Перенаправляем весь трафик контейнера через SOCKS-прокси с помощью tun2socks

Опубликовано 17.06.2025

Иногда возникает необходимость направлять весь исходящий трафик определённого контейнера через прокси-сервер. Это может быть полезно для обеспечения анонимности, обхода геоблокировок или для тестирования сетевых конфигураций. В этой статье мы рассмотрим, как настроить такую систему, используя утилиту tun2socks и правила iptables, а также как управлять этим процессом с помощью systemd.


Что такое tun2socks?

tun2socks – это мощный инструмент, который позволяет перенаправлять сетевой трафик, предназначенный для TUN-устройства, через SOCKS-прокси. Он создаёт виртуальный сетевой интерфейс (TUN-устройство), весь трафик которого заворачивается в SOCKS-соединение. Это особенно удобно, когда прямое проксирование на уровне приложения невозможно или нежелательно.


Установка tun2socks

Для начала нам нужно установить tun2socks. Мы будем использовать предварительно скомпилированные бинарные файлы с GitHub.

  1. Перейдите на страницу релизов tun2socks: https://github.com/xjasonlyu/tun2socks/releases

  2. Выберите последнюю стабильную версию и загрузите подходящий архив для вашей архитектуры (например, tun2socks-linux-amd64.tar.gz для 64-битных систем Linux).

  3. Распакуйте архив и переместите исполняемый файл в системный путь, например, /usr/local/bin/:

    # Пример для linux-amd64, замените версию на актуальную
    wget https://github.com/xjasonlyu/tun2socks/releases/download/v2.5.1/tun2socks-linux-amd64.tar.gz
    tar -xvf tun2socks-linux-amd64.tar.gz
    sudo mv tun2socks-linux-amd64/tun2socks /usr/local/bin/tun2socks
    sudo chmod +x /usr/local/bin/tun2socks
    

    Убедитесь, что путь к бинарнику в вашем скрипте совпадает с фактическим. В нашем примере это /usr/local/bin/tun2socks.


Скрипт перенаправления трафика

Теперь давайте рассмотрим скрипт, который автоматизирует процесс настройки TUN-устройства, iptables и запуска tun2socks.

Важное замечание: Для корректной работы с systemd, мы немного изменим скрипт, чтобы tun2socks запускался в фоновом режиме, и скрипт мог завершиться, а systemd уже управлял процессом tun2socks.

#!/bin/bash
set -euo pipefail

# Конфигурация
TUN_DEV="tun0" # Название TUN-устройства
TUN_ADDR="10.0.0.2/24" # IP-адрес для TUN-устройства
FWMARK="100" # Метка для трафика
ROUTE_TABLE="100" # Номер таблицы маршрутизации
CONTAINER_IP="172.29.172.2" # IP-адрес вашего контейнера, трафик которого нужно перенаправлять
SOCKS_PROXY="socks5://username:[email protected]:yyyyy" # Адрес SOCKS5-прокси (с аутентификацией)
TUN2SOCKS_BIN="/usr/local/bin/tun2socks" # Путь к исполняемому файлу tun2socks

# Путь к PID-файлу, который будет использоваться systemd
PID_FILE="/var/run/tun2socks.pid"

# Функция для очистки правил
cleanup() {
    echo "[INFO] Очистка старых маршрутов и iptables..."
    # Удаляем правила в обратном порядке создания
    iptables -t nat -D POSTROUTING -o "$TUN_DEV" -j MASQUERADE 2>/dev/null || true
    iptables -t mangle -D PREROUTING -s "$CONTAINER_IP" -p tcp -j MARK --set-mark "$FWMARK" 2>/dev/null || true

    ip route flush table "$ROUTE_TABLE" 2>/dev/null || true
    ip rule del fwmark "$FWMARK" table "$ROUTE_TABLE" priority "$FWMARK" 2>/dev/null || true

    ip link set "$TUN_DEV" down 2>/dev/null || true
    ip tuntap del dev "$TUN_DEV" mode tun 2>/dev/null || true

    # Удаляем PID-файл
    rm -f "$PID_FILE" 2>/dev/null || true
}

# Проверяем аргументы командной строки
if [ "$#" -eq 1 ] && [ "$1" == "cleanup_only" ]; then
    cleanup
    echo "[INFO] Очистка завершена."
    exit 0
fi

# Вызываем cleanup при старте для гарантии чистоты, если не режим cleanup_only
cleanup

echo "[INFO] Создание $TUN_DEV..."
ip tuntap add dev "$TUN_DEV" mode tun
ip addr add "$TUN_ADDR" dev "$TUN_DEV"
ip link set "$TUN_DEV" up

echo "[INFO] Настройка ip rule и iptables..."
ip rule add fwmark "$FWMARK" table "$ROUTE_TABLE" priority "$FWMARK"
ip route replace default dev "$TUN_DEV" table "$ROUTE_TABLE"

iptables -t mangle -A PREROUTING -s "$CONTAINER_IP" -p tcp -j MARK --set-mark "$FWMARK"
iptables -t nat -A POSTROUTING -o "$TUN_DEV" -j MASQUERADE

echo "[INFO] Запуск tun2socks..."
"$TUN2SOCKS_BIN" \
  --device "$TUN_DEV" \
  --proxy "$SOCKS_PROXY" \
  --nohup \
  --log-level info &

# Сохраняем PID tun2socks для systemd
echo $! > "$PID_FILE"

echo "[INFO] Настройка завершена. tun2socks запущен."

Разбор скрипта

Давайте подробнее разберем, что делает каждая часть скрипта:

Конфигурация

В начале скрипта определяются ключевые переменные:

  • TUN_DEV: Имя виртуального сетевого интерфейса (например, tun0).
  • TUN_ADDR: IP-адрес и маска подсети, которые будут назначены TUN_DEV. Этот адрес будет использоваться как шлюз для контейнера.
  • FWMARK: Произвольная числовая метка, которая будет использоваться для маркировки пакетов, предназначенных для перенаправления.
  • ROUTE_TABLE: Номер пользовательской таблицы маршрутизации, куда будет направлен помеченный трафик.
  • CONTAINER_IP: Критически важный параметр! Это IP-адрес вашего контейнера, трафик которого вы хотите перенаправлять. Вам нужно будет узнать его.
  • SOCKS_PROXY: Полный адрес вашего SOCKS5-прокси, включая протокол, имя пользователя, пароль и порт.
  • PID_FILE: Путь к файлу, куда будет записан PID процесса tun2socks для отслеживания systemd.

Функция cleanup

Функция cleanup() отвечает за удаление всех ранее созданных правил iptables, маршрутов и самого TUN-устройства. Это важно для обеспечения “чистого” состояния перед каждой новой настройкой и при остановке сервиса. Она также удаляет PID-файл.

Логика запуска и очистки

Скрипт проверяет аргументы командной строки. Если он запущен с аргументом cleanup_only, то выполняет только функцию cleanup и завершает работу. В противном случае, он сначала очищает предыдущие настройки, а затем приступает к созданию новых.

Создание TUN-устройства

  • ip tuntap add dev "$TUN_DEV" mode tun: Создает новый TUN-интерфейс с указанным именем.
  • ip addr add "$TUN_ADDR" dev "$TUN_DEV": Назначает IP-адрес созданному TUN-интерфейсу.
  • ip link set "$TUN_DEV" up: Активирует TUN-интерфейс.

Настройка ip rule и iptables

Это сердце механизма перенаправления трафика:

  • ip rule add fwmark "$FWMARK" table "$ROUTE_TABLE" priority "$FWMARK": Создает правило маршрутизации, которое гласит: “любой пакет с меткой FWMARK должен быть обработан с использованием таблицы маршрутизации ROUTE_TABLE”. Приоритет FWMARK гарантирует, что это правило будет рассмотрено раньше других.

  • ip route replace default dev "$TUN_DEV" table "$ROUTE_TABLE": Внутри нашей специальной таблицы ROUTE_TABLE мы устанавливаем маршрут по умолчанию, который указывает на наше TUN-устройство. Это означает, что весь трафик, попадающий в эту таблицу, будет направлен через TUN_DEV.

  • iptables -t mangle -A PREROUTING -s "$CONTAINER_IP" -p tcp -j MARK --set-mark "$FWMARK": Это правило iptables в цепочке PREROUTING (которая обрабатывает пакеты до того, как они пройдут через маршрутизацию) в таблице mangle (которая используется для изменения пакетов). Оно говорит: “если TCP-пакет исходит от CONTAINER_IP, пометь его меткой FWMARK”. Это то, как мы идентифицируем трафик, который нужно перенаправить.

  • iptables -t nat -A POSTROUTING -o "$TUN_DEV" -j MASQUERADE: Это правило в таблице nat в цепочке POSTROUTING (которая обрабатывает пакеты непосредственно перед их отправкой). Оно выполняет маскарадинг (SNAT), то есть изменяет исходный IP-адрес исходящих пакетов, проходящих через TUN_DEV, на IP-адрес, ассоциированный с TUN_DEV. Это необходимо для корректной работы прокси.

Запуск tun2socks

  • "$TUN2SOCKS_BIN" --device "$TUN_DEV" --proxy "$SOCKS_PROXY" --nohup --log-level info &: Запускает сам tun2socks. Он привязывается к созданному TUN_DEV и использует указанный SOCKS_PROXY для перенаправления всего трафика, который поступает на TUN_DEV. Флаг --nohup позволяет tun2socks продолжать работать даже после завершения родительского процесса (скрипта), а & запускает его в фоновом режиме. --log-level info полезен для отладки.

  • echo $! > "$PID_FILE": Сохраняет PID только что запущенного в фоне tun2socks в файл, чтобы systemd мог его отслеживать.


Как использовать (с systemd)

Теперь, когда скрипт готов, мы можем интегрировать его с systemd для удобного управления.

  1. Сохраните скрипт: Создайте файл, например, /usr/local/bin/tun2socks_redirect.sh, и вставьте в него содержимое измененного скрипта.

    sudo nano /usr/local/bin/tun2socks_redirect.sh
    
  2. Сделайте его исполняемым:

    sudo chmod +x /usr/local/bin/tun2socks_redirect.sh
    
  3. Определите IP-адрес контейнера: Если вы используете Docker, вы можете узнать IP-адрес контейнера, выполнив docker inspect <имя_контейнера> | grep "IPAddress".

  4. Обновите CONTAINER_IP и SOCKS_PROXY: Обязательно измените значения CONTAINER_IP и SOCKS_PROXY в скрипте /usr/local/bin/tun2socks_redirect.sh на ваши собственные.


Создание Systemd Unit-файла

Создадим файл unit-а systemd для нашего сервиса.

  1. Создайте файл /etc/systemd/system/tun2socks-redirect.service:

    sudo nano /etc/systemd/system/tun2socks-redirect.service
    
  2. Вставьте следующее содержимое:

    [Unit]
    Description=Tun2socks Traffic Redirection Service
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=forking
    # Используем Type=forking, так как наш скрипт запускает tun2socks в фоне
    # и завершается сам. tun2socks сам демонизируется (благодаря --nohup).
    # PIDFile используется для отслеживания PID tun2socks.
    PIDFile=/var/run/tun2socks.pid
    ExecStartPre=/usr/local/bin/tun2socks_redirect.sh
    # ExecStart - это команда, которую systemd будет отслеживать.
    # Так как наш скрипт запускает tun2socks в фоне, systemd сам будет следить за tun2socks по PIDFile.
    ExecStart=/bin/true
    # ExecStopPost выполняется после завершения сервиса, для очистки
    ExecStopPost=/usr/local/bin/tun2socks_redirect.sh cleanup_only
    # User=root - поскольку скрипт требует root-прав
    User=root
    Restart=on-failure
    RestartSec=5s
    
    [Install]
    WantedBy=multi-user.target
    

Пояснения к Unit-файлу:

  • [Unit]:
    • Description: Краткое описание сервиса.
    • After=network-online.target: Сервис будет запущен после того, как сеть будет полностью настроена.
    • Wants=network-online.target: Указывает на желаемую зависимость от сети.
  • [Service]:
    • Type=forking: Указывает systemd, что основной процесс сервиса будет “форкать” дочерний процесс (наш tun2socks), и родительский процесс (скрипт) завершится. systemd будет использовать PIDFile для отслеживания истинного процесса сервиса.
    • PIDFile=/var/run/tun2socks.pid: Путь к файлу, в котором наш скрипт сохраняет PID запущенного tun2socks. Это критично для Type=forking.
    • ExecStartPre=/usr/local/bin/tun2socks_redirect.sh: Команда, которая выполняется перед основным запуском сервиса. Здесь наш скрипт настраивает TUN-устройство и правила iptables, а также запускает tun2socks в фоновом режиме.
    • ExecStart=/bin/true: Поскольку tun2socks уже запущен нашим ExecStartPre скриптом и systemd отслеживает его по PIDFile, нам не нужно запускать что-либо ещё в ExecStart. /bin/true просто возвращает успешный код выхода.
    • ExecStopPost=/usr/local/bin/tun2socks_redirect.sh cleanup_only: Команда, которая выполняется после остановки сервиса. При вызове с аргументом cleanup_only скрипт только очищает правила.
    • User=root: Сервис должен запускаться от имени root, так как он изменяет сетевые настройки и правила iptables.
    • Restart=on-failure: Если сервис завершится с ошибкой, systemd попытается перезапустить его.
    • RestartSec=5s: Задержка перед попыткой перезапуска.
  • [Install]:
    • WantedBy=multi-user.target: Сервис будет запущен при загрузке системы в многопользовательском режиме.

Включение и запуск сервиса Systemd

После создания Unit-файла и доработки скрипта:

  1. Перезагрузите systemd daemon:

    sudo systemctl daemon-reload
    
  2. Включите сервис для автоматического запуска при загрузке:

    sudo systemctl enable tun2socks-redirect.service
    
  3. Запустите сервис:

    sudo systemctl start tun2socks-redirect.service
    
  4. Проверьте статус сервиса:

    sudo systemctl status tun2socks-redirect.service
    

    Вы должны увидеть, что сервис активен (active (running)).

  5. Проверьте логи:

    journalctl -u tun2socks-redirect.service -f
    

    Это поможет вам отслеживать вывод скрипта и tun2socks.

Теперь ваш сервис будет автоматически запускаться при загрузке системы и пытаться поддерживать работу tun2socks и правил маршрутизации. Для остановки сервиса используйте sudo systemctl stop tun2socks-redirect.service, и он автоматически очистит правила. Для перезапуска - sudo systemctl restart tun2socks-redirect.service.


Заключение

Таким образом, мы настроили систему, которая перенаправляет весь TCP-трафик от указанного контейнера через SOCKS-прокси-сервер. Этот метод обеспечивает гибкость и контроль над сетевым трафиком, позволяя вам легко управлять его маршрутизацией через внешние прокси-сервисы, а интеграция с systemd значительно повышает надёжность и удобство управления.

Надеюсь, эта статья была полезной! Если у вас есть вопросы или предложения, не стесняйтесь оставлять комментарии.

Свяжитесь со мной

Обсудим ваш проект и найдём подходящее решение