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

Configure Feed

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

at v4.10-rc7 563 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 NFLOGGER_NAME_LEN 64 17 18static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly; 19static DEFINE_MUTEX(nf_log_mutex); 20 21#define nft_log_dereference(logger) \ 22 rcu_dereference_protected(logger, lockdep_is_held(&nf_log_mutex)) 23 24static struct nf_logger *__find_logger(int pf, const char *str_logger) 25{ 26 struct nf_logger *log; 27 int i; 28 29 for (i = 0; i < NF_LOG_TYPE_MAX; i++) { 30 if (loggers[pf][i] == NULL) 31 continue; 32 33 log = nft_log_dereference(loggers[pf][i]); 34 if (!strncasecmp(str_logger, log->name, strlen(log->name))) 35 return log; 36 } 37 38 return NULL; 39} 40 41int nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger) 42{ 43 const struct nf_logger *log; 44 45 if (pf == NFPROTO_UNSPEC || pf >= ARRAY_SIZE(net->nf.nf_loggers)) 46 return -EOPNOTSUPP; 47 48 mutex_lock(&nf_log_mutex); 49 log = nft_log_dereference(net->nf.nf_loggers[pf]); 50 if (log == NULL) 51 rcu_assign_pointer(net->nf.nf_loggers[pf], logger); 52 53 mutex_unlock(&nf_log_mutex); 54 55 return 0; 56} 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 64 mutex_lock(&nf_log_mutex); 65 for (i = 0; i < NFPROTO_NUMPROTO; i++) { 66 log = nft_log_dereference(net->nf.nf_loggers[i]); 67 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 75/* return EEXIST if the same logger is registered, 0 on success. */ 76int nf_log_register(u_int8_t pf, struct nf_logger *logger) 77{ 78 int i; 79 int ret = 0; 80 81 if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers)) 82 return -EINVAL; 83 84 mutex_lock(&nf_log_mutex); 85 86 if (pf == NFPROTO_UNSPEC) { 87 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 } 93 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) 94 rcu_assign_pointer(loggers[i][logger->type], logger); 95 } else { 96 if (rcu_access_pointer(loggers[pf][logger->type])) { 97 ret = -EEXIST; 98 goto unlock; 99 } 100 rcu_assign_pointer(loggers[pf][logger->type], logger); 101 } 102 103unlock: 104 mutex_unlock(&nf_log_mutex); 105 return ret; 106} 107EXPORT_SYMBOL(nf_log_register); 108 109void nf_log_unregister(struct nf_logger *logger) 110{ 111 const struct nf_logger *log; 112 int i; 113 114 mutex_lock(&nf_log_mutex); 115 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 } 120 mutex_unlock(&nf_log_mutex); 121 synchronize_rcu(); 122} 123EXPORT_SYMBOL(nf_log_unregister); 124 125int nf_log_bind_pf(struct net *net, u_int8_t pf, 126 const struct nf_logger *logger) 127{ 128 if (pf >= ARRAY_SIZE(net->nf.nf_loggers)) 129 return -EINVAL; 130 mutex_lock(&nf_log_mutex); 131 if (__find_logger(pf, logger->name) == NULL) { 132 mutex_unlock(&nf_log_mutex); 133 return -ENOENT; 134 } 135 rcu_assign_pointer(net->nf.nf_loggers[pf], logger); 136 mutex_unlock(&nf_log_mutex); 137 return 0; 138} 139EXPORT_SYMBOL(nf_log_bind_pf); 140 141void nf_log_unbind_pf(struct net *net, u_int8_t pf) 142{ 143 if (pf >= ARRAY_SIZE(net->nf.nf_loggers)) 144 return; 145 mutex_lock(&nf_log_mutex); 146 RCU_INIT_POINTER(net->nf.nf_loggers[pf], NULL); 147 mutex_unlock(&nf_log_mutex); 148} 149EXPORT_SYMBOL(nf_log_unbind_pf); 150 151void 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 158int nf_logger_find_get(int pf, enum nf_log_type type) 159{ 160 struct nf_logger *logger; 161 int ret = -ENOENT; 162 163 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 177 if (rcu_access_pointer(loggers[pf][type]) == NULL) 178 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 185 if (try_module_get(logger->me)) 186 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 197 if (pf == NFPROTO_INET) { 198 nf_logger_put(NFPROTO_IPV4, type); 199 nf_logger_put(NFPROTO_IPV6, type); 200 return; 201 } 202 203 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 212void nf_log_packet(struct net *net, 213 u_int8_t pf, 214 unsigned int hooknum, 215 const struct sk_buff *skb, 216 const struct net_device *in, 217 const struct net_device *out, 218 const struct nf_loginfo *loginfo, 219 const char *fmt, ...) 220{ 221 va_list args; 222 char prefix[NF_LOG_PREFIXLEN]; 223 const struct nf_logger *logger; 224 225 rcu_read_lock(); 226 if (loginfo != NULL) 227 logger = rcu_dereference(loggers[pf][loginfo->type]); 228 else 229 logger = rcu_dereference(net->nf.nf_loggers[pf]); 230 231 if (logger) { 232 va_start(args, fmt); 233 vsnprintf(prefix, sizeof(prefix), fmt, args); 234 va_end(args); 235 logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix); 236 } 237 rcu_read_unlock(); 238} 239EXPORT_SYMBOL(nf_log_packet); 240 241void 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 265#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 322#ifdef CONFIG_PROC_FS 323static void *seq_start(struct seq_file *seq, loff_t *pos) 324{ 325 struct net *net = seq_file_net(seq); 326 327 mutex_lock(&nf_log_mutex); 328 329 if (*pos >= ARRAY_SIZE(net->nf.nf_loggers)) 330 return NULL; 331 332 return pos; 333} 334 335static void *seq_next(struct seq_file *s, void *v, loff_t *pos) 336{ 337 struct net *net = seq_file_net(s); 338 339 (*pos)++; 340 341 if (*pos >= ARRAY_SIZE(net->nf.nf_loggers)) 342 return NULL; 343 344 return pos; 345} 346 347static void seq_stop(struct seq_file *s, void *v) 348{ 349 mutex_unlock(&nf_log_mutex); 350} 351 352static int seq_show(struct seq_file *s, void *v) 353{ 354 loff_t *pos = v; 355 const struct nf_logger *logger; 356 int i; 357 struct net *net = seq_file_net(s); 358 359 logger = nft_log_dereference(net->nf.nf_loggers[*pos]); 360 361 if (!logger) 362 seq_printf(s, "%2lld NONE (", *pos); 363 else 364 seq_printf(s, "%2lld %s (", *pos, logger->name); 365 366 if (seq_has_overflowed(s)) 367 return -ENOSPC; 368 369 for (i = 0; i < NF_LOG_TYPE_MAX; i++) { 370 if (loggers[*pos][i] == NULL) 371 continue; 372 373 logger = nft_log_dereference(loggers[*pos][i]); 374 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; 380 } 381 382 seq_printf(s, ")\n"); 383 384 if (seq_has_overflowed(s)) 385 return -ENOSPC; 386 return 0; 387} 388 389static const struct seq_operations nflog_seq_ops = { 390 .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{ 398 return seq_open_net(inode, file, &nflog_seq_ops, 399 sizeof(struct seq_net_private)); 400} 401 402static const struct file_operations nflog_file_ops = { 403 .owner = THIS_MODULE, 404 .open = nflog_open, 405 .read = seq_read, 406 .llseek = seq_lseek, 407 .release = seq_release_net, 408}; 409 410 411#endif /* PROC_FS */ 412 413#ifdef CONFIG_SYSCTL 414static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3]; 415static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1]; 416 417static int nf_log_proc_dostring(struct ctl_table *table, int write, 418 void __user *buffer, size_t *lenp, loff_t *ppos) 419{ 420 const struct nf_logger *logger; 421 char buf[NFLOGGER_NAME_LEN]; 422 int r = 0; 423 int tindex = (unsigned long)table->extra1; 424 struct net *net = table->extra2; 425 426 if (write) { 427 struct ctl_table tmp = *table; 428 429 tmp.data = buf; 430 r = proc_dostring(&tmp, write, buffer, lenp, ppos); 431 if (r) 432 return r; 433 434 if (!strcmp(buf, "NONE")) { 435 nf_log_unbind_pf(net, tindex); 436 return 0; 437 } 438 mutex_lock(&nf_log_mutex); 439 logger = __find_logger(tindex, buf); 440 if (logger == NULL) { 441 mutex_unlock(&nf_log_mutex); 442 return -ENOENT; 443 } 444 rcu_assign_pointer(net->nf.nf_loggers[tindex], logger); 445 mutex_unlock(&nf_log_mutex); 446 } else { 447 mutex_lock(&nf_log_mutex); 448 logger = nft_log_dereference(net->nf.nf_loggers[tindex]); 449 if (!logger) 450 table->data = "NONE"; 451 else 452 table->data = logger->name; 453 r = proc_dostring(table, write, buffer, lenp, ppos); 454 mutex_unlock(&nf_log_mutex); 455 } 456 457 return r; 458} 459 460static int netfilter_log_sysctl_init(struct net *net) 461{ 462 int i; 463 struct ctl_table *table; 464 465 table = nf_log_sysctl_table; 466 if (!net_eq(net, &init_net)) { 467 table = kmemdup(nf_log_sysctl_table, 468 sizeof(nf_log_sysctl_table), 469 GFP_KERNEL); 470 if (!table) 471 goto err_alloc; 472 } else { 473 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) { 474 snprintf(nf_log_sysctl_fnames[i], 475 3, "%d", i); 476 nf_log_sysctl_table[i].procname = 477 nf_log_sysctl_fnames[i]; 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 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) 488 table[i].extra2 = net; 489 490 net->nf.nf_log_dir_header = register_net_sysctl(net, 491 "net/netfilter/nf_log", 492 table); 493 if (!net->nf.nf_log_dir_header) 494 goto err_reg; 495 496 return 0; 497 498err_reg: 499 if (!net_eq(net, &init_net)) 500 kfree(table); 501err_alloc: 502 return -ENOMEM; 503} 504 505static void netfilter_log_sysctl_exit(struct net *net) 506{ 507 struct ctl_table *table; 508 509 table = net->nf.nf_log_dir_header->ctl_table_arg; 510 unregister_net_sysctl_table(net->nf.nf_log_dir_header); 511 if (!net_eq(net, &init_net)) 512 kfree(table); 513} 514#else 515static int netfilter_log_sysctl_init(struct net *net) 516{ 517 return 0; 518} 519 520static void netfilter_log_sysctl_exit(struct net *net) 521{ 522} 523#endif /* CONFIG_SYSCTL */ 524 525static int __net_init nf_log_net_init(struct net *net) 526{ 527 int ret = -ENOMEM; 528 529#ifdef CONFIG_PROC_FS 530 if (!proc_create("nf_log", S_IRUGO, 531 net->nf.proc_netfilter, &nflog_file_ops)) 532 return ret; 533#endif 534 ret = netfilter_log_sysctl_init(net); 535 if (ret < 0) 536 goto out_sysctl; 537 538 return 0; 539 540out_sysctl: 541#ifdef CONFIG_PROC_FS 542 remove_proc_entry("nf_log", net->nf.proc_netfilter); 543#endif 544 return ret; 545} 546 547static void __net_exit nf_log_net_exit(struct net *net) 548{ 549 netfilter_log_sysctl_exit(net); 550#ifdef CONFIG_PROC_FS 551 remove_proc_entry("nf_log", net->nf.proc_netfilter); 552#endif 553} 554 555static struct pernet_operations nf_log_net_ops = { 556 .init = nf_log_net_init, 557 .exit = nf_log_net_exit, 558}; 559 560int __init netfilter_log_init(void) 561{ 562 return register_pernet_subsys(&nf_log_net_ops); 563}