Bug Summary

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'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name virtual.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/isakmpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sbin/isakmpd -I . -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/isakmpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/sbin/isakmpd/virtual.c
1/* $OpenBSD: virtual.c,v 1.33 2019/06/28 13:32:44 deraadt Exp $ */
2
3/*
4 * Copyright (c) 2004 Håkan Olsson. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/types.h>
28#include <sys/ioctl.h>
29#include <sys/socket.h>
30#include <sys/sockio.h>
31#include <net/if.h>
32#include <netinet/in.h>
33#include <netinet6/in6_var.h>
34#include <arpa/inet.h>
35#include <ctype.h>
36#include <limits.h>
37#include <netdb.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include "conf.h"
43#include "if.h"
44#include "exchange.h"
45#include "log.h"
46#include "message.h"
47#include "nat_traversal.h"
48#include "transport.h"
49#include "virtual.h"
50#include "udp.h"
51#include "util.h"
52
53#include "udp_encap.h"
54
55static struct transport *virtual_bind(const struct sockaddr *);
56static struct transport *virtual_bind_ADDR_ANY(sa_family_t);
57static int virtual_bind_if(char *, struct sockaddr *, void *);
58static struct transport *virtual_clone(struct transport *, struct sockaddr *);
59static struct transport *virtual_create(char *);
60static char *virtual_decode_ids (struct transport *);
61static void virtual_get_dst(struct transport *,
62 struct sockaddr **);
63static struct msg_head *virtual_get_queue(struct message *);
64static void virtual_get_src(struct transport *,
65 struct sockaddr **);
66static void virtual_handle_message(struct transport *);
67static void virtual_reinit(void);
68static void virtual_remove(struct transport *);
69static void virtual_report(struct transport *);
70static int virtual_send_message(struct message *,
71 struct transport *);
72
73static struct transport_vtbl virtual_transport_vtbl = {
74 { 0 }, "udp",
75 virtual_create,
76 virtual_reinit,
77 virtual_remove,
78 virtual_report,
79 0,
80 0,
81 virtual_handle_message,
82 virtual_send_message,
83 virtual_get_dst,
84 virtual_get_src,
85 virtual_decode_ids,
86 virtual_clone,
87 virtual_get_queue
88};
89
90static LIST_HEAD (virtual_listen_list, virtual_transport)struct virtual_listen_list { struct virtual_transport *lh_first
; }
virtual_listen_list;
91static struct transport *default_transport, *default_transport6;
92
93void
94virtual_init(void)
95{
96 struct conf_list *listen_on;
97
98 LIST_INIT(&virtual_listen_list)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
140struct virtual_transport *
141virtual_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 */
162void
163virtual_reinit(void)
164{
165 struct virtual_transport *v, *v2;
166
167 /* Mark all UDP transports, except the default ones. */
168 for (v = LIST_FIRST(&virtual_listen_list)((&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
193struct virtual_transport *
194virtual_listen_lookup(struct sockaddr *addr)
195{
196 struct virtual_transport *v;
197 struct udp_transport *u;
198
199 for (v = LIST_FIRST(&virtual_listen_list)((&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 */
223static struct transport *
224virtual_bind(const struct sockaddr *addr)
225{
226 struct virtual_transport *v;
227 struct sockaddr_storage tmp_sa;
228 char *stport;
229 in_port_t port;
230
231 v = calloc(1, sizeof *v);
232 if (!v) {
233 log_error("virtual_bind: calloc(1, %lu) failed",
234 (unsigned long)sizeof *v);
235 return 0;
236 }
237
238 v->transport.vtbl = &virtual_transport_vtbl;
239
240 memcpy(&tmp_sa, addr, SA_LEN(addr)((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
291static struct transport *
292virtual_bind_ADDR_ANY(sa_family_t af)
293{
294 struct sockaddr_storage dflt_stor;
295 struct sockaddr_in *d4 = (struct sockaddr_in *)&dflt_stor;
296 struct sockaddr_in6 *d6 = (struct sockaddr_in6 *)&dflt_stor;
297 struct transport *t;
298 struct in6_addr in6addr_any = IN6ADDR_ANY_INIT{{{ 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
324static int
325virtual_bind_if(char *ifname, struct sockaddr *if_addr, void *arg)
326{
327 struct conf_list *listen_on;
328 struct virtual_transport *v;
329 struct conf_list_node *address;
330 struct sockaddr *addr;
331 struct transport *t;
332 struct ifreq flags_ifr;
333 struct in6_ifreq flags_ifr6;
334 char *addr_str;
335 int s, error;
336
337 if (sockaddr2text(if_addr, &addr_str, 0))
338 addr_str = 0;
339
340 LOG_DBG((LOG_TRANSPORT, 90,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
525static struct transport *
526virtual_clone(struct transport *vt, struct sockaddr *raddr)
527{
528 struct virtual_transport *v = (struct virtual_transport *)vt;
529 struct virtual_transport *v2;
530 struct transport *t;
531 char *stport;
532 in_port_t port;
533
534 t = malloc(sizeof *v);
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
575static struct transport *
576virtual_create(char *name)
577{
578 struct virtual_transport *v;
579 struct transport *t, *t2 = 0;
580
581 t = transport_create("udp_physical", name);
582 if (!t)
583 return 0;
584
585 if (!disable_nat_t) {
586 t2 = transport_create("udp_encap", name);
587 if (!t2) {
588 t->vtbl->remove(t);
589 return 0;
590 }
591 }
592
593 v = calloc(1, sizeof *v);
594 if (!v) {
595 log_error("virtual_create: calloc(1, %lu) failed",
596 (unsigned long)sizeof *v);
597 t->vtbl->remove(t);
598 if (t2)
599 t2->vtbl->remove(t2);
600 return 0;
601 }
602
603 memcpy(v, t, sizeof *t);
604 v->transport.virtual = 0;
605 v->main = t;
606 v->encap = t2;
607 v->transport.vtbl = &virtual_transport_vtbl;
608 t->virtual = (struct transport *)v;
609 if (t2)
610 t2->virtual = (struct transport *)v;
611 transport_setup(&v->transport, 1);
612 return (struct transport *)v;
613}
614
615static void
616virtual_remove(struct transport *t)
617{
618 struct virtual_transport *p, *v = (struct virtual_transport *)t;
619
620 if (v->encap)
621 v->encap->vtbl->remove(v->encap);
622 if (v->main)
623 v->main->vtbl->remove(v->main);
624
625 for (p = LIST_FIRST(&virtual_listen_list)((&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
635static void
636virtual_report(struct transport *t)
637{
638}
639
640static void
641virtual_handle_message(struct transport *t)
642{
643 /*
644 * As per the NAT-T draft, in case we have already switched ports,
645 * any messages received on the old (500) port SHOULD be discarded.
646 * (Actually, while phase 1 messages should be discarded,
647 * informational exchanges MAY be processed normally. For now, we
648 * discard them all.)
649 */
650 if (((struct virtual_transport *)t->virtual)->encap_is_active &&
651 ((struct virtual_transport *)t->virtual)->main == t) {
652 LOG_DBG((LOG_MESSAGE, 10, "virtual_handle_message: "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
660static int
661virtual_send_message(struct message *msg, struct transport *t)
662{
663 struct virtual_transport *v =
664 (struct virtual_transport *)msg->transport;
665 struct sockaddr *dst;
666 in_port_t port, default_port;
667
668 /*
669 * Activate NAT-T Encapsulation if
670 * - the exchange says we can, and
671 * - in ID_PROT, after step 4 (draft-ietf-ipsec-nat-t-ike-03), or
672 * - in other exchange (Aggressive, ), asap
673 * XXX ISAKMP_EXCH_BASE etc?
674 */
675
676 if (msg->flags & MSG_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
709static void
710virtual_get_src(struct transport *t, struct sockaddr **s)
711{
712 struct virtual_transport *v = (struct virtual_transport *)t;
713
714 if (v->encap_is_active)
715 v->encap->vtbl->get_src(v->encap, s);
716 else
717 v->main->vtbl->get_src(v->main, s);
718}
719
720static void
721virtual_get_dst(struct transport *t, struct sockaddr **s)
722{
723 struct virtual_transport *v = (struct virtual_transport *)t;
724
725 if (v->encap_is_active)
726 v->encap->vtbl->get_dst(v->encap, s);
727 else
728 v->main->vtbl->get_dst(v->main, s);
729}
730
731static char *
732virtual_decode_ids(struct transport *t)
733{
734 struct virtual_transport *v = (struct virtual_transport *)t;
735
736 if (v->encap_is_active)
737 return v->encap->vtbl->decode_ids(t);
738 else
739 return v->main->vtbl->decode_ids(t);
740}
741
742static struct msg_head *
743virtual_get_queue(struct message *msg)
744{
745 if (msg->flags & MSG_PRIORITIZED0x08)
746 return &msg->transport->prio_sendq;
747 else
748 return &msg->transport->sendq;
749}