GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/isakmpd/udp_encap.c Lines: 0 175 0.0 %
Date: 2017-11-07 Branches: 0 103 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: udp_encap.c,v 1.23 2015/08/20 22:02:21 deraadt 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
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 *
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 *
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 *
226
udp_encap_create(char *name)
227
{
228
	struct virtual_transport *v;
229
	struct udp_transport	*u;
230
	struct transport	*rv, *t;
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
	t = (struct transport *)v;
307
	rv = udp_clone(v->encap, dst);
308
	if (rv)
309
		rv->vtbl = &udp_encap_transport_vtbl;
310
311
ret:
312
	if (addr_list)
313
		conf_free_list(addr_list);
314
	free(dst);
315
	return rv;
316
}
317
318
/* Report transport-method specifics of the T transport.  */
319
void
320
udp_encap_report(struct transport *t)
321
{
322
	struct udp_transport *u = (struct udp_transport *)t;
323
	char	 *src = NULL, *dst = NULL;
324
	in_port_t sport, dport;
325
326
	if (sockaddr2text(u->src, &src, 0))
327
		return;
328
	sport = sockaddr_port(u->src);
329
330
	if (!u->dst || sockaddr2text(u->dst, &dst, 0))
331
		dst = 0;
332
	dport = dst ? sockaddr_port(u->dst) : 0;
333
334
	LOG_DBG ((LOG_REPORT, 0, "udp_encap_report: fd %d src %s:%u dst %s:%u",
335
	    u->s, src, ntohs(sport), dst ? dst : "*", ntohs(dport)));
336
337
	free(dst);
338
	free(src);
339
}
340
341
/*
342
 * A message has arrived on transport T's socket.  If T is single-ended,
343
 * clone it into a double-ended transport which we will use from now on.
344
 * Package the message as we want it and continue processing in the message
345
 * module.
346
 */
347
static void
348
udp_encap_handle_message(struct transport *t)
349
{
350
	struct udp_transport	*u = (struct udp_transport *)t;
351
	struct sockaddr_storage	 from;
352
	struct message		*msg;
353
	u_int32_t	len = sizeof from;
354
	ssize_t		n;
355
	u_int8_t	buf[UDP_SIZE];
356
357
	n = recvfrom(u->s, buf, UDP_SIZE, 0, (struct sockaddr *)&from, &len);
358
	if (n == -1) {
359
		log_error("recvfrom (%d, %p, %d, %d, %p, %p)", u->s, buf,
360
		    UDP_SIZE, 0, &from, &len);
361
		return;
362
	}
363
364
	if (t->virtual == (struct transport *)virtual_get_default(AF_INET) ||
365
	    t->virtual == (struct transport *)virtual_get_default(AF_INET6)) {
366
		t->virtual->vtbl->reinit();
367
368
		/*
369
		 * As we don't know the actual destination address of the
370
		 * packet, we can't really deal with it. So, just ignore it
371
		 * and hope we catch the retransmission.
372
		 */
373
		return;
374
	}
375
376
	/*
377
	 * Make a specialized UDP transport structure out of the incoming
378
	 * transport and the address information we got from recvfrom(2).
379
	 */
380
	t = t->virtual->vtbl->clone(t->virtual, (struct sockaddr *)&from);
381
	if (!t)
382
		return;
383
384
	/* Check NULL-ESP marker.  */
385
	if (n < (ssize_t)sizeof(u_int32_t) || *(u_int32_t *)buf != 0) {
386
		/* Should never happen.  */
387
		log_print("udp_encap_handle_message: "
388
		    "Null-ESP marker not NULL or short message");
389
		return;
390
	}
391
392
	/* NAT-Keepalive messages should not be processed further.  */
393
	n -= sizeof(u_int32_t);
394
	if (n == 1 && buf[sizeof(u_int32_t)] == 0xFF)
395
		return;
396
397
	msg = message_alloc(t, buf + sizeof (u_int32_t), n);
398
	if (!msg) {
399
		log_error("failed to allocate message structure, dropping "
400
		    "packet received on transport %p", u);
401
		return;
402
	}
403
404
	msg->flags |= MSG_NATT;
405
406
	message_recv(msg);
407
}
408
409
/*
410
 * Physically send the message MSG over its associated transport.
411
 * Special: if 'msg' is NULL, send a NAT-T keepalive message.
412
 */
413
static int
414
udp_encap_send_message(struct message *msg, struct transport *t)
415
{
416
	struct udp_transport *u = (struct udp_transport *)t;
417
	struct msghdr	 m;
418
	struct iovec	*new_iov = 0, keepalive;
419
	ssize_t		 n;
420
	u_int32_t	 marker = 0;			/* NULL-ESP Marker */
421
422
	if (msg) {
423
		/* Construct new iov array, prefixing NULL-ESP Marker.  */
424
		new_iov = calloc(msg->iovlen + 1, sizeof *new_iov);
425
		if (!new_iov) {
426
			log_error ("udp_encap_send_message: "
427
			    "calloc(%lu, %lu) failed",
428
			    (unsigned long)msg->iovlen + 1,
429
			    (unsigned long)sizeof *new_iov);
430
			return -1;
431
		}
432
		new_iov[0].iov_base = &marker;
433
		new_iov[0].iov_len = IPSEC_SPI_SIZE;
434
		memcpy (new_iov + 1, msg->iov, msg->iovlen * sizeof *new_iov);
435
	} else {
436
		marker = ~marker;
437
		keepalive.iov_base = &marker;
438
		keepalive.iov_len = 1;
439
	}
440
441
	/*
442
	 * Sending on connected sockets requires that no destination address is
443
	 * given, or else EISCONN will occur.
444
	 */
445
	m.msg_name = (caddr_t)u->dst;
446
	m.msg_namelen = SA_LEN(u->dst);
447
	m.msg_iov = msg ? new_iov : &keepalive;
448
	m.msg_iovlen = msg ? msg->iovlen + 1 : 1;
449
	m.msg_control = 0;
450
	m.msg_controllen = 0;
451
	m.msg_flags = 0;
452
	n = sendmsg (u->s, &m, 0);
453
	if (msg)
454
		free (new_iov);
455
	if (n == -1) {
456
		/* XXX We should check whether the address has gone away */
457
		log_error ("sendmsg (%d, %p, %d)", u->s, &m, 0);
458
		return -1;
459
	}
460
	return 0;
461
}