Постоянная ссылка: 2014-11-04 23:49:00+03:00 , автор Евгений Лопатин в Блог тэги: iptables linux conntrack

Столкнулся с любопытной проблемой:

Дано:

  • сервер А, посылает непрерывный поток UDP-трафика на некий порт NNNN сервера B
  • сервер B - гипервизор (KVM, Linux), через простой DNAT отправляет поток дальше, на виртуальный KVM-контейнер Z

Результат неожиданный - ICMP Port Unreachable в ответ серверу А от ядра сервера B , хотя трафик на интерфейс приходит, видно через tcpdump.

Т.к. в моем мозгу не укладывалось, как такой простой сценарий может не работать (более того, с того же гипервизора другие порты, и TCP, и UDP успешно прокинуты на другие KVM-контейнеры) - начал думать.

Очевидной мыслью стало попробовать проследить прохождение по цепочкам.

iptables -t nat    -A PREROUTING --src A.A.A.A -p udp --dport NNNN -j ACCEPT
iptables -t mangle -A PREROUTING --src A.A.A.A -p udp --dport NNNN -j ACCEPT

Просматривая дальше счетчики этих правил через iptables -Lnv -t nat и iptables -Lnv -t mangle соответственно - увидел самое интересное - счетчик в mangle растёт, а в nat нет! Т.е. пакет в ядро приходил, но до таблицы nat не доходил, что было очень любопытно.

Причина оказалась интересной - хоть я и знал это в теории, но на практике никогда раньше не видел.

Дело в том, что трафик от хоста A был мной отправлен на хост B до того, как я запустил приложение, обрабатывающее этот трафик в контейнере Z. В итоге, будучи по умолчанию активным, модуль Netfiler "ip_conntrack" запомнил, что по этому направлению никто порт не слушает, а т.к. поток был непрерывным - не забывал об этом по истечению времени жизни соединения внутри conntrack, и продолжал отправлять ICMP Port Unreachable, не пытаясь пропустить пакет.

Помогло с помощью утилиты conntrack удалить вручную соответствующую запись из таблиц conntrack.

Если у вас активен ip_conntrack - имейте ввиду, что он может на высоконагруженных системах творить подобные пакости. Ну он не со зла, он хороший и полезный.