From 4e9a51d78ffa0696cf7d14ff0292ca8863689f70 Mon Sep 17 00:00:00 2001 From: james Date: Wed, 11 Jun 2008 10:48:50 +0000 Subject: Merged connection profiles from 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 --- buffer.c | 20 ++ buffer.h | 2 + errlevel.h | 2 +- forward.c | 4 +- helper.c | 12 - init.c | 292 +++++++++++++++++----- misc.c | 33 +++ misc.h | 3 + multi.c | 2 +- occ.c | 4 +- openvpn.8 | 129 +++++++++- openvpn.c | 4 +- openvpn.h | 5 +- options.c | 827 ++++++++++++++++++++++++++++++++++++++----------------------- options.h | 123 ++++++--- proxy.c | 13 +- proxy.h | 7 +- socket.c | 111 +-------- socket.h | 36 +-- socks.c | 13 +- socks.h | 7 +- syshead.h | 7 + version.m4 | 2 +- 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 @@ -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. */ 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 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); @@ -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 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 +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 +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 +and +.B . + +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 + + +remote 198.19.34.56 1194 udp + + + +remote 198.19.34.56 443 tcp + + + +remote 198.19.34.56 443 tcp +http-proxy 192.168.0.8 8080 +http-proxy-retry + + + +remote 198.19.36.99 443 tcp +http-proxy 192.168.0.8 8080 +http-proxy-retry + + +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 +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 +profiles. If any of the above options (with the exception of +.B remote +) appear outside of a +.B +block, but in a configuration file which has one or more +.B +blocks, the option setting will be used as a default for +.B +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 +block. The effect would be as if +.B nobind +were declared in all +.B +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 @@ -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, " 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]) 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 @@ -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, 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 ... 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]) -- cgit