diff options
Diffstat (limited to 'src/openvpn/init.c')
-rw-r--r-- | src/openvpn/init.c | 1125 |
1 files changed, 654 insertions, 471 deletions
diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 2148777..470dc89 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -43,6 +43,9 @@ #include "lladdr.h" #include "ping.h" #include "mstats.h" +#include "ssl_verify.h" +#include "tls_crypt.h" +#include "forward-inline.h" #include "memdbg.h" @@ -125,42 +128,25 @@ 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->retry = true; + ho->port = string_alloc (p[3], gc); ho->auth_retry = (p[4] && streq (p[4], "nct") ? PAR_NCT : PAR_ALL); ret = true; -#endif } else if (streq (p[1], "SOCKS")) { -#ifndef ENABLE_SOCKS - 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 } } else @@ -227,8 +213,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) @@ -237,8 +222,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; } @@ -253,7 +240,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; @@ -262,7 +249,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); @@ -278,8 +265,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); @@ -294,95 +279,129 @@ 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, bool free) +{ + if (lsa->remote_list && free) + 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; + bool ce_defined; + struct connection_entry *ce; + int n_cycles = 0; - ce_defined = true; - if (l->no_advance && l->current >= 0) - { - l->no_advance = false; - } - else - { - if (++l->current >= l->len) + 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) { - l->current = 0; - ++l->n_cycles; - if (++n_cycles >= 2) - msg (M_FATAL, "No usable connection profiles are present"); + /* close_instance should have cleared the addrinfo objects */ + ASSERT (c->c1.link_socket_addr.current_remote == NULL); + ASSERT (c->c1.link_socket_addr.remote_list == NULL); } + else + c->c1.link_socket_addr.current_remote = + c->c1.link_socket_addr.remote_list; - if (l->current == 0) - newcycle = true; - } + /* + * Increase the number of connection attempts + * If this is connect-retry-max * size(l) + * OpenVPN will quit + */ - ce = l->array[l->current]; + c->options.unsuccessful_attempts++; - if (c->options.remote_ip_hint && !l->n_cycles) - remote_ip_hint = c->options.remote_ip_hint; + if (++l->current >= l->len) + { - if (ce->flags & CE_DISABLED) - ce_defined = false; + l->current = 0; + if (++n_cycles >= 2) + msg (M_FATAL, "No usable connection profiles are present"); + } + } + } + + ce = l->array[l->current]; - c->options.ce = *ce; + if (ce->flags & CE_DISABLED) + ce_defined = false; + + 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); } @@ -392,7 +411,7 @@ next_connection_entry (struct context *c) void init_query_passwords (const struct context *c) { -#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) +#ifdef ENABLE_CRYPTO /* Certificate password input */ if (c->options.key_pass_file) pem_password_setup (c->options.key_pass_file); @@ -415,47 +434,30 @@ init_query_passwords (const 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; -#else - const bool did_http = false; -#endif uninit_proxy_dowork (c); -#ifdef ENABLE_HTTP_PROXY if (c->options.ce.http_proxy_options) { /* Possible HTTP proxy user/pass input */ @@ -466,51 +468,31 @@ init_proxy_dowork (struct context *c) c->c1.http_proxy_owned = true; } } -#endif -#ifdef ENABLE_SOCKS - if (!did_http && c->options.ce.socks_proxy_server) + if (!did_http && c->options.ce.socks_proxy_server) { c->c1.socks_proxy = socks_proxy_new (c->options.ce.socks_proxy_server, c->options.ce.socks_proxy_port, - c->options.ce.socks_proxy_authfile, - c->options.ce.socks_proxy_retry); + c->options.ce.socks_proxy_authfile); if (c->c1.socks_proxy) { c->c1.socks_proxy_owned = true; } } -#endif } 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); -} - -#else - -static inline void -init_proxy (struct context *c, const int scope) -{ -} - -static inline void -uninit_proxy (struct context *c) -{ + uninit_proxy_dowork (c); } -#endif - void context_init_1 (struct context *c) { @@ -544,8 +526,6 @@ context_init_1 (struct context *c) } #endif - /* initialize HTTP or SOCKS proxy object at scope level 1 */ - init_proxy (c, 1); } void @@ -598,7 +578,7 @@ init_static (void) error_reset (); /* initialize error.c */ reset_check_status (); /* initialize status check code in socket.c */ -#ifdef WIN32 +#ifdef _WIN32 init_win32 (); #endif @@ -659,8 +639,10 @@ init_static (void) #ifdef TEST_GET_DEFAULT_GATEWAY { struct route_gateway_info rgi; + struct route_ipv6_gateway_info rgi6; get_default_gateway(&rgi); - print_default_gateway(M_INFO, &rgi); + get_default_gateway_ipv6(&rgi6, NULL); + print_default_gateway(M_INFO, &rgi, &rgi6); return false; } #endif @@ -810,7 +792,7 @@ uninit_static (void) close_port_share (); #endif -#if defined(MEASURE_TLS_HANDSHAKE_STATS) && defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) +#if defined(MEASURE_TLS_HANDSHAKE_STATS) && defined(ENABLE_CRYPTO) show_tls_performance_stats (); #endif } @@ -853,10 +835,7 @@ print_openssl_info (const struct options *options) */ #ifdef ENABLE_CRYPTO if (options->show_ciphers || options->show_digests || options->show_engines -#ifdef ENABLE_SSL - || options->show_tls_ciphers -#endif - ) + || options->show_tls_ciphers || options->show_curves) { if (options->show_ciphers) show_available_ciphers (); @@ -864,10 +843,10 @@ print_openssl_info (const struct options *options) show_available_digests (); if (options->show_engines) show_available_engines (); -#ifdef ENABLE_SSL if (options->show_tls_ciphers) show_available_tls_ciphers (options->cipher_list); -#endif + if (options->show_curves) + show_available_curves(); return true; } #endif @@ -916,10 +895,8 @@ do_persist_tuntap (const struct options *options) || options->ifconfig_remote_netmask #ifdef ENABLE_CRYPTO || options->shared_secret_file -#ifdef ENABLE_SSL || options->tls_server || options->tls_client #endif -#endif ) msg (M_FATAL|M_OPTERR, "options --mktun or --rmtun should only be used together with --dev"); @@ -1036,7 +1013,7 @@ const char * format_common_name (struct context *c, struct gc_arena *gc) { struct buffer out = alloc_buf_gc (256, gc); -#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) +#ifdef ENABLE_CRYPTO if (c->c2.tls_multi) { buf_printf (&out, "[%s] ", tls_common_name (c->c2.tls_multi, false)); @@ -1048,7 +1025,7 @@ format_common_name (struct context *c, struct gc_arena *gc) void pre_setup (const struct options *options) { -#ifdef WIN32 +#ifdef _WIN32 if (options->exit_event_name) { win32_signal_open (&win32_signal, @@ -1080,6 +1057,19 @@ reset_coarse_timers (struct context *c) } /* + * Initialise the server poll timeout timer + * This timer is used in the http/socks proxy setup so it needs to be setup + * before + */ +static void +do_init_server_poll_timeout (struct context *c) +{ + update_time (); + if (c->options.ce.connect_timeout) + event_timeout_init (&c->c2.server_poll_interval, c->options.ce.connect_timeout, now); +} + +/* * Initialize timers */ static void @@ -1100,11 +1090,6 @@ do_init_timers (struct context *c, bool deferred) if (c->options.ping_rec_timeout) event_timeout_init (&c->c2.ping_rec_interval, c->options.ping_rec_timeout, now); -#if P2MP - if (c->options.server_poll_timeout) - event_timeout_init (&c->c2.server_poll_interval, c->options.server_poll_timeout, now); -#endif - if (!deferred) { /* initialize connection establishment timer */ @@ -1126,9 +1111,7 @@ do_init_timers (struct context *c, bool deferred) #ifdef ENABLE_CRYPTO if (c->options.packet_id_file) event_timeout_init (&c->c2.packet_id_persist_interval, 60, now); -#endif -#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) /* initialize tmp_int optimization that limits the number of times we call tls_multi_process in the main event loop */ interval_init (&c->c2.tmp_int, TLS_MULTI_HORIZON, TLS_MULTI_REFRESH); @@ -1161,9 +1144,9 @@ static void do_alloc_route_list (struct context *c) { if (!c->c1.route_list) - c->c1.route_list = new_route_list (c->options.max_routes, &c->gc); + ALLOC_OBJ_CLEAR_GC (c->c1.route_list, struct route_list, &c->gc); if (c->options.routes_ipv6 && !c->c1.route_ipv6_list) - c->c1.route_ipv6_list = new_route_ipv6_list (c->options.max_routes, &c->gc); + ALLOC_OBJ_CLEAR_GC (c->c1.route_ipv6_list, struct route_ipv6_list, &c->gc); } @@ -1175,7 +1158,6 @@ static void do_init_route_list (const struct options *options, struct route_list *route_list, const struct link_socket_info *link_socket_info, - bool fatal, struct env_set *es) { const char *gw = NULL; @@ -1189,18 +1171,13 @@ do_init_route_list (const struct options *options, if (options->route_default_metric) metric = options->route_default_metric; - if (!init_route_list (route_list, + if (init_route_list (route_list, options->routes, gw, metric, link_socket_current_remote (link_socket_info), es)) { - if (fatal) - openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */ - } - else - { /* copy routes to environment */ setenv_routes (es, route_list); } @@ -1209,11 +1186,10 @@ do_init_route_list (const struct options *options, static void do_init_route_ipv6_list (const struct options *options, struct route_ipv6_list *route_ipv6_list, - bool fatal, + const struct link_socket_info *link_socket_info, struct env_set *es) { const char *gw = NULL; - int dev = dev_type_enum (options->dev, options->dev_type); int metric = -1; /* no metric set */ gw = options->ifconfig_ipv6_remote; /* default GW = remote end */ @@ -1225,17 +1201,28 @@ do_init_route_ipv6_list (const struct options *options, if (options->route_default_metric) metric = options->route_default_metric; - if (!init_route_ipv6_list (route_ipv6_list, + /* redirect (IPv6) gateway to VPN? if yes, add a few more specifics + */ + if ( options->routes_ipv6->flags & RG_REROUTE_GW ) + { + char *opt_list[] = { "::/3", "2000::/4", "3000::/4", "fc00::/7", NULL }; + int i; + + for (i=0; opt_list[i]; i++) + { + add_route_ipv6_to_option_list( options->routes_ipv6, + string_alloc (opt_list[i], options->routes_ipv6->gc), + NULL, NULL ); + } + } + + if (init_route_ipv6_list (route_ipv6_list, options->routes_ipv6, gw, metric, + link_socket_current_remote_ipv6 (link_socket_info), es)) { - if (fatal) - openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */ - } - else - { /* copy routes to environment */ setenv_routes_ipv6 (es, route_ipv6_list); } @@ -1250,13 +1237,16 @@ 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); /* Test if errors */ if (flags & ISC_ERRORS) { -#ifdef WIN32 +#ifdef _WIN32 show_routes (M_INFO|M_NOPREFIX); show_adapters (M_INFO|M_NOPREFIX); msg (M_INFO, "%s With Errors ( see http://openvpn.net/faq.html#dhcpclientserv )", message); @@ -1267,11 +1257,11 @@ 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 +#ifdef _WIN32 fork_register_dns_action (c->c1.tuntap); #endif @@ -1279,26 +1269,52 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) /* Tell management interface that we initialized */ if (management) { - in_addr_t tun_local = 0; - in_addr_t tun_remote = 0; /* FKS */ + in_addr_t *tun_local = NULL; + struct in6_addr *tun_local6 = NULL; + struct openvpn_sockaddr local, remote; + struct link_socket_actual *actual; + socklen_t sa_len = sizeof(local); const char *detail = "SUCCESS"; - if (c->c1.tuntap) - tun_local = c->c1.tuntap->local; - /* TODO(jjo): for ipv6 this will convert some 32bits in the ipv6 addr - * to a meaningless ipv4 address. - * In any case, is somewhat inconsistent to send local tunnel - * addr with remote _endpoint_ addr (?) - */ - tun_remote = htonl (c->c1.link_socket_addr.actual.dest.addr.in4.sin_addr.s_addr); if (flags & ISC_ERRORS) - detail = "ERROR"; + detail = "ERROR"; + + CLEAR (local); + actual = &get_link_socket_info(c)->lsa->actual; + remote = actual->dest; + getsockname(c->c2.link_socket->sd, &local.addr.sa, &sa_len); +#if ENABLE_IP_PKTINFO + if (!addr_defined(&local)) + { + switch (local.addr.sa.sa_family) + { + case AF_INET: +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) + local.addr.in4.sin_addr = actual->pi.in4.ipi_spec_dst; +#else + local.addr.in4.sin_addr = actual->pi.in4; +#endif + break; + case AF_INET6: + local.addr.in6.sin6_addr = actual->pi.in6.ipi6_addr; + break; + } + } +#endif + + if (c->c1.tuntap) + { + tun_local = &c->c1.tuntap->local; + tun_local6 = &c->c1.tuntap->local_ipv6; + } management_set_state (management, OPENVPN_STATE_CONNECTED, detail, tun_local, - tun_remote); + tun_local6, + &local, + &remote); if (tun_local) - management_post_tunnel_open (management, tun_local); + management_post_tunnel_open (management, *tun_local); } #endif } @@ -1335,12 +1351,12 @@ do_route (const struct options *options, { struct argv argv = argv_new (); setenv_str (es, "script_type", "route-up"); - argv_printf (&argv, "%sc", options->route_script); + argv_parse_cmd (&argv, options->route_script); openvpn_run_script (&argv, es, 0, "--route-up"); argv_reset (&argv); } -#ifdef WIN32 +#ifdef _WIN32 if (options->show_net_up) { show_routes (M_INFO|M_NOPREFIX); @@ -1355,21 +1371,6 @@ do_route (const struct options *options, } /* - * Save current pulled options string in the c1 context store, so we can - * compare against it after possible future restarts. - */ -#if P2MP -static void -save_pulled_options_digest (struct context *c, const struct md5_digest *newdigest) -{ - if (newdigest) - c->c1.pulled_options_digest_save = *newdigest; - else - md5_digest_clear (&c->c1.pulled_options_digest_save); -} -#endif - -/* * initialize tun/tap device object */ static void @@ -1383,14 +1384,11 @@ 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); - /* flag tunnel for IPv6 config if --tun-ipv6 is set */ - c->c1.tuntap->ipv6 = c->options.tun_ipv6; - init_tun_post (c->c1.tuntap, &c->c2.frame, &c->options.tuntap_options); @@ -1408,22 +1406,39 @@ do_open_tun (struct context *c) struct gc_arena gc = gc_new (); bool ret = false; - c->c2.ipv4_tun = (!c->options.tun_ipv6 - && is_dev_type (c->options.dev, c->options.dev_type, "tun")); - +#ifndef TARGET_ANDROID if (!c->c1.tuntap) { +#endif + +#ifdef TARGET_ANDROID + /* If we emulate persist-tun on android we still have to open a new tun and + * then close the old */ + int oldtunfd=-1; + if (c->c1.tuntap) + oldtunfd = c->c1.tuntap->fd; +#endif + /* initialize (but do not open) tun/tap object */ do_init_tun (c); +#ifdef _WIN32 + /* store (hide) interactive service handle in tuntap_options */ + c->c1.tuntap->options.msg_channel = c->options.msg_channel; + msg (D_ROUTE, "interactive service msg_channel=%u", (unsigned int) c->options.msg_channel); +#endif + /* allocate route list structure */ do_alloc_route_list (c); /* parse and resolve the route option list */ - if (c->options.routes && c->c1.route_list && c->c2.link_socket) - do_init_route_list (&c->options, c->c1.route_list, &c->c2.link_socket->info, false, c->c2.es); - if (c->options.routes_ipv6 && c->c1.route_ipv6_list ) - do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, false, c->c2.es); + ASSERT(c->c2.link_socket); + if (c->options.routes && c->c1.route_list) + do_init_route_list (&c->options, c->c1.route_list, + &c->c2.link_socket->info, c->c2.es); + if (c->options.routes_ipv6 && c->c1.route_ipv6_list) + do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, + &c->c2.link_socket->info, c->c2.es); /* do ifconfig */ if (!c->options.ifconfig_noexec @@ -1438,6 +1453,16 @@ do_open_tun (struct context *c) do_ifconfig (c->c1.tuntap, guess, TUN_MTU_SIZE (&c->c2.frame), c->c2.es); } + /* possibly add routes */ + if (route_order() == ROUTE_BEFORE_TUN) { + /* Ignore route_delay, would cause ROUTE_BEFORE_TUN to be ignored */ + do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list, + c->c1.tuntap, c->plugins, c->c2.es); + } +#ifdef TARGET_ANDROID + /* Store the old fd inside the fd so open_tun can use it */ + c->c1.tuntap->fd = oldtunfd; +#endif /* open the tun device */ open_tun (c->options.dev, c->options.dev_type, c->options.dev_node, c->c1.tuntap); @@ -1458,7 +1483,7 @@ do_open_tun (struct context *c) c->plugins, OPENVPN_PLUGIN_UP, c->c1.tuntap->actual_name, -#ifdef WIN32 +#ifdef _WIN32 c->c1.tuntap->adapter_index, #endif dev_type_string (c->options.dev, c->options.dev_type), @@ -1471,17 +1496,17 @@ do_open_tun (struct context *c) "up", c->c2.es); -#ifdef WIN32 +#if defined(_WIN32) if (c->options.block_outside_dns) { dmsg (D_LOW, "Blocking outside DNS"); - if (!win_wfp_block_dns(c->c1.tuntap->adapter_index)) + if (!win_wfp_block_dns(c->c1.tuntap->adapter_index, c->options.msg_channel)) msg (M_FATAL, "Blocking DNS failed!"); } #endif /* possibly add routes */ - if (!c->options.route_delay_defined) + if ((route_order() == ROUTE_AFTER_TUN) && (!c->options.route_delay_defined)) do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list, c->c1.tuntap, c->plugins, c->c2.es); @@ -1495,6 +1520,7 @@ do_open_tun (struct context *c) ret = true; static_context = c; +#ifndef TARGET_ANDROID } else { @@ -1510,7 +1536,7 @@ do_open_tun (struct context *c) c->plugins, OPENVPN_PLUGIN_UP, c->c1.tuntap->actual_name, -#ifdef WIN32 +#ifdef _WIN32 c->c1.tuntap->adapter_index, #endif dev_type_string (c->options.dev, c->options.dev_type), @@ -1522,7 +1548,17 @@ do_open_tun (struct context *c) NULL, "up", c->c2.es); +#if defined(_WIN32) + if (c->options.block_outside_dns) + { + dmsg (D_LOW, "Blocking outside DNS"); + if (!win_wfp_block_dns(c->c1.tuntap->adapter_index, c->options.msg_channel)) + msg (M_FATAL, "Blocking DNS failed!"); + } +#endif + } +#endif gc_free (&gc); return ret; } @@ -1539,7 +1575,7 @@ do_close_tun_simple (struct context *c) c->c1.tuntap = NULL; c->c1.tuntap_owned = false; #if P2MP - save_pulled_options_digest (c, NULL); /* delete C1-saved pulled_options_digest */ + CLEAR (c->c1.pulled_options_digest_save); #endif } @@ -1550,7 +1586,7 @@ do_close_tun (struct context *c, bool force) if (c->c1.tuntap && c->c1.tuntap_owned) { const char *tuntap_actual = string_alloc (c->c1.tuntap->actual_name, &gc); -#ifdef WIN32 +#ifdef _WIN32 DWORD adapter_index = c->c1.tuntap->adapter_index; #endif const in_addr_t local = c->c1.tuntap->local; @@ -1571,12 +1607,12 @@ do_close_tun (struct context *c, bool force) /* delete any routes we added */ if (c->c1.route_list || c->c1.route_ipv6_list ) - { + { run_up_down (c->options.route_predown_script, c->plugins, OPENVPN_PLUGIN_ROUTE_PREDOWN, tuntap_actual, -#ifdef WIN32 +#ifdef _WIN32 adapter_index, #endif NULL, @@ -1604,7 +1640,7 @@ do_close_tun (struct context *c, bool force) c->plugins, OPENVPN_PLUGIN_DOWN, tuntap_actual, -#ifdef WIN32 +#ifdef _WIN32 adapter_index, #endif NULL, @@ -1618,10 +1654,10 @@ do_close_tun (struct context *c, bool force) "down", c->c2.es); -#ifdef WIN32 +#if defined(_WIN32) if (c->options.block_outside_dns) { - if (!win_wfp_uninit()) + if (!win_wfp_uninit(c->options.msg_channel)) msg (M_FATAL, "Uninitialising WFP failed!"); } #endif @@ -1638,7 +1674,7 @@ do_close_tun (struct context *c, bool force) c->plugins, OPENVPN_PLUGIN_DOWN, tuntap_actual, -#ifdef WIN32 +#ifdef _WIN32 adapter_index, #endif NULL, @@ -1651,6 +1687,15 @@ do_close_tun (struct context *c, bool force) c->sig->signal_text), "down", c->c2.es); + +#if defined(_WIN32) + if (c->options.block_outside_dns) + { + if (!win_wfp_uninit(c->options.msg_channel)) + msg (M_FATAL, "Uninitialising WFP failed!"); + } +#endif + } } gc_free (&gc); @@ -1671,7 +1716,22 @@ tun_abort() * Handle delayed tun/tap interface bringup due to --up-delay or --pull */ -void +#if P2MP +/** + * Helper for do_up(). Take two option hashes and return true if they are not + * equal, or either one is all-zeroes. + */ +static bool +options_hash_changed_or_zero(const struct md5_digest *a, + const struct md5_digest *b) +{ + const struct md5_digest zero = {{0}}; + return memcmp (a, b, sizeof(struct md5_digest)) || + !memcmp (a, &zero, sizeof(struct md5_digest)); +} +#endif /* P2MP */ + +bool do_up (struct context *c, bool pulled_options, unsigned int option_types_found) { if (!c->c2.do_up_ran) @@ -1679,7 +1739,13 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found) reset_coarse_timers (c); if (pulled_options && option_types_found) - do_deferred_options (c, option_types_found); + { + if (!do_deferred_options (c, option_types_found)) + { + msg (D_PUSH_ERRORS, "ERROR: Failed to apply push options"); + return false; + } + } /* if --up-delay specified, open tun, do ifconfig, and run up script now */ if (c->options.up_delay || PULL_DEFINED (&c->options)) @@ -1695,8 +1761,8 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found) if (!c->c2.did_open_tun && PULL_DEFINED (&c->options) && c->c1.tuntap - && (!md5_digest_defined (&c->c1.pulled_options_digest_save) || !md5_digest_defined (&c->c2.pulled_options_digest) - || !md5_digest_equal (&c->c1.pulled_options_digest_save, &c->c2.pulled_options_digest))) + && options_hash_changed_or_zero (&c->c1.pulled_options_digest_save, + &c->c2.pulled_options_digest)) { /* if so, close tun, delete routes, then reinitialize tun and add routes */ msg (M_INFO, "NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device."); @@ -1711,11 +1777,11 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found) if (c->c2.did_open_tun) { #if P2MP - save_pulled_options_digest (c, &c->c2.pulled_options_digest); + c->c1.pulled_options_digest_save = c->c2.pulled_options_digest; #endif /* if --route-delay was specified, start timer */ - if (c->options.route_delay_defined) + if ((route_order() == ROUTE_AFTER_TUN) && c->options.route_delay_defined) { event_timeout_init (&c->c2.route_wakeup, c->options.route_delay, now); event_timeout_init (&c->c2.route_wakeup_expire, c->options.route_delay + c->options.route_delay_window, now); @@ -1734,6 +1800,7 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found) c->c2.do_up_ran = true; } + return true; } /* @@ -1761,13 +1828,18 @@ pull_permission_mask (const struct context *c) if (!c->options.route_nopull) flags |= (OPT_P_ROUTE | OPT_P_IPWIN32); +#ifdef ENABLE_CRYPTO + if (c->options.ncp_enabled) + flags |= OPT_P_NCP; +#endif + return flags; } /* * Handle non-tun-related pulled options. */ -void +bool do_deferred_options (struct context *c, const unsigned int found) { if (found & OPT_P_MESSAGES) @@ -1794,14 +1866,12 @@ do_deferred_options (struct context *c, const unsigned int found) } #endif -#ifdef ENABLE_LZO +#ifdef USE_COMP if (found & OPT_P_COMP) { - if (lzo_defined (&c->c2.lzo_compwork)) - { - msg (D_PUSH, "OPTIONS IMPORT: LZO parms modified"); - lzo_modify_flags (&c->c2.lzo_compwork, c->options.lzo); - } + msg (D_PUSH, "OPTIONS IMPORT: compression parms modified"); + comp_uninit (c->c2.comp_context); + c->c2.comp_context = comp_init (&c->options.comp); } #endif @@ -1836,7 +1906,7 @@ do_deferred_options (struct context *c, const unsigned int found) if (found & OPT_P_SETENV) msg (D_PUSH, "OPTIONS IMPORT: environment modified"); -#ifdef ENABLE_SSL +#ifdef ENABLE_CRYPTO if (found & OPT_P_PEER_ID) { msg (D_PUSH, "OPTIONS IMPORT: peer-id set"); @@ -1856,20 +1926,37 @@ do_deferred_options (struct context *c, const unsigned int found) " MTU problems", TUN_MTU_SIZE(&c->c2.frame) ); } } + + /* process (potentially pushed) crypto options */ + if (c->options.pull) + { + struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; + if (found & OPT_P_NCP) + msg (D_PUSH, "OPTIONS IMPORT: data channel crypto options modified"); + /* Do not regenerate keys if server sends an extra push request */ + if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized && + !tls_session_update_crypto_params(session, &c->options, &c->c2.frame)) + { + msg (D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options"); + return false; + } + } #endif + return true; } /* - * Possible hold on initialization + * Possible hold on initialization, holdtime is the + * time OpenVPN would wait without management */ static bool -do_hold (void) +do_hold (int holdtime) { #ifdef ENABLE_MANAGEMENT if (management) { /* block until management hold is released */ - if (management_hold (management)) + if (management_hold (management, holdtime)) return true; } #endif @@ -1882,31 +1969,16 @@ do_hold (void) static void socket_restart_pause (struct context *c) { - bool proxy = false; int sec = 2; - -#ifdef ENABLE_HTTP_PROXY - if (c->options.ce.http_proxy_options) - proxy = true; -#endif -#ifdef ENABLE_SOCKS - if (c->options.ce.socks_proxy_server) - proxy = true; -#endif + int backoff = 0; 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; } @@ -1919,13 +1991,22 @@ socket_restart_pause (struct context *c) #if P2MP if (auth_retry_get () == AR_NOINTERACT) sec = 10; - -#if 0 /* not really needed because of c->persist.restart_sleep_seconds */ - if (c->options.server_poll_timeout && sec > 1) - sec = 1; -#endif #endif + /* Slow down reconnection after 5 retries per remote -- for tcp only in client mode */ + if (c->options.ce.proto != PROTO_TCP_SERVER) + { + backoff = (c->options.unsuccessful_attempts / c->options.connection_list->len) - 4; + if (backoff > 0) + { + /* sec is less than 2^16; we can left shift it by up to 15 bits without overflow */ + sec = max_int (sec, 1) << min_int (backoff, 15); + } + + if (sec > c->options.ce.connect_retry_seconds_max) + sec = c->options.ce.connect_retry_seconds_max; + } + if (c->persist.restart_sleep_seconds > 0 && c->persist.restart_sleep_seconds > sec) sec = c->persist.restart_sleep_seconds; else if (c->persist.restart_sleep_seconds == -1) @@ -1933,8 +2014,10 @@ socket_restart_pause (struct context *c) c->persist.restart_sleep_seconds = 0; /* do managment hold on context restart, i.e. second, third, fourth, etc. initialization */ - if (do_hold ()) + if (do_hold (sec)) + { sec = 0; + } if (sec) { @@ -1952,7 +2035,7 @@ do_startup_pause (struct context *c) if (!c->first_time) socket_restart_pause (c); else - do_hold (); /* do management hold on first context initialization */ + do_hold (0); /* do management hold on first context initialization */ } /* @@ -1977,6 +2060,7 @@ frame_finalize_options (struct context *c, const struct options *o) |FRAME_HEADROOM_MARKER_READ_STREAM); } + frame_add_to_extra_buffer (&c->c2.frame, PAYLOAD_ALIGN); frame_finalize (&c->c2.frame, o->ce.link_mtu_defined, o->ce.link_mtu, @@ -1992,13 +2076,11 @@ key_schedule_free (struct key_schedule *ks, bool free_ssl_ctx) { #ifdef ENABLE_CRYPTO free_key_ctx_bi (&ks->static_key); -#ifdef ENABLE_SSL if (tls_ctx_initialised(&ks->ssl_ctx) && free_ssl_ctx) { tls_ctx_free (&ks->ssl_ctx); - free_key_ctx_bi (&ks->tls_auth_key); + free_key_ctx_bi (&ks->tls_wrap_key); } -#endif /* ENABLE_SSL */ #endif /* ENABLE_CRYPTO */ CLEAR (*ks); } @@ -2018,14 +2100,6 @@ init_crypto_pre (struct context *c, const unsigned int flags) packet_id_persist_load (&c->c1.pid_persist, c->options.packet_id_file); } - /* Initialize crypto options */ - - if (c->options.use_iv) - c->c2.crypto_options.flags |= CO_USE_IV; - - if (c->options.mute_replay_warnings) - c->c2.crypto_options.flags |= CO_MUTE_REPLAY_WARNINGS; - #ifdef ENABLE_PREDICTION_RESISTANCE if (c->options.use_prediction_resistance) rand_ctx_enable_prediction_resistance(); @@ -2044,60 +2118,38 @@ do_init_crypto_static (struct context *c, const unsigned int flags) init_crypto_pre (c, flags); + /* Initialize flags */ + if (c->options.use_iv) + c->c2.crypto_options.flags |= CO_USE_IV; + + if (c->options.mute_replay_warnings) + c->c2.crypto_options.flags |= CO_MUTE_REPLAY_WARNINGS; + /* Initialize packet ID tracking */ if (options->replay) { - packet_id_init (&c->c2.packet_id, - link_socket_proto_connection_oriented (options->ce.proto), + packet_id_init (&c->c2.crypto_options.packet_id, options->replay_window, options->replay_time, "STATIC", 0); - c->c2.crypto_options.packet_id = &c->c2.packet_id; c->c2.crypto_options.pid_persist = &c->c1.pid_persist; c->c2.crypto_options.flags |= CO_PACKET_ID_LONG_FORM; packet_id_persist_load_obj (&c->c1.pid_persist, - c->c2.crypto_options.packet_id); + &c->c2.crypto_options.packet_id); } if (!key_ctx_bi_defined (&c->c1.ks.static_key)) { - struct key2 key2; - struct key_direction_state kds; - /* Get cipher & hash algorithms */ - init_key_type (&c->c1.ks.key_type, options->ciphername, - options->ciphername_defined, options->authname, - options->authname_defined, options->keysize, - options->test_crypto, true); + init_key_type (&c->c1.ks.key_type, options->ciphername, options->authname, + options->keysize, options->test_crypto, true); /* Read cipher and hmac keys from shared secret file */ - { - unsigned int rkf_flags = RKF_MUST_SUCCEED; - const char *rkf_file = options->shared_secret_file; - - if (options->shared_secret_file_inline) - { - rkf_file = options->shared_secret_file_inline; - rkf_flags |= RKF_INLINE; - } - read_key_file (&key2, rkf_file, rkf_flags); - } - - /* Check for and fix highly unlikely key problems */ - verify_fix_key2 (&key2, &c->c1.ks.key_type, - options->shared_secret_file); - - /* Initialize OpenSSL key objects */ - key_direction_state_init (&kds, options->key_direction); - must_have_n_keys (options->shared_secret_file, "secret", &key2, - kds.need_keys); - init_key_ctx (&c->c1.ks.static_key.encrypt, &key2.keys[kds.out_key], - &c->c1.ks.key_type, OPENVPN_OP_ENCRYPT, "Static Encrypt"); - init_key_ctx (&c->c1.ks.static_key.decrypt, &key2.keys[kds.in_key], - &c->c1.ks.key_type, OPENVPN_OP_DECRYPT, "Static Decrypt"); - - /* Erase the temporary copy of key */ - CLEAR (key2); + crypto_read_openvpn_key (&c->c1.ks.key_type, &c->c1.ks.static_key, + options->shared_secret_file, + options->shared_secret_file_inline, + options->key_direction, "Static Key Encryption", + "secret"); } else { @@ -2105,12 +2157,11 @@ do_init_crypto_static (struct context *c, const unsigned int flags) } /* Get key schedule */ - c->c2.crypto_options.key_ctx_bi = &c->c1.ks.static_key; + c->c2.crypto_options.key_ctx_bi = c->c1.ks.static_key; /* Compute MTU parameters */ crypto_adjust_frame_parameters (&c->c2.frame, &c->c1.ks.key_type, - options->ciphername_defined, options->use_iv, options->replay, true); /* Sanity check on IV, sequence number, and cipher mode options */ @@ -2118,8 +2169,6 @@ do_init_crypto_static (struct context *c, const unsigned int flags) options->use_iv); } -#ifdef ENABLE_SSL - /* * Initialize the persistent component of OpenVPN's TLS mode, * which is preserved across SIGUSR1 resets. @@ -2160,9 +2209,8 @@ do_init_crypto_tls_c1 (struct context *c) } /* Get cipher & hash algorithms */ - init_key_type (&c->c1.ks.key_type, options->ciphername, - options->ciphername_defined, options->authname, - options->authname_defined, options->keysize, true, true); + init_key_type (&c->c1.ks.key_type, options->ciphername, options->authname, + options->keysize, true, true); /* Initialize PRNG with config-specified digest */ prng_init (options->prng_hash, options->prng_nonce_secret_len); @@ -2170,21 +2218,36 @@ do_init_crypto_tls_c1 (struct context *c) /* TLS handshake authentication (--tls-auth) */ if (options->tls_auth_file) { - unsigned int flags = 0; - const char *file = options->tls_auth_file; - - if (options->tls_auth_file_inline) + /* Initialize key_type for tls-auth with auth only */ + CLEAR (c->c1.ks.tls_auth_key_type); + if (!streq (options->authname, "none")) { - flags |= GHK_INLINE; - file = options->tls_auth_file_inline; + c->c1.ks.tls_auth_key_type.digest = md_kt_get (options->authname); + c->c1.ks.tls_auth_key_type.hmac_length = + md_kt_size (c->c1.ks.tls_auth_key_type.digest); } - get_tls_handshake_key (&c->c1.ks.key_type, - &c->c1.ks.tls_auth_key, - file, - options->key_direction, - flags); + else + { + msg (M_FATAL, "ERROR: tls-auth enabled, but no valid --auth " + "algorithm specified ('%s')", options->authname); + } + + crypto_read_openvpn_key (&c->c1.ks.tls_auth_key_type, + &c->c1.ks.tls_wrap_key, options->tls_auth_file, + options->tls_auth_file_inline, options->key_direction, + "Control Channel Authentication", "tls-auth"); } + /* TLS handshake encryption+authentication (--tls-crypt) */ + if (options->tls_crypt_file) { + tls_crypt_init_key (&c->c1.ks.tls_wrap_key, options->tls_crypt_file, + options->tls_crypt_inline, options->tls_server); + } + + c->c1.ciphername = options->ciphername; + c->c1.authname = options->authname; + c->c1.keysize = options->keysize; + #if 0 /* was: #if ENABLE_INLINE_FILES -- Note that enabling this code will break restarts */ if (options->priv_key_file_inline) { @@ -2196,6 +2259,11 @@ do_init_crypto_tls_c1 (struct context *c) else { msg (D_INIT_MEDIUM, "Re-using SSL/TLS context"); + + /* Restore pre-NCP cipher options */ + c->options.ciphername = c->c1.ciphername; + c->options.authname = c->c1.authname; + c->options.keysize = c->c1.keysize; } } @@ -2226,17 +2294,28 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) /* In short form, unique datagram identifier is 32 bits, in long form 64 bits */ packet_id_long_form = cipher_kt_mode_ofb_cfb (c->c1.ks.key_type.cipher); - /* Compute MTU parameters */ - crypto_adjust_frame_parameters (&c->c2.frame, - &c->c1.ks.key_type, - options->ciphername_defined, - options->use_iv, - options->replay, packet_id_long_form); + /* Compute MTU parameters (postpone if we push/pull options) */ + if (c->options.pull || c->options.mode == MODE_SERVER) + { + /* Account for worst-case crypto overhead before allocating buffers */ + frame_add_to_extra_frame (&c->c2.frame, crypto_max_overhead()); + } + else + { + crypto_adjust_frame_parameters(&c->c2.frame, &c->c1.ks.key_type, + options->use_iv, options->replay, packet_id_long_form); + } tls_adjust_frame_parameters (&c->c2.frame); /* Set all command-line TLS-related options */ CLEAR (to); + if (options->use_iv) + to.crypto_flags |= CO_USE_IV; + + if (options->mute_replay_warnings) + to.crypto_flags |= CO_MUTE_REPLAY_WARNINGS; + to.crypto_flags_and = ~(CO_PACKET_ID_LONG_FORM); if (packet_id_long_form) to.crypto_flags_or = CO_PACKET_ID_LONG_FORM; @@ -2249,6 +2328,9 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.replay_window = options->replay_window; to.replay_time = options->replay_time; to.tcp_mode = link_socket_proto_connection_oriented (options->ce.proto); + to.config_ciphername = c->c1.ciphername; + to.config_authname = c->c1.authname; + to.ncp_enabled = options->ncp_enabled; to.transition_window = options->transition_window; to.handshake_window = options->handshake_window; to.packet_timeout = options->tls_timeout; @@ -2256,6 +2338,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.renegotiate_packets = options->renegotiate_packets; to.renegotiate_seconds = options->renegotiate_seconds; to.single_session = options->single_session; + to.mode = options->mode; + to.pull = options->pull; #ifdef ENABLE_PUSH_PEER_INFO if (options->push_peer_info) /* all there is */ to.push_peer_info_detail = 2; @@ -2267,7 +2351,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 @@ -2279,6 +2363,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.verify_x509_type = (options->verify_x509_type & 0xff); to.verify_x509_name = options->verify_x509_name; to.crl_file = options->crl_file; + to.crl_file_inline = options->crl_file_inline; to.ssl_flags = options->ssl_flags; to.ns_cert_type = options->ns_cert_type; memmove (to.remote_cert_ku, options->remote_cert_ku, sizeof (to.remote_cert_ku)); @@ -2308,11 +2393,11 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) if (options->ccd_exclusive) to.client_config_dir_exclusive = options->client_config_dir; to.auth_user_pass_file = options->auth_user_pass_file; + to.auth_token_generate = options->auth_token_generate; + to.auth_token_lifetime = options->auth_token_lifetime; #endif -#ifdef ENABLE_X509_TRACK to.x509_track = options->x509_track; -#endif #if P2MP #ifdef ENABLE_CLIENT_CR @@ -2320,15 +2405,46 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) #endif #endif +#ifdef USE_COMP + to.comp_options = options->comp; +#endif + +#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000 + if (options->keying_material_exporter_label) + { + to.ekm_size = options->keying_material_exporter_length; + if (to.ekm_size < 16 || to.ekm_size > 4095) + to.ekm_size = 0; + + to.ekm_label = options->keying_material_exporter_label; + to.ekm_label_size = strlen(to.ekm_label); + } + else + { + to.ekm_size = 0; + } +#endif + /* TLS handshake authentication (--tls-auth) */ if (options->tls_auth_file) { - to.tls_auth_key = c->c1.ks.tls_auth_key; - to.tls_auth.pid_persist = &c->c1.pid_persist; - to.tls_auth.flags |= CO_PACKET_ID_LONG_FORM; + to.tls_wrap.mode = TLS_WRAP_AUTH; + to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key; + to.tls_wrap.opt.pid_persist = &c->c1.pid_persist; + to.tls_wrap.opt.flags |= CO_PACKET_ID_LONG_FORM; crypto_adjust_frame_parameters (&to.frame, - &c->c1.ks.key_type, - false, false, true, true); + &c->c1.ks.tls_auth_key_type, + false, true, true); + } + + /* TLS handshake encryption (--tls-crypt) */ + if (options->tls_crypt_file) + { + to.tls_wrap.mode = TLS_WRAP_CRYPT; + to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key; + to.tls_wrap.opt.pid_persist = &c->c1.pid_persist; + to.tls_wrap.opt.flags |= CO_PACKET_ID_LONG_FORM; + tls_crypt_adjust_frame_parameters (&to.frame); } /* If we are running over TCP, allow for @@ -2364,10 +2480,6 @@ do_init_finalize_tls_frame (struct context *c) } } -#endif /* ENABLE_SSL */ -#endif /* ENABLE_CRYPTO */ - -#ifdef ENABLE_CRYPTO /* * No encryption or authentication. */ @@ -2386,54 +2498,70 @@ do_init_crypto (struct context *c, const unsigned int flags) #ifdef ENABLE_CRYPTO if (c->options.shared_secret_file) do_init_crypto_static (c, flags); -#ifdef ENABLE_SSL else if (c->options.tls_server || c->options.tls_client) do_init_crypto_tls (c, flags); -#endif else /* no encryption or authentication. */ do_init_crypto_none (c); #else /* ENABLE_CRYPTO */ msg (M_WARN, "******* WARNING *******: " PACKAGE_NAME - " built without OpenSSL -- encryption and authentication features disabled -- all data will be tunnelled as cleartext"); + " built without crypto library -- encryption and authentication features disabled -- all data will be tunnelled as cleartext"); #endif /* ENABLE_CRYPTO */ } static void do_init_frame (struct context *c) { -#ifdef ENABLE_LZO +#ifdef USE_COMP /* - * Initialize LZO compression library. + * modify frame parameters if compression is enabled */ - if (c->options.lzo & LZO_SELECTED) + if (comp_enabled(&c->options.comp)) { - lzo_adjust_frame_parameters (&c->c2.frame); + comp_add_to_extra_frame (&c->c2.frame); +#if !defined(ENABLE_LZ4) /* - * LZO usage affects buffer alignment. + * Compression usage affects buffer alignment when non-swapped algs + * such as LZO is used. + * Newer algs like LZ4 and comp-stub with COMP_F_SWAP don't need + * any special alignment because of the control-byte swap approach. + * LZO alignment (on the other hand) is problematic because + * the presence of the control byte means that either the output of + * decryption must be written to an unaligned buffer, or the input + * to compression (or packet dispatch if packet is uncompressed) + * must be read from an unaligned buffer. + * This code tries to align the input to compression (or packet + * dispatch if packet is uncompressed) at the cost of requiring + * decryption output to be written to an unaligned buffer, so + * it's more of a tradeoff than an optimal solution and we don't + * include it when we are doing a modern build with LZ4. + * Strictly speaking, on the server it would be better to execute + * this code for every connection after we decide the compression + * method, but currently the frame code doesn't appear to be + * flexible enough for this, since the frame is already established + * before it is known which compression options will be pushed. */ - if (CIPHER_ENABLED (c)) + if (comp_unswapped_prefix (&c->options.comp) && CIPHER_ENABLED (c)) { - frame_add_to_align_adjust (&c->c2.frame, LZO_PREFIX_LEN); + frame_add_to_align_adjust (&c->c2.frame, COMP_PREFIX_LEN); frame_or_align_flags (&c->c2.frame, FRAME_HEADROOM_MARKER_FRAGMENT |FRAME_HEADROOM_MARKER_DECRYPT); } +#endif #ifdef ENABLE_FRAGMENT - lzo_adjust_frame_parameters (&c->c2.frame_fragment_omit); /* omit LZO frame delta from final frame_fragment */ + comp_add_to_extra_frame (&c->c2.frame_fragment_omit); /* omit compression frame delta from final frame_fragment */ #endif } -#endif /* ENABLE_LZO */ +#endif /* USE_COMP */ -#ifdef ENABLE_SOCKS /* * Adjust frame size for UDP Socks support. */ if (c->options.ce.socks_proxy_server) socks_adjust_frame_parameters (&c->c2.frame, c->options.ce.proto); -#endif /* * Adjust frame size based on the --tun-mtu-extra parameter. @@ -2454,16 +2582,27 @@ do_init_frame (struct context *c) */ frame_finalize_options (c, NULL); +#ifdef USE_COMP + /* + * Modify frame parameters if compression is compiled in. + * Should be called after frame_finalize_options. + */ + comp_add_to_extra_buffer (&c->c2.frame); +#ifdef ENABLE_FRAGMENT + comp_add_to_extra_buffer (&c->c2.frame_fragment_omit); /* omit compression frame delta from final frame_fragment */ +#endif +#endif /* USE_COMP */ + /* packets with peer-id (P_DATA_V2) need 3 extra bytes in frame (on client) * and need link_mtu+3 bytes on socket reception (on server). * - * accomodate receive path in f->extra_link - * send path in f->extra_buffer (+leave room for alignment) + * accomodate receive path in f->extra_link, which has the side effect of + * also increasing send buffers (BUF_SIZE() macro), which need to be + * allocated big enough before receiving peer-id option from server. * * f->extra_frame is adjusted when peer-id option is push-received */ frame_add_to_extra_link(&c->c2.frame, 3); - frame_add_to_extra_buffer(&c->c2.frame, 8); #ifdef ENABLE_FRAGMENT /* @@ -2546,7 +2685,6 @@ do_option_warnings (struct context *c) if (!o->use_iv) msg (M_WARN, "WARNING: You have disabled Crypto IVs (--no-iv) which may make " PACKAGE_NAME " less secure"); -#ifdef ENABLE_SSL if (o->tls_server) warn_on_use_of_common_subnets (); if (o->tls_client @@ -2556,12 +2694,6 @@ do_option_warnings (struct context *c) && !o->remote_cert_eku) msg (M_WARN, "WARNING: No server certificate verification method has been enabled. See http://openvpn.net/howto.html#mitm for more info."); #endif -#endif - -#ifndef CONNECT_NONBLOCK - if (o->ce.connect_timeout_defined) - msg (M_WARN, "NOTE: --connect-timeout option is not supported on this OS"); -#endif /* If a script is used, print appropiate warnings */ if (o->user_script_used) @@ -2578,7 +2710,7 @@ do_option_warnings (struct context *c) static void do_init_frame_tls (struct context *c) { -#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) +#ifdef ENABLE_CRYPTO do_init_finalize_tls_frame (c); #endif } @@ -2600,9 +2732,9 @@ init_context_buffers (const struct frame *frame) b->decrypt_buf = alloc_buf (BUF_SIZE (frame)); #endif -#ifdef ENABLE_LZO - b->lzo_compress_buf = alloc_buf (BUF_SIZE (frame)); - b->lzo_decompress_buf = alloc_buf (BUF_SIZE (frame)); +#ifdef USE_COMP + b->compress_buf = alloc_buf (BUF_SIZE (frame)); + b->decompress_buf = alloc_buf (BUF_SIZE (frame)); #endif return b; @@ -2617,9 +2749,9 @@ free_context_buffers (struct context_buffers *b) free_buf (&b->read_tun_buf); free_buf (&b->aux_buf); -#ifdef ENABLE_LZO - free_buf (&b->lzo_compress_buf); - free_buf (&b->lzo_decompress_buf); +#ifdef USE_COMP + free_buf (&b->compress_buf); + free_buf (&b->decompress_buf); #endif #ifdef ENABLE_CRYPTO @@ -2658,19 +2790,6 @@ do_init_fragment (struct context *c) #endif /* - * Set the --mssfix option. - */ -static void -do_init_mssfix (struct context *c) -{ - if (c->options.ce.mssfix) - { - frame_set_mtu_dynamic (&c->c2.frame, - c->options.ce.mssfix, SET_MTU_UPPER_BOUND); - } -} - -/* * Allocate our socket object. */ static void @@ -2695,20 +2814,18 @@ 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->c1.dns_cache, c->options.ce.proto, + c->options.ce.af, + c->options.ce.bind_ipv6_only, mode, c->c2.accept_from, -#ifdef ENABLE_HTTP_PROXY c->c1.http_proxy, -#endif -#ifdef ENABLE_SOCKS c->c1.socks_proxy, -#endif #ifdef ENABLE_DEBUG c->options.gremlin, #endif @@ -2719,13 +2836,11 @@ 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, c->options.mark, + &c->c2.server_poll_interval, sockflags); } @@ -2736,7 +2851,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); } /* @@ -2767,22 +2882,14 @@ do_compute_occ_strings (struct context *c) c->c2.options_string_remote = options_string (&c->options, &c->c2.frame, c->c1.tuntap, true, &gc); - msg (D_SHOW_OCC, "Local Options String: '%s'", c->c2.options_string_local); - msg (D_SHOW_OCC, "Expected Remote Options String: '%s'", - c->c2.options_string_remote); + msg (D_SHOW_OCC, "Local Options String (VER=%s): '%s'", + options_string_version (c->c2.options_string_local, &gc), + c->c2.options_string_local); + msg (D_SHOW_OCC, "Expected Remote Options String (VER=%s): '%s'", + options_string_version (c->c2.options_string_remote, &gc), + c->c2.options_string_remote); #ifdef ENABLE_CRYPTO - msg (D_SHOW_OCC_HASH, "Local Options hash (VER=%s): '%s'", - options_string_version (c->c2.options_string_local, &gc), - md5sum ((uint8_t*)c->c2.options_string_local, - strlen (c->c2.options_string_local), 9, &gc)); - msg (D_SHOW_OCC_HASH, "Expected Remote Options hash (VER=%s): '%s'", - options_string_version (c->c2.options_string_remote, &gc), - md5sum ((uint8_t*)c->c2.options_string_remote, - strlen (c->c2.options_string_remote), 9, &gc)); -#endif - -#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) if (c->c2.tls_multi) tls_multi_init_set_options (c->c2.tls_multi, c->c2.options_string_local, @@ -2859,7 +2966,7 @@ do_close_free_buf (struct context *c) static void do_close_tls (struct context *c) { -#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) +#ifdef ENABLE_CRYPTO if (c->c2.tls_multi) { tls_multi_free (c->c2.tls_multi, true); @@ -2899,14 +3006,31 @@ 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, !c->options.resolve_in_advance); + } + + /* 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 && !c->options.resolve_in_advance) + freeaddrinfo(c->c1.link_socket_addr.bind_local); + + c->c1.link_socket_addr.bind_local=NULL; + } } /* @@ -2916,7 +3040,7 @@ static void do_close_packet_id (struct context *c) { #ifdef ENABLE_CRYPTO - packet_id_free (&c->c2.packet_id); + packet_id_free (&c->c2.crypto_options.packet_id); packet_id_persist_save (&c->c1.pid_persist); if (!(c->sig->signal_received == SIGUSR1)) packet_id_persist_close (&c->c1.pid_persist); @@ -3070,7 +3194,7 @@ do_setup_fast_io (struct context *c) { if (c->options.fast_io) { -#ifdef WIN32 +#ifdef _WIN32 msg (M_INFO, "NOTE: --fast-io is disabled since we are running on Windows"); #else if (!proto_is_udp(c->options.ce.proto)) @@ -3093,7 +3217,7 @@ do_setup_fast_io (struct context *c) static void do_signal_on_tls_errors (struct context *c) { -#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) +#ifdef ENABLE_CRYPTO if (c->options.tls_exit) c->c2.tls_exit_signal = SIGTERM; else @@ -3183,7 +3307,7 @@ management_callback_status_p2p (void *arg, const int version, struct status_outp void management_show_net_callback (void *arg, const int msglevel) { -#ifdef WIN32 +#ifdef _WIN32 show_routes (msglevel); show_adapters (msglevel); msg (msglevel, "END"); @@ -3192,6 +3316,37 @@ management_show_net_callback (void *arg, const int msglevel) #endif } +#ifdef TARGET_ANDROID +int +management_callback_network_change (void *arg, bool samenetwork) +{ + /* Check if the client should translate the network change to a SIGUSR1 to + reestablish the connection or just reprotect the socket + + At the moment just assume that, for all settings that use pull (not + --static) and are not using peer-id reestablishing the connection is + required (unless the network is the same) + + The function returns -1 on invalid fd and -2 if the socket cannot be + reused. On the -2 return value the man_network_change function triggers + a SIGUSR1 to force a reconnect. + */ + + int socketfd=-1; + struct context *c = (struct context *) arg; + if (!c->c2.link_socket) + return -1; + if (c->c2.link_socket->sd == SOCKET_UNDEFINED) + return -1; + + socketfd = c->c2.link_socket->sd; + if (!c->options.pull || c->c2.tls_multi->use_peer_id || samenetwork) + return socketfd; + else + return -2; +} +#endif + #endif void @@ -3207,6 +3362,9 @@ init_management_callback_p2p (struct context *c) cb.show_net = management_show_net_callback; cb.proxy_cmd = management_callback_proxy_cmd; cb.remote_cmd = management_callback_remote_cmd; +#ifdef TARGET_ANDROID + cb.network_change = management_callback_network_change; +#endif management_set_callback (management, &cb); } #endif @@ -3248,12 +3406,14 @@ open_management (struct context *c) management_set_state (management, OPENVPN_STATE_CONNECTING, NULL, - (in_addr_t)0, - (in_addr_t)0); + NULL, + NULL, + NULL, + NULL); } /* initial management hold, called early, before first context initialization */ - do_hold (); + do_hold (0); if (IS_SIG (c)) { msg (M_WARN, "Signal received from management interface, exiting"); @@ -3326,10 +3486,14 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int /* init garbage collection level */ gc_init (&c->c2.gc); + /* inherit environmental variables */ + if (env) + do_inherit_env (c, env); + /* 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); @@ -3342,14 +3506,20 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int goto sig; } + if (c->options.resolve_in_advance) + { + do_preresolve (c); + if (IS_SIG (c)) + goto sig; + } + /* 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.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; @@ -3378,10 +3548,6 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int if (c->mode == CM_P2P || c->mode == CM_TOP) do_option_warnings (c); - /* inherit environmental variables */ - if (env) - do_inherit_env (c, env); - #ifdef ENABLE_PLUGIN /* initialize plugins */ if (c->mode == CM_P2P || c->mode == CM_TOP) @@ -3416,7 +3582,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) @@ -3442,10 +3608,10 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int goto sig; } -#ifdef ENABLE_LZO - /* initialize LZO compression library. */ - if ((options->lzo & LZO_SELECTED) && (c->mode == CM_P2P || child)) - lzo_compress_init (&c->c2.lzo_compwork, options->lzo); +#ifdef USE_COMP + /* initialize compression library. */ + if (comp_enabled(&options->comp) && (c->mode == CM_P2P || child)) + c->c2.comp_context = comp_init (&options->comp); #endif /* initialize MTU variables */ @@ -3465,7 +3631,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int #endif /* initialize dynamic MTU variable */ - do_init_mssfix (c); + frame_init_mssfix (&c->c2.frame, &c->options); /* bind the TCP/UDP socket */ if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) @@ -3498,16 +3664,19 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int open_plugins (c, false, OPENVPN_PLUGIN_INIT_POST_DAEMON); #endif + /* initialise connect timeout timer */ + do_init_server_poll_timeout(c); + + /* finalize the TCP/UDP socket */ + if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) + do_init_socket_2 (c); + /* * Actually do UID/GID downgrade, and chroot, if requested. * May be delayed by --client, --pull, or --up-delay. */ do_uid_gid_chroot (c, c->c2.did_open_tun); - /* finalize the TCP/UDP socket */ - if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) - do_init_socket_2 (c); - /* initialize timers */ if (c->mode == CM_P2P || child) do_init_timers (c, false); @@ -3559,9 +3728,12 @@ close_instance (struct context *c) /* if xinetd/inetd mode, don't allow restart */ do_close_check_if_restart_permitted (c); -#ifdef ENABLE_LZO - if (lzo_defined (&c->c2.lzo_compwork)) - lzo_compress_uninit (&c->c2.lzo_compwork); +#ifdef USE_COMP + if (c->c2.comp_context) + { + comp_uninit (c->c2.comp_context); + c->c2.comp_context = NULL; + } #endif /* free buffers */ @@ -3636,11 +3808,14 @@ inherit_context_child (struct context *dest, #ifdef ENABLE_CRYPTO dest->c1.ks.key_type = src->c1.ks.key_type; -#ifdef ENABLE_SSL /* inherit SSL context */ dest->c1.ks.ssl_ctx = src->c1.ks.ssl_ctx; - dest->c1.ks.tls_auth_key = src->c1.ks.tls_auth_key; -#endif + dest->c1.ks.tls_wrap_key = src->c1.ks.tls_wrap_key; + dest->c1.ks.tls_auth_key_type = src->c1.ks.tls_auth_key_type; + /* inherit pre-NCP ciphers */ + dest->c1.ciphername = src->c1.ciphername; + dest->c1.authname = src->c1.authname; + dest->c1.keysize = src->c1.keysize; #endif /* options */ @@ -3713,7 +3888,7 @@ inherit_context_top (struct context *dest, /* detach plugins */ dest->plugins_owned = false; -#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) +#ifdef ENABLE_CRYPTO dest->c2.tls_multi = NULL; #endif @@ -3733,6 +3908,10 @@ inherit_context_top (struct context *dest, dest->c2.event_set = NULL; if (proto_is_dgram(src->options.ce.proto)) do_event_set_init (dest, false); + +#ifdef USE_COMP + dest->c2.comp_context = NULL; +#endif } void @@ -3747,8 +3926,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)) @@ -3773,6 +3955,7 @@ test_crypto_thread (void *arg) ASSERT (options->test_crypto); init_verb_mute (c, IVM_LEVEL_1); context_init_1 (c); + next_connection_entry(c); do_init_crypto_static (c, 0); frame_finalize_options (c, options); @@ -3780,13 +3963,13 @@ test_crypto_thread (void *arg) test_crypto (&c->c2.crypto_options, &c->c2.frame); key_schedule_free (&c->c1.ks, true); - packet_id_free (&c->c2.packet_id); + packet_id_free (&c->c2.crypto_options.packet_id); context_gc_free (c); return NULL; } -#endif +#endif /* ENABLE_CRYPTO */ bool do_test_crypto (const struct options *o) |