Шлюзи VPN із високою пропускною здатністю часто підтримують вхідні з'єднання за протоколом TCP паралельно з основними тунелями UDP. В інфраструктурних середовищах TCP слугує резервним каналом передавання даних під час фільтрації трафіку UDP корпоративними мережами, а також використовується для службових протоколів та захищеного транспорту TLS. Відкриті публічні порти TCP 443 неминуче стикаються з масованими розподіленими атаками класу TCP SYN flood.
Хоча сучасні мережеві карти здатні обробляти мільйони пакетів щосекунди, стандартна підсистема відстеження з'єднань Linux (conntrack) стає слабкою ланкою під час шторму запитів. Якщо система створює запис стану для кожного вхідного пакета до перевірки клієнта, внутрішня таблиця переповнюється миттєво. Розв'язанням цієї проблеми є повне усунення стану під час початкового рукостискання за допомогою Linux nftables SYNPROXY.
Розуміння роботи SYNPROXY вимагає ретельного аналізу обробки пакетів підсистемою Netfilter під високим навантаженням.
Загроза переповнення таблиці conntrack:
Вхідний SYN Flood ──> Мережева карта (NIC) ──> Netfilter PREROUTING ──> Виділення пам'яті conntrack (struct nf_conn)
│
ПЕРЕПОВНЕННЯ (nf_conntrack: table full)
│
ВТРАТА ЗВ'ЯЗКУ (Скидання всіх сесій)
─────────────────────────────────────────────────────────────────────────────────────────────────────────────
Фільтрація без збереження стану через nftables SYNPROXY:
Вхідний SYN Flood ──> PREROUTING (notrack) ──> INPUT (SYNPROXY) ──> Відповідь SYN-ACK без стану (Syncookie)
│
(Пам'ять conntrack не виділяється)
│
Справжній клієнт надсилає ACK ─────────────────────────────────> Перевірка Syncookie ──> Створення conntrack ──> Демон VPN
Вузьке місце conntrack: Обмеження стандартних syncookie сокета
Системні інженери нерідко припускають, що увімкнення параметра net.ipv4.tcp_syncookies = 1 повністю захищає від атак SYN flood. На практиці цей механізм захищає лише локальну чергу очікування сокета (listen(backlog)), не захищаючи підсистему відстеження з'єднань Netfilter (nf_conntrack).
У мережевому стеку Linux підсистема Netfilter перехоплює трафік на етапі NF_INET_PRE_ROUTING, задовго до локального транспортного стека (NF_INET_LOCAL_IN). Коли пакет із прапорцем SYN потрапляє до системи, nf_conntrack відразу виділяє структуру пам'яті struct nf_conn і додає її до глобальної хеш-таблиці в стані SYN_RECV:
Надходження пакета ──> nf_conntrack_in() ──> init_conntrack() ──> kmem_cache_alloc(nf_conntrack_cachep)
Кожен запис займає від 320 до 384 байтів пам'яті ядра. За стандартного ліміту nf_conntrack_max у 262 144 записи атака потужністю 300 000 пакетів на секунду вичерпує таблицю менш ніж за 900 мілісекунд.
Наслідки переповнення conntrack:
- Ядро фіксує помилку
net_ratelimit: nf_conntrack: table full, dropping packet. - Активні туннелі VPN та нові легітимні з'єднання скидаються.
- Навантаження на процесор зростає через обробку переповнених списків у softirq.
Оскільки сокетні syncookie перевіряються у функції tcp_v4_rcv() вже після невдалого виділення пам'яті в nf_conntrack, вони не спрацьовують. Для захисту шлюзу перевірку рукостискання необхідно винести перед підсистемою відстеження стану.
Архітектура підсистеми Netfilter SYNPROXY
Механізм synproxy, реалізований у ядрі в файлі net/netfilter/nf_synproxy_core.c та доступний через nftables, функціонує як проксі-сервер TCP без збереження стану. Він розділяє встановлення з'єднання на два етапи: зовнішнє рукостискання без стану з клієнтом і наступне внутрішнє рукопожаття з локальною службою.
Зовнішній клієнт nftables SYNPROXY Локальний демон VPN
│ │ │
│─── 1. TCP SYN [MSS, WScale, SACK] ─────>│ (Без збереження стану в пам'яті) │
│ │ │
│<── 2. Відповідь SYN-ACK [Cookie] ───────│ (Криптографічний хеш 4-tuple та ISN) │
│ │ │
│─── 3. TCP ACK [Cookie + 1] ────────────>│ │
│ │─── 4. Локальний TCP SYN ─────────────>│
│ │<── 5. Локальний SYN-ACK [ISN демона] ─│
│ │─── 6. Локальний ACK ─────────────────>│
│ │ │
│═════════════════════════════════════════╪═══════════════════════════════════════│
│ Фаза передавання даних та коригування зміщення послідовності │
│─── 7. Трафік TLS / Дані ───────────────>│─── 8. Модифікація SEQ/ACK (дельта) ───>│
│<── 10. Модифікація SEQ/ACK (дельта) ────│<── 9. Відповідні дані ────────────────│
Процес обробки охоплює чотири етапи:
Етап 1: Виключення з відстеження
Вхідні пакети SYN до порту VPN позначаються директивою notrack у таблиці raw prerouting. Це запобігає виділенню пам'яті для struct nf_conn.
Етап 2: Генерація Syncookie без стану
Пакет переходить до ланцюжка INPUT із правилом SYNPROXY. Замість черги сокета SYNPROXY обчислює 32-бітний початковий номер послідовності (ISN) за допомогою криптографічного алгоритму на основі:
- IP-адрес джерела та призначення
- Портів джерела та призначення
- Початкового номера послідовності клієнта
- Внутрішнього секретного ключа ядра, що оновлюється кожні 60 секунд
- Закодованих параметрів TCP (MSS, Window Scaling, SACK)
SYNPROXY негайно надсилає клієнту пакет SYN-ACK із цим значенням. Жодних структур у пам'яті та таймерів не створюється. Якщо це була сфальсифікована атака, обробка завершується без навантаження на систему.
Етап 3: Перевірка підтвердження ACK та реєстрація стану
Справжній клієнт надсилає пакет ACK із номером Cookie + 1. SYNPROXY перехоплює його та перевіряє криптографічний хеш.
Після успішної перевірки:
- Створюється повноцінний запис
struct nf_connуnf_conntrack. - З'єднання переходить у статус
ESTABLISHED. - Відновлюються всі узгоджені параметри сесії TCP.
Етап 4: Локальне рукостискання та трансляція номерів
Оскільки локальний демон VPN очікує стандартне рукостискання, SYNPROXY створює локальний пакет SYN для локального сокета.
Після отримання відповіді SYN-ACK від демона із власним номером (ISN_server), SYNPROXY фіксує різницю:
$$\Delta = ext{ISN}_{ ext{server}} - ext{Cookie}$$
У подальшому під час передавання корисного навантаження SYNPROXY модифікує заголовки пакетів безпосередньо в ядрі:
- Для вхідного трафіку: збільшує номер послідовності на величину $\Delta$.
- Для вихідного трафіку: зменшує номер підтвердження на величину $\Delta$.
Ця трансляція виконується прозоро для застосунку з максимальною швидкодією.
Практична реалізація: Налаштування правил nftables SYNPROXY
Для надійного захисту створюється конфігурація nftables із чітким розділенням пріоритетів.
Конфігурація для захисту порту 443:
#!/usr/sbin/nft -f
flush ruleset
table inet vpn_filter {
synproxy synproxy_vpn {
mss 1460
wscale 7
timestamp sack-perm
}
chain raw_prerouting {
type filter hook prerouting priority raw; policy accept;
tcp dport 443 tcp flags syn notrack
}
chain filter_input {
type filter hook input priority filter; policy drop;
iif "lo" accept
ct state established,related accept
ct state invalid drop
tcp dport 443 synproxy config synproxy_vpn
tcp dport 443 ct state new accept
}
chain filter_forward {
type filter hook forward priority filter; policy drop;
}
chain filter_output {
type filter hook output priority filter; policy accept;
}
}
Застосування конфігурації:
sudo nft -f /etc/nftables.conf
Перевірка активних правил:
sudo nft list table inet vpn_filter
Оптимізація параметрів ядра та моніторинг
Для стабільної роботи SYNPROXY параметри мережевого стека Linux записуються у файл /etc/sysctl.d/99-synproxy.conf:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_timestamps = 1
net.netfilter.nf_conntrack_tcp_loose = 0
net.netfilter.nf_conntrack_max = 2097152
net.netfilter.nf_conntrack_buckets = 524288
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 10
net.netfilter.nf_conntrack_tcp_timeout_established = 3600
Застосування налаштувань:
sudo sysctl --system
Перевірка показників у реальному часі
Поточний стан підсистеми можна оцінити через інтерфейс /proc:
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/net/stat/synproxy
Показники лічильників:
entries: Кількість активних сесій під контролем SYNPROXY.syn_received: Число оброблених пакетів SYN без збереження стану.cookie_invalid: Кількість відхилених підроблених пакетів ACK.cookie_valid: Успішно підтверджені сесії, додані до conntrack.
Впровадження в архітектуру шлюзів RiceGuard
Безпека корпоративного рівня спирається на надійний захист кожного протокольного рівня. Попри те, що ядро RiceGuard працює на базі UDP з криптографічною перевіркою кукі, шлюзові вузли підтримують інтерфейси TCP для сумісності з обмеженими мережами та захисту запитів DNS через HTTPS.
Використання nftables SYNPROXY на зовнішньому периметрі дозволяє шлюзам RiceGuard витримувати масовані шторми сфальсифікованого трафіку без вичерпання ресурсів, забезпечуючи надійну роботу каналів зв'язку.



