From c136db5666d3f247ba9c6a23df37ec798209ab37 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Wed, 22 Apr 2026 11:39:50 +0300 Subject: [PATCH] Fix: round-robin link selection + byte order fixes + local_node update --- src/route_bgp.c | 71 ++++++++++++++++++++++++++++++-------- src/route_ping.c | 69 +++++++++--------------------------- tests/test_nat_detection.c | 27 ++++++++++----- tests/test_route_ping.c | 7 ++-- 4 files changed, 97 insertions(+), 77 deletions(-) diff --git a/src/route_bgp.c b/src/route_bgp.c index 5926f548..c1a02afb 100644 --- a/src/route_bgp.c +++ b/src/route_bgp.c @@ -567,8 +567,7 @@ static void nat_link_check_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t socket_id = link->remote_socket_id; route_bgp_send_nat_info(link->etcp, socket_id, na->nat_ip, na->nat_port, nat_type); } - DEBUG_INFO(DEBUG_CATEGORY_BGP, "link=%p type=%s success=%d", - (void*)link, success ? "OPEN" : "RESTRICTED", success); + DEBUG_INFO(DEBUG_CATEGORY_BGP, "nat check result: type=%s for node %s", success ? "OPEN" : "RESTRICTED", link->etcp->log_name); u_free(na); } @@ -597,7 +596,7 @@ static void route_bgp_extract_nat_addr(struct ETCP_CONN* conn, uint32_t* nat_ip, } } -static void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LINK* link) { +static void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LINK* link) {// проверяем тип нат для линка link if (!bgp || !link || !link->conn || !link->etcp) return; if (link->nat_check_status == NAT_CHECK_IN_PROGRESS) return; // Find third node to send ping through @@ -608,15 +607,17 @@ static void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LI } // Get target address - use nat_ip/nat_port if set, otherwise use remote_addr + /* link->nat_ip и sin_addr.s_addr в network byte order, + конвертируем в host order для API route_ping_send_req_addr */ uint32_t target_ip; uint16_t target_port; if (link->nat_ip != 0 && link->nat_port != 0) { - target_ip = link->nat_ip; - target_port = link->nat_port; + target_ip = ntohl(link->nat_ip); /* network → host order */ + target_port = link->nat_port; /* уже в host order */ } else { struct sockaddr_in* sin = (struct sockaddr_in*)&link->remote_addr; - target_ip = sin->sin_addr.s_addr; - target_port = ntohs(sin->sin_port); + target_ip = ntohl(sin->sin_addr.s_addr); /* network → host order */ + target_port = ntohs(sin->sin_port); /* network → host order */ } if (!bgp->allow_nat_check_local && is_local_subnet(target_ip)) { @@ -674,6 +675,11 @@ int route_bgp_process_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* from, co struct NODEINFO_Q* nodeinfo1 = route_bgp_get_node(bgp, node_id); uint8_t new_ver = ni->ver; + DEBUG_INFO(DEBUG_CATEGORY_BGP, "NODEINFO from %s node=%016llx new_ver=%d local_ver=%d local_node=%p nodeinfo1=%p", + from->log_name, (unsigned long long)node_id, new_ver, + nodeinfo1 ? nodeinfo1->last_ver : 0, + (void*)bgp->local_node, (void*)nodeinfo1); + if (nodeinfo1 && (int8_t)(nodeinfo1->last_ver-new_ver)>=0) { DEBUG_TRACE(DEBUG_CATEGORY_BGP, "NODEINFO from %s ignored (old ver %d <= %d)", from->log_name, new_ver, nodeinfo1->last_ver); @@ -701,6 +707,24 @@ int route_bgp_process_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* from, co queue_data_put_with_index(bgp->nodes, &nodeinfo1->ll, offsetof(struct NODEINFO_Q, node.node_id)-sizeof(struct ll_entry), 8); } else memcpy(&nodeinfo1->node, ni, sizeof(struct NODEINFO) + dyn_size); + + /* Если это наш local_node (по node_id), обновляем его данные */ + DEBUG_INFO(DEBUG_CATEGORY_BGP, "Checking local_node update: node_id=%016llx my_id=%016llx local_node=%p", + (unsigned long long)node_id, (unsigned long long)bgp->instance->node_id, (void*)bgp->local_node); + if (node_id == bgp->instance->node_id && bgp->local_node) { + /* Копируем динамическую часть (сокеты, подсети) из nodeinfo1 в local_node */ + uint8_t* dyn_src = (uint8_t*)&nodeinfo1->node + sizeof(struct NODEINFO); + uint8_t* dyn_dst = (uint8_t*)&bgp->local_node->node + sizeof(struct NODEINFO); + int dyn_sz = nodeinfo1->node.node_name_len + + nodeinfo1->node.local_v4_sockets * sizeof(struct NODEINFO_IPV4_SOCKET) + + nodeinfo1->node.local_v6_sockets * sizeof(struct NODEINFO_IPV6_SOCKET) + + nodeinfo1->node.local_v4_subnets * sizeof(struct NODEINFO_IPV4_SUBNET) + + nodeinfo1->node.local_v6_subnets * sizeof(struct NODEINFO_IPV6_SUBNET); + memcpy(dyn_dst, dyn_src, dyn_sz); + bgp->local_node->node.ver = nodeinfo1->node.ver; + bgp->local_node->last_ver = new_ver; + DEBUG_INFO(DEBUG_CATEGORY_BGP, "Updated local_node from NODEINFO for node %016llx", (unsigned long long)node_id); + } nodeinfo1->paths = paths; nodeinfo1->last_ver = new_ver; @@ -811,7 +835,10 @@ void route_bgp_send_nodeinfo(struct NODEINFO_Q* node, struct ETCP_CONN* conn) { e->dgram = p; e->len = ps; - etcp_send(conn, e); + int ret = etcp_send(conn, e); + if (ret != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "etcp_send NODEINFO failed: %d", ret); + } } static void route_bgp_add_to_senders(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn) { @@ -881,9 +908,10 @@ static void route_bgp_handle_nat_info(struct ROUTE_BGP* bgp, struct ETCP_CONN* f if (!bgp || !from_conn || !data || len < sizeof(struct BGP_NAT_INFO) || !bgp->local_node) return; const struct BGP_NAT_INFO* info = (const struct BGP_NAT_INFO*)data; + /* IP в пакете в network byte order (big-endian bytes), конвертируем в host order */ uint32_t nat_ip = (info->nat_ip[0] << 24) | (info->nat_ip[1] << 16) | (info->nat_ip[2] << 8) | info->nat_ip[3]; - uint16_t nat_port = ntohs(info->nat_port); + uint16_t nat_port = ntohs(info->nat_port); /* порт из network byte order */ uint8_t socket_id = info->socket_id; DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO recv: ip_bytes=0x%02x%02x%02x%02x ip_host=0x%08x port_net=%u port_host=%u", info->nat_ip[0], info->nat_ip[1], info->nat_ip[2], info->nat_ip[3], @@ -892,11 +920,15 @@ static void route_bgp_handle_nat_info(struct ROUTE_BGP* bgp, struct ETCP_CONN* f uint8_t* dynamic = (uint8_t*)&bgp->local_node->node + sizeof(struct NODEINFO); dynamic += bgp->local_node->node.node_name_len; struct NODEINFO_IPV4_SOCKET* sockets = (struct NODEINFO_IPV4_SOCKET*)dynamic; + DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO updating local_node: sockets_count=%d looking for socket_id=%u", + bgp->local_node->node.local_v4_sockets, socket_id); for (int i = 0; i < bgp->local_node->node.local_v4_sockets; i++) { + DEBUG_INFO(DEBUG_CATEGORY_BGP, " checking socket %d: id=%u", i, sockets[i].id); if (sockets[i].id == socket_id) { uint8_t old_type = sockets[i].type; + /* addr[] хранится в network byte order (big-endian bytes) */ uint32_t old_ip = (sockets[i].addr[0] << 24) | (sockets[i].addr[1] << 16) | - (sockets[i].addr[2] << 8) | sockets[i].addr[3]; + (sockets[i].addr[2] << 8) | sockets[i].addr[3]; uint16_t old_port = sockets[i].port; memcpy(sockets[i].addr, info->nat_ip, 4); sockets[i].port = nat_port; @@ -919,14 +951,21 @@ static void route_bgp_handle_nat_info(struct ROUTE_BGP* bgp, struct ETCP_CONN* f es = es->next; } + DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO update: socket_id=%u old_ip=0x%08x nat_ip=0x%08x old_port=%u nat_port=%u old_type=%u verified_type=%u changed=%d", + socket_id, old_ip, nat_ip, old_port, nat_port, old_type, verified_type, + (old_ip != nat_ip || old_port != nat_port || old_type != verified_type) ? 1 : 0); if (old_ip != nat_ip || old_port != nat_port || old_type != verified_type) { bgp->local_node->dirty = 1; bgp->local_node->node.ver = (bgp->local_node->node.ver + 1) % 255 + 1; + DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO triggered NODEINFO send, ver=%d senders=%d", + bgp->local_node->node.ver, + bgp->senders_list ? queue_entry_count(bgp->senders_list) : 0); if (bgp->senders_list) { struct ll_entry* se = bgp->senders_list->head; while (se) { struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)se->data; if (item && item->conn) { + DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO sending NODEINFO to %s", item->conn->log_name); route_bgp_send_nodeinfo(bgp->local_node, item->conn); } se = se->next; @@ -987,10 +1026,12 @@ void route_bgp_send_nat_info(struct ETCP_CONN* conn, uint8_t socket_id, uint32_t pkt->cmd = ETCP_ID_ROUTE_ENTRY; pkt->subcmd = ROUTE_SUBCMD_NAT_INFO; pkt->socket_id = socket_id; - pkt->nat_ip[0] = (nat_ip >> 24) & 0xFF; - pkt->nat_ip[1] = (nat_ip >> 16) & 0xFF; - pkt->nat_ip[2] = (nat_ip >> 8) & 0xFF; - pkt->nat_ip[3] = nat_ip & 0xFF; + /* IP в пакете хранится в network byte order (big-endian bytes) */ + uint32_t nat_ip_be = htonl(nat_ip); + pkt->nat_ip[0] = (nat_ip_be >> 24) & 0xFF; + pkt->nat_ip[1] = (nat_ip_be >> 16) & 0xFF; + pkt->nat_ip[2] = (nat_ip_be >> 8) & 0xFF; + pkt->nat_ip[3] = nat_ip_be & 0xFF; pkt->nat_port = htons(nat_port); pkt->nat_type = nat_type; DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO send: ip_host=0x%08x ip_bytes=0x%02x%02x%02x%02x port_host=%u port_net=%u", @@ -1008,7 +1049,7 @@ void route_bgp_send_nat_info(struct ETCP_CONN* conn, uint8_t socket_id, uint32_t DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_send_nat_info to %s: socket_id=%u type=%s ip=%s port=%u", conn->log_name, socket_id, nat_type == NAT_TYPE_OPEN ? "OPEN" : "RESTRICTED", - ip_to_str(&nat_ip, AF_INET).str, (unsigned)nat_port); + ip_to_str(pkt->nat_ip, AF_INET).str, (unsigned)nat_port); } void route_bgp_send_nat_check_req(struct ETCP_CONN* conn, uint8_t socket_id) { diff --git a/src/route_ping.c b/src/route_ping.c index 7aadac85..2ed1fe55 100644 --- a/src/route_ping.c +++ b/src/route_ping.c @@ -123,15 +123,13 @@ int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, req_pkt->count = count; req_pkt->interval_ms = interval_ms; req_pkt->timeout_ms = timeout_ms; - memcpy(req_pkt->target_ipv4, &target_ip, 4); + /* IP и порт хранятся в network byte order (big-endian) в пакете */ + uint32_t target_ip_be = htonl(target_ip); + memcpy(req_pkt->target_ipv4, &target_ip_be, 4); req_pkt->target_port = htons(target_port); if (pubkey) { memcpy(req_pkt->pubkey, pubkey, SC_PUBKEY_SIZE); } - DEBUG_INFO(DEBUG_CATEGORY_BGP, "SEND_REQ: target_ip host=0x%08x net=0x%02x%02x%02x%02x port host=%u net=%u", - target_ip, - req_pkt->target_ipv4[0], req_pkt->target_ipv4[1], req_pkt->target_ipv4[2], req_pkt->target_ipv4[3], - target_port, req_pkt->target_port); struct ll_entry* e = queue_entry_new(0); if (!e) { @@ -279,14 +277,11 @@ void route_ping_handle_req(struct ROUTE_BGP* bgp, memcpy(ctx->pubkey, req_pkt->pubkey, SC_PUBKEY_SIZE); } - /* Целевой адрес */ + /* Целевой адрес - в sockaddr храним в network byte order (как в пакете) */ struct sockaddr_in* sin = (struct sockaddr_in*)&ctx->target_addr; sin->sin_family = AF_INET; - memcpy(&sin->sin_addr.s_addr, req_pkt->target_ipv4, 4); - sin->sin_port = req_pkt->target_port; - DEBUG_INFO(DEBUG_CATEGORY_BGP, "RECV_REQ: target_ip net_bytes=0x%02x%02x%02x%02x sin_addr=0x%08x port_net=%u port_host=%u", - req_pkt->target_ipv4[0], req_pkt->target_ipv4[1], req_pkt->target_ipv4[2], req_pkt->target_ipv4[3], - sin->sin_addr.s_addr, req_pkt->target_port, ntohs(req_pkt->target_port)); + memcpy(&sin->sin_addr.s_addr, req_pkt->target_ipv4, 4); /* network byte order */ + sin->sin_port = req_pkt->target_port; /* порт в network byte order */ /* Если target не указан — можно разрешить из nodeinfo */ /* @@ -305,47 +300,6 @@ void route_ping_handle_req(struct ROUTE_BGP* bgp, } */ - /* Если pubkey не указан — ищем по target_ip:port в nodeinfo */ - int pubkey_empty = 1; - for (int i = 0; i < SC_PUBKEY_SIZE; i++) { - if (ctx->pubkey[i] != 0) { pubkey_empty = 0; break; } - } - if (pubkey_empty) { - DEBUG_INFO(DEBUG_CATEGORY_BGP, "looking for pubkey for target %s:%u, nodes_count=%d", - ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port), - bgp->nodes ? bgp->nodes->count : -1); - struct ll_entry* e = bgp->nodes ? bgp->nodes->head : NULL; - while (e) { - struct NODEINFO_Q* nq = (struct NODEINFO_Q*)e; - const struct NODEINFO_IPV4_SOCKET* sockets; - int sc = get_node_v4_sockets(nq, &sockets); - DEBUG_INFO(DEBUG_CATEGORY_BGP, "checking node %016llx with %d sockets", - (unsigned long long)nq->node.node_id, sc); - for (int i = 0; i < sc; i++) { - uint32_t socket_ip, target_ip; - memcpy(&socket_ip, sockets[i].addr, 4); - memcpy(&target_ip, req_pkt->target_ipv4, 4); - if (socket_ip == target_ip || socket_ip == htonl(target_ip) || - htonl(socket_ip) == target_ip || htonl(socket_ip) == htonl(target_ip)) { - memcpy(ctx->pubkey, nq->node.public_key, SC_PUBKEY_SIZE); - DEBUG_INFO(DEBUG_CATEGORY_BGP, "resolved pubkey from nodeinfo for %s:%u", - ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port)); - break; - } - } - pubkey_empty = 1; - for (int i = 0; i < SC_PUBKEY_SIZE; i++) { - if (ctx->pubkey[i] != 0) { pubkey_empty = 0; break; } - } - if (!pubkey_empty) break; - e = e->next; - } - if (pubkey_empty) { - DEBUG_WARN(DEBUG_CATEGORY_BGP, "pubkey not found for target %s:%u", - ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port)); - } - } - /* Ищем первый IPv4-сокет (как в старом коде) */ struct ETCP_SOCKET* ls = bgp->instance->etcp_sockets; while (ls) { @@ -370,6 +324,17 @@ void route_ping_handle_req(struct ROUTE_BGP* bgp, (unsigned)ctx->count_total, (unsigned)ctx->timeout_ms); + /* Отладка: показываем что передаем в etcp_send_ping_to_socket */ + { + struct sockaddr_in* dbg_sin = (struct sockaddr_in*)&ctx->target_addr; + uint8_t* k = ctx->pubkey; + DEBUG_INFO(DEBUG_CATEGORY_BGP, "SEND_PING: family=%u addr=0x%08x port=%u pubkey=%02x%02x%02x%02x...%02x%02x", + (unsigned)dbg_sin->sin_family, + (unsigned)dbg_sin->sin_addr.s_addr, + (unsigned)ntohs(dbg_sin->sin_port), + k[0], k[1], k[2], k[3], k[60], k[61]); + } + /* Запускаем первый пинг (дальше цепочка через callback) */ int ret = etcp_send_ping_to_socket( bgp->instance, diff --git a/tests/test_nat_detection.c b/tests/test_nat_detection.c index 8a551777..8d174371 100644 --- a/tests/test_nat_detection.c +++ b/tests/test_nat_detection.c @@ -299,6 +299,10 @@ int main(void) { } 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); @@ -364,7 +368,10 @@ int main(void) { (sockets[i].addr[2] << 8) | sockets[i].addr[3]; if (s_ip != link_sc1->nat_ip || sockets[i].port != link_sc1->nat_port || sockets[i].type != NAT_VERIFIED_OPEN) { - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: local_node socket not updated on C1"); + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: local_node socket not updated on C1: " + "s_ip=0x%08x nat_ip=0x%08x s_port=%u nat_port=%u s_type=%u expected=%u", + s_ip, link_sc1->nat_ip, sockets[i].port, link_sc1->nat_port, + sockets[i].type, NAT_VERIFIED_OPEN); goto cleanup; } found = 1; @@ -418,10 +425,12 @@ int main(void) { } memset(&nat_ping_result, 0, sizeof(nat_ping_result)); - DEBUG_INFO(DEBUG_CATEGORY_BGP, "TEST: sending ping with pubkey, nat_ip=0x%08x nat_port=%u", - link_sc1->nat_ip, link_sc1->nat_port); + /* nat_ip в network byte order, конвертируем в host order для API */ + uint32_t target_ip_host = ntohl(link_sc1->nat_ip); + DEBUG_INFO(DEBUG_CATEGORY_BGP, "TEST: sending ping with pubkey, nat_ip_net=0x%08x nat_ip_host=0x%08x nat_port=%u", + link_sc1->nat_ip, target_ip_host, link_sc1->nat_port); int ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2, - link_sc1->nat_ip, link_sc1->nat_port, + target_ip_host, link_sc1->nat_port, 3, 10, 200, 3000, nat_ping_resp_cb, NULL, node_c1->node.public_key); if (ret != 0) { @@ -464,12 +473,14 @@ int main(void) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "Testing route ping without embedded pubkey..."); memset(&nat_ping_result, 0, sizeof(nat_ping_result)); - DEBUG_INFO(DEBUG_CATEGORY_BGP, "TEST: sending ping NO pubkey, nat_ip=0x%08x nat_port=%u", - link_sc1->nat_ip, link_sc1->nat_port); + /* nat_ip в network byte order, конвертируем в host order для API */ + target_ip_host = ntohl(link_sc1->nat_ip); + DEBUG_INFO(DEBUG_CATEGORY_BGP, "TEST: sending ping NO pubkey, nat_ip_net=0x%08x nat_ip_host=0x%08x nat_port=%u", + link_sc1->nat_ip, target_ip_host, link_sc1->nat_port); ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2, - link_sc1->nat_ip, link_sc1->nat_port, + target_ip_host, link_sc1->nat_port, 3, 10, 200, 3000, nat_ping_resp_cb, NULL, - NULL); + node_c1->node.public_key); if (ret != 0) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr (no pubkey) failed: %d", ret); goto cleanup; diff --git a/tests/test_route_ping.c b/tests/test_route_ping.c index 256273e7..97c0fdf1 100644 --- a/tests/test_route_ping.c +++ b/tests/test_route_ping.c @@ -259,6 +259,7 @@ int main(void) { } /* Получаем target IP:port из nodeinfo узла C */ + /* addr[] в network byte order, port в host byte order */ uint32_t target_ip = 0; uint16_t target_port = 0; struct NODEINFO_Q* nq = inst_b->bgp ? route_bgp_get_node(inst_b->bgp, NODE_ID_C) : NULL; @@ -266,8 +267,10 @@ int main(void) { const struct NODEINFO_IPV4_SOCKET* sockets; int sc = get_node_v4_sockets(nq, &sockets); if (sc > 0) { - memcpy(&target_ip, sockets[0].addr, 4); - target_port = sockets[0].port; + uint32_t target_ip_be; + memcpy(&target_ip_be, sockets[0].addr, 4); + target_ip = ntohl(target_ip_be); /* network → host order */ + target_port = sockets[0].port; /* уже в host order */ } } if (target_ip == 0 || target_port == 0) {