tests: finish cold UDP detection before opening additional TCP links
This commit is contained in:
1 parent
d2a8e6fda7
commit
2513e9ae81
1 file changed
+44
-39
@@ -64,7 +64,11 @@ def check_profiles(scenario):
|
||||
print(f"NAT routed private helper: {private_helper.name} through {second.name}, group={actual['group']}", flush=True)
|
||||
|
||||
verified = {}
|
||||
protocols = ["tcp"] if scenario.args.tcp_only else ["udp", "tcp"] if scenario.args.tcp else ["udp"]
|
||||
for owner in public + [node for node in NODES if node.nat]:
|
||||
verified[owner.name] = {}
|
||||
if scenario.args.tcp_only:
|
||||
continue
|
||||
observer = second if owner.name == first.name else first
|
||||
if not scenario.args.tcp_only:
|
||||
agents[owner.name].rpc("nat_check", socket="udp", observer=agents[observer.name].identity)
|
||||
@@ -80,45 +84,46 @@ def check_profiles(scenario):
|
||||
connect(observer, helper)
|
||||
connect(owner, observer)
|
||||
store_owner(owner, observer)
|
||||
protocols = ["tcp"] if scenario.args.tcp_only else ["udp", "tcp"] if scenario.args.tcp else ["udp"]
|
||||
observed = {}
|
||||
for protocol in protocols:
|
||||
if protocol == "tcp":
|
||||
# Только один действующий TCP-пир, без испытания входящих и без сравнения портов.
|
||||
connect(owner, observer, "tcp")
|
||||
data = scenario.wait(f"nat-tcp-ip-{owner.name}", lambda statistics:
|
||||
profile(statistics[owner.name], "tcp")["source"] == "ETCP" and
|
||||
bool(profile(statistics[owner.name], "tcp")["external"]), 10)
|
||||
actual = profile(data[owner.name], "tcp")
|
||||
expected = ("UNKNOWN" if owner.nat else "UNCHANGED", "UNKNOWN")
|
||||
if actual["rounds"] or int(actual["helper"]):
|
||||
raise RuntimeError(f"{owner.name}: TCP IP detection unexpectedly used a helper round: {actual}")
|
||||
else:
|
||||
actual = measure(owner, observer, protocol)
|
||||
if not owner.nat:
|
||||
expected = ("UNCHANGED", "OPEN")
|
||||
else:
|
||||
gateway = next(item for item in NATS if item.name == owner.nat)
|
||||
expected = {"cone": ("EIM", "OPEN"), "restricted": ("EIM", "CONTACT_REQUIRED"),
|
||||
"strict": ("DEPENDENT", "UNKNOWN")}[gateway.mode]
|
||||
if (actual["mapping"], actual["inbound"]) != expected:
|
||||
raise RuntimeError(f"{owner.name}/{protocol}: expected {expected}, detector returned {actual}")
|
||||
if protocol == "tcp":
|
||||
ip = next(item for item in NATS if item.name == owner.nat).ip if owner.nat else owner.ip
|
||||
external = f"{ip}:0"
|
||||
elif expected[0] == "EIM":
|
||||
gateway = next(item for item in NATS if item.name == owner.nat)
|
||||
external = f"{gateway.ip}:{owner.mapped_port}"
|
||||
elif expected[0] == "UNCHANGED":
|
||||
external = f"{owner.ip}:32000"
|
||||
else:
|
||||
external = ""
|
||||
if actual["external"] != external:
|
||||
raise RuntimeError(f"{owner.name}/{protocol}: foreign/invalid external endpoint: {actual}, expected {external}")
|
||||
observed[protocol] = actual
|
||||
print(f"NAT {owner.name}/{protocol}: {actual['mapping']} / {actual['inbound']}"
|
||||
f" external={actual['external'] or '-'} reason={actual['reason']}", flush=True)
|
||||
verified[owner.name] = observed
|
||||
actual = measure(owner, observer, "udp")
|
||||
if not owner.nat:
|
||||
expected = ("UNCHANGED", "OPEN")
|
||||
else:
|
||||
gateway = next(item for item in NATS if item.name == owner.nat)
|
||||
expected = {"cone": ("EIM", "OPEN"), "restricted": ("EIM", "CONTACT_REQUIRED"),
|
||||
"strict": ("DEPENDENT", "UNKNOWN")}[gateway.mode]
|
||||
if (actual["mapping"], actual["inbound"]) != expected:
|
||||
raise RuntimeError(f"{owner.name}/udp: expected {expected}, detector returned {actual}")
|
||||
if expected[0] == "EIM":
|
||||
gateway = next(item for item in NATS if item.name == owner.nat)
|
||||
external = f"{gateway.ip}:{owner.mapped_port}"
|
||||
elif expected[0] == "UNCHANGED":
|
||||
external = f"{owner.ip}:32000"
|
||||
else:
|
||||
external = ""
|
||||
if actual["external"] != external:
|
||||
raise RuntimeError(f"{owner.name}/udp: foreign/invalid external endpoint: {actual}, expected {external}")
|
||||
verified[owner.name]["udp"] = actual
|
||||
print(f"NAT {owner.name}/udp: {actual['mapping']} / {actual['inbound']}"
|
||||
f" external={actual['external'] or '-'} reason={actual['reason']}", flush=True)
|
||||
(scenario.network.directory / "nat-profiles.json").write_text(json.dumps(verified, indent=2) + "\n")
|
||||
|
||||
# Дополнительные TCP-линки создаются после холодных UDP-измерений: NCD может запустить и UDP-попытки.
|
||||
if "tcp" in protocols:
|
||||
for owner in public + [node for node in NODES if node.nat]:
|
||||
observer = second if owner.name == first.name else first
|
||||
connect(owner, observer, "tcp")
|
||||
data = scenario.wait(f"nat-tcp-ip-{owner.name}", lambda statistics:
|
||||
profile(statistics[owner.name], "tcp")["source"] == "ETCP" and
|
||||
bool(profile(statistics[owner.name], "tcp")["external"]), 10)
|
||||
actual = profile(data[owner.name], "tcp")
|
||||
expected = ("UNKNOWN" if owner.nat else "UNCHANGED", "UNKNOWN")
|
||||
ip = next(item for item in NATS if item.name == owner.nat).ip if owner.nat else owner.ip
|
||||
if (actual["mapping"], actual["inbound"], actual["external"]) != (*expected, f"{ip}:0"):
|
||||
raise RuntimeError(f"{owner.name}/tcp: expected {expected}, IP={ip}:0, detector returned {actual}")
|
||||
if actual["rounds"] or int(actual["helper"]):
|
||||
raise RuntimeError(f"{owner.name}: TCP IP detection unexpectedly used a helper round: {actual}")
|
||||
verified[owner.name]["tcp"] = actual
|
||||
print(f"NAT {owner.name}/tcp: {actual['mapping']} / {actual['inbound']} external={actual['external']}", flush=True)
|
||||
(scenario.network.directory / "nat-profiles.json").write_text(json.dumps(verified, indent=2) + "\n")
|
||||
|
||||
# Повтор на использовавшемся порту сохраняет mapping, но не обновляет OPEN
|
||||
|
||||
Reference in new issue
Block a user