blob: 42938f9c467eb78db05da32b388c9c1e9bd3f826 [file] [log] [blame]
Harald Weltef6ebe772005-08-09 20:21:49 -07001#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>
Harald Weltebbd86b9f2005-08-09 20:23:11 -07007#include <linux/seq_file.h>
Harald Weltef6ebe772005-08-09 20:21:49 -07008#include <net/protocol.h>
Patrick McHardyf01ffbd2007-12-17 22:38:49 -08009#include <net/netfilter/nf_log.h>
Harald Weltef6ebe772005-08-09 20:21:49 -070010
11#include "nf_internals.h"
12
YOSHIFUJI Hideakia5d29262007-07-19 10:44:21 +090013/* Internal logging interface, which relies on the real
Harald Weltef6ebe772005-08-09 20:21:49 -070014 LOG target modules */
15
Eric Leblond17625272009-03-23 13:16:53 +010016#define NFLOGGER_NAME_LEN 64
Harald Weltef6ebe772005-08-09 20:21:49 -070017
Pablo Neira Ayuso59628152014-06-18 19:24:30 +020018static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly;
Patrick McHardy9b735342007-02-12 11:11:39 -080019static DEFINE_MUTEX(nf_log_mutex);
Harald Weltef6ebe772005-08-09 20:21:49 -070020
Marcelo Leitner0c26ed12014-10-29 10:04:51 -020021#define nft_log_dereference(logger) \
22 rcu_dereference_protected(logger, lockdep_is_held(&nf_log_mutex))
23
Eric Leblondca735b32009-03-16 14:54:21 +010024static struct nf_logger *__find_logger(int pf, const char *str_logger)
Harald Weltef6ebe772005-08-09 20:21:49 -070025{
Pablo Neira Ayuso59628152014-06-18 19:24:30 +020026 struct nf_logger *log;
27 int i;
Eric Leblondca735b32009-03-16 14:54:21 +010028
Pablo Neira Ayuso59628152014-06-18 19:24:30 +020029 for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
30 if (loggers[pf][i] == NULL)
31 continue;
32
Marcelo Leitner0c26ed12014-10-29 10:04:51 -020033 log = nft_log_dereference(loggers[pf][i]);
Rasmus Villemoes18082742014-10-13 15:54:31 -070034 if (!strncasecmp(str_logger, log->name, strlen(log->name)))
Pablo Neira Ayuso59628152014-06-18 19:24:30 +020035 return log;
Eric Leblondca735b32009-03-16 14:54:21 +010036 }
37
38 return NULL;
39}
40
Gao Feng779994f2016-08-29 18:25:28 +080041int nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger)
Gao feng30e0c6a2013-03-24 23:50:40 +000042{
43 const struct nf_logger *log;
44
Gao Feng779994f2016-08-29 18:25:28 +080045 if (pf == NFPROTO_UNSPEC || pf >= ARRAY_SIZE(net->nf.nf_loggers))
46 return -EOPNOTSUPP;
Gao feng30e0c6a2013-03-24 23:50:40 +000047
48 mutex_lock(&nf_log_mutex);
Marcelo Leitner0c26ed12014-10-29 10:04:51 -020049 log = nft_log_dereference(net->nf.nf_loggers[pf]);
Gao feng30e0c6a2013-03-24 23:50:40 +000050 if (log == NULL)
51 rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
52
53 mutex_unlock(&nf_log_mutex);
Gao Feng779994f2016-08-29 18:25:28 +080054
55 return 0;
Gao feng30e0c6a2013-03-24 23:50:40 +000056}
57EXPORT_SYMBOL(nf_log_set);
58
59void nf_log_unset(struct net *net, const struct nf_logger *logger)
60{
61 int i;
62 const struct nf_logger *log;
63
Gao feng30e0c6a2013-03-24 23:50:40 +000064 mutex_lock(&nf_log_mutex);
65 for (i = 0; i < NFPROTO_NUMPROTO; i++) {
Marcelo Leitner0c26ed12014-10-29 10:04:51 -020066 log = nft_log_dereference(net->nf.nf_loggers[i]);
Gao feng30e0c6a2013-03-24 23:50:40 +000067 if (log == logger)
68 RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL);
69 }
70 mutex_unlock(&nf_log_mutex);
71 synchronize_rcu();
72}
73EXPORT_SYMBOL(nf_log_unset);
74
Adam Buchbinderd93cf062012-09-19 21:47:58 -040075/* return EEXIST if the same logger is registered, 0 on success. */
Eric Leblondca735b32009-03-16 14:54:21 +010076int nf_log_register(u_int8_t pf, struct nf_logger *logger)
77{
Eric Dumazetb6f0a362009-04-15 12:16:19 +020078 int i;
Marcelo Leitner8ac2bde2014-10-29 10:51:13 -020079 int ret = 0;
Harald Weltef6ebe772005-08-09 20:21:49 -070080
Gao feng30e0c6a2013-03-24 23:50:40 +000081 if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers))
Harald Welte8a61fad2005-08-09 20:23:53 -070082 return -EINVAL;
83
Eric Leblondca735b32009-03-16 14:54:21 +010084 mutex_lock(&nf_log_mutex);
Harald Welted72367b2005-08-09 20:23:36 -070085
Eric Leblondca735b32009-03-16 14:54:21 +010086 if (pf == NFPROTO_UNSPEC) {
Marcelo Leitner8ac2bde2014-10-29 10:51:13 -020087 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
88 if (rcu_access_pointer(loggers[i][logger->type])) {
89 ret = -EEXIST;
90 goto unlock;
91 }
92 }
Eric Leblondca735b32009-03-16 14:54:21 +010093 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
Pablo Neira Ayuso59628152014-06-18 19:24:30 +020094 rcu_assign_pointer(loggers[i][logger->type], logger);
Eric Leblondca735b32009-03-16 14:54:21 +010095 } else {
Marcelo Leitner8ac2bde2014-10-29 10:51:13 -020096 if (rcu_access_pointer(loggers[pf][logger->type])) {
97 ret = -EEXIST;
98 goto unlock;
99 }
Pablo Neira Ayuso59628152014-06-18 19:24:30 +0200100 rcu_assign_pointer(loggers[pf][logger->type], logger);
Eric Leblondca735b32009-03-16 14:54:21 +0100101 }
Patrick McHardy9b735342007-02-12 11:11:39 -0800102
Marcelo Leitner8ac2bde2014-10-29 10:51:13 -0200103unlock:
Patrick McHardy9b735342007-02-12 11:11:39 -0800104 mutex_unlock(&nf_log_mutex);
Marcelo Leitner8ac2bde2014-10-29 10:51:13 -0200105 return ret;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800106}
Harald Weltef6ebe772005-08-09 20:21:49 -0700107EXPORT_SYMBOL(nf_log_register);
108
Eric Leblondca735b32009-03-16 14:54:21 +0100109void nf_log_unregister(struct nf_logger *logger)
Harald Weltef6ebe772005-08-09 20:21:49 -0700110{
Florian Westphal205ee1172015-09-09 02:57:21 +0200111 const struct nf_logger *log;
Harald Weltef6ebe772005-08-09 20:21:49 -0700112 int i;
113
Patrick McHardy9b735342007-02-12 11:11:39 -0800114 mutex_lock(&nf_log_mutex);
Florian Westphal205ee1172015-09-09 02:57:21 +0200115 for (i = 0; i < NFPROTO_NUMPROTO; i++) {
116 log = nft_log_dereference(loggers[i][logger->type]);
117 if (log == logger)
118 RCU_INIT_POINTER(loggers[i][logger->type], NULL);
119 }
Patrick McHardy9b735342007-02-12 11:11:39 -0800120 mutex_unlock(&nf_log_mutex);
Pablo Neira Ayusoad5001c2015-09-17 13:37:00 +0200121 synchronize_rcu();
Harald Weltef6ebe772005-08-09 20:21:49 -0700122}
Patrick McHardye92ad992007-02-12 11:11:55 -0800123EXPORT_SYMBOL(nf_log_unregister);
Harald Weltef6ebe772005-08-09 20:21:49 -0700124
Gao feng30e0c6a2013-03-24 23:50:40 +0000125int nf_log_bind_pf(struct net *net, u_int8_t pf,
126 const struct nf_logger *logger)
Eric Leblondca735b32009-03-16 14:54:21 +0100127{
Gao feng30e0c6a2013-03-24 23:50:40 +0000128 if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
Jan Engelhardt9ef02982011-03-02 12:10:13 +0100129 return -EINVAL;
Eric Leblondca735b32009-03-16 14:54:21 +0100130 mutex_lock(&nf_log_mutex);
131 if (__find_logger(pf, logger->name) == NULL) {
132 mutex_unlock(&nf_log_mutex);
133 return -ENOENT;
134 }
Gao feng30e0c6a2013-03-24 23:50:40 +0000135 rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
Eric Leblondca735b32009-03-16 14:54:21 +0100136 mutex_unlock(&nf_log_mutex);
137 return 0;
138}
139EXPORT_SYMBOL(nf_log_bind_pf);
140
Gao feng30e0c6a2013-03-24 23:50:40 +0000141void nf_log_unbind_pf(struct net *net, u_int8_t pf)
Eric Leblondca735b32009-03-16 14:54:21 +0100142{
Gao feng30e0c6a2013-03-24 23:50:40 +0000143 if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
Jan Engelhardt9ef02982011-03-02 12:10:13 +0100144 return;
Eric Leblondca735b32009-03-16 14:54:21 +0100145 mutex_lock(&nf_log_mutex);
Gao feng30e0c6a2013-03-24 23:50:40 +0000146 RCU_INIT_POINTER(net->nf.nf_loggers[pf], NULL);
Eric Leblondca735b32009-03-16 14:54:21 +0100147 mutex_unlock(&nf_log_mutex);
148}
149EXPORT_SYMBOL(nf_log_unbind_pf);
150
Pablo Neira Ayuso960649d2014-06-23 00:28:18 +0200151void nf_logger_request_module(int pf, enum nf_log_type type)
152{
153 if (loggers[pf][type] == NULL)
154 request_module("nf-logger-%u-%u", pf, type);
155}
156EXPORT_SYMBOL_GPL(nf_logger_request_module);
157
Pablo Neira Ayusofab40852014-06-18 19:38:25 +0200158int nf_logger_find_get(int pf, enum nf_log_type type)
159{
160 struct nf_logger *logger;
161 int ret = -ENOENT;
162
Liping Zhangf3bb5332016-06-08 20:43:17 +0800163 if (pf == NFPROTO_INET) {
164 ret = nf_logger_find_get(NFPROTO_IPV4, type);
165 if (ret < 0)
166 return ret;
167
168 ret = nf_logger_find_get(NFPROTO_IPV6, type);
169 if (ret < 0) {
170 nf_logger_put(NFPROTO_IPV4, type);
171 return ret;
172 }
173
174 return 0;
175 }
176
Pablo Neira Ayusoc5a589c2014-10-30 18:39:12 +0100177 if (rcu_access_pointer(loggers[pf][type]) == NULL)
Pablo Neira Ayusofab40852014-06-18 19:38:25 +0200178 request_module("nf-logger-%u-%u", pf, type);
179
180 rcu_read_lock();
181 logger = rcu_dereference(loggers[pf][type]);
182 if (logger == NULL)
183 goto out;
184
Shivani Bhardwaj7e53e7f2016-06-12 00:26:10 +0530185 if (try_module_get(logger->me))
Pablo Neira Ayusofab40852014-06-18 19:38:25 +0200186 ret = 0;
187out:
188 rcu_read_unlock();
189 return ret;
190}
191EXPORT_SYMBOL_GPL(nf_logger_find_get);
192
193void nf_logger_put(int pf, enum nf_log_type type)
194{
195 struct nf_logger *logger;
196
Liping Zhangf3bb5332016-06-08 20:43:17 +0800197 if (pf == NFPROTO_INET) {
198 nf_logger_put(NFPROTO_IPV4, type);
199 nf_logger_put(NFPROTO_IPV6, type);
200 return;
201 }
202
Pablo Neira Ayusofab40852014-06-18 19:38:25 +0200203 BUG_ON(loggers[pf][type] == NULL);
204
205 rcu_read_lock();
206 logger = rcu_dereference(loggers[pf][type]);
207 module_put(logger->me);
208 rcu_read_unlock();
209}
210EXPORT_SYMBOL_GPL(nf_logger_put);
211
Gao feng30e0c6a2013-03-24 23:50:40 +0000212void nf_log_packet(struct net *net,
213 u_int8_t pf,
Harald Weltef6ebe772005-08-09 20:21:49 -0700214 unsigned int hooknum,
215 const struct sk_buff *skb,
216 const struct net_device *in,
217 const struct net_device *out,
Patrick McHardy7b2f9632007-12-17 22:39:08 -0800218 const struct nf_loginfo *loginfo,
Harald Weltef6ebe772005-08-09 20:21:49 -0700219 const char *fmt, ...)
220{
221 va_list args;
222 char prefix[NF_LOG_PREFIXLEN];
Patrick McHardy7b2f9632007-12-17 22:39:08 -0800223 const struct nf_logger *logger;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800224
Harald Weltef6ebe772005-08-09 20:21:49 -0700225 rcu_read_lock();
Pablo Neira Ayusofab40852014-06-18 19:38:25 +0200226 if (loginfo != NULL)
227 logger = rcu_dereference(loggers[pf][loginfo->type]);
228 else
229 logger = rcu_dereference(net->nf.nf_loggers[pf]);
230
Harald Weltef6ebe772005-08-09 20:21:49 -0700231 if (logger) {
232 va_start(args, fmt);
233 vsnprintf(prefix, sizeof(prefix), fmt, args);
234 va_end(args);
Hans Schillstrom8cdb46d2013-05-15 01:23:45 +0000235 logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
Harald Weltef6ebe772005-08-09 20:21:49 -0700236 }
237 rcu_read_unlock();
238}
239EXPORT_SYMBOL(nf_log_packet);
240
Pablo Neira Ayuso4017a7e2015-03-02 01:10:28 +0100241void nf_log_trace(struct net *net,
242 u_int8_t pf,
243 unsigned int hooknum,
244 const struct sk_buff *skb,
245 const struct net_device *in,
246 const struct net_device *out,
247 const struct nf_loginfo *loginfo, const char *fmt, ...)
248{
249 va_list args;
250 char prefix[NF_LOG_PREFIXLEN];
251 const struct nf_logger *logger;
252
253 rcu_read_lock();
254 logger = rcu_dereference(net->nf.nf_loggers[pf]);
255 if (logger) {
256 va_start(args, fmt);
257 vsnprintf(prefix, sizeof(prefix), fmt, args);
258 va_end(args);
259 logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
260 }
261 rcu_read_unlock();
262}
263EXPORT_SYMBOL(nf_log_trace);
264
Pablo Neira Ayuso27fd8d902014-06-19 12:37:58 +0200265#define S_SIZE (1024 - (sizeof(unsigned int) + 1))
266
267struct nf_log_buf {
268 unsigned int count;
269 char buf[S_SIZE + 1];
270};
271static struct nf_log_buf emergency, *emergency_ptr = &emergency;
272
273__printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...)
274{
275 va_list args;
276 int len;
277
278 if (likely(m->count < S_SIZE)) {
279 va_start(args, f);
280 len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args);
281 va_end(args);
282 if (likely(m->count + len < S_SIZE)) {
283 m->count += len;
284 return 0;
285 }
286 }
287 m->count = S_SIZE;
288 printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n");
289 return -1;
290}
291EXPORT_SYMBOL_GPL(nf_log_buf_add);
292
293struct nf_log_buf *nf_log_buf_open(void)
294{
295 struct nf_log_buf *m = kmalloc(sizeof(*m), GFP_ATOMIC);
296
297 if (unlikely(!m)) {
298 local_bh_disable();
299 do {
300 m = xchg(&emergency_ptr, NULL);
301 } while (!m);
302 }
303 m->count = 0;
304 return m;
305}
306EXPORT_SYMBOL_GPL(nf_log_buf_open);
307
308void nf_log_buf_close(struct nf_log_buf *m)
309{
310 m->buf[m->count] = 0;
311 printk("%s\n", m->buf);
312
313 if (likely(m != &emergency))
314 kfree(m);
315 else {
316 emergency_ptr = m;
317 local_bh_enable();
318 }
319}
320EXPORT_SYMBOL_GPL(nf_log_buf_close);
321
Harald Weltef6ebe772005-08-09 20:21:49 -0700322#ifdef CONFIG_PROC_FS
323static void *seq_start(struct seq_file *seq, loff_t *pos)
324{
Gao feng30e0c6a2013-03-24 23:50:40 +0000325 struct net *net = seq_file_net(seq);
326
Patrick McHardy6440fe02009-11-19 04:59:05 +0000327 mutex_lock(&nf_log_mutex);
Harald Weltef6ebe772005-08-09 20:21:49 -0700328
Gao feng30e0c6a2013-03-24 23:50:40 +0000329 if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
Harald Weltef6ebe772005-08-09 20:21:49 -0700330 return NULL;
331
332 return pos;
333}
334
335static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
336{
Gao feng30e0c6a2013-03-24 23:50:40 +0000337 struct net *net = seq_file_net(s);
338
Harald Weltef6ebe772005-08-09 20:21:49 -0700339 (*pos)++;
340
Gao feng30e0c6a2013-03-24 23:50:40 +0000341 if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
Harald Weltef6ebe772005-08-09 20:21:49 -0700342 return NULL;
343
344 return pos;
345}
346
347static void seq_stop(struct seq_file *s, void *v)
348{
Patrick McHardy6440fe02009-11-19 04:59:05 +0000349 mutex_unlock(&nf_log_mutex);
Harald Weltef6ebe772005-08-09 20:21:49 -0700350}
351
352static int seq_show(struct seq_file *s, void *v)
353{
354 loff_t *pos = v;
355 const struct nf_logger *logger;
Steven Rostedt (Red Hat)e71456a2014-10-27 17:43:45 -0400356 int i;
Gao feng30e0c6a2013-03-24 23:50:40 +0000357 struct net *net = seq_file_net(s);
Harald Weltef6ebe772005-08-09 20:21:49 -0700358
Marcelo Leitner0c26ed12014-10-29 10:04:51 -0200359 logger = nft_log_dereference(net->nf.nf_loggers[*pos]);
Harald Weltef6ebe772005-08-09 20:21:49 -0700360
361 if (!logger)
Steven Rostedt (Red Hat)e71456a2014-10-27 17:43:45 -0400362 seq_printf(s, "%2lld NONE (", *pos);
Eric Leblondc7a913c2009-03-16 14:55:27 +0100363 else
Steven Rostedt (Red Hat)e71456a2014-10-27 17:43:45 -0400364 seq_printf(s, "%2lld %s (", *pos, logger->name);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800365
Steven Rostedt (Red Hat)e71456a2014-10-27 17:43:45 -0400366 if (seq_has_overflowed(s))
367 return -ENOSPC;
Eric Leblondc7a913c2009-03-16 14:55:27 +0100368
Pablo Neira Ayuso59628152014-06-18 19:24:30 +0200369 for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
370 if (loggers[*pos][i] == NULL)
371 continue;
372
Marcelo Leitner0c26ed12014-10-29 10:04:51 -0200373 logger = nft_log_dereference(loggers[*pos][i]);
Steven Rostedt (Red Hat)e71456a2014-10-27 17:43:45 -0400374 seq_printf(s, "%s", logger->name);
375 if (i == 0 && loggers[*pos][i + 1] != NULL)
376 seq_printf(s, ",");
377
378 if (seq_has_overflowed(s))
379 return -ENOSPC;
Eric Leblondc7a913c2009-03-16 14:55:27 +0100380 }
Eric Leblondc7a913c2009-03-16 14:55:27 +0100381
Steven Rostedt (Red Hat)e71456a2014-10-27 17:43:45 -0400382 seq_printf(s, ")\n");
383
384 if (seq_has_overflowed(s))
385 return -ENOSPC;
386 return 0;
Harald Weltef6ebe772005-08-09 20:21:49 -0700387}
388
Philippe De Muyter56b3d972007-07-10 23:07:31 -0700389static const struct seq_operations nflog_seq_ops = {
Harald Weltef6ebe772005-08-09 20:21:49 -0700390 .start = seq_start,
391 .next = seq_next,
392 .stop = seq_stop,
393 .show = seq_show,
394};
395
396static int nflog_open(struct inode *inode, struct file *file)
397{
Gao feng30e0c6a2013-03-24 23:50:40 +0000398 return seq_open_net(inode, file, &nflog_seq_ops,
399 sizeof(struct seq_net_private));
Harald Weltef6ebe772005-08-09 20:21:49 -0700400}
401
Arjan van de Venda7071d2007-02-12 00:55:36 -0800402static const struct file_operations nflog_file_ops = {
Harald Weltef6ebe772005-08-09 20:21:49 -0700403 .owner = THIS_MODULE,
404 .open = nflog_open,
405 .read = seq_read,
406 .llseek = seq_lseek,
Gao feng30e0c6a2013-03-24 23:50:40 +0000407 .release = seq_release_net,
Harald Weltef6ebe772005-08-09 20:21:49 -0700408};
409
Eric Leblond17625272009-03-23 13:16:53 +0100410
Harald Weltef6ebe772005-08-09 20:21:49 -0700411#endif /* PROC_FS */
412
Eric Leblond17625272009-03-23 13:16:53 +0100413#ifdef CONFIG_SYSCTL
Eric Leblond17625272009-03-23 13:16:53 +0100414static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
415static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
Eric Leblond17625272009-03-23 13:16:53 +0100416
Joe Perchesfe2c6332013-06-11 23:04:25 -0700417static int nf_log_proc_dostring(struct ctl_table *table, int write,
Patrick McHardy24955612009-06-22 14:15:30 +0200418 void __user *buffer, size_t *lenp, loff_t *ppos)
Eric Leblond17625272009-03-23 13:16:53 +0100419{
420 const struct nf_logger *logger;
Patrick McHardy24955612009-06-22 14:15:30 +0200421 char buf[NFLOGGER_NAME_LEN];
Eric Leblond17625272009-03-23 13:16:53 +0100422 int r = 0;
423 int tindex = (unsigned long)table->extra1;
Jann Horndbb59182016-09-18 21:40:55 +0200424 struct net *net = table->extra2;
Eric Leblond17625272009-03-23 13:16:53 +0100425
426 if (write) {
Pavel Tikhomirovc6ac37d2016-07-01 16:53:54 +0300427 struct ctl_table tmp = *table;
428
Jann Hornf6a67682018-06-20 18:33:45 +0200429 /* proc_dostring() can append to existing strings, so we need to
430 * initialize it as an empty string.
431 */
432 buf[0] = '\0';
Pavel Tikhomirovc6ac37d2016-07-01 16:53:54 +0300433 tmp.data = buf;
434 r = proc_dostring(&tmp, write, buffer, lenp, ppos);
435 if (r)
436 return r;
Patrick McHardy24955612009-06-22 14:15:30 +0200437
438 if (!strcmp(buf, "NONE")) {
Gao feng30e0c6a2013-03-24 23:50:40 +0000439 nf_log_unbind_pf(net, tindex);
Eric Leblond17625272009-03-23 13:16:53 +0100440 return 0;
441 }
442 mutex_lock(&nf_log_mutex);
Patrick McHardy24955612009-06-22 14:15:30 +0200443 logger = __find_logger(tindex, buf);
Eric Leblond17625272009-03-23 13:16:53 +0100444 if (logger == NULL) {
445 mutex_unlock(&nf_log_mutex);
446 return -ENOENT;
447 }
Gao feng30e0c6a2013-03-24 23:50:40 +0000448 rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
Eric Leblond17625272009-03-23 13:16:53 +0100449 mutex_unlock(&nf_log_mutex);
450 } else {
Jann Horn1712fae2018-06-25 17:22:00 +0200451 struct ctl_table tmp = *table;
452
453 tmp.data = buf;
Patrick McHardy266d07c2009-06-13 12:21:10 +0200454 mutex_lock(&nf_log_mutex);
Marcelo Leitner0c26ed12014-10-29 10:04:51 -0200455 logger = nft_log_dereference(net->nf.nf_loggers[tindex]);
Eric Leblond17625272009-03-23 13:16:53 +0100456 if (!logger)
Jann Horn1712fae2018-06-25 17:22:00 +0200457 strlcpy(buf, "NONE", sizeof(buf));
Eric Leblond17625272009-03-23 13:16:53 +0100458 else
Jann Horn1712fae2018-06-25 17:22:00 +0200459 strlcpy(buf, logger->name, sizeof(buf));
Patrick McHardy266d07c2009-06-13 12:21:10 +0200460 mutex_unlock(&nf_log_mutex);
Jann Horn1712fae2018-06-25 17:22:00 +0200461 r = proc_dostring(&tmp, write, buffer, lenp, ppos);
Eric Leblond17625272009-03-23 13:16:53 +0100462 }
463
464 return r;
465}
466
Gao feng30e0c6a2013-03-24 23:50:40 +0000467static int netfilter_log_sysctl_init(struct net *net)
Eric Leblond17625272009-03-23 13:16:53 +0100468{
469 int i;
Gao feng30e0c6a2013-03-24 23:50:40 +0000470 struct ctl_table *table;
Eric Leblond17625272009-03-23 13:16:53 +0100471
Gao feng30e0c6a2013-03-24 23:50:40 +0000472 table = nf_log_sysctl_table;
473 if (!net_eq(net, &init_net)) {
474 table = kmemdup(nf_log_sysctl_table,
475 sizeof(nf_log_sysctl_table),
476 GFP_KERNEL);
477 if (!table)
478 goto err_alloc;
479 } else {
480 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
481 snprintf(nf_log_sysctl_fnames[i],
482 3, "%d", i);
483 nf_log_sysctl_table[i].procname =
484 nf_log_sysctl_fnames[i];
Fabian Frederick8aefc4d2014-12-22 19:36:15 +0100485 nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN;
Gao feng30e0c6a2013-03-24 23:50:40 +0000486 nf_log_sysctl_table[i].mode = 0644;
487 nf_log_sysctl_table[i].proc_handler =
488 nf_log_proc_dostring;
489 nf_log_sysctl_table[i].extra1 =
490 (void *)(unsigned long) i;
491 }
Eric Leblond17625272009-03-23 13:16:53 +0100492 }
493
Jann Horndbb59182016-09-18 21:40:55 +0200494 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
495 table[i].extra2 = net;
496
Gao feng30e0c6a2013-03-24 23:50:40 +0000497 net->nf.nf_log_dir_header = register_net_sysctl(net,
498 "net/netfilter/nf_log",
499 table);
500 if (!net->nf.nf_log_dir_header)
501 goto err_reg;
Eric Leblond17625272009-03-23 13:16:53 +0100502
503 return 0;
Gao feng30e0c6a2013-03-24 23:50:40 +0000504
505err_reg:
506 if (!net_eq(net, &init_net))
507 kfree(table);
508err_alloc:
509 return -ENOMEM;
510}
511
512static void netfilter_log_sysctl_exit(struct net *net)
513{
514 struct ctl_table *table;
515
516 table = net->nf.nf_log_dir_header->ctl_table_arg;
517 unregister_net_sysctl_table(net->nf.nf_log_dir_header);
518 if (!net_eq(net, &init_net))
519 kfree(table);
Eric Leblond17625272009-03-23 13:16:53 +0100520}
521#else
Gao feng30e0c6a2013-03-24 23:50:40 +0000522static int netfilter_log_sysctl_init(struct net *net)
Eric Leblond17625272009-03-23 13:16:53 +0100523{
524 return 0;
525}
Gao feng30e0c6a2013-03-24 23:50:40 +0000526
527static void netfilter_log_sysctl_exit(struct net *net)
528{
529}
Eric Leblond17625272009-03-23 13:16:53 +0100530#endif /* CONFIG_SYSCTL */
Harald Weltef6ebe772005-08-09 20:21:49 -0700531
Gao feng30e0c6a2013-03-24 23:50:40 +0000532static int __net_init nf_log_net_init(struct net *net)
Harald Weltef6ebe772005-08-09 20:21:49 -0700533{
Gao feng30e0c6a2013-03-24 23:50:40 +0000534 int ret = -ENOMEM;
535
Harald Weltef6ebe772005-08-09 20:21:49 -0700536#ifdef CONFIG_PROC_FS
Denis V. Lunev8eeee8b2008-03-27 16:55:53 -0700537 if (!proc_create("nf_log", S_IRUGO,
Gao feng30e0c6a2013-03-24 23:50:40 +0000538 net->nf.proc_netfilter, &nflog_file_ops))
539 return ret;
Harald Welte62243922005-08-11 15:30:45 -0700540#endif
Gao feng30e0c6a2013-03-24 23:50:40 +0000541 ret = netfilter_log_sysctl_init(net);
542 if (ret < 0)
543 goto out_sysctl;
Eric Leblondca735b32009-03-16 14:54:21 +0100544
Gao feng30e0c6a2013-03-24 23:50:40 +0000545 return 0;
546
547out_sysctl:
Pablo Neira Ayusoe778f562013-04-30 08:01:18 +0000548#ifdef CONFIG_PROC_FS
Pablo Neira Ayuso6d11cfd2013-05-22 22:42:36 +0000549 remove_proc_entry("nf_log", net->nf.proc_netfilter);
Pablo Neira Ayusoe778f562013-04-30 08:01:18 +0000550#endif
Gao feng30e0c6a2013-03-24 23:50:40 +0000551 return ret;
552}
553
554static void __net_exit nf_log_net_exit(struct net *net)
555{
556 netfilter_log_sysctl_exit(net);
Pablo Neira Ayusoe778f562013-04-30 08:01:18 +0000557#ifdef CONFIG_PROC_FS
Gao feng30e0c6a2013-03-24 23:50:40 +0000558 remove_proc_entry("nf_log", net->nf.proc_netfilter);
Pablo Neira Ayusoe778f562013-04-30 08:01:18 +0000559#endif
Gao feng30e0c6a2013-03-24 23:50:40 +0000560}
561
562static struct pernet_operations nf_log_net_ops = {
563 .init = nf_log_net_init,
564 .exit = nf_log_net_exit,
565};
566
567int __init netfilter_log_init(void)
568{
Pablo Neira Ayuso59628152014-06-18 19:24:30 +0200569 return register_pernet_subsys(&nf_log_net_ops);
Harald Weltef6ebe772005-08-09 20:21:49 -0700570}