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