aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-11-28 20:35:17 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-03 00:31:17 -0500
commitd62f9ed4a490309bd9e5df0b42ba5d096e7b5902 (patch)
tree8d0791c4e4d711c7ae0c259d80553a85dbfe62bd
parentf8eb24a89afa12b48fa7e39775faea6d64b8e538 (diff)
[NETFILTER]: nf_conntrack: automatic sysctl registation for conntrack protocols
Add helper functions for sysctl registration with optional instantiating of common path elements (like net/netfilter) and use it for support for automatic registation of conntrack protocol sysctls. Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--include/linux/netfilter.h10
-rw-r--r--include/net/netfilter/nf_conntrack_l3proto.h6
-rw-r--r--include/net/netfilter/nf_conntrack_l4proto.h6
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/nf_conntrack_proto.c102
-rw-r--r--net/netfilter/nf_sysctl.c134
6 files changed, 259 insertions, 0 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 6ab5e2d6133e..f6f3fcbd70ed 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -117,6 +117,16 @@ void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n);
117int nf_register_sockopt(struct nf_sockopt_ops *reg); 117int nf_register_sockopt(struct nf_sockopt_ops *reg);
118void nf_unregister_sockopt(struct nf_sockopt_ops *reg); 118void nf_unregister_sockopt(struct nf_sockopt_ops *reg);
119 119
120#ifdef CONFIG_SYSCTL
121/* Sysctl registration */
122struct ctl_table_header *nf_register_sysctl_table(struct ctl_table *path,
123 struct ctl_table *table);
124void nf_unregister_sysctl_table(struct ctl_table_header *header,
125 struct ctl_table *table);
126extern struct ctl_table nf_net_netfilter_sysctl_path[];
127extern struct ctl_table nf_net_ipv4_netfilter_sysctl_path[];
128#endif /* CONFIG_SYSCTL */
129
120extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; 130extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
121 131
122/* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will 132/* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index 6364df059422..664ddcffe00d 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -75,6 +75,12 @@ struct nf_conntrack_l3proto
75 int (*nfattr_to_tuple)(struct nfattr *tb[], 75 int (*nfattr_to_tuple)(struct nfattr *tb[],
76 struct nf_conntrack_tuple *t); 76 struct nf_conntrack_tuple *t);
77 77
78#ifdef CONFIG_SYSCTL
79 struct ctl_table_header *ctl_table_header;
80 struct ctl_table *ctl_table_path;
81 struct ctl_table *ctl_table;
82#endif /* CONFIG_SYSCTL */
83
78 /* Module (if any) which this is connected to. */ 84 /* Module (if any) which this is connected to. */
79 struct module *me; 85 struct module *me;
80}; 86};
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
index c22804aa227e..fe1e8fa30d2f 100644
--- a/include/net/netfilter/nf_conntrack_l4proto.h
+++ b/include/net/netfilter/nf_conntrack_l4proto.h
@@ -76,6 +76,12 @@ struct nf_conntrack_l4proto
76 int (*nfattr_to_tuple)(struct nfattr *tb[], 76 int (*nfattr_to_tuple)(struct nfattr *tb[],
77 struct nf_conntrack_tuple *t); 77 struct nf_conntrack_tuple *t);
78 78
79#ifdef CONFIG_SYSCTL
80 struct ctl_table_header **ctl_table_header;
81 struct ctl_table *ctl_table;
82 unsigned int *ctl_table_users;
83#endif /* CONFIG_SYSCTL */
84
79 /* Module (if any) which this is connected to. */ 85 /* Module (if any) which this is connected to. */
80 struct module *me; 86 struct module *me;
81}; 87};
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 627105df1040..84d529ded952 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -4,6 +4,7 @@ nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_exp
4nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o 4nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o
5 5
6obj-$(CONFIG_NETFILTER) = netfilter.o 6obj-$(CONFIG_NETFILTER) = netfilter.o
7obj-$(CONFIG_SYSCTL) += nf_sysctl.o
7 8
8obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o 9obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o
9obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o 10obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index a6a3b1ddd00d..941b5c3754af 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -12,6 +12,7 @@
12#include <linux/types.h> 12#include <linux/types.h>
13#include <linux/netfilter.h> 13#include <linux/netfilter.h>
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/mutex.h>
15#include <linux/skbuff.h> 16#include <linux/skbuff.h>
16#include <linux/vmalloc.h> 17#include <linux/vmalloc.h>
17#include <linux/stddef.h> 18#include <linux/stddef.h>
@@ -30,6 +31,34 @@
30struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly; 31struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly;
31struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly; 32struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly;
32 33
34#ifdef CONFIG_SYSCTL
35static DEFINE_MUTEX(nf_ct_proto_sysctl_mutex);
36
37static int
38nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_table *path,
39 struct ctl_table *table, unsigned int *users)
40{
41 if (*header == NULL) {
42 *header = nf_register_sysctl_table(path, table);
43 if (*header == NULL)
44 return -ENOMEM;
45 }
46 if (users != NULL)
47 (*users)++;
48 return 0;
49}
50
51static void
52nf_ct_unregister_sysctl(struct ctl_table_header **header,
53 struct ctl_table *table, unsigned int *users)
54{
55 if (users != NULL && --*users > 0)
56 return;
57 nf_unregister_sysctl_table(*header, table);
58 *header = NULL;
59}
60#endif
61
33struct nf_conntrack_l4proto * 62struct nf_conntrack_l4proto *
34__nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) 63__nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto)
35{ 64{
@@ -124,6 +153,33 @@ static int kill_l4proto(struct nf_conn *i, void *data)
124 l4proto->l3proto); 153 l4proto->l3proto);
125} 154}
126 155
156static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto)
157{
158 int err = 0;
159
160#ifdef CONFIG_SYSCTL
161 mutex_lock(&nf_ct_proto_sysctl_mutex);
162 if (l3proto->ctl_table != NULL) {
163 err = nf_ct_register_sysctl(&l3proto->ctl_table_header,
164 l3proto->ctl_table_path,
165 l3proto->ctl_table, NULL);
166 }
167 mutex_unlock(&nf_ct_proto_sysctl_mutex);
168#endif
169 return err;
170}
171
172static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto)
173{
174#ifdef CONFIG_SYSCTL
175 mutex_lock(&nf_ct_proto_sysctl_mutex);
176 if (l3proto->ctl_table_header != NULL)
177 nf_ct_unregister_sysctl(&l3proto->ctl_table_header,
178 l3proto->ctl_table, NULL);
179 mutex_unlock(&nf_ct_proto_sysctl_mutex);
180#endif
181}
182
127int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) 183int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
128{ 184{
129 int ret = 0; 185 int ret = 0;
@@ -139,6 +195,12 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
139 goto out_unlock; 195 goto out_unlock;
140 } 196 }
141 nf_ct_l3protos[proto->l3proto] = proto; 197 nf_ct_l3protos[proto->l3proto] = proto;
198 write_unlock_bh(&nf_conntrack_lock);
199
200 ret = nf_ct_l3proto_register_sysctl(proto);
201 if (ret < 0)
202 nf_conntrack_l3proto_unregister(proto);
203 return ret;
142 204
143out_unlock: 205out_unlock:
144 write_unlock_bh(&nf_conntrack_lock); 206 write_unlock_bh(&nf_conntrack_lock);
@@ -165,6 +227,8 @@ int nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
165 nf_ct_l3protos[proto->l3proto] = &nf_conntrack_l3proto_generic; 227 nf_ct_l3protos[proto->l3proto] = &nf_conntrack_l3proto_generic;
166 write_unlock_bh(&nf_conntrack_lock); 228 write_unlock_bh(&nf_conntrack_lock);
167 229
230 nf_ct_l3proto_unregister_sysctl(proto);
231
168 /* Somebody could be still looking at the proto in bh. */ 232 /* Somebody could be still looking at the proto in bh. */
169 synchronize_net(); 233 synchronize_net();
170 234
@@ -175,6 +239,36 @@ out:
175 return ret; 239 return ret;
176} 240}
177 241
242static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto)
243{
244 int err = 0;
245
246#ifdef CONFIG_SYSCTL
247 mutex_lock(&nf_ct_proto_sysctl_mutex);
248 if (l4proto->ctl_table != NULL) {
249 err = nf_ct_register_sysctl(l4proto->ctl_table_header,
250 nf_net_netfilter_sysctl_path,
251 l4proto->ctl_table,
252 l4proto->ctl_table_users);
253 }
254 mutex_unlock(&nf_ct_proto_sysctl_mutex);
255#endif
256 return err;
257}
258
259static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto)
260{
261#ifdef CONFIG_SYSCTL
262 mutex_lock(&nf_ct_proto_sysctl_mutex);
263 if (l4proto->ctl_table_header != NULL &&
264 *l4proto->ctl_table_header != NULL)
265 nf_ct_unregister_sysctl(l4proto->ctl_table_header,
266 l4proto->ctl_table,
267 l4proto->ctl_table_users);
268 mutex_unlock(&nf_ct_proto_sysctl_mutex);
269#endif
270}
271
178/* FIXME: Allow NULL functions and sub in pointers to generic for 272/* FIXME: Allow NULL functions and sub in pointers to generic for
179 them. --RR */ 273 them. --RR */
180int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) 274int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
@@ -230,6 +324,12 @@ retry:
230 } 324 }
231 325
232 nf_ct_protos[l4proto->l3proto][l4proto->l4proto] = l4proto; 326 nf_ct_protos[l4proto->l3proto][l4proto->l4proto] = l4proto;
327 write_unlock_bh(&nf_conntrack_lock);
328
329 ret = nf_ct_l4proto_register_sysctl(l4proto);
330 if (ret < 0)
331 nf_conntrack_l4proto_unregister(l4proto);
332 return ret;
233 333
234out_unlock: 334out_unlock:
235 write_unlock_bh(&nf_conntrack_lock); 335 write_unlock_bh(&nf_conntrack_lock);
@@ -257,6 +357,8 @@ int nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
257 = &nf_conntrack_l4proto_generic; 357 = &nf_conntrack_l4proto_generic;
258 write_unlock_bh(&nf_conntrack_lock); 358 write_unlock_bh(&nf_conntrack_lock);
259 359
360 nf_ct_l4proto_unregister_sysctl(l4proto);
361
260 /* Somebody could be still looking at the proto in bh. */ 362 /* Somebody could be still looking at the proto in bh. */
261 synchronize_net(); 363 synchronize_net();
262 364
diff --git a/net/netfilter/nf_sysctl.c b/net/netfilter/nf_sysctl.c
new file mode 100644
index 000000000000..06ddddb2911f
--- /dev/null
+++ b/net/netfilter/nf_sysctl.c
@@ -0,0 +1,134 @@
1/* nf_sysctl.c netfilter sysctl registration/unregistation
2 *
3 * Copyright (c) 2006 Patrick McHardy <kaber@trash.net>
4 */
5#include <linux/module.h>
6#include <linux/sysctl.h>
7#include <linux/string.h>
8#include <linux/slab.h>
9
10static void
11path_free(struct ctl_table *path, struct ctl_table *table)
12{
13 struct ctl_table *t, *next;
14
15 for (t = path; t != NULL && t != table; t = next) {
16 next = t->child;
17 kfree(t);
18 }
19}
20
21static struct ctl_table *
22path_dup(struct ctl_table *path, struct ctl_table *table)
23{
24 struct ctl_table *t, *last = NULL, *tmp;
25
26 for (t = path; t != NULL; t = t->child) {
27 /* twice the size since path elements are terminated by an
28 * empty element */
29 tmp = kmemdup(t, 2 * sizeof(*t), GFP_KERNEL);
30 if (tmp == NULL) {
31 if (last != NULL)
32 path_free(path, table);
33 return NULL;
34 }
35
36 if (last != NULL)
37 last->child = tmp;
38 else
39 path = tmp;
40 last = tmp;
41 }
42
43 if (last != NULL)
44 last->child = table;
45 else
46 path = table;
47
48 return path;
49}
50
51struct ctl_table_header *
52nf_register_sysctl_table(struct ctl_table *path, struct ctl_table *table)
53{
54 struct ctl_table_header *header;
55
56 path = path_dup(path, table);
57 if (path == NULL)
58 return NULL;
59 header = register_sysctl_table(path, 0);
60 if (header == NULL)
61 path_free(path, table);
62 return header;
63}
64EXPORT_SYMBOL_GPL(nf_register_sysctl_table);
65
66void
67nf_unregister_sysctl_table(struct ctl_table_header *header,
68 struct ctl_table *table)
69{
70 struct ctl_table *path = header->ctl_table;
71
72 unregister_sysctl_table(header);
73 path_free(path, table);
74}
75EXPORT_SYMBOL_GPL(nf_unregister_sysctl_table);
76
77/* net/netfilter */
78static struct ctl_table nf_net_netfilter_table[] = {
79 {
80 .ctl_name = NET_NETFILTER,
81 .procname = "netfilter",
82 .mode = 0555,
83 },
84 {
85 .ctl_name = 0
86 }
87};
88struct ctl_table nf_net_netfilter_sysctl_path[] = {
89 {
90 .ctl_name = CTL_NET,
91 .procname = "net",
92 .mode = 0555,
93 .child = nf_net_netfilter_table,
94 },
95 {
96 .ctl_name = 0
97 }
98};
99EXPORT_SYMBOL_GPL(nf_net_netfilter_sysctl_path);
100
101/* net/ipv4/netfilter */
102static struct ctl_table nf_net_ipv4_netfilter_table[] = {
103 {
104 .ctl_name = NET_IPV4_NETFILTER,
105 .procname = "netfilter",
106 .mode = 0555,
107 },
108 {
109 .ctl_name = 0
110 }
111};
112static struct ctl_table nf_net_ipv4_table[] = {
113 {
114 .ctl_name = NET_IPV4,
115 .procname = "ipv4",
116 .mode = 0555,
117 .child = nf_net_ipv4_netfilter_table,
118 },
119 {
120 .ctl_name = 0
121 }
122};
123struct ctl_table nf_net_ipv4_netfilter_sysctl_path[] = {
124 {
125 .ctl_name = CTL_NET,
126 .procname = "net",
127 .mode = 0555,
128 .child = nf_net_ipv4_table,
129 },
130 {
131 .ctl_name = 0
132 }
133};
134EXPORT_SYMBOL_GPL(nf_net_ipv4_netfilter_sysctl_path);