diff --git a/src/route_ping.c b/src/route_ping.c index f9d1e2a2..ecd1202e 100644 --- a/src/route_ping.c +++ b/src/route_ping.c @@ -99,8 +99,14 @@ static void route_ping_cb(int success, uint16_t rtt, void* arg, uint64_t nonce, series->rtt_sum += rtt; } if (series->count_sent < series->count_total && series->req->reply_conn) { - struct UTUN_INSTANCE* inst = series->req->reply_conn->instance; - series->next_timer = uasync_set_timeout(inst->ua, series->interval_ms * 10, series, route_ping_next); + if (success) { + // Ответ получен — следующий пинг сразу (burst mode) + route_ping_next(series); + } else { + // Таймаут — ждем interval_ms перед retry + struct UTUN_INSTANCE* inst = series->req->reply_conn->instance; + series->next_timer = uasync_set_timeout(inst->ua, series->interval_ms * 10, series, route_ping_next); + } return; } // серия завершена @@ -236,7 +242,7 @@ int route_ping_send_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, uint64 return -3; } e->dgram = (uint8_t*)req_pkt; - e->len = sizeof(struct BGP_PING_REQUEST); + e->len = offsetof(struct BGP_PING_REQUEST, target_ipv4); int ret = etcp_send(to_conn, e); if (ret != 0) { @@ -275,8 +281,7 @@ int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, u DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr: invalid args"); return -1; } - size_t extra = 6 + (pubkey ? SC_PUBKEY_SIZE : 0); - size_t pkt_size = sizeof(struct BGP_PING_REQUEST) + extra; + size_t pkt_size = pubkey ? sizeof(struct BGP_PING_REQUEST) : offsetof(struct BGP_PING_REQUEST, pubkey); struct BGP_PING_REQUEST* req_pkt = u_calloc(1, pkt_size); if (!req_pkt) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr: alloc failed"); @@ -289,16 +294,13 @@ int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, u req_pkt->count = count; req_pkt->interval_ms = interval_ms; req_pkt->timeout_ms = timeout_ms; - - uint8_t* tail = (uint8_t*)req_pkt + sizeof(struct BGP_PING_REQUEST); - tail[0] = (target_ip >> 24) & 0xFF; - tail[1] = (target_ip >> 16) & 0xFF; - tail[2] = (target_ip >> 8) & 0xFF; - tail[3] = target_ip & 0xFF; - tail[4] = (target_port >> 8) & 0xFF; - tail[5] = target_port & 0xFF; + req_pkt->target_ipv4[0] = (target_ip >> 24) & 0xFF; + req_pkt->target_ipv4[1] = (target_ip >> 16) & 0xFF; + req_pkt->target_ipv4[2] = (target_ip >> 8) & 0xFF; + req_pkt->target_ipv4[3] = target_ip & 0xFF; + req_pkt->target_port = target_port; if (pubkey) { - memcpy(tail + 6, pubkey, SC_PUBKEY_SIZE); + memcpy(req_pkt->pubkey, pubkey, SC_PUBKEY_SIZE); } struct ll_entry* e = queue_entry_new(0); @@ -352,8 +354,10 @@ void route_ping_destroy_pending(struct ROUTE_BGP* bgp) { } void route_ping_handle_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, const uint8_t* data, size_t len) { - if (!bgp || !from_conn || !data || len < sizeof(struct BGP_PING_REQUEST)) { - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_handle_req: invalid args"); + const size_t base_len = offsetof(struct BGP_PING_REQUEST, target_ipv4); + const size_t addr_len = offsetof(struct BGP_PING_REQUEST, pubkey); + if (!bgp || !from_conn || !data || (len != base_len && len != addr_len && len != sizeof(struct BGP_PING_REQUEST))) { + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_handle_req: invalid args len=%zu", len); return; } const struct BGP_PING_REQUEST* req_pkt = (const struct BGP_PING_REQUEST*)data; @@ -367,29 +371,34 @@ void route_ping_handle_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, c struct NODEINFO_Q* target = NULL; const uint8_t* embedded_pubkey = NULL; - if (len >= sizeof(struct BGP_PING_REQUEST) + 6) { - // Custom target address provided (for NAT ping) - const uint8_t* tail = data + sizeof(struct BGP_PING_REQUEST); - custom_socket.addr[0] = tail[0]; - custom_socket.addr[1] = tail[1]; - custom_socket.addr[2] = tail[2]; - custom_socket.addr[3] = tail[3]; - custom_socket.port = (tail[4] << 8) | tail[5]; + if (len == sizeof(struct BGP_PING_REQUEST) || len == addr_len) { + // Extended packet with custom target (with or without pubkey) + custom_socket.addr[0] = req_pkt->target_ipv4[0]; + custom_socket.addr[1] = req_pkt->target_ipv4[1]; + custom_socket.addr[2] = req_pkt->target_ipv4[2]; + custom_socket.addr[3] = req_pkt->target_ipv4[3]; + custom_socket.port = req_pkt->target_port; custom_socket.type = 0; custom_socket.id = 0; sockets_v4 = &custom_socket; sock_count_v4 = 1; DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_ping_handle_req: using custom target %d.%d.%d.%d:%u for node %016llx", - tail[0], tail[1], tail[2], tail[3], custom_socket.port, - (unsigned long long)req_pkt->node_id); - // Check for embedded pubkey - if (len >= sizeof(struct BGP_PING_REQUEST) + 6 + SC_PUBKEY_SIZE) { - embedded_pubkey = tail + 6; + req_pkt->target_ipv4[0], req_pkt->target_ipv4[1], req_pkt->target_ipv4[2], req_pkt->target_ipv4[3], + req_pkt->target_port, (unsigned long long)req_pkt->node_id); + // Check if embedded pubkey is non-zero (only when full packet length) + if (len == sizeof(struct BGP_PING_REQUEST)) { + int pubkey_zero = 1; + for (int i = 0; i < SC_PUBKEY_SIZE; i++) { + if (req_pkt->pubkey[i] != 0) { pubkey_zero = 0; break; } + } + if (!pubkey_zero) { + embedded_pubkey = req_pkt->pubkey; + } } // For custom target, we still need target node for pubkey lookup if not embedded target = route_bgp_get_node(bgp, req_pkt->node_id); - } else { - // No custom target - look up nodeinfo for advertised sockets + } else if (len == base_len) { + // Base packet without custom target - use nodeinfo sockets target = route_bgp_get_node(bgp, req_pkt->node_id); if (!target) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "route_ping_handle_req: node %016llx not found", @@ -407,6 +416,9 @@ void route_ping_handle_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, c } sock_count_v4 = get_node_v4_sockets(target, &sockets_v4); sock_count_v6 = get_node_v6_sockets(target, &sockets_v6); + } else { + DEBUG_WARN(DEBUG_CATEGORY_BGP, "route_ping_handle_req: unexpected packet size %zu", len); + return; } if ((sock_count_v4 <= 0 || !sockets_v4) && (sock_count_v6 <= 0 || !sockets_v6)) { diff --git a/src/route_ping.h b/src/route_ping.h index b4b71d99..04e9ef25 100644 --- a/src/route_ping.h +++ b/src/route_ping.h @@ -9,13 +9,16 @@ #define ROUTE_SUBCMD_PING_RESP 0x08 struct BGP_PING_REQUEST { - uint8_t cmd; // ETCP_ID_ROUTE_ENTRY - uint8_t subcmd; // ROUTE_SUBCMD_PING_REQ - uint64_t request_id; // для корреляции - uint64_t node_id; // целевой узел (должен быть известен в nodes) - uint8_t count; // число пингов - uint16_t interval_ms; // интервал между пингами - uint16_t timeout_ms; // таймаут одного пинга + uint8_t cmd; // ETCP_ID_ROUTE_ENTRY + uint8_t subcmd; // ROUTE_SUBCMD_PING_REQ + uint64_t request_id; // для корреляции + uint64_t node_id; // целевой узел + uint8_t count; // число пингов + uint16_t interval_ms; // интервал между пингами + uint16_t timeout_ms; // таймаут одного пинга + uint8_t target_ipv4[4]; // custom target IP (0 = use nodeinfo sockets) + uint16_t target_port; // custom target port + uint8_t pubkey[SC_PUBKEY_SIZE]; // pubkey for encryption if target not in nodes } __attribute__((packed)); struct BGP_PING_RESPONSE { diff --git a/tests/Makefile.am b/tests/Makefile.am index 4d47c2a9..961bc337 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -291,11 +291,16 @@ check-local: total=$$((total + 1)); \ logfile="$(TEST_LOG_DIR)/$$test.log"; \ if test -f "./$$test"; then \ + start=$$(date +%s%N); \ if "./$$test" > "$$logfile" 2>&1; then \ - echo "[PASS] $$test"; \ + end=$$(date +%s%N); \ + elapsed_ms=$$(( (end - start) / 1000000 )); \ + echo "[PASS] $$test ($${elapsed_ms}ms)"; \ passed=$$((passed + 1)); \ else \ - echo "[FAIL] $$test (see $$logfile)"; \ + end=$$(date +%s%N); \ + elapsed_ms=$$(( (end - start) / 1000000 )); \ + echo "[FAIL] $$test ($${elapsed_ms}ms) (see $$logfile)"; \ failed=$$((failed + 1)); \ if test -z "$$failed_tests"; then \ failed_tests="$$test"; \ diff --git a/tests/test_etcp_simple_traffic.c b/tests/test_etcp_simple_traffic.c index 3d1a6f5b..20f47fc9 100644 --- a/tests/test_etcp_simple_traffic.c +++ b/tests/test_etcp_simple_traffic.c @@ -23,7 +23,7 @@ #include "../lib/ll_queue.h" #include "../lib/debug_config.h" -#define TEST_TIMEOUT_MS 5000 // 5 seconds for packet transmission +#define TEST_TIMEOUT_MS 50000 // 5 seconds in uasync timebase (0.1ms units) #define PACKET_SIZE 100 // Test packet size static struct UTUN_INSTANCE* server_instance = NULL; @@ -34,45 +34,21 @@ static struct UASYNC* ua = NULL; static char temp_dir[] = "/tmp/utun_test_XXXXXX"; static char server_config_path[256]; static char client_config_path[256]; +static int server_port = 0; +static int client_port = 0; -// Server config content -static const char* server_config_content = - "[global]\n" - "my_node_id=0x1111111111111111\n" - "my_private_key=67b705a92b41bcaae105af2d6a17743faa7b26ccebba8b3b9b0af05e9cd1d5fb\n" - "my_public_key=1c55e4ccae7c4470707759086738b10681bf88b81f198cc2ab54a647d1556e17c65e6b1833e0c771e5a39382c03067c388915a4c732191bc130480f20f8e00b9\n" - "tun_ip=10.99.0.1/24\n" - "tun_ifname=tun99\n" - "\n" - "[server: test]\n" - "addr=127.0.0.1:9001\n" - "type=public\n"; - -// Client config content -static const char* client_config_content = - "[global]\n" - "my_node_id=0x2222222222222222\n" - "my_private_key=4813d31d28b7e9829247f488c6be7672f2bdf61b2508333128e386d1759afed2\n" - "my_public_key=c594f33c91f3a2222795c2c110c527bf214ad1009197ce14556cb13df3c461b3c373bed8f205a8dd1fc0c364f90bf471d7c6f5db49564c33e4235d268569ac71\n" - "tun_ip=10.99.0.2/24\n" - "tun_ifname=tun98\n" - "\n" - "[server: test]\n" - "addr=127.0.0.1:9002\n" - "type=public\n" - "\n" - "[client: test_client]\n" - "keepalive=1\n" - "peer_public_key=1c55e4ccae7c4470707759086738b10681bf88b81f198cc2ab54a647d1556e17c65e6b1833e0c771e5a39382c03067c388915a4c732191bc130480f20f8e00b9\n" - "link=test:127.0.0.1:9001\n"; - -// Create temp config files +// Create temp config files with dynamic ports to avoid conflicts static int create_temp_configs(void) { if (test_mkdtemp(temp_dir) != 0) { fprintf(stderr, "Failed to create temp directory\n"); return -1; } + // Use PID-based ports to avoid conflicts with parallel tests or leftovers + int base_port = 40000 + (getpid() % 20000); + server_port = base_port; + client_port = base_port + 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); @@ -81,7 +57,18 @@ static int create_temp_configs(void) { fprintf(stderr, "Failed to create server config file\n"); return -1; } - fprintf(f, "%s", server_config_content); + fprintf(f, + "[global]\n" + "my_node_id=0x1111111111111111\n" + "my_private_key=67b705a92b41bcaae105af2d6a17743faa7b26ccebba8b3b9b0af05e9cd1d5fb\n" + "my_public_key=1c55e4ccae7c4470707759086738b10681bf88b81f198cc2ab54a647d1556e17c65e6b1833e0c771e5a39382c03067c388915a4c732191bc130480f20f8e00b9\n" + "tun_ip=10.99.0.1/24\n" + "tun_ifname=tun99\n" + "\n" + "[server: test]\n" + "addr=127.0.0.1:%d\n" + "type=public\n", + server_port); fclose(f); f = fopen(client_config_path, "w"); @@ -90,7 +77,23 @@ static int create_temp_configs(void) { test_unlink(server_config_path); return -1; } - fprintf(f, "%s", client_config_content); + fprintf(f, + "[global]\n" + "my_node_id=0x2222222222222222\n" + "my_private_key=4813d31d28b7e9829247f488c6be7672f2bdf61b2508333128e386d1759afed2\n" + "my_public_key=c594f33c91f3a2222795c2c110c527bf214ad1009197ce14556cb13df3c461b3c373bed8f205a8dd1fc0c364f90bf471d7c6f5db49564c33e4235d268569ac71\n" + "tun_ip=10.99.0.2/24\n" + "tun_ifname=tun98\n" + "\n" + "[server: test]\n" + "addr=127.0.0.1:%d\n" + "type=public\n" + "\n" + "[client: test_client]\n" + "keepalive=1\n" + "peer_public_key=1c55e4ccae7c4470707759086738b10681bf88b81f198cc2ab54a647d1556e17c65e6b1833e0c771e5a39382c03067c388915a4c732191bc130480f20f8e00b9\n" + "link=test:127.0.0.1:%d\n", + client_port, server_port); fclose(f); return 0; @@ -341,7 +344,7 @@ static void monitor_and_send(void* arg) { static void test_timeout(void* arg) { (void)arg; if (!test_completed) { - printf("\n=== TIMEOUT: Packet not received within %d seconds ===\n", TEST_TIMEOUT_MS/1000); + printf("\n=== TIMEOUT: Packet not received within %d seconds ===\n", TEST_TIMEOUT_MS/10000); test_completed = 2; // Timeout/failure if (packet_timeout_id) { uasync_cancel_timeout(server_instance->ua, packet_timeout_id); @@ -483,7 +486,7 @@ int main() { printf("Starting connection and packet transmission...\n"); int elapsed = 0; - int poll_interval = 5; + int poll_interval = 50; // 5ms in uasync timebase (0.1ms units) int check_counter = 0; while (!test_completed && elapsed < TEST_TIMEOUT_MS + 1000) { if (ua) uasync_poll(ua, poll_interval); diff --git a/tests/test_nat_detection.c b/tests/test_nat_detection.c index d7970c3f..a0324ad9 100644 --- a/tests/test_nat_detection.c +++ b/tests/test_nat_detection.c @@ -217,10 +217,7 @@ int main(void) { // 1. Wait for links C1->S and C2->S to initialize DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Waiting for ETCP links to initialize..."); - // Give some time for connections to establish before checking - for (int i = 0; i < 100; i++) { - uasync_poll(ua, 10); - } + // 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"); @@ -392,6 +389,54 @@ int main(void) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "STUN check PASSED: recv_ip=%08x recv_port=%u", (unsigned)nat_ping_result.recv_ip, (unsigned)nat_ping_result.recv_port); + // 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 (inst_c2->bgp && route_bgp_get_node(inst_c2->bgp, NODE_ID_C1) != NULL) { + DEBUG_INFO(DEBUG_CATEGORY_BGP, "C2 learned C1 nodeinfo"); + break; + } + uasync_poll(ua, 10); + bgp_wait_cycles++; + } + if (!inst_c2->bgp || route_bgp_get_node(inst_c2->bgp, 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)); + ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2, NODE_ID_C1, + node_c1->nat_ip, node_c1->nat_port, + 3, 10, 200, 3000, nat_ping_resp_cb, NULL, + NULL); + 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; + } + if (nat_ping_result.recv_ip == 0 || nat_ping_result.recv_port == 0) { + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: no-pubkey ping STUN fields zero"); + goto cleanup; + } + DEBUG_INFO(DEBUG_CATEGORY_BGP, "No-pubkey ping check PASSED"); + DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT detection test PASSED"); test_result = 0;