#include #include #include #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" void topo_node_ref(struct TOPO_NODE* ni) { if (!ni) return; ni->ref_count++; } void topo_node_unref(struct TOPO_NODE* ni) { if (!ni) return; if (--ni->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; } } void topo_node_free_lists(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq) { if (!group || !nq) return; if (nq->node) { free_v4_sock_list(group->instance->topo_groups->v4_sock_meta_pool, nq->node->v4_sock_meta); free_v4_addr_list(group->instance->topo_groups->v4_addr_pool, nq->node->v4_addrs); free_v6_sock_list(group->instance->topo_groups->v6_sock_meta_pool, nq->node->v6_sock_meta); free_v6_addr_list(group->instance->topo_groups->v6_addr_pool, nq->node->v6_addrs); nq->node->v4_sock_meta = NULL; nq->node->v4_addrs = NULL; nq->node->v6_sock_meta = NULL; nq->node->v6_addrs = NULL; topo_node_unref(nq->node); nq->node = NULL; } if (nq->subnets) { free_v4_sub_list(group->instance->topo_groups->v4_subnet_pool, nq->subnets->v4_subnets); free_v6_sub_list(group->instance->topo_groups->v6_subnet_pool, nq->subnets->v6_subnets); u_free(nq->subnets); nq->subnets = NULL; } u_free(nq->tranzit_data); nq->tranzit_data = NULL; nq->tranzit_count = 0; u_free(nq->hop_list); nq->hop_list = NULL; nq->hop_count = 0; } // ===== serialization ===== 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->tranzit_nodes * sizeof(struct TOPOMSG_TRANZIT) + msg->hop_count * 8; } int topo_node_serialize(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq, uint8_t* out, size_t out_max) { if (!group || !nq || !nq->node || !out) return -1; struct TOPO_NODE* ni = nq->node; 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); 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; msg.tranzit_nodes = nq->tranzit_count; msg.hop_count = nq->hop_count; 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; }} } } if (msg.tranzit_nodes && nq->tranzit_data) { size_t sz = msg.tranzit_nodes * sizeof(struct TOPOMSG_TRANZIT); memcpy(dp, nq->tranzit_data, sz); dp += sz; } if (msg.hop_count && nq->hop_list) { size_t sz = msg.hop_count * 8; memcpy(dp, nq->hop_list, 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, struct TOPOMSG_TRANZIT** out_tranzit, uint8_t* out_tranzit_count, uint64_t** out_hop_list, uint8_t* out_hop_count) { 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->ref_count = 1; 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); 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; } 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_unref(ni); return -1; } e->id = w->id; e->config_type = w->config_type; e->nat_type = w->nat_type; e->next = ni->v4_sock_meta; ni->v4_sock_meta = e; } 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_unref(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 = ni->v4_addrs; ni->v4_addrs = e; } 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_unref(ni); return -1; } e->id = w->id; e->config_type = w->config_type; e->nat_type = w->nat_type; e->next = ni->v6_sock_meta; ni->v6_sock_meta = e; } 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_unref(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 = ni->v6_addrs; ni->v6_addrs = e; } 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_unref(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_unref(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_unref(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_tranzit && msg->tranzit_nodes > 0) { size_t tsz = msg->tranzit_nodes * sizeof(struct TOPOMSG_TRANZIT); *out_tranzit = u_malloc(tsz); if (!*out_tranzit) { topo_node_unref(ni); return -1; } memcpy(*out_tranzit, dp, tsz); dp += tsz; *out_tranzit_count = msg->tranzit_nodes; } 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_unref(ni); return -1; } memcpy(*out_hop_list, dp, hsz); dp += hsz; *out_hop_count = msg->hop_count; } *out_ni = ni; return 0; } struct TOPO_NODEQ* 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_NODEQ*)e : NULL; } // ===== 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; } 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_NODEQ* nq = (struct TOPO_NODEQ*)e; struct TOPO_NODE* ni = nq->node; 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 dirty=%u alien=%u grp=%llu%s ---", idx, (unsigned long long)ni->node_id, name_s, ni->ver, nq->dirty, nq->alien, (unsigned long long)ni->group_id, is_local ? " [LOCAL]" : ""); if (nq->best_socket) DEBUG_INFO(DEBUG_CATEGORY_BGP, " best_socket=%p", (void*)nq->best_socket); 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; }} } for (int i = 0; i < nq->tranzit_count; i++) { DEBUG_INFO(DEBUG_CATEGORY_BGP, " tranzit[%d]: node=%016llx rtt=%u linkq=%u", i, (unsigned long long)nq->tranzit_data[i].node_id, nq->tranzit_data[i].rtt, nq->tranzit_data[i].link_q); } 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", 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); } 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_NODEQ* nq = (struct TOPO_NODEQ*)e; struct TOPO_NODE* ni = nq->node; 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 dirty=%u alien=%u grp=%llu%s ---\n", idx, (unsigned long long)ni->node_id, name_s, ni->ver, nq->dirty, nq->alien, (unsigned long long)ni->group_id, is_local ? " [LOCAL]" : ""); if (nq->best_socket) FMT_ADD(" best_socket=%p\n", (void*)nq->best_socket); 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; }} } for (int i = 0; i < nq->tranzit_count; i++) FMT_ADD(" tranzit[%d]: node=%016llx rtt=%u linkq=%u\n", i, (unsigned long long)nq->tranzit_data[i].node_id, nq->tranzit_data[i].rtt, nq->tranzit_data[i].link_q); 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\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); } 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; } 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; 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++; if (e_sock->nat_addr.ss_family == AF_INET) { struct sockaddr_in* nat_sin = (struct sockaddr_in*)&e_sock->nat_addr; if (nat_sin->sin_addr.s_addr != 0 && e_sock->nat_type != NAT_VERIFIED_STRICT) addr_count++; } if (e_sock->nat_type == NAT_VERIFIED_DIRECT || ((e_sock->type == CFG_SERVER_TYPE_PUBLIC || e_sock->type == CFG_SERVER_TYPE_UNKNOWN) && e_sock->nat_type < NAT_VERIFIED_UNKNOWN)) addr_count++; } else if (e_sock->local_addr.ss_family == AF_INET6) { sock6_count++; addr6_count++; } e_sock = e_sock->next; } { struct CFG_SERVER* srv = instance->config->servers; while (srv) { if (srv->transport) { if (srv->ip.ss_family == AF_INET) addr_count++; else if (srv->ip.ss_family == AF_INET6) addr6_count++; } srv = srv->next; } } int changed = 1; uint8_t old_ver = 0; if (group->local_node && group->local_node->node) { struct TOPO_NODE* oni = group->local_node->node; 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)); 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) { if (group->local_node) { if (instance->rt) route_delete(instance->rt, group->local_node); topo_node_free_lists(group, group->local_node); u_free(group->local_node); group->local_node = NULL; } group->local_node = u_calloc(1, sizeof(struct TOPO_NODEQ)); if (!group->local_node) return -1; struct TOPO_NODEQ* 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->ref_count = 1; 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; 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; } } lq->node = ni; lq->hash_node_id = ni->node_id; lq->hop_count = 0; lq->dirty = 1; lq->last_ver = ni->ver; 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(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* if_sin = (struct sockaddr_in*)&e_sock->interface_addr; struct sockaddr_in* nat_sin = (struct sockaddr_in*)&e_sock->nat_addr; { struct TOPO_ADDR4* a = memory_pool_alloc(group->instance->topo_groups->v4_addr_pool); memcpy(a->addr, &if_sin->sin_addr.s_addr, 4); a->port = ntohs(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; } if (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); 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; a->protocol = TOPO_PROTO_UDP; a->next = ni->v4_addrs; ni->v4_addrs = a; } if (e_sock->nat_type == NAT_VERIFIED_DIRECT || ((e_sock->type == CFG_SERVER_TYPE_PUBLIC || e_sock->type == CFG_SERVER_TYPE_UNKNOWN) && e_sock->nat_type < NAT_VERIFIED_UNKNOWN)) { struct TOPO_ADDR4* a = memory_pool_alloc(group->instance->topo_groups->v4_addr_pool); memcpy(a->addr, &if_sin->sin_addr.s_addr, 4); a->port = ntohs(if_sin->sin_port); a->type = TOPO_ADDR_REAL; 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 CFG_SERVER* srv = instance->config->servers; while (srv) { if (srv->transport && srv->ip.ss_family == AF_INET) { struct sockaddr_in* tcp_sin = (struct sockaddr_in*)&srv->ip; struct TOPO_ADDR4* a = memory_pool_alloc(group->instance->topo_groups->v4_addr_pool); memcpy(a->addr, &tcp_sin->sin_addr.s_addr, 4); a->port = ntohs(tcp_sin->sin_port); a->type = TOPO_ADDR_INTERFACE; a->socket_id = 0; a->protocol = TOPO_PROTO_TCP; a->next = ni->v4_addrs; ni->v4_addrs = a; } else if (srv->transport && srv->ip.ss_family == AF_INET6) { struct sockaddr_in6* tcp_sin6 = (struct sockaddr_in6*)&srv->ip; struct TOPO_ADDR6* a6 = memory_pool_alloc(group->instance->topo_groups->v6_addr_pool); memcpy(a6->addr, &tcp_sin6->sin6_addr, 16); a6->port = ntohs(tcp_sin6->sin6_port); a6->type = TOPO_ADDR_INTERFACE; a6->socket_id = 0; a6->protocol = TOPO_PROTO_TCP; a6->next = ni->v6_addrs; ni->v6_addrs = a6; } srv = srv->next; } } 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; } DEBUG_INFO(DEBUG_CATEGORY_BGP, "my_nodeinfo updated: v4s=%d v4a=%d v6s=%d v6a=%d v4sub=%d v6sub=%d ver=%d", sock_count, addr_count, sock6_count, addr6_count, vc, vc6, ni->ver); 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 { group->local_node->last_ver = group->local_node->node->ver; } return vc; }