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