Страница 1 из 1

Tun2SOCKS Failover — автоматический туннель с фейловером

Добавлено: 11 июл 2026, 17:11
Padonak
📋 Что делает скрипт:

- Создаёт TUN-туннель через tun2socks до SOCKS5-прокси
- Маршрутизирует трафик клиентов WireGuard и OpenVPN через этот туннель
- Автоматически переключается между прокси при падении
- Возвращается на основной прокси при его восстановлении
- Отправляет алерты на почту при переключениях

🖥️ Системные требования:
Linux (Debian/Ubuntu)
systemd
tun2socks (v3)
curl, iptables, iproute2
Три SOCKS5-прокси (основной + два резервных)

📦 Установка:

1. Скачайте и установите tun2socks::

Код: Выделить всё

wget -O tun2socks.zip https://github.com/xjasonlyu/tun2socks/releases/latest/download/tun2socks-linux-amd64.zip

Код: Выделить всё

unzip tun2socks.zip

Код: Выделить всё

chmod +x tun2socks-linux-amd64

Код: Выделить всё

mv tun2socks-linux-amd64 /usr/sbin/tun2socks-linux-amd64-v3

2. Создайте основной скрипт:

Код: Выделить всё

#!/usr/bin/env bash
set -uo pipefail

# =============================================
# НАСТРОЙКИ (измените под себя)
# =============================================
TUN_DEV="tun_out"
TUN_IP="10.99.99.1/24"
SOCKS_LIST="/etc/socks-list.txt"
TUN2SOCKS="/usr/sbin/tun2socks-linux-amd64-v3"
LOGFILE="/var/log/tun2socks-routing.log"
PIDFILE="/var/run/tun2socks-failover.pid"
TUN2SOCKS_PIDFILE="/var/run/tun2socks-process.pid"
MAIL_TO="admin@padonak.su"                    # Куда слать алерты

# Основной прокси (на него возвращаемся при восстановлении)
PRIMARY_PROXY="socks5://vps.padonak.su:3334"

# Подсети клиентов VPN
CLIENT_SUBNETS=(
    "10.8.0.0/24"     # OpenVPN
    "10.11.12.0/24"   # WireGuard
)

# Настройки мониторинга
HEALTHCHECK_URL="http://1.1.1.1"
HEALTHCHECK_INTERVAL=30      # Интервал проверки (сек)
HEALTHCHECK_TIMEOUT=5        # Таймаут проверки (сек)
HEALTHCHECK_RETRIES=2        # Провалов до переключения
PRIMARY_CHECK_INTERVAL=60    # Проверка основного прокси (сек)

LOG_TAG="[tun2socks]"

# =============================================
# ФУНКЦИИ
# =============================================

log() {
    local msg="$*"
    local line="$(date '+%Y-%m-%d %H:%M:%S') ${LOG_TAG} ${msg}"
    echo "$line"
    echo "$line" >> "$LOGFILE"
}

send_alert() {
    local subject="$1"
    local body="$2"
    if command -v mail >/dev/null 2>&1; then
        echo -e "$body" | mail -s "$subject" "$MAIL_TO" 2>/dev/null || true
    fi
}

cleanup() {
    log "Очистка..."
    
    if [[ -f "$TUN2SOCKS_PIDFILE" ]]; then
        local pid=$(cat "$TUN2SOCKS_PIDFILE" 2>/dev/null)
        [[ -n "$pid" ]] && kill "$pid" 2>/dev/null || true
        rm -f "$TUN2SOCKS_PIDFILE"
    fi
    
    pkill -f "tun2socks.*${TUN_DEV}" 2>/dev/null || true
    sleep 1
    
    # Удаляем правила SNAT
    local snat_ip="${TUN_IP%/*}"
    for subnet in "${CLIENT_SUBNETS[@]}"; do
        ip rule del from "$subnet" lookup client_socks_table 2>/dev/null || true
        iptables -t nat -D POSTROUTING -s "$subnet" -o "$TUN_DEV" -j SNAT --to-source "$snat_ip" 2>/dev/null || true
    done
    ip route flush table client_socks_table 2>/dev/null || true
    
    iptables -D FORWARD -i "$TUN_DEV" -j ACCEPT 2>/dev/null || true
    iptables -D FORWARD -o "$TUN_DEV" -j ACCEPT 2>/dev/null || true
    
    if ip link show "$TUN_DEV" &>/dev/null; then
        ip link set dev "$TUN_DEV" down 2>/dev/null || true
        ip tuntap del mode tun dev "$TUN_DEV" 2>/dev/null || true
    fi
    
    rm -f "$PIDFILE"
    log "Очистка завершена"
}

trap cleanup EXIT SIGINT SIGTERM
echo $$ > "$PIDFILE"

load_proxy_list() {
    if [[ ! -f "$SOCKS_LIST" ]]; then
        log "Ошибка: ${SOCKS_LIST} не найден"
        exit 1
    fi
    mapfile -t PROXY_LIST < <(grep -v '^#' "$SOCKS_LIST" | grep -v '^$' | tr -d '\r')
    if [[ ${#PROXY_LIST[@]} -eq 0 ]]; then
        log "Ошибка: список прокси пуст"
        exit 1
    fi
    log "Прокси загружено: ${#PROXY_LIST[@]}"
}

setup_network() {
    log "Настройка сети..."
    
    if ! ip link show "$TUN_DEV" &>/dev/null; then
        ip tuntap add mode tun dev "$TUN_DEV"
    fi
    
    ip addr add "$TUN_IP" dev "$TUN_DEV" 2>/dev/null || true
    ip link set dev "$TUN_DEV" mtu 1400 up
    log "Интерфейс ${TUN_DEV} поднят (IP: ${TUN_IP}, MTU: 1400)"
    
    ip route flush table client_socks_table 2>/dev/null || true
    ip route add default dev "$TUN_DEV" table client_socks_table
    
    local prio=100
    for subnet in "${CLIENT_SUBNETS[@]}"; do
        ip rule del from "$subnet" lookup client_socks_table 2>/dev/null || true
        ip rule add from "$subnet" priority "$prio" lookup client_socks_table
        ((prio++))
    done
    
    # Используем SNAT вместо MASQUERADE (быстрее)
    local snat_ip="${TUN_IP%/*}"
    for subnet in "${CLIENT_SUBNETS[@]}"; do
        if ! iptables -t nat -C POSTROUTING -s "$subnet" -o "$TUN_DEV" -j SNAT --to-source "$snat_ip" 2>/dev/null; then
            iptables -t nat -A POSTROUTING -s "$subnet" -o "$TUN_DEV" -j SNAT --to-source "$snat_ip"
            log "SNAT: ${subnet} -> ${snat_ip}"
        fi
    done
    
    iptables -C FORWARD -i "$TUN_DEV" -j ACCEPT 2>/dev/null || iptables -A FORWARD -i "$TUN_DEV" -j ACCEPT
    iptables -C FORWARD -o "$TUN_DEV" -j ACCEPT 2>/dev/null || iptables -A FORWARD -o "$TUN_DEV" -j ACCEPT
    
    log "Сеть настроена"
}

start_tun2socks() {
    local proxy="$1"
    
    log "Запуск: ${proxy}"
    
    pkill -f "tun2socks.*${TUN_DEV}" 2>/dev/null || true
    sleep 1
    
    $TUN2SOCKS \
        --device "tun://${TUN_DEV}" \
        --proxy "$proxy" \
        --loglevel warn \
        &>> "$LOGFILE" &
    
    local pid=$!
    echo "$pid" > "$TUN2SOCKS_PIDFILE"
    
    sleep 3
    
    if kill -0 "$pid" 2>/dev/null; then
        log "tun2socks PID: ${pid}"
        return 0
    else
        log "Ошибка запуска"
        return 1
    fi
}

check_health() {
    local proxy="$1"
    
    # Проверка напрямую через прокси
    if curl --socks5-hostname "$proxy" --max-time "$HEALTHCHECK_TIMEOUT" -s -o /dev/null "$HEALTHCHECK_URL" 2>/dev/null; then
        return 0
    fi
    
    # Запасной вариант — через TUN
    if curl --interface "$TUN_DEV" --max-time "$HEALTHCHECK_TIMEOUT" -s -o /dev/null "$HEALTHCHECK_URL" 2>/dev/null; then
        return 0
    fi
    
    return 1
}

# Проверка доступности основного прокси (напрямую, без TUN)
check_primary() {
    if curl --socks5-hostname "$PRIMARY_PROXY" --max-time "$HEALTHCHECK_TIMEOUT" -s -o /dev/null "$HEALTHCHECK_URL" 2>/dev/null; then
        return 0
    fi
    return 1
}

# Переключение на указанный прокси
switch_to_proxy() {
    local proxy="$1"
    local reason="$2"
    
    log "Переключение на ${proxy} (${reason})..."
    send_alert "tun2socks: переключение на ${proxy}" \
        "Причина: ${reason}\nПереключаемся на ${proxy}"
    
    pkill -f "tun2socks.*${TUN_DEV}" 2>/dev/null || true
    sleep 1
    
    if start_tun2socks "$proxy"; then
        return 0
    fi
    return 1
}

# =============================================
# ГЛАВНЫЙ ЦИКЛ
# =============================================

main() {
    log "=== СТАРТ ==="
    
    load_proxy_list
    setup_network
    
    local current_proxy=""
    local failures=0
    local primary_check_counter=0
    
    # Начинаем с основного прокси если он доступен
    if check_primary; then
        log "Основной прокси ${PRIMARY_PROXY} доступен, начинаем с него"
        if start_tun2socks "$PRIMARY_PROXY"; then
            current_proxy="$PRIMARY_PROXY"
        fi
    fi
    
    while true; do
        # Если нет текущего прокси — перебор списка
        if [[ -z "$current_proxy" ]]; then
            for proxy in "${PROXY_LIST[@]}"; do
                log "Пробуем: ${proxy}"
                if start_tun2socks "$proxy"; then
                    current_proxy="$proxy"
                    failures=0
                    break
                fi
            done
            
            if [[ -z "$current_proxy" ]]; then
                log "Все прокси недоступны. Пауза 30с..."
                send_alert "tun2socks: все прокси недоступны" \
                    "Все прокси перебраны. Пауза 30с."
                sleep 30
                continue
            fi
        fi
        
        # Мониторинг текущего прокси
        while [[ -n "$current_proxy" ]]; do
            sleep "$HEALTHCHECK_INTERVAL"
            ((primary_check_counter += HEALTHCHECK_INTERVAL))
            
            # Периодическая проверка основного прокси
            if [[ $primary_check_counter -ge $PRIMARY_CHECK_INTERVAL ]]; then
                primary_check_counter=0
                
                # Если мы не на основном — проверяем, не восстановился ли он
                if [[ "$current_proxy" != "$PRIMARY_PROXY" ]]; then
                    if check_primary; then
                        log "Основной прокси ${PRIMARY_PROXY} снова доступен!"
                        switch_to_proxy "$PRIMARY_PROXY" "основной прокси восстановился"
                        current_proxy="$PRIMARY_PROXY"
                        failures=0
                        continue
                    fi
                fi
            fi
            
            # Healthcheck текущего прокси
            if ! check_health "$current_proxy"; then
                ((failures++))
                log "Healthcheck FAIL (${failures}/${HEALTHCHECK_RETRIES}) для ${current_proxy}"
                
                if [[ $failures -ge $HEALTHCHECK_RETRIES ]]; then
                    log "Прокси ${current_proxy} не отвечает, переключаем..."
                    send_alert "tun2socks: прокси недоступен" \
                        "Прокси ${current_proxy} не отвечает (${failures} провалов)"
                    
                    pkill -f "tun2socks.*${TUN_DEV}" 2>/dev/null || true
                    sleep 1
                    current_proxy=""
                    failures=0
                    break
                fi
            else
                [[ $failures -gt 0 ]] && log "Healthcheck восстановлен для ${current_proxy}"
                failures=0
            fi
        done
    done
}

main

3. Сделайте скрипт исполняемым:

Код: Выделить всё

chmod +x /usr/local/bin/tun2socks-failover.sh
4. Создайте скрипт очистки:

Код: Выделить всё

vim /usr/local/bin/tun2socks-failover-cleanup.sh

Код: Выделить всё


#!/usr/bin/env bash
TUN_DEV="tun_out"
CLIENT_SUBNETS=("10.8.0.0/24" "10.11.12.0/24")

pkill -9 -f "tun2socks.*${TUN_DEV}" 2>/dev/null || true
sleep 1

for subnet in "${CLIENT_SUBNETS[@]}"; do
    ip rule del from "$subnet" lookup client_socks_table 2>/dev/null || true
    iptables -t nat -D POSTROUTING -s "$subnet" -o "$TUN_DEV" -j MASQUERADE 2>/dev/null || true
done
ip route flush table client_socks_table 2>/dev/null || true

iptables -D FORWARD -i "$TUN_DEV" -j ACCEPT 2>/dev/null || true
iptables -D FORWARD -o "$TUN_DEV" -j ACCEPT 2>/dev/null || true

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

rm -f /var/run/tun2socks-failover.pid /var/run/tun2socks-process.pid
echo "Очистка завершена"

Код: Выделить всё

chmod +x /usr/local/bin/tun2socks-failover-cleanup.sh
5. Создайте список прокси:

Код: Выделить всё

vim /etc/socks-list.txt

Код: Выделить всё

socks5://1.padonak.su:333
socks5://2.padonak.su:333
socks5://3.padonak.su:333
6. Создайте systemd-сервис:

Код: Выделить всё

vim /etc/systemd/system/tun2socks-failover.service

Код: Выделить всё

[Unit]
Description=tun2socks with automatic failover and alerting
After=network.target
Wants=network-online.target

[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/tun2socks-failover.sh
ExecStop=/bin/bash -c 'pkill -9 -f tun2socks; sleep 1'
ExecStopPost=/usr/local/bin/tun2socks-failover-cleanup.sh
Restart=always
RestartSec=10s
StandardOutput=journal
StandardError=journal
LimitNOFILE=65536
KillMode=mixed
TimeoutStopSec=15

[Install]
WantedBy=multi-user.target
7. Включите IP Forwarding:

Код: Выделить всё

echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p
8. Запустите сервис:

Код: Выделить всё

systemctl daemon-reload
systemctl enable tun2socks-failover
systemctl start tun2socks-failover
systemctl status tun2socks-failover
🔧 Проверка работы:

Код: Выделить всё

# Статус сервиса
systemctl status tun2socks-failover

# Процессы
ps aux | grep tun2socks

# Логи
tail -f /var/log/tun2socks-routing.log

# Тест скорости через прокси
curl --socks5-hostname socks5://1.padonak.su:3334 \
     -o /dev/null -w "Speed: %{speed_download} B/s\n" \
     http://ipv4.download.thinkbroadband.com/10MB.zip
⚙️ Настройка под себя:

В скрипте измените:
Переменная Значение
- PRIMARY_PROXY Основной прокси
- CLIENT_SUBNETS Подсети ваших VPN
- MAIL_TO Почта для алертов
- HEALTHCHECK_INTERVAL Частота проверки
- HEALTHCHECK_RETRIES Провалов до переключения


📊 Оптимизация прокси-серверов:

Код: Выделить всё

cat >> /etc/sysctl.conf << 'EOF'
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
EOF
sysctl -p
Готово! 🚀