xref: /netbsd-src/external/bsd/tcpdump/dist/print-gre.c (revision ccd9df534e375a4366c5b55f23782053c7a98d82)
1 /*	$OpenBSD: print-gre.c,v 1.6 2002/10/30 03:04:04 fgsch 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 /* \summary: Generic Routing Encapsulation (GRE) printer */
30 
31 /*
32  * netdissect printer for GRE - Generic Routing Encapsulation
33  * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE)
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __RCSID("$NetBSD: print-gre.c,v 1.10 2023/08/17 20:19:40 christos Exp $");
39 #endif
40 
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44 
45 #include "netdissect-stdinc.h"
46 
47 #include "netdissect.h"
48 #include "addrtostr.h"
49 #include "extract.h"
50 #include "ethertype.h"
51 
52 
53 #define	GRE_CP		0x8000		/* checksum present */
54 #define	GRE_RP		0x4000		/* routing present */
55 #define	GRE_KP		0x2000		/* key present */
56 #define	GRE_SP		0x1000		/* sequence# present */
57 #define	GRE_sP		0x0800		/* source routing */
58 #define	GRE_AP		0x0080		/* acknowledgment# present */
59 
60 static const struct tok gre_flag_values[] = {
61     { GRE_CP, "checksum present"},
62     { GRE_RP, "routing present"},
63     { GRE_KP, "key present"},
64     { GRE_SP, "sequence# present"},
65     { GRE_sP, "source routing present"},
66     { GRE_AP, "ack present"},
67     { 0, NULL }
68 };
69 
70 #define	GRE_RECRS_MASK	0x0700		/* recursion count */
71 #define	GRE_VERS_MASK	0x0007		/* protocol version */
72 
73 /* source route entry types */
74 #define	GRESRE_IP	0x0800		/* IP */
75 #define	GRESRE_ASN	0xfffe		/* ASN */
76 
77 static void gre_print_0(netdissect_options *, const u_char *, u_int);
78 static void gre_print_1(netdissect_options *, const u_char *, u_int);
79 static int gre_sre_print(netdissect_options *, uint16_t, uint8_t, uint8_t, const u_char *, u_int);
80 static int gre_sre_ip_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
81 static int gre_sre_asn_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
82 
83 void
84 gre_print(netdissect_options *ndo, const u_char *bp, u_int length)
85 {
86 	u_int len = length, vers;
87 
88 	ndo->ndo_protocol = "gre";
89 	ND_TCHECK_2(bp);
90 	if (len < 2)
91 		goto trunc;
92 	vers = GET_BE_U_2(bp) & GRE_VERS_MASK;
93 	ND_PRINT("GREv%u",vers);
94 
95 	switch(vers) {
96 	case 0:
97 		gre_print_0(ndo, bp, len);
98 		break;
99 	case 1:
100 		gre_print_1(ndo, bp, len);
101 		break;
102 	default:
103 		ND_PRINT(" ERROR: unknown-version");
104 		break;
105 	}
106 	return;
107 
108 trunc:
109 	nd_print_trunc(ndo);
110 }
111 
112 static void
113 gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length)
114 {
115 	u_int len = length;
116 	uint16_t flags, prot;
117 
118 	/* 16 bits ND_TCHECKed in gre_print() */
119 	flags = GET_BE_U_2(bp);
120 	if (ndo->ndo_vflag)
121 		ND_PRINT(", Flags [%s]",
122 			 bittok2str(gre_flag_values,"none",flags));
123 
124 	len -= 2;
125 	bp += 2;
126 
127 	ND_TCHECK_2(bp);
128 	if (len < 2)
129 		goto trunc;
130 	prot = GET_BE_U_2(bp);
131 	len -= 2;
132 	bp += 2;
133 
134 	if ((flags & GRE_CP) | (flags & GRE_RP)) {
135 		ND_TCHECK_2(bp);
136 		if (len < 2)
137 			goto trunc;
138 		if (ndo->ndo_vflag)
139 			ND_PRINT(", sum 0x%x", GET_BE_U_2(bp));
140 		bp += 2;
141 		len -= 2;
142 
143 		ND_TCHECK_2(bp);
144 		if (len < 2)
145 			goto trunc;
146 		ND_PRINT(", off 0x%x", GET_BE_U_2(bp));
147 		bp += 2;
148 		len -= 2;
149 	}
150 
151 	if (flags & GRE_KP) {
152 		ND_TCHECK_4(bp);
153 		if (len < 4)
154 			goto trunc;
155 		ND_PRINT(", key=0x%x", GET_BE_U_4(bp));
156 		bp += 4;
157 		len -= 4;
158 	}
159 
160 	if (flags & GRE_SP) {
161 		ND_TCHECK_4(bp);
162 		if (len < 4)
163 			goto trunc;
164 		ND_PRINT(", seq %u", GET_BE_U_4(bp));
165 		bp += 4;
166 		len -= 4;
167 	}
168 
169 	if (flags & GRE_RP) {
170 		for (;;) {
171 			uint16_t af;
172 			uint8_t sreoff;
173 			uint8_t srelen;
174 
175 			ND_TCHECK_4(bp);
176 			if (len < 4)
177 				goto trunc;
178 			af = GET_BE_U_2(bp);
179 			sreoff = GET_U_1(bp + 2);
180 			srelen = GET_U_1(bp + 3);
181 			bp += 4;
182 			len -= 4;
183 
184 			if (af == 0 && srelen == 0)
185 				break;
186 
187 			if (!gre_sre_print(ndo, af, sreoff, srelen, bp, len))
188 				goto trunc;
189 
190 			if (len < srelen)
191 				goto trunc;
192 			bp += srelen;
193 			len -= srelen;
194 		}
195 	}
196 
197 	if (ndo->ndo_eflag)
198 		ND_PRINT(", proto %s (0x%04x)",
199 			 tok2str(ethertype_values,"unknown",prot), prot);
200 
201 	ND_PRINT(", length %u",length);
202 
203 	if (ndo->ndo_vflag < 1)
204 		ND_PRINT(": "); /* put in a colon as protocol demarc */
205 	else
206 		ND_PRINT("\n\t"); /* if verbose go multiline */
207 
208 	switch (prot) {
209 	case ETHERTYPE_IP:
210 		ip_print(ndo, bp, len);
211 		break;
212 	case ETHERTYPE_IPV6:
213 		ip6_print(ndo, bp, len);
214 		break;
215 	case ETHERTYPE_MPLS:
216 		mpls_print(ndo, bp, len);
217 		break;
218 	case ETHERTYPE_IPX:
219 		ipx_print(ndo, bp, len);
220 		break;
221 	case ETHERTYPE_ATALK:
222 		atalk_print(ndo, bp, len);
223 		break;
224 	case ETHERTYPE_GRE_ISO:
225 		isoclns_print(ndo, bp, len);
226 		break;
227 	case ETHERTYPE_TEB:
228 		ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
229 		break;
230 	default:
231 		ND_PRINT("gre-proto-0x%x", prot);
232 	}
233 	return;
234 
235 trunc:
236 	nd_print_trunc(ndo);
237 }
238 
239 static void
240 gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length)
241 {
242 	u_int len = length;
243 	uint16_t flags, prot;
244 
245 	/* 16 bits ND_TCHECKed in gre_print() */
246 	flags = GET_BE_U_2(bp);
247 	len -= 2;
248 	bp += 2;
249 
250 	if (ndo->ndo_vflag)
251 		ND_PRINT(", Flags [%s]",
252 			 bittok2str(gre_flag_values,"none",flags));
253 
254 	ND_TCHECK_2(bp);
255 	if (len < 2)
256 		goto trunc;
257 	prot = GET_BE_U_2(bp);
258 	len -= 2;
259 	bp += 2;
260 
261 
262 	if (flags & GRE_KP) {
263 		uint32_t k;
264 
265 		ND_TCHECK_4(bp);
266 		if (len < 4)
267 			goto trunc;
268 		k = GET_BE_U_4(bp);
269 		ND_PRINT(", call %u", k & 0xffff);
270 		len -= 4;
271 		bp += 4;
272 	}
273 
274 	if (flags & GRE_SP) {
275 		ND_TCHECK_4(bp);
276 		if (len < 4)
277 			goto trunc;
278 		ND_PRINT(", seq %u", GET_BE_U_4(bp));
279 		bp += 4;
280 		len -= 4;
281 	}
282 
283 	if (flags & GRE_AP) {
284 		ND_TCHECK_4(bp);
285 		if (len < 4)
286 			goto trunc;
287 		ND_PRINT(", ack %u", GET_BE_U_4(bp));
288 		bp += 4;
289 		len -= 4;
290 	}
291 
292 	if ((flags & GRE_SP) == 0)
293 		ND_PRINT(", no-payload");
294 
295 	if (ndo->ndo_eflag)
296 		ND_PRINT(", proto %s (0x%04x)",
297 			 tok2str(ethertype_values,"unknown",prot), prot);
298 
299 	ND_PRINT(", length %u",length);
300 
301 	if ((flags & GRE_SP) == 0)
302 		return;
303 
304 	if (ndo->ndo_vflag < 1)
305 		ND_PRINT(": "); /* put in a colon as protocol demarc */
306 	else
307 		ND_PRINT("\n\t"); /* if verbose go multiline */
308 
309 	switch (prot) {
310 	case ETHERTYPE_PPP:
311 		ppp_print(ndo, bp, len);
312 		break;
313 	default:
314 		ND_PRINT("gre-proto-0x%x", prot);
315 		break;
316 	}
317 	return;
318 
319 trunc:
320 	nd_print_trunc(ndo);
321 }
322 
323 static int
324 gre_sre_print(netdissect_options *ndo, uint16_t af, uint8_t sreoff,
325 	      uint8_t srelen, const u_char *bp, u_int len)
326 {
327 	int ret;
328 
329 	switch (af) {
330 	case GRESRE_IP:
331 		ND_PRINT(", (rtaf=ip");
332 		ret = gre_sre_ip_print(ndo, sreoff, srelen, bp, len);
333 		ND_PRINT(")");
334 		break;
335 	case GRESRE_ASN:
336 		ND_PRINT(", (rtaf=asn");
337 		ret = gre_sre_asn_print(ndo, sreoff, srelen, bp, len);
338 		ND_PRINT(")");
339 		break;
340 	default:
341 		ND_PRINT(", (rtaf=0x%x)", af);
342 		ret = 1;
343 	}
344 	return (ret);
345 }
346 
347 static int
348 gre_sre_ip_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
349 		 const u_char *bp, u_int len)
350 {
351 	const u_char *up = bp;
352 	char buf[INET_ADDRSTRLEN];
353 
354 	if (sreoff & 3) {
355 		ND_PRINT(", badoffset=%u", sreoff);
356 		return (1);
357 	}
358 	if (srelen & 3) {
359 		ND_PRINT(", badlength=%u", srelen);
360 		return (1);
361 	}
362 	if (sreoff >= srelen) {
363 		ND_PRINT(", badoff/len=%u/%u", sreoff, srelen);
364 		return (1);
365 	}
366 
367 	while (srelen != 0) {
368 		ND_TCHECK_4(bp);
369 		if (len < 4)
370 			return (0);
371 
372 		addrtostr(bp, buf, sizeof(buf));
373 		ND_PRINT(" %s%s",
374 			 ((bp - up) == sreoff) ? "*" : "", buf);
375 
376 		bp += 4;
377 		len -= 4;
378 		srelen -= 4;
379 	}
380 	return (1);
381 trunc:
382 	return 0;
383 }
384 
385 static int
386 gre_sre_asn_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
387 		  const u_char *bp, u_int len)
388 {
389 	const u_char *up = bp;
390 
391 	if (sreoff & 1) {
392 		ND_PRINT(", badoffset=%u", sreoff);
393 		return (1);
394 	}
395 	if (srelen & 1) {
396 		ND_PRINT(", badlength=%u", srelen);
397 		return (1);
398 	}
399 	if (sreoff >= srelen) {
400 		ND_PRINT(", badoff/len=%u/%u", sreoff, srelen);
401 		return (1);
402 	}
403 
404 	while (srelen != 0) {
405 		ND_TCHECK_2(bp);
406 		if (len < 2)
407 			return (0);
408 
409 		ND_PRINT(" %s%x",
410 			 ((bp - up) == sreoff) ? "*" : "", GET_BE_U_2(bp));
411 
412 		bp += 2;
413 		len -= 2;
414 		srelen -= 2;
415 	}
416 	return (1);
417 trunc:
418 	return 0;
419 }
420