src/openvpn/socket.c
6fbf66fa
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single TCP/UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
6fbf66fa
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
caa54ac3
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
6fbf66fa
  */
 
c110b289
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
6fbf66fa
 #include "syshead.h"
 
 #include "socket.h"
 #include "fdmisc.h"
 #include "misc.h"
 #include "gremlin.h"
 #include "plugin.h"
6add6b2f
 #include "ps.h"
bf97c00f
 #include "run_command.h"
e482a632
 #include "manage.h"
8e9666d5
 #include "misc.h"
a55b3cdb
 #include "manage.h"
e719a053
 #include "openvpn.h"
f2134b7b
 #include "forward.h"
6fbf66fa
 
 #include "memdbg.h"
 
1406db55
 const int proto_overhead[] = { /* indexed by PROTO_x */
81d882d5
     0,
     IPv4_UDP_HEADER_SIZE, /* IPv4 */
     IPv4_TCP_HEADER_SIZE,
     IPv4_TCP_HEADER_SIZE,
     IPv6_UDP_HEADER_SIZE, /* IPv6 */
     IPv6_TCP_HEADER_SIZE,
     IPv6_TCP_HEADER_SIZE,
     IPv6_TCP_HEADER_SIZE,
1406db55
 };
 
6fbf66fa
 /*
8e9666d5
  * Convert sockflags/getaddr_flags into getaddr_flags
  */
 static unsigned int
86093c1c
 sf2gaf(const unsigned int getaddr_flags,
8e9666d5
        const unsigned int sockflags)
 {
81d882d5
     if (sockflags & SF_HOST_RANDOMIZE)
     {
         return getaddr_flags | GETADDR_RANDOMIZE;
     }
     else
     {
         return getaddr_flags;
     }
8e9666d5
 }
 
 /*
6fbf66fa
  * Functions related to the translation of DNS names to IP addresses.
  */
 
 /*
  * Translate IP addr or hostname to in_addr_t.
  * If resolve error, try again for
  * resolve_retry_seconds seconds.
  */
 in_addr_t
81d882d5
 getaddr(unsigned int flags,
         const char *hostname,
         int resolve_retry_seconds,
         bool *succeeded,
         volatile int *signal_received)
 {
     struct addrinfo *ai;
     int status;
     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)
         {
             *succeeded = true;
         }
         ia = ((struct sockaddr_in *)ai->ai_addr)->sin_addr;
         freeaddrinfo(ai);
         return (flags & GETADDR_HOST_ORDER) ? ntohl(ia.s_addr) : ia.s_addr;
     }
     else
     {
         if (succeeded)
         {
             *succeeded = false;
         }
         return 0;
     }
6fbf66fa
 }
 
e719a053
 static inline bool
81d882d5
 streqnull(const char *a, const char *b)
e719a053
 {
81d882d5
     if (a == NULL && b == NULL)
     {
         return true;
     }
     else if (a == NULL || b == NULL)
     {
         return false;
     }
     else
     {
         return streq(a, b);
     }
e719a053
 }
 
 /*
81d882d5
  * get_cached_dns_entry return 0 on success and -1
  * otherwise. (like getaddrinfo)
e719a053
  */
 static int
81d882d5
 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)
e719a053
 {
81d882d5
     struct cached_dns_entry *ph;
     int flags;
e719a053
 
81d882d5
     /* Only use flags that are relevant for the structure */
     flags = resolve_flags & GETADDR_CACHE_MASK;
e719a053
 
81d882d5
     for (ph = dns_cache; ph; ph = ph->next)
e719a053
     {
81d882d5
         if (streqnull(ph->hostname, hostname)
             && streqnull(ph->servname, servname)
             && ph->ai_family == ai_family
             && ph->flags == flags)
         {
             *ai = ph->ai;
             return 0;
         }
e719a053
     }
81d882d5
     return -1;
e719a053
 }
 
 
 static int
81d882d5
 do_preresolve_host(struct context *c,
                    const char *hostname,
                    const char *servname,
                    const int af,
                    const int flags)
e719a053
 {
81d882d5
     struct addrinfo *ai;
     int status;
e719a053
 
81d882d5
     if (get_cached_dns_entry(c->c1.dns_cache,
                              hostname,
                              servname,
                              af,
                              flags,
                              &ai) == 0)
e719a053
     {
81d882d5
         /* entry already cached, return success */
         return 0;
e719a053
     }
 
81d882d5
     status = openvpn_getaddrinfo(flags, hostname, servname,
                                  c->options.resolve_retry_seconds, NULL,
                                  af, &ai);
     if (status == 0)
e719a053
     {
81d882d5
         struct cached_dns_entry *ph;
e719a053
 
81d882d5
         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;
e719a053
 
81d882d5
         if (!c->c1.dns_cache)
         {
             c->c1.dns_cache = ph;
         }
         else
         {
             struct cached_dns_entry *prev = c->c1.dns_cache;
             while (prev->next)
4cd4899e
             {
81d882d5
                 prev = prev->next;
4cd4899e
             }
81d882d5
             prev->next = ph;
         }
e719a053
 
81d882d5
         gc_addspecial(ai, &gc_freeaddrinfo_callback, &c->gc);
e719a053
 
     }
81d882d5
     return status;
e719a053
 }
 
 void
81d882d5
 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;
             }
 
         }
e719a053
 
     }
     return;
 
81d882d5
 err:
     throw_signal_soft(SIGHUP, "Preresolving failed");
e719a053
 }
f2d6f3bc
 
ea93a078
 /*
f2d6f3bc
  * Translate IPv4/IPv6 addr or hostname into struct addrinfo
  * If resolve error, try again for resolve_retry_seconds seconds.
ea93a078
  */
f2d6f3bc
 int
81d882d5
 openvpn_getaddrinfo(unsigned int flags,
                     const char *hostname,
                     const char *servname,
                     int resolve_retry_seconds,
                     volatile int *signal_received,
                     int ai_family,
                     struct addrinfo **res)
ea93a078
 {
81d882d5
     struct addrinfo hints;
     int status;
     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;
ea93a078
 
81d882d5
     ASSERT(res);
f2d6f3bc
 
81d882d5
     ASSERT(hostname || servname);
     ASSERT(!(flags & GETADDR_HOST_ORDER));
076fd3e4
 
81d882d5
     if (servname)
     {
         print_servname = servname;
     }
     else
     {
         print_servname = "";
     }
076fd3e4
 
81d882d5
     if (flags & GETADDR_MSG_VIRT_OUT)
     {
         msglevel |= M_MSG_VIRT_OUT;
     }
ea93a078
 
81d882d5
     if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL))
         && !signal_received)
     {
         signal_received = &sigrec;
     }
ea93a078
 
81d882d5
     /* try numeric ipv6 addr first */
     CLEAR(hints);
     hints.ai_family = ai_family;
     hints.ai_flags = AI_NUMERICHOST;
97ba084b
 
81d882d5
     if (flags & GETADDR_PASSIVE)
     {
         hints.ai_flags |= AI_PASSIVE;
     }
076fd3e4
 
81d882d5
     if (flags & GETADDR_DATAGRAM)
     {
         hints.ai_socktype = SOCK_DGRAM;
     }
     else
     {
         hints.ai_socktype = SOCK_STREAM;
     }
23d61c56
 
81d882d5
     status = getaddrinfo(hostname, servname, &hints, res);
ea93a078
 
81d882d5
     if (status != 0) /* parse as numeric address failed? */
ea93a078
     {
81d882d5
         const int fail_wait_interval = 5; /* seconds */
         /* 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;
ea93a078
 
3c748aeb
         if (hostname && (flags & GETADDR_RANDOMIZE))
         {
             hostname = hostname_randomize(hostname, &gc);
         }
 
         if (hostname)
         {
             print_hostname = hostname;
         }
         else
         {
             print_hostname = "undefined";
         }
 
81d882d5
         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 (%s) (I would have retried this name query if you had specified the --resolv-retry option.)";
         }
ea93a078
 
81d882d5
         if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL)
f2d6f3bc
         {
81d882d5
             msg(msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)",
                 print_hostname,print_servname, gai_strerror(status));
             goto done;
f2d6f3bc
         }
ea93a078
 
 #ifdef ENABLE_MANAGEMENT
81d882d5
         if (flags & GETADDR_UPDATE_MANAGEMENT_STATE)
f2d6f3bc
         {
81d882d5
             if (management)
             {
                 management_set_state(management,
                                      OPENVPN_STATE_RESOLVE,
                                      NULL,
                                      NULL,
                                      NULL,
                                      NULL,
                                      NULL);
             }
f2d6f3bc
         }
ea93a078
 #endif
 
81d882d5
         /*
          * Resolve hostname
          */
         while (true)
f2d6f3bc
         {
445b192a
 #ifndef _WIN32
81d882d5
             res_init();
288a819a
 #endif
81d882d5
             /* try hostname lookup */
             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, servname, &hints, res);
6d1b80bd
 
81d882d5
             if (signal_received)
f2d6f3bc
             {
81d882d5
                 get_signal(signal_received);
                 if (*signal_received) /* were we interrupted by a signal? */
f2d6f3bc
                 {
81d882d5
                     if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */
f2d6f3bc
                     {
81d882d5
                         msg(level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt");
                         *signal_received = 0;
f2d6f3bc
                     }
81d882d5
                     else
282788a8
                     {
81d882d5
                         /* turn success into failure (interrupted syscall) */
                         if (0 == status)
                         {
                             ASSERT(res);
                             freeaddrinfo(*res);
                             *res = NULL;
                             status = EAI_AGAIN; /* = temporary failure */
                             errno = EINTR;
                         }
                         goto done;
282788a8
                     }
f2d6f3bc
                 }
             }
ea93a078
 
81d882d5
             /* success? */
             if (0 == status)
             {
                 break;
             }
ea93a078
 
81d882d5
             /* resolve lookup failed, should we
              * continue or fail? */
             level = msglevel;
             if (resolve_retries > 0)
             {
                 level = D_RESOLVE_ERRORS;
             }
ea93a078
 
81d882d5
             msg(level,
                 fmt,
                 print_hostname,
                 print_servname,
                 gai_strerror(status));
f2d6f3bc
 
81d882d5
             if (--resolve_retries <= 0)
             {
                 goto done;
             }
ea93a078
 
45b2af9c
             management_sleep(fail_wait_interval);
ea93a078
         }
 
81d882d5
         ASSERT(res);
ea93a078
 
81d882d5
         /* hostname resolve succeeded */
f2d6f3bc
 
81d882d5
         /*
          * Do not choose an IP Addresse by random or change the order *
          * of IP addresses, doing so will break RFC 3484 address selection *
          */
ea93a078
     }
81d882d5
     else
ea93a078
     {
81d882d5
         /* IP address parse succeeded */
3c748aeb
         if (flags & GETADDR_RANDOMIZE)
         {
             msg(M_WARN, "WARNING: ignoring --remote-random-hostname because the hostname is an IP address");
         }
ea93a078
     }
 
81d882d5
 done:
     if (signal_received && *signal_received)
ea93a078
     {
81d882d5
         int level = 0;
         if (flags & GETADDR_FATAL_ON_SIGNAL)
         {
             level = M_FATAL;
         }
         else if (flags & GETADDR_WARN_ON_SIGNAL)
         {
             level = M_WARN;
         }
         msg(level, "RESOLVE: signal received during DNS resolution attempt");
ea93a078
     }
 
81d882d5
     gc_free(&gc);
     return status;
ea93a078
 }
 
6fbf66fa
 /*
  * We do our own inet_aton because the glibc function
  * isn't very good about error checking.
  */
 int
81d882d5
 openvpn_inet_aton(const char *dotted_quad, struct in_addr *addr)
6fbf66fa
 {
81d882d5
     unsigned int a, b, c, d;
6fbf66fa
 
81d882d5
     CLEAR(*addr);
     if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) == 4)
     {
         if (a < 256 && b < 256 && c < 256 && d < 256)
         {
             addr->s_addr = htonl(a<<24 | b<<16 | c<<8 | d);
             return OIA_IP; /* good dotted quad */
         }
     }
     if (string_class(dotted_quad, CC_DIGIT|CC_DOT, 0))
     {
         return OIA_ERROR; /* probably a badly formatted dotted quad */
     }
     else
6fbf66fa
     {
81d882d5
         return OIA_HOSTNAME; /* probably a hostname */
6fbf66fa
     }
 }
 
b4073a76
 bool
81d882d5
 ip_addr_dotted_quad_safe(const char *dotted_quad)
b4073a76
 {
81d882d5
     /* verify non-NULL */
     if (!dotted_quad)
     {
         return false;
     }
b4073a76
 
81d882d5
     /* verify length is within limits */
     if (strlen(dotted_quad) > 15)
     {
         return false;
     }
 
     /* verify that all chars are either numeric or '.' and that no numeric
      * substring is greater than 3 chars */
     {
         int nnum = 0;
         const char *p = dotted_quad;
         int c;
b4073a76
 
81d882d5
         while ((c = *p++))
         {
             if (c >= '0' && c <= '9')
             {
                 ++nnum;
                 if (nnum > 3)
                 {
                     return false;
                 }
             }
             else if (c == '.')
             {
                 nnum = 0;
             }
             else
             {
                 return false;
             }
         }
     }
 
     /* verify that string will convert to IP address */
     {
         struct in_addr a;
         return openvpn_inet_aton(dotted_quad, &a) == OIA_IP;
     }
b4073a76
 }
 
512cda46
 bool
81d882d5
 ipv6_addr_safe(const char *ipv6_text_addr)
512cda46
 {
81d882d5
     /* verify non-NULL */
     if (!ipv6_text_addr)
     {
         return false;
     }
512cda46
 
81d882d5
     /* verify length is within limits */
     if (strlen(ipv6_text_addr) > INET6_ADDRSTRLEN)
     {
         return false;
     }
512cda46
 
81d882d5
     /* verify that string will convert to IPv6 address */
     {
         struct in6_addr a6;
         return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1;
     }
512cda46
 }
 
b4b5c311
 static bool
81d882d5
 dns_addr_safe(const char *addr)
b4b5c311
 {
81d882d5
     if (addr)
b4b5c311
     {
81d882d5
         const size_t len = strlen(addr);
         return len > 0 && len <= 255 && string_class(addr, CC_ALNUM|CC_DASH|CC_DOT, 0);
     }
     else
     {
         return false;
b4b5c311
     }
 }
 
0a838de8
 bool
81d882d5
 ip_or_dns_addr_safe(const char *addr, const bool allow_fqdn)
0a838de8
 {
81d882d5
     if (ip_addr_dotted_quad_safe(addr))
     {
         return true;
     }
     else if (allow_fqdn)
     {
         return dns_addr_safe(addr);
     }
     else
     {
         return false;
     }
0a838de8
 }
 
6e2c457d
 bool
81d882d5
 mac_addr_safe(const char *mac_addr)
6e2c457d
 {
81d882d5
     /* verify non-NULL */
     if (!mac_addr)
     {
         return false;
     }
6e2c457d
 
81d882d5
     /* verify length is within limits */
     if (strlen(mac_addr) > 17)
     {
         return false;
     }
 
     /* verify that all chars are either alphanumeric or ':' and that no
      * alphanumeric substring is greater than 2 chars */
     {
         int nnum = 0;
         const char *p = mac_addr;
         int c;
 
         while ((c = *p++))
         {
             if ( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )
             {
                 ++nnum;
                 if (nnum > 2)
                 {
                     return false;
                 }
             }
             else if (c == ':')
             {
                 nnum = 0;
             }
             else
             {
                 return false;
             }
         }
     }
6e2c457d
 
81d882d5
     /* error-checking is left to script invoked in lladdr.c */
     return true;
6e2c457d
 }
 
6fbf66fa
 static int
81d882d5
 socket_get_sndbuf(int sd)
6fbf66fa
 {
 #if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF)
81d882d5
     int val;
     socklen_t len;
6fbf66fa
 
81d882d5
     len = sizeof(val);
     if (getsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &val, &len) == 0
         && len == sizeof(val))
     {
         return val;
     }
6fbf66fa
 #endif
81d882d5
     return 0;
6fbf66fa
 }
 
 static void
81d882d5
 socket_set_sndbuf(int sd, int size)
6fbf66fa
 {
 #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF)
81d882d5
     if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof(size)) != 0)
6fbf66fa
     {
81d882d5
         msg(M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size);
6fbf66fa
     }
 #endif
 }
 
 static int
81d882d5
 socket_get_rcvbuf(int sd)
6fbf66fa
 {
 #if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF)
81d882d5
     int val;
     socklen_t len;
6fbf66fa
 
81d882d5
     len = sizeof(val);
     if (getsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void *) &val, &len) == 0
         && len == sizeof(val))
     {
         return val;
     }
6fbf66fa
 #endif
81d882d5
     return 0;
6fbf66fa
 }
 
 static bool
81d882d5
 socket_set_rcvbuf(int sd, int size)
6fbf66fa
 {
 #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF)
81d882d5
     if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof(size)) != 0)
6fbf66fa
     {
81d882d5
         msg(M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size);
         return false;
6fbf66fa
     }
81d882d5
     return true;
6fbf66fa
 #endif
 }
 
 static void
81d882d5
 socket_set_buffers(int fd, const struct socket_buffer_size *sbs)
6fbf66fa
 {
81d882d5
     if (sbs)
6fbf66fa
     {
81d882d5
         const int sndbuf_old = socket_get_sndbuf(fd);
         const int rcvbuf_old = socket_get_rcvbuf(fd);
 
         if (sbs->sndbuf)
         {
             socket_set_sndbuf(fd, sbs->sndbuf);
         }
6fbf66fa
 
81d882d5
         if (sbs->rcvbuf)
         {
             socket_set_rcvbuf(fd, sbs->rcvbuf);
         }
6fbf66fa
 
81d882d5
         msg(D_OSBUF, "Socket Buffers: R=[%d->%d] S=[%d->%d]",
             rcvbuf_old,
             socket_get_rcvbuf(fd),
             sndbuf_old,
             socket_get_sndbuf(fd));
6fbf66fa
     }
 }
 
 /*
00d39170
  * Set other socket options
  */
 
 static bool
81d882d5
 socket_set_tcp_nodelay(int sd, int state)
00d39170
 {
445b192a
 #if defined(_WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY))
81d882d5
     if (setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (void *) &state, sizeof(state)) != 0)
00d39170
     {
81d882d5
         msg(M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed", state);
         return false;
00d39170
     }
81d882d5
     else
00d39170
     {
81d882d5
         dmsg(D_OSBUF, "Socket flags: TCP_NODELAY=%d succeeded", state);
         return true;
00d39170
     }
81d882d5
 #else  /* if defined(_WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY)) */
     msg(M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed (No kernel support)", state);
     return false;
00d39170
 #endif
 }
 
032f0045
 static inline void
81d882d5
 socket_set_mark(int sd, int mark)
d90428d1
 {
51bd56f4
 #if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK
81d882d5
     if (mark && setsockopt(sd, SOL_SOCKET, SO_MARK, (void *) &mark, sizeof(mark)) != 0)
     {
         msg(M_WARN, "NOTE: setsockopt SO_MARK=%d failed", mark);
     }
d90428d1
 #endif
 }
 
00d39170
 static bool
81d882d5
 socket_set_flags(int sd, unsigned int sockflags)
00d39170
 {
81d882d5
     if (sockflags & SF_TCP_NODELAY)
     {
         return socket_set_tcp_nodelay(sd, 1);
     }
     else
     {
         return true;
     }
00d39170
 }
 
 bool
81d882d5
 link_socket_update_flags(struct link_socket *ls, unsigned int sockflags)
00d39170
 {
81d882d5
     if (ls && socket_defined(ls->sd))
     {
         return socket_set_flags(ls->sd, ls->sockflags = sockflags);
     }
     else
     {
         return false;
     }
00d39170
 }
 
 void
81d882d5
 link_socket_update_buffer_sizes(struct link_socket *ls, int rcvbuf, int sndbuf)
00d39170
 {
81d882d5
     if (ls && socket_defined(ls->sd))
00d39170
     {
81d882d5
         ls->socket_buffer_sizes.sndbuf = sndbuf;
         ls->socket_buffer_sizes.rcvbuf = rcvbuf;
         socket_set_buffers(ls->sd, &ls->socket_buffer_sizes);
00d39170
     }
 }
 
 /*
6fbf66fa
  * SOCKET INITALIZATION CODE.
  * Create a TCP/UDP socket
  */
 
 socket_descriptor_t
81d882d5
 create_socket_tcp(struct addrinfo *addrinfo)
6fbf66fa
 {
81d882d5
     socket_descriptor_t sd;
6fbf66fa
 
81d882d5
     ASSERT(addrinfo);
     ASSERT(addrinfo->ai_socktype == SOCK_STREAM);
7dbe04de
 
81d882d5
     if ((sd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
     {
         msg(M_ERR, "Cannot create TCP socket");
     }
6fbf66fa
 
445b192a
 #ifndef _WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */
81d882d5
     /* set SO_REUSEADDR on socket */
     {
         int on = 1;
         if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,
                        (void *) &on, sizeof(on)) < 0)
         {
             msg(M_ERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP socket");
         }
     }
7d770f1e
 #endif
6fbf66fa
 
81d882d5
     /* set socket file descriptor to not pass across execs, so that
      * scripts don't have access to it */
     set_cloexec(sd);
e35a7883
 
81d882d5
     return sd;
6fbf66fa
 }
 
 static socket_descriptor_t
81d882d5
 create_socket_udp(struct addrinfo *addrinfo, const unsigned int flags)
6fbf66fa
 {
81d882d5
     socket_descriptor_t sd;
6fbf66fa
 
81d882d5
     ASSERT(addrinfo);
     ASSERT(addrinfo->ai_socktype == SOCK_DGRAM);
7dbe04de
 
81d882d5
     if ((sd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
     {
         msg(M_ERR, "UDP: Cannot create UDP/UDP6 socket");
     }
8bc93d7f
 #if ENABLE_IP_PKTINFO
81d882d5
     else if (flags & SF_USE_IP_PKTINFO)
8bc93d7f
     {
81d882d5
         int pad = 1;
         if (addrinfo->ai_family == AF_INET)
23d61c56
         {
7efa60d9
 #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
81d882d5
             if (setsockopt(sd, SOL_IP, IP_PKTINFO,
                            (void *)&pad, sizeof(pad)) < 0)
             {
                 msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO");
             }
d3774cdf
 #elif defined(IP_RECVDSTADDR)
81d882d5
             if (setsockopt(sd, IPPROTO_IP, IP_RECVDSTADDR,
                            (void *)&pad, sizeof(pad)) < 0)
             {
                 msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR");
             }
 #else  /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
d3774cdf
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
23d61c56
         }
81d882d5
         else if (addrinfo->ai_family == AF_INET6)
23d61c56
         {
fe8a7f0c
 #ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */
81d882d5
             if (setsockopt(sd, IPPROTO_IPV6, IPV6_PKTINFO,
                            (void *)&pad, sizeof(pad)) < 0)
fe8a7f0c
 #else
81d882d5
             if (setsockopt(sd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
                            (void *)&pad, sizeof(pad)) < 0)
fe8a7f0c
 #endif
81d882d5
             { msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");}
23d61c56
         }
8335caf9
     }
81d882d5
 #endif /* if ENABLE_IP_PKTINFO */
e35a7883
 
81d882d5
     /* set socket file descriptor to not pass across execs, so that
      * scripts don't have access to it */
     set_cloexec(sd);
e35a7883
 
81d882d5
     return sd;
8335caf9
 }
 
81d882d5
 static void
 bind_local(struct link_socket *sock, const sa_family_t ai_family)
6fbf66fa
 {
7dbe04de
     /* bind to local address/port */
     if (sock->bind_local)
81d882d5
     {
7dbe04de
         if (sock->socks_proxy && sock->info.proto == PROTO_UDP)
81d882d5
         {
             socket_bind(sock->ctrl_sd, sock->info.lsa->bind_local,
                         ai_family, "SOCKS", false);
         }
7dbe04de
         else
81d882d5
         {
             socket_bind(sock->sd, sock->info.lsa->bind_local,
                         ai_family,
                         "TCP/UDP", sock->info.bind_ipv6_only);
         }
     }
7dbe04de
 }
23d61c56
 
7dbe04de
 static void
81d882d5
 create_socket(struct link_socket *sock, struct addrinfo *addr)
7dbe04de
 {
81d882d5
     if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM)
6fbf66fa
     {
81d882d5
         sock->sd = create_socket_udp(addr, sock->sockflags);
         sock->sockflags |= SF_GETADDRINFO_DGRAM;
6fbf66fa
 
81d882d5
         /* Assume that control socket and data socket to the socks proxy
          * are using the same IP family */
         if (sock->socks_proxy)
         {
             /* 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);
         }
6fbf66fa
     }
81d882d5
     else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM)
8335caf9
     {
81d882d5
         sock->sd = create_socket_tcp(addr);
8335caf9
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         ASSERT(0);
6fbf66fa
     }
23d61c56
     /* set socket buffers based on --sndbuf and --rcvbuf options */
81d882d5
     socket_set_buffers(sock->sd, &sock->socket_buffer_sizes);
23d61c56
 
     /* set socket to --mark packets with given value */
81d882d5
     socket_set_mark(sock->sd, sock->mark);
7dbe04de
 
81d882d5
     bind_local(sock, addr->ai_family);
51187871
 }
23d61c56
 
a55b3cdb
 #ifdef TARGET_ANDROID
81d882d5
 static void
 protect_fd_nonlocal(int fd, const struct sockaddr *addr)
51187871
 {
81d882d5
     /* 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;
     }
a55b3cdb
 
81d882d5
     msg(D_SOCKET_DEBUG, "Protecting socket fd %d", fd);
     management->connection.fdtosend = fd;
     management_android_control(management, "PROTECTFD", __func__);
6fbf66fa
 }
51187871
 #endif
6fbf66fa
 
 /*
  * Functions used for establishing a TCP stream connection.
  */
 static void
81d882d5
 socket_do_listen(socket_descriptor_t sd,
                  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->ai_addr, &gc));
         if (listen(sd, 1))
         {
             msg(M_ERR, "TCP: listen() failed");
         }
6fbf66fa
     }
 
81d882d5
     /* set socket to non-blocking mode */
     if (do_set_nonblock)
     {
         set_nonblock(sd);
     }
6fbf66fa
 
81d882d5
     gc_free(&gc);
6fbf66fa
 }
 
 socket_descriptor_t
81d882d5
 socket_do_accept(socket_descriptor_t sd,
                  struct link_socket_actual *act,
                  const bool nowait)
6fbf66fa
 {
81d882d5
     /* af_addr_size WILL return 0 in this case if AFs other than AF_INET
      * are compiled because act is empty here.
      * could use getsockname() to support later remote_len check
      */
     socklen_t remote_len_af = af_addr_size(act->dest.addr.sa.sa_family);
     socklen_t remote_len = sizeof(act->dest.addr);
     socket_descriptor_t new_sd = SOCKET_UNDEFINED;
6fbf66fa
 
81d882d5
     CLEAR(*act);
8bc93d7f
 
6fbf66fa
 #ifdef HAVE_GETPEERNAME
81d882d5
     if (nowait)
6fbf66fa
     {
81d882d5
         new_sd = getpeername(sd, &act->dest.addr.sa, &remote_len);
6fbf66fa
 
81d882d5
         if (!socket_defined(new_sd))
         {
             msg(D_LINK_ERRORS | M_ERRNO, "TCP: getpeername() failed");
         }
         else
         {
             new_sd = sd;
         }
     }
 #else  /* ifdef HAVE_GETPEERNAME */
     if (nowait)
     {
         msg(M_WARN, "TCP: this OS does not provide the getpeername() function");
6fbf66fa
     }
 #endif
81d882d5
     else
6fbf66fa
     {
81d882d5
         new_sd = accept(sd, &act->dest.addr.sa, &remote_len);
6fbf66fa
     }
 
e8c1720d
 #if 0 /* For debugging only, test the effect of accept() failures */
81d882d5
     {
         static int foo = 0;
         ++foo;
         if (foo & 1)
         {
             new_sd = -1;
         }
     }
e8c1720d
 #endif
 
81d882d5
     if (!socket_defined(new_sd))
6fbf66fa
     {
06ad53e0
         msg(D_LINK_ERRORS | M_ERRNO, "TCP: accept(%d) failed", (int)sd);
6fbf66fa
     }
81d882d5
     /* only valid if we have remote_len_af!=0 */
     else if (remote_len_af && remote_len != remote_len_af)
6fbf66fa
     {
81d882d5
         msg(D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len);
         openvpn_close_socket(new_sd);
         new_sd = SOCKET_UNDEFINED;
6fbf66fa
     }
81d882d5
     else
e35a7883
     {
81d882d5
         /* set socket file descriptor to not pass across execs, so that
          * scripts don't have access to it */
         set_cloexec(sd);
e35a7883
     }
81d882d5
     return new_sd;
6fbf66fa
 }
 
 static void
81d882d5
 tcp_connection_established(const struct link_socket_actual *act)
6fbf66fa
 {
81d882d5
     struct gc_arena gc = gc_new();
     msg(M_INFO, "TCP connection established with %s",
         print_link_socket_actual(act, &gc));
     gc_free(&gc);
6fbf66fa
 }
 
33e1a869
 static socket_descriptor_t
81d882d5
 socket_listen_accept(socket_descriptor_t sd,
                      struct link_socket_actual *act,
                      const char *remote_dynamic,
                      const struct addrinfo *local,
                      bool do_listen,
                      bool nowait,
                      volatile int *signal_received)
 {
     struct gc_arena gc = gc_new();
     /* struct openvpn_sockaddr *remote = &act->dest; */
     struct openvpn_sockaddr remote_verify = act->dest;
33e1a869
     socket_descriptor_t new_sd = SOCKET_UNDEFINED;
81d882d5
 
     CLEAR(*act);
     socket_do_listen(sd, local, do_listen, true);
 
     while (true)
     {
         int status;
         fd_set reads;
         struct timeval tv;
 
         FD_ZERO(&reads);
         openvpn_fd_set(sd, &reads);
         tv.tv_sec = 0;
         tv.tv_usec = 0;
 
         status = select(sd + 1, &reads, NULL, NULL, &tv);
 
         get_signal(signal_received);
         if (*signal_received)
         {
             gc_free(&gc);
             return sd;
         }
 
         if (status < 0)
         {
             msg(D_LINK_ERRORS | M_ERRNO, "TCP: select() failed");
         }
 
         if (status <= 0)
         {
45b2af9c
             management_sleep(1);
81d882d5
             continue;
         }
 
         new_sd = socket_do_accept(sd, act, nowait);
 
         if (socket_defined(new_sd))
         {
             struct addrinfo *ai = NULL;
             if (remote_dynamic)
             {
                 openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL,
23d61c56
                                     remote_verify.addr.sa.sa_family, &ai);
81d882d5
             }
23d61c56
 
81d882d5
             if (ai && !addrlist_match(&remote_verify, ai))
23d61c56
             {
81d882d5
                 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);
23d61c56
             }
81d882d5
             else
23d61c56
             {
81d882d5
                 if (ai)
                 {
                     freeaddrinfo(ai);
                 }
                 break;
23d61c56
             }
81d882d5
         }
45b2af9c
         management_sleep(1);
6fbf66fa
     }
 
81d882d5
     if (!nowait && openvpn_close_socket(sd))
     {
         msg(M_ERR, "TCP: close socket failed (sd)");
     }
6fbf66fa
 
81d882d5
     tcp_connection_established(act);
6fbf66fa
 
81d882d5
     gc_free(&gc);
     return new_sd;
6fbf66fa
 }
 
188a6515
 /* older mingw versions and WinXP do not have this define,
  * but Vista and up support the functionality - just define it here
  */
445b192a
 #ifdef _WIN32
81d882d5
 #ifndef IPV6_V6ONLY
 #define IPV6_V6ONLY 27
 #endif
188a6515
 #endif
7ef85434
 void
81d882d5
 socket_bind(socket_descriptor_t sd,
             struct addrinfo *local,
             int ai_family,
             const char *prefix,
             bool ipv6only)
04f4b793
 {
81d882d5
     struct gc_arena gc = gc_new();
04f4b793
 
81d882d5
     /* 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?
      */
23d61c56
 
81d882d5
     struct addrinfo *cur;
23d61c56
 
81d882d5
     ASSERT(local);
8832c6c4
 
 
81d882d5
     /* 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)
23d61c56
     {
81d882d5
         msg(M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record",
             prefix, addr_family_name(ai_family));
23d61c56
     }
 
81d882d5
     if (ai_family == AF_INET6)
8832c6c4
     {
81d882d5
         int v6only = ipv6only ? 1 : 0;  /* setsockopt must have an "int" */
8832c6c4
 
81d882d5
         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);
         }
8832c6c4
     }
81d882d5
     if (bind(sd, cur->ai_addr, cur->ai_addrlen))
04f4b793
     {
56b396dc
         msg(M_FATAL | M_ERRNO, "%s: Socket bind failed on local address %s",
81d882d5
             prefix,
56b396dc
             print_sockaddr_ex(local->ai_addr, ":", PS_SHOW_PORT, &gc));
04f4b793
     }
81d882d5
     gc_free(&gc);
04f4b793
 }
 
4f404ad3
 int
81d882d5
 openvpn_connect(socket_descriptor_t sd,
                 const struct sockaddr *remote,
                 int connect_timeout,
                 volatile int *signal_received)
1ae9d051
 {
81d882d5
     int status = 0;
1ae9d051
 
51187871
 #ifdef TARGET_ANDROID
81d882d5
     protect_fd_nonlocal(sd, remote);
51187871
 #endif
 
1ae9d051
 #ifdef CONNECT_NONBLOCK
81d882d5
     set_nonblock(sd);
     status = connect(sd, remote, af_addr_size(remote->sa_family));
     if (status)
     {
         status = openvpn_errno();
     }
     if (
445b192a
 #ifdef _WIN32
81d882d5
         status == WSAEWOULDBLOCK
9081e0ad
 #else
81d882d5
         status == EINPROGRESS
9081e0ad
 #endif
81d882d5
         )
1ae9d051
     {
81d882d5
         while (true)
         {
007738e9
 #if POLL
81d882d5
             struct pollfd fds[1];
             fds[0].fd = sd;
             fds[0].events = POLLOUT;
             status = poll(fds, 1, 0);
007738e9
 #else
81d882d5
             fd_set writes;
             struct timeval tv;
1ae9d051
 
81d882d5
             FD_ZERO(&writes);
             openvpn_fd_set(sd, &writes);
             tv.tv_sec = 0;
             tv.tv_usec = 0;
1ae9d051
 
81d882d5
             status = select(sd + 1, NULL, &writes, NULL, &tv);
007738e9
 #endif
81d882d5
             if (signal_received)
             {
                 get_signal(signal_received);
                 if (*signal_received)
                 {
                     status = 0;
                     break;
                 }
             }
             if (status < 0)
             {
                 status = openvpn_errno();
                 break;
             }
             if (status <= 0)
             {
                 if (--connect_timeout < 0)
                 {
445b192a
 #ifdef _WIN32
81d882d5
                     status = WSAETIMEDOUT;
5f5229e4
 #else
81d882d5
                     status = ETIMEDOUT;
5f5229e4
 #endif
81d882d5
                     break;
                 }
45b2af9c
                 management_sleep(1);
81d882d5
                 continue;
             }
 
             /* got it */
             {
                 int val = 0;
                 socklen_t len;
 
                 len = sizeof(val);
                 if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (void *) &val, &len) == 0
                     && len == sizeof(val))
                 {
                     status = val;
                 }
                 else
                 {
                     status = openvpn_errno();
                 }
                 break;
             }
         }
1ae9d051
     }
81d882d5
 #else  /* ifdef CONNECT_NONBLOCK */
     status = connect(sd, remote, af_addr_size(remote->sa_family));
     if (status)
     {
         status = openvpn_errno();
     }
 #endif /* ifdef CONNECT_NONBLOCK */
1ae9d051
 
81d882d5
     return status;
1ae9d051
 }
 
81d882d5
 void
 set_actual_address(struct link_socket_actual *actual, struct addrinfo *ai)
23d61c56
 {
81d882d5
     CLEAR(*actual);
     ASSERT(ai);
23d61c56
 
     if (ai->ai_family == AF_INET)
81d882d5
     {
23d61c56
         actual->dest.addr.in4 =
81d882d5
             *((struct sockaddr_in *) ai->ai_addr);
     }
23d61c56
     else if (ai->ai_family == AF_INET6)
81d882d5
     {
23d61c56
         actual->dest.addr.in6 =
81d882d5
             *((struct sockaddr_in6 *) ai->ai_addr);
     }
23d61c56
     else
81d882d5
     {
23d61c56
         ASSERT(0);
81d882d5
     }
23d61c56
 
 }
 
72bcdfdc
 static void
81d882d5
 socket_connect(socket_descriptor_t *sd,
                const struct sockaddr *dest,
                const int connect_timeout,
                struct signal_info *sig_info)
6fbf66fa
 {
81d882d5
     struct gc_arena gc = gc_new();
     int status;
6fbf66fa
 
1ae9d051
 #ifdef CONNECT_NONBLOCK
81d882d5
     msg(M_INFO, "Attempting to establish TCP connection with %s [nonblock]",
         print_sockaddr(dest, &gc));
1ae9d051
 #else
81d882d5
     msg(M_INFO, "Attempting to establish TCP connection with %s",
         print_sockaddr(dest, &gc));
1ae9d051
 #endif
 
e482a632
 #ifdef ENABLE_MANAGEMENT
81d882d5
     if (management)
     {
         management_set_state(management,
                              OPENVPN_STATE_TCP_CONNECT,
                              NULL,
                              NULL,
                              NULL,
                              NULL,
                              NULL);
     }
e482a632
 #endif
 
81d882d5
     /* Set the actual address */
     status = openvpn_connect(*sd, dest, connect_timeout, &sig_info->signal_received);
a17f6969
 
81d882d5
     get_signal(&sig_info->signal_received);
     if (sig_info->signal_received)
     {
         goto done;
     }
a17f6969
 
81d882d5
     if (status)
     {
97549c67
 
fd2a29ab
         msg(D_LINK_ERRORS, "TCP: connect to %s failed: %s",
             print_sockaddr(dest, &gc), strerror(status));
6fbf66fa
 
81d882d5
         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));
     }
6fbf66fa
 
81d882d5
 done:
     gc_free(&gc);
6fbf66fa
 }
 
 /* For stream protocols, allocate a buffer to build up packet.
81d882d5
  * Called after frame has been finalized. */
6fbf66fa
 
 static void
81d882d5
 socket_frame_init(const struct frame *frame, struct link_socket *sock)
6fbf66fa
 {
445b192a
 #ifdef _WIN32
81d882d5
     overlapped_io_init(&sock->reads, frame, FALSE, false);
     overlapped_io_init(&sock->writes, frame, TRUE, false);
     sock->rw_handle.read = sock->reads.overlapped.hEvent;
     sock->rw_handle.write = sock->writes.overlapped.hEvent;
6fbf66fa
 #endif
 
81d882d5
     if (link_socket_connection_oriented(sock))
6fbf66fa
     {
445b192a
 #ifdef _WIN32
81d882d5
         stream_buf_init(&sock->stream_buf,
                         &sock->reads.buf_init,
                         sock->sockflags,
                         sock->info.proto);
6fbf66fa
 #else
81d882d5
         alloc_buf_sock_tun(&sock->stream_buf_data,
                            frame,
                            false,
                            FRAME_HEADROOM_MARKER_READ_STREAM);
 
         stream_buf_init(&sock->stream_buf,
                         &sock->stream_buf_data,
                         sock->sockflags,
                         sock->info.proto);
6fbf66fa
 #endif
     }
 }
 
 /*
  * Adjust frame structure based on a Path MTU value given
  * to us by the OS.
  */
 void
81d882d5
 frame_adjust_path_mtu(struct frame *frame, int pmtu, int proto)
6fbf66fa
 {
81d882d5
     frame_set_mtu_dynamic(frame, pmtu - datagram_overhead(proto), SET_MTU_UPPER_BOUND);
6fbf66fa
 }
 
 static void
81d882d5
 resolve_bind_local(struct link_socket *sock, const sa_family_t af)
6fbf66fa
 {
81d882d5
     struct gc_arena gc = gc_new();
6fbf66fa
 
81d882d5
     /* resolve local address if undefined */
     if (!sock->info.lsa->bind_local)
d9c04efc
     {
81d882d5
         int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL
                     |GETADDR_FATAL | GETADDR_PASSIVE;
         int status;
23d61c56
 
81d882d5
         if (proto_is_dgram(sock->info.proto))
         {
             flags |= GETADDR_DATAGRAM;
         }
23d61c56
 
81d882d5
         /* 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);
e719a053
 
81d882d5
         if (status)
         {
             status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
                                          NULL, af, &sock->info.lsa->bind_local);
         }
23d61c56
 
81d882d5
         if (status !=0)
         {
             msg(M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s",
                 sock->local_host, sock->local_port,
                 gai_strerror(status));
         }
6fbf66fa
     }
076fd3e4
 
81d882d5
     gc_free(&gc);
23d61c56
 }
 
6fbf66fa
 static void
81d882d5
 resolve_remote(struct link_socket *sock,
                int phase,
                const char **remote_dynamic,
                volatile int *signal_received)
 {
     struct gc_arena gc = gc_new();
 
     /* resolve remote address if undefined */
     if (!sock->info.lsa->remote_list)
     {
         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)
             {
                 if (phase == 2)
                 {
                     flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
                 }
                 retry = 0;
             }
             else if (phase == 1)
             {
                 if (sock->resolve_retry_seconds)
                 {
                     retry = 0;
                 }
                 else
                 {
                     flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
                     retry = 0;
                 }
             }
             else if (phase == 2)
             {
                 if (sock->resolve_retry_seconds)
                 {
                     flags |= GETADDR_FATAL;
                     retry = sock->resolve_retry_seconds;
                 }
                 else
                 {
                     ASSERT(0);
                 }
             }
             else
             {
                 ASSERT(0);
             }
 
 
             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;
             }
         }
     }
 
     /* 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)
         {
             set_actual_address(&sock->info.lsa->actual,
                                sock->info.lsa->current_remote);
         }
     }
 
 done:
     gc_free(&gc);
6fbf66fa
 }
 
23d61c56
 
 
6fbf66fa
 struct link_socket *
81d882d5
 link_socket_new(void)
6fbf66fa
 {
81d882d5
     struct link_socket *sock;
6fbf66fa
 
81d882d5
     ALLOC_OBJ_CLEAR(sock, struct link_socket);
     sock->sd = SOCKET_UNDEFINED;
     sock->ctrl_sd = SOCKET_UNDEFINED;
     return sock;
6fbf66fa
 }
 
48f1d41a
 void
81d882d5
 link_socket_init_phase1(struct link_socket *sock,
                         const char *local_host,
                         const char *local_port,
                         const char *remote_host,
                         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,
                         struct http_proxy_info *http_proxy,
                         struct socks_proxy_info *socks_proxy,
6fbf66fa
 #ifdef ENABLE_DEBUG
81d882d5
                         int gremlin,
6fbf66fa
 #endif
81d882d5
                         bool bind_local,
                         bool remote_float,
                         int inetd,
                         struct link_socket_addr *lsa,
                         const char *ipchange_command,
                         const struct plugin_list *plugins,
                         int resolve_retry_seconds,
                         int mtu_discover_type,
                         int rcvbuf,
                         int sndbuf,
                         int mark,
                         struct event_timeout *server_poll_timeout,
                         unsigned int sockflags)
 {
     ASSERT(sock);
 
     sock->local_host = local_host;
     sock->local_port = local_port;
     sock->remote_host = remote_host;
     sock->remote_port = remote_port;
     sock->dns_cache = dns_cache;
     sock->http_proxy = http_proxy;
     sock->socks_proxy = socks_proxy;
     sock->bind_local = bind_local;
     sock->inetd = inetd;
     sock->resolve_retry_seconds = resolve_retry_seconds;
     sock->mtu_discover_type = mtu_discover_type;
6fbf66fa
 
 #ifdef ENABLE_DEBUG
81d882d5
     sock->gremlin = gremlin;
6fbf66fa
 #endif
 
81d882d5
     sock->socket_buffer_sizes.rcvbuf = rcvbuf;
     sock->socket_buffer_sizes.sndbuf = sndbuf;
6fbf66fa
 
81d882d5
     sock->sockflags = sockflags;
     sock->mark = mark;
00d39170
 
81d882d5
     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;
6fbf66fa
 
81d882d5
     sock->mode = mode;
     if (mode == LS_MODE_TCP_ACCEPT_FROM)
6fbf66fa
     {
81d882d5
         ASSERT(accept_from);
         ASSERT(sock->info.proto == PROTO_TCP_SERVER);
         ASSERT(!sock->inetd);
         sock->sd = accept_from->sd;
682e7fea
         /* inherit (possibly guessed) info AF from parent context */
         sock->info.af = accept_from->info.af;
6fbf66fa
     }
 
81d882d5
     /* are we running in HTTP proxy mode? */
     if (sock->http_proxy)
6fbf66fa
     {
81d882d5
         ASSERT(sock->info.proto == PROTO_TCP_CLIENT);
         ASSERT(!sock->inetd);
6fbf66fa
 
81d882d5
         /* the proxy server */
         sock->remote_host = http_proxy->options.server;
         sock->remote_port = http_proxy->options.port;
6fbf66fa
 
81d882d5
         /* the OpenVPN server we will use the proxy to connect to */
         sock->proxy_dest_host = remote_host;
         sock->proxy_dest_port = remote_port;
6fbf66fa
     }
81d882d5
     /* or in Socks proxy mode? */
     else if (sock->socks_proxy)
6fbf66fa
     {
81d882d5
         ASSERT(!sock->inetd);
6fbf66fa
 
81d882d5
         /* the proxy server */
         sock->remote_host = socks_proxy->server;
         sock->remote_port = socks_proxy->port;
6fbf66fa
 
81d882d5
         /* the OpenVPN server we will use the proxy to connect to */
         sock->proxy_dest_host = remote_host;
         sock->proxy_dest_port = remote_port;
6fbf66fa
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         sock->remote_host = remote_host;
         sock->remote_port = remote_port;
6fbf66fa
     }
 
81d882d5
     /* bind behavior for TCP server vs. client */
     if (sock->info.proto == PROTO_TCP_SERVER)
6fbf66fa
     {
81d882d5
         if (sock->mode == LS_MODE_TCP_ACCEPT_FROM)
         {
             sock->bind_local = false;
         }
         else
         {
             sock->bind_local = true;
         }
6fbf66fa
     }
 
81d882d5
     /* were we started by inetd or xinetd? */
     if (sock->inetd)
6fbf66fa
     {
81d882d5
         ASSERT(sock->info.proto != PROTO_TCP_CLIENT);
         ASSERT(socket_defined(inetd_socket_descriptor));
         sock->sd = inetd_socket_descriptor;
         set_cloexec(sock->sd);          /* not created by create_socket*() */
6fbf66fa
     }
81d882d5
     else if (mode != LS_MODE_TCP_ACCEPT_FROM)
6fbf66fa
     {
81d882d5
         if (sock->bind_local)
         {
             resolve_bind_local(sock, sock->info.af);
         }
         resolve_remote(sock, 1, NULL, NULL);
48f1d41a
     }
 }
 
 static
81d882d5
 void
 phase2_inetd(struct link_socket *sock, const struct frame *frame,
              const char *remote_dynamic, volatile int *signal_received)
48f1d41a
 {
81d882d5
     bool remote_changed = false;
48f1d41a
 
81d882d5
     if (sock->info.proto == PROTO_TCP_SERVER)
48f1d41a
     {
81d882d5
         /* 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),
06ad53e0
                      local_addr.addr.sa.sa_family, (int)sock->sd);
81d882d5
             }
             else
             {
                 msg(M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET",
06ad53e0
                     proto2ascii(sock->info.proto, sock->info.af, false), (int)sock->sd);
81d882d5
             }
         }
 #else  /* ifdef HAVE_GETSOCKNAME */
         msg(M_WARN, "inetd(%s): this OS does not provide the getsockname() "
             "function, using AF_INET",
             proto2ascii(sock->info.proto, false));
 #endif /* ifdef HAVE_GETSOCKNAME */
         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);
23d61c56
 
81d882d5
     }
     ASSERT(!remote_changed);
48f1d41a
 }
2b9b4c8a
 
48f1d41a
 static void
81d882d5
 phase2_set_socket_flags(struct link_socket *sock)
48f1d41a
 {
81d882d5
     /* set misc socket parameters */
     socket_set_flags(sock->sd, sock->sockflags);
48f1d41a
 
81d882d5
     /* set socket to non-blocking mode */
     set_nonblock(sock->sd);
48f1d41a
 
81d882d5
     /* set Path MTU discovery options on the socket */
     set_mtu_discover_type(sock->sd, sock->mtu_discover_type, sock->info.af);
48f1d41a
 
 #if EXTENDED_SOCKET_ERROR_CAPABILITY
81d882d5
     /* if the OS supports it, enable extended error passing on the socket */
     set_sock_extended_error_passing(sock->sd);
48f1d41a
 #endif
 }
2b9b4c8a
 
d90428d1
 
48f1d41a
 static void
81d882d5
 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);
48f1d41a
 }
 
 static void
81d882d5
 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);
6fbf66fa
     }
 }
 
48f1d41a
 
 static void
81d882d5
 phase2_tcp_client(struct link_socket *sock, struct signal_info *sig_info)
48f1d41a
 {
81d882d5
     bool proxy_retry = false;
4cd4899e
     do
     {
81d882d5
         socket_connect(&sock->sd,
                        sock->info.lsa->current_remote->ai_addr,
                        get_server_poll_remaining_time(sock->server_poll_timeout),
                        sig_info);
23d61c56
 
81d882d5
         if (sig_info->signal_received)
         {
             return;
         }
23d61c56
 
81d882d5
         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);
         }
23d61c56
 
81d882d5
     } while (proxy_retry);
23d61c56
 
48f1d41a
 }
 
 static void
81d882d5
 phase2_socks_client(struct link_socket *sock, struct signal_info *sig_info)
48f1d41a
 {
81d882d5
     socket_connect(&sock->ctrl_sd,
                    sock->info.lsa->current_remote->ai_addr,
                    get_server_poll_remaining_time(sock->server_poll_timeout),
                    sig_info);
48f1d41a
 
23d61c56
     if (sig_info->signal_received)
81d882d5
     {
         return;
     }
48f1d41a
 
81d882d5
     establish_socks_proxy_udpassoc(sock->socks_proxy,
                                    sock->ctrl_sd,
                                    sock->sd,
                                    &sock->socks_relay.dest,
                                    &sig_info->signal_received);
48f1d41a
 
23d61c56
     if (sig_info->signal_received)
81d882d5
     {
         return;
     }
48f1d41a
 
     sock->remote_host = sock->proxy_dest_host;
     sock->remote_port = sock->proxy_dest_port;
 
     addr_zero_host(&sock->info.lsa->actual.dest);
23d61c56
     if (sock->info.lsa->remote_list)
81d882d5
     {
         freeaddrinfo(sock->info.lsa->remote_list);
         sock->info.lsa->current_remote = NULL;
         sock->info.lsa->remote_list = NULL;
     }
48f1d41a
 
81d882d5
     resolve_remote(sock, 1, NULL, &sig_info->signal_received);
48f1d41a
 }
 
6fbf66fa
 /* finalize socket initialization */
 void
81d882d5
 link_socket_init_phase2(struct link_socket *sock,
                         const struct frame *frame,
                         struct signal_info *sig_info)
 {
     const char *remote_dynamic = NULL;
     int sig_save = 0;
 
     ASSERT(sock);
     ASSERT(sig_info);
 
     if (sig_info->signal_received)
     {
         sig_save = sig_info->signal_received;
         sig_info->signal_received = 0;
     }
 
     /* initialize buffers */
     socket_frame_init(frame, sock);
 
     /*
      * Pass a remote name to connect/accept so that
      * they can test for dynamic IP address changes
      * and throw a SIGUSR1 if appropriate.
      */
     if (sock->resolve_retry_seconds)
     {
         remote_dynamic = sock->remote_host;
     }
 
     /* were we started by inetd or xinetd? */
     if (sock->inetd)
     {
         phase2_inetd(sock, frame, remote_dynamic,  &sig_info->signal_received);
         if (sig_info->signal_received)
         {
             goto done;
         }
 
     }
     else
     {
         /* Second chance to resolv/create socket */
         resolve_remote(sock, 2, &remote_dynamic,  &sig_info->signal_received);
 
         /* 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);
         }
 
         /* If socket has not already been created create it now */
         if (sock->sd == SOCKET_UNDEFINED)
         {
             /* 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)
             {
                 /* 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;
                 }
 
                 create_socket(sock, sock->info.lsa->bind_local);
             }
         }
 
         /* Socket still undefined, give a warning and abort connection */
         if (sock->sd == SOCKET_UNDEFINED)
         {
             msg(M_WARN, "Could not determine IPv4/IPv6 protocol");
             sig_info->signal_received = SIGUSR1;
             goto done;
         }
 
         if (sig_info->signal_received)
         {
             goto done;
         }
 
         if (sock->info.proto == PROTO_TCP_SERVER)
         {
             phase2_tcp_server(sock, remote_dynamic,
                               &sig_info->signal_received);
         }
         else if (sock->info.proto == PROTO_TCP_CLIENT)
         {
             phase2_tcp_client(sock, sig_info);
 
         }
         else if (sock->info.proto == PROTO_UDP && sock->socks_proxy)
         {
             phase2_socks_client(sock, sig_info);
         }
51187871
 #ifdef TARGET_ANDROID
81d882d5
         if (sock->sd != -1)
         {
             protect_fd_nonlocal(sock->sd, &sock->info.lsa->actual.dest.addr.sa);
         }
51187871
 #endif
81d882d5
         if (sig_info->signal_received)
         {
             goto done;
         }
6fbf66fa
     }
 
81d882d5
     phase2_set_socket_flags(sock);
     linksock_print_addr(sock);
6fbf66fa
 
81d882d5
 done:
     if (sig_save)
76a59eae
     {
81d882d5
         if (!sig_info->signal_received)
         {
             sig_info->signal_received = sig_save;
         }
76a59eae
     }
6fbf66fa
 }
 
 void
81d882d5
 link_socket_close(struct link_socket *sock)
6fbf66fa
 {
81d882d5
     if (sock)
6fbf66fa
     {
 #ifdef ENABLE_DEBUG
81d882d5
         const int gremlin = GREMLIN_CONNECTION_FLOOD_LEVEL(sock->gremlin);
6fbf66fa
 #else
81d882d5
         const int gremlin = 0;
6fbf66fa
 #endif
 
81d882d5
         if (socket_defined(sock->sd))
         {
445b192a
 #ifdef _WIN32
81d882d5
             close_net_event_win32(&sock->listen_handle, sock->sd, 0);
6fbf66fa
 #endif
81d882d5
             if (!gremlin)
             {
                 msg(D_LOW, "TCP/UDP: Closing socket");
                 if (openvpn_close_socket(sock->sd))
                 {
                     msg(M_WARN | M_ERRNO, "TCP/UDP: Close Socket failed");
                 }
             }
             sock->sd = SOCKET_UNDEFINED;
445b192a
 #ifdef _WIN32
81d882d5
             if (!gremlin)
             {
                 overlapped_io_close(&sock->reads);
                 overlapped_io_close(&sock->writes);
             }
6fbf66fa
 #endif
81d882d5
         }
6fbf66fa
 
81d882d5
         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;
         }
6fbf66fa
 
81d882d5
         stream_buf_close(&sock->stream_buf);
         free_buf(&sock->stream_buf_data);
         if (!gremlin)
         {
             free(sock);
         }
6fbf66fa
     }
 }
 
 /* for stream protocols, allow for packet length prefix */
 void
81d882d5
 socket_adjust_frame_parameters(struct frame *frame, int proto)
6fbf66fa
 {
81d882d5
     if (link_socket_proto_connection_oriented(proto))
     {
         frame_add_to_extra_frame(frame, sizeof(packet_size_type));
     }
6fbf66fa
 }
 
 void
81d882d5
 setenv_trusted(struct env_set *es, const struct link_socket_info *info)
6fbf66fa
 {
81d882d5
     setenv_link_socket_actual(es, "trusted", &info->lsa->actual, SA_IP_PORT);
6fbf66fa
 }
 
5a2e9a25
 static void
81d882d5
 ipchange_fmt(const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc)
5a2e9a25
 {
81d882d5
     const char *host = print_sockaddr_ex(&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT, gc);
     if (include_cmd)
25360912
     {
81d882d5
         argv_parse_cmd(argv, info->ipchange_command);
         argv_printf_cat(argv, "%s", host);
     }
     else
     {
         argv_printf(argv, "%s", host);
25360912
     }
d3310d2e
 
5a2e9a25
 }
 
6fbf66fa
 void
81d882d5
 link_socket_connection_initiated(const struct buffer *buf,
                                  struct link_socket_info *info,
                                  const struct link_socket_actual *act,
                                  const char *common_name,
                                  struct env_set *es)
6fbf66fa
 {
81d882d5
     struct gc_arena gc = gc_new();
6fbf66fa
 
81d882d5
     info->lsa->actual = *act; /* Note: skip this line for --force-dest */
     setenv_trusted(es, info);
     info->connection_established = true;
6fbf66fa
 
81d882d5
     /* Print connection initiated message, with common name if available */
     {
         struct buffer out = alloc_buf_gc(256, &gc);
         if (common_name)
         {
             buf_printf(&out, "[%s] ", common_name);
         }
         buf_printf(&out, "Peer Connection Initiated with %s", print_link_socket_actual(&info->lsa->actual, &gc));
         msg(M_INFO, "%s", BSTR(&out));
     }
 
     /* set environmental vars */
     setenv_str(es, "common_name", common_name);
6fbf66fa
 
81d882d5
     /* Process --ipchange plugin */
     if (plugin_defined(info->plugins, OPENVPN_PLUGIN_IPCHANGE))
6fbf66fa
     {
81d882d5
         struct argv argv = argv_new();
         ipchange_fmt(false, &argv, info, &gc);
         if (plugin_call(info->plugins, OPENVPN_PLUGIN_IPCHANGE, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
         {
             msg(M_WARN, "WARNING: ipchange plugin call failed");
         }
         argv_reset(&argv);
6fbf66fa
     }
 
81d882d5
     /* Process --ipchange option */
     if (info->ipchange_command)
6fbf66fa
     {
81d882d5
         struct argv argv = argv_new();
         setenv_str(es, "script_type", "ipchange");
         ipchange_fmt(true, &argv, info, &gc);
         openvpn_run_script(&argv, es, 0, "--ipchange");
         argv_reset(&argv);
6fbf66fa
     }
 
81d882d5
     gc_free(&gc);
6fbf66fa
 }
 
 void
81d882d5
 link_socket_bad_incoming_addr(struct buffer *buf,
                               const struct link_socket_info *info,
                               const struct link_socket_actual *from_addr)
 {
     struct gc_arena gc = gc_new();
     struct addrinfo *ai;
 
     switch (from_addr->dest.addr.sa.sa_family)
     {
         case AF_INET:
         case AF_INET6:
             msg(D_LINK_ERRORS,
                 "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_ex(info->lsa->remote_list->ai_addr,":",PS_SHOW_PORT, &gc));
             /* print additional remote addresses */
4cd4899e
             for (ai = info->lsa->remote_list->ai_next; ai; ai = ai->ai_next)
             {
81d882d5
                 msg(D_LINK_ERRORS,"or from peer address: %s",
                     print_sockaddr_ex(ai->ai_addr,":",PS_SHOW_PORT, &gc));
             }
             break;
d9c04efc
     }
81d882d5
     buf->len = 0;
     gc_free(&gc);
6fbf66fa
 }
 
 void
81d882d5
 link_socket_bad_outgoing_addr(void)
6fbf66fa
 {
81d882d5
     dmsg(D_READ_WRITE, "TCP/UDP: No outgoing address to send packet");
6fbf66fa
 }
 
 in_addr_t
81d882d5
 link_socket_current_remote(const struct link_socket_info *info)
6fbf66fa
 {
81d882d5
     const struct link_socket_addr *lsa = info->lsa;
6fbf66fa
 
81d882d5
 /*
  * This logic supports "redirect-gateway" semantic, which
8335caf9
  * makes sense only for PF_INET routes over PF_INET endpoints
  *
  * Maybe in the future consider PF_INET6 endpoints also ...
  * by now just ignore it
  *
23d61c56
  * For --remote entries with multiple addresses this
  * only return the actual endpoint we have sucessfully connected to
8335caf9
  */
81d882d5
     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 (lsa->current_remote)
     {
         return ntohl(((struct sockaddr_in *)lsa->current_remote->ai_addr)
                      ->sin_addr.s_addr);
     }
     else
     {
         return 0;
     }
6fbf66fa
 }
 
3ddb5643
 const struct in6_addr *
81d882d5
 link_socket_current_remote_ipv6(const struct link_socket_info *info)
3ddb5643
 {
81d882d5
     const struct link_socket_addr *lsa = info->lsa;
3ddb5643
 
 /* 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
  */
81d882d5
     if (lsa->actual.dest.addr.sa.sa_family != AF_INET6)
     {
         return NULL;
     }
3ddb5643
 
81d882d5
     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;
     }
3ddb5643
 }
 
6fbf66fa
 /*
  * Return a status string describing socket state.
  */
 const char *
81d882d5
 socket_stat(const struct link_socket *s, unsigned int rwflags, struct gc_arena *gc)
6fbf66fa
 {
81d882d5
     struct buffer out = alloc_buf_gc(64, gc);
     if (s)
6fbf66fa
     {
81d882d5
         if (rwflags & EVENT_READ)
         {
             buf_printf(&out, "S%s",
                        (s->rwflags_debug & EVENT_READ) ? "R" : "r");
445b192a
 #ifdef _WIN32
81d882d5
             buf_printf(&out, "%s",
                        overlapped_io_state_ascii(&s->reads));
6fbf66fa
 #endif
81d882d5
         }
         if (rwflags & EVENT_WRITE)
         {
             buf_printf(&out, "S%s",
                        (s->rwflags_debug & EVENT_WRITE) ? "W" : "w");
445b192a
 #ifdef _WIN32
81d882d5
             buf_printf(&out, "%s",
                        overlapped_io_state_ascii(&s->writes));
6fbf66fa
 #endif
81d882d5
         }
6fbf66fa
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         buf_printf(&out, "S?");
6fbf66fa
     }
81d882d5
     return BSTR(&out);
6fbf66fa
 }
 
 /*
  * Stream buffer functions, used to packetize a TCP
  * stream connection.
  */
 
 static inline void
81d882d5
 stream_buf_reset(struct stream_buf *sb)
6fbf66fa
 {
81d882d5
     dmsg(D_STREAM_DEBUG, "STREAM: RESET");
     sb->residual_fully_formed = false;
     sb->buf = sb->buf_init;
     buf_reset(&sb->next);
     sb->len = -1;
6fbf66fa
 }
 
 void
81d882d5
 stream_buf_init(struct stream_buf *sb,
                 struct buffer *buf,
                 const unsigned int sockflags,
                 const int proto)
 {
     sb->buf_init = *buf;
     sb->maxlen = sb->buf_init.len;
     sb->buf_init.len = 0;
     sb->residual = alloc_buf(sb->maxlen);
     sb->error = false;
6add6b2f
 #if PORT_SHARE
81d882d5
     sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCP_SERVER))
                            ? PS_ENABLED
                            : PS_DISABLED;
6add6b2f
 #endif
81d882d5
     stream_buf_reset(sb);
6fbf66fa
 
81d882d5
     dmsg(D_STREAM_DEBUG, "STREAM: INIT maxlen=%d", sb->maxlen);
6fbf66fa
 }
 
 static inline void
81d882d5
 stream_buf_set_next(struct stream_buf *sb)
6fbf66fa
 {
81d882d5
     /* set up 'next' for next i/o read */
     sb->next = sb->buf;
     sb->next.offset = sb->buf.offset + sb->buf.len;
     sb->next.len = (sb->len >= 0 ? sb->len : sb->maxlen) - sb->buf.len;
     dmsg(D_STREAM_DEBUG, "STREAM: SET NEXT, buf=[%d,%d] next=[%d,%d] len=%d maxlen=%d",
          sb->buf.offset, sb->buf.len,
          sb->next.offset, sb->next.len,
          sb->len, sb->maxlen);
     ASSERT(sb->next.len > 0);
     ASSERT(buf_safe(&sb->buf, sb->next.len));
6fbf66fa
 }
 
 static inline void
81d882d5
 stream_buf_get_final(struct stream_buf *sb, struct buffer *buf)
6fbf66fa
 {
81d882d5
     dmsg(D_STREAM_DEBUG, "STREAM: GET FINAL len=%d",
          buf_defined(&sb->buf) ? sb->buf.len : -1);
     ASSERT(buf_defined(&sb->buf));
     *buf = sb->buf;
6fbf66fa
 }
 
 static inline void
81d882d5
 stream_buf_get_next(struct stream_buf *sb, struct buffer *buf)
6fbf66fa
 {
81d882d5
     dmsg(D_STREAM_DEBUG, "STREAM: GET NEXT len=%d",
          buf_defined(&sb->next) ? sb->next.len : -1);
     ASSERT(buf_defined(&sb->next));
     *buf = sb->next;
6fbf66fa
 }
 
 bool
81d882d5
 stream_buf_read_setup_dowork(struct link_socket *sock)
6fbf66fa
 {
81d882d5
     if (sock->stream_buf.residual.len && !sock->stream_buf.residual_fully_formed)
6fbf66fa
     {
81d882d5
         ASSERT(buf_copy(&sock->stream_buf.buf, &sock->stream_buf.residual));
         ASSERT(buf_init(&sock->stream_buf.residual, 0));
         sock->stream_buf.residual_fully_formed = stream_buf_added(&sock->stream_buf, 0);
         dmsg(D_STREAM_DEBUG, "STREAM: RESIDUAL FULLY FORMED [%s], len=%d",
              sock->stream_buf.residual_fully_formed ? "YES" : "NO",
              sock->stream_buf.residual.len);
6fbf66fa
     }
 
81d882d5
     if (!sock->stream_buf.residual_fully_formed)
     {
         stream_buf_set_next(&sock->stream_buf);
     }
     return !sock->stream_buf.residual_fully_formed;
6fbf66fa
 }
 
 bool
81d882d5
 stream_buf_added(struct stream_buf *sb,
                  int length_added)
6fbf66fa
 {
81d882d5
     dmsg(D_STREAM_DEBUG, "STREAM: ADD length_added=%d", length_added);
     if (length_added > 0)
     {
         sb->buf.len += length_added;
     }
6fbf66fa
 
81d882d5
     /* if length unknown, see if we can get the length prefix from
      * the head of the buffer */
     if (sb->len < 0 && sb->buf.len >= (int) sizeof(packet_size_type))
6fbf66fa
     {
81d882d5
         packet_size_type net_size;
6add6b2f
 
 #if PORT_SHARE
81d882d5
         if (sb->port_share_state == PS_ENABLED)
         {
             if (!is_openvpn_protocol(&sb->buf))
             {
                 msg(D_STREAM_ERRORS, "Non-OpenVPN client protocol detected");
                 sb->port_share_state = PS_FOREIGN;
                 sb->error = true;
                 return false;
             }
             else
             {
                 sb->port_share_state = PS_DISABLED;
             }
         }
6add6b2f
 #endif
 
81d882d5
         ASSERT(buf_read(&sb->buf, &net_size, sizeof(net_size)));
         sb->len = ntohps(net_size);
6fbf66fa
 
81d882d5
         if (sb->len < 1 || sb->len > sb->maxlen)
         {
             msg(M_WARN, "WARNING: Bad encapsulated packet length from peer (%d), which must be > 0 and <= %d -- please ensure that --tun-mtu or --link-mtu is equal on both peers -- this condition could also indicate a possible active attack on the TCP link -- [Attempting restart...]", sb->len, sb->maxlen);
             stream_buf_reset(sb);
             sb->error = true;
             return false;
         }
6fbf66fa
     }
 
81d882d5
     /* is our incoming packet fully read? */
     if (sb->len > 0 && sb->buf.len >= sb->len)
6fbf66fa
     {
81d882d5
         /* save any residual data that's part of the next packet */
         ASSERT(buf_init(&sb->residual, 0));
         if (sb->buf.len > sb->len)
         {
             ASSERT(buf_copy_excess(&sb->residual, &sb->buf, sb->len));
         }
         dmsg(D_STREAM_DEBUG, "STREAM: ADD returned TRUE, buf_len=%d, residual_len=%d",
              BLEN(&sb->buf),
              BLEN(&sb->residual));
         return true;
6fbf66fa
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         dmsg(D_STREAM_DEBUG, "STREAM: ADD returned FALSE (have=%d need=%d)", sb->buf.len, sb->len);
         stream_buf_set_next(sb);
         return false;
6fbf66fa
     }
 }
 
 void
81d882d5
 stream_buf_close(struct stream_buf *sb)
6fbf66fa
 {
81d882d5
     free_buf(&sb->residual);
6fbf66fa
 }
 
 /*
  * The listen event is a special event whose sole purpose is
  * to tell us that there's a new incoming connection on a
  * TCP socket, for use in server mode.
  */
 event_t
81d882d5
 socket_listen_event_handle(struct link_socket *s)
6fbf66fa
 {
445b192a
 #ifdef _WIN32
81d882d5
     if (!defined_net_event_win32(&s->listen_handle))
     {
         init_net_event_win32(&s->listen_handle, FD_ACCEPT, s->sd, 0);
     }
     return &s->listen_handle;
 #else  /* ifdef _WIN32 */
     return s->sd;
6fbf66fa
 #endif
 }
 
 /*
  * Format IP addresses in ascii
  */
 
 const char *
81d882d5
 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 = false;
     char hostaddr[NI_MAXHOST] = "";
     char servname[NI_MAXSERV] = "";
     int status;
 
     socklen_t salen = 0;
     switch (sa->sa_family)
     {
         case AF_INET:
             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;
d3310d2e
 
81d882d5
         case AF_INET6:
             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);
d9c04efc
     }
d3310d2e
 
81d882d5
     status = getnameinfo(sa, salen, hostaddr, sizeof(hostaddr),
                          servname, sizeof(servname), NI_NUMERICHOST | NI_NUMERICSERV);
d3310d2e
 
81d882d5
     if (status!=0)
     {
         buf_printf(&out,"[nameinfo() err: %s]",gai_strerror(status));
         return BSTR(&out);
     }
d3310d2e
 
81d882d5
     if (!(flags & PS_DONT_SHOW_ADDR))
d3310d2e
     {
81d882d5
         if (addr_is_defined)
         {
             buf_puts(&out, hostaddr);
         }
         else
         {
             buf_puts(&out, "[undef]");
         }
d3310d2e
     }
 
81d882d5
     if ((flags & PS_SHOW_PORT) || (flags & PS_SHOW_PORT_IF_DEFINED))
d3310d2e
     {
81d882d5
         if (separator)
         {
             buf_puts(&out, separator);
         }
d3310d2e
 
81d882d5
         buf_puts(&out, servname);
d3310d2e
     }
 
81d882d5
     return BSTR(&out);
8bc93d7f
 }
 
 const char *
81d882d5
 print_link_socket_actual(const struct link_socket_actual *act, struct gc_arena *gc)
8bc93d7f
 {
81d882d5
     return print_link_socket_actual_ex(act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc);
8bc93d7f
 }
 
6dbf82a9
 #ifndef IF_NAMESIZE
 #define IF_NAMESIZE 16
 #endif
 
8bc93d7f
 const char *
81d882d5
 print_link_socket_actual_ex(const struct link_socket_actual *act,
                             const char *separator,
                             const unsigned int flags,
                             struct gc_arena *gc)
8bc93d7f
 {
81d882d5
     if (act)
8bc93d7f
     {
81d882d5
         char ifname[IF_NAMESIZE] = "[undef]";
         struct buffer out = alloc_buf_gc(128, gc);
         buf_printf(&out, "%s", print_sockaddr_ex(&act->dest.addr.sa, separator, flags, gc));
8bc93d7f
 #if ENABLE_IP_PKTINFO
81d882d5
         if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act))
         {
             switch (act->dest.addr.sa.sa_family)
             {
                 case AF_INET:
                 {
                     struct openvpn_sockaddr sa;
                     CLEAR(sa);
                     sa.addr.in4.sin_family = AF_INET;
7efa60d9
 #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
81d882d5
                     sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst;
                     if_indextoname(act->pi.in4.ipi_ifindex, ifname);
d3774cdf
 #elif defined(IP_RECVDSTADDR)
81d882d5
                     sa.addr.in4.sin_addr = act->pi.in4;
                     ifname[0] = 0;
 #else  /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
d3774cdf
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
81d882d5
                     buf_printf(&out, " (via %s%%%s)",
                                print_sockaddr_ex(&sa.addr.sa, separator, 0, gc),
                                ifname);
                 }
                 break;
 
                 case AF_INET6:
                 {
                     struct sockaddr_in6 sin6;
                     char buf[INET6_ADDRSTRLEN] = "[undef]";
                     CLEAR(sin6);
                     sin6.sin6_family = AF_INET6;
                     sin6.sin6_addr = act->pi.in6.ipi6_addr;
                     if_indextoname(act->pi.in6.ipi6_ifindex, ifname);
                     if (getnameinfo((struct sockaddr *)&sin6, sizeof(struct sockaddr_in6),
                                     buf, sizeof(buf), NULL, 0, NI_NUMERICHOST) == 0)
                     {
                         buf_printf(&out, " (via %s%%%s)", buf, ifname);
                     }
                     else
                     {
                         buf_printf(&out, " (via [getnameinfo() err]%%%s)", ifname);
                     }
                 }
                 break;
             }
         }
 #endif /* if ENABLE_IP_PKTINFO */
         return BSTR(&out);
     }
     else
     {
         return "[NULL]";
8bc93d7f
     }
6fbf66fa
 }
 
 /*
  * Convert an in_addr_t in host byte order
  * to an ascii dotted quad.
  */
 const char *
81d882d5
 print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
6fbf66fa
 {
81d882d5
     struct in_addr ia;
     struct buffer out = alloc_buf_gc(64, gc);
6fbf66fa
 
81d882d5
     if (addr || !(flags & IA_EMPTY_IF_UNDEF))
6fbf66fa
     {
81d882d5
         CLEAR(ia);
         ia.s_addr = (flags & IA_NET_ORDER) ? addr : htonl(addr);
6fbf66fa
 
81d882d5
         buf_printf(&out, "%s", inet_ntoa(ia));
6fbf66fa
     }
81d882d5
     return BSTR(&out);
6fbf66fa
 }
 
512cda46
 /*
  * Convert an in6_addr in host byte order
  * to an ascii representation of an IPv6 address
  */
 const char *
81d882d5
 print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
512cda46
 {
81d882d5
     struct buffer out = alloc_buf_gc(64, gc);
     char tmp_out_buf[64];       /* inet_ntop wants pointer to buffer */
512cda46
 
81d882d5
     if (memcmp(&a6, &in6addr_any, sizeof(a6)) != 0
         || !(flags & IA_EMPTY_IF_UNDEF))
512cda46
     {
81d882d5
         inet_ntop(AF_INET6, &a6, tmp_out_buf, sizeof(tmp_out_buf)-1);
         buf_printf(&out, "%s", tmp_out_buf );
512cda46
     }
81d882d5
     return BSTR(&out);
512cda46
 }
 
1ffdb2c9
 #ifndef UINT8_MAX
81d882d5
 #define UINT8_MAX 0xff
1ffdb2c9
 #endif
 
512cda46
 /* add some offset to an ipv6 address
1ffdb2c9
  * (add in steps of 8 bits, taking overflow into next round)
512cda46
  */
81d882d5
 struct in6_addr
 add_in6_addr( struct in6_addr base, uint32_t add )
512cda46
 {
     int i;
 
81d882d5
     for (i = 15; i>=0 && add > 0; i--)
512cda46
     {
81d882d5
         register int carry;
         register uint32_t h;
1ffdb2c9
 
81d882d5
         h = (unsigned char) base.s6_addr[i];
         base.s6_addr[i] = (h+add) & UINT8_MAX;
1ffdb2c9
 
81d882d5
         /* using explicit carry for the 8-bit additions will catch
1ffdb2c9
          * 8-bit and(!) 32-bit overruns nicely
512cda46
          */
81d882d5
         carry = ((h & 0xff)  + (add & 0xff)) >> 8;
         add = (add>>8) + carry;
512cda46
     }
     return base;
 }
 
6fbf66fa
 /* set environmental variables for ip/port in *addr */
 void
81d882d5
 setenv_sockaddr(struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const unsigned int flags)
 {
     char name_buf[256];
 
     char buf[128];
     switch (addr->addr.sa.sa_family)
     {
         case AF_INET:
             if (flags & SA_IP_PORT)
             {
                 openvpn_snprintf(name_buf, sizeof(name_buf), "%s_ip", name_prefix);
             }
             else
             {
                 openvpn_snprintf(name_buf, sizeof(name_buf), "%s", name_prefix);
             }
 
             setenv_str(es, name_buf, inet_ntoa(addr->addr.in4.sin_addr));
 
             if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port)
             {
                 openvpn_snprintf(name_buf, sizeof(name_buf), "%s_port", name_prefix);
                 setenv_int(es, name_buf, ntohs(addr->addr.in4.sin_port));
             }
             break;
 
         case AF_INET6:
             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)
             {
                 openvpn_snprintf(name_buf, sizeof(name_buf), "%s_port", name_prefix);
                 setenv_int(es, name_buf, ntohs(addr->addr.in6.sin6_port));
             }
             break;
d9c04efc
     }
6fbf66fa
 }
 
 void
81d882d5
 setenv_in_addr_t(struct env_set *es, const char *name_prefix, in_addr_t addr, const unsigned int flags)
6fbf66fa
 {
81d882d5
     if (addr || !(flags & SA_SET_IF_NONZERO))
6fbf66fa
     {
81d882d5
         struct openvpn_sockaddr si;
         CLEAR(si);
         si.addr.in4.sin_family = AF_INET;
         si.addr.in4.sin_addr.s_addr = htonl(addr);
         setenv_sockaddr(es, name_prefix, &si, flags);
6fbf66fa
     }
 }
 
8bc93d7f
 void
81d882d5
 setenv_in6_addr(struct env_set *es,
                 const char *name_prefix,
                 const struct in6_addr *addr,
                 const unsigned int flags)
a8f8b926
 {
81d882d5
     if (!IN6_IS_ADDR_UNSPECIFIED(addr) || !(flags & SA_SET_IF_NONZERO))
a8f8b926
     {
81d882d5
         struct openvpn_sockaddr si;
         CLEAR(si);
         si.addr.in6.sin6_family = AF_INET6;
         si.addr.in6.sin6_addr = *addr;
         setenv_sockaddr(es, name_prefix, &si, flags);
a8f8b926
     }
 }
 
 void
81d882d5
 setenv_link_socket_actual(struct env_set *es,
                           const char *name_prefix,
                           const struct link_socket_actual *act,
                           const unsigned int flags)
8bc93d7f
 {
81d882d5
     setenv_sockaddr(es, name_prefix, &act->dest, flags);
8bc93d7f
 }
 
6fbf66fa
 /*
  * Convert protocol names between index and ascii form.
  */
 
 struct proto_names {
81d882d5
     const char *short_form;
     const char *display_form;
     sa_family_t proto_af;
     int proto;
6fbf66fa
 };
 
 /* Indexed by PROTO_x */
30077d1f
 static const struct proto_names proto_names[] = {
81d882d5
     {"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},
6fbf66fa
 };
 
8335caf9
 bool
 proto_is_net(int proto)
 {
81d882d5
     if (proto < 0 || proto >= PROTO_N)
     {
         ASSERT(0);
     }
30077d1f
     return proto != PROTO_NONE;
8335caf9
 }
 bool
 proto_is_dgram(int proto)
 {
30077d1f
     return proto_is_udp(proto);
8335caf9
 }
30077d1f
 
8335caf9
 bool
 proto_is_udp(int proto)
 {
81d882d5
     if (proto < 0 || proto >= PROTO_N)
     {
         ASSERT(0);
     }
     return proto == PROTO_UDP;
8335caf9
 }
30077d1f
 
8335caf9
 bool
 proto_is_tcp(int proto)
 {
81d882d5
     if (proto < 0 || proto >= PROTO_N)
     {
         ASSERT(0);
     }
     return proto == PROTO_TCP_CLIENT || proto == PROTO_TCP_SERVER;
8335caf9
 }
 
6fbf66fa
 int
81d882d5
 ascii2proto(const char *proto_name)
6fbf66fa
 {
81d882d5
     int i;
     for (i = 0; i < SIZE(proto_names); ++i)
4cd4899e
     {
81d882d5
         if (!strcmp(proto_name, proto_names[i].short_form))
         {
             return proto_names[i].proto;
         }
4cd4899e
     }
81d882d5
     return -1;
6fbf66fa
 }
 
30077d1f
 sa_family_t
81d882d5
 ascii2af(const char *proto_name)
30077d1f
 {
     int i;
81d882d5
     for (i = 0; i < SIZE(proto_names); ++i)
4cd4899e
     {
81d882d5
         if (!strcmp(proto_name, proto_names[i].short_form))
         {
30077d1f
             return proto_names[i].proto_af;
81d882d5
         }
4cd4899e
     }
30077d1f
     return 0;
 }
 
6fbf66fa
 const char *
81d882d5
 proto2ascii(int proto, sa_family_t af, bool display_form)
6fbf66fa
 {
81d882d5
     unsigned int i;
     for (i = 0; i < SIZE(proto_names); ++i)
30077d1f
     {
81d882d5
         if (proto_names[i].proto_af == af && proto_names[i].proto == proto)
30077d1f
         {
81d882d5
             if (display_form)
             {
                 return proto_names[i].display_form;
             }
             else
             {
                 return proto_names[i].short_form;
             }
30077d1f
         }
     }
 
81d882d5
     return "[unknown protocol]";
6fbf66fa
 }
 
 const char *
81d882d5
 proto2ascii_all(struct gc_arena *gc)
6fbf66fa
 {
81d882d5
     struct buffer out = alloc_buf_gc(256, gc);
     int i;
6fbf66fa
 
81d882d5
     for (i = 0; i < SIZE(proto_names); ++i)
6fbf66fa
     {
81d882d5
         if (i)
         {
             buf_printf(&out, " ");
         }
         buf_printf(&out, "[%s]", proto_names[i].short_form);
6fbf66fa
     }
81d882d5
     return BSTR(&out);
6fbf66fa
 }
 
8335caf9
 const char *
81d882d5
 addr_family_name(int af)
8335caf9
 {
81d882d5
     switch (af)
51afc8b8
     {
81d882d5
         case AF_INET:  return "AF_INET";
 
         case AF_INET6: return "AF_INET6";
51afc8b8
     }
81d882d5
     return "AF_UNSPEC";
8335caf9
 }
 
6fbf66fa
 /*
  * Given a local proto, return local proto
  * if !remote, or compatible remote proto
  * if remote.
  *
  * This is used for options compatibility
  * checking.
38727e09
  *
  * IPv6 and IPv4 protocols are comptabile but OpenVPN
  * has always sent UDPv4, TCPv4 over the wire. Keep these
  * strings for backward compatbility
6fbf66fa
  */
81d882d5
 const char *
 proto_remote(int proto, bool remote)
6fbf66fa
 {
81d882d5
     ASSERT(proto >= 0 && proto < PROTO_N);
     if (proto == PROTO_UDP)
     {
         return "UDPv4";
     }
34136dd8
 
81d882d5
     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";
     }
34136dd8
 
81d882d5
     ASSERT(0);
     return ""; /* Make the compiler happy */
6fbf66fa
 }
 
 /*
  * Bad incoming address lengths that differ from what
  * we expect are considered to be fatal errors.
  */
 void
81d882d5
 bad_address_length(int actual, int expected)
6fbf66fa
 {
81d882d5
     msg(M_FATAL, "ERROR: received strange incoming packet with an address length of %d -- we only accept address lengths of %d.",
         actual,
         expected);
6fbf66fa
 }
 
 /*
  * Socket Read Routines
  */
 
 int
81d882d5
 link_socket_read_tcp(struct link_socket *sock,
                      struct buffer *buf)
6fbf66fa
 {
81d882d5
     int len = 0;
6fbf66fa
 
81d882d5
     if (!sock->stream_buf.residual_fully_formed)
6fbf66fa
     {
445b192a
 #ifdef _WIN32
81d882d5
         len = socket_finalize(sock->sd, &sock->reads, buf, NULL);
6fbf66fa
 #else
81d882d5
         struct buffer frag;
         stream_buf_get_next(&sock->stream_buf, &frag);
         len = recv(sock->sd, BPTR(&frag), BLEN(&frag), MSG_NOSIGNAL);
6fbf66fa
 #endif
 
81d882d5
         if (!len)
         {
             sock->stream_reset = true;
         }
         if (len <= 0)
         {
             return buf->len = len;
         }
6fbf66fa
     }
 
81d882d5
     if (sock->stream_buf.residual_fully_formed
         || stream_buf_added(&sock->stream_buf, len)) /* packet complete? */
6fbf66fa
     {
81d882d5
         stream_buf_get_final(&sock->stream_buf, buf);
         stream_buf_reset(&sock->stream_buf);
         return buf->len;
     }
     else
     {
         return buf->len = 0; /* no error, but packet is still incomplete */
6fbf66fa
     }
 }
 
445b192a
 #ifndef _WIN32
6fbf66fa
 
8bc93d7f
 #if ENABLE_IP_PKTINFO
 
3fb246e3
 /* make the buffer large enough to handle ancilliary socket data for
  * both IPv4 and IPv6 destination addresses, plus padding (see RFC 2292)
  */
7efa60d9
 #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
81d882d5
 #define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof(struct in6_pktinfo)), \
                                   CMSG_SPACE(sizeof(struct in_pktinfo)) )
3fb246e3
 #else
81d882d5
 #define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof(struct in6_pktinfo)), \
                                   CMSG_SPACE(sizeof(struct in_addr)) )
d3774cdf
 #endif
8bc93d7f
 
 static socklen_t
81d882d5
 link_socket_read_udp_posix_recvmsg(struct link_socket *sock,
                                    struct buffer *buf,
                                    struct link_socket_actual *from)
 {
     struct iovec iov;
     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 = 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 = pktinfo_buf;
     mesg.msg_controllen = sizeof pktinfo_buf;
     buf->len = recvmsg(sock->sd, &mesg, 0);
     if (buf->len >= 0)
     {
         struct cmsghdr *cmsg;
         fromlen = mesg.msg_namelen;
         cmsg = CMSG_FIRSTHDR(&mesg);
         if (cmsg != NULL
             && CMSG_NXTHDR(&mesg, cmsg) == NULL
7efa60d9
 #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
81d882d5
             && cmsg->cmsg_level == SOL_IP
             && cmsg->cmsg_type == IP_PKTINFO
             && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_pktinfo)) )
d3774cdf
 #elif defined(IP_RECVDSTADDR)
81d882d5
             && cmsg->cmsg_level == IPPROTO_IP
             && cmsg->cmsg_type == IP_RECVDSTADDR
             && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_addr)) )
 #else  /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
d3774cdf
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
81d882d5
         {
7efa60d9
 #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
81d882d5
             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;
d3774cdf
 #elif defined(IP_RECVDSTADDR)
81d882d5
             from->pi.in4 = *(struct in_addr *) CMSG_DATA(cmsg);
 #else  /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
d3774cdf
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
81d882d5
         }
         else if (cmsg != NULL
                  && CMSG_NXTHDR(&mesg, cmsg) == NULL
                  && cmsg->cmsg_level == IPPROTO_IPV6
                  && cmsg->cmsg_type == IPV6_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;
8bc93d7f
 }
81d882d5
 #endif /* if ENABLE_IP_PKTINFO */
8bc93d7f
 
6fbf66fa
 int
81d882d5
 link_socket_read_udp_posix(struct link_socket *sock,
                            struct buffer *buf,
                            struct link_socket_actual *from)
6fbf66fa
 {
81d882d5
     socklen_t fromlen = sizeof(from->dest.addr);
     socklen_t expectedlen = af_addr_size(sock->info.af);
     addr_zero_host(&from->dest);
8bc93d7f
 #if ENABLE_IP_PKTINFO
81d882d5
     /* Both PROTO_UDPv4 and PROTO_UDPv6 */
     if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO)
     {
         fromlen = link_socket_read_udp_posix_recvmsg(sock, buf, from);
     }
     else
8bc93d7f
 #endif
81d882d5
     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;
6fbf66fa
 }
 
81d882d5
 #endif /* ifndef _WIN32 */
6fbf66fa
 
 /*
  * Socket Write Routines
  */
 
 int
81d882d5
 link_socket_write_tcp(struct link_socket *sock,
                       struct buffer *buf,
                       struct link_socket_actual *to)
 {
     packet_size_type len = BLEN(buf);
     dmsg(D_STREAM_DEBUG, "STREAM: WRITE %d offset=%d", (int)len, buf->offset);
     ASSERT(len <= sock->stream_buf.maxlen);
     len = htonps(len);
     ASSERT(buf_write_prepend(buf, &len, sizeof(len)));
445b192a
 #ifdef _WIN32
81d882d5
     return link_socket_write_win32(sock, buf, to);
6fbf66fa
 #else
81d882d5
     return link_socket_write_tcp_posix(sock, buf, to);
6fbf66fa
 #endif
 }
 
8bc93d7f
 #if ENABLE_IP_PKTINFO
 
23d61c56
 size_t
81d882d5
 link_socket_write_udp_posix_sendmsg(struct link_socket *sock,
                                     struct buffer *buf,
                                     struct link_socket_actual *to)
 {
     struct iovec iov;
     struct msghdr mesg;
     struct cmsghdr *cmsg;
     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 (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 = pktinfo_buf;
             mesg.msg_flags = 0;
7efa60d9
 #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
81d882d5
             mesg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
             cmsg = CMSG_FIRSTHDR(&mesg);
             cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
             cmsg->cmsg_level = SOL_IP;
             cmsg->cmsg_type = IP_PKTINFO;
             {
                 struct in_pktinfo *pkti;
                 pkti = (struct in_pktinfo *) CMSG_DATA(cmsg);
                 pkti->ipi_ifindex = to->pi.in4.ipi_ifindex;
                 pkti->ipi_spec_dst = to->pi.in4.ipi_spec_dst;
                 pkti->ipi_addr.s_addr = 0;
             }
d3774cdf
 #elif defined(IP_RECVDSTADDR)
81d882d5
             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));
             cmsg->cmsg_level = IPPROTO_IP;
             cmsg->cmsg_type = IP_RECVDSTADDR;
             *(struct in_addr *) CMSG_DATA(cmsg) = to->pi.in4;
 #else  /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
d3774cdf
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
81d882d5
 #endif /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
             break;
         }
 
         case AF_INET6:
         {
             struct in6_pktinfo *pkti6;
             mesg.msg_name = &to->dest.addr.sa;
             mesg.msg_namelen = sizeof(struct sockaddr_in6);
 
             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 = 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;
             break;
         }
 
         default: ASSERT(0);
     }
     return sendmsg(sock->sd, &mesg, 0);
8bc93d7f
 }
 
81d882d5
 #endif /* if ENABLE_IP_PKTINFO */
8bc93d7f
 
6fbf66fa
 /*
  * Win32 overlapped socket I/O functions.
  */
 
445b192a
 #ifdef _WIN32
6fbf66fa
 
 int
81d882d5
 socket_recv_queue(struct link_socket *sock, int maxsize)
 {
     if (sock->reads.iostate == IOSTATE_INITIAL)
     {
         WSABUF wsabuf[1];
         int status;
 
         /* reset buf to its initial state */
         if (proto_is_udp(sock->info.proto))
         {
             sock->reads.buf = sock->reads.buf_init;
         }
         else if (proto_is_tcp(sock->info.proto))
         {
             stream_buf_get_next(&sock->stream_buf, &sock->reads.buf);
         }
         else
         {
             ASSERT(0);
         }
 
         /* Win32 docs say it's okay to allocate the wsabuf on the stack */
         wsabuf[0].buf = BPTR(&sock->reads.buf);
         wsabuf[0].len = maxsize ? maxsize : BLEN(&sock->reads.buf);
 
         /* check for buffer overflow */
         ASSERT(wsabuf[0].len <= BLEN(&sock->reads.buf));
 
         /* the overlapped read will signal this event on I/O completion */
         ASSERT(ResetEvent(sock->reads.overlapped.hEvent));
         sock->reads.flags = 0;
 
         if (proto_is_udp(sock->info.proto))
         {
             sock->reads.addr_defined = true;
             sock->reads.addrlen = sizeof(sock->reads.addr6);
             status = WSARecvFrom(
                 sock->sd,
                 wsabuf,
                 1,
                 &sock->reads.size,
                 &sock->reads.flags,
                 (struct sockaddr *) &sock->reads.addr,
                 &sock->reads.addrlen,
                 &sock->reads.overlapped,
                 NULL);
         }
         else if (proto_is_tcp(sock->info.proto))
         {
             sock->reads.addr_defined = false;
             status = WSARecv(
                 sock->sd,
                 wsabuf,
                 1,
                 &sock->reads.size,
                 &sock->reads.flags,
                 &sock->reads.overlapped,
                 NULL);
         }
         else
         {
             status = 0;
             ASSERT(0);
         }
 
         if (!status) /* operation completed immediately? */
         {
             /* 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 */
             ASSERT(SetEvent(sock->reads.overlapped.hEvent));
             sock->reads.status = 0;
 
             dmsg(D_WIN32_IO, "WIN32 I/O: Socket Receive immediate return [%d,%d]",
                  (int) wsabuf[0].len,
                  (int) sock->reads.size);
         }
         else
         {
             status = WSAGetLastError();
             if (status == WSA_IO_PENDING) /* operation queued? */
             {
                 sock->reads.iostate = IOSTATE_QUEUED;
                 sock->reads.status = status;
                 dmsg(D_WIN32_IO, "WIN32 I/O: Socket Receive queued [%d]",
                      (int) wsabuf[0].len);
             }
             else /* error occurred */
             {
                 struct gc_arena gc = gc_new();
                 ASSERT(SetEvent(sock->reads.overlapped.hEvent));
                 sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
                 sock->reads.status = status;
                 dmsg(D_WIN32_IO, "WIN32 I/O: Socket Receive error [%d]: %s",
                      (int) wsabuf[0].len,
                      strerror_win32(status, &gc));
                 gc_free(&gc);
             }
         }
     }
     return sock->reads.iostate;
6fbf66fa
 }
 
 int
81d882d5
 socket_send_queue(struct link_socket *sock, struct buffer *buf, const struct link_socket_actual *to)
 {
     if (sock->writes.iostate == IOSTATE_INITIAL)
     {
         WSABUF wsabuf[1];
         int status;
 
         /* make a private copy of buf */
         sock->writes.buf = sock->writes.buf_init;
         sock->writes.buf.len = 0;
         ASSERT(buf_copy(&sock->writes.buf, buf));
 
         /* Win32 docs say it's okay to allocate the wsabuf on the stack */
         wsabuf[0].buf = BPTR(&sock->writes.buf);
         wsabuf[0].len = BLEN(&sock->writes.buf);
 
         /* the overlapped write will signal this event on I/O completion */
         ASSERT(ResetEvent(sock->writes.overlapped.hEvent));
         sock->writes.flags = 0;
 
         if (proto_is_udp(sock->info.proto))
         {
             /* set destination address for UDP writes */
             sock->writes.addr_defined = true;
             if (to->dest.addr.sa.sa_family == AF_INET6)
             {
                 sock->writes.addr6 = to->dest.addr.in6;
                 sock->writes.addrlen = sizeof(sock->writes.addr6);
             }
             else
             {
                 sock->writes.addr = to->dest.addr.in4;
                 sock->writes.addrlen = sizeof(sock->writes.addr);
             }
 
             status = WSASendTo(
                 sock->sd,
                 wsabuf,
                 1,
                 &sock->writes.size,
                 sock->writes.flags,
                 (struct sockaddr *) &sock->writes.addr,
                 sock->writes.addrlen,
                 &sock->writes.overlapped,
                 NULL);
         }
         else if (proto_is_tcp(sock->info.proto))
         {
             /* destination address for TCP writes was established on connection initiation */
             sock->writes.addr_defined = false;
 
             status = WSASend(
                 sock->sd,
                 wsabuf,
                 1,
                 &sock->writes.size,
                 sock->writes.flags,
                 &sock->writes.overlapped,
                 NULL);
         }
         else
         {
             status = 0;
             ASSERT(0);
         }
 
         if (!status) /* operation completed immediately? */
         {
             sock->writes.iostate = IOSTATE_IMMEDIATE_RETURN;
 
             /* since we got an immediate return, we must signal the event object ourselves */
             ASSERT(SetEvent(sock->writes.overlapped.hEvent));
 
             sock->writes.status = 0;
 
             dmsg(D_WIN32_IO, "WIN32 I/O: Socket Send immediate return [%d,%d]",
                  (int) wsabuf[0].len,
                  (int) sock->writes.size);
         }
         else
         {
             status = WSAGetLastError();
             if (status == WSA_IO_PENDING) /* operation queued? */
             {
                 sock->writes.iostate = IOSTATE_QUEUED;
                 sock->writes.status = status;
                 dmsg(D_WIN32_IO, "WIN32 I/O: Socket Send queued [%d]",
                      (int) wsabuf[0].len);
             }
             else /* error occurred */
             {
                 struct gc_arena gc = gc_new();
                 ASSERT(SetEvent(sock->writes.overlapped.hEvent));
                 sock->writes.iostate = IOSTATE_IMMEDIATE_RETURN;
                 sock->writes.status = status;
 
                 dmsg(D_WIN32_IO, "WIN32 I/O: Socket Send error [%d]: %s",
                      (int) wsabuf[0].len,
                      strerror_win32(status, &gc));
 
                 gc_free(&gc);
             }
         }
     }
     return sock->writes.iostate;
6fbf66fa
 }
 
 int
81d882d5
 socket_finalize(SOCKET s,
                 struct overlapped_io *io,
                 struct buffer *buf,
                 struct link_socket_actual *from)
 {
     int ret = -1;
     BOOL status;
 
     switch (io->iostate)
     {
         case IOSTATE_QUEUED:
             status = WSAGetOverlappedResult(
                 s,
                 &io->overlapped,
                 &io->size,
                 FALSE,
                 &io->flags
                 );
             if (status)
             {
                 /* successful return for a queued operation */
                 if (buf)
                 {
                     *buf = io->buf;
                 }
                 ret = io->size;
                 io->iostate = IOSTATE_INITIAL;
                 ASSERT(ResetEvent(io->overlapped.hEvent));
 
                 dmsg(D_WIN32_IO, "WIN32 I/O: Socket Completion success [%d]", ret);
             }
             else
             {
                 /* error during a queued operation */
                 ret = -1;
                 if (WSAGetLastError() != WSA_IO_INCOMPLETE)
                 {
                     /* if no error (i.e. just not finished yet), then DON'T execute this code */
                     io->iostate = IOSTATE_INITIAL;
                     ASSERT(ResetEvent(io->overlapped.hEvent));
                     msg(D_WIN32_IO | M_ERRNO, "WIN32 I/O: Socket Completion error");
                 }
             }
             break;
 
         case IOSTATE_IMMEDIATE_RETURN:
             io->iostate = IOSTATE_INITIAL;
             ASSERT(ResetEvent(io->overlapped.hEvent));
             if (io->status)
             {
                 /* error return for a non-queued operation */
                 WSASetLastError(io->status);
                 ret = -1;
                 msg(D_WIN32_IO | M_ERRNO, "WIN32 I/O: Socket Completion non-queued error");
             }
             else
             {
                 /* successful return for a non-queued operation */
                 if (buf)
                 {
                     *buf = io->buf;
                 }
                 ret = io->size;
                 dmsg(D_WIN32_IO, "WIN32 I/O: Socket Completion non-queued success [%d]", ret);
             }
             break;
 
         case IOSTATE_INITIAL: /* were we called without proper queueing? */
             WSASetLastError(WSAEINVAL);
             ret = -1;
             dmsg(D_WIN32_IO, "WIN32 I/O: Socket Completion BAD STATE");
             break;
 
         default:
             ASSERT(0);
     }
 
     /* return from address if requested */
     if (from)
     {
         if (ret >= 0 && io->addr_defined)
         {
             /* TODO(jjo): streamline this mess */
             /* in this func we dont have relevant info about the PF_ of this
              * endpoint, as link_socket_actual will be zero for the 1st received packet
              *
              * Test for inets PF_ possible sizes
              */
             switch (io->addrlen)
             {
                 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*/
                 case sizeof(struct sockaddr_in6)-4:
                     break;
 
                 default:
                     bad_address_length(io->addrlen, af_addr_size(io->addr.sin_family));
             }
 
             switch (io->addr.sin_family)
             {
                 case AF_INET:
                     from->dest.addr.in4 = io->addr;
                     break;
 
                 case AF_INET6:
                     from->dest.addr.in6 = io->addr6;
                     break;
             }
         }
         else
         {
             CLEAR(from->dest.addr);
         }
     }
 
     if (buf)
     {
         buf->len = ret;
     }
     return ret;
6fbf66fa
 }
 
445b192a
 #endif /* _WIN32 */
6fbf66fa
 
 /*
  * Socket event notification
  */
 
 unsigned int
81d882d5
 socket_set(struct link_socket *s,
            struct event_set *es,
            unsigned int rwflags,
            void *arg,
            unsigned int *persistent)
 {
     if (s)
     {
         if ((rwflags & EVENT_READ) && !stream_buf_read_setup(s))
         {
             ASSERT(!persistent);
             rwflags &= ~EVENT_READ;
         }
 
445b192a
 #ifdef _WIN32
81d882d5
         if (rwflags & EVENT_READ)
         {
             socket_recv_queue(s, 0);
         }
6fbf66fa
 #endif
 
81d882d5
         /* if persistent is defined, call event_ctl only if rwflags has changed since last call */
         if (!persistent || *persistent != rwflags)
         {
             event_ctl(es, socket_event_handle(s), rwflags, arg);
             if (persistent)
             {
                 *persistent = rwflags;
             }
         }
6fbf66fa
 
81d882d5
         s->rwflags_debug = rwflags;
6fbf66fa
     }
81d882d5
     return rwflags;
6fbf66fa
 }
bb564a59
 
 void
81d882d5
 sd_close(socket_descriptor_t *sd)
bb564a59
 {
81d882d5
     if (sd && socket_defined(*sd))
bb564a59
     {
81d882d5
         openvpn_close_socket(*sd);
         *sd = SOCKET_UNDEFINED;
bb564a59
     }
 }
 
 #if UNIX_SOCK_SUPPORT
 
 /*
  * code for unix domain sockets
  */
 
 const char *
81d882d5
 sockaddr_unix_name(const struct sockaddr_un *local, const char *null)
bb564a59
 {
81d882d5
     if (local && local->sun_family == PF_UNIX)
     {
         return local->sun_path;
     }
     else
     {
         return null;
     }
bb564a59
 }
 
 socket_descriptor_t
81d882d5
 create_socket_unix(void)
bb564a59
 {
81d882d5
     socket_descriptor_t sd;
bb564a59
 
81d882d5
     if ((sd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
     {
         msg(M_ERR, "Cannot create unix domain socket");
     }
e35a7883
 
81d882d5
     /* set socket file descriptor to not pass across execs, so that
      * scripts don't have access to it */
     set_cloexec(sd);
e35a7883
 
81d882d5
     return sd;
bb564a59
 }
 
 void
81d882d5
 socket_bind_unix(socket_descriptor_t sd,
                  struct sockaddr_un *local,
                  const char *prefix)
bb564a59
 {
81d882d5
     struct gc_arena gc = gc_new();
bb564a59
 
 #ifdef HAVE_UMASK
81d882d5
     const mode_t orig_umask = umask(0);
bb564a59
 #endif
 
81d882d5
     if (bind(sd, (struct sockaddr *) local, sizeof(struct sockaddr_un)))
bb564a59
     {
56b396dc
         msg(M_FATAL | M_ERRNO,
             "%s: Socket bind[%d] failed on unix domain socket %s",
81d882d5
             prefix,
             (int)sd,
56b396dc
             sockaddr_unix_name(local, "NULL"));
bb564a59
     }
 
 #ifdef HAVE_UMASK
81d882d5
     umask(orig_umask);
bb564a59
 #endif
 
81d882d5
     gc_free(&gc);
bb564a59
 }
 
 socket_descriptor_t
81d882d5
 socket_accept_unix(socket_descriptor_t sd,
                    struct sockaddr_un *remote)
bb564a59
 {
81d882d5
     socklen_t remote_len = sizeof(struct sockaddr_un);
     socket_descriptor_t ret;
bb564a59
 
81d882d5
     CLEAR(*remote);
     ret = accept(sd, (struct sockaddr *) remote, &remote_len);
     if (ret >= 0)
e35a7883
     {
81d882d5
         /* set socket file descriptor to not pass across execs, so that
          * scripts don't have access to it */
         set_cloexec(ret);
e35a7883
     }
81d882d5
     return ret;
bb564a59
 }
 
86f5c7c9
 int
81d882d5
 socket_connect_unix(socket_descriptor_t sd,
                     struct sockaddr_un *remote)
86f5c7c9
 {
81d882d5
     int status = connect(sd, (struct sockaddr *) remote, sizeof(struct sockaddr_un));
     if (status)
     {
         status = openvpn_errno();
     }
     return status;
86f5c7c9
 }
 
bb564a59
 void
81d882d5
 sockaddr_unix_init(struct sockaddr_un *local, const char *path)
bb564a59
 {
81d882d5
     local->sun_family = PF_UNIX;
     strncpynt(local->sun_path, path, sizeof(local->sun_path));
bb564a59
 }
 
 void
81d882d5
 socket_delete_unix(const struct sockaddr_un *local)
bb564a59
 {
81d882d5
     const char *name = sockaddr_unix_name(local, NULL);
bb564a59
 #ifdef HAVE_UNLINK
81d882d5
     if (name && strlen(name))
     {
         unlink(name);
     }
bb564a59
 #endif
 }
 
 bool
81d882d5
 unix_socket_get_peer_uid_gid(const socket_descriptor_t sd, int *uid, int *gid)
bb564a59
 {
 #ifdef HAVE_GETPEEREID
81d882d5
     uid_t u;
     gid_t g;
     if (getpeereid(sd, &u, &g) == -1)
     {
         return false;
     }
     if (uid)
     {
         *uid = u;
     }
     if (gid)
     {
         *gid = g;
     }
     return true;
bb564a59
 #elif defined(SO_PEERCRED)
81d882d5
     struct ucred peercred;
     socklen_t so_len = sizeof(peercred);
     if (getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) == -1)
     {
         return false;
     }
     if (uid)
     {
         *uid = peercred.uid;
     }
     if (gid)
     {
         *gid = peercred.gid;
     }
     return true;
 #else  /* ifdef HAVE_GETPEEREID */
bb564a59
     return false;
81d882d5
 #endif /* ifdef HAVE_GETPEEREID */
bb564a59
 }
 
81d882d5
 #endif /* if UNIX_SOCK_SUPPORT */