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