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

// 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;
}
}