#include #include #include #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 "etcp_debug.h" /** * @brief Получает указатель на массив IPv4-подсетей узла (без malloc/копирования). * * Функция вычисляет смещение внутри динамической части BGP_NODEINFO_Q * и возвращает прямой указатель на массив struct BGP_NODEINFO_IPV4_SUBNET. * * @param node Указатель на BGP_NODEINFO_Q * @param out_subnets [out] сюда будет записан указатель на первый элемент массива * (NULL если подсетей нет) * @return количество подсетей (>= 0) или -1 при ошибке */ int get_node_v4_sockets(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_SOCKET **out_sockets) { if (!node || !out_sockets) { return -1; } *out_sockets = NULL; const struct NODEINFO *info = &node->node; if (info->local_v4_sockets == 0) { return 0; } const uint8_t *dynamic = (const uint8_t *)&node->node + sizeof(struct NODEINFO); dynamic += info->node_name_len; *out_sockets = (const struct NODEINFO_IPV4_SOCKET *)dynamic; DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "get_node_v4_sockets: returned %u IPv4 sockets from node %p", (unsigned)info->local_v4_sockets, (void*)node); return (int)info->local_v4_sockets; } int get_node_v6_sockets(struct NODEINFO_Q *node, const struct NODEINFO_IPV6_SOCKET **out_sockets) { if (!node || !out_sockets) { return -1; } *out_sockets = NULL; const struct NODEINFO *info = &node->node; if (info->local_v6_sockets == 0) { return 0; } const uint8_t *dynamic = (const uint8_t *)&node->node + sizeof(struct NODEINFO); dynamic += info->node_name_len; dynamic += info->local_v4_sockets * sizeof(struct NODEINFO_IPV4_SOCKET); *out_sockets = (const struct NODEINFO_IPV6_SOCKET *)dynamic; DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "get_node_v6_sockets: returned %u IPv6 sockets from node %p", (unsigned)info->local_v6_sockets, (void*)node); return (int)info->local_v6_sockets; } 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; // успех, но нет подсетей } // Начало динамических полей сразу после фиксированной части NODEINFO const uint8_t *dynamic = (const uint8_t *)&node->node + sizeof(struct NODEINFO); // 1. Пропускаем node_name dynamic += info->node_name_len; // 2. Пропускаем local_v4_sockets dynamic += info->local_v4_sockets * sizeof(struct NODEINFO_IPV4_SOCKET); // 3. Пропускаем local_v6_sockets dynamic += info->local_v6_sockets * sizeof(struct NODEINFO_IPV6_SOCKET); // Теперь dynamic указывает точно на начало массива NODEINFO_IPV4_SUBNET *out_subnets = (const struct NODEINFO_IPV4_SUBNET *)dynamic; DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "get_node_routes: returned %u IPv4 subnets from node %p", (unsigned)info->local_v4_subnets, (void*)node); return (int)info->local_v4_subnets; } 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; struct CFG_ROUTE_ENTRY* s = instance->config->my_subnets; while (s) { if (s->ip.family == AF_INET) vc++; s = s->next; } int sock_count = 0; struct ETCP_SOCKET* e_sock = instance->etcp_sockets; while (e_sock) { if (e_sock->local_addr.ss_family == AF_INET) sock_count++; e_sock = e_sock->next; } size_t dyn = name_len + sock_count * sizeof(struct NODEINFO_IPV4_SOCKET) + vc * sizeof(struct NODEINFO_IPV4_SUBNET); if (!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 = 1; bgp->local_node->dirty = 1; bgp->local_node->last_ver = 1; bgp->local_node->node.local_v4_sockets = sock_count; bgp->local_node->node.local_v4_subnets = vc; bgp->local_node->node.node_name_len = name_len; memcpy(bgp->local_node->node.public_key, instance->my_keys.public_key, SC_PUBKEY_SIZE); } int changed = (vc != (int)bgp->local_node->node.local_v4_subnets) || (sock_count != (int)bgp->local_node->node.local_v4_sockets) || (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); if (!changed && vc > 0) { uint8_t* current = (uint8_t*)&bgp->local_node->node + sizeof(struct NODEINFO); current += name_len + sock_count * sizeof(struct NODEINFO_IPV4_SOCKET); struct NODEINFO_IPV4_SUBNET* ra = (struct NODEINFO_IPV4_SUBNET*)current; s = instance->config->my_subnets; bool same = true; while (s) { if (s->ip.family == AF_INET) { if (memcmp(ra->addr, &s->ip.addr.v4, 4) != 0 || ra->prefix_length != s->netmask) { same = false; break; } ra++; } s = s->next; } changed = !same; } if (!changed && sock_count > 0) { uint8_t* current = (uint8_t*)&bgp->local_node->node + sizeof(struct NODEINFO); current += name_len; struct NODEINFO_IPV4_SOCKET* sa = (struct NODEINFO_IPV4_SOCKET*)current; e_sock = instance->etcp_sockets; bool same = true; 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; uint8_t nat_addr_cmp[4] = {0}; uint16_t nat_port_cmp = 0; if (e_sock->nat_addr.ss_family == AF_INET) { memcpy(nat_addr_cmp, &nat_sin->sin_addr.s_addr, 4); nat_port_cmp = ntohs(nat_sin->sin_port); } if (memcmp(sa->addr, &if_sin->sin_addr.s_addr, 4) != 0 || sa->port != ntohs(if_sin->sin_port) || memcmp(sa->nat_addr, nat_addr_cmp, 4) != 0 || sa->nat_port != nat_port_cmp || sa->type != e_sock->nat_type || sa->id != e_sock->sock_id) { same = false; break; } sa++; } e_sock = e_sock->next; } changed = !same; } if (changed) { if (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; uint8_t oldv = bgp->local_node->node.ver; bgp->local_node->node.ver = ((oldv + 1) % 255) + 1; bgp->local_node->node.local_v4_sockets = sock_count; bgp->local_node->node.local_v4_subnets = vc; bgp->local_node->node.node_name_len = name_len; memcpy(bgp->local_node->node.public_key, instance->my_keys.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; } struct NODEINFO_IPV4_SOCKET* sa = (struct NODEINFO_IPV4_SOCKET*)dp; 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(sa->addr, &if_sin->sin_addr.s_addr, 4); sa->port = ntohs(if_sin->sin_port); sa->type = e_sock->nat_type; sa->id = e_sock->sock_id; if (e_sock->nat_addr.ss_family == AF_INET) { memcpy(sa->nat_addr, &nat_sin->sin_addr.s_addr, 4); sa->nat_port = ntohs(nat_sin->sin_port); } else { memset(sa->nat_addr, 0, 4); sa->nat_port = 0; } DEBUG_INFO(DEBUG_CATEGORY_BGP, "NODEINFO socket: addr=0x%02x%02x%02x%02x port=%u nat=0x%02x%02x%02x%02x:%u", sa->addr[0], sa->addr[1], sa->addr[2], sa->addr[3], sa->port, sa->nat_addr[0], sa->nat_addr[1], sa->nat_addr[2], sa->nat_addr[3], sa->nat_port); sa++; } e_sock = e_sock->next; } dp = (uint8_t*)sa; 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; } } else { bgp->local_node->last_ver = bgp->local_node->node.ver; } return vc; }