URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID1
Нить номер: 74186
[ Назад ]

Исходное сообщение
"Проблема с выбором таблицы маршрутизации"

Отправлено Эдмон , 21-Май-07 16:38 
Добрый день всем!

Имеется два канала в интернет. И Linux машина, которая их разруливает. Имеем 3 интерфейса. Два на каждого провайдера и один смотрит в сторону локальной сети, в которой находится веб-сервер, к которому собственно и необходимо дать доступ через обоих провайдеров.

eth1 - смотрит в сторону 1го провайдера (назовем его isp1) и имеет адрес 100.0.0.100/24 (default gw = 100.0.0.1)
на этот адрес рутится подсеть 10.10.10.0/24 в которую входит адрес 10.10.10.10/24. 10.10.10.10/24 и является адресом для веб-сервера через 1го провайдера. Этот канал, собственно, и является основным.

eth2 - смотрит в сторону 2го провайдера (назовем его isp2) и имеет адрес 10.20.20.9/24 (default gw = 10.20.20.1), плюс он имеет алиас eth2:1 10.20.20.20/24, который является адресом для веб-сервера через второго провайдера.

eth0 - смотрит в локалку и имеет адрес 10.0.0.1/24, в этой локалке и стоит веб-сервер, который имеет адрес 10.0.0.2/24.


Имеем примерно следующие правила для iptables:
# Пропускаем всех, кто идет на веб-сервер
-A FORWARD -p tcp -m tcp -d 10.0.0.2 -i eth1 -o eth0 --dport 80 -j ACCEPT
-A FORWARD -p tcp -m tcp -d 10.0.0.2 -i eth2 -o eth0 --dport 80 -j ACCEPT

# Меняем адреса в случае, когда веб-сервер идет в инет
-A POSTROUTING -s 10.0.0.0/24 -o eth1 -j SNAT --to-source 10.10.10.10
-A POSTROUTING -s 10.0.0.0/24 -o eth2 -j SNAT --to-source 10.20.20.20

# Меняем адреса, когда клиенты идут на веб-сервер
-A PREROUTING -d 10.10.10.10 -i eth1 -j DNAT --to-destination 10.0.0.2
-A PREROUTING -d 10.20.20.20 -i eth2 -j DNAT --to-destination 10.0.0.2

Далее iproute2:
# Создаю алиас на 2ой интерфейс
ip addr add 10.20.20.20/24 dev eth2 label eth2:1

# Формируем таблицу маршрутизации для 1го провайдера
ip route add 100.0.0.0/24 dev eth1 src 100.0.0.100 table isp1
ip route add 10.0.0.0/24 dev eth0 src 10.0.0.1 table isp1
ip route add 127.0.0.0/8 dev lo table isp1
ip route add default via 100.0.0.1 table isp1

# Формируем таблицу маршрутизации для 2го провайдера
ip route add 10.20.20.0/24 dev eth2 src 10.20.20.9 table isp2
ip route add 10.0.0.0/24 dev eth0 src 10.0.0.1 table isp2
ip route add 127.0.0.0/8 dev lo table isp2
ip route add default via 10.20.20.1 table isp2

# Default GW для Default таблицы
ip route add default via 100.0.0.1 dev eth1

# Правила для isp1
ip rule add from 100.0.0.100 table isp1
ip rule add from 10.10.10.0/24 table isp1

# Правила для isp2
ip rule add from 10.20.20.9 table isp2
ip rule add from 10.20.20.20 table isp2

# Очищаем кэш
ip route flush cache


А проблема, собственно, заключается вот в чем:
Рассматриваем 3-way handshake, клиент пытается установить соединение с веб-сервером через второго провайдера, отправляет SYN сегмент, отслеживаю tcpdump'ом, что адреса сменились (10.20.20.20 -> 10.0.0.2) и сегмент был благополучно доставлен. Теперь веб-сервер отправляет SYN+ACK клиенту. Так же вижу, что адреса нормально преобразовались обратно DNAT'ом (10.0.0.2 -> 10.20.20.20), но уходит сегмент через eth1, а не через eth2, где и благополучно посылается куда подальше. Как не сложно догадаться, где-то что-то не так.
Но вот где именно и что?

Скажу сразу, что пробовал менять:
1. Отказатся от алиасов и сделать, как и в случае с isp1, используя подсети.
2. Отрубить SNAT.
3. Быть может что-то еще, но забыл:-)


Содержание

Сообщения в этом обсуждении
"Проблема с выбором таблицы маршрутизации"
Отправлено perece , 21-Май-07 18:43 
># Правила для isp1
>ip rule add from 100.0.0.100 table isp1
>ip rule add from 10.10.10.0/24 table isp1

># Правила для isp2
>ip rule add from 10.20.20.9 table isp2
>ip rule add from 10.20.20.20 table isp2

приоритеты не указаны. соотв. непонятно, как они соотносятся с уже имевшимся правилом (lookup main)
приоритеты желательно указывать явно, и разные. т.е. даже у логически "равноправных" table isp1 и table isp2.
и еще. для того, чтобы все было "в ажуре" нужно правильно прописать link scope маршруты. в вашем случае в обеих таблицах (isp1 и isp2) должны быть абсолютные копии main, отличающиеся только default гейтом. (opt - на "основного" отдельную таблицу можно не заводить, все равно к нему полетит все, что не улетело к "дополнительному)


Я лично в "многолапой" конфигурации предпочитаю дуплировать маршруты в свои сети в rule table, а в дополнительных таблицах иметь только дефолтгейты. в этом случае "местные" сети прописаны два раза (table main и rule database) вне зависимости от количества линков (в вашей схеме - сколько линков, столько раз таблицу маршрутов и надо скопировать)
пример для вашего случая:
{предполагаю, что на момент начала настройки iproute2 основная таблица выглядит так:
  #ip ro ls
  100.0.0.0/24 dev eth1  proto kernel  scope link  src 100.0.0.100
  10.20.20.0/24 dev eth2  proto kernel  scope link  src 10.20.20.9
  10.0.0.0/24 dev eth0  proto kernel  scope link  src 10.0.0.1
}
ip route add default via 100.0.0.1 table main
ip route add default via 100.0.0.1 table isp1  # необязательно, но чтоб было понятно - их может быть много
ip route add default via 10.20.20.1 table isp2

ip rule add to 100.0.0.0/24 prio 32001 table main
ip rule add to 10.20.20.0/24 prio 32002 table main
ip rule add to 10.0.0.0/24 prio 32003 table main
ip rule add from 100.0.0.0/24 prio 32764 table isp1  # опять же не обязательно т.к. defgw(isp1) == defgw(main)
ip rule add from 10.20.20.0/24 prio 32765 table isp2
#уже есть rule from all prio 32766 table main
#уже есть rule from all prio 32767 table default

\^P^/


"Проблема с выбором таблицы маршрутизации"
Отправлено Эдмон , 21-Май-07 19:10 
> нужно правильно прописать link scope маршруты

это конечно дописать не долго, но вряд ли это может повлиять на выбор таблицы :-(

> приоритеты не указаны

текущее положение дел, вроде нормально выглядит

#ip rule list
0:      from all lookup 255
32762:  from 10.20.20.20 lookup isp2
32763:  from 10.20.20.9 lookup isp2
32764:  from 10.10.10.0/24 lookup isp1
32765:  from 100.0.0.100 lookup isp1
32766:  from all lookup main
32767:  from all lookup default


"Проблема с выбором таблицы маршрутизации"
Отправлено perece , 21-Май-07 19:25 
>#ip rule list
>0:      from all lookup 255
>32762:  from 10.20.20.20 lookup isp2
>32763:  from 10.20.20.9 lookup isp2
>32764:  from 10.10.10.0/24 lookup isp1
>32765:  from 100.0.0.100 lookup isp1
>32766:  from all lookup main
>32767:  from all lookup default
это нужно было сразу запостить, тут нагляднее гораздо
если написать from 10.0.0.2 lookup isp2 то все пойдут через второго. но когда пакет попадает в роутинг - src address еще не странслирован, т.е. именно 10.0.0.2 (не важно, проходил ли пакет через таблицу нат, "встречные" транслируются автоматически по connection tracking'у, но все равно - dst адрес до маршрутизации, а src - _после_ оной).
соотв в твоем неудачном случае - либо разносить полиси роутинг и НАТ на разные хосты, или пробрасывать порт каким-нибудь tcpd или тому подобной "недопроксей". честно этого не сделать.

\^P^/


"Проблема с выбором таблицы маршрутизации"
Отправлено Эдмон , 22-Май-07 02:47 
>когда пакет попадает в роутинг - src address еще не странслирован,
>т.е. именно 10.0.0.2 (не важно, проходил ли пакет через таблицу нат,
>"встречные" транслируются автоматически по connection tracking'у, но все равно - dst
>адрес до маршрутизации, а src - _после_ оной).

Можно ссылку на документацию, где об этом говорится?
На сколько я в курсе "Un-DNAT" происходит так же в PREROUTING.


"Проблема с выбором таблицы маршрутизации"
Отправлено perece , 22-Май-07 09:02 
>>когда пакет попадает в роутинг - src address еще не странслирован,
>>т.е. именно 10.0.0.2 (не важно, проходил ли пакет через таблицу нат,
>>"встречные" транслируются автоматически по connection tracking'у, но все равно - dst
>>адрес до маршрутизации, а src - _после_ оной).
>
>Можно ссылку на документацию, где об этом говорится?
вот здесь http://www.opennet.me/openforum/vsluhforumID9/6352.html#10 я давал ссылку на netfilter hacking howto. "внутренности" помоему лучше не описаны нигде, а для понимания, как оно работает, знание "механики" - лучшее. однако насчет интересующего нас вопроса формулировка там весьма нечеткая:
"... for non-local packets, the NF_IP_PRE_ROUTING and NF_IP_POST_ROUTING hooks are perfect for destination and source alterations respectively."
это следует понимать буквально, типа как юристы законы трактуют. сие означает, что для _любого_ пакета (здесь ведь не говорится ни о каких "ответах", related или чем-нибудь таком) NF_IP_PRE_ROUTING и NF_IP_POST_ROUTING используются для изменения dst и src СООТВЕТСТВЕННО (т.е. NF_IP_PRE_ROUTING для dst и NF_IP_POST_ROUTING для src).
в документации на iptables вы на эту тему не найдете вообще ничего, ибо определяется это отнюдь не таблесами (оно есть лишь средство для заполнения этих таблиц) а самим фреймворком netfilter. это уровень даже ниже ядерных модулей iptables.

>На сколько я в курсе "Un-DNAT" происходит так же в PREROUTING.
вот и неправильно вы понимаете. если допускающая различные трактования формулировка в документации netfilter вас не устраивает, а "логика разработчиков" и здравый смысл вам не указ, то поставьте, в конце концов, парочку экспериментов и убедитесь сами - оно работает именно так, как я сказал. т.е. _все_ src адреса транслируются _после_ маршрутизации (а все dst - до оной).

\^P^/


"Проблема с выбором таблицы маршрутизации"
Отправлено Эдмон , 22-Май-07 12:28 
>если допускающая различные трактования формулировка в документации
>netfilter вас не устраивает, а "логика разработчиков" и здравый смысл вам
>не указ, то поставьте, в конце концов, парочку экспериментов

Здравый смысл и эксперименты подсказывали, что обратная замена адреса происходит в postroute, но ни в документации прямо не сказано, ни в экспериментах проследить явно не удалось, где именно происходит замена, и т.к. результаты были эмпирическими, то теплелась надежда, что все таки в preroute.


"Проблема с выбором таблицы маршрутизации"
Отправлено perece , 22-Май-07 09:40 
>>#ip rule list
>>0:      from all lookup 255
>>32762:  from 10.20.20.20 lookup isp2
>>32763:  from 10.20.20.9 lookup isp2
>>32764:  from 10.10.10.0/24 lookup isp1
>>32765:  from 100.0.0.100 lookup isp1
>>32766:  from all lookup main
>>32767:  from all lookup default
>это нужно было сразу запостить, тут нагляднее гораздо
>если написать from 10.0.0.2 lookup isp2 то все пойдут через второго. но
>когда пакет попадает в роутинг - src address еще не странслирован,
>т.е. именно 10.0.0.2 (не важно, проходил ли пакет через таблицу нат,
>"встречные" транслируются автоматически по connection tracking'у, но все равно - dst
>адрес до маршрутизации, а src - _после_ оной).
>соотв в твоем неудачном случае - либо разносить полиси роутинг и НАТ
>на разные хосты, или пробрасывать порт каким-нибудь tcpd или тому подобной
>"недопроксей". честно этого не сделать.

...
размышляя о дальнейшем возможном ходе дискуссии с Эдмоном придумал решение, которое будет работать в вашем случае (если у вас ядро 2.6, а не 2.4)
предпосылками являются а) то, что хук mangle в PREROUTING срабатывает _до_ nat (в POST тоже, но в данном случае это не важно. картинку можно посмотреть все в том же netfilter hacking how-to), и б) наличие модуля connmark в ядре 2.6.

в mangle/PREROUTING мы имеем еще нетронутые внешние адреса веб-сервиса. соотв. используя state match, можно анализировать коннектообразующие пакеты и метить connmark'ами соотв.
потом, там же в mangle/PREROUTING, используя connmark выставлять packet mark для _всех_ пакетов соединения, уже не анализируя их адресов (этот шаг необходим т.к. в RPDB можно указывать в качестве ключа packet mark, но не conn mark - routing code вообще ничего не знает о коннэкшнах и их отслеживании).
и наконец RPDB (Routing Policy Database) использующая packet mark для выбора таблицы маршрутов.

итого:
iptables -t mangle -A PREROUTING -m state --state NEW -d 10.10.10.10 -j CONNMARK --set-mark 10
iptables -t mangle -A PREROUTING -m state --state NEW -d 10.20.20.20 -j CONNMARK --set-mark 20
iptables -t mangle -A PREROUTING -m connmark --mark 10 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -m connmark --mark 20 -j MARK --set-mark 2
ip rule add fwmark 1 prio ... table isp1
ip rule add fwmark 2 prio ... table isp2
ну с остальным сам разберешься..

\^P^/