Netfilter bug ? NAT'ed connections ignore icmp redirect

Henrik Stoerner henrik-netfilter at
Wed Sep 15 15:39:59 CEST 2004

I have a setup where I use a Linux box with netfilter to forward
tcp connections between a "client" and a "server.

The Linux box has a default gateway defined. However, there are
multiple other routers on the same network, and the default
gateway router sends ICMP redirects to inform the Linux box 
which router should be used to reach some destination.

In ascii art (somewhat simplified):

				  |----| firewall |---| server |
                                  |----| routerA |-------
                                  |    |  |
      | Linux NAT |   ------------|
                                  |----| routerB |----------
                                  |----| routerC |----+-----
                                  |                   |
                                  |                   |
                                  |                   |
				                  | client |

This works fine for traffic that originates on the Linux box.
If I connect from the Linux NAT box to the client, the default
gateway sends an ICMP redirect telling the Linux box to use
routerC, and all further traffic then goes via that router.
A lookup with "ip route get <client-IP>" also tells me that
traffic goes via routerC.

If the client connects to a service on the Linux NAT box, the
packets sent from the Linux NAT box to the client also obey
the routing defined by the ICMP redirect, and go via routerC.

But when the connection is initiated by the client for a port that
get's NAT'ed and forwarded to the server, then the packets going 
from the Linux NAT box to the client are sent to the default 
gateway, completely ignoring the route generated by the ICMP 

* client sends a SYN to Linux-NAT on port 1984
* Linux-NAT does SNAT+DNAT and forwards packet to server
* server sends SYN+ACK to Linux-NAT box
* Linux-NAT box does the necessary DNAT/SNAT and forwards 
  SYN+ACK to client using routerA instead of via routerC

Even though routerA sends an ICMP redirect telling Linux-NAT
to use routerC, all of the packets from Linux-NAT to the client
for this connection are sent via routerA.

The iptables rules are simple. I use this in a script:

/sbin/modprobe iptable_nat
/sbin/iptables -t nat -A PREROUTING -p tcp --dport 1984 -j DNAT --to-destination IP.ADDR.OF.SERVER:1984
/sbin/iptables -t nat -A POSTROUTING -p tcp --dport 1984 -j SNAT --to-source IP.ADDR.OF.LINUX-NAT
/sbin/sysctl -w net.ipv4.ip_forward=1
for f in /proc/sys/net/ipv4/conf/*/accept_redirects; do
	echo "1" >$f

giving me:

# iptables -t nat -L
target     prot opt source               destination
DNAT       tcp  --  anywhere             anywhere            tcp dpt:1984 to:IP.ADDR.OF.SERVER:1984

target     prot opt source               destination
SNAT       tcp  --  anywhere             anywhere            tcp dpt:1984 to:IP.ADDR.OF.LINUX-NAT

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

# lsmod
Module                  Size  Used by    Not tainted
iptable_nat            15816   1
ip_conntrack           16488   1  [iptable_nat]
ip_tables              14784   3  [iptable_nat]

I've tried kernels 2.4.18 and 2.4.27. The Linux NAT box is running Debian/testing
on an UltraSparc. The 2.4.18 kernel is the default Debian kernel; the 2.4.27 was
compiled locally. The configuration is available if you need it.

Henrik Storner

More information about the netfilter mailing list