nat: prefer fresh public helpers while retaining known mapping candidates
This commit is contained in:
1 parent
3c321ac59c
commit
bbb8cff4a6
2 files changed
+24
-30
No files matched your search
@@ -48,7 +48,7 @@ struct nat_wire {
|
||||
|
||||
struct nat_pair {
|
||||
uint64_t group, observer, helper;
|
||||
uint8_t helper_priority; /* Сначала публичный endpoint C, затем приватный, затем один наблюдатель. */
|
||||
uint8_t helper_priority; /* Публичные IP: свежий/знакомый; затем приватные: свежий/знакомый; затем один B. */
|
||||
uint8_t observer_endpoint[ROUTE_ADDR_WIRE_SIZE], helper_endpoint[ROUTE_ADDR_WIRE_SIZE];
|
||||
};
|
||||
struct nat_recheck_wire { uint8_t cmd, command, version, socket_id, address[ROUTE_ADDR_WIRE_SIZE]; };
|
||||
@@ -65,11 +65,11 @@ struct nat_socket {
|
||||
uint8_t observer_key[32], helper_key[32];
|
||||
uint64_t group_id, round, observer, helper, token, observation_token, deadline, due, completed_tb, preferred_observer;
|
||||
uint64_t cycle_deadline, heartbeat_due, heartbeat_received, pre_started;
|
||||
struct nat_pair cursor, fallback;
|
||||
struct nat_pair cursor;
|
||||
uint8_t contacts[NAT_MAX_CONTACTS][17];
|
||||
unsigned contact_count, contact_cutoff, phase, reason, retries;
|
||||
uint8_t history_loaded, history_complete, history_incomplete, filter_clean, pre_received, post_received, pre_healthy;
|
||||
uint8_t helper_socket, active_ping, heartbeat_active, forced, cycling, using_fallback, prefer_fresh;
|
||||
uint8_t helper_socket, active_ping, heartbeat_active, forced, cycling;
|
||||
uint32_t rounds, helper_reselections;
|
||||
};
|
||||
|
||||
@@ -258,7 +258,7 @@ static int select_pair(struct nat_socket *state) {
|
||||
node_udp_endpoint(detector, bn, state->local.ss_family, 0, previous_b, &ba, &bs)) {
|
||||
if (!state->socket->is_tcp && route_ping_addr_encode(previous_b, &ba)) break;
|
||||
observers++;
|
||||
struct nat_pair observer_only = {.group = group->group_id, .observer = observer, .helper_priority = 2};
|
||||
struct nat_pair observer_only = {.group = group->group_id, .observer = observer, .helper_priority = 4};
|
||||
memcpy(observer_only.observer_endpoint, previous_b, sizeof(previous_b));
|
||||
if (!state->socket->is_tcp && pair_after(observer_only, state->cursor) &&
|
||||
(!single.group || pair_after(single, observer_only))) {
|
||||
@@ -275,13 +275,10 @@ static int select_pair(struct nat_socket *state) {
|
||||
node_udp_endpoint(detector, cn, state->local.ss_family, 1, previous_c, &ca, &cs)) {
|
||||
if (!state->socket->is_tcp && route_ping_addr_encode(previous_c, &ca)) break;
|
||||
struct nat_pair candidate = {.group = group->group_id, .observer = observer, .helper = helper,
|
||||
.helper_priority = !public_address(detector, &ca)};
|
||||
.helper_priority = state->socket->is_tcp ? 0 : 2 * !public_address(detector, &ca) + contacted(state, &ca)};
|
||||
memcpy(candidate.observer_endpoint, previous_b, sizeof(previous_b));
|
||||
memcpy(candidate.helper_endpoint, previous_c, sizeof(previous_c));
|
||||
if (state->using_fallback) {
|
||||
if (pair_after(candidate, state->fallback) || pair_after(state->fallback, candidate)) continue;
|
||||
} else if (!pair_after(candidate, state->cursor)) continue;
|
||||
if (!state->socket->is_tcp && state->prefer_fresh && !state->using_fallback && contacted(state, &ca)) continue;
|
||||
if (!pair_after(candidate, state->cursor)) continue;
|
||||
if (best.group && !pair_after(best, candidate)) continue;
|
||||
best = candidate; observer_address = ba; helper_address = ca; helper_socket = cs;
|
||||
memcpy(observer_key, bn->public_key, 32); memcpy(helper_key, cn->public_key, 32);
|
||||
@@ -290,27 +287,23 @@ static int select_pair(struct nat_socket *state) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!best.group && single.group && !state->using_fallback && !state->prefer_fresh) {
|
||||
if (!best.group && single.group) {
|
||||
best = single; observer_address = single_address; memcpy(observer_key, single_key, 32);
|
||||
}
|
||||
if (!best.group) {
|
||||
if (state->prefer_fresh && !state->using_fallback) {
|
||||
state->prefer_fresh = 0; state->cursor = (struct nat_pair){0}; return select_pair(state);
|
||||
}
|
||||
if (!state->using_fallback && state->fallback.group) { state->using_fallback = 1; return select_pair(state); }
|
||||
state->reason = observers ? NAT_REASON_NO_HELPER : NAT_REASON_NO_OBSERVER;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT candidate cycle exhausted socket=%s groups=%u observers=%u reason=%s",
|
||||
state->socket->name, groups, observers, nat_check_reason_name(state->reason));
|
||||
return -1;
|
||||
}
|
||||
if (!state->using_fallback) state->cursor = best;
|
||||
state->cursor = best;
|
||||
state->group_id = best.group; state->observer = best.observer; state->helper = best.helper;
|
||||
state->observer_address = observer_address; state->helper_address = helper_address; state->helper_socket = helper_socket;
|
||||
memcpy(state->observer_key, observer_key, 32); memcpy(state->helper_key, helper_key, 32);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT candidates socket=%s group=%016llx observer=%016llx endpoint=%s helper=%016llx candidate=%s fallback=%u",
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT candidates socket=%s group=%016llx observer=%016llx endpoint=%s helper=%016llx candidate=%s priority=%u",
|
||||
state->socket->name, (unsigned long long)best.group, (unsigned long long)best.observer,
|
||||
sockaddr_storage_to_str(&observer_address).str, (unsigned long long)best.helper,
|
||||
sockaddr_storage_to_str(&helper_address).str, state->using_fallback);
|
||||
sockaddr_storage_to_str(&helper_address).str, best.helper_priority);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -634,7 +627,7 @@ static void owner_finish(struct nat_socket *state, uint8_t reason) {
|
||||
if (owner_observe(state)) owner_finish(state, NAT_REASON_SEND_ERROR);
|
||||
return;
|
||||
}
|
||||
int next_pair = reason && state->phase && state->cycling && !state->using_fallback &&
|
||||
int next_pair = reason && state->phase && state->cycling &&
|
||||
reason != NAT_REASON_CANCELLED && reason != NAT_REASON_ADDRESS_CHANGED;
|
||||
etcp_cancel_pings(state->detector->instance, owner_ping_cb, state);
|
||||
etcp_cancel_pings(state->detector->instance, owner_heartbeat_cb, state);
|
||||
@@ -647,8 +640,7 @@ static void owner_finish(struct nat_socket *state, uint8_t reason) {
|
||||
if (next_pair) {
|
||||
state->forced = 1; state->due = get_time_tb() + 1000; state->helper_reselections++;
|
||||
} else {
|
||||
state->cycling = 0; state->using_fallback = 0; state->preferred_observer = 0;
|
||||
state->cursor = (struct nat_pair){0}; state->fallback = (struct nat_pair){0};
|
||||
state->cycling = 0; state->preferred_observer = 0; state->cursor = (struct nat_pair){0};
|
||||
int complete = state->measured_profile.mapping == ADDRESS_MAP_DEPENDENT ||
|
||||
(state->measured_profile.mapping && state->measured_profile.inbound);
|
||||
state->due = get_time_tb() + (reason == NAT_REASON_ADDRESS_CHANGED ? 2500 : complete ? NAT_REFRESH_TB : NAT_RETRY_TB);
|
||||
@@ -845,8 +837,7 @@ void nat_detection_receive_ingress(struct NAT_DETECTION *detector, struct ETCP_S
|
||||
}
|
||||
if (step == NAT_STEP_PRE || step == NAT_STEP_PREPARE) {
|
||||
if (!state->pre_received) {
|
||||
if (contacted(state, source) && !state->using_fallback) {
|
||||
if (!state->fallback.group) state->fallback = state->cursor;
|
||||
if (contacted(state, source)) {
|
||||
state->helper_address = *source; state->filter_clean = 0;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT helper rejected by receiver socket=%s round=%016llx source=%s reason=previous_udp_contact",
|
||||
socket->name, (unsigned long long)state->round, sockaddr_storage_to_str(source).str);
|
||||
@@ -1131,7 +1122,7 @@ static void handle_result(struct nat_socket *state, const struct nat_wire *messa
|
||||
if (old_contact) DEBUG_INFO(DEBUG_CATEGORY_NAT,
|
||||
"NAT known helper used for mapping only socket=%s round=%016llx helper=%s",
|
||||
state->socket->name, (unsigned long long)state->round, sockaddr_storage_to_str(&primary).str);
|
||||
if (state->pre_received || old_contact || state->using_fallback) {
|
||||
if (state->pre_received || old_contact) {
|
||||
state->phase = NAT_OBSERVE_C;
|
||||
if (owner_observe(state)) owner_finish(state, NAT_REASON_SEND_ERROR);
|
||||
return;
|
||||
@@ -1289,8 +1280,7 @@ static void owner_start(struct nat_socket *state) {
|
||||
state->socket->name, sockaddr_storage_to_str(&state->local).str); return;
|
||||
}
|
||||
if (!state->cycling) {
|
||||
state->cycling = 1; state->cursor = (struct nat_pair){0}; state->fallback = (struct nat_pair){0};
|
||||
state->using_fallback = 0; state->prefer_fresh = state->measured_profile.mapping != ADDRESS_MAP_UNKNOWN;
|
||||
state->cycling = 1; state->cursor = (struct nat_pair){0};
|
||||
state->cycle_deadline = get_time_tb() + NAT_ROUND_TB;
|
||||
}
|
||||
history_load(state);
|
||||
@@ -1489,7 +1479,7 @@ static void topology_wake(void *arg) {
|
||||
if (!changed || !fingerprint || !detector->automatic || state->cycling) continue;
|
||||
if (state->measured_profile.source == ADDRESS_SOURCE_ETCP && state->measured_profile.mapping && state->measured_profile.inbound)
|
||||
continue;
|
||||
state->cursor = (struct nat_pair){0}; state->fallback = (struct nat_pair){0}; state->using_fallback = 0;
|
||||
state->cursor = (struct nat_pair){0};
|
||||
state->due = get_time_tb() + 2500;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT available candidates changed socket=%s; early measurement scheduled", state->socket->name);
|
||||
}
|
||||
@@ -1506,7 +1496,6 @@ void nat_detection_topology_changed(struct NAT_DETECTION *detector) {
|
||||
void nat_detection_cancel_group(struct NAT_DETECTION *detector, uint64_t group_id) {
|
||||
if (!detector || detector->stopping) return;
|
||||
for (struct nat_socket *state = detector->sockets; state; state = state->next) {
|
||||
if (state->fallback.group == group_id) state->fallback = (struct nat_pair){0};
|
||||
if (state->group_id != group_id || (!state->phase && !state->cycling)) continue;
|
||||
owner_finish(state, NAT_REASON_CANCELLED); state->forced = 0; state->group_id = 0; state->due = get_time_tb() + 2500;
|
||||
}
|
||||
@@ -1700,7 +1689,7 @@ void nat_detection_request_check_all(struct NAT_DETECTION *detector) {
|
||||
struct nat_socket *state = socket_state(detector, socket, 1);
|
||||
if (!state) continue;
|
||||
if (state->phase) owner_finish(state, NAT_REASON_CANCELLED);
|
||||
state->cycling = 0; state->cursor = (struct nat_pair){0}; state->fallback = (struct nat_pair){0}; state->using_fallback = 0;
|
||||
state->cycling = 0; state->cursor = (struct nat_pair){0};
|
||||
state->due = get_time_tb(); state->forced = 1; state->preferred_observer = 0;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT endpoint recheck requested");
|
||||
@@ -1712,7 +1701,7 @@ int nat_detection_request_check_socket(struct NAT_DETECTION *detector, struct ET
|
||||
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT endpoint recheck has invalid endpoint/observer"); return -1;
|
||||
}
|
||||
if (state->phase) owner_finish(state, NAT_REASON_CANCELLED);
|
||||
state->cycling = 0; state->cursor = (struct nat_pair){0}; state->fallback = (struct nat_pair){0}; state->using_fallback = 0;
|
||||
state->cycling = 0; state->cursor = (struct nat_pair){0};
|
||||
state->preferred_observer = observer; state->due = get_time_tb(); state->forced = 1;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT endpoint recheck socket=%s observer=%016llx", socket->name, (unsigned long long)observer);
|
||||
return 0;
|
||||
|
||||
@@ -66,7 +66,7 @@ static int check_addresses(const char *channel) {
|
||||
char value[128];
|
||||
REQUIRE(json && !extract(json, "$.adr[0].ad", value, sizeof(value)) && !strcmp(value, "194.63.142.140"));
|
||||
REQUIRE(!extract(json, "$.adr[0].po", value, sizeof(value)) && !strcmp(value, "1333"));
|
||||
REQUIRE(!extract(json, "$.adr[0].at", value, sizeof(value)) && !strcmp(value, "4"));
|
||||
REQUIRE(!extract(json, "$.adr[0].at", value, sizeof(value)) && !strcmp(value, "0")); /* адрес интерфейса, не NAT */
|
||||
REQUIRE(!extract(json, "$.adr[0].pt", value, sizeof(value)) && !strcmp(value, "UDP"));
|
||||
REQUIRE(!extract(json, "$.adr[0].si", value, sizeof(value)) && !strcmp(value, "5"));
|
||||
REQUIRE(!extract(json, "$.adr[1].ad", value, sizeof(value)) && !strcmp(value, "2a04:5200::f"));
|
||||
@@ -74,6 +74,11 @@ static int check_addresses(const char *channel) {
|
||||
REQUIRE(!extract(json, "$.adr[1].pt", value, sizeof(value)) && !strcmp(value, "TCP"));
|
||||
REQUIRE(!extract(json, "$.adr[1].po", value, sizeof(value)) && !strcmp(value, "443"));
|
||||
REQUIRE(!extract(json, "$.adr[1].si", value, sizeof(value)) && !strcmp(value, "6"));
|
||||
u_free(json);
|
||||
addr4.type = TOPO_ADDR_NAT; meta4.address_profile.source = ADDRESS_SOURCE_ETCP;
|
||||
REQUIRE(!topo_node_sqlite_addrs_put(instance->topo_sqlite_db, instance->node_id, &node));
|
||||
json = utun_bridge_get_member_detail_json(channel, instance->node_id);
|
||||
REQUIRE(json && !extract(json, "$.adr[0].at", value, sizeof(value)) && !strcmp(value, "4")); /* NAT, тип неизвестен */
|
||||
u_free(json); return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user