This extends log statement to support the behaviour achieved with AUDIT target in iptables. Audit logging is enabled via a pseudo log level 8. In this case any other settings like log prefix are ignored since audit log format is fixed.
Unified · Split
| @@ -1080,6 +1080,11 @@ enum nft_log_attributes { · 1079 unmodified lines | |||
| 1080 | }; | 1080 | }; |
| 1081 | #define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1) | 1081 | #define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1) |
| 1082 | 1082 | ||
| 1083 | /** | ||
| 1084 | * LOGLEVEL_AUDIT - a pseudo log level enabling audit logging | ||
| 1085 | */ | ||
| 1086 | #define LOGLEVEL_AUDIT 8 | ||
| 1087 | |||
| 1083 | /** | 1088 | /** |
| 1084 | * enum nft_queue_attributes - nf_tables queue expression netlink attributes | 1089 | * enum nft_queue_attributes - nf_tables queue expression netlink attributes |
| 1085 | * | 1090 | * |
| @@ -9,12 +9,15 @@ · 8 unmodified lines | |||
| 9 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | 9 | * Development of this code funded by Astaro AG (http://www.astaro.com/) |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/audit.h> | ||
| 12 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 13 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 15 | #include <linux/netlink.h> | 16 | #include <linux/netlink.h> |
| 16 | #include <linux/netfilter.h> | 17 | #include <linux/netfilter.h> |
| 17 | #include <linux/netfilter/nf_tables.h> | 18 | #include <linux/netfilter/nf_tables.h> |
| 19 | #include <net/ipv6.h> | ||
| 20 | #include <net/ip.h> | ||
| 18 | #include <net/netfilter/nf_tables.h> | 21 | #include <net/netfilter/nf_tables.h> |
| 19 | #include <net/netfilter/nf_log.h> | 22 | #include <net/netfilter/nf_log.h> |
| 20 | #include <linux/netdevice.h> | 23 | #include <linux/netdevice.h> |
| @@ -26,12 +29,93 @@ struct nft_log { · 5 unmodified lines | |||
| 26 | char *prefix; | 29 | char *prefix; |
| 27 | }; | 30 | }; |
| 28 | 31 | ||
| 32 | static bool audit_ip4(struct audit_buffer *ab, struct sk_buff *skb) | ||
| 33 | { | ||
| 34 | struct iphdr _iph; | ||
| 35 | const struct iphdr *ih; | ||
| 36 | |||
| 37 | ih = skb_header_pointer(skb, skb_network_offset(skb), sizeof(_iph), &_iph); | ||
| 38 | if (!ih) | ||
| 39 | return false; | ||
| 40 | |||
| 41 | audit_log_format(ab, " saddr=%pI4 daddr=%pI4 proto=%hhu", | ||
| 42 | &ih->saddr, &ih->daddr, ih->protocol); | ||
| 43 | |||
| 44 | return true; | ||
| 45 | } | ||
| 46 | |||
| 47 | static bool audit_ip6(struct audit_buffer *ab, struct sk_buff *skb) | ||
| 48 | { | ||
| 49 | struct ipv6hdr _ip6h; | ||
| 50 | const struct ipv6hdr *ih; | ||
| 51 | u8 nexthdr; | ||
| 52 | __be16 frag_off; | ||
| 53 | |||
| 54 | ih = skb_header_pointer(skb, skb_network_offset(skb), sizeof(_ip6h), &_ip6h); | ||
| 55 | if (!ih) | ||
| 56 | return false; | ||
| 57 | |||
| 58 | nexthdr = ih->nexthdr; | ||
| 59 | ipv6_skip_exthdr(skb, skb_network_offset(skb) + sizeof(_ip6h), &nexthdr, &frag_off); | ||
| 60 | |||
| 61 | audit_log_format(ab, " saddr=%pI6c daddr=%pI6c proto=%hhu", | ||
| 62 | &ih->saddr, &ih->daddr, nexthdr); | ||
| 63 | |||
| 64 | return true; | ||
| 65 | } | ||
| 66 | |||
| 67 | static void nft_log_eval_audit(const struct nft_pktinfo *pkt) | ||
| 68 | { | ||
| 69 | struct sk_buff *skb = pkt->skb; | ||
| 70 | struct audit_buffer *ab; | ||
| 71 | int fam = -1; | ||
| 72 | |||
| 73 | if (!audit_enabled) | ||
| 74 | return; | ||
| 75 | |||
| 76 | ab = audit_log_start(NULL, GFP_ATOMIC, AUDIT_NETFILTER_PKT); | ||
| 77 | if (!ab) | ||
| 78 | return; | ||
| 79 | |||
| 80 | audit_log_format(ab, "mark=%#x", skb->mark); | ||
| 81 | |||
| 82 | switch (nft_pf(pkt)) { | ||
| 83 | case NFPROTO_BRIDGE: | ||
| 84 | switch (eth_hdr(skb)->h_proto) { | ||
| 85 | case htons(ETH_P_IP): | ||
| 86 | fam = audit_ip4(ab, skb) ? NFPROTO_IPV4 : -1; | ||
| 87 | break; | ||
| 88 | case htons(ETH_P_IPV6): | ||
| 89 | fam = audit_ip6(ab, skb) ? NFPROTO_IPV6 : -1; | ||
| 90 | break; | ||
| 91 | } | ||
| 92 | break; | ||
| 93 | case NFPROTO_IPV4: | ||
| 94 | fam = audit_ip4(ab, skb) ? NFPROTO_IPV4 : -1; | ||
| 95 | break; | ||
| 96 | case NFPROTO_IPV6: | ||
| 97 | fam = audit_ip6(ab, skb) ? NFPROTO_IPV6 : -1; | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | |||
| 101 | if (fam == -1) | ||
| 102 | audit_log_format(ab, " saddr=? daddr=? proto=-1"); | ||
| 103 | |||
| 104 | audit_log_end(ab); | ||
| 105 | } | ||
| 106 | |||
| 29 | static void nft_log_eval(const struct nft_expr *expr, | 107 | static void nft_log_eval(const struct nft_expr *expr, |
| 30 | struct nft_regs *regs, | 108 | struct nft_regs *regs, |
| 31 | const struct nft_pktinfo *pkt) | 109 | const struct nft_pktinfo *pkt) |
| 32 | { | 110 | { |
| 33 | const struct nft_log *priv = nft_expr_priv(expr); | 111 | const struct nft_log *priv = nft_expr_priv(expr); |
| 34 | 112 | ||
| 113 | if (priv->loginfo.type == NF_LOG_TYPE_LOG && | ||
| 114 | priv->loginfo.u.log.level == LOGLEVEL_AUDIT) { | ||
| 115 | nft_log_eval_audit(pkt); | ||
| 116 | return; | ||
| 117 | } | ||
| 118 | |||
| 35 | nf_log_packet(nft_net(pkt), nft_pf(pkt), nft_hook(pkt), pkt->skb, | 119 | nf_log_packet(nft_net(pkt), nft_pf(pkt), nft_hook(pkt), pkt->skb, |
| 36 | nft_in(pkt), nft_out(pkt), &priv->loginfo, "%s", | 120 | nft_in(pkt), nft_out(pkt), &priv->loginfo, "%s", |
| 37 | priv->prefix); | 121 | priv->prefix); |
| @@ -84,7 +168,7 @@ static int nft_log_init(const struct nft_ctx *ctx, · 46 unmodified lines | |||
| 84 | } else { | 168 | } else { |
| 85 | li->u.log.level = LOGLEVEL_WARNING; | 169 | li->u.log.level = LOGLEVEL_WARNING; |
| 86 | } | 170 | } |
| 87 | if (li->u.log.level > LOGLEVEL_DEBUG) { | 171 | if (li->u.log.level > LOGLEVEL_AUDIT) { |
| 88 | err = -EINVAL; | 172 | err = -EINVAL; |
| 89 | goto err1; | 173 | goto err1; |
| 90 | } | 174 | } |
| @@ -112,6 +196,9 @@ static int nft_log_init(const struct nft_ctx *ctx, · 21 unmodified lines | |||
| 112 | break; | 196 | break; |
| 113 | } | 197 | } |
| 114 | 198 | ||
| 199 | if (li->u.log.level == LOGLEVEL_AUDIT) | ||
| 200 | return 0; | ||
| 201 | |||
| 115 | err = nf_logger_find_get(ctx->family, li->type); | 202 | err = nf_logger_find_get(ctx->family, li->type); |
| 116 | if (err < 0) | 203 | if (err < 0) |
| 117 | goto err1; | 204 | goto err1; |
| @@ -133,6 +220,9 @@ static void nft_log_destroy(const struct nft_ctx *ctx, · 15 unmodified lines | |||
| 133 | if (priv->prefix != nft_log_null_prefix) | 220 | if (priv->prefix != nft_log_null_prefix) |
| 134 | kfree(priv->prefix); | 221 | kfree(priv->prefix); |
| 135 | 222 | ||
| 223 | if (li->u.log.level == LOGLEVEL_AUDIT) | ||
| 224 | return; | ||
| 225 | |||
| 136 | nf_logger_put(ctx->family, li->type); | 226 | nf_logger_put(ctx->family, li->type); |
| 137 | } | 227 | } |
| 138 | 228 | ||