Browse Source

Keep STUN round diagnostics separate from published NAT profiles

master
evgeny 7 days ago
parent
commit
89f031f4f9
  1. 8
      tests/stream_netns/node.c
  2. 2
      tests/stream_netns/stun_scenario.py
  3. 22
      tests/test_stun_nat.c

8
tests/stream_netns/node.c

@ -186,9 +186,8 @@ static void statistics(struct lab *lab, uint64_t id, int loads) {
socket->sock_id, socket->generation, socket->is_tcp ? "tcp" : "udp");
json_string(sockaddr_storage_to_str(socket->is_tcp ? &socket->interface_addr : &socket->local_addr).str);
printf(",\"source\":\"%s\"", address_profile_source_name(socket->address_profile.source));
printf(",\"mapping\":\"%s\",\"inbound\":\"%s\",\"evidence\":\"%" PRIu64 "\",\"checked_at\":\"%" PRIu64 "\",\"external\":",
address_mapping_name(socket->address_profile.mapping), address_inbound_name(socket->address_profile.inbound),
socket->address_profile.evidence_id, socket->address_profile.checked_at);
printf(",\"mapping\":\"%s\",\"inbound\":\"%s\",\"external\":",
address_mapping_name(socket->address_profile.mapping), address_inbound_name(socket->address_profile.inbound));
const struct sockaddr_storage *external = &socket->nat_addr;
if (!external->ss_family && socket->address_profile.mapping == ADDRESS_MAP_UNCHANGED &&
socket->address_profile.source == ADDRESS_SOURCE_ETCP)
@ -196,7 +195,8 @@ static void statistics(struct lab *lab, uint64_t id, int loads) {
json_string(external->ss_family ? sockaddr_storage_to_str(external).str : "");
struct stun_nat_result stun;
if (!stun_nat_get_socket_result(lab->inst, socket, &stun)) {
printf(",\"stun\":{\"members\":%u,\"generation\":\"%" PRIu64 "\",\"test_local\":", stun.members, stun.generation);
printf(",\"stun\":{\"members\":%u,\"generation\":\"%" PRIu64 "\",\"evidence\":\"%" PRIu64 "\",\"test_local\":",
stun.members, stun.generation, stun.evidence_id);
json_string(sockaddr_storage_to_str(&stun.local).str); printf("}");
}
printf(",\"phase\":%u,\"reason\":\"%s\",\"observer\":\"%" PRIu64 "\",\"helper\":\"%" PRIu64 "\","

2
tests/stream_netns/stun_scenario.py

@ -48,7 +48,7 @@ def check_stun(scenario):
udp, duplicate = profile(data[owner_name], "udp"), profile(data[owner_name], "duplicate")
if (udp["mapping"], udp["inbound"]) != (mapping, inbound):
raise RuntimeError(f"{owner_name}: STUN class mismatch: {udp}")
if udp["evidence"] != duplicate["evidence"] or udp["stun"]["members"] != 2 or udp["external"]:
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,):
agents[name] = Agent(network, nodes[name], Path(scenario.args.binary).resolve(), scenario.args.seed,

22
tests/test_stun_nat.c

@ -163,8 +163,6 @@ static void fixture_init(struct fixture* f) {
f->source.address_profile.mapping = ADDRESS_MAP_DEPENDENT;
f->source.address_profile.inbound = ADDRESS_IN_CONTACT;
f->source.address_profile.source = ADDRESS_SOURCE_ETCP;
f->source.address_profile.evidence_id = 1;
f->source.address_profile.checked_at = 1;
f->source.nat_addr = f->source.local_addr;
snprintf(f->source.name, sizeof(f->source.name), "source");
f->inst.etcp_sockets = &f->source;
@ -388,7 +386,7 @@ static void test_fallback(void) {
struct ETCP_SOCKET* duplicate = test_etcp_bound_socket(owner, "duplicate");
wait_source(&nf, socket, ADDRESS_SOURCE_STUN); wait_source(&nf, duplicate, ADDRESS_SOURCE_STUN);
assert(socket->address_profile.mapping == ADDRESS_MAP_EIM && socket->address_profile.inbound == ADDRESS_IN_OPEN);
assert(socket->address_profile.evidence_id == duplicate->address_profile.evidence_id);
assert(!memcmp(&socket->address_profile, &duplicate->address_profile, sizeof(socket->address_profile)));
assert(!socket->nat_addr.ss_family && !duplicate->nat_addr.ss_family);
struct nat_check_status status; assert(!nat_detection_get_status(owner->nat_det, socket, &status));
assert(status.reason == NAT_REASON_NO_OBSERVER && status.fallback_allowed);
@ -406,19 +404,25 @@ static void test_fallback(void) {
nat_fixture_connect(&nf, observer, "udp", helper); nat_detection_request_check_all(owner->nat_det);
wait_source(&nf, socket, ADDRESS_SOURCE_ETCP); wait_source(&nf, duplicate, ADDRESS_SOURCE_ETCP);
assert(socket->address_profile.mapping == ADDRESS_MAP_UNCHANGED && socket->address_profile.inbound == ADDRESS_IN_OPEN);
uint64_t evidence = socket->address_profile.evidence_id;
assert(!nat_detection_get_status(owner->nat_det, socket, &status));
uint64_t round = status.round;
struct address_profile measured = socket->address_profile;
struct stun_nat_result prior, next;
assert(!stun_nat_get_socket_result(owner, socket, &prior)); stun_nat_recheck(owner);
end = get_time_tb() + 3000000;
do { test_clock_poll(nf.ua, 10000); assert(!stun_nat_get_socket_result(owner, socket, &next)); }
while (get_time_tb() < end && next.status == STUN_NAT_PENDING);
assert(next.mapping == STUN_MAP_EIM && next.evidence_id != prior.evidence_id);
assert(socket->address_profile.source == ADDRESS_SOURCE_ETCP && socket->address_profile.evidence_id == evidence);
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); }
while (get_time_tb() < end && socket->address_profile.evidence_id == evidence);
assert(socket->address_profile.source == ADDRESS_SOURCE_ETCP && socket->address_profile.evidence_id != evidence);
assert(socket->address_profile.mapping == ADDRESS_MAP_UNCHANGED && socket->address_profile.inbound == ADDRESS_IN_UNKNOWN);
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);
assert(!memcmp(&socket->address_profile, &measured, sizeof(measured)));
/* Прошедшие пять минут не сбрасывают последний успешный ETCP. */
uint64_t timestamp = snapshot->timestamp;
test_clock_run_for(nf.ua, 3000001);
assert(!memcmp(&socket->address_profile, &measured, sizeof(measured)) && snapshot->timestamp == timestamp);
for (unsigned i = 0; i < 6; i++) {
assert(!uasync_remove_socket_t(nf.ua, server.endpoints[i].fd)); socket_close_wrapper(server.endpoints[i].fd);
}

Loading…
Cancel
Save