From cecc5d7d1f908365fe94e4449718b59ba1bc4617 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 21 Oct 2026 22:32:29 +0200 Subject: [PATCH] Validate provider replies before client TUN delivery --- src/eim_nat.c | 18 +++++++++++++----- src/eim_nat.h | 5 +++++ src/nat_transport.c | 7 +++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/eim_nat.c b/src/eim_nat.c index 61d80e08..99adde0c 100644 --- a/src/eim_nat.c +++ b/src/eim_nat.c @@ -117,9 +117,9 @@ static struct eim_nat_entry* eim_nat_insert(struct eim_nat_ctx* ctx, uint16_t ex // ==================== Public API ==================== // Проверить полный IPv4 и границы транспорта до изменения пакета/таблицы. memcpy допускает любой alignment. -static int eim_nat_parse_packet(struct eim_nat_ctx* ctx, const uint8_t* ip, size_t len, uint16_t* header_len) { - if (!ctx || !ctx->initialized || !ctx->table || !ip || len < IP_HDR_MIN_SIZE) { - DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT invalid packet/context: ctx=%p data=%p bytes=%zu", (void*)ctx, (const void*)ip, len); +int eim_nat_validate_packet(const uint8_t* ip, size_t len, uint16_t* header_len) { + if (!header_len || !ip || len < IP_HDR_MIN_SIZE) { + DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT invalid packet: data=%p bytes=%zu header=%p", (const void*)ip, len, (void*)header_len); return EIM_NAT_ERROR; } *header_len = (ip[0] & 15) * 4; @@ -158,8 +158,12 @@ static int eim_nat_parse_packet(struct eim_nat_ctx* ctx, const uint8_t* ip, size int eim_nat_egress(struct eim_nat_ctx* ctx, uint8_t* ip_data, size_t ip_len, uint64_t src_node_id, struct ETCP_CONN* src_conn) { + if (!ctx || !ctx->initialized || !ctx->table || !ctx->buckets) { + DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT egress requires initialized context"); + return EIM_NAT_ERROR; + } uint16_t ip_hdr_len; - int parsed = eim_nat_parse_packet(ctx, ip_data, ip_len, &ip_hdr_len); + int parsed = eim_nat_validate_packet(ip_data, ip_len, &ip_hdr_len); if (parsed != EIM_NAT_OK) return parsed; uint8_t proto = ip_data[IP_PROTO_OFFSET]; @@ -224,8 +228,12 @@ int eim_nat_egress(struct eim_nat_ctx* ctx, uint8_t* ip_data, size_t ip_len, int eim_nat_ingress(struct eim_nat_ctx* ctx, uint8_t* ip_data, size_t ip_len, struct eim_nat_entry** out_entry) { if (out_entry) *out_entry = NULL; + if (!ctx || !ctx->initialized || !ctx->table || !ctx->buckets) { + DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT ingress requires initialized context"); + return EIM_NAT_ERROR; + } uint16_t ip_hdr_len; - int parsed = eim_nat_parse_packet(ctx, ip_data, ip_len, &ip_hdr_len); + int parsed = eim_nat_validate_packet(ip_data, ip_len, &ip_hdr_len); if (parsed != EIM_NAT_OK) return parsed; uint8_t proto = ip_data[IP_PROTO_OFFSET]; diff --git a/src/eim_nat.h b/src/eim_nat.h index ae9a918e..38f4fb07 100644 --- a/src/eim_nat.h +++ b/src/eim_nat.h @@ -66,6 +66,11 @@ struct eim_nat_ctx { struct global_config; +/* Проверить IPv4 и транспортные границы без изменения данных. header_len обязателен и получает IHL в байтах. + * EIM_NAT_OK — поддерживаемый полный пакет; SKIP — фрагмент/неподдерживаемый протокол; ERROR — неверный формат. + * Checksums не проверяются. Не требует созданного NAT ctx. */ +int eim_nat_validate_packet(const uint8_t* ip, size_t len, uint16_t* header_len); + /* Создать ctx по g: IPv4 шлюза, 1 <= port_start < port_end <= 65535, статические пробросы. * ctx не должен владеть предыдущей таблицей: перед повторным init вызвать destroy_ctx. * 0 — успех (при !nat_enabled таблица не создаётся); -1 — ошибка, созданная таблица освобождена. */ diff --git a/src/nat_transport.c b/src/nat_transport.c index 9c31060b..5fa40162 100644 --- a/src/nat_transport.c +++ b/src/nat_transport.c @@ -1,4 +1,5 @@ #include "nat_transport.h" +#include "etcp.h" #include "eim_nat.h" #include "utun_instance.h" #include "config_parser.h" @@ -219,6 +220,12 @@ static void nat_receive(struct ETCP_CONN* conn, struct ll_entry* entry) { if (!tr->nat_via_node_id) { int result = eim_nat_egress(&inst->nat, entry->dgram + ROUTER_SVC_PAYLOAD_OFF, len, source, conn); if (result != EIM_NAT_OK) { nat_drop(inst, entry, source, "egress invalid or unsupported packet"); return; } + } else { + uint16_t header_len; + if (eim_nat_validate_packet(entry->dgram + ROUTER_SVC_PAYLOAD_OFF, len, &header_len) != EIM_NAT_OK) { + nat_drop(inst, entry, source, "invalid provider IPv4 packet"); + return; + } } if (tr->tun_pending) { nat_drop(inst, entry, source, "concurrent TUN delivery"); return; } // Возможен только loopback. tr->tun_pending = entry;