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