root/net/netfilter/nft_log.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. audit_ip4
  2. audit_ip6
  3. nft_log_eval_audit
  4. nft_log_eval
  5. nft_log_init
  6. nft_log_destroy
  7. nft_log_dump
  8. nft_log_module_init
  9. nft_log_module_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
   4  * Copyright (c) 2012-2014 Pablo Neira Ayuso <pablo@netfilter.org>
   5  *
   6  * Development of this code funded by Astaro AG (http://www.astaro.com/)
   7  */
   8 
   9 #include <linux/audit.h>
  10 #include <linux/kernel.h>
  11 #include <linux/init.h>
  12 #include <linux/module.h>
  13 #include <linux/netlink.h>
  14 #include <linux/netfilter.h>
  15 #include <linux/netfilter/nf_tables.h>
  16 #include <net/ipv6.h>
  17 #include <net/ip.h>
  18 #include <net/netfilter/nf_tables.h>
  19 #include <net/netfilter/nf_log.h>
  20 #include <linux/netdevice.h>
  21 
  22 static const char *nft_log_null_prefix = "";
  23 
  24 struct nft_log {
  25         struct nf_loginfo       loginfo;
  26         char                    *prefix;
  27 };
  28 
  29 static bool audit_ip4(struct audit_buffer *ab, struct sk_buff *skb)
  30 {
  31         struct iphdr _iph;
  32         const struct iphdr *ih;
  33 
  34         ih = skb_header_pointer(skb, skb_network_offset(skb), sizeof(_iph), &_iph);
  35         if (!ih)
  36                 return false;
  37 
  38         audit_log_format(ab, " saddr=%pI4 daddr=%pI4 proto=%hhu",
  39                          &ih->saddr, &ih->daddr, ih->protocol);
  40 
  41         return true;
  42 }
  43 
  44 static bool audit_ip6(struct audit_buffer *ab, struct sk_buff *skb)
  45 {
  46         struct ipv6hdr _ip6h;
  47         const struct ipv6hdr *ih;
  48         u8 nexthdr;
  49         __be16 frag_off;
  50 
  51         ih = skb_header_pointer(skb, skb_network_offset(skb), sizeof(_ip6h), &_ip6h);
  52         if (!ih)
  53                 return false;
  54 
  55         nexthdr = ih->nexthdr;
  56         ipv6_skip_exthdr(skb, skb_network_offset(skb) + sizeof(_ip6h), &nexthdr, &frag_off);
  57 
  58         audit_log_format(ab, " saddr=%pI6c daddr=%pI6c proto=%hhu",
  59                          &ih->saddr, &ih->daddr, nexthdr);
  60 
  61         return true;
  62 }
  63 
  64 static void nft_log_eval_audit(const struct nft_pktinfo *pkt)
  65 {
  66         struct sk_buff *skb = pkt->skb;
  67         struct audit_buffer *ab;
  68         int fam = -1;
  69 
  70         if (!audit_enabled)
  71                 return;
  72 
  73         ab = audit_log_start(NULL, GFP_ATOMIC, AUDIT_NETFILTER_PKT);
  74         if (!ab)
  75                 return;
  76 
  77         audit_log_format(ab, "mark=%#x", skb->mark);
  78 
  79         switch (nft_pf(pkt)) {
  80         case NFPROTO_BRIDGE:
  81                 switch (eth_hdr(skb)->h_proto) {
  82                 case htons(ETH_P_IP):
  83                         fam = audit_ip4(ab, skb) ? NFPROTO_IPV4 : -1;
  84                         break;
  85                 case htons(ETH_P_IPV6):
  86                         fam = audit_ip6(ab, skb) ? NFPROTO_IPV6 : -1;
  87                         break;
  88                 }
  89                 break;
  90         case NFPROTO_IPV4:
  91                 fam = audit_ip4(ab, skb) ? NFPROTO_IPV4 : -1;
  92                 break;
  93         case NFPROTO_IPV6:
  94                 fam = audit_ip6(ab, skb) ? NFPROTO_IPV6 : -1;
  95                 break;
  96         }
  97 
  98         if (fam == -1)
  99                 audit_log_format(ab, " saddr=? daddr=? proto=-1");
 100 
 101         audit_log_end(ab);
 102 }
 103 
 104 static void nft_log_eval(const struct nft_expr *expr,
 105                          struct nft_regs *regs,
 106                          const struct nft_pktinfo *pkt)
 107 {
 108         const struct nft_log *priv = nft_expr_priv(expr);
 109 
 110         if (priv->loginfo.type == NF_LOG_TYPE_LOG &&
 111             priv->loginfo.u.log.level == NFT_LOGLEVEL_AUDIT) {
 112                 nft_log_eval_audit(pkt);
 113                 return;
 114         }
 115 
 116         nf_log_packet(nft_net(pkt), nft_pf(pkt), nft_hook(pkt), pkt->skb,
 117                       nft_in(pkt), nft_out(pkt), &priv->loginfo, "%s",
 118                       priv->prefix);
 119 }
 120 
 121 static const struct nla_policy nft_log_policy[NFTA_LOG_MAX + 1] = {
 122         [NFTA_LOG_GROUP]        = { .type = NLA_U16 },
 123         [NFTA_LOG_PREFIX]       = { .type = NLA_STRING,
 124                                     .len = NF_LOG_PREFIXLEN - 1 },
 125         [NFTA_LOG_SNAPLEN]      = { .type = NLA_U32 },
 126         [NFTA_LOG_QTHRESHOLD]   = { .type = NLA_U16 },
 127         [NFTA_LOG_LEVEL]        = { .type = NLA_U32 },
 128         [NFTA_LOG_FLAGS]        = { .type = NLA_U32 },
 129 };
 130 
 131 static int nft_log_init(const struct nft_ctx *ctx,
 132                         const struct nft_expr *expr,
 133                         const struct nlattr * const tb[])
 134 {
 135         struct nft_log *priv = nft_expr_priv(expr);
 136         struct nf_loginfo *li = &priv->loginfo;
 137         const struct nlattr *nla;
 138         int err;
 139 
 140         li->type = NF_LOG_TYPE_LOG;
 141         if (tb[NFTA_LOG_LEVEL] != NULL &&
 142             tb[NFTA_LOG_GROUP] != NULL)
 143                 return -EINVAL;
 144         if (tb[NFTA_LOG_GROUP] != NULL) {
 145                 li->type = NF_LOG_TYPE_ULOG;
 146                 if (tb[NFTA_LOG_FLAGS] != NULL)
 147                         return -EINVAL;
 148         }
 149 
 150         nla = tb[NFTA_LOG_PREFIX];
 151         if (nla != NULL) {
 152                 priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
 153                 if (priv->prefix == NULL)
 154                         return -ENOMEM;
 155                 nla_strlcpy(priv->prefix, nla, nla_len(nla) + 1);
 156         } else {
 157                 priv->prefix = (char *)nft_log_null_prefix;
 158         }
 159 
 160         switch (li->type) {
 161         case NF_LOG_TYPE_LOG:
 162                 if (tb[NFTA_LOG_LEVEL] != NULL) {
 163                         li->u.log.level =
 164                                 ntohl(nla_get_be32(tb[NFTA_LOG_LEVEL]));
 165                 } else {
 166                         li->u.log.level = NFT_LOGLEVEL_WARNING;
 167                 }
 168                 if (li->u.log.level > NFT_LOGLEVEL_AUDIT) {
 169                         err = -EINVAL;
 170                         goto err1;
 171                 }
 172 
 173                 if (tb[NFTA_LOG_FLAGS] != NULL) {
 174                         li->u.log.logflags =
 175                                 ntohl(nla_get_be32(tb[NFTA_LOG_FLAGS]));
 176                         if (li->u.log.logflags & ~NF_LOG_MASK) {
 177                                 err = -EINVAL;
 178                                 goto err1;
 179                         }
 180                 }
 181                 break;
 182         case NF_LOG_TYPE_ULOG:
 183                 li->u.ulog.group = ntohs(nla_get_be16(tb[NFTA_LOG_GROUP]));
 184                 if (tb[NFTA_LOG_SNAPLEN] != NULL) {
 185                         li->u.ulog.flags |= NF_LOG_F_COPY_LEN;
 186                         li->u.ulog.copy_len =
 187                                 ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN]));
 188                 }
 189                 if (tb[NFTA_LOG_QTHRESHOLD] != NULL) {
 190                         li->u.ulog.qthreshold =
 191                                 ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD]));
 192                 }
 193                 break;
 194         }
 195 
 196         if (li->u.log.level == NFT_LOGLEVEL_AUDIT)
 197                 return 0;
 198 
 199         err = nf_logger_find_get(ctx->family, li->type);
 200         if (err < 0)
 201                 goto err1;
 202 
 203         return 0;
 204 
 205 err1:
 206         if (priv->prefix != nft_log_null_prefix)
 207                 kfree(priv->prefix);
 208         return err;
 209 }
 210 
 211 static void nft_log_destroy(const struct nft_ctx *ctx,
 212                             const struct nft_expr *expr)
 213 {
 214         struct nft_log *priv = nft_expr_priv(expr);
 215         struct nf_loginfo *li = &priv->loginfo;
 216 
 217         if (priv->prefix != nft_log_null_prefix)
 218                 kfree(priv->prefix);
 219 
 220         if (li->u.log.level == NFT_LOGLEVEL_AUDIT)
 221                 return;
 222 
 223         nf_logger_put(ctx->family, li->type);
 224 }
 225 
 226 static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr)
 227 {
 228         const struct nft_log *priv = nft_expr_priv(expr);
 229         const struct nf_loginfo *li = &priv->loginfo;
 230 
 231         if (priv->prefix != nft_log_null_prefix)
 232                 if (nla_put_string(skb, NFTA_LOG_PREFIX, priv->prefix))
 233                         goto nla_put_failure;
 234         switch (li->type) {
 235         case NF_LOG_TYPE_LOG:
 236                 if (nla_put_be32(skb, NFTA_LOG_LEVEL, htonl(li->u.log.level)))
 237                         goto nla_put_failure;
 238 
 239                 if (li->u.log.logflags) {
 240                         if (nla_put_be32(skb, NFTA_LOG_FLAGS,
 241                                          htonl(li->u.log.logflags)))
 242                                 goto nla_put_failure;
 243                 }
 244                 break;
 245         case NF_LOG_TYPE_ULOG:
 246                 if (nla_put_be16(skb, NFTA_LOG_GROUP, htons(li->u.ulog.group)))
 247                         goto nla_put_failure;
 248 
 249                 if (li->u.ulog.flags & NF_LOG_F_COPY_LEN) {
 250                         if (nla_put_be32(skb, NFTA_LOG_SNAPLEN,
 251                                          htonl(li->u.ulog.copy_len)))
 252                                 goto nla_put_failure;
 253                 }
 254                 if (li->u.ulog.qthreshold) {
 255                         if (nla_put_be16(skb, NFTA_LOG_QTHRESHOLD,
 256                                          htons(li->u.ulog.qthreshold)))
 257                                 goto nla_put_failure;
 258                 }
 259                 break;
 260         }
 261         return 0;
 262 
 263 nla_put_failure:
 264         return -1;
 265 }
 266 
 267 static struct nft_expr_type nft_log_type;
 268 static const struct nft_expr_ops nft_log_ops = {
 269         .type           = &nft_log_type,
 270         .size           = NFT_EXPR_SIZE(sizeof(struct nft_log)),
 271         .eval           = nft_log_eval,
 272         .init           = nft_log_init,
 273         .destroy        = nft_log_destroy,
 274         .dump           = nft_log_dump,
 275 };
 276 
 277 static struct nft_expr_type nft_log_type __read_mostly = {
 278         .name           = "log",
 279         .ops            = &nft_log_ops,
 280         .policy         = nft_log_policy,
 281         .maxattr        = NFTA_LOG_MAX,
 282         .owner          = THIS_MODULE,
 283 };
 284 
 285 static int __init nft_log_module_init(void)
 286 {
 287         return nft_register_expr(&nft_log_type);
 288 }
 289 
 290 static void __exit nft_log_module_exit(void)
 291 {
 292         nft_unregister_expr(&nft_log_type);
 293 }
 294 
 295 module_init(nft_log_module_init);
 296 module_exit(nft_log_module_exit);
 297 
 298 MODULE_LICENSE("GPL");
 299 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
 300 MODULE_ALIAS_NFT_EXPR("log");

/* [<][>][^][v][top][bottom][index][help] */