From 4afd5df55fc4c15579270d4a24d1298c3ce746e0 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 10 Oct 2026 15:27:47 +0200 Subject: [PATCH] tests: use bound ephemeral ports for ETCP and IPv6 peers --- tests/Makefile.am | 2 +- tests/test_etcp_ping.c | 8 +++-- tests/test_etcp_two_instances.c | 10 +++--- tests/test_ipv6_sockets.c | 8 +++-- tests/test_net.h | 56 +++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 tests/test_net.h diff --git a/tests/Makefile.am b/tests/Makefile.am index 97a66d63..368b2b76 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ # Tests Makefile.am for utun - all tests with new ll_queue library -EXTRA_DIST = fixtures/reality_openssl_hello.hex data/silero_speech.pcm data/silero_speech.txt +EXTRA_DIST = fixtures/reality_openssl_hello.hex data/silero_speech.pcm data/silero_speech.txt test_net.h # Порядок по замерам Linux: быстрые проверки раньше длительных; состав зависит от прежних configure-условий. diff --git a/tests/test_etcp_ping.c b/tests/test_etcp_ping.c index 26058f9e..dfdab45e 100644 --- a/tests/test_etcp_ping.c +++ b/tests/test_etcp_ping.c @@ -6,6 +6,7 @@ #include #include #include "test_utils.h" +#include "test_net.h" #include "etcp.h" #include "etcp_connections.h" #include "../src/config_parser.h" @@ -38,7 +39,7 @@ static const char* server_config_content = "tun_ifname=tun99\n" "\n" "[server:test]\n" - "addr=127.0.0.1:9011\n" + "addr=127.0.0.1:0\n" "type=public\n" "\n" "[allowed_keys]\n" @@ -53,13 +54,13 @@ static const char* client_config_content = "tun_ifname=tun98\n" "\n" "[server:test]\n" - "addr=127.0.0.1:9012\n" + "addr=127.0.0.1:0\n" "type=public\n" "\n" "[client:test_client]\n" "keepalive=1\n" "peer_public_key=ce8871f07fa056c636d297115f231b08c29cdf94e0d440fce83a07c34416d36a\n" - "link=test:127.0.0.1:9011\n"; + "link=test:127.0.0.1:0\n"; static int create_temp_configs(void) { if (test_mkdtemp(temp_dir) != 0) { @@ -165,6 +166,7 @@ int main(void) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "instance creation failed"); goto cleanup; } + test_etcp_set_peer(client_instance, "test_client", server_instance, "test"); int ret; ret = utun_instance_init(server_instance); if (ret != 0) { diff --git a/tests/test_etcp_two_instances.c b/tests/test_etcp_two_instances.c index ee03e253..5d0dcaca 100644 --- a/tests/test_etcp_two_instances.c +++ b/tests/test_etcp_two_instances.c @@ -3,6 +3,7 @@ #include #include "../lib/platform_compat.h" #include "test_utils.h" +#include "test_net.h" #ifdef _WIN32 #include #include @@ -47,7 +48,7 @@ static const char* server_config_content = "tun_ifname=tun99\n" "\n" "[server: test]\n" - "addr=127.0.0.1:9011\n" + "addr=127.0.0.1:0\n" "type=public\n" "\n" "[allowed_keys]\n" @@ -63,13 +64,13 @@ static const char* client_config_content = "tun_ifname=tun98\n" "\n" "[server: test]\n" - "addr=127.0.0.1:9012\n" + "addr=127.0.0.1:0\n" "type=public\n" "\n" "[client: test_client]\n" "keepalive=1\n" "peer_public_key=ce8871f07fa056c636d297115f231b08c29cdf94e0d440fce83a07c34416d36a\n" - "link=test:127.0.0.1:9011\n"; + "link=test:127.0.0.1:0\n"; // Create temp config files static int create_temp_configs(void) { @@ -298,6 +299,7 @@ int main() { } // Initialize instance (TUN is initialized in utun_instance_create if enabled) + test_etcp_set_peer(client_instance, "test_client", server_instance, "test"); if (utun_instance_init(client_instance) < 0) { DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Failed to initialize client instance\n"); utun_instance_destroy(server_instance); @@ -405,4 +407,4 @@ int main() { cleanup_temp_configs(); return (test_completed == 1) ? 0 : 1; -} \ No newline at end of file +} diff --git a/tests/test_ipv6_sockets.c b/tests/test_ipv6_sockets.c index bda3bb23..3a0347ae 100644 --- a/tests/test_ipv6_sockets.c +++ b/tests/test_ipv6_sockets.c @@ -20,6 +20,7 @@ #endif #include "../lib/platform_compat.h" #include "test_utils.h" +#include "test_net.h" #ifdef _WIN32 #include @@ -67,7 +68,7 @@ static const char* server_config = "my_subnet=2001:db8:1::/48\n" "\n" "[server: v6srv]\n" - "addr=[::1]:40111\n" + "addr=[::1]:0\n" "type=public\n" "\n" "[allowed_keys]\n" @@ -83,13 +84,13 @@ static const char* client_config = "tun_test_mode=1\n" "\n" "[server: v6srv]\n" - "addr=[::1]:40112\n" + "addr=[::1]:0\n" "type=public\n" "\n" "[client: v6client]\n" "keepalive=1\n" "peer_public_key=ce8871f07fa056c636d297115f231b08c29cdf94e0d440fce83a07c34416d36a\n" - "link=v6srv:[::1]:40111\n"; + "link=v6srv:[::1]:0\n"; static int create_temp_configs(void) { if (test_mkdtemp(temp_dir) != 0) { @@ -283,6 +284,7 @@ int main(void) { client_instance = utun_instance_create(ua, client_config_path); if (!client_instance) { fprintf(stderr, "Client instance create failed\n"); return 1; } + test_etcp_set_peer(client_instance, "v6client", server_instance, "v6srv"); if (utun_instance_init(client_instance) < 0) { fprintf(stderr, "Client init failed\n"); return 1; } monitor_timer = uasync_set_timeout(ua, 100, NULL, monitor, "v6_monitor"); diff --git a/tests/test_net.h b/tests/test_net.h new file mode 100644 index 00000000..c02c6720 --- /dev/null +++ b/tests/test_net.h @@ -0,0 +1,56 @@ +#ifndef TEST_NET_H +#define TEST_NET_H + +#include "../src/utun_instance.h" +#include "../src/transport_layer/etcp_connections.h" +#include "../lib/debug_config.h" +#include "../lib/socket_compat.h" +#include +#include + +// Читаем порт уже открытого сокета; владение fd и резервирование порта сохраняются. +static inline uint16_t test_bound_port(socket_t fd) { + struct sockaddr_storage address; socklen_t size = sizeof(address); + if (getsockname(fd, (struct sockaddr*)&address, &size) != 0 || !ss_get_port(&address)) { + DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "test fixture: cannot read bound port fd=%d error=%d", (int)fd, socket_get_error()); + abort(); + } + return ss_get_port(&address); +} + +static inline struct ETCP_SOCKET* test_etcp_bound_socket(struct UTUN_INSTANCE* inst, const char* name) { + for (struct ETCP_SOCKET* s = inst ? inst->etcp_sockets : NULL; s; s = s->next) { + if (strcmp(s->name, name)) continue; + if (ss_get_port(&s->local_addr) && ss_get_port(&s->local_addr) == ss_get_port(&s->interface_addr)) return s; + DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "test fixture: socket %s has no valid bound endpoint", name); abort(); + } + DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "test fixture: missing listener %s", name); abort(); +} + +// Связываем явно указанные endpoints до start; никаких замен по номеру порта или обхода эмуляторов. +static inline void test_etcp_set_peer(struct UTUN_INSTANCE* client, const char* client_name, + struct UTUN_INSTANCE* peer, const char* socket_name) { + struct ETCP_SOCKET* target = test_etcp_bound_socket(peer, socket_name); + if (!client || !client->config || client->utun_started) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "test fixture: client %s must be configured before start", client_name); abort(); + } + for (struct CFG_CLIENT* c = client->config->clients; c; c = c->next) { + if (strcmp(c->name, client_name)) continue; + if (!c->links) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "test fixture: client %s has no links", client_name); abort(); } + for (struct CFG_CLIENT_LINK* link = c->links; link; link = link->next) { + if (link->remote_addr.ss_family != target->interface_addr.ss_family || + (link->local_srv && link->local_srv->transport != target->is_tcp)) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "test fixture: incompatible endpoints client=%s listener=%s", client_name, socket_name); + abort(); + } + link->remote_addr = target->interface_addr; + debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_INFO); + DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "test fixture: client=%s listener=%s peer=%016llx port=%u", + client_name, socket_name, (unsigned long long)peer->node_id, ss_get_port(&link->remote_addr)); + } + return; + } + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "test fixture: missing client %s", client_name); abort(); +} + +#endif