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.
  *
564a2109
  *  Copyright (C) 2002-2010 OpenVPN Technologies, 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.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program (see the file COPYING included with this
  *  distribution); if not, write to the Free Software Foundation, Inc.,
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
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"
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 */
8335caf9
   0,
   IPv4_UDP_HEADER_SIZE, /* IPv4 */
1406db55
   IPv4_TCP_HEADER_SIZE,
   IPv4_TCP_HEADER_SIZE,
8335caf9
   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)
 {
86093c1c
   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
 getaddr (unsigned int flags,
f2d6f3bc
          const char *hostname,
          int resolve_retry_seconds,
          bool *succeeded,
          volatile int *signal_received)
6fbf66fa
 {
f2d6f3bc
   struct addrinfo *ai;
6fbf66fa
   int status;
076fd3e4
   status = openvpn_getaddrinfo (flags & ~GETADDR_HOST_ORDER, hostname, NULL,
                                 resolve_retry_seconds, signal_received, AF_INET, &ai);
f2d6f3bc
   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
 streqnull (const char* a, const char* b)
 {
   if (a == NULL && b == NULL)
     return true;
   else if (a == NULL || b == NULL)
     return false;
   else
     return streq (a, b);
 }
 
 /*
   get_cached_dns_entry return 0 on success and -1
   otherwise. (like getaddrinfo)
  */
 static int
 get_cached_dns_entry (struct cached_dns_entry* dns_cache,
 		      const char* hostname,
 		      const char* servname,
 		      int ai_family,
 		      int resolve_flags,
 		      struct addrinfo **ai)
 {
   struct cached_dns_entry *ph;
   int flags;
 
   /* Only use flags that are relevant for the structure */
   flags = resolve_flags & GETADDR_CACHE_MASK;
 
   for (ph = dns_cache; ph ; ph = ph->next)
     {
       if (streqnull (ph->hostname, hostname) &&
 	  streqnull (ph->servname, servname) &&
 	  ph->ai_family == ai_family &&
 	  ph->flags == flags)
 	{
 	  *ai = ph->ai;
 	  return 0;
 	}
     }
   return -1;
 }
 
 
 static int
 do_preresolve_host (struct context *c,
 		    const char *hostname,
 		    const char *servname,
 		    const int af,
 		    const int flags)
 {
   struct addrinfo *ai;
   int status;
 
   if (get_cached_dns_entry(c->c1.dns_cache,
 			   hostname,
 			   servname,
 			   af,
 			   flags,
 			   &ai) == 0 )
     {
       /* entry already cached, return success */
       return 0;
     }
 
   status = openvpn_getaddrinfo (flags, hostname, servname,
 				c->options.resolve_retry_seconds, NULL,
 				af, &ai);
   if (status == 0)
     {
       struct cached_dns_entry *ph;
 
       ALLOC_OBJ_CLEAR_GC (ph, struct cached_dns_entry, &c->gc);
       ph->ai = ai;
       ph->hostname = hostname;
       ph->servname = servname;
       ph->flags = flags & GETADDR_CACHE_MASK;
 
       if (!c->c1.dns_cache)
 	c->c1.dns_cache = ph;
       else
 	{
 	  struct cached_dns_entry *prev = c->c1.dns_cache;
 	  while (prev->next)
 	    prev = prev->next;
 	  prev->next = ph;
 	}
 
       gc_addspecial (ai, &gc_freeaddrinfo_callback, &c->gc);
 
     }
   return status;
 }
 
 void
 do_preresolve (struct context *c)
 {
   int i;
   struct connection_list *l = c->options.connection_list;
   const unsigned int preresolve_flags = GETADDR_RESOLVE|
     GETADDR_UPDATE_MANAGEMENT_STATE|
     GETADDR_MENTION_RESOLVE_RETRY|
     GETADDR_FATAL;
 
 
   for (i = 0; i < l->len; ++i)
     {
       int status;
       const char *remote;
       int flags = preresolve_flags;
 
       struct connection_entry* ce = c->options.connection_list->array[i];
 
       if (proto_is_dgram(ce->proto))
 	  flags |= GETADDR_DATAGRAM;
 
       if (c->options.sockflags & SF_HOST_RANDOMIZE)
 	  flags |= GETADDR_RANDOMIZE;
 
       if (c->options.ip_remote_hint)
 	  remote = c->options.ip_remote_hint;
       else
 	  remote = ce->remote;
 
       /* HTTP remote hostname does not need to be resolved */
       if (! ce->http_proxy_options)
 	{
 	  status = do_preresolve_host (c, remote, ce->remote_port, ce->af, flags);
 	  if (status != 0)
 	      goto err;
 	}
 
       /* Preresolve proxy */
       if (ce->http_proxy_options)
 	{
 	  status = do_preresolve_host (c,
 				       ce->http_proxy_options->server,
 				       ce->http_proxy_options->port,
 				       ce->af,
 				       preresolve_flags);
 
 	  if (status != 0)
 	      goto err;
 	}
 
       if (ce->socks_proxy_server)
 	{
 	  status = do_preresolve_host (c,
 				       ce->socks_proxy_server,
 				       ce->socks_proxy_port,
 				       ce->af,
 				       flags);
 	  if (status != 0)
 	      goto err;
 	}
 
       if (ce->bind_local)
 	{
 	  flags |= GETADDR_PASSIVE;
 	  flags &= ~GETADDR_RANDOMIZE;
 	  status = do_preresolve_host (c, ce->local, ce->local_port, ce->af, flags);
 	  if (status != 0)
 	      goto err;
 
 	}
 
     }
     return;
 
  err:
   throw_signal_soft (SIGHUP, "Preresolving failed");
 }
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
 openvpn_getaddrinfo (unsigned int flags,
                      const char *hostname,
076fd3e4
                      const char *servname,
f2d6f3bc
                      int resolve_retry_seconds,
                      volatile int *signal_received,
                      int ai_family,
                      struct addrinfo **res)
ea93a078
 {
f2d6f3bc
   struct addrinfo hints;
ea93a078
   int status;
   int sigrec = 0;
   int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;
   struct gc_arena gc = gc_new ();
076fd3e4
   const char *print_hostname;
   const char *print_servname;
ea93a078
 
f2d6f3bc
   ASSERT(res);
 
076fd3e4
   ASSERT (hostname || servname);
   ASSERT (!(flags & GETADDR_HOST_ORDER));
 
23d61c56
   if (hostname && (flags & GETADDR_RANDOMIZE))
     hostname = hostname_randomize(hostname, &gc);
 
076fd3e4
   if(hostname)
     print_hostname = hostname;
   else
     print_hostname = "undefined";
 
   if(servname)
     print_servname = servname;
   else
     print_servname = "";
 
ea93a078
   if (flags & GETADDR_MSG_VIRT_OUT)
     msglevel |= M_MSG_VIRT_OUT;
 
   if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL))
       && !signal_received)
     signal_received = &sigrec;
 
   /* try numeric ipv6 addr first */
   CLEAR(hints);
f2d6f3bc
   hints.ai_family = ai_family;
ea93a078
   hints.ai_flags = AI_NUMERICHOST;
97ba084b
 
076fd3e4
   if(flags & GETADDR_PASSIVE)
       hints.ai_flags |= AI_PASSIVE;
 
23d61c56
   if(flags & GETADDR_DATAGRAM)
       hints.ai_socktype = SOCK_DGRAM;
   else
       hints.ai_socktype = SOCK_STREAM;
 
076fd3e4
   status = getaddrinfo(hostname, servname, &hints, res);
ea93a078
 
f2d6f3bc
   if (status != 0) /* parse as numeric address failed? */
ea93a078
     {
       const int fail_wait_interval = 5; /* seconds */
23d61c56
       /* 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);
ea93a078
       const char *fmt;
       int level = 0;
 
aa162d44
       fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)";
ea93a078
       if ((flags & GETADDR_MENTION_RESOLVE_RETRY)
f2d6f3bc
           && !resolve_retry_seconds)
aa162d44
         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
 
       if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL)
f2d6f3bc
         {
aa162d44
           msg (msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)",
                print_hostname,print_servname, gai_strerror(status));
f2d6f3bc
           goto done;
         }
ea93a078
 
 #ifdef ENABLE_MANAGEMENT
       if (flags & GETADDR_UPDATE_MANAGEMENT_STATE)
f2d6f3bc
         {
           if (management)
             management_set_state (management,
                                   OPENVPN_STATE_RESOLVE,
                                   NULL,
2191c471
                                   NULL,
                                   NULL,
                                   NULL,
                                   NULL);
f2d6f3bc
         }
ea93a078
 #endif
 
       /*
        * Resolve hostname
        */
       while (true)
f2d6f3bc
         {
288a819a
 #ifndef WIN32
 	  res_init ();
 #endif
f2d6f3bc
           /* try hostname lookup */
076fd3e4
           hints.ai_flags &= ~AI_NUMERICHOST;
f2d6f3bc
           dmsg (D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d",
                 flags, hints.ai_family, hints.ai_socktype);
076fd3e4
           status = getaddrinfo(hostname, servname, &hints, res);
6d1b80bd
 
f2d6f3bc
           if (signal_received)
             {
               get_signal (signal_received);
               if (*signal_received) /* were we interrupted by a signal? */
                 {
                   if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */
                     {
                       msg (level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt");
                       *signal_received = 0;
                     }
                   else
282788a8
                     {
5f6c01ea
 		      /* turn success into failure (interrupted syscall) */
282788a8
                       if (0 == status) {
                           ASSERT(res);
                           freeaddrinfo(*res);
5f6c01ea
                           *res = NULL;
8ceb9619
                           status = EAI_AGAIN;	/* = temporary failure */
5f6c01ea
                           errno = EINTR;
282788a8
                       }
                       goto done;
                     }
f2d6f3bc
                 }
             }
ea93a078
 
f2d6f3bc
           /* success? */
           if (0 == status)
             break;
ea93a078
 
f2d6f3bc
           /* resolve lookup failed, should we
              continue or fail? */
           level = msglevel;
           if (resolve_retries > 0)
             level = D_RESOLVE_ERRORS;
ea93a078
 
f2d6f3bc
           msg (level,
                fmt,
076fd3e4
                print_hostname,
                print_servname,
f2d6f3bc
                gai_strerror(status));
 
           if (--resolve_retries <= 0)
             goto done;
ea93a078
 
f2d6f3bc
           openvpn_sleep (fail_wait_interval);
ea93a078
         }
 
f2d6f3bc
       ASSERT(res);
ea93a078
 
       /* hostname resolve succeeded */
f2d6f3bc
 
23d61c56
       /*
        * Do not choose an IP Addresse by random or change the order *
f2d6f3bc
        * of IP addresses, doing so will break RFC 3484 address selection *
        */
ea93a078
     }
   else
     {
       /* IP address parse succeeded */
     }
 
  done:
   if (signal_received && *signal_received)
     {
       int level = 0;
       if (flags & GETADDR_FATAL_ON_SIGNAL)
f2d6f3bc
         level = M_FATAL;
ea93a078
       else if (flags & GETADDR_WARN_ON_SIGNAL)
f2d6f3bc
         level = M_WARN;
ea93a078
       msg (level, "RESOLVE: signal received during DNS resolution attempt");
     }
 
   gc_free (&gc);
f2d6f3bc
   return status;
ea93a078
 }
 
6fbf66fa
 /*
  * We do our own inet_aton because the glibc function
  * isn't very good about error checking.
  */
 int
 openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr)
 {
   unsigned int a, b, c, d;
 
   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
     return OIA_HOSTNAME; /* probably a hostname */
 }
 
b4073a76
 bool
 ip_addr_dotted_quad_safe (const char *dotted_quad)
 {
   /* verify non-NULL */
   if (!dotted_quad)
     return false;
 
   /* 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;
 
     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;
   }
 }
 
512cda46
 bool
 ipv6_addr_safe (const char *ipv6_text_addr)
 {
   /* verify non-NULL */
   if (!ipv6_text_addr)
     return false;
 
   /* verify length is within limits */
   if (strlen (ipv6_text_addr) > INET6_ADDRSTRLEN )
     return false;
 
   /* verify that string will convert to IPv6 address */
   {
     struct in6_addr a6;
     return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1;
   }
 }
 
b4b5c311
 static bool
 dns_addr_safe (const char *addr)
 {
   if (addr)
     {
       const size_t len = strlen (addr);
       return len > 0 && len <= 255 && string_class (addr, CC_ALNUM|CC_DASH|CC_DOT, 0);
     }
   else
     return false;
 }
 
0a838de8
 bool
b4b5c311
 ip_or_dns_addr_safe (const char *addr, const bool allow_fqdn)
0a838de8
 {
b4b5c311
   if (ip_addr_dotted_quad_safe (addr))
0a838de8
     return true;
   else if (allow_fqdn)
b4b5c311
     return dns_addr_safe (addr);
0a838de8
   else
     return false;
 }
 
6e2c457d
 bool
 mac_addr_safe (const char *mac_addr)
 {
   /* verify non-NULL */
   if (!mac_addr)
     return false;
 
   /* 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;
       }
   }
 
   /* error-checking is left to script invoked in lladdr.c */
   return true;
 }
 
6fbf66fa
 static int
 socket_get_sndbuf (int sd)
 {
 #if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF)
   int val;
   socklen_t len;
 
   len = sizeof (val);
   if (getsockopt (sd, SOL_SOCKET, SO_SNDBUF, (void *) &val, &len) == 0
       && len == sizeof (val))
     return val;
 #endif
   return 0;
 }
 
 static void
 socket_set_sndbuf (int sd, int size)
 {
 #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF)
f0b64e5d
   if (setsockopt (sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof (size)) != 0)
6fbf66fa
     {
f0b64e5d
       msg (M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size);
6fbf66fa
     }
 #endif
 }
 
 static int
 socket_get_rcvbuf (int sd)
 {
 #if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF)
   int val;
   socklen_t len;
 
   len = sizeof (val);
   if (getsockopt (sd, SOL_SOCKET, SO_RCVBUF, (void *) &val, &len) == 0
       && len == sizeof (val))
     return val;
 #endif
   return 0;
 }
 
 static bool
 socket_set_rcvbuf (int sd, int size)
 {
 #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF)
f0b64e5d
   if (setsockopt (sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof (size)) != 0)
6fbf66fa
     {
f0b64e5d
       msg (M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size);
       return false;
6fbf66fa
     }
   return true;
 #endif
 }
 
 static void
 socket_set_buffers (int fd, const struct socket_buffer_size *sbs)
 {
   if (sbs)
     {
       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);
 
       if (sbs->rcvbuf)
 	socket_set_rcvbuf (fd, sbs->rcvbuf);
        
       msg (D_OSBUF, "Socket Buffers: R=[%d->%d] S=[%d->%d]",
 	   rcvbuf_old,
 	   socket_get_rcvbuf (fd),
 	   sndbuf_old,
 	   socket_get_sndbuf (fd));
     }
 }
 
 /*
00d39170
  * Set other socket options
  */
 
 static bool
 socket_set_tcp_nodelay (int sd, int state)
 {
8db6234d
 #if defined(WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY))
00d39170
   if (setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (void *) &state, sizeof (state)) != 0)
     {
       msg (M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed", state);
       return false;
     }
   else
     {
       dmsg (D_OSBUF, "Socket flags: TCP_NODELAY=%d succeeded", state);
       return true;
     }
 #else
   msg (M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed (No kernel support)", state);
   return false;
 #endif
 }
 
032f0045
 static inline void
d90428d1
 socket_set_mark (int sd, int mark)
 {
51bd56f4
 #if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK
a2466d9e
   if (mark && setsockopt (sd, SOL_SOCKET, SO_MARK, (void *) &mark, sizeof (mark)) != 0)
d90428d1
     msg (M_WARN, "NOTE: setsockopt SO_MARK=%d failed", mark);
 #endif
 }
 
00d39170
 static bool
 socket_set_flags (int sd, unsigned int sockflags)
 {
   if (sockflags & SF_TCP_NODELAY)
     return socket_set_tcp_nodelay (sd, 1);
   else
     return true;
 }
 
 bool
 link_socket_update_flags (struct link_socket *ls, unsigned int sockflags)
 {
   if (ls && socket_defined (ls->sd))
     return socket_set_flags (ls->sd, ls->sockflags = sockflags);
   else
     return false;
 }
 
 void
 link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf)
 {
   if (ls && socket_defined (ls->sd))
     {
       ls->socket_buffer_sizes.sndbuf = sndbuf;
       ls->socket_buffer_sizes.rcvbuf = rcvbuf;
       socket_set_buffers (ls->sd, &ls->socket_buffer_sizes);
     }
 }
 
 /*
6fbf66fa
  * SOCKET INITALIZATION CODE.
  * Create a TCP/UDP socket
  */
 
 socket_descriptor_t
7dbe04de
 create_socket_tcp (struct addrinfo* addrinfo)
6fbf66fa
 {
   socket_descriptor_t sd;
 
7dbe04de
   ASSERT (addrinfo);
   ASSERT (addrinfo->ai_socktype == SOCK_STREAM);
 
   if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
910675de
     msg (M_ERR, "Cannot create TCP socket");
6fbf66fa
 
7d770f1e
 #ifndef WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */
6fbf66fa
   /* set SO_REUSEADDR on socket */
   {
     int on = 1;
     if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR,
 		    (void *) &on, sizeof (on)) < 0)
910675de
       msg (M_ERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP socket");
6fbf66fa
   }
7d770f1e
 #endif
6fbf66fa
 
   return sd;
 }
 
 static socket_descriptor_t
7dbe04de
 create_socket_udp (struct addrinfo* addrinfo, const unsigned int flags)
6fbf66fa
 {
   socket_descriptor_t sd;
 
7dbe04de
   ASSERT (addrinfo);
   ASSERT (addrinfo->ai_socktype == SOCK_DGRAM);
 
   if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
23d61c56
     msg (M_ERR, "UDP: Cannot create UDP/UDP6 socket");
8bc93d7f
 #if ENABLE_IP_PKTINFO
   else if (flags & SF_USE_IP_PKTINFO)
     {
       int pad = 1;
7dbe04de
       if(addrinfo->ai_family == AF_INET)
23d61c56
         {
d3774cdf
 #ifdef IP_PKTINFO
23d61c56
           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)
23d61c56
           if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR,
                           (void*)&pad, sizeof(pad)) < 0)
             msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR");
d3774cdf
 #else
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
23d61c56
         }
7dbe04de
       else if (addrinfo->ai_family == AF_INET6 )
23d61c56
         {
fe8a7f0c
 #ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */
23d61c56
           if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO,
                           (void*)&pad, sizeof(pad)) < 0)
fe8a7f0c
 #else
23d61c56
           if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
                           (void*)&pad, sizeof(pad)) < 0)
fe8a7f0c
 #endif
23d61c56
             msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");
         }
8335caf9
     }
 #endif
   return sd;
 }
 
7dbe04de
 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)
       {
         if (sock->socks_proxy && sock->info.proto == PROTO_UDP)
             socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local,
 			 ai_family, "SOCKS", false);
         else
             socket_bind (sock->sd, sock->info.lsa->bind_local,
 			 ai_family,
                          "TCP/UDP", sock->info.bind_ipv6_only);
       }
 }
23d61c56
 
7dbe04de
 static void
 create_socket (struct link_socket* sock, struct addrinfo* addr)
 {
891636cb
   if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM)
6fbf66fa
     {
7dbe04de
       sock->sd = create_socket_udp (addr, sock->sockflags);
6d1b80bd
       sock->sockflags |= SF_GETADDRINFO_DGRAM;
6fbf66fa
 
7dbe04de
       /* Assume that control socket and data socket to the socks proxy
        * are using the same IP family */
6fbf66fa
       if (sock->socks_proxy)
7dbe04de
 	{
 	  /* 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
     }
891636cb
   else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM)
8335caf9
     {
7dbe04de
       sock->sd = create_socket_tcp (addr);
8335caf9
     }
6fbf66fa
   else
     {
       ASSERT (0);
     }
23d61c56
     /* set socket buffers based on --sndbuf and --rcvbuf options */
     socket_set_buffers (sock->sd, &sock->socket_buffer_sizes);
 
     /* set socket to --mark packets with given value */
     socket_set_mark (sock->sd, sock->mark);
7dbe04de
 
     bind_local (sock, addr->ai_family);
51187871
 }
23d61c56
 
a55b3cdb
 #ifdef TARGET_ANDROID
51187871
 static void protect_fd_nonlocal (int fd, const struct sockaddr* addr)
 {
a55b3cdb
   /* pass socket FD to management interface to pass on to VPNService API
    * as "protected socket" (exempt from being routed into tunnel)
    */
51187871
   if (addr_local (addr)) {
acd487d0
     msg(D_SOCKET_DEBUG, "Address is local, not protecting socket fd %d", fd);
51187871
     return;
   }
a55b3cdb
 
acd487d0
   msg(D_SOCKET_DEBUG, "Protecting socket fd %d", fd);
51187871
   management->connection.fdtosend = fd;
a55b3cdb
   management_android_control (management, "PROTECTFD", __func__);
6fbf66fa
 }
51187871
 #endif
6fbf66fa
 
 /*
  * Functions used for establishing a TCP stream connection.
  */
 static void
 socket_do_listen (socket_descriptor_t sd,
1ba6f427
 		  const struct addrinfo *local,
6fbf66fa
 		  bool do_listen,
 		  bool do_set_nonblock)
 {
   struct gc_arena gc = gc_new ();
   if (do_listen)
     {
1ba6f427
       ASSERT(local);
6fbf66fa
       msg (M_INFO, "Listening for incoming TCP connection on %s", 
1ba6f427
 	   print_sockaddr (local->ai_addr, &gc));
6fbf66fa
       if (listen (sd, 1))
910675de
 	msg (M_ERR, "TCP: listen() failed");
6fbf66fa
     }
 
   /* set socket to non-blocking mode */
   if (do_set_nonblock)
     set_nonblock (sd);
 
   gc_free (&gc);
 }
 
 socket_descriptor_t
 socket_do_accept (socket_descriptor_t sd,
8bc93d7f
 		  struct link_socket_actual *act,
6fbf66fa
 		  const bool nowait)
 {
8335caf9
   /* 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);
6fbf66fa
   socket_descriptor_t new_sd = SOCKET_UNDEFINED;
 
8bc93d7f
   CLEAR (*act);
 
6fbf66fa
 #ifdef HAVE_GETPEERNAME
   if (nowait)
     {
8335caf9
       new_sd = getpeername (sd, &act->dest.addr.sa, &remote_len);
6fbf66fa
 
       if (!socket_defined (new_sd))
910675de
 	msg (D_LINK_ERRORS | M_ERRNO, "TCP: getpeername() failed");
6fbf66fa
       else
 	new_sd = sd;
     }
 #else
   if (nowait)
     msg (M_WARN, "TCP: this OS does not provide the getpeername() function");
 #endif
   else
     {
8335caf9
       new_sd = accept (sd, &act->dest.addr.sa, &remote_len);
6fbf66fa
     }
 
e8c1720d
 #if 0 /* For debugging only, test the effect of accept() failures */
  {
    static int foo = 0;
    ++foo;
    if (foo & 1)
      new_sd = -1;
  }
 #endif
 
6fbf66fa
   if (!socket_defined (new_sd))
     {
910675de
       msg (D_LINK_ERRORS | M_ERRNO, "TCP: accept(%d) failed", sd);
6fbf66fa
     }
8335caf9
   /* only valid if we have remote_len_af!=0 */
   else if (remote_len_af && remote_len != remote_len_af)
6fbf66fa
     {
       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;
     }
   return new_sd;
 }
 
 static void
8bc93d7f
 tcp_connection_established (const struct link_socket_actual *act)
6fbf66fa
 {
   struct gc_arena gc = gc_new ();
   msg (M_INFO, "TCP connection established with %s", 
8bc93d7f
        print_link_socket_actual (act, &gc));
6fbf66fa
   gc_free (&gc);
 }
 
 static int
 socket_listen_accept (socket_descriptor_t sd,
8bc93d7f
 		      struct link_socket_actual *act,
6fbf66fa
 		      const char *remote_dynamic,
23d61c56
 		      const struct addrinfo *local,
6fbf66fa
 		      bool do_listen,
 		      bool nowait,
 		      volatile int *signal_received)
 {
   struct gc_arena gc = gc_new ();
4e75b2e8
   /* struct openvpn_sockaddr *remote = &act->dest; */
8bc93d7f
   struct openvpn_sockaddr remote_verify = act->dest;
6fbf66fa
   int new_sd = SOCKET_UNDEFINED;
 
8bc93d7f
   CLEAR (*act);
1ba6f427
   socket_do_listen (sd, local, do_listen, true);
6fbf66fa
 
   while (true)
     {
       int status;
       fd_set reads;
       struct timeval tv;
 
       FD_ZERO (&reads);
e0b3fd49
       openvpn_fd_set (sd, &reads);
6fbf66fa
       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)
910675de
 	msg (D_LINK_ERRORS | M_ERRNO, "TCP: select() failed");
6fbf66fa
 
       if (status <= 0)
 	{
 	  openvpn_sleep (1);
 	  continue;
 	}
 
8bc93d7f
       new_sd = socket_do_accept (sd, act, nowait);
6fbf66fa
 
       if (socket_defined (new_sd))
 	{
1ba6f427
           struct addrinfo* ai = NULL;
23d61c56
           if(remote_dynamic)
               openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL,
                                     remote_verify.addr.sa.sa_family, &ai);
 
           if(ai && !addrlist_match(&remote_verify, ai))
             {
               msg (M_WARN,
                    "TCP NOTE: Rejected connection attempt from %s due to --remote setting",
                    print_link_socket_actual (act, &gc));
               if (openvpn_close_socket (new_sd))
                   msg (M_ERR, "TCP: close socket failed (new_sd)");
               freeaddrinfo(ai);
             }
6fbf66fa
 	  else
23d61c56
             {
               if(ai)
                   freeaddrinfo(ai);
               break;
             }
6fbf66fa
 	}
       openvpn_sleep (1);
     }
 
   if (!nowait && openvpn_close_socket (sd))
910675de
     msg (M_ERR, "TCP: close socket failed (sd)");
6fbf66fa
 
8bc93d7f
   tcp_connection_established (act);
6fbf66fa
 
   gc_free (&gc);
   return new_sd;
 }
 
188a6515
 /* older mingw versions and WinXP do not have this define,
  * but Vista and up support the functionality - just define it here
  */
 #ifdef WIN32
 # ifndef IPV6_V6ONLY
 #  define IPV6_V6ONLY 27
 # endif
 #endif
7ef85434
 void
04f4b793
 socket_bind (socket_descriptor_t sd,
23d61c56
              struct addrinfo *local,
              int ai_family,
8832c6c4
 	     const char *prefix,
              bool ipv6only)
04f4b793
 {
   struct gc_arena gc = gc_new ();
 
23d61c56
   /* FIXME (schwabe)
    * getaddrinfo for the bind address might return multiple AF_INET/AF_INET6
    * entries for the requested protocol.
    * For example if an address has multiple A records
    * What is the correct way to deal with it?
    */
 
   struct addrinfo* cur;
 
8832c6c4
   ASSERT(local);
 
 
23d61c56
   /* find the first addrinfo with correct ai_family */
   for (cur = local; cur; cur=cur->ai_next)
     {
       if(cur->ai_family == ai_family)
           break;
     }
   if (!cur)
       msg (M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record",
            prefix, addr_family_name(ai_family));
 
8832c6c4
   if (ai_family == AF_INET6)
     {
451de0a8
       int v6only = ipv6only ? 1: 0;	/* setsockopt must have an "int" */
8832c6c4
 
451de0a8
       msg (M_INFO, "setsockopt(IPV6_V6ONLY=%d)", v6only);
a2466d9e
       if (setsockopt (sd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &v6only, sizeof(v6only)))
8832c6c4
 	{
 	  msg (M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY=%d failed", v6only);
 	}
     }
23d61c56
   if (bind (sd, cur->ai_addr, cur->ai_addrlen))
04f4b793
     {
910675de
       const int errnum = openvpn_errno ();
7ef85434
       msg (M_FATAL, "%s: Socket bind failed on local address %s: %s",
 	   prefix,
23d61c56
            print_sockaddr_ex (local->ai_addr, ":", PS_SHOW_PORT, &gc),
04f4b793
            strerror_ts (errnum, &gc));
     }
   gc_free (&gc);
 }
 
4f404ad3
 int
1ae9d051
 openvpn_connect (socket_descriptor_t sd,
23d61c56
 		 const struct sockaddr *remote,
1ae9d051
 		 int connect_timeout,
 		 volatile int *signal_received)
 {
   int status = 0;
 
51187871
 #ifdef TARGET_ANDROID
   protect_fd_nonlocal(sd, remote);
 #endif
 
1ae9d051
 #ifdef CONNECT_NONBLOCK
   set_nonblock (sd);
23d61c56
   status = connect (sd, remote, af_addr_size(remote->sa_family));
1ae9d051
   if (status)
910675de
     status = openvpn_errno ();
9081e0ad
   if (
 #ifdef WIN32
     status == WSAEWOULDBLOCK
 #else
     status == EINPROGRESS
 #endif
   )
1ae9d051
     {
       while (true)
 	{
007738e9
 #if POLL
 	  struct pollfd fds[1];
 	  fds[0].fd = sd;
 	  fds[0].events = POLLOUT;
 	  status = poll(fds, 1, 0);
 #else
1ae9d051
 	  fd_set writes;
 	  struct timeval tv;
 
 	  FD_ZERO (&writes);
e0b3fd49
 	  openvpn_fd_set (sd, &writes);
1ae9d051
 	  tv.tv_sec = 0;
 	  tv.tv_usec = 0;
 
 	  status = select (sd + 1, NULL, &writes, NULL, &tv);
007738e9
 #endif
6add6b2f
 	  if (signal_received)
1ae9d051
 	    {
6add6b2f
 	      get_signal (signal_received);
 	      if (*signal_received)
 		{
 		  status = 0;
 		  break;
 		}
1ae9d051
 	    }
 	  if (status < 0)
 	    {
910675de
 	      status = openvpn_errno ();
1ae9d051
 	      break;
 	    }
 	  if (status <= 0)
 	    {
 	      if (--connect_timeout < 0)
 		{
5f5229e4
 #ifdef WIN32
 		  status = WSAETIMEDOUT;
 #else
1ae9d051
 		  status = ETIMEDOUT;
5f5229e4
 #endif
1ae9d051
 		  break;
 		}
 	      openvpn_sleep (1);
 	      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
910675de
 	      status = openvpn_errno ();
1ae9d051
 	    break;
 	  }
 	}
     }
 #else
188a6515
   status = connect (sd, remote, af_addr_size(remote->sa_family));
1ae9d051
   if (status)
910675de
     status = openvpn_errno ();
1ae9d051
 #endif
 
   return status;
 }
 
23d61c56
 void set_actual_address (struct link_socket_actual* actual, struct addrinfo* ai)
 {
     CLEAR (*actual);
     ASSERT (ai);
 
     if (ai->ai_family == AF_INET)
         actual->dest.addr.in4 =
         *((struct sockaddr_in*) ai->ai_addr);
     else if (ai->ai_family == AF_INET6)
         actual->dest.addr.in6 =
         *((struct sockaddr_in6*) ai->ai_addr);
     else
         ASSERT(0);
 
 }
 
4f404ad3
 void
7dbe04de
 socket_connect (socket_descriptor_t* sd,
                 const struct sockaddr* dest,
23d61c56
                 const int connect_timeout,
                 struct signal_info* sig_info)
6fbf66fa
 {
   struct gc_arena gc = gc_new ();
23d61c56
   int status;
6fbf66fa
 
1ae9d051
 #ifdef CONNECT_NONBLOCK
23d61c56
   msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]",
        print_sockaddr (dest, &gc));
1ae9d051
 #else
23d61c56
   msg (M_INFO, "Attempting to establish TCP connection with %s",
        print_sockaddr (dest, &gc));
1ae9d051
 #endif
 
e482a632
 #ifdef ENABLE_MANAGEMENT
23d61c56
   if (management)
e482a632
 	management_set_state (management,
 			      OPENVPN_STATE_TCP_CONNECT,
 			      NULL,
2191c471
                               NULL,
                               NULL,
                               NULL,
                               NULL);
e482a632
 #endif
 
23d61c56
   /* Set the actual address */
   status = openvpn_connect (*sd, dest, connect_timeout, &sig_info->signal_received);
a17f6969
 
23d61c56
   get_signal (&sig_info->signal_received);
   if (sig_info->signal_received)
a17f6969
 	goto done;
 
23d61c56
   if (status) {
97549c67
 
23d61c56
     msg (D_LINK_ERRORS,
          "TCP: connect to %s failed: %s",
          print_sockaddr (dest, &gc),
          strerror_ts (status, &gc));
6fbf66fa
 
23d61c56
     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
 
  done:
   gc_free (&gc);
 }
 
 /* For stream protocols, allocate a buffer to build up packet.
    Called after frame has been finalized. */
 
 static void
 socket_frame_init (const struct frame *frame, struct link_socket *sock)
 {
 #ifdef WIN32
   overlapped_io_init (&sock->reads, frame, FALSE, false);
   overlapped_io_init (&sock->writes, frame, TRUE, false);
   sock->rw_handle.read = sock->reads.overlapped.hEvent;
   sock->rw_handle.write = sock->writes.overlapped.hEvent;
 #endif
 
   if (link_socket_connection_oriented (sock))
     {
 #ifdef WIN32
dc46c067
       stream_buf_init (&sock->stream_buf,
 		       &sock->reads.buf_init,
 		       sock->sockflags,
 		       sock->info.proto);
6fbf66fa
 #else
       alloc_buf_sock_tun (&sock->stream_buf_data,
 			  frame,
 			  false,
 			  FRAME_HEADROOM_MARKER_READ_STREAM);
dc46c067
 
       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
 frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto)
 {
   frame_set_mtu_dynamic (frame, pmtu - datagram_overhead (proto), SET_MTU_UPPER_BOUND);
 }
 
 static void
23d61c56
 resolve_bind_local (struct link_socket *sock, const sa_family_t af)
6fbf66fa
 {
   struct gc_arena gc = gc_new ();
 
   /* resolve local address if undefined */
23d61c56
   if (!sock->info.lsa->bind_local)
d9c04efc
     {
23d61c56
       int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL |
 	GETADDR_FATAL | GETADDR_PASSIVE;
076fd3e4
       int status;
23d61c56
 
       if(proto_is_dgram(sock->info.proto))
 	flags |= GETADDR_DATAGRAM;
 
       /* will return AF_{INET|INET6}from local_host */
e719a053
       status = get_cached_dns_entry (sock->dns_cache,
 				     sock->local_host,
 				     sock->local_port,
 				     af,
 				     flags,
 				     &sock->info.lsa->bind_local);
 
       if (status)
 	status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
23d61c56
 				   NULL, af, &sock->info.lsa->bind_local);
 
       if(status !=0) {
 	msg (M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s",
 	     sock->local_host, sock->local_port,
 	     gai_strerror(status));
076fd3e4
       }
6fbf66fa
     }
076fd3e4
 
23d61c56
   gc_free (&gc);
 }
 
6fbf66fa
 static void
 resolve_remote (struct link_socket *sock,
 		int phase,
 		const char **remote_dynamic,
 		volatile int *signal_received)
 {
   struct gc_arena gc = gc_new ();
 
e719a053
   /* resolve remote address if undefined */
   if (!sock->info.lsa->remote_list)
6fbf66fa
     {
e719a053
       if (sock->remote_host)
6fbf66fa
 	{
e719a053
 	  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)
6fbf66fa
 	    {
e719a053
 	      if (phase == 2)
 		flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
 	      retry = 0;
 	    }
 	  else if (phase == 1)
 	    {
 	      if (sock->resolve_retry_seconds)
6fbf66fa
 		{
 		  retry = 0;
 		}
e719a053
 	      else
6fbf66fa
 		{
e719a053
 		  flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
 		  retry = 0;
6fbf66fa
 		}
e719a053
 	    }
 	  else if (phase == 2)
 	    {
 	      if (sock->resolve_retry_seconds)
6fbf66fa
 		{
e719a053
 		  flags |= GETADDR_FATAL;
 		  retry = sock->resolve_retry_seconds;
6fbf66fa
 		}
 	      else
 		{
 		  ASSERT (0);
 		}
e719a053
 	    }
 	  else
 	    {
 	      ASSERT (0);
 	    }
6fbf66fa
 
e719a053
 
 	  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;
 	    }
f2d6f3bc
 	      if (status!=0)
ea93a078
 		{
 		  if (signal_received)
 		    *signal_received = SIGUSR1;
 		  goto done;
 		}
6fbf66fa
 	}
e719a053
     }
6fbf66fa
   
e719a053
   /* 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)
8bc93d7f
 	{
e719a053
 	  set_actual_address (&sock->info.lsa->actual,
 			      sock->info.lsa->current_remote);
8bc93d7f
 	}
6fbf66fa
     }
 
  done:
   gc_free (&gc);
 }
 
23d61c56
 
 
6fbf66fa
 struct link_socket *
 link_socket_new (void)
 {
   struct link_socket *sock;
 
   ALLOC_OBJ_CLEAR (sock, struct link_socket);
   sock->sd = SOCKET_UNDEFINED;
   sock->ctrl_sd = SOCKET_UNDEFINED;
   return sock;
 }
 
48f1d41a
 void
6fbf66fa
 link_socket_init_phase1 (struct link_socket *sock,
 			 const char *local_host,
076fd3e4
 			 const char *local_port,
4e9a51d7
 			 const char *remote_host,
076fd3e4
 			 const char *remote_port,
e719a053
 			 struct cached_dns_entry *dns_cache,
6fbf66fa
 			 int proto,
30077d1f
 			 sa_family_t af,
8832c6c4
 			 bool bind_ipv6_only,
6fbf66fa
 			 int mode,
 			 const struct link_socket *accept_from,
 			 struct http_proxy_info *http_proxy,
 			 struct socks_proxy_info *socks_proxy,
 #ifdef ENABLE_DEBUG
 			 int gremlin,
 #endif
 			 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,
00d39170
 			 int sndbuf,
d90428d1
 			 int mark,
f2134b7b
 			 struct event_timeout* server_poll_timeout,
00d39170
 			 unsigned int sockflags)
6fbf66fa
 {
   ASSERT (sock);
 
   sock->local_host = local_host;
   sock->local_port = local_port;
4e9a51d7
   sock->remote_host = remote_host;
   sock->remote_port = remote_port;
e719a053
   sock->dns_cache = dns_cache;
6fbf66fa
   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;
 
 #ifdef ENABLE_DEBUG
   sock->gremlin = gremlin;
 #endif
 
   sock->socket_buffer_sizes.rcvbuf = rcvbuf;
   sock->socket_buffer_sizes.sndbuf = sndbuf;
 
00d39170
   sock->sockflags = sockflags;
23d61c56
   sock->mark = mark;
00d39170
 
6fbf66fa
   sock->info.proto = proto;
30077d1f
   sock->info.af = af;
6fbf66fa
   sock->info.remote_float = remote_float;
   sock->info.lsa = lsa;
8832c6c4
   sock->info.bind_ipv6_only = bind_ipv6_only;
6fbf66fa
   sock->info.ipchange_command = ipchange_command;
   sock->info.plugins = plugins;
f2134b7b
   sock->server_poll_timeout = server_poll_timeout;
6fbf66fa
 
   sock->mode = mode;
   if (mode == LS_MODE_TCP_ACCEPT_FROM)
     {
       ASSERT (accept_from);
30077d1f
       ASSERT (sock->info.proto == PROTO_TCP_SERVER);
6fbf66fa
       ASSERT (!sock->inetd);
       sock->sd = accept_from->sd;
     }
 
   /* are we running in HTTP proxy mode? */
0e3f8940
   if (sock->http_proxy)
6fbf66fa
     {
500c16f3
       ASSERT (sock->info.proto == PROTO_TCP_CLIENT);
6fbf66fa
       ASSERT (!sock->inetd);
 
       /* the proxy server */
       sock->remote_host = http_proxy->options.server;
       sock->remote_port = http_proxy->options.port;
 
       /* the OpenVPN server we will use the proxy to connect to */
       sock->proxy_dest_host = remote_host;
       sock->proxy_dest_port = remote_port;
     }
   /* or in Socks proxy mode? */
   else if (sock->socks_proxy)
     {
       ASSERT (!sock->inetd);
 
       /* the proxy server */
       sock->remote_host = socks_proxy->server;
       sock->remote_port = socks_proxy->port;
 
       /* the OpenVPN server we will use the proxy to connect to */
       sock->proxy_dest_host = remote_host;
       sock->proxy_dest_port = remote_port;
     }
   else
     {
       sock->remote_host = remote_host;
       sock->remote_port = remote_port;
     }
 
   /* bind behavior for TCP server vs. client */
500c16f3
   if (sock->info.proto == PROTO_TCP_SERVER)
6fbf66fa
     {
       if (sock->mode == LS_MODE_TCP_ACCEPT_FROM)
 	sock->bind_local = false;
       else
 	sock->bind_local = true;
     }
 
   /* were we started by inetd or xinetd? */
   if (sock->inetd)
     {
30077d1f
       ASSERT (sock->info.proto != PROTO_TCP_CLIENT);
6fbf66fa
       ASSERT (socket_defined (inetd_socket_descriptor));
       sock->sd = inetd_socket_descriptor;
     }
   else if (mode != LS_MODE_TCP_ACCEPT_FROM)
     {
7dbe04de
       if (sock->bind_local) {
 	  resolve_bind_local (sock, sock->info.af);
       }
       resolve_remote (sock, 1, NULL, NULL);
48f1d41a
     }
 }
 
 static
 void phase2_inetd (struct link_socket* sock, const struct frame *frame,
 		   const char *remote_dynamic, volatile int *signal_received)
 {
   bool remote_changed = false;
 
   if (sock->info.proto == PROTO_TCP_SERVER) {
     /* AF_INET as default (and fallback) for inetd */
     sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET;
 #ifdef HAVE_GETSOCKNAME
     {
       /* inetd: hint family type for dest = local's */
       struct openvpn_sockaddr local_addr;
       socklen_t addrlen = sizeof(local_addr);
23d61c56
       if (getsockname (sock->sd, &local_addr.addr.sa, &addrlen) == 0) {
48f1d41a
 	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)",
23d61c56
 	      proto2ascii(sock->info.proto, sock->info.af, false),
 	      local_addr.addr.sa.sa_family, sock->sd);
48f1d41a
       } else
 	msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET",
 	     proto2ascii(sock->info.proto, sock->info.af, false), sock->sd);
     }
 #else
     msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() "
 	 "function, using AF_INET",
 	 proto2ascii(sock->info.proto, false));
 #endif
     sock->sd =
       socket_listen_accept (sock->sd,
 			    &sock->info.lsa->actual,
 			    remote_dynamic,
23d61c56
 			    sock->info.lsa->bind_local,
48f1d41a
 			    false,
 			    sock->inetd == INETD_NOWAIT,
 			    signal_received);
23d61c56
 
48f1d41a
   }
   ASSERT (!remote_changed);
 }
2b9b4c8a
 
48f1d41a
 static void
 phase2_set_socket_flags (struct link_socket* sock)
 {
   /* set misc socket parameters */
   socket_set_flags (sock->sd, sock->sockflags);
 
   /* set socket to non-blocking mode */
   set_nonblock (sock->sd);
 
   /* set socket file descriptor to not pass across execs, so that
      scripts don't have access to it */
   set_cloexec (sock->sd);
 
   if (socket_defined (sock->ctrl_sd))
     set_cloexec (sock->ctrl_sd);
 
   /* set Path MTU discovery options on the socket */
2bed089d
   set_mtu_discover_type (sock->sd, sock->mtu_discover_type, sock->info.af);
48f1d41a
 
 #if EXTENDED_SOCKET_ERROR_CAPABILITY
   /* if the OS supports it, enable extended error passing on the socket */
   set_sock_extended_error_passing (sock->sd);
 #endif
 }
2b9b4c8a
 
d90428d1
 
48f1d41a
 static void
 linksock_print_addr (struct link_socket *sock)
 {
   struct gc_arena gc = gc_new ();
   const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO;
 
   /* print local address */
e719a053
  if (sock->inetd)
48f1d41a
     msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true));
e719a053
   else if (sock->bind_local)
     {
7dbe04de
       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 */
e719a053
       struct addrinfo *cur;
       for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next)
 	{
7dbe04de
 	  if(!ai_family || ai_family == cur->ai_family)
e719a053
 	    break;
 	}
       ASSERT (cur);
       msg (msglevel, "%s link local (bound): %s",
48f1d41a
 	   proto2ascii (sock->info.proto, sock->info.af, true),
23d61c56
 	   print_sockaddr(cur->ai_addr,&gc));
e719a053
     }
   else
     msg (msglevel, "%s link local: (not bound)",
 	 proto2ascii (sock->info.proto, sock->info.af, true));
48f1d41a
 
   /* print active remote address */
   msg (msglevel, "%s link remote: %s",
e719a053
        proto2ascii (sock->info.proto, sock->info.af, true),
        print_link_socket_actual_ex (&sock->info.lsa->actual,
 				    ":",
 				    PS_SHOW_PORT_IF_DEFINED,
 				    &gc));
48f1d41a
   gc_free(&gc);
 }
 
 static void
23d61c56
 phase2_tcp_server (struct link_socket *sock, const char *remote_dynamic,
 		   volatile int *signal_received)
48f1d41a
 {
   switch (sock->mode)
     {
     case LS_MODE_DEFAULT:
       sock->sd = socket_listen_accept (sock->sd,
 				       &sock->info.lsa->actual,
 				       remote_dynamic,
23d61c56
 				       sock->info.lsa->bind_local,
48f1d41a
 				       true,
 				       false,
 				       signal_received);
       break;
     case LS_MODE_TCP_LISTEN:
       socket_do_listen (sock->sd,
1ba6f427
 			sock->info.lsa->bind_local,
48f1d41a
 			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
23d61c56
 phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info)
48f1d41a
 {
23d61c56
   bool proxy_retry = false;
   do {
     socket_connect (&sock->sd,
7dbe04de
                    sock->info.lsa->current_remote->ai_addr,
f2134b7b
                    get_server_poll_remaining_time (sock->server_poll_timeout),
23d61c56
                    sig_info);
 
     if (sig_info->signal_received)
       return;
 
0e3f8940
     if (sock->http_proxy)
23d61c56
       {
 	proxy_retry = establish_http_proxy_passthru (sock->http_proxy,
 						     sock->sd,
 						     sock->proxy_dest_host,
 						     sock->proxy_dest_port,
f2134b7b
 						     sock->server_poll_timeout,
23d61c56
 						     &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);
7dbe04de
 	sock->sd = create_socket_tcp (sock->info.lsa->current_remote);
23d61c56
       }
 
   } while (proxy_retry);
 
48f1d41a
 }
 
 static void
23d61c56
 phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info)
48f1d41a
 {
     socket_connect (&sock->ctrl_sd,
7dbe04de
 		    sock->info.lsa->current_remote->ai_addr,
f2134b7b
 		    get_server_poll_remaining_time (sock->server_poll_timeout),
23d61c56
 		    sig_info);
48f1d41a
 
23d61c56
     if (sig_info->signal_received)
48f1d41a
 	return;
 
     establish_socks_proxy_udpassoc (sock->socks_proxy,
 				    sock->ctrl_sd,
 				    sock->sd,
 				    &sock->socks_relay.dest,
23d61c56
 				    &sig_info->signal_received);
48f1d41a
 
23d61c56
     if (sig_info->signal_received)
48f1d41a
 	return;
 
     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)
       {
6c5db192
 	freeaddrinfo(sock->info.lsa->remote_list);
23d61c56
 	sock->info.lsa->current_remote = NULL;
 	sock->info.lsa->remote_list = NULL;
       }
48f1d41a
 
23d61c56
     resolve_remote (sock, 1, NULL, &sig_info->signal_received);
48f1d41a
 }
 
6fbf66fa
 /* finalize socket initialization */
 void
 link_socket_init_phase2 (struct link_socket *sock,
 			 const struct frame *frame,
23d61c56
 			 struct signal_info *sig_info)
6fbf66fa
 {
   const char *remote_dynamic = NULL;
76a59eae
   int sig_save = 0;
6fbf66fa
 
   ASSERT (sock);
 
23d61c56
   if (sig_info && sig_info->signal_received)
76a59eae
     {
23d61c56
       sig_save = sig_info->signal_received;
       sig_info->signal_received = 0;
76a59eae
     }
 
6fbf66fa
   /* 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)
     {
23d61c56
       phase2_inetd (sock, frame, remote_dynamic,  &sig_info->signal_received);
       if (sig_info && sig_info->signal_received)
6fbf66fa
 	goto done;
48f1d41a
 
6fbf66fa
     }
   else
     {
23d61c56
       /* Second chance to resolv/create socket */
       resolve_remote (sock, 2, &remote_dynamic,  &sig_info->signal_received);
6fbf66fa
 
7dbe04de
       /* 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);
 
23d61c56
       /* If socket has not already been created create it now */
       if (sock->sd == SOCKET_UNDEFINED)
 	{
7dbe04de
 	  /* If we have no --remote and have still not figured out the
 	   * protocol family to use we will use the first of the bind */
45184804
 
7dbe04de
 	  if (sock->bind_local  && !sock->remote_host && sock->info.lsa->bind_local)
23d61c56
 	    {
7dbe04de
 	      /* Warn if this is because neither v4 or v6 was specified
 	       * and we should not connect a remote */
 	      if (sock->info.af == AF_UNSPEC)
ed5d0fe5
 	        {
 		  msg (M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s",
7dbe04de
 		     addr_family_name(sock->info.lsa->bind_local->ai_family));
ed5d0fe5
 		  sock->info.af = sock->info.lsa->bind_local->ai_family;
 		}
7dbe04de
 
 	      create_socket (sock, sock->info.lsa->bind_local);
23d61c56
 	    }
7dbe04de
 	}
23d61c56
 
7dbe04de
       /* 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;
23d61c56
 	}
 
       if (sig_info && sig_info->signal_received)
6fbf66fa
 	goto done;
 
30077d1f
       if (sock->info.proto == PROTO_TCP_SERVER)
6fbf66fa
 	{
23d61c56
 	  phase2_tcp_server (sock, remote_dynamic,
 			     &sig_info->signal_received);
6fbf66fa
 	}
30077d1f
       else if (sock->info.proto == PROTO_TCP_CLIENT)
6fbf66fa
 	{
23d61c56
 	  phase2_tcp_client (sock, sig_info);
f214bb21
 
6fbf66fa
 	}
23d61c56
       else if (sock->info.proto == PROTO_UDP && sock->socks_proxy)
6fbf66fa
 	{
23d61c56
 	  phase2_socks_client (sock, sig_info);
48f1d41a
 	}
51187871
 #ifdef TARGET_ANDROID
       if (sock->sd != -1)
 	protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa);
 #endif
23d61c56
       if (sig_info && sig_info->signal_received)
6fbf66fa
 	goto done;
     }
 
48f1d41a
   phase2_set_socket_flags(sock);
   linksock_print_addr(sock);
6fbf66fa
 
  done:
23d61c56
   if (sig_save && sig_info)
76a59eae
     {
23d61c56
       if (!sig_info->signal_received)
 	sig_info->signal_received = sig_save;
76a59eae
     }
6fbf66fa
 }
 
 void
 link_socket_close (struct link_socket *sock)
 {
   if (sock)
     {
 #ifdef ENABLE_DEBUG
       const int gremlin = GREMLIN_CONNECTION_FLOOD_LEVEL (sock->gremlin);
 #else
       const int gremlin = 0;
 #endif
 
       if (socket_defined (sock->sd))
 	{
 #ifdef WIN32
 	  close_net_event_win32 (&sock->listen_handle, sock->sd, 0);
 #endif
 	  if (!gremlin)
 	    {
9df9e13f
 	      msg (D_LOW, "TCP/UDP: Closing socket");
6fbf66fa
 	      if (openvpn_close_socket (sock->sd))
910675de
 		msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket failed");
6fbf66fa
 	    }
 	  sock->sd = SOCKET_UNDEFINED;
 #ifdef WIN32
 	  if (!gremlin)
 	    {
 	      overlapped_io_close (&sock->reads);
 	      overlapped_io_close (&sock->writes);
 	    }
 #endif
 	}
 
       if (socket_defined (sock->ctrl_sd))
 	{
 	  if (openvpn_close_socket (sock->ctrl_sd))
910675de
 	    msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket (ctrl_sd) failed");
6fbf66fa
 	  sock->ctrl_sd = SOCKET_UNDEFINED;
 	}
 
       stream_buf_close (&sock->stream_buf);
       free_buf (&sock->stream_buf_data);
       if (!gremlin)
 	free (sock);
     }
 }
 
 /* for stream protocols, allow for packet length prefix */
 void
 socket_adjust_frame_parameters (struct frame *frame, int proto)
 {
   if (link_socket_proto_connection_oriented (proto))
     frame_add_to_extra_frame (frame, sizeof (packet_size_type));
 }
 
 void
 setenv_trusted (struct env_set *es, const struct link_socket_info *info)
 {
8bc93d7f
   setenv_link_socket_actual (es, "trusted", &info->lsa->actual, SA_IP_PORT);
6fbf66fa
 }
 
5a2e9a25
 static void
 ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc)
 {
d3310d2e
   const char *host = print_sockaddr_ex (&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT , gc);
5a2e9a25
   if (include_cmd)
d3310d2e
     argv_printf (argv, "%sc %s",
5a2e9a25
 		 info->ipchange_command,
d3310d2e
 		 host);
5a2e9a25
   else
d3310d2e
     argv_printf (argv, "%s", host);
 
5a2e9a25
 }
 
6fbf66fa
 void
 link_socket_connection_initiated (const struct buffer *buf,
 				  struct link_socket_info *info,
8bc93d7f
 				  const struct link_socket_actual *act,
6fbf66fa
 				  const char *common_name,
 				  struct env_set *es)
 {
   struct gc_arena gc = gc_new ();
   
8bc93d7f
   info->lsa->actual = *act; /* Note: skip this line for --force-dest */
6fbf66fa
   setenv_trusted (es, info);
   info->connection_established = true;
 
   /* 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);
8bc93d7f
     buf_printf (&out, "Peer Connection Initiated with %s", print_link_socket_actual (&info->lsa->actual, &gc));
6fbf66fa
     msg (M_INFO, "%s", BSTR (&out));
   }
 
   /* set environmental vars */
   setenv_str (es, "common_name", common_name);
 
   /* Process --ipchange plugin */
   if (plugin_defined (info->plugins, OPENVPN_PLUGIN_IPCHANGE))
     {
5a2e9a25
       struct argv argv = argv_new ();
       ipchange_fmt (false, &argv, info, &gc);
1876ccd0
       if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
6fbf66fa
 	msg (M_WARN, "WARNING: ipchange plugin call failed");
5a2e9a25
       argv_reset (&argv);
6fbf66fa
     }
 
   /* Process --ipchange option */
   if (info->ipchange_command)
     {
5a2e9a25
       struct argv argv = argv_new ();
6fbf66fa
       setenv_str (es, "script_type", "ipchange");
5a2e9a25
       ipchange_fmt (true, &argv, info, &gc);
c2533d18
       openvpn_run_script (&argv, es, 0, "--ipchange");
5a2e9a25
       argv_reset (&argv);
6fbf66fa
     }
 
   gc_free (&gc);
 }
 
 void
 link_socket_bad_incoming_addr (struct buffer *buf,
 			       const struct link_socket_info *info,
8bc93d7f
 			       const struct link_socket_actual *from_addr)
6fbf66fa
 {
   struct gc_arena gc = gc_new ();
23d61c56
   struct addrinfo* ai;
6fbf66fa
 
8335caf9
   switch(from_addr->dest.addr.sa.sa_family)
d9c04efc
     {
8335caf9
     case AF_INET:
     case AF_INET6:
       msg (D_LINK_ERRORS,
d9c04efc
 	   "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,
23d61c56
 	   print_sockaddr_ex (info->lsa->remote_list->ai_addr,":" ,PS_SHOW_PORT, &gc));
           /* print additional remote addresses */
           for(ai=info->lsa->remote_list->ai_next;ai;ai=ai->ai_next) {
              msg(D_LINK_ERRORS,"or from peer address: %s",
                  print_sockaddr_ex(ai->ai_addr,":",PS_SHOW_PORT, &gc));
           }
8335caf9
       break;
d9c04efc
     }
6fbf66fa
   buf->len = 0;
   gc_free (&gc);
 }
 
 void
 link_socket_bad_outgoing_addr (void)
 {
   dmsg (D_READ_WRITE, "TCP/UDP: No outgoing address to send packet");
 }
 
 in_addr_t
 link_socket_current_remote (const struct link_socket_info *info)
 {
   const struct link_socket_addr *lsa = info->lsa;
 
8335caf9
 /* 
  * This logic supports "redirect-gateway" semantic, which 
  * 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
  */
1ad6fc29
   if (lsa->actual.dest.addr.sa.sa_family != AF_INET)
9d4c64b5
     return IPV4_INVALID_ADDR;
8335caf9
 
8bc93d7f
   if (link_socket_actual_defined (&lsa->actual))
8335caf9
     return ntohl (lsa->actual.dest.addr.in4.sin_addr.s_addr);
23d61c56
   else if (lsa->current_remote)
     return ntohl (((struct sockaddr_in*)lsa->current_remote->ai_addr)
                     ->sin_addr.s_addr);
6fbf66fa
   else
     return 0;
 }
 
3ddb5643
 const struct in6_addr *
 link_socket_current_remote_ipv6 (const struct link_socket_info *info)
 {
   const struct link_socket_addr *lsa = info->lsa;
 
 /* This logic supports "redirect-gateway" semantic,
  * for PF_INET6 routes over PF_INET6 endpoints
  *
  * For --remote entries with multiple addresses this
  * only return the actual endpoint we have sucessfully connected to
  */
   if (lsa->actual.dest.addr.sa.sa_family != AF_INET6)
     return NULL;
 
   if (link_socket_actual_defined (&lsa->actual))
     return &(lsa->actual.dest.addr.in6.sin6_addr);
   else if (lsa->current_remote)
     return &(((struct sockaddr_in6*)lsa->current_remote->ai_addr) ->sin6_addr);
   else
     return NULL;
 }
 
6fbf66fa
 /*
  * Return a status string describing socket state.
  */
 const char *
 socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena *gc)
 {
   struct buffer out = alloc_buf_gc (64, gc);
   if (s)
     {
       if (rwflags & EVENT_READ)
 	{
 	  buf_printf (&out, "S%s",
 		      (s->rwflags_debug & EVENT_READ) ? "R" : "r");
 #ifdef WIN32
 	  buf_printf (&out, "%s",
 		      overlapped_io_state_ascii (&s->reads));
 #endif
 	}
       if (rwflags & EVENT_WRITE)
 	{
 	  buf_printf (&out, "S%s",
 		      (s->rwflags_debug & EVENT_WRITE) ? "W" : "w");
 #ifdef WIN32
 	  buf_printf (&out, "%s",
 		      overlapped_io_state_ascii (&s->writes));
 #endif
 	}
     }
   else
     {
       buf_printf (&out, "S?");
     }
   return BSTR (&out);
 }
 
 /*
  * Stream buffer functions, used to packetize a TCP
  * stream connection.
  */
 
 static inline void
 stream_buf_reset (struct stream_buf *sb)
 {
   dmsg (D_STREAM_DEBUG, "STREAM: RESET");
   sb->residual_fully_formed = false;
   sb->buf = sb->buf_init;
   buf_reset (&sb->next);
   sb->len = -1;
 }
 
 void
 stream_buf_init (struct stream_buf *sb,
dc46c067
 		 struct buffer *buf,
 		 const unsigned int sockflags,
 		 const int proto)
6fbf66fa
 {
   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
30077d1f
   sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCP_SERVER))
dc46c067
     ? PS_ENABLED
     : PS_DISABLED;
6add6b2f
 #endif
6fbf66fa
   stream_buf_reset (sb);
 
   dmsg (D_STREAM_DEBUG, "STREAM: INIT maxlen=%d", sb->maxlen);
 }
 
 static inline void
 stream_buf_set_next (struct stream_buf *sb)
 {
   /* 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));
 }
 
 static inline void
 stream_buf_get_final (struct stream_buf *sb, struct buffer *buf)
 {
   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;
 }
 
 static inline void
 stream_buf_get_next (struct stream_buf *sb, struct buffer *buf)
 {
   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;
 }
 
 bool
 stream_buf_read_setup_dowork (struct link_socket* sock)
 {
   if (sock->stream_buf.residual.len && !sock->stream_buf.residual_fully_formed)
     {
       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);
     }
 
   if (!sock->stream_buf.residual_fully_formed)
     stream_buf_set_next (&sock->stream_buf);
   return !sock->stream_buf.residual_fully_formed;
 }
 
 bool
 stream_buf_added (struct stream_buf *sb,
 		  int length_added)
 {
   dmsg (D_STREAM_DEBUG, "STREAM: ADD length_added=%d", length_added);
   if (length_added > 0)
     sb->buf.len += length_added;
 
   /* 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))
     {
       packet_size_type net_size;
6add6b2f
 
 #if PORT_SHARE
       if (sb->port_share_state == PS_ENABLED)
 	{
 	  if (!is_openvpn_protocol (&sb->buf))
 	    {
dc46c067
 	      msg (D_STREAM_ERRORS, "Non-OpenVPN client protocol detected");
6add6b2f
 	      sb->port_share_state = PS_FOREIGN;
 	      sb->error = true;
 	      return false;
 	    }
 	  else
 	    sb->port_share_state = PS_DISABLED;
 	}
 #endif
 
6fbf66fa
       ASSERT (buf_read (&sb->buf, &net_size, sizeof (net_size)));
       sb->len = ntohps (net_size);
 
       if (sb->len < 1 || sb->len > sb->maxlen)
 	{
afa7ddf0
 	  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);
6fbf66fa
 	  stream_buf_reset (sb);
 	  sb->error = true;
 	  return false;
 	}
     }
 
   /* is our incoming packet fully read? */
   if (sb->len > 0 && sb->buf.len >= sb->len)
     {
       /* 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;
     }
   else
     {
       dmsg (D_STREAM_DEBUG, "STREAM: ADD returned FALSE (have=%d need=%d)", sb->buf.len, sb->len);
       stream_buf_set_next (sb);
       return false;
     }
 }
 
 void
 stream_buf_close (struct stream_buf* sb)
 {
   free_buf (&sb->residual);
 }
 
 /*
  * 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
 socket_listen_event_handle (struct link_socket *s)
 {
 #ifdef WIN32
   if (!defined_net_event_win32 (&s->listen_handle))
     init_net_event_win32 (&s->listen_handle, FD_ACCEPT, s->sd, 0);
   return &s->listen_handle;
 #else
   return s->sd;
 #endif
 }
 
 /*
  * Format IP addresses in ascii
  */
 
 const char *
d3310d2e
 print_sockaddr_ex (const struct sockaddr *sa,
 				   const char* separator,
 				   const unsigned int flags,
 				   struct gc_arena *gc)
6fbf66fa
 {
fc9a44e2
   struct buffer out = alloc_buf_gc (128, gc);
5ead2ae0
   bool addr_is_defined = false;
d3310d2e
   char hostaddr[NI_MAXHOST] = "";
   char servname[NI_MAXSERV] = "";
   int status;
 
5ead2ae0
   socklen_t salen = 0;
d3310d2e
   switch(sa->sa_family)
d9c04efc
     {
8335caf9
     case AF_INET:
2191c471
       if (!(flags & PS_DONT_SHOW_FAMILY))
         buf_puts (&out, "[AF_INET]");
d3310d2e
       salen = sizeof (struct sockaddr_in);
       addr_is_defined = ((struct sockaddr_in*) sa)->sin_addr.s_addr != 0;
d9c04efc
       break;
8335caf9
     case AF_INET6:
2191c471
       if (!(flags & PS_DONT_SHOW_FAMILY))
         buf_puts (&out, "[AF_INET6]");
d3310d2e
       salen = sizeof (struct sockaddr_in6);
       addr_is_defined = !IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6*) sa)->sin6_addr);
8335caf9
       break;
d3310d2e
     case AF_UNSPEC:
2191c471
       if (!(flags & PS_DONT_SHOW_FAMILY))
         return "[AF_UNSPEC]";
       else
         return "";
fc9a44e2
     default:
       ASSERT(0);
d9c04efc
     }
d3310d2e
 
   status = getnameinfo(sa, salen, hostaddr, sizeof (hostaddr),
               servname, sizeof(servname), NI_NUMERICHOST | NI_NUMERICSERV);
 
   if(status!=0) {
       buf_printf(&out,"[nameinfo() err: %s]",gai_strerror(status));
       return BSTR(&out);
   }
 
   if (!(flags & PS_DONT_SHOW_ADDR))
     {
       if (addr_is_defined)
         buf_puts (&out, hostaddr);
       else
         buf_puts (&out, "[undef]");
     }
 
   if ((flags & PS_SHOW_PORT) || (flags & PS_SHOW_PORT_IF_DEFINED))
     {
       if (separator)
         buf_puts (&out, separator);
 
       buf_puts (&out, servname);
     }
 
8335caf9
   return BSTR (&out);
8bc93d7f
 }
 
 const char *
 print_link_socket_actual (const struct link_socket_actual *act, struct gc_arena *gc)
 {
   return print_link_socket_actual_ex (act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc);
 }
 
6dbf82a9
 #ifndef IF_NAMESIZE
 #define IF_NAMESIZE 16
 #endif
 
8bc93d7f
 const char *
 print_link_socket_actual_ex (const struct link_socket_actual *act,
 			     const char *separator,
 			     const unsigned int flags,
 			     struct gc_arena *gc)
 {
   if (act)
     {
5d6dbb03
       char ifname[IF_NAMESIZE] = "[undef]";
8bc93d7f
       struct buffer out = alloc_buf_gc (128, gc);
d3310d2e
       buf_printf (&out, "%s", print_sockaddr_ex (&act->dest.addr.sa, separator, flags, gc));
8bc93d7f
 #if ENABLE_IP_PKTINFO
8335caf9
       if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act))
8bc93d7f
 	{
8335caf9
 	  switch(act->dest.addr.sa.sa_family)
 	    {
d9c04efc
 	    case AF_INET:
 		{
 		  struct openvpn_sockaddr sa;
 		  CLEAR (sa);
830038fc
 		  sa.addr.in4.sin_family = AF_INET;
d3774cdf
 #ifdef IP_PKTINFO
d9c04efc
 		  sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst;
5d6dbb03
 		  if_indextoname(act->pi.in4.ipi_ifindex, ifname);
d3774cdf
 #elif defined(IP_RECVDSTADDR)
 		  sa.addr.in4.sin_addr = act->pi.in4;
 		  ifname[0]=0;
 #else
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
5d6dbb03
 		  buf_printf (&out, " (via %s%%%s)",
d3310d2e
 			      print_sockaddr_ex (&sa.addr.sa, separator, 0, gc),
5d6dbb03
 			      ifname);
d9c04efc
 		}
51afc8b8
 	      break;
d9c04efc
 	    case AF_INET6:
 		{
 		  struct sockaddr_in6 sin6;
 		  char buf[INET6_ADDRSTRLEN] = "[undef]";
1ad6fc29
 		  CLEAR(sin6);
d9c04efc
 		  sin6.sin6_family = AF_INET6;
 		  sin6.sin6_addr = act->pi.in6.ipi6_addr;
5d6dbb03
 		  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);
d9c04efc
 		}
 	      break;
 	    }
8bc93d7f
 	}
 #endif
       return BSTR (&out);
     }
   else
     return "[NULL]";
6fbf66fa
 }
 
 /*
  * Convert an in_addr_t in host byte order
  * to an ascii dotted quad.
  */
 const char *
 print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc)
 {
   struct in_addr ia;
   struct buffer out = alloc_buf_gc (64, gc);
 
   if (addr || !(flags & IA_EMPTY_IF_UNDEF))
     {
       CLEAR (ia);
       ia.s_addr = (flags & IA_NET_ORDER) ? addr : htonl (addr);
 
       buf_printf (&out, "%s", inet_ntoa (ia));
     }
   return BSTR (&out);
 }
 
512cda46
 /*
  * Convert an in6_addr in host byte order
  * to an ascii representation of an IPv6 address
  */
 const char *
 print_in6_addr (struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
 {
   struct buffer out = alloc_buf_gc (64, gc);
   char tmp_out_buf[64];		/* inet_ntop wants pointer to buffer */
 
   if ( memcmp(&a6, &in6addr_any, sizeof(a6)) != 0 || 
        !(flags & IA_EMPTY_IF_UNDEF))
     {
       inet_ntop (AF_INET6, &a6, tmp_out_buf, sizeof(tmp_out_buf)-1);
       buf_printf (&out, "%s", tmp_out_buf );
     }
   return BSTR (&out);
 }
 
1ffdb2c9
 #ifndef UINT8_MAX
 # define UINT8_MAX 0xff
 #endif
 
512cda46
 /* add some offset to an ipv6 address
1ffdb2c9
  * (add in steps of 8 bits, taking overflow into next round)
512cda46
  */
 struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add )
 {
     int i;
 
1ffdb2c9
     for( i=15; i>=0 && add > 0 ; i-- )
512cda46
     {
1ffdb2c9
 	register int carry;
 	register uint32_t h;
 
 	h = (unsigned char) base.s6_addr[i];
 	base.s6_addr[i] = (h+add) & UINT8_MAX;
 
 	/* using explicit carry for the 8-bit additions will catch
          * 8-bit and(!) 32-bit overruns nicely
512cda46
          */
1ffdb2c9
 	carry = ((h & 0xff)  + (add & 0xff)) >> 8;
 	add = (add>>8) + carry;
512cda46
     }
     return base;
 }
 
6fbf66fa
 /* set environmental variables for ip/port in *addr */
 void
5cfe3d4c
 setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const unsigned int flags)
6fbf66fa
 {
   char name_buf[256];
 
4d3df224
   char buf[128];
d9c04efc
   switch(addr->addr.sa.sa_family)
     {
8335caf9
     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);
6fbf66fa
 
8335caf9
       setenv_str (es, name_buf, inet_ntoa (addr->addr.in4.sin_addr));
 
       if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port)
d9c04efc
 	{
 	  openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix);
 	  setenv_int (es, name_buf, ntohs (addr->addr.in4.sin_port));
 	}
       break;
8335caf9
     case AF_INET6:
0b1a68ff
       if ( IN6_IS_ADDR_V4MAPPED( &addr->addr.in6.sin6_addr ))
 	{
 	  struct in_addr ia;
 	  ia.s_addr = *(in_addr_t *)&addr->addr.in6.sin6_addr.s6_addr[12] ;
 	  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);
 	}
8335caf9
       setenv_str (es, name_buf, buf);
6fbf66fa
 
86093c1c
       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));
 	}
8335caf9
       break;
d9c04efc
     }
6fbf66fa
 }
 
 void
5cfe3d4c
 setenv_in_addr_t (struct env_set *es, const char *name_prefix, in_addr_t addr, const unsigned int flags)
6fbf66fa
 {
   if (addr || !(flags & SA_SET_IF_NONZERO))
     {
8bc93d7f
       struct openvpn_sockaddr si;
6fbf66fa
       CLEAR (si);
8335caf9
       si.addr.in4.sin_family = AF_INET;
       si.addr.in4.sin_addr.s_addr = htonl (addr);
6fbf66fa
       setenv_sockaddr (es, name_prefix, &si, flags);
     }
 }
 
8bc93d7f
 void
a8f8b926
 setenv_in6_addr (struct env_set *es,
                  const char *name_prefix,
                  const struct in6_addr *addr,
                  const unsigned int flags)
 {
   if (!IN6_IS_ADDR_UNSPECIFIED (addr) || !(flags & SA_SET_IF_NONZERO))
     {
       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);
     }
 }
 
 void
8bc93d7f
 setenv_link_socket_actual (struct env_set *es,
 			   const char *name_prefix,
 			   const struct link_socket_actual *act,
5cfe3d4c
 			   const unsigned int flags)
8bc93d7f
 {
   setenv_sockaddr (es, name_prefix, &act->dest, flags);
 }
 
6fbf66fa
 /*
  * Convert protocol names between index and ascii form.
  */
 
 struct proto_names {
   const char *short_form;
   const char *display_form;
30077d1f
   sa_family_t proto_af;
   int proto;
6fbf66fa
 };
 
 /* Indexed by PROTO_x */
30077d1f
 static const struct proto_names proto_names[] = {
   {"proto-uninitialized",        "proto-NONE", AF_UNSPEC, PROTO_NONE},
23d61c56
   /* 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 */
30077d1f
   {"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)
 {
   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)
 {
   if (proto < 0 || proto >= PROTO_N)
     ASSERT(0);
30077d1f
   return proto == PROTO_UDP;
8335caf9
 }
30077d1f
 
8335caf9
 bool
 proto_is_tcp(int proto)
 {
   if (proto < 0 || proto >= PROTO_N)
     ASSERT(0);
d0ce829f
   return proto == PROTO_TCP_CLIENT || proto == PROTO_TCP_SERVER;
8335caf9
 }
 
6fbf66fa
 int
 ascii2proto (const char* proto_name)
 {
   int i;
30077d1f
   for (i = 0; i < SIZE (proto_names); ++i)
6fbf66fa
     if (!strcmp (proto_name, proto_names[i].short_form))
30077d1f
       return proto_names[i].proto;
6fbf66fa
   return -1;
 }
 
30077d1f
 sa_family_t
 ascii2af (const char* proto_name)
 {
     int i;
     for (i = 0; i < SIZE (proto_names); ++i)
         if (!strcmp (proto_name, proto_names[i].short_form))
             return proto_names[i].proto_af;
     return 0;
 }
 
6fbf66fa
 const char *
30077d1f
 proto2ascii (int proto, sa_family_t af, bool display_form)
6fbf66fa
 {
30077d1f
   unsigned int i;
   for (i = 0; i < SIZE (proto_names); ++i)
     {
       if(proto_names[i].proto_af == af && proto_names[i].proto == proto)
         {
           if(display_form)
               return proto_names[i].display_form;
           else
               return proto_names[i].short_form;
         }
     }
 
   return "[unknown protocol]";
6fbf66fa
 }
 
 const char *
 proto2ascii_all (struct gc_arena *gc)
 {
   struct buffer out = alloc_buf_gc (256, gc);
   int i;
 
30077d1f
   for (i = 0; i < SIZE (proto_names); ++i)
6fbf66fa
     {
       if (i)
 	buf_printf(&out, " ");
30077d1f
       buf_printf(&out, "[%s]", proto_names[i].short_form);
6fbf66fa
     }
   return BSTR (&out);
 }
 
8335caf9
 const char *
 addr_family_name (int af) 
 {
51afc8b8
   switch (af)
     {
     case AF_INET:  return "AF_INET";
8335caf9
     case AF_INET6: return "AF_INET6";
51afc8b8
     }
8335caf9
   return "AF_UNSPEC";
 }
 
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
  */
34136dd8
 const char*
6fbf66fa
 proto_remote (int proto, bool remote)
 {
   ASSERT (proto >= 0 && proto < PROTO_N);
34136dd8
   if (proto == PROTO_UDP)
 	return "UDPv4";
 
   if ( (remote && proto == PROTO_TCP_CLIENT) ||
        (!remote && proto == PROTO_TCP_SERVER))
 	return "TCPv4_SERVER";
   if ( (remote && proto == PROTO_TCP_SERVER) ||
        (!remote && proto == PROTO_TCP_CLIENT))
 	return "TCPv4_CLIENT";
 
   ASSERT (0);
7dbe04de
   return ""; /* Make the compiler happy */
6fbf66fa
 }
 
 /*
  * Bad incoming address lengths that differ from what
  * we expect are considered to be fatal errors.
  */
 void
 bad_address_length (int actual, int expected)
 {
   msg (M_FATAL, "ERROR: received strange incoming packet with an address length of %d -- we only accept address lengths of %d.",
        actual,
        expected);
 }
 
 /*
  * Socket Read Routines
  */
 
 int
 link_socket_read_tcp (struct link_socket *sock,
 		      struct buffer *buf)
 {
   int len = 0;
 
   if (!sock->stream_buf.residual_fully_formed)
     {
 #ifdef WIN32
       len = socket_finalize (sock->sd, &sock->reads, buf, NULL);
 #else
       struct buffer frag;
       stream_buf_get_next (&sock->stream_buf, &frag);
       len = recv (sock->sd, BPTR (&frag), BLEN (&frag), MSG_NOSIGNAL);
 #endif
 
       if (!len)
 	sock->stream_reset = true;
       if (len <= 0)
 	return buf->len = len;
     }
 
   if (sock->stream_buf.residual_fully_formed
       || stream_buf_added (&sock->stream_buf, len)) /* packet complete? */
     {
       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 */
 }
 
 #ifndef WIN32
 
8bc93d7f
 #if ENABLE_IP_PKTINFO
 
1bda73a7
 #pragma pack(1) /* needed to keep structure size consistent for 32 vs. 64-bit architectures */
8335caf9
 struct openvpn_in4_pktinfo
8bc93d7f
 {
   struct cmsghdr cmsghdr;
d3774cdf
 #ifdef HAVE_IN_PKTINFO
830038fc
   struct in_pktinfo pi4;
c02a8405
 #elif defined(IP_RECVDSTADDR)
d3774cdf
   struct in_addr pi4;
 #endif
8335caf9
 };
 struct openvpn_in6_pktinfo
 {
   struct cmsghdr cmsghdr;
   struct in6_pktinfo pi6;
 };
 
 union openvpn_pktinfo {
830038fc
 	struct openvpn_in4_pktinfo msgpi4;
 	struct openvpn_in6_pktinfo msgpi6;
8bc93d7f
 };
1bda73a7
 #pragma pack()
8bc93d7f
 
 static socklen_t
 link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
 				    struct buffer *buf,
 				    struct link_socket_actual *from)
 {
   struct iovec iov;
8335caf9
   union openvpn_pktinfo opi;
8bc93d7f
   struct msghdr mesg;
8335caf9
   socklen_t fromlen = sizeof (from->dest.addr);
8bc93d7f
 
   iov.iov_base = BPTR (buf);
3c1b19e0
   iov.iov_len = buf_forward_capacity_total (buf);
8bc93d7f
   mesg.msg_iov = &iov;
   mesg.msg_iovlen = 1;
8335caf9
   mesg.msg_name = &from->dest.addr;
8bc93d7f
   mesg.msg_namelen = fromlen;
   mesg.msg_control = &opi;
830038fc
   mesg.msg_controllen = sizeof opi;
8bc93d7f
   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
d3774cdf
 #ifdef IP_PKTINFO
8bc93d7f
 	  && cmsg->cmsg_level == SOL_IP 
 	  && cmsg->cmsg_type == IP_PKTINFO
d3774cdf
 #elif defined(IP_RECVDSTADDR)
 	  && cmsg->cmsg_level == IPPROTO_IP
 	  && cmsg->cmsg_type == IP_RECVDSTADDR
 #else
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
830038fc
 	  && cmsg->cmsg_len >= sizeof (struct openvpn_in4_pktinfo))
8bc93d7f
 	{
d3774cdf
 #ifdef IP_PKTINFO
8bc93d7f
 	  struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
8335caf9
 	  from->pi.in4.ipi_ifindex = pkti->ipi_ifindex;
 	  from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst;
d3774cdf
 #elif defined(IP_RECVDSTADDR)
 	  from->pi.in4 = *(struct in_addr*) CMSG_DATA (cmsg);
 #else
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
8bc93d7f
 	}
8335caf9
       else if (cmsg != NULL
 	  && CMSG_NXTHDR (&mesg, cmsg) == NULL
 	  && cmsg->cmsg_level == IPPROTO_IPV6 
 	  && cmsg->cmsg_type == IPV6_PKTINFO
 	  && cmsg->cmsg_len >= sizeof (struct openvpn_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;
 	}
7dbe04de
       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 );
 	}
8bc93d7f
     }
7dbe04de
 
8bc93d7f
   return fromlen;
 }
 #endif
 
6fbf66fa
 int
 link_socket_read_udp_posix (struct link_socket *sock,
 			    struct buffer *buf,
8bc93d7f
 			    struct link_socket_actual *from)
6fbf66fa
 {
8335caf9
   socklen_t fromlen = sizeof (from->dest.addr);
30077d1f
   socklen_t expectedlen = af_addr_size(sock->info.af);
8335caf9
   addr_zero_host(&from->dest);
8bc93d7f
 #if ENABLE_IP_PKTINFO
8335caf9
   /* Both PROTO_UDPv4 and PROTO_UDPv6 */
30077d1f
   if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO)
3c1b19e0
     fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, from);
8bc93d7f
   else
 #endif
3c1b19e0
     buf->len = recvfrom (sock->sd, BPTR (buf), buf_forward_capacity(buf), 0,
8335caf9
 			 &from->dest.addr.sa, &fromlen);
78b8fc72
   /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */
8335caf9
   if (buf->len >= 0 && expectedlen && fromlen != expectedlen)
     bad_address_length (fromlen, expectedlen);
6fbf66fa
   return buf->len;
 }
 
 #endif
 
 /*
  * Socket Write Routines
  */
 
 int
 link_socket_write_tcp (struct link_socket *sock,
 		       struct buffer *buf,
8bc93d7f
 		       struct link_socket_actual *to)
6fbf66fa
 {
   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)));
 #ifdef WIN32
   return link_socket_write_win32 (sock, buf, to);
 #else
   return link_socket_write_tcp_posix (sock, buf, to);  
 #endif
 }
 
8bc93d7f
 #if ENABLE_IP_PKTINFO
 
23d61c56
 size_t
8bc93d7f
 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;
8c431f96
   union openvpn_pktinfo opi;
8bc93d7f
 
   iov.iov_base = BPTR (buf);
   iov.iov_len = BLEN (buf);
   mesg.msg_iov = &iov;
   mesg.msg_iovlen = 1;
7dbe04de
   switch (to->dest.addr.sa.sa_family)
d9c04efc
     {
     case AF_INET:
       {
         mesg.msg_name = &to->dest.addr.sa;
         mesg.msg_namelen = sizeof (struct sockaddr_in);
8c431f96
         mesg.msg_control = &opi;
d9c04efc
         mesg.msg_flags = 0;
661d914c
 #ifdef HAVE_IN_PKTINFO
         mesg.msg_controllen = sizeof (struct openvpn_in4_pktinfo);
d9c04efc
         cmsg = CMSG_FIRSTHDR (&mesg);
830038fc
         cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo);
d9c04efc
         cmsg->cmsg_level = SOL_IP;
         cmsg->cmsg_type = IP_PKTINFO;
d3774cdf
 	{
         struct in_pktinfo *pkti;
d9c04efc
         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)
661d914c
 	ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(opi) );
         mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_addr));
         cmsg = CMSG_FIRSTHDR (&mesg);
         cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
d3774cdf
         cmsg->cmsg_level = IPPROTO_IP;
         cmsg->cmsg_type = IP_RECVDSTADDR;
         *(struct in_addr *) CMSG_DATA (cmsg) = to->pi.in4;
 #else
 #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
 #endif
d9c04efc
         break;
       }
     case AF_INET6:
       {
         struct in6_pktinfo *pkti6;
         mesg.msg_name = &to->dest.addr.sa;
         mesg.msg_namelen = sizeof (struct sockaddr_in6);
8c431f96
         mesg.msg_control = &opi;
         mesg.msg_controllen = sizeof (struct openvpn_in6_pktinfo);
d9c04efc
         mesg.msg_flags = 0;
         cmsg = CMSG_FIRSTHDR (&mesg);
830038fc
         cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo);
d9c04efc
         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;
       }
8335caf9
     default: ASSERT(0);
d9c04efc
     }
8bc93d7f
   return sendmsg (sock->sd, &mesg, 0);
 }
 
 #endif
 
6fbf66fa
 /*
  * Win32 overlapped socket I/O functions.
  */
 
 #ifdef WIN32
 
 int
 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 */
1ad6fc29
       if (proto_is_udp(sock->info.proto))
6fbf66fa
 	{
 	  sock->reads.buf = sock->reads.buf_init;
 	}
1ad6fc29
       else if (proto_is_tcp(sock->info.proto))
6fbf66fa
 	{
 	  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;
 
1ad6fc29
       if (proto_is_udp(sock->info.proto))
6fbf66fa
 	{
 	  sock->reads.addr_defined = true;
78b8fc72
 	  sock->reads.addrlen = sizeof (sock->reads.addr6);
6fbf66fa
 	  status = WSARecvFrom(
 			       sock->sd,
 			       wsabuf,
 			       1,
 			       &sock->reads.size,
 			       &sock->reads.flags,
 			       (struct sockaddr *) &sock->reads.addr,
 			       &sock->reads.addrlen,
 			       &sock->reads.overlapped,
 			       NULL);
 	}
1ad6fc29
       else if (proto_is_tcp(sock->info.proto))
6fbf66fa
 	{
 	  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? */
 	{
78b8fc72
 	  /* 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);
6fbf66fa
 	  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;
 }
 
 int
8bc93d7f
 socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct link_socket_actual *to)
6fbf66fa
 {
   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;
 
1ad6fc29
       if (proto_is_udp(sock->info.proto))
6fbf66fa
 	{
 	  /* set destination address for UDP writes */
 	  sock->writes.addr_defined = true;
78b8fc72
 	  if (to->dest.addr.sa.sa_family == AF_INET6)
b7f203c8
 	    {
 	      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);
 	    }
6fbf66fa
 
 	  status = WSASendTo(
 			       sock->sd,
 			       wsabuf,
 			       1,
 			       &sock->writes.size,
 			       sock->writes.flags,
 			       (struct sockaddr *) &sock->writes.addr,
 			       sock->writes.addrlen,
 			       &sock->writes.overlapped,
 			       NULL);
 	}
1ad6fc29
       else if (proto_is_tcp(sock->info.proto))
6fbf66fa
 	{
 	  /* 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;
 }
 
 int
8bc93d7f
 socket_finalize (SOCKET s,
6fbf66fa
 		 struct overlapped_io *io,
 		 struct buffer *buf,
8bc93d7f
 		 struct link_socket_actual *from)
6fbf66fa
 {
   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));
910675de
 	      msg (D_WIN32_IO | M_ERRNO, "WIN32 I/O: Socket Completion error");
6fbf66fa
 	    }
 	}
       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;
910675de
 	  msg (D_WIN32_IO | M_ERRNO, "WIN32 I/O: Socket Completion non-queued error");
6fbf66fa
 	}
       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)
b7f203c8
 	{
 	  /* 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):
eb230891
 	    /* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6
 	     * under WIN32*/
b7f203c8
 	    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;
 	    }
 	}
6fbf66fa
       else
4d3df224
 	CLEAR (from->dest.addr);
6fbf66fa
     }
   
   if (buf)
     buf->len = ret;
   return ret;
 }
 
 #endif /* WIN32 */
 
 /*
  * Socket event notification
  */
 
 unsigned int
 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;
 	}
       
 #ifdef WIN32
       if (rwflags & EVENT_READ)
 	socket_recv_queue (s, 0);
 #endif
 
       /* 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;
 	}
 
       s->rwflags_debug = rwflags;
     }
   return rwflags;
 }
bb564a59
 
 void
 sd_close (socket_descriptor_t *sd)
 {
   if (sd && socket_defined (*sd))
     {
       openvpn_close_socket (*sd);
       *sd = SOCKET_UNDEFINED;
     }
 }
 
 #if UNIX_SOCK_SUPPORT
 
 /*
  * code for unix domain sockets
  */
 
 const char *
 sockaddr_unix_name (const struct sockaddr_un *local, const char *null)
 {
   if (local && local->sun_family == PF_UNIX)
     return local->sun_path;
   else
     return null;
 }
 
 socket_descriptor_t
 create_socket_unix (void)
 {
   socket_descriptor_t sd;
 
   if ((sd = socket (PF_UNIX, SOCK_STREAM, 0)) < 0)
910675de
     msg (M_ERR, "Cannot create unix domain socket");
bb564a59
   return sd;
 }
 
 void
 socket_bind_unix (socket_descriptor_t sd,
 		  struct sockaddr_un *local,
 		  const char *prefix)
 {
   struct gc_arena gc = gc_new ();
 
 #ifdef HAVE_UMASK
   const mode_t orig_umask = umask (0);
 #endif
 
   if (bind (sd, (struct sockaddr *) local, sizeof (struct sockaddr_un)))
     {
910675de
       const int errnum = openvpn_errno ();
bb564a59
       msg (M_FATAL, "%s: Socket bind[%d] failed on unix domain socket %s: %s",
 	   prefix,
 	   (int)sd,
            sockaddr_unix_name (local, "NULL"),
            strerror_ts (errnum, &gc));
     }
 
 #ifdef HAVE_UMASK
   umask (orig_umask);
 #endif
 
   gc_free (&gc);
 }
 
 socket_descriptor_t
 socket_accept_unix (socket_descriptor_t sd,
 		    struct sockaddr_un *remote)
 {
   socklen_t remote_len = sizeof (struct sockaddr_un);
   socket_descriptor_t ret;
 
   CLEAR (*remote);
   ret = accept (sd, (struct sockaddr *) remote, &remote_len);
   return ret;
 }
 
86f5c7c9
 int
 socket_connect_unix (socket_descriptor_t sd,
 		     struct sockaddr_un *remote)
 {
   int status = connect (sd, (struct sockaddr *) remote, sizeof (struct sockaddr_un));
   if (status)
910675de
     status = openvpn_errno ();
86f5c7c9
   return status;
 }
 
bb564a59
 void
 sockaddr_unix_init (struct sockaddr_un *local, const char *path)
 {
   local->sun_family = PF_UNIX;
   strncpynt (local->sun_path, path, sizeof (local->sun_path));
 }
 
 void
 socket_delete_unix (const struct sockaddr_un *local)
 {
   const char *name = sockaddr_unix_name (local, NULL);
 #ifdef HAVE_UNLINK
   if (name && strlen (name))
     unlink (name);
 #endif
 }
 
 bool
 unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int *gid)
 {
 #ifdef HAVE_GETPEEREID
   uid_t u;
   gid_t g;
   if (getpeereid (sd, &u, &g) == -1) 
     return false;
   if (uid)
     *uid = u;
   if (gid)
     *gid = g;
   return true;
 #elif defined(SO_PEERCRED)
   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
   return false;
 #endif
 }
 
 #endif