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