Browse Source

Wait for complete NAT cycles and test an indirect private helper

master
evgeny 7 days ago
parent
commit
ceab874abc
  1. 16
      tests/stream_netns/nat_scenario.py
  2. 4
      tests/stream_netns/node.c
  3. 4
      tests/test_stun_nat.c

16
tests/stream_netns/nat_scenario.py

@ -34,7 +34,8 @@ def check_profiles(scenario):
agents[owner.name].rpc("nat_check", socket=protocol, observer=agents[observer.name].identity)
data = scenario.wait(f"nat-profile-{owner.name}-{protocol}", lambda statistics:
profile(statistics[owner.name], protocol)["rounds"] > before["rounds"] and
profile(statistics[owner.name], protocol)["phase"] == 0, 40)
profile(statistics[owner.name], protocol)["phase"] == 0 and
not profile(statistics[owner.name], protocol)["cycling"], 40)
return profile(data[owner.name], protocol)
# Отсутствие второго наблюдателя не превращается в STRICT/DIRECT.
@ -45,6 +46,19 @@ def check_profiles(scenario):
if (incomplete["mapping"], incomplete["inbound"], incomplete["reason"]) != ("UNKNOWN", "UNKNOWN", "no_helper"):
raise RuntimeError(f"NAT no-helper test: {incomplete}")
# Третий узел за NAT появляется через B: A не имеет ни линка, ни прежнего UDP-контакта с C.
private_helper = next(node for node in NODES if node.nat)
agents[first.name].rpc("nat_auto", enabled=1)
connect(private_helper, second)
data = scenario.wait("nat-routed-private-helper", lambda statistics:
(profile(statistics[first.name], "udp")["mapping"],
profile(statistics[first.name], "udp")["inbound"]) == ("UNCHANGED", "OPEN"), 40)
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

4
tests/stream_netns/node.c

@ -200,9 +200,9 @@ static void statistics(struct lab *lab, uint64_t id, int loads) {
json_string(sockaddr_storage_to_str(&stun.local).str); printf("}");
}
printf(",\"phase\":%u,\"reason\":\"%s\",\"group\":\"%" PRIu64 "\",\"observer\":\"%" PRIu64 "\",\"helper\":\"%" PRIu64 "\","
"\"rounds\":%u,\"helper_reselections\":%u,\"history_complete\":%u,\"contacts\":[", status.phase,
"\"rounds\":%u,\"helper_reselections\":%u,\"cycling\":%u,\"history_complete\":%u,\"contacts\":[", status.phase,
nat_check_reason_name(status.reason), status.group_id, status.observer, status.helper, status.rounds,
status.helper_reselections, status.history_complete);
status.helper_reselections, status.cycling, status.history_complete);
uint8_t local[ROUTE_ADDR_WIRE_SIZE]; sqlite3_stmt *contacts = NULL; int contact_separator = 0;
if (!socket->is_tcp && !route_ping_addr_encode(local, &socket->local_addr) &&
sqlite3_prepare_v2(lab->inst->topo_sqlite_db, "SELECT remote FROM nat_contacts WHERE local=?",

4
tests/test_stun_nat.c

@ -416,8 +416,8 @@ static void test_fallback(void) {
assert(!memcmp(&socket->address_profile, &measured, sizeof(measured)));
nat_detection_request_check_all(owner->nat_det); end = get_time_tb() + 300000;
do { test_clock_poll(nf.ua, 10000); assert(!nat_detection_get_status(owner->nat_det, socket, &status)); }
while (get_time_tb() < end && (status.round == round || status.phase));
assert(status.round != round && !status.phase);
while (get_time_tb() < end && (status.round == round || status.phase || status.cycling));
assert(status.round != round && !status.phase && !status.cycling);
assert(!memcmp(&socket->address_profile, &measured, sizeof(measured)));
/* Прошедшие пять минут не сбрасывают последний успешный ETCP. */
uint64_t timestamp = snapshot->timestamp;

Loading…
Cancel
Save