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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <string.h> 28 #include <fcntl.h> 29 #include <string.h> 30 #include <sys/types.h> 31 #include <sys/time.h> 32 33 #include <sys/stropts.h> 34 #include <sys/socket.h> 35 #include <net/if.h> 36 #include <netinet/in_systm.h> 37 #include <netinet/in.h> 38 #include <netinet/ip.h> 39 #include <netinet/ip6.h> 40 #include <netinet/ip_icmp.h> 41 #include <netinet/icmp6.h> 42 #include <netinet/if_ether.h> 43 #include <inet/ip.h> 44 #include <inet/ip6.h> 45 #include <arpa/inet.h> 46 #include <netdb.h> 47 #include <tsol/label.h> 48 #include <sys/tsol/tndb.h> 49 #include <sys/tsol/label_macro.h> 50 51 #include "snoop.h" 52 53 54 /* 55 * IPv6 extension header masks. These are used by the print_ipv6_extensions() 56 * function to return information to the caller about which extension headers 57 * were processed. This can be useful if the caller wants to know if the 58 * packet is an IPv6 fragment, for example. 59 */ 60 #define SNOOP_HOPOPTS 0x01U 61 #define SNOOP_ROUTING 0x02U 62 #define SNOOP_DSTOPTS 0x04U 63 #define SNOOP_FRAGMENT 0x08U 64 #define SNOOP_AH 0x10U 65 #define SNOOP_ESP 0x20U 66 #define SNOOP_IPV6 0x40U 67 68 static void prt_routing_hdr(int, const struct ip6_rthdr *); 69 static void prt_fragment_hdr(int, const struct ip6_frag *); 70 static void prt_hbh_options(int, const struct ip6_hbh *); 71 static void prt_dest_options(int, const struct ip6_dest *); 72 static void print_route(const uchar_t *); 73 static void print_ipoptions(const uchar_t *, int); 74 static void print_ripso(const uchar_t *); 75 static void print_cipso(const uchar_t *); 76 77 /* Keep track of how many nested IP headers we have. */ 78 unsigned int encap_levels; 79 unsigned int total_encap_levels = 1; 80 81 int 82 interpret_ip(int flags, const struct ip *ip, int fraglen) 83 { 84 uchar_t *data; 85 char buff[24]; 86 boolean_t isfrag = B_FALSE; 87 boolean_t morefrag; 88 uint16_t fragoffset; 89 int hdrlen; 90 uint16_t iplen, uitmp; 91 92 if (ip->ip_v == IPV6_VERSION) { 93 iplen = interpret_ipv6(flags, (ip6_t *)ip, fraglen); 94 return (iplen); 95 } 96 97 if (encap_levels == 0) 98 total_encap_levels = 0; 99 encap_levels++; 100 total_encap_levels++; 101 102 hdrlen = ip->ip_hl * 4; 103 data = ((uchar_t *)ip) + hdrlen; 104 iplen = ntohs(ip->ip_len) - hdrlen; 105 fraglen -= hdrlen; 106 if (fraglen > iplen) 107 fraglen = iplen; 108 if (fraglen < 0) { 109 (void) snprintf(get_sum_line(), MAXLINE, 110 "IP truncated: header missing %d bytes", -fraglen); 111 encap_levels--; 112 return (fraglen + iplen); 113 } 114 /* 115 * We flag this as a fragment if the more fragments bit is set, or 116 * if the fragment offset is non-zero. 117 */ 118 morefrag = (ntohs(ip->ip_off) & IP_MF) == 0 ? B_FALSE : B_TRUE; 119 fragoffset = (ntohs(ip->ip_off) & 0x1FFF) * 8; 120 if (morefrag || fragoffset != 0) 121 isfrag = B_TRUE; 122 123 src_name = addrtoname(AF_INET, &ip->ip_src); 124 dst_name = addrtoname(AF_INET, &ip->ip_dst); 125 126 if (flags & F_SUM) { 127 if (isfrag) { 128 (void) snprintf(get_sum_line(), MAXLINE, 129 "%s IP fragment ID=%d Offset=%-4d MF=%d TOS=0x%x " 130 "TTL=%d", 131 getproto(ip->ip_p), 132 ntohs(ip->ip_id), 133 fragoffset, 134 morefrag, 135 ip->ip_tos, 136 ip->ip_ttl); 137 } else { 138 (void) strlcpy(buff, inet_ntoa(ip->ip_dst), 139 sizeof (buff)); 140 uitmp = ntohs(ip->ip_len); 141 (void) snprintf(get_sum_line(), MAXLINE, 142 "IP D=%s S=%s LEN=%u%s, ID=%d, TOS=0x%x, TTL=%d", 143 buff, 144 inet_ntoa(ip->ip_src), 145 uitmp, 146 iplen > fraglen ? "?" : "", 147 ntohs(ip->ip_id), 148 ip->ip_tos, 149 ip->ip_ttl); 150 } 151 } 152 153 if (flags & F_DTAIL) { 154 show_header("IP: ", "IP Header", iplen); 155 show_space(); 156 (void) snprintf(get_line(0, 0), get_line_remain(), 157 "Version = %d", ip->ip_v); 158 (void) snprintf(get_line(0, 0), get_line_remain(), 159 "Header length = %d bytes", hdrlen); 160 (void) snprintf(get_line(0, 0), get_line_remain(), 161 "Type of service = 0x%02x", ip->ip_tos); 162 (void) snprintf(get_line(0, 0), get_line_remain(), 163 " xxx. .... = %d (precedence)", 164 ip->ip_tos >> 5); 165 (void) snprintf(get_line(0, 0), get_line_remain(), 166 " %s", getflag(ip->ip_tos, IPTOS_LOWDELAY, 167 "low delay", "normal delay")); 168 (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 169 getflag(ip->ip_tos, IPTOS_THROUGHPUT, 170 "high throughput", "normal throughput")); 171 (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 172 getflag(ip->ip_tos, IPTOS_RELIABILITY, 173 "high reliability", "normal reliability")); 174 (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 175 getflag(ip->ip_tos, IPTOS_ECT, 176 "ECN capable transport", "not ECN capable transport")); 177 (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 178 getflag(ip->ip_tos, IPTOS_CE, 179 "ECN congestion experienced", 180 "no ECN congestion experienced")); 181 /* warning: ip_len is signed in netinet/ip.h */ 182 uitmp = ntohs(ip->ip_len); 183 (void) snprintf(get_line(0, 0), get_line_remain(), 184 "Total length = %u bytes%s", uitmp, 185 iplen > fraglen ? " -- truncated" : ""); 186 (void) snprintf(get_line(0, 0), get_line_remain(), 187 "Identification = %d", ntohs(ip->ip_id)); 188 /* warning: ip_off is signed in netinet/ip.h */ 189 uitmp = ntohs(ip->ip_off); 190 (void) snprintf(get_line(0, 0), get_line_remain(), 191 "Flags = 0x%x", uitmp >> 12); 192 (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 193 getflag(uitmp >> 8, IP_DF >> 8, 194 "do not fragment", "may fragment")); 195 (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 196 getflag(uitmp >> 8, IP_MF >> 8, 197 "more fragments", "last fragment")); 198 (void) snprintf(get_line(0, 0), get_line_remain(), 199 "Fragment offset = %u bytes", 200 fragoffset); 201 (void) snprintf(get_line(0, 0), get_line_remain(), 202 "Time to live = %d seconds/hops", 203 ip->ip_ttl); 204 (void) snprintf(get_line(0, 0), get_line_remain(), 205 "Protocol = %d (%s)", ip->ip_p, 206 getproto(ip->ip_p)); 207 /* 208 * XXX need to compute checksum and print whether it's correct 209 */ 210 (void) snprintf(get_line(0, 0), get_line_remain(), 211 "Header checksum = %04x", 212 ntohs(ip->ip_sum)); 213 (void) snprintf(get_line(0, 0), get_line_remain(), 214 "Source address = %s, %s", 215 inet_ntoa(ip->ip_src), addrtoname(AF_INET, &ip->ip_src)); 216 (void) snprintf(get_line(0, 0), get_line_remain(), 217 "Destination address = %s, %s", 218 inet_ntoa(ip->ip_dst), addrtoname(AF_INET, &ip->ip_dst)); 219 220 /* Print IP options - if any */ 221 222 print_ipoptions((const uchar_t *)(ip + 1), 223 hdrlen - sizeof (struct ip)); 224 show_space(); 225 } 226 227 /* 228 * If we are in detail mode, and this is not the first fragment of 229 * a fragmented packet, print out a little line stating this. 230 * Otherwise, go to the next protocol layer only if this is not a 231 * fragment, or we are in detail mode and this is the first fragment 232 * of a fragmented packet. 233 */ 234 if (flags & F_DTAIL && fragoffset != 0) { 235 (void) snprintf(get_detail_line(0, 0), MAXLINE, 236 "%s: [%d byte(s) of data, continuation of IP ident=%d]", 237 getproto(ip->ip_p), 238 iplen, 239 ntohs(ip->ip_id)); 240 } else if (!isfrag || (flags & F_DTAIL) && isfrag && fragoffset == 0) { 241 /* go to the next protocol layer */ 242 243 if (fraglen > 0) { 244 switch (ip->ip_p) { 245 case IPPROTO_IP: 246 break; 247 case IPPROTO_ENCAP: 248 (void) interpret_ip(flags, 249 /* LINTED: alignment */ 250 (const struct ip *)data, fraglen); 251 break; 252 case IPPROTO_ICMP: 253 (void) interpret_icmp(flags, 254 /* LINTED: alignment */ 255 (struct icmp *)data, iplen, fraglen); 256 break; 257 case IPPROTO_IGMP: 258 interpret_igmp(flags, data, iplen, fraglen); 259 break; 260 case IPPROTO_GGP: 261 break; 262 case IPPROTO_TCP: 263 (void) interpret_tcp(flags, 264 (struct tcphdr *)data, iplen, fraglen); 265 break; 266 267 case IPPROTO_ESP: 268 (void) interpret_esp(flags, data, iplen, 269 fraglen); 270 break; 271 case IPPROTO_AH: 272 (void) interpret_ah(flags, data, iplen, 273 fraglen); 274 break; 275 276 case IPPROTO_OSPF: 277 interpret_ospf(flags, data, iplen, fraglen); 278 break; 279 280 case IPPROTO_EGP: 281 case IPPROTO_PUP: 282 break; 283 case IPPROTO_UDP: 284 (void) interpret_udp(flags, 285 (struct udphdr *)data, iplen, fraglen); 286 break; 287 288 case IPPROTO_IDP: 289 case IPPROTO_HELLO: 290 case IPPROTO_ND: 291 case IPPROTO_RAW: 292 break; 293 case IPPROTO_IPV6: /* IPV6 encap */ 294 /* LINTED: alignment */ 295 (void) interpret_ipv6(flags, (ip6_t *)data, 296 iplen); 297 break; 298 case IPPROTO_SCTP: 299 (void) interpret_sctp(flags, 300 (struct sctp_hdr *)data, iplen, fraglen); 301 break; 302 case IPPROTO_DCCP: 303 (void) interpret_dccp(flags, 304 (struct dccphdr *)data, iplen, fraglen); 305 break; 306 } 307 } 308 } 309 310 encap_levels--; 311 return (iplen); 312 } 313 314 int 315 interpret_ipv6(int flags, const ip6_t *ip6h, int fraglen) 316 { 317 uint8_t *data; 318 int hdrlen, iplen; 319 int version, flow, class; 320 uchar_t proto; 321 boolean_t isfrag = B_FALSE; 322 uint8_t extmask; 323 /* 324 * The print_srcname and print_dstname strings are the hostname 325 * parts of the verbose IPv6 header output, including the comma 326 * and the space after the litteral address strings. 327 */ 328 char print_srcname[MAXHOSTNAMELEN + 2]; 329 char print_dstname[MAXHOSTNAMELEN + 2]; 330 char src_addrstr[INET6_ADDRSTRLEN]; 331 char dst_addrstr[INET6_ADDRSTRLEN]; 332 333 iplen = ntohs(ip6h->ip6_plen); 334 hdrlen = IPV6_HDR_LEN; 335 fraglen -= hdrlen; 336 if (fraglen < 0) 337 return (fraglen + hdrlen); 338 data = ((uint8_t *)ip6h) + hdrlen; 339 340 proto = ip6h->ip6_nxt; 341 342 src_name = addrtoname(AF_INET6, &ip6h->ip6_src); 343 dst_name = addrtoname(AF_INET6, &ip6h->ip6_dst); 344 345 /* 346 * Use endian-aware masks to extract traffic class and 347 * flowinfo. Also, flowinfo is now 20 bits and class 8 348 * rather than 24 and 4. 349 */ 350 class = ntohl((ip6h->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20); 351 flow = ntohl(ip6h->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL); 352 353 /* 354 * NOTE: the F_SUM and F_DTAIL flags are mutually exclusive, 355 * so the code within the first part of the following if statement 356 * will not affect the detailed printing of the packet. 357 */ 358 if (flags & F_SUM) { 359 (void) snprintf(get_sum_line(), MAXLINE, 360 "IPv6 S=%s D=%s LEN=%d HOPS=%d CLASS=0x%x FLOW=0x%x", 361 src_name, dst_name, iplen, ip6h->ip6_hops, class, flow); 362 } else if (flags & F_DTAIL) { 363 364 (void) inet_ntop(AF_INET6, &ip6h->ip6_src, src_addrstr, 365 INET6_ADDRSTRLEN); 366 (void) inet_ntop(AF_INET6, &ip6h->ip6_dst, dst_addrstr, 367 INET6_ADDRSTRLEN); 368 369 version = ntohl(ip6h->ip6_vcf) >> 28; 370 371 if (strcmp(src_name, src_addrstr) == 0) { 372 print_srcname[0] = '\0'; 373 } else { 374 snprintf(print_srcname, sizeof (print_srcname), 375 ", %s", src_name); 376 } 377 378 if (strcmp(dst_name, dst_addrstr) == 0) { 379 print_dstname[0] = '\0'; 380 } else { 381 snprintf(print_dstname, sizeof (print_dstname), 382 ", %s", dst_name); 383 } 384 385 show_header("IPv6: ", "IPv6 Header", iplen); 386 show_space(); 387 388 (void) snprintf(get_line(0, 0), get_line_remain(), 389 "Version = %d", version); 390 (void) snprintf(get_line(0, 0), get_line_remain(), 391 "Traffic Class = %d", class); 392 (void) snprintf(get_line(0, 0), get_line_remain(), 393 "Flow label = 0x%x", flow); 394 (void) snprintf(get_line(0, 0), get_line_remain(), 395 "Payload length = %d", iplen); 396 (void) snprintf(get_line(0, 0), get_line_remain(), 397 "Next Header = %d (%s)", proto, 398 getproto(proto)); 399 (void) snprintf(get_line(0, 0), get_line_remain(), 400 "Hop Limit = %d", ip6h->ip6_hops); 401 (void) snprintf(get_line(0, 0), get_line_remain(), 402 "Source address = %s%s", src_addrstr, print_srcname); 403 (void) snprintf(get_line(0, 0), get_line_remain(), 404 "Destination address = %s%s", dst_addrstr, print_dstname); 405 406 show_space(); 407 } 408 409 /* 410 * Print IPv6 Extension Headers, or skip them in the summary case. 411 * Set isfrag to true if one of the extension headers encounterred 412 * was a fragment header. 413 */ 414 if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS || 415 proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) { 416 extmask = print_ipv6_extensions(flags, &data, &proto, &iplen, 417 &fraglen); 418 if ((extmask & SNOOP_FRAGMENT) != 0) { 419 isfrag = B_TRUE; 420 } 421 } 422 423 /* 424 * We only want to print upper layer information if this is not 425 * a fragment, or if we're printing in detail. Note that the 426 * proto variable will be set to IPPROTO_NONE if this is a fragment 427 * with a non-zero fragment offset. 428 */ 429 if (!isfrag || flags & F_DTAIL) { 430 /* go to the next protocol layer */ 431 432 switch (proto) { 433 case IPPROTO_IP: 434 break; 435 case IPPROTO_ENCAP: 436 /* LINTED: alignment */ 437 (void) interpret_ip(flags, (const struct ip *)data, 438 fraglen); 439 break; 440 case IPPROTO_ICMPV6: 441 /* LINTED: alignment */ 442 (void) interpret_icmpv6(flags, (icmp6_t *)data, iplen, 443 fraglen); 444 break; 445 case IPPROTO_IGMP: 446 interpret_igmp(flags, data, iplen, fraglen); 447 break; 448 case IPPROTO_GGP: 449 break; 450 case IPPROTO_TCP: 451 (void) interpret_tcp(flags, (struct tcphdr *)data, 452 iplen, fraglen); 453 break; 454 case IPPROTO_ESP: 455 (void) interpret_esp(flags, data, iplen, fraglen); 456 break; 457 case IPPROTO_AH: 458 (void) interpret_ah(flags, data, iplen, fraglen); 459 break; 460 case IPPROTO_EGP: 461 case IPPROTO_PUP: 462 break; 463 case IPPROTO_UDP: 464 (void) interpret_udp(flags, (struct udphdr *)data, 465 iplen, fraglen); 466 break; 467 case IPPROTO_IDP: 468 case IPPROTO_HELLO: 469 case IPPROTO_ND: 470 case IPPROTO_RAW: 471 break; 472 case IPPROTO_IPV6: 473 /* LINTED: alignment */ 474 (void) interpret_ipv6(flags, (const ip6_t *)data, 475 iplen); 476 break; 477 case IPPROTO_SCTP: 478 (void) interpret_sctp(flags, (struct sctp_hdr *)data, 479 iplen, fraglen); 480 break; 481 case IPPROTO_OSPF: 482 interpret_ospf6(flags, data, iplen, fraglen); 483 break; 484 case IPPROTO_DCCP: 485 (void) interpret_dccp(flags, (struct dccphdr *)data, 486 iplen, fraglen); 487 break; 488 } 489 } 490 491 return (iplen); 492 } 493 494 /* 495 * ip_ext: data including the extension header. 496 * iplen: length of the data remaining in the packet. 497 * Returns a mask of IPv6 extension headers it processed. 498 */ 499 uint8_t 500 print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen, 501 int *fraglen) 502 { 503 uint8_t *data_ptr; 504 uchar_t proto = *next; 505 boolean_t is_extension_header; 506 struct ip6_hbh *ipv6ext_hbh; 507 struct ip6_dest *ipv6ext_dest; 508 struct ip6_rthdr *ipv6ext_rthdr; 509 struct ip6_frag *ipv6ext_frag; 510 uint32_t exthdrlen; 511 uint8_t extmask = 0; 512 513 if ((hdr == NULL) || (*hdr == NULL) || (next == NULL) || (iplen == 0)) 514 return (0); 515 516 data_ptr = *hdr; 517 is_extension_header = B_TRUE; 518 while (is_extension_header) { 519 520 /* 521 * There must be at least enough data left to read the 522 * next header and header length fields from the next 523 * header. 524 */ 525 if (*fraglen < 2) { 526 return (extmask); 527 } 528 529 switch (proto) { 530 case IPPROTO_HOPOPTS: 531 ipv6ext_hbh = (struct ip6_hbh *)data_ptr; 532 exthdrlen = 8 + ipv6ext_hbh->ip6h_len * 8; 533 if (*fraglen <= exthdrlen) { 534 return (extmask); 535 } 536 prt_hbh_options(flags, ipv6ext_hbh); 537 extmask |= SNOOP_HOPOPTS; 538 proto = ipv6ext_hbh->ip6h_nxt; 539 break; 540 case IPPROTO_DSTOPTS: 541 ipv6ext_dest = (struct ip6_dest *)data_ptr; 542 exthdrlen = 8 + ipv6ext_dest->ip6d_len * 8; 543 if (*fraglen <= exthdrlen) { 544 return (extmask); 545 } 546 prt_dest_options(flags, ipv6ext_dest); 547 extmask |= SNOOP_DSTOPTS; 548 proto = ipv6ext_dest->ip6d_nxt; 549 break; 550 case IPPROTO_ROUTING: 551 ipv6ext_rthdr = (struct ip6_rthdr *)data_ptr; 552 exthdrlen = 8 + ipv6ext_rthdr->ip6r_len * 8; 553 if (*fraglen <= exthdrlen) { 554 return (extmask); 555 } 556 prt_routing_hdr(flags, ipv6ext_rthdr); 557 extmask |= SNOOP_ROUTING; 558 proto = ipv6ext_rthdr->ip6r_nxt; 559 break; 560 case IPPROTO_FRAGMENT: 561 /* LINTED: alignment */ 562 ipv6ext_frag = (struct ip6_frag *)data_ptr; 563 exthdrlen = sizeof (struct ip6_frag); 564 if (*fraglen <= exthdrlen) { 565 return (extmask); 566 } 567 prt_fragment_hdr(flags, ipv6ext_frag); 568 extmask |= SNOOP_FRAGMENT; 569 /* 570 * If this is not the first fragment, forget about 571 * the rest of the packet, snoop decoding is 572 * stateless. 573 */ 574 if ((ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK) != 0) 575 proto = IPPROTO_NONE; 576 else 577 proto = ipv6ext_frag->ip6f_nxt; 578 break; 579 default: 580 is_extension_header = B_FALSE; 581 break; 582 } 583 584 if (is_extension_header) { 585 *iplen -= exthdrlen; 586 *fraglen -= exthdrlen; 587 data_ptr += exthdrlen; 588 } 589 } 590 591 *next = proto; 592 *hdr = data_ptr; 593 return (extmask); 594 } 595 596 static void 597 print_ipoptions(const uchar_t *opt, int optlen) 598 { 599 int len; 600 int remain; 601 char *line; 602 const char *truncstr; 603 604 if (optlen <= 0) { 605 (void) snprintf(get_line(0, 0), get_line_remain(), 606 "No options"); 607 return; 608 } 609 610 (void) snprintf(get_line(0, 0), get_line_remain(), 611 "Options: (%d bytes)", optlen); 612 613 while (optlen > 0) { 614 line = get_line(0, 0); 615 remain = get_line_remain(); 616 len = opt[1]; 617 truncstr = len > optlen ? "?" : ""; 618 switch (opt[0]) { 619 case IPOPT_EOL: 620 (void) strlcpy(line, " - End of option list", remain); 621 return; 622 case IPOPT_NOP: 623 (void) strlcpy(line, " - No op", remain); 624 len = 1; 625 break; 626 case IPOPT_RR: 627 (void) snprintf(line, remain, 628 " - Record route (%d bytes%s)", len, truncstr); 629 print_route(opt); 630 break; 631 case IPOPT_TS: 632 (void) snprintf(line, remain, 633 " - Time stamp (%d bytes%s)", len, truncstr); 634 break; 635 case IPOPT_SECURITY: 636 (void) snprintf(line, remain, " - RIPSO (%d bytes%s)", 637 len, truncstr); 638 print_ripso(opt); 639 break; 640 case IPOPT_COMSEC: 641 (void) snprintf(line, remain, " - CIPSO (%d bytes%s)", 642 len, truncstr); 643 print_cipso(opt); 644 break; 645 case IPOPT_LSRR: 646 (void) snprintf(line, remain, 647 " - Loose source route (%d bytes%s)", len, 648 truncstr); 649 print_route(opt); 650 break; 651 case IPOPT_SATID: 652 (void) snprintf(line, remain, 653 " - SATNET Stream id (%d bytes%s)", 654 len, truncstr); 655 break; 656 case IPOPT_SSRR: 657 (void) snprintf(line, remain, 658 " - Strict source route, (%d bytes%s)", len, 659 truncstr); 660 print_route(opt); 661 break; 662 default: 663 (void) snprintf(line, remain, 664 " - Option %d (unknown - %d bytes%s) %s", 665 opt[0], len, truncstr, 666 tohex((char *)&opt[2], len - 2)); 667 break; 668 } 669 if (len <= 0) { 670 (void) snprintf(line, remain, 671 " - Incomplete option len %d", len); 672 break; 673 } 674 opt += len; 675 optlen -= len; 676 } 677 } 678 679 static void 680 print_route(const uchar_t *opt) 681 { 682 int len, pointer, remain; 683 struct in_addr addr; 684 char *line; 685 686 len = opt[1]; 687 pointer = opt[2]; 688 689 (void) snprintf(get_line(0, 0), get_line_remain(), 690 " Pointer = %d", pointer); 691 692 pointer -= IPOPT_MINOFF; 693 opt += (IPOPT_OFFSET + 1); 694 len -= (IPOPT_OFFSET + 1); 695 696 while (len > 0) { 697 line = get_line(0, 0); 698 remain = get_line_remain(); 699 memcpy((char *)&addr, opt, sizeof (addr)); 700 if (addr.s_addr == INADDR_ANY) 701 (void) strlcpy(line, " -", remain); 702 else 703 (void) snprintf(line, remain, " %s", 704 addrtoname(AF_INET, &addr)); 705 if (pointer == 0) 706 (void) strlcat(line, " <-- (current)", remain); 707 708 opt += sizeof (addr); 709 len -= sizeof (addr); 710 pointer -= sizeof (addr); 711 } 712 } 713 714 char * 715 getproto(int p) 716 { 717 switch (p) { 718 case IPPROTO_HOPOPTS: return ("IPv6-HopOpts"); 719 case IPPROTO_IPV6: return ("IPv6"); 720 case IPPROTO_ROUTING: return ("IPv6-Route"); 721 case IPPROTO_FRAGMENT: return ("IPv6-Frag"); 722 case IPPROTO_RSVP: return ("RSVP"); 723 case IPPROTO_ENCAP: return ("IP-in-IP"); 724 case IPPROTO_AH: return ("AH"); 725 case IPPROTO_ESP: return ("ESP"); 726 case IPPROTO_ICMP: return ("ICMP"); 727 case IPPROTO_ICMPV6: return ("ICMPv6"); 728 case IPPROTO_DSTOPTS: return ("IPv6-DstOpts"); 729 case IPPROTO_IGMP: return ("IGMP"); 730 case IPPROTO_GGP: return ("GGP"); 731 case IPPROTO_TCP: return ("TCP"); 732 case IPPROTO_EGP: return ("EGP"); 733 case IPPROTO_PUP: return ("PUP"); 734 case IPPROTO_UDP: return ("UDP"); 735 case IPPROTO_IDP: return ("IDP"); 736 case IPPROTO_HELLO: return ("HELLO"); 737 case IPPROTO_ND: return ("ND"); 738 case IPPROTO_EON: return ("EON"); 739 case IPPROTO_RAW: return ("RAW"); 740 case IPPROTO_OSPF: return ("OSPF"); 741 case IPPROTO_DCCP: return ("DCCP"); 742 default: return (""); 743 } 744 } 745 746 static void 747 prt_routing_hdr(int flags, const struct ip6_rthdr *ipv6ext_rthdr) 748 { 749 uint8_t nxt_hdr; 750 uint8_t type; 751 uint32_t len; 752 uint8_t segleft; 753 uint32_t numaddrs; 754 int i; 755 struct ip6_rthdr0 *ipv6ext_rthdr0; 756 struct in6_addr *addrs; 757 char addr[INET6_ADDRSTRLEN]; 758 759 /* in summary mode, we don't do anything. */ 760 if (flags & F_SUM) { 761 return; 762 } 763 764 nxt_hdr = ipv6ext_rthdr->ip6r_nxt; 765 type = ipv6ext_rthdr->ip6r_type; 766 len = 8 * (ipv6ext_rthdr->ip6r_len + 1); 767 segleft = ipv6ext_rthdr->ip6r_segleft; 768 769 show_header("IPv6-Route: ", "IPv6 Routing Header", 0); 770 show_space(); 771 772 (void) snprintf(get_line(0, 0), get_line_remain(), 773 "Next header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 774 (void) snprintf(get_line(0, 0), get_line_remain(), 775 "Header length = %d", len); 776 (void) snprintf(get_line(0, 0), get_line_remain(), 777 "Routing type = %d", type); 778 (void) snprintf(get_line(0, 0), get_line_remain(), 779 "Segments left = %d", segleft); 780 781 if (type == IPV6_RTHDR_TYPE_0) { 782 /* 783 * XXX This loop will print all addresses in the routing header, 784 * XXX not just the segments left. 785 * XXX (The header length field is twice the number of 786 * XXX addresses) 787 * XXX At some future time, we may want to change this 788 * XXX to differentiate between the hops yet to do 789 * XXX and the hops already taken. 790 */ 791 /* LINTED: alignment */ 792 ipv6ext_rthdr0 = (struct ip6_rthdr0 *)ipv6ext_rthdr; 793 numaddrs = ipv6ext_rthdr0->ip6r0_len / 2; 794 addrs = (struct in6_addr *)(ipv6ext_rthdr0 + 1); 795 for (i = 0; i < numaddrs; i++) { 796 (void) inet_ntop(AF_INET6, &addrs[i], addr, 797 INET6_ADDRSTRLEN); 798 (void) snprintf(get_line(0, 0), get_line_remain(), 799 "address[%d]=%s", i, addr); 800 } 801 } 802 803 show_space(); 804 } 805 806 static void 807 prt_fragment_hdr(int flags, const struct ip6_frag *ipv6ext_frag) 808 { 809 boolean_t morefrag; 810 uint16_t fragoffset; 811 uint8_t nxt_hdr; 812 uint32_t fragident; 813 814 /* extract the various fields from the fragment header */ 815 nxt_hdr = ipv6ext_frag->ip6f_nxt; 816 morefrag = (ipv6ext_frag->ip6f_offlg & IP6F_MORE_FRAG) == 0 817 ? B_FALSE : B_TRUE; 818 fragoffset = ntohs(ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK); 819 fragident = ntohl(ipv6ext_frag->ip6f_ident); 820 821 if (flags & F_SUM) { 822 (void) snprintf(get_sum_line(), MAXLINE, 823 "IPv6 fragment ID=%u Offset=%-4d MF=%d", 824 fragident, 825 fragoffset, 826 morefrag); 827 } else { /* F_DTAIL */ 828 show_header("IPv6-Frag: ", "IPv6 Fragment Header", 0); 829 show_space(); 830 831 (void) snprintf(get_line(0, 0), get_line_remain(), 832 "Next Header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 833 (void) snprintf(get_line(0, 0), get_line_remain(), 834 "Fragment Offset = %d", fragoffset); 835 (void) snprintf(get_line(0, 0), get_line_remain(), 836 "More Fragments Flag = %s", morefrag ? "true" : "false"); 837 (void) snprintf(get_line(0, 0), get_line_remain(), 838 "Identification = %u", fragident); 839 840 show_space(); 841 } 842 } 843 844 static void 845 print_ip6opt_ls(const uchar_t *data, unsigned int op_len) 846 { 847 uint32_t doi; 848 uint8_t sotype, solen; 849 uint16_t value, value2; 850 char *cp; 851 int remlen; 852 boolean_t printed; 853 854 (void) snprintf(get_line(0, 0), get_line_remain(), 855 "Labeled Security Option len = %u bytes%s", op_len, 856 op_len < sizeof (uint32_t) || (op_len & 1) != 0 ? "?" : ""); 857 if (op_len < sizeof (uint32_t)) 858 return; 859 GETINT32(doi, data); 860 (void) snprintf(get_line(0, 0), get_line_remain(), 861 " DOI = %d (%s)", doi, doi == IP6LS_DOI_V4 ? "IPv4" : "???"); 862 op_len -= sizeof (uint32_t); 863 while (op_len > 0) { 864 GETINT8(sotype, data); 865 if (op_len < 2) { 866 (void) snprintf(get_line(0, 0), get_line_remain(), 867 " truncated %u suboption (no len)", sotype); 868 break; 869 } 870 GETINT8(solen, data); 871 if (solen < 2 || solen > op_len) { 872 (void) snprintf(get_line(0, 0), get_line_remain(), 873 " bad %u suboption (len 2 <= %u <= %u)", 874 sotype, solen, op_len); 875 if (solen < 2) 876 solen = 2; 877 if (solen > op_len) 878 solen = op_len; 879 } 880 op_len -= solen; 881 solen -= 2; 882 cp = get_line(0, 0); 883 remlen = get_line_remain(); 884 (void) strlcpy(cp, " ", remlen); 885 cp += 4; 886 remlen -= 4; 887 printed = B_TRUE; 888 switch (sotype) { 889 case IP6LS_TT_LEVEL: 890 if (solen != 2) { 891 printed = B_FALSE; 892 break; 893 } 894 GETINT16(value, data); 895 (void) snprintf(cp, remlen, "Level %u", value); 896 solen = 0; 897 break; 898 case IP6LS_TT_VECTOR: 899 (void) strlcpy(cp, "Bit-Vector: ", remlen); 900 remlen -= strlen(cp); 901 cp += strlen(cp); 902 while (solen > 1) { 903 GETINT16(value, data); 904 solen -= 2; 905 (void) snprintf(cp, remlen, "%04x", value); 906 remlen -= strlen(cp); 907 cp += strlen(cp); 908 } 909 break; 910 case IP6LS_TT_ENUM: 911 (void) strlcpy(cp, "Enumeration:", remlen); 912 remlen -= strlen(cp); 913 cp += strlen(cp); 914 while (solen > 1) { 915 GETINT16(value, data); 916 solen -= 2; 917 (void) snprintf(cp, remlen, " %u", value); 918 remlen -= strlen(cp); 919 cp += strlen(cp); 920 } 921 break; 922 case IP6LS_TT_RANGES: 923 (void) strlcpy(cp, "Ranges:", remlen); 924 remlen -= strlen(cp); 925 cp += strlen(cp); 926 while (solen > 3) { 927 GETINT16(value, data); 928 GETINT16(value2, data); 929 solen -= 4; 930 (void) snprintf(cp, remlen, " %u-%u", value, 931 value2); 932 remlen -= strlen(cp); 933 cp += strlen(cp); 934 } 935 break; 936 case IP6LS_TT_V4: 937 (void) strlcpy(cp, "IPv4 Option", remlen); 938 print_ipoptions(data, solen); 939 solen = 0; 940 break; 941 case IP6LS_TT_DEST: 942 (void) snprintf(cp, remlen, 943 "Destination-Only Data length %u", solen); 944 solen = 0; 945 break; 946 default: 947 (void) snprintf(cp, remlen, 948 " unknown %u suboption (len %u)", sotype, solen); 949 solen = 0; 950 break; 951 } 952 if (solen != 0) { 953 if (printed) { 954 cp = get_line(0, 0); 955 remlen = get_line_remain(); 956 } 957 (void) snprintf(cp, remlen, 958 " malformed %u suboption (remaining %u)", 959 sotype, solen); 960 data += solen; 961 } 962 } 963 } 964 965 static void 966 prt_hbh_options(int flags, const struct ip6_hbh *ipv6ext_hbh) 967 { 968 const uint8_t *data, *ndata; 969 uint32_t len; 970 uint8_t op_type; 971 uint8_t op_len; 972 uint8_t nxt_hdr; 973 974 /* in summary mode, we don't do anything. */ 975 if (flags & F_SUM) { 976 return; 977 } 978 979 show_header("IPv6-HopOpts: ", "IPv6 Hop-by-Hop Options Header", 0); 980 show_space(); 981 982 /* 983 * Store the lengh of this ext hdr in bytes. The caller has 984 * ensured that there is at least len bytes of data left. 985 */ 986 len = ipv6ext_hbh->ip6h_len * 8 + 8; 987 988 ndata = (const uint8_t *)ipv6ext_hbh + 2; 989 len -= 2; 990 991 nxt_hdr = ipv6ext_hbh->ip6h_nxt; 992 (void) snprintf(get_line(0, 0), get_line_remain(), 993 "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr)); 994 995 while (len > 0) { 996 data = ndata; 997 GETINT8(op_type, data); 998 /* This is the only one-octet IPv6 option */ 999 if (op_type == IP6OPT_PAD1) { 1000 (void) snprintf(get_line(0, 0), get_line_remain(), 1001 "pad1 option "); 1002 len--; 1003 ndata = data; 1004 continue; 1005 } 1006 GETINT8(op_len, data); 1007 if (len < 2 || op_len + 2 > len) { 1008 (void) snprintf(get_line(0, 0), get_line_remain(), 1009 "Error: option %u truncated (%u + 2 > %u)", 1010 op_type, op_len, len); 1011 op_len = len - 2; 1012 /* 1013 * Continue processing the malformed option so that we 1014 * can display as much as possible. 1015 */ 1016 } 1017 1018 /* advance pointers to the next option */ 1019 len -= op_len + 2; 1020 ndata = data + op_len; 1021 1022 /* process this option */ 1023 switch (op_type) { 1024 case IP6OPT_PADN: 1025 (void) snprintf(get_line(0, 0), get_line_remain(), 1026 "padN option len = %u", op_len); 1027 break; 1028 case IP6OPT_JUMBO: { 1029 uint32_t payload_len; 1030 1031 (void) snprintf(get_line(0, 0), get_line_remain(), 1032 "Jumbo Payload Option len = %u bytes%s", op_len, 1033 op_len == sizeof (uint32_t) ? "" : "?"); 1034 if (op_len == sizeof (uint32_t)) { 1035 GETINT32(payload_len, data); 1036 (void) snprintf(get_line(0, 0), 1037 get_line_remain(), 1038 "Jumbo Payload Length = %u bytes", 1039 payload_len); 1040 } 1041 break; 1042 } 1043 case IP6OPT_ROUTER_ALERT: { 1044 uint16_t value; 1045 const char *label[] = {"MLD", "RSVP", "AN"}; 1046 1047 (void) snprintf(get_line(0, 0), get_line_remain(), 1048 "Router Alert Option len = %u bytes%s", op_len, 1049 op_len == sizeof (uint16_t) ? "" : "?"); 1050 if (op_len == sizeof (uint16_t)) { 1051 GETINT16(value, data); 1052 (void) snprintf(get_line(0, 0), 1053 get_line_remain(), 1054 "Alert Type = %d (%s)", value, 1055 value < sizeof (label) / sizeof (label[0]) ? 1056 label[value] : "???"); 1057 } 1058 break; 1059 } 1060 case IP6OPT_LS: 1061 print_ip6opt_ls(data, op_len); 1062 break; 1063 default: 1064 (void) snprintf(get_line(0, 0), get_line_remain(), 1065 "Option type = %u, len = %u", op_type, op_len); 1066 break; 1067 } 1068 } 1069 1070 show_space(); 1071 } 1072 1073 static void 1074 prt_dest_options(int flags, const struct ip6_dest *ipv6ext_dest) 1075 { 1076 const uint8_t *data, *ndata; 1077 uint32_t len; 1078 uint8_t op_type; 1079 uint32_t op_len; 1080 uint8_t nxt_hdr; 1081 uint8_t value; 1082 1083 /* in summary mode, we don't do anything. */ 1084 if (flags & F_SUM) { 1085 return; 1086 } 1087 1088 show_header("IPv6-DstOpts: ", "IPv6 Destination Options Header", 0); 1089 show_space(); 1090 1091 /* 1092 * Store the length of this ext hdr in bytes. The caller has 1093 * ensured that there is at least len bytes of data left. 1094 */ 1095 len = ipv6ext_dest->ip6d_len * 8 + 8; 1096 1097 ndata = (const uint8_t *)ipv6ext_dest + 2; /* skip hdr/len */ 1098 len -= 2; 1099 1100 nxt_hdr = ipv6ext_dest->ip6d_nxt; 1101 (void) snprintf(get_line(0, 0), get_line_remain(), 1102 "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr)); 1103 1104 while (len > 0) { 1105 data = ndata; 1106 GETINT8(op_type, data); 1107 if (op_type == IP6OPT_PAD1) { 1108 (void) snprintf(get_line(0, 0), get_line_remain(), 1109 "pad1 option "); 1110 len--; 1111 ndata = data; 1112 continue; 1113 } 1114 GETINT8(op_len, data); 1115 if (len < 2 || op_len + 2 > len) { 1116 (void) snprintf(get_line(0, 0), get_line_remain(), 1117 "Error: option %u truncated (%u + 2 > %u)", 1118 op_type, op_len, len); 1119 op_len = len - 2; 1120 /* 1121 * Continue processing the malformed option so that we 1122 * can display as much as possible. 1123 */ 1124 } 1125 1126 /* advance pointers to the next option */ 1127 len -= op_len + 2; 1128 ndata = data + op_len; 1129 1130 /* process this option */ 1131 switch (op_type) { 1132 case IP6OPT_PADN: 1133 (void) snprintf(get_line(0, 0), get_line_remain(), 1134 "padN option len = %u", op_len); 1135 break; 1136 case IP6OPT_TUNNEL_LIMIT: 1137 GETINT8(value, data); 1138 (void) snprintf(get_line(0, 0), get_line_remain(), 1139 "tunnel encapsulation limit len = %d, value = %d", 1140 op_len, value); 1141 break; 1142 case IP6OPT_LS: 1143 print_ip6opt_ls(data, op_len); 1144 break; 1145 default: 1146 (void) snprintf(get_line(0, 0), get_line_remain(), 1147 "Option type = %u, len = %u", op_type, op_len); 1148 break; 1149 } 1150 } 1151 1152 show_space(); 1153 } 1154 1155 #define ALABEL_MAXLEN 256 1156 1157 static char ascii_label[ALABEL_MAXLEN]; 1158 static char *plabel = ascii_label; 1159 1160 struct snoop_pair { 1161 int val; 1162 const char *name; 1163 }; 1164 1165 static struct snoop_pair ripso_class_tbl[] = { 1166 TSOL_CL_TOP_SECRET, "TOP SECRET", 1167 TSOL_CL_SECRET, "SECRET", 1168 TSOL_CL_CONFIDENTIAL, "CONFIDENTIAL", 1169 TSOL_CL_UNCLASSIFIED, "UNCLASSIFIED", 1170 -1, NULL 1171 }; 1172 1173 static struct snoop_pair ripso_prot_tbl[] = { 1174 TSOL_PA_GENSER, "GENSER", 1175 TSOL_PA_SIOP_ESI, "SIOP-ESI", 1176 TSOL_PA_SCI, "SCI", 1177 TSOL_PA_NSA, "NSA", 1178 TSOL_PA_DOE, "DOE", 1179 0x04, "UNASSIGNED", 1180 0x02, "UNASSIGNED", 1181 -1, NULL 1182 }; 1183 1184 static struct snoop_pair * 1185 get_pair_byval(struct snoop_pair pairlist[], int val) 1186 { 1187 int i; 1188 1189 for (i = 0; pairlist[i].name != NULL; i++) 1190 if (pairlist[i].val == val) 1191 return (&pairlist[i]); 1192 return (NULL); 1193 } 1194 1195 static void 1196 print_ripso(const uchar_t *opt) 1197 { 1198 struct snoop_pair *ripso_class; 1199 int i, index, prot_len; 1200 boolean_t first_prot; 1201 char line[100], *ptr; 1202 1203 prot_len = opt[1] - 3; 1204 if (prot_len < 0) 1205 return; 1206 1207 show_header("RIPSO: ", "Revised IP Security Option", 0); 1208 show_space(); 1209 1210 (void) snprintf(get_line(0, 0), get_line_remain(), 1211 "Type = Basic Security Option (%d), Length = %d", opt[0], opt[1]); 1212 1213 /* 1214 * Display Classification Level 1215 */ 1216 ripso_class = get_pair_byval(ripso_class_tbl, (int)opt[2]); 1217 if (ripso_class != NULL) 1218 (void) snprintf(get_line(0, 0), get_line_remain(), 1219 "Classification = Unknown (0x%02x)", opt[2]); 1220 else 1221 (void) snprintf(get_line(0, 0), get_line_remain(), 1222 "Classification = %s (0x%02x)", 1223 ripso_class->name, ripso_class->val); 1224 1225 /* 1226 * Display Protection Authority Flags 1227 */ 1228 (void) snprintf(line, sizeof (line), "Protection Authority = "); 1229 ptr = line; 1230 first_prot = B_TRUE; 1231 for (i = 0; i < prot_len; i++) { 1232 index = 0; 1233 while (ripso_prot_tbl[index].name != NULL) { 1234 if (opt[3 + i] & ripso_prot_tbl[index].val) { 1235 ptr = strchr(ptr, 0); 1236 if (!first_prot) { 1237 (void) strlcpy(ptr, ", ", 1238 sizeof (line) - (ptr - line)); 1239 ptr = strchr(ptr, 0); 1240 } 1241 (void) snprintf(ptr, 1242 sizeof (line) - (ptr - line), 1243 "%s (0x%02x)", 1244 ripso_prot_tbl[index].name, 1245 ripso_prot_tbl[index].val); 1246 } 1247 index++; 1248 } 1249 if ((opt[3 + i] & 1) == 0) 1250 break; 1251 } 1252 if (!first_prot) 1253 (void) snprintf(get_line(0, 0), get_line_remain(), "%s", line); 1254 else 1255 (void) snprintf(get_line(0, 0), get_line_remain(), "%sNone", 1256 line); 1257 } 1258 1259 #define CIPSO_GENERIC_ARRAY_LEN 200 1260 1261 /* 1262 * Return 1 if CIPSO SL and Categories are all 1's; 0 otherwise. 1263 * 1264 * Note: opt starts with "Tag Type": 1265 * 1266 * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)| 1267 * 1268 */ 1269 static boolean_t 1270 cipso_high(const uchar_t *opt) 1271 { 1272 int i; 1273 1274 if (((int)opt[1] + 6) < IP_MAX_OPT_LENGTH) 1275 return (B_FALSE); 1276 for (i = 0; i < ((int)opt[1] - 3); i++) 1277 if (opt[3 + i] != 0xff) 1278 return (B_FALSE); 1279 return (B_TRUE); 1280 } 1281 1282 /* 1283 * Converts CIPSO label to SL. 1284 * 1285 * Note: opt starts with "Tag Type": 1286 * 1287 * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)| 1288 * 1289 */ 1290 static void 1291 cipso2sl(const uchar_t *opt, bslabel_t *sl, int *high) 1292 { 1293 int i, taglen; 1294 uchar_t *q = (uchar_t *)&((_bslabel_impl_t *)sl)->compartments; 1295 1296 *high = 0; 1297 taglen = opt[1]; 1298 memset((caddr_t)sl, 0, sizeof (bslabel_t)); 1299 1300 if (cipso_high(opt)) { 1301 BSLHIGH(sl); 1302 *high = 1; 1303 } else { 1304 LCLASS_SET((_bslabel_impl_t *)sl, opt[3]); 1305 for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) 1306 q[i] = opt[TSOL_TT1_MIN_LENGTH + i]; 1307 } 1308 SETBLTYPE(sl, SUN_SL_ID); 1309 } 1310 1311 static int 1312 interpret_cipso_tagtype1(const uchar_t *opt) 1313 { 1314 int i, taglen, ishigh; 1315 bslabel_t sl; 1316 char line[CIPSO_GENERIC_ARRAY_LEN], *ptr; 1317 1318 taglen = opt[1]; 1319 if (taglen < TSOL_TT1_MIN_LENGTH || 1320 taglen > TSOL_TT1_MAX_LENGTH) 1321 return (taglen); 1322 1323 (void) snprintf(get_line(0, 0), get_line_remain(), 1324 "Tag Type = %d, Tag Length = %d", opt[0], opt[1]); 1325 (void) snprintf(get_line(0, 0), get_line_remain(), 1326 "Sensitivity Level = 0x%02x", opt[3]); 1327 ptr = line; 1328 for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) { 1329 (void) snprintf(ptr, sizeof (line) - (ptr - line), "%02x", 1330 opt[TSOL_TT1_MIN_LENGTH + i]); 1331 ptr = strchr(ptr, 0); 1332 } 1333 if (i != 0) { 1334 (void) snprintf(get_line(0, 0), get_line_remain(), 1335 "Categories = "); 1336 (void) snprintf(get_line(0, 0), get_line_remain(), "\t%s", 1337 line); 1338 } else { 1339 (void) snprintf(get_line(0, 0), get_line_remain(), 1340 "Categories = None"); 1341 } 1342 cipso2sl(opt, &sl, &ishigh); 1343 if (is_system_labeled()) { 1344 if (bsltos(&sl, &plabel, ALABEL_MAXLEN, 1345 LONG_CLASSIFICATION|LONG_WORDS|VIEW_INTERNAL) < 0) { 1346 (void) snprintf(get_line(0, 0), get_line_remain(), 1347 "The Sensitivity Level and Categories can't be " 1348 "mapped to a valid SL"); 1349 } else { 1350 (void) snprintf(get_line(0, 0), get_line_remain(), 1351 "The Sensitivity Level and Categories are mapped " 1352 "to the SL:"); 1353 (void) snprintf(get_line(0, 0), get_line_remain(), 1354 "\t%s", ascii_label); 1355 } 1356 } 1357 return (taglen); 1358 } 1359 1360 /* 1361 * The following struct definition #define's are copied from TS1.x. They are 1362 * not used here (except TTYPE_3_MAX_TOKENS), but included as a reference for 1363 * the tag type 3 packet format. 1364 */ 1365 #define TTYPE_3_MAX_TOKENS 7 1366 1367 /* 1368 * Display CIPSO tag type 3 which is defined by MAXSIX. 1369 */ 1370 static int 1371 interpret_cipso_tagtype3(const uchar_t *opt) 1372 { 1373 uchar_t tagtype; 1374 int index, numtokens, taglen; 1375 uint16_t mask; 1376 uint32_t token; 1377 static const char *name[] = { 1378 "SL", 1379 "NCAV", 1380 "INTEG", 1381 "SID", 1382 "undefined", 1383 "undefined", 1384 "IL", 1385 "PRIVS", 1386 "LUID", 1387 "PID", 1388 "IDS", 1389 "ACL" 1390 }; 1391 1392 tagtype = *opt++; 1393 (void) memcpy(&mask, opt + 3, sizeof (mask)); 1394 (void) snprintf(get_line(0, 0), get_line_remain(), 1395 "Tag Type = %d (MAXSIX)", tagtype); 1396 (void) snprintf(get_line(0, 0), get_line_remain(), 1397 "Generation = 0x%02x%02x%02x, Mask = 0x%04x", opt[0], opt[1], 1398 opt[2], mask); 1399 opt += 3 + sizeof (mask); 1400 1401 /* 1402 * Display tokens 1403 */ 1404 numtokens = 0; 1405 index = 0; 1406 while (mask != 0 && numtokens < TTYPE_3_MAX_TOKENS) { 1407 if (mask & 0x0001) { 1408 (void) memcpy(&token, opt, sizeof (token)); 1409 opt += sizeof (token); 1410 (void) snprintf(get_line(0, 0), get_line_remain(), 1411 "Attribute = %s, Token = 0x%08x", 1412 index < sizeof (name) / sizeof (*name) ? 1413 name[index] : "unknown", token); 1414 numtokens++; 1415 } 1416 mask = mask >> 1; 1417 index++; 1418 } 1419 1420 taglen = 6 + numtokens * 4; 1421 return (taglen); 1422 } 1423 1424 static void 1425 print_cipso(const uchar_t *opt) 1426 { 1427 int optlen, taglen, tagnum; 1428 uint32_t doi; 1429 char line[CIPSO_GENERIC_ARRAY_LEN]; 1430 char *oldnest; 1431 1432 optlen = opt[1]; 1433 if (optlen < TSOL_CIPSO_MIN_LENGTH || optlen > TSOL_CIPSO_MAX_LENGTH) 1434 return; 1435 1436 oldnest = prot_nest_prefix; 1437 prot_nest_prefix = prot_prefix; 1438 show_header("CIPSO: ", "Common IP Security Option", 0); 1439 show_space(); 1440 1441 /* 1442 * Display CIPSO Header 1443 */ 1444 (void) snprintf(get_line(0, 0), get_line_remain(), 1445 "Type = CIPSO (%d), Length = %d", opt[0], opt[1]); 1446 (void) memcpy(&doi, opt + 2, sizeof (doi)); 1447 (void) snprintf(get_line(0, 0), get_line_remain(), 1448 "Domain of Interpretation = %u", (unsigned)ntohl(doi)); 1449 1450 if (opt[1] == TSOL_CIPSO_MIN_LENGTH) { /* no tags */ 1451 show_space(); 1452 prot_prefix = prot_nest_prefix; 1453 prot_nest_prefix = oldnest; 1454 return; 1455 } 1456 optlen -= TSOL_CIPSO_MIN_LENGTH; 1457 opt += TSOL_CIPSO_MIN_LENGTH; 1458 1459 /* 1460 * Display Each Tag 1461 */ 1462 tagnum = 1; 1463 while (optlen >= TSOL_TT1_MIN_LENGTH) { 1464 (void) snprintf(line, sizeof (line), "Tag# %d", tagnum); 1465 show_header("CIPSO: ", line, 0); 1466 /* 1467 * We handle tag type 1 and 3 only. Note, tag type 3 1468 * is MAXSIX defined. 1469 */ 1470 switch (opt[0]) { 1471 case 1: 1472 taglen = interpret_cipso_tagtype1(opt); 1473 break; 1474 case 3: 1475 taglen = interpret_cipso_tagtype3(opt); 1476 break; 1477 default: 1478 (void) snprintf(get_line(0, 0), get_line_remain(), 1479 "Unknown Tag Type %d", opt[0]); 1480 show_space(); 1481 prot_prefix = prot_nest_prefix; 1482 prot_nest_prefix = oldnest; 1483 return; 1484 } 1485 1486 /* 1487 * Move to the next tag 1488 */ 1489 if (taglen <= 0) 1490 break; 1491 optlen -= taglen; 1492 opt += taglen; 1493 tagnum++; 1494 } 1495 show_space(); 1496 prot_prefix = prot_nest_prefix; 1497 prot_nest_prefix = oldnest; 1498 }