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