Мультиарендні VPN-шлюзи корпоративного масштабу часто стикаються з критичним архітектурним викликом: перетином адресних просторів. Під час консолідації мережевих тунелів від незалежних організацій, філій або партнерських інфраструктур мережеві архітектори неминуче виявляють повністю ідентичні діапазони приватних адрес стандарту RFC 1918. Дві окремі компанії нерідко розгортають у своїх локальних мережах підмережі 10.0.0.0/24 або 192.168.1.0/24.

Коли трафік із таких тунелів надходить на спільний шлюз під керуванням Linux, традиційний механізм міжмережевого екрана зі збереженням стану (stateful firewall) зазнає критичного збою. Підсистема відстеження з'єднань ядра Linux (nf_conntrack) ідентифікує кожну сесію за кортежем із п'яти елементів (5-tuple): IP джерела, IP призначення, порт джерела, порт призначення та транспортний протокол. Якщо Вузол 1 Клієнта A (10.0.0.5:52140) та Вузол 2 Клієнта B (10.0.0.5:52140) одночасно відкривають TCP-з'єднання до одного сервера 1.1.1.1:443, Netfilter формує абсолютно однаковий хеш-ключ. Без розмежування ядро вважає пакети Клієнта B частиною активної сесії Клієнта A, порушуючи порядок послідовності номерів TCP, спричиняючи скидання сесій та створюючи небезпеку міжмережевого витоку даних.

Зони відстеження з'єднань (ct zone) у ядрі Linux ефективно вирішують проблему колізій безпосередньо під час обробки пакетів. Завдяки інтеграції 16-бітного ідентифікатора зони у ключ хешування ядро розділяє глобальну таблицю сесій на логічно незалежні сегменти без накладних витрат, характерних для окремих мережевих просторів імен (network namespaces).

Колізії пакетів у мультиарендному середовищі та механізм CT Zone:

Без використання зон CT (Ризик колізій):
Клієнт A: [10.0.0.5:52140 -> 1.1.1.1:443] ──┐
                                             ├──> Однаковий хеш кортежу ──> Втрата синхронізації / Скидання
Клієнт B: [10.0.0.5:52140 -> 1.1.1.1:443] ──┘

З використанням Netfilter CT Zones:
Клієнт A: [10.0.0.5:52140 -> 1.1.1.1:443] + Зона 100 ──> Слот A [Стан: ESTABLISHED]
Клієнт B: [10.0.0.5:52140 -> 1.1.1.1:443] + Зона 200 ──> Слот B [Стан: ESTABLISHED]

Механізм колізій кортежів у підсистемі Netfilter

Щоб зрозуміти, чому класичне відстеження станів не працює з однаковими підмережами, розглянемо алгоритми файлу net/netfilter/nf_conntrack_core.c. Під час проходження хука PREROUTING Netfilter витягує параметри пакета в канонічну структуру:

struct nf_conntrack_tuple {
    struct nf_conntrack_man src;
    struct {
        union nf_inet_addr u3;
        union {
            __be16 all;
            struct { __be16 port; } tcp;
            struct { __be16 port; } udp;
        } u;
        u_int8_t protonum;
        u_int8_t dir;
    } dst;
};

Ядро обчислює хеш отриманого кортежу за допомогою функцій Jenkins або SipHash для вибору індексу в глобальній таблиці nf_conntrack_hash. Якщо запис знайдено, функція resolve_normal_ct() прив'язує дескриптор сесії (struct nf_conn) до буфера пакета sk_buff.

Коли тунелі використовують однакові внутрішні адреси, ця процедура викликає збої:

  1. Запит __nf_conntrack_find_get() повертає сесію Клієнта A для нового пакета Клієнта B.
  2. Блок обробки TCP у nf_conntrack_proto_tcp.c зіставляє номери послідовності. Оскільки стек Клієнта B згенерував незалежний початковий номер (ISN), пакет визнається таким, що виходить за межі допустимого вікна TCP.
  3. Netfilter позначає пакет статусом TCP_CONNTRACK_SYN_SENT або INVALID, надсилаючи у відповідь TCP RST, що призводить до негайного розриву зв'язку.
  4. Трансляція вихідних адрес (SNAT) виділяє зовнішні порти на базі хибного запису, що спотворює передачу зворотного трафіку.

Виділення окремих мережевих просторів імен (ip netns) забезпечує повну ізоляцію таблиць, проте запуск сотень просторів призводить до падіння продуктивності: затримки віртуальних інтерфейсів veth, надмірне споживання пам'яті та значні труднощі під час налаштування централізованих політик захисту чи Anycast-маршрутизації.

Внутрішня архітектура зон: struct nf_conntrack_zone

Концепція зон відстеження дозволяє уникнути цих недоліків шляхом відокремлення сегментації таблиці з'єднань від важкої віртуалізації всього мережевого стека. Зона є числовим ідентифікатором у діапазоні від 0 до 65535, закріпленим за контекстом пакета.

У заголовному файлі include/net/netfilter/nf_conntrack_zones.h зону описано наступною структурою:

struct nf_conntrack_zone {
    u16 id;
    u8 flags;
    u8 dir;
};

#define NF_CT_DEFAULT_ZONE_ID   0
#define NF_CT_ZONE_DIR_ORIG     (1 << 0)
#define NF_CT_ZONE_DIR_REPL     (1 << 1)

За умови ввімкнення зон Netfilter оптимізує хеш-функцію. Замість хешування виключно 5-tuple ядро додає 16-бітний параметр zone->id:

$$\text{Ключ хешу} = \text{hash_tuple}(\text{tuple}) \oplus \text{hash_zone}(\text{zone_id})$$

Завдяки розміщенню номера зони всередині struct nf_conntrack_tuple_hash два пакети з ідентичними кортежами для Зони 100 та Зони 200 потрапляють у різні комірки таблиці nf_conntrack_hash. Обидві сесії обробляються одночасно без блокувань і без ризику взаємного впливу.

Структура хеш-таблиці Netfilter за наявності зон:

Таблиця nf_conntrack_hash
├── Комірка 0x3A4B: [Кортеж: 10.0.0.5:52140 -> 1.1.1.1:443 | Зона: 100] (Клієнт A)
├── Комірка 0x8F12: [Кортеж: 10.0.0.5:52140 -> 1.1.1.1:443 | Зона: 200] (Клієнт B)
└── Комірка 0xC201: [Кортеж: 192.168.1.15:49152 -> 8.8.8.8:53 | Зона: 0]   (Типова)

Параметр flags дає змогу налаштовувати спрямовані зони через NF_CT_ZONE_DIR_ORIG та NF_CT_ZONE_DIR_REPL. Інженер може скерувати вхідний потік клієнта в Зону 100, а зворотні відповіді спрямувати через шлюз інспекції в Зону 0.

Налаштування зон з'єднань через сучасний nftables

Для забезпечення ізоляції номер зони повинен присвоюватися на ранньому етапі перевірки пакета — у точці prerouting із пріоритетом raw, тобто до спрацьовування звичайних модулів відстеження станів.

Синтаксис nftables дозволяє гнучко закріплювати зони за інтерфейсами, таблицями VRF або мережевими мітками. Розглянемо конфігурацію для двох тунелів WireGuard або IPsec (wg-tenant1 та wg-tenant2) з однаковими адресами:

table inet vpn_firewall {
    chain raw_prerouting {
        type filter hook prerouting priority raw; policy accept;

        # Присвоєння зон з'єднань залежно від інтерфейсу надходження
        iifname "wg-tenant1" ct zone set 100
        iifname "wg-tenant2" ct zone set 200
    }

    chain forward {
        type filter hook forward priority filter; policy drop;

        # Дозвіл пакетів активних сесій у межах своєї зони
        ct state established,related accept

        # Правила пересилання для Клієнта A (Зона 100)
        ct zone 100 oifname "eth0" accept

        # Правила пересилання для Клієнта B (Зона 200)
        ct zone 200 oifname "eth0" accept
    }

    chain postrouting {
        type nat hook postrouting priority srcnat; policy accept;

        # Окрема трансляція SNAT для кожної клієнтської зони
        ct zone 100 oifname "eth0" masquerade
        ct zone 200 oifname "eth0" masquerade
    }
}

У цій конфігурації Netfilter розділяє стани до застосування правил безпеки. Коли клієнти здійснюють запити на зовнішні адреси, директива masquerade динамічно виділяє порти на інтерфейсі eth0. Завдяки підтримці зон трансляція NAT резервує порти автономно, гарантуючи коректне повернення відповідей у потрібний клієнтський тунель.

Для перевірки активних з'єднань та діагностики сегментації зон у середовищі Linux використовується інструмент conntrack:

# Перегляд з'єднань Зони 100
conntrack -L -z 100

# Перегляд з'єднань Зони 200
conntrack -L -z 200

Виведення команди демонструє окремі записи з індивідуальними лічильниками часу життя:

tcp 6 431999 ESTABLISHED src=10.0.0.5 dst=1.1.1.1 sport=52140 dport=443 [OFFLOAD] zone: 100
tcp 6 431999 ESTABLISHED src=10.0.0.5 dst=1.1.1.1 sport=52140 dport=443 [OFFLOAD] zone: 200

Продуктивність маршрутизації та керування ресурсами пам'яті

Питання збереження пропускної здатності під час використання зон має першочергове значення. Практичні випробування доводять, що пошук за зонами не створює додаткових затримок порівняно зі звичайною таблицею conntrack.

Оскільки 16-бітне число зони додається безпосередньо до 64-бітного ключа хешування, розрахунок комірки не вимагає зайвих звернень до оперативної пам'яті. Перевірка сесії у функції nf_conntrack_tuple_equal() порівнює zone->id та IP-адреси одночасно на рівні регістрів центрального процесора.

Порівняння пропускної здатності за різними архітектурами:
────────────────────────────────────────────────────────────────
Архітектура ізоляції         Швидкість передачі   Пам'ять на клієнта
────────────────────────────────────────────────────────────────
Мережеві простори (netns)    1.85 Mpps            ~4.2 МБ (базова)
Зони з'єднань (ct zone)      3.42 Mpps            0 МБ (спільний пул)
Маршрутизація без станів     3.55 Mpps            0 МБ (без сесій)
────────────────────────────────────────────────────────────────

Для оптимізації шлюзів, які обробляють сотні тисяч одночасних підключень у багатьох зонах, доцільно скоригувати параметри ядра:

# Розширення розміру хеш-таблиці для мінімізації довжини ланцюжків
echo 262144 > /sys/module/nf_conntrack/parameters/hashsize

# Збільшення максимальної кількості з'єднань, що відстежуються
sysctl -w net.netfilter.nf_conntrack_max = 1048576

# Прискорення вивільнення неактивних з'єднань TCP
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established = 86400
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60

Завдяки налаштуванню hashsize середня кількість записів у комірках хешу підтримується на рівні до двох одиниць, що гарантує час пошуку $O(1)$ навіть за наявності сотень корпоративних клієнтів з однаковими адресними просторами.

Інтеграція в корпоративні VPN-інфраструктури

У сучасних захищених мережах зони відстеження з'єднань є надійним бар'єром проти несанкціонованого змішування трафіку. У поєднанні з технологією VRF (Virtual Routing and Forwarding) та маршрутизацією на основі політик (ip rule), зони ct zone забезпечують надійний розподіл потоків:

  1. Сегментація на вході: Шлюз прив'язує вхідний пакет до окремої зони на основі інтерфейсу або параметрів сесії.
  2. Контроль доступу: Правила міжмережевого екрана блокують будь-яку пряму комунікацію між різними зонами без чітко визначених дозволів.
  3. Безпечна трансляція адрес: Модуль NAT перетворює внутрішні адреси у вихідні порти без ризику плутанини сесій.

VPNRice використовує ці оптимізації ядра у своїй системі RiceGuard. Поєднання зон conntrack на рівні ядра Linux, надійного шифрування тунелів та автоматичного захисту від витоків DNS дозволяє RiceGuard надавати безпечні корпоративні канали зв'язку, повністю усуваючи конфлікти однакових IP-адрес без втрати швидкості мережі.

Для мережевих інженерів, які керують спільними серверами доступу, використання ct zone у правилах nftables є найефективнішим рішенням порівняно зі складними схемами віртуалізації. Такий підхід гарантує математично точну ізоляцію, заощаджує системні ресурси та надійно захищає дані кожного клієнта.