patch-2.4.18 linux/net/ipv4/netfilter/ip_fw_compat_redir.c

Next file: linux/net/ipv4/netfilter/ip_nat_rule.c
Previous file: linux/net/ipv4/netfilter/ip_fw_compat_masq.c
Back to the patch index
Back to the overall index

diff -Naur -X /home/marcelo/lib/dontdiff linux.orig/net/ipv4/netfilter/ip_fw_compat_redir.c linux/net/ipv4/netfilter/ip_fw_compat_redir.c
@@ -20,6 +20,9 @@
 
 #include <linux/netfilter_ipv4/lockhelp.h>
 
+/* Very simple timeout pushed back by each packet */
+#define REDIR_TIMEOUT (240*HZ)
+
 static DECLARE_LOCK(redir_lock);
 #define ASSERT_READ_LOCK(x) MUST_BE_LOCKED(&redir_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_LOCKED(&redir_lock)
@@ -150,6 +153,14 @@
 	skb->nfcache |= NFC_ALTERED;
 }
 
+static void destroyme(unsigned long me)
+{
+	LOCK_BH(&redir_lock);
+	LIST_DELETE(&redirs, (struct redir *)me);
+	UNLOCK_BH(&redir_lock);
+	kfree((struct redir *)me);
+}
+
 /* REDIRECT a packet. */
 unsigned int
 do_redirect(struct sk_buff *skb,
@@ -172,6 +183,10 @@
 		struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph
 							+ iph->ihl);
 
+		/* Must have whole header */
+		if (skb->len < iph->ihl*4 + sizeof(*udph))
+			return NF_DROP;
+
 		if (udph->check) /* 0 is a special case meaning no checksum */
 			udph->check = cheat_check(~iph->daddr, newdst,
 					  cheat_check(udph->dest ^ 0xFFFF,
@@ -191,6 +206,10 @@
 		struct redir *redir;
 		int ret;
 
+		/* Must have whole header */
+		if (skb->len < iph->ihl*4 + sizeof(*tcph))
+			return NF_DROP;
+
 		DEBUGP("Doing tcp redirect. %08X:%u %08X:%u -> %08X:%u\n",
 		       iph->saddr, tcph->source, iph->daddr, tcph->dest,
 		       newdst, redirpt);
@@ -206,7 +225,9 @@
 			}
 			list_prepend(&redirs, redir);
 			init_timer(&redir->destroyme);
-			redir->destroyme.expires = jiffies + 75*HZ;
+			redir->destroyme.function = destroyme;
+			redir->destroyme.data = (unsigned long)redir;
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
 			add_timer(&redir->destroyme);
 		}
 		/* In case mangling has changed, rewrite this part. */
@@ -227,13 +248,6 @@
 	}
 }
 
-static void destroyme(unsigned long me)
-{
-	LOCK_BH(&redir_lock);
-	LIST_DELETE(&redirs, (struct redir *)me);
-	UNLOCK_BH(&redir_lock);
-}
-
 /* Incoming packet: is it a reply to a masqueraded connection, or
    part of an already-redirected TCP connection? */
 void
@@ -247,15 +261,18 @@
 	if (iph->protocol != IPPROTO_TCP)
 		return;
 
+	/* Must have whole header */
+	if (skb->len < iph->ihl*4 + sizeof(*tcph))
+		return;
+
 	LOCK_BH(&redir_lock);
 	redir = find_redir(iph->saddr, iph->daddr, tcph->source, tcph->dest);
 	if (redir) {
 		DEBUGP("Doing tcp redirect again.\n");
 		do_tcp_redir(skb, redir);
-		if (tcph->rst || tcph->fin) {
-			redir->destroyme.function = destroyme;
-			redir->destroyme.data = (unsigned long)redir;
-			mod_timer(&redir->destroyme, 75*HZ);
+		if (del_timer(&redir->destroyme)) {
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
+			add_timer(&redir->destroyme);
 		}
 	}
 	UNLOCK_BH(&redir_lock);
@@ -272,15 +289,18 @@
 	if (iph->protocol != IPPROTO_TCP)
 		return;
 
+	/* Must have whole header */
+	if (skb->len < iph->ihl*4 + sizeof(*tcph))
+		return;
+
 	LOCK_BH(&redir_lock);
 	redir = find_unredir(iph->saddr, iph->daddr, tcph->source, tcph->dest);
 	if (redir) {
 		DEBUGP("Doing tcp unredirect.\n");
 		do_tcp_unredir(skb, redir);
-		if (tcph->rst || tcph->fin) {
-			redir->destroyme.function = destroyme;
-			redir->destroyme.data = (unsigned long)redir;
-			mod_timer(&redir->destroyme, 75*HZ);
+		if (del_timer(&redir->destroyme)) {
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
+			add_timer(&redir->destroyme);
 		}
 	}
 	UNLOCK_BH(&redir_lock);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)