📄 multi.c
字号:
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); m->hash = NULL; 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); }}/* * Create a client instance object for a newly connected client. */static struct multi_instance *multi_create_instance (struct multi_thread *mt, const struct mroute_addr *real){ struct gc_arena gc = gc_new (); struct multi_instance *mi; ALLOC_OBJ_CLEAR (mi, struct multi_instance); msg (D_MULTI_LOW, "MULTI: multi_create_instance called"); mi->gc = gc_new (); multi_instance_inc_refcount (mi); mroute_addr_init (&mi->real); mi->vaddr_handle = -1; mi->created = now; mi->real = *real; generate_prefix (mi); if (!hash_add (mt->multi->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; } mi->did_iter = true; inherit_context_child (&mi->context, &mt->top); mi->did_open_context = true; mi->context.c2.push_reply_deferred = true; if (!multi_process_post (mt, mi)) { msg (D_MULTI_ERRORS, "MULTI: signal occurred during client instance initialization"); goto err; } gc_free (&gc); return mi; err: multi_close_instance (mt->multi, mi, false); gc_free (&gc); return NULL;}/* * Get a client instance based on real address. If * the instance doesn't exist, create it while * maintaining real address hash table atomicity. */static struct multi_instance *multi_get_create_instance (struct multi_thread *mt){ struct gc_arena gc = gc_new (); struct mroute_addr real; struct multi_instance *mi = NULL; struct hash *hash = mt->multi->hash; if (mroute_extract_sockaddr_in (&real, &mt->top.c2.from, true)) { struct hash_element *he; const uint32_t hv = hash_value (hash, &real); struct hash_bucket *bucket = hash_bucket (hash, hv); hash_bucket_lock (bucket); he = hash_lookup_fast (hash, bucket, &real, hv); if (he) { mi = (struct multi_instance *) he->value; } else { if (!mt->top.c2.tls_auth_standalone || tls_pre_decrypt_lite (mt->top.c2.tls_auth_standalone, &mt->top.c2.from, &mt->top.c2.buf)) { if (frequency_limit_event_allowed (mt->multi->new_connection_limiter)) { mi = multi_create_instance (mt, &real); if (mi) { hash_add_fast (hash, bucket, &mi->real, hv, mi); mi->did_real_hash = true; } } else { msg (D_MULTI_ERRORS, "MULTI: Connection from %s would exceed new connection frequency limit as controlled by --connect-freq", mroute_addr_print (&real, &gc)); } } } hash_bucket_unlock (bucket);#ifdef MULTI_DEBUG if (check_debug_level (D_MULTI_DEBUG)) { const char *status; if (he && mi) status = "[succeeded]"; else if (!he && mi) status = "[created]"; else status = "[failed]"; msg (D_MULTI_DEBUG, "GET INST BY REAL: %s %s", mroute_addr_print (&real, &gc), status); }#endif } gc_free (&gc); ASSERT (!(mi && mi->halt)); return mi;}/* * Dump tables -- triggered by SIGUSR2. * If status file is defined, write to file. * If status file is NULL, write to syslog. */static voidmulti_print_status (struct multi_context *m, struct status_output *so){ if (m->hash) { struct gc_arena gc_top = gc_new (); struct hash_iterator hi; const struct hash_element *he; status_reset (so); status_printf (so, PACKAGE_NAME " 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, true); 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, true); 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"); status_printf (so, "Max bcast/mcast queue length,%d", mbuf_maximum_queued (m->mbuf)); status_printf (so, "END"); status_flush (so); gc_free (&gc_top); }}/* * Learn a virtual address or route. */static voidmulti_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; hash_bucket_lock (bucket); he = hash_lookup_fast (m->vhash, bucket, addr, hv); if (he) oldroute = (struct multi_route *) he->value; /* do we need to add address to hash table? */ if ((!oldroute || oldroute->instance != mi || !multi_route_defined (m, oldroute)) && mroute_learnable_address (addr) && !mroute_addr_equal (addr, &m->local)) { struct gc_arena gc = gc_new (); struct multi_route *newroute; 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; multi_instance_inc_refcount (mi); if (oldroute) /* route already exists? */ { /* delete old route */ multi_route_del (oldroute); /* modify hash table entry, replacing old route */ he->key = &newroute->addr; he->value = newroute; learn_address_script (m, mi, "update", &newroute->addr); } else { /* add new route */ hash_add_fast (m->vhash, bucket, &newroute->addr, hv, newroute); learn_address_script (m, mi, "add", &newroute->addr); } msg (D_MULTI_LOW, "MULTI: Learn: %s -> %s", mroute_addr_print (&newroute->addr, &gc), multi_instance_string (mi, false, &gc)); gc_free (&gc); } hash_bucket_unlock (bucket);}/* * 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){ struct multi_route *route; struct multi_instance *ret = NULL; /* check for local address */ if (mroute_addr_equal (addr, &m->local)) return NULL; route = (struct multi_route *) hash_lookup (m->vhash, addr); /* 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; } 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; mroute_helper_lock (rh); /* 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; } } mroute_helper_unlock (rh); } #ifdef MULTI_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) { msg (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 { msg (D_MULTI_DEBUG, "GET INST BY VIRT: %s [failed]", addr_text); } gc_free (&gc); }#endif ASSERT (!(ret && ret->halt)); return ret;}/* * Helper function to multi_learn_addr(). */static voidmulti_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 */{ struct sockaddr_in remote_si; struct mroute_addr addr; CLEAR (remote_si); remote_si.sin_family = AF_INET; remote_si.sin_addr.s_addr = htonl (a); ASSERT (mroute_extract_sockaddr_in (&addr, &remote_si, false)); if (netbits >= 0) { addr.type |= MR_WITH_NETBITS; addr.netbits = (uint8_t) netbits; } multi_learn_addr (m, mi, &addr, 0);}/* * A new client has connected, add routes (server -> client) * to internal routing table. */static voidmulti_add_iroutes (struct multi_context *m, struct multi_instance *mi){ struct gc_arena gc = gc_new (); const struct iroute *ir; 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, false, &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, false, &gc), multi_instance_string (mi, false, &gc)); mroute_helper_add_iroute (m->route_helper, ir); multi_learn_in_addr_t (m, mi, ir->network, ir->netbits); } gc_free (&gc);}/* * Given an instance (new_mi), delete all other instances which use the * same common name. */static voidmulti_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; hash_iterator_init (m->iter, &hi, true); while ((he = hash_iterator_next (&hi))) { struct multi_instance *mi = (struct multi_instance *) he->value; if (mi != new_mi) { 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); } } } hash_iterator_free (&hi); } }}/* * Called as soon as the SSL/TLS connection authenticates.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -