Fix NAT flow lookup at the maximum port boundary

This commit is contained in:
evgeny committed 2026-10-21 21:48:28 +02:00
1 parent fbbd62acc4
commit 6e9bacd843
3 files changed
+57 -3

No files matched your search

+2 -1
View File
@@ -67,9 +67,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 после последнего порта.
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) {
for (uint16_t i = ctx->port_start; i <= ctx->port_end; i++) {
for (uint32_t i = ctx->port_start; i <= ctx->port_end; i++) {
struct eim_nat_entry* e = &ctx->table[i];
if (e->state != EIM_NAT_ENTRY_FREE && e->proto == proto &&
e->internal_ip == ip_host && e->internal_port == port_net) return e;
+2 -2
View File
@@ -40,8 +40,8 @@ struct eim_nat_entry {
// Состояние преобразования; TUN и транспортные ресурсы принадлежат nat_transport.
struct eim_nat_ctx {
uint32_t gateway_ip;
uint16_t port_start;
uint16_t port_end;
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;
+53
View File
@@ -297,6 +297,58 @@ static void test_port_alloc(void) {
PASS();
}
/* Верхняя граница 65535: поиск отсутствующего потока, оба порта, wrap, reuse и исчерпание. */
static void test_port_limit(void) {
TEST("port_range_ending_at_65535");
struct global_config g = make_global_config();
g.nat_port_start = 65534; g.nat_port_end = 65535;
struct eim_nat_ctx ctx;
ASSERT_EQ(eim_nat_init_ctx(&ctx, &g), 0, "init maximum port range");
const size_t len = 28 + TEST_PAYLOAD_LEN;
for (unsigned int i = 0; i < 2; i++) {
uint8_t* pkt = make_udp_pkt(TEST_IP_SRC_HOST, TEST_SRC_PORT + i, TEST_IP_DST_HOST, TEST_DST_PORT);
int r = eim_nat_egress(&ctx, pkt, len, 1, get_mock_conn());
uint16_t port; memcpy(&port, pkt + 20, 2);
free(pkt);
ASSERT_EQ(r, 0, "new flow completes at maximum range");
ASSERT_EQ(be16toh(port), 65534 + i, "both boundary ports allocated");
ASSERT_EQ(ctx.table[65534 + i].state, EIM_NAT_ENTRY_ACTIVE, "boundary entry active");
}
ASSERT_EQ(ctx.next_port, 65534, "allocator wraps from 65535 to port_start");
uint8_t* pkt = make_udp_pkt(TEST_IP_SRC_HOST, TEST_SRC_PORT + 2, TEST_IP_DST_HOST, TEST_DST_PORT);
uint8_t original[28 + TEST_PAYLOAD_LEN]; memcpy(original, pkt, len);
int r = eim_nat_egress(&ctx, pkt, len, 1, get_mock_conn());
int unchanged = memcmp(pkt, original, len) == 0;
free(pkt);
ASSERT_EQ(r, -1, "exhausted maximum range returns error");
ASSERT(unchanged, "exhaustion preserves packet");
for (unsigned int i = 0; i < 2; i++) {
pkt = make_udp_pkt(TEST_IP_SRC_HOST, TEST_SRC_PORT + i, 0x08080404, TEST_DST_PORT);
r = eim_nat_egress(&ctx, pkt, len, 1, get_mock_conn());
uint16_t port; memcpy(&port, pkt + 20, 2);
free(pkt);
ASSERT_EQ(r, 0, "existing flow works after exhaustion");
ASSERT_EQ(be16toh(port), 65534 + i, "existing flow keeps boundary port");
}
pkt = make_udp_pkt(TEST_IP_DST_HOST, TEST_DST_PORT, TEST_GW_HOST, 65535);
struct eim_nat_entry* entry = NULL;
r = eim_nat_ingress(&ctx, pkt, len, &entry);
uint16_t port; memcpy(&port, pkt + 22, 2);
free(pkt);
ASSERT_EQ(r, 0, "reply to 65535 accepted");
ASSERT(entry == &ctx.table[65535], "reply finds last table entry");
ASSERT_EQ(be16toh(port), TEST_SRC_PORT + 1, "reply restores internal port");
ctx.table[65535].state = EIM_NAT_ENTRY_FREE;
pkt = make_udp_pkt(TEST_IP_SRC_HOST, TEST_SRC_PORT + 2, TEST_IP_DST_HOST, TEST_DST_PORT);
r = eim_nat_egress(&ctx, pkt, len, 1, get_mock_conn());
memcpy(&port, pkt + 20, 2);
free(pkt);
ASSERT_EQ(r, 0, "allocator skips occupied port after wrap");
ASSERT_EQ(be16toh(port), 65535, "allocator reuses free maximum port");
eim_nat_destroy_ctx(&ctx);
PASS();
}
/* ================================================================
* Test 3: Egress NAT — UDP
* ================================================================ */
@@ -775,6 +827,7 @@ int main(void) {
test_init_destroy();
test_port_alloc();
test_port_limit();
test_egress_udp();
test_egress_tcp();
test_egress_icmp();