struct multi_instance * multi_get_create_instance_udp (struct multi_context *m) { struct gc_arena gc = gc_new (); struct mroute_addr real; struct multi_instance *mi = NULL; struct hash *hash = m->hash; if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true)) { struct hash_element *he; const uint32_t hv = hash_value (hash, &real); struct hash_bucket *bucket = hash_bucket (hash, hv); uint8_t* ptr = BPTR(&m->top.c2.buf); uint8_t op = ptr[0] >> P_OPCODE_SHIFT; uint32_t sess_id; bool session_forged = false; if (op == P_DATA_V2) { sess_id = (*(uint32_t*)ptr) >> 8; if ((sess_id < m->max_clients) && (m->instances[sess_id])) { mi = m->instances[sess_id]; if (!link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from)) { msg(D_MULTI_MEDIUM, "floating detected from %s to %s", print_link_socket_actual (&mi->context.c2.from, &gc), print_link_socket_actual (&m->top.c2.from, &gc)); /* session-id is not trusted, so check hmac */ session_forged = !(crypto_test_hmac(&m->top.c2.buf, &mi->context.c2.crypto_options)); if (session_forged) { mi = NULL; msg (D_MULTI_MEDIUM, "hmac verification failed, session forge detected!"); } else { update_floated(m, mi, real, hv); } } } } else {
struct multi_instance * multi_get_create_instance_udp (struct multi_context *m, bool *floated) { struct gc_arena gc = gc_new (); struct mroute_addr real; struct multi_instance *mi = NULL; struct hash *hash = m->hash; if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true) && m->top.c2.buf.len > 0) { struct hash_element *he; const uint32_t hv = hash_value (hash, &real); struct hash_bucket *bucket = hash_bucket (hash, hv); uint8_t* ptr = BPTR(&m->top.c2.buf); uint8_t op = ptr[0] >> P_OPCODE_SHIFT; /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */ if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3)) { uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFFFFFF; if ((peer_id < m->max_clients) && (m->instances[peer_id])) { mi = m->instances[peer_id]; *floated = !link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from); if (*floated) { /* reset prefix, since here we are not sure peer is the one it claims to be */ ungenerate_prefix(mi); msg (D_MULTI_ERRORS, "Untrusted peer %" PRIu32 " wants to float to %s", peer_id, mroute_addr_print (&real, &gc)); } } } else { he = hash_lookup_fast (hash, bucket, &real, hv); if (he) { mi = (struct multi_instance *) he->value; } } if (!mi) { if (!m->top.c2.tls_auth_standalone || tls_pre_decrypt_lite (m->top.c2.tls_auth_standalone, &m->top.c2.from, &m->top.c2.buf)) { if (frequency_limit_event_allowed (m->new_connection_limiter)) { mi = multi_create_instance (m, &real); if (mi) { int i; hash_add_fast (hash, bucket, &mi->real, hv, mi); mi->did_real_hash = true; for (i = 0; i < m->max_clients; ++i) { if (!m->instances[i]) { mi->context.c2.tls_multi->peer_id = i; m->instances[i] = mi; break; } } /* should not really end up here, since multi_create_instance returns null * if amount of clients exceeds max_clients */ ASSERT(i < m->max_clients); } } 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)); } } } #ifdef ENABLE_DEBUG if (check_debug_level (D_MULTI_DEBUG)) { const char *status = mi ? "[ok]" : "[failed]"; dmsg (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; }