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