1,6
рейтинг
16 апреля 2011 в 13:18

Администрирование → Linux + 2 ISP. И доступность внутреннего сервера через обоих провайдеров

Есть замечательная статья, в которой рассказывается, как это делается на Cisco. Но мы не хотим тратить $100500 на приобретение штампованных оттисков «Cisco Systems» на корпусе маршрутизатора.

Описание проблемы

Итак, суть проблемы: имеется два NAT через двух разных провайдеров, локальная сеть, в которой есть сервер и который должен быть публичным и доступным через оба NAT. У провайдеров разные приоритеты: сначала задействуется первый, потом второй.

Если пакет вошёл через первого провайдера, он NAT-ится на наш сервер, обрабатывается, образуется ответный пакет, который выходит через первого провайдера и уходит туда, откуда пришёл первый пакет. Хорошо.

Если пакет вошёл через второго провайдера, он NAT-ится на наш сервер, обрабатывается, образуется ответный пакет, который выходит через первого провайдера… а почему? Потому, что сначала в Linux происходит маршрутизация, а потом уже SNAT. Итак, при маршрутизации пакету назначается следующий узел — шлюз первого провайдера (по умолчанию). Потом происходит отслеживание соединения — conntrack замечает, что этот пакет является ответом на другой, и заменяет адрес отправителя адресом, который выдал нам второй провайдер. А потом пакет направляется через интерфейс первого провайдера на его шлюз. Как правило, провайдер блокирует пакеты, адресом отправителя которых указан адрес не из их подсети. Плохо.


Как должно быть

А нельзя ли как-то поменять порядок — сначала отслеживать, какой нужен провайдер, а потом уже на основании этого выбирать next hop?

Можно. Для этого в Linux есть интерфейс к его отслеживателю соединений — conntrack match и CONNTRACK target. Первый из них — это условие соответствия пакета правилу, согласно которому будут обработаны только те пакеты, в которых специальная метка — метка соединения — имеет определённое значение. Второй — это средство управления меткой соединения.

Метки соединений отличаются от обычных меток пакетов (MARK) тем, что дополнительно обслуживаются и поддерживаются модулем conntrack. Если мы назначаем пакету метку соединения, то в дальнейшем эта метка будет обнаружена на всех пакетах, относящихся к этому же соединению. Отслеживание соединений и восстановление метки происходит после завершения обработки таблицы raw (цепочка PREROUTING или OUPTUT), перед обработкой этих же цепочек таблицы mangle, а запоминание метки соединения в conntrack — в цепочке POSTROUTING после обработки таблицы nat.

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

В Linux есть RPDB — Routing Policy DataBase — это то же самое, что в Cisco называется route-map — база данных политик маршрутизации. При этом, мы создаём несколько разных таблиц маршрутизации, а выбор, по какой из них будет происходить обработка пакета, будет делаться на основании политик. Критериями выбора таблицы могут быть: интерфейс, через который вошёл наш пакет; метка netfilter (nfmark); адрес отправителя; адрес назначения и другие.

Метка netfilter (nfmark) — подходящий для этого случая критерий. Это не то же самое, что метка соединения (ctmark), но что нам мешает установить nfmark на основании ctmark? Напротив, в CONNTRACK target есть специальная команда как раз для этого.

Настройка

Для начала, настроим RPDB. Я не буду назначать таблицам имён — это выходит за рамки темы, тем более, что в данном случае нагляднее будут именно номера.
Правила условной маршрутизации добавляются задаются при поднятии соответствующих интерфейсов, убиваются при останове.

ip rule add fwmark 0x1/0x3 lookup 201
ip rule add from {ip-адрес, связанный с ppp1} lookup 201
ip rule add fwmark 0x2/0x3 lookup 202
ip rule add from {ip-адрес, связанный с ppp2} lookup 202

ip rule add fwmark — это как раз те самые правила: если стоит метка 1, маршрутизируй через 201, если 2 — через 202. Другие два правила — это обычный split-access (как описано в LARTC). Если ни один из критериев не совпадёт, маршрутизация пойдёт по таблице по умолчанию (это справедливо для начальных пакетов соединений, инициированных из локальной сети или на маршрутизаторе).

В таблицы маршрутизации мы (также динамически, при поднятии интерфейсов) добавляем правила:
ip route add default dev ppp2 table 202
ip route add default dev ppp1 table 201
ip route add default dev ppp2 metric 2000
ip route add default dev ppp1 metric 1000

(если у нас не ppp, то правила будут такими: default via {nexthopN} table 20N или metric 2000)
Это, собственно, тоже по LARTC. Метрика задаёт приоритет провайдера (будет выбран маршрут с минимальной метрикой), но для помеченых пакетов будут обрабатываться таблицы 201 и 202 соответственно, в каждой из которых по одному провайдеру.

Осталось начать метить пакеты.
# все пакеты, содержащие метки соединения - идентификаторы внешнего интерфейса
iptables -t mangle -N out-marking
iptables -t mangle -A PREROUTING -m connmark ! --mark 0x0/0x3 -j out-marking
# если пакет вошёл через любой внутренний интерфейс - копируем метку соединения в метку пакета
iptables -t mangle -A out-marking -i eth0 -j CONNMARK --restore-mark --mask 0x3
iptables -t mangle -A out-marking -i eth2 -j CONNMARK --restore-mark --mask 0x3

# все новые соединения
iptables -t mangle -N in-marking
iptables -t mangle -A PREROUTING -m conntrack --ctstate NEW -j in-marking
# пакет вошёл через ppp1 - ставим метку 1, чтобы машрутизация любых ответов пошла по таблице 201
iptables -t mangle -A in-marking -i ppp1 -j CONNMARK --set-xmark 0x1/0x3
# пакет вошёл через ppp2 - ставим метку 2, чтобы маршрутизация любых ответов пошла по таблице 202
iptables -t mangle -A in-marking -i ppp2 -j CONNMARK --set-xmark 0x2/0x3


Нужно обратить внимание на три момента.

Во-первых, вся обработка происходит в цепочке PREROUTING таблицы mangle. Это потому, что мы хотим метить пакеты (поэтому mangle) до того, как произойдёт обработка этих меток при маршрутизации (поэтому PREROUTING).

Во-вторых, задание метки соединения происходит только для головных пакетов (-ctstate NEW) — остальные и так её имеют. Если новый пакет не имеет метки соединения, то его вообще никак обслуживать не надо — он пойдёт по таблице по умолчанию. Это справедливо для всех соединений, инициированных из локалки.

Под «номера провайдеров» задействовано 2 бита, т.е. мы таким способом мы можем сделать 3 аплинка (0 всегда остаётся под «неопределённый провайдер», для таких пакетов будет использоваться маршрут по умолчанию). Поэтому везде метки написаны с маской /0x3 — наши команды никак не будут влиять на все остальные биты меток, и их можно задействовать под другие цели. У меня, например, другие биты задействованы под шейпинг трафика.

А можно и по-другому

Назначаем внутреннему серверу второй адрес. Для этого адреса в rpdb назначаем выход через второго провайдера, и DNAT для пакетов, попавших к нам через второго провайдера, делаем на этот второй адрес.

Проще? В каком-то смысле да. Зато придётся обслуживать по N адресов на внутреннем сервере (по число провайдеров) и N правил DNAT.
Никита Киприянов @merlin-vrn
карма
99,0
рейтинг 1,6
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Администрирование

Комментарии (29)

  • +8
    Это в очередном свете и для конкретного случая обставлена статья LARTC?
    Для тех кто не в курсе, что это за странная аббревиатура LARTC.

    p.s. Всё подобное уже давно изложено в почти старинной статье «Linux Advanced Routing & Traffic Control HOWTO» (на которую автор топика ссылается) — русский перевод имеется на opennet.ru. Вот конкретно по данному вопросу, а вообще статья вся прекрасна.
    • +3
      Конкретно этого в LARTC нет. Если поискать по теме, то найдёте только то, что написано в «а можно и по-другому» (и то не сразу найдёте).

      Здесь изложены оба способа.
    • 0
      Тоже сразу вспомнился LARTC. Уже хотел проглядеть его, пока не почитал комментарии.
      Статья полезная, в закладки, автор спасибо.
      • +1
        LARTC — хорошая штука для начала. Но она очень многое не охватывает, а частично описания устарели.

        Посудите сами — писалось это в 2002-2003 году, а сейчас 2011…
        • 0
          ага, сейчас в моде ospf и bgp с фул вью для юникаст трафика, а не всякие статик маршруты с PBR, но если кто хочет поизвращаться…
          • 0
            что то Вы вспомнили моду из 2002
    • 0
      Тогда топик хороший пример продвижения статьями «Linux Advanced Routing & Traffic Control HOWTO». И это не менее важно, чем знать 1001 способ контроля над сетевыми пакетами.
  • +2
    Отличная статья. Теперь вопрос раскрыт со всех сторон.
    Когда то удалось реализовать подобное на FreeBSD в PF. Если будет кем-то востребовано, постараюсь вспомнить и расписать. Хотя после этой статьи сомневаюсь, что будет спрос. =)
  • –11
    «Но мы не хотим тратить $100500 на приобретение штампованных оттисков «Cisco Systems»» — после этого читать не стал, еще один любитель построить сеть из говна и палок.
    • –3
      Ну да, товарищ то навреное не знает сколько реально стоит 871.
      Вот ему квадриллионы и мерещатся.

      • 0
        Вообще-то знаю и настраивал их. И что? Всё равно в \infty раз дороже линукса.
        • +1
          Ну, линукс то тоже не в воздухе висит.
          • –2
            У красноглазых исключительно в воздухе.:-)

            Сам использую как циски так и линукс, но красноглазие противно.

  • +1
    • 0
      Хм… внезапно как-то сообщение отправилось.
      и 2я ссылка — habrahabr.ru/blogs/sysadm/30076/
    • +1
      Да, действительно, как-то я пропустил эту статью. А когда-то искал, как это делать… В любом случае, там как-то очень наворочено всё, «можно проще».

      Про вторую ссылку сразу: split-access делается элементарно «по LARTC». Вся суть в том, как сделать DNAT, чтобы работало через обоих…
    • 0
      Кстати, там ошибка на картинке, которая и в википедии есть. После цепочки FORWARD нет никакого routing decision. Зато есть rerouting в OUTPUT после mangle.
  • –1
    Есть замечательная статья, в которой рассказывается, как это делается на Cisco. Но мы не хотим тратить $100500 на приобретение штампованных оттисков «Cisco Systems» на корпусе маршрутизатора.

    если для Вас Cisco — всего лишь штампик, сочувствую.
    • 0
      Мне кажется что автор намеренно начал статью с такой провакационного заяления :) Хотя конечно после него мнение об авторе и его статье у многих пользователей будет изначально негативное…
      • +1
        Есть задачи, где действительно нет необходимости в аппаратных решениях уровня Cisco.
        Тогда применяются мелкие сервера и есть необходимость в разных ухищрениях, вроде описанных в этой статье.
        • 0
          Рад что наши мнения по данному вопросу совпадают :) Не очень понятно правда причем тут мой комментарий — я-то про провокационность начала поста :)
          Провакационность заключается в следующем — у любого думающего человека в нашей индустрии есть понимание:
          1. Что разные инструменты предназначены для разного спектра задач (причем эти спектры могут перекрываться);
          2. На выбор конкретного инструмента для решения конкретных задач влияет большое кол-во факторов;

          Соответственно, любой специалист на «приобретение штампованных оттисков «Cisco Systems» на корпусе» отреагирует с некоторым раздражением. Но я предположил, что сочувствовать (как предлагает Илья) автору рано — и что такая фраза вставлена для привлечения внимания к статье, а не из-за того что автор не понимает чем одни инструменты отличаются от других.
      • 0
        если к статье больше нечем привлечь внимание — тоже сочувствую :)
      • 0
        Да вот. Видимо, ирония оказалась слишком тонкой для Хабра :(
    • 0
      Ну простите, я не ожидал, что цискари так обидятся. Честное слово.

      В следующий раз буду политкорректнее.
  • 0
    Уже неделю подряд удивляюсь как в интернете возникают проблемы и просто статьи параллельные с моими проблемами. :)

    В данный момент стоит задача сделать разведение двух ISP, один из которых — только RDP на один комп, второй — весь остальной траффик.

    В данный момент медленно, но верно кручу FreeBSD под это дело via ipfw.
    • 0
      В комментах говорят, что и такое делали. Так что просите статью, для более полного комплекта ;)
    • 0
      Ключевое слово для поиска setfib
    • 0
      Про ipfw не знаю, но pf умеет route-to, это как раз то что нужно. Просто пакеты пришедшие с нужного интерфейса роутить в него обратно.

      pass out route-to (vr1 192.168.1.1) inet from (vr1) to! 192.168.0.0/16 no state
      где 192.168.1.1 — второй роутер(недефолт), а 192.168 включено чтобы траффик локалки через роутер не гоняло

      setfib тут вряд ли поможет
      • 0
        В данный момент изучаю водворение в жизнь через ipfw nat, то бишь «ядерный» NAT FreeBSD.

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

        Спасибо за ответ BTW. :)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.