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

Line Branch Exec Source
1
/*	$OpenBSD: virtual.c,v 1.32 2015/08/20 22:02:21 deraadt Exp $	*/
2
3
/*
4
 * Copyright (c) 2004 Håkan Olsson.  All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 *
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 */
26
27
#include <sys/types.h>
28
#include <sys/ioctl.h>
29
#include <sys/socket.h>
30
#include <sys/sockio.h>
31
#include <net/if.h>
32
#include <netinet/in.h>
33
#include <netinet6/in6_var.h>
34
#include <arpa/inet.h>
35
#include <ctype.h>
36
#include <limits.h>
37
#include <netdb.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <unistd.h>
41
42
#include "conf.h"
43
#include "if.h"
44
#include "exchange.h"
45
#include "log.h"
46
#include "message.h"
47
#include "nat_traversal.h"
48
#include "transport.h"
49
#include "virtual.h"
50
#include "udp.h"
51
#include "util.h"
52
53
#include "udp_encap.h"
54
55
static struct transport	*virtual_bind(const struct sockaddr *);
56
static struct transport	*virtual_bind_ADDR_ANY(sa_family_t);
57
static int		 virtual_bind_if(char *, struct sockaddr *, void *);
58
static struct transport	*virtual_clone(struct transport *, struct sockaddr *);
59
static struct transport	*virtual_create(char *);
60
static char		*virtual_decode_ids (struct transport *);
61
static void		 virtual_get_dst(struct transport *,
62
			     struct sockaddr **);
63
static struct msg_head	*virtual_get_queue(struct message *);
64
static void		 virtual_get_src(struct transport *,
65
			     struct sockaddr **);
66
static void		 virtual_handle_message(struct transport *);
67
static void		 virtual_reinit(void);
68
static void		 virtual_remove(struct transport *);
69
static void		 virtual_report(struct transport *);
70
static int		 virtual_send_message(struct message *,
71
			     struct transport *);
72
73
static struct transport_vtbl virtual_transport_vtbl = {
74
	{ 0 }, "udp",
75
	virtual_create,
76
	virtual_reinit,
77
	virtual_remove,
78
	virtual_report,
79
	0,
80
	0,
81
	virtual_handle_message,
82
	virtual_send_message,
83
	virtual_get_dst,
84
	virtual_get_src,
85
	virtual_decode_ids,
86
	virtual_clone,
87
	virtual_get_queue
88
};
89
90
static LIST_HEAD (virtual_listen_list, virtual_transport) virtual_listen_list;
91
static struct transport *default_transport, *default_transport6;
92
93
void
94
virtual_init(void)
95
{
96
	struct conf_list *listen_on;
97
98
	LIST_INIT(&virtual_listen_list);
99
100
	transport_method_add(&virtual_transport_vtbl);
101
102
	/* Bind the ISAKMP port(s) on all network interfaces we have.  */
103
	if (if_map(virtual_bind_if, 0) == -1)
104
		log_fatal("virtual_init: "
105
		    "could not bind the ISAKMP port(s) on all interfaces");
106
107
	/* Only listen to the specified address if Listen-on is configured */
108
	listen_on = conf_get_list("General", "Listen-on");
109
	if (listen_on) {
110
		LOG_DBG((LOG_TRANSPORT, 50,
111
		    "virtual_init: not binding ISAKMP port(s) to ADDR_ANY"));
112
		conf_free_list(listen_on);
113
		return;
114
	}
115
116
	/*
117
	 * Bind to INADDR_ANY in case of new addresses popping up.
118
	 * Packet reception on this transport is taken as a hint to reprobe the
119
	 * interface list.
120
	 */
121
	if (!bind_family || (bind_family & BIND_FAMILY_INET4)) {
122
		default_transport = virtual_bind_ADDR_ANY(AF_INET);
123
		if (!default_transport)
124
			return;
125
		LIST_INSERT_HEAD(&virtual_listen_list,
126
		    (struct virtual_transport *)default_transport, link);
127
		transport_reference(default_transport);
128
	}
129
130
	if (!bind_family || (bind_family & BIND_FAMILY_INET6)) {
131
		default_transport6 = virtual_bind_ADDR_ANY(AF_INET6);
132
		if (!default_transport6)
133
			return;
134
		LIST_INSERT_HEAD(&virtual_listen_list,
135
		    (struct virtual_transport *)default_transport6, link);
136
		transport_reference(default_transport6);
137
	}
138
}
139
140
struct virtual_transport *
141
virtual_get_default(sa_family_t af)
142
{
143
	switch (af) {
144
	case AF_INET:
145
		return (struct virtual_transport *)default_transport;
146
	case AF_INET6:
147
		return (struct virtual_transport *)default_transport6;
148
	default:
149
		return 0;
150
	}
151
}
152
153
/*
154
 * Probe the interface list and determine what new interfaces have
155
 * appeared.
156
 *
157
 * At the same time, we try to determine whether existing interfaces have
158
 * been rendered invalid; we do this by marking all virtual transports before
159
 * we call virtual_bind_if() through if_map(), and then releasing those
160
 * transports that have not been unmarked.
161
 */
162
void
163
virtual_reinit(void)
164
{
165
	struct virtual_transport *v, *v2;
166
167
	/* Mark all UDP transports, except the default ones. */
168
	for (v = LIST_FIRST(&virtual_listen_list); v; v = LIST_NEXT(v, link))
169
		if (&v->transport != default_transport &&
170
		    &v->transport != default_transport6)
171
			v->transport.flags |= TRANSPORT_MARK;
172
173
	/* Re-probe interface list.  */
174
	if (if_map(virtual_bind_if, 0) == -1)
175
		log_print("virtual_init: "
176
		    "could not bind the ISAKMP port(s) on all interfaces");
177
178
	/*
179
	 * Release listening transports for local addresses that no
180
	 * longer exist. virtual_bind_if () will have left those still marked.
181
	 */
182
	v = LIST_FIRST(&virtual_listen_list);
183
	while (v) {
184
		v2 = LIST_NEXT(v, link);
185
		if (v->transport.flags & TRANSPORT_MARK) {
186
			LIST_REMOVE(v, link);
187
			transport_release(&v->transport);
188
		}
189
		v = v2;
190
	}
191
}
192
193
struct virtual_transport *
194
virtual_listen_lookup(struct sockaddr *addr)
195
{
196
	struct virtual_transport *v;
197
	struct udp_transport	 *u;
198
199
	for (v = LIST_FIRST(&virtual_listen_list); v;
200
	    v = LIST_NEXT(v, link)) {
201
		if (!(u = (struct udp_transport *)v->main))
202
			if (!(u = (struct udp_transport *)v->encap)) {
203
				log_print("virtual_listen_lookup: "
204
				    "virtual %p has no low-level transports",
205
				    v);
206
				continue;
207
			}
208
209
		if (u->src->sa_family == addr->sa_family &&
210
		    sockaddr_addrlen(u->src) == sockaddr_addrlen(addr) &&
211
		    memcmp(sockaddr_addrdata (u->src), sockaddr_addrdata(addr),
212
		    sockaddr_addrlen(addr)) == 0)
213
			return v;
214
	}
215
216
	LOG_DBG((LOG_TRANSPORT, 40, "virtual_listen_lookup: no match"));
217
	return 0;
218
}
219
220
/*
221
 * Initialize an object of the VIRTUAL transport class.
222
 */
223
static struct transport *
224
virtual_bind(const struct sockaddr *addr)
225
{
226
	struct virtual_transport *v;
227
	struct sockaddr_storage	  tmp_sa;
228
	char	*stport;
229
	in_port_t port;
230
231
	v = calloc(1, sizeof *v);
232
	if (!v) {
233
		log_error("virtual_bind: calloc(1, %lu) failed",
234
		    (unsigned long)sizeof *v);
235
		return 0;
236
	}
237
238
	v->transport.vtbl = &virtual_transport_vtbl;
239
240
	memcpy(&tmp_sa, addr, SA_LEN(addr));
241
242
	/* Get port. */
243
	stport = udp_default_port ? udp_default_port : UDP_DEFAULT_PORT_STR;
244
	port = text2port(stport);
245
	if (port == 0) {
246
		log_print("virtual_bind: bad port \"%s\"", stport);
247
		free(v);
248
		return 0;
249
	}
250
251
	sockaddr_set_port((struct sockaddr *)&tmp_sa, port);
252
	v->main = udp_bind((struct sockaddr *)&tmp_sa);
253
	if (!v->main) {
254
		free(v);
255
		return 0;
256
	}
257
	v->main->virtual = (struct transport *)v;
258
259
	if (!disable_nat_t) {
260
		memcpy(&tmp_sa, addr, SA_LEN(addr));
261
262
		/* Get port. */
263
		stport = udp_encap_default_port
264
		    ? udp_encap_default_port : UDP_ENCAP_DEFAULT_PORT_STR;
265
		port = text2port(stport);
266
		if (port == 0) {
267
			log_print("virtual_bind: bad encap port \"%s\"",
268
			    stport);
269
			v->main->vtbl->remove(v->main);
270
			free(v);
271
			return 0;
272
		}
273
274
		sockaddr_set_port((struct sockaddr *)&tmp_sa, port);
275
		v->encap = udp_encap_bind((struct sockaddr *)&tmp_sa);
276
		if (!v->encap) {
277
			v->main->vtbl->remove(v->main);
278
			free(v);
279
			return 0;
280
		}
281
		v->encap->virtual = (struct transport *)v;
282
	}
283
	v->encap_is_active = 0;
284
285
	transport_setup(&v->transport, 1);
286
	v->transport.flags |= TRANSPORT_LISTEN;
287
288
	return (struct transport *)v;
289
}
290
291
static struct transport *
292
virtual_bind_ADDR_ANY(sa_family_t af)
293
{
294
	struct sockaddr_storage dflt_stor;
295
	struct sockaddr_in	*d4 = (struct sockaddr_in *)&dflt_stor;
296
	struct sockaddr_in6	*d6 = (struct sockaddr_in6 *)&dflt_stor;
297
	struct transport	*t;
298
	struct in6_addr		in6addr_any = IN6ADDR_ANY_INIT;
299
300
	bzero(&dflt_stor, sizeof dflt_stor);
301
	switch (af) {
302
	case AF_INET:
303
		d4->sin_family = af;
304
		d4->sin_len = sizeof(struct sockaddr_in);
305
		d4->sin_addr.s_addr = INADDR_ANY;
306
		break;
307
308
	case AF_INET6:
309
		d6->sin6_family = af;
310
		d6->sin6_len = sizeof(struct sockaddr_in6);
311
		memcpy(&d6->sin6_addr.s6_addr, &in6addr_any,
312
		    sizeof in6addr_any);
313
		break;
314
	}
315
316
	t = virtual_bind((struct sockaddr *)&dflt_stor);
317
	if (!t)
318
		log_error("virtual_bind_ADDR_ANY: "
319
		    "could not allocate default IPv%s ISAKMP port(s)",
320
		    af == AF_INET ? "4" : "6");
321
	return t;
322
}
323
324
static int
325
virtual_bind_if(char *ifname, struct sockaddr *if_addr, void *arg)
326
{
327
	struct conf_list	*listen_on;
328
	struct virtual_transport *v;
329
	struct conf_list_node	*address;
330
	struct sockaddr		*addr;
331
	struct transport	*t;
332
	struct ifreq		flags_ifr;
333
	struct in6_ifreq	flags_ifr6;
334
	char	*addr_str;
335
	int	 s, error;
336
337
	if (sockaddr2text(if_addr, &addr_str, 0))
338
		addr_str = 0;
339
340
	LOG_DBG((LOG_TRANSPORT, 90,
341
	    "virtual_bind_if: interface %s family %s address %s",
342
	    ifname ? ifname : "<unknown>",
343
	    if_addr->sa_family == AF_INET ? "v4" :
344
	    (if_addr->sa_family == AF_INET6 ? "v6" : "<unknown>"),
345
	    addr_str ? addr_str : "<invalid>"));
346
	free(addr_str);
347
348
	/*
349
	 * Drop non-Internet stuff.
350
	 */
351
	if ((if_addr->sa_family != AF_INET ||
352
	    SA_LEN(if_addr) != sizeof (struct sockaddr_in)) &&
353
	    (if_addr->sa_family != AF_INET6 ||
354
	    SA_LEN(if_addr) != sizeof (struct sockaddr_in6)))
355
		return 0;
356
357
	/*
358
	 * Only create sockets for families we should listen to.
359
	 */
360
	if (bind_family)
361
		switch (if_addr->sa_family) {
362
		case AF_INET:
363
			if ((bind_family & BIND_FAMILY_INET4) == 0)
364
				return 0;
365
			break;
366
		case AF_INET6:
367
			if ((bind_family & BIND_FAMILY_INET6) == 0)
368
				return 0;
369
			break;
370
		default:
371
			return 0;
372
		}
373
374
	/*
375
	 * These special addresses are not useable as they have special meaning
376
	 * in the IP stack.
377
	 */
378
	if (if_addr->sa_family == AF_INET &&
379
	    (((struct sockaddr_in *)if_addr)->sin_addr.s_addr == INADDR_ANY ||
380
	    (((struct sockaddr_in *)if_addr)->sin_addr.s_addr == INADDR_NONE)))
381
		return 0;
382
383
	/*
384
	 * Go through the list of transports and see if we already have this
385
	 * address bound. If so, unmark the transport and skip it; this allows
386
	 * us to call this function when we suspect a new address has appeared.
387
	 */
388
	if ((v = virtual_listen_lookup(if_addr)) != 0) {
389
		LOG_DBG ((LOG_TRANSPORT, 90, "virtual_bind_if: "
390
		    "already bound"));
391
		v->transport.flags &= ~TRANSPORT_MARK;
392
		return 0;
393
	}
394
395
	/*
396
	 * Don't bother with interfaces that are down.
397
	 * Note: This socket is only used to collect the interface status,
398
	 * rtables and inet6 addresses.
399
	 */
400
	s = socket(if_addr->sa_family, SOCK_DGRAM, 0);
401
	if (s == -1) {
402
		log_error("virtual_bind_if: "
403
		    "socket (%d, SOCK_DGRAM, 0) failed", if_addr->sa_family);
404
		return -1;
405
	}
406
	strlcpy(flags_ifr.ifr_name, ifname, sizeof flags_ifr.ifr_name);
407
	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&flags_ifr) == -1) {
408
		log_error("virtual_bind_if: "
409
		    "ioctl (%d, SIOCGIFFLAGS, ...) failed", s);
410
		close(s);
411
		return -1;
412
	}
413
	if (!(flags_ifr.ifr_flags & IFF_UP)) {
414
		close(s);
415
		return 0;
416
	}
417
	/* Also skip tentative addresses during DAD since bind(2) would fail. */
418
	if (if_addr->sa_family == AF_INET6) {
419
		memset(&flags_ifr6, 0, sizeof(flags_ifr6));
420
		strlcpy(flags_ifr6.ifr_name, ifname, sizeof flags_ifr6.ifr_name);
421
		flags_ifr6.ifr_addr = *(struct sockaddr_in6 *)if_addr;
422
		if (ioctl(s, SIOCGIFAFLAG_IN6, (caddr_t)&flags_ifr6) < 0) {
423
			log_error("virtual_bind_if: "
424
			    "ioctl (%d, SIOCGIFAFLAG_IN6, ...) failed", s);
425
			close(s);
426
			return 0;
427
		}
428
		if (flags_ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_ANYCAST|
429
		    IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED|IN6_IFF_DETACHED)) {
430
			error = sockaddr2text(if_addr, &addr_str, 0);
431
			log_print("virtual_bind_if: "
432
			    "IPv6 address %s not ready (flags 0x%x)",
433
			    error ? "unknown" : addr_str,
434
			    flags_ifr6.ifr_ifru.ifru_flags6);
435
			/* XXX schedule an interface rescan */
436
			if (!error)
437
				free(addr_str);
438
			close(s);
439
			return 0;
440
		}
441
	}
442
443
	if (ioctl(s, SIOCGIFRDOMAIN, (caddr_t)&flags_ifr) == -1) {
444
		log_error("virtual_bind_if: "
445
		    "ioctl (%d, SIOCGIFRDOMAIN, ...) failed", s);
446
		close(s);
447
		return -1;
448
	}
449
450
	/*
451
	 * Ignore interfaces outside of our rtable
452
	 */
453
	if (getrtable() != flags_ifr.ifr_rdomainid) {
454
		close(s);
455
		return 0;
456
	}
457
458
	close(s);
459
460
	/* Set the port number to zero.  */
461
	switch (if_addr->sa_family) {
462
	case AF_INET:
463
		((struct sockaddr_in *)if_addr)->sin_port = htons(0);
464
		break;
465
	case AF_INET6:
466
		((struct sockaddr_in6 *)if_addr)->sin6_port = htons(0);
467
		break;
468
	default:
469
		log_print("virtual_bind_if: unsupported protocol family %d",
470
		    if_addr->sa_family);
471
		break;
472
	}
473
474
	/*
475
	 * If we are explicit about what addresses we can listen to, be sure
476
	 * to respect that option.
477
	 * This is quite wasteful redoing the list-run for every interface,
478
	 * but who cares?  This is not an operation that needs to be fast.
479
	 */
480
	listen_on = conf_get_list("General", "Listen-on");
481
	if (listen_on) {
482
		for (address = TAILQ_FIRST(&listen_on->fields); address;
483
		    address = TAILQ_NEXT(address, link)) {
484
			if (text2sockaddr(address->field, 0, &addr, 0, 0)) {
485
				log_print("virtual_bind_if: "
486
				    "invalid address %s in \"Listen-on\"",
487
				    address->field);
488
				continue;
489
			}
490
491
			/* If found, take the easy way out. */
492
			if (memcmp(addr, if_addr, SA_LEN(addr)) == 0) {
493
				free(addr);
494
				break;
495
			}
496
			free(addr);
497
		}
498
		conf_free_list(listen_on);
499
500
		/*
501
		 * If address is zero then we did not find the address among
502
		 * the ones we should listen to.
503
		 * XXX We do not discover if we do not find our listen
504
		 * addresses. Maybe this should be the other way round.
505
		 */
506
		if (!address)
507
			return 0;
508
	}
509
510
	t = virtual_bind(if_addr);
511
	if (!t) {
512
		error = sockaddr2text(if_addr, &addr_str, 0);
513
		log_print("virtual_bind_if: failed to create a socket on %s",
514
		    error ? "unknown" : addr_str);
515
		if (!error)
516
			free(addr_str);
517
		return -1;
518
	}
519
	LIST_INSERT_HEAD(&virtual_listen_list, (struct virtual_transport *)t,
520
	    link);
521
	transport_reference(t);
522
	return 0;
523
}
524
525
static struct transport *
526
virtual_clone(struct transport *vt, struct sockaddr *raddr)
527
{
528
	struct virtual_transport *v = (struct virtual_transport *)vt;
529
	struct virtual_transport *v2;
530
	struct transport	 *t;
531
	char			 *stport;
532
	in_port_t		  port;
533
534
	t = malloc(sizeof *v);
535
	if (!t) {
536
		log_error("virtual_clone: malloc(%lu) failed",
537
		    (unsigned long)sizeof *v);
538
		return 0;
539
	}
540
	v2 = (struct virtual_transport *)t;
541
542
	memcpy(v2, v, sizeof *v);
543
	/* Remove the copy's links into virtual_listen_list.  */
544
	memset(&v2->link, 0, sizeof v2->link);
545
546
	if (v->encap_is_active)
547
		v2->main = 0; /* No need to clone this.  */
548
	else {
549
		v2->main = v->main->vtbl->clone(v->main, raddr);
550
		v2->main->virtual = (struct transport *)v2;
551
	}
552
	if (!disable_nat_t) {
553
		stport = udp_encap_default_port ? udp_encap_default_port :
554
		    UDP_ENCAP_DEFAULT_PORT_STR;
555
		port = text2port(stport);
556
		if (port == 0) {
557
			log_print("virtual_clone: port string \"%s\" not convertible "
558
			    "to in_port_t", stport);
559
			free(t);
560
			return 0;
561
		}
562
		sockaddr_set_port(raddr, port);
563
		v2->encap = v->encap->vtbl->clone(v->encap, raddr);
564
		v2->encap->virtual = (struct transport *)v2;
565
	}
566
	LOG_DBG((LOG_TRANSPORT, 50, "virtual_clone: old %p new %p (%s is %p)",
567
	    v, t, v->encap_is_active ? "encap" : "main",
568
	    v->encap_is_active ? v2->encap : v2->main));
569
570
	t->flags &= ~TRANSPORT_LISTEN;
571
	transport_setup(t, 1);
572
	return t;
573
}
574
575
static struct transport *
576
virtual_create(char *name)
577
{
578
	struct virtual_transport *v;
579
	struct transport	 *t, *t2 = 0;
580
581
	t = transport_create("udp_physical", name);
582
	if (!t)
583
		return 0;
584
585
	if (!disable_nat_t) {
586
		t2 = transport_create("udp_encap", name);
587
		if (!t2) {
588
			t->vtbl->remove(t);
589
			return 0;
590
		}
591
	}
592
593
	v = calloc(1, sizeof *v);
594
	if (!v) {
595
		log_error("virtual_create: calloc(1, %lu) failed",
596
		    (unsigned long)sizeof *v);
597
		t->vtbl->remove(t);
598
		if (t2)
599
			t2->vtbl->remove(t2);
600
		return 0;
601
	}
602
603
	memcpy(v, t, sizeof *t);
604
	v->transport.virtual = 0;
605
	v->main = t;
606
	v->encap = t2;
607
	v->transport.vtbl = &virtual_transport_vtbl;
608
	t->virtual = (struct transport *)v;
609
	if (t2)
610
		t2->virtual = (struct transport *)v;
611
	transport_setup(&v->transport, 1);
612
	return (struct transport *)v;
613
}
614
615
static void
616
virtual_remove(struct transport *t)
617
{
618
	struct virtual_transport *p, *v = (struct virtual_transport *)t;
619
620
	if (v->encap)
621
		v->encap->vtbl->remove(v->encap);
622
	if (v->main)
623
		v->main->vtbl->remove(v->main);
624
625
	for (p = LIST_FIRST(&virtual_listen_list); p && p != v; p =
626
	    LIST_NEXT(p, link))
627
		;
628
	if (p == v)
629
		LIST_REMOVE(v, link);
630
631
	LOG_DBG((LOG_TRANSPORT, 90, "virtual_remove: removed %p", v));
632
	free(t);
633
}
634
635
static void
636
virtual_report(struct transport *t)
637
{
638
}
639
640
static void
641
virtual_handle_message(struct transport *t)
642
{
643
	/*
644
	 * As per the NAT-T draft, in case we have already switched ports,
645
	 * any messages received on the old (500) port SHOULD be discarded.
646
	 * (Actually, while phase 1 messages should be discarded,
647
	 *  informational exchanges MAY be processed normally. For now, we
648
	 *  discard them all.)
649
	 */
650
	if (((struct virtual_transport *)t->virtual)->encap_is_active &&
651
	    ((struct virtual_transport *)t->virtual)->main == t) {
652
		LOG_DBG((LOG_MESSAGE, 10, "virtual_handle_message: "
653
		    "message on old port discarded"));
654
		return;
655
	}
656
657
	t->vtbl->handle_message(t);
658
}
659
660
static int
661
virtual_send_message(struct message *msg, struct transport *t)
662
{
663
	struct virtual_transport *v =
664
	    (struct virtual_transport *)msg->transport;
665
	struct sockaddr *dst;
666
	in_port_t port, default_port;
667
668
	/*
669
	 * Activate NAT-T Encapsulation if
670
	 *   - the exchange says we can, and
671
	 *   - in ID_PROT, after step 4 (draft-ietf-ipsec-nat-t-ike-03), or
672
	 *   - in other exchange (Aggressive, ), asap
673
	 * XXX ISAKMP_EXCH_BASE etc?
674
	 */
675
676
	if (msg->flags & MSG_NATT) {
677
		msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE;
678
		msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_CAP_PEER;
679
	}
680
681
	if ((v->encap_is_active == 0 &&
682
	    (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE) &&
683
	    (msg->exchange->type != ISAKMP_EXCH_ID_PROT ||
684
		msg->exchange->step > 4)) || (msg->flags & MSG_NATT)) {
685
		LOG_DBG((LOG_MESSAGE, 10, "virtual_send_message: "
686
		    "enabling NAT-T encapsulation for this exchange"));
687
		v->encap_is_active++;
688
689
		/* Copy destination port if it is translated (NAT).  */
690
		v->main->vtbl->get_dst(v->main, &dst);
691
		port = ntohs(sockaddr_port(dst));
692
693
		if (udp_default_port)
694
			default_port = text2port(udp_default_port);
695
		else
696
			default_port = UDP_DEFAULT_PORT;
697
		if (port != default_port) {
698
			v->main->vtbl->get_dst(v->encap, &dst);
699
			sockaddr_set_port(dst, port);
700
		}
701
	}
702
703
	if (v->encap_is_active)
704
		return v->encap->vtbl->send_message(msg, v->encap);
705
	else
706
		return v->main->vtbl->send_message(msg, v->main);
707
}
708
709
static void
710
virtual_get_src(struct transport *t, struct sockaddr **s)
711
{
712
	struct virtual_transport *v = (struct virtual_transport *)t;
713
714
	if (v->encap_is_active)
715
		v->encap->vtbl->get_src(v->encap, s);
716
	else
717
		v->main->vtbl->get_src(v->main, s);
718
}
719
720
static void
721
virtual_get_dst(struct transport *t, struct sockaddr **s)
722
{
723
	struct virtual_transport *v = (struct virtual_transport *)t;
724
725
	if (v->encap_is_active)
726
		v->encap->vtbl->get_dst(v->encap, s);
727
	else
728
		v->main->vtbl->get_dst(v->main, s);
729
}
730
731
static char *
732
virtual_decode_ids(struct transport *t)
733
{
734
	struct virtual_transport *v = (struct virtual_transport *)t;
735
736
	if (v->encap_is_active)
737
		return v->encap->vtbl->decode_ids(t);
738
	else
739
		return v->main->vtbl->decode_ids(t);
740
}
741
742
static struct msg_head *
743
virtual_get_queue(struct message *msg)
744
{
745
	if (msg->flags & MSG_PRIORITIZED)
746
		return &msg->transport->prio_sendq;
747
	else
748
		return &msg->transport->sendq;
749
}