1 /* $OpenBSD: print-gre.c,v 1.26 2019/05/17 06:47:10 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 #define ERSPAN_II 0x88be 71 #define ERSPAN_III 0x22eb 72 73 struct wccp_redirect { 74 uint8_t flags; 75 #define WCCP_D (1 << 7) 76 #define WCCP_A (1 << 6) 77 uint8_t ServiceId; 78 uint8_t AltBucket; 79 uint8_t PriBucket; 80 }; 81 82 void gre_print_0(const u_char *, u_int); 83 void gre_print_1(const u_char *, u_int); 84 void gre_print_pptp(const u_char *, u_int, uint16_t); 85 void gre_print_eoip(const u_char *, u_int, uint16_t); 86 void gre_print_erspan(uint16_t, const u_char *, u_int); 87 void gre_print_erspan3(const u_char *, u_int); 88 void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int); 89 void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int); 90 void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int); 91 92 void 93 gre_print(const u_char *p, u_int length) 94 { 95 uint16_t vers; 96 int l; 97 98 l = snapend - p; 99 100 if (l < sizeof(vers)) { 101 printf("[|gre]"); 102 return; 103 } 104 vers = EXTRACT_16BITS(p) & GRE_VERS; 105 106 switch (vers) { 107 case 0: 108 gre_print_0(p, length); 109 break; 110 case 1: 111 gre_print_1(p, length); 112 break; 113 default: 114 printf("gre-unknown-version=%u", vers); 115 break; 116 } 117 } 118 119 void 120 gre_print_0(const u_char *p, u_int length) 121 { 122 uint16_t flags, proto; 123 u_int l; 124 125 l = snapend - p; 126 127 flags = EXTRACT_16BITS(p); 128 p += sizeof(flags); 129 l -= sizeof(flags); 130 length -= sizeof(flags); 131 132 printf("gre"); 133 134 if (vflag) { 135 printf(" [%s%s%s%s%s]", 136 (flags & GRE_CP) ? "C" : "", 137 (flags & GRE_RP) ? "R" : "", 138 (flags & GRE_KP) ? "K" : "", 139 (flags & GRE_SP) ? "S" : "", 140 (flags & GRE_sP) ? "s" : ""); 141 } 142 143 if (l < sizeof(proto)) 144 goto trunc; 145 proto = EXTRACT_16BITS(p); 146 p += sizeof(proto); 147 l -= sizeof(proto); 148 length -= sizeof(proto); 149 150 if (vflag) 151 printf(" %04x", proto); 152 153 if ((flags & GRE_CP) | (flags & GRE_RP)) { 154 if (l < 2) 155 goto trunc; 156 if ((flags & GRE_CP) && vflag) 157 printf(" sum 0x%x", EXTRACT_16BITS(p)); 158 p += 2; 159 l -= 2; 160 length -= 2; 161 162 if (l < 2) 163 goto trunc; 164 if (flags & GRE_RP) 165 printf(" off 0x%x", EXTRACT_16BITS(p)); 166 p += 2; 167 l -= 2; 168 length -= 2; 169 } 170 171 if (flags & GRE_KP) { 172 uint32_t key, vsid; 173 174 if (l < sizeof(key)) 175 goto trunc; 176 key = EXTRACT_32BITS(p); 177 p += sizeof(key); 178 l -= sizeof(key); 179 length -= sizeof(key); 180 181 /* maybe NVGRE, or key entropy? */ 182 vsid = (key & NVGRE_VSID_MASK) >> NVGRE_VSID_SHIFT; 183 printf(" key=%u|%u+%02x", key, vsid, 184 (key & NVGRE_FLOWID_MASK) >> NVGRE_FLOWID_SHIFT); 185 } 186 187 if (flags & GRE_SP) { 188 if (l < 4) 189 goto trunc; 190 printf(" seq %u", EXTRACT_32BITS(p)); 191 p += 4; 192 l -= 4; 193 length -= 4; 194 } 195 196 if (flags & GRE_RP) { 197 for (;;) { 198 u_int16_t af; 199 u_int8_t sreoff; 200 u_int8_t srelen; 201 202 if (l < 4) 203 goto trunc; 204 af = EXTRACT_16BITS(p); 205 sreoff = *(p + 2); 206 srelen = *(p + 3); 207 p += 4; 208 l -= 4; 209 length -= 4; 210 211 if (af == 0 && srelen == 0) 212 break; 213 214 gre_sre_print(af, sreoff, srelen, p, l); 215 216 if (l < srelen) 217 goto trunc; 218 p += srelen; 219 l -= srelen; 220 length -= srelen; 221 } 222 } 223 224 printf(" "); 225 226 switch (proto) { 227 case 0: 228 printf("keep-alive"); 229 break; 230 case GRE_WCCP: { 231 printf("wccp "); 232 233 if (l == 0) 234 return; 235 236 if (*p >> 4 != 4) { 237 struct wccp_redirect *wccp; 238 239 if (l < sizeof(*wccp)) { 240 printf("[|wccp]"); 241 return; 242 } 243 244 wccp = (struct wccp_redirect *)p; 245 246 printf("D:%c A:%c SId:%u Alt:%u Pri:%u", 247 (wccp->flags & WCCP_D) ? '1' : '0', 248 (wccp->flags & WCCP_A) ? '1' : '0', 249 wccp->ServiceId, wccp->AltBucket, wccp->PriBucket); 250 251 p += sizeof(*wccp); 252 l -= sizeof(*wccp); 253 254 printf(": "); 255 } 256 257 /* FALLTHROUGH */ 258 } 259 case ETHERTYPE_IP: 260 ip_print(p, length); 261 break; 262 case ETHERTYPE_IPV6: 263 ip6_print(p, length); 264 break; 265 case ETHERTYPE_MPLS: 266 case ETHERTYPE_MPLS_MCAST: 267 mpls_print(p, length); 268 break; 269 case ETHERTYPE_TRANSETHER: 270 ether_tryprint(p, length, 0); 271 break; 272 case ERSPAN_II: 273 gre_print_erspan(flags, p, length); 274 break; 275 case 0x2000: 276 cdp_print(p, length, l, 0); 277 break; 278 default: 279 printf("unknown-proto-%04x", proto); 280 } 281 return; 282 283 trunc: 284 printf("[|gre]"); 285 } 286 287 void 288 gre_print_1(const u_char *p, u_int length) 289 { 290 uint16_t flags, proto; 291 int l; 292 293 l = snapend - p; 294 295 flags = EXTRACT_16BITS(p); 296 p += sizeof(flags); 297 l -= sizeof(flags); 298 length -= sizeof(flags); 299 300 if (l < sizeof(proto)) 301 goto trunc; 302 303 proto = EXTRACT_16BITS(p); 304 p += sizeof(proto); 305 l -= sizeof(proto); 306 length -= sizeof(proto); 307 308 switch (proto) { 309 case ETHERTYPE_PPP: 310 gre_print_pptp(p, length, flags); 311 break; 312 case 0x6400: 313 /* MikroTik RouterBoard Ethernet over IP (EoIP) */ 314 gre_print_eoip(p, length, flags); 315 break; 316 default: 317 printf("unknown-gre1-proto-%04x", proto); 318 break; 319 } 320 321 return; 322 323 trunc: 324 printf("[|gre1]"); 325 } 326 327 void 328 gre_print_pptp(const u_char *p, u_int length, uint16_t flags) 329 { 330 uint16_t len; 331 int l; 332 333 l = snapend - p; 334 335 printf("pptp"); 336 337 if (vflag) { 338 printf(" [%s%s%s%s%s%s]", 339 (flags & GRE_CP) ? "C" : "", 340 (flags & GRE_RP) ? "R" : "", 341 (flags & GRE_KP) ? "K" : "", 342 (flags & GRE_SP) ? "S" : "", 343 (flags & GRE_sP) ? "s" : "", 344 (flags & GRE_AP) ? "A" : ""); 345 } 346 347 if (flags & GRE_CP) { 348 printf(" cpset!"); 349 return; 350 } 351 if (flags & GRE_RP) { 352 printf(" rpset!"); 353 return; 354 } 355 if ((flags & GRE_KP) == 0) { 356 printf(" kpunset!"); 357 return; 358 } 359 if (flags & GRE_sP) { 360 printf(" spset!"); 361 return; 362 } 363 364 /* GRE_KP */ 365 if (l < sizeof(len)) 366 goto trunc; 367 len = EXTRACT_16BITS(p); 368 p += sizeof(len); 369 l -= sizeof(len); 370 length -= sizeof(len); 371 372 if (vflag) 373 printf(" len %u", EXTRACT_16BITS(p)); 374 375 if (l < 2) 376 goto trunc; 377 printf(" callid %u", EXTRACT_16BITS(p)); 378 p += 2; 379 l -= 2; 380 length -= 2; 381 382 if (flags & GRE_SP) { 383 if (l < 4) 384 goto trunc; 385 printf(" seq %u", EXTRACT_32BITS(p)); 386 p += 4; 387 l -= 4; 388 length -= 4; 389 } 390 391 if (flags & GRE_AP) { 392 if (l < 4) 393 goto trunc; 394 printf(" ack %u", EXTRACT_32BITS(p)); 395 p += 4; 396 l -= 4; 397 length -= 4; 398 } 399 400 if ((flags & GRE_SP) == 0) 401 return; 402 403 if (length < len) { 404 (void)printf(" truncated-pptp - %d bytes missing!", 405 len - length); 406 len = length; 407 } 408 409 printf(": "); 410 411 ppp_hdlc_print(p, len); 412 return; 413 414 trunc: 415 printf("[|pptp]"); 416 } 417 418 void 419 gre_print_eoip(const u_char *p, u_int length, uint16_t flags) 420 { 421 uint16_t len, id; 422 int l; 423 424 l = snapend - p; 425 426 printf("eoip"); 427 428 flags &= ~GRE_VERS; 429 if (flags != GRE_KP) { 430 printf(" unknown-eoip-flags-%04x!", flags); 431 return; 432 } 433 434 if (l < sizeof(len)) 435 goto trunc; 436 437 len = EXTRACT_16BITS(p); 438 p += sizeof(len); 439 l -= sizeof(len); 440 length -= sizeof(len); 441 442 if (l < sizeof(id)) 443 goto trunc; 444 445 id = EXTRACT_LE_16BITS(p); 446 p += sizeof(id); 447 l -= sizeof(id); 448 length -= sizeof(id); 449 450 if (vflag) 451 printf(" len=%u tunnel-id=%u", len, id); 452 else 453 printf(" %u", id); 454 455 if (length < len) { 456 (void)printf(" truncated-eoip - %d bytes missing!", 457 len - length); 458 len = length; 459 } 460 461 printf(": "); 462 463 if (len == 0) 464 printf("keepalive"); 465 else 466 ether_tryprint(p, len, 0); 467 468 return; 469 470 trunc: 471 printf("[|eoip]"); 472 } 473 474 #define ERSPAN2_VER_SHIFT 28 475 #define ERSPAN2_VER_MASK (0xfU << ERSPAN2_VER_SHIFT) 476 #define ERSPAN2_VER (0x1U << ERSPAN2_VER_SHIFT) 477 #define ERSPAN2_VLAN_SHIFT 16 478 #define ERSPAN2_VLAN_MASK (0xfffU << ERSPAN2_VLAN_SHIFT) 479 #define ERSPAN2_COS_SHIFT 13 480 #define ERSPAN2_COS_MASK (0x7U << ERSPAN2_COS_SHIFT) 481 #define ERSPAN2_EN_SHIFT 11 482 #define ERSPAN2_EN_MASK (0x3U << ERSPAN2_EN_SHIFT) 483 #define ERSPAN2_EN_NONE (0x0U << ERSPAN2_EN_SHIFT) 484 #define ERSPAN2_EN_ISL (0x1U << ERSPAN2_EN_SHIFT) 485 #define ERSPAN2_EN_DOT1Q (0x2U << ERSPAN2_EN_SHIFT) 486 #define ERSPAN2_EN_VLAN (0x3U << ERSPAN2_EN_SHIFT) 487 #define ERSPAN2_T_SHIFT 10 488 #define ERSPAN2_T_MASK (0x1U << ERSPAN2_T_SHIFT) 489 #define ERSPAN2_SID_SHIFT 0 490 #define ERSPAN2_SID_MASK (0x3ffU << ERSPAN2_SID_SHIFT) 491 492 #define ERSPAN2_INDEX_SHIFT 0 493 #define ERSPAN2_INDEX_MASK (0xfffffU << ERSPAN2_INDEX_SHIFT) 494 495 void 496 gre_print_erspan(uint16_t flags, const u_char *bp, u_int len) 497 { 498 uint32_t hdr, ver, vlan, cos, en, sid, index; 499 u_int l; 500 501 printf("erspan"); 502 503 if (!(flags & GRE_SP)) { 504 printf(" I: "); 505 ether_tryprint(bp, len, 0); 506 return; 507 } 508 509 l = snapend - bp; 510 if (l < sizeof(hdr)) 511 goto trunc; 512 513 hdr = EXTRACT_32BITS(bp); 514 bp += sizeof(hdr); 515 l -= sizeof(hdr); 516 len -= sizeof(hdr); 517 518 ver = hdr & ERSPAN2_VER_MASK; 519 if (ver != ERSPAN2_VER) { 520 ver >>= ERSPAN2_VER_SHIFT; 521 printf(" erspan-unknown-version-%x", ver); 522 return; 523 } 524 525 if (vflag) 526 printf(" II"); 527 528 sid = (hdr & ERSPAN2_SID_MASK) >> ERSPAN2_SID_SHIFT; 529 printf(" session %u", sid); 530 531 en = hdr & ERSPAN2_EN_MASK; 532 vlan = (hdr & ERSPAN2_VLAN_MASK) >> ERSPAN2_VLAN_SHIFT; 533 switch (en) { 534 case ERSPAN2_EN_NONE: 535 break; 536 case ERSPAN2_EN_ISL: 537 printf(" isl %u", vlan); 538 break; 539 case ERSPAN2_EN_DOT1Q: 540 printf(" vlan %u", vlan); 541 break; 542 case ERSPAN2_EN_VLAN: 543 printf(" vlan payload"); 544 break; 545 } 546 547 if (vflag) { 548 cos = (hdr & ERSPAN2_COS_MASK) >> ERSPAN2_COS_SHIFT; 549 printf(" cos %u", cos); 550 551 if (hdr & ERSPAN2_T_MASK) 552 printf(" truncated"); 553 } 554 555 if (l < sizeof(hdr)) 556 goto trunc; 557 558 hdr = EXTRACT_32BITS(bp); 559 bp += sizeof(hdr); 560 l -= sizeof(hdr); 561 len -= sizeof(hdr); 562 563 if (vflag) { 564 index = (hdr & ERSPAN2_INDEX_MASK) >> ERSPAN2_INDEX_SHIFT; 565 printf(" index %u", index); 566 } 567 568 printf(": "); 569 ether_tryprint(bp, len, 0); 570 return; 571 572 trunc: 573 printf(" [|erspan]"); 574 } 575 576 void 577 gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen, 578 const u_char *bp, u_int len) 579 { 580 switch (af) { 581 case GRESRE_IP: 582 printf(" (rtaf=ip"); 583 gre_sre_ip_print(sreoff, srelen, bp, len); 584 printf(")"); 585 break; 586 case GRESRE_ASN: 587 printf(" (rtaf=asn"); 588 gre_sre_asn_print(sreoff, srelen, bp, len); 589 printf(")"); 590 break; 591 default: 592 printf(" (rtaf=0x%x)", af); 593 } 594 } 595 void 596 gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len) 597 { 598 struct in_addr a; 599 const u_char *up = bp; 600 601 if (sreoff & 3) { 602 printf(" badoffset=%u", sreoff); 603 return; 604 } 605 if (srelen & 3) { 606 printf(" badlength=%u", srelen); 607 return; 608 } 609 if (sreoff >= srelen) { 610 printf(" badoff/len=%u/%u", sreoff, srelen); 611 return; 612 } 613 614 for (;;) { 615 if (len < 4 || srelen == 0) 616 return; 617 618 memcpy(&a, bp, sizeof(a)); 619 printf(" %s%s", 620 ((bp - up) == sreoff) ? "*" : "", 621 inet_ntoa(a)); 622 623 bp += 4; 624 len -= 4; 625 srelen -= 4; 626 } 627 } 628 629 void 630 gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len) 631 { 632 const u_char *up = bp; 633 634 if (sreoff & 1) { 635 printf(" badoffset=%u", sreoff); 636 return; 637 } 638 if (srelen & 1) { 639 printf(" badlength=%u", srelen); 640 return; 641 } 642 if (sreoff >= srelen) { 643 printf(" badoff/len=%u/%u", sreoff, srelen); 644 return; 645 } 646 647 for (;;) { 648 if (len < 2 || srelen == 0) 649 return; 650 651 printf(" %s%x", 652 ((bp - up) == sreoff) ? "*" : "", 653 EXTRACT_16BITS(bp)); 654 655 bp += 2; 656 len -= 2; 657 srelen -= 2; 658 } 659 } 660 661 struct vxlan_header { 662 uint16_t flags; 663 #define VXLAN_I 0x0800 664 uint16_t proto; 665 uint32_t vni; 666 #define VXLAN_VNI_SHIFT 8 667 #define VXLAN_VNI_MASK (0xffffffU << VXLAN_VNI_SHIFT) 668 #define VXLAN_VNI_RESERVED (~VXLAN_VNI_MASK) 669 }; 670 671 void 672 vxlan_print(const u_char *p, u_int length) 673 { 674 const struct vxlan_header *vh; 675 uint16_t flags, proto; 676 uint32_t vni; 677 size_t l; 678 679 l = snapend - p; 680 if (l < sizeof(*vh)) { 681 printf("[|vxlan]"); 682 return; 683 } 684 vh = (const struct vxlan_header *)p; 685 686 flags = ntohs(vh->flags); 687 if (flags & ~VXLAN_I) { 688 printf("vxlan-invalid-flags %04x", flags); 689 return; 690 } 691 692 proto = ntohs(vh->proto); 693 if (proto != 0) { 694 printf("vxlan-invalid-proto %04x", proto); 695 return; 696 } 697 698 vni = ntohl(vh->vni); 699 if (flags & VXLAN_I) { 700 if (vni & VXLAN_VNI_RESERVED) { 701 printf("vxlan-vni-reserved %02x", 702 vni & VXLAN_VNI_RESERVED); 703 return; 704 } 705 706 printf("vxlan %u: ", vni >> VXLAN_VNI_SHIFT); 707 } else { 708 if (vh->vni != 0) { 709 printf("vxlan-invalid-vni %08x\n", vni); 710 return; 711 } 712 713 printf("vxlan: "); 714 } 715 716 p += sizeof(*vh); 717 length -= sizeof(*vh); 718 719 ether_tryprint(p, length, 0); 720 } 721