/** * @file topo_node.h * @brief Модель данных узла сети — структуры, сериализация, wire-формат. * * Этот модуль определяет: * - Как узел представлен в памяти (TOPO_NODE, TOPO_GROUP_NODE, адреса, подсети) * - Как узел передаётся по сети (packed-структуры TOPOMSG_*) * - Как узел сериализуется/десериализуется (topo_node_serialize/deserialize) * * Хранение: * - Идентичность узла (pubkeys, адреса, имя) — в глобальном реестре TOPO_GROUPS->node_registry * Единственный экземпляр TOPO_NODE, разделяется между группами через group_ref_count. * - Per-group данные (node_id, paths, subnets, connectivity) — в TOPO_GROUP->nodes (очередь TOPO_GROUP_NODE) * * Основные понятия: * TOPO_NODE — глобальная идентичность узла. Встроен в node_registry как queue entry. * TOPO_GROUP_NODE — узел в контексте группы: node_id + paths, hop_list, связность * TOPO_NODEPATH — путь до узла через конкретное ETCP-соединение * TOPOMSG_NODE — wire-формат, передаваемый по NODEINFO */ #ifndef TOPO_NODE_H #define TOPO_NODE_H #ifdef __cplusplus extern "C" { #endif #include #include #include "../lib/ll_queue.h" #include "secure_channel.h" struct TOPO_GROUP; struct TOPO_GROUPS; struct ETCP_SOCKET; struct ETCP_LINK; struct NODE_CONN_DIRECT; struct ETCP_CONN; struct UTUN_INSTANCE; #define TOPO_ADDR_INTERFACE 0 #define TOPO_ADDR_NAT 1 #define TOPO_ADDR_REAL 2 #define TOPO_PROTO_UDP 0x01 #define TOPO_PROTO_TCP 0x02 #define TOPO_PROTO_REALITY 0x04 /* флаг reality-камуфляжа поверх TCP (reality-TCP = 0x06) */ #define ADDR_TYPE_NETIF 0 #define ADDR_TYPE_DIRECT 1 #define ADDR_TYPE_NAT_EIM 2 #define ADDR_TYPE_NAT_STRICT 3 #define ADDR_TYPE_NAT 4 /* за NAT, тип неизвестен */ #define PROBE_STATUS_NONE 0 #define PROBE_STATUS_IN_PROGRESS 1 #define PROBE_STATUS_DONE 2 #define PROBE_STATUS_DEFERRED 3 /* отложена до следующего burst (standby_wait) */ #define PROBE_RESULT_UNKNOWN 0 #define PROBE_RESULT_REACHABLE 1 #define PROBE_RESULT_UNREACHABLE 2 #define CONN_PROBE_COUNT 3 #define CONN_PROBE_TIMEOUT_MS 1000 #define CONN_TYPE_NONE 0 #define CONN_TYPE_DIRECT 1 #define CONN_TYPE_REVERSE 2 #define CONN_TYPE_INDIRECT 3 #define CLIENT_TYPE_SERVER 0 #define CLIENT_TYPE_DESKTOP 1 #define CLIENT_TYPE_MOBILE 2 #define CLIENT_ACTIVITY_STANDBY 0 #define CLIENT_ACTIVITY_ACTIVE 1 #define CONN_MGR_MAX_INTERMEDIARIES 3 #define NCONN_DIRECT (1 << 0) // прямое ETCP подключение #define NCONN_INDIRECT (1 << 1) // через посредника #define NCONN_BGP (1 << 2) // узел виден в топологии (BGP) #define TOPO_FLAG_SEND_SUBNETS 0x01 #define TOPO_FLAG_RADIO 0x02 #define TOPO_GROUP_UTUN 0x8000000000000000ULL #define TOPO_GROUP_TYPE_UTUN 1 #define TOPO_GROUP_TYPE_CHAT 2 struct TOPO_CONNECTIVITY { uint8_t probe_status; uint8_t pending_count; uint64_t probe_start_time; uint16_t interface_min_rtt; uint16_t nat_min_rtt; uint16_t real_min_rtt; uint8_t interface_status; uint8_t nat_status; uint8_t real_status; uint8_t reserved; uint64_t interface_probe_time; uint64_t nat_probe_time; uint64_t real_probe_time; uint64_t ping_req_time; uint64_t last_ping_time; void* probe_list; void* probe_deferred_wait; /* контекст отложенной пробы (standby_wait, Android) */ }; #define PING_TTL_TB (86400ULL * 10000ULL) struct TOPOMSG_SOCKMETA4 { uint8_t id, config_type, nat_type; } __attribute__((packed)); struct TOPOMSG_ADDR4 { uint8_t addr[4]; uint16_t port; uint8_t type, socket_id, protocol; } __attribute__((packed)); struct TOPOMSG_SOCKMETA6 { uint8_t id, config_type, nat_type; } __attribute__((packed)); struct TOPOMSG_ADDR6 { uint8_t addr[16]; uint16_t port; uint8_t type, socket_id, protocol; } __attribute__((packed)); struct TOPOMSG_SUBNET4 { uint8_t addr[4]; uint8_t prefix_length; } __attribute__((packed)); struct TOPOMSG_SUBNET6 { uint8_t addr[16]; uint8_t prefix_length; } __attribute__((packed)); /* Reality-камуфляж сокета: что нужно клиенту для подключения к reality TCP-сокету. * short_id(8) + server_pubkey(32) + version(3) + server_name(фиксированный 64). */ #define TOPO_REALITY_SNAME_MAX 64 struct TOPOMSG_REALITY_SOCK { uint8_t socket_id; uint8_t short_id[8]; uint8_t server_pubkey[32]; uint8_t version[3]; uint8_t server_name[TOPO_REALITY_SNAME_MAX]; } __attribute__((packed)); struct TOPOMSG_NODE { uint8_t flags; uint64_t group_id, node_id; uint8_t ver; uint8_t public_key[SC_PUBKEY_SIZE], ed25519_public_key[SC_PUBKEY_SIZE]; uint8_t x25519_self_sig[64]; uint8_t node_name_len, local_v4_sockets, local_v4_addrs, local_v6_sockets, local_v6_addrs; uint8_t local_v4_subnets, local_v6_subnets, hop_count; uint8_t local_reality_socks; // кол-во reality-сокетов uint8_t client_type; // CLIENT_TYPE_SERVER/DESKTOP/MOBILE uint8_t client_activity; // CLIENT_ACTIVITY_STANDBY/ACTIVE uint16_t cumulative_rtt; } __attribute__((packed)); #define TOPOMSG_NODE_HDR_SIZE sizeof(struct TOPOMSG_NODE) struct TOPO_SOCKMETA4 { struct TOPO_SOCKMETA4* next; uint8_t id, config_type, nat_type; }; struct TOPO_ADDR4 { struct TOPO_ADDR4* next; uint8_t addr[4]; uint16_t port; uint8_t type, socket_id, protocol; }; struct TOPO_SOCKMETA6 { struct TOPO_SOCKMETA6* next; uint8_t id, config_type, nat_type; }; struct TOPO_ADDR6 { struct TOPO_ADDR6* next; uint8_t addr[16]; uint16_t port; uint8_t type, socket_id, protocol; }; struct TOPO_SUBNET4 { struct TOPO_SUBNET4* next; uint8_t addr[4]; uint8_t prefix_length; }; struct TOPO_SUBNET6 { struct TOPO_SUBNET6* next; uint8_t addr[16]; uint8_t prefix_length; }; /* Reality-камуфляж сокета (in-memory): per-socket список, значения на узел одинаковы. */ struct TOPO_REALITY_SOCK { struct TOPO_REALITY_SOCK* next; uint8_t socket_id; uint8_t short_id[8]; uint8_t server_pubkey[32]; uint8_t version[3]; char server_name[TOPO_REALITY_SNAME_MAX]; }; /* Reality-параметры адреса для персистенции в node_addresses.options (BLOB, фиксированный размер). */ #define TOPO_ADDR_REALITY_OPTS_SIZE 107 struct TOPO_ADDR_REALITY_OPTS { uint8_t short_id[8]; uint8_t server_pubkey[32]; uint8_t version[3]; char server_name[TOPO_REALITY_SNAME_MAX]; }; struct _topo_head { struct _topo_head* next; }; static inline int topo_list_count(struct _topo_head* head) { int n = 0; while (head) { n++; head = head->next; } return n; } /** Глобальная идентичность узла. Встроен в TOPO_GROUPS->node_registry как queue entry. */ struct TOPO_NODE { struct ll_entry ll; uint32_t group_ref_count; uint64_t node_id; uint8_t ver; uint8_t public_key[SC_PUBKEY_SIZE], ed25519_public_key[SC_PUBKEY_SIZE]; uint8_t x25519_self_sig[64]; uint8_t client_type; // CLIENT_TYPE_SERVER/DESKTOP/MOBILE uint8_t client_activity; // CLIENT_ACTIVITY_STANDBY/ACTIVE char* node_name; struct TOPO_SOCKMETA4* v4_sock_meta; struct TOPO_ADDR4* v4_addrs; struct TOPO_SOCKMETA6* v6_sock_meta; struct TOPO_ADDR6* v6_addrs; struct TOPO_REALITY_SOCK* reality_socks; // reality-камуфляж сокетов (per-socket, значения на узел) }; struct TOPO_NODESUBNETS { struct TOPO_SUBNET4* v4_subnets; struct TOPO_SUBNET6* v6_subnets; }; struct TOPO_NODEPATH { struct ll_entry ll; struct ETCP_CONN* conn; uint8_t hop_count; uint16_t cumulative_rtt; }; /** Узел в контексте группы (per-group данные). Хранится в TOPO_GROUP->nodes (ll_queue). */ struct TOPO_GROUP_NODE { struct ll_entry ll; // queue entry, хеш-ключ 8 байт → node_id uint64_t node_id; // идентификатор узла в этой группе struct TOPO_NODESUBNETS* subnets; // подсети узла (v4/v6), для route_insert() struct ll_queue* paths; // TOPO_NODEPATH{conn,hop_count,rtt} — маршруты uint8_t last_ver; // последняя версия NODEINFO (защита от stale, BGP) uint8_t conn_mgr_type; // CONN_TYPE_DIRECT/REVERSE/INDIRECT/NONE uint64_t conn_mgr_intermediaries[CONN_MGR_MAX_INTERMEDIARIES]; // посредники для INDIRECT uint8_t conn_mgr_intermediariy_count; // количество посредников struct TOPO_CONNECTIVITY connectivity; // результаты ping-проб (interface/nat/real) uint8_t conn_presence; // NODE_CONN_* — какие подключения есть в принципе uint8_t conn_up; // NODE_CONN_* — какие из них подняты uint8_t radio; // 1 = узел слушает рацию канала (TOPO_FLAG_RADIO) struct NODE_CONN_DIRECT* handle; // активный ncd-handle прямого соединения к узлу }; // API — глобальный реестр TOPO_NODE struct TOPO_NODE* topo_node_registry_find(struct TOPO_GROUPS* groups, uint64_t node_id); struct TOPO_NODE* topo_node_registry_store(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni); void topo_node_registry_ref(struct TOPO_GROUPS* groups, uint64_t node_id); void topo_node_registry_unref(struct TOPO_GROUPS* groups, uint64_t node_id); void topo_node_destroy(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni); // API — per-group struct TOPO_GROUP_NODE* topo_node_find_by_id(struct TOPO_GROUP* group, uint64_t node_id); void topo_nodeq_free_group_fields(struct TOPO_GROUPS* groups, struct TOPO_GROUP_NODE* nq); /* Полное удаление узла из группы: отменяет влётные пробы, освобождает paths/subnets, * убирает из group->nodes и освобождает сам nq. Единственный корректный способ удаления узла. */ void topo_nodeq_remove_node(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* nq); int topo_node_dyn_size(const struct TOPOMSG_NODE* msg); int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq, uint64_t group_id, uint8_t flags, uint8_t* out, size_t out_max, uint16_t cumulative_rtt); 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); uint64_t* topo_node_best_hop_list(struct TOPO_GROUP_NODE* nq, uint8_t* out_count, uint16_t* out_rtt); int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GROUP* group); int topo_node_update_my_addresses(struct UTUN_INSTANCE* instance); /* 1=changed, 0=unchanged, -1=error */ void topo_node_on_socket_changed(struct ETCP_SOCKET* sock, int event, void* arg); void topo_node_dump_all(struct TOPO_GROUP* group); int topo_node_format_all(struct TOPO_GROUP* group, char* buf, size_t buf_size); int topo_node_ping_request_cbk(struct TOPO_GROUPS* groups, uint64_t node_id); void topo_node_ping_update_rtt(struct TOPO_GROUPS* groups, uint64_t node_id, uint16_t rtt); uint16_t topo_get_chain_rtt(struct TOPO_GROUP_NODE* nq); /** Build canonical message for Ed25519 signature: x25519_pubkey || name || client_type || client_activity || addresses */ #define TOPO_SIG_MSG_MAX_SIZE 2048 int topo_node_build_sig_msg(struct TOPO_NODE* ni, uint8_t* buf, size_t buf_size); /** Sign self NODEINFO with Ed25519: build_sig_msg + sc_ed25519_sign → ni->x25519_self_sig */ void topo_node_sign_self(struct UTUN_INSTANCE* instance, struct TOPO_NODE* ni); static inline const struct TOPO_SOCKMETA4* topo_v4_sock_meta(const struct TOPO_NODE* ni) { return ni->v4_sock_meta; } static inline const struct TOPO_ADDR4* topo_v4_addrs(const struct TOPO_NODE* ni) { return ni->v4_addrs; } static inline const struct TOPO_SOCKMETA6* topo_v6_sock_meta(const struct TOPO_NODE* ni) { return ni->v6_sock_meta; } static inline const struct TOPO_ADDR6* topo_v6_addrs(const struct TOPO_NODE* ni) { return ni->v6_addrs; } static inline const struct TOPO_SUBNET4* topo_v4_subnets(const struct TOPO_NODESUBNETS* r) { return r ? r->v4_subnets : NULL; } static inline const struct TOPO_SUBNET6* topo_v6_subnets(const struct TOPO_NODESUBNETS* r) { return r ? r->v6_subnets : NULL; } /* Найти reality-инфо сокета по socket_id (NULL, если сокет без reality). */ const struct TOPO_REALITY_SOCK* topo_node_find_reality_sock(const struct TOPO_NODE* ni, uint8_t socket_id); /* Заполнить link->reality из reality-инфо пира (rs из BGP). link->reality_set = 1. */ void topo_node_apply_reality(struct ETCP_LINK* link, const struct TOPO_REALITY_SOCK* rs); #ifdef __cplusplus } #endif #endif