diff options
author | Alberto Gonzalez Iniesta <agi@inittab.org> | 2016-12-27 18:25:47 +0100 |
---|---|---|
committer | Alberto Gonzalez Iniesta <agi@inittab.org> | 2016-12-27 18:25:47 +0100 |
commit | 79f3537f69e125f19f59c36aa090120a63186a54 (patch) | |
tree | 2089a3b7dac990841dbc2e4d9b2f535b82dbb0af /src/openvpn/multi.c | |
parent | f2137fedb30cb87448eb03b2f288920df6187571 (diff) | |
parent | 3a2bbdb05ca6a6996e424c9fb225cb0d53804125 (diff) |
Merge tag 'upstream/2.4.0'
Upstream version 2.4.0
Diffstat (limited to 'src/openvpn/multi.c')
-rw-r--r-- | src/openvpn/multi.c | 4813 |
1 files changed, 2492 insertions, 2321 deletions
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 4fc8b02..f6f3f5d 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -55,22 +55,28 @@ #ifdef MULTI_DEBUG_EVENT_LOOP static const char * -id (struct multi_instance *mi) +id(struct multi_instance *mi) { - if (mi) - return tls_common_name (mi->context.c2.tls_multi, false); - else - return "NULL"; + if (mi) + { + return tls_common_name(mi->context.c2.tls_multi, false); + } + else + { + return "NULL"; + } } #endif #ifdef MANAGEMENT_DEF_AUTH static void -set_cc_config (struct multi_instance *mi, struct buffer_list *cc_config) +set_cc_config(struct multi_instance *mi, struct buffer_list *cc_config) { - if (mi->cc_config) - buffer_list_free (mi->cc_config); - mi->cc_config = cc_config; + if (mi->cc_config) + { + buffer_list_free(mi->cc_config); + } + mi->cc_config = cc_config; } #endif @@ -78,170 +84,188 @@ static inline void update_mstat_n_clients(const int n_clients) { #ifdef ENABLE_MEMSTATS - if (mmap_stats) - mmap_stats->n_clients = n_clients; + if (mmap_stats) + { + mmap_stats->n_clients = n_clients; + } #endif } static bool -learn_address_script (const struct multi_context *m, - const struct multi_instance *mi, - const char *op, - const struct mroute_addr *addr) -{ - struct gc_arena gc = gc_new (); - struct env_set *es; - bool ret = true; - struct plugin_list *plugins; - - /* get environmental variable source */ - if (mi && mi->context.c2.es) - es = mi->context.c2.es; - else - es = env_set_create (&gc); - - /* get plugin source */ - if (mi) - plugins = mi->context.plugins; - else - plugins = m->top.plugins; - - if (plugin_defined (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS)) - { - struct argv argv = argv_new (); - argv_printf (&argv, "%s %s", - op, - mroute_addr_print (addr, &gc)); - if (mi) - argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false)); - if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg (M_WARN, "WARNING: learn-address plugin call failed"); - ret = false; - } - argv_reset (&argv); - } - - if (m->top.options.learn_address_script) - { - struct argv argv = argv_new (); - setenv_str (es, "script_type", "learn-address"); - argv_parse_cmd (&argv, m->top.options.learn_address_script); - argv_printf_cat (&argv, "%s %s", op, mroute_addr_print (addr, &gc)); - if (mi) - argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false)); - if (!openvpn_run_script (&argv, es, 0, "--learn-address")) - ret = false; - argv_reset (&argv); - } - - gc_free (&gc); - return ret; +learn_address_script(const struct multi_context *m, + const struct multi_instance *mi, + const char *op, + const struct mroute_addr *addr) +{ + struct gc_arena gc = gc_new(); + struct env_set *es; + bool ret = true; + struct plugin_list *plugins; + + /* get environmental variable source */ + if (mi && mi->context.c2.es) + { + es = mi->context.c2.es; + } + else + { + es = env_set_create(&gc); + } + + /* get plugin source */ + if (mi) + { + plugins = mi->context.plugins; + } + else + { + plugins = m->top.plugins; + } + + if (plugin_defined(plugins, OPENVPN_PLUGIN_LEARN_ADDRESS)) + { + struct argv argv = argv_new(); + argv_printf(&argv, "%s %s", + op, + mroute_addr_print(addr, &gc)); + if (mi) + { + argv_printf_cat(&argv, "%s", tls_common_name(mi->context.c2.tls_multi, false)); + } + if (plugin_call(plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(M_WARN, "WARNING: learn-address plugin call failed"); + ret = false; + } + argv_reset(&argv); + } + + if (m->top.options.learn_address_script) + { + struct argv argv = argv_new(); + setenv_str(es, "script_type", "learn-address"); + argv_parse_cmd(&argv, m->top.options.learn_address_script); + argv_printf_cat(&argv, "%s %s", op, mroute_addr_print(addr, &gc)); + if (mi) + { + argv_printf_cat(&argv, "%s", tls_common_name(mi->context.c2.tls_multi, false)); + } + if (!openvpn_run_script(&argv, es, 0, "--learn-address")) + { + ret = false; + } + argv_reset(&argv); + } + + gc_free(&gc); + return ret; } void -multi_ifconfig_pool_persist (struct multi_context *m, bool force) +multi_ifconfig_pool_persist(struct multi_context *m, bool force) { - /* write pool data to file */ - if (m->ifconfig_pool - && m->top.c1.ifconfig_pool_persist - && (force || ifconfig_pool_write_trigger (m->top.c1.ifconfig_pool_persist))) + /* write pool data to file */ + if (m->ifconfig_pool + && m->top.c1.ifconfig_pool_persist + && (force || ifconfig_pool_write_trigger(m->top.c1.ifconfig_pool_persist))) { - ifconfig_pool_write (m->top.c1.ifconfig_pool_persist, m->ifconfig_pool); + ifconfig_pool_write(m->top.c1.ifconfig_pool_persist, m->ifconfig_pool); } } static void -multi_reap_range (const struct multi_context *m, - int start_bucket, - int end_bucket) +multi_reap_range(const struct multi_context *m, + int start_bucket, + int end_bucket) { - struct gc_arena gc = gc_new (); - struct hash_iterator hi; - struct hash_element *he; + struct gc_arena gc = gc_new(); + struct hash_iterator hi; + struct hash_element *he; - if (start_bucket < 0) + if (start_bucket < 0) { - start_bucket = 0; - end_bucket = hash_n_buckets (m->vhash); + start_bucket = 0; + end_bucket = hash_n_buckets(m->vhash); } - dmsg (D_MULTI_DEBUG, "MULTI: REAP range %d -> %d", start_bucket, end_bucket); - hash_iterator_init_range (m->vhash, &hi, start_bucket, end_bucket); - while ((he = hash_iterator_next (&hi)) != NULL) + dmsg(D_MULTI_DEBUG, "MULTI: REAP range %d -> %d", start_bucket, end_bucket); + hash_iterator_init_range(m->vhash, &hi, start_bucket, end_bucket); + while ((he = hash_iterator_next(&hi)) != NULL) { - struct multi_route *r = (struct multi_route *) he->value; - if (!multi_route_defined (m, r)) - { - dmsg (D_MULTI_DEBUG, "MULTI: REAP DEL %s", - mroute_addr_print (&r->addr, &gc)); - learn_address_script (m, NULL, "delete", &r->addr); - multi_route_del (r); - hash_iterator_delete_element (&hi); - } + struct multi_route *r = (struct multi_route *) he->value; + if (!multi_route_defined(m, r)) + { + dmsg(D_MULTI_DEBUG, "MULTI: REAP DEL %s", + mroute_addr_print(&r->addr, &gc)); + learn_address_script(m, NULL, "delete", &r->addr); + multi_route_del(r); + hash_iterator_delete_element(&hi); + } } - hash_iterator_free (&hi); - gc_free (&gc); + hash_iterator_free(&hi); + gc_free(&gc); } static void -multi_reap_all (const struct multi_context *m) +multi_reap_all(const struct multi_context *m) { - multi_reap_range (m, -1, 0); + multi_reap_range(m, -1, 0); } static struct multi_reap * -multi_reap_new (int buckets_per_pass) +multi_reap_new(int buckets_per_pass) { - struct multi_reap *mr; - ALLOC_OBJ (mr, struct multi_reap); - mr->bucket_base = 0; - mr->buckets_per_pass = buckets_per_pass; - mr->last_call = now; - return mr; + struct multi_reap *mr; + ALLOC_OBJ(mr, struct multi_reap); + mr->bucket_base = 0; + mr->buckets_per_pass = buckets_per_pass; + mr->last_call = now; + return mr; } void -multi_reap_process_dowork (const struct multi_context *m) +multi_reap_process_dowork(const struct multi_context *m) { - struct multi_reap *mr = m->reaper; - if (mr->bucket_base >= hash_n_buckets (m->vhash)) - mr->bucket_base = 0; - multi_reap_range (m, mr->bucket_base, mr->bucket_base + mr->buckets_per_pass); - mr->bucket_base += mr->buckets_per_pass; - mr->last_call = now; + struct multi_reap *mr = m->reaper; + if (mr->bucket_base >= hash_n_buckets(m->vhash)) + { + mr->bucket_base = 0; + } + multi_reap_range(m, mr->bucket_base, mr->bucket_base + mr->buckets_per_pass); + mr->bucket_base += mr->buckets_per_pass; + mr->last_call = now; } static void -multi_reap_free (struct multi_reap *mr) +multi_reap_free(struct multi_reap *mr) { - free (mr); + free(mr); } /* * How many buckets in vhash to reap per pass. */ static int -reap_buckets_per_pass (int n_buckets) +reap_buckets_per_pass(int n_buckets) { - return constrain_int (n_buckets / REAP_DIVISOR, REAP_MIN, REAP_MAX); + return constrain_int(n_buckets / REAP_DIVISOR, REAP_MIN, REAP_MAX); } #ifdef MANAGEMENT_DEF_AUTH static uint32_t -cid_hash_function (const void *key, uint32_t iv) +cid_hash_function(const void *key, uint32_t iv) { - const unsigned long *k = (const unsigned long *)key; - return (uint32_t) *k; + const unsigned long *k = (const unsigned long *)key; + return (uint32_t) *k; } static bool -cid_compare_function (const void *key1, const void *key2) +cid_compare_function(const void *key1, const void *key2) { - const unsigned long *k1 = (const unsigned long *)key1; - const unsigned long *k2 = (const unsigned long *)key2; - return *k1 == *k2; + const unsigned long *k1 = (const unsigned long *)key1; + const unsigned long *k2 = (const unsigned long *)key2; + return *k1 == *k2; } #endif @@ -251,15 +275,15 @@ static uint32_t /* * inotify watcher descriptors are used as hash value */ -int_hash_function (const void *key, uint32_t iv) +int_hash_function(const void *key, uint32_t iv) { - return (unsigned long)key; + return (unsigned long)key; } static bool -int_compare_function (const void *key1, const void *key2) +int_compare_function(const void *key1, const void *key2) { - return (unsigned long)key1 == (unsigned long)key2; + return (unsigned long)key1 == (unsigned long)key2; } #endif @@ -267,216 +291,236 @@ int_compare_function (const void *key1, const void *key2) * Main initialization function, init multi_context object. */ void -multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int thread_mode) -{ - int dev = DEV_TYPE_UNDEF; - - msg (D_MULTI_LOW, "MULTI: multi_init called, r=%d v=%d", - t->options.real_hash_size, - t->options.virtual_hash_size); - - /* - * Get tun/tap/null device type - */ - dev = dev_type_enum (t->options.dev, t->options.dev_type); - - /* - * Init our multi_context object. - */ - CLEAR (*m); - - m->thread_mode = thread_mode; - - /* - * Real address hash table (source port number is - * considered to be part of the address). Used - * to determine which client sent an incoming packet - * which is seen on the TCP/UDP socket. - */ - m->hash = hash_init (t->options.real_hash_size, - get_random (), - mroute_addr_hash_function, - mroute_addr_compare_function); - - /* - * Virtual address hash table. Used to determine - * which client to route a packet to. - */ - m->vhash = hash_init (t->options.virtual_hash_size, - get_random (), - mroute_addr_hash_function, - mroute_addr_compare_function); - - /* - * This hash table is a clone of m->hash but with a - * bucket size of one so that it can be used - * for fast iteration through the list. - */ - m->iter = hash_init (1, - get_random (), - mroute_addr_hash_function, - mroute_addr_compare_function); +multi_init(struct multi_context *m, struct context *t, bool tcp_mode, int thread_mode) +{ + int dev = DEV_TYPE_UNDEF; + + msg(D_MULTI_LOW, "MULTI: multi_init called, r=%d v=%d", + t->options.real_hash_size, + t->options.virtual_hash_size); + + /* + * Get tun/tap/null device type + */ + dev = dev_type_enum(t->options.dev, t->options.dev_type); + + /* + * Init our multi_context object. + */ + CLEAR(*m); + + m->thread_mode = thread_mode; + + /* + * Real address hash table (source port number is + * considered to be part of the address). Used + * to determine which client sent an incoming packet + * which is seen on the TCP/UDP socket. + */ + m->hash = hash_init(t->options.real_hash_size, + get_random(), + mroute_addr_hash_function, + mroute_addr_compare_function); + + /* + * Virtual address hash table. Used to determine + * which client to route a packet to. + */ + m->vhash = hash_init(t->options.virtual_hash_size, + get_random(), + mroute_addr_hash_function, + mroute_addr_compare_function); + + /* + * This hash table is a clone of m->hash but with a + * bucket size of one so that it can be used + * for fast iteration through the list. + */ + m->iter = hash_init(1, + get_random(), + mroute_addr_hash_function, + mroute_addr_compare_function); #ifdef MANAGEMENT_DEF_AUTH - m->cid_hash = hash_init (t->options.real_hash_size, - 0, - cid_hash_function, - cid_compare_function); + m->cid_hash = hash_init(t->options.real_hash_size, + 0, + cid_hash_function, + cid_compare_function); #endif #ifdef ENABLE_ASYNC_PUSH - /* - * Mapping between inotify watch descriptors and - * multi_instances. - */ - m->inotify_watchers = hash_init (t->options.real_hash_size, - get_random(), - int_hash_function, - int_compare_function); + /* + * Mapping between inotify watch descriptors and + * multi_instances. + */ + m->inotify_watchers = hash_init(t->options.real_hash_size, + get_random(), + int_hash_function, + int_compare_function); #endif - /* - * This is our scheduler, for time-based wakeup - * events. - */ - m->schedule = schedule_init (); - - /* - * Limit frequency of incoming connections to control - * DoS. - */ - m->new_connection_limiter = frequency_limit_init (t->options.cf_max, - t->options.cf_per); - - /* - * Allocate broadcast/multicast buffer list - */ - m->mbuf = mbuf_init (t->options.n_bcast_buf); - - /* - * Different status file format options are available - */ - m->status_file_version = t->options.status_file_version; - - /* - * Possibly allocate an ifconfig pool, do it - * differently based on whether a tun or tap style - * tunnel. - */ - if (t->options.ifconfig_pool_defined) - { - int pool_type = IFCONFIG_POOL_INDIV; - - if ( dev == DEV_TYPE_TUN && t->options.topology == TOP_NET30 ) - pool_type = IFCONFIG_POOL_30NET; - - m->ifconfig_pool = ifconfig_pool_init (pool_type, - t->options.ifconfig_pool_start, - t->options.ifconfig_pool_end, - t->options.duplicate_cn, - t->options.ifconfig_ipv6_pool_defined, - t->options.ifconfig_ipv6_pool_base, - t->options.ifconfig_ipv6_pool_netbits ); - - /* reload pool data from file */ - if (t->c1.ifconfig_pool_persist) - ifconfig_pool_read (t->c1.ifconfig_pool_persist, m->ifconfig_pool); - } - - /* - * Help us keep track of routing table. - */ - m->route_helper = mroute_helper_init (MULTI_CACHE_ROUTE_TTL); - - /* - * Initialize route and instance reaper. - */ - m->reaper = multi_reap_new (reap_buckets_per_pass (t->options.virtual_hash_size)); - - /* - * Get local ifconfig address - */ - CLEAR (m->local); - ASSERT (t->c1.tuntap); - mroute_extract_in_addr_t (&m->local, t->c1.tuntap->local); - - /* - * Per-client limits - */ - m->max_clients = t->options.max_clients; - - m->instances = calloc(m->max_clients, sizeof(struct multi_instance*)); - - /* - * Initialize multi-socket TCP I/O wait object - */ - if (tcp_mode) - m->mtcp = multi_tcp_init (t->options.max_clients, &m->max_clients); - m->tcp_queue_limit = t->options.tcp_queue_limit; - - /* - * Allow client <-> client communication, without going through - * tun/tap interface and network stack? - */ - m->enable_c2c = t->options.enable_c2c; - - /* initialize stale routes check timer */ - if (t->options.stale_routes_check_interval > 0) - { - msg (M_INFO, "Initializing stale route check timer to run every %i seconds and to removing routes with activity timeout older than %i seconds", - t->options.stale_routes_check_interval, t->options.stale_routes_ageing_time); - event_timeout_init (&m->stale_routes_check_et, t->options.stale_routes_check_interval, 0); - } - - m->deferred_shutdown_signal.signal_received = 0; + /* + * This is our scheduler, for time-based wakeup + * events. + */ + m->schedule = schedule_init(); + + /* + * Limit frequency of incoming connections to control + * DoS. + */ + m->new_connection_limiter = frequency_limit_init(t->options.cf_max, + t->options.cf_per); + + /* + * Allocate broadcast/multicast buffer list + */ + m->mbuf = mbuf_init(t->options.n_bcast_buf); + + /* + * Different status file format options are available + */ + m->status_file_version = t->options.status_file_version; + + /* + * Possibly allocate an ifconfig pool, do it + * differently based on whether a tun or tap style + * tunnel. + */ + if (t->options.ifconfig_pool_defined) + { + int pool_type = IFCONFIG_POOL_INDIV; + + if (dev == DEV_TYPE_TUN && t->options.topology == TOP_NET30) + { + pool_type = IFCONFIG_POOL_30NET; + } + + m->ifconfig_pool = ifconfig_pool_init(pool_type, + t->options.ifconfig_pool_start, + t->options.ifconfig_pool_end, + t->options.duplicate_cn, + t->options.ifconfig_ipv6_pool_defined, + t->options.ifconfig_ipv6_pool_base, + t->options.ifconfig_ipv6_pool_netbits ); + + /* reload pool data from file */ + if (t->c1.ifconfig_pool_persist) + { + ifconfig_pool_read(t->c1.ifconfig_pool_persist, m->ifconfig_pool); + } + } + + /* + * Help us keep track of routing table. + */ + m->route_helper = mroute_helper_init(MULTI_CACHE_ROUTE_TTL); + + /* + * Initialize route and instance reaper. + */ + m->reaper = multi_reap_new(reap_buckets_per_pass(t->options.virtual_hash_size)); + + /* + * Get local ifconfig address + */ + CLEAR(m->local); + ASSERT(t->c1.tuntap); + mroute_extract_in_addr_t(&m->local, t->c1.tuntap->local); + + /* + * Per-client limits + */ + m->max_clients = t->options.max_clients; + + m->instances = calloc(m->max_clients, sizeof(struct multi_instance *)); + + /* + * Initialize multi-socket TCP I/O wait object + */ + if (tcp_mode) + { + m->mtcp = multi_tcp_init(t->options.max_clients, &m->max_clients); + } + m->tcp_queue_limit = t->options.tcp_queue_limit; + + /* + * Allow client <-> client communication, without going through + * tun/tap interface and network stack? + */ + m->enable_c2c = t->options.enable_c2c; + + /* initialize stale routes check timer */ + if (t->options.stale_routes_check_interval > 0) + { + msg(M_INFO, "Initializing stale route check timer to run every %i seconds and to removing routes with activity timeout older than %i seconds", + t->options.stale_routes_check_interval, t->options.stale_routes_ageing_time); + event_timeout_init(&m->stale_routes_check_et, t->options.stale_routes_check_interval, 0); + } + + m->deferred_shutdown_signal.signal_received = 0; } const char * -multi_instance_string (const struct multi_instance *mi, bool null, struct gc_arena *gc) +multi_instance_string(const struct multi_instance *mi, bool null, struct gc_arena *gc) { - if (mi) + if (mi) { - struct buffer out = alloc_buf_gc (MULTI_PREFIX_MAX_LENGTH, gc); - const char *cn = tls_common_name (mi->context.c2.tls_multi, true); + struct buffer out = alloc_buf_gc(MULTI_PREFIX_MAX_LENGTH, gc); + const char *cn = tls_common_name(mi->context.c2.tls_multi, true); - if (cn) - buf_printf (&out, "%s/", cn); - buf_printf (&out, "%s", mroute_addr_print (&mi->real, gc)); - return BSTR (&out); + if (cn) + { + buf_printf(&out, "%s/", cn); + } + buf_printf(&out, "%s", mroute_addr_print(&mi->real, gc)); + return BSTR(&out); + } + else if (null) + { + return NULL; + } + else + { + return "UNDEF"; } - else if (null) - return NULL; - else - return "UNDEF"; } void -generate_prefix (struct multi_instance *mi) +generate_prefix(struct multi_instance *mi) { - struct gc_arena gc = gc_new(); - const char *prefix = multi_instance_string (mi, true, &gc); - if (prefix) - strncpynt(mi->msg_prefix, prefix, sizeof(mi->msg_prefix)); - else - mi->msg_prefix[0] = '\0'; - set_prefix (mi); - gc_free(&gc); + struct gc_arena gc = gc_new(); + const char *prefix = multi_instance_string(mi, true, &gc); + if (prefix) + { + strncpynt(mi->msg_prefix, prefix, sizeof(mi->msg_prefix)); + } + else + { + mi->msg_prefix[0] = '\0'; + } + set_prefix(mi); + gc_free(&gc); } void -ungenerate_prefix (struct multi_instance *mi) +ungenerate_prefix(struct multi_instance *mi) { - mi->msg_prefix[0] = '\0'; - set_prefix (mi); + mi->msg_prefix[0] = '\0'; + set_prefix(mi); } static const char * -mi_prefix (const struct multi_instance *mi) +mi_prefix(const struct multi_instance *mi) { - if (mi && mi->msg_prefix[0]) - return mi->msg_prefix; - else - return "UNDEF_I"; + if (mi && mi->msg_prefix[0]) + { + return mi->msg_prefix; + } + else + { + return "UNDEF_I"; + } } /* @@ -485,219 +529,233 @@ mi_prefix (const struct multi_instance *mi) * CIDR netlengths. */ static void -multi_del_iroutes (struct multi_context *m, - struct multi_instance *mi) +multi_del_iroutes(struct multi_context *m, + struct multi_instance *mi) { - const struct iroute *ir; - const struct iroute_ipv6 *ir6; - if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) + const struct iroute *ir; + const struct iroute_ipv6 *ir6; + if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) { - for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) - mroute_helper_del_iroute46 (m->route_helper, ir->netbits); + for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) + mroute_helper_del_iroute46(m->route_helper, ir->netbits); - for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next ) - mroute_helper_del_iroute46 (m->route_helper, ir6->netbits); + for (ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next) + mroute_helper_del_iroute46(m->route_helper, ir6->netbits); } } static void -setenv_stats (struct context *c) +setenv_stats(struct context *c) { - setenv_counter (c->c2.es, "bytes_received", c->c2.link_read_bytes); - setenv_counter (c->c2.es, "bytes_sent", c->c2.link_write_bytes); + setenv_counter(c->c2.es, "bytes_received", c->c2.link_read_bytes); + setenv_counter(c->c2.es, "bytes_sent", c->c2.link_write_bytes); } static void -multi_client_disconnect_setenv (struct multi_context *m, - struct multi_instance *mi) +multi_client_disconnect_setenv(struct multi_context *m, + struct multi_instance *mi) { - /* setenv client real IP address */ - setenv_trusted (mi->context.c2.es, get_link_socket_info (&mi->context)); + /* setenv client real IP address */ + setenv_trusted(mi->context.c2.es, get_link_socket_info(&mi->context)); - /* setenv stats */ - setenv_stats (&mi->context); + /* setenv stats */ + setenv_stats(&mi->context); - /* setenv connection duration */ - { - const unsigned int duration = (unsigned int) now - mi->created; - setenv_unsigned (mi->context.c2.es, "time_duration", duration); - } + /* setenv connection duration */ + { + const unsigned int duration = (unsigned int) now - mi->created; + setenv_unsigned(mi->context.c2.es, "time_duration", duration); + } } static void -multi_client_disconnect_script (struct multi_context *m, - struct multi_instance *mi) -{ - if ((mi->context.c2.context_auth == CAS_SUCCEEDED && mi->connection_established_flag) - || mi->context.c2.context_auth == CAS_PARTIAL) - { - multi_client_disconnect_setenv (m, mi); - - if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT)) - { - if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - msg (M_WARN, "WARNING: client-disconnect plugin call failed"); - } - - if (mi->context.options.client_disconnect_script) - { - struct argv argv = argv_new (); - setenv_str (mi->context.c2.es, "script_type", "client-disconnect"); - argv_parse_cmd (&argv, mi->context.options.client_disconnect_script); - openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-disconnect"); - argv_reset (&argv); - } +multi_client_disconnect_script(struct multi_context *m, + struct multi_instance *mi) +{ + if ((mi->context.c2.context_auth == CAS_SUCCEEDED && mi->connection_established_flag) + || mi->context.c2.context_auth == CAS_PARTIAL) + { + multi_client_disconnect_setenv(m, mi); + + if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT)) + { + if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(M_WARN, "WARNING: client-disconnect plugin call failed"); + } + } + + if (mi->context.options.client_disconnect_script) + { + struct argv argv = argv_new(); + setenv_str(mi->context.c2.es, "script_type", "client-disconnect"); + argv_parse_cmd(&argv, mi->context.options.client_disconnect_script); + openvpn_run_script(&argv, mi->context.c2.es, 0, "--client-disconnect"); + argv_reset(&argv); + } #ifdef MANAGEMENT_DEF_AUTH - if (management) - management_notify_client_close (management, &mi->context.c2.mda_context, mi->context.c2.es); + if (management) + { + management_notify_client_close(management, &mi->context.c2.mda_context, mi->context.c2.es); + } #endif } } void -multi_close_instance (struct multi_context *m, - struct multi_instance *mi, - bool shutdown) -{ - perf_push (PERF_MULTI_CLOSE_INSTANCE); - - ASSERT (!mi->halt); - mi->halt = true; - - dmsg (D_MULTI_DEBUG, "MULTI: multi_close_instance called"); - - /* adjust current client connection count */ - m->n_clients += mi->n_clients_delta; - update_mstat_n_clients(m->n_clients); - mi->n_clients_delta = 0; - - /* prevent dangling pointers */ - if (m->pending == mi) - multi_set_pending (m, NULL); - if (m->earliest_wakeup == mi) - m->earliest_wakeup = NULL; - - if (!shutdown) - { - if (mi->did_real_hash) - { - ASSERT (hash_remove (m->hash, &mi->real)); - } - if (mi->did_iter) - { - ASSERT (hash_remove (m->iter, &mi->real)); - } +multi_close_instance(struct multi_context *m, + struct multi_instance *mi, + bool shutdown) +{ + perf_push(PERF_MULTI_CLOSE_INSTANCE); + + ASSERT(!mi->halt); + mi->halt = true; + + dmsg(D_MULTI_DEBUG, "MULTI: multi_close_instance called"); + + /* adjust current client connection count */ + m->n_clients += mi->n_clients_delta; + update_mstat_n_clients(m->n_clients); + mi->n_clients_delta = 0; + + /* prevent dangling pointers */ + if (m->pending == mi) + { + multi_set_pending(m, NULL); + } + if (m->earliest_wakeup == mi) + { + m->earliest_wakeup = NULL; + } + + if (!shutdown) + { + if (mi->did_real_hash) + { + ASSERT(hash_remove(m->hash, &mi->real)); + } + if (mi->did_iter) + { + ASSERT(hash_remove(m->iter, &mi->real)); + } #ifdef MANAGEMENT_DEF_AUTH - if (mi->did_cid_hash) - { - ASSERT (hash_remove (m->cid_hash, &mi->context.c2.mda_context.cid)); - } + if (mi->did_cid_hash) + { + ASSERT(hash_remove(m->cid_hash, &mi->context.c2.mda_context.cid)); + } #endif #ifdef ENABLE_ASYNC_PUSH - if (mi->inotify_watch != -1) - { - hash_remove(m->inotify_watchers, (void*) (unsigned long)mi->inotify_watch); - mi->inotify_watch = -1; - } + if (mi->inotify_watch != -1) + { + hash_remove(m->inotify_watchers, (void *) (unsigned long)mi->inotify_watch); + mi->inotify_watch = -1; + } #endif - if (mi->context.c2.tls_multi->peer_id != MAX_PEER_ID) - m->instances[mi->context.c2.tls_multi->peer_id] = NULL; + if (mi->context.c2.tls_multi->peer_id != MAX_PEER_ID) + { + m->instances[mi->context.c2.tls_multi->peer_id] = NULL; + } - schedule_remove_entry (m->schedule, (struct schedule_entry *) mi); + schedule_remove_entry(m->schedule, (struct schedule_entry *) mi); - ifconfig_pool_release (m->ifconfig_pool, mi->vaddr_handle, false); - - if (mi->did_iroutes) + ifconfig_pool_release(m->ifconfig_pool, mi->vaddr_handle, false); + + if (mi->did_iroutes) { - multi_del_iroutes (m, mi); - mi->did_iroutes = false; + multi_del_iroutes(m, mi); + mi->did_iroutes = false; } - if (m->mtcp) - multi_tcp_dereference_instance (m->mtcp, mi); + if (m->mtcp) + { + multi_tcp_dereference_instance(m->mtcp, mi); + } - mbuf_dereference_instance (m->mbuf, mi); + mbuf_dereference_instance(m->mbuf, mi); } #ifdef MANAGEMENT_DEF_AUTH - set_cc_config (mi, NULL); + set_cc_config(mi, NULL); #endif - multi_client_disconnect_script (m, mi); + multi_client_disconnect_script(m, mi); - if (mi->did_open_context) - close_context (&mi->context, SIGTERM, CC_GC_FREE); + if (mi->did_open_context) + { + close_context(&mi->context, SIGTERM, CC_GC_FREE); + } - multi_tcp_instance_specific_free (mi); + multi_tcp_instance_specific_free(mi); - ungenerate_prefix (mi); + ungenerate_prefix(mi); - /* - * Don't actually delete the instance memory allocation yet, - * because virtual routes may still point to it. Let the - * vhash reaper deal with it. - */ - multi_instance_dec_refcount (mi); + /* + * Don't actually delete the instance memory allocation yet, + * because virtual routes may still point to it. Let the + * vhash reaper deal with it. + */ + multi_instance_dec_refcount(mi); - perf_pop (); + perf_pop(); } /* * Called on shutdown or restart. */ void -multi_uninit (struct multi_context *m) +multi_uninit(struct multi_context *m) { - if (m->thread_mode & MC_WORK_THREAD) + if (m->thread_mode & MC_WORK_THREAD) { - multi_top_free (m); - m->thread_mode = MC_UNDEF; + multi_top_free(m); + m->thread_mode = MC_UNDEF; } - else if (m->thread_mode) + else if (m->thread_mode) { - if (m->hash) - { - struct hash_iterator hi; - struct hash_element *he; - - hash_iterator_init (m->iter, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct multi_instance *mi = (struct multi_instance *) he->value; - mi->did_iter = false; - multi_close_instance (m, mi, true); - } - hash_iterator_free (&hi); - - multi_reap_all (m); - - hash_free (m->hash); - hash_free (m->vhash); - hash_free (m->iter); + if (m->hash) + { + struct hash_iterator hi; + struct hash_element *he; + + hash_iterator_init(m->iter, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct multi_instance *mi = (struct multi_instance *) he->value; + mi->did_iter = false; + multi_close_instance(m, mi, true); + } + hash_iterator_free(&hi); + + multi_reap_all(m); + + hash_free(m->hash); + hash_free(m->vhash); + hash_free(m->iter); #ifdef MANAGEMENT_DEF_AUTH - hash_free (m->cid_hash); + hash_free(m->cid_hash); #endif - m->hash = NULL; + m->hash = NULL; - free(m->instances); + free(m->instances); #ifdef ENABLE_ASYNC_PUSH - hash_free (m->inotify_watchers); - m->inotify_watchers = NULL; + hash_free(m->inotify_watchers); + m->inotify_watchers = NULL; #endif - schedule_free (m->schedule); - mbuf_free (m->mbuf); - ifconfig_pool_free (m->ifconfig_pool); - frequency_limit_free (m->new_connection_limiter); - multi_reap_free (m->reaper); - mroute_helper_free (m->route_helper); - multi_tcp_free (m->mtcp); - m->thread_mode = MC_UNDEF; - } + schedule_free(m->schedule); + mbuf_free(m->mbuf); + ifconfig_pool_free(m->ifconfig_pool); + frequency_limit_free(m->new_connection_limiter); + multi_reap_free(m->reaper); + mroute_helper_free(m->route_helper); + multi_tcp_free(m->mtcp); + m->thread_mode = MC_UNDEF; + } } } @@ -705,86 +763,90 @@ multi_uninit (struct multi_context *m) * Create a client instance object for a newly connected client. */ struct multi_instance * -multi_create_instance (struct multi_context *m, const struct mroute_addr *real) +multi_create_instance(struct multi_context *m, const struct mroute_addr *real) { - struct gc_arena gc = gc_new (); - struct multi_instance *mi; + struct gc_arena gc = gc_new(); + struct multi_instance *mi; - perf_push (PERF_MULTI_CREATE_INSTANCE); + perf_push(PERF_MULTI_CREATE_INSTANCE); - msg (D_MULTI_MEDIUM, "MULTI: multi_create_instance called"); + msg(D_MULTI_MEDIUM, "MULTI: multi_create_instance called"); - ALLOC_OBJ_CLEAR (mi, struct multi_instance); + ALLOC_OBJ_CLEAR(mi, struct multi_instance); - mi->gc = gc_new (); - multi_instance_inc_refcount (mi); - mi->vaddr_handle = -1; - mi->created = now; - mroute_addr_init (&mi->real); + mi->gc = gc_new(); + multi_instance_inc_refcount(mi); + mi->vaddr_handle = -1; + mi->created = now; + mroute_addr_init(&mi->real); - if (real) + if (real) { - mi->real = *real; - generate_prefix (mi); + mi->real = *real; + generate_prefix(mi); } - mi->did_open_context = true; - inherit_context_child (&mi->context, &m->top); - if (IS_SIG (&mi->context)) - goto err; + mi->did_open_context = true; + inherit_context_child(&mi->context, &m->top); + if (IS_SIG(&mi->context)) + { + goto err; + } - mi->context.c2.context_auth = CAS_PENDING; + mi->context.c2.context_auth = CAS_PENDING; - if (hash_n_elements (m->hash) >= m->max_clients) + if (hash_n_elements(m->hash) >= m->max_clients) { - msg (D_MULTI_ERRORS, "MULTI: new incoming connection would exceed maximum number of clients (%d)", m->max_clients); - goto err; + msg(D_MULTI_ERRORS, "MULTI: new incoming connection would exceed maximum number of clients (%d)", m->max_clients); + goto err; } - if (!real) /* TCP mode? */ + if (!real) /* TCP mode? */ { - if (!multi_tcp_instance_specific_init (m, mi)) - goto err; - generate_prefix (mi); + if (!multi_tcp_instance_specific_init(m, mi)) + { + goto err; + } + generate_prefix(mi); } - if (!hash_add (m->iter, &mi->real, mi, false)) + if (!hash_add(m->iter, &mi->real, mi, false)) { - msg (D_MULTI_LOW, "MULTI: unable to add real address [%s] to iterator hash table", - mroute_addr_print (&mi->real, &gc)); - goto err; + msg(D_MULTI_LOW, "MULTI: unable to add real address [%s] to iterator hash table", + mroute_addr_print(&mi->real, &gc)); + goto err; } - mi->did_iter = true; + mi->did_iter = true; #ifdef MANAGEMENT_DEF_AUTH - do { - mi->context.c2.mda_context.cid = m->cid_counter++; - } while (!hash_add (m->cid_hash, &mi->context.c2.mda_context.cid, mi, false)); - mi->did_cid_hash = true; + do { + mi->context.c2.mda_context.cid = m->cid_counter++; + } while (!hash_add(m->cid_hash, &mi->context.c2.mda_context.cid, mi, false)); + mi->did_cid_hash = true; #endif - mi->context.c2.push_reply_deferred = true; + mi->context.c2.push_reply_deferred = true; #ifdef ENABLE_ASYNC_PUSH - mi->context.c2.push_request_received = false; - mi->inotify_watch = -1; + mi->context.c2.push_request_received = false; + mi->inotify_watch = -1; #endif - if (!multi_process_post (m, mi, MPP_PRE_SELECT)) + if (!multi_process_post(m, mi, MPP_PRE_SELECT)) { - msg (D_MULTI_ERRORS, "MULTI: signal occurred during client instance initialization"); - goto err; + msg(D_MULTI_ERRORS, "MULTI: signal occurred during client instance initialization"); + goto err; } - perf_pop (); - gc_free (&gc); - return mi; + perf_pop(); + gc_free(&gc); + return mi; - err: - multi_close_instance (m, mi, false); - perf_pop (); - gc_free (&gc); - return NULL; +err: + multi_close_instance(m, mi, false); + perf_pop(); + gc_free(&gc); + return NULL; } /* @@ -793,194 +855,202 @@ multi_create_instance (struct multi_context *m, const struct mroute_addr *real) * If status file is NULL, write to syslog. */ void -multi_print_status (struct multi_context *m, struct status_output *so, const int version) -{ - if (m->hash) - { - struct gc_arena gc_top = gc_new (); - struct hash_iterator hi; - const struct hash_element *he; - - status_reset (so); - - if (version == 1) /* WAS: m->status_file_version */ - { - /* - * Status file version 1 - */ - status_printf (so, "OpenVPN CLIENT LIST"); - status_printf (so, "Updated,%s", time_string (0, 0, false, &gc_top)); - status_printf (so, "Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since"); - hash_iterator_init (m->hash, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct gc_arena gc = gc_new (); - const struct multi_instance *mi = (struct multi_instance *) he->value; - - if (!mi->halt) - { - status_printf (so, "%s,%s," counter_format "," counter_format ",%s", - tls_common_name (mi->context.c2.tls_multi, false), - mroute_addr_print (&mi->real, &gc), - mi->context.c2.link_read_bytes, - mi->context.c2.link_write_bytes, - time_string (mi->created, 0, false, &gc)); - } - gc_free (&gc); - } - hash_iterator_free (&hi); - - status_printf (so, "ROUTING TABLE"); - status_printf (so, "Virtual Address,Common Name,Real Address,Last Ref"); - hash_iterator_init (m->vhash, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct gc_arena gc = gc_new (); - const struct multi_route *route = (struct multi_route *) he->value; - - if (multi_route_defined (m, route)) - { - const struct multi_instance *mi = route->instance; - const struct mroute_addr *ma = &route->addr; - char flags[2] = {0, 0}; - - if (route->flags & MULTI_ROUTE_CACHE) - flags[0] = 'C'; - status_printf (so, "%s%s,%s,%s,%s", - mroute_addr_print (ma, &gc), - flags, - tls_common_name (mi->context.c2.tls_multi, false), - mroute_addr_print (&mi->real, &gc), - time_string (route->last_reference, 0, false, &gc)); - } - gc_free (&gc); - } - hash_iterator_free (&hi); - - status_printf (so, "GLOBAL STATS"); - if (m->mbuf) - status_printf (so, "Max bcast/mcast queue length,%d", - mbuf_maximum_queued (m->mbuf)); - - status_printf (so, "END"); - } - else if (version == 2 || version == 3) - { - const char sep = (version == 3) ? '\t' : ','; - - /* - * Status file version 2 and 3 - */ - status_printf (so, "TITLE%c%s", sep, title_string); - status_printf (so, "TIME%c%s%c%u", sep, time_string (now, 0, false, &gc_top), sep, (unsigned int)now); - status_printf (so, "HEADER%cCLIENT_LIST%cCommon Name%cReal Address%cVirtual Address%cVirtual IPv6 Address%cBytes Received%cBytes Sent%cConnected Since%cConnected Since (time_t)%cUsername%cClient ID%cPeer ID", - sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep); - hash_iterator_init (m->hash, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct gc_arena gc = gc_new (); - const struct multi_instance *mi = (struct multi_instance *) he->value; - - if (!mi->halt) - { - status_printf (so, "CLIENT_LIST%c%s%c%s%c%s%c%s%c" counter_format "%c" counter_format "%c%s%c%u%c%s%c" +multi_print_status(struct multi_context *m, struct status_output *so, const int version) +{ + if (m->hash) + { + struct gc_arena gc_top = gc_new(); + struct hash_iterator hi; + const struct hash_element *he; + + status_reset(so); + + if (version == 1) /* WAS: m->status_file_version */ + { + /* + * Status file version 1 + */ + status_printf(so, "OpenVPN CLIENT LIST"); + status_printf(so, "Updated,%s", time_string(0, 0, false, &gc_top)); + status_printf(so, "Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since"); + hash_iterator_init(m->hash, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct gc_arena gc = gc_new(); + const struct multi_instance *mi = (struct multi_instance *) he->value; + + if (!mi->halt) + { + status_printf(so, "%s,%s," counter_format "," counter_format ",%s", + tls_common_name(mi->context.c2.tls_multi, false), + mroute_addr_print(&mi->real, &gc), + mi->context.c2.link_read_bytes, + mi->context.c2.link_write_bytes, + time_string(mi->created, 0, false, &gc)); + } + gc_free(&gc); + } + hash_iterator_free(&hi); + + status_printf(so, "ROUTING TABLE"); + status_printf(so, "Virtual Address,Common Name,Real Address,Last Ref"); + hash_iterator_init(m->vhash, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct gc_arena gc = gc_new(); + const struct multi_route *route = (struct multi_route *) he->value; + + if (multi_route_defined(m, route)) + { + const struct multi_instance *mi = route->instance; + const struct mroute_addr *ma = &route->addr; + char flags[2] = {0, 0}; + + if (route->flags & MULTI_ROUTE_CACHE) + { + flags[0] = 'C'; + } + status_printf(so, "%s%s,%s,%s,%s", + mroute_addr_print(ma, &gc), + flags, + tls_common_name(mi->context.c2.tls_multi, false), + mroute_addr_print(&mi->real, &gc), + time_string(route->last_reference, 0, false, &gc)); + } + gc_free(&gc); + } + hash_iterator_free(&hi); + + status_printf(so, "GLOBAL STATS"); + if (m->mbuf) + { + status_printf(so, "Max bcast/mcast queue length,%d", + mbuf_maximum_queued(m->mbuf)); + } + + status_printf(so, "END"); + } + else if (version == 2 || version == 3) + { + const char sep = (version == 3) ? '\t' : ','; + + /* + * Status file version 2 and 3 + */ + status_printf(so, "TITLE%c%s", sep, title_string); + status_printf(so, "TIME%c%s%c%u", sep, time_string(now, 0, false, &gc_top), sep, (unsigned int)now); + status_printf(so, "HEADER%cCLIENT_LIST%cCommon Name%cReal Address%cVirtual Address%cVirtual IPv6 Address%cBytes Received%cBytes Sent%cConnected Since%cConnected Since (time_t)%cUsername%cClient ID%cPeer ID", + sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep); + hash_iterator_init(m->hash, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct gc_arena gc = gc_new(); + const struct multi_instance *mi = (struct multi_instance *) he->value; + + if (!mi->halt) + { + status_printf(so, "CLIENT_LIST%c%s%c%s%c%s%c%s%c" counter_format "%c" counter_format "%c%s%c%u%c%s%c" #ifdef MANAGEMENT_DEF_AUTH - "%lu" + "%lu" #else - "" + "" #endif - "%c%"PRIu32, - sep, tls_common_name (mi->context.c2.tls_multi, false), - sep, mroute_addr_print (&mi->real, &gc), - sep, print_in_addr_t (mi->reporting_addr, IA_EMPTY_IF_UNDEF, &gc), - sep, print_in6_addr (mi->reporting_addr_ipv6, IA_EMPTY_IF_UNDEF, &gc), - sep, mi->context.c2.link_read_bytes, - sep, mi->context.c2.link_write_bytes, - sep, time_string (mi->created, 0, false, &gc), - sep, (unsigned int)mi->created, - sep, tls_username (mi->context.c2.tls_multi, false), + "%c%" PRIu32, + sep, tls_common_name(mi->context.c2.tls_multi, false), + sep, mroute_addr_print(&mi->real, &gc), + sep, print_in_addr_t(mi->reporting_addr, IA_EMPTY_IF_UNDEF, &gc), + sep, print_in6_addr(mi->reporting_addr_ipv6, IA_EMPTY_IF_UNDEF, &gc), + sep, mi->context.c2.link_read_bytes, + sep, mi->context.c2.link_write_bytes, + sep, time_string(mi->created, 0, false, &gc), + sep, (unsigned int)mi->created, + sep, tls_username(mi->context.c2.tls_multi, false), #ifdef MANAGEMENT_DEF_AUTH - sep, mi->context.c2.mda_context.cid, + sep, mi->context.c2.mda_context.cid, #else - sep, + sep, #endif - sep, mi->context.c2.tls_multi ? mi->context.c2.tls_multi->peer_id : UINT32_MAX); - } - gc_free (&gc); - } - hash_iterator_free (&hi); - - status_printf (so, "HEADER%cROUTING_TABLE%cVirtual Address%cCommon Name%cReal Address%cLast Ref%cLast Ref (time_t)", - sep, sep, sep, sep, sep, sep); - hash_iterator_init (m->vhash, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct gc_arena gc = gc_new (); - const struct multi_route *route = (struct multi_route *) he->value; - - if (multi_route_defined (m, route)) - { - const struct multi_instance *mi = route->instance; - const struct mroute_addr *ma = &route->addr; - char flags[2] = {0, 0}; - - if (route->flags & MULTI_ROUTE_CACHE) - flags[0] = 'C'; - status_printf (so, "ROUTING_TABLE%c%s%s%c%s%c%s%c%s%c%u", - sep, mroute_addr_print (ma, &gc), flags, - sep, tls_common_name (mi->context.c2.tls_multi, false), - sep, mroute_addr_print (&mi->real, &gc), - sep, time_string (route->last_reference, 0, false, &gc), - sep, (unsigned int)route->last_reference); - } - gc_free (&gc); - } - hash_iterator_free (&hi); - - if (m->mbuf) - status_printf (so, "GLOBAL_STATS%cMax bcast/mcast queue length%c%d", - sep, sep, mbuf_maximum_queued (m->mbuf)); - - status_printf (so, "END"); - } - else - { - status_printf (so, "ERROR: bad status format version number"); - } + sep, mi->context.c2.tls_multi ? mi->context.c2.tls_multi->peer_id : UINT32_MAX); + } + gc_free(&gc); + } + hash_iterator_free(&hi); + + status_printf(so, "HEADER%cROUTING_TABLE%cVirtual Address%cCommon Name%cReal Address%cLast Ref%cLast Ref (time_t)", + sep, sep, sep, sep, sep, sep); + hash_iterator_init(m->vhash, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct gc_arena gc = gc_new(); + const struct multi_route *route = (struct multi_route *) he->value; + + if (multi_route_defined(m, route)) + { + const struct multi_instance *mi = route->instance; + const struct mroute_addr *ma = &route->addr; + char flags[2] = {0, 0}; + + if (route->flags & MULTI_ROUTE_CACHE) + { + flags[0] = 'C'; + } + status_printf(so, "ROUTING_TABLE%c%s%s%c%s%c%s%c%s%c%u", + sep, mroute_addr_print(ma, &gc), flags, + sep, tls_common_name(mi->context.c2.tls_multi, false), + sep, mroute_addr_print(&mi->real, &gc), + sep, time_string(route->last_reference, 0, false, &gc), + sep, (unsigned int)route->last_reference); + } + gc_free(&gc); + } + hash_iterator_free(&hi); + + if (m->mbuf) + { + status_printf(so, "GLOBAL_STATS%cMax bcast/mcast queue length%c%d", + sep, sep, mbuf_maximum_queued(m->mbuf)); + } + + status_printf(so, "END"); + } + else + { + status_printf(so, "ERROR: bad status format version number"); + } #ifdef PACKET_TRUNCATION_CHECK - { - status_printf (so, "HEADER,ERRORS,Common Name,TUN Read Trunc,TUN Write Trunc,Pre-encrypt Trunc,Post-decrypt Trunc"); - hash_iterator_init (m->hash, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct gc_arena gc = gc_new (); - const struct multi_instance *mi = (struct multi_instance *) he->value; - - if (!mi->halt) - { - status_printf (so, "ERRORS,%s," counter_format "," counter_format "," counter_format "," counter_format, - tls_common_name (mi->context.c2.tls_multi, false), - m->top.c2.n_trunc_tun_read, - mi->context.c2.n_trunc_tun_write, - mi->context.c2.n_trunc_pre_encrypt, - mi->context.c2.n_trunc_post_decrypt); - } - gc_free (&gc); - } - hash_iterator_free (&hi); - } -#endif + { + status_printf(so, "HEADER,ERRORS,Common Name,TUN Read Trunc,TUN Write Trunc,Pre-encrypt Trunc,Post-decrypt Trunc"); + hash_iterator_init(m->hash, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct gc_arena gc = gc_new(); + const struct multi_instance *mi = (struct multi_instance *) he->value; + + if (!mi->halt) + { + status_printf(so, "ERRORS,%s," counter_format "," counter_format "," counter_format "," counter_format, + tls_common_name(mi->context.c2.tls_multi, false), + m->top.c2.n_trunc_tun_read, + mi->context.c2.n_trunc_tun_write, + mi->context.c2.n_trunc_pre_encrypt, + mi->context.c2.n_trunc_post_decrypt); + } + gc_free(&gc); + } + hash_iterator_free(&hi); + } +#endif /* ifdef PACKET_TRUNCATION_CHECK */ - status_flush (so); - gc_free (&gc_top); + status_flush(so); + gc_free(&gc_top); } #ifdef ENABLE_ASYNC_PUSH - if (m->inotify_watchers) - { - msg (D_MULTI_DEBUG, "inotify watchers count: %d\n", hash_n_elements(m->inotify_watchers)); - } + if (m->inotify_watchers) + { + msg(D_MULTI_DEBUG, "inotify watchers count: %d\n", hash_n_elements(m->inotify_watchers)); + } #endif } @@ -993,229 +1063,243 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int * or NULL if none. */ static struct multi_instance * -multi_learn_addr (struct multi_context *m, - struct multi_instance *mi, - const struct mroute_addr *addr, - const unsigned int flags) -{ - struct hash_element *he; - const uint32_t hv = hash_value (m->vhash, addr); - struct hash_bucket *bucket = hash_bucket (m->vhash, hv); - struct multi_route *oldroute = NULL; - struct multi_instance *owner = NULL; - - /* if route currently exists, get the instance which owns it */ - he = hash_lookup_fast (m->vhash, bucket, addr, hv); - if (he) - oldroute = (struct multi_route *) he->value; - if (oldroute && multi_route_defined (m, oldroute)) - owner = oldroute->instance; - - /* do we need to add address to hash table? */ - if ((!owner || owner != mi) - && mroute_learnable_address (addr) - && !mroute_addr_equal (addr, &m->local)) - { - struct gc_arena gc = gc_new (); - struct multi_route *newroute; - bool learn_succeeded = false; - - ALLOC_OBJ (newroute, struct multi_route); - newroute->addr = *addr; - newroute->instance = mi; - newroute->flags = flags; - newroute->last_reference = now; - newroute->cache_generation = 0; - - /* The cache is invalidated when cache_generation is incremented */ - if (flags & MULTI_ROUTE_CACHE) - newroute->cache_generation = m->route_helper->cache_generation; - - if (oldroute) /* route already exists? */ - { - if (route_quota_test (m, mi) && learn_address_script (m, mi, "update", &newroute->addr)) - { - learn_succeeded = true; - owner = mi; - multi_instance_inc_refcount (mi); - route_quota_inc (mi); - - /* delete old route */ - multi_route_del (oldroute); - - /* modify hash table entry, replacing old route */ - he->key = &newroute->addr; - he->value = newroute; - } - } - else - { - if (route_quota_test (m, mi) && learn_address_script (m, mi, "add", &newroute->addr)) - { - learn_succeeded = true; - owner = mi; - multi_instance_inc_refcount (mi); - route_quota_inc (mi); - - /* add new route */ - hash_add_fast (m->vhash, bucket, &newroute->addr, hv, newroute); - } - } - - msg (D_MULTI_LOW, "MULTI: Learn%s: %s -> %s", - learn_succeeded ? "" : " FAILED", - mroute_addr_print (&newroute->addr, &gc), - multi_instance_string (mi, false, &gc)); - - if (!learn_succeeded) - free (newroute); - - gc_free (&gc); - } - - return owner; +multi_learn_addr(struct multi_context *m, + struct multi_instance *mi, + const struct mroute_addr *addr, + const unsigned int flags) +{ + struct hash_element *he; + const uint32_t hv = hash_value(m->vhash, addr); + struct hash_bucket *bucket = hash_bucket(m->vhash, hv); + struct multi_route *oldroute = NULL; + struct multi_instance *owner = NULL; + + /* if route currently exists, get the instance which owns it */ + he = hash_lookup_fast(m->vhash, bucket, addr, hv); + if (he) + { + oldroute = (struct multi_route *) he->value; + } + if (oldroute && multi_route_defined(m, oldroute)) + { + owner = oldroute->instance; + } + + /* do we need to add address to hash table? */ + if ((!owner || owner != mi) + && mroute_learnable_address(addr) + && !mroute_addr_equal(addr, &m->local)) + { + struct gc_arena gc = gc_new(); + struct multi_route *newroute; + bool learn_succeeded = false; + + ALLOC_OBJ(newroute, struct multi_route); + newroute->addr = *addr; + newroute->instance = mi; + newroute->flags = flags; + newroute->last_reference = now; + newroute->cache_generation = 0; + + /* The cache is invalidated when cache_generation is incremented */ + if (flags & MULTI_ROUTE_CACHE) + { + newroute->cache_generation = m->route_helper->cache_generation; + } + + if (oldroute) /* route already exists? */ + { + if (route_quota_test(m, mi) && learn_address_script(m, mi, "update", &newroute->addr)) + { + learn_succeeded = true; + owner = mi; + multi_instance_inc_refcount(mi); + route_quota_inc(mi); + + /* delete old route */ + multi_route_del(oldroute); + + /* modify hash table entry, replacing old route */ + he->key = &newroute->addr; + he->value = newroute; + } + } + else + { + if (route_quota_test(m, mi) && learn_address_script(m, mi, "add", &newroute->addr)) + { + learn_succeeded = true; + owner = mi; + multi_instance_inc_refcount(mi); + route_quota_inc(mi); + + /* add new route */ + hash_add_fast(m->vhash, bucket, &newroute->addr, hv, newroute); + } + } + + msg(D_MULTI_LOW, "MULTI: Learn%s: %s -> %s", + learn_succeeded ? "" : " FAILED", + mroute_addr_print(&newroute->addr, &gc), + multi_instance_string(mi, false, &gc)); + + if (!learn_succeeded) + { + free(newroute); + } + + gc_free(&gc); + } + + return owner; } /* * Get client instance based on virtual address. */ static struct multi_instance * -multi_get_instance_by_virtual_addr (struct multi_context *m, - const struct mroute_addr *addr, - bool cidr_routing) +multi_get_instance_by_virtual_addr(struct multi_context *m, + const struct mroute_addr *addr, + bool cidr_routing) { - struct multi_route *route; - struct multi_instance *ret = NULL; + struct multi_route *route; + struct multi_instance *ret = NULL; - /* check for local address */ - if (mroute_addr_equal (addr, &m->local)) - return NULL; + /* check for local address */ + if (mroute_addr_equal(addr, &m->local)) + { + return NULL; + } - route = (struct multi_route *) hash_lookup (m->vhash, addr); + route = (struct multi_route *) hash_lookup(m->vhash, addr); - /* does host route (possible cached) exist? */ - if (route && multi_route_defined (m, route)) + /* does host route (possible cached) exist? */ + if (route && multi_route_defined(m, route)) { - struct multi_instance *mi = route->instance; - route->last_reference = now; - ret = mi; + struct multi_instance *mi = route->instance; + route->last_reference = now; + ret = mi; } - else if (cidr_routing) /* do we need to regenerate a host route cache entry? */ + else if (cidr_routing) /* do we need to regenerate a host route cache entry? */ { - struct mroute_helper *rh = m->route_helper; - struct mroute_addr tryaddr; - int i; - - /* cycle through each CIDR length */ - for (i = 0; i < rh->n_net_len; ++i) - { - tryaddr = *addr; - tryaddr.type |= MR_WITH_NETBITS; - tryaddr.netbits = rh->net_len[i]; - mroute_addr_mask_host_bits (&tryaddr); + struct mroute_helper *rh = m->route_helper; + struct mroute_addr tryaddr; + int i; - /* look up a possible route with netbits netmask */ - route = (struct multi_route *) hash_lookup (m->vhash, &tryaddr); - - if (route && multi_route_defined (m, route)) - { - /* found an applicable route, cache host route */ - struct multi_instance *mi = route->instance; - multi_learn_addr (m, mi, addr, MULTI_ROUTE_CACHE|MULTI_ROUTE_AGEABLE); - ret = mi; - break; - } - } + /* cycle through each CIDR length */ + for (i = 0; i < rh->n_net_len; ++i) + { + tryaddr = *addr; + tryaddr.type |= MR_WITH_NETBITS; + tryaddr.netbits = rh->net_len[i]; + mroute_addr_mask_host_bits(&tryaddr); + + /* look up a possible route with netbits netmask */ + route = (struct multi_route *) hash_lookup(m->vhash, &tryaddr); + + if (route && multi_route_defined(m, route)) + { + /* found an applicable route, cache host route */ + struct multi_instance *mi = route->instance; + multi_learn_addr(m, mi, addr, MULTI_ROUTE_CACHE|MULTI_ROUTE_AGEABLE); + ret = mi; + break; + } + } } - + #ifdef ENABLE_DEBUG - if (check_debug_level (D_MULTI_DEBUG)) - { - struct gc_arena gc = gc_new (); - const char *addr_text = mroute_addr_print (addr, &gc); - if (ret) - { - dmsg (D_MULTI_DEBUG, "GET INST BY VIRT: %s -> %s via %s", - addr_text, - multi_instance_string (ret, false, &gc), - mroute_addr_print (&route->addr, &gc)); - } - else - { - dmsg (D_MULTI_DEBUG, "GET INST BY VIRT: %s [failed]", - addr_text); - } - gc_free (&gc); + if (check_debug_level(D_MULTI_DEBUG)) + { + struct gc_arena gc = gc_new(); + const char *addr_text = mroute_addr_print(addr, &gc); + if (ret) + { + dmsg(D_MULTI_DEBUG, "GET INST BY VIRT: %s -> %s via %s", + addr_text, + multi_instance_string(ret, false, &gc), + mroute_addr_print(&route->addr, &gc)); + } + else + { + dmsg(D_MULTI_DEBUG, "GET INST BY VIRT: %s [failed]", + addr_text); + } + gc_free(&gc); } #endif - ASSERT (!(ret && ret->halt)); - return ret; + ASSERT(!(ret && ret->halt)); + return ret; } /* * Helper function to multi_learn_addr(). */ static struct multi_instance * -multi_learn_in_addr_t (struct multi_context *m, - struct multi_instance *mi, - in_addr_t a, - int netbits, /* -1 if host route, otherwise # of network bits in address */ - bool primary) +multi_learn_in_addr_t(struct multi_context *m, + struct multi_instance *mi, + in_addr_t a, + int netbits, /* -1 if host route, otherwise # of network bits in address */ + bool primary) { - struct openvpn_sockaddr remote_si; - struct mroute_addr addr; + struct openvpn_sockaddr remote_si; + struct mroute_addr addr; - CLEAR (remote_si); - remote_si.addr.in4.sin_family = AF_INET; - remote_si.addr.in4.sin_addr.s_addr = htonl (a); - ASSERT (mroute_extract_openvpn_sockaddr (&addr, &remote_si, false)); + CLEAR(remote_si); + remote_si.addr.in4.sin_family = AF_INET; + remote_si.addr.in4.sin_addr.s_addr = htonl(a); + ASSERT(mroute_extract_openvpn_sockaddr(&addr, &remote_si, false)); - if (netbits >= 0) + if (netbits >= 0) { - addr.type |= MR_WITH_NETBITS; - addr.netbits = (uint8_t) netbits; + addr.type |= MR_WITH_NETBITS; + addr.netbits = (uint8_t) netbits; } - { - struct multi_instance *owner = multi_learn_addr (m, mi, &addr, 0); + { + struct multi_instance *owner = multi_learn_addr(m, mi, &addr, 0); #ifdef MANAGEMENT_DEF_AUTH - if (management && owner) - management_learn_addr (management, &mi->context.c2.mda_context, &addr, primary); + if (management && owner) + { + management_learn_addr(management, &mi->context.c2.mda_context, &addr, primary); + } #endif - return owner; - } + return owner; + } } static struct multi_instance * -multi_learn_in6_addr (struct multi_context *m, - struct multi_instance *mi, - struct in6_addr a6, - int netbits, /* -1 if host route, otherwise # of network bits in address */ - bool primary) +multi_learn_in6_addr(struct multi_context *m, + struct multi_instance *mi, + struct in6_addr a6, + int netbits, /* -1 if host route, otherwise # of network bits in address */ + bool primary) { - struct mroute_addr addr; + struct mroute_addr addr; - addr.len = 16; - addr.type = MR_ADDR_IPV6; - addr.netbits = 0; - addr.v6.addr = a6; + addr.len = 16; + addr.type = MR_ADDR_IPV6; + addr.netbits = 0; + addr.v6.addr = a6; - if (netbits >= 0) + if (netbits >= 0) { - addr.type |= MR_WITH_NETBITS; - addr.netbits = (uint8_t) netbits; - mroute_addr_mask_host_bits( &addr ); + addr.type |= MR_WITH_NETBITS; + addr.netbits = (uint8_t) netbits; + mroute_addr_mask_host_bits( &addr ); } - { - struct multi_instance *owner = multi_learn_addr (m, mi, &addr, 0); + { + struct multi_instance *owner = multi_learn_addr(m, mi, &addr, 0); #ifdef MANAGEMENT_DEF_AUTH - if (management && owner) - management_learn_addr (management, &mi->context.c2.mda_context, &addr, primary); + if (management && owner) + { + management_learn_addr(management, &mi->context.c2.mda_context, &addr, primary); + } #endif - return owner; - } + return owner; + } } /* @@ -1223,44 +1307,48 @@ multi_learn_in6_addr (struct multi_context *m, * to internal routing table. */ static void -multi_add_iroutes (struct multi_context *m, - struct multi_instance *mi) -{ - struct gc_arena gc = gc_new (); - const struct iroute *ir; - const struct iroute_ipv6 *ir6; - if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) - { - mi->did_iroutes = true; - for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) - { - if (ir->netbits >= 0) - msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", - print_in_addr_t (ir->network, 0, &gc), - ir->netbits, - multi_instance_string (mi, false, &gc)); - else - msg (D_MULTI_LOW, "MULTI: internal route %s -> %s", - print_in_addr_t (ir->network, 0, &gc), - multi_instance_string (mi, false, &gc)); - - mroute_helper_add_iroute46 (m->route_helper, ir->netbits); - - multi_learn_in_addr_t (m, mi, ir->network, ir->netbits, false); - } - for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next ) - { - msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", - print_in6_addr (ir6->network, 0, &gc), - ir6->netbits, - multi_instance_string (mi, false, &gc)); - - mroute_helper_add_iroute46 (m->route_helper, ir6->netbits); - - multi_learn_in6_addr (m, mi, ir6->network, ir6->netbits, false); - } - } - gc_free (&gc); +multi_add_iroutes(struct multi_context *m, + struct multi_instance *mi) +{ + struct gc_arena gc = gc_new(); + const struct iroute *ir; + const struct iroute_ipv6 *ir6; + if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) + { + mi->did_iroutes = true; + for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) + { + if (ir->netbits >= 0) + { + msg(D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", + print_in_addr_t(ir->network, 0, &gc), + ir->netbits, + multi_instance_string(mi, false, &gc)); + } + else + { + msg(D_MULTI_LOW, "MULTI: internal route %s -> %s", + print_in_addr_t(ir->network, 0, &gc), + multi_instance_string(mi, false, &gc)); + } + + mroute_helper_add_iroute46(m->route_helper, ir->netbits); + + multi_learn_in_addr_t(m, mi, ir->network, ir->netbits, false); + } + for (ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next) + { + msg(D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", + print_in6_addr(ir6->network, 0, &gc), + ir6->netbits, + multi_instance_string(mi, false, &gc)); + + mroute_helper_add_iroute46(m->route_helper, ir6->netbits); + + multi_learn_in6_addr(m, mi, ir6->network, ir6->netbits, false); + } + } + gc_free(&gc); } /* @@ -1268,65 +1356,67 @@ multi_add_iroutes (struct multi_context *m, * same common name. */ static void -multi_delete_dup (struct multi_context *m, struct multi_instance *new_mi) -{ - if (new_mi) - { - const char *new_cn = tls_common_name (new_mi->context.c2.tls_multi, true); - if (new_cn) - { - struct hash_iterator hi; - struct hash_element *he; - int count = 0; - - hash_iterator_init (m->iter, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct multi_instance *mi = (struct multi_instance *) he->value; - if (mi != new_mi && !mi->halt) - { - const char *cn = tls_common_name (mi->context.c2.tls_multi, true); - if (cn && !strcmp (cn, new_cn)) - { - mi->did_iter = false; - multi_close_instance (m, mi, false); - hash_iterator_delete_element (&hi); - ++count; - } - } - } - hash_iterator_free (&hi); - - if (count) - msg (D_MULTI_LOW, "MULTI: new connection by client '%s' will cause previous active sessions by this client to be dropped. Remember to use the --duplicate-cn option if you want multiple clients using the same certificate or username to concurrently connect.", new_cn); - } +multi_delete_dup(struct multi_context *m, struct multi_instance *new_mi) +{ + if (new_mi) + { + const char *new_cn = tls_common_name(new_mi->context.c2.tls_multi, true); + if (new_cn) + { + struct hash_iterator hi; + struct hash_element *he; + int count = 0; + + hash_iterator_init(m->iter, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct multi_instance *mi = (struct multi_instance *) he->value; + if (mi != new_mi && !mi->halt) + { + const char *cn = tls_common_name(mi->context.c2.tls_multi, true); + if (cn && !strcmp(cn, new_cn)) + { + mi->did_iter = false; + multi_close_instance(m, mi, false); + hash_iterator_delete_element(&hi); + ++count; + } + } + } + hash_iterator_free(&hi); + + if (count) + { + msg(D_MULTI_LOW, "MULTI: new connection by client '%s' will cause previous active sessions by this client to be dropped. Remember to use the --duplicate-cn option if you want multiple clients using the same certificate or username to concurrently connect.", new_cn); + } + } } } static void -check_stale_routes (struct multi_context *m) +check_stale_routes(struct multi_context *m) { - struct gc_arena gc = gc_new (); - struct hash_iterator hi; - struct hash_element *he; + struct gc_arena gc = gc_new(); + struct hash_iterator hi; + struct hash_element *he; - dmsg (D_MULTI_DEBUG, "MULTI: Checking stale routes"); - hash_iterator_init_range (m->vhash, &hi, 0, hash_n_buckets (m->vhash)); - while ((he = hash_iterator_next (&hi)) != NULL) + dmsg(D_MULTI_DEBUG, "MULTI: Checking stale routes"); + hash_iterator_init_range(m->vhash, &hi, 0, hash_n_buckets(m->vhash)); + while ((he = hash_iterator_next(&hi)) != NULL) { - struct multi_route *r = (struct multi_route *) he->value; - if (multi_route_defined (m, r) && difftime(now, r->last_reference) >= m->top.options.stale_routes_ageing_time) + struct multi_route *r = (struct multi_route *) he->value; + if (multi_route_defined(m, r) && difftime(now, r->last_reference) >= m->top.options.stale_routes_ageing_time) { - dmsg (D_MULTI_DEBUG, "MULTI: Deleting stale route for address '%s'", - mroute_addr_print (&r->addr, &gc)); - learn_address_script (m, NULL, "delete", &r->addr); - multi_route_del (r); - hash_iterator_delete_element (&hi); + dmsg(D_MULTI_DEBUG, "MULTI: Deleting stale route for address '%s'", + mroute_addr_print(&r->addr, &gc)); + learn_address_script(m, NULL, "delete", &r->addr); + multi_route_del(r); + hash_iterator_delete_element(&hi); } } - hash_iterator_free (&hi); - gc_free (&gc); + hash_iterator_free(&hi); + gc_free(&gc); } /* @@ -1334,192 +1424,208 @@ check_stale_routes (struct multi_context *m) * complies with --ifconfig-push-constraint directive. */ static bool -ifconfig_push_constraint_satisfied (const struct context *c) +ifconfig_push_constraint_satisfied(const struct context *c) { - const struct options *o = &c->options; - if (o->push_ifconfig_constraint_defined && c->c2.push_ifconfig_defined) - return (o->push_ifconfig_constraint_netmask & c->c2.push_ifconfig_local) == o->push_ifconfig_constraint_network; - else - return true; + const struct options *o = &c->options; + if (o->push_ifconfig_constraint_defined && c->c2.push_ifconfig_defined) + { + return (o->push_ifconfig_constraint_netmask & c->c2.push_ifconfig_local) == o->push_ifconfig_constraint_network; + } + else + { + return true; + } } /* * Select a virtual address for a new client instance. * Use an --ifconfig-push directive, if given (static IP). - * Otherwise use an --ifconfig-pool address (dynamic IP). + * Otherwise use an --ifconfig-pool address (dynamic IP). */ static void -multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi) -{ - struct gc_arena gc = gc_new (); - - /* - * If ifconfig addresses were set by dynamic config file, - * release pool addresses, otherwise keep them. - */ - if (mi->context.options.push_ifconfig_defined) - { - /* ifconfig addresses were set statically, - release dynamic allocation */ - if (mi->vaddr_handle >= 0) - { - ifconfig_pool_release (m->ifconfig_pool, mi->vaddr_handle, true); - mi->vaddr_handle = -1; - } - - mi->context.c2.push_ifconfig_defined = true; - mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local; - mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask; - mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias; - - /* the current implementation does not allow "static IPv4, pool IPv6", - * (see below) so issue a warning if that happens - don't break the - * session, though, as we don't even know if this client WANTS IPv6 - */ - if ( mi->context.options.ifconfig_ipv6_pool_defined && - ! mi->context.options.push_ifconfig_ipv6_defined ) - { - msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work. Use --ifconfig-ipv6-push for IPv6 then." ); - } - } - else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */ - { - in_addr_t local=0, remote=0; - struct in6_addr remote_ipv6; - const char *cn = NULL; - - if (!mi->context.options.duplicate_cn) - cn = tls_common_name (mi->context.c2.tls_multi, true); - - CLEAR(remote_ipv6); - mi->vaddr_handle = ifconfig_pool_acquire (m->ifconfig_pool, &local, &remote, &remote_ipv6, cn); - if (mi->vaddr_handle >= 0) - { - const int tunnel_type = TUNNEL_TYPE (mi->context.c1.tuntap); - const int tunnel_topology = TUNNEL_TOPOLOGY (mi->context.c1.tuntap); - - msg( M_INFO, "MULTI_sva: pool returned IPv4=%s, IPv6=%s", - print_in_addr_t( remote, 0, &gc ), - (mi->context.options.ifconfig_ipv6_pool_defined - ? print_in6_addr( remote_ipv6, 0, &gc ) - : "(Not enabled)") ); - - /* set push_ifconfig_remote_netmask from pool ifconfig address(es) */ - mi->context.c2.push_ifconfig_local = remote; - if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) - { - mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.ifconfig_pool_netmask; - if (!mi->context.c2.push_ifconfig_remote_netmask) - mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->remote_netmask; - } - else if (tunnel_type == DEV_TYPE_TUN) - { - if (tunnel_topology == TOP_P2P) - mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->local; - else if (tunnel_topology == TOP_NET30) - mi->context.c2.push_ifconfig_remote_netmask = local; - } - - if (mi->context.c2.push_ifconfig_remote_netmask) - mi->context.c2.push_ifconfig_defined = true; - else - msg (D_MULTI_ERRORS, "MULTI: no --ifconfig-pool netmask parameter is available to push to %s", - multi_instance_string (mi, false, &gc)); - - if ( mi->context.options.ifconfig_ipv6_pool_defined ) - { - mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6; - mi->context.c2.push_ifconfig_ipv6_remote = - mi->context.c1.tuntap->local_ipv6; - mi->context.c2.push_ifconfig_ipv6_netbits = - mi->context.options.ifconfig_ipv6_netbits; - mi->context.c2.push_ifconfig_ipv6_defined = true; - } - } - else - { - msg (D_MULTI_ERRORS, "MULTI: no free --ifconfig-pool addresses are available"); - } - } - - /* IPv6 push_ifconfig is a bit problematic - since IPv6 shares the - * pool handling with IPv4, the combination "static IPv4, dynamic IPv6" - * will fail (because no pool will be allocated in this case). - * OTOH, this doesn't make too much sense in reality - and the other - * way round ("dynamic IPv4, static IPv6") or "both static" makes sense - * -> and so it's implemented right now - */ - if ( mi->context.options.push_ifconfig_ipv6_defined ) - { - mi->context.c2.push_ifconfig_ipv6_local = - mi->context.options.push_ifconfig_ipv6_local; - mi->context.c2.push_ifconfig_ipv6_remote = - mi->context.options.push_ifconfig_ipv6_remote; - mi->context.c2.push_ifconfig_ipv6_netbits = - mi->context.options.push_ifconfig_ipv6_netbits; - mi->context.c2.push_ifconfig_ipv6_defined = true; - - msg( M_INFO, "MULTI_sva: push_ifconfig_ipv6 %s/%d", - print_in6_addr( mi->context.c2.push_ifconfig_ipv6_local, 0, &gc ), - mi->context.c2.push_ifconfig_ipv6_netbits ); - } - - gc_free (&gc); +multi_select_virtual_addr(struct multi_context *m, struct multi_instance *mi) +{ + struct gc_arena gc = gc_new(); + + /* + * If ifconfig addresses were set by dynamic config file, + * release pool addresses, otherwise keep them. + */ + if (mi->context.options.push_ifconfig_defined) + { + /* ifconfig addresses were set statically, + * release dynamic allocation */ + if (mi->vaddr_handle >= 0) + { + ifconfig_pool_release(m->ifconfig_pool, mi->vaddr_handle, true); + mi->vaddr_handle = -1; + } + + mi->context.c2.push_ifconfig_defined = true; + mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local; + mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask; + mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias; + + /* the current implementation does not allow "static IPv4, pool IPv6", + * (see below) so issue a warning if that happens - don't break the + * session, though, as we don't even know if this client WANTS IPv6 + */ + if (mi->context.options.ifconfig_ipv6_pool_defined + && !mi->context.options.push_ifconfig_ipv6_defined) + { + msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work. Use --ifconfig-ipv6-push for IPv6 then." ); + } + } + else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */ + { + in_addr_t local = 0, remote = 0; + struct in6_addr remote_ipv6; + const char *cn = NULL; + + if (!mi->context.options.duplicate_cn) + { + cn = tls_common_name(mi->context.c2.tls_multi, true); + } + + CLEAR(remote_ipv6); + mi->vaddr_handle = ifconfig_pool_acquire(m->ifconfig_pool, &local, &remote, &remote_ipv6, cn); + if (mi->vaddr_handle >= 0) + { + const int tunnel_type = TUNNEL_TYPE(mi->context.c1.tuntap); + const int tunnel_topology = TUNNEL_TOPOLOGY(mi->context.c1.tuntap); + + msg( M_INFO, "MULTI_sva: pool returned IPv4=%s, IPv6=%s", + print_in_addr_t( remote, 0, &gc ), + (mi->context.options.ifconfig_ipv6_pool_defined + ? print_in6_addr( remote_ipv6, 0, &gc ) + : "(Not enabled)") ); + + /* set push_ifconfig_remote_netmask from pool ifconfig address(es) */ + mi->context.c2.push_ifconfig_local = remote; + if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) + { + mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.ifconfig_pool_netmask; + if (!mi->context.c2.push_ifconfig_remote_netmask) + { + mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->remote_netmask; + } + } + else if (tunnel_type == DEV_TYPE_TUN) + { + if (tunnel_topology == TOP_P2P) + { + mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->local; + } + else if (tunnel_topology == TOP_NET30) + { + mi->context.c2.push_ifconfig_remote_netmask = local; + } + } + + if (mi->context.c2.push_ifconfig_remote_netmask) + { + mi->context.c2.push_ifconfig_defined = true; + } + else + { + msg(D_MULTI_ERRORS, "MULTI: no --ifconfig-pool netmask parameter is available to push to %s", + multi_instance_string(mi, false, &gc)); + } + + if (mi->context.options.ifconfig_ipv6_pool_defined) + { + mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6; + mi->context.c2.push_ifconfig_ipv6_remote = + mi->context.c1.tuntap->local_ipv6; + mi->context.c2.push_ifconfig_ipv6_netbits = + mi->context.options.ifconfig_ipv6_netbits; + mi->context.c2.push_ifconfig_ipv6_defined = true; + } + } + else + { + msg(D_MULTI_ERRORS, "MULTI: no free --ifconfig-pool addresses are available"); + } + } + + /* IPv6 push_ifconfig is a bit problematic - since IPv6 shares the + * pool handling with IPv4, the combination "static IPv4, dynamic IPv6" + * will fail (because no pool will be allocated in this case). + * OTOH, this doesn't make too much sense in reality - and the other + * way round ("dynamic IPv4, static IPv6") or "both static" makes sense + * -> and so it's implemented right now + */ + if (mi->context.options.push_ifconfig_ipv6_defined) + { + mi->context.c2.push_ifconfig_ipv6_local = + mi->context.options.push_ifconfig_ipv6_local; + mi->context.c2.push_ifconfig_ipv6_remote = + mi->context.options.push_ifconfig_ipv6_remote; + mi->context.c2.push_ifconfig_ipv6_netbits = + mi->context.options.push_ifconfig_ipv6_netbits; + mi->context.c2.push_ifconfig_ipv6_defined = true; + + msg( M_INFO, "MULTI_sva: push_ifconfig_ipv6 %s/%d", + print_in6_addr( mi->context.c2.push_ifconfig_ipv6_local, 0, &gc ), + mi->context.c2.push_ifconfig_ipv6_netbits ); + } + + gc_free(&gc); } /* * Set virtual address environmental variables. */ static void -multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi) -{ - setenv_del (mi->context.c2.es, "ifconfig_pool_local_ip"); - setenv_del (mi->context.c2.es, "ifconfig_pool_remote_ip"); - setenv_del (mi->context.c2.es, "ifconfig_pool_netmask"); - - if (mi->context.c2.push_ifconfig_defined) - { - const int tunnel_type = TUNNEL_TYPE (mi->context.c1.tuntap); - const int tunnel_topology = TUNNEL_TOPOLOGY (mi->context.c1.tuntap); - - setenv_in_addr_t (mi->context.c2.es, - "ifconfig_pool_remote_ip", - mi->context.c2.push_ifconfig_local, - SA_SET_IF_NONZERO); - - if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) - { - setenv_in_addr_t (mi->context.c2.es, - "ifconfig_pool_netmask", - mi->context.c2.push_ifconfig_remote_netmask, - SA_SET_IF_NONZERO); - } - else if (tunnel_type == DEV_TYPE_TUN) - { - setenv_in_addr_t (mi->context.c2.es, - "ifconfig_pool_local_ip", - mi->context.c2.push_ifconfig_remote_netmask, - SA_SET_IF_NONZERO); - } - } - - setenv_del (mi->context.c2.es, "ifconfig_pool_local_ip6"); - setenv_del (mi->context.c2.es, "ifconfig_pool_remote_ip6"); - setenv_del (mi->context.c2.es, "ifconfig_pool_ip6_netbits"); - - if (mi->context.c2.push_ifconfig_ipv6_defined) - { - setenv_in6_addr (mi->context.c2.es, - "ifconfig_pool_remote", - &mi->context.c2.push_ifconfig_ipv6_local, - SA_SET_IF_NONZERO); - setenv_in6_addr (mi->context.c2.es, - "ifconfig_pool_local", - &mi->context.c2.push_ifconfig_ipv6_remote, - SA_SET_IF_NONZERO); - setenv_int (mi->context.c2.es, - "ifconfig_pool_ip6_netbits", - mi->context.c2.push_ifconfig_ipv6_netbits); +multi_set_virtual_addr_env(struct multi_context *m, struct multi_instance *mi) +{ + setenv_del(mi->context.c2.es, "ifconfig_pool_local_ip"); + setenv_del(mi->context.c2.es, "ifconfig_pool_remote_ip"); + setenv_del(mi->context.c2.es, "ifconfig_pool_netmask"); + + if (mi->context.c2.push_ifconfig_defined) + { + const int tunnel_type = TUNNEL_TYPE(mi->context.c1.tuntap); + const int tunnel_topology = TUNNEL_TOPOLOGY(mi->context.c1.tuntap); + + setenv_in_addr_t(mi->context.c2.es, + "ifconfig_pool_remote_ip", + mi->context.c2.push_ifconfig_local, + SA_SET_IF_NONZERO); + + if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) + { + setenv_in_addr_t(mi->context.c2.es, + "ifconfig_pool_netmask", + mi->context.c2.push_ifconfig_remote_netmask, + SA_SET_IF_NONZERO); + } + else if (tunnel_type == DEV_TYPE_TUN) + { + setenv_in_addr_t(mi->context.c2.es, + "ifconfig_pool_local_ip", + mi->context.c2.push_ifconfig_remote_netmask, + SA_SET_IF_NONZERO); + } + } + + setenv_del(mi->context.c2.es, "ifconfig_pool_local_ip6"); + setenv_del(mi->context.c2.es, "ifconfig_pool_remote_ip6"); + setenv_del(mi->context.c2.es, "ifconfig_pool_ip6_netbits"); + + if (mi->context.c2.push_ifconfig_ipv6_defined) + { + setenv_in6_addr(mi->context.c2.es, + "ifconfig_pool_remote", + &mi->context.c2.push_ifconfig_ipv6_local, + SA_SET_IF_NONZERO); + setenv_in6_addr(mi->context.c2.es, + "ifconfig_pool_local", + &mi->context.c2.push_ifconfig_ipv6_remote, + SA_SET_IF_NONZERO); + setenv_int(mi->context.c2.es, + "ifconfig_pool_ip6_netbits", + mi->context.c2.push_ifconfig_ipv6_netbits); } } @@ -1527,30 +1633,30 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi) * Called after client-connect script is called */ 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) +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? */ - if (test_file (dc_file)) + /* Did script generate a dynamic config file? */ + if (test_file(dc_file)) { - options_server_import (&mi->context.options, - dc_file, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - option_types_found, - mi->context.c2.es); + options_server_import(&mi->context.options, + dc_file, + D_IMPORT_ERRORS|M_OPTERR, + option_permissions_mask, + option_types_found, + mi->context.c2.es); - /* - * If the --client-connect script generates a config file - * with an --ifconfig-push directive, it will override any - * --ifconfig-push directive from the --client-config-dir - * directory or any --ifconfig-pool dynamic address. - */ - multi_select_virtual_addr (m, mi); - multi_set_virtual_addr_env (m, mi); + /* + * If the --client-connect script generates a config file + * with an --ifconfig-push directive, it will override any + * --ifconfig-push directive from the --client-config-dir + * directory or any --ifconfig-pool dynamic address. + */ + multi_select_virtual_addr(m, mi); + multi_set_virtual_addr_env(m, mi); } } @@ -1560,43 +1666,45 @@ multi_client_connect_post (struct multi_context *m, * Called after client-connect plug-in is called */ 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; - - plugin_return_get_column (pr, &config, "config"); - - /* Did script generate a dynamic config file? */ - if (plugin_return_defined (&config)) - { - int i; - for (i = 0; i < config.n; ++i) - { - if (config.list[i] && config.list[i]->value) - options_string_import (&mi->context.options, - config.list[i]->value, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - option_types_found, - mi->context.c2.es); - } - - /* - * If the --client-connect script generates a config file - * with an --ifconfig-push directive, it will override any - * --ifconfig-push directive from the --client-config-dir - * directory or any --ifconfig-pool dynamic address. - */ - multi_select_virtual_addr (m, mi); - multi_set_virtual_addr_env (m, mi); +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; + + plugin_return_get_column(pr, &config, "config"); + + /* Did script generate a dynamic config file? */ + if (plugin_return_defined(&config)) + { + int i; + for (i = 0; i < config.n; ++i) + { + if (config.list[i] && config.list[i]->value) + { + options_string_import(&mi->context.options, + config.list[i]->value, + D_IMPORT_ERRORS|M_OPTERR, + option_permissions_mask, + option_types_found, + mi->context.c2.es); + } + } + + /* + * If the --client-connect script generates a config file + * with an --ifconfig-push directive, it will override any + * --ifconfig-push directive from the --client-config-dir + * directory or any --ifconfig-pool dynamic address. + */ + multi_select_virtual_addr(m, mi); + multi_set_virtual_addr_env(m, mi); } } -#endif +#endif /* ifdef ENABLE_PLUGIN */ #ifdef MANAGEMENT_DEF_AUTH @@ -1604,63 +1712,63 @@ multi_client_connect_post_plugin (struct multi_context *m, * Called to load management-derived client-connect config */ 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) - { - struct buffer_entry *be; - - for (be = 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, - option_types_found, - mi->context.c2.es); - } - - /* - * If the --client-connect script generates a config file - * with an --ifconfig-push directive, it will override any - * --ifconfig-push directive from the --client-config-dir - * directory or any --ifconfig-pool dynamic address. - */ - multi_select_virtual_addr (m, mi); - multi_set_virtual_addr_env (m, mi); +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) + { + struct buffer_entry *be; + + for (be = 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, + option_types_found, + mi->context.c2.es); + } + + /* + * If the --client-connect script generates a config file + * with an --ifconfig-push directive, it will override any + * --ifconfig-push directive from the --client-config-dir + * directory or any --ifconfig-pool dynamic address. + */ + multi_select_virtual_addr(m, mi); + multi_set_virtual_addr_env(m, mi); } } -#endif +#endif /* ifdef MANAGEMENT_DEF_AUTH */ static void -multi_client_connect_setenv (struct multi_context *m, - struct multi_instance *mi) +multi_client_connect_setenv(struct multi_context *m, + struct multi_instance *mi) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - /* setenv incoming cert common name for script */ - setenv_str (mi->context.c2.es, "common_name", tls_common_name (mi->context.c2.tls_multi, true)); + /* setenv incoming cert common name for script */ + setenv_str(mi->context.c2.es, "common_name", tls_common_name(mi->context.c2.tls_multi, true)); - /* setenv client real IP address */ - setenv_trusted (mi->context.c2.es, get_link_socket_info (&mi->context)); + /* setenv client real IP address */ + setenv_trusted(mi->context.c2.es, get_link_socket_info(&mi->context)); - /* setenv client virtual IP address */ - multi_set_virtual_addr_env (m, mi); + /* setenv client virtual IP address */ + multi_set_virtual_addr_env(m, mi); - /* setenv connection time */ - { - const char *created_ascii = time_string (mi->created, 0, false, &gc); - setenv_str (mi->context.c2.es, "time_ascii", created_ascii); - setenv_unsigned (mi->context.c2.es, "time_unix", (unsigned int)mi->created); - } + /* setenv connection time */ + { + const char *created_ascii = time_string(mi->created, 0, false, &gc); + setenv_str(mi->context.c2.es, "time_ascii", created_ascii); + setenv_unsigned(mi->context.c2.es, "time_unix", (unsigned int)mi->created); + } - gc_free (&gc); + gc_free(&gc); } /* @@ -1673,316 +1781,328 @@ multi_client_connect_setenv (struct multi_context *m, * 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) - { - struct gc_arena gc = gc_new (); - unsigned int option_types_found = 0; - - 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; - - int cc_succeeded = true; /* client connect script status */ - int cc_succeeded_count = 0; - - 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); - - /* generate a msg() prefix for this client instance */ - generate_prefix (mi); - - /* delete instances of previous clients with same common-name */ - if (!mi->context.options.duplicate_cn) - multi_delete_dup (m, mi); - - /* reset pool handle to null */ - mi->vaddr_handle = -1; - - /* - * Try to source a dynamic config file from the - * --client-config-dir directory. - */ - if (mi->context.options.client_config_dir) - { - const char *ccd_file; - - ccd_file = gen_path (mi->context.options.client_config_dir, - tls_common_name (mi->context.c2.tls_multi, false), - &gc); - - /* try common-name file */ - if (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 = gen_path (mi->context.options.client_config_dir, - CCD_DEFAULT, - &gc); - - if (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); - } - } - } - - /* - * 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_connection_established(struct multi_context *m, struct multi_instance *mi) +{ + if (tls_authentication_status(mi->context.c2.tls_multi, 0) == TLS_AUTHENTICATION_SUCCEEDED) + { + struct gc_arena gc = gc_new(); + unsigned int option_types_found = 0; -#ifdef ENABLE_PLUGIN - /* - * Call client-connect plug-in. - */ + 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; - /* 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 = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); + int cc_succeeded = true; /* client connect script status */ + int cc_succeeded_count = 0; - if( !dc_file ) { - cc_succeeded = false; - goto script_depr_failed; - } - - 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; - } - - if (!platform_unlink (dc_file)) - msg (D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", - dc_file); - - script_depr_failed: - argv_reset (&argv); - } - - /* 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; - - plugin_return_init (&pr); - - 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; - } - - plugin_return_free (&pr); - } -#endif + ASSERT(mi->context.c1.tuntap); - /* - * Run --client-connect script. - */ - if (mi->context.options.client_connect_script && cc_succeeded) - { - struct argv argv = argv_new (); - const char *dc_file = NULL; + /* 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); - setenv_str (mi->context.c2.es, "script_type", "client-connect"); + /* generate a msg() prefix for this client instance */ + generate_prefix(mi); - dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); - if( !dc_file ) { - cc_succeeded = false; - goto script_failed; - } - - argv_parse_cmd (&argv, mi->context.options.client_connect_script); - argv_printf_cat (&argv, "%s", dc_file); - - 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; - - if (!platform_unlink (dc_file)) - msg (D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", - dc_file); - - script_failed: - argv_reset (&argv); - } - - /* - * Check for client-connect script left by management interface client - */ + /* delete instances of previous clients with same common-name */ + if (!mi->context.options.duplicate_cn) + { + multi_delete_dup(m, mi); + } + + /* reset pool handle to null */ + mi->vaddr_handle = -1; + + /* + * Try to source a dynamic config file from the + * --client-config-dir directory. + */ + if (mi->context.options.client_config_dir) + { + const char *ccd_file; + + ccd_file = gen_path(mi->context.options.client_config_dir, + tls_common_name(mi->context.c2.tls_multi, false), + &gc); + + /* try common-name file */ + if (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 = gen_path(mi->context.options.client_config_dir, + CCD_DEFAULT, + &gc); + + if (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); + } + } + } + + /* + * 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); + +#ifdef ENABLE_PLUGIN + /* + * Call client-connect plug-in. + */ + + /* 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 = create_temp_file(mi->context.options.tmp_dir, "cc", &gc); + + if (!dc_file) + { + cc_succeeded = false; + goto script_depr_failed; + } + + 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; + } + + if (!platform_unlink(dc_file)) + { + msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", + dc_file); + } + +script_depr_failed: + argv_reset(&argv); + } + + /* 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; + + plugin_return_init(&pr); + + 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; + } + + plugin_return_free(&pr); + } +#endif /* ifdef ENABLE_PLUGIN */ + + /* + * Run --client-connect script. + */ + if (mi->context.options.client_connect_script && cc_succeeded) + { + struct argv argv = argv_new(); + const char *dc_file = NULL; + + setenv_str(mi->context.c2.es, "script_type", "client-connect"); + + dc_file = create_temp_file(mi->context.options.tmp_dir, "cc", &gc); + if (!dc_file) + { + cc_succeeded = false; + goto script_failed; + } + + argv_parse_cmd(&argv, mi->context.options.client_connect_script); + argv_printf_cat(&argv, "%s", dc_file); + + 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; + } + + if (!platform_unlink(dc_file)) + { + msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", + dc_file); + } + +script_failed: + argv_reset(&argv); + } + + /* + * Check for client-connect script left by management interface client + */ #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; - } + if (cc_succeeded && mi->cc_config) + { + multi_client_connect_mda(m, mi, mi->cc_config, option_permissions_mask, &option_types_found); + ++cc_succeeded_count; + } #endif - /* - * Check for "disable" directive in client-config-dir file - * or config file generated by --client-connect script. - */ - if (mi->context.options.disable) - { - 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; + /* + * Check for "disable" directive in client-config-dir file + * or config file generated by --client-connect script. + */ + if (mi->context.options.disable) + { + 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); - } + /* authentication complete, send push reply */ + if (mi->context.c2.push_request_received) + { + process_incoming_push_request(&mi->context); + } #endif - } - else - { - /* set context-level authentication flag */ - mi->context.c2.context_auth = cc_succeeded_count ? CAS_PARTIAL : CAS_FAILED; - } + } + else + { + /* set context-level authentication flag */ + mi->context.c2.context_auth = cc_succeeded_count ? CAS_PARTIAL : CAS_FAILED; + } - /* set flag so we don't get called again */ - mi->connection_established_flag = true; + /* set flag so we don't get called again */ + mi->connection_established_flag = true; - /* increment number of current authenticated clients */ - ++m->n_clients; - update_mstat_n_clients(m->n_clients); - --mi->n_clients_delta; + /* increment number of current authenticated clients */ + ++m->n_clients; + update_mstat_n_clients(m->n_clients); + --mi->n_clients_delta; #ifdef MANAGEMENT_DEF_AUTH - if (management) - management_connection_established (management, &mi->context.c2.mda_context, mi->context.c2.es); + if (management) + { + management_connection_established(management, &mi->context.c2.mda_context, mi->context.c2.es); + } #endif - gc_free (&gc); + gc_free(&gc); } - /* - * Reply now to client's PUSH_REQUEST query - */ - mi->context.c2.push_reply_deferred = false; + /* + * Reply now to client's PUSH_REQUEST query + */ + mi->context.c2.push_reply_deferred = false; } #ifdef ENABLE_ASYNC_PUSH @@ -1991,71 +2111,71 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi * Continues authentication and sends push_reply. */ void -multi_process_file_closed (struct multi_context *m, const unsigned int mpp_flags) -{ - char buffer[INOTIFY_EVENT_BUFFER_SIZE]; - size_t buffer_i = 0; - int r = read (m->top.c2.inotify_fd, buffer, INOTIFY_EVENT_BUFFER_SIZE); - - while (buffer_i < r) - { - /* parse inotify events */ - struct inotify_event *pevent = (struct inotify_event *) &buffer[buffer_i]; - size_t event_size = sizeof (struct inotify_event) + pevent->len; - buffer_i += event_size; - - msg(D_MULTI_DEBUG, "MULTI: modified fd %d, mask %d", pevent->wd, pevent->mask); - - struct multi_instance* mi = hash_lookup(m->inotify_watchers, (void*) (unsigned long) pevent->wd); - - if (pevent->mask & IN_CLOSE_WRITE) - { - if (mi) - { - /* continue authentication and send push_reply */ - multi_process_post (m, mi, mpp_flags); - } - else - { - msg(D_MULTI_ERRORS, "MULTI: multi_instance not found!"); - } - } - else if (pevent->mask & IN_IGNORED) - { - /* this event is _always_ fired when watch is removed or file is deleted */ - if (mi) - { - hash_remove(m->inotify_watchers, (void*) (unsigned long) pevent->wd); - mi->inotify_watch = -1; - } - } - else - { - msg(D_MULTI_ERRORS, "MULTI: unknown mask %d", pevent->mask); - } +multi_process_file_closed(struct multi_context *m, const unsigned int mpp_flags) +{ + char buffer[INOTIFY_EVENT_BUFFER_SIZE]; + size_t buffer_i = 0; + int r = read(m->top.c2.inotify_fd, buffer, INOTIFY_EVENT_BUFFER_SIZE); + + while (buffer_i < r) + { + /* parse inotify events */ + struct inotify_event *pevent = (struct inotify_event *) &buffer[buffer_i]; + size_t event_size = sizeof(struct inotify_event) + pevent->len; + buffer_i += event_size; + + msg(D_MULTI_DEBUG, "MULTI: modified fd %d, mask %d", pevent->wd, pevent->mask); + + struct multi_instance *mi = hash_lookup(m->inotify_watchers, (void *) (unsigned long) pevent->wd); + + if (pevent->mask & IN_CLOSE_WRITE) + { + if (mi) + { + /* continue authentication and send push_reply */ + multi_process_post(m, mi, mpp_flags); + } + else + { + msg(D_MULTI_ERRORS, "MULTI: multi_instance not found!"); + } + } + else if (pevent->mask & IN_IGNORED) + { + /* this event is _always_ fired when watch is removed or file is deleted */ + if (mi) + { + hash_remove(m->inotify_watchers, (void *) (unsigned long) pevent->wd); + mi->inotify_watch = -1; + } + } + else + { + msg(D_MULTI_ERRORS, "MULTI: unknown mask %d", pevent->mask); + } } } -#endif +#endif /* ifdef ENABLE_ASYNC_PUSH */ /* * Add a mbuf buffer to a particular * instance. */ void -multi_add_mbuf (struct multi_context *m, - struct multi_instance *mi, - struct mbuf_buffer *mb) +multi_add_mbuf(struct multi_context *m, + struct multi_instance *mi, + struct mbuf_buffer *mb) { - if (multi_output_queue_ready (m, mi)) + if (multi_output_queue_ready(m, mi)) { - struct mbuf_item item; - item.buffer = mb; - item.instance = mi; - mbuf_add_item (m->mbuf, &item); + struct mbuf_item item; + item.buffer = mb; + item.instance = mi; + mbuf_add_item(m->mbuf, &item); } - else + else { - msg (D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_add_mbuf)"); + msg(D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_add_mbuf)"); } } @@ -2063,18 +2183,18 @@ multi_add_mbuf (struct multi_context *m, * Add a packet to a client instance output queue. */ static inline void -multi_unicast (struct multi_context *m, - const struct buffer *buf, - struct multi_instance *mi) +multi_unicast(struct multi_context *m, + const struct buffer *buf, + struct multi_instance *mi) { - struct mbuf_buffer *mb; + struct mbuf_buffer *mb; - if (BLEN (buf) > 0) + if (BLEN(buf) > 0) { - mb = mbuf_alloc_buf (buf); - mb->flags = MF_UNICAST; - multi_add_mbuf (m, mi, mb); - mbuf_free_buf (mb); + mb = mbuf_alloc_buf(buf); + mb->flags = MF_UNICAST; + multi_add_mbuf(m, mi, mb); + mbuf_free_buf(mb); } } @@ -2082,61 +2202,61 @@ multi_unicast (struct multi_context *m, * Broadcast a packet to all clients. */ static void -multi_bcast (struct multi_context *m, - const struct buffer *buf, - const struct multi_instance *sender_instance, - const struct mroute_addr *sender_addr) +multi_bcast(struct multi_context *m, + const struct buffer *buf, + const struct multi_instance *sender_instance, + const struct mroute_addr *sender_addr) { - struct hash_iterator hi; - struct hash_element *he; - struct multi_instance *mi; - struct mbuf_buffer *mb; + struct hash_iterator hi; + struct hash_element *he; + struct multi_instance *mi; + struct mbuf_buffer *mb; - if (BLEN (buf) > 0) + if (BLEN(buf) > 0) { - perf_push (PERF_MULTI_BCAST); + perf_push(PERF_MULTI_BCAST); #ifdef MULTI_DEBUG_EVENT_LOOP - printf ("BCAST len=%d\n", BLEN (buf)); + printf("BCAST len=%d\n", BLEN(buf)); #endif - mb = mbuf_alloc_buf (buf); - hash_iterator_init (m->iter, &hi); - - while ((he = hash_iterator_next (&hi))) - { - mi = (struct multi_instance *) he->value; - if (mi != sender_instance && !mi->halt) - { + mb = mbuf_alloc_buf(buf); + hash_iterator_init(m->iter, &hi); + + while ((he = hash_iterator_next(&hi))) + { + mi = (struct multi_instance *) he->value; + if (mi != sender_instance && !mi->halt) + { #ifdef ENABLE_PF - if (sender_instance) - { - if (!pf_c2c_test (&sender_instance->context, &mi->context, "bcast_c2c")) - { - msg (D_PF_DROPPED_BCAST, "PF: client[%s] -> client[%s] packet dropped by BCAST packet filter", - mi_prefix (sender_instance), - mi_prefix (mi)); - continue; - } - } - if (sender_addr) - { - if (!pf_addr_test (&mi->context, sender_addr, "bcast_src_addr")) - { - struct gc_arena gc = gc_new (); - msg (D_PF_DROPPED_BCAST, "PF: addr[%s] -> client[%s] packet dropped by BCAST packet filter", - mroute_addr_print_ex (sender_addr, MAPF_SHOW_ARP, &gc), - mi_prefix (mi)); - gc_free (&gc); - continue; - } - } -#endif - multi_add_mbuf (m, mi, mb); - } - } + if (sender_instance) + { + if (!pf_c2c_test(&sender_instance->context, &mi->context, "bcast_c2c")) + { + msg(D_PF_DROPPED_BCAST, "PF: client[%s] -> client[%s] packet dropped by BCAST packet filter", + mi_prefix(sender_instance), + mi_prefix(mi)); + continue; + } + } + if (sender_addr) + { + if (!pf_addr_test(&mi->context, sender_addr, "bcast_src_addr")) + { + struct gc_arena gc = gc_new(); + msg(D_PF_DROPPED_BCAST, "PF: addr[%s] -> client[%s] packet dropped by BCAST packet filter", + mroute_addr_print_ex(sender_addr, MAPF_SHOW_ARP, &gc), + mi_prefix(mi)); + gc_free(&gc); + continue; + } + } +#endif /* ifdef ENABLE_PF */ + multi_add_mbuf(m, mi, mb); + } + } - hash_iterator_free (&hi); - mbuf_free_buf (mb); - perf_pop (); + hash_iterator_free(&hi); + mbuf_free_buf(mb); + perf_pop(); } } @@ -2152,35 +2272,39 @@ multi_bcast (struct multi_context *m, * Sigma should be no larger than TV_WITHIN_SIGMA_MAX_USEC */ static inline unsigned int -compute_wakeup_sigma (const struct timeval *delta) +compute_wakeup_sigma(const struct timeval *delta) { - if (delta->tv_sec < 1) + if (delta->tv_sec < 1) { - /* if < 1 sec, fuzz = # of microseconds / 8 */ - return delta->tv_usec >> 3; + /* if < 1 sec, fuzz = # of microseconds / 8 */ + return delta->tv_usec >> 3; } - else + else { - /* if < 10 minutes, fuzz = 13.1% of timeout */ - if (delta->tv_sec < 600) - return delta->tv_sec << 17; - else - return 120000000; /* if >= 10 minutes, fuzz = 2 minutes */ + /* if < 10 minutes, fuzz = 13.1% of timeout */ + if (delta->tv_sec < 600) + { + return delta->tv_sec << 17; + } + else + { + return 120000000; /* if >= 10 minutes, fuzz = 2 minutes */ + } } } static void -multi_schedule_context_wakeup (struct multi_context *m, struct multi_instance *mi) +multi_schedule_context_wakeup(struct multi_context *m, struct multi_instance *mi) { - /* calculate an absolute wakeup time */ - ASSERT (!openvpn_gettimeofday (&mi->wakeup, NULL)); - tv_add (&mi->wakeup, &mi->context.c2.timeval); + /* calculate an absolute wakeup time */ + ASSERT(!openvpn_gettimeofday(&mi->wakeup, NULL)); + tv_add(&mi->wakeup, &mi->context.c2.timeval); - /* tell scheduler to wake us up at some point in the future */ - schedule_add_entry (m->schedule, - (struct schedule_entry *) mi, - &mi->wakeup, - compute_wakeup_sigma (&mi->context.c2.timeval)); + /* tell scheduler to wake us up at some point in the future */ + schedule_add_entry(m->schedule, + (struct schedule_entry *) mi, + &mi->wakeup, + compute_wakeup_sigma(&mi->context.c2.timeval)); } /* @@ -2191,139 +2315,146 @@ multi_schedule_context_wakeup (struct multi_context *m, struct multi_instance *m * Also close context on signal. */ bool -multi_process_post (struct multi_context *m, struct multi_instance *mi, const unsigned int flags) +multi_process_post(struct multi_context *m, struct multi_instance *mi, const unsigned int flags) { - bool ret = true; + bool ret = true; - if (!IS_SIG (&mi->context) && ((flags & MPP_PRE_SELECT) || ((flags & MPP_CONDITIONAL_PRE_SELECT) && !ANY_OUT (&mi->context)))) + if (!IS_SIG(&mi->context) && ((flags & MPP_PRE_SELECT) || ((flags & MPP_CONDITIONAL_PRE_SELECT) && !ANY_OUT(&mi->context)))) { #if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH) - bool was_authenticated = false; - struct key_state *ks = NULL; - if (mi->context.c2.tls_multi) + bool was_authenticated = false; + struct key_state *ks = NULL; + if (mi->context.c2.tls_multi) { - ks = &mi->context.c2.tls_multi->session[TM_ACTIVE].key[KS_PRIMARY]; - was_authenticated = ks->authenticated; + ks = &mi->context.c2.tls_multi->session[TM_ACTIVE].key[KS_PRIMARY]; + was_authenticated = ks->authenticated; } #endif - /* figure timeouts and fetch possible outgoing - to_link packets (such as ping or TLS control) */ - pre_select (&mi->context); + /* figure timeouts and fetch possible outgoing + * to_link packets (such as ping or TLS control) */ + pre_select(&mi->context); #if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH) - if (ks && ks->auth_control_file && ks->auth_deferred && !was_authenticated) - { - /* watch acf file */ - long watch_descriptor = inotify_add_watch(m->top.c2.inotify_fd, ks->auth_control_file, IN_CLOSE_WRITE | IN_ONESHOT); - if (watch_descriptor >= 0) - { - if (mi->inotify_watch != -1) - { - hash_remove(m->inotify_watchers, (void*) (unsigned long)mi->inotify_watch); - } - hash_add (m->inotify_watchers, (const uintptr_t*)watch_descriptor, mi, true); - mi->inotify_watch = watch_descriptor; - } - else - { - msg(M_NONFATAL, "MULTI: inotify_add_watch error: %s", strerror(errno)); - } - } + if (ks && ks->auth_control_file && ks->auth_deferred && !was_authenticated) + { + /* watch acf file */ + long watch_descriptor = inotify_add_watch(m->top.c2.inotify_fd, ks->auth_control_file, IN_CLOSE_WRITE | IN_ONESHOT); + if (watch_descriptor >= 0) + { + if (mi->inotify_watch != -1) + { + hash_remove(m->inotify_watchers, (void *) (unsigned long)mi->inotify_watch); + } + hash_add(m->inotify_watchers, (const uintptr_t *)watch_descriptor, mi, true); + mi->inotify_watch = watch_descriptor; + } + else + { + msg(M_NONFATAL, "MULTI: inotify_add_watch error: %s", strerror(errno)); + } + } #endif - if (!IS_SIG (&mi->context)) - { - /* connection is "established" when SSL/TLS key negotiation succeeds - and (if specified) auth user/pass succeeds */ - if (!mi->connection_established_flag && CONNECTION_ESTABLISHED (&mi->context)) - multi_connection_established (m, mi); - - /* tell scheduler to wake us up at some point in the future */ - multi_schedule_context_wakeup(m, mi); - } + if (!IS_SIG(&mi->context)) + { + /* connection is "established" when SSL/TLS key negotiation succeeds + * and (if specified) auth user/pass succeeds */ + if (!mi->connection_established_flag && CONNECTION_ESTABLISHED(&mi->context)) + { + multi_connection_established(m, mi); + } + + /* tell scheduler to wake us up at some point in the future */ + multi_schedule_context_wakeup(m, mi); + } } - if (IS_SIG (&mi->context)) + if (IS_SIG(&mi->context)) { - if (flags & MPP_CLOSE_ON_SIGNAL) - { - multi_close_instance_on_signal (m, mi); - ret = false; - } + if (flags & MPP_CLOSE_ON_SIGNAL) + { + multi_close_instance_on_signal(m, mi); + ret = false; + } } - else + else { - /* continue to pend on output? */ - multi_set_pending (m, ANY_OUT (&mi->context) ? mi : NULL); + /* continue to pend on output? */ + multi_set_pending(m, ANY_OUT(&mi->context) ? mi : NULL); #ifdef MULTI_DEBUG_EVENT_LOOP - printf ("POST %s[%d] to=%d lo=%d/%d w=%d/%d\n", - id(mi), - (int) (mi == m->pending), - mi ? mi->context.c2.to_tun.len : -1, - mi ? mi->context.c2.to_link.len : -1, - (mi && mi->context.c2.fragment) ? mi->context.c2.fragment->outgoing.len : -1, - (int)mi->context.c2.timeval.tv_sec, - (int)mi->context.c2.timeval.tv_usec); + printf("POST %s[%d] to=%d lo=%d/%d w=%d/%d\n", + id(mi), + (int) (mi == m->pending), + mi ? mi->context.c2.to_tun.len : -1, + mi ? mi->context.c2.to_link.len : -1, + (mi && mi->context.c2.fragment) ? mi->context.c2.fragment->outgoing.len : -1, + (int)mi->context.c2.timeval.tv_sec, + (int)mi->context.c2.timeval.tv_usec); #endif } - if ((flags & MPP_RECORD_TOUCH) && m->mpp_touched) - *m->mpp_touched = mi; + if ((flags & MPP_RECORD_TOUCH) && m->mpp_touched) + { + *m->mpp_touched = mi; + } - return ret; + return ret; } -void multi_process_float (struct multi_context* m, struct multi_instance* mi) +void +multi_process_float(struct multi_context *m, struct multi_instance *mi) { - struct mroute_addr real; - struct hash *hash = m->hash; - struct gc_arena gc = gc_new (); + struct mroute_addr real; + struct hash *hash = m->hash; + struct gc_arena gc = gc_new(); - if (!mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true)) - goto done; + if (!mroute_extract_openvpn_sockaddr(&real, &m->top.c2.from.dest, true)) + { + goto done; + } - const uint32_t hv = hash_value (hash, &real); - struct hash_bucket *bucket = hash_bucket (hash, hv); + const uint32_t hv = hash_value(hash, &real); + struct hash_bucket *bucket = hash_bucket(hash, hv); - /* make sure that we don't float to an address taken by another client */ - struct hash_element *he = hash_lookup_fast (hash, bucket, &real, hv); - if (he) + /* make sure that we don't float to an address taken by another client */ + struct hash_element *he = hash_lookup_fast(hash, bucket, &real, hv); + if (he) { - struct multi_instance *ex_mi = (struct multi_instance *) he->value; + struct multi_instance *ex_mi = (struct multi_instance *) he->value; - struct tls_multi *m1 = mi->context.c2.tls_multi; - struct tls_multi *m2 = ex_mi->context.c2.tls_multi; + struct tls_multi *m1 = mi->context.c2.tls_multi; + struct tls_multi *m2 = ex_mi->context.c2.tls_multi; - /* do not float if target address is taken by client with another cert */ - if (!cert_hash_compare(m1->locked_cert_hash_set, m2->locked_cert_hash_set)) - { - msg (D_MULTI_LOW, "Disallow float to an address taken by another client %s", - multi_instance_string (ex_mi, false, &gc)); + /* do not float if target address is taken by client with another cert */ + if (!cert_hash_compare(m1->locked_cert_hash_set, m2->locked_cert_hash_set)) + { + msg(D_MULTI_LOW, "Disallow float to an address taken by another client %s", + multi_instance_string(ex_mi, false, &gc)); - mi->context.c2.buf.len = 0; + mi->context.c2.buf.len = 0; - goto done; - } + goto done; + } - msg (D_MULTI_MEDIUM, "closing instance %s", multi_instance_string (ex_mi, false, &gc)); - multi_close_instance(m, ex_mi, false); + msg(D_MULTI_MEDIUM, "closing instance %s", multi_instance_string(ex_mi, false, &gc)); + multi_close_instance(m, ex_mi, false); } - msg (D_MULTI_MEDIUM, "peer %" PRIu32 " (%s) floated from %s to %s", - mi->context.c2.tls_multi->peer_id, - tls_common_name (mi->context.c2.tls_multi, false), - mroute_addr_print (&mi->real, &gc), - print_link_socket_actual (&m->top.c2.from, &gc)); + msg(D_MULTI_MEDIUM, "peer %" PRIu32 " (%s) floated from %s to %s", + mi->context.c2.tls_multi->peer_id, + tls_common_name(mi->context.c2.tls_multi, false), + mroute_addr_print(&mi->real, &gc), + print_link_socket_actual(&m->top.c2.from, &gc)); /* remove old address from hash table before changing address */ - ASSERT (hash_remove (m->hash, &mi->real)); - ASSERT (hash_remove (m->iter, &mi->real)); + ASSERT(hash_remove(m->hash, &mi->real)); + ASSERT(hash_remove(m->iter, &mi->real)); /* change external network address of the remote peer */ mi->real = real; - generate_prefix (mi); + generate_prefix(mi); mi->context.c2.from = m->top.c2.from; mi->context.c2.to_link_addr = &mi->context.c2.from; @@ -2332,17 +2463,17 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) mi->context.c2.link_socket = m->top.c2.link_socket; mi->context.c2.link_socket_info->lsa->actual = m->top.c2.from; - tls_update_remote_addr (mi->context.c2.tls_multi, &mi->context.c2.from); + tls_update_remote_addr(mi->context.c2.tls_multi, &mi->context.c2.from); - ASSERT (hash_add (m->hash, &mi->real, mi, false)); - ASSERT (hash_add (m->iter, &mi->real, mi, false)); + ASSERT(hash_add(m->hash, &mi->real, mi, false)); + ASSERT(hash_add(m->iter, &mi->real, mi, false)); #ifdef MANAGEMENT_DEF_AUTH - ASSERT (hash_add (m->cid_hash, &mi->context.c2.mda_context.cid, mi, true)); + ASSERT(hash_add(m->cid_hash, &mi->context.c2.mda_context.cid, mi, true)); #endif done: - gc_free (&gc); + gc_free(&gc); } /* @@ -2350,224 +2481,230 @@ done: * i.e. client -> server direction. */ bool -multi_process_incoming_link (struct multi_context *m, struct multi_instance *instance, const unsigned int mpp_flags) +multi_process_incoming_link(struct multi_context *m, struct multi_instance *instance, const unsigned int mpp_flags) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - struct context *c; - struct mroute_addr src, dest; - unsigned int mroute_flags; - struct multi_instance *mi; - bool ret = true; - bool floated = false; + struct context *c; + struct mroute_addr src, dest; + unsigned int mroute_flags; + struct multi_instance *mi; + bool ret = true; + bool floated = false; - if (m->pending) - return true; + if (m->pending) + { + return true; + } - if (!instance) + if (!instance) { #ifdef MULTI_DEBUG_EVENT_LOOP - printf ("TCP/UDP -> TUN [%d]\n", BLEN (&m->top.c2.buf)); + printf("TCP/UDP -> TUN [%d]\n", BLEN(&m->top.c2.buf)); #endif - multi_set_pending (m, multi_get_create_instance_udp (m, &floated)); - } - else - multi_set_pending (m, instance); - - if (m->pending) - { - set_prefix (m->pending); - - /* get instance context */ - c = &m->pending->context; - - if (!instance) - { - /* transfer packet pointer from top-level context buffer to instance */ - c->c2.buf = m->top.c2.buf; - - /* transfer from-addr from top-level context buffer to instance */ - if (!floated) - c->c2.from = m->top.c2.from; - } - - if (BLEN (&c->c2.buf) > 0) - { - struct link_socket_info *lsi; - const uint8_t *orig_buf; - - /* decrypt in instance context */ - - perf_push (PERF_PROC_IN_LINK); - lsi = get_link_socket_info (c); - orig_buf = c->c2.buf.data; - if (process_incoming_link_part1(c, lsi, floated)) - { - if (floated) - { - multi_process_float (m, m->pending); - } - - process_incoming_link_part2(c, lsi, orig_buf); - } - perf_pop (); - - if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TUN) - { - /* extract packet source and dest addresses */ - mroute_flags = mroute_extract_addr_from_packet (&src, - &dest, - NULL, - NULL, - &c->c2.to_tun, - DEV_TYPE_TUN); - - /* drop packet if extract failed */ - if (!(mroute_flags & MROUTE_EXTRACT_SUCCEEDED)) - { - c->c2.to_tun.len = 0; - } - /* make sure that source address is associated with this client */ - else if (multi_get_instance_by_virtual_addr (m, &src, true) != m->pending) - { - /* IPv6 link-local address (fe80::xxx)? */ - if ( (src.type & MR_ADDR_MASK) == MR_ADDR_IPV6 && - IN6_IS_ADDR_LINKLOCAL (&src.v6.addr) ) - { - /* do nothing, for now. TODO: add address learning */ - } - else - { - msg (D_MULTI_DROPPED, "MULTI: bad source address from client [%s], packet dropped", - mroute_addr_print (&src, &gc)); - } - c->c2.to_tun.len = 0; - } - /* client-to-client communication enabled? */ - else if (m->enable_c2c) - { - /* multicast? */ - if (mroute_flags & MROUTE_EXTRACT_MCAST) - { - /* for now, treat multicast as broadcast */ - multi_bcast (m, &c->c2.to_tun, m->pending, NULL); - } - else /* possible client to client routing */ - { - ASSERT (!(mroute_flags & MROUTE_EXTRACT_BCAST)); - mi = multi_get_instance_by_virtual_addr (m, &dest, true); - - /* if dest addr is a known client, route to it */ - if (mi) - { + multi_set_pending(m, multi_get_create_instance_udp(m, &floated)); + } + else + { + multi_set_pending(m, instance); + } + + if (m->pending) + { + set_prefix(m->pending); + + /* get instance context */ + c = &m->pending->context; + + if (!instance) + { + /* transfer packet pointer from top-level context buffer to instance */ + c->c2.buf = m->top.c2.buf; + + /* transfer from-addr from top-level context buffer to instance */ + if (!floated) + { + c->c2.from = m->top.c2.from; + } + } + + if (BLEN(&c->c2.buf) > 0) + { + struct link_socket_info *lsi; + const uint8_t *orig_buf; + + /* decrypt in instance context */ + + perf_push(PERF_PROC_IN_LINK); + lsi = get_link_socket_info(c); + orig_buf = c->c2.buf.data; + if (process_incoming_link_part1(c, lsi, floated)) + { + if (floated) + { + multi_process_float(m, m->pending); + } + + process_incoming_link_part2(c, lsi, orig_buf); + } + perf_pop(); + + if (TUNNEL_TYPE(m->top.c1.tuntap) == DEV_TYPE_TUN) + { + /* extract packet source and dest addresses */ + mroute_flags = mroute_extract_addr_from_packet(&src, + &dest, + NULL, + NULL, + &c->c2.to_tun, + DEV_TYPE_TUN); + + /* drop packet if extract failed */ + if (!(mroute_flags & MROUTE_EXTRACT_SUCCEEDED)) + { + c->c2.to_tun.len = 0; + } + /* make sure that source address is associated with this client */ + else if (multi_get_instance_by_virtual_addr(m, &src, true) != m->pending) + { + /* IPv6 link-local address (fe80::xxx)? */ + if ( (src.type & MR_ADDR_MASK) == MR_ADDR_IPV6 + && IN6_IS_ADDR_LINKLOCAL(&src.v6.addr) ) + { + /* do nothing, for now. TODO: add address learning */ + } + else + { + msg(D_MULTI_DROPPED, "MULTI: bad source address from client [%s], packet dropped", + mroute_addr_print(&src, &gc)); + } + c->c2.to_tun.len = 0; + } + /* client-to-client communication enabled? */ + else if (m->enable_c2c) + { + /* multicast? */ + if (mroute_flags & MROUTE_EXTRACT_MCAST) + { + /* for now, treat multicast as broadcast */ + multi_bcast(m, &c->c2.to_tun, m->pending, NULL); + } + else /* possible client to client routing */ + { + ASSERT(!(mroute_flags & MROUTE_EXTRACT_BCAST)); + mi = multi_get_instance_by_virtual_addr(m, &dest, true); + + /* if dest addr is a known client, route to it */ + if (mi) + { #ifdef ENABLE_PF - if (!pf_c2c_test (c, &mi->context, "tun_c2c")) - { - msg (D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TUN packet filter", - mi_prefix (mi)); - } - else + if (!pf_c2c_test(c, &mi->context, "tun_c2c")) + { + msg(D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TUN packet filter", + mi_prefix(mi)); + } + else #endif - { - multi_unicast (m, &c->c2.to_tun, mi); - register_activity (c, BLEN(&c->c2.to_tun)); - } - c->c2.to_tun.len = 0; - } - } - } + { + multi_unicast(m, &c->c2.to_tun, mi); + register_activity(c, BLEN(&c->c2.to_tun)); + } + c->c2.to_tun.len = 0; + } + } + } #ifdef ENABLE_PF - if (c->c2.to_tun.len && !pf_addr_test (c, &dest, "tun_dest_addr")) - { - msg (D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TUN packet filter", - mroute_addr_print_ex (&dest, MAPF_SHOW_ARP, &gc)); - c->c2.to_tun.len = 0; - } + if (c->c2.to_tun.len && !pf_addr_test(c, &dest, "tun_dest_addr")) + { + msg(D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TUN packet filter", + mroute_addr_print_ex(&dest, MAPF_SHOW_ARP, &gc)); + c->c2.to_tun.len = 0; + } #endif - } - else if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TAP) - { + } + else if (TUNNEL_TYPE(m->top.c1.tuntap) == DEV_TYPE_TAP) + { #ifdef ENABLE_PF - struct mroute_addr edest; - mroute_addr_reset (&edest); + struct mroute_addr edest; + mroute_addr_reset(&edest); #endif - /* extract packet source and dest addresses */ - mroute_flags = mroute_extract_addr_from_packet (&src, - &dest, - NULL, + /* extract packet source and dest addresses */ + mroute_flags = mroute_extract_addr_from_packet(&src, + &dest, + NULL, #ifdef ENABLE_PF - &edest, + &edest, #else - NULL, + NULL, #endif - &c->c2.to_tun, - DEV_TYPE_TAP); - - if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) - { - if (multi_learn_addr (m, m->pending, &src, 0) == m->pending) - { - /* check for broadcast */ - if (m->enable_c2c) - { - if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) - { - multi_bcast (m, &c->c2.to_tun, m->pending, NULL); - } - else /* try client-to-client routing */ - { - mi = multi_get_instance_by_virtual_addr (m, &dest, false); - - /* if dest addr is a known client, route to it */ - if (mi) - { + &c->c2.to_tun, + DEV_TYPE_TAP); + + if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) + { + if (multi_learn_addr(m, m->pending, &src, 0) == m->pending) + { + /* check for broadcast */ + if (m->enable_c2c) + { + if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) + { + multi_bcast(m, &c->c2.to_tun, m->pending, NULL); + } + else /* try client-to-client routing */ + { + mi = multi_get_instance_by_virtual_addr(m, &dest, false); + + /* if dest addr is a known client, route to it */ + if (mi) + { #ifdef ENABLE_PF - if (!pf_c2c_test (c, &mi->context, "tap_c2c")) - { - msg (D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TAP packet filter", - mi_prefix (mi)); - } - else + if (!pf_c2c_test(c, &mi->context, "tap_c2c")) + { + msg(D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TAP packet filter", + mi_prefix(mi)); + } + else #endif - { - multi_unicast (m, &c->c2.to_tun, mi); - register_activity (c, BLEN(&c->c2.to_tun)); - } - c->c2.to_tun.len = 0; - } - } - } + { + multi_unicast(m, &c->c2.to_tun, mi); + register_activity(c, BLEN(&c->c2.to_tun)); + } + c->c2.to_tun.len = 0; + } + } + } #ifdef ENABLE_PF - if (c->c2.to_tun.len && !pf_addr_test (c, &edest, "tap_dest_addr")) - { - msg (D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TAP packet filter", - mroute_addr_print_ex (&edest, MAPF_SHOW_ARP, &gc)); - c->c2.to_tun.len = 0; - } + if (c->c2.to_tun.len && !pf_addr_test(c, &edest, "tap_dest_addr")) + { + msg(D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TAP packet filter", + mroute_addr_print_ex(&edest, MAPF_SHOW_ARP, &gc)); + c->c2.to_tun.len = 0; + } #endif - } - else - { - msg (D_MULTI_DROPPED, "MULTI: bad source address from client [%s], packet dropped", - mroute_addr_print (&src, &gc)); - c->c2.to_tun.len = 0; - } - } - else - { - c->c2.to_tun.len = 0; - } - } - } + } + else + { + msg(D_MULTI_DROPPED, "MULTI: bad source address from client [%s], packet dropped", + mroute_addr_print(&src, &gc)); + c->c2.to_tun.len = 0; + } + } + else + { + c->c2.to_tun.len = 0; + } + } + } - /* postprocess and set wakeup */ - ret = multi_process_post (m, m->pending, mpp_flags); + /* postprocess and set wakeup */ + ret = multi_process_post(m, m->pending, mpp_flags); - clear_prefix (); + clear_prefix(); } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } /* @@ -2575,115 +2712,117 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins * i.e. server -> client direction. */ bool -multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flags) +multi_process_incoming_tun(struct multi_context *m, const unsigned int mpp_flags) { - struct gc_arena gc = gc_new (); - bool ret = true; + struct gc_arena gc = gc_new(); + bool ret = true; - if (BLEN (&m->top.c2.buf) > 0) + if (BLEN(&m->top.c2.buf) > 0) { - unsigned int mroute_flags; - struct mroute_addr src, dest; - const int dev_type = TUNNEL_TYPE (m->top.c1.tuntap); + unsigned int mroute_flags; + struct mroute_addr src, dest; + const int dev_type = TUNNEL_TYPE(m->top.c1.tuntap); #ifdef ENABLE_PF - struct mroute_addr esrc, *e1, *e2; - if (dev_type == DEV_TYPE_TUN) - { - e1 = NULL; - e2 = &src; - } - else - { - e1 = e2 = &esrc; - mroute_addr_reset (&esrc); - } + struct mroute_addr esrc, *e1, *e2; + if (dev_type == DEV_TYPE_TUN) + { + e1 = NULL; + e2 = &src; + } + else + { + e1 = e2 = &esrc; + mroute_addr_reset(&esrc); + } #endif #ifdef MULTI_DEBUG_EVENT_LOOP - printf ("TUN -> TCP/UDP [%d]\n", BLEN (&m->top.c2.buf)); + printf("TUN -> TCP/UDP [%d]\n", BLEN(&m->top.c2.buf)); #endif - if (m->pending) - return true; + if (m->pending) + { + return true; + } - /* - * Route an incoming tun/tap packet to - * the appropriate multi_instance object. - */ + /* + * Route an incoming tun/tap packet to + * the appropriate multi_instance object. + */ - mroute_flags = mroute_extract_addr_from_packet (&src, - &dest, + mroute_flags = mroute_extract_addr_from_packet(&src, + &dest, #ifdef ENABLE_PF - e1, + e1, #else - NULL, + NULL, #endif - NULL, - &m->top.c2.buf, - dev_type); - - if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) - { - struct context *c; - - /* broadcast or multicast dest addr? */ - if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) - { - /* for now, treat multicast as broadcast */ + NULL, + &m->top.c2.buf, + dev_type); + + if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) + { + struct context *c; + + /* broadcast or multicast dest addr? */ + if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) + { + /* for now, treat multicast as broadcast */ #ifdef ENABLE_PF - multi_bcast (m, &m->top.c2.buf, NULL, e2); + multi_bcast(m, &m->top.c2.buf, NULL, e2); #else - multi_bcast (m, &m->top.c2.buf, NULL, NULL); + multi_bcast(m, &m->top.c2.buf, NULL, NULL); #endif - } - else - { - multi_set_pending (m, multi_get_instance_by_virtual_addr (m, &dest, dev_type == DEV_TYPE_TUN)); - - if (m->pending) - { - /* get instance context */ - c = &m->pending->context; - - set_prefix (m->pending); + } + else + { + multi_set_pending(m, multi_get_instance_by_virtual_addr(m, &dest, dev_type == DEV_TYPE_TUN)); + + if (m->pending) + { + /* get instance context */ + c = &m->pending->context; + + set_prefix(m->pending); #ifdef ENABLE_PF - if (!pf_addr_test (c, e2, "tun_tap_src_addr")) - { - msg (D_PF_DROPPED, "PF: addr[%s] -> client packet dropped by packet filter", - mroute_addr_print_ex (&src, MAPF_SHOW_ARP, &gc)); - buf_reset_len (&c->c2.buf); - } - else + if (!pf_addr_test(c, e2, "tun_tap_src_addr")) + { + msg(D_PF_DROPPED, "PF: addr[%s] -> client packet dropped by packet filter", + mroute_addr_print_ex(&src, MAPF_SHOW_ARP, &gc)); + buf_reset_len(&c->c2.buf); + } + else #endif - { - if (multi_output_queue_ready (m, m->pending)) - { - /* transfer packet pointer from top-level context buffer to instance */ - c->c2.buf = m->top.c2.buf; - } - else - { - /* drop packet */ - msg (D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_process_incoming_tun)"); - buf_reset_len (&c->c2.buf); - } - } - - /* encrypt in instance context */ - process_incoming_tun (c); - - /* postprocess and set wakeup */ - ret = multi_process_post (m, m->pending, mpp_flags); - - clear_prefix (); - } - } - } - } - gc_free (&gc); - return ret; + { + if (multi_output_queue_ready(m, m->pending)) + { + /* transfer packet pointer from top-level context buffer to instance */ + c->c2.buf = m->top.c2.buf; + } + else + { + /* drop packet */ + msg(D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_process_incoming_tun)"); + buf_reset_len(&c->c2.buf); + } + } + + /* encrypt in instance context */ + process_incoming_tun(c); + + /* postprocess and set wakeup */ + ret = multi_process_post(m, m->pending, mpp_flags); + + clear_prefix(); + } + } + } + } + gc_free(&gc); + return ret; } /* @@ -2691,30 +2830,32 @@ multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flag * queue. */ struct multi_instance * -multi_get_queue (struct mbuf_set *ms) +multi_get_queue(struct mbuf_set *ms) { - struct mbuf_item item; + struct mbuf_item item; - if (mbuf_extract_item (ms, &item)) /* cleartext IP packet */ + if (mbuf_extract_item(ms, &item)) /* cleartext IP packet */ { - unsigned int pip_flags = PIPV4_PASSTOS; + unsigned int pip_flags = PIPV4_PASSTOS; - set_prefix (item.instance); - item.instance->context.c2.buf = item.buffer->buf; - if (item.buffer->flags & MF_UNICAST) /* --mssfix doesn't make sense for broadcast or multicast */ - pip_flags |= PIP_MSSFIX; - process_ip_header (&item.instance->context, pip_flags, &item.instance->context.c2.buf); - encrypt_sign (&item.instance->context, true); - mbuf_free_buf (item.buffer); + set_prefix(item.instance); + item.instance->context.c2.buf = item.buffer->buf; + if (item.buffer->flags & MF_UNICAST) /* --mssfix doesn't make sense for broadcast or multicast */ + { + pip_flags |= PIP_MSSFIX; + } + process_ip_header(&item.instance->context, pip_flags, &item.instance->context.c2.buf); + encrypt_sign(&item.instance->context, true); + mbuf_free_buf(item.buffer); - dmsg (D_MULTI_DEBUG, "MULTI: C2C/MCAST/BCAST"); + dmsg(D_MULTI_DEBUG, "MULTI: C2C/MCAST/BCAST"); - clear_prefix (); - return item.instance; + clear_prefix(); + return item.instance; } - else + else { - return NULL; + return NULL; } } @@ -2723,52 +2864,52 @@ multi_get_queue (struct mbuf_set *ms) * client instance object needs timer-based service. */ bool -multi_process_timeout (struct multi_context *m, const unsigned int mpp_flags) +multi_process_timeout(struct multi_context *m, const unsigned int mpp_flags) { - bool ret = true; + bool ret = true; #ifdef MULTI_DEBUG_EVENT_LOOP - printf ("%s -> TIMEOUT\n", id(m->earliest_wakeup)); + printf("%s -> TIMEOUT\n", id(m->earliest_wakeup)); #endif - /* instance marked for wakeup? */ - if (m->earliest_wakeup) + /* instance marked for wakeup? */ + if (m->earliest_wakeup) { - if (m->earliest_wakeup == (struct multi_instance*)&m->deferred_shutdown_signal) - { - schedule_remove_entry(m->schedule, (struct schedule_entry*) &m->deferred_shutdown_signal); - throw_signal(m->deferred_shutdown_signal.signal_received); - } - else - { - set_prefix (m->earliest_wakeup); - ret = multi_process_post (m, m->earliest_wakeup, mpp_flags); - clear_prefix (); - } - m->earliest_wakeup = NULL; + if (m->earliest_wakeup == (struct multi_instance *)&m->deferred_shutdown_signal) + { + schedule_remove_entry(m->schedule, (struct schedule_entry *) &m->deferred_shutdown_signal); + throw_signal(m->deferred_shutdown_signal.signal_received); + } + else + { + set_prefix(m->earliest_wakeup); + ret = multi_process_post(m, m->earliest_wakeup, mpp_flags); + clear_prefix(); + } + m->earliest_wakeup = NULL; } - return ret; + return ret; } /* * Drop a TUN/TAP outgoing packet.. */ void -multi_process_drop_outgoing_tun (struct multi_context *m, const unsigned int mpp_flags) +multi_process_drop_outgoing_tun(struct multi_context *m, const unsigned int mpp_flags) { - struct multi_instance *mi = m->pending; + struct multi_instance *mi = m->pending; - ASSERT (mi); + ASSERT(mi); - set_prefix (mi); + set_prefix(mi); - msg (D_MULTI_ERRORS, "MULTI: Outgoing TUN queue full, dropped packet len=%d", - mi->context.c2.to_tun.len); + msg(D_MULTI_ERRORS, "MULTI: Outgoing TUN queue full, dropped packet len=%d", + mi->context.c2.to_tun.len); - buf_reset (&mi->context.c2.to_tun); + buf_reset(&mi->context.c2.to_tun); - multi_process_post (m, mi, mpp_flags); - clear_prefix (); + multi_process_post(m, mi, mpp_flags); + clear_prefix(); } /* @@ -2776,13 +2917,13 @@ multi_process_drop_outgoing_tun (struct multi_context *m, const unsigned int mpp */ void -route_quota_exceeded (const struct multi_context *m, const struct multi_instance *mi) +route_quota_exceeded(const struct multi_context *m, const struct multi_instance *mi) { - struct gc_arena gc = gc_new (); - msg (D_ROUTE_QUOTA, "MULTI ROUTE: route quota (%d) exceeded for %s (see --max-routes-per-client option)", - mi->context.options.max_routes_per_client, - multi_instance_string (mi, false, &gc)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + msg(D_ROUTE_QUOTA, "MULTI ROUTE: route quota (%d) exceeded for %s (see --max-routes-per-client option)", + mi->context.options.max_routes_per_client, + multi_instance_string(mi, false, &gc)); + gc_free(&gc); } #ifdef ENABLE_DEBUG @@ -2790,124 +2931,128 @@ route_quota_exceeded (const struct multi_context *m, const struct multi_instance * Flood clients with random packets */ static void -gremlin_flood_clients (struct multi_context *m) +gremlin_flood_clients(struct multi_context *m) { - const int level = GREMLIN_PACKET_FLOOD_LEVEL (m->top.options.gremlin); - if (level) + const int level = GREMLIN_PACKET_FLOOD_LEVEL(m->top.options.gremlin); + if (level) { - struct gc_arena gc = gc_new (); - struct buffer buf = alloc_buf_gc (BUF_SIZE (&m->top.c2.frame), &gc); - struct packet_flood_parms parm = get_packet_flood_parms (level); - int i; + struct gc_arena gc = gc_new(); + struct buffer buf = alloc_buf_gc(BUF_SIZE(&m->top.c2.frame), &gc); + struct packet_flood_parms parm = get_packet_flood_parms(level); + int i; - ASSERT (buf_init (&buf, FRAME_HEADROOM (&m->top.c2.frame))); - parm.packet_size = min_int (parm.packet_size, MAX_RW_SIZE_TUN (&m->top.c2.frame)); + ASSERT(buf_init(&buf, FRAME_HEADROOM(&m->top.c2.frame))); + parm.packet_size = min_int(parm.packet_size, MAX_RW_SIZE_TUN(&m->top.c2.frame)); - msg (D_GREMLIN, "GREMLIN_FLOOD_CLIENTS: flooding clients with %d packets of size %d", - parm.n_packets, - parm.packet_size); + msg(D_GREMLIN, "GREMLIN_FLOOD_CLIENTS: flooding clients with %d packets of size %d", + parm.n_packets, + parm.packet_size); - for (i = 0; i < parm.packet_size; ++i) - ASSERT (buf_write_u8 (&buf, get_random () & 0xFF)); + for (i = 0; i < parm.packet_size; ++i) + ASSERT(buf_write_u8(&buf, get_random() & 0xFF)); - for (i = 0; i < parm.n_packets; ++i) - multi_bcast (m, &buf, NULL, NULL); + for (i = 0; i < parm.n_packets; ++i) + multi_bcast(m, &buf, NULL, NULL); - gc_free (&gc); + gc_free(&gc); } } -#endif +#endif /* ifdef ENABLE_DEBUG */ bool -stale_route_check_trigger (struct multi_context *m) +stale_route_check_trigger(struct multi_context *m) { - struct timeval null; - CLEAR (null); - return event_timeout_trigger (&m->stale_routes_check_et, &null, ETT_DEFAULT); + struct timeval null; + CLEAR(null); + return event_timeout_trigger(&m->stale_routes_check_et, &null, ETT_DEFAULT); } /* * Process timers in the top-level context */ void -multi_process_per_second_timers_dowork (struct multi_context *m) +multi_process_per_second_timers_dowork(struct multi_context *m) { - /* possibly reap instances/routes in vhash */ - multi_reap_process (m); + /* possibly reap instances/routes in vhash */ + multi_reap_process(m); - /* possibly print to status log */ - if (m->top.c1.status_output) + /* possibly print to status log */ + if (m->top.c1.status_output) { - if (status_trigger (m->top.c1.status_output)) - multi_print_status (m, m->top.c1.status_output, m->status_file_version); + if (status_trigger(m->top.c1.status_output)) + { + multi_print_status(m, m->top.c1.status_output, m->status_file_version); + } } - /* possibly flush ifconfig-pool file */ - multi_ifconfig_pool_persist (m, false); + /* possibly flush ifconfig-pool file */ + multi_ifconfig_pool_persist(m, false); #ifdef ENABLE_DEBUG - gremlin_flood_clients (m); + gremlin_flood_clients(m); #endif - /* Should we check for stale routes? */ - if (m->top.options.stale_routes_check_interval && stale_route_check_trigger (m)) - check_stale_routes (m); + /* Should we check for stale routes? */ + if (m->top.options.stale_routes_check_interval && stale_route_check_trigger(m)) + { + check_stale_routes(m); + } } void -multi_top_init (struct multi_context *m, const struct context *top) +multi_top_init(struct multi_context *m, const struct context *top) { - inherit_context_top (&m->top, top); - m->top.c2.buffers = init_context_buffers (&top->c2.frame); + inherit_context_top(&m->top, top); + m->top.c2.buffers = init_context_buffers(&top->c2.frame); } void -multi_top_free (struct multi_context *m) +multi_top_free(struct multi_context *m) { - close_context (&m->top, -1, CC_GC_FREE); - free_context_buffers (m->top.c2.buffers); + close_context(&m->top, -1, CC_GC_FREE); + free_context_buffers(m->top.c2.buffers); } static bool is_exit_restart(int sig) { - return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == SIGINT); + return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == SIGINT); } static void multi_push_restart_schedule_exit(struct multi_context *m, bool next_server) { - struct hash_iterator hi; - struct hash_element *he; - struct timeval tv; + struct hash_iterator hi; + struct hash_element *he; + struct timeval tv; - /* tell all clients to restart */ - hash_iterator_init (m->iter, &hi); - while ((he = hash_iterator_next (&hi))) + /* tell all clients to restart */ + hash_iterator_init(m->iter, &hi); + while ((he = hash_iterator_next(&hi))) { - struct multi_instance *mi = (struct multi_instance *) he->value; - if (!mi->halt) + struct multi_instance *mi = (struct multi_instance *) he->value; + if (!mi->halt) { - send_control_channel_string (&mi->context, next_server ? "RESTART,[N]" : "RESTART", D_PUSH); - multi_schedule_context_wakeup(m, mi); + send_control_channel_string(&mi->context, next_server ? "RESTART,[N]" : "RESTART", D_PUSH); + multi_schedule_context_wakeup(m, mi); } } - hash_iterator_free (&hi); + hash_iterator_free(&hi); - /* reschedule signal */ - ASSERT (!openvpn_gettimeofday (&m->deferred_shutdown_signal.wakeup, NULL)); - tv.tv_sec = 2; - tv.tv_usec = 0; - tv_add (&m->deferred_shutdown_signal.wakeup, &tv); + /* reschedule signal */ + ASSERT(!openvpn_gettimeofday(&m->deferred_shutdown_signal.wakeup, NULL)); + tv.tv_sec = 2; + tv.tv_usec = 0; + tv_add(&m->deferred_shutdown_signal.wakeup, &tv); - m->deferred_shutdown_signal.signal_received = m->top.sig->signal_received; + m->deferred_shutdown_signal.signal_received = m->top.sig->signal_received; - schedule_add_entry (m->schedule, - (struct schedule_entry *) &m->deferred_shutdown_signal, - &m->deferred_shutdown_signal.wakeup, - compute_wakeup_sigma (&m->deferred_shutdown_signal.wakeup)); + schedule_add_entry(m->schedule, + (struct schedule_entry *) &m->deferred_shutdown_signal, + &m->deferred_shutdown_signal.wakeup, + compute_wakeup_sigma(&m->deferred_shutdown_signal.wakeup)); - m->top.sig->signal_received = 0; + m->top.sig->signal_received = 0; } /* @@ -2915,25 +3060,25 @@ multi_push_restart_schedule_exit(struct multi_context *m, bool next_server) * false if it should continue. */ bool -multi_process_signal (struct multi_context *m) +multi_process_signal(struct multi_context *m) { - if (m->top.sig->signal_received == SIGUSR2) + if (m->top.sig->signal_received == SIGUSR2) { - struct status_output *so = status_open (NULL, 0, M_INFO, NULL, 0); - multi_print_status (m, so, m->status_file_version); - status_close (so); - m->top.sig->signal_received = 0; - return false; + struct status_output *so = status_open(NULL, 0, M_INFO, NULL, 0); + multi_print_status(m, so, m->status_file_version); + status_close(so); + m->top.sig->signal_received = 0; + return false; } - else if (proto_is_dgram(m->top.options.ce.proto) && - is_exit_restart(m->top.sig->signal_received) && - (m->deferred_shutdown_signal.signal_received == 0) && - m->top.options.ce.explicit_exit_notification != 0) + else if (proto_is_dgram(m->top.options.ce.proto) + && is_exit_restart(m->top.sig->signal_received) + && (m->deferred_shutdown_signal.signal_received == 0) + && m->top.options.ce.explicit_exit_notification != 0) { - multi_push_restart_schedule_exit(m, m->top.options.ce.explicit_exit_notification == 2); - return false; + multi_push_restart_schedule_exit(m, m->top.options.ce.explicit_exit_notification == 2); + return false; } - return true; + return true; } /* @@ -2941,20 +3086,20 @@ multi_process_signal (struct multi_context *m) * reception of a soft signal. */ void -multi_close_instance_on_signal (struct multi_context *m, struct multi_instance *mi) +multi_close_instance_on_signal(struct multi_context *m, struct multi_instance *mi) { - remap_signal (&mi->context); - set_prefix (mi); - print_signal (mi->context.sig, "client-instance", D_MULTI_LOW); - clear_prefix (); - multi_close_instance (m, mi, false); + remap_signal(&mi->context); + set_prefix(mi); + print_signal(mi->context.sig, "client-instance", D_MULTI_LOW); + clear_prefix(); + multi_close_instance(m, mi, false); } static void -multi_signal_instance (struct multi_context *m, struct multi_instance *mi, const int sig) +multi_signal_instance(struct multi_context *m, struct multi_instance *mi, const int sig) { - mi->context.sig->signal_received = sig; - multi_close_instance_on_signal (m, mi); + mi->context.sig->signal_received = sig; + multi_close_instance_on_signal(m, mi); } /* @@ -2964,246 +3109,272 @@ multi_signal_instance (struct multi_context *m, struct multi_instance *mi, const #ifdef ENABLE_MANAGEMENT static void -management_callback_status (void *arg, const int version, struct status_output *so) +management_callback_status(void *arg, const int version, struct status_output *so) { - struct multi_context *m = (struct multi_context *) arg; + struct multi_context *m = (struct multi_context *) arg; - if (!version) - multi_print_status (m, so, m->status_file_version); - else - multi_print_status (m, so, version); + if (!version) + { + multi_print_status(m, so, m->status_file_version); + } + else + { + multi_print_status(m, so, version); + } } static int -management_callback_n_clients (void *arg) +management_callback_n_clients(void *arg) { - struct multi_context *m = (struct multi_context *) arg; - return m->n_clients; + struct multi_context *m = (struct multi_context *) arg; + return m->n_clients; } static int -management_callback_kill_by_cn (void *arg, const char *del_cn) +management_callback_kill_by_cn(void *arg, const char *del_cn) { - struct multi_context *m = (struct multi_context *) arg; - struct hash_iterator hi; - struct hash_element *he; - int count = 0; + struct multi_context *m = (struct multi_context *) arg; + struct hash_iterator hi; + struct hash_element *he; + int count = 0; - hash_iterator_init (m->iter, &hi); - while ((he = hash_iterator_next (&hi))) + hash_iterator_init(m->iter, &hi); + while ((he = hash_iterator_next(&hi))) { - struct multi_instance *mi = (struct multi_instance *) he->value; - if (!mi->halt) - { - const char *cn = tls_common_name (mi->context.c2.tls_multi, false); - if (cn && !strcmp (cn, del_cn)) - { - multi_signal_instance (m, mi, SIGTERM); - ++count; - } - } + struct multi_instance *mi = (struct multi_instance *) he->value; + if (!mi->halt) + { + const char *cn = tls_common_name(mi->context.c2.tls_multi, false); + if (cn && !strcmp(cn, del_cn)) + { + multi_signal_instance(m, mi, SIGTERM); + ++count; + } + } } - hash_iterator_free (&hi); - return count; + hash_iterator_free(&hi); + return count; } static int -management_callback_kill_by_addr (void *arg, const in_addr_t addr, const int port) -{ - struct multi_context *m = (struct multi_context *) arg; - struct hash_iterator hi; - struct hash_element *he; - struct openvpn_sockaddr saddr; - struct mroute_addr maddr; - int count = 0; - - CLEAR (saddr); - saddr.addr.in4.sin_family = AF_INET; - saddr.addr.in4.sin_addr.s_addr = htonl (addr); - saddr.addr.in4.sin_port = htons (port); - if (mroute_extract_openvpn_sockaddr (&maddr, &saddr, true)) - { - hash_iterator_init (m->iter, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct multi_instance *mi = (struct multi_instance *) he->value; - if (!mi->halt && mroute_addr_equal (&maddr, &mi->real)) - { - multi_signal_instance (m, mi, SIGTERM); - ++count; - } - } - hash_iterator_free (&hi); - } - return count; +management_callback_kill_by_addr(void *arg, const in_addr_t addr, const int port) +{ + struct multi_context *m = (struct multi_context *) arg; + struct hash_iterator hi; + struct hash_element *he; + struct openvpn_sockaddr saddr; + struct mroute_addr maddr; + int count = 0; + + CLEAR(saddr); + saddr.addr.in4.sin_family = AF_INET; + saddr.addr.in4.sin_addr.s_addr = htonl(addr); + saddr.addr.in4.sin_port = htons(port); + if (mroute_extract_openvpn_sockaddr(&maddr, &saddr, true)) + { + hash_iterator_init(m->iter, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct multi_instance *mi = (struct multi_instance *) he->value; + if (!mi->halt && mroute_addr_equal(&maddr, &mi->real)) + { + multi_signal_instance(m, mi, SIGTERM); + ++count; + } + } + hash_iterator_free(&hi); + } + return count; } static void -management_delete_event (void *arg, event_t event) +management_delete_event(void *arg, event_t event) { - struct multi_context *m = (struct multi_context *) arg; - if (m->mtcp) - multi_tcp_delete_event (m->mtcp, event); + struct multi_context *m = (struct multi_context *) arg; + if (m->mtcp) + { + multi_tcp_delete_event(m->mtcp, event); + } } -#endif +#endif /* ifdef ENABLE_MANAGEMENT */ #ifdef MANAGEMENT_DEF_AUTH static struct multi_instance * -lookup_by_cid (struct multi_context *m, const unsigned long cid) +lookup_by_cid(struct multi_context *m, const unsigned long cid) { - if (m) + if (m) { - struct multi_instance *mi = (struct multi_instance *) hash_lookup (m->cid_hash, &cid); - if (mi && !mi->halt) - return mi; + struct multi_instance *mi = (struct multi_instance *) hash_lookup(m->cid_hash, &cid); + if (mi && !mi->halt) + { + return mi; + } } - return NULL; + return NULL; } static bool -management_kill_by_cid (void *arg, const unsigned long cid, const char *kill_msg) +management_kill_by_cid(void *arg, const unsigned long cid, const char *kill_msg) { - struct multi_context *m = (struct multi_context *) arg; - struct multi_instance *mi = lookup_by_cid (m, cid); - if (mi) + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid(m, cid); + if (mi) { - send_restart (&mi->context, kill_msg); /* was: multi_signal_instance (m, mi, SIGTERM); */ - multi_schedule_context_wakeup(m, mi); - return true; + send_restart(&mi->context, kill_msg); /* was: multi_signal_instance (m, mi, SIGTERM); */ + multi_schedule_context_wakeup(m, mi); + return true; + } + else + { + return false; } - else - return false; } static bool -management_client_auth (void *arg, - const unsigned long cid, - const unsigned int mda_key_id, - const bool auth, - const char *reason, - const char *client_reason, - struct buffer_list *cc_config) /* ownership transferred */ -{ - struct multi_context *m = (struct multi_context *) arg; - struct multi_instance *mi = lookup_by_cid (m, cid); - bool cc_config_owned = true; - bool ret = false; - - if (mi) - { - ret = tls_authenticate_key (mi->context.c2.tls_multi, mda_key_id, auth, client_reason); - if (ret) - { - if (auth) - { - if (!mi->connection_established_flag) - { - set_cc_config (mi, cc_config); - cc_config_owned = false; - } - } - else - { - if (reason) - msg (D_MULTI_LOW, "MULTI: connection rejected: %s, CLI:%s", reason, np(client_reason)); - if (mi->connection_established_flag) - { - send_auth_failed (&mi->context, client_reason); /* mid-session reauth failed */ - multi_schedule_context_wakeup(m, mi); - } - } - } - } - if (cc_config_owned && cc_config) - buffer_list_free (cc_config); - return ret; +management_client_auth(void *arg, + const unsigned long cid, + const unsigned int mda_key_id, + const bool auth, + const char *reason, + const char *client_reason, + struct buffer_list *cc_config) /* ownership transferred */ +{ + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid(m, cid); + bool cc_config_owned = true; + bool ret = false; + + if (mi) + { + ret = tls_authenticate_key(mi->context.c2.tls_multi, mda_key_id, auth, client_reason); + if (ret) + { + if (auth) + { + if (!mi->connection_established_flag) + { + set_cc_config(mi, cc_config); + cc_config_owned = false; + } + } + else + { + if (reason) + { + msg(D_MULTI_LOW, "MULTI: connection rejected: %s, CLI:%s", reason, np(client_reason)); + } + if (mi->connection_established_flag) + { + send_auth_failed(&mi->context, client_reason); /* mid-session reauth failed */ + multi_schedule_context_wakeup(m, mi); + } + } + } + } + if (cc_config_owned && cc_config) + { + buffer_list_free(cc_config); + } + return ret; } static char * -management_get_peer_info (void *arg, const unsigned long cid) +management_get_peer_info(void *arg, const unsigned long cid) { - struct multi_context *m = (struct multi_context *) arg; - struct multi_instance *mi = lookup_by_cid (m, cid); - char *ret = NULL; + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid(m, cid); + char *ret = NULL; - if (mi) - ret = tls_get_peer_info (mi->context.c2.tls_multi); + if (mi) + { + ret = tls_get_peer_info(mi->context.c2.tls_multi); + } - return ret; + return ret; } -#endif +#endif /* ifdef MANAGEMENT_DEF_AUTH */ #ifdef MANAGEMENT_PF static bool -management_client_pf (void *arg, - const unsigned long cid, - struct buffer_list *pf_config) /* ownership transferred */ +management_client_pf(void *arg, + const unsigned long cid, + struct buffer_list *pf_config) /* ownership transferred */ { - struct multi_context *m = (struct multi_context *) arg; - struct multi_instance *mi = lookup_by_cid (m, cid); - bool ret = false; + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid(m, cid); + bool ret = false; - if (mi && pf_config) - ret = pf_load_from_buffer_list (&mi->context, pf_config); + if (mi && pf_config) + { + ret = pf_load_from_buffer_list(&mi->context, pf_config); + } - if (pf_config) - buffer_list_free (pf_config); - return ret; + if (pf_config) + { + buffer_list_free(pf_config); + } + return ret; } -#endif +#endif /* ifdef MANAGEMENT_PF */ void -init_management_callback_multi (struct multi_context *m) +init_management_callback_multi(struct multi_context *m) { #ifdef ENABLE_MANAGEMENT - if (management) - { - struct management_callback cb; - CLEAR (cb); - cb.arg = m; - cb.flags = MCF_SERVER; - cb.status = management_callback_status; - cb.show_net = management_show_net_callback; - cb.kill_by_cn = management_callback_kill_by_cn; - cb.kill_by_addr = management_callback_kill_by_addr; - cb.delete_event = management_delete_event; - cb.n_clients = management_callback_n_clients; + if (management) + { + struct management_callback cb; + CLEAR(cb); + cb.arg = m; + cb.flags = MCF_SERVER; + cb.status = management_callback_status; + cb.show_net = management_show_net_callback; + cb.kill_by_cn = management_callback_kill_by_cn; + cb.kill_by_addr = management_callback_kill_by_addr; + cb.delete_event = management_delete_event; + cb.n_clients = management_callback_n_clients; #ifdef MANAGEMENT_DEF_AUTH - cb.kill_by_cid = management_kill_by_cid; - cb.client_auth = management_client_auth; - cb.get_peer_info = management_get_peer_info; + cb.kill_by_cid = management_kill_by_cid; + cb.client_auth = management_client_auth; + cb.get_peer_info = management_get_peer_info; #endif #ifdef MANAGEMENT_PF - cb.client_pf = management_client_pf; + cb.client_pf = management_client_pf; #endif - management_set_callback (management, &cb); + management_set_callback(management, &cb); } -#endif +#endif /* ifdef ENABLE_MANAGEMENT */ } void -uninit_management_callback_multi (struct multi_context *m) +uninit_management_callback_multi(struct multi_context *m) { - uninit_management_callback (); + uninit_management_callback(); } /* * Top level event loop. */ void -tunnel_server (struct context *top) +tunnel_server(struct context *top) { - ASSERT (top->options.mode == MODE_SERVER); + ASSERT(top->options.mode == MODE_SERVER); - if (proto_is_dgram(top->options.ce.proto)) - tunnel_server_udp(top); - else - tunnel_server_tcp(top); + if (proto_is_dgram(top->options.ce.proto)) + { + tunnel_server_udp(top); + } + else + { + tunnel_server_tcp(top); + } } -#else -static void dummy(void) {} +#else /* if P2MP_SERVER */ +static void +dummy(void) { +} #endif /* P2MP_SERVER */ |