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