Message ID | 20181121101019.1801-2-arne@rfc2549.org |
---|---|
State | Superseded |
Delegated to: | Antonio Quartulli |
Headers | show |
Series | Deferred client-connect patch set | expand |
Hi, On 21/11/2018 11:10, Arne Schwabe wrote: > From: Fabian Knittel <fabian.knittel@lettink.de> > > This patch splits up the multi_connection_established() function. Each new > helper function does a specific job. Functions that do a similar job receive a > similar calling interface. > > The patch tries not to reindent code, so that the real changes are as clearly > visible as possible. (A follow-up patch will only do indentation changes.) > > Signed-off-by: Fabian Knittel <fabian.knittel@lettink.de> > > PATCH v3: Since the code has changed enough from the time the original patch > to the current master, the splitting has been redone from the current code. > Also some style and minor code changes have been added doing this patch. > This elimininates and the big reformatting done before eliminates the follow > up patch with indentation changes. > > The original patch already replaces some instances of option_permission_mask > with CLIENT_CONNECT_OPT_MASK. The V3 version does this more consequently. > Did you mean "more consistently" ? > Signed-off-by: Arne Schwabe <arne@rfc2549.org> > --- I have some comments below > src/openvpn/multi.c | 597 +++++++++++++++++++++++++------------------- > src/openvpn/multi.h | 4 +- > 2 files changed, 346 insertions(+), 255 deletions(-) > > diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c > index 8440f311..a4b62151 100644 > --- a/src/openvpn/multi.c > +++ b/src/openvpn/multi.c > @@ -1638,7 +1638,6 @@ static void > multi_client_connect_post(struct multi_context *m, > struct multi_instance *mi, > const char *dc_file, > - unsigned int option_permissions_mask, > unsigned int *option_types_found) > { > /* Did script generate a dynamic config file? */ > @@ -1647,7 +1646,7 @@ multi_client_connect_post(struct multi_context *m, > options_server_import(&mi->context.options, > dc_file, > D_IMPORT_ERRORS|M_OPTERR, > - option_permissions_mask, > + CLIENT_CONNECT_OPT_MASK, every invocation of options_server_import() gets CLIENT_CONNECT_OPT_MASK as parameter. Do we really need it to be a parameter? I am also thinking whether a change like this may be worth its own commit (it's unrelated to the commit except that it touches similar code and could be easier to review/merge). > option_types_found, > mi->context.c2.es); > > @@ -1671,7 +1670,6 @@ static void > multi_client_connect_post_plugin(struct multi_context *m, > struct multi_instance *mi, > const struct plugin_return *pr, > - unsigned int option_permissions_mask, > unsigned int *option_types_found) > { > struct plugin_return config; > @@ -1689,7 +1687,7 @@ multi_client_connect_post_plugin(struct multi_context *m, > options_string_import(&mi->context.options, > config.list[i]->value, > D_IMPORT_ERRORS|M_OPTERR, > - option_permissions_mask, > + CLIENT_CONNECT_OPT_MASK, > option_types_found, > mi->context.c2.es); > } > @@ -1716,21 +1714,19 @@ multi_client_connect_post_plugin(struct multi_context *m, > static void > multi_client_connect_mda(struct multi_context *m, > struct multi_instance *mi, > - const struct buffer_list *config, > - unsigned int option_permissions_mask, > unsigned int *option_types_found) > { > - if (config) > + if (mi->cc_config) Also getting rid of config and using mi->cc_config looks like something that could go in its own patch, as it is quite unrelated. > { > struct buffer_entry *be; > > - for (be = config->head; be != NULL; be = be->next) > + for (be = mi->cc_config->head; be != NULL; be = be->next) > { > const char *opt = BSTR(&be->buf); > options_string_import(&mi->context.options, > opt, > D_IMPORT_ERRORS|M_OPTERR, > - option_permissions_mask, > + CLIENT_CONNECT_OPT_MASK, > option_types_found, > mi->context.c2.es); > } > @@ -1773,215 +1769,386 @@ multi_client_connect_setenv(struct multi_context *m, > gc_free(&gc); > } > > -/* > - * Called as soon as the SSL/TLS connection authenticates. > - * > - * Instance-specific directives to be processed: > - * > - * iroute start-ip end-ip > - * ifconfig-push local remote-netmask > - * push > - */ > static void > -multi_connection_established(struct multi_context *m, struct multi_instance *mi) > +multi_client_connect_call_plugin_v1(struct multi_context *m, > + struct multi_instance *mi, > + unsigned int *option_types_found, > + int *cc_succeeded, > + int *cc_succeeded_count) > { > - if (tls_authentication_status(mi->context.c2.tls_multi, 0) == TLS_AUTHENTICATION_SUCCEEDED) > +#ifdef ENABLE_PLUGIN > + ASSERT(m); > + ASSERT(mi); > + ASSERT(option_types_found); > + ASSERT(cc_succeeded); > + ASSERT(cc_succeeded_count); > + > + /* deprecated callback, use a file for passing back return info */ > + if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) > { > + struct argv argv = argv_new(); > struct gc_arena gc = gc_new(); > - unsigned int option_types_found = 0; > + const char *dc_file = > + platform_create_temp_file(mi->context.options.tmp_dir, "cc", &gc); > > - const unsigned int option_permissions_mask = > - OPT_P_INSTANCE > - | OPT_P_INHERIT > - | OPT_P_PUSH > - | OPT_P_TIMER > - | OPT_P_CONFIG > - | OPT_P_ECHO > - | OPT_P_COMP > - | OPT_P_SOCKFLAGS; > + if (!dc_file) > + { > + cc_succeeded = false; > + goto cleanup; > + } > > - int cc_succeeded = true; /* client connect script status */ > - int cc_succeeded_count = 0; > + argv_printf(&argv, "%s", dc_file); > + if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, > + &argv, NULL, mi->context.c2.es) > + != OPENVPN_PLUGIN_FUNC_SUCCESS) > + { > + msg(M_WARN, "WARNING: client-connect plugin call failed"); > + *cc_succeeded = false; > + } > + else > + { > + multi_client_connect_post(m, mi, dc_file, option_types_found); > + (*cc_succeeded_count)++; > + } > + > + { > + msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", > + dc_file); > + } > + > +cleanup: > + argv_reset(&argv); > + gc_free(&gc); > + } > +#endif /* ifdef ENABLE_PLUGIN */ > +} > > - ASSERT(mi->context.c1.tuntap); > +static void > +multi_client_connect_call_plugin_v2(struct multi_context *m, > + struct multi_instance *mi, > + unsigned int *option_types_found, > + int *cc_succeeded, > + int *cc_succeeded_count) > +{ > +#ifdef ENABLE_PLUGIN > + ASSERT(m); > + ASSERT(mi); > + ASSERT(option_types_found); > + ASSERT(cc_succeeded); > + ASSERT(cc_succeeded_count); > > - /* lock down the common name and cert hashes so they can't change during future TLS renegotiations */ > - tls_lock_common_name(mi->context.c2.tls_multi); > - tls_lock_cert_hash_set(mi->context.c2.tls_multi); > + /* V2 callback, use a plugin_return struct for passing back return info */ > + if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2)) > + { > + struct plugin_return pr; > > - /* generate a msg() prefix for this client instance */ > - generate_prefix(mi); > + plugin_return_init(&pr); > > - /* delete instances of previous clients with same common-name */ > - if (!mi->context.options.duplicate_cn) > + if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, > + NULL, &pr, mi->context.c2.es) > + != OPENVPN_PLUGIN_FUNC_SUCCESS) > { > - multi_delete_dup(m, mi); > + msg(M_WARN, "WARNING: client-connect-v2 plugin call failed"); > + *cc_succeeded = false; > + } > + else > + { > + multi_client_connect_post_plugin(m, mi, &pr, option_types_found); > + (*cc_succeeded_count)++; > } > > - /* reset pool handle to null */ > - mi->vaddr_handle = -1; > + plugin_return_free(&pr); > + } > +#endif /* ifdef ENABLE_PLUGIN */ > +} > > - /* > - * Try to source a dynamic config file from the > - * --client-config-dir directory. > - */ > - if (mi->context.options.client_config_dir) > + > + > +/** > + * Runs the --client-connect script if one is defined. > + */ > +static void > +multi_client_connect_call_script(struct multi_context *m, > + struct multi_instance *mi, > + unsigned int *option_types_found, > + int *cc_succeeded, > + int *cc_succeeded_count) > +{ > + if (mi->context.options.client_connect_script) > + { > + struct argv argv = argv_new(); > + struct gc_arena gc = gc_new(); > + const char *dc_file = NULL; > + > + setenv_str(mi->context.c2.es, "script_type", "client-connect"); > + > + dc_file = platform_create_temp_file(mi->context.options.tmp_dir, > + "cc", &gc); > + if (!dc_file) > { > - const char *ccd_file; > + *cc_succeeded = false; > + goto cleanup; > + } > > - ccd_file = platform_gen_path(mi->context.options.client_config_dir, > - tls_common_name(mi->context.c2.tls_multi, > - false), > - &gc); > + argv_parse_cmd(&argv, mi->context.options.client_connect_script); > + argv_printf_cat(&argv, "%s", dc_file); > > - /* try common-name file */ > - if (platform_test_file(ccd_file)) > - { > - options_server_import(&mi->context.options, > - ccd_file, > - D_IMPORT_ERRORS|M_OPTERR, > - option_permissions_mask, > - &option_types_found, > - mi->context.c2.es); > - } > - else /* try default file */ > - { > - ccd_file = platform_gen_path(mi->context.options.client_config_dir, > - CCD_DEFAULT, > - &gc); > + if (openvpn_run_script(&argv, mi->context.c2.es, 0, "--client-connect")) > + { > + multi_client_connect_post(m, mi, dc_file, option_types_found); > + (*cc_succeeded_count)++; > + } > + else > + { > + *cc_succeeded = false; > + } > > - if (platform_test_file(ccd_file)) > - { > - options_server_import(&mi->context.options, > - ccd_file, > - D_IMPORT_ERRORS|M_OPTERR, > - option_permissions_mask, > - &option_types_found, > - mi->context.c2.es); > - } > - } > + if (!platform_unlink(dc_file)) > + { > + msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", > + dc_file); > } > +cleanup: > + argv_reset(&argv); > + gc_free(&gc); > + } > +} > > - /* > - * Select a virtual address from either --ifconfig-push in --client-config-dir file > - * or --ifconfig-pool. > - */ > - multi_select_virtual_addr(m, mi); > +static void > +multi_client_connect_late_setup(struct multi_context *m, > + struct multi_instance *mi, > + const unsigned int option_types_found) > +{ > + struct gc_arena gc = gc_new(); > + /* > + * Process sourced options. > + */ > + do_deferred_options(&mi->context, option_types_found); > > - /* do --client-connect setenvs */ > - multi_client_connect_setenv(m, mi); > + /* > + * make sure we got ifconfig settings from somewhere > + */ > + if (!mi->context.c2.push_ifconfig_defined) > + { > + msg(D_MULTI_ERRORS, "MULTI: no dynamic or static remote" > + "--ifconfig address is available for %s", > + multi_instance_string(mi, false, &gc)); > + } > + > + /* > + * make sure that ifconfig settings comply with constraints > + */ > + if (!ifconfig_push_constraint_satisfied(&mi->context)) > + { > + const char *ifconfig_constraint_network = > + print_in_addr_t(mi->context.options.push_ifconfig_constraint_network, 0, &gc); > + const char *ifconfig_constraint_netmask = > + print_in_addr_t(mi->context.options.push_ifconfig_constraint_netmask, 0, &gc); > + > + /* JYFIXME -- this should cause the connection to fail */ > + msg(D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s)" > + "violates tunnel network/netmask constraint (%s/%s)", > + multi_instance_string(mi, false, &gc), > + print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc), > + ifconfig_constraint_network, ifconfig_constraint_netmask); > + } > + > + /* > + * For routed tunnels, set up internal route to endpoint > + * plus add all iroute routes. > + */ > + if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) > + { > + if (mi->context.c2.push_ifconfig_defined) > + { > + multi_learn_in_addr_t(m, mi, > + mi->context.c2.push_ifconfig_local, > + -1, true); > + msg(D_MULTI_LOW, "MULTI: primary virtual IP for %s: %s", > + multi_instance_string(mi, false, &gc), > + print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc)); > + } > + > + if (mi->context.c2.push_ifconfig_ipv6_defined) > + { > + multi_learn_in6_addr(m, mi, > + mi->context.c2.push_ifconfig_ipv6_local, > + -1, true); > + /* TODO: find out where addresses are "unlearned"!! */ > + const char *ifconfig_local_ipv6 = > + print_in6_addr(mi->context.c2.push_ifconfig_ipv6_local, 0, &gc); > + msg(D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s", > + multi_instance_string(mi, false, &gc), > + ifconfig_local_ipv6); > + } > + > + /* add routes locally, pointing to new client, if > + * --iroute options have been specified */ > + multi_add_iroutes(m, mi); > > -#ifdef ENABLE_PLUGIN > /* > - * Call client-connect plug-in. > + * iroutes represent subnets which are "owned" by a particular > + * client. Therefore, do not actually push a route to a client > + * if it matches one of the client's iroutes. > */ > + remove_iroutes_from_push_route_list(&mi->context.options); > + } > + else if (mi->context.options.iroutes) > + { > + msg(D_MULTI_ERRORS, "MULTI: --iroute options rejected for %s -- iroute" > + "only works with tun-style tunnels", > + multi_instance_string(mi, false, &gc)); > + } > > - /* deprecated callback, use a file for passing back return info */ > - if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) > - { > - struct argv argv = argv_new(); > - const char *dc_file = platform_create_temp_file(mi->context.options.tmp_dir, > - "cc", &gc); > + /* set our client's VPN endpoint for status reporting purposes */ > + mi->reporting_addr = mi->context.c2.push_ifconfig_local; > + mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local; > > - if (!dc_file) > - { > - cc_succeeded = false; > - goto script_depr_failed; > - } > + /* set context-level authentication flag */ > + mi->context.c2.context_auth = CAS_SUCCEEDED; > > - argv_printf(&argv, "%s", dc_file); > - if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, &argv, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) > - { > - msg(M_WARN, "WARNING: client-connect plugin call failed"); > - cc_succeeded = false; > - } > - else > - { > - multi_client_connect_post(m, mi, dc_file, option_permissions_mask, &option_types_found); > - ++cc_succeeded_count; > - } > +#ifdef ENABLE_ASYNC_PUSH > + /* authentication complete, send push reply */ > + if (mi->context.c2.push_request_received) > + { > + process_incoming_push_request(&mi->context); > + } > +#endif > + gc_free(&gc); > +} > > - if (!platform_unlink(dc_file)) > - { > - msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", > - dc_file); > - } > > -script_depr_failed: > - argv_reset(&argv); > - } > +static void > +multi_client_connect_early_setup(struct multi_context *m, > + struct multi_instance *mi) > +{ > + ASSERT(mi->context.c1.tuntap); > + /* > + * lock down the common name and cert hashes so they can't change > + * during future TLS renegotiations > + */ > + tls_lock_common_name(mi->context.c2.tls_multi); > + tls_lock_cert_hash_set(mi->context.c2.tls_multi); > > - /* V2 callback, use a plugin_return struct for passing back return info */ > - if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2)) > - { > - struct plugin_return pr; > + /* generate a msg() prefix for this client instance */ > + generate_prefix(mi); > > - plugin_return_init(&pr); > + /* delete instances of previous clients with same common-name */ > + if (!mi->context.options.duplicate_cn) > + { > + multi_delete_dup(m, mi); > + } > > - if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, NULL, &pr, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) > - { > - msg(M_WARN, "WARNING: client-connect-v2 plugin call failed"); > - cc_succeeded = false; > - } > - else > - { > - multi_client_connect_post_plugin(m, mi, &pr, option_permissions_mask, &option_types_found); > - ++cc_succeeded_count; > - } > + /* reset pool handle to null */ > + mi->vaddr_handle = -1; > +} > > - plugin_return_free(&pr); > - } > -#endif /* ifdef ENABLE_PLUGIN */ > +/** > + * Try to source a dynamic config file from the > + * --client-config-dir directory. > + */ > +static void > +multi_client_connect_source_ccd(struct multi_context *m, > + struct multi_instance *mi, > + unsigned int *option_types_found) > +{ > + if (mi->context.options.client_config_dir) > + { > + struct gc_arena gc = gc_new(); > + const char *ccd_file; > > - /* > - * Run --client-connect script. > - */ > - if (mi->context.options.client_connect_script && cc_succeeded) > - { > - struct argv argv = argv_new(); > - const char *dc_file = NULL; > + ccd_file = platform_gen_path(mi->context.options.client_config_dir, > + tls_common_name(mi->context.c2.tls_multi, > + false), > + &gc); > > - setenv_str(mi->context.c2.es, "script_type", "client-connect"); > + /* try common-name file */ > + if (platform_test_file(ccd_file)) > + { > + options_server_import(&mi->context.options, > + ccd_file, > + D_IMPORT_ERRORS|M_OPTERR, > + CLIENT_CONNECT_OPT_MASK, > + option_types_found, > + mi->context.c2.es); > + } > + else /* try default file */ > + { > + ccd_file = platform_gen_path(mi->context.options.client_config_dir, > + CCD_DEFAULT, > + &gc); > > - dc_file = platform_create_temp_file(mi->context.options.tmp_dir, > - "cc", &gc); > - if (!dc_file) > + if (platform_test_file(ccd_file)) > { > - cc_succeeded = false; > - goto script_failed; > + options_server_import(&mi->context.options, > + ccd_file, > + D_IMPORT_ERRORS|M_OPTERR, > + CLIENT_CONNECT_OPT_MASK, > + option_types_found, > + mi->context.c2.es); > } > + } > + gc_free(&gc); > + } > +} > + > +/* > + * Called as soon as the SSL/TLS connection authenticates. > + * > + * Instance-specific directives to be processed: > + * > + * iroute start-ip end-ip > + * ifconfig-push local remote-netmask > + * push > + */ > +static void > +multi_connection_established(struct multi_context *m, struct multi_instance *mi) > +{ > + if (tls_authentication_status(mi->context.c2.tls_multi, 0) > + == TLS_AUTHENTICATION_SUCCEEDED) > + { > + unsigned int option_types_found = 0; > > - argv_parse_cmd(&argv, mi->context.options.client_connect_script); > - argv_printf_cat(&argv, "%s", dc_file); > + int cc_succeeded = true; /* client connect script status */ > + int cc_succeeded_count = 0; > > - if (openvpn_run_script(&argv, mi->context.c2.es, 0, "--client-connect")) > - { > - multi_client_connect_post(m, mi, dc_file, option_permissions_mask, &option_types_found); > - ++cc_succeeded_count; > - } > - else > - { > - cc_succeeded = false; > - } > + multi_client_connect_early_setup(m, mi); > > - if (!platform_unlink(dc_file)) > - { > - msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", > - dc_file); > - } > + multi_client_connect_source_ccd(m, mi, &option_types_found); > > -script_failed: > - argv_reset(&argv); > - } > + /* > + * Select a virtual address from either --ifconfig-push in > + * --client-config-dir file or --ifconfig-pool. > + */ > + multi_select_virtual_addr(m, mi); > + > + /* do --client-connect setenvs */ > + multi_client_connect_setenv(m, mi); > + > + multi_client_connect_call_plugin_v1(m, mi, &option_types_found, > + &cc_succeeded, > + &cc_succeeded_count); > + > + multi_client_connect_call_plugin_v2(m, mi, &option_types_found, > + &cc_succeeded, > + &cc_succeeded_count); > > /* > * Check for client-connect script left by management interface client > */ > + > + if (cc_succeeded) > + { > + multi_client_connect_call_script(m, mi, &option_types_found, > + &cc_succeeded, > + &cc_succeeded_count); > + > + } > #ifdef MANAGEMENT_DEF_AUTH > if (cc_succeeded && mi->cc_config) > { > - multi_client_connect_mda(m, mi, mi->cc_config, option_permissions_mask, &option_types_found); > - ++cc_succeeded_count; > + multi_client_connect_mda(m, mi, &option_types_found); > + cc_succeeded_count++; > } > #endif > > @@ -1991,99 +2158,21 @@ script_failed: > */ > if (mi->context.options.disable) > { > - msg(D_MULTI_ERRORS, "MULTI: client has been rejected due to 'disable' directive"); > + msg(D_MULTI_ERRORS, "MULTI: client has been rejected due to" > + "'disable' directive"); > cc_succeeded = false; > cc_succeeded_count = 0; > } > > if (cc_succeeded) > { > - /* > - * Process sourced options. > - */ > - do_deferred_options(&mi->context, option_types_found); > - > - /* > - * make sure we got ifconfig settings from somewhere > - */ > - if (!mi->context.c2.push_ifconfig_defined) > - { > - msg(D_MULTI_ERRORS, "MULTI: no dynamic or static remote --ifconfig address is available for %s", > - multi_instance_string(mi, false, &gc)); > - } > - > - /* > - * make sure that ifconfig settings comply with constraints > - */ > - if (!ifconfig_push_constraint_satisfied(&mi->context)) > - { > - /* JYFIXME -- this should cause the connection to fail */ > - msg(D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s) violates tunnel network/netmask constraint (%s/%s)", > - multi_instance_string(mi, false, &gc), > - print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc), > - print_in_addr_t(mi->context.options.push_ifconfig_constraint_network, 0, &gc), > - print_in_addr_t(mi->context.options.push_ifconfig_constraint_netmask, 0, &gc)); > - } > - > - /* > - * For routed tunnels, set up internal route to endpoint > - * plus add all iroute routes. > - */ > - if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) > - { > - if (mi->context.c2.push_ifconfig_defined) > - { > - multi_learn_in_addr_t(m, mi, mi->context.c2.push_ifconfig_local, -1, true); > - msg(D_MULTI_LOW, "MULTI: primary virtual IP for %s: %s", > - multi_instance_string(mi, false, &gc), > - print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc)); > - } > - > - if (mi->context.c2.push_ifconfig_ipv6_defined) > - { > - multi_learn_in6_addr(m, mi, mi->context.c2.push_ifconfig_ipv6_local, -1, true); > - /* TODO: find out where addresses are "unlearned"!! */ > - msg(D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s", > - multi_instance_string(mi, false, &gc), > - print_in6_addr(mi->context.c2.push_ifconfig_ipv6_local, 0, &gc)); > - } > - > - /* add routes locally, pointing to new client, if > - * --iroute options have been specified */ > - multi_add_iroutes(m, mi); > - > - /* > - * iroutes represent subnets which are "owned" by a particular > - * client. Therefore, do not actually push a route to a client > - * if it matches one of the client's iroutes. > - */ > - remove_iroutes_from_push_route_list(&mi->context.options); > - } > - else if (mi->context.options.iroutes) > - { > - msg(D_MULTI_ERRORS, "MULTI: --iroute options rejected for %s -- iroute only works with tun-style tunnels", > - multi_instance_string(mi, false, &gc)); > - } > - > - /* set our client's VPN endpoint for status reporting purposes */ > - mi->reporting_addr = mi->context.c2.push_ifconfig_local; > - mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local; > - > - /* set context-level authentication flag */ > - mi->context.c2.context_auth = CAS_SUCCEEDED; > - > -#ifdef ENABLE_ASYNC_PUSH > - /* authentication complete, send push reply */ > - if (mi->context.c2.push_request_received) > - { > - process_incoming_push_request(&mi->context); > - } > -#endif > + multi_client_connect_late_setup(m, mi, option_types_found); > } > else > { > /* set context-level authentication flag */ > - mi->context.c2.context_auth = cc_succeeded_count ? CAS_PARTIAL : CAS_FAILED; > + mi->context.c2.context_auth = > + cc_succeeded_count ? CAS_PARTIAL : CAS_FAILED; > } > > /* set flag so we don't get called again */ > @@ -2097,11 +2186,11 @@ script_failed: > #ifdef MANAGEMENT_DEF_AUTH > if (management) > { > - management_connection_established(management, &mi->context.c2.mda_context, mi->context.c2.es); > + management_connection_established > + (management, &mi->context.c2.mda_context, mi->context.c2.es); I don't get the change above. I don't think the new style reflects our coding style, no? Normally you'd go to the new line with the first argument exceeding the max line length. > } > #endif > > - gc_free(&gc); > } > > /* > diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h > index 3d3d6875..489c073a 100644 > --- a/src/openvpn/multi.h > +++ b/src/openvpn/multi.h > @@ -628,7 +628,9 @@ multi_process_outgoing_tun(struct multi_context *m, const unsigned int mpp_flags > return ret; > } > > - > +#define CLIENT_CONNECT_OPT_MASK (OPT_P_INSTANCE | OPT_P_INHERIT \ > + |OPT_P_PUSH | OPT_P_TIMER | OPT_P_CONFIG \ > + |OPT_P_ECHO | OPT_P_COMP | OPT_P_SOCKFLAGS) > > static inline bool > multi_process_outgoing_link_dowork(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags) > other than those few comments the change "looks" reasonable. However, do we have a way to test the code being changed? I mean all the code being changed (not just the part used by the deferred connect logic) Because even though it all looks sane, we might be breaking something else. Regards,
>> This elimininates and the big reformatting done before eliminates the follow >> up patch with indentation changes. >> >> The original patch already replaces some instances of option_permission_mask >> with CLIENT_CONNECT_OPT_MASK. The V3 version does this more consequently. >> > > Did you mean "more consistently" ? Hm both work I think. Can change it to cosistently. >> options_server_import(&mi->context.options, >> dc_file, >> D_IMPORT_ERRORS|M_OPTERR, >> - option_permissions_mask, >> + CLIENT_CONNECT_OPT_MASK, > > every invocation of options_server_import() gets CLIENT_CONNECT_OPT_MASK > as parameter. Do we really need it to be a parameter? The call in init.c does gets OPT_P_DEFAULT & ~OPT_P_PLUGIN instead. mi->context.c2.es); >> } >> @@ -1716,21 +1714,19 @@ multi_client_connect_post_plugin(struct multi_context *m, >> static void >> multi_client_connect_mda(struct multi_context *m, >> struct multi_instance *mi, >> - const struct buffer_list *config, >> - unsigned int option_permissions_mask, >> unsigned int *option_types_found) >> { >> - if (config) >> + if (mi->cc_config) > > Also getting rid of config and using mi->cc_config looks like something > that could go in its own patch, as it is quite unrelated. > Okay. That will be a tiny patch. >> - >> +#define CLIENT_CONNECT_OPT_MASK (OPT_P_INSTANCE | OPT_P_INHERIT \ >> + |OPT_P_PUSH | OPT_P_TIMER | OPT_P_CONFIG \ >> + |OPT_P_ECHO | OPT_P_COMP | OPT_P_SOCKFLAGS) >> >> static inline bool >> multi_process_outgoing_link_dowork(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags) >> > > > other than those few comments the change "looks" reasonable. However, do > we have a way to test the code being changed? I mean all the code being > changed (not just the part used by the deferred connect logic) > > Because even though it all looks sane, we might be breaking something else. > I am not aware of a test suite other than manually testing the changes what I did with the whole patch set but not with individual commits. Arne
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 8440f311..a4b62151 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1638,7 +1638,6 @@ static void multi_client_connect_post(struct multi_context *m, struct multi_instance *mi, const char *dc_file, - unsigned int option_permissions_mask, unsigned int *option_types_found) { /* Did script generate a dynamic config file? */ @@ -1647,7 +1646,7 @@ multi_client_connect_post(struct multi_context *m, options_server_import(&mi->context.options, dc_file, D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, + CLIENT_CONNECT_OPT_MASK, option_types_found, mi->context.c2.es); @@ -1671,7 +1670,6 @@ static void multi_client_connect_post_plugin(struct multi_context *m, struct multi_instance *mi, const struct plugin_return *pr, - unsigned int option_permissions_mask, unsigned int *option_types_found) { struct plugin_return config; @@ -1689,7 +1687,7 @@ multi_client_connect_post_plugin(struct multi_context *m, options_string_import(&mi->context.options, config.list[i]->value, D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, + CLIENT_CONNECT_OPT_MASK, option_types_found, mi->context.c2.es); } @@ -1716,21 +1714,19 @@ multi_client_connect_post_plugin(struct multi_context *m, static void multi_client_connect_mda(struct multi_context *m, struct multi_instance *mi, - const struct buffer_list *config, - unsigned int option_permissions_mask, unsigned int *option_types_found) { - if (config) + if (mi->cc_config) { struct buffer_entry *be; - for (be = config->head; be != NULL; be = be->next) + for (be = mi->cc_config->head; be != NULL; be = be->next) { const char *opt = BSTR(&be->buf); options_string_import(&mi->context.options, opt, D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, + CLIENT_CONNECT_OPT_MASK, option_types_found, mi->context.c2.es); } @@ -1773,215 +1769,386 @@ multi_client_connect_setenv(struct multi_context *m, gc_free(&gc); } -/* - * Called as soon as the SSL/TLS connection authenticates. - * - * Instance-specific directives to be processed: - * - * iroute start-ip end-ip - * ifconfig-push local remote-netmask - * push - */ static void -multi_connection_established(struct multi_context *m, struct multi_instance *mi) +multi_client_connect_call_plugin_v1(struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found, + int *cc_succeeded, + int *cc_succeeded_count) { - if (tls_authentication_status(mi->context.c2.tls_multi, 0) == TLS_AUTHENTICATION_SUCCEEDED) +#ifdef ENABLE_PLUGIN + ASSERT(m); + ASSERT(mi); + ASSERT(option_types_found); + ASSERT(cc_succeeded); + ASSERT(cc_succeeded_count); + + /* deprecated callback, use a file for passing back return info */ + if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) { + struct argv argv = argv_new(); struct gc_arena gc = gc_new(); - unsigned int option_types_found = 0; + const char *dc_file = + platform_create_temp_file(mi->context.options.tmp_dir, "cc", &gc); - const unsigned int option_permissions_mask = - OPT_P_INSTANCE - | OPT_P_INHERIT - | OPT_P_PUSH - | OPT_P_TIMER - | OPT_P_CONFIG - | OPT_P_ECHO - | OPT_P_COMP - | OPT_P_SOCKFLAGS; + if (!dc_file) + { + cc_succeeded = false; + goto cleanup; + } - int cc_succeeded = true; /* client connect script status */ - int cc_succeeded_count = 0; + argv_printf(&argv, "%s", dc_file); + if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, + &argv, NULL, mi->context.c2.es) + != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(M_WARN, "WARNING: client-connect plugin call failed"); + *cc_succeeded = false; + } + else + { + multi_client_connect_post(m, mi, dc_file, option_types_found); + (*cc_succeeded_count)++; + } + + { + msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", + dc_file); + } + +cleanup: + argv_reset(&argv); + gc_free(&gc); + } +#endif /* ifdef ENABLE_PLUGIN */ +} - ASSERT(mi->context.c1.tuntap); +static void +multi_client_connect_call_plugin_v2(struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found, + int *cc_succeeded, + int *cc_succeeded_count) +{ +#ifdef ENABLE_PLUGIN + ASSERT(m); + ASSERT(mi); + ASSERT(option_types_found); + ASSERT(cc_succeeded); + ASSERT(cc_succeeded_count); - /* lock down the common name and cert hashes so they can't change during future TLS renegotiations */ - tls_lock_common_name(mi->context.c2.tls_multi); - tls_lock_cert_hash_set(mi->context.c2.tls_multi); + /* V2 callback, use a plugin_return struct for passing back return info */ + if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2)) + { + struct plugin_return pr; - /* generate a msg() prefix for this client instance */ - generate_prefix(mi); + plugin_return_init(&pr); - /* delete instances of previous clients with same common-name */ - if (!mi->context.options.duplicate_cn) + if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, + NULL, &pr, mi->context.c2.es) + != OPENVPN_PLUGIN_FUNC_SUCCESS) { - multi_delete_dup(m, mi); + msg(M_WARN, "WARNING: client-connect-v2 plugin call failed"); + *cc_succeeded = false; + } + else + { + multi_client_connect_post_plugin(m, mi, &pr, option_types_found); + (*cc_succeeded_count)++; } - /* reset pool handle to null */ - mi->vaddr_handle = -1; + plugin_return_free(&pr); + } +#endif /* ifdef ENABLE_PLUGIN */ +} - /* - * Try to source a dynamic config file from the - * --client-config-dir directory. - */ - if (mi->context.options.client_config_dir) + + +/** + * Runs the --client-connect script if one is defined. + */ +static void +multi_client_connect_call_script(struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found, + int *cc_succeeded, + int *cc_succeeded_count) +{ + if (mi->context.options.client_connect_script) + { + struct argv argv = argv_new(); + struct gc_arena gc = gc_new(); + const char *dc_file = NULL; + + setenv_str(mi->context.c2.es, "script_type", "client-connect"); + + dc_file = platform_create_temp_file(mi->context.options.tmp_dir, + "cc", &gc); + if (!dc_file) { - const char *ccd_file; + *cc_succeeded = false; + goto cleanup; + } - ccd_file = platform_gen_path(mi->context.options.client_config_dir, - tls_common_name(mi->context.c2.tls_multi, - false), - &gc); + argv_parse_cmd(&argv, mi->context.options.client_connect_script); + argv_printf_cat(&argv, "%s", dc_file); - /* try common-name file */ - if (platform_test_file(ccd_file)) - { - options_server_import(&mi->context.options, - ccd_file, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - &option_types_found, - mi->context.c2.es); - } - else /* try default file */ - { - ccd_file = platform_gen_path(mi->context.options.client_config_dir, - CCD_DEFAULT, - &gc); + if (openvpn_run_script(&argv, mi->context.c2.es, 0, "--client-connect")) + { + multi_client_connect_post(m, mi, dc_file, option_types_found); + (*cc_succeeded_count)++; + } + else + { + *cc_succeeded = false; + } - if (platform_test_file(ccd_file)) - { - options_server_import(&mi->context.options, - ccd_file, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - &option_types_found, - mi->context.c2.es); - } - } + if (!platform_unlink(dc_file)) + { + msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", + dc_file); } +cleanup: + argv_reset(&argv); + gc_free(&gc); + } +} - /* - * Select a virtual address from either --ifconfig-push in --client-config-dir file - * or --ifconfig-pool. - */ - multi_select_virtual_addr(m, mi); +static void +multi_client_connect_late_setup(struct multi_context *m, + struct multi_instance *mi, + const unsigned int option_types_found) +{ + struct gc_arena gc = gc_new(); + /* + * Process sourced options. + */ + do_deferred_options(&mi->context, option_types_found); - /* do --client-connect setenvs */ - multi_client_connect_setenv(m, mi); + /* + * make sure we got ifconfig settings from somewhere + */ + if (!mi->context.c2.push_ifconfig_defined) + { + msg(D_MULTI_ERRORS, "MULTI: no dynamic or static remote" + "--ifconfig address is available for %s", + multi_instance_string(mi, false, &gc)); + } + + /* + * make sure that ifconfig settings comply with constraints + */ + if (!ifconfig_push_constraint_satisfied(&mi->context)) + { + const char *ifconfig_constraint_network = + print_in_addr_t(mi->context.options.push_ifconfig_constraint_network, 0, &gc); + const char *ifconfig_constraint_netmask = + print_in_addr_t(mi->context.options.push_ifconfig_constraint_netmask, 0, &gc); + + /* JYFIXME -- this should cause the connection to fail */ + msg(D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s)" + "violates tunnel network/netmask constraint (%s/%s)", + multi_instance_string(mi, false, &gc), + print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc), + ifconfig_constraint_network, ifconfig_constraint_netmask); + } + + /* + * For routed tunnels, set up internal route to endpoint + * plus add all iroute routes. + */ + if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) + { + if (mi->context.c2.push_ifconfig_defined) + { + multi_learn_in_addr_t(m, mi, + mi->context.c2.push_ifconfig_local, + -1, true); + msg(D_MULTI_LOW, "MULTI: primary virtual IP for %s: %s", + multi_instance_string(mi, false, &gc), + print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc)); + } + + if (mi->context.c2.push_ifconfig_ipv6_defined) + { + multi_learn_in6_addr(m, mi, + mi->context.c2.push_ifconfig_ipv6_local, + -1, true); + /* TODO: find out where addresses are "unlearned"!! */ + const char *ifconfig_local_ipv6 = + print_in6_addr(mi->context.c2.push_ifconfig_ipv6_local, 0, &gc); + msg(D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s", + multi_instance_string(mi, false, &gc), + ifconfig_local_ipv6); + } + + /* add routes locally, pointing to new client, if + * --iroute options have been specified */ + multi_add_iroutes(m, mi); -#ifdef ENABLE_PLUGIN /* - * Call client-connect plug-in. + * iroutes represent subnets which are "owned" by a particular + * client. Therefore, do not actually push a route to a client + * if it matches one of the client's iroutes. */ + remove_iroutes_from_push_route_list(&mi->context.options); + } + else if (mi->context.options.iroutes) + { + msg(D_MULTI_ERRORS, "MULTI: --iroute options rejected for %s -- iroute" + "only works with tun-style tunnels", + multi_instance_string(mi, false, &gc)); + } - /* deprecated callback, use a file for passing back return info */ - if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) - { - struct argv argv = argv_new(); - const char *dc_file = platform_create_temp_file(mi->context.options.tmp_dir, - "cc", &gc); + /* set our client's VPN endpoint for status reporting purposes */ + mi->reporting_addr = mi->context.c2.push_ifconfig_local; + mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local; - if (!dc_file) - { - cc_succeeded = false; - goto script_depr_failed; - } + /* set context-level authentication flag */ + mi->context.c2.context_auth = CAS_SUCCEEDED; - argv_printf(&argv, "%s", dc_file); - if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, &argv, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg(M_WARN, "WARNING: client-connect plugin call failed"); - cc_succeeded = false; - } - else - { - multi_client_connect_post(m, mi, dc_file, option_permissions_mask, &option_types_found); - ++cc_succeeded_count; - } +#ifdef ENABLE_ASYNC_PUSH + /* authentication complete, send push reply */ + if (mi->context.c2.push_request_received) + { + process_incoming_push_request(&mi->context); + } +#endif + gc_free(&gc); +} - if (!platform_unlink(dc_file)) - { - msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", - dc_file); - } -script_depr_failed: - argv_reset(&argv); - } +static void +multi_client_connect_early_setup(struct multi_context *m, + struct multi_instance *mi) +{ + ASSERT(mi->context.c1.tuntap); + /* + * lock down the common name and cert hashes so they can't change + * during future TLS renegotiations + */ + tls_lock_common_name(mi->context.c2.tls_multi); + tls_lock_cert_hash_set(mi->context.c2.tls_multi); - /* V2 callback, use a plugin_return struct for passing back return info */ - if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2)) - { - struct plugin_return pr; + /* generate a msg() prefix for this client instance */ + generate_prefix(mi); - plugin_return_init(&pr); + /* delete instances of previous clients with same common-name */ + if (!mi->context.options.duplicate_cn) + { + multi_delete_dup(m, mi); + } - if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, NULL, &pr, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg(M_WARN, "WARNING: client-connect-v2 plugin call failed"); - cc_succeeded = false; - } - else - { - multi_client_connect_post_plugin(m, mi, &pr, option_permissions_mask, &option_types_found); - ++cc_succeeded_count; - } + /* reset pool handle to null */ + mi->vaddr_handle = -1; +} - plugin_return_free(&pr); - } -#endif /* ifdef ENABLE_PLUGIN */ +/** + * Try to source a dynamic config file from the + * --client-config-dir directory. + */ +static void +multi_client_connect_source_ccd(struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found) +{ + if (mi->context.options.client_config_dir) + { + struct gc_arena gc = gc_new(); + const char *ccd_file; - /* - * Run --client-connect script. - */ - if (mi->context.options.client_connect_script && cc_succeeded) - { - struct argv argv = argv_new(); - const char *dc_file = NULL; + ccd_file = platform_gen_path(mi->context.options.client_config_dir, + tls_common_name(mi->context.c2.tls_multi, + false), + &gc); - setenv_str(mi->context.c2.es, "script_type", "client-connect"); + /* try common-name file */ + if (platform_test_file(ccd_file)) + { + options_server_import(&mi->context.options, + ccd_file, + D_IMPORT_ERRORS|M_OPTERR, + CLIENT_CONNECT_OPT_MASK, + option_types_found, + mi->context.c2.es); + } + else /* try default file */ + { + ccd_file = platform_gen_path(mi->context.options.client_config_dir, + CCD_DEFAULT, + &gc); - dc_file = platform_create_temp_file(mi->context.options.tmp_dir, - "cc", &gc); - if (!dc_file) + if (platform_test_file(ccd_file)) { - cc_succeeded = false; - goto script_failed; + options_server_import(&mi->context.options, + ccd_file, + D_IMPORT_ERRORS|M_OPTERR, + CLIENT_CONNECT_OPT_MASK, + option_types_found, + mi->context.c2.es); } + } + gc_free(&gc); + } +} + +/* + * Called as soon as the SSL/TLS connection authenticates. + * + * Instance-specific directives to be processed: + * + * iroute start-ip end-ip + * ifconfig-push local remote-netmask + * push + */ +static void +multi_connection_established(struct multi_context *m, struct multi_instance *mi) +{ + if (tls_authentication_status(mi->context.c2.tls_multi, 0) + == TLS_AUTHENTICATION_SUCCEEDED) + { + unsigned int option_types_found = 0; - argv_parse_cmd(&argv, mi->context.options.client_connect_script); - argv_printf_cat(&argv, "%s", dc_file); + int cc_succeeded = true; /* client connect script status */ + int cc_succeeded_count = 0; - if (openvpn_run_script(&argv, mi->context.c2.es, 0, "--client-connect")) - { - multi_client_connect_post(m, mi, dc_file, option_permissions_mask, &option_types_found); - ++cc_succeeded_count; - } - else - { - cc_succeeded = false; - } + multi_client_connect_early_setup(m, mi); - if (!platform_unlink(dc_file)) - { - msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", - dc_file); - } + multi_client_connect_source_ccd(m, mi, &option_types_found); -script_failed: - argv_reset(&argv); - } + /* + * Select a virtual address from either --ifconfig-push in + * --client-config-dir file or --ifconfig-pool. + */ + multi_select_virtual_addr(m, mi); + + /* do --client-connect setenvs */ + multi_client_connect_setenv(m, mi); + + multi_client_connect_call_plugin_v1(m, mi, &option_types_found, + &cc_succeeded, + &cc_succeeded_count); + + multi_client_connect_call_plugin_v2(m, mi, &option_types_found, + &cc_succeeded, + &cc_succeeded_count); /* * Check for client-connect script left by management interface client */ + + if (cc_succeeded) + { + multi_client_connect_call_script(m, mi, &option_types_found, + &cc_succeeded, + &cc_succeeded_count); + + } #ifdef MANAGEMENT_DEF_AUTH if (cc_succeeded && mi->cc_config) { - multi_client_connect_mda(m, mi, mi->cc_config, option_permissions_mask, &option_types_found); - ++cc_succeeded_count; + multi_client_connect_mda(m, mi, &option_types_found); + cc_succeeded_count++; } #endif @@ -1991,99 +2158,21 @@ script_failed: */ if (mi->context.options.disable) { - msg(D_MULTI_ERRORS, "MULTI: client has been rejected due to 'disable' directive"); + msg(D_MULTI_ERRORS, "MULTI: client has been rejected due to" + "'disable' directive"); cc_succeeded = false; cc_succeeded_count = 0; } if (cc_succeeded) { - /* - * Process sourced options. - */ - do_deferred_options(&mi->context, option_types_found); - - /* - * make sure we got ifconfig settings from somewhere - */ - if (!mi->context.c2.push_ifconfig_defined) - { - msg(D_MULTI_ERRORS, "MULTI: no dynamic or static remote --ifconfig address is available for %s", - multi_instance_string(mi, false, &gc)); - } - - /* - * make sure that ifconfig settings comply with constraints - */ - if (!ifconfig_push_constraint_satisfied(&mi->context)) - { - /* JYFIXME -- this should cause the connection to fail */ - msg(D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s) violates tunnel network/netmask constraint (%s/%s)", - multi_instance_string(mi, false, &gc), - print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc), - print_in_addr_t(mi->context.options.push_ifconfig_constraint_network, 0, &gc), - print_in_addr_t(mi->context.options.push_ifconfig_constraint_netmask, 0, &gc)); - } - - /* - * For routed tunnels, set up internal route to endpoint - * plus add all iroute routes. - */ - if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) - { - if (mi->context.c2.push_ifconfig_defined) - { - multi_learn_in_addr_t(m, mi, mi->context.c2.push_ifconfig_local, -1, true); - msg(D_MULTI_LOW, "MULTI: primary virtual IP for %s: %s", - multi_instance_string(mi, false, &gc), - print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc)); - } - - if (mi->context.c2.push_ifconfig_ipv6_defined) - { - multi_learn_in6_addr(m, mi, mi->context.c2.push_ifconfig_ipv6_local, -1, true); - /* TODO: find out where addresses are "unlearned"!! */ - msg(D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s", - multi_instance_string(mi, false, &gc), - print_in6_addr(mi->context.c2.push_ifconfig_ipv6_local, 0, &gc)); - } - - /* add routes locally, pointing to new client, if - * --iroute options have been specified */ - multi_add_iroutes(m, mi); - - /* - * iroutes represent subnets which are "owned" by a particular - * client. Therefore, do not actually push a route to a client - * if it matches one of the client's iroutes. - */ - remove_iroutes_from_push_route_list(&mi->context.options); - } - else if (mi->context.options.iroutes) - { - msg(D_MULTI_ERRORS, "MULTI: --iroute options rejected for %s -- iroute only works with tun-style tunnels", - multi_instance_string(mi, false, &gc)); - } - - /* set our client's VPN endpoint for status reporting purposes */ - mi->reporting_addr = mi->context.c2.push_ifconfig_local; - mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local; - - /* set context-level authentication flag */ - mi->context.c2.context_auth = CAS_SUCCEEDED; - -#ifdef ENABLE_ASYNC_PUSH - /* authentication complete, send push reply */ - if (mi->context.c2.push_request_received) - { - process_incoming_push_request(&mi->context); - } -#endif + multi_client_connect_late_setup(m, mi, option_types_found); } else { /* set context-level authentication flag */ - mi->context.c2.context_auth = cc_succeeded_count ? CAS_PARTIAL : CAS_FAILED; + mi->context.c2.context_auth = + cc_succeeded_count ? CAS_PARTIAL : CAS_FAILED; } /* set flag so we don't get called again */ @@ -2097,11 +2186,11 @@ script_failed: #ifdef MANAGEMENT_DEF_AUTH if (management) { - management_connection_established(management, &mi->context.c2.mda_context, mi->context.c2.es); + management_connection_established + (management, &mi->context.c2.mda_context, mi->context.c2.es); } #endif - gc_free(&gc); } /* diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index 3d3d6875..489c073a 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -628,7 +628,9 @@ multi_process_outgoing_tun(struct multi_context *m, const unsigned int mpp_flags return ret; } - +#define CLIENT_CONNECT_OPT_MASK (OPT_P_INSTANCE | OPT_P_INHERIT \ + |OPT_P_PUSH | OPT_P_TIMER | OPT_P_CONFIG \ + |OPT_P_ECHO | OPT_P_COMP | OPT_P_SOCKFLAGS) static inline bool multi_process_outgoing_link_dowork(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags)