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 /* 22*10616SSebastien.Roy@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <stdio.h> 270Sstevel@tonic-gate #include <string.h> 280Sstevel@tonic-gate #include <fcntl.h> 290Sstevel@tonic-gate #include <string.h> 300Sstevel@tonic-gate #include <sys/types.h> 310Sstevel@tonic-gate #include <sys/time.h> 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <sys/stropts.h> 340Sstevel@tonic-gate #include <sys/socket.h> 350Sstevel@tonic-gate #include <net/if.h> 360Sstevel@tonic-gate #include <netinet/in_systm.h> 370Sstevel@tonic-gate #include <netinet/in.h> 380Sstevel@tonic-gate #include <netinet/ip.h> 390Sstevel@tonic-gate #include <netinet/ip6.h> 400Sstevel@tonic-gate #include <netinet/ip_icmp.h> 410Sstevel@tonic-gate #include <netinet/icmp6.h> 420Sstevel@tonic-gate #include <netinet/if_ether.h> 431676Sjpk #include <inet/ip.h> 440Sstevel@tonic-gate #include <inet/ip6.h> 450Sstevel@tonic-gate #include <arpa/inet.h> 460Sstevel@tonic-gate #include <netdb.h> 471676Sjpk #include <tsol/label.h> 481676Sjpk #include <sys/tsol/tndb.h> 491676Sjpk #include <sys/tsol/label_macro.h> 501676Sjpk 510Sstevel@tonic-gate #include "snoop.h" 520Sstevel@tonic-gate 530Sstevel@tonic-gate 540Sstevel@tonic-gate /* 550Sstevel@tonic-gate * IPv6 extension header masks. These are used by the print_ipv6_extensions() 560Sstevel@tonic-gate * function to return information to the caller about which extension headers 570Sstevel@tonic-gate * were processed. This can be useful if the caller wants to know if the 580Sstevel@tonic-gate * packet is an IPv6 fragment, for example. 590Sstevel@tonic-gate */ 600Sstevel@tonic-gate #define SNOOP_HOPOPTS 0x01U 610Sstevel@tonic-gate #define SNOOP_ROUTING 0x02U 620Sstevel@tonic-gate #define SNOOP_DSTOPTS 0x04U 630Sstevel@tonic-gate #define SNOOP_FRAGMENT 0x08U 640Sstevel@tonic-gate #define SNOOP_AH 0x10U 650Sstevel@tonic-gate #define SNOOP_ESP 0x20U 660Sstevel@tonic-gate #define SNOOP_IPV6 0x40U 670Sstevel@tonic-gate 681676Sjpk static void prt_routing_hdr(int, const struct ip6_rthdr *); 691676Sjpk static void prt_fragment_hdr(int, const struct ip6_frag *); 701676Sjpk static void prt_hbh_options(int, const struct ip6_hbh *); 711676Sjpk static void prt_dest_options(int, const struct ip6_dest *); 721676Sjpk static void print_route(const uchar_t *); 731676Sjpk static void print_ipoptions(const uchar_t *, int); 741676Sjpk static void print_ripso(const uchar_t *); 751676Sjpk static void print_cipso(const uchar_t *); 760Sstevel@tonic-gate 770Sstevel@tonic-gate /* Keep track of how many nested IP headers we have. */ 780Sstevel@tonic-gate unsigned int encap_levels; 790Sstevel@tonic-gate unsigned int total_encap_levels = 1; 800Sstevel@tonic-gate 810Sstevel@tonic-gate int 821676Sjpk interpret_ip(int flags, const struct ip *ip, int fraglen) 830Sstevel@tonic-gate { 841676Sjpk uchar_t *data; 850Sstevel@tonic-gate char buff[24]; 860Sstevel@tonic-gate boolean_t isfrag = B_FALSE; 870Sstevel@tonic-gate boolean_t morefrag; 880Sstevel@tonic-gate uint16_t fragoffset; 890Sstevel@tonic-gate int hdrlen; 900Sstevel@tonic-gate uint16_t iplen, uitmp; 910Sstevel@tonic-gate 920Sstevel@tonic-gate if (ip->ip_v == IPV6_VERSION) { 930Sstevel@tonic-gate iplen = interpret_ipv6(flags, (ip6_t *)ip, fraglen); 940Sstevel@tonic-gate return (iplen); 950Sstevel@tonic-gate } 960Sstevel@tonic-gate 970Sstevel@tonic-gate if (encap_levels == 0) 980Sstevel@tonic-gate total_encap_levels = 0; 990Sstevel@tonic-gate encap_levels++; 1000Sstevel@tonic-gate total_encap_levels++; 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate hdrlen = ip->ip_hl * 4; 1031676Sjpk data = ((uchar_t *)ip) + hdrlen; 1040Sstevel@tonic-gate iplen = ntohs(ip->ip_len) - hdrlen; 1050Sstevel@tonic-gate fraglen -= hdrlen; 1060Sstevel@tonic-gate if (fraglen > iplen) 1070Sstevel@tonic-gate fraglen = iplen; 1080Sstevel@tonic-gate if (fraglen < 0) { 1090Sstevel@tonic-gate (void) snprintf(get_sum_line(), MAXLINE, 1100Sstevel@tonic-gate "IP truncated: header missing %d bytes", -fraglen); 1110Sstevel@tonic-gate encap_levels--; 1120Sstevel@tonic-gate return (fraglen + iplen); 1130Sstevel@tonic-gate } 1140Sstevel@tonic-gate /* 1150Sstevel@tonic-gate * We flag this as a fragment if the more fragments bit is set, or 1160Sstevel@tonic-gate * if the fragment offset is non-zero. 1170Sstevel@tonic-gate */ 1180Sstevel@tonic-gate morefrag = (ntohs(ip->ip_off) & IP_MF) == 0 ? B_FALSE : B_TRUE; 1190Sstevel@tonic-gate fragoffset = (ntohs(ip->ip_off) & 0x1FFF) * 8; 1200Sstevel@tonic-gate if (morefrag || fragoffset != 0) 1210Sstevel@tonic-gate isfrag = B_TRUE; 1220Sstevel@tonic-gate 123*10616SSebastien.Roy@Sun.COM src_name = addrtoname(AF_INET, &ip->ip_src); 124*10616SSebastien.Roy@Sun.COM dst_name = addrtoname(AF_INET, &ip->ip_dst); 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate if (flags & F_SUM) { 1270Sstevel@tonic-gate if (isfrag) { 1280Sstevel@tonic-gate (void) snprintf(get_sum_line(), MAXLINE, 1290Sstevel@tonic-gate "%s IP fragment ID=%d Offset=%-4d MF=%d TOS=0x%x " 1300Sstevel@tonic-gate "TTL=%d", 1310Sstevel@tonic-gate getproto(ip->ip_p), 1320Sstevel@tonic-gate ntohs(ip->ip_id), 1330Sstevel@tonic-gate fragoffset, 1340Sstevel@tonic-gate morefrag, 1350Sstevel@tonic-gate ip->ip_tos, 1360Sstevel@tonic-gate ip->ip_ttl); 1370Sstevel@tonic-gate } else { 1380Sstevel@tonic-gate (void) strlcpy(buff, inet_ntoa(ip->ip_dst), 1390Sstevel@tonic-gate sizeof (buff)); 1400Sstevel@tonic-gate uitmp = ntohs(ip->ip_len); 1410Sstevel@tonic-gate (void) snprintf(get_sum_line(), MAXLINE, 1420Sstevel@tonic-gate "IP D=%s S=%s LEN=%u%s, ID=%d, TOS=0x%x, TTL=%d", 1430Sstevel@tonic-gate buff, 1440Sstevel@tonic-gate inet_ntoa(ip->ip_src), 1450Sstevel@tonic-gate uitmp, 1460Sstevel@tonic-gate iplen > fraglen ? "?" : "", 1470Sstevel@tonic-gate ntohs(ip->ip_id), 1480Sstevel@tonic-gate ip->ip_tos, 1490Sstevel@tonic-gate ip->ip_ttl); 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate if (flags & F_DTAIL) { 1540Sstevel@tonic-gate show_header("IP: ", "IP Header", iplen); 1550Sstevel@tonic-gate show_space(); 1561676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1571676Sjpk "Version = %d", ip->ip_v); 1581676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1591676Sjpk "Header length = %d bytes", hdrlen); 1601676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1611676Sjpk "Type of service = 0x%02x", ip->ip_tos); 1621676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1631676Sjpk " xxx. .... = %d (precedence)", 1640Sstevel@tonic-gate ip->ip_tos >> 5); 1651676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1661676Sjpk " %s", getflag(ip->ip_tos, IPTOS_LOWDELAY, 1670Sstevel@tonic-gate "low delay", "normal delay")); 1681676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 1690Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_THROUGHPUT, 1700Sstevel@tonic-gate "high throughput", "normal throughput")); 1711676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 1720Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_RELIABILITY, 1730Sstevel@tonic-gate "high reliability", "normal reliability")); 1741676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 1750Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_ECT, 1760Sstevel@tonic-gate "ECN capable transport", "not ECN capable transport")); 1771676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 1780Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_CE, 1790Sstevel@tonic-gate "ECN congestion experienced", 1800Sstevel@tonic-gate "no ECN congestion experienced")); 1810Sstevel@tonic-gate /* warning: ip_len is signed in netinet/ip.h */ 1820Sstevel@tonic-gate uitmp = ntohs(ip->ip_len); 1831676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1841676Sjpk "Total length = %u bytes%s", uitmp, 1850Sstevel@tonic-gate iplen > fraglen ? " -- truncated" : ""); 1861676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1871676Sjpk "Identification = %d", ntohs(ip->ip_id)); 1880Sstevel@tonic-gate /* warning: ip_off is signed in netinet/ip.h */ 1890Sstevel@tonic-gate uitmp = ntohs(ip->ip_off); 1901676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1911676Sjpk "Flags = 0x%x", uitmp >> 12); 1921676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 1930Sstevel@tonic-gate getflag(uitmp >> 8, IP_DF >> 8, 1940Sstevel@tonic-gate "do not fragment", "may fragment")); 1951676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 1960Sstevel@tonic-gate getflag(uitmp >> 8, IP_MF >> 8, 1970Sstevel@tonic-gate "more fragments", "last fragment")); 1981676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1991676Sjpk "Fragment offset = %u bytes", 2000Sstevel@tonic-gate fragoffset); 2011676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 2021676Sjpk "Time to live = %d seconds/hops", 2030Sstevel@tonic-gate ip->ip_ttl); 2041676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 2051676Sjpk "Protocol = %d (%s)", ip->ip_p, 2060Sstevel@tonic-gate getproto(ip->ip_p)); 2070Sstevel@tonic-gate /* 2080Sstevel@tonic-gate * XXX need to compute checksum and print whether it's correct 2090Sstevel@tonic-gate */ 2101676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 2111676Sjpk "Header checksum = %04x", 2120Sstevel@tonic-gate ntohs(ip->ip_sum)); 2131676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 2141676Sjpk "Source address = %s, %s", 2150Sstevel@tonic-gate inet_ntoa(ip->ip_src), addrtoname(AF_INET, &ip->ip_src)); 2161676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 2171676Sjpk "Destination address = %s, %s", 2180Sstevel@tonic-gate inet_ntoa(ip->ip_dst), addrtoname(AF_INET, &ip->ip_dst)); 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate /* Print IP options - if any */ 2210Sstevel@tonic-gate 2221676Sjpk print_ipoptions((const uchar_t *)(ip + 1), 2231676Sjpk hdrlen - sizeof (struct ip)); 2240Sstevel@tonic-gate show_space(); 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate /* 2280Sstevel@tonic-gate * If we are in detail mode, and this is not the first fragment of 2290Sstevel@tonic-gate * a fragmented packet, print out a little line stating this. 2300Sstevel@tonic-gate * Otherwise, go to the next protocol layer only if this is not a 2310Sstevel@tonic-gate * fragment, or we are in detail mode and this is the first fragment 2320Sstevel@tonic-gate * of a fragmented packet. 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate if (flags & F_DTAIL && fragoffset != 0) { 2351676Sjpk (void) snprintf(get_detail_line(0, 0), MAXLINE, 2360Sstevel@tonic-gate "%s: [%d byte(s) of data, continuation of IP ident=%d]", 2370Sstevel@tonic-gate getproto(ip->ip_p), 2380Sstevel@tonic-gate iplen, 2390Sstevel@tonic-gate ntohs(ip->ip_id)); 2400Sstevel@tonic-gate } else if (!isfrag || (flags & F_DTAIL) && isfrag && fragoffset == 0) { 2410Sstevel@tonic-gate /* go to the next protocol layer */ 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate if (fraglen > 0) { 2440Sstevel@tonic-gate switch (ip->ip_p) { 2450Sstevel@tonic-gate case IPPROTO_IP: 2460Sstevel@tonic-gate break; 2470Sstevel@tonic-gate case IPPROTO_ENCAP: 2481676Sjpk (void) interpret_ip(flags, 2491676Sjpk /* LINTED: alignment */ 2501676Sjpk (const struct ip *)data, fraglen); 2510Sstevel@tonic-gate break; 2520Sstevel@tonic-gate case IPPROTO_ICMP: 2531676Sjpk (void) interpret_icmp(flags, 2541676Sjpk /* LINTED: alignment */ 2551676Sjpk (struct icmp *)data, iplen, fraglen); 2560Sstevel@tonic-gate break; 2570Sstevel@tonic-gate case IPPROTO_IGMP: 2580Sstevel@tonic-gate interpret_igmp(flags, data, iplen, fraglen); 2590Sstevel@tonic-gate break; 2600Sstevel@tonic-gate case IPPROTO_GGP: 2610Sstevel@tonic-gate break; 2620Sstevel@tonic-gate case IPPROTO_TCP: 2631676Sjpk (void) interpret_tcp(flags, 2641676Sjpk (struct tcphdr *)data, iplen, fraglen); 2650Sstevel@tonic-gate break; 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate case IPPROTO_ESP: 2681676Sjpk (void) interpret_esp(flags, data, iplen, 2691676Sjpk fraglen); 2700Sstevel@tonic-gate break; 2710Sstevel@tonic-gate case IPPROTO_AH: 2721676Sjpk (void) interpret_ah(flags, data, iplen, 2731676Sjpk fraglen); 2740Sstevel@tonic-gate break; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate case IPPROTO_OSPF: 2770Sstevel@tonic-gate interpret_ospf(flags, data, iplen, fraglen); 2780Sstevel@tonic-gate break; 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate case IPPROTO_EGP: 2810Sstevel@tonic-gate case IPPROTO_PUP: 2820Sstevel@tonic-gate break; 2830Sstevel@tonic-gate case IPPROTO_UDP: 2841676Sjpk (void) interpret_udp(flags, 2851676Sjpk (struct udphdr *)data, iplen, fraglen); 2860Sstevel@tonic-gate break; 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate case IPPROTO_IDP: 2890Sstevel@tonic-gate case IPPROTO_HELLO: 2900Sstevel@tonic-gate case IPPROTO_ND: 2910Sstevel@tonic-gate case IPPROTO_RAW: 2920Sstevel@tonic-gate break; 2930Sstevel@tonic-gate case IPPROTO_IPV6: /* IPV6 encap */ 2941676Sjpk /* LINTED: alignment */ 2950Sstevel@tonic-gate (void) interpret_ipv6(flags, (ip6_t *)data, 2960Sstevel@tonic-gate iplen); 2970Sstevel@tonic-gate break; 2980Sstevel@tonic-gate case IPPROTO_SCTP: 2991676Sjpk (void) interpret_sctp(flags, 3001676Sjpk (struct sctp_hdr *)data, iplen, fraglen); 3010Sstevel@tonic-gate break; 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate encap_levels--; 3070Sstevel@tonic-gate return (iplen); 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate int 3111676Sjpk interpret_ipv6(int flags, const ip6_t *ip6h, int fraglen) 3120Sstevel@tonic-gate { 3130Sstevel@tonic-gate uint8_t *data; 3140Sstevel@tonic-gate int hdrlen, iplen; 3150Sstevel@tonic-gate int version, flow, class; 3160Sstevel@tonic-gate uchar_t proto; 3170Sstevel@tonic-gate boolean_t isfrag = B_FALSE; 3180Sstevel@tonic-gate uint8_t extmask; 3190Sstevel@tonic-gate /* 3200Sstevel@tonic-gate * The print_srcname and print_dstname strings are the hostname 3210Sstevel@tonic-gate * parts of the verbose IPv6 header output, including the comma 3220Sstevel@tonic-gate * and the space after the litteral address strings. 3230Sstevel@tonic-gate */ 3240Sstevel@tonic-gate char print_srcname[MAXHOSTNAMELEN + 2]; 3250Sstevel@tonic-gate char print_dstname[MAXHOSTNAMELEN + 2]; 3260Sstevel@tonic-gate char src_addrstr[INET6_ADDRSTRLEN]; 3270Sstevel@tonic-gate char dst_addrstr[INET6_ADDRSTRLEN]; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate iplen = ntohs(ip6h->ip6_plen); 3300Sstevel@tonic-gate hdrlen = IPV6_HDR_LEN; 3310Sstevel@tonic-gate fraglen -= hdrlen; 3320Sstevel@tonic-gate if (fraglen < 0) 3330Sstevel@tonic-gate return (fraglen + hdrlen); 3340Sstevel@tonic-gate data = ((uint8_t *)ip6h) + hdrlen; 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate proto = ip6h->ip6_nxt; 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate src_name = addrtoname(AF_INET6, &ip6h->ip6_src); 3390Sstevel@tonic-gate dst_name = addrtoname(AF_INET6, &ip6h->ip6_dst); 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate /* 3420Sstevel@tonic-gate * Use endian-aware masks to extract traffic class and 3430Sstevel@tonic-gate * flowinfo. Also, flowinfo is now 20 bits and class 8 3440Sstevel@tonic-gate * rather than 24 and 4. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate class = ntohl((ip6h->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20); 3470Sstevel@tonic-gate flow = ntohl(ip6h->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL); 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate /* 3500Sstevel@tonic-gate * NOTE: the F_SUM and F_DTAIL flags are mutually exclusive, 3510Sstevel@tonic-gate * so the code within the first part of the following if statement 3520Sstevel@tonic-gate * will not affect the detailed printing of the packet. 3530Sstevel@tonic-gate */ 3540Sstevel@tonic-gate if (flags & F_SUM) { 3551676Sjpk (void) snprintf(get_sum_line(), MAXLINE, 3561676Sjpk "IPv6 S=%s D=%s LEN=%d HOPS=%d CLASS=0x%x FLOW=0x%x", 3570Sstevel@tonic-gate src_name, dst_name, iplen, ip6h->ip6_hops, class, flow); 3580Sstevel@tonic-gate } else if (flags & F_DTAIL) { 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &ip6h->ip6_src, src_addrstr, 3610Sstevel@tonic-gate INET6_ADDRSTRLEN); 3620Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &ip6h->ip6_dst, dst_addrstr, 3630Sstevel@tonic-gate INET6_ADDRSTRLEN); 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate version = ntohl(ip6h->ip6_vcf) >> 28; 3660Sstevel@tonic-gate 367*10616SSebastien.Roy@Sun.COM if (strcmp(src_name, src_addrstr) == 0) { 3680Sstevel@tonic-gate print_srcname[0] = '\0'; 369*10616SSebastien.Roy@Sun.COM } else { 3700Sstevel@tonic-gate snprintf(print_srcname, sizeof (print_srcname), 371*10616SSebastien.Roy@Sun.COM ", %s", src_name); 372*10616SSebastien.Roy@Sun.COM } 3730Sstevel@tonic-gate 374*10616SSebastien.Roy@Sun.COM if (strcmp(dst_name, dst_addrstr) == 0) { 3750Sstevel@tonic-gate print_dstname[0] = '\0'; 376*10616SSebastien.Roy@Sun.COM } else { 3770Sstevel@tonic-gate snprintf(print_dstname, sizeof (print_dstname), 378*10616SSebastien.Roy@Sun.COM ", %s", dst_name); 379*10616SSebastien.Roy@Sun.COM } 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate show_header("IPv6: ", "IPv6 Header", iplen); 3820Sstevel@tonic-gate show_space(); 3830Sstevel@tonic-gate 3841676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3850Sstevel@tonic-gate "Version = %d", version); 3861676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3870Sstevel@tonic-gate "Traffic Class = %d", class); 3881676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3890Sstevel@tonic-gate "Flow label = 0x%x", flow); 3901676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3911676Sjpk "Payload length = %d", iplen); 3921676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3931676Sjpk "Next Header = %d (%s)", proto, 3940Sstevel@tonic-gate getproto(proto)); 3951676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3961676Sjpk "Hop Limit = %d", ip6h->ip6_hops); 3971676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3980Sstevel@tonic-gate "Source address = %s%s", src_addrstr, print_srcname); 3991676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 4000Sstevel@tonic-gate "Destination address = %s%s", dst_addrstr, print_dstname); 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate show_space(); 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate /* 4060Sstevel@tonic-gate * Print IPv6 Extension Headers, or skip them in the summary case. 4070Sstevel@tonic-gate * Set isfrag to true if one of the extension headers encounterred 4080Sstevel@tonic-gate * was a fragment header. 4090Sstevel@tonic-gate */ 4100Sstevel@tonic-gate if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS || 4110Sstevel@tonic-gate proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) { 4120Sstevel@tonic-gate extmask = print_ipv6_extensions(flags, &data, &proto, &iplen, 4130Sstevel@tonic-gate &fraglen); 4140Sstevel@tonic-gate if ((extmask & SNOOP_FRAGMENT) != 0) { 4150Sstevel@tonic-gate isfrag = B_TRUE; 4160Sstevel@tonic-gate } 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate /* 4200Sstevel@tonic-gate * We only want to print upper layer information if this is not 4210Sstevel@tonic-gate * a fragment, or if we're printing in detail. Note that the 4220Sstevel@tonic-gate * proto variable will be set to IPPROTO_NONE if this is a fragment 4230Sstevel@tonic-gate * with a non-zero fragment offset. 4240Sstevel@tonic-gate */ 4250Sstevel@tonic-gate if (!isfrag || flags & F_DTAIL) { 4260Sstevel@tonic-gate /* go to the next protocol layer */ 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate switch (proto) { 4290Sstevel@tonic-gate case IPPROTO_IP: 4300Sstevel@tonic-gate break; 4310Sstevel@tonic-gate case IPPROTO_ENCAP: 4321676Sjpk /* LINTED: alignment */ 4331676Sjpk (void) interpret_ip(flags, (const struct ip *)data, 4341676Sjpk fraglen); 4350Sstevel@tonic-gate break; 4360Sstevel@tonic-gate case IPPROTO_ICMPV6: 4371676Sjpk /* LINTED: alignment */ 4381676Sjpk (void) interpret_icmpv6(flags, (icmp6_t *)data, iplen, 4390Sstevel@tonic-gate fraglen); 4400Sstevel@tonic-gate break; 4410Sstevel@tonic-gate case IPPROTO_IGMP: 4420Sstevel@tonic-gate interpret_igmp(flags, data, iplen, fraglen); 4430Sstevel@tonic-gate break; 4440Sstevel@tonic-gate case IPPROTO_GGP: 4450Sstevel@tonic-gate break; 4460Sstevel@tonic-gate case IPPROTO_TCP: 4471676Sjpk (void) interpret_tcp(flags, (struct tcphdr *)data, 4481676Sjpk iplen, fraglen); 4490Sstevel@tonic-gate break; 4500Sstevel@tonic-gate case IPPROTO_ESP: 4511676Sjpk (void) interpret_esp(flags, data, iplen, fraglen); 4520Sstevel@tonic-gate break; 4530Sstevel@tonic-gate case IPPROTO_AH: 4541676Sjpk (void) interpret_ah(flags, data, iplen, fraglen); 4550Sstevel@tonic-gate break; 4560Sstevel@tonic-gate case IPPROTO_EGP: 4570Sstevel@tonic-gate case IPPROTO_PUP: 4580Sstevel@tonic-gate break; 4590Sstevel@tonic-gate case IPPROTO_UDP: 4601676Sjpk (void) interpret_udp(flags, (struct udphdr *)data, 4611676Sjpk iplen, fraglen); 4620Sstevel@tonic-gate break; 4630Sstevel@tonic-gate case IPPROTO_IDP: 4640Sstevel@tonic-gate case IPPROTO_HELLO: 4650Sstevel@tonic-gate case IPPROTO_ND: 4660Sstevel@tonic-gate case IPPROTO_RAW: 4670Sstevel@tonic-gate break; 4680Sstevel@tonic-gate case IPPROTO_IPV6: 4691676Sjpk /* LINTED: alignment */ 4701676Sjpk (void) interpret_ipv6(flags, (const ip6_t *)data, 4711676Sjpk iplen); 4720Sstevel@tonic-gate break; 4730Sstevel@tonic-gate case IPPROTO_SCTP: 4741676Sjpk (void) interpret_sctp(flags, (struct sctp_hdr *)data, 4751676Sjpk iplen, fraglen); 4760Sstevel@tonic-gate break; 4770Sstevel@tonic-gate case IPPROTO_OSPF: 4780Sstevel@tonic-gate interpret_ospf6(flags, data, iplen, fraglen); 4790Sstevel@tonic-gate break; 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate return (iplen); 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate /* 4870Sstevel@tonic-gate * ip_ext: data including the extension header. 4880Sstevel@tonic-gate * iplen: length of the data remaining in the packet. 4890Sstevel@tonic-gate * Returns a mask of IPv6 extension headers it processed. 4900Sstevel@tonic-gate */ 4910Sstevel@tonic-gate uint8_t 4920Sstevel@tonic-gate print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen, 4930Sstevel@tonic-gate int *fraglen) 4940Sstevel@tonic-gate { 4950Sstevel@tonic-gate uint8_t *data_ptr; 4960Sstevel@tonic-gate uchar_t proto = *next; 4970Sstevel@tonic-gate boolean_t is_extension_header; 4980Sstevel@tonic-gate struct ip6_hbh *ipv6ext_hbh; 4990Sstevel@tonic-gate struct ip6_dest *ipv6ext_dest; 5000Sstevel@tonic-gate struct ip6_rthdr *ipv6ext_rthdr; 5010Sstevel@tonic-gate struct ip6_frag *ipv6ext_frag; 5020Sstevel@tonic-gate uint32_t exthdrlen; 5030Sstevel@tonic-gate uint8_t extmask = 0; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate if ((hdr == NULL) || (*hdr == NULL) || (next == NULL) || (iplen == 0)) 5060Sstevel@tonic-gate return (0); 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate data_ptr = *hdr; 5090Sstevel@tonic-gate is_extension_header = B_TRUE; 5100Sstevel@tonic-gate while (is_extension_header) { 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate /* 5130Sstevel@tonic-gate * There must be at least enough data left to read the 5140Sstevel@tonic-gate * next header and header length fields from the next 5150Sstevel@tonic-gate * header. 5160Sstevel@tonic-gate */ 5170Sstevel@tonic-gate if (*fraglen < 2) { 5180Sstevel@tonic-gate return (extmask); 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate switch (proto) { 5220Sstevel@tonic-gate case IPPROTO_HOPOPTS: 5230Sstevel@tonic-gate ipv6ext_hbh = (struct ip6_hbh *)data_ptr; 5240Sstevel@tonic-gate exthdrlen = 8 + ipv6ext_hbh->ip6h_len * 8; 5250Sstevel@tonic-gate if (*fraglen <= exthdrlen) { 5260Sstevel@tonic-gate return (extmask); 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate prt_hbh_options(flags, ipv6ext_hbh); 5290Sstevel@tonic-gate extmask |= SNOOP_HOPOPTS; 5300Sstevel@tonic-gate proto = ipv6ext_hbh->ip6h_nxt; 5310Sstevel@tonic-gate break; 5320Sstevel@tonic-gate case IPPROTO_DSTOPTS: 5330Sstevel@tonic-gate ipv6ext_dest = (struct ip6_dest *)data_ptr; 5340Sstevel@tonic-gate exthdrlen = 8 + ipv6ext_dest->ip6d_len * 8; 5350Sstevel@tonic-gate if (*fraglen <= exthdrlen) { 5360Sstevel@tonic-gate return (extmask); 5370Sstevel@tonic-gate } 5380Sstevel@tonic-gate prt_dest_options(flags, ipv6ext_dest); 5390Sstevel@tonic-gate extmask |= SNOOP_DSTOPTS; 5400Sstevel@tonic-gate proto = ipv6ext_dest->ip6d_nxt; 5410Sstevel@tonic-gate break; 5420Sstevel@tonic-gate case IPPROTO_ROUTING: 5430Sstevel@tonic-gate ipv6ext_rthdr = (struct ip6_rthdr *)data_ptr; 5440Sstevel@tonic-gate exthdrlen = 8 + ipv6ext_rthdr->ip6r_len * 8; 5450Sstevel@tonic-gate if (*fraglen <= exthdrlen) { 5460Sstevel@tonic-gate return (extmask); 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate prt_routing_hdr(flags, ipv6ext_rthdr); 5490Sstevel@tonic-gate extmask |= SNOOP_ROUTING; 5500Sstevel@tonic-gate proto = ipv6ext_rthdr->ip6r_nxt; 5510Sstevel@tonic-gate break; 5520Sstevel@tonic-gate case IPPROTO_FRAGMENT: 5531676Sjpk /* LINTED: alignment */ 5540Sstevel@tonic-gate ipv6ext_frag = (struct ip6_frag *)data_ptr; 5550Sstevel@tonic-gate exthdrlen = sizeof (struct ip6_frag); 5560Sstevel@tonic-gate if (*fraglen <= exthdrlen) { 5570Sstevel@tonic-gate return (extmask); 5580Sstevel@tonic-gate } 5590Sstevel@tonic-gate prt_fragment_hdr(flags, ipv6ext_frag); 5600Sstevel@tonic-gate extmask |= SNOOP_FRAGMENT; 5610Sstevel@tonic-gate /* 5620Sstevel@tonic-gate * If this is not the first fragment, forget about 5630Sstevel@tonic-gate * the rest of the packet, snoop decoding is 5640Sstevel@tonic-gate * stateless. 5650Sstevel@tonic-gate */ 5660Sstevel@tonic-gate if ((ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK) != 0) 5670Sstevel@tonic-gate proto = IPPROTO_NONE; 5680Sstevel@tonic-gate else 5690Sstevel@tonic-gate proto = ipv6ext_frag->ip6f_nxt; 5700Sstevel@tonic-gate break; 5710Sstevel@tonic-gate default: 5720Sstevel@tonic-gate is_extension_header = B_FALSE; 5730Sstevel@tonic-gate break; 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate if (is_extension_header) { 5770Sstevel@tonic-gate *iplen -= exthdrlen; 5780Sstevel@tonic-gate *fraglen -= exthdrlen; 5790Sstevel@tonic-gate data_ptr += exthdrlen; 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate *next = proto; 5840Sstevel@tonic-gate *hdr = data_ptr; 5850Sstevel@tonic-gate return (extmask); 5860Sstevel@tonic-gate } 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate static void 5891676Sjpk print_ipoptions(const uchar_t *opt, int optlen) 5900Sstevel@tonic-gate { 5910Sstevel@tonic-gate int len; 5921676Sjpk int remain; 5930Sstevel@tonic-gate char *line; 5941676Sjpk const char *truncstr; 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate if (optlen <= 0) { 5971676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 5980Sstevel@tonic-gate "No options"); 5990Sstevel@tonic-gate return; 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate 6021676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 6030Sstevel@tonic-gate "Options: (%d bytes)", optlen); 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate while (optlen > 0) { 6061676Sjpk line = get_line(0, 0); 6071676Sjpk remain = get_line_remain(); 6080Sstevel@tonic-gate len = opt[1]; 6091676Sjpk truncstr = len > optlen ? "?" : ""; 6100Sstevel@tonic-gate switch (opt[0]) { 6110Sstevel@tonic-gate case IPOPT_EOL: 6121676Sjpk (void) strlcpy(line, " - End of option list", remain); 6130Sstevel@tonic-gate return; 6140Sstevel@tonic-gate case IPOPT_NOP: 6151676Sjpk (void) strlcpy(line, " - No op", remain); 6160Sstevel@tonic-gate len = 1; 6170Sstevel@tonic-gate break; 6180Sstevel@tonic-gate case IPOPT_RR: 6191676Sjpk (void) snprintf(line, remain, 6201676Sjpk " - Record route (%d bytes%s)", len, truncstr); 6210Sstevel@tonic-gate print_route(opt); 6220Sstevel@tonic-gate break; 6230Sstevel@tonic-gate case IPOPT_TS: 6241676Sjpk (void) snprintf(line, remain, 6251676Sjpk " - Time stamp (%d bytes%s)", len, truncstr); 6260Sstevel@tonic-gate break; 6270Sstevel@tonic-gate case IPOPT_SECURITY: 6281676Sjpk (void) snprintf(line, remain, " - RIPSO (%d bytes%s)", 6291676Sjpk len, truncstr); 6301676Sjpk print_ripso(opt); 6311676Sjpk break; 6321676Sjpk case IPOPT_COMSEC: 6331676Sjpk (void) snprintf(line, remain, " - CIPSO (%d bytes%s)", 6341676Sjpk len, truncstr); 6351676Sjpk print_cipso(opt); 6360Sstevel@tonic-gate break; 6370Sstevel@tonic-gate case IPOPT_LSRR: 6381676Sjpk (void) snprintf(line, remain, 6391676Sjpk " - Loose source route (%d bytes%s)", len, 6401676Sjpk truncstr); 6410Sstevel@tonic-gate print_route(opt); 6420Sstevel@tonic-gate break; 6430Sstevel@tonic-gate case IPOPT_SATID: 6441676Sjpk (void) snprintf(line, remain, 6451676Sjpk " - SATNET Stream id (%d bytes%s)", 6461676Sjpk len, truncstr); 6470Sstevel@tonic-gate break; 6480Sstevel@tonic-gate case IPOPT_SSRR: 6491676Sjpk (void) snprintf(line, remain, 6501676Sjpk " - Strict source route, (%d bytes%s)", len, 6511676Sjpk truncstr); 6520Sstevel@tonic-gate print_route(opt); 6530Sstevel@tonic-gate break; 6540Sstevel@tonic-gate default: 6551676Sjpk (void) snprintf(line, remain, 6561676Sjpk " - Option %d (unknown - %d bytes%s) %s", 6571676Sjpk opt[0], len, truncstr, 6581676Sjpk tohex((char *)&opt[2], len - 2)); 6590Sstevel@tonic-gate break; 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate if (len <= 0) { 6621676Sjpk (void) snprintf(line, remain, 6631676Sjpk " - Incomplete option len %d", len); 6640Sstevel@tonic-gate break; 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate opt += len; 6670Sstevel@tonic-gate optlen -= len; 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate static void 6721676Sjpk print_route(const uchar_t *opt) 6730Sstevel@tonic-gate { 6741676Sjpk int len, pointer, remain; 6750Sstevel@tonic-gate struct in_addr addr; 6760Sstevel@tonic-gate char *line; 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate len = opt[1]; 6790Sstevel@tonic-gate pointer = opt[2]; 6800Sstevel@tonic-gate 6811676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 6820Sstevel@tonic-gate " Pointer = %d", pointer); 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate pointer -= IPOPT_MINOFF; 6850Sstevel@tonic-gate opt += (IPOPT_OFFSET + 1); 6860Sstevel@tonic-gate len -= (IPOPT_OFFSET + 1); 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate while (len > 0) { 6891676Sjpk line = get_line(0, 0); 6901676Sjpk remain = get_line_remain(); 6910Sstevel@tonic-gate memcpy((char *)&addr, opt, sizeof (addr)); 6920Sstevel@tonic-gate if (addr.s_addr == INADDR_ANY) 6931676Sjpk (void) strlcpy(line, " -", remain); 6940Sstevel@tonic-gate else 6951676Sjpk (void) snprintf(line, remain, " %s", 6960Sstevel@tonic-gate addrtoname(AF_INET, &addr)); 6970Sstevel@tonic-gate if (pointer == 0) 6981676Sjpk (void) strlcat(line, " <-- (current)", remain); 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate opt += sizeof (addr); 7010Sstevel@tonic-gate len -= sizeof (addr); 7020Sstevel@tonic-gate pointer -= sizeof (addr); 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate } 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate char * 7071676Sjpk getproto(int p) 7080Sstevel@tonic-gate { 7090Sstevel@tonic-gate switch (p) { 7100Sstevel@tonic-gate case IPPROTO_HOPOPTS: return ("IPv6-HopOpts"); 7110Sstevel@tonic-gate case IPPROTO_IPV6: return ("IPv6"); 7120Sstevel@tonic-gate case IPPROTO_ROUTING: return ("IPv6-Route"); 7130Sstevel@tonic-gate case IPPROTO_FRAGMENT: return ("IPv6-Frag"); 7140Sstevel@tonic-gate case IPPROTO_RSVP: return ("RSVP"); 7150Sstevel@tonic-gate case IPPROTO_ENCAP: return ("IP-in-IP"); 7160Sstevel@tonic-gate case IPPROTO_AH: return ("AH"); 7170Sstevel@tonic-gate case IPPROTO_ESP: return ("ESP"); 7180Sstevel@tonic-gate case IPPROTO_ICMP: return ("ICMP"); 7190Sstevel@tonic-gate case IPPROTO_ICMPV6: return ("ICMPv6"); 7200Sstevel@tonic-gate case IPPROTO_DSTOPTS: return ("IPv6-DstOpts"); 7210Sstevel@tonic-gate case IPPROTO_IGMP: return ("IGMP"); 7220Sstevel@tonic-gate case IPPROTO_GGP: return ("GGP"); 7230Sstevel@tonic-gate case IPPROTO_TCP: return ("TCP"); 7240Sstevel@tonic-gate case IPPROTO_EGP: return ("EGP"); 7250Sstevel@tonic-gate case IPPROTO_PUP: return ("PUP"); 7260Sstevel@tonic-gate case IPPROTO_UDP: return ("UDP"); 7270Sstevel@tonic-gate case IPPROTO_IDP: return ("IDP"); 7280Sstevel@tonic-gate case IPPROTO_HELLO: return ("HELLO"); 7290Sstevel@tonic-gate case IPPROTO_ND: return ("ND"); 7300Sstevel@tonic-gate case IPPROTO_EON: return ("EON"); 7310Sstevel@tonic-gate case IPPROTO_RAW: return ("RAW"); 7320Sstevel@tonic-gate case IPPROTO_OSPF: return ("OSPF"); 7330Sstevel@tonic-gate default: return (""); 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate static void 7381676Sjpk prt_routing_hdr(int flags, const struct ip6_rthdr *ipv6ext_rthdr) 7390Sstevel@tonic-gate { 7400Sstevel@tonic-gate uint8_t nxt_hdr; 7410Sstevel@tonic-gate uint8_t type; 7420Sstevel@tonic-gate uint32_t len; 7430Sstevel@tonic-gate uint8_t segleft; 7440Sstevel@tonic-gate uint32_t numaddrs; 7450Sstevel@tonic-gate int i; 7460Sstevel@tonic-gate struct ip6_rthdr0 *ipv6ext_rthdr0; 7470Sstevel@tonic-gate struct in6_addr *addrs; 7480Sstevel@tonic-gate char addr[INET6_ADDRSTRLEN]; 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate /* in summary mode, we don't do anything. */ 7510Sstevel@tonic-gate if (flags & F_SUM) { 7520Sstevel@tonic-gate return; 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate nxt_hdr = ipv6ext_rthdr->ip6r_nxt; 7560Sstevel@tonic-gate type = ipv6ext_rthdr->ip6r_type; 7570Sstevel@tonic-gate len = 8 * (ipv6ext_rthdr->ip6r_len + 1); 7580Sstevel@tonic-gate segleft = ipv6ext_rthdr->ip6r_segleft; 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate show_header("IPv6-Route: ", "IPv6 Routing Header", 0); 7610Sstevel@tonic-gate show_space(); 7620Sstevel@tonic-gate 7631676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7640Sstevel@tonic-gate "Next header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 7651676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7660Sstevel@tonic-gate "Header length = %d", len); 7671676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7680Sstevel@tonic-gate "Routing type = %d", type); 7691676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7700Sstevel@tonic-gate "Segments left = %d", segleft); 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate if (type == IPV6_RTHDR_TYPE_0) { 7730Sstevel@tonic-gate /* 7740Sstevel@tonic-gate * XXX This loop will print all addresses in the routing header, 7750Sstevel@tonic-gate * XXX not just the segments left. 7760Sstevel@tonic-gate * XXX (The header length field is twice the number of 7770Sstevel@tonic-gate * XXX addresses) 7780Sstevel@tonic-gate * XXX At some future time, we may want to change this 7790Sstevel@tonic-gate * XXX to differentiate between the hops yet to do 7800Sstevel@tonic-gate * XXX and the hops already taken. 7810Sstevel@tonic-gate */ 7821676Sjpk /* LINTED: alignment */ 7830Sstevel@tonic-gate ipv6ext_rthdr0 = (struct ip6_rthdr0 *)ipv6ext_rthdr; 7840Sstevel@tonic-gate numaddrs = ipv6ext_rthdr0->ip6r0_len / 2; 7850Sstevel@tonic-gate addrs = (struct in6_addr *)(ipv6ext_rthdr0 + 1); 7860Sstevel@tonic-gate for (i = 0; i < numaddrs; i++) { 7870Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &addrs[i], addr, 7880Sstevel@tonic-gate INET6_ADDRSTRLEN); 7891676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7900Sstevel@tonic-gate "address[%d]=%s", i, addr); 7910Sstevel@tonic-gate } 7920Sstevel@tonic-gate } 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate show_space(); 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate static void 7981676Sjpk prt_fragment_hdr(int flags, const struct ip6_frag *ipv6ext_frag) 7990Sstevel@tonic-gate { 8000Sstevel@tonic-gate boolean_t morefrag; 8010Sstevel@tonic-gate uint16_t fragoffset; 8020Sstevel@tonic-gate uint8_t nxt_hdr; 8030Sstevel@tonic-gate uint32_t fragident; 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate /* extract the various fields from the fragment header */ 8060Sstevel@tonic-gate nxt_hdr = ipv6ext_frag->ip6f_nxt; 8070Sstevel@tonic-gate morefrag = (ipv6ext_frag->ip6f_offlg & IP6F_MORE_FRAG) == 0 8080Sstevel@tonic-gate ? B_FALSE : B_TRUE; 8090Sstevel@tonic-gate fragoffset = ntohs(ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK); 8100Sstevel@tonic-gate fragident = ntohl(ipv6ext_frag->ip6f_ident); 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate if (flags & F_SUM) { 8131676Sjpk (void) snprintf(get_sum_line(), MAXLINE, 8140Sstevel@tonic-gate "IPv6 fragment ID=%d Offset=%-4d MF=%d", 8150Sstevel@tonic-gate fragident, 8160Sstevel@tonic-gate fragoffset, 8170Sstevel@tonic-gate morefrag); 8180Sstevel@tonic-gate } else { /* F_DTAIL */ 8190Sstevel@tonic-gate show_header("IPv6-Frag: ", "IPv6 Fragment Header", 0); 8200Sstevel@tonic-gate show_space(); 8210Sstevel@tonic-gate 8221676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8230Sstevel@tonic-gate "Next Header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 8241676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8250Sstevel@tonic-gate "Fragment Offset = %d", fragoffset); 8261676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8270Sstevel@tonic-gate "More Fragments Flag = %s", morefrag ? "true" : "false"); 8281676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8290Sstevel@tonic-gate "Identification = %d", fragident); 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate show_space(); 8320Sstevel@tonic-gate } 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate static void 8361676Sjpk print_ip6opt_ls(const uchar_t *data, unsigned int op_len) 8370Sstevel@tonic-gate { 8381676Sjpk uint32_t doi; 8391676Sjpk uint8_t sotype, solen; 8401676Sjpk uint16_t value, value2; 8411676Sjpk char *cp; 8421676Sjpk int remlen; 8431676Sjpk boolean_t printed; 8441676Sjpk 8451676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8461676Sjpk "Labeled Security Option len = %u bytes%s", op_len, 8471676Sjpk op_len < sizeof (uint32_t) || (op_len & 1) != 0 ? "?" : ""); 8481676Sjpk if (op_len < sizeof (uint32_t)) 8491676Sjpk return; 8501676Sjpk GETINT32(doi, data); 8511676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8521676Sjpk " DOI = %d (%s)", doi, doi == IP6LS_DOI_V4 ? "IPv4" : "???"); 8531676Sjpk op_len -= sizeof (uint32_t); 8541676Sjpk while (op_len > 0) { 8551676Sjpk GETINT8(sotype, data); 8561676Sjpk if (op_len < 2) { 8571676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8581676Sjpk " truncated %u suboption (no len)", sotype); 8591676Sjpk break; 8601676Sjpk } 8611676Sjpk GETINT8(solen, data); 8621676Sjpk if (solen < 2 || solen > op_len) { 8631676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8641676Sjpk " bad %u suboption (len 2 <= %u <= %u)", 8651676Sjpk sotype, solen, op_len); 8661676Sjpk if (solen < 2) 8671676Sjpk solen = 2; 8681676Sjpk if (solen > op_len) 8691676Sjpk solen = op_len; 8701676Sjpk } 8711676Sjpk op_len -= solen; 8721676Sjpk solen -= 2; 8731676Sjpk cp = get_line(0, 0); 8741676Sjpk remlen = get_line_remain(); 8751676Sjpk (void) strlcpy(cp, " ", remlen); 8761676Sjpk cp += 4; 8771676Sjpk remlen -= 4; 8781676Sjpk printed = B_TRUE; 8791676Sjpk switch (sotype) { 8801676Sjpk case IP6LS_TT_LEVEL: 8811676Sjpk if (solen != 2) { 8821676Sjpk printed = B_FALSE; 8831676Sjpk break; 8841676Sjpk } 8851676Sjpk GETINT16(value, data); 8861676Sjpk (void) snprintf(cp, remlen, "Level %u", value); 8871676Sjpk solen = 0; 8881676Sjpk break; 8891676Sjpk case IP6LS_TT_VECTOR: 8901676Sjpk (void) strlcpy(cp, "Bit-Vector: ", remlen); 8911676Sjpk remlen -= strlen(cp); 8921676Sjpk cp += strlen(cp); 8931676Sjpk while (solen > 1) { 8941676Sjpk GETINT16(value, data); 8951676Sjpk solen -= 2; 8961676Sjpk (void) snprintf(cp, remlen, "%04x", value); 8971676Sjpk remlen -= strlen(cp); 8981676Sjpk cp += strlen(cp); 8991676Sjpk } 9001676Sjpk break; 9011676Sjpk case IP6LS_TT_ENUM: 9021676Sjpk (void) strlcpy(cp, "Enumeration:", remlen); 9031676Sjpk remlen -= strlen(cp); 9041676Sjpk cp += strlen(cp); 9051676Sjpk while (solen > 1) { 9061676Sjpk GETINT16(value, data); 9071676Sjpk solen -= 2; 9081676Sjpk (void) snprintf(cp, remlen, " %u", value); 9091676Sjpk remlen -= strlen(cp); 9101676Sjpk cp += strlen(cp); 9111676Sjpk } 9121676Sjpk break; 9131676Sjpk case IP6LS_TT_RANGES: 9141676Sjpk (void) strlcpy(cp, "Ranges:", remlen); 9151676Sjpk remlen -= strlen(cp); 9161676Sjpk cp += strlen(cp); 9171676Sjpk while (solen > 3) { 9181676Sjpk GETINT16(value, data); 9191676Sjpk GETINT16(value2, data); 9201676Sjpk solen -= 4; 9211676Sjpk (void) snprintf(cp, remlen, " %u-%u", value, 9221676Sjpk value2); 9231676Sjpk remlen -= strlen(cp); 9241676Sjpk cp += strlen(cp); 9251676Sjpk } 9261676Sjpk break; 9271676Sjpk case IP6LS_TT_V4: 9281676Sjpk (void) strlcpy(cp, "IPv4 Option", remlen); 9291676Sjpk print_ipoptions(data, solen); 9301676Sjpk solen = 0; 9311676Sjpk break; 9321676Sjpk case IP6LS_TT_DEST: 9331676Sjpk (void) snprintf(cp, remlen, 9341676Sjpk "Destination-Only Data length %u", solen); 9351676Sjpk solen = 0; 9361676Sjpk break; 9371676Sjpk default: 9381676Sjpk (void) snprintf(cp, remlen, 9391676Sjpk " unknown %u suboption (len %u)", sotype, solen); 9401676Sjpk solen = 0; 9411676Sjpk break; 9421676Sjpk } 9431676Sjpk if (solen != 0) { 9441676Sjpk if (printed) { 9451676Sjpk cp = get_line(0, 0); 9461676Sjpk remlen = get_line_remain(); 9471676Sjpk } 9481676Sjpk (void) snprintf(cp, remlen, 9491676Sjpk " malformed %u suboption (remaining %u)", 9501676Sjpk sotype, solen); 9511676Sjpk data += solen; 9521676Sjpk } 9531676Sjpk } 9541676Sjpk } 9551676Sjpk 9561676Sjpk static void 9571676Sjpk prt_hbh_options(int flags, const struct ip6_hbh *ipv6ext_hbh) 9581676Sjpk { 9591676Sjpk const uint8_t *data, *ndata; 9601676Sjpk uint32_t len; 9610Sstevel@tonic-gate uint8_t op_type; 9620Sstevel@tonic-gate uint8_t op_len; 9630Sstevel@tonic-gate uint8_t nxt_hdr; 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate /* in summary mode, we don't do anything. */ 9660Sstevel@tonic-gate if (flags & F_SUM) { 9670Sstevel@tonic-gate return; 9680Sstevel@tonic-gate } 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate show_header("IPv6-HopOpts: ", "IPv6 Hop-by-Hop Options Header", 0); 9710Sstevel@tonic-gate show_space(); 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate /* 9740Sstevel@tonic-gate * Store the lengh of this ext hdr in bytes. The caller has 9750Sstevel@tonic-gate * ensured that there is at least len bytes of data left. 9760Sstevel@tonic-gate */ 9770Sstevel@tonic-gate len = ipv6ext_hbh->ip6h_len * 8 + 8; 9780Sstevel@tonic-gate 9791676Sjpk ndata = (const uint8_t *)ipv6ext_hbh + 2; 9800Sstevel@tonic-gate len -= 2; 9810Sstevel@tonic-gate 9820Sstevel@tonic-gate nxt_hdr = ipv6ext_hbh->ip6h_nxt; 9831676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 9840Sstevel@tonic-gate "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr)); 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate while (len > 0) { 9871676Sjpk data = ndata; 9880Sstevel@tonic-gate GETINT8(op_type, data); 9891676Sjpk /* This is the only one-octet IPv6 option */ 9901676Sjpk if (op_type == IP6OPT_PAD1) { 9911676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 9920Sstevel@tonic-gate "pad1 option "); 9930Sstevel@tonic-gate len--; 9941676Sjpk ndata = data; 9951676Sjpk continue; 9961676Sjpk } 9971676Sjpk GETINT8(op_len, data); 9981676Sjpk if (len < 2 || op_len + 2 > len) { 9991676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 10001676Sjpk "Error: option %u truncated (%u + 2 > %u)", 10011676Sjpk op_type, op_len, len); 10021676Sjpk op_len = len - 2; 10031676Sjpk /* 10041676Sjpk * Continue processing the malformed option so that we 10051676Sjpk * can display as much as possible. 10061676Sjpk */ 10071676Sjpk } 10081676Sjpk 10091676Sjpk /* advance pointers to the next option */ 10101676Sjpk len -= op_len + 2; 10111676Sjpk ndata = data + op_len; 10121676Sjpk 10131676Sjpk /* process this option */ 10141676Sjpk switch (op_type) { 10150Sstevel@tonic-gate case IP6OPT_PADN: 10161676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 10170Sstevel@tonic-gate "padN option len = %u", op_len); 10180Sstevel@tonic-gate break; 10190Sstevel@tonic-gate case IP6OPT_JUMBO: { 10200Sstevel@tonic-gate uint32_t payload_len; 10210Sstevel@tonic-gate 10221676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 10231676Sjpk "Jumbo Payload Option len = %u bytes%s", op_len, 10241676Sjpk op_len == sizeof (uint32_t) ? "" : "?"); 10250Sstevel@tonic-gate if (op_len == sizeof (uint32_t)) { 10260Sstevel@tonic-gate GETINT32(payload_len, data); 10271676Sjpk (void) snprintf(get_line(0, 0), 10281676Sjpk get_line_remain(), 10290Sstevel@tonic-gate "Jumbo Payload Length = %u bytes", 10300Sstevel@tonic-gate payload_len); 10310Sstevel@tonic-gate } 10320Sstevel@tonic-gate break; 10330Sstevel@tonic-gate } 10340Sstevel@tonic-gate case IP6OPT_ROUTER_ALERT: { 10350Sstevel@tonic-gate uint16_t value; 10360Sstevel@tonic-gate const char *label[] = {"MLD", "RSVP", "AN"}; 10370Sstevel@tonic-gate 10381676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 10391676Sjpk "Router Alert Option len = %u bytes%s", op_len, 10401676Sjpk op_len == sizeof (uint16_t) ? "" : "?"); 10410Sstevel@tonic-gate if (op_len == sizeof (uint16_t)) { 10420Sstevel@tonic-gate GETINT16(value, data); 10431676Sjpk (void) snprintf(get_line(0, 0), 10441676Sjpk get_line_remain(), 10450Sstevel@tonic-gate "Alert Type = %d (%s)", value, 10460Sstevel@tonic-gate value < sizeof (label) / sizeof (label[0]) ? 10470Sstevel@tonic-gate label[value] : "???"); 10480Sstevel@tonic-gate } 10490Sstevel@tonic-gate break; 10500Sstevel@tonic-gate } 10511676Sjpk case IP6OPT_LS: 10521676Sjpk print_ip6opt_ls(data, op_len); 10531676Sjpk break; 10540Sstevel@tonic-gate default: 10551676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 10560Sstevel@tonic-gate "Option type = %u, len = %u", op_type, op_len); 10570Sstevel@tonic-gate break; 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate } 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate show_space(); 10620Sstevel@tonic-gate } 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate static void 10651676Sjpk prt_dest_options(int flags, const struct ip6_dest *ipv6ext_dest) 10660Sstevel@tonic-gate { 10671676Sjpk const uint8_t *data, *ndata; 10681676Sjpk uint32_t len; 10690Sstevel@tonic-gate uint8_t op_type; 10700Sstevel@tonic-gate uint32_t op_len; 10710Sstevel@tonic-gate uint8_t nxt_hdr; 10720Sstevel@tonic-gate uint8_t value; 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate /* in summary mode, we don't do anything. */ 10750Sstevel@tonic-gate if (flags & F_SUM) { 10760Sstevel@tonic-gate return; 10770Sstevel@tonic-gate } 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate show_header("IPv6-DstOpts: ", "IPv6 Destination Options Header", 0); 10800Sstevel@tonic-gate show_space(); 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate /* 10830Sstevel@tonic-gate * Store the length of this ext hdr in bytes. The caller has 10840Sstevel@tonic-gate * ensured that there is at least len bytes of data left. 10850Sstevel@tonic-gate */ 10860Sstevel@tonic-gate len = ipv6ext_dest->ip6d_len * 8 + 8; 10870Sstevel@tonic-gate 10881676Sjpk ndata = (const uint8_t *)ipv6ext_dest + 2; /* skip hdr/len */ 10890Sstevel@tonic-gate len -= 2; 10900Sstevel@tonic-gate 10910Sstevel@tonic-gate nxt_hdr = ipv6ext_dest->ip6d_nxt; 10921676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 10930Sstevel@tonic-gate "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr)); 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate while (len > 0) { 10961676Sjpk data = ndata; 10970Sstevel@tonic-gate GETINT8(op_type, data); 10981676Sjpk if (op_type == IP6OPT_PAD1) { 10991676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 11000Sstevel@tonic-gate "pad1 option "); 11010Sstevel@tonic-gate len--; 11021676Sjpk ndata = data; 11031676Sjpk continue; 11041676Sjpk } 11051676Sjpk GETINT8(op_len, data); 11061676Sjpk if (len < 2 || op_len + 2 > len) { 11071676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 11081676Sjpk "Error: option %u truncated (%u + 2 > %u)", 11091676Sjpk op_type, op_len, len); 11101676Sjpk op_len = len - 2; 11111676Sjpk /* 11121676Sjpk * Continue processing the malformed option so that we 11131676Sjpk * can display as much as possible. 11141676Sjpk */ 11151676Sjpk } 11161676Sjpk 11171676Sjpk /* advance pointers to the next option */ 11181676Sjpk len -= op_len + 2; 11191676Sjpk ndata = data + op_len; 11201676Sjpk 11211676Sjpk /* process this option */ 11221676Sjpk switch (op_type) { 11230Sstevel@tonic-gate case IP6OPT_PADN: 11241676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 11250Sstevel@tonic-gate "padN option len = %u", op_len); 11260Sstevel@tonic-gate break; 11270Sstevel@tonic-gate case IP6OPT_TUNNEL_LIMIT: 11280Sstevel@tonic-gate GETINT8(value, data); 11291676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 11300Sstevel@tonic-gate "tunnel encapsulation limit len = %d, value = %d", 11310Sstevel@tonic-gate op_len, value); 11321676Sjpk break; 11331676Sjpk case IP6OPT_LS: 11341676Sjpk print_ip6opt_ls(data, op_len); 11350Sstevel@tonic-gate break; 11360Sstevel@tonic-gate default: 11371676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 11380Sstevel@tonic-gate "Option type = %u, len = %u", op_type, op_len); 11390Sstevel@tonic-gate break; 11400Sstevel@tonic-gate } 11410Sstevel@tonic-gate } 11420Sstevel@tonic-gate 11430Sstevel@tonic-gate show_space(); 11440Sstevel@tonic-gate } 11451676Sjpk 11461676Sjpk #define ALABEL_MAXLEN 256 11471676Sjpk 11481676Sjpk static char ascii_label[ALABEL_MAXLEN]; 11491676Sjpk static char *plabel = ascii_label; 11501676Sjpk 11511676Sjpk struct snoop_pair { 11521676Sjpk int val; 11531676Sjpk const char *name; 11541676Sjpk }; 11551676Sjpk 11561676Sjpk static struct snoop_pair ripso_class_tbl[] = { 11571676Sjpk TSOL_CL_TOP_SECRET, "TOP SECRET", 11581676Sjpk TSOL_CL_SECRET, "SECRET", 11591676Sjpk TSOL_CL_CONFIDENTIAL, "CONFIDENTIAL", 11601676Sjpk TSOL_CL_UNCLASSIFIED, "UNCLASSIFIED", 11611676Sjpk -1, NULL 11621676Sjpk }; 11631676Sjpk 11641676Sjpk static struct snoop_pair ripso_prot_tbl[] = { 11651676Sjpk TSOL_PA_GENSER, "GENSER", 11661676Sjpk TSOL_PA_SIOP_ESI, "SIOP-ESI", 11671676Sjpk TSOL_PA_SCI, "SCI", 11681676Sjpk TSOL_PA_NSA, "NSA", 11691676Sjpk TSOL_PA_DOE, "DOE", 11701676Sjpk 0x04, "UNASSIGNED", 11711676Sjpk 0x02, "UNASSIGNED", 11721676Sjpk -1, NULL 11731676Sjpk }; 11741676Sjpk 11751676Sjpk static struct snoop_pair * 11761676Sjpk get_pair_byval(struct snoop_pair pairlist[], int val) 11771676Sjpk { 11781676Sjpk int i; 11791676Sjpk 11801676Sjpk for (i = 0; pairlist[i].name != NULL; i++) 11811676Sjpk if (pairlist[i].val == val) 11821676Sjpk return (&pairlist[i]); 11831676Sjpk return (NULL); 11841676Sjpk } 11851676Sjpk 11861676Sjpk static void 11871676Sjpk print_ripso(const uchar_t *opt) 11881676Sjpk { 11891676Sjpk struct snoop_pair *ripso_class; 11901676Sjpk int i, index, prot_len; 11911676Sjpk boolean_t first_prot; 11921676Sjpk char line[100], *ptr; 11931676Sjpk 11941676Sjpk prot_len = opt[1] - 3; 11951676Sjpk if (prot_len < 0) 11961676Sjpk return; 11971676Sjpk 11981676Sjpk show_header("RIPSO: ", "Revised IP Security Option", 0); 11991676Sjpk show_space(); 12001676Sjpk 12011676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 12021676Sjpk "Type = Basic Security Option (%d), Length = %d", opt[0], opt[1]); 12031676Sjpk 12041676Sjpk /* 12051676Sjpk * Display Classification Level 12061676Sjpk */ 12071676Sjpk ripso_class = get_pair_byval(ripso_class_tbl, (int)opt[2]); 12081676Sjpk if (ripso_class != NULL) 12091676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 12101676Sjpk "Classification = Unknown (0x%02x)", opt[2]); 12111676Sjpk else 12121676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 12131676Sjpk "Classification = %s (0x%02x)", 12141676Sjpk ripso_class->name, ripso_class->val); 12151676Sjpk 12161676Sjpk /* 12171676Sjpk * Display Protection Authority Flags 12181676Sjpk */ 12191676Sjpk (void) snprintf(line, sizeof (line), "Protection Authority = "); 12201676Sjpk ptr = line; 12211676Sjpk first_prot = B_TRUE; 12221676Sjpk for (i = 0; i < prot_len; i++) { 12231676Sjpk index = 0; 12241676Sjpk while (ripso_prot_tbl[index].name != NULL) { 12251676Sjpk if (opt[3 + i] & ripso_prot_tbl[index].val) { 12261676Sjpk ptr = strchr(ptr, 0); 12271676Sjpk if (!first_prot) { 12281676Sjpk (void) strlcpy(ptr, ", ", 12291676Sjpk sizeof (line) - (ptr - line)); 12301676Sjpk ptr = strchr(ptr, 0); 12311676Sjpk } 12321676Sjpk (void) snprintf(ptr, 12331676Sjpk sizeof (line) - (ptr - line), 12341676Sjpk "%s (0x%02x)", 12351676Sjpk ripso_prot_tbl[index].name, 12361676Sjpk ripso_prot_tbl[index].val); 12371676Sjpk } 12381676Sjpk index++; 12391676Sjpk } 12401676Sjpk if ((opt[3 + i] & 1) == 0) 12411676Sjpk break; 12421676Sjpk } 12431676Sjpk if (!first_prot) 12441676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), "%s", line); 12451676Sjpk else 12461676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), "%sNone", 12471676Sjpk line); 12481676Sjpk } 12491676Sjpk 12501676Sjpk #define CIPSO_GENERIC_ARRAY_LEN 200 12511676Sjpk 12521676Sjpk /* 12531676Sjpk * Return 1 if CIPSO SL and Categories are all 1's; 0 otherwise. 12541676Sjpk * 12551676Sjpk * Note: opt starts with "Tag Type": 12561676Sjpk * 12571676Sjpk * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)| 12581676Sjpk * 12591676Sjpk */ 12601676Sjpk static boolean_t 12611676Sjpk cipso_high(const uchar_t *opt) 12621676Sjpk { 12631676Sjpk int i; 12641676Sjpk 12651676Sjpk if (((int)opt[1] + 6) < IP_MAX_OPT_LENGTH) 12661676Sjpk return (B_FALSE); 12671676Sjpk for (i = 0; i < ((int)opt[1] - 3); i++) 12681676Sjpk if (opt[3 + i] != 0xff) 12691676Sjpk return (B_FALSE); 12701676Sjpk return (B_TRUE); 12711676Sjpk } 12721676Sjpk 12731676Sjpk /* 12741676Sjpk * Converts CIPSO label to SL. 12751676Sjpk * 12761676Sjpk * Note: opt starts with "Tag Type": 12771676Sjpk * 12781676Sjpk * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)| 12791676Sjpk * 12801676Sjpk */ 12811676Sjpk static void 12821676Sjpk cipso2sl(const uchar_t *opt, bslabel_t *sl, int *high) 12831676Sjpk { 12841676Sjpk int i, taglen; 12851676Sjpk uchar_t *q = (uchar_t *)&((_bslabel_impl_t *)sl)->compartments; 12861676Sjpk 12871676Sjpk *high = 0; 12881676Sjpk taglen = opt[1]; 12891676Sjpk memset((caddr_t)sl, 0, sizeof (bslabel_t)); 12901676Sjpk 12911676Sjpk if (cipso_high(opt)) { 12921676Sjpk BSLHIGH(sl); 12931676Sjpk *high = 1; 12941676Sjpk } else { 12951676Sjpk LCLASS_SET((_bslabel_impl_t *)sl, opt[3]); 12961676Sjpk for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) 12971676Sjpk q[i] = opt[TSOL_TT1_MIN_LENGTH + i]; 12981676Sjpk } 12991676Sjpk SETBLTYPE(sl, SUN_SL_ID); 13001676Sjpk } 13011676Sjpk 13021676Sjpk static int 13031676Sjpk interpret_cipso_tagtype1(const uchar_t *opt) 13041676Sjpk { 13051676Sjpk int i, taglen, ishigh; 13061676Sjpk bslabel_t sl; 13071676Sjpk char line[CIPSO_GENERIC_ARRAY_LEN], *ptr; 13081676Sjpk 13091676Sjpk taglen = opt[1]; 13101676Sjpk if (taglen < TSOL_TT1_MIN_LENGTH || 13111676Sjpk taglen > TSOL_TT1_MAX_LENGTH) 13121676Sjpk return (taglen); 13131676Sjpk 13141676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13151676Sjpk "Tag Type = %d, Tag Length = %d", opt[0], opt[1]); 13161676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13171676Sjpk "Sensitivity Level = 0x%02x", opt[3]); 13181676Sjpk ptr = line; 13191676Sjpk for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) { 13201676Sjpk (void) snprintf(ptr, sizeof (line) - (ptr - line), "%02x", 13211676Sjpk opt[TSOL_TT1_MIN_LENGTH + i]); 13221676Sjpk ptr = strchr(ptr, 0); 13231676Sjpk } 13241676Sjpk if (i != 0) { 13251676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13261676Sjpk "Categories = "); 13271676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), "\t%s", 13281676Sjpk line); 13291676Sjpk } else { 13301676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13311676Sjpk "Categories = None"); 13321676Sjpk } 13331676Sjpk cipso2sl(opt, &sl, &ishigh); 13341688Srica if (is_system_labeled()) { 13351676Sjpk if (bsltos(&sl, &plabel, ALABEL_MAXLEN, 13361676Sjpk LONG_CLASSIFICATION|LONG_WORDS|VIEW_INTERNAL) < 0) { 13371676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13381676Sjpk "The Sensitivity Level and Categories can't be " 13391676Sjpk "mapped to a valid SL"); 13401676Sjpk } else { 13411676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13421676Sjpk "The Sensitivity Level and Categories are mapped " 13431676Sjpk "to the SL:"); 13441676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13451676Sjpk "\t%s", ascii_label); 13461676Sjpk } 13471676Sjpk } 13481676Sjpk return (taglen); 13491676Sjpk } 13501676Sjpk 13511676Sjpk /* 13521676Sjpk * The following struct definition #define's are copied from TS1.x. They are 13531676Sjpk * not used here (except TTYPE_3_MAX_TOKENS), but included as a reference for 13541676Sjpk * the tag type 3 packet format. 13551676Sjpk */ 13561676Sjpk #define TTYPE_3_MAX_TOKENS 7 13571676Sjpk 13581676Sjpk /* 13591676Sjpk * Display CIPSO tag type 3 which is defined by MAXSIX. 13601676Sjpk */ 13611676Sjpk static int 13621676Sjpk interpret_cipso_tagtype3(const uchar_t *opt) 13631676Sjpk { 13641676Sjpk uchar_t tagtype; 13651676Sjpk int index, numtokens, taglen; 13661676Sjpk uint16_t mask; 13671676Sjpk uint32_t token; 13681676Sjpk static const char *name[] = { 13691676Sjpk "SL", 13701676Sjpk "NCAV", 13711676Sjpk "INTEG", 13721676Sjpk "SID", 13731676Sjpk "undefined", 13741676Sjpk "undefined", 13751676Sjpk "IL", 13761676Sjpk "PRIVS", 13771676Sjpk "LUID", 13781676Sjpk "PID", 13791676Sjpk "IDS", 13801676Sjpk "ACL" 13811676Sjpk }; 13821676Sjpk 13831676Sjpk tagtype = *opt++; 13841676Sjpk (void) memcpy(&mask, opt + 3, sizeof (mask)); 13851676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13861676Sjpk "Tag Type = %d (MAXSIX)", tagtype); 13871676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 13881676Sjpk "Generation = 0x%02x%02x%02x, Mask = 0x%04x", opt[0], opt[1], 13891676Sjpk opt[2], mask); 13901676Sjpk opt += 3 + sizeof (mask); 13911676Sjpk 13921676Sjpk /* 13931676Sjpk * Display tokens 13941676Sjpk */ 13951676Sjpk numtokens = 0; 13961676Sjpk index = 0; 13971676Sjpk while (mask != 0 && numtokens < TTYPE_3_MAX_TOKENS) { 13981676Sjpk if (mask & 0x0001) { 13991676Sjpk (void) memcpy(&token, opt, sizeof (token)); 14001676Sjpk opt += sizeof (token); 14011676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 14021676Sjpk "Attribute = %s, Token = 0x%08x", 14031676Sjpk index < sizeof (name) / sizeof (*name) ? 14041676Sjpk name[index] : "unknown", token); 14051676Sjpk numtokens++; 14061676Sjpk } 14071676Sjpk mask = mask >> 1; 14081676Sjpk index++; 14091676Sjpk } 14101676Sjpk 14111676Sjpk taglen = 6 + numtokens * 4; 14121676Sjpk return (taglen); 14131676Sjpk } 14141676Sjpk 14151676Sjpk static void 14161676Sjpk print_cipso(const uchar_t *opt) 14171676Sjpk { 14181676Sjpk int optlen, taglen, tagnum; 14191676Sjpk uint32_t doi; 14201676Sjpk char line[CIPSO_GENERIC_ARRAY_LEN]; 14211676Sjpk char *oldnest; 14221676Sjpk 14231676Sjpk optlen = opt[1]; 14241676Sjpk if (optlen < TSOL_CIPSO_MIN_LENGTH || optlen > TSOL_CIPSO_MAX_LENGTH) 14251676Sjpk return; 14261676Sjpk 14271676Sjpk oldnest = prot_nest_prefix; 14281676Sjpk prot_nest_prefix = prot_prefix; 14291676Sjpk show_header("CIPSO: ", "Common IP Security Option", 0); 14301676Sjpk show_space(); 14311676Sjpk 14321676Sjpk /* 14331676Sjpk * Display CIPSO Header 14341676Sjpk */ 14351676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 14361676Sjpk "Type = CIPSO (%d), Length = %d", opt[0], opt[1]); 14371676Sjpk (void) memcpy(&doi, opt + 2, sizeof (doi)); 14381676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 14391676Sjpk "Domain of Interpretation = %u", (unsigned)ntohl(doi)); 14401676Sjpk 14411676Sjpk if (opt[1] == TSOL_CIPSO_MIN_LENGTH) { /* no tags */ 14421676Sjpk show_space(); 14431676Sjpk prot_prefix = prot_nest_prefix; 14441676Sjpk prot_nest_prefix = oldnest; 14451676Sjpk return; 14461676Sjpk } 14471676Sjpk optlen -= TSOL_CIPSO_MIN_LENGTH; 14481676Sjpk opt += TSOL_CIPSO_MIN_LENGTH; 14491676Sjpk 14501676Sjpk /* 14511676Sjpk * Display Each Tag 14521676Sjpk */ 14531676Sjpk tagnum = 1; 14541676Sjpk while (optlen >= TSOL_TT1_MIN_LENGTH) { 14551676Sjpk (void) snprintf(line, sizeof (line), "Tag# %d", tagnum); 14561676Sjpk show_header("CIPSO: ", line, 0); 14571676Sjpk /* 14581676Sjpk * We handle tag type 1 and 3 only. Note, tag type 3 14591676Sjpk * is MAXSIX defined. 14601676Sjpk */ 14611676Sjpk switch (opt[0]) { 14621676Sjpk case 1: 14631676Sjpk taglen = interpret_cipso_tagtype1(opt); 14641676Sjpk break; 14651676Sjpk case 3: 14661676Sjpk taglen = interpret_cipso_tagtype3(opt); 14671676Sjpk break; 14681676Sjpk default: 14691676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 14701676Sjpk "Unknown Tag Type %d", opt[0]); 14711676Sjpk show_space(); 14721676Sjpk prot_prefix = prot_nest_prefix; 14731676Sjpk prot_nest_prefix = oldnest; 14741676Sjpk return; 14751676Sjpk } 14761676Sjpk 14771676Sjpk /* 14781676Sjpk * Move to the next tag 14791676Sjpk */ 14801676Sjpk if (taglen <= 0) 14811676Sjpk break; 14821676Sjpk optlen -= taglen; 14831676Sjpk opt += taglen; 14841676Sjpk tagnum++; 14851676Sjpk } 14861676Sjpk show_space(); 14871676Sjpk prot_prefix = prot_nest_prefix; 14881676Sjpk prot_nest_prefix = oldnest; 14891676Sjpk } 1490