Через некоторое время после публикации этого вопроса я переключил некоторые термины в своих поисках в Google и нашел следующую жемчужину сообщения в блоге: http://simonmott.co.uk/vpn-bonding
Статья длинная и предоставляет всю информацию, необходимую для работы. Однако в подходе автора есть существенный недостаток. Туннелируя по SSH, он делает туннель транспортным TCP. Ack. Это означает, что если вы туннелируете TCP через туннель, вы получаете TCP поверх TCP. С какой - либо значительной задержки или потери пакетов на всех, TCP стека будет запутаться и начать метаться , как и TCP стека попытка справиться с алгоритмами управления перегрузкой, повторных передач и т.д. Это существенно ограничивает вашу пропускную способность, если вы не будете использовать только что - то вроде UDP внутри Туннель (что означает, что вы не можете получить доступ к Интернету).
В статье упоминается, что она будет работать аналогично туннелю с чем-то иным, чем ssh, и он прав. Я решил использовать для этого двухточечную функцию OpenVPN. Это не очень безопасно, так как использует статический ключ, но безопасность была достаточно хорошей для моих целей (почти только Advanced Persistent Threats сможет взломать криптографию).
OpenVPN может транспортировать через TCP или ... UDP ! Мы хотим сделать транспортный уровень нашего туннеля UDP, потому что, если пакеты потеряны, "внутренний" уровень TCP будет иметь дело с контролем перегрузки. И если вы запускаете UDP внутри UDP, код приложения отвечает за потерю пакетов или задержку и будет нормально справляться с этим.
Я столкнулся с серьезной проблемой в виде регрессии ядра, которая случилась когда-то во время точечного выпуска серии 3.13, и на данный момент она не решалась даже в git master Торвальдса. Это не упоминается в статье, потому что регрессия не существовала на момент написания статьи. Как на вашем клиенте, так и на сервере вам нужно будет либо перекомпилировать ядро с этим патчем (достаточно просто применить вручную, если patch
отказывается работать), либо использовать версию ядра 3.13.0 или более раннюю.
Для своих целей я использовал Debian Wheezy (в настоящее время ветвь oldstable
ветки Debian) с ядром 3.2 для сервера, потому что я не хотел перекомпилировать свое ядро на VPS Amazon EC2 t2.nano. На стороне клиента (рабочий стол 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
Сервер 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 или их форк для файлов конфигурации. Вы можете выполнить эквивалентную настройку для систем на базе CentOS/RHEL в /etc/sysconfig/network-scripts/ifcfg-bond0
, если я правильно помню. Вам придется настроить синтаксис конфигурации для этого вида ОС. И все может значительно измениться в ближайшем будущем с внедрением 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, GW2, eth1
и wlan0
и т. д.), чтобы они работали на вас.
Не заменять 172.26.0.1
/ 172.26.0.2
с чем - нибудь; это произвольно выбранные частные IP-адреса, которые соответствуют ссылке на связь сервера 0 и ссылку на связь клиента соответственно.
#!/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
чтобы получить пакеты в и из вашей интернет-линии связи и интерфейса 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, буфера recv и т.д., Чтобы повысить производительность и оптимизировать пропускную способность.