summaryrefslogtreecommitdiffstats
path: root/multi.c
diff options
context:
space:
mode:
Diffstat (limited to 'multi.c')
-rw-r--r--multi.c353
1 files changed, 329 insertions, 24 deletions
diff --git a/multi.c b/multi.c
index 431ad95..bc3500f 100644
--- a/multi.c
+++ b/multi.c
@@ -35,6 +35,7 @@
#include "memdbg.h"
#include "forward-inline.h"
+#include "pf-inline.h"
/*#define MULTI_DEBUG_EVENT_LOOP*/
@@ -49,6 +50,16 @@ id (struct multi_instance *mi)
}
#endif
+#ifdef MANAGEMENT_DEF_AUTH
+static void
+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;
+}
+#endif
+
static bool
learn_address_script (const struct multi_context *m,
const struct multi_instance *mi,
@@ -198,6 +209,25 @@ reap_buckets_per_pass (int n_buckets)
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)
+{
+ const unsigned long *k = (const unsigned long *)key;
+ return (uint32_t) *k;
+}
+
+static bool
+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;
+}
+
+#endif
+
/*
* Main initialization function, init multi_context object.
*/
@@ -252,6 +282,13 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
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);
+#endif
+
/*
* This is our scheduler, for time-based wakeup
* events.
@@ -376,6 +413,15 @@ ungenerate_prefix (struct multi_instance *mi)
set_prefix (mi);
}
+static const char *
+mi_prefix (const struct multi_instance *mi)
+{
+ if (mi && mi->msg_prefix)
+ return mi->msg_prefix;
+ else
+ return "UNDEF_I";
+}
+
/*
* Tell the route helper about deleted iroutes so
* that it can update its mask of currently used
@@ -439,6 +485,11 @@ multi_client_disconnect_script (struct multi_context *m,
gc_free (&gc);
}
+#ifdef MANAGEMENT_DEF_AUTH
+ if (management)
+ management_notify_client_close (management, &mi->context.c2.mda_context, mi->context.c2.es);
+#endif
+
}
}
@@ -470,6 +521,12 @@ multi_close_instance (struct multi_context *m,
{
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));
+ }
+#endif
schedule_remove_entry (m->schedule, (struct schedule_entry *) mi);
@@ -487,6 +544,10 @@ multi_close_instance (struct multi_context *m,
mbuf_dereference_instance (m->mbuf, mi);
}
+#ifdef MANAGEMENT_DEF_AUTH
+ set_cc_config (mi, NULL);
+#endif
+
multi_client_disconnect_script (m, mi);
if (mi->did_open_context)
@@ -538,6 +599,9 @@ multi_uninit (struct multi_context *m)
hash_free (m->hash);
hash_free (m->vhash);
hash_free (m->iter);
+#ifdef MANAGEMENT_DEF_AUTH
+ hash_free (m->cid_hash);
+#endif
m->hash = NULL;
schedule_free (m->schedule);
@@ -608,6 +672,13 @@ multi_create_instance (struct multi_context *m, const struct mroute_addr *real)
}
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;
+#endif
+
mi->context.c2.push_reply_deferred = true;
if (!multi_process_post (m, mi, MPP_PRE_SELECT))
@@ -983,7 +1054,8 @@ 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 */
+ int netbits, /* -1 if host route, otherwise # of network bits in address */
+ bool primary)
{
struct openvpn_sockaddr remote_si;
struct mroute_addr addr;
@@ -998,7 +1070,15 @@ multi_learn_in_addr_t (struct multi_context *m,
addr.type |= MR_WITH_NETBITS;
addr.netbits = (uint8_t) netbits;
}
- return 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);
+#endif
+ return owner;
+ }
}
/*
@@ -1028,7 +1108,7 @@ multi_add_iroutes (struct multi_context *m,
mroute_helper_add_iroute (m->route_helper, ir);
- multi_learn_in_addr_t (m, mi, ir->network, ir->netbits);
+ multi_learn_in_addr_t (m, mi, ir->network, ir->netbits, false);
}
}
gc_free (&gc);
@@ -1255,7 +1335,7 @@ multi_client_connect_post_plugin (struct multi_context *m,
for (i = 0; i < config.n; ++i)
{
if (config.list[i] && config.list[i]->value)
- options_plugin_import (&mi->context.options,
+ options_string_import (&mi->context.options,
config.list[i]->value,
D_IMPORT_ERRORS|M_OPTERR,
option_permissions_mask,
@@ -1276,6 +1356,46 @@ multi_client_connect_post_plugin (struct multi_context *m,
#endif
+#ifdef MANAGEMENT_DEF_AUTH
+
+/*
+ * 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);
+ }
+}
+
+#endif
+
static void
multi_client_connect_setenv (struct multi_context *m,
struct multi_instance *mi)
@@ -1469,6 +1589,17 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
}
/*
+ * 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;
+ }
+#endif
+
+ /*
* Check for "disable" directive in client-config-dir file
* or config file generated by --client-connect script.
*/
@@ -1515,7 +1646,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
{
if (mi->context.c2.push_ifconfig_defined)
{
- multi_learn_in_addr_t (m, mi, mi->context.c2.push_ifconfig_local, -1);
+ 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));
@@ -1553,6 +1684,11 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
/* set flag so we don't get called again */
mi->connection_established_flag = true;
+#ifdef MANAGEMENT_DEF_AUTH
+ if (management)
+ management_connection_established (management, &mi->context.c2.mda_context);
+#endif
+
gc_free (&gc);
}
@@ -1606,10 +1742,11 @@ multi_unicast (struct multi_context *m,
/*
* Broadcast a packet to all clients.
*/
-void
+static void
multi_bcast (struct multi_context *m,
const struct buffer *buf,
- struct multi_instance *omit)
+ const struct multi_instance *sender_instance,
+ const struct mroute_addr *sender_addr)
{
struct hash_iterator hi;
struct hash_element *he;
@@ -1628,8 +1765,34 @@ multi_bcast (struct multi_context *m,
while ((he = hash_iterator_next (&hi)))
{
mi = (struct multi_instance *) he->value;
- if (mi != omit && !mi->halt)
- multi_add_mbuf (m, mi, mb);
+ 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);
+ }
}
hash_iterator_free (&hi);
@@ -1789,6 +1952,8 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
/* extract packet source and dest addresses */
mroute_flags = mroute_extract_addr_from_packet (&src,
&dest,
+ NULL,
+ NULL,
&c->c2.to_tun,
DEV_TYPE_TUN);
@@ -1811,7 +1976,7 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
if (mroute_flags & MROUTE_EXTRACT_MCAST)
{
/* for now, treat multicast as broadcast */
- multi_bcast (m, &c->c2.to_tun, m->pending);
+ multi_bcast (m, &c->c2.to_tun, m->pending, NULL);
}
else /* possible client to client routing */
{
@@ -1822,10 +1987,10 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
if (mi)
{
#ifdef ENABLE_PF
- if (!pf_c2c_test (c, &mi->context))
+ if (!pf_c2c_test (c, &mi->context, "tun_c2c"))
{
- msg (D_PF, "PF: client -> [%s] packet dropped by packet filter",
- np (mi->msg_prefix));
+ msg (D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TUN packet filter",
+ mi_prefix (mi));
}
else
#endif
@@ -1838,18 +2003,29 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
}
}
#ifdef ENABLE_PF
- else if (!pf_addr_test (c, &dest))
+ if (c->c2.to_tun.len && !pf_addr_test (c, &dest, "tun_dest_addr"))
{
- msg (D_PF, "PF: client -> [%s] packet dropped by packet filter",
- mroute_addr_print (&dest, &gc));
+ 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)
{
+#ifdef ENABLE_PF
+ 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,
+#ifdef ENABLE_PF
+ &edest,
+#else
+ NULL,
+#endif
&c->c2.to_tun,
DEV_TYPE_TAP);
@@ -1862,7 +2038,7 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
{
if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST))
{
- multi_bcast (m, &c->c2.to_tun, m->pending);
+ multi_bcast (m, &c->c2.to_tun, m->pending, NULL);
}
else /* try client-to-client routing */
{
@@ -1871,12 +2047,30 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
/* if dest addr is a known client, route to it */
if (mi)
{
- multi_unicast (m, &c->c2.to_tun, mi);
- register_activity (c, BLEN(&c->c2.to_tun));
+#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
+#endif
+ {
+ 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;
+ }
+#endif
}
else
{
@@ -1918,6 +2112,20 @@ multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flag
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);
+ }
+#endif
+
#ifdef MULTI_DEBUG_EVENT_LOOP
printf ("TUN -> TCP/UDP [%d]\n", BLEN (&m->top.c2.buf));
#endif
@@ -1932,6 +2140,12 @@ multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flag
mroute_flags = mroute_extract_addr_from_packet (&src,
&dest,
+#ifdef ENABLE_PF
+ e1,
+#else
+ NULL,
+#endif
+ NULL,
&m->top.c2.buf,
dev_type);
@@ -1943,7 +2157,11 @@ multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flag
if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST))
{
/* for now, treat multicast as broadcast */
- multi_bcast (m, &m->top.c2.buf, NULL);
+#ifdef ENABLE_PF
+ multi_bcast (m, &m->top.c2.buf, NULL, e2);
+#else
+ multi_bcast (m, &m->top.c2.buf, NULL, NULL);
+#endif
}
else
{
@@ -1957,10 +2175,10 @@ multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flag
set_prefix (m->pending);
#ifdef ENABLE_PF
- if (!pf_addr_test (c, &src))
+ if (!pf_addr_test (c, e2, "tun_tap_src_addr"))
{
- msg (D_PF, "PF: [%s] -> client packet dropped by packet filter",
- mroute_addr_print (&src, &gc));
+ 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
@@ -2111,7 +2329,7 @@ gremlin_flood_clients (struct multi_context *m)
ASSERT (buf_write_u8 (&buf, get_random () & 0xFF));
for (i = 0; i < parm.n_packets; ++i)
- multi_bcast (m, &buf, NULL);
+ multi_bcast (m, &buf, NULL, NULL);
gc_free (&gc);
}
@@ -2281,6 +2499,86 @@ management_delete_event (void *arg, event_t event)
#endif
+#ifdef MANAGEMENT_DEF_AUTH
+
+static struct multi_instance *
+lookup_by_cid (struct multi_context *m, const unsigned long cid)
+{
+ if (m)
+ {
+ struct multi_instance *mi = (struct multi_instance *) hash_lookup (m->cid_hash, &cid);
+ if (mi && !mi->halt)
+ return mi;
+ }
+ return NULL;
+}
+
+static bool
+management_kill_by_cid (void *arg, const unsigned long cid)
+{
+ struct multi_context *m = (struct multi_context *) arg;
+ struct multi_instance *mi = lookup_by_cid (m, cid);
+ if (mi)
+ {
+ multi_signal_instance (m, mi, SIGTERM);
+ return true;
+ }
+ 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,
+ 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);
+ if (ret)
+ {
+ if (auth && !mi->connection_established_flag)
+ {
+ set_cc_config (mi, cc_config);
+ cc_config_owned = false;
+ }
+ if (!auth && reason)
+ msg (D_MULTI_LOW, "MULTI: connection rejected: %s", reason);
+ }
+ }
+ if (cc_config_owned && cc_config)
+ buffer_list_free (cc_config);
+ return ret;
+}
+#endif
+
+#ifdef MANAGEMENT_PF
+static bool
+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;
+
+ if (mi && pf_config)
+ ret = pf_load_from_buffer_list (&mi->context, pf_config);
+
+ if (pf_config)
+ buffer_list_free (pf_config);
+ return ret;
+}
+#endif
+
void
init_management_callback_multi (struct multi_context *m)
{
@@ -2295,6 +2593,13 @@ init_management_callback_multi (struct multi_context *m)
cb.kill_by_cn = management_callback_kill_by_cn;
cb.kill_by_addr = management_callback_kill_by_addr;
cb.delete_event = management_delete_event;
+#ifdef MANAGEMENT_DEF_AUTH
+ cb.kill_by_cid = management_kill_by_cid;
+ cb.client_auth = management_client_auth;
+#endif
+#ifdef MANAGEMENT_PF
+ cb.client_pf = management_client_pf;
+#endif
management_set_callback (management, &cb);
}
#endif