• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* (C) 1999-2001 Paul `Rusty' Russell
2  * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8 
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/spinlock.h>
14 #include <linux/skbuff.h>
15 #include <linux/if_arp.h>
16 #include <linux/ip.h>
17 #include <net/ipv6.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_ipv6/ip6_tables.h>
25 #include <linux/netfilter/xt_LOG.h>
26 #include <net/netfilter/nf_log.h>
27 
28 static const struct nf_loginfo default_loginfo = {
29 	.type	= NF_LOG_TYPE_LOG,
30 	.u = {
31 		.log = {
32 			.level	  = LOGLEVEL_NOTICE,
33 			.logflags = NF_LOG_DEFAULT_MASK,
34 		},
35 	},
36 };
37 
38 /* One level of recursion won't kill us */
dump_ipv6_packet(struct nf_log_buf * m,const struct nf_loginfo * info,const struct sk_buff * skb,unsigned int ip6hoff,int recurse)39 static void dump_ipv6_packet(struct nf_log_buf *m,
40 			     const struct nf_loginfo *info,
41 			     const struct sk_buff *skb, unsigned int ip6hoff,
42 			     int recurse)
43 {
44 	u_int8_t currenthdr;
45 	int fragment;
46 	struct ipv6hdr _ip6h;
47 	const struct ipv6hdr *ih;
48 	unsigned int ptr;
49 	unsigned int hdrlen = 0;
50 	unsigned int logflags;
51 
52 	if (info->type == NF_LOG_TYPE_LOG)
53 		logflags = info->u.log.logflags;
54 	else
55 		logflags = NF_LOG_DEFAULT_MASK;
56 
57 	ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h);
58 	if (ih == NULL) {
59 		nf_log_buf_add(m, "TRUNCATED");
60 		return;
61 	}
62 
63 	/* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */
64 	nf_log_buf_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr);
65 
66 	/* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
67 	nf_log_buf_add(m, "LEN=%zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
68 	       ntohs(ih->payload_len) + sizeof(struct ipv6hdr),
69 	       (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20,
70 	       ih->hop_limit,
71 	       (ntohl(*(__be32 *)ih) & 0x000fffff));
72 
73 	fragment = 0;
74 	ptr = ip6hoff + sizeof(struct ipv6hdr);
75 	currenthdr = ih->nexthdr;
76 	while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) {
77 		struct ipv6_opt_hdr _hdr;
78 		const struct ipv6_opt_hdr *hp;
79 
80 		hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
81 		if (hp == NULL) {
82 			nf_log_buf_add(m, "TRUNCATED");
83 			return;
84 		}
85 
86 		/* Max length: 48 "OPT (...) " */
87 		if (logflags & NF_LOG_IPOPT)
88 			nf_log_buf_add(m, "OPT ( ");
89 
90 		switch (currenthdr) {
91 		case IPPROTO_FRAGMENT: {
92 			struct frag_hdr _fhdr;
93 			const struct frag_hdr *fh;
94 
95 			nf_log_buf_add(m, "FRAG:");
96 			fh = skb_header_pointer(skb, ptr, sizeof(_fhdr),
97 						&_fhdr);
98 			if (fh == NULL) {
99 				nf_log_buf_add(m, "TRUNCATED ");
100 				return;
101 			}
102 
103 			/* Max length: 6 "65535 " */
104 			nf_log_buf_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8);
105 
106 			/* Max length: 11 "INCOMPLETE " */
107 			if (fh->frag_off & htons(0x0001))
108 				nf_log_buf_add(m, "INCOMPLETE ");
109 
110 			nf_log_buf_add(m, "ID:%08x ",
111 				       ntohl(fh->identification));
112 
113 			if (ntohs(fh->frag_off) & 0xFFF8)
114 				fragment = 1;
115 
116 			hdrlen = 8;
117 
118 			break;
119 		}
120 		case IPPROTO_DSTOPTS:
121 		case IPPROTO_ROUTING:
122 		case IPPROTO_HOPOPTS:
123 			if (fragment) {
124 				if (logflags & NF_LOG_IPOPT)
125 					nf_log_buf_add(m, ")");
126 				return;
127 			}
128 			hdrlen = ipv6_optlen(hp);
129 			break;
130 		/* Max Length */
131 		case IPPROTO_AH:
132 			if (logflags & NF_LOG_IPOPT) {
133 				struct ip_auth_hdr _ahdr;
134 				const struct ip_auth_hdr *ah;
135 
136 				/* Max length: 3 "AH " */
137 				nf_log_buf_add(m, "AH ");
138 
139 				if (fragment) {
140 					nf_log_buf_add(m, ")");
141 					return;
142 				}
143 
144 				ah = skb_header_pointer(skb, ptr, sizeof(_ahdr),
145 							&_ahdr);
146 				if (ah == NULL) {
147 					/*
148 					 * Max length: 26 "INCOMPLETE [65535
149 					 *  bytes] )"
150 					 */
151 					nf_log_buf_add(m, "INCOMPLETE [%u bytes] )",
152 						       skb->len - ptr);
153 					return;
154 				}
155 
156 				/* Length: 15 "SPI=0xF1234567 */
157 				nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi));
158 
159 			}
160 
161 			hdrlen = (hp->hdrlen+2)<<2;
162 			break;
163 		case IPPROTO_ESP:
164 			if (logflags & NF_LOG_IPOPT) {
165 				struct ip_esp_hdr _esph;
166 				const struct ip_esp_hdr *eh;
167 
168 				/* Max length: 4 "ESP " */
169 				nf_log_buf_add(m, "ESP ");
170 
171 				if (fragment) {
172 					nf_log_buf_add(m, ")");
173 					return;
174 				}
175 
176 				/*
177 				 * Max length: 26 "INCOMPLETE [65535 bytes] )"
178 				 */
179 				eh = skb_header_pointer(skb, ptr, sizeof(_esph),
180 							&_esph);
181 				if (eh == NULL) {
182 					nf_log_buf_add(m, "INCOMPLETE [%u bytes] )",
183 						       skb->len - ptr);
184 					return;
185 				}
186 
187 				/* Length: 16 "SPI=0xF1234567 )" */
188 				nf_log_buf_add(m, "SPI=0x%x )",
189 					       ntohl(eh->spi));
190 			}
191 			return;
192 		default:
193 			/* Max length: 20 "Unknown Ext Hdr 255" */
194 			nf_log_buf_add(m, "Unknown Ext Hdr %u", currenthdr);
195 			return;
196 		}
197 		if (logflags & NF_LOG_IPOPT)
198 			nf_log_buf_add(m, ") ");
199 
200 		currenthdr = hp->nexthdr;
201 		ptr += hdrlen;
202 	}
203 
204 	switch (currenthdr) {
205 	case IPPROTO_TCP:
206 		if (nf_log_dump_tcp_header(m, skb, currenthdr, fragment,
207 					   ptr, logflags))
208 			return;
209 		break;
210 	case IPPROTO_UDP:
211 	case IPPROTO_UDPLITE:
212 		if (nf_log_dump_udp_header(m, skb, currenthdr, fragment, ptr))
213 			return;
214 		break;
215 	case IPPROTO_ICMPV6: {
216 		struct icmp6hdr _icmp6h;
217 		const struct icmp6hdr *ic;
218 
219 		/* Max length: 13 "PROTO=ICMPv6 " */
220 		nf_log_buf_add(m, "PROTO=ICMPv6 ");
221 
222 		if (fragment)
223 			break;
224 
225 		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
226 		ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h);
227 		if (ic == NULL) {
228 			nf_log_buf_add(m, "INCOMPLETE [%u bytes] ",
229 				       skb->len - ptr);
230 			return;
231 		}
232 
233 		/* Max length: 18 "TYPE=255 CODE=255 " */
234 		nf_log_buf_add(m, "TYPE=%u CODE=%u ",
235 			       ic->icmp6_type, ic->icmp6_code);
236 
237 		switch (ic->icmp6_type) {
238 		case ICMPV6_ECHO_REQUEST:
239 		case ICMPV6_ECHO_REPLY:
240 			/* Max length: 19 "ID=65535 SEQ=65535 " */
241 			nf_log_buf_add(m, "ID=%u SEQ=%u ",
242 				ntohs(ic->icmp6_identifier),
243 				ntohs(ic->icmp6_sequence));
244 			break;
245 		case ICMPV6_MGM_QUERY:
246 		case ICMPV6_MGM_REPORT:
247 		case ICMPV6_MGM_REDUCTION:
248 			break;
249 
250 		case ICMPV6_PARAMPROB:
251 			/* Max length: 17 "POINTER=ffffffff " */
252 			nf_log_buf_add(m, "POINTER=%08x ",
253 				       ntohl(ic->icmp6_pointer));
254 			/* Fall through */
255 		case ICMPV6_DEST_UNREACH:
256 		case ICMPV6_PKT_TOOBIG:
257 		case ICMPV6_TIME_EXCEED:
258 			/* Max length: 3+maxlen */
259 			if (recurse) {
260 				nf_log_buf_add(m, "[");
261 				dump_ipv6_packet(m, info, skb,
262 						 ptr + sizeof(_icmp6h), 0);
263 				nf_log_buf_add(m, "] ");
264 			}
265 
266 			/* Max length: 10 "MTU=65535 " */
267 			if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) {
268 				nf_log_buf_add(m, "MTU=%u ",
269 					       ntohl(ic->icmp6_mtu));
270 			}
271 		}
272 		break;
273 	}
274 	/* Max length: 10 "PROTO=255 " */
275 	default:
276 		nf_log_buf_add(m, "PROTO=%u ", currenthdr);
277 	}
278 
279 	/* Max length: 15 "UID=4294967295 " */
280 	if ((logflags & NF_LOG_UID) && recurse)
281 		nf_log_dump_sk_uid_gid(m, skb->sk);
282 
283 	/* Max length: 16 "MARK=0xFFFFFFFF " */
284 	if (recurse && skb->mark)
285 		nf_log_buf_add(m, "MARK=0x%x ", skb->mark);
286 }
287 
dump_ipv6_mac_header(struct nf_log_buf * m,const struct nf_loginfo * info,const struct sk_buff * skb)288 static void dump_ipv6_mac_header(struct nf_log_buf *m,
289 				 const struct nf_loginfo *info,
290 				 const struct sk_buff *skb)
291 {
292 	struct net_device *dev = skb->dev;
293 	unsigned int logflags = 0;
294 
295 	if (info->type == NF_LOG_TYPE_LOG)
296 		logflags = info->u.log.logflags;
297 
298 	if (!(logflags & NF_LOG_MACDECODE))
299 		goto fallback;
300 
301 	switch (dev->type) {
302 	case ARPHRD_ETHER:
303 		nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
304 		       eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
305 		       ntohs(eth_hdr(skb)->h_proto));
306 		return;
307 	default:
308 		break;
309 	}
310 
311 fallback:
312 	nf_log_buf_add(m, "MAC=");
313 	if (dev->hard_header_len &&
314 	    skb->mac_header != skb->network_header) {
315 		const unsigned char *p = skb_mac_header(skb);
316 		unsigned int len = dev->hard_header_len;
317 		unsigned int i;
318 
319 		if (dev->type == ARPHRD_SIT) {
320 			p -= ETH_HLEN;
321 
322 			if (p < skb->head)
323 				p = NULL;
324 		}
325 
326 		if (p != NULL) {
327 			nf_log_buf_add(m, "%02x", *p++);
328 			for (i = 1; i < len; i++)
329 				nf_log_buf_add(m, ":%02x", *p++);
330 		}
331 		nf_log_buf_add(m, " ");
332 
333 		if (dev->type == ARPHRD_SIT) {
334 			const struct iphdr *iph =
335 				(struct iphdr *)skb_mac_header(skb);
336 			nf_log_buf_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr,
337 				       &iph->daddr);
338 		}
339 	} else {
340 		nf_log_buf_add(m, " ");
341 	}
342 }
343 
nf_log_ip6_packet(struct net * net,u_int8_t pf,unsigned int hooknum,const struct sk_buff * skb,const struct net_device * in,const struct net_device * out,const struct nf_loginfo * loginfo,const char * prefix)344 static void nf_log_ip6_packet(struct net *net, u_int8_t pf,
345 			      unsigned int hooknum, const struct sk_buff *skb,
346 			      const struct net_device *in,
347 			      const struct net_device *out,
348 			      const struct nf_loginfo *loginfo,
349 			      const char *prefix)
350 {
351 	struct nf_log_buf *m;
352 
353 	/* FIXME: Disabled from containers until syslog ns is supported */
354 	if (!net_eq(net, &init_net) && !sysctl_nf_log_all_netns)
355 		return;
356 
357 	m = nf_log_buf_open();
358 
359 	if (!loginfo)
360 		loginfo = &default_loginfo;
361 
362 	nf_log_dump_packet_common(m, pf, hooknum, skb, in, out,
363 				  loginfo, prefix);
364 
365 	if (in != NULL)
366 		dump_ipv6_mac_header(m, loginfo, skb);
367 
368 	dump_ipv6_packet(m, loginfo, skb, skb_network_offset(skb), 1);
369 
370 	nf_log_buf_close(m);
371 }
372 
373 static struct nf_logger nf_ip6_logger __read_mostly = {
374 	.name		= "nf_log_ipv6",
375 	.type		= NF_LOG_TYPE_LOG,
376 	.logfn		= nf_log_ip6_packet,
377 	.me		= THIS_MODULE,
378 };
379 
nf_log_ipv6_net_init(struct net * net)380 static int __net_init nf_log_ipv6_net_init(struct net *net)
381 {
382 	return nf_log_set(net, NFPROTO_IPV6, &nf_ip6_logger);
383 }
384 
nf_log_ipv6_net_exit(struct net * net)385 static void __net_exit nf_log_ipv6_net_exit(struct net *net)
386 {
387 	nf_log_unset(net, &nf_ip6_logger);
388 }
389 
390 static struct pernet_operations nf_log_ipv6_net_ops = {
391 	.init = nf_log_ipv6_net_init,
392 	.exit = nf_log_ipv6_net_exit,
393 };
394 
nf_log_ipv6_init(void)395 static int __init nf_log_ipv6_init(void)
396 {
397 	int ret;
398 
399 	ret = register_pernet_subsys(&nf_log_ipv6_net_ops);
400 	if (ret < 0)
401 		return ret;
402 
403 	ret = nf_log_register(NFPROTO_IPV6, &nf_ip6_logger);
404 	if (ret < 0) {
405 		pr_err("failed to register logger\n");
406 		goto err1;
407 	}
408 
409 	return 0;
410 
411 err1:
412 	unregister_pernet_subsys(&nf_log_ipv6_net_ops);
413 	return ret;
414 }
415 
nf_log_ipv6_exit(void)416 static void __exit nf_log_ipv6_exit(void)
417 {
418 	unregister_pernet_subsys(&nf_log_ipv6_net_ops);
419 	nf_log_unregister(&nf_ip6_logger);
420 }
421 
422 module_init(nf_log_ipv6_init);
423 module_exit(nf_log_ipv6_exit);
424 
425 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
426 MODULE_DESCRIPTION("Netfilter IPv6 packet logging");
427 MODULE_LICENSE("GPL");
428 MODULE_ALIAS_NF_LOGGER(AF_INET6, 0);
429