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 }