diff options
author | Alberto Gonzalez Iniesta <agi@inittab.org> | 2016-11-21 09:37:33 +0100 |
---|---|---|
committer | Alberto Gonzalez Iniesta <agi@inittab.org> | 2016-11-21 09:37:33 +0100 |
commit | 20c8675ba46bda97330a4117c459a59a9f1c465e (patch) | |
tree | d888c714fb61947dd79dc44b64a4aaae2f70bfb7 /src/openvpn/socket.c | |
parent | ffca24bed7a03d95585ad02278667abe75d8b272 (diff) |
New upstream version 2.4~beta1upstream/2.4_beta1
Diffstat (limited to 'src/openvpn/socket.c')
-rw-r--r-- | src/openvpn/socket.c | 1938 |
1 files changed, 1063 insertions, 875 deletions
diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index b7ac339..c233f2b 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -38,6 +38,9 @@ #include "ps.h" #include "manage.h" #include "misc.h" +#include "manage.h" +#include "openvpn.h" +#include "forward.h" #include "memdbg.h" @@ -69,23 +72,6 @@ sf2gaf(const unsigned int getaddr_flags, * Functions related to the translation of DNS names to IP addresses. */ -static const char* -h_errno_msg(int h_errno_err) -{ - switch (h_errno_err) - { - case HOST_NOT_FOUND: - return "[HOST_NOT_FOUND] The specified host is unknown."; - case NO_DATA: - return "[NO_DATA] The requested name is valid but does not have an IP address."; - case NO_RECOVERY: - return "[NO_RECOVERY] A non-recoverable name server error occurred."; - case TRY_AGAIN: - return "[TRY_AGAIN] A temporary error occurred on an authoritative name server."; - } - return "[unknown h_errno value]"; -} - /* * Translate IP addr or hostname to in_addr_t. * If resolve error, try again for @@ -100,8 +86,8 @@ getaddr (unsigned int flags, { struct addrinfo *ai; int status; - status = openvpn_getaddrinfo(flags, hostname, resolve_retry_seconds, - signal_received, AF_INET, &ai); + status = openvpn_getaddrinfo (flags & ~GETADDR_HOST_ORDER, hostname, NULL, + resolve_retry_seconds, signal_received, AF_INET, &ai); if(status==0) { struct in_addr ia; if(succeeded) @@ -116,6 +102,178 @@ getaddr (unsigned int flags, } } +static inline bool +streqnull (const char* a, const char* b) +{ + if (a == NULL && b == NULL) + return true; + else if (a == NULL || b == NULL) + return false; + else + return streq (a, b); +} + +/* + get_cached_dns_entry return 0 on success and -1 + otherwise. (like getaddrinfo) + */ +static int +get_cached_dns_entry (struct cached_dns_entry* dns_cache, + const char* hostname, + const char* servname, + int ai_family, + int resolve_flags, + struct addrinfo **ai) +{ + struct cached_dns_entry *ph; + int flags; + + /* Only use flags that are relevant for the structure */ + flags = resolve_flags & GETADDR_CACHE_MASK; + + for (ph = dns_cache; ph ; ph = ph->next) + { + if (streqnull (ph->hostname, hostname) && + streqnull (ph->servname, servname) && + ph->ai_family == ai_family && + ph->flags == flags) + { + *ai = ph->ai; + return 0; + } + } + return -1; +} + + +static int +do_preresolve_host (struct context *c, + const char *hostname, + const char *servname, + const int af, + const int flags) +{ + struct addrinfo *ai; + int status; + + if (get_cached_dns_entry(c->c1.dns_cache, + hostname, + servname, + af, + flags, + &ai) == 0 ) + { + /* entry already cached, return success */ + return 0; + } + + status = openvpn_getaddrinfo (flags, hostname, servname, + c->options.resolve_retry_seconds, NULL, + af, &ai); + if (status == 0) + { + struct cached_dns_entry *ph; + + ALLOC_OBJ_CLEAR_GC (ph, struct cached_dns_entry, &c->gc); + ph->ai = ai; + ph->hostname = hostname; + ph->servname = servname; + ph->flags = flags & GETADDR_CACHE_MASK; + + if (!c->c1.dns_cache) + c->c1.dns_cache = ph; + else + { + struct cached_dns_entry *prev = c->c1.dns_cache; + while (prev->next) + prev = prev->next; + prev->next = ph; + } + + gc_addspecial (ai, &gc_freeaddrinfo_callback, &c->gc); + + } + return status; +} + +void +do_preresolve (struct context *c) +{ + int i; + struct connection_list *l = c->options.connection_list; + const unsigned int preresolve_flags = GETADDR_RESOLVE| + GETADDR_UPDATE_MANAGEMENT_STATE| + GETADDR_MENTION_RESOLVE_RETRY| + GETADDR_FATAL; + + + for (i = 0; i < l->len; ++i) + { + int status; + const char *remote; + int flags = preresolve_flags; + + struct connection_entry* ce = c->options.connection_list->array[i]; + + if (proto_is_dgram(ce->proto)) + flags |= GETADDR_DATAGRAM; + + if (c->options.sockflags & SF_HOST_RANDOMIZE) + flags |= GETADDR_RANDOMIZE; + + if (c->options.ip_remote_hint) + remote = c->options.ip_remote_hint; + else + remote = ce->remote; + + /* HTTP remote hostname does not need to be resolved */ + if (! ce->http_proxy_options) + { + status = do_preresolve_host (c, remote, ce->remote_port, ce->af, flags); + if (status != 0) + goto err; + } + + /* Preresolve proxy */ + if (ce->http_proxy_options) + { + status = do_preresolve_host (c, + ce->http_proxy_options->server, + ce->http_proxy_options->port, + ce->af, + preresolve_flags); + + if (status != 0) + goto err; + } + + if (ce->socks_proxy_server) + { + status = do_preresolve_host (c, + ce->socks_proxy_server, + ce->socks_proxy_port, + ce->af, + flags); + if (status != 0) + goto err; + } + + if (ce->bind_local) + { + flags |= GETADDR_PASSIVE; + flags &= ~GETADDR_RANDOMIZE; + status = do_preresolve_host (c, ce->local, ce->local_port, ce->af, flags); + if (status != 0) + goto err; + + } + + } + return; + + err: + throw_signal_soft (SIGHUP, "Preresolving failed"); +} /* * Translate IPv4/IPv6 addr or hostname into struct addrinfo @@ -124,6 +282,7 @@ getaddr (unsigned int flags, int openvpn_getaddrinfo (unsigned int flags, const char *hostname, + const char *servname, int resolve_retry_seconds, volatile int *signal_received, int ai_family, @@ -134,15 +293,27 @@ openvpn_getaddrinfo (unsigned int flags, int sigrec = 0; int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS; struct gc_arena gc = gc_new (); + const char *print_hostname; + const char *print_servname; ASSERT(res); - if (!hostname) - hostname = "::"; + ASSERT (hostname || servname); + ASSERT (!(flags & GETADDR_HOST_ORDER)); - if (flags & GETADDR_RANDOMIZE) + if (hostname && (flags & GETADDR_RANDOMIZE)) hostname = hostname_randomize(hostname, &gc); + if(hostname) + print_hostname = hostname; + else + print_hostname = "undefined"; + + if(servname) + print_servname = servname; + else + print_servname = ""; + if (flags & GETADDR_MSG_VIRT_OUT) msglevel |= M_MSG_VIRT_OUT; @@ -154,25 +325,35 @@ openvpn_getaddrinfo (unsigned int flags, CLEAR(hints); hints.ai_family = ai_family; hints.ai_flags = AI_NUMERICHOST; - hints.ai_socktype = SOCK_STREAM; - status = getaddrinfo(hostname, NULL, &hints, res); + if(flags & GETADDR_PASSIVE) + hints.ai_flags |= AI_PASSIVE; + + if(flags & GETADDR_DATAGRAM) + hints.ai_socktype = SOCK_DGRAM; + else + hints.ai_socktype = SOCK_STREAM; + + status = getaddrinfo(hostname, servname, &hints, res); if (status != 0) /* parse as numeric address failed? */ { const int fail_wait_interval = 5; /* seconds */ - int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : (resolve_retry_seconds / fail_wait_interval); + /* Add +4 to cause integer division rounding up (1 + 4) = 5, (0+4)/5=0 */ + int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : + ((resolve_retry_seconds + 4)/ fail_wait_interval); const char *fmt; int level = 0; - fmt = "RESOLVE: Cannot resolve host address: %s: %s"; + fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)"; if ((flags & GETADDR_MENTION_RESOLVE_RETRY) && !resolve_retry_seconds) - fmt = "RESOLVE: Cannot resolve host address: %s: %s (I would have retried this name query if you had specified the --resolv-retry option.)"; + fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s) (I would have retried this name query if you had specified the --resolv-retry option.)"; if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL) { - msg (msglevel, "RESOLVE: Cannot parse IP address: %s", hostname); + msg (msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)", + print_hostname,print_servname, gai_strerror(status)); goto done; } @@ -183,8 +364,10 @@ openvpn_getaddrinfo (unsigned int flags, management_set_state (management, OPENVPN_STATE_RESOLVE, NULL, - (in_addr_t)0, - (in_addr_t)0); + NULL, + NULL, + NULL, + NULL); } #endif @@ -193,14 +376,14 @@ openvpn_getaddrinfo (unsigned int flags, */ while (true) { -#ifndef WIN32 +#ifndef _WIN32 res_init (); #endif /* try hostname lookup */ - hints.ai_flags = 0; + hints.ai_flags &= ~AI_NUMERICHOST; dmsg (D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d", flags, hints.ai_family, hints.ai_socktype); - status = getaddrinfo(hostname, NULL, &hints, res); + status = getaddrinfo(hostname, servname, &hints, res); if (signal_received) { @@ -239,7 +422,8 @@ openvpn_getaddrinfo (unsigned int flags, msg (level, fmt, - hostname, + print_hostname, + print_servname, gai_strerror(status)); if (--resolve_retries <= 0) @@ -252,7 +436,8 @@ openvpn_getaddrinfo (unsigned int flags, /* hostname resolve succeeded */ - /* Do not chose an IP Addresse by random or change the order * + /* + * Do not choose an IP Addresse by random or change the order * * of IP addresses, doing so will break RFC 3484 address selection * */ } @@ -422,59 +607,6 @@ mac_addr_safe (const char *mac_addr) return true; } -static void -update_remote (const char* host, - struct openvpn_sockaddr *addr, - bool *changed, - const unsigned int sockflags) -{ - switch(addr->addr.sa.sa_family) - { - case AF_INET: - if (host && addr) - { - const in_addr_t new_addr = getaddr ( - sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags), - host, - 1, - NULL, - NULL); - if (new_addr && addr->addr.in4.sin_addr.s_addr != new_addr) - { - addr->addr.in4.sin_addr.s_addr = new_addr; - *changed = true; - } - } - break; - case AF_INET6: - if (host && addr) - { - int status; - struct addrinfo* ai; - - status = openvpn_getaddrinfo(sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags), host, 1, NULL, AF_INET6, &ai); - - if ( status ==0 ) - { - struct sockaddr_in6 sin6; - CLEAR(sin6); - sin6 = *((struct sockaddr_in6*)ai->ai_addr); - if (!IN6_ARE_ADDR_EQUAL(&sin6.sin6_addr, &addr->addr.in6.sin6_addr)) - { - int port = addr->addr.in6.sin6_port; - /* ipv6 requires also eg. sin6_scope_id => easier to fully copy and override port */ - addr->addr.in6 = sin6; - addr->addr.in6.sin6_port = port; - } - freeaddrinfo(ai); - } - } - break; - default: - ASSERT(0); - } -} - static int socket_get_sndbuf (int sd) { @@ -558,7 +690,7 @@ socket_set_buffers (int fd, const struct socket_buffer_size *sbs) static bool socket_set_tcp_nodelay (int sd, int state) { -#if defined(WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY)) +#if defined(_WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY)) if (setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (void *) &state, sizeof (state)) != 0) { msg (M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed", state); @@ -579,7 +711,7 @@ static inline void socket_set_mark (int sd, int mark) { #if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK - if (mark && setsockopt (sd, SOL_SOCKET, SO_MARK, &mark, sizeof (mark)) != 0) + if (mark && setsockopt (sd, SOL_SOCKET, SO_MARK, (void *) &mark, sizeof (mark)) != 0) msg (M_WARN, "NOTE: setsockopt SO_MARK=%d failed", mark); #endif } @@ -619,14 +751,17 @@ link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf) */ socket_descriptor_t -create_socket_tcp (int af) +create_socket_tcp (struct addrinfo* addrinfo) { socket_descriptor_t sd; - if ((sd = socket (af, SOCK_STREAM, IPPROTO_TCP)) < 0) + ASSERT (addrinfo); + ASSERT (addrinfo->ai_socktype == SOCK_STREAM); + + if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0) msg (M_ERR, "Cannot create TCP socket"); -#ifndef WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */ +#ifndef _WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */ /* set SO_REUSEADDR on socket */ { int on = 1; @@ -640,106 +775,134 @@ create_socket_tcp (int af) } static socket_descriptor_t -create_socket_udp (const unsigned int flags) +create_socket_udp (struct addrinfo* addrinfo, const unsigned int flags) { socket_descriptor_t sd; - if ((sd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) - msg (M_ERR, "UDP: Cannot create UDP socket"); + ASSERT (addrinfo); + ASSERT (addrinfo->ai_socktype == SOCK_DGRAM); + + if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0) + msg (M_ERR, "UDP: Cannot create UDP/UDP6 socket"); #if ENABLE_IP_PKTINFO else if (flags & SF_USE_IP_PKTINFO) { int pad = 1; -#ifdef IP_PKTINFO - if (setsockopt (sd, SOL_IP, IP_PKTINFO, - (void*)&pad, sizeof(pad)) < 0) - msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO"); + if(addrinfo->ai_family == AF_INET) + { +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) + if (setsockopt (sd, SOL_IP, IP_PKTINFO, + (void*)&pad, sizeof(pad)) < 0) + msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO"); #elif defined(IP_RECVDSTADDR) - if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR, - (void*)&pad, sizeof(pad)) < 0) - msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR"); + if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR, + (void*)&pad, sizeof(pad)) < 0) + msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR"); #else #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) #endif - } -#endif - return sd; -} - -static socket_descriptor_t -create_socket_udp6 (const unsigned int flags) -{ - socket_descriptor_t sd; - - if ((sd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) - msg (M_ERR, "UDP: Cannot create UDP6 socket"); -#if ENABLE_IP_PKTINFO - else if (flags & SF_USE_IP_PKTINFO) - { - int pad = 1; + } + else if (addrinfo->ai_family == AF_INET6 ) + { #ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */ - if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, - (void*)&pad, sizeof(pad)) < 0) + if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, + (void*)&pad, sizeof(pad)) < 0) #else - if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO, - (void*)&pad, sizeof(pad)) < 0) + if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + (void*)&pad, sizeof(pad)) < 0) #endif - msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO"); + msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO"); + } } #endif return sd; } +static void bind_local (struct link_socket *sock, const sa_family_t ai_family) +{ + /* bind to local address/port */ + if (sock->bind_local) + { + if (sock->socks_proxy && sock->info.proto == PROTO_UDP) + socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local, + ai_family, "SOCKS", false); + else + socket_bind (sock->sd, sock->info.lsa->bind_local, + ai_family, + "TCP/UDP", sock->info.bind_ipv6_only); + } +} + static void -create_socket (struct link_socket *sock) +create_socket (struct link_socket* sock, struct addrinfo* addr) { - /* create socket */ - if (sock->info.proto == PROTO_UDPv4) + if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM) { - sock->sd = create_socket_udp (sock->sockflags); + sock->sd = create_socket_udp (addr, sock->sockflags); sock->sockflags |= SF_GETADDRINFO_DGRAM; -#ifdef ENABLE_SOCKS + /* Assume that control socket and data socket to the socks proxy + * are using the same IP family */ if (sock->socks_proxy) - sock->ctrl_sd = create_socket_tcp (AF_INET); -#endif - } - else if (sock->info.proto == PROTO_TCPv4_SERVER - || sock->info.proto == PROTO_TCPv4_CLIENT) - { - sock->sd = create_socket_tcp (AF_INET); - } - else if (sock->info.proto == PROTO_TCPv6_SERVER - || sock->info.proto == PROTO_TCPv6_CLIENT) - { - sock->sd = create_socket_tcp (AF_INET6); + { + /* Construct a temporary addrinfo to create the socket, + * currently resolve two remote addresses is not supported, + * TODO: Rewrite the whole resolve_remote */ + struct addrinfo addrinfo_tmp = *addr; + addrinfo_tmp.ai_socktype = SOCK_STREAM; + addrinfo_tmp.ai_protocol = IPPROTO_TCP; + sock->ctrl_sd = create_socket_tcp (&addrinfo_tmp); + } } - else if (sock->info.proto == PROTO_UDPv6) + else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM) { - sock->sd = create_socket_udp6 (sock->sockflags); - sock->sockflags |= SF_GETADDRINFO_DGRAM; + sock->sd = create_socket_tcp (addr); } else { ASSERT (0); } + /* set socket buffers based on --sndbuf and --rcvbuf options */ + socket_set_buffers (sock->sd, &sock->socket_buffer_sizes); + + /* set socket to --mark packets with given value */ + socket_set_mark (sock->sd, sock->mark); + + bind_local (sock, addr->ai_family); +} + +#ifdef TARGET_ANDROID +static void protect_fd_nonlocal (int fd, const struct sockaddr* addr) +{ + /* pass socket FD to management interface to pass on to VPNService API + * as "protected socket" (exempt from being routed into tunnel) + */ + if (addr_local (addr)) { + msg(D_SOCKET_DEBUG, "Address is local, not protecting socket fd %d", fd); + return; + } + + msg(D_SOCKET_DEBUG, "Protecting socket fd %d", fd); + management->connection.fdtosend = fd; + management_android_control (management, "PROTECTFD", __func__); } +#endif /* * Functions used for establishing a TCP stream connection. */ - static void socket_do_listen (socket_descriptor_t sd, - const struct openvpn_sockaddr *local, + const struct addrinfo *local, bool do_listen, bool do_set_nonblock) { struct gc_arena gc = gc_new (); if (do_listen) { + ASSERT(local); msg (M_INFO, "Listening for incoming TCP connection on %s", - print_sockaddr (local, &gc)); + print_sockaddr (local->ai_addr, &gc)); if (listen (sd, 1)) msg (M_ERR, "TCP: listen() failed"); } @@ -821,8 +984,7 @@ static int socket_listen_accept (socket_descriptor_t sd, struct link_socket_actual *act, const char *remote_dynamic, - bool *remote_changed, - const struct openvpn_sockaddr *local, + const struct addrinfo *local, bool do_listen, bool nowait, volatile int *signal_received) @@ -868,18 +1030,26 @@ socket_listen_accept (socket_descriptor_t sd, if (socket_defined (new_sd)) { - update_remote (remote_dynamic, &remote_verify, remote_changed, 0); - if (addr_defined (&remote_verify) - && !addr_match (&remote_verify, &act->dest)) - { - msg (M_WARN, - "TCP NOTE: Rejected connection attempt from %s due to --remote setting", - print_link_socket_actual (act, &gc)); - if (openvpn_close_socket (new_sd)) - msg (M_ERR, "TCP: close socket failed (new_sd)"); - } + struct addrinfo* ai = NULL; + if(remote_dynamic) + openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL, + remote_verify.addr.sa.sa_family, &ai); + + if(ai && !addrlist_match(&remote_verify, ai)) + { + msg (M_WARN, + "TCP NOTE: Rejected connection attempt from %s due to --remote setting", + print_link_socket_actual (act, &gc)); + if (openvpn_close_socket (new_sd)) + msg (M_ERR, "TCP: close socket failed (new_sd)"); + freeaddrinfo(ai); + } else - break; + { + if(ai) + freeaddrinfo(ai); + break; + } } openvpn_sleep (1); } @@ -893,19 +1063,61 @@ socket_listen_accept (socket_descriptor_t sd, return new_sd; } +/* older mingw versions and WinXP do not have this define, + * but Vista and up support the functionality - just define it here + */ +#ifdef _WIN32 +# ifndef IPV6_V6ONLY +# define IPV6_V6ONLY 27 +# endif +#endif void socket_bind (socket_descriptor_t sd, - struct openvpn_sockaddr *local, - const char *prefix) + struct addrinfo *local, + int ai_family, + const char *prefix, + bool ipv6only) { struct gc_arena gc = gc_new (); - if (bind (sd, &local->addr.sa, af_addr_size(local->addr.sa.sa_family))) + /* FIXME (schwabe) + * getaddrinfo for the bind address might return multiple AF_INET/AF_INET6 + * entries for the requested protocol. + * For example if an address has multiple A records + * What is the correct way to deal with it? + */ + + struct addrinfo* cur; + + ASSERT(local); + + + /* find the first addrinfo with correct ai_family */ + for (cur = local; cur; cur=cur->ai_next) + { + if(cur->ai_family == ai_family) + break; + } + if (!cur) + msg (M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record", + prefix, addr_family_name(ai_family)); + + if (ai_family == AF_INET6) + { + int v6only = ipv6only ? 1: 0; /* setsockopt must have an "int" */ + + msg (M_INFO, "setsockopt(IPV6_V6ONLY=%d)", v6only); + if (setsockopt (sd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &v6only, sizeof(v6only))) + { + msg (M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY=%d failed", v6only); + } + } + if (bind (sd, cur->ai_addr, cur->ai_addrlen)) { const int errnum = openvpn_errno (); msg (M_FATAL, "%s: Socket bind failed on local address %s: %s", prefix, - print_sockaddr (local, &gc), + print_sockaddr_ex (local->ai_addr, ":", PS_SHOW_PORT, &gc), strerror_ts (errnum, &gc)); } gc_free (&gc); @@ -913,19 +1125,23 @@ socket_bind (socket_descriptor_t sd, int openvpn_connect (socket_descriptor_t sd, - struct openvpn_sockaddr *remote, + const struct sockaddr *remote, int connect_timeout, volatile int *signal_received) { int status = 0; +#ifdef TARGET_ANDROID + protect_fd_nonlocal(sd, remote); +#endif + #ifdef CONNECT_NONBLOCK set_nonblock (sd); - status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family)); + status = connect (sd, remote, af_addr_size(remote->sa_family)); if (status) status = openvpn_errno (); if ( -#ifdef WIN32 +#ifdef _WIN32 status == WSAEWOULDBLOCK #else status == EINPROGRESS @@ -968,7 +1184,7 @@ openvpn_connect (socket_descriptor_t sd, { if (--connect_timeout < 0) { -#ifdef WIN32 +#ifdef _WIN32 status = WSAETIMEDOUT; #else status = ETIMEDOUT; @@ -995,7 +1211,7 @@ openvpn_connect (socket_descriptor_t sd, } } #else - status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family)); + status = connect (sd, remote, af_addr_size(remote->sa_family)); if (status) status = openvpn_errno (); #endif @@ -1003,85 +1219,72 @@ openvpn_connect (socket_descriptor_t sd, return status; } +void set_actual_address (struct link_socket_actual* actual, struct addrinfo* ai) +{ + CLEAR (*actual); + ASSERT (ai); + + if (ai->ai_family == AF_INET) + actual->dest.addr.in4 = + *((struct sockaddr_in*) ai->ai_addr); + else if (ai->ai_family == AF_INET6) + actual->dest.addr.in6 = + *((struct sockaddr_in6*) ai->ai_addr); + else + ASSERT(0); + +} + void -socket_connect (socket_descriptor_t *sd, - struct openvpn_sockaddr *local, - bool bind_local, - struct openvpn_sockaddr *remote, - const bool connection_profiles_defined, - const char *remote_dynamic, - bool *remote_changed, - const int connect_retry_seconds, - const int connect_timeout, - const int connect_retry_max, - const unsigned int sockflags, - volatile int *signal_received) +socket_connect (socket_descriptor_t* sd, + const struct sockaddr* dest, + const int connect_timeout, + struct signal_info* sig_info) { struct gc_arena gc = gc_new (); - int retry = 0; + int status; #ifdef CONNECT_NONBLOCK - msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]", - print_sockaddr (remote, &gc)); + msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]", + print_sockaddr (dest, &gc)); #else - msg (M_INFO, "Attempting to establish TCP connection with %s", - print_sockaddr (remote, &gc)); + msg (M_INFO, "Attempting to establish TCP connection with %s", + print_sockaddr (dest, &gc)); #endif - while (true) - { - int status; - #ifdef ENABLE_MANAGEMENT - if (management) + if (management) management_set_state (management, OPENVPN_STATE_TCP_CONNECT, NULL, - (in_addr_t)0, - (in_addr_t)0); + NULL, + NULL, + NULL, + NULL); #endif - status = openvpn_connect (*sd, remote, connect_timeout, signal_received); + /* Set the actual address */ + status = openvpn_connect (*sd, dest, connect_timeout, &sig_info->signal_received); - get_signal (signal_received); - if (*signal_received) + get_signal (&sig_info->signal_received); + if (sig_info->signal_received) goto done; - if (!status) - break; + if (status) { - msg (D_LINK_ERRORS, - "TCP: connect to %s failed, will try again in %d seconds: %s", - print_sockaddr (remote, &gc), - connect_retry_seconds, - strerror_ts (status, &gc)); + msg (D_LINK_ERRORS, + "TCP: connect to %s failed: %s", + print_sockaddr (dest, &gc), + strerror_ts (status, &gc)); - gc_reset (&gc); - - openvpn_close_socket (*sd); - *sd = SOCKET_UNDEFINED; - - if ((connect_retry_max > 0 && ++retry >= connect_retry_max) || connection_profiles_defined) - { - *signal_received = SIGUSR1; - goto done; - } - - openvpn_sleep (connect_retry_seconds); - - get_signal (signal_received); - if (*signal_received) - goto done; - - *sd = create_socket_tcp (local->addr.sa.sa_family); - - if (bind_local) - socket_bind (*sd, local, "TCP Client"); - update_remote (remote_dynamic, remote, remote_changed, sockflags); - } - - msg (M_INFO, "TCP connection established with %s", - print_sockaddr (remote, &gc)); + openvpn_close_socket (*sd); + *sd = SOCKET_UNDEFINED; + sig_info->signal_received = SIGUSR1; + sig_info->source = SIG_SOURCE_CONNECTION_FAILED; + } else { + msg (M_INFO, "TCP connection established with %s", + print_sockaddr (dest, &gc)); + } done: gc_free (&gc); @@ -1093,7 +1296,7 @@ socket_connect (socket_descriptor_t *sd, static void socket_frame_init (const struct frame *frame, struct link_socket *sock) { -#ifdef WIN32 +#ifdef _WIN32 overlapped_io_init (&sock->reads, frame, FALSE, false); overlapped_io_init (&sock->writes, frame, TRUE, false); sock->rw_handle.read = sock->reads.overlapped.hEvent; @@ -1102,7 +1305,7 @@ socket_frame_init (const struct frame *frame, struct link_socket *sock) if (link_socket_connection_oriented (sock)) { -#ifdef WIN32 +#ifdef _WIN32 stream_buf_init (&sock->stream_buf, &sock->reads.buf_init, sock->sockflags, @@ -1132,70 +1335,39 @@ frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto) } static void -resolve_bind_local (struct link_socket *sock) +resolve_bind_local (struct link_socket *sock, const sa_family_t af) { struct gc_arena gc = gc_new (); /* resolve local address if undefined */ - if (!addr_defined (&sock->info.lsa->local)) - { - /* may return AF_{INET|INET6} guessed from local_host */ - switch(addr_guess_family(sock->info.proto, sock->local_host)) - { - case AF_INET: - sock->info.lsa->local.addr.in4.sin_family = AF_INET; - sock->info.lsa->local.addr.in4.sin_addr.s_addr = - (sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, - sock->local_host, - 0, - NULL, - NULL) - : htonl (INADDR_ANY)); - sock->info.lsa->local.addr.in4.sin_port = htons (sock->local_port); - break; - case AF_INET6: - { - int status; - CLEAR(sock->info.lsa->local.addr.in6); - if (sock->local_host) - { - struct addrinfo *ai; - - status = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, - sock->local_host, 0, NULL, AF_INET6, &ai); - if(status ==0) { - sock->info.lsa->local.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); - freeaddrinfo(ai); - } - } - else - { - sock->info.lsa->local.addr.in6.sin6_family = AF_INET6; - sock->info.lsa->local.addr.in6.sin6_addr = in6addr_any; - status = 0; - } - if (!status == 0) - { - msg (M_FATAL, "getaddr6() failed for local \"%s\": %s", - sock->local_host, - gai_strerror(status)); - } - sock->info.lsa->local.addr.in6.sin6_port = htons (sock->local_port); - } - break; - } - } - - /* bind to local address/port */ - if (sock->bind_local) + if (!sock->info.lsa->bind_local) { -#ifdef ENABLE_SOCKS - if (sock->socks_proxy && sock->info.proto == PROTO_UDPv4) - socket_bind (sock->ctrl_sd, &sock->info.lsa->local, "SOCKS"); - else -#endif - socket_bind (sock->sd, &sock->info.lsa->local, "TCP/UDP"); + int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | + GETADDR_FATAL | GETADDR_PASSIVE; + int status; + + if(proto_is_dgram(sock->info.proto)) + flags |= GETADDR_DATAGRAM; + + /* will return AF_{INET|INET6}from local_host */ + status = get_cached_dns_entry (sock->dns_cache, + sock->local_host, + sock->local_port, + af, + flags, + &sock->info.lsa->bind_local); + + if (status) + status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0, + NULL, af, &sock->info.lsa->bind_local); + + if(status !=0) { + msg (M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s", + sock->local_host, sock->local_port, + gai_strerror(status)); + } } + gc_free (&gc); } @@ -1206,132 +1378,113 @@ resolve_remote (struct link_socket *sock, volatile int *signal_received) { struct gc_arena gc = gc_new (); - int af; - if (!sock->did_resolve_remote) + /* resolve remote address if undefined */ + if (!sock->info.lsa->remote_list) { - /* resolve remote address if undefined */ - if (!addr_defined (&sock->info.lsa->remote)) + if (sock->remote_host) { - af = addr_guess_family(sock->info.proto, sock->remote_host); - switch(af) - { - case AF_INET: - sock->info.lsa->remote.addr.in4.sin_family = AF_INET; - sock->info.lsa->remote.addr.in4.sin_addr.s_addr = 0; - break; - case AF_INET6: - CLEAR(sock->info.lsa->remote.addr.in6); - sock->info.lsa->remote.addr.in6.sin6_family = AF_INET6; - sock->info.lsa->remote.addr.in6.sin6_addr = in6addr_any; - break; - } - - if (sock->remote_host) + unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags); + int retry = 0; + int status = -1; + struct addrinfo* ai; + if (proto_is_dgram(sock->info.proto)) + flags |= GETADDR_DATAGRAM; + + if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) { - unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags); - int retry = 0; - int status = -1; - struct addrinfo* ai; - - if (sock->connection_profiles_defined && sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) + if (phase == 2) + flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL); + retry = 0; + } + else if (phase == 1) + { + if (sock->resolve_retry_seconds) { - if (phase == 2) - flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL); retry = 0; } - else if (phase == 1) + else { - if (sock->resolve_retry_seconds) - { - retry = 0; - } - else - { - flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY); - retry = 0; - } + flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY); + retry = 0; } - else if (phase == 2) + } + else if (phase == 2) + { + if (sock->resolve_retry_seconds) { - if (sock->resolve_retry_seconds) - { - flags |= GETADDR_FATAL; - retry = sock->resolve_retry_seconds; - } - else - { - ASSERT (0); - } + flags |= GETADDR_FATAL; + retry = sock->resolve_retry_seconds; } else { ASSERT (0); } + } + else + { + ASSERT (0); + } - /* Temporary fix, this need to be changed for dual stack */ - status = openvpn_getaddrinfo(flags, sock->remote_host, retry, - signal_received, af, &ai); - if(status == 0) - { - if ( ai->ai_family == AF_INET6 ) - sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); - else - sock->info.lsa->remote.addr.in4 = *((struct sockaddr_in*)(ai->ai_addr)); - freeaddrinfo(ai); - - dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", - flags, - phase, - retry, - signal_received ? *signal_received : -1, - status); - } - if (signal_received) - { - if (*signal_received) - goto done; - } + + status = get_cached_dns_entry (sock->dns_cache, + sock->remote_host, + sock->remote_port, + sock->info.af, + flags, &ai); + if (status) + status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port, + retry, signal_received, sock->info.af, &ai); + + if(status == 0) { + sock->info.lsa->remote_list = ai; + sock->info.lsa->current_remote = ai; + + dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", + flags, + phase, + retry, + signal_received ? *signal_received : -1, + status); + } + if (signal_received) + { + if (*signal_received) + goto done; + } if (status!=0) { if (signal_received) *signal_received = SIGUSR1; goto done; } - } - switch(af) - { - case AF_INET: - sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port); - break; - case AF_INET6: - sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port); - break; - } } + } - /* should we re-use previous active remote address? */ - if (link_socket_actual_defined (&sock->info.lsa->actual)) - { - msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s", - print_link_socket_actual (&sock->info.lsa->actual, &gc)); - if (remote_dynamic) - *remote_dynamic = NULL; - } - else + /* should we re-use previous active remote address? */ + if (link_socket_actual_defined (&sock->info.lsa->actual)) + { + msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s", + print_link_socket_actual (&sock->info.lsa->actual, &gc)); + if (remote_dynamic) + *remote_dynamic = NULL; + } + else + { + CLEAR (sock->info.lsa->actual); + if(sock->info.lsa->current_remote) { - CLEAR (sock->info.lsa->actual); - sock->info.lsa->actual.dest = sock->info.lsa->remote; + set_actual_address (&sock->info.lsa->actual, + sock->info.lsa->current_remote); } - - /* remember that we finished */ - sock->did_resolve_remote = true; } done: gc_free (&gc); } + + struct link_socket * link_socket_new (void) { @@ -1339,29 +1492,24 @@ link_socket_new (void) ALLOC_OBJ_CLEAR (sock, struct link_socket); sock->sd = SOCKET_UNDEFINED; -#ifdef ENABLE_SOCKS sock->ctrl_sd = SOCKET_UNDEFINED; -#endif return sock; } -/* bind socket if necessary */ void link_socket_init_phase1 (struct link_socket *sock, - const bool connection_profiles_defined, const char *local_host, - int local_port, + const char *local_port, const char *remote_host, - int remote_port, + const char *remote_port, + struct cached_dns_entry *dns_cache, int proto, + sa_family_t af, + bool bind_ipv6_only, int mode, const struct link_socket *accept_from, -#ifdef ENABLE_HTTP_PROXY struct http_proxy_info *http_proxy, -#endif -#ifdef ENABLE_SOCKS struct socks_proxy_info *socks_proxy, -#endif #ifdef ENABLE_DEBUG int gremlin, #endif @@ -1372,38 +1520,25 @@ link_socket_init_phase1 (struct link_socket *sock, const char *ipchange_command, const struct plugin_list *plugins, int resolve_retry_seconds, - int connect_retry_seconds, - int connect_timeout, - int connect_retry_max, int mtu_discover_type, int rcvbuf, int sndbuf, int mark, + struct event_timeout* server_poll_timeout, unsigned int sockflags) { ASSERT (sock); - sock->connection_profiles_defined = connection_profiles_defined; - sock->local_host = local_host; sock->local_port = local_port; sock->remote_host = remote_host; sock->remote_port = remote_port; - -#ifdef ENABLE_HTTP_PROXY + sock->dns_cache = dns_cache; sock->http_proxy = http_proxy; -#endif - -#ifdef ENABLE_SOCKS sock->socks_proxy = socks_proxy; -#endif - sock->bind_local = bind_local; sock->inetd = inetd; sock->resolve_retry_seconds = resolve_retry_seconds; - sock->connect_retry_seconds = connect_retry_seconds; - sock->connect_timeout = connect_timeout; - sock->connect_retry_max = connect_retry_max; sock->mtu_discover_type = mtu_discover_type; #ifdef ENABLE_DEBUG @@ -1414,31 +1549,30 @@ link_socket_init_phase1 (struct link_socket *sock, sock->socket_buffer_sizes.sndbuf = sndbuf; sock->sockflags = sockflags; + sock->mark = mark; sock->info.proto = proto; + sock->info.af = af; sock->info.remote_float = remote_float; sock->info.lsa = lsa; + sock->info.bind_ipv6_only = bind_ipv6_only; sock->info.ipchange_command = ipchange_command; sock->info.plugins = plugins; + sock->server_poll_timeout = server_poll_timeout; sock->mode = mode; if (mode == LS_MODE_TCP_ACCEPT_FROM) { ASSERT (accept_from); - ASSERT (sock->info.proto == PROTO_TCPv4_SERVER - || sock->info.proto == PROTO_TCPv6_SERVER - ); + ASSERT (sock->info.proto == PROTO_TCP_SERVER); ASSERT (!sock->inetd); sock->sd = accept_from->sd; } - if (false) - ; -#ifdef ENABLE_HTTP_PROXY /* are we running in HTTP proxy mode? */ - else if (sock->http_proxy) + if (sock->http_proxy) { - ASSERT (sock->info.proto == PROTO_TCPv4_CLIENT); + ASSERT (sock->info.proto == PROTO_TCP_CLIENT); ASSERT (!sock->inetd); /* the proxy server */ @@ -1449,12 +1583,9 @@ link_socket_init_phase1 (struct link_socket *sock, sock->proxy_dest_host = remote_host; sock->proxy_dest_port = remote_port; } -#endif -#ifdef ENABLE_SOCKS /* or in Socks proxy mode? */ else if (sock->socks_proxy) { - ASSERT (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_UDPv4); ASSERT (!sock->inetd); /* the proxy server */ @@ -1465,7 +1596,6 @@ link_socket_init_phase1 (struct link_socket *sock, sock->proxy_dest_host = remote_host; sock->proxy_dest_port = remote_port; } -#endif else { sock->remote_host = remote_host; @@ -1473,7 +1603,7 @@ link_socket_init_phase1 (struct link_socket *sock, } /* bind behavior for TCP server vs. client */ - if (sock->info.proto == PROTO_TCPv4_SERVER) + if (sock->info.proto == PROTO_TCP_SERVER) { if (sock->mode == LS_MODE_TCP_ACCEPT_FROM) sock->bind_local = false; @@ -1484,43 +1614,255 @@ link_socket_init_phase1 (struct link_socket *sock, /* were we started by inetd or xinetd? */ if (sock->inetd) { - ASSERT (sock->info.proto != PROTO_TCPv4_CLIENT - && sock->info.proto != PROTO_TCPv6_CLIENT); + ASSERT (sock->info.proto != PROTO_TCP_CLIENT); ASSERT (socket_defined (inetd_socket_descriptor)); sock->sd = inetd_socket_descriptor; } else if (mode != LS_MODE_TCP_ACCEPT_FROM) { - create_socket (sock); + if (sock->bind_local) { + resolve_bind_local (sock, sock->info.af); + } + resolve_remote (sock, 1, NULL, NULL); + } +} - /* set socket buffers based on --sndbuf and --rcvbuf options */ - socket_set_buffers (sock->sd, &sock->socket_buffer_sizes); +static +void phase2_inetd (struct link_socket* sock, const struct frame *frame, + const char *remote_dynamic, volatile int *signal_received) +{ + bool remote_changed = false; - /* set socket to --mark packets with given value */ - socket_set_mark (sock->sd, mark); + if (sock->info.proto == PROTO_TCP_SERVER) { + /* AF_INET as default (and fallback) for inetd */ + sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET; +#ifdef HAVE_GETSOCKNAME + { + /* inetd: hint family type for dest = local's */ + struct openvpn_sockaddr local_addr; + socklen_t addrlen = sizeof(local_addr); + if (getsockname (sock->sd, &local_addr.addr.sa, &addrlen) == 0) { + sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family; + dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)", + proto2ascii(sock->info.proto, sock->info.af, false), + local_addr.addr.sa.sa_family, sock->sd); + } else + msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET", + proto2ascii(sock->info.proto, sock->info.af, false), sock->sd); + } +#else + msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() " + "function, using AF_INET", + proto2ascii(sock->info.proto, false)); +#endif + sock->sd = + socket_listen_accept (sock->sd, + &sock->info.lsa->actual, + remote_dynamic, + sock->info.lsa->bind_local, + false, + sock->inetd == INETD_NOWAIT, + signal_received); - resolve_bind_local (sock); - resolve_remote (sock, 1, NULL, NULL); + } + ASSERT (!remote_changed); +} + +static void +phase2_set_socket_flags (struct link_socket* sock) +{ + /* set misc socket parameters */ + socket_set_flags (sock->sd, sock->sockflags); + + /* set socket to non-blocking mode */ + set_nonblock (sock->sd); + + /* set socket file descriptor to not pass across execs, so that + scripts don't have access to it */ + set_cloexec (sock->sd); + + if (socket_defined (sock->ctrl_sd)) + set_cloexec (sock->ctrl_sd); + + /* set Path MTU discovery options on the socket */ + set_mtu_discover_type (sock->sd, sock->mtu_discover_type, sock->info.af); + +#if EXTENDED_SOCKET_ERROR_CAPABILITY + /* if the OS supports it, enable extended error passing on the socket */ + set_sock_extended_error_passing (sock->sd); +#endif +} + + +static void +linksock_print_addr (struct link_socket *sock) +{ + struct gc_arena gc = gc_new (); + const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO; + + /* print local address */ + if (sock->inetd) + msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true)); + else if (sock->bind_local) + { + sa_family_t ai_family = sock->info.lsa->actual.dest.addr.sa.sa_family; + /* Socket is always bound on the first matching address, + * For bound sockets with no remote addr this is the element of + * the list */ + struct addrinfo *cur; + for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next) + { + if(!ai_family || ai_family == cur->ai_family) + break; + } + ASSERT (cur); + msg (msglevel, "%s link local (bound): %s", + proto2ascii (sock->info.proto, sock->info.af, true), + print_sockaddr(cur->ai_addr,&gc)); } + else + msg (msglevel, "%s link local: (not bound)", + proto2ascii (sock->info.proto, sock->info.af, true)); + + /* print active remote address */ + msg (msglevel, "%s link remote: %s", + proto2ascii (sock->info.proto, sock->info.af, true), + print_link_socket_actual_ex (&sock->info.lsa->actual, + ":", + PS_SHOW_PORT_IF_DEFINED, + &gc)); + gc_free(&gc); +} + +static void +phase2_tcp_server (struct link_socket *sock, const char *remote_dynamic, + volatile int *signal_received) +{ + switch (sock->mode) + { + case LS_MODE_DEFAULT: + sock->sd = socket_listen_accept (sock->sd, + &sock->info.lsa->actual, + remote_dynamic, + sock->info.lsa->bind_local, + true, + false, + signal_received); + break; + case LS_MODE_TCP_LISTEN: + socket_do_listen (sock->sd, + sock->info.lsa->bind_local, + true, + false); + break; + case LS_MODE_TCP_ACCEPT_FROM: + sock->sd = socket_do_accept (sock->sd, + &sock->info.lsa->actual, + false); + if (!socket_defined (sock->sd)) + { + *signal_received = SIGTERM; + return; + } + tcp_connection_established (&sock->info.lsa->actual); + break; + default: + ASSERT (0); + } +} + + +static void +phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info) +{ + bool proxy_retry = false; + do { + socket_connect (&sock->sd, + sock->info.lsa->current_remote->ai_addr, + get_server_poll_remaining_time (sock->server_poll_timeout), + sig_info); + + if (sig_info->signal_received) + return; + + if (sock->http_proxy) + { + proxy_retry = establish_http_proxy_passthru (sock->http_proxy, + sock->sd, + sock->proxy_dest_host, + sock->proxy_dest_port, + sock->server_poll_timeout, + &sock->stream_buf.residual, + &sig_info->signal_received); + } + else if (sock->socks_proxy) + { + establish_socks_proxy_passthru (sock->socks_proxy, + sock->sd, + sock->proxy_dest_host, + sock->proxy_dest_port, + &sig_info->signal_received); + } + if (proxy_retry) + { + openvpn_close_socket (sock->sd); + sock->sd = create_socket_tcp (sock->info.lsa->current_remote); + } + + } while (proxy_retry); + +} + +static void +phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info) +{ + socket_connect (&sock->ctrl_sd, + sock->info.lsa->current_remote->ai_addr, + get_server_poll_remaining_time (sock->server_poll_timeout), + sig_info); + + if (sig_info->signal_received) + return; + + establish_socks_proxy_udpassoc (sock->socks_proxy, + sock->ctrl_sd, + sock->sd, + &sock->socks_relay.dest, + &sig_info->signal_received); + + if (sig_info->signal_received) + return; + + sock->remote_host = sock->proxy_dest_host; + sock->remote_port = sock->proxy_dest_port; + + addr_zero_host(&sock->info.lsa->actual.dest); + if (sock->info.lsa->remote_list) + { + freeaddrinfo(sock->info.lsa->remote_list); + sock->info.lsa->current_remote = NULL; + sock->info.lsa->remote_list = NULL; + } + + resolve_remote (sock, 1, NULL, &sig_info->signal_received); } /* finalize socket initialization */ void link_socket_init_phase2 (struct link_socket *sock, const struct frame *frame, - volatile int *signal_received) + struct signal_info *sig_info) { - struct gc_arena gc = gc_new (); const char *remote_dynamic = NULL; - bool remote_changed = false; int sig_save = 0; ASSERT (sock); + ASSERT (sig_info); - if (signal_received && *signal_received) + if (sig_info->signal_received) { - sig_save = *signal_received; - *signal_received = 0; + sig_save = sig_info->signal_received; + sig_info->signal_received = 0; } /* initialize buffers */ @@ -1537,246 +1879,83 @@ link_socket_init_phase2 (struct link_socket *sock, /* were we started by inetd or xinetd? */ if (sock->inetd) { - if (sock->info.proto == PROTO_TCPv4_SERVER - || sock->info.proto == PROTO_TCPv6_SERVER) { - /* AF_INET as default (and fallback) for inetd */ - sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET; -#ifdef HAVE_GETSOCKNAME - { - /* inetd: hint family type for dest = local's */ - struct openvpn_sockaddr local_addr; - socklen_t addrlen = sizeof(local_addr); - if (getsockname (sock->sd, (struct sockaddr *)&local_addr, &addrlen) == 0) { - sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family; - dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)", - proto2ascii(sock->info.proto, false), local_addr.addr.sa.sa_family, - sock->sd); - } else - msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET", - proto2ascii(sock->info.proto, false), sock->sd); - } -#else - msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() " - "function, using AF_INET", - proto2ascii(sock->info.proto, false)); -#endif - sock->sd = - socket_listen_accept (sock->sd, - &sock->info.lsa->actual, - remote_dynamic, - &remote_changed, - &sock->info.lsa->local, - false, - sock->inetd == INETD_NOWAIT, - signal_received); - } - ASSERT (!remote_changed); - if (*signal_received) + phase2_inetd (sock, frame, remote_dynamic, &sig_info->signal_received); + if (sig_info->signal_received) goto done; + } else { - resolve_remote (sock, 2, &remote_dynamic, signal_received); + /* Second chance to resolv/create socket */ + resolve_remote (sock, 2, &remote_dynamic, &sig_info->signal_received); - if (*signal_received) - goto done; + /* If a valid remote has been found, create the socket with its addrinfo */ + if (sock->info.lsa->current_remote) + create_socket (sock, sock->info.lsa->current_remote); - /* TCP client/server */ - if (sock->info.proto == PROTO_TCPv4_SERVER - ||sock->info.proto == PROTO_TCPv6_SERVER) + /* If socket has not already been created create it now */ + if (sock->sd == SOCKET_UNDEFINED) { - switch (sock->mode) + /* If we have no --remote and have still not figured out the + * protocol family to use we will use the first of the bind */ + + if (sock->bind_local && !sock->remote_host && sock->info.lsa->bind_local) { - case LS_MODE_DEFAULT: - sock->sd = socket_listen_accept (sock->sd, - &sock->info.lsa->actual, - remote_dynamic, - &remote_changed, - &sock->info.lsa->local, - true, - false, - signal_received); - break; - case LS_MODE_TCP_LISTEN: - socket_do_listen (sock->sd, - &sock->info.lsa->local, - true, - false); - break; - case LS_MODE_TCP_ACCEPT_FROM: - sock->sd = socket_do_accept (sock->sd, - &sock->info.lsa->actual, - false); - if (!socket_defined (sock->sd)) - { - *signal_received = SIGTERM; - goto done; + /* Warn if this is because neither v4 or v6 was specified + * and we should not connect a remote */ + if (sock->info.af == AF_UNSPEC) + { + msg (M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s", + addr_family_name(sock->info.lsa->bind_local->ai_family)); + sock->info.af = sock->info.lsa->bind_local->ai_family; } - tcp_connection_established (&sock->info.lsa->actual); - break; - default: - ASSERT (0); + + create_socket (sock, sock->info.lsa->bind_local); } } - else if (sock->info.proto == PROTO_TCPv4_CLIENT - ||sock->info.proto == PROTO_TCPv6_CLIENT) - { -#ifdef GENERAL_PROXY_SUPPORT - bool proxy_retry = false; -#else - const bool proxy_retry = false; -#endif - do { - socket_connect (&sock->sd, - &sock->info.lsa->local, - sock->bind_local, - &sock->info.lsa->actual.dest, - sock->connection_profiles_defined, - remote_dynamic, - &remote_changed, - sock->connect_retry_seconds, - sock->connect_timeout, - sock->connect_retry_max, - sock->sockflags, - signal_received); - - if (*signal_received) - goto done; - - if (false) - ; -#ifdef ENABLE_HTTP_PROXY - else if (sock->http_proxy) - { - proxy_retry = establish_http_proxy_passthru (sock->http_proxy, - sock->sd, - sock->proxy_dest_host, - sock->proxy_dest_port, - &sock->stream_buf.residual, - signal_received); - } -#endif -#ifdef ENABLE_SOCKS - else if (sock->socks_proxy) - { - establish_socks_proxy_passthru (sock->socks_proxy, - sock->sd, - sock->proxy_dest_host, - sock->proxy_dest_port, - signal_received); - } -#endif - if (proxy_retry) - { - openvpn_close_socket (sock->sd); - sock->sd = create_socket_tcp (AF_INET); - } - } while (proxy_retry); - } -#ifdef ENABLE_SOCKS - else if (sock->info.proto == PROTO_UDPv4 && sock->socks_proxy) + /* Socket still undefined, give a warning and abort connection */ + if (sock->sd == SOCKET_UNDEFINED) { - socket_connect (&sock->ctrl_sd, - &sock->info.lsa->local, - sock->bind_local, - &sock->info.lsa->actual.dest, - sock->connection_profiles_defined, - remote_dynamic, - &remote_changed, - sock->connect_retry_seconds, - sock->connect_timeout, - sock->connect_retry_max, - sock->sockflags, - signal_received); - - if (*signal_received) - goto done; - - establish_socks_proxy_udpassoc (sock->socks_proxy, - sock->ctrl_sd, - sock->sd, - &sock->socks_relay.dest, - signal_received); - - if (*signal_received) - goto done; - - sock->remote_host = sock->proxy_dest_host; - sock->remote_port = sock->proxy_dest_port; - sock->did_resolve_remote = false; - - addr_zero_host(&sock->info.lsa->actual.dest); - addr_zero_host(&sock->info.lsa->remote); - - resolve_remote (sock, 1, NULL, signal_received); - - if (*signal_received) - goto done; + msg (M_WARN, "Could not determine IPv4/IPv6 protocol"); + sig_info->signal_received = SIGUSR1; + goto done; } -#endif - if (*signal_received) + if (sig_info->signal_received) goto done; - if (remote_changed) + if (sock->info.proto == PROTO_TCP_SERVER) { - msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment"); - addr_copy_host(&sock->info.lsa->remote, &sock->info.lsa->actual.dest); + phase2_tcp_server (sock, remote_dynamic, + &sig_info->signal_received); } - } - - /* set misc socket parameters */ - socket_set_flags (sock->sd, sock->sockflags); - - /* set socket to non-blocking mode */ - set_nonblock (sock->sd); - - /* set socket file descriptor to not pass across execs, so that - scripts don't have access to it */ - set_cloexec (sock->sd); - -#ifdef ENABLE_SOCKS - if (socket_defined (sock->ctrl_sd)) - set_cloexec (sock->ctrl_sd); -#endif - - /* set Path MTU discovery options on the socket */ - set_mtu_discover_type (sock->sd, sock->mtu_discover_type); + else if (sock->info.proto == PROTO_TCP_CLIENT) + { + phase2_tcp_client (sock, sig_info); -#if EXTENDED_SOCKET_ERROR_CAPABILITY - /* if the OS supports it, enable extended error passing on the socket */ - set_sock_extended_error_passing (sock->sd); + } + else if (sock->info.proto == PROTO_UDP && sock->socks_proxy) + { + phase2_socks_client (sock, sig_info); + } +#ifdef TARGET_ANDROID + if (sock->sd != -1) + protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa); #endif + if (sig_info->signal_received) + goto done; + } - /* print local address */ - { - const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO; - - if (sock->inetd) - msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, true)); - else - msg (msglevel, "%s link local%s: %s", - proto2ascii (sock->info.proto, true), - (sock->bind_local ? " (bound)" : ""), - print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT : 0, &gc)); - - /* print active remote address */ - msg (msglevel, "%s link remote: %s", - proto2ascii (sock->info.proto, true), - print_link_socket_actual_ex (&sock->info.lsa->actual, - ":", - PS_SHOW_PORT_IF_DEFINED, - &gc)); - } + phase2_set_socket_flags(sock); + linksock_print_addr(sock); done: - if (sig_save && signal_received) + if (sig_save) { - if (!*signal_received) - *signal_received = sig_save; + if (!sig_info->signal_received) + sig_info->signal_received = sig_save; } - gc_free (&gc); } void @@ -1792,7 +1971,7 @@ link_socket_close (struct link_socket *sock) if (socket_defined (sock->sd)) { -#ifdef WIN32 +#ifdef _WIN32 close_net_event_win32 (&sock->listen_handle, sock->sd, 0); #endif if (!gremlin) @@ -1802,7 +1981,7 @@ link_socket_close (struct link_socket *sock) msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket failed"); } sock->sd = SOCKET_UNDEFINED; -#ifdef WIN32 +#ifdef _WIN32 if (!gremlin) { overlapped_io_close (&sock->reads); @@ -1811,14 +1990,12 @@ link_socket_close (struct link_socket *sock) #endif } -#ifdef ENABLE_SOCKS if (socket_defined (sock->ctrl_sd)) { if (openvpn_close_socket (sock->ctrl_sd)) msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket (ctrl_sd) failed"); sock->ctrl_sd = SOCKET_UNDEFINED; } -#endif stream_buf_close (&sock->stream_buf); free_buf (&sock->stream_buf_data); @@ -1844,17 +2021,15 @@ setenv_trusted (struct env_set *es, const struct link_socket_info *info) static void ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc) { - const char *ip = print_sockaddr_ex (&info->lsa->actual.dest, NULL, 0, gc); - const char *port = print_sockaddr_ex (&info->lsa->actual.dest, NULL, PS_DONT_SHOW_ADDR|PS_SHOW_PORT, gc); + const char *host = print_sockaddr_ex (&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT , gc); if (include_cmd) - argv_printf (argv, "%sc %s %s", - info->ipchange_command, - ip, - port); + { + argv_parse_cmd (argv, info->ipchange_command); + argv_printf_cat (argv, "%s", host); + } else - argv_printf (argv, "%s %s", - ip, - port); + argv_printf (argv, "%s", host); + } void @@ -1911,6 +2086,7 @@ link_socket_bad_incoming_addr (struct buffer *buf, const struct link_socket_actual *from_addr) { struct gc_arena gc = gc_new (); + struct addrinfo* ai; switch(from_addr->dest.addr.sa.sa_family) { @@ -1920,7 +2096,12 @@ link_socket_bad_incoming_addr (struct buffer *buf, "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)", print_link_socket_actual (from_addr, &gc), (int)from_addr->dest.addr.sa.sa_family, - print_sockaddr (&info->lsa->remote, &gc)); + print_sockaddr_ex (info->lsa->remote_list->ai_addr,":" ,PS_SHOW_PORT, &gc)); + /* print additional remote addresses */ + for(ai=info->lsa->remote_list->ai_next;ai;ai=ai->ai_next) { + msg(D_LINK_ERRORS,"or from peer address: %s", + print_sockaddr_ex(ai->ai_addr,":",PS_SHOW_PORT, &gc)); + } break; } buf->len = 0; @@ -1945,18 +2126,43 @@ link_socket_current_remote (const struct link_socket_info *info) * Maybe in the future consider PF_INET6 endpoints also ... * by now just ignore it * + * For --remote entries with multiple addresses this + * only return the actual endpoint we have sucessfully connected to */ if (lsa->actual.dest.addr.sa.sa_family != AF_INET) return IPV4_INVALID_ADDR; if (link_socket_actual_defined (&lsa->actual)) return ntohl (lsa->actual.dest.addr.in4.sin_addr.s_addr); - else if (addr_defined (&lsa->remote)) - return ntohl (lsa->remote.addr.in4.sin_addr.s_addr); + else if (lsa->current_remote) + return ntohl (((struct sockaddr_in*)lsa->current_remote->ai_addr) + ->sin_addr.s_addr); else return 0; } +const struct in6_addr * +link_socket_current_remote_ipv6 (const struct link_socket_info *info) +{ + const struct link_socket_addr *lsa = info->lsa; + +/* This logic supports "redirect-gateway" semantic, + * for PF_INET6 routes over PF_INET6 endpoints + * + * For --remote entries with multiple addresses this + * only return the actual endpoint we have sucessfully connected to + */ + if (lsa->actual.dest.addr.sa.sa_family != AF_INET6) + return NULL; + + if (link_socket_actual_defined (&lsa->actual)) + return &(lsa->actual.dest.addr.in6.sin6_addr); + else if (lsa->current_remote) + return &(((struct sockaddr_in6*)lsa->current_remote->ai_addr) ->sin6_addr); + else + return NULL; +} + /* * Return a status string describing socket state. */ @@ -1970,7 +2176,7 @@ socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena { buf_printf (&out, "S%s", (s->rwflags_debug & EVENT_READ) ? "R" : "r"); -#ifdef WIN32 +#ifdef _WIN32 buf_printf (&out, "%s", overlapped_io_state_ascii (&s->reads)); #endif @@ -1979,7 +2185,7 @@ socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena { buf_printf (&out, "S%s", (s->rwflags_debug & EVENT_WRITE) ? "W" : "w"); -#ifdef WIN32 +#ifdef _WIN32 buf_printf (&out, "%s", overlapped_io_state_ascii (&s->writes)); #endif @@ -2019,7 +2225,7 @@ stream_buf_init (struct stream_buf *sb, sb->residual = alloc_buf (sb->maxlen); sb->error = false; #if PORT_SHARE - sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCPv4_SERVER)) + sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCP_SERVER)) ? PS_ENABLED : PS_DISABLED; #endif @@ -2154,7 +2360,7 @@ stream_buf_close (struct stream_buf* sb) event_t socket_listen_event_handle (struct link_socket *s) { -#ifdef WIN32 +#ifdef _WIN32 if (!defined_net_event_win32 (&s->listen_handle)) init_net_event_win32 (&s->listen_handle, FD_ACCEPT, s->sd, 0); return &s->listen_handle; @@ -2168,67 +2374,65 @@ socket_listen_event_handle (struct link_socket *s) */ const char * -print_sockaddr (const struct openvpn_sockaddr *addr, struct gc_arena *gc) -{ - return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc); -} - -const char * -print_sockaddr_ex (const struct openvpn_sockaddr *addr, - const char* separator, - const unsigned int flags, - struct gc_arena *gc) +print_sockaddr_ex (const struct sockaddr *sa, + const char* separator, + const unsigned int flags, + struct gc_arena *gc) { struct buffer out = alloc_buf_gc (128, gc); - bool addr_is_defined; - addr_is_defined = addr_defined (addr); - if (!addr_is_defined) { - return "[undef]"; - } - switch(addr->addr.sa.sa_family) + bool addr_is_defined = false; + char hostaddr[NI_MAXHOST] = ""; + char servname[NI_MAXSERV] = ""; + int status; + + socklen_t salen = 0; + switch(sa->sa_family) { case AF_INET: - { - const int port= ntohs (addr->addr.in4.sin_port); - buf_puts (&out, "[AF_INET]"); - - if (!(flags & PS_DONT_SHOW_ADDR)) - buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->addr.in4.sin_addr) : "[undef]")); - - if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED))) - && port) - { - if (separator) - buf_printf (&out, "%s", separator); - - buf_printf (&out, "%d", port); - } - } + if (!(flags & PS_DONT_SHOW_FAMILY)) + buf_puts (&out, "[AF_INET]"); + salen = sizeof (struct sockaddr_in); + addr_is_defined = ((struct sockaddr_in*) sa)->sin_addr.s_addr != 0; break; case AF_INET6: - { - const int port= ntohs (addr->addr.in6.sin6_port); - char buf[INET6_ADDRSTRLEN] = ""; - buf_puts (&out, "[AF_INET6]"); - if (addr_is_defined) - { - getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), - buf, sizeof (buf), NULL, 0, NI_NUMERICHOST); - buf_puts (&out, buf); - } - if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED))) - && port) - { - if (separator) - buf_puts (&out, separator); - - buf_printf (&out, "%d", port); - } - } + if (!(flags & PS_DONT_SHOW_FAMILY)) + buf_puts (&out, "[AF_INET6]"); + salen = sizeof (struct sockaddr_in6); + addr_is_defined = !IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6*) sa)->sin6_addr); break; + case AF_UNSPEC: + if (!(flags & PS_DONT_SHOW_FAMILY)) + return "[AF_UNSPEC]"; + else + return ""; default: ASSERT(0); } + + status = getnameinfo(sa, salen, hostaddr, sizeof (hostaddr), + servname, sizeof(servname), NI_NUMERICHOST | NI_NUMERICSERV); + + if(status!=0) { + buf_printf(&out,"[nameinfo() err: %s]",gai_strerror(status)); + return BSTR(&out); + } + + if (!(flags & PS_DONT_SHOW_ADDR)) + { + if (addr_is_defined) + buf_puts (&out, hostaddr); + else + buf_puts (&out, "[undef]"); + } + + if ((flags & PS_SHOW_PORT) || (flags & PS_SHOW_PORT_IF_DEFINED)) + { + if (separator) + buf_puts (&out, separator); + + buf_puts (&out, servname); + } + return BSTR (&out); } @@ -2252,7 +2456,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, { char ifname[IF_NAMESIZE] = "[undef]"; struct buffer out = alloc_buf_gc (128, gc); - buf_printf (&out, "%s", print_sockaddr_ex (&act->dest, separator, flags, gc)); + buf_printf (&out, "%s", print_sockaddr_ex (&act->dest.addr.sa, separator, flags, gc)); #if ENABLE_IP_PKTINFO if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act)) { @@ -2263,7 +2467,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, struct openvpn_sockaddr sa; CLEAR (sa); sa.addr.in4.sin_family = AF_INET; -#ifdef IP_PKTINFO +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst; if_indextoname(act->pi.in4.ipi_ifindex, ifname); #elif defined(IP_RECVDSTADDR) @@ -2273,7 +2477,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) #endif buf_printf (&out, " (via %s%%%s)", - print_sockaddr_ex (&sa, separator, 0, gc), + print_sockaddr_ex (&sa.addr.sa, separator, 0, gc), ifname); } break; @@ -2392,9 +2596,20 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openv } break; case AF_INET6: - openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix); - getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), - buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); + if ( IN6_IS_ADDR_V4MAPPED( &addr->addr.in6.sin6_addr )) + { + struct in_addr ia; + memcpy (&ia.s_addr, &addr->addr.in6.sin6_addr.s6_addr[12], + sizeof (ia.s_addr)); + openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix); + openvpn_snprintf (buf, sizeof(buf), "%s", inet_ntoa(ia) ); + } + else + { + openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix); + getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), + buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); + } setenv_str (es, name_buf, buf); if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port) @@ -2451,22 +2666,28 @@ setenv_link_socket_actual (struct env_set *es, struct proto_names { const char *short_form; const char *display_form; - bool is_dgram; - bool is_net; - unsigned short proto_af; + sa_family_t proto_af; + int proto; }; /* Indexed by PROTO_x */ -static const struct proto_names proto_names[PROTO_N] = { - {"proto-uninitialized", "proto-NONE",0,0, AF_UNSPEC}, - {"udp", "UDPv4",1,1, AF_INET}, - {"tcp-server", "TCPv4_SERVER",0,1, AF_INET}, - {"tcp-client", "TCPv4_CLIENT",0,1, AF_INET}, - {"tcp", "TCPv4",0,1, AF_INET}, - {"udp6" ,"UDPv6",1,1, AF_INET6}, - {"tcp6-server","TCPv6_SERVER",0,1, AF_INET6}, - {"tcp6-client","TCPv6_CLIENT",0,1, AF_INET6}, - {"tcp6" ,"TCPv6",0,1, AF_INET6}, +static const struct proto_names proto_names[] = { + {"proto-uninitialized", "proto-NONE", AF_UNSPEC, PROTO_NONE}, + /* try IPv4 and IPv6 (client), bind dual-stack (server) */ + {"udp", "UDP", AF_UNSPEC, PROTO_UDP}, + {"tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER}, + {"tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT}, + {"tcp", "TCP", AF_UNSPEC, PROTO_TCP}, + /* force IPv4 */ + {"udp4", "UDPv4", AF_INET, PROTO_UDP}, + {"tcp4-server","TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER}, + {"tcp4-client","TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT}, + {"tcp4", "TCPv4", AF_INET, PROTO_TCP}, + /* force IPv6 */ + {"udp6" ,"UDPv6", AF_INET6, PROTO_UDP}, + {"tcp6-server","TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER}, + {"tcp6-client","TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT}, + {"tcp6" ,"TCPv6", AF_INET6, PROTO_TCP}, }; bool @@ -2474,59 +2695,66 @@ proto_is_net(int proto) { if (proto < 0 || proto >= PROTO_N) ASSERT(0); - return proto_names[proto].is_net; + return proto != PROTO_NONE; } bool proto_is_dgram(int proto) { - if (proto < 0 || proto >= PROTO_N) - ASSERT(0); - return proto_names[proto].is_dgram; + return proto_is_udp(proto); } + bool proto_is_udp(int proto) { if (proto < 0 || proto >= PROTO_N) ASSERT(0); - return proto_names[proto].is_dgram&&proto_names[proto].is_net; + return proto == PROTO_UDP; } + bool proto_is_tcp(int proto) { if (proto < 0 || proto >= PROTO_N) ASSERT(0); - return (!proto_names[proto].is_dgram)&&proto_names[proto].is_net; -} - -unsigned short -proto_sa_family(int proto) -{ - if (proto < 0 || proto >= PROTO_N) - ASSERT(0); - return proto_names[proto].proto_af; + return proto == PROTO_TCP_CLIENT || proto == PROTO_TCP_SERVER; } int ascii2proto (const char* proto_name) { int i; - ASSERT (PROTO_N == SIZE (proto_names)); - for (i = 0; i < PROTO_N; ++i) + for (i = 0; i < SIZE (proto_names); ++i) if (!strcmp (proto_name, proto_names[i].short_form)) - return i; + return proto_names[i].proto; return -1; } +sa_family_t +ascii2af (const char* proto_name) +{ + int i; + for (i = 0; i < SIZE (proto_names); ++i) + if (!strcmp (proto_name, proto_names[i].short_form)) + return proto_names[i].proto_af; + return 0; +} + const char * -proto2ascii (int proto, bool display_form) +proto2ascii (int proto, sa_family_t af, bool display_form) { - ASSERT (PROTO_N == SIZE (proto_names)); - if (proto < 0 || proto >= PROTO_N) - return "[unknown protocol]"; - else if (display_form) - return proto_names[proto].display_form; - else - return proto_names[proto].short_form; + unsigned int i; + for (i = 0; i < SIZE (proto_names); ++i) + { + if(proto_names[i].proto_af == af && proto_names[i].proto == proto) + { + if(display_form) + return proto_names[i].display_form; + else + return proto_names[i].short_form; + } + } + + return "[unknown protocol]"; } const char * @@ -2535,40 +2763,15 @@ proto2ascii_all (struct gc_arena *gc) struct buffer out = alloc_buf_gc (256, gc); int i; - ASSERT (PROTO_N == SIZE (proto_names)); - for (i = 0; i < PROTO_N; ++i) + for (i = 0; i < SIZE (proto_names); ++i) { if (i) buf_printf(&out, " "); - buf_printf(&out, "[%s]", proto2ascii(i, false)); + buf_printf(&out, "[%s]", proto_names[i].short_form); } return BSTR (&out); } -int -addr_guess_family(int proto, const char *name) -{ - unsigned short ret; - if (proto) - { - return proto_sa_family(proto); /* already stamped */ - } - else - { - struct addrinfo hints , *ai; - int err; - CLEAR(hints); - hints.ai_flags = AI_NUMERICHOST; - err = getaddrinfo(name, NULL, &hints, &ai); - if ( 0 == err ) - { - ret=ai->ai_family; - freeaddrinfo(ai); - return ret; - } - } - return AF_INET; /* default */ -} const char * addr_family_name (int af) { @@ -2592,31 +2795,22 @@ addr_family_name (int af) * has always sent UDPv4, TCPv4 over the wire. Keep these * strings for backward compatbility */ -int +const char* proto_remote (int proto, bool remote) { ASSERT (proto >= 0 && proto < PROTO_N); - if (remote) - { - switch (proto) - { - case PROTO_TCPv4_SERVER: return PROTO_TCPv4_CLIENT; - case PROTO_TCPv4_CLIENT: return PROTO_TCPv4_SERVER; - case PROTO_TCPv6_SERVER: return PROTO_TCPv4_CLIENT; - case PROTO_TCPv6_CLIENT: return PROTO_TCPv4_SERVER; - case PROTO_UDPv6: return PROTO_UDPv4; - } - } - else - { - switch (proto) - { - case PROTO_TCPv6_SERVER: return PROTO_TCPv4_SERVER; - case PROTO_TCPv6_CLIENT: return PROTO_TCPv4_CLIENT; - case PROTO_UDPv6: return PROTO_UDPv4; - } - } - return proto; + if (proto == PROTO_UDP) + return "UDPv4"; + + if ( (remote && proto == PROTO_TCP_CLIENT) || + (!remote && proto == PROTO_TCP_SERVER)) + return "TCPv4_SERVER"; + if ( (remote && proto == PROTO_TCP_SERVER) || + (!remote && proto == PROTO_TCP_CLIENT)) + return "TCPv4_CLIENT"; + + ASSERT (0); + return ""; /* Make the compiler happy */ } /* @@ -2643,7 +2837,7 @@ link_socket_read_tcp (struct link_socket *sock, if (!sock->stream_buf.residual_fully_formed) { -#ifdef WIN32 +#ifdef _WIN32 len = socket_finalize (sock->sd, &sock->reads, buf, NULL); #else struct buffer frag; @@ -2668,51 +2862,39 @@ link_socket_read_tcp (struct link_socket *sock, return buf->len = 0; /* no error, but packet is still incomplete */ } -#ifndef WIN32 +#ifndef _WIN32 #if ENABLE_IP_PKTINFO -#pragma pack(1) /* needed to keep structure size consistent for 32 vs. 64-bit architectures */ -struct openvpn_in4_pktinfo -{ - struct cmsghdr cmsghdr; -#ifdef HAVE_IN_PKTINFO - struct in_pktinfo pi4; -#elif defined(IP_RECVDSTADDR) - struct in_addr pi4; +/* make the buffer large enough to handle ancilliary socket data for + * both IPv4 and IPv6 destination addresses, plus padding (see RFC 2292) + */ +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) +#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \ + CMSG_SPACE(sizeof (struct in_pktinfo)) ) +#else +#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \ + CMSG_SPACE(sizeof (struct in_addr)) ) #endif -}; -struct openvpn_in6_pktinfo -{ - struct cmsghdr cmsghdr; - struct in6_pktinfo pi6; -}; - -union openvpn_pktinfo { - struct openvpn_in4_pktinfo msgpi4; - struct openvpn_in6_pktinfo msgpi6; -}; -#pragma pack() static socklen_t link_socket_read_udp_posix_recvmsg (struct link_socket *sock, struct buffer *buf, - int maxsize, struct link_socket_actual *from) { struct iovec iov; - union openvpn_pktinfo opi; + uint8_t pktinfo_buf[PKTINFO_BUF_SIZE]; struct msghdr mesg; socklen_t fromlen = sizeof (from->dest.addr); iov.iov_base = BPTR (buf); - iov.iov_len = maxsize; + iov.iov_len = buf_forward_capacity_total (buf); mesg.msg_iov = &iov; mesg.msg_iovlen = 1; mesg.msg_name = &from->dest.addr; mesg.msg_namelen = fromlen; - mesg.msg_control = &opi; - mesg.msg_controllen = sizeof opi; + mesg.msg_control = pktinfo_buf; + mesg.msg_controllen = sizeof pktinfo_buf; buf->len = recvmsg (sock->sd, &mesg, 0); if (buf->len >= 0) { @@ -2721,18 +2903,19 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, cmsg = CMSG_FIRSTHDR (&mesg); if (cmsg != NULL && CMSG_NXTHDR (&mesg, cmsg) == NULL -#ifdef IP_PKTINFO +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) && cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO + && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_pktinfo)) ) #elif defined(IP_RECVDSTADDR) && cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR + && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_addr)) ) #else #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) #endif - && cmsg->cmsg_len >= sizeof (struct openvpn_in4_pktinfo)) { -#ifdef IP_PKTINFO +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); from->pi.in4.ipi_ifindex = pkti->ipi_ifindex; from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst; @@ -2746,13 +2929,18 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, && CMSG_NXTHDR (&mesg, cmsg) == NULL && cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO - && cmsg->cmsg_len >= sizeof (struct openvpn_in6_pktinfo)) + && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in6_pktinfo)) ) { struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg); from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex; from->pi.in6.ipi6_addr = pkti6->ipi6_addr; } + else if (cmsg != NULL) + { + msg(M_WARN, "CMSG received that cannot be parsed (cmsg_level=%d, cmsg_type=%d, cmsg=len=%d)", (int)cmsg->cmsg_level, (int)cmsg->cmsg_type, (int)cmsg->cmsg_len ); + } } + return fromlen; } #endif @@ -2760,21 +2948,20 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, int link_socket_read_udp_posix (struct link_socket *sock, struct buffer *buf, - int maxsize, struct link_socket_actual *from) { socklen_t fromlen = sizeof (from->dest.addr); - socklen_t expectedlen = af_addr_size(proto_sa_family(sock->info.proto)); + socklen_t expectedlen = af_addr_size(sock->info.af); addr_zero_host(&from->dest); - ASSERT (buf_safe (buf, maxsize)); #if ENABLE_IP_PKTINFO /* Both PROTO_UDPv4 and PROTO_UDPv6 */ - if (proto_is_udp(sock->info.proto) && sock->sockflags & SF_USE_IP_PKTINFO) - fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from); + if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO) + fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, from); else #endif - buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0, + buf->len = recvfrom (sock->sd, BPTR (buf), buf_forward_capacity(buf), 0, &from->dest.addr.sa, &fromlen); + /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */ if (buf->len >= 0 && expectedlen && fromlen != expectedlen) bad_address_length (fromlen, expectedlen); return buf->len; @@ -2796,7 +2983,7 @@ link_socket_write_tcp (struct link_socket *sock, ASSERT (len <= sock->stream_buf.maxlen); len = htonps (len); ASSERT (buf_write_prepend (buf, &len, sizeof (len))); -#ifdef WIN32 +#ifdef _WIN32 return link_socket_write_win32 (sock, buf, to); #else return link_socket_write_tcp_posix (sock, buf, to); @@ -2805,7 +2992,7 @@ link_socket_write_tcp (struct link_socket *sock, #if ENABLE_IP_PKTINFO -int +size_t link_socket_write_udp_posix_sendmsg (struct link_socket *sock, struct buffer *buf, struct link_socket_actual *to) @@ -2813,24 +3000,24 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, struct iovec iov; struct msghdr mesg; struct cmsghdr *cmsg; - union openvpn_pktinfo opi; + uint8_t pktinfo_buf[PKTINFO_BUF_SIZE]; iov.iov_base = BPTR (buf); iov.iov_len = BLEN (buf); mesg.msg_iov = &iov; mesg.msg_iovlen = 1; - switch (sock->info.lsa->remote.addr.sa.sa_family) + switch (to->dest.addr.sa.sa_family) { case AF_INET: { mesg.msg_name = &to->dest.addr.sa; mesg.msg_namelen = sizeof (struct sockaddr_in); - mesg.msg_control = &opi; + mesg.msg_control = pktinfo_buf; mesg.msg_flags = 0; -#ifdef HAVE_IN_PKTINFO - mesg.msg_controllen = sizeof (struct openvpn_in4_pktinfo); +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) + mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_pktinfo)); cmsg = CMSG_FIRSTHDR (&mesg); - cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo); + cmsg->cmsg_len = CMSG_LEN(sizeof (struct in_pktinfo)); cmsg->cmsg_level = SOL_IP; cmsg->cmsg_type = IP_PKTINFO; { @@ -2841,7 +3028,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, pkti->ipi_addr.s_addr = 0; } #elif defined(IP_RECVDSTADDR) - ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(opi) ); + ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(pktinfo_buf) ); mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_addr)); cmsg = CMSG_FIRSTHDR (&mesg); cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); @@ -2858,13 +3045,16 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, struct in6_pktinfo *pkti6; mesg.msg_name = &to->dest.addr.sa; mesg.msg_namelen = sizeof (struct sockaddr_in6); - mesg.msg_control = &opi; - mesg.msg_controllen = sizeof (struct openvpn_in6_pktinfo); + + ASSERT( CMSG_SPACE(sizeof (struct in6_pktinfo)) <= sizeof(pktinfo_buf) ); + mesg.msg_control = pktinfo_buf; + mesg.msg_controllen = CMSG_SPACE(sizeof (struct in6_pktinfo)); mesg.msg_flags = 0; cmsg = CMSG_FIRSTHDR (&mesg); - cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo); + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; + pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg); pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex; pkti6->ipi6_addr = to->pi.in6.ipi6_addr; @@ -2881,7 +3071,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, * Win32 overlapped socket I/O functions. */ -#ifdef WIN32 +#ifdef _WIN32 int socket_recv_queue (struct link_socket *sock, int maxsize) @@ -2919,10 +3109,7 @@ socket_recv_queue (struct link_socket *sock, int maxsize) if (proto_is_udp(sock->info.proto)) { sock->reads.addr_defined = true; - if (sock->info.proto == PROTO_UDPv6) - sock->reads.addrlen = sizeof (sock->reads.addr6); - else - sock->reads.addrlen = sizeof (sock->reads.addr); + sock->reads.addrlen = sizeof (sock->reads.addr6); status = WSARecvFrom( sock->sd, wsabuf, @@ -2954,9 +3141,10 @@ socket_recv_queue (struct link_socket *sock, int maxsize) if (!status) /* operation completed immediately? */ { - int addrlen = af_addr_size(sock->info.lsa->local.addr.sa.sa_family); - if (sock->reads.addr_defined && sock->reads.addrlen != addrlen) - bad_address_length (sock->reads.addrlen, addrlen); + /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */ + int af_len = af_addr_size (sock->info.af); + if (sock->reads.addr_defined && af_len && sock->reads.addrlen != af_len) + bad_address_length (sock->reads.addrlen, af_len); sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN; /* since we got an immediate return, we must signal the event object ourselves */ @@ -3018,7 +3206,7 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct li { /* set destination address for UDP writes */ sock->writes.addr_defined = true; - if (sock->info.proto == PROTO_UDPv6) + if (to->dest.addr.sa.sa_family == AF_INET6) { sock->writes.addr6 = to->dest.addr.in6; sock->writes.addrlen = sizeof (sock->writes.addr6); @@ -3191,7 +3379,7 @@ socket_finalize (SOCKET s, case sizeof(struct sockaddr_in): case sizeof(struct sockaddr_in6): /* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6 - * under WIN32*/ + * under _WIN32*/ case sizeof(struct sockaddr_in6)-4: break; default: @@ -3217,7 +3405,7 @@ socket_finalize (SOCKET s, return ret; } -#endif /* WIN32 */ +#endif /* _WIN32 */ /* * Socket event notification @@ -3238,7 +3426,7 @@ socket_set (struct link_socket *s, rwflags &= ~EVENT_READ; } -#ifdef WIN32 +#ifdef _WIN32 if (rwflags & EVENT_READ) socket_recv_queue (s, 0); #endif |