You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
986 lines
54 KiB
986 lines
54 KiB
#include <stdlib.h> |
|
#include <string.h> |
|
#include <stdint.h> |
|
|
|
#include "../lib/ll_queue.h" |
|
#include "../lib/debug_config.h" |
|
#include "../lib/mem.h" |
|
#include "../lib/memory_pool.h" |
|
#include "utun_instance.h" |
|
#include "etcp.h" |
|
#include "config_parser.h" |
|
#include "topo_node.h" |
|
#include "topo_group.h" |
|
#include "route_lib.h" |
|
#include "etcp_debug.h" |
|
#include "topo_node_sqlite.h" |
|
#include "../transport_layer/etcp_connections.h" |
|
#include "../lib/u_async.h" |
|
|
|
void topo_node_ref(struct TOPO_NODE* ni) { |
|
if (!ni) return; |
|
ni->group_ref_count++; |
|
} |
|
|
|
void topo_node_registry_ref(struct TOPO_GROUPS* groups, uint64_t node_id) { |
|
struct TOPO_NODE* ni = topo_node_registry_find(groups, node_id); |
|
if (ni) ni->group_ref_count++; |
|
} |
|
|
|
void topo_node_unref(struct TOPO_NODE* ni) { |
|
if (!ni) return; |
|
if (--ni->group_ref_count == 0) { |
|
u_free(ni->node_name); |
|
u_free(ni); |
|
} |
|
} |
|
|
|
static void free_v4_sock_list(struct memory_pool* pool, struct TOPO_SOCKMETA4* head) { |
|
while (head) { struct TOPO_SOCKMETA4* next = head->next; memory_pool_free(pool, head); head = next; } |
|
} |
|
static void free_v4_addr_list(struct memory_pool* pool, struct TOPO_ADDR4* head) { |
|
while (head) { struct TOPO_ADDR4* next = head->next; memory_pool_free(pool, head); head = next; } |
|
} |
|
static void free_v6_sock_list(struct memory_pool* pool, struct TOPO_SOCKMETA6* head) { |
|
while (head) { struct TOPO_SOCKMETA6* next = head->next; memory_pool_free(pool, head); head = next; } |
|
} |
|
static void free_v6_addr_list(struct memory_pool* pool, struct TOPO_ADDR6* head) { |
|
while (head) { struct TOPO_ADDR6* next = head->next; memory_pool_free(pool, head); head = next; } |
|
} |
|
static void free_v4_sub_list(struct memory_pool* pool, struct TOPO_SUBNET4* head) { |
|
while (head) { struct TOPO_SUBNET4* next = head->next; memory_pool_free(pool, head); head = next; } |
|
} |
|
static void free_v6_sub_list(struct memory_pool* pool, struct TOPO_SUBNET6* head) { |
|
while (head) { struct TOPO_SUBNET6* next = head->next; memory_pool_free(pool, head); head = next; } |
|
} |
|
|
|
/* извлекает hop_list из лучшего живого path в nq->paths (или любого, если живых нет). |
|
память принадлежит TOPO_NODEPATH в paths, не освобождать */ |
|
uint64_t* topo_node_best_hop_list(struct TOPO_GROUP_NODE* nq, uint8_t* out_count, uint16_t* out_rtt) { |
|
if (!nq || !nq->paths || !nq->paths->head) { *out_count = 0; if (out_rtt) *out_rtt = 0; return NULL; } |
|
struct TOPO_NODEPATH* best = NULL; uint8_t min_hops = 255; |
|
struct ll_entry* e = nq->paths->head; |
|
while (e) { struct TOPO_NODEPATH* p = (struct TOPO_NODEPATH*)e; if (p->conn && p->conn->links_up && p->hop_count < min_hops) { best = p; min_hops = p->hop_count; } e = e->next; } |
|
if (!best) best = (struct TOPO_NODEPATH*)nq->paths->head; |
|
*out_count = best->hop_count; |
|
if (out_rtt) *out_rtt = best->cumulative_rtt; |
|
return (uint64_t*)((uint8_t*)best + sizeof(struct TOPO_NODEPATH)); |
|
} |
|
|
|
void topo_node_free_raw(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) { |
|
if (!ni) return; |
|
if (groups) { |
|
free_v4_sock_list(groups->v4_sock_meta_pool, ni->v4_sock_meta); |
|
free_v4_addr_list(groups->v4_addr_pool, ni->v4_addrs); |
|
free_v6_sock_list(groups->v6_sock_meta_pool, ni->v6_sock_meta); |
|
free_v6_addr_list(groups->v6_addr_pool, ni->v6_addrs); |
|
} |
|
u_free(ni->node_name); |
|
u_free(ni); |
|
} |
|
|
|
void topo_node_destroy(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) { |
|
topo_node_free_raw(groups, ni); |
|
} |
|
|
|
void topo_nodeq_free_group_fields(struct TOPO_GROUPS* groups, struct TOPO_GROUP_NODE* nq) { |
|
if (!groups || !nq) return; |
|
struct TOPO_NODE* ni = topo_node_registry_find(groups, nq->node_id); |
|
if (ni) { |
|
free_v4_sock_list(groups->v4_sock_meta_pool, ni->v4_sock_meta); |
|
free_v4_addr_list(groups->v4_addr_pool, ni->v4_addrs); |
|
free_v6_sock_list(groups->v6_sock_meta_pool, ni->v6_sock_meta); |
|
free_v6_addr_list(groups->v6_addr_pool, ni->v6_addrs); |
|
ni->v4_sock_meta = NULL; ni->v4_addrs = NULL; |
|
ni->v6_sock_meta = NULL; ni->v6_addrs = NULL; |
|
topo_node_registry_unref(groups, nq->node_id); |
|
} |
|
if (nq->subnets) { |
|
free_v4_sub_list(groups->v4_subnet_pool, nq->subnets->v4_subnets); |
|
free_v6_sub_list(groups->v6_subnet_pool, nq->subnets->v6_subnets); |
|
u_free(nq->subnets); |
|
nq->subnets = NULL; |
|
} |
|
nq->handle = NULL; |
|
} |
|
|
|
// ===== глобальный реестр TOPO_NODE ===== |
|
|
|
struct TOPO_NODE* topo_node_registry_find(struct TOPO_GROUPS* groups, uint64_t node_id) { |
|
if (!groups || !groups->node_registry) return NULL; |
|
struct ll_entry* e = queue_find_data_by_index(groups->node_registry, &node_id); |
|
if (!e) return NULL; |
|
struct TOPO_NODE* node; |
|
memcpy(&node, e->data + 8, sizeof(node)); |
|
return node; |
|
} |
|
|
|
struct TOPO_NODE* topo_node_registry_store(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) { |
|
if (!groups || !ni) return NULL; |
|
struct TOPO_NODE* existing = topo_node_registry_find(groups, ni->node_id); |
|
if (existing) { |
|
int n4 = topo_list_count((struct _topo_head*)ni->v4_addrs); |
|
int n6 = topo_list_count((struct _topo_head*)ni->v6_addrs); |
|
int e4 = topo_list_count((struct _topo_head*)existing->v4_addrs); |
|
int e6 = topo_list_count((struct _topo_head*)existing->v6_addrs); |
|
int drop4 = (e4 && n4), drop6 = (e6 && n6); |
|
if (drop4 || drop6) |
|
DEBUG_WARN(DEBUG_CATEGORY_BGP, "registry_store: node=%016llx EXISTS — dropping new addrs v4=%d v6=%d (existing v4=%d v6=%d)", |
|
(unsigned long long)ni->node_id, drop4 ? n4 : 0, drop6 ? n6 : 0, e4, e6); |
|
topo_node_ref(existing); |
|
if (!existing->v4_addrs && ni->v4_addrs) { existing->v4_addrs = ni->v4_addrs; ni->v4_addrs = NULL; } |
|
if (!existing->v6_addrs && ni->v6_addrs) { existing->v6_addrs = ni->v6_addrs; ni->v6_addrs = NULL; } |
|
topo_node_free_raw(groups, ni); |
|
return existing; |
|
} |
|
struct ll_entry* qe = queue_entry_new(8 + sizeof(struct TOPO_NODE*)); |
|
if (!qe) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "registry_acquire: queue_entry_new failed for node=%016llx", (unsigned long long)ni->node_id); |
|
return NULL; |
|
} |
|
topo_node_ref(ni); |
|
memcpy(qe->data, &ni->node_id, 8); |
|
memcpy(qe->data + 8, &ni, sizeof(ni)); |
|
queue_data_put_with_index(groups->node_registry, qe); |
|
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "registry_store: node=%016llx NEW v4=%d v6=%d", |
|
(unsigned long long)ni->node_id, |
|
topo_list_count((struct _topo_head*)ni->v4_addrs), |
|
topo_list_count((struct _topo_head*)ni->v6_addrs)); |
|
return ni; |
|
} |
|
|
|
void topo_node_registry_unref(struct TOPO_GROUPS* groups, uint64_t node_id) { |
|
if (!groups) return; |
|
struct TOPO_NODE* ni = topo_node_registry_find(groups, node_id); |
|
if (!ni) return; |
|
uint32_t prev_ref = ni->group_ref_count; |
|
topo_node_unref(ni); |
|
if (prev_ref == 1) { |
|
struct ll_entry* e = groups->node_registry ? queue_find_data_by_index(groups->node_registry, &node_id) : NULL; |
|
if (e) { queue_remove_data(groups->node_registry, e); queue_entry_free(e); } |
|
} |
|
} |
|
|
|
// ===== serialization ===== |
|
|
|
int topo_node_build_sig_msg(struct TOPO_NODE* ni, uint8_t* buf, size_t buf_size) { |
|
if (!ni || !buf || buf_size < 64) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "build_sig_msg: invalid args"); return -1; } |
|
size_t off = 0; |
|
|
|
memcpy(buf + off, ni->public_key, SC_PUBKEY_SIZE); off += SC_PUBKEY_SIZE; |
|
|
|
size_t name_len = ni->node_name ? strlen(ni->node_name) : 0; |
|
if (name_len > 63) name_len = 63; |
|
if (off + name_len + 1 > buf_size) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "build_sig_msg: buf too small for name"); return -1; } |
|
if (name_len) { memcpy(buf + off, ni->node_name, name_len); off += name_len; } |
|
buf[off++] = '\0'; |
|
|
|
if (off + 2 > buf_size) return -1; |
|
buf[off++] = ni->client_type; |
|
buf[off++] = ni->client_activity; |
|
|
|
{ struct TOPO_SOCKMETA4* e = ni->v4_sock_meta; while (e) { |
|
if (off + 3 > buf_size) return -1; |
|
buf[off++] = e->id; buf[off++] = e->config_type; buf[off++] = e->nat_type; e = e->next; |
|
}} |
|
{ struct TOPO_ADDR4* e = ni->v4_addrs; while (e) { |
|
if (off + 9 > buf_size) return -1; |
|
memcpy(buf + off, e->addr, 4); off += 4; |
|
buf[off++] = (uint8_t)(e->port & 0xFF); buf[off++] = (uint8_t)((e->port >> 8) & 0xFF); |
|
buf[off++] = e->type; buf[off++] = e->socket_id; buf[off++] = e->protocol; e = e->next; |
|
}} |
|
{ struct TOPO_SOCKMETA6* e = ni->v6_sock_meta; while (e) { |
|
if (off + 3 > buf_size) return -1; |
|
buf[off++] = e->id; buf[off++] = e->config_type; buf[off++] = e->nat_type; e = e->next; |
|
}} |
|
{ struct TOPO_ADDR6* e = ni->v6_addrs; while (e) { |
|
if (off + 21 > buf_size) return -1; |
|
memcpy(buf + off, e->addr, 16); off += 16; |
|
buf[off++] = (uint8_t)(e->port & 0xFF); buf[off++] = (uint8_t)((e->port >> 8) & 0xFF); |
|
buf[off++] = e->type; buf[off++] = e->socket_id; buf[off++] = e->protocol; e = e->next; |
|
}} |
|
|
|
return (int)off; |
|
} |
|
|
|
void topo_node_sign_self(struct UTUN_INSTANCE* instance, struct TOPO_NODE* ni) { |
|
if (!instance || !ni) return; |
|
uint8_t sig_msg[TOPO_SIG_MSG_MAX_SIZE]; |
|
int sig_len = topo_node_build_sig_msg(ni, sig_msg, sizeof(sig_msg)); |
|
if (sig_len > 0 && sc_ed25519_sign(instance->my_ed25519_privkey, sig_msg, (size_t)sig_len, ni->x25519_self_sig) != SC_OK) |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Ed25519 self-sign FAILED for node=%016llx", (unsigned long long)ni->node_id); |
|
} |
|
|
|
int topo_node_dyn_size(const struct TOPOMSG_NODE* msg) { |
|
return msg->node_name_len |
|
+ msg->local_v4_sockets * sizeof(struct TOPOMSG_SOCKMETA4) |
|
+ msg->local_v4_addrs * sizeof(struct TOPOMSG_ADDR4) |
|
+ msg->local_v6_sockets * sizeof(struct TOPOMSG_SOCKMETA6) |
|
+ msg->local_v6_addrs * sizeof(struct TOPOMSG_ADDR6) |
|
+ ((msg->flags & TOPO_FLAG_SEND_SUBNETS) |
|
? (msg->local_v4_subnets * sizeof(struct TOPOMSG_SUBNET4) + msg->local_v6_subnets * sizeof(struct TOPOMSG_SUBNET6)) |
|
: 0) |
|
+ msg->hop_count * 8; |
|
} |
|
|
|
int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq, uint8_t* out, size_t out_max, uint16_t cumulative_rtt) { |
|
if (!ni || !nq || !out) return -1; |
|
|
|
struct TOPOMSG_NODE msg; |
|
memset(&msg, 0, sizeof(msg)); |
|
msg.flags = ni->flags; |
|
msg.group_id = ni->group_id; |
|
msg.node_id = ni->node_id; |
|
msg.ver = ni->ver; |
|
memcpy(msg.public_key, ni->public_key, SC_PUBKEY_SIZE); |
|
memcpy(msg.ed25519_public_key, ni->ed25519_public_key, SC_PUBKEY_SIZE); |
|
memcpy(msg.x25519_self_sig, ni->x25519_self_sig, 64); |
|
msg.node_name_len = ni->node_name ? (uint8_t)strlen(ni->node_name) : 0; |
|
msg.local_v4_sockets = topo_list_count((struct _topo_head*)ni->v4_sock_meta); |
|
msg.local_v4_addrs = topo_list_count((struct _topo_head*)ni->v4_addrs); |
|
msg.local_v6_sockets = topo_list_count((struct _topo_head*)ni->v6_sock_meta); |
|
msg.local_v6_addrs = topo_list_count((struct _topo_head*)ni->v6_addrs); |
|
msg.local_v4_subnets = nq->subnets ? topo_list_count((struct _topo_head*)nq->subnets->v4_subnets) : 0; |
|
msg.local_v6_subnets = nq->subnets ? topo_list_count((struct _topo_head*)nq->subnets->v6_subnets) : 0; |
|
{ uint8_t hc; uint64_t* hl = topo_node_best_hop_list(nq, &hc, NULL); |
|
msg.hop_count = hc; } |
|
msg.client_type = ni->client_type; |
|
msg.client_activity = ni->client_activity; |
|
msg.cumulative_rtt = cumulative_rtt; |
|
|
|
size_t total = TOPOMSG_NODE_HDR_SIZE + (size_t)topo_node_dyn_size(&msg); |
|
if (total > out_max) return -1; |
|
|
|
memcpy(out, &msg, TOPOMSG_NODE_HDR_SIZE); |
|
uint8_t* dp = out + TOPOMSG_NODE_HDR_SIZE; |
|
|
|
if (msg.node_name_len) { memcpy(dp, ni->node_name, msg.node_name_len); dp += msg.node_name_len; } |
|
|
|
{ struct TOPO_SOCKMETA4* e = ni->v4_sock_meta; while (e) { |
|
struct TOPOMSG_SOCKMETA4 w = { .id=e->id, .config_type=e->config_type, .nat_type=e->nat_type }; |
|
memcpy(dp, &w, sizeof(w)); dp += sizeof(w); e = e->next; |
|
}} |
|
{ struct TOPO_ADDR4* e = ni->v4_addrs; while (e) { |
|
struct TOPOMSG_ADDR4 w = { .port=e->port, .type=e->type, .socket_id=e->socket_id, .protocol=e->protocol }; |
|
memcpy(w.addr, e->addr, 4); memcpy(dp, &w, sizeof(w)); dp += sizeof(w); e = e->next; |
|
}} |
|
{ struct TOPO_SOCKMETA6* e = ni->v6_sock_meta; while (e) { |
|
struct TOPOMSG_SOCKMETA6 w = { .id=e->id, .config_type=e->config_type, .nat_type=e->nat_type }; |
|
memcpy(dp, &w, sizeof(w)); dp += sizeof(w); e = e->next; |
|
}} |
|
{ struct TOPO_ADDR6* e = ni->v6_addrs; while (e) { |
|
struct TOPOMSG_ADDR6 w = { .port=e->port, .type=e->type, .socket_id=e->socket_id, .protocol=e->protocol }; |
|
memcpy(w.addr, e->addr, 16); memcpy(dp, &w, sizeof(w)); dp += sizeof(w); e = e->next; |
|
}} |
|
if (msg.flags & TOPO_FLAG_SEND_SUBNETS) { |
|
if (nq->subnets) { |
|
{ struct TOPO_SUBNET4* e = nq->subnets->v4_subnets; while (e) { |
|
struct TOPOMSG_SUBNET4 w = { .prefix_length=e->prefix_length }; |
|
memcpy(w.addr, e->addr, 4); memcpy(dp, &w, sizeof(w)); dp += sizeof(w); e = e->next; |
|
}} |
|
{ struct TOPO_SUBNET6* e = nq->subnets->v6_subnets; while (e) { |
|
struct TOPOMSG_SUBNET6 w = { .prefix_length=e->prefix_length }; |
|
memcpy(w.addr, e->addr, 16); memcpy(dp, &w, sizeof(w)); dp += sizeof(w); e = e->next; |
|
}} |
|
} |
|
} |
|
{ uint8_t hc; uint64_t* hl = topo_node_best_hop_list(nq, &hc, NULL); |
|
if (hc && hl) { size_t sz = hc * 8; memcpy(dp, hl, sz); dp += sz; } } |
|
return (int)(dp - out); |
|
} |
|
|
|
// ===== deserialization ===== |
|
|
|
int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t len, struct TOPO_NODE** out_ni, struct TOPO_NODESUBNETS** out_subnets, |
|
uint64_t** out_hop_list, uint8_t* out_hop_count, |
|
uint16_t* out_cumulative_rtt) { |
|
if (!group || !data || len < TOPOMSG_NODE_HDR_SIZE || !out_ni) return -1; |
|
|
|
const struct TOPOMSG_NODE* msg = (const struct TOPOMSG_NODE*)data; |
|
int dyn = topo_node_dyn_size(msg); |
|
if ((size_t)dyn + TOPOMSG_NODE_HDR_SIZE != len) return -1; |
|
|
|
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE)); |
|
if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "alloc TOPO_NODE failed"); return -1; } |
|
ni->group_ref_count = 0; |
|
ni->flags = msg->flags; |
|
ni->group_id = msg->group_id; |
|
ni->node_id = msg->node_id; |
|
ni->ver = msg->ver; |
|
memcpy(ni->public_key, msg->public_key, SC_PUBKEY_SIZE); |
|
memcpy(ni->ed25519_public_key, msg->ed25519_public_key, SC_PUBKEY_SIZE); |
|
memcpy(ni->x25519_self_sig, msg->x25519_self_sig, 64); |
|
ni->client_type = msg->client_type; |
|
ni->client_activity = msg->client_activity; |
|
|
|
const uint8_t* dp = data + TOPOMSG_NODE_HDR_SIZE; |
|
|
|
if (msg->node_name_len) { |
|
ni->node_name = u_malloc(msg->node_name_len + 1); |
|
if (ni->node_name) { memcpy(ni->node_name, dp, msg->node_name_len); ni->node_name[msg->node_name_len] = 0; } |
|
dp += msg->node_name_len; |
|
} |
|
|
|
{ struct TOPO_SOCKMETA4* head = NULL; struct TOPO_SOCKMETA4* tail = NULL; |
|
for (int i = 0; i < msg->local_v4_sockets; i++) { |
|
const struct TOPOMSG_SOCKMETA4* w = (const struct TOPOMSG_SOCKMETA4*)dp; dp += sizeof(*w); |
|
struct TOPO_SOCKMETA4* e = memory_pool_alloc(group->instance->topo_groups->v4_sock_meta_pool); |
|
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; } |
|
e->id = w->id; e->config_type = w->config_type; e->nat_type = w->nat_type; e->next = NULL; |
|
if (!head) head = tail = e; else { tail->next = e; tail = e; } |
|
} |
|
ni->v4_sock_meta = head; } |
|
{ struct TOPO_ADDR4* head = NULL; struct TOPO_ADDR4* tail = NULL; |
|
for (int i = 0; i < msg->local_v4_addrs; i++) { |
|
const struct TOPOMSG_ADDR4* w = (const struct TOPOMSG_ADDR4*)dp; dp += sizeof(*w); |
|
struct TOPO_ADDR4* e = memory_pool_alloc(group->instance->topo_groups->v4_addr_pool); |
|
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; } |
|
memcpy(e->addr, w->addr, 4); e->port = w->port; e->type = w->type; e->socket_id = w->socket_id; e->protocol = w->protocol; e->next = NULL; |
|
if (!head) head = tail = e; else { tail->next = e; tail = e; } |
|
} |
|
ni->v4_addrs = head; } |
|
{ struct TOPO_SOCKMETA6* head = NULL; struct TOPO_SOCKMETA6* tail = NULL; |
|
for (int i = 0; i < msg->local_v6_sockets; i++) { |
|
const struct TOPOMSG_SOCKMETA6* w = (const struct TOPOMSG_SOCKMETA6*)dp; dp += sizeof(*w); |
|
struct TOPO_SOCKMETA6* e = memory_pool_alloc(group->instance->topo_groups->v6_sock_meta_pool); |
|
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; } |
|
e->id = w->id; e->config_type = w->config_type; e->nat_type = w->nat_type; e->next = NULL; |
|
if (!head) head = tail = e; else { tail->next = e; tail = e; } |
|
} |
|
ni->v6_sock_meta = head; } |
|
{ struct TOPO_ADDR6* head = NULL; struct TOPO_ADDR6* tail = NULL; |
|
for (int i = 0; i < msg->local_v6_addrs; i++) { |
|
const struct TOPOMSG_ADDR6* w = (const struct TOPOMSG_ADDR6*)dp; dp += sizeof(*w); |
|
struct TOPO_ADDR6* e = memory_pool_alloc(group->instance->topo_groups->v6_addr_pool); |
|
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; } |
|
memcpy(e->addr, w->addr, 16); e->port = w->port; e->type = w->type; e->socket_id = w->socket_id; e->protocol = w->protocol; e->next = NULL; |
|
if (!head) head = tail = e; else { tail->next = e; tail = e; } |
|
} |
|
ni->v6_addrs = head; } |
|
|
|
if (out_subnets && (msg->flags & TOPO_FLAG_SEND_SUBNETS) && (msg->local_v4_subnets || msg->local_v6_subnets)) { |
|
struct TOPO_NODESUBNETS* r = u_calloc(1, sizeof(struct TOPO_NODESUBNETS)); |
|
if (!r) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; } |
|
for (int i = 0; i < msg->local_v4_subnets; i++) { |
|
const struct TOPOMSG_SUBNET4* w = (const struct TOPOMSG_SUBNET4*)dp; dp += sizeof(*w); |
|
struct TOPO_SUBNET4* e = memory_pool_alloc(group->instance->topo_groups->v4_subnet_pool); |
|
if (!e) { u_free(r); topo_node_free_raw(group->instance->topo_groups, ni); return -1; } |
|
memcpy(e->addr, w->addr, 4); e->prefix_length = w->prefix_length; |
|
e->next = r->v4_subnets; r->v4_subnets = e; |
|
} |
|
for (int i = 0; i < msg->local_v6_subnets; i++) { |
|
const struct TOPOMSG_SUBNET6* w = (const struct TOPOMSG_SUBNET6*)dp; dp += sizeof(*w); |
|
struct TOPO_SUBNET6* e = memory_pool_alloc(group->instance->topo_groups->v6_subnet_pool); |
|
if (!e) { u_free(r); topo_node_free_raw(group->instance->topo_groups, ni); return -1; } |
|
memcpy(e->addr, w->addr, 16); e->prefix_length = w->prefix_length; |
|
e->next = r->v6_subnets; r->v6_subnets = e; |
|
} |
|
*out_subnets = r; |
|
} else if (!(msg->flags & TOPO_FLAG_SEND_SUBNETS)) { |
|
dp += msg->local_v4_subnets * sizeof(struct TOPOMSG_SUBNET4) |
|
+ msg->local_v6_subnets * sizeof(struct TOPOMSG_SUBNET6); |
|
if (out_subnets) *out_subnets = NULL; |
|
} else { |
|
if (out_subnets) *out_subnets = NULL; |
|
} |
|
|
|
if (out_hop_list && msg->hop_count > 0) { |
|
size_t hsz = msg->hop_count * 8; |
|
*out_hop_list = u_malloc(hsz); |
|
if (!*out_hop_list) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; } |
|
memcpy(*out_hop_list, dp, hsz); dp += hsz; |
|
*out_hop_count = msg->hop_count; |
|
} |
|
|
|
if (out_cumulative_rtt) *out_cumulative_rtt = msg->cumulative_rtt; |
|
*out_ni = ni; |
|
return 0; |
|
} |
|
|
|
struct TOPO_GROUP_NODE* topo_node_find_by_id(struct TOPO_GROUP* group, uint64_t node_id) { |
|
if (!group || !group->nodes) return NULL; |
|
uint64_t key = node_id; |
|
struct ll_entry* e = queue_find_data_by_index(group->nodes, &key); |
|
return e ? (struct TOPO_GROUP_NODE*)e : NULL; |
|
} |
|
|
|
int topo_node_ping_request_cbk(struct TOPO_GROUPS* groups, uint64_t node_id) { |
|
if (!groups || !groups->group_list) return 0; |
|
uint64_t now = get_time_tb(); |
|
struct ll_entry* ge = groups->group_list->head; |
|
while (ge) { |
|
struct TOPO_GROUP* g = (struct TOPO_GROUP*)ge; |
|
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(g, node_id); |
|
if (nq) { |
|
struct TOPO_CONNECTIVITY* c = &nq->connectivity; |
|
if (c->last_ping_time == 0 || (now - c->last_ping_time) > PING_TTL_TB) { |
|
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "ping_request_cbk: node=%016llx last_ping=%llu now=%llu stale=1", |
|
(unsigned long long)node_id, (unsigned long long)c->last_ping_time, (unsigned long long)now); |
|
return 1; |
|
} |
|
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "ping_request_cbk: node=%016llx last_ping=%llu now=%llu stale=0", |
|
(unsigned long long)node_id, (unsigned long long)c->last_ping_time, (unsigned long long)now); |
|
} |
|
ge = ge->next; |
|
} |
|
return 0; |
|
} |
|
|
|
void topo_node_ping_update_rtt(struct TOPO_GROUPS* groups, uint64_t node_id, uint16_t rtt) { |
|
if (!groups || !groups->group_list) { |
|
DEBUG_WARN(DEBUG_CATEGORY_BGP, "ping_update_rtt: no groups, node=%016llx rtt=%u", (unsigned long long)node_id, (unsigned)rtt); |
|
return; |
|
} |
|
uint64_t now = get_time_tb(); |
|
struct ll_entry* ge = groups->group_list->head; |
|
while (ge) { |
|
struct TOPO_GROUP* g = (struct TOPO_GROUP*)ge; |
|
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(g, node_id); |
|
if (nq) { |
|
nq->connectivity.last_ping_time = now; |
|
if (nq->connectivity.interface_min_rtt == 0 || rtt < nq->connectivity.interface_min_rtt) |
|
nq->connectivity.interface_min_rtt = rtt; |
|
if (nq->connectivity.nat_min_rtt == 0 || rtt < nq->connectivity.nat_min_rtt) |
|
nq->connectivity.nat_min_rtt = rtt; |
|
if (nq->connectivity.real_min_rtt == 0 || rtt < nq->connectivity.real_min_rtt) |
|
nq->connectivity.real_min_rtt = rtt; |
|
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "ping_update_rtt: node=%016llx rtt=%u (%llu) group=%016llx", |
|
(unsigned long long)node_id, (unsigned)rtt, (unsigned long long)now, (unsigned long long)g->group_id); |
|
if (groups->instance && groups->instance->topo_sqlite_db) |
|
topo_node_sqlite_update_rtt(groups->instance->topo_sqlite_db, node_id, rtt); |
|
topo_fire_nodeinfo_cbk(groups->instance, g, nq); |
|
} |
|
ge = ge->next; |
|
} |
|
} |
|
|
|
uint16_t topo_get_chain_rtt(struct TOPO_GROUP_NODE* nq) { |
|
if (!nq || !nq->paths || !nq->paths->head) { |
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "chain_rtt: nid=%016llx NO PATHS", (unsigned long long)(nq ? nq->node_id : 0)); |
|
return 0xFFFF; |
|
} |
|
uint16_t best = 0xFFFF; |
|
for (struct ll_entry* e = nq->paths->head; e; e = e->next) { |
|
struct TOPO_NODEPATH* p = (struct TOPO_NODEPATH*)e; |
|
if (!p->conn || !p->conn->links_up || !p->conn->rtt_last) { |
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "chain_rtt: nid=%016llx SKIP conn=%s up=%d rtt=%u cum=%u", |
|
(unsigned long long)nq->node_id, p->conn ? p->conn->log_name : "NULL", |
|
p->conn ? p->conn->links_up : 0, p->conn ? p->conn->rtt_last : 0, p->cumulative_rtt); |
|
continue; |
|
} |
|
uint16_t total = (uint16_t)((uint32_t)p->conn->rtt_last + p->cumulative_rtt); |
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "chain_rtt: nid=%016llx PATH %s rtt=%u+cum=%u=%u best=%u", |
|
(unsigned long long)nq->node_id, p->conn->log_name, p->conn->rtt_last, p->cumulative_rtt, total, best); |
|
if (total < best) best = total; |
|
} |
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "chain_rtt: nid=%016llx RESULT=%u(0x%04X)", (unsigned long long)nq->node_id, best, best); |
|
return best; |
|
} |
|
|
|
// ===== dump / format ===== |
|
|
|
static int is_node_connectivity_active(struct TOPO_CONNECTIVITY* c) { |
|
return c->probe_status != PROBE_STATUS_NONE |
|
|| c->interface_status != PROBE_RESULT_UNKNOWN |
|
|| c->nat_status != PROBE_RESULT_UNKNOWN |
|
|| c->real_status != PROBE_RESULT_UNKNOWN |
|
|| c->probe_start_time != 0 |
|
|| c->ping_req_time != 0 |
|
|| c->last_ping_time != 0; |
|
} |
|
|
|
static const char* probe_status_str(uint8_t s) { |
|
switch (s) { case 0: return "NONE"; case 1: return "IN_PROGRESS"; case 2: return "DONE"; default: return "?"; } |
|
} |
|
static const char* probe_result_str(uint8_t s) { |
|
switch (s) { case 0: return "UNKNOWN"; case 1: return "REACHABLE"; case 2: return "UNREACHABLE"; default: return "?"; } |
|
} |
|
static const char* conn_mgr_type_str(uint8_t t) { |
|
switch (t) { case 1: return "DIRECT"; case 2: return "REVERSE"; case 3: return "INDIRECT"; default: return "NONE"; } |
|
} |
|
|
|
void topo_node_dump_all(struct TOPO_GROUP* group) { |
|
if (!group || !group->nodes) return; |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "=== BGP Nodes dump: %d nodes ===", queue_entry_count(group->nodes)); |
|
|
|
int idx = 0; |
|
struct ll_entry* e = group->nodes->head; |
|
while (e) { |
|
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)e; |
|
struct TOPO_NODE* ni = topo_node_registry_find(group->instance->topo_groups, nq->node_id); |
|
if (!ni) { e = e->next; continue; } |
|
int is_local = (group->local_node == nq); |
|
const char* name_s = ni->node_name ? ni->node_name : ""; |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "--- Node #%d: id=%016llx name=\"%s\" ver=%u grp=%llu%s ---", |
|
idx, (unsigned long long)ni->node_id, name_s, ni->ver, |
|
(unsigned long long)ni->group_id, is_local ? " [LOCAL]" : ""); |
|
|
|
log_dump(DEBUG_LEVEL_INFO, DEBUG_CATEGORY_BGP, " pubkey ", ni->public_key, SC_PUBKEY_SIZE); |
|
log_dump(DEBUG_LEVEL_INFO, DEBUG_CATEGORY_BGP, " ed25519", ni->ed25519_public_key, SC_PUBKEY_SIZE); |
|
|
|
int si = 0; |
|
{ struct TOPO_SOCKMETA4* sm = ni->v4_sock_meta; while (sm) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v4sock[%d]: id=%u config=%u nat=%u", si++, sm->id, sm->config_type, sm->nat_type); |
|
sm = sm->next; |
|
}} |
|
{ const char* atn[] = {"INTERFACE","NAT","REAL"}; |
|
int ai = 0; struct TOPO_ADDR4* a = ni->v4_addrs; while (a) { |
|
const char* proto = (a->protocol & TOPO_PROTO_TCP) ? "tcp" : (a->protocol & TOPO_PROTO_UDP) ? "udp" : "?"; |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v4addr[%d]: %s:%u %s sock=%u proto=%s", ai++, |
|
ip_to_str(a->addr, AF_INET).str, a->port, (a->type<=2)?atn[a->type]:"?", a->socket_id, proto); |
|
a = a->next; |
|
}} |
|
{ int si6 = 0; struct TOPO_SOCKMETA6* sm6 = ni->v6_sock_meta; while (sm6) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v6sock[%d]: id=%u config=%u nat=%u", si6++, sm6->id, sm6->config_type, sm6->nat_type); |
|
sm6 = sm6->next; |
|
}} |
|
{ int ai6 = 0; struct TOPO_ADDR6* a6 = ni->v6_addrs; while (a6) { |
|
const char* proto = (a6->protocol & TOPO_PROTO_TCP) ? "tcp" : (a6->protocol & TOPO_PROTO_UDP) ? "udp" : "?"; |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v6addr[%d]: %s:%u type=%u sock=%u proto=%s", ai6++, |
|
ip_to_str(a6->addr, AF_INET6).str, a6->port, a6->type, a6->socket_id, proto); |
|
a6 = a6->next; |
|
}} |
|
if (nq->subnets) { |
|
{ int ri = 0; struct TOPO_SUBNET4* sub = nq->subnets->v4_subnets; while (sub) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v4sub[%d]: %s/%d", ri++, ip_to_str(sub->addr, AF_INET).str, sub->prefix_length); |
|
sub = sub->next; |
|
}} |
|
{ int ri6 = 0; struct TOPO_SUBNET6* sub6 = nq->subnets->v6_subnets; while (sub6) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v6sub[%d]: %s/%d", ri6++, ip_to_str(sub6->addr, AF_INET6).str, sub6->prefix_length); |
|
sub6 = sub6->next; |
|
}} |
|
} |
|
int path_idx = 0; |
|
if (nq->paths) { |
|
struct ll_entry* pe = nq->paths->head; |
|
while (pe) { |
|
struct TOPO_NODEPATH* path = (struct TOPO_NODEPATH*)pe; |
|
uint64_t* hop = (uint64_t*)((uint8_t*)path + sizeof(struct TOPO_NODEPATH)); |
|
char hop_buf[256] = ""; int hop_pos = 0; |
|
for (uint8_t hi = 0; hi < path->hop_count && hop_pos < (int)sizeof(hop_buf)-20; hi++) |
|
hop_pos += snprintf(hop_buf + hop_pos, sizeof(hop_buf) - hop_pos, "%s%016llx", hi ? "->" : "", (unsigned long long)hop[hi]); |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " path[%d]: conn=%s hop_count=%u hops=[%s]", |
|
path_idx, path->conn ? path->conn->log_name : "NULL", path->hop_count, hop_buf); |
|
path_idx++; pe = pe->next; |
|
} |
|
} |
|
|
|
struct TOPO_CONNECTIVITY* c = &nq->connectivity; |
|
if (is_node_connectivity_active(c)) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " connectivity: probe=%s iface=%s(%u) nat=%s(%u) real=%s(%u) pend=%u iface_rtt=%u nat_rtt=%u real_rtt=%u start_tb=%llu ping_req_tb=%llu last_ping_tb=%llu", |
|
probe_status_str(c->probe_status), probe_result_str(c->interface_status), c->interface_min_rtt, |
|
probe_result_str(c->nat_status), c->nat_min_rtt, probe_result_str(c->real_status), c->real_min_rtt, |
|
c->pending_count, c->interface_min_rtt, c->nat_min_rtt, c->real_min_rtt, |
|
(unsigned long long)c->probe_start_time, (unsigned long long)c->ping_req_time, (unsigned long long)c->last_ping_time); |
|
} |
|
if (nq->conn_mgr_type != CONN_TYPE_NONE) { |
|
char interm_buf[200] = ""; int ipos = 0; |
|
for (uint8_t i = 0; i < nq->conn_mgr_intermediariy_count && ipos < (int)sizeof(interm_buf)-19; i++) |
|
ipos += snprintf(interm_buf + ipos, sizeof(interm_buf) - ipos, "%s%016llx", i ? "," : "", (unsigned long long)nq->conn_mgr_intermediaries[i]); |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " conn_mgr: type=%s intermediates=[%s]", conn_mgr_type_str(nq->conn_mgr_type), interm_buf); |
|
} |
|
|
|
e = e->next; idx++; |
|
} |
|
} |
|
|
|
int topo_node_format_all(struct TOPO_GROUP* group, char* buf, size_t buf_size) { |
|
if (!group || !group->nodes || !buf || buf_size == 0) return 0; |
|
int pos = 0; |
|
|
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, |
|
"=== BGP Nodes dump: %d nodes ===\n", queue_entry_count(group->nodes)); |
|
|
|
int idx = 0; |
|
struct ll_entry* e = group->nodes->head; |
|
while (e && (size_t)pos < buf_size) { |
|
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)e; |
|
struct TOPO_NODE* ni = topo_node_registry_find(group->instance->topo_groups, nq->node_id); |
|
if (!ni) { e = e->next; continue; } |
|
int is_local = (group->local_node == nq); |
|
const char* name_s = ni->node_name ? ni->node_name : ""; |
|
|
|
#define FMT_ADD(fmt, ...) pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, fmt, ##__VA_ARGS__) |
|
|
|
FMT_ADD("--- Node #%d: id=%016llx name=\"%s\" ver=%u grp=%llu%s ---\n", |
|
idx, (unsigned long long)ni->node_id, name_s, ni->ver, |
|
(unsigned long long)ni->group_id, is_local ? " [LOCAL]" : ""); |
|
|
|
FMT_ADD(" pubkey: "); for (int k = 0; k < SC_PUBKEY_SIZE; k++) FMT_ADD("%02x", ni->public_key[k]); FMT_ADD("\n"); |
|
FMT_ADD(" ed25519: "); for (int k = 0; k < SC_PUBKEY_SIZE; k++) FMT_ADD("%02x", ni->ed25519_public_key[k]); FMT_ADD("\n"); |
|
|
|
{ struct TOPO_SOCKMETA4* sm = ni->v4_sock_meta; int si = 0; while (sm) { |
|
FMT_ADD(" v4sock[%d]: id=%u config=%u nat=%u\n", si++, sm->id, sm->config_type, sm->nat_type); sm = sm->next; |
|
}} |
|
{ const char* atn[] = {"INTERFACE","NAT","REAL"}; struct TOPO_ADDR4* a = ni->v4_addrs; int ai = 0; while (a) { |
|
const char* proto = (a->protocol & TOPO_PROTO_TCP) ? "tcp" : (a->protocol & TOPO_PROTO_UDP) ? "udp" : "?"; |
|
FMT_ADD(" v4addr[%d]: %s:%u %s sock=%u proto=%s\n", |
|
ai++, ip_to_str(a->addr, AF_INET).str, a->port, (a->type<=2)?atn[a->type]:"?", a->socket_id, proto); |
|
a = a->next; |
|
}} |
|
{ struct TOPO_SOCKMETA6* sm6 = ni->v6_sock_meta; int s6i = 0; while (sm6) { |
|
FMT_ADD(" v6sock[%d]: id=%u config=%u nat=%u\n", s6i++, sm6->id, sm6->config_type, sm6->nat_type); sm6 = sm6->next; |
|
}} |
|
{ struct TOPO_ADDR6* a6 = ni->v6_addrs; int a6i = 0; while (a6) { |
|
const char* proto = (a6->protocol & TOPO_PROTO_TCP) ? "tcp" : (a6->protocol & TOPO_PROTO_UDP) ? "udp" : "?"; |
|
FMT_ADD(" v6addr[%d]: %s:%u type=%u sock=%u proto=%s\n", |
|
a6i++, ip_to_str(a6->addr, AF_INET6).str, a6->port, a6->type, a6->socket_id, proto); |
|
a6 = a6->next; |
|
}} |
|
if (nq->subnets) { |
|
{ struct TOPO_SUBNET4* sub = nq->subnets->v4_subnets; int ri = 0; while (sub) { |
|
FMT_ADD(" v4sub[%d]: %s/%d\n", ri++, ip_to_str(sub->addr, AF_INET).str, sub->prefix_length); sub = sub->next; |
|
}} |
|
{ struct TOPO_SUBNET6* sub6 = nq->subnets->v6_subnets; int r6i = 0; while (sub6) { |
|
FMT_ADD(" v6sub[%d]: %s/%d\n", r6i++, ip_to_str(sub6->addr, AF_INET6).str, sub6->prefix_length); sub6 = sub6->next; |
|
}} |
|
} |
|
if (nq->paths) { |
|
struct ll_entry* pe = nq->paths->head; int pi = 0; |
|
while (pe) { |
|
struct TOPO_NODEPATH* path = (struct TOPO_NODEPATH*)pe; |
|
uint64_t* hop = (uint64_t*)((uint8_t*)path + sizeof(struct TOPO_NODEPATH)); |
|
FMT_ADD(" path[%d]: conn=%s hop_count=%u hops=[", pi++, path->conn ? path->conn->log_name : "NULL", path->hop_count); |
|
for (uint8_t hi = 0; hi < path->hop_count; hi++) |
|
FMT_ADD("%s%016llx", hi ? "->" : "", (unsigned long long)hop[hi]); |
|
FMT_ADD("]\n"); pe = pe->next; |
|
} |
|
} |
|
|
|
struct TOPO_CONNECTIVITY* c = &nq->connectivity; |
|
if (is_node_connectivity_active(c)) { |
|
FMT_ADD(" connectivity: probe=%s iface=%s(%u) nat=%s(%u) real=%s(%u) pend=%u iface_rtt=%u nat_rtt=%u real_rtt=%u start_tb=%llu ping_req_tb=%llu last_ping_tb=%llu\n", |
|
probe_status_str(c->probe_status), probe_result_str(c->interface_status), c->interface_min_rtt, |
|
probe_result_str(c->nat_status), c->nat_min_rtt, probe_result_str(c->real_status), c->real_min_rtt, |
|
c->pending_count, c->interface_min_rtt, c->nat_min_rtt, c->real_min_rtt, |
|
(unsigned long long)c->probe_start_time, (unsigned long long)c->ping_req_time, (unsigned long long)c->last_ping_time); |
|
} |
|
if (nq->conn_mgr_type != CONN_TYPE_NONE) { |
|
FMT_ADD(" conn_mgr: type=%s intermediates=[", conn_mgr_type_str(nq->conn_mgr_type)); |
|
for (uint8_t i = 0; i < nq->conn_mgr_intermediariy_count; i++) |
|
FMT_ADD("%s%016llx", i ? "," : "", (unsigned long long)nq->conn_mgr_intermediaries[i]); |
|
FMT_ADD("]\n"); |
|
} |
|
|
|
#undef FMT_ADD |
|
e = e->next; idx++; |
|
} |
|
|
|
if ((size_t)pos >= buf_size) { |
|
pos = (int)buf_size - 14; if (pos < 0) pos = 0; |
|
pos += snprintf(buf + pos, buf_size - pos, "\n[TRUNCATED]\n"); |
|
} |
|
return pos; |
|
} |
|
|
|
// ===== update my nodeinfo ===== |
|
|
|
int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GROUP* group) { |
|
if (!instance || !group) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args"); return -1; } |
|
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "TOPO_UPD_SELF: ENTER inst=%p nid=0x%016llx grp=%p grp_inst=%p grp_type=%d", |
|
(void*)instance, (unsigned long long)instance->node_id, (void*)group, (void*)group->instance, group->group_type); |
|
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "TOPO_UPD_SELF: topo_groups=%p etcp=%p reg=%p", |
|
(void*)instance->topo_groups, (void*)instance->etcp_sockets, |
|
instance->topo_groups ? (void*)instance->topo_groups->node_registry : NULL); |
|
if (instance->topo_groups) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "TOPO_UPD_SELF: pools sm4=%p a4=%p sm6=%p a6=%p sub4=%p sub6=%p", |
|
(void*)instance->topo_groups->v4_sock_meta_pool, (void*)instance->topo_groups->v4_addr_pool, |
|
(void*)instance->topo_groups->v6_sock_meta_pool, (void*)instance->topo_groups->v6_addr_pool, |
|
(void*)instance->topo_groups->v4_subnet_pool, (void*)instance->topo_groups->v6_subnet_pool); |
|
} |
|
size_t name_len = 0; |
|
if (instance->name[0]) { name_len = strlen(instance->name); if (name_len > 63) name_len = 63; } |
|
int vc = 0, vc6 = 0; |
|
struct CFG_ROUTE_ENTRY* s = instance->config->my_subnets; |
|
while (s) { if (s->ip.family == AF_INET) vc++; else if (s->ip.family == AF_INET6) vc6++; s = s->next; } |
|
|
|
// Для chat групп подсети не передаём |
|
if (group->group_type == TOPO_GROUP_TYPE_CHAT) { vc = 0; vc6 = 0; } |
|
|
|
int sock_count = 0, addr_count = 0, sock6_count = 0, addr6_count = 0; |
|
int tcp4_count = 0, tcp6_count = 0; |
|
struct ETCP_SOCKET* e_sock = instance->etcp_sockets; |
|
while (e_sock) { |
|
if (e_sock->type == CFG_SERVER_TYPE_PRIVATE || e_sock->type == CFG_SERVER_TYPE_LOCAL) { e_sock = e_sock->next; continue; } |
|
if (e_sock->local_addr.ss_family == AF_INET) { sock_count++; addr_count++; } |
|
else if (e_sock->local_addr.ss_family == AF_INET6) { sock6_count++; addr6_count++; } |
|
e_sock = e_sock->next; |
|
} |
|
{ struct ETCP_SOCKET* ts = instance->etcp_sockets; |
|
while (ts) { if (!ts->is_tcp) { ts = ts->next; continue; } |
|
if (ts->type == CFG_SERVER_TYPE_PRIVATE || ts->type == CFG_SERVER_TYPE_LOCAL) { ts = ts->next; continue; } |
|
if (ts->interface_addr.ss_family == AF_INET || ts->local_addr.ss_family == AF_INET) { tcp4_count++; addr_count++; } |
|
else if (ts->interface_addr.ss_family == AF_INET6 || ts->local_addr.ss_family == AF_INET6) { tcp6_count++; addr6_count++; } |
|
ts = ts->next; } |
|
} |
|
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "counts: udp_v4s=%d udp_v4a=%d udp_v6s=%d udp_v6a=%d tcp4=%d tcp6=%d v4a_total=%d v6a_total=%d", |
|
sock_count, addr_count - tcp4_count, sock6_count, addr6_count - tcp6_count, |
|
tcp4_count, tcp6_count, addr_count, addr6_count); |
|
|
|
int changed = 1; uint8_t old_ver = 0; |
|
if (group->local_node) { |
|
struct TOPO_NODE* oni = topo_node_registry_find(instance->topo_groups, group->local_node->node_id); |
|
if (oni) { |
|
old_ver = oni->ver; |
|
changed = (vc != (group->local_node->subnets ? topo_list_count((struct _topo_head*)group->local_node->subnets->v4_subnets) : 0)) |
|
|| (sock_count != topo_list_count((struct _topo_head*)oni->v4_sock_meta)) |
|
|| (addr_count != topo_list_count((struct _topo_head*)oni->v4_addrs)) |
|
|| (name_len != (oni->node_name ? strlen(oni->node_name) : 0)) |
|
|| (memcmp(oni->public_key, instance->my_keys.public_key, SC_PUBKEY_SIZE) != 0) |
|
|| (vc6 != (group->local_node->subnets ? topo_list_count((struct _topo_head*)group->local_node->subnets->v6_subnets) : 0)) |
|
|| (sock6_count != topo_list_count((struct _topo_head*)oni->v6_sock_meta)) |
|
|| (addr6_count != topo_list_count((struct _topo_head*)oni->v6_addrs)) |
|
|| (oni->client_type != instance->client_type) |
|
|| (oni->client_activity != instance->client_activity); |
|
if (!changed && oni->v4_sock_meta) { |
|
struct ETCP_SOCKET* es = instance->etcp_sockets; |
|
struct TOPO_SOCKMETA4* sm = oni->v4_sock_meta; |
|
while (es && sm) { |
|
if (es->type == CFG_SERVER_TYPE_PRIVATE || es->type == CFG_SERVER_TYPE_LOCAL) { es = es->next; continue; } |
|
if (es->local_addr.ss_family != AF_INET) { es = es->next; continue; } |
|
if (sm->nat_type != es->nat_type) { changed = 1; break; } |
|
sm = sm->next; es = es->next; |
|
} |
|
} |
|
if (group->local_node && group->instance && group->instance->topo_groups) |
|
if (memcmp(oni->ed25519_public_key, group->ed25519_public_key, SC_PUBKEY_SIZE) != 0) changed = 1; |
|
} |
|
} |
|
if (!changed && group->local_node) { |
|
struct TOPO_NODE* oni2 = topo_node_registry_find(instance->topo_groups, group->local_node->node_id); |
|
int old_v4a = oni2 ? topo_list_count((struct _topo_head*)oni2->v4_addrs) : -1; |
|
int old_v6a = oni2 ? topo_list_count((struct _topo_head*)oni2->v6_addrs) : -1; |
|
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "nodeinfo unchanged: old_v4a=%d new_v4a=%d old_v6a=%d new_v6a=%d tcp4=%d tcp6=%d", |
|
old_v4a, addr_count, old_v6a, addr6_count, tcp4_count, tcp6_count); |
|
} |
|
|
|
if (changed) { |
|
if (group->local_node) { |
|
if (instance->rt) route_delete(instance->rt, group->local_node); |
|
topo_nodeq_free_group_fields(instance->topo_groups, group->local_node); |
|
u_free(group->local_node); |
|
group->local_node = NULL; |
|
} |
|
|
|
group->local_node = u_calloc(1, sizeof(struct TOPO_GROUP_NODE)); |
|
if (!group->local_node) return -1; |
|
struct TOPO_GROUP_NODE* lq = group->local_node; |
|
|
|
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE)); |
|
if (!ni) { u_free(lq); group->local_node = NULL; return -1; } |
|
ni->group_ref_count = 0; |
|
ni->flags = (group->group_type == TOPO_GROUP_TYPE_CHAT) ? 0 : TOPO_FLAG_SEND_SUBNETS; |
|
ni->group_id = group->group_id; |
|
ni->node_id = instance->node_id; |
|
ni->ver = (old_ver % 255) + 1; |
|
ni->client_type = instance->client_type; |
|
ni->client_activity = instance->client_activity; |
|
memcpy(ni->public_key, instance->my_keys.public_key, SC_PUBKEY_SIZE); |
|
memcpy(ni->ed25519_public_key, group->ed25519_public_key, SC_PUBKEY_SIZE); |
|
if (name_len) { ni->node_name = u_malloc(name_len + 1); if (ni->node_name) { memcpy(ni->node_name, instance->name, name_len); ni->node_name[name_len] = 0; } } |
|
|
|
{ uint64_t saved_node_id = ni->node_id; uint32_t saved_ver = ni->ver; |
|
ni = topo_node_registry_store(instance->topo_groups, ni); |
|
lq->node_id = saved_node_id; |
|
lq->last_ver = saved_ver; } |
|
|
|
e_sock = instance->etcp_sockets; |
|
int etcp_iter_cnt = 0; |
|
while (e_sock) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "TOPO_UPD_SELF: etcp_iter[%d] e_sock=%p type=%d fam=%d next=%p", |
|
etcp_iter_cnt, (void*)e_sock, e_sock->type, e_sock->local_addr.ss_family, (void*)e_sock->next); |
|
etcp_iter_cnt++; |
|
if (e_sock->type == CFG_SERVER_TYPE_PRIVATE || e_sock->type == CFG_SERVER_TYPE_LOCAL) { e_sock = e_sock->next; continue; } |
|
if (e_sock->local_addr.ss_family == AF_INET) { |
|
{ struct TOPO_SOCKMETA4* sm = memory_pool_alloc(group->instance->topo_groups->v4_sock_meta_pool); |
|
sm->id = e_sock->sock_id; sm->config_type = e_sock->type; sm->nat_type = e_sock->nat_type; |
|
sm->next = ni->v4_sock_meta; ni->v4_sock_meta = sm; } |
|
|
|
struct sockaddr_in* local_sin = (struct sockaddr_in*)&e_sock->local_addr; |
|
struct sockaddr_in* if_sin = (struct sockaddr_in*)&e_sock->interface_addr; |
|
struct sockaddr_in* nat_sin = (struct sockaddr_in*)&e_sock->nat_addr; |
|
int nat_verified = (e_sock->nat_addr.ss_family == AF_INET && nat_sin->sin_addr.s_addr != 0 && e_sock->nat_type != NAT_VERIFIED_STRICT); |
|
{ struct TOPO_ADDR4* a = memory_pool_alloc(group->instance->topo_groups->v4_addr_pool); |
|
if (nat_verified) { |
|
memcpy(a->addr, &nat_sin->sin_addr.s_addr, 4); a->port = ntohs(nat_sin->sin_port); |
|
a->type = TOPO_ADDR_NAT; a->socket_id = e_sock->sock_id | 1; |
|
} else { |
|
int use_local = (local_sin->sin_addr.s_addr != 0); |
|
memcpy(a->addr, use_local ? &local_sin->sin_addr.s_addr : &if_sin->sin_addr.s_addr, 4); |
|
a->port = ntohs(use_local ? local_sin->sin_port : if_sin->sin_port); |
|
a->type = TOPO_ADDR_INTERFACE; a->socket_id = e_sock->sock_id; |
|
} |
|
a->protocol = TOPO_PROTO_UDP; |
|
a->next = ni->v4_addrs; ni->v4_addrs = a; } |
|
} else if (e_sock->local_addr.ss_family == AF_INET6) { |
|
{ struct TOPO_SOCKMETA6* sm6 = memory_pool_alloc(group->instance->topo_groups->v6_sock_meta_pool); |
|
sm6->id = e_sock->sock_id; sm6->config_type = e_sock->type; sm6->nat_type = e_sock->nat_type; |
|
sm6->next = ni->v6_sock_meta; ni->v6_sock_meta = sm6; } |
|
struct sockaddr_in6* if_sin6 = (struct sockaddr_in6*)&e_sock->interface_addr; |
|
{ struct TOPO_ADDR6* a6 = memory_pool_alloc(group->instance->topo_groups->v6_addr_pool); |
|
memcpy(a6->addr, &if_sin6->sin6_addr, 16); a6->port = ntohs(if_sin6->sin6_port); |
|
a6->type = TOPO_ADDR_INTERFACE; a6->socket_id = e_sock->sock_id; a6->protocol = TOPO_PROTO_UDP; |
|
a6->next = ni->v6_addrs; ni->v6_addrs = a6; } |
|
} |
|
e_sock = e_sock->next; |
|
} |
|
{ struct ETCP_SOCKET* ts = instance->etcp_sockets; |
|
int tcp_iter_cnt = 0; |
|
while (ts) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "TOPO_UPD_SELF: tcp_iter[%d] ts=%p type=%d fam=%d next=%p", |
|
tcp_iter_cnt, (void*)ts, ts->type, ts->local_addr.ss_family, (void*)ts->next); |
|
tcp_iter_cnt++; if (!ts->is_tcp) { ts = ts->next; continue; } |
|
struct sockaddr_storage* addr = ts->interface_addr.ss_family ? &ts->interface_addr : &ts->local_addr; |
|
if (!addr || !addr->ss_family) { ts = ts->next; continue; } |
|
if (addr->ss_family == AF_INET) { |
|
struct sockaddr_in* sin = (struct sockaddr_in*)addr; |
|
{ struct TOPO_ADDR4* a = memory_pool_alloc(group->instance->topo_groups->v4_addr_pool); |
|
memcpy(a->addr, &sin->sin_addr.s_addr, 4); a->port = ntohs(sin->sin_port); |
|
a->type = TOPO_ADDR_INTERFACE; a->socket_id = ts->sock_id; a->protocol = TOPO_PROTO_TCP; |
|
a->next = ni->v4_addrs; ni->v4_addrs = a; } |
|
} else if (addr->ss_family == AF_INET6) { |
|
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr; |
|
{ struct TOPO_ADDR6* a6 = memory_pool_alloc(group->instance->topo_groups->v6_addr_pool); |
|
memcpy(a6->addr, &sin6->sin6_addr, 16); a6->port = ntohs(sin6->sin6_port); |
|
a6->type = TOPO_ADDR_INTERFACE; a6->socket_id = ts->sock_id; a6->protocol = TOPO_PROTO_TCP; |
|
a6->next = ni->v6_addrs; ni->v6_addrs = a6; } |
|
} |
|
ts = ts->next; } |
|
} |
|
|
|
topo_node_sign_self(instance, ni); |
|
|
|
if (group->group_type != TOPO_GROUP_TYPE_CHAT && (vc || vc6)) { |
|
struct TOPO_NODESUBNETS* r = u_calloc(1, sizeof(struct TOPO_NODESUBNETS)); |
|
s = instance->config->my_subnets; |
|
while (s) { |
|
if (s->ip.family == AF_INET) { |
|
struct TOPO_SUBNET4* sub = memory_pool_alloc(group->instance->topo_groups->v4_subnet_pool); |
|
memcpy(sub->addr, &s->ip.addr.v4, 4); sub->prefix_length = s->netmask; |
|
sub->next = r->v4_subnets; r->v4_subnets = sub; |
|
} else if (s->ip.family == AF_INET6) { |
|
struct TOPO_SUBNET6* sub6 = memory_pool_alloc(group->instance->topo_groups->v6_subnet_pool); |
|
memcpy(sub6->addr, &s->ip.addr.v6, 16); sub6->prefix_length = s->netmask; |
|
sub6->next = r->v6_subnets; r->v6_subnets = sub6; |
|
} |
|
s = s->next; |
|
} |
|
lq->subnets = r; |
|
} |
|
|
|
if (group->group_type == TOPO_GROUP_TYPE_CHAT) |
|
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "my_nodeinfo updated: v4s=%d v4a=%d v6s=%d v6a=%d tcp4=%d tcp6=%d v4sub=%d v6sub=%d ver=%d grp=%016llx", |
|
sock_count, addr_count, sock6_count, addr6_count, tcp4_count, tcp6_count, vc, vc6, ni->ver, (unsigned long long)group->group_id); |
|
else |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "my_nodeinfo updated: v4s=%d v4a=%d v6s=%d v6a=%d tcp4=%d tcp6=%d v4sub=%d v6sub=%d ver=%d grp=%016llx", |
|
sock_count, addr_count, sock6_count, addr6_count, tcp4_count, tcp6_count, vc, vc6, ni->ver, (unsigned long long)group->group_id); |
|
if (group->group_type != TOPO_GROUP_TYPE_CHAT && instance->rt && !route_insert(instance->rt, lq)) |
|
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "failed to insert local routes"); |
|
} else { |
|
struct TOPO_NODE* lni = topo_node_registry_find(instance->topo_groups, group->local_node->node_id); |
|
if (lni) group->local_node->last_ver = lni->ver; |
|
} |
|
return vc; |
|
} |
|
|
|
void topo_node_update_my_addresses(struct UTUN_INSTANCE* instance) { |
|
if (!instance || !instance->topo_groups) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args"); return; } |
|
struct TOPO_GROUP* default_group = topo_groups_get_default(instance->topo_groups); |
|
if (!default_group || !default_group->local_node) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "no local_node"); return; } |
|
struct TOPO_NODE* ni = topo_node_registry_find(instance->topo_groups, instance->node_id); |
|
if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "my node not in registry"); return; } |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "updating my addresses, old ver=%d", ni->ver); |
|
|
|
free_v4_sock_list(instance->topo_groups->v4_sock_meta_pool, ni->v4_sock_meta); ni->v4_sock_meta = NULL; |
|
free_v4_addr_list(instance->topo_groups->v4_addr_pool, ni->v4_addrs); ni->v4_addrs = NULL; |
|
free_v6_sock_list(instance->topo_groups->v6_sock_meta_pool, ni->v6_sock_meta); ni->v6_sock_meta = NULL; |
|
free_v6_addr_list(instance->topo_groups->v6_addr_pool, ni->v6_addrs); ni->v6_addrs = NULL; |
|
|
|
struct ETCP_SOCKET* e_sock = instance->etcp_sockets; |
|
while (e_sock) { |
|
if (e_sock->type == CFG_SERVER_TYPE_PRIVATE || e_sock->type == CFG_SERVER_TYPE_LOCAL) { e_sock = e_sock->next; continue; } |
|
if (e_sock->local_addr.ss_family == AF_INET) { |
|
{ struct TOPO_SOCKMETA4* sm = memory_pool_alloc(instance->topo_groups->v4_sock_meta_pool); |
|
sm->id = e_sock->sock_id; sm->config_type = e_sock->type; sm->nat_type = e_sock->nat_type; |
|
sm->next = ni->v4_sock_meta; ni->v4_sock_meta = sm; } |
|
struct sockaddr_in* local_sin = (struct sockaddr_in*)&e_sock->local_addr; |
|
struct sockaddr_in* if_sin = (struct sockaddr_in*)&e_sock->interface_addr; |
|
struct sockaddr_in* nat_sin = (struct sockaddr_in*)&e_sock->nat_addr; |
|
int nat_verified = (e_sock->nat_addr.ss_family == AF_INET && nat_sin->sin_addr.s_addr != 0 && e_sock->nat_type != NAT_VERIFIED_STRICT); |
|
{ struct TOPO_ADDR4* a = memory_pool_alloc(instance->topo_groups->v4_addr_pool); |
|
if (nat_verified) { |
|
memcpy(a->addr, &nat_sin->sin_addr.s_addr, 4); a->port = ntohs(nat_sin->sin_port); |
|
a->type = TOPO_ADDR_NAT; a->socket_id = e_sock->sock_id | 1; |
|
} else { |
|
int use_local = (local_sin->sin_addr.s_addr != 0); |
|
memcpy(a->addr, use_local ? &local_sin->sin_addr.s_addr : &if_sin->sin_addr.s_addr, 4); |
|
a->port = ntohs(use_local ? local_sin->sin_port : if_sin->sin_port); |
|
a->type = TOPO_ADDR_INTERFACE; a->socket_id = e_sock->sock_id; |
|
} |
|
a->protocol = TOPO_PROTO_UDP; |
|
a->next = ni->v4_addrs; ni->v4_addrs = a; } |
|
} else if (e_sock->local_addr.ss_family == AF_INET6) { |
|
{ struct TOPO_SOCKMETA6* sm6 = memory_pool_alloc(instance->topo_groups->v6_sock_meta_pool); |
|
sm6->id = e_sock->sock_id; sm6->config_type = e_sock->type; sm6->nat_type = e_sock->nat_type; |
|
sm6->next = ni->v6_sock_meta; ni->v6_sock_meta = sm6; } |
|
struct sockaddr_in6* if_sin6 = (struct sockaddr_in6*)&e_sock->interface_addr; |
|
{ struct TOPO_ADDR6* a6 = memory_pool_alloc(instance->topo_groups->v6_addr_pool); |
|
memcpy(a6->addr, &if_sin6->sin6_addr, 16); a6->port = ntohs(if_sin6->sin6_port); |
|
a6->type = TOPO_ADDR_INTERFACE; a6->socket_id = e_sock->sock_id; a6->protocol = TOPO_PROTO_UDP; |
|
a6->next = ni->v6_addrs; ni->v6_addrs = a6; } |
|
} |
|
e_sock = e_sock->next; |
|
} |
|
{ struct ETCP_SOCKET* ts = instance->etcp_sockets; |
|
while (ts) { if (!ts->is_tcp) { ts = ts->next; continue; } |
|
if (ts->type == CFG_SERVER_TYPE_PRIVATE || ts->type == CFG_SERVER_TYPE_LOCAL) { ts = ts->next; continue; } |
|
struct sockaddr_storage* addr = ts->interface_addr.ss_family ? &ts->interface_addr : &ts->local_addr; |
|
if (!addr || !addr->ss_family) { ts = ts->next; continue; } |
|
if (addr->ss_family == AF_INET) { |
|
struct sockaddr_in* sin = (struct sockaddr_in*)addr; |
|
{ struct TOPO_ADDR4* a = memory_pool_alloc(instance->topo_groups->v4_addr_pool); |
|
memcpy(a->addr, &sin->sin_addr.s_addr, 4); a->port = ntohs(sin->sin_port); |
|
a->type = TOPO_ADDR_INTERFACE; a->socket_id = ts->sock_id; a->protocol = TOPO_PROTO_TCP; |
|
a->next = ni->v4_addrs; ni->v4_addrs = a; } |
|
} else if (addr->ss_family == AF_INET6) { |
|
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr; |
|
{ struct TOPO_ADDR6* a6 = memory_pool_alloc(instance->topo_groups->v6_addr_pool); |
|
memcpy(a6->addr, &sin6->sin6_addr, 16); a6->port = ntohs(sin6->sin6_port); |
|
a6->type = TOPO_ADDR_INTERFACE; a6->socket_id = ts->sock_id; a6->protocol = TOPO_PROTO_TCP; |
|
a6->next = ni->v6_addrs; ni->v6_addrs = a6; } |
|
} |
|
ts = ts->next; } |
|
} |
|
|
|
ni->ver = (ni->ver % 255) + 1; |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "my addresses updated, new ver=%d", ni->ver); |
|
|
|
topo_node_sign_self(instance, ni); |
|
|
|
struct ll_entry* ge = instance->topo_groups->group_list->head; |
|
while (ge) { |
|
struct TOPO_GROUP* g = (struct TOPO_GROUP*)ge; |
|
if (g->local_node) { |
|
if (g->senders_list) { |
|
struct ll_entry* se = g->senders_list->head; |
|
while (se) { |
|
struct TOPO_GROUP_CONN_ITEM* item = (struct TOPO_GROUP_CONN_ITEM*)se->data; |
|
if (item && item->conn) topo_group_send_nodeinfo(g, g->local_node, item->conn, 0); |
|
se = se->next; |
|
} |
|
} |
|
} |
|
ge = ge->next; |
|
} |
|
} |
|
|
|
void topo_node_on_socket_changed(struct ETCP_SOCKET* sock, int event, void* arg) { |
|
(void)arg; |
|
if (!sock || !sock->instance) return; |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "socket %s changed (event=0x%x), updating nodeinfo", sock->name, event); |
|
topo_node_update_my_addresses(sock->instance); |
|
if (sock->instance->topo_sqlite_db) |
|
topo_node_sqlite_nodeinfo_updated(sock->instance->topo_sqlite_db, sock->instance->node_id); |
|
}
|
|
|