From 80b481827cf05be248b04b715bf9345dc2db8c39 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 21 Oct 2026 22:46:09 +0200 Subject: [PATCH] Verify bounded global NAT pressure and retained destination across mapping reuse --- tests/test_nat_transport.c | 45 +++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/tests/test_nat_transport.c b/tests/test_nat_transport.c index 63e04323..863bfc26 100644 --- a/tests/test_nat_transport.c +++ b/tests/test_nat_transport.c @@ -524,7 +524,8 @@ static int test_unexpected_nat_sender(int wrong_group) { /* Первый входящий пакет по статическому пробросу ниже динамического диапазона доходит до заданного узла. */ static int test_static_forward_delivery(void) { - if (eim_nat_add_forward(&inst_provider->nat, IPPROTO_UDP_UINT8, 0x0a0000ce, htobe16(8081), 8080, g_client_node_id)) return 0; + if (inst_provider->nat.table[8080].state == EIM_NAT_ENTRY_FREE && + eim_nat_add_forward(&inst_provider->nat, IPPROTO_UDP_UINT8, 0x0a0000ce, htobe16(8081), 8080, g_client_node_id)) return 0; size_t len; uint8_t* packet = build_udp_pkt(0x08080808, 53, inst_provider->nat.gateway_ip, 8080, &len); test_state.capture_count = 0; test_state.captured_len = 0; @@ -730,6 +731,47 @@ static int test_slow_peer_and_shutdown(void) { return ok; } +/* Общий предел останавливает TUN. После освобождения места адресат и уже преобразованный IP сохраняются. */ +static int test_global_backpressure(void) { + const uint64_t base = UINT64_C(0x8000000010000000); + size_t len; + for (uint32_t peer = 0; peer <= NAT_PENDING_TOTAL / NAT_PENDING_PER_PEER; peer++) { + uint16_t external = 1000 + peer; + if (eim_nat_add_forward(&inst_provider->nat, IPPROTO_UDP_UINT8, 0x0a000100 + peer, htobe16(5000), external, base + peer)) return 0; + uint8_t* packet = build_udp_pkt(0x08080808, 53, inst_provider->nat.gateway_ip, external, &len); + unsigned int count = peer < NAT_PENDING_TOTAL / NAT_PENDING_PER_PEER ? ROUTER_MAX_SEND_Q_PACKETS + NAT_PENDING_PER_PEER : 1; + for (unsigned int i = 0; i < count; i++) { + if (tun_inject_packet(inst_provider->nat_tr.nat_tun, packet, len)) { free(packet); return 0; } + } + free(packet); + } + struct nat_transport_ctx* tr = &inst_provider->nat_tr; + int ok = tr->pending_count == NAT_PENDING_TOTAL && tr->blocked_packet && queue_entry_count(tr->nat_tun->output_queue) == 1; + uint64_t saved_destination = tr->blocked_destination; + uint16_t external = 1000 + NAT_PENDING_TOTAL / NAT_PENDING_PER_PEER; + if (eim_nat_remove(&inst_provider->nat, external) != 1 || + eim_nat_add_forward(&inst_provider->nat, IPPROTO_UDP_UINT8, 0x0a000099, htobe16(9999), external, 0xabcdef)) ok = 0; + struct ETCP_ROUTER_CONN* route = etcp_router_conn_get(inst_provider, TOPO_GROUP_UTUN, base, ETCP_RT_ID_NAT); + struct ll_entry* consumed = queue_data_get(route->send_q); // Освободить один слот, вызвав реальный producer waiter. + if (!consumed) ok = 0; + else { queue_dgram_free(consumed); queue_entry_free(consumed); } + queue_resume_callback(route->send_q); + for (int cycles = 0; cycles < 20 && tr->blocked_packet; cycles++) uasync_poll(ua, 0); + if (tr->blocked_packet || queue_entry_count(tr->nat_tun->output_queue) || tr->pending_count >= NAT_PENDING_TOTAL) ok = 0; + struct ETCP_ROUTER_CONN* resumed = etcp_router_conn_get(inst_provider, TOPO_GROUP_UTUN, saved_destination, ETCP_RT_ID_NAT); + if (!resumed || !resumed->send_q->head || resumed->send_q->head->len != 42) ok = 0; + else { + uint32_t destination; memcpy(&destination, resumed->send_q->head->dgram + 16, 4); + if (destination != htobe32(0x0a000100 + NAT_PENDING_TOTAL / NAT_PENDING_PER_PEER)) ok = 0; + } + nat_transport_destroy(inst_provider); + uasync_poll(ua, 0); + if (inst_provider->nat_tr.initialized || inst_provider->nat_tr.pending_count) ok = 0; + if (ok) DEBUG_INFO(DEBUG_CATEGORY_NAT, "PASS global NAT backpressure: bounded at 1024, TUN pause/resume, mapping reuse and pending shutdown"); + else DEBUG_ERROR(DEBUG_CATEGORY_NAT, "FAIL global NAT backpressure"); + return ok; +} + // ==================== Main ==================== int main(void) { int test_result = 1; @@ -809,6 +851,7 @@ int main(void) { total++; if (test_tun_write_backpressure()) passed++; else DEBUG_ERROR(DEBUG_CATEGORY_NAT, "FAIL: tun_write_backpressure"); #endif total++; if (test_slow_peer_and_shutdown()) passed++; else DEBUG_ERROR(DEBUG_CATEGORY_NAT, "FAIL: slow_peer_shutdown"); + total++; if (test_global_backpressure()) passed++; else DEBUG_ERROR(DEBUG_CATEGORY_NAT, "FAIL: global_backpressure"); printf("\n=== NAT Transport Tests: %d/%d passed ===\n", passed, total); test_result = (passed == total) ? 0 : 1;