Linux multihomed — отправка ответов на входящие пакеты по тому же интерфейсу, по какому пришли

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

Думаю, на сегодня достаточно стандартная ситуация, когда на входе в локальную сеть стоит Linux-роутер, к которому подключены несколько внешних линий от разных провайдеров.
Как управляться с такой конфигурацией, писали много, например вот здесь.
Но когда берёшь реальный линукс и начинаешь строить, немедленно наступаешь на грабли.
Повторять все шаги из статьи по ссылке не буду, опишу только участвующие в «граблях».
А именно (далее все примеры в предположении, что основной внешний интерфейс eth0, а запасной — ppp0):
Чтобы ответы на пакеты уходили по тому же интерфейсу, по какому пришёл запрос, везде советуют включать маркировку пакетов

iptables -t mangle -I INPUT -i ppp0 -j CONNMARK --set-mark 0x1
iptables -t mangle -I OUTPUT -j CONNMARK --restore-mark


и далее назначать таблицу маршрутизации (с именем modem в файле /etc/iproute2/rt_tables) согласно меткам:

ip route add default dev ppp0 table modem
ip rule add fwmark 0x1 lookup modem

И вроде бы всё правильно, но — НЕ РАБОТАЕТ! Проверяешь с внешнего хоста пингом на адрес внешнего интерфейса — просто не увеличиваются счётчики на правиле iptables в таблице mangle, цепочке INPUT — то есть пакет туда НЕ ПОПАДАЕТ.
Начинаешь экспериментировать — выясняется, что в цепочку PREROUTING таблицы mangle пакеты попадают, а в цепочку INPUT уже нет. Продолжение экспериментов показывает, что и в цепочку PREROUTING таблицы nat пакеты попадают, а ни в INPUT ни в FORWARD — нет, значит согласно схеме прохождения цепочек пакеты теряются на первом узле «routing decision», где принимается решение куда отправить пакет — в FORWARD или в INPUT.
Так вот, многочасовое разбирательство, включая попытку влезть в исходники iptables и iproute, привели к поразительно простому открытию, которое почему-то почти нигде не упоминается: надо на входящих интерфейсах выключить rp_filter:

# prevent incoming packets on masqueraded connections from being dropped
# as "martians" due to the destination address being translated before the
# rp_filter check is performed
echo 0 > /proc/sys/net/ipv4/conf/ppp0/rp_filter

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

Удачи на интерфейсах!
Tags:
iptables, iproute2, linux, multihomed

You can't comment this post because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author's username will be hidden by an alias.