1/*	$OpenBSD: virtual.c,v 1.33 2019/06/28 13:32:44 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
55static struct transport	*virtual_bind(const struct sockaddr *);
56static struct transport	*virtual_bind_ADDR_ANY(sa_family_t);
57static int		 virtual_bind_if(char *, struct sockaddr *, void *);
58static struct transport	*virtual_clone(struct transport *, struct sockaddr *);
59static struct transport	*virtual_create(char *);
60static char		*virtual_decode_ids (struct transport *);
61static void		 virtual_get_dst(struct transport *,
62			     struct sockaddr **);
63static struct msg_head	*virtual_get_queue(struct message *);
64static void		 virtual_get_src(struct transport *,
65			     struct sockaddr **);
66static void		 virtual_handle_message(struct transport *);
67static void		 virtual_reinit(void);
68static void		 virtual_remove(struct transport *);
69static void		 virtual_report(struct transport *);
70static int		 virtual_send_message(struct message *,
71			     struct transport *);
72
73static 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
90static LIST_HEAD (virtual_listen_list, virtual_transport) virtual_listen_list;
91static struct transport *default_transport, *default_transport6;
92
93void
94virtual_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
140struct virtual_transport *
141virtual_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 */
162void
163virtual_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
193struct virtual_transport *
194virtual_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 */
223static struct transport *
224virtual_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
291static struct transport *
292virtual_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
324static int
325virtual_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) == -1) {
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
525static struct transport *
526virtual_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
575static struct transport *
576virtual_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
615static void
616virtual_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
635static void
636virtual_report(struct transport *t)
637{
638}
639
640static void
641virtual_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
660static int
661virtual_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
709static void
710virtual_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
720static void
721virtual_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
731static char *
732virtual_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
742static struct msg_head *
743virtual_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}
750