diff options
author | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2008-06-11 08:45:09 +0000 |
---|---|---|
committer | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2008-06-11 08:45:09 +0000 |
commit | 90efcacba6378a4e29275cd6e9914d73d836a4a4 (patch) | |
tree | da032ba71582994f9e1f2ed7162ba14f152cb7d7 /multi.c | |
parent | Added support for building and linking with (diff) | |
download | openvpn-90efcacba6378a4e29275cd6e9914d73d836a4a4.tar.xz |
Updated version to 2.1_rc7e.
Added client authentication and packet filtering capability
to management interface.
Extended packet filtering capability to work on both --dev tun
and --dev tap tunnels.
Updated valgrind-suppress file.
Made "Linux ip addr del failed" error nonfatal.
Amplified --client-cert-not-required warning.
Added #pragma pack to proto.h.
git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@2991 e7ae566f-a301-0410-adde-c780ea21d3b5
Diffstat (limited to '')
-rw-r--r-- | multi.c | 353 |
1 files changed, 329 insertions, 24 deletions
@@ -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 |