all*_*tic 8 networking openvpn
我想实现这一点:
我该怎么做?
可靠模式就像 RAID-1,在两个或多个上行链路上发送相同的数据包,到达服务器的第一个数据包被获取,而另一个副本被丢弃。在可靠模式下,理论上您的总吞吐量是两个上行链路中较快的一个,但如果来自较慢上行链路的数据包有时首先到达端点,则实际上会少一些。
速度模式类似于 RAID-0,其中不同的数据包通过两条链路发送,因此您的总吞吐量(例如下载)是两条上行链路的吞吐量之和。
Speedify 使用这种机制,更多信息在这里。我可以简单地使用它,除了 Speedify 自己的服务不加密数据,而且我的两个上行链路之一是不安全的 WiFi 热点;我需要强大的加密来保护本身没有加密的应用程序协议(如访问 superuser.com 的常规 HTTP)。
我有两个连接到公共互联网:
我想将它们组合如下:
Connection A --> Internet --> Server --> Internet Activity
Connection B --> Internet --> Server --> Internet Activity
Run Code Online (Sandbox Code Playgroud)
在Internet Activity
结束是它得到冒险。我想在我的本地计算机和 之间建立两个单独的连接Server
,但在更广泛的公共 Internet之间建立一个统一的连接Server
。
例如,假设我提交了一个 HTTP 请求,该请求需要 10 个 IP 数据包。或许其中 6 个数据包将通过连接 A 发送,4 个通过连接 B 发送。细分将基于每个上行链路的饱和水平。这就是 Speedify 所做的,但 Speedify 不加密任何东西。
这些数据包将以正确的顺序从Server
我试图到达的公共 Internet 上的任何端点发送。
然后,当 HTTP 响应从 Web 返回时,它将作为 10 个数据包返回,然后将这些数据包传递Server
并分发回Connection A
并Connection B
以一种试图避免网络拥塞的方式(因此,如果其中一个上行链路有大量数据包丢失或饱和,它将专注于使用另一个上行链路,但如果数据包在两条链路上都通过,它将根据链路速度将它们分布在两条链路上)。
这就是幕后发生的事情的要点。我考虑过可能使用 OpenVPN 之类的东西。但是,我不熟悉是否或如何配置它来做到这一点。
我不是在寻找可能有用的软件建议列表。相反,我的问题是如何实现这一目标的细节是什么?
发布这个问题一段时间后,我在谷歌搜索中切换了一些术语,发现了以下博客文章的精华: http: //simonmott.co.uk/vpn-bonding
这篇文章很长,提供了实现此功能所需的所有信息。然而,作者所采用的方法存在一个重大缺陷。通过 SSH 建立隧道,他使隧道传输TCP。确认。这意味着如果您通过隧道建立 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
并且eth1
在服务器上提供两个独立的公共 IP(下面缩写为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
Run Code Online (Sandbox Code Playgroud)
服务器tun1.conf:
dev tun1
local SERVER_IP2
proto udp
topology p2p
push "topology p2p"
secret static.key
keepalive 30 90
Run Code Online (Sandbox Code Playgroud)
客户端tun0.conf:
dev tun0
nobind
remote SERVER_IP1
proto udp
topology p2p
secret static.key
Run Code Online (Sandbox Code Playgroud)
客户端tun1.conf:
dev tun1
nobind
remote SERVER_IP2
proto udp
topology p2p
secret static.key
Run Code Online (Sandbox Code Playgroud)
现在您要首先在服务器上启动 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
Run Code Online (Sandbox Code Playgroud)
在客户端:
iface bond0 inet static
address 172.26.0.2
netmask 255.255.255.252
bond-slaves tun0 tun1
bond_mode balance-rr
Run Code Online (Sandbox Code Playgroud)
在继续之前,请确保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
Run Code Online (Sandbox Code Playgroud)
这是服务器脚本。一般来说,它看起来应该与客户端脚本非常相似,只是您必须执行一些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
Run Code Online (Sandbox Code Playgroud)
...就是这样。
快吗?嗯……有点。在这一点上,我并没有对性能感到震惊,但它确实比两个链接中较慢的链接提供了更好的速度,并且我使用方便的工具iptraf
来确定当我加载负载时,wlan0
和正在发送和接收 UDP 数据包eth1
默认网关(例如通过访问网站)。我正在研究可能的 MTU、MSS、recv 缓冲区等调整方式,以提高性能并优化吞吐量。
归档时间: |
|
查看次数: |
797 次 |
最近记录: |