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