diff options
author | davem <davem> | 2002-01-15 08:53:21 +0000 |
---|---|---|
committer | davem <davem> | 2002-01-15 08:53:21 +0000 |
commit | 6373d1582fba1a9562f778852407b34dbbeaf75f (patch) | |
tree | 54ab054327e3859f7d922e685a38fe35d7173109 | |
parent | 1e812cd6f27d0db6dbef28a663f06569e8506345 (diff) | |
download | netdev-vger-cvs-6373d1582fba1a9562f778852407b34dbbeaf75f.tar.gz |
Fix destroyme timer handling, for real.
From Paul Russell.
-rw-r--r-- | net/ipv4/netfilter/ip_fw_compat_redir.c | 52 |
1 files changed, 34 insertions, 18 deletions
diff --git a/net/ipv4/netfilter/ip_fw_compat_redir.c b/net/ipv4/netfilter/ip_fw_compat_redir.c index f55680e7e..6760147c4 100644 --- a/net/ipv4/netfilter/ip_fw_compat_redir.c +++ b/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 @@ static void do_tcp_unredir(struct sk_buff *skb, struct redir *redir) 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 @@ do_redirect(struct sk_buff *skb, 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 @@ do_redirect(struct sk_buff *skb, 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 @@ do_redirect(struct sk_buff *skb, } 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 @@ do_redirect(struct sk_buff *skb, } } -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,16 +261,17 @@ check_for_redirect(struct sk_buff *skb) 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)) + add_timer(&redir->destroyme, jiffies + REDIR_TIMEOUT); } UNLOCK_BH(&redir_lock); } @@ -272,16 +287,17 @@ check_for_unredirect(struct sk_buff *skb) 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)) + add_timer(&redir->destroyme, jiffies + REDIR_TIMEOUT); } UNLOCK_BH(&redir_lock); } |