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.
314 lines
9.1 KiB
314 lines
9.1 KiB
// test_routing_mesh.c - Test routing between 3 instances in mesh topology |
|
// Based on test_etcp_two_instances.c approach - using config files |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include "test_utils.h" |
|
#include "../lib/platform_compat.h" |
|
#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/tun_if.h" |
|
#include "../src/secure_channel.h" |
|
#include "../lib/u_async.h" |
|
#include "../lib/debug_config.h" |
|
|
|
#define TEST_TIMEOUT_MS 10000 // 10 seconds timeout |
|
|
|
// Keys from test_etcp_two_instances.c (known working keys) |
|
// Instance A keys |
|
#define KEY_A_PRIV "67b705a92b41bcaae105af2d6a17743faa7b26ccebba8b3b9b0af05e9cd1d5fb" |
|
#define KEY_A_PUB "1c55e4ccae7c4470707759086738b10681bf88b81f198cc2ab54a647d1556e17c65e6b1833e0c771e5a39382c03067c388915a4c732191bc130480f20f8e00b9" |
|
|
|
// Instance B keys |
|
#define KEY_B_PRIV "4813d31d28b7e9829247f488c6be7672f2bdf61b2508333128e386d1759afed2" |
|
#define KEY_B_PUB "c594f33c91f3a2222795c2c110c527bf214ad1009197ce14556cb13df3c461b3c373bed8f205a8dd1fc0c364f90bf471d7c6f5db49564c33e4235d268569ac71" |
|
|
|
// Instance C keys (need valid keys - generate them) |
|
static char key_c_priv[65]; |
|
static char key_c_pub[129]; |
|
|
|
static struct UTUN_INSTANCE* inst_a = NULL; |
|
static struct UTUN_INSTANCE* inst_b = NULL; |
|
static struct UTUN_INSTANCE* inst_c = NULL; |
|
static struct UASYNC* ua = NULL; |
|
static int test_phase = 0; |
|
static void* timeout_id = NULL; |
|
|
|
static char temp_dir[] = "/tmp/utun_mesh_test_XXXXXX"; |
|
static char config_a[256], config_b[256], config_c[256]; |
|
|
|
// Config A: servers for B and C to connect to |
|
static const char* config_a_content = |
|
"[global]\n" |
|
"my_node_id=0xAAAAAAAAAAAAAAAA\n" |
|
"my_private_key=" KEY_A_PRIV "\n" |
|
"my_public_key=" KEY_A_PUB "\n" |
|
"tun_ip=10.99.1.1/24\n" |
|
"tun_ifname=tun_a\n" |
|
"tun_test_mode=1\n" |
|
"\n" |
|
"[routing]\n" |
|
"my_subnet=192.168.10.0/24\n" |
|
"my_subnet=192.168.11.0/24\n" |
|
"\n" |
|
"[server: b]\n" |
|
"addr=127.0.0.1:9101\n" |
|
"type=public\n" |
|
"\n" |
|
"[server: c]\n" |
|
"addr=127.0.0.1:9102\n" |
|
"type=public\n"; |
|
|
|
// Config B: servers for A and C to connect to |
|
static const char* config_b_content = |
|
"[global]\n" |
|
"my_node_id=0xBBBBBBBBBBBBBBBB\n" |
|
"my_private_key=" KEY_B_PRIV "\n" |
|
"my_public_key=" KEY_B_PUB "\n" |
|
"tun_ip=10.99.2.1/24\n" |
|
"tun_ifname=tun_b\n" |
|
"tun_test_mode=1\n" |
|
"\n" |
|
"[routing]\n" |
|
"my_subnet=192.168.20.0/24\n" |
|
"my_subnet=192.168.21.0/24\n" |
|
"\n" |
|
"[server: a]\n" |
|
"addr=127.0.0.1:9201\n" |
|
"type=public\n" |
|
"\n" |
|
"[server: c]\n" |
|
"addr=127.0.0.1:9202\n" |
|
"type=public\n"; |
|
|
|
// Config C: servers for A and B to connect to |
|
static const char* config_c_content_template = |
|
"[global]\n" |
|
"my_node_id=0xCCCCCCCCCCCCCCCC\n" |
|
"my_private_key=%s\n" |
|
"my_public_key=%s\n" |
|
"tun_ip=10.99.3.1/24\n" |
|
"tun_ifname=tun_c\n" |
|
"tun_test_mode=1\n" |
|
"\n" |
|
"[routing]\n" |
|
"my_subnet=192.168.30.0/24\n" |
|
"my_subnet=192.168.31.0/24\n" |
|
"\n" |
|
"[server: a]\n" |
|
"addr=127.0.0.1:9302\n" |
|
"type=public\n" |
|
"\n" |
|
"[server: b]\n" |
|
"addr=127.0.0.1:9303\n" |
|
"type=public\n"; |
|
|
|
// Client sections to add to configs for mesh topology |
|
static const char* client_a_content = |
|
"\n[client: to_b]\n" |
|
"keepalive=1\n" |
|
"peer_public_key=" KEY_B_PUB "\n" |
|
"link=b:127.0.0.1:9201\n" |
|
"\n[client: to_c]\n" |
|
"keepalive=1\n" |
|
"peer_public_key=%s\n" // Will be filled with C's key |
|
"link=c:127.0.0.1:9302\n"; |
|
|
|
static const char* client_b_content = |
|
"\n[client: to_a]\n" |
|
"keepalive=1\n" |
|
"peer_public_key=" KEY_A_PUB "\n" |
|
"link=a:127.0.0.1:9101\n" |
|
"\n[client: to_c]\n" |
|
"keepalive=1\n" |
|
"peer_public_key=%s\n" // Will be filled with C's key |
|
"link=c:127.0.0.1:9303\n"; |
|
|
|
static const char* client_c_content_template = |
|
"\n[client: to_a]\n" |
|
"keepalive=1\n" |
|
"peer_public_key=" KEY_A_PUB "\n" |
|
"link=a:127.0.0.1:9102\n" |
|
"\n[client: to_b]\n" |
|
"keepalive=1\n" |
|
"peer_public_key=" KEY_B_PUB "\n" |
|
"link=b:127.0.0.1:9202\n"; |
|
|
|
static int create_temp_configs(void) { |
|
if (test_mkdtemp(temp_dir) != 0) { |
|
fprintf(stderr, "Failed to create temp directory\n"); |
|
return -1; |
|
} |
|
|
|
snprintf(config_a, sizeof(config_a), "%s/a.conf", temp_dir); |
|
snprintf(config_b, sizeof(config_b), "%s/b.conf", temp_dir); |
|
snprintf(config_c, sizeof(config_c), "%s/c.conf", temp_dir); |
|
|
|
// Generate keys for C |
|
struct SC_MYKEYS keys_c; |
|
if (sc_generate_keypair(&keys_c) != SC_OK) { |
|
fprintf(stderr, "Failed to generate keys for C\n"); |
|
return -1; |
|
} |
|
|
|
// Convert to hex |
|
const char* hex_chars = "0123456789abcdef"; |
|
for (int i = 0; i < 32; i++) { |
|
key_c_priv[i*2] = hex_chars[(keys_c.private_key[i] >> 4) & 0xF]; |
|
key_c_priv[i*2+1] = hex_chars[keys_c.private_key[i] & 0xF]; |
|
} |
|
key_c_priv[64] = '\0'; |
|
|
|
for (int i = 0; i < 64; i++) { |
|
key_c_pub[i*2] = hex_chars[(keys_c.public_key[i] >> 4) & 0xF]; |
|
key_c_pub[i*2+1] = hex_chars[keys_c.public_key[i] & 0xF]; |
|
} |
|
key_c_pub[128] = '\0'; |
|
|
|
printf("Generated C keys:\n"); |
|
printf(" priv: %.16s...\n", key_c_priv); |
|
printf(" pub: %.16s...\n", key_c_pub); |
|
|
|
// Write config A with C's public key |
|
FILE* f = fopen(config_a, "w"); |
|
if (!f) return -1; |
|
fprintf(f, "%s", config_a_content); |
|
fprintf(f, client_a_content, key_c_pub); |
|
fclose(f); |
|
|
|
// Write config B with C's public key |
|
f = fopen(config_b, "w"); |
|
if (!f) return -1; |
|
fprintf(f, "%s", config_b_content); |
|
fprintf(f, client_b_content, key_c_pub); |
|
fclose(f); |
|
|
|
// Write config C with generated keys |
|
char c_config[4096]; |
|
snprintf(c_config, sizeof(c_config), config_c_content_template, key_c_priv, key_c_pub); |
|
f = fopen(config_c, "w"); |
|
if (!f) return -1; |
|
fprintf(f, "%s", c_config); |
|
fprintf(f, "%s", client_c_content_template); |
|
fclose(f); |
|
|
|
return 0; |
|
} |
|
|
|
static void cleanup_temp_configs(void) { |
|
if (config_a[0]) unlink(config_a); |
|
if (config_b[0]) unlink(config_b); |
|
if (config_c[0]) unlink(config_c); |
|
if (temp_dir[0]) rmdir(temp_dir); |
|
} |
|
|
|
static int count_initialized_links(struct UTUN_INSTANCE* inst) { |
|
int count = 0; |
|
struct ETCP_CONN* conn = inst->connections; |
|
while (conn) { |
|
struct ETCP_LINK* link = conn->links; |
|
while (link) { |
|
if (link->initialized) count++; |
|
link = link->next; |
|
} |
|
conn = conn->next; |
|
} |
|
return count; |
|
} |
|
|
|
static void check_connections(void* arg) { |
|
(void)arg; |
|
|
|
int a = count_initialized_links(inst_a); |
|
int b = count_initialized_links(inst_b); |
|
int c = count_initialized_links(inst_c); |
|
|
|
printf("[CONNECT] Links ready: A=%d, B=%d, C=%d (need 2 each)\n", a, b, c); |
|
|
|
if (a >= 2 && b >= 2 && c >= 2) { |
|
printf("\n[SUCCESS] All connections established!\n"); |
|
test_phase = 1; |
|
return; |
|
} |
|
|
|
timeout_id = uasync_set_timeout(ua, 100, NULL, check_connections); |
|
} |
|
|
|
static void timeout_handler(void* arg) { |
|
(void)arg; |
|
printf("\n[TIMEOUT] Test failed\n"); |
|
test_phase = -1; |
|
} |
|
|
|
int main(void) { |
|
printf("========================================\n"); |
|
printf(" Routing Mesh Test (3 instances)\n"); |
|
printf("========================================\n\n"); |
|
|
|
if (create_temp_configs() != 0) { |
|
fprintf(stderr, "Failed to create configs\n"); |
|
return 1; |
|
} |
|
|
|
debug_config_init(); |
|
debug_set_level(DEBUG_LEVEL_WARN); |
|
|
|
ua = uasync_create(); |
|
if (!ua) { |
|
fprintf(stderr, "Failed to create uasync\n"); |
|
return 1; |
|
} |
|
|
|
printf("[INIT] Creating instances from config files...\n"); |
|
|
|
inst_a = utun_instance_create(ua, config_a); |
|
inst_b = utun_instance_create(ua, config_b); |
|
inst_c = utun_instance_create(ua, config_c); |
|
|
|
if (!inst_a || !inst_b || !inst_c) { |
|
fprintf(stderr, "Failed to create instances\n"); |
|
return 1; |
|
} |
|
|
|
printf(" Instance A: node_id=%016llX\n", (unsigned long long)inst_a->node_id); |
|
printf(" Instance B: node_id=%016llX\n", (unsigned long long)inst_b->node_id); |
|
printf(" Instance C: node_id=%016llX\n", (unsigned long long)inst_c->node_id); |
|
|
|
printf("\n[INIT] Initializing connections...\n"); |
|
|
|
if (init_connections(inst_a) < 0 || |
|
init_connections(inst_b) < 0 || |
|
init_connections(inst_c) < 0) { |
|
fprintf(stderr, "Failed to initialize connections\n"); |
|
return 1; |
|
} |
|
|
|
printf(" Connections initialized\n"); |
|
|
|
printf("\n[PHASE] Waiting for connections to establish...\n"); |
|
timeout_id = uasync_set_timeout(ua, TEST_TIMEOUT_MS, NULL, timeout_handler); |
|
check_connections(NULL); |
|
|
|
while (test_phase == 0) { |
|
uasync_poll(ua, 10); |
|
} |
|
|
|
// Cleanup |
|
if (inst_a) utun_instance_destroy(inst_a); |
|
if (inst_b) utun_instance_destroy(inst_b); |
|
if (inst_c) utun_instance_destroy(inst_c); |
|
if (ua) uasync_destroy(ua, 0); |
|
cleanup_temp_configs(); |
|
|
|
if (test_phase == 1) { |
|
printf("\n✓ TEST PASSED\n"); |
|
return 0; |
|
} else { |
|
printf("\n✗ TEST FAILED\n"); |
|
return 1; |
|
} |
|
}
|
|
|