diff --git a/src/control_server.c b/src/control_server.c index 1ddcb0ba..815641d7 100644 --- a/src/control_server.c +++ b/src/control_server.c @@ -785,9 +785,8 @@ static void handle_client_data(struct control_server* server, struct control_cli struct etcpmon_cmd_action* cmd = (struct etcpmon_cmd_action*)payload; if (strncmp(cmd->action, "nat", 3) == 0) { DEBUG_INFO(DEBUG_CATEGORY_CONTROL, "Action 'nat' received, requesting NAT check for all links"); - struct TOPO_GROUP* g = topo_groups_get_default(server->instance->topo_groups); - if (server->instance->nat_det && g) - nat_detection_request_check_all(server->instance->nat_det, g); + if (server->instance->nat_det) + nat_detection_request_check_all(server->instance->nat_det); } else if (strncmp(cmd->action, "nodes", 5) == 0) { DEBUG_INFO(DEBUG_CATEGORY_CONTROL, "Action 'nodes' received, dumping all BGP nodes"); uint16_t text_max = (ETCPMON_MAX_MSG_SIZE > 1024) ? ETCPMON_MAX_MSG_SIZE - 512 : 1024; diff --git a/src/etcp_connections.c b/src/etcp_connections.c index b394c3d3..1daf387a 100644 --- a/src/etcp_connections.c +++ b/src/etcp_connections.c @@ -1381,8 +1381,7 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk start_keepalive_timer(link); loadbalancer_link_ready(link); // Restart NAT check after link is up (e.g. after address change or reinit) - { struct TOPO_GROUP* g = topo_groups_get_default(link->etcp->instance->topo_groups); - if (link->etcp->instance->nat_det && g) nat_detection_link_ready(link->etcp->instance->nat_det, g, link); } + if (link->etcp->instance->nat_det) nat_detection_link_ready(link->etcp->instance->nat_det, link); } static int handle_init_response_client(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, struct ETCP_LINK* link, uint8_t pkt_code, size_t pkt_len) { diff --git a/src/nat_detection.c b/src/nat_detection.c index 7547431c..0e2e4ef0 100644 --- a/src/nat_detection.c +++ b/src/nat_detection.c @@ -1,11 +1,11 @@ /** * @file nat_detection.c - * @brief NAT-детекция: STUN-like проверка через третьего BGP-пира. + * @brief NAT-детекция: STUN-like проверка через третьего пира. * * Самодостаточный модуль: * - Сам биндится на ETCP_ID_NAT_DETECTION (0x02) и принимает свои пакеты - * - Сам подписывается на on_down новых ETCP-соединений (отмена pending) - * - Получает trigger_checks из topo_group после заполнения senders_list + * - Сам подписывается на conn_up/conn_down новых ETCP-соединений + * - Ищет третий узел прямо в instance->connections (без привязки к BGP-группе) */ #include #include @@ -33,16 +33,16 @@ /* ====== Internal NAT check logic ====== */ -static struct ETCP_CONN* nat_check_find_third_node(struct TOPO_GROUP* group, struct ETCP_CONN* exclude) { - if (!group || !group->senders_list) return NULL; - struct ll_entry* e = group->senders_list->head; +static struct ETCP_CONN* nat_check_find_third_node(struct NAT_DETECTION* nd, struct ETCP_CONN* exclude) { + if (!nd || !nd->inst || !nd->inst->connections) return NULL; + struct ll_entry* e = nd->inst->connections->head; while (e) { - struct TOPO_GROUP_CONN_ITEM* item = (struct TOPO_GROUP_CONN_ITEM*)e->data; - if (item && item->conn && item->conn != exclude && item->conn->links - && item->conn->links->remote_only_local == 0 - && item->conn->links->remote_type != CFG_SERVER_TYPE_PRIVATE - && item->conn->links->remote_type != CFG_SERVER_TYPE_LOCAL) - return item->conn; + struct conn_queue_entry* ce = (struct conn_queue_entry*)e->data; + if (ce->conn && ce->conn != exclude && ce->conn->links + && ce->conn->links->remote_only_local == 0 + && ce->conn->links->remote_type != CFG_SERVER_TYPE_PRIVATE + && ce->conn->links->remote_type != CFG_SERVER_TYPE_LOCAL) + return ce->conn; e = e->next; } return NULL; @@ -69,15 +69,14 @@ static void nat_link_check_cb(int success, uint16_t avg_rtt, uint8_t count_sent, u_free(na); } -static void nat_detection_start_link_check(struct NAT_DETECTION* nd, struct TOPO_GROUP* group, - struct ETCP_LINK* link) { - if (!nd || !group || !link || !link->conn || !link->etcp) return; +static void nat_detection_start_link_check(struct NAT_DETECTION* nd, struct ETCP_LINK* link) { + if (!nd || !link || !link->conn || !link->etcp) return; if (link->nat_type == NAT_TYPE_DIRECT) return; if (link->nat_check_status == NAT_CHECK_IN_PROGRESS) return; if (link->conn->type == CFG_SERVER_TYPE_PRIVATE || link->conn->type == CFG_SERVER_TYPE_LOCAL) { DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "skip nat check for private/local socket link"); return; } - struct ETCP_CONN* third_conn = nat_check_find_third_node(group, link->etcp); + struct ETCP_CONN* third_conn = nat_check_find_third_node(nd, link->etcp); if (!third_conn) { DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "no third node found for link"); return; } uint32_t target_ip; uint16_t target_port; @@ -92,6 +91,8 @@ static void nat_detection_start_link_check(struct NAT_DETECTION* nd, struct TOPO ip_to_str(&target_ip, AF_INET).str); return; } + struct TOPO_GROUP* group = topo_groups_get_default(nd->inst->topo_groups); + if (!group) return; struct nat_check_arg* arg = u_calloc(1, sizeof(struct nat_check_arg)); if (!arg) return; arg->link = link; arg->nat_ip = target_ip; arg->nat_port = target_port; @@ -204,12 +205,20 @@ static void nat_detection_handle_nat_check_req(struct NAT_DETECTION* nd, struct } if (!target_link) return; if (target_link->nat_check_status == NAT_CHECK_IN_PROGRESS) return; - nat_detection_start_link_check(nd, group, target_link); + nat_detection_start_link_check(nd, target_link); } /* ====== ETCP callbacks (self-registering) ====== */ +static void nat_detection_trigger_checks(struct NAT_DETECTION* nd); + +static void nat_detection_on_conn_up(struct ETCP_CONN* conn, void* arg) { + struct NAT_DETECTION* nd = (struct NAT_DETECTION*)arg; + if (!nd) return; + nat_detection_trigger_checks(nd); +} + static void nat_detection_on_conn_down(struct ETCP_CONN* conn, void* arg) { struct NAT_DETECTION* nd = (struct NAT_DETECTION*)arg; if (!nd || !conn) return; @@ -225,6 +234,7 @@ static void nat_detection_new_conn_cbk(struct ETCP_CONN* conn, void* arg) { if (!conn || !conn->instance) return; struct NAT_DETECTION* nd = (struct NAT_DETECTION*)arg; DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT detection set callbacks: %s", conn->log_name); + etcp_conn_add_up_cbk(conn, nat_detection_on_conn_up, nd); etcp_conn_add_down_cbk(conn, nat_detection_on_conn_down, nd); } @@ -274,17 +284,17 @@ static void nat_detection_receive_cbk(struct ETCP_CONN* from_conn, struct ll_ent } -/* ====== NAT check trigger (called from topo_group after senders_list updated) ====== */ +/* ====== NAT check trigger ====== */ -void nat_detection_trigger_checks(struct NAT_DETECTION* nd, struct TOPO_GROUP* group) { - if (!nd || !group || !nd->inst) return; +static void nat_detection_trigger_checks(struct NAT_DETECTION* nd) { + if (!nd || !nd->inst) return; struct ll_entry* entry = nd->inst->connections->head; while (entry) { struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data; struct ETCP_LINK* l = ce->conn->links; while (l) { if (l->initialized && l->conn && l->nat_check_status < NAT_CHECK_IN_PROGRESS) - nat_detection_start_link_check(nd, group, l); + nat_detection_start_link_check(nd, l); l = l->next; } entry = entry->next; @@ -319,11 +329,10 @@ void nat_detection_destroy(struct NAT_DETECTION* nd) { /* ====== Link lifecycle ====== */ -void nat_detection_link_ready(struct NAT_DETECTION* nd, struct TOPO_GROUP* group, - struct ETCP_LINK* link) { - if (!nd || !group || !link) return; +void nat_detection_link_ready(struct NAT_DETECTION* nd, struct ETCP_LINK* link) { + if (!nd || !link) return; if (link->nat_check_status < NAT_CHECK_IN_PROGRESS) - nat_detection_start_link_check(nd, group, link); + nat_detection_start_link_check(nd, link); } void nat_detection_cancel_for_conn(struct NAT_DETECTION* nd, struct ETCP_CONN* conn) { @@ -386,21 +395,19 @@ static void nat_detection_send_nat_check_req(struct NAT_DETECTION* nd, struct ET /* ====== Control API ====== */ -void nat_detection_request_check_all(struct NAT_DETECTION* nd, struct TOPO_GROUP* group) { - if (!nd || !group || !group->instance) return; - int count = 0; - struct ll_entry* entry = group->instance->connections->head; +void nat_detection_request_check_all(struct NAT_DETECTION* nd) { + if (!nd || !nd->inst) return; + struct ll_entry* entry = nd->inst->connections->head; while (entry) { struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data; struct ETCP_LINK* link = ce->conn->links; while (link) { if (link->nat_check_status < NAT_CHECK_IN_PROGRESS) - nat_detection_start_link_check(nd, group, link); - count++; link = link->next; + nat_detection_start_link_check(nd, link); + link = link->next; } entry = entry->next; } - (void)count; } diff --git a/src/nat_detection.h b/src/nat_detection.h index 589faa4b..2355be7d 100644 --- a/src/nat_detection.h +++ b/src/nat_detection.h @@ -1,25 +1,11 @@ /** * @file nat_detection.h - * @brief NAT-детекция через третьего BGP-пира (STUN-like ping). + * @brief NAT-детекция через третьего пира (STUN-like ping). * - * Модуль полностью самодостаточен: - * - Владеет своим ETCP_ID (0x02), сам биндится на приём своих пакетов - * - Сам подписывается на conn_down новых ETCP-соединений (отмена pending пингов) - * - NAT-чек запускается через trigger_checks (из topo_group, после senders_list) - * или link_ready (из etcp_connections, при поднятии линка) - * - Получив результат NAT-чека — сам обновляет ETCP_SOCKET, local_node и - * делает broadcast NODEINFO через topo_group - * - * Публичное API (9 функций): - * create / destroy — жизненный цикл, вызывается из topo_groups_init/destroy - * trigger_checks — запуск чека всех линков, из topo_group_new_conn - * link_ready — запуск чека одного линка, из etcp_connections - * cancel_for_conn — отмена pending при реините/смене адреса - * send_nat_info — немедленное уведомление (DIRECT detection) - * request_check_all — принудительная перепроверка (control API) - * set_allow_local — разрешить чек loopback (тесты) - * route_ping_send_req_addr — низкоуровневый STUN-пинг (тесты) - * route_ping_cancel_for_conn — отмена одного pending-пинга + * Самодостаточный модуль на своём ETCP_ID (0x02): + * сам биндится, сам подписывается на conn_up/conn_down, + * ищет третий узел прямо в instance->connections, + * обновляет ETCP_SOCKET/loc_node и broadcast-ит NODEINFO. */ #ifndef NAT_DETECTION_H #define NAT_DETECTION_H @@ -121,9 +107,7 @@ struct nat_check_arg { /* -------- Жизненный цикл -------- */ -/** Создать модуль: etcp_bind на 0x02, подписка на new_conn для on_down очистки. - * Вызывается из topo_groups_init(). */ - +/** Создать модуль: etcp_bind на 0x02, подписка на new_conn (on_up + on_down). */ struct NAT_DETECTION* nat_detection_create(struct UTUN_INSTANCE* inst); /** Уничтожить: отписаться от new_conn, etcp_unbind, очистить pending пинги. @@ -133,20 +117,10 @@ void nat_detection_destroy(struct NAT_DETECTION* nd); /* -------- Служебные: вызываются другими модулями в ответ на события ETCP -------- */ -/** - * Запустить NAT-чек для всех линков у которых nat_check_status < IN_PROGRESS. - * - * ВАЖНО: должен вызываться из topo_group_new_conn() ПОСЛЕ topo_group_add_to_senders() — - * только тогда новый пир есть в senders_list и find_third_node сможет его найти. - */ - -void nat_detection_trigger_checks(struct NAT_DETECTION* nd, struct TOPO_GROUP* group); - /** Линк поднялся (INIT handshake завершён) — запустить для него NAT-чек. * Вызывается из etcp_connections: handle_init_response_server(). */ -void nat_detection_link_ready(struct NAT_DETECTION* nd, struct TOPO_GROUP* group, - struct ETCP_LINK* link); +void nat_detection_link_ready(struct NAT_DETECTION* nd, struct ETCP_LINK* link); /** Отменить все pending NAT-пинги для соединения и сбросить nat_check_status. * Вызывается из etcp.c при реините и etcp_connections.c при смене адреса линка. */ @@ -165,7 +139,7 @@ void nat_detection_send_nat_info(struct NAT_DETECTION* nd, struct ETCP_CONN* to_ /** Принудительная перепроверка NAT для всех линков (etcpmon команда "nat"). * Вызывается из control_server. */ -void nat_detection_request_check_all(struct NAT_DETECTION* nd, struct TOPO_GROUP* group); +void nat_detection_request_check_all(struct NAT_DETECTION* nd); /* -------- Тестовые хелперы -------- */ @@ -185,11 +159,6 @@ int route_ping_send_req_addr(struct NAT_DETECTION* nd, struct TOPO_GROUP* group, uint16_t wait_timeout_ms, route_ping_callback_t cb, void* arg, const uint8_t* pubkey); -/** Отменить ожидающий пинг для указанного соединения. */ - -void route_ping_cancel_for_conn(struct NAT_DETECTION* nd, struct ETCP_CONN* conn); - - #ifdef __cplusplus } #endif diff --git a/src/topo_group.c b/src/topo_group.c index 6f3b7606..af42084e 100644 --- a/src/topo_group.c +++ b/src/topo_group.c @@ -362,7 +362,6 @@ void topo_group_new_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { struct TOPO_NODEQ* peer_nq = topo_node_find_by_id(group, conn->peer_node_id); topo_group_add_to_senders(group, conn); - if (group->instance->nat_det) nat_detection_trigger_checks(group->instance->nat_det, group); if (peer_nq && peer_nq->alien) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "peer 0x%016llx is alien, skipping route exchange", (unsigned long long)conn->peer_node_id); DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "topo_group_new_conn: peer=%016llx group=%016llx type=%d ch=%s ALIEN=1 — SKIP", (unsigned long long)conn->peer_node_id, (unsigned long long)group->group_id, group->group_type, group->channel_id); return; } DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "topo_group_new_conn: peer=%016llx group=%016llx type=%d ch=%s alien=%d", (unsigned long long)conn->peer_node_id, (unsigned long long)group->group_id, group->group_type, group->channel_id, peer_nq ? peer_nq->alien : -1);