Browse Source

topo_group: disable in chatgui; fix NAT detection for matching addresses

- Add utun_instance_set_topo_group_enabled() flag (default=1, chatgui sets 0)
- Move nat_detection create/destroy from topo_group.c to utun_instance.c (unconditional)
- NAT detection: simplify third_node search (any connected node)
- NAT detection: allow NULL topo_groups in receive_cbk and handlers
- NAT detection: handle NAT_INFO without topo_group (update socket directly)
- route_ping: make TOPO_GROUP optional in send_req_addr/handle_req
- topo_node: when NAT verified and address matches interface, set entry type to NAT instead of INTERFACE + socket_id|1
- topo_node: detect nat_type change in changed computation for rebuild
- test_nat_detection: fix socket_id check (|1 for NAT entries)
- chatgui: call utun_instance_set_topo_group_enabled(0)
topo_upd
Evgeny 3 months ago
parent
commit
501b636d19
  1. 137
      src/nat_detection.c
  2. 16
      src/route_ping.c
  3. 7
      src/topo_group.c
  4. 31
      src/topo_node.c
  5. 39
      src/utun_instance.c
  6. 1
      src/utun_instance.h
  7. 2
      tests/test_nat_detection.c
  8. 1
      tools/chatgui/transport/utun_node.cpp

137
src/nat_detection.c

@ -38,10 +38,7 @@ static struct ETCP_CONN* nat_check_find_third_node(struct NAT_DETECTION* nd, str
struct ll_entry* e = nd->inst->connections->head; struct ll_entry* e = nd->inst->connections->head;
while (e) { while (e) {
struct conn_queue_entry* ce = (struct conn_queue_entry*)e->data; struct conn_queue_entry* ce = (struct conn_queue_entry*)e->data;
if (ce->conn && ce->conn != exclude && ce->conn->links 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; return ce->conn;
e = e->next; e = e->next;
} }
@ -91,8 +88,8 @@ static void nat_detection_start_link_check(struct NAT_DETECTION* nd, struct ETCP
ip_to_str(&target_ip, AF_INET).str); return; ip_to_str(&target_ip, AF_INET).str); return;
} }
struct TOPO_GROUP* group = topo_groups_get_default(nd->inst->topo_groups); struct TOPO_GROUP* group = nd->inst->topo_groups
if (!group) return; ? topo_groups_get_default(nd->inst->topo_groups) : NULL;
struct nat_check_arg* arg = u_calloc(1, sizeof(struct nat_check_arg)); struct nat_check_arg* arg = u_calloc(1, sizeof(struct nat_check_arg));
if (!arg) return; if (!arg) return;
arg->link = link; arg->nat_ip = target_ip; arg->nat_port = target_port; arg->link = link; arg->nat_ip = target_ip; arg->nat_port = target_port;
@ -117,8 +114,7 @@ static void nat_detection_start_link_check(struct NAT_DETECTION* nd, struct ETCP
static void nat_detection_handle_nat_info(struct NAT_DETECTION* nd, struct TOPO_GROUP* group, static void nat_detection_handle_nat_info(struct NAT_DETECTION* nd, struct TOPO_GROUP* group,
struct ETCP_CONN* from_conn, struct ETCP_CONN* from_conn,
const uint8_t* data, size_t len) { const uint8_t* data, size_t len) {
if (!nd || !group || !from_conn || !data || len < sizeof(struct NATDET_MSG_NAT_INFO) if (!nd || !from_conn || !data || len < sizeof(struct NATDET_MSG_NAT_INFO)) return;
|| !group->local_node || !group->local_node->node) return;
const struct NATDET_MSG_NAT_INFO* info = (const struct NATDET_MSG_NAT_INFO*)data; const struct NATDET_MSG_NAT_INFO* info = (const struct NATDET_MSG_NAT_INFO*)data;
uint32_t nat_ip = (info->nat_ip[0] << 24) | (info->nat_ip[1] << 16) uint32_t nat_ip = (info->nat_ip[0] << 24) | (info->nat_ip[1] << 16)
@ -132,8 +128,8 @@ static void nat_detection_handle_nat_info(struct NAT_DETECTION* nd, struct TOPO_
else if (info->nat_type == NAT_TYPE_DIRECT) verified_type = NAT_VERIFIED_DIRECT; else if (info->nat_type == NAT_TYPE_DIRECT) verified_type = NAT_VERIFIED_DIRECT;
else verified_type = NAT_VERIFIED_UNKNOWN; else verified_type = NAT_VERIFIED_UNKNOWN;
int data_changed = 0; if (group && group->local_node && group->local_node->node) {
{ int data_changed = 0;
struct TOPO_SOCKMETA4* sm = group->local_node->node->v4_sock_meta; struct TOPO_SOCKMETA4* sm = group->local_node->node->v4_sock_meta;
while (sm) { while (sm) {
if (sm->id == socket_id) { if (sm->id == socket_id) {
@ -142,48 +138,81 @@ static void nat_detection_handle_nat_info(struct NAT_DETECTION* nd, struct TOPO_
} }
sm = sm->next; sm = sm->next;
} }
}
struct ETCP_SOCKET* es = group->instance->etcp_sockets; struct ETCP_SOCKET* es = group->instance->etcp_sockets;
while (es) { while (es) {
if (es->sock_id == socket_id) { if (es->sock_id == socket_id) {
if (verified_type == NAT_VERIFIED_STRICT) { if (verified_type == NAT_VERIFIED_STRICT) {
struct sockaddr_in* nat_sin = (struct sockaddr_in*)&es->nat_addr; struct sockaddr_in* nat_sin = (struct sockaddr_in*)&es->nat_addr;
nat_sin->sin_family = AF_INET; nat_sin->sin_family = AF_INET;
nat_sin->sin_addr.s_addr = nat_ip; nat_sin->sin_addr.s_addr = nat_ip;
nat_sin->sin_port = htons(nat_port); nat_sin->sin_port = htons(nat_port);
es->nat_type = verified_type; es->nat_type = verified_type;
} else { } else {
struct sockaddr_in* nat_sin = (struct sockaddr_in*)&es->nat_addr;
uint32_t old_nat_ip = nat_sin->sin_addr.s_addr;
uint16_t old_nat_port = ntohs(nat_sin->sin_port);
nat_sin->sin_family = AF_INET;
nat_sin->sin_addr.s_addr = nat_ip;
nat_sin->sin_port = htons(nat_port);
if (old_nat_ip != nat_ip || old_nat_port != nat_port) data_changed = 1;
es->nat_type = verified_type;
}
break;
}
es = es->next;
}
if (data_changed) {
int prev_v4a = topo_list_count((struct _topo_head*)group->local_node->node->v4_addrs);
topo_group_update_my_nodeinfo(group->instance, group);
if (topo_list_count((struct _topo_head*)group->local_node->node->v4_addrs) != prev_v4a) {
group->local_node->dirty = 1;
group->local_node->node->ver = (group->local_node->node->ver % 255) + 1;
group->local_node->last_ver = group->local_node->node->ver;
}
if (topo_list_count((struct _topo_head*)group->local_node->node->v4_addrs) == prev_v4a) {
struct TOPO_ADDR4* a = group->local_node->node->v4_addrs;
while (a) {
if (a->type == TOPO_ADDR_INTERFACE && a->socket_id == socket_id) {
uint32_t a_ip; memcpy(&a_ip, a->addr, 4);
if (a_ip == nat_ip && a->port == nat_port) {
a->type = TOPO_ADDR_NAT; a->socket_id = socket_id | 1;
group->local_node->dirty = 1;
group->local_node->node->ver = (group->local_node->node->ver % 255) + 1;
group->local_node->last_ver = group->local_node->node->ver;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO matched interface addr, updated entry type to NAT sock=%d", socket_id);
}
break;
}
a = a->next;
}
}
if (group->local_node->dirty && group->senders_list) {
struct ll_entry* se = group->senders_list->head;
while (se) {
struct TOPO_GROUP_CONN_ITEM* item = (struct TOPO_GROUP_CONN_ITEM*)se->data;
if (item && item->conn)
topo_group_send_nodeinfo(group, group->local_node, item->conn);
se = se->next;
}
}
}
} else {
struct ETCP_SOCKET* es = nd->inst->etcp_sockets;
while (es) {
if (es->sock_id == socket_id) {
struct sockaddr_in* nat_sin = (struct sockaddr_in*)&es->nat_addr; struct sockaddr_in* nat_sin = (struct sockaddr_in*)&es->nat_addr;
uint32_t old_nat_ip = nat_sin->sin_addr.s_addr;
uint16_t old_nat_port = ntohs(nat_sin->sin_port);
nat_sin->sin_family = AF_INET; nat_sin->sin_family = AF_INET;
nat_sin->sin_addr.s_addr = nat_ip; nat_sin->sin_addr.s_addr = nat_ip;
nat_sin->sin_port = htons(nat_port); nat_sin->sin_port = htons(nat_port);
if (old_nat_ip != nat_ip || old_nat_port != nat_port) data_changed = 1;
es->nat_type = verified_type; es->nat_type = verified_type;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO socket=%s id=%d type=%d addr=%s:%u (no topo_group)",
es->name, socket_id, verified_type,
ip_to_str(&nat_ip, AF_INET).str, nat_port);
break;
} }
break; es = es->next;
}
es = es->next;
}
if (data_changed) {
int prev_v4a = topo_list_count((struct _topo_head*)group->local_node->node->v4_addrs);
topo_group_update_my_nodeinfo(group->instance, group);
if (topo_list_count((struct _topo_head*)group->local_node->node->v4_addrs) != prev_v4a) {
group->local_node->dirty = 1;
group->local_node->node->ver = (group->local_node->node->ver % 255) + 1;
group->local_node->last_ver = group->local_node->node->ver;
}
if (group->local_node->dirty && group->senders_list) {
struct ll_entry* se = group->senders_list->head;
while (se) {
struct TOPO_GROUP_CONN_ITEM* item = (struct TOPO_GROUP_CONN_ITEM*)se->data;
if (item && item->conn)
topo_group_send_nodeinfo(group, group->local_node, item->conn);
se = se->next;
}
} }
} }
@ -194,7 +223,8 @@ static void nat_detection_handle_nat_info(struct NAT_DETECTION* nd, struct TOPO_
static void nat_detection_handle_nat_check_req(struct NAT_DETECTION* nd, struct TOPO_GROUP* group, static void nat_detection_handle_nat_check_req(struct NAT_DETECTION* nd, struct TOPO_GROUP* group,
struct ETCP_CONN* from_conn, struct ETCP_CONN* from_conn,
const uint8_t* data, size_t len) { const uint8_t* data, size_t len) {
if (!nd || !group || !from_conn || !data || len < sizeof(struct NATDET_MSG_NAT_CHECK_REQ)) return; if (!nd || !from_conn || !data || len < sizeof(struct NATDET_MSG_NAT_CHECK_REQ)) return;
(void)group;
const struct NATDET_MSG_NAT_CHECK_REQ* req = (const struct NATDET_MSG_NAT_CHECK_REQ*)data; const struct NATDET_MSG_NAT_CHECK_REQ* req = (const struct NATDET_MSG_NAT_CHECK_REQ*)data;
uint8_t socket_id = req->socket_id; uint8_t socket_id = req->socket_id;
struct ETCP_LINK* target_link = NULL; struct ETCP_LINK* target_link = NULL;
@ -256,20 +286,17 @@ static void nat_detection_receive_cbk(struct ETCP_CONN* from_conn, struct ll_ent
if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return; if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return;
} }
struct UTUN_INSTANCE* instance = from_conn->instance; struct UTUN_INSTANCE* instance = from_conn->instance;
if (!instance || !instance->nat_det || !instance->topo_groups) { if (!instance || !instance->nat_det) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid instance/nat_det/topo_groups"); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid instance/nat_det");
queue_dgram_free(entry); queue_entry_free(entry); return;
}
struct TOPO_GROUP* group = topo_groups_get_default(instance->topo_groups);
if (!group) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "no default group");
queue_dgram_free(entry); queue_entry_free(entry); return; queue_dgram_free(entry); queue_entry_free(entry); return;
} }
struct TOPO_GROUP* group = instance->topo_groups
? topo_groups_get_default(instance->topo_groups) : NULL;
struct NAT_DETECTION* nd = instance->nat_det; struct NAT_DETECTION* nd = instance->nat_det;
uint8_t* data = entry->dgram; uint8_t subcmd = data[1]; uint8_t* data = entry->dgram; uint8_t subcmd = data[1];
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT recv %s from %s len=%zu", DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT recv %s from %s len=%zu group=%s",
nat_subcmd_name(subcmd), from_conn->log_name, entry->len); nat_subcmd_name(subcmd), from_conn->log_name, entry->len, group ? "yes" : "no");
if (subcmd == NATDET_SUBCMD_PING_REQ) if (subcmd == NATDET_SUBCMD_PING_REQ)
route_ping_handle_req(nd, group, from_conn, data, entry->len); route_ping_handle_req(nd, group, from_conn, data, entry->len);

16
src/route_ping.c

@ -171,7 +171,8 @@ int route_ping_send_req_addr(struct NAT_DETECTION* nd, struct TOPO_GROUP* group,
uint8_t count, uint16_t interval_ms, uint16_t timeout_ms, uint8_t count, uint16_t interval_ms, uint16_t timeout_ms,
uint16_t wait_timeout_ms, route_ping_callback_t cb, void* arg, uint16_t wait_timeout_ms, route_ping_callback_t cb, void* arg,
const uint8_t* pubkey) { const uint8_t* pubkey) {
if (!nd || !group || !to_conn || count == 0 || timeout_ms == 0) { (void)group;
if (!nd || !to_conn || count == 0 || timeout_ms == 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args"); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args");
return -1; return -1;
} }
@ -326,8 +327,7 @@ void route_ping_handle_req(struct NAT_DETECTION* nd, struct TOPO_GROUP* group,
struct ETCP_CONN* from_conn, struct ETCP_CONN* from_conn,
const uint8_t* data, const uint8_t* data,
size_t len) { size_t len) {
(void)nd; if (!from_conn || !nd || !data || len < offsetof(struct NATDET_PING_REQ, pubkey)) {
if (!group || !from_conn || !data || len < offsetof(struct NATDET_PING_REQ, pubkey)) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "ping req: bad args len=%zu", len); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "ping req: bad args len=%zu", len);
return; return;
} }
@ -347,8 +347,10 @@ void route_ping_handle_req(struct NAT_DETECTION* nd, struct TOPO_GROUP* group,
ctx->timeout_ms = req_pkt->timeout_ms; ctx->timeout_ms = req_pkt->timeout_ms;
{ {
struct TOPO_NODEQ* req_nq = topo_node_find_by_id(group, from_conn->peer_node_id); if (group) {
if (req_nq) req_nq->connectivity.ping_req_time = get_time_tb(); struct TOPO_NODEQ* req_nq = topo_node_find_by_id(group, from_conn->peer_node_id);
if (req_nq) req_nq->connectivity.ping_req_time = get_time_tb();
}
} }
if (len >= sizeof(struct NATDET_PING_REQ)) { if (len >= sizeof(struct NATDET_PING_REQ)) {
memcpy(ctx->pubkey, req_pkt->pubkey, SC_PUBKEY_SIZE); memcpy(ctx->pubkey, req_pkt->pubkey, SC_PUBKEY_SIZE);
@ -361,7 +363,7 @@ void route_ping_handle_req(struct NAT_DETECTION* nd, struct TOPO_GROUP* group,
sin->sin_port = req_pkt->target_port; /* порт в network byte order */ sin->sin_port = req_pkt->target_port; /* порт в network byte order */
/* Ищем первый IPv4-сокет */ /* Ищем первый IPv4-сокет */
struct ETCP_SOCKET* ls = group->instance->etcp_sockets; struct ETCP_SOCKET* ls = (group ? group->instance : nd->inst)->etcp_sockets;
while (ls) { while (ls) {
if (ls->local_addr.ss_family == AF_INET) { if (ls->local_addr.ss_family == AF_INET) {
ctx->local_sock = ls; ctx->local_sock = ls;
@ -382,7 +384,7 @@ void route_ping_handle_req(struct NAT_DETECTION* nd, struct TOPO_GROUP* group,
/* Запускаем первый пинг (дальше цепочка через callback) */ /* Запускаем первый пинг (дальше цепочка через callback) */
int ret = etcp_send_ping_to_socket( int ret = etcp_send_ping_to_socket(
group->instance, (group ? group->instance : nd->inst),
ctx->local_sock, ctx->local_sock,
ctx->pubkey, ctx->pubkey,
&ctx->target_addr, &ctx->target_addr,

7
src/topo_group.c

@ -276,11 +276,6 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) {
instance->topo_groups = g; instance->topo_groups = g;
g->instance->nat_det = nat_detection_create(instance);
if (!g->instance->nat_det) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NAT detection creation failed");
}
struct TOPO_GROUP* default_group = topo_group_create(instance, TOPO_GROUP_UTUN, TOPO_GROUP_TYPE_UTUN); struct TOPO_GROUP* default_group = topo_group_create(instance, TOPO_GROUP_UTUN, TOPO_GROUP_TYPE_UTUN);
if (!default_group) { if (!default_group) {
memory_pool_destroy(g->v4_sock_meta_pool); memory_pool_destroy(g->v4_addr_pool); memory_pool_destroy(g->v4_sock_meta_pool); memory_pool_destroy(g->v4_addr_pool);
@ -307,8 +302,6 @@ void topo_groups_destroy(struct UTUN_INSTANCE* instance) {
etcp_unbind(instance, ETCP_ID_TOPO_ENTRY); etcp_unbind(instance, ETCP_ID_TOPO_ENTRY);
route_connectivity_cancel_all(instance); route_connectivity_cancel_all(instance);
if (instance->nat_det) { nat_detection_destroy(instance->nat_det); instance->nat_det = NULL; }
struct TOPO_GROUPS* g = instance->topo_groups; struct TOPO_GROUPS* g = instance->topo_groups;
struct ll_entry* ge; struct ll_entry* ge;
while ((ge = queue_data_get(g->group_list)) != NULL) { struct TOPO_GROUP* grp = (struct TOPO_GROUP*)ge; topo_group_destroy(grp); queue_entry_free(ge); } while ((ge = queue_data_get(g->group_list)) != NULL) { struct TOPO_GROUP* grp = (struct TOPO_GROUP*)ge; topo_group_destroy(grp); queue_entry_free(ge); }

31
src/topo_node.c

@ -492,8 +492,13 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
if (e_sock->local_addr.ss_family == AF_INET) { if (e_sock->local_addr.ss_family == AF_INET) {
sock_count++; addr_count++; sock_count++; addr_count++;
if (e_sock->nat_addr.ss_family == AF_INET) { if (e_sock->nat_addr.ss_family == AF_INET) {
struct sockaddr_in* nat_sin = (struct sockaddr_in*)&e_sock->nat_addr; struct sockaddr_in* ns = (struct sockaddr_in*)&e_sock->nat_addr;
if (nat_sin->sin_addr.s_addr != 0 && e_sock->nat_type != NAT_VERIFIED_STRICT) addr_count++; struct sockaddr_in* ls = (struct sockaddr_in*)&e_sock->local_addr;
struct sockaddr_in* ifs = (struct sockaddr_in*)&e_sock->interface_addr;
uint32_t ref_ip = ls->sin_addr.s_addr ? ls->sin_addr.s_addr : ifs->sin_addr.s_addr;
uint16_t ref_port = ntohs(ls->sin_addr.s_addr ? ls->sin_port : ifs->sin_port);
if (ns->sin_addr.s_addr != 0 && e_sock->nat_type != NAT_VERIFIED_STRICT && (ns->sin_addr.s_addr != ref_ip || ntohs(ns->sin_port) != ref_port))
addr_count++;
} }
if (e_sock->nat_type == NAT_VERIFIED_DIRECT || ((e_sock->type == CFG_SERVER_TYPE_PUBLIC || e_sock->type == CFG_SERVER_TYPE_UNKNOWN) && e_sock->nat_type < NAT_VERIFIED_UNKNOWN)) addr_count++; if (e_sock->nat_type == NAT_VERIFIED_DIRECT || ((e_sock->type == CFG_SERVER_TYPE_PUBLIC || e_sock->type == CFG_SERVER_TYPE_UNKNOWN) && e_sock->nat_type < NAT_VERIFIED_UNKNOWN)) addr_count++;
} else if (e_sock->local_addr.ss_family == AF_INET6) { sock6_count++; addr6_count++; } } else if (e_sock->local_addr.ss_family == AF_INET6) { sock6_count++; addr6_count++; }
@ -515,6 +520,16 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
|| (vc6 != (group->local_node->subnets ? topo_list_count((struct _topo_head*)group->local_node->subnets->v6_subnets) : 0)) || (vc6 != (group->local_node->subnets ? topo_list_count((struct _topo_head*)group->local_node->subnets->v6_subnets) : 0))
|| (sock6_count != topo_list_count((struct _topo_head*)oni->v6_sock_meta)) || (sock6_count != topo_list_count((struct _topo_head*)oni->v6_sock_meta))
|| (addr6_count != topo_list_count((struct _topo_head*)oni->v6_addrs)); || (addr6_count != topo_list_count((struct _topo_head*)oni->v6_addrs));
if (!changed && oni->v4_sock_meta) {
struct ETCP_SOCKET* es = instance->etcp_sockets;
struct TOPO_SOCKMETA4* sm = oni->v4_sock_meta;
while (es && sm) {
if (es->type == CFG_SERVER_TYPE_PRIVATE || es->type == CFG_SERVER_TYPE_LOCAL) { es = es->next; continue; }
if (es->local_addr.ss_family != AF_INET) { es = es->next; continue; }
if (sm->nat_type != es->nat_type) { changed = 1; break; }
sm = sm->next; es = es->next;
}
}
if (group->local_node && group->instance && group->instance->topo_groups) if (group->local_node && group->instance && group->instance->topo_groups)
if (memcmp(oni->ed25519_public_key, group->ed25519_public_key, SC_PUBKEY_SIZE) != 0) changed = 1; if (memcmp(oni->ed25519_public_key, group->ed25519_public_key, SC_PUBKEY_SIZE) != 0) changed = 1;
} }
@ -560,15 +575,19 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
struct sockaddr_in* if_sin = (struct sockaddr_in*)&e_sock->interface_addr; struct sockaddr_in* if_sin = (struct sockaddr_in*)&e_sock->interface_addr;
struct sockaddr_in* nat_sin = (struct sockaddr_in*)&e_sock->nat_addr; struct sockaddr_in* nat_sin = (struct sockaddr_in*)&e_sock->nat_addr;
int use_local = (local_sin->sin_addr.s_addr != 0); int use_local = (local_sin->sin_addr.s_addr != 0);
uint32_t ref_ip = use_local ? local_sin->sin_addr.s_addr : if_sin->sin_addr.s_addr;
uint16_t ref_port = ntohs(use_local ? local_sin->sin_port : if_sin->sin_port);
int nat_verified = (e_sock->nat_addr.ss_family == AF_INET && nat_sin->sin_addr.s_addr != 0 && e_sock->nat_type != NAT_VERIFIED_STRICT);
int nat_differs = (nat_verified && (nat_sin->sin_addr.s_addr != ref_ip || ntohs(nat_sin->sin_port) != ref_port));
{ struct TOPO_ADDR4* a = memory_pool_alloc(group->instance->topo_groups->v4_addr_pool); { struct TOPO_ADDR4* a = memory_pool_alloc(group->instance->topo_groups->v4_addr_pool);
memcpy(a->addr, use_local ? &local_sin->sin_addr.s_addr : &if_sin->sin_addr.s_addr, 4); memcpy(a->addr, use_local ? &local_sin->sin_addr.s_addr : &if_sin->sin_addr.s_addr, 4);
a->port = ntohs(use_local ? local_sin->sin_port : if_sin->sin_port); a->port = ntohs(use_local ? local_sin->sin_port : if_sin->sin_port);
a->type = TOPO_ADDR_INTERFACE; a->socket_id = e_sock->sock_id; a->protocol = TOPO_PROTO_UDP; a->type = (!nat_differs && nat_verified) ? TOPO_ADDR_NAT : TOPO_ADDR_INTERFACE;
a->socket_id = (a->type == TOPO_ADDR_NAT) ? (e_sock->sock_id | 1) : e_sock->sock_id;
a->protocol = TOPO_PROTO_UDP;
a->next = ni->v4_addrs; ni->v4_addrs = a; } a->next = ni->v4_addrs; ni->v4_addrs = a; }
if (e_sock->nat_addr.ss_family == AF_INET && nat_sin->sin_addr.s_addr != 0 && e_sock->nat_type != NAT_VERIFIED_STRICT if (nat_differs) {
&& (nat_sin->sin_addr.s_addr != (use_local ? local_sin->sin_addr.s_addr : if_sin->sin_addr.s_addr)
|| nat_sin->sin_port != (use_local ? local_sin->sin_port : if_sin->sin_port))) {
struct TOPO_ADDR4* a = memory_pool_alloc(group->instance->topo_groups->v4_addr_pool); struct TOPO_ADDR4* a = memory_pool_alloc(group->instance->topo_groups->v4_addr_pool);
memcpy(a->addr, &nat_sin->sin_addr.s_addr, 4); a->port = ntohs(nat_sin->sin_port); memcpy(a->addr, &nat_sin->sin_addr.s_addr, 4); a->port = ntohs(nat_sin->sin_port);
a->type = TOPO_ADDR_NAT; a->socket_id = e_sock->sock_id | 1; a->protocol = TOPO_PROTO_UDP; a->type = TOPO_ADDR_NAT; a->socket_id = e_sock->sock_id | 1; a->protocol = TOPO_PROTO_UDP;

39
src/utun_instance.c

@ -9,6 +9,7 @@
#include "route_lib.h" #include "route_lib.h"
#include "routing.h" #include "routing.h"
#include "topo_group.h" #include "topo_group.h"
#include "nat_detection.h"
#include "etcp_connections.h" #include "etcp_connections.h"
#include "etcp.h" #include "etcp.h"
#include "conn_mgr.h" #include "conn_mgr.h"
@ -50,6 +51,14 @@ void utun_instance_set_tun_init_enabled(int enabled) {
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN initialization %s", enabled ? "enabled" : "disabled"); DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN initialization %s", enabled ? "enabled" : "disabled");
} }
// Global flag to control topo_group initialization (enabled by default)
static int g_topo_group_enabled = 1;
void utun_instance_set_topo_group_enabled(int enabled) {
g_topo_group_enabled = enabled ? 1 : 0;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "topo_group initialization %s", enabled ? "enabled" : "disabled");
}
static int local_sockaddr_equal(const struct sockaddr_storage *a, const struct sockaddr_storage *b) { static int local_sockaddr_equal(const struct sockaddr_storage *a, const struct sockaddr_storage *b) {
if (!a || !b || a->ss_family != b->ss_family) return 0; if (!a || !b || a->ss_family != b->ss_family) return 0;
if (a->ss_family == AF_INET) { if (a->ss_family == AF_INET) {
@ -177,15 +186,23 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
if (socket_result == 1) { if (socket_result == 1) {
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "Partial socket initialization - some servers failed to bind"); DEBUG_WARN(DEBUG_CATEGORY_ETCP, "Partial socket initialization - some servers failed to bind");
} }
instance->topo_groups = topo_groups_init(instance); instance->nat_det = nat_detection_create(instance);
if (!instance->topo_groups) { if (!instance->nat_det) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NAT detection creation failed"); }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Failed to initialize BGP module");
} else { if (g_topo_group_enabled) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP module initialized"); instance->topo_groups = topo_groups_init(instance);
struct TOPO_GROUP* g = topo_groups_get_default(instance->topo_groups); if (!instance->topo_groups) {
if (instance->rt && g && g->local_node) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Failed to initialize BGP module");
topo_group_update_my_nodeinfo(instance, g); } else {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP module initialized");
struct TOPO_GROUP* g = topo_groups_get_default(instance->topo_groups);
if (instance->rt && g && g->local_node) {
topo_group_update_my_nodeinfo(instance, g);
}
} }
} else {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "topo_group initialization disabled, skipping BGP module");
instance->topo_groups = NULL;
} }
instance->conn_mgr = conn_mgr_init(instance); instance->conn_mgr = conn_mgr_init(instance);
@ -483,6 +500,12 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Destroying BGP module"); DEBUG_INFO(DEBUG_CATEGORY_BGP, "Destroying BGP module");
topo_groups_destroy(instance); topo_groups_destroy(instance);
} }
// Cleanup NAT detection
if (instance->nat_det) {
nat_detection_destroy(instance->nat_det);
instance->nat_det = NULL;
}
// Cleanup firewall // Cleanup firewall
fw_free(&instance->fw); fw_free(&instance->fw);

1
src/utun_instance.h

@ -173,6 +173,7 @@ struct UTUN_INSTANCE *utun_instance_reload(struct UTUN_INSTANCE *instance, struc
void utun_instance_run(struct UTUN_INSTANCE *instance); void utun_instance_run(struct UTUN_INSTANCE *instance);
void utun_instance_stop(struct UTUN_INSTANCE *instance); void utun_instance_stop(struct UTUN_INSTANCE *instance);
void utun_instance_set_tun_init_enabled(int enabled); void utun_instance_set_tun_init_enabled(int enabled);
void utun_instance_set_topo_group_enabled(int enabled);
// Diagnostic function for memory leak analysis // Diagnostic function for memory leak analysis
void utun_instance_diagnose_leaks(struct UTUN_INSTANCE* instance, const char* phase); void utun_instance_diagnose_leaks(struct UTUN_INSTANCE* instance, const char* phase);

2
tests/test_nat_detection.c

@ -376,7 +376,7 @@ int main(void) {
// Verify NAT addr in flat address list // Verify NAT addr in flat address list
int nat_found = 0; int nat_found = 0;
for (const struct TOPO_ADDR4* a = topo_groups_get_default(inst_c1->topo_groups)->local_node->node->v4_addrs; a; a = a->next) { for (const struct TOPO_ADDR4* a = topo_groups_get_default(inst_c1->topo_groups)->local_node->node->v4_addrs; a; a = a->next) {
if (a->type == TOPO_ADDR_NAT && a->socket_id == sock_c1->sock_id) { if (a->type == TOPO_ADDR_NAT && a->socket_id == (sock_c1->sock_id | 1)) {
uint32_t addr_ip; memcpy(&addr_ip, a->addr, 4); uint32_t addr_ip; memcpy(&addr_ip, a->addr, 4);
if (addr_ip != link_sc1->nat_ip || a->port != link_sc1->nat_port) { 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", DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: NAT addr mismatch in local_node: addr=%08x nat_ip=%08x port=%u nat_port=%u",

1
tools/chatgui/transport/utun_node.cpp

@ -239,6 +239,7 @@ void UtunNode::runLoop() {
} }
utun_instance_set_tun_init_enabled(0); utun_instance_set_tun_init_enabled(0);
utun_instance_set_topo_group_enabled(0);
struct UASYNC* ua = uasync_create(); struct UASYNC* ua = uasync_create();
if (!ua) { if (!ua) {

Loading…
Cancel
Save