Browse Source

refactor(nat_detection): remove BGP dependency, auto trigger on conn_up, clean API

- find_third_node: use nd->inst->connections instead of group->senders_list
- on_conn_up callback auto-calls trigger_checks (no BGP handshake needed)
- Remove group param from link_ready, request_check_all — nat_detection self-sufficient
- Remove trigger_checks + route_ping_cancel_for_conn from public API (internal only)
- topo_group.c: removed last nat_detection_trigger_checks call — completely decoupled
- Header: 4-line summary, no duplicate function list, 7 public functions
topo_upd
Evgeny 3 months ago
parent
commit
b238089678
  1. 5
      src/control_server.c
  2. 3
      src/etcp_connections.c
  3. 71
      src/nat_detection.c
  4. 47
      src/nat_detection.h
  5. 1
      src/topo_group.c

5
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;

3
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) {

71
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 <stdlib.h>
#include <string.h>
@ -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;
}

47
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

1
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);

Loading…
Cancel
Save