From e137778ba2838ec0f41ffaa28a158ddca2fe63fd Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 19:54:21 +0200 Subject: [PATCH] Exercise IPv6 REALITY guards and reentrant node snapshot replacement --- tests/Makefile.am | 2 +- tests/test_ncd_faults.c | 65 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index a6a492c9..88a2e431 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -721,7 +721,7 @@ test_ncd_faults_SOURCES = test_ncd_faults.c $(test_clock_sources) test_ncd_faults_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib test_ncd_faults_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS) test_ncd_faults_LDFLAGS = $(test_clock_ldflags) -Wl,--wrap=etcp_conn_add_cbk -Wl,--wrap=uasync_call_soon \ - -Wl,--wrap=uasync_set_timeout -Wl,--wrap=u_calloc_impl + -Wl,--wrap=uasync_set_timeout -Wl,--wrap=u_calloc_impl -Wl,--wrap=socket_sendto endif test_group_ownership_SOURCES = test_group_ownership.c diff --git a/tests/test_ncd_faults.c b/tests/test_ncd_faults.c index eb1e24a1..3a8f6887 100644 --- a/tests/test_ncd_faults.c +++ b/tests/test_ncd_faults.c @@ -18,6 +18,11 @@ static struct UTUN_INSTANCE* inst; static size_t allocations; static int fail_callback, fail_soon, fail_connect, fail_alloc; +/* Здесь проверяем выбор пар и состояния; пакеты проб не отправляем в сеть. */ +ssize_t __wrap_socket_sendto(socket_t fd, const void* data, size_t length, const struct sockaddr* addr, socklen_t size) { + (void)fd; (void)data; (void)addr; (void)size; return (ssize_t)length; +} + void __real_etcp_conn_add_cbk(struct ETCP_CONN*, etcp_cbk_fn, void*, int); void __wrap_etcp_conn_add_cbk(struct ETCP_CONN* conn, etcp_cbk_fn fn, void* arg, int events) { if (!fail_callback) __real_etcp_conn_add_cbk(conn, fn, arg, events); @@ -270,6 +275,63 @@ static void nested_remove(void) { node_conn_direct_force_close(handle); teardown(); } +static void ipv6_candidates(void) { + setup(); struct TOPO_NODE* node = known_node(0); + struct TOPO_ADDR6* global = memory_pool_alloc(inst->topo_groups->v6_addr_pool); CHECK(global); + struct TOPO_ADDR6* local = memory_pool_alloc(inst->topo_groups->v6_addr_pool); CHECK(local); + *global = (struct TOPO_ADDR6){.addr = {0x20,1,0xd,0xb8,0,0,0,0,0,0,0,0,0,0,0,1}, .port = 9, .protocol = TOPO_PROTO_UDP}; + *local = (struct TOPO_ADDR6){.addr = {0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, .port = 10, + .protocol = TOPO_PROTO_UDP, .next = global}; + node->v6_addrs = local; + struct TOPO_SOCKMETA6* meta = memory_pool_alloc(inst->topo_groups->v6_sock_meta_pool); CHECK(meta); + *meta = (struct TOPO_SOCKMETA6){.config_type = CFG_SERVER_TYPE_PRIVATE}; node->v6_sock_meta = meta; + struct CFG_SERVER server = {.name = "NCD IPv6", .type = CFG_SERVER_TYPE_LOCAL, .mtu = 1280}; + struct sockaddr_in6* addr = (struct sockaddr_in6*)&server.ip; + addr->sin6_family = AF_INET6; addr->sin6_addr = in6addr_loopback; + struct ETCP_SOCKET* sock = etcp_socket_add(inst, &server); CHECK(sock); sock->netif_index = 0; + struct NODE_CONN_DIRECT* handle = NULL; + CHECK(node_conn_direct_open(inst, node->node_id, NULL, NULL, &handle, NULL) == NCD_NEW); + struct ETCP_CONN* conn = node_conn_direct_get_conn(handle); CHECK(link_count(conn) == 1); + sock->netif_index = 1; + CHECK(ncd_add_socket_links(inst, sock) == 1 && link_count(conn) == 2); + CHECK(((struct sockaddr_in6*)&conn->links->remote_addr)->sin6_scope_id == 1); + node_conn_direct_force_close(handle); teardown(); +} + +static void missing_reality(void) { + setup(); struct TOPO_NODE* node = known_node(1); + node->v4_addrs->protocol = TOPO_PROTO_TCP | TOPO_PROTO_REALITY; + struct NODE_CONN_DIRECT* handle = NULL; + CHECK(node_conn_direct_open(inst, node->node_id, NULL, NULL, &handle, NULL) == NCD_NEW); + CHECK(!node_conn_direct_get_conn(handle)->links && !node_conn_direct_compatible(inst, node->node_id)); + node_conn_direct_force_close(handle); teardown(); +} + +static void replace_addresses(struct ETCP_CONN* conn, struct ETCP_LINK* link, int old_state, int old_status, void* arg) { + (void)link; (void)old_status; + int* replaced = arg; + if (old_state != -1 || (*replaced)++) return; + struct TOPO_NODE* update = u_calloc(1, sizeof(*update)); CHECK(update); + struct TOPO_NODE* known = topo_node_registry_find(inst->topo_groups, conn->peer_node_id); CHECK(known); + update->node_id = known->node_id; memcpy(update->public_key, known->public_key, sizeof(update->public_key)); + struct TOPO_ADDR4* addr = memory_pool_alloc(inst->topo_groups->v4_addr_pool); CHECK(addr); + *addr = (struct TOPO_ADDR4){.addr = {127,0,0,1}, .port = 12, .protocol = TOPO_PROTO_UDP}; update->v4_addrs = addr; + CHECK(topo_node_registry_store(inst->topo_groups, update) == known); + topo_node_registry_unref(inst->topo_groups, known->node_id); +} + +static void snapshot_replaced(void) { + setup(); struct TOPO_NODE* node = known_node(2); local_socket(); + struct NODE_CONN_DIRECT* handle = NULL; int replaced = 0; + etcp_add_link_status_cbk(inst, replace_addresses, &replaced); + CHECK(node_conn_direct_open(inst, node->node_id, NULL, NULL, &handle, NULL) == NCD_NEW); + etcp_remove_link_status_cbk(inst, replace_addresses, &replaced); + struct ETCP_CONN* conn = node_conn_direct_get_conn(handle); + CHECK(replaced == 2 && link_count(conn) == 2 && node->v4_addrs->port == 12); + CHECK(node_conn_direct_update_node(inst, node->node_id) == 1 && link_count(conn) == 3); + node_conn_direct_force_close(handle); teardown(); +} + int main(int argc, char** argv) { debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_INFO); if (getenv("UTUN_TEST_DEBUG")) debug_set_category_level(DEBUG_CATEGORY_ETCP, DEBUG_LEVEL_DEBUG); @@ -278,7 +340,8 @@ int main(int argc, char** argv) { {"callback", callback_failure}, {"up", up_failure}, {"timer", timer_failure}, {"fin_wait", fin_wait_failure}, {"nested", nested_events}, {"control", control_length}, {"new", new_transport_failures}, {"policy", candidate_policy}, {"capacity", socket_capacity}, - {"cancel", open_cancelled}, {"remove", nested_remove} + {"cancel", open_cancelled}, {"remove", nested_remove}, {"ipv6", ipv6_candidates}, + {"reality", missing_reality}, {"snapshot", snapshot_replaced} }; unsigned selected = 0; for (unsigned i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {