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 #endif /* PROC_FS */ 398 399 #ifdef CONFIG_SYSCTL 400 static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3]; 401 static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1]; 402 static struct ctl_table_header *nf_log_sysctl_fhdr; 403 404 static struct ctl_table nf_log_sysctl_ftable[] = { 405 { 406 .procname = "nf_log_all_netns", 407 .data = &sysctl_nf_log_all_netns, 408 .maxlen = sizeof(sysctl_nf_log_all_netns), 409 .mode = 0644, 410 .proc_handler = proc_dointvec, 411 }, 412 { } 413 }; 414 415 static int nf_log_proc_dostring(struct ctl_table *table, int write, 416 void __user *buffer, size_t *lenp, loff_t *ppos) 417 { 418 const struct nf_logger *logger; 419 char buf[NFLOGGER_NAME_LEN]; 420 int r = 0; 421 int tindex = (unsigned long)table->extra1; 422 struct net *net = table->extra2; 423 424 if (write) { 425 struct ctl_table tmp = *table; 426 427 /* proc_dostring() can append to existing strings, so we need to 428 * initialize it as an empty string. 429 */ 430 buf[0] = '\0'; 431 tmp.data = buf; 432 r = proc_dostring(&tmp, write, buffer, lenp, ppos); 433 if (r) 434 return r; 435 436 if (!strcmp(buf, "NONE")) { 437 nf_log_unbind_pf(net, tindex); 438 return 0; 439 } 440 mutex_lock(&nf_log_mutex); 441 logger = __find_logger(tindex, buf); 442 if (logger == NULL) { 443 mutex_unlock(&nf_log_mutex); 444 return -ENOENT; 445 } 446 rcu_assign_pointer(net->nf.nf_loggers[tindex], logger); 447 mutex_unlock(&nf_log_mutex); 448 } else { 449 struct ctl_table tmp = *table; 450 451 tmp.data = buf; 452 mutex_lock(&nf_log_mutex); 453 logger = nft_log_dereference(net->nf.nf_loggers[tindex]); 454 if (!logger) 455 strlcpy(buf, "NONE", sizeof(buf)); 456 else 457 strlcpy(buf, logger->name, sizeof(buf)); 458 mutex_unlock(&nf_log_mutex); 459 r = proc_dostring(&tmp, write, buffer, lenp, ppos); 460 } 461 462 return r; 463 } 464 465 static int netfilter_log_sysctl_init(struct net *net) 466 { 467 int i; 468 struct ctl_table *table; 469 470 table = nf_log_sysctl_table; 471 if (!net_eq(net, &init_net)) { 472 table = kmemdup(nf_log_sysctl_table, 473 sizeof(nf_log_sysctl_table), 474 GFP_KERNEL); 475 if (!table) 476 goto err_alloc; 477 } else { 478 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) { 479 snprintf(nf_log_sysctl_fnames[i], 480 3, "%d", i); 481 nf_log_sysctl_table[i].procname = 482 nf_log_sysctl_fnames[i]; 483 nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN; 484 nf_log_sysctl_table[i].mode = 0644; 485 nf_log_sysctl_table[i].proc_handler = 486 nf_log_proc_dostring; 487 nf_log_sysctl_table[i].extra1 = 488 (void *)(unsigned long) i; 489 } 490 nf_log_sysctl_fhdr = register_net_sysctl(net, "net/netfilter", 491 nf_log_sysctl_ftable); 492 if (!nf_log_sysctl_fhdr) 493 goto err_freg; 494 } 495 496 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) 497 table[i].extra2 = net; 498 499 net->nf.nf_log_dir_header = register_net_sysctl(net, 500 "net/netfilter/nf_log", 501 table); 502 if (!net->nf.nf_log_dir_header) 503 goto err_reg; 504 505 return 0; 506 507 err_reg: 508 if (!net_eq(net, &init_net)) 509 kfree(table); 510 else 511 unregister_net_sysctl_table(nf_log_sysctl_fhdr); 512 err_freg: 513 err_alloc: 514 return -ENOMEM; 515 } 516 517 static void netfilter_log_sysctl_exit(struct net *net) 518 { 519 struct ctl_table *table; 520 521 table = net->nf.nf_log_dir_header->ctl_table_arg; 522 unregister_net_sysctl_table(net->nf.nf_log_dir_header); 523 if (!net_eq(net, &init_net)) 524 kfree(table); 525 else 526 unregister_net_sysctl_table(nf_log_sysctl_fhdr); 527 } 528 #else 529 static int netfilter_log_sysctl_init(struct net *net) 530 { 531 return 0; 532 } 533 534 static void netfilter_log_sysctl_exit(struct net *net) 535 { 536 } 537 #endif /* CONFIG_SYSCTL */ 538 539 static int __net_init nf_log_net_init(struct net *net) 540 { 541 int ret = -ENOMEM; 542 543 #ifdef CONFIG_PROC_FS 544 if (!proc_create_net("nf_log", 0444, net->nf.proc_netfilter, 545 &nflog_seq_ops, sizeof(struct seq_net_private))) 546 return ret; 547 #endif 548 ret = netfilter_log_sysctl_init(net); 549 if (ret < 0) 550 goto out_sysctl; 551 552 return 0; 553 554 out_sysctl: 555 #ifdef CONFIG_PROC_FS 556 remove_proc_entry("nf_log", net->nf.proc_netfilter); 557 #endif 558 return ret; 559 } 560 561 static void __net_exit nf_log_net_exit(struct net *net) 562 { 563 netfilter_log_sysctl_exit(net); 564 #ifdef CONFIG_PROC_FS 565 remove_proc_entry("nf_log", net->nf.proc_netfilter); 566 #endif 567 } 568 569 static struct pernet_operations nf_log_net_ops = { 570 .init = nf_log_net_init, 571 .exit = nf_log_net_exit, 572 }; 573 574 int __init netfilter_log_init(void) 575 { 576 return register_pernet_subsys(&nf_log_net_ops); 577 } 578