Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: audit target to record accepted/dropped packets

This patch adds a new netfilter target which creates audit records
for packets traversing a certain chain.

It can be used to record packets which are rejected administraively
as follows:

-N AUDIT_DROP
-A AUDIT_DROP -j AUDIT --type DROP
-A AUDIT_DROP -j DROP

a rule which would typically drop or reject a packet would then
invoke the new chain to record packets before dropping them.

-j AUDIT_DROP

The module is protocol independant and works for iptables, ip6tables
and ebtables.

The following information is logged:
- netfilter hook
- packet length
- incomming/outgoing interface
- MAC src/dst/proto for ethernet packets
- src/dst/protocol address for IPv4/IPv6
- src/dst port for TCP/UDP/UDPLITE
- icmp type/code

Cc: Patrick McHardy <kaber@trash.net>
Cc: Eric Paris <eparis@parisplace.org>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Thomas Graf <tgraf@redhat.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Thomas Graf and committed by
Patrick McHardy
43f393ca d862a662

+247
+1
include/linux/audit.h
··· 103 103 #define AUDIT_BPRM_FCAPS 1321 /* Information about fcaps increasing perms */ 104 104 #define AUDIT_CAPSET 1322 /* Record showing argument to sys_capset */ 105 105 #define AUDIT_MMAP 1323 /* Record showing descriptor and flags in mmap */ 106 + #define AUDIT_NETFILTER_PKT 1324 /* Packets traversing netfilter chains */ 106 107 107 108 #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ 108 109 #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
+1
include/linux/netfilter/Kbuild
··· 9 9 header-y += nfnetlink_log.h 10 10 header-y += nfnetlink_queue.h 11 11 header-y += x_tables.h 12 + header-y += xt_AUDIT.h 12 13 header-y += xt_CHECKSUM.h 13 14 header-y += xt_CLASSIFY.h 14 15 header-y += xt_CONNMARK.h
+30
include/linux/netfilter/xt_AUDIT.h
··· 1 + /* 2 + * Header file for iptables xt_AUDIT target 3 + * 4 + * (C) 2010-2011 Thomas Graf <tgraf@redhat.com> 5 + * (C) 2010-2011 Red Hat, Inc. 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + */ 11 + 12 + #ifndef _XT_AUDIT_TARGET_H 13 + #define _XT_AUDIT_TARGET_H 14 + 15 + #include <linux/types.h> 16 + 17 + enum { 18 + XT_AUDIT_TYPE_ACCEPT = 0, 19 + XT_AUDIT_TYPE_DROP, 20 + XT_AUDIT_TYPE_REJECT, 21 + __XT_AUDIT_TYPE_MAX, 22 + }; 23 + 24 + #define XT_AUDIT_TYPE_MAX (__XT_AUDIT_TYPE_MAX - 1) 25 + 26 + struct xt_audit_info { 27 + __u8 type; /* XT_AUDIT_TYPE_* */ 28 + }; 29 + 30 + #endif /* _XT_AUDIT_TARGET_H */
+10
net/netfilter/Kconfig
··· 326 326 327 327 comment "Xtables targets" 328 328 329 + config NETFILTER_XT_TARGET_AUDIT 330 + tristate "AUDIT target support" 331 + depends on AUDIT 332 + depends on NETFILTER_ADVANCED 333 + ---help--- 334 + This option adds a 'AUDIT' target, which can be used to create 335 + audit records for packets dropped/accepted. 336 + 337 + To compileit as a module, choose M here. If unsure, say N. 338 + 329 339 config NETFILTER_XT_TARGET_CHECKSUM 330 340 tristate "CHECKSUM target support" 331 341 depends on IP_NF_MANGLE || IP6_NF_MANGLE
+1
net/netfilter/Makefile
··· 45 45 obj-$(CONFIG_NETFILTER_XT_CONNMARK) += xt_connmark.o 46 46 47 47 # targets 48 + obj-$(CONFIG_NETFILTER_XT_TARGET_AUDIT) += xt_AUDIT.o 48 49 obj-$(CONFIG_NETFILTER_XT_TARGET_CHECKSUM) += xt_CHECKSUM.o 49 50 obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o 50 51 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
+204
net/netfilter/xt_AUDIT.c
··· 1 + /* 2 + * Creates audit record for dropped/accepted packets 3 + * 4 + * (C) 2010-2011 Thomas Graf <tgraf@redhat.com> 5 + * (C) 2010-2011 Red Hat, Inc. 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + */ 11 + 12 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13 + 14 + #include <linux/audit.h> 15 + #include <linux/module.h> 16 + #include <linux/skbuff.h> 17 + #include <linux/tcp.h> 18 + #include <linux/udp.h> 19 + #include <linux/if_arp.h> 20 + #include <linux/netfilter/x_tables.h> 21 + #include <linux/netfilter/xt_AUDIT.h> 22 + #include <net/ipv6.h> 23 + #include <net/ip.h> 24 + 25 + MODULE_LICENSE("GPL"); 26 + MODULE_AUTHOR("Thomas Graf <tgraf@redhat.com>"); 27 + MODULE_DESCRIPTION("Xtables: creates audit records for dropped/accepted packets"); 28 + MODULE_ALIAS("ipt_AUDIT"); 29 + MODULE_ALIAS("ip6t_AUDIT"); 30 + MODULE_ALIAS("ebt_AUDIT"); 31 + MODULE_ALIAS("arpt_AUDIT"); 32 + 33 + static void audit_proto(struct audit_buffer *ab, struct sk_buff *skb, 34 + unsigned int proto, unsigned int offset) 35 + { 36 + switch (proto) { 37 + case IPPROTO_TCP: 38 + case IPPROTO_UDP: 39 + case IPPROTO_UDPLITE: { 40 + const __be16 *pptr; 41 + __be16 _ports[2]; 42 + 43 + pptr = skb_header_pointer(skb, offset, sizeof(_ports), _ports); 44 + if (pptr == NULL) { 45 + audit_log_format(ab, " truncated=1"); 46 + return; 47 + } 48 + 49 + audit_log_format(ab, " sport=%hu dport=%hu", 50 + ntohs(pptr[0]), ntohs(pptr[1])); 51 + } 52 + break; 53 + 54 + case IPPROTO_ICMP: 55 + case IPPROTO_ICMPV6: { 56 + const u8 *iptr; 57 + u8 _ih[2]; 58 + 59 + iptr = skb_header_pointer(skb, offset, sizeof(_ih), &_ih); 60 + if (iptr == NULL) { 61 + audit_log_format(ab, " truncated=1"); 62 + return; 63 + } 64 + 65 + audit_log_format(ab, " icmptype=%hhu icmpcode=%hhu", 66 + iptr[0], iptr[1]); 67 + 68 + } 69 + break; 70 + } 71 + } 72 + 73 + static void audit_ip4(struct audit_buffer *ab, struct sk_buff *skb) 74 + { 75 + struct iphdr _iph; 76 + const struct iphdr *ih; 77 + 78 + ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); 79 + if (!ih) { 80 + audit_log_format(ab, " truncated=1"); 81 + return; 82 + } 83 + 84 + audit_log_format(ab, " saddr=%pI4 daddr=%pI4 ipid=%hu proto=%hhu", 85 + &ih->saddr, &ih->daddr, ntohs(ih->id), ih->protocol); 86 + 87 + if (ntohs(ih->frag_off) & IP_OFFSET) { 88 + audit_log_format(ab, " frag=1"); 89 + return; 90 + } 91 + 92 + audit_proto(ab, skb, ih->protocol, ih->ihl * 4); 93 + } 94 + 95 + static void audit_ip6(struct audit_buffer *ab, struct sk_buff *skb) 96 + { 97 + struct ipv6hdr _ip6h; 98 + const struct ipv6hdr *ih; 99 + u8 nexthdr; 100 + int offset; 101 + 102 + ih = skb_header_pointer(skb, skb_network_offset(skb), sizeof(_ip6h), &_ip6h); 103 + if (!ih) { 104 + audit_log_format(ab, " truncated=1"); 105 + return; 106 + } 107 + 108 + nexthdr = ih->nexthdr; 109 + offset = ipv6_skip_exthdr(skb, skb_network_offset(skb) + sizeof(_ip6h), 110 + &nexthdr); 111 + 112 + audit_log_format(ab, " saddr=%pI6c daddr=%pI6c proto=%hhu", 113 + &ih->saddr, &ih->daddr, nexthdr); 114 + 115 + if (offset) 116 + audit_proto(ab, skb, nexthdr, offset); 117 + } 118 + 119 + static unsigned int 120 + audit_tg(struct sk_buff *skb, const struct xt_action_param *par) 121 + { 122 + const struct xt_audit_info *info = par->targinfo; 123 + struct audit_buffer *ab; 124 + 125 + ab = audit_log_start(NULL, GFP_ATOMIC, AUDIT_NETFILTER_PKT); 126 + if (ab == NULL) 127 + goto errout; 128 + 129 + audit_log_format(ab, "action=%hhu hook=%u len=%u inif=%s outif=%s", 130 + info->type, par->hooknum, skb->len, 131 + par->in ? par->in->name : "?", 132 + par->out ? par->out->name : "?"); 133 + 134 + if (skb->mark) 135 + audit_log_format(ab, " mark=%#x", skb->mark); 136 + 137 + if (skb->dev && skb->dev->type == ARPHRD_ETHER) { 138 + audit_log_format(ab, " smac=%pM dmac=%pM macproto=0x%04x", 139 + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, 140 + ntohs(eth_hdr(skb)->h_proto)); 141 + 142 + if (par->family == NFPROTO_BRIDGE) { 143 + switch (eth_hdr(skb)->h_proto) { 144 + case __constant_htons(ETH_P_IP): 145 + audit_ip4(ab, skb); 146 + break; 147 + 148 + case __constant_htons(ETH_P_IPV6): 149 + audit_ip6(ab, skb); 150 + break; 151 + } 152 + } 153 + } 154 + 155 + switch (par->family) { 156 + case NFPROTO_IPV4: 157 + audit_ip4(ab, skb); 158 + break; 159 + 160 + case NFPROTO_IPV6: 161 + audit_ip6(ab, skb); 162 + break; 163 + } 164 + 165 + audit_log_end(ab); 166 + 167 + errout: 168 + return XT_CONTINUE; 169 + } 170 + 171 + static int audit_tg_check(const struct xt_tgchk_param *par) 172 + { 173 + const struct xt_audit_info *info = par->targinfo; 174 + 175 + if (info->type > XT_AUDIT_TYPE_MAX) { 176 + pr_info("Audit type out of range (valid range: 0..%hhu)\n", 177 + XT_AUDIT_TYPE_MAX); 178 + return -ERANGE; 179 + } 180 + 181 + return 0; 182 + } 183 + 184 + static struct xt_target audit_tg_reg __read_mostly = { 185 + .name = "AUDIT", 186 + .family = NFPROTO_UNSPEC, 187 + .target = audit_tg, 188 + .targetsize = sizeof(struct xt_audit_info), 189 + .checkentry = audit_tg_check, 190 + .me = THIS_MODULE, 191 + }; 192 + 193 + static int __init audit_tg_init(void) 194 + { 195 + return xt_register_target(&audit_tg_reg); 196 + } 197 + 198 + static void __exit audit_tg_exit(void) 199 + { 200 + xt_unregister_target(&audit_tg_reg); 201 + } 202 + 203 + module_init(audit_tg_init); 204 + module_exit(audit_tg_exit);