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