Preserve NAT index invariants across transport and reuse tests
This commit is contained in:
1 parent
d0c83cfff1
commit
5e2e6c15cf
3 files changed
+11
-18
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user