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

需知

首先需要声明一下观看本文以及实践本文内容的部分前提:

  1. 有一台低延迟的海外服务器,地区包括港台,类型包括云主机、VPS 之类(虚拟主机不可行)
  2. 有虚拟机安装 Linux 经验或者路由器上运行的是 Linux(包括 OpenWrt、DD-WRT、AsusWRT 等及其衍生系统)
  3. 比较痛恨月供几十元的网游加速器

前言

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

其实 VPN 对于 UDP 流量的代理是一个不错的选择,但是由于某些原因现阶段流行的 VPN(包括主流和非主流)基本上已死完或者半死不活。

导致这个现象还不是因为很多人将它们用于翻墙,当然本文的目的不是用来翻墙,此文章的重点是网络游戏流量的代理,跟网游加速器厂商做一样的事情。

UDP 和 QoS

在游戏界基于 UDP 协议的网络通信又被称作高性能网络,不过它的适用面也比较狭窄并没有 TCP 被采用得广泛。但是也有反例,例如大家非常熟悉的 QQ 就是采用 UDP 通信的。其实即时通信是一个比较典型更适合 TCP 的场景,但是腾讯却将 UDP 的使用优化到了超出常规 UDP 协议印象的地步,并且其目的也是弥补 TCP 的缺陷。

游戏已经提过了,还有一个非常常见的场景,那就是 DNS 查询。我们的操作系统在进行 DNS 查询的时候,通信流量就是 UDP 协议(默认)。虽然 DNS 规范中也是支持 TCP 协议的(Public DNS 开放不开放 TCP 端口又是另一回事了),但是 TCP 只是一种备选方案。

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

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

不使用 Shadowsocks 的原因

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

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

最后有一点要明确,Shadowsocks 从成立这个项目之初的目的就是绕过墙的阻碍,而不是加速网络。相反,它对网络性能是有损耗的,加密会消耗 CPU 性能,混淆会带来冗余数据的传输。而且 Shadowsocks 存在被 QoS 的可能性,之所以很多人要用 SSR 或者混淆插件也是为了逃过运营商的 QoS。 所以,代理游戏 Shadowsocks 不太适合,至少有一些比它更适合的工具。

而且:Shadowsocks 被明令禁止的违法翻墙软件,我们代理游戏不能被认为是在干违法的事情!(滑稽

OpenVPN

OpenVPN 是一个使用单一 ip 和端口,默认使用 UDP 且不兼容 IPsec 协议的代理软件。它会在客户端创建虚拟网卡转发本机流量,是比较推荐的选择之一。

虽然 OpenVPN 是采用通用网络协议,但是仍然避免不了它被墙掉的现象。如果使用 TCP 协议,客户端和服务端的通信会直接被重置。用 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\\ca.crt
cert D:\\OpenVpn\\mypc.crt
key D:\\OpenVpn\\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 调优

此部分暂时略过。

运行环境

客户端运行环境通常有下面两种:

当然我是后种,因为我的路由器是 Linux(路由器发行版)。路由器不行的话,使用虚拟机也是可以的,跑一个无 GUI 的 Linux 对于宿主机的资源消耗是很低很低的。你甚至可以找一些极简的发行版,启动系统速度快到只要几秒,资源消耗更是极低。隧道软件客户端配置开机启动即可。

效果

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

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

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

不说了,上图吧(之前都至少是 120 以上)!

最后

如果你只是一个对 IT 技术一无所知只想好好玩游戏的小白用户,此文的内容实践对你而言可能非常困难,那么我建议你不要尝试了(当然你非常有兴趣可以一试)。

其实我这篇文章是写给同样吃鸡的同行看的… 当然实际上本文毫无技术含量,一个稍微懂得折腾的高中生不需要任何专业知识也能做到。

我听过一个叫 SSTap 的工具,貌似也可以用来代理 UDP 流量(其实这个工具我在 Shadowsocks 章节描述过了)。我个人没有使用过,据说效果不是太好,但是嫌麻烦的也许可以试试。

顺便:如果你跟我一样厌恶 YY 这类语音软件,那么我建议你使用 Discord 这个十分纯净和智能的游戏队伍语音软件。如果你想尝试或者已经在使用它,为什么不加入这个中文的 Steam for discord 服务器呢?

如果你没注意到刚才的链接,那么我再重复一遍好了!~ STEAM_CN ~