17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*cc1d2096SPaul Wernau * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <stdio.h> 277c478bd9Sstevel@tonic-gate #include <stdlib.h> 287c478bd9Sstevel@tonic-gate #include <ctype.h> 297c478bd9Sstevel@tonic-gate #include <string.h> 307c478bd9Sstevel@tonic-gate #include <fcntl.h> 317c478bd9Sstevel@tonic-gate #include <string.h> 3245916cd2Sjpk #include <strings.h> 337c478bd9Sstevel@tonic-gate #include <sys/types.h> 347c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 357c478bd9Sstevel@tonic-gate #include <sys/time.h> 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <sys/socket.h> 387c478bd9Sstevel@tonic-gate #include <sys/sockio.h> 397c478bd9Sstevel@tonic-gate #include <net/if.h> 407c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 417c478bd9Sstevel@tonic-gate #include <netinet/in.h> 427c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 437c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h> 447c478bd9Sstevel@tonic-gate #include <netinet/icmp6.h> 457c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h> 467c478bd9Sstevel@tonic-gate #include <inet/ipsecesp.h> 477c478bd9Sstevel@tonic-gate #include <inet/ipsecah.h> 487c478bd9Sstevel@tonic-gate #include "snoop.h" 497c478bd9Sstevel@tonic-gate 5045916cd2Sjpk /* ARGSUSED */ 517c478bd9Sstevel@tonic-gate int 527c478bd9Sstevel@tonic-gate interpret_esp(int flags, uint8_t *hdr, int iplen, int fraglen) 537c478bd9Sstevel@tonic-gate { 5445916cd2Sjpk /* LINTED: alignment */ 557c478bd9Sstevel@tonic-gate esph_t *esph = (esph_t *)hdr; 567c478bd9Sstevel@tonic-gate esph_t *aligned_esph; 577c478bd9Sstevel@tonic-gate esph_t storage; /* In case hdr isn't aligned. */ 587c478bd9Sstevel@tonic-gate char *line; 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate if (fraglen < sizeof (esph_t)) 612e3b6467Skcpoon return (fraglen); /* incomplete header */ 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate if (!IS_P2ALIGNED(hdr, 4)) { 647c478bd9Sstevel@tonic-gate aligned_esph = &storage; 657c478bd9Sstevel@tonic-gate bcopy(hdr, aligned_esph, sizeof (esph_t)); 667c478bd9Sstevel@tonic-gate } else { 677c478bd9Sstevel@tonic-gate aligned_esph = esph; 687c478bd9Sstevel@tonic-gate } 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate if (flags & F_SUM) { 717c478bd9Sstevel@tonic-gate line = (char *)get_sum_line(); 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * sprintf() is safe because line guarantees us 80 columns, 747c478bd9Sstevel@tonic-gate * and SPI and replay certainly won't exceed that. 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate (void) sprintf(line, "ESP SPI=0x%x Replay=%u", 777c478bd9Sstevel@tonic-gate ntohl(aligned_esph->esph_spi), 787c478bd9Sstevel@tonic-gate ntohl(aligned_esph->esph_replay)); 797c478bd9Sstevel@tonic-gate line += strlen(line); 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate if (flags & F_DTAIL) { 837c478bd9Sstevel@tonic-gate show_header("ESP: ", "Encapsulating Security Payload", 847c478bd9Sstevel@tonic-gate sizeof (esph_t)); 857c478bd9Sstevel@tonic-gate show_space(); 867c478bd9Sstevel@tonic-gate /* 877c478bd9Sstevel@tonic-gate * sprintf() is safe because get_line guarantees us 80 columns, 887c478bd9Sstevel@tonic-gate * and SPI and replay certainly won't exceed that. 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)&esph->esph_spi - dlc_header, 917c478bd9Sstevel@tonic-gate 4), "SPI = 0x%x", ntohl(aligned_esph->esph_spi)); 927c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)&esph->esph_replay - 937c478bd9Sstevel@tonic-gate dlc_header, 4), "Replay = %u", 947c478bd9Sstevel@tonic-gate ntohl(aligned_esph->esph_replay)); 957c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)(esph + 1) - dlc_header, 967c478bd9Sstevel@tonic-gate 4), " ....ENCRYPTED DATA...."); 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate return (sizeof (esph_t)); 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate int 1037c478bd9Sstevel@tonic-gate interpret_ah(int flags, uint8_t *hdr, int iplen, int fraglen) 1047c478bd9Sstevel@tonic-gate { 10545916cd2Sjpk /* LINTED: alignment */ 1067c478bd9Sstevel@tonic-gate ah_t *ah = (ah_t *)hdr; 1077c478bd9Sstevel@tonic-gate ah_t *aligned_ah; 1087c478bd9Sstevel@tonic-gate ah_t storage; /* In case hdr isn't aligned. */ 1097c478bd9Sstevel@tonic-gate char *line, *buff; 1107c478bd9Sstevel@tonic-gate uint_t ahlen, auth_data_len; 1117c478bd9Sstevel@tonic-gate uint8_t *auth_data, *data; 1127c478bd9Sstevel@tonic-gate int new_iplen; 1137c478bd9Sstevel@tonic-gate uint8_t proto; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate if (fraglen < sizeof (ah_t)) 1162e3b6467Skcpoon return (fraglen); /* incomplete header */ 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate if (!IS_P2ALIGNED(hdr, 4)) { 1197c478bd9Sstevel@tonic-gate aligned_ah = (ah_t *)&storage; 12045916cd2Sjpk bcopy(hdr, &storage, sizeof (ah_t)); 1217c478bd9Sstevel@tonic-gate } else { 1227c478bd9Sstevel@tonic-gate aligned_ah = ah; 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /* 1267c478bd9Sstevel@tonic-gate * "+ 8" is for the "constant" part that's not included in the AH 1277c478bd9Sstevel@tonic-gate * length. 1287c478bd9Sstevel@tonic-gate * 1297c478bd9Sstevel@tonic-gate * The AH RFC specifies the length field in "length in 4-byte units, 1307c478bd9Sstevel@tonic-gate * not counting the first 8 bytes". So if an AH is 24 bytes long, 1317c478bd9Sstevel@tonic-gate * the length field will contain "4". (4 * 4 + 8 == 24). 1327c478bd9Sstevel@tonic-gate */ 1337c478bd9Sstevel@tonic-gate ahlen = (aligned_ah->ah_length << 2) + 8; 1347c478bd9Sstevel@tonic-gate fraglen -= ahlen; 1357c478bd9Sstevel@tonic-gate if (fraglen < 0) 1362e3b6467Skcpoon return (fraglen + ahlen); /* incomplete header */ 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate auth_data_len = ahlen - sizeof (ah_t); 1397c478bd9Sstevel@tonic-gate auth_data = (uint8_t *)(ah + 1); 1407c478bd9Sstevel@tonic-gate data = auth_data + auth_data_len; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate if (flags & F_SUM) { 1437c478bd9Sstevel@tonic-gate line = (char *)get_sum_line(); 1447c478bd9Sstevel@tonic-gate (void) sprintf(line, "AH SPI=0x%x Replay=%u", 1457c478bd9Sstevel@tonic-gate ntohl(aligned_ah->ah_spi), ntohl(aligned_ah->ah_replay)); 1467c478bd9Sstevel@tonic-gate line += strlen(line); 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate if (flags & F_DTAIL) { 1507c478bd9Sstevel@tonic-gate show_header("AH: ", "Authentication Header", ahlen); 1517c478bd9Sstevel@tonic-gate show_space(); 1527c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)&ah->ah_nexthdr - dlc_header, 1537c478bd9Sstevel@tonic-gate 1), "Next header = %d (%s)", aligned_ah->ah_nexthdr, 1547c478bd9Sstevel@tonic-gate getproto(aligned_ah->ah_nexthdr)); 1557c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)&ah->ah_length - dlc_header, 1), 1567c478bd9Sstevel@tonic-gate "AH length = %d (%d bytes)", aligned_ah->ah_length, ahlen); 1577c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)&ah->ah_reserved - dlc_header, 1587c478bd9Sstevel@tonic-gate 2), "<Reserved field = 0x%x>", 1597c478bd9Sstevel@tonic-gate ntohs(aligned_ah->ah_reserved)); 1607c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)&ah->ah_spi - dlc_header, 4), 1617c478bd9Sstevel@tonic-gate "SPI = 0x%x", ntohl(aligned_ah->ah_spi)); 1627c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)&ah->ah_replay - dlc_header, 4), 1637c478bd9Sstevel@tonic-gate "Replay = %u", ntohl(aligned_ah->ah_replay)); 1647c478bd9Sstevel@tonic-gate 165*cc1d2096SPaul Wernau /* 166*cc1d2096SPaul Wernau * 2 for two hex digits per auth_data byte 167*cc1d2096SPaul Wernau * plus one byte for trailing null byte. 168*cc1d2096SPaul Wernau */ 169*cc1d2096SPaul Wernau buff = malloc(auth_data_len * 2 + 1); 1707c478bd9Sstevel@tonic-gate if (buff != NULL) { 1717c478bd9Sstevel@tonic-gate int i; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate for (i = 0; i < auth_data_len; i++) 1747c478bd9Sstevel@tonic-gate sprintf(buff + i * 2, "%02x", auth_data[i]); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)auth_data - dlc_header, 1787c478bd9Sstevel@tonic-gate auth_data_len), "ICV = %s", 1797c478bd9Sstevel@tonic-gate (buff == NULL) ? "<out of memory>" : buff); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* malloc(3c) says I can call free even if buff == NULL */ 1827c478bd9Sstevel@tonic-gate free(buff); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate show_space(); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate new_iplen = iplen - ahlen; 1887c478bd9Sstevel@tonic-gate proto = aligned_ah->ah_nexthdr; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate /* 1917c478bd9Sstevel@tonic-gate * Print IPv6 Extension Headers, or skip them in the summary case. 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS || 1947c478bd9Sstevel@tonic-gate proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) { 1957c478bd9Sstevel@tonic-gate (void) print_ipv6_extensions(flags, &data, &proto, &iplen, 1967c478bd9Sstevel@tonic-gate &fraglen); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate if (fraglen > 0) 2007c478bd9Sstevel@tonic-gate switch (proto) { 2017c478bd9Sstevel@tonic-gate case IPPROTO_ENCAP: 20245916cd2Sjpk /* LINTED: alignment */ 2037c478bd9Sstevel@tonic-gate (void) interpret_ip(flags, (struct ip *)data, 2047c478bd9Sstevel@tonic-gate new_iplen); 2057c478bd9Sstevel@tonic-gate break; 2067c478bd9Sstevel@tonic-gate case IPPROTO_IPV6: 2077c478bd9Sstevel@tonic-gate (void) interpret_ipv6(flags, (ip6_t *)data, 2087c478bd9Sstevel@tonic-gate new_iplen); 2097c478bd9Sstevel@tonic-gate break; 2107c478bd9Sstevel@tonic-gate case IPPROTO_ICMP: 21145916cd2Sjpk (void) interpret_icmp(flags, 21245916cd2Sjpk /* LINTED: alignment */ 21345916cd2Sjpk (struct icmp *)data, new_iplen, fraglen); 2147c478bd9Sstevel@tonic-gate break; 2157c478bd9Sstevel@tonic-gate case IPPROTO_ICMPV6: 21645916cd2Sjpk /* LINTED: alignment */ 21745916cd2Sjpk (void) interpret_icmpv6(flags, (icmp6_t *)data, 2187c478bd9Sstevel@tonic-gate new_iplen, fraglen); 2197c478bd9Sstevel@tonic-gate break; 2207c478bd9Sstevel@tonic-gate case IPPROTO_TCP: 22145916cd2Sjpk (void) interpret_tcp(flags, 22245916cd2Sjpk (struct tcphdr *)data, new_iplen, fraglen); 2237c478bd9Sstevel@tonic-gate break; 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate case IPPROTO_ESP: 22645916cd2Sjpk (void) interpret_esp(flags, data, new_iplen, 22745916cd2Sjpk fraglen); 2287c478bd9Sstevel@tonic-gate break; 2297c478bd9Sstevel@tonic-gate 23045916cd2Sjpk case IPPROTO_AH: 23145916cd2Sjpk (void) interpret_ah(flags, data, new_iplen, 23245916cd2Sjpk fraglen); 23345916cd2Sjpk break; 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate case IPPROTO_UDP: 23645916cd2Sjpk (void) interpret_udp(flags, 23745916cd2Sjpk (struct udphdr *)data, new_iplen, fraglen); 2387c478bd9Sstevel@tonic-gate break; 2397c478bd9Sstevel@tonic-gate /* default case is to not print anything else */ 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate return (ahlen); 2437c478bd9Sstevel@tonic-gate } 244