Столкнулся с проблемой описаной в https://github.com/net4people/bbs/issues/490 . Перестал работать сервер VLESS с мобильный операторов. Решил попробовать создать промежуточный сервер в России с прозрачным прокси к удалённому серверу с VLESS.
В результате накидал небольшой тестовый скрипт для накатки на промежуточный сервер.
Скрипт
#!/bin/bash
validate_ports() {
local ports="$1"
local -n port_array_ref="$2"
echo "$ports"
port_array_ref=()
if [ -z "$ports" ]; then
echo "Ошибка: строка с портами пуста" >&2
return 1
fi
old_IFS=$IFS
IFS=',' read -ra port_array <<< "$ports"
IFS=$old_IFS
for port in "${port_array[@]}"; do
port=$(echo "$port" | xargs)
if ! [[ "${port%%/*}" =~ ^[0-9]+$ ]]; then
echo "Ошибка: '${port%%/*}' не является числом" >&2
return 1
fi
if (("${port%%/*}" < 1 || "${port%%/*} > 65535")); then
echo "Ошибка: порт $port вне допустимого диапазона (1-65535)" >&2
return 1
fi
port_array_ref+=("$port")
done
return 0
}
if [ "$(id -u)" -ne 0 ]; then
echo "Этот скрипт должен запускаться от root!" >&2
exit 1
fi
SERVER_IP=$(hostname -I | awk '{print $1}')
# Запрос параметров
read -p "Введите ip прокси сервера: " DEST_IP
read -p "Введите 'номер порта:протокол' через запятую, которые нужно прокидывать до прокси сервера (e.g. 443/TCP,443/UDP ...): " DEST_PORTS
declare -a ports_list
if ! validate_ports "$DEST_PORTS" "ports_list"; then
echo "Некорректный ввод портов" >&2
exit 1
fi
if [ "${#ports_list[@]}" -eq 0 ]; then
echo "Нет портов для прокидывания" >&2
exit 1
fi
read -p "Введите имя сетевого интерфейса (default: auto): " INTERFACE
if [ -z "$INTERFACE" ]; then
INTERFACE=$(ip route show default | awk '/default/ {print $5}' | head -n 1)
if [ -z "$INTERFACE" ]; then
echo "Не удалось автоматически определить интерфейс для выхода в сеть!"
exit 1
else
echo "Сетевой интерфейс для выхода в интернет: $INTERFACE"
fi
fi
echo "Включаем IP-форвардинг..."
sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
read -p "Введите режим работы (DNAT/Transparent default: DNAT): " MODE
MODE=${MODE:-DNAT}
if [[ "$MODE" != "DNAT" && "$MODE" != "Transparent" ]]; then
echo "Ошибка: допустимые значения - DNAT или Transparent"
exit 1
fi
echo "Выбран режим работы: $MODE"
read -p "Reset iptables? (default: no): " IS_REMOVE_OLD_RULES
if [ -n "$IS_REMOVE_OLD_RULES" ]; then
echo "Очищаем старые правила iptables..."
iptables -t nat -F
iptables -t nat -X
iptables -F
iptables -X
iptables -Z
iptables -t mangle -F
iptables -t mangle -X
sudo iptables -F INPUT
sudo iptables -F FORWARD
sudo iptables -F OUTPUT
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
fi
case "$MODE" in
"DNAT")
echo "Настраиваем DNAT"
for port in "${ports_list[@]}"; do
echo "Настраиваем DNAT для портов ${DEST_PORTS}"
iptables -t nat -A PREROUTING -d "$SERVER_IP" -p "${port#*/}" --dport "${port%%/*}" -j DNAT --to-destination "$DEST_IP:${port%%/*}"
echo "Разрешаем переадресацию в FORWARD..."
iptables -A FORWARD -p "${port#*/}" -d "$DEST_IP" --dport "${port%%/*}" -j ACCEPT
done
echo "Настраиваем MASQUERADE для интерфейса $INTERFACE..."
iptables -t nat -A POSTROUTING -o "$INTERFACE" -j MASQUERADE
;;
"Transparent")
echo "Настраиваем прозрачное проксирование (REDIRECT/TPROXY)..."
for port in "${ports_list[@]}"; do
proto="${port#*/}"
port_num="${port%%/*}"
if [ "$proto" = "TCP" ]; then
iptables -t mangle -A PREROUTING -p tcp --dport "$port_num" -j MARK --set-mark 0x1
iptables -t mangle -A PREROUTING -p tcp --dport "$port_num" -j TPROXY --on-port "$port_num" --tproxy-mark 0x1/0x1
elif [ "$proto" = "UDP" ]; then
iptables -t mangle -A PREROUTING -p udp --dport "$port_num" -j MARK --set-mark 0x1
iptables -t mangle -A PREROUTING -p udp --dport "$port_num" -j TPROXY --on-port "$port_num" --tproxy-mark 0x1/0x1
else
echo "Неподдерживаемый протокол: $proto" >&2
exit 1
fi
done
ip rule add fwmark 0x1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100
;;
*)
echo "Неизвестный режим: $MODE (допустимые варианты: dnat, transparent)" >&2
exit 1
;;
esac
if command -v iptables-save &> /dev/null; then
iptables-save > /etc/iptables/rules.v4
fi
echo "Готово! Правила применены:"
echo "- Весь трафик на $SERVER_IP:${DEST_PORTS} перенаправляется на $DEST_IP:$DEST_PORT"
echo "- Переадресация включена (net.ipv4.ip_forward=1)"
echo -e "\nТекущие правила NAT:"
iptables -t nat -L -n -v
echo -e "\nТекущие правила FILTER:"
iptables -L -n -v
echo -e "\nТекущие правила MANGLE (TPROXY):"
iptables -t mangle -L -n -v
Накатка работает в 2-х режимах - DNAT или Transparent. С DNAT всё хорошо. Трафик ходит нормально, на мобильных операторах vless ожил. Но хотелось бы настроить именно прозрачное прокси, чтобы на vless сервере сохранялись исходные ip адреса (сервером пользуюсь не я один). И вот в этом режиме прокси не работает.
Что делаю:
настроил VLESS: sniffing: ON , domain strategy: UseIp, TProxy: TProxy
Запускаю свою накатку в режиме Transparent, которая выставляет на промежуточном сервере
iptables -t mangle -A PREROUTING -p tcp --dport $port_num -j MARK --set-mark 0x1
iptables -t mangle -A PREROUTING -p tcp --dport $port_num -j TPROXY --on-port
ip rule add fwmark 0x1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100
Должен ли я что-то ещё делать на промежуточном сервере или сервере с vless. К сожалению я не являюсь сетевым специалистом и не понимаю в полной мере взаимодействие vless и tsproxy на стыке.
На промежуточном сервере можно поднять обратный прокси на nginx, который будет форвардить запросы на целевой сервер. Погугли как делать reverse proxy on nginx, в моем случае я форваржу вебсокетовый трафик через ру сервер.
это убирает возможность использовать любые другие протоколы кроме websocket, чтобы видеть на основном сервере оригинальные айпи то нужно еще добавлять header x-forwarded-for
eth0 заменить на свой wan интерфейс (из ip a). tcp port 80 для примера, протестируйте сначала на веб сервере и смотрите его логи, если будут проблемы то можно снизить mtu до 1280
на выходной впс (европа впс) конфиг такой
[Interface]
Address = 10.5.0.1/24
ListenPort = 51820
PrivateKey = uHTaXqdCUktrlFUlP2GC4BiscMlFP3V4DyLgCvs9Tnk=
MTU=1440
#используем вторичную таблицу маршрутов где 0.0.0.0/0 (шлюз) будет ру впс
Table=111
PostUp=sysctl -w net.ipv4.ip_forward=1
#правило чтобы ответные пакеты от сервера не улетали в wan, а в таблицу 111
PostUp=ip rule add from 10.5.0.1 table 111
PostDown=ip rule del from 10.5.0.1 table 111
[Peer] #yKXgHJTLcbNR/1Ffdj0Q8bytWfKqvhhT6wgdOAF0UkA=
PublicKey = 7Oe80+rD8Xz0nz/RsshRc7gqBspU12FBSMWazuqw7xc=
AllowedIPs = 0.0.0.0/0 #пиру разрешен весь ipv4, т.е. он становится шлюзом в таблице 111
Спасибо большое за рекомендации и за конфиги. Как будет время, опробую это на практике.
Насчёт wireguard есть вопрос. Я так понимаю, идея его использования в том, чтобы отказаться от правил masquerade? Но не будет ли проблем с самим wireguard без обфускаций и его блокировками в РФ?
Насчёт TProxy - идея была в гибкости подобного решения. Помимо TCP от vless, было бы здорово иметь на перспективу возможность гонять UDP протоколы по такой же схеме. С TProxy теоретически возможно сохранять исходное IP клиента и в одном и в другом случае. Положим, я захочу гнать по такому же маршруту трафик от amneziaWG или чего-то похожего, можно ли будет это организовать так же через wireguard малой кровью, или нужно будет в любом случае разбираться с HAProxy+ PROXY Protocol или тем же TProxy?
Нужно будет убедиться что нет проблем с мту (mtu wireguard это “wan mtu”-60 для ipv4), в примере у меня мту 1440, значит в вг/авг (который будет через через вг) нужно ставить мту 1380.
В таком виде оно у меня работает.
Как выше посоветовали, стоит попробовать поднять туннель между серверами и отправлять через него, что-то вроде:
postUp = ''
${pkgs.iproute2}/bin/ip rule add fwmark 1 lookup 200
${pkgs.iproute2}/bin/ip route add default dev wg1 via 10.0.0.2 table 200
# TPROXY to remote server through tunnel wg1, assuming sing-box is 10.0.0.2:1337
${pkgs.iptables}/bin/iptables -t mangle -A PREROUTING -i awg0 -p tcp -j TPROXY --tproxy-mark 1 --on-port 1337 --on-ip 10.0.0.2
${pkgs.iptables}/bin/iptables -t mangle -A PREROUTING -i awg0 -p udp -j TPROXY --tproxy-mark 1 --on-port 1337 --on-ip 10.0.0.2
${pkgs.iptables}/bin/iptables -I nixos-fw -i awg0 -j nixos-fw-accept
'';
Правда могут быть сложности с тем, каким маршрутом удаленный сервер будет посылать ответ, если оригинальные IP клиентов сохраняются с промежуточного сервера…
Возможно вся эта информация будет для вас бесполезна, но на всякий решил что-то написать. Если получится настроить - покажите пример конфигурации, интересно посмотреть
Если входной узел будет в РФ, по идее проблем быть не должно. Главное чтобы был доступ с входного узла к Европе, если влесс будет там.
Я себе поднял Амнезию и влесс через РФ сервер, на удивление с входной машины есть доступ до европы с чистым вг (тьфу тьфу), влесс заходит на нее и уходит в туннель до Германии
трафик wg, openvpn подхватывать в tproxy просто правилом на уровне входного интерфейса.
трафик vless-клиентов прогонять через nginx или haproxy с поддержкой PROXY 1/2. И там и там без проблем передается первоначальный адрес клиента. Хотя зачем? Такое лучше не логгировать на vps, особенно ru )
Валить сразу всё подхваченное на зарубежную vps конечно не стоит. Потому что клиент не будет париться с разделением трафика (или просто сразу при включении vpn) все его банковские приложения и прочие яндексы полетят с забугорного vps, давая пищу для размышлений )
Через простой stream без proxy protocol в nginx то понятно, а на сайте написано “With the PROXY protocol, NGINX can learn the originating IP address from HTTP, SSL, HTTP/2, SPDY, WebSocket, and TCP”: про udp ничего нет, значит openvpn udp и wireguard так прокинуть не выйдет, придется через впн между впс
Вообще не понял, зачем нужны все эти сложные схемы. Почему нельзя на российском VPS банально настроить xray в режиме клиента и сервера одновременно? Делается vless инбаунд, к которому подключаются клиенты в россии, и vless аутбаунд для подключения к зарубежному VPS. Можно даже сделать реверс схему, где зарубежный VPS подключается к российскому. Итог будет тот же самый, только настраивается это гораздо проще. Исходные ip, конечно, сохраняться не будут, но это вообще не проблема, т.к. можно всё контролировать внутри xray через uuid клиентов.