Verify bounded global NAT pressure and retained destination across mapping reuse

This commit is contained in:
evgeny committed 2026-10-21 22:46:09 +02:00
1 parent 8360e48622
commit 80b481827c
1 file changed
+44 -1
+44 -1
View File
@@ -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;