xref: /freebsd/contrib/tcpdump/print-gre.c (revision 74bf4e164ba5851606a27d4feff27717452583e5)
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 #ifndef lint
40 static const char rcsid[] _U_ =
41     "@(#) $Header: /tcpdump/master/tcpdump/print-gre.c,v 1.22.2.2 2003/11/16 08:51:24 guy Exp $ (LBL)";
42 #endif
43 
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47 
48 #include <tcpdump-stdinc.h>
49 
50 #include <stdio.h>
51 #include <string.h>
52 
53 #include "interface.h"
54 #include "addrtoname.h"
55 #include "extract.h"
56 
57 #include "ip.h"
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 #define	GRE_VERS	0x0007		/* protocol version */
67 
68 #define	GREPROTO_IP	0x0800		/* IP */
69 #define	GREPROTO_PPP	0x880b		/* PPTP */
70 #define	GREPROTO_ISO	0x00fe		/* OSI */
71 
72 /* source route entry types */
73 #define	GRESRE_IP	0x0800		/* IP */
74 #define	GRESRE_ASN	0xfffe		/* ASN */
75 
76 void gre_print_0(const u_char *, u_int);
77 void gre_print_1(const u_char *, u_int);
78 void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int);
79 void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int);
80 void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int);
81 
82 void
83 gre_print(const u_char *bp, u_int length)
84 {
85 	u_int len = length, vers;
86 
87 	if (len < 2) {
88 		printf("[|gre]");
89 		return;
90 	}
91 	vers = EXTRACT_16BITS(bp) & 7;
92 
93 	if (vers == 0)
94 		gre_print_0(bp, len);
95 	else if (vers == 1)
96 		gre_print_1(bp, len);
97 	else
98 		printf("gre-unknown-version=%u", vers);
99 	return;
100 
101 }
102 
103 void
104 gre_print_0(const u_char *bp, u_int length)
105 {
106 	u_int len = length;
107 	u_int16_t flags, prot;
108 
109 	flags = EXTRACT_16BITS(bp);
110 	if (vflag) {
111 		printf("[%s%s%s%s%s] ",
112 		    (flags & GRE_CP) ? "C" : "",
113 		    (flags & GRE_RP) ? "R" : "",
114 		    (flags & GRE_KP) ? "K" : "",
115 		    (flags & GRE_SP) ? "S" : "",
116 		    (flags & GRE_sP) ? "s" : "");
117 	}
118 
119 	len -= 2;
120 	bp += 2;
121 
122 	if (len < 2)
123 		goto trunc;
124 	prot = EXTRACT_16BITS(bp);
125 	len -= 2;
126 	bp += 2;
127 
128 	if ((flags & GRE_CP) | (flags & GRE_RP)) {
129 		if (len < 2)
130 			goto trunc;
131 		if (vflag)
132 			printf("sum 0x%x ", EXTRACT_16BITS(bp));
133 		bp += 2;
134 		len -= 2;
135 
136 		if (len < 2)
137 			goto trunc;
138 		printf("off 0x%x ", EXTRACT_16BITS(bp));
139 		bp += 2;
140 		len -= 2;
141 	}
142 
143 	if (flags & GRE_KP) {
144 		if (len < 4)
145 			goto trunc;
146 		printf("key=0x%x ", EXTRACT_32BITS(bp));
147 		bp += 4;
148 		len -= 4;
149 	}
150 
151 	if (flags & GRE_SP) {
152 		if (len < 4)
153 			goto trunc;
154 		printf("seq %u ", EXTRACT_32BITS(bp));
155 		bp += 4;
156 		len -= 4;
157 	}
158 
159 	if (flags & GRE_RP) {
160 		for (;;) {
161 			u_int16_t af;
162 			u_int8_t sreoff;
163 			u_int8_t srelen;
164 
165 			if (len < 4)
166 				goto trunc;
167 			af = EXTRACT_16BITS(bp);
168 			sreoff = *(bp + 2);
169 			srelen = *(bp + 3);
170 			bp += 4;
171 			len -= 4;
172 
173 			if (af == 0 && srelen == 0)
174 				break;
175 
176 			gre_sre_print(af, sreoff, srelen, bp, len);
177 
178 			if (len < srelen)
179 				goto trunc;
180 			bp += srelen;
181 			len -= srelen;
182 		}
183 	}
184 
185 	switch (prot) {
186 	case GREPROTO_IP:
187 		ip_print(bp, len);
188 		break;
189 	case GREPROTO_ISO:
190 		isoclns_print(bp, len, len);
191 		break;
192 	default:
193 		printf("gre-proto-0x%x", prot);
194 	}
195 	return;
196 
197 trunc:
198 	printf("[|gre]");
199 }
200 
201 void
202 gre_print_1(const u_char *bp, u_int length)
203 {
204 	u_int len = length;
205 	u_int16_t flags, prot;
206 
207 	flags = EXTRACT_16BITS(bp);
208 	len -= 2;
209 	bp += 2;
210 
211 	if (vflag) {
212 		printf("[%s%s%s%s%s%s] ",
213 		    (flags & GRE_CP) ? "C" : "",
214 		    (flags & GRE_RP) ? "R" : "",
215 		    (flags & GRE_KP) ? "K" : "",
216 		    (flags & GRE_SP) ? "S" : "",
217 		    (flags & GRE_sP) ? "s" : "",
218 		    (flags & GRE_AP) ? "A" : "");
219 	}
220 
221 	if (len < 2)
222 		goto trunc;
223 	prot = EXTRACT_16BITS(bp);
224 	len -= 2;
225 	bp += 2;
226 
227 	if (flags & GRE_CP) {
228 		printf("cpset!");
229 		return;
230 	}
231 	if (flags & GRE_RP) {
232 		printf("rpset!");
233 		return;
234 	}
235 	if ((flags & GRE_KP) == 0) {
236 		printf("kpunset!");
237 		return;
238 	}
239 	if (flags & GRE_sP) {
240 		printf("spset!");
241 		return;
242 	}
243 
244 	if (flags & GRE_KP) {
245 		u_int32_t k;
246 
247 		if (len < 4)
248 			goto trunc;
249 		k = EXTRACT_32BITS(bp);
250 		printf("call %d ", k & 0xffff);
251 		len -= 4;
252 		bp += 4;
253 	}
254 
255 	if (flags & GRE_SP) {
256 		if (len < 4)
257 			goto trunc;
258 		printf("seq %u ", EXTRACT_32BITS(bp));
259 		bp += 4;
260 		len -= 4;
261 	}
262 
263 	if (flags & GRE_AP) {
264 		if (len < 4)
265 			goto trunc;
266 		printf("ack %u ", EXTRACT_32BITS(bp));
267 		bp += 4;
268 		len -= 4;
269 	}
270 
271 	if ((flags & GRE_SP) == 0) {
272 		printf("no-payload");
273 		return;
274 	}
275 
276 	switch (prot) {
277 	case GREPROTO_PPP:
278 		printf("gre-ppp-payload");
279 		break;
280 	default:
281 		printf("gre-proto-0x%x", prot);
282 		break;
283 	}
284 	return;
285 
286 trunc:
287 	printf("[|gre]");
288 }
289 
290 void
291 gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen,
292     const u_char *bp, u_int len)
293 {
294 	switch (af) {
295 	case GRESRE_IP:
296 		printf("(rtaf=ip");
297 		gre_sre_ip_print(sreoff, srelen, bp, len);
298 		printf(") ");
299 		break;
300 	case GRESRE_ASN:
301 		printf("(rtaf=asn");
302 		gre_sre_asn_print(sreoff, srelen, bp, len);
303 		printf(") ");
304 		break;
305 	default:
306 		printf("(rtaf=0x%x) ", af);
307 	}
308 }
309 void
310 gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
311 {
312 	struct in_addr a;
313 	const u_char *up = bp;
314 
315 	if (sreoff & 3) {
316 		printf(" badoffset=%u", sreoff);
317 		return;
318 	}
319 	if (srelen & 3) {
320 		printf(" badlength=%u", srelen);
321 		return;
322 	}
323 	if (sreoff >= srelen) {
324 		printf(" badoff/len=%u/%u", sreoff, srelen);
325 		return;
326 	}
327 
328 	for (;;) {
329 		if (len < 4 || srelen == 0)
330 			return;
331 
332 		memcpy(&a, bp, sizeof(a));
333 		printf(" %s%s",
334 		    ((bp - up) == sreoff) ? "*" : "",
335 		    inet_ntoa(a));
336 
337 		bp += 4;
338 		len -= 4;
339 		srelen -= 4;
340 	}
341 }
342 
343 void
344 gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
345 {
346 	const u_char *up = bp;
347 
348 	if (sreoff & 1) {
349 		printf(" badoffset=%u", sreoff);
350 		return;
351 	}
352 	if (srelen & 1) {
353 		printf(" badlength=%u", srelen);
354 		return;
355 	}
356 	if (sreoff >= srelen) {
357 		printf(" badoff/len=%u/%u", sreoff, srelen);
358 		return;
359 	}
360 
361 	for (;;) {
362 		if (len < 2 || srelen == 0)
363 			return;
364 
365 		printf(" %s%x",
366 		    ((bp - up) == sreoff) ? "*" : "",
367 		    EXTRACT_16BITS(bp));
368 
369 		bp += 2;
370 		len -= 2;
371 		srelen -= 2;
372 	}
373 }
374