]> Pileus Git - ~andy/linux/blob - net/netfilter/nf_log.c
Linux 3.14
[~andy/linux] / net / netfilter / nf_log.c
1 #include <linux/kernel.h>
2 #include <linux/init.h>
3 #include <linux/module.h>
4 #include <linux/proc_fs.h>
5 #include <linux/skbuff.h>
6 #include <linux/netfilter.h>
7 #include <linux/seq_file.h>
8 #include <net/protocol.h>
9 #include <net/netfilter/nf_log.h>
10
11 #include "nf_internals.h"
12
13 /* Internal logging interface, which relies on the real
14    LOG target modules */
15
16 #define NF_LOG_PREFIXLEN                128
17 #define NFLOGGER_NAME_LEN               64
18
19 static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly;
20 static DEFINE_MUTEX(nf_log_mutex);
21
22 static struct nf_logger *__find_logger(int pf, const char *str_logger)
23 {
24         struct nf_logger *t;
25
26         list_for_each_entry(t, &nf_loggers_l[pf], list[pf]) {
27                 if (!strnicmp(str_logger, t->name, strlen(t->name)))
28                         return t;
29         }
30
31         return NULL;
32 }
33
34 void nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger)
35 {
36         const struct nf_logger *log;
37
38         if (pf == NFPROTO_UNSPEC)
39                 return;
40
41         mutex_lock(&nf_log_mutex);
42         log = rcu_dereference_protected(net->nf.nf_loggers[pf],
43                                         lockdep_is_held(&nf_log_mutex));
44         if (log == NULL)
45                 rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
46
47         mutex_unlock(&nf_log_mutex);
48 }
49 EXPORT_SYMBOL(nf_log_set);
50
51 void nf_log_unset(struct net *net, const struct nf_logger *logger)
52 {
53         int i;
54         const struct nf_logger *log;
55
56         mutex_lock(&nf_log_mutex);
57         for (i = 0; i < NFPROTO_NUMPROTO; i++) {
58                 log = rcu_dereference_protected(net->nf.nf_loggers[i],
59                                 lockdep_is_held(&nf_log_mutex));
60                 if (log == logger)
61                         RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL);
62         }
63         mutex_unlock(&nf_log_mutex);
64         synchronize_rcu();
65 }
66 EXPORT_SYMBOL(nf_log_unset);
67
68 /* return EEXIST if the same logger is registered, 0 on success. */
69 int nf_log_register(u_int8_t pf, struct nf_logger *logger)
70 {
71         int i;
72
73         if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers))
74                 return -EINVAL;
75
76         for (i = 0; i < ARRAY_SIZE(logger->list); i++)
77                 INIT_LIST_HEAD(&logger->list[i]);
78
79         mutex_lock(&nf_log_mutex);
80
81         if (pf == NFPROTO_UNSPEC) {
82                 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
83                         list_add_tail(&(logger->list[i]), &(nf_loggers_l[i]));
84         } else {
85                 /* register at end of list to honor first register win */
86                 list_add_tail(&logger->list[pf], &nf_loggers_l[pf]);
87         }
88
89         mutex_unlock(&nf_log_mutex);
90
91         return 0;
92 }
93 EXPORT_SYMBOL(nf_log_register);
94
95 void nf_log_unregister(struct nf_logger *logger)
96 {
97         int i;
98
99         mutex_lock(&nf_log_mutex);
100         for (i = 0; i < NFPROTO_NUMPROTO; i++)
101                 list_del(&logger->list[i]);
102         mutex_unlock(&nf_log_mutex);
103 }
104 EXPORT_SYMBOL(nf_log_unregister);
105
106 int nf_log_bind_pf(struct net *net, u_int8_t pf,
107                    const struct nf_logger *logger)
108 {
109         if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
110                 return -EINVAL;
111         mutex_lock(&nf_log_mutex);
112         if (__find_logger(pf, logger->name) == NULL) {
113                 mutex_unlock(&nf_log_mutex);
114                 return -ENOENT;
115         }
116         rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
117         mutex_unlock(&nf_log_mutex);
118         return 0;
119 }
120 EXPORT_SYMBOL(nf_log_bind_pf);
121
122 void nf_log_unbind_pf(struct net *net, u_int8_t pf)
123 {
124         if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
125                 return;
126         mutex_lock(&nf_log_mutex);
127         RCU_INIT_POINTER(net->nf.nf_loggers[pf], NULL);
128         mutex_unlock(&nf_log_mutex);
129 }
130 EXPORT_SYMBOL(nf_log_unbind_pf);
131
132 void nf_log_packet(struct net *net,
133                    u_int8_t pf,
134                    unsigned int hooknum,
135                    const struct sk_buff *skb,
136                    const struct net_device *in,
137                    const struct net_device *out,
138                    const struct nf_loginfo *loginfo,
139                    const char *fmt, ...)
140 {
141         va_list args;
142         char prefix[NF_LOG_PREFIXLEN];
143         const struct nf_logger *logger;
144
145         rcu_read_lock();
146         logger = rcu_dereference(net->nf.nf_loggers[pf]);
147         if (logger) {
148                 va_start(args, fmt);
149                 vsnprintf(prefix, sizeof(prefix), fmt, args);
150                 va_end(args);
151                 logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
152         }
153         rcu_read_unlock();
154 }
155 EXPORT_SYMBOL(nf_log_packet);
156
157 #ifdef CONFIG_PROC_FS
158 static void *seq_start(struct seq_file *seq, loff_t *pos)
159 {
160         struct net *net = seq_file_net(seq);
161
162         mutex_lock(&nf_log_mutex);
163
164         if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
165                 return NULL;
166
167         return pos;
168 }
169
170 static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
171 {
172         struct net *net = seq_file_net(s);
173
174         (*pos)++;
175
176         if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
177                 return NULL;
178
179         return pos;
180 }
181
182 static void seq_stop(struct seq_file *s, void *v)
183 {
184         mutex_unlock(&nf_log_mutex);
185 }
186
187 static int seq_show(struct seq_file *s, void *v)
188 {
189         loff_t *pos = v;
190         const struct nf_logger *logger;
191         struct nf_logger *t;
192         int ret;
193         struct net *net = seq_file_net(s);
194
195         logger = rcu_dereference_protected(net->nf.nf_loggers[*pos],
196                                            lockdep_is_held(&nf_log_mutex));
197
198         if (!logger)
199                 ret = seq_printf(s, "%2lld NONE (", *pos);
200         else
201                 ret = seq_printf(s, "%2lld %s (", *pos, logger->name);
202
203         if (ret < 0)
204                 return ret;
205
206         list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) {
207                 ret = seq_printf(s, "%s", t->name);
208                 if (ret < 0)
209                         return ret;
210                 if (&t->list[*pos] != nf_loggers_l[*pos].prev) {
211                         ret = seq_printf(s, ",");
212                         if (ret < 0)
213                                 return ret;
214                 }
215         }
216
217         return seq_printf(s, ")\n");
218 }
219
220 static const struct seq_operations nflog_seq_ops = {
221         .start  = seq_start,
222         .next   = seq_next,
223         .stop   = seq_stop,
224         .show   = seq_show,
225 };
226
227 static int nflog_open(struct inode *inode, struct file *file)
228 {
229         return seq_open_net(inode, file, &nflog_seq_ops,
230                             sizeof(struct seq_net_private));
231 }
232
233 static const struct file_operations nflog_file_ops = {
234         .owner   = THIS_MODULE,
235         .open    = nflog_open,
236         .read    = seq_read,
237         .llseek  = seq_lseek,
238         .release = seq_release_net,
239 };
240
241
242 #endif /* PROC_FS */
243
244 #ifdef CONFIG_SYSCTL
245 static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
246 static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
247
248 static int nf_log_proc_dostring(struct ctl_table *table, int write,
249                          void __user *buffer, size_t *lenp, loff_t *ppos)
250 {
251         const struct nf_logger *logger;
252         char buf[NFLOGGER_NAME_LEN];
253         size_t size = *lenp;
254         int r = 0;
255         int tindex = (unsigned long)table->extra1;
256         struct net *net = current->nsproxy->net_ns;
257
258         if (write) {
259                 if (size > sizeof(buf))
260                         size = sizeof(buf);
261                 if (copy_from_user(buf, buffer, size))
262                         return -EFAULT;
263
264                 if (!strcmp(buf, "NONE")) {
265                         nf_log_unbind_pf(net, tindex);
266                         return 0;
267                 }
268                 mutex_lock(&nf_log_mutex);
269                 logger = __find_logger(tindex, buf);
270                 if (logger == NULL) {
271                         mutex_unlock(&nf_log_mutex);
272                         return -ENOENT;
273                 }
274                 rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
275                 mutex_unlock(&nf_log_mutex);
276         } else {
277                 mutex_lock(&nf_log_mutex);
278                 logger = rcu_dereference_protected(net->nf.nf_loggers[tindex],
279                                                    lockdep_is_held(&nf_log_mutex));
280                 if (!logger)
281                         table->data = "NONE";
282                 else
283                         table->data = logger->name;
284                 r = proc_dostring(table, write, buffer, lenp, ppos);
285                 mutex_unlock(&nf_log_mutex);
286         }
287
288         return r;
289 }
290
291 static int netfilter_log_sysctl_init(struct net *net)
292 {
293         int i;
294         struct ctl_table *table;
295
296         table = nf_log_sysctl_table;
297         if (!net_eq(net, &init_net)) {
298                 table = kmemdup(nf_log_sysctl_table,
299                                  sizeof(nf_log_sysctl_table),
300                                  GFP_KERNEL);
301                 if (!table)
302                         goto err_alloc;
303         } else {
304                 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
305                         snprintf(nf_log_sysctl_fnames[i],
306                                  3, "%d", i);
307                         nf_log_sysctl_table[i].procname =
308                                 nf_log_sysctl_fnames[i];
309                         nf_log_sysctl_table[i].data = NULL;
310                         nf_log_sysctl_table[i].maxlen =
311                                 NFLOGGER_NAME_LEN * sizeof(char);
312                         nf_log_sysctl_table[i].mode = 0644;
313                         nf_log_sysctl_table[i].proc_handler =
314                                 nf_log_proc_dostring;
315                         nf_log_sysctl_table[i].extra1 =
316                                 (void *)(unsigned long) i;
317                 }
318         }
319
320         net->nf.nf_log_dir_header = register_net_sysctl(net,
321                                                 "net/netfilter/nf_log",
322                                                 table);
323         if (!net->nf.nf_log_dir_header)
324                 goto err_reg;
325
326         return 0;
327
328 err_reg:
329         if (!net_eq(net, &init_net))
330                 kfree(table);
331 err_alloc:
332         return -ENOMEM;
333 }
334
335 static void netfilter_log_sysctl_exit(struct net *net)
336 {
337         struct ctl_table *table;
338
339         table = net->nf.nf_log_dir_header->ctl_table_arg;
340         unregister_net_sysctl_table(net->nf.nf_log_dir_header);
341         if (!net_eq(net, &init_net))
342                 kfree(table);
343 }
344 #else
345 static int netfilter_log_sysctl_init(struct net *net)
346 {
347         return 0;
348 }
349
350 static void netfilter_log_sysctl_exit(struct net *net)
351 {
352 }
353 #endif /* CONFIG_SYSCTL */
354
355 static int __net_init nf_log_net_init(struct net *net)
356 {
357         int ret = -ENOMEM;
358
359 #ifdef CONFIG_PROC_FS
360         if (!proc_create("nf_log", S_IRUGO,
361                          net->nf.proc_netfilter, &nflog_file_ops))
362                 return ret;
363 #endif
364         ret = netfilter_log_sysctl_init(net);
365         if (ret < 0)
366                 goto out_sysctl;
367
368         return 0;
369
370 out_sysctl:
371 #ifdef CONFIG_PROC_FS
372         remove_proc_entry("nf_log", net->nf.proc_netfilter);
373 #endif
374         return ret;
375 }
376
377 static void __net_exit nf_log_net_exit(struct net *net)
378 {
379         netfilter_log_sysctl_exit(net);
380 #ifdef CONFIG_PROC_FS
381         remove_proc_entry("nf_log", net->nf.proc_netfilter);
382 #endif
383 }
384
385 static struct pernet_operations nf_log_net_ops = {
386         .init = nf_log_net_init,
387         .exit = nf_log_net_exit,
388 };
389
390 int __init netfilter_log_init(void)
391 {
392         int i, ret;
393
394         ret = register_pernet_subsys(&nf_log_net_ops);
395         if (ret < 0)
396                 return ret;
397
398         for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
399                 INIT_LIST_HEAD(&(nf_loggers_l[i]));
400
401         return 0;
402 }