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