10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51676Sjpk * Common Development and Distribution License (the "License"). 61676Sjpk * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 221676Sjpk * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <stdio.h> 300Sstevel@tonic-gate #include <string.h> 310Sstevel@tonic-gate #include <fcntl.h> 320Sstevel@tonic-gate #include <string.h> 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/time.h> 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include <sys/stropts.h> 370Sstevel@tonic-gate #include <sys/socket.h> 380Sstevel@tonic-gate #include <net/if.h> 390Sstevel@tonic-gate #include <netinet/in_systm.h> 400Sstevel@tonic-gate #include <netinet/in.h> 410Sstevel@tonic-gate #include <netinet/ip.h> 420Sstevel@tonic-gate #include <netinet/ip6.h> 430Sstevel@tonic-gate #include <netinet/ip_icmp.h> 440Sstevel@tonic-gate #include <netinet/icmp6.h> 450Sstevel@tonic-gate #include <netinet/if_ether.h> 461676Sjpk #include <inet/ip.h> 470Sstevel@tonic-gate #include <inet/ip6.h> 480Sstevel@tonic-gate #include <arpa/inet.h> 490Sstevel@tonic-gate #include <netdb.h> 501676Sjpk #include <tsol/label.h> 511676Sjpk #include <sys/tsol/tndb.h> 521676Sjpk #include <sys/tsol/label_macro.h> 531676Sjpk 540Sstevel@tonic-gate #include "snoop.h" 550Sstevel@tonic-gate 560Sstevel@tonic-gate 570Sstevel@tonic-gate /* 580Sstevel@tonic-gate * IPv6 extension header masks. These are used by the print_ipv6_extensions() 590Sstevel@tonic-gate * function to return information to the caller about which extension headers 600Sstevel@tonic-gate * were processed. This can be useful if the caller wants to know if the 610Sstevel@tonic-gate * packet is an IPv6 fragment, for example. 620Sstevel@tonic-gate */ 630Sstevel@tonic-gate #define SNOOP_HOPOPTS 0x01U 640Sstevel@tonic-gate #define SNOOP_ROUTING 0x02U 650Sstevel@tonic-gate #define SNOOP_DSTOPTS 0x04U 660Sstevel@tonic-gate #define SNOOP_FRAGMENT 0x08U 670Sstevel@tonic-gate #define SNOOP_AH 0x10U 680Sstevel@tonic-gate #define SNOOP_ESP 0x20U 690Sstevel@tonic-gate #define SNOOP_IPV6 0x40U 700Sstevel@tonic-gate 711676Sjpk static void prt_routing_hdr(int, const struct ip6_rthdr *); 721676Sjpk static void prt_fragment_hdr(int, const struct ip6_frag *); 731676Sjpk static void prt_hbh_options(int, const struct ip6_hbh *); 741676Sjpk static void prt_dest_options(int, const struct ip6_dest *); 751676Sjpk static void print_route(const uchar_t *); 761676Sjpk static void print_ipoptions(const uchar_t *, int); 771676Sjpk static void print_ripso(const uchar_t *); 781676Sjpk static void print_cipso(const uchar_t *); 790Sstevel@tonic-gate 800Sstevel@tonic-gate /* Keep track of how many nested IP headers we have. */ 810Sstevel@tonic-gate unsigned int encap_levels; 820Sstevel@tonic-gate unsigned int total_encap_levels = 1; 830Sstevel@tonic-gate 840Sstevel@tonic-gate int 851676Sjpk interpret_ip(int flags, const struct ip *ip, int fraglen) 860Sstevel@tonic-gate { 871676Sjpk uchar_t *data; 880Sstevel@tonic-gate char buff[24]; 890Sstevel@tonic-gate boolean_t isfrag = B_FALSE; 900Sstevel@tonic-gate boolean_t morefrag; 910Sstevel@tonic-gate uint16_t fragoffset; 920Sstevel@tonic-gate int hdrlen; 930Sstevel@tonic-gate uint16_t iplen, uitmp; 940Sstevel@tonic-gate 950Sstevel@tonic-gate if (ip->ip_v == IPV6_VERSION) { 960Sstevel@tonic-gate iplen = interpret_ipv6(flags, (ip6_t *)ip, fraglen); 970Sstevel@tonic-gate return (iplen); 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* XXX Should this count for mix-and-match v4/v6 encapsulations? */ 1010Sstevel@tonic-gate if (encap_levels == 0) 1020Sstevel@tonic-gate total_encap_levels = 0; 1030Sstevel@tonic-gate encap_levels++; 1040Sstevel@tonic-gate total_encap_levels++; 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate hdrlen = ip->ip_hl * 4; 1071676Sjpk data = ((uchar_t *)ip) + hdrlen; 1080Sstevel@tonic-gate iplen = ntohs(ip->ip_len) - hdrlen; 1090Sstevel@tonic-gate fraglen -= hdrlen; 1100Sstevel@tonic-gate if (fraglen > iplen) 1110Sstevel@tonic-gate fraglen = iplen; 1120Sstevel@tonic-gate if (fraglen < 0) { 1130Sstevel@tonic-gate (void) snprintf(get_sum_line(), MAXLINE, 1140Sstevel@tonic-gate "IP truncated: header missing %d bytes", -fraglen); 1150Sstevel@tonic-gate encap_levels--; 1160Sstevel@tonic-gate return (fraglen + iplen); 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate /* 1190Sstevel@tonic-gate * We flag this as a fragment if the more fragments bit is set, or 1200Sstevel@tonic-gate * if the fragment offset is non-zero. 1210Sstevel@tonic-gate */ 1220Sstevel@tonic-gate morefrag = (ntohs(ip->ip_off) & IP_MF) == 0 ? B_FALSE : B_TRUE; 1230Sstevel@tonic-gate fragoffset = (ntohs(ip->ip_off) & 0x1FFF) * 8; 1240Sstevel@tonic-gate if (morefrag || fragoffset != 0) 1250Sstevel@tonic-gate isfrag = B_TRUE; 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate if (encap_levels == 1) { 1280Sstevel@tonic-gate src_name = addrtoname(AF_INET, &ip->ip_src); 1290Sstevel@tonic-gate dst_name = addrtoname(AF_INET, &ip->ip_dst); 1300Sstevel@tonic-gate } /* Else we already have the src_name and dst_name we want! */ 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate if (flags & F_SUM) { 1330Sstevel@tonic-gate if (isfrag) { 1340Sstevel@tonic-gate (void) snprintf(get_sum_line(), MAXLINE, 1350Sstevel@tonic-gate "%s IP fragment ID=%d Offset=%-4d MF=%d TOS=0x%x " 1360Sstevel@tonic-gate "TTL=%d", 1370Sstevel@tonic-gate getproto(ip->ip_p), 1380Sstevel@tonic-gate ntohs(ip->ip_id), 1390Sstevel@tonic-gate fragoffset, 1400Sstevel@tonic-gate morefrag, 1410Sstevel@tonic-gate ip->ip_tos, 1420Sstevel@tonic-gate ip->ip_ttl); 1430Sstevel@tonic-gate } else { 1440Sstevel@tonic-gate (void) strlcpy(buff, inet_ntoa(ip->ip_dst), 1450Sstevel@tonic-gate sizeof (buff)); 1460Sstevel@tonic-gate uitmp = ntohs(ip->ip_len); 1470Sstevel@tonic-gate (void) snprintf(get_sum_line(), MAXLINE, 1480Sstevel@tonic-gate "IP D=%s S=%s LEN=%u%s, ID=%d, TOS=0x%x, TTL=%d", 1490Sstevel@tonic-gate buff, 1500Sstevel@tonic-gate inet_ntoa(ip->ip_src), 1510Sstevel@tonic-gate uitmp, 1520Sstevel@tonic-gate iplen > fraglen ? "?" : "", 1530Sstevel@tonic-gate ntohs(ip->ip_id), 1540Sstevel@tonic-gate ip->ip_tos, 1550Sstevel@tonic-gate ip->ip_ttl); 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate if (flags & F_DTAIL) { 1600Sstevel@tonic-gate show_header("IP: ", "IP Header", iplen); 1610Sstevel@tonic-gate show_space(); 1621676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1631676Sjpk "Version = %d", ip->ip_v); 1641676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1651676Sjpk "Header length = %d bytes", hdrlen); 1661676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1671676Sjpk "Type of service = 0x%02x", ip->ip_tos); 1681676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1691676Sjpk " xxx. .... = %d (precedence)", 1700Sstevel@tonic-gate ip->ip_tos >> 5); 1711676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1721676Sjpk " %s", getflag(ip->ip_tos, IPTOS_LOWDELAY, 1730Sstevel@tonic-gate "low delay", "normal delay")); 1741676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 1750Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_THROUGHPUT, 1760Sstevel@tonic-gate "high throughput", "normal throughput")); 1771676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 1780Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_RELIABILITY, 1790Sstevel@tonic-gate "high reliability", "normal reliability")); 1801676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 1810Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_ECT, 1820Sstevel@tonic-gate "ECN capable transport", "not ECN capable transport")); 1831676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 1840Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_CE, 1850Sstevel@tonic-gate "ECN congestion experienced", 1860Sstevel@tonic-gate "no ECN congestion experienced")); 1870Sstevel@tonic-gate /* warning: ip_len is signed in netinet/ip.h */ 1880Sstevel@tonic-gate uitmp = ntohs(ip->ip_len); 1891676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1901676Sjpk "Total length = %u bytes%s", uitmp, 1910Sstevel@tonic-gate iplen > fraglen ? " -- truncated" : ""); 1921676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1931676Sjpk "Identification = %d", ntohs(ip->ip_id)); 1940Sstevel@tonic-gate /* warning: ip_off is signed in netinet/ip.h */ 1950Sstevel@tonic-gate uitmp = ntohs(ip->ip_off); 1961676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1971676Sjpk "Flags = 0x%x", uitmp >> 12); 1981676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 1990Sstevel@tonic-gate getflag(uitmp >> 8, IP_DF >> 8, 2000Sstevel@tonic-gate "do not fragment", "may fragment")); 2011676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 2020Sstevel@tonic-gate getflag(uitmp >> 8, IP_MF >> 8, 2030Sstevel@tonic-gate "more fragments", "last fragment")); 2041676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 2051676Sjpk "Fragment offset = %u bytes", 2060Sstevel@tonic-gate fragoffset); 2071676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 2081676Sjpk "Time to live = %d seconds/hops", 2090Sstevel@tonic-gate ip->ip_ttl); 2101676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 2111676Sjpk "Protocol = %d (%s)", ip->ip_p, 2120Sstevel@tonic-gate getproto(ip->ip_p)); 2130Sstevel@tonic-gate /* 2140Sstevel@tonic-gate * XXX need to compute checksum and print whether it's correct 2150Sstevel@tonic-gate */ 2161676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 2171676Sjpk "Header checksum = %04x", 2180Sstevel@tonic-gate ntohs(ip->ip_sum)); 2191676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 2201676Sjpk "Source address = %s, %s", 2210Sstevel@tonic-gate inet_ntoa(ip->ip_src), addrtoname(AF_INET, &ip->ip_src)); 2221676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 2231676Sjpk "Destination address = %s, %s", 2240Sstevel@tonic-gate inet_ntoa(ip->ip_dst), addrtoname(AF_INET, &ip->ip_dst)); 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /* Print IP options - if any */ 2270Sstevel@tonic-gate 2281676Sjpk print_ipoptions((const uchar_t *)(ip + 1), 2291676Sjpk hdrlen - sizeof (struct ip)); 2300Sstevel@tonic-gate show_space(); 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate /* 2340Sstevel@tonic-gate * If we are in detail mode, and this is not the first fragment of 2350Sstevel@tonic-gate * a fragmented packet, print out a little line stating this. 2360Sstevel@tonic-gate * Otherwise, go to the next protocol layer only if this is not a 2370Sstevel@tonic-gate * fragment, or we are in detail mode and this is the first fragment 2380Sstevel@tonic-gate * of a fragmented packet. 2390Sstevel@tonic-gate */ 2400Sstevel@tonic-gate if (flags & F_DTAIL && fragoffset != 0) { 2411676Sjpk (void) snprintf(get_detail_line(0, 0), MAXLINE, 2420Sstevel@tonic-gate "%s: [%d byte(s) of data, continuation of IP ident=%d]", 2430Sstevel@tonic-gate getproto(ip->ip_p), 2440Sstevel@tonic-gate iplen, 2450Sstevel@tonic-gate ntohs(ip->ip_id)); 2460Sstevel@tonic-gate } else if (!isfrag || (flags & F_DTAIL) && isfrag && fragoffset == 0) { 2470Sstevel@tonic-gate /* go to the next protocol layer */ 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate if (fraglen > 0) { 2500Sstevel@tonic-gate switch (ip->ip_p) { 2510Sstevel@tonic-gate case IPPROTO_IP: 2520Sstevel@tonic-gate break; 2530Sstevel@tonic-gate case IPPROTO_ENCAP: 2541676Sjpk (void) interpret_ip(flags, 2551676Sjpk /* LINTED: alignment */ 2561676Sjpk (const struct ip *)data, fraglen); 2570Sstevel@tonic-gate break; 2580Sstevel@tonic-gate case IPPROTO_ICMP: 2591676Sjpk (void) interpret_icmp(flags, 2601676Sjpk /* LINTED: alignment */ 2611676Sjpk (struct icmp *)data, iplen, fraglen); 2620Sstevel@tonic-gate break; 2630Sstevel@tonic-gate case IPPROTO_IGMP: 2640Sstevel@tonic-gate interpret_igmp(flags, data, iplen, fraglen); 2650Sstevel@tonic-gate break; 2660Sstevel@tonic-gate case IPPROTO_GGP: 2670Sstevel@tonic-gate break; 2680Sstevel@tonic-gate case IPPROTO_TCP: 2691676Sjpk (void) interpret_tcp(flags, 2701676Sjpk (struct tcphdr *)data, iplen, fraglen); 2710Sstevel@tonic-gate break; 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate case IPPROTO_ESP: 2741676Sjpk (void) interpret_esp(flags, data, iplen, 2751676Sjpk fraglen); 2760Sstevel@tonic-gate break; 2770Sstevel@tonic-gate case IPPROTO_AH: 2781676Sjpk (void) interpret_ah(flags, data, iplen, 2791676Sjpk fraglen); 2800Sstevel@tonic-gate break; 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate case IPPROTO_OSPF: 2830Sstevel@tonic-gate interpret_ospf(flags, data, iplen, fraglen); 2840Sstevel@tonic-gate break; 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate case IPPROTO_EGP: 2870Sstevel@tonic-gate case IPPROTO_PUP: 2880Sstevel@tonic-gate break; 2890Sstevel@tonic-gate case IPPROTO_UDP: 2901676Sjpk (void) interpret_udp(flags, 2911676Sjpk (struct udphdr *)data, iplen, fraglen); 2920Sstevel@tonic-gate break; 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate case IPPROTO_IDP: 2950Sstevel@tonic-gate case IPPROTO_HELLO: 2960Sstevel@tonic-gate case IPPROTO_ND: 2970Sstevel@tonic-gate case IPPROTO_RAW: 2980Sstevel@tonic-gate break; 2990Sstevel@tonic-gate case IPPROTO_IPV6: /* IPV6 encap */ 3001676Sjpk /* LINTED: alignment */ 3010Sstevel@tonic-gate (void) interpret_ipv6(flags, (ip6_t *)data, 3020Sstevel@tonic-gate iplen); 3030Sstevel@tonic-gate break; 3040Sstevel@tonic-gate case IPPROTO_SCTP: 3051676Sjpk (void) interpret_sctp(flags, 3061676Sjpk (struct sctp_hdr *)data, iplen, fraglen); 3070Sstevel@tonic-gate break; 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate } 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate encap_levels--; 3130Sstevel@tonic-gate return (iplen); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate int 3171676Sjpk interpret_ipv6(int flags, const ip6_t *ip6h, int fraglen) 3180Sstevel@tonic-gate { 3190Sstevel@tonic-gate uint8_t *data; 3200Sstevel@tonic-gate int hdrlen, iplen; 3210Sstevel@tonic-gate int version, flow, class; 3220Sstevel@tonic-gate uchar_t proto; 3230Sstevel@tonic-gate boolean_t isfrag = B_FALSE; 3240Sstevel@tonic-gate uint8_t extmask; 3250Sstevel@tonic-gate /* 3260Sstevel@tonic-gate * The print_srcname and print_dstname strings are the hostname 3270Sstevel@tonic-gate * parts of the verbose IPv6 header output, including the comma 3280Sstevel@tonic-gate * and the space after the litteral address strings. 3290Sstevel@tonic-gate */ 3300Sstevel@tonic-gate char print_srcname[MAXHOSTNAMELEN + 2]; 3310Sstevel@tonic-gate char print_dstname[MAXHOSTNAMELEN + 2]; 3320Sstevel@tonic-gate char src_addrstr[INET6_ADDRSTRLEN]; 3330Sstevel@tonic-gate char dst_addrstr[INET6_ADDRSTRLEN]; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate iplen = ntohs(ip6h->ip6_plen); 3360Sstevel@tonic-gate hdrlen = IPV6_HDR_LEN; 3370Sstevel@tonic-gate fraglen -= hdrlen; 3380Sstevel@tonic-gate if (fraglen < 0) 3390Sstevel@tonic-gate return (fraglen + hdrlen); 3400Sstevel@tonic-gate data = ((uint8_t *)ip6h) + hdrlen; 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate proto = ip6h->ip6_nxt; 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate src_name = addrtoname(AF_INET6, &ip6h->ip6_src); 3450Sstevel@tonic-gate dst_name = addrtoname(AF_INET6, &ip6h->ip6_dst); 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate /* 3480Sstevel@tonic-gate * Use endian-aware masks to extract traffic class and 3490Sstevel@tonic-gate * flowinfo. Also, flowinfo is now 20 bits and class 8 3500Sstevel@tonic-gate * rather than 24 and 4. 3510Sstevel@tonic-gate */ 3520Sstevel@tonic-gate class = ntohl((ip6h->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20); 3530Sstevel@tonic-gate flow = ntohl(ip6h->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL); 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /* 3560Sstevel@tonic-gate * NOTE: the F_SUM and F_DTAIL flags are mutually exclusive, 3570Sstevel@tonic-gate * so the code within the first part of the following if statement 3580Sstevel@tonic-gate * will not affect the detailed printing of the packet. 3590Sstevel@tonic-gate */ 3600Sstevel@tonic-gate if (flags & F_SUM) { 3611676Sjpk (void) snprintf(get_sum_line(), MAXLINE, 3621676Sjpk "IPv6 S=%s D=%s LEN=%d HOPS=%d CLASS=0x%x FLOW=0x%x", 3630Sstevel@tonic-gate src_name, dst_name, iplen, ip6h->ip6_hops, class, flow); 3640Sstevel@tonic-gate } else if (flags & F_DTAIL) { 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &ip6h->ip6_src, src_addrstr, 3670Sstevel@tonic-gate INET6_ADDRSTRLEN); 3680Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &ip6h->ip6_dst, dst_addrstr, 3690Sstevel@tonic-gate INET6_ADDRSTRLEN); 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate version = ntohl(ip6h->ip6_vcf) >> 28; 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate if (strcmp(src_name, src_addrstr) == 0) 3740Sstevel@tonic-gate print_srcname[0] = '\0'; 3750Sstevel@tonic-gate else 3760Sstevel@tonic-gate snprintf(print_srcname, sizeof (print_srcname), 3770Sstevel@tonic-gate ", %s", src_name); 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate if (strcmp(dst_name, dst_addrstr) == 0) 3800Sstevel@tonic-gate print_dstname[0] = '\0'; 3810Sstevel@tonic-gate else 3820Sstevel@tonic-gate snprintf(print_dstname, sizeof (print_dstname), 3830Sstevel@tonic-gate ", %s", dst_name); 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate show_header("IPv6: ", "IPv6 Header", iplen); 3860Sstevel@tonic-gate show_space(); 3870Sstevel@tonic-gate 3881676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3890Sstevel@tonic-gate "Version = %d", version); 3901676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3910Sstevel@tonic-gate "Traffic Class = %d", class); 3921676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3930Sstevel@tonic-gate "Flow label = 0x%x", flow); 3941676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3951676Sjpk "Payload length = %d", iplen); 3961676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3971676Sjpk "Next Header = %d (%s)", proto, 3980Sstevel@tonic-gate getproto(proto)); 3991676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 4001676Sjpk "Hop Limit = %d", ip6h->ip6_hops); 4011676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 4020Sstevel@tonic-gate "Source address = %s%s", src_addrstr, print_srcname); 4031676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 4040Sstevel@tonic-gate "Destination address = %s%s", dst_addrstr, print_dstname); 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate show_space(); 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate /* 4100Sstevel@tonic-gate * Print IPv6 Extension Headers, or skip them in the summary case. 4110Sstevel@tonic-gate * Set isfrag to true if one of the extension headers encounterred 4120Sstevel@tonic-gate * was a fragment header. 4130Sstevel@tonic-gate */ 4140Sstevel@tonic-gate if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS || 4150Sstevel@tonic-gate proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) { 4160Sstevel@tonic-gate extmask = print_ipv6_extensions(flags, &data, &proto, &iplen, 4170Sstevel@tonic-gate &fraglen); 4180Sstevel@tonic-gate if ((extmask & SNOOP_FRAGMENT) != 0) { 4190Sstevel@tonic-gate isfrag = B_TRUE; 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate /* 4240Sstevel@tonic-gate * We only want to print upper layer information if this is not 4250Sstevel@tonic-gate * a fragment, or if we're printing in detail. Note that the 4260Sstevel@tonic-gate * proto variable will be set to IPPROTO_NONE if this is a fragment 4270Sstevel@tonic-gate * with a non-zero fragment offset. 4280Sstevel@tonic-gate */ 4290Sstevel@tonic-gate if (!isfrag || flags & F_DTAIL) { 4300Sstevel@tonic-gate /* go to the next protocol layer */ 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate switch (proto) { 4330Sstevel@tonic-gate case IPPROTO_IP: 4340Sstevel@tonic-gate break; 4350Sstevel@tonic-gate case IPPROTO_ENCAP: 4361676Sjpk /* LINTED: alignment */ 4371676Sjpk (void) interpret_ip(flags, (const struct ip *)data, 4381676Sjpk fraglen); 4390Sstevel@tonic-gate break; 4400Sstevel@tonic-gate case IPPROTO_ICMPV6: 4411676Sjpk /* LINTED: alignment */ 4421676Sjpk (void) interpret_icmpv6(flags, (icmp6_t *)data, iplen, 4430Sstevel@tonic-gate fraglen); 4440Sstevel@tonic-gate break; 4450Sstevel@tonic-gate case IPPROTO_IGMP: 4460Sstevel@tonic-gate interpret_igmp(flags, data, iplen, fraglen); 4470Sstevel@tonic-gate break; 4480Sstevel@tonic-gate case IPPROTO_GGP: 4490Sstevel@tonic-gate break; 4500Sstevel@tonic-gate case IPPROTO_TCP: 4511676Sjpk (void) interpret_tcp(flags, (struct tcphdr *)data, 4521676Sjpk iplen, fraglen); 4530Sstevel@tonic-gate break; 4540Sstevel@tonic-gate case IPPROTO_ESP: 4551676Sjpk (void) interpret_esp(flags, data, iplen, fraglen); 4560Sstevel@tonic-gate break; 4570Sstevel@tonic-gate case IPPROTO_AH: 4581676Sjpk (void) interpret_ah(flags, data, iplen, fraglen); 4590Sstevel@tonic-gate break; 4600Sstevel@tonic-gate case IPPROTO_EGP: 4610Sstevel@tonic-gate case IPPROTO_PUP: 4620Sstevel@tonic-gate break; 4630Sstevel@tonic-gate case IPPROTO_UDP: 4641676Sjpk (void) interpret_udp(flags, (struct udphdr *)data, 4651676Sjpk iplen, fraglen); 4660Sstevel@tonic-gate break; 4670Sstevel@tonic-gate case IPPROTO_IDP: 4680Sstevel@tonic-gate case IPPROTO_HELLO: 4690Sstevel@tonic-gate case IPPROTO_ND: 4700Sstevel@tonic-gate case IPPROTO_RAW: 4710Sstevel@tonic-gate break; 4720Sstevel@tonic-gate case IPPROTO_IPV6: 4731676Sjpk /* LINTED: alignment */ 4741676Sjpk (void) interpret_ipv6(flags, (const ip6_t *)data, 4751676Sjpk iplen); 4760Sstevel@tonic-gate break; 4770Sstevel@tonic-gate case IPPROTO_SCTP: 4781676Sjpk (void) interpret_sctp(flags, (struct sctp_hdr *)data, 4791676Sjpk iplen, fraglen); 4800Sstevel@tonic-gate break; 4810Sstevel@tonic-gate case IPPROTO_OSPF: 4820Sstevel@tonic-gate interpret_ospf6(flags, data, iplen, fraglen); 4830Sstevel@tonic-gate break; 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate return (iplen); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate /* 4910Sstevel@tonic-gate * ip_ext: data including the extension header. 4920Sstevel@tonic-gate * iplen: length of the data remaining in the packet. 4930Sstevel@tonic-gate * Returns a mask of IPv6 extension headers it processed. 4940Sstevel@tonic-gate */ 4950Sstevel@tonic-gate uint8_t 4960Sstevel@tonic-gate print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen, 4970Sstevel@tonic-gate int *fraglen) 4980Sstevel@tonic-gate { 4990Sstevel@tonic-gate uint8_t *data_ptr; 5000Sstevel@tonic-gate uchar_t proto = *next; 5010Sstevel@tonic-gate boolean_t is_extension_header; 5020Sstevel@tonic-gate struct ip6_hbh *ipv6ext_hbh; 5030Sstevel@tonic-gate struct ip6_dest *ipv6ext_dest; 5040Sstevel@tonic-gate struct ip6_rthdr *ipv6ext_rthdr; 5050Sstevel@tonic-gate struct ip6_frag *ipv6ext_frag; 5060Sstevel@tonic-gate uint32_t exthdrlen; 5070Sstevel@tonic-gate uint8_t extmask = 0; 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate if ((hdr == NULL) || (*hdr == NULL) || (next == NULL) || (iplen == 0)) 5100Sstevel@tonic-gate return (0); 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate data_ptr = *hdr; 5130Sstevel@tonic-gate is_extension_header = B_TRUE; 5140Sstevel@tonic-gate while (is_extension_header) { 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate /* 5170Sstevel@tonic-gate * There must be at least enough data left to read the 5180Sstevel@tonic-gate * next header and header length fields from the next 5190Sstevel@tonic-gate * header. 5200Sstevel@tonic-gate */ 5210Sstevel@tonic-gate if (*fraglen < 2) { 5220Sstevel@tonic-gate return (extmask); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate switch (proto) { 5260Sstevel@tonic-gate case IPPROTO_HOPOPTS: 5270Sstevel@tonic-gate ipv6ext_hbh = (struct ip6_hbh *)data_ptr; 5280Sstevel@tonic-gate exthdrlen = 8 + ipv6ext_hbh->ip6h_len * 8; 5290Sstevel@tonic-gate if (*fraglen <= exthdrlen) { 5300Sstevel@tonic-gate return (extmask); 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate prt_hbh_options(flags, ipv6ext_hbh); 5330Sstevel@tonic-gate extmask |= SNOOP_HOPOPTS; 5340Sstevel@tonic-gate proto = ipv6ext_hbh->ip6h_nxt; 5350Sstevel@tonic-gate break; 5360Sstevel@tonic-gate case IPPROTO_DSTOPTS: 5370Sstevel@tonic-gate ipv6ext_dest = (struct ip6_dest *)data_ptr; 5380Sstevel@tonic-gate exthdrlen = 8 + ipv6ext_dest->ip6d_len * 8; 5390Sstevel@tonic-gate if (*fraglen <= exthdrlen) { 5400Sstevel@tonic-gate return (extmask); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate prt_dest_options(flags, ipv6ext_dest); 5430Sstevel@tonic-gate extmask |= SNOOP_DSTOPTS; 5440Sstevel@tonic-gate proto = ipv6ext_dest->ip6d_nxt; 5450Sstevel@tonic-gate break; 5460Sstevel@tonic-gate case IPPROTO_ROUTING: 5470Sstevel@tonic-gate ipv6ext_rthdr = (struct ip6_rthdr *)data_ptr; 5480Sstevel@tonic-gate exthdrlen = 8 + ipv6ext_rthdr->ip6r_len * 8; 5490Sstevel@tonic-gate if (*fraglen <= exthdrlen) { 5500Sstevel@tonic-gate return (extmask); 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate prt_routing_hdr(flags, ipv6ext_rthdr); 5530Sstevel@tonic-gate extmask |= SNOOP_ROUTING; 5540Sstevel@tonic-gate proto = ipv6ext_rthdr->ip6r_nxt; 5550Sstevel@tonic-gate break; 5560Sstevel@tonic-gate case IPPROTO_FRAGMENT: 5571676Sjpk /* LINTED: alignment */ 5580Sstevel@tonic-gate ipv6ext_frag = (struct ip6_frag *)data_ptr; 5590Sstevel@tonic-gate exthdrlen = sizeof (struct ip6_frag); 5600Sstevel@tonic-gate if (*fraglen <= exthdrlen) { 5610Sstevel@tonic-gate return (extmask); 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate prt_fragment_hdr(flags, ipv6ext_frag); 5640Sstevel@tonic-gate extmask |= SNOOP_FRAGMENT; 5650Sstevel@tonic-gate /* 5660Sstevel@tonic-gate * If this is not the first fragment, forget about 5670Sstevel@tonic-gate * the rest of the packet, snoop decoding is 5680Sstevel@tonic-gate * stateless. 5690Sstevel@tonic-gate */ 5700Sstevel@tonic-gate if ((ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK) != 0) 5710Sstevel@tonic-gate proto = IPPROTO_NONE; 5720Sstevel@tonic-gate else 5730Sstevel@tonic-gate proto = ipv6ext_frag->ip6f_nxt; 5740Sstevel@tonic-gate break; 5750Sstevel@tonic-gate default: 5760Sstevel@tonic-gate is_extension_header = B_FALSE; 5770Sstevel@tonic-gate break; 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate if (is_extension_header) { 5810Sstevel@tonic-gate *iplen -= exthdrlen; 5820Sstevel@tonic-gate *fraglen -= exthdrlen; 5830Sstevel@tonic-gate data_ptr += exthdrlen; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate *next = proto; 5880Sstevel@tonic-gate *hdr = data_ptr; 5890Sstevel@tonic-gate return (extmask); 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate static void 5931676Sjpk print_ipoptions(const uchar_t *opt, int optlen) 5940Sstevel@tonic-gate { 5950Sstevel@tonic-gate int len; 5961676Sjpk int remain; 5970Sstevel@tonic-gate char *line; 5981676Sjpk const char *truncstr; 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate if (optlen <= 0) { 6011676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 6020Sstevel@tonic-gate "No options"); 6030Sstevel@tonic-gate return; 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate 6061676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 6070Sstevel@tonic-gate "Options: (%d bytes)", optlen); 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate while (optlen > 0) { 6101676Sjpk line = get_line(0, 0); 6111676Sjpk remain = get_line_remain(); 6120Sstevel@tonic-gate len = opt[1]; 6131676Sjpk truncstr = len > optlen ? "?" : ""; 6140Sstevel@tonic-gate switch (opt[0]) { 6150Sstevel@tonic-gate case IPOPT_EOL: 6161676Sjpk (void) strlcpy(line, " - End of option list", remain); 6170Sstevel@tonic-gate return; 6180Sstevel@tonic-gate case IPOPT_NOP: 6191676Sjpk (void) strlcpy(line, " - No op", remain); 6200Sstevel@tonic-gate len = 1; 6210Sstevel@tonic-gate break; 6220Sstevel@tonic-gate case IPOPT_RR: 6231676Sjpk (void) snprintf(line, remain, 6241676Sjpk " - Record route (%d bytes%s)", len, truncstr); 6250Sstevel@tonic-gate print_route(opt); 6260Sstevel@tonic-gate break; 6270Sstevel@tonic-gate case IPOPT_TS: 6281676Sjpk (void) snprintf(line, remain, 6291676Sjpk " - Time stamp (%d bytes%s)", len, truncstr); 6300Sstevel@tonic-gate break; 6310Sstevel@tonic-gate case IPOPT_SECURITY: 6321676Sjpk (void) snprintf(line, remain, " - RIPSO (%d bytes%s)", 6331676Sjpk len, truncstr); 6341676Sjpk print_ripso(opt); 6351676Sjpk break; 6361676Sjpk case IPOPT_COMSEC: 6371676Sjpk (void) snprintf(line, remain, " - CIPSO (%d bytes%s)", 6381676Sjpk len, truncstr); 6391676Sjpk print_cipso(opt); 6400Sstevel@tonic-gate break; 6410Sstevel@tonic-gate case IPOPT_LSRR: 6421676Sjpk (void) snprintf(line, remain, 6431676Sjpk " - Loose source route (%d bytes%s)", len, 6441676Sjpk truncstr); 6450Sstevel@tonic-gate print_route(opt); 6460Sstevel@tonic-gate break; 6470Sstevel@tonic-gate case IPOPT_SATID: 6481676Sjpk (void) snprintf(line, remain, 6491676Sjpk " - SATNET Stream id (%d bytes%s)", 6501676Sjpk len, truncstr); 6510Sstevel@tonic-gate break; 6520Sstevel@tonic-gate case IPOPT_SSRR: 6531676Sjpk (void) snprintf(line, remain, 6541676Sjpk " - Strict source route, (%d bytes%s)", len, 6551676Sjpk truncstr); 6560Sstevel@tonic-gate print_route(opt); 6570Sstevel@tonic-gate break; 6580Sstevel@tonic-gate default: 6591676Sjpk (void) snprintf(line, remain, 6601676Sjpk " - Option %d (unknown - %d bytes%s) %s", 6611676Sjpk opt[0], len, truncstr, 6621676Sjpk tohex((char *)&opt[2], len - 2)); 6630Sstevel@tonic-gate break; 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate if (len <= 0) { 6661676Sjpk (void) snprintf(line, remain, 6671676Sjpk " - Incomplete option len %d", len); 6680Sstevel@tonic-gate break; 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate opt += len; 6710Sstevel@tonic-gate optlen -= len; 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate static void 6761676Sjpk print_route(const uchar_t *opt) 6770Sstevel@tonic-gate { 6781676Sjpk int len, pointer, remain; 6790Sstevel@tonic-gate struct in_addr addr; 6800Sstevel@tonic-gate char *line; 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate len = opt[1]; 6830Sstevel@tonic-gate pointer = opt[2]; 6840Sstevel@tonic-gate 6851676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 6860Sstevel@tonic-gate " Pointer = %d", pointer); 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate pointer -= IPOPT_MINOFF; 6890Sstevel@tonic-gate opt += (IPOPT_OFFSET + 1); 6900Sstevel@tonic-gate len -= (IPOPT_OFFSET + 1); 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate while (len > 0) { 6931676Sjpk line = get_line(0, 0); 6941676Sjpk remain = get_line_remain(); 6950Sstevel@tonic-gate memcpy((char *)&addr, opt, sizeof (addr)); 6960Sstevel@tonic-gate if (addr.s_addr == INADDR_ANY) 6971676Sjpk (void) strlcpy(line, " -", remain); 6980Sstevel@tonic-gate else 6991676Sjpk (void) snprintf(line, remain, " %s", 7000Sstevel@tonic-gate addrtoname(AF_INET, &addr)); 7010Sstevel@tonic-gate if (pointer == 0) 7021676Sjpk (void) strlcat(line, " <-- (current)", remain); 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate opt += sizeof (addr); 7050Sstevel@tonic-gate len -= sizeof (addr); 7060Sstevel@tonic-gate pointer -= sizeof (addr); 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate char * 7111676Sjpk getproto(int p) 7120Sstevel@tonic-gate { 7130Sstevel@tonic-gate switch (p) { 7140Sstevel@tonic-gate case IPPROTO_HOPOPTS: return ("IPv6-HopOpts"); 7150Sstevel@tonic-gate case IPPROTO_IPV6: return ("IPv6"); 7160Sstevel@tonic-gate case IPPROTO_ROUTING: return ("IPv6-Route"); 7170Sstevel@tonic-gate case IPPROTO_FRAGMENT: return ("IPv6-Frag"); 7180Sstevel@tonic-gate case IPPROTO_RSVP: return ("RSVP"); 7190Sstevel@tonic-gate case IPPROTO_ENCAP: return ("IP-in-IP"); 7200Sstevel@tonic-gate case IPPROTO_AH: return ("AH"); 7210Sstevel@tonic-gate case IPPROTO_ESP: return ("ESP"); 7220Sstevel@tonic-gate case IPPROTO_ICMP: return ("ICMP"); 7230Sstevel@tonic-gate case IPPROTO_ICMPV6: return ("ICMPv6"); 7240Sstevel@tonic-gate case IPPROTO_DSTOPTS: return ("IPv6-DstOpts"); 7250Sstevel@tonic-gate case IPPROTO_IGMP: return ("IGMP"); 7260Sstevel@tonic-gate case IPPROTO_GGP: return ("GGP"); 7270Sstevel@tonic-gate case IPPROTO_TCP: return ("TCP"); 7280Sstevel@tonic-gate case IPPROTO_EGP: return ("EGP"); 7290Sstevel@tonic-gate case IPPROTO_PUP: return ("PUP"); 7300Sstevel@tonic-gate case IPPROTO_UDP: return ("UDP"); 7310Sstevel@tonic-gate case IPPROTO_IDP: return ("IDP"); 7320Sstevel@tonic-gate case IPPROTO_HELLO: return ("HELLO"); 7330Sstevel@tonic-gate case IPPROTO_ND: return ("ND"); 7340Sstevel@tonic-gate case IPPROTO_EON: return ("EON"); 7350Sstevel@tonic-gate case IPPROTO_RAW: return ("RAW"); 7360Sstevel@tonic-gate case IPPROTO_OSPF: return ("OSPF"); 7370Sstevel@tonic-gate default: return (""); 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate } 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate static void 7421676Sjpk prt_routing_hdr(int flags, const struct ip6_rthdr *ipv6ext_rthdr) 7430Sstevel@tonic-gate { 7440Sstevel@tonic-gate uint8_t nxt_hdr; 7450Sstevel@tonic-gate uint8_t type; 7460Sstevel@tonic-gate uint32_t len; 7470Sstevel@tonic-gate uint8_t segleft; 7480Sstevel@tonic-gate uint32_t numaddrs; 7490Sstevel@tonic-gate int i; 7500Sstevel@tonic-gate struct ip6_rthdr0 *ipv6ext_rthdr0; 7510Sstevel@tonic-gate struct in6_addr *addrs; 7520Sstevel@tonic-gate char addr[INET6_ADDRSTRLEN]; 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate /* in summary mode, we don't do anything. */ 7550Sstevel@tonic-gate if (flags & F_SUM) { 7560Sstevel@tonic-gate return; 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate nxt_hdr = ipv6ext_rthdr->ip6r_nxt; 7600Sstevel@tonic-gate type = ipv6ext_rthdr->ip6r_type; 7610Sstevel@tonic-gate len = 8 * (ipv6ext_rthdr->ip6r_len + 1); 7620Sstevel@tonic-gate segleft = ipv6ext_rthdr->ip6r_segleft; 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate show_header("IPv6-Route: ", "IPv6 Routing Header", 0); 7650Sstevel@tonic-gate show_space(); 7660Sstevel@tonic-gate 7671676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7680Sstevel@tonic-gate "Next header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 7691676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7700Sstevel@tonic-gate "Header length = %d", len); 7711676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7720Sstevel@tonic-gate "Routing type = %d", type); 7731676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7740Sstevel@tonic-gate "Segments left = %d", segleft); 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate if (type == IPV6_RTHDR_TYPE_0) { 7770Sstevel@tonic-gate /* 7780Sstevel@tonic-gate * XXX This loop will print all addresses in the routing header, 7790Sstevel@tonic-gate * XXX not just the segments left. 7800Sstevel@tonic-gate * XXX (The header length field is twice the number of 7810Sstevel@tonic-gate * XXX addresses) 7820Sstevel@tonic-gate * XXX At some future time, we may want to change this 7830Sstevel@tonic-gate * XXX to differentiate between the hops yet to do 7840Sstevel@tonic-gate * XXX and the hops already taken. 7850Sstevel@tonic-gate */ 7861676Sjpk /* LINTED: alignment */ 7870Sstevel@tonic-gate ipv6ext_rthdr0 = (struct ip6_rthdr0 *)ipv6ext_rthdr; 7880Sstevel@tonic-gate numaddrs = ipv6ext_rthdr0->ip6r0_len / 2; 7890Sstevel@tonic-gate addrs = (struct in6_addr *)(ipv6ext_rthdr0 + 1); 7900Sstevel@tonic-gate for (i = 0; i < numaddrs; i++) { 7910Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &addrs[i], addr, 7920Sstevel@tonic-gate INET6_ADDRSTRLEN); 7931676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7940Sstevel@tonic-gate "address[%d]=%s", i, addr); 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate show_space(); 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate static void 8021676Sjpk prt_fragment_hdr(int flags, const struct ip6_frag *ipv6ext_frag) 8030Sstevel@tonic-gate { 8040Sstevel@tonic-gate boolean_t morefrag; 8050Sstevel@tonic-gate uint16_t fragoffset; 8060Sstevel@tonic-gate uint8_t nxt_hdr; 8070Sstevel@tonic-gate uint32_t fragident; 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate /* extract the various fields from the fragment header */ 8100Sstevel@tonic-gate nxt_hdr = ipv6ext_frag->ip6f_nxt; 8110Sstevel@tonic-gate morefrag = (ipv6ext_frag->ip6f_offlg & IP6F_MORE_FRAG) == 0 8120Sstevel@tonic-gate ? B_FALSE : B_TRUE; 8130Sstevel@tonic-gate fragoffset = ntohs(ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK); 8140Sstevel@tonic-gate fragident = ntohl(ipv6ext_frag->ip6f_ident); 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate if (flags & F_SUM) { 8171676Sjpk (void) snprintf(get_sum_line(), MAXLINE, 8180Sstevel@tonic-gate "IPv6 fragment ID=%d Offset=%-4d MF=%d", 8190Sstevel@tonic-gate fragident, 8200Sstevel@tonic-gate fragoffset, 8210Sstevel@tonic-gate morefrag); 8220Sstevel@tonic-gate } else { /* F_DTAIL */ 8230Sstevel@tonic-gate show_header("IPv6-Frag: ", "IPv6 Fragment Header", 0); 8240Sstevel@tonic-gate show_space(); 8250Sstevel@tonic-gate 8261676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8270Sstevel@tonic-gate "Next Header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 8281676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8290Sstevel@tonic-gate "Fragment Offset = %d", fragoffset); 8301676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8310Sstevel@tonic-gate "More Fragments Flag = %s", morefrag ? "true" : "false"); 8321676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8330Sstevel@tonic-gate "Identification = %d", fragident); 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate show_space(); 8360Sstevel@tonic-gate } 8370Sstevel@tonic-gate } 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate static void 8401676Sjpk print_ip6opt_ls(const uchar_t *data, unsigned int op_len) 8410Sstevel@tonic-gate { 8421676Sjpk uint32_t doi; 8431676Sjpk uint8_t sotype, solen; 8441676Sjpk uint16_t value, value2; 8451676Sjpk char *cp; 8461676Sjpk int remlen; 8471676Sjpk boolean_t printed; 8481676Sjpk 8491676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8501676Sjpk "Labeled Security Option len = %u bytes%s", op_len, 8511676Sjpk op_len < sizeof (uint32_t) || (op_len & 1) != 0 ? "?" : ""); 8521676Sjpk if (op_len < sizeof (uint32_t)) 8531676Sjpk return; 8541676Sjpk GETINT32(doi, data); 8551676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8561676Sjpk " DOI = %d (%s)", doi, doi == IP6LS_DOI_V4 ? "IPv4" : "???"); 8571676Sjpk op_len -= sizeof (uint32_t); 8581676Sjpk while (op_len > 0) { 8591676Sjpk GETINT8(sotype, data); 8601676Sjpk if (op_len < 2) { 8611676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8621676Sjpk " truncated %u suboption (no len)", sotype); 8631676Sjpk break; 8641676Sjpk } 8651676Sjpk GETINT8(solen, data); 8661676Sjpk if (solen < 2 || solen > op_len) { 8671676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8681676Sjpk " bad %u suboption (len 2 <= %u <= %u)", 8691676Sjpk sotype, solen, op_len); 8701676Sjpk if (solen < 2) 8711676Sjpk solen = 2; 8721676Sjpk if (solen > op_len) 8731676Sjpk solen = op_len; 8741676Sjpk } 8751676Sjpk op_len -= solen; 8761676Sjpk solen -= 2; 8771676Sjpk cp = get_line(0, 0); 8781676Sjpk remlen = get_line_remain(); 8791676Sjpk (void) strlcpy(cp, " ", remlen); 8801676Sjpk cp += 4; 8811676Sjpk remlen -= 4; 8821676Sjpk printed = B_TRUE; 8831676Sjpk switch (sotype) { 8841676Sjpk case IP6LS_TT_LEVEL: 8851676Sjpk if (solen != 2) { 8861676Sjpk printed = B_FALSE; 8871676Sjpk break; 8881676Sjpk } 8891676Sjpk GETINT16(value, data); 8901676Sjpk (void) snprintf(cp, remlen, "Level %u", value); 8911676Sjpk solen = 0; 8921676Sjpk break; 8931676Sjpk case IP6LS_TT_VECTOR: 8941676Sjpk (void) strlcpy(cp, "Bit-Vector: ", remlen); 8951676Sjpk remlen -= strlen(cp); 8961676Sjpk cp += strlen(cp); 8971676Sjpk while (solen > 1) { 8981676Sjpk GETINT16(value, data); 8991676Sjpk solen -= 2; 9001676Sjpk (void) snprintf(cp, remlen, "%04x", value); 9011676Sjpk remlen -= strlen(cp); 9021676Sjpk cp += strlen(cp); 9031676Sjpk } 9041676Sjpk break; 9051676Sjpk case IP6LS_TT_ENUM: 9061676Sjpk (void) strlcpy(cp, "Enumeration:", remlen); 9071676Sjpk remlen -= strlen(cp); 9081676Sjpk cp += strlen(cp); 9091676Sjpk while (solen > 1) { 9101676Sjpk GETINT16(value, data); 9111676Sjpk solen -= 2; 9121676Sjpk (void) snprintf(cp, remlen, " %u", value); 9131676Sjpk remlen -= strlen(cp); 9141676Sjpk cp += strlen(cp); 9151676Sjpk } 9161676Sjpk break; 9171676Sjpk case IP6LS_TT_RANGES: 9181676Sjpk (void) strlcpy(cp, "Ranges:", remlen); 9191676Sjpk remlen -= strlen(cp); 9201676Sjpk cp += strlen(cp); 9211676Sjpk while (solen > 3) { 9221676Sjpk GETINT16(value, data); 9231676Sjpk GETINT16(value2, data); 9241676Sjpk solen -= 4; 9251676Sjpk (void) snprintf(cp, remlen, " %u-%u", value, 9261676Sjpk value2); 9271676Sjpk remlen -= strlen(cp); 9281676Sjpk cp += strlen(cp); 9291676Sjpk } 9301676Sjpk break; 9311676Sjpk case IP6LS_TT_V4: 9321676Sjpk (void) strlcpy(cp, "IPv4 Option", remlen); 9331676Sjpk print_ipoptions(data, solen); 9341676Sjpk solen = 0; 9351676Sjpk break; 9361676Sjpk case IP6LS_TT_DEST: 9371676Sjpk (void) snprintf(cp, remlen, 9381676Sjpk "Destination-Only Data length %u", solen); 9391676Sjpk solen = 0; 9401676Sjpk break; 9411676Sjpk default: 9421676Sjpk (void) snprintf(cp, remlen, 9431676Sjpk " unknown %u suboption (len %u)", sotype, solen); 9441676Sjpk solen = 0; 9451676Sjpk break; 9461676Sjpk } 9471676Sjpk if (solen != 0) { 9481676Sjpk if (printed) { 9491676Sjpk cp = get_line(0, 0); 9501676Sjpk remlen = get_line_remain(); 9511676Sjpk } 9521676Sjpk (void) snprintf(cp, remlen, 9531676Sjpk " malformed %u suboption (remaining %u)", 9541676Sjpk sotype, solen); 9551676Sjpk data += solen; 9561676Sjpk } 9571676Sjpk } 9581676Sjpk } 9591676Sjpk 9601676Sjpk static void 9611676Sjpk prt_hbh_options(int flags, const struct ip6_hbh *ipv6ext_hbh) 9621676Sjpk { 9631676Sjpk const uint8_t *data, *ndata; 9641676Sjpk uint32_t len; 9650Sstevel@tonic-gate uint8_t op_type; 9660Sstevel@tonic-gate uint8_t op_len; 9670Sstevel@tonic-gate uint8_t nxt_hdr; 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate /* in summary mode, we don't do anything. */ 9700Sstevel@tonic-gate if (flags & F_SUM) { 9710Sstevel@tonic-gate return; 9720Sstevel@tonic-gate } 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate show_header("IPv6-HopOpts: ", "IPv6 Hop-by-Hop Options Header", 0); 9750Sstevel@tonic-gate show_space(); 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate /* 9780Sstevel@tonic-gate * Store the lengh of this ext hdr in bytes. The caller has 9790Sstevel@tonic-gate * ensured that there is at least len bytes of data left. 9800Sstevel@tonic-gate */ 9810Sstevel@tonic-gate len = ipv6ext_hbh->ip6h_len * 8 + 8; 9820Sstevel@tonic-gate 9831676Sjpk ndata = (const uint8_t *)ipv6ext_hbh + 2; 9840Sstevel@tonic-gate len -= 2; 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate nxt_hdr = ipv6ext_hbh->ip6h_nxt; 9871676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 9880Sstevel@tonic-gate "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr)); 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate while (len > 0) { 9911676Sjpk data = ndata; 9920Sstevel@tonic-gate GETINT8(op_type, data); 9931676Sjpk /* This is the only one-octet IPv6 option */ 9941676Sjpk if (op_type == IP6OPT_PAD1) { 9951676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 9960Sstevel@tonic-gate "pad1 option "); 9970Sstevel@tonic-gate len--; 9981676Sjpk ndata = data; 9991676Sjpk continue; 10001676Sjpk } 10011676Sjpk GETINT8(op_len, data); 10021676Sjpk if (len < 2 || op_len + 2 > len) { 10031676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 10041676Sjpk "Error: option %u truncated (%u + 2 > %u)", 10051676Sjpk op_type, op_len, len); 10061676Sjpk op_len = len - 2; 10071676Sjpk /* 10081676Sjpk * Continue processing the malformed option so that we 10091676Sjpk * can display as much as possible. 10101676Sjpk */ 10111676Sjpk } 10121676Sjpk 10131676Sjpk /* advance pointers to the next option */ 10141676Sjpk len -= op_len + 2; 10151676Sjpk ndata = data + op_len; 10161676Sjpk 10171676Sjpk /* process this option */ 10181676Sjpk switch (op_type) { 10190Sstevel@tonic-gate case IP6OPT_PADN: 10201676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 10210Sstevel@tonic-gate "padN option len = %u", op_len); 10220Sstevel@tonic-gate break; 10230Sstevel@tonic-gate case IP6OPT_JUMBO: { 10240Sstevel@tonic-gate uint32_t payload_len; 10250Sstevel@tonic-gate 10261676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 10271676Sjpk "Jumbo Payload Option len = %u bytes%s", op_len, 10281676Sjpk op_len == sizeof (uint32_t) ? "" : "?"); 10290Sstevel@tonic-gate if (op_len == sizeof (uint32_t)) { 10300Sstevel@tonic-gate GETINT32(payload_len, data); 10311676Sjpk (void) snprintf(get_line(0, 0), 10321676Sjpk get_line_remain(), 10330Sstevel@tonic-gate "Jumbo Payload Length = %u bytes", 10340Sstevel@tonic-gate payload_len); 10350Sstevel@tonic-gate } 10360Sstevel@tonic-gate break; 10370Sstevel@tonic-gate } 10380Sstevel@tonic-gate case IP6OPT_ROUTER_ALERT: { 10390Sstevel@tonic-gate uint16_t value; 10400Sstevel@tonic-gate const char *label[] = {"MLD", "RSVP", "AN"}; 10410Sstevel@tonic-gate 10421676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 10431676Sjpk "Router Alert Option len = %u bytes%s", op_len, 10441676Sjpk op_len == sizeof (uint16_t) ? "" : "?"); 10450Sstevel@tonic-gate if (op_len == sizeof (uint16_t)) { 10460Sstevel@tonic-gate GETINT16(value, data); 10471676Sjpk (void) snprintf(get_line(0, 0), 10481676Sjpk get_line_remain(), 10490Sstevel@tonic-gate "Alert Type = %d (%s)", value, 10500Sstevel@tonic-gate value < sizeof (label) / sizeof (label[0]) ? 10510Sstevel@tonic-gate label[value] : "???"); 10520Sstevel@tonic-gate } 10530Sstevel@tonic-gate break; 10540Sstevel@tonic-gate } 10551676Sjpk case IP6OPT_LS: 10561676Sjpk print_ip6opt_ls(data, op_len); 10571676Sjpk break; 10580Sstevel@tonic-gate default: 10591676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 10600Sstevel@tonic-gate "Option type = %u, len = %u", op_type, op_len); 10610Sstevel@tonic-gate break; 10620Sstevel@tonic-gate } 10630Sstevel@tonic-gate } 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate show_space(); 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate static void 10691676Sjpk prt_dest_options(int flags, const struct ip6_dest *ipv6ext_dest) 10700Sstevel@tonic-gate { 10711676Sjpk const uint8_t *data, *ndata; 10721676Sjpk uint32_t len; 10730Sstevel@tonic-gate uint8_t op_type; 10740Sstevel@tonic-gate uint32_t op_len; 10750Sstevel@tonic-gate uint8_t nxt_hdr; 10760Sstevel@tonic-gate uint8_t value; 10770Sstevel@tonic-gate 10780Sstevel@tonic-gate /* in summary mode, we don't do anything. */ 10790Sstevel@tonic-gate if (flags & F_SUM) { 10800Sstevel@tonic-gate return; 10810Sstevel@tonic-gate } 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate show_header("IPv6-DstOpts: ", "IPv6 Destination Options Header", 0); 10840Sstevel@tonic-gate show_space(); 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate /* 10870Sstevel@tonic-gate * Store the length of this ext hdr in bytes. The caller has 10880Sstevel@tonic-gate * ensured that there is at least len bytes of data left. 10890Sstevel@tonic-gate */ 10900Sstevel@tonic-gate len = ipv6ext_dest->ip6d_len * 8 + 8; 10910Sstevel@tonic-gate 10921676Sjpk ndata = (const uint8_t *)ipv6ext_dest + 2; /* skip hdr/len */ 10930Sstevel@tonic-gate len -= 2; 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate nxt_hdr = ipv6ext_dest->ip6d_nxt; 10961676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 10970Sstevel@tonic-gate "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr)); 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate while (len > 0) { 11001676Sjpk data = ndata; 11010Sstevel@tonic-gate GETINT8(op_type, data); 11021676Sjpk if (op_type == IP6OPT_PAD1) { 11031676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 11040Sstevel@tonic-gate "pad1 option "); 11050Sstevel@tonic-gate len--; 11061676Sjpk ndata = data; 11071676Sjpk continue; 11081676Sjpk } 11091676Sjpk GETINT8(op_len, data); 11101676Sjpk if (len < 2 || op_len + 2 > len) { 11111676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 11121676Sjpk "Error: option %u truncated (%u + 2 > %u)", 11131676Sjpk op_type, op_len, len); 11141676Sjpk op_len = len - 2; 11151676Sjpk /* 11161676Sjpk * Continue processing the malformed option so that we 11171676Sjpk * can display as much as possible. 11181676Sjpk */ 11191676Sjpk } 11201676Sjpk 11211676Sjpk /* advance pointers to the next option */ 11221676Sjpk len -= op_len + 2; 11231676Sjpk ndata = data + op_len; 11241676Sjpk 11251676Sjpk /* process this option */ 11261676Sjpk switch (op_type) { 11270Sstevel@tonic-gate case IP6OPT_PADN: 11281676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 11290Sstevel@tonic-gate "padN option len = %u", op_len); 11300Sstevel@tonic-gate break; 11310Sstevel@tonic-gate case IP6OPT_TUNNEL_LIMIT: 11320Sstevel@tonic-gate GETINT8(value, data); 11331676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 11340Sstevel@tonic-gate "tunnel encapsulation limit len = %d, value = %d", 11350Sstevel@tonic-gate op_len, value); 11361676Sjpk break; 11371676Sjpk case IP6OPT_LS: 11381676Sjpk print_ip6opt_ls(data, op_len); 11390Sstevel@tonic-gate break; 11400Sstevel@tonic-gate default: 11411676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 11420Sstevel@tonic-gate "Option type = %u, len = %u", op_type, op_len); 11430Sstevel@tonic-gate break; 11440Sstevel@tonic-gate } 11450Sstevel@tonic-gate } 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate show_space(); 11480Sstevel@tonic-gate } 11491676Sjpk 11501676Sjpk #define ALABEL_MAXLEN 256 11511676Sjpk 11521676Sjpk static char ascii_label[ALABEL_MAXLEN]; 11531676Sjpk static char *plabel = ascii_label; 11541676Sjpk 11551676Sjpk struct snoop_pair { 11561676Sjpk int val; 11571676Sjpk const char *name; 11581676Sjpk }; 11591676Sjpk 11601676Sjpk static struct snoop_pair ripso_class_tbl[] = { 11611676Sjpk TSOL_CL_TOP_SECRET, "TOP SECRET", 11621676Sjpk TSOL_CL_SECRET, "SECRET", 11631676Sjpk TSOL_CL_CONFIDENTIAL, "CONFIDENTIAL", 11641676Sjpk TSOL_CL_UNCLASSIFIED, "UNCLASSIFIED", 11651676Sjpk -1, NULL 11661676Sjpk }; 11671676Sjpk 11681676Sjpk static struct snoop_pair ripso_prot_tbl[] = { 11691676Sjpk TSOL_PA_GENSER, "GENSER", 11701676Sjpk TSOL_PA_SIOP_ESI, "SIOP-ESI", 11711676Sjpk TSOL_PA_SCI, "SCI", 11721676Sjpk TSOL_PA_NSA, "NSA", 11731676Sjpk TSOL_PA_DOE, "DOE", 11741676Sjpk 0x04, "UNASSIGNED", 11751676Sjpk 0x02, "UNASSIGNED", 11761676Sjpk -1, NULL 11771676Sjpk }; 11781676Sjpk 11791676Sjpk static struct snoop_pair * 11801676Sjpk get_pair_byval(struct snoop_pair pairlist[], int val) 11811676Sjpk { 11821676Sjpk int i; 11831676Sjpk 11841676Sjpk for (i = 0; pairlist[i].name != NULL; i++) 11851676Sjpk if (pairlist[i].val == val) 11861676Sjpk return (&pairlist[i]); 11871676Sjpk return (NULL); 11881676Sjpk } 11891676Sjpk 11901676Sjpk static void 11911676Sjpk print_ripso(const uchar_t *opt) 11921676Sjpk { 11931676Sjpk struct snoop_pair *ripso_class; 11941676Sjpk int i, index, prot_len; 11951676Sjpk boolean_t first_prot; 11961676Sjpk char line[100], *ptr; 11971676Sjpk 11981676Sjpk prot_len = opt[1] - 3; 11991676Sjpk if (prot_len < 0) 12001676Sjpk return; 12011676Sjpk 12021676Sjpk show_header("RIPSO: ", "Revised IP Security Option", 0); 12031676Sjpk show_space(); 12041676Sjpk 12051676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 12061676Sjpk "Type = Basic Security Option (%d), Length = %d", opt[0], opt[1]); 12071676Sjpk 12081676Sjpk /* 12091676Sjpk * Display Classification Level 12101676Sjpk */ 12111676Sjpk ripso_class = get_pair_byval(ripso_class_tbl, (int)opt[2]); 12121676Sjpk if (ripso_class != NULL) 12131676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 12141676Sjpk "Classification = Unknown (0x%02x)", opt[2]); 12151676Sjpk else 12161676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 12171676Sjpk "Classification = %s (0x%02x)", 12181676Sjpk ripso_class->name, ripso_class->val); 12191676Sjpk 12201676Sjpk /* 12211676Sjpk * Display Protection Authority Flags 12221676Sjpk */ 12231676Sjpk (void) snprintf(line, sizeof (line), "Protection Authority = "); 12241676Sjpk ptr = line; 12251676Sjpk first_prot = B_TRUE; 12261676Sjpk for (i = 0; i < prot_len; i++) { 12271676Sjpk index = 0; 12281676Sjpk while (ripso_prot_tbl[index].name != NULL) { 12291676Sjpk if (opt[3 + i] & ripso_prot_tbl[index].val) { 12301676Sjpk ptr = strchr(ptr, 0); 12311676Sjpk if (!first_prot) { 12321676Sjpk (void) strlcpy(ptr, ", ", 12331676Sjpk sizeof (line) - (ptr - line)); 12341676Sjpk ptr = strchr(ptr, 0); 12351676Sjpk } 12361676Sjpk (void) snprintf(ptr, 12371676Sjpk sizeof (line) - (ptr - line), 12381676Sjpk "%s (0x%02x)", 12391676Sjpk ripso_prot_tbl[index].name, 12401676Sjpk ripso_prot_tbl[index].val); 12411676Sjpk } 12421676Sjpk index++; 12431676Sjpk } 12441676Sjpk if ((opt[3 + i] & 1) == 0) 12451676Sjpk break; 12461676Sjpk } 12471676Sjpk if (!first_prot) 12481676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), "%s", line); 12491676Sjpk else 12501676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), "%sNone", 12511676Sjpk line); 12521676Sjpk } 12531676Sjpk 12541676Sjpk #define CIPSO_GENERIC_ARRAY_LEN 200 12551676Sjpk 12561676Sjpk /* 12571676Sjpk * Return 1 if CIPSO SL and Categories are all 1's; 0 otherwise. 12581676Sjpk * 12591676Sjpk * Note: opt starts with "Tag Type": 12601676Sjpk * 12611676Sjpk * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)| 12621676Sjpk * 12631676Sjpk */ 12641676Sjpk static boolean_t 12651676Sjpk cipso_high(const uchar_t *opt) 12661676Sjpk { 12671676Sjpk int i; 12681676Sjpk 12691676Sjpk if (((int)opt[1] + 6) < IP_MAX_OPT_LENGTH) 12701676Sjpk return (B_FALSE); 12711676Sjpk for (i = 0; i < ((int)opt[1] - 3); i++) 12721676Sjpk if (opt[3 + i] != 0xff) 12731676Sjpk return (B_FALSE); 12741676Sjpk return (B_TRUE); 12751676Sjpk } 12761676Sjpk 12771676Sjpk /* 12781676Sjpk * Converts CIPSO label to SL. 12791676Sjpk * 12801676Sjpk * Note: opt starts with "Tag Type": 12811676Sjpk * 12821676Sjpk * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)| 12831676Sjpk * 12841676Sjpk */ 12851676Sjpk static void 12861676Sjpk cipso2sl(const uchar_t *opt, bslabel_t *sl, int *high) 12871676Sjpk { 12881676Sjpk int i, taglen; 12891676Sjpk uchar_t *q = (uchar_t *)&((_bslabel_impl_t *)sl)->compartments; 12901676Sjpk 12911676Sjpk *high = 0; 12921676Sjpk taglen = opt[1]; 12931676Sjpk memset((caddr_t)sl, 0, sizeof (bslabel_t)); 12941676Sjpk 12951676Sjpk if (cipso_high(opt)) { 12961676Sjpk BSLHIGH(sl); 12971676Sjpk *high = 1; 12981676Sjpk } else { 12991676Sjpk LCLASS_SET((_bslabel_impl_t *)sl, opt[3]); 13001676Sjpk for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) 13011676Sjpk q[i] = opt[TSOL_TT1_MIN_LENGTH + i]; 13021676Sjpk } 13031676Sjpk SETBLTYPE(sl, SUN_SL_ID); 13041676Sjpk } 13051676Sjpk 13061676Sjpk static int 13071676Sjpk interpret_cipso_tagtype1(const uchar_t *opt) 13081676Sjpk { 13091676Sjpk int i, taglen, ishigh; 13101676Sjpk bslabel_t sl; 13111676Sjpk char line[CIPSO_GENERIC_ARRAY_LEN], *ptr; 13121676Sjpk 13131676Sjpk taglen = opt[1]; 13141676Sjpk if (taglen < TSOL_TT1_MIN_LENGTH || 13151676Sjpk taglen > TSOL_TT1_MAX_LENGTH) 13161676Sjpk return (taglen); 13171676Sjpk 13181676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13191676Sjpk "Tag Type = %d, Tag Length = %d", opt[0], opt[1]); 13201676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13211676Sjpk "Sensitivity Level = 0x%02x", opt[3]); 13221676Sjpk ptr = line; 13231676Sjpk for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) { 13241676Sjpk (void) snprintf(ptr, sizeof (line) - (ptr - line), "%02x", 13251676Sjpk opt[TSOL_TT1_MIN_LENGTH + i]); 13261676Sjpk ptr = strchr(ptr, 0); 13271676Sjpk } 13281676Sjpk if (i != 0) { 13291676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13301676Sjpk "Categories = "); 13311676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), "\t%s", 13321676Sjpk line); 13331676Sjpk } else { 13341676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13351676Sjpk "Categories = None"); 13361676Sjpk } 13371676Sjpk cipso2sl(opt, &sl, &ishigh); 1338*1688Srica if (is_system_labeled()) { 13391676Sjpk if (bsltos(&sl, &plabel, ALABEL_MAXLEN, 13401676Sjpk LONG_CLASSIFICATION|LONG_WORDS|VIEW_INTERNAL) < 0) { 13411676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13421676Sjpk "The Sensitivity Level and Categories can't be " 13431676Sjpk "mapped to a valid SL"); 13441676Sjpk } else { 13451676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13461676Sjpk "The Sensitivity Level and Categories are mapped " 13471676Sjpk "to the SL:"); 13481676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13491676Sjpk "\t%s", ascii_label); 13501676Sjpk } 13511676Sjpk } 13521676Sjpk return (taglen); 13531676Sjpk } 13541676Sjpk 13551676Sjpk /* 13561676Sjpk * The following struct definition #define's are copied from TS1.x. They are 13571676Sjpk * not used here (except TTYPE_3_MAX_TOKENS), but included as a reference for 13581676Sjpk * the tag type 3 packet format. 13591676Sjpk */ 13601676Sjpk #define TTYPE_3_MAX_TOKENS 7 13611676Sjpk 13621676Sjpk /* 13631676Sjpk * Display CIPSO tag type 3 which is defined by MAXSIX. 13641676Sjpk */ 13651676Sjpk static int 13661676Sjpk interpret_cipso_tagtype3(const uchar_t *opt) 13671676Sjpk { 13681676Sjpk uchar_t tagtype; 13691676Sjpk int index, numtokens, taglen; 13701676Sjpk uint16_t mask; 13711676Sjpk uint32_t token; 13721676Sjpk static const char *name[] = { 13731676Sjpk "SL", 13741676Sjpk "NCAV", 13751676Sjpk "INTEG", 13761676Sjpk "SID", 13771676Sjpk "undefined", 13781676Sjpk "undefined", 13791676Sjpk "IL", 13801676Sjpk "PRIVS", 13811676Sjpk "LUID", 13821676Sjpk "PID", 13831676Sjpk "IDS", 13841676Sjpk "ACL" 13851676Sjpk }; 13861676Sjpk 13871676Sjpk tagtype = *opt++; 13881676Sjpk (void) memcpy(&mask, opt + 3, sizeof (mask)); 13891676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13901676Sjpk "Tag Type = %d (MAXSIX)", tagtype); 13911676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13921676Sjpk "Generation = 0x%02x%02x%02x, Mask = 0x%04x", opt[0], opt[1], 13931676Sjpk opt[2], mask); 13941676Sjpk opt += 3 + sizeof (mask); 13951676Sjpk 13961676Sjpk /* 13971676Sjpk * Display tokens 13981676Sjpk */ 13991676Sjpk numtokens = 0; 14001676Sjpk index = 0; 14011676Sjpk while (mask != 0 && numtokens < TTYPE_3_MAX_TOKENS) { 14021676Sjpk if (mask & 0x0001) { 14031676Sjpk (void) memcpy(&token, opt, sizeof (token)); 14041676Sjpk opt += sizeof (token); 14051676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 14061676Sjpk "Attribute = %s, Token = 0x%08x", 14071676Sjpk index < sizeof (name) / sizeof (*name) ? 14081676Sjpk name[index] : "unknown", token); 14091676Sjpk numtokens++; 14101676Sjpk } 14111676Sjpk mask = mask >> 1; 14121676Sjpk index++; 14131676Sjpk } 14141676Sjpk 14151676Sjpk taglen = 6 + numtokens * 4; 14161676Sjpk return (taglen); 14171676Sjpk } 14181676Sjpk 14191676Sjpk static void 14201676Sjpk print_cipso(const uchar_t *opt) 14211676Sjpk { 14221676Sjpk int optlen, taglen, tagnum; 14231676Sjpk uint32_t doi; 14241676Sjpk char line[CIPSO_GENERIC_ARRAY_LEN]; 14251676Sjpk char *oldnest; 14261676Sjpk 14271676Sjpk optlen = opt[1]; 14281676Sjpk if (optlen < TSOL_CIPSO_MIN_LENGTH || optlen > TSOL_CIPSO_MAX_LENGTH) 14291676Sjpk return; 14301676Sjpk 14311676Sjpk oldnest = prot_nest_prefix; 14321676Sjpk prot_nest_prefix = prot_prefix; 14331676Sjpk show_header("CIPSO: ", "Common IP Security Option", 0); 14341676Sjpk show_space(); 14351676Sjpk 14361676Sjpk /* 14371676Sjpk * Display CIPSO Header 14381676Sjpk */ 14391676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 14401676Sjpk "Type = CIPSO (%d), Length = %d", opt[0], opt[1]); 14411676Sjpk (void) memcpy(&doi, opt + 2, sizeof (doi)); 14421676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 14431676Sjpk "Domain of Interpretation = %u", (unsigned)ntohl(doi)); 14441676Sjpk 14451676Sjpk if (opt[1] == TSOL_CIPSO_MIN_LENGTH) { /* no tags */ 14461676Sjpk show_space(); 14471676Sjpk prot_prefix = prot_nest_prefix; 14481676Sjpk prot_nest_prefix = oldnest; 14491676Sjpk return; 14501676Sjpk } 14511676Sjpk optlen -= TSOL_CIPSO_MIN_LENGTH; 14521676Sjpk opt += TSOL_CIPSO_MIN_LENGTH; 14531676Sjpk 14541676Sjpk /* 14551676Sjpk * Display Each Tag 14561676Sjpk */ 14571676Sjpk tagnum = 1; 14581676Sjpk while (optlen >= TSOL_TT1_MIN_LENGTH) { 14591676Sjpk (void) snprintf(line, sizeof (line), "Tag# %d", tagnum); 14601676Sjpk show_header("CIPSO: ", line, 0); 14611676Sjpk /* 14621676Sjpk * We handle tag type 1 and 3 only. Note, tag type 3 14631676Sjpk * is MAXSIX defined. 14641676Sjpk */ 14651676Sjpk switch (opt[0]) { 14661676Sjpk case 1: 14671676Sjpk taglen = interpret_cipso_tagtype1(opt); 14681676Sjpk break; 14691676Sjpk case 3: 14701676Sjpk taglen = interpret_cipso_tagtype3(opt); 14711676Sjpk break; 14721676Sjpk default: 14731676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 14741676Sjpk "Unknown Tag Type %d", opt[0]); 14751676Sjpk show_space(); 14761676Sjpk prot_prefix = prot_nest_prefix; 14771676Sjpk prot_nest_prefix = oldnest; 14781676Sjpk return; 14791676Sjpk } 14801676Sjpk 14811676Sjpk /* 14821676Sjpk * Move to the next tag 14831676Sjpk */ 14841676Sjpk if (taglen <= 0) 14851676Sjpk break; 14861676Sjpk optlen -= taglen; 14871676Sjpk opt += taglen; 14881676Sjpk tagnum++; 14891676Sjpk } 14901676Sjpk show_space(); 14911676Sjpk prot_prefix = prot_nest_prefix; 14921676Sjpk prot_nest_prefix = oldnest; 14931676Sjpk } 1494