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