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 case ETHERTYPE_IPV6: 204 ip6_print(ndo, bp, len); 205 break; 206 case ETHERTYPE_MPLS: 207 mpls_print(ndo, bp, len); 208 break; 209 case ETHERTYPE_IPX: 210 ipx_print(ndo, bp, len); 211 break; 212 case ETHERTYPE_ATALK: 213 atalk_print(ndo, bp, len); 214 break; 215 case ETHERTYPE_GRE_ISO: 216 isoclns_print(ndo, bp, len, len); 217 break; 218 case ETHERTYPE_TEB: 219 ether_print(ndo, bp, len, len, NULL, NULL); 220 break; 221 default: 222 ND_PRINT((ndo, "gre-proto-0x%x", prot)); 223 } 224 return; 225 226 trunc: 227 ND_PRINT((ndo, "%s", tstr)); 228 } 229 230 static void 231 gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length) 232 { 233 u_int len = length; 234 uint16_t flags, prot; 235 236 flags = EXTRACT_16BITS(bp); 237 len -= 2; 238 bp += 2; 239 240 if (ndo->ndo_vflag) 241 ND_PRINT((ndo, ", Flags [%s]", 242 bittok2str(gre_flag_values,"none",flags))); 243 244 if (len < 2) 245 goto trunc; 246 prot = EXTRACT_16BITS(bp); 247 len -= 2; 248 bp += 2; 249 250 251 if (flags & GRE_KP) { 252 uint32_t k; 253 254 if (len < 4) 255 goto trunc; 256 k = EXTRACT_32BITS(bp); 257 ND_PRINT((ndo, ", call %d", k & 0xffff)); 258 len -= 4; 259 bp += 4; 260 } 261 262 if (flags & GRE_SP) { 263 if (len < 4) 264 goto trunc; 265 ND_PRINT((ndo, ", seq %u", EXTRACT_32BITS(bp))); 266 bp += 4; 267 len -= 4; 268 } 269 270 if (flags & GRE_AP) { 271 if (len < 4) 272 goto trunc; 273 ND_PRINT((ndo, ", ack %u", EXTRACT_32BITS(bp))); 274 bp += 4; 275 len -= 4; 276 } 277 278 if ((flags & GRE_SP) == 0) 279 ND_PRINT((ndo, ", no-payload")); 280 281 if (ndo->ndo_eflag) 282 ND_PRINT((ndo, ", proto %s (0x%04x)", 283 tok2str(ethertype_values,"unknown",prot), 284 prot)); 285 286 ND_PRINT((ndo, ", length %u",length)); 287 288 if ((flags & GRE_SP) == 0) 289 return; 290 291 if (ndo->ndo_vflag < 1) 292 ND_PRINT((ndo, ": ")); /* put in a colon as protocol demarc */ 293 else 294 ND_PRINT((ndo, "\n\t")); /* if verbose go multiline */ 295 296 switch (prot) { 297 case ETHERTYPE_PPP: 298 ppp_print(ndo, bp, len); 299 break; 300 default: 301 ND_PRINT((ndo, "gre-proto-0x%x", prot)); 302 break; 303 } 304 return; 305 306 trunc: 307 ND_PRINT((ndo, "%s", tstr)); 308 } 309 310 static void 311 gre_sre_print(netdissect_options *ndo, uint16_t af, uint8_t sreoff, 312 uint8_t srelen, const u_char *bp, u_int len) 313 { 314 switch (af) { 315 case GRESRE_IP: 316 ND_PRINT((ndo, ", (rtaf=ip")); 317 gre_sre_ip_print(ndo, sreoff, srelen, bp, len); 318 ND_PRINT((ndo, ") ")); 319 break; 320 case GRESRE_ASN: 321 ND_PRINT((ndo, ", (rtaf=asn")); 322 gre_sre_asn_print(ndo, sreoff, srelen, bp, len); 323 ND_PRINT((ndo, ") ")); 324 break; 325 default: 326 ND_PRINT((ndo, ", (rtaf=0x%x) ", af)); 327 } 328 } 329 330 static void 331 gre_sre_ip_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen, 332 const u_char *bp, u_int len) 333 { 334 struct in_addr a; 335 const u_char *up = bp; 336 337 if (sreoff & 3) { 338 ND_PRINT((ndo, ", badoffset=%u", sreoff)); 339 return; 340 } 341 if (srelen & 3) { 342 ND_PRINT((ndo, ", badlength=%u", srelen)); 343 return; 344 } 345 if (sreoff >= srelen) { 346 ND_PRINT((ndo, ", badoff/len=%u/%u", sreoff, srelen)); 347 return; 348 } 349 350 for (;;) { 351 if (len < 4 || srelen == 0) 352 return; 353 354 memcpy(&a, bp, sizeof(a)); 355 ND_PRINT((ndo, " %s%s", 356 ((bp - up) == sreoff) ? "*" : "", 357 inet_ntoa(a))); 358 359 bp += 4; 360 len -= 4; 361 srelen -= 4; 362 } 363 } 364 365 static void 366 gre_sre_asn_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen, 367 const u_char *bp, u_int len) 368 { 369 const u_char *up = bp; 370 371 if (sreoff & 1) { 372 ND_PRINT((ndo, ", badoffset=%u", sreoff)); 373 return; 374 } 375 if (srelen & 1) { 376 ND_PRINT((ndo, ", badlength=%u", srelen)); 377 return; 378 } 379 if (sreoff >= srelen) { 380 ND_PRINT((ndo, ", badoff/len=%u/%u", sreoff, srelen)); 381 return; 382 } 383 384 for (;;) { 385 if (len < 2 || srelen == 0) 386 return; 387 388 ND_PRINT((ndo, " %s%x", 389 ((bp - up) == sreoff) ? "*" : "", 390 EXTRACT_16BITS(bp))); 391 392 bp += 2; 393 len -= 2; 394 srelen -= 2; 395 } 396 } 397