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