Вопрос или проблема
Я столкнулся с проблемой – я хотел бы подключить множество встроенных устройств с OpenWRT к своему серверу Wireguard, но все порты, кроме 80, 443 и некоторых других, заблокированы. Более того, в сети разрешен только TCP.
Похоже, мне нужно закапывать WireGuard, который работает по UDP, в TCP. На своем сервере я хотел бы использовать сервис SSHL (обмен портами), чтобы одновременно запустить HTTPS сервер и туннель для WireGuard на порту 443 (или другом, разрешенном брандмауэром). Я хотел бы иметь многопользовательский туннель, поэтому подозреваю, что быстрые хаки с socat не сработают для большего количества клиентов.
- Я пробовал
wireguard-proxy
, он отлично работает с обменом портами через SSLH, но написан на Rust, и я не могу развернуть его на OpenWRT (я пробовал, и получил ошибки компиляции).
– Я также протестировалudp2raw
, и он тоже хорошо работает на выделенном порту, но я не могу к нему подключиться, когда использую мультиплексор портов SSLH.
Я ищу какое-то программное обеспечение для туннелирования, написанное на C/C++, которое можно перекомпилировать в системе сборки OpenWRT и использовать с моими модифицированными сетевыми устройствами.
Вы можете использовать socat
в качестве программного обеспечения для туннелирования.
Вот типичная настройка (выполняется интерактивно) с WireGuard, который слушает на порту 51820. Вам все равно придется выполнить адекватную интеграцию в сервисы запуска.
OpenWRT (но на самом деле протестировано на другой Linux)
-
Включите интерфейс Wireguard, как обычно
… кроме MTU: смотрите описание в Примечаниях ниже. Давайте использовать MTU 1420-64=1356. Пример (это должно быть сделано в
wg0.conf
, когда используетсяwg-quick
):ip link set wg0 mtu 1356
-
терминал1:
sslh -n --listen 0.0.0.0:443 \ --tls 127.0.0.1:8443 \ --anyprot 127.0.0.1:51820 \ -f
sslh
не распознает протокол WireGuard, поэтому соединение будет направлено на--anyprot
. -
терминал2:
socat -T 120 \ tcp4-listen:51820,bind=127.0.0.1,reuseaddr,nodelay,fork \ udp4-connect:127.0.0.1:51820
Как
socat
предлагает для другого случая:Примечание: Если вы намереваетесь передавать пакеты между двумя “проводами” Socat, вам нужен протокол, который сохраняет границы пакетов, например, UDP; TCP может работать с опцией nodelay.
Хотя
sslh
не использует nodelay, обаsocat
будут это делать, что hopefully поможет в этой части.-T 120
– это задержка неактивности перед завершением форкнутыхsocat
. Полезно, если клиент перемещается и теряет соединение. Это значение должно быть выше, чем ожидаемый постоянный keepalive WireGuard клиента. В любом случае, это не сильно поможет в случае DDoS-атаки без TLS: будет несколько форкнутыхsocat
, и это может помочь только при DoS (сам WireGuard игнорирует такой трафик).
Клиент
-
терминал1:
socat -T 120 \ udp4-listen:51821,bind=127.0.0.1,fork \ tcp4:public-endpoint:51820,nodelay
На самом деле, если клиент перемещается, эту команду
socat
может понадобиться перезапустить, потому что ее TCP-часть может занять время, чтобы правильно завершить работу. -
Интерфейс Wireguard
Как и прежде, уменьшите MTU. В Linux это снова будет:
ip link set wg0 mtu 1356
И измените конечную точку пир-узла, чтобы переключиться на вход туннеля, который теперь находится на локальной системе (это также должно быть сделано в
wg0.conf
клиента):wg set wg0 peer XXXXXXXXX= endpoint 127.0.0.1:51821
Теперь, как только клиент отправляет любой пакет внутри туннеля и аутентифицируется, WireGuard сервера обновит конечную точку своего клиента (на 127.0.0.1:randomport от локального socat
) и сможет ответить. Это создает полудуплексное взаимодействие:
client ⟺ WG ⟺ UDP ⟺ socat ⟺ TCP через интернет
⇧
⇩
server ⟺ WG ⟺ UDP ⟺ socat ⟺ TCP ⟺ sslh
Примечания
-
Соображения по MTU
В дополнение к обычным 80 байтам накладных расходов (1500-80=1420), WireGuard резервирует, необходимо добавить на накладные расходы TCP. Это чтобы избежать того, что внешний туннельный уровень:
socat
+sslh
, которые не осведомлены о нижележащем протоколе, получили слишком большой полезный груз, разбитый на два TCP пакета: это может разрушить как минимум второй инкапсулированный UDP-полезный груз, вызывая повторные передачи.Эта накладная плата на самом деле динамическая. Для IPv4 это как минимум 20 для IP плюс 20 для TCP. Затем любое современное TCP-соединение использует 2+8+2=12 байтов для метки времени и будет использовать случайное количество SACK, когда пакеты теряются. Давайте оставим один (2+2*4+2=12): 20+20+12+12=64. Точная величина не так важна (действительно ли между этими двумя опциями TCP есть два NOP для выравнивания? Я не знаю). Таким образом, в конечном итоге я решил, что MTU WireGuard будет 1420-64=1356.
Некоторые тесты, проведенные по фактической физической локальной сети с использованием
ping -M do -s $MTU-28 -f 10.x.x.x
, показали, что поддержание MTU=1420 на интерфейсах приводило к потере ~ 40% пакетов, и что MTU=1356 не терял никаких, даже если более высокие MTU также казались адекватными. -
случай ограничения на port 443, требующий также SSL
Если брандмауэр, ограничивающий использование порта 443, ожидает только SSL-трафик на этом порту, то дело усложняется. Следует заменить
sslh
наhaproxy
илиnginx
(обе, как кажется, упакованы на OpenWRT, я не знаю, были ли доступны необходимые функции) и использовать их функцию TLS pass-through для маршрутизации TLS-соединения в зависимости от полученного ClientHello’s SNI. Обаsocat
тогда заменятtcp-listen
/tcp
наopenssl-listen
/openssl
для общения, но я не уверен, как MTU будет затронут в этом случае.
Ответ или решение
Для решения вашей задачи о туннелировании WireGuard через TCP на порту 443, учитывая ограничения сетевых портов и предпочитаемый протокол TCP, я предлагаю использовать сочетание утилит sslh
и socat
. Данная схема позволяет организовать многопользовательский туннель для WireGuard, обрабатывая соединения на порту 443 без необходимости использования дополнительных UDP портов.
Настройка на сервере OpenWRT
-
Установите необходимые пакеты:
Убедитесь, что у вас установленыwireguard
,sslh
иsocat
. Вы можете установить их с помощьюopkg
:opkg update opkg install wireguard sslh socat
-
Настройка интерфейса WireGuard:
Создайте файл конфигурации WireGuard (например,/etc/wireguard/wg0.conf
) и настройте интерфейс. Обратите внимание на MTU:[Interface] Address = 10.0.0.1/24 ListenPort = 51820 PrivateKey = <ваш_приватный_ключ> [Peer] PublicKey = <публичный_ключ_клиента> AllowedIPs = 10.0.0.2/32
Настройте MTU интерфейса:
ip link set wg0 mtu 1356
-
Настройка
sslh
:
Запуститеsslh
, чтобы он слушал на порту 443 и перенаправлял трафик:sslh -n --listen 0.0.0.0:443 \ --tls 127.0.0.1:8443 \ --anyprot 127.0.0.1:51820
Обратите внимание, что в случае WireGuard SSLH не способен распознать его протокол, поэтому трафик будет передан на
--anyprot
. -
Настройка
socat
:
Создайте туннель с помощьюsocat
для перенаправления UDP-пакетов через TCP:socat -T 120 \ tcp4-listen:51820,bind=127.0.0.1,reuseaddr,nodelay,fork \ udp4-connect:127.0.0.1:51820
Данный вызов
socat
будет слушать TCP-соединения и пересылать их на WireGuard.
Настройка клиента OpenWRT
-
Настройка
socat
на клиенте:
На стороне клиента настройтеsocat
, чтобы он слушал UDP-пакеты и отправлял их на сервер:socat -T 120 \ udp4-listen:51821,bind=127.0.0.1,fork \ tcp4:<публичный_IP_сервера>:51820,nodelay
-
Настройка WireGuard клиента:
Измените конфигурацию клиента, чтобы использовать локальный сокет:[Interface] Address = 10.0.0.2/24 PrivateKey = <приватный_ключ_клиента> [Peer] PublicKey = <публичный_ключ_сервера> Endpoint = 127.0.0.1:51821 AllowedIPs = 10.0.0.0/24
Настройте MTU так же, как на сервере:
ip link set wg0 mtu 1356
Заметки и рекомендации
-
MTU: Убедитесь, что значение MTU корректное, чтобы избежать фрагментации пакетов. Используйте указанный выше размер (1356) для стабильной передачи.
-
Дополнительные ограничения на порту 443: Если ваша сеть требует, чтобы на порту 443 использовался только SSL, вам потребуется заменить SSLH на такой прокси, который может учитывать SNI, например,
haproxy
илиnginx
, с соответствующими настройками для TLS. -
Перезапуск служб: Не забывайте включить эти службы при старте системы, чтобы ваши настройки работали автоматически при загрузке маршрутизатора.
Эта инструкция предоставляет вам полное решение для установки туннеля WireGuard через TCP на OpenWRT, позволяя подключаться к многопользовательским клиентам через ограниченные порты.