Перенаправляем весь трафик контейнера через SOCKS-прокси с помощью tun2socks
Опубликовано 17.06.2025
Иногда возникает необходимость направлять весь исходящий трафик определённого контейнера через прокси-сервер. Это может быть полезно для обеспечения анонимности, обхода геоблокировок или для тестирования сетевых конфигураций. В этой статье мы рассмотрим, как настроить такую систему, используя утилиту tun2socks и правила iptables, а также как управлять этим процессом с помощью systemd.
Что такое tun2socks?
tun2socks – это мощный инструмент, который позволяет перенаправлять сетевой трафик, предназначенный для TUN-устройства, через SOCKS-прокси. Он создаёт виртуальный сетевой интерфейс (TUN-устройство), весь трафик которого заворачивается в SOCKS-соединение. Это особенно удобно, когда прямое проксирование на уровне приложения невозможно или нежелательно.
Установка tun2socks
Для начала нам нужно установить tun2socks. Мы будем использовать предварительно скомпилированные бинарные файлы с GitHub.
Перейдите на страницу релизов tun2socks: https://github.com/xjasonlyu/tun2socks/releases
Выберите последнюю стабильную версию и загрузите подходящий архив для вашей архитектуры (например,
tun2socks-linux-amd64.tar.gz
для 64-битных систем Linux).Распакуйте архив и переместите исполняемый файл в системный путь, например,
/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 для удобного управления.
Сохраните скрипт: Создайте файл, например,
/usr/local/bin/tun2socks_redirect.sh
, и вставьте в него содержимое измененного скрипта.sudo nano /usr/local/bin/tun2socks_redirect.sh
Сделайте его исполняемым:
sudo chmod +x /usr/local/bin/tun2socks_redirect.sh
Определите IP-адрес контейнера: Если вы используете Docker, вы можете узнать IP-адрес контейнера, выполнив
docker inspect <имя_контейнера> | grep "IPAddress"
.Обновите CONTAINER_IP и SOCKS_PROXY: Обязательно измените значения
CONTAINER_IP
иSOCKS_PROXY
в скрипте/usr/local/bin/tun2socks_redirect.sh
на ваши собственные.
Создание Systemd Unit-файла
Создадим файл unit-а systemd для нашего сервиса.
Создайте файл
/etc/systemd/system/tun2socks-redirect.service
:sudo nano /etc/systemd/system/tun2socks-redirect.service
Вставьте следующее содержимое:
[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-файла и доработки скрипта:
Перезагрузите systemd daemon:
sudo systemctl daemon-reload
Включите сервис для автоматического запуска при загрузке:
sudo systemctl enable tun2socks-redirect.service
Запустите сервис:
sudo systemctl start tun2socks-redirect.service
Проверьте статус сервиса:
sudo systemctl status tun2socks-redirect.service
Вы должны увидеть, что сервис активен (
active (running)
).Проверьте логи:
journalctl -u tun2socks-redirect.service -f
Это поможет вам отслеживать вывод скрипта и tun2socks.
Теперь ваш сервис будет автоматически запускаться при загрузке системы и пытаться поддерживать работу tun2socks
и правил маршрутизации. Для остановки сервиса используйте sudo systemctl stop tun2socks-redirect.service
, и он автоматически очистит правила. Для перезапуска - sudo systemctl restart tun2socks-redirect.service
.
Заключение
Таким образом, мы настроили систему, которая перенаправляет весь TCP-трафик от указанного контейнера через SOCKS-прокси-сервер. Этот метод обеспечивает гибкость и контроль над сетевым трафиком, позволяя вам легко управлять его маршрутизацией через внешние прокси-сервисы, а интеграция с systemd значительно повышает надёжность и удобство управления.
Надеюсь, эта статья была полезной! Если у вас есть вопросы или предложения, не стесняйтесь оставлять комментарии.