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