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 5*1676Sjpk * Common Development and Distribution License (the "License"). 6*1676Sjpk * 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*1676Sjpk * 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> 46*1676Sjpk #include <inet/ip.h> 470Sstevel@tonic-gate #include <inet/ip6.h> 480Sstevel@tonic-gate #include <arpa/inet.h> 490Sstevel@tonic-gate #include <netdb.h> 50*1676Sjpk #include <tsol/label.h> 51*1676Sjpk #include <sys/tsol/tndb.h> 52*1676Sjpk #include <sys/tsol/label_macro.h> 53*1676Sjpk 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 71*1676Sjpk static void prt_routing_hdr(int, const struct ip6_rthdr *); 72*1676Sjpk static void prt_fragment_hdr(int, const struct ip6_frag *); 73*1676Sjpk static void prt_hbh_options(int, const struct ip6_hbh *); 74*1676Sjpk static void prt_dest_options(int, const struct ip6_dest *); 75*1676Sjpk static void print_route(const uchar_t *); 76*1676Sjpk static void print_ipoptions(const uchar_t *, int); 77*1676Sjpk static void print_ripso(const uchar_t *); 78*1676Sjpk 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 85*1676Sjpk interpret_ip(int flags, const struct ip *ip, int fraglen) 860Sstevel@tonic-gate { 87*1676Sjpk 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; 107*1676Sjpk 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(); 162*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 163*1676Sjpk "Version = %d", ip->ip_v); 164*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 165*1676Sjpk "Header length = %d bytes", hdrlen); 166*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 167*1676Sjpk "Type of service = 0x%02x", ip->ip_tos); 168*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 169*1676Sjpk " xxx. .... = %d (precedence)", 1700Sstevel@tonic-gate ip->ip_tos >> 5); 171*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 172*1676Sjpk " %s", getflag(ip->ip_tos, IPTOS_LOWDELAY, 1730Sstevel@tonic-gate "low delay", "normal delay")); 174*1676Sjpk (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")); 177*1676Sjpk (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")); 180*1676Sjpk (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")); 183*1676Sjpk (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); 189*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 190*1676Sjpk "Total length = %u bytes%s", uitmp, 1910Sstevel@tonic-gate iplen > fraglen ? " -- truncated" : ""); 192*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 193*1676Sjpk "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); 196*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 197*1676Sjpk "Flags = 0x%x", uitmp >> 12); 198*1676Sjpk (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")); 201*1676Sjpk (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")); 204*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 205*1676Sjpk "Fragment offset = %u bytes", 2060Sstevel@tonic-gate fragoffset); 207*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 208*1676Sjpk "Time to live = %d seconds/hops", 2090Sstevel@tonic-gate ip->ip_ttl); 210*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 211*1676Sjpk "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 */ 216*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 217*1676Sjpk "Header checksum = %04x", 2180Sstevel@tonic-gate ntohs(ip->ip_sum)); 219*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 220*1676Sjpk "Source address = %s, %s", 2210Sstevel@tonic-gate inet_ntoa(ip->ip_src), addrtoname(AF_INET, &ip->ip_src)); 222*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 223*1676Sjpk "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 228*1676Sjpk print_ipoptions((const uchar_t *)(ip + 1), 229*1676Sjpk 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) { 241*1676Sjpk (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: 254*1676Sjpk (void) interpret_ip(flags, 255*1676Sjpk /* LINTED: alignment */ 256*1676Sjpk (const struct ip *)data, fraglen); 2570Sstevel@tonic-gate break; 2580Sstevel@tonic-gate case IPPROTO_ICMP: 259*1676Sjpk (void) interpret_icmp(flags, 260*1676Sjpk /* LINTED: alignment */ 261*1676Sjpk (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: 269*1676Sjpk (void) interpret_tcp(flags, 270*1676Sjpk (struct tcphdr *)data, iplen, fraglen); 2710Sstevel@tonic-gate break; 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate case IPPROTO_ESP: 274*1676Sjpk (void) interpret_esp(flags, data, iplen, 275*1676Sjpk fraglen); 2760Sstevel@tonic-gate break; 2770Sstevel@tonic-gate case IPPROTO_AH: 278*1676Sjpk (void) interpret_ah(flags, data, iplen, 279*1676Sjpk 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: 290*1676Sjpk (void) interpret_udp(flags, 291*1676Sjpk (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 */ 300*1676Sjpk /* 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: 305*1676Sjpk (void) interpret_sctp(flags, 306*1676Sjpk (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 317*1676Sjpk 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) { 361*1676Sjpk (void) snprintf(get_sum_line(), MAXLINE, 362*1676Sjpk "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 388*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3890Sstevel@tonic-gate "Version = %d", version); 390*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3910Sstevel@tonic-gate "Traffic Class = %d", class); 392*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 3930Sstevel@tonic-gate "Flow label = 0x%x", flow); 394*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 395*1676Sjpk "Payload length = %d", iplen); 396*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 397*1676Sjpk "Next Header = %d (%s)", proto, 3980Sstevel@tonic-gate getproto(proto)); 399*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 400*1676Sjpk "Hop Limit = %d", ip6h->ip6_hops); 401*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 4020Sstevel@tonic-gate "Source address = %s%s", src_addrstr, print_srcname); 403*1676Sjpk (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: 436*1676Sjpk /* LINTED: alignment */ 437*1676Sjpk (void) interpret_ip(flags, (const struct ip *)data, 438*1676Sjpk fraglen); 4390Sstevel@tonic-gate break; 4400Sstevel@tonic-gate case IPPROTO_ICMPV6: 441*1676Sjpk /* LINTED: alignment */ 442*1676Sjpk (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: 451*1676Sjpk (void) interpret_tcp(flags, (struct tcphdr *)data, 452*1676Sjpk iplen, fraglen); 4530Sstevel@tonic-gate break; 4540Sstevel@tonic-gate case IPPROTO_ESP: 455*1676Sjpk (void) interpret_esp(flags, data, iplen, fraglen); 4560Sstevel@tonic-gate break; 4570Sstevel@tonic-gate case IPPROTO_AH: 458*1676Sjpk (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: 464*1676Sjpk (void) interpret_udp(flags, (struct udphdr *)data, 465*1676Sjpk 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: 473*1676Sjpk /* LINTED: alignment */ 474*1676Sjpk (void) interpret_ipv6(flags, (const ip6_t *)data, 475*1676Sjpk iplen); 4760Sstevel@tonic-gate break; 4770Sstevel@tonic-gate case IPPROTO_SCTP: 478*1676Sjpk (void) interpret_sctp(flags, (struct sctp_hdr *)data, 479*1676Sjpk 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: 557*1676Sjpk /* 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 593*1676Sjpk print_ipoptions(const uchar_t *opt, int optlen) 5940Sstevel@tonic-gate { 5950Sstevel@tonic-gate int len; 596*1676Sjpk int remain; 5970Sstevel@tonic-gate char *line; 598*1676Sjpk const char *truncstr; 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate if (optlen <= 0) { 601*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 6020Sstevel@tonic-gate "No options"); 6030Sstevel@tonic-gate return; 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate 606*1676Sjpk (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) { 610*1676Sjpk line = get_line(0, 0); 611*1676Sjpk remain = get_line_remain(); 6120Sstevel@tonic-gate len = opt[1]; 613*1676Sjpk truncstr = len > optlen ? "?" : ""; 6140Sstevel@tonic-gate switch (opt[0]) { 6150Sstevel@tonic-gate case IPOPT_EOL: 616*1676Sjpk (void) strlcpy(line, " - End of option list", remain); 6170Sstevel@tonic-gate return; 6180Sstevel@tonic-gate case IPOPT_NOP: 619*1676Sjpk (void) strlcpy(line, " - No op", remain); 6200Sstevel@tonic-gate len = 1; 6210Sstevel@tonic-gate break; 6220Sstevel@tonic-gate case IPOPT_RR: 623*1676Sjpk (void) snprintf(line, remain, 624*1676Sjpk " - Record route (%d bytes%s)", len, truncstr); 6250Sstevel@tonic-gate print_route(opt); 6260Sstevel@tonic-gate break; 6270Sstevel@tonic-gate case IPOPT_TS: 628*1676Sjpk (void) snprintf(line, remain, 629*1676Sjpk " - Time stamp (%d bytes%s)", len, truncstr); 6300Sstevel@tonic-gate break; 6310Sstevel@tonic-gate case IPOPT_SECURITY: 632*1676Sjpk (void) snprintf(line, remain, " - RIPSO (%d bytes%s)", 633*1676Sjpk len, truncstr); 634*1676Sjpk print_ripso(opt); 635*1676Sjpk break; 636*1676Sjpk case IPOPT_COMSEC: 637*1676Sjpk (void) snprintf(line, remain, " - CIPSO (%d bytes%s)", 638*1676Sjpk len, truncstr); 639*1676Sjpk print_cipso(opt); 6400Sstevel@tonic-gate break; 6410Sstevel@tonic-gate case IPOPT_LSRR: 642*1676Sjpk (void) snprintf(line, remain, 643*1676Sjpk " - Loose source route (%d bytes%s)", len, 644*1676Sjpk truncstr); 6450Sstevel@tonic-gate print_route(opt); 6460Sstevel@tonic-gate break; 6470Sstevel@tonic-gate case IPOPT_SATID: 648*1676Sjpk (void) snprintf(line, remain, 649*1676Sjpk " - SATNET Stream id (%d bytes%s)", 650*1676Sjpk len, truncstr); 6510Sstevel@tonic-gate break; 6520Sstevel@tonic-gate case IPOPT_SSRR: 653*1676Sjpk (void) snprintf(line, remain, 654*1676Sjpk " - Strict source route, (%d bytes%s)", len, 655*1676Sjpk truncstr); 6560Sstevel@tonic-gate print_route(opt); 6570Sstevel@tonic-gate break; 6580Sstevel@tonic-gate default: 659*1676Sjpk (void) snprintf(line, remain, 660*1676Sjpk " - Option %d (unknown - %d bytes%s) %s", 661*1676Sjpk opt[0], len, truncstr, 662*1676Sjpk tohex((char *)&opt[2], len - 2)); 6630Sstevel@tonic-gate break; 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate if (len <= 0) { 666*1676Sjpk (void) snprintf(line, remain, 667*1676Sjpk " - 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 676*1676Sjpk print_route(const uchar_t *opt) 6770Sstevel@tonic-gate { 678*1676Sjpk 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 685*1676Sjpk (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) { 693*1676Sjpk line = get_line(0, 0); 694*1676Sjpk remain = get_line_remain(); 6950Sstevel@tonic-gate memcpy((char *)&addr, opt, sizeof (addr)); 6960Sstevel@tonic-gate if (addr.s_addr == INADDR_ANY) 697*1676Sjpk (void) strlcpy(line, " -", remain); 6980Sstevel@tonic-gate else 699*1676Sjpk (void) snprintf(line, remain, " %s", 7000Sstevel@tonic-gate addrtoname(AF_INET, &addr)); 7010Sstevel@tonic-gate if (pointer == 0) 702*1676Sjpk (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 * 711*1676Sjpk 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 742*1676Sjpk 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 767*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7680Sstevel@tonic-gate "Next header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 769*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7700Sstevel@tonic-gate "Header length = %d", len); 771*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 7720Sstevel@tonic-gate "Routing type = %d", type); 773*1676Sjpk (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 */ 786*1676Sjpk /* 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); 793*1676Sjpk (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 802*1676Sjpk 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) { 817*1676Sjpk (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 826*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8270Sstevel@tonic-gate "Next Header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 828*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8290Sstevel@tonic-gate "Fragment Offset = %d", fragoffset); 830*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 8310Sstevel@tonic-gate "More Fragments Flag = %s", morefrag ? "true" : "false"); 832*1676Sjpk (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 840*1676Sjpk print_ip6opt_ls(const uchar_t *data, unsigned int op_len) 8410Sstevel@tonic-gate { 842*1676Sjpk uint32_t doi; 843*1676Sjpk uint8_t sotype, solen; 844*1676Sjpk uint16_t value, value2; 845*1676Sjpk char *cp; 846*1676Sjpk int remlen; 847*1676Sjpk boolean_t printed; 848*1676Sjpk 849*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 850*1676Sjpk "Labeled Security Option len = %u bytes%s", op_len, 851*1676Sjpk op_len < sizeof (uint32_t) || (op_len & 1) != 0 ? "?" : ""); 852*1676Sjpk if (op_len < sizeof (uint32_t)) 853*1676Sjpk return; 854*1676Sjpk GETINT32(doi, data); 855*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 856*1676Sjpk " DOI = %d (%s)", doi, doi == IP6LS_DOI_V4 ? "IPv4" : "???"); 857*1676Sjpk op_len -= sizeof (uint32_t); 858*1676Sjpk while (op_len > 0) { 859*1676Sjpk GETINT8(sotype, data); 860*1676Sjpk if (op_len < 2) { 861*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 862*1676Sjpk " truncated %u suboption (no len)", sotype); 863*1676Sjpk break; 864*1676Sjpk } 865*1676Sjpk GETINT8(solen, data); 866*1676Sjpk if (solen < 2 || solen > op_len) { 867*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 868*1676Sjpk " bad %u suboption (len 2 <= %u <= %u)", 869*1676Sjpk sotype, solen, op_len); 870*1676Sjpk if (solen < 2) 871*1676Sjpk solen = 2; 872*1676Sjpk if (solen > op_len) 873*1676Sjpk solen = op_len; 874*1676Sjpk } 875*1676Sjpk op_len -= solen; 876*1676Sjpk solen -= 2; 877*1676Sjpk cp = get_line(0, 0); 878*1676Sjpk remlen = get_line_remain(); 879*1676Sjpk (void) strlcpy(cp, " ", remlen); 880*1676Sjpk cp += 4; 881*1676Sjpk remlen -= 4; 882*1676Sjpk printed = B_TRUE; 883*1676Sjpk switch (sotype) { 884*1676Sjpk case IP6LS_TT_LEVEL: 885*1676Sjpk if (solen != 2) { 886*1676Sjpk printed = B_FALSE; 887*1676Sjpk break; 888*1676Sjpk } 889*1676Sjpk GETINT16(value, data); 890*1676Sjpk (void) snprintf(cp, remlen, "Level %u", value); 891*1676Sjpk solen = 0; 892*1676Sjpk break; 893*1676Sjpk case IP6LS_TT_VECTOR: 894*1676Sjpk (void) strlcpy(cp, "Bit-Vector: ", remlen); 895*1676Sjpk remlen -= strlen(cp); 896*1676Sjpk cp += strlen(cp); 897*1676Sjpk while (solen > 1) { 898*1676Sjpk GETINT16(value, data); 899*1676Sjpk solen -= 2; 900*1676Sjpk (void) snprintf(cp, remlen, "%04x", value); 901*1676Sjpk remlen -= strlen(cp); 902*1676Sjpk cp += strlen(cp); 903*1676Sjpk } 904*1676Sjpk break; 905*1676Sjpk case IP6LS_TT_ENUM: 906*1676Sjpk (void) strlcpy(cp, "Enumeration:", remlen); 907*1676Sjpk remlen -= strlen(cp); 908*1676Sjpk cp += strlen(cp); 909*1676Sjpk while (solen > 1) { 910*1676Sjpk GETINT16(value, data); 911*1676Sjpk solen -= 2; 912*1676Sjpk (void) snprintf(cp, remlen, " %u", value); 913*1676Sjpk remlen -= strlen(cp); 914*1676Sjpk cp += strlen(cp); 915*1676Sjpk } 916*1676Sjpk break; 917*1676Sjpk case IP6LS_TT_RANGES: 918*1676Sjpk (void) strlcpy(cp, "Ranges:", remlen); 919*1676Sjpk remlen -= strlen(cp); 920*1676Sjpk cp += strlen(cp); 921*1676Sjpk while (solen > 3) { 922*1676Sjpk GETINT16(value, data); 923*1676Sjpk GETINT16(value2, data); 924*1676Sjpk solen -= 4; 925*1676Sjpk (void) snprintf(cp, remlen, " %u-%u", value, 926*1676Sjpk value2); 927*1676Sjpk remlen -= strlen(cp); 928*1676Sjpk cp += strlen(cp); 929*1676Sjpk } 930*1676Sjpk break; 931*1676Sjpk case IP6LS_TT_V4: 932*1676Sjpk (void) strlcpy(cp, "IPv4 Option", remlen); 933*1676Sjpk print_ipoptions(data, solen); 934*1676Sjpk solen = 0; 935*1676Sjpk break; 936*1676Sjpk case IP6LS_TT_DEST: 937*1676Sjpk (void) snprintf(cp, remlen, 938*1676Sjpk "Destination-Only Data length %u", solen); 939*1676Sjpk solen = 0; 940*1676Sjpk break; 941*1676Sjpk default: 942*1676Sjpk (void) snprintf(cp, remlen, 943*1676Sjpk " unknown %u suboption (len %u)", sotype, solen); 944*1676Sjpk solen = 0; 945*1676Sjpk break; 946*1676Sjpk } 947*1676Sjpk if (solen != 0) { 948*1676Sjpk if (printed) { 949*1676Sjpk cp = get_line(0, 0); 950*1676Sjpk remlen = get_line_remain(); 951*1676Sjpk } 952*1676Sjpk (void) snprintf(cp, remlen, 953*1676Sjpk " malformed %u suboption (remaining %u)", 954*1676Sjpk sotype, solen); 955*1676Sjpk data += solen; 956*1676Sjpk } 957*1676Sjpk } 958*1676Sjpk } 959*1676Sjpk 960*1676Sjpk static void 961*1676Sjpk prt_hbh_options(int flags, const struct ip6_hbh *ipv6ext_hbh) 962*1676Sjpk { 963*1676Sjpk const uint8_t *data, *ndata; 964*1676Sjpk 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 983*1676Sjpk ndata = (const uint8_t *)ipv6ext_hbh + 2; 9840Sstevel@tonic-gate len -= 2; 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate nxt_hdr = ipv6ext_hbh->ip6h_nxt; 987*1676Sjpk (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) { 991*1676Sjpk data = ndata; 9920Sstevel@tonic-gate GETINT8(op_type, data); 993*1676Sjpk /* This is the only one-octet IPv6 option */ 994*1676Sjpk if (op_type == IP6OPT_PAD1) { 995*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 9960Sstevel@tonic-gate "pad1 option "); 9970Sstevel@tonic-gate len--; 998*1676Sjpk ndata = data; 999*1676Sjpk continue; 1000*1676Sjpk } 1001*1676Sjpk GETINT8(op_len, data); 1002*1676Sjpk if (len < 2 || op_len + 2 > len) { 1003*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1004*1676Sjpk "Error: option %u truncated (%u + 2 > %u)", 1005*1676Sjpk op_type, op_len, len); 1006*1676Sjpk op_len = len - 2; 1007*1676Sjpk /* 1008*1676Sjpk * Continue processing the malformed option so that we 1009*1676Sjpk * can display as much as possible. 1010*1676Sjpk */ 1011*1676Sjpk } 1012*1676Sjpk 1013*1676Sjpk /* advance pointers to the next option */ 1014*1676Sjpk len -= op_len + 2; 1015*1676Sjpk ndata = data + op_len; 1016*1676Sjpk 1017*1676Sjpk /* process this option */ 1018*1676Sjpk switch (op_type) { 10190Sstevel@tonic-gate case IP6OPT_PADN: 1020*1676Sjpk (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 1026*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1027*1676Sjpk "Jumbo Payload Option len = %u bytes%s", op_len, 1028*1676Sjpk op_len == sizeof (uint32_t) ? "" : "?"); 10290Sstevel@tonic-gate if (op_len == sizeof (uint32_t)) { 10300Sstevel@tonic-gate GETINT32(payload_len, data); 1031*1676Sjpk (void) snprintf(get_line(0, 0), 1032*1676Sjpk 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 1042*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1043*1676Sjpk "Router Alert Option len = %u bytes%s", op_len, 1044*1676Sjpk op_len == sizeof (uint16_t) ? "" : "?"); 10450Sstevel@tonic-gate if (op_len == sizeof (uint16_t)) { 10460Sstevel@tonic-gate GETINT16(value, data); 1047*1676Sjpk (void) snprintf(get_line(0, 0), 1048*1676Sjpk 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 } 1055*1676Sjpk case IP6OPT_LS: 1056*1676Sjpk print_ip6opt_ls(data, op_len); 1057*1676Sjpk break; 10580Sstevel@tonic-gate default: 1059*1676Sjpk (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 1069*1676Sjpk prt_dest_options(int flags, const struct ip6_dest *ipv6ext_dest) 10700Sstevel@tonic-gate { 1071*1676Sjpk const uint8_t *data, *ndata; 1072*1676Sjpk 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 1092*1676Sjpk 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; 1096*1676Sjpk (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) { 1100*1676Sjpk data = ndata; 11010Sstevel@tonic-gate GETINT8(op_type, data); 1102*1676Sjpk if (op_type == IP6OPT_PAD1) { 1103*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 11040Sstevel@tonic-gate "pad1 option "); 11050Sstevel@tonic-gate len--; 1106*1676Sjpk ndata = data; 1107*1676Sjpk continue; 1108*1676Sjpk } 1109*1676Sjpk GETINT8(op_len, data); 1110*1676Sjpk if (len < 2 || op_len + 2 > len) { 1111*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1112*1676Sjpk "Error: option %u truncated (%u + 2 > %u)", 1113*1676Sjpk op_type, op_len, len); 1114*1676Sjpk op_len = len - 2; 1115*1676Sjpk /* 1116*1676Sjpk * Continue processing the malformed option so that we 1117*1676Sjpk * can display as much as possible. 1118*1676Sjpk */ 1119*1676Sjpk } 1120*1676Sjpk 1121*1676Sjpk /* advance pointers to the next option */ 1122*1676Sjpk len -= op_len + 2; 1123*1676Sjpk ndata = data + op_len; 1124*1676Sjpk 1125*1676Sjpk /* process this option */ 1126*1676Sjpk switch (op_type) { 11270Sstevel@tonic-gate case IP6OPT_PADN: 1128*1676Sjpk (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); 1133*1676Sjpk (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); 1136*1676Sjpk break; 1137*1676Sjpk case IP6OPT_LS: 1138*1676Sjpk print_ip6opt_ls(data, op_len); 11390Sstevel@tonic-gate break; 11400Sstevel@tonic-gate default: 1141*1676Sjpk (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 } 1149*1676Sjpk 1150*1676Sjpk #define ALABEL_MAXLEN 256 1151*1676Sjpk 1152*1676Sjpk static char ascii_label[ALABEL_MAXLEN]; 1153*1676Sjpk static char *plabel = ascii_label; 1154*1676Sjpk 1155*1676Sjpk struct snoop_pair { 1156*1676Sjpk int val; 1157*1676Sjpk const char *name; 1158*1676Sjpk }; 1159*1676Sjpk 1160*1676Sjpk static struct snoop_pair ripso_class_tbl[] = { 1161*1676Sjpk TSOL_CL_TOP_SECRET, "TOP SECRET", 1162*1676Sjpk TSOL_CL_SECRET, "SECRET", 1163*1676Sjpk TSOL_CL_CONFIDENTIAL, "CONFIDENTIAL", 1164*1676Sjpk TSOL_CL_UNCLASSIFIED, "UNCLASSIFIED", 1165*1676Sjpk -1, NULL 1166*1676Sjpk }; 1167*1676Sjpk 1168*1676Sjpk static struct snoop_pair ripso_prot_tbl[] = { 1169*1676Sjpk TSOL_PA_GENSER, "GENSER", 1170*1676Sjpk TSOL_PA_SIOP_ESI, "SIOP-ESI", 1171*1676Sjpk TSOL_PA_SCI, "SCI", 1172*1676Sjpk TSOL_PA_NSA, "NSA", 1173*1676Sjpk TSOL_PA_DOE, "DOE", 1174*1676Sjpk 0x04, "UNASSIGNED", 1175*1676Sjpk 0x02, "UNASSIGNED", 1176*1676Sjpk -1, NULL 1177*1676Sjpk }; 1178*1676Sjpk 1179*1676Sjpk static struct snoop_pair * 1180*1676Sjpk get_pair_byval(struct snoop_pair pairlist[], int val) 1181*1676Sjpk { 1182*1676Sjpk int i; 1183*1676Sjpk 1184*1676Sjpk for (i = 0; pairlist[i].name != NULL; i++) 1185*1676Sjpk if (pairlist[i].val == val) 1186*1676Sjpk return (&pairlist[i]); 1187*1676Sjpk return (NULL); 1188*1676Sjpk } 1189*1676Sjpk 1190*1676Sjpk static void 1191*1676Sjpk print_ripso(const uchar_t *opt) 1192*1676Sjpk { 1193*1676Sjpk struct snoop_pair *ripso_class; 1194*1676Sjpk int i, index, prot_len; 1195*1676Sjpk boolean_t first_prot; 1196*1676Sjpk char line[100], *ptr; 1197*1676Sjpk 1198*1676Sjpk prot_len = opt[1] - 3; 1199*1676Sjpk if (prot_len < 0) 1200*1676Sjpk return; 1201*1676Sjpk 1202*1676Sjpk show_header("RIPSO: ", "Revised IP Security Option", 0); 1203*1676Sjpk show_space(); 1204*1676Sjpk 1205*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1206*1676Sjpk "Type = Basic Security Option (%d), Length = %d", opt[0], opt[1]); 1207*1676Sjpk 1208*1676Sjpk /* 1209*1676Sjpk * Display Classification Level 1210*1676Sjpk */ 1211*1676Sjpk ripso_class = get_pair_byval(ripso_class_tbl, (int)opt[2]); 1212*1676Sjpk if (ripso_class != NULL) 1213*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1214*1676Sjpk "Classification = Unknown (0x%02x)", opt[2]); 1215*1676Sjpk else 1216*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1217*1676Sjpk "Classification = %s (0x%02x)", 1218*1676Sjpk ripso_class->name, ripso_class->val); 1219*1676Sjpk 1220*1676Sjpk /* 1221*1676Sjpk * Display Protection Authority Flags 1222*1676Sjpk */ 1223*1676Sjpk (void) snprintf(line, sizeof (line), "Protection Authority = "); 1224*1676Sjpk ptr = line; 1225*1676Sjpk first_prot = B_TRUE; 1226*1676Sjpk for (i = 0; i < prot_len; i++) { 1227*1676Sjpk index = 0; 1228*1676Sjpk while (ripso_prot_tbl[index].name != NULL) { 1229*1676Sjpk if (opt[3 + i] & ripso_prot_tbl[index].val) { 1230*1676Sjpk ptr = strchr(ptr, 0); 1231*1676Sjpk if (!first_prot) { 1232*1676Sjpk (void) strlcpy(ptr, ", ", 1233*1676Sjpk sizeof (line) - (ptr - line)); 1234*1676Sjpk ptr = strchr(ptr, 0); 1235*1676Sjpk } 1236*1676Sjpk (void) snprintf(ptr, 1237*1676Sjpk sizeof (line) - (ptr - line), 1238*1676Sjpk "%s (0x%02x)", 1239*1676Sjpk ripso_prot_tbl[index].name, 1240*1676Sjpk ripso_prot_tbl[index].val); 1241*1676Sjpk } 1242*1676Sjpk index++; 1243*1676Sjpk } 1244*1676Sjpk if ((opt[3 + i] & 1) == 0) 1245*1676Sjpk break; 1246*1676Sjpk } 1247*1676Sjpk if (!first_prot) 1248*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), "%s", line); 1249*1676Sjpk else 1250*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), "%sNone", 1251*1676Sjpk line); 1252*1676Sjpk } 1253*1676Sjpk 1254*1676Sjpk #define CIPSO_GENERIC_ARRAY_LEN 200 1255*1676Sjpk 1256*1676Sjpk /* 1257*1676Sjpk * Return 1 if CIPSO SL and Categories are all 1's; 0 otherwise. 1258*1676Sjpk * 1259*1676Sjpk * Note: opt starts with "Tag Type": 1260*1676Sjpk * 1261*1676Sjpk * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)| 1262*1676Sjpk * 1263*1676Sjpk */ 1264*1676Sjpk static boolean_t 1265*1676Sjpk cipso_high(const uchar_t *opt) 1266*1676Sjpk { 1267*1676Sjpk int i; 1268*1676Sjpk 1269*1676Sjpk if (((int)opt[1] + 6) < IP_MAX_OPT_LENGTH) 1270*1676Sjpk return (B_FALSE); 1271*1676Sjpk for (i = 0; i < ((int)opt[1] - 3); i++) 1272*1676Sjpk if (opt[3 + i] != 0xff) 1273*1676Sjpk return (B_FALSE); 1274*1676Sjpk return (B_TRUE); 1275*1676Sjpk } 1276*1676Sjpk 1277*1676Sjpk /* 1278*1676Sjpk * Converts CIPSO label to SL. 1279*1676Sjpk * 1280*1676Sjpk * Note: opt starts with "Tag Type": 1281*1676Sjpk * 1282*1676Sjpk * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)| 1283*1676Sjpk * 1284*1676Sjpk */ 1285*1676Sjpk static void 1286*1676Sjpk cipso2sl(const uchar_t *opt, bslabel_t *sl, int *high) 1287*1676Sjpk { 1288*1676Sjpk int i, taglen; 1289*1676Sjpk uchar_t *q = (uchar_t *)&((_bslabel_impl_t *)sl)->compartments; 1290*1676Sjpk 1291*1676Sjpk *high = 0; 1292*1676Sjpk taglen = opt[1]; 1293*1676Sjpk memset((caddr_t)sl, 0, sizeof (bslabel_t)); 1294*1676Sjpk 1295*1676Sjpk if (cipso_high(opt)) { 1296*1676Sjpk BSLHIGH(sl); 1297*1676Sjpk *high = 1; 1298*1676Sjpk } else { 1299*1676Sjpk LCLASS_SET((_bslabel_impl_t *)sl, opt[3]); 1300*1676Sjpk for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) 1301*1676Sjpk q[i] = opt[TSOL_TT1_MIN_LENGTH + i]; 1302*1676Sjpk } 1303*1676Sjpk SETBLTYPE(sl, SUN_SL_ID); 1304*1676Sjpk } 1305*1676Sjpk 1306*1676Sjpk static int 1307*1676Sjpk interpret_cipso_tagtype1(const uchar_t *opt) 1308*1676Sjpk { 1309*1676Sjpk int i, taglen, ishigh; 1310*1676Sjpk bslabel_t sl; 1311*1676Sjpk char line[CIPSO_GENERIC_ARRAY_LEN], *ptr; 1312*1676Sjpk 1313*1676Sjpk taglen = opt[1]; 1314*1676Sjpk if (taglen < TSOL_TT1_MIN_LENGTH || 1315*1676Sjpk taglen > TSOL_TT1_MAX_LENGTH) 1316*1676Sjpk return (taglen); 1317*1676Sjpk 1318*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1319*1676Sjpk "Tag Type = %d, Tag Length = %d", opt[0], opt[1]); 1320*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1321*1676Sjpk "Sensitivity Level = 0x%02x", opt[3]); 1322*1676Sjpk ptr = line; 1323*1676Sjpk for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) { 1324*1676Sjpk (void) snprintf(ptr, sizeof (line) - (ptr - line), "%02x", 1325*1676Sjpk opt[TSOL_TT1_MIN_LENGTH + i]); 1326*1676Sjpk ptr = strchr(ptr, 0); 1327*1676Sjpk } 1328*1676Sjpk if (i != 0) { 1329*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1330*1676Sjpk "Categories = "); 1331*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), "\t%s", 1332*1676Sjpk line); 1333*1676Sjpk } else { 1334*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1335*1676Sjpk "Categories = None"); 1336*1676Sjpk } 1337*1676Sjpk cipso2sl(opt, &sl, &ishigh); 1338*1676Sjpk if (is_system_labeled) { 1339*1676Sjpk if (bsltos(&sl, &plabel, ALABEL_MAXLEN, 1340*1676Sjpk LONG_CLASSIFICATION|LONG_WORDS|VIEW_INTERNAL) < 0) { 1341*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1342*1676Sjpk "The Sensitivity Level and Categories can't be " 1343*1676Sjpk "mapped to a valid SL"); 1344*1676Sjpk } else { 1345*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1346*1676Sjpk "The Sensitivity Level and Categories are mapped " 1347*1676Sjpk "to the SL:"); 1348*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1349*1676Sjpk "\t%s", ascii_label); 1350*1676Sjpk } 1351*1676Sjpk } 1352*1676Sjpk return (taglen); 1353*1676Sjpk } 1354*1676Sjpk 1355*1676Sjpk /* 1356*1676Sjpk * The following struct definition #define's are copied from TS1.x. They are 1357*1676Sjpk * not used here (except TTYPE_3_MAX_TOKENS), but included as a reference for 1358*1676Sjpk * the tag type 3 packet format. 1359*1676Sjpk */ 1360*1676Sjpk #define TTYPE_3_MAX_TOKENS 7 1361*1676Sjpk 1362*1676Sjpk /* 1363*1676Sjpk * Display CIPSO tag type 3 which is defined by MAXSIX. 1364*1676Sjpk */ 1365*1676Sjpk static int 1366*1676Sjpk interpret_cipso_tagtype3(const uchar_t *opt) 1367*1676Sjpk { 1368*1676Sjpk uchar_t tagtype; 1369*1676Sjpk int index, numtokens, taglen; 1370*1676Sjpk uint16_t mask; 1371*1676Sjpk uint32_t token; 1372*1676Sjpk static const char *name[] = { 1373*1676Sjpk "SL", 1374*1676Sjpk "NCAV", 1375*1676Sjpk "INTEG", 1376*1676Sjpk "SID", 1377*1676Sjpk "undefined", 1378*1676Sjpk "undefined", 1379*1676Sjpk "IL", 1380*1676Sjpk "PRIVS", 1381*1676Sjpk "LUID", 1382*1676Sjpk "PID", 1383*1676Sjpk "IDS", 1384*1676Sjpk "ACL" 1385*1676Sjpk }; 1386*1676Sjpk 1387*1676Sjpk tagtype = *opt++; 1388*1676Sjpk (void) memcpy(&mask, opt + 3, sizeof (mask)); 1389*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1390*1676Sjpk "Tag Type = %d (MAXSIX)", tagtype); 1391*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1392*1676Sjpk "Generation = 0x%02x%02x%02x, Mask = 0x%04x", opt[0], opt[1], 1393*1676Sjpk opt[2], mask); 1394*1676Sjpk opt += 3 + sizeof (mask); 1395*1676Sjpk 1396*1676Sjpk /* 1397*1676Sjpk * Display tokens 1398*1676Sjpk */ 1399*1676Sjpk numtokens = 0; 1400*1676Sjpk index = 0; 1401*1676Sjpk while (mask != 0 && numtokens < TTYPE_3_MAX_TOKENS) { 1402*1676Sjpk if (mask & 0x0001) { 1403*1676Sjpk (void) memcpy(&token, opt, sizeof (token)); 1404*1676Sjpk opt += sizeof (token); 1405*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1406*1676Sjpk "Attribute = %s, Token = 0x%08x", 1407*1676Sjpk index < sizeof (name) / sizeof (*name) ? 1408*1676Sjpk name[index] : "unknown", token); 1409*1676Sjpk numtokens++; 1410*1676Sjpk } 1411*1676Sjpk mask = mask >> 1; 1412*1676Sjpk index++; 1413*1676Sjpk } 1414*1676Sjpk 1415*1676Sjpk taglen = 6 + numtokens * 4; 1416*1676Sjpk return (taglen); 1417*1676Sjpk } 1418*1676Sjpk 1419*1676Sjpk static void 1420*1676Sjpk print_cipso(const uchar_t *opt) 1421*1676Sjpk { 1422*1676Sjpk int optlen, taglen, tagnum; 1423*1676Sjpk uint32_t doi; 1424*1676Sjpk char line[CIPSO_GENERIC_ARRAY_LEN]; 1425*1676Sjpk char *oldnest; 1426*1676Sjpk 1427*1676Sjpk optlen = opt[1]; 1428*1676Sjpk if (optlen < TSOL_CIPSO_MIN_LENGTH || optlen > TSOL_CIPSO_MAX_LENGTH) 1429*1676Sjpk return; 1430*1676Sjpk 1431*1676Sjpk oldnest = prot_nest_prefix; 1432*1676Sjpk prot_nest_prefix = prot_prefix; 1433*1676Sjpk show_header("CIPSO: ", "Common IP Security Option", 0); 1434*1676Sjpk show_space(); 1435*1676Sjpk 1436*1676Sjpk /* 1437*1676Sjpk * Display CIPSO Header 1438*1676Sjpk */ 1439*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1440*1676Sjpk "Type = CIPSO (%d), Length = %d", opt[0], opt[1]); 1441*1676Sjpk (void) memcpy(&doi, opt + 2, sizeof (doi)); 1442*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1443*1676Sjpk "Domain of Interpretation = %u", (unsigned)ntohl(doi)); 1444*1676Sjpk 1445*1676Sjpk if (opt[1] == TSOL_CIPSO_MIN_LENGTH) { /* no tags */ 1446*1676Sjpk show_space(); 1447*1676Sjpk prot_prefix = prot_nest_prefix; 1448*1676Sjpk prot_nest_prefix = oldnest; 1449*1676Sjpk return; 1450*1676Sjpk } 1451*1676Sjpk optlen -= TSOL_CIPSO_MIN_LENGTH; 1452*1676Sjpk opt += TSOL_CIPSO_MIN_LENGTH; 1453*1676Sjpk 1454*1676Sjpk /* 1455*1676Sjpk * Display Each Tag 1456*1676Sjpk */ 1457*1676Sjpk tagnum = 1; 1458*1676Sjpk while (optlen >= TSOL_TT1_MIN_LENGTH) { 1459*1676Sjpk (void) snprintf(line, sizeof (line), "Tag# %d", tagnum); 1460*1676Sjpk show_header("CIPSO: ", line, 0); 1461*1676Sjpk /* 1462*1676Sjpk * We handle tag type 1 and 3 only. Note, tag type 3 1463*1676Sjpk * is MAXSIX defined. 1464*1676Sjpk */ 1465*1676Sjpk switch (opt[0]) { 1466*1676Sjpk case 1: 1467*1676Sjpk taglen = interpret_cipso_tagtype1(opt); 1468*1676Sjpk break; 1469*1676Sjpk case 3: 1470*1676Sjpk taglen = interpret_cipso_tagtype3(opt); 1471*1676Sjpk break; 1472*1676Sjpk default: 1473*1676Sjpk (void) snprintf(get_line(0, 0), get_line_remain(), 1474*1676Sjpk "Unknown Tag Type %d", opt[0]); 1475*1676Sjpk show_space(); 1476*1676Sjpk prot_prefix = prot_nest_prefix; 1477*1676Sjpk prot_nest_prefix = oldnest; 1478*1676Sjpk return; 1479*1676Sjpk } 1480*1676Sjpk 1481*1676Sjpk /* 1482*1676Sjpk * Move to the next tag 1483*1676Sjpk */ 1484*1676Sjpk if (taglen <= 0) 1485*1676Sjpk break; 1486*1676Sjpk optlen -= taglen; 1487*1676Sjpk opt += taglen; 1488*1676Sjpk tagnum++; 1489*1676Sjpk } 1490*1676Sjpk show_space(); 1491*1676Sjpk prot_prefix = prot_nest_prefix; 1492*1676Sjpk prot_nest_prefix = oldnest; 1493*1676Sjpk } 1494