From c7be1ebbbebb44b4e4a7b86c3c62336d7605ad34 Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 12 Oct 2026 20:43:39 +0200 Subject: [PATCH] Preserve cold NAT trials in the real network fixture --- src/routing_layer/nat_detection.c | 1 + tests/stream_netns/nat_scenario.py | 8 +++++--- .../src/main/java/com/utun/chat/data/ChatRepository.kt | 2 +- .../com/utun/chat/ui/screens/MemberAddressFormatTest.kt | 2 ++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/routing_layer/nat_detection.c b/src/routing_layer/nat_detection.c index 77f4fb1f..05e4844b 100644 --- a/src/routing_layer/nat_detection.c +++ b/src/routing_layer/nat_detection.c @@ -1367,6 +1367,7 @@ void nat_detection_connection_failed(struct NAT_DETECTION *detector, struct ETCP struct ll_entry *packet = ll_alloc_lldgram(1 + sizeof(request)); if (!packet) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT failure recheck allocation failed"); break; } packet->dgram[0] = ETCP_RT_ID_NAT_DETECTION; memcpy(packet->dgram + 1, &request, sizeof(request)); + packet->len = 1 + sizeof(request); if (etcp_route_send(detector->instance, group->group_id, connection->peer_node_id, packet, 0, ROUTE_CRYPTO_SIGN | ROUTE_CRYPTO_ENCRYPT)) DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT failure recheck forwarding failed group=%016llx peer=%016llx", diff --git a/tests/stream_netns/nat_scenario.py b/tests/stream_netns/nat_scenario.py index c13b86fc..a4c597ca 100644 --- a/tests/stream_netns/nat_scenario.py +++ b/tests/stream_netns/nat_scenario.py @@ -14,6 +14,9 @@ def check_profiles(scenario): public = [node for node in NODES if not node.nat] transport = "tcp" if scenario.args.tcp_only else "udp" connected = set() + # Первый профиль измеряется при появлении маршрутов, до фонового обхода всех NODEINFO. + for agent in agents.values(): + agent.rpc("nat_auto", enabled=1) def connect(source, target): pair = (source.name, target.name) @@ -56,13 +59,13 @@ def check_profiles(scenario): actual = profile(data[first.name], "udp") if actual["helper"] != agents[private_helper.name].identity or agents[private_helper.name].identity in data[first.name]["direct_up"]: raise RuntimeError(f"NAT indirect private helper was not used: {actual}") - agents[first.name].rpc("nat_auto", enabled=0) print(f"NAT routed private helper: {private_helper.name} through {second.name}, group={actual['group']}", flush=True) verified = {} for owner in public + [node for node in NODES if node.nat]: observer = second if owner.name == first.name else first - agents[owner.name].rpc("nat_auto", enabled=1) + if not scenario.args.tcp_only: + agents[owner.name].rpc("nat_check", socket="udp", observer=agents[observer.name].identity) if not scenario.args.tcp_only: contacts = set(profile(agents[owner.name].rpc("stats"), "udp")["contacts"]) helper = next((node for node in public if node.name not in {owner.name, observer.name} and node.ip not in contacts), None) @@ -104,7 +107,6 @@ def check_profiles(scenario): print(f"NAT {owner.name}/{protocol}: {actual['mapping']} / {actual['inbound']}" f" external={actual['external'] or '-'} reason={actual['reason']}", flush=True) verified[owner.name] = observed - agents[owner.name].rpc("nat_auto", enabled=0) (scenario.network.directory / "nat-profiles.json").write_text(json.dumps(verified, indent=2) + "\n") # Повтор на использовавшемся порту сохраняет mapping, но не обновляет OPEN diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/ChatRepository.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/ChatRepository.kt index 68885c07..61a41d20 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/ChatRepository.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/ChatRepository.kt @@ -102,7 +102,7 @@ data class MemberAddr(val family: Int = 0, val protocol: String = "", val addres val port: Int = 0, val socketId: Int = 0, val addrType: Int = 0, val rtt: Int = 0) { val roleLabelRes: Int get() = when (addrType) { 0 -> R.string.address_local; 1 -> R.string.address_public - 2 -> R.string.address_nat_eim; 3 -> R.string.address_nat_dependent; 4 -> R.string.address_nat + 2 -> R.string.address_nat_eim; 3 -> R.string.address_nat_dependent 5 -> R.string.address_contact; else -> R.string.address_unknown } } diff --git a/tools/chatgui-android/app/src/test/java/com/utun/chat/ui/screens/MemberAddressFormatTest.kt b/tools/chatgui-android/app/src/test/java/com/utun/chat/ui/screens/MemberAddressFormatTest.kt index dad0aef0..4ace1654 100644 --- a/tools/chatgui-android/app/src/test/java/com/utun/chat/ui/screens/MemberAddressFormatTest.kt +++ b/tools/chatgui-android/app/src/test/java/com/utun/chat/ui/screens/MemberAddressFormatTest.kt @@ -16,6 +16,8 @@ class MemberAddressFormatTest { @Test fun contactRequiredIsDistinctFromPublicAndNat() { assertEquals(R.string.address_public, MemberAddr(addrType = 1).roleLabelRes) assertEquals(R.string.address_nat_eim, MemberAddr(addrType = 2).roleLabelRes) + assertEquals(R.string.address_nat_dependent, MemberAddr(addrType = 3).roleLabelRes) + assertEquals(R.string.address_unknown, MemberAddr(addrType = 4).roleLabelRes) assertEquals(R.string.address_contact, MemberAddr(addrType = 5).roleLabelRes) assertEquals(R.string.address_unknown, MemberAddr(addrType = 6).roleLabelRes) }