Transparent Gateway · HAProxy · redsocks · iptables · Мережі
Прозоре проксіювання TCP через redsocks і HAProxy
У попередній статті про 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.

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

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

Додатково я обмежив management-інтерфейс VM правилами 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 для перемикання режиму балансування та перевірки поточного стану.

За замовчуванням активний режим roundrobin: кожне нове з’єднання послідовно передається наступному доступному proxy backend, тому навантаження розподіляється рівномірно.
Ехо-сервер працює за адресою http://10.10.10.2:8000. Надсилаю до нього десять запитів через gateway.

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

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

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

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