You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

348 lines
13 KiB

/**
* @file test_ipv6_sockets.c
* @brief Тест IPv6 сокетов: подключение, nodeinfo, BGP-обмен
*
* Проверяет:
* - Создание и бинд AF_INET6 сокета
* - IPv6 подключение клиент→сервер
* - Заполнение local_v6_sockets/addrs/subnets в nodeinfo
* - Корректность NODEINFO_IPV6_SOCKET_META и NODEINFO_IPV6_ADDR
* - Передачу IPv6 адресов через BGP соседнему узлу
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include "../lib/platform_compat.h"
#include "test_utils.h"
#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#else
#include <unistd.h>
#endif
#include "../src/etcp.h"
#include "../src/etcp_connections.h"
#include "../src/config_parser.h"
#include "../src/utun_instance.h"
#include "../src/routing.h"
#include "../src/route_lib.h"
#include "../src/route_bgp.h"
#include "../src/route_node.h"
#include "../src/tun_if.h"
#include "../src/secure_channel.h"
#include "../lib/u_async.h"
#include "../lib/debug_config.h"
#define TEST_TIMEOUT_MS 8000
static struct UTUN_INSTANCE* server_instance = NULL;
static struct UTUN_INSTANCE* client_instance = NULL;
static struct UASYNC* ua = NULL;
static int test_phase = 0;
static void* monitor_timer = NULL;
static void* timeout_timer = NULL;
static char temp_dir[] = "/tmp/utun_v6test_XXXXXX";
static char server_config_path[256];
static char client_config_path[256];
static const char* server_config =
"[global]\n"
"my_node_name=server_v6\n"
"my_node_id=0xAAAA000000000001\n"
"my_private_key=67b705a92b41bcaae105af2d6a17743faa7b26ccebba8b3b9b0af05e9cd1d5fb\n"
"my_public_key=1c55e4ccae7c4470707759086738b10681bf88b81f198cc2ab54a647d1556e17c65e6b1833e0c771e5a39382c03067c388915a4c732191bc130480f20f8e00b9\n"
"tun_ip=10.99.0.1/24\n"
"tun_ifname=tun99\n"
"tun_test_mode=1\n"
"\n"
"[routing]\n"
"my_subnet=2001:db8:1::/48\n"
"\n"
"[server: v6srv]\n"
"addr=[::1]:40111\n"
"type=public\n"
"\n"
"[allowed_keys]\n"
"allow_all=1\n";
static const char* client_config =
"[global]\n"
"my_node_name=client_v6\n"
"my_node_id=0xBBBB000000000002\n"
"my_private_key=4813d31d28b7e9829247f488c6be7672f2bdf61b2508333128e386d1759afed2\n"
"my_public_key=c594f33c91f3a2222795c2c110c527bf214ad1009197ce14556cb13df3c461b3c373bed8f205a8dd1fc0c364f90bf471d7c6f5db49564c33e4235d268569ac71\n"
"tun_ip=10.99.0.2/24\n"
"tun_ifname=tun98\n"
"tun_test_mode=1\n"
"\n"
"[server: v6srv]\n"
"addr=[::1]:40112\n"
"type=public\n"
"\n"
"[client: v6client]\n"
"keepalive=1\n"
"peer_public_key=1c55e4ccae7c4470707759086738b10681bf88b81f198cc2ab54a647d1556e17c65e6b1833e0c771e5a39382c03067c388915a4c732191bc130480f20f8e00b9\n"
"link=v6srv:[::1]:40111\n";
static int create_temp_configs(void) {
if (test_mkdtemp(temp_dir) != 0) {
fprintf(stderr, "Failed to create temp directory\n");
return -1;
}
snprintf(server_config_path, sizeof(server_config_path), "%s/server.conf", temp_dir);
snprintf(client_config_path, sizeof(client_config_path), "%s/client.conf", temp_dir);
FILE* f = fopen(server_config_path, "w");
if (!f) { fprintf(stderr, "Failed to create server config\n"); return -1; }
fprintf(f, "%s", server_config);
fclose(f);
f = fopen(client_config_path, "w");
if (!f) { fprintf(stderr, "Failed to create client config\n"); test_unlink(server_config_path); return -1; }
fprintf(f, "%s", client_config);
fclose(f);
return 0;
}
static void cleanup_temp_configs(void) {
if (server_config_path[0]) test_unlink(server_config_path);
if (client_config_path[0]) test_unlink(client_config_path);
if (temp_dir[0]) test_rmdir(temp_dir);
}
static int is_connection_established(struct UTUN_INSTANCE* inst) {
if (!inst) return 0;
struct ETCP_CONN* conn = inst->connections;
while (conn) {
struct ETCP_LINK* link = conn->links;
while (link) {
if (link->initialized) return 1;
link = link->next;
}
conn = conn->next;
}
return 0;
}
static int verify_ipv6_local_nodeinfo(const char* name, struct UTUN_INSTANCE* inst,
int expect_socks, int expect_addrs, int expect_subnets) {
if (!inst || !inst->bgp || !inst->bgp->local_node) {
printf("FAIL [%s]: no bgp/local_node\n", name);
return 0;
}
struct NODEINFO* ni = &inst->bgp->local_node->node;
struct ETCP_SOCKET* es = inst->etcp_sockets;
// Check socket family
int v6_sock_found = 0;
while (es) {
if (es->local_addr.ss_family == AF_INET6) { v6_sock_found = 1; break; }
es = es->next;
}
if (!v6_sock_found) { printf("FAIL [%s]: no AF_INET6 socket\n", name); return 0; }
printf("PASS [%s]: AF_INET6 socket exists\n", name);
// Check nodeinfo counts
if ((int)ni->local_v6_sockets != expect_socks) {
printf("FAIL [%s]: local_v6_sockets=%d expected=%d\n", name, ni->local_v6_sockets, expect_socks); return 0;
}
printf("PASS [%s]: local_v6_sockets=%d\n", name, ni->local_v6_sockets);
if ((int)ni->local_v6_addrs != expect_addrs) {
printf("FAIL [%s]: local_v6_addrs=%d expected=%d\n", name, ni->local_v6_addrs, expect_addrs); return 0;
}
printf("PASS [%s]: local_v6_addrs=%d\n", name, ni->local_v6_addrs);
if ((int)ni->local_v6_subnets != expect_subnets) {
printf("FAIL [%s]: local_v6_subnets=%d expected=%d\n", name, ni->local_v6_subnets, expect_subnets); return 0;
}
printf("PASS [%s]: local_v6_subnets=%d\n", name, ni->local_v6_subnets);
// Verify socket meta
const struct NODEINFO_IPV6_SOCKET_META* meta;
int mc = get_node_v6_sockets_meta(inst->bgp->local_node, &meta);
if (mc != expect_socks || !meta) { printf("FAIL [%s]: v6 sockets meta retrieval failed\n", name); return 0; }
for (int i = 0; i < mc; i++) {
if (meta[i].type != CFG_SERVER_TYPE_PUBLIC) {
printf("FAIL [%s]: v6 socket meta[%d] type=%d expected=%d\n", name, i, meta[i].type, CFG_SERVER_TYPE_PUBLIC); return 0;
}
printf("PASS [%s]: v6 socket meta[%d] id=%d type=%d\n", name, i, meta[i].id, meta[i].type);
}
// Verify IPv6 addresses
const struct NODEINFO_IPV6_ADDR* addrs;
int ac = get_node_v6_addrs(inst->bgp->local_node, &addrs);
if (ac != expect_addrs || !addrs) { printf("FAIL [%s]: v6 addrs retrieval failed\n", name); return 0; }
for (int i = 0; i < ac; i++) {
if (addrs[i].port == 0) { printf("FAIL [%s]: v6 addr port=0\n", name); return 0; }
if (addrs[i].type != ADDR_TYPE_INTERFACE) {
printf("FAIL [%s]: v6 addr[%d] type=%d expected=%d(INTERFACE)\n", name, i, addrs[i].type, ADDR_TYPE_INTERFACE); return 0;
}
if (addrs[i].type != ADDR_TYPE_INTERFACE) {
printf("FAIL [%s]: v6 addr[%d] type=%d expected=%d(INTERFACE)\n", name, i, addrs[i].type, ADDR_TYPE_INTERFACE); return 0;
}
printf("PASS [%s]: v6 addr[%d] port=%d type=%d socket_id=%d\n", name, i, addrs[i].port, addrs[i].type, addrs[i].socket_id);
}
// Verify IPv6 subnets
if (expect_subnets > 0) {
const struct NODEINFO_IPV6_SUBNET* subs;
const uint8_t* dyn_start = (const uint8_t*)ni + sizeof(struct NODEINFO);
const uint8_t* p = dyn_start + ni->node_name_len;
p += ni->local_v4_sockets * sizeof(struct NODEINFO_IPV4_SOCKET_META);
p += ni->local_v4_addrs * sizeof(struct NODEINFO_IPV4_ADDR);
p += ni->local_v6_sockets * sizeof(struct NODEINFO_IPV6_SOCKET_META);
p += ni->local_v6_addrs * sizeof(struct NODEINFO_IPV6_ADDR);
p += ni->local_v4_subnets * sizeof(struct NODEINFO_IPV4_SUBNET);
subs = (const struct NODEINFO_IPV6_SUBNET*)p;
uint8_t expected_sub[16] = {0x20,0x01,0x0d,0xb8,0x00,0x01,0,0,0,0,0,0,0,0,0,0};
if (memcmp(subs[0].addr, expected_sub, 16) != 0) {
printf("FAIL [%s]: v6 subnet != 2001:db8:1::/48\n", name); return 0;
}
if (subs[0].prefix_length != 48) {
printf("FAIL [%s]: v6 subnet prefix=%d expected=48\n", name, subs[0].prefix_length); return 0;
}
printf("PASS [%s]: v6 subnet 2001:db8:1::/48\n", name);
}
return 1;
}
static int verify_remote_v6_nodeinfo(const char* name, struct UTUN_INSTANCE* inst, uint64_t peer_node_id) {
if (!inst || !inst->bgp) {
printf("FAIL [%s]: no bgp\n", name);
return 0;
}
struct NODEINFO_Q* nq = route_bgp_get_node(inst->bgp, peer_node_id);
if (!nq) {
printf("FAIL [%s]: remote node %016llx not found\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.local_v6_sockets == 0) {
printf("FAIL [%s]: remote node has no v6 sockets\n", name);
return 0;
}
printf("PASS [%s]: remote node v6_sockets=%d\n", name, nq->node.local_v6_sockets);
if (nq->node.local_v6_addrs == 0) {
printf("FAIL [%s]: remote node has no v6 addrs\n", name);
return 0;
}
printf("PASS [%s]: remote node v6_addrs=%d\n", name, nq->node.local_v6_addrs);
const struct NODEINFO_IPV6_ADDR* addrs;
int ac = get_node_v6_addrs(nq, &addrs);
if (ac > 0 && addrs) {
uint8_t loopback[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
if (memcmp(addrs[0].addr, loopback, 16) != 0)
{ printf("FAIL [%s]: remote v6 addr not ::1\n", name); return 0; }
printf("PASS [%s]: remote v6 addr verified ::1 port=%d\n", name, addrs[0].port);
}
return 1;
}
static void timeout_cb(void* arg) {
(void)arg;
if (test_phase < 3) {
printf("=== TEST TIMEOUT ===\n");
test_phase = 4;
if (monitor_timer) { uasync_cancel_timeout(ua, monitor_timer); monitor_timer = NULL; }
}
}
static void monitor(void* arg) {
(void)arg;
if (test_phase >= 3) { monitor_timer = NULL; return; }
switch (test_phase) {
case 0: {
int srv_ok = is_connection_established(server_instance);
int cli_ok = is_connection_established(client_instance);
if (srv_ok && cli_ok) {
printf("Connection established, verifying nodeinfo...\n");
test_phase = 1;
monitor_timer = uasync_set_timeout(ua, 500, NULL, monitor, "v6_monitor");
return;
}
break;
}
case 1: {
int server_ok = verify_ipv6_local_nodeinfo("server_local", server_instance, 1, 1, 1);
int client_ok = verify_ipv6_local_nodeinfo("client_local", client_instance, 1, 1, 0);
if (!server_ok || !client_ok) { test_phase = 4; return; }
printf("Local nodeinfo verified, waiting for BGP exchange...\n");
test_phase = 2;
monitor_timer = uasync_set_timeout(ua, 500, NULL, monitor, "v6_monitor");
return;
}
case 2: {
int ok = verify_remote_v6_nodeinfo("client_remote", client_instance, 0xAAAA000000000001ULL);
if (!ok) { test_phase = 4; return; }
printf("=== ALL CHECKS PASSED ===\n");
test_phase = 3;
if (timeout_timer) { uasync_cancel_timeout(ua, timeout_timer); timeout_timer = NULL; }
return;
}
}
if (test_phase < 3) {
monitor_timer = uasync_set_timeout(ua, 100, NULL, monitor, "v6_monitor");
}
}
int main(void) {
printf("=== IPv6 Sockets + Nodeinfo Test ===\n\n");
if (create_temp_configs() != 0) {
fprintf(stderr, "Failed to create config files\n");
return 1;
}
debug_config_init();
debug_set_level(DEBUG_LEVEL_ERROR);
utun_instance_set_tun_init_enabled(0);
ua = uasync_create();
if (!ua) { fprintf(stderr, "uasync_create failed\n"); return 1; }
server_instance = utun_instance_create(ua, server_config_path);
if (!server_instance) { fprintf(stderr, "Server instance create failed\n"); return 1; }
if (utun_instance_init(server_instance) < 0) { fprintf(stderr, "Server init failed\n"); return 1; }
client_instance = utun_instance_create(ua, client_config_path);
if (!client_instance) { fprintf(stderr, "Client instance create failed\n"); return 1; }
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");
timeout_timer = uasync_set_timeout(ua, TEST_TIMEOUT_MS, NULL, timeout_cb, "v6_timeout");
while (test_phase < 3) uasync_poll(ua, -1);
if (timeout_timer) { uasync_cancel_timeout(ua, timeout_timer); timeout_timer = NULL; }
if (monitor_timer) { uasync_cancel_timeout(ua, monitor_timer); monitor_timer = NULL; }
if (server_instance) { server_instance->running = 0; utun_instance_destroy(server_instance); }
if (client_instance) { client_instance->running = 0; utun_instance_destroy(client_instance); }
if (ua) { uasync_destroy(ua, 0); ua = NULL; }
cleanup_temp_configs();
if (test_phase == 3) {
printf("\n=== TEST PASSED ===\n");
return 0;
}
printf("\n=== TEST FAILED ===\n");
return 1;
}