diff options
Diffstat (limited to 'openvpn/src')
39 files changed, 1392 insertions, 1440 deletions
| diff --git a/openvpn/src/openvpn/buffer.c b/openvpn/src/openvpn/buffer.c index 5eee3ee4..56d14b1a 100644 --- a/openvpn/src/openvpn/buffer.c +++ b/openvpn/src/openvpn/buffer.c @@ -782,6 +782,16 @@ char_class (const unsigned char c, const unsigned int flags)      return true;    if ((flags & CC_EQUAL) && c == '=')      return true; +  if ((flags & CC_LESS_THAN) && c == '<') +    return true; +  if ((flags & CC_GREATER_THAN) && c == '>') +    return true; +  if ((flags & CC_PIPE) && c == '|') +    return true; +  if ((flags & CC_QUESTION_MARK) && c == '?') +    return true; +  if ((flags & CC_ASTERISK) && c == '*') +    return true;    return false;  } diff --git a/openvpn/src/openvpn/buffer.h b/openvpn/src/openvpn/buffer.h index 9bc33dba..5e11de05 100644 --- a/openvpn/src/openvpn/buffer.h +++ b/openvpn/src/openvpn/buffer.h @@ -736,6 +736,11 @@ const char *np (const char *str);  #define CC_REVERSE_QUOTE      (1<<23)  #define CC_AT                 (1<<24)  #define CC_EQUAL              (1<<25) +#define CC_LESS_THAN          (1<<26) +#define CC_GREATER_THAN       (1<<27) +#define CC_PIPE               (1<<28) +#define CC_QUESTION_MARK      (1<<29) +#define CC_ASTERISK           (1<<30)  /* macro classes */  #define CC_NAME               (CC_ALNUM|CC_UNDERBAR) diff --git a/openvpn/src/openvpn/error.c b/openvpn/src/openvpn/error.c index 6848425e..ebe9a52d 100644 --- a/openvpn/src/openvpn/error.c +++ b/openvpn/src/openvpn/error.c @@ -259,7 +259,7 @@ void x_msg_va (const unsigned int flags, const char *format, va_list arglist)    if (flags & M_SSL)      {        int nerrs = 0; -      int err; +      size_t err;        while ((err = ERR_get_error ()))  	{  	  openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s", @@ -602,7 +602,7 @@ x_check_status (int status,    const char *extended_msg = NULL;    msg (x_cs_verbose_level, "%s %s returned %d", -       sock ? proto2ascii (sock->info.proto, true) : "", +       sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "",         description,         status); @@ -630,14 +630,14 @@ x_check_status (int status,  	  if (extended_msg)  	    msg (x_cs_info_level, "%s %s [%s]: %s (code=%d)",  		 description, -		 sock ? proto2ascii (sock->info.proto, true) : "", +		 sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "",  		 extended_msg,  		 strerror_ts (my_errno, &gc),  		 my_errno);  	  else  	    msg (x_cs_info_level, "%s %s: %s (code=%d)",  		 description, -		 sock ? proto2ascii (sock->info.proto, true) : "", +		 sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "",  		 strerror_ts (my_errno, &gc),  		 my_errno); diff --git a/openvpn/src/openvpn/forward-inline.h b/openvpn/src/openvpn/forward-inline.h index 5853ce29..7eb480dd 100644 --- a/openvpn/src/openvpn/forward-inline.h +++ b/openvpn/src/openvpn/forward-inline.h @@ -228,6 +228,7 @@ context_reschedule_sec (struct context *c, int sec)  static inline struct link_socket_info *  get_link_socket_info (struct context *c)  { +    if (c->c2.link_socket_info)      return c->c2.link_socket_info;    else diff --git a/openvpn/src/openvpn/forward.c b/openvpn/src/openvpn/forward.c index 57c78462..9e9c406c 100644 --- a/openvpn/src/openvpn/forward.c +++ b/openvpn/src/openvpn/forward.c @@ -620,7 +620,7 @@ check_timeout_random_component (struct context *c)  static inline void  socks_postprocess_incoming_link (struct context *c)  { -  if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4) +  if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDP)      socks_process_incoming_udp (&c->c2.buf, &c->c2.from);  } @@ -629,7 +629,7 @@ socks_preprocess_outgoing_link (struct context *c,  				struct link_socket_actual **to_addr,  				int *size_delta)  { -  if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4) +  if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDP)      {        *size_delta += socks_process_outgoing_udp (&c->c2.to_link, c->c2.to_link_addr);        *to_addr = &c->c2.link_socket->socks_relay; @@ -778,7 +778,7 @@ process_incoming_link (struct context *c)      fprintf (stderr, "R");  #endif    msg (D_LINK_RW, "%s READ [%d] from %s: %s", -       proto2ascii (lsi->proto, true), +       proto2ascii (lsi->proto, lsi->af, true),         BLEN (&c->c2.buf),         print_link_socket_actual (&c->c2.from, &gc),         PROTO_DUMP (&c->c2.buf, &gc)); @@ -985,9 +985,9 @@ process_incoming_tun (struct context *c)      {        /*         * The --passtos and --mssfix options require -       * us to examine the IPv4 header. +       * us to examine the IP header (IPv4 or IPv6).         */ -      process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf); +      process_ip_header (c, PIPV4_PASSTOS|PIP_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf);  #ifdef PACKET_TRUNCATION_CHECK        /* if (c->c2.buf.len > 1) --c->c2.buf.len; */ @@ -1009,10 +1009,10 @@ process_incoming_tun (struct context *c)  }  void -process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf) +process_ip_header (struct context *c, unsigned int flags, struct buffer *buf)  {    if (!c->options.ce.mssfix) -    flags &= ~PIPV4_MSSFIX; +    flags &= ~PIP_MSSFIX;  #if PASSTOS_CAPABILITY    if (!c->options.passtos)      flags &= ~PIPV4_PASSTOS; @@ -1027,9 +1027,9 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)         * us to examine the IPv4 header.         */  #if PASSTOS_CAPABILITY -      if (flags & (PIPV4_PASSTOS|PIPV4_MSSFIX)) +      if (flags & (PIPV4_PASSTOS|PIP_MSSFIX))  #else -      if (flags & PIPV4_MSSFIX) +      if (flags & PIP_MSSFIX)  #endif  	{  	  struct buffer ipbuf = *buf; @@ -1042,8 +1042,8 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)  #endif  	      /* possibly alter the TCP MSS */ -	      if (flags & PIPV4_MSSFIX) -		mss_fixup (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame))); +	      if (flags & PIP_MSSFIX) +		mss_fixup_ipv4 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));  #ifdef ENABLE_CLIENT_NAT  	      /* possibly do NAT on packet */ @@ -1061,6 +1061,12 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)  		    route_list_add_vpn_gateway (c->c1.route_list, c->c2.es, dhcp_router);  		}  	    } +	  else if (is_ipv6 (TUNNEL_TYPE (c->c1.tuntap), &ipbuf)) +	    { +	      /* possibly alter the TCP MSS */ +	      if (flags & PIP_MSSFIX) +		mss_fixup_ipv6 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame))); +	    }  	}      }  } @@ -1116,7 +1122,7 @@ process_outgoing_link (struct context *c)  	    fprintf (stderr, "W");  #endif  	  msg (D_LINK_RW, "%s WRITE [%d] to %s: %s", -	       proto2ascii (c->c2.link_socket->info.proto, true), +	       proto2ascii (c->c2.link_socket->info.proto, c->c2.link_socket->info.proto, true),  	       BLEN (&c->c2.to_link),  	       print_link_socket_actual (c->c2.to_link_addr, &gc),  	       PROTO_DUMP (&c->c2.to_link, &gc)); @@ -1217,9 +1223,9 @@ process_outgoing_tun (struct context *c)    /*     * The --mssfix option requires -   * us to examine the IPv4 header. +   * us to examine the IP header (IPv4 or IPv6).     */ -  process_ipv4_header (c, PIPV4_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun); +  process_ip_header (c, PIP_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun);    if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN (&c->c2.frame))      { diff --git a/openvpn/src/openvpn/forward.h b/openvpn/src/openvpn/forward.h index 0f829bde..1830a00b 100644 --- a/openvpn/src/openvpn/forward.h +++ b/openvpn/src/openvpn/forward.h @@ -228,12 +228,12 @@ void process_outgoing_tun (struct context *c);  bool send_control_channel_string (struct context *c, const char *str, int msglevel);  #define PIPV4_PASSTOS         (1<<0) -#define PIPV4_MSSFIX          (1<<1) +#define PIP_MSSFIX            (1<<1)         /* v4 and v6 */  #define PIPV4_OUTGOING        (1<<2)  #define PIPV4_EXTRACT_DHCP_ROUTER (1<<3)  #define PIPV4_CLIENT_NAT      (1<<4) -void process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf); +void process_ip_header (struct context *c, unsigned int flags, struct buffer *buf);  #if P2MP  void schedule_exit (struct context *c, const int n_seconds, const int signal); diff --git a/openvpn/src/openvpn/init.c b/openvpn/src/openvpn/init.c index 1f06eaa5..fe70dd57 100644 --- a/openvpn/src/openvpn/init.c +++ b/openvpn/src/openvpn/init.c @@ -125,28 +125,19 @@ management_callback_proxy_cmd (void *arg, const char **p)      ret = true;    else if (p[2] && p[3])      { -      const int port = atoi(p[3]); -      if (!legal_ipv4_port (port)) -        { -          msg (M_WARN, "Bad proxy port number: %s", p[3]); -          return false; -        } -        if (streq (p[1], "HTTP"))          {  #ifndef ENABLE_HTTP_PROXY            msg (M_WARN, "HTTP proxy support is not available");  #else            struct http_proxy_options *ho; -          if (ce->proto != PROTO_TCPv4 && ce->proto != PROTO_TCPv4_CLIENT && -              ce->proto != PROTO_TCPv6 && ce->proto != PROTO_TCPv6_CLIENT) -            { +          if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_CLIENT )            {                msg (M_WARN, "HTTP proxy support only works for TCP based connections");                return false;              }            ho = init_http_proxy_options_once (&ce->http_proxy_options, gc);            ho->server = string_alloc (p[2], gc); -          ho->port = port; +          ho->port = p[3];            ho->retry = true;            ho->auth_retry = (p[4] && streq (p[4], "nct") ? PAR_NCT : PAR_ALL);            ret = true; @@ -158,7 +149,7 @@ management_callback_proxy_cmd (void *arg, const char **p)            msg (M_WARN, "SOCKS proxy support is not available");  #else            ce->socks_proxy_server = string_alloc (p[2], gc); -          ce->socks_proxy_port = port; +          ce->socks_proxy_port = p[3];            ret = true;  #endif          } @@ -225,8 +216,7 @@ management_callback_remote_cmd (void *arg, const char **p)  	}        else if (!strcmp(p[1], "MOD") && p[2] && p[3])  	{ -	  const int port = atoi(p[3]); -	  if (strlen(p[2]) < RH_HOST_LEN && legal_ipv4_port(port)) +	  if (strlen(p[2]) < RH_HOST_LEN && strlen(p[3]) < RH_PORT_LEN)  	    {  	      struct remote_host_store *rhs = c->options.rh_store;  	      if (!rhs) @@ -235,8 +225,10 @@ management_callback_remote_cmd (void *arg, const char **p)  		  c->options.rh_store = rhs;  		}  	      strncpynt(rhs->host, p[2], RH_HOST_LEN); +              strncpynt(rhs->port, p[3], RH_PORT_LEN); +  	      ce->remote = rhs->host; -	      ce->remote_port = port; +	      ce->remote_port = rhs->port;  	      flags = CE_MAN_QUERY_REMOTE_MOD;  	      ret = true;  	    } @@ -251,7 +243,7 @@ management_callback_remote_cmd (void *arg, const char **p)  }  static bool -ce_management_query_remote (struct context *c, const char *remote_ip_hint) +ce_management_query_remote (struct context *c)  {    struct gc_arena gc = gc_new ();    volatile struct connection_entry *ce = &c->options.ce; @@ -260,7 +252,7 @@ ce_management_query_remote (struct context *c, const char *remote_ip_hint)    if (management)      {        struct buffer out = alloc_buf_gc (256, &gc); -      buf_printf (&out, ">REMOTE:%s,%d,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, false)); +      buf_printf (&out, ">REMOTE:%s,%s,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, ce->af, false));        management_notify_generic(management, BSTR (&out));        ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<<CE_MAN_QUERY_REMOTE_SHIFT);        ce->flags |= (CE_MAN_QUERY_REMOTE_QUERY<<CE_MAN_QUERY_REMOTE_SHIFT); @@ -276,8 +268,6 @@ ce_management_query_remote (struct context *c, const char *remote_ip_hint)      }    {      const int flags = ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK); -    if (flags == CE_MAN_QUERY_REMOTE_ACCEPT && remote_ip_hint) -      ce->remote = remote_ip_hint;      ret = (flags != CE_MAN_QUERY_REMOTE_SKIP);    }    gc_free (&gc); @@ -292,25 +282,34 @@ static void  init_connection_list (struct context *c)  {    struct connection_list *l = c->options.connection_list; -  if (l) +  l->current = -1; +  if (c->options.remote_random)      { -      l->current = -1; -      if (c->options.remote_random) -	{ -	  int i; -	  for (i = 0; i < l->len; ++i) -	    { -	      const int j = get_random () % l->len; -	      if (i != j) -		{ -		  struct connection_entry *tmp; -		  tmp = l->array[i]; -		  l->array[i] = l->array[j]; -		  l->array[j] = tmp; -		} -	    } -	} +      int i; +      for (i = 0; i < l->len; ++i) +        { +          const int j = get_random () % l->len; +          if (i != j) +            { +              struct connection_entry *tmp; +              tmp = l->array[i]; +              l->array[i] = l->array[j]; +              l->array[j] = tmp; +            } +        } +    } +} + +/* + * Clear the remote address list + */ +static void clear_remote_addrlist (struct link_socket_addr *lsa) +{ +    if (lsa->remote_list) { +        freeaddrinfo(lsa->remote_list);      } +    lsa->remote_list = NULL; +    lsa->current_remote = NULL;  }  /* @@ -320,67 +319,84 @@ static void  next_connection_entry (struct context *c)  {    struct connection_list *l = c->options.connection_list; -  if (l) -    { -      bool ce_defined; -      struct connection_entry *ce; -      int n_cycles = 0; - -      do { -	const char *remote_ip_hint = NULL; -	bool newcycle = false; - -	ce_defined = true; -	if (l->no_advance && l->current >= 0) -	  { -	    l->no_advance = false; -	  } -	else -	  { -	    if (++l->current >= l->len) -	      { -		l->current = 0; -		++l->n_cycles; -		if (++n_cycles >= 2) -		  msg (M_FATAL, "No usable connection profiles are present"); -	      } - -	    if (l->current == 0) -	      newcycle = true; -	  } - -	ce = l->array[l->current]; +  bool ce_defined; +  struct connection_entry *ce; +  int n_cycles = 0; +   +  do { +    ce_defined = true; +    if (c->options.no_advance && l->current >= 0) +      { +        c->options.no_advance = false; +      } +    else +      { +        /* Check if there is another resolved address to try for +         * the current connection */ +        if (c->c1.link_socket_addr.current_remote && +            c->c1.link_socket_addr.current_remote->ai_next) +          { +            c->c1.link_socket_addr.current_remote = +                c->c1.link_socket_addr.current_remote->ai_next; +          } +        else +          { +            c->options.unsuccessful_attempts++; +            if (++l->current >= l->len) +              { +                /* FIXME (schwabe) fix the persist-remote-ip option for real, +                 * this is broken probably ever since connection lists and multiple +                 * remote existed +                 */ +                /* +                 * Increase the number of connection attempts +                 * If this is connect-retry-max * size(l) +                 * OpenVPN will quit +                 */ +                 +                if (!c->options.persist_remote_ip) +                    clear_remote_addrlist (&c->c1.link_socket_addr); +                 +                l->current = 0; +                ++l->n_cycles; +                if (++n_cycles >= 2) +                    msg (M_FATAL, "No usable connection profiles are present"); +              } +          } +      } -	if (c->options.remote_ip_hint && !l->n_cycles) -	  remote_ip_hint = c->options.remote_ip_hint; +    ce = l->array[l->current]; -	if (ce->flags & CE_DISABLED) -	  ce_defined = false; +    if (ce->flags & CE_DISABLED) +      ce_defined = false; -	c->options.ce = *ce; +    c->options.ce = *ce;  #ifdef ENABLE_MANAGEMENT -	if (ce_defined && management && management_query_remote_enabled(management)) -	  { -	    /* allow management interface to override connection entry details */ -	    ce_defined = ce_management_query_remote(c, remote_ip_hint); -	    if (IS_SIG (c)) -	      break; -	  } -        else +    if (ce_defined && management && management_query_remote_enabled(management)) +      { +        /* allow management interface to override connection entry details */ +        ce_defined = ce_management_query_remote(c); +        if (IS_SIG (c)) +          break; +      } +    else  #endif -	if (remote_ip_hint) -	  c->options.ce.remote = remote_ip_hint;  #ifdef ENABLE_MANAGEMENT -        if (ce_defined && management && management_query_proxy_enabled (management)) -          { -            ce_defined = ce_management_query_proxy (c); -            if (IS_SIG (c)) -              break; -          } +      if (ce_defined && management && management_query_proxy_enabled (management)) +        { +          ce_defined = ce_management_query_proxy (c); +          if (IS_SIG (c)) +            break; +        }  #endif -      } while (!ce_defined); -    } +  } while (!ce_defined); +   +  /* Check if this connection attempt would bring us over the limit */ +  if (c->options.connect_retry_max > 0 && +      c->options.unsuccessful_attempts > (l->len  * c->options.connect_retry_max)) +      msg(M_FATAL, "All connections have been connect-retry-max (%d) times unsuccessful, exiting", +          c->options.connect_retry_max);    update_options_ce_post (&c->options);  } @@ -415,12 +431,6 @@ init_query_passwords (struct context *c)  #ifdef GENERAL_PROXY_SUPPORT -static int -proxy_scope (struct context *c) -{ -  return connection_list_defined (&c->options) ? 2 : 1; -} -  static void  uninit_proxy_dowork (struct context *c)  { @@ -482,17 +492,15 @@ init_proxy_dowork (struct context *c)  }  static void -init_proxy (struct context *c, const int scope) +init_proxy (struct context *c)  { -  if (scope == proxy_scope (c)) -    init_proxy_dowork (c); +  init_proxy_dowork (c);  }  static void  uninit_proxy (struct context *c)  { -  if (c->sig->signal_received != SIGUSR1 || proxy_scope (c) == 2) -    uninit_proxy_dowork (c); +   uninit_proxy_dowork (c);  }  #else @@ -544,8 +552,6 @@ context_init_1 (struct context *c)   }  #endif -  /* initialize HTTP or SOCKS proxy object at scope level 1 */ -  init_proxy (c, 1);  }  void @@ -1240,6 +1246,9 @@ void  initialization_sequence_completed (struct context *c, const unsigned int flags)  {    static const char message[] = "Initialization Sequence Completed"; +     +  /* Reset the unsuccessful connection counter on complete initialisation */ +  c->options.unsuccessful_attempts=0;    /* If we delayed UID/GID downgrade or chroot, do it now */    do_uid_gid_chroot (c, true); @@ -1258,9 +1267,9 @@ initialization_sequence_completed (struct context *c, const unsigned int flags)    else      msg (M_INFO, "%s", message); -  /* Flag connection_list that we initialized */ -  if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0 && connection_list_defined (&c->options)) -    connection_list_set_no_advance (&c->options); +  /* Flag that we initialized */ +  if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0) +    c->options.no_advance=true;  #ifdef WIN32    fork_register_dns_action (c->c1.tuntap); @@ -1374,8 +1383,8 @@ do_init_tun (struct context *c)  			   c->options.ifconfig_ipv6_local,  			   c->options.ifconfig_ipv6_netbits,  			   c->options.ifconfig_ipv6_remote, -			   addr_host (&c->c1.link_socket_addr.local), -			   addr_host (&c->c1.link_socket_addr.remote), +			   c->c1.link_socket_addr.bind_local, +			   c->c1.link_socket_addr.remote_list,  			   !c->options.ifconfig_nowarn,  			   c->c2.es); @@ -1853,17 +1862,11 @@ socket_restart_pause (struct context *c)    switch (c->options.ce.proto)      { -    case PROTO_UDPv4: -    case PROTO_UDPv6: -      if (proxy) -	sec = c->options.ce.connect_retry_seconds; -      break; -    case PROTO_TCPv4_SERVER: -    case PROTO_TCPv6_SERVER: +    case PROTO_TCP_SERVER:        sec = 1;        break; -    case PROTO_TCPv4_CLIENT: -    case PROTO_TCPv6_CLIENT: +    case PROTO_UDP: +    case PROTO_TCP_CLIENT:        sec = c->options.ce.connect_retry_seconds;        break;      } @@ -2219,7 +2222,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)    /* should we not xmit any packets until we get an initial       response from client? */ -  if (to.server && options->ce.proto == PROTO_TCPv4_SERVER) +  if (to.server && options->ce.proto == PROTO_TCP_SERVER)      to.xmit_hold = true;  #ifdef ENABLE_OCC @@ -2504,8 +2507,6 @@ do_option_warnings (struct context *c)      msg (M_WARN, "NOTE: --connect-timeout option is not supported on this OS");  #endif -  if (script_method == SM_SYSTEM) -    msg (M_WARN, "NOTE: --script-security method='system' is deprecated due to the fact that passed parameters will be subject to shell expansion");  }  static void @@ -2628,12 +2629,12 @@ do_init_socket_1 (struct context *c, const int mode)  #endif    link_socket_init_phase1 (c->c2.link_socket, -			   connection_list_defined (&c->options),  			   c->options.ce.local,  			   c->options.ce.local_port,  			   c->options.ce.remote,  			   c->options.ce.remote_port,  			   c->options.ce.proto, +         c->options.ce.af,  			   mode,  			   c->c2.accept_from,  #ifdef ENABLE_HTTP_PROXY @@ -2652,9 +2653,7 @@ do_init_socket_1 (struct context *c, const int mode)  			   c->options.ipchange,  			   c->plugins,  			   c->options.resolve_retry_seconds, -			   c->options.ce.connect_retry_seconds,  			   c->options.ce.connect_timeout, -			   c->options.ce.connect_retry_max,  			   c->options.ce.mtu_discover_type,  			   c->options.rcvbuf,  			   c->options.sndbuf, @@ -2669,7 +2668,7 @@ static void  do_init_socket_2 (struct context *c)  {    link_socket_init_phase2 (c->c2.link_socket, &c->c2.frame, -			   &c->sig->signal_received); +			   c->sig);  }  /* @@ -2841,14 +2840,30 @@ do_close_link_socket (struct context *c)        c->c2.link_socket = NULL;      } -  if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_remote_ip)) -    { -      CLEAR (c->c1.link_socket_addr.remote); +     +  /* Preserve the resolved list of remote if the user request to or if we want +   * reconnect to the same host again or there are still addresses that need +   * to be tried */ +  if (!(c->sig->signal_received == SIGUSR1 && +        ( (c->options.persist_remote_ip) +         || +         ( c->sig->source != SIG_SOURCE_HARD && +          ((c->c1.link_socket_addr.current_remote && c->c1.link_socket_addr.current_remote->ai_next) +           || c->options.no_advance)) +         ))) +    { +      clear_remote_addrlist(&c->c1.link_socket_addr); +    } + +    /* Clear the remote actual address when persist_remote_ip is not in use */ +    if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_remote_ip))        CLEAR (c->c1.link_socket_addr.actual); -    } -  if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip)) -    CLEAR (c->c1.link_socket_addr.local); +  if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip)) { +    if (c->c1.link_socket_addr.bind_local) +        freeaddrinfo(c->c1.link_socket_addr.bind_local); +    c->c1.link_socket_addr.bind_local=NULL; +  }  }  /* @@ -3271,7 +3286,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int    /* signals caught here will abort */    c->sig->signal_received = 0;    c->sig->signal_text = NULL; -  c->sig->hard = false; +  c->sig->source = SIG_SOURCE_SOFT;    if (c->mode == CM_P2P)      init_management_callback_p2p (c); @@ -3290,8 +3305,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int    /* link_socket_mode allows CM_CHILD_TCP       instances to inherit acceptable fds       from a top-level parent */ -  if (c->options.ce.proto == PROTO_TCPv4_SERVER -      || c->options.ce.proto == PROTO_TCPv6_SERVER) +  if (c->options.ce.proto == PROTO_TCP_SERVER)      {        if (c->mode == CM_TOP)  	link_socket_mode = LS_MODE_TCP_LISTEN; @@ -3358,7 +3372,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int      do_event_set_init (c, false);    /* initialize HTTP or SOCKS proxy object at scope level 2 */ -  init_proxy (c, 2); +  init_proxy (c);    /* allocate our socket object */    if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) @@ -3689,7 +3703,7 @@ close_context (struct context *c, int sig, unsigned int flags)    if (c->sig->signal_received == SIGUSR1)      {        if ((flags & CC_USR1_TO_HUP) -	  || (c->sig->hard && (flags & CC_HARD_USR1_TO_HUP))) +	  || (c->sig->source == SIG_SOURCE_HARD && (flags & CC_HARD_USR1_TO_HUP)))  	c->sig->signal_received = SIGHUP;      } diff --git a/openvpn/src/openvpn/manage.c b/openvpn/src/openvpn/manage.c index 45e0bd43..c4e834b2 100644 --- a/openvpn/src/openvpn/manage.c +++ b/openvpn/src/openvpn/manage.c @@ -287,13 +287,13 @@ virtual_output_callback_func (void *arg, const unsigned int flags, const char *s  # define AF_DID_PUSH  (1<<0)  # define AF_DID_RESET (1<<1) -  unsigned int action_flags = 0;    if (!recursive_level) /* don't allow recursion */      {        struct gc_arena gc = gc_new ();        struct log_entry e;        const char *out = NULL; +      unsigned int action_flags = 0;        ++recursive_level; @@ -334,14 +334,15 @@ virtual_output_callback_func (void *arg, const unsigned int flags, const char *s  	    }  	} -      --recursive_level;        gc_free (&gc); -    } -  if (action_flags & AF_DID_PUSH) -    man_output_list_push_finalize (man); -  if (action_flags & AF_DID_RESET) -    man_reset_client_socket (man, true); +      if (action_flags & AF_DID_PUSH) +        man_output_list_push_finalize (man); +      if (action_flags & AF_DID_RESET) +        man_reset_client_socket (man, true); + +      --recursive_level; +    }  }  /* @@ -1460,7 +1461,7 @@ man_new_connection_post (struct management *man, const char *description)  #endif      msg (D_MANAGEMENT, "MANAGEMENT: %s %s",  	 description, -	 print_sockaddr (&man->settings.local, &gc)); +	 print_sockaddr (man->settings.local->ai_addr, &gc));    buffer_list_reset (man->connection.out); @@ -1568,7 +1569,8 @@ man_listen (struct management *man)  #endif  	{  	  man->connection.sd_top = create_socket_tcp (AF_INET); -	  socket_bind (man->connection.sd_top, &man->settings.local, "MANAGEMENT"); +	  socket_bind (man->connection.sd_top, man->settings.local, +                       AF_INET, "MANAGEMENT");  	}        /* @@ -1592,7 +1594,7 @@ man_listen (struct management *man)        else  #endif  	msg (D_MANAGEMENT, "MANAGEMENT: TCP Socket listening on %s", -	     print_sockaddr (&man->settings.local, &gc)); +	     print_sockaddr (man->settings.local->ai_addr, &gc));      }  #ifdef WIN32 @@ -1635,7 +1637,7 @@ man_connect (struct management *man)      {        man->connection.sd_cli = create_socket_tcp (AF_INET);        status = openvpn_connect (man->connection.sd_cli, -				&man->settings.local, +				man->settings.local->ai_addr,  				5,  				&signal_received);      } @@ -1660,7 +1662,7 @@ man_connect (struct management *man)  #endif        msg (D_LINK_ERRORS,  	   "MANAGEMENT: connect to %s failed: %s", -	   print_sockaddr (&man->settings.local, &gc), +	   print_sockaddr (man->settings.local->ai_addr, &gc),  	   strerror_ts (status, &gc));        throw_signal_soft (SIGTERM, "management-connect-failed");        goto done; @@ -2044,7 +2046,7 @@ man_persist_close (struct man_persist *mp)  static void  man_settings_init (struct man_settings *ms,  		   const char *addr, -		   const int port, +		   const char *port,  		   const char *pass_file,  		   const char *client_user,  		   const char *client_group, @@ -2097,12 +2099,6 @@ man_settings_init (struct man_settings *ms,        else  #endif  	{ -	  /* -	   * Initialize socket address -	   */ -	  ms->local.addr.in4.sin_family = AF_INET; -	  ms->local.addr.in4.sin_addr.s_addr = 0; -	  ms->local.addr.in4.sin_port = htons (port);  	  /*  	   * Run management over tunnel, or @@ -2114,8 +2110,9 @@ man_settings_init (struct man_settings *ms,  	    }  	  else  	    { -	      ms->local.addr.in4.sin_addr.s_addr = getaddr -		(GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, addr, 0, NULL, NULL); +              int status = openvpn_getaddrinfo(GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, +                                               addr, port, 0, NULL, AF_INET, &ms->local); +              ASSERT(status==0);  	    }  	} @@ -2234,7 +2231,7 @@ management_init (void)  bool  management_open (struct management *man,  		 const char *addr, -		 const int port, +		 const char *port,  		 const char *pass_file,  		 const char *client_user,  		 const char *client_group, @@ -2600,7 +2597,13 @@ management_post_tunnel_open (struct management *man, const in_addr_t tun_local_i        && man->connection.state == MS_INITIAL)      {        /* listen on our local TUN/TAP IP address */ -      man->settings.local.addr.in4.sin_addr.s_addr = htonl (tun_local_ip); +      struct in_addr ia; +      int ret; +       +      ia.s_addr = htonl(tun_local_ip); +      ret = openvpn_getaddrinfo(0, inet_ntoa(ia), NULL, 0, NULL, +                                AF_INET, &man->settings.local); +      ASSERT (ret==0);        man_connection_init (man);      } diff --git a/openvpn/src/openvpn/manage.h b/openvpn/src/openvpn/manage.h index eec24a2e..d2790dd4 100644 --- a/openvpn/src/openvpn/manage.h +++ b/openvpn/src/openvpn/manage.h @@ -212,7 +212,7 @@ struct man_persist {  struct man_settings {    bool defined;    unsigned int flags; /* MF_x flags */ -  struct openvpn_sockaddr local; +  struct addrinfo* local;  #if UNIX_SOCK_SUPPORT    struct sockaddr_un local_unix;  #endif @@ -341,7 +341,7 @@ struct management *management_init (void);  bool management_open (struct management *man,  		      const char *addr, -		      const int port, +		      const char *port,  		      const char *pass_file,  		      const char *client_user,  		      const char *client_group, diff --git a/openvpn/src/openvpn/misc.c b/openvpn/src/openvpn/misc.c index d2882d81..fcc85526 100644 --- a/openvpn/src/openvpn/misc.c +++ b/openvpn/src/openvpn/misc.c @@ -53,9 +53,6 @@ const char *iproute_path = IPROUTE_PATH; /* GLOBAL */  /* contains an SSEC_x value defined in misc.h */  int script_security = SSEC_BUILT_IN; /* GLOBAL */ -/* contains SM_x value defined in misc.h */ -int script_method = SM_EXECVE; /* GLOBAL */ -  /*   * Pass tunnel endpoint and MTU parms to a user-supplied script.   * Used to execute the up/down script/plugins. @@ -303,36 +300,25 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i  #if defined(ENABLE_FEATURE_EXECVE)        if (openvpn_execve_allowed (flags))  	{ -	  if (script_method == SM_EXECVE) -	    { -	      const char *cmd = a->argv[0]; -	      char *const *argv = a->argv; -	      char *const *envp = (char *const *)make_env_array (es, true, &gc); -	      pid_t pid; - -	      pid = fork (); -	      if (pid == (pid_t)0) /* child side */ -		{ -		  execve (cmd, argv, envp); -		  exit (127); -		} -	      else if (pid < (pid_t)0) /* fork failed */ -		msg (M_ERR, "openvpn_execve: unable to fork"); -	      else /* parent side */ -		{ -		  if (waitpid (pid, &ret, 0) != pid) -		    ret = -1; -		} -	    } -	  else if (script_method == SM_SYSTEM) -	    { -	      ret = openvpn_system (argv_system_str (a), es, flags); -	    } -	  else -	    { -	      ASSERT (0); -	    } -	} +          const char *cmd = a->argv[0]; +          char *const *argv = a->argv; +          char *const *envp = (char *const *)make_env_array (es, true, &gc); +          pid_t pid; + +          pid = fork (); +          if (pid == (pid_t)0) /* child side */ +            { +              execve (cmd, argv, envp); +              exit (127); +            } +          else if (pid < (pid_t)0) /* fork failed */ +            msg (M_ERR, "openvpn_execve: unable to fork"); +          else /* parent side */ +            { +              if (waitpid (pid, &ret, 0) != pid) +                ret = -1; +            } +        }        else if (!warn_shown && (script_security < SSEC_SCRIPTS))  	{  	  msg (M_WARN, SCRIPT_SECURITY_WARNING); @@ -353,52 +339,6 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i  #endif  /* - * Wrapper around the system() call. - */ -int -openvpn_system (const char *command, const struct env_set *es, unsigned int flags) -{ -#ifdef HAVE_SYSTEM -  int ret; - -  perf_push (PERF_SCRIPT); - -  /* -   * add env_set to environment. -   */ -  if (flags & S_SCRIPT) -    env_set_add_to_environment (es); - - -  /* debugging */ -  dmsg (D_SCRIPT, "SYSTEM[%u] '%s'", flags, command); -  if (flags & S_SCRIPT) -    env_set_print (D_SCRIPT, es); - -  /* -   * execute the command -   */ -  ret = platform_system(command); - -  /* debugging */ -  dmsg (D_SCRIPT, "SYSTEM return=%u", ret); - -  /* -   * remove env_set from environment -   */ -  if (flags & S_SCRIPT) -    env_set_remove_from_environment (es); - -  perf_pop (); -  return ret; - -#else -  msg (M_FATAL, "Sorry but I can't execute the shell command '%s' because this operating system doesn't appear to support the system() call", command); -  return -1; /* NOTREACHED */ -#endif -} - -/*   * Run execve() inside a fork(), duping stdout.  Designed to replicate the semantics of popen() but   * in a safer way that doesn't require the invocation of a shell or the risks   * assocated with formatting and parsing a command line. @@ -1056,7 +996,13 @@ hostname_randomize(const char *hostname, struct gc_arena *gc)  const char *  gen_path (const char *directory, const char *filename, struct gc_arena *gc)  { -  const char *safe_filename = string_mod_const (filename, CC_ALNUM|CC_UNDERBAR|CC_DASH|CC_DOT|CC_AT, 0, '_', gc); +#if WIN32 +  const int CC_PATH_RESERVED = CC_LESS_THAN|CC_GREATER_THAN|CC_COLON| +    CC_DOUBLE_QUOTE|CC_SLASH|CC_BACKSLASH|CC_PIPE|CC_QUESTION_MARK|CC_ASTERISK; +#else +  const int CC_PATH_RESERVED = CC_SLASH; +#endif +  const char *safe_filename = string_mod_const (filename, CC_PRINT, CC_PATH_RESERVED, '_', gc);    if (safe_filename        && strcmp (safe_filename, ".") diff --git a/openvpn/src/openvpn/misc.h b/openvpn/src/openvpn/misc.h index b6da3f4b..183898e3 100644 --- a/openvpn/src/openvpn/misc.h +++ b/openvpn/src/openvpn/misc.h @@ -96,7 +96,6 @@ int openvpn_popen (const struct argv *a,  const struct env_set *es);  int openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags);  bool openvpn_execve_check (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message);  bool openvpn_execve_allowed (const unsigned int flags); -int openvpn_system (const char *command, const struct env_set *es, unsigned int flags);  static inline bool  openvpn_run_script (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *hook) @@ -322,10 +321,6 @@ extern const char *iproute_path;  #define SSEC_PW_ENV    3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */  extern int script_security; /* GLOBAL */ -#define SM_EXECVE 0      /* call external programs with execve() or CreateProcess() */ -#define SM_SYSTEM 1      /* call external programs with system() */ -extern int script_method; /* GLOBAL */ -  /* return the next largest power of 2 */  size_t adjust_power_of_2 (size_t u); diff --git a/openvpn/src/openvpn/mss.c b/openvpn/src/openvpn/mss.c index 8981badc..64fd722f 100644 --- a/openvpn/src/openvpn/mss.c +++ b/openvpn/src/openvpn/mss.c @@ -38,8 +38,13 @@   * problems which arise from protocol   * encapsulation.   */ + +/* + * IPv4 packet: find TCP header, check flags for "SYN" + *              if yes, hand to mss_fixup_dowork() + */  void -mss_fixup (struct buffer *buf, int maxmss) +mss_fixup_ipv4 (struct buffer *buf, int maxmss)  {    const struct openvpn_iphdr *pip;    int hlen; @@ -69,6 +74,56 @@ mss_fixup (struct buffer *buf, int maxmss)      }  } +/* + * IPv6 packet: find TCP header, check flags for "SYN" + *              if yes, hand to mss_fixup_dowork() + *              (IPv6 header structure is sufficiently different from IPv4...) + */ +void +mss_fixup_ipv6 (struct buffer *buf, int maxmss) +{ +  const struct openvpn_ipv6hdr *pip6; +  struct buffer newbuf; + +  if (BLEN (buf) < (int) sizeof (struct openvpn_ipv6hdr)) +    return; + +  verify_align_4 (buf); +  pip6 = (struct openvpn_ipv6hdr *) BPTR (buf); + +  /* do we have the full IPv6 packet? +   * "payload_len" does not include IPv6 header (+40 bytes) +   */ +  if (BLEN (buf) != (int) ntohs(pip6->payload_len)+40 ) +    return; + +  /* follow header chain until we reach final header, then check for TCP +   * +   * An IPv6 packet could, theoretically, have a chain of multiple headers +   * before the final header (TCP, UDP, ...), so we'd need to walk that +   * chain (see RFC 2460 and RFC 6564 for details). +   * +   * In practice, "most typically used" extention headers (AH, routing, +   * fragment, mobility) are very unlikely to be seen inside an OpenVPN +   * tun, so for now, we only handle the case of "single next header = TCP" +   */ +  if ( pip6->nexthdr != OPENVPN_IPPROTO_TCP ) +    return; + +  newbuf = *buf; +  if ( buf_advance( &newbuf, 40 ) ) +    { +      struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR (&newbuf); +      if (tc->flags & OPENVPN_TCPH_SYN_MASK) +	    mss_fixup_dowork (&newbuf, (uint16_t) maxmss-20); +    } +} + +/* + * change TCP MSS option in SYN/SYN-ACK packets, if present + * this is generic for IPv4 and IPv6, as the TCP header is the same + */ +  void  mss_fixup_dowork (struct buffer *buf, uint16_t maxmss)  { diff --git a/openvpn/src/openvpn/mss.h b/openvpn/src/openvpn/mss.h index 0b290c36..0d329432 100644 --- a/openvpn/src/openvpn/mss.h +++ b/openvpn/src/openvpn/mss.h @@ -28,7 +28,8 @@  #include "proto.h"  #include "error.h" -void mss_fixup (struct buffer *buf, int maxmss); +void mss_fixup_ipv4 (struct buffer *buf, int maxmss); +void mss_fixup_ipv6 (struct buffer *buf, int maxmss);  void mss_fixup_dowork (struct buffer *buf, uint16_t maxmss);  #endif diff --git a/openvpn/src/openvpn/multi.c b/openvpn/src/openvpn/multi.c index 9876b80a..ab3f10cb 100644 --- a/openvpn/src/openvpn/multi.c +++ b/openvpn/src/openvpn/multi.c @@ -2411,13 +2411,13 @@ multi_get_queue (struct mbuf_set *ms)    if (mbuf_extract_item (ms, &item)) /* cleartext IP packet */      { -      unsigned int pipv4_flags = PIPV4_PASSTOS; +      unsigned int pip_flags = PIPV4_PASSTOS;        set_prefix (item.instance);        item.instance->context.c2.buf = item.buffer->buf;        if (item.buffer->flags & MF_UNICAST) /* --mssfix doesn't make sense for broadcast or multicast */ -	pipv4_flags |= PIPV4_MSSFIX; -      process_ipv4_header (&item.instance->context, pipv4_flags, &item.instance->context.c2.buf); +	pip_flags |= PIP_MSSFIX; +      process_ip_header (&item.instance->context, pip_flags, &item.instance->context.c2.buf);        encrypt_sign (&item.instance->context, true);        mbuf_free_buf (item.buffer); diff --git a/openvpn/src/openvpn/options.c b/openvpn/src/openvpn/options.c index 47aaffcb..dabc7577 100644 --- a/openvpn/src/openvpn/options.c +++ b/openvpn/src/openvpn/options.c @@ -167,8 +167,8 @@ static const char usage_message[] =    "--ipchange cmd  : Run command cmd on remote ip address initial\n"    "                  setting or change -- execute as: cmd ip-address port#\n"    "--port port     : TCP/UDP port # for both local and remote.\n" -  "--lport port    : TCP/UDP port # for local (default=%d). Implies --bind.\n" -  "--rport port    : TCP/UDP port # for remote (default=%d).\n" +  "--lport port    : TCP/UDP port # for local (default=%s). Implies --bind.\n" +  "--rport port    : TCP/UDP port # for remote (default=%s).\n"    "--bind          : Bind to local address and port. (This is the default unless\n"    "                  --proto tcp-client"  #ifdef ENABLE_HTTP_PROXY @@ -248,7 +248,7 @@ static const char usage_message[] =    "--setenv name value : Set a custom environmental variable to pass to script.\n"    "--setenv FORWARD_COMPATIBLE 1 : Relax config file syntax checking to allow\n"    "                  directives for future OpenVPN versions to be ignored.\n" -  "--script-security level mode : mode='execve' (default) or 'system', level=\n" +  "--script-security level: Where level can be:\n"    "                  0 -- strictly no calling of external programs\n"    "                  1 -- (default) only call built-ins such as ifconfig\n"    "                  2 -- allow calling of built-ins and scripts\n" @@ -767,10 +767,11 @@ init_options (struct options *o, const bool init_gc)      }    o->mode = MODE_POINT_TO_POINT;    o->topology = TOP_NET30; -  o->ce.proto = PROTO_UDPv4; +  o->ce.proto = PROTO_UDP; +  o->ce.af = AF_UNSPEC;    o->ce.connect_retry_seconds = 5;    o->ce.connect_timeout = 10; -  o->ce.connect_retry_max = 0; +  o->connect_retry_max = 0;    o->ce.local_port = o->ce.remote_port = OPENVPN_PORT;    o->verbosity = 1;    o->status_file_update_freq = 60; @@ -897,24 +898,24 @@ setenv_connection_entry (struct env_set *es,  			 const struct connection_entry *e,  			 const int i)  { -  setenv_str_i (es, "proto", proto2ascii (e->proto, false), i); +  setenv_str_i (es, "proto", proto2ascii (e->proto, e->af, false), i);    setenv_str_i (es, "local", e->local, i); -  setenv_int_i (es, "local_port", e->local_port, i); +  setenv_str_i (es, "local_port", e->local_port, i);    setenv_str_i (es, "remote", e->remote, i); -  setenv_int_i (es, "remote_port", e->remote_port, i); +  setenv_str_i (es, "remote_port", e->remote_port, i);  #ifdef ENABLE_HTTP_PROXY    if (e->http_proxy_options)      {        setenv_str_i (es, "http_proxy_server", e->http_proxy_options->server, i); -      setenv_int_i (es, "http_proxy_port", e->http_proxy_options->port, i); +      setenv_str_i (es, "http_proxy_port", e->http_proxy_options->port, i);      }  #endif  #ifdef ENABLE_SOCKS    if (e->socks_proxy_server)      {        setenv_str_i (es, "socks_proxy_server", e->socks_proxy_server, i); -      setenv_int_i (es, "socks_proxy_port", e->socks_proxy_port, i); +      setenv_str_i (es, "socks_proxy_port", e->socks_proxy_port, i);      }  #endif  } @@ -1216,7 +1217,7 @@ show_p2mp_parms (const struct options *o)    SHOW_BOOL (auth_user_pass_verify_script_via_file);  #if PORT_SHARE    SHOW_STR (port_share_host); -  SHOW_INT (port_share_port); +  SHOW_STR (port_share_port);  #endif  #endif /* P2MP_SERVER */ @@ -1287,7 +1288,7 @@ show_http_proxy_options (const struct http_proxy_options *o)  {    msg (D_SHOW_PARMS, "BEGIN http_proxy");    SHOW_STR (server); -  SHOW_INT (port); +  SHOW_STR (port);    SHOW_STR (auth_method_string);    SHOW_STR (auth_file);    SHOW_BOOL (retry); @@ -1338,17 +1339,16 @@ cnol_check_alloc (struct options *options)  static void  show_connection_entry (const struct connection_entry *o)  { -  msg (D_SHOW_PARMS, "  proto = %s", proto2ascii (o->proto, false)); +  msg (D_SHOW_PARMS, "  proto = %s", proto2ascii (o->proto, o->af, false));    SHOW_STR (local); -  SHOW_INT (local_port); +  SHOW_STR (local_port);    SHOW_STR (remote); -  SHOW_INT (remote_port); +  SHOW_STR (remote_port);    SHOW_BOOL (remote_float);    SHOW_BOOL (bind_defined);    SHOW_BOOL (bind_local);    SHOW_INT (connect_retry_seconds);    SHOW_INT (connect_timeout); -  SHOW_INT (connect_retry_max);  #ifdef ENABLE_HTTP_PROXY    if (o->http_proxy_options) @@ -1356,7 +1356,7 @@ show_connection_entry (const struct connection_entry *o)  #endif  #ifdef ENABLE_SOCKS    SHOW_STR (socks_proxy_server); -  SHOW_INT (socks_proxy_port); +  SHOW_STR (socks_proxy_port);    SHOW_BOOL (socks_proxy_retry);  #endif    SHOW_INT (tun_mtu); @@ -1425,6 +1425,7 @@ show_settings (const struct options *o)  #endif  #endif +  SHOW_INT (connect_retry_max);    show_connection_entries (o);    SHOW_BOOL (remote_random); @@ -1536,7 +1537,7 @@ show_settings (const struct options *o)  #ifdef ENABLE_MANAGEMENT    SHOW_STR (management_addr); -  SHOW_INT (management_port); +  SHOW_STR (management_port);    SHOW_STR (management_user_pass);    SHOW_INT (management_log_history_cache);    SHOW_INT (management_echo_buffer_size); @@ -1683,17 +1684,9 @@ parse_http_proxy_override (const char *server,    if (server && port)      {        struct http_proxy_options *ho; -      const int int_port = atoi(port); - -      if (!legal_ipv4_port (int_port)) -	{ -	  msg (msglevel, "Bad http-proxy port number: %s", port); -	  return NULL; -	} -        ALLOC_OBJ_CLEAR_GC (ho, struct http_proxy_options, gc);        ho->server = string_alloc(server, gc); -      ho->port = int_port; +      ho->port = port;        ho->retry = true;        ho->timeout = 5;        if (flags && !strcmp(flags, "nct")) @@ -1712,32 +1705,31 @@ void  options_postprocess_http_proxy_override (struct options *o)  {    const struct connection_list *l = o->connection_list; -   if (l) +  int i; +  bool succeed = false; +  for (i = 0; i < l->len; ++i) +    { +      struct connection_entry *ce = l->array[i]; +      if (ce->proto == PROTO_TCP_CLIENT || ce->proto == PROTO_TCP) +        { +          ce->http_proxy_options = o->http_proxy_override; +          succeed = true; +        } +    } +  if (succeed)      { -      int i; -      bool succeed = false;        for (i = 0; i < l->len; ++i) -	{ -	  struct connection_entry *ce = l->array[i]; -	  if (ce->proto == PROTO_TCPv4_CLIENT || ce->proto == PROTO_TCPv4) -	    { -	      ce->http_proxy_options = o->http_proxy_override; -	      succeed = true; -	    } -	} -      if (succeed) -	{ -	  for (i = 0; i < l->len; ++i) -	    { -	      struct connection_entry *ce = l->array[i]; -	      if (ce->proto == PROTO_UDPv4) -		{ -		  ce->flags |= CE_DISABLED; -		} -	    } -	} -      else -        msg (M_WARN, "Note: option http-proxy-override ignored because no TCP-based connection profiles are defined"); +        { +          struct connection_entry *ce = l->array[i]; +          if (ce->proto == PROTO_UDP) +            { +              ce->flags |= CE_DISABLED; +            } +        } +    } +  else +    { +      msg (M_WARN, "Note: option http-proxy-override ignored because no TCP-based connection profiles are defined");      }  } @@ -1796,10 +1788,12 @@ connection_entry_load_re (struct connection_entry *ce, const struct remote_entry  {    if (re->remote)      ce->remote = re->remote; -  if (re->remote_port >= 0) +  if (re->remote_port)      ce->remote_port = re->remote_port;    if (re->proto >= 0)      ce->proto = re->proto; +  if (re->af > 0) +    ce->af = re->af;  }  static void @@ -1829,7 +1823,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne     * If "proto tcp" is specified, make sure we know whether it is     * tcp-client or tcp-server.     */ -  if (ce->proto == PROTO_TCPv4) +  if (ce->proto == PROTO_TCP)      msg (M_USAGE, "--proto tcp is ambiguous in this context.  Please specify --proto tcp-server or --proto tcp-client");    /* @@ -1842,10 +1836,10 @@ options_postprocess_verify_ce (const struct options *options, const struct conne    if (options->inetd && (ce->local || ce->remote))      msg (M_USAGE, "--local or --remote cannot be used with --inetd"); -  if (options->inetd && ce->proto == PROTO_TCPv4_CLIENT) +  if (options->inetd && ce->proto == PROTO_TCP_CLIENT)      msg (M_USAGE, "--proto tcp-client cannot be used with --inetd"); -  if (options->inetd == INETD_NOWAIT && ce->proto != PROTO_TCPv4_SERVER) +  if (options->inetd == INETD_NOWAIT && ce->proto != PROTO_TCP_SERVER)      msg (M_USAGE, "--inetd nowait can only be used with --proto tcp-server");    if (options->inetd == INETD_NOWAIT @@ -1866,13 +1860,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne     * Sanity check on TCP mode options     */ -  if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT -      && ce->proto != PROTO_TCPv6_CLIENT) +  if (ce->connect_retry_defined && ce->proto != PROTO_TCP_CLIENT)      msg (M_USAGE, "--connect-retry doesn't make sense unless also used with "  	 "--proto tcp-client or tcp6-client"); -  if (ce->connect_timeout_defined && ce->proto != PROTO_TCPv4_CLIENT -      && ce->proto != PROTO_TCPv6_CLIENT) +  if (ce->connect_timeout_defined && ce->proto != PROTO_TCP_CLIENT)      msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with "  	 "--proto tcp-client or tcp6-client"); @@ -1898,7 +1890,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne    if (proto_is_net(ce->proto)        && string_defined_equal (ce->local, ce->remote) -      && ce->local_port == ce->remote_port) +      && string_defined_equal (ce->local_port, ce->remote_port))      msg (M_USAGE, "--remote and --local addresses are the same");    if (string_defined_equal (ce->remote, options->ifconfig_local) @@ -1971,12 +1963,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne      msg (M_USAGE, "--explicit-exit-notify can only be used with --proto udp");  #endif -  if (!ce->remote && (ce->proto == PROTO_TCPv4_CLIENT  -		      || ce->proto == PROTO_TCPv6_CLIENT)) +  if (!ce->remote && ce->proto == PROTO_TCP_CLIENT)      msg (M_USAGE, "--remote MUST be used in TCP Client mode");  #ifdef ENABLE_HTTP_PROXY -  if ((ce->http_proxy_options) && ce->proto != PROTO_TCPv4_CLIENT) +  if ((ce->http_proxy_options) && ce->proto != PROTO_TCP_CLIENT)      msg (M_USAGE, "--http-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)");  #endif @@ -1986,12 +1977,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne  #endif  #ifdef ENABLE_SOCKS -  if (ce->socks_proxy_server && ce->proto == PROTO_TCPv4_SERVER) +  if (ce->socks_proxy_server && ce->proto == PROTO_TCP_SERVER)      msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode");  #endif -  if ((ce->proto == PROTO_TCPv4_SERVER || ce->proto == PROTO_TCPv6_SERVER) -      && connection_list_defined (options)) +  if (ce->proto == PROTO_TCP_SERVER && (options->connection_list->len > 1))      msg (M_USAGE, "TCP server mode allows at most one --remote address");  #if P2MP_SERVER @@ -2005,13 +1995,12 @@ options_postprocess_verify_ce (const struct options *options, const struct conne  	msg (M_USAGE, "--mode server only works with --dev tun or --dev tap");        if (options->pull)  	msg (M_USAGE, "--pull cannot be used with --mode server"); -      if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCPv4_SERVER -	    || ce->proto == PROTO_TCPv6_SERVER)) +      if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCP_SERVER))  	msg (M_USAGE, "--mode server currently only supports "  	     "--proto udp or --proto tcp-server or proto tcp6-server");  #if PORT_SHARE        if ((options->port_share_host || options->port_share_port) &&  -	  (ce->proto != PROTO_TCPv4_SERVER && ce->proto != PROTO_TCPv6_SERVER)) +	  (ce->proto != PROTO_TCP_SERVER))  	msg (M_USAGE, "--port-share only works in TCP server mode "  	     "(--proto tcp-server or tcp6-server)");  #endif @@ -2041,8 +2030,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne  	msg (M_USAGE, "--inetd cannot be used with --mode server");        if (options->ipchange)  	msg (M_USAGE, "--ipchange cannot be used with --mode server (use --client-connect instead)"); -      if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCPv4_SERVER -	    || ce->proto == PROTO_TCPv6_SERVER)) +      if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCP_SERVER))  	msg (M_USAGE, "--mode server currently only supports "  	     "--proto udp or --proto tcp-server or --proto tcp6-server");        if (!proto_is_udp(ce->proto) && (options->cf_max || options->cf_per)) @@ -2194,13 +2182,15 @@ options_postprocess_verify_ce (const struct options *options, const struct conne         }        else  #endif -#ifdef ENABLE_CRYPTOAPI  #ifdef MANAGMENT_EXTERNAL_KEY  	 if((options->management_flags & MF_EXTERNAL_KEY) && options->priv_key_file) -		msg (M_USAGE, "--key and --management-external-key are mutually exclusive"); +	   { +		 msg (M_USAGE, "--key and --management-external-key are mutually exclusive"); +	   } +	 else  #endif - -      if (options->cryptoapi_cert) +#ifdef ENABLE_CRYPTOAPI +     if (options->cryptoapi_cert)  	{  	  if ((!(options->ca_file)) && (!(options->ca_path)))  	    msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath)"); @@ -2274,7 +2264,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne  	    {  	      notnull (options->cert_file, "certificate file (--cert) or PKCS#12 file (--pkcs12)");  #ifdef MANAGMENT_EXTERNAL_KEY -          if (!options->management_flags & MF_EXTERNAL_KEY) +          if (!(options->management_flags & MF_EXTERNAL_KEY))  #endif  	      notnull (options->priv_key_file, "private key file (--key) or PKCS#12 file (--pkcs12)");  	    } @@ -2350,35 +2340,33 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce)  #if P2MP_SERVER    if (o->server_defined || o->server_bridge_defined || o->server_bridge_proxy_dhcp)      { -      if (ce->proto == PROTO_TCPv4) -	ce->proto = PROTO_TCPv4_SERVER; +      if (ce->proto == PROTO_TCP) +	ce->proto = PROTO_TCP_SERVER;      }  #endif  #if P2MP    if (o->client)      { -      if (ce->proto == PROTO_TCPv4) -	ce->proto = PROTO_TCPv4_CLIENT; -      else if (ce->proto == PROTO_TCPv6) -	ce->proto = PROTO_TCPv6_CLIENT; +      if (ce->proto == PROTO_TCP) +	ce->proto = PROTO_TCP_CLIENT;      }  #endif -  if (ce->proto == PROTO_TCPv4_CLIENT && !ce->local && !ce->local_port_defined && !ce->bind_defined) +  if (ce->proto == PROTO_TCP_CLIENT && !ce->local && !ce->local_port_defined && !ce->bind_defined)      ce->bind_local = false;  #ifdef ENABLE_SOCKS -  if (ce->proto == PROTO_UDPv4 && ce->socks_proxy_server && !ce->local && !ce->local_port_defined && !ce->bind_defined) +  if (ce->proto == PROTO_UDP && ce->socks_proxy_server && !ce->local && !ce->local_port_defined && !ce->bind_defined)      ce->bind_local = false;  #endif    if (!ce->bind_local) -    ce->local_port = 0; +    ce->local_port = NULL;    /* if protocol forcing is enabled, disable all protocols except for the forced one */ -  if (o->proto_force >= 0 && proto_is_tcp(o->proto_force) != proto_is_tcp(ce->proto)) +  if (o->proto_force >= 0 && o->proto_force != ce->proto)      ce->flags |= CE_DISABLED; - +        /*     * If --mssfix is supplied without a parameter, default     * it to --fragment value, if --fragment is specified. @@ -2488,48 +2476,33 @@ options_postprocess_mutate (struct options *o)    if (o->remote_list && !o->connection_list)      {        /* -       * For compatibility with 2.0.x, map multiple --remote options -       * into connection list (connection lists added in 2.1). +       * Convert remotes into connection list         */ -      if (o->remote_list->len > 1 || o->force_connection_list) -	{ -	  const struct remote_list *rl = o->remote_list; -	  int i; -	  for (i = 0; i < rl->len; ++i) -	    { -	      const struct remote_entry *re = rl->array[i]; -	      struct connection_entry ce = o->ce; -	      struct connection_entry *ace; - -	      ASSERT (re->remote); -	      connection_entry_load_re (&ce, re); -	      ace = alloc_connection_entry (o, M_USAGE); -	      ASSERT (ace); -	      *ace = ce; -	    } -	} -      else if (o->remote_list->len == 1) /* one --remote option specified */ -	{ -	  connection_entry_load_re (&o->ce, o->remote_list->array[0]); -	} -      else -	{ -	  ASSERT (0); -	} -    } -  if (o->connection_list) -    { +      const struct remote_list *rl = o->remote_list;        int i; -      for (i = 0; i < o->connection_list->len; ++i) -	options_postprocess_mutate_ce (o, o->connection_list->array[i]); +      for (i = 0; i < rl->len; ++i) +        { +          const struct remote_entry *re = rl->array[i]; +          struct connection_entry ce = o->ce; +          struct connection_entry *ace; +           +          ASSERT (re->remote); +          connection_entry_load_re (&ce, re); +          ace = alloc_connection_entry (o, M_USAGE); +          ASSERT (ace); +          *ace = ce; +        } +    } +  ASSERT (o->connection_list); +  int i; +  for (i = 0; i < o->connection_list->len; ++i) +	options_postprocess_mutate_ce (o, o->connection_list->array[i]); +    #if HTTP_PROXY_OVERRIDE -      if (o->http_proxy_override) +  if (o->http_proxy_override)  	options_postprocess_http_proxy_override(o);  #endif -    } -  else -    options_postprocess_mutate_ce (o, &o->ce);    #if P2MP    /* @@ -2666,7 +2639,7 @@ options_postprocess_filechecks (struct options *options)    errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->extra_certs_file, R_OK,                               "--extra-certs");  #ifdef MANAGMENT_EXTERNAL_KEY -  if(!options->management_flags & MF_EXTERNAL_KEY) +  if(!(options->management_flags & MF_EXTERNAL_KEY))  #endif       errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->priv_key_file, R_OK,                               "--key"); @@ -2916,7 +2889,7 @@ options_string (const struct options *o,    buf_printf (&out, ",dev-type %s", dev_type_string (o->dev, o->dev_type));    buf_printf (&out, ",link-mtu %d", EXPANDED_SIZE (frame));    buf_printf (&out, ",tun-mtu %d", PAYLOAD_SIZE (frame)); -  buf_printf (&out, ",proto %s", proto2ascii (proto_remote (o->ce.proto, remote), true)); +  buf_printf (&out, ",proto %s", proto2ascii (proto_remote (o->ce.proto, remote),o->ce.af, true));    if (o->tun_ipv6)      buf_printf (&out, ",tun-ipv6"); @@ -4096,8 +4069,6 @@ add_option (struct options *options,  #ifdef ENABLE_MANAGEMENT    else if (streq (p[0], "management") && p[1] && p[2])      { -      int port = 0; -        VERIFY_PERMISSION (OPT_P_GENERAL);        if (streq (p[2], "unix"))  	{ @@ -4108,18 +4079,9 @@ add_option (struct options *options,  	  goto err;  #endif  	} -      else -	{ -	  port = atoi (p[2]); -	  if (!legal_ipv4_port (port)) -	    { -	      msg (msglevel, "port number associated with --management directive is out of range"); -	      goto err; -	    } -	}        options->management_addr = p[1]; -      options->management_port = port; +      options->management_port = p[2];        if (p[3])  	{  	  options->management_user_pass = p[3]; @@ -4149,7 +4111,6 @@ add_option (struct options *options,      {        VERIFY_PERMISSION (OPT_P_GENERAL);        options->management_flags |= MF_QUERY_PROXY; -      options->force_connection_list = true;      }    else if (streq (p[0], "management-hold"))      { @@ -4378,11 +4339,6 @@ add_option (struct options *options,  	  uninit_options (&sub);  	}      } -  else if (streq (p[0], "remote-ip-hint") && p[1]) -    { -      VERIFY_PERMISSION (OPT_P_GENERAL); -      options->remote_ip_hint = p[1]; -    }  #if HTTP_PROXY_OVERRIDE    else if (streq (p[0], "http-proxy-override") && p[1] && p[2])      { @@ -4390,35 +4346,31 @@ add_option (struct options *options,        options->http_proxy_override = parse_http_proxy_override(p[1], p[2], p[3], msglevel, &options->gc);        if (!options->http_proxy_override)  	goto err; -      options->force_connection_list = true;      }  #endif    else if (streq (p[0], "remote") && p[1])      {        struct remote_entry re; -      re.remote = NULL; -      re.remote_port = re.proto = -1; +      re.remote = re.remote_port= NULL; +      re.proto = -1; +      re.af=0;        VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);        re.remote = p[1];        if (p[2])  	{ -	  const int port = atoi (p[2]); -	  if (!legal_ipv4_port (port)) -	    { -	      msg (msglevel, "remote: port number associated with host %s is out of range", p[1]); -	      goto err; -	    } -	  re.remote_port = port; +	  re.remote_port = p[2];  	  if (p[3])  	    {  	      const int proto = ascii2proto (p[3]); +        const sa_family_t af = ascii2af (p[3]);  	      if (proto < 0)  		{  		  msg (msglevel, "remote: bad protocol associated with host %s: '%s'", p[1], p[3]);  		  goto err;  		}  	      re.proto = proto; +        re.af = af;  	    }  	}        if (permission_mask & OPT_P_GENERAL) @@ -4456,7 +4408,7 @@ add_option (struct options *options,    else if (streq (p[0], "connect-retry-max") && p[1])      {        VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); -      options->ce.connect_retry_max = positive_atoi (p[1]); +      options->connect_retry_max = positive_atoi (p[1]);      }    else if (streq (p[0], "ipchange") && p[1])      { @@ -4811,43 +4763,19 @@ add_option (struct options *options,      }    else if (streq (p[0], "port") && p[1])      { -      int port; -        VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); -      port = atoi (p[1]); -      if (!legal_ipv4_port (port)) -	{ -	  msg (msglevel, "Bad port number: %s", p[1]); -	  goto err; -	} -      options->ce.local_port = options->ce.remote_port = port; +      options->ce.local_port = options->ce.remote_port = p[1];      }    else if (streq (p[0], "lport") && p[1])      { -      int port; -        VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); -      port = atoi (p[1]); -      if ((port != 0) && !legal_ipv4_port (port)) -	{ -	  msg (msglevel, "Bad local port number: %s", p[1]); -	  goto err; -	}        options->ce.local_port_defined = true; -      options->ce.local_port = port; +      options->ce.local_port = p[1];      }    else if (streq (p[0], "rport") && p[1])      { -      int port; -        VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); -      port = atoi (p[1]); -      if (!legal_ipv4_port (port)) -	{ -	  msg (msglevel, "Bad remote port number: %s", p[1]); -	  goto err; -	} -      options->ce.remote_port = port; +      options->ce.remote_port = p[1];      }    else if (streq (p[0], "bind"))      { @@ -4874,8 +4802,10 @@ add_option (struct options *options,    else if (streq (p[0], "proto") && p[1])      {        int proto; +      sa_family_t af;        VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);        proto = ascii2proto (p[1]); +      af = ascii2af(p[1]);        if (proto < 0)  	{  	  msg (msglevel, "Bad protocol: '%s'.  Allowed protocols with --proto option: %s", @@ -4884,6 +4814,7 @@ add_option (struct options *options,  	  goto err;  	}        options->ce.proto = proto; +      options->ce.af = af;      }    else if (streq (p[0], "proto-force") && p[1])      { @@ -4896,7 +4827,6 @@ add_option (struct options *options,  	  goto err;  	}        options->proto_force = proto_force; -      options->force_connection_list = true;      }  #ifdef ENABLE_HTTP_PROXY    else if (streq (p[0], "http-proxy") && p[1]) @@ -4906,23 +4836,16 @@ add_option (struct options *options,        VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);        { -	int port;  	if (!p[2])  	  {  	    msg (msglevel, "http-proxy port number not defined");  	    goto err;  	  } -	port = atoi (p[2]); -	if (!legal_ipv4_port (port)) -	  { -	    msg (msglevel, "Bad http-proxy port number: %s", p[2]); -	    goto err; -	  }  	ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc);  	ho->server = p[1]; -	ho->port = port; +	ho->port = p[2];        }        if (p[3]) @@ -4992,19 +4915,12 @@ add_option (struct options *options,        VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);        if (p[2]) -	{ -	  int port; -          port = atoi (p[2]); -          if (!legal_ipv4_port (port)) -	    { -	      msg (msglevel, "Bad socks-proxy port number: %s", p[2]); -	      goto err; -	    } -          options->ce.socks_proxy_port = port; +        { +          options->ce.socks_proxy_port = p[2];  	}        else  	{ -	  options->ce.socks_proxy_port = 1080; +	  options->ce.socks_proxy_port = "1080";  	}        options->ce.socks_proxy_server = p[1];        options->ce.socks_proxy_authfile = p[3]; /* might be NULL */ @@ -5141,6 +5057,11 @@ add_option (struct options *options,  	  msg (msglevel, "--max-routes parameter is out of range");  	  goto err;  	} +      if (options->routes || options->routes_ipv6) +        { +          msg (msglevel, "--max-routes must to be specifed before any route/route-ipv6/redirect-gateway option"); +          goto err; +        }        options->max_routes = max_routes;      }    else if (streq (p[0], "route-gateway") && p[1]) @@ -5293,20 +5214,6 @@ add_option (struct options *options,      {        VERIFY_PERMISSION (OPT_P_GENERAL);        script_security = atoi (p[1]); -      if (p[2]) -	{ -	  if (streq (p[2], "execve")) -	    script_method = SM_EXECVE; -	  else if (streq (p[2], "system")) -	    script_method = SM_SYSTEM; -	  else -	    { -	      msg (msglevel, "unknown --script-security method: %s", p[2]); -	      goto err; -	    } -	} -      else -	script_method = SM_EXECVE;      }    else if (streq (p[0], "mssfix"))      { @@ -5652,18 +5559,9 @@ add_option (struct options *options,  #if PORT_SHARE    else if (streq (p[0], "port-share") && p[1] && p[2])      { -      int port; -        VERIFY_PERMISSION (OPT_P_GENERAL); -      port = atoi (p[2]); -      if (!legal_ipv4_port (port)) -	{ -	  msg (msglevel, "port number associated with --port-share directive is out of range"); -	  goto err; -	} -        options->port_share_host = p[1]; -      options->port_share_port = port; +      options->port_share_port = p[2];        options->port_share_journal_dir = p[3];      }  #endif diff --git a/openvpn/src/openvpn/options.h b/openvpn/src/openvpn/options.h index 306520b0..62b1cbf3 100644 --- a/openvpn/src/openvpn/options.h +++ b/openvpn/src/openvpn/options.h @@ -87,9 +87,10 @@ struct options_pre_pull  struct connection_entry  {    int proto; -  int local_port; +  sa_family_t af; +  const char* local_port;    bool local_port_defined; -  int remote_port; +  const char* remote_port;    const char *local;    const char *remote;    bool remote_float; @@ -97,7 +98,6 @@ struct connection_entry    bool bind_local;    int connect_retry_seconds;    bool connect_retry_defined; -  int connect_retry_max;    int connect_timeout;    bool connect_timeout_defined;  #ifdef ENABLE_HTTP_PROXY @@ -105,7 +105,7 @@ struct connection_entry  #endif    #ifdef ENABLE_SOCKS    const char *socks_proxy_server; -  int socks_proxy_port; +  const char *socks_proxy_port;    const char *socks_proxy_authfile;    bool socks_proxy_retry;  #endif @@ -143,8 +143,9 @@ struct connection_entry  struct remote_entry  {    const char *remote; -  int remote_port; +  const char *remote_port;    int proto; +  sa_family_t af;  };  #define CONNECTION_LIST_SIZE 64 @@ -154,7 +155,6 @@ struct connection_list    int len;    int current;    int n_cycles; -  bool no_advance;    struct connection_entry *array[CONNECTION_LIST_SIZE];  }; @@ -168,6 +168,8 @@ struct remote_host_store  {  # define RH_HOST_LEN 80    char host[RH_HOST_LEN]; +#define RH_PORT_LEN 20 +  char port[RH_PORT_LEN];  };  /* Command line options */ @@ -203,11 +205,15 @@ struct options  #endif    /* Networking parms */ +  int connect_retry_max;    struct connection_entry ce; -  char *remote_ip_hint;    struct connection_list *connection_list; +    struct remote_list *remote_list; -  bool force_connection_list; +  /* Do not advanced the connection or remote addr list*/ +  bool no_advance; +  /* Counts the number of unsuccessful connection attempts */ +  unsigned int unsuccessful_attempts;  #if HTTP_PROXY_OVERRIDE    struct http_proxy_options *http_proxy_override; @@ -354,7 +360,7 @@ struct options  #ifdef ENABLE_MANAGEMENT    const char *management_addr; -  int management_port; +  const char *management_port;    const char *management_user_pass;    int management_log_history_cache;    int management_echo_buffer_size; @@ -449,7 +455,7 @@ struct options    bool auth_user_pass_verify_script_via_file;  #if PORT_SHARE    char *port_share_host; -  int port_share_port; +  char *port_share_port;    const char *port_share_journal_dir;  #endif  #endif @@ -769,20 +775,5 @@ bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network,  		    unsigned int * netbits, char ** printable_ipv6,   		    int msglevel ); -/* - * inline functions - */ -static inline bool -connection_list_defined (const struct options *o) -{ -  return o->connection_list != NULL; -} - -static inline void -connection_list_set_no_advance (struct options *o) -{ -  if (o->connection_list) -    o->connection_list->no_advance = true; -}  #endif diff --git a/openvpn/src/openvpn/pf.c b/openvpn/src/openvpn/pf.c index 3c468019..aafe9ff0 100644 --- a/openvpn/src/openvpn/pf.c +++ b/openvpn/src/openvpn/pf.c @@ -606,7 +606,6 @@ pf_destroy_context (struct pf_context *pfc)    if (pfc->filename)      {        platform_unlink (pfc->filename); -      free (pfc->filename);      }  #endif    if (pfc->pfs) diff --git a/openvpn/src/openvpn/pkcs11.c b/openvpn/src/openvpn/pkcs11.c index 645f1f48..3a15ef68 100644 --- a/openvpn/src/openvpn/pkcs11.c +++ b/openvpn/src/openvpn/pkcs11.c @@ -887,7 +887,7 @@ show_pkcs11_ids (  		      (dn = pkcs11_certificate_dn (  				certificate,  				&gc -		      )) +		      )) == NULL  		) {  			goto cleanup1;  		} diff --git a/openvpn/src/openvpn/platform.c b/openvpn/src/openvpn/platform.c index c79f6807..e79de7a7 100644 --- a/openvpn/src/openvpn/platform.c +++ b/openvpn/src/openvpn/platform.c @@ -205,7 +205,7 @@ platform_chdir (const char* dir)  }  /* - * convert system() return into a success/failure value + * convert execve() return into a success/failure value   */  bool  platform_system_ok (int stat) @@ -217,19 +217,6 @@ platform_system_ok (int stat)  #endif  } -/* - * did system() call execute the given command? - */ -bool -platform_system_executed (int stat) -{ -#ifdef WIN32 -  return stat != -1; -#else -  return stat != -1 && WEXITSTATUS (stat) != 127; -#endif -} -  int  platform_access (const char *path, int mode)  { @@ -288,18 +275,6 @@ platform_unlink (const char *filename)  #endif  } -int platform_system(const char *command) { -  int ret; -#ifdef WIN32 -  struct gc_arena gc = gc_new (); -  ret = _wsystem (wide_string (command, &gc)); -  gc_free (&gc); -#else -  ret = system (command); -#endif -  return ret; -} -  int platform_putenv(char *string)  {    int status; diff --git a/openvpn/src/openvpn/platform.h b/openvpn/src/openvpn/platform.h index 7bd20671..7c0a4d72 100644 --- a/openvpn/src/openvpn/platform.h +++ b/openvpn/src/openvpn/platform.h @@ -113,10 +113,8 @@ void platform_mlockall (bool print_msg); /* Disable paging */  int platform_chdir (const char* dir); -/* interpret the status code returned by system()/execve() */ +/* interpret the status code returned by execve() */  bool platform_system_ok (int stat); -bool platform_system_executed (int stat); -int platform_system(const char *command);  int platform_access (const char *path, int mode); diff --git a/openvpn/src/openvpn/plugin.c b/openvpn/src/openvpn/plugin.c index d785daec..83f79e4f 100644 --- a/openvpn/src/openvpn/plugin.c +++ b/openvpn/src/openvpn/plugin.c @@ -98,7 +98,9 @@ plugin_type_name (const int type)      case OPENVPN_PLUGIN_TLS_FINAL:        return "PLUGIN_TLS_FINAL";      case OPENVPN_PLUGIN_ENABLE_PF: -      return "OPENVPN_PLUGIN_ENABLE_PF"; +      return "PLUGIN_ENABLE_PF"; +    case OPENVPN_PLUGIN_ROUTE_PREDOWN: +      return "PLUGIN_ROUTE_PREDOWN";      default:        return "PLUGIN_???";      } @@ -376,10 +378,10 @@ plugin_open_item (struct plugin *p,          struct openvpn_plugin_args_open_return retargs;          CLEAR(retargs); +        retargs.return_list = retlist;          if ((*p->open3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs) == OPENVPN_PLUGIN_FUNC_SUCCESS) {            p->plugin_type_mask = retargs.type_mask;            p->plugin_handle = retargs.handle; -          retlist = retargs.return_list;          } else {            p->plugin_handle = NULL;          } @@ -458,8 +460,8 @@ plugin_call_item (const struct plugin *p,          struct openvpn_plugin_args_func_return retargs;          CLEAR(retargs); +        retargs.return_list = retlist;          status = (*p->func3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs); -        retlist = retargs.return_list;        } else if (p->func2)  	status = (*p->func2)(p->plugin_handle, type, (const char **)a.argv, envp, per_client_context, retlist);        else if (p->func1) diff --git a/openvpn/src/openvpn/proto.c b/openvpn/src/openvpn/proto.c index 2cf8314b..b437f1ad 100644 --- a/openvpn/src/openvpn/proto.c +++ b/openvpn/src/openvpn/proto.c @@ -36,11 +36,12 @@  #include "memdbg.h"  /* - * If raw tunnel packet is IPv4, return true and increment + * If raw tunnel packet is IPv<X>, return true and increment   * buffer offset to start of IP header.   */ +static  bool -is_ipv4 (int tunnel_type, struct buffer *buf) +is_ipv_X ( int tunnel_type, struct buffer *buf, int ip_ver )  {    int offset;    const struct openvpn_iphdr *ih; @@ -68,12 +69,24 @@ is_ipv4 (int tunnel_type, struct buffer *buf)    ih = (const struct openvpn_iphdr *) (BPTR (buf) + offset); -  if (OPENVPN_IPH_GET_VER (ih->version_len) == 4) +  /* IP version is stored in the same bits for IPv4 or IPv6 header */ +  if (OPENVPN_IPH_GET_VER (ih->version_len) == ip_ver)      return buf_advance (buf, offset);    else      return false;  } +bool +is_ipv4 (int tunnel_type, struct buffer *buf) +{ +    return is_ipv_X( tunnel_type, buf, 4 ); +} +bool +is_ipv6 (int tunnel_type, struct buffer *buf) +{ +    return is_ipv_X( tunnel_type, buf, 6 ); +} +  #ifdef PACKET_TRUNCATION_CHECK  void diff --git a/openvpn/src/openvpn/proto.h b/openvpn/src/openvpn/proto.h index 8cd4edec..f91e787e 100644 --- a/openvpn/src/openvpn/proto.h +++ b/openvpn/src/openvpn/proto.h @@ -219,10 +219,11 @@ struct ip_tcp_udp_hdr {                               - sizeof(struct openvpn_tcphdr))  /* - * If raw tunnel packet is IPv4, return true and increment + * If raw tunnel packet is IPv4 or IPv6, return true and increment   * buffer offset to start of IP header.   */  bool is_ipv4 (int tunnel_type, struct buffer *buf); +bool is_ipv6 (int tunnel_type, struct buffer *buf);  #ifdef PACKET_TRUNCATION_CHECK  void ipv4_packet_size_verify (const uint8_t *data, diff --git a/openvpn/src/openvpn/proxy.c b/openvpn/src/openvpn/proxy.c index 363d8a73..17748504 100644 --- a/openvpn/src/openvpn/proxy.c +++ b/openvpn/src/openvpn/proxy.c @@ -444,7 +444,7 @@ http_proxy_new (const struct http_proxy_options *o)    if (!o || !o->server)      msg (M_FATAL, "HTTP_PROXY: server not specified"); -  ASSERT (legal_ipv4_port (o->port)); +  ASSERT ( o->port);    ALLOC_OBJ_CLEAR (p, struct http_proxy_info);    p->options = *o; @@ -493,7 +493,7 @@ bool  establish_http_proxy_passthru (struct http_proxy_info *p,  			       socket_descriptor_t sd, /* already open to proxy */  			       const char *host,       /* openvpn server remote */ -			       const int port,         /* openvpn server port */ +			       const char *port,         /* openvpn server port */  			       struct buffer *lookahead,  			       volatile int *signal_received)  { @@ -521,7 +521,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,    else      {        /* format HTTP CONNECT message */ -      openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", +      openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%s HTTP/%s",  			host,  			port,  			p->options.http_version); @@ -642,7 +642,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,            /* now send the phase 3 reply */            /* format HTTP CONNECT message */ -          openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", +          openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%s HTTP/%s",  			    host,  			    port,  			    p->options.http_version); @@ -730,7 +730,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,  	      /* build the digest response */ -	      openvpn_snprintf (uri, sizeof(uri), "%s:%d", +	      openvpn_snprintf (uri, sizeof(uri), "%s:%s",  				host,  				port); diff --git a/openvpn/src/openvpn/proxy.h b/openvpn/src/openvpn/proxy.h index 5e476f16..9d75e063 100644 --- a/openvpn/src/openvpn/proxy.h +++ b/openvpn/src/openvpn/proxy.h @@ -40,7 +40,7 @@  struct http_proxy_options {    const char *server; -  int port; +  const char *port;    bool retry;    int timeout; @@ -57,7 +57,7 @@ struct http_proxy_options {  struct http_proxy_options_simple {    const char *server; -  int port; +  const char *port;    int auth_retry;  }; @@ -80,7 +80,7 @@ void http_proxy_close (struct http_proxy_info *hp);  bool establish_http_proxy_passthru (struct http_proxy_info *p,  				    socket_descriptor_t sd, /* already open to proxy */  				    const char *host,       /* openvpn server remote */ -				    const int port,         /* openvpn server port */ +				    const char *port,         /* openvpn server port */  				    struct buffer *lookahead,  				    volatile int *signal_received); diff --git a/openvpn/src/openvpn/ps.c b/openvpn/src/openvpn/ps.c index 6495dc71..c1868642 100644 --- a/openvpn/src/openvpn/ps.c +++ b/openvpn/src/openvpn/ps.c @@ -330,8 +330,8 @@ journal_add (const char *journal_dir, struct proxy_connection *pc, struct proxy_    if (!getpeername (pc->sd, (struct sockaddr *) &from.addr.sa, &slen)        && !getsockname (cp->sd, (struct sockaddr *) &to.addr.sa, &dlen))      { -      const char *f = print_sockaddr_ex (&from, ":", PS_SHOW_PORT, &gc); -      const char *t = print_sockaddr_ex (&to, ":", PS_SHOW_PORT, &gc); +      const char *f = print_openvpn_sockaddr (&from, &gc); +      const char *t = print_openvpn_sockaddr (&to, &gc);        fnlen =  strlen(journal_dir) + strlen(t) + 2;        jfn = (char *) malloc(fnlen);        check_malloc_return (jfn); @@ -403,8 +403,7 @@ proxy_connection_io_requeue (struct proxy_connection *pc, const int rwflags_new,  static bool  proxy_entry_new (struct proxy_connection **list,  		 struct event_set *es, -		 const in_addr_t server_addr, -		 const int server_port, +		 const struct sockaddr_in server_addr,  		 const socket_descriptor_t sd_client,  		 struct buffer *initial_data,  		 const char *journal_dir) @@ -416,7 +415,7 @@ proxy_entry_new (struct proxy_connection **list,    struct proxy_connection *cp;    /* connect to port share server */ -  sock_addr_set (&osaddr, server_addr, server_port); +  osaddr.addr.in4 = server_addr;    if ((sd_server = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)      {        msg (M_WARN|M_ERRNO, "PORT SHARE PROXY: cannot create socket"); @@ -482,8 +481,7 @@ static bool  control_message_from_parent (const socket_descriptor_t sd_control,  			     struct proxy_connection **list,  			     struct event_set *es, -			     const in_addr_t server_addr, -			     const int server_port, +			     const struct sockaddr_in server_addr,  			     const int max_initial_buf,  			     const char *journal_dir)  { @@ -539,7 +537,6 @@ control_message_from_parent (const socket_descriptor_t sd_control,  	      if (proxy_entry_new (list,  				   es,  				   server_addr, -				   server_port,  				   received_fd,  				   &buf,  				   journal_dir)) @@ -716,8 +713,7 @@ proxy_connection_io_dispatch (struct proxy_connection *pc,   * This is the main function for the port share proxy background process.   */  static void -port_share_proxy (const in_addr_t hostaddr, -		  const int port, +port_share_proxy (const struct sockaddr_in hostaddr,  		  const socket_descriptor_t sd_control,  		  const int max_initial_buf,  		  const char *journal_dir) @@ -754,7 +750,7 @@ port_share_proxy (const in_addr_t hostaddr,  		  const struct event_set_return *e = &esr[i];  		  if (e->arg == sd_control_marker)  		    { -		      if (!control_message_from_parent (sd_control, &list, es, hostaddr, port, max_initial_buf, journal_dir)) +		      if (!control_message_from_parent (sd_control, &list, es, hostaddr, max_initial_buf, journal_dir))  			goto done;  		    }  		  else @@ -789,14 +785,16 @@ port_share_proxy (const in_addr_t hostaddr,   */  struct port_share *  port_share_open (const char *host, -		 const int port, +		 const char *port,  		 const int max_initial_buf,  		 const char *journal_dir)  {    pid_t pid;    socket_descriptor_t fd[2]; -  in_addr_t hostaddr; +  struct sockaddr_in hostaddr;    struct port_share *ps; +  int status; +  struct addrinfo* ai;    ALLOC_OBJ_CLEAR (ps, struct port_share);    ps->foreground_fd = -1; @@ -805,7 +803,12 @@ port_share_open (const char *host,    /*     * Get host's IP address     */ -  hostaddr = getaddr (GETADDR_RESOLVE|GETADDR_HOST_ORDER|GETADDR_FATAL, host, 0, NULL, NULL); +   +  status = openvpn_getaddrinfo (GETADDR_RESOLVE|GETADDR_HOST_ORDER|GETADDR_FATAL, +                                 host, port,  0, NULL, AF_INET, &ai); +  ASSERT (status==0); +  hostaddr = *((struct sockaddr_in*) ai->ai_addr); +  freeaddrinfo(ai);    /*     * Make a socket for foreground and background processes @@ -881,7 +884,7 @@ port_share_open (const char *host,        prng_init (NULL, 0);        /* execute the event loop */ -      port_share_proxy (hostaddr, port, fd[1], max_initial_buf, journal_dir); +      port_share_proxy (hostaddr, fd[1], max_initial_buf, journal_dir);        openvpn_close_socket (fd[1]); diff --git a/openvpn/src/openvpn/ps.h b/openvpn/src/openvpn/ps.h index 4280635d..e8919d48 100644 --- a/openvpn/src/openvpn/ps.h +++ b/openvpn/src/openvpn/ps.h @@ -44,7 +44,7 @@ struct port_share {  extern struct port_share *port_share;  struct port_share *port_share_open (const char *host, -				    const int port, +				    const char *port,  				    const int max_initial_buf,  				    const char *journal_dir); diff --git a/openvpn/src/openvpn/push.c b/openvpn/src/openvpn/push.c index 05a38e0d..929a2f24 100644 --- a/openvpn/src/openvpn/push.c +++ b/openvpn/src/openvpn/push.c @@ -49,7 +49,7 @@ void  receive_auth_failed (struct context *c, const struct buffer *buffer)  {    msg (M_VERB0, "AUTH: Received control message: %s", BSTR(buffer)); -  connection_list_set_no_advance(&c->options); +    c->options.no_advance=true;    if (c->options.pull)      {        switch (auth_retry_get ()) diff --git a/openvpn/src/openvpn/route.c b/openvpn/src/openvpn/route.c index caa2459b..8a778884 100644 --- a/openvpn/src/openvpn/route.c +++ b/openvpn/src/openvpn/route.c @@ -294,12 +294,12 @@ init_route (struct route *r,    if(get_special_addr (rl, ro->network, &special.s_addr, &status))      {        special.s_addr = htonl(special.s_addr); -      ret = openvpn_getaddrinfo(0, inet_ntoa(special), 0, NULL, +      ret = openvpn_getaddrinfo(0, inet_ntoa(special), NULL, 0, NULL,                                  AF_INET, network_list);      }    else      ret = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL, -                              ro->network, 0, NULL, AF_INET, network_list); +                              ro->network, NULL, 0, NULL, AF_INET, network_list);    status = (ret == 0); @@ -2722,7 +2722,7 @@ get_default_gateway (struct route_gateway_info *rgi)    if (write(s, (char *)&m_rtmsg, l) < 0)      { -      warn("writing to routing socket"); +      msg(M_WARN|M_ERRNO, "Could not retrieve default gateway from route socket:");        gc_free (&gc);        close(s);        return; @@ -3088,7 +3088,7 @@ get_default_gateway (struct route_gateway_info *rgi)    if (write(s, (char *)&m_rtmsg, l) < 0)      { -      warn("writing to routing socket"); +      msg(M_WARN|M_ERRNO, "Could not retrieve default gateway from route socket:");        gc_free (&gc);        close(s);        return; diff --git a/openvpn/src/openvpn/sig.c b/openvpn/src/openvpn/sig.c index 0ebde245..7ddfd0ed 100644 --- a/openvpn/src/openvpn/sig.c +++ b/openvpn/src/openvpn/sig.c @@ -97,14 +97,14 @@ void  throw_signal (const int signum)  {    siginfo_static.signal_received = signum; -  siginfo_static.hard = true; +  siginfo_static.source = SIG_SOURCE_HARD;  }  void  throw_signal_soft (const int signum, const char *signal_text)  {    siginfo_static.signal_received = signum; -  siginfo_static.hard = false; +  siginfo_static.source = SIG_SOURCE_SOFT;    siginfo_static.signal_text = signal_text;  } @@ -115,7 +115,7 @@ signal_reset (struct signal_info *si)      {        si->signal_received = 0;        si->signal_text = NULL; -      si->hard = false; +      si->source = SIG_SOURCE_SOFT;      }  } @@ -124,9 +124,23 @@ print_signal (const struct signal_info *si, const char *title, int msglevel)  {    if (si)      { -      const char *hs = (si->hard ? "hard" : "soft");        const char *type = (si->signal_text ? si->signal_text : "");        const char *t = (title ? title : "process"); +      const char *hs; +      switch (si->source) +        { +        case SIG_SOURCE_SOFT: +          hs= "soft"; +          break; +        case SIG_SOURCE_HARD: +          hs = "hard"; +          break; +        case SIG_SOURCE_CONNECTION_FAILED: +          hs = "connection failed(soft)"; +          break; +        default: +          ASSERT(0); +        }        switch (si->signal_received)  	{ diff --git a/openvpn/src/openvpn/sig.h b/openvpn/src/openvpn/sig.h index 987efef5..c2c7b54e 100644 --- a/openvpn/src/openvpn/sig.h +++ b/openvpn/src/openvpn/sig.h @@ -28,6 +28,15 @@  #include "status.h"  #include "win32.h" + + +#define SIG_SOURCE_SOFT 0 +#define SIG_SOURCE_HARD 1 +/* CONNECTION_FAILED is also a "soft" status, + * It is thrown if a connection attempt fails + */ +#define SIG_SOURCE_CONNECTION_FAILED 2 +  /*   * Signal information, including signal code   * and descriptive text. @@ -35,7 +44,7 @@  struct signal_info  {    volatile int signal_received; -  volatile bool hard; +  volatile int source;    const char *signal_text;  }; diff --git a/openvpn/src/openvpn/socket.c b/openvpn/src/openvpn/socket.c index 1e38e82c..c861fdd2 100644 --- a/openvpn/src/openvpn/socket.c +++ b/openvpn/src/openvpn/socket.c @@ -101,8 +101,8 @@ getaddr (unsigned int flags,  {    struct addrinfo *ai;    int status; -  status = openvpn_getaddrinfo(flags, hostname, resolve_retry_seconds, -							   signal_received, AF_INET, &ai); +  status = openvpn_getaddrinfo (flags & ~GETADDR_HOST_ORDER, hostname, NULL, +                                resolve_retry_seconds, signal_received, AF_INET, &ai);    if(status==0) {      struct in_addr ia;      if(succeeded) @@ -125,6 +125,7 @@ getaddr (unsigned int flags,  int  openvpn_getaddrinfo (unsigned int flags,                       const char *hostname, +                     const char *servname,                       int resolve_retry_seconds,                       volatile int *signal_received,                       int ai_family, @@ -135,6 +136,8 @@ openvpn_getaddrinfo (unsigned int flags,    int sigrec = 0;    int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;    struct gc_arena gc = gc_new (); +  const char *print_hostname; +  const char *print_servname;    ASSERT(res); @@ -142,8 +145,19 @@ openvpn_getaddrinfo (unsigned int flags,    res_init ();  #endif -  if (!hostname) -    hostname = "::"; +  ASSERT (hostname || servname); +  ASSERT (!(flags & GETADDR_HOST_ORDER)); + +  if(hostname) +    print_hostname = hostname; +  else +    print_hostname = "undefined"; +     +  if(servname) +    print_servname = servname; +  else +    print_servname = ""; +    if (flags & GETADDR_RANDOMIZE)      hostname = hostname_randomize(hostname, &gc); @@ -159,25 +173,36 @@ openvpn_getaddrinfo (unsigned int flags,    CLEAR(hints);    hints.ai_family = ai_family;    hints.ai_flags = AI_NUMERICHOST; -  hints.ai_socktype = dnsflags_to_socktype(flags); +  hints.ai_socktype = SOCK_STREAM; +   +  if(flags & GETADDR_PASSIVE) +      hints.ai_flags |= AI_PASSIVE; +     +  if(flags & GETADDR_DATAGRAM) +      hints.ai_socktype = SOCK_DGRAM; +  else +      hints.ai_socktype = SOCK_STREAM; -  status = getaddrinfo(hostname, NULL, &hints, res); +  status = getaddrinfo(hostname, servname, &hints, res);    if (status != 0) /* parse as numeric address failed? */      {        const int fail_wait_interval = 5; /* seconds */ -      int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : (resolve_retry_seconds / fail_wait_interval); +      /* Add +4 to cause integer division rounding up (1 + 4) = 5, (0+4)/5=0 */ +      int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : +            ((resolve_retry_seconds + 4)/ fail_wait_interval);        const char *fmt;        int level = 0; - -      fmt = "RESOLVE: Cannot resolve host address: %s: %s"; +       +      fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)";        if ((flags & GETADDR_MENTION_RESOLVE_RETRY)            && !resolve_retry_seconds) -        fmt = "RESOLVE: Cannot resolve host address: %s: %s (I would have retried this name query if you had specified the --resolv-retry option.)"; +        fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s) (I would have retried this name query if you had specified the --resolv-retry option.)";        if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL)          { -          msg (msglevel, "RESOLVE: Cannot parse IP address: %s", hostname); +          msg (msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)", +               print_hostname,print_servname, gai_strerror(status));            goto done;          } @@ -199,10 +224,10 @@ openvpn_getaddrinfo (unsigned int flags,        while (true)          {            /* try hostname lookup */ -          hints.ai_flags = 0; +          hints.ai_flags &= ~AI_NUMERICHOST;            dmsg (D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d",                  flags, hints.ai_family, hints.ai_socktype); -          status = getaddrinfo(hostname, NULL, &hints, res); +          status = getaddrinfo(hostname, servname, &hints, res);            if (signal_received)              { @@ -236,7 +261,8 @@ openvpn_getaddrinfo (unsigned int flags,            msg (level,                 fmt, -               hostname, +               print_hostname, +               print_servname,                 gai_strerror(status));            if (--resolve_retries <= 0) @@ -249,7 +275,8 @@ openvpn_getaddrinfo (unsigned int flags,        /* hostname resolve succeeded */ -      /* Do not chose an IP Addresse by random or change the order * +      /*  +       * Do not chose an IP Addresse by random or change the order *         * of IP addresses, doing so will break RFC 3484 address selection *         */      } @@ -419,59 +446,6 @@ mac_addr_safe (const char *mac_addr)    return true;  } -static void -update_remote (const char* host, -	       struct openvpn_sockaddr *addr, -	       bool *changed, -	       const unsigned int sockflags) -{ -  switch(addr->addr.sa.sa_family) -    { -    case AF_INET: -      if (host && addr) -	{ -	  const in_addr_t new_addr = getaddr ( -					      sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags), -					      host, -					      1, -					      NULL, -					      NULL); -	  if (new_addr && addr->addr.in4.sin_addr.s_addr != new_addr) -	    { -	      addr->addr.in4.sin_addr.s_addr = new_addr; -	      *changed = true; -	    } -	} -      break; -    case AF_INET6: -      if (host && addr) -        { -          int status; -          struct addrinfo* ai; - -		  status = openvpn_getaddrinfo(sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags), host, 1, NULL, AF_INET6, &ai); - -          if ( status ==0 ) -            { -			  struct sockaddr_in6 sin6; -			  CLEAR(sin6); -			  sin6 = *((struct sockaddr_in6*)ai->ai_addr); -              if (!IN6_ARE_ADDR_EQUAL(&sin6.sin6_addr, &addr->addr.in6.sin6_addr)) -              { -                int port = addr->addr.in6.sin6_port; -                /* ipv6 requires also eg. sin6_scope_id => easier to fully copy and override port */ -                addr->addr.in6 = sin6;  -                addr->addr.in6.sin6_port = port; -              } -			  freeaddrinfo(ai); -            } -        } -      break; -    default: -        ASSERT(0); -  } -} -  static int  socket_get_sndbuf (int sd)  { @@ -643,51 +617,41 @@ create_socket_tcp (int af)  }  static socket_descriptor_t -create_socket_udp (const unsigned int flags) +create_socket_udp (const int af, const unsigned int flags)  {    socket_descriptor_t sd; -  if ((sd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) -    msg (M_ERR, "UDP: Cannot create UDP socket"); +  if ((sd = socket (af, SOCK_DGRAM, IPPROTO_UDP)) < 0) +    msg (M_ERR, "UDP: Cannot create UDP/UDP6 socket");  #if ENABLE_IP_PKTINFO    else if (flags & SF_USE_IP_PKTINFO)      {        int pad = 1; +      if(af == AF_INET)  +        {  #ifdef IP_PKTINFO -      if (setsockopt (sd, SOL_IP, IP_PKTINFO, -		      (void*)&pad, sizeof(pad)) < 0) -        msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO"); +          if (setsockopt (sd, SOL_IP, IP_PKTINFO, +                          (void*)&pad, sizeof(pad)) < 0) +            msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO");  #elif defined(IP_RECVDSTADDR) -      if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR, -		      (void*)&pad, sizeof(pad)) < 0) -        msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR"); +          if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR, +                          (void*)&pad, sizeof(pad)) < 0) +            msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR");  #else  #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)  #endif -    } -#endif -  return sd; -} - -static socket_descriptor_t -create_socket_udp6 (const unsigned int flags) -{ -  socket_descriptor_t sd; - -  if ((sd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) -    msg (M_ERR, "UDP: Cannot create UDP6 socket"); -#if ENABLE_IP_PKTINFO -  else if (flags & SF_USE_IP_PKTINFO) -    { -      int pad = 1; +        }  +      else if (af == AF_INET6 )  +        {  #ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */ -      if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, -		      (void*)&pad, sizeof(pad)) < 0) +          if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, +                          (void*)&pad, sizeof(pad)) < 0)  #else -      if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO, -		      (void*)&pad, sizeof(pad)) < 0) +          if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO, +                          (void*)&pad, sizeof(pad)) < 0)  #endif -	msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO"); +            msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO"); +        }      }  #endif    return sd; @@ -696,10 +660,16 @@ create_socket_udp6 (const unsigned int flags)  static void  create_socket (struct link_socket *sock)  { -  /* create socket */ -  if (sock->info.proto == PROTO_UDPv4) +  /* create socket, use information carried over from getaddrinfo */ +  const int ai_proto = sock->info.lsa->actual.ai_protocol; +  const int ai_family = sock->info.lsa->actual.ai_family; +     +  ASSERT (sock->info.af == AF_UNSPEC  || sock->info.af == ai_family); + +     +  if (ai_proto == IPPROTO_UDP)      { -      sock->sd = create_socket_udp (sock->sockflags); +      sock->sd = create_socket_udp (ai_family, sock->sockflags);        sock->sockflags |= SF_GETADDRINFO_DGRAM;  #ifdef ENABLE_SOCKS @@ -707,20 +677,9 @@ create_socket (struct link_socket *sock)  	sock->ctrl_sd = create_socket_tcp (AF_INET);  #endif      } -  else if (sock->info.proto == PROTO_TCPv4_SERVER -	   || sock->info.proto == PROTO_TCPv4_CLIENT) -    { -      sock->sd = create_socket_tcp (AF_INET); -    } -  else if (sock->info.proto == PROTO_TCPv6_SERVER -	   || sock->info.proto == PROTO_TCPv6_CLIENT) +  else if (ai_proto == IPPROTO_TCP)      { -      sock->sd = create_socket_tcp (AF_INET6); -    } -  else if (sock->info.proto == PROTO_UDPv6) -    { -      sock->sd = create_socket_udp6 (sock->sockflags); -      sock->sockflags |= SF_GETADDRINFO_DGRAM; +      sock->sd = create_socket_tcp (ai_family);      }    else      { @@ -740,10 +699,9 @@ create_socket (struct link_socket *sock)  /*   * Functions used for establishing a TCP stream connection.   */ -  static void  socket_do_listen (socket_descriptor_t sd, -		  const struct openvpn_sockaddr *local, +		  const struct sockaddr *local,  		  bool do_listen,  		  bool do_set_nonblock)  { @@ -833,8 +791,7 @@ static int  socket_listen_accept (socket_descriptor_t sd,  		      struct link_socket_actual *act,  		      const char *remote_dynamic, -		      bool *remote_changed, -		      const struct openvpn_sockaddr *local, +		      const struct addrinfo *local,  		      bool do_listen,  		      bool nowait,  		      volatile int *signal_received) @@ -845,7 +802,7 @@ socket_listen_accept (socket_descriptor_t sd,    int new_sd = SOCKET_UNDEFINED;    CLEAR (*act); -  socket_do_listen (sd, local, do_listen, true); +  socket_do_listen (sd, local->ai_addr, do_listen, true);    while (true)      { @@ -880,18 +837,26 @@ socket_listen_accept (socket_descriptor_t sd,        if (socket_defined (new_sd))  	{ -	  update_remote (remote_dynamic, &remote_verify, remote_changed, 0); -	  if (addr_defined (&remote_verify) -	      && !addr_match (&remote_verify, &act->dest)) -	    { -	      msg (M_WARN, -		   "TCP NOTE: Rejected connection attempt from %s due to --remote setting", -		   print_link_socket_actual (act, &gc)); -	      if (openvpn_close_socket (new_sd)) -		msg (M_ERR, "TCP: close socket failed (new_sd)"); -	    } +          struct addrinfo* ai; +          if(remote_dynamic) +              openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL, +                                    remote_verify.addr.sa.sa_family, &ai); + +          if(ai && !addrlist_match(&remote_verify, ai)) +            { +              msg (M_WARN, +                   "TCP NOTE: Rejected connection attempt from %s due to --remote setting", +                   print_link_socket_actual (act, &gc)); +              if (openvpn_close_socket (new_sd)) +                  msg (M_ERR, "TCP: close socket failed (new_sd)"); +              freeaddrinfo(ai); +            }  	  else -	    break; +            { +              if(ai) +                  freeaddrinfo(ai); +              break; +            }  	}        openvpn_sleep (1);      } @@ -907,17 +872,37 @@ socket_listen_accept (socket_descriptor_t sd,  void  socket_bind (socket_descriptor_t sd, -             struct openvpn_sockaddr *local, +             struct addrinfo *local, +             int ai_family,  	     const char *prefix)  {    struct gc_arena gc = gc_new (); -  if (bind (sd, &local->addr.sa, af_addr_size(local->addr.sa.sa_family))) +  /* FIXME (schwabe) +   * getaddrinfo for the bind address might return multiple AF_INET/AF_INET6 +   * entries for the requested protocol. +   * For example if an address has multiple A records +   * What is the correct way to deal with it? +   */ +   +  ASSERT(local); +  struct addrinfo* cur; +     +  /* 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: No addr to bind has no v4/v6 record", prefix); +     +  if (bind (sd, cur->ai_addr, cur->ai_addrlen))      {        const int errnum = openvpn_errno ();        msg (M_FATAL, "%s: Socket bind failed on local address %s: %s",  	   prefix, -           print_sockaddr (local, &gc), +           print_sockaddr_ex (local->ai_addr, ":", PS_SHOW_PORT, &gc),             strerror_ts (errnum, &gc));      }    gc_free (&gc); @@ -925,7 +910,7 @@ socket_bind (socket_descriptor_t sd,  int  openvpn_connect (socket_descriptor_t sd, -		 struct openvpn_sockaddr *remote, +		 const struct sockaddr *remote,  		 int connect_timeout,  		 volatile int *signal_received)  { @@ -933,7 +918,7 @@ openvpn_connect (socket_descriptor_t sd,  #ifdef CONNECT_NONBLOCK    set_nonblock (sd); -  status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family)); +  status = connect (sd, remote, af_addr_size(remote->sa_family));    if (status)      status = openvpn_errno ();    if ( @@ -1005,85 +990,76 @@ openvpn_connect (socket_descriptor_t sd,    return status;  } +void set_actual_address (struct link_socket_actual* actual, struct addrinfo* ai) +{ +    CLEAR (*actual); +    ASSERT (ai); +     +    if (ai->ai_family == AF_INET) +        actual->dest.addr.in4 = +        *((struct sockaddr_in*) ai->ai_addr); +    else if (ai->ai_family == AF_INET6) +        actual->dest.addr.in6 = +        *((struct sockaddr_in6*) ai->ai_addr); +    else +        ASSERT(0); +     +    /* Copy addrinfo sock parameters for socket creating */ +    actual->ai_family = ai->ai_family; +    actual->ai_protocol = ai->ai_protocol; +    actual->ai_socktype = ai->ai_socktype; +} +  void  socket_connect (socket_descriptor_t *sd, -                struct openvpn_sockaddr *local, -                bool bind_local, -		struct openvpn_sockaddr *remote, -		const bool connection_profiles_defined, -		const char *remote_dynamic, -		bool *remote_changed, -		const int connect_retry_seconds, -		const int connect_timeout, -		const int connect_retry_max, -		const unsigned int sockflags, -		volatile int *signal_received) +                struct link_socket_addr *lsa, +                const int connect_timeout, +                struct signal_info* sig_info)  {    struct gc_arena gc = gc_new (); -  int retry = 0; - +  const struct sockaddr *dest = &lsa->actual.dest.addr.sa; +     +  int status; +        #ifdef CONNECT_NONBLOCK -  msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]",  -       print_sockaddr (remote, &gc)); +  msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]", +       print_sockaddr (dest, &gc));  #else -  msg (M_INFO, "Attempting to establish TCP connection with %s",  -       print_sockaddr (remote, &gc)); +  msg (M_INFO, "Attempting to establish TCP connection with %s", +       print_sockaddr (dest, &gc));  #endif - -  while (true) -    { -      int status; - +        #ifdef ENABLE_MANAGEMENT -      if (management) +  if (management)  	management_set_state (management, -			      OPENVPN_STATE_TCP_CONNECT, -			      NULL, -			      (in_addr_t)0, -			      (in_addr_t)0); +                          OPENVPN_STATE_TCP_CONNECT, +                          NULL, +                          (in_addr_t)0, +                          (in_addr_t)0);  #endif -      status = openvpn_connect (*sd, remote, connect_timeout, signal_received); +  /* Set the actual address */ +  status = openvpn_connect (*sd, dest, connect_timeout, &sig_info->signal_received); -      get_signal (signal_received); -      if (*signal_received) +  get_signal (&sig_info->signal_received); +  if (sig_info->signal_received)  	goto done; -      if (!status) -	break; - -      msg (D_LINK_ERRORS, -	   "TCP: connect to %s failed, will try again in %d seconds: %s", -	   print_sockaddr (remote, &gc), -	   connect_retry_seconds, -	   strerror_ts (status, &gc)); - -      gc_reset (&gc); +  if (status) { -      openvpn_close_socket (*sd); -      *sd = SOCKET_UNDEFINED; +    msg (D_LINK_ERRORS, +         "TCP: connect to %s failed: %s", +         print_sockaddr (dest, &gc), +         strerror_ts (status, &gc)); -      if ((connect_retry_max > 0 && ++retry >= connect_retry_max) || connection_profiles_defined) -	{ -	  *signal_received = SIGUSR1; -	  goto done; -	} - -      openvpn_sleep (connect_retry_seconds); - -      get_signal (signal_received); -      if (*signal_received) -	goto done; - -	*sd = create_socket_tcp (local->addr.sa.sa_family); - -      if (bind_local) -        socket_bind (*sd, local, "TCP Client"); -      update_remote (remote_dynamic, remote, remote_changed, sockflags); -    } - -  msg (M_INFO, "TCP connection established with %s",  -       print_sockaddr (remote, &gc)); +    openvpn_close_socket (*sd); +    *sd = SOCKET_UNDEFINED; +    sig_info->signal_received = SIGUSR1; +    sig_info->source = SIG_SOURCE_CONNECTION_FAILED; +  } else { +      msg (M_INFO, "TCP connection established with %s", +        print_sockaddr (dest, &gc)); +  }   done:    gc_free (&gc); @@ -1134,72 +1110,47 @@ frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto)  }  static void -resolve_bind_local (struct link_socket *sock) +resolve_bind_local (struct link_socket *sock, const sa_family_t af)  {    struct gc_arena gc = gc_new ();    /* resolve local address if undefined */ -  if (!addr_defined (&sock->info.lsa->local)) +  if (!sock->info.lsa->bind_local)      { -      /* may return AF_{INET|INET6} guessed from local_host */ -      switch(addr_guess_family(sock->info.proto, sock->local_host)) -	{ -	case AF_INET: -	  sock->info.lsa->local.addr.in4.sin_family = AF_INET; -	  sock->info.lsa->local.addr.in4.sin_addr.s_addr = -	    (sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, -					 sock->local_host, -					 0, -					 NULL, -					 NULL) -	     : htonl (INADDR_ANY)); -	  sock->info.lsa->local.addr.in4.sin_port = htons (sock->local_port); -	  break; -	case AF_INET6: -	    { -	      int status; -	      int err; -	      CLEAR(sock->info.lsa->local.addr.in6); -	      if (sock->local_host) -		{ -		  struct addrinfo *ai; - -		  status = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, -									   sock->local_host, 0, NULL, AF_INET6, &ai); -		  if(status ==0) { -			  sock->info.lsa->local.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); -			  freeaddrinfo(ai); -		  } -		} -	      else -		{ -		  sock->info.lsa->local.addr.in6.sin6_family = AF_INET6; -		  sock->info.lsa->local.addr.in6.sin6_addr = in6addr_any; -		  status = 0; -		} -	      if (!status == 0) -		{ -		  msg (M_FATAL, "getaddr6() failed for local \"%s\": %s", -		       sock->local_host, -		       gai_strerror(err)); -		} -	      sock->info.lsa->local.addr.in6.sin6_port = htons (sock->local_port); -	    } -	  break; -	} +      int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | +                   GETADDR_FATAL | GETADDR_PASSIVE; +      int status; +       +      if(proto_is_dgram(sock->info.proto)) +          flags |= GETADDR_DATAGRAM; +  +      /* will return AF_{INET|INET6}from local_host */ +      status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0, +                                   NULL, af, &sock->info.lsa->bind_local); +      if(status !=0) { +        msg (M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s", +             sock->local_host, sock->local_port, +             gai_strerror(status)); +      }      } -   -  /* bind to local address/port */ -  if (sock->bind_local) -    { + +  gc_free (&gc); +} + +static void bind_local (struct link_socket *sock) +{ +    /* bind to local address/port */ +    if (sock->bind_local) +      {  #ifdef ENABLE_SOCKS -      if (sock->socks_proxy && sock->info.proto == PROTO_UDPv4) -          socket_bind (sock->ctrl_sd, &sock->info.lsa->local, "SOCKS"); -      else +        if (sock->socks_proxy && sock->info.proto == PROTO_UDP && sock->info.af == AF_INET) +            socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local, +                         sock->info.lsa->actual.ai_family, "SOCKS"); +        else  #endif -          socket_bind (sock->sd, &sock->info.lsa->local, "TCP/UDP"); -    } -  gc_free (&gc); +            socket_bind (sock->sd, sock->info.lsa->bind_local, +                         sock->info.lsa->actual.ai_family,  "TCP/UDP"); +      }  }  static void @@ -1209,34 +1160,22 @@ resolve_remote (struct link_socket *sock,  		volatile int *signal_received)  {    struct gc_arena gc = gc_new (); -  int af;    if (!sock->did_resolve_remote)      {        /* resolve remote address if undefined */ -      if (!addr_defined (&sock->info.lsa->remote)) +      if (!sock->info.lsa->remote_list)  	{ -          af = addr_guess_family(sock->info.proto, sock->remote_host); -          switch(af) -            { -              case AF_INET: -                sock->info.lsa->remote.addr.in4.sin_family = AF_INET; -                sock->info.lsa->remote.addr.in4.sin_addr.s_addr = 0; -                break; -              case AF_INET6: -                CLEAR(sock->info.lsa->remote.addr.in6); -                sock->info.lsa->remote.addr.in6.sin6_family = AF_INET6; -                sock->info.lsa->remote.addr.in6.sin6_addr = in6addr_any; -                break; -            } -  	  if (sock->remote_host)  	    {  	      unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);  	      int retry = 0;  	      int status = -1; +               +              if (proto_is_dgram(sock->info.proto)) +                  flags |= GETADDR_DATAGRAM; -	      if (sock->connection_profiles_defined && sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) +	      if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)  		{  		  if (phase == 2)  		    flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL); @@ -1272,12 +1211,11 @@ resolve_remote (struct link_socket *sock,  		}  		  struct addrinfo* ai; -		  /* Temporary fix, this need to be changed for dual stack */ -		  status = openvpn_getaddrinfo(flags, sock->remote_host, retry, -											  signal_received, af, &ai); +		  status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port, +                                               retry, signal_received, sock->info.af, &ai);  		  if(status == 0) { -			  sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); -			  freeaddrinfo(ai); +                          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, @@ -1298,15 +1236,6 @@ resolve_remote (struct link_socket *sock,  		  goto done;  		}  	    } -          switch(af) -            { -              case AF_INET: -                sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port); -                break; -              case AF_INET6: -                sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port); -                break; -            }  	}        /* should we re-use previous active remote address? */ @@ -1319,8 +1248,12 @@ resolve_remote (struct link_socket *sock,  	}        else  	{ -	  CLEAR (sock->info.lsa->actual); -	  sock->info.lsa->actual.dest = sock->info.lsa->remote; +          CLEAR (sock->info.lsa->actual); +          if(sock->info.lsa->current_remote) +            { +              set_actual_address (&sock->info.lsa->actual, +                                  sock->info.lsa->current_remote); +            }  	}        /* remember that we finished */ @@ -1331,6 +1264,8 @@ resolve_remote (struct link_socket *sock,    gc_free (&gc);  } + +  struct link_socket *  link_socket_new (void)  { @@ -1344,15 +1279,36 @@ link_socket_new (void)    return sock;  } +void +create_new_socket (struct link_socket* sock, int mark) +{ +   if (sock->bind_local) { +      resolve_bind_local (sock, sock->info.af); +  } +  resolve_remote (sock, 1, NULL, NULL); +  create_socket (sock); + +  /* 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, mark); + +  if (sock->bind_local) +    bind_local(sock); +     +} + +  /* bind socket if necessary */  void  link_socket_init_phase1 (struct link_socket *sock, -			 const bool connection_profiles_defined,  			 const char *local_host, -			 int local_port, +			 const char *local_port,  			 const char *remote_host, -			 int remote_port, +			 const char *remote_port,  			 int proto, +       sa_family_t af,  			 int mode,  			 const struct link_socket *accept_from,  #ifdef ENABLE_HTTP_PROXY @@ -1371,9 +1327,7 @@ link_socket_init_phase1 (struct link_socket *sock,  			 const char *ipchange_command,  			 const struct plugin_list *plugins,  			 int resolve_retry_seconds, -			 int connect_retry_seconds,  			 int connect_timeout, -			 int connect_retry_max,  			 int mtu_discover_type,  			 int rcvbuf,  			 int sndbuf, @@ -1382,8 +1336,6 @@ link_socket_init_phase1 (struct link_socket *sock,  {    ASSERT (sock); -  sock->connection_profiles_defined = connection_profiles_defined; -    sock->local_host = local_host;    sock->local_port = local_port;    sock->remote_host = remote_host; @@ -1400,9 +1352,7 @@ link_socket_init_phase1 (struct link_socket *sock,    sock->bind_local = bind_local;    sock->inetd = inetd;    sock->resolve_retry_seconds = resolve_retry_seconds; -  sock->connect_retry_seconds = connect_retry_seconds;    sock->connect_timeout = connect_timeout; -  sock->connect_retry_max = connect_retry_max;    sock->mtu_discover_type = mtu_discover_type;  #ifdef ENABLE_DEBUG @@ -1415,6 +1365,7 @@ link_socket_init_phase1 (struct link_socket *sock,    sock->sockflags = sockflags;    sock->info.proto = proto; +  sock->info.af = af;    sock->info.remote_float = remote_float;    sock->info.lsa = lsa;    sock->info.ipchange_command = ipchange_command; @@ -1424,20 +1375,18 @@ link_socket_init_phase1 (struct link_socket *sock,    if (mode == LS_MODE_TCP_ACCEPT_FROM)      {        ASSERT (accept_from); -      ASSERT (sock->info.proto == PROTO_TCPv4_SERVER -	      || sock->info.proto == PROTO_TCPv6_SERVER -	     ); +      ASSERT (sock->info.proto == PROTO_TCP_SERVER);        ASSERT (!sock->inetd);        sock->sd = accept_from->sd;      } - +        if (false)      ;  #ifdef ENABLE_HTTP_PROXY    /* are we running in HTTP proxy mode? */    else if (sock->http_proxy)      { -      ASSERT (sock->info.proto == PROTO_TCPv4_CLIENT); +      ASSERT (sock->info.proto == PROTO_TCP_CLIENT && sock->info.af == AF_INET);        ASSERT (!sock->inetd);        /* the proxy server */ @@ -1453,7 +1402,7 @@ link_socket_init_phase1 (struct link_socket *sock,    /* or in Socks proxy mode? */    else if (sock->socks_proxy)      { -      ASSERT (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_UDPv4); +      ASSERT (sock->info.af == AF_INET);        ASSERT (!sock->inetd);        /* the proxy server */ @@ -1472,7 +1421,7 @@ link_socket_init_phase1 (struct link_socket *sock,      }    /* bind behavior for TCP server vs. client */ -  if (sock->info.proto == PROTO_TCPv4_SERVER) +  if (sock->info.proto == PROTO_TCP_SERVER && sock->info.af==AF_INET)      {        if (sock->mode == LS_MODE_TCP_ACCEPT_FROM)  	sock->bind_local = false; @@ -1483,248 +1432,59 @@ link_socket_init_phase1 (struct link_socket *sock,    /* were we started by inetd or xinetd? */    if (sock->inetd)      { -      ASSERT (sock->info.proto != PROTO_TCPv4_CLIENT -	      && sock->info.proto != PROTO_TCPv6_CLIENT); +      ASSERT (sock->info.proto != PROTO_TCP_CLIENT);        ASSERT (socket_defined (inetd_socket_descriptor));        sock->sd = inetd_socket_descriptor;      }    else if (mode != LS_MODE_TCP_ACCEPT_FROM)      { -      create_socket (sock); - -      /* 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, mark); - -      resolve_bind_local (sock); -      resolve_remote (sock, 1, NULL, NULL); +      create_new_socket (sock, mark);      }  } -/* finalize socket initialization */ -void -link_socket_init_phase2 (struct link_socket *sock, -			 const struct frame *frame, -			 volatile int *signal_received) +static +void phase2_inetd (struct link_socket* sock, const struct frame *frame, +                   const char *remote_dynamic, volatile int *signal_received)  { -  struct gc_arena gc = gc_new (); -  const char *remote_dynamic = NULL;    bool remote_changed = false; -  int sig_save = 0; -  ASSERT (sock); - -  if (signal_received && *signal_received) -    { -      sig_save = *signal_received; -      *signal_received = 0; -    } - -  /* initialize buffers */ -  socket_frame_init (frame, sock); - -  /* -   * Pass a remote name to connect/accept so that -   * they can test for dynamic IP address changes -   * and throw a SIGUSR1 if appropriate. -   */ -  if (sock->resolve_retry_seconds) -    remote_dynamic = sock->remote_host; - -  /* were we started by inetd or xinetd? */ -  if (sock->inetd) -    { -      if (sock->info.proto == PROTO_TCPv4_SERVER -	  || sock->info.proto == PROTO_TCPv6_SERVER) { -	/* AF_INET as default (and fallback) for inetd */ -	sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET; +  if (sock->info.proto == PROTO_TCP_SERVER) { +    /* AF_INET as default (and fallback) for inetd */ +    sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET;  #ifdef HAVE_GETSOCKNAME -	  { -	    /* inetd: hint family type for dest = local's */ -	    struct openvpn_sockaddr local_addr; -	    socklen_t addrlen = sizeof(local_addr); -	    if (getsockname (sock->sd, (struct sockaddr *)&local_addr, &addrlen) == 0) { -	      sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family; -	      dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)", -		    proto2ascii(sock->info.proto, false), local_addr.addr.sa.sa_family, -		    sock->sd); -	    } else -	      msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET", -		   proto2ascii(sock->info.proto, false), sock->sd); -	  } -#else -	msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() " -	     "function, using AF_INET", -	     proto2ascii(sock->info.proto, false)); -#endif -	sock->sd = -	  socket_listen_accept (sock->sd, -				&sock->info.lsa->actual, -				remote_dynamic, -				&remote_changed, -				&sock->info.lsa->local, -				false, -				sock->inetd == INETD_NOWAIT, -				signal_received); -      } -      ASSERT (!remote_changed); -      if (*signal_received) -	goto done; -    } -  else      { -      resolve_remote (sock, 2, &remote_dynamic, signal_received); - -      if (*signal_received) -	goto done; - -      /* TCP client/server */ -      if (sock->info.proto == PROTO_TCPv4_SERVER -	  ||sock->info.proto == PROTO_TCPv6_SERVER) -	{ -	  switch (sock->mode) -	    { -	    case LS_MODE_DEFAULT: -	      sock->sd = socket_listen_accept (sock->sd, -					       &sock->info.lsa->actual, -					       remote_dynamic, -					       &remote_changed, -					       &sock->info.lsa->local, -					       true, -					       false, -					       signal_received); -	      break; -	    case LS_MODE_TCP_LISTEN: -	      socket_do_listen (sock->sd, -				&sock->info.lsa->local, -				true, -				false); -	      break; -	    case LS_MODE_TCP_ACCEPT_FROM: -	      sock->sd = socket_do_accept (sock->sd, -					   &sock->info.lsa->actual, -					   false); -	      if (!socket_defined (sock->sd)) -		{ -		  *signal_received = SIGTERM; -		  goto done; -		} -	      tcp_connection_established (&sock->info.lsa->actual); -	      break; -	    default: -	      ASSERT (0); -	    } -	} -      else if (sock->info.proto == PROTO_TCPv4_CLIENT -	       ||sock->info.proto == PROTO_TCPv6_CLIENT) -	{ - -#ifdef GENERAL_PROXY_SUPPORT -	  bool proxy_retry = false; -#else -	  const bool proxy_retry = false; -#endif -	  do { -	    socket_connect (&sock->sd, -			    &sock->info.lsa->local, -			    sock->bind_local, -			    &sock->info.lsa->actual.dest, -			    sock->connection_profiles_defined, -			    remote_dynamic, -			    &remote_changed, -			    sock->connect_retry_seconds, -			    sock->connect_timeout, -			    sock->connect_retry_max, -			    sock->sockflags, -			    signal_received); - -	    if (*signal_received) -	      goto done; - -	    if (false) -	      ; -#ifdef ENABLE_HTTP_PROXY -	    else if (sock->http_proxy) -	      { -		proxy_retry = establish_http_proxy_passthru (sock->http_proxy, -							     sock->sd, -							     sock->proxy_dest_host, -							     sock->proxy_dest_port, -							     &sock->stream_buf.residual, -							     signal_received); -	      } -#endif -#ifdef ENABLE_SOCKS -	    else if (sock->socks_proxy) -	      { -		establish_socks_proxy_passthru (sock->socks_proxy, -						sock->sd, -						sock->proxy_dest_host, -						sock->proxy_dest_port, -						signal_received); -	      } -#endif -	    if (proxy_retry) -	      { -		openvpn_close_socket (sock->sd); -		sock->sd = create_socket_tcp (AF_INET); -	      } -	  } while (proxy_retry); -	} -#ifdef ENABLE_SOCKS -      else if (sock->info.proto == PROTO_UDPv4 && sock->socks_proxy) -	{ -	  socket_connect (&sock->ctrl_sd, -                          &sock->info.lsa->local, -                          sock->bind_local, -			  &sock->info.lsa->actual.dest, -			  sock->connection_profiles_defined, -			  remote_dynamic, -			  &remote_changed, -			  sock->connect_retry_seconds, -			  sock->connect_timeout, -			  sock->connect_retry_max, -			  sock->sockflags, -			  signal_received); - -	  if (*signal_received) -	    goto done; - -	  establish_socks_proxy_udpassoc (sock->socks_proxy, -					  sock->ctrl_sd, -					  sock->sd, -					  &sock->socks_relay.dest, -					  signal_received); - -	  if (*signal_received) -	    goto done; - -	  sock->remote_host = sock->proxy_dest_host; -	  sock->remote_port = sock->proxy_dest_port; -	  sock->did_resolve_remote = false; - -	  addr_zero_host(&sock->info.lsa->actual.dest); -	  addr_zero_host(&sock->info.lsa->remote); - -	  resolve_remote (sock, 1, NULL, signal_received); - -	  if (*signal_received) -	    goto done; -	} -#endif - -      if (*signal_received) -	goto done; - -      if (remote_changed) -	{ -	  msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment"); -	  addr_copy_host(&sock->info.lsa->remote, &sock->info.lsa->actual.dest); -	} +      /* inetd: hint family type for dest = local's */ +      struct openvpn_sockaddr local_addr; +      socklen_t addrlen = sizeof(local_addr); +      if (getsockname (sock->sd, &local_addr.addr.sa, &addrlen) == 0) { +        sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family; +        dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)", +              proto2ascii(sock->info.proto, sock->info.af, false), local_addr.addr.sa.sa_family, +              sock->sd); +      } else +        msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET", +             proto2ascii(sock->info.proto, sock->info.af, false), sock->sd);      } +#else +    msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() " +         "function, using AF_INET", +         proto2ascii(sock->info.proto, false)); +#endif +    sock->sd = +      socket_listen_accept (sock->sd, +                            &sock->info.lsa->actual, +                            remote_dynamic, +                            sock->info.lsa->bind_local, +                            false, +                            sock->inetd == INETD_NOWAIT, +                            signal_received); +  } +  ASSERT (!remote_changed); +} +static void +phase2_set_socket_flags (struct link_socket* sock) +{    /* set misc socket parameters */    socket_set_flags (sock->sd, sock->sockflags); @@ -1747,35 +1507,245 @@ link_socket_init_phase2 (struct link_socket *sock,    /* if the OS supports it, enable extended error passing on the socket */    set_sock_extended_error_passing (sock->sd);  #endif +} + + +static void +linksock_print_addr (struct link_socket *sock) +{ +  struct gc_arena gc = gc_new ();    /* print local address */    {      const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO; - +          if (sock->inetd) -      msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, true)); +      msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true)); +    else if (sock->bind_local) +      { +        /* Socket is always bound on the first matching address */ +        struct addrinfo *cur; +        for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next) +          { +            if(cur->ai_family == sock->info.lsa->actual.ai_family) +                break; +          } +        ASSERT (cur); +        msg (msglevel, "%s link local (bound): %s", +           proto2ascii (sock->info.proto, sock->info.af, true), +           print_sockaddr(cur->ai_addr,&gc)); +      }      else -      msg (msglevel, "%s link local%s: %s", -	   proto2ascii (sock->info.proto, true), -	   (sock->bind_local ? " (bound)" : ""), -	   print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT : 0, &gc)); - +        msg (msglevel, "%s link local: (not bound)", +             proto2ascii (sock->info.proto, sock->info.af, true)); +          /* print active remote address */      msg (msglevel, "%s link remote: %s", -	 proto2ascii (sock->info.proto, true), -	 print_link_socket_actual_ex (&sock->info.lsa->actual, -				      ":", -				      PS_SHOW_PORT_IF_DEFINED, -				      &gc)); +         proto2ascii (sock->info.proto, sock->info.af, true), +         print_link_socket_actual_ex (&sock->info.lsa->actual, +                                      ":", +                                      PS_SHOW_PORT_IF_DEFINED, +                                      &gc));    } +  gc_free(&gc); +} + +static void +phase2_tcp_server (struct link_socket *sock, const char *remote_dynamic, +                   volatile int *signal_received) +{ +  switch (sock->mode) +    { +    case LS_MODE_DEFAULT: +      sock->sd = socket_listen_accept (sock->sd, +                                       &sock->info.lsa->actual, +                                       remote_dynamic, +                                       sock->info.lsa->bind_local, +                                       true, +                                       false, +                                       signal_received); +      break; +    case LS_MODE_TCP_LISTEN: +      socket_do_listen (sock->sd, +                        sock->info.lsa->bind_local->ai_addr, +                        true, +                        false); +      break; +    case LS_MODE_TCP_ACCEPT_FROM: +      sock->sd = socket_do_accept (sock->sd, +                                   &sock->info.lsa->actual, +                                   false); +      if (!socket_defined (sock->sd)) +        { +          *signal_received = SIGTERM; +          return; +        } +      tcp_connection_established (&sock->info.lsa->actual); +      break; +    default: +      ASSERT (0); +    } + +} + + +static void +phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info) +{ +#ifdef GENERAL_PROXY_SUPPORT +    bool proxy_retry = false; +#else +    const bool proxy_retry = false; +#endif +    do { +        socket_connect (&sock->sd, +                        sock->info.lsa, +                        sock->connect_timeout, +                        sig_info); +         +        if (sig_info->signal_received) +            return; +         +        if (false) +            ; +#ifdef ENABLE_HTTP_PROXY +        else if (sock->http_proxy) +            { +                proxy_retry = establish_http_proxy_passthru (sock->http_proxy, +                                                             sock->sd, +                                                             sock->proxy_dest_host, +                                                             sock->proxy_dest_port, +                                                             &sock->stream_buf.residual, +                                                             &sig_info->signal_received); +            } +#endif +#ifdef ENABLE_SOCKS +        else if (sock->socks_proxy) +            { +                establish_socks_proxy_passthru (sock->socks_proxy, +                                                sock->sd, +                                                sock->proxy_dest_host, +                                                sock->proxy_dest_port, +                                                &sig_info->signal_received); +            } +#endif +        if (proxy_retry) +            { +              /* TODO (schwabe): This code assumes AF_INET for the proxy socket +               * when retrying a connection */ +                openvpn_close_socket (sock->sd); +                sock->sd = create_socket_tcp (AF_INET); +            } +    } while (proxy_retry); + +} + +#ifdef ENABLE_SOCKS +static void +phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info) +{ +    socket_connect (&sock->ctrl_sd, +                    sock->info.lsa, +                    sock->connect_timeout, +                    sig_info); +     +    if (sig_info->signal_received) +        return; +     +    establish_socks_proxy_udpassoc (sock->socks_proxy, +                                    sock->ctrl_sd, +                                    sock->sd, +                                    &sock->socks_relay.dest, +                                    &sig_info->signal_received); +     +    if (sig_info->signal_received) +        return; +     +    sock->remote_host = sock->proxy_dest_host; +    sock->remote_port = sock->proxy_dest_port; +    sock->did_resolve_remote = false; +     +    addr_zero_host(&sock->info.lsa->actual.dest); +    if (sock->info.lsa->remote_list) +        freeaddrinfo(sock->info.lsa->remote_list); +     +    resolve_remote (sock, 1, NULL, &sig_info->signal_received); +     +} +#endif +/* finalize socket initialization */ +void +link_socket_init_phase2 (struct link_socket *sock, +                         const struct frame *frame, +                         struct signal_info *sig_info) +{ +  const char *remote_dynamic = NULL; +  int sig_save = 0; + +  ASSERT (sock); + +  if (sig_info && sig_info->signal_received) +    { +      sig_save = sig_info->signal_received; +      sig_info->signal_received = 0; +    } + +  /* initialize buffers */ +  socket_frame_init (frame, sock); + +  /* +   * Pass a remote name to connect/accept so that +   * they can test for dynamic IP address changes +   * and throw a SIGUSR1 if appropriate. +   */ +  if (sock->resolve_retry_seconds) +    remote_dynamic = sock->remote_host; + +  /* were we started by inetd or xinetd? */ +  if (sock->inetd) +    { +      phase2_inetd (sock, frame, remote_dynamic,  &sig_info->signal_received); +      if (sig_info && sig_info->signal_received) +        goto done; + +    } +  else +    { +      resolve_remote (sock, 2, &remote_dynamic,  &sig_info->signal_received); + +      if (sig_info && sig_info->signal_received) +        goto done; + +      if (sock->info.proto == PROTO_TCP_SERVER) +        { +          phase2_tcp_server (sock, remote_dynamic, +                             &sig_info->signal_received); +        } +      else if (sock->info.proto == PROTO_TCP_CLIENT) +        { +          phase2_tcp_client (sock, sig_info); +     +        } +#ifdef ENABLE_SOCKS +      else if (sock->info.proto == PROTO_UDP && sock->socks_proxy && sock->info.af == AF_INET) +        { +          phase2_socks_client (sock, sig_info); +#endif +        } +      if (sig_info && sig_info->signal_received) +        goto done; +    } + +  phase2_set_socket_flags(sock); +  linksock_print_addr(sock); +    done: -  if (sig_save && signal_received) +  if (sig_save && sig_info)      { -      if (!*signal_received) -	*signal_received = sig_save; +      if (!sig_info->signal_received) +        sig_info->signal_received = sig_save;      } -  gc_free (&gc);  }  void @@ -1843,17 +1813,14 @@ setenv_trusted (struct env_set *es, const struct link_socket_info *info)  static void  ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc)  { -  const char *ip = print_sockaddr_ex (&info->lsa->actual.dest, NULL, 0, gc); -  const char *port = print_sockaddr_ex (&info->lsa->actual.dest, NULL, PS_DONT_SHOW_ADDR|PS_SHOW_PORT, gc); +  const char *host = print_sockaddr_ex (&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT , gc);    if (include_cmd) -    argv_printf (argv, "%sc %s %s", +    argv_printf (argv, "%sc %s",  		 info->ipchange_command, -		 ip, -		 port); +		 host);    else -    argv_printf (argv, "%s %s", -		 ip, -		 port); +    argv_printf (argv, "%s", host); +  }  void @@ -1910,6 +1877,7 @@ link_socket_bad_incoming_addr (struct buffer *buf,  			       const struct link_socket_actual *from_addr)  {    struct gc_arena gc = gc_new (); +  struct addrinfo* ai;    switch(from_addr->dest.addr.sa.sa_family)      { @@ -1919,7 +1887,12 @@ link_socket_bad_incoming_addr (struct buffer *buf,  	   "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)",  	   print_link_socket_actual (from_addr, &gc),  	   (int)from_addr->dest.addr.sa.sa_family, -	   print_sockaddr (&info->lsa->remote, &gc)); +	   print_sockaddr_ex (info->lsa->remote_list->ai_addr,":" ,PS_SHOW_PORT, &gc)); +          /* print additional remote addresses */ +          for(ai=info->lsa->remote_list->ai_next;ai;ai=ai->ai_next) { +             msg(D_LINK_ERRORS,"or from peer address: %s", +                 print_sockaddr_ex(ai->ai_addr,":",PS_SHOW_PORT, &gc)); +          }        break;      }    buf->len = 0; @@ -1944,14 +1917,17 @@ link_socket_current_remote (const struct link_socket_info *info)   * Maybe in the future consider PF_INET6 endpoints also ...   * by now just ignore it   * + * For --remote entries with multiple addresses this + * only return the actual endpoint we have sucessfully connected to   */    if (lsa->actual.dest.addr.sa.sa_family != AF_INET)      return IPV4_INVALID_ADDR;    if (link_socket_actual_defined (&lsa->actual))      return ntohl (lsa->actual.dest.addr.in4.sin_addr.s_addr); -  else if (addr_defined (&lsa->remote)) -    return ntohl (lsa->remote.addr.in4.sin_addr.s_addr); +  else if (lsa->current_remote) +    return ntohl (((struct sockaddr_in*)lsa->current_remote->ai_addr) +                    ->sin_addr.s_addr);    else      return 0;  } @@ -2018,7 +1994,7 @@ stream_buf_init (struct stream_buf *sb,    sb->residual = alloc_buf (sb->maxlen);    sb->error = false;  #if PORT_SHARE -  sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCPv4_SERVER)) +  sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCP_SERVER))      ? PS_ENABLED      : PS_DISABLED;  #endif @@ -2167,67 +2143,58 @@ socket_listen_event_handle (struct link_socket *s)   */  const char * -print_sockaddr (const struct openvpn_sockaddr *addr, struct gc_arena *gc) -{ -  return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc); -} - -const char * -print_sockaddr_ex (const struct openvpn_sockaddr *addr, -		   const char* separator, -		   const unsigned int flags, -		   struct gc_arena *gc) +print_sockaddr_ex (const struct sockaddr *sa, +				   const char* separator, +				   const unsigned int flags, +				   struct gc_arena *gc)  {    struct buffer out = alloc_buf_gc (128, gc);    bool addr_is_defined; -  addr_is_defined = addr_defined (addr); -  if (!addr_is_defined) { -    return "[undef]"; -  } -  switch(addr->addr.sa.sa_family) +  char hostaddr[NI_MAXHOST] = ""; +  char servname[NI_MAXSERV] = ""; +  int status; + +  socklen_t salen; +  switch(sa->sa_family)      {      case AF_INET: -	{ -	  const int port= ntohs (addr->addr.in4.sin_port); -	  buf_puts (&out, "[AF_INET]"); - -	  if (!(flags & PS_DONT_SHOW_ADDR)) -	    buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->addr.in4.sin_addr) : "[undef]")); - -	  if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED))) -	      && port) -	    { -	      if (separator) -		buf_printf (&out, "%s", separator); - -	      buf_printf (&out, "%d", port); -	    } -	} +      buf_puts (&out, "[AF_INET]"); +      salen = sizeof (struct sockaddr_in); +      addr_is_defined = ((struct sockaddr_in*) sa)->sin_addr.s_addr != 0;        break;      case AF_INET6: -	{ -	  const int port= ntohs (addr->addr.in6.sin6_port); -	  char buf[INET6_ADDRSTRLEN] = ""; -	  buf_puts (&out, "[AF_INET6]"); -	  if (addr_is_defined) -	    { -	      getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), -			  buf, sizeof (buf), NULL, 0, NI_NUMERICHOST); -	      buf_puts (&out, buf); -	    } -	  if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED))) -	      && port) -	    { -	      if (separator) -		buf_puts (&out, separator); - -	      buf_printf (&out, "%d", port); -	    } -	} +      buf_puts (&out, "[AF_INET6]"); +      salen = sizeof (struct sockaddr_in6); +      addr_is_defined = !IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6*) sa)->sin6_addr);        break;      default:        ASSERT(0);      } + +  status = getnameinfo(sa, salen, hostaddr, sizeof (hostaddr), +              servname, sizeof(servname), NI_NUMERICHOST | NI_NUMERICSERV); + +  if(status!=0) { +      buf_printf(&out,"[nameinfo() err: %s]",gai_strerror(status)); +      return BSTR(&out); +  } + +  if (!(flags & PS_DONT_SHOW_ADDR)) +    { +      if (addr_is_defined) +        buf_puts (&out, hostaddr); +      else +        buf_puts (&out, "[undef]"); +    } + +  if ((flags & PS_SHOW_PORT) || (flags & PS_SHOW_PORT_IF_DEFINED)) +    { +      if (separator) +        buf_puts (&out, separator); +		 +      buf_puts (&out, servname); +    } +	    return BSTR (&out);  } @@ -2251,7 +2218,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act,      {        char ifname[IF_NAMESIZE] = "[undef]";        struct buffer out = alloc_buf_gc (128, gc); -      buf_printf (&out, "%s", print_sockaddr_ex (&act->dest, separator, flags, gc)); +      buf_printf (&out, "%s", print_sockaddr_ex (&act->dest.addr.sa, separator, flags, gc));  #if ENABLE_IP_PKTINFO        if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act))  	{ @@ -2272,7 +2239,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act,  #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)  #endif  		  buf_printf (&out, " (via %s%%%s)", -			      print_sockaddr_ex (&sa, separator, 0, gc), +			      print_sockaddr_ex (&sa.addr.sa, separator, 0, gc),  			      ifname);  		}  	      break; @@ -2434,22 +2401,23 @@ setenv_link_socket_actual (struct env_set *es,  struct proto_names {    const char *short_form;    const char *display_form; -  bool	is_dgram; -  bool	is_net; -  unsigned short proto_af; +  sa_family_t proto_af; +  int proto;  };  /* Indexed by PROTO_x */ -static const struct proto_names proto_names[PROTO_N] = { -  {"proto-uninitialized",        "proto-NONE",0,0, AF_UNSPEC}, -  {"udp",        "UDPv4",1,1, AF_INET}, -  {"tcp-server", "TCPv4_SERVER",0,1, AF_INET}, -  {"tcp-client", "TCPv4_CLIENT",0,1, AF_INET}, -  {"tcp",        "TCPv4",0,1, AF_INET}, -  {"udp6"       ,"UDPv6",1,1, AF_INET6}, -  {"tcp6-server","TCPv6_SERVER",0,1, AF_INET6}, -  {"tcp6-client","TCPv6_CLIENT",0,1, AF_INET6}, -  {"tcp6"       ,"TCPv6",0,1, AF_INET6}, +static const struct proto_names proto_names[] = { +  {"proto-uninitialized",        "proto-NONE", AF_UNSPEC, PROTO_NONE}, +  {"udp",        "UDP", AF_UNSPEC, PROTO_UDP}, +  {"udp4",        "UDPv4", AF_INET, PROTO_UDP}, +  {"tcp-server", "TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER}, +  {"tcp-client", "TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT}, +  {"tcp",        "TCP", AF_UNSPEC, PROTO_TCP}, +  {"tcp4",        "TCPv4", AF_INET, PROTO_TCP}, +  {"udp6"       ,"UDPv6", AF_INET6, PROTO_UDP}, +  {"tcp6-server","TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER}, +  {"tcp6-client","TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT}, +  {"tcp6"       ,"TCPv6", AF_INET6, PROTO_TCP},  };  bool @@ -2457,59 +2425,66 @@ proto_is_net(int proto)  {    if (proto < 0 || proto >= PROTO_N)      ASSERT(0); -  return proto_names[proto].is_net; +    return proto != PROTO_NONE;  }  bool  proto_is_dgram(int proto)  { -  if (proto < 0 || proto >= PROTO_N) -    ASSERT(0); -  return proto_names[proto].is_dgram; +    return proto_is_udp(proto);  } +  bool  proto_is_udp(int proto)  {    if (proto < 0 || proto >= PROTO_N)      ASSERT(0); -  return proto_names[proto].is_dgram&&proto_names[proto].is_net; +  return proto == PROTO_UDP;  } +  bool  proto_is_tcp(int proto)  {    if (proto < 0 || proto >= PROTO_N)      ASSERT(0); -  return (!proto_names[proto].is_dgram)&&proto_names[proto].is_net; -} - -unsigned short  -proto_sa_family(int proto) -{ -  if (proto < 0 || proto >= PROTO_N) -    ASSERT(0); -  return proto_names[proto].proto_af; +  return proto == PROTO_TCP_CLIENT || proto == PROTO_TCP_SERVER || proto == PROTO_TCP_CLIENT;  }  int  ascii2proto (const char* proto_name)  {    int i; -  ASSERT (PROTO_N == SIZE (proto_names)); -  for (i = 0; i < PROTO_N; ++i) +  for (i = 0; i < SIZE (proto_names); ++i)      if (!strcmp (proto_name, proto_names[i].short_form)) -      return i; +      return proto_names[i].proto;    return -1;  } +sa_family_t +ascii2af (const char* proto_name) +{ +    int i; +    for (i = 0; i < SIZE (proto_names); ++i) +        if (!strcmp (proto_name, proto_names[i].short_form)) +            return proto_names[i].proto_af; +    return 0; +} +  const char * -proto2ascii (int proto, bool display_form) +proto2ascii (int proto, sa_family_t af, bool display_form)  { -  ASSERT (PROTO_N == SIZE (proto_names)); -  if (proto < 0 || proto >= PROTO_N) -    return "[unknown protocol]"; -  else if (display_form) -    return proto_names[proto].display_form; -  else -    return proto_names[proto].short_form; +  unsigned int i; +  for (i = 0; i < SIZE (proto_names); ++i) +    { +      if(proto_names[i].proto_af == af && proto_names[i].proto == proto)  +        { +          if(display_form) +              return proto_names[i].display_form; +          else +              return proto_names[i].short_form; +        } +    } + +  return "[unknown protocol]";  }  const char * @@ -2518,23 +2493,22 @@ proto2ascii_all (struct gc_arena *gc)    struct buffer out = alloc_buf_gc (256, gc);    int i; -  ASSERT (PROTO_N == SIZE (proto_names)); -  for (i = 0; i < PROTO_N; ++i) +  for (i = 0; i < SIZE (proto_names); ++i)      {        if (i)  	buf_printf(&out, " "); -      buf_printf(&out, "[%s]", proto2ascii(i, false)); +      buf_printf(&out, "[%s]", proto_names[i].short_form);      }    return BSTR (&out);  }  int -addr_guess_family(int proto, const char *name)  +addr_guess_family(sa_family_t af, const char *name)   {    unsigned short ret; -  if (proto) +  if (af)      { -      return proto_sa_family(proto);	/* already stamped */ +      return af;	/* already stamped */      }     else      { @@ -2570,6 +2544,10 @@ addr_family_name (int af)   *   * This is used for options compatibility   * checking. + * + * IPv6 and IPv4 protocols are comptabile but OpenVPN + * has always sent UDPv4, TCPv4 over the wire. Keep these + * strings for backward compatbility   */  int  proto_remote (int proto, bool remote) @@ -2579,10 +2557,8 @@ proto_remote (int proto, bool remote)      {        switch (proto)        { -	case PROTO_TCPv4_SERVER: return PROTO_TCPv4_CLIENT; -	case PROTO_TCPv4_CLIENT: return PROTO_TCPv4_SERVER; -	case PROTO_TCPv6_SERVER: return PROTO_TCPv6_CLIENT; -	case PROTO_TCPv6_CLIENT: return PROTO_TCPv6_SERVER; +	case PROTO_TCP_SERVER: return PROTO_TCP_CLIENT; +	case PROTO_TCP_CLIENT: return PROTO_TCP_SERVER;        }      }    return proto; @@ -2733,7 +2709,7 @@ link_socket_read_udp_posix (struct link_socket *sock,  			    struct link_socket_actual *from)  {    socklen_t fromlen = sizeof (from->dest.addr); -  socklen_t expectedlen = af_addr_size(proto_sa_family(sock->info.proto)); +  socklen_t expectedlen = af_addr_size(sock->info.af);    addr_zero_host(&from->dest);    ASSERT (buf_safe (buf, maxsize));  #if ENABLE_IP_PKTINFO @@ -2774,7 +2750,7 @@ link_socket_write_tcp (struct link_socket *sock,  #if ENABLE_IP_PKTINFO -int +size_t  link_socket_write_udp_posix_sendmsg (struct link_socket *sock,  				     struct buffer *buf,  				     struct link_socket_actual *to) @@ -2787,7 +2763,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,    iov.iov_len = BLEN (buf);    mesg.msg_iov = &iov;    mesg.msg_iovlen = 1; -  switch (sock->info.lsa->remote.addr.sa.sa_family) +  switch (to->ai_family)      {      case AF_INET:        { diff --git a/openvpn/src/openvpn/socket.h b/openvpn/src/openvpn/socket.h index 44f1098b..ae6cb9bc 100644 --- a/openvpn/src/openvpn/socket.h +++ b/openvpn/src/openvpn/socket.h @@ -39,7 +39,7 @@  /*   * OpenVPN's default port number as assigned by IANA.   */ -#define OPENVPN_PORT 1194 +#define OPENVPN_PORT "1194"  /*   * Maximum size passed passed to setsockopt SNDBUF/RCVBUF @@ -81,6 +81,11 @@ struct openvpn_sockaddr  struct link_socket_actual  {    /*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */ + int ai_family;	/* PF_xxx */ + int ai_socktype;	/* SOCK_xxx */ + int ai_protocol;	/* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + +        struct openvpn_sockaddr dest;  #if ENABLE_IP_PKTINFO    union { @@ -97,8 +102,10 @@ struct link_socket_actual  /* IP addresses which are persistant across SIGUSR1s */  struct link_socket_addr  { -  struct openvpn_sockaddr local; -  struct openvpn_sockaddr remote;   /* initial remote */ +  struct addrinfo* bind_local; +  struct addrinfo* remote_list;   /* complete remote list */ +  struct addrinfo* current_remote;  /* remote used in the  +                                     current connection attempt */    struct link_socket_actual actual; /* reply to this address */  }; @@ -110,6 +117,7 @@ struct link_socket_info    const struct plugin_list *plugins;    bool remote_float;      int proto;                    /* Protocol (PROTO_x defined below) */ +  sa_family_t af;                       /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/    int mtu_changed;              /* Set to true when mtu value is changed */  }; @@ -175,13 +183,10 @@ struct link_socket    /* used for long-term queueing of pre-accepted socket listen */    bool listen_persistent_queued; -  /* Does config file contain any <connection> ... </connection> blocks? */ -  bool connection_profiles_defined; -    const char *remote_host; -  int remote_port; +  const char *remote_port;    const char *local_host; -  int local_port; +  const char *local_port;    bool bind_local;  # define INETD_NONE   0 @@ -195,9 +200,7 @@ struct link_socket    int mode;    int resolve_retry_seconds; -  int connect_retry_seconds;    int connect_timeout; -  int connect_retry_max;    int mtu_discover_type;    struct socket_buffer_size socket_buffer_sizes; @@ -232,7 +235,7 @@ struct link_socket  #if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_SOCKS)    /* The OpenVPN server we will use the proxy to connect to */    const char *proxy_dest_host; -  int proxy_dest_port; +  const char *proxy_dest_port;  #endif  #if PASSTOS_CAPABILITY @@ -279,11 +282,12 @@ int socket_finalize (  struct link_socket *link_socket_new (void);  void socket_bind (socket_descriptor_t sd, -		  struct openvpn_sockaddr *local, +		  struct addrinfo *local, +                  int af_family,  		  const char *prefix);  int openvpn_connect (socket_descriptor_t sd, -		     struct openvpn_sockaddr *remote, +		     const struct sockaddr *remote,  		     int connect_timeout,  		     volatile int *signal_received); @@ -293,12 +297,12 @@ int openvpn_connect (socket_descriptor_t sd,  void  link_socket_init_phase1 (struct link_socket *sock, -			 const bool connection_profiles_defined,  			 const char *local_host, -			 int local_port, +			 const char *local_port,  			 const char *remote_host, -			 int remote_port, +			 const char *remote_port,  			 int proto, +       sa_family_t af,  			 int mode,  			 const struct link_socket *accept_from,  #ifdef ENABLE_HTTP_PROXY @@ -317,9 +321,7 @@ link_socket_init_phase1 (struct link_socket *sock,  			 const char *ipchange_command,  			 const struct plugin_list *plugins,  			 int resolve_retry_seconds, -			 int connect_retry_seconds,  			 int connect_timeout, -			 int connect_retry_max,  			 int mtu_discover_type,  			 int rcvbuf,  			 int sndbuf, @@ -328,7 +330,7 @@ link_socket_init_phase1 (struct link_socket *sock,  void link_socket_init_phase2 (struct link_socket *sock,  			      const struct frame *frame, -			      volatile int *signal_received); +			      struct signal_info *sig_info);  void socket_adjust_frame_parameters (struct frame *frame, int proto); @@ -343,14 +345,35 @@ void sd_close (socket_descriptor_t *sd);  #define PS_SHOW_PKTINFO         (1<<2)  #define PS_DONT_SHOW_ADDR       (1<<3) -const char *print_sockaddr_ex (const struct openvpn_sockaddr *addr, +const char *print_sockaddr_ex (const struct sockaddr *addr,  			       const char* separator,  			       const unsigned int flags,  			       struct gc_arena *gc); +static inline +const char *print_openvpn_sockaddr_ex (const struct openvpn_sockaddr *addr, +			       const char* separator, +			       const unsigned int flags, +			       struct gc_arena *gc) +{ +    return print_sockaddr_ex(&addr->addr.sa, separator, flags, gc); +} + +static inline +const char *print_openvpn_sockaddr (const struct openvpn_sockaddr *addr, +			    struct gc_arena *gc) +{ +    return print_sockaddr_ex (&addr->addr.sa, ":", PS_SHOW_PORT, gc); +} + +static inline +const char *print_sockaddr (const struct sockaddr *addr, +                                    struct gc_arena *gc) +{ +    return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc); +} + -const char *print_sockaddr (const struct openvpn_sockaddr *addr, -			    struct gc_arena *gc);  const char *print_link_socket_actual_ex (const struct link_socket_actual *act,  					 const char* separator, @@ -402,6 +425,9 @@ void link_socket_bad_incoming_addr (struct buffer *buf,  				    const struct link_socket_info *info,  				    const struct link_socket_actual *from_addr); +void set_actual_address (struct link_socket_actual* actual, +                         struct addrinfo* ai); +  void link_socket_bad_outgoing_addr (void);  void setenv_trusted (struct env_set *es, const struct link_socket_info *info); @@ -477,11 +503,8 @@ bool unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int *  #define GETADDR_TRY_ONCE              (1<<7)  #define GETADDR_UPDATE_MANAGEMENT_STATE (1<<8)  #define GETADDR_RANDOMIZE             (1<<9) - -/* [ab]use flags bits to get socktype info downstream */ -/* TODO(jjo): resolve tradeoff between hackiness|args-overhead */ -#define GETADDR_DGRAM                 (1<<10) -#define dnsflags_to_socktype(flags) ((flags & GETADDR_DGRAM) ? SOCK_DGRAM : SOCK_STREAM) +#define GETADDR_PASSIVE               (1<<10) +#define GETADDR_DATAGRAM              (1<<11)  in_addr_t getaddr (unsigned int flags,  		   const char *hostname, @@ -491,6 +514,7 @@ in_addr_t getaddr (unsigned int flags,  int openvpn_getaddrinfo (unsigned int flags,                           const char *hostname, +                         const char *servname,                           int resolve_retry_seconds,                           volatile int *signal_received,                           int ai_family, @@ -506,19 +530,16 @@ int openvpn_getaddrinfo (unsigned int flags,   */  enum proto_num {  	PROTO_NONE, /* catch for uninitialized */ -	PROTO_UDPv4, -	PROTO_TCPv4_SERVER, -	PROTO_TCPv4_CLIENT, -	PROTO_TCPv4, -	PROTO_UDPv6, -	PROTO_TCPv6_SERVER, -	PROTO_TCPv6_CLIENT, -	PROTO_TCPv6, +	PROTO_UDP, +	PROTO_TCP, +	PROTO_TCP_SERVER, +	PROTO_TCP_CLIENT,  	PROTO_N  };  int ascii2proto (const char* proto_name); -const char *proto2ascii (int proto, bool display_form); +sa_family_t ascii2af (const char* proto_name); +const char *proto2ascii (int proto, sa_family_t af, bool display_form);  const char *proto2ascii_all (struct gc_arena *gc);  int proto_remote (int proto, bool remote);  const char *addr_family_name(int af); @@ -545,12 +566,6 @@ datagram_overhead (int proto)   */  static inline bool -legal_ipv4_port (int port) -{ -  return port > 0 && port < 65536; -} - -static inline bool  link_socket_proto_connection_oriented (int proto)  {    return !proto_is_dgram(proto); @@ -604,13 +619,35 @@ link_socket_actual_defined (const struct link_socket_actual *act)  static inline bool  addr_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)  { -  switch(a1->addr.sa.sa_family) { +    switch(a1->addr.sa.sa_family) { +        case AF_INET: +            return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr; +        case AF_INET6: +            return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr); +    } +    ASSERT(0); +    return false; +} + +static inline bool +addrlist_match (const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist) +{ +  const struct addrinfo *curele; +  for (curele = addrlist; curele; curele=curele->ai_next) { + +    switch(a1->addr.sa.sa_family) {      case AF_INET: -      return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr; +      if (a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr) +        return true; +      break;      case AF_INET6: -      return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr); +      if (IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr)) +        return true; +      break; +    default: +      ASSERT(0); +    }    } -  ASSERT(0);    return false;  } @@ -627,6 +664,34 @@ addr_host (const struct openvpn_sockaddr *addr)    return ntohl (addr->addr.in4.sin_addr.s_addr);  } + +static inline bool +addrlist_port_match (const struct openvpn_sockaddr *a1, const struct addrinfo *a2) +{ +    const struct addrinfo *curele; +    for(curele=a2;curele;curele = curele->ai_next) { +        switch(a1->addr.sa.sa_family) { +            case AF_INET: +            if (curele->ai_family == AF_INET +                && a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr +                && a1->addr.in4.sin_port == ((struct sockaddr_in*)curele->ai_addr)->sin_port) +                return true; +                break; +            case AF_INET6: +                if (curele->ai_family == AF_INET6 +                && IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr) +                && a1->addr.in6.sin6_port == ((struct sockaddr_in6*) curele->ai_addr)->sin6_port) +                    return true; +                break; +            default: +                ASSERT(0); +        } +    } +    return false; +} + + +  static inline bool  addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)  { @@ -644,14 +709,25 @@ addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockadd  static inline bool  addr_match_proto (const struct openvpn_sockaddr *a1, -		  const struct openvpn_sockaddr *a2, -		  const int proto) +                      const struct openvpn_sockaddr *a2, +                      const int proto)  { -  return link_socket_proto_connection_oriented (proto) +    return link_socket_proto_connection_oriented (proto)      ? addr_match (a1, a2)      : addr_port_match (a1, a2);  } + +static inline bool +addrlist_match_proto (const struct openvpn_sockaddr *a1, +		  struct addrinfo *addr_list, +		  const int proto) +{ +  return link_socket_proto_connection_oriented (proto) +    ? addrlist_match (a1, addr_list) +    : addrlist_port_match (a1, addr_list); +} +  static inline void  addr_zero_host(struct openvpn_sockaddr *addr)  { @@ -671,28 +747,15 @@ addr_copy_sa(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src)    dst->addr = src->addr;  } -static inline void -addr_copy_host(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src) -{ -   switch(src->addr.sa.sa_family) { -     case AF_INET: -       dst->addr.in4.sin_addr.s_addr = src->addr.in4.sin_addr.s_addr; -       break; -     case AF_INET6:  -       dst->addr.in6.sin6_addr = src->addr.in6.sin6_addr; -       break; -   } -} -  static inline bool  addr_inet4or6(struct sockaddr *addr)  {  	return addr->sa_family == AF_INET || addr->sa_family == AF_INET6;  } -int addr_guess_family(int proto, const char *name); +int addr_guess_family(sa_family_t af,const char *name);  static inline int -af_addr_size(unsigned short af) +af_addr_size(sa_family_t af)  {     switch(af) {       case AF_INET: return sizeof (struct sockaddr_in); @@ -768,9 +831,9 @@ link_socket_verify_incoming_addr (struct buffer *buf,  	case AF_INET:  	  if (!link_socket_actual_defined (from_addr))  	    return false; -	  if (info->remote_float || !addr_defined (&info->lsa->remote)) +	  if (info->remote_float || !info->lsa->remote_list)  	    return true; -	  if (addr_match_proto (&from_addr->dest, &info->lsa->remote, info->proto)) +	  if (addrlist_match_proto (&from_addr->dest, info->lsa->remote_list, info->proto))  	    return true;        }      } @@ -812,8 +875,8 @@ link_socket_set_outgoing_addr (const struct buffer *buf,  	   || !addr_match_proto (&act->dest, &lsa->actual.dest, info->proto))  	  /* address undef or address == remote or --float */  	  && (info->remote_float -	      || !addr_defined (&lsa->remote) -	      || addr_match_proto (&act->dest, &lsa->remote, info->proto)) +	      || !lsa->remote_list) +	      || addrlist_match_proto (&act->dest, lsa->remote_list, info->proto)  	  )  	{  	  link_socket_connection_initiated (buf, info, act, common_name, es); @@ -937,13 +1000,13 @@ link_socket_write_win32 (struct link_socket *sock,  #else -static inline int +static inline size_t  link_socket_write_udp_posix (struct link_socket *sock,  			     struct buffer *buf,  			     struct link_socket_actual *to)  {  #if ENABLE_IP_PKTINFO -  int link_socket_write_udp_posix_sendmsg (struct link_socket *sock, +  size_t link_socket_write_udp_posix_sendmsg (struct link_socket *sock,  					   struct buffer *buf,  					   struct link_socket_actual *to); @@ -957,7 +1020,7 @@ link_socket_write_udp_posix (struct link_socket *sock,  		   (socklen_t) af_addr_size(to->dest.addr.sa.sa_family));  } -static inline int +static inline size_t  link_socket_write_tcp_posix (struct link_socket *sock,  			     struct buffer *buf,  			     struct link_socket_actual *to) @@ -967,7 +1030,7 @@ link_socket_write_tcp_posix (struct link_socket *sock,  #endif -static inline int +static inline size_t  link_socket_write_udp (struct link_socket *sock,  		       struct buffer *buf,  		       struct link_socket_actual *to) diff --git a/openvpn/src/openvpn/socks.c b/openvpn/src/openvpn/socks.c index 235982e4..804c9836 100644 --- a/openvpn/src/openvpn/socks.c +++ b/openvpn/src/openvpn/socks.c @@ -55,13 +55,13 @@  void  socks_adjust_frame_parameters (struct frame *frame, int proto)  { -  if (proto == PROTO_UDPv4) +  if (proto == PROTO_UDP)      frame_add_to_extra_link (frame, 10);  }  struct socks_proxy_info *  socks_proxy_new (const char *server, -		 int port, +		 const char *port,  		 const char *authfile,  		 bool retry)  { @@ -70,7 +70,7 @@ socks_proxy_new (const char *server,    ALLOC_OBJ_CLEAR (p, struct socks_proxy_info);    ASSERT (server); -  ASSERT (legal_ipv4_port (port)); +  ASSERT (port);    strncpynt (p->server, server, sizeof (p->server));    p->port = port; @@ -389,11 +389,27 @@ recv_socks_reply (socket_descriptor_t sd,    return true;  } +static int +port_from_servname(const char* servname) +{ +    int port =0; +    port = atoi(servname); +    if(port >0 && port < 65536) +        return port; +     +    struct  servent* service; +    service = getservbyname(servname, NULL); +    if(service) +        return service->s_port; + +    return 0; +} +  void  establish_socks_proxy_passthru (struct socks_proxy_info *p,  			        socket_descriptor_t sd, /* already open to proxy */  			        const char *host,       /* openvpn server remote */ -			        const int port,         /* openvpn server port */ +			        const char *servname,   /* openvpn server port */  			        volatile int *signal_received)  {    char buf[128]; @@ -414,6 +430,13 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p,    buf[4] = (char) len;    memcpy(buf + 5, host, len); +  int port = port_from_servname (servname); +  if (port ==0) +    { +      msg (D_LINK_ERRORS, "establish_socks_proxy_passthrough: Cannot convert %s to port number", servname); +      goto error; +    } +        buf[5 + len] = (char) (port >> 8);    buf[5 + len + 1] = (char) (port & 0xff); @@ -425,6 +448,7 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p,  	goto error;        }    } +        /* receive reply from Socks proxy and discard */    if (!recv_socks_reply (sd, NULL, signal_received)) diff --git a/openvpn/src/openvpn/socks.h b/openvpn/src/openvpn/socks.h index b55ff6fb..30b957d7 100644 --- a/openvpn/src/openvpn/socks.h +++ b/openvpn/src/openvpn/socks.h @@ -42,14 +42,14 @@ struct socks_proxy_info {    bool retry;    char server[128]; -  int port; +  const char *port;    char authfile[256];  };  void socks_adjust_frame_parameters (struct frame *frame, int proto);  struct socks_proxy_info *socks_proxy_new (const char *server, -					  int port, +					  const char *port,  					  const char *authfile,  					  bool retry); @@ -58,7 +58,7 @@ void socks_proxy_close (struct socks_proxy_info *sp);  void establish_socks_proxy_passthru (struct socks_proxy_info *p,  				     socket_descriptor_t sd, /* already open to proxy */  				     const char *host,       /* openvpn server remote */ -				     const int port,         /* openvpn server port */ +				     const char *servname,         /* openvpn server port */  				     volatile int *signal_received);  void establish_socks_proxy_udpassoc (struct socks_proxy_info *p, diff --git a/openvpn/src/openvpn/ssl_polarssl.c b/openvpn/src/openvpn/ssl_polarssl.c index 6995958b..12318b33 100644 --- a/openvpn/src/openvpn/ssl_polarssl.c +++ b/openvpn/src/openvpn/ssl_polarssl.c @@ -338,7 +338,7 @@ void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,    if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_file_inline)      { -      if (0 != x509parse_crt(ctx->ca_chain, ca_file_inline, strlen(ca_file_inline))); +      if (0 != x509parse_crt(ctx->ca_chain, ca_file_inline, strlen(ca_file_inline)))  	msg (M_FATAL, "Cannot load inline CA certificates");      }    else diff --git a/openvpn/src/openvpn/tun.c b/openvpn/src/openvpn/tun.c index 1b2e5822..a0754427 100644 --- a/openvpn/src/openvpn/tun.c +++ b/openvpn/src/openvpn/tun.c @@ -413,8 +413,8 @@ init_tun (const char *dev,       /* --dev option */  	  const char *ifconfig_ipv6_local_parm,     /* --ifconfig parm 1 IPv6 */  	  int         ifconfig_ipv6_netbits_parm,  	  const char *ifconfig_ipv6_remote_parm,    /* --ifconfig parm 2 IPv6 */ -	  in_addr_t local_public, -	  in_addr_t remote_public, +	  struct addrinfo *local_public, +	  struct addrinfo *remote_public,  	  const bool strict_warn,  	  struct env_set *es)  { @@ -468,24 +468,31 @@ init_tun (const char *dev,       /* --dev option */         */        if (strict_warn)  	{ +          struct addrinfo *curele;  	  ifconfig_sanity_check (tt->type == DEV_TYPE_TUN, tt->remote_netmask, tt->topology);  	  /*  	   * If local_public or remote_public addresses are defined,  	   * make sure they do not clash with our virtual subnet.  	   */ - -	  check_addr_clash ("local", +           +          for(curele=remote_public;curele;curele=curele->ai_next) { +            if(curele->ai_family == AF_INET) +              check_addr_clash ("local",  			    tt->type, -			    local_public, +                            ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr,  			    tt->local,  			    tt->remote_netmask); +          } -	  check_addr_clash ("remote", -			    tt->type, -			    remote_public, -			    tt->local, -			    tt->remote_netmask); +          for(curele=remote_public;curele;curele=curele->ai_next) { +            if(curele->ai_family == AF_INET) +              check_addr_clash ("remote", +                                tt->type, +                                ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr, +			        tt->local, +			        tt->remote_netmask); +          }  	  if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET))  	    check_subnet_conflict (tt->local, tt->remote_netmask, "TUN/TAP adapter"); @@ -1405,7 +1412,7 @@ close_tun_generic (struct tuntap *tt)    if (tt->fd >= 0)      close (tt->fd);    if (tt->actual_name) -	  free (tt->actual_name); +    free (tt->actual_name);    clear_tuntap (tt);  } @@ -1439,8 +1446,8 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu          msg (M_ERR, "ERROR: Cannot open TUN");      }      /* Set the actual name to a dummy name to enable scripts */ -	tt->actual_name = (char *) malloc(32); -	strncpy(tt->actual_name, "vpnservice-tun",32); +    tt->actual_name = (char *) malloc(32); +    strncpy(tt->actual_name, "vpnservice-tun",32);      gc_free (&gc);  } diff --git a/openvpn/src/openvpn/tun.h b/openvpn/src/openvpn/tun.h index c31ac001..e7d941ab 100644 --- a/openvpn/src/openvpn/tun.h +++ b/openvpn/src/openvpn/tun.h @@ -231,8 +231,8 @@ struct tuntap *init_tun (const char *dev,       /* --dev option */  			 const char *ifconfig_ipv6_local_parm,     /* --ifconfig parm 1 / IPv6 */  			 int ifconfig_ipv6_netbits_parm,           /* --ifconfig parm 1 / bits */  			 const char *ifconfig_ipv6_remote_parm,    /* --ifconfig parm 2 / IPv6 */ -			 in_addr_t local_public, -			 in_addr_t remote_public, +			 struct addrinfo *local_public, +			 struct addrinfo *remote_public,  			 const bool strict_warn,  			 struct env_set *es); diff --git a/openvpn/src/openvpn/win32.c b/openvpn/src/openvpn/win32.c index d00088eb..2db96a8d 100644 --- a/openvpn/src/openvpn/win32.c +++ b/openvpn/src/openvpn/win32.c @@ -82,51 +82,6 @@ struct semaphore netcmd_semaphore; /* GLOBAL */   */  static char *win_sys_path = NULL; /* GLOBAL */ -/* - * Configure PATH.  On Windows, sometimes PATH is not set correctly - * by default. - */ -static void -configure_win_path (void) -{ -  static bool done = false; /* GLOBAL */ -  if (!done) -    { -      FILE *fp; -      fp = fopen ("c:\\windows\\system32\\route.exe", "rb"); -      if (fp) -	{ -	  const int bufsiz = 4096; -	  struct gc_arena gc = gc_new (); -	  struct buffer oldpath = alloc_buf_gc (bufsiz, &gc); -	  struct buffer newpath = alloc_buf_gc (bufsiz, &gc); -	  const char* delim = ";"; -	  DWORD status; -	  fclose (fp); -	  status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath)); -#if 0 -	  status = 0; -#endif -	  if (!status) -	    { -	      *BPTR(&oldpath) = '\0'; -	      delim = ""; -	    } -	  buf_printf (&newpath, "C:\\WINDOWS\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem%s%s", -		      delim, -		      BSTR(&oldpath)); -	  SetEnvironmentVariable ("PATH", BSTR(&newpath)); -#if 0 -	  status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath)); -	  if (status > 0) -	    printf ("PATH: %s\n", BSTR(&oldpath)); -#endif -	  gc_free (&gc); -	  done = true; -	} -    } -} -  void  init_win32 (void)  { @@ -907,53 +862,41 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i      {        if (openvpn_execve_allowed (flags))  	{ -	  if (script_method == SM_EXECVE) -	    { -	      struct gc_arena gc = gc_new (); -	      STARTUPINFOW start_info; -	      PROCESS_INFORMATION proc_info; - -	      char *env = env_block (es); -	      WCHAR *cl = wide_cmd_line (a, &gc); -	      WCHAR *cmd = wide_string (a->argv[0], &gc); - -	      CLEAR (start_info); -	      CLEAR (proc_info); - -	      /* fill in STARTUPINFO struct */ -	      GetStartupInfoW(&start_info); -	      start_info.cb = sizeof(start_info); -	      start_info.dwFlags = STARTF_USESHOWWINDOW; -	      start_info.wShowWindow = SW_HIDE; - -	      if (CreateProcessW (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info)) -		{ -		  DWORD exit_status = 0; -		  CloseHandle (proc_info.hThread); -		  WaitForSingleObject (proc_info.hProcess, INFINITE); -		  if (GetExitCodeProcess (proc_info.hProcess, &exit_status)) -		    ret = (int)exit_status; -		  else -		    msg (M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %S failed", cmd); -		  CloseHandle (proc_info.hProcess); -		} -	      else -		{ -		  msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %S failed", cmd); -		} -	      free (env); -	      gc_free (&gc); -	    } -	  else if (script_method == SM_SYSTEM) -	    { -	      configure_win_path (); -	      ret = openvpn_system (argv_system_str (a), es, flags); -	    } -	  else -	    { -	      ASSERT (0); -	    } -	} +          struct gc_arena gc = gc_new (); +          STARTUPINFOW start_info; +          PROCESS_INFORMATION proc_info; + +          char *env = env_block (es); +          WCHAR *cl = wide_cmd_line (a, &gc); +          WCHAR *cmd = wide_string (a->argv[0], &gc); + +          CLEAR (start_info); +          CLEAR (proc_info); + +          /* fill in STARTUPINFO struct */ +          GetStartupInfoW(&start_info); +          start_info.cb = sizeof(start_info); +          start_info.dwFlags = STARTF_USESHOWWINDOW; +          start_info.wShowWindow = SW_HIDE; + +          if (CreateProcessW (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info)) +            { +              DWORD exit_status = 0; +              CloseHandle (proc_info.hThread); +              WaitForSingleObject (proc_info.hProcess, INFINITE); +              if (GetExitCodeProcess (proc_info.hProcess, &exit_status)) +                ret = (int)exit_status; +              else +                msg (M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %S failed", cmd); +              CloseHandle (proc_info.hProcess); +            } +          else +            { +              msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %S failed", cmd); +            } +          free (env); +          gc_free (&gc); +        }        else if (!exec_warn && (script_security < SSEC_SCRIPTS))  	{  	  msg (M_WARN, SCRIPT_SECURITY_WARNING); | 
