xref: /openbsd-src/usr.sbin/tcpdump/print-gre.c (revision c90a81c56dcebd6a1b73fe4aff9b03385b8e63b3)
1 /*	$OpenBSD: print-gre.c,v 1.21 2018/07/06 07:13:21 dlg Exp $	*/
2 
3 /*
4  * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * tcpdump filter for GRE - Generic Routing Encapsulation
31  * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE)
32  */
33 
34 #include <sys/time.h>
35 #include <sys/uio.h>
36 #include <sys/socket.h>
37 
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40 #include <arpa/inet.h>
41 
42 #include <net/ethertypes.h>
43 
44 #include <stdio.h>
45 #include <string.h>
46 
47 #include "interface.h"
48 #include "addrtoname.h"
49 #include "extract.h"
50 
51 #define	GRE_CP		0x8000		/* checksum present */
52 #define	GRE_RP		0x4000		/* routing present */
53 #define	GRE_KP		0x2000		/* key present */
54 #define	GRE_SP		0x1000		/* sequence# present */
55 #define	GRE_sP		0x0800		/* source routing */
56 #define	GRE_RECRS	0x0700		/* recursion count */
57 #define	GRE_AP		0x0080		/* acknowledgment# present */
58 #define	GRE_VERS	0x0007		/* protocol version */
59 
60 /* source route entry types */
61 #define	GRESRE_IP	0x0800		/* IP */
62 #define	GRESRE_ASN	0xfffe		/* ASN */
63 
64 #define NVGRE_VSID_MASK		0xffffff00U
65 #define NVGRE_VSID_SHIFT	8
66 #define NVGRE_FLOWID_MASK	0x000000ffU
67 #define NVGRE_FLOWID_SHIFT	0
68 
69 #define GRE_WCCP	0x883e
70 
71 struct wccp_redirect {
72 	uint8_t		flags;
73 #define WCCP_D			(1 << 7)
74 #define WCCP_A			(1 << 6)
75 	uint8_t		ServiceId;
76 	uint8_t		AltBucket;
77 	uint8_t		PriBucket;
78 };
79 
80 void gre_print_0(const u_char *, u_int);
81 void gre_print_1(const u_char *, u_int);
82 void gre_print_pptp(const u_char *, u_int, uint16_t);
83 void gre_print_eoip(const u_char *, u_int, uint16_t);
84 void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int);
85 void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int);
86 void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int);
87 
88 void
89 gre_print(const u_char *p, u_int length)
90 {
91 	uint16_t vers;
92 	int l;
93 
94 	l = snapend - p;
95 
96 	if (l < sizeof(vers)) {
97 		printf("[|gre]");
98 		return;
99 	}
100 	vers = EXTRACT_16BITS(p) & GRE_VERS;
101 
102 	switch (vers) {
103 	case 0:
104 		gre_print_0(p, length);
105 		break;
106 	case 1:
107 		gre_print_1(p, length);
108 		break;
109 	default:
110 		printf("gre-unknown-version=%u", vers);
111 		break;
112 	}
113 }
114 
115 void
116 gre_print_0(const u_char *p, u_int length)
117 {
118 	uint16_t flags, proto;
119 	u_int l;
120 
121 	l = snapend - p;
122 
123 	flags = EXTRACT_16BITS(p);
124 	p += sizeof(flags);
125 	l -= sizeof(flags);
126 	length -= sizeof(flags);
127 
128 	printf("gre");
129 
130 	if (vflag) {
131 		printf(" [%s%s%s%s%s]",
132 		    (flags & GRE_CP) ? "C" : "",
133 		    (flags & GRE_RP) ? "R" : "",
134 		    (flags & GRE_KP) ? "K" : "",
135 		    (flags & GRE_SP) ? "S" : "",
136 		    (flags & GRE_sP) ? "s" : "");
137 	}
138 
139 	if (l < sizeof(proto))
140 		goto trunc;
141 	proto = EXTRACT_16BITS(p);
142 	p += sizeof(proto);
143 	l -= sizeof(proto);
144 	length -= sizeof(proto);
145 
146 	if ((flags & GRE_CP) | (flags & GRE_RP)) {
147 		if (l < 2)
148 			goto trunc;
149 		if ((flags & GRE_CP) && vflag)
150 			printf(" sum 0x%x", EXTRACT_16BITS(p));
151 		p += 2;
152 		l -= 2;
153 		length -= 2;
154 
155 		if (l < 2)
156 			goto trunc;
157 		if (flags & GRE_RP)
158 			printf(" off 0x%x", EXTRACT_16BITS(p));
159 		p += 2;
160 		l -= 2;
161 		length -= 2;
162 	}
163 
164 	if (flags & GRE_KP) {
165 		uint32_t key, vsid;
166 
167 		if (l < sizeof(key))
168 			goto trunc;
169 		key = EXTRACT_32BITS(p);
170 		p += sizeof(key);
171 		l -= sizeof(key);
172 		length -= sizeof(key);
173 
174 		/* maybe NVGRE, or key entropy? */
175 		vsid = (key & NVGRE_VSID_MASK) >> NVGRE_VSID_SHIFT;
176 		printf(" key=%u|%u+%02x", key, vsid,
177 		    (key & NVGRE_FLOWID_MASK) >> NVGRE_FLOWID_SHIFT);
178 	}
179 
180 	if (flags & GRE_SP) {
181 		if (l < 4)
182 			goto trunc;
183 		printf(" seq %u", EXTRACT_32BITS(p));
184 		p += 4;
185 		l -= 4;
186 		length -= 4;
187 	}
188 
189 	if (flags & GRE_RP) {
190 		for (;;) {
191 			u_int16_t af;
192 			u_int8_t sreoff;
193 			u_int8_t srelen;
194 
195 			if (l < 4)
196 				goto trunc;
197 			af = EXTRACT_16BITS(p);
198 			sreoff = *(p + 2);
199 			srelen = *(p + 3);
200 			p += 4;
201 			l -= 4;
202 			length -= 4;
203 
204 			if (af == 0 && srelen == 0)
205 				break;
206 
207 			gre_sre_print(af, sreoff, srelen, p, l);
208 
209 			if (l < srelen)
210 				goto trunc;
211 			p += srelen;
212 			l -= srelen;
213 			length -= srelen;
214 		}
215 	}
216 
217 	printf(" ");
218 
219 	switch (proto) {
220 	case 0:
221 		printf("keep-alive");
222 		break;
223 	case GRE_WCCP: {
224 		printf("wccp ");
225 
226 		if (l == 0)
227 			return;
228 
229 		if (*p >> 4 != 4) {
230 			struct wccp_redirect *wccp;
231 
232 			if (l < sizeof(*wccp)) {
233 				printf("[|wccp]");
234 				return;
235 			}
236 
237 			wccp = (struct wccp_redirect *)p;
238 
239 			printf("D:%c A:%c SId:%u Alt:%u Pri:%u",
240 			    (wccp->flags & WCCP_D) ? '1' : '0',
241 			    (wccp->flags & WCCP_A) ? '1' : '0',
242 			    wccp->ServiceId, wccp->AltBucket, wccp->PriBucket);
243 
244 			p += sizeof(*wccp);
245 			l -= sizeof(*wccp);
246 
247 			printf(": ");
248 		}
249 
250 		/* FALLTHROUGH */
251 	}
252 	case ETHERTYPE_IP:
253 		ip_print(p, length);
254 		break;
255 	case ETHERTYPE_IPV6:
256 		ip6_print(p, length);
257 		break;
258 	case ETHERTYPE_MPLS:
259 		mpls_print(p, length);
260 		break;
261 	case ETHERTYPE_TRANSETHER:
262 		ether_tryprint(p, length, 0);
263 		break;
264 	default:
265 		printf("unknown-proto-%04x", proto);
266 	}
267 	return;
268 
269 trunc:
270 	printf("[|gre]");
271 }
272 
273 void
274 gre_print_1(const u_char *p, u_int length)
275 {
276 	uint16_t flags, proto;
277 	int l;
278 
279 	l = snapend - p;
280 
281 	flags = EXTRACT_16BITS(p);
282 	p += sizeof(flags);
283 	l -= sizeof(flags);
284 	length -= sizeof(flags);
285 
286 	if (l < sizeof(proto))
287 		goto trunc;
288 
289 	proto = EXTRACT_16BITS(p);
290 	p += sizeof(proto);
291 	l -= sizeof(proto);
292 	length -= sizeof(proto);
293 
294 	switch (proto) {
295 	case ETHERTYPE_PPP:
296 		gre_print_pptp(p, length, flags);
297 		break;
298 	case 0x6400:
299 		/* MikroTik RouterBoard Ethernet over IP (EoIP) */
300 		gre_print_eoip(p, length, flags);
301 		break;
302 	default:
303 		printf("unknown-gre1-proto-%04x", proto);
304 		break;
305 	}
306 
307 	return;
308 
309 trunc:
310 	printf("[|gre1]");
311 }
312 
313 void
314 gre_print_pptp(const u_char *p, u_int length, uint16_t flags)
315 {
316 	uint16_t len;
317 	int l;
318 
319 	l = snapend - p;
320 
321 	printf("pptp");
322 
323 	if (vflag) {
324 		printf(" [%s%s%s%s%s%s]",
325 		    (flags & GRE_CP) ? "C" : "",
326 		    (flags & GRE_RP) ? "R" : "",
327 		    (flags & GRE_KP) ? "K" : "",
328 		    (flags & GRE_SP) ? "S" : "",
329 		    (flags & GRE_sP) ? "s" : "",
330 		    (flags & GRE_AP) ? "A" : "");
331 	}
332 
333 	if (flags & GRE_CP) {
334 		printf(" cpset!");
335 		return;
336 	}
337 	if (flags & GRE_RP) {
338 		printf(" rpset!");
339 		return;
340 	}
341 	if ((flags & GRE_KP) == 0) {
342 		printf(" kpunset!");
343 		return;
344 	}
345 	if (flags & GRE_sP) {
346 		printf(" spset!");
347 		return;
348 	}
349 
350 	/* GRE_KP */
351 	if (l < sizeof(len))
352 		goto trunc;
353 	len = EXTRACT_16BITS(p);
354 	p += sizeof(len);
355 	l -= sizeof(len);
356 	length -= sizeof(len);
357 
358 	if (vflag)
359 		printf(" len %u", EXTRACT_16BITS(p));
360 
361 	if (l < 2)
362 		goto trunc;
363 	printf(" callid %u", EXTRACT_16BITS(p));
364 	p += 2;
365 	l -= 2;
366 	length -= 2;
367 
368 	if (flags & GRE_SP) {
369 		if (l < 4)
370 			goto trunc;
371 		printf(" seq %u", EXTRACT_32BITS(p));
372 		p += 4;
373 		l -= 4;
374 		length -= 4;
375 	}
376 
377 	if (flags & GRE_AP) {
378 		if (l < 4)
379 			goto trunc;
380 		printf(" ack %u", EXTRACT_32BITS(p));
381 		p += 4;
382 		l -= 4;
383 		length -= 4;
384 	}
385 
386 	if ((flags & GRE_SP) == 0)
387 		return;
388 
389         if (length < len) {
390                 (void)printf(" truncated-pptp - %d bytes missing!",
391 		    len - length);
392 		len = length;
393 	}
394 
395 	printf(": ");
396 
397 	ppp_hdlc_print(p, len);
398 	return;
399 
400 trunc:
401 	printf("[|pptp]");
402 }
403 
404 void
405 gre_print_eoip(const u_char *p, u_int length, uint16_t flags)
406 {
407 	uint16_t len, id;
408 	int l;
409 
410 	l = snapend - p;
411 
412 	printf("eoip");
413 
414 	flags &= ~GRE_VERS;
415 	if (flags != GRE_KP) {
416 		printf(" unknown-eoip-flags-%04x!", flags);
417 		return;
418 	}
419 
420 	if (l < sizeof(len))
421 		goto trunc;
422 
423 	len = EXTRACT_16BITS(p);
424 	p += sizeof(len);
425 	l -= sizeof(len);
426 	length -= sizeof(len);
427 
428 	if (l < sizeof(id))
429 		goto trunc;
430 
431 	id = EXTRACT_LE_16BITS(p);
432 	p += sizeof(id);
433 	l -= sizeof(id);
434 	length -= sizeof(id);
435 
436 	if (vflag)
437 		printf(" len=%u tunnel-id=%u", len, id);
438 	else
439 		printf(" %u", id);
440 
441         if (length < len) {
442                 (void)printf(" truncated-eoip - %d bytes missing!",
443 		    len - length);
444 		len = length;
445 	}
446 
447 	printf(": ");
448 
449 	if (len == 0)
450 		printf("keepalive");
451 	else
452 		ether_tryprint(p, len, 0);
453 
454 	return;
455 
456 trunc:
457 	printf("[|eoip]");
458 }
459 
460 void
461 gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen,
462     const u_char *bp, u_int len)
463 {
464 	switch (af) {
465 	case GRESRE_IP:
466 		printf(" (rtaf=ip");
467 		gre_sre_ip_print(sreoff, srelen, bp, len);
468 		printf(")");
469 		break;
470 	case GRESRE_ASN:
471 		printf(" (rtaf=asn");
472 		gre_sre_asn_print(sreoff, srelen, bp, len);
473 		printf(")");
474 		break;
475 	default:
476 		printf(" (rtaf=0x%x)", af);
477 	}
478 }
479 void
480 gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
481 {
482 	struct in_addr a;
483 	const u_char *up = bp;
484 
485 	if (sreoff & 3) {
486 		printf(" badoffset=%u", sreoff);
487 		return;
488 	}
489 	if (srelen & 3) {
490 		printf(" badlength=%u", srelen);
491 		return;
492 	}
493 	if (sreoff >= srelen) {
494 		printf(" badoff/len=%u/%u", sreoff, srelen);
495 		return;
496 	}
497 
498 	for (;;) {
499 		if (len < 4 || srelen == 0)
500 			return;
501 
502 		memcpy(&a, bp, sizeof(a));
503 		printf(" %s%s",
504 		    ((bp - up) == sreoff) ? "*" : "",
505 		    inet_ntoa(a));
506 
507 		bp += 4;
508 		len -= 4;
509 		srelen -= 4;
510 	}
511 }
512 
513 void
514 gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
515 {
516 	const u_char *up = bp;
517 
518 	if (sreoff & 1) {
519 		printf(" badoffset=%u", sreoff);
520 		return;
521 	}
522 	if (srelen & 1) {
523 		printf(" badlength=%u", srelen);
524 		return;
525 	}
526 	if (sreoff >= srelen) {
527 		printf(" badoff/len=%u/%u", sreoff, srelen);
528 		return;
529 	}
530 
531 	for (;;) {
532 		if (len < 2 || srelen == 0)
533 			return;
534 
535 		printf(" %s%x",
536 		    ((bp - up) == sreoff) ? "*" : "",
537 		    EXTRACT_16BITS(bp));
538 
539 		bp += 2;
540 		len -= 2;
541 		srelen -= 2;
542 	}
543 }
544 
545 struct vxlan_header {
546 	uint16_t	flags;
547 #define VXLAN_I			0x0800
548 	uint16_t	proto;
549 	uint32_t	vni;
550 #define VXLAN_VNI_SHIFT		8
551 #define VXLAN_VNI_MASK		(0xffffffU << VXLAN_VNI_SHIFT)
552 #define VXLAN_VNI_RESERVED	(~VXLAN_VNI_MASK)
553 };
554 
555 void
556 vxlan_print(const u_char *p, u_int length)
557 {
558 	const struct vxlan_header *vh;
559 	uint16_t flags, proto;
560 	uint32_t vni;
561 	size_t l;
562 
563 	l = snapend - p;
564 	if (l < sizeof(*vh)) {
565 		printf("[|vxlan]");
566 		return;
567 	}
568 	vh = (const struct vxlan_header *)p;
569 
570 	flags = ntohs(vh->flags);
571 	if (flags & ~VXLAN_I) {
572 		printf("vxlan-invalid-flags %04x", flags);
573 		return;
574 	}
575 
576 	proto = ntohs(vh->proto);
577 	if (proto != 0) {
578 		printf("vxlan-invalid-proto %04x", proto);
579 		return;
580 	}
581 
582 	vni = ntohl(vh->vni);
583 	if (flags & VXLAN_I) {
584 		if (vni & VXLAN_VNI_RESERVED) {
585 			printf("vxlan-vni-reserved %02x",
586 			    vni & VXLAN_VNI_RESERVED);
587 			return;
588 		}
589 
590 		printf("vxlan %u: ", vni >> VXLAN_VNI_SHIFT);
591 	} else {
592 		if (vh->vni != 0) {
593 			printf("vxlan-invalid-vni %08x\n", vni);
594 			return;
595 		}
596 
597 		printf("vxlan: ");
598 	}
599 
600 	p += sizeof(*vh);
601 	length -= sizeof(*vh);
602 
603 	ether_tryprint(p, length, 0);
604 }
605