From 1d1f5d081fd63c789fa3831f6eb31c3d4c44661d Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 17 Oct 2026 23:41:51 +0200 Subject: [PATCH] test(nat): reserve fresh helper before publishing it during recheck --- tests/test_nat_detection_faults.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/test_nat_detection_faults.c b/tests/test_nat_detection_faults.c index 1146344e..4f113fc8 100644 --- a/tests/test_nat_detection_faults.c +++ b/tests/test_nat_detection_faults.c @@ -14,7 +14,7 @@ static struct { struct UTUN_INSTANCE *owner, *observer, *helper, *alias; struct ETCP_SOCKET *socket, *alias_source; enum fault_mode mode; - unsigned dropped, altered, direct_received, observations; + unsigned dropped, altered, direct_received, observations, preserved; int contacted, injected; socket_t delayed_fd; uint8_t delayed[1600]; @@ -160,6 +160,9 @@ void __wrap_nat_detection_record_observation(struct NAT_DETECTION *detector, str /* Подлинная проба приходит с локального IP, несмотря на пригодный предварительный адрес помощника. */ void __wrap_nat_detection_receive_ingress(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket, const uint8_t *key, const struct sockaddr_storage *source, const uint8_t *tag, size_t length) { + if (fault.fixture && fault.mode == FAULT_KNOWN_ALIAS && detector == fault.owner->nat_det && + !memcmp(key, fault.alias->my_keys.public_key, 32) && socket->address_profile.inbound == ADDRESS_IN_OPEN) + fault.preserved++; if (fault.fixture && fault.mode == FAULT_LOCAL_INGRESS && detector == fault.owner->nat_det && !memcmp(key, fault.alias->my_keys.public_key, 32)) { struct nat_check_status before, after; @@ -275,16 +278,16 @@ static void run_alias(const char *alias_ip, enum fault_mode mode) { do { assert(sc_generate_keypair(&next) == SC_OK); } while (sc_derive_node_id_from_pubkey(next.public_key) <= alias->node_id); struct UTUN_INSTANCE *fresh = nat_fixture_node(&fixture, "127.0.0.6", &next, NULL); - nat_detection_set_automatic(fresh->nat_det, 0); nat_fixture_connect(&fixture, observer, "udp", fresh); + nat_detection_set_automatic(fresh->nat_det, 0); fault.helper = fresh; rounds = status.rounds; assert(!nat_detection_request_check_socket(owner->nat_det, socket, observer->node_id)); - int preserved_seen = 0; end = get_time_tb() + 400000; + /* Резерв нового измерения включён до появления нового IP в топологии. */ + nat_fixture_connect(&fixture, observer, "udp", fresh); + end = get_time_tb() + 400000; do { test_clock_poll(fixture.ua, 1000); assert(!nat_detection_get_status(owner->nat_det, socket, &status)); - if (status.helper == alias->node_id && status.reason == NAT_REASON_CONTACT_HISTORY && status.cycling && - socket->address_profile.inbound == ADDRESS_IN_OPEN) preserved_seen = 1; } while (get_time_tb() < end && (status.rounds == rounds || status.phase || status.cycling)); - assert(preserved_seen && !status.phase && !status.cycling && status.helper == fresh->node_id); + assert(fault.preserved && !status.phase && !status.cycling && status.helper == fresh->node_id && !status.reason); assert(socket->address_profile.mapping == ADDRESS_MAP_UNCHANGED && socket->address_profile.inbound == ADDRESS_IN_OPEN); } fault.fixture = NULL; nat_fixture_cleanup(&fixture); @@ -402,6 +405,9 @@ static void run_budget_resume(void) { nat_fixture_connect(&fixture, owner, "udp", observer); memset(&fault, 0, sizeof(fault)); fault.fixture = &fixture; fault.owner = owner; fault.observer = observer; fault.socket = test_etcp_bound_socket(owner, "udp"); fault.mode = FAULT_BUDGET; + for (unsigned i = 2; i < fixture.node_count; i++) + assert(!etcp_send_ping_to_socket(owner, fault.socket, fixture.nodes[i]->my_keys.public_key, + &test_etcp_bound_socket(fixture.nodes[i], "udp")->local_addr, 500, ignored_ping, NULL, NULL, 0, 0)); assert(!nat_detection_request_check_socket(owner->nat_det, fault.socket, observer->node_id)); struct nat_check_status status = {0}; uint64_t end = get_time_tb() + 500000; do { test_clock_poll(fixture.ua, 1000); assert(!nat_detection_get_status(owner->nat_det, fault.socket, &status)); } @@ -421,10 +427,13 @@ static void run_budget_resume(void) { assert(fault.socket->address_profile.inbound == ADDRESS_IN_UNKNOWN); fault.mode = FAULT_NONE; fault.delayed_length = 0; end = get_time_tb() + 700000; do { test_clock_poll(fixture.ua, 1000); assert(!nat_detection_get_status(owner->nat_det, fault.socket, &status)); } + while (get_time_tb() < end && status.round == paused_round); + assert(status.round != paused_round && status.helper == paused_helper && status.helper_reselections == completed_pairs); + do { test_clock_poll(fixture.ua, 1000); assert(!nat_detection_get_status(owner->nat_det, fault.socket, &status)); } while (get_time_tb() < end && status.cycling); assert(!status.phase && !status.cycling && status.round != paused_round && status.helper == paused_helper); - assert(status.helper_reselections == completed_pairs && fault.socket->address_profile.mapping == ADDRESS_MAP_UNCHANGED && - fault.socket->address_profile.inbound == ADDRESS_IN_OPEN); + assert(status.helper_reselections == completed_pairs + 1 && fault.socket->address_profile.mapping == ADDRESS_MAP_UNCHANGED && + fault.socket->address_profile.inbound == ADDRESS_IN_UNKNOWN && status.reason == NAT_REASON_CONTACT_HISTORY); fault.fixture = NULL; nat_fixture_cleanup(&fixture); DEBUG_INFO(DEBUG_CATEGORY_NAT, "PASS NAT budget pause retains mapping, rejects late ingress and retries the unfinished pair"); }