1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 30 #include <stdio.h> 31 #include <ctype.h> 32 #include <string.h> 33 #include <fcntl.h> 34 #include <string.h> 35 #include <sys/types.h> 36 #include <sys/time.h> 37 38 #include <sys/stropts.h> 39 #include <sys/socket.h> 40 #include <sys/sockio.h> 41 #include <net/if.h> 42 #include <netinet/in_systm.h> 43 #include <netinet/in.h> 44 #include <netinet/ip.h> 45 #include <netinet/ip6.h> 46 #include <netinet/ip_icmp.h> 47 #include <netinet/icmp6.h> 48 #include <netinet/if_ether.h> 49 #include <inet/ip6.h> 50 #include <inet/ipsecah.h> 51 #include <arpa/inet.h> 52 #include <netdb.h> 53 #include "snoop.h" 54 55 56 /* 57 * IPv6 extension header masks. These are used by the print_ipv6_extensions() 58 * function to return information to the caller about which extension headers 59 * were processed. This can be useful if the caller wants to know if the 60 * packet is an IPv6 fragment, for example. 61 */ 62 #define SNOOP_HOPOPTS 0x01U 63 #define SNOOP_ROUTING 0x02U 64 #define SNOOP_DSTOPTS 0x04U 65 #define SNOOP_FRAGMENT 0x08U 66 #define SNOOP_AH 0x10U 67 #define SNOOP_ESP 0x20U 68 #define SNOOP_IPV6 0x40U 69 70 extern char *dlc_header; 71 72 static void prt_routing_hdr(); 73 static void prt_fragment_hdr(); 74 static void prt_hbh_options(); 75 static void prt_dest_options(); 76 static void print_route(); 77 static void print_ipoptions(); 78 char *getproto(); 79 80 /* Keep track of how many nested IP headers we have. */ 81 unsigned int encap_levels; 82 unsigned int total_encap_levels = 1; 83 84 int 85 interpret_ip(flags, ip, fraglen) 86 int flags; 87 struct ip *ip; 88 int fraglen; 89 { 90 char *data; 91 char buff[24]; 92 boolean_t isfrag = B_FALSE; 93 boolean_t morefrag; 94 uint16_t fragoffset; 95 int hdrlen; 96 uint16_t iplen, uitmp; 97 extern char *src_name, *dst_name; 98 99 if (ip->ip_v == IPV6_VERSION) { 100 iplen = interpret_ipv6(flags, (ip6_t *)ip, fraglen); 101 return (iplen); 102 } 103 104 /* XXX Should this count for mix-and-match v4/v6 encapsulations? */ 105 if (encap_levels == 0) 106 total_encap_levels = 0; 107 encap_levels++; 108 total_encap_levels++; 109 110 hdrlen = ip->ip_hl * 4; 111 data = ((char *)ip) + hdrlen; 112 iplen = ntohs(ip->ip_len) - hdrlen; 113 fraglen -= hdrlen; 114 if (fraglen > iplen) 115 fraglen = iplen; 116 if (fraglen < 0) { 117 (void) snprintf(get_sum_line(), MAXLINE, 118 "IP truncated: header missing %d bytes", -fraglen); 119 encap_levels--; 120 return (fraglen + iplen); 121 } 122 /* 123 * We flag this as a fragment if the more fragments bit is set, or 124 * if the fragment offset is non-zero. 125 */ 126 morefrag = (ntohs(ip->ip_off) & IP_MF) == 0 ? B_FALSE : B_TRUE; 127 fragoffset = (ntohs(ip->ip_off) & 0x1FFF) * 8; 128 if (morefrag || fragoffset != 0) 129 isfrag = B_TRUE; 130 131 if (encap_levels == 1) { 132 src_name = addrtoname(AF_INET, &ip->ip_src); 133 dst_name = addrtoname(AF_INET, &ip->ip_dst); 134 } /* Else we already have the src_name and dst_name we want! */ 135 136 if (flags & F_SUM) { 137 if (isfrag) { 138 (void) snprintf(get_sum_line(), MAXLINE, 139 "%s IP fragment ID=%d Offset=%-4d MF=%d TOS=0x%x " 140 "TTL=%d", 141 getproto(ip->ip_p), 142 ntohs(ip->ip_id), 143 fragoffset, 144 morefrag, 145 ip->ip_tos, 146 ip->ip_ttl); 147 } else { 148 (void) strlcpy(buff, inet_ntoa(ip->ip_dst), 149 sizeof (buff)); 150 uitmp = ntohs(ip->ip_len); 151 (void) snprintf(get_sum_line(), MAXLINE, 152 "IP D=%s S=%s LEN=%u%s, ID=%d, TOS=0x%x, TTL=%d", 153 buff, 154 inet_ntoa(ip->ip_src), 155 uitmp, 156 iplen > fraglen ? "?" : "", 157 ntohs(ip->ip_id), 158 ip->ip_tos, 159 ip->ip_ttl); 160 } 161 } 162 163 if (flags & F_DTAIL) { 164 show_header("IP: ", "IP Header", iplen); 165 show_space(); 166 (void) snprintf(get_line((char *)ip - dlc_header, 1), 167 get_line_remain(), "Version = %d", ip->ip_v); 168 (void) snprintf(get_line((char *)ip - dlc_header, 1), 169 get_line_remain(), "Header length = %d bytes", hdrlen); 170 (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 171 get_line_remain(), "Type of service = 0x%02x", ip->ip_tos); 172 (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 173 get_line_remain(), " xxx. .... = %d (precedence)", 174 ip->ip_tos >> 5); 175 (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 176 get_line_remain(), " %s", 177 getflag(ip->ip_tos, IPTOS_LOWDELAY, 178 "low delay", "normal delay")); 179 (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 180 get_line_remain(), " %s", 181 getflag(ip->ip_tos, IPTOS_THROUGHPUT, 182 "high throughput", "normal throughput")); 183 (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 184 get_line_remain(), " %s", 185 getflag(ip->ip_tos, IPTOS_RELIABILITY, 186 "high reliability", "normal reliability")); 187 (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 188 get_line_remain(), " %s", 189 getflag(ip->ip_tos, IPTOS_ECT, 190 "ECN capable transport", "not ECN capable transport")); 191 (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 192 get_line_remain(), " %s", 193 getflag(ip->ip_tos, IPTOS_CE, 194 "ECN congestion experienced", 195 "no ECN congestion experienced")); 196 /* warning: ip_len is signed in netinet/ip.h */ 197 uitmp = ntohs(ip->ip_len); 198 (void) snprintf(get_line((char *)&ip->ip_len - dlc_header, 2), 199 get_line_remain(), "Total length = %u bytes%s", uitmp, 200 iplen > fraglen ? " -- truncated" : ""); 201 (void) snprintf(get_line((char *)&ip->ip_id - dlc_header, 2), 202 get_line_remain(), "Identification = %d", ntohs(ip->ip_id)); 203 /* warning: ip_off is signed in netinet/ip.h */ 204 uitmp = ntohs(ip->ip_off); 205 (void) snprintf(get_line((char *)&ip->ip_off - dlc_header, 1), 206 get_line_remain(), "Flags = 0x%x", uitmp >> 12); 207 (void) snprintf(get_line((char *)&ip->ip_off - dlc_header, 1), 208 get_line_remain(), " %s", 209 getflag(uitmp >> 8, IP_DF >> 8, 210 "do not fragment", "may fragment")); 211 (void) snprintf(get_line((char *)&ip->ip_off - dlc_header, 1), 212 get_line_remain(), " %s", 213 getflag(uitmp >> 8, IP_MF >> 8, 214 "more fragments", "last fragment")); 215 (void) snprintf(get_line((char *)&ip->ip_off - dlc_header, 2), 216 get_line_remain(), "Fragment offset = %u bytes", 217 fragoffset); 218 (void) snprintf(get_line((char *)&ip->ip_ttl - dlc_header, 1), 219 get_line_remain(), "Time to live = %d seconds/hops", 220 ip->ip_ttl); 221 (void) snprintf(get_line((char *)&ip->ip_p - dlc_header, 1), 222 get_line_remain(), "Protocol = %d (%s)", ip->ip_p, 223 getproto(ip->ip_p)); 224 /* 225 * XXX need to compute checksum and print whether it's correct 226 */ 227 (void) snprintf(get_line((char *)&ip->ip_sum - dlc_header, 1), 228 get_line_remain(), "Header checksum = %04x", 229 ntohs(ip->ip_sum)); 230 (void) snprintf(get_line((char *)&ip->ip_src - dlc_header, 1), 231 get_line_remain(), "Source address = %s, %s", 232 inet_ntoa(ip->ip_src), addrtoname(AF_INET, &ip->ip_src)); 233 (void) snprintf(get_line((char *)&ip->ip_dst - dlc_header, 1), 234 get_line_remain(), "Destination address = %s, %s", 235 inet_ntoa(ip->ip_dst), addrtoname(AF_INET, &ip->ip_dst)); 236 237 /* Print IP options - if any */ 238 239 print_ipoptions(ip + 1, hdrlen - sizeof (struct ip)); 240 show_space(); 241 } 242 243 /* 244 * If we are in detail mode, and this is not the first fragment of 245 * a fragmented packet, print out a little line stating this. 246 * Otherwise, go to the next protocol layer only if this is not a 247 * fragment, or we are in detail mode and this is the first fragment 248 * of a fragmented packet. 249 */ 250 if (flags & F_DTAIL && fragoffset != 0) { 251 (void) snprintf(get_detail_line(data - dlc_header, iplen), 252 MAXLINE, 253 "%s: [%d byte(s) of data, continuation of IP ident=%d]", 254 getproto(ip->ip_p), 255 iplen, 256 ntohs(ip->ip_id)); 257 } else if (!isfrag || (flags & F_DTAIL) && isfrag && fragoffset == 0) { 258 /* go to the next protocol layer */ 259 260 if (fraglen > 0) { 261 switch (ip->ip_p) { 262 case IPPROTO_IP: 263 break; 264 case IPPROTO_ENCAP: 265 (void) interpret_ip(flags, (struct ip *)data, 266 fraglen); 267 break; 268 case IPPROTO_ICMP: 269 interpret_icmp(flags, (struct icmp *)data, 270 iplen, fraglen); 271 break; 272 case IPPROTO_IGMP: 273 interpret_igmp(flags, data, iplen, fraglen); 274 break; 275 case IPPROTO_GGP: 276 break; 277 case IPPROTO_TCP: 278 interpret_tcp(flags, data, iplen, fraglen); 279 break; 280 281 case IPPROTO_ESP: 282 interpret_esp(flags, data, iplen, fraglen); 283 break; 284 case IPPROTO_AH: 285 interpret_ah(flags, data, iplen, fraglen); 286 break; 287 288 case IPPROTO_OSPF: 289 interpret_ospf(flags, data, iplen, fraglen); 290 break; 291 292 case IPPROTO_EGP: 293 case IPPROTO_PUP: 294 break; 295 case IPPROTO_UDP: 296 interpret_udp(flags, data, iplen, fraglen); 297 break; 298 299 case IPPROTO_IDP: 300 case IPPROTO_HELLO: 301 case IPPROTO_ND: 302 case IPPROTO_RAW: 303 break; 304 case IPPROTO_IPV6: /* IPV6 encap */ 305 (void) interpret_ipv6(flags, (ip6_t *)data, 306 iplen); 307 break; 308 case IPPROTO_SCTP: 309 interpret_sctp(flags, data, iplen, fraglen); 310 break; 311 } 312 } 313 } 314 315 encap_levels--; 316 return (iplen); 317 } 318 319 int 320 interpret_ipv6(flags, ip6h, fraglen) 321 int flags; 322 ip6_t *ip6h; 323 int fraglen; 324 { 325 uint8_t *data; 326 int hdrlen, iplen; 327 extern char *src_name, *dst_name; 328 int version, flow, class; 329 uchar_t proto; 330 boolean_t isfrag = B_FALSE; 331 uint8_t extmask; 332 /* 333 * The print_srcname and print_dstname strings are the hostname 334 * parts of the verbose IPv6 header output, including the comma 335 * and the space after the litteral address strings. 336 */ 337 char print_srcname[MAXHOSTNAMELEN + 2]; 338 char print_dstname[MAXHOSTNAMELEN + 2]; 339 char src_addrstr[INET6_ADDRSTRLEN]; 340 char dst_addrstr[INET6_ADDRSTRLEN]; 341 342 iplen = ntohs(ip6h->ip6_plen); 343 hdrlen = IPV6_HDR_LEN; 344 fraglen -= hdrlen; 345 if (fraglen < 0) 346 return (fraglen + hdrlen); 347 data = ((uint8_t *)ip6h) + hdrlen; 348 349 proto = ip6h->ip6_nxt; 350 351 src_name = addrtoname(AF_INET6, &ip6h->ip6_src); 352 dst_name = addrtoname(AF_INET6, &ip6h->ip6_dst); 353 354 /* 355 * Use endian-aware masks to extract traffic class and 356 * flowinfo. Also, flowinfo is now 20 bits and class 8 357 * rather than 24 and 4. 358 */ 359 class = ntohl((ip6h->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20); 360 flow = ntohl(ip6h->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL); 361 362 /* 363 * NOTE: the F_SUM and F_DTAIL flags are mutually exclusive, 364 * so the code within the first part of the following if statement 365 * will not affect the detailed printing of the packet. 366 */ 367 if (flags & F_SUM) { 368 (void) sprintf(get_sum_line(), "IPv6 S=%s D=%s LEN=%d " 369 "HOPS=%d CLASS=0x%x FLOW=0x%x", 370 src_name, dst_name, iplen, ip6h->ip6_hops, class, flow); 371 } else if (flags & F_DTAIL) { 372 373 (void) inet_ntop(AF_INET6, &ip6h->ip6_src, src_addrstr, 374 INET6_ADDRSTRLEN); 375 (void) inet_ntop(AF_INET6, &ip6h->ip6_dst, dst_addrstr, 376 INET6_ADDRSTRLEN); 377 378 version = ntohl(ip6h->ip6_vcf) >> 28; 379 380 if (strcmp(src_name, src_addrstr) == 0) 381 print_srcname[0] = '\0'; 382 else 383 snprintf(print_srcname, sizeof (print_srcname), 384 ", %s", src_name); 385 386 if (strcmp(dst_name, dst_addrstr) == 0) 387 print_dstname[0] = '\0'; 388 else 389 snprintf(print_dstname, sizeof (print_dstname), 390 ", %s", dst_name); 391 392 show_header("IPv6: ", "IPv6 Header", iplen); 393 show_space(); 394 395 (void) sprintf(get_line((char *)ip6h - dlc_header, 1), 396 "Version = %d", version); 397 (void) sprintf(get_line((char *)ip6h - dlc_header, 1), 398 "Traffic Class = %d", class); 399 (void) sprintf(get_line((char *)&ip6h->ip6_vcf - dlc_header, 4), 400 "Flow label = 0x%x", flow); 401 (void) sprintf(get_line((char *)&ip6h->ip6_plen - 402 dlc_header, 2), "Payload length = %d", iplen); 403 (void) sprintf(get_line((char *)&ip6h->ip6_nxt - 404 dlc_header, 1), "Next Header = %d (%s)", proto, 405 getproto(proto)); 406 (void) sprintf(get_line((char *)&ip6h->ip6_hops - 407 dlc_header, 1), "Hop Limit = %d", ip6h->ip6_hops); 408 (void) sprintf(get_line((char *)&ip6h->ip6_src - dlc_header, 1), 409 "Source address = %s%s", src_addrstr, print_srcname); 410 (void) sprintf(get_line((char *)&ip6h->ip6_dst - dlc_header, 1), 411 "Destination address = %s%s", dst_addrstr, print_dstname); 412 413 show_space(); 414 } 415 416 /* 417 * Print IPv6 Extension Headers, or skip them in the summary case. 418 * Set isfrag to true if one of the extension headers encounterred 419 * was a fragment header. 420 */ 421 if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS || 422 proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) { 423 extmask = print_ipv6_extensions(flags, &data, &proto, &iplen, 424 &fraglen); 425 if ((extmask & SNOOP_FRAGMENT) != 0) { 426 isfrag = B_TRUE; 427 } 428 } 429 430 /* 431 * We only want to print upper layer information if this is not 432 * a fragment, or if we're printing in detail. Note that the 433 * proto variable will be set to IPPROTO_NONE if this is a fragment 434 * with a non-zero fragment offset. 435 */ 436 if (!isfrag || flags & F_DTAIL) { 437 /* go to the next protocol layer */ 438 439 switch (proto) { 440 case IPPROTO_IP: 441 break; 442 case IPPROTO_ENCAP: 443 (void) interpret_ip(flags, (struct ip *)data, fraglen); 444 break; 445 case IPPROTO_ICMPV6: 446 interpret_icmpv6(flags, (icmp6_t *)data, iplen, 447 fraglen); 448 break; 449 case IPPROTO_IGMP: 450 interpret_igmp(flags, data, iplen, fraglen); 451 break; 452 case IPPROTO_GGP: 453 break; 454 case IPPROTO_TCP: 455 interpret_tcp(flags, data, iplen, fraglen); 456 break; 457 case IPPROTO_ESP: 458 interpret_esp(flags, data, iplen, fraglen); 459 break; 460 case IPPROTO_AH: 461 interpret_ah(flags, data, iplen, fraglen); 462 break; 463 case IPPROTO_EGP: 464 case IPPROTO_PUP: 465 break; 466 case IPPROTO_UDP: 467 interpret_udp(flags, data, iplen, fraglen); 468 break; 469 case IPPROTO_IDP: 470 case IPPROTO_HELLO: 471 case IPPROTO_ND: 472 case IPPROTO_RAW: 473 break; 474 case IPPROTO_IPV6: 475 (void) interpret_ipv6(flags, (ip6_t *)data, iplen); 476 break; 477 case IPPROTO_SCTP: 478 interpret_sctp(flags, data, iplen, fraglen); 479 break; 480 case IPPROTO_OSPF: 481 interpret_ospf6(flags, data, iplen, fraglen); 482 break; 483 } 484 } 485 486 return (iplen); 487 } 488 489 /* 490 * ip_ext: data including the extension header. 491 * iplen: length of the data remaining in the packet. 492 * Returns a mask of IPv6 extension headers it processed. 493 */ 494 uint8_t 495 print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen, 496 int *fraglen) 497 { 498 uint8_t *data_ptr; 499 uchar_t proto = *next; 500 boolean_t is_extension_header; 501 struct ip6_hbh *ipv6ext_hbh; 502 struct ip6_dest *ipv6ext_dest; 503 struct ip6_rthdr *ipv6ext_rthdr; 504 struct ip6_frag *ipv6ext_frag; 505 uint32_t exthdrlen; 506 uint8_t extmask = 0; 507 508 if ((hdr == NULL) || (*hdr == NULL) || (next == NULL) || (iplen == 0)) 509 return (0); 510 511 data_ptr = *hdr; 512 is_extension_header = B_TRUE; 513 while (is_extension_header) { 514 515 /* 516 * There must be at least enough data left to read the 517 * next header and header length fields from the next 518 * header. 519 */ 520 if (*fraglen < 2) { 521 proto = IPPROTO_NONE; 522 return (extmask); 523 } 524 525 switch (proto) { 526 case IPPROTO_HOPOPTS: 527 ipv6ext_hbh = (struct ip6_hbh *)data_ptr; 528 exthdrlen = 8 + ipv6ext_hbh->ip6h_len * 8; 529 if (*fraglen <= exthdrlen) { 530 proto = IPPROTO_NONE; 531 return (extmask); 532 } 533 prt_hbh_options(flags, ipv6ext_hbh); 534 extmask |= SNOOP_HOPOPTS; 535 proto = ipv6ext_hbh->ip6h_nxt; 536 break; 537 case IPPROTO_DSTOPTS: 538 ipv6ext_dest = (struct ip6_dest *)data_ptr; 539 exthdrlen = 8 + ipv6ext_dest->ip6d_len * 8; 540 if (*fraglen <= exthdrlen) { 541 proto = IPPROTO_NONE; 542 return (extmask); 543 } 544 prt_dest_options(flags, ipv6ext_dest); 545 extmask |= SNOOP_DSTOPTS; 546 proto = ipv6ext_dest->ip6d_nxt; 547 break; 548 case IPPROTO_ROUTING: 549 ipv6ext_rthdr = (struct ip6_rthdr *)data_ptr; 550 exthdrlen = 8 + ipv6ext_rthdr->ip6r_len * 8; 551 if (*fraglen <= exthdrlen) { 552 proto = IPPROTO_NONE; 553 return (extmask); 554 } 555 prt_routing_hdr(flags, ipv6ext_rthdr); 556 extmask |= SNOOP_ROUTING; 557 proto = ipv6ext_rthdr->ip6r_nxt; 558 break; 559 case IPPROTO_FRAGMENT: 560 ipv6ext_frag = (struct ip6_frag *)data_ptr; 561 exthdrlen = sizeof (struct ip6_frag); 562 if (*fraglen <= exthdrlen) { 563 proto = IPPROTO_NONE; 564 return (extmask); 565 } 566 prt_fragment_hdr(flags, ipv6ext_frag); 567 extmask |= SNOOP_FRAGMENT; 568 /* 569 * If this is not the first fragment, forget about 570 * the rest of the packet, snoop decoding is 571 * stateless. 572 */ 573 if ((ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK) != 0) 574 proto = IPPROTO_NONE; 575 else 576 proto = ipv6ext_frag->ip6f_nxt; 577 break; 578 default: 579 is_extension_header = B_FALSE; 580 break; 581 } 582 583 if (is_extension_header) { 584 *iplen -= exthdrlen; 585 *fraglen -= exthdrlen; 586 data_ptr += exthdrlen; 587 } 588 } 589 590 *next = proto; 591 *hdr = data_ptr; 592 return (extmask); 593 } 594 595 static void 596 print_ipoptions(opt, optlen) 597 uchar_t *opt; 598 int optlen; 599 { 600 int len; 601 char *line; 602 603 if (optlen <= 0) { 604 (void) sprintf(get_line((char *)&opt - dlc_header, 1), 605 "No options"); 606 return; 607 } 608 609 (void) sprintf(get_line((char *)&opt - dlc_header, 1), 610 "Options: (%d bytes)", optlen); 611 612 while (optlen > 0) { 613 line = get_line((char *)&opt - dlc_header, 1); 614 len = opt[1]; 615 switch (opt[0]) { 616 case IPOPT_EOL: 617 (void) strcpy(line, " - End of option list"); 618 return; 619 case IPOPT_NOP: 620 (void) strcpy(line, " - No op"); 621 len = 1; 622 break; 623 case IPOPT_RR: 624 (void) sprintf(line, " - Record route (%d bytes)", 625 len); 626 print_route(opt); 627 break; 628 case IPOPT_TS: 629 (void) sprintf(line, " - Time stamp (%d bytes)", len); 630 break; 631 case IPOPT_SECURITY: 632 (void) sprintf(line, " - Security (%d bytes)", len); 633 break; 634 case IPOPT_LSRR: 635 (void) sprintf(line, 636 " - Loose source route (%d bytes)", len); 637 print_route(opt); 638 break; 639 case IPOPT_SATID: 640 (void) sprintf(line, " - SATNET Stream id (%d bytes)", 641 len); 642 break; 643 case IPOPT_SSRR: 644 (void) sprintf(line, 645 " - Strict source route, (%d bytes)", len); 646 print_route(opt); 647 break; 648 default: 649 sprintf(line, " - Option %d (unknown - %d bytes) %s", 650 opt[0], len, tohex((char *)&opt[2], len - 2)); 651 break; 652 } 653 if (len <= 0) { 654 (void) sprintf(line, " - Incomplete option len %d", 655 len); 656 break; 657 } 658 opt += len; 659 optlen -= len; 660 } 661 } 662 663 static void 664 print_route(opt) 665 uchar_t *opt; 666 { 667 int len, pointer; 668 struct in_addr addr; 669 char *line; 670 671 len = opt[1]; 672 pointer = opt[2]; 673 674 (void) sprintf(get_line((char *)(&opt + 2) - dlc_header, 1), 675 " Pointer = %d", pointer); 676 677 pointer -= IPOPT_MINOFF; 678 opt += (IPOPT_OFFSET + 1); 679 len -= (IPOPT_OFFSET + 1); 680 681 while (len > 0) { 682 line = get_line((char *)&(opt) - dlc_header, 4); 683 memcpy((char *)&addr, opt, sizeof (addr)); 684 if (addr.s_addr == INADDR_ANY) 685 (void) strcpy(line, " -"); 686 else 687 (void) sprintf(line, " %s", 688 addrtoname(AF_INET, &addr)); 689 if (pointer == 0) 690 (void) strcat(line, " <-- (current)"); 691 692 opt += sizeof (addr); 693 len -= sizeof (addr); 694 pointer -= sizeof (addr); 695 } 696 } 697 698 char * 699 getproto(p) 700 int p; 701 { 702 switch (p) { 703 case IPPROTO_HOPOPTS: return ("IPv6-HopOpts"); 704 case IPPROTO_IPV6: return ("IPv6"); 705 case IPPROTO_ROUTING: return ("IPv6-Route"); 706 case IPPROTO_FRAGMENT: return ("IPv6-Frag"); 707 case IPPROTO_RSVP: return ("RSVP"); 708 case IPPROTO_ENCAP: return ("IP-in-IP"); 709 case IPPROTO_AH: return ("AH"); 710 case IPPROTO_ESP: return ("ESP"); 711 case IPPROTO_ICMP: return ("ICMP"); 712 case IPPROTO_ICMPV6: return ("ICMPv6"); 713 case IPPROTO_DSTOPTS: return ("IPv6-DstOpts"); 714 case IPPROTO_IGMP: return ("IGMP"); 715 case IPPROTO_GGP: return ("GGP"); 716 case IPPROTO_TCP: return ("TCP"); 717 case IPPROTO_EGP: return ("EGP"); 718 case IPPROTO_PUP: return ("PUP"); 719 case IPPROTO_UDP: return ("UDP"); 720 case IPPROTO_IDP: return ("IDP"); 721 case IPPROTO_HELLO: return ("HELLO"); 722 case IPPROTO_ND: return ("ND"); 723 case IPPROTO_EON: return ("EON"); 724 case IPPROTO_RAW: return ("RAW"); 725 case IPPROTO_OSPF: return ("OSPF"); 726 default: return (""); 727 } 728 } 729 730 static void 731 prt_routing_hdr(flags, ipv6ext_rthdr) 732 int flags; 733 struct ip6_rthdr *ipv6ext_rthdr; 734 { 735 uint8_t nxt_hdr; 736 uint8_t type; 737 uint32_t len; 738 uint8_t segleft; 739 uint32_t numaddrs; 740 int i; 741 struct ip6_rthdr0 *ipv6ext_rthdr0; 742 struct in6_addr *addrs; 743 char addr[INET6_ADDRSTRLEN]; 744 745 /* in summary mode, we don't do anything. */ 746 if (flags & F_SUM) { 747 return; 748 } 749 750 nxt_hdr = ipv6ext_rthdr->ip6r_nxt; 751 type = ipv6ext_rthdr->ip6r_type; 752 len = 8 * (ipv6ext_rthdr->ip6r_len + 1); 753 segleft = ipv6ext_rthdr->ip6r_segleft; 754 755 show_header("IPv6-Route: ", "IPv6 Routing Header", 0); 756 show_space(); 757 758 (void) sprintf(get_line((char *)ipv6ext_rthdr - dlc_header, 1), 759 "Next header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 760 (void) sprintf(get_line((char *)ipv6ext_rthdr - dlc_header, 1), 761 "Header length = %d", len); 762 (void) sprintf(get_line((char *)ipv6ext_rthdr - dlc_header, 1), 763 "Routing type = %d", type); 764 (void) sprintf(get_line((char *)ipv6ext_rthdr - dlc_header, 1), 765 "Segments left = %d", segleft); 766 767 if (type == IPV6_RTHDR_TYPE_0) { 768 /* 769 * XXX This loop will print all addresses in the routing header, 770 * XXX not just the segments left. 771 * XXX (The header length field is twice the number of 772 * XXX addresses) 773 * XXX At some future time, we may want to change this 774 * XXX to differentiate between the hops yet to do 775 * XXX and the hops already taken. 776 */ 777 ipv6ext_rthdr0 = (struct ip6_rthdr0 *)ipv6ext_rthdr; 778 numaddrs = ipv6ext_rthdr0->ip6r0_len / 2; 779 addrs = (struct in6_addr *)(ipv6ext_rthdr0 + 1); 780 for (i = 0; i < numaddrs; i++) { 781 (void) inet_ntop(AF_INET6, &addrs[i], addr, 782 INET6_ADDRSTRLEN); 783 (void) sprintf(get_line((char *)ipv6ext_rthdr - 784 dlc_header, 1), 785 "address[%d]=%s", i, addr); 786 } 787 } 788 789 show_space(); 790 } 791 792 static void 793 prt_fragment_hdr(flags, ipv6ext_frag) 794 int flags; 795 struct ip6_frag *ipv6ext_frag; 796 { 797 boolean_t morefrag; 798 uint16_t fragoffset; 799 uint8_t nxt_hdr; 800 uint32_t fragident; 801 802 /* extract the various fields from the fragment header */ 803 nxt_hdr = ipv6ext_frag->ip6f_nxt; 804 morefrag = (ipv6ext_frag->ip6f_offlg & IP6F_MORE_FRAG) == 0 805 ? B_FALSE : B_TRUE; 806 fragoffset = ntohs(ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK); 807 fragident = ntohl(ipv6ext_frag->ip6f_ident); 808 809 if (flags & F_SUM) { 810 (void) sprintf(get_sum_line(), 811 "IPv6 fragment ID=%d Offset=%-4d MF=%d", 812 fragident, 813 fragoffset, 814 morefrag); 815 } else { /* F_DTAIL */ 816 show_header("IPv6-Frag: ", "IPv6 Fragment Header", 0); 817 show_space(); 818 819 (void) sprintf(get_line((char *)ipv6ext_frag - dlc_header, 1), 820 "Next Header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 821 (void) sprintf(get_line((char *)ipv6ext_frag - dlc_header, 1), 822 "Fragment Offset = %d", fragoffset); 823 (void) sprintf(get_line((char *)ipv6ext_frag - dlc_header, 1), 824 "More Fragments Flag = %s", morefrag ? "true" : "false"); 825 (void) sprintf(get_line((char *)ipv6ext_frag - dlc_header, 1), 826 "Identification = %d", fragident); 827 828 show_space(); 829 } 830 } 831 832 static void 833 prt_hbh_options(flags, ipv6ext_hbh) 834 int flags; 835 struct ip6_hbh *ipv6ext_hbh; 836 { 837 uint8_t *data; 838 uint32_t len, olen; 839 uint8_t op_type; 840 uint8_t op_len; 841 uint8_t nxt_hdr; 842 843 /* in summary mode, we don't do anything. */ 844 if (flags & F_SUM) { 845 return; 846 } 847 848 show_header("IPv6-HopOpts: ", "IPv6 Hop-by-Hop Options Header", 0); 849 show_space(); 850 851 /* 852 * Store the lengh of this ext hdr in bytes. The caller has 853 * ensured that there is at least len bytes of data left. 854 */ 855 len = ipv6ext_hbh->ip6h_len * 8 + 8; 856 857 data = (uint8_t *)ipv6ext_hbh + 2; 858 len -= 2; 859 860 nxt_hdr = ipv6ext_hbh->ip6h_nxt; 861 (void) sprintf(get_line((char *)ipv6ext_hbh - dlc_header, 1), 862 "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr)); 863 864 while (len > 0) { 865 GETINT8(op_type, data); 866 olen = len; 867 switch (op_type) { 868 case IP6OPT_PAD1: 869 (void) sprintf(get_line((char *)ipv6ext_hbh - 870 dlc_header, 1), 871 "pad1 option "); 872 len--; 873 break; 874 case IP6OPT_PADN: 875 GETINT8(op_len, data); 876 (void) sprintf(get_line((char *)ipv6ext_hbh - 877 dlc_header, 1), 878 "padN option len = %u", op_len); 879 data += op_len; /* skip pads */ 880 len -= (op_len + 2); 881 break; 882 case IP6OPT_JUMBO: { 883 uint32_t payload_len; 884 885 GETINT8(op_len, data); 886 (void) sprintf(get_line((char *)ipv6ext_hbh - 887 dlc_header, 1), 888 "Jumbo Payload Option len = %u bytes", op_len); 889 if (op_len == sizeof (uint32_t)) { 890 GETINT32(payload_len, data); 891 (void) sprintf(get_line((char *)ipv6ext_hbh - 892 dlc_header, 1), 893 "Jumbo Payload Length = %u bytes", 894 payload_len); 895 } else { 896 data += op_len; 897 } 898 len -= (op_len + 2); 899 break; 900 } 901 case IP6OPT_ROUTER_ALERT: { 902 uint16_t value; 903 const char *label[] = {"MLD", "RSVP", "AN"}; 904 905 GETINT8(op_len, data); 906 (void) snprintf(get_line((char *)ipv6ext_hbh - 907 dlc_header, 1), get_line_remain(), 908 "Router Alert Option len = %u bytes", op_len); 909 if (op_len == sizeof (uint16_t)) { 910 GETINT16(value, data); 911 (void) snprintf(get_line((char *)ipv6ext_hbh - 912 dlc_header, 1), get_line_remain(), 913 "Alert Type = %d (%s)", value, 914 value < sizeof (label) / sizeof (label[0]) ? 915 label[value] : "???"); 916 } else { 917 data += op_len; 918 } 919 len -= (op_len + 2); 920 break; 921 } 922 default: 923 GETINT8(op_len, data); 924 (void) sprintf(get_line((char *)ipv6ext_hbh - 925 dlc_header, 1), 926 "Option type = %u, len = %u", op_type, op_len); 927 data += op_len; 928 len -= (op_len + 2); 929 } 930 /* check for corrupt length */ 931 if (olen <= len) { 932 (void) sprintf(get_line((char *)ipv6ext_hbh - 933 dlc_header, 1), 934 "Incomplete option len = %u, len = %u", op_type, 935 len); 936 break; 937 } 938 } 939 940 show_space(); 941 } 942 943 static void 944 prt_dest_options(flags, ipv6ext_dest) 945 int flags; 946 struct ip6_dest *ipv6ext_dest; 947 { 948 uint8_t *data; 949 uint32_t len, olen; 950 uint8_t op_type; 951 uint32_t op_len; 952 uint8_t nxt_hdr; 953 uint8_t value; 954 955 /* in summary mode, we don't do anything. */ 956 if (flags & F_SUM) { 957 return; 958 } 959 960 show_header("IPv6-DstOpts: ", "IPv6 Destination Options Header", 0); 961 show_space(); 962 963 /* 964 * Store the length of this ext hdr in bytes. The caller has 965 * ensured that there is at least len bytes of data left. 966 */ 967 len = ipv6ext_dest->ip6d_len * 8 + 8; 968 969 data = (uint8_t *)ipv6ext_dest + 2; /* skip hdr/len */ 970 len -= 2; 971 972 nxt_hdr = ipv6ext_dest->ip6d_nxt; 973 (void) sprintf(get_line((char *)ipv6ext_dest - dlc_header, 1), 974 "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr)); 975 976 while (len > 0) { 977 GETINT8(op_type, data); 978 olen = len; 979 switch (op_type) { 980 case IP6OPT_PAD1: 981 (void) sprintf(get_line((char *)ipv6ext_dest - 982 dlc_header, 1), 983 "pad1 option "); 984 len--; 985 break; 986 case IP6OPT_PADN: 987 GETINT8(op_len, data); 988 (void) sprintf(get_line((char *)ipv6ext_dest - 989 dlc_header, 1), 990 "padN option len = %u", op_len); 991 data += op_len; 992 len -= (op_len + 2); 993 break; 994 case IP6OPT_TUNNEL_LIMIT: 995 GETINT8(op_len, data); 996 GETINT8(value, data); 997 (void) sprintf(get_line((char *)ipv6ext_dest - 998 dlc_header, 1), 999 "tunnel encapsulation limit len = %d, value = %d", 1000 op_len, value); 1001 len -= (op_len + 2); 1002 break; 1003 default: 1004 GETINT8(op_len, data); 1005 (void) sprintf(get_line((char *)ipv6ext_dest - 1006 dlc_header, 1), 1007 "Option type = %u, len = %u", op_type, op_len); 1008 data += op_len; 1009 len -= (op_len + 2); 1010 } 1011 /* check for corrupt length */ 1012 if (olen <= len) { 1013 (void) sprintf(get_line((char *)ipv6ext_dest - 1014 dlc_header, 1), 1015 "Incomplete option len = %u, len = %u", op_type, 1016 len); 1017 break; 1018 } 1019 } 1020 1021 show_space(); 1022 } 1023