xref: /netbsd-src/external/bsd/tcpdump/dist/print-gre.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
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  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Jason L. Wright
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /* \summary: Generic Routing Encapsulation (GRE) printer */
35 
36 /*
37  * netdissect printer for GRE - Generic Routing Encapsulation
38  * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE)
39  */
40 
41 #include <sys/cdefs.h>
42 #ifndef lint
43 __RCSID("$NetBSD: print-gre.c,v 1.9 2017/09/08 14:01:13 christos Exp $");
44 #endif
45 
46 #ifdef HAVE_CONFIG_H
47 #include "config.h"
48 #endif
49 
50 #include <netdissect-stdinc.h>
51 
52 #include <string.h>
53 
54 #include "netdissect.h"
55 #include "addrtostr.h"
56 #include "extract.h"
57 #include "ethertype.h"
58 
59 static const char tstr[] = "[|gre]";
60 
61 #define	GRE_CP		0x8000		/* checksum present */
62 #define	GRE_RP		0x4000		/* routing present */
63 #define	GRE_KP		0x2000		/* key present */
64 #define	GRE_SP		0x1000		/* sequence# present */
65 #define	GRE_sP		0x0800		/* source routing */
66 #define	GRE_RECRS	0x0700		/* recursion count */
67 #define	GRE_AP		0x0080		/* acknowledgment# present */
68 
69 static const struct tok gre_flag_values[] = {
70     { GRE_CP, "checksum present"},
71     { GRE_RP, "routing present"},
72     { GRE_KP, "key present"},
73     { GRE_SP, "sequence# present"},
74     { GRE_sP, "source routing present"},
75     { GRE_RECRS, "recursion count"},
76     { GRE_AP, "ack present"},
77     { 0, NULL }
78 };
79 
80 #define	GRE_VERS_MASK	0x0007		/* protocol version */
81 
82 /* source route entry types */
83 #define	GRESRE_IP	0x0800		/* IP */
84 #define	GRESRE_ASN	0xfffe		/* ASN */
85 
86 static void gre_print_0(netdissect_options *, const u_char *, u_int);
87 static void gre_print_1(netdissect_options *, const u_char *, u_int);
88 static int gre_sre_print(netdissect_options *, uint16_t, uint8_t, uint8_t, const u_char *, u_int);
89 static int gre_sre_ip_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
90 static int gre_sre_asn_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
91 
92 void
93 gre_print(netdissect_options *ndo, const u_char *bp, u_int length)
94 {
95 	u_int len = length, vers;
96 
97 	ND_TCHECK2(*bp, 2);
98 	if (len < 2)
99 		goto trunc;
100 	vers = EXTRACT_16BITS(bp) & GRE_VERS_MASK;
101         ND_PRINT((ndo, "GREv%u",vers));
102 
103         switch(vers) {
104         case 0:
105             gre_print_0(ndo, bp, len);
106             break;
107         case 1:
108             gre_print_1(ndo, bp, len);
109             break;
110 	default:
111             ND_PRINT((ndo, " ERROR: unknown-version"));
112             break;
113         }
114         return;
115 
116 trunc:
117 	ND_PRINT((ndo, "%s", tstr));
118 	return;
119 }
120 
121 static void
122 gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length)
123 {
124 	u_int len = length;
125 	uint16_t flags, prot;
126 
127 	flags = EXTRACT_16BITS(bp);
128         if (ndo->ndo_vflag)
129             ND_PRINT((ndo, ", Flags [%s]",
130                    bittok2str(gre_flag_values,"none",flags)));
131 
132 	len -= 2;
133 	bp += 2;
134 
135 	ND_TCHECK2(*bp, 2);
136 	if (len < 2)
137 		goto trunc;
138 	prot = EXTRACT_16BITS(bp);
139 	len -= 2;
140 	bp += 2;
141 
142 	if ((flags & GRE_CP) | (flags & GRE_RP)) {
143 		ND_TCHECK2(*bp, 2);
144 		if (len < 2)
145 			goto trunc;
146 		if (ndo->ndo_vflag)
147 			ND_PRINT((ndo, ", sum 0x%x", EXTRACT_16BITS(bp)));
148 		bp += 2;
149 		len -= 2;
150 
151 		ND_TCHECK2(*bp, 2);
152 		if (len < 2)
153 			goto trunc;
154 		ND_PRINT((ndo, ", off 0x%x", EXTRACT_16BITS(bp)));
155 		bp += 2;
156 		len -= 2;
157 	}
158 
159 	if (flags & GRE_KP) {
160 		ND_TCHECK2(*bp, 4);
161 		if (len < 4)
162 			goto trunc;
163 		ND_PRINT((ndo, ", key=0x%x", EXTRACT_32BITS(bp)));
164 		bp += 4;
165 		len -= 4;
166 	}
167 
168 	if (flags & GRE_SP) {
169 		ND_TCHECK2(*bp, 4);
170 		if (len < 4)
171 			goto trunc;
172 		ND_PRINT((ndo, ", seq %u", EXTRACT_32BITS(bp)));
173 		bp += 4;
174 		len -= 4;
175 	}
176 
177 	if (flags & GRE_RP) {
178 		for (;;) {
179 			uint16_t af;
180 			uint8_t sreoff;
181 			uint8_t srelen;
182 
183 			ND_TCHECK2(*bp, 4);
184 			if (len < 4)
185 				goto trunc;
186 			af = EXTRACT_16BITS(bp);
187 			sreoff = *(bp + 2);
188 			srelen = *(bp + 3);
189 			bp += 4;
190 			len -= 4;
191 
192 			if (af == 0 && srelen == 0)
193 				break;
194 
195 			if (!gre_sre_print(ndo, af, sreoff, srelen, bp, len))
196 				goto trunc;
197 
198 			if (len < srelen)
199 				goto trunc;
200 			bp += srelen;
201 			len -= srelen;
202 		}
203 	}
204 
205         if (ndo->ndo_eflag)
206             ND_PRINT((ndo, ", proto %s (0x%04x)",
207                    tok2str(ethertype_values,"unknown",prot),
208                    prot));
209 
210         ND_PRINT((ndo, ", length %u",length));
211 
212         if (ndo->ndo_vflag < 1)
213             ND_PRINT((ndo, ": ")); /* put in a colon as protocol demarc */
214         else
215             ND_PRINT((ndo, "\n\t")); /* if verbose go multiline */
216 
217 	switch (prot) {
218 	case ETHERTYPE_IP:
219 	        ip_print(ndo, bp, len);
220 		break;
221 	case ETHERTYPE_IPV6:
222 		ip6_print(ndo, bp, len);
223 		break;
224 	case ETHERTYPE_MPLS:
225 		mpls_print(ndo, bp, len);
226 		break;
227 	case ETHERTYPE_IPX:
228 		ipx_print(ndo, bp, len);
229 		break;
230 	case ETHERTYPE_ATALK:
231 		atalk_print(ndo, bp, len);
232 		break;
233 	case ETHERTYPE_GRE_ISO:
234 		isoclns_print(ndo, bp, len);
235 		break;
236 	case ETHERTYPE_TEB:
237 		ether_print(ndo, bp, len, ndo->ndo_snapend - bp, NULL, NULL);
238 		break;
239 	default:
240 		ND_PRINT((ndo, "gre-proto-0x%x", prot));
241 	}
242 	return;
243 
244 trunc:
245 	ND_PRINT((ndo, "%s", tstr));
246 }
247 
248 static void
249 gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length)
250 {
251 	u_int len = length;
252 	uint16_t flags, prot;
253 
254 	flags = EXTRACT_16BITS(bp);
255 	len -= 2;
256 	bp += 2;
257 
258 	if (ndo->ndo_vflag)
259             ND_PRINT((ndo, ", Flags [%s]",
260                    bittok2str(gre_flag_values,"none",flags)));
261 
262 	ND_TCHECK2(*bp, 2);
263 	if (len < 2)
264 		goto trunc;
265 	prot = EXTRACT_16BITS(bp);
266 	len -= 2;
267 	bp += 2;
268 
269 
270 	if (flags & GRE_KP) {
271 		uint32_t k;
272 
273 		ND_TCHECK2(*bp, 4);
274 		if (len < 4)
275 			goto trunc;
276 		k = EXTRACT_32BITS(bp);
277 		ND_PRINT((ndo, ", call %d", k & 0xffff));
278 		len -= 4;
279 		bp += 4;
280 	}
281 
282 	if (flags & GRE_SP) {
283 		ND_TCHECK2(*bp, 4);
284 		if (len < 4)
285 			goto trunc;
286 		ND_PRINT((ndo, ", seq %u", EXTRACT_32BITS(bp)));
287 		bp += 4;
288 		len -= 4;
289 	}
290 
291 	if (flags & GRE_AP) {
292 		ND_TCHECK2(*bp, 4);
293 		if (len < 4)
294 			goto trunc;
295 		ND_PRINT((ndo, ", ack %u", EXTRACT_32BITS(bp)));
296 		bp += 4;
297 		len -= 4;
298 	}
299 
300 	if ((flags & GRE_SP) == 0)
301 		ND_PRINT((ndo, ", no-payload"));
302 
303         if (ndo->ndo_eflag)
304             ND_PRINT((ndo, ", proto %s (0x%04x)",
305                    tok2str(ethertype_values,"unknown",prot),
306                    prot));
307 
308         ND_PRINT((ndo, ", length %u",length));
309 
310         if ((flags & GRE_SP) == 0)
311             return;
312 
313         if (ndo->ndo_vflag < 1)
314             ND_PRINT((ndo, ": ")); /* put in a colon as protocol demarc */
315         else
316             ND_PRINT((ndo, "\n\t")); /* if verbose go multiline */
317 
318 	switch (prot) {
319 	case ETHERTYPE_PPP:
320 		ppp_print(ndo, bp, len);
321 		break;
322 	default:
323 		ND_PRINT((ndo, "gre-proto-0x%x", prot));
324 		break;
325 	}
326 	return;
327 
328 trunc:
329 	ND_PRINT((ndo, "%s", tstr));
330 }
331 
332 static int
333 gre_sre_print(netdissect_options *ndo, uint16_t af, uint8_t sreoff,
334     uint8_t srelen, const u_char *bp, u_int len)
335 {
336 	int ret;
337 
338 	switch (af) {
339 	case GRESRE_IP:
340 		ND_PRINT((ndo, ", (rtaf=ip"));
341 		ret = gre_sre_ip_print(ndo, sreoff, srelen, bp, len);
342 		ND_PRINT((ndo, ")"));
343 		break;
344 	case GRESRE_ASN:
345 		ND_PRINT((ndo, ", (rtaf=asn"));
346 		ret = gre_sre_asn_print(ndo, sreoff, srelen, bp, len);
347 		ND_PRINT((ndo, ")"));
348 		break;
349 	default:
350 		ND_PRINT((ndo, ", (rtaf=0x%x)", af));
351 		ret = 1;
352 	}
353 	return (ret);
354 }
355 
356 static int
357 gre_sre_ip_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
358                  const u_char *bp, u_int len)
359 {
360 	const u_char *up = bp;
361 	char buf[INET_ADDRSTRLEN];
362 
363 	if (sreoff & 3) {
364 		ND_PRINT((ndo, ", badoffset=%u", sreoff));
365 		return (1);
366 	}
367 	if (srelen & 3) {
368 		ND_PRINT((ndo, ", badlength=%u", srelen));
369 		return (1);
370 	}
371 	if (sreoff >= srelen) {
372 		ND_PRINT((ndo, ", badoff/len=%u/%u", sreoff, srelen));
373 		return (1);
374 	}
375 
376 	while (srelen != 0) {
377 		if (!ND_TTEST2(*bp, 4))
378 			return (0);
379 		if (len < 4)
380 			return (0);
381 
382 		addrtostr(bp, buf, sizeof(buf));
383 		ND_PRINT((ndo, " %s%s",
384 		    ((bp - up) == sreoff) ? "*" : "", buf));
385 
386 		bp += 4;
387 		len -= 4;
388 		srelen -= 4;
389 	}
390 	return (1);
391 }
392 
393 static int
394 gre_sre_asn_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
395                   const u_char *bp, u_int len)
396 {
397 	const u_char *up = bp;
398 
399 	if (sreoff & 1) {
400 		ND_PRINT((ndo, ", badoffset=%u", sreoff));
401 		return (1);
402 	}
403 	if (srelen & 1) {
404 		ND_PRINT((ndo, ", badlength=%u", srelen));
405 		return (1);
406 	}
407 	if (sreoff >= srelen) {
408 		ND_PRINT((ndo, ", badoff/len=%u/%u", sreoff, srelen));
409 		return (1);
410 	}
411 
412 	while (srelen != 0) {
413 		if (!ND_TTEST2(*bp, 2))
414 			return (0);
415 		if (len < 2)
416 			return (0);
417 
418 		ND_PRINT((ndo, " %s%x",
419 		    ((bp - up) == sreoff) ? "*" : "",
420 		    EXTRACT_16BITS(bp)));
421 
422 		bp += 2;
423 		len -= 2;
424 		srelen -= 2;
425 	}
426 	return (1);
427 }
428