diff --git a/tests/test_routing_mesh.c b/tests/test_routing_mesh.c index 119e13e..b44bda3 100644 --- a/tests/test_routing_mesh.c +++ b/tests/test_routing_mesh.c @@ -1,9 +1,10 @@ // test_routing_mesh.c - Test routing between 3 instances in mesh topology -// Based on test_etcp_two_instances.c approach - using config files +// Uses programmatic config creation (no temp files) #include #include #include +#include #include "test_utils.h" #include "../lib/platform_compat.h" #include "../src/etcp.h" @@ -27,10 +28,6 @@ #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; @@ -38,172 +35,222 @@ 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]; +// Helper: fill sockaddr_storage from IP:port string +static int make_sockaddr(const char* ip_port, struct sockaddr_storage* ss) { + char buf[64]; + strncpy(buf, ip_port, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + + char* colon = strrchr(buf, ':'); + if (!colon) return -1; + *colon = '\0'; + int port = atoi(colon + 1); + + struct sockaddr_in* sin = (struct sockaddr_in*)ss; + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + if (inet_pton(AF_INET, buf, &sin->sin_addr) != 1) return -1; + return 0; +} -// 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"; +// Helper: create CFG_SERVER +static struct CFG_SERVER* create_server(const char* name, const char* ip_port, uint8_t type) { + struct CFG_SERVER* srv = calloc(1, sizeof(struct CFG_SERVER)); + if (!srv) return NULL; + strncpy(srv->name, name, MAX_CONN_NAME_LEN-1); + if (make_sockaddr(ip_port, &srv->ip) < 0) { + free(srv); + return NULL; + } + srv->type = type; + return srv; +} -// 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"; +// Helper: create CFG_CLIENT_LINK +static struct CFG_CLIENT_LINK* create_link(struct CFG_SERVER* local_srv, const char* remote_ip_port) { + struct CFG_CLIENT_LINK* link = calloc(1, sizeof(struct CFG_CLIENT_LINK)); + if (!link) return NULL; + link->local_srv = local_srv; + strncpy(link->server_name, local_srv->name, MAX_CONN_NAME_LEN-1); + if (make_sockaddr(remote_ip_port, &link->remote_addr) < 0) { + free(link); + return NULL; + } + return link; +} -// 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"; +// Helper: create CFG_CLIENT +static struct CFG_CLIENT* create_client(const char* name, const char* peer_key, int keepalive) { + struct CFG_CLIENT* cli = calloc(1, sizeof(struct CFG_CLIENT)); + if (!cli) return NULL; + strncpy(cli->name, name, MAX_CONN_NAME_LEN-1); + strncpy(cli->peer_public_key_hex, peer_key, MAX_KEY_LEN-1); + cli->keepalive = keepalive; + return cli; +} -// 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"; +// Helper: add link to client +static void client_add_link(struct CFG_CLIENT* cli, struct CFG_CLIENT_LINK* link) { + link->next = cli->links; + cli->links = link; +} -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"; +// Helper: add server to list (at end to preserve order) +static void add_server(struct utun_config* cfg, struct CFG_SERVER* srv) { + if (!cfg->servers) { + cfg->servers = srv; + } else { + struct CFG_SERVER* tail = cfg->servers; + while (tail->next) tail = tail->next; + tail->next = srv; + } +} + +// Helper: find server by name +static struct CFG_SERVER* find_server(struct utun_config* cfg, const char* name) { + struct CFG_SERVER* srv = cfg->servers; + while (srv) { + if (strcmp(srv->name, name) == 0) return srv; + srv = srv->next; + } + return NULL; +} -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"; +// Helper: add client to list +static void add_client(struct utun_config* cfg, struct CFG_CLIENT* cli) { + cli->next = cfg->clients; + cfg->clients = cli; +} -static int create_temp_configs(void) { - if (test_mkdtemp(temp_dir) != 0) { - fprintf(stderr, "Failed to create temp directory\n"); - return -1; +// Helper: add subnet +static void add_subnet(struct CFG_ROUTE_ENTRY** list, const char* cidr) { + struct CFG_ROUTE_ENTRY* entry = calloc(1, sizeof(struct CFG_ROUTE_ENTRY)); + if (!entry) return; + + char buf[32]; + strncpy(buf, cidr, sizeof(buf)-1); + char* slash = strchr(buf, '/'); + if (slash) { + *slash = '\0'; + entry->netmask = atoi(slash + 1); } + entry->ip.family = AF_INET; + inet_pton(AF_INET, buf, &entry->ip.addr.v4); + + entry->next = *list; + *list = entry; +} + +// Create config for instance A +static struct utun_config* create_config_a(const char* key_c_pub) { + struct utun_config* cfg = calloc(1, sizeof(struct utun_config)); + if (!cfg) return NULL; - 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); + // Global settings + strncpy(cfg->global.my_private_key_hex, KEY_A_PRIV, MAX_KEY_LEN-1); + strncpy(cfg->global.my_public_key_hex, KEY_A_PUB, MAX_KEY_LEN-1); + cfg->global.my_node_id = 0xAAAAAAAAAAAAAAAAULL; + strncpy(cfg->global.tun_ifname, "tun_a", 15); + inet_pton(AF_INET, "10.99.1.1", &cfg->global.tun_ip.addr.v4); + cfg->global.tun_ip.family = AF_INET; + cfg->global.tun_test_mode = 1; + cfg->global.mtu = 1500; - // 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; - } + // Servers (for others to connect to) + add_server(cfg, create_server("b", "127.0.0.1:9101", CFG_SERVER_TYPE_PUBLIC)); + add_server(cfg, create_server("c", "127.0.0.1:9102", CFG_SERVER_TYPE_PUBLIC)); - // 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'; + // Clients (to connect to others) - find server by name for correct mapping + struct CFG_CLIENT* cli_b = create_client("to_b", KEY_B_PUB, 1); + client_add_link(cli_b, create_link(find_server(cfg, "b"), "127.0.0.1:9201")); // connect to B's server + add_client(cfg, cli_b); - 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'; + struct CFG_CLIENT* cli_c = create_client("to_c", key_c_pub, 1); + client_add_link(cli_c, create_link(find_server(cfg, "c"), "127.0.0.1:9302")); // connect to C's server + add_client(cfg, cli_c); - 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); + // Subnets + add_subnet(&cfg->my_subnets, "192.168.10.0/24"); + add_subnet(&cfg->my_subnets, "192.168.11.0/24"); - return 0; + return cfg; } -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); +// Create config for instance B +static struct utun_config* create_config_b(const char* key_c_pub) { + struct utun_config* cfg = calloc(1, sizeof(struct utun_config)); + if (!cfg) return NULL; + + // Global settings + strncpy(cfg->global.my_private_key_hex, KEY_B_PRIV, MAX_KEY_LEN-1); + strncpy(cfg->global.my_public_key_hex, KEY_B_PUB, MAX_KEY_LEN-1); + cfg->global.my_node_id = 0xBBBBBBBBBBBBBBBBULL; + strncpy(cfg->global.tun_ifname, "tun_b", 15); + inet_pton(AF_INET, "10.99.2.1", &cfg->global.tun_ip.addr.v4); + cfg->global.tun_ip.family = AF_INET; + cfg->global.tun_test_mode = 1; + cfg->global.mtu = 1500; + + // Servers + add_server(cfg, create_server("a", "127.0.0.1:9201", CFG_SERVER_TYPE_PUBLIC)); + add_server(cfg, create_server("c", "127.0.0.1:9202", CFG_SERVER_TYPE_PUBLIC)); + + // Clients - find server by name for correct mapping + struct CFG_CLIENT* cli_a = create_client("to_a", KEY_A_PUB, 1); + client_add_link(cli_a, create_link(find_server(cfg, "a"), "127.0.0.1:9101")); + add_client(cfg, cli_a); + + struct CFG_CLIENT* cli_c = create_client("to_c", key_c_pub, 1); + client_add_link(cli_c, create_link(find_server(cfg, "c"), "127.0.0.1:9303")); + add_client(cfg, cli_c); + + // Subnets + add_subnet(&cfg->my_subnets, "192.168.20.0/24"); + add_subnet(&cfg->my_subnets, "192.168.21.0/24"); + + return cfg; +} + +// Create config for instance C +static struct utun_config* create_config_c(const char* key_c_priv, const char* key_c_pub) { + struct utun_config* cfg = calloc(1, sizeof(struct utun_config)); + if (!cfg) return NULL; + + // Global settings + strncpy(cfg->global.my_private_key_hex, key_c_priv, MAX_KEY_LEN-1); + strncpy(cfg->global.my_public_key_hex, key_c_pub, MAX_KEY_LEN-1); + cfg->global.my_node_id = 0xCCCCCCCCCCCCCCCCULL; + strncpy(cfg->global.tun_ifname, "tun_c", 15); + inet_pton(AF_INET, "10.99.3.1", &cfg->global.tun_ip.addr.v4); + cfg->global.tun_ip.family = AF_INET; + cfg->global.tun_test_mode = 1; + cfg->global.mtu = 1500; + + // Servers + add_server(cfg, create_server("a", "127.0.0.1:9302", CFG_SERVER_TYPE_PUBLIC)); + add_server(cfg, create_server("b", "127.0.0.1:9303", CFG_SERVER_TYPE_PUBLIC)); + + // Clients - find server by name for correct mapping + struct CFG_CLIENT* cli_a = create_client("to_a", KEY_A_PUB, 1); + client_add_link(cli_a, create_link(find_server(cfg, "a"), "127.0.0.1:9102")); + add_client(cfg, cli_a); + + struct CFG_CLIENT* cli_b = create_client("to_b", KEY_B_PUB, 1); + client_add_link(cli_b, create_link(find_server(cfg, "b"), "127.0.0.1:9202")); + add_client(cfg, cli_b); + + // Subnets + add_subnet(&cfg->my_subnets, "192.168.30.0/24"); + add_subnet(&cfg->my_subnets, "192.168.31.0/24"); + + return cfg; +} + +// Free config (simplified - just free top level, rest will be cleaned on exit) +static void free_config_manual(struct utun_config* cfg) { + (void)cfg; // Config structures cleaned up by utun_instance_destroy + // Note: utun_instance_create_from_config makes copies of config data, + // so we don't need to keep the config structures after instance creation } static int count_initialized_links(struct UTUN_INSTANCE* inst) { @@ -247,9 +294,41 @@ static void timeout_handler(void* arg) { int main(void) { printf("========================================\n"); printf(" Routing Mesh Test (3 instances)\n"); + printf(" (programmatic config, no temp files)\n"); printf("========================================\n\n"); - if (create_temp_configs() != 0) { + // 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 + char key_c_priv[65], key_c_pub[129]; + 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\n", key_c_pub); + + // Create configs programmatically + struct utun_config* cfg_a = create_config_a(key_c_pub); + struct utun_config* cfg_b = create_config_b(key_c_pub); + struct utun_config* cfg_c = create_config_c(key_c_priv, key_c_pub); + + if (!cfg_a || !cfg_b || !cfg_c) { fprintf(stderr, "Failed to create configs\n"); return 1; } @@ -263,11 +342,11 @@ int main(void) { return 1; } - printf("[INIT] Creating instances from config files...\n"); + printf("[INIT] Creating instances from programmatic config...\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); + inst_a = utun_instance_create_from_config(ua, cfg_a); + inst_b = utun_instance_create_from_config(ua, cfg_b); + inst_c = utun_instance_create_from_config(ua, cfg_c); if (!inst_a || !inst_b || !inst_c) { fprintf(stderr, "Failed to create instances\n"); @@ -302,7 +381,11 @@ int main(void) { 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(); + + // Free configs + free_config_manual(cfg_a); + free_config_manual(cfg_b); + free_config_manual(cfg_c); if (test_phase == 1) { printf("\n✓ TEST PASSED\n");