LCOV - code coverage report
Current view: top level - net/netfilter - nf_log.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 26 137 19.0 %
Date: 2014-04-07 Functions: 6 18 33.3 %
Branches: 9 70 12.9 %

           Branch data     Line data    Source code
       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                 :            : 
      19                 :            : static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly;
      20                 :            : static DEFINE_MUTEX(nf_log_mutex);
      21                 :            : 
      22                 :          0 : static struct nf_logger *__find_logger(int pf, const char *str_logger)
      23                 :            : {
      24                 :            :         struct nf_logger *t;
      25                 :            : 
      26         [ #  # ]:          0 :         list_for_each_entry(t, &nf_loggers_l[pf], list[pf]) {
      27         [ #  # ]:          0 :                 if (!strnicmp(str_logger, t->name, strlen(t->name)))
      28                 :            :                         return t;
      29                 :            :         }
      30                 :            : 
      31                 :            :         return NULL;
      32                 :            : }
      33                 :            : 
      34                 :          0 : void nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger)
      35                 :            : {
      36                 :            :         const struct nf_logger *log;
      37                 :            : 
      38         [ #  # ]:          0 :         if (pf == NFPROTO_UNSPEC)
      39                 :          0 :                 return;
      40                 :            : 
      41                 :          0 :         mutex_lock(&nf_log_mutex);
      42                 :          0 :         log = rcu_dereference_protected(net->nf.nf_loggers[pf],
      43                 :            :                                         lockdep_is_held(&nf_log_mutex));
      44         [ #  # ]:          0 :         if (log == NULL)
      45                 :          0 :                 rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
      46                 :            : 
      47                 :          0 :         mutex_unlock(&nf_log_mutex);
      48                 :            : }
      49                 :            : EXPORT_SYMBOL(nf_log_set);
      50                 :            : 
      51                 :          0 : void nf_log_unset(struct net *net, const struct nf_logger *logger)
      52                 :            : {
      53                 :            :         int i;
      54                 :            :         const struct nf_logger *log;
      55                 :            : 
      56                 :          0 :         mutex_lock(&nf_log_mutex);
      57         [ #  # ]:          0 :         for (i = 0; i < NFPROTO_NUMPROTO; i++) {
      58                 :          0 :                 log = rcu_dereference_protected(net->nf.nf_loggers[i],
      59                 :            :                                 lockdep_is_held(&nf_log_mutex));
      60         [ #  # ]:          0 :                 if (log == logger)
      61                 :          0 :                         RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL);
      62                 :            :         }
      63                 :          0 :         mutex_unlock(&nf_log_mutex);
      64                 :            :         synchronize_rcu();
      65                 :          0 : }
      66                 :            : EXPORT_SYMBOL(nf_log_unset);
      67                 :            : 
      68                 :            : /* return EEXIST if the same logger is registered, 0 on success. */
      69                 :          0 : int nf_log_register(u_int8_t pf, struct nf_logger *logger)
      70                 :            : {
      71                 :            :         int i;
      72                 :            : 
      73         [ #  # ]:          0 :         if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers))
      74                 :            :                 return -EINVAL;
      75                 :            : 
      76         [ #  # ]:          0 :         for (i = 0; i < ARRAY_SIZE(logger->list); i++)
      77                 :          0 :                 INIT_LIST_HEAD(&logger->list[i]);
      78                 :            : 
      79                 :          0 :         mutex_lock(&nf_log_mutex);
      80                 :            : 
      81         [ #  # ]:          0 :         if (pf == NFPROTO_UNSPEC) {
      82         [ #  # ]:          0 :                 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
      83                 :          0 :                         list_add_tail(&(logger->list[i]), &(nf_loggers_l[i]));
      84                 :            :         } else {
      85                 :            :                 /* register at end of list to honor first register win */
      86                 :          0 :                 list_add_tail(&logger->list[pf], &nf_loggers_l[pf]);
      87                 :            :         }
      88                 :            : 
      89                 :          0 :         mutex_unlock(&nf_log_mutex);
      90                 :            : 
      91                 :          0 :         return 0;
      92                 :            : }
      93                 :            : EXPORT_SYMBOL(nf_log_register);
      94                 :            : 
      95                 :          0 : void nf_log_unregister(struct nf_logger *logger)
      96                 :            : {
      97                 :            :         int i;
      98                 :            : 
      99                 :          0 :         mutex_lock(&nf_log_mutex);
     100         [ #  # ]:          0 :         for (i = 0; i < NFPROTO_NUMPROTO; i++)
     101                 :          0 :                 list_del(&logger->list[i]);
     102                 :          0 :         mutex_unlock(&nf_log_mutex);
     103                 :          0 : }
     104                 :            : EXPORT_SYMBOL(nf_log_unregister);
     105                 :            : 
     106                 :          0 : int nf_log_bind_pf(struct net *net, u_int8_t pf,
     107                 :            :                    const struct nf_logger *logger)
     108                 :            : {
     109         [ #  # ]:          0 :         if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
     110                 :            :                 return -EINVAL;
     111                 :          0 :         mutex_lock(&nf_log_mutex);
     112         [ #  # ]:          0 :         if (__find_logger(pf, logger->name) == NULL) {
     113                 :          0 :                 mutex_unlock(&nf_log_mutex);
     114                 :          0 :                 return -ENOENT;
     115                 :            :         }
     116                 :          0 :         rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
     117                 :          0 :         mutex_unlock(&nf_log_mutex);
     118                 :          0 :         return 0;
     119                 :            : }
     120                 :            : EXPORT_SYMBOL(nf_log_bind_pf);
     121                 :            : 
     122                 :          0 : void nf_log_unbind_pf(struct net *net, u_int8_t pf)
     123                 :            : {
     124         [ #  # ]:          0 :         if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
     125                 :          0 :                 return;
     126                 :          0 :         mutex_lock(&nf_log_mutex);
     127                 :          0 :         RCU_INIT_POINTER(net->nf.nf_loggers[pf], NULL);
     128                 :          0 :         mutex_unlock(&nf_log_mutex);
     129                 :            : }
     130                 :            : EXPORT_SYMBOL(nf_log_unbind_pf);
     131                 :            : 
     132                 :          0 : void nf_log_packet(struct net *net,
     133                 :            :                    u_int8_t pf,
     134                 :            :                    unsigned int hooknum,
     135                 :            :                    const struct sk_buff *skb,
     136                 :            :                    const struct net_device *in,
     137                 :            :                    const struct net_device *out,
     138                 :            :                    const struct nf_loginfo *loginfo,
     139                 :            :                    const char *fmt, ...)
     140                 :            : {
     141                 :            :         va_list args;
     142                 :            :         char prefix[NF_LOG_PREFIXLEN];
     143                 :            :         const struct nf_logger *logger;
     144                 :            : 
     145                 :            :         rcu_read_lock();
     146                 :          0 :         logger = rcu_dereference(net->nf.nf_loggers[pf]);
     147         [ #  # ]:          0 :         if (logger) {
     148                 :          0 :                 va_start(args, fmt);
     149                 :          0 :                 vsnprintf(prefix, sizeof(prefix), fmt, args);
     150                 :          0 :                 va_end(args);
     151                 :          0 :                 logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
     152                 :            :         }
     153                 :            :         rcu_read_unlock();
     154                 :          0 : }
     155                 :            : EXPORT_SYMBOL(nf_log_packet);
     156                 :            : 
     157                 :            : #ifdef CONFIG_PROC_FS
     158                 :          0 : static void *seq_start(struct seq_file *seq, loff_t *pos)
     159                 :            : {
     160                 :            :         struct net *net = seq_file_net(seq);
     161                 :            : 
     162                 :          2 :         mutex_lock(&nf_log_mutex);
     163                 :            : 
     164         [ +  + ]:          2 :         if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
     165                 :            :                 return NULL;
     166                 :            : 
     167                 :          1 :         return pos;
     168                 :            : }
     169                 :            : 
     170                 :          0 : static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
     171                 :            : {
     172                 :            :         struct net *net = seq_file_net(s);
     173                 :            : 
     174                 :         13 :         (*pos)++;
     175                 :            : 
     176         [ +  + ]:         13 :         if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
     177                 :            :                 return NULL;
     178                 :            : 
     179                 :         12 :         return pos;
     180                 :            : }
     181                 :            : 
     182                 :          0 : static void seq_stop(struct seq_file *s, void *v)
     183                 :            : {
     184                 :          2 :         mutex_unlock(&nf_log_mutex);
     185                 :          2 : }
     186                 :            : 
     187                 :          0 : static int seq_show(struct seq_file *s, void *v)
     188                 :            : {
     189                 :            :         loff_t *pos = v;
     190                 :            :         const struct nf_logger *logger;
     191                 :            :         struct nf_logger *t;
     192                 :            :         int ret;
     193                 :            :         struct net *net = seq_file_net(s);
     194                 :            : 
     195                 :         13 :         logger = rcu_dereference_protected(net->nf.nf_loggers[*pos],
     196                 :            :                                            lockdep_is_held(&nf_log_mutex));
     197                 :            : 
     198         [ +  - ]:         13 :         if (!logger)
     199                 :         13 :                 ret = seq_printf(s, "%2lld NONE (", *pos);
     200                 :            :         else
     201                 :          0 :                 ret = seq_printf(s, "%2lld %s (", *pos, logger->name);
     202                 :            : 
     203         [ +  - ]:         26 :         if (ret < 0)
     204                 :            :                 return ret;
     205                 :            : 
     206         [ -  + ]:         13 :         list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) {
     207                 :          0 :                 ret = seq_printf(s, "%s", t->name);
     208         [ #  # ]:          0 :                 if (ret < 0)
     209                 :            :                         return ret;
     210         [ #  # ]:          0 :                 if (&t->list[*pos] != nf_loggers_l[*pos].prev) {
     211                 :          0 :                         ret = seq_printf(s, ",");
     212         [ #  # ]:          0 :                         if (ret < 0)
     213                 :            :                                 return ret;
     214                 :            :                 }
     215                 :            :         }
     216                 :            : 
     217                 :         13 :         return seq_printf(s, ")\n");
     218                 :            : }
     219                 :            : 
     220                 :            : static const struct seq_operations nflog_seq_ops = {
     221                 :            :         .start  = seq_start,
     222                 :            :         .next   = seq_next,
     223                 :            :         .stop   = seq_stop,
     224                 :            :         .show   = seq_show,
     225                 :            : };
     226                 :            : 
     227                 :          0 : static int nflog_open(struct inode *inode, struct file *file)
     228                 :            : {
     229                 :          1 :         return seq_open_net(inode, file, &nflog_seq_ops,
     230                 :            :                             sizeof(struct seq_net_private));
     231                 :            : }
     232                 :            : 
     233                 :            : static const struct file_operations nflog_file_ops = {
     234                 :            :         .owner   = THIS_MODULE,
     235                 :            :         .open    = nflog_open,
     236                 :            :         .read    = seq_read,
     237                 :            :         .llseek  = seq_lseek,
     238                 :            :         .release = seq_release_net,
     239                 :            : };
     240                 :            : 
     241                 :            : 
     242                 :            : #endif /* PROC_FS */
     243                 :            : 
     244                 :            : #ifdef CONFIG_SYSCTL
     245                 :            : static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
     246                 :            : static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
     247                 :            : 
     248                 :          0 : static int nf_log_proc_dostring(struct ctl_table *table, int write,
     249                 :            :                          void __user *buffer, size_t *lenp, loff_t *ppos)
     250                 :            : {
     251                 :            :         const struct nf_logger *logger;
     252                 :            :         char buf[NFLOGGER_NAME_LEN];
     253                 :         26 :         size_t size = *lenp;
     254                 :            :         int r = 0;
     255                 :         26 :         int tindex = (unsigned long)table->extra1;
     256                 :         26 :         struct net *net = current->nsproxy->net_ns;
     257                 :            : 
     258         [ -  + ]:         26 :         if (write) {
     259         [ #  # ]:          0 :                 if (size > sizeof(buf))
     260                 :            :                         size = sizeof(buf);
     261         [ #  # ]:          0 :                 if (copy_from_user(buf, buffer, size))
     262                 :            :                         return -EFAULT;
     263                 :            : 
     264         [ #  # ]:          0 :                 if (!strcmp(buf, "NONE")) {
     265                 :          0 :                         nf_log_unbind_pf(net, tindex);
     266                 :          0 :                         return 0;
     267                 :            :                 }
     268                 :          0 :                 mutex_lock(&nf_log_mutex);
     269                 :          0 :                 logger = __find_logger(tindex, buf);
     270         [ #  # ]:          0 :                 if (logger == NULL) {
     271                 :          0 :                         mutex_unlock(&nf_log_mutex);
     272                 :          0 :                         return -ENOENT;
     273                 :            :                 }
     274                 :          0 :                 rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
     275                 :          0 :                 mutex_unlock(&nf_log_mutex);
     276                 :            :         } else {
     277                 :         26 :                 mutex_lock(&nf_log_mutex);
     278                 :         26 :                 logger = rcu_dereference_protected(net->nf.nf_loggers[tindex],
     279                 :            :                                                    lockdep_is_held(&nf_log_mutex));
     280         [ +  - ]:         52 :                 if (!logger)
     281                 :         26 :                         table->data = "NONE";
     282                 :            :                 else
     283                 :          0 :                         table->data = logger->name;
     284                 :         26 :                 r = proc_dostring(table, write, buffer, lenp, ppos);
     285                 :         26 :                 mutex_unlock(&nf_log_mutex);
     286                 :            :         }
     287                 :            : 
     288                 :         26 :         return r;
     289                 :            : }
     290                 :            : 
     291                 :          0 : static int netfilter_log_sysctl_init(struct net *net)
     292                 :            : {
     293                 :            :         int i;
     294                 :            :         struct ctl_table *table;
     295                 :            : 
     296                 :            :         table = nf_log_sysctl_table;
     297                 :            :         if (!net_eq(net, &init_net)) {
     298                 :            :                 table = kmemdup(nf_log_sysctl_table,
     299                 :            :                                  sizeof(nf_log_sysctl_table),
     300                 :            :                                  GFP_KERNEL);
     301                 :            :                 if (!table)
     302                 :            :                         goto err_alloc;
     303                 :            :         } else {
     304         [ #  # ]:          0 :                 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
     305                 :          0 :                         snprintf(nf_log_sysctl_fnames[i],
     306                 :            :                                  3, "%d", i);
     307                 :          0 :                         nf_log_sysctl_table[i].procname =
     308                 :            :                                 nf_log_sysctl_fnames[i];
     309                 :          0 :                         nf_log_sysctl_table[i].data = NULL;
     310                 :          0 :                         nf_log_sysctl_table[i].maxlen =
     311                 :            :                                 NFLOGGER_NAME_LEN * sizeof(char);
     312                 :          0 :                         nf_log_sysctl_table[i].mode = 0644;
     313                 :          0 :                         nf_log_sysctl_table[i].proc_handler =
     314                 :            :                                 nf_log_proc_dostring;
     315                 :          0 :                         nf_log_sysctl_table[i].extra1 =
     316                 :          0 :                                 (void *)(unsigned long) i;
     317                 :            :                 }
     318                 :            :         }
     319                 :            : 
     320                 :          0 :         net->nf.nf_log_dir_header = register_net_sysctl(net,
     321                 :            :                                                 "net/netfilter/nf_log",
     322                 :            :                                                 table);
     323         [ #  # ]:          0 :         if (!net->nf.nf_log_dir_header)
     324                 :            :                 goto err_reg;
     325                 :            : 
     326                 :            :         return 0;
     327                 :            : 
     328                 :            : err_reg:
     329                 :            :         if (!net_eq(net, &init_net))
     330                 :            :                 kfree(table);
     331                 :            : err_alloc:
     332                 :            :         return -ENOMEM;
     333                 :            : }
     334                 :            : 
     335                 :            : static void netfilter_log_sysctl_exit(struct net *net)
     336                 :            : {
     337                 :            :         struct ctl_table *table;
     338                 :            : 
     339                 :            :         table = net->nf.nf_log_dir_header->ctl_table_arg;
     340                 :          0 :         unregister_net_sysctl_table(net->nf.nf_log_dir_header);
     341                 :            :         if (!net_eq(net, &init_net))
     342                 :            :                 kfree(table);
     343                 :            : }
     344                 :            : #else
     345                 :            : static int netfilter_log_sysctl_init(struct net *net)
     346                 :            : {
     347                 :            :         return 0;
     348                 :            : }
     349                 :            : 
     350                 :            : static void netfilter_log_sysctl_exit(struct net *net)
     351                 :            : {
     352                 :            : }
     353                 :            : #endif /* CONFIG_SYSCTL */
     354                 :            : 
     355                 :          0 : static int __net_init nf_log_net_init(struct net *net)
     356                 :            : {
     357                 :            :         int ret = -ENOMEM;
     358                 :            : 
     359                 :            : #ifdef CONFIG_PROC_FS
     360         [ #  # ]:          0 :         if (!proc_create("nf_log", S_IRUGO,
     361                 :            :                          net->nf.proc_netfilter, &nflog_file_ops))
     362                 :            :                 return ret;
     363                 :            : #endif
     364                 :          0 :         ret = netfilter_log_sysctl_init(net);
     365         [ #  # ]:          0 :         if (ret < 0)
     366                 :            :                 goto out_sysctl;
     367                 :            : 
     368                 :            :         return 0;
     369                 :            : 
     370                 :            : out_sysctl:
     371                 :            : #ifdef CONFIG_PROC_FS
     372                 :          0 :         remove_proc_entry("nf_log", net->nf.proc_netfilter);
     373                 :            : #endif
     374                 :          0 :         return ret;
     375                 :            : }
     376                 :            : 
     377                 :          0 : static void __net_exit nf_log_net_exit(struct net *net)
     378                 :            : {
     379                 :            :         netfilter_log_sysctl_exit(net);
     380                 :            : #ifdef CONFIG_PROC_FS
     381                 :          0 :         remove_proc_entry("nf_log", net->nf.proc_netfilter);
     382                 :            : #endif
     383                 :          0 : }
     384                 :            : 
     385                 :            : static struct pernet_operations nf_log_net_ops = {
     386                 :            :         .init = nf_log_net_init,
     387                 :            :         .exit = nf_log_net_exit,
     388                 :            : };
     389                 :            : 
     390                 :          0 : int __init netfilter_log_init(void)
     391                 :            : {
     392                 :            :         int i, ret;
     393                 :            : 
     394                 :          0 :         ret = register_pernet_subsys(&nf_log_net_ops);
     395         [ #  # ]:          0 :         if (ret < 0)
     396                 :            :                 return ret;
     397                 :            : 
     398         [ #  # ]:          0 :         for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
     399                 :          0 :                 INIT_LIST_HEAD(&(nf_loggers_l[i]));
     400                 :            : 
     401                 :            :         return 0;
     402                 :            : }

Generated by: LCOV version 1.9