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.
 
 
 
 
 
 

247 lines
10 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 "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;
}