1190815Srmacklem/* $OpenBSD: print-gre.c,v 1.6 2002/10/30 03:04:04 fgsch Exp $ */ 2190815Srmacklem 3190815Srmacklem/* 4190815Srmacklem * Copyright (c) 2002 Jason L. Wright (jason@thought.net) 5190815Srmacklem * All rights reserved. 6190815Srmacklem * 7190815Srmacklem * Redistribution and use in source and binary forms, with or without 8190815Srmacklem * modification, are permitted provided that the following conditions 9190815Srmacklem * are met: 10190815Srmacklem * 1. Redistributions of source code must retain the above copyright 11190815Srmacklem * notice, this list of conditions and the following disclaimer. 12190815Srmacklem * 2. Redistributions in binary form must reproduce the above copyright 13190815Srmacklem * notice, this list of conditions and the following disclaimer in the 14190815Srmacklem * documentation and/or other materials provided with the distribution. 15190815Srmacklem * 16190815Srmacklem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17190815Srmacklem * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18190815Srmacklem * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19190815Srmacklem * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20190815Srmacklem * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21190815Srmacklem * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22190815Srmacklem * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23190815Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24190815Srmacklem * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25190815Srmacklem * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26190815Srmacklem * POSSIBILITY OF SUCH DAMAGE. 27190815Srmacklem */ 28190815Srmacklem 29190815Srmacklem/* \summary: Generic Routing Encapsulation (GRE) printer */ 30190815Srmacklem 31190815Srmacklem/* 32190815Srmacklem * netdissect printer for GRE - Generic Routing Encapsulation 33190815Srmacklem * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE) 34190815Srmacklem */ 35190815Srmacklem 36190815Srmacklem#include <sys/cdefs.h> 37190815Srmacklem#ifndef lint 38190815Srmacklem__RCSID("$NetBSD: print-gre.c,v 1.10 2023/08/17 20:19:40 christos Exp $"); 39190815Srmacklem#endif 40190815Srmacklem 41190815Srmacklem#ifdef HAVE_CONFIG_H 42190815Srmacklem#include <config.h> 43190815Srmacklem#endif 44190815Srmacklem 45190815Srmacklem#include "netdissect-stdinc.h" 46190815Srmacklem 47190815Srmacklem#include "netdissect.h" 48190815Srmacklem#include "addrtostr.h" 49190815Srmacklem#include "extract.h" 50190815Srmacklem#include "ethertype.h" 51190815Srmacklem 52190815Srmacklem 53190815Srmacklem#define GRE_CP 0x8000 /* checksum present */ 54190815Srmacklem#define GRE_RP 0x4000 /* routing present */ 55190815Srmacklem#define GRE_KP 0x2000 /* key present */ 56190815Srmacklem#define GRE_SP 0x1000 /* sequence# present */ 57190815Srmacklem#define GRE_sP 0x0800 /* source routing */ 58190815Srmacklem#define GRE_AP 0x0080 /* acknowledgment# present */ 59190815Srmacklem 60190815Srmacklemstatic const struct tok gre_flag_values[] = { 61190815Srmacklem { GRE_CP, "checksum present"}, 62190815Srmacklem { GRE_RP, "routing present"}, 63190815Srmacklem { GRE_KP, "key present"}, 64190815Srmacklem { GRE_SP, "sequence# present"}, 65190815Srmacklem { GRE_sP, "source routing present"}, 66217432Srmacklem { GRE_AP, "ack present"}, 67221439Srmacklem { 0, NULL } 68221439Srmacklem}; 69241561Srmacklem 70241561Srmacklem#define GRE_RECRS_MASK 0x0700 /* recursion count */ 71243782Srmacklem#define GRE_VERS_MASK 0x0007 /* protocol version */ 72291527Srmacklem 73190815Srmacklem/* source route entry types */ 74243782Srmacklem#define GRESRE_IP 0x0800 /* IP */ 75243782Srmacklem#define GRESRE_ASN 0xfffe /* ASN */ 76243782Srmacklem 77243782Srmacklemstatic void gre_print_0(netdissect_options *, const u_char *, u_int); 78243782Srmacklemstatic void gre_print_1(netdissect_options *, const u_char *, u_int); 79243782Srmacklemstatic int gre_sre_print(netdissect_options *, uint16_t, uint8_t, uint8_t, const u_char *, u_int); 80243782Srmacklemstatic int gre_sre_ip_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int); 81190815Srmacklemstatic int gre_sre_asn_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int); 82 83void 84gre_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 108trunc: 109 nd_print_trunc(ndo); 110} 111 112static void 113gre_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 235trunc: 236 nd_print_trunc(ndo); 237} 238 239static void 240gre_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 319trunc: 320 nd_print_trunc(ndo); 321} 322 323static int 324gre_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 347static int 348gre_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); 381trunc: 382 return 0; 383} 384 385static int 386gre_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); 417trunc: 418 return 0; 419} 420