Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

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