xref: /openbsd-src/usr.sbin/tcpdump/print-gre.c (revision 9f11ffb7133c203312a01e4b986886bc88c7d74b)
1 /*	$OpenBSD: print-gre.c,v 1.22 2019/02/05 10:57:48 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 #define ERSPAN_II	0x88be
71 #define ERSPAN_III	0x22eb
72 
73 struct wccp_redirect {
74 	uint8_t		flags;
75 #define WCCP_D			(1 << 7)
76 #define WCCP_A			(1 << 6)
77 	uint8_t		ServiceId;
78 	uint8_t		AltBucket;
79 	uint8_t		PriBucket;
80 };
81 
82 void gre_print_0(const u_char *, u_int);
83 void gre_print_1(const u_char *, u_int);
84 void gre_print_pptp(const u_char *, u_int, uint16_t);
85 void gre_print_eoip(const u_char *, u_int, uint16_t);
86 void gre_print_erspan2(const u_char *, u_int);
87 void gre_print_erspan3(const u_char *, u_int);
88 void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int);
89 void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int);
90 void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int);
91 
92 void
93 gre_print(const u_char *p, u_int length)
94 {
95 	uint16_t vers;
96 	int l;
97 
98 	l = snapend - p;
99 
100 	if (l < sizeof(vers)) {
101 		printf("[|gre]");
102 		return;
103 	}
104 	vers = EXTRACT_16BITS(p) & GRE_VERS;
105 
106 	switch (vers) {
107 	case 0:
108 		gre_print_0(p, length);
109 		break;
110 	case 1:
111 		gre_print_1(p, length);
112 		break;
113 	default:
114 		printf("gre-unknown-version=%u", vers);
115 		break;
116 	}
117 }
118 
119 void
120 gre_print_0(const u_char *p, u_int length)
121 {
122 	uint16_t flags, proto;
123 	u_int l;
124 
125 	l = snapend - p;
126 
127 	flags = EXTRACT_16BITS(p);
128 	p += sizeof(flags);
129 	l -= sizeof(flags);
130 	length -= sizeof(flags);
131 
132 	printf("gre");
133 
134 	if (vflag) {
135 		printf(" [%s%s%s%s%s]",
136 		    (flags & GRE_CP) ? "C" : "",
137 		    (flags & GRE_RP) ? "R" : "",
138 		    (flags & GRE_KP) ? "K" : "",
139 		    (flags & GRE_SP) ? "S" : "",
140 		    (flags & GRE_sP) ? "s" : "");
141 	}
142 
143 	if (l < sizeof(proto))
144 		goto trunc;
145 	proto = EXTRACT_16BITS(p);
146 	p += sizeof(proto);
147 	l -= sizeof(proto);
148 	length -= sizeof(proto);
149 
150 	if ((flags & GRE_CP) | (flags & GRE_RP)) {
151 		if (l < 2)
152 			goto trunc;
153 		if ((flags & GRE_CP) && vflag)
154 			printf(" sum 0x%x", EXTRACT_16BITS(p));
155 		p += 2;
156 		l -= 2;
157 		length -= 2;
158 
159 		if (l < 2)
160 			goto trunc;
161 		if (flags & GRE_RP)
162 			printf(" off 0x%x", EXTRACT_16BITS(p));
163 		p += 2;
164 		l -= 2;
165 		length -= 2;
166 	}
167 
168 	if (flags & GRE_KP) {
169 		uint32_t key, vsid;
170 
171 		if (l < sizeof(key))
172 			goto trunc;
173 		key = EXTRACT_32BITS(p);
174 		p += sizeof(key);
175 		l -= sizeof(key);
176 		length -= sizeof(key);
177 
178 		/* maybe NVGRE, or key entropy? */
179 		vsid = (key & NVGRE_VSID_MASK) >> NVGRE_VSID_SHIFT;
180 		printf(" key=%u|%u+%02x", key, vsid,
181 		    (key & NVGRE_FLOWID_MASK) >> NVGRE_FLOWID_SHIFT);
182 	}
183 
184 	if (flags & GRE_SP) {
185 		if (l < 4)
186 			goto trunc;
187 		printf(" seq %u", EXTRACT_32BITS(p));
188 		p += 4;
189 		l -= 4;
190 		length -= 4;
191 	}
192 
193 	if (flags & GRE_RP) {
194 		for (;;) {
195 			u_int16_t af;
196 			u_int8_t sreoff;
197 			u_int8_t srelen;
198 
199 			if (l < 4)
200 				goto trunc;
201 			af = EXTRACT_16BITS(p);
202 			sreoff = *(p + 2);
203 			srelen = *(p + 3);
204 			p += 4;
205 			l -= 4;
206 			length -= 4;
207 
208 			if (af == 0 && srelen == 0)
209 				break;
210 
211 			gre_sre_print(af, sreoff, srelen, p, l);
212 
213 			if (l < srelen)
214 				goto trunc;
215 			p += srelen;
216 			l -= srelen;
217 			length -= srelen;
218 		}
219 	}
220 
221 	printf(" ");
222 
223 	switch (proto) {
224 	case 0:
225 		printf("keep-alive");
226 		break;
227 	case GRE_WCCP: {
228 		printf("wccp ");
229 
230 		if (l == 0)
231 			return;
232 
233 		if (*p >> 4 != 4) {
234 			struct wccp_redirect *wccp;
235 
236 			if (l < sizeof(*wccp)) {
237 				printf("[|wccp]");
238 				return;
239 			}
240 
241 			wccp = (struct wccp_redirect *)p;
242 
243 			printf("D:%c A:%c SId:%u Alt:%u Pri:%u",
244 			    (wccp->flags & WCCP_D) ? '1' : '0',
245 			    (wccp->flags & WCCP_A) ? '1' : '0',
246 			    wccp->ServiceId, wccp->AltBucket, wccp->PriBucket);
247 
248 			p += sizeof(*wccp);
249 			l -= sizeof(*wccp);
250 
251 			printf(": ");
252 		}
253 
254 		/* FALLTHROUGH */
255 	}
256 	case ETHERTYPE_IP:
257 		ip_print(p, length);
258 		break;
259 	case ETHERTYPE_IPV6:
260 		ip6_print(p, length);
261 		break;
262 	case ETHERTYPE_MPLS:
263 		mpls_print(p, length);
264 		break;
265 	case ETHERTYPE_TRANSETHER:
266 		ether_tryprint(p, length, 0);
267 		break;
268 	case ERSPAN_II:
269 		gre_print_erspan2(p, length);
270 		break;
271 	default:
272 		printf("unknown-proto-%04x", proto);
273 	}
274 	return;
275 
276 trunc:
277 	printf("[|gre]");
278 }
279 
280 void
281 gre_print_1(const u_char *p, u_int length)
282 {
283 	uint16_t flags, proto;
284 	int l;
285 
286 	l = snapend - p;
287 
288 	flags = EXTRACT_16BITS(p);
289 	p += sizeof(flags);
290 	l -= sizeof(flags);
291 	length -= sizeof(flags);
292 
293 	if (l < sizeof(proto))
294 		goto trunc;
295 
296 	proto = EXTRACT_16BITS(p);
297 	p += sizeof(proto);
298 	l -= sizeof(proto);
299 	length -= sizeof(proto);
300 
301 	switch (proto) {
302 	case ETHERTYPE_PPP:
303 		gre_print_pptp(p, length, flags);
304 		break;
305 	case 0x6400:
306 		/* MikroTik RouterBoard Ethernet over IP (EoIP) */
307 		gre_print_eoip(p, length, flags);
308 		break;
309 	default:
310 		printf("unknown-gre1-proto-%04x", proto);
311 		break;
312 	}
313 
314 	return;
315 
316 trunc:
317 	printf("[|gre1]");
318 }
319 
320 void
321 gre_print_pptp(const u_char *p, u_int length, uint16_t flags)
322 {
323 	uint16_t len;
324 	int l;
325 
326 	l = snapend - p;
327 
328 	printf("pptp");
329 
330 	if (vflag) {
331 		printf(" [%s%s%s%s%s%s]",
332 		    (flags & GRE_CP) ? "C" : "",
333 		    (flags & GRE_RP) ? "R" : "",
334 		    (flags & GRE_KP) ? "K" : "",
335 		    (flags & GRE_SP) ? "S" : "",
336 		    (flags & GRE_sP) ? "s" : "",
337 		    (flags & GRE_AP) ? "A" : "");
338 	}
339 
340 	if (flags & GRE_CP) {
341 		printf(" cpset!");
342 		return;
343 	}
344 	if (flags & GRE_RP) {
345 		printf(" rpset!");
346 		return;
347 	}
348 	if ((flags & GRE_KP) == 0) {
349 		printf(" kpunset!");
350 		return;
351 	}
352 	if (flags & GRE_sP) {
353 		printf(" spset!");
354 		return;
355 	}
356 
357 	/* GRE_KP */
358 	if (l < sizeof(len))
359 		goto trunc;
360 	len = EXTRACT_16BITS(p);
361 	p += sizeof(len);
362 	l -= sizeof(len);
363 	length -= sizeof(len);
364 
365 	if (vflag)
366 		printf(" len %u", EXTRACT_16BITS(p));
367 
368 	if (l < 2)
369 		goto trunc;
370 	printf(" callid %u", EXTRACT_16BITS(p));
371 	p += 2;
372 	l -= 2;
373 	length -= 2;
374 
375 	if (flags & GRE_SP) {
376 		if (l < 4)
377 			goto trunc;
378 		printf(" seq %u", EXTRACT_32BITS(p));
379 		p += 4;
380 		l -= 4;
381 		length -= 4;
382 	}
383 
384 	if (flags & GRE_AP) {
385 		if (l < 4)
386 			goto trunc;
387 		printf(" ack %u", EXTRACT_32BITS(p));
388 		p += 4;
389 		l -= 4;
390 		length -= 4;
391 	}
392 
393 	if ((flags & GRE_SP) == 0)
394 		return;
395 
396         if (length < len) {
397                 (void)printf(" truncated-pptp - %d bytes missing!",
398 		    len - length);
399 		len = length;
400 	}
401 
402 	printf(": ");
403 
404 	ppp_hdlc_print(p, len);
405 	return;
406 
407 trunc:
408 	printf("[|pptp]");
409 }
410 
411 void
412 gre_print_eoip(const u_char *p, u_int length, uint16_t flags)
413 {
414 	uint16_t len, id;
415 	int l;
416 
417 	l = snapend - p;
418 
419 	printf("eoip");
420 
421 	flags &= ~GRE_VERS;
422 	if (flags != GRE_KP) {
423 		printf(" unknown-eoip-flags-%04x!", flags);
424 		return;
425 	}
426 
427 	if (l < sizeof(len))
428 		goto trunc;
429 
430 	len = EXTRACT_16BITS(p);
431 	p += sizeof(len);
432 	l -= sizeof(len);
433 	length -= sizeof(len);
434 
435 	if (l < sizeof(id))
436 		goto trunc;
437 
438 	id = EXTRACT_LE_16BITS(p);
439 	p += sizeof(id);
440 	l -= sizeof(id);
441 	length -= sizeof(id);
442 
443 	if (vflag)
444 		printf(" len=%u tunnel-id=%u", len, id);
445 	else
446 		printf(" %u", id);
447 
448         if (length < len) {
449                 (void)printf(" truncated-eoip - %d bytes missing!",
450 		    len - length);
451 		len = length;
452 	}
453 
454 	printf(": ");
455 
456 	if (len == 0)
457 		printf("keepalive");
458 	else
459 		ether_tryprint(p, len, 0);
460 
461 	return;
462 
463 trunc:
464 	printf("[|eoip]");
465 }
466 
467 #define ERSPAN2_VER_SHIFT	28
468 #define ERSPAN2_VER_MASK	(0xfU << ERSPAN2_VER_SHIFT)
469 #define ERSPAN2_VER		(0x1U << ERSPAN2_VER_SHIFT)
470 #define ERSPAN2_VLAN_SHIFT	16
471 #define ERSPAN2_VLAN_MASK	(0xfffU << ERSPAN2_VLAN_SHIFT)
472 #define ERSPAN2_COS_SHIFT	13
473 #define ERSPAN2_COS_MASK	(0x7U << ERSPAN2_COS_SHIFT)
474 #define ERSPAN2_EN_SHIFT	11
475 #define ERSPAN2_EN_MASK		(0x3U << ERSPAN2_EN_SHIFT)
476 #define ERSPAN2_EN_NONE		(0x0U << ERSPAN2_EN_SHIFT)
477 #define ERSPAN2_EN_ISL		(0x1U << ERSPAN2_EN_SHIFT)
478 #define ERSPAN2_EN_DOT1Q	(0x2U << ERSPAN2_EN_SHIFT)
479 #define ERSPAN2_EN_VLAN		(0x3U << ERSPAN2_EN_SHIFT)
480 #define ERSPAN2_T_SHIFT		10
481 #define ERSPAN2_T_MASK		(0x1U << ERSPAN2_T_SHIFT)
482 #define ERSPAN2_SID_SHIFT	0
483 #define ERSPAN2_SID_MASK	(0x3ffU << ERSPAN2_SID_SHIFT)
484 
485 #define ERSPAN2_INDEX_SHIFT	0
486 #define ERSPAN2_INDEX_MASK	(0xfffffU << ERSPAN2_INDEX_SHIFT)
487 
488 void
489 gre_print_erspan2(const u_char *bp, u_int len)
490 {
491 	uint32_t hdr, ver, vlan, cos, en, sid, index;
492 	u_int l;
493 
494 	printf("erspan");
495 
496 	l = snapend - bp;
497 	if (l < sizeof(hdr))
498 		goto trunc;
499 
500 	hdr = EXTRACT_32BITS(bp);
501 	bp += sizeof(hdr);
502 	l -= sizeof(hdr);
503 	len -= sizeof(hdr);
504 
505 	ver = hdr & ERSPAN2_VER_MASK;
506 	if (ver != ERSPAN2_VER) {
507 		ver >>= ERSPAN2_VER_SHIFT;
508 		printf(" erspan-unknown-version-%x", ver);
509 		return;
510 	}
511 
512 	if (vflag)
513 		printf(" II");
514 
515 	sid = (hdr & ERSPAN2_SID_MASK) >> ERSPAN2_SID_SHIFT;
516 	printf(" session %u", sid);
517 
518 	en = hdr & ERSPAN2_EN_MASK;
519 	vlan = (hdr & ERSPAN2_VLAN_MASK) >> ERSPAN2_VLAN_SHIFT;
520 	switch (en) {
521 	case ERSPAN2_EN_NONE:
522 		break;
523 	case ERSPAN2_EN_ISL:
524 		printf(" isl %u", vlan);
525 		break;
526 	case ERSPAN2_EN_DOT1Q:
527 		printf(" vlan %u", vlan);
528 		break;
529 	case ERSPAN2_EN_VLAN:
530 		printf(" vlan payload");
531 		break;
532 	}
533 
534 	if (vflag) {
535 		cos = (hdr & ERSPAN2_COS_MASK) >> ERSPAN2_COS_SHIFT;
536 		printf(" cos %u", cos);
537 
538 		if (hdr & ERSPAN2_T_MASK)
539 			printf(" truncated");
540 	}
541 
542 	if (l < sizeof(hdr))
543 		goto trunc;
544 
545 	hdr = EXTRACT_32BITS(bp);
546 	bp += sizeof(hdr);
547 	l -= sizeof(hdr);
548 	len -= sizeof(hdr);
549 
550 	if (vflag) {
551 		index = (hdr & ERSPAN2_INDEX_MASK) >> ERSPAN2_INDEX_SHIFT;
552 		printf(" index %u", index);
553 	}
554 
555 	printf(": ");
556 	ether_tryprint(bp, len, 0);
557 	return;
558 
559 trunc:
560 	printf(" [|erspan]");
561 }
562 
563 void
564 gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen,
565     const u_char *bp, u_int len)
566 {
567 	switch (af) {
568 	case GRESRE_IP:
569 		printf(" (rtaf=ip");
570 		gre_sre_ip_print(sreoff, srelen, bp, len);
571 		printf(")");
572 		break;
573 	case GRESRE_ASN:
574 		printf(" (rtaf=asn");
575 		gre_sre_asn_print(sreoff, srelen, bp, len);
576 		printf(")");
577 		break;
578 	default:
579 		printf(" (rtaf=0x%x)", af);
580 	}
581 }
582 void
583 gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
584 {
585 	struct in_addr a;
586 	const u_char *up = bp;
587 
588 	if (sreoff & 3) {
589 		printf(" badoffset=%u", sreoff);
590 		return;
591 	}
592 	if (srelen & 3) {
593 		printf(" badlength=%u", srelen);
594 		return;
595 	}
596 	if (sreoff >= srelen) {
597 		printf(" badoff/len=%u/%u", sreoff, srelen);
598 		return;
599 	}
600 
601 	for (;;) {
602 		if (len < 4 || srelen == 0)
603 			return;
604 
605 		memcpy(&a, bp, sizeof(a));
606 		printf(" %s%s",
607 		    ((bp - up) == sreoff) ? "*" : "",
608 		    inet_ntoa(a));
609 
610 		bp += 4;
611 		len -= 4;
612 		srelen -= 4;
613 	}
614 }
615 
616 void
617 gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
618 {
619 	const u_char *up = bp;
620 
621 	if (sreoff & 1) {
622 		printf(" badoffset=%u", sreoff);
623 		return;
624 	}
625 	if (srelen & 1) {
626 		printf(" badlength=%u", srelen);
627 		return;
628 	}
629 	if (sreoff >= srelen) {
630 		printf(" badoff/len=%u/%u", sreoff, srelen);
631 		return;
632 	}
633 
634 	for (;;) {
635 		if (len < 2 || srelen == 0)
636 			return;
637 
638 		printf(" %s%x",
639 		    ((bp - up) == sreoff) ? "*" : "",
640 		    EXTRACT_16BITS(bp));
641 
642 		bp += 2;
643 		len -= 2;
644 		srelen -= 2;
645 	}
646 }
647 
648 struct vxlan_header {
649 	uint16_t	flags;
650 #define VXLAN_I			0x0800
651 	uint16_t	proto;
652 	uint32_t	vni;
653 #define VXLAN_VNI_SHIFT		8
654 #define VXLAN_VNI_MASK		(0xffffffU << VXLAN_VNI_SHIFT)
655 #define VXLAN_VNI_RESERVED	(~VXLAN_VNI_MASK)
656 };
657 
658 void
659 vxlan_print(const u_char *p, u_int length)
660 {
661 	const struct vxlan_header *vh;
662 	uint16_t flags, proto;
663 	uint32_t vni;
664 	size_t l;
665 
666 	l = snapend - p;
667 	if (l < sizeof(*vh)) {
668 		printf("[|vxlan]");
669 		return;
670 	}
671 	vh = (const struct vxlan_header *)p;
672 
673 	flags = ntohs(vh->flags);
674 	if (flags & ~VXLAN_I) {
675 		printf("vxlan-invalid-flags %04x", flags);
676 		return;
677 	}
678 
679 	proto = ntohs(vh->proto);
680 	if (proto != 0) {
681 		printf("vxlan-invalid-proto %04x", proto);
682 		return;
683 	}
684 
685 	vni = ntohl(vh->vni);
686 	if (flags & VXLAN_I) {
687 		if (vni & VXLAN_VNI_RESERVED) {
688 			printf("vxlan-vni-reserved %02x",
689 			    vni & VXLAN_VNI_RESERVED);
690 			return;
691 		}
692 
693 		printf("vxlan %u: ", vni >> VXLAN_VNI_SHIFT);
694 	} else {
695 		if (vh->vni != 0) {
696 			printf("vxlan-invalid-vni %08x\n", vni);
697 			return;
698 		}
699 
700 		printf("vxlan: ");
701 	}
702 
703 	p += sizeof(*vh);
704 	length -= sizeof(*vh);
705 
706 	ether_tryprint(p, length, 0);
707 }
708