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