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 const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO] __read_mostly;
  20static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly;
  21static DEFINE_MUTEX(nf_log_mutex);
  22
  23static struct nf_logger *__find_logger(int pf, const char *str_logger)
  24{
  25        struct nf_logger *t;
  26
  27        list_for_each_entry(t, &nf_loggers_l[pf], list[pf]) {
  28                if (!strnicmp(str_logger, t->name, strlen(t->name)))
  29                        return t;
  30        }
  31
  32        return NULL;
  33}
  34
  35/* return EEXIST if the same logger is registred, 0 on success. */
  36int nf_log_register(u_int8_t pf, struct nf_logger *logger)
  37{
  38        const struct nf_logger *llog;
  39        int i;
  40
  41        if (pf >= ARRAY_SIZE(nf_loggers))
  42                return -EINVAL;
  43
  44        for (i = 0; i < ARRAY_SIZE(logger->list); i++)
  45                INIT_LIST_HEAD(&logger->list[i]);
  46
  47        mutex_lock(&nf_log_mutex);
  48
  49        if (pf == NFPROTO_UNSPEC) {
  50                for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
  51                        list_add_tail(&(logger->list[i]), &(nf_loggers_l[i]));
  52        } else {
  53                /* register at end of list to honor first register win */
  54                list_add_tail(&logger->list[pf], &nf_loggers_l[pf]);
  55                llog = rcu_dereference_protected(nf_loggers[pf],
  56                                                 lockdep_is_held(&nf_log_mutex));
  57                if (llog == NULL)
  58                        rcu_assign_pointer(nf_loggers[pf], logger);
  59        }
  60
  61        mutex_unlock(&nf_log_mutex);
  62
  63        return 0;
  64}
  65EXPORT_SYMBOL(nf_log_register);
  66
  67void nf_log_unregister(struct nf_logger *logger)
  68{
  69        const struct nf_logger *c_logger;
  70        int i;
  71
  72        mutex_lock(&nf_log_mutex);
  73        for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) {
  74                c_logger = rcu_dereference_protected(nf_loggers[i],
  75                                                     lockdep_is_held(&nf_log_mutex));
  76                if (c_logger == logger)
  77                        RCU_INIT_POINTER(nf_loggers[i], NULL);
  78                list_del(&logger->list[i]);
  79        }
  80        mutex_unlock(&nf_log_mutex);
  81
  82        synchronize_rcu();
  83}
  84EXPORT_SYMBOL(nf_log_unregister);
  85
  86int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger)
  87{
  88        if (pf >= ARRAY_SIZE(nf_loggers))
  89                return -EINVAL;
  90        mutex_lock(&nf_log_mutex);
  91        if (__find_logger(pf, logger->name) == NULL) {
  92                mutex_unlock(&nf_log_mutex);
  93                return -ENOENT;
  94        }
  95        rcu_assign_pointer(nf_loggers[pf], logger);
  96        mutex_unlock(&nf_log_mutex);
  97        return 0;
  98}
  99EXPORT_SYMBOL(nf_log_bind_pf);
 100
 101void nf_log_unbind_pf(u_int8_t pf)
 102{
 103        if (pf >= ARRAY_SIZE(nf_loggers))
 104                return;
 105        mutex_lock(&nf_log_mutex);
 106        RCU_INIT_POINTER(nf_loggers[pf], NULL);
 107        mutex_unlock(&nf_log_mutex);
 108}
 109EXPORT_SYMBOL(nf_log_unbind_pf);
 110
 111void nf_log_packet(u_int8_t pf,
 112                   unsigned int hooknum,
 113                   const struct sk_buff *skb,
 114                   const struct net_device *in,
 115                   const struct net_device *out,
 116                   const struct nf_loginfo *loginfo,
 117                   const char *fmt, ...)
 118{
 119        va_list args;
 120        char prefix[NF_LOG_PREFIXLEN];
 121        const struct nf_logger *logger;
 122
 123        rcu_read_lock();
 124        logger = rcu_dereference(nf_loggers[pf]);
 125        if (logger) {
 126                va_start(args, fmt);
 127                vsnprintf(prefix, sizeof(prefix), fmt, args);
 128                va_end(args);
 129                logger->logfn(pf, hooknum, skb, in, out, loginfo, prefix);
 130        }
 131        rcu_read_unlock();
 132}
 133EXPORT_SYMBOL(nf_log_packet);
 134
 135#ifdef CONFIG_PROC_FS
 136static void *seq_start(struct seq_file *seq, loff_t *pos)
 137{
 138        mutex_lock(&nf_log_mutex);
 139
 140        if (*pos >= ARRAY_SIZE(nf_loggers))
 141                return NULL;
 142
 143        return pos;
 144}
 145
 146static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
 147{
 148        (*pos)++;
 149
 150        if (*pos >= ARRAY_SIZE(nf_loggers))
 151                return NULL;
 152
 153        return pos;
 154}
 155
 156static void seq_stop(struct seq_file *s, void *v)
 157{
 158        mutex_unlock(&nf_log_mutex);
 159}
 160
 161static int seq_show(struct seq_file *s, void *v)
 162{
 163        loff_t *pos = v;
 164        const struct nf_logger *logger;
 165        struct nf_logger *t;
 166        int ret;
 167
 168        logger = rcu_dereference_protected(nf_loggers[*pos],
 169                                           lockdep_is_held(&nf_log_mutex));
 170
 171        if (!logger)
 172                ret = seq_printf(s, "%2lld NONE (", *pos);
 173        else
 174                ret = seq_printf(s, "%2lld %s (", *pos, logger->name);
 175
 176        if (ret < 0)
 177                return ret;
 178
 179        list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) {
 180                ret = seq_printf(s, "%s", t->name);
 181                if (ret < 0)
 182                        return ret;
 183                if (&t->list[*pos] != nf_loggers_l[*pos].prev) {
 184                        ret = seq_printf(s, ",");
 185                        if (ret < 0)
 186                                return ret;
 187                }
 188        }
 189
 190        return seq_printf(s, ")\n");
 191}
 192
 193static const struct seq_operations nflog_seq_ops = {
 194        .start  = seq_start,
 195        .next   = seq_next,
 196        .stop   = seq_stop,
 197        .show   = seq_show,
 198};
 199
 200static int nflog_open(struct inode *inode, struct file *file)
 201{
 202        return seq_open(file, &nflog_seq_ops);
 203}
 204
 205static const struct file_operations nflog_file_ops = {
 206        .owner   = THIS_MODULE,
 207        .open    = nflog_open,
 208        .read    = seq_read,
 209        .llseek  = seq_lseek,
 210        .release = seq_release,
 211};
 212
 213
 214#endif /* PROC_FS */
 215
 216#ifdef CONFIG_SYSCTL
 217static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
 218static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
 219static struct ctl_table_header *nf_log_dir_header;
 220
 221static int nf_log_proc_dostring(ctl_table *table, int write,
 222                         void __user *buffer, size_t *lenp, loff_t *ppos)
 223{
 224        const struct nf_logger *logger;
 225        char buf[NFLOGGER_NAME_LEN];
 226        size_t size = *lenp;
 227        int r = 0;
 228        int tindex = (unsigned long)table->extra1;
 229
 230        if (write) {
 231                if (size > sizeof(buf))
 232                        size = sizeof(buf);
 233                if (copy_from_user(buf, buffer, size))
 234                        return -EFAULT;
 235
 236                if (!strcmp(buf, "NONE")) {
 237                        nf_log_unbind_pf(tindex);
 238                        return 0;
 239                }
 240                mutex_lock(&nf_log_mutex);
 241                logger = __find_logger(tindex, buf);
 242                if (logger == NULL) {
 243                        mutex_unlock(&nf_log_mutex);
 244                        return -ENOENT;
 245                }
 246                rcu_assign_pointer(nf_loggers[tindex], logger);
 247                mutex_unlock(&nf_log_mutex);
 248        } else {
 249                mutex_lock(&nf_log_mutex);
 250                logger = rcu_dereference_protected(nf_loggers[tindex],
 251                                                   lockdep_is_held(&nf_log_mutex));
 252                if (!logger)
 253                        table->data = "NONE";
 254                else
 255                        table->data = logger->name;
 256                r = proc_dostring(table, write, buffer, lenp, ppos);
 257                mutex_unlock(&nf_log_mutex);
 258        }
 259
 260        return r;
 261}
 262
 263static __init int netfilter_log_sysctl_init(void)
 264{
 265        int i;
 266
 267        for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
 268                snprintf(nf_log_sysctl_fnames[i-NFPROTO_UNSPEC], 3, "%d", i);
 269                nf_log_sysctl_table[i].procname =
 270                        nf_log_sysctl_fnames[i-NFPROTO_UNSPEC];
 271                nf_log_sysctl_table[i].data = NULL;
 272                nf_log_sysctl_table[i].maxlen =
 273                        NFLOGGER_NAME_LEN * sizeof(char);
 274                nf_log_sysctl_table[i].mode = 0644;
 275                nf_log_sysctl_table[i].proc_handler = nf_log_proc_dostring;
 276                nf_log_sysctl_table[i].extra1 = (void *)(unsigned long) i;
 277        }
 278
 279        nf_log_dir_header = register_net_sysctl(&init_net, "net/netfilter/nf_log",
 280                                       nf_log_sysctl_table);
 281        if (!nf_log_dir_header)
 282                return -ENOMEM;
 283
 284        return 0;
 285}
 286#else
 287static __init int netfilter_log_sysctl_init(void)
 288{
 289        return 0;
 290}
 291#endif /* CONFIG_SYSCTL */
 292
 293int __init netfilter_log_init(void)
 294{
 295        int i, r;
 296#ifdef CONFIG_PROC_FS
 297        if (!proc_create("nf_log", S_IRUGO,
 298                         proc_net_netfilter, &nflog_file_ops))
 299                return -1;
 300#endif
 301
 302        /* Errors will trigger panic, unroll on error is unnecessary. */
 303        r = netfilter_log_sysctl_init();
 304        if (r < 0)
 305                return r;
 306
 307        for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
 308                INIT_LIST_HEAD(&(nf_loggers_l[i]));
 309
 310        return 0;
 311}
 312