diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2010-09-28 15:06:34 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2010-09-28 15:06:34 -0400 |
commit | bc01befdcf3e40979eb518085a075cbf0aacede0 (patch) | |
tree | 8d6c4352e135ade290f2ba0b68b45cbcffde8af8 /net/netfilter/nf_conntrack_expect.c | |
parent | 8b008faf92ac8f7eeb65e8cd36077601af7c46db (diff) |
netfilter: ctnetlink: add support for user-space expectation helpers
This patch adds the basic infrastructure to support user-space
expectation helpers via ctnetlink and the netfilter queuing
infrastructure NFQUEUE. Basically, this patch:
* adds NF_CT_EXPECT_USERSPACE flag to identify user-space
created expectations. I have also added a sanity check in
__nf_ct_expect_check() to avoid that kernel-space helpers
may create an expectation if the master conntrack has no
helper assigned.
* adds some branches to check if the master conntrack helper
exists, otherwise we skip the code that refers to kernel-space
helper such as the local expectation list and the expectation
policy.
* allows to set the timeout for user-space expectations with
no helper assigned.
* a list of expectations created from user-space that depends
on ctnetlink (if this module is removed, they are deleted).
* includes USERSPACE in the /proc output for expectations
that have been created by a user-space helper.
This patch also modifies ctnetlink to skip including the helper
name in the Netlink messages if no kernel-space helper is set
(since no user-space expectation has not kernel-space kernel
assigned).
You can access an example user-space FTP conntrack helper at:
http://people.netfilter.org/pablo/userspace-conntrack-helpers/nf-ftp-helper-userspace-POC.tar.bz
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/netfilter/nf_conntrack_expect.c')
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 62 |
1 files changed, 47 insertions, 15 deletions
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index acb29ccaa41..b30a1f2aac0 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -38,20 +38,23 @@ static int nf_ct_expect_hash_rnd_initted __read_mostly; | |||
38 | 38 | ||
39 | static struct kmem_cache *nf_ct_expect_cachep __read_mostly; | 39 | static struct kmem_cache *nf_ct_expect_cachep __read_mostly; |
40 | 40 | ||
41 | static HLIST_HEAD(nf_ct_userspace_expect_list); | ||
42 | |||
41 | /* nf_conntrack_expect helper functions */ | 43 | /* nf_conntrack_expect helper functions */ |
42 | void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) | 44 | void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) |
43 | { | 45 | { |
44 | struct nf_conn_help *master_help = nfct_help(exp->master); | 46 | struct nf_conn_help *master_help = nfct_help(exp->master); |
45 | struct net *net = nf_ct_exp_net(exp); | 47 | struct net *net = nf_ct_exp_net(exp); |
46 | 48 | ||
47 | NF_CT_ASSERT(master_help); | ||
48 | NF_CT_ASSERT(!timer_pending(&exp->timeout)); | 49 | NF_CT_ASSERT(!timer_pending(&exp->timeout)); |
49 | 50 | ||
50 | hlist_del_rcu(&exp->hnode); | 51 | hlist_del_rcu(&exp->hnode); |
51 | net->ct.expect_count--; | 52 | net->ct.expect_count--; |
52 | 53 | ||
53 | hlist_del(&exp->lnode); | 54 | hlist_del(&exp->lnode); |
54 | master_help->expecting[exp->class]--; | 55 | if (!(exp->flags & NF_CT_EXPECT_USERSPACE)) |
56 | master_help->expecting[exp->class]--; | ||
57 | |||
55 | nf_ct_expect_put(exp); | 58 | nf_ct_expect_put(exp); |
56 | 59 | ||
57 | NF_CT_STAT_INC(net, expect_delete); | 60 | NF_CT_STAT_INC(net, expect_delete); |
@@ -320,16 +323,21 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) | |||
320 | 323 | ||
321 | atomic_inc(&exp->use); | 324 | atomic_inc(&exp->use); |
322 | 325 | ||
323 | hlist_add_head(&exp->lnode, &master_help->expectations); | 326 | if (master_help) { |
324 | master_help->expecting[exp->class]++; | 327 | hlist_add_head(&exp->lnode, &master_help->expectations); |
328 | master_help->expecting[exp->class]++; | ||
329 | } else if (exp->flags & NF_CT_EXPECT_USERSPACE) | ||
330 | hlist_add_head(&exp->lnode, &nf_ct_userspace_expect_list); | ||
325 | 331 | ||
326 | hlist_add_head_rcu(&exp->hnode, &net->ct.expect_hash[h]); | 332 | hlist_add_head_rcu(&exp->hnode, &net->ct.expect_hash[h]); |
327 | net->ct.expect_count++; | 333 | net->ct.expect_count++; |
328 | 334 | ||
329 | setup_timer(&exp->timeout, nf_ct_expectation_timed_out, | 335 | setup_timer(&exp->timeout, nf_ct_expectation_timed_out, |
330 | (unsigned long)exp); | 336 | (unsigned long)exp); |
331 | p = &master_help->helper->expect_policy[exp->class]; | 337 | if (master_help) { |
332 | exp->timeout.expires = jiffies + p->timeout * HZ; | 338 | p = &master_help->helper->expect_policy[exp->class]; |
339 | exp->timeout.expires = jiffies + p->timeout * HZ; | ||
340 | } | ||
333 | add_timer(&exp->timeout); | 341 | add_timer(&exp->timeout); |
334 | 342 | ||
335 | atomic_inc(&exp->use); | 343 | atomic_inc(&exp->use); |
@@ -380,7 +388,9 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) | |||
380 | unsigned int h; | 388 | unsigned int h; |
381 | int ret = 1; | 389 | int ret = 1; |
382 | 390 | ||
383 | if (!master_help->helper) { | 391 | /* Don't allow expectations created from kernel-space with no helper */ |
392 | if (!(expect->flags & NF_CT_EXPECT_USERSPACE) && | ||
393 | (!master_help || (master_help && !master_help->helper))) { | ||
384 | ret = -ESHUTDOWN; | 394 | ret = -ESHUTDOWN; |
385 | goto out; | 395 | goto out; |
386 | } | 396 | } |
@@ -398,13 +408,16 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) | |||
398 | } | 408 | } |
399 | } | 409 | } |
400 | /* Will be over limit? */ | 410 | /* Will be over limit? */ |
401 | p = &master_help->helper->expect_policy[expect->class]; | 411 | if (master_help) { |
402 | if (p->max_expected && | 412 | p = &master_help->helper->expect_policy[expect->class]; |
403 | master_help->expecting[expect->class] >= p->max_expected) { | 413 | if (p->max_expected && |
404 | evict_oldest_expect(master, expect); | 414 | master_help->expecting[expect->class] >= p->max_expected) { |
405 | if (master_help->expecting[expect->class] >= p->max_expected) { | 415 | evict_oldest_expect(master, expect); |
406 | ret = -EMFILE; | 416 | if (master_help->expecting[expect->class] |
407 | goto out; | 417 | >= p->max_expected) { |
418 | ret = -EMFILE; | ||
419 | goto out; | ||
420 | } | ||
408 | } | 421 | } |
409 | } | 422 | } |
410 | 423 | ||
@@ -439,6 +452,21 @@ out: | |||
439 | } | 452 | } |
440 | EXPORT_SYMBOL_GPL(nf_ct_expect_related_report); | 453 | EXPORT_SYMBOL_GPL(nf_ct_expect_related_report); |
441 | 454 | ||
455 | void nf_ct_remove_userspace_expectations(void) | ||
456 | { | ||
457 | struct nf_conntrack_expect *exp; | ||
458 | struct hlist_node *n, *next; | ||
459 | |||
460 | hlist_for_each_entry_safe(exp, n, next, | ||
461 | &nf_ct_userspace_expect_list, lnode) { | ||
462 | if (del_timer(&exp->timeout)) { | ||
463 | nf_ct_unlink_expect(exp); | ||
464 | nf_ct_expect_put(exp); | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | EXPORT_SYMBOL_GPL(nf_ct_remove_userspace_expectations); | ||
469 | |||
442 | #ifdef CONFIG_PROC_FS | 470 | #ifdef CONFIG_PROC_FS |
443 | struct ct_expect_iter_state { | 471 | struct ct_expect_iter_state { |
444 | struct seq_net_private p; | 472 | struct seq_net_private p; |
@@ -529,8 +557,12 @@ static int exp_seq_show(struct seq_file *s, void *v) | |||
529 | seq_printf(s, "PERMANENT"); | 557 | seq_printf(s, "PERMANENT"); |
530 | delim = ","; | 558 | delim = ","; |
531 | } | 559 | } |
532 | if (expect->flags & NF_CT_EXPECT_INACTIVE) | 560 | if (expect->flags & NF_CT_EXPECT_INACTIVE) { |
533 | seq_printf(s, "%sINACTIVE", delim); | 561 | seq_printf(s, "%sINACTIVE", delim); |
562 | delim = ","; | ||
563 | } | ||
564 | if (expect->flags & NF_CT_EXPECT_USERSPACE) | ||
565 | seq_printf(s, "%sUSERSPACE", delim); | ||
534 | 566 | ||
535 | helper = rcu_dereference(nfct_help(expect->master)->helper); | 567 | helper = rcu_dereference(nfct_help(expect->master)->helper); |
536 | if (helper) { | 568 | if (helper) { |