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 * Use endian-aware masks to extract traffic class and 344 * flowinfo. Also, flowinfo is now 20 bits and class 8 345 * rather than 24 and 4. 346 */ 347 class = ntohl((ip6h->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20); 348 flow = ntohl(ip6h->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL); 349 350 /* 351 * NOTE: the F_SUM and F_DTAIL flags are mutually exclusive, 352 * so the code within the first part of the following if statement 353 * will not affect the detailed printing of the packet. 354 */ 355 if (flags & F_SUM) { 356 (void) snprintf(get_sum_line(), MAXLINE, 357 "IPv6 S=%s D=%s LEN=%d HOPS=%d CLASS=0x%x FLOW=0x%x", 358 src_name, dst_name, iplen, ip6h->ip6_hops, class, flow); 359 } else if (flags & F_DTAIL) { 360 361 (void) inet_ntop(AF_INET6, &ip6h->ip6_src, src_addrstr, 362 INET6_ADDRSTRLEN); 363 (void) inet_ntop(AF_INET6, &ip6h->ip6_dst, dst_addrstr, 364 INET6_ADDRSTRLEN); 365 366 version = ntohl(ip6h->ip6_vcf) >> 28; 367 368 if (strcmp(src_name, src_addrstr) == 0) { 369 print_srcname[0] = '\0'; 370 } else { 371 snprintf(print_srcname, sizeof (print_srcname), 372 ", %s", src_name); 373 } 374 375 if (strcmp(dst_name, dst_addrstr) == 0) { 376 print_dstname[0] = '\0'; 377 } else { 378 snprintf(print_dstname, sizeof (print_dstname), 379 ", %s", dst_name); 380 } 381 382 show_header("IPv6: ", "IPv6 Header", iplen); 383 show_space(); 384 385 (void) snprintf(get_line(0, 0), get_line_remain(), 386 "Version = %d", version); 387 (void) snprintf(get_line(0, 0), get_line_remain(), 388 "Traffic Class = %d", class); 389 (void) snprintf(get_line(0, 0), get_line_remain(), 390 "Flow label = 0x%x", flow); 391 (void) snprintf(get_line(0, 0), get_line_remain(), 392 "Payload length = %d", iplen); 393 (void) snprintf(get_line(0, 0), get_line_remain(), 394 "Next Header = %d (%s)", proto, 395 getproto(proto)); 396 (void) snprintf(get_line(0, 0), get_line_remain(), 397 "Hop Limit = %d", ip6h->ip6_hops); 398 (void) snprintf(get_line(0, 0), get_line_remain(), 399 "Source address = %s%s", src_addrstr, print_srcname); 400 (void) snprintf(get_line(0, 0), get_line_remain(), 401 "Destination address = %s%s", dst_addrstr, print_dstname); 402 403 show_space(); 404 } 405 406 /* 407 * Print IPv6 Extension Headers, or skip them in the summary case. 408 * Set isfrag to true if one of the extension headers encounterred 409 * was a fragment header. 410 */ 411 if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS || 412 proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) { 413 extmask = print_ipv6_extensions(flags, &data, &proto, &iplen, 414 &fraglen); 415 if ((extmask & SNOOP_FRAGMENT) != 0) { 416 isfrag = B_TRUE; 417 } 418 } 419 420 /* 421 * We only want to print upper layer information if this is not 422 * a fragment, or if we're printing in detail. Note that the 423 * proto variable will be set to IPPROTO_NONE if this is a fragment 424 * with a non-zero fragment offset. 425 */ 426 if (!isfrag || flags & F_DTAIL) { 427 /* go to the next protocol layer */ 428 429 switch (proto) { 430 case IPPROTO_IP: 431 break; 432 case IPPROTO_ENCAP: 433 /* LINTED: alignment */ 434 (void) interpret_ip(flags, (const struct ip *)data, 435 fraglen); 436 break; 437 case IPPROTO_ICMPV6: 438 /* LINTED: alignment */ 439 (void) interpret_icmpv6(flags, (icmp6_t *)data, iplen, 440 fraglen); 441 break; 442 case IPPROTO_IGMP: 443 interpret_igmp(flags, data, iplen, fraglen); 444 break; 445 case IPPROTO_GGP: 446 break; 447 case IPPROTO_TCP: 448 (void) interpret_tcp(flags, (struct tcphdr *)data, 449 iplen, fraglen); 450 break; 451 case IPPROTO_ESP: 452 (void) interpret_esp(flags, data, iplen, fraglen); 453 break; 454 case IPPROTO_AH: 455 (void) interpret_ah(flags, data, iplen, fraglen); 456 break; 457 case IPPROTO_EGP: 458 case IPPROTO_PUP: 459 break; 460 case IPPROTO_UDP: 461 (void) interpret_udp(flags, (struct udphdr *)data, 462 iplen, fraglen); 463 break; 464 case IPPROTO_IDP: 465 case IPPROTO_HELLO: 466 case IPPROTO_ND: 467 case IPPROTO_RAW: 468 break; 469 case IPPROTO_IPV6: 470 /* LINTED: alignment */ 471 (void) interpret_ipv6(flags, (const ip6_t *)data, 472 iplen); 473 break; 474 case IPPROTO_SCTP: 475 (void) interpret_sctp(flags, (struct sctp_hdr *)data, 476 iplen, fraglen); 477 break; 478 case IPPROTO_OSPF: 479 interpret_ospf6(flags, data, iplen, fraglen); 480 break; 481 } 482 } 483 484 return (iplen); 485 } 486 487 /* 488 * ip_ext: data including the extension header. 489 * iplen: length of the data remaining in the packet. 490 * Returns a mask of IPv6 extension headers it processed. 491 */ 492 uint8_t 493 print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen, 494 int *fraglen) 495 { 496 uint8_t *data_ptr; 497 uchar_t proto = *next; 498 boolean_t is_extension_header; 499 struct ip6_hbh *ipv6ext_hbh; 500 struct ip6_dest *ipv6ext_dest; 501 struct ip6_rthdr *ipv6ext_rthdr; 502 struct ip6_frag *ipv6ext_frag; 503 uint32_t exthdrlen; 504 uint8_t extmask = 0; 505 506 if ((hdr == NULL) || (*hdr == NULL) || (next == NULL) || (iplen == 0)) 507 return (0); 508 509 data_ptr = *hdr; 510 is_extension_header = B_TRUE; 511 while (is_extension_header) { 512 513 /* 514 * There must be at least enough data left to read the 515 * next header and header length fields from the next 516 * header. 517 */ 518 if (*fraglen < 2) { 519 return (extmask); 520 } 521 522 switch (proto) { 523 case IPPROTO_HOPOPTS: 524 ipv6ext_hbh = (struct ip6_hbh *)data_ptr; 525 exthdrlen = 8 + ipv6ext_hbh->ip6h_len * 8; 526 if (*fraglen <= exthdrlen) { 527 return (extmask); 528 } 529 prt_hbh_options(flags, ipv6ext_hbh); 530 extmask |= SNOOP_HOPOPTS; 531 proto = ipv6ext_hbh->ip6h_nxt; 532 break; 533 case IPPROTO_DSTOPTS: 534 ipv6ext_dest = (struct ip6_dest *)data_ptr; 535 exthdrlen = 8 + ipv6ext_dest->ip6d_len * 8; 536 if (*fraglen <= exthdrlen) { 537 return (extmask); 538 } 539 prt_dest_options(flags, ipv6ext_dest); 540 extmask |= SNOOP_DSTOPTS; 541 proto = ipv6ext_dest->ip6d_nxt; 542 break; 543 case IPPROTO_ROUTING: 544 ipv6ext_rthdr = (struct ip6_rthdr *)data_ptr; 545 exthdrlen = 8 + ipv6ext_rthdr->ip6r_len * 8; 546 if (*fraglen <= exthdrlen) { 547 return (extmask); 548 } 549 prt_routing_hdr(flags, ipv6ext_rthdr); 550 extmask |= SNOOP_ROUTING; 551 proto = ipv6ext_rthdr->ip6r_nxt; 552 break; 553 case IPPROTO_FRAGMENT: 554 /* LINTED: alignment */ 555 ipv6ext_frag = (struct ip6_frag *)data_ptr; 556 exthdrlen = sizeof (struct ip6_frag); 557 if (*fraglen <= exthdrlen) { 558 return (extmask); 559 } 560 prt_fragment_hdr(flags, ipv6ext_frag); 561 extmask |= SNOOP_FRAGMENT; 562 /* 563 * If this is not the first fragment, forget about 564 * the rest of the packet, snoop decoding is 565 * stateless. 566 */ 567 if ((ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK) != 0) 568 proto = IPPROTO_NONE; 569 else 570 proto = ipv6ext_frag->ip6f_nxt; 571 break; 572 default: 573 is_extension_header = B_FALSE; 574 break; 575 } 576 577 if (is_extension_header) { 578 *iplen -= exthdrlen; 579 *fraglen -= exthdrlen; 580 data_ptr += exthdrlen; 581 } 582 } 583 584 *next = proto; 585 *hdr = data_ptr; 586 return (extmask); 587 } 588 589 static void 590 print_ipoptions(const uchar_t *opt, int optlen) 591 { 592 int len; 593 int remain; 594 char *line; 595 const char *truncstr; 596 597 if (optlen <= 0) { 598 (void) snprintf(get_line(0, 0), get_line_remain(), 599 "No options"); 600 return; 601 } 602 603 (void) snprintf(get_line(0, 0), get_line_remain(), 604 "Options: (%d bytes)", optlen); 605 606 while (optlen > 0) { 607 line = get_line(0, 0); 608 remain = get_line_remain(); 609 len = opt[1]; 610 truncstr = len > optlen ? "?" : ""; 611 switch (opt[0]) { 612 case IPOPT_EOL: 613 (void) strlcpy(line, " - End of option list", remain); 614 return; 615 case IPOPT_NOP: 616 (void) strlcpy(line, " - No op", remain); 617 len = 1; 618 break; 619 case IPOPT_RR: 620 (void) snprintf(line, remain, 621 " - Record route (%d bytes%s)", len, truncstr); 622 print_route(opt); 623 break; 624 case IPOPT_TS: 625 (void) snprintf(line, remain, 626 " - Time stamp (%d bytes%s)", len, truncstr); 627 break; 628 case IPOPT_SECURITY: 629 (void) snprintf(line, remain, " - RIPSO (%d bytes%s)", 630 len, truncstr); 631 print_ripso(opt); 632 break; 633 case IPOPT_COMSEC: 634 (void) snprintf(line, remain, " - CIPSO (%d bytes%s)", 635 len, truncstr); 636 print_cipso(opt); 637 break; 638 case IPOPT_LSRR: 639 (void) snprintf(line, remain, 640 " - Loose source route (%d bytes%s)", len, 641 truncstr); 642 print_route(opt); 643 break; 644 case IPOPT_SATID: 645 (void) snprintf(line, remain, 646 " - SATNET Stream id (%d bytes%s)", 647 len, truncstr); 648 break; 649 case IPOPT_SSRR: 650 (void) snprintf(line, remain, 651 " - Strict source route, (%d bytes%s)", len, 652 truncstr); 653 print_route(opt); 654 break; 655 default: 656 (void) snprintf(line, remain, 657 " - Option %d (unknown - %d bytes%s) %s", 658 opt[0], len, truncstr, 659 tohex((char *)&opt[2], len - 2)); 660 break; 661 } 662 if (len <= 0) { 663 (void) snprintf(line, remain, 664 " - Incomplete option len %d", len); 665 break; 666 } 667 opt += len; 668 optlen -= len; 669 } 670 } 671 672 static void 673 print_route(const uchar_t *opt) 674 { 675 int len, pointer, remain; 676 struct in_addr addr; 677 char *line; 678 679 len = opt[1]; 680 pointer = opt[2]; 681 682 (void) snprintf(get_line(0, 0), get_line_remain(), 683 " Pointer = %d", pointer); 684 685 pointer -= IPOPT_MINOFF; 686 opt += (IPOPT_OFFSET + 1); 687 len -= (IPOPT_OFFSET + 1); 688 689 while (len > 0) { 690 line = get_line(0, 0); 691 remain = get_line_remain(); 692 memcpy((char *)&addr, opt, sizeof (addr)); 693 if (addr.s_addr == INADDR_ANY) 694 (void) strlcpy(line, " -", remain); 695 else 696 (void) snprintf(line, remain, " %s", 697 addrtoname(AF_INET, &addr)); 698 if (pointer == 0) 699 (void) strlcat(line, " <-- (current)", remain); 700 701 opt += sizeof (addr); 702 len -= sizeof (addr); 703 pointer -= sizeof (addr); 704 } 705 } 706 707 char * 708 getproto(int p) 709 { 710 switch (p) { 711 case IPPROTO_HOPOPTS: return ("IPv6-HopOpts"); 712 case IPPROTO_IPV6: return ("IPv6"); 713 case IPPROTO_ROUTING: return ("IPv6-Route"); 714 case IPPROTO_FRAGMENT: return ("IPv6-Frag"); 715 case IPPROTO_RSVP: return ("RSVP"); 716 case IPPROTO_ENCAP: return ("IP-in-IP"); 717 case IPPROTO_AH: return ("AH"); 718 case IPPROTO_ESP: return ("ESP"); 719 case IPPROTO_ICMP: return ("ICMP"); 720 case IPPROTO_ICMPV6: return ("ICMPv6"); 721 case IPPROTO_DSTOPTS: return ("IPv6-DstOpts"); 722 case IPPROTO_IGMP: return ("IGMP"); 723 case IPPROTO_GGP: return ("GGP"); 724 case IPPROTO_TCP: return ("TCP"); 725 case IPPROTO_EGP: return ("EGP"); 726 case IPPROTO_PUP: return ("PUP"); 727 case IPPROTO_UDP: return ("UDP"); 728 case IPPROTO_IDP: return ("IDP"); 729 case IPPROTO_HELLO: return ("HELLO"); 730 case IPPROTO_ND: return ("ND"); 731 case IPPROTO_EON: return ("EON"); 732 case IPPROTO_RAW: return ("RAW"); 733 case IPPROTO_OSPF: return ("OSPF"); 734 default: return (""); 735 } 736 } 737 738 static void 739 prt_routing_hdr(int flags, const struct ip6_rthdr *ipv6ext_rthdr) 740 { 741 uint8_t nxt_hdr; 742 uint8_t type; 743 uint32_t len; 744 uint8_t segleft; 745 uint32_t numaddrs; 746 int i; 747 struct ip6_rthdr0 *ipv6ext_rthdr0; 748 struct in6_addr *addrs; 749 char addr[INET6_ADDRSTRLEN]; 750 751 /* in summary mode, we don't do anything. */ 752 if (flags & F_SUM) { 753 return; 754 } 755 756 nxt_hdr = ipv6ext_rthdr->ip6r_nxt; 757 type = ipv6ext_rthdr->ip6r_type; 758 len = 8 * (ipv6ext_rthdr->ip6r_len + 1); 759 segleft = ipv6ext_rthdr->ip6r_segleft; 760 761 show_header("IPv6-Route: ", "IPv6 Routing Header", 0); 762 show_space(); 763 764 (void) snprintf(get_line(0, 0), get_line_remain(), 765 "Next header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 766 (void) snprintf(get_line(0, 0), get_line_remain(), 767 "Header length = %d", len); 768 (void) snprintf(get_line(0, 0), get_line_remain(), 769 "Routing type = %d", type); 770 (void) snprintf(get_line(0, 0), get_line_remain(), 771 "Segments left = %d", segleft); 772 773 if (type == IPV6_RTHDR_TYPE_0) { 774 /* 775 * XXX This loop will print all addresses in the routing header, 776 * XXX not just the segments left. 777 * XXX (The header length field is twice the number of 778 * XXX addresses) 779 * XXX At some future time, we may want to change this 780 * XXX to differentiate between the hops yet to do 781 * XXX and the hops already taken. 782 */ 783 /* LINTED: alignment */ 784 ipv6ext_rthdr0 = (struct ip6_rthdr0 *)ipv6ext_rthdr; 785 numaddrs = ipv6ext_rthdr0->ip6r0_len / 2; 786 addrs = (struct in6_addr *)(ipv6ext_rthdr0 + 1); 787 for (i = 0; i < numaddrs; i++) { 788 (void) inet_ntop(AF_INET6, &addrs[i], addr, 789 INET6_ADDRSTRLEN); 790 (void) snprintf(get_line(0, 0), get_line_remain(), 791 "address[%d]=%s", i, addr); 792 } 793 } 794 795 show_space(); 796 } 797 798 static void 799 prt_fragment_hdr(int flags, const struct ip6_frag *ipv6ext_frag) 800 { 801 boolean_t morefrag; 802 uint16_t fragoffset; 803 uint8_t nxt_hdr; 804 uint32_t fragident; 805 806 /* extract the various fields from the fragment header */ 807 nxt_hdr = ipv6ext_frag->ip6f_nxt; 808 morefrag = (ipv6ext_frag->ip6f_offlg & IP6F_MORE_FRAG) == 0 809 ? B_FALSE : B_TRUE; 810 fragoffset = ntohs(ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK); 811 fragident = ntohl(ipv6ext_frag->ip6f_ident); 812 813 if (flags & F_SUM) { 814 (void) snprintf(get_sum_line(), MAXLINE, 815 "IPv6 fragment ID=%u Offset=%-4d MF=%d", 816 fragident, 817 fragoffset, 818 morefrag); 819 } else { /* F_DTAIL */ 820 show_header("IPv6-Frag: ", "IPv6 Fragment Header", 0); 821 show_space(); 822 823 (void) snprintf(get_line(0, 0), get_line_remain(), 824 "Next Header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 825 (void) snprintf(get_line(0, 0), get_line_remain(), 826 "Fragment Offset = %d", fragoffset); 827 (void) snprintf(get_line(0, 0), get_line_remain(), 828 "More Fragments Flag = %s", morefrag ? "true" : "false"); 829 (void) snprintf(get_line(0, 0), get_line_remain(), 830 "Identification = %u", fragident); 831 832 show_space(); 833 } 834 } 835 836 static void 837 print_ip6opt_ls(const uchar_t *data, unsigned int op_len) 838 { 839 uint32_t doi; 840 uint8_t sotype, solen; 841 uint16_t value, value2; 842 char *cp; 843 int remlen; 844 boolean_t printed; 845 846 (void) snprintf(get_line(0, 0), get_line_remain(), 847 "Labeled Security Option len = %u bytes%s", op_len, 848 op_len < sizeof (uint32_t) || (op_len & 1) != 0 ? "?" : ""); 849 if (op_len < sizeof (uint32_t)) 850 return; 851 GETINT32(doi, data); 852 (void) snprintf(get_line(0, 0), get_line_remain(), 853 " DOI = %d (%s)", doi, doi == IP6LS_DOI_V4 ? "IPv4" : "???"); 854 op_len -= sizeof (uint32_t); 855 while (op_len > 0) { 856 GETINT8(sotype, data); 857 if (op_len < 2) { 858 (void) snprintf(get_line(0, 0), get_line_remain(), 859 " truncated %u suboption (no len)", sotype); 860 break; 861 } 862 GETINT8(solen, data); 863 if (solen < 2 || solen > op_len) { 864 (void) snprintf(get_line(0, 0), get_line_remain(), 865 " bad %u suboption (len 2 <= %u <= %u)", 866 sotype, solen, op_len); 867 if (solen < 2) 868 solen = 2; 869 if (solen > op_len) 870 solen = op_len; 871 } 872 op_len -= solen; 873 solen -= 2; 874 cp = get_line(0, 0); 875 remlen = get_line_remain(); 876 (void) strlcpy(cp, " ", remlen); 877 cp += 4; 878 remlen -= 4; 879 printed = B_TRUE; 880 switch (sotype) { 881 case IP6LS_TT_LEVEL: 882 if (solen != 2) { 883 printed = B_FALSE; 884 break; 885 } 886 GETINT16(value, data); 887 (void) snprintf(cp, remlen, "Level %u", value); 888 solen = 0; 889 break; 890 case IP6LS_TT_VECTOR: 891 (void) strlcpy(cp, "Bit-Vector: ", remlen); 892 remlen -= strlen(cp); 893 cp += strlen(cp); 894 while (solen > 1) { 895 GETINT16(value, data); 896 solen -= 2; 897 (void) snprintf(cp, remlen, "%04x", value); 898 remlen -= strlen(cp); 899 cp += strlen(cp); 900 } 901 break; 902 case IP6LS_TT_ENUM: 903 (void) strlcpy(cp, "Enumeration:", remlen); 904 remlen -= strlen(cp); 905 cp += strlen(cp); 906 while (solen > 1) { 907 GETINT16(value, data); 908 solen -= 2; 909 (void) snprintf(cp, remlen, " %u", value); 910 remlen -= strlen(cp); 911 cp += strlen(cp); 912 } 913 break; 914 case IP6LS_TT_RANGES: 915 (void) strlcpy(cp, "Ranges:", remlen); 916 remlen -= strlen(cp); 917 cp += strlen(cp); 918 while (solen > 3) { 919 GETINT16(value, data); 920 GETINT16(value2, data); 921 solen -= 4; 922 (void) snprintf(cp, remlen, " %u-%u", value, 923 value2); 924 remlen -= strlen(cp); 925 cp += strlen(cp); 926 } 927 break; 928 case IP6LS_TT_V4: 929 (void) strlcpy(cp, "IPv4 Option", remlen); 930 print_ipoptions(data, solen); 931 solen = 0; 932 break; 933 case IP6LS_TT_DEST: 934 (void) snprintf(cp, remlen, 935 "Destination-Only Data length %u", solen); 936 solen = 0; 937 break; 938 default: 939 (void) snprintf(cp, remlen, 940 " unknown %u suboption (len %u)", sotype, solen); 941 solen = 0; 942 break; 943 } 944 if (solen != 0) { 945 if (printed) { 946 cp = get_line(0, 0); 947 remlen = get_line_remain(); 948 } 949 (void) snprintf(cp, remlen, 950 " malformed %u suboption (remaining %u)", 951 sotype, solen); 952 data += solen; 953 } 954 } 955 } 956 957 static void 958 prt_hbh_options(int flags, const struct ip6_hbh *ipv6ext_hbh) 959 { 960 const uint8_t *data, *ndata; 961 uint32_t len; 962 uint8_t op_type; 963 uint8_t op_len; 964 uint8_t nxt_hdr; 965 966 /* in summary mode, we don't do anything. */ 967 if (flags & F_SUM) { 968 return; 969 } 970 971 show_header("IPv6-HopOpts: ", "IPv6 Hop-by-Hop Options Header", 0); 972 show_space(); 973 974 /* 975 * Store the lengh of this ext hdr in bytes. The caller has 976 * ensured that there is at least len bytes of data left. 977 */ 978 len = ipv6ext_hbh->ip6h_len * 8 + 8; 979 980 ndata = (const uint8_t *)ipv6ext_hbh + 2; 981 len -= 2; 982 983 nxt_hdr = ipv6ext_hbh->ip6h_nxt; 984 (void) snprintf(get_line(0, 0), get_line_remain(), 985 "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr)); 986 987 while (len > 0) { 988 data = ndata; 989 GETINT8(op_type, data); 990 /* This is the only one-octet IPv6 option */ 991 if (op_type == IP6OPT_PAD1) { 992 (void) snprintf(get_line(0, 0), get_line_remain(), 993 "pad1 option "); 994 len--; 995 ndata = data; 996 continue; 997 } 998 GETINT8(op_len, data); 999 if (len < 2 || op_len + 2 > len) { 1000 (void) snprintf(get_line(0, 0), get_line_remain(), 1001 "Error: option %u truncated (%u + 2 > %u)", 1002 op_type, op_len, len); 1003 op_len = len - 2; 1004 /* 1005 * Continue processing the malformed option so that we 1006 * can display as much as possible. 1007 */ 1008 } 1009 1010 /* advance pointers to the next option */ 1011 len -= op_len + 2; 1012 ndata = data + op_len; 1013 1014 /* process this option */ 1015 switch (op_type) { 1016 case IP6OPT_PADN: 1017 (void) snprintf(get_line(0, 0), get_line_remain(), 1018 "padN option len = %u", op_len); 1019 break; 1020 case IP6OPT_JUMBO: { 1021 uint32_t payload_len; 1022 1023 (void) snprintf(get_line(0, 0), get_line_remain(), 1024 "Jumbo Payload Option len = %u bytes%s", op_len, 1025 op_len == sizeof (uint32_t) ? "" : "?"); 1026 if (op_len == sizeof (uint32_t)) { 1027 GETINT32(payload_len, data); 1028 (void) snprintf(get_line(0, 0), 1029 get_line_remain(), 1030 "Jumbo Payload Length = %u bytes", 1031 payload_len); 1032 } 1033 break; 1034 } 1035 case IP6OPT_ROUTER_ALERT: { 1036 uint16_t value; 1037 const char *label[] = {"MLD", "RSVP", "AN"}; 1038 1039 (void) snprintf(get_line(0, 0), get_line_remain(), 1040 "Router Alert Option len = %u bytes%s", op_len, 1041 op_len == sizeof (uint16_t) ? "" : "?"); 1042 if (op_len == sizeof (uint16_t)) { 1043 GETINT16(value, data); 1044 (void) snprintf(get_line(0, 0), 1045 get_line_remain(), 1046 "Alert Type = %d (%s)", value, 1047 value < sizeof (label) / sizeof (label[0]) ? 1048 label[value] : "???"); 1049 } 1050 break; 1051 } 1052 case IP6OPT_LS: 1053 print_ip6opt_ls(data, op_len); 1054 break; 1055 default: 1056 (void) snprintf(get_line(0, 0), get_line_remain(), 1057 "Option type = %u, len = %u", op_type, op_len); 1058 break; 1059 } 1060 } 1061 1062 show_space(); 1063 } 1064 1065 static void 1066 prt_dest_options(int flags, const struct ip6_dest *ipv6ext_dest) 1067 { 1068 const uint8_t *data, *ndata; 1069 uint32_t len; 1070 uint8_t op_type; 1071 uint32_t op_len; 1072 uint8_t nxt_hdr; 1073 uint8_t value; 1074 1075 /* in summary mode, we don't do anything. */ 1076 if (flags & F_SUM) { 1077 return; 1078 } 1079 1080 show_header("IPv6-DstOpts: ", "IPv6 Destination Options Header", 0); 1081 show_space(); 1082 1083 /* 1084 * Store the length of this ext hdr in bytes. The caller has 1085 * ensured that there is at least len bytes of data left. 1086 */ 1087 len = ipv6ext_dest->ip6d_len * 8 + 8; 1088 1089 ndata = (const uint8_t *)ipv6ext_dest + 2; /* skip hdr/len */ 1090 len -= 2; 1091 1092 nxt_hdr = ipv6ext_dest->ip6d_nxt; 1093 (void) snprintf(get_line(0, 0), get_line_remain(), 1094 "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr)); 1095 1096 while (len > 0) { 1097 data = ndata; 1098 GETINT8(op_type, data); 1099 if (op_type == IP6OPT_PAD1) { 1100 (void) snprintf(get_line(0, 0), get_line_remain(), 1101 "pad1 option "); 1102 len--; 1103 ndata = data; 1104 continue; 1105 } 1106 GETINT8(op_len, data); 1107 if (len < 2 || op_len + 2 > len) { 1108 (void) snprintf(get_line(0, 0), get_line_remain(), 1109 "Error: option %u truncated (%u + 2 > %u)", 1110 op_type, op_len, len); 1111 op_len = len - 2; 1112 /* 1113 * Continue processing the malformed option so that we 1114 * can display as much as possible. 1115 */ 1116 } 1117 1118 /* advance pointers to the next option */ 1119 len -= op_len + 2; 1120 ndata = data + op_len; 1121 1122 /* process this option */ 1123 switch (op_type) { 1124 case IP6OPT_PADN: 1125 (void) snprintf(get_line(0, 0), get_line_remain(), 1126 "padN option len = %u", op_len); 1127 break; 1128 case IP6OPT_TUNNEL_LIMIT: 1129 GETINT8(value, data); 1130 (void) snprintf(get_line(0, 0), get_line_remain(), 1131 "tunnel encapsulation limit len = %d, value = %d", 1132 op_len, value); 1133 break; 1134 case IP6OPT_LS: 1135 print_ip6opt_ls(data, op_len); 1136 break; 1137 default: 1138 (void) snprintf(get_line(0, 0), get_line_remain(), 1139 "Option type = %u, len = %u", op_type, op_len); 1140 break; 1141 } 1142 } 1143 1144 show_space(); 1145 } 1146 1147 #define ALABEL_MAXLEN 256 1148 1149 static char ascii_label[ALABEL_MAXLEN]; 1150 static char *plabel = ascii_label; 1151 1152 struct snoop_pair { 1153 int val; 1154 const char *name; 1155 }; 1156 1157 static struct snoop_pair ripso_class_tbl[] = { 1158 TSOL_CL_TOP_SECRET, "TOP SECRET", 1159 TSOL_CL_SECRET, "SECRET", 1160 TSOL_CL_CONFIDENTIAL, "CONFIDENTIAL", 1161 TSOL_CL_UNCLASSIFIED, "UNCLASSIFIED", 1162 -1, NULL 1163 }; 1164 1165 static struct snoop_pair ripso_prot_tbl[] = { 1166 TSOL_PA_GENSER, "GENSER", 1167 TSOL_PA_SIOP_ESI, "SIOP-ESI", 1168 TSOL_PA_SCI, "SCI", 1169 TSOL_PA_NSA, "NSA", 1170 TSOL_PA_DOE, "DOE", 1171 0x04, "UNASSIGNED", 1172 0x02, "UNASSIGNED", 1173 -1, NULL 1174 }; 1175 1176 static struct snoop_pair * 1177 get_pair_byval(struct snoop_pair pairlist[], int val) 1178 { 1179 int i; 1180 1181 for (i = 0; pairlist[i].name != NULL; i++) 1182 if (pairlist[i].val == val) 1183 return (&pairlist[i]); 1184 return (NULL); 1185 } 1186 1187 static void 1188 print_ripso(const uchar_t *opt) 1189 { 1190 struct snoop_pair *ripso_class; 1191 int i, index, prot_len; 1192 boolean_t first_prot; 1193 char line[100], *ptr; 1194 1195 prot_len = opt[1] - 3; 1196 if (prot_len < 0) 1197 return; 1198 1199 show_header("RIPSO: ", "Revised IP Security Option", 0); 1200 show_space(); 1201 1202 (void) snprintf(get_line(0, 0), get_line_remain(), 1203 "Type = Basic Security Option (%d), Length = %d", opt[0], opt[1]); 1204 1205 /* 1206 * Display Classification Level 1207 */ 1208 ripso_class = get_pair_byval(ripso_class_tbl, (int)opt[2]); 1209 if (ripso_class == NULL) 1210 (void) snprintf(get_line(0, 0), get_line_remain(), 1211 "Classification = Unknown (0x%02x)", opt[2]); 1212 else 1213 (void) snprintf(get_line(0, 0), get_line_remain(), 1214 "Classification = %s (0x%02x)", 1215 ripso_class->name, ripso_class->val); 1216 1217 /* 1218 * Display Protection Authority Flags 1219 */ 1220 (void) snprintf(line, sizeof (line), "Protection Authority = "); 1221 ptr = line; 1222 first_prot = B_TRUE; 1223 for (i = 0; i < prot_len; i++) { 1224 index = 0; 1225 while (ripso_prot_tbl[index].name != NULL) { 1226 if (opt[3 + i] & ripso_prot_tbl[index].val) { 1227 ptr = strchr(ptr, 0); 1228 if (!first_prot) { 1229 (void) strlcpy(ptr, ", ", 1230 sizeof (line) - (ptr - line)); 1231 ptr = strchr(ptr, 0); 1232 } 1233 (void) snprintf(ptr, 1234 sizeof (line) - (ptr - line), 1235 "%s (0x%02x)", 1236 ripso_prot_tbl[index].name, 1237 ripso_prot_tbl[index].val); 1238 } 1239 index++; 1240 } 1241 if ((opt[3 + i] & 1) == 0) 1242 break; 1243 } 1244 if (!first_prot) 1245 (void) snprintf(get_line(0, 0), get_line_remain(), "%s", line); 1246 else 1247 (void) snprintf(get_line(0, 0), get_line_remain(), "%sNone", 1248 line); 1249 } 1250 1251 #define CIPSO_GENERIC_ARRAY_LEN 200 1252 1253 /* 1254 * Return 1 if CIPSO SL and Categories are all 1's; 0 otherwise. 1255 * 1256 * Note: opt starts with "Tag Type": 1257 * 1258 * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)| 1259 * 1260 */ 1261 static boolean_t 1262 cipso_high(const uchar_t *opt) 1263 { 1264 int i; 1265 1266 if (((int)opt[1] + 6) < IP_MAX_OPT_LENGTH) 1267 return (B_FALSE); 1268 for (i = 0; i < ((int)opt[1] - 3); i++) 1269 if (opt[3 + i] != 0xff) 1270 return (B_FALSE); 1271 return (B_TRUE); 1272 } 1273 1274 /* 1275 * Converts CIPSO label to SL. 1276 * 1277 * Note: opt starts with "Tag Type": 1278 * 1279 * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)| 1280 * 1281 */ 1282 static void 1283 cipso2sl(const uchar_t *opt, bslabel_t *sl, int *high) 1284 { 1285 int i, taglen; 1286 uchar_t *q = (uchar_t *)&((_bslabel_impl_t *)sl)->compartments; 1287 1288 *high = 0; 1289 taglen = opt[1]; 1290 memset((caddr_t)sl, 0, sizeof (bslabel_t)); 1291 1292 if (cipso_high(opt)) { 1293 BSLHIGH(sl); 1294 *high = 1; 1295 } else { 1296 LCLASS_SET((_bslabel_impl_t *)sl, opt[3]); 1297 for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) 1298 q[i] = opt[TSOL_TT1_MIN_LENGTH + i]; 1299 } 1300 SETBLTYPE(sl, SUN_SL_ID); 1301 } 1302 1303 static int 1304 interpret_cipso_tagtype1(const uchar_t *opt) 1305 { 1306 int i, taglen, ishigh; 1307 bslabel_t sl; 1308 char line[CIPSO_GENERIC_ARRAY_LEN], *ptr; 1309 1310 taglen = opt[1]; 1311 if (taglen < TSOL_TT1_MIN_LENGTH || 1312 taglen > TSOL_TT1_MAX_LENGTH) 1313 return (taglen); 1314 1315 (void) snprintf(get_line(0, 0), get_line_remain(), 1316 "Tag Type = %d, Tag Length = %d", opt[0], opt[1]); 1317 (void) snprintf(get_line(0, 0), get_line_remain(), 1318 "Sensitivity Level = 0x%02x", opt[3]); 1319 ptr = line; 1320 for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) { 1321 (void) snprintf(ptr, sizeof (line) - (ptr - line), "%02x", 1322 opt[TSOL_TT1_MIN_LENGTH + i]); 1323 ptr = strchr(ptr, 0); 1324 } 1325 if (i != 0) { 1326 (void) snprintf(get_line(0, 0), get_line_remain(), 1327 "Categories = "); 1328 (void) snprintf(get_line(0, 0), get_line_remain(), "\t%s", 1329 line); 1330 } else { 1331 (void) snprintf(get_line(0, 0), get_line_remain(), 1332 "Categories = None"); 1333 } 1334 cipso2sl(opt, &sl, &ishigh); 1335 if (is_system_labeled()) { 1336 if (bsltos(&sl, &plabel, ALABEL_MAXLEN, 1337 LONG_CLASSIFICATION|LONG_WORDS|VIEW_INTERNAL) < 0) { 1338 (void) snprintf(get_line(0, 0), get_line_remain(), 1339 "The Sensitivity Level and Categories can't be " 1340 "mapped to a valid SL"); 1341 } else { 1342 (void) snprintf(get_line(0, 0), get_line_remain(), 1343 "The Sensitivity Level and Categories are mapped " 1344 "to the SL:"); 1345 (void) snprintf(get_line(0, 0), get_line_remain(), 1346 "\t%s", ascii_label); 1347 } 1348 } 1349 return (taglen); 1350 } 1351 1352 /* 1353 * The following struct definition #define's are copied from TS1.x. They are 1354 * not used here (except TTYPE_3_MAX_TOKENS), but included as a reference for 1355 * the tag type 3 packet format. 1356 */ 1357 #define TTYPE_3_MAX_TOKENS 7 1358 1359 /* 1360 * Display CIPSO tag type 3 which is defined by MAXSIX. 1361 */ 1362 static int 1363 interpret_cipso_tagtype3(const uchar_t *opt) 1364 { 1365 uchar_t tagtype; 1366 int index, numtokens, taglen; 1367 uint16_t mask; 1368 uint32_t token; 1369 static const char *name[] = { 1370 "SL", 1371 "NCAV", 1372 "INTEG", 1373 "SID", 1374 "undefined", 1375 "undefined", 1376 "IL", 1377 "PRIVS", 1378 "LUID", 1379 "PID", 1380 "IDS", 1381 "ACL" 1382 }; 1383 1384 tagtype = *opt++; 1385 (void) memcpy(&mask, opt + 3, sizeof (mask)); 1386 (void) snprintf(get_line(0, 0), get_line_remain(), 1387 "Tag Type = %d (MAXSIX)", tagtype); 1388 (void) snprintf(get_line(0, 0), get_line_remain(), 1389 "Generation = 0x%02x%02x%02x, Mask = 0x%04x", opt[0], opt[1], 1390 opt[2], mask); 1391 opt += 3 + sizeof (mask); 1392 1393 /* 1394 * Display tokens 1395 */ 1396 numtokens = 0; 1397 index = 0; 1398 while (mask != 0 && numtokens < TTYPE_3_MAX_TOKENS) { 1399 if (mask & 0x0001) { 1400 (void) memcpy(&token, opt, sizeof (token)); 1401 opt += sizeof (token); 1402 (void) snprintf(get_line(0, 0), get_line_remain(), 1403 "Attribute = %s, Token = 0x%08x", 1404 index < sizeof (name) / sizeof (*name) ? 1405 name[index] : "unknown", token); 1406 numtokens++; 1407 } 1408 mask = mask >> 1; 1409 index++; 1410 } 1411 1412 taglen = 6 + numtokens * 4; 1413 return (taglen); 1414 } 1415 1416 static void 1417 print_cipso(const uchar_t *opt) 1418 { 1419 int optlen, taglen, tagnum; 1420 uint32_t doi; 1421 char line[CIPSO_GENERIC_ARRAY_LEN]; 1422 char *oldnest; 1423 1424 optlen = opt[1]; 1425 if (optlen < TSOL_CIPSO_MIN_LENGTH || optlen > TSOL_CIPSO_MAX_LENGTH) 1426 return; 1427 1428 oldnest = prot_nest_prefix; 1429 prot_nest_prefix = prot_prefix; 1430 show_header("CIPSO: ", "Common IP Security Option", 0); 1431 show_space(); 1432 1433 /* 1434 * Display CIPSO Header 1435 */ 1436 (void) snprintf(get_line(0, 0), get_line_remain(), 1437 "Type = CIPSO (%d), Length = %d", opt[0], opt[1]); 1438 (void) memcpy(&doi, opt + 2, sizeof (doi)); 1439 (void) snprintf(get_line(0, 0), get_line_remain(), 1440 "Domain of Interpretation = %u", (unsigned)ntohl(doi)); 1441 1442 if (opt[1] == TSOL_CIPSO_MIN_LENGTH) { /* no tags */ 1443 show_space(); 1444 prot_prefix = prot_nest_prefix; 1445 prot_nest_prefix = oldnest; 1446 return; 1447 } 1448 optlen -= TSOL_CIPSO_MIN_LENGTH; 1449 opt += TSOL_CIPSO_MIN_LENGTH; 1450 1451 /* 1452 * Display Each Tag 1453 */ 1454 tagnum = 1; 1455 while (optlen >= TSOL_TT1_MIN_LENGTH) { 1456 (void) snprintf(line, sizeof (line), "Tag# %d", tagnum); 1457 show_header("CIPSO: ", line, 0); 1458 /* 1459 * We handle tag type 1 and 3 only. Note, tag type 3 1460 * is MAXSIX defined. 1461 */ 1462 switch (opt[0]) { 1463 case 1: 1464 taglen = interpret_cipso_tagtype1(opt); 1465 break; 1466 case 3: 1467 taglen = interpret_cipso_tagtype3(opt); 1468 break; 1469 default: 1470 (void) snprintf(get_line(0, 0), get_line_remain(), 1471 "Unknown Tag Type %d", opt[0]); 1472 show_space(); 1473 prot_prefix = prot_nest_prefix; 1474 prot_nest_prefix = oldnest; 1475 return; 1476 } 1477 1478 /* 1479 * Move to the next tag 1480 */ 1481 if (taglen <= 0) 1482 break; 1483 optlen -= taglen; 1484 opt += taglen; 1485 tagnum++; 1486 } 1487 show_space(); 1488 prot_prefix = prot_nest_prefix; 1489 prot_nest_prefix = oldnest; 1490 } 1491