1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Creates audit record for dropped/accepted packets |
4 | * |
5 | * (C) 2010-2011 Thomas Graf <tgraf@redhat.com> |
6 | * (C) 2010-2011 Red Hat, Inc. |
7 | */ |
8 | |
9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
10 | |
11 | #include <linux/audit.h> |
12 | #include <linux/module.h> |
13 | #include <linux/skbuff.h> |
14 | #include <linux/tcp.h> |
15 | #include <linux/udp.h> |
16 | #include <linux/if_arp.h> |
17 | #include <linux/netfilter/x_tables.h> |
18 | #include <linux/netfilter/xt_AUDIT.h> |
19 | #include <linux/netfilter_bridge/ebtables.h> |
20 | #include <net/ipv6.h> |
21 | #include <net/ip.h> |
22 | |
23 | MODULE_LICENSE("GPL" ); |
24 | MODULE_AUTHOR("Thomas Graf <tgraf@redhat.com>" ); |
25 | MODULE_DESCRIPTION("Xtables: creates audit records for dropped/accepted packets" ); |
26 | MODULE_ALIAS("ipt_AUDIT" ); |
27 | MODULE_ALIAS("ip6t_AUDIT" ); |
28 | MODULE_ALIAS("ebt_AUDIT" ); |
29 | MODULE_ALIAS("arpt_AUDIT" ); |
30 | |
31 | static bool audit_ip4(struct audit_buffer *ab, struct sk_buff *skb) |
32 | { |
33 | struct iphdr _iph; |
34 | const struct iphdr *ih; |
35 | |
36 | ih = skb_header_pointer(skb, offset: skb_network_offset(skb), len: sizeof(_iph), buffer: &_iph); |
37 | if (!ih) |
38 | return false; |
39 | |
40 | audit_log_format(ab, fmt: " saddr=%pI4 daddr=%pI4 proto=%hhu" , |
41 | &ih->saddr, &ih->daddr, ih->protocol); |
42 | |
43 | return true; |
44 | } |
45 | |
46 | static bool audit_ip6(struct audit_buffer *ab, struct sk_buff *skb) |
47 | { |
48 | struct ipv6hdr _ip6h; |
49 | const struct ipv6hdr *ih; |
50 | u8 nexthdr; |
51 | __be16 frag_off; |
52 | |
53 | ih = skb_header_pointer(skb, offset: skb_network_offset(skb), len: sizeof(_ip6h), buffer: &_ip6h); |
54 | if (!ih) |
55 | return false; |
56 | |
57 | nexthdr = ih->nexthdr; |
58 | ipv6_skip_exthdr(skb, start: skb_network_offset(skb) + sizeof(_ip6h), nexthdrp: &nexthdr, frag_offp: &frag_off); |
59 | |
60 | audit_log_format(ab, fmt: " saddr=%pI6c daddr=%pI6c proto=%hhu" , |
61 | &ih->saddr, &ih->daddr, nexthdr); |
62 | |
63 | return true; |
64 | } |
65 | |
66 | static unsigned int |
67 | audit_tg(struct sk_buff *skb, const struct xt_action_param *par) |
68 | { |
69 | struct audit_buffer *ab; |
70 | int fam = -1; |
71 | |
72 | if (audit_enabled == AUDIT_OFF) |
73 | goto errout; |
74 | ab = audit_log_start(NULL, GFP_ATOMIC, AUDIT_NETFILTER_PKT); |
75 | if (ab == NULL) |
76 | goto errout; |
77 | |
78 | audit_log_format(ab, fmt: "mark=%#x" , skb->mark); |
79 | |
80 | switch (xt_family(par)) { |
81 | case NFPROTO_BRIDGE: |
82 | switch (eth_hdr(skb)->h_proto) { |
83 | case htons(ETH_P_IP): |
84 | fam = audit_ip4(ab, skb) ? NFPROTO_IPV4 : -1; |
85 | break; |
86 | case htons(ETH_P_IPV6): |
87 | fam = audit_ip6(ab, skb) ? NFPROTO_IPV6 : -1; |
88 | break; |
89 | } |
90 | break; |
91 | case NFPROTO_IPV4: |
92 | fam = audit_ip4(ab, skb) ? NFPROTO_IPV4 : -1; |
93 | break; |
94 | case NFPROTO_IPV6: |
95 | fam = audit_ip6(ab, skb) ? NFPROTO_IPV6 : -1; |
96 | break; |
97 | } |
98 | |
99 | if (fam == -1) |
100 | audit_log_format(ab, fmt: " saddr=? daddr=? proto=-1" ); |
101 | |
102 | audit_log_end(ab); |
103 | |
104 | errout: |
105 | return XT_CONTINUE; |
106 | } |
107 | |
108 | static unsigned int |
109 | audit_tg_ebt(struct sk_buff *skb, const struct xt_action_param *par) |
110 | { |
111 | audit_tg(skb, par); |
112 | return EBT_CONTINUE; |
113 | } |
114 | |
115 | static int audit_tg_check(const struct xt_tgchk_param *par) |
116 | { |
117 | const struct xt_audit_info *info = par->targinfo; |
118 | |
119 | if (info->type > XT_AUDIT_TYPE_MAX) { |
120 | pr_info_ratelimited("Audit type out of range (valid range: 0..%u)\n" , |
121 | XT_AUDIT_TYPE_MAX); |
122 | return -ERANGE; |
123 | } |
124 | |
125 | return 0; |
126 | } |
127 | |
128 | static struct xt_target audit_tg_reg[] __read_mostly = { |
129 | { |
130 | .name = "AUDIT" , |
131 | .family = NFPROTO_UNSPEC, |
132 | .target = audit_tg, |
133 | .targetsize = sizeof(struct xt_audit_info), |
134 | .checkentry = audit_tg_check, |
135 | .me = THIS_MODULE, |
136 | }, |
137 | { |
138 | .name = "AUDIT" , |
139 | .family = NFPROTO_BRIDGE, |
140 | .target = audit_tg_ebt, |
141 | .targetsize = sizeof(struct xt_audit_info), |
142 | .checkentry = audit_tg_check, |
143 | .me = THIS_MODULE, |
144 | }, |
145 | }; |
146 | |
147 | static int __init audit_tg_init(void) |
148 | { |
149 | return xt_register_targets(target: audit_tg_reg, ARRAY_SIZE(audit_tg_reg)); |
150 | } |
151 | |
152 | static void __exit audit_tg_exit(void) |
153 | { |
154 | xt_unregister_targets(target: audit_tg_reg, ARRAY_SIZE(audit_tg_reg)); |
155 | } |
156 | |
157 | module_init(audit_tg_init); |
158 | module_exit(audit_tg_exit); |
159 | |