OpenVPN 流量混淆补丁

2013年2月9日 | 分类: 翻墙相关 | 标签: ,

最近墙抽风得比较厉害,OpenVPN 几乎全部阵亡,我自己架设的不用于翻墙用途的 OpenVPN 也都一并阵亡了。我只是用 OpenVPN 来组建一个虚拟局域网,以便从外网连接到我那被糟糕的移动宽带挡在内网里面的机器而已啊,这种人畜无害的服务都被咔嚓掉了,墙这次抽风抽得不轻。不过听说 有北邮的学生参与了墙的开发,考虑到天朝大学生的水平,出现这种情况也就不足为奇了。

虽然说我可以使用其他的虚拟专用网技术,但是比较起来还是 OpenVPN 更容易配置和方便部署。所以决定还是继续使用 OpenVPN,暂时不考虑更换到其他的虚拟专用网技术去。

据目前观察到的情况,墙只是会根据 OpenVPN 进行 TLS 握手时候的特征对特定的端口进行封杀,如果 OpenVPN 不使用 TLS 握手的话,墙就不会认出 OpenVPN 了。不过如果不使用 TLS 握手的话,OpenVPN 就只能配置成一对一的网络,没法组建局域网,故使用 TLS 是必须的(所以说你这墙放着只能用于翻墙用途的非 TLS 方式不管而去对可以作为正常应用的 TLS 协议下手你是要想怎样)。既然这样,那就只能对 TLS 握手过程进行一些模糊了。考虑到即使是握手之后的流量也会带有 OpenVPN 的表示,干脆顺便把握手之后的流量也一起做个模糊处理算了(好吧其实真正的原因修改代码的时候对所有流量进行处理要比仅仅对 TLS 握手流量进行处理更简单-_-b)。

于是这个补丁就出现了:

openvpn-2.2.2-obfs.patch <– 这个版本在 TCP 模式下会有问题,请使用下面的版本

OpenVPN-2.2.2-obfs.patch <– 这个版本的 TCP 和 UDP 模式均无问题,请使用此版本

同时这个补丁也发到了 gist 上: https://gist.github.com/4372285

使用说明

  1. 从 OpenVPN 官方下载 2.2.2 源码包,并解压
  2. 将此补丁保存到解压后的目录内,然后执行
  1. patch < openvpn-2.2.2-obfs.patch

另外建议手工修改源码目录中的 version.m4 文件,将 OpenVPN 的版本号 2.2.2 改为 2.2.2-obfs,以便和原始的 OpenVPN 区分

之后按正常的编译安装步骤进行

  1. ./configure –enable-password-save
  2. make
  3. make install

配置选项说明

该补丁有 2 个配置文件参数,分别如下

obfs-salt <secret>

混淆密钥,secret 是一个任意字符串,必须保证服务端的配置文件和客户端的配置文件的 secret 完全相同,否则客户端无法连接到服务器。

使用此选项即可开启流量混淆功能。

obfs-padlen <num>

num 是一个不大于 255 的正整数。如果使用了此选项,则本补丁会在每个数据包后面添加一个长度随机且不超过 num 的随机内容。

该选项只有在启用了  obfs-salt 之后才能使用。

注意事项

本补丁会在数据包在发送出去之前在数据包头部增加4字节的数据,如果启用了 obfs-padlen <num> 选项,还会在数据包尾部增加最多 num 字节的数据请使用 OpenVPN 自带的 mssfix 参数来指定最大的 TCP 包长度,保证原始TCP 包长度与随机增加的内容的长度之和不小于 MTU,如有必要,还应使用 fragment 来指定最大包长度,以确保数据包能够正常发送出去。

本补丁虽然使用了类似加密的方法对流量进行处理,但是我无法保证这种类似加密算法的安全性,不要尝试使用本补丁对流量进行加密。要对流量进行加密,请使用 OpenVPN 自带的加密功能。

选项示例

  1. ###示例壹####
  2. # 使用 threebody 作为混淆密钥,不改变数据包长度(但 obfs 补丁还是会在包头添加一段 4 字节的数据,实际上包的总长度会比原来多4,建议使用 mssfix 选项设置限制 TCP 包大小)
  3. obfs-salt threebody
  4. ###########
  5. ###示例二####
  6. # 使用 theansweris42 作为混淆密钥,随机将原始数据包增长0~10个字节
  7. # 假设 MTU 为 1400,因为原始数据包最多可能增加 10 个字节,另外 obfs 补丁会额外使用 4 个字节,因此要控制原始 TCP 包的大小在 1400 – 10 – 4 = 1386 以下
  8. obfs-salt theansweris42
  9. obfs-padlen 20
  10. mssfix 1386
  11. ##########

常见问题

问:使用了 obfs 补丁之后,速度变得很慢很慢

答:查看 OpenVPN 的 verb 3 级别的日志,检查其中是否包含有数据包错误之类的消息,如果有的话,可能是 mssfix 设置过大,将 mssfix 调小可解决问题

问:客户端已经向服务器发送请求,但服务器日志中看不到任何信息,客户端也无法连接

答:请检查服务端和客户端的 obfs-salt 以及 obfs-padlen 参数是否完全一致

问:使用 obfs 补丁后,性能是否会下降?

答:CPU 占用率会有一定提高,但除非是古董级 CPU,否则基本没影响。网络性能会有一定下降,如果没开启 obfs-padlen 选项,则下降不大,基本没影响。如果开启了 obfs-padlen <num> 选项,则 num 越大,影响越大。根据实测,num 选择 20 在 4Mbps 的线路下感觉不到速度降低。

补丁原理

本补丁在 OpenVPN 发送包之前以及接收包之后对数据包进行混淆,混淆方法是将数据包与一个混淆密钥进行异或操作。混淆密钥的产生方法如下:

  1. 从包头中提取一个随机数 R
  2. 密钥 C0=SHA1(R+salt)
  3. SHA1 计算结果为 20 字节,使用 C0 对数据包前 20 个字节进行异或运算
  4. 若数据包长度大于 20 字节,则计算 Cn=SHA1(Cn−1),然后用 Cn 继续对原始数据包进行异或运算

为保证每个数据包使用的密钥都不相同,补丁会在每个数据包的开头添加 4 字节的随机数据,这个随机数据就是随机数 R,随机数本身就是随机的,不需要进行混淆操作。平均大约发送 42 亿个数据包之后才会出现相同的密钥,假设数据包平均大小 100 字节,则流量平均大约达到 400G 后才会出现相同的密钥。

混淆之后,OpenVPN 的流量看上去就是完全无意义的随机流量了,但此时还有包大小信息是可识别的。为了把包大小信息也一并混淆,可以在包末尾增加一些随机长度的随机内容,这样包长度信息就也被混淆了。

由于 OpenVPN 在处理数据包时,会丢弃大小不正确的数据包,所以在接收端要把数据包中随机添加的内容去掉,这就要求接收端知道发送端添加了多长的内容,所以 obfs-padlen 选项随机增加的长度应该是伪随机的,也就是可以计算的。计算方法如下:

  1. 取 C=MD5(R+salt),其中 R 是随机数,和混淆时使用的随机数相同
  2. 取 MD5 值的第一个字节,作为无符号数,取 256 除的余数,作为随机增加的内容的长度,即 随机长度 L = (unsigned char)C[0] % 256

在单个连接流量较小的情况下,OpenVPN 的 ping 包是按照固定时间间隔发送的,这同样也是一个有用的信息。本补丁未针对此情况进行数据包混淆处理,用户可以通过在服务器端和客户端都禁用 OpenVPN 的 keepalive 及 ping 系列选项来避免此类信息被识别。

性能估算

最近装了个 MathJax 插件,不写几个公式手就痒,于是弄几个公式出来玩玩。

下面的计算均假设最大传输单元为 1500,且数据包长度服从均匀分布。

在启用了混淆补丁,但不开启 obfs-padlen 选项时,吞吐量与原始吞吐量的百分比的最好、最坏和平均情况分别为:

 

最好情况:1500−41500×10≈99.73%最坏情况:11+4=20%平均情况:∑1500−4i=1i∑1500k=4k≈99.46%

这结果比我预想中的要好啊,我估计平均会有20%~30%左右的性能下降,也就是性能仅为原始情况的 80%~70%,没想到结果竟然比我预想的要好得多。

在启用了 obfs-padlen 选项的情况下,最好、最坏和平均性能与原始吞吐量的百分比为:

 

最好情况:1500−4−n1500=1496−n1500×100%,最坏情况:11+4+n=1n+5×100%,平均情况:∑1500−4−ni=1i∑1500k=n+4k≈(1494−n)(1495−n)(1504+n)(1497−n)×100%,(0<n<256)(0<n<256)(0<n<256)

我现在在服务器上使用的参数是 n=20, 代入计算得到最好情况 98.40%,最坏情况 4%,平均情况 96.59%. 开了 20 个字节长度的随机内容填充,性能竟然还是这么好,真出乎我意料。不过这个计算结果确实也和实际情况相符。

其实上面的计算并不精确,因为没有考虑到当包的大小超过最大传输单元时拆分包后多出来的 TCP 头和 IP 头大小。不过要考虑这种情况的话就比较麻烦,所以就不算了。


截止到写这篇文章为止,我已经在两台服务器上运行这个补丁超过 5 天时间,暂时还没有观察到墙有任何反应,这比使用原版 OpenVPN 的时候运行不到一天就被墙的情况强多了。期间只出现了一个小插曲,其中一台服务器的 IP 地址被局部墙掉,主要是在非电信线路上被墙,不过这有可能和我在此期间在手机上使用联通网络去访问这台服务器的 SSH 引起的,此猜测有待证实。另外和这台服务器上 OpenVPN 产生的流量主要都是和一台位于电信宽带上的服务器进行的,估计这台服务器局部被墙和 OpenVPN 的关系不大。

也就是说到目前为止,这个补丁运行得还不错,至少没看到墙有什么实质性的动静。不过既然我把这个补丁发出来了,如果日后有其他人使用的话,到时候墙会作出何种反应就不得而知了,总之保持观察然后根据其反应作出调整即可。

最后要黑一下 Windows。我写这个补丁花了两天时间,在 Windows 上研究怎样编译 OpenVPN 又花了另外两天时间。在 Windows 上研究编译方法的时间竟然和我写补丁的时间一样长!于是得出结论:企图在 Windows 下进行开发=自虐。


若转载本文,无须遵守本站的授权许可,即转载时无须注明出处,同时,转载本文时不得注明本文出处。

  1. cjyl
    2016年6月12日15:02

    请问为什么执行补丁的时候会出现
    “can’t find file to patch at input line 3
    Perhaps you should have used the -p or –strip option?
    The text leading up to this was:”

    • iGFW
      2016年7月12日15:55

      这个是很旧之前的了,不知道是不是失效了

  2. TopKx
    2013年3月14日11:30

    我编译客户端已经成功了,打了这个补丁也可以翻墙了,就是TCP最新提供的补丁也没用,还是使用UDP才行,还有就是服务端的日志频繁输出这些
    Thu Mar 14 11:29:52 2013 cjc/118.26.228.3:4147 1, write buflen=85
    Thu Mar 14 11:29:52 2013 cjc/124.172.25.2:3709 2, write buflen=225
    Thu Mar 14 11:29:52 2013 1, read buflen=81
    Thu Mar 14 11:29:52 2013 1, read buflen=77, padlen=0
    Thu Mar 14 11:29:52 2013 1, read buflen=81
    Thu Mar 14 11:29:52 2013 1, read buflen=77, padlen=0
    Thu Mar 14 11:29:52 2013 1, read buflen=81
    Thu Mar 14 11:29:52 2013 1, read buflen=77, padlen=0
    Thu Mar 14 11:29:52 2013 1, read buflen=81
    Thu Mar 14 11:29:52 2013 1, read buflen=77, padlen=0
    Thu Mar 14 11:29:52 2013 1, read buflen=105
    Thu Mar 14 11:29:52 2013 1, read buflen=101, padlen=0
    Thu Mar 14 11:29:52 2013 cjc/118.26.228.8:37195 1, write buflen=301
    Thu Mar 14 11:29:52 2013 cjc/118.26.228.8:37195 2, write buflen=305
    Thu Mar 14 11:29:52 2013 1, read buflen=105
    Thu Mar 14 11:29:52 2013 1, read buflen=101, padlen=0

  3. windbizz
    2013年3月14日00:43

    你好, 小弟是一名長駐內地工作的香港人
    請教一下版主, 在沒有使用TLS的情況下, 透過轉換不同的port, 同一ip能支撐多久?

    • iGFW
      2013年3月24日14:37

      成不了多久
      IP换端口频繁最后会导致ip被封

  4. 清水
    2013年2月26日14:39

    博主,请问对于这个情况,如何在windows下编译openvpn客户端呢?您说您都用了2天时间研究的那个.如果可以的话,请赐教

    • 清水
      2013年2月26日14:40

      谢谢.

    • iGFW
      2013年2月27日12:27

      其实我也不会编程、编译之类的东西

  5. Mr.Koala
    2013年2月25日17:08

      刚刚注意到:“若转载本文,无须遵守本站的授权许可,即转载时无须注明出处,同时,转载本文时不得注明本文出处。”这是什么意思啊?  -_-|||

    • iGFW
      2013年2月27日12:24

      原文作者估计是怕流传多了导致他的博客被封,所以不让注明原文地址

  6. Larry
    2013年2月25日11:47

    请问两个配置参数在哪里输入,是否跟在./configure –enable-password-save 后面? 另外,加了混淆参数,客户端是不是也要修改呢?原来的Windows客户端还可用么?谢谢楼主。

    • Mr.Koala
      2013年2月25日17:07

      配置文件是指你的 .ovpn 配置文件,跟编译无关。
      两边都要重新编译,原有的一概不能用。

    • Mr.Koala
      2013年2月25日17:13

      还有,如果你在 Windows 下使用 GUI 的话,可能可以用这个替换原有的 OpenVPN 程序,让 GUI 照常运行。(GUI 会不会得到什么不认识的输出而报错?)具体情况我等手头有 Windows 的时候看下。

    • iGFW
      2013年2月27日12:19

      是的,客户端也要改

      • Ksyou
        2013年3月8日10:52

        请问客户端咋重新编译才能支持如下参数,服务端打完补丁以后加入如下参数即可吗?
        博主提供的最新补丁的下载已经失效了.
        obfs-salt xx
        obfs-padlen xx

      • Ksyou
        2013年3月8日10:55

        在 Windows 下使用 GUI 的客户端。。

  7. Mr.Koala
    2013年2月21日14:05

    如果此类混淆方法流行,会不会导致 GFW 在敏感词期间直接掐掉无法识别协议的包?有混淆成常见“安全”协议的方案吗?

  8. iGFW
    2013年2月19日21:50

    哪里解封了?

  9. byr
    2013年2月11日17:26

    有北邮学生参与?哪里得到的消息?有无更具体的信息?

  10. Anon
    2013年2月11日16:41

    博主,2月7日GFW解封了一大堆网站,现在情况基本上回到几年前(封死UTB、推特、FB和大纪元等反华网站,解封了除此以外所有被连带伤害的,谷歌不被干扰,只要搜索返回结果中没有关键词——虽然很难——就可以正常使用,加密服务如gmail都可以正常运行),不知道为什么这个消息没有被我看到的任何一家网站报道,博客和微博上倒是传得很开,不知是何原因?个人感觉会不会GFW是把屏蔽的范围缩小,把机能集中到对加密连接的检测和封堵上了?

    • KIOJ
      2013年2月12日13:05

      “你好”1 yuan pay you

    • 2013年2月13日15:56

      本身GFW的存在就不被報道,那麼解封什麼的消息也自然不會被報道。
      要是用您的觀點看待這次的動作的話,您就太小看她們呢。

    • iGFW
      2013年2月24日09:09

      我这里谷歌还是被干扰的,我的博客也没有被解封。

  11. AS
    2013年2月11日02:27

    Firefox-goagent
    为新手提供goagent和wallproxy的共享服务端,配合Firefox,三分钟出墙。
    https://code.google.com/p/firefox-goagent/
    “Firefox-GoAgent
    点Download去下载。
    已将Firefox和goagent打包,解压后按照里面的说明操作即可,一些可能出现的问题也在说明内。”
    https://code.google.com/p/firefox-goagent/downloads/list
    “Firefox-goagent.7z Firefox使用的便携版v18.0.2;goagent版本v2.1.9-50,内含90个id,如果使用人数增加还会继续添加id。 2 days ago 2 days ago 31.4 MB “

  12. Aquamarine
    2013年2月10日16:53

    博主也太强大了吧,开始还以为是官方补丁。

  13. fishdf
    2013年2月10日16:35

    我试过,还是不行啊。博主有测试过吗

    • iGFW
      2013年2月24日09:07

      没有,你测试的话openvpn换新端口呢?
      我想他是防止被gfw发现而不是直接突破gfw封锁,所以要vpn服务器IP上的端口尚未被GFW封锁才行

  14. zdcs
    2013年2月10日08:31

    博主 新年好!感谢你渡人 功德无量

  15. AS
    2013年2月10日02:00

    New ver.:Freenet
    https://code.google.com/p/freenet/downloads/list
    “FreenetInstaller-1433.exe Freenet 0.7.5 build 1433 installer (windows) Featured 65 minutes ago 14.4 MB
    FreenetInstaller-1433.exe.sig Freenet 0.7.5 build 1433 installer (windows) (signature) 66 minutes ago 72 bytes …..”

    2013年2月9日

  16. AS
    2013年2月10日00:16

    https://www.techsupportalert.com/content/critical-update-java-you-must-install.htm?utm_source=feedburner&utm_medium=email&utm_campaign=Feed%3A+gizmosbest+%28Gizmo%27s+Best-ever+Freeware%29
    “A Critical Update For Java That You Must Install
    Updated 8. February 2013 – 15:38 by rob.schifreen

    For the past few weeks, security experts have warned that recently-discovered security flaws in Java were so dangerous that you should uninstall Java from your PC.

    Oracle, the company behind Java, has now issued an update for the system. It corrects 50 separate security problems, many of which could have allowed hackers to gain remote access to your PC.

    If you deleted Java, it’s now safe to reinstall. If you didn’t uninstall Java, you really should uninstall your current version and then head to http://www.java.com to get the latest release”

    2013年2月9日