diff options
author | Richard Weinberger <richard@nod.at> | 2012-02-10 17:10:52 -0500 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-03-07 11:40:49 -0500 |
commit | 6939c33a757bd006c5e0b8b5fd429fc587a4d0f4 (patch) | |
tree | c635fa7ceeb8a1a80540b45cf9e059ccb98ecdb1 | |
parent | 544d5c7d9f4d1ec4f170bc5bcc522012cb7704bc (diff) |
netfilter: merge ipt_LOG and ip6_LOG into xt_LOG
ipt_LOG and ip6_LOG have a lot of common code, merge them
to reduce duplicate code.
Signed-off-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | include/linux/netfilter/Kbuild | 1 | ||||
-rw-r--r-- | include/linux/netfilter/xt_LOG.h | 19 | ||||
-rw-r--r-- | include/linux/netfilter_ipv4/ipt_LOG.h | 2 | ||||
-rw-r--r-- | include/linux/netfilter_ipv6/ip6t_LOG.h | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter/Kconfig | 9 | ||||
-rw-r--r-- | net/ipv4/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_LOG.c | 516 | ||||
-rw-r--r-- | net/ipv6/netfilter/Kconfig | 9 | ||||
-rw-r--r-- | net/ipv6/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_LOG.c | 527 | ||||
-rw-r--r-- | net/netfilter/Kconfig | 9 | ||||
-rw-r--r-- | net/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/netfilter/xt_LOG.c | 921 |
13 files changed, 955 insertions, 1063 deletions
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index e144f54185c0..aaa72aaa21de 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild | |||
@@ -22,6 +22,7 @@ header-y += xt_CT.h | |||
22 | header-y += xt_DSCP.h | 22 | header-y += xt_DSCP.h |
23 | header-y += xt_IDLETIMER.h | 23 | header-y += xt_IDLETIMER.h |
24 | header-y += xt_LED.h | 24 | header-y += xt_LED.h |
25 | header-y += xt_LOG.h | ||
25 | header-y += xt_MARK.h | 26 | header-y += xt_MARK.h |
26 | header-y += xt_nfacct.h | 27 | header-y += xt_nfacct.h |
27 | header-y += xt_NFLOG.h | 28 | header-y += xt_NFLOG.h |
diff --git a/include/linux/netfilter/xt_LOG.h b/include/linux/netfilter/xt_LOG.h new file mode 100644 index 000000000000..cac079095305 --- /dev/null +++ b/include/linux/netfilter/xt_LOG.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef _XT_LOG_H | ||
2 | #define _XT_LOG_H | ||
3 | |||
4 | /* make sure not to change this without changing nf_log.h:NF_LOG_* (!) */ | ||
5 | #define XT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ | ||
6 | #define XT_LOG_TCPOPT 0x02 /* Log TCP options */ | ||
7 | #define XT_LOG_IPOPT 0x04 /* Log IP options */ | ||
8 | #define XT_LOG_UID 0x08 /* Log UID owning local socket */ | ||
9 | #define XT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ | ||
10 | #define XT_LOG_MACDECODE 0x20 /* Decode MAC header */ | ||
11 | #define XT_LOG_MASK 0x2f | ||
12 | |||
13 | struct xt_log_info { | ||
14 | unsigned char level; | ||
15 | unsigned char logflags; | ||
16 | char prefix[30]; | ||
17 | }; | ||
18 | |||
19 | #endif /* _XT_LOG_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ipt_LOG.h b/include/linux/netfilter_ipv4/ipt_LOG.h index dcdbadf9fd4a..5d8152077d71 100644 --- a/include/linux/netfilter_ipv4/ipt_LOG.h +++ b/include/linux/netfilter_ipv4/ipt_LOG.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef _IPT_LOG_H | 1 | #ifndef _IPT_LOG_H |
2 | #define _IPT_LOG_H | 2 | #define _IPT_LOG_H |
3 | 3 | ||
4 | #warning "Please update iptables, this file will be removed soon!" | ||
5 | |||
4 | /* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ | 6 | /* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ |
5 | #define IPT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ | 7 | #define IPT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ |
6 | #define IPT_LOG_TCPOPT 0x02 /* Log TCP options */ | 8 | #define IPT_LOG_TCPOPT 0x02 /* Log TCP options */ |
diff --git a/include/linux/netfilter_ipv6/ip6t_LOG.h b/include/linux/netfilter_ipv6/ip6t_LOG.h index 9dd5579e02ec..3dd0bc4e0735 100644 --- a/include/linux/netfilter_ipv6/ip6t_LOG.h +++ b/include/linux/netfilter_ipv6/ip6t_LOG.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef _IP6T_LOG_H | 1 | #ifndef _IP6T_LOG_H |
2 | #define _IP6T_LOG_H | 2 | #define _IP6T_LOG_H |
3 | 3 | ||
4 | #warning "Please update iptables, this file will be removed soon!" | ||
5 | |||
4 | /* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ | 6 | /* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ |
5 | #define IP6T_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ | 7 | #define IP6T_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ |
6 | #define IP6T_LOG_TCPOPT 0x02 /* Log TCP options */ | 8 | #define IP6T_LOG_TCPOPT 0x02 /* Log TCP options */ |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 74dfc9e5211f..fcc543cd987a 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -123,15 +123,6 @@ config IP_NF_TARGET_REJECT | |||
123 | 123 | ||
124 | To compile it as a module, choose M here. If unsure, say N. | 124 | To compile it as a module, choose M here. If unsure, say N. |
125 | 125 | ||
126 | config IP_NF_TARGET_LOG | ||
127 | tristate "LOG target support" | ||
128 | default m if NETFILTER_ADVANCED=n | ||
129 | help | ||
130 | This option adds a `LOG' target, which allows you to create rules in | ||
131 | any iptables table which records the packet header to the syslog. | ||
132 | |||
133 | To compile it as a module, choose M here. If unsure, say N. | ||
134 | |||
135 | config IP_NF_TARGET_ULOG | 126 | config IP_NF_TARGET_ULOG |
136 | tristate "ULOG target support" | 127 | tristate "ULOG target support" |
137 | default m if NETFILTER_ADVANCED=n | 128 | default m if NETFILTER_ADVANCED=n |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 213a462b739b..240b68469a7a 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -54,7 +54,6 @@ obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o | |||
54 | # targets | 54 | # targets |
55 | obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o | 55 | obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o |
56 | obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o | 56 | obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o |
57 | obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o | ||
58 | obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o | 57 | obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o |
59 | obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o | 58 | obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o |
60 | obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o | 59 | obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o |
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c deleted file mode 100644 index d76d6c9ed946..000000000000 --- a/net/ipv4/netfilter/ipt_LOG.c +++ /dev/null | |||
@@ -1,516 +0,0 @@ | |||
1 | /* | ||
2 | * This is a module which is used for logging packets. | ||
3 | */ | ||
4 | |||
5 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
6 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <linux/if_arp.h> | ||
17 | #include <linux/ip.h> | ||
18 | #include <net/icmp.h> | ||
19 | #include <net/udp.h> | ||
20 | #include <net/tcp.h> | ||
21 | #include <net/route.h> | ||
22 | |||
23 | #include <linux/netfilter.h> | ||
24 | #include <linux/netfilter/x_tables.h> | ||
25 | #include <linux/netfilter_ipv4/ipt_LOG.h> | ||
26 | #include <net/netfilter/nf_log.h> | ||
27 | #include <net/netfilter/xt_log.h> | ||
28 | |||
29 | MODULE_LICENSE("GPL"); | ||
30 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | ||
31 | MODULE_DESCRIPTION("Xtables: IPv4 packet logging to syslog"); | ||
32 | |||
33 | /* One level of recursion won't kill us */ | ||
34 | static void dump_packet(struct sbuff *m, | ||
35 | const struct nf_loginfo *info, | ||
36 | const struct sk_buff *skb, | ||
37 | unsigned int iphoff) | ||
38 | { | ||
39 | struct iphdr _iph; | ||
40 | const struct iphdr *ih; | ||
41 | unsigned int logflags; | ||
42 | |||
43 | if (info->type == NF_LOG_TYPE_LOG) | ||
44 | logflags = info->u.log.logflags; | ||
45 | else | ||
46 | logflags = NF_LOG_MASK; | ||
47 | |||
48 | ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); | ||
49 | if (ih == NULL) { | ||
50 | sb_add(m, "TRUNCATED"); | ||
51 | return; | ||
52 | } | ||
53 | |||
54 | /* Important fields: | ||
55 | * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ | ||
56 | /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ | ||
57 | sb_add(m, "SRC=%pI4 DST=%pI4 ", | ||
58 | &ih->saddr, &ih->daddr); | ||
59 | |||
60 | /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ | ||
61 | sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", | ||
62 | ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, | ||
63 | ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); | ||
64 | |||
65 | /* Max length: 6 "CE DF MF " */ | ||
66 | if (ntohs(ih->frag_off) & IP_CE) | ||
67 | sb_add(m, "CE "); | ||
68 | if (ntohs(ih->frag_off) & IP_DF) | ||
69 | sb_add(m, "DF "); | ||
70 | if (ntohs(ih->frag_off) & IP_MF) | ||
71 | sb_add(m, "MF "); | ||
72 | |||
73 | /* Max length: 11 "FRAG:65535 " */ | ||
74 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
75 | sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); | ||
76 | |||
77 | if ((logflags & IPT_LOG_IPOPT) && | ||
78 | ih->ihl * 4 > sizeof(struct iphdr)) { | ||
79 | const unsigned char *op; | ||
80 | unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; | ||
81 | unsigned int i, optsize; | ||
82 | |||
83 | optsize = ih->ihl * 4 - sizeof(struct iphdr); | ||
84 | op = skb_header_pointer(skb, iphoff+sizeof(_iph), | ||
85 | optsize, _opt); | ||
86 | if (op == NULL) { | ||
87 | sb_add(m, "TRUNCATED"); | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
92 | sb_add(m, "OPT ("); | ||
93 | for (i = 0; i < optsize; i++) | ||
94 | sb_add(m, "%02X", op[i]); | ||
95 | sb_add(m, ") "); | ||
96 | } | ||
97 | |||
98 | switch (ih->protocol) { | ||
99 | case IPPROTO_TCP: { | ||
100 | struct tcphdr _tcph; | ||
101 | const struct tcphdr *th; | ||
102 | |||
103 | /* Max length: 10 "PROTO=TCP " */ | ||
104 | sb_add(m, "PROTO=TCP "); | ||
105 | |||
106 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
107 | break; | ||
108 | |||
109 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
110 | th = skb_header_pointer(skb, iphoff + ih->ihl * 4, | ||
111 | sizeof(_tcph), &_tcph); | ||
112 | if (th == NULL) { | ||
113 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
114 | skb->len - iphoff - ih->ihl*4); | ||
115 | break; | ||
116 | } | ||
117 | |||
118 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
119 | sb_add(m, "SPT=%u DPT=%u ", | ||
120 | ntohs(th->source), ntohs(th->dest)); | ||
121 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ | ||
122 | if (logflags & IPT_LOG_TCPSEQ) | ||
123 | sb_add(m, "SEQ=%u ACK=%u ", | ||
124 | ntohl(th->seq), ntohl(th->ack_seq)); | ||
125 | /* Max length: 13 "WINDOW=65535 " */ | ||
126 | sb_add(m, "WINDOW=%u ", ntohs(th->window)); | ||
127 | /* Max length: 9 "RES=0x3F " */ | ||
128 | sb_add(m, "RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); | ||
129 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ | ||
130 | if (th->cwr) | ||
131 | sb_add(m, "CWR "); | ||
132 | if (th->ece) | ||
133 | sb_add(m, "ECE "); | ||
134 | if (th->urg) | ||
135 | sb_add(m, "URG "); | ||
136 | if (th->ack) | ||
137 | sb_add(m, "ACK "); | ||
138 | if (th->psh) | ||
139 | sb_add(m, "PSH "); | ||
140 | if (th->rst) | ||
141 | sb_add(m, "RST "); | ||
142 | if (th->syn) | ||
143 | sb_add(m, "SYN "); | ||
144 | if (th->fin) | ||
145 | sb_add(m, "FIN "); | ||
146 | /* Max length: 11 "URGP=65535 " */ | ||
147 | sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); | ||
148 | |||
149 | if ((logflags & IPT_LOG_TCPOPT) && | ||
150 | th->doff * 4 > sizeof(struct tcphdr)) { | ||
151 | unsigned char _opt[4 * 15 - sizeof(struct tcphdr)]; | ||
152 | const unsigned char *op; | ||
153 | unsigned int i, optsize; | ||
154 | |||
155 | optsize = th->doff * 4 - sizeof(struct tcphdr); | ||
156 | op = skb_header_pointer(skb, | ||
157 | iphoff+ih->ihl*4+sizeof(_tcph), | ||
158 | optsize, _opt); | ||
159 | if (op == NULL) { | ||
160 | sb_add(m, "TRUNCATED"); | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
165 | sb_add(m, "OPT ("); | ||
166 | for (i = 0; i < optsize; i++) | ||
167 | sb_add(m, "%02X", op[i]); | ||
168 | sb_add(m, ") "); | ||
169 | } | ||
170 | break; | ||
171 | } | ||
172 | case IPPROTO_UDP: | ||
173 | case IPPROTO_UDPLITE: { | ||
174 | struct udphdr _udph; | ||
175 | const struct udphdr *uh; | ||
176 | |||
177 | if (ih->protocol == IPPROTO_UDP) | ||
178 | /* Max length: 10 "PROTO=UDP " */ | ||
179 | sb_add(m, "PROTO=UDP " ); | ||
180 | else /* Max length: 14 "PROTO=UDPLITE " */ | ||
181 | sb_add(m, "PROTO=UDPLITE "); | ||
182 | |||
183 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
184 | break; | ||
185 | |||
186 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
187 | uh = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
188 | sizeof(_udph), &_udph); | ||
189 | if (uh == NULL) { | ||
190 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
191 | skb->len - iphoff - ih->ihl*4); | ||
192 | break; | ||
193 | } | ||
194 | |||
195 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
196 | sb_add(m, "SPT=%u DPT=%u LEN=%u ", | ||
197 | ntohs(uh->source), ntohs(uh->dest), | ||
198 | ntohs(uh->len)); | ||
199 | break; | ||
200 | } | ||
201 | case IPPROTO_ICMP: { | ||
202 | struct icmphdr _icmph; | ||
203 | const struct icmphdr *ich; | ||
204 | static const size_t required_len[NR_ICMP_TYPES+1] | ||
205 | = { [ICMP_ECHOREPLY] = 4, | ||
206 | [ICMP_DEST_UNREACH] | ||
207 | = 8 + sizeof(struct iphdr), | ||
208 | [ICMP_SOURCE_QUENCH] | ||
209 | = 8 + sizeof(struct iphdr), | ||
210 | [ICMP_REDIRECT] | ||
211 | = 8 + sizeof(struct iphdr), | ||
212 | [ICMP_ECHO] = 4, | ||
213 | [ICMP_TIME_EXCEEDED] | ||
214 | = 8 + sizeof(struct iphdr), | ||
215 | [ICMP_PARAMETERPROB] | ||
216 | = 8 + sizeof(struct iphdr), | ||
217 | [ICMP_TIMESTAMP] = 20, | ||
218 | [ICMP_TIMESTAMPREPLY] = 20, | ||
219 | [ICMP_ADDRESS] = 12, | ||
220 | [ICMP_ADDRESSREPLY] = 12 }; | ||
221 | |||
222 | /* Max length: 11 "PROTO=ICMP " */ | ||
223 | sb_add(m, "PROTO=ICMP "); | ||
224 | |||
225 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
226 | break; | ||
227 | |||
228 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
229 | ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, | ||
230 | sizeof(_icmph), &_icmph); | ||
231 | if (ich == NULL) { | ||
232 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
233 | skb->len - iphoff - ih->ihl*4); | ||
234 | break; | ||
235 | } | ||
236 | |||
237 | /* Max length: 18 "TYPE=255 CODE=255 " */ | ||
238 | sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); | ||
239 | |||
240 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
241 | if (ich->type <= NR_ICMP_TYPES && | ||
242 | required_len[ich->type] && | ||
243 | skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { | ||
244 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
245 | skb->len - iphoff - ih->ihl*4); | ||
246 | break; | ||
247 | } | ||
248 | |||
249 | switch (ich->type) { | ||
250 | case ICMP_ECHOREPLY: | ||
251 | case ICMP_ECHO: | ||
252 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | ||
253 | sb_add(m, "ID=%u SEQ=%u ", | ||
254 | ntohs(ich->un.echo.id), | ||
255 | ntohs(ich->un.echo.sequence)); | ||
256 | break; | ||
257 | |||
258 | case ICMP_PARAMETERPROB: | ||
259 | /* Max length: 14 "PARAMETER=255 " */ | ||
260 | sb_add(m, "PARAMETER=%u ", | ||
261 | ntohl(ich->un.gateway) >> 24); | ||
262 | break; | ||
263 | case ICMP_REDIRECT: | ||
264 | /* Max length: 24 "GATEWAY=255.255.255.255 " */ | ||
265 | sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); | ||
266 | /* Fall through */ | ||
267 | case ICMP_DEST_UNREACH: | ||
268 | case ICMP_SOURCE_QUENCH: | ||
269 | case ICMP_TIME_EXCEEDED: | ||
270 | /* Max length: 3+maxlen */ | ||
271 | if (!iphoff) { /* Only recurse once. */ | ||
272 | sb_add(m, "["); | ||
273 | dump_packet(m, info, skb, | ||
274 | iphoff + ih->ihl*4+sizeof(_icmph)); | ||
275 | sb_add(m, "] "); | ||
276 | } | ||
277 | |||
278 | /* Max length: 10 "MTU=65535 " */ | ||
279 | if (ich->type == ICMP_DEST_UNREACH && | ||
280 | ich->code == ICMP_FRAG_NEEDED) | ||
281 | sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu)); | ||
282 | } | ||
283 | break; | ||
284 | } | ||
285 | /* Max Length */ | ||
286 | case IPPROTO_AH: { | ||
287 | struct ip_auth_hdr _ahdr; | ||
288 | const struct ip_auth_hdr *ah; | ||
289 | |||
290 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
291 | break; | ||
292 | |||
293 | /* Max length: 9 "PROTO=AH " */ | ||
294 | sb_add(m, "PROTO=AH "); | ||
295 | |||
296 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
297 | ah = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
298 | sizeof(_ahdr), &_ahdr); | ||
299 | if (ah == NULL) { | ||
300 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
301 | skb->len - iphoff - ih->ihl*4); | ||
302 | break; | ||
303 | } | ||
304 | |||
305 | /* Length: 15 "SPI=0xF1234567 " */ | ||
306 | sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); | ||
307 | break; | ||
308 | } | ||
309 | case IPPROTO_ESP: { | ||
310 | struct ip_esp_hdr _esph; | ||
311 | const struct ip_esp_hdr *eh; | ||
312 | |||
313 | /* Max length: 10 "PROTO=ESP " */ | ||
314 | sb_add(m, "PROTO=ESP "); | ||
315 | |||
316 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
317 | break; | ||
318 | |||
319 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
320 | eh = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
321 | sizeof(_esph), &_esph); | ||
322 | if (eh == NULL) { | ||
323 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
324 | skb->len - iphoff - ih->ihl*4); | ||
325 | break; | ||
326 | } | ||
327 | |||
328 | /* Length: 15 "SPI=0xF1234567 " */ | ||
329 | sb_add(m, "SPI=0x%x ", ntohl(eh->spi)); | ||
330 | break; | ||
331 | } | ||
332 | /* Max length: 10 "PROTO 255 " */ | ||
333 | default: | ||
334 | sb_add(m, "PROTO=%u ", ih->protocol); | ||
335 | } | ||
336 | |||
337 | /* Max length: 15 "UID=4294967295 " */ | ||
338 | if ((logflags & IPT_LOG_UID) && !iphoff && skb->sk) { | ||
339 | read_lock_bh(&skb->sk->sk_callback_lock); | ||
340 | if (skb->sk->sk_socket && skb->sk->sk_socket->file) | ||
341 | sb_add(m, "UID=%u GID=%u ", | ||
342 | skb->sk->sk_socket->file->f_cred->fsuid, | ||
343 | skb->sk->sk_socket->file->f_cred->fsgid); | ||
344 | read_unlock_bh(&skb->sk->sk_callback_lock); | ||
345 | } | ||
346 | |||
347 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | ||
348 | if (!iphoff && skb->mark) | ||
349 | sb_add(m, "MARK=0x%x ", skb->mark); | ||
350 | |||
351 | /* Proto Max log string length */ | ||
352 | /* IP: 40+46+6+11+127 = 230 */ | ||
353 | /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ | ||
354 | /* UDP: 10+max(25,20) = 35 */ | ||
355 | /* UDPLITE: 14+max(25,20) = 39 */ | ||
356 | /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ | ||
357 | /* ESP: 10+max(25)+15 = 50 */ | ||
358 | /* AH: 9+max(25)+15 = 49 */ | ||
359 | /* unknown: 10 */ | ||
360 | |||
361 | /* (ICMP allows recursion one level deep) */ | ||
362 | /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ | ||
363 | /* maxlen = 230+ 91 + 230 + 252 = 803 */ | ||
364 | } | ||
365 | |||
366 | static void dump_mac_header(struct sbuff *m, | ||
367 | const struct nf_loginfo *info, | ||
368 | const struct sk_buff *skb) | ||
369 | { | ||
370 | struct net_device *dev = skb->dev; | ||
371 | unsigned int logflags = 0; | ||
372 | |||
373 | if (info->type == NF_LOG_TYPE_LOG) | ||
374 | logflags = info->u.log.logflags; | ||
375 | |||
376 | if (!(logflags & IPT_LOG_MACDECODE)) | ||
377 | goto fallback; | ||
378 | |||
379 | switch (dev->type) { | ||
380 | case ARPHRD_ETHER: | ||
381 | sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
382 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
383 | ntohs(eth_hdr(skb)->h_proto)); | ||
384 | return; | ||
385 | default: | ||
386 | break; | ||
387 | } | ||
388 | |||
389 | fallback: | ||
390 | sb_add(m, "MAC="); | ||
391 | if (dev->hard_header_len && | ||
392 | skb->mac_header != skb->network_header) { | ||
393 | const unsigned char *p = skb_mac_header(skb); | ||
394 | unsigned int i; | ||
395 | |||
396 | sb_add(m, "%02x", *p++); | ||
397 | for (i = 1; i < dev->hard_header_len; i++, p++) | ||
398 | sb_add(m, ":%02x", *p); | ||
399 | } | ||
400 | sb_add(m, " "); | ||
401 | } | ||
402 | |||
403 | static struct nf_loginfo default_loginfo = { | ||
404 | .type = NF_LOG_TYPE_LOG, | ||
405 | .u = { | ||
406 | .log = { | ||
407 | .level = 5, | ||
408 | .logflags = NF_LOG_MASK, | ||
409 | }, | ||
410 | }, | ||
411 | }; | ||
412 | |||
413 | static void | ||
414 | ipt_log_packet(u_int8_t pf, | ||
415 | unsigned int hooknum, | ||
416 | const struct sk_buff *skb, | ||
417 | const struct net_device *in, | ||
418 | const struct net_device *out, | ||
419 | const struct nf_loginfo *loginfo, | ||
420 | const char *prefix) | ||
421 | { | ||
422 | struct sbuff *m = sb_open(); | ||
423 | |||
424 | if (!loginfo) | ||
425 | loginfo = &default_loginfo; | ||
426 | |||
427 | sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, | ||
428 | prefix, | ||
429 | in ? in->name : "", | ||
430 | out ? out->name : ""); | ||
431 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
432 | if (skb->nf_bridge) { | ||
433 | const struct net_device *physindev; | ||
434 | const struct net_device *physoutdev; | ||
435 | |||
436 | physindev = skb->nf_bridge->physindev; | ||
437 | if (physindev && in != physindev) | ||
438 | sb_add(m, "PHYSIN=%s ", physindev->name); | ||
439 | physoutdev = skb->nf_bridge->physoutdev; | ||
440 | if (physoutdev && out != physoutdev) | ||
441 | sb_add(m, "PHYSOUT=%s ", physoutdev->name); | ||
442 | } | ||
443 | #endif | ||
444 | |||
445 | if (in != NULL) | ||
446 | dump_mac_header(m, loginfo, skb); | ||
447 | |||
448 | dump_packet(m, loginfo, skb, 0); | ||
449 | |||
450 | sb_close(m); | ||
451 | } | ||
452 | |||
453 | static unsigned int | ||
454 | log_tg(struct sk_buff *skb, const struct xt_action_param *par) | ||
455 | { | ||
456 | const struct ipt_log_info *loginfo = par->targinfo; | ||
457 | struct nf_loginfo li; | ||
458 | |||
459 | li.type = NF_LOG_TYPE_LOG; | ||
460 | li.u.log.level = loginfo->level; | ||
461 | li.u.log.logflags = loginfo->logflags; | ||
462 | |||
463 | ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in, par->out, &li, | ||
464 | loginfo->prefix); | ||
465 | return XT_CONTINUE; | ||
466 | } | ||
467 | |||
468 | static int log_tg_check(const struct xt_tgchk_param *par) | ||
469 | { | ||
470 | const struct ipt_log_info *loginfo = par->targinfo; | ||
471 | |||
472 | if (loginfo->level >= 8) { | ||
473 | pr_debug("level %u >= 8\n", loginfo->level); | ||
474 | return -EINVAL; | ||
475 | } | ||
476 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { | ||
477 | pr_debug("prefix is not null-terminated\n"); | ||
478 | return -EINVAL; | ||
479 | } | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static struct xt_target log_tg_reg __read_mostly = { | ||
484 | .name = "LOG", | ||
485 | .family = NFPROTO_IPV4, | ||
486 | .target = log_tg, | ||
487 | .targetsize = sizeof(struct ipt_log_info), | ||
488 | .checkentry = log_tg_check, | ||
489 | .me = THIS_MODULE, | ||
490 | }; | ||
491 | |||
492 | static struct nf_logger ipt_log_logger __read_mostly = { | ||
493 | .name = "ipt_LOG", | ||
494 | .logfn = &ipt_log_packet, | ||
495 | .me = THIS_MODULE, | ||
496 | }; | ||
497 | |||
498 | static int __init log_tg_init(void) | ||
499 | { | ||
500 | int ret; | ||
501 | |||
502 | ret = xt_register_target(&log_tg_reg); | ||
503 | if (ret < 0) | ||
504 | return ret; | ||
505 | nf_log_register(NFPROTO_IPV4, &ipt_log_logger); | ||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | static void __exit log_tg_exit(void) | ||
510 | { | ||
511 | nf_log_unregister(&ipt_log_logger); | ||
512 | xt_unregister_target(&log_tg_reg); | ||
513 | } | ||
514 | |||
515 | module_init(log_tg_init); | ||
516 | module_exit(log_tg_exit); | ||
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 9a68fb5b9e77..d33cddd16fbb 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -154,15 +154,6 @@ config IP6_NF_TARGET_HL | |||
154 | (e.g. when running oldconfig). It selects | 154 | (e.g. when running oldconfig). It selects |
155 | CONFIG_NETFILTER_XT_TARGET_HL. | 155 | CONFIG_NETFILTER_XT_TARGET_HL. |
156 | 156 | ||
157 | config IP6_NF_TARGET_LOG | ||
158 | tristate "LOG target support" | ||
159 | default m if NETFILTER_ADVANCED=n | ||
160 | help | ||
161 | This option adds a `LOG' target, which allows you to create rules in | ||
162 | any iptables table which records the packet header to the syslog. | ||
163 | |||
164 | To compile it as a module, choose M here. If unsure, say N. | ||
165 | |||
166 | config IP6_NF_FILTER | 157 | config IP6_NF_FILTER |
167 | tristate "Packet filtering" | 158 | tristate "Packet filtering" |
168 | default m if NETFILTER_ADVANCED=n | 159 | default m if NETFILTER_ADVANCED=n |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 2eaed96db02c..d4dfd0a21097 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -31,5 +31,4 @@ obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o | |||
31 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o | 31 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o |
32 | 32 | ||
33 | # targets | 33 | # targets |
34 | obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o | ||
35 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o | 34 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o |
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c deleted file mode 100644 index e6af8d72f26b..000000000000 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ /dev/null | |||
@@ -1,527 +0,0 @@ | |||
1 | /* | ||
2 | * This is a module which is used for logging packets. | ||
3 | */ | ||
4 | |||
5 | /* (C) 2001 Jan Rekorajski <baggins@pld.org.pl> | ||
6 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/if_arp.h> | ||
16 | #include <linux/ip.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/icmpv6.h> | ||
19 | #include <net/udp.h> | ||
20 | #include <net/tcp.h> | ||
21 | #include <net/ipv6.h> | ||
22 | #include <linux/netfilter.h> | ||
23 | #include <linux/netfilter/x_tables.h> | ||
24 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
25 | #include <net/netfilter/nf_log.h> | ||
26 | #include <net/netfilter/xt_log.h> | ||
27 | |||
28 | MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>"); | ||
29 | MODULE_DESCRIPTION("Xtables: IPv6 packet logging to syslog"); | ||
30 | MODULE_LICENSE("GPL"); | ||
31 | |||
32 | struct in_device; | ||
33 | #include <net/route.h> | ||
34 | #include <linux/netfilter_ipv6/ip6t_LOG.h> | ||
35 | |||
36 | /* One level of recursion won't kill us */ | ||
37 | static void dump_packet(struct sbuff *m, | ||
38 | const struct nf_loginfo *info, | ||
39 | const struct sk_buff *skb, unsigned int ip6hoff, | ||
40 | int recurse) | ||
41 | { | ||
42 | u_int8_t currenthdr; | ||
43 | int fragment; | ||
44 | struct ipv6hdr _ip6h; | ||
45 | const struct ipv6hdr *ih; | ||
46 | unsigned int ptr; | ||
47 | unsigned int hdrlen = 0; | ||
48 | unsigned int logflags; | ||
49 | |||
50 | if (info->type == NF_LOG_TYPE_LOG) | ||
51 | logflags = info->u.log.logflags; | ||
52 | else | ||
53 | logflags = NF_LOG_MASK; | ||
54 | |||
55 | ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); | ||
56 | if (ih == NULL) { | ||
57 | sb_add(m, "TRUNCATED"); | ||
58 | return; | ||
59 | } | ||
60 | |||
61 | /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ | ||
62 | sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); | ||
63 | |||
64 | /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ | ||
65 | sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", | ||
66 | ntohs(ih->payload_len) + sizeof(struct ipv6hdr), | ||
67 | (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, | ||
68 | ih->hop_limit, | ||
69 | (ntohl(*(__be32 *)ih) & 0x000fffff)); | ||
70 | |||
71 | fragment = 0; | ||
72 | ptr = ip6hoff + sizeof(struct ipv6hdr); | ||
73 | currenthdr = ih->nexthdr; | ||
74 | while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) { | ||
75 | struct ipv6_opt_hdr _hdr; | ||
76 | const struct ipv6_opt_hdr *hp; | ||
77 | |||
78 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | ||
79 | if (hp == NULL) { | ||
80 | sb_add(m, "TRUNCATED"); | ||
81 | return; | ||
82 | } | ||
83 | |||
84 | /* Max length: 48 "OPT (...) " */ | ||
85 | if (logflags & IP6T_LOG_IPOPT) | ||
86 | sb_add(m, "OPT ( "); | ||
87 | |||
88 | switch (currenthdr) { | ||
89 | case IPPROTO_FRAGMENT: { | ||
90 | struct frag_hdr _fhdr; | ||
91 | const struct frag_hdr *fh; | ||
92 | |||
93 | sb_add(m, "FRAG:"); | ||
94 | fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), | ||
95 | &_fhdr); | ||
96 | if (fh == NULL) { | ||
97 | sb_add(m, "TRUNCATED "); | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | /* Max length: 6 "65535 " */ | ||
102 | sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); | ||
103 | |||
104 | /* Max length: 11 "INCOMPLETE " */ | ||
105 | if (fh->frag_off & htons(0x0001)) | ||
106 | sb_add(m, "INCOMPLETE "); | ||
107 | |||
108 | sb_add(m, "ID:%08x ", ntohl(fh->identification)); | ||
109 | |||
110 | if (ntohs(fh->frag_off) & 0xFFF8) | ||
111 | fragment = 1; | ||
112 | |||
113 | hdrlen = 8; | ||
114 | |||
115 | break; | ||
116 | } | ||
117 | case IPPROTO_DSTOPTS: | ||
118 | case IPPROTO_ROUTING: | ||
119 | case IPPROTO_HOPOPTS: | ||
120 | if (fragment) { | ||
121 | if (logflags & IP6T_LOG_IPOPT) | ||
122 | sb_add(m, ")"); | ||
123 | return; | ||
124 | } | ||
125 | hdrlen = ipv6_optlen(hp); | ||
126 | break; | ||
127 | /* Max Length */ | ||
128 | case IPPROTO_AH: | ||
129 | if (logflags & IP6T_LOG_IPOPT) { | ||
130 | struct ip_auth_hdr _ahdr; | ||
131 | const struct ip_auth_hdr *ah; | ||
132 | |||
133 | /* Max length: 3 "AH " */ | ||
134 | sb_add(m, "AH "); | ||
135 | |||
136 | if (fragment) { | ||
137 | sb_add(m, ")"); | ||
138 | return; | ||
139 | } | ||
140 | |||
141 | ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), | ||
142 | &_ahdr); | ||
143 | if (ah == NULL) { | ||
144 | /* | ||
145 | * Max length: 26 "INCOMPLETE [65535 | ||
146 | * bytes] )" | ||
147 | */ | ||
148 | sb_add(m, "INCOMPLETE [%u bytes] )", | ||
149 | skb->len - ptr); | ||
150 | return; | ||
151 | } | ||
152 | |||
153 | /* Length: 15 "SPI=0xF1234567 */ | ||
154 | sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); | ||
155 | |||
156 | } | ||
157 | |||
158 | hdrlen = (hp->hdrlen+2)<<2; | ||
159 | break; | ||
160 | case IPPROTO_ESP: | ||
161 | if (logflags & IP6T_LOG_IPOPT) { | ||
162 | struct ip_esp_hdr _esph; | ||
163 | const struct ip_esp_hdr *eh; | ||
164 | |||
165 | /* Max length: 4 "ESP " */ | ||
166 | sb_add(m, "ESP "); | ||
167 | |||
168 | if (fragment) { | ||
169 | sb_add(m, ")"); | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * Max length: 26 "INCOMPLETE [65535 bytes] )" | ||
175 | */ | ||
176 | eh = skb_header_pointer(skb, ptr, sizeof(_esph), | ||
177 | &_esph); | ||
178 | if (eh == NULL) { | ||
179 | sb_add(m, "INCOMPLETE [%u bytes] )", | ||
180 | skb->len - ptr); | ||
181 | return; | ||
182 | } | ||
183 | |||
184 | /* Length: 16 "SPI=0xF1234567 )" */ | ||
185 | sb_add(m, "SPI=0x%x )", ntohl(eh->spi) ); | ||
186 | |||
187 | } | ||
188 | return; | ||
189 | default: | ||
190 | /* Max length: 20 "Unknown Ext Hdr 255" */ | ||
191 | sb_add(m, "Unknown Ext Hdr %u", currenthdr); | ||
192 | return; | ||
193 | } | ||
194 | if (logflags & IP6T_LOG_IPOPT) | ||
195 | sb_add(m, ") "); | ||
196 | |||
197 | currenthdr = hp->nexthdr; | ||
198 | ptr += hdrlen; | ||
199 | } | ||
200 | |||
201 | switch (currenthdr) { | ||
202 | case IPPROTO_TCP: { | ||
203 | struct tcphdr _tcph; | ||
204 | const struct tcphdr *th; | ||
205 | |||
206 | /* Max length: 10 "PROTO=TCP " */ | ||
207 | sb_add(m, "PROTO=TCP "); | ||
208 | |||
209 | if (fragment) | ||
210 | break; | ||
211 | |||
212 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
213 | th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph); | ||
214 | if (th == NULL) { | ||
215 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); | ||
216 | return; | ||
217 | } | ||
218 | |||
219 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
220 | sb_add(m, "SPT=%u DPT=%u ", | ||
221 | ntohs(th->source), ntohs(th->dest)); | ||
222 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ | ||
223 | if (logflags & IP6T_LOG_TCPSEQ) | ||
224 | sb_add(m, "SEQ=%u ACK=%u ", | ||
225 | ntohl(th->seq), ntohl(th->ack_seq)); | ||
226 | /* Max length: 13 "WINDOW=65535 " */ | ||
227 | sb_add(m, "WINDOW=%u ", ntohs(th->window)); | ||
228 | /* Max length: 9 "RES=0x3C " */ | ||
229 | sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); | ||
230 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ | ||
231 | if (th->cwr) | ||
232 | sb_add(m, "CWR "); | ||
233 | if (th->ece) | ||
234 | sb_add(m, "ECE "); | ||
235 | if (th->urg) | ||
236 | sb_add(m, "URG "); | ||
237 | if (th->ack) | ||
238 | sb_add(m, "ACK "); | ||
239 | if (th->psh) | ||
240 | sb_add(m, "PSH "); | ||
241 | if (th->rst) | ||
242 | sb_add(m, "RST "); | ||
243 | if (th->syn) | ||
244 | sb_add(m, "SYN "); | ||
245 | if (th->fin) | ||
246 | sb_add(m, "FIN "); | ||
247 | /* Max length: 11 "URGP=65535 " */ | ||
248 | sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); | ||
249 | |||
250 | if ((logflags & IP6T_LOG_TCPOPT) && | ||
251 | th->doff * 4 > sizeof(struct tcphdr)) { | ||
252 | u_int8_t _opt[60 - sizeof(struct tcphdr)]; | ||
253 | const u_int8_t *op; | ||
254 | unsigned int i; | ||
255 | unsigned int optsize = th->doff * 4 | ||
256 | - sizeof(struct tcphdr); | ||
257 | |||
258 | op = skb_header_pointer(skb, | ||
259 | ptr + sizeof(struct tcphdr), | ||
260 | optsize, _opt); | ||
261 | if (op == NULL) { | ||
262 | sb_add(m, "OPT (TRUNCATED)"); | ||
263 | return; | ||
264 | } | ||
265 | |||
266 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
267 | sb_add(m, "OPT ("); | ||
268 | for (i =0; i < optsize; i++) | ||
269 | sb_add(m, "%02X", op[i]); | ||
270 | sb_add(m, ") "); | ||
271 | } | ||
272 | break; | ||
273 | } | ||
274 | case IPPROTO_UDP: | ||
275 | case IPPROTO_UDPLITE: { | ||
276 | struct udphdr _udph; | ||
277 | const struct udphdr *uh; | ||
278 | |||
279 | if (currenthdr == IPPROTO_UDP) | ||
280 | /* Max length: 10 "PROTO=UDP " */ | ||
281 | sb_add(m, "PROTO=UDP " ); | ||
282 | else /* Max length: 14 "PROTO=UDPLITE " */ | ||
283 | sb_add(m, "PROTO=UDPLITE "); | ||
284 | |||
285 | if (fragment) | ||
286 | break; | ||
287 | |||
288 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
289 | uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph); | ||
290 | if (uh == NULL) { | ||
291 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); | ||
292 | return; | ||
293 | } | ||
294 | |||
295 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
296 | sb_add(m, "SPT=%u DPT=%u LEN=%u ", | ||
297 | ntohs(uh->source), ntohs(uh->dest), | ||
298 | ntohs(uh->len)); | ||
299 | break; | ||
300 | } | ||
301 | case IPPROTO_ICMPV6: { | ||
302 | struct icmp6hdr _icmp6h; | ||
303 | const struct icmp6hdr *ic; | ||
304 | |||
305 | /* Max length: 13 "PROTO=ICMPv6 " */ | ||
306 | sb_add(m, "PROTO=ICMPv6 "); | ||
307 | |||
308 | if (fragment) | ||
309 | break; | ||
310 | |||
311 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
312 | ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); | ||
313 | if (ic == NULL) { | ||
314 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); | ||
315 | return; | ||
316 | } | ||
317 | |||
318 | /* Max length: 18 "TYPE=255 CODE=255 " */ | ||
319 | sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); | ||
320 | |||
321 | switch (ic->icmp6_type) { | ||
322 | case ICMPV6_ECHO_REQUEST: | ||
323 | case ICMPV6_ECHO_REPLY: | ||
324 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | ||
325 | sb_add(m, "ID=%u SEQ=%u ", | ||
326 | ntohs(ic->icmp6_identifier), | ||
327 | ntohs(ic->icmp6_sequence)); | ||
328 | break; | ||
329 | case ICMPV6_MGM_QUERY: | ||
330 | case ICMPV6_MGM_REPORT: | ||
331 | case ICMPV6_MGM_REDUCTION: | ||
332 | break; | ||
333 | |||
334 | case ICMPV6_PARAMPROB: | ||
335 | /* Max length: 17 "POINTER=ffffffff " */ | ||
336 | sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer)); | ||
337 | /* Fall through */ | ||
338 | case ICMPV6_DEST_UNREACH: | ||
339 | case ICMPV6_PKT_TOOBIG: | ||
340 | case ICMPV6_TIME_EXCEED: | ||
341 | /* Max length: 3+maxlen */ | ||
342 | if (recurse) { | ||
343 | sb_add(m, "["); | ||
344 | dump_packet(m, info, skb, | ||
345 | ptr + sizeof(_icmp6h), 0); | ||
346 | sb_add(m, "] "); | ||
347 | } | ||
348 | |||
349 | /* Max length: 10 "MTU=65535 " */ | ||
350 | if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) | ||
351 | sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu)); | ||
352 | } | ||
353 | break; | ||
354 | } | ||
355 | /* Max length: 10 "PROTO=255 " */ | ||
356 | default: | ||
357 | sb_add(m, "PROTO=%u ", currenthdr); | ||
358 | } | ||
359 | |||
360 | /* Max length: 15 "UID=4294967295 " */ | ||
361 | if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) { | ||
362 | read_lock_bh(&skb->sk->sk_callback_lock); | ||
363 | if (skb->sk->sk_socket && skb->sk->sk_socket->file) | ||
364 | sb_add(m, "UID=%u GID=%u ", | ||
365 | skb->sk->sk_socket->file->f_cred->fsuid, | ||
366 | skb->sk->sk_socket->file->f_cred->fsgid); | ||
367 | read_unlock_bh(&skb->sk->sk_callback_lock); | ||
368 | } | ||
369 | |||
370 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | ||
371 | if (!recurse && skb->mark) | ||
372 | sb_add(m, "MARK=0x%x ", skb->mark); | ||
373 | } | ||
374 | |||
375 | static void dump_mac_header(struct sbuff *m, | ||
376 | const struct nf_loginfo *info, | ||
377 | const struct sk_buff *skb) | ||
378 | { | ||
379 | struct net_device *dev = skb->dev; | ||
380 | unsigned int logflags = 0; | ||
381 | |||
382 | if (info->type == NF_LOG_TYPE_LOG) | ||
383 | logflags = info->u.log.logflags; | ||
384 | |||
385 | if (!(logflags & IP6T_LOG_MACDECODE)) | ||
386 | goto fallback; | ||
387 | |||
388 | switch (dev->type) { | ||
389 | case ARPHRD_ETHER: | ||
390 | sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
391 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
392 | ntohs(eth_hdr(skb)->h_proto)); | ||
393 | return; | ||
394 | default: | ||
395 | break; | ||
396 | } | ||
397 | |||
398 | fallback: | ||
399 | sb_add(m, "MAC="); | ||
400 | if (dev->hard_header_len && | ||
401 | skb->mac_header != skb->network_header) { | ||
402 | const unsigned char *p = skb_mac_header(skb); | ||
403 | unsigned int len = dev->hard_header_len; | ||
404 | unsigned int i; | ||
405 | |||
406 | if (dev->type == ARPHRD_SIT && | ||
407 | (p -= ETH_HLEN) < skb->head) | ||
408 | p = NULL; | ||
409 | |||
410 | if (p != NULL) { | ||
411 | sb_add(m, "%02x", *p++); | ||
412 | for (i = 1; i < len; i++) | ||
413 | sb_add(m, ":%02x", *p++); | ||
414 | } | ||
415 | sb_add(m, " "); | ||
416 | |||
417 | if (dev->type == ARPHRD_SIT) { | ||
418 | const struct iphdr *iph = | ||
419 | (struct iphdr *)skb_mac_header(skb); | ||
420 | sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr); | ||
421 | } | ||
422 | } else | ||
423 | sb_add(m, " "); | ||
424 | } | ||
425 | |||
426 | static struct nf_loginfo default_loginfo = { | ||
427 | .type = NF_LOG_TYPE_LOG, | ||
428 | .u = { | ||
429 | .log = { | ||
430 | .level = 5, | ||
431 | .logflags = NF_LOG_MASK, | ||
432 | }, | ||
433 | }, | ||
434 | }; | ||
435 | |||
436 | static void | ||
437 | ip6t_log_packet(u_int8_t pf, | ||
438 | unsigned int hooknum, | ||
439 | const struct sk_buff *skb, | ||
440 | const struct net_device *in, | ||
441 | const struct net_device *out, | ||
442 | const struct nf_loginfo *loginfo, | ||
443 | const char *prefix) | ||
444 | { | ||
445 | struct sbuff *m = sb_open(); | ||
446 | |||
447 | if (!loginfo) | ||
448 | loginfo = &default_loginfo; | ||
449 | |||
450 | sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, | ||
451 | prefix, | ||
452 | in ? in->name : "", | ||
453 | out ? out->name : ""); | ||
454 | |||
455 | if (in != NULL) | ||
456 | dump_mac_header(m, loginfo, skb); | ||
457 | |||
458 | dump_packet(m, loginfo, skb, skb_network_offset(skb), 1); | ||
459 | |||
460 | sb_close(m); | ||
461 | } | ||
462 | |||
463 | static unsigned int | ||
464 | log_tg6(struct sk_buff *skb, const struct xt_action_param *par) | ||
465 | { | ||
466 | const struct ip6t_log_info *loginfo = par->targinfo; | ||
467 | struct nf_loginfo li; | ||
468 | |||
469 | li.type = NF_LOG_TYPE_LOG; | ||
470 | li.u.log.level = loginfo->level; | ||
471 | li.u.log.logflags = loginfo->logflags; | ||
472 | |||
473 | ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in, par->out, | ||
474 | &li, loginfo->prefix); | ||
475 | return XT_CONTINUE; | ||
476 | } | ||
477 | |||
478 | |||
479 | static int log_tg6_check(const struct xt_tgchk_param *par) | ||
480 | { | ||
481 | const struct ip6t_log_info *loginfo = par->targinfo; | ||
482 | |||
483 | if (loginfo->level >= 8) { | ||
484 | pr_debug("level %u >= 8\n", loginfo->level); | ||
485 | return -EINVAL; | ||
486 | } | ||
487 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { | ||
488 | pr_debug("prefix not null-terminated\n"); | ||
489 | return -EINVAL; | ||
490 | } | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static struct xt_target log_tg6_reg __read_mostly = { | ||
495 | .name = "LOG", | ||
496 | .family = NFPROTO_IPV6, | ||
497 | .target = log_tg6, | ||
498 | .targetsize = sizeof(struct ip6t_log_info), | ||
499 | .checkentry = log_tg6_check, | ||
500 | .me = THIS_MODULE, | ||
501 | }; | ||
502 | |||
503 | static struct nf_logger ip6t_logger __read_mostly = { | ||
504 | .name = "ip6t_LOG", | ||
505 | .logfn = &ip6t_log_packet, | ||
506 | .me = THIS_MODULE, | ||
507 | }; | ||
508 | |||
509 | static int __init log_tg6_init(void) | ||
510 | { | ||
511 | int ret; | ||
512 | |||
513 | ret = xt_register_target(&log_tg6_reg); | ||
514 | if (ret < 0) | ||
515 | return ret; | ||
516 | nf_log_register(NFPROTO_IPV6, &ip6t_logger); | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static void __exit log_tg6_exit(void) | ||
521 | { | ||
522 | nf_log_unregister(&ip6t_logger); | ||
523 | xt_unregister_target(&log_tg6_reg); | ||
524 | } | ||
525 | |||
526 | module_init(log_tg6_init); | ||
527 | module_exit(log_tg6_exit); | ||
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f8ac4ef0b794..b895d8b13215 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -524,6 +524,15 @@ config NETFILTER_XT_TARGET_LED | |||
524 | For more information on the LEDs available on your system, see | 524 | For more information on the LEDs available on your system, see |
525 | Documentation/leds/leds-class.txt | 525 | Documentation/leds/leds-class.txt |
526 | 526 | ||
527 | config NETFILTER_XT_TARGET_LOG | ||
528 | tristate "LOG target support" | ||
529 | default m if NETFILTER_ADVANCED=n | ||
530 | help | ||
531 | This option adds a `LOG' target, which allows you to create rules in | ||
532 | any iptables table which records the packet header to the syslog. | ||
533 | |||
534 | To compile it as a module, choose M here. If unsure, say N. | ||
535 | |||
527 | config NETFILTER_XT_TARGET_MARK | 536 | config NETFILTER_XT_TARGET_MARK |
528 | tristate '"MARK" target support' | 537 | tristate '"MARK" target support' |
529 | depends on NETFILTER_ADVANCED | 538 | depends on NETFILTER_ADVANCED |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 40f4c3d636c5..a28c2a6563f8 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -58,6 +58,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o | |||
58 | obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o | 58 | obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o |
59 | obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o | 59 | obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o |
60 | obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o | 60 | obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o |
61 | obj-$(CONFIG_NETFILTER_XT_TARGET_LOG) += xt_LOG.o | ||
61 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o | 62 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o |
62 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o | 63 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o |
63 | obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o | 64 | obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o |
diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c new file mode 100644 index 000000000000..1595608a892d --- /dev/null +++ b/net/netfilter/xt_LOG.c | |||
@@ -0,0 +1,921 @@ | |||
1 | /* | ||
2 | * This is a module which is used for logging packets. | ||
3 | */ | ||
4 | |||
5 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
6 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/spinlock.h> | ||
16 | #include <linux/skbuff.h> | ||
17 | #include <linux/if_arp.h> | ||
18 | #include <linux/ip.h> | ||
19 | #include <net/ipv6.h> | ||
20 | #include <net/icmp.h> | ||
21 | #include <net/udp.h> | ||
22 | #include <net/tcp.h> | ||
23 | #include <net/route.h> | ||
24 | |||
25 | #include <linux/netfilter.h> | ||
26 | #include <linux/netfilter/x_tables.h> | ||
27 | #include <linux/netfilter/xt_LOG.h> | ||
28 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
29 | #include <net/netfilter/nf_log.h> | ||
30 | #include <net/netfilter/xt_log.h> | ||
31 | |||
32 | static struct nf_loginfo default_loginfo = { | ||
33 | .type = NF_LOG_TYPE_LOG, | ||
34 | .u = { | ||
35 | .log = { | ||
36 | .level = 5, | ||
37 | .logflags = NF_LOG_MASK, | ||
38 | }, | ||
39 | }, | ||
40 | }; | ||
41 | |||
42 | static int dump_udp_header(struct sbuff *m, const struct sk_buff *skb, | ||
43 | u8 proto, int fragment, unsigned int offset) | ||
44 | { | ||
45 | struct udphdr _udph; | ||
46 | const struct udphdr *uh; | ||
47 | |||
48 | if (proto == IPPROTO_UDP) | ||
49 | /* Max length: 10 "PROTO=UDP " */ | ||
50 | sb_add(m, "PROTO=UDP "); | ||
51 | else /* Max length: 14 "PROTO=UDPLITE " */ | ||
52 | sb_add(m, "PROTO=UDPLITE "); | ||
53 | |||
54 | if (fragment) | ||
55 | goto out; | ||
56 | |||
57 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
58 | uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); | ||
59 | if (uh == NULL) { | ||
60 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); | ||
61 | |||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
66 | sb_add(m, "SPT=%u DPT=%u LEN=%u ", ntohs(uh->source), ntohs(uh->dest), | ||
67 | ntohs(uh->len)); | ||
68 | |||
69 | out: | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int dump_tcp_header(struct sbuff *m, const struct sk_buff *skb, | ||
74 | u8 proto, int fragment, unsigned int offset, | ||
75 | unsigned int logflags) | ||
76 | { | ||
77 | struct tcphdr _tcph; | ||
78 | const struct tcphdr *th; | ||
79 | |||
80 | /* Max length: 10 "PROTO=TCP " */ | ||
81 | sb_add(m, "PROTO=TCP "); | ||
82 | |||
83 | if (fragment) | ||
84 | return 0; | ||
85 | |||
86 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
87 | th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); | ||
88 | if (th == NULL) { | ||
89 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); | ||
90 | return 1; | ||
91 | } | ||
92 | |||
93 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
94 | sb_add(m, "SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest)); | ||
95 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ | ||
96 | if (logflags & XT_LOG_TCPSEQ) | ||
97 | sb_add(m, "SEQ=%u ACK=%u ", ntohl(th->seq), ntohl(th->ack_seq)); | ||
98 | |||
99 | /* Max length: 13 "WINDOW=65535 " */ | ||
100 | sb_add(m, "WINDOW=%u ", ntohs(th->window)); | ||
101 | /* Max length: 9 "RES=0x3C " */ | ||
102 | sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & | ||
103 | TCP_RESERVED_BITS) >> 22)); | ||
104 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ | ||
105 | if (th->cwr) | ||
106 | sb_add(m, "CWR "); | ||
107 | if (th->ece) | ||
108 | sb_add(m, "ECE "); | ||
109 | if (th->urg) | ||
110 | sb_add(m, "URG "); | ||
111 | if (th->ack) | ||
112 | sb_add(m, "ACK "); | ||
113 | if (th->psh) | ||
114 | sb_add(m, "PSH "); | ||
115 | if (th->rst) | ||
116 | sb_add(m, "RST "); | ||
117 | if (th->syn) | ||
118 | sb_add(m, "SYN "); | ||
119 | if (th->fin) | ||
120 | sb_add(m, "FIN "); | ||
121 | /* Max length: 11 "URGP=65535 " */ | ||
122 | sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); | ||
123 | |||
124 | if ((logflags & XT_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) { | ||
125 | u_int8_t _opt[60 - sizeof(struct tcphdr)]; | ||
126 | const u_int8_t *op; | ||
127 | unsigned int i; | ||
128 | unsigned int optsize = th->doff*4 - sizeof(struct tcphdr); | ||
129 | |||
130 | op = skb_header_pointer(skb, offset + sizeof(struct tcphdr), | ||
131 | optsize, _opt); | ||
132 | if (op == NULL) { | ||
133 | sb_add(m, "OPT (TRUNCATED)"); | ||
134 | return 1; | ||
135 | } | ||
136 | |||
137 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
138 | sb_add(m, "OPT ("); | ||
139 | for (i = 0; i < optsize; i++) | ||
140 | sb_add(m, "%02X", op[i]); | ||
141 | |||
142 | sb_add(m, ") "); | ||
143 | } | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | /* One level of recursion won't kill us */ | ||
149 | static void dump_ipv4_packet(struct sbuff *m, | ||
150 | const struct nf_loginfo *info, | ||
151 | const struct sk_buff *skb, | ||
152 | unsigned int iphoff) | ||
153 | { | ||
154 | struct iphdr _iph; | ||
155 | const struct iphdr *ih; | ||
156 | unsigned int logflags; | ||
157 | |||
158 | if (info->type == NF_LOG_TYPE_LOG) | ||
159 | logflags = info->u.log.logflags; | ||
160 | else | ||
161 | logflags = NF_LOG_MASK; | ||
162 | |||
163 | ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); | ||
164 | if (ih == NULL) { | ||
165 | sb_add(m, "TRUNCATED"); | ||
166 | return; | ||
167 | } | ||
168 | |||
169 | /* Important fields: | ||
170 | * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ | ||
171 | /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ | ||
172 | sb_add(m, "SRC=%pI4 DST=%pI4 ", | ||
173 | &ih->saddr, &ih->daddr); | ||
174 | |||
175 | /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ | ||
176 | sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", | ||
177 | ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, | ||
178 | ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); | ||
179 | |||
180 | /* Max length: 6 "CE DF MF " */ | ||
181 | if (ntohs(ih->frag_off) & IP_CE) | ||
182 | sb_add(m, "CE "); | ||
183 | if (ntohs(ih->frag_off) & IP_DF) | ||
184 | sb_add(m, "DF "); | ||
185 | if (ntohs(ih->frag_off) & IP_MF) | ||
186 | sb_add(m, "MF "); | ||
187 | |||
188 | /* Max length: 11 "FRAG:65535 " */ | ||
189 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
190 | sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); | ||
191 | |||
192 | if ((logflags & XT_LOG_IPOPT) && | ||
193 | ih->ihl * 4 > sizeof(struct iphdr)) { | ||
194 | const unsigned char *op; | ||
195 | unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; | ||
196 | unsigned int i, optsize; | ||
197 | |||
198 | optsize = ih->ihl * 4 - sizeof(struct iphdr); | ||
199 | op = skb_header_pointer(skb, iphoff+sizeof(_iph), | ||
200 | optsize, _opt); | ||
201 | if (op == NULL) { | ||
202 | sb_add(m, "TRUNCATED"); | ||
203 | return; | ||
204 | } | ||
205 | |||
206 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
207 | sb_add(m, "OPT ("); | ||
208 | for (i = 0; i < optsize; i++) | ||
209 | sb_add(m, "%02X", op[i]); | ||
210 | sb_add(m, ") "); | ||
211 | } | ||
212 | |||
213 | switch (ih->protocol) { | ||
214 | case IPPROTO_TCP: | ||
215 | if (dump_tcp_header(m, skb, ih->protocol, | ||
216 | ntohs(ih->frag_off) & IP_OFFSET, | ||
217 | iphoff+ih->ihl*4, logflags)) | ||
218 | return; | ||
219 | case IPPROTO_UDP: | ||
220 | case IPPROTO_UDPLITE: | ||
221 | if (dump_udp_header(m, skb, ih->protocol, | ||
222 | ntohs(ih->frag_off) & IP_OFFSET, | ||
223 | iphoff+ih->ihl*4)) | ||
224 | return; | ||
225 | case IPPROTO_ICMP: { | ||
226 | struct icmphdr _icmph; | ||
227 | const struct icmphdr *ich; | ||
228 | static const size_t required_len[NR_ICMP_TYPES+1] | ||
229 | = { [ICMP_ECHOREPLY] = 4, | ||
230 | [ICMP_DEST_UNREACH] | ||
231 | = 8 + sizeof(struct iphdr), | ||
232 | [ICMP_SOURCE_QUENCH] | ||
233 | = 8 + sizeof(struct iphdr), | ||
234 | [ICMP_REDIRECT] | ||
235 | = 8 + sizeof(struct iphdr), | ||
236 | [ICMP_ECHO] = 4, | ||
237 | [ICMP_TIME_EXCEEDED] | ||
238 | = 8 + sizeof(struct iphdr), | ||
239 | [ICMP_PARAMETERPROB] | ||
240 | = 8 + sizeof(struct iphdr), | ||
241 | [ICMP_TIMESTAMP] = 20, | ||
242 | [ICMP_TIMESTAMPREPLY] = 20, | ||
243 | [ICMP_ADDRESS] = 12, | ||
244 | [ICMP_ADDRESSREPLY] = 12 }; | ||
245 | |||
246 | /* Max length: 11 "PROTO=ICMP " */ | ||
247 | sb_add(m, "PROTO=ICMP "); | ||
248 | |||
249 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
250 | break; | ||
251 | |||
252 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
253 | ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, | ||
254 | sizeof(_icmph), &_icmph); | ||
255 | if (ich == NULL) { | ||
256 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
257 | skb->len - iphoff - ih->ihl*4); | ||
258 | break; | ||
259 | } | ||
260 | |||
261 | /* Max length: 18 "TYPE=255 CODE=255 " */ | ||
262 | sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); | ||
263 | |||
264 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
265 | if (ich->type <= NR_ICMP_TYPES && | ||
266 | required_len[ich->type] && | ||
267 | skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { | ||
268 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
269 | skb->len - iphoff - ih->ihl*4); | ||
270 | break; | ||
271 | } | ||
272 | |||
273 | switch (ich->type) { | ||
274 | case ICMP_ECHOREPLY: | ||
275 | case ICMP_ECHO: | ||
276 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | ||
277 | sb_add(m, "ID=%u SEQ=%u ", | ||
278 | ntohs(ich->un.echo.id), | ||
279 | ntohs(ich->un.echo.sequence)); | ||
280 | break; | ||
281 | |||
282 | case ICMP_PARAMETERPROB: | ||
283 | /* Max length: 14 "PARAMETER=255 " */ | ||
284 | sb_add(m, "PARAMETER=%u ", | ||
285 | ntohl(ich->un.gateway) >> 24); | ||
286 | break; | ||
287 | case ICMP_REDIRECT: | ||
288 | /* Max length: 24 "GATEWAY=255.255.255.255 " */ | ||
289 | sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); | ||
290 | /* Fall through */ | ||
291 | case ICMP_DEST_UNREACH: | ||
292 | case ICMP_SOURCE_QUENCH: | ||
293 | case ICMP_TIME_EXCEEDED: | ||
294 | /* Max length: 3+maxlen */ | ||
295 | if (!iphoff) { /* Only recurse once. */ | ||
296 | sb_add(m, "["); | ||
297 | dump_ipv4_packet(m, info, skb, | ||
298 | iphoff + ih->ihl*4+sizeof(_icmph)); | ||
299 | sb_add(m, "] "); | ||
300 | } | ||
301 | |||
302 | /* Max length: 10 "MTU=65535 " */ | ||
303 | if (ich->type == ICMP_DEST_UNREACH && | ||
304 | ich->code == ICMP_FRAG_NEEDED) | ||
305 | sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu)); | ||
306 | } | ||
307 | break; | ||
308 | } | ||
309 | /* Max Length */ | ||
310 | case IPPROTO_AH: { | ||
311 | struct ip_auth_hdr _ahdr; | ||
312 | const struct ip_auth_hdr *ah; | ||
313 | |||
314 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
315 | break; | ||
316 | |||
317 | /* Max length: 9 "PROTO=AH " */ | ||
318 | sb_add(m, "PROTO=AH "); | ||
319 | |||
320 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
321 | ah = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
322 | sizeof(_ahdr), &_ahdr); | ||
323 | if (ah == NULL) { | ||
324 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
325 | skb->len - iphoff - ih->ihl*4); | ||
326 | break; | ||
327 | } | ||
328 | |||
329 | /* Length: 15 "SPI=0xF1234567 " */ | ||
330 | sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); | ||
331 | break; | ||
332 | } | ||
333 | case IPPROTO_ESP: { | ||
334 | struct ip_esp_hdr _esph; | ||
335 | const struct ip_esp_hdr *eh; | ||
336 | |||
337 | /* Max length: 10 "PROTO=ESP " */ | ||
338 | sb_add(m, "PROTO=ESP "); | ||
339 | |||
340 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
341 | break; | ||
342 | |||
343 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
344 | eh = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
345 | sizeof(_esph), &_esph); | ||
346 | if (eh == NULL) { | ||
347 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
348 | skb->len - iphoff - ih->ihl*4); | ||
349 | break; | ||
350 | } | ||
351 | |||
352 | /* Length: 15 "SPI=0xF1234567 " */ | ||
353 | sb_add(m, "SPI=0x%x ", ntohl(eh->spi)); | ||
354 | break; | ||
355 | } | ||
356 | /* Max length: 10 "PROTO 255 " */ | ||
357 | default: | ||
358 | sb_add(m, "PROTO=%u ", ih->protocol); | ||
359 | } | ||
360 | |||
361 | /* Max length: 15 "UID=4294967295 " */ | ||
362 | if ((logflags & XT_LOG_UID) && !iphoff && skb->sk) { | ||
363 | read_lock_bh(&skb->sk->sk_callback_lock); | ||
364 | if (skb->sk->sk_socket && skb->sk->sk_socket->file) | ||
365 | sb_add(m, "UID=%u GID=%u ", | ||
366 | skb->sk->sk_socket->file->f_cred->fsuid, | ||
367 | skb->sk->sk_socket->file->f_cred->fsgid); | ||
368 | read_unlock_bh(&skb->sk->sk_callback_lock); | ||
369 | } | ||
370 | |||
371 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | ||
372 | if (!iphoff && skb->mark) | ||
373 | sb_add(m, "MARK=0x%x ", skb->mark); | ||
374 | |||
375 | /* Proto Max log string length */ | ||
376 | /* IP: 40+46+6+11+127 = 230 */ | ||
377 | /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ | ||
378 | /* UDP: 10+max(25,20) = 35 */ | ||
379 | /* UDPLITE: 14+max(25,20) = 39 */ | ||
380 | /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ | ||
381 | /* ESP: 10+max(25)+15 = 50 */ | ||
382 | /* AH: 9+max(25)+15 = 49 */ | ||
383 | /* unknown: 10 */ | ||
384 | |||
385 | /* (ICMP allows recursion one level deep) */ | ||
386 | /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ | ||
387 | /* maxlen = 230+ 91 + 230 + 252 = 803 */ | ||
388 | } | ||
389 | |||
390 | static void dump_ipv4_mac_header(struct sbuff *m, | ||
391 | const struct nf_loginfo *info, | ||
392 | const struct sk_buff *skb) | ||
393 | { | ||
394 | struct net_device *dev = skb->dev; | ||
395 | unsigned int logflags = 0; | ||
396 | |||
397 | if (info->type == NF_LOG_TYPE_LOG) | ||
398 | logflags = info->u.log.logflags; | ||
399 | |||
400 | if (!(logflags & XT_LOG_MACDECODE)) | ||
401 | goto fallback; | ||
402 | |||
403 | switch (dev->type) { | ||
404 | case ARPHRD_ETHER: | ||
405 | sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
406 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
407 | ntohs(eth_hdr(skb)->h_proto)); | ||
408 | return; | ||
409 | default: | ||
410 | break; | ||
411 | } | ||
412 | |||
413 | fallback: | ||
414 | sb_add(m, "MAC="); | ||
415 | if (dev->hard_header_len && | ||
416 | skb->mac_header != skb->network_header) { | ||
417 | const unsigned char *p = skb_mac_header(skb); | ||
418 | unsigned int i; | ||
419 | |||
420 | sb_add(m, "%02x", *p++); | ||
421 | for (i = 1; i < dev->hard_header_len; i++, p++) | ||
422 | sb_add(m, ":%02x", *p); | ||
423 | } | ||
424 | sb_add(m, " "); | ||
425 | } | ||
426 | |||
427 | static void | ||
428 | log_packet_common(struct sbuff *m, | ||
429 | u_int8_t pf, | ||
430 | unsigned int hooknum, | ||
431 | const struct sk_buff *skb, | ||
432 | const struct net_device *in, | ||
433 | const struct net_device *out, | ||
434 | const struct nf_loginfo *loginfo, | ||
435 | const char *prefix) | ||
436 | { | ||
437 | sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, | ||
438 | prefix, | ||
439 | in ? in->name : "", | ||
440 | out ? out->name : ""); | ||
441 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
442 | if (skb->nf_bridge) { | ||
443 | const struct net_device *physindev; | ||
444 | const struct net_device *physoutdev; | ||
445 | |||
446 | physindev = skb->nf_bridge->physindev; | ||
447 | if (physindev && in != physindev) | ||
448 | sb_add(m, "PHYSIN=%s ", physindev->name); | ||
449 | physoutdev = skb->nf_bridge->physoutdev; | ||
450 | if (physoutdev && out != physoutdev) | ||
451 | sb_add(m, "PHYSOUT=%s ", physoutdev->name); | ||
452 | } | ||
453 | #endif | ||
454 | } | ||
455 | |||
456 | |||
457 | static void | ||
458 | ipt_log_packet(u_int8_t pf, | ||
459 | unsigned int hooknum, | ||
460 | const struct sk_buff *skb, | ||
461 | const struct net_device *in, | ||
462 | const struct net_device *out, | ||
463 | const struct nf_loginfo *loginfo, | ||
464 | const char *prefix) | ||
465 | { | ||
466 | struct sbuff *m = sb_open(); | ||
467 | |||
468 | if (!loginfo) | ||
469 | loginfo = &default_loginfo; | ||
470 | |||
471 | log_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix); | ||
472 | |||
473 | if (in != NULL) | ||
474 | dump_ipv4_mac_header(m, loginfo, skb); | ||
475 | |||
476 | dump_ipv4_packet(m, loginfo, skb, 0); | ||
477 | |||
478 | sb_close(m); | ||
479 | } | ||
480 | |||
481 | #if IS_ENABLED(CONFIG_IPV6) | ||
482 | /* One level of recursion won't kill us */ | ||
483 | static void dump_ipv6_packet(struct sbuff *m, | ||
484 | const struct nf_loginfo *info, | ||
485 | const struct sk_buff *skb, unsigned int ip6hoff, | ||
486 | int recurse) | ||
487 | { | ||
488 | u_int8_t currenthdr; | ||
489 | int fragment; | ||
490 | struct ipv6hdr _ip6h; | ||
491 | const struct ipv6hdr *ih; | ||
492 | unsigned int ptr; | ||
493 | unsigned int hdrlen = 0; | ||
494 | unsigned int logflags; | ||
495 | |||
496 | if (info->type == NF_LOG_TYPE_LOG) | ||
497 | logflags = info->u.log.logflags; | ||
498 | else | ||
499 | logflags = NF_LOG_MASK; | ||
500 | |||
501 | ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); | ||
502 | if (ih == NULL) { | ||
503 | sb_add(m, "TRUNCATED"); | ||
504 | return; | ||
505 | } | ||
506 | |||
507 | /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ | ||
508 | sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); | ||
509 | |||
510 | /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ | ||
511 | sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", | ||
512 | ntohs(ih->payload_len) + sizeof(struct ipv6hdr), | ||
513 | (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, | ||
514 | ih->hop_limit, | ||
515 | (ntohl(*(__be32 *)ih) & 0x000fffff)); | ||
516 | |||
517 | fragment = 0; | ||
518 | ptr = ip6hoff + sizeof(struct ipv6hdr); | ||
519 | currenthdr = ih->nexthdr; | ||
520 | while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) { | ||
521 | struct ipv6_opt_hdr _hdr; | ||
522 | const struct ipv6_opt_hdr *hp; | ||
523 | |||
524 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | ||
525 | if (hp == NULL) { | ||
526 | sb_add(m, "TRUNCATED"); | ||
527 | return; | ||
528 | } | ||
529 | |||
530 | /* Max length: 48 "OPT (...) " */ | ||
531 | if (logflags & XT_LOG_IPOPT) | ||
532 | sb_add(m, "OPT ( "); | ||
533 | |||
534 | switch (currenthdr) { | ||
535 | case IPPROTO_FRAGMENT: { | ||
536 | struct frag_hdr _fhdr; | ||
537 | const struct frag_hdr *fh; | ||
538 | |||
539 | sb_add(m, "FRAG:"); | ||
540 | fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), | ||
541 | &_fhdr); | ||
542 | if (fh == NULL) { | ||
543 | sb_add(m, "TRUNCATED "); | ||
544 | return; | ||
545 | } | ||
546 | |||
547 | /* Max length: 6 "65535 " */ | ||
548 | sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); | ||
549 | |||
550 | /* Max length: 11 "INCOMPLETE " */ | ||
551 | if (fh->frag_off & htons(0x0001)) | ||
552 | sb_add(m, "INCOMPLETE "); | ||
553 | |||
554 | sb_add(m, "ID:%08x ", ntohl(fh->identification)); | ||
555 | |||
556 | if (ntohs(fh->frag_off) & 0xFFF8) | ||
557 | fragment = 1; | ||
558 | |||
559 | hdrlen = 8; | ||
560 | |||
561 | break; | ||
562 | } | ||
563 | case IPPROTO_DSTOPTS: | ||
564 | case IPPROTO_ROUTING: | ||
565 | case IPPROTO_HOPOPTS: | ||
566 | if (fragment) { | ||
567 | if (logflags & XT_LOG_IPOPT) | ||
568 | sb_add(m, ")"); | ||
569 | return; | ||
570 | } | ||
571 | hdrlen = ipv6_optlen(hp); | ||
572 | break; | ||
573 | /* Max Length */ | ||
574 | case IPPROTO_AH: | ||
575 | if (logflags & XT_LOG_IPOPT) { | ||
576 | struct ip_auth_hdr _ahdr; | ||
577 | const struct ip_auth_hdr *ah; | ||
578 | |||
579 | /* Max length: 3 "AH " */ | ||
580 | sb_add(m, "AH "); | ||
581 | |||
582 | if (fragment) { | ||
583 | sb_add(m, ")"); | ||
584 | return; | ||
585 | } | ||
586 | |||
587 | ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), | ||
588 | &_ahdr); | ||
589 | if (ah == NULL) { | ||
590 | /* | ||
591 | * Max length: 26 "INCOMPLETE [65535 | ||
592 | * bytes] )" | ||
593 | */ | ||
594 | sb_add(m, "INCOMPLETE [%u bytes] )", | ||
595 | skb->len - ptr); | ||
596 | return; | ||
597 | } | ||
598 | |||
599 | /* Length: 15 "SPI=0xF1234567 */ | ||
600 | sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); | ||
601 | |||
602 | } | ||
603 | |||
604 | hdrlen = (hp->hdrlen+2)<<2; | ||
605 | break; | ||
606 | case IPPROTO_ESP: | ||
607 | if (logflags & XT_LOG_IPOPT) { | ||
608 | struct ip_esp_hdr _esph; | ||
609 | const struct ip_esp_hdr *eh; | ||
610 | |||
611 | /* Max length: 4 "ESP " */ | ||
612 | sb_add(m, "ESP "); | ||
613 | |||
614 | if (fragment) { | ||
615 | sb_add(m, ")"); | ||
616 | return; | ||
617 | } | ||
618 | |||
619 | /* | ||
620 | * Max length: 26 "INCOMPLETE [65535 bytes] )" | ||
621 | */ | ||
622 | eh = skb_header_pointer(skb, ptr, sizeof(_esph), | ||
623 | &_esph); | ||
624 | if (eh == NULL) { | ||
625 | sb_add(m, "INCOMPLETE [%u bytes] )", | ||
626 | skb->len - ptr); | ||
627 | return; | ||
628 | } | ||
629 | |||
630 | /* Length: 16 "SPI=0xF1234567 )" */ | ||
631 | sb_add(m, "SPI=0x%x )", ntohl(eh->spi)); | ||
632 | |||
633 | } | ||
634 | return; | ||
635 | default: | ||
636 | /* Max length: 20 "Unknown Ext Hdr 255" */ | ||
637 | sb_add(m, "Unknown Ext Hdr %u", currenthdr); | ||
638 | return; | ||
639 | } | ||
640 | if (logflags & XT_LOG_IPOPT) | ||
641 | sb_add(m, ") "); | ||
642 | |||
643 | currenthdr = hp->nexthdr; | ||
644 | ptr += hdrlen; | ||
645 | } | ||
646 | |||
647 | switch (currenthdr) { | ||
648 | case IPPROTO_TCP: | ||
649 | if (dump_tcp_header(m, skb, currenthdr, fragment, ptr, | ||
650 | logflags)) | ||
651 | return; | ||
652 | case IPPROTO_UDP: | ||
653 | case IPPROTO_UDPLITE: | ||
654 | if (dump_udp_header(m, skb, currenthdr, fragment, ptr)) | ||
655 | return; | ||
656 | case IPPROTO_ICMPV6: { | ||
657 | struct icmp6hdr _icmp6h; | ||
658 | const struct icmp6hdr *ic; | ||
659 | |||
660 | /* Max length: 13 "PROTO=ICMPv6 " */ | ||
661 | sb_add(m, "PROTO=ICMPv6 "); | ||
662 | |||
663 | if (fragment) | ||
664 | break; | ||
665 | |||
666 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
667 | ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); | ||
668 | if (ic == NULL) { | ||
669 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); | ||
670 | return; | ||
671 | } | ||
672 | |||
673 | /* Max length: 18 "TYPE=255 CODE=255 " */ | ||
674 | sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); | ||
675 | |||
676 | switch (ic->icmp6_type) { | ||
677 | case ICMPV6_ECHO_REQUEST: | ||
678 | case ICMPV6_ECHO_REPLY: | ||
679 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | ||
680 | sb_add(m, "ID=%u SEQ=%u ", | ||
681 | ntohs(ic->icmp6_identifier), | ||
682 | ntohs(ic->icmp6_sequence)); | ||
683 | break; | ||
684 | case ICMPV6_MGM_QUERY: | ||
685 | case ICMPV6_MGM_REPORT: | ||
686 | case ICMPV6_MGM_REDUCTION: | ||
687 | break; | ||
688 | |||
689 | case ICMPV6_PARAMPROB: | ||
690 | /* Max length: 17 "POINTER=ffffffff " */ | ||
691 | sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer)); | ||
692 | /* Fall through */ | ||
693 | case ICMPV6_DEST_UNREACH: | ||
694 | case ICMPV6_PKT_TOOBIG: | ||
695 | case ICMPV6_TIME_EXCEED: | ||
696 | /* Max length: 3+maxlen */ | ||
697 | if (recurse) { | ||
698 | sb_add(m, "["); | ||
699 | dump_ipv6_packet(m, info, skb, | ||
700 | ptr + sizeof(_icmp6h), 0); | ||
701 | sb_add(m, "] "); | ||
702 | } | ||
703 | |||
704 | /* Max length: 10 "MTU=65535 " */ | ||
705 | if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) | ||
706 | sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu)); | ||
707 | } | ||
708 | break; | ||
709 | } | ||
710 | /* Max length: 10 "PROTO=255 " */ | ||
711 | default: | ||
712 | sb_add(m, "PROTO=%u ", currenthdr); | ||
713 | } | ||
714 | |||
715 | /* Max length: 15 "UID=4294967295 " */ | ||
716 | if ((logflags & XT_LOG_UID) && recurse && skb->sk) { | ||
717 | read_lock_bh(&skb->sk->sk_callback_lock); | ||
718 | if (skb->sk->sk_socket && skb->sk->sk_socket->file) | ||
719 | sb_add(m, "UID=%u GID=%u ", | ||
720 | skb->sk->sk_socket->file->f_cred->fsuid, | ||
721 | skb->sk->sk_socket->file->f_cred->fsgid); | ||
722 | read_unlock_bh(&skb->sk->sk_callback_lock); | ||
723 | } | ||
724 | |||
725 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | ||
726 | if (!recurse && skb->mark) | ||
727 | sb_add(m, "MARK=0x%x ", skb->mark); | ||
728 | } | ||
729 | |||
730 | static void dump_ipv6_mac_header(struct sbuff *m, | ||
731 | const struct nf_loginfo *info, | ||
732 | const struct sk_buff *skb) | ||
733 | { | ||
734 | struct net_device *dev = skb->dev; | ||
735 | unsigned int logflags = 0; | ||
736 | |||
737 | if (info->type == NF_LOG_TYPE_LOG) | ||
738 | logflags = info->u.log.logflags; | ||
739 | |||
740 | if (!(logflags & XT_LOG_MACDECODE)) | ||
741 | goto fallback; | ||
742 | |||
743 | switch (dev->type) { | ||
744 | case ARPHRD_ETHER: | ||
745 | sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
746 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
747 | ntohs(eth_hdr(skb)->h_proto)); | ||
748 | return; | ||
749 | default: | ||
750 | break; | ||
751 | } | ||
752 | |||
753 | fallback: | ||
754 | sb_add(m, "MAC="); | ||
755 | if (dev->hard_header_len && | ||
756 | skb->mac_header != skb->network_header) { | ||
757 | const unsigned char *p = skb_mac_header(skb); | ||
758 | unsigned int len = dev->hard_header_len; | ||
759 | unsigned int i; | ||
760 | |||
761 | if (dev->type == ARPHRD_SIT) { | ||
762 | p -= ETH_HLEN; | ||
763 | |||
764 | if (p < skb->head) | ||
765 | p = NULL; | ||
766 | } | ||
767 | |||
768 | if (p != NULL) { | ||
769 | sb_add(m, "%02x", *p++); | ||
770 | for (i = 1; i < len; i++) | ||
771 | sb_add(m, ":%02x", *p++); | ||
772 | } | ||
773 | sb_add(m, " "); | ||
774 | |||
775 | if (dev->type == ARPHRD_SIT) { | ||
776 | const struct iphdr *iph = | ||
777 | (struct iphdr *)skb_mac_header(skb); | ||
778 | sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, | ||
779 | &iph->daddr); | ||
780 | } | ||
781 | } else | ||
782 | sb_add(m, " "); | ||
783 | } | ||
784 | |||
785 | static void | ||
786 | ip6t_log_packet(u_int8_t pf, | ||
787 | unsigned int hooknum, | ||
788 | const struct sk_buff *skb, | ||
789 | const struct net_device *in, | ||
790 | const struct net_device *out, | ||
791 | const struct nf_loginfo *loginfo, | ||
792 | const char *prefix) | ||
793 | { | ||
794 | struct sbuff *m = sb_open(); | ||
795 | |||
796 | if (!loginfo) | ||
797 | loginfo = &default_loginfo; | ||
798 | |||
799 | log_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix); | ||
800 | |||
801 | if (in != NULL) | ||
802 | dump_ipv6_mac_header(m, loginfo, skb); | ||
803 | |||
804 | dump_ipv6_packet(m, loginfo, skb, skb_network_offset(skb), 1); | ||
805 | |||
806 | sb_close(m); | ||
807 | } | ||
808 | #endif | ||
809 | |||
810 | static unsigned int | ||
811 | log_tg(struct sk_buff *skb, const struct xt_action_param *par) | ||
812 | { | ||
813 | const struct xt_log_info *loginfo = par->targinfo; | ||
814 | struct nf_loginfo li; | ||
815 | |||
816 | li.type = NF_LOG_TYPE_LOG; | ||
817 | li.u.log.level = loginfo->level; | ||
818 | li.u.log.logflags = loginfo->logflags; | ||
819 | |||
820 | if (par->family == NFPROTO_IPV4) | ||
821 | ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in, | ||
822 | par->out, &li, loginfo->prefix); | ||
823 | #if IS_ENABLED(CONFIG_IPV6) | ||
824 | else if (par->family == NFPROTO_IPV6) | ||
825 | ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in, | ||
826 | par->out, &li, loginfo->prefix); | ||
827 | #endif | ||
828 | else | ||
829 | WARN_ON_ONCE(1); | ||
830 | |||
831 | return XT_CONTINUE; | ||
832 | } | ||
833 | |||
834 | static int log_tg_check(const struct xt_tgchk_param *par) | ||
835 | { | ||
836 | const struct xt_log_info *loginfo = par->targinfo; | ||
837 | |||
838 | if (par->family != NFPROTO_IPV4 && par->family != NFPROTO_IPV6) | ||
839 | return -EINVAL; | ||
840 | |||
841 | if (loginfo->level >= 8) { | ||
842 | pr_debug("level %u >= 8\n", loginfo->level); | ||
843 | return -EINVAL; | ||
844 | } | ||
845 | |||
846 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { | ||
847 | pr_debug("prefix is not null-terminated\n"); | ||
848 | return -EINVAL; | ||
849 | } | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
854 | static struct xt_target log_tg_regs[] __read_mostly = { | ||
855 | { | ||
856 | .name = "LOG", | ||
857 | .family = NFPROTO_IPV4, | ||
858 | .target = log_tg, | ||
859 | .targetsize = sizeof(struct xt_log_info), | ||
860 | .checkentry = log_tg_check, | ||
861 | .me = THIS_MODULE, | ||
862 | }, | ||
863 | #if IS_ENABLED(CONFIG_IPV6) | ||
864 | { | ||
865 | .name = "LOG", | ||
866 | .family = NFPROTO_IPV6, | ||
867 | .target = log_tg, | ||
868 | .targetsize = sizeof(struct xt_log_info), | ||
869 | .checkentry = log_tg_check, | ||
870 | .me = THIS_MODULE, | ||
871 | }, | ||
872 | #endif | ||
873 | }; | ||
874 | |||
875 | static struct nf_logger ipt_log_logger __read_mostly = { | ||
876 | .name = "ipt_LOG", | ||
877 | .logfn = &ipt_log_packet, | ||
878 | .me = THIS_MODULE, | ||
879 | }; | ||
880 | |||
881 | #if IS_ENABLED(CONFIG_IPV6) | ||
882 | static struct nf_logger ip6t_log_logger __read_mostly = { | ||
883 | .name = "ip6t_LOG", | ||
884 | .logfn = &ip6t_log_packet, | ||
885 | .me = THIS_MODULE, | ||
886 | }; | ||
887 | #endif | ||
888 | |||
889 | static int __init log_tg_init(void) | ||
890 | { | ||
891 | int ret; | ||
892 | |||
893 | ret = xt_register_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); | ||
894 | if (ret < 0) | ||
895 | return ret; | ||
896 | |||
897 | nf_log_register(NFPROTO_IPV4, &ipt_log_logger); | ||
898 | #if IS_ENABLED(CONFIG_IPV6) | ||
899 | nf_log_register(NFPROTO_IPV6, &ip6t_log_logger); | ||
900 | #endif | ||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | static void __exit log_tg_exit(void) | ||
905 | { | ||
906 | nf_log_unregister(&ipt_log_logger); | ||
907 | #if IS_ENABLED(CONFIG_IPV6) | ||
908 | nf_log_unregister(&ip6t_log_logger); | ||
909 | #endif | ||
910 | xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); | ||
911 | } | ||
912 | |||
913 | module_init(log_tg_init); | ||
914 | module_exit(log_tg_exit); | ||
915 | |||
916 | MODULE_LICENSE("GPL"); | ||
917 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | ||
918 | MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>"); | ||
919 | MODULE_DESCRIPTION("Xtables: IPv4/IPv6 packet logging"); | ||
920 | MODULE_ALIAS("ipt_LOG"); | ||
921 | MODULE_ALIAS("ip6t_LOG"); | ||