|
|
|
|
@ -7,7 +7,7 @@
|
|
|
|
|
enum fault_mode { FAULT_NONE, FAULT_NO_PONG, FAULT_FILTERED, FAULT_LATE_PRE, FAULT_CONTACT, |
|
|
|
|
FAULT_DEPENDENT, FAULT_UNSTABLE, FAULT_NO_REPORT, FAULT_INGRESS_BLOCKED, FAULT_NO_ANCHOR, |
|
|
|
|
FAULT_LOCAL_INGRESS, FAULT_LOCAL_OBSERVER, FAULT_LOCAL_HELPER_MAPPING, FAULT_CONTROL_STALL, FAULT_EIM_UNVERIFIED, |
|
|
|
|
FAULT_KNOWN_ALIAS, FAULT_BUDGET }; |
|
|
|
|
FAULT_KNOWN_ALIAS, FAULT_BUDGET, FAULT_RESUME_TIMEOUT }; |
|
|
|
|
|
|
|
|
|
static struct { |
|
|
|
|
struct nat_fixture *fixture; |
|
|
|
|
@ -123,6 +123,10 @@ ssize_t __wrap_socket_sendto(socket_t fd, const void *packet, size_t length, con
|
|
|
|
|
|
|
|
|
|
void __wrap_nat_detection_record_observation(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket, |
|
|
|
|
const uint8_t *key, const struct sockaddr_storage *source, const uint8_t *tag, size_t length) { |
|
|
|
|
if (fault.fixture && fault.mode == FAULT_RESUME_TIMEOUT && socket->instance == fault.observer && |
|
|
|
|
length == ROUTE_OBSERVE_TAG_SIZE + 9 && !memcmp(key, fault.owner->my_keys.public_key, 32)) { |
|
|
|
|
fault.dropped++; return; |
|
|
|
|
} |
|
|
|
|
if (fault.fixture && fault.mode == FAULT_EIM_UNVERIFIED && length == ROUTE_OBSERVE_TAG_SIZE + 9 && |
|
|
|
|
!memcmp(key, fault.owner->my_keys.public_key, 32)) { |
|
|
|
|
/* Два направления видят один переведённый адрес. История помощника уже загрязнена настоящим PING. */ |
|
|
|
|
@ -425,14 +429,18 @@ static void run_budget_resume(void) {
|
|
|
|
|
assert(!nat_detection_get_status(owner->nat_det, fault.socket, &status)); |
|
|
|
|
assert(!status.phase && status.cycling && status.round == paused_round && status.helper_reselections == completed_pairs); |
|
|
|
|
assert(fault.socket->address_profile.inbound == ADDRESS_IN_UNKNOWN); |
|
|
|
|
fault.delayed_length = 0; end = get_time_tb() + 1300000; |
|
|
|
|
do { test_clock_poll(fixture.ua, 1000); assert(!nat_detection_get_status(owner->nat_det, fault.socket, &status)); } |
|
|
|
|
while (get_time_tb() < end && status.round == paused_round); |
|
|
|
|
assert(status.round != paused_round && status.helper == paused_helper && status.helper_reselections == completed_pairs); |
|
|
|
|
uint32_t resumed_rounds = status.rounds; |
|
|
|
|
/* Полный бюджет уже дан этой паре: следующий предел завершает её, а не запускает бесконечные повторы. */ |
|
|
|
|
do { test_clock_poll(fixture.ua, 1000); assert(!nat_detection_get_status(owner->nat_det, fault.socket, &status)); } |
|
|
|
|
while (get_time_tb() < end && status.cycling); |
|
|
|
|
fault.mode = FAULT_RESUME_TIMEOUT; fault.delayed_length = 0; end = get_time_tb() + 1300000; |
|
|
|
|
uint32_t resumed_rounds = 0; |
|
|
|
|
/* Большой RTT увеличивает ожидание UDP-отчёта за общий предел; отчёты B теряются в сети. */ |
|
|
|
|
struct ETCP_CONN *connection = instance_find_conn(owner, observer->node_id); assert(connection); |
|
|
|
|
do { |
|
|
|
|
for (struct ETCP_LINK *link = connection->links; link; link = link->next) link->rtt_last = 60000; |
|
|
|
|
test_clock_poll(fixture.ua, 1000); assert(!nat_detection_get_status(owner->nat_det, fault.socket, &status)); |
|
|
|
|
if (status.round != paused_round && !resumed_rounds) { |
|
|
|
|
assert(status.helper == paused_helper && status.helper_reselections == completed_pairs); |
|
|
|
|
resumed_rounds = status.rounds; |
|
|
|
|
} |
|
|
|
|
} while (get_time_tb() < end && status.cycling); |
|
|
|
|
assert(!status.phase && !status.cycling && status.round != paused_round && status.helper == paused_helper); |
|
|
|
|
assert(status.rounds == resumed_rounds); |
|
|
|
|
assert(status.helper_reselections == completed_pairs + 1 && fault.socket->address_profile.mapping == ADDRESS_MAP_UNCHANGED && |
|
|
|
|
|