UDP reverse (obfuscating) proxy

Друзья, нужен реверсный прокси-сервер для UDP. То, что делает ssh-опция -R, только для UDP. Я как не старался, найти не смог.

Дополнительным бонусом была бы возможность прикидываться каким-нибудь “легитимным” протоколом, например, dtls, ну, или хотя бы просто XOR с ключом. Ну, или “настоящий” dtls реверс-прокси.

Именно реверс, а не прямой нужен из-за того, что целевая машина находится за NAT.

Shadowsocks не подходит?

Я не нашёл такого функционала в shadowsocks. Не подскажете, как именно это сделать?

Ну, и вы же сами спрашивали два года назад, и выяснялось, что обфускации тоже нет:

Вам шашечки или ехать? С обфускацией UDP сейчас нигде нет вроде бы.

Обфускация – это не шашечки, это иногда очень нужно.

Но даже если считать её “шашечками”, всё равно shadowsocks не умеет обратное проксирование, только прямое.

Какую вы решаете задачу? Почему ищете именно реверс-прокси, а не хотите применить стандартные методы, вроде VPN?
VPN идеально подходит для вашей задачи.

Задача выглядит тривиальной. Это примерно уровень университетской лабораторной работы. Кажется будет проблемно найти готовое решение промышленного качества. Впрочем, несложно сделать самому или нанять кого-нибудь.

Для простейшей обфускации перед отправкой добавляйте к полезной нагрузке каждой дейтаграммы несколько случайных байт в качестве ключа, затем этими же байтами проксорьте буфер. На принимающей стороне извлеките ключ из принятых данных и снова проксорьте отстальную часть. В конце не забудьте обрезать полезню нагрузку на длину ключа. Операция выполняется очень быстро. Издержки на работу сети обычно существенно выше.

Не совсем понятно что вы понимаете под обратным прокси применительно к UDP. В соединениях UDP стороны практически равнозначны. Просто два узла попеременно шлют друг другу дейтаграммы. Нет состояний, рукопожатий и прочего. Конечно, для того чтобы временно открыть на прием порт через NAT необходимо чтобы самую первую дейтаграмму отправил узел за NAT. Так же стоит учитывать то, что NAT автоматически закроет порт через 1…2 минуты если в течение этого срока не будет получено входящих дейтаграм.

Здесь можно найти нескольколько простых примеров работы через UDP: UDP/datagram sockets | Node.js v18.4.0 Documentation

  1. VPN и есть задача, которую я решаю.
  2. Мой VPN-сервер за NAT’ом, машина – это релей.
  3. Для прохождения NAT нужен реверс-прокси.
  4. Обфускация нужна, чтобы провайдер релея не забанил.
  5. UDP нужен, потому что TCP-VPN это дрянь.

VPN идеально подходит для вашей задачи.

Я не хочу гонять VPN-over-VPN, и я не хочу держать сервер VPN на релее.

Задача выглядит тривиальной.

Вы готовы за неё взяться? Сколько это будет стоить? Более конкретно, вы готовы добавить опцию -R и/или DTLS в UDPspeeder?

https://securesocketfunneling.github.io/ssf/

ssf туннелирует через tls, а не dtls, то есть, через tcp. Не годится.

Вряд ли у нас что-то получится. Но если будут вопросы, конечно, обращайтесь.

В таком случае, как вы представляете архитектуру реверс-прокси для UDP без установки какой-либо программы и на релее, и на сервере? Чем это принципиально отличается от установки какого-либо туннеля (хоть fou) и на релее, и на сервере?

Мне кажется, у вас проблема проблема XY: вы описываете не задачу, а ваше видение её решения.

В таком случае, как вы представляете архитектуру реверс-прокси для UDP без установки какой-либо программы и на релее, и на сервере?

Почему без установки? На релее устанавливается сервер udp-ssh-R и открывает два слушающих сокета (один для клиента udp-ssh-R, один для входящих соединений), на VPN-машине клиент udp-ssh-R, и раз в 2 минуты шлёт на релей keepalive. При подключении к сокету на релее, он принимает “коннект”, и пересылает пакет udp-ssh-R клиенту (за NAT), и тот уже подключается к слушающему сокету VPN-процесса.

Естественно, нужен ещё и сервер прямого прокси на релее, например, тот же самый shadowsocks, который будет деобфусцировать входящее соединение с клиента.

Что на релее не делается, это не создаётся нового VPN-интерфейса, не хранится ценных (более-менее) приватных ключей, и не производится лишних хопов маршрутизации. И с MTU меньше трудностей.

Чем это принципиально отличается от установки какого-либо туннеля (хоть fou) и на релее, и на сервере?

Я не знаю, как работает fou. Спасибо за наводку, я почитаю. Хотя беглым взглядом я не вижу, как это должно работать.

Но куда релей должен отправлять ответ сервера, если сервер не знает и, соответственно, не сообщает адрес клиента, а на релей, допустим, пришло пять клиентов? Все-таки нужен или VPN или в более общем виде программа-мультиплексор умеющая передавать несколько UDP-соединений через одно. VPN проще. Я бы попытался прикрутить wireguard. Там каждый узел может работать и как клиент и как сервер для разных подключений. Ваш серевер может установить соединение с релеем как клиент, а уже через него принимать подключения клиентов (не раскрывая при этом ключи). Не пробовал такую схему, но вроде должно работать.

Если клиенты подклчаются через shadowsocks, то может быть проще проксировать необработанный shadowsocks через релей?

Но куда релей должен отправлять ответ сервера, если сервер не знает и, соответственно, не сообщает адрес клиента, а на релей, допустим, пришло пять клиентов?

У меня всего один клиент, мне достаточно одного.

Все-таки нужен или VPN или в более общем виде программа-мультиплексор умеющая передавать несколько UDP-соединений через одно.

Как ssh передаёт? Вот так же и передавать. Да, видимо, добавлять свой заголовок к пакету, а может быть, вообще если два маленьких пакета пришло, уложившись в буфер, упаковывать их в один UDP пакет, а на сервере распаковывать.

VPN проще. Я бы попытался прикрутить wireguard. Там каждый узел может работать и как клиент и как сервер для разных подключений.

Это не проще. Это VPN-over-VPN, лишний хоп маршрутизации, лишний интерфейс на сервере, лишние айпи в файрволе, проблемы с MTU. Собственно, сейчас оно так и работает, только VPN это ssh-VPN.

Ваш серевер может установить соединение с релеем как клиент, а уже через него принимать подключения клиентов (не раскрывая при этом ключи). Не пробовал такую схему, но вроде должно работать.

Работать будет, но хочется более прямолинейного решения. Собственно, таким решением мог бы являться socat, но socat не сохраняет границы пакетов, из-за чего половина пакетов не проходит.

В таком случае, если IP-адреса клиента и сервера заранее известны (если у вас стационарный клиент) и NAT не симметричный, вы можете установить соединение без релея, отправляя UDP-пакеты в обе стороны с фиксированными портами. OpenVPN, например, можно настроить в таком режиме: задайте port и lport фиксированными и на клиенте, и на сервере.
Если адрес клиента или сервера заранее не известен, но клиент всё ещё стационарный и NAT не симметричный, можете использовать ваш релей-сервер для их согласования.

Если у вас нет ограничений на ОС/протокол, то попробуйте, например, weron — это VPN поверх WebRTC (DTLS), с «пробивом» NAT. Или, например, tinc, или zerotier, или tailscale.

Софт для UDP reverse proxy мне неизвестен. Ближе всего в этому был бы v2fly, но он не поддерживает режим reverse proxy на UDP-порт, а только на TCP-сервисы (хоть и трафик туннелировать может через UDP, например, через QUIC).
Не зная, чего в действительности вы хотите добиться, посоветовать вам что-то обстоятельно не представляется возможности — вы не рассказываете о задаче.

Не зная, чего в действительности вы хотите добиться, посоветовать вам что-то обстоятельно не представляется возможности — вы не рассказываете о задаче.

Reverse UDP прокси, такой же как ssh -R, только для udp, сохраняющий границы пакетов при доставке.

weron tinc zerotier, tailscale.

Я ещё раз поковыряюсь со всем этим, но для тупого проксирования UDP это все кажется оверкиллом.

Простой рабочий вариант для одного клиента, с OpenVPN.

На стороне релея:

  1. Скомпилировать GitHub - TLINDEN/udpxd: A general purpose UDP relay/port forwarder/proxy
  2. Запустить: ./udpxd -l 0.0.0.0:1194 -b 0.0.0.0:12498 -t 1.1.1.1:1194, где 1.1.1.1 — IP-адрес сервера.

На стороне сервера (за несимметричным NAT):

  1. Запустить OpenVPN на порту 1194 UDP
  2. Запустить sudo nping --udp -g 1194 -p 12498 2.2.2.2 -c1, где 2.2.2.2 — IP-адрес relay-сервера.

Готово. Клиент может подключаться к 2.2.2.2:1194. Команду с nping нужно выполнять каждые пару минут при отсутствии клиента. Также в OpenVPN следует настроить keepalive на 30-40 секунд.
Обфускации в этом способе нет, установка дополнительного ПО на VPN-сервер не требуется.

Это опять не похоже на задачу, а на ваше видение её решения. Ранее вы говорили о VPN. Вы хотите соеденить двух клиентов VPN, оба из которых находятся за NAT? В таком случае, рассмотрите VPN-решения, упомянутые выше, они позволят это сделать без промежуточного сервера.