aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netfilter/nf_conntrack.h26
-rw-r--r--include/net/netfilter/nf_conntrack_core.h3
-rw-r--r--include/net/netfilter/nf_conntrack_extend.h3
-rw-r--r--include/net/netfilter/nf_conntrack_helper.h5
-rw-r--r--net/ipv4/netfilter/nf_nat_standalone.c10
-rw-r--r--net/netfilter/nf_conntrack_core.c80
-rw-r--r--net/netfilter/nf_conntrack_helper.c27
-rw-r--r--net/netfilter/nf_conntrack_netlink.c37
8 files changed, 99 insertions, 92 deletions
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index c31382d3ef11..f1e0fee9aa9c 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -294,32 +294,6 @@ static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct)
294 offset = ALIGN(offset, __alignof__(struct nf_conn_nat)); 294 offset = ALIGN(offset, __alignof__(struct nf_conn_nat));
295 return (struct nf_conn_nat *) ((void *)ct + offset); 295 return (struct nf_conn_nat *) ((void *)ct + offset);
296} 296}
297
298static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
299{
300 unsigned int offset = sizeof(struct nf_conn);
301
302 if (!(ct->features & NF_CT_F_HELP))
303 return NULL;
304 if (ct->features & NF_CT_F_NAT) {
305 offset = ALIGN(offset, __alignof__(struct nf_conn_nat));
306 offset += sizeof(struct nf_conn_nat);
307 }
308
309 offset = ALIGN(offset, __alignof__(struct nf_conn_help));
310 return (struct nf_conn_help *) ((void *)ct + offset);
311}
312#else /* No NAT */
313static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
314{
315 unsigned int offset = sizeof(struct nf_conn);
316
317 if (!(ct->features & NF_CT_F_HELP))
318 return NULL;
319
320 offset = ALIGN(offset, __alignof__(struct nf_conn_help));
321 return (struct nf_conn_help *) ((void *)ct + offset);
322}
323#endif /* CONFIG_NF_NAT_NEEDED */ 297#endif /* CONFIG_NF_NAT_NEEDED */
324#endif /* __KERNEL__ */ 298#endif /* __KERNEL__ */
325#endif /* _NF_CONNTRACK_H */ 299#endif /* _NF_CONNTRACK_H */
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index 9fb906688ffa..3bf7d05ea64d 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -30,6 +30,9 @@ extern void nf_conntrack_cleanup(void);
30extern int nf_conntrack_proto_init(void); 30extern int nf_conntrack_proto_init(void);
31extern void nf_conntrack_proto_fini(void); 31extern void nf_conntrack_proto_fini(void);
32 32
33extern int nf_conntrack_helper_init(void);
34extern void nf_conntrack_helper_fini(void);
35
33struct nf_conntrack_l3proto; 36struct nf_conntrack_l3proto;
34extern struct nf_conntrack_l3proto *nf_ct_find_l3proto(u_int16_t pf); 37extern struct nf_conntrack_l3proto *nf_ct_find_l3proto(u_int16_t pf);
35/* Like above, but you already have conntrack read lock. */ 38/* Like above, but you already have conntrack read lock. */
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
index 8a988d136465..05357dc5d2d2 100644
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -5,9 +5,12 @@
5 5
6enum nf_ct_ext_id 6enum nf_ct_ext_id
7{ 7{
8 NF_CT_EXT_HELPER,
8 NF_CT_EXT_NUM, 9 NF_CT_EXT_NUM,
9}; 10};
10 11
12#define NF_CT_EXT_HELPER_TYPE struct nf_conn_help
13
11/* Extensions: optional stuff which isn't permanently in struct. */ 14/* Extensions: optional stuff which isn't permanently in struct. */
12struct nf_ct_ext { 15struct nf_ct_ext {
13 u8 offset[NF_CT_EXT_NUM]; 16 u8 offset[NF_CT_EXT_NUM];
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index 8c72ac9f0ab8..b43a75ba44ac 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -10,6 +10,7 @@
10#ifndef _NF_CONNTRACK_HELPER_H 10#ifndef _NF_CONNTRACK_HELPER_H
11#define _NF_CONNTRACK_HELPER_H 11#define _NF_CONNTRACK_HELPER_H
12#include <net/netfilter/nf_conntrack.h> 12#include <net/netfilter/nf_conntrack.h>
13#include <net/netfilter/nf_conntrack_extend.h>
13 14
14struct module; 15struct module;
15 16
@@ -52,4 +53,8 @@ extern void nf_ct_helper_put(struct nf_conntrack_helper *helper);
52extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); 53extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
53extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); 54extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
54 55
56static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
57{
58 return nf_ct_ext_find(ct, NF_CT_EXT_HELPER);
59}
55#endif /*_NF_CONNTRACK_HELPER_H*/ 60#endif /*_NF_CONNTRACK_HELPER_H*/
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index 55dac36dbc85..0b2f0c33f7cd 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -338,14 +338,6 @@ static int __init nf_nat_standalone_init(void)
338 return ret; 338 return ret;
339 } 339 }
340 340
341 size = ALIGN(size, __alignof__(struct nf_conn_help)) +
342 sizeof(struct nf_conn_help);
343 ret = nf_conntrack_register_cache(NF_CT_F_NAT|NF_CT_F_HELP,
344 "nf_nat:help", size);
345 if (ret < 0) {
346 printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n");
347 goto cleanup_register_cache;
348 }
349#ifdef CONFIG_XFRM 341#ifdef CONFIG_XFRM
350 BUG_ON(ip_nat_decode_session != NULL); 342 BUG_ON(ip_nat_decode_session != NULL);
351 ip_nat_decode_session = nat_decode_session; 343 ip_nat_decode_session = nat_decode_session;
@@ -370,8 +362,6 @@ static int __init nf_nat_standalone_init(void)
370 ip_nat_decode_session = NULL; 362 ip_nat_decode_session = NULL;
371 synchronize_net(); 363 synchronize_net();
372#endif 364#endif
373 nf_conntrack_unregister_cache(NF_CT_F_NAT|NF_CT_F_HELP);
374 cleanup_register_cache:
375 nf_conntrack_unregister_cache(NF_CT_F_NAT); 365 nf_conntrack_unregister_cache(NF_CT_F_NAT);
376 return ret; 366 return ret;
377} 367}
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index b56f954895bb..914506e6c787 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -566,7 +566,6 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
566 u_int32_t features) 566 u_int32_t features)
567{ 567{
568 struct nf_conn *conntrack = NULL; 568 struct nf_conn *conntrack = NULL;
569 struct nf_conntrack_helper *helper;
570 569
571 if (unlikely(!nf_conntrack_hash_rnd_initted)) { 570 if (unlikely(!nf_conntrack_hash_rnd_initted)) {
572 get_random_bytes(&nf_conntrack_hash_rnd, 4); 571 get_random_bytes(&nf_conntrack_hash_rnd, 4);
@@ -593,14 +592,6 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
593 /* find features needed by this conntrack. */ 592 /* find features needed by this conntrack. */
594 features |= l3proto->get_features(orig); 593 features |= l3proto->get_features(orig);
595 594
596 /* FIXME: protect helper list per RCU */
597 read_lock_bh(&nf_conntrack_lock);
598 helper = __nf_ct_helper_find(repl);
599 /* NAT might want to assign a helper later */
600 if (helper || features & NF_CT_F_NAT)
601 features |= NF_CT_F_HELP;
602 read_unlock_bh(&nf_conntrack_lock);
603
604 DEBUGP("nf_conntrack_alloc: features=0x%x\n", features); 595 DEBUGP("nf_conntrack_alloc: features=0x%x\n", features);
605 596
606 read_lock_bh(&nf_ct_cache_lock); 597 read_lock_bh(&nf_ct_cache_lock);
@@ -681,12 +672,6 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
681 return NULL; 672 return NULL;
682 } 673 }
683 674
684 read_lock_bh(&nf_conntrack_lock);
685 exp = __nf_conntrack_expect_find(tuple);
686 if (exp && exp->helper)
687 features = NF_CT_F_HELP;
688 read_unlock_bh(&nf_conntrack_lock);
689
690 conntrack = __nf_conntrack_alloc(tuple, &repl_tuple, l3proto, features); 675 conntrack = __nf_conntrack_alloc(tuple, &repl_tuple, l3proto, features);
691 if (conntrack == NULL || IS_ERR(conntrack)) { 676 if (conntrack == NULL || IS_ERR(conntrack)) {
692 DEBUGP("Can't allocate conntrack.\n"); 677 DEBUGP("Can't allocate conntrack.\n");
@@ -701,16 +686,21 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
701 686
702 write_lock_bh(&nf_conntrack_lock); 687 write_lock_bh(&nf_conntrack_lock);
703 exp = find_expectation(tuple); 688 exp = find_expectation(tuple);
704
705 help = nfct_help(conntrack);
706 if (exp) { 689 if (exp) {
707 DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", 690 DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
708 conntrack, exp); 691 conntrack, exp);
709 /* Welcome, Mr. Bond. We've been expecting you... */ 692 /* Welcome, Mr. Bond. We've been expecting you... */
710 __set_bit(IPS_EXPECTED_BIT, &conntrack->status); 693 __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
711 conntrack->master = exp->master; 694 conntrack->master = exp->master;
712 if (exp->helper) 695 if (exp->helper) {
713 rcu_assign_pointer(help->helper, exp->helper); 696 help = nf_ct_ext_add(conntrack, NF_CT_EXT_HELPER,
697 GFP_ATOMIC);
698 if (help)
699 rcu_assign_pointer(help->helper, exp->helper);
700 else
701 DEBUGP("failed to add helper extension area");
702 }
703
714#ifdef CONFIG_NF_CONNTRACK_MARK 704#ifdef CONFIG_NF_CONNTRACK_MARK
715 conntrack->mark = exp->master->mark; 705 conntrack->mark = exp->master->mark;
716#endif 706#endif
@@ -720,10 +710,18 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
720 nf_conntrack_get(&conntrack->master->ct_general); 710 nf_conntrack_get(&conntrack->master->ct_general);
721 NF_CT_STAT_INC(expect_new); 711 NF_CT_STAT_INC(expect_new);
722 } else { 712 } else {
723 if (help) { 713 struct nf_conntrack_helper *helper;
724 /* not in hash table yet, so not strictly necessary */ 714
725 rcu_assign_pointer(help->helper, 715 helper = __nf_ct_helper_find(&repl_tuple);
726 __nf_ct_helper_find(&repl_tuple)); 716 if (helper) {
717 help = nf_ct_ext_add(conntrack, NF_CT_EXT_HELPER,
718 GFP_ATOMIC);
719 if (help)
720 /* not in hash table yet, so not strictly
721 necessary */
722 rcu_assign_pointer(help->helper, helper);
723 else
724 DEBUGP("failed to add helper extension area");
727 } 725 }
728 NF_CT_STAT_INC(new); 726 NF_CT_STAT_INC(new);
729 } 727 }
@@ -892,6 +890,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
892 const struct nf_conntrack_tuple *newreply) 890 const struct nf_conntrack_tuple *newreply)
893{ 891{
894 struct nf_conn_help *help = nfct_help(ct); 892 struct nf_conn_help *help = nfct_help(ct);
893 struct nf_conntrack_helper *helper;
895 894
896 write_lock_bh(&nf_conntrack_lock); 895 write_lock_bh(&nf_conntrack_lock);
897 /* Should be unconfirmed, so not in hash table yet */ 896 /* Should be unconfirmed, so not in hash table yet */
@@ -901,14 +900,28 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
901 NF_CT_DUMP_TUPLE(newreply); 900 NF_CT_DUMP_TUPLE(newreply);
902 901
903 ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; 902 ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
904 if (!ct->master && help && help->expecting == 0) { 903 if (ct->master || (help && help->expecting != 0))
905 struct nf_conntrack_helper *helper; 904 goto out;
906 helper = __nf_ct_helper_find(newreply); 905
907 if (helper) 906 helper = __nf_ct_helper_find(newreply);
908 memset(&help->help, 0, sizeof(help->help)); 907 if (helper == NULL) {
909 /* not in hash table yet, so not strictly necessary */ 908 if (help)
910 rcu_assign_pointer(help->helper, helper); 909 rcu_assign_pointer(help->helper, NULL);
910 goto out;
911 } 911 }
912
913 if (help == NULL) {
914 help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, GFP_ATOMIC);
915 if (help == NULL) {
916 DEBUGP("failed to add helper extension area");
917 goto out;
918 }
919 } else {
920 memset(&help->help, 0, sizeof(help->help));
921 }
922
923 rcu_assign_pointer(help->helper, helper);
924out:
912 write_unlock_bh(&nf_conntrack_lock); 925 write_unlock_bh(&nf_conntrack_lock);
913} 926}
914EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); 927EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);
@@ -1150,6 +1163,7 @@ void nf_conntrack_cleanup(void)
1150 nf_conntrack_htable_size); 1163 nf_conntrack_htable_size);
1151 1164
1152 nf_conntrack_proto_fini(); 1165 nf_conntrack_proto_fini();
1166 nf_conntrack_helper_fini();
1153} 1167}
1154 1168
1155static struct list_head *alloc_hashtable(int size, int *vmalloced) 1169static struct list_head *alloc_hashtable(int size, int *vmalloced)
@@ -1272,6 +1286,10 @@ int __init nf_conntrack_init(void)
1272 if (ret < 0) 1286 if (ret < 0)
1273 goto out_free_expect_slab; 1287 goto out_free_expect_slab;
1274 1288
1289 ret = nf_conntrack_helper_init();
1290 if (ret < 0)
1291 goto out_fini_proto;
1292
1275 /* For use by REJECT target */ 1293 /* For use by REJECT target */
1276 rcu_assign_pointer(ip_ct_attach, __nf_conntrack_attach); 1294 rcu_assign_pointer(ip_ct_attach, __nf_conntrack_attach);
1277 rcu_assign_pointer(nf_ct_destroy, destroy_conntrack); 1295 rcu_assign_pointer(nf_ct_destroy, destroy_conntrack);
@@ -1284,6 +1302,8 @@ int __init nf_conntrack_init(void)
1284 1302
1285 return ret; 1303 return ret;
1286 1304
1305out_fini_proto:
1306 nf_conntrack_proto_fini();
1287out_free_expect_slab: 1307out_free_expect_slab:
1288 kmem_cache_destroy(nf_conntrack_expect_cachep); 1308 kmem_cache_destroy(nf_conntrack_expect_cachep);
1289err_free_conntrack_slab: 1309err_free_conntrack_slab:
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index f868b7fbd9b4..6d32399d64e1 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -26,6 +26,7 @@
26#include <net/netfilter/nf_conntrack_l4proto.h> 26#include <net/netfilter/nf_conntrack_l4proto.h>
27#include <net/netfilter/nf_conntrack_helper.h> 27#include <net/netfilter/nf_conntrack_helper.h>
28#include <net/netfilter/nf_conntrack_core.h> 28#include <net/netfilter/nf_conntrack_core.h>
29#include <net/netfilter/nf_conntrack_extend.h>
29 30
30static __read_mostly LIST_HEAD(helpers); 31static __read_mostly LIST_HEAD(helpers);
31 32
@@ -100,18 +101,8 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i,
100 101
101int nf_conntrack_helper_register(struct nf_conntrack_helper *me) 102int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
102{ 103{
103 int size, ret;
104
105 BUG_ON(me->timeout == 0); 104 BUG_ON(me->timeout == 0);
106 105
107 size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_help)) +
108 sizeof(struct nf_conn_help);
109 ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help",
110 size);
111 if (ret < 0) {
112 printk(KERN_ERR "nf_conntrack_helper_register: Unable to create slab cache for conntracks\n");
113 return ret;
114 }
115 write_lock_bh(&nf_conntrack_lock); 106 write_lock_bh(&nf_conntrack_lock);
116 list_add(&me->list, &helpers); 107 list_add(&me->list, &helpers);
117 write_unlock_bh(&nf_conntrack_lock); 108 write_unlock_bh(&nf_conntrack_lock);
@@ -153,3 +144,19 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
153 synchronize_net(); 144 synchronize_net();
154} 145}
155EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister); 146EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
147
148struct nf_ct_ext_type helper_extend = {
149 .len = sizeof(struct nf_conn_help),
150 .align = __alignof__(struct nf_conn_help),
151 .id = NF_CT_EXT_HELPER,
152};
153
154int nf_conntrack_helper_init()
155{
156 return nf_ct_extend_register(&helper_extend);
157}
158
159void nf_conntrack_helper_fini()
160{
161 nf_ct_extend_unregister(&helper_extend);
162}
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index d0fe3d769828..3d56f36074f7 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -856,23 +856,23 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
856 return 0; 856 return 0;
857 } 857 }
858 858
859 if (!help) {
860 /* FIXME: we need to reallocate and rehash */
861 return -EBUSY;
862 }
863
864 helper = __nf_conntrack_helper_find_byname(helpname); 859 helper = __nf_conntrack_helper_find_byname(helpname);
865 if (helper == NULL) 860 if (helper == NULL)
866 return -EINVAL; 861 return -EINVAL;
867 862
868 if (help->helper == helper) 863 if (help) {
869 return 0; 864 if (help->helper == helper)
870 865 return 0;
871 if (help->helper) 866 if (help->helper)
872 return -EBUSY; 867 return -EBUSY;
868 /* need to zero data of old helper */
869 memset(&help->help, 0, sizeof(help->help));
870 } else {
871 help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, GFP_KERNEL);
872 if (help == NULL)
873 return -ENOMEM;
874 }
873 875
874 /* need to zero data of old helper */
875 memset(&help->help, 0, sizeof(help->help));
876 rcu_assign_pointer(help->helper, helper); 876 rcu_assign_pointer(help->helper, helper);
877 877
878 return 0; 878 return 0;
@@ -957,7 +957,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
957 struct nf_conn *ct; 957 struct nf_conn *ct;
958 int err = -EINVAL; 958 int err = -EINVAL;
959 struct nf_conn_help *help; 959 struct nf_conn_help *help;
960 struct nf_conntrack_helper *helper = NULL; 960 struct nf_conntrack_helper *helper;
961 961
962 ct = nf_conntrack_alloc(otuple, rtuple); 962 ct = nf_conntrack_alloc(otuple, rtuple);
963 if (ct == NULL || IS_ERR(ct)) 963 if (ct == NULL || IS_ERR(ct))
@@ -987,9 +987,14 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
987 ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); 987 ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1]));
988#endif 988#endif
989 989
990 help = nfct_help(ct); 990 helper = nf_ct_helper_find_get(rtuple);
991 if (help) { 991 if (helper) {
992 helper = nf_ct_helper_find_get(rtuple); 992 help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, GFP_KERNEL);
993 if (help == NULL) {
994 nf_ct_helper_put(helper);
995 err = -ENOMEM;
996 goto err;
997 }
993 /* not in hash table yet so not strictly necessary */ 998 /* not in hash table yet so not strictly necessary */
994 rcu_assign_pointer(help->helper, helper); 999 rcu_assign_pointer(help->helper, helper);
995 } 1000 }