diff options
Diffstat (limited to 'openvpn/src/openvpn/init.c')
-rw-r--r-- | openvpn/src/openvpn/init.c | 292 |
1 files changed, 157 insertions, 135 deletions
diff --git a/openvpn/src/openvpn/init.c b/openvpn/src/openvpn/init.c index 1f06eaa5..b3125282 100644 --- a/openvpn/src/openvpn/init.c +++ b/openvpn/src/openvpn/init.c @@ -125,28 +125,19 @@ management_callback_proxy_cmd (void *arg, const char **p) ret = true; else if (p[2] && p[3]) { - const int port = atoi(p[3]); - if (!legal_ipv4_port (port)) - { - msg (M_WARN, "Bad proxy port number: %s", p[3]); - return false; - } - if (streq (p[1], "HTTP")) { #ifndef ENABLE_HTTP_PROXY msg (M_WARN, "HTTP proxy support is not available"); #else struct http_proxy_options *ho; - if (ce->proto != PROTO_TCPv4 && ce->proto != PROTO_TCPv4_CLIENT && - ce->proto != PROTO_TCPv6 && ce->proto != PROTO_TCPv6_CLIENT) - { + if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_CLIENT ) { msg (M_WARN, "HTTP proxy support only works for TCP based connections"); return false; } ho = init_http_proxy_options_once (&ce->http_proxy_options, gc); ho->server = string_alloc (p[2], gc); - ho->port = port; + ho->port = string_alloc (p[3], gc); ho->retry = true; ho->auth_retry = (p[4] && streq (p[4], "nct") ? PAR_NCT : PAR_ALL); ret = true; @@ -158,7 +149,7 @@ management_callback_proxy_cmd (void *arg, const char **p) msg (M_WARN, "SOCKS proxy support is not available"); #else ce->socks_proxy_server = string_alloc (p[2], gc); - ce->socks_proxy_port = port; + ce->socks_proxy_port = p[3]; ret = true; #endif } @@ -225,8 +216,7 @@ management_callback_remote_cmd (void *arg, const char **p) } else if (!strcmp(p[1], "MOD") && p[2] && p[3]) { - const int port = atoi(p[3]); - if (strlen(p[2]) < RH_HOST_LEN && legal_ipv4_port(port)) + if (strlen(p[2]) < RH_HOST_LEN && strlen(p[3]) < RH_PORT_LEN) { struct remote_host_store *rhs = c->options.rh_store; if (!rhs) @@ -235,8 +225,10 @@ management_callback_remote_cmd (void *arg, const char **p) c->options.rh_store = rhs; } strncpynt(rhs->host, p[2], RH_HOST_LEN); + strncpynt(rhs->port, p[3], RH_PORT_LEN); + ce->remote = rhs->host; - ce->remote_port = port; + ce->remote_port = rhs->port; flags = CE_MAN_QUERY_REMOTE_MOD; ret = true; } @@ -251,7 +243,7 @@ management_callback_remote_cmd (void *arg, const char **p) } static bool -ce_management_query_remote (struct context *c, const char *remote_ip_hint) +ce_management_query_remote (struct context *c) { struct gc_arena gc = gc_new (); volatile struct connection_entry *ce = &c->options.ce; @@ -260,7 +252,7 @@ ce_management_query_remote (struct context *c, const char *remote_ip_hint) if (management) { struct buffer out = alloc_buf_gc (256, &gc); - buf_printf (&out, ">REMOTE:%s,%d,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, false)); + buf_printf (&out, ">REMOTE:%s,%s,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, ce->af, false)); management_notify_generic(management, BSTR (&out)); ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<<CE_MAN_QUERY_REMOTE_SHIFT); ce->flags |= (CE_MAN_QUERY_REMOTE_QUERY<<CE_MAN_QUERY_REMOTE_SHIFT); @@ -276,8 +268,6 @@ ce_management_query_remote (struct context *c, const char *remote_ip_hint) } { const int flags = ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK); - if (flags == CE_MAN_QUERY_REMOTE_ACCEPT && remote_ip_hint) - ce->remote = remote_ip_hint; ret = (flags != CE_MAN_QUERY_REMOTE_SKIP); } gc_free (&gc); @@ -292,95 +282,126 @@ static void init_connection_list (struct context *c) { struct connection_list *l = c->options.connection_list; - if (l) + l->current = -1; + if (c->options.remote_random) { - l->current = -1; - if (c->options.remote_random) - { - int i; - for (i = 0; i < l->len; ++i) - { - const int j = get_random () % l->len; - if (i != j) - { - struct connection_entry *tmp; - tmp = l->array[i]; - l->array[i] = l->array[j]; - l->array[j] = tmp; - } - } - } + int i; + for (i = 0; i < l->len; ++i) + { + const int j = get_random () % l->len; + if (i != j) + { + struct connection_entry *tmp; + tmp = l->array[i]; + l->array[i] = l->array[j]; + l->array[j] = tmp; + } + } } } /* + * Clear the remote address list + */ +static void clear_remote_addrlist (struct link_socket_addr *lsa) +{ + if (lsa->remote_list) { + freeaddrinfo(lsa->remote_list); + } + lsa->remote_list = NULL; + lsa->current_remote = NULL; +} + +/* * Increment to next connection entry */ static void next_connection_entry (struct context *c) { struct connection_list *l = c->options.connection_list; - if (l) - { - bool ce_defined; - struct connection_entry *ce; - int n_cycles = 0; - - do { - const char *remote_ip_hint = NULL; - bool newcycle = false; - - ce_defined = true; - if (l->no_advance && l->current >= 0) - { - l->no_advance = false; - } - else - { - if (++l->current >= l->len) - { - l->current = 0; - ++l->n_cycles; - if (++n_cycles >= 2) - msg (M_FATAL, "No usable connection profiles are present"); - } - - if (l->current == 0) - newcycle = true; - } - - ce = l->array[l->current]; + bool ce_defined; + struct connection_entry *ce; + int n_cycles = 0; + + do { + ce_defined = true; + if (c->options.no_advance && l->current >= 0) + { + c->options.no_advance = false; + } + else + { + /* Check if there is another resolved address to try for + * the current connection */ + if (c->c1.link_socket_addr.current_remote && + c->c1.link_socket_addr.current_remote->ai_next) + { + c->c1.link_socket_addr.current_remote = + c->c1.link_socket_addr.current_remote->ai_next; + } + else + { + /* FIXME (schwabe) fix the persist-remote-ip option for real, + * this is broken probably ever since connection lists and multiple + * remote existed + */ + + if (!c->options.persist_remote_ip) + clear_remote_addrlist (&c->c1.link_socket_addr); + else + c->c1.link_socket_addr.current_remote = + c->c1.link_socket_addr.remote_list; + + /* + * Increase the number of connection attempts + * If this is connect-retry-max * size(l) + * OpenVPN will quit + */ + + c->options.unsuccessful_attempts++; + + if (++l->current >= l->len) + { + + l->current = 0; + if (++n_cycles >= 2) + msg (M_FATAL, "No usable connection profiles are present"); + } + } + } - if (c->options.remote_ip_hint && !l->n_cycles) - remote_ip_hint = c->options.remote_ip_hint; + ce = l->array[l->current]; - if (ce->flags & CE_DISABLED) - ce_defined = false; + if (ce->flags & CE_DISABLED) + ce_defined = false; - c->options.ce = *ce; + c->options.ce = *ce; #ifdef ENABLE_MANAGEMENT - if (ce_defined && management && management_query_remote_enabled(management)) - { - /* allow management interface to override connection entry details */ - ce_defined = ce_management_query_remote(c, remote_ip_hint); - if (IS_SIG (c)) - break; - } - else + if (ce_defined && management && management_query_remote_enabled(management)) + { + /* allow management interface to override connection entry details */ + ce_defined = ce_management_query_remote(c); + if (IS_SIG (c)) + break; + } + else #endif - if (remote_ip_hint) - c->options.ce.remote = remote_ip_hint; #ifdef ENABLE_MANAGEMENT - if (ce_defined && management && management_query_proxy_enabled (management)) - { - ce_defined = ce_management_query_proxy (c); - if (IS_SIG (c)) - break; - } + if (ce_defined && management && management_query_proxy_enabled (management)) + { + ce_defined = ce_management_query_proxy (c); + if (IS_SIG (c)) + break; + } #endif - } while (!ce_defined); - } + } while (!ce_defined); + + /* Check if this connection attempt would bring us over the limit */ + if (c->options.connect_retry_max > 0 && + c->options.unsuccessful_attempts > (l->len * c->options.connect_retry_max)) + msg(M_FATAL, "All connections have been connect-retry-max (%d) times unsuccessful, exiting", + c->options.connect_retry_max); update_options_ce_post (&c->options); } @@ -415,12 +436,6 @@ init_query_passwords (struct context *c) #ifdef GENERAL_PROXY_SUPPORT -static int -proxy_scope (struct context *c) -{ - return connection_list_defined (&c->options) ? 2 : 1; -} - static void uninit_proxy_dowork (struct context *c) { @@ -482,17 +497,15 @@ init_proxy_dowork (struct context *c) } static void -init_proxy (struct context *c, const int scope) +init_proxy (struct context *c) { - if (scope == proxy_scope (c)) - init_proxy_dowork (c); + init_proxy_dowork (c); } static void uninit_proxy (struct context *c) { - if (c->sig->signal_received != SIGUSR1 || proxy_scope (c) == 2) - uninit_proxy_dowork (c); + uninit_proxy_dowork (c); } #else @@ -544,8 +557,6 @@ context_init_1 (struct context *c) } #endif - /* initialize HTTP or SOCKS proxy object at scope level 1 */ - init_proxy (c, 1); } void @@ -1240,6 +1251,9 @@ void initialization_sequence_completed (struct context *c, const unsigned int flags) { static const char message[] = "Initialization Sequence Completed"; + + /* Reset the unsuccessful connection counter on complete initialisation */ + c->options.unsuccessful_attempts=0; /* If we delayed UID/GID downgrade or chroot, do it now */ do_uid_gid_chroot (c, true); @@ -1258,9 +1272,9 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) else msg (M_INFO, "%s", message); - /* Flag connection_list that we initialized */ - if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0 && connection_list_defined (&c->options)) - connection_list_set_no_advance (&c->options); + /* Flag that we initialized */ + if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0) + c->options.no_advance=true; #ifdef WIN32 fork_register_dns_action (c->c1.tuntap); @@ -1374,8 +1388,8 @@ do_init_tun (struct context *c) c->options.ifconfig_ipv6_local, c->options.ifconfig_ipv6_netbits, c->options.ifconfig_ipv6_remote, - addr_host (&c->c1.link_socket_addr.local), - addr_host (&c->c1.link_socket_addr.remote), + c->c1.link_socket_addr.bind_local, + c->c1.link_socket_addr.remote_list, !c->options.ifconfig_nowarn, c->c2.es); @@ -1853,17 +1867,11 @@ socket_restart_pause (struct context *c) switch (c->options.ce.proto) { - case PROTO_UDPv4: - case PROTO_UDPv6: - if (proxy) - sec = c->options.ce.connect_retry_seconds; - break; - case PROTO_TCPv4_SERVER: - case PROTO_TCPv6_SERVER: + case PROTO_TCP_SERVER: sec = 1; break; - case PROTO_TCPv4_CLIENT: - case PROTO_TCPv6_CLIENT: + case PROTO_UDP: + case PROTO_TCP_CLIENT: sec = c->options.ce.connect_retry_seconds; break; } @@ -2219,7 +2227,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) /* should we not xmit any packets until we get an initial response from client? */ - if (to.server && options->ce.proto == PROTO_TCPv4_SERVER) + if (to.server && options->ce.proto == PROTO_TCP_SERVER) to.xmit_hold = true; #ifdef ENABLE_OCC @@ -2504,8 +2512,6 @@ do_option_warnings (struct context *c) msg (M_WARN, "NOTE: --connect-timeout option is not supported on this OS"); #endif - if (script_method == SM_SYSTEM) - msg (M_WARN, "NOTE: --script-security method='system' is deprecated due to the fact that passed parameters will be subject to shell expansion"); } static void @@ -2628,12 +2634,12 @@ do_init_socket_1 (struct context *c, const int mode) #endif link_socket_init_phase1 (c->c2.link_socket, - connection_list_defined (&c->options), c->options.ce.local, c->options.ce.local_port, c->options.ce.remote, c->options.ce.remote_port, c->options.ce.proto, + c->options.ce.af, mode, c->c2.accept_from, #ifdef ENABLE_HTTP_PROXY @@ -2652,9 +2658,7 @@ do_init_socket_1 (struct context *c, const int mode) c->options.ipchange, c->plugins, c->options.resolve_retry_seconds, - c->options.ce.connect_retry_seconds, c->options.ce.connect_timeout, - c->options.ce.connect_retry_max, c->options.ce.mtu_discover_type, c->options.rcvbuf, c->options.sndbuf, @@ -2669,7 +2673,7 @@ static void do_init_socket_2 (struct context *c) { link_socket_init_phase2 (c->c2.link_socket, &c->c2.frame, - &c->sig->signal_received); + c->sig); } /* @@ -2841,14 +2845,30 @@ do_close_link_socket (struct context *c) c->c2.link_socket = NULL; } - if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_remote_ip)) - { - CLEAR (c->c1.link_socket_addr.remote); + + /* Preserve the resolved list of remote if the user request to or if we want + * reconnect to the same host again or there are still addresses that need + * to be tried */ + if (!(c->sig->signal_received == SIGUSR1 && + ( (c->options.persist_remote_ip) + || + ( c->sig->source != SIG_SOURCE_HARD && + ((c->c1.link_socket_addr.current_remote && c->c1.link_socket_addr.current_remote->ai_next) + || c->options.no_advance)) + ))) + { + clear_remote_addrlist(&c->c1.link_socket_addr); + } + + /* Clear the remote actual address when persist_remote_ip is not in use */ + if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_remote_ip)) CLEAR (c->c1.link_socket_addr.actual); - } - if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip)) - CLEAR (c->c1.link_socket_addr.local); + if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip)) { + if (c->c1.link_socket_addr.bind_local) + freeaddrinfo(c->c1.link_socket_addr.bind_local); + c->c1.link_socket_addr.bind_local=NULL; + } } /* @@ -3271,7 +3291,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int /* signals caught here will abort */ c->sig->signal_received = 0; c->sig->signal_text = NULL; - c->sig->hard = false; + c->sig->source = SIG_SOURCE_SOFT; if (c->mode == CM_P2P) init_management_callback_p2p (c); @@ -3290,8 +3310,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int /* link_socket_mode allows CM_CHILD_TCP instances to inherit acceptable fds from a top-level parent */ - if (c->options.ce.proto == PROTO_TCPv4_SERVER - || c->options.ce.proto == PROTO_TCPv6_SERVER) + if (c->options.ce.proto == PROTO_TCP_SERVER) { if (c->mode == CM_TOP) link_socket_mode = LS_MODE_TCP_LISTEN; @@ -3358,7 +3377,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int do_event_set_init (c, false); /* initialize HTTP or SOCKS proxy object at scope level 2 */ - init_proxy (c, 2); + init_proxy (c); /* allocate our socket object */ if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) @@ -3689,8 +3708,11 @@ close_context (struct context *c, int sig, unsigned int flags) if (c->sig->signal_received == SIGUSR1) { if ((flags & CC_USR1_TO_HUP) - || (c->sig->hard && (flags & CC_HARD_USR1_TO_HUP))) - c->sig->signal_received = SIGHUP; + || (c->sig->source == SIG_SOURCE_HARD && (flags & CC_HARD_USR1_TO_HUP))) + { + c->sig->signal_received = SIGHUP; + c->sig->signal_text = "close_context usr1 to hup"; + } } if (!(flags & CC_NO_CLOSE)) |