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