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