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 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  *
  26  * Copyright 2017 Jason King.
  27  * Copyright 2017 Joyent, Inc.
  28  */
  29 
  30 #include <sys/types.h>
  31 #include <sys/socket.h>
  32 #include <netinet/in.h>
  33 #include <netinet/udp.h>
  34 #include <arpa/inet.h>
  35 #include <inttypes.h>
  36 #include <stdio.h>
  37 #include <err.h>
  38 #include <errno.h>
  39 #include <pthread.h>
  40 #include <string.h>
  41 #include <port.h>
  42 #include <assert.h>
  43 #include <locale.h>
  44 #include <ipsec_util.h>
  45 #include <note.h>
  46 #include <err.h>
  47 #include <sys/debug.h>
  48 #include <bunyan.h>
  49 #include "inbound.h"
  50 #include "defs.h"
  51 #include "ikev2.h"
  52 #include "ikev2_pkt.h"
  53 #include "fromto.h"
  54 #include "ikev2_proto.h"
  55 
  56 static uchar_t *inbound_buf(void);
  57 static pthread_key_t inbound_key = PTHREAD_ONCE_KEY_NP;
  58 
  59 int ikesock4 = -1;
  60 int ikesock6 = -1;
  61 int nattsock = -1;
  62 
  63 static void
  64 inbound(int s, void *arg)
  65 {
  66         _NOTE(ARGUNUSED(arg))
  67 
  68         uchar_t *buf = NULL;
  69         pkt_t *pkt = NULL;
  70         struct sockaddr_storage to = { 0 };
  71         struct sockaddr_storage from = { 0 };
  72         socklen_t tolen = sizeof (to);
  73         socklen_t fromlen = sizeof (from);
  74         ssize_t pktlen;
  75 
  76         buf = inbound_buf();
  77         (void) memset(buf, 0, MAX_PACKET_SIZE);
  78 
  79         pktlen = recvfromto(s, buf, MAX_PACKET_SIZE, 0, &from, &fromlen, &to,
  80             &tolen);
  81         schedule_socket(s, inbound);
  82 
  83         if (pktlen == -1) {
  84                 /* recvfromto() should have dumped enough debug info */
  85                 return;
  86         }
  87 
  88         /*
  89          * recvfromto() guarantees we've received at least ike_header_t
  90          * bytes (or it returns -1)
  91          */
  92 
  93         /* sanity checks */
  94         ike_header_t *hdr = (ike_header_t *)buf;
  95         size_t hdrlen = ntohl(hdr->length);
  96 
  97         if (hdrlen != pktlen) {
  98                 NETLOG(info, log, "ISAKMP header length doesn't match "
  99                     "received length; discarding", &from, &to,
 100                     BUNYAN_T_UINT32, "hdrlen", (uint32_t)hdrlen,
 101                     BUNYAN_T_UINT32, "pktlen", (uint32_t)pktlen);
 102                 return;
 103         }
 104 
 105         pkt = ikev2_pkt_new_inbound(buf, pktlen);
 106         if (pkt == NULL)
 107                 return;
 108 
 109         ikev2_dispatch(pkt, &to, &from);
 110 }
 111 
 112 static int
 113 udp_listener_socket(sa_family_t af, uint16_t port)
 114 {
 115         struct sockaddr_storage storage = { 0 };
 116         sockaddr_u_t sau = { .sau_ss = &storage };
 117         size_t socksize = 0;
 118         const char *afstring = NULL;
 119         int sock = -1;
 120         int yes = 1;
 121         ipsec_req_t ipsr = { 0 };
 122 
 123         ipsr.ipsr_ah_req = ipsr.ipsr_esp_req = IPSEC_PREF_NEVER;
 124 
 125         switch (af) {
 126         case AF_INET:
 127                 afstring = "AF_INET";
 128                 socksize = sizeof (struct sockaddr_in);
 129                 break;
 130         case AF_INET6:
 131                 afstring = "AF_INET6";
 132                 socksize = sizeof (struct sockaddr_in6);
 133                 break;
 134         default:
 135                 INVALID("af");
 136         }
 137 
 138         if ((sock = socket(af, SOCK_DGRAM, 0)) == -1)
 139                 err(EXIT_FAILURE, "%s: socket(%s)", __func__, afstring);
 140 
 141         sau.sau_ss->ss_family = af;
 142         /* Exploit that sin_port and sin6_port live at the same offset. */
 143         sau.sau_sin->sin_port = htons(port);
 144         if (bind(sock, (const struct sockaddr *)sau.sau_ss, socksize) == -1)
 145                 err(EXIT_FAILURE, "%s: bind(%s, %d)", __func__, afstring, port);
 146 
 147         switch (af) {
 148         case AF_INET:
 149                 /* Make sure we can receive the destination address */
 150                 if (setsockopt(sock, IPPROTO_IP, IP_RECVDSTADDR,
 151                     (const void *)&yes, sizeof (yes)) == -1)
 152                         err(EXIT_FAILURE, "%s: setsockopt(IP_RECVDSTADDR)",
 153                             __func__);
 154 
 155                 if (setsockopt(sock, IPPROTO_IP, IP_SEC_OPT,
 156                     (const void *)&ipsr, sizeof (ipsr)) == -1)
 157                         err(EXIT_FAILURE, "%s: setsockopt(IP_SEC_OPT)",
 158                             __func__);
 159                 break;
 160         case AF_INET6:
 161                 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
 162                     (const void *)&yes, sizeof (yes)) == -1)
 163                         err(EXIT_FAILURE, "%s: setsockopt(IPV6_RECVPKTINFO)",
 164                             __func__);
 165 
 166                 if (setsockopt(sock, IPPROTO_IPV6, IPV6_SEC_OPT,
 167                     (const void *)&ipsr, sizeof (ipsr)) == -1)
 168                         err(EXIT_FAILURE, "%s: setsockopt(IPV6_SEC_OPT)",
 169                             __func__);
 170                 break;
 171         default:
 172                 INVALID(af);
 173         }
 174 
 175         /* Setup IPv4 NAT Traversal */
 176         if (af == AF_INET && port == IPPORT_IKE_NATT) {
 177                 int nat_t = 1;
 178 
 179                 if (setsockopt(sock, IPPROTO_UDP, UDP_NAT_T_ENDPOINT,
 180                     &nat_t, sizeof (nat_t)) == -1)
 181                         err(EXIT_FAILURE, "%s: setsockopt(IPPROTO_UDP, "
 182                             "UDP_NAT_T_ENDPOINT", __func__);
 183         }
 184 
 185         return (sock);
 186 }
 187 
 188 static uchar_t *
 189 inbound_buf(void)
 190 {
 191         uchar_t *ptr = pthread_getspecific(inbound_key);
 192 
 193         if (ptr != NULL)
 194                 return (ptr);
 195 
 196         if ((ptr = umem_alloc(MAX_PACKET_SIZE, UMEM_DEFAULT)) == NULL)
 197                 err(EXIT_FAILURE, "%s", __func__);
 198 
 199         PTH(pthread_setspecific(inbound_key, ptr));
 200         return (ptr);
 201 }
 202 
 203 static void
 204 inbound_free_buf(void *buf)
 205 {
 206         umem_free(buf, MAX_PACKET_SIZE);
 207 }
 208 
 209 void
 210 inbound_init(void)
 211 {
 212         PTH(pthread_key_create_once_np(&inbound_key, inbound_free_buf));
 213 
 214         ikesock4 = udp_listener_socket(AF_INET, IPPORT_IKE);
 215         nattsock = udp_listener_socket(AF_INET, IPPORT_IKE_NATT);
 216         ikesock6 = udp_listener_socket(AF_INET6, IPPORT_IKE);
 217 
 218         schedule_socket(ikesock4, inbound);
 219         schedule_socket(nattsock, inbound);
 220         schedule_socket(ikesock6, inbound);
 221 }