• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly;
20 static DEFINE_MUTEX(nf_log_mutex);
21 
22 #define nft_log_dereference(logger) \
23 	rcu_dereference_protected(logger, lockdep_is_held(&nf_log_mutex))
24 
__find_logger(int pf,const char * str_logger)25 static struct nf_logger *__find_logger(int pf, const char *str_logger)
26 {
27 	struct nf_logger *log;
28 	int i;
29 
30 	for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
31 		if (loggers[pf][i] == NULL)
32 			continue;
33 
34 		log = nft_log_dereference(loggers[pf][i]);
35 		if (!strncasecmp(str_logger, log->name, strlen(log->name)))
36 			return log;
37 	}
38 
39 	return NULL;
40 }
41 
nf_log_set(struct net * net,u_int8_t pf,const struct nf_logger * logger)42 void nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger)
43 {
44 	const struct nf_logger *log;
45 
46 	if (pf == NFPROTO_UNSPEC)
47 		return;
48 
49 	mutex_lock(&nf_log_mutex);
50 	log = nft_log_dereference(net->nf.nf_loggers[pf]);
51 	if (log == NULL)
52 		rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
53 
54 	mutex_unlock(&nf_log_mutex);
55 }
56 EXPORT_SYMBOL(nf_log_set);
57 
nf_log_unset(struct net * net,const struct nf_logger * logger)58 void nf_log_unset(struct net *net, const struct nf_logger *logger)
59 {
60 	int i;
61 	const struct nf_logger *log;
62 
63 	mutex_lock(&nf_log_mutex);
64 	for (i = 0; i < NFPROTO_NUMPROTO; i++) {
65 		log = nft_log_dereference(net->nf.nf_loggers[i]);
66 		if (log == logger)
67 			RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL);
68 	}
69 	mutex_unlock(&nf_log_mutex);
70 	synchronize_rcu();
71 }
72 EXPORT_SYMBOL(nf_log_unset);
73 
74 /* return EEXIST if the same logger is registered, 0 on success. */
nf_log_register(u_int8_t pf,struct nf_logger * logger)75 int nf_log_register(u_int8_t pf, struct nf_logger *logger)
76 {
77 	int i;
78 
79 	if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers))
80 		return -EINVAL;
81 
82 	mutex_lock(&nf_log_mutex);
83 
84 	if (pf == NFPROTO_UNSPEC) {
85 		for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
86 			rcu_assign_pointer(loggers[i][logger->type], logger);
87 	} else {
88 		/* register at end of list to honor first register win */
89 		rcu_assign_pointer(loggers[pf][logger->type], logger);
90 	}
91 
92 	mutex_unlock(&nf_log_mutex);
93 
94 	return 0;
95 }
96 EXPORT_SYMBOL(nf_log_register);
97 
nf_log_unregister(struct nf_logger * logger)98 void nf_log_unregister(struct nf_logger *logger)
99 {
100 	const struct nf_logger *log;
101 	int i;
102 
103 	mutex_lock(&nf_log_mutex);
104 	for (i = 0; i < NFPROTO_NUMPROTO; i++) {
105 		log = nft_log_dereference(loggers[i][logger->type]);
106 		if (log == logger)
107 			RCU_INIT_POINTER(loggers[i][logger->type], NULL);
108 	}
109 	mutex_unlock(&nf_log_mutex);
110 	synchronize_rcu();
111 }
112 EXPORT_SYMBOL(nf_log_unregister);
113 
nf_log_bind_pf(struct net * net,u_int8_t pf,const struct nf_logger * logger)114 int nf_log_bind_pf(struct net *net, u_int8_t pf,
115 		   const struct nf_logger *logger)
116 {
117 	if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
118 		return -EINVAL;
119 	mutex_lock(&nf_log_mutex);
120 	if (__find_logger(pf, logger->name) == NULL) {
121 		mutex_unlock(&nf_log_mutex);
122 		return -ENOENT;
123 	}
124 	rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
125 	mutex_unlock(&nf_log_mutex);
126 	return 0;
127 }
128 EXPORT_SYMBOL(nf_log_bind_pf);
129 
nf_log_unbind_pf(struct net * net,u_int8_t pf)130 void nf_log_unbind_pf(struct net *net, u_int8_t pf)
131 {
132 	if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
133 		return;
134 	mutex_lock(&nf_log_mutex);
135 	RCU_INIT_POINTER(net->nf.nf_loggers[pf], NULL);
136 	mutex_unlock(&nf_log_mutex);
137 }
138 EXPORT_SYMBOL(nf_log_unbind_pf);
139 
nf_logger_request_module(int pf,enum nf_log_type type)140 void nf_logger_request_module(int pf, enum nf_log_type type)
141 {
142 	if (loggers[pf][type] == NULL)
143 		request_module("nf-logger-%u-%u", pf, type);
144 }
145 EXPORT_SYMBOL_GPL(nf_logger_request_module);
146 
nf_logger_find_get(int pf,enum nf_log_type type)147 int nf_logger_find_get(int pf, enum nf_log_type type)
148 {
149 	struct nf_logger *logger;
150 	int ret = -ENOENT;
151 
152 	logger = loggers[pf][type];
153 	if (logger == NULL)
154 		request_module("nf-logger-%u-%u", pf, type);
155 
156 	rcu_read_lock();
157 	logger = rcu_dereference(loggers[pf][type]);
158 	if (logger == NULL)
159 		goto out;
160 
161 	if (logger && try_module_get(logger->me))
162 		ret = 0;
163 out:
164 	rcu_read_unlock();
165 	return ret;
166 }
167 EXPORT_SYMBOL_GPL(nf_logger_find_get);
168 
nf_logger_put(int pf,enum nf_log_type type)169 void nf_logger_put(int pf, enum nf_log_type type)
170 {
171 	struct nf_logger *logger;
172 
173 	BUG_ON(loggers[pf][type] == NULL);
174 
175 	rcu_read_lock();
176 	logger = rcu_dereference(loggers[pf][type]);
177 	module_put(logger->me);
178 	rcu_read_unlock();
179 }
180 EXPORT_SYMBOL_GPL(nf_logger_put);
181 
nf_log_packet(struct net * net,u_int8_t pf,unsigned int hooknum,const struct sk_buff * skb,const struct net_device * in,const struct net_device * out,const struct nf_loginfo * loginfo,const char * fmt,...)182 void nf_log_packet(struct net *net,
183 		   u_int8_t pf,
184 		   unsigned int hooknum,
185 		   const struct sk_buff *skb,
186 		   const struct net_device *in,
187 		   const struct net_device *out,
188 		   const struct nf_loginfo *loginfo,
189 		   const char *fmt, ...)
190 {
191 	va_list args;
192 	char prefix[NF_LOG_PREFIXLEN];
193 	const struct nf_logger *logger;
194 
195 	rcu_read_lock();
196 	if (loginfo != NULL)
197 		logger = rcu_dereference(loggers[pf][loginfo->type]);
198 	else
199 		logger = rcu_dereference(net->nf.nf_loggers[pf]);
200 
201 	if (logger) {
202 		va_start(args, fmt);
203 		vsnprintf(prefix, sizeof(prefix), fmt, args);
204 		va_end(args);
205 		logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
206 	}
207 	rcu_read_unlock();
208 }
209 EXPORT_SYMBOL(nf_log_packet);
210 
211 #define S_SIZE (1024 - (sizeof(unsigned int) + 1))
212 
213 struct nf_log_buf {
214 	unsigned int	count;
215 	char		buf[S_SIZE + 1];
216 };
217 static struct nf_log_buf emergency, *emergency_ptr = &emergency;
218 
nf_log_buf_add(struct nf_log_buf * m,const char * f,...)219 __printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...)
220 {
221 	va_list args;
222 	int len;
223 
224 	if (likely(m->count < S_SIZE)) {
225 		va_start(args, f);
226 		len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args);
227 		va_end(args);
228 		if (likely(m->count + len < S_SIZE)) {
229 			m->count += len;
230 			return 0;
231 		}
232 	}
233 	m->count = S_SIZE;
234 	printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n");
235 	return -1;
236 }
237 EXPORT_SYMBOL_GPL(nf_log_buf_add);
238 
nf_log_buf_open(void)239 struct nf_log_buf *nf_log_buf_open(void)
240 {
241 	struct nf_log_buf *m = kmalloc(sizeof(*m), GFP_ATOMIC);
242 
243 	if (unlikely(!m)) {
244 		local_bh_disable();
245 		do {
246 			m = xchg(&emergency_ptr, NULL);
247 		} while (!m);
248 	}
249 	m->count = 0;
250 	return m;
251 }
252 EXPORT_SYMBOL_GPL(nf_log_buf_open);
253 
nf_log_buf_close(struct nf_log_buf * m)254 void nf_log_buf_close(struct nf_log_buf *m)
255 {
256 	m->buf[m->count] = 0;
257 	printk("%s\n", m->buf);
258 
259 	if (likely(m != &emergency))
260 		kfree(m);
261 	else {
262 		emergency_ptr = m;
263 		local_bh_enable();
264 	}
265 }
266 EXPORT_SYMBOL_GPL(nf_log_buf_close);
267 
268 #ifdef CONFIG_PROC_FS
seq_start(struct seq_file * seq,loff_t * pos)269 static void *seq_start(struct seq_file *seq, loff_t *pos)
270 {
271 	struct net *net = seq_file_net(seq);
272 
273 	mutex_lock(&nf_log_mutex);
274 
275 	if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
276 		return NULL;
277 
278 	return pos;
279 }
280 
seq_next(struct seq_file * s,void * v,loff_t * pos)281 static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
282 {
283 	struct net *net = seq_file_net(s);
284 
285 	(*pos)++;
286 
287 	if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
288 		return NULL;
289 
290 	return pos;
291 }
292 
seq_stop(struct seq_file * s,void * v)293 static void seq_stop(struct seq_file *s, void *v)
294 {
295 	mutex_unlock(&nf_log_mutex);
296 }
297 
seq_show(struct seq_file * s,void * v)298 static int seq_show(struct seq_file *s, void *v)
299 {
300 	loff_t *pos = v;
301 	const struct nf_logger *logger;
302 	int i, ret;
303 	struct net *net = seq_file_net(s);
304 
305 	logger = nft_log_dereference(net->nf.nf_loggers[*pos]);
306 
307 	if (!logger)
308 		ret = seq_printf(s, "%2lld NONE (", *pos);
309 	else
310 		ret = seq_printf(s, "%2lld %s (", *pos, logger->name);
311 
312 	if (ret < 0)
313 		return ret;
314 
315 	for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
316 		if (loggers[*pos][i] == NULL)
317 			continue;
318 
319 		logger = nft_log_dereference(loggers[*pos][i]);
320 		ret = seq_printf(s, "%s", logger->name);
321 		if (ret < 0)
322 			return ret;
323 		if (i == 0 && loggers[*pos][i + 1] != NULL) {
324 			ret = seq_printf(s, ",");
325 			if (ret < 0)
326 				return ret;
327 		}
328 	}
329 
330 	return seq_printf(s, ")\n");
331 }
332 
333 static const struct seq_operations nflog_seq_ops = {
334 	.start	= seq_start,
335 	.next	= seq_next,
336 	.stop	= seq_stop,
337 	.show	= seq_show,
338 };
339 
nflog_open(struct inode * inode,struct file * file)340 static int nflog_open(struct inode *inode, struct file *file)
341 {
342 	return seq_open_net(inode, file, &nflog_seq_ops,
343 			    sizeof(struct seq_net_private));
344 }
345 
346 static const struct file_operations nflog_file_ops = {
347 	.owner	 = THIS_MODULE,
348 	.open	 = nflog_open,
349 	.read	 = seq_read,
350 	.llseek	 = seq_lseek,
351 	.release = seq_release_net,
352 };
353 
354 
355 #endif /* PROC_FS */
356 
357 #ifdef CONFIG_SYSCTL
358 static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
359 static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
360 
nf_log_proc_dostring(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)361 static int nf_log_proc_dostring(struct ctl_table *table, int write,
362 			 void __user *buffer, size_t *lenp, loff_t *ppos)
363 {
364 	const struct nf_logger *logger;
365 	char buf[NFLOGGER_NAME_LEN];
366 	size_t size = *lenp;
367 	int r = 0;
368 	int tindex = (unsigned long)table->extra1;
369 	struct net *net = current->nsproxy->net_ns;
370 
371 	if (write) {
372 		if (size > sizeof(buf))
373 			size = sizeof(buf);
374 		if (copy_from_user(buf, buffer, size))
375 			return -EFAULT;
376 
377 		if (!strcmp(buf, "NONE")) {
378 			nf_log_unbind_pf(net, tindex);
379 			return 0;
380 		}
381 		mutex_lock(&nf_log_mutex);
382 		logger = __find_logger(tindex, buf);
383 		if (logger == NULL) {
384 			mutex_unlock(&nf_log_mutex);
385 			return -ENOENT;
386 		}
387 		rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
388 		mutex_unlock(&nf_log_mutex);
389 	} else {
390 		mutex_lock(&nf_log_mutex);
391 		logger = nft_log_dereference(net->nf.nf_loggers[tindex]);
392 		if (!logger)
393 			table->data = "NONE";
394 		else
395 			table->data = logger->name;
396 		r = proc_dostring(table, write, buffer, lenp, ppos);
397 		mutex_unlock(&nf_log_mutex);
398 	}
399 
400 	return r;
401 }
402 
netfilter_log_sysctl_init(struct net * net)403 static int netfilter_log_sysctl_init(struct net *net)
404 {
405 	int i;
406 	struct ctl_table *table;
407 
408 	table = nf_log_sysctl_table;
409 	if (!net_eq(net, &init_net)) {
410 		table = kmemdup(nf_log_sysctl_table,
411 				 sizeof(nf_log_sysctl_table),
412 				 GFP_KERNEL);
413 		if (!table)
414 			goto err_alloc;
415 	} else {
416 		for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
417 			snprintf(nf_log_sysctl_fnames[i],
418 				 3, "%d", i);
419 			nf_log_sysctl_table[i].procname	=
420 				nf_log_sysctl_fnames[i];
421 			nf_log_sysctl_table[i].data = NULL;
422 			nf_log_sysctl_table[i].maxlen =
423 				NFLOGGER_NAME_LEN * sizeof(char);
424 			nf_log_sysctl_table[i].mode = 0644;
425 			nf_log_sysctl_table[i].proc_handler =
426 				nf_log_proc_dostring;
427 			nf_log_sysctl_table[i].extra1 =
428 				(void *)(unsigned long) i;
429 		}
430 	}
431 
432 	net->nf.nf_log_dir_header = register_net_sysctl(net,
433 						"net/netfilter/nf_log",
434 						table);
435 	if (!net->nf.nf_log_dir_header)
436 		goto err_reg;
437 
438 	return 0;
439 
440 err_reg:
441 	if (!net_eq(net, &init_net))
442 		kfree(table);
443 err_alloc:
444 	return -ENOMEM;
445 }
446 
netfilter_log_sysctl_exit(struct net * net)447 static void netfilter_log_sysctl_exit(struct net *net)
448 {
449 	struct ctl_table *table;
450 
451 	table = net->nf.nf_log_dir_header->ctl_table_arg;
452 	unregister_net_sysctl_table(net->nf.nf_log_dir_header);
453 	if (!net_eq(net, &init_net))
454 		kfree(table);
455 }
456 #else
netfilter_log_sysctl_init(struct net * net)457 static int netfilter_log_sysctl_init(struct net *net)
458 {
459 	return 0;
460 }
461 
netfilter_log_sysctl_exit(struct net * net)462 static void netfilter_log_sysctl_exit(struct net *net)
463 {
464 }
465 #endif /* CONFIG_SYSCTL */
466 
nf_log_net_init(struct net * net)467 static int __net_init nf_log_net_init(struct net *net)
468 {
469 	int ret = -ENOMEM;
470 
471 #ifdef CONFIG_PROC_FS
472 	if (!proc_create("nf_log", S_IRUGO,
473 			 net->nf.proc_netfilter, &nflog_file_ops))
474 		return ret;
475 #endif
476 	ret = netfilter_log_sysctl_init(net);
477 	if (ret < 0)
478 		goto out_sysctl;
479 
480 	return 0;
481 
482 out_sysctl:
483 #ifdef CONFIG_PROC_FS
484 	remove_proc_entry("nf_log", net->nf.proc_netfilter);
485 #endif
486 	return ret;
487 }
488 
nf_log_net_exit(struct net * net)489 static void __net_exit nf_log_net_exit(struct net *net)
490 {
491 	netfilter_log_sysctl_exit(net);
492 #ifdef CONFIG_PROC_FS
493 	remove_proc_entry("nf_log", net->nf.proc_netfilter);
494 #endif
495 }
496 
497 static struct pernet_operations nf_log_net_ops = {
498 	.init = nf_log_net_init,
499 	.exit = nf_log_net_exit,
500 };
501 
netfilter_log_init(void)502 int __init netfilter_log_init(void)
503 {
504 	return register_pernet_subsys(&nf_log_net_ops);
505 }
506