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