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