Isolate NAT mappings by source node identity
This commit is contained in:
1 parent
a9820bea42
commit
3d0c4ff0a5
3 files changed
+41
-3
No files matched your search
+3
-3
@@ -72,10 +72,10 @@ static void csum_update_icmp(uint8_t* icmp, uint16_t old_word, uint16_t new_word
|
||||
|
||||
// Поиск в замкнутом диапазоне; индекс должен вмещать 65536 после последнего порта.
|
||||
static struct eim_nat_entry* eim_nat_find_egress(struct eim_nat_ctx* ctx,
|
||||
uint8_t proto, uint32_t ip_host, uint16_t port_net) {
|
||||
uint8_t proto, uint32_t ip_host, uint16_t port_net, uint64_t src_node_id) {
|
||||
for (uint32_t i = ctx->port_start; i <= ctx->port_end; i++) {
|
||||
struct eim_nat_entry* e = &ctx->table[i];
|
||||
if (e->state != EIM_NAT_ENTRY_FREE && e->proto == proto &&
|
||||
if (e->state != EIM_NAT_ENTRY_FREE && e->proto == proto && e->src_node_id == src_node_id &&
|
||||
e->internal_ip == ip_host && e->internal_port == port_net) return e;
|
||||
}
|
||||
return NULL;
|
||||
@@ -131,7 +131,7 @@ int eim_nat_egress(struct eim_nat_ctx* ctx, uint8_t* ip_data, size_t ip_len,
|
||||
}
|
||||
if (!is_tcp && !is_udp && !is_icmp_echo) return 0;
|
||||
|
||||
struct eim_nat_entry* entry = eim_nat_find_egress(ctx, proto, src_ip_host, src_port_net);
|
||||
struct eim_nat_entry* entry = eim_nat_find_egress(ctx, proto, src_ip_host, src_port_net, src_node_id);
|
||||
uint16_t ext_port_host;
|
||||
if (entry) {
|
||||
ext_port_host = (uint16_t)(entry - ctx->table);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eim_nat — таблица Endpoint-Independent Mapping для IPv4 TCP/UDP и ICMP echo.
|
||||
* Ключ mapping: (src_node_id, протокол, внутренний IP, внутренний порт/echo ID), без внешнего адресата.
|
||||
* init_ctx создаёт состояние из global_config; при отключённом NAT оставляет initialized=0.
|
||||
* egress/ingress меняют IP/порты и checksums на месте, не отправляют пакеты и не владеют TUN/ETCP.
|
||||
* IPv4 UDP: отключённая checksum=0 сохраняется; вычисленный ноль записывается как 0xffff.
|
||||
|
||||
@@ -937,6 +937,42 @@ static void test_udp_checksum_encoding(int computed_zero) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Перекрывающиеся частные адреса разных узлов не должны делить mapping и адресата ответа. */
|
||||
static void test_node_mapping_isolation(void) {
|
||||
TEST("mapping_isolated_by_source_node");
|
||||
struct global_config g = make_global_config();
|
||||
struct eim_nat_ctx ctx;
|
||||
ASSERT_EQ(eim_nat_init_ctx(&ctx, &g), 0, "node isolation context initialized");
|
||||
const size_t len = 28 + TEST_PAYLOAD_LEN;
|
||||
for (uint64_t node = 1; node <= 2; node++) {
|
||||
uint8_t* pkt = make_udp_pkt(TEST_IP_SRC_HOST, TEST_SRC_PORT, TEST_IP_DST_HOST, TEST_DST_PORT);
|
||||
int r = eim_nat_egress(&ctx, pkt, len, node, NULL);
|
||||
uint16_t port; memcpy(&port, pkt + 20, 2);
|
||||
free(pkt);
|
||||
ASSERT_EQ(r, 0, "node flow accepted");
|
||||
ASSERT_EQ(be16toh(port), TEST_PORT_START + node - 1, "each node has its own external port");
|
||||
}
|
||||
for (uint64_t node = 1; node <= 2; node++) {
|
||||
uint16_t external_port = TEST_PORT_START + node - 1;
|
||||
uint8_t* pkt = make_udp_pkt(TEST_IP_DST_HOST, TEST_DST_PORT, TEST_GW_HOST, external_port);
|
||||
struct eim_nat_entry* entry = NULL;
|
||||
int r = eim_nat_ingress(&ctx, pkt, len, &entry);
|
||||
uint16_t port; memcpy(&port, pkt + 22, 2);
|
||||
free(pkt);
|
||||
ASSERT_EQ(r, 0, "node response accepted");
|
||||
ASSERT(entry && entry->src_node_id == node, "response returns to its source node");
|
||||
ASSERT_EQ(be16toh(port), TEST_SRC_PORT, "node response restores private port");
|
||||
pkt = make_udp_pkt(TEST_IP_SRC_HOST, TEST_SRC_PORT, 0x08080404, TEST_DST_PORT);
|
||||
r = eim_nat_egress(&ctx, pkt, len, node, NULL);
|
||||
memcpy(&port, pkt + 20, 2);
|
||||
free(pkt);
|
||||
ASSERT_EQ(r, 0, "node flow reused for a different destination");
|
||||
ASSERT_EQ(be16toh(port), external_port, "node mapping remains endpoint independent");
|
||||
}
|
||||
eim_nat_destroy_ctx(&ctx);
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* Main
|
||||
* ================================================================ */
|
||||
@@ -959,6 +995,7 @@ int main(void) {
|
||||
test_checksum_update();
|
||||
test_udp_checksum_encoding(0);
|
||||
test_udp_checksum_encoding(1);
|
||||
test_node_mapping_isolation();
|
||||
|
||||
printf("\n=== Results: %d run, %d passed, %d failed ===\n",
|
||||
stats.run, stats.passed, stats.failed);
|
||||
|
||||
Reference in new issue
Block a user