524 lines
21 KiB
C
524 lines
21 KiB
C
/**
|
|
* @file test_nat_detection.c
|
|
* @brief Интеграционный тест детекции типа NAT через три узла
|
|
*
|
|
* Топология: C1 -> S <- C2
|
|
* - S получает NODEINFO от C1 (direct peer)
|
|
* - S использует C2 как третий узел для NAT-пинга C1
|
|
* - C2 пингует C1, результат возвращается S
|
|
* - S отправляет NAT_INFO C1
|
|
* - Проверяем корректность заполнения всех NAT-полей
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "test_utils.h"
|
|
#include "etcp.h"
|
|
#include "etcp_connections.h"
|
|
#include "../src/config_parser.h"
|
|
#include "../src/config_updater.h"
|
|
#include "../src/utun_instance.h"
|
|
#include "routing.h"
|
|
#include "topo_group.h"
|
|
#include "route_ping.h"
|
|
#include "nat_detection.h"
|
|
#include "topo_node.h"
|
|
#include "../src/tun_if.h"
|
|
#include "secure_channel.h"
|
|
#include "../lib/u_async.h"
|
|
#include "../lib/debug_config.h"
|
|
|
|
#define TEST_TIMEOUT_MS 5000
|
|
static uint64_t g_node_id_s = 0;
|
|
static uint64_t g_node_id_c1 = 0;
|
|
static uint64_t g_node_id_c2 = 0;
|
|
|
|
static struct UTUN_INSTANCE* inst_s = NULL;
|
|
static struct UTUN_INSTANCE* inst_c1 = NULL;
|
|
static struct UTUN_INSTANCE* inst_c2 = NULL;
|
|
static struct UASYNC* ua = NULL;
|
|
static int test_timed_out = 0;
|
|
static void* test_timeout_id = NULL;
|
|
|
|
static char temp_dir[] = "/tmp/utun_nat_test_XXXXXX";
|
|
static char config_s[256];
|
|
static char config_c1[256];
|
|
static char config_c2[256];
|
|
|
|
static struct {
|
|
int done;
|
|
int success;
|
|
uint16_t avg_rtt;
|
|
uint8_t count_sent;
|
|
uint8_t count_ok;
|
|
} nat_ping_result;
|
|
|
|
static int write_config(const char* path, const char* content) {
|
|
FILE* f = fopen(path, "w");
|
|
if (!f) return -1;
|
|
fprintf(f, "%s", content);
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
|
|
static char* get_pubkey_from_config(const char* path) {
|
|
struct utun_config* cfg = parse_config(path);
|
|
if (!cfg) return NULL;
|
|
char* pub = strdup(cfg->global.my_public_key_hex);
|
|
free_config(cfg);
|
|
return pub;
|
|
}
|
|
|
|
static int create_temp_configs(void) {
|
|
if (test_mkdtemp(temp_dir) != 0) {
|
|
fprintf(stderr, "Failed to create temp directory\n");
|
|
return -1;
|
|
}
|
|
snprintf(config_s, sizeof(config_s), "%s/s.conf", temp_dir);
|
|
snprintf(config_c1, sizeof(config_c1), "%s/c1.conf", temp_dir);
|
|
snprintf(config_c2, sizeof(config_c2), "%s/c2.conf", temp_dir);
|
|
|
|
const char* tpl_s =
|
|
"[global]\n"
|
|
"tun_ip=10.100.0.1/24\n"
|
|
"tun_ifname=tun100\n"
|
|
"\n"
|
|
"[server:test_s]\n"
|
|
"addr=127.0.0.1:39011\n"
|
|
"type=public\n"
|
|
"\n"
|
|
"[allowed_keys]\n"
|
|
"allow_all=1\n";
|
|
if (write_config(config_s, tpl_s) != 0) return -1;
|
|
if (config_ensure_keys_and_node_id(config_s) != 0) return -1;
|
|
char* pub_s = get_pubkey_from_config(config_s);
|
|
if (!pub_s) return -1;
|
|
|
|
const char* tpl_c2 =
|
|
"[global]\n"
|
|
"tun_ip=10.100.0.3/24\n"
|
|
"tun_ifname=tun103\n"
|
|
"\n"
|
|
"[server:test_c2]\n"
|
|
"addr=127.0.0.1:39013\n"
|
|
"type=public\n"
|
|
"\n"
|
|
"[client:to_s]\n"
|
|
"keepalive=1\n"
|
|
"peer_public_key=%s\n"
|
|
"link=test_c2:127.0.0.1:39011\n";
|
|
char tpl_c2_full[4096];
|
|
snprintf(tpl_c2_full, sizeof(tpl_c2_full), tpl_c2, pub_s);
|
|
if (write_config(config_c2, tpl_c2_full) != 0) { free(pub_s); return -1; }
|
|
if (config_ensure_keys_and_node_id(config_c2) != 0) { free(pub_s); return -1; }
|
|
char* pub_c2 = get_pubkey_from_config(config_c2);
|
|
if (!pub_c2) { free(pub_s); return -1; }
|
|
|
|
const char* tpl_c1 =
|
|
"[global]\n"
|
|
"tun_ip=10.100.0.2/24\n"
|
|
"tun_ifname=tun102\n"
|
|
"\n"
|
|
"[server:test_c1]\n"
|
|
"addr=127.0.0.1:39012\n"
|
|
"type=nat\n"
|
|
"\n"
|
|
"[client:to_s]\n"
|
|
"keepalive=1\n"
|
|
"peer_public_key=%s\n"
|
|
"link=test_c1:127.0.0.1:39011\n";
|
|
char tpl_c1_full[4096];
|
|
snprintf(tpl_c1_full, sizeof(tpl_c1_full), tpl_c1, pub_s);
|
|
free(pub_s);
|
|
if (write_config(config_c1, tpl_c1_full) != 0) { free(pub_c2); return -1; }
|
|
if (config_ensure_keys_and_node_id(config_c1) != 0) { free(pub_c2); return -1; }
|
|
free(pub_c2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void cleanup_temp_configs(void) {
|
|
test_unlink(config_s);
|
|
test_unlink(config_c1);
|
|
test_unlink(config_c2);
|
|
test_rmdir(temp_dir);
|
|
}
|
|
|
|
static int has_initialized_link(struct UTUN_INSTANCE* inst) {
|
|
if (!inst || !inst->connections) return 0;
|
|
struct ll_entry* entry = inst->connections->head;
|
|
while (entry) {
|
|
struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data;
|
|
struct ETCP_CONN* conn = ce->conn;
|
|
struct ETCP_LINK* link = conn->links;
|
|
while (link) {
|
|
if (link->initialized) return 1;
|
|
link = link->next;
|
|
}
|
|
entry = entry->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static struct ETCP_LINK* find_link_to_node(struct UTUN_INSTANCE* inst, uint64_t node_id) {
|
|
if (!inst || !inst->connections) return NULL;
|
|
struct ll_entry* entry = queue_find_data_by_index(inst->connections, (const uint8_t*)&node_id);
|
|
return entry ? ((struct conn_queue_entry*)entry->data)->conn->links : NULL;
|
|
}
|
|
|
|
static void test_timeout_cb(void* arg) {
|
|
(void)arg;
|
|
test_timed_out = 1;
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "test_nat_detection: overall test timeout");
|
|
}
|
|
|
|
static void nat_ping_resp_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, void* arg) {
|
|
(void)arg;
|
|
nat_ping_result.done = 1;
|
|
nat_ping_result.success = success;
|
|
nat_ping_result.avg_rtt = avg_rtt;
|
|
nat_ping_result.count_sent = count_sent;
|
|
nat_ping_result.count_ok = count_ok;
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "nat_ping_resp_cb: success=%d avg_rtt=%u sent=%u ok=%u",
|
|
success, (unsigned)avg_rtt, (unsigned)count_sent, (unsigned)count_ok);
|
|
}
|
|
|
|
int main(void) {
|
|
int test_result = 1;
|
|
debug_config_init();
|
|
debug_set_level(DEBUG_LEVEL_INFO);
|
|
debug_set_categories(DEBUG_CATEGORY_ETCP | DEBUG_CATEGORY_BGP | DEBUG_CATEGORY_ROUTING);
|
|
utun_instance_set_tun_init_enabled(0);
|
|
|
|
if (create_temp_configs() != 0) {
|
|
fprintf(stderr, "Failed to create temp configs\n");
|
|
return 1;
|
|
}
|
|
|
|
ua = uasync_create();
|
|
if (!ua) {
|
|
cleanup_temp_configs();
|
|
return 1;
|
|
}
|
|
|
|
inst_s = utun_instance_create(ua, config_s);
|
|
inst_c1 = utun_instance_create(ua, config_c1);
|
|
inst_c2 = utun_instance_create(ua, config_c2);
|
|
if (!inst_s || !inst_c1 || !inst_c2) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create instances");
|
|
goto cleanup;
|
|
}
|
|
|
|
// Разрешаем NAT check для localhost (для теста)
|
|
if (topo_groups_get_default(inst_s->topo_groups)) topo_group_set_nat_check_local(topo_groups_get_default(inst_s->topo_groups), 1);
|
|
|
|
if (init_connections(inst_s) != 0 || init_connections(inst_c1) != 0 || init_connections(inst_c2) != 0) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to init connections");
|
|
goto cleanup;
|
|
}
|
|
|
|
g_node_id_s = inst_s->node_id; g_node_id_c1 = inst_c1->node_id; g_node_id_c2 = inst_c2->node_id;
|
|
|
|
test_timeout_id = uasync_set_timeout(ua, TEST_TIMEOUT_MS * 10, NULL, test_timeout_cb, "test_nat");
|
|
|
|
// 1. Wait for links C1->S and C2->S to initialize
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Waiting for ETCP links to initialize...");
|
|
// Wait for links to be initialized instead of fixed 100 iterations
|
|
while (!test_timed_out) {
|
|
if (has_initialized_link(inst_c1) && has_initialized_link(inst_c2)) {
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Links C1->S and C2->S initialized");
|
|
break;
|
|
}
|
|
uasync_poll(ua, 10);
|
|
}
|
|
if (test_timed_out) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Timeout waiting for links");
|
|
goto cleanup;
|
|
}
|
|
|
|
// 2. Wait for BGP exchange so S learns about C1 and C2
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Waiting for BGP exchange (S learns C1 and C2)...");
|
|
int bgp_wait_cycles = 0;
|
|
while (!test_timed_out && bgp_wait_cycles < 500) {
|
|
if (topo_groups_get_default(inst_s->topo_groups) && topo_node_find_by_id(topo_groups_get_default(inst_s->topo_groups), g_node_id_c1) != NULL &&
|
|
topo_node_find_by_id(topo_groups_get_default(inst_s->topo_groups), g_node_id_c2) != NULL) {
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "S learned about C1 and C2");
|
|
break;
|
|
}
|
|
uasync_poll(ua, 10);
|
|
bgp_wait_cycles++;
|
|
}
|
|
if (!topo_groups_get_default(inst_s->topo_groups) || topo_node_find_by_id(topo_groups_get_default(inst_s->topo_groups), g_node_id_c1) == NULL ||
|
|
topo_node_find_by_id(topo_groups_get_default(inst_s->topo_groups), g_node_id_c2) == NULL) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "S did not learn about C1/C2 in time");
|
|
goto cleanup;
|
|
}
|
|
|
|
// Verify C1 socket has config type before NAT detection
|
|
{
|
|
struct ETCP_SOCKET* s = inst_c1->etcp_sockets;
|
|
if (!s || s->type != CFG_SERVER_TYPE_NAT) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: C1 socket type=%d, expected CFG_SERVER_TYPE_NAT(%d) before detection",
|
|
s ? (int)s->type : -1, CFG_SERVER_TYPE_NAT);
|
|
goto cleanup;
|
|
}
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "C1 socket has config NAT type before detection");
|
|
}
|
|
|
|
// 3. Wait for NAT detection to complete for C1 - check link on server
|
|
struct ETCP_LINK* link_sc1 = find_link_to_node(inst_s, g_node_id_c1);
|
|
if (!link_sc1) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "No link to C1 on server");
|
|
goto cleanup;
|
|
}
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Waiting for NAT detection to complete for C1...");
|
|
bgp_wait_cycles = 0;
|
|
while (!test_timed_out && bgp_wait_cycles < 1500) {
|
|
if (link_sc1->nat_check_status == NAT_CHECK_EIM) {
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT detection completed for C1: EIM");
|
|
break;
|
|
}
|
|
uasync_poll(ua, 10);
|
|
bgp_wait_cycles++;
|
|
}
|
|
if (!link_sc1 || link_sc1->nat_check_status != NAT_CHECK_EIM) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NAT detection did not complete for C1");
|
|
goto cleanup;
|
|
}
|
|
|
|
// 4. Wait for C1 to receive NAT_INFO (verified type)
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Waiting for C1 to receive NAT_INFO...");
|
|
bgp_wait_cycles = 0;
|
|
while (!test_timed_out && bgp_wait_cycles < 500) {
|
|
struct ETCP_SOCKET* sock = inst_c1->etcp_sockets;
|
|
int found = 0;
|
|
while (sock) {
|
|
if (sock->nat_type == NAT_VERIFIED_EIM) { found = 1; break; }
|
|
sock = sock->next;
|
|
}
|
|
if (found) {
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "C1 received NAT_INFO");
|
|
/* Даем время для получения NODEINFO с обновленным local_node */
|
|
for (int i = 0; i < 50 && !test_timed_out; i++) {
|
|
uasync_poll(ua, 10);
|
|
}
|
|
break;
|
|
}
|
|
uasync_poll(ua, 10);
|
|
bgp_wait_cycles++;
|
|
}
|
|
|
|
// 5. Verify all NAT fields on server
|
|
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_GROUP_NODE for C1 disappeared");
|
|
goto cleanup;
|
|
}
|
|
if (link_sc1->nat_check_status != NAT_CHECK_EIM) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: nat_check_status=%d, expected EIM(%d)",
|
|
(int)link_sc1->nat_check_status, NAT_CHECK_EIM);
|
|
goto cleanup;
|
|
}
|
|
if (link_sc1->nat_type != NAT_TYPE_EIM) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: nat_type=%d, expected EIM(%d)",
|
|
(int)link_sc1->nat_type, NAT_TYPE_EIM);
|
|
goto cleanup;
|
|
}
|
|
if (link_sc1->nat_ip == 0 || link_sc1->nat_port == 0) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: nat_ip/port not set (ip=%08x port=%u)",
|
|
(unsigned)link_sc1->nat_ip, (unsigned)link_sc1->nat_port);
|
|
goto cleanup;
|
|
}
|
|
|
|
// Verify link nat_type on server
|
|
struct ETCP_CONN* conn_sc1 = NULL;
|
|
{ struct ll_entry* e = inst_s->connections->head;
|
|
while (e) {
|
|
struct conn_queue_entry* ce = (struct conn_queue_entry*)e->data;
|
|
if (ce->conn->peer_node_id == g_node_id_c1) { conn_sc1 = ce->conn; break; }
|
|
e = e->next;
|
|
} }
|
|
if (!link_sc1 || link_sc1->nat_type != NAT_TYPE_EIM) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: link nat_type not EIM on server");
|
|
goto cleanup;
|
|
}
|
|
|
|
// Verify socket nat_type on C1
|
|
struct ETCP_SOCKET* sock_c1 = NULL;
|
|
struct ETCP_SOCKET* sock = inst_c1->etcp_sockets;
|
|
while (sock) {
|
|
if (sock->nat_type == NAT_VERIFIED_EIM) {
|
|
sock_c1 = sock;
|
|
break;
|
|
}
|
|
sock = sock->next;
|
|
}
|
|
if (!sock_c1) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: no socket with NAT_VERIFIED_EIM on C1");
|
|
goto cleanup;
|
|
}
|
|
|
|
// 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) {
|
|
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);
|
|
goto cleanup;
|
|
}
|
|
found = 1; break;
|
|
}
|
|
}
|
|
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 = lni->v4_addrs; a; a = a->next) {
|
|
if (a->type == TOPO_ADDR_NAT && a->socket_id == sock_c1->sock_id) {
|
|
uint32_t addr_ip; memcpy(&addr_ip, a->addr, 4);
|
|
if (addr_ip != link_sc1->nat_ip || a->port != link_sc1->nat_port) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: NAT addr mismatch in local_node: addr=%08x nat_ip=%08x port=%u nat_port=%u",
|
|
addr_ip, link_sc1->nat_ip, a->port, link_sc1->nat_port);
|
|
goto cleanup;
|
|
}
|
|
nat_found = 1; break;
|
|
}
|
|
}
|
|
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) {
|
|
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;
|
|
}
|
|
uasync_poll(ua, 10);
|
|
bgp_wait_cycles++;
|
|
}
|
|
if (!c2_verified_nat) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: C2 did not receive updated C1 nodeinfo with verified NAT");
|
|
goto cleanup;
|
|
}
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "C2 received updated C1 nodeinfo with verified NAT");
|
|
|
|
// 6. Separate STUN check via explicit route_ping_send_req_addr
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Performing explicit STUN ping from S via C2 to C1...");
|
|
struct ETCP_CONN* conn_sc2 = NULL;
|
|
struct ll_entry* entry = inst_s->connections->head;
|
|
while (entry) {
|
|
struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data;
|
|
if (ce->conn->peer_node_id == g_node_id_c2) { conn_sc2 = ce->conn; break; }
|
|
entry = entry->next;
|
|
}
|
|
if (!conn_sc2) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: S has no connection to C2");
|
|
goto cleanup;
|
|
}
|
|
|
|
memset(&nat_ping_result, 0, sizeof(nat_ping_result));
|
|
/* nat_ip уже в network byte order, API тоже принимает NBO */
|
|
uint32_t target_ip_net = link_sc1->nat_ip;
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "TEST: sending ping with pubkey, nat_ip_net=0x%08x nat_port=%u",
|
|
link_sc1->nat_ip, link_sc1->nat_port);
|
|
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_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;
|
|
}
|
|
|
|
bgp_wait_cycles = 0;
|
|
while (!test_timed_out && bgp_wait_cycles < 500 && !nat_ping_result.done) {
|
|
uasync_poll(ua, 10);
|
|
bgp_wait_cycles++;
|
|
}
|
|
if (!nat_ping_result.done) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: STUN ping timeout");
|
|
goto cleanup;
|
|
}
|
|
if (!nat_ping_result.success || nat_ping_result.count_ok == 0) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: STUN ping failed success=%d ok=%u",
|
|
nat_ping_result.success, (unsigned)nat_ping_result.count_ok);
|
|
goto cleanup;
|
|
}
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "STUN check PASSED");
|
|
|
|
// 7. Test route_ping_send_req_addr WITHOUT embedded pubkey (C2 should resolve pubkey from node_id)
|
|
// First wait for C2 to learn C1's nodeinfo via BGP exchange from S
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Waiting for C2 to learn C1 nodeinfo...");
|
|
bgp_wait_cycles = 0;
|
|
while (!test_timed_out && bgp_wait_cycles < 500) {
|
|
if (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) {
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "C2 learned C1 nodeinfo");
|
|
break;
|
|
}
|
|
uasync_poll(ua, 10);
|
|
bgp_wait_cycles++;
|
|
}
|
|
if (!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) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: C2 did not learn C1 nodeinfo in time");
|
|
goto cleanup;
|
|
}
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Testing route ping without embedded pubkey...");
|
|
memset(&nat_ping_result, 0, sizeof(nat_ping_result));
|
|
/* nat_ip уже в network byte order, API тоже принимает NBO */
|
|
target_ip_net = link_sc1->nat_ip;
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "TEST: sending ping NO pubkey, nat_ip_net=0x%08x nat_port=%u",
|
|
link_sc1->nat_ip, link_sc1->nat_port);
|
|
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,
|
|
cni->public_key);
|
|
if (ret != 0) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr (no pubkey) failed: %d", ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
bgp_wait_cycles = 0;
|
|
while (!test_timed_out && bgp_wait_cycles < 500 && !nat_ping_result.done) {
|
|
uasync_poll(ua, 10);
|
|
bgp_wait_cycles++;
|
|
}
|
|
if (!nat_ping_result.done) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: no-pubkey ping timeout");
|
|
goto cleanup;
|
|
}
|
|
if (!nat_ping_result.success || nat_ping_result.count_ok == 0) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: no-pubkey ping failed success=%d ok=%u",
|
|
nat_ping_result.success, (unsigned)nat_ping_result.count_ok);
|
|
goto cleanup;
|
|
}
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "No-pubkey ping check PASSED");
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT detection test PASSED");
|
|
test_result = 0;
|
|
|
|
cleanup:
|
|
if (test_timeout_id) uasync_cancel_timeout(ua, test_timeout_id);
|
|
if (inst_s) utun_instance_destroy(inst_s);
|
|
if (inst_c1) utun_instance_destroy(inst_c1);
|
|
if (inst_c2) utun_instance_destroy(inst_c2);
|
|
if (ua) uasync_destroy(ua, 0);
|
|
cleanup_temp_configs();
|
|
return test_result;
|
|
}
|