📄 multi.c
字号:
*/static voidmulti_connection_established (struct multi_context *m, struct multi_instance *mi){ struct gc_arena gc = gc_new (); in_addr_t local=0, remote=0; const char *dynamic_config_file = NULL; bool dynamic_config_file_mark_for_delete = false; /* acquire script mutex */ mutex_lock_static (L_SCRIPT); /* 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); /* * Get a pool address, which may be released before the end * of this function if it's not needed. */ if (m->ifconfig_pool) { mi->vaddr_handle = ifconfig_pool_acquire (m->ifconfig_pool, &local, &remote, tls_common_name (mi->context.c2.tls_multi, true)); if (mi->vaddr_handle >= 0) { if (local) setenv_in_addr_t ("ifconfig_pool_local", local); if (remote) setenv_in_addr_t ("ifconfig_pool_remote", remote); } else { msg (D_MULTI_ERRORS, "MULTI: no free --ifconfig-pool addresses are available"); } } /* 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)); /* * instance-specific directives to be processed: * * iroute start-ip end-ip * ifconfig-push local remote-netmask * push */ /* * Run --client-connect script. */ if (mi->context.options.client_connect_script) { struct buffer cmd = alloc_buf_gc (256, &gc); setenv_str ("script_type", "client-connect"); dynamic_config_file = create_temp_filename (mi->context.options.tmp_dir, &gc); delete_file (dynamic_config_file); buf_printf (&cmd, "%s %s", mi->context.options.client_connect_script, dynamic_config_file); system_check (BSTR (&cmd), "client-connect command failed", false); if (test_file (dynamic_config_file)) { dynamic_config_file_mark_for_delete = true; } else { dynamic_config_file = NULL; } } /* * If client connect script was not run, or if it * was run but did not create a dynamic config file, * try to get a dynamic config file from the * --client-config-dir directory. */ if (!dynamic_config_file) { dynamic_config_file = gen_path (mi->context.options.client_config_dir, tls_common_name (mi->context.c2.tls_multi, false), &gc); if (!test_file (dynamic_config_file)) dynamic_config_file = NULL; } /* * Load the dynamic options. */ if (dynamic_config_file) { unsigned int option_types_found = 0; options_server_import (&mi->context.options, dynamic_config_file, D_IMPORT_ERRORS, OPT_P_PUSH|OPT_P_INSTANCE|OPT_P_TIMER|OPT_P_CONFIG, &option_types_found); do_deferred_options (&mi->context, option_types_found); } /* * Delete script-generated dynamic config file. */ if (dynamic_config_file && dynamic_config_file_mark_for_delete) { if (!delete_file (dynamic_config_file)) msg (D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", dynamic_config_file); } /* * 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 */ ifconfig_pool_release (m->ifconfig_pool, mi->vaddr_handle); 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; } else { if (mi->vaddr_handle >= 0) { /* use pool ifconfig address(es) */ mi->context.c2.push_ifconfig_local = remote; if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) { mi->context.c2.push_ifconfig_remote_netmask = local; mi->context.c2.push_ifconfig_defined = true; } else if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TAP) { mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->remote_netmask; mi->context.c2.push_ifconfig_defined = true; } } } /* * 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)); } /* * 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); 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, false, &gc)); } /* add routes locally, pointing to new client, if --iroute options have been specified */ multi_add_iroutes (m, mi); } 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)); } /* * Reply now to client's PUSH_REQUEST query */ mi->context.c2.push_reply_deferred = false; mutex_unlock_static (L_SCRIPT); gc_free (&gc);}/* * Compute earliest timeout expiry from the set of * all instances. Output: * * m->earliest_wakeup : instance needing the earliest service. * dest : earliest timeout as a delta in relation * to current time. */static inline voidmulti_get_timeout (struct multi_thread *mt, struct timeval *dest){ struct timeval tv, current; mt->earliest_wakeup = (struct multi_instance *) schedule_get_earliest_wakeup (mt->multi->schedule, &tv); if (mt->earliest_wakeup) { ASSERT (!gettimeofday (¤t, NULL)); tv_delta (dest, ¤t, &tv); if (dest->tv_sec >= REAP_MAX_WAKEUP) { mt->earliest_wakeup = NULL; dest->tv_sec = REAP_MAX_WAKEUP; dest->tv_usec = 0; } } else { dest->tv_sec = REAP_MAX_WAKEUP; dest->tv_usec = 0; }}/* * Add a packet to a client instance output queue. */static inline voidmulti_unicast (struct multi_context *m, const struct buffer *buf, struct multi_instance *mi){ struct mbuf_buffer *mb; if (BLEN (buf) > 0) { mb = mbuf_alloc_buf (buf); multi_add_mbuf (m, mi, mb); mbuf_free_buf (mb); }}/* * Broadcast a packet to all clients. */voidmulti_bcast (struct multi_context *m, const struct buffer *buf, struct multi_instance *omit){ struct hash_iterator hi; struct hash_element *he; struct multi_instance *mi; struct mbuf_buffer *mb; if (BLEN (buf) > 0) {#ifdef MULTI_DEBUG_EVENT_LOOP printf ("BCAST len=%d\n", BLEN (buf));#endif mb = mbuf_alloc_buf (buf); hash_iterator_init (m->iter, &hi, true); while ((he = hash_iterator_next (&hi))) { mi = (struct multi_instance *) he->value; if (mi != omit) multi_add_mbuf (m, mi, mb); } hash_iterator_free (&hi); mbuf_free_buf (mb); }}/* * Given a time delta, indicating that we wish to be * awoken by the scheduler at time now + delta, figure * a sigma parameter (in microseconds) that represents * a sort of fuzz factor around delta, so that we're * really telling the scheduler to wake us up any time * between now + delta - sigma and now + delta + sigma. * * The sigma parameter helps the scheduler to run more efficiently. * Sigma should be no larger than TV_WITHIN_SIGMA_MAX_USEC */static inline unsigned intcompute_wakeup_sigma (const struct timeval *delta){ if (delta->tv_sec < 1) { /* if < 1 sec, fuzz = # of microseconds / 8 */ return delta->tv_usec >> 3; } 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 */ }}/* * Figure instance-specific timers, convert * earliest to absolute time in mi->wakeup, * call scheduler with our future wakeup time. * * Also close context on signal. */static boolmulti_process_post (struct multi_thread *mt, struct multi_instance *mi){ if (!IS_SIG (&mi->context)) { /* figure timeouts and fetch possible outgoing to_link packets (such as ping or TLS control) */ pre_select (&mi->context); if (!IS_SIG (&mi->context)) { /* calculate an absolute wakeup time */ ASSERT (!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 (mt->multi->schedule, (struct schedule_entry *) mi, &mi->wakeup, compute_wakeup_sigma (&mi->context.c2.timeval)); /* connection is "established" when SSL/TLS key negotiation succeeds */ if (!mi->connection_established_flag && CONNECTION_ESTABLISHED (&mi->context)) { multi_connection_established (mt->multi, mi); mi->connection_established_flag = true; } } } if (IS_SIG (&mi->context)) { /* make sure that pending is nullified if it points to our soon-to-be-deleted instance */ if (mt->pending == mi) mt->pending = NULL; if (mt->earliest_wakeup == mi) mt->earliest_wakeup = NULL; multi_close_instance (mt->multi, mi, false); return false; } else { /* continue to pend on output? */ mt->pending = 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 == mt->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 return true; }}/* * Process packets in the TCP/UDP socket -> TUN/TAP interface direction, * i.e. client -> server direction. */static voidmulti_process_incoming_link (struct multi_thread *mt){ struct gc_arena gc = gc_new (); if (BLEN (&mt->top.c2.buf) > 0) { struct context *c; struct mroute_addr src, dest; unsigned int mroute_flags; struct multi_instance *mi; struct multi_context *m = mt->multi;#ifdef MULTI_DEBUG_EVENT_LOOP printf ("UDP -> TUN [%d]\n", BLEN (&mt->top.c2.buf));#endif ASSERT (!mt->pending); mt->pending = multi_get_create_instance (mt); if (!mt->pending) return; set_prefix (mt->pending); /* get instance context */ c = &mt->pending->context; /* transfer packet pointer from top-level context buffer to instance */ c->c2.buf = mt->top.c2.buf; /* transfer from-addr from top-level context buffer to instance */ c->c2.from = mt->top.c2.from; /* decrypt in instance context */ process_incoming_link (c); if (TUNNEL_TYPE (mt->top.c1.tuntap) == DEV_TYPE_TUN) { /* extract packet source and dest addresses */ mroute_flags = mroute_extract_addr_from_packet (&src, &dest, &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) != mt->pending) { msg (D_MULTI_DEBUG, "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, mt->pending); } 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_unicast (m, &c->c2.to_tun, mi); register_activity (c); c->c2.to_tun.len = 0; } } } } else if (TUNNEL_TYPE (mt->top.c1.tuntap) == DEV_TYPE_TAP) { /* extract packet source and dest addresses */ mroute_flags = mroute_extract_addr_from_packet (&src,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -