ICMP packets associated with NAT connections sent out wrong interface?

Yasuyuki KOZAKAI yasuyuki.kozakai at toshiba.co.jp
Sat Jul 7 14:24:21 CEST 2007


From: Yasuyuki KOZAKAI <yasuyuki.kozakai at toshiba.co.jp>
Date: Sat, 07 Jul 2007 15:27:06 +0900 (JST)

> Hi, Jordan,
> 
> I'll sort out observations from your report and try to explain my idea in
> other mail after finishing some tests.

OK, I try to explain what the current netfilter does in Jordan's situation.
I also attach the patch to fix this problem. Jordan, can you try it ?

Patrick, please consider to apply it. Even if following my idea is not
correct, clearly it fixes a bug. I'm wondering why I missed '!'
when I copied & pasted ip_conntrack_proto_icmp.c...


- This situation occurred on 2.6.20.12 and 2.6.21.5 at least.
- your rules are following

*nat
:PREROUTING ACCEPT [32:2910]
:POSTROUTING ACCEPT [29:2330]
:OUTPUT ACCEPT [2:152]
-A PREROUTING -i eth1 -p tcp -m tcp --dport 25000 -j DNAT
--to-destination 192.168.0.133
-A PREROUTING -i eth1 -p udp -m udp --dport 25000 -j DNAT
--to-destination 192.168.0.133
-A POSTROUTING -o eth1 -j MASQUERADE
COMMIT
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth0 -j ACCEPT
-A INPUT -i eth1 -m state --state ESTABLISHED -j ACCEPT
-A INPUT -i eth1 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -j DROP
-A FORWARD -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -d 192.168.0.0/255.255.255.0 -o eth0 -j ACCEPT
-A OUTPUT -d 192.168.0.0/255.255.255.0 -j LOG --log-prefix "[packet out wrong interface] "
-A OUTPUT -o eth1 -j ACCEPT
-A OUTPUT -j DROP
COMMIT

- ICMP error is generated by this router but destination address of it is strange.

Jul  4 14:54:33 webby kernel: [packet out wrong interface] IN= OUT=eth1
SRC=123.23.23.23 DST=192.168.0.133 LEN=68 TOS=0x00 PREC=0xC0 TTL=64
ID=39698 PROTO=ICMP TYPE=3 CODE=3 [SRC=192.168.0.133 DST=123.23.23.23
LEN=40 TOS=0x00 PREC=0x20 TTL=239 ID=39262 PROTO=TCP SPT=25000 DPT=25000
WINDOW=64172 RES=0x00 RST URGP=0 ]

- original TCP reset is following

14:54:33.931831 IP (tos 0x20, ttl 239, id 39262, offset 0, flags [none],
proto: TCP (6), length: 40) 70.243.226.250.1703 > 123.23.23.23.25000: R,
cksum 0xacb6 (correct), 4070626809:4070626809(0) win 64172

- no error message is printed by nf_ct_tcp, no 'table is full' error.


My idea is following.

- This TCP reset is not initial packet of TCP connection. If it is initial packet,
  no address in ICMP packet should be mangled. Jordan, if you see
  /proc/net/netfilter/nf_conntrack, you will find the entry matched the TCP packet.

- TCP packet was marked as error packet. Because '--state ESTABLISHED'
  didn't match the packet. No conntrack entry wasn't assigned to the
  packet. Usually, error log by nf_conntrack_tcp should be generated in
  such case, but no message is generated in some cases. I don't know why
  this TCP reset was handled as error.

- Then ICMP error generated at this router was not assigned to any conntrack entry.

- nf_conntarck_icmp.c assigns the ICMP error to the conntrack which matches
  the TCP reset. But IP_CT_IS_REPLY didn't set to *ctinfo. This is bug.

        h = nf_conntrack_find_get(&innertuple, NULL);
        if (!h) {
                /* Locally generated ICMPs will match inverted if they
                   haven't been SNAT'ed yet */
                /* FIXME: NAT code has to handle half-done double NAT --RR  */
                if (hooknum == NF_IP_LOCAL_OUT)
                        h = nf_conntrack_find_get(&origtuple, NULL);

                if (!h) {
                        DEBUGP("icmp_error_message: no match\n");
                        return -NF_ACCEPT;
                }

                /* Reverse direction from that found */
                if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
                        *ctinfo += IP_CT_IS_REPLY;
        } else {
                if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
                        *ctinfo += IP_CT_IS_REPLY;


- As a result, nf_nat_packet mistook the address in ICMP packet which
  should be mangled.
-------------- next part --------------
>From e36c67a5f57a0bd45f6666627ad3d60d42ee4497 Mon Sep 17 00:00:00 2001
From: Yasuyuki Kozakai <yasuyuki.kozakai at toshiba.co.jp>
Date: Sat, 7 Jul 2007 20:29:39 +0900
Subject: [PATCH 1/1] [NETFILTER]: nf_conntrack: Fixes direction of locally generated ICMP error

The conntrack assigned to locally generated ICMP error is usually the one
assigned to the original packet which has caused the error. But if
the original packet is handled as invalid by nf_conntrack, no conntrack
is assigned to the original packet. Then nf_ct_attach() cannot assign
any conntrack to the ICMP error packet. In that case nf_conntrack_icmp
tries to assign appropriate conntrack to it. But the current code
mistakes the direction of the packet. As a result, NAT code mistakes
the address in the packet to mangle.

Spotted by Jordan Russell.

Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai at toshiba.co.jp>
---
 net/ipv4/netfilter/nf_conntrack_proto_icmp.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index f4fc657..5973b58 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -201,7 +201,7 @@ icmp_error_message(struct sk_buff *skb,
 		}
 
 		/* Reverse direction from that found */
-		if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
+		if (NF_CT_DIRECTION(h) != IP_CT_DIR_REPLY)
 			*ctinfo += IP_CT_IS_REPLY;
 	} else {
 		if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
-- 
1.5.2.2



More information about the netfilter-devel mailing list