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 (rcu_access_pointer(loggers[pf][type]) == NULL) 163 request_module("nf-logger-%u-%u", pf, type); 164 165 rcu_read_lock(); 166 logger = rcu_dereference(loggers[pf][type]); 167 if (logger == NULL) 168 goto out; 169 170 if (logger && try_module_get(logger->me)) 171 ret = 0; 172out: 173 rcu_read_unlock(); 174 return ret; 175} 176EXPORT_SYMBOL_GPL(nf_logger_find_get); 177 178void nf_logger_put(int pf, enum nf_log_type type) 179{ 180 struct nf_logger *logger; 181 182 BUG_ON(loggers[pf][type] == NULL); 183 184 rcu_read_lock(); 185 logger = rcu_dereference(loggers[pf][type]); 186 module_put(logger->me); 187 rcu_read_unlock(); 188} 189EXPORT_SYMBOL_GPL(nf_logger_put); 190 191void nf_log_packet(struct net *net, 192 u_int8_t pf, 193 unsigned int hooknum, 194 const struct sk_buff *skb, 195 const struct net_device *in, 196 const struct net_device *out, 197 const struct nf_loginfo *loginfo, 198 const char *fmt, ...) 199{ 200 va_list args; 201 char prefix[NF_LOG_PREFIXLEN]; 202 const struct nf_logger *logger; 203 204 rcu_read_lock(); 205 if (loginfo != NULL) 206 logger = rcu_dereference(loggers[pf][loginfo->type]); 207 else 208 logger = rcu_dereference(net->nf.nf_loggers[pf]); 209 210 if (logger) { 211 va_start(args, fmt); 212 vsnprintf(prefix, sizeof(prefix), fmt, args); 213 va_end(args); 214 logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix); 215 } 216 rcu_read_unlock(); 217} 218EXPORT_SYMBOL(nf_log_packet); 219 220void nf_log_trace(struct net *net, 221 u_int8_t pf, 222 unsigned int hooknum, 223 const struct sk_buff *skb, 224 const struct net_device *in, 225 const struct net_device *out, 226 const struct nf_loginfo *loginfo, const char *fmt, ...) 227{ 228 va_list args; 229 char prefix[NF_LOG_PREFIXLEN]; 230 const struct nf_logger *logger; 231 232 rcu_read_lock(); 233 logger = rcu_dereference(net->nf.nf_loggers[pf]); 234 if (logger) { 235 va_start(args, fmt); 236 vsnprintf(prefix, sizeof(prefix), fmt, args); 237 va_end(args); 238 logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix); 239 } 240 rcu_read_unlock(); 241} 242EXPORT_SYMBOL(nf_log_trace); 243 244#define S_SIZE (1024 - (sizeof(unsigned int) + 1)) 245 246struct nf_log_buf { 247 unsigned int count; 248 char buf[S_SIZE + 1]; 249}; 250static struct nf_log_buf emergency, *emergency_ptr = &emergency; 251 252__printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...) 253{ 254 va_list args; 255 int len; 256 257 if (likely(m->count < S_SIZE)) { 258 va_start(args, f); 259 len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args); 260 va_end(args); 261 if (likely(m->count + len < S_SIZE)) { 262 m->count += len; 263 return 0; 264 } 265 } 266 m->count = S_SIZE; 267 printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n"); 268 return -1; 269} 270EXPORT_SYMBOL_GPL(nf_log_buf_add); 271 272struct nf_log_buf *nf_log_buf_open(void) 273{ 274 struct nf_log_buf *m = kmalloc(sizeof(*m), GFP_ATOMIC); 275 276 if (unlikely(!m)) { 277 local_bh_disable(); 278 do { 279 m = xchg(&emergency_ptr, NULL); 280 } while (!m); 281 } 282 m->count = 0; 283 return m; 284} 285EXPORT_SYMBOL_GPL(nf_log_buf_open); 286 287void nf_log_buf_close(struct nf_log_buf *m) 288{ 289 m->buf[m->count] = 0; 290 printk("%s\n", m->buf); 291 292 if (likely(m != &emergency)) 293 kfree(m); 294 else { 295 emergency_ptr = m; 296 local_bh_enable(); 297 } 298} 299EXPORT_SYMBOL_GPL(nf_log_buf_close); 300 301#ifdef CONFIG_PROC_FS 302static void *seq_start(struct seq_file *seq, loff_t *pos) 303{ 304 struct net *net = seq_file_net(seq); 305 306 mutex_lock(&nf_log_mutex); 307 308 if (*pos >= ARRAY_SIZE(net->nf.nf_loggers)) 309 return NULL; 310 311 return pos; 312} 313 314static void *seq_next(struct seq_file *s, void *v, loff_t *pos) 315{ 316 struct net *net = seq_file_net(s); 317 318 (*pos)++; 319 320 if (*pos >= ARRAY_SIZE(net->nf.nf_loggers)) 321 return NULL; 322 323 return pos; 324} 325 326static void seq_stop(struct seq_file *s, void *v) 327{ 328 mutex_unlock(&nf_log_mutex); 329} 330 331static int seq_show(struct seq_file *s, void *v) 332{ 333 loff_t *pos = v; 334 const struct nf_logger *logger; 335 int i; 336 struct net *net = seq_file_net(s); 337 338 logger = nft_log_dereference(net->nf.nf_loggers[*pos]); 339 340 if (!logger) 341 seq_printf(s, "%2lld NONE (", *pos); 342 else 343 seq_printf(s, "%2lld %s (", *pos, logger->name); 344 345 if (seq_has_overflowed(s)) 346 return -ENOSPC; 347 348 for (i = 0; i < NF_LOG_TYPE_MAX; i++) { 349 if (loggers[*pos][i] == NULL) 350 continue; 351 352 logger = nft_log_dereference(loggers[*pos][i]); 353 seq_printf(s, "%s", logger->name); 354 if (i == 0 && loggers[*pos][i + 1] != NULL) 355 seq_printf(s, ","); 356 357 if (seq_has_overflowed(s)) 358 return -ENOSPC; 359 } 360 361 seq_printf(s, ")\n"); 362 363 if (seq_has_overflowed(s)) 364 return -ENOSPC; 365 return 0; 366} 367 368static const struct seq_operations nflog_seq_ops = { 369 .start = seq_start, 370 .next = seq_next, 371 .stop = seq_stop, 372 .show = seq_show, 373}; 374 375static int nflog_open(struct inode *inode, struct file *file) 376{ 377 return seq_open_net(inode, file, &nflog_seq_ops, 378 sizeof(struct seq_net_private)); 379} 380 381static const struct file_operations nflog_file_ops = { 382 .owner = THIS_MODULE, 383 .open = nflog_open, 384 .read = seq_read, 385 .llseek = seq_lseek, 386 .release = seq_release_net, 387}; 388 389 390#endif /* PROC_FS */ 391 392#ifdef CONFIG_SYSCTL 393static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3]; 394static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1]; 395 396static int nf_log_proc_dostring(struct ctl_table *table, int write, 397 void __user *buffer, size_t *lenp, loff_t *ppos) 398{ 399 const struct nf_logger *logger; 400 char buf[NFLOGGER_NAME_LEN]; 401 size_t size = *lenp; 402 int r = 0; 403 int tindex = (unsigned long)table->extra1; 404 struct net *net = current->nsproxy->net_ns; 405 406 if (write) { 407 if (size > sizeof(buf)) 408 size = sizeof(buf); 409 if (copy_from_user(buf, buffer, size)) 410 return -EFAULT; 411 412 if (!strcmp(buf, "NONE")) { 413 nf_log_unbind_pf(net, tindex); 414 return 0; 415 } 416 mutex_lock(&nf_log_mutex); 417 logger = __find_logger(tindex, buf); 418 if (logger == NULL) { 419 mutex_unlock(&nf_log_mutex); 420 return -ENOENT; 421 } 422 rcu_assign_pointer(net->nf.nf_loggers[tindex], logger); 423 mutex_unlock(&nf_log_mutex); 424 } else { 425 mutex_lock(&nf_log_mutex); 426 logger = nft_log_dereference(net->nf.nf_loggers[tindex]); 427 if (!logger) 428 table->data = "NONE"; 429 else 430 table->data = logger->name; 431 r = proc_dostring(table, write, buffer, lenp, ppos); 432 mutex_unlock(&nf_log_mutex); 433 } 434 435 return r; 436} 437 438static int netfilter_log_sysctl_init(struct net *net) 439{ 440 int i; 441 struct ctl_table *table; 442 443 table = nf_log_sysctl_table; 444 if (!net_eq(net, &init_net)) { 445 table = kmemdup(nf_log_sysctl_table, 446 sizeof(nf_log_sysctl_table), 447 GFP_KERNEL); 448 if (!table) 449 goto err_alloc; 450 } else { 451 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) { 452 snprintf(nf_log_sysctl_fnames[i], 453 3, "%d", i); 454 nf_log_sysctl_table[i].procname = 455 nf_log_sysctl_fnames[i]; 456 nf_log_sysctl_table[i].data = NULL; 457 nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN; 458 nf_log_sysctl_table[i].mode = 0644; 459 nf_log_sysctl_table[i].proc_handler = 460 nf_log_proc_dostring; 461 nf_log_sysctl_table[i].extra1 = 462 (void *)(unsigned long) i; 463 } 464 } 465 466 net->nf.nf_log_dir_header = register_net_sysctl(net, 467 "net/netfilter/nf_log", 468 table); 469 if (!net->nf.nf_log_dir_header) 470 goto err_reg; 471 472 return 0; 473 474err_reg: 475 if (!net_eq(net, &init_net)) 476 kfree(table); 477err_alloc: 478 return -ENOMEM; 479} 480 481static void netfilter_log_sysctl_exit(struct net *net) 482{ 483 struct ctl_table *table; 484 485 table = net->nf.nf_log_dir_header->ctl_table_arg; 486 unregister_net_sysctl_table(net->nf.nf_log_dir_header); 487 if (!net_eq(net, &init_net)) 488 kfree(table); 489} 490#else 491static int netfilter_log_sysctl_init(struct net *net) 492{ 493 return 0; 494} 495 496static void netfilter_log_sysctl_exit(struct net *net) 497{ 498} 499#endif /* CONFIG_SYSCTL */ 500 501static int __net_init nf_log_net_init(struct net *net) 502{ 503 int ret = -ENOMEM; 504 505#ifdef CONFIG_PROC_FS 506 if (!proc_create("nf_log", S_IRUGO, 507 net->nf.proc_netfilter, &nflog_file_ops)) 508 return ret; 509#endif 510 ret = netfilter_log_sysctl_init(net); 511 if (ret < 0) 512 goto out_sysctl; 513 514 return 0; 515 516out_sysctl: 517#ifdef CONFIG_PROC_FS 518 remove_proc_entry("nf_log", net->nf.proc_netfilter); 519#endif 520 return ret; 521} 522 523static void __net_exit nf_log_net_exit(struct net *net) 524{ 525 netfilter_log_sysctl_exit(net); 526#ifdef CONFIG_PROC_FS 527 remove_proc_entry("nf_log", net->nf.proc_netfilter); 528#endif 529} 530 531static struct pernet_operations nf_log_net_ops = { 532 .init = nf_log_net_init, 533 .exit = nf_log_net_exit, 534}; 535 536int __init netfilter_log_init(void) 537{ 538 return register_pernet_subsys(&nf_log_net_ops); 539} 540