diff --git a/src/nat_transport.c b/src/nat_transport.c index 7d0fc3cf..b6b7dcf9 100644 --- a/src/nat_transport.c +++ b/src/nat_transport.c @@ -111,6 +111,14 @@ static void nat_transport_etcp_recv_cb(struct ETCP_CONN* conn, struct ll_entry* uint64_t src_node_id; memcpy(&src_node_id, entry->dgram + ROUTER_SVC_SRC_OFF, 8); + uint64_t group_id; + memcpy(&group_id, entry->dgram + ROUTER_SVC_GROUP_OFF, 8); + if (group_id != TOPO_GROUP_UTUN || (tr->nat_via_node_id && src_node_id != tr->nat_via_node_id)) { + DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT receive rejected: group=%016llx source=%016llx configured_provider=%016llx", + (unsigned long long)group_id, (unsigned long long)src_node_id, (unsigned long long)tr->nat_via_node_id); + queue_dgram_free(entry); queue_entry_free(entry); + return; + } uint8_t* ip_data = entry->dgram + ROUTER_SVC_PAYLOAD_OFF; size_t ip_len = entry->len - ROUTER_SVC_PAYLOAD_OFF; diff --git a/src/nat_transport.h b/src/nat_transport.h index d28f6336..820294e2 100644 --- a/src/nat_transport.h +++ b/src/nat_transport.h @@ -1,5 +1,6 @@ /* IPv4 NAT через отдельный TUN и сервис ETCP_RT_ID_NAT в UTUN-router. * nat_via_node_id задаёт удалённого провайдера; при 0 узел сам выполняет eim_nat для клиентов. + * Приём ограничен группой UTUN; клиент принимает ответы только от настроенного провайдера. * init создаёт TUN/обработчики по nat_enabled; destroy снимает их и освобождает ресурсы. * Контекст принадлежит UTUN_INSTANCE; очереди и callbacks работают в uasync. */ #ifndef NAT_TRANSPORT_H diff --git a/tests/test_nat_transport.c b/tests/test_nat_transport.c index fd589e53..e4d5197b 100644 --- a/tests/test_nat_transport.c +++ b/tests/test_nat_transport.c @@ -496,6 +496,27 @@ static int test_send_failure_ownership(int provider) { } #endif +/* Loopback проходит реальный router API: клиент не принимает IP от постороннего узла/группы. */ +static int test_unexpected_nat_sender(int wrong_group) { + size_t len; + uint8_t* packet = build_udp_pkt(0x08080808, 53, 0x0a0000cd, 44444, &len); + struct ll_entry* entry = ll_alloc_lldgram((uint16_t)(len + 1)); + if (!entry) { free(packet); DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT sender test allocation failed"); return 0; } + entry->dgram[0] = ETCP_RT_ID_NAT; memcpy(entry->dgram + 1, packet, len); entry->len = len + 1; + free(packet); + uint64_t saved_provider = inst_client->nat_tr.nat_via_node_id; + if (wrong_group) inst_client->nat_tr.nat_via_node_id = g_client_node_id; + int r = etcp_route_send(inst_client, wrong_group ? 1234 : TOPO_GROUP_UTUN, g_client_node_id, entry, 0, 0); + inst_client->nat_tr.nat_via_node_id = saved_provider; + test_state.captured_len = 0; test_state.capture_count = 0; + capture_tun_read(inst_client->nat_tr.nat_tun); + int ok = r == 0 && !test_state.capture_count; + if (ok) DEBUG_INFO(DEBUG_CATEGORY_NAT, "PASS NAT client rejects unexpected %s", wrong_group ? "group" : "sender"); + else DEBUG_ERROR(DEBUG_CATEGORY_NAT, "FAIL NAT client accepted unexpected %s: result=%d captured=%d", + wrong_group ? "group" : "sender", r, test_state.capture_count); + return ok; +} + /* Первый входящий пакет по статическому пробросу ниже динамического диапазона доходит до заданного узла. */ 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; @@ -656,6 +677,8 @@ int main(void) { total++; if (test_send_failure_ownership(0)) passed++; else DEBUG_ERROR(DEBUG_CATEGORY_NAT, "FAIL: client send ownership"); total++; if (test_send_failure_ownership(1)) passed++; else DEBUG_ERROR(DEBUG_CATEGORY_NAT, "FAIL: provider send ownership"); #endif + total++; if (test_unexpected_nat_sender(0)) passed++; else DEBUG_ERROR(DEBUG_CATEGORY_NAT, "FAIL: unexpected_sender"); + total++; if (test_unexpected_nat_sender(1)) passed++; else DEBUG_ERROR(DEBUG_CATEGORY_NAT, "FAIL: unexpected_group"); // Реальная доставка после инъекций проверяет восстановление обеих веток без перезапуска NAT. total++; if (test_full_roundtrip()) passed++; else DEBUG_ERROR(DEBUG_CATEGORY_NAT, "FAIL: full_roundtrip"); total++; if (test_static_forward_delivery()) passed++; else DEBUG_ERROR(DEBUG_CATEGORY_NAT, "FAIL: static_forward");