1 /* $OpenBSD: print-gre.c,v 1.25 2019/04/05 00:59:24 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_erspan2(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_erspan2(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_erspan2(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 l = snapend - bp; 504 if (l < sizeof(hdr)) 505 goto trunc; 506 507 hdr = EXTRACT_32BITS(bp); 508 bp += sizeof(hdr); 509 l -= sizeof(hdr); 510 len -= sizeof(hdr); 511 512 ver = hdr & ERSPAN2_VER_MASK; 513 if (ver != ERSPAN2_VER) { 514 ver >>= ERSPAN2_VER_SHIFT; 515 printf(" erspan-unknown-version-%x", ver); 516 return; 517 } 518 519 if (vflag) 520 printf(" II"); 521 522 sid = (hdr & ERSPAN2_SID_MASK) >> ERSPAN2_SID_SHIFT; 523 printf(" session %u", sid); 524 525 en = hdr & ERSPAN2_EN_MASK; 526 vlan = (hdr & ERSPAN2_VLAN_MASK) >> ERSPAN2_VLAN_SHIFT; 527 switch (en) { 528 case ERSPAN2_EN_NONE: 529 break; 530 case ERSPAN2_EN_ISL: 531 printf(" isl %u", vlan); 532 break; 533 case ERSPAN2_EN_DOT1Q: 534 printf(" vlan %u", vlan); 535 break; 536 case ERSPAN2_EN_VLAN: 537 printf(" vlan payload"); 538 break; 539 } 540 541 if (vflag) { 542 cos = (hdr & ERSPAN2_COS_MASK) >> ERSPAN2_COS_SHIFT; 543 printf(" cos %u", cos); 544 545 if (hdr & ERSPAN2_T_MASK) 546 printf(" truncated"); 547 } 548 549 if (l < sizeof(hdr)) 550 goto trunc; 551 552 hdr = EXTRACT_32BITS(bp); 553 bp += sizeof(hdr); 554 l -= sizeof(hdr); 555 len -= sizeof(hdr); 556 557 if (vflag) { 558 index = (hdr & ERSPAN2_INDEX_MASK) >> ERSPAN2_INDEX_SHIFT; 559 printf(" index %u", index); 560 } 561 562 printf(": "); 563 ether_tryprint(bp, len, 0); 564 return; 565 566 trunc: 567 printf(" [|erspan]"); 568 } 569 570 void 571 gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen, 572 const u_char *bp, u_int len) 573 { 574 switch (af) { 575 case GRESRE_IP: 576 printf(" (rtaf=ip"); 577 gre_sre_ip_print(sreoff, srelen, bp, len); 578 printf(")"); 579 break; 580 case GRESRE_ASN: 581 printf(" (rtaf=asn"); 582 gre_sre_asn_print(sreoff, srelen, bp, len); 583 printf(")"); 584 break; 585 default: 586 printf(" (rtaf=0x%x)", af); 587 } 588 } 589 void 590 gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len) 591 { 592 struct in_addr a; 593 const u_char *up = bp; 594 595 if (sreoff & 3) { 596 printf(" badoffset=%u", sreoff); 597 return; 598 } 599 if (srelen & 3) { 600 printf(" badlength=%u", srelen); 601 return; 602 } 603 if (sreoff >= srelen) { 604 printf(" badoff/len=%u/%u", sreoff, srelen); 605 return; 606 } 607 608 for (;;) { 609 if (len < 4 || srelen == 0) 610 return; 611 612 memcpy(&a, bp, sizeof(a)); 613 printf(" %s%s", 614 ((bp - up) == sreoff) ? "*" : "", 615 inet_ntoa(a)); 616 617 bp += 4; 618 len -= 4; 619 srelen -= 4; 620 } 621 } 622 623 void 624 gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len) 625 { 626 const u_char *up = bp; 627 628 if (sreoff & 1) { 629 printf(" badoffset=%u", sreoff); 630 return; 631 } 632 if (srelen & 1) { 633 printf(" badlength=%u", srelen); 634 return; 635 } 636 if (sreoff >= srelen) { 637 printf(" badoff/len=%u/%u", sreoff, srelen); 638 return; 639 } 640 641 for (;;) { 642 if (len < 2 || srelen == 0) 643 return; 644 645 printf(" %s%x", 646 ((bp - up) == sreoff) ? "*" : "", 647 EXTRACT_16BITS(bp)); 648 649 bp += 2; 650 len -= 2; 651 srelen -= 2; 652 } 653 } 654 655 struct vxlan_header { 656 uint16_t flags; 657 #define VXLAN_I 0x0800 658 uint16_t proto; 659 uint32_t vni; 660 #define VXLAN_VNI_SHIFT 8 661 #define VXLAN_VNI_MASK (0xffffffU << VXLAN_VNI_SHIFT) 662 #define VXLAN_VNI_RESERVED (~VXLAN_VNI_MASK) 663 }; 664 665 void 666 vxlan_print(const u_char *p, u_int length) 667 { 668 const struct vxlan_header *vh; 669 uint16_t flags, proto; 670 uint32_t vni; 671 size_t l; 672 673 l = snapend - p; 674 if (l < sizeof(*vh)) { 675 printf("[|vxlan]"); 676 return; 677 } 678 vh = (const struct vxlan_header *)p; 679 680 flags = ntohs(vh->flags); 681 if (flags & ~VXLAN_I) { 682 printf("vxlan-invalid-flags %04x", flags); 683 return; 684 } 685 686 proto = ntohs(vh->proto); 687 if (proto != 0) { 688 printf("vxlan-invalid-proto %04x", proto); 689 return; 690 } 691 692 vni = ntohl(vh->vni); 693 if (flags & VXLAN_I) { 694 if (vni & VXLAN_VNI_RESERVED) { 695 printf("vxlan-vni-reserved %02x", 696 vni & VXLAN_VNI_RESERVED); 697 return; 698 } 699 700 printf("vxlan %u: ", vni >> VXLAN_VNI_SHIFT); 701 } else { 702 if (vh->vni != 0) { 703 printf("vxlan-invalid-vni %08x\n", vni); 704 return; 705 } 706 707 printf("vxlan: "); 708 } 709 710 p += sizeof(*vh); 711 length -= sizeof(*vh); 712 713 ether_tryprint(p, length, 0); 714 } 715