File: | src/sbin/isakmpd/virtual.c |
Warning: | line 534, column 6 Result of 'malloc' is converted to a pointer of type 'struct transport', which is incompatible with sizeof operand type 'struct virtual_transport' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
55 | static struct transport *virtual_bind(const struct sockaddr *); |
56 | static struct transport *virtual_bind_ADDR_ANY(sa_family_t); |
57 | static int virtual_bind_if(char *, struct sockaddr *, void *); |
58 | static struct transport *virtual_clone(struct transport *, struct sockaddr *); |
59 | static struct transport *virtual_create(char *); |
60 | static char *virtual_decode_ids (struct transport *); |
61 | static void virtual_get_dst(struct transport *, |
62 | struct sockaddr **); |
63 | static struct msg_head *virtual_get_queue(struct message *); |
64 | static void virtual_get_src(struct transport *, |
65 | struct sockaddr **); |
66 | static void virtual_handle_message(struct transport *); |
67 | static void virtual_reinit(void); |
68 | static void virtual_remove(struct transport *); |
69 | static void virtual_report(struct transport *); |
70 | static int virtual_send_message(struct message *, |
71 | struct transport *); |
72 | |
73 | static struct transport_vtbl virtual_transport_vtbl = { |
74 | { 0 }, "udp", |
75 | virtual_create, |
76 | virtual_reinit, |
77 | virtual_remove, |
78 | virtual_report, |
79 | 0, |
80 | 0, |
81 | virtual_handle_message, |
82 | virtual_send_message, |
83 | virtual_get_dst, |
84 | virtual_get_src, |
85 | virtual_decode_ids, |
86 | virtual_clone, |
87 | virtual_get_queue |
88 | }; |
89 | |
90 | static LIST_HEAD (virtual_listen_list, virtual_transport)struct virtual_listen_list { struct virtual_transport *lh_first ; } virtual_listen_list; |
91 | static struct transport *default_transport, *default_transport6; |
92 | |
93 | void |
94 | virtual_init(void) |
95 | { |
96 | struct conf_list *listen_on; |
97 | |
98 | LIST_INIT(&virtual_listen_list)do { ((&virtual_listen_list)->lh_first) = ((void *)0); } while (0); |
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,log_debug (LOG_TRANSPORT, 50, "virtual_init: not binding ISAKMP port(s) to ADDR_ANY" ) |
111 | "virtual_init: not binding ISAKMP port(s) to ADDR_ANY"))log_debug (LOG_TRANSPORT, 50, "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_INET40x0001)) { |
122 | default_transport = virtual_bind_ADDR_ANY(AF_INET2); |
123 | if (!default_transport) |
124 | return; |
125 | LIST_INSERT_HEAD(&virtual_listen_list,do { if ((((struct virtual_transport *)default_transport)-> link.le_next = (&virtual_listen_list)->lh_first) != (( void *)0)) (&virtual_listen_list)->lh_first->link.le_prev = &((struct virtual_transport *)default_transport)->link .le_next; (&virtual_listen_list)->lh_first = ((struct virtual_transport *)default_transport); ((struct virtual_transport *)default_transport )->link.le_prev = &(&virtual_listen_list)->lh_first ; } while (0) |
126 | (struct virtual_transport *)default_transport, link)do { if ((((struct virtual_transport *)default_transport)-> link.le_next = (&virtual_listen_list)->lh_first) != (( void *)0)) (&virtual_listen_list)->lh_first->link.le_prev = &((struct virtual_transport *)default_transport)->link .le_next; (&virtual_listen_list)->lh_first = ((struct virtual_transport *)default_transport); ((struct virtual_transport *)default_transport )->link.le_prev = &(&virtual_listen_list)->lh_first ; } while (0); |
127 | transport_reference(default_transport); |
128 | } |
129 | |
130 | if (!bind_family || (bind_family & BIND_FAMILY_INET60x0002)) { |
131 | default_transport6 = virtual_bind_ADDR_ANY(AF_INET624); |
132 | if (!default_transport6) |
133 | return; |
134 | LIST_INSERT_HEAD(&virtual_listen_list,do { if ((((struct virtual_transport *)default_transport6)-> link.le_next = (&virtual_listen_list)->lh_first) != (( void *)0)) (&virtual_listen_list)->lh_first->link.le_prev = &((struct virtual_transport *)default_transport6)-> link.le_next; (&virtual_listen_list)->lh_first = ((struct virtual_transport *)default_transport6); ((struct virtual_transport *)default_transport6)->link.le_prev = &(&virtual_listen_list )->lh_first; } while (0) |
135 | (struct virtual_transport *)default_transport6, link)do { if ((((struct virtual_transport *)default_transport6)-> link.le_next = (&virtual_listen_list)->lh_first) != (( void *)0)) (&virtual_listen_list)->lh_first->link.le_prev = &((struct virtual_transport *)default_transport6)-> link.le_next; (&virtual_listen_list)->lh_first = ((struct virtual_transport *)default_transport6); ((struct virtual_transport *)default_transport6)->link.le_prev = &(&virtual_listen_list )->lh_first; } while (0); |
136 | transport_reference(default_transport6); |
137 | } |
138 | } |
139 | |
140 | struct virtual_transport * |
141 | virtual_get_default(sa_family_t af) |
142 | { |
143 | switch (af) { |
144 | case AF_INET2: |
145 | return (struct virtual_transport *)default_transport; |
146 | case AF_INET624: |
147 | return (struct virtual_transport *)default_transport6; |
148 | default: |
149 | return 0; |
150 | } |
151 | } |
152 | |
153 | /* |
154 | * Probe the interface list and determine what new interfaces have |
155 | * appeared. |
156 | * |
157 | * At the same time, we try to determine whether existing interfaces have |
158 | * been rendered invalid; we do this by marking all virtual transports before |
159 | * we call virtual_bind_if() through if_map(), and then releasing those |
160 | * transports that have not been unmarked. |
161 | */ |
162 | void |
163 | virtual_reinit(void) |
164 | { |
165 | struct virtual_transport *v, *v2; |
166 | |
167 | /* Mark all UDP transports, except the default ones. */ |
168 | for (v = LIST_FIRST(&virtual_listen_list)((&virtual_listen_list)->lh_first); v; v = LIST_NEXT(v, link)((v)->link.le_next)) |
169 | if (&v->transport != default_transport && |
170 | &v->transport != default_transport6) |
171 | v->transport.flags |= TRANSPORT_MARK2; |
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)((&virtual_listen_list)->lh_first); |
183 | while (v) { |
184 | v2 = LIST_NEXT(v, link)((v)->link.le_next); |
185 | if (v->transport.flags & TRANSPORT_MARK2) { |
186 | LIST_REMOVE(v, link)do { if ((v)->link.le_next != ((void *)0)) (v)->link.le_next ->link.le_prev = (v)->link.le_prev; *(v)->link.le_prev = (v)->link.le_next; ; ; } while (0); |
187 | transport_release(&v->transport); |
188 | } |
189 | v = v2; |
190 | } |
191 | } |
192 | |
193 | struct virtual_transport * |
194 | virtual_listen_lookup(struct sockaddr *addr) |
195 | { |
196 | struct virtual_transport *v; |
197 | struct udp_transport *u; |
198 | |
199 | for (v = LIST_FIRST(&virtual_listen_list)((&virtual_listen_list)->lh_first); v; |
200 | v = LIST_NEXT(v, link)((v)->link.le_next)) { |
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"))log_debug (LOG_TRANSPORT, 40, "virtual_listen_lookup: no match" ); |
217 | return 0; |
218 | } |
219 | |
220 | /* |
221 | * Initialize an object of the VIRTUAL transport class. |
222 | */ |
223 | static struct transport * |
224 | virtual_bind(const struct sockaddr *addr) |
225 | { |
226 | struct virtual_transport *v; |
227 | struct sockaddr_storage tmp_sa; |
228 | char *stport; |
229 | in_port_t port; |
230 | |
231 | v = 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)((addr)->sa_len)); |
241 | |
242 | /* Get port. */ |
243 | stport = udp_default_port ? udp_default_port : UDP_DEFAULT_PORT_STR"500"; |
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)((addr)->sa_len)); |
261 | |
262 | /* Get port. */ |
263 | stport = udp_encap_default_port |
264 | ? udp_encap_default_port : UDP_ENCAP_DEFAULT_PORT_STR"4500"; |
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_LISTEN1; |
287 | |
288 | return (struct transport *)v; |
289 | } |
290 | |
291 | static struct transport * |
292 | virtual_bind_ADDR_ANY(sa_family_t af) |
293 | { |
294 | struct sockaddr_storage dflt_stor; |
295 | struct sockaddr_in *d4 = (struct sockaddr_in *)&dflt_stor; |
296 | struct sockaddr_in6 *d6 = (struct sockaddr_in6 *)&dflt_stor; |
297 | struct transport *t; |
298 | struct in6_addr in6addr_any = IN6ADDR_ANY_INIT{{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}; |
299 | |
300 | bzero(&dflt_stor, sizeof dflt_stor); |
301 | switch (af) { |
302 | case AF_INET2: |
303 | d4->sin_family = af; |
304 | d4->sin_len = sizeof(struct sockaddr_in); |
305 | d4->sin_addr.s_addr = INADDR_ANY((u_int32_t)(0x00000000)); |
306 | break; |
307 | |
308 | case AF_INET624: |
309 | d6->sin6_family = af; |
310 | d6->sin6_len = sizeof(struct sockaddr_in6); |
311 | memcpy(&d6->sin6_addr.s6_addr__u6_addr.__u6_addr8, &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_INET2 ? "4" : "6"); |
321 | return t; |
322 | } |
323 | |
324 | static int |
325 | virtual_bind_if(char *ifname, struct sockaddr *if_addr, void *arg) |
326 | { |
327 | struct conf_list *listen_on; |
328 | struct virtual_transport *v; |
329 | struct conf_list_node *address; |
330 | struct sockaddr *addr; |
331 | struct transport *t; |
332 | struct ifreq flags_ifr; |
333 | struct in6_ifreq flags_ifr6; |
334 | char *addr_str; |
335 | int s, error; |
336 | |
337 | if (sockaddr2text(if_addr, &addr_str, 0)) |
338 | addr_str = 0; |
339 | |
340 | LOG_DBG((LOG_TRANSPORT, 90,log_debug (LOG_TRANSPORT, 90, "virtual_bind_if: interface %s family %s address %s" , ifname ? ifname : "<unknown>", if_addr->sa_family == 2 ? "v4" : (if_addr->sa_family == 24 ? "v6" : "<unknown>" ), addr_str ? addr_str : "<invalid>") |
341 | "virtual_bind_if: interface %s family %s address %s",log_debug (LOG_TRANSPORT, 90, "virtual_bind_if: interface %s family %s address %s" , ifname ? ifname : "<unknown>", if_addr->sa_family == 2 ? "v4" : (if_addr->sa_family == 24 ? "v6" : "<unknown>" ), addr_str ? addr_str : "<invalid>") |
342 | ifname ? ifname : "<unknown>",log_debug (LOG_TRANSPORT, 90, "virtual_bind_if: interface %s family %s address %s" , ifname ? ifname : "<unknown>", if_addr->sa_family == 2 ? "v4" : (if_addr->sa_family == 24 ? "v6" : "<unknown>" ), addr_str ? addr_str : "<invalid>") |
343 | if_addr->sa_family == AF_INET ? "v4" :log_debug (LOG_TRANSPORT, 90, "virtual_bind_if: interface %s family %s address %s" , ifname ? ifname : "<unknown>", if_addr->sa_family == 2 ? "v4" : (if_addr->sa_family == 24 ? "v6" : "<unknown>" ), addr_str ? addr_str : "<invalid>") |
344 | (if_addr->sa_family == AF_INET6 ? "v6" : "<unknown>"),log_debug (LOG_TRANSPORT, 90, "virtual_bind_if: interface %s family %s address %s" , ifname ? ifname : "<unknown>", if_addr->sa_family == 2 ? "v4" : (if_addr->sa_family == 24 ? "v6" : "<unknown>" ), addr_str ? addr_str : "<invalid>") |
345 | addr_str ? addr_str : "<invalid>"))log_debug (LOG_TRANSPORT, 90, "virtual_bind_if: interface %s family %s address %s" , ifname ? ifname : "<unknown>", if_addr->sa_family == 2 ? "v4" : (if_addr->sa_family == 24 ? "v6" : "<unknown>" ), addr_str ? addr_str : "<invalid>"); |
346 | free(addr_str); |
347 | |
348 | /* |
349 | * Drop non-Internet stuff. |
350 | */ |
351 | if ((if_addr->sa_family != AF_INET2 || |
352 | SA_LEN(if_addr)((if_addr)->sa_len) != sizeof (struct sockaddr_in)) && |
353 | (if_addr->sa_family != AF_INET624 || |
354 | SA_LEN(if_addr)((if_addr)->sa_len) != 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_INET2: |
363 | if ((bind_family & BIND_FAMILY_INET40x0001) == 0) |
364 | return 0; |
365 | break; |
366 | case AF_INET624: |
367 | if ((bind_family & BIND_FAMILY_INET60x0002) == 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_INET2 && |
379 | (((struct sockaddr_in *)if_addr)->sin_addr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)) || |
380 | (((struct sockaddr_in *)if_addr)->sin_addr.s_addr == INADDR_NONE((u_int32_t)(0xffffffff))))) |
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: "log_debug (LOG_TRANSPORT, 90, "virtual_bind_if: " "already bound" ) |
390 | "already bound"))log_debug (LOG_TRANSPORT, 90, "virtual_bind_if: " "already bound" ); |
391 | v->transport.flags &= ~TRANSPORT_MARK2; |
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_DGRAM2, 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(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((17))), (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_flagsifr_ifru.ifru_flags & IFF_UP0x1)) { |
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_INET624) { |
419 | memset(&flags_ifr6, 0, sizeof(flags_ifr6)); |
420 | strlcpy(flags_ifr6.ifr_name, ifname, sizeof flags_ifr6.ifr_name); |
421 | flags_ifr6.ifr_addrifr_ifru.ifru_addr = *(struct sockaddr_in6 *)if_addr; |
422 | if (ioctl(s, SIOCGIFAFLAG_IN6(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct in6_ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((73))), (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_ANYCAST0x01| |
429 | IN6_IFF_TENTATIVE0x02|IN6_IFF_DUPLICATED0x04|IN6_IFF_DETACHED0x08)) { |
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(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((160))), (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_rdomainidifr_ifru.ifru_metric) { |
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_INET2: |
463 | ((struct sockaddr_in *)if_addr)->sin_port = htons(0)(__uint16_t)(__builtin_constant_p(0) ? (__uint16_t)(((__uint16_t )(0) & 0xffU) << 8 | ((__uint16_t)(0) & 0xff00U ) >> 8) : __swap16md(0)); |
464 | break; |
465 | case AF_INET624: |
466 | ((struct sockaddr_in6 *)if_addr)->sin6_port = htons(0)(__uint16_t)(__builtin_constant_p(0) ? (__uint16_t)(((__uint16_t )(0) & 0xffU) << 8 | ((__uint16_t)(0) & 0xff00U ) >> 8) : __swap16md(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)((&listen_on->fields)->tqh_first); address; |
483 | address = TAILQ_NEXT(address, link)((address)->link.tqe_next)) { |
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)((addr)->sa_len)) == 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,do { if ((((struct virtual_transport *)t)->link.le_next = ( &virtual_listen_list)->lh_first) != ((void *)0)) (& virtual_listen_list)->lh_first->link.le_prev = &((struct virtual_transport *)t)->link.le_next; (&virtual_listen_list )->lh_first = ((struct virtual_transport *)t); ((struct virtual_transport *)t)->link.le_prev = &(&virtual_listen_list)-> lh_first; } while (0) |
520 | link)do { if ((((struct virtual_transport *)t)->link.le_next = ( &virtual_listen_list)->lh_first) != ((void *)0)) (& virtual_listen_list)->lh_first->link.le_prev = &((struct virtual_transport *)t)->link.le_next; (&virtual_listen_list )->lh_first = ((struct virtual_transport *)t); ((struct virtual_transport *)t)->link.le_prev = &(&virtual_listen_list)-> lh_first; } while (0); |
521 | transport_reference(t); |
522 | return 0; |
523 | } |
524 | |
525 | static struct transport * |
526 | virtual_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); |
Result of 'malloc' is converted to a pointer of type 'struct transport', which is incompatible with sizeof operand type 'struct virtual_transport' | |
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"4500"; |
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)",log_debug (LOG_TRANSPORT, 50, "virtual_clone: old %p new %p (%s is %p)" , v, t, v->encap_is_active ? "encap" : "main", v->encap_is_active ? v2->encap : v2->main) |
567 | v, t, v->encap_is_active ? "encap" : "main",log_debug (LOG_TRANSPORT, 50, "virtual_clone: old %p new %p (%s is %p)" , v, t, v->encap_is_active ? "encap" : "main", v->encap_is_active ? v2->encap : v2->main) |
568 | v->encap_is_active ? v2->encap : v2->main))log_debug (LOG_TRANSPORT, 50, "virtual_clone: old %p new %p (%s is %p)" , v, t, v->encap_is_active ? "encap" : "main", v->encap_is_active ? v2->encap : v2->main); |
569 | |
570 | t->flags &= ~TRANSPORT_LISTEN1; |
571 | transport_setup(t, 1); |
572 | return t; |
573 | } |
574 | |
575 | static struct transport * |
576 | virtual_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 | |
615 | static void |
616 | virtual_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)((&virtual_listen_list)->lh_first); p && p != v; p = |
626 | LIST_NEXT(p, link)((p)->link.le_next)) |
627 | ; |
628 | if (p == v) |
629 | LIST_REMOVE(v, link)do { if ((v)->link.le_next != ((void *)0)) (v)->link.le_next ->link.le_prev = (v)->link.le_prev; *(v)->link.le_prev = (v)->link.le_next; ; ; } while (0); |
630 | |
631 | LOG_DBG((LOG_TRANSPORT, 90, "virtual_remove: removed %p", v))log_debug (LOG_TRANSPORT, 90, "virtual_remove: removed %p", v ); |
632 | free(t); |
633 | } |
634 | |
635 | static void |
636 | virtual_report(struct transport *t) |
637 | { |
638 | } |
639 | |
640 | static void |
641 | virtual_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: "log_debug (LOG_MESSAGE, 10, "virtual_handle_message: " "message on old port discarded" ) |
653 | "message on old port discarded"))log_debug (LOG_MESSAGE, 10, "virtual_handle_message: " "message on old port discarded" ); |
654 | return; |
655 | } |
656 | |
657 | t->vtbl->handle_message(t); |
658 | } |
659 | |
660 | static int |
661 | virtual_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_NATT0x20) { |
677 | msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE0x0010; |
678 | msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_CAP_PEER0x0008; |
679 | } |
680 | |
681 | if ((v->encap_is_active == 0 && |
682 | (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE0x0010) && |
683 | (msg->exchange->type != ISAKMP_EXCH_ID_PROT2 || |
684 | msg->exchange->step > 4)) || (msg->flags & MSG_NATT0x20)) { |
685 | LOG_DBG((LOG_MESSAGE, 10, "virtual_send_message: "log_debug (LOG_MESSAGE, 10, "virtual_send_message: " "enabling NAT-T encapsulation for this exchange" ) |
686 | "enabling NAT-T encapsulation for this exchange"))log_debug (LOG_MESSAGE, 10, "virtual_send_message: " "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))(__uint16_t)(__builtin_constant_p(sockaddr_port(dst)) ? (__uint16_t )(((__uint16_t)(sockaddr_port(dst)) & 0xffU) << 8 | ((__uint16_t)(sockaddr_port(dst)) & 0xff00U) >> 8) : __swap16md(sockaddr_port(dst))); |
692 | |
693 | if (udp_default_port) |
694 | default_port = text2port(udp_default_port); |
695 | else |
696 | default_port = UDP_DEFAULT_PORT500; |
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 | |
709 | static void |
710 | virtual_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 | |
720 | static void |
721 | virtual_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 | |
731 | static char * |
732 | virtual_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 | |
742 | static struct msg_head * |
743 | virtual_get_queue(struct message *msg) |
744 | { |
745 | if (msg->flags & MSG_PRIORITIZED0x08) |
746 | return &msg->transport->prio_sendq; |
747 | else |
748 | return &msg->transport->sendq; |
749 | } |