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