← Усі статті

Transparent Gateway · HAProxy · redsocks · iptables · Мережі

Прозоре проксіювання TCP через redsocks і HAProxy

23 серпня 2026 р. · 5 хв читання

Схема прозорого проксіювання TCP через gateway і пул проксі-серверів.

У попередній статті про DNS-витоки вже використав цей механізм для DNS. Тут детально розберу прозоре проксіювання звичайного TCP-трафіку.

Схема працює за простим лінійним принципом: TCP-трафік надходить на gateway, перенаправляється до локального прозорого проксі, проходить через балансувальник і вибраний upstream proxy, а потім потрапляє на цільовий хост. Відповідь повертається тим самим ланцюжком у зворотному напрямку.

Для коректної ізоляції я налаштував між тестовими машинами окремий VLAN. Машина, трафік з якої проксіюю, не має прямого маршруту до інтернету: її запити проходять через Transparent Gateway.

Архітектура тестового стенда

Показати код
 Kali VM                        Gateway VM
  eth0  192.168.88.194/24        eth0  192.168.88.104/24
    │ vmbr0                        │ vmbr0
    │                              │

  eth1  192.168.90.10/24         eth1  192.168.90.1/24
    │ vmbr90                       │ vmbr90
    └──── ізольована внутрішня мережа ────┘

TCP-пакети з підмережі 192.168.90.0/24 перенаправляю на локальний порт 12345, який слухає redsocks.

Перехоплення TCP-трафіку через iptables

Bash-код
iptables -t nat -N TG_TCP

  iptables -t nat -A PREROUTING \
      -s 192.168.90.0/24 \
      -p tcp \
      -j TG_TCP

  iptables -t nat -A TG_TCP \
      -p tcp \
      -j REDIRECT \
      --to-ports 12345

У лабораторній схемі правило перехоплює весь TCP-трафік тестової підмережі. У production-конфігурації перед REDIRECT варто додати винятки для локальних мереж, адрес керування та інших напрямків, які не потрібно проксіювати.

Роль redsocks

redsocks працює як прозорий proxy client: приймає перенаправлене TCP-з'єднання, відкриває його через балансувальник і повертає відповідь клієнту. Я обрав redsocks, тому що це легка програма, яка виконує одну конкретну роль — слугує мостом між клієнтом і проксі-інфраструктурою.

Роль HAProxy

HAProxy балансує з'єднання між проксі-серверами та перевіряє працездатність кожного backend. Сервери, які не проходять health check, тимчасово виключаються з пулу й не отримують нових з'єднань.

Для нових з'єднань використовую roundrobin, який послідовно розподіляє їх між доступними backend. Stick-table — це не окремий алгоритм балансування, а таблиця стану: разом зі stick on src вона запам'ятовує відповідність IP клієнта вибраному backend і зберігає стабільну вихідну адресу в багатокрокових сценаріях.

Також я написав невелику REST API-обгортку над HAProxy Runtime API. Вона дає змогу переглядати поточний режим і перемикати стратегію без перезапуску балансувальника. API доступний лише в мережі керування, а операції зміни режиму захищені Bearer-токеном.

Шлях TCP-трафіку

Схема має одну основну гілку:

Показати код
      TCP             iptables
(VM) <----> (Gateway <--------> redsocks <---> HAProxy) <---> proxy <---> host

Пакет надходить від клієнта до Transparent Gateway, правило iptables перенаправляє з’єднання у redsocks, а HAProxy вибирає доступний proxy backend. Відповідь повертається через той самий backend, HAProxy і redsocks до клієнта. Переходжу до перевірки цієї схеми.

Перевірка ізоляції та вихідної IP-адреси

Спочатку перевіряю, чи достатньо ізольована робоча VM. Запит до ifconfig.me очікувано повернув IP-адресу проксі-сервера — отже, TCP-трафік проходить через Transparent Gateway.

На зображенні показані таблиця маршрутів і запит curl до ifconfig.me.

Таблиця маршрутів Kali VM та curl до ifconfig.me через проксі.
Таблиця маршрутів і перевірка вихідної IP-адреси через ifconfig.me.

Після видалення маршруту за замовчуванням доступ до мережі зник: curl не зміг виконати DNS-запит, а ping повернув Network is unreachable. Ця перевірка підтверджує, що іншого маршруту до інтернету VM не має.

Відсутність доступу до мережі після видалення default route.
Після видалення маршруту за замовчуванням прямого доступу до мережі немає.

Після цього повернув маршрут за замовчуванням через gateway 192.168.90.1 і повторив перевірку.

Відновлення default route через 192.168.90.1 та повторний curl.
Маршрут за замовчуванням повернуто через Transparent Gateway.

Додатково я обмежив management-інтерфейс VM правилами firewall гіпервізора.

Правила firewall для management-адреси та тестової підмережі.
Обмеження вихідного трафіку management-інтерфейсу на firewall гіпервізора.

Показані правила дозволяють явно заданий напрямок до тестової підмережі та блокують довільний вихід із management-адреси 192.168.88.194. TCP-трафік із тестової адреси 192.168.90.10 і далі проходить через gateway 192.168.90.1.

Під час першого налаштування мережа повністю перестала працювати через OutputPolicy=DROP: політика блокувала також пакети керування, для яких не було окремих правил. Для лабораторного стенда я встановив ACCEPT і залишив явне DROP для небажаного виходу через management-інтерфейс. У production-середовищі краще зберігати політику deny-by-default і додати точні правила для SSH та службового трафіку.

Тестування балансування

Для тестів я створив вісім легких LXC-контейнерів із вимкненим NAT, які імітують проксі-сервери. Зовнішній інтернет їм не потрібен: запити надсилаються до ехо-сервера, розгорнутого в тестовій мережі.

Для зручності REST API має endpoints для перемикання режиму балансування та перевірки поточного стану.

REST API повертає активний режим балансування roundrobin.
Перевірка поточного режиму балансування через REST API.

За замовчуванням активний режим roundrobin: кожне нове з’єднання послідовно передається наступному доступному proxy backend, тому навантаження розподіляється рівномірно.

Ехо-сервер працює за адресою http://10.10.10.2:8000. Надсилаю до нього десять запитів через gateway.

Логи десяти CONNECT-запитів, розподілених між LXC-контейнерами.
Розподіл десяти запитів між proxy backend у режимі roundrobin.

У логах видно десять CONNECT-запитів. Якщо впорядкувати записи за timestamp, контейнери проходять послідовно, після чого цикл починається знову — roundrobin працює.

Перемикання HAProxy у режим stick-table через REST API.
REST API перемикає прив’язку клієнта до backend через stick-table.

Після цього через REST API перемикаю режим на stick-table і повторюю ті самі десять запитів. Усі їх зафіксував контейнер CT-302: прив’язка клієнта до одного backend працює.

Десять запитів stick-table потрапили до контейнера CT-302.
У режимі stick-table всі запити одного клієнта обробив CT-302.

Перевірка вбудованого health check

Щоб переконатися, що HAProxy не передає нові з’єднання непрацездатному проксі-серверу, я вимкнув один із тестових контейнерів і виконав десять запитів. Усі вони повернули HTTP 200, а в логах не з’явилися нові записи від вимкненого backend. Для production-моніторингу стан DOWN додатково варто контролювати через HAProxy Runtime API або сторінку статистики.

Усі 10 запитів успішно пройшли й повернули HTTP 200.

Десять відповідей HTTP 200 після вимкнення одного proxy backend.
Усі десять запитів успішні після виключення непрацездатного backend.

Прозоре проксіювання TCP реалізовано. Наступний крок — збір проксі-серверів із дозволених джерел, їх ранжування та перевірка перед завантаженням у балансувальник. Про це буде наступний матеріал.

Поточна схема перехоплює TCP-трафік. Довільний UDP, зокрема QUIC/HTTP3 через UDP/443, цими правилами не проксіюється; DNS обробляється окремими маршрутами, описаними в попередній статті.

Стежити за розвитком проєкту та переглянути код можна в репозиторії: TransparentGateway на GitHub.