📄 multi.c
字号:
/* * OpenVPN -- An application to securely tunnel IP networks * over a single TCP/UDP port, with support for SSL/TLS-based * session authentication and key exchange, * packet encryption, packet authentication, and * packet compression. * * Copyright (C) 2002-2004 James Yonan <jim@yonan.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING included with this * distribution); if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#ifdef WIN32#include "config-win32.h"#else#include "config.h"#endif#include "syshead.h"#if P2MP#include "multi.h"#include "init.h"#include "forward.h"#include "push.h"#include "misc.h"#include "otime.h"#include "memdbg.h"#include "forward-inline.h"#define MULTI_DEBUG // JYFIXME//#define MULTI_DEBUG_EVENT_LOOP // JYFIXME/* * Reaper constants. The reaper is the process where the virtual address * and virtual route hash table is scanned for dead entries which are * then removed. The hash table could potentially be quite large, so we * don't want to reap in a single pass. */#define REAP_MAX_WAKEUP 10 /* Do reap pass at least once per n seconds */#define REAP_DIVISOR 256 /* How many passes to cover whole hash table */#define REAP_MIN 16 /* Minimum number of buckets per pass */#define REAP_MAX 1024 /* Maximum number of buckets per pass *//* * Mark a cached host route for deletion after this * many seconds without any references. */#define MULTI_CACHE_ROUTE_TTL 60static bool multi_process_post (struct multi_thread *mt, struct multi_instance *mi);#ifdef MULTI_DEBUG_EVENT_LOOPstatic const char *id (struct multi_instance *mi){ if (mi) return tls_common_name (mi->context.c2.tls_multi, false); else return "NULL";}#endifstatic voidlearn_address_script (const struct multi_context *m, const struct multi_instance *mi, const char *op, const struct mroute_addr *addr){ if (m->learn_address_script) { struct gc_arena gc = gc_new (); struct buffer cmd = alloc_buf_gc (256, &gc); mutex_lock_static (L_SCRIPT); setenv_str ("script_type", "learn-address"); buf_printf (&cmd, "%s \"%s\" \"%s\"", m->learn_address_script, op, mroute_addr_print (addr, &gc)); if (mi) buf_printf (&cmd, " \"%s\"", tls_common_name (mi->context.c2.tls_multi, true)); system_check (BSTR (&cmd), "learn-address command failed", false); mutex_unlock_static (L_SCRIPT); gc_free (&gc); }}static voidmulti_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; if (start_bucket < 0) { start_bucket = 0; end_bucket = hash_n_buckets (m->vhash); } msg (D_MULTI_DEBUG, "MULTI: REAP range %d -> %d", start_bucket, end_bucket); hash_iterator_init_range (m->vhash, &hi, true, 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)) { msg (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);}static voidmulti_reap_all (const struct multi_context *m){ multi_reap_range (m, -1, 0);}static struct multi_reap *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;}static voidmulti_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;}static inline voidmulti_reap_process (const struct multi_context *m){ if (m->reaper->last_call != now) multi_reap_process_dowork (m);}static voidmulti_reap_free (struct multi_reap *mr){ free (mr);}/* * How many buckets in vhash to reap per pass. */static intreap_buckets_per_pass (int n_buckets){ return constrain_int (n_buckets / REAP_DIVISOR, REAP_MIN, REAP_MAX);}/* * Main initialization function, init multi_context object. */static voidmulti_init (struct multi_context *m, struct context *t){ 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); /* * 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, 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, 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, mroute_addr_hash_function, mroute_addr_compare_function); /* * 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); /* * Possibly allocate an ifconfig pool, do it * differently based on whether a tun or tap style * tunnel. */ if (t->options.ifconfig_pool_defined) { if (dev == DEV_TYPE_TUN) { m->ifconfig_pool = ifconfig_pool_init (IFCONFIG_POOL_30NET, t->options.ifconfig_pool_start, t->options.ifconfig_pool_end); } else if (dev == DEV_TYPE_TAP) { m->ifconfig_pool = ifconfig_pool_init (IFCONFIG_POOL_INDIV, t->options.ifconfig_pool_start, t->options.ifconfig_pool_end); } } /* * 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); /* * Remember possible learn_address_script */ m->learn_address_script = t->options.learn_address_script; /* * Allow client <-> client communication, without going through * tun/tap interface and network stack? */ m->enable_c2c = t->options.enable_c2c;}const char *multi_instance_string (struct multi_instance *mi, bool null, struct gc_arena *gc){ if (mi) { struct buffer out = alloc_buf_gc (256, 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); } else if (null) return NULL; else return "UNDEF";}/* * Set a msg() function prefix with our current client instance ID. */static inline voidset_prefix (struct multi_instance *mi){#ifdef MULTI_DEBUG_EVENT_LOOP if (mi->msg_prefix) printf ("[%s]\n", mi->msg_prefix);#endif msg_set_prefix (mi->msg_prefix);}static inline voidclear_prefix (void){#ifdef MULTI_DEBUG_EVENT_LOOP printf ("[NULL]\n");#endif msg_set_prefix (NULL);}voidgenerate_prefix (struct multi_instance *mi){ mi->msg_prefix = multi_instance_string (mi, true, &mi->gc); set_prefix (mi);}voidungenerate_prefix (struct multi_instance *mi){ mi->msg_prefix = NULL; set_prefix (mi);}/* * Tell the route helper about deleted iroutes so * that it can update its mask of currently used * CIDR netlengths. */static voidmulti_del_iroutes (struct multi_context *m, struct multi_instance *mi){ const struct iroute *ir; for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) mroute_helper_del_iroute (m->route_helper, ir);}static voidmulti_close_instance (struct multi_context *m, struct multi_instance *mi, bool shutdown){ ASSERT (!mi->halt); mi->halt = true; msg (D_MULTI_LOW, "MULTI: multi_close_instance called"); 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)); } schedule_remove_entry (m->schedule, (struct schedule_entry *) mi); ifconfig_pool_release (m->ifconfig_pool, mi->vaddr_handle); multi_del_iroutes (m, mi); mbuf_dereference_instance (m->mbuf, mi); } if (mi->context.options.client_disconnect_script) { struct gc_arena gc = gc_new (); struct buffer cmd = alloc_buf_gc (256, &gc); mutex_lock_static (L_SCRIPT); setenv_str ("script_type", "client-disconnect"); /* setenv incoming cert common name for script */ setenv_str ("common_name", tls_common_name (mi->context.c2.tls_multi, false)); /* setenv client real IP address */ setenv_trusted (get_link_socket_info (&mi->context)); buf_printf (&cmd, "%s", mi->context.options.client_disconnect_script); system_check (BSTR (&cmd), "client-disconnect command failed", false); mutex_unlock_static (L_SCRIPT); gc_free (&gc); } if (mi->did_open_context) { close_context (&mi->context, SIGTERM); } 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);}/* * Called on shutdown or restart. */static voidmulti_uninit (struct multi_context *m){ if (m->hash) { struct hash_iterator hi; struct hash_element *he; hash_iterator_init (m->iter, &hi, true); while ((he = hash_iterator_next (&hi))) { struct multi_instance *mi = (struct multi_instance *) he->value;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -