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 #include <stdio.h> 290Sstevel@tonic-gate #include <stdlib.h> 300Sstevel@tonic-gate #include <ctype.h> 310Sstevel@tonic-gate #include <string.h> 320Sstevel@tonic-gate #include <fcntl.h> 330Sstevel@tonic-gate #include <string.h> 34*1676Sjpk #include <strings.h> 350Sstevel@tonic-gate #include <sys/types.h> 360Sstevel@tonic-gate #include <sys/sysmacros.h> 370Sstevel@tonic-gate #include <sys/time.h> 380Sstevel@tonic-gate 390Sstevel@tonic-gate #include <sys/socket.h> 400Sstevel@tonic-gate #include <sys/sockio.h> 410Sstevel@tonic-gate #include <net/if.h> 420Sstevel@tonic-gate #include <netinet/in_systm.h> 430Sstevel@tonic-gate #include <netinet/in.h> 440Sstevel@tonic-gate #include <netinet/ip.h> 450Sstevel@tonic-gate #include <netinet/ip_icmp.h> 460Sstevel@tonic-gate #include <netinet/icmp6.h> 470Sstevel@tonic-gate #include <netinet/if_ether.h> 480Sstevel@tonic-gate #include <inet/ipsecesp.h> 490Sstevel@tonic-gate #include <inet/ipsecah.h> 500Sstevel@tonic-gate #include "snoop.h" 510Sstevel@tonic-gate 52*1676Sjpk /* ARGSUSED */ 530Sstevel@tonic-gate int 540Sstevel@tonic-gate interpret_esp(int flags, uint8_t *hdr, int iplen, int fraglen) 550Sstevel@tonic-gate { 56*1676Sjpk /* LINTED: alignment */ 570Sstevel@tonic-gate esph_t *esph = (esph_t *)hdr; 580Sstevel@tonic-gate esph_t *aligned_esph; 590Sstevel@tonic-gate esph_t storage; /* In case hdr isn't aligned. */ 600Sstevel@tonic-gate char *line; 610Sstevel@tonic-gate 620Sstevel@tonic-gate if (fraglen < sizeof (esph_t)) 63410Skcpoon return (fraglen); /* incomplete header */ 640Sstevel@tonic-gate 650Sstevel@tonic-gate if (!IS_P2ALIGNED(hdr, 4)) { 660Sstevel@tonic-gate aligned_esph = &storage; 670Sstevel@tonic-gate bcopy(hdr, aligned_esph, sizeof (esph_t)); 680Sstevel@tonic-gate } else { 690Sstevel@tonic-gate aligned_esph = esph; 700Sstevel@tonic-gate } 710Sstevel@tonic-gate 720Sstevel@tonic-gate if (flags & F_SUM) { 730Sstevel@tonic-gate line = (char *)get_sum_line(); 740Sstevel@tonic-gate /* 750Sstevel@tonic-gate * sprintf() is safe because line guarantees us 80 columns, 760Sstevel@tonic-gate * and SPI and replay certainly won't exceed that. 770Sstevel@tonic-gate */ 780Sstevel@tonic-gate (void) sprintf(line, "ESP SPI=0x%x Replay=%u", 790Sstevel@tonic-gate ntohl(aligned_esph->esph_spi), 800Sstevel@tonic-gate ntohl(aligned_esph->esph_replay)); 810Sstevel@tonic-gate line += strlen(line); 820Sstevel@tonic-gate } 830Sstevel@tonic-gate 840Sstevel@tonic-gate if (flags & F_DTAIL) { 850Sstevel@tonic-gate show_header("ESP: ", "Encapsulating Security Payload", 860Sstevel@tonic-gate sizeof (esph_t)); 870Sstevel@tonic-gate show_space(); 880Sstevel@tonic-gate /* 890Sstevel@tonic-gate * sprintf() is safe because get_line guarantees us 80 columns, 900Sstevel@tonic-gate * and SPI and replay certainly won't exceed that. 910Sstevel@tonic-gate */ 920Sstevel@tonic-gate (void) sprintf(get_line((char *)&esph->esph_spi - dlc_header, 930Sstevel@tonic-gate 4), "SPI = 0x%x", ntohl(aligned_esph->esph_spi)); 940Sstevel@tonic-gate (void) sprintf(get_line((char *)&esph->esph_replay - 950Sstevel@tonic-gate dlc_header, 4), "Replay = %u", 960Sstevel@tonic-gate ntohl(aligned_esph->esph_replay)); 970Sstevel@tonic-gate (void) sprintf(get_line((char *)(esph + 1) - dlc_header, 980Sstevel@tonic-gate 4), " ....ENCRYPTED DATA...."); 990Sstevel@tonic-gate } 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate return (sizeof (esph_t)); 1020Sstevel@tonic-gate } 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate int 1050Sstevel@tonic-gate interpret_ah(int flags, uint8_t *hdr, int iplen, int fraglen) 1060Sstevel@tonic-gate { 107*1676Sjpk /* LINTED: alignment */ 1080Sstevel@tonic-gate ah_t *ah = (ah_t *)hdr; 1090Sstevel@tonic-gate ah_t *aligned_ah; 1100Sstevel@tonic-gate ah_t storage; /* In case hdr isn't aligned. */ 1110Sstevel@tonic-gate char *line, *buff; 1120Sstevel@tonic-gate uint_t ahlen, auth_data_len; 1130Sstevel@tonic-gate uint8_t *auth_data, *data; 1140Sstevel@tonic-gate int new_iplen; 1150Sstevel@tonic-gate uint8_t proto; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate if (fraglen < sizeof (ah_t)) 118410Skcpoon return (fraglen); /* incomplete header */ 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate if (!IS_P2ALIGNED(hdr, 4)) { 1210Sstevel@tonic-gate aligned_ah = (ah_t *)&storage; 122*1676Sjpk bcopy(hdr, &storage, sizeof (ah_t)); 1230Sstevel@tonic-gate } else { 1240Sstevel@tonic-gate aligned_ah = ah; 1250Sstevel@tonic-gate } 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate /* 1280Sstevel@tonic-gate * "+ 8" is for the "constant" part that's not included in the AH 1290Sstevel@tonic-gate * length. 1300Sstevel@tonic-gate * 1310Sstevel@tonic-gate * The AH RFC specifies the length field in "length in 4-byte units, 1320Sstevel@tonic-gate * not counting the first 8 bytes". So if an AH is 24 bytes long, 1330Sstevel@tonic-gate * the length field will contain "4". (4 * 4 + 8 == 24). 1340Sstevel@tonic-gate */ 1350Sstevel@tonic-gate ahlen = (aligned_ah->ah_length << 2) + 8; 1360Sstevel@tonic-gate fraglen -= ahlen; 1370Sstevel@tonic-gate if (fraglen < 0) 138410Skcpoon return (fraglen + ahlen); /* incomplete header */ 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate auth_data_len = ahlen - sizeof (ah_t); 1410Sstevel@tonic-gate auth_data = (uint8_t *)(ah + 1); 1420Sstevel@tonic-gate data = auth_data + auth_data_len; 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate if (flags & F_SUM) { 1450Sstevel@tonic-gate line = (char *)get_sum_line(); 1460Sstevel@tonic-gate (void) sprintf(line, "AH SPI=0x%x Replay=%u", 1470Sstevel@tonic-gate ntohl(aligned_ah->ah_spi), ntohl(aligned_ah->ah_replay)); 1480Sstevel@tonic-gate line += strlen(line); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate if (flags & F_DTAIL) { 1520Sstevel@tonic-gate show_header("AH: ", "Authentication Header", ahlen); 1530Sstevel@tonic-gate show_space(); 1540Sstevel@tonic-gate (void) sprintf(get_line((char *)&ah->ah_nexthdr - dlc_header, 1550Sstevel@tonic-gate 1), "Next header = %d (%s)", aligned_ah->ah_nexthdr, 1560Sstevel@tonic-gate getproto(aligned_ah->ah_nexthdr)); 1570Sstevel@tonic-gate (void) sprintf(get_line((char *)&ah->ah_length - dlc_header, 1), 1580Sstevel@tonic-gate "AH length = %d (%d bytes)", aligned_ah->ah_length, ahlen); 1590Sstevel@tonic-gate (void) sprintf(get_line((char *)&ah->ah_reserved - dlc_header, 1600Sstevel@tonic-gate 2), "<Reserved field = 0x%x>", 1610Sstevel@tonic-gate ntohs(aligned_ah->ah_reserved)); 1620Sstevel@tonic-gate (void) sprintf(get_line((char *)&ah->ah_spi - dlc_header, 4), 1630Sstevel@tonic-gate "SPI = 0x%x", ntohl(aligned_ah->ah_spi)); 1640Sstevel@tonic-gate (void) sprintf(get_line((char *)&ah->ah_replay - dlc_header, 4), 1650Sstevel@tonic-gate "Replay = %u", ntohl(aligned_ah->ah_replay)); 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate /* * 2 for two hex digits per auth_data byte. */ 1680Sstevel@tonic-gate buff = malloc(auth_data_len * 2); 1690Sstevel@tonic-gate if (buff != NULL) { 1700Sstevel@tonic-gate int i; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate for (i = 0; i < auth_data_len; i++) 1730Sstevel@tonic-gate sprintf(buff + i * 2, "%02x", auth_data[i]); 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate (void) sprintf(get_line((char *)auth_data - dlc_header, 1770Sstevel@tonic-gate auth_data_len), "ICV = %s", 1780Sstevel@tonic-gate (buff == NULL) ? "<out of memory>" : buff); 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate /* malloc(3c) says I can call free even if buff == NULL */ 1810Sstevel@tonic-gate free(buff); 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate show_space(); 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate new_iplen = iplen - ahlen; 1870Sstevel@tonic-gate proto = aligned_ah->ah_nexthdr; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate /* 1900Sstevel@tonic-gate * Print IPv6 Extension Headers, or skip them in the summary case. 1910Sstevel@tonic-gate */ 1920Sstevel@tonic-gate if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS || 1930Sstevel@tonic-gate proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) { 1940Sstevel@tonic-gate (void) print_ipv6_extensions(flags, &data, &proto, &iplen, 1950Sstevel@tonic-gate &fraglen); 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate if (fraglen > 0) 1990Sstevel@tonic-gate switch (proto) { 2000Sstevel@tonic-gate case IPPROTO_ENCAP: 201*1676Sjpk /* LINTED: alignment */ 2020Sstevel@tonic-gate (void) interpret_ip(flags, (struct ip *)data, 2030Sstevel@tonic-gate new_iplen); 2040Sstevel@tonic-gate break; 2050Sstevel@tonic-gate case IPPROTO_IPV6: 2060Sstevel@tonic-gate (void) interpret_ipv6(flags, (ip6_t *)data, 2070Sstevel@tonic-gate new_iplen); 2080Sstevel@tonic-gate break; 2090Sstevel@tonic-gate case IPPROTO_ICMP: 210*1676Sjpk (void) interpret_icmp(flags, 211*1676Sjpk /* LINTED: alignment */ 212*1676Sjpk (struct icmp *)data, new_iplen, fraglen); 2130Sstevel@tonic-gate break; 2140Sstevel@tonic-gate case IPPROTO_ICMPV6: 215*1676Sjpk /* LINTED: alignment */ 216*1676Sjpk (void) interpret_icmpv6(flags, (icmp6_t *)data, 2170Sstevel@tonic-gate new_iplen, fraglen); 2180Sstevel@tonic-gate break; 2190Sstevel@tonic-gate case IPPROTO_TCP: 220*1676Sjpk (void) interpret_tcp(flags, 221*1676Sjpk (struct tcphdr *)data, new_iplen, fraglen); 2220Sstevel@tonic-gate break; 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate case IPPROTO_ESP: 225*1676Sjpk (void) interpret_esp(flags, data, new_iplen, 226*1676Sjpk fraglen); 2270Sstevel@tonic-gate break; 2280Sstevel@tonic-gate 229*1676Sjpk case IPPROTO_AH: 230*1676Sjpk (void) interpret_ah(flags, data, new_iplen, 231*1676Sjpk fraglen); 232*1676Sjpk break; 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate case IPPROTO_UDP: 235*1676Sjpk (void) interpret_udp(flags, 236*1676Sjpk (struct udphdr *)data, new_iplen, fraglen); 2370Sstevel@tonic-gate break; 2380Sstevel@tonic-gate /* default case is to not print anything else */ 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate return (ahlen); 2420Sstevel@tonic-gate } 243