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