tests: verify STUN estimates and ETCP promotion in isolated networks
This commit is contained in:
1 parent
8983026625
commit
7a40ba536e
2 files changed
+25
-12
No files matched your search
@@ -32,9 +32,11 @@ python3 tests/stream_netns/run.py --stun-only --output /tmp/stun-interface-netns
|
||||
По очереди проверяются n03 (cone), n14 (restricted) и n05 (dependent mapping).
|
||||
Два рабочих порта одного IP/netif используют одну STUN-пробу. Сначала у владельца
|
||||
нет ETCP-пиров, затем появляется один наблюдатель, затем независимый помощник.
|
||||
Проверяются source=NONE до измерения рабочего порта и source=ETCP после него;
|
||||
STUN остаётся отдельной диагностикой. Тестовый внешний порт не попадает в рекламу
|
||||
рабочего сокета. JOIN/стриминг в этом режиме не запускаются.
|
||||
Для EIM сначала проверяется предварительный source=STUN с inbound=UNKNOWN,
|
||||
после измерения рабочего порта — source=ETCP с проверенной доступностью входящих.
|
||||
Зависимый STUN-mapping не назначает предварительный EIM?. Один наблюдатель сохраняет
|
||||
рабочий внешний адрес; тестовый внешний порт не попадает в рекламу рабочего сокета.
|
||||
JOIN/стриминг в этом режиме не запускаются.
|
||||
Случайные тестовые порты получают тот же класс NAT; правила для рабочего 32000 сохраняются.
|
||||
Для испытания случайных портов активен один клиент каждого выбранного NAT-шлюза.
|
||||
Расширенная классификация restricted/dependent включает реальные таймауты CHANGE,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""STUN другого порта остаётся диагностикой; рабочий профиль назначает независимый ETCP-раунд."""
|
||||
"""STUN даёт предварительный EIM? того же IP/netif; ETCP уточняет профиль рабочего порта."""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
@@ -51,9 +51,14 @@ def check_stun(scenario):
|
||||
expected_filtering = {"EIF"} if inbound == "OPEN" else {"ADF", "APDF"}
|
||||
if udp["stun"]["mapping"] not in expected_mapping or udp["stun"]["filtering"] not in expected_filtering:
|
||||
raise RuntimeError(f"{owner_name}: STUN diagnostic class mismatch: {udp}")
|
||||
if any(item["source"] != "NONE" or item["mapping"] != "UNKNOWN" or item["inbound"] != "UNKNOWN"
|
||||
for item in (udp, duplicate)):
|
||||
raise RuntimeError(f"{owner_name}: STUN diagnostics changed a working endpoint: {udp}, {duplicate}")
|
||||
estimated = mapping == "EIM"
|
||||
expected_source, expected_map = ("STUN", "EIM") if estimated else ("NONE", "UNKNOWN")
|
||||
data = scenario.wait(f"stun-tentative-{owner_name}", lambda statistics:
|
||||
all((profile(statistics[owner_name], name)["source"],
|
||||
profile(statistics[owner_name], name)["mapping"],
|
||||
profile(statistics[owner_name], name)["inbound"]) ==
|
||||
(expected_source, expected_map, "UNKNOWN") for name in ("udp", "duplicate")), 5)
|
||||
udp, duplicate = profile(data[owner_name], "udp"), profile(data[owner_name], "duplicate")
|
||||
if udp["stun"]["evidence"] != duplicate["stun"]["evidence"] or udp["stun"]["members"] != 2 or udp["external"]:
|
||||
raise RuntimeError(f"{owner_name}: duplicated probe or foreign external port: {udp}, {duplicate}")
|
||||
for name in (observer_name,):
|
||||
@@ -66,8 +71,12 @@ def check_stun(scenario):
|
||||
agents[owner_name].rpc("nat_check", socket="udp", observer=agents[observer_name].identity)
|
||||
data = scenario.wait(f"stun-no-helper-{owner_name}", lambda statistics:
|
||||
profile(statistics[owner_name], "udp")["reason"] == "no_helper", 40)
|
||||
if profile(data[owner_name], "udp")["source"] != "NONE":
|
||||
raise RuntimeError(f"{owner_name}: single observer assigned an unmeasured endpoint profile")
|
||||
partial = profile(data[owner_name], "udp")
|
||||
expected_source = "STUN" if estimated else "ETCP"
|
||||
if (partial["source"], partial["mapping"], partial["inbound"]) != (expected_source, expected_map, "UNKNOWN"):
|
||||
raise RuntimeError(f"{owner_name}: single-observer profile mismatch: {partial}")
|
||||
if not partial["external"]:
|
||||
raise RuntimeError(f"{owner_name}: single observer did not preserve working external address")
|
||||
agents[helper_name] = Agent(network, nodes[helper_name], Path(scenario.args.binary).resolve(), scenario.args.seed,
|
||||
False, False, True)
|
||||
agents[observer_name].rpc("nat_link", snapshot=agents[helper_name].rpc("snapshot")["snapshot"], socket="udp")
|
||||
@@ -75,10 +84,12 @@ def check_stun(scenario):
|
||||
agents[helper_name].identity in statistics[observer_name]["group_ready"] and
|
||||
agents[observer_name].identity in statistics[helper_name]["group_ready"], 20)
|
||||
agents[owner_name].rpc("nat_check", socket="udp", observer=agents[observer_name].identity)
|
||||
data = scenario.wait(f"stun-etcp-promotion-{owner_name}", lambda statistics:
|
||||
profile(statistics[owner_name], "udp")["source"] == "ETCP", 40)
|
||||
measured = profile(data[owner_name], "udp")
|
||||
expected = ("DEPENDENT", "UNKNOWN") if gateway.mode == "strict" else (mapping, inbound)
|
||||
data = scenario.wait(f"stun-etcp-promotion-{owner_name}", lambda statistics:
|
||||
(profile(statistics[owner_name], "udp")["source"],
|
||||
profile(statistics[owner_name], "udp")["mapping"],
|
||||
profile(statistics[owner_name], "udp")["inbound"]) == ("ETCP", *expected), 40)
|
||||
measured = profile(data[owner_name], "udp")
|
||||
if (measured["mapping"], measured["inbound"]) != expected:
|
||||
raise RuntimeError(f"{owner_name}: ETCP class mismatch: {measured}")
|
||||
verified[owner_name] = {"stun": udp, "etcp": measured}
|
||||
|
||||
Reference in new issue
Block a user