Browse Source

route_node: refactor NODEINFO — separate protocol/memory structs, linked lists with memory_pool

- NODEINFO_MSG (protocol, packed): added flags byte + group_id field
- NODEINFO (memory): ref_count, linked list heads instead of inline arrays
- NODEINFO_ROUTES: separate struct with linked list subnet heads
- NODEINFO_Q: node*, routes*, tranzit_data*, hop_list* as separate mallocs
- 6 memory_pools in ROUTE_BGP for NI_* linked list items
- ni_list_count() universal counter via _ni_head cast
- nodeinfo_serialize/deserialize for protocol <-> memory conversion
- NODEINFO_FLAG_SEND_SUBNETS controls subnet data in protocol
- group_id defaults: utun=NODEINFO_GROUP_UTUN(1) with subnets

Fixes:
- deserialization: data+2 instead of data+sizeof(BGP_NODEINFO_PACKET)
- memset: start after ll_entry to preserve ll.size
- hop_src: subtract hop_count*8 to point at correct dynamic offset
- same-ver branch: remove_path(conn) instead of remove_path_by_hop(peer)
- double-free in route_bgp_remove_conn/process_withdraw
- conn_mgr_add_alien_node: rewritten for new structures
- all test files updated for new API
chatgui
Evgeny 3 months ago
parent
commit
c7ac42eb5f
  1. 2436
      compile_commands.json
  2. 9
      src/_route_tz.txt
  3. 171
      src/conn_mgr.c
  4. 19
      src/control_server.c
  5. 64
      src/etcp_connect.c
  6. 2
      src/etcp_connections.c
  7. 4
      src/etcp_router.c
  8. 4
      src/msg_transport.c
  9. 20
      src/route6_lib.c
  10. 1026
      src/route_bgp.c
  11. 19
      src/route_bgp.h
  12. 136
      src/route_connectivity.c
  13. 97
      src/route_lib.c
  14. 931
      src/route_node.c
  15. 226
      src/route_node.h
  16. 132
      src/route_node_lmdb.c
  17. 6
      src/routing.c
  18. 2
      tests/test_bgp_route_exchange.c
  19. 2
      tests/test_bgp_triangle.c
  20. 27
      tests/test_etcp_connect.c
  21. 24
      tests/test_etcp_router_reconnect.c
  22. 16
      tests/test_etcp_router_unit.c
  23. 131
      tests/test_ipv6_sockets.c
  24. 56
      tests/test_nat_detection.c
  25. 38
      tests/test_route6_lib.c
  26. 39
      tests/test_route_lib.c
  27. 13
      tests/test_route_ping.c

2436
compile_commands.json

File diff suppressed because it is too large Load Diff

9
src/_route_tz.txt

@ -0,0 +1,9 @@
Задача сделать механизм маршрутизации между узлами для групповых чатов.
Узлы для всех чатов находятся в одной таблице - это nodeinfo (информация о подключении)
В другой таблице есть список узлов конкретного чата.
надо сделать возможность хранить одновременно несколько групп узлов. в группу узлов добавить тип - utun или чатовая.
если utun - в группе используется роутинг (ipv4/ipv6).
если чатовая - то только связность между узлами.

171
src/conn_mgr.c

@ -273,18 +273,19 @@ int conn_mgr_add_alien_node(struct CONN_MGR* mgr, const uint8_t* nodeinfo_data,
if (!mgr || !nodeinfo_data || len < sizeof(struct NODEINFO)) return CONN_MGR_ERR_INTERNAL; if (!mgr || !nodeinfo_data || len < sizeof(struct NODEINFO)) return CONN_MGR_ERR_INTERNAL;
struct ROUTE_BGP* bgp = mgr->instance->bgp; struct ROUTE_BGP* bgp = mgr->instance->bgp;
if (!bgp) return CONN_MGR_ERR_INTERNAL; if (!bgp) return CONN_MGR_ERR_INTERNAL;
const struct NODEINFO* ni = (const struct NODEINFO*)nodeinfo_data; const struct NODEINFO* src = (const struct NODEINFO*)nodeinfo_data;
uint64_t node_id = ni->node_id; uint64_t node_id = src->node_id;
struct NODEINFO_Q* existing = nodeinfo_find_by_id(bgp, node_id); struct NODEINFO_Q* existing = nodeinfo_find_by_id(bgp, node_id);
if (existing) { DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: alien node 0x%016llx already exists, ignoring", (unsigned long long)node_id); return CONN_MGR_OK; } if (existing) { DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: alien node 0x%016llx already exists, ignoring", (unsigned long long)node_id); return CONN_MGR_OK; }
size_t dyn_sz = len - sizeof(struct NODEINFO); struct NODEINFO* ni = u_calloc(1, sizeof(struct NODEINFO));
size_t data_sz = sizeof(struct NODEINFO_Q) - sizeof(struct ll_entry) + dyn_sz + 8; if (!ni) return CONN_MGR_ERR_INTERNAL;
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)queue_entry_new(data_sz); memcpy(ni, nodeinfo_data, len < sizeof(*ni) ? len : sizeof(*ni));
if (!nq) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "conn_mgr: alien node alloc failed"); return CONN_MGR_ERR_INTERNAL; } ni->ref_count = 1;
memcpy(&nq->node, nodeinfo_data, len); struct NODEINFO_Q* nq = (struct NODEINFO_Q*)queue_entry_new(sizeof(struct NODEINFO_Q));
nq->alien = 1; if (!nq) { u_free(ni); return CONN_MGR_ERR_INTERNAL; }
nq->dirty = 0; nq->node = ni; nodeinfo_ref(ni);
nq->last_ver = ni->ver; nq->hash_node_id = ni->node_id;
nq->alien = 1; nq->dirty = 0; nq->last_ver = ni->ver;
nq->connectivity.ping_req_time = 0; nq->connectivity.ping_req_time = 0;
if (bgp->nodes) queue_data_put_with_index(bgp->nodes, &nq->ll); if (bgp->nodes) queue_data_put_with_index(bgp->nodes, &nq->ll);
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: added alien node 0x%016llx", (unsigned long long)node_id); DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: added alien node 0x%016llx", (unsigned long long)node_id);
@ -386,17 +387,12 @@ static int cm_is_rtt_fresh(struct NODEINFO_Q* nq, uint64_t now_tb) {
} }
static int cm_has_direct_ip(struct NODEINFO_Q* nq) { static int cm_has_direct_ip(struct NODEINFO_Q* nq) {
if (!nq) return 0; if (!nq || !nq->node) return 0;
const struct NODEINFO_IPV4_ADDR* addrs = NULL; for (const struct NI_IPV4_ADDR* a = nq->node->v4_addrs; a; a = a->next) {
const struct NODEINFO_IPV4_SOCKET_META* metas = NULL; if (a->type == ADDR_TYPE_REAL || a->type == ADDR_TYPE_NAT) {
int addr_count = get_node_v4_addrs(nq, &addrs); for (const struct NI_IPV4_SOCKET_META* m = nq->node->v4_sock_meta; m; m = m->next) {
int meta_count = get_node_v4_sockets_meta(nq, &metas); if (m->id == a->socket_id && (m->config_type == CFG_SERVER_TYPE_PUBLIC || m->config_type == CFG_SERVER_TYPE_UNKNOWN
for (int i = 0; i < addr_count; i++) { || m->nat_type == NAT_VERIFIED_EIM || m->nat_type == NAT_VERIFIED_DIRECT))
if (addrs[i].type == ADDR_TYPE_REAL || addrs[i].type == ADDR_TYPE_NAT) {
for (int j = 0; j < meta_count; j++) {
if (metas[j].id == addrs[i].socket_id &&
(metas[j].config_type == CFG_SERVER_TYPE_PUBLIC || metas[j].config_type == CFG_SERVER_TYPE_UNKNOWN
|| metas[j].nat_type == NAT_VERIFIED_EIM || metas[j].nat_type == NAT_VERIFIED_DIRECT))
return 1; return 1;
} }
} }
@ -405,16 +401,11 @@ static int cm_has_direct_ip(struct NODEINFO_Q* nq) {
} }
static int cm_has_local_addr(struct NODEINFO_Q* nq) { static int cm_has_local_addr(struct NODEINFO_Q* nq) {
if (!nq) return 0; if (!nq || !nq->node) return 0;
const struct NODEINFO_IPV4_ADDR* addrs = NULL; for (const struct NI_IPV4_ADDR* a = nq->node->v4_addrs; a; a = a->next) {
const struct NODEINFO_IPV4_SOCKET_META* metas = NULL; if (a->type == ADDR_TYPE_INTERFACE) {
int addr_count = get_node_v4_addrs(nq, &addrs); for (const struct NI_IPV4_SOCKET_META* m = nq->node->v4_sock_meta; m; m = m->next) {
int meta_count = get_node_v4_sockets_meta(nq, &metas); if (m->id == a->socket_id && (m->config_type == CFG_SERVER_TYPE_PRIVATE || m->config_type == CFG_SERVER_TYPE_LOCAL))
for (int i = 0; i < addr_count; i++) {
if (addrs[i].type == ADDR_TYPE_INTERFACE) {
for (int j = 0; j < meta_count; j++) {
if (metas[j].id == addrs[i].socket_id &&
(metas[j].config_type == CFG_SERVER_TYPE_PRIVATE || metas[j].config_type == CFG_SERVER_TYPE_LOCAL))
return 1; return 1;
} }
} }
@ -437,36 +428,20 @@ struct cm_ping_ctx {
static void cm_start_local_scan(struct CONN_MGR_ENTRY* entry) { static void cm_start_local_scan(struct CONN_MGR_ENTRY* entry) {
struct ROUTE_BGP* bgp = entry->mgr->instance->bgp; struct ROUTE_BGP* bgp = entry->mgr->instance->bgp;
struct NODEINFO_Q* target = nodeinfo_find_by_id(bgp, entry->node_id); struct NODEINFO_Q* target = nodeinfo_find_by_id(bgp, entry->node_id);
if (!target) { entry->local_scan_state = CM_TRY_FAILED; return; } if (!target || !target->node) { entry->local_scan_state = CM_TRY_FAILED; return; }
const struct NODEINFO_IPV4_ADDR* addrs = NULL; for (const struct NI_IPV4_ADDR* a = target->node->v4_addrs; a; a = a->next) {
const struct NODEINFO_IPV4_SOCKET_META* metas = NULL; if (a->type != ADDR_TYPE_INTERFACE) continue;
int addr_count = get_node_v4_addrs(target, &addrs); for (const struct NI_IPV4_SOCKET_META* m = target->node->v4_sock_meta; m; m = m->next) {
int meta_count = get_node_v4_sockets_meta(target, &metas); if (m->id != a->socket_id || (m->config_type != CFG_SERVER_TYPE_PRIVATE && m->config_type != CFG_SERVER_TYPE_LOCAL)) continue;
for (int i = 0; i < addr_count; i++) {
if (addrs[i].type != ADDR_TYPE_INTERFACE) continue;
for (int j = 0; j < meta_count; j++) {
if (metas[j].id != addrs[i].socket_id ||
(metas[j].config_type != CFG_SERVER_TYPE_PRIVATE && metas[j].config_type != CFG_SERVER_TYPE_LOCAL)) continue;
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets; struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
while (s) { while (s) {
if ((s->type == CFG_SERVER_TYPE_PRIVATE || s->type == CFG_SERVER_TYPE_LOCAL) && s->local_addr.ss_family == AF_INET) { if ((s->type == CFG_SERVER_TYPE_PRIVATE || s->type == CFG_SERVER_TYPE_LOCAL) && s->local_addr.ss_family == AF_INET) {
struct sockaddr_in sin; struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET;
memset(&sin, 0, sizeof(sin)); memcpy(&sin.sin_addr.s_addr, a->addr, 4); sin.sin_port = htons(a->port);
sin.sin_family = AF_INET; struct sockaddr_storage sa; memset(&sa, 0, sizeof(sa)); memcpy(&sa, &sin, sizeof(sin));
memcpy(&sin.sin_addr.s_addr, addrs[i].addr, 4); struct cm_ping_ctx* ctx = u_calloc(1, sizeof(struct cm_ping_ctx)); if (!ctx) continue;
sin.sin_port = htons(addrs[i].port); ctx->entry = entry; ctx->addr = sa; ctx->sock = s; ctx->phase = 0; ctx->attempt = 0;
struct sockaddr_storage sa; etcp_send_ping_to_socket(entry->mgr->instance, s, target->node->public_key, &sa, CONN_MGR_LOCAL_SCAN_TIMEOUT_MS, cm_ping_cb, ctx, NULL, 0);
memset(&sa, 0, sizeof(sa));
memcpy(&sa, &sin, sizeof(sin));
struct cm_ping_ctx* ctx = u_calloc(1, sizeof(struct cm_ping_ctx));
if (!ctx) continue;
ctx->entry = entry;
ctx->addr = sa;
ctx->sock = s;
ctx->phase = 0;
ctx->attempt = 0;
etcp_send_ping_to_socket(entry->mgr->instance, s, target->node.public_key, &sa,
CONN_MGR_LOCAL_SCAN_TIMEOUT_MS, cm_ping_cb, ctx, NULL, 0);
return; return;
} }
s = s->next; s = s->next;
@ -474,7 +449,6 @@ static void cm_start_local_scan(struct CONN_MGR_ENTRY* entry) {
} }
} }
entry->local_scan_state = CM_TRY_FAILED; entry->local_scan_state = CM_TRY_FAILED;
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: local scan no candidates for 0x%016llx", (unsigned long long)entry->node_id);
} }
static void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry) { static void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry) {
@ -482,39 +456,25 @@ static void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry) {
if (entry->local_scan_state == CM_TRY_OK) return; if (entry->local_scan_state == CM_TRY_OK) return;
struct ROUTE_BGP* bgp = entry->mgr->instance->bgp; struct ROUTE_BGP* bgp = entry->mgr->instance->bgp;
struct NODEINFO_Q* target = nodeinfo_find_by_id(bgp, entry->node_id); struct NODEINFO_Q* target = nodeinfo_find_by_id(bgp, entry->node_id);
if (!target) { cm_deliver_result(entry, CONN_MGR_ERR_NOT_FOUND); return; } if (!target || !target->node) { cm_deliver_result(entry, CONN_MGR_ERR_NOT_FOUND); return; }
const struct NODEINFO_IPV4_ADDR* addrs = NULL;
const struct NODEINFO_IPV4_SOCKET_META* metas = NULL;
int addr_count = get_node_v4_addrs(target, &addrs);
int meta_count = get_node_v4_sockets_meta(target, &metas);
uint8_t priority_order[] = { ADDR_TYPE_REAL, ADDR_TYPE_NAT, ADDR_TYPE_INTERFACE }; uint8_t priority_order[] = { ADDR_TYPE_REAL, ADDR_TYPE_NAT, ADDR_TYPE_INTERFACE };
for (int pri = 0; pri < 3; pri++) { for (int pri = 0; pri < 3; pri++) {
for (int i = 0; i < addr_count; i++) { for (const struct NI_IPV4_ADDR* a = target->node->v4_addrs; a; a = a->next) {
if (addrs[i].type != priority_order[pri]) continue; if (a->type != priority_order[pri]) continue;
for (int j = 0; j < meta_count; j++) { for (const struct NI_IPV4_SOCKET_META* m = target->node->v4_sock_meta; m; m = m->next) {
if (metas[j].id != addrs[i].socket_id) continue; if (m->id != a->socket_id) continue;
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets; struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
while (s) { while (s) {
int compat = cm_nat_compatible(s, metas[j].config_type, metas[j].nat_type); if (cm_nat_compatible(s, m->config_type, m->nat_type) && s->local_addr.ss_family == AF_INET) {
if (compat && s->local_addr.ss_family == AF_INET) { struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET;
struct sockaddr_in sin; memcpy(&sin.sin_addr.s_addr, a->addr, 4); sin.sin_port = htons(a->port);
memset(&sin, 0, sizeof(sin)); struct sockaddr_storage sa; memset(&sa, 0, sizeof(sa)); memcpy(&sa, &sin, sizeof(sin));
sin.sin_family = AF_INET;
memcpy(&sin.sin_addr.s_addr, addrs[i].addr, 4);
sin.sin_port = htons(addrs[i].port);
struct sockaddr_storage sa;
memset(&sa, 0, sizeof(sa));
memcpy(&sa, &sin, sizeof(sin));
struct ETCP_CONN* conn = etcp_connection_create(entry->mgr->instance, NULL); struct ETCP_CONN* conn = etcp_connection_create(entry->mgr->instance, NULL);
if (conn) { if (conn) {
etcp_conn_set_ready_cbk(conn, cm_direct_ready_cb, entry); etcp_conn_set_ready_cbk(conn, cm_direct_ready_cb, entry);
sc_set_peer_public_key(&conn->crypto_ctx, target->node.public_key, 0); sc_set_peer_public_key(&conn->crypto_ctx, target->node->public_key, 0);
struct ETCP_LINK* link = etcp_link_new(conn, s, &sa, 0); if (etcp_link_new(conn, s, &sa, 0)) {
if (link) { entry->main.timer = uasync_set_timeout(entry->mgr->instance->ua, CONN_MGR_CONNECT_DIRECT_TIMEOUT_MS * 10, entry, cm_direct_timeout_cb, "conn_mgr_direct");
entry->main.timer = uasync_set_timeout(entry->mgr->instance->ua,
CONN_MGR_CONNECT_DIRECT_TIMEOUT_MS * 10, entry, cm_direct_timeout_cb, "conn_mgr_direct");
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: phase 1 (direct) started INIT to 0x%016llx",
(unsigned long long)entry->node_id);
return; return;
} }
} }
@ -524,8 +484,6 @@ static void cm_start_phase_direct(struct CONN_MGR_ENTRY* entry) {
} }
} }
} }
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: phase 1 (direct) no compatible pairs for 0x%016llx",
(unsigned long long)entry->node_id);
int has_our = cm_has_direct_ip(bgp->local_node); int has_our = cm_has_direct_ip(bgp->local_node);
int has_target = cm_has_direct_ip(target); int has_target = cm_has_direct_ip(target);
if (has_our && !has_target) { cm_start_phase_reverse(entry); return; } if (has_our && !has_target) { cm_start_phase_reverse(entry); return; }
@ -584,7 +542,7 @@ static void cm_ping_cb(int success, uint16_t rtt, void* arg, uint64_t nonce,
ctx->attempt++; ctx->attempt++;
if (ctx->attempt < CONN_MGR_LOCAL_SCAN_ATTEMPTS && ctx->phase == 0) { if (ctx->attempt < CONN_MGR_LOCAL_SCAN_ATTEMPTS && ctx->phase == 0) {
etcp_send_ping_to_socket(entry->mgr->instance, ctx->sock, etcp_send_ping_to_socket(entry->mgr->instance, ctx->sock,
nodeinfo_find_by_id(entry->mgr->instance->bgp, entry->node_id)->node.public_key, nodeinfo_find_by_id(entry->mgr->instance->bgp, entry->node_id)->node->public_key,
&ctx->addr, CONN_MGR_LOCAL_SCAN_TIMEOUT_MS, cm_ping_cb, ctx, NULL, 0); &ctx->addr, CONN_MGR_LOCAL_SCAN_TIMEOUT_MS, cm_ping_cb, ctx, NULL, 0);
return; return;
} }
@ -597,28 +555,19 @@ static void cm_ping_cb(int success, uint16_t rtt, void* arg, uint64_t nonce,
static void cm_start_phase_reverse(struct CONN_MGR_ENTRY* entry) { static void cm_start_phase_reverse(struct CONN_MGR_ENTRY* entry) {
struct ROUTE_BGP* bgp = entry->mgr->instance->bgp; struct ROUTE_BGP* bgp = entry->mgr->instance->bgp;
struct NODEINFO_Q* local = bgp->local_node; struct NODEINFO_Q* local = bgp->local_node;
if (!local) { cm_deliver_result(entry, CONN_MGR_ERR_INTERNAL); return; } if (!local || !local->node) { cm_deliver_result(entry, CONN_MGR_ERR_INTERNAL); return; }
uint32_t req_id = ++entry->mgr->next_request_id; uint32_t req_id = ++entry->mgr->next_request_id;
entry->main.request_id = req_id; entry->main.request_id = req_id; entry->main.phase = 2;
entry->main.phase = 2;
const struct NODEINFO_IPV4_ADDR* addrs = NULL;
const struct NODEINFO_IPV4_SOCKET_META* metas = NULL;
int addr_count = get_node_v4_addrs(local, &addrs);
int meta_count = get_node_v4_sockets_meta(local, &metas);
uint8_t direct_count = 0; uint8_t direct_count = 0;
struct { uint8_t type; uint8_t ip[4]; uint16_t port; uint8_t socket_id; } out_addrs[8]; struct { uint8_t type; uint8_t ip[4]; uint16_t port; uint8_t socket_id; } out_addrs[8];
for (int i = 0; i < addr_count && direct_count < 8; i++) { for (const struct NI_IPV4_ADDR* a = local->node->v4_addrs; a && direct_count < 8; a = a->next) {
if (addrs[i].type != ADDR_TYPE_REAL && addrs[i].type != ADDR_TYPE_NAT) continue; if (a->type != ADDR_TYPE_REAL && a->type != ADDR_TYPE_NAT) continue;
for (int j = 0; j < meta_count; j++) { for (const struct NI_IPV4_SOCKET_META* m = local->node->v4_sock_meta; m; m = m->next) {
if (metas[j].id == addrs[i].socket_id && if (m->id == a->socket_id && (m->config_type == CFG_SERVER_TYPE_PUBLIC || m->config_type == CFG_SERVER_TYPE_UNKNOWN
(metas[j].config_type == CFG_SERVER_TYPE_PUBLIC || metas[j].config_type == CFG_SERVER_TYPE_UNKNOWN || m->nat_type == NAT_VERIFIED_EIM || m->nat_type == NAT_VERIFIED_DIRECT)) {
|| metas[j].nat_type == NAT_VERIFIED_EIM || metas[j].nat_type == NAT_VERIFIED_DIRECT)) { out_addrs[direct_count].type = a->type; memcpy(out_addrs[direct_count].ip, a->addr, 4);
out_addrs[direct_count].type = addrs[i].type; out_addrs[direct_count].port = htons(a->port); out_addrs[direct_count].socket_id = a->socket_id;
memcpy(out_addrs[direct_count].ip, addrs[i].addr, 4); direct_count++; break;
out_addrs[direct_count].port = htons(addrs[i].port);
out_addrs[direct_count].socket_id = addrs[i].socket_id;
direct_count++;
break;
} }
} }
} }
@ -904,7 +853,7 @@ static void cm_handle_direct_req(struct ETCP_CONN* conn, const uint8_t* data, si
struct ETCP_CONN* new_conn = etcp_connection_create(conn->instance, NULL); struct ETCP_CONN* new_conn = etcp_connection_create(conn->instance, NULL);
if (new_conn) { if (new_conn) {
struct NODEINFO_Q* nq = nodeinfo_find_by_id(conn->instance->bgp, src_node_id); struct NODEINFO_Q* nq = nodeinfo_find_by_id(conn->instance->bgp, src_node_id);
if (nq) sc_set_peer_public_key(&new_conn->crypto_ctx, nq->node.public_key, 0); if (nq) sc_set_peer_public_key(&new_conn->crypto_ctx, nq->node->public_key, 0);
struct cm_reverse_pending* rp = u_calloc(1, sizeof(struct cm_reverse_pending)); struct cm_reverse_pending* rp = u_calloc(1, sizeof(struct cm_reverse_pending));
if (rp) { rp->request_id = req->request_id; rp->entry = NULL; rp->next = mgr->reverse_pending; if (rp) { rp->request_id = req->request_id; rp->entry = NULL; rp->next = mgr->reverse_pending;
etcp_conn_set_ready_cbk(new_conn, cm_reverse_ready_cb, rp); mgr->reverse_pending = rp; } etcp_conn_set_ready_cbk(new_conn, cm_reverse_ready_cb, rp); mgr->reverse_pending = rp; }
@ -991,7 +940,7 @@ static void cm_bg_ping_timer_cb(void* arg) {
while (e && cursor < mgr->bg_ping_cursor) { cursor++; e = e->next; } while (e && cursor < mgr->bg_ping_cursor) { cursor++; e = e->next; }
if (e) { if (e) {
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)e; struct NODEINFO_Q* nq = (struct NODEINFO_Q*)e;
uint64_t node_id = nq->node.node_id; uint64_t node_id = nq->node->node_id;
if (node_id != mgr->instance->node_id) { if (node_id != mgr->instance->node_id) {
struct ETCP_CONN* dconn = route_bgp_find_conn_for_node(bgp, node_id); struct ETCP_CONN* dconn = route_bgp_find_conn_for_node(bgp, node_id);
int has_active = 0; int has_active = 0;
@ -1000,7 +949,7 @@ static void cm_bg_ping_timer_cb(void* arg) {
while (l) { if (l->initialized && l->link_status) { has_active = 1; break; } l = l->next; } while (l) { if (l->initialized && l->link_status) { has_active = 1; break; } l = l->next; }
} }
if (!has_active) { if (!has_active) {
etcp_send_ping(mgr->instance, nq->node.public_key, NULL, CONN_PROBE_TIMEOUT_MS, etcp_send_ping(mgr->instance, nq->node->public_key, NULL, CONN_PROBE_TIMEOUT_MS,
NULL, NULL, NULL, 0); NULL, NULL, NULL, 0);
} }
} }
@ -1032,7 +981,7 @@ static void cm_candidate_ping_timer_cb(void* arg) {
while (l) { if (l->initialized && l->link_status) { has_active = 1; break; } l = l->next; } while (l) { if (l->initialized && l->link_status) { has_active = 1; break; } l = l->next; }
} }
if (has_active) if (has_active)
etcp_send_ping(mgr->instance, nq->node.public_key, &dconn->links->remote_addr, CONN_PROBE_TIMEOUT_MS, NULL, NULL, NULL, 0); etcp_send_ping(mgr->instance, nq->node->public_key, &dconn->links->remote_addr, CONN_PROBE_TIMEOUT_MS, NULL, NULL, NULL, 0);
else else
route_connectivity_probe_node(mgr->instance, nq); route_connectivity_probe_node(mgr->instance, nq);
} }

19
src/control_server.c

@ -1386,19 +1386,20 @@ static struct ETCP_CONN* find_connection_by_peer_id(struct UTUN_INSTANCE* instan
* ============================================================================ */ * ============================================================================ */
static void send_single_node_info(struct control_server* server, struct control_client* client, struct NODEINFO_Q* nq) { static void send_single_node_info(struct control_server* server, struct control_client* client, struct NODEINFO_Q* nq) {
int dyn = nodeinfo_dyn_size(&nq->node); if (!server || !nq || !nq->node) return;
size_t np_size = sizeof(struct etcpmon_msg_header) + 2 + sizeof(struct NODEINFO) + dyn; uint8_t buf[8192];
int ser_len = nodeinfo_serialize(server->instance->bgp, nq, buf + 2, sizeof(buf) - 2);
if (ser_len < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONTROL, "Failed to serialize node info"); return; }
buf[0] = CTRL_BGP_CMD; buf[1] = CTRL_BGP_SUBCMD;
size_t data_size = 2 + (size_t)ser_len;
size_t np_size = sizeof(struct etcpmon_msg_header) + data_size;
uint8_t* buffer = (uint8_t*)u_malloc(np_size); uint8_t* buffer = (uint8_t*)u_malloc(np_size);
if (!buffer) { DEBUG_ERROR(DEBUG_CATEGORY_CONTROL, "Failed to allocate node info buffer"); return; } if (!buffer) { DEBUG_ERROR(DEBUG_CATEGORY_CONTROL, "Failed to allocate node info buffer"); return; }
struct etcpmon_msg_header* hdr = (struct etcpmon_msg_header*)buffer; struct etcpmon_msg_header* hdr = (struct etcpmon_msg_header*)buffer;
etcpmon_build_header(hdr, 2 + sizeof(struct NODEINFO) + dyn, ETCPMON_RSP_NODE_INFO, 0); etcpmon_build_header(hdr, (uint16_t)data_size, ETCPMON_RSP_NODE_INFO, 0);
memcpy(buffer + sizeof(*hdr), buf, data_size);
uint8_t* pay = buffer + sizeof(*hdr);
pay[0] = CTRL_BGP_CMD; pay[1] = CTRL_BGP_SUBCMD;
memcpy(pay + 2, &nq->node, sizeof(struct NODEINFO));
memcpy(pay + 2 + sizeof(struct NODEINFO), (uint8_t*)&nq->node + sizeof(struct NODEINFO), dyn);
control_client_send(server, client, buffer, (uint16_t)np_size); control_client_send(server, client, buffer, (uint16_t)np_size);
} }

64
src/etcp_connect.c

@ -70,61 +70,43 @@ static void connect_cancel(struct ETCP_CONNECT* ctx) {
} }
static void connect_create_links_v4(struct ETCP_CONNECT* ctx, struct NODEINFO_Q* node) { static void connect_create_links_v4(struct ETCP_CONNECT* ctx, struct NODEINFO_Q* node) {
const struct NODEINFO_IPV4_ADDR* addrs; int ac = get_node_v4_addrs(node, &addrs); if (!node || !node->node) return;
for (int i = 0; i < ac; i++) { for (const struct NI_IPV4_ADDR* a = node->node->v4_addrs; a; a = a->next) {
if (addrs[i].port == 0) continue; if (a->port == 0) continue;
{ int zero = 1; for (int j = 0; j < 4; j++) if (addrs[i].addr[j] != 0) { zero = 0; break; } if (zero) continue; } { int zero = 1; for (int j = 0; j < 4; j++) if (a->addr[j] != 0) { zero = 0; break; } if (zero) continue; }
struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET;
sin.sin_family = AF_INET; memcpy(&sin.sin_addr.s_addr, a->addr, 4); sin.sin_port = htons(a->port);
memcpy(&sin.sin_addr.s_addr, addrs[i].addr, 4);
sin.sin_port = htons(addrs[i].port);
struct sockaddr_storage sa; memcpy(&sa, &sin, sizeof(sin)); struct sockaddr_storage sa; memcpy(&sa, &sin, sizeof(sin));
if (!(addrs[i].protocol & NODE_PROTO_TCP)) { if (!(a->protocol & NODE_PROTO_TCP)) {
struct ETCP_SOCKET* s = ctx->instance->etcp_sockets; struct ETCP_SOCKET* s = ctx->instance->etcp_sockets;
while (s) { while (s) { if (s->local_addr.ss_family == AF_INET) etcp_link_new(ctx->conn, s, &sa, 0); s = s->next; }
if (s->local_addr.ss_family == AF_INET)
etcp_link_new(ctx->conn, s, &sa, 0);
s = s->next;
}
} }
if ((addrs[i].protocol & NODE_PROTO_TCP) && !ctx->tcp_link) { if ((a->protocol & NODE_PROTO_TCP) && !ctx->tcp_link) {
struct stcp_link_config tcp_cfg = {.ua = ctx->instance->ua, .my_keys = &ctx->instance->my_keys, .inst = ctx->instance, struct stcp_link_config tcp_cfg = {.ua = ctx->instance->ua, .my_keys = &ctx->instance->my_keys, .inst = ctx->instance,
.peer_pubkey = ctx->conn->crypto_ctx.peer_public_key, .peer_pubkey_mode = 0, .peer_pubkey = ctx->conn->crypto_ctx.peer_public_key, .peer_pubkey_mode = 0,
.remote_addr = &sa, .remote_port = addrs[i].port}; .remote_addr = &sa, .remote_port = a->port};
ctx->tcp_link = stcp_link_connect(&tcp_cfg); ctx->tcp_link = stcp_link_connect(&tcp_cfg);
if (ctx->tcp_link) { if (ctx->tcp_link) { ctx->conn->transport_link = (void*)ctx->tcp_link; stcp_link_set_on_ready(ctx->tcp_link, tcp_link_ready_cb, ctx); stcp_link_set_on_close(ctx->tcp_link, tcp_link_close_cb, ctx); }
ctx->conn->transport_link = (void*)ctx->tcp_link;
stcp_link_set_on_ready(ctx->tcp_link, tcp_link_ready_cb, ctx);
stcp_link_set_on_close(ctx->tcp_link, tcp_link_close_cb, ctx);
}
} }
} }
} }
static void connect_create_links_v6(struct ETCP_CONNECT* ctx, struct NODEINFO_Q* node) { static void connect_create_links_v6(struct ETCP_CONNECT* ctx, struct NODEINFO_Q* node) {
const struct NODEINFO_IPV6_ADDR* addrs; int ac = get_node_v6_addrs(node, &addrs); if (!node || !node->node) return;
for (int i = 0; i < ac; i++) { for (const struct NI_IPV6_ADDR* a = node->node->v6_addrs; a; a = a->next) {
if (addrs[i].port == 0) continue; if (a->port == 0) continue;
int zero = 1; int zero = 1; for (int j = 0; j < 16; j++) if (a->addr[j] != 0) { zero = 0; break; } if (zero) continue;
for (int j = 0; j < 16; j++) if (addrs[i].addr[j] != 0) { zero = 0; break; } struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6;
if (zero) continue; memcpy(&sin6.sin6_addr, a->addr, 16); sin6.sin6_port = htons(a->port);
struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
memcpy(&sin6.sin6_addr, addrs[i].addr, 16);
sin6.sin6_port = htons(addrs[i].port);
struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6)); struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6));
if (!(addrs[i].protocol & NODE_PROTO_TCP)) { if (!(a->protocol & NODE_PROTO_TCP)) {
struct ETCP_SOCKET* s = ctx->instance->etcp_sockets; struct ETCP_SOCKET* s = ctx->instance->etcp_sockets;
while (s) { while (s) { if (s->local_addr.ss_family == AF_INET6) etcp_link_new(ctx->conn, s, &sa, 0); s = s->next; }
if (s->local_addr.ss_family == AF_INET6)
etcp_link_new(ctx->conn, s, &sa, 0);
s = s->next;
}
} }
if ((addrs[i].protocol & NODE_PROTO_TCP) && !ctx->tcp_link) { if ((a->protocol & NODE_PROTO_TCP) && !ctx->tcp_link) {
struct stcp_link_config tcp_cfg = {.ua = ctx->instance->ua, .my_keys = &ctx->instance->my_keys, .inst = ctx->instance, struct stcp_link_config tcp_cfg = {.ua = ctx->instance->ua, .my_keys = &ctx->instance->my_keys, .inst = ctx->instance,
.peer_pubkey = ctx->conn->crypto_ctx.peer_public_key, .peer_pubkey_mode = 0, .peer_pubkey = ctx->conn->crypto_ctx.peer_public_key, .peer_pubkey_mode = 0,
.remote_addr = &sa, .remote_port = addrs[i].port}; .remote_addr = &sa, .remote_port = a->port};
ctx->tcp_link = stcp_link_connect(&tcp_cfg); ctx->tcp_link = stcp_link_connect(&tcp_cfg);
if (ctx->tcp_link) { if (ctx->tcp_link) {
ctx->conn->transport_link = (void*)ctx->tcp_link; ctx->conn->transport_link = (void*)ctx->tcp_link;
@ -226,7 +208,7 @@ static void connect_ready_cb(struct ETCP_CONN* conn, void* arg) {
int etcp_connect(struct UTUN_INSTANCE* inst, struct NODEINFO_Q* node, int etcp_connect(struct UTUN_INSTANCE* inst, struct NODEINFO_Q* node,
etcp_connect_callback_t cb, void* arg, uint8_t flags) { etcp_connect_callback_t cb, void* arg, uint8_t flags) {
if (!inst || !node || !cb) return -1; if (!inst || !node || !cb) return -1;
uint64_t node_id = node->node.node_id; uint64_t node_id = node->node->node_id;
struct ETCP_CONN* existing = inst->connections; struct ETCP_CONN* existing = inst->connections;
while (existing) { while (existing) {
@ -264,7 +246,7 @@ int etcp_connect(struct UTUN_INSTANCE* inst, struct NODEINFO_Q* node,
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] sc_init_ctx failed for node 0x%016llx", (unsigned long long)node_id); DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] sc_init_ctx failed for node 0x%016llx", (unsigned long long)node_id);
etcp_connection_close(conn); cb(arg, NULL, 0); return -1; etcp_connection_close(conn); cb(arg, NULL, 0); return -1;
} }
if (sc_set_peer_public_key(&conn->crypto_ctx, node->node.public_key, 0) != SC_OK) { if (sc_set_peer_public_key(&conn->crypto_ctx, node->node->public_key, 0) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] sc_set_peer_public_key failed for node 0x%016llx", (unsigned long long)node_id); DEBUG_ERROR(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] sc_set_peer_public_key failed for node 0x%016llx", (unsigned long long)node_id);
etcp_connection_close(conn); cb(arg, NULL, 0); return -1; etcp_connection_close(conn); cb(arg, NULL, 0); return -1;
} }

2
src/etcp_connections.c

@ -1314,7 +1314,7 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
route_bgp_update_my_nodeinfo(link->etcp->instance->bgp->instance, link->etcp->instance->bgp); route_bgp_update_my_nodeinfo(link->etcp->instance->bgp->instance, link->etcp->instance->bgp);
struct ROUTE_BGP* bgp = link->etcp->instance->bgp; struct ROUTE_BGP* bgp = link->etcp->instance->bgp;
if (bgp->local_node && bgp->senders_list) { if (bgp->local_node && bgp->senders_list) {
bgp->local_node->node.ver = (bgp->local_node->node.ver % 255) + 1; bgp->local_node->node->ver = (bgp->local_node->node->ver % 255) + 1;
bgp->local_node->dirty = 1; bgp->local_node->dirty = 1;
struct ll_entry* se = bgp->senders_list->head; struct ll_entry* se = bgp->senders_list->head;
while (se) { while (se) {

4
src/etcp_router.c

@ -797,14 +797,14 @@ static int router_verify_signature(struct UTUN_INSTANCE* inst, struct ll_entry*
} }
{ {
uint8_t zero[SC_PUBKEY_SIZE] = {0}; uint8_t zero[SC_PUBKEY_SIZE] = {0};
if (memcmp(nq->node.ed25519_public_key, zero, SC_PUBKEY_SIZE) == 0) { if (memcmp(nq->node->ed25519_public_key, zero, SC_PUBKEY_SIZE) == 0) {
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: no Ed25519 pubkey for node %016llx — dropping", DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: no Ed25519 pubkey for node %016llx — dropping",
(unsigned long long)hdr->src_node_id); (unsigned long long)hdr->src_node_id);
free_entry(entry); return -1; free_entry(entry); return -1;
} }
} }
struct sc_stream_sign_state vfy_state; struct sc_stream_sign_state vfy_state;
if (sc_stream_sign_verify_init(&vfy_state, nq->node.ed25519_public_key) != SC_OK) { if (sc_stream_sign_verify_init(&vfy_state, nq->node->ed25519_public_key) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router: sign_verify_init failed for node %016llx", DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router: sign_verify_init failed for node %016llx",
(unsigned long long)hdr->src_node_id); (unsigned long long)hdr->src_node_id);
free_entry(entry); return -1; free_entry(entry); return -1;

4
src/msg_transport.c

@ -470,8 +470,8 @@ static void handle_client_data(struct msg_transport* t, struct msg_client* clien
break; break;
} }
uint8_t buf[SC_PUBKEY_SIZE * 2]; uint8_t buf[SC_PUBKEY_SIZE * 2];
memcpy(buf, nq->node.public_key, SC_PUBKEY_SIZE); memcpy(buf, nq->node->public_key, SC_PUBKEY_SIZE);
memcpy(buf + SC_PUBKEY_SIZE, nq->node.ed25519_public_key, SC_PUBKEY_SIZE); memcpy(buf + SC_PUBKEY_SIZE, nq->node->ed25519_public_key, SC_PUBKEY_SIZE);
send_response(client, MSG_RSP_PEER_INFO, peer_id, buf, SC_PUBKEY_SIZE * 2); send_response(client, MSG_RSP_PEER_INFO, peer_id, buf, SC_PUBKEY_SIZE * 2);
DEBUG_INFO(DEBUG_CATEGORY_MSGTRANSPORT, "GET_PEER_INFO: peer=%016llx sent pubkey+edpub", DEBUG_INFO(DEBUG_CATEGORY_MSGTRANSPORT, "GET_PEER_INFO: peer=%016llx sent pubkey+edpub",
(unsigned long long)peer_id); (unsigned long long)peer_id);

20
src/route6_lib.c

@ -64,22 +64,16 @@ void route6_table_destroy(struct ROUTE6_TABLE *table) {
} }
bool route6_insert(struct ROUTE6_TABLE *table, struct NODEINFO_Q *node) { bool route6_insert(struct ROUTE6_TABLE *table, struct NODEINFO_Q *node) {
if (!table || !node) return false; if (!table || !node || !node->routes || !node->routes->v6_subnets) return false;
const struct NODEINFO_IPV6_SUBNET *subnets = NULL; for (const struct NI_IPV6_SUBNET* s = node->routes->v6_subnets; s; s = s->next) {
int cnt = get_node_v6_routes(node, &subnets);
if (cnt <= 0) {
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route6_insert: node has no v6 subnets");
return false;
}
for (int i = 0; i < cnt; i++) {
struct ll_entry *entry = queue_entry_new(ROUTE6_DATA_SIZE); struct ll_entry *entry = queue_entry_new(ROUTE6_DATA_SIZE);
if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route6_insert: queue_entry_new failed"); return false; } if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route6_insert: queue_entry_new failed"); return false; }
struct ROUTE6_DATA *rd = (struct ROUTE6_DATA *)entry->data; struct ROUTE6_DATA *rd = (struct ROUTE6_DATA *)entry->data;
make_key6(rd->key, subnets[i].addr); make_key6(rd->key, s->addr);
make_mask6(rd->mask, subnets[i].prefix_length); make_mask6(rd->mask, s->prefix_length);
rd->v_node_info = node; rd->v_node_info = node;
rd->node_id = node->node.node_id; rd->node_id = node->node->node_id;
rd->prefix_length = subnets[i].prefix_length; rd->prefix_length = s->prefix_length;
struct radix_node *rn = rn_addroute(rd->key, rd->mask, &table->rnh->rh, rd->rn_nodes); struct radix_node *rn = rn_addroute(rd->key, rd->mask, &table->rnh->rh, rd->rn_nodes);
if (!rn) { queue_entry_free(entry); continue; } if (!rn) { queue_entry_free(entry); continue; }
queue_data_put_with_index(table->queue, entry); queue_data_put_with_index(table->queue, entry);
@ -89,7 +83,7 @@ bool route6_insert(struct ROUTE6_TABLE *table, struct NODEINFO_Q *node) {
void route6_delete(struct ROUTE6_TABLE *table, struct NODEINFO_Q *node) { void route6_delete(struct ROUTE6_TABLE *table, struct NODEINFO_Q *node) {
if (!table || !node) return; if (!table || !node) return;
uint64_t node_id = node->node.node_id; uint64_t node_id = node->node->node_id;
struct ll_entry *entry = queue_find_data_by_index(table->queue, &node_id); struct ll_entry *entry = queue_find_data_by_index(table->queue, &node_id);
while (entry) { while (entry) {
struct ROUTE6_DATA *rd = (struct ROUTE6_DATA *)entry->data; struct ROUTE6_DATA *rd = (struct ROUTE6_DATA *)entry->data;

1026
src/route_bgp.c

File diff suppressed because it is too large Load Diff

19
src/route_bgp.h

@ -9,6 +9,7 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "../lib/ll_queue.h" #include "../lib/ll_queue.h"
#include "../lib/memory_pool.h"
#include "../lib/liblmdb/lmdb.h" #include "../lib/liblmdb/lmdb.h"
#include "route_lib.h" #include "route_lib.h"
#include "route_node.h" #include "route_node.h"
@ -35,7 +36,7 @@ extern "C" {
struct BGP_NODEINFO_PACKET { struct BGP_NODEINFO_PACKET {
uint8_t cmd; // ETCP_ID_ROUTE_ENTRY uint8_t cmd; // ETCP_ID_ROUTE_ENTRY
uint8_t subcmd; // ROUTE_SUBCMD_NODEINFO uint8_t subcmd; // ROUTE_SUBCMD_NODEINFO
struct NODEINFO node; struct NODEINFO_MSG node;
} __attribute__((packed)); } __attribute__((packed));
/** /**
@ -94,10 +95,16 @@ struct ROUTE_BGP {
struct NODEINFO_Q* local_node; struct NODEINFO_Q* local_node;
struct route_ping_pending* ping_pending; struct route_ping_pending* ping_pending;
uint32_t next_ping_req_id; uint32_t next_ping_req_id;
uint8_t allow_nat_check_local; // 1 = разрешить NAT check для локальных подсетей (для тестов) uint8_t allow_nat_check_local;
uint8_t ed25519_public_key[SC_PUBKEY_SIZE]; // свой Ed25519 pubkey (для подписи сообщений) uint8_t ed25519_public_key[SC_PUBKEY_SIZE];
MDB_env* nodeinfo_env; // LMDB environment handle MDB_env* nodeinfo_env;
MDB_dbi nodeinfo_dbi; // LMDB database handle for nodeinfo table MDB_dbi nodeinfo_dbi;
struct memory_pool* v4_sock_meta_pool;
struct memory_pool* v4_addr_pool;
struct memory_pool* v6_sock_meta_pool;
struct memory_pool* v6_addr_pool;
struct memory_pool* v4_subnet_pool;
struct memory_pool* v6_subnet_pool;
}; };
/** /**
@ -161,8 +168,6 @@ void route_bgp_send_nodeinfo(struct NODEINFO_Q* node, struct ETCP_CONN* conn);
*/ */
void route_bgp_send_withdraw(struct ROUTE_BGP* bgp, uint64_t node_id); void route_bgp_send_withdraw(struct ROUTE_BGP* bgp, uint64_t node_id);
int nodeinfo_dyn_size(struct NODEINFO* node);
/** /**
* @brief Поиск оптимального ETCP соединения для указанного node_id. * @brief Поиск оптимального ETCP соединения для указанного node_id.
* *

136
src/route_connectivity.c

@ -277,7 +277,7 @@ static void conn_probe_finish(struct conn_probe_ctx* ctx, int ok) {
if (c->pending_count == 0) { if (c->pending_count == 0) {
c->probe_status = PROBE_STATUS_DONE; c->probe_status = PROBE_STATUS_DONE;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "connectivity probe DONE for node %016llx: intf=%d nat=%d real=%d", DEBUG_INFO(DEBUG_CATEGORY_BGP, "connectivity probe DONE for node %016llx: intf=%d nat=%d real=%d",
(unsigned long long)ctx->nq->node.node_id, (unsigned long long)ctx->nq->node->node_id,
c->interface_status, c->nat_status, c->real_status); c->interface_status, c->nat_status, c->real_status);
} }
} }
@ -289,9 +289,9 @@ static void conn_probe_finish(struct conn_probe_ctx* ctx, int ok) {
void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct NODEINFO_Q* nq) { void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct NODEINFO_Q* nq) {
if (!instance || !nq) return; if (!instance || !nq) return;
if (nq->node.node_id == instance->node_id) return; // не пингуем себя if (nq->node->node_id == instance->node_id) return; // не пингуем себя
if (nq->connectivity.probe_status == PROBE_STATUS_IN_PROGRESS) { if (nq->connectivity.probe_status == PROBE_STATUS_IN_PROGRESS) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "probe already in progress for node %016llx", (unsigned long long)nq->node.node_id); DEBUG_INFO(DEBUG_CATEGORY_BGP, "probe already in progress for node %016llx", (unsigned long long)nq->node->node_id);
return; return;
} }
@ -308,131 +308,71 @@ void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct NODEIN
int pend = 0; int pend = 0;
// ---- IPv4 addresses ---- // ---- IPv4 addresses ----
const struct NODEINFO_IPV4_ADDR* addrs; if (nq->node && nq->node->v4_addrs) {
int addr_count = get_node_v4_addrs(nq, &addrs); uint32_t seen_ips[16]; uint16_t seen_ports[16]; int seen_count = 0;
if (addr_count > 0) { for (const struct NI_IPV4_ADDR* a = nq->node->v4_addrs; a; a = a->next) {
uint32_t seen_ips[16]; uint16_t seen_ports[16]; uint32_t ip; memcpy(&ip, a->addr, 4); uint16_t port = a->port;
int seen_count = 0;
for (int i = 0; i < addr_count; i++) {
uint32_t ip; memcpy(&ip, addrs[i].addr, 4);
uint16_t port = addrs[i].port;
if (ip == 0 || port == 0) continue; if (ip == 0 || port == 0) continue;
int dup = 0; for (int j = 0; j < seen_count; j++) { if (seen_ips[j] == ip && seen_ports[j] == port) { dup = 1; break; } }
int dup = 0;
for (int j = 0; j < seen_count; j++) {
if (seen_ips[j] == ip && seen_ports[j] == port) { dup = 1; break; }
}
if (dup) continue; if (dup) continue;
if (seen_count >= 16) break; if (seen_count >= 16) break;
seen_ips[seen_count] = ip; seen_ports[seen_count] = port; seen_count++; seen_ips[seen_count] = ip; seen_ports[seen_count] = port; seen_count++;
struct sockaddr_storage target; struct sockaddr_storage target; memset(&target, 0, sizeof(target));
memset(&target, 0, sizeof(target)); struct sockaddr_in* sin = (struct sockaddr_in*)&target; sin->sin_family = AF_INET; sin->sin_addr.s_addr = ip; sin->sin_port = htons(port);
struct sockaddr_in* sin = (struct sockaddr_in*)&target;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = ip;
sin->sin_port = htons(port);
struct ETCP_SOCKET* candidates[CONN_MAX_SOCKET_CANDIDATES]; struct ETCP_SOCKET* candidates[CONN_MAX_SOCKET_CANDIDATES];
int cand_count = conn_match_candidate_sockets(instance, addrs[i].type, &target, int cand_count = conn_match_candidate_sockets(instance, a->type, &target, candidates, CONN_MAX_SOCKET_CANDIDATES);
candidates, CONN_MAX_SOCKET_CANDIDATES); if (cand_count == 0) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "probe: no local sockets for target %s:%u type=%d", ip_to_str(&ip, AF_INET).str, port, a->type); continue; }
if (cand_count == 0) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "probe: no local sockets for target %s:%u type=%d",
ip_to_str(&ip, AF_INET).str, port, addrs[i].type);
continue;
}
struct conn_probe_ctx* ctx = u_calloc(1, sizeof(struct conn_probe_ctx)); struct conn_probe_ctx* ctx = u_calloc(1, sizeof(struct conn_probe_ctx)); if (!ctx) continue;
if (!ctx) continue; ctx->instance = instance; ctx->nq = nq; ctx->addr_type = a->type; ctx->target_addr = target;
ctx->instance = instance; memcpy(ctx->peer_pubkey, nq->node->public_key, SC_PUBKEY_SIZE);
ctx->nq = nq;
ctx->addr_type = addrs[i].type;
ctx->target_addr = target;
memcpy(ctx->peer_pubkey, nq->node.public_key, SC_PUBKEY_SIZE);
memcpy(ctx->candidate_sockets, candidates, cand_count * sizeof(struct ETCP_SOCKET*)); memcpy(ctx->candidate_sockets, candidates, cand_count * sizeof(struct ETCP_SOCKET*));
ctx->candidate_count = cand_count; ctx->candidate_count = cand_count; ctx->candidate_index = 0; ctx->count_total = CONN_PROBE_COUNT; ctx->timeout_ms = CONN_PROBE_TIMEOUT_MS; ctx->best_across_sockets = 65535;
ctx->candidate_index = 0; ctx->next = (struct conn_probe_ctx*)nq->connectivity.probe_list; nq->connectivity.probe_list = ctx; pend++;
ctx->count_total = CONN_PROBE_COUNT;
ctx->timeout_ms = CONN_PROBE_TIMEOUT_MS;
ctx->best_across_sockets = 65535;
ctx->next = (struct conn_probe_ctx*)nq->connectivity.probe_list;
nq->connectivity.probe_list = ctx;
pend++;
conn_probe_start_series(ctx); conn_probe_start_series(ctx);
} }
} }
// ---- IPv6 addresses ---- // ---- IPv6 addresses ----
const struct NODEINFO_IPV6_ADDR* addrs6; if (nq->node && nq->node->v6_addrs) {
int addr6_count = get_node_v6_addrs(nq, &addrs6); uint8_t seen_ip6s[16][16]; uint16_t seen_ports6[16]; int seen6_count = 0;
if (addr6_count > 0) { for (const struct NI_IPV6_ADDR* a6 = nq->node->v6_addrs; a6; a6 = a6->next) {
uint8_t seen_ip6s[16][16]; uint16_t seen_ports6[16]; if (a6->port == 0) continue;
int seen6_count = 0; int zero = 1; for (int z = 0; z < 16; z++) if (a6->addr[z] != 0) { zero = 0; break; } if (zero) continue;
int dup = 0; for (int j = 0; j < seen6_count; j++) { if (memcmp(seen_ip6s[j], a6->addr, 16) == 0 && seen_ports6[j] == a6->port) { dup = 1; break; } }
for (int i = 0; i < addr6_count; i++) {
if (addrs6[i].port == 0) continue;
// skip zero address
int zero = 1;
for (int z = 0; z < 16; z++) if (addrs6[i].addr[z] != 0) { zero = 0; break; }
if (zero) continue;
int dup = 0;
for (int j = 0; j < seen6_count; j++) {
if (memcmp(seen_ip6s[j], addrs6[i].addr, 16) == 0 && seen_ports6[j] == addrs6[i].port) { dup = 1; break; }
}
if (dup) continue; if (dup) continue;
if (seen6_count >= 16) break; if (seen6_count >= 16) break;
memcpy(seen_ip6s[seen6_count], addrs6[i].addr, 16); memcpy(seen_ip6s[seen6_count], a6->addr, 16); seen_ports6[seen6_count] = a6->port; seen6_count++;
seen_ports6[seen6_count] = addrs6[i].port;
seen6_count++;
struct sockaddr_storage target; struct sockaddr_storage target; memset(&target, 0, sizeof(target));
memset(&target, 0, sizeof(target)); struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&target; sin6->sin6_family = AF_INET6;
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&target; memcpy(&sin6->sin6_addr, a6->addr, 16); sin6->sin6_port = htons(a6->port);
sin6->sin6_family = AF_INET6;
memcpy(&sin6->sin6_addr, addrs6[i].addr, 16);
sin6->sin6_port = htons(addrs6[i].port);
struct ETCP_SOCKET* candidates[CONN_MAX_SOCKET_CANDIDATES]; struct ETCP_SOCKET* candidates[CONN_MAX_SOCKET_CANDIDATES];
int cand_count = conn_match_candidate_sockets(instance, addrs6[i].type, &target, int cand_count = conn_match_candidate_sockets(instance, a6->type, &target, candidates, CONN_MAX_SOCKET_CANDIDATES);
candidates, CONN_MAX_SOCKET_CANDIDATES); if (cand_count == 0) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "probe: no local sockets for IPv6 target type=%d", a6->type); continue; }
if (cand_count == 0) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "probe: no local sockets for IPv6 target type=%d", addrs6[i].type);
continue;
}
struct conn_probe_ctx* ctx = u_calloc(1, sizeof(struct conn_probe_ctx)); struct conn_probe_ctx* ctx = u_calloc(1, sizeof(struct conn_probe_ctx)); if (!ctx) continue;
if (!ctx) continue; ctx->instance = instance; ctx->nq = nq; ctx->addr_type = a6->type; ctx->target_addr = target;
ctx->instance = instance; memcpy(ctx->peer_pubkey, nq->node->public_key, SC_PUBKEY_SIZE);
ctx->nq = nq;
ctx->addr_type = addrs6[i].type;
ctx->target_addr = target;
memcpy(ctx->peer_pubkey, nq->node.public_key, SC_PUBKEY_SIZE);
memcpy(ctx->candidate_sockets, candidates, cand_count * sizeof(struct ETCP_SOCKET*)); memcpy(ctx->candidate_sockets, candidates, cand_count * sizeof(struct ETCP_SOCKET*));
ctx->candidate_count = cand_count; ctx->candidate_count = cand_count; ctx->candidate_index = 0; ctx->count_total = CONN_PROBE_COUNT; ctx->timeout_ms = CONN_PROBE_TIMEOUT_MS; ctx->best_across_sockets = 65535;
ctx->candidate_index = 0; ctx->next = (struct conn_probe_ctx*)nq->connectivity.probe_list; nq->connectivity.probe_list = ctx; pend++;
ctx->count_total = CONN_PROBE_COUNT;
ctx->timeout_ms = CONN_PROBE_TIMEOUT_MS;
ctx->best_across_sockets = 65535;
ctx->next = (struct conn_probe_ctx*)nq->connectivity.probe_list;
nq->connectivity.probe_list = ctx;
pend++;
conn_probe_start_series(ctx); conn_probe_start_series(ctx);
} }
} }
if (pend == 0) { if (pend == 0) {
nq->connectivity.probe_status = PROBE_STATUS_DONE; nq->connectivity.probe_status = PROBE_STATUS_DONE;
if (addr_count == 0 && addr6_count == 0) { if (!nq->node->v4_addrs && !nq->node->v6_addrs) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "no addresses to probe for node %016llx", (unsigned long long)nq->node.node_id); DEBUG_INFO(DEBUG_CATEGORY_BGP, "no addresses to probe for node %016llx", (unsigned long long)nq->node->node_id);
} }
} else { } else {
nq->connectivity.pending_count = pend; nq->connectivity.pending_count = pend;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "connectivity probe started for node %016llx: %d series pending", DEBUG_INFO(DEBUG_CATEGORY_BGP, "connectivity probe started for node %016llx: %d series pending",
(unsigned long long)nq->node.node_id, pend); (unsigned long long)nq->node->node_id, pend);
} }
} }
@ -443,7 +383,7 @@ void route_connectivity_cancel_node(struct UTUN_INSTANCE* instance, struct NODEI
struct conn_probe_ctx* ctx = (struct conn_probe_ctx*)nq->connectivity.probe_list; struct conn_probe_ctx* ctx = (struct conn_probe_ctx*)nq->connectivity.probe_list;
while (ctx) { ctx->nq = NULL; ctx = ctx->next; } while (ctx) { ctx->nq = NULL; ctx = ctx->next; }
nq->connectivity.probe_list = NULL; nq->connectivity.probe_list = NULL;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "connectivity probe cancelled for node %016llx", (unsigned long long)nq->node.node_id); DEBUG_INFO(DEBUG_CATEGORY_BGP, "connectivity probe cancelled for node %016llx", (unsigned long long)nq->node->node_id);
} }
void route_connectivity_cancel_all(struct UTUN_INSTANCE* instance) { void route_connectivity_cancel_all(struct UTUN_INSTANCE* instance) {

97
src/route_lib.c

@ -146,103 +146,62 @@ void route_table_destroy(struct ROUTE_TABLE *table) {
} }
bool route_insert(struct ROUTE_TABLE *table, struct NODEINFO_Q *node) { bool route_insert(struct ROUTE_TABLE *table, struct NODEINFO_Q *node) {
if (!table || !node) { if (!table || !node) { DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_insert: invalid arguments"); return false; }
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_insert: invalid arguments");
return false;
}
// === Вызов сторонней функции (теперь без malloc) ===
const struct NODEINFO_IPV4_SUBNET *subnets = NULL;
int cnt = get_node_routes(node, &subnets);
if (cnt <= 0) { if (!node->routes || !node->routes->v4_subnets) {
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_insert: get_node_routes returned %d subnets", cnt); DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_insert: node has no v4 subnets");
return false; return false;
} }
const struct NI_IPV4_SUBNET* sub = node->routes->v4_subnets;
int cnt = 0; for (const struct NI_IPV4_SUBNET* s = sub; s; s = s->next) cnt++;
if (cnt == 0) { DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_insert: 0 subnets"); return false; }
size_t count = (size_t)cnt; size_t count = (size_t)cnt;
// === Проверка пересечений === for (const struct NI_IPV4_SUBNET* s = sub; s; s = s->next) {
for (size_t i = 0; i < count; i++) { uint32_t network; memcpy(&network, s->addr, 4); network = ntohl(network);
uint32_t network; if (check_route_overlap_in_table(network, s->prefix_length, table->entries, table->count)) {
memcpy(&network, subnets[i].addr, 4); DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_insert: overlap detected for %s/%d", ip_to_string(network).a, s->prefix_length);
network = ntohl(network);
uint8_t prefix = subnets[i].prefix_length;
if (check_route_overlap_in_table(network, prefix,
table->entries, table->count)) {
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_insert: overlap detected for %s/%d",
ip_to_string(network).a, prefix);
return false; return false;
} }
} }
// === Реаллокация при необходимости ===
if (table->count + count > table->capacity) { if (table->count + count > table->capacity) {
size_t new_cap = table->capacity * 2; size_t new_cap = table->capacity * 2;
while (new_cap < table->count + count) new_cap *= 2; while (new_cap < table->count + count) new_cap *= 2;
struct ROUTE_ENTRY *new_entries = u_realloc(table->entries, new_cap * sizeof(struct ROUTE_ENTRY)); struct ROUTE_ENTRY* new_entries = u_realloc(table->entries, new_cap * sizeof(struct ROUTE_ENTRY));
if (!new_entries) { if (!new_entries) { DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_insert: realloc failed"); return false; }
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_insert: realloc failed"); table->entries = new_entries; table->capacity = new_cap;
return false;
}
table->entries = new_entries;
table->capacity = new_cap;
} }
// === Вставка каждого префикса (таблица остаётся отсортированной) === for (const struct NI_IPV4_SUBNET* s = sub; s; s = s->next) {
for (size_t i = 0; i < count; i++) { uint32_t network; memcpy(&network, s->addr, 4); network = ntohl(network);
uint32_t network; int pos = binary_search_insert_pos(table->entries, table->count, network, s->prefix_length);
memcpy(&network, subnets[i].addr, 4); if (pos < (int)table->count) memmove(&table->entries[pos + 1], &table->entries[pos], (table->count - pos) * sizeof(struct ROUTE_ENTRY));
network = ntohl(network); struct ROUTE_ENTRY* e = &table->entries[pos];
uint8_t prefix_length = subnets[i].prefix_length; e->network = network; e->prefix_length = s->prefix_length; e->v_node_info = node;
int pos = binary_search_insert_pos(table->entries, table->count, network, prefix_length);
if (pos < (int)table->count) {
memmove(&table->entries[pos + 1], &table->entries[pos],
(table->count - pos) * sizeof(struct ROUTE_ENTRY));
}
struct ROUTE_ENTRY *e = &table->entries[pos];
e->network = network;
e->prefix_length = prefix_length;
e->v_node_info = node;
table->count++; table->count++;
if (node && node->node.hop_count == 0) table->stats.local_routes++; else table->stats.learned_routes++; if (node->hop_count == 0) table->stats.local_routes++; else table->stats.learned_routes++;
} }
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "route_insert: added %zu route(s) for node=%016llx", DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "route_insert: added %zu route(s) for node=%016llx",
count, node ? (unsigned long long)node->node.node_id : 0ULL); count, (unsigned long long)node->node->node_id);
return true; return true;
} }
void route_delete(struct ROUTE_TABLE *table, struct NODEINFO_Q *node) { void route_delete(struct ROUTE_TABLE *table, struct NODEINFO_Q *node) {
if (!table || !node) return; if (!table || !node) return;
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "route_delete: removing all routes for node=%016llx", (unsigned long long)node->node->node_id);
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "route_delete: removing all routes for node=%016llx", size_t i = 0, removed = 0;
(unsigned long long)node->node.node_id);
size_t i = 0;
size_t removed = 0;
while (i < table->count) { while (i < table->count) {
if (table->entries[i].v_node_info == node) { if (table->entries[i].v_node_info == node) {
if (i < table->count - 1) { if (i < table->count - 1) memmove(&table->entries[i], &table->entries[i + 1], (table->count - i - 1) * sizeof(struct ROUTE_ENTRY));
memmove(&table->entries[i], &table->entries[i + 1],
(table->count - i - 1) * sizeof(struct ROUTE_ENTRY));
}
table->count--; table->count--;
if (node && node->node.hop_count == 0) table->stats.local_routes--; else table->stats.learned_routes--; if (node->hop_count == 0) table->stats.local_routes--; else table->stats.learned_routes--;
removed++; removed++; continue;
continue;
} }
i++; i++;
} }
if (removed > 0) DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "route_delete: removed %zu route(s)", removed);
if (removed > 0) {
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "route_delete: removed %zu route(s)", removed);
}
} }
struct ROUTE_ENTRY* route_lookup(struct ROUTE_TABLE *table, uint32_t dest_ip) { struct ROUTE_ENTRY* route_lookup(struct ROUTE_TABLE *table, uint32_t dest_ip) {
@ -277,7 +236,7 @@ void route_table_print(const struct ROUTE_TABLE *table) {
const struct ROUTE_ENTRY *entry = &table->entries[i]; const struct ROUTE_ENTRY *entry = &table->entries[i];
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " %zu: %s/%d", DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " %zu: %s/%d",
i + 1, ip_to_string(entry->network).a, entry->prefix_length); i + 1, ip_to_string(entry->network).a, entry->prefix_length);
if (entry->v_node_info && entry->v_node_info->node.hop_count != 0) { if (entry->v_node_info && entry->v_node_info->hop_count != 0) {
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " v_node_info=%p", (void*)entry->v_node_info); DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " v_node_info=%p", (void*)entry->v_node_info);
} else { } else {
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " LOCAL"); DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " LOCAL");

931
src/route_node.c

File diff suppressed because it is too large Load Diff

226
src/route_node.h

@ -47,87 +47,66 @@ struct UTUN_INSTANCE;
#define CONN_TYPE_INDIRECT 3 #define CONN_TYPE_INDIRECT 3
#define CONN_MGR_MAX_INTERMEDIARIES 3 #define CONN_MGR_MAX_INTERMEDIARIES 3
// ---- флаги nodeinfo (protocol) ----
#define NODEINFO_FLAG_SEND_SUBNETS 0x01
// ---- group_id по умолчанию ----
#define NODEINFO_GROUP_UTUN 1
// ---- состояние связности с удалённым узлом (локальное, не передаётся по BGP) ---- // ---- состояние связности с удалённым узлом (локальное, не передаётся по BGP) ----
struct NODE_CONNECTIVITY { struct NODE_CONNECTIVITY {
uint8_t probe_status; // PROBE_STATUS_* uint8_t probe_status;
uint8_t pending_count; // активных probe series uint8_t pending_count;
uint64_t probe_start_time; // timebase uint64_t probe_start_time;
uint16_t interface_min_rtt; // x0.1ms uint16_t interface_min_rtt;
uint16_t nat_min_rtt; uint16_t nat_min_rtt;
uint16_t real_min_rtt; uint16_t real_min_rtt;
uint8_t interface_status; // PROBE_RESULT_* uint8_t interface_status;
uint8_t nat_status; uint8_t nat_status;
uint8_t real_status; uint8_t real_status;
uint8_t reserved; uint8_t reserved;
uint64_t interface_probe_time; uint64_t interface_probe_time;
uint64_t nat_probe_time; uint64_t nat_probe_time;
uint64_t real_probe_time; uint64_t real_probe_time;
uint64_t ping_req_time; // время последнего полученного ping request от этого узла (0.1ms tb) uint64_t ping_req_time;
void* probe_list; // linked list of active conn_probe_ctx (для cancel) void* probe_list;
}; };
/** // =======================================================================
* @brief Информация о узле (передаётся по BGP) // Протокольные структуры (wire-format, packed, без next)
*/ // =======================================================================
struct NODEINFO {
uint64_t node_id; // (big-endian)
uint8_t ver; // версия пакета (циклический счетчик чтобы быстро сравнивать с локальной копией - были ли обновления)
uint8_t public_key[SC_PUBKEY_SIZE]; // X25519 pubkey
uint8_t ed25519_public_key[SC_PUBKEY_SIZE]; // Ed25519 pubkey for signature verification
uint8_t node_name_len; // размер в байтах (без null терминации)
uint8_t local_v4_sockets; // NODEINFO_IPV4_SOCKET_META число метаданных ipv4 сокетов
uint8_t local_v4_addrs; // NODEINFO_IPV4_ADDR число типизированных ipv4 адресов узла (плоский список)
uint8_t local_v6_sockets; // NODEINFO_IPV6_SOCKET_META число метаданных ipv6 сокетов
uint8_t local_v6_addrs; // NODEINFO_IPV6_ADDR число типизированных ipv6 адресов узла
uint8_t local_v4_subnets; // NODEINFO_IPV4_SUBNET число локальных ipv4 подсетей узла
uint8_t local_v6_subnets; // NODEINFO_IPV6_SUBNET число локальных ipv6 подсетей узла
uint8_t tranzit_nodes; // NODEINFO_TRANZIT_NODE лучшие транзитные узлы для этой ноды >>> надо перенести в group-specific struct
uint8_t hop_count; // hop list: маршрут по которому распространялся этот NODEINFO_PACKET >>> надо перенести в group-specific struct
// далее идут динамические поля по порядку:
// char node_name[node_name_len]
// NODEINFO_IPV4_SOCKET_META[local_v4_sockets]
// NODEINFO_IPV4_ADDR[local_v4_addrs]
// NODEINFO_IPV6_SOCKET_META[local_v6_sockets]
// NODEINFO_IPV6_ADDR[local_v6_addrs]
// NODEINFO_IPV4_SUBNET[local_v4_subnets]
// NODEINFO_IPV6_SUBNET[local_v6_subnets]
// NODEINFO_TRANZIT_NODE[tranzit_nodes]
// uint64_t hop_list[hop_count]
} __attribute__((packed));
// метаданные одного сокета
struct NODEINFO_IPV4_SOCKET_META { struct NODEINFO_IPV4_SOCKET_META {
uint8_t id; // unique socket id (0-255) uint8_t id;
uint8_t config_type; // CFG_SERVER_TYPE_PUBLIC/NAT/PRIVATE uint8_t config_type;
uint8_t nat_type; // NAT_TYPE_* / NAT_VERIFIED_* uint8_t nat_type;
} __attribute__((packed)); } __attribute__((packed));
// одна типизированная адресная запись (плоский список)
struct NODEINFO_IPV4_ADDR { struct NODEINFO_IPV4_ADDR {
uint8_t addr[4]; // IP (network byte order) uint8_t addr[4];
uint16_t port; // port (host byte order) uint16_t port;
uint8_t type; // ADDR_TYPE_INTERFACE/NAT/REAL uint8_t type;
uint8_t socket_id; // к какому сокету относится uint8_t socket_id;
uint8_t protocol; // битовая маска NODE_PROTO_UDP/NODE_PROTO_TCP uint8_t protocol;
} __attribute__((packed)); } __attribute__((packed));
struct NODEINFO_IPV6_SOCKET_META { struct NODEINFO_IPV6_SOCKET_META {
uint8_t id; // unique socket id (0-255) uint8_t id;
uint8_t config_type; // CFG_SERVER_TYPE_PUBLIC/NAT/PRIVATE uint8_t config_type;
uint8_t nat_type; // NAT_TYPE_* / NAT_VERIFIED_* uint8_t nat_type;
} __attribute__((packed)); } __attribute__((packed));
struct NODEINFO_IPV6_ADDR { struct NODEINFO_IPV6_ADDR {
uint8_t addr[16]; uint8_t addr[16];
uint16_t port; uint16_t port;
uint8_t type; uint8_t type;
uint8_t socket_id; uint8_t socket_id;
uint8_t protocol; // битовая маска NODE_PROTO_UDP/NODE_PROTO_TCP uint8_t protocol;
} __attribute__((packed)); } __attribute__((packed));
struct NODEINFO_IPV4_SUBNET { struct NODEINFO_IPV4_SUBNET {
uint8_t addr[4];// network byte order uint8_t addr[4];
uint8_t prefix_length; uint8_t prefix_length;
} __attribute__((packed)); } __attribute__((packed));
@ -137,68 +116,127 @@ struct NODEINFO_IPV6_SUBNET {
} __attribute__((packed)); } __attribute__((packed));
struct NODEINFO_TRANZIT_NODE { struct NODEINFO_TRANZIT_NODE {
uint64_t node_id; // (big-endian) uint64_t node_id;
uint16_t rtt; // x0.1 ms (измеренный удаленным узлом RTT до транзитного узла) uint16_t rtt;
uint16_t link_q; // меньше - лучше (потери + 1/BW) uint16_t link_q;
} __attribute__((packed));
/**
* @brief Протокольный формат NODEINFO сообщения (wire-format)
*/
struct NODEINFO_MSG {
uint8_t flags;
uint64_t group_id;
uint64_t node_id;
uint8_t ver;
uint8_t public_key[SC_PUBKEY_SIZE];
uint8_t ed25519_public_key[SC_PUBKEY_SIZE];
uint8_t node_name_len;
uint8_t local_v4_sockets;
uint8_t local_v4_addrs;
uint8_t local_v6_sockets;
uint8_t local_v6_addrs;
uint8_t local_v4_subnets;
uint8_t local_v6_subnets;
uint8_t tranzit_nodes;
uint8_t hop_count;
} __attribute__((packed)); } __attribute__((packed));
#define NODEINFO_MSG_HDR_SIZE sizeof(struct NODEINFO_MSG)
// =======================================================================
// Структуры для хранения в памяти (linked list с next* первым полем)
// =======================================================================
struct NI_IPV4_SOCKET_META { struct NI_IPV4_SOCKET_META* next; uint8_t id, config_type, nat_type; };
struct NI_IPV4_ADDR { struct NI_IPV4_ADDR* next; uint8_t addr[4]; uint16_t port; uint8_t type, socket_id, protocol; };
struct NI_IPV6_SOCKET_META { struct NI_IPV6_SOCKET_META* next; uint8_t id, config_type, nat_type; };
struct NI_IPV6_ADDR { struct NI_IPV6_ADDR* next; uint8_t addr[16]; uint16_t port; uint8_t type, socket_id, protocol; };
struct NI_IPV4_SUBNET { struct NI_IPV4_SUBNET* next; uint8_t addr[4]; uint8_t prefix_length; };
struct NI_IPV6_SUBNET { struct NI_IPV6_SUBNET* next; uint8_t addr[16]; uint8_t prefix_length; };
// Универсальная голова списка (next — первое поле во всех NI_*)
struct _ni_head { struct _ni_head* next; };
static inline int ni_list_count(struct _ni_head* head) { int n = 0; while (head) { n++; head = head->next; } return n; }
/**
* @brief Идентификационная информация об узле (память, разделяется между группами)
*/
struct NODEINFO {
uint32_t ref_count;
uint8_t flags;
uint64_t group_id;
uint64_t node_id;
uint8_t ver;
uint8_t public_key[SC_PUBKEY_SIZE];
uint8_t ed25519_public_key[SC_PUBKEY_SIZE];
char* node_name; // отдельный u_strdup/u_free
struct NI_IPV4_SOCKET_META* v4_sock_meta; // linked list head
struct NI_IPV4_ADDR* v4_addrs; // linked list head
struct NI_IPV6_SOCKET_META* v6_sock_meta;
struct NI_IPV6_ADDR* v6_addrs;
};
/**
* @brief Маршруты узла (отдельный malloc, NULL если нет подсетей)
*/
struct NODEINFO_ROUTES {
struct NI_IPV4_SUBNET* v4_subnets; // linked list head
struct NI_IPV6_SUBNET* v6_subnets;
};
struct NODEINFO_PATH { struct NODEINFO_PATH {
struct ll_entry ll; struct ll_entry ll;
struct ETCP_CONN* conn; struct ETCP_CONN* conn;
uint8_t hop_count; // hop list: маршрут этого path uint8_t hop_count;
}; };
struct NODEINFO_Q { struct NODEINFO_Q {
struct ll_entry ll; struct ll_entry ll;
struct ll_queue* paths; // сюда помещаем struct NODEINFO_PATH uint64_t hash_node_id; // копия node_id для хеш-индекса
struct NODEINFO* node; // отдельный malloc, ref_count
struct NODEINFO_ROUTES* routes; // отдельный malloc (NULL если без подсетей)
struct NODEINFO_TRANZIT_NODE* tranzit_data; // отдельный malloc
uint64_t* hop_list; // отдельный malloc
uint8_t tranzit_count;
uint8_t hop_count;
struct ll_queue* paths;
uint8_t dirty; uint8_t dirty;
uint8_t last_ver; uint8_t last_ver;
uint8_t alien; // 1 = чужой узел (не запрашиваем роутинг при connect) uint8_t alien;
uint8_t conn_mgr_type; // CONN_TYPE_* — тип managed-подключения uint8_t conn_mgr_type;
uint64_t conn_mgr_intermediaries[CONN_MGR_MAX_INTERMEDIARIES]; // посредники для INDIRECT uint64_t conn_mgr_intermediaries[CONN_MGR_MAX_INTERMEDIARIES];
uint8_t conn_mgr_intermediariy_count; uint8_t conn_mgr_intermediariy_count;
struct NODE_CONNECTIVITY connectivity; // состояние связности (локальное) struct NODE_CONNECTIVITY connectivity;
struct ETCP_SOCKET* best_socket; struct ETCP_SOCKET* best_socket;
struct NODEINFO node; // Всегда в конце структуры - динамически расширяемый блок
}; };
/** // =======================================================================
* @brief Создаёт/обновляет nodeinfo для собственного узла // API
*/ // =======================================================================
int route_bgp_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BGP* bgp);
/**
* @brief Получает указатель на массив IPv4-подсетей узла (без malloc/копирования).
*/
int get_node_routes(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_SUBNET **out_subnets);
/**
* @brief Получает указатель на массив IPv6-подсетей узла (без malloc/копирования).
*/
int get_node_v6_routes(struct NODEINFO_Q *node, const struct NODEINFO_IPV6_SUBNET **out_subnets);
/** struct NODEINFO_Q* nodeinfo_find_by_id(struct ROUTE_BGP* bgp, uint64_t node_id);
* @brief Получает указатель на массив метаданных IPv4-сокетов узла.
*/
int get_node_v4_sockets_meta(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_SOCKET_META **out_meta);
/** void nodeinfo_ref(struct NODEINFO* ni);
* @brief Получает указатель на плоский список IPv4-адресов узла. void nodeinfo_unref(struct NODEINFO* ni);
*/ void nodeinfo_free_lists(struct ROUTE_BGP* bgp, struct NODEINFO_Q* nq);
int get_node_v4_addrs(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_ADDR **out_addrs); int nodeinfo_dyn_size(const struct NODEINFO_MSG* msg);
/** // convenience accessors
* @brief Получает указатель на массив метаданных IPv6-сокетов узла. static inline const struct NI_IPV4_SOCKET_META* ni_v4_sock_meta(const struct NODEINFO* ni) { return ni->v4_sock_meta; }
*/ static inline const struct NI_IPV4_ADDR* ni_v4_addrs(const struct NODEINFO* ni) { return ni->v4_addrs; }
int get_node_v6_sockets_meta(struct NODEINFO_Q *node, const struct NODEINFO_IPV6_SOCKET_META **out_meta); static inline const struct NI_IPV6_SOCKET_META* ni_v6_sock_meta(const struct NODEINFO* ni) { return ni->v6_sock_meta; }
static inline const struct NI_IPV6_ADDR* ni_v6_addrs(const struct NODEINFO* ni) { return ni->v6_addrs; }
static inline const struct NI_IPV4_SUBNET* ni_v4_subnets(const struct NODEINFO_ROUTES* r) { return r ? r->v4_subnets : NULL; }
static inline const struct NI_IPV6_SUBNET* ni_v6_subnets(const struct NODEINFO_ROUTES* r) { return r ? r->v6_subnets : NULL; }
/** int nodeinfo_serialize(struct ROUTE_BGP* bgp, struct NODEINFO_Q* nq, uint8_t* out, size_t out_max);
* @brief Получает указатель на плоский список IPv6-адресов узла. int nodeinfo_deserialize(struct ROUTE_BGP* bgp, const uint8_t* data, size_t len, struct NODEINFO** out_ni, struct NODEINFO_ROUTES** out_routes,
*/ struct NODEINFO_TRANZIT_NODE** out_tranzit, uint8_t* out_tranzit_count, uint64_t** out_hop_list, uint8_t* out_hop_count);
int get_node_v6_addrs(struct NODEINFO_Q *node, const struct NODEINFO_IPV6_ADDR **out_addrs);
struct NODEINFO_Q* nodeinfo_find_by_id(struct ROUTE_BGP* bgp, uint64_t node_id); int route_bgp_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BGP* bgp);
void route_node_dump_all(struct ROUTE_BGP* bgp); void route_node_dump_all(struct ROUTE_BGP* bgp);
int route_node_format_all(struct ROUTE_BGP* bgp, char* buf, size_t buf_size); int route_node_format_all(struct ROUTE_BGP* bgp, char* buf, size_t buf_size);

132
src/route_node_lmdb.c

@ -11,140 +11,56 @@
int route_node_lmdb_init(struct ROUTE_BGP* bgp, const char* db_path) { int route_node_lmdb_init(struct ROUTE_BGP* bgp, const char* db_path) {
if (!bgp || !db_path || !db_path[0]) return -1; if (!bgp || !db_path || !db_path[0]) return -1;
int rc = mdb_env_create(&bgp->nodeinfo_env); int rc = mdb_env_create(&bgp->nodeinfo_env);
if (rc != MDB_SUCCESS) { if (rc != MDB_SUCCESS) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_env_create failed: %s", mdb_strerror(rc)); return -1; }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_env_create failed: %s", mdb_strerror(rc));
return -1;
}
rc = mdb_env_set_mapsize(bgp->nodeinfo_env, NODEINFO_DB_MAPSIZE); rc = mdb_env_set_mapsize(bgp->nodeinfo_env, NODEINFO_DB_MAPSIZE);
if (rc != MDB_SUCCESS) { if (rc != MDB_SUCCESS) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_env_set_mapsize failed: %s", mdb_strerror(rc)); mdb_env_close(bgp->nodeinfo_env); bgp->nodeinfo_env = NULL; return -1; }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_env_set_mapsize failed: %s", mdb_strerror(rc));
mdb_env_close(bgp->nodeinfo_env);
bgp->nodeinfo_env = NULL;
return -1;
}
rc = mdb_env_set_maxdbs(bgp->nodeinfo_env, 2); rc = mdb_env_set_maxdbs(bgp->nodeinfo_env, 2);
if (rc != MDB_SUCCESS) { if (rc != MDB_SUCCESS) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_env_set_maxdbs failed: %s", mdb_strerror(rc)); mdb_env_close(bgp->nodeinfo_env); bgp->nodeinfo_env = NULL; return -1; }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_env_set_maxdbs failed: %s", mdb_strerror(rc));
mdb_env_close(bgp->nodeinfo_env);
bgp->nodeinfo_env = NULL;
return -1;
}
rc = mdb_env_open(bgp->nodeinfo_env, db_path, 0, 0644); rc = mdb_env_open(bgp->nodeinfo_env, db_path, 0, 0644);
if (rc != MDB_SUCCESS) { if (rc != MDB_SUCCESS) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_env_open(%s) failed: %s", db_path, mdb_strerror(rc)); mdb_env_close(bgp->nodeinfo_env); bgp->nodeinfo_env = NULL; return -1; }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_env_open(%s) failed: %s", db_path, mdb_strerror(rc)); MDB_txn* txn = NULL; rc = mdb_txn_begin(bgp->nodeinfo_env, NULL, 0, &txn);
mdb_env_close(bgp->nodeinfo_env); if (rc != MDB_SUCCESS) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_txn_begin failed: %s", mdb_strerror(rc)); mdb_env_close(bgp->nodeinfo_env); bgp->nodeinfo_env = NULL; return -1; }
bgp->nodeinfo_env = NULL;
return -1;
}
MDB_txn* txn = NULL;
rc = mdb_txn_begin(bgp->nodeinfo_env, NULL, 0, &txn);
if (rc != MDB_SUCCESS) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_txn_begin failed: %s", mdb_strerror(rc));
mdb_env_close(bgp->nodeinfo_env);
bgp->nodeinfo_env = NULL;
return -1;
}
rc = mdb_dbi_open(txn, "nodeinfo", MDB_CREATE, &bgp->nodeinfo_dbi); rc = mdb_dbi_open(txn, "nodeinfo", MDB_CREATE, &bgp->nodeinfo_dbi);
if (rc != MDB_SUCCESS) { if (rc != MDB_SUCCESS) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_dbi_open(nodeinfo) failed: %s", mdb_strerror(rc)); mdb_txn_abort(txn); mdb_env_close(bgp->nodeinfo_env); bgp->nodeinfo_env = NULL; return -1; }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_dbi_open(nodeinfo) failed: %s", mdb_strerror(rc));
mdb_txn_abort(txn);
mdb_env_close(bgp->nodeinfo_env);
bgp->nodeinfo_env = NULL;
return -1;
}
rc = mdb_txn_commit(txn); rc = mdb_txn_commit(txn);
if (rc != MDB_SUCCESS) { if (rc != MDB_SUCCESS) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_txn_commit failed: %s", mdb_strerror(rc)); mdb_env_close(bgp->nodeinfo_env); bgp->nodeinfo_env = NULL; return -1; }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_txn_commit failed: %s", mdb_strerror(rc));
mdb_env_close(bgp->nodeinfo_env);
bgp->nodeinfo_env = NULL;
return -1;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "LMDB nodeinfo database opened: %s", db_path); DEBUG_INFO(DEBUG_CATEGORY_BGP, "LMDB nodeinfo database opened: %s", db_path);
return 0; return 0;
} }
void route_node_lmdb_destroy(struct ROUTE_BGP* bgp) { void route_node_lmdb_destroy(struct ROUTE_BGP* bgp) {
if (!bgp) return; if (!bgp) return;
if (bgp->nodeinfo_env) { if (bgp->nodeinfo_env) { mdb_env_close(bgp->nodeinfo_env); bgp->nodeinfo_env = NULL; DEBUG_INFO(DEBUG_CATEGORY_BGP, "LMDB nodeinfo database closed"); }
mdb_env_close(bgp->nodeinfo_env);
bgp->nodeinfo_env = NULL;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "LMDB nodeinfo database closed");
}
} }
int route_node_lmdb_put(struct ROUTE_BGP* bgp, struct NODEINFO_Q* nq) { int route_node_lmdb_put(struct ROUTE_BGP* bgp, struct NODEINFO_Q* nq) {
if (!bgp || !bgp->nodeinfo_env || !nq) return -1; if (!bgp || !bgp->nodeinfo_env || !nq || !nq->node) return -1;
uint8_t buf[8192];
int dyn_size = nodeinfo_dyn_size(&nq->node); int ser_len = nodeinfo_serialize(bgp, nq, buf, sizeof(buf));
size_t val_size = sizeof(struct NODEINFO) + dyn_size; if (ser_len < 0) return -1;
MDB_val key, data; MDB_val key, data;
key.mv_size = 8; key.mv_size = 8; key.mv_data = &nq->node->node_id;
key.mv_data = &nq->node.node_id; data.mv_size = (size_t)ser_len; data.mv_data = buf;
data.mv_size = val_size;
data.mv_data = (void*)&nq->node;
MDB_txn* txn = NULL;
int rc = mdb_txn_begin(bgp->nodeinfo_env, NULL, 0, &txn);
if (rc != MDB_SUCCESS) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB put mdb_txn_begin failed: %s", mdb_strerror(rc));
return -1;
}
MDB_txn* txn = NULL; int rc = mdb_txn_begin(bgp->nodeinfo_env, NULL, 0, &txn);
if (rc != MDB_SUCCESS) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB put mdb_txn_begin failed: %s", mdb_strerror(rc)); return -1; }
rc = mdb_put(txn, bgp->nodeinfo_dbi, &key, &data, 0); rc = mdb_put(txn, bgp->nodeinfo_dbi, &key, &data, 0);
if (rc != MDB_SUCCESS) { if (rc != MDB_SUCCESS) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_put node %016llx failed: %s", (unsigned long long)nq->node->node_id, mdb_strerror(rc)); mdb_txn_abort(txn); return -1; }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_put node %016llx failed: %s",
(unsigned long long)nq->node.node_id, mdb_strerror(rc));
mdb_txn_abort(txn);
return -1;
}
rc = mdb_txn_commit(txn); rc = mdb_txn_commit(txn);
if (rc != MDB_SUCCESS) { if (rc != MDB_SUCCESS) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB put mdb_txn_commit failed: %s", mdb_strerror(rc)); return -1; }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB put mdb_txn_commit failed: %s", mdb_strerror(rc));
return -1;
}
return 0; return 0;
} }
int route_node_lmdb_del(struct ROUTE_BGP* bgp, uint64_t node_id) { int route_node_lmdb_del(struct ROUTE_BGP* bgp, uint64_t node_id) {
if (!bgp || !bgp->nodeinfo_env) return -1; if (!bgp || !bgp->nodeinfo_env) return -1;
MDB_val key; key.mv_size = 8; key.mv_data = &node_id;
MDB_val key; MDB_txn* txn = NULL; int rc = mdb_txn_begin(bgp->nodeinfo_env, NULL, 0, &txn);
key.mv_size = 8; if (rc != MDB_SUCCESS) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB del mdb_txn_begin failed: %s", mdb_strerror(rc)); return -1; }
key.mv_data = &node_id;
MDB_txn* txn = NULL;
int rc = mdb_txn_begin(bgp->nodeinfo_env, NULL, 0, &txn);
if (rc != MDB_SUCCESS) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB del mdb_txn_begin failed: %s", mdb_strerror(rc));
return -1;
}
rc = mdb_del(txn, bgp->nodeinfo_dbi, &key, NULL); rc = mdb_del(txn, bgp->nodeinfo_dbi, &key, NULL);
if (rc != MDB_SUCCESS && rc != MDB_NOTFOUND) { if (rc != MDB_SUCCESS && rc != MDB_NOTFOUND) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_del node %016llx failed: %s", (unsigned long long)node_id, mdb_strerror(rc)); mdb_txn_abort(txn); return -1; }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB mdb_del node %016llx failed: %s",
(unsigned long long)node_id, mdb_strerror(rc));
mdb_txn_abort(txn);
return -1;
}
rc = mdb_txn_commit(txn); rc = mdb_txn_commit(txn);
if (rc != MDB_SUCCESS) { if (rc != MDB_SUCCESS) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB del mdb_txn_commit failed: %s", mdb_strerror(rc)); return -1; }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "LMDB del mdb_txn_commit failed: %s", mdb_strerror(rc));
return -1;
}
return 0; return 0;
} }

6
src/routing.c

@ -139,12 +139,12 @@ void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry, uint64_t
} }
struct NODEINFO_Q* nq = route->v_node_info; struct NODEINFO_Q* nq = route->v_node_info;
if (!nq || nq->node.hop_count == 0) { if (!nq || !nq->node || nq->hop_count == 0) {
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "Local route to %s", ip_to_str(&addr, AF_INET).str); DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "Local route to %s", ip_to_str(&addr, AF_INET).str);
} else { } else {
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_pkt: sending %zu bytes to node %016llx dst=%s", DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_pkt: sending %zu bytes to node %016llx dst=%s",
ip_len, (unsigned long long)nq->node.node_id, ip_to_str(&addr, AF_INET).str); ip_len, (unsigned long long)nq->node->node_id, ip_to_str(&addr, AF_INET).str);
int send_err = etcp_route_send(instance, nq->node.node_id, entry, 1); int send_err = etcp_route_send(instance, nq->node->node_id, entry, 1);
if (send_err != 0) { if (send_err != 0) {
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: etcp_route_send failed: dst=%s err=%d", DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: etcp_route_send failed: dst=%s err=%d",
ip_to_str(&addr, AF_INET).str, send_err); ip_to_str(&addr, AF_INET).str, send_err);

2
tests/test_bgp_route_exchange.c

@ -215,7 +215,7 @@ static int check_learned_route(struct UTUN_INSTANCE* inst, uint32_t network, uin
for (size_t i = 0; i < inst->rt->count; i++) { for (size_t i = 0; i < inst->rt->count; i++) {
struct ROUTE_ENTRY* e = &inst->rt->entries[i]; struct ROUTE_ENTRY* e = &inst->rt->entries[i];
if (e->network == network && e->prefix_length == prefix_len && if (e->network == network && e->prefix_length == prefix_len &&
e->v_node_info && e->v_node_info->node.node_id == expected_be) return 1; e->v_node_info && e->v_node_info->node->node_id == expected_be) return 1;
} }
return 0; return 0;
} }

2
tests/test_bgp_triangle.c

@ -156,7 +156,7 @@ static int route_count_for_node(struct UTUN_INSTANCE* inst, uint64_t node_id) {
int cnt = 0; int cnt = 0;
for (size_t i = 0; i < inst->rt->count; i++) for (size_t i = 0; i < inst->rt->count; i++)
if (inst->rt->entries[i].v_node_info && if (inst->rt->entries[i].v_node_info &&
inst->rt->entries[i].v_node_info->node.node_id == expected_be) cnt++; inst->rt->entries[i].v_node_info->node->node_id == expected_be) cnt++;
return cnt; return cnt;
} }

27
tests/test_etcp_connect.c

@ -66,24 +66,17 @@ static void connect_ccb(void* a, struct ETCP_CONN* conn, int type) { cb_type = t
/* ----- helper: create minimal NODEINFO_Q with 1 v4 addr ----- */ /* ----- helper: create minimal NODEINFO_Q with 1 v4 addr ----- */
static struct NODEINFO_Q* mknode(uint64_t nid, const uint8_t pubkey[32], static struct NODEINFO_Q* mknode(uint64_t nid, const uint8_t pubkey[32],
uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port) { uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port) {
size_t extra = sizeof(struct NODEINFO_IPV4_SOCKET_META) + sizeof(struct NODEINFO_IPV4_ADDR); struct NODEINFO_Q* nq = u_calloc(1, sizeof(struct NODEINFO_Q));
size_t data_sz = sizeof(struct NODEINFO_Q) - sizeof(struct ll_entry) + extra; struct NODEINFO* ni = u_calloc(1, sizeof(struct NODEINFO));
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)queue_entry_new(data_sz); if (!nq || !ni) { u_free(nq); u_free(ni); return NULL; }
if (!nq) return NULL; ni->ref_count = 1; ni->node_id = nid; ni->ver = 0;
struct NODEINFO* ni = &nq->node;
ni->node_id = nid; ni->ver = 0;
memcpy(ni->public_key, pubkey, SC_PUBKEY_SIZE); memcpy(ni->public_key, pubkey, SC_PUBKEY_SIZE);
ni->local_v4_sockets = 1; nq->ll.size = sizeof(struct NODEINFO_Q) - sizeof(struct ll_entry);
ni->local_v4_addrs = 1; nq->node = ni; nq->hash_node_id = nid;
struct NI_IPV4_SOCKET_META* sm = u_calloc(1, sizeof(struct NI_IPV4_SOCKET_META));
uint8_t* dyn = (uint8_t*)(ni + 1); if (sm) { sm->id = 0; sm->config_type = CFG_SERVER_TYPE_PUBLIC; sm->nat_type = NAT_TYPE_UNKNOWN; sm->next = ni->v4_sock_meta; ni->v4_sock_meta = sm; }
struct NODEINFO_IPV4_SOCKET_META* meta = (struct NODEINFO_IPV4_SOCKET_META*)dyn; struct NI_IPV4_ADDR* addr = u_calloc(1, sizeof(struct NI_IPV4_ADDR));
meta->id = 0; meta->config_type = CFG_SERVER_TYPE_PUBLIC; meta->nat_type = NAT_TYPE_UNKNOWN; if (addr) { addr->addr[0] = a; addr->addr[1] = b; addr->addr[2] = c; addr->addr[3] = d; addr->port = port; addr->type = ADDR_TYPE_INTERFACE; addr->socket_id = 0; addr->next = ni->v4_addrs; ni->v4_addrs = addr; }
dyn += sizeof(struct NODEINFO_IPV4_SOCKET_META);
struct NODEINFO_IPV4_ADDR* addr = (struct NODEINFO_IPV4_ADDR*)dyn;
addr->addr[0] = a; addr->addr[1] = b; addr->addr[2] = c; addr->addr[3] = d;
addr->port = port; addr->type = ADDR_TYPE_INTERFACE; addr->socket_id = 0;
return nq; return nq;
} }

24
tests/test_etcp_router_reconnect.c

@ -80,22 +80,16 @@ static void gen_payload(uint32_t seq, uint8_t* buf, int len) {
static struct NODEINFO_Q* mknode(uint64_t nid, const uint8_t pubkey[32], static struct NODEINFO_Q* mknode(uint64_t nid, const uint8_t pubkey[32],
uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port) { uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port) {
size_t extra = sizeof(struct NODEINFO_IPV4_SOCKET_META) + sizeof(struct NODEINFO_IPV4_ADDR); struct NODEINFO_Q* nq = u_calloc(1, sizeof(struct NODEINFO_Q));
size_t data_sz = sizeof(struct NODEINFO_Q) - sizeof(struct ll_entry) + extra; struct NODEINFO* ni = u_calloc(1, sizeof(struct NODEINFO));
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)queue_entry_new(data_sz); if (!nq || !ni) { u_free(nq); u_free(ni); return NULL; }
if (!nq) return NULL; ni->ref_count = 1; ni->node_id = nid; ni->ver = 0;
struct NODEINFO* ni = &nq->node;
ni->node_id = nid; ni->ver = 0;
memcpy(ni->public_key, pubkey, SC_PUBKEY_SIZE); memcpy(ni->public_key, pubkey, SC_PUBKEY_SIZE);
ni->local_v4_sockets = 1; nq->node = ni; nq->hash_node_id = nid;
ni->local_v4_addrs = 1; struct NI_IPV4_SOCKET_META* sm = u_calloc(1, sizeof(struct NI_IPV4_SOCKET_META));
uint8_t* dyn = (uint8_t*)(ni + 1); if (sm) { sm->id = 0; sm->config_type = CFG_SERVER_TYPE_PUBLIC; sm->nat_type = NAT_TYPE_UNKNOWN; sm->next = ni->v4_sock_meta; ni->v4_sock_meta = sm; }
struct NODEINFO_IPV4_SOCKET_META* meta = (struct NODEINFO_IPV4_SOCKET_META*)dyn; struct NI_IPV4_ADDR* addr = u_calloc(1, sizeof(struct NI_IPV4_ADDR));
meta->id = 0; meta->config_type = CFG_SERVER_TYPE_PUBLIC; meta->nat_type = NAT_TYPE_UNKNOWN; if (addr) { addr->addr[0] = a; addr->addr[1] = b; addr->addr[2] = c; addr->addr[3] = d; addr->port = port; addr->type = ADDR_TYPE_INTERFACE; addr->socket_id = 0; addr->next = ni->v4_addrs; ni->v4_addrs = addr; }
dyn += sizeof(struct NODEINFO_IPV4_SOCKET_META);
struct NODEINFO_IPV4_ADDR* addr = (struct NODEINFO_IPV4_ADDR*)dyn;
addr->addr[0] = a; addr->addr[1] = b; addr->addr[2] = c; addr->addr[3] = d;
addr->port = port; addr->type = ADDR_TYPE_INTERFACE; addr->socket_id = 0;
return nq; return nq;
} }

16
tests/test_etcp_router_unit.c

@ -144,16 +144,18 @@ static void setup_bgp_for_sign_test(struct UTUN_INSTANCE* inst, int with_ed25519
if (!bgp) { printf(" setup_bgp: u_calloc failed\n"); return; } if (!bgp) { printf(" setup_bgp: u_calloc failed\n"); return; }
bgp->instance = inst; bgp->instance = inst;
bgp->nodes = queue_new(inst->ua, BGP_NODES_HASH_SIZE, bgp->nodes = queue_new(inst->ua, BGP_NODES_HASH_SIZE,
offsetof(struct NODEINFO_Q, node.node_id) - sizeof(struct ll_entry), 8, "bgp_nodes_test"); offsetof(struct NODEINFO_Q, hash_node_id) - sizeof(struct ll_entry), 8, "bgp_nodes_test");
if (!bgp->nodes) { printf(" setup_bgp: queue_new failed\n"); u_free(bgp); return; } if (!bgp->nodes) { printf(" setup_bgp: queue_new failed\n"); u_free(bgp); return; }
inst->bgp = bgp; inst->bgp = bgp;
size_t dsize = sizeof(struct NODEINFO_Q) - sizeof(struct ll_entry); struct NODEINFO_Q* nq = u_calloc(1, sizeof(struct NODEINFO_Q));
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)queue_entry_new(dsize); if (!nq) { printf(" setup_bgp: nq alloc failed\n"); return; }
if (!nq) { printf(" setup_bgp: queue_entry_new failed\n"); return; } nq->ll.size = sizeof(struct NODEINFO_Q) - sizeof(struct ll_entry);
memset(&nq->node, 0, sizeof(nq->node)); struct NODEINFO* ni = u_calloc(1, sizeof(struct NODEINFO));
nq->node.node_id = SIGNER_NODE; if (!ni) { printf(" setup_bgp: ni alloc failed\n"); u_free(nq); return; }
if (with_ed25519_key) memcpy(nq->node.ed25519_public_key, g_sign_ed25519_pubkey, SC_PUBKEY_SIZE); ni->ref_count = 1; ni->node_id = SIGNER_NODE;
if (with_ed25519_key) memcpy(ni->ed25519_public_key, g_sign_ed25519_pubkey, SC_PUBKEY_SIZE);
nq->node = ni; nq->hash_node_id = ni->node_id;
queue_data_put_with_index(bgp->nodes, &nq->ll); queue_data_put_with_index(bgp->nodes, &nq->ll);
} }

131
tests/test_ipv6_sockets.c

@ -136,119 +136,74 @@ static int is_connection_established(struct UTUN_INSTANCE* inst) {
static int verify_ipv6_local_nodeinfo(const char* name, struct UTUN_INSTANCE* inst, static int verify_ipv6_local_nodeinfo(const char* name, struct UTUN_INSTANCE* inst,
int expect_socks, int expect_addrs, int expect_subnets) { int expect_socks, int expect_addrs, int expect_subnets) {
if (!inst || !inst->bgp || !inst->bgp->local_node) { if (!inst || !inst->bgp || !inst->bgp->local_node || !inst->bgp->local_node->node) {
printf("FAIL [%s]: no bgp/local_node\n", name); printf("FAIL [%s]: no bgp/local_node\n", name);
return 0; return 0;
} }
struct NODEINFO* ni = &inst->bgp->local_node->node; struct NODEINFO* ni = inst->bgp->local_node->node;
struct ETCP_SOCKET* es = inst->etcp_sockets; struct ETCP_SOCKET* es = inst->etcp_sockets;
// Check socket family
int v6_sock_found = 0; int v6_sock_found = 0;
while (es) { while (es) { if (es->local_addr.ss_family == AF_INET6) { v6_sock_found = 1; break; } es = es->next; }
if (es->local_addr.ss_family == AF_INET6) { v6_sock_found = 1; break; }
es = es->next;
}
if (!v6_sock_found) { printf("FAIL [%s]: no AF_INET6 socket\n", name); return 0; } if (!v6_sock_found) { printf("FAIL [%s]: no AF_INET6 socket\n", name); return 0; }
printf("PASS [%s]: AF_INET6 socket exists\n", name); printf("PASS [%s]: AF_INET6 socket exists\n", name);
// Check nodeinfo counts int v6s = ni_list_count((struct _ni_head*)ni->v6_sock_meta);
if ((int)ni->local_v6_sockets != expect_socks) { if (v6s != expect_socks) { printf("FAIL [%s]: v6_socks=%d expected=%d\n", name, v6s, expect_socks); return 0; }
printf("FAIL [%s]: local_v6_sockets=%d expected=%d\n", name, ni->local_v6_sockets, expect_socks); return 0; printf("PASS [%s]: v6_sockets=%d\n", name, v6s);
}
printf("PASS [%s]: local_v6_sockets=%d\n", name, ni->local_v6_sockets);
if ((int)ni->local_v6_addrs != expect_addrs) { int v6a = ni_list_count((struct _ni_head*)ni->v6_addrs);
printf("FAIL [%s]: local_v6_addrs=%d expected=%d\n", name, ni->local_v6_addrs, expect_addrs); return 0; if (v6a != expect_addrs) { printf("FAIL [%s]: v6_addrs=%d expected=%d\n", name, v6a, expect_addrs); return 0; }
} printf("PASS [%s]: v6_addrs=%d\n", name, v6a);
printf("PASS [%s]: local_v6_addrs=%d\n", name, ni->local_v6_addrs);
if ((int)ni->local_v6_subnets != expect_subnets) { int v6sub = inst->bgp->local_node->routes ? ni_list_count((struct _ni_head*)inst->bgp->local_node->routes->v6_subnets) : 0;
printf("FAIL [%s]: local_v6_subnets=%d expected=%d\n", name, ni->local_v6_subnets, expect_subnets); return 0; if (v6sub != expect_subnets) { printf("FAIL [%s]: v6_subnets=%d expected=%d\n", name, v6sub, expect_subnets); return 0; }
} printf("PASS [%s]: v6_subnets=%d\n", name, v6sub);
printf("PASS [%s]: local_v6_subnets=%d\n", name, ni->local_v6_subnets);
// Verify socket meta
const struct NODEINFO_IPV6_SOCKET_META* meta;
int mc = get_node_v6_sockets_meta(inst->bgp->local_node, &meta);
if (mc != expect_socks || !meta) { printf("FAIL [%s]: v6 sockets meta retrieval failed\n", name); return 0; }
for (int i = 0; i < mc; i++) {
if (meta[i].config_type != CFG_SERVER_TYPE_PUBLIC) {
printf("FAIL [%s]: v6 socket meta[%d] config_type=%d expected=%d\n", name, i, meta[i].config_type, CFG_SERVER_TYPE_PUBLIC); return 0;
}
printf("PASS [%s]: v6 socket meta[%d] id=%d config=%d nat=%d\n", name, i, meta[i].id, meta[i].config_type, meta[i].nat_type);
}
// Verify IPv6 addresses { const struct NI_IPV6_SOCKET_META* m = ni->v6_sock_meta; int i = 0;
const struct NODEINFO_IPV6_ADDR* addrs; while (m) {
int ac = get_node_v6_addrs(inst->bgp->local_node, &addrs); if (m->config_type != CFG_SERVER_TYPE_PUBLIC) { printf("FAIL [%s]: v6 socket meta[%d] config_type=%d expected=%d\n", name, i, m->config_type, CFG_SERVER_TYPE_PUBLIC); return 0; }
if (ac != expect_addrs || !addrs) { printf("FAIL [%s]: v6 addrs retrieval failed\n", name); return 0; } printf("PASS [%s]: v6 socket meta[%d] id=%d config=%d nat=%d\n", name, i, m->id, m->config_type, m->nat_type);
for (int i = 0; i < ac; i++) { i++; m = m->next;
if (addrs[i].port == 0) { printf("FAIL [%s]: v6 addr port=0\n", name); return 0; } }
if (addrs[i].type != ADDR_TYPE_INTERFACE) {
printf("FAIL [%s]: v6 addr[%d] type=%d expected=%d(INTERFACE)\n", name, i, addrs[i].type, ADDR_TYPE_INTERFACE); return 0;
}
if (addrs[i].type != ADDR_TYPE_INTERFACE) {
printf("FAIL [%s]: v6 addr[%d] type=%d expected=%d(INTERFACE)\n", name, i, addrs[i].type, ADDR_TYPE_INTERFACE); return 0;
}
printf("PASS [%s]: v6 addr[%d] port=%d type=%d socket_id=%d\n", name, i, addrs[i].port, addrs[i].type, addrs[i].socket_id);
} }
{ const struct NI_IPV6_ADDR* a = ni->v6_addrs; int i = 0;
// Verify IPv6 subnets while (a) {
if (expect_subnets > 0) { if (a->port == 0) { printf("FAIL [%s]: v6 addr port=0\n", name); return 0; }
const struct NODEINFO_IPV6_SUBNET* subs; if (a->type != ADDR_TYPE_INTERFACE) { printf("FAIL [%s]: v6 addr[%d] type=%d expected=%d(INTERFACE)\n", name, i, a->type, ADDR_TYPE_INTERFACE); return 0; }
const uint8_t* dyn_start = (const uint8_t*)ni + sizeof(struct NODEINFO); printf("PASS [%s]: v6 addr[%d] port=%d type=%d socket_id=%d\n", name, i, a->port, a->type, a->socket_id);
const uint8_t* p = dyn_start + ni->node_name_len; i++; a = a->next;
p += ni->local_v4_sockets * sizeof(struct NODEINFO_IPV4_SOCKET_META); }
p += ni->local_v4_addrs * sizeof(struct NODEINFO_IPV4_ADDR); }
p += ni->local_v6_sockets * sizeof(struct NODEINFO_IPV6_SOCKET_META); if (expect_subnets > 0 && inst->bgp->local_node->routes) {
p += ni->local_v6_addrs * sizeof(struct NODEINFO_IPV6_ADDR); const struct NI_IPV6_SUBNET* subs = inst->bgp->local_node->routes->v6_subnets;
p += ni->local_v4_subnets * sizeof(struct NODEINFO_IPV4_SUBNET); if (subs) {
subs = (const struct NODEINFO_IPV6_SUBNET*)p; uint8_t expected_sub[16] = {0x20,0x01,0x0d,0xb8,0x00,0x01,0,0,0,0,0,0,0,0,0,0};
uint8_t expected_sub[16] = {0x20,0x01,0x0d,0xb8,0x00,0x01,0,0,0,0,0,0,0,0,0,0}; if (memcmp(subs->addr, expected_sub, 16) != 0) { printf("FAIL [%s]: v6 subnet != 2001:db8:1::/48\n", name); return 0; }
if (memcmp(subs[0].addr, expected_sub, 16) != 0) { if (subs->prefix_length != 48) { printf("FAIL [%s]: v6 subnet prefix=%d expected=48\n", name, subs->prefix_length); return 0; }
printf("FAIL [%s]: v6 subnet != 2001:db8:1::/48\n", name); return 0; printf("PASS [%s]: v6 subnet 2001:db8:1::/48\n", name);
}
if (subs[0].prefix_length != 48) {
printf("FAIL [%s]: v6 subnet prefix=%d expected=48\n", name, subs[0].prefix_length); return 0;
} }
printf("PASS [%s]: v6 subnet 2001:db8:1::/48\n", name);
} }
return 1; return 1;
} }
static int verify_remote_v6_nodeinfo(const char* name, struct UTUN_INSTANCE* inst, uint64_t peer_node_id) { static int verify_remote_v6_nodeinfo(const char* name, struct UTUN_INSTANCE* inst, uint64_t peer_node_id) {
if (!inst || !inst->bgp) { if (!inst || !inst->bgp) { printf("FAIL [%s]: no bgp\n", name); return 0; }
printf("FAIL [%s]: no bgp\n", name);
return 0;
}
struct NODEINFO_Q* nq = nodeinfo_find_by_id(inst->bgp, peer_node_id); struct NODEINFO_Q* nq = nodeinfo_find_by_id(inst->bgp, peer_node_id);
if (!nq) { if (!nq || !nq->node) { printf("FAIL [%s]: remote node %016llx not found\n", name, (unsigned long long)peer_node_id); return 0; }
printf("FAIL [%s]: remote node %016llx not found\n", name, (unsigned long long)peer_node_id);
return 0;
}
printf("PASS [%s]: remote node %016llx found\n", name, (unsigned long long)peer_node_id); printf("PASS [%s]: remote node %016llx found\n", name, (unsigned long long)peer_node_id);
if (nq->node.local_v6_sockets == 0) { if (!nq->node->v6_sock_meta) { printf("FAIL [%s]: remote node has no v6 sockets\n", name); return 0; }
printf("FAIL [%s]: remote node has no v6 sockets\n", name); printf("PASS [%s]: remote node v6_sockets=%d\n", name, ni_list_count((struct _ni_head*)nq->node->v6_sock_meta));
return 0;
}
printf("PASS [%s]: remote node v6_sockets=%d\n", name, nq->node.local_v6_sockets);
if (nq->node.local_v6_addrs == 0) { if (!nq->node->v6_addrs) { printf("FAIL [%s]: remote node has no v6 addrs\n", name); return 0; }
printf("FAIL [%s]: remote node has no v6 addrs\n", name); printf("PASS [%s]: remote node v6_addrs=%d\n", name, ni_list_count((struct _ni_head*)nq->node->v6_addrs));
return 0;
}
printf("PASS [%s]: remote node v6_addrs=%d\n", name, nq->node.local_v6_addrs);
const struct NODEINFO_IPV6_ADDR* addrs; const struct NI_IPV6_ADDR* a = nq->node->v6_addrs;
int ac = get_node_v6_addrs(nq, &addrs); if (a) {
if (ac > 0 && addrs) {
uint8_t loopback[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; uint8_t loopback[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
if (memcmp(addrs[0].addr, loopback, 16) != 0) if (memcmp(a->addr, loopback, 16) != 0) { printf("FAIL [%s]: remote v6 addr not ::1\n", name); return 0; }
{ printf("FAIL [%s]: remote v6 addr not ::1\n", name); return 0; } printf("PASS [%s]: remote v6 addr verified ::1 port=%d\n", name, a->port);
printf("PASS [%s]: remote v6 addr verified ::1 port=%d\n", name, addrs[0].port);
} }
return 1; return 1;
} }

56
tests/test_nat_detection.c

@ -361,45 +361,32 @@ int main(void) {
} }
// Verify local_node socket update on C1 (received NAT_INFO updated nodeinfo) // Verify local_node socket update on C1 (received NAT_INFO updated nodeinfo)
if (inst_c1->bgp && inst_c1->bgp->local_node) { if (inst_c1->bgp && inst_c1->bgp->local_node && inst_c1->bgp->local_node->node) {
const struct NODEINFO_IPV4_SOCKET_META* meta = NULL;
int meta_count = get_node_v4_sockets_meta(inst_c1->bgp->local_node, &meta);
int found = 0; int found = 0;
for (int i = 0; i < meta_count; i++) { for (const struct NI_IPV4_SOCKET_META* m = inst_c1->bgp->local_node->node->v4_sock_meta; m; m = m->next) {
if (meta[i].id == sock_c1->sock_id) { if (m->id == sock_c1->sock_id) {
if (meta[i].nat_type != NAT_VERIFIED_EIM) { if (m->nat_type != NAT_VERIFIED_EIM) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: local_node socket meta not updated on C1: nat_type=%u expected=%u", DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: local_node socket meta not updated on C1: nat_type=%u expected=%u", m->nat_type, NAT_VERIFIED_EIM);
meta[i].nat_type, NAT_VERIFIED_EIM);
goto cleanup; goto cleanup;
} }
found = 1; found = 1; break;
break;
} }
} }
if (!found) { if (!found) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: socket not found in local_node meta on C1"); goto cleanup; }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: socket not found in local_node meta on C1");
goto cleanup;
}
// Verify NAT addr in flat address list // Verify NAT addr in flat address list
const struct NODEINFO_IPV4_ADDR* addrs = NULL;
int addr_count = get_node_v4_addrs(inst_c1->bgp->local_node, &addrs);
int nat_found = 0; int nat_found = 0;
for (int i = 0; i < addr_count; i++) { for (const struct NI_IPV4_ADDR* a = inst_c1->bgp->local_node->node->v4_addrs; a; a = a->next) {
if (addrs[i].type == ADDR_TYPE_NAT && addrs[i].socket_id == sock_c1->sock_id) { if (a->type == ADDR_TYPE_NAT && a->socket_id == sock_c1->sock_id) {
uint32_t addr_ip; memcpy(&addr_ip, addrs[i].addr, 4); uint32_t addr_ip; memcpy(&addr_ip, a->addr, 4);
if (addr_ip != link_sc1->nat_ip || addrs[i].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",
addr_ip, link_sc1->nat_ip, addrs[i].port, link_sc1->nat_port); addr_ip, link_sc1->nat_ip, a->port, link_sc1->nat_port);
goto cleanup; goto cleanup;
} }
nat_found = 1; nat_found = 1; break;
break;
} }
} }
if (!nat_found) { if (!nat_found) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: NAT addr not found in local_node flat addr list on C1"); goto cleanup; }
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: NAT addr not found in local_node flat addr list on C1");
goto cleanup;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "local_node meta+addr check PASSED on C1"); DEBUG_INFO(DEBUG_CATEGORY_BGP, "local_node meta+addr check PASSED on C1");
} }
@ -409,14 +396,9 @@ int main(void) {
int c2_verified_nat = 0; int c2_verified_nat = 0;
while (!test_timed_out && bgp_wait_cycles < 500) { while (!test_timed_out && bgp_wait_cycles < 500) {
struct NODEINFO_Q* node_c1_on_c2 = inst_c2->bgp ? nodeinfo_find_by_id(inst_c2->bgp, NODE_ID_C1) : NULL; struct NODEINFO_Q* node_c1_on_c2 = inst_c2->bgp ? nodeinfo_find_by_id(inst_c2->bgp, NODE_ID_C1) : NULL;
if (node_c1_on_c2) { if (node_c1_on_c2 && node_c1_on_c2->node) {
const struct NODEINFO_IPV4_SOCKET_META* meta = NULL; for (const struct NI_IPV4_SOCKET_META* m = node_c1_on_c2->node->v4_sock_meta; m; m = m->next) {
int meta_count = get_node_v4_sockets_meta(node_c1_on_c2, &meta); if (m->nat_type == NAT_VERIFIED_EIM) { c2_verified_nat = 1; break; }
for (int i = 0; i < meta_count; i++) {
if (meta[i].nat_type == NAT_VERIFIED_EIM) {
c2_verified_nat = 1;
break;
}
} }
if (c2_verified_nat) break; if (c2_verified_nat) break;
} }
@ -450,7 +432,7 @@ int main(void) {
int ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2, int ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2,
target_ip_net, link_sc1->nat_port, target_ip_net, link_sc1->nat_port,
3, 10, 200, 3000, nat_ping_resp_cb, NULL, 3, 10, 200, 3000, nat_ping_resp_cb, NULL,
node_c1->node.public_key); node_c1->node->public_key);
if (ret != 0) { if (ret != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr failed: %d", ret); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr failed: %d", ret);
goto cleanup; goto cleanup;
@ -498,7 +480,7 @@ int main(void) {
ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2, ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2,
target_ip_net, link_sc1->nat_port, target_ip_net, link_sc1->nat_port,
3, 10, 200, 3000, nat_ping_resp_cb, NULL, 3, 10, 200, 3000, nat_ping_resp_cb, NULL,
node_c1->node.public_key); node_c1->node->public_key);
if (ret != 0) { if (ret != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr (no pubkey) failed: %d", ret); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr (no pubkey) failed: %d", ret);
goto cleanup; goto cleanup;

38
tests/test_route6_lib.c

@ -22,20 +22,36 @@ static int tests_run = 0;
static struct NODEINFO_Q *make_node(uint64_t node_id, static struct NODEINFO_Q *make_node(uint64_t node_id,
const uint8_t addrs[][16], const uint8_t addrs[][16],
const uint8_t *plens, int N) { const uint8_t *plens, int N) {
size_t dyn = N * sizeof(struct NODEINFO_IPV6_SUBNET); struct NODEINFO_Q *nq = u_calloc(1, sizeof(*nq));
struct NODEINFO_Q *nq = u_calloc(1, sizeof(*nq) + dyn); struct NODEINFO *ni = u_calloc(1, sizeof(struct NODEINFO));
nq->node.node_id = node_id; if (!nq || !ni) { u_free(nq); u_free(ni); return NULL; }
nq->node.local_v6_subnets = (uint8_t)N; ni->ref_count = 1; ni->node_id = node_id;
struct NODEINFO_IPV6_SUBNET *subs = nq->node = ni; nq->hash_node_id = node_id;
(struct NODEINFO_IPV6_SUBNET *)((uint8_t *)&nq->node + sizeof(struct NODEINFO)); if (N > 0) {
for (int i = 0; i < N; i++) { struct NODEINFO_ROUTES *r = u_calloc(1, sizeof(struct NODEINFO_ROUTES));
memcpy(subs[i].addr, addrs[i], 16); nq->routes = r;
subs[i].prefix_length = plens[i]; struct NI_IPV6_SUBNET *head = NULL;
for (int i = N-1; i >= 0; i--) {
struct NI_IPV6_SUBNET *s = u_calloc(1, sizeof(struct NI_IPV6_SUBNET));
memcpy(s->addr, addrs[i], 16); s->prefix_length = plens[i];
s->next = head; head = s;
}
r->v6_subnets = head;
} }
return nq; return nq;
} }
static void free_node(struct NODEINFO_Q *nq) { u_free(nq); } static void free_node(struct NODEINFO_Q *nq) {
if (nq) {
if (nq->routes) {
struct NI_IPV6_SUBNET *s = nq->routes->v6_subnets;
while (s) { struct NI_IPV6_SUBNET *next = s->next; u_free(s); s = next; }
u_free(nq->routes);
}
if (nq->node) u_free(nq->node);
u_free(nq);
}
}
static void make_key(uint8_t out[17], const uint8_t addr[16]) { static void make_key(uint8_t out[17], const uint8_t addr[16]) {
out[0] = 17; memcpy(out + 1, addr, 16); out[0] = 17; memcpy(out + 1, addr, 16);
@ -317,7 +333,7 @@ static void test_stress(void) {
if (rand() % 10 < 6 && n_created > 0) { if (rand() % 10 < 6 && n_created > 0) {
// delete random active node // delete random active node
int idx = rand() % n_created; int idx = rand() % n_created;
uint64_t nid = nodes[idx]->node.node_id; uint64_t nid = nodes[idx]->node->node_id;
route6_delete(t, nodes[idx]); route6_delete(t, nodes[idx]);
// mark all routes of this node inactive // mark all routes of this node inactive
for (int j = 0; j < nsr; j++) { for (int j = 0; j < nsr; j++) {

39
tests/test_route_lib.c

@ -40,34 +40,35 @@ struct UTUN_INSTANCE {
struct ROUTE_BGP* bgp; struct ROUTE_BGP* bgp;
}; };
/* Helper to create test NODEINFO_Q with subnet in dynamic section */ /* Helper to create test NODEINFO_Q with subnet in linked list */
static struct NODEINFO_Q* create_test_node(uint64_t node_id, uint8_t ver, uint32_t subnet_net, uint8_t prefix) { static struct NODEINFO_Q* create_test_node(uint64_t node_id, uint8_t ver, uint32_t subnet_net, uint8_t prefix) {
/* Allocate fixed + dynamic for 1 subnet (no name, no sockets) */ struct NODEINFO_Q* nq = u_calloc(1, sizeof(struct NODEINFO_Q));
size_t dyn_size = sizeof(struct NODEINFO_IPV4_SUBNET);
struct NODEINFO_Q* nq = u_calloc(1, sizeof(struct NODEINFO_Q) + dyn_size);
if (!nq) return NULL; if (!nq) return NULL;
nq->node.node_id = htobe64(node_id); struct NODEINFO* ni = u_calloc(1, sizeof(struct NODEINFO));
nq->node.ver = ver; if (!ni) { u_free(nq); return NULL; }
nq->node.node_name_len = 0; ni->ref_count = 1;
nq->node.local_v4_sockets = 0; ni->node_id = htobe64(node_id);
nq->node.local_v6_sockets = 0; ni->ver = ver;
nq->node.local_v4_subnets = 1; nq->node = ni;
nq->node.local_v6_subnets = 0; nq->hash_node_id = ni->node_id;
nq->node.tranzit_nodes = 0; nq->hop_count = 0;
nq->node.hop_count = 0;
nq->paths = queue_new(NULL, 16, 0, 0, "test_paths"); nq->paths = queue_new(NULL, 16, 0, 0, "test_paths");
/* Fill subnet after fixed header (after name_len=0, sockets=0) */ struct NODEINFO_ROUTES* r = u_calloc(1, sizeof(struct NODEINFO_ROUTES));
uint8_t *dyn = (uint8_t *)&nq->node + sizeof(struct NODEINFO); if (r) {
struct NODEINFO_IPV4_SUBNET *sn = (struct NODEINFO_IPV4_SUBNET *)dyn; struct NI_IPV4_SUBNET* sn = u_calloc(1, sizeof(struct NI_IPV4_SUBNET));
uint32_t net = htonl(subnet_net); uint32_t net = htonl(subnet_net);
memcpy(sn->addr, &net, 4); memcpy(sn->addr, &net, 4); sn->prefix_length = prefix;
sn->prefix_length = prefix; r->v4_subnets = sn;
nq->routes = r;
}
return nq; return nq;
} }
static void free_test_node(struct NODEINFO_Q* nq) { static void free_test_node(struct NODEINFO_Q* nq) {
if (nq) { if (nq) {
if (nq->paths) queue_free(nq->paths); if (nq->paths) queue_free(nq->paths);
if (nq->routes) { u_free(nq->routes->v4_subnets); u_free(nq->routes); }
if (nq->node) { u_free(nq->node->node_name); u_free(nq->node); }
u_free(nq); u_free(nq);
} }
} }

13
tests/test_route_ping.c

@ -272,12 +272,11 @@ int main(void) {
uint32_t target_ip = 0; uint32_t target_ip = 0;
uint16_t target_port = 0; uint16_t target_port = 0;
struct NODEINFO_Q* nq = inst_b->bgp ? nodeinfo_find_by_id(inst_b->bgp, NODE_ID_C) : NULL; struct NODEINFO_Q* nq = inst_b->bgp ? nodeinfo_find_by_id(inst_b->bgp, NODE_ID_C) : NULL;
if (nq) { if (nq && nq->node) {
const struct NODEINFO_IPV4_ADDR* addrs; const struct NI_IPV4_ADDR* a = nq->node->v4_addrs;
int sc = get_node_v4_addrs(nq, &addrs); if (a) {
if (sc > 0) { memcpy(&target_ip, a->addr, 4);
memcpy(&target_ip, addrs[0].addr, 4); /* network byte order */ target_port = a->port;
target_port = addrs[0].port; /* host byte order */
} }
} }
if (target_ip == 0 || target_port == 0) { if (target_ip == 0 || target_port == 0) {
@ -294,7 +293,7 @@ int main(void) {
200, // timeout_ms 200, // timeout_ms
5000,// wait_timeout_ms 5000,// wait_timeout_ms
ping_resp_cb, NULL, ping_resp_cb, NULL,
nq ? nq->node.public_key : NULL); nq ? nq->node->public_key : NULL);
if (ret != 0) { if (ret != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr failed: %d", ret); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr failed: %d", ret);
goto cleanup; goto cleanup;

Loading…
Cancel
Save