![有没有办法优化多个互联网连接上的加密数据包流量?](https://linux22.com/image/1478924/%E6%9C%89%E6%B2%A1%E6%9C%89%E5%8A%9E%E6%B3%95%E4%BC%98%E5%8C%96%E5%A4%9A%E4%B8%AA%E4%BA%92%E8%81%94%E7%BD%91%E8%BF%9E%E6%8E%A5%E4%B8%8A%E7%9A%84%E5%8A%A0%E5%AF%86%E6%95%B0%E6%8D%AE%E5%8C%85%E6%B5%81%E9%87%8F%EF%BC%9F.png)
我想实现这个目标:
- 合并多个互联网连接。
- 加密从本地计算机到远程代理/VPN 服务器的连接。
- 理想情况下,在“可靠”和“速度”模式之间切换(如下所述)。如果这不可能,那么我至少希望能够进行通道绑定(速度)模式。
- 将服务器软件托管在我自己的基础架构上(如专用服务器或 VPS)。
- 理想情况下,该解决方案应该能够在连接到 Linux 服务器的 Windows 客户端上运行。(例如,客户端上运行 Windows 10,服务器上上运行 Ubuntu 14.04 Server。)如果 Linux 客户端必需的,请在您的回答中说明;如果它需要 Linux 客户端,这仍然是一个可以接受的答案,如果必须的话,我总是可以在 VM 中运行它。
我怎样才能做到这一点?
更多详情
可靠模式与速度模式
可靠模式类似于 RAID-1,其中相同的数据包在两个或更多个上行链路上发送,并且第一个到达服务器的数据包被获取,而另一个副本被丢弃。在可靠模式下,您的总吞吐量理论上是快点两个上行链路,但实际上,如果来自较慢上行链路的数据包有时首先到达端点,则数据包会少一些。
速度模式类似于 RAID-0,其中不同的数据包在两个链路上发送,以便您的总吞吐量(例如下载)是两个上行链路吞吐量的总和。
Speedify 使用这种机制,更多信息这里。我可以简单地使用它,但 Speedify 自己的服务不加密数据,并且我的两个上行链路之一是不安全的 WiFi 热点;我需要强加密来保护未加密的应用程序协议(例如访问 superuser.com 的常规 HTTP)。
我的情况
我有两个与公共互联网的连接:
- 通过 USB 适配器作为以太网的 ~12 Mbps LTE 连接(它实际上是 iPhone,但它向操作系统公开为常规以太网)
- 通过 WiFi 热点建立约 5 Mbps LTE 连接,传输至 USB 802.11ac 加密狗
我想要结合具体如下:
Connection A --> Internet --> Server --> Internet Activity
Connection B --> Internet --> Server --> Internet Activity
结局Internet Activity
很危险。我想有两个分离我的本地计算机和之间建立了连接Server
,但只有一个统一Server
与更广泛的公共互联网之间建立的连接。
例如,假设我提交了一个 HTTP 请求,该请求需要 10 个 IP 数据包。也许其中 6 个数据包将通过连接 A 发送,4 个数据包将通过连接 B 发送。该细分将基于每个上行链路的饱和度。这就是 Speedify 所做的,但 Speedify 不会加密任何内容。
这些数据包将按照正确的顺序发送到Server
我试图访问的公共互联网上的任何端点。
然后,当 HTTP 响应从 Web 返回时,它将以 10 个数据包的形式返回,然后这些数据包将被传递Server
并分发回来Connection A
,并Connection B
尽量避免网络拥塞(因此,如果其中一个上行链路有大量数据包丢失或饱和,它将专注于使用另一个上行链路,但如果数据包在两个链路上都通过,它将根据链路速度将它们分配到两个链路上)。
这就是幕后发生的事情的要点。我考虑过使用类似 OpenVPN 的东西。但是,我不知道是否可以或如何配置它来做到这一点。
我的问题
我并不是在寻找一份可能有用的软件建议列表。相反,我的问题是如何实现这一点的细节是什么?
答案1
在发布这个问题后不久,我在谷歌搜索中切换了一些术语,并找到了以下精彩的博客文章:http://simonmott.co.uk/vpn-bonding
这篇文章很长,提供了实现此功能所需的所有信息。但是,作者所采用的方法存在一个重大缺陷。通过 SSH 隧道,他使隧道传输TCP. Ack。这意味着如果你通过隧道传输 TCP,那么你就得到了 TCP 之上的 TCP。如果出现任何明显的延迟或数据包丢失,TCP 堆栈就会变得混乱,并开始崩溃两个都TCP 协议栈尝试处理拥塞控制算法、重传等。这严重限制了你的吞吐量,除非你仅有的在隧道内使用类似 UDP 的东西(这意味着您无法访问 Web)。
文章确实提到,它可以与 ssh 以外的其他隧道等效地工作,并且他是对的。我决定使用 OpenVPN 的点对点功能。由于它使用静态密钥,因此安全性不是很高,但对于我的目的来说安全性已经足够好了(几乎只有高级持续性威胁才能破解加密)。
OpenVPN 可以通过 TCP 或...传输。UDP!我们希望将隧道的传输层设为 UDP,因为如果数据包丢失,“内部” TCP 层将处理拥塞控制。如果您在 UDP 内部运行 UDP,则应用程序代码负责处理数据包丢失或延迟,并且往往会很好地处理它。
我遇到了一个重大问题,核回归在 3.13 系列的某个版本中出现了这个问题,目前甚至在 torvalds 的 git master 中也没有解决这个问题。本文没有提到这一点,因为在撰写本文时,回归并不存在。在客户端和服务器上,您都需要使用以下命令重新编译内核此补丁(如果不工作的话,手动操作很简单patch
),或者使用 3.13.0 或更早版本的内核。
为了达到我的目的,我使用了 Debian Wheezy(目前是 Debian 的oldstable
分支)和 3.2 内核作为服务器,因为我不想在 Amazon EC2 t2.nano VPS 上重新编译内核。在客户端(Linux Mint 桌面),我使用了内核重新编译。因此,两种方法都有效。
以下是重新编译内核后进行设置的说明:
您将有四个openvpn
进程:两个在客户端,两个在服务器上。使用 openvpn 2.1 或更高版本,否则这将不起作用。将文件放在 /etc/openvpn 目录中(除非您有自定义sysconfdir
和自定义编译的 openvpn)。
在我的例子中,我有两个独立的 NIC,在服务器上有eth0
和,它们提供两个独立的公共 IP,下面缩写为和。在客户端上,我有和连接到我的 Internet 上行链路,它们的网关(使用和找到)缩写为和。eth1
SERVER_IP1
SERVER_IP2
eth1
wlan0
ifconfig
route -n
GW1
GW2
要创建static.key
,请阅读 OpenVPN手册页。
服务器tun0.conf:
dev tun0
local SERVER_IP1
proto udp
topology p2p
push "topology p2p"
secret static.key
keepalive 30 90
服务器tun1.conf:
dev tun1
local SERVER_IP2
proto udp
topology p2p
push "topology p2p"
secret static.key
keepalive 30 90
客户端tun0.conf:
dev tun0
nobind
remote SERVER_IP1
proto udp
topology p2p
secret static.key
客户端tun1.conf:
dev tun1
nobind
remote SERVER_IP2
proto udp
topology p2p
secret static.key
现在您要在服务器上启动 OpenVPN 实例第一的,然后是客户端。
一旦您拥有tun0
和tun1
都处于连接POINTOPOINT
模式(运行时界面描述中应该会这么说ifconfig
),您就可以设置绑定链接了bond0
。
我假设您使用的是 Debian、Ubuntu 或其分支的配置文件。/etc/sysconfig/network-scripts/ifcfg-bond0
如果我没记错的话,您可以在基于 CentOS/RHEL 的系统上进行等效配置。您必须调整该操作系统的配置语法。随着 systemd 及其网络守护程序的引入,情况可能会在不久的将来发生重大变化。
无论如何,将其添加到/etc/network/interfaces
服务器上:
iface bond0 inet static
address 172.26.0.1
netmask 255.255.255.252
bond-slaves tun0 tun1
bond_mode balance-rr
在客户端上:
iface bond0 inet static
address 172.26.0.2
netmask 255.255.255.252
bond-slaves tun0 tun1
bond_mode balance-rr
在继续之前,请确保ifenslave
命令行上的命令有效。如果不是,请从包管理器安装它,使用类似 的命令sudo apt-get install ifenslave
。
另外还要确保取消注释说 的行#net.ipv4.ip_forward=1
,如果您不想在更改后重新启动,/etc/sysctl.conf
则可能必须这样做。echo 1 > /proc/sys/net/ipv4/ip_forward
/etc/sysctl.conf
这是我为客户端编写的启动脚本;您必须替换几个占位符值(SERVER_IP1、SERVER_IP2、GW1、GW2eth1
等wlan0
)才能使其为您工作。
做不是将172.26.0.1
/替换172.26.0.2
为任何内容;这些是任意选择的私有 IP,分别对应于服务器的 bond0 链接和客户端的 bond0 链接。
#!/bin/bash
modprobe bonding
modprobe tun
iptables -F
#Force connecting to each of the two server IPs through the separate Internet uplinks you have
ip route add SERVER_IP1 via GW1 dev eth1
ip route add SERVER_IP2 via GW2 dev wlan0
#Connect to OpenVPN - this establishes the tunnel interfaces
sleep 1
screen -mdS tun0 openvpn --config /etc/openvpn/tun0.conf
sleep 1
screen -mdS tun1 openvpn --config /etc/openvpn/tun1.conf
sleep 5
#The next line should be all you need, but I find it doesn't work on Linux Mint, it just hangs after partially configuring the interface. Works fine on Debian Wheezy though.
ifup bond0 >& /dev/null &
sleep 5
killall ifup >& /dev/null
ifconfig bond0 up >& /dev/null
#If the ifup script doesn't do its job (it fails on certain Debian OSes depending on the version of your ifenslave program), we have to manually set it up - the next few lines take care of that
ifconfig bond0 172.26.0.2 netmask 255.255.255.252
sleep 2
echo '+tun0' > /sys/class/net/bond0/bonding/slaves
echo '+tun1' > /sys/class/net/bond0/bonding/slaves
#Clear the default gateway and set it to the bond interface
#Required regardless of whether you had to manually configure bond0 above or not
ip route del 0.0.0.0/0
ip route add 0.0.0.0/0 via 172.26.0.1 dev bond0
#Use fair queue controlled delay active queue management for managing multiple TCP flows simultaneously - prevents webpages from loading horribly slowly while you have a download going - requires a recent kernel (3.2 or later should suffice)
tc qdisc add dev bond0 root fq_codel
#DEBUGGING
#On client and server:
#ifconfig bond0, make sure IPs are assigned
#iptables -F on client (don't need any rules)
#cat /sys/class/net/bond0/bonding/slaves - make sure tun0 and tun1 are there
#ifdown bond0; modprobe bonding; ifup bond0 then re-set-up the slaves and IPs
这是服务器脚本。它看起来应该与客户端脚本非常相似,只是您必须进行一些iptables
数据包转发才能将数据包发送到 Internet 上行链路和 bond0 接口。
幸运的是,不服务器脚本中的占位符...!只需复制、粘贴并运行即可。(呃,除非您的客户端连接的两个接口恰好不是eth0
和eth1
。)
#!/bin/bash
#The next line should be executed before you start doing anything on the client; or you can set openvpn to automatically start on system boot if you prefer.
/etc/init.d/openvpn start
sleep 1
ifup bond0
sleep 1
#Not necessary if your ifenslave script is working properly, but I had to add them manually
echo '+tun0' > /sys/class/net/bond0/bonding/slaves
echo '+tun1' > /sys/class/net/bond0/bonding/slaves
#I honestly have no idea what this line does, but it's in the original blog post and it seems to be required :/
ip route add 10.0.0.0/8 via 172.26.0.2 dev bond0
iptables -A POSTROUTING -t nat -o eth0 -j MASQUERADE
iptables -A POSTROUTING -t nat -o eth1 -j MASQUERADE
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
#Optional, but again, the best active queue management around - see client script for details
tc qdisc add dev bond0 root fq_codel
#This gets inserted automatically at some point along the way; 169.254 is defined as unroutable so you definitely don't want that hanging around in there. Could be an artifact of using Amazon EC2, so this may error out for you with a "No such process" error if you don't get this route.
ip route del 169.254.0.0/16
...就是这样。
快吗?嗯……有点。目前我对性能并不满意,但它的速度肯定比两个链接中较慢的那个要快,而且我使用方便的工具iptraf
确定当我将负载放在默认网关上时,wlan0
和eth1
都在发送和接收 UDP 数据包(例如通过访问网站)。我正在研究以 MTU、MSS、接收缓冲区等方式进行可能的调整,以提高性能并优化吞吐量。