[PATCH] netfilter conntrack/nat ICMP bugfix 2.5.x

Harald Welte laforge@gnumonks.org
Wed, 17 Apr 2002 11:20:52 +0200


This is the same bugfix as in my previous mail, this time for 2.5.x:
Patch again by James Morris.

Please apply,
	Thanks


diff -urN linux-2.5.8-pre3.orig/include/linux/skbuff.h linux-2.5.8-pre3-nf-01/include/linux/skbuff.h
--- linux-2.5.8-pre3.orig/include/linux/skbuff.h	Thu Apr 11 03:09:33 2002
+++ linux-2.5.8-pre3-nf-01/include/linux/skbuff.h	Fri Apr 12 00:27:15 2002
@@ -1145,6 +1145,17 @@
 	if (nfct)
 		atomic_inc(&nfct->master->use);
 }
+static inline struct nf_ct_info *
+skb_nf_ct(struct sk_buff *skb)
+{
+	return skb->nfct;
+}
+#else
+static inline struct nf_ct_info *
+skb_nf_ct(struct sk_buff *skb)
+{
+	return NULL;
+}
 #endif
 
 #endif	/* __KERNEL__ */
diff -urN linux-2.5.8-pre3.orig/include/net/ip.h linux-2.5.8-pre3-nf-01/include/net/ip.h
--- linux-2.5.8-pre3.orig/include/net/ip.h	Sun Mar 24 12:30:00 2002
+++ linux-2.5.8-pre3-nf-01/include/net/ip.h	Fri Apr 12 00:27:15 2002
@@ -67,6 +67,7 @@
 
 extern struct ip_ra_chain *ip_ra_chain;
 extern rwlock_t ip_ra_lock;
+struct nf_ct_info;
 
 /* IP flags. */
 #define IP_CE		0x8000		/* Flag: "Congestion"		*/
@@ -107,7 +108,8 @@
 				      unsigned length,
 				      struct ipcm_cookie *ipc,
 				      struct rtable *rt,
-				      int flags);
+				      int flags,
+				      struct nf_ct_info *nfct);
 
 /*
  *	Map a multicast IP onto multicast MAC for type Token Ring.
diff -urN linux-2.5.8-pre3.orig/net/ipv4/icmp.c linux-2.5.8-pre3-nf-01/net/ipv4/icmp.c
--- linux-2.5.8-pre3.orig/net/ipv4/icmp.c	Thu Apr 11 03:09:33 2002
+++ linux-2.5.8-pre3-nf-01/net/ipv4/icmp.c	Fri Apr 12 00:27:15 2002
@@ -370,7 +370,7 @@
 			       icmp_param->data.icmph.code)) { 
 		ip_build_xmit(sk, icmp_glue_bits, icmp_param, 
 			      icmp_param->data_len+icmp_param->head_len,
-			      &ipc, rt, MSG_DONTWAIT);
+			      &ipc, rt, MSG_DONTWAIT, NULL);
 	}
 	ip_rt_put(rt);
 out:
@@ -528,7 +529,7 @@
 
 	ip_build_xmit(icmp_socket->sk, icmp_glue_bits, &icmp_param, 
 		icmp_param.data_len+sizeof(struct icmphdr),
-		&ipc, rt, MSG_DONTWAIT);
+		&ipc, rt, MSG_DONTWAIT, skb_nf_ct(skb_in));
 
 ende:
 	ip_rt_put(rt);
diff -urN linux-2.5.8-pre3.orig/net/ipv4/ip_output.c linux-2.5.8-pre3-nf-01/net/ipv4/ip_output.c
--- linux-2.5.8-pre3.orig/net/ipv4/ip_output.c	Sun Mar 24 12:30:00 2002
+++ linux-2.5.8-pre3-nf-01/net/ipv4/ip_output.c	Fri Apr 12 00:27:15 2002
@@ -407,6 +407,22 @@
 	return -EHOSTUNREACH;
 }
 
+#ifdef CONFIG_NETFILTER
+/* If the original packet is part of a connection, but the connection
+   is not confirmed, our manufactured reply will not be associated
+   with it, so we need to do this manually. */
+static void nfct_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
+{
+	void (*attach)(struct sk_buff *, struct nf_ct_info *);
+
+	/* Avoid module unload race with ip_ct_attach being NULLed out */
+	if (nfct && (attach = ip_ct_attach) != NULL)
+		attach(new_skb, nfct);
+}
+#else
+static void nfct_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct) { }
+#endif
+
 /*
  *	Build and send a packet, with as little as one copy
  *
@@ -436,7 +452,8 @@
 		  unsigned length,
 		  struct ipcm_cookie *ipc,
 		  struct rtable *rt,
-		  int flags)
+		  int flags,
+		  struct nf_ct_info *nfct)
 {
 	struct inet_opt *inet = inet_sk(sk);
 	unsigned int fraglen, maxfraglen, fragheaderlen;
@@ -602,6 +619,7 @@
 
 		nfrags++;
 
+		nfct_attach(skb, nfct);
 		err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, 
 			      skb->dst->dev, output_maybe_reroute);
 		if (err) {
@@ -636,7 +654,8 @@
 		  unsigned length,
 		  struct ipcm_cookie *ipc,
 		  struct rtable *rt,
-		  int flags)
+		  int flags,
+		  struct nf_ct_info *nfct)
 {
 	struct inet_opt *inet = inet_sk(sk);
 	int err;
@@ -656,7 +675,7 @@
 		 * 	Check for slow path.
 		 */
 		if (length > rt->u.dst.pmtu || ipc->opt != NULL)  
-			return ip_build_xmit_slow(sk,getfrag,frag,length,ipc,rt,flags); 
+			return ip_build_xmit_slow(sk,getfrag,frag,length,ipc,rt,flags,nfct); 
 	} else {
 		if (length > rt->u.dst.dev->mtu) {
 			ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport,
@@ -715,6 +734,7 @@
 	if (err)
 		goto error_fault;
 
+	nfct_attach(skb, nfct);
 	err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
 		      output_maybe_reroute);
 	if (err > 0)
@@ -983,7 +1003,8 @@
 	inet->tos = skb->nh.iph->tos;
 	sk->priority = skb->priority;
 	sk->protocol = skb->nh.iph->protocol;
-	ip_build_xmit(sk, ip_reply_glue_bits, arg, len, &ipc, rt, MSG_DONTWAIT);
+	ip_build_xmit(sk, ip_reply_glue_bits, arg, len, &ipc, rt, MSG_DONTWAIT,
+		      NULL);
 	bh_unlock_sock(sk);
 
 	ip_rt_put(rt);
diff -urN linux-2.5.8-pre3.orig/net/ipv4/netfilter/ip_nat_core.c linux-2.5.8-pre3-nf-01/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.5.8-pre3.orig/net/ipv4/netfilter/ip_nat_core.c	Thu Apr 11 03:09:33 2002
+++ linux-2.5.8-pre3-nf-01/net/ipv4/netfilter/ip_nat_core.c	Fri Apr 12 00:27:22 2002
@@ -857,6 +857,18 @@
 	/* not reached */
 }
 
+/*
+ * Decide whether to map inner header of an ICMP reply, including when
+ * we generate the reply ourselves.
+ */
+static inline int
+map_innards(unsigned int maniphook, unsigned int hooknum)
+{
+	return (maniphook == opposite_hook[hooknum]
+	        || (hooknum == NF_IP_LOCAL_OUT
+	             && HOOK2MANIP(maniphook) == IP_NAT_MANIP_SRC));
+}
+
 unsigned int
 icmp_reply_translation(struct sk_buff *skb,
 		       struct ip_conntrack *conntrack,
@@ -914,7 +926,7 @@
 		   packet, except it was never src/dst reversed, so
 		   where we would normally apply a dst manip, we apply
 		   a src, and vice versa. */
-		if (info->manips[i].hooknum == opposite_hook[hooknum]) {
+		if (map_innards(info->manips[i].hooknum, hooknum)) {
 			DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
 			       info->manips[i].maniptype == IP_NAT_MANIP_SRC
 			       ? "DST" : "SRC",
diff -urN linux-2.5.8-pre3.orig/net/ipv4/netfilter/ipt_REJECT.c linux-2.5.8-pre3-nf-01/net/ipv4/netfilter/ipt_REJECT.c
--- linux-2.5.8-pre3.orig/net/ipv4/netfilter/ipt_REJECT.c	Sun Mar 24 12:30:00 2002
+++ linux-2.5.8-pre3-nf-01/net/ipv4/netfilter/ipt_REJECT.c	Fri Apr 12 00:27:15 2002
@@ -32,7 +32,8 @@
 		attach(new_skb, nfct);
 }
 
-/* Send RST reply */
+/* Send RST reply: we want to use the dest as the RST src ip, so can't
+   use normal RST routine. --RR */
 static void send_reset(struct sk_buff *oldskb, int local)
 {
 	struct sk_buff *nskb;
@@ -150,6 +151,7 @@
 	kfree_skb(nskb);
 }
 
+#if 0
 static void send_unreach(struct sk_buff *skb_in, int code)
 {
 	struct iphdr *iph;
@@ -267,6 +269,12 @@
 	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
 		ip_finish_output);
 }	
+#else
+static void send_unreach(struct sk_buff *skb_in, int code)
+{
+	icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
+}
+#endif
 
 static unsigned int reject(struct sk_buff **pskb,
 			   unsigned int hooknum,
diff -urN linux-2.5.8-pre3.orig/net/ipv4/raw.c linux-2.5.8-pre3-nf-01/net/ipv4/raw.c
--- linux-2.5.8-pre3.orig/net/ipv4/raw.c	Sun Mar 24 12:30:00 2002
+++ linux-2.5.8-pre3-nf-01/net/ipv4/raw.c	Fri Apr 12 00:27:15 2002
@@ -431,7 +431,8 @@
 	if (!ipc.addr)
 		ipc.addr = rt->rt_dst;
 	err = ip_build_xmit(sk, inet->hdrincl ? raw_getrawfrag :
-		       	    raw_getfrag, &rfh, len, &ipc, rt, msg->msg_flags);
+		       	    raw_getfrag, &rfh, len, &ipc, rt, msg->msg_flags,
+			    NULL);
 
 done:
 	if (free)
diff -urN linux-2.5.8-pre3.orig/net/ipv4/udp.c linux-2.5.8-pre3-nf-01/net/ipv4/udp.c
--- linux-2.5.8-pre3.orig/net/ipv4/udp.c	Thu Apr 11 03:09:33 2002
+++ linux-2.5.8-pre3-nf-01/net/ipv4/udp.c	Fri Apr 12 00:27:15 2002
@@ -559,7 +559,7 @@
 			    (sk->no_check == UDP_CSUM_NOXMIT ?
 			     udp_getfrag_nosum :
 			     udp_getfrag),
-			    &ufh, ulen, &ipc, rt, msg->msg_flags);
+			    &ufh, ulen, &ipc, rt, msg->msg_flags, NULL);
 
 out:
 	ip_rt_put(rt);
-- 
Live long and prosper
- Harald Welte / laforge@gnumonks.org               http://www.gnumonks.org/
============================================================================
GCS/E/IT d- s-: a-- C+++ UL++++$ P+++ L++++$ E--- W- N++ o? K- w--- O- M+ 
V-- PS++ PE-- Y++ PGP++ t+ 5-- !X !R tv-- b+++ !DI !D G+ e* h--- r++ y+(*)