From 5c0db6ce9e3232b2d6cdf41905d5ba99c4a2a78b Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 17 Oct 2026 19:47:37 +0200 Subject: [PATCH] nat: remove TCP listener probes from endpoint detection --- src/routing_layer/nat_detection.c | 106 ++++++++---------------------- 1 file changed, 28 insertions(+), 78 deletions(-) diff --git a/src/routing_layer/nat_detection.c b/src/routing_layer/nat_detection.c index 8ab56c95..2e83b47d 100644 --- a/src/routing_layer/nat_detection.c +++ b/src/routing_layer/nat_detection.c @@ -15,7 +15,6 @@ #include "topo_group.h" #include "etcp_router.h" #include "route_crypto.h" -#include "stcp_client.h" #include "stun_nat.h" #include "sock_match.h" #include "../lib/debug_config.h" @@ -36,8 +35,8 @@ enum nat_command { NAT_RUN = 1, NAT_RESULT, NAT_RECHECK, NAT_OBSERVATION }; enum nat_phase { NAT_IDLE, NAT_OBSERVE_B, NAT_PREPARE_C, NAT_PRE, NAT_OBSERVE_C, - NAT_POST, NAT_REPEAT_B, NAT_REPEAT_C, NAT_PRE_WAIT, NAT_POST_WAIT, NAT_TCP }; -enum nat_step { NAT_STEP_PREPARE = 1, NAT_STEP_PRE, NAT_STEP_POST, NAT_STEP_TCP, NAT_STEP_HELPER_OBSERVE = 128 }; + NAT_POST, NAT_REPEAT_B, NAT_REPEAT_C, NAT_PRE_WAIT, NAT_POST_WAIT }; +enum nat_step { NAT_STEP_PREPARE = 1, NAT_STEP_PRE, NAT_STEP_POST, NAT_STEP_HELPER_OBSERVE = 128 }; /* Только байты: формат независим от alignment/endian платформы. */ struct nat_wire { @@ -88,7 +87,6 @@ struct nat_probe { uint64_t group_id, reply, source_generation, io_generation, due, expires; uint8_t owner_key[32], observer_key[32]; uint8_t source_socket, io_socket, active, cancelled, finding_primary; - struct stcp_client *tcp; }; struct NAT_DETECTION { @@ -485,7 +483,7 @@ static int make_message(struct nat_socket *state, struct nat_wire *message, uint write64(message->owner, state->detector->instance->node_id); write64(message->generation, state->socket->generation); write64(message->round, state->round); write64(message->helper, state->helper); write64(message->observer, state->observer); write64(message->token, state->token); - if (route_ping_addr_encode(message->target, state->socket->is_tcp ? &state->local : &state->baseline)) return -1; + if (route_ping_addr_encode(message->target, &state->baseline)) return -1; if (state->helper_address.ss_family && route_ping_addr_encode(message->primary, &state->helper_address)) return -1; if (state->observer_address.ss_family && route_ping_addr_encode(message->observer_address, &state->observer_address)) return -1; int timeout = probe_timeout_ms(state); @@ -706,7 +704,7 @@ static int owner_run(struct nat_socket *state, uint8_t step) { struct nat_wire message; if (make_message(state, &message, NAT_RUN)) return -1; message.step = step; - state->phase = step == NAT_STEP_TCP ? NAT_TCP : step == NAT_STEP_PREPARE ? NAT_PREPARE_C : + state->phase = step == NAT_STEP_PREPARE ? NAT_PREPARE_C : step == NAT_STEP_PRE ? NAT_PRE : NAT_POST; uint64_t budget = (uint64_t)probe_timeout_ms(state) * 10 * (step == NAT_STEP_PREPARE ? 2 * NAT_PROBE_COUNT + 2 : NAT_PROBE_COUNT + 2); @@ -914,7 +912,6 @@ static void helper_remove(struct nat_probe *probe) { if (*cursor) *cursor = probe->next; probe->cancelled = 1; etcp_cancel_pings(detector->instance, helper_ping_cb, probe); - if (probe->tcp) { struct stcp_client *tcp = probe->tcp; probe->tcp = NULL; stcp_client_destroy(tcp); } u_free(probe); } @@ -943,7 +940,7 @@ static void helper_ping_cb(int success, uint16_t rtt, void *arg, uint64_t nonce, (void)rtt; (void)nonce; struct nat_probe *probe = arg; if (probe->cancelled) return; - probe->active = 0; probe->tcp = NULL; + probe->active = 0; uint8_t step = probe->message.step; if (step == NAT_STEP_PREPARE && probe->finding_primary) { struct ETCP_SOCKET *socket = find_socket(probe->detector, probe->io_socket, probe->io_generation); @@ -959,9 +956,6 @@ static void helper_ping_cb(int success, uint16_t rtt, void *arg, uint64_t nonce, } if (success) { helper_finish(probe, NAT_REASON_INVALID_OBSERVATION); return; } if (probe->message.sent >= NAT_PROBE_COUNT) { helper_finish(probe, NAT_REASON_TIMEOUT); return; } - } else if (step == NAT_STEP_TCP) { - if (success) probe->message.received++; - helper_finish(probe, success ? NAT_REASON_NONE : NAT_REASON_TIMEOUT); return; } else { if (success) DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT one-way ingress unexpectedly received PONG group=%016llx step=%u", (unsigned long long)probe->group_id, step); @@ -984,14 +978,7 @@ static int helper_send(struct nat_probe *probe) { DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT helper has invalid timeout_ms=%d", timeout); return -1; } int result; - if (probe->message.step == NAT_STEP_TCP) { - struct reality_client_config reality, *camouflage = NULL; - const struct TOPO_NODE *owner = topo_node_registry_find(detector->instance->topo_groups, read64(probe->message.owner)); - const struct TOPO_REALITY_SOCK *parameters = topo_node_find_reality_sock(owner, probe->message.owner_socket); - if (parameters) { topo_node_reality_config(&reality, parameters); camouflage = &reality; } - result = etcp_send_tcp_ping(detector->instance, probe->owner_key, &target, timeout, - helper_ping_cb, probe, &probe->tcp, camouflage); - } else if (probe->message.step == NAT_STEP_PREPARE && probe->finding_primary) { + if (probe->message.step == NAT_STEP_PREPARE && probe->finding_primary) { struct ETCP_SOCKET *source = find_socket(detector, probe->source_socket, probe->source_generation); if (!source) { DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT helper source generation disappeared"); return -1; } struct ETCP_SOCKET *socket = helper_socket(detector, source); @@ -1017,24 +1004,6 @@ static int helper_send(struct nat_probe *probe) { probe->message.sent++; probe->active = 1; return 0; } -static int tcp_target_advertised(struct NAT_DETECTION *detector, uint64_t group_id, const struct nat_wire *message, - const struct sockaddr_storage *target) { - const struct TOPO_NODE *owner = group_node(detector, group_id, read64(message->owner)); - if (!owner) return 0; - uint8_t address[ROUTE_ADDR_WIRE_SIZE]; - if (route_ping_addr_encode(address, target)) return 0; - if (target->ss_family == AF_INET) { - for (const struct TOPO_ADDR4 *item = owner->v4_addrs; item; item = item->next) - if (item->socket_id == message->owner_socket && (item->protocol & TOPO_PROTO_TCP) && - !memcmp(item->addr, address + 1, 4) && item->port == (((unsigned)address[17] << 8) | address[18])) return 1; - } else { - for (const struct TOPO_ADDR6 *item = owner->v6_addrs; item; item = item->next) - if (item->socket_id == message->owner_socket && (item->protocol & TOPO_PROTO_TCP) && - !memcmp(item->addr, address + 1, 16) && item->port == (((unsigned)address[17] << 8) | address[18])) return 1; - } - return 0; -} - /* Broker проверяет реальное наблюдение owner, затем делегирует выбранному владельцем помощнику через ту же группу. */ static void handle_run(struct NAT_DETECTION *detector, uint64_t group_id, uint64_t sender, struct nat_wire *message) { uint64_t owner = read64(message->owner), observer = read64(message->observer), helper = read64(message->helper); @@ -1049,15 +1018,13 @@ static void handle_run(struct NAT_DETECTION *detector, uint64_t group_id, uint64 (unsigned long long)helper); goto reject; } if (sender == owner && observer == detector->instance->node_id) { - if (message->step != NAT_STEP_TCP) { - struct nat_binding *binding = binding_find(detector, group_id, owner, read64(message->generation), read64(message->round)); - if (!binding || binding->owner_socket != message->owner_socket || !route_ping_addr_equal(&binding->target, &target, 1) || - memcmp(binding->owner_key, owner_node->public_key, 32) || helper == observer) { - DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT delegation rejected: stale own observation group=%016llx owner=%016llx", - (unsigned long long)group_id, (unsigned long long)owner); goto reject; - } - binding->helper = helper; binding->token = read64(message->token); binding->expires = get_time_tb() + NAT_ROUND_TB; + struct nat_binding *binding = binding_find(detector, group_id, owner, read64(message->generation), read64(message->round)); + if (!binding || binding->owner_socket != message->owner_socket || !route_ping_addr_equal(&binding->target, &target, 1) || + memcmp(binding->owner_key, owner_node->public_key, 32) || helper == observer) { + DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT delegation rejected: stale own observation group=%016llx owner=%016llx", + (unsigned long long)group_id, (unsigned long long)owner); goto reject; } + binding->helper = helper; binding->token = read64(message->token); binding->expires = get_time_tb() + NAT_ROUND_TB; if (helper != detector->instance->node_id) { if (!control_route(detector, group_id, helper) || send_control(detector, group_id, helper, message)) { DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT delegation route failed group=%016llx helper=%016llx", @@ -1071,10 +1038,6 @@ static void handle_run(struct NAT_DETECTION *detector, uint64_t group_id, uint64 (unsigned long long)group_id, (unsigned long long)sender, (unsigned long long)observer, (unsigned long long)helper); goto reject; } - if (message->step == NAT_STEP_TCP && (helper != observer || !tcp_target_advertised(detector, group_id, message, &target))) { - DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT TCP target is not the signed owner listener group=%016llx", (unsigned long long)group_id); - goto reject; - } unsigned count = 0; for (struct nat_probe *probe = detector->probes; probe; probe = probe->next) { count++; @@ -1085,25 +1048,22 @@ static void handle_run(struct NAT_DETECTION *detector, uint64_t group_id, uint64 } } if (count >= NAT_MAX_PROBES) { DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT helper probe limit reached"); reason = NAT_REASON_SEND_ERROR; goto reject; } - struct ETCP_SOCKET *source = NULL; - if (message->step != NAT_STEP_TCP) { - struct sockaddr_storage observer_address; - source = find_socket(detector, message->helper_socket, 0); - if (!source || source->is_tcp || source->probe_only || source->socks_udp || - source->type == CFG_SERVER_TYPE_PRIVATE || source->type == CFG_SERVER_TYPE_LOCAL || - source->local_addr.ss_family != target.ss_family || - route_ping_addr_decode(message->observer_address, &observer_address) || - observer_address.ss_family != target.ss_family || !public_address(detector, &observer_address)) { - DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT helper source is not a native socket group=%016llx socket=%u", - (unsigned long long)group_id, message->helper_socket); - reason = source && source->socks_udp ? NAT_REASON_PROXY : NAT_REASON_NO_HELPER; goto reject; - } + struct sockaddr_storage observer_address; + struct ETCP_SOCKET *source = find_socket(detector, message->helper_socket, 0); + if (!source || source->is_tcp || source->probe_only || source->socks_udp || + source->type == CFG_SERVER_TYPE_PRIVATE || source->type == CFG_SERVER_TYPE_LOCAL || + source->local_addr.ss_family != target.ss_family || + route_ping_addr_decode(message->observer_address, &observer_address) || + observer_address.ss_family != target.ss_family || !public_address(detector, &observer_address)) { + DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT helper source is not a native socket group=%016llx socket=%u", + (unsigned long long)group_id, message->helper_socket); + reason = source && source->socks_udp ? NAT_REASON_PROXY : NAT_REASON_NO_HELPER; goto reject; } struct nat_probe *probe = u_calloc(1, sizeof(*probe)); if (!probe) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT helper probe allocation failed"); reason = NAT_REASON_SEND_ERROR; goto reject; } probe->detector = detector; probe->message = *message; probe->group_id = group_id; probe->reply = sender; memcpy(probe->owner_key, owner_node->public_key, 32); memcpy(probe->observer_key, observer_node->public_key, 32); - if (source) { probe->source_socket = source->sock_id; probe->source_generation = source->generation; } + probe->source_socket = source->sock_id; probe->source_generation = source->generation; probe->expires = get_time_tb() + NAT_ROUND_TB; probe->next = detector->probes; detector->probes = probe; if (helper_send(probe)) helper_finish(probe, NAT_REASON_SEND_ERROR); @@ -1115,18 +1075,13 @@ reject: static void handle_result(struct nat_socket *state, const struct nat_wire *message) { uint8_t step = state->phase == NAT_PRE ? NAT_STEP_PRE : state->phase == NAT_POST ? NAT_STEP_POST : - state->phase == NAT_TCP ? NAT_STEP_TCP : state->phase == NAT_PREPARE_C ? NAT_STEP_PREPARE : 0; + state->phase == NAT_PREPARE_C ? NAT_STEP_PREPARE : 0; if (!step || message->step != step || read64(message->token) != state->token || read64(message->helper) != state->helper) { DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT stale helper result ignored socket=%s phase=%u", state->socket->name, state->phase); return; } if (message->reason || message->errors || !message->sent || message->received > message->sent) { owner_finish(state, message->reason ? message->reason : NAT_REASON_SEND_ERROR); return; } - if (step == NAT_STEP_TCP) { - if (message->received) owner_apply(state, ADDRESS_MAP_UNCHANGED, ADDRESS_IN_OPEN); - else owner_finish(state, NAT_REASON_TIMEOUT); - return; - } if (step == NAT_STEP_PREPARE) { struct sockaddr_storage primary; if (route_ping_addr_decode(message->primary, &primary) || primary.ss_family != state->local.ss_family || @@ -1259,7 +1214,7 @@ static void receive_control(struct ETCP_CONN *from, struct ll_entry *entry) { !read64(message.generation) || !read64(message.round) || !read64(message.token) || (message.command != NAT_RUN && message.command != NAT_RESULT && message.command != NAT_OBSERVATION) || message.reason > NAT_REASON_DEPENDENT_MAPPING || - (message.command != NAT_OBSERVATION && (message.step < NAT_STEP_PREPARE || message.step > NAT_STEP_TCP))) { + (message.command != NAT_OBSERVATION && (message.step < NAT_STEP_PREPARE || message.step > NAT_STEP_POST))) { DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT control malformed command=%u version=%u step=%u", message.command, message.version, message.step); return; } @@ -1318,13 +1273,8 @@ static void owner_start(struct nat_socket *state) { state->socket->name, (unsigned long long)state->group_id, state->socket->sock_id, (unsigned long long)state->socket->generation, (unsigned long long)state->round, (unsigned long long)state->observer, (unsigned long long)state->helper, state->socket->is_tcp ? "TCP" : "UDP"); - if (state->socket->is_tcp) { - state->baseline = state->local; - if (owner_run(state, NAT_STEP_TCP)) owner_finish(state, NAT_REASON_CONTROL_LOST); - } else { - state->phase = NAT_OBSERVE_B; - if (owner_observe(state)) owner_finish(state, NAT_REASON_SEND_ERROR); - } + state->phase = NAT_OBSERVE_B; + if (owner_observe(state)) owner_finish(state, NAT_REASON_SEND_ERROR); } static void detector_tick(void *arg) { @@ -1708,7 +1658,7 @@ struct NAT_DETECTION *nat_detection_create(struct UTUN_INSTANCE *instance) { etcp_router_unbind(instance, ETCP_RT_ID_NAT_DETECTION); u_free(detector); DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT detector initial timer failed"); return NULL; } - DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT endpoint detector started: UDP mapping/inbound measured separately, TCP listener probes"); + DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT endpoint detector started: UDP mapping/inbound, TCP IP-only presence with port=0"); return detector; }