LINUX.ORG.RU
ФорумAdmin

iproute2+iptables=маршрутизация по меткам


0

0

Добрый день.

Как водится, появилась пара провайдеров, соответственно, следует раскидать трафик по интерфейсам.

Настроен iproute2:

# ip rule
0:      from all lookup local 
32756:  from 1.1.1.1 lookup s
32757:  from all fwmark 0x1e lookup s
32758:  from 2.2.2.2 lookup b
32759:  from all fwmark 0x14 lookup b
32766:  from all lookup main 
32767:  from all lookup default

# ip route list table s
ip.addr.dns.serv1 via 1.1.1.2 dev eth0 
127.0.0.0/8 via 127.0.0.1 dev lo 
default via 1.1.1.2 dev eth0
# ip route list table b
ip.addr.dns.serv2 via 2.2.2.3 dev eth2 
127.0.0.0/8 via 127.0.0.1 dev lo 
default via 2.2.2.3 dev eth2

Маршрут по умолчанию для всей системы при этом установлен через 1.1.1.2, т.е. через интерфейс eth0.

Настраиваем icmp:

$IPT -t mangle -A OUTPUT -s $EXTIP2 -p icmp -j MARK --set-mark 0x14                                                                 
$IPT -t mangle -A OUTPUT -s $EXTIP -p icmp -j MARK --set-mark 0x1e

Пробуем:

# ping -I eth0 -c 3 ya.ru 
PING ya.ru (77.88.21.8) from 1.1.1.1 eth0: 56(84) bytes of data.
64 bytes from ya.ru (77.88.21.8): icmp_seq=1 ttl=52 time=16.5 ms
64 bytes from ya.ru (77.88.21.8): icmp_seq=2 ttl=52 time=16.1 ms
64 bytes from ya.ru (77.88.21.8): icmp_seq=3 ttl=52 time=16.4 ms

--- ya.ru ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 16.181/16.381/16.557/0.186 ms

gate ~ # ping -I eth2 -c 3 ya.ru 
PING ya.ru (77.88.21.8) from 2.2.2.2 eth2: 56(84) bytes of data.
64 bytes from ya.ru (77.88.21.8): icmp_seq=1 ttl=59 time=2.46 ms
64 bytes from ya.ru (77.88.21.8): icmp_seq=2 ttl=59 time=2.49 ms
64 bytes from ya.ru (77.88.21.8): icmp_seq=3 ttl=59 time=2.42 ms

--- ya.ru ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 2.425/2.460/2.495/0.028 ms

Как видно, всё работает. Для чистоты эксперимента в таблицах временно убирались правила

from ip
. В общем, метки от iptables принимаются и понимаются iproute2.

Теперь, пробуем пустить исходящий трафик, скажем, от squid через интерфейс eth2. По умолчанию, как выше сказано, он бегает через eth0. Добавляем правило фаервола:

$IPT -t mangle -A OUTPUT -p tcp --dport http -j MARK --set-mark 0x14

и смотрим, куда же побежит сей трафик по логам:

Feb 18 14:28:03 gate kernel: [46051.290116] ACCEPT IN= OUT=eth0 SRC=1.1.1.1 DST=213.180.204.11 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=23141 DF PROTO=TCP SPT=45386 DPT=80 WINDOW=5840 RES=0x00 SYN URGP=0 MARK=0x14 
Feb 18 14:28:05 gate kernel: [46053.183161] ACCEPT IN= OUT=eth0 SRC=1.1.1.1 DST=87.250.251.60 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=15276 DF PROTO=TCP SPT=58717 DPT=80 WINDOW=5840 RES=0x00 SYN URGP=0 MARK=0x14

Если последить через tcpdump, то выясняется, что исходящий трафик бежит через eth2, но с адресом eth0:

# tcpdump -i eth2 -n 'tcp port 80'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth2, link-type EN10MB (Ethernet), capture size 68 bytes
15:04:37.727833 IP 1.1.1.1.58404 > 78.140.142.125.80: . ack 3246838659 win 501 <nop,nop,timestamp[|tcp]>
15:04:37.734168 IP 1.1.1.1.58404 > 78.140.142.125.80: . ack 2897 win 501 <nop,nop,timestamp[|tcp]>
, а ответы возвращаются на интерфейс eth0, как и должно следовать из данного расклада.

Вопрос: как же заставить правильно работать эту связку? Ловить пакеты и менять адрес источника, и тогда, как понимаю, метить ничего не надо будет, iproute2 уже сказано, что делать с пакетами от соответствующих источников? Иных путей для решения проблемы нет?

Отмечу, что решение использовать встроенные в приложение средства для направления трафика через определённый интерфейс не совсем подходят: приложение может работать на всех интерфейсах, может не иметь подобного функционала и тд и тп. К тому же, хочется подобные вещи разруливать в одном месте.



Последнее исправление: HolyBoy (всего исправлений: 1)

для решения проблемы надо понять, в каком месте принимается решение о выборе интерфейса. Что говорит ip route на предмет default ?

azure ★★
()

Добавь SNAT на оба интерфейса и не парься.

Хотя по-хорошему нужно src указывать, да. И таблицу со статическими маршрутами тоже не мешает сделать.

nnz ★★★★
()
Ответ на: комментарий от azure

Об этом было написано: шлюз по умолчанию за интерфейсом eth0.

# ip route | grep default
default via 1.1.1.2 dev eth0
HolyBoy
() автор топика
Ответ на: комментарий от nnz

Таблицы со статическими маршрутами сделаны, см. первый пост.

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

HolyBoy
() автор топика
Ответ на: комментарий от HolyBoy

Это не таблицы со статическими маршрутами, а таблицы со шлюзами.

Таблица со статическими маршрутами всегда одна, и перечислены в ней обычно локалки, непосредственно подключенные к хосту. Подробнее см. http://ru.wikipedia.org/w/index.php?title=Iptables&oldid=22042839#.D0.9A.D1.8... С правильным указанием src и проч. Кстати, в default его тоже вроде можно указывать.

Кстати, маршруты для локалхоста там не нужны. Это один какой-то ламер ляпнул, и люди бездумно повторяют. Все маршруты для 127.0.0.1 и проч. находятся в таблице local, которую все пакеты проходят в первую очередь.

А не хватает либо src, либо SNAT. Либо того и другого (роль src в этом бардаке, к сожалению, не документирована).

nnz ★★★★
()

Если приложение не указало с какого адреса оно будет устанавливать соединение (0.0.0.0), то этот адрес автоматически назначается ядром. При этом рассматривается только основная таблица маршрутизации. Там определяеся наиболее подходящий маршрут и берётся либо первый адрес интерфейса, через который пойдет маршрут, либо, если в маршруте указан параметр src, берётся его значение. То есть при автоматичеком назначении исходящего адреса пакета не учитывается по какой таблице на самом деле таблице будет смаршрутизирован пакет.

В вашем случае «Маршрут по умолчанию для всей системы через интерфейс eth0». То есть когда squid идёт куда-то, и в его конфиге не указано с какого адреса идти, то ядро даёт его пакетам src-адрес 1.1.1.1. Далее с помощью iptables вы выставляете метку и по данному пакету принимается решение о маршрутизации (выбор таблицы маршрутизации {table b} и маршрута {via eth2}). После этого пакет отправляется через определённый интерфейс. И чтобы исправить src-адрес этого пакета остаётся только SNAT POSTROUTING. Хотя можно и SNAT OUTPUT и может в вашем случае это будет более правильным и MARK будет не нужен.

mky ★★★★★
()
Ответ на: комментарий от mky

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

А где в официальной документации это описано?

Хотя можно и SNAT OUTPUT


Боюсь, что нельзя. Маскарадить можно только уже маршрутизированные пакеты (POSTROUTING).
В OUTPUT, как и в PREROUTING, выполняются только пробросы и редиректы.

nnz ★★★★
()
Ответ на: комментарий от nnz

В документации я это не находил, (кроме опции src в команде ip route). Просто получается, что это да и rp_filter тоже, учитывают только таблицу по умолчанию. Навероное, надо посмотреть исходники ядра...

mky ★★★★★
()
Ответ на: комментарий от mky

Ну, про rp_filter это история давно известная.

Получается, что вне таблицы main указание src бессмысленно?

nnz ★★★★
()
Ответ на: комментарий от nnz

Получается, что так, бессмысленно. Хотя хорошо бы, чтобы кто-нибудь поковырял сорцы и подвердил это.

mky ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.