0001
0002 #include <linux/kernel.h>
0003 #include <linux/init.h>
0004 #include <linux/module.h>
0005 #include <linux/proc_fs.h>
0006 #include <linux/skbuff.h>
0007 #include <linux/netfilter.h>
0008 #include <linux/seq_file.h>
0009 #include <net/protocol.h>
0010 #include <net/netfilter/nf_log.h>
0011
0012 #include "nf_internals.h"
0013
0014
0015
0016
0017 #define NFLOGGER_NAME_LEN 64
0018
0019 int sysctl_nf_log_all_netns __read_mostly;
0020 EXPORT_SYMBOL(sysctl_nf_log_all_netns);
0021
0022 static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly;
0023 static DEFINE_MUTEX(nf_log_mutex);
0024
0025 #define nft_log_dereference(logger) \
0026 rcu_dereference_protected(logger, lockdep_is_held(&nf_log_mutex))
0027
0028 static struct nf_logger *__find_logger(int pf, const char *str_logger)
0029 {
0030 struct nf_logger *log;
0031 int i;
0032
0033 for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
0034 if (loggers[pf][i] == NULL)
0035 continue;
0036
0037 log = nft_log_dereference(loggers[pf][i]);
0038 if (!strncasecmp(str_logger, log->name, strlen(log->name)))
0039 return log;
0040 }
0041
0042 return NULL;
0043 }
0044
0045 int nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger)
0046 {
0047 const struct nf_logger *log;
0048
0049 if (pf == NFPROTO_UNSPEC || pf >= ARRAY_SIZE(net->nf.nf_loggers))
0050 return -EOPNOTSUPP;
0051
0052 mutex_lock(&nf_log_mutex);
0053 log = nft_log_dereference(net->nf.nf_loggers[pf]);
0054 if (log == NULL)
0055 rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
0056
0057 mutex_unlock(&nf_log_mutex);
0058
0059 return 0;
0060 }
0061 EXPORT_SYMBOL(nf_log_set);
0062
0063 void nf_log_unset(struct net *net, const struct nf_logger *logger)
0064 {
0065 int i;
0066 const struct nf_logger *log;
0067
0068 mutex_lock(&nf_log_mutex);
0069 for (i = 0; i < NFPROTO_NUMPROTO; i++) {
0070 log = nft_log_dereference(net->nf.nf_loggers[i]);
0071 if (log == logger)
0072 RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL);
0073 }
0074 mutex_unlock(&nf_log_mutex);
0075 }
0076 EXPORT_SYMBOL(nf_log_unset);
0077
0078
0079 int nf_log_register(u_int8_t pf, struct nf_logger *logger)
0080 {
0081 int i;
0082 int ret = 0;
0083
0084 if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers))
0085 return -EINVAL;
0086
0087 mutex_lock(&nf_log_mutex);
0088
0089 if (pf == NFPROTO_UNSPEC) {
0090 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
0091 if (rcu_access_pointer(loggers[i][logger->type])) {
0092 ret = -EEXIST;
0093 goto unlock;
0094 }
0095 }
0096 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
0097 rcu_assign_pointer(loggers[i][logger->type], logger);
0098 } else {
0099 if (rcu_access_pointer(loggers[pf][logger->type])) {
0100 ret = -EEXIST;
0101 goto unlock;
0102 }
0103 rcu_assign_pointer(loggers[pf][logger->type], logger);
0104 }
0105
0106 unlock:
0107 mutex_unlock(&nf_log_mutex);
0108 return ret;
0109 }
0110 EXPORT_SYMBOL(nf_log_register);
0111
0112 void nf_log_unregister(struct nf_logger *logger)
0113 {
0114 const struct nf_logger *log;
0115 int i;
0116
0117 mutex_lock(&nf_log_mutex);
0118 for (i = 0; i < NFPROTO_NUMPROTO; i++) {
0119 log = nft_log_dereference(loggers[i][logger->type]);
0120 if (log == logger)
0121 RCU_INIT_POINTER(loggers[i][logger->type], NULL);
0122 }
0123 mutex_unlock(&nf_log_mutex);
0124 synchronize_rcu();
0125 }
0126 EXPORT_SYMBOL(nf_log_unregister);
0127
0128 int nf_log_bind_pf(struct net *net, u_int8_t pf,
0129 const struct nf_logger *logger)
0130 {
0131 if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
0132 return -EINVAL;
0133 mutex_lock(&nf_log_mutex);
0134 if (__find_logger(pf, logger->name) == NULL) {
0135 mutex_unlock(&nf_log_mutex);
0136 return -ENOENT;
0137 }
0138 rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
0139 mutex_unlock(&nf_log_mutex);
0140 return 0;
0141 }
0142 EXPORT_SYMBOL(nf_log_bind_pf);
0143
0144 void nf_log_unbind_pf(struct net *net, u_int8_t pf)
0145 {
0146 if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
0147 return;
0148 mutex_lock(&nf_log_mutex);
0149 RCU_INIT_POINTER(net->nf.nf_loggers[pf], NULL);
0150 mutex_unlock(&nf_log_mutex);
0151 }
0152 EXPORT_SYMBOL(nf_log_unbind_pf);
0153
0154 int nf_logger_find_get(int pf, enum nf_log_type type)
0155 {
0156 struct nf_logger *logger;
0157 int ret = -ENOENT;
0158
0159 if (pf == NFPROTO_INET) {
0160 ret = nf_logger_find_get(NFPROTO_IPV4, type);
0161 if (ret < 0)
0162 return ret;
0163
0164 ret = nf_logger_find_get(NFPROTO_IPV6, type);
0165 if (ret < 0) {
0166 nf_logger_put(NFPROTO_IPV4, type);
0167 return ret;
0168 }
0169
0170 return 0;
0171 }
0172
0173 rcu_read_lock();
0174 logger = rcu_dereference(loggers[pf][type]);
0175 if (logger == NULL)
0176 goto out;
0177
0178 if (try_module_get(logger->me))
0179 ret = 0;
0180 out:
0181 rcu_read_unlock();
0182 return ret;
0183 }
0184 EXPORT_SYMBOL_GPL(nf_logger_find_get);
0185
0186 void nf_logger_put(int pf, enum nf_log_type type)
0187 {
0188 struct nf_logger *logger;
0189
0190 if (pf == NFPROTO_INET) {
0191 nf_logger_put(NFPROTO_IPV4, type);
0192 nf_logger_put(NFPROTO_IPV6, type);
0193 return;
0194 }
0195
0196 BUG_ON(loggers[pf][type] == NULL);
0197
0198 rcu_read_lock();
0199 logger = rcu_dereference(loggers[pf][type]);
0200 module_put(logger->me);
0201 rcu_read_unlock();
0202 }
0203 EXPORT_SYMBOL_GPL(nf_logger_put);
0204
0205 void nf_log_packet(struct net *net,
0206 u_int8_t pf,
0207 unsigned int hooknum,
0208 const struct sk_buff *skb,
0209 const struct net_device *in,
0210 const struct net_device *out,
0211 const struct nf_loginfo *loginfo,
0212 const char *fmt, ...)
0213 {
0214 va_list args;
0215 char prefix[NF_LOG_PREFIXLEN];
0216 const struct nf_logger *logger;
0217
0218 rcu_read_lock();
0219 if (loginfo != NULL)
0220 logger = rcu_dereference(loggers[pf][loginfo->type]);
0221 else
0222 logger = rcu_dereference(net->nf.nf_loggers[pf]);
0223
0224 if (logger) {
0225 va_start(args, fmt);
0226 vsnprintf(prefix, sizeof(prefix), fmt, args);
0227 va_end(args);
0228 logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
0229 }
0230 rcu_read_unlock();
0231 }
0232 EXPORT_SYMBOL(nf_log_packet);
0233
0234 void nf_log_trace(struct net *net,
0235 u_int8_t pf,
0236 unsigned int hooknum,
0237 const struct sk_buff *skb,
0238 const struct net_device *in,
0239 const struct net_device *out,
0240 const struct nf_loginfo *loginfo, const char *fmt, ...)
0241 {
0242 va_list args;
0243 char prefix[NF_LOG_PREFIXLEN];
0244 const struct nf_logger *logger;
0245
0246 rcu_read_lock();
0247 logger = rcu_dereference(net->nf.nf_loggers[pf]);
0248 if (logger) {
0249 va_start(args, fmt);
0250 vsnprintf(prefix, sizeof(prefix), fmt, args);
0251 va_end(args);
0252 logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
0253 }
0254 rcu_read_unlock();
0255 }
0256 EXPORT_SYMBOL(nf_log_trace);
0257
0258 #define S_SIZE (1024 - (sizeof(unsigned int) + 1))
0259
0260 struct nf_log_buf {
0261 unsigned int count;
0262 char buf[S_SIZE + 1];
0263 };
0264 static struct nf_log_buf emergency, *emergency_ptr = &emergency;
0265
0266 __printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...)
0267 {
0268 va_list args;
0269 int len;
0270
0271 if (likely(m->count < S_SIZE)) {
0272 va_start(args, f);
0273 len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args);
0274 va_end(args);
0275 if (likely(m->count + len < S_SIZE)) {
0276 m->count += len;
0277 return 0;
0278 }
0279 }
0280 m->count = S_SIZE;
0281 printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n");
0282 return -1;
0283 }
0284 EXPORT_SYMBOL_GPL(nf_log_buf_add);
0285
0286 struct nf_log_buf *nf_log_buf_open(void)
0287 {
0288 struct nf_log_buf *m = kmalloc(sizeof(*m), GFP_ATOMIC);
0289
0290 if (unlikely(!m)) {
0291 local_bh_disable();
0292 do {
0293 m = xchg(&emergency_ptr, NULL);
0294 } while (!m);
0295 }
0296 m->count = 0;
0297 return m;
0298 }
0299 EXPORT_SYMBOL_GPL(nf_log_buf_open);
0300
0301 void nf_log_buf_close(struct nf_log_buf *m)
0302 {
0303 m->buf[m->count] = 0;
0304 printk("%s\n", m->buf);
0305
0306 if (likely(m != &emergency))
0307 kfree(m);
0308 else {
0309 emergency_ptr = m;
0310 local_bh_enable();
0311 }
0312 }
0313 EXPORT_SYMBOL_GPL(nf_log_buf_close);
0314
0315 #ifdef CONFIG_PROC_FS
0316 static void *seq_start(struct seq_file *seq, loff_t *pos)
0317 {
0318 struct net *net = seq_file_net(seq);
0319
0320 mutex_lock(&nf_log_mutex);
0321
0322 if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
0323 return NULL;
0324
0325 return pos;
0326 }
0327
0328 static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
0329 {
0330 struct net *net = seq_file_net(s);
0331
0332 (*pos)++;
0333
0334 if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
0335 return NULL;
0336
0337 return pos;
0338 }
0339
0340 static void seq_stop(struct seq_file *s, void *v)
0341 {
0342 mutex_unlock(&nf_log_mutex);
0343 }
0344
0345 static int seq_show(struct seq_file *s, void *v)
0346 {
0347 loff_t *pos = v;
0348 const struct nf_logger *logger;
0349 int i;
0350 struct net *net = seq_file_net(s);
0351
0352 logger = nft_log_dereference(net->nf.nf_loggers[*pos]);
0353
0354 if (!logger)
0355 seq_printf(s, "%2lld NONE (", *pos);
0356 else
0357 seq_printf(s, "%2lld %s (", *pos, logger->name);
0358
0359 if (seq_has_overflowed(s))
0360 return -ENOSPC;
0361
0362 for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
0363 if (loggers[*pos][i] == NULL)
0364 continue;
0365
0366 logger = nft_log_dereference(loggers[*pos][i]);
0367 seq_puts(s, logger->name);
0368 if (i == 0 && loggers[*pos][i + 1] != NULL)
0369 seq_puts(s, ",");
0370
0371 if (seq_has_overflowed(s))
0372 return -ENOSPC;
0373 }
0374
0375 seq_puts(s, ")\n");
0376
0377 if (seq_has_overflowed(s))
0378 return -ENOSPC;
0379 return 0;
0380 }
0381
0382 static const struct seq_operations nflog_seq_ops = {
0383 .start = seq_start,
0384 .next = seq_next,
0385 .stop = seq_stop,
0386 .show = seq_show,
0387 };
0388 #endif
0389
0390 #ifdef CONFIG_SYSCTL
0391 static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
0392 static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
0393 static struct ctl_table_header *nf_log_sysctl_fhdr;
0394
0395 static struct ctl_table nf_log_sysctl_ftable[] = {
0396 {
0397 .procname = "nf_log_all_netns",
0398 .data = &sysctl_nf_log_all_netns,
0399 .maxlen = sizeof(sysctl_nf_log_all_netns),
0400 .mode = 0644,
0401 .proc_handler = proc_dointvec,
0402 },
0403 { }
0404 };
0405
0406 static int nf_log_proc_dostring(struct ctl_table *table, int write,
0407 void *buffer, size_t *lenp, loff_t *ppos)
0408 {
0409 const struct nf_logger *logger;
0410 char buf[NFLOGGER_NAME_LEN];
0411 int r = 0;
0412 int tindex = (unsigned long)table->extra1;
0413 struct net *net = table->extra2;
0414
0415 if (write) {
0416 struct ctl_table tmp = *table;
0417
0418
0419
0420
0421 buf[0] = '\0';
0422 tmp.data = buf;
0423 r = proc_dostring(&tmp, write, buffer, lenp, ppos);
0424 if (r)
0425 return r;
0426
0427 if (!strcmp(buf, "NONE")) {
0428 nf_log_unbind_pf(net, tindex);
0429 return 0;
0430 }
0431 mutex_lock(&nf_log_mutex);
0432 logger = __find_logger(tindex, buf);
0433 if (logger == NULL) {
0434 mutex_unlock(&nf_log_mutex);
0435 return -ENOENT;
0436 }
0437 rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
0438 mutex_unlock(&nf_log_mutex);
0439 } else {
0440 struct ctl_table tmp = *table;
0441
0442 tmp.data = buf;
0443 mutex_lock(&nf_log_mutex);
0444 logger = nft_log_dereference(net->nf.nf_loggers[tindex]);
0445 if (!logger)
0446 strlcpy(buf, "NONE", sizeof(buf));
0447 else
0448 strlcpy(buf, logger->name, sizeof(buf));
0449 mutex_unlock(&nf_log_mutex);
0450 r = proc_dostring(&tmp, write, buffer, lenp, ppos);
0451 }
0452
0453 return r;
0454 }
0455
0456 static int netfilter_log_sysctl_init(struct net *net)
0457 {
0458 int i;
0459 struct ctl_table *table;
0460
0461 table = nf_log_sysctl_table;
0462 if (!net_eq(net, &init_net)) {
0463 table = kmemdup(nf_log_sysctl_table,
0464 sizeof(nf_log_sysctl_table),
0465 GFP_KERNEL);
0466 if (!table)
0467 goto err_alloc;
0468 } else {
0469 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
0470 snprintf(nf_log_sysctl_fnames[i],
0471 3, "%d", i);
0472 nf_log_sysctl_table[i].procname =
0473 nf_log_sysctl_fnames[i];
0474 nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN;
0475 nf_log_sysctl_table[i].mode = 0644;
0476 nf_log_sysctl_table[i].proc_handler =
0477 nf_log_proc_dostring;
0478 nf_log_sysctl_table[i].extra1 =
0479 (void *)(unsigned long) i;
0480 }
0481 nf_log_sysctl_fhdr = register_net_sysctl(net, "net/netfilter",
0482 nf_log_sysctl_ftable);
0483 if (!nf_log_sysctl_fhdr)
0484 goto err_freg;
0485 }
0486
0487 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
0488 table[i].extra2 = net;
0489
0490 net->nf.nf_log_dir_header = register_net_sysctl(net,
0491 "net/netfilter/nf_log",
0492 table);
0493 if (!net->nf.nf_log_dir_header)
0494 goto err_reg;
0495
0496 return 0;
0497
0498 err_reg:
0499 if (!net_eq(net, &init_net))
0500 kfree(table);
0501 else
0502 unregister_net_sysctl_table(nf_log_sysctl_fhdr);
0503 err_freg:
0504 err_alloc:
0505 return -ENOMEM;
0506 }
0507
0508 static void netfilter_log_sysctl_exit(struct net *net)
0509 {
0510 struct ctl_table *table;
0511
0512 table = net->nf.nf_log_dir_header->ctl_table_arg;
0513 unregister_net_sysctl_table(net->nf.nf_log_dir_header);
0514 if (!net_eq(net, &init_net))
0515 kfree(table);
0516 else
0517 unregister_net_sysctl_table(nf_log_sysctl_fhdr);
0518 }
0519 #else
0520 static int netfilter_log_sysctl_init(struct net *net)
0521 {
0522 return 0;
0523 }
0524
0525 static void netfilter_log_sysctl_exit(struct net *net)
0526 {
0527 }
0528 #endif
0529
0530 static int __net_init nf_log_net_init(struct net *net)
0531 {
0532 int ret = -ENOMEM;
0533
0534 #ifdef CONFIG_PROC_FS
0535 if (!proc_create_net("nf_log", 0444, net->nf.proc_netfilter,
0536 &nflog_seq_ops, sizeof(struct seq_net_private)))
0537 return ret;
0538 #endif
0539 ret = netfilter_log_sysctl_init(net);
0540 if (ret < 0)
0541 goto out_sysctl;
0542
0543 return 0;
0544
0545 out_sysctl:
0546 #ifdef CONFIG_PROC_FS
0547 remove_proc_entry("nf_log", net->nf.proc_netfilter);
0548 #endif
0549 return ret;
0550 }
0551
0552 static void __net_exit nf_log_net_exit(struct net *net)
0553 {
0554 netfilter_log_sysctl_exit(net);
0555 #ifdef CONFIG_PROC_FS
0556 remove_proc_entry("nf_log", net->nf.proc_netfilter);
0557 #endif
0558 }
0559
0560 static struct pernet_operations nf_log_net_ops = {
0561 .init = nf_log_net_init,
0562 .exit = nf_log_net_exit,
0563 };
0564
0565 int __init netfilter_log_init(void)
0566 {
0567 return register_pernet_subsys(&nf_log_net_ops);
0568 }