1 /* $OpenBSD: print-gre.c,v 1.21 2018/07/06 07:13:21 dlg 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 /* 30 * tcpdump filter for GRE - Generic Routing Encapsulation 31 * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE) 32 */ 33 34 #include <sys/time.h> 35 #include <sys/uio.h> 36 #include <sys/socket.h> 37 38 #include <netinet/in.h> 39 #include <netinet/ip.h> 40 #include <arpa/inet.h> 41 42 #include <net/ethertypes.h> 43 44 #include <stdio.h> 45 #include <string.h> 46 47 #include "interface.h" 48 #include "addrtoname.h" 49 #include "extract.h" 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_RECRS 0x0700 /* recursion count */ 57 #define GRE_AP 0x0080 /* acknowledgment# present */ 58 #define GRE_VERS 0x0007 /* protocol version */ 59 60 /* source route entry types */ 61 #define GRESRE_IP 0x0800 /* IP */ 62 #define GRESRE_ASN 0xfffe /* ASN */ 63 64 #define NVGRE_VSID_MASK 0xffffff00U 65 #define NVGRE_VSID_SHIFT 8 66 #define NVGRE_FLOWID_MASK 0x000000ffU 67 #define NVGRE_FLOWID_SHIFT 0 68 69 #define GRE_WCCP 0x883e 70 71 struct wccp_redirect { 72 uint8_t flags; 73 #define WCCP_D (1 << 7) 74 #define WCCP_A (1 << 6) 75 uint8_t ServiceId; 76 uint8_t AltBucket; 77 uint8_t PriBucket; 78 }; 79 80 void gre_print_0(const u_char *, u_int); 81 void gre_print_1(const u_char *, u_int); 82 void gre_print_pptp(const u_char *, u_int, uint16_t); 83 void gre_print_eoip(const u_char *, u_int, uint16_t); 84 void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int); 85 void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int); 86 void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int); 87 88 void 89 gre_print(const u_char *p, u_int length) 90 { 91 uint16_t vers; 92 int l; 93 94 l = snapend - p; 95 96 if (l < sizeof(vers)) { 97 printf("[|gre]"); 98 return; 99 } 100 vers = EXTRACT_16BITS(p) & GRE_VERS; 101 102 switch (vers) { 103 case 0: 104 gre_print_0(p, length); 105 break; 106 case 1: 107 gre_print_1(p, length); 108 break; 109 default: 110 printf("gre-unknown-version=%u", vers); 111 break; 112 } 113 } 114 115 void 116 gre_print_0(const u_char *p, u_int length) 117 { 118 uint16_t flags, proto; 119 u_int l; 120 121 l = snapend - p; 122 123 flags = EXTRACT_16BITS(p); 124 p += sizeof(flags); 125 l -= sizeof(flags); 126 length -= sizeof(flags); 127 128 printf("gre"); 129 130 if (vflag) { 131 printf(" [%s%s%s%s%s]", 132 (flags & GRE_CP) ? "C" : "", 133 (flags & GRE_RP) ? "R" : "", 134 (flags & GRE_KP) ? "K" : "", 135 (flags & GRE_SP) ? "S" : "", 136 (flags & GRE_sP) ? "s" : ""); 137 } 138 139 if (l < sizeof(proto)) 140 goto trunc; 141 proto = EXTRACT_16BITS(p); 142 p += sizeof(proto); 143 l -= sizeof(proto); 144 length -= sizeof(proto); 145 146 if ((flags & GRE_CP) | (flags & GRE_RP)) { 147 if (l < 2) 148 goto trunc; 149 if ((flags & GRE_CP) && vflag) 150 printf(" sum 0x%x", EXTRACT_16BITS(p)); 151 p += 2; 152 l -= 2; 153 length -= 2; 154 155 if (l < 2) 156 goto trunc; 157 if (flags & GRE_RP) 158 printf(" off 0x%x", EXTRACT_16BITS(p)); 159 p += 2; 160 l -= 2; 161 length -= 2; 162 } 163 164 if (flags & GRE_KP) { 165 uint32_t key, vsid; 166 167 if (l < sizeof(key)) 168 goto trunc; 169 key = EXTRACT_32BITS(p); 170 p += sizeof(key); 171 l -= sizeof(key); 172 length -= sizeof(key); 173 174 /* maybe NVGRE, or key entropy? */ 175 vsid = (key & NVGRE_VSID_MASK) >> NVGRE_VSID_SHIFT; 176 printf(" key=%u|%u+%02x", key, vsid, 177 (key & NVGRE_FLOWID_MASK) >> NVGRE_FLOWID_SHIFT); 178 } 179 180 if (flags & GRE_SP) { 181 if (l < 4) 182 goto trunc; 183 printf(" seq %u", EXTRACT_32BITS(p)); 184 p += 4; 185 l -= 4; 186 length -= 4; 187 } 188 189 if (flags & GRE_RP) { 190 for (;;) { 191 u_int16_t af; 192 u_int8_t sreoff; 193 u_int8_t srelen; 194 195 if (l < 4) 196 goto trunc; 197 af = EXTRACT_16BITS(p); 198 sreoff = *(p + 2); 199 srelen = *(p + 3); 200 p += 4; 201 l -= 4; 202 length -= 4; 203 204 if (af == 0 && srelen == 0) 205 break; 206 207 gre_sre_print(af, sreoff, srelen, p, l); 208 209 if (l < srelen) 210 goto trunc; 211 p += srelen; 212 l -= srelen; 213 length -= srelen; 214 } 215 } 216 217 printf(" "); 218 219 switch (proto) { 220 case 0: 221 printf("keep-alive"); 222 break; 223 case GRE_WCCP: { 224 printf("wccp "); 225 226 if (l == 0) 227 return; 228 229 if (*p >> 4 != 4) { 230 struct wccp_redirect *wccp; 231 232 if (l < sizeof(*wccp)) { 233 printf("[|wccp]"); 234 return; 235 } 236 237 wccp = (struct wccp_redirect *)p; 238 239 printf("D:%c A:%c SId:%u Alt:%u Pri:%u", 240 (wccp->flags & WCCP_D) ? '1' : '0', 241 (wccp->flags & WCCP_A) ? '1' : '0', 242 wccp->ServiceId, wccp->AltBucket, wccp->PriBucket); 243 244 p += sizeof(*wccp); 245 l -= sizeof(*wccp); 246 247 printf(": "); 248 } 249 250 /* FALLTHROUGH */ 251 } 252 case ETHERTYPE_IP: 253 ip_print(p, length); 254 break; 255 case ETHERTYPE_IPV6: 256 ip6_print(p, length); 257 break; 258 case ETHERTYPE_MPLS: 259 mpls_print(p, length); 260 break; 261 case ETHERTYPE_TRANSETHER: 262 ether_tryprint(p, length, 0); 263 break; 264 default: 265 printf("unknown-proto-%04x", proto); 266 } 267 return; 268 269 trunc: 270 printf("[|gre]"); 271 } 272 273 void 274 gre_print_1(const u_char *p, u_int length) 275 { 276 uint16_t flags, proto; 277 int l; 278 279 l = snapend - p; 280 281 flags = EXTRACT_16BITS(p); 282 p += sizeof(flags); 283 l -= sizeof(flags); 284 length -= sizeof(flags); 285 286 if (l < sizeof(proto)) 287 goto trunc; 288 289 proto = EXTRACT_16BITS(p); 290 p += sizeof(proto); 291 l -= sizeof(proto); 292 length -= sizeof(proto); 293 294 switch (proto) { 295 case ETHERTYPE_PPP: 296 gre_print_pptp(p, length, flags); 297 break; 298 case 0x6400: 299 /* MikroTik RouterBoard Ethernet over IP (EoIP) */ 300 gre_print_eoip(p, length, flags); 301 break; 302 default: 303 printf("unknown-gre1-proto-%04x", proto); 304 break; 305 } 306 307 return; 308 309 trunc: 310 printf("[|gre1]"); 311 } 312 313 void 314 gre_print_pptp(const u_char *p, u_int length, uint16_t flags) 315 { 316 uint16_t len; 317 int l; 318 319 l = snapend - p; 320 321 printf("pptp"); 322 323 if (vflag) { 324 printf(" [%s%s%s%s%s%s]", 325 (flags & GRE_CP) ? "C" : "", 326 (flags & GRE_RP) ? "R" : "", 327 (flags & GRE_KP) ? "K" : "", 328 (flags & GRE_SP) ? "S" : "", 329 (flags & GRE_sP) ? "s" : "", 330 (flags & GRE_AP) ? "A" : ""); 331 } 332 333 if (flags & GRE_CP) { 334 printf(" cpset!"); 335 return; 336 } 337 if (flags & GRE_RP) { 338 printf(" rpset!"); 339 return; 340 } 341 if ((flags & GRE_KP) == 0) { 342 printf(" kpunset!"); 343 return; 344 } 345 if (flags & GRE_sP) { 346 printf(" spset!"); 347 return; 348 } 349 350 /* GRE_KP */ 351 if (l < sizeof(len)) 352 goto trunc; 353 len = EXTRACT_16BITS(p); 354 p += sizeof(len); 355 l -= sizeof(len); 356 length -= sizeof(len); 357 358 if (vflag) 359 printf(" len %u", EXTRACT_16BITS(p)); 360 361 if (l < 2) 362 goto trunc; 363 printf(" callid %u", EXTRACT_16BITS(p)); 364 p += 2; 365 l -= 2; 366 length -= 2; 367 368 if (flags & GRE_SP) { 369 if (l < 4) 370 goto trunc; 371 printf(" seq %u", EXTRACT_32BITS(p)); 372 p += 4; 373 l -= 4; 374 length -= 4; 375 } 376 377 if (flags & GRE_AP) { 378 if (l < 4) 379 goto trunc; 380 printf(" ack %u", EXTRACT_32BITS(p)); 381 p += 4; 382 l -= 4; 383 length -= 4; 384 } 385 386 if ((flags & GRE_SP) == 0) 387 return; 388 389 if (length < len) { 390 (void)printf(" truncated-pptp - %d bytes missing!", 391 len - length); 392 len = length; 393 } 394 395 printf(": "); 396 397 ppp_hdlc_print(p, len); 398 return; 399 400 trunc: 401 printf("[|pptp]"); 402 } 403 404 void 405 gre_print_eoip(const u_char *p, u_int length, uint16_t flags) 406 { 407 uint16_t len, id; 408 int l; 409 410 l = snapend - p; 411 412 printf("eoip"); 413 414 flags &= ~GRE_VERS; 415 if (flags != GRE_KP) { 416 printf(" unknown-eoip-flags-%04x!", flags); 417 return; 418 } 419 420 if (l < sizeof(len)) 421 goto trunc; 422 423 len = EXTRACT_16BITS(p); 424 p += sizeof(len); 425 l -= sizeof(len); 426 length -= sizeof(len); 427 428 if (l < sizeof(id)) 429 goto trunc; 430 431 id = EXTRACT_LE_16BITS(p); 432 p += sizeof(id); 433 l -= sizeof(id); 434 length -= sizeof(id); 435 436 if (vflag) 437 printf(" len=%u tunnel-id=%u", len, id); 438 else 439 printf(" %u", id); 440 441 if (length < len) { 442 (void)printf(" truncated-eoip - %d bytes missing!", 443 len - length); 444 len = length; 445 } 446 447 printf(": "); 448 449 if (len == 0) 450 printf("keepalive"); 451 else 452 ether_tryprint(p, len, 0); 453 454 return; 455 456 trunc: 457 printf("[|eoip]"); 458 } 459 460 void 461 gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen, 462 const u_char *bp, u_int len) 463 { 464 switch (af) { 465 case GRESRE_IP: 466 printf(" (rtaf=ip"); 467 gre_sre_ip_print(sreoff, srelen, bp, len); 468 printf(")"); 469 break; 470 case GRESRE_ASN: 471 printf(" (rtaf=asn"); 472 gre_sre_asn_print(sreoff, srelen, bp, len); 473 printf(")"); 474 break; 475 default: 476 printf(" (rtaf=0x%x)", af); 477 } 478 } 479 void 480 gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len) 481 { 482 struct in_addr a; 483 const u_char *up = bp; 484 485 if (sreoff & 3) { 486 printf(" badoffset=%u", sreoff); 487 return; 488 } 489 if (srelen & 3) { 490 printf(" badlength=%u", srelen); 491 return; 492 } 493 if (sreoff >= srelen) { 494 printf(" badoff/len=%u/%u", sreoff, srelen); 495 return; 496 } 497 498 for (;;) { 499 if (len < 4 || srelen == 0) 500 return; 501 502 memcpy(&a, bp, sizeof(a)); 503 printf(" %s%s", 504 ((bp - up) == sreoff) ? "*" : "", 505 inet_ntoa(a)); 506 507 bp += 4; 508 len -= 4; 509 srelen -= 4; 510 } 511 } 512 513 void 514 gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len) 515 { 516 const u_char *up = bp; 517 518 if (sreoff & 1) { 519 printf(" badoffset=%u", sreoff); 520 return; 521 } 522 if (srelen & 1) { 523 printf(" badlength=%u", srelen); 524 return; 525 } 526 if (sreoff >= srelen) { 527 printf(" badoff/len=%u/%u", sreoff, srelen); 528 return; 529 } 530 531 for (;;) { 532 if (len < 2 || srelen == 0) 533 return; 534 535 printf(" %s%x", 536 ((bp - up) == sreoff) ? "*" : "", 537 EXTRACT_16BITS(bp)); 538 539 bp += 2; 540 len -= 2; 541 srelen -= 2; 542 } 543 } 544 545 struct vxlan_header { 546 uint16_t flags; 547 #define VXLAN_I 0x0800 548 uint16_t proto; 549 uint32_t vni; 550 #define VXLAN_VNI_SHIFT 8 551 #define VXLAN_VNI_MASK (0xffffffU << VXLAN_VNI_SHIFT) 552 #define VXLAN_VNI_RESERVED (~VXLAN_VNI_MASK) 553 }; 554 555 void 556 vxlan_print(const u_char *p, u_int length) 557 { 558 const struct vxlan_header *vh; 559 uint16_t flags, proto; 560 uint32_t vni; 561 size_t l; 562 563 l = snapend - p; 564 if (l < sizeof(*vh)) { 565 printf("[|vxlan]"); 566 return; 567 } 568 vh = (const struct vxlan_header *)p; 569 570 flags = ntohs(vh->flags); 571 if (flags & ~VXLAN_I) { 572 printf("vxlan-invalid-flags %04x", flags); 573 return; 574 } 575 576 proto = ntohs(vh->proto); 577 if (proto != 0) { 578 printf("vxlan-invalid-proto %04x", proto); 579 return; 580 } 581 582 vni = ntohl(vh->vni); 583 if (flags & VXLAN_I) { 584 if (vni & VXLAN_VNI_RESERVED) { 585 printf("vxlan-vni-reserved %02x", 586 vni & VXLAN_VNI_RESERVED); 587 return; 588 } 589 590 printf("vxlan %u: ", vni >> VXLAN_VNI_SHIFT); 591 } else { 592 if (vh->vni != 0) { 593 printf("vxlan-invalid-vni %08x\n", vni); 594 return; 595 } 596 597 printf("vxlan: "); 598 } 599 600 p += sizeof(*vh); 601 length -= sizeof(*vh); 602 603 ether_tryprint(p, length, 0); 604 } 605