如何绑定两个(多个)Internet 连接以提高速度和故障转移

leg*_*108 7 vpn internet slow-connection bonding dsl

我们位于有两个慢速 ADSL 连接 (3.5/0.5 Mbps) 的农村地区,并希望通过某种方式“组合”它们来提高连接速度和可靠性。下面描述了我们迄今为止效果很好的解决方案。

因此,这不是我们需要解决的问题,而是一些有用的文档,因为很难找到说明,我希望这可以帮助处于类似情况的其他人。也许比我更先进的人发现了一个我很乐意知道并修复的错误。

该文档是从工作系统编译而来的,必须稍微调整以适应我们所在位置的特定要求,而这些要求与更一般的描述无关。因此,虽然已尽一切努力确保可靠的准确性,但我并没有重做本文档中的全部内容,因此可能存在遗漏或错误的地方。如果它对您不起作用,请发表评论,我会尽力提供帮助。

以下两个来源对使其工作非常有帮助,非常感谢两位作者!

leg*_*108 10

此解决方案将 Linux 以太网绑定应用于从本地网关服务器到您拥有根访问权限的云中服务器(如 Linode 或 DigitalOcean Droplet)的两个独立 OpenVPN 连接。OpenVPN 连接所基于的两个 Internet 连接在透明桥接模式下使用两个 ADSL 路由器,即我们仅使用它们的调制解调器功能并通过以太网上的 PPP (PPPoE) 驱动程序创建连接。并且在绑定连接的两端使用FireHOL实施防火墙。

ADSL 互联网连接绑定

该图提供了概览。LAN PC 连接到网关服务器上的 eth0、192.168.1.1/24。两个路由器通过单独的物理网络接口 eth1 192.168.10.1/24 和 eth2 192.168.11.1/24 连接。(无法使 PPPoE 与 eth0 上的虚拟接口一起工作。)PPPoE 驱动程序为与 ISP 的各个连接创建接口 ppp0 和 ppp1。OpenVPN 绑定到网关服务器的 LAN 侧的 192.168.10.1/24 和 192.168.11.1/24 地址,以及云服务器的 eth0 接口 50.60.70.80/24 的端口 1194 和 1195。然后将这两个 OpenVPN 连接绑定在一起,在 LAN 端创建虚拟接口 10.80.0.2/30,在云服务器端创建虚拟接口 10.80.0.1/30。将云服务器的 10.80.0.1 地址定义为 LAN 上的默认网关'

以下配置基于 Ubuntu Server(这里使用 LAN 侧的 16.04 和 Cloud 侧的 18.04)。所有命令都假定 root 权限。

云服务器端

OpenVPN 隧道

安装最新的 OpenVPN 版本(将bionic18.04替换xenial为 16.04)

cloud-server# wget -O - https://swupdate.openvpn.net/repos/repo-public.gpg|apt-key add -
cloud-server# echo "deb http://build.openvpn.net/debian/openvpn/stable bionic main" > /etc/apt/sources.list.d/openvpn-aptrepo.list
cloud-server# apt update && apt install openvpn
Run Code Online (Sandbox Code Playgroud)

/etc/default/openvpn确保

AUTOSTART="none"
Run Code Online (Sandbox Code Playgroud)

活跃。禁用该服务,隧道将从以下位置进行管理/etc/network/interfaces

cloud-server# systemctl disable openvpn
Run Code Online (Sandbox Code Playgroud)

创建 /etc/openvpn/tap0.conf

# disable encryption, traffic continues unencrypted anyways
auth none
cipher none

dev tap0
mode p2p
port 1194
local 50.60.70.80
proto udp

log /var/log/tap0.log
verb 3

ping 2
ping-restart 10
persist-tun

compress lz4-v2

daemon
Run Code Online (Sandbox Code Playgroud)

并且/etc/openvpn/tap1.conf喜欢/etc/openvpn/tap0.conf除了

dev tap1
...
port 1195
...
log /var/log/tap1.log
Run Code Online (Sandbox Code Playgroud)

Linux 以太网绑定

使用ifupdown网络管理的云服务器上,修改/etc/network/interfaces(调整gateway为您的环境):

auto eth0
iface eth0 inet static
  address 50.60.70.80
  netmask 255.255.255.0
  gateway 50.60.70.1
  post-up /usr/local/bin/vpn-start
  pre-down /usr/local/bin/vpn-stop
Run Code Online (Sandbox Code Playgroud)

可以在以下位置维护绑定设备的选项/etc/modprobe.d/bonding.conf

options bonding mode=0 miimon=100
Run Code Online (Sandbox Code Playgroud)

mode=0 意味着以循环方式使用绑定线路,这应该提供故障转移和速度增强。

以下两个脚本创建/销毁绑定设备。创建/usr/local/bin/vpn-start(和chmod +x):

#!/bin/bash
openvpn --config /etc/openvpn/tap0.conf
openvpn --config /etc/openvpn/tap1.conf

ip link add bond0 type bond
ip addr add 10.80.0.1/30 dev bond0

ip link set tap0 master bond0
ip link set tap1 master bond0

ip link set bond0 up mtu 1440
ip route add 192.168.1.0/24 via 10.80.0.2
Run Code Online (Sandbox Code Playgroud)

您可能需要mtu根据您的环境进行调整。创建/usr/local/bin/vpn-stop(和chmod +x):

#!/bin/bash
ip route del 192.168.1.0/24 via 10.80.0.2
ip link set bond0 down
ip link del bond0

pkill 'openvpn'
Run Code Online (Sandbox Code Playgroud)

防火墙

对于您的防火墙需求,您可以安装FireHOL

cloud-server# apt install firehol
Run Code Online (Sandbox Code Playgroud)

START_FIREHOL=NO/etc/default/firehol,而是创建/etc/systemd/system/firehol.service

[Unit]
Description=FireHOL Stateful Packet Filtering Firewall
Documentation=man:firehol(1) man:firehol.conf(5)

DefaultDependencies=no

Before=network-pre.target
Wants=network-pre.target

Wants=systemd-modules-load.service local-fs.target
After=systemd-modules-load.service local-fs.target

Conflicts=shutdown.target
Before=shutdown.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/firehol start
ExecStop=/usr/sbin/firehol stop

[Install]
WantedBy=multi-user.target
Run Code Online (Sandbox Code Playgroud)

并启用它

cloud-server# systemctl enable firehol
Run Code Online (Sandbox Code Playgroud)

创建/etc/firehol/firehol.conf

version 6

server_vpn_ports="udp/1194-1195"
client_vpn_ports="default"

snat4 to 50.60.70.80 outface eth0 dst not 50.60.70.80

interface eth0 web
  protection strong
  server ssh accept
  server vpn accept
  # more servers here as per your needs
  client all accept

interface bond0 vpn
  policy accept

router4 web2vpn inface eth0 outface bond0 dst 192.168.1.0/24,10.80.0.2
  client all accept
Run Code Online (Sandbox Code Playgroud)

激活和检查

重启云服务器。检查绑定设备:

cloud-server# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011)

Bonding Mode: load balancing (round-robin)
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0

Slave Interface: tap0
MII Status: up
Speed: 10 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: aa:04:0b:ea:33:48
Slave queue ID: 0

Slave Interface: tap1
MII Status: up
Speed: 10 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 1e:70:4f:4b:2a:e8
Slave queue ID: 0
Run Code Online (Sandbox Code Playgroud)

局域网侧

PPPoE 互联网连接

您必须为您的调制解调器找出如何将它们置于透明桥接模式并分配 LAN 地址。使用ifupdown的LAN网关服务器上的网络管理,添加以下内容/etc/network/interfaces

auto eth1
iface eth1 inet static
  address 192.168.10.1
  netmask 255.255.255.0
  network 192.168.10.0
  broadcast 192.168.10.255

auto eth2
iface eth2 inet static
  address 192.168.11.1
  netmask 255.255.255.0
  network 192.168.11.0
  broadcast 192.168.11.255
Run Code Online (Sandbox Code Playgroud)

安装PPPoE驱动:

lan-server# apt update
lan-server# apt install pppoe pppoeconf
Run Code Online (Sandbox Code Playgroud)

创建两个 PPP 配置文件,/etc/ppp/peers/dsl1

plugin rp-pppoe.so eth1
unit 0
user "YourUsername1"
noauth
hide-password
persist
mtu 1492
noipdefault
defaultroute
replacedefaultroute
Run Code Online (Sandbox Code Playgroud)

/etc/ppp/peers/dsl2

plugin rp-pppoe.so eth2
unit 1
user "YourUsername2"
noauth
hide-password
persist
mtu 1492
noipdefault
defaultroute
Run Code Online (Sandbox Code Playgroud)

replacedefaultroutein/etc/ppp/peers/dsl1使此连接成为绑定前的默认 Internet 连接。

/etc/ppp/chap-secrets和 中提供密码/etc/ppp/pap-secrets

"YourUsername1" * "Password1"
"YourUsername2" * "Password2"
Run Code Online (Sandbox Code Playgroud)

确保这两个文件都归root和拥有chmod 600

将以下内容添加到末尾/etc/network/interfaces

auto dsl1
iface dsl1 inet ppp
  provider dsl1

auto dsl2
iface dsl2 inet ppp
  provider dsl2
Run Code Online (Sandbox Code Playgroud)

这将自动建立在配置文件中定义的 PPPoE 连接,它们的名称由provider指令指定。

VPN 隧道和绑定设备由两个脚本管理,这些脚本在两个 PPP 连接出现/断开时运行。创建/etc/ppp/ip-up.d/bond0(和chmod +x):

#!/bin/bash
nPpp=`ls -1 /etc/ppp/peers/* | wc -l`
if [[ `ip addr | grep -E 'ppp[0-9]:' | wc -l` -eq $nPpp ]] && \
    [[ `ip addr | grep -E 'tap[0-9]:' | wc -l` -eq 0 ]]; then
  /usr/local/bin/vpn-start
fi
Run Code Online (Sandbox Code Playgroud)

/etc/ppp/ip-down.d/bond0(和chmod +x):

#!/bin/bash
if [[ `ip addr | grep -E 'ppp[0-9]:' | wc -l` -eq 0 ]]; then
  /usr/local/bin/vpn-stop
fi
Run Code Online (Sandbox Code Playgroud)

有关vpn-*脚本的实现,请参见下文。

OpenVPN 隧道

对于 OpenVPN 安装,像在云服务器上一样进行。OpenVPN 将由在建立/破坏 PPPoE 连接时触发的脚本管理。

创建 /etc/openvpn/tap0.conf

remote 50.60.70.80

auth none
cipher none

dev tap0
mode p2p
port 1194
local 192.168.10.1
proto udp

log /var/log/tap0.log
verb 3

ping 2
ping-restart 10
persist-tun

compress lz4-v2

daemon
Run Code Online (Sandbox Code Playgroud)

并且 /etc/openvpn/tap1.conf喜欢/etc/openvpn/tap0.conf除了

dev tap1
...
port 1195
local 192.168.11.1
...
log /var/log/tap1.log
Run Code Online (Sandbox Code Playgroud)

Linux 以太网绑定

/usr/local/bin/vpn-start( chmod +x) 创建 VPN 隧道,设置绑定设备并创建路由表条目,以确保流量在绑定驱动程序请求时通过正确的通道:

#!/bin/bash
openvpn --config /etc/openvpn/tap0.conf
ip route add 192.168.10.0/24 dev eth1 scope link table dsl1
ip route add default dev ppp0 table dsl1
ip rule add pref 10 from 192.168.10.0/24 table dsl1

openvpn --config /etc/openvpn/tap1.conf
ip route add 192.168.11.0/24 dev eth2 scope link table dsl2
ip route add default dev ppp1 table dsl2
ip rule add pref 11 from 192.168.11.0/24 table dsl2

ip route flush cache

ip link add bond0 type bond
ip addr add 10.80.0.2/30 dev bond0

ip link set tap0 master bond0
ip link set tap1 master bond0

ip link set bond0 up mtu 1440

/usr/local/bin/gw bond0
Run Code Online (Sandbox Code Playgroud)

需要在以下位置声明路由表的名称/etc/iproute2/rt_tables

...
10  dsl1
11  dsl2
Run Code Online (Sandbox Code Playgroud)

确保数字在此配置文件中是唯一的。

mtu需要对应到一个云服务器上配置。

/usr/local/bin/gw( chmod +x) 允许切换默认网关:

#!/bin/bash
newGw=$1
if [[ ! $newGw =~ ^ppp[0-9]$ && $newGw != bond0 ]]; then
  echo "$0 {ppp[0-9]|bond0}"
  exit -1
fi

ip addr show dev $newGw >/dev/null 2>&1
ret=$?
if [[ $ret -ne 0 ]]; then
  echo "$newGw is not available"
  exit -1
fi

via=0.0.0.0
if [[ $newGw == bond0 ]]; then
  via=10.80.0.1
fi
ip route repl default via $via dev $newGw
ip route show
Run Code Online (Sandbox Code Playgroud)

创建/usr/local/bin/vpn-stop( chmod +x):

#!/bin/bash
/usr/local/bin/gw ppp0

ip link set bond0 down
ip link del bond0

pkill 'openvpn'

ip rule del pref 10 from 192.168.10.0/24 table dsl1
ip route del default dev ppp0 table dsl1
ip route del 192.168.10.0/24 dev eth1 scope link table dsl1

ip rule del pref 11 from 192.168.11.0/24 table dsl2
ip route del default dev ppp1 table dsl2
ip route del 192.168.11.0/24 dev eth2 scope link table dsl2

ip route flush cache
Run Code Online (Sandbox Code Playgroud)

如果需要,这两个vpn-*gw脚本当然也可以手动运行。

防火墙

使用以下/etc/firehol/firehol.conf配置在云服务器上安装 FireHOL :

version 6

lan="eth0"
web="ppp+"
vpn="bond+"

tcpmss auto "${web}"
masquerade "${web}"

interface "${lan}" lan
  policy accept

interface "${web}" web
  protection bad-packets
  server ident reject with tcp-reset
  client all accept

interface "${vpn}" vpn
  policy accept

router web2lan inface "${web}" outface "${lan}"
  protection bad-packets
  server ident reject with tcp-reset
  client all accept

router vpn2lan inface "${vpn}" outface "${lan}"
  policy accept
Run Code Online (Sandbox Code Playgroud)

激活和检查

重新启动 LAN Server 并检查绑定设备:

lan-server# cat /proc/net/bonding/bond0
Run Code Online (Sandbox Code Playgroud)

输出应类似于云服务器。

如果您现在在浏览器中导航到https://www.whatsmyip.org/,您应该会看到您的云服务器的 IP 地址。

您可以测试您的速度提高,例如通过运行

lan-server# wget -4 -O /dev/null http://proof.ovh.net/files/1Gio.dat
Run Code Online (Sandbox Code Playgroud)

在这里,我们看到绑定速度仅比各条生产线速度之和低约 5%。

使用链路平衡器进行故障转移

如果 Internet 连接之一出现故障,则绑定设备不会像人们预期的那样继续使用剩余的连接。对于此事件,可以通过设置FireHOL 的 Link Balancer进行准备。

一种方法是通过创建一个合适的/etc/firehol/link-balancer.conf计划/usr/sbin/link-balancer作为 cron 作业定期(例如每 2 分钟)检查连接并在需要时故障转移到仍然可用的内容。link-balancer.conf如果出现故障,以下内容将使 Internet 访问继续在剩余的良好线路上进行:

check_bond0() {
  for dev in ppp0 ppp1 bond0; do
    /sbin/ip addr show dev $dev >/dev/null 2>&1
    ret=$?
    if [[ $ret -ne 0 ]]; then
      break
    fi
  done
  if [[ $ret -eq 0 ]]; then
    /bin/ping -w 8 -c 4 -I 10.80.0.2 10.80.0.1 >/dev/null 2>&1
    ret=$?
  fi
  return $ret
}

gateway bond dev bond0 gw 10.80.0.1 check bond0
gateway dsl1 dev ppp0
gateway dsl2 dev ppp1

table main
  default via bond weight 100
  fallback via dsl1
  fallback via dsl2
Run Code Online (Sandbox Code Playgroud)

绑定连接的默认检查似乎无法可靠地检测其状态,这就是自定义check_bond0.

当坏连接再次恢复时,Link Balancer 将使两个连接成为默认网关,这些网关将基于连接进行平衡。无法通过合理的努力恢复绑定连接,因此在这些极少数情况下,您必须手动重新启动可能的 VPN 两端。