Цели и средства
- Имеется два или более каналов интернет, работающие на разных интерфейсах
- Необходимо объединить эти каналы, увеличив общую скорость интернет, что может быть полезно для программ, создающих множественные подключения (Transmission, aMule и т.д.)
-
В руководстве предлагается 3 способа это сделать. Два из них не требуют дополнительного программного обеспечения, третий предполагает использование пакета patch-o-matic-ng (последний способ не проверен автором данного руководства)
Способ 1
-
Настройка iproute2 : Создать в /etc/iproute2/rt_tables две таблицы для каждого из провайдеров:
sudo nano /etc/iproute2/rt_tables
# # reserved values # 255 local 254 main 253 default 0 unspec # # local # #1 inr.ruhep 101 FreeNet 102 NLine
- Создать файл /etc/routing/FreeNet.list в него можно дописывать адреса путь к которым будет идти четко через основного провайдера.
-
Создать и запустить данный скрипт,предварительно отредактировав переменные:
#!/bin/sh ################### CONFIG ############ FreeNet="/etc/routing/FreeNet.list" ### Home Network l_eth=eth2 l_ip=192.168.5.1 l_net=192.168.5.0/24 ########### Local ISP Network ######### li_net=10.0.0.0/8 ########### ISP1 ###################### i1_eth=eth0 i1_ip=89.252.20.173 i1_net=89.252.20.0/24 i1_gw=89.252.20.1 ########### ISP2 ###################### i2_eth=eth1 i2_ip=10.1.2.161 i2_net=10.0.0.0/16 i2_gw=10.1.0.1 #########ip route2 tables############## t1=101 t2=102 ####################################### ########### Flushing ################## iptables -t mangle -F NEW_OUT_CONN iptables -t mangle -F PREROUTING iptables -t mangle -F OUTPUT iptables -t mangle -X NEW_OUT_CONN ip route flush table $t2 ip rule del table $t2 ip route flush table $t1 ip rule del table $t1 ip route flush cache ####################################### iptables -t mangle -N NEW_OUT_CONN iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 1 iptables -t mangle -A NEW_OUT_CONN -m statistic --mode random --probability 0.50 -j RETURN iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 2 for file in $FreeNet; do if [ -f "$file" ]; then { cat "$file" ; echo ; } | while read ip_addr; do if [ "$ip_addr" != "" ]; then echo "Статическая маршрутизация для $ip_addr" iptables -t mangle -A NEW_OUT_CONN -d $ip_addr -j CONNMARK --set-mark 1 fi done fi done iptables -t mangle -A PREROUTING -d $l_net -j RETURN iptables -t mangle -A PREROUTING -d $li_net -j RETURN iptables -t mangle -A PREROUTING -s $l_net -m state --state new,related -j NEW_OUT_CONN iptables -t mangle -A PREROUTING -s $l_net -j CONNMARK --restore-mark iptables -t mangle -A OUTPUT -d $l_net -j RETURN iptables -t mangle -A OUTPUT -d $li_net -j RETURN iptables -t mangle -A OUTPUT -s $l_net -m state --state new,related -j NEW_OUT_CONN iptables -t mangle -A OUTPUT -s $li_net -j CONNMARK --restore-mark ip route add $l_net dev $l_eth scope link table $t1 ip route add $i2_net dev $i2_eth scope link table $t1 ip route add $i1_net dev $i1_eth scope link src $i1_ip table $t1 ip route add 127.0.0.0/8 dev lo scope link table $t1 ip route add default via $i1_gw table $t1 ip rule add prio 51 fwmark 1 table $t1 ip rule add from $i1_ip table $t1 ip route add $l_net dev $l_eth scope link table $t2 ip route add $i1_net dev $i1_eth scope link table $t2 ip route add $i2_net dev $i2_eth scope link src $i2_ip table $t2 ip route add 127.0.0.0/8 dev lo scope link table $t2 ip route add default via $i2_gw table $t2 ip rule add prio 52 fwmark 2 table $t2 ip rule add from $i2_ip table $t2 ip route flush cache
- Это рабочее решение в приниципе для любой Linux системы с версией iptables 1.3.8 и выше.
Способ 2
-
Создаём папку для скриптов:
sudo mkdir /etc/balance
-
Для начала определим переменные:
#!/bin/bash # LAN interface IF0="eth1" # WAN interface 1 IF1="eth0" # WAN interface 2 IF2="ppp0" IP1="194.9.xx.xx" IP2="`ip addr show $IF2 | grep inet | awk '{print $2}'`" # gateway 1 P1="194.9.xx.xx" # gateway 2 P2="195.5.xx.xx" # LAN netmask P0_NET="192.168.0.0/24" # WAN1 netmask P1_NET="194.9.xx.xx/xx" # WAN2 netmask P2_NET="195.5.xx.xx/xx" TBL1="provider1" TBL2="provider2" # Realtive weight of channels bandwidth W1="2" W2="1"
-
Добавим в файл /etc/iproute2/rt_tables две дополнительные таблицы маршрутизации:
sudo nano /etc/iproute2/rt_tables
# # reserved values # 255 local 254 main 253 default 0 unspec # # local # #1 inr.ruhep 1 provider1 2 provider2
-
Теперь напишем скрипт, который будет прописывать все необходимые маршруты и правила файрвола:
sudo nano /etc/balance/routing.sh
#!/bin/bash . /etc/balance/vars echo "1" > /proc/sys/net/ipv4/ip_forward ip route add $P1_NET dev $IF1 src $IP1 table $TBL1 > /dev/null 2>&1 ip route add default via $P1 table $TBL1 > /dev/null 2>&1 ip route add $P2_NET dev $IF2 src $IP2 table $TBL2 > /dev/null 2>&1 ip route add default via $P2 table $TBL2 > /dev/null 2>&1 ip route add $P1_NET dev $IF1 src $IP1 > /dev/null 2>&1 ip route add $P2_NET dev $IF2 src $IP2 ip route add default via $P1 > /dev/null 2>&1 ip rule add from $IP1 table $TBL1 > /dev/null 2>&1 ip rule add from $IP2 table $TBL2 > /dev/null 2>&1 ip route add $P0_NET dev $IF0 table $TBL1 > /dev/null 2>&1 ip route add $P2_NET dev $IF2 table $TBL1 > /dev/null 2>&1 ip route add 127.0.0.0/8 dev lo table $TBL1 > /dev/null 2>&1 ip route add $P0_NET dev $IF0 table $TBL2 > /dev/null 2>&1 ip route add $P1_NET dev $IF1 table $TBL2 > /dev/null 2>&1 ip route add 127.0.0.0/8 dev lo table $TBL2 > /dev/null 2>&1 iptables -t nat -F POSTROUTING iptables -t nat -A POSTROUTING -s $P0_NET -o $IF1 -j MASQUERADE iptables -t nat -A POSTROUTING -s $P0_NET -o $IF2 -j MASQUERADE
Этот набор команд обеспечивает маршрутизацию ответов через интерфейс, на котором был получен запрос, а так же маскарадинг на обоих интерфейсах.
-
Теперь напишем скрипт, который будет определять, работатет ли тот или иной канал и соответственно менять записи шлюза по умолчанию.
sudo nano /etc/balance/check.sh
#!/bin/bash . /etc/balance/vars OLDIF1=0 OLDIF2=0 . /etc/balance/routing.sh while true; do ping -c 3 -s 100 $P1 -I $IF1 > /dev/null if [ $? -ne 0 ]; then echo "Failed IF1!" NEWIF1=0 else NEWIF1=1 fi ping -c 3 -s 100 $P2 -I $IF2 > /dev/null if [ $? -ne 0 ]; then echo "Failed IF2!" NEWIF2=0 else NEWIF2=1 fi if (( ($NEWIF1!=$OLDIF1) || ($NEWIF2!=$OLDIF2) )); then echo "Changing routes" if (( ($NEWIF1==1) && ($NEWIF2==1) )); then echo "Both channels" ip route delete default ip route add default scope global nexthop via $P1 dev $IF1 weight $W1 \ nexthop via $P2 dev $IF2 weight $W2 elif (( ($NEWIF1==1) && ($NEWIF2==0) )); then echo "First channel" ip route delete default ip route add default via $P1 dev $IF1 elif (( ($NEWIF1==0) && ($NEWIF2==1) )); then echo "Second channel" ip route delete default ip route add default via $P2 dev $IF2 fi else echo "Not changed" fi OLDIF1=$NEWIF1 OLDIF2=$NEWIF2 sleep 3 done
Работу канала проверяем пингуя шлюз, и если нет ответа на 3 пинга подряд — мы считаем, что канал упал, и соответственно исключаем его из таблицы маршрутизации.Таким образом, если работают оба канала:
ip route 195.5.xx.xx dev ppp0 proto kernel scope link src 95.133.xx.xx 194.9.xx.xx/xx dev eth0 proto kernel scope link src 194.9.xx.xx 192.168.0.0/24 dev eth1 proto kernel scope link src 192.168.0.75 default nexthop via 194.9.xx.xx dev eth0 weight 2 nexthop via 195.5.xx.xx dev ppp0 weight 1
Итого имеем два шлюза, первый с весом 2 и второй с весом 1. Тоесть через первый канал пойдет в два раза больше трафика, чем через второй.Для того, чтобы изменить эти скрипты под ваши нужды необходимо настроить значения в файле vars, остальные скрипты практически не требуют настройки.
Способ 3
В следующем примере понадобится пропатченное ядро Linux с поддержкой ROUTE и модулей nth или random.Эти модули предоставляются пакетом patch-o-matic-ng,который нужно скачать с репозитория subversion .О том,как пропатчить ядро и установить требуемый пакет,смотрите прилагающуюся документацию к нему.
Установка
В следующем примере будем считать,что имеется три разных интефейса:
- eth0: Проводное соединение, 192.168.1.0/24, шлюз 192.168.1.1, канал по умолчанию.
- eth1: Беспроводное соединение 1, 172.16.0.0/16, шлюз 172.16.0.1
- rausb0: Бесроводное соединение 2, 192.168.0.0/24, шлюз 192.168.0.1
Мы будем использовать connmark для привязки соединений к конкретному интерфейсу,чтобы определённые пакеты были жёстко привязаны к интерфейсу и шли только через него.Балансировка может быть сделана с помощью модуля nth ,а также random.Мы рассмотрим оба случая,Вы выбирайте тот,который вам больше нравится.
-
Сначала общие команды для обоих методов:
# FIXME (тут нужен точный перевод) # prevent incoming packets on masqueraded connections from being dropped # as "martians" due to the destination address being translated before the # rp_filter check is performed echo 0 > /proc/sys/net/ipv4/conf/eth1/rp_filter echo 0 > /proc/sys/net/ipv4/conf/rausb0/rp_filter # FIXME (тут нужен точный перевод) # Load protocol-specific connection tracking modules so that new connections # associated with existing connections have state "RELATED" and inherit the # same connmark. modprobe ip_conntrack_ftp # Маскарадинг для исходящих соединений на второстепенных интерфейсах iptables -t nat -A POSTROUTING -o eth1 -s ! 172.16.0.0/16 -m state --state NEW,RELATED -j MASQUERADE iptables -t nat -A POSTROUTING -o rausb0 -s ! 192.168.0.0/24 -m state --state NEW,RELATED -j MASQUERADE # Создаём цепочку,обрабатывающую новые исходящие соединения iptables -t mangle -N NEW_OUT_CONN # Пропустить соединения,которые мы хотим,чтобы шли всегда через проводное соединение iptables -t mangle -A NEW_OUT_CONN -d 192.168.1.0/24 -j RETURN iptables -t mangle -A NEW_OUT_CONN -p tcp -m multiport --destination-ports 21,22,80,443,6667 -j RETURN iptables -t mangle -A NEW_OUT_CONN -p udp --dport 53 -j RETURN # новые исходящие соединения проходят через вышеуказанную цепочку правил iptables -t mangle -A OUTPUT -o eth0 -m state --state NEW -j NEW_OUT_CONN # шлём пакеты через выбранный интерфейс iptables -t mangle -A OUTPUT -m connmark --mark 2 -j ROUTE --gw 172.16.0.1 --continue iptables -t mangle -A OUTPUT -m connmark --mark 3 -j ROUTE --gw 192.168.0.1 --continue
-
Метод с помощью random:
# 34% от времени идём через канал по умолчанию iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 0 iptables -t mangle -A NEW_OUT_CONN -m random --average 34 -j RETURN # примерно 33% от времени идём через eth1 (50% от оставшейся вероятности) iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 2 iptables -t mangle -A NEW_OUT_CONN -m random --average 50 -j RETURN # иначе (примерно 33% от времени) идём через rausb0 iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 3
-
Метод с помощью nth:
# Каждое первое из трёх соединений идёт через канал по умолчанию iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 0 iptables -t mangle -A NEW_OUT_CONN -m nth --counter 1 --every 3 --packet 0 -j RETURN # Каждое второе из трёх соединений идёт через eth1 iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 2 iptables -t mangle -A NEW_OUT_CONN -m nth --counter 1 --every 3 --packet 1 -j RETURN # Каждое третье из трёх соединений идёт rausb0 iptables -t mangle -A NEW_OUT_CONN -j CONNMARK --set-mark 3 iptables -t mangle -A NEW_OUT_CONN -m nth --counter 1 --every 3 --packet 2 -j RETURN
-
Предусмотрим случай,когда один из интерфейсов перестаёт работать (на Debian-системах нужно положить этот скрипт в папку /etc/network/if-down.d/ и сделать его исполняемым (chmod +x)):
#!/bin/sh if [ "$IFACE" = "eth1" ]; then iptables -t mangle -D OUTPUT -m connmark --mark 2 -j ROUTE --gw 172.16.0.1 --continue 2>/dev/null fi if [ "$IFACE" = "rausb0" ]; then iptables -t mangle -D OUTPUT -m connmark --mark 3 -j ROUTE --gw 192.168.0.1 --continue 2>/dev/null fi exit 0
-
Теперь скрипт в случае,если интерфейс заработал снова (на Debian-системах нужно положить этот скрипт в папку /etc/network/if-up.d/ и сделать его исполняемым (chmod +x)):
#!/bin/sh if [ "$IFACE" = "eth1" ]; then iptables -t mangle -A OUTPUT -m connmark --mark 2 -j ROUTE --gw 172.16.0.1 --continue 2>/dev/null fi if [ "$IFACE" = "rausb0" ]; then iptables -t mangle -A OUTPUT -m connmark --mark 3 -j ROUTE --gw 192.168.0.1 --continue 2>/dev/null fi exit 0