diff options
Diffstat (limited to 'options.c')
-rw-r--r-- | options.c | 827 |
1 files changed, 513 insertions, 314 deletions
@@ -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]) |