【自建加速器&愉快吃鸡】UDP 隧道(udp2raw)防 QoS 加速网络游戏

前言

通常来讲,即时网游会采用 UDP 当做客户端 <- 与 -> 服务端通信的协议,特别是实时性要求极高的 FPS 游戏,例如绝地求生、守望先锋等。

而多数情况下,人们对翻墙上网的需求以及工具只需要满足 TCP 协议的代理即可。毕竟因为 Web 技术基于 TCP,网民又以上网页为主。
虽然 VPN 可以同时转发 udp 和 tcp 流量,但是现阶段 VPN(包括主流和非主流)基本上已死完或者半死不活。如果墙没有干扰你的 VPN 使用,你要记住:一定有不可告人的交易,而你是吃亏的那一方(具体原因我不想讨论)。
当然,我们的重点不是墙为什么要干扰 VPN,我们的重点是让墙无法干扰 VPN 以达到代理 UDP 流量的目的。

PS:同时本文的目的不是用来翻墙,翻墙有比这更适合的方式,我的博客有写的。此文章的重点是代理网络游戏。

UDP 和 QoS

上面有说,UDP 被很多实时性要求高的网游采用,在游戏界基于 UDP 协议的网络通信又被称作高性能网络(相反 TCP 是低性能的)。不过由于 UDP 的不可靠性导致并没有 TCP 被采用得广泛。但是也有反例,例如大家非常熟悉的 QQ 就是采用 UDP 通信的,即时通信是一个比较典型的不适合 UDP 的场景,但是腾讯却将 UDP 的使用优化到了超出常规 UDP 协议印象的地步,可靠性堪比 TCP。

相反,由于网络性能差异,TCP 却并不适合替代使用 UDP 的场景。上面 QQ 是一个例子,还有例如一个叫 kcptun 的工具,它是利用 UDP 模拟 TCP 以到达加速 TCP 的效果,你可以理解为将 UDP 当 TCP 使用,让 TCP 流量以 UDP 协议传输。所以 UDP 却可以替代 TCP 的场景,虽然它的优势很明显但是复杂程度和缺陷也明显。

游戏已经提过了,还有一个非常常见的场景,那就是 DNS 查询。我们的操作系统在进行 DNS 查询的时候,通信流量就是 UDP 协议(默认)。虽然 DNS 规范中也是支持 TCP 协议的(Public DNS 开放不开放 TCP 端口又是另一回事了),但是 TCP 只是一种备选方案,因为域名解析这种请求数量高,响应速度要求极高的场景 UDP 当然是更优选。

PS:不得不提的是,DNS 投毒污染就利用了 UDP 的不可靠性。

UDP 虽然很好,但是它在很多地方、很多情况下会被运营商 QoS 以及被墙干扰。自己搭建过 VPN 的应该有过体验,可能你们没意识到,但是原因并不一定出在网络线路上。

QoS 就是一种对网络流量的控制机制,如果你在路由器上配置过 QoS 的话你大概能明白它是干嘛的。例如我可以将迅雷的网络流量优先级调低,避免占用大量宽带导致室友或者其它进程网络缓慢。
而宽带运营商在很多时候会恶意 QoS 你的通信流量,例如发现你长期和海外某个 ip 通信,或者占用了大量海外出口宽带,就可能会出现限速以及丢包。过一段时间后网络状况又会恢复。不过比较重要的是看运营商认为你的流量是干嘛的,要不要 QoS 它,所以伪装协议是常见的逃避 QoS 的方式。

(注意:上述运营商 QoS 纯属我以及他人的推测,并没有实锤证据,但确实是客观存在的现象。)

不使用 Shadowsocks 的原因

注意:这里说的不使用 Shadowsocks 是指的不用它代理游戏网络,而不是指不用它翻墙。前者有比它更适合的方案,后者它又是最好的方案。

Shadowsocks 是一个优秀的 Socks 代理工具,在很长的一段时间里它仅支持 TCP 代理,后来在 Shadowsocks-libev 上实现了 UDP 转发的功能。而 Python、Go 等其它版本版本可能仍然不支持(Python 版最近看了下 Github 上的动态,好像已经支持了有一段时间了),所以你首先要确定你所用 Python 服务端是支持且启用了 UDP 转发功能。

有人用特殊的手段,例如某些兼容 Shadowsocks 协议的非标准客户端(不开放 Socks 代理,而是以类似 VPN 的形式创建虚拟网卡代理流量)将 UDP 流量以 TCP 的方式和服务端通信,实际上是将网络性能大打了折扣。

最后有一点要明确,Shadowsocks 从成立这个项目之初的目的就是绕过墙的阻碍,而不是加速网络。相反,它对网络性能是有损耗的,加密会消耗 CPU 性能,混淆会带来冗余数据的传输。而且 Shadowsocks 存在被 QoS 的可能性,之所以很多人要用 SSR 或者混淆插件也是为了逃过运营商的 QoS。
所以,代理游戏 Shadowsocks 不太适合,至少有一些比它更适合的工具。我就是因为前段时间有人跟我说 GCP 代理吃鸡效果很差,导致我连尝试的欲望都没有了,原因可能就在于他用的 SSTab 做本机代理,Shadowsocks 的后端。
恰好我最近加速器到期了,找了个时间自己搭建了一个 OpenVPN 的 UDP 隧道环境,发现效果完美堪比加速器。才意识到自己当初多么愚蠢,有低延迟的境外服务器不用,反而月供几十元交给网络加速器厂商。

步骤简描

我们分两个阶段进行,第一个阶段是让 OpenVPN 可用,第二个阶段是优化网络性能。

在第一个阶段:

  1. 搭建一个 OpenVPN 服务端
  2. 给 OpenVPN 搭建一个 udp2raw 通道(UDP 隧道)
  3. 配置 OpenVPN 客户端

在第二个阶段:

  1. 搭建 UDPspeeder 通道串联 udp2raw
  2. 为游戏网络环境调优 UDPspeeder

OpenVPN

有关 OpenVPN 的安装本文不做介绍,因为我发现了 Linux 中国上一篇写得很好的中文文章,请点击这里详细阅读。

注意:有关 DNS 的部分不需要配置,直接略过。在搭建好 OpenVPN 以及配置好客户端以后可以直接尝试连接,如果发现连接不上,那是正常现象,因为 OpenVPN 在 GFW 面前早就跪了。

顺便说明一下 OpenVPN 在 Systemd 上应该怎么管理守护进程:

如果你根据 Linux 中国上的文章全部配置完成,那么你的 Server 端配置文件应该叫 delta.conf,或者你自己改的名字,这个文件名是至关重要的。
你可以通过 systemctl <start/status/restart> openvpn@<cfg_name> 来管理,例如:

systemctl start openvpn@delta
          

这样就启动了 openvpn 服务端,且用的是你自己的配置。当然,你得把这个加入开机自启中:

systemctl enable openvpn@delta
          

客户端的话,如果是 Linux 直接用 openvpn <cfg_file> 命令启动即可。如果是 Windows 你去这里下载 OpenVPN 客户端,然后将客户端配置中的 client.conf 重命名为 client.ovpn,并且将配置中的密钥、证书等文件路径改为绝对路径,并且要用双反斜杠切割(\\),例如我的:

ca D:\\OpenVpn_Share\\ca.crt
          cert D:\\OpenVpn_Share\\mypc.crt
          key D:\\OpenVpn_Share\\mypc.key
          

然后导入即可,这样就基本大功告成了。如果你的服务端运行不起来,重点记得看日志,问题都在上面。我依稀记得按照 Linux 中国中的步骤做的话会缺少一个名为 ta.key 的密钥导致无法启动,自己生成即可:

openvpn --genkey --secret /etc/openvpn/ta.key
          

到这里,你至少要保证服务端正常启动和运行,客户端配置已经保存到本地。

搭建 UDP 隧道(udp2raw-tunnel)

你可以从这里下载编译好的最新版本,或者直接从源代码编译。 然后其实就是照着项目 README 的命令做就行了(注意下面的命令用的都是同一个可执行文件, -s 参数表示以服务端形式运行,-c 表示客户端)。

在服务端运行命令:

./udp2raw_amd64 -s -l0.0.0.0:4096 -r 127.0.0.1:1194  -a -k "passwd" --raw-mode faketcp
          

这条命令的意思是监听 4096 端口,流量转发到本机的 1194 端口(也就是 OpenVPN 的默认端口)

在客户端运行命令:

./udp2raw_arm -c -l0.0.0.0:3333  -r8.8.8.8:4096 -a -k "passwd" --raw-mode faketcp
          

注意:这条命令中的 8.8.8.8 要替换成你的服务器 ip 地址,不能使用域名,并且 ip 前面的字母 r 是紧挨着的。这条命令的意思是监听 3333 端口,流量转发给服务端的 4096 端口(也就是 udp2raw 的服务端)。

当然,你还得修改下 OpenVPN 的客户端配置。例如 remote 后面要改为 “192.168.1.1 3333” 而不再是远程服务器地址和 1194 端口了。这里的 192.168.1.1 指的是你的 udp2raw 客户端运行环境的 ip,可以是路由器、可以是局域网内的其它机器(Linux 系统)也可以是本机上运行的 Linux 虚拟机。

先后运行服务端和客户端,如果没有连接失败,那么隧道就打通了。连接客户端运行环境的 3333 端口,相当于连接到服务端的 1194 端口。而 udp2raw 的作用就相当于在 4096 端口上建立了一个对应用程序透明的通道。
说到这里,你应该明白了 OpenVPN 的客户端不再是连接服务器的 OpenVPN 后端(1194 端口)了,而是连接 udp2raw 客户端环境的 3333 端口。这样子 OpenVPN 的连接会处于“隧道”之中,不再具有 OpenVPN 自身的流量特征,所以 OpenVPN 会满血复活。

优化 OpenVPN 性能

当你搭建好隧道以后,再连接 OpenVPN 会发现不仅能连接上,而且还能翻墙上网了。因为 udp2raw 加密和伪装了 OpenVPN 的 UDP 流量,使之能逃过 GFW 的识别。
准确的说任何在这个隧道中传输的流量都能逃过 GFW 的识别和干扰,所以 OpenVPN 自身的加密不再有意义,反而是性能上的浪费。那么要优化性能,可以将 OpenVPN 配置中的 cipher 后面的加密方法改为 none(客户端和服务端都要改),记得重启服务端的 OpenVPN 服务。

指的一提的是,到这一步我这里出现了 MTU 异常,日志上一大堆的相关输出,并且网络很卡很卡。我是这样解决的:

在 OpenVPN 的客户端和服务端配置文件中,都加入了设置 MTU 参数相关配置:

mssfix 1240
          tun-mtu 1240
          

之后没有再出现该问题,网络也流畅无比。可能在不同位置、不同的运营商这个值会有些许差异。

到此,启动 OpenVPN 客户端以后游戏进程的网络就会走代理了。此时的代理网络处于一种非常安全和纯净(无干扰)的环境中,如果你发现游戏延迟或者体验已经完全能接受了甚至可以不用往下看了。
继续往下的意义在于,对网络性能的进一步优化和加速。如果已经满足当前的效果可以不用继续做,因为可能起不到效果,或者出现反效果(参数不适合场景),想优化可能需要反复调试参数以得出一个最优的效果。

优化 UDP 性能(UDPspeeder)

上面的 udp2raw 隧道已经让自建的 OpenVPN 正常的使用,但是它的目的也基本仅仅如此而已,对于 UDP 在性能方面的优化它并无帮助。所以在 udp2raw 的隧道中,OpenVPN 客户端流量的下游和服务端的上游应该再插入一个专门 优化 UDP 性能的网络加速隧道,也就是这个篇章的主角 UDPspeeder。

我们从这里下载编译好的可执行文件,如果架构不兼容可以跟 udp2raw 一样自行编译。
分别在客户机和服务器上放一份,在服务器上运行命令:

./speederv2 -s -l0.0.0.0:4097 -r127.0.0.1:1194 --mode 0 -f2:4 -q1
          

可以看到转发到本机 1194 端口的已经不是 udp2raw 了,因为 OpenVPN 服务端流量的上游需要来自 UDPspeeder 而不是 udp2raw。于是我们 kill 掉 udp2raw 的进程,重新运行命令:

./udp2raw_amd64 -s -l0.0.0.0:4096  -r127.0.0.1:4097 -a -k "passwd" --raw-mode faketcp --cipher-mode xor
          

这里的 4097 也就是 UDPspeeder 监听的端口啦。在客户端上,我们是相反的操作,OpenVPN 流量需要首先通过 UDPspeeder,然后再进入 udp2raw 的隧道。所以我们用 UDPspeeder 客户端监听连接端口,转发到 udp2raw:

./speederv2_arm -c -l0.0.0.0:3333 -r127.0.0.1:2222 --mode 0 -f2:4 -q1
          

3333 端口就是之前用过的 OpenVPN 客户端连接的端口,我们重新运行 udp2raw 的客户端让它监听本机 2222 端口:

./udp2raw_arm -c -l0.0.0.0:2222 -r8.8.8.8:4096 -a -k "passwd" --raw-mode faketcp --cipher-mode xor
          

此时性能优化过后的 OpenVPN 流量经过 udp2raw 通信,既能加速网络又能避免干扰,我们的最终目的也达到了。

UDPspeeder 调优

此部分暂时略过。

效果

仅仅只用 udp2raw 在我这里就能流畅吃鸡了,流畅到直观的感觉是和国内的网络加速器没有区别,毕竟绝地球上这款游戏没有显示延迟的功能。

如果换做 Steam 版的 CS:GO,那就略微有些差异了。在我这里直连是 140 ms 的延迟,还是比较大的,但是使用 udp2raw 以后延迟会降低到 70 上下。不过虽然延迟降低了,游戏却反而出现了一系列的高延迟才会出现的现象,例如:人物瞬移、坐标重置,莫名其妙的被打死看回放才知道我一直没动。
但是加上 UDPspeeder 以后,适当的调优让这种现象好了很多很多,正常玩基本没什么问题。延迟低至 60 ms。

PS:我的服务器延迟一般在 50 ms 左右,我偶尔会用加速器偶尔会用自己的服务器。对于我而言区别只有一个,那就是游戏前打开的客户端不一样:一个是 OpenVPN 一个是网络加速器客户端。至于 UDP 隧道客户端都在路由器上 24 小时运行着呢。