xref: /openbsd-src/usr.sbin/tcpdump/print-gre.c (revision 6c6408334dbede3a2c0dcd9ff9c489157df0c856)
1 /*	$OpenBSD: print-gre.c,v 1.19 2018/02/24 08:53:36 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_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int);
83 void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int);
84 void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int);
85 
86 void
87 gre_print(const u_char *p, u_int length)
88 {
89 	uint16_t vers;
90 	int l;
91 
92 	l = snapend - p;
93 
94 	if (l < sizeof(vers)) {
95 		printf("[|gre]");
96 		return;
97 	}
98 	vers = EXTRACT_16BITS(p) & GRE_VERS;
99 
100 	switch (vers) {
101 	case 0:
102 		gre_print_0(p, length);
103 		break;
104 	case 1:
105 		gre_print_1(p, length);
106 		break;
107 	default:
108 		printf("gre-unknown-version=%u", vers);
109 		break;
110 	}
111 }
112 
113 void
114 gre_print_0(const u_char *p, u_int length)
115 {
116 	uint16_t flags, proto;
117 	u_int l;
118 
119 	l = snapend - p;
120 
121 	flags = EXTRACT_16BITS(p);
122 	p += sizeof(flags);
123 	l -= sizeof(flags);
124 	length -= sizeof(flags);
125 
126 	printf("gre");
127 
128 	if (vflag) {
129 		printf(" [%s%s%s%s%s]",
130 		    (flags & GRE_CP) ? "C" : "",
131 		    (flags & GRE_RP) ? "R" : "",
132 		    (flags & GRE_KP) ? "K" : "",
133 		    (flags & GRE_SP) ? "S" : "",
134 		    (flags & GRE_sP) ? "s" : "");
135 	}
136 
137 	if (l < sizeof(proto))
138 		goto trunc;
139 	proto = EXTRACT_16BITS(p);
140 	p += sizeof(proto);
141 	l -= sizeof(proto);
142 	length -= sizeof(proto);
143 
144 	if ((flags & GRE_CP) | (flags & GRE_RP)) {
145 		if (l < 2)
146 			goto trunc;
147 		if ((flags & GRE_CP) && vflag)
148 			printf(" sum 0x%x", EXTRACT_16BITS(p));
149 		p += 2;
150 		l -= 2;
151 		length -= 2;
152 
153 		if (l < 2)
154 			goto trunc;
155 		if (flags & GRE_RP)
156 			printf(" off 0x%x", EXTRACT_16BITS(p));
157 		p += 2;
158 		l -= 2;
159 		length -= 2;
160 	}
161 
162 	if (flags & GRE_KP) {
163 		uint32_t key, vsid;
164 
165 		if (l < sizeof(key))
166 			goto trunc;
167 		key = EXTRACT_32BITS(p);
168 		p += sizeof(key);
169 		l -= sizeof(key);
170 		length -= sizeof(key);
171 
172 		/* maybe NVGRE, or key entropy? */
173 		vsid = (key & NVGRE_VSID_MASK) >> NVGRE_VSID_SHIFT;
174 		printf(" key=%u|%u+%02x", key, vsid,
175 		    (key & NVGRE_FLOWID_MASK) >> NVGRE_FLOWID_SHIFT);
176 	}
177 
178 	if (flags & GRE_SP) {
179 		if (l < 4)
180 			goto trunc;
181 		printf(" seq %u", EXTRACT_32BITS(p));
182 		p += 4;
183 		l -= 4;
184 		length -= 4;
185 	}
186 
187 	if (flags & GRE_RP) {
188 		for (;;) {
189 			u_int16_t af;
190 			u_int8_t sreoff;
191 			u_int8_t srelen;
192 
193 			if (l < 4)
194 				goto trunc;
195 			af = EXTRACT_16BITS(p);
196 			sreoff = *(p + 2);
197 			srelen = *(p + 3);
198 			p += 4;
199 			l -= 4;
200 			length -= 4;
201 
202 			if (af == 0 && srelen == 0)
203 				break;
204 
205 			gre_sre_print(af, sreoff, srelen, p, l);
206 
207 			if (l < srelen)
208 				goto trunc;
209 			p += srelen;
210 			l -= srelen;
211 			length -= srelen;
212 		}
213 	}
214 
215 	printf(" ");
216 
217 	switch (proto) {
218 	case 0:
219 		printf("keep-alive");
220 		break;
221 	case GRE_WCCP: {
222 		printf("wccp ");
223 
224 		if (l == 0)
225 			return;
226 
227 		if (*p >> 4 != 4) {
228 			struct wccp_redirect *wccp;
229 
230 			if (l < sizeof(*wccp)) {
231 				printf("[|wccp]");
232 				return;
233 			}
234 
235 			wccp = (struct wccp_redirect *)p;
236 
237 			printf("D:%c A:%c SId:%u Alt:%u Pri:%u",
238 			    (wccp->flags & WCCP_D) ? '1' : '0',
239 			    (wccp->flags & WCCP_A) ? '1' : '0',
240 			    wccp->ServiceId, wccp->AltBucket, wccp->PriBucket);
241 
242 			p += sizeof(*wccp);
243 			l -= sizeof(*wccp);
244 
245 			printf(": ");
246 		}
247 
248 		/* FALLTHROUGH */
249 	}
250 	case ETHERTYPE_IP:
251 		ip_print(p, length);
252 		break;
253 	case ETHERTYPE_IPV6:
254 		ip6_print(p, length);
255 		break;
256 	case ETHERTYPE_MPLS:
257 		mpls_print(p, length);
258 		break;
259 	case ETHERTYPE_TRANSETHER:
260 		ether_tryprint(p, length, 0);
261 		break;
262 	default:
263 		printf("unknown-proto-%04x", proto);
264 	}
265 	return;
266 
267 trunc:
268 	printf("[|gre]");
269 }
270 
271 void
272 gre_print_1(const u_char *p, u_int length)
273 {
274 	uint16_t flags, proto, len;
275 	int l;
276 
277 	l = snapend - p;
278 
279 	flags = EXTRACT_16BITS(p);
280 	p += sizeof(flags);
281 	l -= sizeof(flags);
282 	length -= sizeof(flags);
283 
284 	printf("pptp");
285 
286 	if (vflag) {
287 		printf(" [%s%s%s%s%s%s] ",
288 		    (flags & GRE_CP) ? "C" : "",
289 		    (flags & GRE_RP) ? "R" : "",
290 		    (flags & GRE_KP) ? "K" : "",
291 		    (flags & GRE_SP) ? "S" : "",
292 		    (flags & GRE_sP) ? "s" : "",
293 		    (flags & GRE_AP) ? "A" : "");
294 	}
295 
296 	if (l < sizeof(proto))
297 		goto trunc;
298 
299 	proto = EXTRACT_16BITS(p);
300 	p += sizeof(proto);
301 	l -= sizeof(proto);
302 	length -= sizeof(proto);
303 
304 	if (flags & GRE_CP) {
305 		printf(" cpset!");
306 		return;
307 	}
308 	if (flags & GRE_RP) {
309 		printf(" rpset!");
310 		return;
311 	}
312 	if ((flags & GRE_KP) == 0) {
313 		printf(" kpunset!");
314 		return;
315 	}
316 	if (flags & GRE_sP) {
317 		printf(" spset!");
318 		return;
319 	}
320 
321 	/* GRE_KP */
322 	if (l < sizeof(len))
323 		goto trunc;
324 	len = EXTRACT_16BITS(p);
325 	p += sizeof(len);
326 	l -= sizeof(len);
327 	length -= sizeof(len);
328 
329 	if (vflag)
330 		printf(" len %u", EXTRACT_16BITS(p));
331 
332 	if (l < 2)
333 		goto trunc;
334 	printf(" callid %u", EXTRACT_16BITS(p));
335 	p += 2;
336 	l -= 2;
337 	length -= 2;
338 
339 	if (flags & GRE_SP) {
340 		if (l < 4)
341 			goto trunc;
342 		printf(" seq %u", EXTRACT_32BITS(p));
343 		p += 4;
344 		l -= 4;
345 		length -= 4;
346 	}
347 
348 	if (flags & GRE_AP) {
349 		if (l < 4)
350 			goto trunc;
351 		printf(" ack %u", EXTRACT_32BITS(p));
352 		p += 4;
353 		l -= 4;
354 		length -= 4;
355 	}
356 
357 	if ((flags & GRE_SP) == 0)
358 		return;
359 
360         if (length < len) {
361                 (void)printf(" truncated-pptp - %d bytes missing!",
362 		    len - length);
363 		len = length;
364 	}
365 
366 	printf(": ");
367 
368 	switch (proto) {
369 	case ETHERTYPE_PPP:
370 		ppp_hdlc_print(p, len);
371 		break;
372 	default:
373 		printf("unknown-proto-%04x", proto);
374 		break;
375 	}
376 	return;
377 
378 trunc:
379 	printf("[|pptp]");
380 }
381 
382 void
383 gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen,
384     const u_char *bp, u_int len)
385 {
386 	switch (af) {
387 	case GRESRE_IP:
388 		printf(" (rtaf=ip");
389 		gre_sre_ip_print(sreoff, srelen, bp, len);
390 		printf(")");
391 		break;
392 	case GRESRE_ASN:
393 		printf(" (rtaf=asn");
394 		gre_sre_asn_print(sreoff, srelen, bp, len);
395 		printf(")");
396 		break;
397 	default:
398 		printf(" (rtaf=0x%x)", af);
399 	}
400 }
401 void
402 gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
403 {
404 	struct in_addr a;
405 	const u_char *up = bp;
406 
407 	if (sreoff & 3) {
408 		printf(" badoffset=%u", sreoff);
409 		return;
410 	}
411 	if (srelen & 3) {
412 		printf(" badlength=%u", srelen);
413 		return;
414 	}
415 	if (sreoff >= srelen) {
416 		printf(" badoff/len=%u/%u", sreoff, srelen);
417 		return;
418 	}
419 
420 	for (;;) {
421 		if (len < 4 || srelen == 0)
422 			return;
423 
424 		memcpy(&a, bp, sizeof(a));
425 		printf(" %s%s",
426 		    ((bp - up) == sreoff) ? "*" : "",
427 		    inet_ntoa(a));
428 
429 		bp += 4;
430 		len -= 4;
431 		srelen -= 4;
432 	}
433 }
434 
435 void
436 gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
437 {
438 	const u_char *up = bp;
439 
440 	if (sreoff & 1) {
441 		printf(" badoffset=%u", sreoff);
442 		return;
443 	}
444 	if (srelen & 1) {
445 		printf(" badlength=%u", srelen);
446 		return;
447 	}
448 	if (sreoff >= srelen) {
449 		printf(" badoff/len=%u/%u", sreoff, srelen);
450 		return;
451 	}
452 
453 	for (;;) {
454 		if (len < 2 || srelen == 0)
455 			return;
456 
457 		printf(" %s%x",
458 		    ((bp - up) == sreoff) ? "*" : "",
459 		    EXTRACT_16BITS(bp));
460 
461 		bp += 2;
462 		len -= 2;
463 		srelen -= 2;
464 	}
465 }
466