Commit 7a85bd22 authored by Harald Welte's avatar Harald Welte Committed by David S. Miller

[NETFILTER]: Fix conntrack bug introduced by list_del change.

parent 1bf453b3
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/netfilter_ipv4/ip_conntrack_tuple.h> #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
#include <linux/bitops.h>
#include <asm/atomic.h> #include <asm/atomic.h>
enum ip_conntrack_info enum ip_conntrack_info
...@@ -41,6 +42,10 @@ enum ip_conntrack_status { ...@@ -41,6 +42,10 @@ enum ip_conntrack_status {
/* Conntrack should never be early-expired. */ /* Conntrack should never be early-expired. */
IPS_ASSURED_BIT = 2, IPS_ASSURED_BIT = 2,
IPS_ASSURED = (1 << IPS_ASSURED_BIT), IPS_ASSURED = (1 << IPS_ASSURED_BIT),
/* Connection is confirmed: originating packet has left box */
IPS_CONFIRMED_BIT = 3,
IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
}; };
#include <linux/netfilter_ipv4/ip_conntrack_tcp.h> #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
...@@ -159,7 +164,7 @@ struct ip_conntrack ...@@ -159,7 +164,7 @@ struct ip_conntrack
struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
/* Have we seen traffic both ways yet? (bitset) */ /* Have we seen traffic both ways yet? (bitset) */
volatile unsigned long status; unsigned long status;
/* Timer function; drops refcnt when it goes off. */ /* Timer function; drops refcnt when it goes off. */
struct timer_list timeout; struct timer_list timeout;
...@@ -255,7 +260,7 @@ ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data), ...@@ -255,7 +260,7 @@ ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
/* It's confirmed if it is, or has been in the hash table. */ /* It's confirmed if it is, or has been in the hash table. */
static inline int is_confirmed(struct ip_conntrack *ct) static inline int is_confirmed(struct ip_conntrack *ct)
{ {
return ct->tuplehash[IP_CT_DIR_ORIGINAL].list.next != NULL; return test_bit(IPS_CONFIRMED_BIT, &ct->status);
} }
extern unsigned int ip_conntrack_htable_size; extern unsigned int ip_conntrack_htable_size;
......
...@@ -290,9 +290,6 @@ clean_from_lists(struct ip_conntrack *ct) ...@@ -290,9 +290,6 @@ clean_from_lists(struct ip_conntrack *ct)
{ {
DEBUGP("clean_from_lists(%p)\n", ct); DEBUGP("clean_from_lists(%p)\n", ct);
MUST_BE_WRITE_LOCKED(&ip_conntrack_lock); MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
/* Remove from both hash lists: must not NULL out next ptrs,
otherwise we'll look unconfirmed. Fortunately, LIST_DELETE
doesn't do this. --RR */
LIST_DELETE(&ip_conntrack_hash LIST_DELETE(&ip_conntrack_hash
[hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)], [hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)],
&ct->tuplehash[IP_CT_DIR_ORIGINAL]); &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
...@@ -465,6 +462,7 @@ __ip_conntrack_confirm(struct nf_ct_info *nfct) ...@@ -465,6 +462,7 @@ __ip_conntrack_confirm(struct nf_ct_info *nfct)
ct->timeout.expires += jiffies; ct->timeout.expires += jiffies;
add_timer(&ct->timeout); add_timer(&ct->timeout);
atomic_inc(&ct->ct_general.use); atomic_inc(&ct->ct_general.use);
set_bit(IPS_CONFIRMED_BIT, &ct->status);
WRITE_UNLOCK(&ip_conntrack_lock); WRITE_UNLOCK(&ip_conntrack_lock);
return NF_ACCEPT; return NF_ACCEPT;
} }
...@@ -583,7 +581,7 @@ icmp_error_track(struct sk_buff *skb, ...@@ -583,7 +581,7 @@ icmp_error_track(struct sk_buff *skb,
connection. Too bad: we're in trouble anyway. */ connection. Too bad: we're in trouble anyway. */
static inline int unreplied(const struct ip_conntrack_tuple_hash *i) static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
{ {
return !(i->ctrack->status & IPS_ASSURED); return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
} }
static int early_drop(struct list_head *chain) static int early_drop(struct list_head *chain)
...@@ -718,7 +716,7 @@ init_conntrack(const struct ip_conntrack_tuple *tuple, ...@@ -718,7 +716,7 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
conntrack, expected); conntrack, expected);
/* Welcome, Mr. Bond. We've been expecting you... */ /* Welcome, Mr. Bond. We've been expecting you... */
IP_NF_ASSERT(master_ct(conntrack)); IP_NF_ASSERT(master_ct(conntrack));
conntrack->status = IPS_EXPECTED; __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
conntrack->master = expected; conntrack->master = expected;
expected->sibling = conntrack; expected->sibling = conntrack;
LIST_DELETE(&ip_conntrack_expect_list, expected); LIST_DELETE(&ip_conntrack_expect_list, expected);
...@@ -766,11 +764,11 @@ resolve_normal_ct(struct sk_buff *skb, ...@@ -766,11 +764,11 @@ resolve_normal_ct(struct sk_buff *skb,
*set_reply = 1; *set_reply = 1;
} else { } else {
/* Once we've had two way comms, always ESTABLISHED. */ /* Once we've had two way comms, always ESTABLISHED. */
if (h->ctrack->status & IPS_SEEN_REPLY) { if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
DEBUGP("ip_conntrack_in: normal packet for %p\n", DEBUGP("ip_conntrack_in: normal packet for %p\n",
h->ctrack); h->ctrack);
*ctinfo = IP_CT_ESTABLISHED; *ctinfo = IP_CT_ESTABLISHED;
} else if (h->ctrack->status & IPS_EXPECTED) { } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
DEBUGP("ip_conntrack_in: related packet for %p\n", DEBUGP("ip_conntrack_in: related packet for %p\n",
h->ctrack); h->ctrack);
*ctinfo = IP_CT_RELATED; *ctinfo = IP_CT_RELATED;
......
...@@ -190,7 +190,7 @@ static int tcp_packet(struct ip_conntrack *conntrack, ...@@ -190,7 +190,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
have an established connection: this is a fairly common have an established connection: this is a fairly common
problem case, so we can delete the conntrack problem case, so we can delete the conntrack
immediately. --RR */ immediately. --RR */
if (!(conntrack->status & IPS_SEEN_REPLY) && tcph->rst) { if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph->rst) {
WRITE_UNLOCK(&tcp_lock); WRITE_UNLOCK(&tcp_lock);
if (del_timer(&conntrack->timeout)) if (del_timer(&conntrack->timeout))
conntrack->timeout.function((unsigned long)conntrack); conntrack->timeout.function((unsigned long)conntrack);
......
...@@ -51,7 +51,7 @@ static int udp_packet(struct ip_conntrack *conntrack, ...@@ -51,7 +51,7 @@ static int udp_packet(struct ip_conntrack *conntrack,
{ {
/* If we've seen traffic both ways, this is some kind of UDP /* If we've seen traffic both ways, this is some kind of UDP
stream. Extend timeout. */ stream. Extend timeout. */
if (conntrack->status & IPS_SEEN_REPLY) { if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
ip_ct_refresh(conntrack, UDP_STREAM_TIMEOUT); ip_ct_refresh(conntrack, UDP_STREAM_TIMEOUT);
/* Also, more likely to be important, and not a probe */ /* Also, more likely to be important, and not a probe */
set_bit(IPS_ASSURED_BIT, &conntrack->status); set_bit(IPS_ASSURED_BIT, &conntrack->status);
......
...@@ -76,7 +76,7 @@ print_expect(char *buffer, const struct ip_conntrack_expect *expect) ...@@ -76,7 +76,7 @@ print_expect(char *buffer, const struct ip_conntrack_expect *expect)
} }
static unsigned int static unsigned int
print_conntrack(char *buffer, const struct ip_conntrack *conntrack) print_conntrack(char *buffer, struct ip_conntrack *conntrack)
{ {
unsigned int len; unsigned int len;
struct ip_conntrack_protocol *proto struct ip_conntrack_protocol *proto
...@@ -94,12 +94,12 @@ print_conntrack(char *buffer, const struct ip_conntrack *conntrack) ...@@ -94,12 +94,12 @@ print_conntrack(char *buffer, const struct ip_conntrack *conntrack)
len += print_tuple(buffer + len, len += print_tuple(buffer + len,
&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
proto); proto);
if (!(conntrack->status & IPS_SEEN_REPLY)) if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
len += sprintf(buffer + len, "[UNREPLIED] "); len += sprintf(buffer + len, "[UNREPLIED] ");
len += print_tuple(buffer + len, len += print_tuple(buffer + len,
&conntrack->tuplehash[IP_CT_DIR_REPLY].tuple, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
proto); proto);
if (conntrack->status & IPS_ASSURED) if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
len += sprintf(buffer + len, "[ASSURED] "); len += sprintf(buffer + len, "[ASSURED] ");
len += sprintf(buffer + len, "use=%u ", len += sprintf(buffer + len, "use=%u ",
atomic_read(&conntrack->ct_general.use)); atomic_read(&conntrack->ct_general.use));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment