aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Leblond <eric@regit.org>2012-04-18 05:20:41 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2012-05-08 13:35:18 -0400
commita9006892643a8f4e885b692de0708bcb35a7d530 (patch)
treede5ba86bb36d05cd859bffb2370a9a3b462722d9
parent031d7709f21c778bcb1eed96d790e82b3bee96b5 (diff)
netfilter: nf_ct_helper: allow to disable automatic helper assignment
This patch allows you to disable automatic conntrack helper lookup based on TCP/UDP ports, eg. echo 0 > /proc/sys/net/netfilter/nf_conntrack_helper [ Note: flows that already got a helper will keep using it even if automatic helper assignment has been disabled ] Once this behaviour has been disabled, you have to explicitly use the iptables CT target to attach helper to flows. There are good reasons to stop supporting automatic helper assignment, for further information, please read: http://www.netfilter.org/news.html#2012-04-03 This patch also adds one message to inform that automatic helper assignment is deprecated and it will be removed soon (this is spotted only once, with the first flow that gets a helper attached to make it as less annoying as possible). Signed-off-by: Eric Leblond <eric@regit.org> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/net/netfilter/nf_conntrack_helper.h4
-rw-r--r--include/net/netns/conntrack.h3
-rw-r--r--net/netfilter/nf_conntrack_core.c15
-rw-r--r--net/netfilter/nf_conntrack_helper.c109
4 files changed, 110 insertions, 21 deletions
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index 5767dc242dee..1d1889409b9e 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -60,8 +60,8 @@ static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
60 return nf_ct_ext_find(ct, NF_CT_EXT_HELPER); 60 return nf_ct_ext_find(ct, NF_CT_EXT_HELPER);
61} 61}
62 62
63extern int nf_conntrack_helper_init(void); 63extern int nf_conntrack_helper_init(struct net *net);
64extern void nf_conntrack_helper_fini(void); 64extern void nf_conntrack_helper_fini(struct net *net);
65 65
66extern int nf_conntrack_broadcast_help(struct sk_buff *skb, 66extern int nf_conntrack_broadcast_help(struct sk_buff *skb,
67 unsigned int protoff, 67 unsigned int protoff,
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
index 7a911eca0f18..a053a19870cf 100644
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -26,11 +26,14 @@ struct netns_ct {
26 int sysctl_tstamp; 26 int sysctl_tstamp;
27 int sysctl_checksum; 27 int sysctl_checksum;
28 unsigned int sysctl_log_invalid; /* Log invalid packets */ 28 unsigned int sysctl_log_invalid; /* Log invalid packets */
29 int sysctl_auto_assign_helper;
30 bool auto_assign_helper_warned;
29#ifdef CONFIG_SYSCTL 31#ifdef CONFIG_SYSCTL
30 struct ctl_table_header *sysctl_header; 32 struct ctl_table_header *sysctl_header;
31 struct ctl_table_header *acct_sysctl_header; 33 struct ctl_table_header *acct_sysctl_header;
32 struct ctl_table_header *tstamp_sysctl_header; 34 struct ctl_table_header *tstamp_sysctl_header;
33 struct ctl_table_header *event_sysctl_header; 35 struct ctl_table_header *event_sysctl_header;
36 struct ctl_table_header *helper_sysctl_header;
34#endif 37#endif
35 char *slabname; 38 char *slabname;
36}; 39};
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index cf0747c5741f..32c59093146e 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1336,7 +1336,6 @@ static void nf_conntrack_cleanup_init_net(void)
1336 while (untrack_refs() > 0) 1336 while (untrack_refs() > 0)
1337 schedule(); 1337 schedule();
1338 1338
1339 nf_conntrack_helper_fini();
1340 nf_conntrack_proto_fini(); 1339 nf_conntrack_proto_fini();
1341#ifdef CONFIG_NF_CONNTRACK_ZONES 1340#ifdef CONFIG_NF_CONNTRACK_ZONES
1342 nf_ct_extend_unregister(&nf_ct_zone_extend); 1341 nf_ct_extend_unregister(&nf_ct_zone_extend);
@@ -1354,6 +1353,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
1354 } 1353 }
1355 1354
1356 nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); 1355 nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
1356 nf_conntrack_helper_fini(net);
1357 nf_conntrack_timeout_fini(net); 1357 nf_conntrack_timeout_fini(net);
1358 nf_conntrack_ecache_fini(net); 1358 nf_conntrack_ecache_fini(net);
1359 nf_conntrack_tstamp_fini(net); 1359 nf_conntrack_tstamp_fini(net);
@@ -1504,10 +1504,6 @@ static int nf_conntrack_init_init_net(void)
1504 if (ret < 0) 1504 if (ret < 0)
1505 goto err_proto; 1505 goto err_proto;
1506 1506
1507 ret = nf_conntrack_helper_init();
1508 if (ret < 0)
1509 goto err_helper;
1510
1511#ifdef CONFIG_NF_CONNTRACK_ZONES 1507#ifdef CONFIG_NF_CONNTRACK_ZONES
1512 ret = nf_ct_extend_register(&nf_ct_zone_extend); 1508 ret = nf_ct_extend_register(&nf_ct_zone_extend);
1513 if (ret < 0) 1509 if (ret < 0)
@@ -1525,10 +1521,8 @@ static int nf_conntrack_init_init_net(void)
1525 1521
1526#ifdef CONFIG_NF_CONNTRACK_ZONES 1522#ifdef CONFIG_NF_CONNTRACK_ZONES
1527err_extend: 1523err_extend:
1528 nf_conntrack_helper_fini();
1529#endif
1530err_helper:
1531 nf_conntrack_proto_fini(); 1524 nf_conntrack_proto_fini();
1525#endif
1532err_proto: 1526err_proto:
1533 return ret; 1527 return ret;
1534} 1528}
@@ -1589,9 +1583,14 @@ static int nf_conntrack_init_net(struct net *net)
1589 ret = nf_conntrack_timeout_init(net); 1583 ret = nf_conntrack_timeout_init(net);
1590 if (ret < 0) 1584 if (ret < 0)
1591 goto err_timeout; 1585 goto err_timeout;
1586 ret = nf_conntrack_helper_init(net);
1587 if (ret < 0)
1588 goto err_helper;
1592 1589
1593 return 0; 1590 return 0;
1594 1591
1592err_helper:
1593 nf_conntrack_timeout_fini(net);
1595err_timeout: 1594err_timeout:
1596 nf_conntrack_ecache_fini(net); 1595 nf_conntrack_ecache_fini(net);
1597err_ecache: 1596err_ecache:
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 436b7cb79ba4..317f6e43db87 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -34,6 +34,67 @@ static struct hlist_head *nf_ct_helper_hash __read_mostly;
34static unsigned int nf_ct_helper_hsize __read_mostly; 34static unsigned int nf_ct_helper_hsize __read_mostly;
35static unsigned int nf_ct_helper_count __read_mostly; 35static unsigned int nf_ct_helper_count __read_mostly;
36 36
37static bool nf_ct_auto_assign_helper __read_mostly = true;
38module_param_named(nf_conntrack_helper, nf_ct_auto_assign_helper, bool, 0644);
39MODULE_PARM_DESC(nf_conntrack_helper,
40 "Enable automatic conntrack helper assignment (default 1)");
41
42#ifdef CONFIG_SYSCTL
43static struct ctl_table helper_sysctl_table[] = {
44 {
45 .procname = "nf_conntrack_helper",
46 .data = &init_net.ct.sysctl_auto_assign_helper,
47 .maxlen = sizeof(unsigned int),
48 .mode = 0644,
49 .proc_handler = proc_dointvec,
50 },
51 {}
52};
53
54static int nf_conntrack_helper_init_sysctl(struct net *net)
55{
56 struct ctl_table *table;
57
58 table = kmemdup(helper_sysctl_table, sizeof(helper_sysctl_table),
59 GFP_KERNEL);
60 if (!table)
61 goto out;
62
63 table[0].data = &net->ct.sysctl_auto_assign_helper;
64
65 net->ct.helper_sysctl_header =
66 register_net_sysctl(net, "net/netfilter", table);
67
68 if (!net->ct.helper_sysctl_header) {
69 pr_err("nf_conntrack_helper: can't register to sysctl.\n");
70 goto out_register;
71 }
72 return 0;
73
74out_register:
75 kfree(table);
76out:
77 return -ENOMEM;
78}
79
80static void nf_conntrack_helper_fini_sysctl(struct net *net)
81{
82 struct ctl_table *table;
83
84 table = net->ct.helper_sysctl_header->ctl_table_arg;
85 unregister_net_sysctl_table(net->ct.helper_sysctl_header);
86 kfree(table);
87}
88#else
89static int nf_conntrack_helper_init_sysctl(struct net *net)
90{
91 return 0;
92}
93
94static void nf_conntrack_helper_fini_sysctl(struct net *net)
95{
96}
97#endif /* CONFIG_SYSCTL */
37 98
38/* Stupid hash, but collision free for the default registrations of the 99/* Stupid hash, but collision free for the default registrations of the
39 * helpers currently in the kernel. */ 100 * helpers currently in the kernel. */
@@ -118,6 +179,7 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
118{ 179{
119 struct nf_conntrack_helper *helper = NULL; 180 struct nf_conntrack_helper *helper = NULL;
120 struct nf_conn_help *help; 181 struct nf_conn_help *help;
182 struct net *net = nf_ct_net(ct);
121 int ret = 0; 183 int ret = 0;
122 184
123 if (tmpl != NULL) { 185 if (tmpl != NULL) {
@@ -127,8 +189,17 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
127 } 189 }
128 190
129 help = nfct_help(ct); 191 help = nfct_help(ct);
130 if (helper == NULL) 192 if (net->ct.sysctl_auto_assign_helper && helper == NULL) {
131 helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); 193 helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
194 if (unlikely(!net->ct.auto_assign_helper_warned && helper)) {
195 pr_info("nf_conntrack: automatic helper "
196 "assignment is deprecated and it will "
197 "be removed soon. Use the iptables CT target "
198 "to attach helpers instead.\n");
199 net->ct.auto_assign_helper_warned = true;
200 }
201 }
202
132 if (helper == NULL) { 203 if (helper == NULL) {
133 if (help) 204 if (help)
134 RCU_INIT_POINTER(help->helper, NULL); 205 RCU_INIT_POINTER(help->helper, NULL);
@@ -315,28 +386,44 @@ static struct nf_ct_ext_type helper_extend __read_mostly = {
315 .id = NF_CT_EXT_HELPER, 386 .id = NF_CT_EXT_HELPER,
316}; 387};
317 388
318int nf_conntrack_helper_init(void) 389int nf_conntrack_helper_init(struct net *net)
319{ 390{
320 int err; 391 int err;
321 392
322 nf_ct_helper_hsize = 1; /* gets rounded up to use one page */ 393 net->ct.auto_assign_helper_warned = false;
323 nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize, 0); 394 net->ct.sysctl_auto_assign_helper = nf_ct_auto_assign_helper;
324 if (!nf_ct_helper_hash)
325 return -ENOMEM;
326 395
327 err = nf_ct_extend_register(&helper_extend); 396 if (net_eq(net, &init_net)) {
397 nf_ct_helper_hsize = 1; /* gets rounded up to use one page */
398 nf_ct_helper_hash =
399 nf_ct_alloc_hashtable(&nf_ct_helper_hsize, 0);
400 if (!nf_ct_helper_hash)
401 return -ENOMEM;
402
403 err = nf_ct_extend_register(&helper_extend);
404 if (err < 0)
405 goto err1;
406 }
407
408 err = nf_conntrack_helper_init_sysctl(net);
328 if (err < 0) 409 if (err < 0)
329 goto err1; 410 goto out_sysctl;
330 411
331 return 0; 412 return 0;
332 413
414out_sysctl:
415 if (net_eq(net, &init_net))
416 nf_ct_extend_unregister(&helper_extend);
333err1: 417err1:
334 nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize); 418 nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize);
335 return err; 419 return err;
336} 420}
337 421
338void nf_conntrack_helper_fini(void) 422void nf_conntrack_helper_fini(struct net *net)
339{ 423{
340 nf_ct_extend_unregister(&helper_extend); 424 nf_conntrack_helper_fini_sysctl(net);
341 nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize); 425 if (net_eq(net, &init_net)) {
426 nf_ct_extend_unregister(&helper_extend);
427 nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize);
428 }
342} 429}