Цели и средства

  • Имеется два или более каналов интернет, работающие на разных интерфейсах
  • Необходимо объединить эти каналы, увеличив общую скорость интернет, что может быть полезно для программ, создающих множественные подключения (Transmission, aMule и т.д.)
  • В руководстве предлагается 3 способа это сделать. Два из них не требуют дополнительного программного обеспечения, третий предполагает использование пакета patch-o-matic-ng (последний способ не проверен автором данного руководства)

Способ 1

  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

  2. Создать файл /etc/routing/FreeNet.list в него можно дописывать адреса путь к которым будет идти четко через основного провайдера.
  3. Создать и запустить данный скрипт,предварительно отредактировав переменные:

    #!/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

  4. Это рабочее решение в приниципе для любой Linux системы с версией iptables 1.3.8 и выше.


Способ 2

  1. Создаём папку для скриптов:
    sudo mkdir /etc/balance

  2. Для начала определим переменные:

    #!/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"

  3. Добавим в файл /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

  4. Теперь напишем скрипт, который будет прописывать все необходимые маршруты и правила файрвола:

    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

    Этот набор команд обеспечивает маршрутизацию ответов через интерфейс, на котором был получен запрос, а так же маскарадинг на обоих интерфейсах.

  5. Теперь напишем скрипт, который будет определять, работатет ли тот или иной канал и соответственно менять записи шлюза по умолчанию.

    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

Ссылки

Обсуждение

Для обсуждения проблем,связанных с данным руководством,предлагаем Вам создать тему на форуме http://forum.ubuntu.ru (не забудьте,пожалуйста,обновить данную статью и добавить тут ссылку на обсуждение)