1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <ctype.h>
  29 #include <string.h>
  30 #include <fcntl.h>
  31 #include <string.h>
  32 #include <strings.h>
  33 #include <sys/types.h>
  34 #include <sys/sysmacros.h>
  35 #include <sys/time.h>
  36 
  37 #include <sys/socket.h>
  38 #include <sys/sockio.h>
  39 #include <net/if.h>
  40 #include <netinet/in_systm.h>
  41 #include <netinet/in.h>
  42 #include <netinet/ip.h>
  43 #include <netinet/ip_icmp.h>
  44 #include <netinet/icmp6.h>
  45 #include <netinet/if_ether.h>
  46 #include <inet/ipsecesp.h>
  47 #include <inet/ipsecah.h>
  48 #include "snoop.h"
  49 
  50 /* ARGSUSED */
  51 int
  52 interpret_esp(int flags, uint8_t *hdr, int iplen, int fraglen)
  53 {
  54         /* LINTED: alignment */
  55         esph_t *esph = (esph_t *)hdr;
  56         esph_t *aligned_esph;
  57         esph_t storage; /* In case hdr isn't aligned. */
  58         char *line;
  59 
  60         if (fraglen < sizeof (esph_t))
  61                 return (fraglen);       /* incomplete header */
  62 
  63         if (!IS_P2ALIGNED(hdr, 4)) {
  64                 aligned_esph = &storage;
  65                 bcopy(hdr, aligned_esph, sizeof (esph_t));
  66         } else {
  67                 aligned_esph = esph;
  68         }
  69 
  70         if (flags & F_SUM) {
  71                 line = (char *)get_sum_line();
  72                 /*
  73                  * sprintf() is safe because line guarantees us 80 columns,
  74                  * and SPI and replay certainly won't exceed that.
  75                  */
  76                 (void) sprintf(line, "ESP SPI=0x%x Replay=%u",
  77                     ntohl(aligned_esph->esph_spi),
  78                     ntohl(aligned_esph->esph_replay));
  79                 line += strlen(line);
  80         }
  81 
  82         if (flags & F_DTAIL) {
  83                 show_header("ESP:  ", "Encapsulating Security Payload",
  84                     sizeof (esph_t));
  85                 show_space();
  86                 /*
  87                  * sprintf() is safe because get_line guarantees us 80 columns,
  88                  * and SPI and replay certainly won't exceed that.
  89                  */
  90                 (void) sprintf(get_line((char *)&esph->esph_spi - dlc_header,
  91                     4), "SPI = 0x%x", ntohl(aligned_esph->esph_spi));
  92                 (void) sprintf(get_line((char *)&esph->esph_replay -
  93                     dlc_header, 4), "Replay = %u",
  94                     ntohl(aligned_esph->esph_replay));
  95                 (void) sprintf(get_line((char *)(esph + 1) - dlc_header,
  96                     4), "   ....ENCRYPTED DATA....");
  97         }
  98 
  99         return (sizeof (esph_t));
 100 }
 101 
 102 int
 103 interpret_ah(int flags, uint8_t *hdr, int iplen, int fraglen)
 104 {
 105         /* LINTED: alignment */
 106         ah_t *ah = (ah_t *)hdr;
 107         ah_t *aligned_ah;
 108         ah_t storage;   /* In case hdr isn't aligned. */
 109         char *line, *buff;
 110         uint_t ahlen, auth_data_len;
 111         uint8_t *auth_data, *data;
 112         int new_iplen;
 113         uint8_t proto;
 114 
 115         if (fraglen < sizeof (ah_t))
 116                 return (fraglen);               /* incomplete header */
 117 
 118         if (!IS_P2ALIGNED(hdr, 4)) {
 119                 aligned_ah = (ah_t *)&storage;
 120                 bcopy(hdr, &storage, sizeof (ah_t));
 121         } else {
 122                 aligned_ah = ah;
 123         }
 124 
 125         /*
 126          * "+ 8" is for the "constant" part that's not included in the AH
 127          * length.
 128          *
 129          * The AH RFC specifies the length field in "length in 4-byte units,
 130          * not counting the first 8 bytes".  So if an AH is 24 bytes long,
 131          * the length field will contain "4".  (4 * 4 + 8 == 24).
 132          */
 133         ahlen = (aligned_ah->ah_length << 2) + 8;
 134         fraglen -= ahlen;
 135         if (fraglen < 0)
 136                 return (fraglen + ahlen);       /* incomplete header */
 137 
 138         auth_data_len = ahlen - sizeof (ah_t);
 139         auth_data = (uint8_t *)(ah + 1);
 140         data = auth_data + auth_data_len;
 141 
 142         if (flags & F_SUM) {
 143                 line = (char *)get_sum_line();
 144                 (void) sprintf(line, "AH SPI=0x%x Replay=%u",
 145                     ntohl(aligned_ah->ah_spi), ntohl(aligned_ah->ah_replay));
 146                 line += strlen(line);
 147         }
 148 
 149         if (flags & F_DTAIL) {
 150                 show_header("AH:  ", "Authentication Header", ahlen);
 151                 show_space();
 152                 (void) sprintf(get_line((char *)&ah->ah_nexthdr - dlc_header,
 153                     1), "Next header = %d (%s)", aligned_ah->ah_nexthdr,
 154                     getproto(aligned_ah->ah_nexthdr));
 155                 (void) sprintf(get_line((char *)&ah->ah_length - dlc_header, 1),
 156                     "AH length = %d (%d bytes)", aligned_ah->ah_length, ahlen);
 157                 (void) sprintf(get_line((char *)&ah->ah_reserved - dlc_header,
 158                     2), "<Reserved field = 0x%x>",
 159                     ntohs(aligned_ah->ah_reserved));
 160                 (void) sprintf(get_line((char *)&ah->ah_spi - dlc_header, 4),
 161                     "SPI = 0x%x", ntohl(aligned_ah->ah_spi));
 162                 (void) sprintf(get_line((char *)&ah->ah_replay - dlc_header, 4),
 163                     "Replay = %u", ntohl(aligned_ah->ah_replay));
 164 
 165                 /*
 166                  * 2 for two hex digits per auth_data byte
 167                  * plus one byte for trailing null byte.
 168                  */
 169                 buff = malloc(auth_data_len * 2 + 1);
 170                 if (buff != NULL) {
 171                         int i;
 172 
 173                         for (i = 0; i < auth_data_len; i++)
 174                                 sprintf(buff + i * 2, "%02x", auth_data[i]);
 175                 }
 176 
 177                 (void) sprintf(get_line((char *)auth_data - dlc_header,
 178                     auth_data_len), "ICV = %s",
 179                     (buff == NULL) ? "<out of memory>" : buff);
 180 
 181                 /* malloc(3c) says I can call free even if buff == NULL */
 182                 free(buff);
 183 
 184                 show_space();
 185         }
 186 
 187         new_iplen = iplen - ahlen;
 188         proto = aligned_ah->ah_nexthdr;
 189 
 190         /*
 191          * Print IPv6 Extension Headers, or skip them in the summary case.
 192          */
 193         if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS ||
 194             proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) {
 195                 (void) print_ipv6_extensions(flags, &data, &proto, &iplen,
 196                     &fraglen);
 197         }
 198 
 199         if (fraglen > 0)
 200                 switch (proto) {
 201                         case IPPROTO_ENCAP:
 202                                 /* LINTED: alignment */
 203                                 (void) interpret_ip(flags, (struct ip *)data,
 204                                     new_iplen);
 205                                 break;
 206                         case IPPROTO_IPV6:
 207                                 (void) interpret_ipv6(flags, (ip6_t *)data,
 208                                     new_iplen);
 209                                 break;
 210                         case IPPROTO_ICMP:
 211                                 (void) interpret_icmp(flags,
 212                                     /* LINTED: alignment */
 213                                     (struct icmp *)data, new_iplen, fraglen);
 214                                 break;
 215                         case IPPROTO_ICMPV6:
 216                                 /* LINTED: alignment */
 217                                 (void) interpret_icmpv6(flags, (icmp6_t *)data,
 218                                     new_iplen, fraglen);
 219                                 break;
 220                         case IPPROTO_TCP:
 221                                 (void) interpret_tcp(flags,
 222                                     (struct tcphdr *)data, new_iplen, fraglen);
 223                                 break;
 224 
 225                         case IPPROTO_ESP:
 226                                 (void) interpret_esp(flags, data, new_iplen,
 227                                     fraglen);
 228                                 break;
 229 
 230                         case IPPROTO_AH:
 231                                 (void) interpret_ah(flags, data, new_iplen,
 232                                     fraglen);
 233                                 break;
 234 
 235                         case IPPROTO_UDP:
 236                                 (void) interpret_udp(flags,
 237                                     (struct udphdr *)data, new_iplen, fraglen);
 238                                 break;
 239                         /* default case is to not print anything else */
 240                 }
 241 
 242         return (ahlen);
 243 }