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