Exercise NAT startup rollback and UDP timeout allocation failure

This commit is contained in:
evgeny committed 2026-10-24 16:52:10 +02:00
1 parent a6444725da
commit 857a4cee2f
2 files changed
+63

No files matched your search

+1
View File
@@ -524,6 +524,7 @@ test_nat_detection_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_nat_detection_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
if OS_LINUX
test_nat_detection_LDFLAGS = -Wl,--wrap=etcp_add_conn_status_cbk -Wl,--wrap=etcp_add_socket_cbk -Wl,--wrap=uasync_set_timeout
check_PROGRAMS += test_nat_detection_faults
test_nat_detection_faults_SOURCES = test_nat_detection_faults.c $(test_clock_sources)
test_nat_detection_faults_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
+62
View File
@@ -2,6 +2,65 @@
* Настоящие ETCP/NCD/PING/STCP, без групповой автосвязности и без подмены времени. */
#include "nat_fixture.h"
#include "ntp_time.h"
#include "transport_layer/etcp_api.h"
#include "routing_layer/etcp_router.h"
#ifdef __linux__
static int fail_subscription, fail_nat_timer, fail_ping_timer;
void __real_etcp_add_conn_status_cbk(struct UTUN_INSTANCE*, etcp_conn_status_fn, void*);
void __wrap_etcp_add_conn_status_cbk(struct UTUN_INSTANCE* inst, etcp_conn_status_fn fn, void* arg) {
if (fail_subscription != 1) __real_etcp_add_conn_status_cbk(inst, fn, arg);
}
void __real_etcp_add_socket_cbk(struct UTUN_INSTANCE*, etcp_socket_cbk_fn, void*, int);
void __wrap_etcp_add_socket_cbk(struct UTUN_INSTANCE* inst, etcp_socket_cbk_fn fn, void* arg, int events) {
if (fail_subscription != 2) __real_etcp_add_socket_cbk(inst, fn, arg, events);
}
void* __real_uasync_set_timeout(struct UASYNC*, int, void*, timeout_callback_t, const char*);
void* __wrap_uasync_set_timeout(struct UASYNC* ua, int delay, void* arg, timeout_callback_t fn, const char* name) {
if ((fail_nat_timer && !strcmp(name, "nat_detection")) || (fail_ping_timer && !strcmp(name, "ping_timeout"))) return NULL;
return __real_uasync_set_timeout(ua, delay, arg, fn, name);
}
static void unexpected_ping(int success, uint16_t rtt, void* arg, uint64_t nonce, const uint8_t* data, size_t size) {
(void)success; (void)rtt; (void)nonce; (void)data; (void)size; (*(int*)arg)++;
}
/* Частичный запуск снимает только свои подписки; не принятая проба не оставляет вечного pending. */
static void test_start_failures(void) {
struct nat_fixture fixture; nat_fixture_init(&fixture);
struct UTUN_INSTANCE* inst = nat_fixture_node(&fixture, "127.0.0.2", NULL, NULL);
nat_detection_destroy(inst->nat_det); inst->nat_det = NULL;
uasync_poll(fixture.ua, 0);
struct etcp_status_cbk_entry* connections = inst->conn_status_cbks;
struct etcp_socket_cbk_entry* sockets = inst->socket_cbks;
size_t allocations = u_get_allocated_count();
for (int failure = 1; failure <= 3; failure++) {
fail_subscription = failure; fail_nat_timer = failure == 3;
assert(!nat_detection_create(inst));
fail_subscription = 0; fail_nat_timer = 0;
assert(inst->conn_status_cbks == connections && inst->socket_cbks == sockets);
assert(!inst->router_bindings.callbacks[ETCP_RT_ID_NAT_DETECTION]);
assert(u_get_allocated_count() == allocations);
}
inst->nat_det = nat_detection_create(inst); assert(inst->nat_det);
nat_detection_set_automatic(inst->nat_det, 0);
struct ETCP_SOCKET* socket = test_etcp_bound_socket(inst, "udp");
struct sockaddr_storage target = socket->local_addr;
((struct sockaddr_in*)&target)->sin_port = htons(9);
struct PING_CONTEXT* pending = inst->pending_pings;
int callbacks = 0; fail_ping_timer = 1;
assert(etcp_send_ping_to_socket(inst, socket, inst->my_keys.public_key, &target, 1000,
unexpected_ping, &callbacks, NULL, 0, 0) < 0);
fail_ping_timer = 0;
assert(inst->pending_pings == pending);
uasync_poll(fixture.ua, 0); assert(!callbacks);
nat_fixture_cleanup(&fixture);
DEBUG_INFO(DEBUG_CATEGORY_NAT, "PASS NAT partial startup rollback: two subscriptions, timer; failed UDP probe leaves no pending");
}
#endif
static void wait_profile(struct nat_fixture *fixture, struct ETCP_SOCKET *socket, uint8_t mapping, uint8_t inbound) {
uint64_t end = get_time_tb() + 180000;
@@ -255,6 +314,9 @@ static void test_all_groups_tcp(void) {
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); debug_set_category_level(DEBUG_CATEGORY_NAT, DEBUG_LEVEL_DEBUG);
if (getenv("UTUN_TEST_DEBUG")) debug_set_category_level(DEBUG_CATEGORY_BGP, DEBUG_LEVEL_DEBUG);
#ifdef __linux__
test_start_failures();
#endif
struct nat_fixture fixture; nat_fixture_init(&fixture);
struct SC_MYKEYS first, second;
assert(sc_generate_keypair(&first) == SC_OK && sc_generate_keypair(&second) == SC_OK);