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 } 399