Document NAT ownership, packet formats and API contracts

This commit is contained in:
evgeny committed 2026-10-21 22:00:06 +02:00
1 parent bfa23afae9
commit 19a5870d5f
3 files changed
+49 -23

No files matched your search

+2 -1
View File
@@ -184,7 +184,8 @@ struct global_config {
int allowed_keys_count;
int allowed_keys_allow_all;
// NAT configuration ([nat] section)
// Опции [nat] включают NAT; forward=proto:node_id_hex:IPv4:internal_port:external_port.
// Ошибки parse_nat отклоняют весь конфиг; диапазон портов дополнительно проверяет eim_nat_init_ctx.
int nat_enabled;
char nat_tun_ifname[16];
struct IP nat_tun_ip;
+32 -16
View File
@@ -5,7 +5,9 @@
* IPv4 UDP: отключённая checksum=0 сохраняется; вычисленный ноль записывается как 0xffff.
* Перед обработкой нужен инициализированный ctx; вызовы последовательны в uasync-потоке.
* gateway/internal IP — host order, internal_port — network order, внешний порт — host order.
* src_conn заимствован; срок жизни и выбор транспорта обратной отправки контролирует nat_transport. */
* Записи живут до destroy_ctx, автоматического истечения/освобождения портов нет.
* Фрагменты и неподдерживаемые протоколы возвращаются без изменений с кодом 0.
* src_conn только сохраняется при создании динамической записи, для отправки не используется. */
#ifndef EIM_NAT_H
#define EIM_NAT_H
@@ -30,39 +32,53 @@ struct ETCP_CONN;
#define IPPROTO_ICMP_UINT8 1
struct eim_nat_entry {
uint32_t internal_ip;
uint16_t internal_port;
uint8_t proto;
uint8_t state;
uint64_t src_node_id; // which node sent the original packet
uint64_t last_seen;
struct ETCP_CONN* src_conn; // cached connection for sendback
uint32_t internal_ip; // Внутренний IPv4, host order.
uint16_t internal_port; // Внутренний TCP/UDP-порт или ICMP echo ID, network order.
uint8_t proto; // IPPROTO_*_UINT8.
uint8_t state; // EIM_NAT_ENTRY_FREE / ACTIVE / STATIC.
uint64_t src_node_id; // Узел-владелец mapping и адресат обратной отправки.
uint64_t last_seen; // Резерв, остаётся 0; таймауты записей не реализованы.
struct ETCP_CONN* src_conn; // Заимствованная метка исходного conn, может быть NULL; модуль её не разыменовывает.
};
// Состояние преобразования; TUN и транспортные ресурсы принадлежат nat_transport.
struct eim_nat_ctx {
uint32_t gateway_ip;
uint32_t gateway_ip; // Внешний IPv4 NAT, host order; nat_tun_ip, иначе tun_ip.
uint16_t port_start; // Начало динамического диапазона включительно; 1 <= port_start < port_end.
uint16_t port_end; // Конец диапазона включительно; допускается 65535.
uint16_t next_port;
struct eim_nat_entry* table;
size_t table_size;
int initialized;
uint16_t next_port; // Следующая позиция циклического поиска свободного динамического порта.
struct eim_nat_entry* table; // Владеет table_size записями; индекс — внешний порт/echo ID для всех протоколов вместе.
size_t table_size; // EIM_NAT_TABLE_SIZE при успешной инициализации.
int initialized; // 1 — таблица создана; 0 — NAT отключён, не создан или уничтожен.
};
struct global_config;
/* Создать ctx по g: IPv4 шлюза, 1 <= port_start < port_end <= 65535, статические пробросы.
* ctx не должен владеть предыдущей таблицей: перед повторным init вызвать destroy_ctx.
* 0 — успех (при !nat_enabled таблица не создаётся); -1 — ошибка, созданная таблица освобождена. */
int eim_nat_init_ctx(struct eim_nat_ctx* ctx, const struct global_config* g);
/* Освободить таблицу и обнулить созданный ctx; NULL и повторное уничтожение допустимы. */
void eim_nat_destroy_ctx(struct eim_nat_ctx* ctx);
/* 0 — обработано или пакет не подлежит NAT, -1 — ошибка; буфер принадлежит вызывающему. */
/* Изменить source IP и порт/echo ID в ip_data (ip_len байтов IPv4), выделив/переиспользовав mapping.
* src_node_id — владелец записи; src_conn — необязательная заимствованная метка только для новой ACTIVE-записи.
* Контрольные суммы должны быть корректны до вызова: модуль их обновляет, но не проверяет.
* ctx создан, ip_data — полный доступный для записи IPv4-пакет; буфер остаётся у вызывающего.
* 0 — преобразован или пропущен без изменений; -1 — короткий заголовок/неверный IHL/исчерпан пул. */
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);
/* out_entry изменяется только при найденном mapping; заранее установить *out_entry=NULL.
* Запись заимствована у ctx. 0 само по себе не означает, что пакет был преобразован. */
/* Для пакета на gateway_ip найти запись по внешнему порту/echo ID и протоколу, восстановить destination.
* ctx/ip_data/checksum — как у egress. out_entry необязателен и изменяется только при найденном mapping:
* заранее установить *out_entry=NULL. Запись заимствована у ctx до destroy_ctx.
* 0 — преобразован или не найден/не поддерживается; -1 — короткий заголовок/неверный IHL. */
int eim_nat_ingress(struct eim_nat_ctx* ctx, uint8_t* ip_data, size_t ip_len,
struct eim_nat_entry** out_entry);
/* Добавить TCP/UDP-проброс на node_id != 0: internal_ip_host — IPv4 host order,
* internal_port_net — ненулевой порт network order; external_port — 1..65535 host order,
* включая порты вне динамического диапазона. Ответ владельца использует тот же внешний порт.
* 0 — добавлен; -1 — 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, uint64_t node_id);
+15 -6
View File
@@ -2,7 +2,11 @@
* nat_via_node_id задаёт удалённого провайдера; при 0 узел сам выполняет eim_nat для клиентов.
* Приём ограничен группой UTUN; клиент принимает ответы только от настроенного провайдера.
* init создаёт TUN/обработчики по nat_enabled; destroy снимает их и освобождает ресурсы.
* Контекст принадлежит UTUN_INSTANCE; очереди и callbacks работают в uasync. */
* TUN-очередь содержит [prefix:1][IP]; tun_write принимает только IP без prefix.
* Отправка роутеру: [svc_id:1][IP], владение entry/dgram передаётся ему даже при ошибке.
* Приём использует общий ROUTER_SVC_HDR_SIZE=26: [svc][src][dst][flags][group][IP].
* Клиент не создаёт таблицу eim_nat: inst->nat.initialized служит флагом готовности транспорта.
* Контекст принадлежит UTUN_INSTANCE; все вызовы и callbacks работают в его uasync-потоке. */
#ifndef NAT_TRANSPORT_H
#define NAT_TRANSPORT_H
@@ -14,18 +18,23 @@ extern "C" {
#include <stdint.h>
struct tun_if;
struct ETCP_CONN;
struct nat_transport_ctx {
uint64_t self_node_id;
uint64_t nat_via_node_id;
struct tun_if* nat_tun;
int initialized;
uint64_t self_node_id; // Копия локального ID, установленная при init.
uint64_t nat_via_node_id; // 0 — провайдер; иначе ID единственного NAT-провайдера клиента.
struct tun_if* nat_tun; // Отдельный принадлежащий модулю TUN, MTU=TUN_MTU_DEFAULT.
int initialized; // TUN, binding и callback созданы; 0 при отключённом NAT/после destroy.
};
struct UTUN_INSTANCE;
/* inst и inst->config обязательны, ядро/роутер уже созданы; перед повторным init вызвать destroy.
* Создать отдельный TUN и binding ETCP_RT_ID_NAT; провайдер также создаёт eim_nat.
* 0 — успех, включая выключенный NAT; -1 — ошибка, созданные NAT-ресурсы освобождены.
* Настройка внешних маршрутов/доступа в интернет выполняется отдельно от этого API. */
int nat_transport_init(struct UTUN_INSTANCE* inst);
/* Снять binding, закрыть NAT TUN и уничтожить eim_nat; NULL и повторный вызов допустимы.
* Вызвать до освобождения роутера/uasync, вне выполняемого NAT callback. */
void nat_transport_destroy(struct UTUN_INSTANCE* inst);