linux/net/netfilter/nft_log.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
   3 * Copyright (c) 2012-2014 Pablo Neira Ayuso <pablo@netfilter.org>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 *
   9 * Development of this code funded by Astaro AG (http://www.astaro.com/)
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/init.h>
  14#include <linux/module.h>
  15#include <linux/netlink.h>
  16#include <linux/netfilter.h>
  17#include <linux/netfilter/nf_tables.h>
  18#include <net/netfilter/nf_tables.h>
  19#include <net/netfilter/nf_log.h>
  20#include <linux/netdevice.h>
  21
  22static const char *nft_log_null_prefix = "";
  23
  24struct nft_log {
  25        struct nf_loginfo       loginfo;
  26        char                    *prefix;
  27};
  28
  29static void nft_log_eval(const struct nft_expr *expr,
  30                         struct nft_regs *regs,
  31                         const struct nft_pktinfo *pkt)
  32{
  33        const struct nft_log *priv = nft_expr_priv(expr);
  34
  35        nf_log_packet(pkt->net, pkt->pf, pkt->hook, pkt->skb, pkt->in,
  36                      pkt->out, &priv->loginfo, "%s", priv->prefix);
  37}
  38
  39static const struct nla_policy nft_log_policy[NFTA_LOG_MAX + 1] = {
  40        [NFTA_LOG_GROUP]        = { .type = NLA_U16 },
  41        [NFTA_LOG_PREFIX]       = { .type = NLA_STRING },
  42        [NFTA_LOG_SNAPLEN]      = { .type = NLA_U32 },
  43        [NFTA_LOG_QTHRESHOLD]   = { .type = NLA_U16 },
  44        [NFTA_LOG_LEVEL]        = { .type = NLA_U32 },
  45        [NFTA_LOG_FLAGS]        = { .type = NLA_U32 },
  46};
  47
  48static int nft_log_init(const struct nft_ctx *ctx,
  49                        const struct nft_expr *expr,
  50                        const struct nlattr * const tb[])
  51{
  52        struct nft_log *priv = nft_expr_priv(expr);
  53        struct nf_loginfo *li = &priv->loginfo;
  54        const struct nlattr *nla;
  55        int ret;
  56
  57        nla = tb[NFTA_LOG_PREFIX];
  58        if (nla != NULL) {
  59                priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
  60                if (priv->prefix == NULL)
  61                        return -ENOMEM;
  62                nla_strlcpy(priv->prefix, nla, nla_len(nla) + 1);
  63        } else {
  64                priv->prefix = (char *)nft_log_null_prefix;
  65        }
  66
  67        li->type = NF_LOG_TYPE_LOG;
  68        if (tb[NFTA_LOG_LEVEL] != NULL &&
  69            tb[NFTA_LOG_GROUP] != NULL)
  70                return -EINVAL;
  71        if (tb[NFTA_LOG_GROUP] != NULL)
  72                li->type = NF_LOG_TYPE_ULOG;
  73
  74        switch (li->type) {
  75        case NF_LOG_TYPE_LOG:
  76                if (tb[NFTA_LOG_LEVEL] != NULL) {
  77                        li->u.log.level =
  78                                ntohl(nla_get_be32(tb[NFTA_LOG_LEVEL]));
  79                } else {
  80                        li->u.log.level = LOGLEVEL_WARNING;
  81                }
  82                if (tb[NFTA_LOG_FLAGS] != NULL) {
  83                        li->u.log.logflags =
  84                                ntohl(nla_get_be32(tb[NFTA_LOG_FLAGS]));
  85                }
  86                break;
  87        case NF_LOG_TYPE_ULOG:
  88                li->u.ulog.group = ntohs(nla_get_be16(tb[NFTA_LOG_GROUP]));
  89                if (tb[NFTA_LOG_SNAPLEN] != NULL) {
  90                        li->u.ulog.copy_len =
  91                                ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN]));
  92                }
  93                if (tb[NFTA_LOG_QTHRESHOLD] != NULL) {
  94                        li->u.ulog.qthreshold =
  95                                ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD]));
  96                }
  97                break;
  98        }
  99
 100        if (ctx->afi->family == NFPROTO_INET) {
 101                ret = nf_logger_find_get(NFPROTO_IPV4, li->type);
 102                if (ret < 0)
 103                        return ret;
 104
 105                ret = nf_logger_find_get(NFPROTO_IPV6, li->type);
 106                if (ret < 0) {
 107                        nf_logger_put(NFPROTO_IPV4, li->type);
 108                        return ret;
 109                }
 110                return 0;
 111        }
 112
 113        return nf_logger_find_get(ctx->afi->family, li->type);
 114}
 115
 116static void nft_log_destroy(const struct nft_ctx *ctx,
 117                            const struct nft_expr *expr)
 118{
 119        struct nft_log *priv = nft_expr_priv(expr);
 120        struct nf_loginfo *li = &priv->loginfo;
 121
 122        if (priv->prefix != nft_log_null_prefix)
 123                kfree(priv->prefix);
 124
 125        if (ctx->afi->family == NFPROTO_INET) {
 126                nf_logger_put(NFPROTO_IPV4, li->type);
 127                nf_logger_put(NFPROTO_IPV6, li->type);
 128        } else {
 129                nf_logger_put(ctx->afi->family, li->type);
 130        }
 131}
 132
 133static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr)
 134{
 135        const struct nft_log *priv = nft_expr_priv(expr);
 136        const struct nf_loginfo *li = &priv->loginfo;
 137
 138        if (priv->prefix != nft_log_null_prefix)
 139                if (nla_put_string(skb, NFTA_LOG_PREFIX, priv->prefix))
 140                        goto nla_put_failure;
 141        switch (li->type) {
 142        case NF_LOG_TYPE_LOG:
 143                if (nla_put_be32(skb, NFTA_LOG_LEVEL, htonl(li->u.log.level)))
 144                        goto nla_put_failure;
 145
 146                if (li->u.log.logflags) {
 147                        if (nla_put_be32(skb, NFTA_LOG_FLAGS,
 148                                         htonl(li->u.log.logflags)))
 149                                goto nla_put_failure;
 150                }
 151                break;
 152        case NF_LOG_TYPE_ULOG:
 153                if (nla_put_be16(skb, NFTA_LOG_GROUP, htons(li->u.ulog.group)))
 154                        goto nla_put_failure;
 155
 156                if (li->u.ulog.copy_len) {
 157                        if (nla_put_be32(skb, NFTA_LOG_SNAPLEN,
 158                                         htonl(li->u.ulog.copy_len)))
 159                                goto nla_put_failure;
 160                }
 161                if (li->u.ulog.qthreshold) {
 162                        if (nla_put_be16(skb, NFTA_LOG_QTHRESHOLD,
 163                                         htons(li->u.ulog.qthreshold)))
 164                                goto nla_put_failure;
 165                }
 166                break;
 167        }
 168        return 0;
 169
 170nla_put_failure:
 171        return -1;
 172}
 173
 174static struct nft_expr_type nft_log_type;
 175static const struct nft_expr_ops nft_log_ops = {
 176        .type           = &nft_log_type,
 177        .size           = NFT_EXPR_SIZE(sizeof(struct nft_log)),
 178        .eval           = nft_log_eval,
 179        .init           = nft_log_init,
 180        .destroy        = nft_log_destroy,
 181        .dump           = nft_log_dump,
 182};
 183
 184static struct nft_expr_type nft_log_type __read_mostly = {
 185        .name           = "log",
 186        .ops            = &nft_log_ops,
 187        .policy         = nft_log_policy,
 188        .maxattr        = NFTA_LOG_MAX,
 189        .owner          = THIS_MODULE,
 190};
 191
 192static int __init nft_log_module_init(void)
 193{
 194        return nft_register_expr(&nft_log_type);
 195}
 196
 197static void __exit nft_log_module_exit(void)
 198{
 199        nft_unregister_expr(&nft_log_type);
 200}
 201
 202module_init(nft_log_module_init);
 203module_exit(nft_log_module_exit);
 204
 205MODULE_LICENSE("GPL");
 206MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
 207MODULE_ALIAS_NFT_EXPR("log");
 208