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.
1007 lines
38 KiB
1007 lines
38 KiB
/** |
|
* @file route_bgp.c |
|
* @brief BGP-like обмен маршрутами — исправленная версия под новую route_lib |
|
*/ |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <stdio.h> |
|
#include "../lib/platform_compat.h" |
|
#include "../lib/debug_config.h" |
|
#include "../lib/mem.h" |
|
#include "utun_instance.h" |
|
#include "etcp_api.h" |
|
#include "etcp.h" |
|
#include "etcp_connections.h" |
|
#include "etcp_debug.h" |
|
#include "config_parser.h" |
|
#include "route_node.h" |
|
#include "route_lib.h" |
|
#include "route_bgp.h" |
|
#include "route_ping.h" |
|
|
|
|
|
// ============================================================================ |
|
// Вспомогательные функции |
|
// ============================================================================ |
|
|
|
static void route_bgp_send_table_request(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn) { |
|
if (!bgp || !conn) return; |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sending table request to %s", conn->log_name); |
|
struct BGP_ROUTE_REQUEST* req = u_calloc(1, sizeof(struct BGP_ROUTE_REQUEST)); |
|
if (!req) return; |
|
req->cmd = ETCP_ID_ROUTE_ENTRY; |
|
req->subcmd = ROUTE_SUBCMD_REQUEST_TABLE; |
|
struct ll_entry* e = queue_entry_new(0); |
|
if (!e) { |
|
u_free(req); |
|
return; |
|
} |
|
e->dgram = (uint8_t*)req; |
|
e->len = sizeof(struct BGP_ROUTE_REQUEST); |
|
etcp_send(conn, e); |
|
} |
|
|
|
static void route_bgp_add_to_senders(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn); |
|
static bool route_bgp_should_send_to(const struct NODEINFO_Q* nq, uint64_t target_id); |
|
static void route_bgp_send_full_table(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn); |
|
static void route_bgp_handle_request_table(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn); |
|
|
|
static char* nodeinfo_format(const uint8_t* data, size_t len) { |
|
if (!data || len < sizeof(struct BGP_NODEINFO_PACKET)) return NULL; |
|
struct BGP_NODEINFO_PACKET* pkt = (struct BGP_NODEINFO_PACKET*)data; |
|
struct NODEINFO* ni = &pkt->node; |
|
uint64_t node_id = ni->node_id; |
|
const uint8_t* dyn = data + sizeof(struct BGP_NODEINFO_PACKET); |
|
size_t off = 0; |
|
char name_buf[64] = {0}; |
|
size_t nl = ni->node_name_len; |
|
if (nl > 0 && nl < 63 && off + nl < len - sizeof(struct BGP_NODEINFO_PACKET)) { |
|
memcpy(name_buf, dyn + off, nl); off += nl; |
|
} |
|
off += ni->local_v4_sockets * sizeof(struct NODEINFO_IPV4_SOCKET); |
|
off += ni->local_v6_sockets * sizeof(struct NODEINFO_IPV6_SOCKET); |
|
char subs_buf[512] = {0}; |
|
if (ni->local_v4_subnets > 0) { |
|
const struct NODEINFO_IPV4_SUBNET* subs = (const struct NODEINFO_IPV4_SUBNET*)(dyn + off); |
|
size_t sl = 0; |
|
for (uint8_t i = 0; i < ni->local_v4_subnets && sl < 400; i++) { |
|
uint32_t addr = (subs[i].addr[0]<<24)|(subs[i].addr[1]<<16)|(subs[i].addr[2]<<8)|subs[i].addr[3]; |
|
char tmp[64]; snprintf(tmp,sizeof(tmp),"%d.%d.%d.%d/%u ",(addr>>24)&255,(addr>>16)&255,(addr>>8)&255,addr&255,subs[i].prefix_length); |
|
strcat(subs_buf,tmp); sl += strlen(tmp); |
|
} |
|
} |
|
int need = snprintf(NULL,0,"NODEINFO nid=%016llx ver=%u name=\"%s\" v4subs=\"%s\" v4s=%u v6s=%u v4subcnt=%u hop=%u", (unsigned long long)node_id,(unsigned)ni->ver,name_buf,subs_buf,(unsigned)ni->local_v4_sockets,(unsigned)ni->local_v6_sockets,(unsigned)ni->local_v4_subnets,(unsigned)ni->hop_count); |
|
char* buf = u_malloc(need+1); |
|
if (!buf) return NULL; |
|
snprintf(buf,need+1,"NODEINFO nid=%016llx ver=%u name=\"%s\" v4subs=\"%s\" v4s=%u v6s=%u v4subcnt=%u hop=%u", (unsigned long long)node_id,(unsigned)ni->ver,name_buf,subs_buf,(unsigned)ni->local_v4_sockets,(unsigned)ni->local_v6_sockets,(unsigned)ni->local_v4_subnets,(unsigned)ni->hop_count); |
|
return buf; |
|
} |
|
|
|
/* Old full table sending removed - now using NODEINFO broadcast now */ |
|
|
|
// ============================================================================ |
|
// Broadcast / Withdraw: node_id - удаляемый узел, wd_source - от кого получена команда удалить |
|
// ============================================================================ |
|
|
|
static void route_bgp_broadcast_withdraw(struct ROUTE_BGP* bgp, uint64_t node_id, uint64_t wd_source, struct ETCP_CONN* exclude) { |
|
if (!bgp) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "bgp is NULL"); return; } |
|
struct BGP_WITHDRAW_PACKET* pkt = u_calloc(1, sizeof(struct BGP_WITHDRAW_PACKET)); |
|
if (!pkt) return; |
|
pkt->cmd = ETCP_ID_ROUTE_ENTRY; |
|
pkt->subcmd = ROUTE_SUBCMD_WITHDRAW; |
|
pkt->node_id = node_id; |
|
pkt->wd_source = wd_source; |
|
struct ll_entry* e = bgp->senders_list ? bgp->senders_list->head : NULL; |
|
while (e) { |
|
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)e->data; |
|
if (item && item->conn && item->conn != exclude) { |
|
struct ll_entry* copy = queue_entry_new(0); |
|
if (copy) { |
|
copy->dgram = u_malloc(sizeof(*pkt)); |
|
if (copy->dgram) memcpy(copy->dgram, pkt, sizeof(*pkt)); |
|
copy->len = sizeof(*pkt); |
|
etcp_send(item->conn, copy); |
|
} |
|
} |
|
e = e->next; |
|
} |
|
u_free(pkt); |
|
} |
|
|
|
|
|
// ============================================================================ |
|
// Приём пакетов |
|
// ============================================================================ |
|
|
|
static void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LINK* link); |
|
|
|
static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry* entry) { |
|
if (!from_conn || !entry || entry->len < 2) { |
|
if (entry) { |
|
queue_dgram_free(entry); |
|
queue_entry_free(entry); |
|
} |
|
return; |
|
} |
|
|
|
struct UTUN_INSTANCE* instance = from_conn->instance; |
|
if (!instance || !instance->bgp) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_receive_cbk: invalid instance/bgp"); |
|
queue_dgram_free(entry); |
|
queue_entry_free(entry); |
|
return; |
|
} |
|
|
|
struct ROUTE_BGP* bgp = instance->bgp; |
|
uint8_t* data = entry->dgram; |
|
uint8_t cmd = data[0]; |
|
uint8_t subcmd = data[1]; |
|
|
|
if (cmd != ETCP_ID_ROUTE_ENTRY) { |
|
queue_dgram_free(entry); |
|
queue_entry_free(entry); |
|
return; |
|
} |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received BGP packet from %s, subcmd=%d, len=%zu", |
|
from_conn->log_name, subcmd, entry->len); |
|
|
|
if (subcmd == ROUTE_SUBCMD_NODEINFO) { |
|
char* s = nodeinfo_format(data, entry->len); if (s) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "%s from %s", s, from_conn->log_name); u_free(s); } |
|
route_bgp_process_nodeinfo(bgp, from_conn, data, entry->len); |
|
} else if (subcmd == ROUTE_SUBCMD_WITHDRAW) { |
|
route_bgp_process_withdraw(bgp, from_conn, data, entry->len); |
|
} else if (subcmd == ROUTE_SUBCMD_REQUEST_TABLE) { |
|
route_bgp_handle_request_table(bgp, from_conn); |
|
} else if (subcmd == ROUTE_SUBCMD_PING_REQ) { |
|
route_ping_handle_req(bgp, from_conn, data, entry->len); |
|
} else if (subcmd == ROUTE_SUBCMD_PING_RESP) { |
|
route_ping_handle_resp(bgp, from_conn, data, entry->len); |
|
} else if (subcmd == ROUTE_SUBCMD_NAT_INFO) { |
|
if (entry->len >= sizeof(struct BGP_NAT_INFO) && bgp && bgp->local_node) { |
|
const struct BGP_NAT_INFO* info = (const struct BGP_NAT_INFO*)data; |
|
uint32_t nat_ip = (info->nat_ip[0] << 24) | (info->nat_ip[1] << 16) | |
|
(info->nat_ip[2] << 8) | info->nat_ip[3]; |
|
uint16_t nat_port = ((info->nat_port >> 8) & 0xFF) | ((info->nat_port & 0xFF) << 8); |
|
uint8_t socket_id = info->socket_id; |
|
// Update socket in local_node and ETCP_SOCKET |
|
uint8_t* dynamic = (uint8_t*)&bgp->local_node->node + sizeof(struct NODEINFO); |
|
dynamic += bgp->local_node->node.node_name_len; |
|
struct NODEINFO_IPV4_SOCKET* sockets = (struct NODEINFO_IPV4_SOCKET*)dynamic; |
|
for (int i = 0; i < bgp->local_node->node.local_v4_sockets; i++) { |
|
if (sockets[i].id == socket_id) { |
|
uint8_t old_type = sockets[i].type; |
|
uint32_t old_ip = (sockets[i].addr[0] << 24) | (sockets[i].addr[1] << 16) | |
|
(sockets[i].addr[2] << 8) | sockets[i].addr[3]; |
|
uint16_t old_port = sockets[i].port; |
|
memcpy(sockets[i].addr, info->nat_ip, 4); |
|
sockets[i].port = nat_port; |
|
uint8_t verified_type; |
|
if (info->nat_type == NAT_TYPE_OPEN) { |
|
verified_type = NAT_VERIFIED_OPEN; |
|
} else if (info->nat_type == NAT_TYPE_RESTRICTED) { |
|
verified_type = NAT_VERIFIED_RESTRICTED; |
|
} else { |
|
verified_type = NAT_VERIFIED_UNKNOWN; |
|
} |
|
sockets[i].type = verified_type; |
|
// Update ETCP_SOCKET |
|
struct ETCP_SOCKET* es = bgp->instance->etcp_sockets; |
|
while (es) { |
|
if (es->sock_id == socket_id) { |
|
es->nat_type = verified_type; |
|
break; |
|
} |
|
es = es->next; |
|
} |
|
// Check if NAT actually changed - only update nodeinfo if changed |
|
if (old_ip != nat_ip || old_port != nat_port || old_type != verified_type) { |
|
bgp->local_node->dirty = 1; |
|
bgp->local_node->node.ver = (bgp->local_node->node.ver + 1) % 255 + 1; |
|
// Broadcast updated nodeinfo to all peers immediately |
|
if (bgp->senders_list) { |
|
struct ll_entry* se = bgp->senders_list->head; |
|
while (se) { |
|
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)se->data; |
|
if (item && item->conn) { |
|
route_bgp_send_nodeinfo(bgp->local_node, item->conn); |
|
} |
|
se = se->next; |
|
} |
|
} |
|
} |
|
break; |
|
} |
|
} |
|
// Save nat_type to all links of this connection |
|
struct ETCP_LINK* l = from_conn->links; |
|
while (l) { |
|
l->nat_type = info->nat_type; |
|
l = l->next; |
|
} |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO from %s: socket_id=%u type=%s ip=%u.%u.%u.%u %s port=%u", |
|
from_conn->log_name, socket_id, |
|
info->nat_type == NAT_TYPE_OPEN ? "OPEN" : "RESTRICTED", |
|
(info->nat_ip[0]), (info->nat_ip[1]), |
|
(info->nat_ip[2]), (info->nat_ip[3]), ip_to_str(&info->nat_ip, AF_INET).str, |
|
(unsigned)nat_port); |
|
} |
|
} else if (subcmd == ROUTE_SUBCMD_NAT_CHECK_REQ) { |
|
if (entry->len >= sizeof(struct BGP_NAT_CHECK_REQ) && bgp) { |
|
const struct BGP_NAT_CHECK_REQ* req = (const struct BGP_NAT_CHECK_REQ*)data; |
|
uint8_t socket_id = req->socket_id; |
|
// Find link by remote_socket_id in the connection |
|
struct ETCP_LINK* target_link = NULL; |
|
struct ETCP_LINK* l = from_conn->links; |
|
while (l) { |
|
if (l->remote_socket_id == socket_id) { |
|
target_link = l; |
|
break; |
|
} |
|
l = l->next; |
|
} |
|
if (!target_link) { |
|
DEBUG_WARN(DEBUG_CATEGORY_BGP, "NAT_CHECK_REQ from %s: no link with remote_socket_id=%u", |
|
from_conn->log_name, socket_id); |
|
} else if (target_link->nat_check_status == NAT_CHECK_IN_PROGRESS) { |
|
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "NAT_CHECK_REQ from %s: check already in progress for socket_id=%u", |
|
from_conn->log_name, socket_id); |
|
} else { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_CHECK_REQ from %s: restarting NAT check for socket_id=%u", |
|
from_conn->log_name, socket_id); |
|
route_bgp_start_link_nat_check(bgp, target_link); |
|
} |
|
} |
|
} |
|
|
|
queue_dgram_free(entry); |
|
queue_entry_free(entry); |
|
} |
|
|
|
|
|
// ============================================================================ |
|
// Init / Destroy / New / Remove conn |
|
// ============================================================================ |
|
|
|
// Callback для готовности ETCP соединения - отправляет маршруты |
|
static void route_bgp_on_conn_up(struct ETCP_CONN* conn, void* arg) { |
|
(void)arg; |
|
if (conn && conn->instance && conn->instance->bgp) { |
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "BGP ON UP %s", conn->log_name); |
|
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "Connection %s on up ", conn->log_name); |
|
route_bgp_new_conn(conn); |
|
} |
|
} |
|
|
|
static void route_bgp_on_conn_down(struct ETCP_CONN* conn, void* arg) { |
|
(void)arg; |
|
if (conn && conn->instance && conn->instance->bgp) { |
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "BGP ON DOWN %s", conn->log_name); |
|
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "Connection %s on down ", conn->log_name); |
|
route_bgp_remove_conn(conn); |
|
} |
|
} |
|
|
|
// Callback для новых ETCP соединений - устанавливает ready callback |
|
static void route_bgp_etcp_conn_cbk(struct ETCP_CONN* conn, void* arg) { |
|
(void)arg; |
|
if (conn && conn->instance && conn->instance->bgp) { |
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "BGP SET CBKS %s", conn->log_name); |
|
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "Set ETCP ready callback for connection %s", conn->log_name); |
|
etcp_conn_set_up_cbk(conn, route_bgp_on_conn_up, conn->instance->bgp); |
|
etcp_conn_set_down_cbk(conn, route_bgp_on_conn_down, conn->instance->bgp); |
|
} |
|
} |
|
|
|
struct ROUTE_BGP* route_bgp_init(struct UTUN_INSTANCE* instance) { |
|
if (!instance) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_init: instance is NULL"); |
|
return NULL; |
|
} |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_init: node_id=%016llx", |
|
(unsigned long long)instance->node_id); |
|
|
|
struct ROUTE_BGP* bgp = u_calloc(1, sizeof(struct ROUTE_BGP)); |
|
if (!bgp) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_init: alloc failed"); |
|
return NULL; |
|
} |
|
|
|
bgp->instance = instance; |
|
bgp->ping_pending = NULL; |
|
bgp->next_ping_req_id = 1; |
|
|
|
// Create nodes queue with hash support for fast lookup by node_id |
|
bgp->nodes = queue_new(instance->ua, BGP_NODES_HASH_SIZE, "bgp_nodes"); |
|
if (!bgp->nodes) { |
|
u_free(bgp); |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_init: nodes queue creation failed"); |
|
return NULL; |
|
} |
|
|
|
bgp->senders_list = queue_new(instance->ua, 0, "BGP_senders"); |
|
if (!bgp->senders_list) { |
|
queue_free(bgp->nodes); |
|
u_free(bgp); |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_init: senders_list queue creation failed"); |
|
return NULL; |
|
} |
|
|
|
int vc = 0; |
|
struct CFG_ROUTE_ENTRY* s = instance->config->my_subnets; |
|
while (s) { |
|
if (s->ip.family == AF_INET) vc++; |
|
s = s->next; |
|
} |
|
size_t d = vc * sizeof(struct NODEINFO_IPV4_SUBNET); |
|
bgp->local_node = u_calloc(1, sizeof(struct NODEINFO_Q) + d); |
|
if (!bgp->local_node) { |
|
queue_free(bgp->nodes); |
|
queue_free(bgp->senders_list); |
|
u_free(bgp); |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_init: local_node alloc failed"); |
|
return NULL; |
|
} |
|
|
|
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 = 0; |
|
route_bgp_update_my_nodeinfo(instance, bgp); |
|
|
|
etcp_bind(instance, ETCP_ID_ROUTE_ENTRY, route_bgp_receive_cbk); |
|
|
|
// Устанавливаем callback для новых ETCP соединений |
|
etcp_set_new_conn_cbk(instance, route_bgp_etcp_conn_cbk, NULL); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP module initialized (NODEINFO based routing)"); |
|
return bgp; |
|
} |
|
|
|
void route_bgp_destroy(struct UTUN_INSTANCE* instance) { |
|
if (!instance) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_destroy: instance is NULL"); |
|
return; |
|
} |
|
if (!instance->bgp) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_destroy: bgp is NULL"); |
|
return; |
|
} |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_destroy: node_id=%016llx", |
|
(unsigned long long)instance->node_id); |
|
|
|
etcp_unbind(instance, ETCP_ID_ROUTE_ENTRY); |
|
|
|
route_ping_destroy_pending(instance->bgp); |
|
|
|
struct ll_entry* e; |
|
while ((e = queue_data_get(instance->bgp->senders_list)) != NULL) { |
|
queue_entry_free(e); |
|
} |
|
queue_free(instance->bgp->senders_list); |
|
|
|
if (instance->bgp->local_node) { |
|
if (instance->bgp->local_node->paths) { |
|
queue_free(instance->bgp->local_node->paths); |
|
} |
|
u_free(instance->bgp->local_node); |
|
} |
|
|
|
if (instance->bgp->nodes) { |
|
queue_free(instance->bgp->nodes); |
|
} |
|
|
|
u_free(instance->bgp); |
|
instance->bgp = NULL; |
|
} |
|
|
|
void route_bgp_new_conn(struct ETCP_CONN* conn) { |
|
if (!conn) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_new_conn: conn is NULL"); |
|
return; |
|
} |
|
if (!conn->instance) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_new_conn: conn->instance is NULL"); |
|
return; |
|
} |
|
if (!conn->instance->bgp) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_new_conn: conn->instance->bgp is NULL"); |
|
return; |
|
} |
|
if (!conn->instance->rt) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_new_conn: conn->instance->rt is NULL"); |
|
return; |
|
} |
|
|
|
struct ROUTE_BGP* bgp = conn->instance->bgp; |
|
|
|
route_bgp_add_to_senders(bgp, conn); |
|
|
|
// Scan ALL connections and ALL links in instance - start NAT check if not started |
|
struct ETCP_CONN* c = conn->instance->connections; |
|
while (c) { |
|
struct ETCP_LINK* l = c->links; |
|
while (l) { |
|
if (l->initialized && l->conn && l->nat_check_status < NAT_CHECK_IN_PROGRESS) { |
|
route_bgp_start_link_nat_check(bgp, l); |
|
} |
|
l = l->next; |
|
} |
|
c = c->next; |
|
} |
|
|
|
route_bgp_send_table_request(bgp, conn); |
|
} |
|
|
|
void route_bgp_remove_conn(struct ETCP_CONN* conn) { |
|
if (!conn) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_remove_conn: conn is NULL"); |
|
return; |
|
} |
|
if (!conn->instance || !conn->instance->bgp) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_remove_conn: invalid instance/bgp"); |
|
return; |
|
} |
|
|
|
struct ROUTE_BGP* bgp = conn->instance->bgp; |
|
|
|
// SAFETY: проверяем что conn ещё есть в senders_list |
|
bool found_in_list = false; |
|
struct ll_entry* e = bgp->senders_list->head; |
|
while (e) { |
|
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)e->data; |
|
if (item->conn == conn) { |
|
found_in_list = true; |
|
break; |
|
} |
|
e = e->next; |
|
} |
|
|
|
if (!found_in_list) { |
|
DEBUG_WARN(DEBUG_CATEGORY_BGP, "route_bgp_remove_conn: conn already removed or not in list, skipping"); |
|
return; |
|
} |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_remove_conn: peer=%016llx", |
|
(unsigned long long)conn->peer_node_id); |
|
|
|
struct ROUTE_TABLE* rt = conn->instance->rt; |
|
|
|
// Remove this connection from all nodes' path lists |
|
// and send WITHDRAW if a node becomes unreachable |
|
bool need_withdraw = false; |
|
struct ll_entry* node_entry = bgp->nodes ? bgp->nodes->head : NULL; |
|
while (node_entry) { |
|
struct ll_entry* next = node_entry->next; |
|
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)node_entry; |
|
if (route_bgp_remove_path(nq, conn) == 1) { |
|
need_withdraw = true; |
|
if (rt) { |
|
route_delete(rt, nq); |
|
} |
|
nq->dirty = 1; |
|
if (nq->paths) { |
|
queue_free(nq->paths); |
|
nq->paths = NULL; |
|
} |
|
uint64_t key = nq->node.node_id; |
|
struct ll_entry* entry = node_entry; |
|
if (entry) { |
|
queue_remove_data(bgp->nodes, entry); |
|
queue_entry_free(entry); |
|
} |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Removed node %016llx after link down", (unsigned long long)key); |
|
} |
|
node_entry = next; |
|
} |
|
|
|
// Удаляем из списка рассылки |
|
e = bgp->senders_list->head; |
|
while (e) { |
|
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)e->data; |
|
if (item->conn == conn) { |
|
queue_remove_data(bgp->senders_list, e); |
|
queue_entry_free(e); |
|
break; |
|
} |
|
e = e->next; |
|
} |
|
|
|
if (need_withdraw) { |
|
route_bgp_broadcast_withdraw(bgp, conn->peer_node_id, conn->instance->node_id, NULL); |
|
} |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Connection removed, paths updated"); |
|
} |
|
|
|
|
|
/* ================================================ |
|
* NEW NODEINFO BASED IMPLEMENTATION |
|
* ================================================ */ |
|
|
|
struct NODEINFO_Q* route_bgp_get_node(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, 8); |
|
return e ? (struct NODEINFO_Q*)e : NULL; |
|
} |
|
|
|
int route_bgp_add_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn, uint64_t* hop_list, uint8_t hop_count) { |
|
if (!nq || !conn || hop_count > MAX_HOPS || !hop_list) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "add_path: invalid args"); |
|
return -1; |
|
} |
|
if (!nq->paths) { |
|
nq->paths = queue_new(conn->instance->ua, 0, "node_paths"); |
|
if (!nq->paths) return -1; |
|
} |
|
size_t hop_size = hop_count * 8; |
|
size_t path_size = sizeof(struct NODEINFO_PATH) - sizeof(struct ll_entry) + hop_size; |
|
struct ll_entry* pe = queue_entry_new(path_size); |
|
if (!pe) return -1; |
|
struct NODEINFO_PATH* path = (struct NODEINFO_PATH*)pe; |
|
path->conn = conn; |
|
path->hop_count = hop_count; |
|
uint64_t* stored = (uint64_t*)((uint8_t*)path + sizeof(struct NODEINFO_PATH)); |
|
memcpy(stored, hop_list, hop_size); |
|
queue_data_put(nq->paths, pe); |
|
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "Added path for node %016llx via conn %s with %d hops", (unsigned long long)nq->node.node_id, conn->log_name, hop_count); |
|
return 0; |
|
} |
|
|
|
int route_bgp_remove_path_by_hop(struct NODEINFO_Q* nq, uint64_t wd_source) { |
|
if (!nq || !nq->paths) return 0; |
|
int removed = 0; |
|
struct ll_entry* e = nq->paths->head; |
|
while (e) { |
|
struct NODEINFO_PATH* path = (struct NODEINFO_PATH*)e; |
|
// parse hoplist in dyn after hop_count (after fixed PATH) |
|
uint64_t* hop = (uint64_t*)((uint8_t*)path + sizeof(struct NODEINFO_PATH)); |
|
bool has_wd = false; |
|
for (uint8_t i = 0; i < path->hop_count; i++) { |
|
if (hop[i] == wd_source) { |
|
has_wd = true; |
|
break; |
|
} |
|
} |
|
if (has_wd) { |
|
struct ll_entry* next = e->next; |
|
queue_remove_data(nq->paths, e); |
|
queue_entry_free(e); |
|
removed++; |
|
e = next; |
|
continue; |
|
} |
|
e = e->next; |
|
} |
|
if (removed > 0 && nq->paths && queue_entry_count(nq->paths) == 0) { |
|
queue_free(nq->paths); |
|
nq->paths = NULL; |
|
return 1; // unreachable |
|
} |
|
return removed; |
|
} |
|
|
|
int route_bgp_remove_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn) |
|
{ |
|
if (!nq || !conn || !nq->paths) { |
|
return -1; |
|
} |
|
|
|
// Remove conn from paths queue |
|
struct ll_entry* e = nq->paths->head; |
|
while (e) { |
|
struct NODEINFO_PATH* path = (struct NODEINFO_PATH*)e; |
|
if (path->conn == conn) { |
|
queue_remove_data(nq->paths, e); |
|
queue_entry_free(e); |
|
break; |
|
} |
|
e = e->next; |
|
} |
|
|
|
int remaining = nq->paths ? queue_entry_count(nq->paths) : 0; |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Removed path for node %016llx via %s, remaining paths: %d", |
|
(unsigned long long)nq->node.node_id, conn->log_name, remaining); |
|
|
|
// If no paths left - node is unreachable |
|
if (remaining == 0) { |
|
if (nq->paths) { |
|
queue_free(nq->paths); |
|
nq->paths = NULL; |
|
} |
|
return 1; // signal that node became unreachable |
|
} |
|
return 0; |
|
} |
|
|
|
int nodeinfo_dyn_size(struct NODEINFO* node) { |
|
return node->node_name_len + |
|
node->local_v4_sockets * sizeof(struct NODEINFO_IPV4_SOCKET) + |
|
node->local_v6_sockets * sizeof(struct NODEINFO_IPV6_SOCKET) + |
|
node->local_v4_subnets * sizeof(struct NODEINFO_IPV4_SUBNET) + |
|
node->local_v6_subnets * sizeof(struct NODEINFO_IPV6_SUBNET) + |
|
node->tranzit_nodes * 8 + |
|
node->hop_count * 8; |
|
} |
|
|
|
// NAT check context |
|
struct nat_check_arg { |
|
struct ETCP_LINK* link; |
|
uint32_t nat_ip; |
|
uint16_t nat_port; |
|
}; |
|
|
|
static void nat_link_check_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, |
|
uint32_t recv_ip, uint16_t recv_port, void* arg) { |
|
(void)avg_rtt; (void)count_sent; (void)count_ok; (void)recv_ip; (void)recv_port; |
|
struct nat_check_arg* na = (struct nat_check_arg*)arg; |
|
if (!na || !na->link) { u_free(na); return; } |
|
struct ETCP_LINK* link = na->link; |
|
uint8_t nat_type = success ? NAT_TYPE_OPEN : NAT_TYPE_RESTRICTED; |
|
link->nat_type = nat_type; |
|
link->nat_check_status = success ? NAT_CHECK_OPEN : NAT_CHECK_RESTRICTED; |
|
// Send NAT_INFO to peer (via their connection) |
|
if (link->etcp) { |
|
uint8_t socket_id = link->remote_socket_id; |
|
route_bgp_send_nat_info(link->etcp, socket_id, na->nat_ip, na->nat_port, nat_type); |
|
} |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "link=%p type=%s success=%d", |
|
(void*)link, success ? "OPEN" : "RESTRICTED", success); |
|
u_free(na); |
|
} |
|
|
|
static struct ETCP_CONN* route_bgp_find_third_node(struct ROUTE_BGP* bgp, struct ETCP_CONN* exclude) { |
|
if (!bgp || !bgp->senders_list) return NULL; |
|
struct ll_entry* e = bgp->senders_list->head; |
|
while (e) { |
|
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)e->data; |
|
if (item && item->conn && item->conn != exclude) return item->conn; |
|
e = e->next; |
|
} |
|
return NULL; |
|
} |
|
|
|
static void route_bgp_extract_nat_addr(struct ETCP_CONN* conn, uint32_t* nat_ip, uint16_t* nat_port) { |
|
*nat_ip = 0; *nat_port = 0; |
|
if (!conn) return; |
|
struct ETCP_LINK* l = conn->links; |
|
while (l) { |
|
if (l->nat_ip != 0) { |
|
*nat_ip = l->nat_ip; |
|
*nat_port = l->nat_port; |
|
return; |
|
} |
|
l = l->next; |
|
} |
|
} |
|
|
|
static void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LINK* link) { |
|
if (!bgp || !link || !link->conn || !link->etcp) return; |
|
if (link->nat_check_status == NAT_CHECK_IN_PROGRESS) return; |
|
// Find third node to send ping through |
|
struct ETCP_CONN* third_conn = route_bgp_find_third_node(bgp, link->etcp); |
|
if (!third_conn) { |
|
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "no third node found for link"); |
|
return; |
|
} |
|
|
|
// Get target address - use nat_ip/nat_port if set, otherwise use remote_addr |
|
uint32_t target_ip; |
|
uint16_t target_port; |
|
if (link->nat_ip != 0 && link->nat_port != 0) { |
|
target_ip = link->nat_ip; |
|
target_port = link->nat_port; |
|
} else { |
|
struct sockaddr_in* sin = (struct sockaddr_in*)&link->remote_addr; |
|
target_ip = sin->sin_addr.s_addr; |
|
target_port = ntohs(sin->sin_port); |
|
} |
|
|
|
// if (!is_local_subnet(target_ip)) { DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "local ip: %s, skip nat check", ip_to_str(&target_ip, AF_INET).str); return; } |
|
|
|
// Allocate callback arg |
|
struct nat_check_arg* arg = u_calloc(1, sizeof(struct nat_check_arg)); |
|
if (!arg) return; |
|
arg->link = link; |
|
arg->nat_ip = target_ip; |
|
arg->nat_port = target_port; |
|
// Use peer public key from the connection's crypto context |
|
const uint8_t* pubkey = link->etcp->crypto_ctx.peer_key_set ? link->etcp->crypto_ctx.peer_public_key : NULL; |
|
if (!pubkey) { |
|
u_free(arg); |
|
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "no peer pubkey for link=%p", (void*)link); |
|
return; |
|
} |
|
// Send ping via third node - embed peer pubkey for NAT detection |
|
int ret = route_ping_send_req_addr(bgp, third_conn, link->etcp->peer_node_id, target_ip, target_port, |
|
3, 500, 1000, 5000, nat_link_check_cb, arg, |
|
pubkey); |
|
if (ret == 0) { |
|
link->nat_check_status = NAT_CHECK_IN_PROGRESS; |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "ping remote request via=%s (%s:%d)", |
|
third_conn->log_name, ip_to_str(&target_ip, AF_INET).str, target_port); |
|
} else { |
|
u_free(arg); |
|
DEBUG_WARN(DEBUG_CATEGORY_BGP, "failed to start for link=%s (%s:%d)", |
|
third_conn->log_name, ip_to_str(&target_ip, AF_INET).str, target_port); |
|
} |
|
} |
|
|
|
int route_bgp_process_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* from, const uint8_t* data, size_t len) { |
|
if (!bgp || !from || len < sizeof(struct BGP_NODEINFO_PACKET)) return -1; |
|
|
|
struct BGP_NODEINFO_PACKET* pkt = (struct BGP_NODEINFO_PACKET*)data; |
|
struct NODEINFO* ni = &pkt->node; |
|
int dyn_size=nodeinfo_dyn_size(ni); |
|
if (len!=dyn_size + sizeof(struct BGP_NODEINFO_PACKET)) { |
|
DEBUG_WARN(DEBUG_CATEGORY_BGP, "Incorrect packet size (%s)",from->log_name); |
|
return -1; |
|
} |
|
|
|
uint64_t node_id = ni->node_id; |
|
|
|
if (ni->hop_count >= MAX_HOPS) { |
|
DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO from %s dropped: too many hops (%d)", |
|
from->log_name, ni->hop_count); |
|
return -1; |
|
} |
|
|
|
struct NODEINFO_Q* nodeinfo1 = route_bgp_get_node(bgp, node_id); |
|
uint8_t new_ver = ni->ver; |
|
|
|
if (nodeinfo1 && (int8_t)(nodeinfo1->last_ver-new_ver)>=0) { |
|
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "NODEINFO from %s ignored (old ver %d <= %d)", |
|
from->log_name, new_ver, nodeinfo1->last_ver); |
|
return 0; |
|
} |
|
int new_data_size=sizeof(struct NODEINFO_Q) - sizeof(struct ll_entry) + dyn_size + 8; |
|
struct ll_queue* paths=NULL; |
|
int need_alloc=0; |
|
if (nodeinfo1) {// remove old node |
|
paths=nodeinfo1->paths; |
|
if (nodeinfo1->ll.size < new_data_size) { |
|
|
|
need_alloc=1; |
|
} |
|
} else need_alloc=1; |
|
|
|
if (need_alloc) { |
|
if (nodeinfo1) { |
|
queue_remove_data(bgp->nodes, &nodeinfo1->ll); |
|
queue_entry_free(&nodeinfo1->ll); |
|
} |
|
nodeinfo1 = (struct NODEINFO_Q*)queue_entry_new(new_data_size); |
|
paths = queue_new(bgp->instance->ua, 0, "node_paths"); |
|
memcpy(&nodeinfo1->node, ni, sizeof(struct NODEINFO) + dyn_size); |
|
queue_data_put_with_index(bgp->nodes, &nodeinfo1->ll, offsetof(struct NODEINFO_Q, node.node_id)-sizeof(struct ll_entry), 8); |
|
} |
|
else memcpy(&nodeinfo1->node, ni, sizeof(struct NODEINFO) + dyn_size); |
|
nodeinfo1->paths = paths; |
|
nodeinfo1->last_ver = new_ver; |
|
|
|
// add last hop |
|
uint64_t* hop_list = (uint64_t*)((uint8_t*)&nodeinfo1->node + sizeof(struct NODEINFO) + dyn_size); |
|
uint64_t sender = from->peer_node_id; |
|
memcpy(hop_list, &sender, 8); |
|
nodeinfo1->node.hop_count++; |
|
|
|
// update node path |
|
route_bgp_remove_path_by_hop(nodeinfo1, from->peer_node_id); |
|
route_bgp_add_path(nodeinfo1, from, hop_list, nodeinfo1->node.hop_count); |
|
|
|
if (bgp->instance->rt) { |
|
route_insert(bgp->instance->rt, nodeinfo1); |
|
} |
|
|
|
int hop_count=nodeinfo1->node.hop_count; |
|
|
|
// рассылаем по узлам которых нет в hop_list этой ноды (loop prevention) |
|
struct ll_entry* e = bgp->senders_list ? bgp->senders_list->head : NULL; |
|
while (e) { |
|
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)e->data; |
|
if (item->conn) { |
|
uint64_t id=item->conn->peer_node_id; |
|
int found=0; |
|
for (int i=0; i<hop_count; i++) if (hop_list[i]==id) found=1; |
|
if (found==0) { |
|
route_bgp_send_nodeinfo(nodeinfo1, item->conn); |
|
} |
|
else DEBUG_INFO(DEBUG_CATEGORY_BGP, "Skip send NODEINFO to node %016llx",id); |
|
|
|
} |
|
e = e->next; |
|
} |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Processed NODEINFO from %s (node=%016llx,ver=%d,paths=%d)", |
|
from->log_name, (unsigned long long)node_id, new_ver, |
|
nodeinfo1->paths ? queue_entry_count(nodeinfo1->paths) : 0); |
|
|
|
return 0; |
|
} |
|
|
|
int route_bgp_process_withdraw(struct ROUTE_BGP* bgp, struct ETCP_CONN* sender, const uint8_t* data, size_t len) { |
|
if (!bgp || len < sizeof(struct BGP_WITHDRAW_PACKET)) return -1; |
|
|
|
struct BGP_WITHDRAW_PACKET* wp = (struct BGP_WITHDRAW_PACKET*)data; |
|
uint64_t node_id = wp->node_id; |
|
uint64_t wd_source = wp->wd_source; |
|
|
|
struct NODEINFO_Q* nq = route_bgp_get_node(bgp, node_id); |
|
if (!nq) { |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "node not found"); |
|
return 0; |
|
} |
|
int ret=route_bgp_remove_path_by_hop(nq, wd_source); |
|
if (ret>0 || !nq->paths || (nq->paths && queue_entry_count(nq->paths) == 0)) { |
|
if (bgp->instance && bgp->instance->rt) { |
|
route_delete(bgp->instance->rt, nq); |
|
} |
|
nq->dirty = 1; |
|
if (nq->paths) { |
|
queue_free(nq->paths); |
|
nq->paths = NULL; |
|
} |
|
uint64_t key = node_id; |
|
struct ll_entry* entry = queue_find_data_by_index(bgp->nodes, &key, 8); |
|
if (entry) { |
|
queue_remove_data(bgp->nodes, entry); |
|
queue_entry_free(entry); |
|
} |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Removed node %016llx after WITHDRAW", (unsigned long long)node_id); |
|
route_bgp_broadcast_withdraw(bgp, node_id, wd_source, sender); |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
void route_bgp_send_nodeinfo(struct NODEINFO_Q* node, struct ETCP_CONN* conn) { |
|
if (!node || !conn) { |
|
return; |
|
} |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sending NODEINFO to %s", conn->log_name); |
|
|
|
int dyn = nodeinfo_dyn_size(&node->node); |
|
|
|
size_t ps = sizeof(struct BGP_NODEINFO_PACKET) + dyn; |
|
|
|
uint8_t* p = u_malloc(ps); |
|
if (!p) { |
|
return; |
|
} |
|
|
|
p[0] = ETCP_ID_ROUTE_ENTRY; |
|
p[1] = ROUTE_SUBCMD_NODEINFO; |
|
memcpy(p + 2, &node->node, sizeof(struct NODEINFO)); |
|
|
|
uint8_t* ds = (uint8_t*)&node->node + sizeof(struct NODEINFO); |
|
memcpy(p + sizeof(struct BGP_NODEINFO_PACKET), ds, dyn); |
|
|
|
struct ll_entry* e = queue_entry_new(0); |
|
if (!e) { |
|
u_free(p); |
|
return; |
|
} |
|
|
|
e->dgram = p; |
|
e->len = ps; |
|
|
|
etcp_send(conn, e); |
|
} |
|
|
|
static void route_bgp_add_to_senders(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn) { |
|
if (!bgp || !conn || !bgp->senders_list) return; |
|
bool already = false; |
|
struct ll_entry* e = bgp->senders_list->head; |
|
while (e) { |
|
if (((struct ROUTE_BGP_CONN_ITEM*)e->data)->conn == conn) { already = true; break; } |
|
e = e->next; |
|
} |
|
if (!already) { |
|
struct ll_entry* item_entry = queue_entry_new(sizeof(struct ROUTE_BGP_CONN_ITEM)); |
|
if (item_entry) { |
|
((struct ROUTE_BGP_CONN_ITEM*)item_entry->data)->conn = conn; |
|
queue_data_put(bgp->senders_list, item_entry); |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Added to senders_list"); |
|
} |
|
} |
|
} |
|
|
|
static bool route_bgp_should_send_to(const struct NODEINFO_Q* nq, uint64_t target_id) { |
|
if (!nq || !nq->paths) return false; |
|
struct ll_entry* e = nq->paths->head; |
|
while (e) { |
|
struct NODEINFO_PATH* path = (struct NODEINFO_PATH*)e; |
|
uint64_t* hop = (uint64_t*)((uint8_t*)path + sizeof(struct NODEINFO_PATH)); |
|
bool has_id = false; |
|
for (uint8_t i = 0; i < path->hop_count; i++) { |
|
if (hop[i] == target_id) { has_id = true; break; } |
|
} |
|
if (!has_id) return true; |
|
e = e->next; |
|
} |
|
return false; |
|
} |
|
|
|
static void route_bgp_send_full_table(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn) { |
|
if (!bgp || !conn) return; |
|
uint64_t target = conn->peer_node_id; |
|
struct ll_entry* e = bgp->nodes ? bgp->nodes->head : NULL; |
|
while (e) { |
|
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)e; |
|
if (nq->node.hop_count == 0) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "local node in learned list"); |
|
e = e->next; continue; |
|
} |
|
if (!nq->paths) { |
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node has no paths"); |
|
e = e->next; continue; |
|
} |
|
if (route_bgp_should_send_to(nq, target)) { |
|
route_bgp_send_nodeinfo(nq, conn); |
|
} |
|
e = e->next; |
|
} |
|
} |
|
|
|
static void route_bgp_handle_request_table(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn) { |
|
if (!bgp || !conn) return; |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received table request from %s", conn->log_name); |
|
route_bgp_send_nodeinfo(bgp->local_node, conn); |
|
route_bgp_send_full_table(bgp, conn); |
|
route_bgp_add_to_senders(bgp, conn); |
|
} |
|
|
|
void route_bgp_send_nat_info(struct ETCP_CONN* conn, uint8_t socket_id, uint32_t nat_ip, uint16_t nat_port, uint8_t nat_type) { |
|
if (!conn) return; |
|
struct BGP_NAT_INFO* pkt = u_calloc(1, sizeof(struct BGP_NAT_INFO)); |
|
if (!pkt) return; |
|
pkt->cmd = ETCP_ID_ROUTE_ENTRY; |
|
pkt->subcmd = ROUTE_SUBCMD_NAT_INFO; |
|
pkt->socket_id = socket_id; |
|
pkt->nat_ip[0] = (nat_ip >> 24) & 0xFF; |
|
pkt->nat_ip[1] = (nat_ip >> 16) & 0xFF; |
|
pkt->nat_ip[2] = (nat_ip >> 8) & 0xFF; |
|
pkt->nat_ip[3] = nat_ip & 0xFF; |
|
pkt->nat_port = htons(nat_port); |
|
pkt->nat_type = nat_type; |
|
|
|
struct ll_entry* e = queue_entry_new(0); |
|
if (!e) { |
|
u_free(pkt); |
|
return; |
|
} |
|
e->dgram = (uint8_t*)pkt; |
|
e->len = sizeof(struct BGP_NAT_INFO); |
|
etcp_send(conn, e); |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_send_nat_info to %s: socket_id=%u type=%s ip=%s port=%u", |
|
conn->log_name, socket_id, |
|
nat_type == NAT_TYPE_OPEN ? "OPEN" : "RESTRICTED", |
|
ip_to_str(&nat_ip, AF_INET).str, (unsigned)nat_port); |
|
} |
|
|
|
void route_bgp_send_nat_check_req(struct ETCP_CONN* conn, uint8_t socket_id) { |
|
if (!conn) return; |
|
struct BGP_NAT_CHECK_REQ* pkt = u_calloc(1, sizeof(struct BGP_NAT_CHECK_REQ)); |
|
if (!pkt) return; |
|
pkt->cmd = ETCP_ID_ROUTE_ENTRY; |
|
pkt->subcmd = ROUTE_SUBCMD_NAT_CHECK_REQ; |
|
pkt->socket_id = socket_id; |
|
|
|
struct ll_entry* e = queue_entry_new(0); |
|
if (!e) { |
|
u_free(pkt); |
|
return; |
|
} |
|
e->dgram = (uint8_t*)pkt; |
|
e->len = sizeof(struct BGP_NAT_CHECK_REQ); |
|
etcp_send(conn, e); |
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_send_nat_check_req to %s: socket_id=%u", |
|
conn->log_name, socket_id); |
|
}
|
|
|