LINUX.ORG.RU
решено ФорумAdmin

неверный src ip в исходящих пакетах при rule based routing

 ,


1

1

Приветствую.

Пытаюсь сделать правильно роутинг некоторых маршрутов через vpn, используя железяку на openwrt (ядро 3.18.20). И столкнулся с проблемой, информации по которой не могу найти буквально нигде. Сырцы ядра еще не курил, но близок к тому.

Проблема. Есть стандартный набор правил для rule based routing:

ip rule add priority 103 fwmark 0x10/0x10 lookup vpn
ipset create vpn hash:net
ipset add vpn 8.8.8.8
iptables -t mangle -A OUTPUT -m set --match-set vpn dst -j MARK --set-mark 0x10
iptables -t mangle -A PREROUTING -i br-lan -m set --match-set vpn dst -j MARK --set-mark 0x10
ip route add default via 10.9.0.1 dev tun1 src 10.9.0.2 table vpn

Это — работает. То есть, компы за железякой благополучно ходят через tun1 для некоторых адресов и горя не знают.

Но! Локально сгенерированные пакеты ходить не хотят. Ни icmp, ни udp, ни tcp, ничего.

Смотрю tcpdump -i tun1, пускаю ping 8.8.8.8 и вижу радость:

# tcpdump -i tun1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun1, link-type RAW (Raw IP), capture size 65535 bytes
02:26:25.653753 IP 100.100.100.100 > 8.8.8.8: ICMP echo request, id 4230, seq 0, length 64
02:26:26.655484 IP 100.100.100.100 > 8.8.8.8: ICMP echo request, id 4230, seq 1, length 64
02:26:27.655723 IP 100.100.100.100 > 8.8.8.8: ICMP echo request, id 4230, seq 2, length 64
02:26:28.655963 IP 100.100.100.100 > 8.8.8.8: ICMP echo request, id 4230, seq 3, length 64
02:26:29.656196 IP 100.100.100.100 > 8.8.8.8: ICMP echo request, id 4230, seq 4, length 64

Где 100.100.100.100 — ip, выданный провайдером, висящий на локальном интерфейсе, отмеченном как default в таблице main.

При этом:

# ip route get 8.8.8.8 mark 0x10
8.8.8.8 via 10.9.0.1 dev tun1  src 10.9.0.2  mark 0x10
    cache

Позвольте, но зачем тогда поле src в таблице роутинга? При этом, ping -I tun1 8.8.8.8 работает как надо, но объяснить dnsmasq что надо сокет открывать на конкретном интерфейсе, вроде бы, нельзя.

И вот дальше я пока не могу продвинуться. Пакеты с левым src ip даже не долетают до другого конца openvpn-туннеля, тоже не могу понять почему.

На другой железяке, x86, с 3.2.0-105-generic-pae такой проблемы, вроде бы, не наблюдается. Может быть, это известная бага ядра 3.18.20? Или, что скорее, я чего-то не понимаю?

★★★★★

У вас не срабатывает правило для «локально сгенерированных пакетов» -

iptables -t mangle -A PREROUTING -i br-lan -m set --match-set vpn dst -j MARK --set-mark 0x10

В правиле жестко указано что оно должно срабатывать для пакетов приходящих с интерфейса «br-lan» - "-i br-lan". Пакеты на самом Openwrt не попадают в это правило, т.к. исходящий интерфейс не является br-lan для них. Так что либо добавляйте интерфейс, либо тупо пропишите доп. роутинг.

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

Нет, рядом есть правило

iptables -t mangle -A OUTPUT -m set --match-set vpn dst -j MARK --set-mark 0x10

и оно работает. Я вижу локальные пакеты на нужном интерфейсе. Но, с неправильным обратным адресом.

dmiceman ★★★★★
() автор топика

imho, при назначении IP адреса локально сгенерированным пакетам ядро использует именно таблицу main и не учитывает данные в альтернативных таблицах. Я когда-то решал это SNAT-ом. Может быть не эстетично, но работало.

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

Первый routing decision происходит до попадания пакета в OUTPUT, и именно это влияет на то, какой у него будет src адрес. Потом он маркируется, проходит второй routing decision, и уже поэтому он отправляется в tun1, но с неверным src адресом.

Можно:
а) делать SNAT на пакетах, уходящих в tun1;
б) делать дефолтный маршрут в таблице main через впн, а в основного провайдера пускать трафик посредством policy routing.

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

Да, правильно. Нашел-таки правильную статью на эту тему: https://utcc.utoronto.ca/~cks/space/blog/linux/IptablesWhenSNATAnnoyance

Пришлось делать SNAT, закономерно заработало. При более внимательном взгляде на железку, где оно работает — оказалось что там тоже маскарад используется.

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

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

Вот что мешает ядру на предварительном этапе роутинга ... подменять src

Мешает то, что роутинг адреса не меняет.

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

Но ведь криво же!

Процесс биндит сокет на IP, роутинг лишь выбирает выходной интерфейс. Предварительный роутинг в вашей терминологии - это и есть основной, а «основной» - это ре-роутинг после SNAT. Если бы ре-роутинг сам по себе мог тупо подменять SRC IP сообразно таблице, то это бы тут же поломало conntrack (см. netfilter flow chart). Поэтому нужен более продвинутый механизм SNAT, который не только подменит src на выходе, но и вернет оригинальный ответным пакетам.

rubic
()
Ответ на: комментарий от pekmop1024

Прикольный кладж, спасибо. Это, собственно, для всех линуксов должно работать.

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

Процесс биндит сокет на IP

Обычно, все же, исходящий ip в программах не выбирается, этим должно ядро заниматься.

это бы тут же поломало conntrack (см. netfilter flow chart)

Ok, понял. Но ощущение некоторой кривизны остается.

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

Обычно, все же, исходящий ip в программах не выбирается, этим должно ядро заниматься.

Зато обычно у более-менее не тупой проги опция прибиндиться к IP есть, ибо установить исходящий адрес при более одном канале по сервисам вещь вполне обычная.

Но ощущение некоторой кривизны остается.

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

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

Зато обычно у более-менее не тупой проги опция прибиндиться к IP есть, ибо установить исходящий адрес при более одном канале по сервисам вещь вполне обычная.

Зачем утилиткам типа dns-resolver-а, ntpdate, fetchmail, curl знать с какого интерфейса соединяться и каким маршрутом ходить? То есть, в статичном мире, когда маршруты не скачут туда-сюда, это все, конечно, здорово, но мы же вроде про rule based routing говорим?

Смена исходящего адреса на рероутинге что-то ломает — ок, понятно. Но это не делает текущее поведение более правильным и разумным.

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

Зачем утилиткам типа dns-resolver-а, ntpdate

Вы не поверите, но udp-шным утилитам биндится и отслеживать интерфейсы надо даже для одного канала, если второй это даже localhost, не говоря уже о локалке. Это tcp не надо, там соединение ядро устанавливает.

Но tcp-шным утилитам тоже полезно, когда вы именно балансируете по сервисам.

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

Зачем утилиткам чего-то отслеживать? INADDR_ANY уже запретили?

когда вы именно балансируете по сервисам.

Это, как раз, очень частная задача.

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

Зачем утилиткам чего-то отслеживать? INADDR_ANY уже запретили?

А вы не возмущались бы, а почитали о проблеме. Когда вы работаете с UDP, то connect-а нет. Это означает, что отсылаемый вами пакет никак не зависит от пришедших к вам пакетов, совсем. Вы без прибиндивания ко всем интерфейсам несколькими сокетами не можете выбрать исходящий интерфейс равный тому, от которого пришёл UDP запрос.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

Ну я нить беседы уже потерял. Какое это имеет отношение к неправильному исходящему адресу?

UDP-сервер получил пакет, ответил на обратный адрес, ядро выбрало интерфейс. Вот, возможно, я даже не знаю — а какой use case отправки обратного пакета через определенный интерфейс? Тот же load balancing? Ну ладно, пусть открывает несколько сокетов, биндится к отдельным интерфейсам. Только это совсем другая проблема.

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

Ну я нить беседы уже потерял.

Дешёвый трюк. Вы сами влезли со своим INADDR_ANY на уточнение о возможности распределения сервисов по адресам.

а какой use case отправки обратного пакета через определенный интерфейс?

Интерфейс определяет src-IP, по которому вы и будете делать src-рутинг.

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

Да ёлки-палки. И правильное поведение для админа, после добавления еще одного tunXXX — бежать по всем скриптам и выставлять у всего что в сеть лезет другой интерфейс?

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

Ещё раз, бежать для UDP-утилит не надо, те, кто более менее не тупые, например bind или там ntpd сами это делают - мониторят изменение интерфейсов. Для TCP/IP: если у вас ровно один сервис на опредлённом IP, то какая разница в каких скриптах вы будете править, в перезапуске этого сервиса, или в правилах фильтрации для установки меток и SNAT-а? Частный то он частный, а вот у меня уже 6 лет так работает squid, он висит на специально выделенном для него IP и только для него канале.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.