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