fix: memory pool alloc mismatch in tests, db_sync SEND_DATA buffer overflow

- test_etcp_router_reconnect, test_etcp_connect, test_stcp_traffic:
  replace u_calloc with memory_pool_alloc for TOPO_SOCKMETA4/TOPO_ADDR4
- db_sync.c: fix req[14] -> req[15] — SEND_DATA request header is 15 bytes
  (type:1 + from:4 + count:2 + vp:4 + want_from:4)
This commit is contained in:
evgeny committed 2026-07-31 21:44:44 +03:00
1 parent fe9be74e29
commit d310bccf08
52 files changed
+1796 -585

No files matched your search

+5
View File
@@ -50,6 +50,7 @@ check_PROGRAMS = \
test_conn_mgr \
test_conn_mgr_already_connected \
test_etcp_connect \
test_node_conn_direct \
test_db_sync \
test_merkle_sync \
test_chat_sync_stress \
@@ -291,6 +292,10 @@ test_etcp_connect_SOURCES = test_etcp_connect.c
test_etcp_connect_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_etcp_connect_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
test_node_conn_direct_SOURCES = test_node_conn_direct.c
test_node_conn_direct_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_node_conn_direct_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
test_db_sync_SOURCES = test_db_sync.c
test_db_sync_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_db_sync_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
+1 -1
View File
@@ -214,7 +214,7 @@ static int check_learned_route(struct UTUN_INSTANCE* inst, uint32_t network, uin
for (size_t i = 0; i < inst->rt->count; i++) {
struct ROUTE_ENTRY* e = &inst->rt->entries[i];
if (e->network == network && e->prefix_length == prefix_len &&
e->v_node_info && e->v_node_info->node->node_id == node_id) return 1;
e->v_node_info && e->v_node_info->node_id == node_id) return 1;
}
return 0;
}
+4 -4
View File
@@ -127,13 +127,13 @@ static int peer_in_nodes(struct UTUN_INSTANCE* inst, uint64_t node_id) {
}
static int node_path_count(struct UTUN_INSTANCE* inst, uint64_t node_id) {
struct TOPO_NODEQ* nq = topo_node_find_by_id(topo_groups_get_default(inst->topo_groups), node_id);
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(topo_groups_get_default(inst->topo_groups), node_id);
if (!nq || !nq->paths) return 0;
return queue_entry_count(nq->paths);
}
static int node_path_has_peer(struct UTUN_INSTANCE* inst, uint64_t node_id, uint64_t peer_id) {
struct TOPO_NODEQ* nq = topo_node_find_by_id(topo_groups_get_default(inst->topo_groups), node_id);
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(topo_groups_get_default(inst->topo_groups), node_id);
if (!nq || !nq->paths) return 0;
struct ll_entry* e = nq->paths->head;
while (e) {
@@ -147,7 +147,7 @@ static int node_path_has_peer(struct UTUN_INSTANCE* inst, uint64_t node_id, uint
}
static int node_version(struct UTUN_INSTANCE* inst, uint64_t node_id) {
struct TOPO_NODEQ* nq = topo_node_find_by_id(topo_groups_get_default(inst->topo_groups), node_id);
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(topo_groups_get_default(inst->topo_groups), node_id);
return nq ? nq->last_ver : -1;
}
@@ -156,7 +156,7 @@ static int route_count_for_node(struct UTUN_INSTANCE* inst, uint64_t node_id) {
int cnt = 0;
for (size_t i = 0; i < inst->rt->count; i++)
if (inst->rt->entries[i].v_node_info &&
inst->rt->entries[i].v_node_info->node->node_id == node_id) cnt++;
inst->rt->entries[i].v_node_info->node_id == node_id) cnt++;
return cnt;
}
+2 -2
View File
@@ -171,7 +171,7 @@ static void test3_check(void* arg) {
fprintf(stderr, " state=%d type=%d\n", st, ty); fflush(stderr);
if (st != CONN_MGR_STATE_CONNECTED || ty != CONN_TYPE_DIRECT) { fail("test3: status mismatch"); return; }
struct TOPO_NODEQ* nq = topo_node_find_by_id(g_a2->conn_mgr->group, g_nid_b2);
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(g_a2->conn_mgr->group, g_nid_b2);
if (!nq) { fail("test3: B2 not in group after connect"); return; }
if (g_a2->conn_mgr->group->group_id != TOPO_GROUP_UTUN) { fail("test3: wrong group_id"); return; }
@@ -192,7 +192,7 @@ static void test4_check(void* arg) {
if (!cdone2) { uasync_set_timeout(ua2, 20, NULL, (timeout_callback_t)test4_check, "t4c"); return; }
if (cresult2 != CONN_MGR_ERR_UNREACHABLE) { fail("test4: expected UNREACHABLE"); return; }
struct TOPO_NODEQ* nq = topo_node_find_by_id(g_a2->conn_mgr->group, g_nid_c);
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(g_a2->conn_mgr->group, g_nid_c);
if (nq && !(nq->paths && queue_entry_count(nq->paths) > 0)) { fail("test4: C still in group after unreachable"); return; }
fprintf(stderr, " OK: UNREACHABLE, node cleaned up\n"); fflush(stderr);
+5 -2
View File
@@ -72,7 +72,7 @@ static void test_mgr_connect(void* arg) {
(void)arg;
cb_fired = 0; cb_ok = 0;
struct CONN_MGR* mgr = g_a->conn_mgr;
struct TOPO_NODEQ* nq = topo_node_find_by_id(mgr->group, g_b->node_id);
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(mgr->group, g_b->node_id);
if (nq) { fprintf(stderr, "node already in UTUN group\n"); fflush(stderr); }
fprintf(stderr, "Test 2: conn_mgr_connect_node(B)\n"); fflush(stderr);
conn_mgr_connect_node(mgr, g_b->node_id, 0, conn_cb, NULL);
@@ -99,7 +99,10 @@ static void test3_preconnect(void* arg) {
struct ETCP_CONN* c = instance_find_conn(g_a, g_b->node_id);
if (c) { fprintf(stderr, "Test3: SKIP — conn already established\n"); return; }
fprintf(stderr, "Test 3: conn_mgr_connect_node BEFORE link up\n"); fflush(stderr);
conn_mgr_connect_node(mgr, g_b->node_id, 0, conn_cb, NULL);
if (!conn_mgr_connect_node(mgr, g_b->node_id, 0, conn_cb, NULL)) {
fprintf(stderr, "Test 3: SKIP — node not found in group (BGP not done yet)\n"); fflush(stderr);
return;
}
uasync_call_soon(ua, NULL, test3_check);
}
+14 -13
View File
@@ -66,20 +66,21 @@ static volatile int cb_type = 0, cb_conn_ok = 0, cb_count = 0;
static void connect_ccb(void* a, struct ETCP_CONN* conn, int type) { cb_type = type; cb_conn_ok = (conn != NULL); cb_count++; }
/* ----- helper: create minimal TOPO_NODEQ with 1 v4 addr ----- */
static struct TOPO_NODEQ* mknode(uint64_t nid, const uint8_t pubkey[32],
/* ----- helper: create minimal TOPO_GROUP_NODE with 1 v4 addr ----- */
static struct TOPO_GROUP_NODE* mknode(struct UTUN_INSTANCE* inst, uint64_t nid, const uint8_t pubkey[32],
uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port) {
struct TOPO_NODEQ* nq = u_calloc(1, sizeof(struct TOPO_NODEQ));
struct TOPO_GROUP_NODE* nq = u_calloc(1, sizeof(struct TOPO_GROUP_NODE));
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
if (!nq || !ni) { u_free(nq); u_free(ni); return NULL; }
ni->ref_count = 1; ni->node_id = nid; ni->ver = 0;
ni->group_ref_count = 1; ni->node_id = nid; ni->ver = 0; ni->group_id = TOPO_GROUP_UTUN;
memcpy(ni->public_key, pubkey, SC_PUBKEY_SIZE);
nq->ll.size = sizeof(struct TOPO_NODEQ) - sizeof(struct ll_entry);
nq->node = ni; nq->hash_node_id = nid;
struct TOPO_SOCKMETA4* sm = u_calloc(1, sizeof(struct TOPO_SOCKMETA4));
nq->ll.size = sizeof(struct TOPO_GROUP_NODE) - sizeof(struct ll_entry);
nq->node_id = nid;
struct TOPO_SOCKMETA4* sm = memory_pool_alloc(inst->topo_groups->v4_sock_meta_pool);
if (sm) { sm->id = 0; sm->config_type = CFG_SERVER_TYPE_PUBLIC; sm->nat_type = NAT_TYPE_UNKNOWN; sm->next = ni->v4_sock_meta; ni->v4_sock_meta = sm; }
struct TOPO_ADDR4* addr = u_calloc(1, sizeof(struct TOPO_ADDR4));
struct TOPO_ADDR4* addr = memory_pool_alloc(inst->topo_groups->v4_addr_pool);
if (addr) { addr->addr[0] = a; addr->addr[1] = b; addr->addr[2] = c; addr->addr[3] = d; addr->port = port; addr->type = TOPO_ADDR_INTERFACE; addr->socket_id = 0; addr->next = ni->v4_addrs; ni->v4_addrs = addr; }
topo_node_registry_store(inst->topo_groups, ni);
return nq;
}
@@ -87,7 +88,7 @@ static struct TOPO_NODEQ* mknode(uint64_t nid, const uint8_t pubkey[32],
static void test1(void* arg) {
(void)arg; if (result) return;
if (lks(g_a) < 1 || lks(g_b) < 1) { uasync_set_timeout(ua, 50, NULL, (timeout_callback_t)test1, "t1"); return; }
struct TOPO_NODEQ* nb = topo_node_find_by_id(topo_groups_get_default(g_a->topo_groups), nid_b);
struct TOPO_GROUP_NODE* nb = topo_node_find_by_id(topo_groups_get_default(g_a->topo_groups), nid_b);
if (!nb) { uasync_set_timeout(ua, 50, NULL, (timeout_callback_t)test1, "t1b"); return; }
fprintf(stderr, "Test 1: already connected → EARLY|LATE\n"); fflush(stderr);
cb_type = 0; cb_conn_ok = 0; cb_count = 0;
@@ -111,7 +112,7 @@ static void test3(void* arg) {
fprintf(stderr, "Test 3: unreachable node → error\n"); fflush(stderr);
struct SC_MYKEYS fk; sc_generate_keypair(&fk);
uint64_t fnid = 0xF000000000000001ULL;
struct TOPO_NODEQ* fn = mknode(fnid, fk.public_key, 127,0,0,1, 49999);
struct TOPO_GROUP_NODE* fn = mknode(g_a, fnid, fk.public_key, 127,0,0,1, 49999);
if (!fn) { fail("mknode failed"); return; }
queue_data_put_with_index(topo_groups_get_default(g_a->topo_groups)->nodes, &fn->ll);
g_a->etcp_connect_timeout_tb = 2000;
@@ -141,7 +142,7 @@ static void test5(void* arg) {
fprintf(stderr, "Test 5: double connect to unreachable → both callbacks\n"); fflush(stderr);
struct SC_MYKEYS fk; sc_generate_keypair(&fk);
uint64_t fnid = 0xF000000000000002ULL;
struct TOPO_NODEQ* fn = mknode(fnid, fk.public_key, 127,0,0,1, 49998);
struct TOPO_GROUP_NODE* fn = mknode(g_a, fnid, fk.public_key, 127,0,0,1, 49998);
if (!fn) { fail("mknode failed"); return; }
queue_data_put_with_index(topo_groups_get_default(g_a->topo_groups)->nodes, &fn->ll);
g_a->etcp_connect_timeout_tb = 2000;
@@ -162,7 +163,7 @@ static void test6(void* arg) {
/* ======================== Test 7: EARLY-only flag ======================== */
static void test7(void* arg) {
(void)arg; if (result) return;
struct TOPO_NODEQ* nb = topo_node_find_by_id(topo_groups_get_default(g_a->topo_groups), nid_b);
struct TOPO_GROUP_NODE* nb = topo_node_find_by_id(topo_groups_get_default(g_a->topo_groups), nid_b);
if (!nb || lks(g_a) < 1) { uasync_set_timeout(ua, 50, NULL, (timeout_callback_t)test7, "t7"); return; }
fprintf(stderr, "Test 7: EARLY-only flag\n"); fflush(stderr);
cb_type = 0; cb_conn_ok = 0; cb_count = 0;
@@ -182,7 +183,7 @@ static void test8(void* arg) {
/* ======================== Test 9: LATE-only flag ======================== */
static void test9(void* arg) {
(void)arg; if (result) return;
struct TOPO_NODEQ* nb = topo_node_find_by_id(topo_groups_get_default(g_a->topo_groups), nid_b);
struct TOPO_GROUP_NODE* nb = topo_node_find_by_id(topo_groups_get_default(g_a->topo_groups), nid_b);
if (!nb || lks(g_a) < 1) { uasync_set_timeout(ua, 50, NULL, (timeout_callback_t)test9, "t9"); return; }
fprintf(stderr, "Test 9: LATE-only flag\n"); fflush(stderr);
cb_type = 0; cb_conn_ok = 0; cb_count = 0;
+13 -11
View File
@@ -78,18 +78,20 @@ static void gen_payload(uint32_t seq, uint8_t* buf, int len) {
for (int i=0;i<len;i++) buf[i]=(uint8_t)((i^seq^0xA5)&0xFF);
}
static struct TOPO_NODEQ* mknode(uint64_t nid, const uint8_t pubkey[32],
static struct TOPO_GROUP_NODE* mknode(struct UTUN_INSTANCE* inst, uint64_t nid, const uint8_t pubkey[32],
uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port) {
struct TOPO_NODEQ* nq = u_calloc(1, sizeof(struct TOPO_NODEQ));
struct TOPO_GROUP_NODE* nq = u_calloc(1, sizeof(struct TOPO_GROUP_NODE));
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
if (!nq || !ni) { u_free(nq); u_free(ni); return NULL; }
ni->ref_count = 1; ni->node_id = nid; ni->ver = 0;
ni->group_ref_count = 1; ni->node_id = nid; ni->ver = 0; ni->group_id = TOPO_GROUP_UTUN;
memcpy(ni->public_key, pubkey, SC_PUBKEY_SIZE);
nq->node = ni; nq->hash_node_id = nid;
struct TOPO_SOCKMETA4* sm = u_calloc(1, sizeof(struct TOPO_SOCKMETA4));
nq->ll.size = sizeof(struct TOPO_GROUP_NODE) - sizeof(struct ll_entry);
nq->node_id = nid;
struct TOPO_SOCKMETA4* sm = memory_pool_alloc(inst->topo_groups->v4_sock_meta_pool);
if (sm) { sm->id = 0; sm->config_type = CFG_SERVER_TYPE_PUBLIC; sm->nat_type = NAT_TYPE_UNKNOWN; sm->next = ni->v4_sock_meta; ni->v4_sock_meta = sm; }
struct TOPO_ADDR4* addr = u_calloc(1, sizeof(struct TOPO_ADDR4));
if (addr) { addr->addr[0] = a; addr->addr[1] = b; addr->addr[2] = c; addr->addr[3] = d; addr->port = port; addr->type = TOPO_ADDR_INTERFACE; addr->socket_id = 0; addr->next = ni->v4_addrs; ni->v4_addrs = addr; }
struct TOPO_ADDR4* addr = memory_pool_alloc(inst->topo_groups->v4_addr_pool);
if (addr) { addr->addr[0] = a; addr->addr[1] = b; addr->addr[2] = c; addr->addr[3] = d; addr->port = port; addr->type = TOPO_ADDR_INTERFACE; addr->socket_id = 0; addr->protocol = TOPO_PROTO_UDP; addr->next = ni->v4_addrs; ni->v4_addrs = addr; }
if (inst && inst->topo_groups) topo_node_registry_store(inst->topo_groups, ni);
return nq;
}
@@ -197,8 +199,8 @@ static void state_step(void) {
g_b=utun_instance_create(ua,b_conf);
if (!g_b||utun_instance_init(g_b)<0) { fprintf(stderr,"FAIL: b restart\n"); g_test_ok=-1; g_fail_code=20; return; }
g_b->etcp_connect_timeout_tb = 300000;
struct TOPO_NODEQ* nq_a = mknode(node_a, keys_a.public_key, 127,0,0,1, (uint16_t)a_port);
struct TOPO_NODEQ* nq_c = mknode(node_c, keys_c.public_key, 127,0,0,1, (uint16_t)c_port);
struct TOPO_GROUP_NODE* nq_a = mknode(g_b, node_a, keys_a.public_key, 127,0,0,1, (uint16_t)a_port);
struct TOPO_GROUP_NODE* nq_c = mknode(g_b, node_c, keys_c.public_key, 127,0,0,1, (uint16_t)c_port);
if (!nq_a || !nq_c) { fprintf(stderr,"FAIL: mknode\n"); g_test_ok=-1; return; }
static int cc_a=0,cc_c=1;
etcp_connect(g_b,nq_a,connect_bgp_ready_cb,&cc_a,ETCP_CONNECT_BGP_READY);
@@ -248,8 +250,8 @@ int main(void) {
etcp_router_bind(g_c, TEST_SVC_ID, recv_handler);
struct TOPO_NODEQ* nq_a = mknode(node_a, keys_a.public_key, 127,0,0,1, (uint16_t)a_port);
struct TOPO_NODEQ* nq_c = mknode(node_c, keys_c.public_key, 127,0,0,1, (uint16_t)c_port);
struct TOPO_GROUP_NODE* nq_a = mknode(g_b, node_a, keys_a.public_key, 127,0,0,1, (uint16_t)a_port);
struct TOPO_GROUP_NODE* nq_c = mknode(g_b, node_c, keys_c.public_key, 127,0,0,1, (uint16_t)c_port);
if (!nq_a || !nq_c) { fprintf(stderr,"FAIL: mknode\n"); goto fail; }
g_b->etcp_connect_timeout_tb = 300000;
{ static int cc_a=0,cc_c=1;
+7 -5
View File
@@ -144,6 +144,7 @@ static void setup_bgp_for_sign_test(struct UTUN_INSTANCE* inst, int with_ed25519
inst->topo_groups = u_calloc(1, sizeof(struct TOPO_GROUPS));
if (!inst->topo_groups) { printf(" setup_bgp: topo_groups alloc failed\n"); return; }
inst->topo_groups->group_list = queue_new(inst->ua, 16, 0, 8, "group_list_test");
inst->topo_groups->node_registry = queue_new(inst->ua, BGP_NODES_HASH_SIZE, 0, 8, "node_registry_test");
struct ll_entry* qe = queue_entry_new(sizeof(struct TOPO_GROUP));
if (!qe) { printf(" setup_bgp: queue_entry_new failed\n"); return; }
@@ -152,18 +153,19 @@ static void setup_bgp_for_sign_test(struct UTUN_INSTANCE* inst, int with_ed25519
group->instance = inst;
group->group_id = TOPO_GROUP_UTUN;
group->nodes = queue_new(inst->ua, BGP_NODES_HASH_SIZE,
offsetof(struct TOPO_NODEQ, hash_node_id) - sizeof(struct ll_entry), 8, "group_nodes_test");
offsetof(struct TOPO_GROUP_NODE, node_id) - sizeof(struct ll_entry), 8, "group_nodes_test");
if (!group->nodes) { printf(" setup_bgp: queue_new failed\n"); queue_entry_free(qe); return; }
queue_data_put_with_index(inst->topo_groups->group_list, &group->ll);
struct TOPO_NODEQ* nq = u_calloc(1, sizeof(struct TOPO_NODEQ));
struct TOPO_GROUP_NODE* nq = u_calloc(1, sizeof(struct TOPO_GROUP_NODE));
if (!nq) { printf(" setup_bgp: nq alloc failed\n"); return; }
nq->ll.size = sizeof(struct TOPO_NODEQ) - sizeof(struct ll_entry);
nq->ll.size = sizeof(struct TOPO_GROUP_NODE) - sizeof(struct ll_entry);
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
if (!ni) { printf(" setup_bgp: ni alloc failed\n"); u_free(nq); return; }
ni->ref_count = 1; ni->node_id = SIGNER_NODE;
ni->group_ref_count = 1; ni->node_id = SIGNER_NODE;
if (with_ed25519_key) memcpy(ni->ed25519_public_key, g_sign_ed25519_pubkey, SC_PUBKEY_SIZE);
nq->node = ni; nq->hash_node_id = ni->node_id;
topo_node_registry_store(inst->topo_groups, ni);
nq->node_id = ni->node_id;
queue_data_put_with_index(group->nodes, &nq->ll);
}
+16 -13
View File
@@ -136,11 +136,11 @@ static int is_connection_established(struct UTUN_INSTANCE* inst) {
static int verify_ipv6_local_nodeinfo(const char* name, struct UTUN_INSTANCE* inst,
int expect_socks, int expect_addrs, int expect_subnets) {
if (!inst || !topo_groups_get_default(inst->topo_groups) || !topo_groups_get_default(inst->topo_groups)->local_node || !topo_groups_get_default(inst->topo_groups)->local_node->node) {
printf("FAIL [%s]: no bgp/local_node\n", name);
return 0;
}
struct TOPO_NODE* ni = topo_groups_get_default(inst->topo_groups)->local_node->node;
struct TOPO_GROUPS* groups = inst ? inst->topo_groups : NULL;
struct TOPO_GROUP* grp = groups ? topo_groups_get_default(groups) : NULL;
if (!grp || !grp->local_node) { printf("FAIL [%s]: no bgp/local_node\n", name); return 0; }
struct TOPO_NODE* ni = topo_node_registry_find(groups, grp->local_node->node_id);
if (!ni) { printf("FAIL [%s]: local node not in registry\n", name); return 0; }
struct ETCP_SOCKET* es = inst->etcp_sockets;
int v6_sock_found = 0;
@@ -188,18 +188,21 @@ static int verify_ipv6_local_nodeinfo(const char* name, struct UTUN_INSTANCE* in
}
static int verify_remote_v6_nodeinfo(const char* name, struct UTUN_INSTANCE* inst, uint64_t peer_node_id) {
if (!inst || !topo_groups_get_default(inst->topo_groups)) { printf("FAIL [%s]: no bgp\n", name); return 0; }
struct TOPO_NODEQ* nq = topo_node_find_by_id(topo_groups_get_default(inst->topo_groups), peer_node_id);
if (!nq || !nq->node) { printf("FAIL [%s]: remote node %016llx not found\n", name, (unsigned long long)peer_node_id); return 0; }
struct TOPO_GROUPS* groups = inst ? inst->topo_groups : NULL;
if (!groups) { printf("FAIL [%s]: no bgp\n", name); return 0; }
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(topo_groups_get_default(groups), peer_node_id);
if (!nq) { printf("FAIL [%s]: remote node %016llx not found\n", name, (unsigned long long)peer_node_id); return 0; }
struct TOPO_NODE* rni = topo_node_registry_find(groups, nq->node_id);
if (!rni) { printf("FAIL [%s]: remote node %016llx not in registry\n", name, (unsigned long long)peer_node_id); return 0; }
printf("PASS [%s]: remote node %016llx found\n", name, (unsigned long long)peer_node_id);
if (!nq->node->v6_sock_meta) { printf("FAIL [%s]: remote node has no v6 sockets\n", name); return 0; }
printf("PASS [%s]: remote node v6_sockets=%d\n", name, topo_list_count((struct _topo_head*)nq->node->v6_sock_meta));
if (!rni->v6_sock_meta) { printf("FAIL [%s]: remote node has no v6 sockets\n", name); return 0; }
printf("PASS [%s]: remote node v6_sockets=%d\n", name, topo_list_count((struct _topo_head*)rni->v6_sock_meta));
if (!nq->node->v6_addrs) { printf("FAIL [%s]: remote node has no v6 addrs\n", name); return 0; }
printf("PASS [%s]: remote node v6_addrs=%d\n", name, topo_list_count((struct _topo_head*)nq->node->v6_addrs));
if (!rni->v6_addrs) { printf("FAIL [%s]: remote node has no v6 addrs\n", name); return 0; }
printf("PASS [%s]: remote node v6_addrs=%d\n", name, topo_list_count((struct _topo_head*)rni->v6_addrs));
const struct TOPO_ADDR6* a = nq->node->v6_addrs;
const struct TOPO_ADDR6* a = rni->v6_addrs;
if (a) {
uint8_t loopback[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
if (memcmp(a->addr, loopback, 16) != 0) { printf("FAIL [%s]: remote v6 addr not ::1\n", name); return 0; }
+17 -11
View File
@@ -311,9 +311,9 @@ int main(void) {
}
// 5. Verify all NAT fields on server
struct TOPO_NODEQ* node_c1 = topo_node_find_by_id(topo_groups_get_default(inst_s->topo_groups), g_node_id_c1);
struct TOPO_GROUP_NODE* node_c1 = topo_node_find_by_id(topo_groups_get_default(inst_s->topo_groups), g_node_id_c1);
if (!node_c1) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "TOPO_NODEQ for C1 disappeared");
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "TOPO_GROUP_NODE for C1 disappeared");
goto cleanup;
}
if (link_sc1->nat_check_status != NAT_CHECK_EIM) {
@@ -361,9 +361,11 @@ int main(void) {
}
// Verify local_node socket update on C1 (received NAT_INFO updated nodeinfo)
if (topo_groups_get_default(inst_c1->topo_groups) && topo_groups_get_default(inst_c1->topo_groups)->local_node && topo_groups_get_default(inst_c1->topo_groups)->local_node->node) {
int found = 0;
for (const struct TOPO_SOCKMETA4* m = topo_groups_get_default(inst_c1->topo_groups)->local_node->node->v4_sock_meta; m; m = m->next) {
if (topo_groups_get_default(inst_c1->topo_groups) && topo_groups_get_default(inst_c1->topo_groups)->local_node) {
struct TOPO_NODE* lni = topo_node_registry_find(inst_c1->topo_groups, topo_groups_get_default(inst_c1->topo_groups)->local_node->node_id);
if (lni) {
int found = 0;
for (const struct TOPO_SOCKMETA4* m = lni->v4_sock_meta; m; m = m->next) {
if (m->id == sock_c1->sock_id) {
if (m->nat_type != NAT_VERIFIED_EIM) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: local_node socket meta not updated on C1: nat_type=%u expected=%u", m->nat_type, NAT_VERIFIED_EIM);
@@ -375,7 +377,7 @@ int main(void) {
if (!found) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: socket not found in local_node meta on C1"); goto cleanup; }
// Verify NAT addr in flat address list
int nat_found = 0;
for (const struct TOPO_ADDR4* a = topo_groups_get_default(inst_c1->topo_groups)->local_node->node->v4_addrs; a; a = a->next) {
for (const struct TOPO_ADDR4* a = lni->v4_addrs; a; a = a->next) {
if (a->type == TOPO_ADDR_NAT && a->socket_id == (sock_c1->sock_id | 1)) {
uint32_t addr_ip; memcpy(&addr_ip, a->addr, 4);
if (addr_ip != link_sc1->nat_ip || a->port != link_sc1->nat_port) {
@@ -388,16 +390,20 @@ int main(void) {
}
if (!nat_found) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: NAT addr not found in local_node flat addr list on C1"); goto cleanup; }
DEBUG_INFO(DEBUG_CATEGORY_BGP, "local_node meta+addr check PASSED on C1");
}
}
// Wait for C2 to learn updated C1 nodeinfo (with verified NAT type)
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Waiting for C2 to learn updated C1 nodeinfo...");
bgp_wait_cycles = 0;
int c2_verified_nat = 0;
struct TOPO_GROUP_NODE* node_c1_on_c2 = NULL;
struct TOPO_NODE* cni = NULL;
while (!test_timed_out && bgp_wait_cycles < 500) {
struct TOPO_NODEQ* node_c1_on_c2 = topo_groups_get_default(inst_c2->topo_groups) ? topo_node_find_by_id(topo_groups_get_default(inst_c2->topo_groups), g_node_id_c1) : NULL;
if (node_c1_on_c2 && node_c1_on_c2->node) {
for (const struct TOPO_SOCKMETA4* m = node_c1_on_c2->node->v4_sock_meta; m; m = m->next) {
node_c1_on_c2 = topo_groups_get_default(inst_c2->topo_groups) ? topo_node_find_by_id(topo_groups_get_default(inst_c2->topo_groups), g_node_id_c1) : NULL;
cni = node_c1_on_c2 ? topo_node_registry_find(inst_c2->topo_groups, node_c1_on_c2->node_id) : NULL;
if (node_c1_on_c2 && cni) {
for (const struct TOPO_SOCKMETA4* m = cni->v4_sock_meta; m; m = m->next) {
if (m->nat_type == NAT_VERIFIED_EIM) { c2_verified_nat = 1; break; }
}
if (c2_verified_nat) break;
@@ -433,7 +439,7 @@ int main(void) {
int ret = route_ping_send_req_addr(inst_s->nat_det, topo_groups_get_default(inst_s->topo_groups), conn_sc2,
target_ip_net, link_sc1->nat_port,
3, 10, 200, 3000, nat_ping_resp_cb, NULL,
node_c1->node->public_key);
node_c1_on_c2 ? topo_node_registry_find(inst_c2->topo_groups, node_c1_on_c2->node_id)->public_key : NULL);
if (ret != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr failed: %d", ret);
goto cleanup;
@@ -481,7 +487,7 @@ int main(void) {
ret = route_ping_send_req_addr(inst_s->nat_det, topo_groups_get_default(inst_s->topo_groups), conn_sc2,
target_ip_net, link_sc1->nat_port,
3, 10, 200, 3000, nat_ping_resp_cb, NULL,
node_c1->node->public_key);
cni->public_key);
if (ret != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr (no pubkey) failed: %d", ret);
goto cleanup;
+251
View File
@@ -0,0 +1,251 @@
/**
* @file test_node_conn_direct.c
* @brief Тест node_conn_direct с 2 инстансами.
*
* Фазы:
* 1 — два open ДО eventloop → NCD_NEW + NCD_REUSED(pending)
* 2 — poll → init_cb → NCD_EVENT_UP на обоих
* 3 — open на ready conn → NCD_REUSED + async cb
* 4 — ещё open → NCD_REUSED
* 5 — close h3,h2 → conn жив
* 6 — close h1,h0 (last) → conn закрыт (fin_wait → CLOSE → DOWN)
* 7 — NCD_ERR unknown node
* 8 — inject unreachable → NCD_NEW → TIMEOUT
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "../lib/platform_compat.h"
#include "test_utils.h"
#ifndef _WIN32
#include <unistd.h>
#endif
#include "etcp.h"
#include "etcp_connections.h"
#include "node_conn_direct.h"
#include "../src/config_parser.h"
#include "../src/config_updater.h"
#include "../src/utun_instance.h"
#include "topo_group.h"
#include "topo_node.h"
#include "secure_channel.h"
#include "../lib/u_async.h"
#include "../lib/ll_queue.h"
#include "../lib/memory_pool.h"
#include "../lib/debug_config.h"
#include "../lib/mem.h"
#define TIMEOUT_TB 600000
#define SHORT_TO_TB 50000
#define POLL_MS 5
static struct UTUN_INSTANCE *g_a = NULL, *g_b = NULL;
static struct UASYNC *ua = NULL;
static volatile int g_result = 0;
static int g_phase = 0;
static void *g_ttimer = NULL;
static char tdir[] = "/tmp/utun_ncd_XXXXXX";
static char ca[256], cb[256];
static int pa = 0, pb = 0;
static uint64_t nid_b = 0;
static uint8_t pubkey_b[SC_PUBKEY_SIZE];
static struct NODE_CONN_DIRECT *gh[4];
static volatile int g_up[4], g_down[4], g_tout[4];
static void ncd_cb(struct NODE_CONN_DIRECT* h, enum ncd_event event, void* arg) {
int idx = (int)(intptr_t)arg;
if (event == NCD_EVENT_UP) g_up[idx]++;
else if (event == NCD_EVENT_DOWN) g_down[idx]++;
else if (event == NCD_EVENT_TIMEOUT) g_tout[idx]++;
fprintf(stderr, " cb[%d]: event=%d (up=%d down=%d tout=%d)\n", idx, (int)event, g_up[idx], g_down[idx], g_tout[idx]); fflush(stderr);
}
static void to_cb(void* arg) { (void)arg; fprintf(stderr, "GLOBAL TIMEOUT phase=%d\n", g_phase); g_result = 2; }
static int wf(const char* p, const char* f, ...) { va_list ap; FILE* fp = fopen(p, "w"); if (!fp) return -1; va_start(ap, f); vfprintf(fp, f, ap); va_end(ap); fclose(fp); return 0; }
static void fail(const char* msg) { fprintf(stderr, "FAIL[%d]: %s\n", g_phase, msg); fflush(stderr); g_result = 2; }
static void t1(void* arg); static void t2(void* arg); static void t3(void* arg);
static void t4(void* arg); static void t5(void* arg); static void t6(void* arg);
static void t7(void* arg); static void t8(void* arg); static void t9(void* arg);
static void t_done(void* arg);
static void t1(void* arg) {
(void)arg; g_phase = 1;
fprintf(stderr, "\n=== P1: two opens before poll ===\n"); fflush(stderr);
g_a->etcp_connect_timeout_tb = TIMEOUT_TB;
int r = node_conn_direct_open(g_a, nid_b, 0, ncd_cb, (void*)0, &gh[0]);
fprintf(stderr, " open#0 → %s\n", r == NCD_NEW ? "NCD_NEW" : r == NCD_REUSED ? "NCD_REUSED" : "ERR");
if (r != NCD_NEW) { fail("expected NCD_NEW"); return; }
r = node_conn_direct_open(g_a, nid_b, 0, ncd_cb, (void*)1, &gh[1]);
fprintf(stderr, " open#1 → %s\n", r == NCD_NEW ? "NCD_NEW" : r == NCD_REUSED ? "NCD_REUSED" : "ERR");
if (r != NCD_REUSED) { fail("expected NCD_REUSED"); return; }
uasync_call_soon(ua, NULL, t2);
}
static void t2(void* arg) {
(void)arg; g_phase = 2;
if (g_up[0] > 0 && g_up[1] > 0) {
if (node_conn_direct_get_conn(gh[0]) == NULL) { fail("get_conn h0 NULL"); return; }
if (node_conn_direct_get_conn(gh[1]) == NULL) { fail("get_conn h1 NULL"); return; }
fprintf(stderr, "\n=== P2: both up, get_conn OK ===\n"); fflush(stderr);
uasync_call_soon(ua, NULL, t3); return;
}
uasync_set_timeout(ua, POLL_MS, NULL, (timeout_callback_t)t2, "t2");
}
static void t3(void* arg) {
(void)arg; g_phase = 3;
fprintf(stderr, "\n=== P3: open on ready conn ===\n"); fflush(stderr);
int r = node_conn_direct_open(g_a, nid_b, 0, ncd_cb, (void*)2, &gh[2]);
fprintf(stderr, " open#2 → %s\n", r == NCD_REUSED ? "NCD_REUSED" : "?");
if (r != NCD_REUSED) { fail("expected NCD_REUSED"); return; }
uasync_call_soon(ua, NULL, t4);
}
static void t4(void* arg) {
(void)arg; g_phase = 4;
if (g_up[2] == 0) { uasync_set_timeout(ua, POLL_MS, NULL, (timeout_callback_t)t4, "t4"); return; }
fprintf(stderr, "\n=== P4: async cb OK, open h3 ===\n"); fflush(stderr);
int r = node_conn_direct_open(g_a, nid_b, 0, ncd_cb, (void*)3, &gh[3]);
fprintf(stderr, " open#3 → %s\n", r == NCD_REUSED ? "NCD_REUSED" : "?");
if (r != NCD_REUSED) { fail("expected NCD_REUSED"); return; }
uasync_call_soon(ua, NULL, t5);
}
static void t5(void* arg) {
(void)arg; g_phase = 5;
if (g_up[3] == 0) { uasync_set_timeout(ua, POLL_MS, NULL, (timeout_callback_t)t5, "t5"); return; }
fprintf(stderr, "\n=== P5: close h3, h2 → conn stays ===\n"); fflush(stderr);
node_conn_direct_close(gh[3]); gh[3] = NULL;
if (node_conn_direct_get_conn(gh[2]) == NULL) { fail("conn died after h3 close"); return; }
node_conn_direct_close(gh[2]); gh[2] = NULL;
if (node_conn_direct_get_conn(gh[1]) == NULL) { fail("conn died after h2 close"); return; }
fprintf(stderr, " OK\n"); fflush(stderr);
uasync_call_soon(ua, NULL, t6);
}
static void t6(void* arg) {
(void)arg; g_phase = 6;
fprintf(stderr, "\n=== P6: close last → conn closed ===\n"); fflush(stderr);
node_conn_direct_close(gh[1]); gh[1] = NULL;
if (node_conn_direct_get_conn(gh[0]) == NULL) { fail("conn died before last handle"); return; }
node_conn_direct_close(gh[0]); gh[0] = NULL;
fprintf(stderr, " OK\n"); fflush(stderr);
uasync_set_timeout(ua, 200, NULL, (timeout_callback_t)t7, "t6d");
}
static void t7(void* arg) {
(void)arg; g_phase = 7;
fprintf(stderr, "\n=== P7: NCD_ERR unknown node ===\n"); fflush(stderr);
struct NODE_CONN_DIRECT* hx = NULL;
int r = node_conn_direct_open(g_a, 0xDEADBEEF00000001ULL, 0, ncd_cb, (void*)99, &hx);
fprintf(stderr, " open(unknown) → %s\n", r == NCD_ERR ? "NCD_ERR" : "?");
if (r != NCD_ERR) { fail("expected NCD_ERR"); return; }
if (hx != NULL) { fail("handle not NULL"); return; }
fprintf(stderr, " OK\n"); fflush(stderr);
uasync_call_soon(ua, NULL, t8);
}
static void t8(void* arg) {
(void)arg; g_phase = 8;
fprintf(stderr, "\n=== P8: unreachable node → timeout ===\n"); fflush(stderr);
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
if (!ni) { fail("alloc ni"); return; }
uint64_t fake_id = 0xF000000000000001ULL;
ni->group_ref_count = 0; ni->node_id = fake_id; ni->ver = 0;
memcpy(ni->public_key, pubkey_b, SC_PUBKEY_SIZE);
struct TOPO_SOCKMETA4* sm = memory_pool_alloc(g_a->topo_groups->v4_sock_meta_pool);
if (sm) { sm->id = 0; sm->config_type = CFG_SERVER_TYPE_PUBLIC; sm->nat_type = NAT_TYPE_UNKNOWN; sm->next = ni->v4_sock_meta; ni->v4_sock_meta = sm; }
struct TOPO_ADDR4* addr = memory_pool_alloc(g_a->topo_groups->v4_addr_pool);
if (addr) { addr->addr[0]=127; addr->addr[1]=0; addr->addr[2]=0; addr->addr[3]=1; addr->port=1; addr->type=TOPO_ADDR_INTERFACE; addr->socket_id=0; addr->protocol=TOPO_PROTO_UDP; addr->next=ni->v4_addrs; ni->v4_addrs=addr; }
if (!topo_node_registry_store(g_a->topo_groups, ni)) { fail("registry acquire"); return; }
memset((void*)g_up, 0, sizeof(g_up));
memset((void*)g_tout, 0, sizeof(g_tout));
g_a->etcp_connect_timeout_tb = SHORT_TO_TB;
int r = node_conn_direct_open(g_a, fake_id, 0, ncd_cb, (void*)0, &gh[0]);
fprintf(stderr, " open(unreachable) → %s\n", r == NCD_NEW ? "NCD_NEW" : "?");
if (r != NCD_NEW) { fail("expected NCD_NEW"); return; }
uasync_call_soon(ua, NULL, t9);
}
static void t9(void* arg) {
(void)arg; g_phase = 9;
if (g_tout[0] == 0) { uasync_set_timeout(ua, POLL_MS, NULL, (timeout_callback_t)t9, "t9"); return; }
if (g_up[0] > 0) { fail("up fired, expected only timeout"); return; }
fprintf(stderr, "\n=== P9: timeout_cb fired, no up ===\n"); fflush(stderr);
node_conn_direct_close(gh[0]); gh[0] = NULL;
uasync_call_soon(ua, NULL, t_done);
}
static void t_done(void* arg) {
(void)arg; g_phase = 99;
fprintf(stderr, "\n=== ALL PASSED ===\n"); fflush(stderr);
g_result = 1;
}
static int inject_node(struct UTUN_INSTANCE* inst, uint64_t nid, const uint8_t pk[SC_PUBKEY_SIZE], uint16_t port) {
if (!inst->topo_groups) return -1;
struct TOPO_NODE* ni = u_calloc(1, sizeof(*ni));
if (!ni) return -1;
ni->group_ref_count = 0; ni->node_id = nid; ni->ver = 0;
memcpy(ni->public_key, pk, SC_PUBKEY_SIZE);
struct TOPO_SOCKMETA4* sm = memory_pool_alloc(inst->topo_groups->v4_sock_meta_pool);
if (sm) { sm->id = 0; sm->config_type = CFG_SERVER_TYPE_PUBLIC; sm->nat_type = NAT_TYPE_UNKNOWN; sm->next = ni->v4_sock_meta; ni->v4_sock_meta = sm; }
struct TOPO_ADDR4* addr = memory_pool_alloc(inst->topo_groups->v4_addr_pool);
if (addr) { addr->addr[0]=127; addr->addr[1]=0; addr->addr[2]=0; addr->addr[3]=1; addr->port=port; addr->type=TOPO_ADDR_INTERFACE; addr->socket_id=0; addr->protocol=TOPO_PROTO_UDP; addr->next=ni->v4_addrs; ni->v4_addrs=addr; }
if (!topo_node_registry_store(inst->topo_groups, ni)) { u_free(ni); return -1; }
return 0;
}
static int setup(void) {
test_mkdtemp(tdir);
int base = 49000 + (getpid() % 10000); pa = base; pb = base + 1;
snprintf(ca, sizeof(ca), "%s/a.conf", tdir); snprintf(cb, sizeof(cb), "%s/b.conf", tdir);
wf(ca, "[global]\ntun_ip=10.97.0.1/24\ntun_ifname=tun95\n[server: s1]\naddr=127.0.0.1:%d\ntype=public\n[allowed_keys]\nallow_all=1\n", pa);
wf(cb, "[global]\ntun_ip=10.97.0.2/24\ntun_ifname=tun94\n[server: s1]\naddr=127.0.0.1:%d\ntype=public\n[allowed_keys]\nallow_all=1\n", pb);
config_ensure_keys_and_node_id(ca); config_ensure_keys_and_node_id(cb);
return 0;
}
static void cleanup(void) { test_unlink(ca); test_unlink(cb); test_rmdir(tdir); }
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN);
utun_instance_set_tun_init_enabled(0);
if (setup() != 0) return 1;
ua = uasync_create();
g_a = utun_instance_create(ua, ca); g_b = utun_instance_create(ua, cb);
if (!g_a || !g_b) { g_result = 2; goto done; }
nid_b = g_b->node_id; memcpy(pubkey_b, g_b->my_keys.public_key, SC_PUBKEY_SIZE);
fprintf(stderr, "B: 0x%016llx port=%d\n", (unsigned long long)nid_b, pb); fflush(stderr);
utun_instance_init(g_a); utun_instance_init(g_b);
if (inject_node(g_a, nid_b, pubkey_b, pb) != 0) { fail("inject_node"); goto done; }
fprintf(stderr, "injected B into A registry\n"); fflush(stderr);
uasync_call_soon(ua, NULL, t1);
g_ttimer = uasync_set_timeout(ua, TIMEOUT_TB, NULL, to_cb, "to");
{ uint64_t st = get_time_tb(); while (!g_result && (int)(get_time_tb() - st) < TIMEOUT_TB + 50000) uasync_poll(ua, POLL_MS); }
if (g_result == 0) g_result = 2;
done:
if (g_ttimer && ua) uasync_cancel_timeout(ua, g_ttimer);
for (int i = 0; i < 4; i++) if (gh[i]) node_conn_direct_close(gh[i]);
if (g_a) { g_a->running = 0; utun_instance_destroy(g_a); }
if (g_b) { g_b->running = 0; utun_instance_destroy(g_b); }
if (ua) uasync_destroy(ua, 0);
cleanup();
fprintf(stderr, "\n%s\n", g_result == 1 ? "=== TEST PASSED ===" : "=== TEST FAILED ==="); fflush(stderr);
return (g_result == 1) ? 0 : 1;
}
+20 -21
View File
@@ -19,14 +19,14 @@ static int tests_run = 0;
/* ──── helpers ──── */
static struct TOPO_NODEQ *make_node(uint64_t node_id,
static struct TOPO_GROUP_NODE *make_node(uint64_t node_id,
const uint8_t addrs[][16],
const uint8_t *plens, int N) {
struct TOPO_NODEQ *nq = u_calloc(1, sizeof(*nq));
struct TOPO_GROUP_NODE *nq = u_calloc(1, sizeof(*nq));
struct TOPO_NODE *ni = u_calloc(1, sizeof(struct TOPO_NODE));
if (!nq || !ni) { u_free(nq); u_free(ni); return NULL; }
ni->ref_count = 1; ni->node_id = node_id;
nq->node = ni; nq->hash_node_id = node_id;
ni->group_ref_count = 1; ni->node_id = node_id;
nq->node_id = node_id;
if (N > 0) {
struct TOPO_NODESUBNETS *r = u_calloc(1, sizeof(struct TOPO_NODESUBNETS));
nq->subnets = r;
@@ -41,14 +41,13 @@ static struct TOPO_NODEQ *make_node(uint64_t node_id,
return nq;
}
static void free_node(struct TOPO_NODEQ *nq) {
static void free_node(struct TOPO_GROUP_NODE *nq) {
if (nq) {
if (nq->subnets) {
struct TOPO_SUBNET6 *s = nq->subnets->v6_subnets;
while (s) { struct TOPO_SUBNET6 *next = s->next; u_free(s); s = next; }
u_free(nq->subnets);
}
if (nq->node) u_free(nq->node);
u_free(nq);
}
}
@@ -69,7 +68,7 @@ static void test_insert_null_args(void) {
assert(t != NULL);
assert(route6_insert(NULL, NULL) == false);
assert(route6_insert(t, NULL) == false);
assert(route6_insert(NULL, t ? (struct TOPO_NODEQ*)(uintptr_t)t : NULL) == false);
assert(route6_insert(NULL, t ? (struct TOPO_GROUP_NODE*)(uintptr_t)t : NULL) == false);
route6_table_destroy(t);
uasync_destroy(ua, 0);
}
@@ -81,7 +80,7 @@ static void test_insert_zero_subnets(void) {
int addr[16] = {0};
uint8_t zero_plen = 0;
struct TOPO_NODEQ *nq = make_node(1, (const uint8_t(*)[16])addr, &zero_plen, 0);
struct TOPO_GROUP_NODE *nq = make_node(1, (const uint8_t(*)[16])addr, &zero_plen, 0);
assert(route6_insert(t, nq) == false);
const uint8_t any[16] = {0};
@@ -99,7 +98,7 @@ static void test_insert_duplicate(void) {
uint8_t addr[16] = {0xfd, 0};
uint8_t plen = 64;
struct TOPO_NODEQ *nq = make_node(10, &addr, &plen, 1);
struct TOPO_GROUP_NODE *nq = make_node(10, &addr, &plen, 1);
assert(route6_insert(t, nq) == true);
assert(route6_insert(t, nq) == true); // re-insert should not crash
@@ -117,7 +116,7 @@ static void test_insert_delete_reinsert(void) {
uint8_t addrs[2][16] = {{0xfd, 1}, {0xfd, 2}};
uint8_t plens[2] = {64, 64};
struct TOPO_NODEQ *nq = make_node(20, addrs, plens, 2);
struct TOPO_GROUP_NODE *nq = make_node(20, addrs, plens, 2);
assert(route6_insert(t, nq) == true);
assert(route6_lookup(t, addrs[0]) != NULL);
@@ -146,8 +145,8 @@ static void test_delete_nonexistent(void) {
uint8_t addr[16] = {0xfd, 10};
uint8_t plen = 64;
struct TOPO_NODEQ *nq1 = make_node(1, &addr, &plen, 1);
struct TOPO_NODEQ *nq2 = make_node(2, &addr, &plen, 1);
struct TOPO_GROUP_NODE *nq1 = make_node(1, &addr, &plen, 1);
struct TOPO_GROUP_NODE *nq2 = make_node(2, &addr, &plen, 1);
assert(route6_insert(t, nq1) == true);
route6_delete(t, nq2); // nq2 not in table — should not crash
@@ -165,7 +164,7 @@ static void test_delete_null_args(void) {
route6_delete(NULL, NULL);
route6_delete(t, NULL);
route6_delete(NULL, (struct TOPO_NODEQ*)(uintptr_t)t);
route6_delete(NULL, (struct TOPO_GROUP_NODE*)(uintptr_t)t);
route6_table_destroy(t);
uasync_destroy(ua, 0);
@@ -178,7 +177,7 @@ static void test_delete_multi_subnet(void) {
uint8_t addrs[3][16] = {{0xfc, 1}, {0xfc, 2}, {0xfc, 3}};
uint8_t plens[3] = {48, 56, 64};
struct TOPO_NODEQ *nq = make_node(30, addrs, plens, 3);
struct TOPO_GROUP_NODE *nq = make_node(30, addrs, plens, 3);
assert(route6_insert(t, nq) == true);
assert(route6_lookup(t, addrs[0]) != NULL);
@@ -204,8 +203,8 @@ static void test_delete_one_of_two(void) {
uint8_t addr_a[16] = {0xfc, 0};
uint8_t addr_b[16] = {0xfd, 0};
uint8_t plen = 64;
struct TOPO_NODEQ *nqa = make_node(100, &addr_a, &plen, 1);
struct TOPO_NODEQ *nqb = make_node(200, &addr_b, &plen, 1);
struct TOPO_GROUP_NODE *nqa = make_node(100, &addr_a, &plen, 1);
struct TOPO_GROUP_NODE *nqb = make_node(200, &addr_b, &plen, 1);
assert(route6_insert(t, nqa) == true);
assert(route6_insert(t, nqb) == true);
@@ -240,7 +239,7 @@ static void test_lookup_returns_correct_data(void) {
uint8_t addr[16] = {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
uint8_t plen = 64;
struct TOPO_NODEQ *nq = make_node(42, &addr, &plen, 1);
struct TOPO_GROUP_NODE *nq = make_node(42, &addr, &plen, 1);
assert(route6_insert(t, nq) == true);
const struct ROUTE6_DATA *rd = route6_lookup(t, addr);
@@ -301,7 +300,7 @@ static void test_stress(void) {
struct saved_route sr[MAX_SAVED];
int nsr = 0;
struct TOPO_NODEQ *nodes[STRESS_NODES + STRESS_OPS];
struct TOPO_GROUP_NODE *nodes[STRESS_NODES + STRESS_OPS];
// create nodes with random subnets
int n_created = 0;
@@ -333,7 +332,7 @@ static void test_stress(void) {
if (rand() % 10 < 6 && n_created > 0) {
// delete random active node
int idx = rand() % n_created;
uint64_t nid = nodes[idx]->node->node_id;
uint64_t nid = nodes[idx]->node_id;
route6_delete(t, nodes[idx]);
// mark all routes of this node inactive
for (int j = 0; j < nsr; j++) {
@@ -392,7 +391,7 @@ static void test_stress(void) {
{
uint8_t addr[16] = {0xfc, 0};
uint8_t plen = 64;
struct TOPO_NODEQ *ghost = make_node(999999, &addr, &plen, 1);
struct TOPO_GROUP_NODE *ghost = make_node(999999, &addr, &plen, 1);
route6_delete(t, ghost); // should no-op
free_node(ghost);
}
@@ -401,7 +400,7 @@ static void test_stress(void) {
{
uint8_t addr[16] = {0};
uint8_t zero_plen = 0;
struct TOPO_NODEQ *z = make_node(777, (const uint8_t(*)[16])addr, &zero_plen, 0);
struct TOPO_GROUP_NODE *z = make_node(777, (const uint8_t(*)[16])addr, &zero_plen, 0);
assert(route6_insert(t, z) == false);
free_node(z);
}
+13 -15
View File
@@ -2,7 +2,7 @@
* FULL REFACTORED TEST for new NODEINFO-based routing system
*
* Tests:
* - TOPO_NODEQ creation and insertion
* - TOPO_GROUP_NODE creation and insertion
* - paths management (add/remove)
* - versioning (ver field)
* - WITHDRAW when no paths left
@@ -40,17 +40,16 @@ struct UTUN_INSTANCE {
struct TOPO_GROUP* group;
};
/* Helper to create test TOPO_NODEQ with subnet in linked list */
static struct TOPO_NODEQ* create_test_node(uint64_t node_id, uint8_t ver, uint32_t subnet_net, uint8_t prefix) {
struct TOPO_NODEQ* nq = u_calloc(1, sizeof(struct TOPO_NODEQ));
/* Helper to create test TOPO_GROUP_NODE with subnet in linked list */
static struct TOPO_GROUP_NODE* create_test_node(uint64_t node_id, uint8_t ver, uint32_t subnet_net, uint8_t prefix) {
struct TOPO_GROUP_NODE* nq = u_calloc(1, sizeof(struct TOPO_GROUP_NODE));
if (!nq) return NULL;
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
if (!ni) { u_free(nq); return NULL; }
ni->ref_count = 1;
ni->group_ref_count = 1;
ni->node_id = htobe64(node_id);
ni->ver = ver;
nq->node = ni;
nq->hash_node_id = ni->node_id;
nq->node_id = ni->node_id;
nq->hop_count = 0;
nq->paths = queue_new(NULL, 16, 0, 0, "test_paths");
struct TOPO_NODESUBNETS* r = u_calloc(1, sizeof(struct TOPO_NODESUBNETS));
@@ -64,11 +63,10 @@ static struct TOPO_NODEQ* create_test_node(uint64_t node_id, uint8_t ver, uint32
return nq;
}
static void free_test_node(struct TOPO_NODEQ* nq) {
static void free_test_node(struct TOPO_GROUP_NODE* nq) {
if (nq) {
if (nq->paths) queue_free(nq->paths);
if (nq->subnets) { u_free(nq->subnets->v4_subnets); u_free(nq->subnets); }
if (nq->node) { u_free(nq->node->node_name); u_free(nq->node); }
u_free(nq);
}
}
@@ -118,9 +116,9 @@ static void test_table_create_destroy(void) {
}
static void test_nodeinfo_insert(void) {
TEST("TOPO_NODEQ insert into routing table");
TEST("TOPO_GROUP_NODE insert into routing table");
struct ROUTE_TABLE *t = route_table_create();
struct TOPO_NODEQ* nq = create_test_node(0x12345678ULL, 1, 0x0a000000, 8);
struct TOPO_GROUP_NODE* nq = create_test_node(0x12345678ULL, 1, 0x0a000000, 8);
bool inserted = route_insert(t, nq);
ASSERT(inserted, "insert nodeinfo");
@@ -134,8 +132,8 @@ static void test_nodeinfo_insert(void) {
static void test_versioning(void) {
TEST("NODEINFO multiple nodes");
struct ROUTE_TABLE *t = route_table_create();
struct TOPO_NODEQ* nq1 = create_test_node(0x1111ULL, 5, 0x0a000000, 8);
struct TOPO_NODEQ* nq2 = create_test_node(0x2222ULL, 1, 0xac100000, 12);
struct TOPO_GROUP_NODE* nq1 = create_test_node(0x1111ULL, 5, 0x0a000000, 8);
struct TOPO_GROUP_NODE* nq2 = create_test_node(0x2222ULL, 1, 0xac100000, 12);
route_insert(t, nq1);
bool ins2 = route_insert(t, nq2);
@@ -157,7 +155,7 @@ static void test_performance_1000_nodes(void) {
for (int i = 0; i < 1000; i++) {
uint32_t sub = 0x0a000000 + (i * 0x100); /* distinct 10.0.x.0/24 to avoid overlap */
struct TOPO_NODEQ* nq = create_test_node(0x1000000ULL + i, 1, sub, 24);
struct TOPO_GROUP_NODE* nq = create_test_node(0x1000000ULL + i, 1, sub, 24);
route_insert(t, nq);
/* note: nq not freed here (table holds ref to it), freed in test cleanup if needed */
}
@@ -175,7 +173,7 @@ static void test_performance_1000_nodes(void) {
static void test_destroy_refcount(void) {
TEST("destroy with multiple paths (ref_count safety)");
struct ROUTE_TABLE *t = route_table_create();
/* TOPO_NODEQ memory managed externally, table only holds pointers */
/* TOPO_GROUP_NODE memory managed externally, table only holds pointers */
route_table_destroy(t);
PASS();
}
+5 -4
View File
@@ -268,9 +268,10 @@ int main(void) {
/* addr[] в network byte order, port в host byte order */
uint32_t target_ip = 0;
uint16_t target_port = 0;
struct TOPO_NODEQ* nq = topo_groups_get_default(inst_b->topo_groups) ? topo_node_find_by_id(topo_groups_get_default(inst_b->topo_groups), g_node_id_c) : NULL;
if (nq && nq->node) {
const struct TOPO_ADDR4* a = nq->node->v4_addrs;
struct TOPO_GROUP_NODE* nq = topo_groups_get_default(inst_b->topo_groups) ? topo_node_find_by_id(topo_groups_get_default(inst_b->topo_groups), g_node_id_c) : NULL;
struct TOPO_NODE* ni = nq ? topo_node_registry_find(inst_b->topo_groups, nq->node_id) : NULL;
if (nq && ni) {
const struct TOPO_ADDR4* a = ni->v4_addrs;
if (a) {
memcpy(&target_ip, a->addr, 4);
target_port = a->port;
@@ -290,7 +291,7 @@ int main(void) {
200, // timeout_ms
5000,// wait_timeout_ms
ping_resp_cb, NULL,
nq ? nq->node->public_key : NULL);
ni ? ni->public_key : NULL);
if (ret != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr failed: %d", ret);
goto cleanup;
+10 -1
View File
@@ -167,8 +167,17 @@ int main(void) {
TASSERT(etcp_bind(srv_inst, 1, srv_recv_cb) >= 0);
TASSERT(etcp_bind(cli_inst, 2, cli_recv_cb) >= 0);
struct TOPO_NODEQ *srv_node = topo_groups_get_default(srv_inst->topo_groups) ? topo_groups_get_default(srv_inst->topo_groups)->local_node : NULL;
struct TOPO_GROUP_NODE *srv_node = topo_groups_get_default(srv_inst->topo_groups) ? topo_groups_get_default(srv_inst->topo_groups)->local_node : NULL;
TASSERT(srv_node);
{ struct TOPO_NODE* srv_ni = topo_node_registry_find(srv_inst->topo_groups, srv_node->node_id); TASSERT(srv_ni);
struct TOPO_NODE* cli_ni = u_calloc(1, sizeof(struct TOPO_NODE));
TASSERT(cli_ni); memcpy(cli_ni, srv_ni, sizeof(struct TOPO_NODE)); cli_ni->group_ref_count = 0;
cli_ni->v4_sock_meta = NULL; cli_ni->v4_addrs = NULL; cli_ni->v6_sock_meta = NULL; cli_ni->v6_addrs = NULL;
struct TOPO_ADDR4* a = memory_pool_alloc(cli_inst->topo_groups->v4_addr_pool);
TASSERT(a); a->addr[0]=127; a->addr[1]=0; a->addr[2]=0; a->addr[3]=1; a->port = port;
a->type = TOPO_ADDR_INTERFACE; a->socket_id = 0; a->protocol = TOPO_PROTO_TCP;
a->next = cli_ni->v4_addrs; cli_ni->v4_addrs = a;
topo_node_registry_store(cli_inst->topo_groups, cli_ni); }
// Increase timeout for TCP STCP handshake
cli_inst->etcp_connect_timeout_tb = 100000; // 10 seconds
TASSERT(etcp_connect(cli_inst, srv_node, connect_cb, NULL, ETCP_CONNECT_EARLY | ETCP_CONNECT_LATE) == 0);