Commit f7e36893 authored by Harald Welte's avatar Harald Welte Committed by Linus Torvalds

[NETFILTER]: Cleanup conntrack helper API

A: Pablo Neira
D: This patch changes the conntrack helper API.  Rather than having the
D: helper allocate an expect on the stack and then have the core
D: kmalloc and memcpy, it is now the job of a helper to call 
D: ip_conntrack_expect_alloc()
parent f4d9b3c6
...@@ -35,9 +35,13 @@ extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *); ...@@ -35,9 +35,13 @@ extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *);
extern struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple); extern struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple);
/* Allocate space for an expectation: this is mandatory before calling
ip_conntrack_expect_related. */
extern struct ip_conntrack_expect *ip_conntrack_expect_alloc(void);
/* Add an expected connection: can have more than one per connection */ /* Add an expected connection: can have more than one per connection */
extern int ip_conntrack_expect_related(struct ip_conntrack *related_to, extern int ip_conntrack_expect_related(struct ip_conntrack_expect *exp,
struct ip_conntrack_expect *exp); struct ip_conntrack *related_to);
extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect, extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
struct ip_conntrack_tuple *newtuple); struct ip_conntrack_tuple *newtuple);
extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp); extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
......
...@@ -46,10 +46,11 @@ static DECLARE_LOCK(amanda_buffer_lock); ...@@ -46,10 +46,11 @@ static DECLARE_LOCK(amanda_buffer_lock);
static int help(struct sk_buff *skb, static int help(struct sk_buff *skb,
struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{ {
struct ip_conntrack_expect exp; struct ip_conntrack_expect *exp;
struct ip_ct_amanda_expect *exp_amanda_info; struct ip_ct_amanda_expect *exp_amanda_info;
char *data, *data_limit, *tmp; char *data, *data_limit, *tmp;
unsigned int dataoff, i; unsigned int dataoff, i;
u_int16_t port, len;
/* Only look at packets from the Amanda server */ /* Only look at packets from the Amanda server */
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
...@@ -79,33 +80,40 @@ static int help(struct sk_buff *skb, ...@@ -79,33 +80,40 @@ static int help(struct sk_buff *skb,
goto out; goto out;
data += strlen("CONNECT "); data += strlen("CONNECT ");
memset(&exp, 0, sizeof(exp));
exp.tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
exp.tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
exp.tuple.dst.protonum = IPPROTO_TCP;
exp.mask.src.ip = 0xFFFFFFFF;
exp.mask.dst.ip = 0xFFFFFFFF;
exp.mask.dst.protonum = 0xFFFF;
exp.mask.dst.u.tcp.port = 0xFFFF;
/* Only search first line. */ /* Only search first line. */
if ((tmp = strchr(data, '\n'))) if ((tmp = strchr(data, '\n')))
*tmp = '\0'; *tmp = '\0';
exp_amanda_info = &exp.help.exp_amanda_info;
for (i = 0; i < ARRAY_SIZE(conns); i++) { for (i = 0; i < ARRAY_SIZE(conns); i++) {
char *match = strstr(data, conns[i]); char *match = strstr(data, conns[i]);
if (!match) if (!match)
continue; continue;
tmp = data = match + strlen(conns[i]); tmp = data = match + strlen(conns[i]);
exp_amanda_info->offset = data - amanda_buffer; port = simple_strtoul(data, &data, 10);
exp_amanda_info->port = simple_strtoul(data, &data, 10); len = data - tmp;
exp_amanda_info->len = data - tmp; if (port == 0 || len > 5)
if (exp_amanda_info->port == 0 || exp_amanda_info->len > 5)
break; break;
exp.tuple.dst.u.tcp.port = htons(exp_amanda_info->port); exp = ip_conntrack_expect_alloc();
ip_conntrack_expect_related(ct, &exp); if (exp == NULL)
goto out;
exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
exp->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
exp->tuple.dst.protonum = IPPROTO_TCP;
exp->mask.src.ip = 0xFFFFFFFF;
exp->mask.dst.ip = 0xFFFFFFFF;
exp->mask.dst.protonum = 0xFFFF;
exp->mask.dst.u.tcp.port = 0xFFFF;
exp_amanda_info = &exp->help.exp_amanda_info;
exp_amanda_info->offset = data - amanda_buffer;
exp_amanda_info->port = port;
exp_amanda_info->len = len;
exp->tuple.dst.u.tcp.port = htons(port);
ip_conntrack_expect_related(exp, ct);
} }
out: out:
......
...@@ -917,11 +917,55 @@ static void expectation_timed_out(unsigned long ul_expect) ...@@ -917,11 +917,55 @@ static void expectation_timed_out(unsigned long ul_expect)
WRITE_UNLOCK(&ip_conntrack_lock); WRITE_UNLOCK(&ip_conntrack_lock);
} }
struct ip_conntrack_expect *
ip_conntrack_expect_alloc()
{
struct ip_conntrack_expect *new;
new = (struct ip_conntrack_expect *)
kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
if (!new) {
DEBUGP("expect_related: OOM allocating expect\n");
return NULL;
}
/* tuple_cmp compares whole union, we have to initialized cleanly */
memset(new, 0, sizeof(struct ip_conntrack_expect));
return new;
}
static void
ip_conntrack_expect_insert(struct ip_conntrack_expect *new,
struct ip_conntrack *related_to)
{
DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
new->expectant = related_to;
new->sibling = NULL;
atomic_set(&new->use, 1);
/* add to expected list for this connection */
list_add(&new->expected_list, &related_to->sibling_list);
/* add to global list of expectations */
list_prepend(&ip_conntrack_expect_list, &new->list);
/* add and start timer if required */
if (related_to->helper->timeout) {
init_timer(&new->timeout);
new->timeout.data = (unsigned long)new;
new->timeout.function = expectation_timed_out;
new->timeout.expires = jiffies +
related_to->helper->timeout * HZ;
add_timer(&new->timeout);
}
related_to->expecting++;
}
/* Add a related connection. */ /* Add a related connection. */
int ip_conntrack_expect_related(struct ip_conntrack *related_to, int ip_conntrack_expect_related(struct ip_conntrack_expect *expect,
struct ip_conntrack_expect *expect) struct ip_conntrack *related_to)
{ {
struct ip_conntrack_expect *old, *new; struct ip_conntrack_expect *old;
int ret = 0; int ret = 0;
WRITE_LOCK(&ip_conntrack_lock); WRITE_LOCK(&ip_conntrack_lock);
...@@ -943,7 +987,7 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to, ...@@ -943,7 +987,7 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to,
if (related_to->helper->timeout) { if (related_to->helper->timeout) {
if (!del_timer(&old->timeout)) { if (!del_timer(&old->timeout)) {
/* expectation is dying. Fall through */ /* expectation is dying. Fall through */
old = NULL; goto out;
} else { } else {
old->timeout.expires = jiffies + old->timeout.expires = jiffies +
related_to->helper->timeout * HZ; related_to->helper->timeout * HZ;
...@@ -951,10 +995,10 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to, ...@@ -951,10 +995,10 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to,
} }
} }
if (old) { WRITE_UNLOCK(&ip_conntrack_lock);
WRITE_UNLOCK(&ip_conntrack_lock); kfree(expect);
return -EEXIST; return -EEXIST;
}
} else if (related_to->helper->max_expected && } else if (related_to->helper->max_expected &&
related_to->expecting >= related_to->helper->max_expected) { related_to->expecting >= related_to->helper->max_expected) {
struct list_head *cur_item; struct list_head *cur_item;
...@@ -971,6 +1015,7 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to, ...@@ -971,6 +1015,7 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to,
related_to->helper->name, related_to->helper->name,
NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip)); NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
kfree(expect);
return -EPERM; return -EPERM;
} }
DEBUGP("ip_conntrack: max number of expected " DEBUGP("ip_conntrack: max number of expected "
...@@ -1010,37 +1055,12 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to, ...@@ -1010,37 +1055,12 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to,
&expect->mask)) { &expect->mask)) {
WRITE_UNLOCK(&ip_conntrack_lock); WRITE_UNLOCK(&ip_conntrack_lock);
DEBUGP("expect_related: busy!\n"); DEBUGP("expect_related: busy!\n");
kfree(expect);
return -EBUSY; return -EBUSY;
} }
new = (struct ip_conntrack_expect *) out: ip_conntrack_expect_insert(expect, related_to);
kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
if (!new) {
WRITE_UNLOCK(&ip_conntrack_lock);
DEBUGP("expect_relaed: OOM allocating expect\n");
return -ENOMEM;
}
DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
memcpy(new, expect, sizeof(*expect));
new->expectant = related_to;
new->sibling = NULL;
atomic_set(&new->use, 1);
/* add to expected list for this connection */
list_add(&new->expected_list, &related_to->sibling_list);
/* add to global list of expectations */
list_prepend(&ip_conntrack_expect_list, &new->list);
/* add and start timer if required */
if (related_to->helper->timeout) {
init_timer(&new->timeout);
new->timeout.data = (unsigned long)new;
new->timeout.function = expectation_timed_out;
new->timeout.expires = jiffies +
related_to->helper->timeout * HZ;
add_timer(&new->timeout);
}
related_to->expecting++;
WRITE_UNLOCK(&ip_conntrack_lock); WRITE_UNLOCK(&ip_conntrack_lock);
......
...@@ -256,8 +256,8 @@ static int help(struct sk_buff *skb, ...@@ -256,8 +256,8 @@ static int help(struct sk_buff *skb,
int dir = CTINFO2DIR(ctinfo); int dir = CTINFO2DIR(ctinfo);
unsigned int matchlen, matchoff; unsigned int matchlen, matchoff;
struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info; struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
struct ip_conntrack_expect expect, *exp = &expect; struct ip_conntrack_expect *exp;
struct ip_ct_ftp_expect *exp_ftp_info = &exp->help.exp_ftp_info; struct ip_ct_ftp_expect *exp_ftp_info;
unsigned int i; unsigned int i;
int found = 0; int found = 0;
...@@ -346,8 +346,15 @@ static int help(struct sk_buff *skb, ...@@ -346,8 +346,15 @@ static int help(struct sk_buff *skb,
DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n", DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
(int)matchlen, data + matchoff, (int)matchlen, data + matchoff,
matchlen, ntohl(tcph.seq) + matchoff); matchlen, ntohl(tcph.seq) + matchoff);
memset(&expect, 0, sizeof(expect)); /* Allocate expectation which will be inserted */
exp = ip_conntrack_expect_alloc();
if (exp == NULL) {
ret = NF_ACCEPT;
goto out;
}
exp_ftp_info = &exp->help.exp_ftp_info;
/* Update the ftp info */ /* Update the ftp info */
if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]) if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
...@@ -389,7 +396,7 @@ static int help(struct sk_buff *skb, ...@@ -389,7 +396,7 @@ static int help(struct sk_buff *skb,
exp->expectfn = NULL; exp->expectfn = NULL;
/* Ignore failure; should only happen with NAT */ /* Ignore failure; should only happen with NAT */
ip_conntrack_expect_related(ct, &expect); ip_conntrack_expect_related(exp, ct);
ret = NF_ACCEPT; ret = NF_ACCEPT;
out: out:
UNLOCK_BH(&ip_ftp_lock); UNLOCK_BH(&ip_ftp_lock);
......
...@@ -106,8 +106,8 @@ static int help(struct sk_buff *skb, ...@@ -106,8 +106,8 @@ static int help(struct sk_buff *skb,
struct tcphdr tcph; struct tcphdr tcph;
char *data, *data_limit; char *data, *data_limit;
int dir = CTINFO2DIR(ctinfo); int dir = CTINFO2DIR(ctinfo);
struct ip_conntrack_expect expect, *exp = &expect; struct ip_conntrack_expect *exp;
struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info; struct ip_ct_irc_expect *exp_irc_info = NULL;
u_int32_t dcc_ip; u_int32_t dcc_ip;
u_int16_t dcc_port; u_int16_t dcc_port;
...@@ -190,8 +190,12 @@ static int help(struct sk_buff *skb, ...@@ -190,8 +190,12 @@ static int help(struct sk_buff *skb,
continue; continue;
} }
memset(&expect, 0, sizeof(expect)); exp = ip_conntrack_expect_alloc();
if (exp == NULL)
goto out;
exp_irc_info = &exp->help.exp_irc_info;
/* save position of address in dcc string, /* save position of address in dcc string,
* necessary for NAT */ * necessary for NAT */
...@@ -218,7 +222,7 @@ static int help(struct sk_buff *skb, ...@@ -218,7 +222,7 @@ static int help(struct sk_buff *skb,
NIPQUAD(exp->tuple.dst.ip), NIPQUAD(exp->tuple.dst.ip),
ntohs(exp->tuple.dst.u.tcp.port)); ntohs(exp->tuple.dst.u.tcp.port));
ip_conntrack_expect_related(ct, &expect); ip_conntrack_expect_related(exp, ct);
goto out; goto out;
} /* for .. NUM_DCCPROTO */ } /* for .. NUM_DCCPROTO */
......
...@@ -591,6 +591,7 @@ EXPORT_SYMBOL(ip_ct_refresh); ...@@ -591,6 +591,7 @@ EXPORT_SYMBOL(ip_ct_refresh);
EXPORT_SYMBOL(ip_ct_find_proto); EXPORT_SYMBOL(ip_ct_find_proto);
EXPORT_SYMBOL(__ip_ct_find_proto); EXPORT_SYMBOL(__ip_ct_find_proto);
EXPORT_SYMBOL(ip_ct_find_helper); EXPORT_SYMBOL(ip_ct_find_helper);
EXPORT_SYMBOL(ip_conntrack_expect_alloc);
EXPORT_SYMBOL(ip_conntrack_expect_related); EXPORT_SYMBOL(ip_conntrack_expect_related);
EXPORT_SYMBOL(ip_conntrack_change_expect); EXPORT_SYMBOL(ip_conntrack_change_expect);
EXPORT_SYMBOL(ip_conntrack_unexpect_related); EXPORT_SYMBOL(ip_conntrack_unexpect_related);
......
...@@ -44,7 +44,7 @@ static int tftp_help(struct sk_buff *skb, ...@@ -44,7 +44,7 @@ static int tftp_help(struct sk_buff *skb,
enum ip_conntrack_info ctinfo) enum ip_conntrack_info ctinfo)
{ {
struct tftphdr tftph; struct tftphdr tftph;
struct ip_conntrack_expect exp; struct ip_conntrack_expect *exp;
if (skb_copy_bits(skb, skb->nh.iph->ihl * 4 + sizeof(struct udphdr), if (skb_copy_bits(skb, skb->nh.iph->ihl * 4 + sizeof(struct udphdr),
&tftph, sizeof(tftph)) != 0) &tftph, sizeof(tftph)) != 0)
...@@ -57,19 +57,22 @@ static int tftp_help(struct sk_buff *skb, ...@@ -57,19 +57,22 @@ static int tftp_help(struct sk_buff *skb,
DEBUGP(""); DEBUGP("");
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
memset(&exp, 0, sizeof(exp));
exp.tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; exp = ip_conntrack_expect_alloc();
exp.mask.src.ip = 0xffffffff; if (exp == NULL)
exp.mask.dst.ip = 0xffffffff; return NF_ACCEPT;
exp.mask.dst.u.udp.port = 0xffff;
exp.mask.dst.protonum = 0xffff; exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
exp.expectfn = NULL; exp->mask.src.ip = 0xffffffff;
exp->mask.dst.ip = 0xffffffff;
exp->mask.dst.u.udp.port = 0xffff;
exp->mask.dst.protonum = 0xffff;
exp->expectfn = NULL;
DEBUGP("expect: "); DEBUGP("expect: ");
DUMP_TUPLE(&exp.tuple); DUMP_TUPLE(&exp->tuple);
DUMP_TUPLE(&exp.mask); DUMP_TUPLE(&exp->mask);
ip_conntrack_expect_related(ct, &exp); ip_conntrack_expect_related(exp, ct);
break; break;
default: default:
DEBUGP("Unknown opcode\n"); DEBUGP("Unknown opcode\n");
......
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