iptables REDIRECT Works Only for First Packet: Solution

firewalliptableslinux

i need to redirect all UDP packets with destination port 15000 to port 15001 if the packet contains for example the string test. i have these two simple rules:

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

The strange behaviors:

  • if the first packet contains test string, redirection is done for
    all packets of the connection;
  • if the first packet of the connection doesn't contains test, redirection is never done even if a subsequent packet contains test

However all packets matching rule are correctly logged.

i tried to add also the track information to the rule:

-m state --state NEW,ESTABLISHED

but the behaviour is the same. Some ideas?

This is the complete iptables ruleset:

filter table:

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  

nat table:

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)

mangle table:

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  

raw table:

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Best Answer

nat table rules always work only for first packet in connection. Subsequent packets of same connection never traverse nat rule list and only supported by conntrack code

As UDP is connectionless in nature, "connection" here is defined simply by addresses, ports and timeout. So, if second UDP packet with same source port and address and same destination port and address arrives within the timeout, Linux believes it belongs to established "connection" and doensn't evaluate nat rule table for it at all, reusing verdict issued for previous packet.

See here: http://www.netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-3.html