Маршрутизация по политике против SOCKS: какой уровень на самом деле проксирует трафик
Маршрут к порту SOCKS — не сеанс SOCKS. Сравните настройки прокси на уровне приложения, адаптер IP-к-прокси и маршрутизируемый шлюз по уровню, который выполняет преобразование.
Вы добавили маршрут по политике, который отправляет трафик клиента VPN на хост с работающим слушателем SOCKS на порту 1080. Пакеты приходят, слушатель ничего не записывает, и соединение зависает. С маршрутом всё в порядке: следующий переход выбирает, куда идёт пакет, а SOCKS — это разговор, который должен начать клиент. Сравните три архитектуры, которые обычно имеют в виду, когда говорят об отправке трафика через прокси, и станет ясно, какой части не хватает в вашей настройке.
Маршрутизация, DNAT и SOCKS меняют разные вещи
Маршрут по политике переписывает решение уровня 3. Двух строк достаточно, чтобы отправить трафик одного клиента на выбранный следующий переход:
ip route add default via 10.50.0.2 table 101
ip rule add from 10.77.0.2 lookup 101После этого ядро передаёт пакет на 10.50.0.2, и первоначальное назначение всё ещё остаётся в заголовке IP. Если 10.50.0.2 — маршрутизатор, он пересылает пакет. Если это хост с демоном SOCKS на 1080, пакет не адресован ничему, что могло бы его принять, и DNAT на порт 1080 тоже не помогает, потому что преобразованный пакет по-прежнему несёт исходную полезную нагрузку приложения вместо приветствия SOCKS.
SOCKS5 начинается с байта версии, списка методов, обмена аутентификацией и запроса, который называет назначение. Это данные приложения. Ни запись маршрутизации, ни цель netfilter их не создают, и в этом сравнение в одну строку: маршрутизация выбирает путь, SOCKS просит сервер установить второе соединение.
Первый случай: приложение само умеет говорить по SOCKS
Когда у программы есть настройка прокси, это самый короткий путь, и он не требует изменений в ядре. Направьте её на слушатель, предоставьте учётные данные, если сервер их запросит, и решите, разрешаются ли имена локально или передаются прокси. В curl это разные флаги, и разница важна, когда назначение разрешается только на стороне прокси:
curl --socks5 10.50.0.2:1080 https://docs.example.com
curl --socks5-hostname 10.50.0.2:1080 https://internal.example.comПриложениям, которые игнорируют переменные окружения прокси или открывают сырые сокеты, так помочь нельзя. Браузеры и большинство инструментов HTTP в порядке; игровой клиент, почтовый демон или произвольный бинарный файл поставщика обычно нет. Граница проходит по каждому приложению и каждому протоколу, поэтому этот вариант отлично подходит для тестирования и слаб как ответ для всего VPN.
Второй случай: адаптер, который превращает IP-потоки в прокси-сеансы
Для программ, которые не умеют говорить по SOCKS, преобразование должно происходить в том, что завершает IP-трафик и открывает прокси-сеансы от их имени. Этот компонент владеет туннельным интерфейсом, принимает потоки, выбранные маршрутизацией по политике, выполняет рукопожатие SOCKS для каждого из них и заново собирает ответы. Маршрут направляет трафик к нему; именно адаптер создаёт сеанс.
Прочитайте документацию, прежде чем доверить ему целую подсеть. Многие адаптеры хорошо переносят TCP и обрабатывают UDP только через ассоциацию UDP в SOCKS5, и ни один из них не превращает ICMP в прокси-трафик, поэтому успешный ping ничего не говорит о пути через прокси. DNS — другая ловушка: если адаптер разрешает имена локально, записи только для внутреннего использования разрешаются в неверный ответ или вообще ни во что.
Предотвращение петель — та операционная деталь, которая кусает. Собственные соединения адаптера к серверу SOCKS не должны маршрутизироваться обратно в адаптер, поэтому его трафику нужно исключение в правиле или отдельный адрес источника. Ошибётесь здесь, и прокси-сеанс попытается проксировать сам себя.
Третий случай: хост на самом деле является маршрутизируемым шлюзом
Иногда работающая настройка вообще не содержит SOCKS. Удалённый хост пересылает пакеты или выполняет для них NAT, и правило на основе источника просто выбирает его как выход. Такая схема законна, и она объясняет, почему скопированная конфигурация работает в одной сети и не работает в другой: правило одинаковое, недостающая часть — служба пересылки на другой стороне.
Три случая разделяются быстро. Проверьте, что именно слушает, а затем посмотрите на первые байты, достигающие хоста:
ss -ltnp 'sport = :1080'
tcpdump -ni eth0 -X 'tcp port 1080'Первый байт полезной нагрузки настоящего клиента SOCKS — 0x05, версия в приветствии. Если запись показывает вместо этого исходные данные приложения, ни один демон SOCKS не ответит, потому что переговоры так и не начались. Если на 1080 ничего не слушает, хост — это шлюз, и вопрос становится таким: пересылает ли он пакеты и существует ли обратный путь.
Выберите уровень с помощью четырёх вопросов
Есть ли у программы настройка прокси? Используйте её и остановитесь на этом. Есть ли в трафике UDP или ICMP, которые должны выжить? ICMP несёт только маршрутизируемый шлюз или шлюз с NAT, а UDP требует ассоциации SOCKS5, которую поддерживают обе стороны. Нужно ли охватить каждый процесс на машине, включая те, которые вы не можете настроить? Тогда нужен адаптер, который владеет интерфейсом и завершает потоки. Можете ли вы взять на себя также его маршрутизацию, DNS и исключения для предотвращения петель? Если нет, обычный шлюз обойдётся дешевле в эксплуатации.
Одно различие стоит держать ясным. Собственная опция socks-proxy клиента VPN описывает, как внешнее туннельное соединение достигает своего сервера, и ничего не говорит о преобразовании внутренних потоков клиента. Эти две вещи постоянно путают в одном и том же тикете. Решите, какая связь вам нужна, прежде чем трогать маршрут.