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