]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Merged connection profiles from
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Wed, 11 Jun 2008 10:48:50 +0000 (10:48 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Wed, 11 Jun 2008 10:48:50 +0000 (10:48 +0000)
http://svn.openvpn.net/projects/openvpn/test/conn

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@2993 e7ae566f-a301-0410-adde-c780ea21d3b5

23 files changed:
buffer.c
buffer.h
errlevel.h
forward.c
helper.c
init.c
misc.c
misc.h
multi.c
occ.c
openvpn.8
openvpn.c
openvpn.h
options.c
options.h
proxy.c
proxy.h
socket.c
socket.h
socks.c
socks.h
syshead.h
version.m4

index 92b10e56fbd353e704b23ca3cc95814bdb295043..f548e9ff2750cf90e543f310c3e6b15048c6d85b 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -314,6 +314,26 @@ x_gc_free (struct gc_arena *a)
     }
 }
 
+/*
+ * Transfer src arena to dest, resetting src to an empty arena.
+ */
+void
+gc_transfer (struct gc_arena *dest, struct gc_arena *src)
+{
+  if (dest && src)
+    {
+      struct gc_entry *e = src->list;
+      if (e)
+       {
+         while (e->next != NULL)
+           e = e->next;
+         e->next = dest->list;
+         dest->list = src->list;
+         src->list = NULL;
+       }
+    }
+}
+
 /*
  * Hex dump -- Output a binary buffer to a hex string and return it.
  */
index 195c7d36877164d9f20679aa2b2dea4f2532c15b..4a6d3a48c40afd40e7efb81a413b99400cf479fe 100644 (file)
--- a/buffer.h
+++ b/buffer.h
@@ -632,6 +632,8 @@ void character_class_debug (void);
  * char ptrs to malloced strings.
  */
 
+void gc_transfer (struct gc_arena *dest, struct gc_arena *src);
+
 void x_gc_free (struct gc_arena *a);
 
 static inline void
index b2a0ddae834f316a3c99302ae77e11f9d393250c..359745ecb4d1d86aa5a83fffb64662baad2dcd8a 100644 (file)
 #define D_MULTI_DEBUG        LOGLEV(7, 70, M_DEBUG)  /* show medium-freq multi debugging info */
 #define D_MSS                LOGLEV(7, 70, M_DEBUG)  /* show MSS adjustments */
 #define D_COMP_LOW           LOGLEV(7, 70, M_DEBUG)  /* show adaptive compression state changes */
-#define D_REMOTE_LIST        LOGLEV(7, 70, M_DEBUG)  /* show --remote list */
+#define D_CONNECTION_LIST    LOGLEV(7, 70, M_DEBUG)  /* show <connection> list info */
 #define D_SCRIPT             LOGLEV(7, 70, M_DEBUG)  /* show parms & env vars passed to scripts */
 #define D_SHOW_NET           LOGLEV(7, 70, M_DEBUG)  /* show routing table and adapter list */
 #define D_ROUTE_DEBUG        LOGLEV(7, 70, M_DEBUG)  /* show verbose route.[ch] output */
index 85c11944728d8c0aa91462449072f43b3328a0c0..e759e24956659bf23126cebe24fb7c10be8a2267 100644 (file)
--- a/forward.c
+++ b/forward.c
@@ -356,7 +356,7 @@ check_fragment_dowork (struct context *c)
   if (lsi->mtu_changed && c->c2.ipv4_tun)
     {
       frame_adjust_path_mtu (&c->c2.frame_fragment, c->c2.link_socket->mtu,
-                            c->options.proto);
+                            c->options.ce.proto);
       lsi->mtu_changed = false;
     }
 
@@ -1038,7 +1038,7 @@ process_outgoing_link (struct context *c)
 #ifdef HAVE_GETTIMEOFDAY
          if (c->options.shaper)
            shaper_wrote_bytes (&c->c2.shaper, BLEN (&c->c2.to_link)
-                               + datagram_overhead (c->options.proto));
+                               + datagram_overhead (c->options.ce.proto));
 #endif
          /*
           * Let the pinger know that we sent a packet.
index a2166876a646e7f3584e0a19572d72cec3ca36d1..4ec63f2b35388dda63b13d31dc33b7f24dc78289 100644 (file)
--- a/helper.c
+++ b/helper.c
@@ -281,9 +281,6 @@ helper_client_server (struct options *o)
          o->push_ifconfig_constraint_network = o->server_network;
          o->push_ifconfig_constraint_netmask = o->server_netmask;
        }
-
-      if (o->proto == PROTO_TCPv4)
-       o->proto = PROTO_TCPv4_SERVER;
     }
 
   /*
@@ -325,9 +322,6 @@ helper_client_server (struct options *o)
       ifconfig_pool_verify_range (M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end);
       o->ifconfig_pool_netmask = o->server_bridge_netmask;
       push_option (o, print_opt_route_gateway (o->server_bridge_ip, &o->gc), M_USAGE);
-
-      if (o->proto == PROTO_TCPv4)
-       o->proto = PROTO_TCPv4_SERVER;
     }
   else
 #endif /* P2MP_SERVER */
@@ -349,16 +343,10 @@ helper_client_server (struct options *o)
 
       o->pull = true;
       o->tls_client = true;
-
-      if (o->proto == PROTO_TCPv4)
-       o->proto = PROTO_TCPv4_CLIENT;
     }
 
 #endif /* P2MP */
 
-  if (o->proto == PROTO_TCPv4)
-    msg (M_USAGE, "--proto tcp is ambiguous in this context.  Please specify --proto tcp-server or --proto tcp-client");
-
   gc_free (&gc);
 }
 
diff --git a/init.c b/init.c
index 97ecf7d37518fe236776a98276ac0305b86142b2..36d7b8f0e76b5af9a742a022a6a3f6ba91515803 100644 (file)
--- a/init.c
+++ b/init.c
@@ -78,23 +78,100 @@ context_clear_all_except_first_time (struct context *c)
 }
 
 /*
- * Initialize and possibly randomize remote list.
+ * Should be called after options->ce is modified at the top
+ * of a SIGUSR1 restart.
  */
 static void
-init_remote_list (struct context *c)
+update_options_ce_post (struct options *options)
 {
-  c->c1.remote_list = NULL;
+#if P2MP
+  /*
+   * In pull mode, we usually import --ping/--ping-restart parameters from
+   * the server.  However we should also set an initial default --ping-restart
+   * for the period of time before we pull the --ping-restart parameter
+   * from the server.
+   */
+  if (options->pull
+      && options->ping_rec_timeout_action == PING_UNDEF
+      && options->ce.proto == PROTO_UDPv4)
+    {
+      options->ping_rec_timeout = PRE_PULL_INITIAL_PING_RESTART;
+      options->ping_rec_timeout_action = PING_RESTART;
+    }
+#endif
+#ifdef USE_CRYPTO
+  /* 
+   * Don't use replay window for TCP mode (i.e. require that packets be strictly in sequence).
+   */
+  if (link_socket_proto_connection_oriented (options->ce.proto))
+    options->replay_window = options->replay_time = 0;
+#endif
+}
 
-  if (c->options.remote_list)
+/*
+ * Initialize and possibly randomize connection list.
+ */
+static void
+init_connection_list (struct context *c)
+{
+#ifdef ENABLE_CONNECTION
+  struct connection_list *l = c->options.connection_list;
+  if (l)
     {
-      struct remote_list *l;
-      ALLOC_OBJ_GC (c->c1.remote_list, struct remote_list, &c->gc);
-      l = c->c1.remote_list;
-      *l = *c->options.remote_list;
       l->current = -1;
       if (c->options.remote_random)
-       remote_list_randomize (l);
+       {
+         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;
+               }
+           }
+       }
     }
+#endif
+}
+
+/*
+ * Increment to next connection entry
+ */
+static void
+next_connection_entry (struct context *c)
+{
+#ifdef ENABLE_CONNECTION
+  struct connection_list *l = c->options.connection_list;
+  if (l)
+    {
+      if (l->no_advance && l->current >= 0)
+       {
+         l->no_advance = false;
+       }
+      else
+       {
+         int i;
+         if (++l->current >= l->len)
+           l->current = 0;
+
+         dmsg (D_CONNECTION_LIST, "CONNECTION_LIST len=%d current=%d",
+               l->len, l->current);
+         for (i = 0; i < l->len; ++i)
+           {
+             dmsg (D_CONNECTION_LIST, "[%d] %s:%d",
+                   i,
+                   l->array[i]->remote,
+                   l->array[i]->remote_port);
+           }
+       }
+      c->options.ce = *l->array[l->current];
+    }
+#endif
+  update_options_ce_post (&c->options);
 }
 
 /*
@@ -116,8 +193,41 @@ init_query_passwords (struct context *c)
 #endif
 }
 
-void
-context_init_1 (struct context *c)
+/*
+ * Initialize/Uninitialize HTTP or SOCKS proxy
+ */
+
+#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)
+{
+#ifdef ENABLE_HTTP_PROXY
+  if (c->c1.http_proxy_owned && c->c1.http_proxy)
+    {
+      http_proxy_close (c->c1.http_proxy);
+      c->c1.http_proxy = NULL;
+      c->c1.http_proxy_owned = false;
+    }
+#endif
+#ifdef ENABLE_SOCKS
+  if (c->c1.socks_proxy_owned && c->c1.socks_proxy)
+    {
+      socks_proxy_close (c->c1.socks_proxy);
+      c->c1.socks_proxy = NULL;
+      c->c1.socks_proxy_owned = false;
+    }
+#endif
+}
+
+static void
+init_proxy_dowork (struct context *c)
 {
 #ifdef ENABLE_HTTP_PROXY
   bool did_http = false;
@@ -125,10 +235,73 @@ context_init_1 (struct context *c)
   const bool did_http = false;
 #endif
 
+  uninit_proxy_dowork (c);
+
+#ifdef ENABLE_HTTP_PROXY
+  if (c->options.ce.http_proxy_options || c->options.auto_proxy_info)
+    {
+      /* Possible HTTP proxy user/pass input */
+      c->c1.http_proxy = http_proxy_new (c->options.ce.http_proxy_options,
+                                        c->options.auto_proxy_info);
+      if (c->c1.http_proxy)
+       {
+         did_http = true;
+         c->c1.http_proxy_owned = true;
+       }
+    }
+#endif
+
+#ifdef ENABLE_SOCKS
+  if (!did_http && (c->options.ce.socks_proxy_server || c->options.auto_proxy_info))
+    {
+      c->c1.socks_proxy = socks_proxy_new (c->options.ce.socks_proxy_server,
+                                          c->options.ce.socks_proxy_port,
+                                          c->options.ce.socks_proxy_retry,
+                                          c->options.auto_proxy_info);
+      if (c->c1.socks_proxy)
+       {
+         c->c1.socks_proxy_owned = true;
+       }
+    }
+#endif
+}
+
+static void
+init_proxy (struct context *c, const int scope)
+{
+  if (scope == proxy_scope (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);
+}
+
+#else
+
+static inline void
+init_proxy (struct context *c, const int scope)
+{
+}
+
+static inline void
+uninit_proxy (struct context *c, const int scope)
+{
+}
+
+#endif
+
+void
+context_init_1 (struct context *c)
+{
   context_clear_1 (c);
 
   packet_id_persist_init (&c->c1.pid_persist);
-  init_remote_list (c);
+
+  init_connection_list (c);
 
   init_query_passwords (c);
 
@@ -156,28 +329,8 @@ context_init_1 (struct context *c)
  }
 #endif
 
-#ifdef ENABLE_HTTP_PROXY
-  if (c->options.http_proxy_options || c->options.auto_proxy_info)
-    {
-      /* Possible HTTP proxy user/pass input */
-      c->c1.http_proxy = new_http_proxy (c->options.http_proxy_options,
-                                        c->options.auto_proxy_info,
-                                        &c->gc);
-      if (c->c1.http_proxy)
-       did_http = true;
-    }
-#endif
-
-#ifdef ENABLE_SOCKS
-  if (!did_http && (c->options.socks_proxy_server || c->options.auto_proxy_info))
-    {
-      c->c1.socks_proxy = new_socks_proxy (c->options.socks_proxy_server,
-                                          c->options.socks_proxy_port,
-                                          c->options.socks_proxy_retry,
-                                          c->options.auto_proxy_info,
-                                          &c->gc);
-    }
-#endif
+  /* initialize HTTP or SOCKS proxy object at scope level 1 */
+  init_proxy (c, 1);
 }
 
 void
@@ -407,7 +560,7 @@ do_persist_tuntap (const struct options *options)
     {
       /* sanity check on options for --mktun or --rmtun */
       notnull (options->dev, "TUN/TAP device (--dev)");
-      if (options->remote_list || options->ifconfig_local
+      if (options->ce.remote || options->ifconfig_local
          || options->ifconfig_remote_netmask
 #ifdef USE_CRYPTO
          || options->shared_secret_file
@@ -684,9 +837,9 @@ initialization_sequence_completed (struct context *c, const unsigned int flags)
   else
     msg (M_INFO, "%s", message);
 
-  /* Flag remote_list that we initialized */
-  if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0 && c->c1.remote_list && c->c1.remote_list->len > 1)
-    c->c1.remote_list->no_advance = true;
+  /* 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);
 
 #ifdef ENABLE_MANAGEMENT
   /* Tell management interface that we initialized */
@@ -1099,7 +1252,7 @@ do_deferred_options (struct context *c, const unsigned int found)
 #ifdef ENABLE_OCC
   if (found & OPT_P_EXPLICIT_NOTIFY)
     {
-      if (c->options.proto != PROTO_UDPv4 && c->options.explicit_exit_notification)
+      if (c->options.ce.proto != PROTO_UDPv4 && c->options.explicit_exit_notification)
        {
          msg (D_PUSH, "OPTIONS IMPORT: --explicit-exit-notify can only be used with --proto udp");
          c->options.explicit_exit_notification = 0;
@@ -1183,25 +1336,25 @@ socket_restart_pause (struct context *c)
   int sec = 2;
 
 #ifdef ENABLE_HTTP_PROXY
-  if (c->options.http_proxy_options)
+  if (c->options.ce.http_proxy_options)
     proxy = true;
 #endif
 #ifdef ENABLE_SOCKS
-  if (c->options.socks_proxy_server)
+  if (c->options.ce.socks_proxy_server)
     proxy = true;
 #endif
 
-  switch (c->options.proto)
+  switch (c->options.ce.proto)
     {
     case PROTO_UDPv4:
       if (proxy)
-       sec = c->options.connect_retry_seconds;
+       sec = c->options.ce.connect_retry_seconds;
       break;
     case PROTO_TCPv4_SERVER:
       sec = 1;
       break;
     case PROTO_TCPv4_CLIENT:
-      sec = c->options.connect_retry_seconds;
+      sec = c->options.ce.connect_retry_seconds;
       break;
     }
 
@@ -1537,7 +1690,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->proto == PROTO_TCPv4_SERVER)
+  if (to.server && options->ce.proto == PROTO_TCPv4_SERVER)
     to.xmit_hold = true;
 
 #ifdef ENABLE_OCC
@@ -1584,7 +1737,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
 
   /* If we are running over TCP, allow for
      length prefix */
-  socket_adjust_frame_parameters (&to.frame, options->proto);
+  socket_adjust_frame_parameters (&to.frame, options->ce.proto);
 
   /*
    * Initialize OpenVPN's master TLS-mode object.
@@ -1682,8 +1835,8 @@ do_init_frame (struct context *c)
   /*
    * Adjust frame size for UDP Socks support.
    */
-  if (c->options.socks_proxy_server)
-    socks_adjust_frame_parameters (&c->c2.frame, c->options.proto);
+  if (c->options.ce.socks_proxy_server)
+    socks_adjust_frame_parameters (&c->c2.frame, c->options.ce.proto);
 #endif
 
   /*
@@ -1697,7 +1850,7 @@ do_init_frame (struct context *c)
    * (Since TCP is a stream protocol, we need to insert
    * a packet length uint16_t in the buffer.)
    */
-  socket_adjust_frame_parameters (&c->c2.frame, c->options.proto);
+  socket_adjust_frame_parameters (&c->c2.frame, c->options.ce.proto);
 
   /*
    * Fill in the blanks in the frame parameters structure,
@@ -1739,7 +1892,7 @@ do_option_warnings (struct context *c)
   const struct options *o = &c->options;
 
 #if 1 /* JYFIXME -- port warning */
-  if (!o->port_option_used && (o->local_port == OPENVPN_PORT && o->remote_port == OPENVPN_PORT))
+  if (!o->ce.port_option_used && (o->ce.local_port == OPENVPN_PORT && o->ce.remote_port == OPENVPN_PORT))
     msg (M_WARN, "IMPORTANT: OpenVPN's default port number is now %d, based on an official port number assignment by IANA.  OpenVPN 2.0-beta16 and earlier used 5000 as the default port.",
         OPENVPN_PORT);
 #endif
@@ -1793,7 +1946,7 @@ do_option_warnings (struct context *c)
 #endif
 
 #ifndef CONNECT_NONBLOCK
-  if (o->connect_timeout_defined)
+  if (o->ce.connect_timeout_defined)
     msg (M_WARN, "NOTE: --connect-timeout option is not supported on this OS");
 #endif
 }
@@ -1918,10 +2071,12 @@ do_init_socket_1 (struct context *c, const int mode)
 #endif
 
   link_socket_init_phase1 (c->c2.link_socket,
-                          c->options.local,
-                          c->c1.remote_list,
-                          c->options.local_port,
-                          c->options.proto,
+                          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,
                           mode,
                           c->c2.accept_from,
 #ifdef ENABLE_HTTP_PROXY
@@ -1933,16 +2088,16 @@ do_init_socket_1 (struct context *c, const int mode)
 #ifdef ENABLE_DEBUG
                           c->options.gremlin,
 #endif
-                          c->options.bind_local,
-                          c->options.remote_float,
+                          c->options.ce.bind_local,
+                          c->options.ce.remote_float,
                           c->options.inetd,
                           &c->c1.link_socket_addr,
                           c->options.ipchange,
                           c->plugins,
                           c->options.resolve_retry_seconds,
-                          c->options.connect_retry_seconds,
-                          c->options.connect_timeout,
-                          c->options.connect_retry_max,
+                          c->options.ce.connect_retry_seconds,
+                          c->options.ce.connect_timeout,
+                          c->options.ce.connect_retry_max,
                           c->options.mtu_discover_type,
                           c->options.rcvbuf,
                           c->options.sndbuf,
@@ -2302,7 +2457,7 @@ do_setup_fast_io (struct context *c)
 #ifdef WIN32
       msg (M_INFO, "NOTE: --fast-io is disabled since we are running on Windows");
 #else
-      if (c->options.proto != PROTO_UDPv4)
+      if (c->options.ce.proto != PROTO_UDPv4)
        msg (M_INFO, "NOTE: --fast-io is disabled since we are not using UDP");
       else
        {
@@ -2556,10 +2711,13 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
   c->sig->signal_text = NULL;
   c->sig->hard = false;
 
+  /* map in current connection entry */
+  next_connection_entry (c);
+
   /* link_socket_mode allows CM_CHILD_TCP
      instances to inherit acceptable fds
      from a top-level parent */
-  if (c->options.proto == PROTO_TCPv4_SERVER)
+  if (c->options.ce.proto == PROTO_TCPv4_SERVER)
     {
       if (c->mode == CM_TOP)
        link_socket_mode = LS_MODE_TCP_LISTEN;
@@ -2633,6 +2791,9 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
   else if (c->mode == CM_CHILD_TCP)
     do_event_set_init (c, false);
 
+  /* initialize HTTP or SOCKS proxy object at scope level 2 */
+  init_proxy (c, 2);
+
   /* allocate our socket object */
   if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP)
     do_link_socket_new (c);
@@ -2825,6 +2986,9 @@ close_instance (struct context *c)
        /* free up environmental variable store */
        do_env_set_destroy (c);
 
+       /* close HTTP or SOCKS proxy */
+       uninit_proxy (c);
+
        /* garbage collect */
        gc_free (&c->c2.gc);
       }
@@ -2836,7 +3000,7 @@ inherit_context_child (struct context *dest,
 {
   CLEAR (*dest);
 
-  switch (src->options.proto)
+  switch (src->options.ce.proto)
     {
     case PROTO_UDPv4:
       dest->mode = CM_CHILD_UDP;
@@ -2952,7 +3116,7 @@ inherit_context_top (struct context *dest,
   dest->c2.es_owned = false;
 
   dest->c2.event_set = NULL;
-  if (src->options.proto == PROTO_UDPv4)
+  if (src->options.ce.proto == PROTO_UDPv4)
     do_event_set_init (dest, false);
 }
 
diff --git a/misc.c b/misc.c
index 5f0ec12e00eb7a98b6c0afde28a42a69494ff056..0ac1250de9030ac3402178c3b6718813c7a7a539 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -940,6 +940,7 @@ setenv_str_ex (struct env_set *es,
        {
          const char *str = construct_name_value (name_tmp, val_tmp, &gc);
          env_set_add (es, str);
+         /*msg (M_INFO, "SETENV_ES '%s'", str);*/
        }
       else
        env_set_del (es, name_tmp);
@@ -974,6 +975,38 @@ setenv_str_ex (struct env_set *es,
   gc_free (&gc);
 }
 
+/*
+ * Setenv functions that append an integer index to the name
+ */
+static const char *
+setenv_format_indexed_name (const char *name, const int i, struct gc_arena *gc)
+{
+  struct buffer out = alloc_buf_gc (strlen (name) + 16, gc);
+  if (i >= 0)
+    buf_printf (&out, "%s_%d", name, i);
+  else
+    buf_printf (&out, "%s", name);
+  return BSTR (&out);
+}
+
+void
+setenv_int_i (struct env_set *es, const char *name, const int value, const int i)
+{
+  struct gc_arena gc = gc_new ();
+  const char *name_str = setenv_format_indexed_name (name, i, &gc);
+  setenv_int (es, name_str, value);
+  gc_free (&gc);
+}
+
+void
+setenv_str_i (struct env_set *es, const char *name, const char *value, const int i)
+{
+  struct gc_arena gc = gc_new ();
+  const char *name_str = setenv_format_indexed_name (name, i, &gc);
+  setenv_str (es, name_str, value);
+  gc_free (&gc);
+}
+
 /*
  * taken from busybox networking/ifupdown.c
  */
diff --git a/misc.h b/misc.h
index 3ee0e2799cb9b8bf82c5738fb51ace0a429f1a4e..634180cdfcb9f5e2c17b16ea7ce6bc09436e00a5 100644 (file)
--- a/misc.h
+++ b/misc.h
@@ -165,6 +165,9 @@ void setenv_str (struct env_set *es, const char *name, const char *value);
 void setenv_str_safe (struct env_set *es, const char *name, const char *value);
 void setenv_del (struct env_set *es, const char *name);
 
+void setenv_int_i (struct env_set *es, const char *name, const int value, const int i);
+void setenv_str_i (struct env_set *es, const char *name, const char *value, const int i);
+
 /* struct env_set functions */
 
 struct env_set *env_set_create (struct gc_arena *gc);
diff --git a/multi.c b/multi.c
index bc3500f887add019ab32a63ec0c25e5575bff36e..3c099940dddc8a47d8c162addbaed42b3e55647e 100644 (file)
--- a/multi.c
+++ b/multi.c
@@ -2619,7 +2619,7 @@ tunnel_server (struct context *top)
 {
   ASSERT (top->options.mode == MODE_SERVER);
 
-  switch (top->options.proto) {
+  switch (top->options.ce.proto) {
   case PROTO_UDPv4:
     tunnel_server_udp (top);
     break;
diff --git a/occ.c b/occ.c
index 1add9d0f07c1904302fdef6a2bdd595761a15210..86bc68c295332eb255b9782e0f94e4bdc1e37c73 100644 (file)
--- a/occ.c
+++ b/occ.c
@@ -149,7 +149,7 @@ check_send_occ_req_dowork (struct context *c)
 {
   if (++c->c2.occ_n_tries >= OCC_N_TRIES)
     {
-      if (c->options.remote_list)
+      if (c->options.ce.remote)
        /*
         * No OCC_REPLY from peer after repeated attempts.
         * Give up.
@@ -369,7 +369,7 @@ process_received_occ_msg (struct context *c)
               c->c2.max_send_size_remote,
               c->c2.max_recv_size_local);
          if (!c->options.fragment
-             && c->options.proto == PROTO_UDPv4
+             && c->options.ce.proto == PROTO_UDPv4
              && c->c2.max_send_size_local > TUN_MTU_MIN
              && (c->c2.max_recv_size_remote < c->c2.max_send_size_local
                  || c->c2.max_recv_size_local < c->c2.max_send_size_remote))
index 69d8f8f3dc6dada826c62d2deb9c7a16f7b365ef..6e261f76d8a1e7bd748b871131da0f6694a83835 100644 (file)
--- a/openvpn.8
+++ b/openvpn.8
@@ -466,11 +466,16 @@ If specified, OpenVPN will bind to this address only.
 If unspecified, OpenVPN will bind to all interfaces.
 .\"*********************************************************
 .TP
-.B --remote host [port]
+.B --remote host [port] [proto]
 Remote host name or IP address.  On the client, multiple
 .B --remote
 options may be specified for redundancy, each referring
-to a different OpenVPN server.
+to a different OpenVPN server.  Specifying multiple
+.B --remote
+options for this purpose is a special case of the more
+general connection-profile feature.  See the
+.B <connection>
+documentation below.
 
 The OpenVPN client will try to connect to a server at
 .B host:port
@@ -478,6 +483,10 @@ in the order specified by the list of
 .B --remote
 options.
 
+.B proto
+indicates the protocol to use when connecting with the
+remote, and may be "tcp" or "udp".
+
 The client will move on to the next host in the list,
 in the event of connection failure.
 Note that at any given time, the OpenVPN client
@@ -525,12 +534,126 @@ is a DNS name which resolves to multiple IP addresses,
 one will be randomly
 chosen, providing a sort of basic load-balancing and
 failover capability.
+.\"*********************************************************
+.TP
+.B <connection>
+Define a client connection
+profile.  Client connection profiles are groups of OpenVPN options that
+describe how to connect to a given OpenVPN server.  Client connection
+profiles are specified within an OpenVPN configuration file, and
+each profile is bracketed by
+.B <connection>
+and
+.B </connection>.
+
+An OpenVPN client will try each connection profile sequentially
+until it achieves a successful connection.  
+
+.B --remote-random
+can be used to initially "scramble" the connection
+list.
+
+Here is an example of connection profile usage:
+
+.RS
+.ft 3
+.nf
+.sp
+client
+dev tun
+
+<connection>
+remote 198.19.34.56 1194 udp
+</connection>
+
+<connection>
+remote 198.19.34.56 443 tcp
+</connection>
+
+<connection>
+remote 198.19.34.56 443 tcp
+http-proxy 192.168.0.8 8080
+http-proxy-retry
+</connection>
+
+<connection>
+remote 198.19.36.99 443 tcp
+http-proxy 192.168.0.8 8080
+http-proxy-retry
+</connection>
+
+persist-key
+persist-tun
+pkcs12 client.p12
+ns-cert-type server
+verb 3
+.ft
+.LP
+.RE
+.fi
+
+First we try to connect to a server at 198.19.34.56:1194 using UDP.
+If that fails, we then try to connect to 198.19.34.56:443 using TCP.
+If that also fails, then try connecting through an HTTP proxy at 
+192.168.0.8:8080 to 198.19.34.56:443 using TCP.  Finally, try to
+connect through the same proxy to a server at 198.19.36.99:443
+using TCP.
+
+The following OpenVPN options may be used inside of
+a
+.B <connection>
+block:
+
+.B bind,
+.B connect-retry,
+.B connect-retry-max,
+.B connect-timeout,
+.B float,
+.B http-proxy,
+.B http-proxy-option,
+.B http-proxy-retry,
+.B http-proxy-timeout,
+.B local,
+.B lport,
+.B nobind,
+.B port,
+.B proto,
+.B remote,
+.B rport,
+.B socks-proxy, and
+.B socks-proxy-retry.
+
+A defaulting mechanism exists for specifying options to apply to
+all
+.B <connection>
+profiles.  If any of the above options (with the exception of
+.B remote
+) appear outside of a
+.B <connection>
+block, but in a configuration file which has one or more
+.B <connection>
+blocks, the option setting will be used as a default for
+.B <connection>
+blocks which follow it in the configuration file.
+
+For example, suppose the
+.B nobind
+option were placed in the sample configuration file above, near
+the top of the file, before the first
+.B <connection>
+block.  The effect would be as if
+.B nobind
+were declared in all
+.B <connection>
+blocks below it.
+
 .\"*********************************************************
 .TP
 .B --remote-random
 When multiple
 .B --remote
-address/ports are specified, initially randomize the order of the list
+address/ports are specified, or if connection profiles are being
+used, initially randomize the order of the list
 as a kind of basic load-balancing measure.
 .\"*********************************************************
 .TP
index f1bf16909aa95bbd971c777cbdf85b54a65af20d..5e87fee0474bab78a06a5e799c83d81f018647c9 100644 (file)
--- a/openvpn.c
+++ b/openvpn.c
@@ -138,7 +138,7 @@ main (int argc, char *argv[])
 #endif
 
          /* initialize options to default state */
-         init_options (&c.options);
+         init_options (&c.options, true);
 
          /* parse command line options, and read configuration file */
          parse_argv (&c.options, argc, argv, M_USAGE, OPT_P_DEFAULT, NULL, c.es);
@@ -169,7 +169,7 @@ main (int argc, char *argv[])
            break;
 
          /* sanity check on options */
-         options_postprocess (&c.options, c.first_time);
+         options_postprocess (&c.options);
 
          /* show all option settings */
          show_settings (&c.options);
index 1ffc44c8a569c392d66e37b77fca3fe761b64d90..258bb1561084d9dde984229ce1348e7727073e00 100644 (file)
--- a/openvpn.h
+++ b/openvpn.h
@@ -158,9 +158,6 @@ struct context_1
   /* persist crypto sequence number to/from file */
   struct packet_id_persist pid_persist;
 
-  /* array of remote addresses */
-  struct remote_list *remote_list;
-
   /* TUN/TAP interface */
   struct tuntap *tuntap;
   bool tuntap_owned;
@@ -175,11 +172,13 @@ struct context_1
 #ifdef ENABLE_HTTP_PROXY
   /* HTTP proxy object */
   struct http_proxy_info *http_proxy;
+  bool http_proxy_owned;
 #endif
 
 #ifdef ENABLE_SOCKS
   /* SOCKS proxy object */
   struct socks_proxy_info *socks_proxy;
+  bool socks_proxy_owned;
 #endif
 
 #if P2MP
index 5328efbe4f294fb5f0cd8f52f7cb3e7e75e15d8e..f9252edc2a402eb54c01300da7434a6fa68fc534 100644 (file)
--- a/options.c
+++ b/options.c
@@ -619,21 +619,25 @@ static const char usage_message[] =
  * will be set to 0.
  */
 void
-init_options (struct options *o)
+init_options (struct options *o, const bool init_gc)
 {
   CLEAR (*o);
-  gc_init (&o->gc);
+  if (init_gc)
+    {
+      gc_init (&o->gc);
+      o->gc_owned = true;
+    }
   o->mode = MODE_POINT_TO_POINT;
   o->topology = TOP_NET30;
-  o->proto = PROTO_UDPv4;
-  o->connect_retry_seconds = 5;
-  o->connect_timeout = 10;
-  o->connect_retry_max = 0;
-  o->local_port = o->remote_port = OPENVPN_PORT;
+  o->ce.proto = PROTO_UDPv4;
+  o->ce.connect_retry_seconds = 5;
+  o->ce.connect_timeout = 10;
+  o->ce.connect_retry_max = 0;
+  o->ce.local_port = o->ce.remote_port = OPENVPN_PORT;
   o->verbosity = 1;
   o->status_file_update_freq = 60;
   o->status_file_version = 1;
-  o->bind_local = true;
+  o->ce.bind_local = true;
   o->tun_mtu = TUN_MTU_DEFAULT;
   o->link_mtu = LINK_MTU_DEFAULT;
   o->mtu_discover_type = -1;
@@ -709,7 +713,8 @@ init_options (struct options *o)
 void
 uninit_options (struct options *o)
 {
-  gc_free (&o->gc);
+  if (o->gc_owned)
+    gc_free (&o->gc);
 }
 
 #ifdef ENABLE_DEBUG
@@ -723,47 +728,51 @@ uninit_options (struct options *o)
 
 #endif
 
+void
+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, "local", e->local, i);
+  setenv_int_i (es, "local_port", e->local_port, i);
+  setenv_str_i (es, "remote", e->local, i);
+  setenv_int_i (es, "remote_port", e->local_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);
+    }
+#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);
+    }
+#endif
+}
+
 void
 setenv_settings (struct env_set *es, const struct options *o)
 {
   setenv_str (es, "config", o->config);
-  setenv_str (es, "proto", proto2ascii (o->proto, false));
-  setenv_str (es, "local", o->local);
-  setenv_int (es, "local_port", o->local_port);
   setenv_int (es, "verb", o->verbosity);
   setenv_int (es, "daemon", o->daemon);
   setenv_int (es, "daemon_log_redirect", o->log);
 
-  if (o->remote_list)
+#ifdef ENABLE_CONNECTION
+  if (o->connection_list)
     {
       int i;
-
-      for (i = 0; i < o->remote_list->len; ++i)
-       {
-         char remote_string[64];
-         char remote_port_string[64];
-
-         openvpn_snprintf (remote_string, sizeof (remote_string), "remote_%d", i+1);
-         openvpn_snprintf (remote_port_string, sizeof (remote_port_string), "remote_port_%d", i+1);
-
-         setenv_str (es, remote_string,      o->remote_list->array[i].hostname);
-         setenv_int (es, remote_port_string, o->remote_list->array[i].port);
-       }
+      for (i = 0; i < o->connection_list->len; ++i)
+       setenv_connection_entry (es, o->connection_list->array[i], i+1);
     }
-#ifdef ENABLE_HTTP_PROXY
-    if (o->http_proxy_options)
-      {
-        setenv_str (es, "http_proxy_server", o->http_proxy_options->server);
-        setenv_int (es, "http_proxy_port", o->http_proxy_options->port);
-      }
-#endif
-#ifdef ENABLE_SOCKS
-    if(o->socks_proxy_server)
-      {
-        setenv_str (es, "socks_proxy_server", o->socks_proxy_server);
-        setenv_int (es, "socks_proxy_port", o->socks_proxy_port);
-      }
+  else
 #endif
+    setenv_connection_entry (es, &o->ce, 1);
 }
 
 static in_addr_t
@@ -816,7 +825,7 @@ is_persist_option (const struct options *o)
 bool
 is_stateful_restart (const struct options *o)
 {
-  return is_persist_option (o) || (o->remote_list && o->remote_list->len > 1);
+  return is_persist_option (o) || connection_list_defined (o);
 }
 
 #ifdef WIN32
@@ -983,26 +992,6 @@ option_iroute (struct options *o,
 #endif /* P2MP_SERVER */
 #endif /* P2MP */
 
-#ifdef ENABLE_DEBUG
-static void
-show_remote_list (const struct remote_list *l)
-{
-  if (l)
-    {
-      int i;
-      for (i = 0; i < l->len; ++i)
-       {
-         msg (D_SHOW_PARMS, "  remote_list[%d] = {'%s', %d}",
-              i, l->array[i].hostname, l->array[i].port);
-       }
-    }
-  else
-    {
-      msg (D_SHOW_PARMS, "  remote_list = NULL");
-    }
-}
-#endif
-
 #if defined(ENABLE_HTTP_PROXY) && defined(ENABLE_DEBUG)
 static void
 show_http_proxy_options (const struct http_proxy_options *o)
@@ -1042,6 +1031,55 @@ rol_check_alloc (struct options *options)
     options->routes = new_route_option_list (&options->gc);
 }
 
+#ifdef ENABLE_DEBUG
+static void
+show_connection_entry (const struct connection_entry *o)
+{
+  msg (D_SHOW_PARMS, "  proto = %s", proto2ascii (o->proto, false));
+  SHOW_STR (local);
+  SHOW_INT (local_port);
+  SHOW_STR (remote);
+  SHOW_INT (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)
+    show_http_proxy_options (o->http_proxy_options);
+#endif
+#ifdef ENABLE_SOCKS
+  SHOW_STR (socks_proxy_server);
+  SHOW_INT (socks_proxy_port);
+  SHOW_BOOL (socks_proxy_retry);
+#endif
+}
+
+static void
+show_connection_entries (const struct options *o)
+{
+  msg (D_SHOW_PARMS, "Connection profiles [default]:");
+  show_connection_entry (&o->ce);
+#ifdef ENABLE_CONNECTION
+ if (o->connection_list)
+   {
+     const struct connection_list *l = o->connection_list;
+     int i;
+     for (i = 0; i < l->len; ++i)
+       {
+        msg (D_SHOW_PARMS, "Connection profiles [%d]:", i);
+        show_connection_entry (l->array[i]);
+       }
+   }
+#endif
+  msg (D_SHOW_PARMS, "Connection profiles END");
+}
+
+#endif
+
 void
 show_settings (const struct options *o)
 {
@@ -1068,17 +1106,11 @@ show_settings (const struct options *o)
 #endif
 #endif
 
-  SHOW_INT (proto);
-  SHOW_STR (local);
-  show_remote_list (o->remote_list);
+  show_connection_entries (o);
+
   SHOW_BOOL (remote_random);
 
-  SHOW_INT (local_port);
-  SHOW_INT (remote_port);
-  SHOW_BOOL (remote_float);
   SHOW_STR (ipchange);
-  SHOW_BOOL (bind_defined);
-  SHOW_BOOL (bind_local);
   SHOW_STR (dev);
   SHOW_STR (dev_type);
   SHOW_STR (dev_node);
@@ -1135,9 +1167,6 @@ show_settings (const struct options *o)
 #endif
 
   SHOW_INT (resolve_retry_seconds);
-  SHOW_INT (connect_retry_seconds);
-  SHOW_INT (connect_timeout);
-  SHOW_INT (connect_retry_max);
 
   SHOW_STR (username);
   SHOW_STR (groupname);
@@ -1170,17 +1199,6 @@ show_settings (const struct options *o)
   SHOW_INT (sndbuf);
   SHOW_INT (sockflags);
 
-#ifdef ENABLE_HTTP_PROXY
-  if (o->http_proxy_options)
-    show_http_proxy_options (o->http_proxy_options);
-#endif
-
-#ifdef ENABLE_SOCKS
-  SHOW_STR (socks_proxy_server);
-  SHOW_INT (socks_proxy_port);
-  SHOW_BOOL (socks_proxy_retry);
-#endif
-
   SHOW_BOOL (fast_io);
 
 #ifdef USE_LZO
@@ -1318,32 +1336,89 @@ show_settings (const struct options *o)
 struct http_proxy_options *
 init_http_options_if_undefined (struct options *o)
 {
-  if (!o->http_proxy_options)
+  if (!o->ce.http_proxy_options)
     {
-      ALLOC_OBJ_CLEAR_GC (o->http_proxy_options, struct http_proxy_options, &o->gc);
+      ALLOC_OBJ_CLEAR_GC (o->ce.http_proxy_options, struct http_proxy_options, &o->gc);
       /* http proxy defaults */
-      o->http_proxy_options->timeout = 5;
-      o->http_proxy_options->http_version = "1.0";
+      o->ce.http_proxy_options->timeout = 5;
+      o->ce.http_proxy_options->http_version = "1.0";
     }
-  return o->http_proxy_options;
+  return o->ce.http_proxy_options;
+}
+
+#endif
+
+#if ENABLE_CONNECTION
+
+static struct connection_list *
+alloc_connection_list_if_undef (struct options *options)
+{
+  if (!options->connection_list)
+    ALLOC_OBJ_CLEAR_GC (options->connection_list, struct connection_list, &options->gc);
+  return options->connection_list;
+}
+
+static struct connection_entry *
+alloc_connection_entry (struct options *options, const int msglevel)
+{
+  struct connection_list *l = alloc_connection_list_if_undef (options);
+  struct connection_entry *e;
+
+  if (l->len >= CONNECTION_LIST_SIZE)
+    {
+      msg (msglevel, "Maximum number of 'connection' options (%d) exceeded", CONNECTION_LIST_SIZE);
+      return NULL;
+    }
+  ALLOC_OBJ_GC (e, struct connection_entry, &options->gc);
+  l->array[l->len++] = e;
+  return e;
+}
+
+static struct remote_list *
+alloc_remote_list_if_undef (struct options *options)
+{
+  if (!options->remote_list)
+    ALLOC_OBJ_CLEAR_GC (options->remote_list, struct remote_list, &options->gc);
+  return options->remote_list;
+}
+
+static struct remote_entry *
+alloc_remote_entry (struct options *options, const int msglevel)
+{
+  struct remote_list *l = alloc_remote_list_if_undef (options);
+  struct remote_entry *e;
+
+  if (l->len >= CONNECTION_LIST_SIZE)
+    {
+      msg (msglevel, "Maximum number of 'remote' options (%d) exceeded", CONNECTION_LIST_SIZE);
+      return NULL;
+    }
+  ALLOC_OBJ_GC (e, struct remote_entry, &options->gc);
+  l->array[l->len++] = e;
+  return e;
 }
 
 #endif
 
-/*
- * Sanity check on options.
- * Also set some options based on other
- * options.
- */
 void
-options_postprocess (struct options *options, bool first_time)
+connection_entry_load_re (struct connection_entry *ce, const struct remote_entry *re)
+{
+  if (re->remote)
+    ce->remote = re->remote;
+  if (re->remote_port >= 0)
+    ce->remote_port = re->remote_port;
+  if (re->proto >= 0)
+    ce->proto = re->proto;
+}
+
+static void
+options_postprocess_verify_ce (const struct options *options, const struct connection_entry *ce)
 {
   struct options defaults;
   int dev = DEV_TYPE_UNDEF;
-  int i;
   bool pull = false;
 
-  init_options (&defaults);
+  init_options (&defaults, true);
 
 #ifdef USE_CRYPTO
   if (options->test_crypto)
@@ -1360,31 +1435,11 @@ options_postprocess (struct options *options, bool first_time)
   dev = dev_type_enum (options->dev, options->dev_type);
 
   /*
-   * Fill in default port number for --remote list
-   */
-  if (options->remote_list)
-    {
-      for (i = 0; i < options->remote_list->len; ++i)
-       {
-         struct remote_entry *e = &options->remote_list->array[i];
-         if (e->port < 0)
-           e->port = options->remote_port;
-       }
-    }
-
-  /*
-   * If --mssfix is supplied without a parameter, default
-   * it to --fragment value, if --fragment is specified.
+   * If "proto tcp" is specified, make sure we know whether it is
+   * tcp-client or tcp-server.
    */
-  if (options->mssfix_default)
-    {
-#ifdef ENABLE_FRAGMENT
-      if (options->fragment)
-       options->mssfix = options->fragment;
-#else
-      msg (M_USAGE, "--mssfix must specify a parameter");
-#endif      
-    }
+  if (ce->proto == PROTO_TCPv4)
+    msg (M_USAGE, "--proto tcp is ambiguous in this context.  Please specify --proto tcp-server or --proto tcp-client");
 
   /*
    * Sanity check on daemon/inetd modes
@@ -1393,13 +1448,13 @@ options_postprocess (struct options *options, bool first_time)
   if (options->daemon && options->inetd)
     msg (M_USAGE, "only one of --daemon or --inetd may be specified");
 
-  if (options->inetd && (options->local || options->remote_list))
+  if (options->inetd && (ce->local || ce->remote))
     msg (M_USAGE, "--local or --remote cannot be used with --inetd");
 
-  if (options->inetd && options->proto == PROTO_TCPv4_CLIENT)
+  if (options->inetd && ce->proto == PROTO_TCPv4_CLIENT)
     msg (M_USAGE, "--proto tcp-client cannot be used with --inetd");
 
-  if (options->inetd == INETD_NOWAIT && options->proto != PROTO_TCPv4_SERVER)
+  if (options->inetd == INETD_NOWAIT && ce->proto != PROTO_TCPv4_SERVER)
     msg (M_USAGE, "--inetd nowait can only be used with --proto tcp-server");
 
   if (options->inetd == INETD_NOWAIT
@@ -1416,21 +1471,14 @@ options_postprocess (struct options *options, bool first_time)
   if (options->lladdr && dev != DEV_TYPE_TAP)
     msg (M_USAGE, "--lladdr can only be used in --dev tap mode");
  
-  /*
-   * In forking TCP server mode, you don't need to ifconfig
-   * the tap device (the assumption is that it will be bridged).
-   */
-  if (options->inetd == INETD_NOWAIT)
-    options->ifconfig_noexec = true;
-
   /*
    * Sanity check on TCP mode options
    */
 
-  if (options->connect_retry_defined && options->proto != PROTO_TCPv4_CLIENT)
+  if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT)
     msg (M_USAGE, "--connect-retry doesn't make sense unless also used with --proto tcp-client");
 
-  if (options->connect_timeout_defined && options->proto != PROTO_TCPv4_CLIENT)
+  if (ce->connect_timeout_defined && ce->proto != PROTO_TCPv4_CLIENT)
     msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with --proto tcp-client");
 
   /*
@@ -1440,32 +1488,10 @@ options_postprocess (struct options *options, bool first_time)
     msg (M_USAGE, "only one of --tun-mtu or --link-mtu may be defined (note that --ifconfig implies --link-mtu %d)", LINK_MTU_DEFAULT);
 
 #ifdef ENABLE_OCC
-  if (options->proto != PROTO_UDPv4 && options->mtu_test)
+  if (ce->proto != PROTO_UDPv4 && options->mtu_test)
     msg (M_USAGE, "--mtu-test only makes sense with --proto udp");
 #endif
 
-  /*
-   * Set MTU defaults
-   */
-  {
-    if (!options->tun_mtu_defined && !options->link_mtu_defined)
-      {
-       options->tun_mtu_defined = true;
-      }
-    if ((dev == DEV_TYPE_TAP) && !options->tun_mtu_extra_defined)
-      {
-       options->tun_mtu_extra_defined = true;
-       options->tun_mtu_extra = TAP_MTU_EXTRA_DEFAULT;
-      }
-  }
-
-  /*
-   * Process helper-type options which map to other, more complex
-   * sequences of options.
-   */
-  helper_client_server (options);
-  helper_keepalive (options);
-
   /* will we be pulling options from server? */
 #if P2MP
   pull = options->pull;
@@ -1475,56 +1501,33 @@ options_postprocess (struct options *options, bool first_time)
    * Sanity check on --local, --remote, and --ifconfig
    */
 
-  if (options->remote_list)
-    {
-      int i;
-      struct remote_list *l = options->remote_list;
-
-      for (i = 0; i < l->len; ++i)
-       {
-         const char *remote = l->array[i].hostname;
-         const int remote_port = l->array[i].port;
-
-         if (string_defined_equal (options->local, remote)
-             && options->local_port == remote_port)
-           msg (M_USAGE, "--remote and --local addresses are the same");
-       
-         if (string_defined_equal (remote, options->ifconfig_local)
-             || string_defined_equal (remote, options->ifconfig_remote_netmask))
-           msg (M_USAGE, "--local and --remote addresses must be distinct from --ifconfig addresses");
-       }
-    }
+  if (string_defined_equal (ce->local, ce->remote)
+      && 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)
+      || string_defined_equal (ce->remote, options->ifconfig_remote_netmask))
+    msg (M_USAGE, "--local and --remote addresses must be distinct from --ifconfig addresses");
 
-  if (string_defined_equal (options->local, options->ifconfig_local)
-      || string_defined_equal (options->local, options->ifconfig_remote_netmask))
+  if (string_defined_equal (ce->local, options->ifconfig_local)
+      || string_defined_equal (ce->local, options->ifconfig_remote_netmask))
     msg (M_USAGE, "--local addresses must be distinct from --ifconfig addresses");
 
   if (string_defined_equal (options->ifconfig_local, options->ifconfig_remote_netmask))
     msg (M_USAGE, "local and remote/netmask --ifconfig addresses must be different");
 
-  if (options->bind_defined && !options->bind_local)
+  if (ce->bind_defined && !ce->bind_local)
     msg (M_USAGE, "--bind and --nobind can't be used together");
 
-  if (options->local && !options->bind_local)
+  if (ce->local && !ce->bind_local)
     msg (M_USAGE, "--local and --nobind don't make sense when used together");
 
-  if (options->local_port_defined && !options->bind_local)
+  if (ce->local_port_defined && !ce->bind_local)
     msg (M_USAGE, "--lport and --nobind don't make sense when used together");
 
-  if (!options->remote_list && !options->bind_local)
+  if (!ce->remote && !ce->bind_local)
     msg (M_USAGE, "--nobind doesn't make sense unless used with --remote");
 
-  if (options->proto == PROTO_TCPv4_CLIENT && !options->local && !options->local_port_defined && !options->bind_defined)
-    options->bind_local = false;
-
-#ifdef ENABLE_SOCKS
-  if (options->proto == PROTO_UDPv4 && options->socks_proxy_server && !options->local && !options->local_port_defined && !options->bind_defined)
-    options->bind_local = false;
-#endif
-
-  if (!options->bind_local)
-    options->local_port = 0;
-
   /*
    * Check for consistency of management options
    */
@@ -1552,18 +1555,6 @@ options_postprocess (struct options *options, bool first_time)
          && options->tuntap_options.ip_win32_type != IPW32_SET_DHCP_MASQ
          && options->tuntap_options.ip_win32_type != IPW32_SET_ADAPTIVE)
        msg (M_USAGE, "--dhcp-options requires --ip-win32 dynamic or adaptive");
-
-      if ((dev == DEV_TYPE_TUN || dev == DEV_TYPE_TAP) && !options->route_delay_defined)
-       {
-         options->route_delay_defined = true;
-         options->route_delay = 5; /* Vista sometimes has a race without this */
-       }
-
-      if (options->ifconfig_noexec)
-       {
-         options->tuntap_options.ip_win32_type = IPW32_SET_MANUAL;
-         options->ifconfig_noexec = false;
-       }
 #endif
 
   /*
@@ -1571,34 +1562,34 @@ options_postprocess (struct options *options, bool first_time)
    */
 
 #ifdef ENABLE_FRAGMENT
-  if (options->proto != PROTO_UDPv4 && options->fragment)
+  if (ce->proto != PROTO_UDPv4 && options->fragment)
     msg (M_USAGE, "--fragment can only be used with --proto udp");
 #endif
 
 #ifdef ENABLE_OCC
-  if (options->proto != PROTO_UDPv4 && options->explicit_exit_notification)
+  if (ce->proto != PROTO_UDPv4 && options->explicit_exit_notification)
     msg (M_USAGE, "--explicit-exit-notify can only be used with --proto udp");
 #endif
 
-  if (!options->remote_list && options->proto == PROTO_TCPv4_CLIENT)
+  if (!ce->remote && ce->proto == PROTO_TCPv4_CLIENT)
     msg (M_USAGE, "--remote MUST be used in TCP Client mode");
 
 #ifdef ENABLE_HTTP_PROXY
-  if ((options->http_proxy_options || options->auto_proxy_info) && options->proto != PROTO_TCPv4_CLIENT)
+  if ((ce->http_proxy_options || options->auto_proxy_info) && ce->proto != PROTO_TCPv4_CLIENT)
     msg (M_USAGE, "--http-proxy or --auto-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)");
 #endif
 
 #if defined(ENABLE_HTTP_PROXY) && defined(ENABLE_SOCKS)
-  if (options->http_proxy_options && options->socks_proxy_server)
+  if (ce->http_proxy_options && ce->socks_proxy_server)
     msg (M_USAGE, "--http-proxy can not be used together with --socks-proxy");
 #endif
 
 #ifdef ENABLE_SOCKS
-  if (options->socks_proxy_server && options->proto == PROTO_TCPv4_SERVER)
+  if (ce->socks_proxy_server && ce->proto == PROTO_TCPv4_SERVER)
     msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode");
 #endif
 
-  if (options->proto == PROTO_TCPv4_SERVER && remote_list_len (options->remote_list) > 1)
+  if (ce->proto == PROTO_TCPv4_SERVER && connection_list_defined (options))
     msg (M_USAGE, "TCP server mode allows at most one --remote address");
 
 #if P2MP_SERVER
@@ -1608,40 +1599,33 @@ options_postprocess (struct options *options, bool first_time)
    */
   if (options->mode == MODE_SERVER)
     {
-#ifdef WIN32
-      /*
-       * We need to explicitly set --tap-sleep because
-       * we do not schedule event timers in the top-level context.
-       */
-      options->tuntap_options.tap_sleep = 10;
-      if (options->route_delay_defined && options->route_delay)
-       options->tuntap_options.tap_sleep = options->route_delay;       
-      options->route_delay_defined = false;
-#endif
-
       if (!(dev == DEV_TYPE_TUN || dev == DEV_TYPE_TAP))
        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 (!(options->proto == PROTO_UDPv4 || options->proto == PROTO_TCPv4_SERVER))
+      if (!(ce->proto == PROTO_UDPv4 || ce->proto == PROTO_TCPv4_SERVER))
        msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server");
 #if PORT_SHARE
-      if ((options->port_share_host || options->port_share_port) && options->proto != PROTO_TCPv4_SERVER)
+      if ((options->port_share_host || options->port_share_port) && ce->proto != PROTO_TCPv4_SERVER)
        msg (M_USAGE, "--port-share only works in TCP server mode (--proto tcp-server)");
 #endif
       if (!options->tls_server)
        msg (M_USAGE, "--mode server requires --tls-server");
-      if (options->remote_list)
+      if (ce->remote)
        msg (M_USAGE, "--remote cannot be used with --mode server");
-      if (!options->bind_local)
+      if (!ce->bind_local)
        msg (M_USAGE, "--nobind cannot be used with --mode server");
 #ifdef ENABLE_HTTP_PROXY
-      if (options->http_proxy_options)
+      if (ce->http_proxy_options)
        msg (M_USAGE, "--http-proxy cannot be used with --mode server");
 #endif
 #ifdef ENABLE_SOCKS
-      if (options->socks_proxy_server)
+      if (ce->socks_proxy_server)
        msg (M_USAGE, "--socks-proxy cannot be used with --mode server");
+#endif
+#ifdef ENABLE_CONNECTION
+      if (options->connection_list)
+       msg (M_USAGE, "<connection> cannot be used with --mode server");
 #endif
       if (options->tun_ipv6)
        msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server");
@@ -1651,9 +1635,9 @@ options_postprocess (struct options *options, bool first_time)
        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 (!(options->proto == PROTO_UDPv4 || options->proto == PROTO_TCPv4_SERVER))
+      if (!(ce->proto == PROTO_UDPv4 || ce->proto == PROTO_TCPv4_SERVER))
        msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server");
-      if (options->proto != PROTO_UDPv4 && (options->cf_max || options->cf_per))
+      if (ce->proto != PROTO_UDPv4 && (options->cf_max || options->cf_per))
        msg (M_USAGE, "--connect-freq only works with --mode server --proto udp.  Try --max-clients instead.");
       if (!(dev == DEV_TYPE_TAP || (dev == DEV_TYPE_TUN && options->topology == TOP_SUBNET)) && options->ifconfig_pool_netmask)
        msg (M_USAGE, "The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode");
@@ -1733,7 +1717,7 @@ options_postprocess (struct options *options, bool first_time)
   /*
    * Check consistency of replay options
    */
-  if ((options->proto != PROTO_UDPv4)
+  if ((ce->proto != PROTO_UDPv4)
       && (options->replay_window != defaults.replay_window
          || options->replay_time != defaults.replay_time))
     msg (M_USAGE, "--replay-window only makes sense with --proto udp");
@@ -1743,13 +1727,6 @@ options_postprocess (struct options *options, bool first_time)
          || options->replay_time != defaults.replay_time))
     msg (M_USAGE, "--replay-window doesn't make sense when replay protection is disabled with --no-replay");
 
-  /* 
-   * Don't use replay window for TCP mode (i.e. require that packets
-   * be strictly in sequence).
-   */
-  if (link_socket_proto_connection_oriented (options->proto))
-    options->replay_window = options->replay_time = 0;
-
   /*
    * SSL/TLS mode sanity checks.
    */
@@ -1887,30 +1864,211 @@ options_postprocess (struct options *options, bool first_time)
 #endif /* USE_SSL */
 
 #if P2MP
+  if (options->auth_user_pass_file && !options->pull)
+    msg (M_USAGE, "--auth-user-pass requires --pull");
+#endif
+
+  uninit_options (&defaults);
+}
+
+static void
+options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce)
+{
+#if P2MP_SERVER
+  if (o->server_defined || o->server_bridge_defined)
+    {
+      if (ce->proto == PROTO_TCPv4)
+       ce->proto = PROTO_TCPv4_SERVER;
+    }
+#endif
+#if P2MP
+  if (o->client)
+    {
+      if (ce->proto == PROTO_TCPv4)
+       ce->proto = PROTO_TCPv4_CLIENT;
+    }
+#endif
+
+  if (ce->proto == PROTO_TCPv4_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)
+    ce->bind_local = false;
+#endif
+
+  if (!ce->bind_local)
+    ce->local_port = 0;
+}
+
+static void
+options_postprocess_mutate_invariant (struct options *options)
+{
+  const int dev = dev_type_enum (options->dev, options->dev_type);
+
   /*
-   * In pull mode, we usually import --ping/--ping-restart parameters from
-   * the server.  However we should also set an initial default --ping-restart
-   * for the period of time before we pull the --ping-restart parameter
-   * from the server.
+   * If --mssfix is supplied without a parameter, default
+   * it to --fragment value, if --fragment is specified.
    */
-  if (options->pull
-      && options->ping_rec_timeout_action == PING_UNDEF
-      && options->proto == PROTO_UDPv4)
+  if (options->mssfix_default)
     {
-      options->ping_rec_timeout = PRE_PULL_INITIAL_PING_RESTART;
-      options->ping_rec_timeout_action = PING_RESTART;
+#ifdef ENABLE_FRAGMENT
+      if (options->fragment)
+       options->mssfix = options->fragment;
+#else
+      msg (M_USAGE, "--mssfix must specify a parameter");
+#endif      
     }
 
-  if (options->auth_user_pass_file && !options->pull)
-    msg (M_USAGE, "--auth-user-pass requires --pull");
+  /*
+   * In forking TCP server mode, you don't need to ifconfig
+   * the tap device (the assumption is that it will be bridged).
+   */
+  if (options->inetd == INETD_NOWAIT)
+    options->ifconfig_noexec = true;
 
+  /*
+   * Set MTU defaults
+   */
+  {
+    if (!options->tun_mtu_defined && !options->link_mtu_defined)
+      {
+       options->tun_mtu_defined = true;
+      }
+    if ((dev == DEV_TYPE_TAP) && !options->tun_mtu_extra_defined)
+      {
+       options->tun_mtu_extra_defined = true;
+       options->tun_mtu_extra = TAP_MTU_EXTRA_DEFAULT;
+      }
+  }
+
+#ifdef WIN32
+  if ((dev == DEV_TYPE_TUN || dev == DEV_TYPE_TAP) && !options->route_delay_defined)
+    {
+      if (options->mode == MODE_POINT_TO_POINT)
+       {
+         options->route_delay_defined = true;
+         options->route_delay = 5; /* Vista sometimes has a race without this */
+       }
+    }
+
+  if (options->ifconfig_noexec)
+    {
+      options->tuntap_options.ip_win32_type = IPW32_SET_MANUAL;
+      options->ifconfig_noexec = false;
+    }
+#endif
+
+#if P2MP_SERVER
+  /*
+   * Check consistency of --mode server options.
+   */
+  if (options->mode == MODE_SERVER)
+    {
+#ifdef WIN32
+      /*
+       * We need to explicitly set --tap-sleep because
+       * we do not schedule event timers in the top-level context.
+       */
+      options->tuntap_options.tap_sleep = 10;
+      if (options->route_delay_defined && options->route_delay)
+       options->tuntap_options.tap_sleep = options->route_delay;       
+      options->route_delay_defined = false;
+#endif
+    }
+#endif
+}
+
+static void
+options_postprocess_verify (const struct options *o)
+{
+#ifdef ENABLE_CONNECTION
+  if (o->connection_list)
+    {
+      int i;
+      for (i = 0; i < o->connection_list->len; ++i)
+       options_postprocess_verify_ce (o, o->connection_list->array[i]);
+    }
+  else
+#endif
+    options_postprocess_verify_ce (o, &o->ce);
+}
+
+static void
+options_postprocess_mutate (struct options *o)
+{
+  /*
+   * Process helper-type options which map to other, more complex
+   * sequences of options.
+   */
+  helper_client_server (o);
+  helper_keepalive (o);
+
+  options_postprocess_mutate_invariant (o);
+
+#ifdef ENABLE_CONNECTION
+  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).
+       */
+      if (o->remote_list->len > 1)
+       {
+         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 specfied */
+       {
+         connection_entry_load_re (&o->ce, o->remote_list->array[0]);
+       }
+      else
+       {
+         ASSERT (0);
+       }
+    }
+  if (o->connection_list)
+    {
+      int i;
+      for (i = 0; i < o->connection_list->len; ++i)
+       options_postprocess_mutate_ce (o, o->connection_list->array[i]);
+    }
+  else
+#endif
+    options_postprocess_mutate_ce (o, &o->ce);  
+
+#if P2MP
   /*
    * Save certain parms before modifying options via --pull
    */
-  pre_pull_save (options);
+  pre_pull_save (o);
 #endif
 }
 
+/*
+ * Sanity check on options.
+ * Also set some options based on other
+ * options.
+ */
+void
+options_postprocess (struct options *options)
+{
+  options_postprocess_mutate (options);
+  options_postprocess_verify (options);
+}
+
 #if P2MP
 
 /*
@@ -2023,7 +2181,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->proto, remote), true));
+  buf_printf (&out, ",proto %s", proto2ascii (proto_remote (o->ce.proto, remote), true));
   if (o->tun_ipv6)
     buf_printf (&out, ",tun-ipv6");
 
@@ -2451,13 +2609,13 @@ usage (void)
 #else
 
   struct options o;
-  init_options (&o);
+  init_options (&o, true);
 
 #if defined(USE_CRYPTO) && defined(USE_SSL)
   fprintf (fp, usage_message,
           title_string,
-          o.connect_retry_seconds,
-          o.local_port, o.remote_port,
+          o.ce.connect_retry_seconds,
+          o.ce.local_port, o.ce.remote_port,
           TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT,
           o.verbosity,
           o.authname, o.ciphername,
@@ -2467,8 +2625,8 @@ usage (void)
 #elif defined(USE_CRYPTO)
   fprintf (fp, usage_message,
           title_string,
-          o.connect_retry_seconds,
-          o.local_port, o.remote_port,
+          o.ce.connect_retry_seconds,
+          o.ce.local_port, o.ce.remote_port,
           TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT,
           o.verbosity,
           o.authname, o.ciphername,
@@ -2476,8 +2634,8 @@ usage (void)
 #else
   fprintf (fp, usage_message,
           title_string,
-          o.connect_retry_seconds,
-          o.local_port, o.remote_port,
+          o.ce.connect_retry_seconds,
+          o.ce.local_port, o.ce.remote_port,
           TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT,
           o.verbosity);
 #endif
@@ -2857,14 +3015,14 @@ read_config_file (struct options *options,
 }
 
 static void
-read_config_string (struct options *options,
+read_config_string (const char *prefix,
+                   struct options *options,
                    const char *config,
                    const int msglevel,
                    const unsigned int permission_mask,
                    unsigned int *option_types_found,
                    struct env_set *es)
 {
-  const char *file = "[CONFIG-STRING]";
   char line[OPTION_LINE_SIZE];
   struct buffer multiline;
   int line_num = 0;
@@ -2876,7 +3034,7 @@ read_config_string (struct options *options,
       char *p[MAX_PARMS];
       CLEAR (p);
       ++line_num;
-      if (parse_line (line, p, SIZE (p), file, line_num, msglevel, &options->gc))
+      if (parse_line (line, p, SIZE (p), prefix, line_num, msglevel, &options->gc))
        {
          bypass_doubledash (&p[0]);
 #if ENABLE_INLINE_FILES
@@ -2997,7 +3155,7 @@ void options_string_import (struct options *options,
                            unsigned int *option_types_found,
                            struct env_set *es)
 {
-  read_config_string (options, config, msglevel, permission_mask, option_types_found, es);
+  read_config_string ("[CONFIG-STRING]", options, config, msglevel, permission_mask, option_types_found, es);
 }
 
 #if P2MP
@@ -3281,41 +3439,82 @@ add_option (struct options *options,
     }
   else if (streq (p[0], "local") && p[1])
     {
-      VERIFY_PERMISSION (OPT_P_GENERAL);
-      options->local = p[1];
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
+      options->ce.local = p[1];
     }
   else if (streq (p[0], "remote-random"))
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
       options->remote_random = true;
     }
-  else if (streq (p[0], "remote") && p[1])
+#if ENABLE_CONNECTION
+  else if (streq (p[0], "connection") && p[1])
     {
-      struct remote_list *l;
-      struct remote_entry e;
-
       VERIFY_PERMISSION (OPT_P_GENERAL);
-      if (!options->remote_list)
-       ALLOC_OBJ_CLEAR_GC (options->remote_list, struct remote_list, &options->gc);
-      l = options->remote_list;
-      if (l->len >= REMOTE_LIST_SIZE)
+      if (streq (p[1], INLINE_FILE_TAG) && p[2])
        {
-         msg (msglevel, "Maximum number of --remote options (%d) exceeded", REMOTE_LIST_SIZE);
-         goto err;
+         struct options sub;
+         struct connection_entry *e;
+
+         init_options (&sub, true);
+         sub.ce = options->ce;
+         read_config_string ("[CONNECTION-OPTIONS]", &sub, p[2], msglevel, OPT_P_CONNECTION, option_types_found, es);
+         if (!sub.ce.remote)
+           {
+             msg (msglevel, "Each 'connection' block must contain exactly one 'remote' directive");
+             goto err;
+           }
+
+         e = alloc_connection_entry (options, msglevel);
+         if (!e)
+           goto err;
+         *e = sub.ce;
+         gc_transfer (&options->gc, &sub.gc);
+         uninit_options (&sub);
        }
-      e.hostname = p[1];
+    }
+#endif
+  else if (streq (p[0], "remote") && p[1])
+    {
+      struct remote_entry re;
+      re.remote = NULL;
+      re.remote_port = re.proto = -1;
+
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
+      re.remote = p[1];
       if (p[2])
        {
-         e.port = atoi (p[2]);
-         if (!legal_ipv4_port (e.port))
+         const int port = atoi (p[2]);
+         if (!legal_ipv4_port (port))
            {
-             msg (msglevel, "port number associated with host %s is out of range", e.hostname);
+             msg (msglevel, "remote: port number associated with host %s is out of range", p[1]);
              goto err;
            }
+         re.remote_port = port;
+         if (p[3])
+           {
+             const int proto = ascii2proto (p[3]);
+             if (proto < 0)
+               {
+                 msg (msglevel, "remote: bad protocol associated with host %s: '%s'", p[1], p[3]);
+                 goto err;
+               }
+             re.proto = proto;
+           }
+       }
+#ifdef ENABLE_CONNECTION
+      if (permission_mask & OPT_P_GENERAL)
+       {
+         struct remote_entry *e = alloc_remote_entry (options, msglevel);
+         if (!e)
+           goto err;
+         *e = re;
+       }
+      else if (permission_mask & OPT_P_CONNECTION)
+#endif
+       {
+         connection_entry_load_re (&options->ce, &re);
        }
-      else
-       e.port = -1;
-      l->array[l->len++] = e;
     }
   else if (streq (p[0], "resolv-retry") && p[1])
     {
@@ -3327,20 +3526,20 @@ add_option (struct options *options,
     }
   else if (streq (p[0], "connect-retry") && p[1])
     {
-      VERIFY_PERMISSION (OPT_P_GENERAL);
-      options->connect_retry_seconds = positive_atoi (p[1]);
-      options->connect_retry_defined = true;
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
+      options->ce.connect_retry_seconds = positive_atoi (p[1]);
+      options->ce.connect_retry_defined = true;
     }
   else if (streq (p[0], "connect-timeout") && p[1])
     {
-      VERIFY_PERMISSION (OPT_P_GENERAL);
-      options->connect_timeout = positive_atoi (p[1]);
-      options->connect_timeout_defined = true;
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
+      options->ce.connect_timeout = positive_atoi (p[1]);
+      options->ce.connect_timeout_defined = true;
     }
   else if (streq (p[0], "connect-retry-max") && p[1])
     {
-      VERIFY_PERMISSION (OPT_P_GENERAL);
-      options->connect_retry_max = positive_atoi (p[1]);
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
+      options->ce.connect_retry_max = positive_atoi (p[1]);
     }
   else if (streq (p[0], "ipchange") && p[1])
     {
@@ -3351,8 +3550,8 @@ add_option (struct options *options,
     }
   else if (streq (p[0], "float"))
     {
-      VERIFY_PERMISSION (OPT_P_GENERAL);
-      options->remote_float = true;
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
+      options->ce.remote_float = true;
     }
 #ifdef ENABLE_DEBUG
   else if (streq (p[0], "gremlin") && p[1])
@@ -3687,54 +3886,54 @@ add_option (struct options *options,
     {
       int port;
 
-      VERIFY_PERMISSION (OPT_P_GENERAL);
+      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->port_option_used = true;
-      options->local_port = options->remote_port = port;
+      options->ce.port_option_used = true;
+      options->ce.local_port = options->ce.remote_port = port;
     }
   else if (streq (p[0], "lport") && p[1])
     {
       int port;
 
-      VERIFY_PERMISSION (OPT_P_GENERAL);
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
       port = atoi (p[1]);
       if (!legal_ipv4_port (port))
        {
          msg (msglevel, "Bad local port number: %s", p[1]);
          goto err;
        }
-      options->local_port_defined = true;
-      options->port_option_used = true;
-      options->local_port = port;
+      options->ce.local_port_defined = true;
+      options->ce.port_option_used = true;
+      options->ce.local_port = port;
     }
   else if (streq (p[0], "rport") && p[1])
     {
       int port;
 
-      VERIFY_PERMISSION (OPT_P_GENERAL);
+      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->port_option_used = true;
-      options->remote_port = port;
+      options->ce.port_option_used = true;
+      options->ce.remote_port = port;
     }
   else if (streq (p[0], "bind"))
     {
-      VERIFY_PERMISSION (OPT_P_GENERAL);
-      options->bind_defined = true;
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
+      options->ce.bind_defined = true;
     }
   else if (streq (p[0], "nobind"))
     {
-      VERIFY_PERMISSION (OPT_P_GENERAL);
-      options->bind_local = false;
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
+      options->ce.bind_local = false;
     }
   else if (streq (p[0], "fast-io"))
     {
@@ -3751,7 +3950,7 @@ add_option (struct options *options,
   else if (streq (p[0], "proto") && p[1])
     {
       int proto;
-      VERIFY_PERMISSION (OPT_P_GENERAL);
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
       proto = ascii2proto (p[1]);
       if (proto < 0)
        {
@@ -3760,7 +3959,7 @@ add_option (struct options *options,
               proto2ascii_all (&gc));
          goto err;
        }
-      options->proto = proto;
+      options->ce.proto = proto;
     }
 #ifdef GENERAL_PROXY_SUPPORT
   else if (streq (p[0], "auto-proxy"))
@@ -3799,7 +3998,7 @@ add_option (struct options *options,
     {
       struct http_proxy_options *ho;
 
-      VERIFY_PERMISSION (OPT_P_GENERAL);
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
 
       {
        int port;
@@ -3844,7 +4043,7 @@ add_option (struct options *options,
   else if (streq (p[0], "http-proxy-retry"))
     {
       struct http_proxy_options *ho;
-      VERIFY_PERMISSION (OPT_P_GENERAL);
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
       ho = init_http_options_if_undefined (options);
       ho->retry = true;
     }
@@ -3852,7 +4051,7 @@ add_option (struct options *options,
     {
       struct http_proxy_options *ho;
 
-      VERIFY_PERMISSION (OPT_P_GENERAL);
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
       ho = init_http_options_if_undefined (options);
       ho->timeout = positive_atoi (p[1]);
     }
@@ -3860,7 +4059,7 @@ add_option (struct options *options,
     {
       struct http_proxy_options *ho;
 
-      VERIFY_PERMISSION (OPT_P_GENERAL);
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
       ho = init_http_options_if_undefined (options);
 
       if (streq (p[1], "VERSION") && p[2])
@@ -3880,7 +4079,7 @@ add_option (struct options *options,
 #ifdef ENABLE_SOCKS
   else if (streq (p[0], "socks-proxy") && p[1])
     {
-      VERIFY_PERMISSION (OPT_P_GENERAL);
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
 
       if (p[2])
        {
@@ -3891,18 +4090,18 @@ add_option (struct options *options,
              msg (msglevel, "Bad socks-proxy port number: %s", p[2]);
              goto err;
            }
-          options->socks_proxy_port = port;
+          options->ce.socks_proxy_port = port;
        }
       else
        {
-         options->socks_proxy_port = 1080;
+         options->ce.socks_proxy_port = 1080;
        }
-      options->socks_proxy_server = p[1];
+      options->ce.socks_proxy_server = p[1];
     }
   else if (streq (p[0], "socks-proxy-retry"))
     {
-      VERIFY_PERMISSION (OPT_P_GENERAL);
-      options->socks_proxy_retry = true;
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
+      options->ce.socks_proxy_retry = true;
     }
 #endif
   else if (streq (p[0], "keepalive") && p[1] && p[2])
index 39f2ac682332317ed1af74b1e09ff23ecac37a9a..2bd7f263c9796f05e061d368dec8d5b2833fff35 100644 (file)
--- a/options.h
+++ b/options.h
@@ -82,10 +82,65 @@ struct options_pre_pull
 
 #endif
 
+struct connection_entry
+{
+  int proto;
+  int local_port;
+  bool local_port_defined;
+  int remote_port;
+  bool port_option_used;
+  const char *local;
+  const char *remote;
+  bool remote_float;
+  bool bind_defined;
+  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
+  struct http_proxy_options *http_proxy_options;
+#endif  
+#ifdef ENABLE_SOCKS
+  const char *socks_proxy_server;
+  int socks_proxy_port;
+  bool socks_proxy_retry;
+#endif
+};
+
+struct remote_entry
+{
+  const char *remote;
+  int remote_port;
+  int proto;
+};
+
+#ifdef ENABLE_CONNECTION
+
+#define CONNECTION_LIST_SIZE 64
+
+struct connection_list
+{
+  int len;
+  int current;
+  bool no_advance;
+  struct connection_entry *array[CONNECTION_LIST_SIZE];
+};
+
+struct remote_list
+{
+  int len;
+  struct remote_entry *array[CONNECTION_LIST_SIZE];
+};
+
+#endif
+
 /* Command line options */
 struct options
 {
   struct gc_arena gc;
+  bool gc_owned;
 
   /* first config file */
   const char *config;
@@ -111,17 +166,19 @@ struct options
 #endif
 
   /* Networking parms */
-  const char *local;
-  int local_port;
-  bool local_port_defined;
-  int remote_port;
-  bool port_option_used;
-  bool remote_float;
+  struct connection_entry ce;
+
+#ifdef ENABLE_CONNECTION
+  struct connection_list *connection_list;
   struct remote_list *remote_list;
+#endif
+
+#ifdef GENERAL_PROXY_SUPPORT
+  struct auto_proxy_info *auto_proxy_info;
+#endif
+
   bool remote_random;
   const char *ipchange;
-  bool bind_defined;
-  bool bind_local;
   const char *dev;
   const char *dev_type;
   const char *dev_node;
@@ -141,14 +198,6 @@ struct options
   bool tun_mtu_defined;  /* true if user overriding parm with command line option */
   bool link_mtu_defined; /* true if user overriding parm with command line option */
 
-  /* Protocol type (PROTO_UDP or PROTO_TCP) */
-  int proto;
-  int connect_retry_seconds;
-  int connect_retry_max;
-  bool connect_retry_defined;
-  int connect_timeout;
-  bool connect_timeout_defined;
-
   /* Advanced MTU negotiation and datagram fragmentation options */
   int mtu_discover_type; /* used if OS supports setting Path MTU discovery options on socket */
 
@@ -254,21 +303,6 @@ struct options
   struct route_option_list *routes;
   bool route_nopull;
 
-#ifdef GENERAL_PROXY_SUPPORT
-  struct auto_proxy_info *auto_proxy_info;
-#endif
-
-#ifdef ENABLE_HTTP_PROXY
-  struct http_proxy_options *http_proxy_options;
-#endif
-
-#ifdef ENABLE_SOCKS
-  /* socks proxy */
-  const char *socks_proxy_server;
-  int socks_proxy_port;
-  bool socks_proxy_retry;
-#endif
-
 #ifdef ENABLE_OCC
   /* Enable options consistency check between peers */
   bool occ;
@@ -499,6 +533,7 @@ struct options
 #define OPT_P_PLUGIN          (1<<24)
 #define OPT_P_SOCKBUF         (1<<25)
 #define OPT_P_SOCKFLAGS       (1<<26)
+#define OPT_P_CONNECTION      (1<<27)
 
 #define OPT_P_DEFAULT   (~(OPT_P_INSTANCE|OPT_P_PULL_MODE))
 
@@ -553,7 +588,7 @@ void notnull (const char *arg, const char *description);
 
 void usage_small (void);
 
-void init_options (struct options *o);
+void init_options (struct options *o, const bool init_gc);
 void uninit_options (struct options *o);
 
 void setenv_settings (struct env_set *es, const struct options *o);
@@ -578,7 +613,7 @@ void options_warning (char *actual, const char *expected);
 
 #endif
 
-void options_postprocess (struct options *options, bool first_time);
+void options_postprocess (struct options *options);
 
 void pre_pull_save (struct options *o);
 void pre_pull_restore (struct options *o);
@@ -643,4 +678,26 @@ void options_string_import (struct options *options,
                            unsigned int *option_types_found,
                            struct env_set *es);
 
+/*
+ * inline functions
+ */
+static inline bool
+connection_list_defined (const struct options *o)
+{
+#ifdef ENABLE_CONNECTION
+  return o->connection_list != NULL;
+#else
+  return false;
+#endif
+}
+
+static inline void
+connection_list_set_no_advance (struct options *o)
+{
+#ifdef ENABLE_CONNECTION
+  if (o->connection_list)
+    o->connection_list->no_advance = true;
+#endif
+}
+
 #endif
diff --git a/proxy.c b/proxy.c
index 620f23c0a4d6ee000e83633210541ec8158e30a2..7d15b173a694e6eba25b3d15a0179ed688648fe8 100644 (file)
--- a/proxy.c
+++ b/proxy.c
@@ -229,9 +229,8 @@ get_user_pass_http (struct http_proxy_info *p, const bool force)
 }
 
 struct http_proxy_info *
-new_http_proxy (const struct http_proxy_options *o,
-               struct auto_proxy_info *auto_proxy_info,
-               struct gc_arena *gc)
+http_proxy_new (const struct http_proxy_options *o,
+               struct auto_proxy_info *auto_proxy_info)
 {
   struct http_proxy_info *p;
   struct http_proxy_options opt;
@@ -275,7 +274,7 @@ new_http_proxy (const struct http_proxy_options *o,
 
   ASSERT (legal_ipv4_port (o->port));
 
-  ALLOC_OBJ_CLEAR_GC (p, struct http_proxy_info, gc);
+  ALLOC_OBJ_CLEAR (p, struct http_proxy_info);
   p->options = *o;
 
   /* parse authentication method */
@@ -310,6 +309,12 @@ new_http_proxy (const struct http_proxy_options *o,
   return p;
 }
 
+void
+http_proxy_close (struct http_proxy_info *hp)
+{
+  free (hp);
+}
+
 bool
 establish_http_proxy_passthru (struct http_proxy_info *p,
                               socket_descriptor_t sd, /* already open to proxy */
diff --git a/proxy.h b/proxy.h
index 1417dbcaffdc4601b3be77424c7a9c70bdfb6c2c..d49a4da7a4fbe7ef360b707a74ba439c6d07e820 100644 (file)
--- a/proxy.h
+++ b/proxy.h
@@ -80,9 +80,10 @@ struct http_proxy_info {
   struct user_pass up;
 };
 
-struct http_proxy_info *new_http_proxy (const struct http_proxy_options *o,
-                                       struct auto_proxy_info *auto_proxy_info,
-                                       struct gc_arena *gc);
+struct http_proxy_info *http_proxy_new (const struct http_proxy_options *o,
+                                       struct auto_proxy_info *auto_proxy_info);
+
+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 */
index 3338990cbf4a3a64888702391837a3b64b33bb84..881d1300612e2c74e6746510e09d7f9b2f5787b3 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -402,77 +402,6 @@ link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf)
     }
 }
 
-/*
- * Remote list code allows clients to specify a list of
- * potential remote server addresses.
- */
-
-static void
-remote_list_next (struct remote_list *l)
-{
-  if (l)
-    {
-      if (l->no_advance && l->current >= 0)
-       {
-         l->no_advance = false;
-       }
-      else
-       {
-         int i;
-         if (++l->current >= l->len)
-           l->current = 0;
-
-         dmsg (D_REMOTE_LIST, "REMOTE_LIST len=%d current=%d",
-               l->len, l->current);
-         for (i = 0; i < l->len; ++i)
-           {
-             dmsg (D_REMOTE_LIST, "[%d] %s:%d",
-                   i,
-                   l->array[i].hostname,
-                   l->array[i].port);
-           }
-       }
-    }
-}
-
-void
-remote_list_randomize (struct remote_list *l)
-{
-  int i;
-  if (l)
-    {
-      for (i = 0; i < l->len; ++i)
-       {
-         const int j = get_random () % l->len;
-         if (i != j)
-           {
-             struct remote_entry tmp;
-             tmp = l->array[i];
-             l->array[i] = l->array[j];
-             l->array[j] = tmp;
-           }
-       }
-    }
-}
-
-static const char *
-remote_list_host (const struct remote_list *rl)
-{
-  if (rl)
-    return rl->array[rl->current].hostname;
-  else
-    return NULL;
-}
-
-static int
-remote_list_port (const struct remote_list *rl)
-{
-  if (rl)
-    return rl->array[rl->current].port;
-  else
-    return 0;
-}
-
 /*
  * SOCKET INITALIZATION CODE.
  * Create a TCP/UDP socket
@@ -813,7 +742,7 @@ socket_connect (socket_descriptor_t *sd,
                 struct openvpn_sockaddr *local,
                 bool bind_local,
                struct openvpn_sockaddr *remote,
-               struct remote_list *remote_list,
+               const bool connection_profiles_defined,
                const char *remote_dynamic,
                bool *remote_changed,
                const int connect_retry_seconds,
@@ -865,7 +794,7 @@ socket_connect (socket_descriptor_t *sd,
       openvpn_close_socket (*sd);
       *sd = SOCKET_UNDEFINED;
 
-      if (connect_retry_max > 0 && ++retry >= connect_retry_max)
+      if ((connect_retry_max > 0 && ++retry >= connect_retry_max) || connection_profiles_defined)
        {
          *signal_received = SIGUSR1;
          goto done;
@@ -877,14 +806,6 @@ socket_connect (socket_descriptor_t *sd,
       if (*signal_received)
        goto done;
 
-      if (remote_list)
-       {
-         remote_list_next (remote_list);
-         remote_dynamic = remote_list_host (remote_list);
-         remote->sa.sin_port = htons (remote_list_port (remote_list));
-         *remote_changed = true;
-       }
-
       *sd = create_socket_tcp ();
       if (bind_local)
         socket_bind (*sd, local, "TCP Client");
@@ -996,7 +917,7 @@ resolve_remote (struct link_socket *sock,
              int retry = 0;
              bool status = false;
 
-             if (remote_list_len (sock->remote_list) > 1 && sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
+             if (sock->connection_profiles_defined && sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
                {
                  if (phase == 2)
                    flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
@@ -1099,9 +1020,11 @@ link_socket_new (void)
 /* bind socket if necessary */
 void
 link_socket_init_phase1 (struct link_socket *sock,
+                        const bool connection_profiles_defined,
                         const char *local_host,
-                        struct remote_list *remote_list,
                         int local_port,
+                        const char *remote_host,
+                        int remote_port,
                         int proto,
                         int mode,
                         const struct link_socket *accept_from,
@@ -1129,18 +1052,14 @@ link_socket_init_phase1 (struct link_socket *sock,
                         int sndbuf,
                         unsigned int sockflags)
 {
-  const char *remote_host;
-  int remote_port;
-
   ASSERT (sock);
 
-  sock->remote_list = remote_list;
-  remote_list_next (remote_list);
-  remote_host = remote_list_host (remote_list);
-  remote_port = remote_list_port (remote_list);
+  sock->connection_profiles_defined = connection_profiles_defined;
 
   sock->local_host = local_host;
   sock->local_port = local_port;
+  sock->remote_host = remote_host;
+  sock->remote_port = remote_port;
 
 #ifdef ENABLE_HTTP_PROXY
   sock->http_proxy = http_proxy;
@@ -1198,10 +1117,6 @@ link_socket_init_phase1 (struct link_socket *sock,
       /* the OpenVPN server we will use the proxy to connect to */
       sock->proxy_dest_host = remote_host;
       sock->proxy_dest_port = remote_port;
-
-      /* this is needed so that connection retries will go to the proxy server,
-        not the remote OpenVPN address */
-      sock->remote_list = NULL;
     }
 #endif
 #ifdef ENABLE_SOCKS
@@ -1218,10 +1133,6 @@ link_socket_init_phase1 (struct link_socket *sock,
       /* the OpenVPN server we will use the proxy to connect to */
       sock->proxy_dest_host = remote_host;
       sock->proxy_dest_port = remote_port;
-
-      /* this is needed so that connection retries will go to the proxy server,
-        not the remote OpenVPN address */
-      sock->remote_list = NULL;
     }
 #endif
   else
@@ -1357,7 +1268,7 @@ link_socket_init_phase2 (struct link_socket *sock,
                            &sock->info.lsa->local,
                            sock->bind_local,
                            &sock->info.lsa->actual.dest,
-                           sock->remote_list,
+                           sock->connection_profiles_defined,
                            remote_dynamic,
                            &remote_changed,
                            sock->connect_retry_seconds,
@@ -1405,7 +1316,7 @@ link_socket_init_phase2 (struct link_socket *sock,
                           &sock->info.lsa->local,
                           sock->bind_local,
                          &sock->info.lsa->actual.dest,
-                         NULL,
+                         sock->connection_profiles_defined,
                          remote_dynamic,
                          &remote_changed,
                          sock->connect_retry_seconds,
index 460b85c4fe8113a536ba315d2161996c0bd0ae62..6a393e5a545f79557ffeb2624d9c6220e65e29ee 100644 (file)
--- a/socket.h
+++ b/socket.h
  */
 #define RESOLV_RETRY_INFINITE 1000000000
 
-#define REMOTE_LIST_SIZE 64
-
-struct remote_entry
-{
-  const char *hostname;
-  int port;
-};
-
-struct remote_list
-{
-  int len;
-  int current;
-  bool no_advance;
-  struct remote_entry array[REMOTE_LIST_SIZE];
-};
-
 /* 
  * packet_size_type is used to communicate packet size
  * over the wire when stream oriented protocols are
@@ -175,8 +159,9 @@ struct link_socket
   /* used for long-term queueing of pre-accepted socket listen */
   bool listen_persistent_queued;
 
-  /* set on initial call to init phase 1 */
-  struct remote_list *remote_list;
+  /* Does config file contain any <connection> ... </connection> blocks? */
+  bool connection_profiles_defined;
+
   const char *remote_host;
   int remote_port;
   const char *local_host;
@@ -290,9 +275,11 @@ 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,
-                        struct remote_list *remote_list,
                         int local_port,
+                        const char *remote_host,
+                        int remote_port,
                         int proto,
                         int mode,
                         const struct link_socket *accept_from,
@@ -391,8 +378,6 @@ void link_socket_bad_outgoing_addr (void);
 
 void setenv_trusted (struct env_set *es, const struct link_socket_info *info);
 
-void remote_list_randomize (struct remote_list *l);
-
 bool link_socket_update_flags (struct link_socket *ls, unsigned int sockflags);
 void link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf);
 
@@ -467,15 +452,6 @@ datagram_overhead (int proto)
  * Misc inline functions
  */
 
-static inline int
-remote_list_len (const struct remote_list *rl)
-{
-  if (rl)
-    return rl->len;
-  else
-    return 0;
-}
-
 static inline bool
 legal_ipv4_port (int port)
 {
diff --git a/socks.c b/socks.c
index 79e11707556bd486c9974ced8419e8bbc228b86e..838758dfab86610d196a87726c20f81d6b85f67e 100644 (file)
--- a/socks.c
+++ b/socks.c
@@ -51,11 +51,10 @@ socks_adjust_frame_parameters (struct frame *frame, int proto)
 }
 
 struct socks_proxy_info *
-new_socks_proxy (const char *server,
+socks_proxy_new (const char *server,
                 int port,
                 bool retry,
-                struct auto_proxy_info *auto_proxy_info,
-                struct gc_arena *gc)
+                struct auto_proxy_info *auto_proxy_info)
 {
   struct socks_proxy_info *p;
 
@@ -71,7 +70,7 @@ new_socks_proxy (const char *server,
        }
     }
 
-  ALLOC_OBJ_CLEAR_GC (p, struct socks_proxy_info, gc);
+  ALLOC_OBJ_CLEAR (p, struct socks_proxy_info);
 
   ASSERT (server);
   ASSERT (legal_ipv4_port (port));
@@ -84,6 +83,12 @@ new_socks_proxy (const char *server,
   return p;
 }
 
+void
+socks_proxy_close (struct socks_proxy_info *sp)
+{
+  free (sp);
+}
+
 static bool
 socks_handshake (socket_descriptor_t sd, volatile int *signal_received)
 {
diff --git a/socks.h b/socks.h
index 506aeb3498c313c74e61d8679721b104e297301c..c868fbbb311f2d7d4af3eb1f5b71093db55083d9 100644 (file)
--- a/socks.h
+++ b/socks.h
@@ -47,11 +47,12 @@ struct socks_proxy_info {
 
 void socks_adjust_frame_parameters (struct frame *frame, int proto);
 
-struct socks_proxy_info *new_socks_proxy (const char *server,
+struct socks_proxy_info *socks_proxy_new (const char *server,
                                          int port,
                                          bool retry,
-                                         struct auto_proxy_info *auto_proxy_info,
-                                         struct gc_arena *gc);
+                                         struct auto_proxy_info *auto_proxy_info);
+
+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 */
index 624ae106f778a51620ff51f09c65dbcf4fa76635..0f8bea383709f65e378ac74a8ef8d41b709b425e 100644 (file)
--- a/syshead.h
+++ b/syshead.h
@@ -605,4 +605,11 @@ socket_defined (const socket_descriptor_t sd)
 #define AUTO_USERID 0
 #endif
 
+/*
+ * Support "connection" directive
+ */
+#if ENABLE_INLINE_FILES
+#define ENABLE_CONNECTION 1
+#endif
+
 #endif
index 1ce8c483e306908d31761c0fc4bf939ebb1f6cc0..0ecbfe1ceceb19229dec5208ecc43f50f3f96d9f 100644 (file)
@@ -1,5 +1,5 @@
 dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1_rc7e])
+define(PRODUCT_VERSION,[2.1_rc7f])
 dnl define the TAP version
 define(PRODUCT_TAP_ID,[tap0901])
 define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])