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