xref: /openbsd/sbin/isakmpd/udp_encap.c (revision 0ebca8ea)
1 /*	$OpenBSD: udp_encap.c,v 1.24 2022/01/16 14:30:11 naddy Exp $	*/
2 
3 /*
4  * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist.  All rights reserved.
5  * Copyright (c) 2000 Angelos D. Keromytis.  All rights reserved.
6  * Copyright (c) 2004 H�kan Olsson.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/types.h>
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
32 #include <sys/sockio.h>
33 #include <net/if.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <ctype.h>
37 #include <limits.h>
38 #include <netdb.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 #include "conf.h"
44 #include "if.h"
45 #include "ipsec_doi.h"
46 #include "isakmp.h"
47 #include "log.h"
48 #include "message.h"
49 #include "monitor.h"
50 #include "transport.h"
51 #include "udp.h"
52 #include "udp_encap.h"
53 #include "util.h"
54 #include "virtual.h"
55 
56 #define UDP_SIZE 65536
57 
58 /* If a system doesn't have SO_REUSEPORT, SO_REUSEADDR will have to do.  */
59 #ifndef SO_REUSEPORT
60 #define SO_REUSEPORT SO_REUSEADDR
61 #endif
62 
63 /* Reused, from udp.c */
64 struct transport *udp_clone(struct transport *, struct sockaddr *);
65 int		  udp_fd_set(struct transport *, fd_set *, int);
66 int		  udp_fd_isset(struct transport *, fd_set *);
67 void		  udp_get_dst(struct transport *, struct sockaddr **);
68 void		  udp_get_src(struct transport *, struct sockaddr **);
69 char		 *udp_decode_ids(struct transport *);
70 void		  udp_remove(struct transport *);
71 
72 static struct transport *udp_encap_create(char *);
73 static void		 udp_encap_report(struct transport *);
74 static void		 udp_encap_handle_message(struct transport *);
75 static struct transport *udp_encap_make(struct sockaddr *);
76 static int		 udp_encap_send_message(struct message *,
77     struct transport *);
78 
79 static struct transport_vtbl udp_encap_transport_vtbl = {
80 	{ 0 }, "udp_encap",
81 	udp_encap_create,
82 	0,
83 	udp_remove,
84 	udp_encap_report,
85 	udp_fd_set,
86 	udp_fd_isset,
87 	udp_encap_handle_message,
88 	udp_encap_send_message,
89 	udp_get_dst,
90 	udp_get_src,
91 	udp_decode_ids,
92 	udp_clone,
93 	0
94 };
95 
96 char	 *udp_encap_default_port = 0;
97 
98 void
udp_encap_init(void)99 udp_encap_init(void)
100 {
101 	transport_method_add(&udp_encap_transport_vtbl);
102 }
103 
104 /* Create a UDP transport structure bound to LADDR just for listening.  */
105 static struct transport *
udp_encap_make(struct sockaddr * laddr)106 udp_encap_make(struct sockaddr *laddr)
107 {
108 	struct udp_transport *t = 0;
109 	int	 s, on, wildcardaddress = 0;
110 	char	*tstr;
111 
112 	t = calloc(1, sizeof *t);
113 	if (!t) {
114 		log_print("udp_encap_make: malloc(%lu) failed",
115 		    (unsigned long)sizeof *t);
116 		free(laddr);
117 		return 0;
118 	}
119 	t->src = laddr;
120 
121 	s = socket(laddr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
122 	if (s == -1) {
123 		log_error("udp_encap_make: socket (%d, %d, %d)",
124 		    laddr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
125 		goto err;
126 	}
127 
128 	/* Make sure we don't get our traffic encrypted.  */
129 	if (sysdep_cleartext(s, laddr->sa_family) == -1)
130 		goto err;
131 
132 	/* Wildcard address ?  */
133 	switch (laddr->sa_family) {
134 	case AF_INET:
135 		if (((struct sockaddr_in *)laddr)->sin_addr.s_addr
136 		    == INADDR_ANY)
137 			wildcardaddress = 1;
138 		break;
139 	case AF_INET6:
140 		if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)laddr)->sin6_addr))
141 			wildcardaddress = 1;
142 		break;
143 	}
144 
145 	/*
146 	 * In order to have several bound specific address-port combinations
147 	 * with the same port SO_REUSEADDR is needed.
148 	 * If this is a wildcard socket and we are not listening there, but
149 	 * only sending from it make sure it is entirely reuseable with
150 	 * SO_REUSEPORT.
151 	 */
152 	on = 1;
153 	if (setsockopt(s, SOL_SOCKET,
154 	    wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR,
155 	    (void *)&on, sizeof on) == -1) {
156 		log_error("udp_encap_make: setsockopt (%d, %d, %d, %p, %lu)",
157 		    s, SOL_SOCKET,
158 		    wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR, &on,
159 		    (unsigned long)sizeof on);
160 		goto err;
161 	}
162 
163 	t->transport.vtbl = &udp_encap_transport_vtbl;
164 	if (monitor_bind(s, t->src, SA_LEN(t->src))) {
165 		if (sockaddr2text(t->src, &tstr, 0))
166 			log_error("udp_encap_make: bind (%d, %p, %lu)", s,
167 			    &t->src, (unsigned long)sizeof t->src);
168 		else {
169 			log_error("udp_encap_make: bind (%d, %s, %lu)", s,
170 			    tstr, (unsigned long)sizeof t->src);
171 			free(tstr);
172 		}
173 		goto err;
174 	}
175 
176 	t->s = s;
177 	if (sockaddr2text(t->src, &tstr, 0))
178 		LOG_DBG((LOG_MISC, 20, "udp_encap_make: "
179 		    "transport %p socket %d family %d", t, s,
180 		    t->src->sa_family == AF_INET ? 4 : 6));
181 	else {
182 		LOG_DBG((LOG_MISC, 20, "udp_encap_make: "
183 		    "transport %p socket %d ip %s port %d", t, s,
184 		    tstr, ntohs(sockaddr_port(t->src))));
185 		free(tstr);
186 	}
187 	transport_setup(&t->transport, 0);
188 	t->transport.flags |= TRANSPORT_LISTEN;
189 	return &t->transport;
190 
191 err:
192 	if (s >= 0)
193 		close (s);
194 	if (t) {
195 		/* Already closed.  */
196 		t->s = -1;
197 		udp_remove(&t->transport);
198 	}
199 	return 0;
200 }
201 
202 /*
203  * Initialize an object of the UDP transport class.  Fill in the local
204  * IP address and port information and create a server socket bound to
205  * that specific port.  Add the polymorphic transport structure to the
206  * system-wide pools of known ISAKMP transports.
207  */
208 struct transport *
udp_encap_bind(const struct sockaddr * addr)209 udp_encap_bind(const struct sockaddr *addr)
210 {
211 	struct sockaddr	*src;
212 
213 	src = malloc(SA_LEN(addr));
214 	if (!src)
215 		return 0;
216 
217 	memcpy(src, addr, SA_LEN(addr));
218 	return udp_encap_make(src);
219 }
220 
221 /*
222  * NAME is a section name found in the config database.  Setup and return
223  * a transport useable to talk to the peer specified by that name.
224  */
225 static struct transport *
udp_encap_create(char * name)226 udp_encap_create(char *name)
227 {
228 	struct virtual_transport *v;
229 	struct udp_transport	*u;
230 	struct transport	*rv;
231 	struct sockaddr		*dst, *addr;
232 	struct conf_list	*addr_list = 0;
233 	struct conf_list_node	*addr_node;
234 	char	*addr_str, *port_str;
235 
236 	port_str = conf_get_str(name, "Port"); /* XXX "Encap-port" ? */
237 	if (!port_str)
238 		port_str = udp_encap_default_port;
239 	if (!port_str)
240 		port_str = UDP_ENCAP_DEFAULT_PORT_STR;
241 
242 	addr_str = conf_get_str(name, "Address");
243 	if (!addr_str) {
244 		log_print("udp_encap_create: no address configured "
245 		    "for \"%s\"", name);
246 		return 0;
247 	}
248 	if (text2sockaddr(addr_str, port_str, &dst, 0, 0)) {
249 		log_print("udp_encap_create: address \"%s\" not understood",
250 		    addr_str);
251 		return 0;
252 	}
253 
254 	addr_str = conf_get_str(name, "Local-address");
255 	if (!addr_str)
256 		addr_list = conf_get_list("General", "Listen-on");
257 	if (!addr_str && !addr_list) {
258 		v = virtual_get_default(dst->sa_family);
259 		u = (struct udp_transport *)v->encap;
260 
261 		if (!u) {
262 			log_print("udp_encap_create: no default transport");
263 			rv = 0;
264 			goto ret;
265 		} else {
266 			rv = udp_clone((struct transport *)u, dst);
267 			if (rv)
268 				rv->vtbl = &udp_encap_transport_vtbl;
269 			goto ret;
270 		}
271 	}
272 
273 	if (addr_list) {
274 		for (addr_node = TAILQ_FIRST(&addr_list->fields);
275 		    addr_node; addr_node = TAILQ_NEXT(addr_node, link))
276 			if (text2sockaddr(addr_node->field, port_str,
277 			    &addr, 0, 0) == 0) {
278 				v = virtual_listen_lookup(addr);
279 				free(addr);
280 				if (v) {
281 					addr_str = addr_node->field;
282 					break;
283 				}
284 			}
285 		if (!addr_str) {
286 			log_print("udp_encap_create: "
287 			    "no matching listener found");
288 			rv = 0;
289 			goto ret;
290 		}
291 	}
292 	if (text2sockaddr(addr_str, port_str, &addr, 0, 0)) {
293 		log_print("udp_encap_create: "
294 		    "address \"%s\" not understood", addr_str);
295 		rv = 0;
296 		goto ret;
297 	}
298 	v = virtual_listen_lookup(addr);
299 	free(addr);
300 	if (!v) {
301 		log_print("udp_encap_create: "
302 		    "%s:%s must exist as a listener too", addr_str, port_str);
303 		rv = 0;
304 		goto ret;
305 	}
306 	rv = udp_clone(v->encap, dst);
307 	if (rv)
308 		rv->vtbl = &udp_encap_transport_vtbl;
309 
310 ret:
311 	if (addr_list)
312 		conf_free_list(addr_list);
313 	free(dst);
314 	return rv;
315 }
316 
317 /* Report transport-method specifics of the T transport.  */
318 void
udp_encap_report(struct transport * t)319 udp_encap_report(struct transport *t)
320 {
321 	struct udp_transport *u = (struct udp_transport *)t;
322 	char	 *src = NULL, *dst = NULL;
323 	in_port_t sport, dport;
324 
325 	if (sockaddr2text(u->src, &src, 0))
326 		return;
327 	sport = sockaddr_port(u->src);
328 
329 	if (!u->dst || sockaddr2text(u->dst, &dst, 0))
330 		dst = 0;
331 	dport = dst ? sockaddr_port(u->dst) : 0;
332 
333 	LOG_DBG ((LOG_REPORT, 0, "udp_encap_report: fd %d src %s:%u dst %s:%u",
334 	    u->s, src, ntohs(sport), dst ? dst : "*", ntohs(dport)));
335 
336 	free(dst);
337 	free(src);
338 }
339 
340 /*
341  * A message has arrived on transport T's socket.  If T is single-ended,
342  * clone it into a double-ended transport which we will use from now on.
343  * Package the message as we want it and continue processing in the message
344  * module.
345  */
346 static void
udp_encap_handle_message(struct transport * t)347 udp_encap_handle_message(struct transport *t)
348 {
349 	struct udp_transport	*u = (struct udp_transport *)t;
350 	struct sockaddr_storage	 from;
351 	struct message		*msg;
352 	u_int32_t	len = sizeof from;
353 	ssize_t		n;
354 	u_int8_t	buf[UDP_SIZE];
355 
356 	n = recvfrom(u->s, buf, UDP_SIZE, 0, (struct sockaddr *)&from, &len);
357 	if (n == -1) {
358 		log_error("recvfrom (%d, %p, %d, %d, %p, %p)", u->s, buf,
359 		    UDP_SIZE, 0, &from, &len);
360 		return;
361 	}
362 
363 	if (t->virtual == (struct transport *)virtual_get_default(AF_INET) ||
364 	    t->virtual == (struct transport *)virtual_get_default(AF_INET6)) {
365 		t->virtual->vtbl->reinit();
366 
367 		/*
368 		 * As we don't know the actual destination address of the
369 		 * packet, we can't really deal with it. So, just ignore it
370 		 * and hope we catch the retransmission.
371 		 */
372 		return;
373 	}
374 
375 	/*
376 	 * Make a specialized UDP transport structure out of the incoming
377 	 * transport and the address information we got from recvfrom(2).
378 	 */
379 	t = t->virtual->vtbl->clone(t->virtual, (struct sockaddr *)&from);
380 	if (!t)
381 		return;
382 
383 	/* Check NULL-ESP marker.  */
384 	if (n < (ssize_t)sizeof(u_int32_t) || *(u_int32_t *)buf != 0) {
385 		/* Should never happen.  */
386 		log_print("udp_encap_handle_message: "
387 		    "Null-ESP marker not NULL or short message");
388 		return;
389 	}
390 
391 	/* NAT-Keepalive messages should not be processed further.  */
392 	n -= sizeof(u_int32_t);
393 	if (n == 1 && buf[sizeof(u_int32_t)] == 0xFF)
394 		return;
395 
396 	msg = message_alloc(t, buf + sizeof (u_int32_t), n);
397 	if (!msg) {
398 		log_error("failed to allocate message structure, dropping "
399 		    "packet received on transport %p", u);
400 		return;
401 	}
402 
403 	msg->flags |= MSG_NATT;
404 
405 	message_recv(msg);
406 }
407 
408 /*
409  * Physically send the message MSG over its associated transport.
410  * Special: if 'msg' is NULL, send a NAT-T keepalive message.
411  */
412 static int
udp_encap_send_message(struct message * msg,struct transport * t)413 udp_encap_send_message(struct message *msg, struct transport *t)
414 {
415 	struct udp_transport *u = (struct udp_transport *)t;
416 	struct msghdr	 m;
417 	struct iovec	*new_iov = 0, keepalive;
418 	ssize_t		 n;
419 	u_int32_t	 marker = 0;			/* NULL-ESP Marker */
420 
421 	if (msg) {
422 		/* Construct new iov array, prefixing NULL-ESP Marker.  */
423 		new_iov = calloc(msg->iovlen + 1, sizeof *new_iov);
424 		if (!new_iov) {
425 			log_error ("udp_encap_send_message: "
426 			    "calloc(%lu, %lu) failed",
427 			    (unsigned long)msg->iovlen + 1,
428 			    (unsigned long)sizeof *new_iov);
429 			return -1;
430 		}
431 		new_iov[0].iov_base = &marker;
432 		new_iov[0].iov_len = IPSEC_SPI_SIZE;
433 		memcpy (new_iov + 1, msg->iov, msg->iovlen * sizeof *new_iov);
434 	} else {
435 		marker = ~marker;
436 		keepalive.iov_base = &marker;
437 		keepalive.iov_len = 1;
438 	}
439 
440 	/*
441 	 * Sending on connected sockets requires that no destination address is
442 	 * given, or else EISCONN will occur.
443 	 */
444 	m.msg_name = (caddr_t)u->dst;
445 	m.msg_namelen = SA_LEN(u->dst);
446 	m.msg_iov = msg ? new_iov : &keepalive;
447 	m.msg_iovlen = msg ? msg->iovlen + 1 : 1;
448 	m.msg_control = 0;
449 	m.msg_controllen = 0;
450 	m.msg_flags = 0;
451 	n = sendmsg (u->s, &m, 0);
452 	if (msg)
453 		free (new_iov);
454 	if (n == -1) {
455 		/* XXX We should check whether the address has gone away */
456 		log_error ("sendmsg (%d, %p, %d)", u->s, &m, 0);
457 		return -1;
458 	}
459 	return 0;
460 }
461