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