1 /* $NetBSD: uipc_mbufdebug.c,v 1.8 2024/12/06 18:36:31 riastradh Exp $ */ 2 3 /* 4 * Copyright (C) 2017 Internet Initiative Japan Inc. 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: uipc_mbufdebug.c,v 1.8 2024/12/06 18:36:31 riastradh Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/types.h> 34 35 #include <sys/malloc.h> 36 #include <sys/mbuf.h> 37 #include <sys/proc.h> 38 #include <sys/systm.h> 39 40 #include <net/if.h> 41 #include <net/if_arp.h> 42 #include <net/if_ether.h> 43 #include <net/ppp_defs.h> 44 45 #include <netinet/icmp6.h> 46 #include <netinet/if_inarp.h> 47 #include <netinet/in.h> 48 #include <netinet/in_systm.h> 49 #include <netinet/ip.h> 50 #include <netinet/ip6.h> 51 #include <netinet/ip_icmp.h> 52 #include <netinet/tcp.h> 53 #include <netinet/udp.h> 54 55 #define EXAMINE_HEX_LIMIT 128 56 #define EXAMINE_HEX_COL 4 57 58 /* mbuf operations without change of mbuf chain */ 59 static int m_peek_data(const struct mbuf *, int, int, void *); 60 static unsigned int m_peek_len(const struct mbuf *, const char *); 61 62 /* utility */ 63 static char *str_ethaddr(const uint8_t *); 64 static char *str_ipaddr(const struct in_addr *); 65 static char *str_ip6addr(const struct in6_addr *); 66 static const char *str_ipproto(const uint8_t); 67 68 /* header structure for some protocol */ 69 struct pppoehdr { 70 uint8_t vertype; 71 uint8_t code; 72 uint16_t session; 73 uint16_t plen; 74 } __attribute__((__packed__)); 75 76 struct pppoetag { 77 uint16_t tag; 78 uint16_t len; 79 } __attribute__((__packed__)); 80 81 #define PPPOE_TAG_EOL 0x0000 82 #define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ 83 #define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ 84 #define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ 85 #define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */ 86 #define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */ 87 88 struct ppp_header { 89 uint8_t address; 90 uint8_t control; 91 uint16_t protocol; 92 } __attribute__((__packed__)); 93 94 #define CISCO_MULTICAST 0x8f /* Cisco multicast address */ 95 #define CISCO_UNICAST 0x0f /* Cisco unicast address */ 96 #define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ 97 98 #ifndef NELEMS 99 #define NELEMS(elem) ((sizeof(elem))/(sizeof((elem)[0]))) 100 #endif 101 102 static int 103 m_peek_data(const struct mbuf *m, int off, int len, void *vp) 104 { 105 unsigned int count; 106 char *cp = vp; 107 108 if (off < 0 || len < 0) 109 return -1; 110 111 while (off > 0) { 112 if (m == 0) 113 return -1; 114 if (off < m->m_len) 115 break; 116 off -= m->m_len; 117 m = m->m_next; 118 } 119 while (len > 0) { 120 if (m == 0) 121 return -1; 122 count = uimin(m->m_len - off, len); 123 memcpy(cp, mtod(m, char *) + off, count); 124 len -= count; 125 cp += count; 126 off = 0; 127 m = m->m_next; 128 } 129 130 return 0; 131 } 132 133 static unsigned int 134 m_peek_len(const struct mbuf *m, const char *modif) 135 { 136 const struct mbuf *m0; 137 unsigned int pktlen; 138 bool opt_c = false; 139 unsigned char ch; 140 141 while (modif && (ch = *(modif++)) != '\0') { 142 switch (ch) { 143 case 'c': 144 opt_c = true; 145 break; 146 } 147 } 148 149 if (opt_c == true) 150 return m->m_len; 151 152 if ((m->m_flags & M_PKTHDR) != 0) 153 return m->m_pkthdr.len; 154 155 pktlen = 0; 156 for (m0 = m; m0 != NULL; m0 = m0->m_next) 157 pktlen += m0->m_len; 158 159 return pktlen; 160 } 161 162 static char * 163 str_ethaddr(const uint8_t *ap) 164 { 165 static char buf[3 * ETHER_ADDR_LEN]; 166 167 return ether_snprintf(buf, sizeof(buf), ap); 168 } 169 170 static char * 171 str_ipaddr(const struct in_addr *ap) 172 { 173 static char buf[INET_ADDRSTRLEN]; 174 175 return IN_PRINT(buf, ap); 176 } 177 178 static char * 179 str_ip6addr(const struct in6_addr *ap) 180 { 181 static char buf[INET6_ADDRSTRLEN]; 182 183 return IN6_PRINT(buf, ap); 184 } 185 186 static const char * 187 str_ipproto(const uint8_t proto) 188 { 189 190 switch (proto) { 191 case IPPROTO_HOPOPTS: 192 return ("IPv6 Hop-by-Hop"); 193 break; 194 case IPPROTO_TCP: 195 return("TCP"); 196 break; 197 case IPPROTO_UDP: 198 return("UDP"); 199 break; 200 case IPPROTO_ICMP: 201 return("ICMP"); 202 break; 203 case IPPROTO_IGMP: 204 return("IGMP"); 205 break; 206 case IPPROTO_ESP: 207 return("ESP"); 208 break; 209 case IPPROTO_AH: 210 return("AH"); 211 break; 212 case IPPROTO_IPV6_ICMP: 213 return("ICMP6"); 214 default: 215 return("unknown"); 216 break; 217 } 218 219 /* not reached */ 220 return NULL; 221 } 222 223 void 224 m_examine_ether(const struct mbuf *m, int off, const char *modif, 225 void (*pr)(const char *, ...)) 226 { 227 struct ether_header eh; 228 unsigned int pktlen; 229 230 pktlen = m_peek_len(m, modif) - off; 231 if (pktlen < sizeof(eh)) { 232 (*pr)("%s: too short mbuf chain (%u < %u)\n", __func__, 233 pktlen, sizeof(eh)); 234 return m_examine_hex(m, off, modif, pr); 235 } 236 237 if (m_peek_data(m, off, sizeof(eh), (void *)(&eh)) < 0) { 238 (*pr)("%s: cannot read header\n", __func__); 239 return m_examine_hex(m, off, modif, pr); 240 } 241 off += sizeof(eh); 242 243 (*pr)("ETHER: DST = %s\n", str_ethaddr(eh.ether_dhost)); 244 (*pr)("ETHER: SRC = %s\n", str_ethaddr(eh.ether_shost)); 245 246 (*pr)("ETHER: TYPE = 0x%04x(", ntohs(eh.ether_type)); 247 switch (ntohs(eh.ether_type)) { 248 case ETHERTYPE_PPPOE: 249 (*pr)("PPPoE)\n"); 250 return m_examine_pppoe(m, off, modif, pr); 251 break; 252 case ETHERTYPE_ARP: 253 (*pr)("ARP)\n"); 254 return m_examine_arp(m, off, modif, pr); 255 break; 256 case ETHERTYPE_IP: 257 (*pr)("IPv4)\n"); 258 return m_examine_ip(m, off, modif, pr); 259 break; 260 case ETHERTYPE_IPV6: 261 (*pr)("IPv6)\n"); 262 return m_examine_ip6(m, off, modif, pr); 263 break; 264 default: 265 (*pr)("unknown)\n"); 266 break; 267 } 268 269 return m_examine_hex(m, off, modif, pr); 270 } 271 272 void 273 m_examine_pppoe(const struct mbuf *m, int off, const char *modif, 274 void (*pr)(const char *, ...)) 275 { 276 struct pppoehdr ph; 277 struct pppoetag pt; 278 unsigned int pktlen; 279 uint8_t vt; 280 281 pktlen = m_peek_len(m, modif) - off; 282 if (pktlen < sizeof(ph)) { 283 (*pr)("%s: too short mbuf chain (%u, %u)\n", __func__, 284 pktlen, sizeof(ph)); 285 return m_examine_hex(m, off, modif, pr); 286 } 287 288 if (m_peek_data(m, off, sizeof(ph), (void *)(&ph)) < 0) { 289 (*pr)("%s: cannot read header\n", __func__); 290 return m_examine_hex(m, off, modif, pr); 291 } 292 off += sizeof(ph); 293 294 while (off + sizeof(pt) > pktlen) { 295 if (m_peek_data(m, off, sizeof(pt), (void *)(&pt)) < 0) { 296 (*pr)("%s: cannot read header\n", __func__); 297 return m_examine_hex(m, off, modif, pr); 298 } 299 off += sizeof(pt); 300 301 if (ntohs(pt.tag) == PPPOE_TAG_EOL) 302 break; 303 off += ntohs(pt.len); 304 } 305 306 vt = ph.vertype; 307 308 (*pr)("PPPoE: Version = %u\n", ((vt >> 4) & 0xff)); 309 (*pr)("PPPoE: Type = %u\n", (vt & 0xff)); 310 (*pr)("PPPoE: Code = %u(", ph.code); 311 switch (ph.code) { 312 case 0: 313 (*pr)("DATA"); 314 break; 315 case PPPOE_CODE_PADI: 316 (*pr)("PADI"); 317 break; 318 case PPPOE_CODE_PADO: 319 (*pr)("PADO"); 320 break; 321 case PPPOE_CODE_PADS: 322 (*pr)("PADS"); 323 break; 324 case PPPOE_CODE_PADT: 325 (*pr)("PADT"); 326 break; 327 default: 328 (*pr)("unknown"); 329 break; 330 } 331 (*pr)(")\n"); 332 333 (*pr)("PPPoE: Session = 0x%04x\n", ntohs(ph.session)); 334 (*pr)("PPPoE: Payload Length = %u\n", ntohs(ph.plen)); 335 336 switch (ph.code) { 337 case PPPOE_CODE_PADI: 338 case PPPOE_CODE_PADO: 339 case PPPOE_CODE_PADS: 340 case PPPOE_CODE_PADT: 341 (*pr)("No parser for PPPoE control frame.\n"); 342 return m_examine_hex(m, off, modif, pr); 343 break; 344 } 345 346 if (ph.code != 0) { 347 (*pr)("Unknown PPPoE code.\n"); 348 return m_examine_hex(m, off, modif, pr); 349 } 350 351 return m_examine_ppp(m, off, modif, pr); 352 } 353 354 void 355 m_examine_ppp(const struct mbuf *m, int off, const char *modif, 356 void (*pr)(const char *, ...)) 357 { 358 struct ppp_header h; 359 unsigned int pktlen; 360 uint16_t protocol; 361 362 pktlen = m_peek_len(m, modif) - off; 363 if (pktlen < sizeof(h)) { 364 (*pr)("%s: too short mbuf chain (%u < %u)\n", __func__, 365 pktlen, sizeof(h)); 366 return m_examine_hex(m, off, modif, pr); 367 } 368 369 if (m_peek_data(m, off, sizeof(h), (void *)(&h)) < 0) { 370 (*pr)("%s: cannot read header\n", __func__); 371 return m_examine_hex(m, off, modif, pr); 372 } 373 off += sizeof(h); 374 375 protocol = ntohs(h.protocol); 376 377 (*pr)("SPPP: Address = %d(", h.address); 378 switch (h.address) { 379 case PPP_ALLSTATIONS: 380 (*pr)("ALLSTATIONS)\n"); 381 (*pr)("SPPP: Protocol = %d(", protocol); 382 switch (protocol) { 383 case PPP_LCP: 384 (*pr)("LCP)\n"); 385 break; 386 case PPP_PAP: 387 (*pr)("PAP)\n"); 388 break; 389 case PPP_CHAP: 390 (*pr)("CHAP)\n"); 391 break; 392 case PPP_IPCP: 393 (*pr)("IPCP)\n"); 394 break; 395 case PPP_IPV6CP: 396 (*pr)("IPV6CP)\n"); 397 break; 398 case PPP_IP: 399 (*pr)("IP)\n"); 400 return m_examine_ip(m, off, modif, pr); 401 break; 402 case PPP_IPV6: 403 (*pr)("IPv6)\n"); 404 return m_examine_ip6(m, off, modif, pr); 405 break; 406 default: 407 (*pr)("unknown)\n"); 408 break; 409 } 410 break; 411 case CISCO_MULTICAST: 412 case CISCO_UNICAST: 413 if (h.address == CISCO_MULTICAST) 414 (*pr)("MULTICAST)\n"); 415 else 416 (*pr)("UNICAST)\n"); 417 418 (*pr)("SPPP: Protocol = %d(", protocol); 419 switch (protocol) { 420 case CISCO_KEEPALIVE: 421 (*pr)("Keepalive)\n"); 422 break; 423 case ETHERTYPE_IP: 424 (*pr)("IP)\n"); 425 return m_examine_ip(m, off, modif, pr); 426 break; 427 case ETHERTYPE_IPV6: 428 (*pr)("IPv6)\n"); 429 return m_examine_ip6(m, off, modif, pr); 430 break; 431 default: 432 (*pr)("unknown)\n"); 433 break; 434 } 435 break; 436 default: 437 (*pr)("unknown)\n", h.address); 438 break; 439 } 440 441 (*pr)("No parser for address %d, protocol %d\n", h.address, protocol); 442 return m_examine_hex(m, off, modif, pr); 443 } 444 445 void 446 m_examine_arp(const struct mbuf *m, int off, const char *modif, 447 void (*pr)(const char *, ...)) 448 { 449 unsigned int pktlen; 450 struct arphdr ar; 451 uint16_t hrd, op; 452 struct in_addr isaddr, itaddr; 453 uint8_t esaddr[ETHER_ADDR_LEN], etaddr[ETHER_ADDR_LEN]; 454 455 pktlen = m_peek_len(m, modif) - off; 456 if (pktlen < sizeof(ar)) { 457 (*pr)("%s: too short mbuf chain (%u < %u)\n", __func__, 458 pktlen, sizeof(ar)); 459 return m_examine_hex(m, off, modif, pr); 460 } 461 462 if (m_peek_data(m, off, sizeof(ar), (void *)(&ar)) < 0) { 463 (*pr)("%s: cannot read header\n", __func__); 464 return m_examine_hex(m, off, modif, pr); 465 } 466 off += sizeof(ar); 467 468 hrd = ntohs(ar.ar_hrd); 469 (*pr)("ARP: AddressType = %u(", hrd); 470 switch (hrd) { 471 case ARPHRD_ETHER: 472 (*pr)("ETHER)\n"); 473 break; 474 case ARPHRD_IEEE802: 475 (*pr)("IEEE802)\n"); 476 break; 477 default: 478 (*pr)("unknown)\n"); 479 return m_examine_hex(m, off, modif, pr); 480 break; 481 } 482 (*pr)("ARP: Protocol Address Format = %u\n", ntohs(ar.ar_pro)); 483 (*pr)("ARP: Protocol Address Length = %u\n", ar.ar_pln); 484 (*pr)("ARP: H/W Address Length = %u\n", ar.ar_hln); 485 op = ntohs(ar.ar_op); 486 (*pr)("ARP: Operation = %u(", op); 487 switch (op) { 488 case ARPOP_REQUEST: 489 (*pr)("REQUEST)\n"); 490 break; 491 case ARPOP_REPLY: 492 (*pr)("REPLY)\n"); 493 break; 494 case ARPOP_REVREQUEST: 495 (*pr)("REVREQUEST)\n"); 496 break; 497 case ARPOP_REVREPLY: 498 (*pr)("REVREPLY)\n"); 499 break; 500 case ARPOP_INVREQUEST: 501 (*pr)("INVREQUEST)\n"); 502 break; 503 case ARPOP_INVREPLY: 504 (*pr)("INVREPLY)\n"); 505 break; 506 } 507 508 if (ar.ar_hln == 0 || ar.ar_pln == 0 || 509 ar.ar_hln != sizeof(esaddr) || ar.ar_pln != sizeof(isaddr)) { 510 (*pr)("Cannot parse.\n"); 511 return m_examine_hex(m, off, modif, pr); 512 } 513 514 if (m_peek_data(m, off, sizeof(esaddr), (void *)(esaddr)) < 0) { 515 (*pr)("Cannot read payload\n"); 516 return m_examine_hex(m, off, modif, pr); 517 } 518 off += sizeof(esaddr); 519 (*pr)("ARP: Ether Src = %s\n", str_ethaddr(esaddr)); 520 521 if (m_peek_data(m, off, sizeof(isaddr), (void *)(&isaddr)) < 0) { 522 (*pr)("Cannot read payload\n"); 523 return m_examine_hex(m, off, modif, pr); 524 } 525 off += sizeof(isaddr); 526 (*pr)("ARP: IP Src = %s\n", str_ipaddr(&isaddr)); 527 528 if (m_peek_data(m, off, sizeof(etaddr), (void *)(etaddr)) < 0) { 529 (*pr)("Cannot read payload\n"); 530 return m_examine_hex(m, off, modif, pr); 531 } 532 off += sizeof(etaddr); 533 (*pr)("ARP: Ether Tgt = %s\n", str_ethaddr(etaddr)); 534 535 if (m_peek_data(m, off, sizeof(itaddr), (void *)(&itaddr)) < 0) { 536 (*pr)("Cannot read payload\n"); 537 return m_examine_hex(m, off, modif, pr); 538 } 539 off += sizeof(itaddr); 540 (*pr)("ARP: IP Tgt = %s\n", str_ipaddr(&itaddr)); 541 542 return m_examine_hex(m, off, modif, pr); 543 } 544 545 void 546 m_examine_ip(const struct mbuf *m, int off, const char *modif, 547 void (*pr)(const char *, ...)) 548 { 549 unsigned int pktlen; 550 struct ip ip; 551 uint16_t offset; 552 553 pktlen = m_peek_len(m, modif) - off; 554 if (pktlen < sizeof(ip)) { 555 (*pr)("%s: too short mbuf chain (%u < %u)\n", __func__, 556 pktlen, sizeof(ip)); 557 return m_examine_hex(m, off, modif, pr); 558 } 559 560 if (m_peek_data(m, off, sizeof(ip), (void *)(&ip)) < 0) { 561 (*pr)("%s: cannot read header\n", __func__); 562 return m_examine_hex(m, off, modif, pr); 563 } 564 off += sizeof(ip); 565 566 (*pr)("IP: Version = %u\n", ip.ip_v); 567 (*pr)("IP: Header Length = %u\n", (ip.ip_hl << 2)); 568 (*pr)("IP: ToS = 0x%02x\n", ip.ip_tos); 569 (*pr)("IP: Packet Length = %u\n", ntohs(ip.ip_len)); 570 (*pr)("IP: ID = %u\n", ntohs(ip.ip_id)); 571 offset = ntohs(ip.ip_off); 572 (*pr)("IP: Offset = %u\n", (offset & IP_OFFMASK)); 573 if (offset & IP_RF) 574 (*pr)("IP: Flag 0x%04x (reserved)\n", IP_RF); 575 if (offset & IP_EF) 576 (*pr)("IP: Flag 0x%04x (evil flag)\n", IP_EF); 577 if (offset & IP_DF) 578 (*pr)("IP: Flag 0x%04x (don't fragment)\n", IP_DF); 579 if (offset & IP_MF) 580 (*pr)("IP: Flag 0x%04x (more fragment)\n", IP_MF); 581 (*pr)("IP: TTL = %u\n", ip.ip_ttl); 582 (*pr)("IP: protocol = %u(%s)\n", ip.ip_p, str_ipproto(ip.ip_p)); 583 (*pr)("IP: checksum = 0x%04x\n", ntohs(ip.ip_sum)); 584 (*pr)("IP: Src = %s\n", str_ipaddr(&ip.ip_src)); 585 (*pr)("IP: Dst = %s\n", str_ipaddr(&ip.ip_dst)); 586 587 switch (ip.ip_p) { 588 case IPPROTO_ICMP: 589 return m_examine_icmp(m, off, modif, pr); 590 break; 591 case IPPROTO_TCP: 592 return m_examine_tcp(m, off, modif, pr); 593 break; 594 case IPPROTO_UDP: 595 return m_examine_udp(m, off, modif, pr); 596 break; 597 default: 598 break; 599 } 600 601 return m_examine_hex(m, off, modif, pr); 602 } 603 604 void 605 m_examine_icmp(const struct mbuf *m, int off, const char *modif, 606 void (*pr)(const char *, ...)) 607 { 608 unsigned int pktlen; 609 struct icmp icmphdr; 610 611 pktlen = m_peek_len(m, modif) - off; 612 if (pktlen < sizeof(icmphdr)) { 613 (*pr)("%s: too short mbuf chain (%u < %u)\n", __func__, 614 pktlen, sizeof(icmphdr)); 615 return m_examine_hex(m, off, modif, pr); 616 } 617 618 if (m_peek_data(m, off, sizeof(icmphdr), (void *)(&icmphdr)) < 0) { 619 (*pr)("%s: cannot read header\n", __func__); 620 return m_examine_hex(m, off, modif, pr); 621 } 622 off += sizeof(icmphdr); 623 624 (*pr)("ICMP: Type = %u(", icmphdr.icmp_type); 625 switch (icmphdr.icmp_type) { 626 case ICMP_ECHOREPLY: 627 (*pr)("Echo Reply)\n"); 628 break; 629 case ICMP_UNREACH: 630 (*pr)("Destination Unreachable)\n"); 631 break; 632 case ICMP_SOURCEQUENCH: 633 (*pr)("Source Quench)\n"); 634 break; 635 case ICMP_REDIRECT: 636 (*pr)("Redirect)\n"); 637 break; 638 case ICMP_TIMXCEED: 639 (*pr)("Time Exceeded)\n"); 640 break; 641 default: 642 (*pr)("unknown)\n"); 643 break; 644 } 645 (*pr)("ICMP: Code = %d\n", icmphdr.icmp_code); 646 647 return m_examine_hex(m, off, modif, pr); 648 } 649 650 void 651 m_examine_ip6(const struct mbuf *m, int off, const char *modif, 652 void (*pr)(const char *, ...)) 653 { 654 unsigned int pktlen; 655 struct ip6_hdr ip6; 656 struct ip6_hbh hbh; 657 int hbhlen; 658 uint32_t flow; 659 uint8_t vfc; 660 uint8_t nxt; 661 662 pktlen = m_peek_len(m, modif) - off; 663 if (pktlen < sizeof(ip6)) { 664 (*pr)("%s: too short mbuf chain (%u < %u)\n", __func__, 665 pktlen, sizeof(ip6)); 666 return m_examine_hex(m, off, modif, pr); 667 } 668 669 if (m_peek_data(m, off, sizeof(ip6), (void *)(&ip6)) < 0) { 670 (*pr)("%s: cannot read header\n", __func__); 671 return m_examine_hex(m, off, modif, pr); 672 } 673 off += sizeof(ip6); 674 675 vfc = ip6.ip6_vfc; 676 (*pr)("IPv6: Version = %u\n", (vfc & IPV6_VERSION_MASK) >> 4); 677 flow = ntohl(ip6.ip6_flow); 678 (*pr)("IPv6: Flow INFO = 0x%07x\n", flow & IPV6_FLOWINFO_MASK); 679 (*pr)("IPv6: Payload Length = %u\n", ntohs(ip6.ip6_plen)); 680 nxt = ip6.ip6_nxt; 681 (*pr)("IPv6: Next Header = %u(%s)\n", nxt, str_ipproto(nxt)); 682 (*pr)("IPv6: Hop Limit = %u\n", ip6.ip6_hlim); 683 (*pr)("IPv6: Src = %s\n", str_ip6addr(&ip6.ip6_src)); 684 (*pr)("IPv6: Dst = %s\n", str_ip6addr(&ip6.ip6_dst)); 685 686 /* Strip Hop-by-Hop options */ 687 if (nxt == IPPROTO_HOPOPTS) { 688 if (m_peek_data(m, off, sizeof(hbh), (void *)(&hbh)) < 0) { 689 (*pr)("Cannot read option\n"); 690 return m_examine_hex(m, off, modif, pr); 691 } 692 hbhlen = (hbh.ip6h_len + 1) << 3; 693 nxt = hbh.ip6h_nxt; 694 off += hbhlen; 695 696 (*pr)("IPv6: Stripped Hop-by-Hop\n"); 697 (*pr)("IPv6: Next Header = %u(%s)\n", nxt, str_ipproto(nxt)); 698 } 699 700 switch (nxt) { 701 case IPPROTO_IPV6_ICMP: 702 return m_examine_icmp6(m, off, modif, pr); 703 break; 704 case IPPROTO_TCP: 705 return m_examine_tcp(m, off, modif, pr); 706 break; 707 case IPPROTO_UDP: 708 return m_examine_udp(m, off, modif, pr); 709 break; 710 default: 711 break; 712 } 713 714 return m_examine_hex(m, off, modif, pr); 715 } 716 717 void 718 m_examine_icmp6(const struct mbuf *m, int off, const char *modif, 719 void (*pr)(const char *, ...)) 720 { 721 unsigned int pktlen; 722 struct icmp6_hdr icmp6; 723 724 pktlen = m_peek_len(m, modif) - off; 725 if (pktlen < sizeof(icmp6)) { 726 (*pr)("%s: too short mbuf chain (%u < %u)\n", __func__, 727 pktlen, sizeof(icmp6)); 728 return m_examine_hex(m, off, modif, pr); 729 } 730 731 if (m_peek_data(m, off, sizeof(icmp6), (void *)(&icmp6)) < 0) { 732 (*pr)("%s: cannot read header\n", __func__); 733 return m_examine_hex(m, off, modif, pr); 734 } 735 off += sizeof(icmp6); 736 737 (*pr)("ICMP6: Type = %u(", icmp6.icmp6_type); 738 switch (icmp6.icmp6_type) { 739 case ICMP6_DST_UNREACH: 740 (*pr)("Destination Unreachable)\n"); 741 break; 742 case ICMP6_PACKET_TOO_BIG: 743 (*pr)("Packet Too Big)\n"); 744 break; 745 case ICMP6_TIME_EXCEEDED: 746 (*pr)("Time Exceeded)\n"); 747 break; 748 case ICMP6_PARAM_PROB: 749 (*pr)("Parameter Problem)\n"); 750 break; 751 case ICMP6_ECHO_REQUEST: 752 (*pr)("Echo Request)\n"); 753 break; 754 case ICMP6_ECHO_REPLY: 755 (*pr)("Echo Reply)\n"); 756 break; 757 758 case MLD_LISTENER_QUERY: 759 (*pr)("MLD Listener Query)\n"); 760 break; 761 case MLD_LISTENER_REPORT: 762 (*pr)("MLD Listener Report)\n"); 763 break; 764 case MLD_LISTENER_DONE: 765 (*pr)("MLD Listener Done)\n"); 766 break; 767 768 case ND_ROUTER_SOLICIT: 769 (*pr)("Router Solicitation)\n"); 770 break; 771 case ND_ROUTER_ADVERT: 772 (*pr)("Router Advertizement)\n"); 773 break; 774 case ND_NEIGHBOR_SOLICIT: 775 (*pr)("Neighbor Solicitation)\n"); 776 break; 777 case ND_NEIGHBOR_ADVERT: 778 (*pr)("Neighbor Advertizement)\n"); 779 break; 780 case ND_REDIRECT: 781 (*pr)("Redirect)\n"); 782 break; 783 784 default: 785 (*pr)("unknown)\n"); 786 break; 787 } 788 (*pr)("ICMP6: Code = %u\n", icmp6.icmp6_code); 789 790 return m_examine_hex(m, off, modif, pr); 791 } 792 793 void 794 m_examine_tcp(const struct mbuf *m, int off, const char *modif, 795 void (*pr)(const char *, ...)) 796 { 797 unsigned int pktlen; 798 struct tcphdr tcp; 799 800 pktlen = m_peek_len(m, modif) - off; 801 if (pktlen < sizeof(tcp)) { 802 (*pr)("%s: too short mbuf chain (%u < %u)\n", __func__, 803 pktlen, sizeof(tcp)); 804 return m_examine_hex(m, off, modif, pr); 805 } 806 807 if (m_peek_data(m, off, sizeof(tcp), (void *)(&tcp)) < 0) { 808 (*pr)("%s: cannot read header\n", __func__); 809 return m_examine_hex(m, off, modif, pr); 810 } 811 off += sizeof(tcp); 812 813 (*pr)("TCP: Src = %u\n", ntohs(tcp.th_sport)); 814 (*pr)("TCP: Dst = %u\n", ntohs(tcp.th_dport)); 815 (*pr)("TCP: Seq. = %u\n", ntohl(tcp.th_seq)); 816 (*pr)("TCP: Ack. = %u\n", ntohl(tcp.th_ack)); 817 (*pr)("TCP: Header Length = %u\n", tcp.th_off << 2); 818 if (tcp.th_flags) { 819 (*pr)("TCP: Flags 0x%02x : ", tcp.th_flags); 820 if (tcp.th_flags & TH_FIN) 821 (*pr)("FIN "); 822 if (tcp.th_flags & TH_SYN) 823 (*pr)("SYN "); 824 if (tcp.th_flags & TH_RST) 825 (*pr)("RST "); 826 if (tcp.th_flags & TH_PUSH) 827 (*pr)("PUSH "); 828 if (tcp.th_flags & TH_URG) 829 (*pr)("URG "); 830 if (tcp.th_flags & TH_ECE) 831 (*pr)("ECE "); 832 if (tcp.th_flags & TH_CWR) 833 (*pr)("CWR "); 834 (*pr)("\n"); 835 } 836 (*pr)("TCP: Windows Size = %u\n", ntohs(tcp.th_win)); 837 (*pr)("TCP: checksum = 0x%04x\n", ntohs(tcp.th_sum)); 838 (*pr)("TCP: Urgent Pointer = %u\n", ntohs(tcp.th_urp)); 839 840 int len; 841 len = (tcp.th_off << 2) - sizeof(struct tcphdr); 842 if (len > 0) { 843 uint8_t *bufp, *op, opt, optlen; 844 845 bufp = malloc(len, M_TEMP, M_DONTWAIT); 846 if ((bufp == NULL) || (m_peek_data(m, off, len, bufp) < 0)) { 847 (*pr)("%s: cannot read TCP option\n", __func__); 848 if (bufp != NULL) 849 free(bufp, M_TEMP); 850 return m_examine_hex(m, off, modif, pr); 851 } 852 off += len; 853 op = bufp; 854 855 while (len > 0) { 856 opt = op[0]; 857 if (opt == TCPOPT_EOL) 858 break; 859 if (opt == TCPOPT_NOP) { 860 (*pr)("TCP: OPTION: NOP\n"); 861 op++; 862 len--; 863 continue; 864 } 865 if (opt == TCPOPT_PAD) { 866 (*pr)("TCP: OPTION: PAD\n"); 867 op++; 868 len--; 869 continue; 870 } 871 optlen = op[1]; 872 if (optlen == 0) 873 break; 874 875 if (opt == TCPOPT_MAXSEG && optlen == TCPOLEN_MAXSEG) { 876 uint16_t mss; 877 878 bcopy(op + 2, &mss, sizeof(mss)); 879 (*pr)("TCP: OPTION: MSS = %d\n", 880 ntohs(mss)); 881 882 op += optlen; 883 len -= optlen; 884 continue; 885 } else if (opt == TCPOPT_WINDOW 886 && optlen == TCPOLEN_WINDOW) { 887 (*pr)("TCP: OPTION: wscale = %d\n", op[2]); 888 op += optlen; 889 len -= optlen; 890 continue; 891 } else if (opt == TCPOPT_SACK_PERMITTED 892 && optlen == TCPOLEN_SACK_PERMITTED) { 893 (*pr)("TCP: OPTION: SACK OK\n"); 894 op += optlen; 895 len -= optlen; 896 continue; 897 } else if (opt == TCPOPT_TIMESTAMP 898 && optlen == TCPOLEN_TIMESTAMP) { 899 uint32_t ts_val, ts_ecr; 900 901 memcpy(&ts_val, op + 2, sizeof(ts_val)); 902 memcpy(&ts_ecr, op + 6, sizeof(ts_ecr)); 903 (*pr)("TCP: OPTION: TIMESTAMP = %u, " 904 "ECR = %u\n", 905 ntohl(ts_val), ntohl(ts_ecr)); 906 op += optlen; 907 len -= optlen; 908 continue; 909 } else { 910 (*pr)("TCP: OPTION: unknown (%d, len = %d)\n", 911 opt, optlen); 912 op += optlen; 913 len -= optlen; 914 continue; 915 } 916 } 917 free(bufp, M_TEMP); 918 } 919 920 if (off < pktlen) 921 m_examine_hex(m, off, modif, pr); 922 923 return; 924 } 925 926 void 927 m_examine_udp(const struct mbuf *m, int off, const char *modif, 928 void (*pr)(const char *, ...)) 929 { 930 unsigned int pktlen; 931 struct udphdr udp; 932 933 pktlen = m_peek_len(m, modif) - off; 934 if (pktlen < sizeof(udp)) { 935 (*pr)("%s: too short mbuf chain (%u < %u)\n", __func__, 936 pktlen, sizeof(udp)); 937 return m_examine_hex(m, off, modif, pr); 938 } 939 940 if (m_peek_data(m, off, sizeof(udp), (void *)(&udp)) < 0) { 941 (*pr)("%s: cannot read header\n", __func__); 942 return m_examine_hex(m, off, modif, pr); 943 } 944 off += sizeof(udp); 945 946 (*pr)("UDP: Src = %u\n", ntohs(udp.uh_sport)); 947 (*pr)("UDP: Dst = %u\n", ntohs(udp.uh_dport)); 948 (*pr)("UDP: Length = %u\n", ntohs(udp.uh_ulen)); 949 950 return m_examine_hex(m, off, modif, pr); 951 } 952 953 void 954 m_examine_hex(const struct mbuf *m, int off, const char *modif, 955 void (*pr)(const char *, ...)) 956 { 957 unsigned int pktlen; 958 int newline = 0; 959 uint8_t v; 960 961 pktlen = m_peek_len(m, modif) - off; 962 if (pktlen > EXAMINE_HEX_LIMIT) 963 pktlen = EXAMINE_HEX_LIMIT; 964 965 if (pktlen == 0) 966 return; 967 968 (*pr)("offset %04d: ", off); 969 while (pktlen > 0) { 970 if (m_peek_data(m, off, sizeof(v), (void *)(&v)) < 0) 971 break; 972 pktlen --; 973 off++; 974 newline++; 975 976 (*pr)("%02x", v); 977 if (pktlen == 0) 978 break; 979 980 if ((newline % EXAMINE_HEX_COL) == 0) { 981 (*pr)("\n"); 982 (*pr)("offset %04d: ", off); 983 } else 984 (*pr)(" "); 985 } 986 (*pr)("\n"); 987 } 988 989 void 990 m_examine(const struct mbuf *m, int af, const char *modif, 991 void (*pr)(const char *, ...)) 992 { 993 if (m == NULL) 994 return; 995 996 if (pr == NULL) 997 return; 998 999 switch (af) { 1000 case AF_UNSPEC: 1001 return m_examine_hex(m, 0, modif, pr); 1002 break; 1003 case AF_ETHER: 1004 return m_examine_ether(m, 0, modif, pr); 1005 break; 1006 case AF_ARP: 1007 return m_examine_arp(m, 0, modif, pr); 1008 break; 1009 case AF_INET: 1010 return m_examine_ip(m, 0, modif, pr); 1011 break; 1012 case AF_INET6: 1013 return m_examine_ip6(m, 0, modif, pr); 1014 break; 1015 default: 1016 (*pr)("No parser for AF %d\n", af); 1017 return m_examine_hex(m, 0, modif, pr); 1018 break; 1019 } 1020 1021 /* not reached */ 1022 return; 1023 } 1024