Настройка роутинга для домашнего multihomed сервера

  • Tutorial
Сейчас наличие нескольких подключений к интернет на одном, в том числе и домашнем сервере — не редкость. Городские локалки, ADSL, 3G модемы… Добавим к этому сети домашние локальные и внешние виртуальные (VPN), и получим ядрёную смесь интерфейсов, между которыми необходимо роутить трафик, балансировать трафик между разными каналами в интернет (когда они есть), и переключаться с нерабочих каналов на рабочие (когда они отваливаются).

Судя по постам в инете, большинство людей, столкнувшихся с этой ситуацией, очень плохо представляет себе, как это настраивается. Надо отметить, что в линухе действительно управление роутингом весьма сложное и запутанное — следствие эволюционного развития и поддержки (частичной) совместимости. Я хочу описать принципы настройки роутинга multihomed серверов на конкретном, достаточно сложном, примере: на сервере три физических сетевых интерфейса (один в домашнюю локалку и два к ADSL-модемам), два ADSL-подключения (ADSL-модемы в режиме bridge, так что pppd поднимает этот же сервер) к разным провайдерам (одно со статическим IP, второе с динамическим), плюс VPN на сервер компании — итого шесть интерфейсов.

Тема достаточно сложная, поэтому для понимания материала потребуется хотя бы минимальное понимание работы роутинга (что такое default route и gateway), файрвола (маркировка пакетов, отслеживание соединений, связь между разными таблицами и цепочками файрвола и роутингом), pppd (скрипты ip-up/ip-down) и протоколов IP и TCP.

Общая конфигурация и постановка задачи


Итак, у нас есть три сетевых интерфейса:
  • eth0 (192.168.0.2), подключён к первому ADSL модему (192.168.0.1)
  • eth1 (192.168.1.2), подключён к второму ADSL модему (192.168.1.1)
  • eth2 (192.168.2.1), подключён к домашней локальной сети (192.168.2.x) и является шлюзом в инет для этой локалки
Ещё два интерфейса появляются когда устанавливается подключение к инету через ADSL:
  • ppp0 (s.s.s.s), статический IP через первый ADSL модем к первому провайдеру (8Mbps)
  • ppp1 (d.d.d.d), динамический IP через второй ADSL модем к второму провайдеру (2Mbps)
И, при наличии хоть одного из подключений к интернет, добавляется ещё один интерфейс:
  • tun0 (v.v.v.v), статический IP через VPN на сервер компании
Необходимо реализовать:
  • доступ с сервера и домашней локалки в инет при наличии любого из ADSL соединений
  • балансирование трафика между ADSL соединениями если доступны оба, в соответствии с шириной каналов
  • VPN должен быть поднят через любое ADSL соединение, а если доступны оба, то через первого провайдера (канал шире)
  • почта должна отправляться через первого провайдера (там статический IP привязанный к моему домену)
  • доступ к веб-сайту со статистикой и контрольной панелью второго провайдера должен идти через второй ADSL (провайдер закрыл доступ к своему сайту снаружи)
Итак, вы все эти соединения уже настроили, можете по одному поднять/опустить любые из них, если поднято только одно ADSL-соединение то всё работает отлично… осталось настроить только multihoming.

Немного теории


Для настройки роутинга раньше (да и сейчас — в простых случаях) использовалась команда route. Про неё можете забыть — такие настройки делаются только через команду ip (из пакета iproute2), а одновременное использование и ip и route ничего кроме неприятностей не принесёт. Во времена команды route, таблица роутинга была одна. Сейчас таблиц роутинга несколько (и одна из них — main — та самая, с которой работает команда route). Эти таблицы перечислены в /etc/iproute2/rt_tables:

# cat /etc/iproute2/rt_tables
#
# reserved values
#
255     local
254     main
253     default
0       unspec
#
# local
#
#1      inr.ruhep

Просмотреть их содержимое можно командой ip route list table <имятаблицы>. В таблице local нет ничего интересного — там правила link-local роутинга через имеющиеся интерфейсы; в таблице main основные правила роутинга; таблица default по умолчанию пустая; таблица unspec (к которой так же можно обратиться как all) выводит все правила роутинга из всех существующих таблиц.
Для создания новых таблиц необходимо добавить их имена в этот файл (точнее, это необходимо только для обращения к своим таблицам по именам — по номерам к ним можно обращаться и так).

# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
127.0.0.0       127.0.0.1       255.0.0.0       UG    0      0        0 lo
192.168.0.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth1
192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 eth2
# ip route list table main
127.0.0.0/8 via 127.0.0.1 dev lo  scope link 
192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.2 
192.168.1.0/24 dev eth1  proto kernel  scope link  src 192.168.1.2 
192.168.2.0/24 dev eth2  proto kernel  scope link  src 192.168.2.1 

Как только у нас оказалось больше одной таблицы роутинга, понадобился и механизм, с помощью которого возможно выбрать используемую таблицу роутинга — его зовут правила роутинга (RPDB, routing policy database). Основное преимущество этого механизма — возможность выбирать роутинг не только на базе адреса назначения (как делала команда route и делает ip route ...), но и по другим критериям (исходный адрес, интерфейс, поля tos, fwmark, ...). Работает это так: вы указываете (через команду ip rule ...) любое количество правил в формате «критерии->таблица роутинга». Если для данного пакета критерии в правилах роутинга совпадут, и в указанной таблице роутинга найдётся маршрут для этого пакета (на базе адреса назначения), то оно выполнится; а если не найдётся, то мы возвращаемся в правила роутинга и проверяем другие варианты. Вот как выглядят правила роутинга по умолчанию:

# ip rule list
0:      from all lookup local 
32766:  from all lookup main 
32767:  from all lookup default

Первая колонка — приоритет; правила просматриваются в порядке увеличения приоритета. Эти правила означают, что сначала просматривается таблица local (где link-local правила роутинга), потом таблица main (которой вы обычно управляли через команду route) и где обычно указан default route — т.е. на этом выполнение правил роутинга останавливается, потом (если в main не был указан default route) таблица default (пустая по умолчанию).

Вот простой пример, как всем этим хозяйством можно воспользоваться для того, чтобы пакеты с адреса домашней локалки 192.168.2.100 обрабатывались с помощью отдельных правил роутинга, отличных от роутинга по умолчанию (дадим ему доступ только к первому ADSL-модему и в интернет через первого провайдера):

# echo '100 local100' >> /etc/iproute2/rt_tables
# ip route add 192.168.0.0/24 dev eth0 table local100
# ip route add default via <шлюз_первого_провайдера> dev ppp0 table local100
# ip rule add from 192.168.2.100 lookup local100 priority 5
# ip route list table local100
192.168.0.0/24 dev eth0  scope link 
default via <шлюз_первого_провайдера> dev ppp0
# ip rule list
0:      from all lookup local 
5:      from 192.168.2.100 lookup local100 
32766:  from all lookup main 
32767:  from all lookup default

Теперь немного о файрволе. С его помощью тоже возможно влиять на роутинг.

Как вы видите на схеме, пакеты от, например, локальных приложений проходят через этап «Routing Decision» дважды. Насколько я понимаю, первый раз это происходит в момент создания пакета, для того, чтобы определить для него исходящий интерфейс и исходящий IP (которые могут проверять правила файрвола, так что они должны быть уже известны когда пакет попадает в файрвол), плюс повторно роутинг для этого пакета вычисляется после выполнения цепочки MANGLE файрвола, которая могла изменить любые поля пакета, что могло повлиять на роутинг этого пакета.

В нашем случае самый простой способ влиять на роутинг через файрвол — изменять в цепочке MANGLE поле fwmark пакета, а потом с помощью правил роутинга выбирать таблицу роутинга на базе значения поля fwmark пакета (для этого потребуется создать несколько таблиц роутинга с разными правилами — например, в одной таблице прописать default route через одного провайдера, а в другой — через другого провайдера).

Настройка роутинга: конечный результат


Путь к этому конечному результату местами тернист (баги особенности pppd и openvpn не дают расслабиться) и поэтому будет описан ниже. А пока давайте посмотрим, что нам требуется получить.

Балансировка между двумя провайдерами

Для начала, настроим одновременное использование обоих провайдеров, с балансированием нагрузки в соотношении 8 к 2 (соответственно ширине каналов). Этот способ выбирает роутинг для каждого отдельного адреса назначения — т.е. если соединение изначально пошло через первого провайдера, то все его пакеты будут уходить только через первого провайдера, и все последующие соединения на этот адрес ещё некоторое время будут уходить только через этого провайдера. Балансировка не по соединениям а по пакета делается иначе, и будет работать только если у нас несколько соединений к одному провайдеру.

# ip route replace default scope global \
    nexthop via <шлюз_isp1> dev ppp0 weight 8 \
    nexthop via <шлюз_isp2> dev ppp1 weight 2

Т.к. ядро кеширует информацию о связи адресов назначения и выбранного для них роутинга по умолчанию, то может потребоваться сбросить этот кеш (чтобы ядро снова, с вероятностью 8 к 2, выбрало роутинг по умолчанию для этого адреса назначения):

# ip route flush cache

Ручной выбор канала для конкретных соединений

Т.к. в некоторых случаях нам необходимо контролировать, через какой из внешних каналов отправить пакет, создадим для каждого канала отдельную таблицу роутинга со своим default route:

# echo '1 isp1' >> /etc/iproute2/rt_tables
# echo '2 isp2' >> /etc/iproute2/rt_tables
# echo '3 vpn' >> /etc/iproute2/rt_tables
# ip route add default via <шлюз_isp1> dev ppp0 table isp1
# ip route add default via <шлюз_isp2> dev ppp1 table isp2
# ip route add default via <шлюз_vpn> dev tun0 table vpn

Теперь добавим правила роутинга так, чтобы с помощью файрвола выставив нужные значения fwmark мы могли выбрать нужную таблицу роутинга:

# ip rule add priority 100 fwmark 0x4/0x4 lookup vpn
# ip rule add priority 101 fwmark 0x1/0x1 lookup isp1
# ip rule add priority 102 fwmark 0x2/0x2 lookup isp2

Значение 0x4/0x4 (значение/маска) означает, что из поля fwmark будут взяты биты по маске 0x4 (т.е. только третий бит) которые должны совпасть со значением 0x4. Т.е. в fwmark должен быть выставлен третий бит чтобы сработало правило для таблицы vpn, а остальные биты значения не имеют. Такой подход позволяет в файрволе выставить несколько битов в fwmark, указав таким образом несколько «подходящих» каналов для этого пакета. Приоритет этих каналов (если они все доступны) задаётся приоритетом правил роутинга. Если какой-то канал недоступен, то соответствующая таблица роутинга всё-равно будет просмотрена, но в ней не окажется default route, поэтому произойдёт возврат к следующим правилам роутинга и будет найден следующий подходящий канал.

Все эти команды пока что ни на что не повлияли — файрвол fwmark не выставляет, значит правила роутинга для таблиц isp1, isp2 и vpn не срабатывают, а по умолчанию роутинг как и раньше определяется таблицей main:

# ip route list   ### "table main" можно не указывать
<шлюз_vpn> dev tun0  proto kernel  scope link  src <v.v.v.v> 
<шлюз_isp1> dev ppp0  proto kernel  scope link  src <s.s.s.s>
<шлюз_isp2> dev ppp1  proto kernel  scope link  src <d.d.d.d> 
192.168.2.0/24 dev eth2  proto kernel  scope link  src 192.168.2.1 
192.168.1.0/24 dev eth1  proto kernel  scope link  src 192.168.1.2 
192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.2 
127.0.0.0/8 via 127.0.0.1 dev lo  scope link 
default 
        nexthop via <шлюз_isp1>  dev ppp0 weight 8
        nexthop via <шлюз_isp2>  dev ppp1 weight 2
# ip route list table isp1
default via <шлюз_isp1> dev ppp0
# ip route list table isp2
default via <шлюз_isp2> dev ppp1
# ip route list table vpn
default via <шлюз_vpn> dev tun0
# ip rule list
0:      from all lookup local 
100:    from all fwmark 0x4/0x4 lookup vpn 
101:    from all fwmark 0x1/0x1 lookup isp1
102:    from all fwmark 0x2/0x2 lookup isp2
32766:  from all lookup main 
32767:  from all lookup default

Теперь мы можем указать, что доступ к веб-сайту со статистикой и контрольной панелью второго провайдера должен идти через второй ADSL:

# iptables -t mangle -A OUTPUT -d <ip_сайта_isp2>/32 -j MARK --set-mark 0x2

Если необходимо, чтобы эти правила работали не только для пакетов исходящих с нашего сервера, но и для пакетов из домашней локалки, то необходимо все эти правила в файрвол добавлять не только в цепочку OUTPUT, но и в цепочку FORWARD.

Ответ с того же интерфейса

Всё это будет отлично работать пока речь идёт только об исходящих соединениях. Но ведь у нас сервер… а к серверу бывают и входящие соединения. Допустим, у нас поднят веб-сайт на статическом IP s.s.s.s (канал первого провайдера). Теперь, если админ второго провайдера с сервера <ip_сайта_isp2> захочет заглянуть (через lynx) на наш веб-сайт, у него ничего не выйдет! Дело в том, что он пошлёт запрос на наш IP s.s.s.s (на котором веб-сайт) через канал нашего первого провайдера, а ответ на этот запрос наш сервер отправит через канал второго провайдера (и, соответственно, с адреса d.d.d.d — у нас ведь, разумеется, настроен SNAT/MASQUERADE пакетов исходящих через интерфейсы ppp0, ppp1 и tun0) — согласно настройкам файрвола, которые мы только что сделали: пакеты на адрес <ip_сайта_isp2> отправлять через канал второго провайдера. Веб-браузер админа, пославший запрос на адрес s.s.s.s никак не ожидает получить ответ с адреса d.d.d.d, так что работать это не будет.

Чтобы решить эту проблему, необходимо гарантировать ответы на входящие соединения с того интерфейса, с которого изначально были приняты пакеты. Для этого, к сожалению, придётся использовать отслеживание соединений файрволом (conntrack) для выставления fwmark (connmark). К сожалению — потому, что conntrack это большая сложная и глючная фигня, но выбора здесь нет. Делается это так (эти правила надо добавить в файрвол первыми, ДО правил устанавливающих fwmark вроде описанного выше):

# iptables -t mangle -A INPUT -i ppp0 -j CONNMARK --set-mark 0x1
# iptables -t mangle -A INPUT -i ppp1 -j CONNMARK --set-mark 0x2
# iptables -t mangle -A INPUT -i tun0 -j CONNMARK --set-mark 0x4
# iptables -t mangle -A INPUT -i eth+ -j CONNMARK --set-mark 0x8
# iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
# iptables -t mangle -A OUTPUT -m mark ! --mark 0x0 -j ACCEPT

Здесь мы маркируем входящие пакеты (точнее, соединения, к которым они относятся) согласно интерфейсам, с которых они пришли. Причем значение fwmark (точнее, connmark) выбираем такое, чтобы оно соответствовало таблице роутинга, через которую нужно отправлять ответы на эти пакеты (1,2,4 — для isp1, isp2 и vpn; 8 — это не используемый в правилах роутинга fwmark, т.е. пакеты с этим fwmark будут отправлены согласно обычному роутингу в таблице main — для пакетов из локальных сетей это вполне подходит).

На роутинг входящих пакетов эта маркировка никак не влияет, но это позволяет нам фактически привязать эту маркировку ко всем пакетам этого соединения, в т.ч. исходящим пакетам. Далее, для исходящих пакетов на этом же соединении (ответов на входящие пакеты) мы устанавливаем значение fwmark в то же значение, которое было у входящих пакетов и которое привязано к этому соединению (точнее, копируем значение connmark в fwmark). И если в результате у исходящих пакетов значение fwmark оказывается установлено (не 0), значит все последующие правила установки fwmark для выбора исходящего канала применять нельзя — этот пакет необходимо отправить через тот же интерфейс, через которых пришёл входящий пакет, поэтому останавливаемся (-j ACCEPT).

Итого, корректный вариант настройки файрвола согласно нашей постановке задачи выглядит так:

# iptables -t mangle -A INPUT -i ppp0 -j CONNMARK --set-mark 0x1
# iptables -t mangle -A INPUT -i ppp1 -j CONNMARK --set-mark 0x2
# iptables -t mangle -A INPUT -i tun0 -j CONNMARK --set-mark 0x4
# iptables -t mangle -A INPUT -i eth+ -j CONNMARK --set-mark 0x8
# iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
# iptables -t mangle -A OUTPUT -m mark ! --mark 0x0 -j ACCEPT
# iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 25 -j MARK --set-mark 0x1
# iptables -t mangle -A OUTPUT -d <ip_сервера_vpn>/32 -p udp -m udp --dport 1130 -j MARK --set-mark 0x1
# iptables -t mangle -A OUTPUT -d <ip_сайта_isp2>/32 -j MARK --set-mark 0x2

Вместе с настройками правил и таблиц роутинга мы получаем именно то, что нам требовалось. Осталось разобраться, как эти настройки устанавливать в динамике, с учётом того, что каналы могут падать и подниматься.

Тернистый путь к конечному результату


Честно говоря, статья получилась и так немаленькая, поэтому дополнительно загромождать её своими ip-up/down скриптами, как собирался, я сейчас не буду. Если кто-то попросит в комментариях — добавлю в статью позже. А сейчас кратко опишу основные задачи и проблемы, возникшие при реализации вышеописанных настроек.
  • pppd не умеет сам поднимать множественный default route, поэтому его необходимо запускать с опцией nodefaultroute, и устанавливать default route ручками в /etc/ppp/ip-{up,down} скриптах (или пользовательских скриптах, вызываемых автоматически из этих скриптов — в разных дистрибутивах это настроено по-разному).
    • Поскольку каналы поднимаются по одному, то в момент вызова скрипта ip-up может не быть никакого default route (этот канал поднялся первым) и тогда он должен установить обычный одиночный default route через этот канал; а может уже существовать default route через другой канал (этот канал поднялся вторым), и тогда ему нужно заменить одиночный default route на двойной (с nexthop-ами и weight) — это делается в таблице роутинга main.
    • Так же необходимо добавить одиночный default route через этот канал в соответствующую таблицу роутинга (isp1 или isp2).
    • В скрипте ip-down, по логике, надо проделать обратную операцию (если отключился один из двух каналов, то нужно двойной default route заменить на обычный через оставшийся канал, если отключился последний канал то нужно вообще удалить default route)… Но на практике pppd сам удаляет default route, даже если он был двойной и даже если pppd запускался с опцией nodefaultroute (вероятно, это баг в pppd). Поэтому задача в ip-down обратная: если это был не единственный канал, то поднять обычный default route через оставшийся канал. К сожалению, здесь тоже не всё просто: pppd удаляет default route параллельно с выполнением скрипта ip-down, т.е. возникает race condition! Так что в ip-down надо сначала дождаться, пока pppd удалит default route, а уже потом поднимать его снова.
    • После внесения изменений в роутинг (и в ip-up и в ip-down) не помешает сделать ip route flush cache.
    • Ещё одно: оба канала могут подниматься/падать одновременно, и их ip-up/down скрипты тоже могут сработать одновременно. Чаще всего это будет приводить к race condition и порче default route. :) Поэтому необходимо обеспечить блокировку при запуске этих скриптов, гарантирующую, что только один из них будет работать в один момент времени — проще всего это реализовать через утилиту chpst из пакета runit или утилиту setlock из пакета daemontools.
  • openvpn тоже умеет вызывать пользовательские up/down скрипты...
    • В up необходимо добавить одиночный default route через этот канал в соответствующую таблицу роутинга (vpn).
    • После внесения изменений в роутинг (и в up и в down) не помешает сделать ip route flush cache.
    • В down в этой конфигурации ничего не требуется (default route из таблицы vpn будет удалён ядром автоматически когда упадёт этот канал), но если что-то потребуется сделать, то имейте в виду, что up скрипт запускается от root, а down от юзера openvpn (или какого вы там указали в настройках openvpn) (это вероятно тоже баг), а юзер openvpn обычно не имеет достаточно прав чтобы управлять роутингом (приходится использовать sudo).
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 46

    +1
    Прекрасная статья. Интересно
      –4
      Мне вот больше интересна статистика: 18 плюсов и 30 человек добавили статью в избранное. Это уже какой то верх цинизма %) Взять себе возьму, но спасибо не скажу! =)
        +5
        У некоторых не хватает кармы, чтобы поставить плюс, но в избранное добавить можно.
          0
          именно
          –2
          Я, например, добавил в избранное, так как скоро предвидится подобная проблема и материал данной статьи может оказаться полезен. Но саму статью сейчас полностью не читал (за ненадобностью), и оценить ее качество не могу.
            0
            Поэтому и не поставил плюс.
        +1
        Благодарю!
          +1
          Еще можно же адресах поднять ДНС, чтобы он с каждого адреса выдавал этот же адрес, домен
          example.com
          в списке его NS серверов должны быть 3 адреса разных интерфейсов сервера, примчем при ДНС запросе к первому адресу ДНС отвечает что домен на первом адресе, и т.д. на всех адресах.
          Время жизни надо сделать минимальным.

          Таким образом при падении какого-либо из каналов запросы к ДНС на адреса, работающие на этом канале поступать не будут, а будут поступать к работающим адресам и клиенты, соответственно, в качестве адреса сайта будут получать рабочий адрес.
            +5
            Ответ с того же интерфейса

            Вместо
            # iptables -t mangle -A INPUT -i ppp0 -j CONNMARK --set-mark 0x1

            можно использовать всё тот же iproute2:
            ip rule add dev ppp0 table isp1

            либо
            ip rule add from s.s.s.s table isp1


            P.S. habrahabr.ru/blogs/sysadm/30076/ :)
              +7
              К сожалению, вариант через ip rule from/dev вместо CONNMARK не работает совместно с управлением роутингом через fwmark. Т.е. если у Вас правила роутинга вот такие:

              # ip rule list
              0: from all lookup local
              200: from v.v.v.v lookup vpn
              201: from s.s.s.s lookup isp1
              202: from s.s.s.s lookup isp2
              32766: from all lookup main
              32767: from all lookup default

              То всё будет работать без CONNMARK, но Вы не сможете управлять роутингом конкретных соединений — к примеру, нельзя будет настроить доступ к сайту со статистикой второго провайдера через второй канал. Дело в том, что если сделать правила для fwmark более приоритетными, чем правила ответа через тот же интерфейс:

              # ip rule list
              0: from all lookup local
              100: from all fwmark 0x4/0x4 lookup vpn
              101: from all fwmark 0x1/0x1 lookup velton
              102: from all fwmark 0x2/0x2 lookup ukrtel
              200: from v.v.v.v lookup vpn
              201: from s.s.s.s lookup isp1
              202: from s.s.s.s lookup isp2
              32766: from all lookup main
              32767: from all lookup default

              То возникнет старая проблема — если с IP сервера статистики второго провайдера будет отправлен запрос на мой веб-сайт на s.s.s.s (канал первого провайдера), то из-за высокого приоритета правил fwmark ответ серверу статистики с моего веб-сайта уйдёт через канал второго провайдера, с IP d.d.d.d.

              Если сделать эти правила менее приоритетными:

              # ip rule list
              0: from all lookup local
              200: from v.v.v.v lookup vpn
              201: from s.s.s.s lookup isp1
              202: from s.s.s.s lookup isp2
              300: from all fwmark 0x4/0x4 lookup vpn
              301: from all fwmark 0x1/0x1 lookup velton
              302: from all fwmark 0x2/0x2 lookup ukrtel
              32766: from all lookup main
              32767: from all lookup default

              То, вспоминая про первый этап «Routing Decision» для локальных исходящих пакетов, получится, что когда с моего сервера отправляется любой запрос (например, на сервер статистики второго провайдера), для него вычисляется исходящий интерфейс (и исходный IP!), причём вычисляется он правилами по умолчанию, а там двойной default route — так что будет случайно выбран один из провайдеров. И это, с вероятностью 8 к 2, окажется первый провайдер (и, соответственно, исходящий IP для этого пакета будет выставлен ядром в s.s.s.s). Далее, несмотря на то, что я добавлю к этому пакету в файрволе fwmark 0x2, во время второго этапа «Routing Decision» сработают более приоритетные правила по from, а не по fwmark — а from у нашего пакета с вероятностью 8 к 2 это s.s.s.s, так что пакет на сервер статистики второго провайдера скорее всего уйдёт через канал первого провайдера.

              Если погуглить, то в инете чаще всего встречается именно предложенное Вами решение через ip rule from, но нигде не описаны ограничения этого подхода.
                0
                Вах, спасибо за такой ответ.
              –2
              Имея 2 адсл-модема, поднимать 2 pppoe соединения бриджем — нелогично.
                0
                Почему?
                  –2
                  2 лишних интерфейса, у которых к тому же траблы с нумерацией, лишние if-up-down скрипты, лишние проверки доступности связи. Некритично, но и удобств не доставляет. Особенно при необходимости настройки гибкой маршрутизации с автоматическим переключением каналов и их мониторингом.
                    0
                    Траблы с нумерацией отсутствуют в принципе: параметр unit для pppd позволяет указать номер ppp-интерфейса поднимаемого этим pppd, так что мой канал второго провайдера всегда поднимается как ppp1, даже если интерфейса ppp0 в системе сейчас нет.

                    Проверки доступности связи отсутствуют — хватает переключения default route в ppp up/down скриптах. А, собственно, как Вы реализуете автоматическое переключение с одного канала на другой, если модемы в режиме router, а не bridge, и ведущие к ним eth0 и eth1 всегда доступны? Пинговать и, опять же, ручками менять default route? По-моему, up/down скрипты проще и эффективнее.

                    Далее, у меня всё-таки сервер, на котором поднято немало разных сервисов, и настраивать ручками форвардинг всех этих портов на модеме я не жажду.

                    Кроме того, я из соображений безопасности предпочитаю, чтобы черви и хакеры из инета долбились в мой, регулярно обновляемый, Hardened Gentoo, а не в древний линух на дешёвых ADSL модемах. В «Хакере» как раз недавно была статья на тему, «Троян в роутере», так что количество атак на модемы только увеличится.

                    Ну и последнее — у модемов в режиме router нередко возникают проблемы под большой нагрузкой, вроде торрентов — соединений много, трафик высокий, а проц слабый, памяти мало, и баги в прошивке. В режиме bridge баги в прошивке модема и его мощность уже не имеют никакого значения.
                      –1
                      Параметр unit задает не номер интерфейса, а точку отсчета нумерации интерфейса. Так что канал второго провайдера запросто может подняться как ppp2.

                      В кроне скрипт проверяет доступность ближайшего шлюза провайдера и dns гугла по ip. В случае проблем срабатывают скрипты, меняющие роутинг. На pppoe случается такое, что и интерфейс есть (если бриджем настроено), и вроде все хорошо, а связи на самом деле нет.

                      На модемах я dmz выставляю — слишком слабая начинка, чтобы на нее полагаться.

                      С dmz черви будут долбиться в генту :)

                      С последним согласен, хуавей этим грешит.
                        0
                        У канала первого провайдера задан unit 0, у второго unit 1, и они всегда поднимаются под этими номерами. И, кстати, я не вижу в доке фразы про «точку отсчёта».

                        У меня проблем конкретно с pppoe не было. Бывало, что у самого провайдера лежит инет, это да. Но это случается настолько редко, и длится так недолго, что я даже не всегда это замечаю, и автоматизировать процесс желания пока не возникало. Если всё совсем плохо — я просто ручками кладу соединение к этому провайдеру, несколько часов работаю через оставшийся канал, потом поднимаю второй канал снова. Да, это ручками, но это приходится делать пару раз в год. А вот задержки/потери пингов — вещь гораздо более обычная, так что при автоматическом мониторинге могут быть ложные срабатывания и отрубания вполне рабочих каналов. Например, у меня настроен мониторинг доступности некоторых сайтов по схеме: раз в минуту делается ping -c1, если три минуты подряд сайт не ответил, отправить админу уведомление. Так вот, я эти уведомления получаю достаточно регулярно, хотя сайты в 98% случаев работают (просто пинги теряются).

                        У меня D-Link 500T и 2500U, на них DMZ вроде бы нет.
                          –1
                          Насчет «точки отсчета» — из личного опыта.
                            0
                            И на 500T и на 2500U есть возможность сделать DMZ. Лично я предпочитаю пользоваться именно установлением соединения на модеме (если это не PPTP), и включать DMZ на сервер. Учитывая скорости DSL-соединений, проблем с падениями соединения практически нет. А вот дефолтный pppd на linux (конкретно на Gentoo) при активном использовании уж очень сильно грузит процессор (на фре такого не наблюдал, кстати). Поэтому, когда я у себя реализовывал подобное, то предпочел разнести функции подключения по модемам. Они напрягутся не сильно, а лишняя производительность на сервере (он же торрентокачалка, он же файлохранилка, он же UPnP/DLNA-сервер и т.д.) никогда не помешает.
                          0
                          Можно наоборот избавиться от eth0 и eth1, оставив ppp интерфейсы. Подключение настраивал через pppoeconfig.
                    –1
                    исправьте название топика=)
                      +1
                      А какой дистрибутив вы использовали для примера?
                        +1
                        У меня Gentoo, но абсолютно всё описанное в статье применимо на любом дистрибутиве. Единственное, что в разных дистрибутивах отличается — это имена файлов, куда необходимо поместить описанные в статье команды: скрипт выполняющийся при загрузке системы (настройка ip rule), файл с правилами файрвола восстанавливающимися при загрузке системы, файлы up/down скриптов для pppd и openvpn.
                          0
                          Ну тогда ясно, почему все так подробно и доходчиво расписано. Спасибо.
                        +1
                        Огромное спасибо автору. Я как раз вчера пытался выполнить такую-же задачу. Лично у меня не получалось запустить корректно оба vpn соединения. Теперь все работает. Еще раз большое спасибо.
                          0
                          Отлично, значит уже не зря статью писал!
                          +1
                          Отличная статья! Тоже интересовался настройкой Linux на работу с двумя каналами, и писал потом по мотивам статью на хабр, правда у меня было не так детально расписано и без картинок. Зато с отказостойчивостью
                            0
                            Спасибо за просвещение!
                              0
                              Отличная статья. Единственное не пойму, что она делает на хабре? Всё-таки более логичней было бы разместить её на opennet. Хабр это же не howto сайт, а новостной…

                              В любом случае спасибо за старания.
                                +4
                                :)) Вы не поверите, но хабр уже не торт. Когда-то я пришёл на хабр именно потому, что здесь было много больших и интересных авторских статей, ПЛЮС новости. Вы это время уже не застали. А вчера вечером я долго листал главную хабра в поисках хоть одной статьи из «Linux для всех» — но видел по большей части новости, причём из блогов компаний (особенно яндекса). Оказалось, что статей из «Linux для всех» на главной не было больше недели. Я решил, что это неправильно, и попытался исправить ситуацию в меру своих сил.
                                0
                                Отлично. У меня 2 вопроса.

                                Может подкините идею как реализовать то же самое, но с одним провайдером и IP шлюза одинаковые.
                                Мне не хватает пропускной способности одного канала при этом другого провайдера нет и в обозримом будущем не будет. Пока что реализовал двумя модемами в режиме роутера.

                                И второй вопрос, при использовании nexthop иногда слетает авторизация на сайтах, т.к. меняется маршрут на другой канал. Решали такую задачу?
                                  0
                                  С двумя каналами к одному провайдеру можно всё делать точно так же. Теоретически, в этом случае можно вообще объединить два канала в один (и делать более точную балансировку нагрузки по пакетам, а не по адресам назначения), но я подозреваю, что это потребует поддержки со стороны провайдера, а он врядли будет ради Вас заморачиваться (впрочем, лично я это никогда не настраивал, так что могу ошибаться).

                                  Задача слетающей авторизации решается добавлением для таких сайтов в файрвол индивидуальных правил, выбирающего для них один из интерфейсов (через fwmark, как обычно) — как я сделал в статье для сайта со статистикой второго провайдера. Если таких сайтов 2-3 штуки, это сделать проще всего. Если их очень много, и правила в файрвол на каждый писать нереально — тогда не знаю, наверное надо копать в сторону настройки в ядре размера кеша маршрутов (который сбрасывается через ip route flush cache) или, что более надёжно, в сторону выставления файрволом fwmark для всех исходящих соединений на базе хеша от адреса назначения — у iptables вполне может найтись подходящий модуль (обычно такие вещи используются для балансировки нагрузки, и как побочный эффект можно получить закрепление за каждым сайтом своего канала).
                                    0
                                    Провайдер частному лицу не будет помогать. ИМХО.
                                    Не так давно ковырялся в L2TP корбины, так там шлюза по умолчанию нет.
                                    «default dev ppp0 scope link»
                                  0
                                  Отлично! Сам подумываю, но реализовывать скорей всего буду на роутере прямо…

                                  Одно но: по правилам хорошего тона — локалка обычно запускается на 192.168.0.x — второй байт начинают трогать если сетка оченнь сильно большая…
                                    0
                                    Я знаю, но… во-первых адреса в статье просто для примера, реальные у меня немного отличаются; во-вторых когда я в ~1994 году начинал изучать линух и роутинг, правила хорошего тона ещё отсутствовали, и я исторически привык к 192.168.2; в-третьих сильно раздражает, что адрес 192.168.0.x любит автоматически выставлять на интерфейсе винда при включении ICS (что особенно грустно в ситуации, когда инет расшаривается для интерфейса VMware), поэтому я стараюсь ни на одном реальном интерфейсе этот адрес не ставить, во избежание лишних конфликтов; в-четвёртых адрес 192.168.1.1 по умолчанию ставят на ADSL модемы — так что первый «безопасный» вариант для локалки получается как раз 192.168.2.
                                      0
                                      именно. адсл модемы длинк по умолчанию ставят 192.168.1.х, а роутеры длинк 192.168.0.х, потому у меня дома сеть начинается с 192.168.2.х. а про правила хорошего тона это бред какой-то, моя сеть — делаю как мне удобно и нравится.
                                    0
                                    А как обстоят дела с производительностью при маркеровке пакетов? Через шлюз, на очень слабенькой машинке (целерон 1800), ходят в интернет порядка 80 пользователей. Сейчас вся маршрутизация только средствами iproute2. Как видно iproute2 + fwmark — дает много больше возможностей.
                                      0
                                      может перенести в блог Системное администрирование
                                        0
                                        В руководстве по iptables на opennet.ru, в схеме прохождения пакетов через файервол, отмечено всего 2 «routing decisions», в отличии от вашей схемы. Немогли бы вы дать источник вашей иллюстрации. Спасибо.
                                          0
                                          Протупил, схема вставленна прямо из источника, как я понимаю.
                                            0
                                            Угу. На opennet версия этой доки устарела (1.1.19) и отстала от реальности на несколько лет. Вот почему доку лучше читать сразу на английском (текущая версия 1.2.2).
                                            +1
                                            Мне теперь ваша статья покоя не дает, а поэксперементировать смогу только в субботу. Выложите, если возможно, ваши скрипты pppd: ip-up, ip-down, посмотреть как реализованны блокировки.
                                              +1
                                              В Gentoo пользовательские ip-up/down скрипты предполагается класть в /etc/ppp/ip-{up,down}.d/90-local.sh:

                                              # cat /etc/ppp/ip-up.d/90-local.sh
                                              #!/bin/sh
                                              chpst -l /etc/ppp/.lock /etc/ppp/ip-up.local.safe "$@"
                                              # cat /etc/ppp/ip-down.d/90-local.sh
                                              #!/bin/sh
                                              chpst -l /etc/ppp/.lock /etc/ppp/ip-down.local.safe "$@"
                                              # cat /etc/ppp/ip-up.local.safe
                                              #!/bin/sh
                                              [ "$1" == "ppp0" ] && table="isp1" || table="isp2"
                                              ip route add default via $5 dev $1 table $table
                                              ...здесь должна быть установка одиночного/множественного default route...
                                              ip route flush cache
                                              # cat /etc/ppp/ip-down.local.safe
                                              #!/bin/sh
                                              # workaround race condition: pppd will delete default route in parallel
                                              # with executing ip-down script
                                              for i in $(seq 1 10); do
                                                ip route list | grep -q ^default && break
                                                sleep 0.3
                                                [[ $i == 10 ]] && echo "Failed to wait until default route will be deleted"
                                              done
                                              ...здесь должна быть установка одиночного default route если другой канал работает...
                                              ip route flush cache
                                                +1
                                                Благодарю
                                              0
                                              Отличная статья, спасибо.
                                              Настроил вчера два дефолтных шлюза для разных интерфейсов, вот так работает:

                                              ip rule add from 10.0.0.2 lookup t0
                                              ip rule add from 192.168.5.2 lookup t0.51
                                              ip route add default via 10.0.0.254 dev eth0 table t0
                                              ip route add default via 192.168.5.254 dev eth0.51 table t0.51

                                              а если первые два правила переписать с использованием интерфейсов
                                              ip rule add dev eth0 lookup t0
                                              ip rule add dev eth0.51 lookup t0.51
                                              То не работает.

                                              В чем причина, подскажите?
                                              И можно ли такую функциональность реализовать ещё проще?
                                                0
                                                Я предполагаю, что причина в том, что исходящий интерфейс всегда eth0, а алиасы вроде eth0:51 являются только способом повесить на этот интерфейс дополнительные IP, так что указание eth0:51 когда речь идёт о выборе интерфейса эквивалентно указанию eth0.

                                                Далее, если Вы посмотрите вывод ip rule list для варианта через dev, то Вы увидите что вместо dev там указан iif. Судя по документации на iif в ip rule (а dev там вообще не упомянут), он используется для различения локальных и форвардящихся пакетов. Так что моё второе предположение заключается в том, что dev для этой задачи использовать вообще неуместно.

                                                Кроме того, если у вас на 192.168.5.2 будет запущен, например, веб-сервер, и на него придёт запрос из сети 10.0.0.x, то ответ на этот запрос будет отправлен некорректно (ответ в сеть 10.0.0.x пойдёт через шлюз 192.168.5.254). Другие ограничения настройки через from описаны в одном из предыдущих комментов.

                                                Так что я бы рекомендовал всё-таки настроить так, как описано в статье, через fwmark. Хотя для простых случаев Ваш вариант через from тоже сработает.

                                              Only users with full accounts can post comments. Log in, please.