Validate provider replies before client TUN delivery

This commit is contained in:
evgeny committed 2026-10-21 22:32:29 +02:00
1 parent 5e2e6c15cf
commit cecc5d7d1f
3 files changed
+25 -5

No files matched your search

+13 -5
View File
@@ -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];
+5
View File
@@ -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 — ошибка, созданная таблица освобождена. */
+7
View File
@@ -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;