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