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