Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 #include <linux/kernel.h>
0003 #include <linux/init.h>
0004 #include <linux/module.h>
0005 #include <linux/proc_fs.h>
0006 #include <linux/skbuff.h>
0007 #include <linux/netfilter.h>
0008 #include <linux/seq_file.h>
0009 #include <net/protocol.h>
0010 #include <net/netfilter/nf_log.h>
0011 
0012 #include "nf_internals.h"
0013 
0014 /* Internal logging interface, which relies on the real
0015    LOG target modules */
0016 
0017 #define NFLOGGER_NAME_LEN       64
0018 
0019 int sysctl_nf_log_all_netns __read_mostly;
0020 EXPORT_SYMBOL(sysctl_nf_log_all_netns);
0021 
0022 static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly;
0023 static DEFINE_MUTEX(nf_log_mutex);
0024 
0025 #define nft_log_dereference(logger) \
0026     rcu_dereference_protected(logger, lockdep_is_held(&nf_log_mutex))
0027 
0028 static struct nf_logger *__find_logger(int pf, const char *str_logger)
0029 {
0030     struct nf_logger *log;
0031     int i;
0032 
0033     for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
0034         if (loggers[pf][i] == NULL)
0035             continue;
0036 
0037         log = nft_log_dereference(loggers[pf][i]);
0038         if (!strncasecmp(str_logger, log->name, strlen(log->name)))
0039             return log;
0040     }
0041 
0042     return NULL;
0043 }
0044 
0045 int nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger)
0046 {
0047     const struct nf_logger *log;
0048 
0049     if (pf == NFPROTO_UNSPEC || pf >= ARRAY_SIZE(net->nf.nf_loggers))
0050         return -EOPNOTSUPP;
0051 
0052     mutex_lock(&nf_log_mutex);
0053     log = nft_log_dereference(net->nf.nf_loggers[pf]);
0054     if (log == NULL)
0055         rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
0056 
0057     mutex_unlock(&nf_log_mutex);
0058 
0059     return 0;
0060 }
0061 EXPORT_SYMBOL(nf_log_set);
0062 
0063 void nf_log_unset(struct net *net, const struct nf_logger *logger)
0064 {
0065     int i;
0066     const struct nf_logger *log;
0067 
0068     mutex_lock(&nf_log_mutex);
0069     for (i = 0; i < NFPROTO_NUMPROTO; i++) {
0070         log = nft_log_dereference(net->nf.nf_loggers[i]);
0071         if (log == logger)
0072             RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL);
0073     }
0074     mutex_unlock(&nf_log_mutex);
0075 }
0076 EXPORT_SYMBOL(nf_log_unset);
0077 
0078 /* return EEXIST if the same logger is registered, 0 on success. */
0079 int nf_log_register(u_int8_t pf, struct nf_logger *logger)
0080 {
0081     int i;
0082     int ret = 0;
0083 
0084     if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers))
0085         return -EINVAL;
0086 
0087     mutex_lock(&nf_log_mutex);
0088 
0089     if (pf == NFPROTO_UNSPEC) {
0090         for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
0091             if (rcu_access_pointer(loggers[i][logger->type])) {
0092                 ret = -EEXIST;
0093                 goto unlock;
0094             }
0095         }
0096         for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
0097             rcu_assign_pointer(loggers[i][logger->type], logger);
0098     } else {
0099         if (rcu_access_pointer(loggers[pf][logger->type])) {
0100             ret = -EEXIST;
0101             goto unlock;
0102         }
0103         rcu_assign_pointer(loggers[pf][logger->type], logger);
0104     }
0105 
0106 unlock:
0107     mutex_unlock(&nf_log_mutex);
0108     return ret;
0109 }
0110 EXPORT_SYMBOL(nf_log_register);
0111 
0112 void nf_log_unregister(struct nf_logger *logger)
0113 {
0114     const struct nf_logger *log;
0115     int i;
0116 
0117     mutex_lock(&nf_log_mutex);
0118     for (i = 0; i < NFPROTO_NUMPROTO; i++) {
0119         log = nft_log_dereference(loggers[i][logger->type]);
0120         if (log == logger)
0121             RCU_INIT_POINTER(loggers[i][logger->type], NULL);
0122     }
0123     mutex_unlock(&nf_log_mutex);
0124     synchronize_rcu();
0125 }
0126 EXPORT_SYMBOL(nf_log_unregister);
0127 
0128 int nf_log_bind_pf(struct net *net, u_int8_t pf,
0129            const struct nf_logger *logger)
0130 {
0131     if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
0132         return -EINVAL;
0133     mutex_lock(&nf_log_mutex);
0134     if (__find_logger(pf, logger->name) == NULL) {
0135         mutex_unlock(&nf_log_mutex);
0136         return -ENOENT;
0137     }
0138     rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
0139     mutex_unlock(&nf_log_mutex);
0140     return 0;
0141 }
0142 EXPORT_SYMBOL(nf_log_bind_pf);
0143 
0144 void nf_log_unbind_pf(struct net *net, u_int8_t pf)
0145 {
0146     if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
0147         return;
0148     mutex_lock(&nf_log_mutex);
0149     RCU_INIT_POINTER(net->nf.nf_loggers[pf], NULL);
0150     mutex_unlock(&nf_log_mutex);
0151 }
0152 EXPORT_SYMBOL(nf_log_unbind_pf);
0153 
0154 int nf_logger_find_get(int pf, enum nf_log_type type)
0155 {
0156     struct nf_logger *logger;
0157     int ret = -ENOENT;
0158 
0159     if (pf == NFPROTO_INET) {
0160         ret = nf_logger_find_get(NFPROTO_IPV4, type);
0161         if (ret < 0)
0162             return ret;
0163 
0164         ret = nf_logger_find_get(NFPROTO_IPV6, type);
0165         if (ret < 0) {
0166             nf_logger_put(NFPROTO_IPV4, type);
0167             return ret;
0168         }
0169 
0170         return 0;
0171     }
0172 
0173     rcu_read_lock();
0174     logger = rcu_dereference(loggers[pf][type]);
0175     if (logger == NULL)
0176         goto out;
0177 
0178     if (try_module_get(logger->me))
0179         ret = 0;
0180 out:
0181     rcu_read_unlock();
0182     return ret;
0183 }
0184 EXPORT_SYMBOL_GPL(nf_logger_find_get);
0185 
0186 void nf_logger_put(int pf, enum nf_log_type type)
0187 {
0188     struct nf_logger *logger;
0189 
0190     if (pf == NFPROTO_INET) {
0191         nf_logger_put(NFPROTO_IPV4, type);
0192         nf_logger_put(NFPROTO_IPV6, type);
0193         return;
0194     }
0195 
0196     BUG_ON(loggers[pf][type] == NULL);
0197 
0198     rcu_read_lock();
0199     logger = rcu_dereference(loggers[pf][type]);
0200     module_put(logger->me);
0201     rcu_read_unlock();
0202 }
0203 EXPORT_SYMBOL_GPL(nf_logger_put);
0204 
0205 void nf_log_packet(struct net *net,
0206            u_int8_t pf,
0207            unsigned int hooknum,
0208            const struct sk_buff *skb,
0209            const struct net_device *in,
0210            const struct net_device *out,
0211            const struct nf_loginfo *loginfo,
0212            const char *fmt, ...)
0213 {
0214     va_list args;
0215     char prefix[NF_LOG_PREFIXLEN];
0216     const struct nf_logger *logger;
0217 
0218     rcu_read_lock();
0219     if (loginfo != NULL)
0220         logger = rcu_dereference(loggers[pf][loginfo->type]);
0221     else
0222         logger = rcu_dereference(net->nf.nf_loggers[pf]);
0223 
0224     if (logger) {
0225         va_start(args, fmt);
0226         vsnprintf(prefix, sizeof(prefix), fmt, args);
0227         va_end(args);
0228         logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
0229     }
0230     rcu_read_unlock();
0231 }
0232 EXPORT_SYMBOL(nf_log_packet);
0233 
0234 void nf_log_trace(struct net *net,
0235           u_int8_t pf,
0236           unsigned int hooknum,
0237           const struct sk_buff *skb,
0238           const struct net_device *in,
0239           const struct net_device *out,
0240           const struct nf_loginfo *loginfo, const char *fmt, ...)
0241 {
0242     va_list args;
0243     char prefix[NF_LOG_PREFIXLEN];
0244     const struct nf_logger *logger;
0245 
0246     rcu_read_lock();
0247     logger = rcu_dereference(net->nf.nf_loggers[pf]);
0248     if (logger) {
0249         va_start(args, fmt);
0250         vsnprintf(prefix, sizeof(prefix), fmt, args);
0251         va_end(args);
0252         logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
0253     }
0254     rcu_read_unlock();
0255 }
0256 EXPORT_SYMBOL(nf_log_trace);
0257 
0258 #define S_SIZE (1024 - (sizeof(unsigned int) + 1))
0259 
0260 struct nf_log_buf {
0261     unsigned int    count;
0262     char        buf[S_SIZE + 1];
0263 };
0264 static struct nf_log_buf emergency, *emergency_ptr = &emergency;
0265 
0266 __printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...)
0267 {
0268     va_list args;
0269     int len;
0270 
0271     if (likely(m->count < S_SIZE)) {
0272         va_start(args, f);
0273         len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args);
0274         va_end(args);
0275         if (likely(m->count + len < S_SIZE)) {
0276             m->count += len;
0277             return 0;
0278         }
0279     }
0280     m->count = S_SIZE;
0281     printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n");
0282     return -1;
0283 }
0284 EXPORT_SYMBOL_GPL(nf_log_buf_add);
0285 
0286 struct nf_log_buf *nf_log_buf_open(void)
0287 {
0288     struct nf_log_buf *m = kmalloc(sizeof(*m), GFP_ATOMIC);
0289 
0290     if (unlikely(!m)) {
0291         local_bh_disable();
0292         do {
0293             m = xchg(&emergency_ptr, NULL);
0294         } while (!m);
0295     }
0296     m->count = 0;
0297     return m;
0298 }
0299 EXPORT_SYMBOL_GPL(nf_log_buf_open);
0300 
0301 void nf_log_buf_close(struct nf_log_buf *m)
0302 {
0303     m->buf[m->count] = 0;
0304     printk("%s\n", m->buf);
0305 
0306     if (likely(m != &emergency))
0307         kfree(m);
0308     else {
0309         emergency_ptr = m;
0310         local_bh_enable();
0311     }
0312 }
0313 EXPORT_SYMBOL_GPL(nf_log_buf_close);
0314 
0315 #ifdef CONFIG_PROC_FS
0316 static void *seq_start(struct seq_file *seq, loff_t *pos)
0317 {
0318     struct net *net = seq_file_net(seq);
0319 
0320     mutex_lock(&nf_log_mutex);
0321 
0322     if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
0323         return NULL;
0324 
0325     return pos;
0326 }
0327 
0328 static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
0329 {
0330     struct net *net = seq_file_net(s);
0331 
0332     (*pos)++;
0333 
0334     if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
0335         return NULL;
0336 
0337     return pos;
0338 }
0339 
0340 static void seq_stop(struct seq_file *s, void *v)
0341 {
0342     mutex_unlock(&nf_log_mutex);
0343 }
0344 
0345 static int seq_show(struct seq_file *s, void *v)
0346 {
0347     loff_t *pos = v;
0348     const struct nf_logger *logger;
0349     int i;
0350     struct net *net = seq_file_net(s);
0351 
0352     logger = nft_log_dereference(net->nf.nf_loggers[*pos]);
0353 
0354     if (!logger)
0355         seq_printf(s, "%2lld NONE (", *pos);
0356     else
0357         seq_printf(s, "%2lld %s (", *pos, logger->name);
0358 
0359     if (seq_has_overflowed(s))
0360         return -ENOSPC;
0361 
0362     for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
0363         if (loggers[*pos][i] == NULL)
0364             continue;
0365 
0366         logger = nft_log_dereference(loggers[*pos][i]);
0367         seq_puts(s, logger->name);
0368         if (i == 0 && loggers[*pos][i + 1] != NULL)
0369             seq_puts(s, ",");
0370 
0371         if (seq_has_overflowed(s))
0372             return -ENOSPC;
0373     }
0374 
0375     seq_puts(s, ")\n");
0376 
0377     if (seq_has_overflowed(s))
0378         return -ENOSPC;
0379     return 0;
0380 }
0381 
0382 static const struct seq_operations nflog_seq_ops = {
0383     .start  = seq_start,
0384     .next   = seq_next,
0385     .stop   = seq_stop,
0386     .show   = seq_show,
0387 };
0388 #endif /* PROC_FS */
0389 
0390 #ifdef CONFIG_SYSCTL
0391 static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
0392 static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
0393 static struct ctl_table_header *nf_log_sysctl_fhdr;
0394 
0395 static struct ctl_table nf_log_sysctl_ftable[] = {
0396     {
0397         .procname   = "nf_log_all_netns",
0398         .data       = &sysctl_nf_log_all_netns,
0399         .maxlen     = sizeof(sysctl_nf_log_all_netns),
0400         .mode       = 0644,
0401         .proc_handler   = proc_dointvec,
0402     },
0403     { }
0404 };
0405 
0406 static int nf_log_proc_dostring(struct ctl_table *table, int write,
0407              void *buffer, size_t *lenp, loff_t *ppos)
0408 {
0409     const struct nf_logger *logger;
0410     char buf[NFLOGGER_NAME_LEN];
0411     int r = 0;
0412     int tindex = (unsigned long)table->extra1;
0413     struct net *net = table->extra2;
0414 
0415     if (write) {
0416         struct ctl_table tmp = *table;
0417 
0418         /* proc_dostring() can append to existing strings, so we need to
0419          * initialize it as an empty string.
0420          */
0421         buf[0] = '\0';
0422         tmp.data = buf;
0423         r = proc_dostring(&tmp, write, buffer, lenp, ppos);
0424         if (r)
0425             return r;
0426 
0427         if (!strcmp(buf, "NONE")) {
0428             nf_log_unbind_pf(net, tindex);
0429             return 0;
0430         }
0431         mutex_lock(&nf_log_mutex);
0432         logger = __find_logger(tindex, buf);
0433         if (logger == NULL) {
0434             mutex_unlock(&nf_log_mutex);
0435             return -ENOENT;
0436         }
0437         rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
0438         mutex_unlock(&nf_log_mutex);
0439     } else {
0440         struct ctl_table tmp = *table;
0441 
0442         tmp.data = buf;
0443         mutex_lock(&nf_log_mutex);
0444         logger = nft_log_dereference(net->nf.nf_loggers[tindex]);
0445         if (!logger)
0446             strlcpy(buf, "NONE", sizeof(buf));
0447         else
0448             strlcpy(buf, logger->name, sizeof(buf));
0449         mutex_unlock(&nf_log_mutex);
0450         r = proc_dostring(&tmp, write, buffer, lenp, ppos);
0451     }
0452 
0453     return r;
0454 }
0455 
0456 static int netfilter_log_sysctl_init(struct net *net)
0457 {
0458     int i;
0459     struct ctl_table *table;
0460 
0461     table = nf_log_sysctl_table;
0462     if (!net_eq(net, &init_net)) {
0463         table = kmemdup(nf_log_sysctl_table,
0464                  sizeof(nf_log_sysctl_table),
0465                  GFP_KERNEL);
0466         if (!table)
0467             goto err_alloc;
0468     } else {
0469         for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
0470             snprintf(nf_log_sysctl_fnames[i],
0471                  3, "%d", i);
0472             nf_log_sysctl_table[i].procname =
0473                 nf_log_sysctl_fnames[i];
0474             nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN;
0475             nf_log_sysctl_table[i].mode = 0644;
0476             nf_log_sysctl_table[i].proc_handler =
0477                 nf_log_proc_dostring;
0478             nf_log_sysctl_table[i].extra1 =
0479                 (void *)(unsigned long) i;
0480         }
0481         nf_log_sysctl_fhdr = register_net_sysctl(net, "net/netfilter",
0482                              nf_log_sysctl_ftable);
0483         if (!nf_log_sysctl_fhdr)
0484             goto err_freg;
0485     }
0486 
0487     for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
0488         table[i].extra2 = net;
0489 
0490     net->nf.nf_log_dir_header = register_net_sysctl(net,
0491                         "net/netfilter/nf_log",
0492                         table);
0493     if (!net->nf.nf_log_dir_header)
0494         goto err_reg;
0495 
0496     return 0;
0497 
0498 err_reg:
0499     if (!net_eq(net, &init_net))
0500         kfree(table);
0501     else
0502         unregister_net_sysctl_table(nf_log_sysctl_fhdr);
0503 err_freg:
0504 err_alloc:
0505     return -ENOMEM;
0506 }
0507 
0508 static void netfilter_log_sysctl_exit(struct net *net)
0509 {
0510     struct ctl_table *table;
0511 
0512     table = net->nf.nf_log_dir_header->ctl_table_arg;
0513     unregister_net_sysctl_table(net->nf.nf_log_dir_header);
0514     if (!net_eq(net, &init_net))
0515         kfree(table);
0516     else
0517         unregister_net_sysctl_table(nf_log_sysctl_fhdr);
0518 }
0519 #else
0520 static int netfilter_log_sysctl_init(struct net *net)
0521 {
0522     return 0;
0523 }
0524 
0525 static void netfilter_log_sysctl_exit(struct net *net)
0526 {
0527 }
0528 #endif /* CONFIG_SYSCTL */
0529 
0530 static int __net_init nf_log_net_init(struct net *net)
0531 {
0532     int ret = -ENOMEM;
0533 
0534 #ifdef CONFIG_PROC_FS
0535     if (!proc_create_net("nf_log", 0444, net->nf.proc_netfilter,
0536             &nflog_seq_ops, sizeof(struct seq_net_private)))
0537         return ret;
0538 #endif
0539     ret = netfilter_log_sysctl_init(net);
0540     if (ret < 0)
0541         goto out_sysctl;
0542 
0543     return 0;
0544 
0545 out_sysctl:
0546 #ifdef CONFIG_PROC_FS
0547     remove_proc_entry("nf_log", net->nf.proc_netfilter);
0548 #endif
0549     return ret;
0550 }
0551 
0552 static void __net_exit nf_log_net_exit(struct net *net)
0553 {
0554     netfilter_log_sysctl_exit(net);
0555 #ifdef CONFIG_PROC_FS
0556     remove_proc_entry("nf_log", net->nf.proc_netfilter);
0557 #endif
0558 }
0559 
0560 static struct pernet_operations nf_log_net_ops = {
0561     .init = nf_log_net_init,
0562     .exit = nf_log_net_exit,
0563 };
0564 
0565 int __init netfilter_log_init(void)
0566 {
0567     return register_pernet_subsys(&nf_log_net_ops);
0568 }