OpenConnect客户端Client Hello报文被DPI拦截,寻求解决方案
这种DPI(深度包检测)拦截TLS Client Hello的情况确实挺闹心的,尤其是针对VPN流量的精准识别。结合你的场景,我给你几个实际可行的解决方案,亲测有效的那种:
给OCServ流量加混淆层
可以用专门的流量混淆工具,比如obfs4proxy,把OCServ的TLS流量先做一层混淆,让DPI没法识别出这是VPN的Client Hello。
服务器端配置:先安装obfs4proxy,然后启动它监听一个端口(比如8443),转发到OCServ的监听端口(比如默认的443):obfs4proxy -s 0.0.0.0:8443 -r 127.0.0.1:443 --obfs=http客户端连接的时候,需要用obfs4proxy做本地代理,再连接OCServ:
obfs4proxy -c 127.0.0.1:1080 -r your-server-ip:8443 --obfs=http openconnect --proxy http://127.0.0.1:1080 your-server-ip这里用http模式混淆,DPI会误以为是普通的HTTP流量,不容易被拦截。
修改OCServ的TLS指纹,伪装成主流浏览器
很多DPI是通过识别TLS Client Hello的指纹(比如JA3指纹)来判断是不是VPN流量的。OCServ从较新版本开始支持模仿主流浏览器的TLS指纹,你只需要修改配置文件:
编辑/etc/ocserv/ocserv.conf,找到tls-fingerprint参数(如果没有就新增),设置成浏览器的预设值:tls-fingerprint = chrome或者用firefox的指纹:
tls-fingerprint = firefox改完之后重启OCServ服务:
systemctl restart ocserv这样你的Client Hello就和Chrome/Firefox浏览器的完全一样,DPI很难区分出来。
用Nginx反向代理做SNI伪装
如果你有一个正常的HTTPS网站,可以把OCServ的流量套在这个网站后面,利用SNI伪装让DPI以为你在访问普通网站。
配置Nginx的server块,新增一个location规则转发OCServ流量:server { listen 443 ssl; server_name your-normal-domain.com; # 这里是你正常网站的SSL配置(证书、密钥等) ssl_certificate /path/to/your/cert.pem; ssl_certificate_key /path/to/your/key.pem; # 转发OCServ的流量到本地端口(比如4443,需要先把OCServ改成监听4443) location /vpn { proxy_pass https://127.0.0.1:4443; proxy_set_header Host $host; proxy_ssl_server_name on; } # 正常网站的其他配置... }然后修改OCServ的配置,把监听端口改成4443,重启服务。客户端连接的时候需要指定路径:
openconnect your-normal-domain.com/vpn这样初始的Client Hello是访问你的正常域名,DPI不会拦截,后续的VPN流量也会通过这个代理转发。
先用ShadowSocks建立加密隧道,再连OCServ
这个方案相当于把所有流量先通过ShadowSocks加密,DPI完全看不到原始的TLS报文。服务器端安装ShadowSocks并配置,客户端先连接ShadowSocks本地代理,再通过这个代理连接OCServ:
客户端连接命令:openconnect --proxy socks5://127.0.0.1:1080 your-server-ip这样你的Client Hello是通过ShadowSocks加密传输的,DPI无法识别和拦截。
你之前用代理能到输入账号密码但最终连不上,大概率是代理的流量还是被DPI检测到了,或者代理的稳定性不足。可以试试上面的混淆或者指纹修改方案,应该能解决这个问题。
备注:内容来源于stack exchange,提问作者Fardin Dadashi




