![通过不可靠的网络使用高级 Linux 路由建立冗余 OpenVPN 连接](https://linux22.com/image/541178/%E9%80%9A%E8%BF%87%E4%B8%8D%E5%8F%AF%E9%9D%A0%E7%9A%84%E7%BD%91%E7%BB%9C%E4%BD%BF%E7%94%A8%E9%AB%98%E7%BA%A7%20Linux%20%E8%B7%AF%E7%94%B1%E5%BB%BA%E7%AB%8B%E5%86%97%E4%BD%99%20OpenVPN%20%E8%BF%9E%E6%8E%A5.png)
我目前居住在一个封锁许多网站并且与外界的网络连接不可靠的国家。我在 Linux 服务器上有两个 OpenVPN 端点(例如:vpn1 和 vpn2),用于绕过防火墙。我可以完全访问这些服务器。除了我的 VPN 连接上数据包丢失率高外,这种方法效果很好。这种数据包丢失率根据时间在 1% 到 30% 之间变化,并且似乎相关性较低,大多数时候似乎是随机的。
我正在考虑设置一个家用路由器(也在 Linux 上),该路由器维护与两个端点的 OpenVPN 连接,并将所有数据包两次发送到两个端点。vpn2 会将所有数据包从家里发送到 vpn1。返回流量将直接从 vpn1 发送到家里,也通过 vpn2 发送。
+------------+
| home |
+------------+
| |
| OpenVPN |
| links |
| |
~~~~~~~~~~~~~~~~~~ unreliable connection
| |
+----------+ +----------+
| vpn1 |---| vpn2 |
+----------+ +----------+
|
+------------+
| HTTP proxy |
+------------+
|
(internet)
为了清楚起见:所有从主服务器到 HTTP 代理的数据包都将被复制并通过不同的路径发送,以增加其中一个数据包到达的机会。如果两个数据包都到达,则可以默默丢弃第一个数据包。
带宽使用不是问题,无论是在家庭端还是端点端。vpn1 和 vpn2 彼此靠近(3ms ping)并且具有可靠的连接。
关于如何使用 Linux 中可用的高级路由策略来实现这一点,有什么指示吗?
答案1
在“home”和“vpn1”侧使用绑定基础设施,特别是使用mode=3设置在属于绑定的所有接口上广播流量。
答案2
我使用了@user48116 提供的答案,效果非常好。设置其实很简单!
笔记:我通过两个连接到一台服务器来实现这一点,因为这已经为我解决了问题。如果您想尝试使用两台服务器进行设置,最简单的方法可能是使用端口转发将 UDP 端口从第二台服务器转发到第一台服务器,并使用此处描述的相同方法。不过我自己还没有测试过。
首先,确保您有一个支持绑定的 2.6 内核(所有现代发行版中的默认设置)并且已经安装了 ifenslave。
接下来,将其放入 /etc/rc.local 或你喜欢的任何其他位置,但确保它已运行前openvpn 已启动(因为它将尝试绑定到 bond0):
客户:
modprobe bonding mode=broadcast
ifconfig bond0 10.10.0.2 netmask 255.255.255.0 up
如果需要,您可以在此处添加一些路由,但请确保从另一侧也完成所有正确的路由。
route add -net 10.7.0.0/24 gw 10.10.0.1
服务器:
modprobe bonding mode=broadcast
ifconfig bond0 10.10.0.1 netmask 255.255.255.0 up
创建一个 /etc/openvpn/tap-up.sh 脚本(并且不要忘记使用 chmod a+x tap-up.sh 将其标记为可执行):
#!/bin/sh
# called as: cmd tap_dev tap_mtu link_mtu ifconfig_local_ip ifconfig_netmask [ init | restart ]
ifenslave bond0 "$1"
接下来,将 bridge0a.conf 和 bridge0b.conf 连同共享密钥一起添加到 /etc/openvpn/。a 和 b 的文件相同,只是端口不同(例如,b 使用 3002)。将 11.22.33.44 替换为您服务器的公共 IP。
客户:
remote 11.22.33.44
dev tap
port 3001
rport 3001
secret bridge.key
comp-lzo
verb 4
nobind
persist-tun
persist-key
script-security 2
up /etc/openvpn/tap-up.sh
服务器:
local 11.22.33.44
dev tap
port 3001
lport 3001
secret bridge.key
comp-lzo
verb 4
script-security 2
up /etc/openvpn/tap-up.sh
不要忘记编辑 /etc/defaults/openvpn 以确保您的新 VPN 配置已启动。重新启动您的机器,或加载 rc.local 并手动重新启动 openvpn。
现在您可以测试您的设置了:
# ping 10.10.0.1
PING 10.10.0.1 (10.10.0.1) 56(84) bytes of data.
64 bytes from 10.10.0.1: icmp_req=1 ttl=64 time=50.4 ms
64 bytes from 10.10.0.1: icmp_req=1 ttl=64 time=51.1 ms (DUP!)
64 bytes from 10.10.0.1: icmp_req=1 ttl=64 time=51.1 ms (DUP!)
64 bytes from 10.10.0.1: icmp_req=1 ttl=64 time=51.1 ms (DUP!)
64 bytes from 10.10.0.1: icmp_req=2 ttl=64 time=52.0 ms
64 bytes from 10.10.0.1: icmp_req=2 ttl=64 time=52.2 ms (DUP!)
64 bytes from 10.10.0.1: icmp_req=2 ttl=64 time=53.0 ms (DUP!)
64 bytes from 10.10.0.1: icmp_req=2 ttl=64 time=53.1 ms (DUP!)
--- 10.10.0.1 ping statistics ---
2 packets transmitted, 2 received, +6 duplicates, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 50.428/51.786/53.160/0.955 ms
如果一切顺利,线路良好,你会看到四对每个 ICMP 包进行回复:您的包在本地端被复制,对这两个包的回复在远程端再次被复制。这对于 TCP 连接来说不是问题,因为 TCP 会忽略所有重复的包。
这是 UDP 数据包的问题,因为处理重复数据包取决于软件。例如,DNS 查询将产生四个回复,而不是预期的两个回复(并且响应使用的带宽是正常带宽的四倍,而不是两次):
# tcpdump -i bond0 -n port 53
listening on bond0, link-type EN10MB (Ethernet), capture size 65535 bytes
13:30:39.870740 IP 10.10.0.2.59330 > 10.7.0.1.53: 59577+ A? serverfault.com. (33)
13:30:40.174281 IP 10.7.0.1.53 > 10.10.0.2.59330: 59577 1/0/0 A 64.34.119.12 (49)
13:30:40.174471 IP 10.7.0.1.53 > 10.10.0.2.59330: 59577 1/0/0 A 64.34.119.12 (49)
13:30:40.186664 IP 10.7.0.1.53 > 10.10.0.2.59330: 59577 1/0/0 A 64.34.119.12 (49)
13:30:40.187030 IP 10.7.0.1.53 > 10.10.0.2.59330: 59577 1/0/0 A 64.34.119.12 (49)
祝你好运!