MultiPath Tunnel (多路 UDP 隧道的用户空间实现)
mptunnel 是一个在用户空间实现的多路 UDP(类似 MPTCP),其创建一个虚拟隧道,将该隧道中的数据包通过多条路径转发到目标服务器。
MPTCP 旨在提高网络稳定性,但它只支持 TCP 协议。似乎目前还没有 MPUDP 的实现,于是我就写了这个小工具。
.---- 桥 1 ----.
/ \
服务器 A --- mpclient ------ 桥 2 ----- mpserver --- 服务器 B
\ /
`---- 桥 3 ----`
有两台服务器,分别是服务器 A 和服务器 B,它们之间的网络连接不是很稳定,丢包率很高。为了提高网络稳定性,我们希望降低丢包率。为达到这一目标,我们将 A 和 B 之间的数据包复制多份,然后通过不同的路径发送出去。这样,除非所有路径上的数据包都丢了,A 和 B 之间的数据包才会真的丢失,只要有一条路径上的数据包能够到达目的地,A 和 B 之间就不会感觉到丢包。
mpserver 运行在服务器端(可以直接在服务器 B 上运行),它接收从多条路径上发来的数据包,并将数据包转发给服务器 B,它也会将服务器 B 的数据包复制多份,然后转发到各个桥。运行 mpserver 时,需要指定监听端口和目标服务器地址及端口。
mpclient 运行在客户端,它会在本地监听一个端口,将收到的数据包复制多份,然后通过桥转发给目标服务器。启动 mpclient 时需要指定远程桥地址和端口。
桥 就是一个简单的数据包转发服务器,你可以用 socat 或者 nc 等工具来实现。桥应该原封不动地在 mpclient 和 mpserver 之间转发数据包。
我有一台 OpenVPN 服务器,但是本机到 OpenVPN 服务器的网络丢包率很高,这很影响 OpenVPN 隧道之上的数据传输吞吐量。为了提高吞吐量,就需要降低丢包率。我可以先建立一条 MPUDP 隧道,然后在这个隧道上再建立 OpenVPN 连接。
OpenVPN 监听服务器的 1194 端口,在 OpenVPN 上运行 mpserver:
mpserver 2000 127.0.0.1 1194
mpserver 会监听 2000 端口,并将数据包转发到本机的 1194 端口。
在本机上,运行 mpclient:
mpclient mpclient.conf
mpclient.conf 的内容是:
1.2.3.4 4000
bridge1.myhost.com 4000
bridge2.myhost.com 4000
1.2.3.4 是 OpenVPN 服务器的 IP 地址。把目标服务器当成一个桥是完全没有问题的。
在桥服务器上,用 socat 来转发数据包:
socat udp-listen:4000 udp4:1.2.3.4:2000
这样,桥服务器就会在监听端口 4000 和 1.2.3.4 的 2000 端口之间转发数据包。
现在,MPUDP 隧道已经建立起来了,接下来要把 OpenVPN 客户端配置文件中的服务器地址改为 127.0.0.1:3000。3000 是 mpclient 在本地监听的端口。启动 OpenVPN 客户端后,OpenVPN 客户端就会在 MPUDP 隧道上建立 OpenVPN 服务器连接了。
-
mptunnel 会在转发的数据包中添加一些控制和包同步信息。如果 mpclient 或者 mpserver 其中的一个被停止了,那么必须重新启动 mpserver 和 mpclient 才能重建 MPUDP 隧道。
-
目前 mptunnel 只支持指定一个目标服务器。事实上我觉得将 mpclient 做成 SOCKS 代理的话会更好用,但是我找了很久也没发现好用的 C 语言的 SOCKS 库,自己实现一个又太麻烦了。有谁知道有什么好用的 SOCKS 库吗?
-
mptunnel 自带数据加密功能,但加密速度较慢,在一台 AMD Athlon II P320 CPU 机器上实测,在 3 通道的情况下,实际数据流量仅为 3Mbps。如果你不需要 mptunnel 对数据进行加密,可以设定环境变量 MPTUNNEL_ENCRYPT=0 以禁用 mptunnel 自带的加密功能。在禁用加密功能后,吞吐量从 3Mbps 提高到了 300Mbps。
编译 mptunnel 时,需要先安装下面的库
- libev
mlvpn 也是一个可以用来做多路 UDP 的项目。