linux/net/netfilter/nf_log.c
<<
>>
Prefs
   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
  18int sysctl_nf_log_all_netns __read_mostly;
  19EXPORT_SYMBOL(sysctl_nf_log_all_netns);
  20
  21static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly;
  22static DEFINE_MUTEX(nf_log_mutex);
  23
  24#define nft_log_dereference(logger) \
  25        rcu_dereference_protected(logger, lockdep_is_held(&nf_log_mutex))
  26
  27static 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
  44int 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}
  60EXPORT_SYMBOL(nf_log_set);
  61
  62void 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}
  75EXPORT_SYMBOL(nf_log_unset);
  76
  77/* return EEXIST if the same logger is registered, 0 on success. */
  78int 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
 105unlock:
 106        mutex_unlock(&nf_log_mutex);
 107        return ret;
 108}
 109EXPORT_SYMBOL(nf_log_register);
 110
 111void 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}
 125EXPORT_SYMBOL(nf_log_unregister);
 126
 127int 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}
 141EXPORT_SYMBOL(nf_log_bind_pf);
 142
 143void 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}
 151EXPORT_SYMBOL(nf_log_unbind_pf);
 152
 153void 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}
 158EXPORT_SYMBOL_GPL(nf_logger_request_module);
 159
 160int 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;
 189out:
 190        rcu_read_unlock();
 191        return ret;
 192}
 193EXPORT_SYMBOL_GPL(nf_logger_find_get);
 194
 195void 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}
 212EXPORT_SYMBOL_GPL(nf_logger_put);
 213
 214void 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}
 241EXPORT_SYMBOL(nf_log_packet);
 242
 243void 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}
 265EXPORT_SYMBOL(nf_log_trace);
 266
 267#define S_SIZE (1024 - (sizeof(unsigned int) + 1))
 268
 269struct nf_log_buf {
 270        unsigned int    count;
 271        char            buf[S_SIZE + 1];
 272};
 273static 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}
 293EXPORT_SYMBOL_GPL(nf_log_buf_add);
 294
 295struct 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}
 308EXPORT_SYMBOL_GPL(nf_log_buf_open);
 309
 310void 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}
 322EXPORT_SYMBOL_GPL(nf_log_buf_close);
 323
 324#ifdef CONFIG_PROC_FS
 325static 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
 337static 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
 349static void seq_stop(struct seq_file *s, void *v)
 350{
 351        mutex_unlock(&nf_log_mutex);
 352}
 353
 354static 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
 391static 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
 398static int nflog_open(struct inode *inode, struct file *file)
 399{
 400        return seq_open_net(inode, file, &nflog_seq_ops,
 401                            sizeof(struct seq_net_private));
 402}
 403
 404static const struct file_operations nflog_file_ops = {
 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];
 417static struct ctl_table_header *nf_log_sysctl_fhdr;
 418
 419static struct ctl_table nf_log_sysctl_ftable[] = {
 420        {
 421                .procname       = "nf_log_all_netns",
 422                .data           = &sysctl_nf_log_all_netns,
 423                .maxlen         = sizeof(sysctl_nf_log_all_netns),
 424                .mode           = 0644,
 425                .proc_handler   = proc_dointvec,
 426        },
 427        { }
 428};
 429
 430static int nf_log_proc_dostring(struct ctl_table *table, int write,
 431                         void __user *buffer, size_t *lenp, loff_t *ppos)
 432{
 433        const struct nf_logger *logger;
 434        char buf[NFLOGGER_NAME_LEN];
 435        int r = 0;
 436        int tindex = (unsigned long)table->extra1;
 437        struct net *net = table->extra2;
 438
 439        if (write) {
 440                struct ctl_table tmp = *table;
 441
 442                tmp.data = buf;
 443                r = proc_dostring(&tmp, write, buffer, lenp, ppos);
 444                if (r)
 445                        return r;
 446
 447                if (!strcmp(buf, "NONE")) {
 448                        nf_log_unbind_pf(net, tindex);
 449                        return 0;
 450                }
 451                mutex_lock(&nf_log_mutex);
 452                logger = __find_logger(tindex, buf);
 453                if (logger == NULL) {
 454                        mutex_unlock(&nf_log_mutex);
 455                        return -ENOENT;
 456                }
 457                rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
 458                mutex_unlock(&nf_log_mutex);
 459        } else {
 460                mutex_lock(&nf_log_mutex);
 461                logger = nft_log_dereference(net->nf.nf_loggers[tindex]);
 462                if (!logger)
 463                        table->data = "NONE";
 464                else
 465                        table->data = logger->name;
 466                r = proc_dostring(table, write, buffer, lenp, ppos);
 467                mutex_unlock(&nf_log_mutex);
 468        }
 469
 470        return r;
 471}
 472
 473static int netfilter_log_sysctl_init(struct net *net)
 474{
 475        int i;
 476        struct ctl_table *table;
 477
 478        table = nf_log_sysctl_table;
 479        if (!net_eq(net, &init_net)) {
 480                table = kmemdup(nf_log_sysctl_table,
 481                                 sizeof(nf_log_sysctl_table),
 482                                 GFP_KERNEL);
 483                if (!table)
 484                        goto err_alloc;
 485        } else {
 486                for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
 487                        snprintf(nf_log_sysctl_fnames[i],
 488                                 3, "%d", i);
 489                        nf_log_sysctl_table[i].procname =
 490                                nf_log_sysctl_fnames[i];
 491                        nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN;
 492                        nf_log_sysctl_table[i].mode = 0644;
 493                        nf_log_sysctl_table[i].proc_handler =
 494                                nf_log_proc_dostring;
 495                        nf_log_sysctl_table[i].extra1 =
 496                                (void *)(unsigned long) i;
 497                }
 498                nf_log_sysctl_fhdr = register_net_sysctl(net, "net/netfilter",
 499                                                         nf_log_sysctl_ftable);
 500                if (!nf_log_sysctl_fhdr)
 501                        goto err_freg;
 502        }
 503
 504        for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
 505                table[i].extra2 = net;
 506
 507        net->nf.nf_log_dir_header = register_net_sysctl(net,
 508                                                "net/netfilter/nf_log",
 509                                                table);
 510        if (!net->nf.nf_log_dir_header)
 511                goto err_reg;
 512
 513        return 0;
 514
 515err_reg:
 516        if (!net_eq(net, &init_net))
 517                kfree(table);
 518        else
 519                unregister_net_sysctl_table(nf_log_sysctl_fhdr);
 520err_freg:
 521err_alloc:
 522        return -ENOMEM;
 523}
 524
 525static void netfilter_log_sysctl_exit(struct net *net)
 526{
 527        struct ctl_table *table;
 528
 529        table = net->nf.nf_log_dir_header->ctl_table_arg;
 530        unregister_net_sysctl_table(net->nf.nf_log_dir_header);
 531        if (!net_eq(net, &init_net))
 532                kfree(table);
 533        else
 534                unregister_net_sysctl_table(nf_log_sysctl_fhdr);
 535}
 536#else
 537static int netfilter_log_sysctl_init(struct net *net)
 538{
 539        return 0;
 540}
 541
 542static void netfilter_log_sysctl_exit(struct net *net)
 543{
 544}
 545#endif /* CONFIG_SYSCTL */
 546
 547static int __net_init nf_log_net_init(struct net *net)
 548{
 549        int ret = -ENOMEM;
 550
 551#ifdef CONFIG_PROC_FS
 552        if (!proc_create("nf_log", S_IRUGO,
 553                         net->nf.proc_netfilter, &nflog_file_ops))
 554                return ret;
 555#endif
 556        ret = netfilter_log_sysctl_init(net);
 557        if (ret < 0)
 558                goto out_sysctl;
 559
 560        return 0;
 561
 562out_sysctl:
 563#ifdef CONFIG_PROC_FS
 564        remove_proc_entry("nf_log", net->nf.proc_netfilter);
 565#endif
 566        return ret;
 567}
 568
 569static void __net_exit nf_log_net_exit(struct net *net)
 570{
 571        netfilter_log_sysctl_exit(net);
 572#ifdef CONFIG_PROC_FS
 573        remove_proc_entry("nf_log", net->nf.proc_netfilter);
 574#endif
 575}
 576
 577static struct pernet_operations nf_log_net_ops = {
 578        .init = nf_log_net_init,
 579        .exit = nf_log_net_exit,
 580};
 581
 582int __init netfilter_log_init(void)
 583{
 584        return register_pernet_subsys(&nf_log_net_ops);
 585}
 586