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