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