diff options
author | Thomas Graf <tgraf@infradead.org> | 2011-01-16 12:10:28 -0500 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2011-01-16 12:10:28 -0500 |
commit | 43f393caec0362abe03c72799d3f342af3973070 (patch) | |
tree | 7ff979877f3d8e725709d7455ef4f977df605d78 | |
parent | d862a6622e9db508d4b28cc7c5bc28bd548cc24e (diff) |
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>
-rw-r--r-- | include/linux/audit.h | 1 | ||||
-rw-r--r-- | include/linux/netfilter/Kbuild | 1 | ||||
-rw-r--r-- | include/linux/netfilter/xt_AUDIT.h | 30 | ||||
-rw-r--r-- | net/netfilter/Kconfig | 10 | ||||
-rw-r--r-- | net/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/netfilter/xt_AUDIT.c | 204 |
6 files changed, 247 insertions, 0 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h index 8b5c0620abf9..ae227dfcf9c6 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -103,6 +103,7 @@ | |||
103 | #define AUDIT_BPRM_FCAPS 1321 /* Information about fcaps increasing perms */ | 103 | #define AUDIT_BPRM_FCAPS 1321 /* Information about fcaps increasing perms */ |
104 | #define AUDIT_CAPSET 1322 /* Record showing argument to sys_capset */ | 104 | #define AUDIT_CAPSET 1322 /* Record showing argument to sys_capset */ |
105 | #define AUDIT_MMAP 1323 /* Record showing descriptor and flags in mmap */ | 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 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ | 108 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ |
108 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ | 109 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ |
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index 9d40effe7ca7..9f11fbc377e2 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild | |||
@@ -9,6 +9,7 @@ header-y += nfnetlink_conntrack.h | |||
9 | header-y += nfnetlink_log.h | 9 | header-y += nfnetlink_log.h |
10 | header-y += nfnetlink_queue.h | 10 | header-y += nfnetlink_queue.h |
11 | header-y += x_tables.h | 11 | header-y += x_tables.h |
12 | header-y += xt_AUDIT.h | ||
12 | header-y += xt_CHECKSUM.h | 13 | header-y += xt_CHECKSUM.h |
13 | header-y += xt_CLASSIFY.h | 14 | header-y += xt_CLASSIFY.h |
14 | header-y += xt_CONNMARK.h | 15 | header-y += xt_CONNMARK.h |
diff --git a/include/linux/netfilter/xt_AUDIT.h b/include/linux/netfilter/xt_AUDIT.h new file mode 100644 index 000000000000..38751d2ea52b --- /dev/null +++ b/include/linux/netfilter/xt_AUDIT.h | |||
@@ -0,0 +1,30 @@ | |||
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 */ | ||
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 1b79353a5d29..93918f022555 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -326,6 +326,16 @@ config NETFILTER_XT_CONNMARK | |||
326 | 326 | ||
327 | comment "Xtables targets" | 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 | config NETFILTER_XT_TARGET_CHECKSUM | 339 | config NETFILTER_XT_TARGET_CHECKSUM |
330 | tristate "CHECKSUM target support" | 340 | tristate "CHECKSUM target support" |
331 | depends on IP_NF_MANGLE || IP6_NF_MANGLE | 341 | depends on IP_NF_MANGLE || IP6_NF_MANGLE |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 441050f31111..401d574bdfd2 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -45,6 +45,7 @@ obj-$(CONFIG_NETFILTER_XT_MARK) += xt_mark.o | |||
45 | obj-$(CONFIG_NETFILTER_XT_CONNMARK) += xt_connmark.o | 45 | obj-$(CONFIG_NETFILTER_XT_CONNMARK) += xt_connmark.o |
46 | 46 | ||
47 | # targets | 47 | # targets |
48 | obj-$(CONFIG_NETFILTER_XT_TARGET_AUDIT) += xt_AUDIT.o | ||
48 | obj-$(CONFIG_NETFILTER_XT_TARGET_CHECKSUM) += xt_CHECKSUM.o | 49 | obj-$(CONFIG_NETFILTER_XT_TARGET_CHECKSUM) += xt_CHECKSUM.o |
49 | obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o | 50 | obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o |
50 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o | 51 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o |
diff --git a/net/netfilter/xt_AUDIT.c b/net/netfilter/xt_AUDIT.c new file mode 100644 index 000000000000..81802d27346e --- /dev/null +++ b/net/netfilter/xt_AUDIT.c | |||
@@ -0,0 +1,204 @@ | |||
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); | ||