xref: /openbsd-src/usr.sbin/tcpdump/print-gre.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1 /*	$OpenBSD: print-gre.c,v 1.12 2016/12/13 06:40: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 void gre_print_0(const u_char *, u_int);
70 void gre_print_1(const u_char *, u_int);
71 void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int);
72 void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int);
73 void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int);
74 
75 void
76 gre_print(const u_char *bp, u_int length)
77 {
78 	u_int len = length, vers;
79 
80 	if (bp + len > snapend)
81 		len = snapend - bp;
82 
83 	if (len < 2) {
84 		printf("[|gre]");
85 		return;
86 	}
87 	vers = EXTRACT_16BITS(bp) & GRE_VERS;
88 
89 	switch (vers) {
90 	case 0:
91 		gre_print_0(bp, len);
92 		break;
93 	case 1:
94 		gre_print_1(bp, len);
95 		break;
96 	default:
97 		printf("gre-unknown-version=%u", vers);
98 		break;
99 	}
100 }
101 
102 void
103 gre_print_0(const u_char *bp, u_int length)
104 {
105 	u_int len = length;
106 	u_int16_t flags, prot;
107 
108 	flags = EXTRACT_16BITS(bp);
109 	if (vflag) {
110 		printf("[%s%s%s%s%s] ",
111 		    (flags & GRE_CP) ? "C" : "",
112 		    (flags & GRE_RP) ? "R" : "",
113 		    (flags & GRE_KP) ? "K" : "",
114 		    (flags & GRE_SP) ? "S" : "",
115 		    (flags & GRE_sP) ? "s" : "");
116 	}
117 
118 	len -= 2;
119 	bp += 2;
120 
121 	if (len < 2)
122 		goto trunc;
123 	prot = EXTRACT_16BITS(bp);
124 	printf("%s", etherproto_string(prot));
125 
126 	len -= 2;
127 	bp += 2;
128 
129 	if ((flags & GRE_CP) | (flags & GRE_RP)) {
130 		if (len < 2)
131 			goto trunc;
132 		if (vflag)
133 			printf(" sum 0x%x", EXTRACT_16BITS(bp));
134 		bp += 2;
135 		len -= 2;
136 
137 		if (len < 2)
138 			goto trunc;
139 		printf(" off 0x%x", EXTRACT_16BITS(bp));
140 		bp += 2;
141 		len -= 2;
142 	}
143 
144 	if (flags & GRE_KP) {
145 		uint32_t key, vsid;
146 
147 		if (len < 4)
148 			goto trunc;
149 		key = EXTRACT_32BITS(bp);
150 
151 		/* maybe NVGRE? */
152 		if (flags == (GRE_KP | 0) && prot == ETHERTYPE_TRANSETHER) {
153 			vsid = (key & NVGRE_VSID_MASK) >> NVGRE_VSID_SHIFT;
154 			printf(" NVGRE vsid=%u (0x%x)+flowid=0x%02x /",
155 			    vsid, vsid,
156 			    (key & NVGRE_FLOWID_MASK) >> NVGRE_FLOWID_SHIFT);
157 		}
158 		printf(" key=%u (0x%x)", key, key);
159 		bp += 4;
160 		len -= 4;
161 	}
162 
163 	if (flags & GRE_SP) {
164 		if (len < 4)
165 			goto trunc;
166 		printf(" seq %u", EXTRACT_32BITS(bp));
167 		bp += 4;
168 		len -= 4;
169 	}
170 
171 	if (flags & GRE_RP) {
172 		for (;;) {
173 			u_int16_t af;
174 			u_int8_t sreoff;
175 			u_int8_t srelen;
176 
177 			if (len < 4)
178 				goto trunc;
179 			af = EXTRACT_16BITS(bp);
180 			sreoff = *(bp + 2);
181 			srelen = *(bp + 3);
182 			bp += 4;
183 			len -= 4;
184 
185 			if (af == 0 && srelen == 0)
186 				break;
187 
188 			gre_sre_print(af, sreoff, srelen, bp, len);
189 
190 			if (len < srelen)
191 				goto trunc;
192 			bp += srelen;
193 			len -= srelen;
194 		}
195 	}
196 
197 	printf(": ");
198 
199 	switch (prot) {
200 	case ETHERTYPE_IP:
201 		ip_print(bp, len);
202 		break;
203 	case ETHERTYPE_IPV6:
204 		ip6_print(bp, len);
205 		break;
206 	case ETHERTYPE_MPLS:
207 		mpls_print(bp, len);
208 		break;
209 	case ETHERTYPE_TRANSETHER:
210 		ether_print(bp, len);
211 		break;
212 	default:
213 		printf("gre-proto-0x%x", prot);
214 	}
215 	return;
216 
217 trunc:
218 	printf("[|gre]");
219 }
220 
221 void
222 gre_print_1(const u_char *bp, u_int length)
223 {
224 	u_int len = length;
225 	u_int16_t flags, prot;
226 
227 	flags = EXTRACT_16BITS(bp);
228 	len -= 2;
229 	bp += 2;
230 
231 	if (vflag) {
232 		printf("[%s%s%s%s%s%s]",
233 		    (flags & GRE_CP) ? "C" : "",
234 		    (flags & GRE_RP) ? "R" : "",
235 		    (flags & GRE_KP) ? "K" : "",
236 		    (flags & GRE_SP) ? "S" : "",
237 		    (flags & GRE_sP) ? "s" : "",
238 		    (flags & GRE_AP) ? "A" : "");
239 	}
240 
241 	if (len < 2)
242 		goto trunc;
243 	prot = EXTRACT_16BITS(bp);
244 	len -= 2;
245 	bp += 2;
246 
247 	if (flags & GRE_CP) {
248 		printf(" cpset!");
249 		return;
250 	}
251 	if (flags & GRE_RP) {
252 		printf(" rpset!");
253 		return;
254 	}
255 	if ((flags & GRE_KP) == 0) {
256 		printf(" kpunset!");
257 		return;
258 	}
259 	if (flags & GRE_sP) {
260 		printf(" spset!");
261 		return;
262 	}
263 
264 	if (flags & GRE_KP) {
265 		u_int32_t k;
266 
267 		if (len < 4)
268 			goto trunc;
269 		k = EXTRACT_32BITS(bp);
270 		printf(" call %d", k & 0xffff);
271 		len -= 4;
272 		bp += 4;
273 	}
274 
275 	if (flags & GRE_SP) {
276 		if (len < 4)
277 			goto trunc;
278 		printf(" seq %u", EXTRACT_32BITS(bp));
279 		bp += 4;
280 		len -= 4;
281 	}
282 
283 	if (flags & GRE_AP) {
284 		if (len < 4)
285 			goto trunc;
286 		printf(" ack %u", EXTRACT_32BITS(bp));
287 		bp += 4;
288 		len -= 4;
289 	}
290 
291 	if ((flags & GRE_SP) == 0) {
292 		printf(" no-payload");
293 		return;
294 	}
295 
296 	printf(": ");
297 
298 	switch (prot) {
299 	case ETHERTYPE_PPP:
300 		printf("gre-ppp-payload");
301 		break;
302 	default:
303 		printf("gre-proto-0x%x", prot);
304 		break;
305 	}
306 	return;
307 
308 trunc:
309 	printf("[|gre]");
310 }
311 
312 void
313 gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen,
314     const u_char *bp, u_int len)
315 {
316 	switch (af) {
317 	case GRESRE_IP:
318 		printf(" (rtaf=ip");
319 		gre_sre_ip_print(sreoff, srelen, bp, len);
320 		printf(")");
321 		break;
322 	case GRESRE_ASN:
323 		printf(" (rtaf=asn");
324 		gre_sre_asn_print(sreoff, srelen, bp, len);
325 		printf(")");
326 		break;
327 	default:
328 		printf(" (rtaf=0x%x)", af);
329 	}
330 }
331 void
332 gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
333 {
334 	struct in_addr a;
335 	const u_char *up = bp;
336 
337 	if (sreoff & 3) {
338 		printf(" badoffset=%u", sreoff);
339 		return;
340 	}
341 	if (srelen & 3) {
342 		printf(" badlength=%u", srelen);
343 		return;
344 	}
345 	if (sreoff >= srelen) {
346 		printf(" badoff/len=%u/%u", sreoff, srelen);
347 		return;
348 	}
349 
350 	for (;;) {
351 		if (len < 4 || srelen == 0)
352 			return;
353 
354 		memcpy(&a, bp, sizeof(a));
355 		printf(" %s%s",
356 		    ((bp - up) == sreoff) ? "*" : "",
357 		    inet_ntoa(a));
358 
359 		bp += 4;
360 		len -= 4;
361 		srelen -= 4;
362 	}
363 }
364 
365 void
366 gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
367 {
368 	const u_char *up = bp;
369 
370 	if (sreoff & 1) {
371 		printf(" badoffset=%u", sreoff);
372 		return;
373 	}
374 	if (srelen & 1) {
375 		printf(" badlength=%u", srelen);
376 		return;
377 	}
378 	if (sreoff >= srelen) {
379 		printf(" badoff/len=%u/%u", sreoff, srelen);
380 		return;
381 	}
382 
383 	for (;;) {
384 		if (len < 2 || srelen == 0)
385 			return;
386 
387 		printf(" %s%x",
388 		    ((bp - up) == sreoff) ? "*" : "",
389 		    EXTRACT_16BITS(bp));
390 
391 		bp += 2;
392 		len -= 2;
393 		srelen -= 2;
394 	}
395 }
396