| 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 | } |