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

iptables REDIRECT работает только для первого пакета

мне нужно перенаправить все пакеты UDP с портом назначения 15000 на порт 15001, если пакет содержит, например, строку test. у меня есть два простых правила:

iptables -t nat -A PREROUTING -i eth0 -p udp --dport 15000 -m string --string 'test' --algo bm -j LOG --log-prefix='[netfilter] '
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 15000 -m string --string 'test' --algo bm -j REDIRECT --to-ports 15001

Странное поведение:

Однако все правила соответствия пакетов регистрируются правильно.

Я попытался добавить в правило также информацию о треке:

-m state --state NEW,ESTABLISHED

но поведение то же самое. Некоторые идеи?

Это полный iptables набор правил:

таблица фильтров:

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination  

нат таблица:

Chain PREROUTING (policy ACCEPT)
 target     prot opt source               destination         
 LOG        udp  --  anywhere             anywhere             udp dpt:15000 STRING match  "test" ALGO name bm TO 65535 LOG level warning prefix "[netfilter] "
 REDIRECT   udp  --  anywhere             anywhere             udp dpt:15000 STRING match  "test" ALGO name bm TO 65535 redir ports 15001

 Chain INPUT (policy ACCEPT)
 target     prot opt source               destination         

 Chain OUTPUT (policy ACCEPT)
 target     prot opt source               destination         

 Chain POSTROUTING (policy ACCEPT)

таблица манжет:

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination  

необработанная таблица:

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Это вызвано тем, что iptables применяет отслеживание соединений на PREROUTING цепь. Каждый раз, когда устанавливается новое соединение, iptables будет обращаться к кешу conntrack. Если совпадение найдено, правило из таблицы nat применяться не будет.

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

Обратите внимание, что это применимо даже к UDP (протокол без установления соединения). Первый пакет считается открывающим соединением NEW а другой - ответ ESTABLISHED.

Я нашел похожий пост на serverfault.

Правила nat table всегда работают только для первого пакета в соединении. Последующие пакеты того же соединения никогда не проходят через список правил NAT и поддерживаются только кодом conntrack

Поскольку UDP не имеет соединения по своей природе, "соединение" здесь определяется просто адресами, портами и тайм-аутом. Таким образом, если второй пакет UDP с тем же портом источника и адресом и тем же портом назначения и адресом прибывает в течение тайм-аута, Linux считает, что он принадлежит установленному «соединению», и вообще не оценивает для него таблицу правил nat, повторно используя вердикт, вынесенный для предыдущего пакет.

Посмотреть здесь: http://www.netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-3.html

iptables с зоны conntrack

В функция зон conntrack позволяет иметь два одинаковых коннтрака 5-ипл (или их часть), считающихся разными по их зона свойство. Обычно это, вероятно, используется со сложной маршрутизацией на основе политик, обрабатывающей идентичные IP-адреса, но проходящей по разным путям (маршрутам), чтобы предотвратить conntrack для слияния несвязанных потоков с разных путей.

Здесь это может быть использовано для решения этой проблемы: рассмотрим UDP-пакеты, не имеющие test и пакет, имеющий test быть частью двух разных зон происхождения (с помощью CT --zone-orig): обычная зона и перенаправленная зона. Каждая исходная зона разрешает записи conntrack в NEW состояние, чтобы не противоречить друг другу и считаться отдельным. Считайте это, как если бы в PREROUTING крючок: вместо оценки nat правила происходят один раз для первого пакета потока, это может произойти один раз для первого нормального пакета и один раз для первого test пакет.

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

iptables -t raw -A PREROUTING -i eth0 -p udp --dport 15000 -m string --string 'test' --algo bm -j MARK --set-mark 1
iptables -t raw -A PREROUTING -m mark --mark 1 -j CT --zone-orig 1   
iptables -t nat -A PREROUTING -m mark --mark 1 -j LOG --log-prefix='[netfilter] '
iptables -t nat -A PREROUTING -p udp -m mark --mark 1 -j REDIRECT --to-ports 15001

Тестирование (сервер находится на IP 10.0.3.66). Хронологически ответы, набранные после запросов (answer1 из term1 и answer2 из term2):

serverterm1$ socat udp4-listen:15000,reuseaddr,fork -
query1normal
query3normal
answer1

serverterm2$ socat udp4-listen:15001,reuseaddr,fork -
query2test
query4test
answer2

client$ socat udp4:10.0.3.66:15000 -
query1normal
query2test
query3normal
query4test
answer1
answer2

serverterm3# conntrack -E -p udp --orig-port-dst 15000
    [NEW] udp      17 30 src=10.0.3.1 dst=10.0.3.66 sport=33150 dport=15000 [UNREPLIED] src=10.0.3.66 dst=10.0.3.1 sport=15000 dport=33150
    [NEW] udp      17 30 src=10.0.3.1 dst=10.0.3.66 sport=33150 dport=15000 zone-orig=1 [UNREPLIED] src=10.0.3.66 dst=10.0.3.1 sport=15001 dport=33150
 [UPDATE] udp      17 30 src=10.0.3.1 dst=10.0.3.66 sport=33150 dport=15000 src=10.0.3.66 dst=10.0.3.1 sport=15000 dport=33150
 [UPDATE] udp      17 30 src=10.0.3.1 dst=10.0.3.66 sport=33150 dport=15000 zone-orig=1 src=10.0.3.66 dst=10.0.3.1 sport=15001 dport=33150

Предупреждение: string соответствие оценивается для каждого пакета потока. Подумайте, если возможно, используя u32 вместо этого с меньшими накладными расходами.