summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--buffer.c20
-rw-r--r--buffer.h2
-rw-r--r--errlevel.h2
-rw-r--r--forward.c4
-rw-r--r--helper.c12
-rw-r--r--init.c292
-rw-r--r--misc.c33
-rw-r--r--misc.h3
-rw-r--r--multi.c2
-rw-r--r--occ.c4
-rw-r--r--openvpn.8129
-rw-r--r--openvpn.c4
-rw-r--r--openvpn.h5
-rw-r--r--options.c827
-rw-r--r--options.h123
-rw-r--r--proxy.c13
-rw-r--r--proxy.h7
-rw-r--r--socket.c111
-rw-r--r--socket.h36
-rw-r--r--socks.c13
-rw-r--r--socks.h7
-rw-r--r--syshead.h7
-rw-r--r--version.m42
23 files changed, 1076 insertions, 582 deletions
diff --git a/buffer.c b/buffer.c
index 92b10e5..f548e9f 100644
--- a/buffer.c
+++ b/buffer.c
@@ -315,6 +315,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.
*/
diff --git a/buffer.h b/buffer.h
index 195c7d3..4a6d3a4 100644
--- 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
diff --git a/errlevel.h b/errlevel.h
index b2a0dda..359745e 100644
--- a/errlevel.h
+++ b/errlevel.h
@@ -120,7 +120,7 @@
#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 */
diff --git a/forward.c b/forward.c
index 85c1194..e759e24 100644
--- 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.
diff --git a/helper.c b/helper.c
index a216687..4ec63f2 100644
--- 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 97ecf7d..36d7b8f 100644
--- 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 5f0ec12..0ac1250 100644
--- 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);
@@ -975,6 +976,38 @@ setenv_str_ex (struct env_set *es,
}
/*
+ * 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
*/
unsigned int
diff --git a/misc.h b/misc.h
index 3ee0e27..634180c 100644
--- 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 bc3500f..3c09994 100644
--- 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 1add9d0..86bc68c 100644
--- 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))
diff --git a/openvpn.8 b/openvpn.8
index 69d8f8f..6e261f7 100644
--- 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
@@ -527,10 +536,124 @@ 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
diff --git a/openvpn.c b/openvpn.c
index f1bf169..5e87fee 100644
--- 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);
diff --git a/openvpn.h b/openvpn.h
index 1ffc44c..258bb15 100644
--- 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
diff --git a/options.c b/options.c
index 5328efb..f9252ed 100644
--- 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
@@ -724,46 +729,50 @@ 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
@@ -1417,20 +1472,13 @@ options_postprocess (struct options *options, bool first_time)
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,41 +1599,34 @@ 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");
if (options->shaper)
@@ -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])
diff --git a/options.h b/options.h
index 39f2ac6..2bd7f26 100644
--- 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 620f23c..7d15b17 100644
--- 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 1417dbc..d49a4da 100644
--- 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 */
diff --git a/socket.c b/socket.c
index 3338990..881d130 100644
--- a/socket.c
+++ b/socket.c
@@ -403,77 +403,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,
diff --git a/socket.h b/socket.h
index 460b85c..6a393e5 100644
--- a/socket.h
+++ b/socket.h
@@ -47,22 +47,6 @@
*/
#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 79e1170..838758d 100644
--- 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 506aeb3..c868fbb 100644
--- 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 */
diff --git a/syshead.h b/syshead.h
index 624ae10..0f8bea3 100644
--- 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
diff --git a/version.m4 b/version.m4
index 1ce8c48..0ecbfe1 100644
--- a/version.m4
+++ b/version.m4
@@ -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])