У меня дома работает сервер Wireguard, чтобы иметь возможность войти в мою домашнюю сеть извне. Wireguard использует UDP. К сожалению, я не могу просто открыть UDP-порт IPv4 в своем фритч-боксе, как это работало в старые времена, потому что мой провайдер подключил меня к CG-NAT, мне приходится использовать IPv6, но IPv6 еще нельзя использовать на моем рабочем месте.
Итак, дома у меня IPv6, а на работе IPv4, и нет возможности подключиться к домашней сети.
У меня также есть VPS с общедоступным IPv4, к которому я могу установить обратные ssh-туннели для TCP-трафика. К сожалению, ssh-туннели поддерживают только TCP, и в любом случае не следует устанавливать VPN-соединения через TCP, поэтому Wireguard использует только UDP.
VPN-Server VPN-Client
(UDP) | | (IPv4 UDP)
| | | not possible |
-----------|--------| <-------------------
| |
NAT CG-NAT
VPN-Server VPN-Client
(UDP) (IPv4 UDP)
| |
| |
inside agent outside agent
tunnel tunnel
|| | | ||
|| punch| punch| ||
| --------->|-------->|-------------------- |
-----------|<--------|<--------------------
| |
| |
NAT CG-NAT
Внешний агент работает на VPS с общедоступным IPv4.
Внутренний агент будет отправлять дейтаграммы UDP на общедоступный IP-адрес и порт внешнего агента, это пробьет дыры в обоих NAT, внешний агент получит эти дейтаграммы и узнает по своему исходному адресу и порту, как отправлять дейтаграммы обратно внутреннему агенту. .
VPN-клиент может отправлять UDP внешнему агенту, и эти датаграммы будут перенаправлены внутреннему агенту, а оттуда на VPN-сервер, VPN-сервер может ответить внутреннему агенту, они будут перенаправлены внешнему агенту и оттуда VPN-клиент.
Внешний агент будет отображаться для клиента как VPN-сервер, а внутренний агент будет отображаться для сервера как VPN-клиент.
Возможны несколько клиентских подключений, поскольку для каждого нового клиента, подключающегося снаружи, будет использоваться туннель и новый сокет внутреннего агента, поэтому для сервера это будет выглядеть так, как если бы на хосте внутреннего агента работало несколько клиентов.
Клонируйте или разархивируйте код на обеих машинах и соберите его. Вам нужны как минимум make и gcc. Введите исходный каталог и используйте команду
$ make
После успешной сборки вы получите двоичный udp-tunnel
в той же папке. Теперь вы можете либо запустить его прямо из терминала (разумеется, с правильными параметрами), чтобы провести несколько быстрых тестов, либо установить его с помощью make-файла.
Скомпилированный двоичный udp-tunnel
может действовать либо как внутренний агент, либо как внешний агент, в зависимости от того, какие параметры вы передаете в командной строке.
Предположим, в качестве примера, что VPN-сервер прослушивает UDP 1234, работает на локальном хосте (так же, как внутренний агент), а внешний компьютер — jump.example.com, и мы хотим, чтобы он прослушивал UDP-порт 9999.
На внутреннем хосте мы начинаем с
$ ./udp-tunnel -s localhost:1234 -o jump.example.com:9999
На внешнем хосте мы начинаем его с
$ ./udp-tunnel -l 9999
Makefile содержит три цели установки: install
для установки только двоичного файла, install-outside
и install-inside
для установки также служебных файлов systemd. Для правильной работы последних двух переменных необходимо передать в make.
Чтобы установить внешний агент на переходном хосте (при условии, что вам нужен порт 9999), вы выполняете следующую команду:
$ sudo make install-outside listen=9999
Это установит двоичный файл в /usr/local/bin/
и установит служебный файл systemd в /etc/systemd/system/
содержащий необходимую команду для запуска его в режиме внешнего агента с портом 9999.
Чтобы установить внутренний агент на внутреннюю машину, используйте следующую команду (предположим, что ваш VPN-сервер — localhost:1234, а ваш хост перехода — jump.example.com):
$ sudo make install-inside service=localhost:1234 outside=jump.example.com:9999
Это снова установит двоичный файл в /usr/local/bin/
и файл модуля systemd в /etc/systemd/system/
На этом этапе вы можете быстро просмотреть файлы модулей systemd, чтобы увидеть, как используется двоичный файл, и проверить правильность параметров. Параметры должны выглядеть так, как описано выше в быстром тесте.
После того, как файлы systemd установлены и подтверждены правильностью, они еще не включены для автозапуска, вам необходимо включить и запустить их. На внутренней машине:
$ sudo systemctl enable udp-tunnel-inside.service
$ sudo systemctl start udp-tunnel-inside.service
и на внешней машине
$ sudo systemctl enable udp-tunnel-outside.service
$ sudo systemctl start udp-tunnel-outside.service
Шифрование отсутствует. Пакеты пересылаются в том виде, в каком они есть, предполагается, что какой бы сервис, который вы туннелируете, знает, как защитить или зашифровать свои данные самостоятельно. Обычно это касается VPN-соединений.
Кроме того, злоумышленник может захотеть подделать пакеты поддержки активности от внутреннего агента, чтобы запутать внешнего агента и перенаправить туннель на свою машину, что приведет к сбою в обслуживании. Чтобы предотвратить эту очень простую атаку, дейтаграммы поддержки активности можно аутентифицировать с помощью кода аутентификации сообщения на основе хэша. Вы можете использовать общий пароль, используя опцию -k на обоих концах туннеля, чтобы активировать эту функцию.
На внутреннем хосте вы бы использовали его вот так
$ ./udp-tunnel -s localhost:1234 -o jump.example.com:9999 -k mysecretpassword
На внешнем хосте вы должны начать с
$ ./udp-tunnel -l 9999 -k mysecretpassword
После того, как вы успешно выполнили шаги установки, описанные выше, вы можете вручную отредактировать файлы systemd на обоих концах и добавить параметр -k, а затем перезагрузить и перезапустить на обоих концах.
Затем сообщение поддержки активности будет содержать SHA-256 для этого пароля и строго увеличивающегося одноразового номера, который можно использовать только один раз для предотвращения простых атак повторного воспроизведения.
Оба агента поддерживают список соединений, каждое соединение хранит адреса сокетов и дескрипторы сокетов, связанные с этим конкретным клиентским соединением.
При запуске внутренний агент инициирует исходящий туннель к внешнему агенту, помечает его как неиспользуемый и отправляет по нему пакеты поддержки активности. Внешний агент увидит эти пакеты и добавит этот туннель с исходным адресом в свой список подключений. Пакеты поддержки активности подписываются с помощью nonce и кода аутентификации, поэтому их нельзя подделать или воспроизвести.
Когда клиент подключается, внешний агент отправит данные клиента по этому неиспользуемому резервному туннелю, внутренний агент увидит это, пометит туннель как активный, создаст сокет для связи со службой и пересылает данные в обоих направлениях. Затем он также немедленно создаст еще один новый исходящий запасной туннель, чтобы быть готовым к приему следующего входящего клиента.
Когда новый запасной туннель достигнет внешнего агента, он добавит его в свой собственный список подключений, чтобы иметь возможность немедленно обслуживать следующего подключающегося клиента.
На данный момент у обоих агентов в списке есть 2 туннеля: один активный, а другой запасной, ожидающий следующего подключения клиента.
тайм-ауты бездействия гарантируют, что мертвые туннели (те, которые были помечены как активные в прошлом, но в течение некоторого времени не было данных клиента) будут удалены, а их сокеты будут закрыты. Внутренний агент обнаружит отсутствие пересылаемых данных в течение длительного времени, удалит их из своего собственного списка и закроет свои сокеты, затем через некоторое время внешний агент обнаружит, что для этого соединения больше не поступает сообщений об активности, и удалит их из своего собственного. список тоже.
Этот код все еще является экспериментальным, поэтому не стоит строить на нем многомиллионный бизнес, по крайней мере, пока. Для меня он прекрасно служит своей цели, но для вас он может привести к сбою, сожжению и взрыву вашего сервера. Вы были предупреждены.