Preserve NAT index invariants across transport and reuse tests

This commit is contained in:
evgeny committed 2026-10-21 22:31:55 +02:00
1 parent d0c83cfff1
commit 5e2e6c15cf
3 files changed
+11 -18

No files matched your search

+2
View File
@@ -102,9 +102,11 @@ static struct nat_peer* nat_peer_get(struct UTUN_INSTANCE* inst, uint64_t node_i
return NULL;
}
queue_set_callback(peer->packets, nat_peer_take, peer);
struct ll_queue* packets = peer->packets;
if (queue_data_put_with_index(tr->peers, &peer->ll) != 0) {
// put принимает/освобождает peer; отдельная очередь принадлежит вызывающему до успеха.
DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT peer index insertion failed node=%016llx", (unsigned long long)node_id);
queue_free(packets);
return NULL;
}
return peer;
+2 -2
View File
@@ -179,6 +179,8 @@ static void stress_egress_ingress_cycle(void) {
ASSERT_EQ(eim_nat_init_ctx(&ctx, &g), 0, "init");
const int CYCLES = 5000;
ASSERT_EQ(eim_nat_add_forward(&ctx, IPPROTO_UDP_UINT8, 0x0a000003, htobe16(50000), 1001, 2),
0, "reserve second port for cyclic reuse");
size_t len;
for (int cycle = 0; cycle < CYCLES; cycle++) {
uint8_t* pkt = make_udp_pkt(0x0A000002, 40000, 0x08080808, 53, &len);
@@ -205,8 +207,6 @@ static void stress_egress_ingress_cycle(void) {
// Free entry for next cycle
ASSERT_EQ(eim_nat_remove(&ctx, 1000), 1, "remove updates hash and free pool");
ASSERT_EQ(eim_nat_add_forward(&ctx, IPPROTO_UDP_UINT8, 0x0a000003, htobe16(50000), 1001, 2),
cycle == 0 ? 0 : -1, "other port remains reserved");
}
eim_nat_destroy_ctx(&ctx);
+7 -16
View File
@@ -461,14 +461,7 @@ static int test_provider_ingress_response(void) {
static int test_send_failure_ownership(int provider) {
struct UTUN_INSTANCE* sender = provider ? inst_provider : inst_client;
struct tun_if* tun = sender->nat_tr.nat_tun;
struct eim_nat_entry saved = {0};
uint16_t external_port = inst_provider->nat.port_start;
if (provider) {
saved = inst_provider->nat.table[external_port];
inst_provider->nat.table[external_port] = (struct eim_nat_entry){.internal_ip = 0x0a0000cd,
.internal_port = htobe16(44444), .proto = IPPROTO_UDP_UINT8,
.state = EIM_NAT_ENTRY_ACTIVE, .src_node_id = g_client_node_id};
}
size_t ip_len;
uint8_t* ip = provider ? build_udp_pkt(0x08080808, 80, inst_provider->nat.gateway_ip, external_port, &ip_len) :
build_udp_pkt(0x0a0000cd, 44444, 0x08080808, 80, &ip_len);
@@ -487,7 +480,6 @@ static int test_send_failure_ownership(int provider) {
if (!send_test_valid || queue_entry_count(tun->output_queue)) ok = 0;
send_test_mode = 0; send_test_instance = NULL;
free(ip);
if (provider) inst_provider->nat.table[external_port] = saved;
if (ok) DEBUG_INFO(DEBUG_CATEGORY_NAT, "PASS NAT %s send failure: no double free/leak, next packet accepted",
provider ? "provider" : "client");
else DEBUG_ERROR(DEBUG_CATEGORY_NAT, "FAIL NAT %s send failure: calls=%d valid=%d live_blocks=%zu baseline=%zu",
@@ -548,10 +540,9 @@ static int test_full_roundtrip(void) {
struct tun_if* client_tun = inst_client->nat_tr.nat_tun;
if (!client_tun) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "No client TUN"); return 0; }
// Clean NAT table from previous test
for (uint16_t p = inst_provider->nat.port_start; p <= inst_provider->nat.port_end; p++)
memset(&inst_provider->nat.table[p], 0, sizeof(struct eim_nat_entry));
inst_provider->nat.next_port = inst_provider->nat.port_start;
// Создать новый mapping без перезапуска/обнуления внутренних индексов после проверок отказов.
uint16_t external_port = inst_provider->nat.next_port;
if (!external_port) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "No free port for roundtrip"); return 0; }
// === Step 1: ОС клиента отправляет пакет в NAT TUN ===
size_t ip_len;
@@ -564,18 +555,18 @@ static int test_full_roundtrip(void) {
int cycles = 0;
while (cycles < 200 && !test_timed_out) {
uasync_poll(ua, 5); cycles++;
if (inst_provider->nat.table[inst_provider->nat.port_start].state != EIM_NAT_ENTRY_FREE) break;
if (inst_provider->nat.table[external_port].state != EIM_NAT_ENTRY_FREE) break;
}
// Verify NAT entry
struct eim_nat_entry* e = &inst_provider->nat.table[inst_provider->nat.port_start];
struct eim_nat_entry* e = &inst_provider->nat.table[external_port];
if (e->state != EIM_NAT_ENTRY_ACTIVE || e->internal_ip != 0x0A0000CD || e->internal_port != htobe16(44444)) {
DEBUG_ERROR(DEBUG_CATEGORY_NAT, "Egress entry not found: ip=%08x port=%u state=%d",
e->internal_ip, be16toh(e->internal_port), e->state);
return 0;
}
DEBUG_INFO(DEBUG_CATEGORY_NAT, "Egress entry ok: %08x:%u ext=%u proto=%u",
e->internal_ip, be16toh(e->internal_port), inst_provider->nat.port_start, e->proto);
e->internal_ip, be16toh(e->internal_port), external_port, e->proto);
// === Step 2: Manually inject internet response into provider's TUN ===
memset(&test_state.captured, 0, sizeof(test_state.captured));
@@ -584,7 +575,7 @@ static int test_full_roundtrip(void) {
uint32_t gw_ip_host = inst_provider->nat.gateway_ip;
size_t rip_len;
uint8_t* resp_ip = build_udp_pkt(0x08080808, 80, gw_ip_host, inst_provider->nat.port_start, &rip_len);
uint8_t* resp_ip = build_udp_pkt(0x08080808, 80, gw_ip_host, external_port, &rip_len);
if (tun_inject_packet(inst_provider->nat_tr.nat_tun, resp_ip, rip_len) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_NAT, "tun_inject response failed");
free(resp_ip); return 0;