nat: remove TCP listener probes from endpoint detection
This commit is contained in:
1 parent
6363c8b7ea
commit
5c0db6ce9e
1 file changed
+28
-78
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user