nat: reject local probe sources and preserve internet profiles on LAN

This commit is contained in:
evgeny committed 2026-10-17 16:54:07 +02:00
1 parent 308eb07742
commit 83efa229ed
3 files changed
+112 -18

No files matched your search

+40 -13
View File
@@ -517,6 +517,21 @@ void nat_detection_record_observation(struct NAT_DETECTION *detector, struct ETC
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT observation has invalid group/identity group=%016llx owner=%016llx",
(unsigned long long)group_id, (unsigned long long)owner); return;
}
int eligible = public_address(detector, source);
if (!eligible) DEBUG_WARN(DEBUG_CATEGORY_NAT,
"NAT observation rejected by receiver group=%016llx owner=%016llx round=%016llx source=%s reason=non_public_source",
(unsigned long long)group_id, (unsigned long long)owner, (unsigned long long)round, sockaddr_storage_to_str(source).str);
if (length == NAT_QUERY_TAG_SIZE) {
struct nat_wire report = {.command = NAT_OBSERVATION, .owner_socket = tag[8], .step = tag[ROUTE_OBSERVE_TAG_SIZE],
.reason = eligible ? NAT_REASON_NONE : NAT_REASON_INVALID_OBSERVATION};
write64(report.owner, owner); write64(report.generation, generation); write64(report.round, round);
write64(report.token, read64(tag + ROUTE_OBSERVE_TAG_SIZE + 1));
write64(report.observer, detector->instance->node_id); write64(report.helper, detector->instance->node_id);
if (route_ping_addr_encode(report.target, source) || send_control(detector, group_id, owner, &report))
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT routed observation delivery failed group=%016llx owner=%016llx round=%016llx",
(unsigned long long)group_id, (unsigned long long)owner, (unsigned long long)round);
}
if (!eligible) return;
struct nat_binding *binding = binding_find(detector, group_id, owner, generation, round);
if (!binding) {
unsigned count = 0;
@@ -532,15 +547,6 @@ void nat_detection_record_observation(struct NAT_DETECTION *detector, struct ETC
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT observation group=%016llx owner=%016llx socket=%u generation=%016llx round=%016llx observed=%s via=%s",
(unsigned long long)group_id, (unsigned long long)owner, tag[8], (unsigned long long)generation, (unsigned long long)round,
sockaddr_storage_to_str(source).str, socket->name);
if (length == NAT_QUERY_TAG_SIZE) {
struct nat_wire report = {.command = NAT_OBSERVATION, .owner_socket = tag[8], .step = tag[ROUTE_OBSERVE_TAG_SIZE]};
write64(report.owner, owner); write64(report.generation, generation); write64(report.round, round);
write64(report.token, read64(tag + ROUTE_OBSERVE_TAG_SIZE + 1));
write64(report.observer, detector->instance->node_id); write64(report.helper, detector->instance->node_id);
if (route_ping_addr_encode(report.target, source) || send_control(detector, group_id, owner, &report))
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT routed observation delivery failed group=%016llx owner=%016llx round=%016llx",
(unsigned long long)group_id, (unsigned long long)owner, (unsigned long long)round);
}
}
static void clear_profile(struct nat_socket *state, uint8_t reason) {
@@ -669,7 +675,8 @@ static void owner_heartbeat_cb(int success, uint16_t rtt, void *arg, uint64_t no
struct nat_socket *state = arg; state->heartbeat_active = 0;
if (!state->phase) return;
struct sockaddr_storage observed;
if (success && !route_ping_observation(data, length, state->socket, state->group_id, state->round, &observed)) {
if (success && !route_ping_observation(data, length, state->socket, state->group_id, state->round, &observed) &&
public_address(state->detector, &observed)) {
if (state->baseline.ss_family && !route_ping_addr_equal(&state->baseline, &observed, 1)) {
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT anchor mapping changed socket=%s round=%016llx previous=%s current=%s",
state->socket->name, (unsigned long long)state->round,
@@ -697,6 +704,11 @@ static void owner_ping_cb(int success, uint16_t rtt, void *arg, uint64_t nonce,
if (++state->retries < NAT_PROBE_COUNT) { state->due = get_time_tb() + 1000; return; }
owner_finish(state, success ? NAT_REASON_INVALID_OBSERVATION : NAT_REASON_TIMEOUT); return;
}
if (!public_address(state->detector, &observed)) {
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT observation unusable socket=%s phase=%u round=%016llx observed=%s reason=non_public_source",
state->socket->name, state->phase, (unsigned long long)state->round, sockaddr_storage_to_str(&observed).str);
owner_finish(state, NAT_REASON_INVALID_OBSERVATION); return;
}
state->retries = 0;
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT own observation socket=%s phase=%u round=%016llx observed=%s",
state->socket->name, state->phase, (unsigned long long)state->round, sockaddr_storage_to_str(&observed).str);
@@ -757,11 +769,20 @@ void nat_detection_receive_ingress(struct NAT_DETECTION *detector, struct ETCP_S
if (!step || memcmp(tag, expected, sizeof(expected)) || tag[ROUTE_OBSERVE_TAG_SIZE] != step ||
read64(tag + ROUTE_OBSERVE_TAG_SIZE + 1) != state->token ||
sc_derive_node_id_from_pubkey(peer_key) != state->helper || memcmp(peer_key, state->helper_key, 32) ||
source->ss_family != state->local.ss_family || !public_address(detector, source) ||
((step == NAT_STEP_POST || state->pre_received) && !route_ping_addr_equal(source, &state->helper_address, 1))) {
source->ss_family != state->local.ss_family) {
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT ingress correlation/source mismatch socket=%s phase=%u round=%016llx source=%s",
socket->name, state->phase, (unsigned long long)state->round, sockaddr_storage_to_str(source).str); return;
}
if (!public_address(detector, source)) {
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT helper rejected by receiver socket=%s round=%016llx helper=%016llx source=%s reason=non_public_source",
socket->name, (unsigned long long)state->round, (unsigned long long)state->helper, sockaddr_storage_to_str(source).str);
owner_finish(state, NAT_REASON_NO_HELPER); return;
}
if ((step == NAT_STEP_POST || state->pre_received) && !route_ping_addr_equal(source, &state->helper_address, 1)) {
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT ingress endpoint mismatch socket=%s phase=%u round=%016llx source=%s expected=%s",
socket->name, state->phase, (unsigned long long)state->round,
sockaddr_storage_to_str(source).str, sockaddr_storage_to_str(&state->helper_address).str); return;
}
if (route_ping_addr_equal(source, &state->observer_address, 0) || route_ping_addr_equal(source, &state->baseline, 0)) {
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT helper rejected by receiver socket=%s round=%016llx helper=%016llx source=%s reason=%s",
socket->name, (unsigned long long)state->round, (unsigned long long)state->helper,
@@ -859,7 +880,7 @@ static void helper_ping_cb(int success, uint16_t rtt, void *arg, uint64_t nonce,
struct ETCP_SOCKET *socket = find_socket(probe->detector, probe->io_socket, probe->io_generation);
struct sockaddr_storage mapped;
if (success && socket && !route_ping_observation(data, length, socket, probe->group_id,
read64(probe->message.round), &mapped)) {
read64(probe->message.round), &mapped) && public_address(probe->detector, &mapped)) {
if (route_ping_addr_encode(probe->message.primary, &mapped)) { helper_finish(probe, NAT_REASON_INVALID_OBSERVATION); return; }
probe->message.received++;
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT helper endpoint measured group=%016llx owner=%016llx step=%u socket=%s mapped=%s fallback=%u",
@@ -1089,6 +1110,7 @@ static void receive_observation(struct NAT_DETECTION *detector, uint64_t group,
probe->io_generation != socket->generation || read64(probe->message.round) != read64(message->round) ||
read64(probe->message.token) != read64(message->token) || read64(probe->message.observer) != sender) continue;
etcp_cancel_pings(detector->instance, helper_ping_cb, probe);
if (message->reason) { helper_finish(probe, message->reason); return; }
helper_ping_cb(1, 0, probe, 0, data, sizeof(data)); return;
}
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT stale helper observation report ignored"); return;
@@ -1101,6 +1123,7 @@ static void receive_observation(struct NAT_DETECTION *detector, uint64_t group,
(unsigned long long)group, (unsigned long long)sender, message->step); return;
}
etcp_cancel_pings(detector->instance, owner_ping_cb, state);
if (message->reason) { owner_finish(state, message->reason); return; }
owner_ping_cb(1, 0, state, 0, data, sizeof(data));
}
@@ -1514,6 +1537,10 @@ void nat_detection_link_ready(struct NAT_DETECTION *detector, struct ETCP_LINK *
void nat_detection_observed_by_peer(struct NAT_DETECTION *detector, struct ETCP_LINK *link,
const struct sockaddr_storage *observed) {
if (!detector || !link || !link->conn || link->is_tcp || link->conn->socks_udp || !observed->ss_family) return;
if (!public_address(detector, observed)) {
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT ignores LAN observation socket=%s peer=%016llx observed=%s",
link->conn->name, (unsigned long long)link->etcp->peer_node_id, sockaddr_storage_to_str(observed).str); return;
}
struct nat_socket *state = socket_state(detector, link->conn, 1);
if (!state) return;
if ((state->measured_profile.mapping == ADDRESS_MAP_UNCHANGED &&