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.
623 lines
29 KiB
623 lines
29 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 "utun_instance.h" |
|
#include "etcp.h" |
|
#include "config_parser.h" |
|
#include "route_node.h" |
|
#include "route_bgp.h" |
|
#include "route_lib.h" |
|
#include "etcp_debug.h" |
|
|
|
static const uint8_t* node_dyn_start(const struct NODEINFO* info) { |
|
return (const uint8_t*)info + sizeof(struct NODEINFO); |
|
} |
|
|
|
static const uint8_t* skip_name(const uint8_t* p, uint8_t name_len) { |
|
return p + name_len; |
|
} |
|
|
|
static const uint8_t* skip_v4_sockets_meta(const uint8_t* p, uint8_t count) { |
|
return p + count * sizeof(struct NODEINFO_IPV4_SOCKET_META); |
|
} |
|
|
|
static const uint8_t* skip_v4_addrs(const uint8_t* p, uint8_t count) { |
|
return p + count * sizeof(struct NODEINFO_IPV4_ADDR); |
|
} |
|
|
|
static const uint8_t* skip_v6_sockets_meta(const uint8_t* p, uint8_t count) { |
|
return p + count * sizeof(struct NODEINFO_IPV6_SOCKET_META); |
|
} |
|
|
|
static const uint8_t* skip_v6_addrs(const uint8_t* p, uint8_t count) { |
|
return p + count * sizeof(struct NODEINFO_IPV6_ADDR); |
|
} |
|
|
|
static const uint8_t* skip_v4_subnets(const uint8_t* p, uint8_t count) { |
|
return p + count * sizeof(struct NODEINFO_IPV4_SUBNET); |
|
} |
|
|
|
int get_node_v4_sockets_meta(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_SOCKET_META **out_meta) { |
|
if (!node || !out_meta) return -1; |
|
*out_meta = NULL; |
|
const struct NODEINFO *info = &node->node; |
|
if (info->local_v4_sockets == 0) return 0; |
|
const uint8_t *dynamic = node_dyn_start(info); |
|
dynamic = skip_name(dynamic, info->node_name_len); |
|
*out_meta = (const struct NODEINFO_IPV4_SOCKET_META *)dynamic; |
|
return (int)info->local_v4_sockets; |
|
} |
|
|
|
int get_node_v4_addrs(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_ADDR **out_addrs) { |
|
if (!node || !out_addrs) return -1; |
|
*out_addrs = NULL; |
|
const struct NODEINFO *info = &node->node; |
|
if (info->local_v4_addrs == 0) return 0; |
|
const uint8_t *dynamic = node_dyn_start(info); |
|
dynamic = skip_name(dynamic, info->node_name_len); |
|
dynamic = skip_v4_sockets_meta(dynamic, info->local_v4_sockets); |
|
*out_addrs = (const struct NODEINFO_IPV4_ADDR *)dynamic; |
|
return (int)info->local_v4_addrs; |
|
} |
|
|
|
int get_node_v6_sockets_meta(struct NODEINFO_Q *node, const struct NODEINFO_IPV6_SOCKET_META **out_meta) { |
|
if (!node || !out_meta) return -1; |
|
*out_meta = NULL; |
|
const struct NODEINFO *info = &node->node; |
|
if (info->local_v6_sockets == 0) return 0; |
|
const uint8_t *dynamic = node_dyn_start(info); |
|
dynamic = skip_name(dynamic, info->node_name_len); |
|
dynamic = skip_v4_sockets_meta(dynamic, info->local_v4_sockets); |
|
dynamic = skip_v4_addrs(dynamic, info->local_v4_addrs); |
|
*out_meta = (const struct NODEINFO_IPV6_SOCKET_META *)dynamic; |
|
return (int)info->local_v6_sockets; |
|
} |
|
|
|
int get_node_v6_addrs(struct NODEINFO_Q *node, const struct NODEINFO_IPV6_ADDR **out_addrs) { |
|
if (!node || !out_addrs) return -1; |
|
*out_addrs = NULL; |
|
const struct NODEINFO *info = &node->node; |
|
if (info->local_v6_addrs == 0) return 0; |
|
const uint8_t *dynamic = node_dyn_start(info); |
|
dynamic = skip_name(dynamic, info->node_name_len); |
|
dynamic = skip_v4_sockets_meta(dynamic, info->local_v4_sockets); |
|
dynamic = skip_v4_addrs(dynamic, info->local_v4_addrs); |
|
dynamic = skip_v6_sockets_meta(dynamic, info->local_v6_sockets); |
|
*out_addrs = (const struct NODEINFO_IPV6_ADDR *)dynamic; |
|
return (int)info->local_v6_addrs; |
|
} |
|
|
|
int get_node_routes(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_SUBNET **out_subnets) { |
|
if (!node || !out_subnets) return -1; |
|
*out_subnets = NULL; |
|
const struct NODEINFO *info = &node->node; |
|
if (info->local_v4_subnets == 0) return 0; |
|
const uint8_t *dynamic = node_dyn_start(info); |
|
dynamic = skip_name(dynamic, info->node_name_len); |
|
dynamic = skip_v4_sockets_meta(dynamic, info->local_v4_sockets); |
|
dynamic = skip_v4_addrs(dynamic, info->local_v4_addrs); |
|
dynamic = skip_v6_sockets_meta(dynamic, info->local_v6_sockets); |
|
dynamic = skip_v6_addrs(dynamic, info->local_v6_addrs); |
|
*out_subnets = (const struct NODEINFO_IPV4_SUBNET *)dynamic; |
|
return (int)info->local_v4_subnets; |
|
} |
|
|
|
int get_node_v6_routes(struct NODEINFO_Q *node, const struct NODEINFO_IPV6_SUBNET **out_subnets) { |
|
if (!node || !out_subnets) return -1; |
|
*out_subnets = NULL; |
|
const struct NODEINFO *info = &node->node; |
|
if (info->local_v6_subnets == 0) return 0; |
|
const uint8_t *dynamic = node_dyn_start(info); |
|
dynamic = skip_name(dynamic, info->node_name_len); |
|
dynamic = skip_v4_sockets_meta(dynamic, info->local_v4_sockets); |
|
dynamic = skip_v4_addrs(dynamic, info->local_v4_addrs); |
|
dynamic = skip_v6_sockets_meta(dynamic, info->local_v6_sockets); |
|
dynamic = skip_v6_addrs(dynamic, info->local_v6_addrs); |
|
dynamic = skip_v4_subnets(dynamic, info->local_v4_subnets); |
|
*out_subnets = (const struct NODEINFO_IPV6_SUBNET *)dynamic; |
|
return (int)info->local_v6_subnets; |
|
} |
|
|
|
struct NODEINFO_Q* nodeinfo_find_by_id(struct ROUTE_BGP* bgp, uint64_t node_id) { |
|
if (!bgp || !bgp->nodes) return NULL; |
|
uint64_t key = node_id; |
|
struct ll_entry* e = queue_find_data_by_index(bgp->nodes, &key); |
|
return e ? (struct NODEINFO_Q*)e : NULL; |
|
} |
|
|
|
static int is_node_connectivity_active(struct NODE_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 route_node_dump_all(struct ROUTE_BGP* bgp) { |
|
if (!bgp || !bgp->nodes) return; |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "=== BGP Nodes dump: %d nodes ===", queue_entry_count(bgp->nodes)); |
|
|
|
int idx = 0; |
|
struct ll_entry* e = bgp->nodes->head; |
|
while (e) { |
|
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)e; |
|
struct NODEINFO* ni = &nq->node; |
|
int is_local = (bgp->local_node == nq); |
|
const char* name_s = (ni->node_name_len > 0) ? (const char*)((const uint8_t*)ni + sizeof(struct NODEINFO)) : ""; |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "--- Node #%d: id=%016llx name=\"%.*s\" ver=%u dirty=%u alien=%u%s ---", |
|
idx, (unsigned long long)ni->node_id, ni->node_name_len, name_s, |
|
ni->ver, nq->dirty, nq->alien, 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); |
|
|
|
const struct NODEINFO_IPV4_SOCKET_META* v4sm; |
|
int v4sm_cnt = get_node_v4_sockets_meta(nq, &v4sm); |
|
if (v4sm_cnt > 0) for (int i = 0; i < v4sm_cnt; i++) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v4sock[%d]: id=%u type=%u", i, v4sm[i].id, v4sm[i].type); |
|
} |
|
|
|
const struct NODEINFO_IPV4_ADDR* v4a; |
|
int v4a_cnt = get_node_v4_addrs(nq, &v4a); |
|
if (v4a_cnt > 0) { |
|
const char* atn[] = {"INTERFACE","NAT","REAL"}; |
|
for (int i = 0; i < v4a_cnt; i++) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v4addr[%d]: %s:%u %s sock=%u", |
|
i, ip_to_str(v4a[i].addr, AF_INET).str, v4a[i].port, |
|
(v4a[i].type<=2)?atn[v4a[i].type]:"?", v4a[i].socket_id); |
|
} |
|
} |
|
|
|
const struct NODEINFO_IPV6_SOCKET_META* v6sm; |
|
int v6sm_cnt = get_node_v6_sockets_meta(nq, &v6sm); |
|
if (v6sm_cnt > 0) for (int i = 0; i < v6sm_cnt; i++) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v6sock[%d]: id=%u type=%u", i, v6sm[i].id, v6sm[i].type); |
|
} |
|
|
|
const struct NODEINFO_IPV6_ADDR* v6a; |
|
int v6a_cnt = get_node_v6_addrs(nq, &v6a); |
|
if (v6a_cnt > 0) { |
|
for (int i = 0; i < v6a_cnt; i++) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v6addr[%d]: %s:%u type=%u sock=%u", |
|
i, ip_to_str(v6a[i].addr, AF_INET6).str, v6a[i].port, |
|
v6a[i].type, v6a[i].socket_id); |
|
} |
|
} |
|
|
|
const struct NODEINFO_IPV4_SUBNET* sub4; |
|
int sub4_cnt = get_node_routes(nq, &sub4); |
|
if (sub4_cnt > 0) for (int i = 0; i < sub4_cnt; i++) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v4sub[%d]: %s/%d", i, |
|
ip_to_str(sub4[i].addr, AF_INET).str, sub4[i].prefix_length); |
|
} |
|
|
|
const struct NODEINFO_IPV6_SUBNET* sub6; |
|
int sub6_cnt = get_node_v6_routes(nq, &sub6); |
|
if (sub6_cnt > 0) for (int i = 0; i < sub6_cnt; i++) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " v6sub[%d]: %s/%d", i, |
|
ip_to_str(sub6[i].addr, AF_INET6).str, sub6[i].prefix_length); |
|
} |
|
|
|
if (ni->tranzit_nodes > 0) { |
|
const uint8_t* dyn = node_dyn_start(ni); |
|
dyn = skip_name(dyn, ni->node_name_len); |
|
dyn = skip_v4_sockets_meta(dyn, ni->local_v4_sockets); |
|
dyn = skip_v4_addrs(dyn, ni->local_v4_addrs); |
|
dyn = skip_v6_sockets_meta(dyn, ni->local_v6_sockets); |
|
dyn = skip_v6_addrs(dyn, ni->local_v6_addrs); |
|
dyn = skip_v4_subnets(dyn, ni->local_v4_subnets); |
|
const struct NODEINFO_IPV6_SUBNET* sub6_dyn = (const struct NODEINFO_IPV6_SUBNET*)dyn; |
|
dyn += ni->local_v6_subnets * sizeof(struct NODEINFO_IPV6_SUBNET); |
|
const struct NODEINFO_TRANZIT_NODE* tr = (const struct NODEINFO_TRANZIT_NODE*)dyn; |
|
for (uint8_t i = 0; i < ni->tranzit_nodes; i++) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, " tranzit[%d]: node=%016llx rtt=%u linkq=%u", |
|
i, (unsigned long long)tr[i].node_id, tr[i].rtt, tr[i].link_q); |
|
} |
|
} |
|
|
|
int path_idx = 0; |
|
if (nq->paths) { |
|
struct ll_entry* pe = nq->paths->head; |
|
while (pe) { |
|
struct NODEINFO_PATH* path = (struct NODEINFO_PATH*)pe; |
|
uint64_t* hop = (uint64_t*)((uint8_t*)path + sizeof(struct NODEINFO_PATH)); |
|
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 NODE_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 route_node_format_all(struct ROUTE_BGP* bgp, char* buf, size_t buf_size) { |
|
if (!bgp || !bgp->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(bgp->nodes)); |
|
|
|
int idx = 0; |
|
struct ll_entry* e = bgp->nodes->head; |
|
while (e && (size_t)pos < buf_size) { |
|
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)e; |
|
struct NODEINFO* ni = &nq->node; |
|
int is_local = (bgp->local_node == nq); |
|
const char* name_s = (ni->node_name_len > 0) ? (const char*)((const uint8_t*)ni + sizeof(struct NODEINFO)) : ""; |
|
|
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, |
|
"--- Node #%d: id=%016llx name=\"%.*s\" ver=%u dirty=%u alien=%u%s ---\n", |
|
idx, (unsigned long long)ni->node_id, ni->node_name_len, name_s, |
|
ni->ver, nq->dirty, nq->alien, is_local ? " [LOCAL]" : ""); |
|
|
|
if (nq->best_socket) |
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, |
|
" best_socket=%p\n", (void*)nq->best_socket); |
|
|
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, " pubkey: "); |
|
for (int k = 0; k < SC_PUBKEY_SIZE; k++) |
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, "%02x", ni->public_key[k]); |
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, "\n"); |
|
|
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, " ed25519: "); |
|
for (int k = 0; k < SC_PUBKEY_SIZE; k++) |
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, "%02x", ni->ed25519_public_key[k]); |
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, "\n"); |
|
|
|
#define FMT_ADD(fmt, ...) \ |
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, fmt, ##__VA_ARGS__) |
|
|
|
const struct NODEINFO_IPV4_SOCKET_META* v4sm; |
|
int v4sm_cnt = get_node_v4_sockets_meta(nq, &v4sm); |
|
for (int i = 0; i < v4sm_cnt; i++) |
|
FMT_ADD(" v4sock[%d]: id=%u type=%u\n", i, v4sm[i].id, v4sm[i].type); |
|
|
|
const struct NODEINFO_IPV4_ADDR* v4a; |
|
int v4a_cnt = get_node_v4_addrs(nq, &v4a); |
|
if (v4a_cnt > 0) { |
|
const char* atn[] = {"INTERFACE","NAT","REAL"}; |
|
for (int i = 0; i < v4a_cnt; i++) |
|
FMT_ADD(" v4addr[%d]: %s:%u %s sock=%u\n", |
|
i, ip_to_str(v4a[i].addr, AF_INET).str, v4a[i].port, |
|
(v4a[i].type<=2)?atn[v4a[i].type]:"?", v4a[i].socket_id); |
|
} |
|
|
|
const struct NODEINFO_IPV6_SOCKET_META* v6sm; |
|
int v6sm_cnt = get_node_v6_sockets_meta(nq, &v6sm); |
|
for (int i = 0; i < v6sm_cnt; i++) |
|
FMT_ADD(" v6sock[%d]: id=%u type=%u\n", i, v6sm[i].id, v6sm[i].type); |
|
|
|
const struct NODEINFO_IPV6_ADDR* v6a; |
|
int v6a_cnt = get_node_v6_addrs(nq, &v6a); |
|
for (int i = 0; i < v6a_cnt; i++) |
|
FMT_ADD(" v6addr[%d]: %s:%u type=%u sock=%u\n", |
|
i, ip_to_str(v6a[i].addr, AF_INET6).str, v6a[i].port, |
|
v6a[i].type, v6a[i].socket_id); |
|
|
|
const struct NODEINFO_IPV4_SUBNET* sub4; |
|
int sub4_cnt = get_node_routes(nq, &sub4); |
|
for (int i = 0; i < sub4_cnt; i++) |
|
FMT_ADD(" v4sub[%d]: %s/%d\n", i, |
|
ip_to_str(sub4[i].addr, AF_INET).str, sub4[i].prefix_length); |
|
|
|
const struct NODEINFO_IPV6_SUBNET* sub6; |
|
int sub6_cnt = get_node_v6_routes(nq, &sub6); |
|
for (int i = 0; i < sub6_cnt; i++) |
|
FMT_ADD(" v6sub[%d]: %s/%d\n", i, |
|
ip_to_str(sub6[i].addr, AF_INET6).str, sub6[i].prefix_length); |
|
|
|
if (ni->tranzit_nodes > 0) { |
|
const uint8_t* dyn = node_dyn_start(ni); |
|
dyn = skip_name(dyn, ni->node_name_len); |
|
dyn = skip_v4_sockets_meta(dyn, ni->local_v4_sockets); |
|
dyn = skip_v4_addrs(dyn, ni->local_v4_addrs); |
|
dyn = skip_v6_sockets_meta(dyn, ni->local_v6_sockets); |
|
dyn = skip_v6_addrs(dyn, ni->local_v6_addrs); |
|
dyn = skip_v4_subnets(dyn, ni->local_v4_subnets); |
|
dyn += ni->local_v6_subnets * sizeof(struct NODEINFO_IPV6_SUBNET); |
|
const struct NODEINFO_TRANZIT_NODE* tr = (const struct NODEINFO_TRANZIT_NODE*)dyn; |
|
for (uint8_t i = 0; i < ni->tranzit_nodes; i++) |
|
FMT_ADD(" tranzit[%d]: node=%016llx rtt=%u linkq=%u\n", |
|
i, (unsigned long long)tr[i].node_id, tr[i].rtt, tr[i].link_q); |
|
} |
|
|
|
if (nq->paths) { |
|
int path_idx = 0; |
|
struct ll_entry* pe = nq->paths->head; |
|
while (pe) { |
|
struct NODEINFO_PATH* path = (struct NODEINFO_PATH*)pe; |
|
uint64_t* hop = (uint64_t*)((uint8_t*)path + sizeof(struct NODEINFO_PATH)); |
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, |
|
" path[%d]: conn=%s hop_count=%u hops=[", |
|
path_idx, path->conn ? path->conn->log_name : "NULL", path->hop_count); |
|
for (uint8_t hi = 0; hi < path->hop_count; hi++) |
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, |
|
"%s%016llx", hi ? "->" : "", (unsigned long long)hop[hi]); |
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, "]\n"); |
|
path_idx++; |
|
pe = pe->next; |
|
} |
|
} |
|
|
|
struct NODE_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) { |
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, |
|
" 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++) |
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, |
|
"%s%016llx", i ? "," : "", |
|
(unsigned long long)nq->conn_mgr_intermediaries[i]); |
|
pos += snprintf(buf + pos, buf_size > (size_t)pos ? buf_size - pos : 0, "]\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; |
|
} |
|
|
|
int route_bgp_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BGP* bgp) { |
|
if (!instance || !bgp) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_update_my_nodeinfo: 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; } |
|
|
|
int sock_count = 0, addr_count = 0; |
|
int sock6_count = 0, addr6_count = 0; |
|
struct ETCP_SOCKET* e_sock = instance->etcp_sockets; |
|
while (e_sock) { |
|
if (e_sock->local_addr.ss_family == AF_INET) { |
|
sock_count++; |
|
addr_count++; // INTERFACE |
|
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) { |
|
if (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->nat_type < NAT_VERIFIED_UNKNOWN)) addr_count++; |
|
} else if (e_sock->local_addr.ss_family == AF_INET6) { |
|
sock6_count++; |
|
addr6_count++; // INTERFACE only (no NAT for IPv6) |
|
} |
|
e_sock = e_sock->next; |
|
} |
|
|
|
size_t dyn = name_len + sock_count * sizeof(struct NODEINFO_IPV4_SOCKET_META) |
|
+ addr_count * sizeof(struct NODEINFO_IPV4_ADDR) |
|
+ sock6_count * sizeof(struct NODEINFO_IPV6_SOCKET_META) |
|
+ addr6_count * sizeof(struct NODEINFO_IPV6_ADDR) |
|
+ vc * sizeof(struct NODEINFO_IPV4_SUBNET) |
|
+ vc6 * sizeof(struct NODEINFO_IPV6_SUBNET); |
|
|
|
int changed = 1; |
|
uint8_t old_ver = 0; |
|
if (bgp->local_node) { |
|
old_ver = bgp->local_node->node.ver; |
|
changed = (vc != (int)bgp->local_node->node.local_v4_subnets) |
|
|| (sock_count != (int)bgp->local_node->node.local_v4_sockets) |
|
|| (addr_count != (int)bgp->local_node->node.local_v4_addrs) |
|
|| (name_len != bgp->local_node->node.node_name_len) |
|
|| (memcmp(bgp->local_node->node.public_key, instance->my_keys.public_key, SC_PUBKEY_SIZE) != 0) |
|
|| (vc6 != (int)bgp->local_node->node.local_v6_subnets) |
|
|| (sock6_count != (int)bgp->local_node->node.local_v6_sockets) |
|
|| (addr6_count != (int)bgp->local_node->node.local_v6_addrs); |
|
if (bgp->local_node && bgp->instance && bgp->instance->bgp) { |
|
if (memcmp(bgp->local_node->node.ed25519_public_key, bgp->instance->bgp->ed25519_public_key, SC_PUBKEY_SIZE) != 0) changed = 1; |
|
} |
|
} |
|
|
|
if (changed) { |
|
if (bgp->local_node) { |
|
if (instance->rt) route_delete(instance->rt, bgp->local_node); |
|
u_free(bgp->local_node); |
|
} |
|
bgp->local_node = u_calloc(1, sizeof(struct NODEINFO_Q) + dyn); |
|
if (!bgp->local_node) return -1; |
|
bgp->local_node->node.node_id = instance->node_id; |
|
bgp->local_node->node.hop_count = 0; |
|
bgp->local_node->node.ver = (old_ver % 255) + 1; |
|
bgp->local_node->node.local_v4_sockets = sock_count; |
|
bgp->local_node->node.local_v4_addrs = addr_count; |
|
bgp->local_node->node.local_v6_sockets = sock6_count; |
|
bgp->local_node->node.local_v6_addrs = addr6_count; |
|
bgp->local_node->node.local_v4_subnets = vc; |
|
bgp->local_node->node.local_v6_subnets = vc6; |
|
bgp->local_node->node.node_name_len = name_len; |
|
memcpy(bgp->local_node->node.public_key, instance->my_keys.public_key, SC_PUBKEY_SIZE); |
|
memcpy(bgp->local_node->node.ed25519_public_key, bgp->ed25519_public_key, SC_PUBKEY_SIZE); |
|
bgp->local_node->dirty = 1; |
|
bgp->local_node->last_ver = bgp->local_node->node.ver; |
|
|
|
uint8_t* dp = (uint8_t*)&bgp->local_node->node + sizeof(struct NODEINFO); |
|
if (name_len) { memcpy(dp, instance->name, name_len); dp += name_len; } |
|
|
|
// Write IPv4 socket meta |
|
struct NODEINFO_IPV4_SOCKET_META* meta = (struct NODEINFO_IPV4_SOCKET_META*)dp; |
|
e_sock = instance->etcp_sockets; |
|
int midx = 0; |
|
while (e_sock) { |
|
if (e_sock->local_addr.ss_family == AF_INET) { |
|
meta[midx].id = e_sock->sock_id; |
|
meta[midx].type = e_sock->nat_type; |
|
midx++; |
|
} |
|
e_sock = e_sock->next; |
|
} |
|
dp += sock_count * sizeof(struct NODEINFO_IPV4_SOCKET_META); |
|
|
|
// Write IPv4 addresses |
|
struct NODEINFO_IPV4_ADDR* addrs = (struct NODEINFO_IPV4_ADDR*)dp; |
|
int aidx = 0; |
|
e_sock = instance->etcp_sockets; |
|
while (e_sock) { |
|
if (e_sock->local_addr.ss_family == AF_INET) { |
|
struct sockaddr_in* if_sin = (struct sockaddr_in*)&e_sock->interface_addr; |
|
struct sockaddr_in* nat_sin = (struct sockaddr_in*)&e_sock->nat_addr; |
|
|
|
memcpy(addrs[aidx].addr, &if_sin->sin_addr.s_addr, 4); |
|
addrs[aidx].port = ntohs(if_sin->sin_port); |
|
addrs[aidx].type = ADDR_TYPE_INTERFACE; |
|
addrs[aidx].socket_id = e_sock->sock_id; |
|
aidx++; |
|
|
|
if (e_sock->nat_addr.ss_family == AF_INET && nat_sin->sin_addr.s_addr != 0) { |
|
if (e_sock->nat_type != NAT_VERIFIED_STRICT) { |
|
memcpy(addrs[aidx].addr, &nat_sin->sin_addr.s_addr, 4); |
|
addrs[aidx].port = ntohs(nat_sin->sin_port); |
|
addrs[aidx].type = ADDR_TYPE_NAT; |
|
addrs[aidx].socket_id = e_sock->sock_id; |
|
aidx++; |
|
} |
|
} |
|
if (e_sock->nat_type == NAT_VERIFIED_DIRECT || |
|
(e_sock->type == CFG_SERVER_TYPE_PUBLIC && e_sock->nat_type < NAT_VERIFIED_UNKNOWN)) { |
|
memcpy(addrs[aidx].addr, &if_sin->sin_addr.s_addr, 4); |
|
addrs[aidx].port = ntohs(if_sin->sin_port); |
|
addrs[aidx].type = ADDR_TYPE_REAL; |
|
addrs[aidx].socket_id = e_sock->sock_id; |
|
aidx++; |
|
} |
|
} |
|
e_sock = e_sock->next; |
|
} |
|
dp += addr_count * sizeof(struct NODEINFO_IPV4_ADDR); |
|
|
|
// Write IPv6 socket meta |
|
struct NODEINFO_IPV6_SOCKET_META* meta6 = (struct NODEINFO_IPV6_SOCKET_META*)dp; |
|
e_sock = instance->etcp_sockets; |
|
int m6idx = 0; |
|
while (e_sock) { |
|
if (e_sock->local_addr.ss_family == AF_INET6) { |
|
meta6[m6idx].id = e_sock->sock_id; |
|
meta6[m6idx].type = e_sock->nat_type; |
|
m6idx++; |
|
} |
|
e_sock = e_sock->next; |
|
} |
|
dp += sock6_count * sizeof(struct NODEINFO_IPV6_SOCKET_META); |
|
|
|
// Write IPv6 addresses (INTERFACE only) |
|
struct NODEINFO_IPV6_ADDR* addrs6 = (struct NODEINFO_IPV6_ADDR*)dp; |
|
int a6idx = 0; |
|
e_sock = instance->etcp_sockets; |
|
while (e_sock) { |
|
if (e_sock->local_addr.ss_family == AF_INET6) { |
|
struct sockaddr_in6* if_sin6 = (struct sockaddr_in6*)&e_sock->interface_addr; |
|
memcpy(addrs6[a6idx].addr, &if_sin6->sin6_addr, 16); |
|
addrs6[a6idx].port = ntohs(if_sin6->sin6_port); |
|
addrs6[a6idx].type = ADDR_TYPE_INTERFACE; |
|
addrs6[a6idx].socket_id = e_sock->sock_id; |
|
a6idx++; |
|
} |
|
e_sock = e_sock->next; |
|
} |
|
dp += addr6_count * sizeof(struct NODEINFO_IPV6_ADDR); |
|
|
|
// Write IPv4 subnets |
|
struct NODEINFO_IPV4_SUBNET* ra = (struct NODEINFO_IPV4_SUBNET*)dp; |
|
s = instance->config->my_subnets; |
|
while (s) { |
|
if (s->ip.family == AF_INET) { memcpy(ra->addr, &s->ip.addr.v4, 4); ra->prefix_length = s->netmask; ra++; } |
|
s = s->next; |
|
} |
|
dp += vc * sizeof(struct NODEINFO_IPV4_SUBNET); |
|
|
|
// Write IPv6 subnets |
|
struct NODEINFO_IPV6_SUBNET* ra6 = (struct NODEINFO_IPV6_SUBNET*)dp; |
|
s = instance->config->my_subnets; |
|
while (s) { |
|
if (s->ip.family == AF_INET6) { memcpy(ra6->addr, &s->ip.addr.v6, 16); ra6->prefix_length = s->netmask; ra6++; } |
|
s = s->next; |
|
} |
|
|
|
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, bgp->local_node->node.ver); |
|
if (instance->rt) { |
|
if (!route_insert(instance->rt, bgp->local_node)) |
|
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_bgp_update_my_nodeinfo: failed to re-insert local routes after update"); |
|
} |
|
} else { |
|
bgp->local_node->last_ver = bgp->local_node->node.ver; |
|
} |
|
return vc; |
|
}
|
|
|