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