iptables_nat in 2.4.0 prevents ICMP destination unreachables

Rusty Russell rusty@linuxcare.com.au
Sat, 03 Jun 2000 03:55:02 +0930


In message <200005292140.WAA02502@raistlin.arm.linux.org.uk> you write:
> If I leave the ping running, and insert iptables_nat, the ICMP net
> unreachable messages stop.  Checking this with tcpdump reveals that
> the machine which just loaded iptables_nat stops sending the ICMP
> error packets, which is obviously wrong since I'm asking the firewall
> to explicitly send them.

Well caught.  Overzealous unconfirmed connection test: ordinarily we
won't associate ICMPs with a connection until a packet from that
connection has passed through the box.  However, we should allow
locally-generated ICMP errors.

Rusty.

diff -urN -X /tmp/filesVWD1a --minimal linux-2.4.0-test1-official/include/linux/netfilter_ipv4/ip_conntrack_core.h working-2.4.0-test1/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- linux-2.4.0-test1-official/include/linux/netfilter_ipv4/ip_conntrack_core.h	Fri Jun  2 15:09:24 2000
+++ working-2.4.0-test1/include/linux/netfilter_ipv4/ip_conntrack_core.h	Sat Jun  3 04:10:09 2000
@@ -22,7 +22,8 @@
 
 /* Returns conntrack if it dealt with ICMP, and filled in skb->nfct */
 extern struct ip_conntrack *icmp_error_track(struct sk_buff *skb,
-					     enum ip_conntrack_info *ctinfo);
+					     enum ip_conntrack_info *ctinfo,
+					     unsigned int hooknum);
 extern int get_tuple(const struct iphdr *iph, size_t len,
 		     struct ip_conntrack_tuple *tuple,
 		     struct ip_conntrack_protocol *protocol);
diff -urN -X /tmp/filesVWD1a --minimal linux-2.4.0-test1-official/net/ipv4/netfilter/ip_conntrack_core.c working-2.4.0-test1/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.0-test1-official/net/ipv4/netfilter/ip_conntrack_core.c	Fri May 12 12:51:52 2000
+++ working-2.4.0-test1/net/ipv4/netfilter/ip_conntrack_core.c	Sat Jun  3 04:12:22 2000
@@ -297,7 +289,9 @@
 
 /* Returns conntrack if it dealt with ICMP, and filled in skb fields */
 struct ip_conntrack *
-icmp_error_track(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
+icmp_error_track(struct sk_buff *skb,
+		 enum ip_conntrack_info *ctinfo,
+		 unsigned int hooknum)
 {
 	const struct iphdr *iph;
 	struct icmphdr *hdr;
@@ -353,7 +354,11 @@
 		DEBUGP("icmp_error_track: no match\n");
 		return NULL;
 	}
-	if (!(h->ctrack->status & IPS_CONFIRMED)) {
+
+	/* REJECT target does this commonly, so allow locally
+           generated ICMP errors --RR */
+	if (!(h->ctrack->status & IPS_CONFIRMED)
+	    && hooknum != NF_IP_LOCAL_OUT) {
 		DEBUGP("icmp_error_track: unconfirmed\n");
 		ip_conntrack_put(h->ctrack);
 		return NULL;
@@ -623,7 +647,7 @@
 
 	/* It may be an icmp error... */
 	if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP 
-	    || !(ct = icmp_error_track(*pskb, &ctinfo))) {
+	    || !(ct = icmp_error_track(*pskb, &ctinfo, hooknum))) {
 		if (!(ct = resolve_normal_ct(*pskb, proto, &ctinfo))) {
 			/* Not valid part of a connection */
 			return NF_ACCEPT;
diff -urN -X /tmp/filesVWD1a --minimal linux-2.4.0-test1-official/net/ipv4/netfilter/ip_fw_compat_masq.c working-2.4.0-test1/net/ipv4/netfilter/ip_fw_compat_masq.c
--- linux-2.4.0-test1-official/net/ipv4/netfilter/ip_fw_compat_masq.c	Fri May 12 12:51:52 2000
+++ working-2.4.0-test1/net/ipv4/netfilter/ip_fw_compat_masq.c	Sat Jun  3 04:10:09 2000
@@ -114,7 +114,8 @@
 	switch (iph->protocol) {
 	case IPPROTO_ICMP:
 		/* ICMP errors. */
-		if ((ct = icmp_error_track(*pskb, &ctinfo))) {
+		ct = icmp_error_track(*pskb, &ctinfo, NF_IP_PRE_ROUTING);
+		if (ct) {
 			icmp_reply_translation(*pskb, ct,
 					       NF_IP_PRE_ROUTING,
 					       CTINFO2DIR(ctinfo));

--
Hacking time.