Назад | Перейти на главную страницу

Странное поведение на iptable с nat и переадресацией портов

У меня есть несколько выделенных серверов, размещенных в нескольких центрах обработки данных, и я хочу перенести почту (pop3, imap, smtp и их варианты TLS / SSL) с одного сервера на другой.

Для этого я намерен временно установить NAT маршрутизация на новом сервере на старый для обработки времени распространения DNS.

Итак, я определил следующее IPTABLES правила:

iptables -t nat -A PREROUTING -p tcp -m tcp --dport 25  -j DNAT --to-destination <my_remote_ip>:8025
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 110 -j DNAT --to-destination <my_remote_ip>
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 143 -j DNAT --to-destination <my_remote_ip>
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 465 -j DNAT --to-destination <my_remote_ip>:8465
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 587 -j DNAT --to-destination <my_remote_ip>:8587
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 993 -j DNAT --to-destination <my_remote_ip>
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 995 -j DNAT --to-destination <my_remote_ip>
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 110  -j SNAT --to-source <my_local_ip>
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 143  -j SNAT --to-source <my_local_ip>
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 993  -j SNAT --to-source <my_local_ip>
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 995  -j SNAT --to-source <my_local_ip>
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 8025 -j SNAT --to-source <my_local_ip>:25
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 8465 -j SNAT --to-source <my_local_ip>:465
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 8587 -j SNAT --to-source <my_local_ip>:587

iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 110  -j ACCEPT
iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 143  -j ACCEPT
iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 993  -j ACCEPT
iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 995  -j ACCEPT
iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 8025 -j ACCEPT
iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 8465 -j ACCEPT
iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 8587 -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 110  -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 143  -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 993  -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 995  -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 8025 -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 8465 -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 8587 -j ACCEPT

(на самом деле упрощено, на самом деле это дублируется для IPv4 и IPV6, а на некоторых серверах интерфейс может отличаться от eth0… и, конечно, я изменил фактические IP-адреса)

Вы можете заметить, что почтовые службы имеют только NAT, но что службы, связанные с SMTP, также имеют перевод порта, связанный либо с обратным преобразованием, либо с конкретным прослушиванием этих портов на конечном сервере.

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

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

Входящие и исходящие (NAT) пакеты используют один и тот же интерфейс. (потому что у этих серверов только один сетевой интерфейс).

На самом деле это работает более или менее, за исключением того, что порт перенаправляет соединения (и только эти, нет проблем на портах 110, 143 и т. д.) имеют странное поведение: они работают, когда я их использую в первый раз, но если я немедленно отключаюсь и снова подключаюсь, пересылка перестанет работать, и мне придется подождать от 1 до 3 минут, прежде чем возможность подключиться снова.

Похоже, это связано с IP-адресом, а не с номером порта: даже если предыдущее соединение было на порту 110 (pop3, а не перенаправленный порт), я должен дождаться той же задержки, прежде чем смогу подключиться к порту 25.

Я подтвердил, что на нескольких серверах, все из которых Linux Debian Wheezy, Джесси или Протяжение, и на обоих IPv4 и IPv6 (кроме Wheezy, которые не могут выполнять NAT IPv6). ……… Да, я знаю, что Wheezy теперь старый, поэтому я перехожу.

Все IP-адреса полностью статичны.

И да, я установил / proc / sys / net / ipv4 / ip_forward (и это эквивалент IPv6) на 1.

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

Может ли кто-нибудь помочь мне найти причину задержки блокировки на 1-3 минуты и как я могу ее исправить?

Гинкго

Ваша проблема связана с особенностями трекера подключений linux.

Быстрый ответ: вы не можете избежать этой задержки в вашей конфигурации. Единственный способ избежать этой проблемы - использовать -j SNAT без указания номера порта в --to-source вариант.

Есть также небольшая хитрость, которая может вам мало помочь - используйте в j SNAT диапазон портов вместо одного номера порта. Это позволит вам установить несколько подключений. Количество одновременных подключений - это количество портов в диапазоне. Правило будет выглядеть так:

iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 8025 -j SNAT --to-source <my_local_ip>:10025-10125

Если вам нужны чертовы подробности, я могу расширить ответ.

Обновить

Чтобы понять детали, у вас должна быть некоторая предыстория. Читать "Linux kernel networking: implementation and theory" пользователя Rami Rosen. В основном вам понадобится «Глава 9. Netfilter. Отслеживание подключений» из этой книги.

Когда пакеты проходят через ваш хост Linux, трекер подключений Linux (conntrack) анализировать их и сохранять информацию о потоках пакетов в таблице (conntrack table). Каждый поток пакетов представлен как запись conntrack. Conntrack использует кортежи для идентифицированных потоков пакетов. Кортежи состоят из L3 (IP-адреса обоих концов и номер протокола L4) и L4 (для TCP это информация о номерах портов на обоих концах) информация о потоках.

Conntrack имеет несколько модулей для каждого протокола L4 для отслеживания состояний соединений, связанных с транспортным протоколом. Часть TCP conntrack реализует конечный автомат TCP.

В лабораторной работе (ядро 4.14) наблюдается странное поведение этой части TCP conntrack. Продемонстрируем это на простой среде.

Клиент (192.0.2.2) подключается к хосту linux (192.0.2.1:22), который перенаправляет это соединение на другой хост (192.0.2.6:22). Хост linux также использует правило SNAT, как и в вашей настройке.

Вывод tcpdump:

14:47:32.036809 IP 192.0.2.2.40079 > 192.0.2.1.22: Flags [S], seq 2159011818, win 29200, length 0
14:47:32.037346 IP 192.0.2.1.22 > 192.0.2.2.40079: Flags [S.], seq 960236935, ack 2159011819, win 28960, options [mss 1460,sackOK,TS val 1415987649 ecr 3003498128,nop,wscale 5], length 0
14:47:32.037683 IP 192.0.2.2.40079 > 192.0.2.1.22: Flags [.], ack 1, win 913, options [nop,nop,TS val 3003498129 ecr 1415987649], length 0
14:47:32.041407 IP 192.0.2.1.22 > 192.0.2.2.40079: Flags [P.], seq 1:22, ack 1, win 905, options [nop,nop,TS val 1415987653 ecr 3003498129], length 21
14:47:32.041806 IP 192.0.2.2.40079 > 192.0.2.1.22: Flags [.], ack 22, win 913, options [nop,nop,TS val 3003498133 ecr 1415987653], length 0
14:47:35.826919 IP 192.0.2.2.40079 > 192.0.2.1.22: Flags [F.], seq 1, ack 22, win 913, options [nop,nop,TS val 3003501918 ecr 1415987653], length 0
14:47:35.827996 IP 192.0.2.1.22 > 192.0.2.2.40079: Flags [F.], seq 22, ack 2, win 905, options [nop,nop,TS val 1415991440 ecr 3003501918], length 0
14:47:35.828386 IP 192.0.2.2.40079 > 192.0.2.1.22: Flags [.], ack 23, win 913, options [nop,nop,TS val 3003501919 ecr 1415991440], length 0

В conntrack на хосте linux я вижу это:

ipv4     2 tcp      6 431999 ESTABLISHED src=192.0.2.2 dst=192.0.2.1 sport=40079 dport=22 src=192.0.2.6 dst=192.0.2.5 sport=22 dport=22 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 431998 ESTABLISHED src=192.0.2.2 dst=192.0.2.1 sport=40079 dport=22 src=192.0.2.6 dst=192.0.2.5 sport=22 dport=22 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 431997 ESTABLISHED src=192.0.2.2 dst=192.0.2.1 sport=40079 dport=22 src=192.0.2.6 dst=192.0.2.5 sport=22 dport=22 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 431996 ESTABLISHED src=192.0.2.2 dst=192.0.2.1 sport=40079 dport=22 src=192.0.2.6 dst=192.0.2.5 sport=22 dport=22 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 119 TIME_WAIT src=192.0.2.2 dst=192.0.2.1 sport=40079 dport=22 src=192.0.2.6 dst=192.0.2.5 sport=22 dport=22 [ASSURED] mark=0 zone=0 use=2
...
ipv4     2 tcp      6 0 TIME_WAIT src=192.0.2.2 dst=192.0.2.1 sport=40079 dport=22 src=192.0.2.6 dst=192.0.2.5 sport=22 dport=22 [ASSURED] mark=0 zone=0 use=2

Как видите, несмотря на то, что соединение было закрыто правильно, соответствующая запись conntrack все еще представлена ​​в таблице conntrack с TIME_WAIT штат. И поскольку у нас есть только один возможный порт для SNAT, который уже занят, новые попытки подключения терпят неудачу. Почему мы не используем этот порт еще раз? Поскольку система не может отличить ответные пакеты от 192.0.2.6 между текущим потоком в TIME_WAIT состояние и новый сток.

Почему conntrack установил соединение в TIME_WAIT государство вместо того, чтобы уничтожить его, я не обнаружил.