root/net/netfilter/nf_log.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __find_logger
  2. nf_log_set
  3. nf_log_unset
  4. nf_log_register
  5. nf_log_unregister
  6. nf_log_bind_pf
  7. nf_log_unbind_pf
  8. nf_logger_request_module
  9. nf_logger_find_get
  10. nf_logger_put
  11. nf_log_packet
  12. nf_log_trace
  13. __printf
  14. nf_log_buf_open
  15. nf_log_buf_close
  16. seq_start
  17. seq_next
  18. seq_stop
  19. seq_show
  20. nf_log_proc_dostring
  21. netfilter_log_sysctl_init
  22. netfilter_log_sysctl_exit
  23. netfilter_log_sysctl_init
  24. netfilter_log_sysctl_exit
  25. nf_log_net_init
  26. nf_log_net_exit
  27. netfilter_log_init

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

/* [<][>][^][v][top][bottom][index][help] */