xref: /openbsd-src/sbin/isakmpd/virtual.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: virtual.c,v 1.30 2009/01/28 17:57:15 hshoexer 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 = (struct virtual_transport *)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 	 */
399 	s = socket(if_addr->sa_family, SOCK_DGRAM, 0);
400 	if (s == -1) {
401 		log_error("virtual_bind_if: "
402 		    "socket (%d, SOCK_DGRAM, 0) failed", if_addr->sa_family);
403 		return -1;
404 	}
405 	strlcpy(flags_ifr.ifr_name, ifname, sizeof flags_ifr.ifr_name);
406 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&flags_ifr) == -1) {
407 		log_error("virtual_bind_if: "
408 		    "ioctl (%d, SIOCGIFFLAGS, ...) failed", s);
409 		close(s);
410 		return -1;
411 	}
412 	if (!(flags_ifr.ifr_flags & IFF_UP)) {
413 		close(s);
414 		return 0;
415 	}
416 	/* Also skip tentative addresses during DAD since bind(2) would fail. */
417 	if (if_addr->sa_family == AF_INET6) {
418 		memset(&flags_ifr6, 0, sizeof(flags_ifr6));
419 		strlcpy(flags_ifr6.ifr_name, ifname, sizeof flags_ifr6.ifr_name);
420 		flags_ifr6.ifr_addr = *(struct sockaddr_in6 *)if_addr;
421 		if (ioctl(s, SIOCGIFAFLAG_IN6, (caddr_t)&flags_ifr6) < 0) {
422 			log_error("virtual_bind_if: "
423 			    "ioctl (%d, SIOCGIFAFLAG_IN6, ...) failed", s);
424 			close(s);
425 			return 0;
426 		}
427 		if (flags_ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_ANYCAST|
428 		    IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED|IN6_IFF_DETACHED)) {
429 			error = sockaddr2text(if_addr, &addr_str, 0);
430 			log_print("virtual_bind_if: "
431 			    "IPv6 address %s not ready (flags 0x%x)",
432 			    error ? "unknown" : addr_str,
433 			    flags_ifr6.ifr_ifru.ifru_flags6);
434 			/* XXX schedule an interface rescan */
435 			if (!error)
436 				free(addr_str);
437 			close(s);
438 			return 0;
439 		}
440 	}
441 	close(s);
442 
443 	/* Set the port number to zero.  */
444 	switch (if_addr->sa_family) {
445 	case AF_INET:
446 		((struct sockaddr_in *)if_addr)->sin_port = htons(0);
447 		break;
448 	case AF_INET6:
449 		((struct sockaddr_in6 *)if_addr)->sin6_port = htons(0);
450 		break;
451 	default:
452 		log_print("virtual_bind_if: unsupported protocol family %d",
453 		    if_addr->sa_family);
454 		break;
455 	}
456 
457 	/*
458 	 * If we are explicit about what addresses we can listen to, be sure
459 	 * to respect that option.
460 	 * This is quite wasteful redoing the list-run for every interface,
461 	 * but who cares?  This is not an operation that needs to be fast.
462 	 */
463 	listen_on = conf_get_list("General", "Listen-on");
464 	if (listen_on) {
465 		for (address = TAILQ_FIRST(&listen_on->fields); address;
466 		    address = TAILQ_NEXT(address, link)) {
467 			if (text2sockaddr(address->field, 0, &addr, 0, 0)) {
468 				log_print("virtual_bind_if: "
469 				    "invalid address %s in \"Listen-on\"",
470 				    address->field);
471 				continue;
472 			}
473 
474 			/* If found, take the easy way out. */
475 			if (memcmp(addr, if_addr, SA_LEN(addr)) == 0) {
476 				free(addr);
477 				break;
478 			}
479 			free(addr);
480 		}
481 		conf_free_list(listen_on);
482 
483 		/*
484 		 * If address is zero then we did not find the address among
485 		 * the ones we should listen to.
486 		 * XXX We do not discover if we do not find our listen
487 		 * addresses. Maybe this should be the other way round.
488 		 */
489 		if (!address)
490 			return 0;
491 	}
492 
493 	t = virtual_bind(if_addr);
494 	if (!t) {
495 		error = sockaddr2text(if_addr, &addr_str, 0);
496 		log_print("virtual_bind_if: failed to create a socket on %s",
497 		    error ? "unknown" : addr_str);
498 		if (!error)
499 			free(addr_str);
500 		return -1;
501 	}
502 	LIST_INSERT_HEAD(&virtual_listen_list, (struct virtual_transport *)t,
503 	    link);
504 	transport_reference(t);
505 	return 0;
506 }
507 
508 static struct transport *
509 virtual_clone(struct transport *vt, struct sockaddr *raddr)
510 {
511 	struct virtual_transport *v = (struct virtual_transport *)vt;
512 	struct virtual_transport *v2;
513 	struct transport	 *t;
514 	char			 *stport;
515 	in_port_t		  port;
516 
517 	t = malloc(sizeof *v);
518 	if (!t) {
519 		log_error("virtual_clone: malloc(%lu) failed",
520 		    (unsigned long)sizeof *v);
521 		return 0;
522 	}
523 	v2 = (struct virtual_transport *)t;
524 
525 	memcpy(v2, v, sizeof *v);
526 	/* Remove the copy's links into virtual_listen_list.  */
527 	memset(&v2->link, 0, sizeof v2->link);
528 
529 	if (v->encap_is_active)
530 		v2->main = 0; /* No need to clone this.  */
531 	else {
532 		v2->main = v->main->vtbl->clone(v->main, raddr);
533 		v2->main->virtual = (struct transport *)v2;
534 	}
535 	if (!disable_nat_t) {
536 		stport = udp_encap_default_port ? udp_encap_default_port :
537 		    UDP_ENCAP_DEFAULT_PORT_STR;
538 		port = text2port(stport);
539 		if (port == 0) {
540 			log_print("virtual_clone: port string \"%s\" not convertible "
541 			    "to in_port_t", stport);
542 			free(t);
543 			return 0;
544 		}
545 		sockaddr_set_port(raddr, port);
546 		v2->encap = v->encap->vtbl->clone(v->encap, raddr);
547 		v2->encap->virtual = (struct transport *)v2;
548 	}
549 	LOG_DBG((LOG_TRANSPORT, 50, "virtual_clone: old %p new %p (%s is %p)",
550 	    v, t, v->encap_is_active ? "encap" : "main",
551 	    v->encap_is_active ? v2->encap : v2->main));
552 
553 	t->flags &= ~TRANSPORT_LISTEN;
554 	transport_setup(t, 1);
555 	return t;
556 }
557 
558 static struct transport *
559 virtual_create(char *name)
560 {
561 	struct virtual_transport *v;
562 	struct transport	 *t, *t2 = 0;
563 
564 	t = transport_create("udp_physical", name);
565 	if (!t)
566 		return 0;
567 
568 	if (!disable_nat_t) {
569 		t2 = transport_create("udp_encap", name);
570 		if (!t2) {
571 			t->vtbl->remove(t);
572 			return 0;
573 		}
574 	}
575 
576 	v = (struct virtual_transport *)calloc(1, sizeof *v);
577 	if (!v) {
578 		log_error("virtual_create: calloc(1, %lu) failed",
579 		    (unsigned long)sizeof *v);
580 		t->vtbl->remove(t);
581 		if (t2)
582 			t2->vtbl->remove(t2);
583 		return 0;
584 	}
585 
586 	memcpy(v, t, sizeof *t);
587 	v->transport.virtual = 0;
588 	v->main = t;
589 	v->encap = t2;
590 	v->transport.vtbl = &virtual_transport_vtbl;
591 	t->virtual = (struct transport *)v;
592 	if (t2)
593 		t2->virtual = (struct transport *)v;
594 	transport_setup(&v->transport, 1);
595 	return (struct transport *)v;
596 }
597 
598 static void
599 virtual_remove(struct transport *t)
600 {
601 	struct virtual_transport *p, *v = (struct virtual_transport *)t;
602 
603 	if (v->encap)
604 		v->encap->vtbl->remove(v->encap);
605 	if (v->main)
606 		v->main->vtbl->remove(v->main);
607 
608 	for (p = LIST_FIRST(&virtual_listen_list); p && p != v; p =
609 	    LIST_NEXT(p, link))
610 		;
611 	if (p == v)
612 		LIST_REMOVE(v, link);
613 
614 	LOG_DBG((LOG_TRANSPORT, 90, "virtual_remove: removed %p", v));
615 	free(t);
616 }
617 
618 static void
619 virtual_report(struct transport *t)
620 {
621 }
622 
623 static void
624 virtual_handle_message(struct transport *t)
625 {
626 	/*
627 	 * As per the NAT-T draft, in case we have already switched ports,
628 	 * any messages received on the old (500) port SHOULD be discarded.
629 	 * (Actually, while phase 1 messages should be discarded,
630 	 *  informational exchanges MAY be processed normally. For now, we
631 	 *  discard them all.)
632 	 */
633 	if (((struct virtual_transport *)t->virtual)->encap_is_active &&
634 	    ((struct virtual_transport *)t->virtual)->main == t) {
635 		LOG_DBG((LOG_MESSAGE, 10, "virtual_handle_message: "
636 		    "message on old port discarded"));
637 		return;
638 	}
639 
640 	t->vtbl->handle_message(t);
641 }
642 
643 static int
644 virtual_send_message(struct message *msg, struct transport *t)
645 {
646 	struct virtual_transport *v =
647 	    (struct virtual_transport *)msg->transport;
648 	struct sockaddr *dst;
649 	in_port_t port, default_port;
650 
651 	/*
652 	 * Activate NAT-T Encapsulation if
653 	 *   - the exchange says we can, and
654 	 *   - in ID_PROT, after step 4 (draft-ietf-ipsec-nat-t-ike-03), or
655 	 *   - in other exchange (Aggressive, ), asap
656 	 * XXX ISAKMP_EXCH_BASE etc?
657 	 */
658 
659 	if (msg->flags & MSG_NATT) {
660 		msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE;
661 		msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_CAP_PEER;
662 	}
663 
664 	if ((v->encap_is_active == 0 &&
665 	    (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE) &&
666 	    (msg->exchange->type != ISAKMP_EXCH_ID_PROT ||
667 		msg->exchange->step > 4)) || (msg->flags & MSG_NATT)) {
668 		LOG_DBG((LOG_MESSAGE, 10, "virtual_send_message: "
669 		    "enabling NAT-T encapsulation for this exchange"));
670 		v->encap_is_active++;
671 
672 		/* Copy destination port if it is translated (NAT).  */
673 		v->main->vtbl->get_dst(v->main, &dst);
674 		port = ntohs(sockaddr_port(dst));
675 
676 		if (udp_default_port)
677 			default_port = text2port(udp_default_port);
678 		else
679 			default_port = UDP_DEFAULT_PORT;
680 		if (port != default_port) {
681 			v->main->vtbl->get_dst(v->encap, &dst);
682 			sockaddr_set_port(dst, port);
683 		}
684 	}
685 
686 	if (v->encap_is_active)
687 		return v->encap->vtbl->send_message(msg, v->encap);
688 	else
689 		return v->main->vtbl->send_message(msg, v->main);
690 }
691 
692 static void
693 virtual_get_src(struct transport *t, struct sockaddr **s)
694 {
695 	struct virtual_transport *v = (struct virtual_transport *)t;
696 
697 	if (v->encap_is_active)
698 		v->encap->vtbl->get_src(v->encap, s);
699 	else
700 		v->main->vtbl->get_src(v->main, s);
701 }
702 
703 static void
704 virtual_get_dst(struct transport *t, struct sockaddr **s)
705 {
706 	struct virtual_transport *v = (struct virtual_transport *)t;
707 
708 	if (v->encap_is_active)
709 		v->encap->vtbl->get_dst(v->encap, s);
710 	else
711 		v->main->vtbl->get_dst(v->main, s);
712 }
713 
714 static char *
715 virtual_decode_ids(struct transport *t)
716 {
717 	struct virtual_transport *v = (struct virtual_transport *)t;
718 
719 	if (v->encap_is_active)
720 		return v->encap->vtbl->decode_ids(t);
721 	else
722 		return v->main->vtbl->decode_ids(t);
723 }
724 
725 static struct msg_head *
726 virtual_get_queue(struct message *msg)
727 {
728 	if (msg->flags & MSG_PRIORITIZED)
729 		return &msg->transport->prio_sendq;
730 	else
731 		return &msg->transport->sendq;
732 }
733