From ca471d777e9cfde7238102cbc83530c83b95ff3c Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 21 Oct 2026 21:55:13 +0200 Subject: [PATCH] Route static NAT forwards to explicit owners on all ports --- src/eim_nat.c | 48 +++++++++++++++++++++++--------------- tests/test_nat_engine.c | 8 +++---- tests/test_nat_transport.c | 2 -- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/eim_nat.c b/src/eim_nat.c index c10dfec6..8ccc8a59 100644 --- a/src/eim_nat.c +++ b/src/eim_nat.c @@ -70,10 +70,10 @@ static void csum_update_icmp(uint8_t* icmp, uint16_t old_word, uint16_t new_word memcpy(icmp + ICMP_CHECKSUM_OFFSET, &new_csum, 2); } -// Поиск в замкнутом диапазоне; индекс должен вмещать 65536 после последнего порта. +// Статические порты могут лежать вне динамического диапазона; индекс вмещает 65536. static struct eim_nat_entry* eim_nat_find_egress(struct eim_nat_ctx* ctx, uint8_t proto, uint32_t ip_host, uint16_t port_net, uint64_t src_node_id) { - for (uint32_t i = ctx->port_start; i <= ctx->port_end; i++) { + for (uint32_t i = 1; i < ctx->table_size; i++) { struct eim_nat_entry* e = &ctx->table[i]; if (e->state != EIM_NAT_ENTRY_FREE && e->proto == proto && e->src_node_id == src_node_id && e->internal_ip == ip_host && e->internal_port == port_net) return e; @@ -208,8 +208,6 @@ int eim_nat_ingress(struct eim_nat_ctx* ctx, uint8_t* ip_data, size_t ip_len, if (!is_tcp && !is_udp && !is_icmp_echo) return 0; uint16_t ext_port_host = ntohs(dst_port_net); - if (ext_port_host < ctx->port_start || ext_port_host > ctx->port_end) return 0; - struct eim_nat_entry* entry = &ctx->table[ext_port_host]; if (entry->state == EIM_NAT_ENTRY_FREE) return 0; if (entry->proto != proto) return 0; @@ -264,24 +262,25 @@ int eim_nat_init_ctx(struct eim_nat_ctx* ctx, const struct global_config* g) { return -1; } ctx->next_port = ctx->port_start; + if (g->nat_forward_count < 0 || g->nat_forward_count > MAX_NAT_FORWARDS) { + DEBUG_ERROR(DEBUG_CATEGORY_NAT, "Invalid NAT forward count: %d", g->nat_forward_count); + return -1; + } ctx->table_size = EIM_NAT_TABLE_SIZE; ctx->table = u_calloc(ctx->table_size, sizeof(struct eim_nat_entry)); if (!ctx->table) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "Failed to allocate NAT table"); return -1; } + ctx->initialized = 1; for (int i = 0; i < g->nat_forward_count; i++) { - uint16_t ext = g->nat_forwards[i].external_port; - if (ext >= ctx->table_size) continue; - struct eim_nat_entry* e = &ctx->table[ext]; - e->internal_ip = g->nat_forwards[i].internal_ip_host; - e->internal_port = g->nat_forwards[i].internal_port_net; - e->proto = g->nat_forwards[i].proto; - e->state = EIM_NAT_ENTRY_STATIC; - DEBUG_INFO(DEBUG_CATEGORY_NAT, "Port forward: %s:%u <- :%u (proto=%u)", - ip_host_to_str(e->internal_ip).str, ntohs(e->internal_port), ext, e->proto); + if (eim_nat_add_forward(ctx, g->nat_forwards[i].proto, g->nat_forwards[i].internal_ip_host, + g->nat_forwards[i].internal_port_net, g->nat_forwards[i].external_port, g->nat_forwards[i].node_id) != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_NAT, "Invalid NAT forward at index %d; initialization aborted", i); + eim_nat_destroy_ctx(ctx); + return -1; + } } - ctx->initialized = 1; DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT engine initialized: gw=%s ports=%u-%u", ip_host_to_str(ctx->gateway_ip).str, ctx->port_start, ctx->port_end); return 0; @@ -296,15 +295,26 @@ void eim_nat_destroy_ctx(struct eim_nat_ctx* ctx) { int eim_nat_add_forward(struct eim_nat_ctx* ctx, uint8_t proto, uint32_t internal_ip_host, uint16_t internal_port_net, - uint16_t external_port) { - if (!ctx || !ctx->initialized || external_port >= ctx->table_size) return -1; - if (ctx->table[external_port].state != EIM_NAT_ENTRY_FREE) return -1; + uint16_t external_port, uint64_t node_id) { + if (!ctx || !ctx->initialized || !node_id || !external_port || !internal_port_net || + (proto != IPPROTO_TCP_UINT8 && proto != IPPROTO_UDP_UINT8) || external_port >= ctx->table_size) { + DEBUG_ERROR(DEBUG_CATEGORY_NAT, "Invalid NAT forward: ctx=%p node=%016llx proto=%u internal_port=%u external_port=%u", + (void*)ctx, (unsigned long long)node_id, proto, ntohs(internal_port_net), external_port); + return -1; + } + if (ctx->table[external_port].state != EIM_NAT_ENTRY_FREE || + eim_nat_find_egress(ctx, proto, internal_ip_host, internal_port_net, node_id)) { + DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT forward conflicts with existing mapping: node=%016llx %s:%u <- :%u proto=%u", + (unsigned long long)node_id, ip_host_to_str(internal_ip_host).str, ntohs(internal_port_net), external_port, proto); + return -1; + } struct eim_nat_entry* e = &ctx->table[external_port]; e->internal_ip = internal_ip_host; e->internal_port = internal_port_net; e->proto = proto; e->state = EIM_NAT_ENTRY_STATIC; - DEBUG_INFO(DEBUG_CATEGORY_NAT, "Port forward: %s:%u <- :%u (proto=%u)", - ip_host_to_str(internal_ip_host).str, ntohs(internal_port_net), external_port, proto); + e->src_node_id = node_id; + DEBUG_INFO(DEBUG_CATEGORY_NAT, "Port forward: node=%016llx %s:%u <- :%u (proto=%u)", + (unsigned long long)node_id, ip_host_to_str(internal_ip_host).str, ntohs(internal_port_net), external_port, proto); return 0; } diff --git a/tests/test_nat_engine.c b/tests/test_nat_engine.c index e258a21e..a33ab3e4 100644 --- a/tests/test_nat_engine.c +++ b/tests/test_nat_engine.c @@ -740,7 +740,7 @@ static void test_port_forward(void) { int r = eim_nat_add_forward(&ctx, IPPROTO_TCP_UINT8, 0x0A0000FE, htobe16(8080), // internal 10.0.0.254:8080 - 10050); + 10050, 1); ASSERT_EQ(r, 0, "add_forward ok"); ASSERT(ctx.table[10050].state == EIM_NAT_ENTRY_STATIC, "entry static"); ASSERT_EQ(ctx.table[10050].internal_ip, 0x0A0000FE, "internal_ip"); @@ -756,8 +756,8 @@ static void test_port_forward(void) { struct eim_nat_ctx ctx; eim_nat_init_ctx(&ctx, &g); - eim_nat_add_forward(&ctx, IPPROTO_TCP_UINT8, 0x0A0000FE, htobe16(8080), 10050); - int r = eim_nat_add_forward(&ctx, IPPROTO_UDP_UINT8, 0x0A0000FF, htobe16(9090), 10050); + eim_nat_add_forward(&ctx, IPPROTO_TCP_UINT8, 0x0A0000FE, htobe16(8080), 10050, 1); + int r = eim_nat_add_forward(&ctx, IPPROTO_UDP_UINT8, 0x0A0000FF, htobe16(9090), 10050, 1); ASSERT_EQ(r, -1, "duplicate rejects"); eim_nat_destroy_ctx(&ctx); } @@ -770,7 +770,7 @@ static void test_port_forward(void) { eim_nat_init_ctx(&ctx, &g); // Static forward: external port 10050 → internal 10.0.0.254:8080 TCP - eim_nat_add_forward(&ctx, IPPROTO_TCP_UINT8, 0x0A0000FE, htobe16(8080), 10050); + eim_nat_add_forward(&ctx, IPPROTO_TCP_UINT8, 0x0A0000FE, htobe16(8080), 10050, 1); // Ingress TCP packet to gateway:10050 uint8_t* resp = make_tcp_pkt(TEST_IP_DST_HOST, 443, TEST_GW_HOST, 10050); diff --git a/tests/test_nat_transport.c b/tests/test_nat_transport.c index d914f095..08f72233 100644 --- a/tests/test_nat_transport.c +++ b/tests/test_nat_transport.c @@ -138,7 +138,6 @@ static int create_temp_configs(void) { "allow_all=1\n" "\n" "[nat]\n" - "enabled=1\n" "tun_ifname=tun_nat\n" "tun_ip=100.64.0.1/24\n" "port_start=20000\n" @@ -166,7 +165,6 @@ static int create_temp_configs(void) { "link=cl:127.0.0.1:0\n" "\n" "[nat]\n" - "enabled=1\n" "tun_ifname=tun_nat_client\n" "tun_ip=100.64.1.1/24\n" "nat_via=0x%016llx\n",