Очень простой IP-туннель, основанный на DTLS.
Если нет необходимости в сильном шифровании, можно рассмотреть возможность использования более легкого утуна?
go install github.com/taoso/dtun/cmd/dtun
# 服务端
dtun -key foo
# 客户端
dtun -connect addr:port -key foo
Вот краткий список нескольких факторов, которые следует учитывать.
Нелегко добиться стабильного и надежного шифрования данных транспортного уровня, поэтому я всегда использовал TLS в качестве основного протокола.
TLS использует TCP, и зашифрованные данные в значительной степени также являются данными TCP. Таким образом, передача пакета данных верхнего уровня требует подтверждения внутреннего и внешнего TCP-соединений. Проблема реализации такого типа TCP через TCP немалая. Подробности см.: Ссылка http://sites.inka.de/~bigred/devel/tcp-tcp.html.
Поэтому лучше всего использовать передачу UDP. Естественно, для шифрования используется DTLS. В настоящее время DTLS не поддерживает версию 1.3, и язык go официально не поддерживает ее. Вы можете использовать только стороннюю реализацию https://github.com/pion/dtls.
Будь то TLS или DTLS, вам обычно необходимо создать сертификат. Сейчас этот процесс бесплатен, но его по-прежнему сложно настроить. Кроме того, сертификат решает только проблему шифрования и не решает проблему аутентификации. Обычно только клиент проверяет сертификат сервера. Вы также можете позволить серверу проверять сертификат клиента, но это слишком хлопотно.
Кроме того, DTLS не требует установления соединения и не может выполнять аутентификацию только при создании соединения, такого как TCP-соединение.
Поэтому лучше всего выполнять аутентификацию обоих концов одновременно во время установления связи DTLS. Поэтому я выбираю режим предварительного общего ключа (PSK). Нам нужно использовать -key
только для указания главного ключа на обоих концах для завершения двусторонней аутентификации. Сеанс DTLS не может быть установлен, если клиент не знает PSK.
Кроме того, PSK также необходимо указать параметр подсказки. Вы можете просто думать об этом как о названии PSK. DTLS не подключен, поэтому сложно определить, находился ли клиент в автономном режиме. Я решил создать уникальный параметр подсказки для каждого клиента. Сервер выделяет устройства Tun для подсказок. Если клиент отключен и повторно подключен, несколько устройств Tun не будут созданы. Но побочным эффектом является то, что клиенты одного и того же hinit не могут войти в систему одновременно.
Для поддержки MacOS устройство настройки можно установить только в режим «точка-точка». Если мы хотим сделать прозрачную маршрутизацию и пересылку, посмотрите на картинку ниже.
pc <-----------> router <====== dtun ======> pc2 <---------> www
10.0.0.2/16 10.0.0.1/16 10.1.0.1/16 10.1.0.2/16
Мы надеемся, что пакеты, отправленные компьютером, будут перенаправлены на компьютер 2 через маршрутизатор, а затем перенаправлены во внешнюю сеть. Обычно мы выполняем NAT один раз на маршрутизаторе, а затем один раз на компьютере 2. Преимущество этого заключается в том, что компьютеру 2 не нужно знать конфигурацию сети компьютера и маршрутизатора. Но и минусы очевидны, есть два нац. Производительность маршрутизаторов, как правило, невысока, поэтому следует избегать использования NAT, насколько это возможно.
Поэтому мой план состоит в том, чтобы напрямую передать сегмент сети 10.0.0.0/16, где находится компьютер, на компьютер 2 и добавить маршрут на компьютер 2.
ip route add 10.0.0.0/16 via 10.1.0.1
Таким образом, маршрутизатор может пересылать пакеты с компьютера на компьютер 2 без изменений, и ему нужно будет выполнить NAT только один раз на компьютере 2.
Иногда нам нужно указать белый список маршрутизации. Используйте маршрут по умолчанию для сегментов сети в белом списке и пересылайте остальные через туннель.
Мы можем сначала добавить маршрут в белый список к маршрутизатору и установить следующий переход в качестве маршрута маршрутизатора по умолчанию. Затем укажите общедоступный IP-адрес компьютера 2, чтобы использовать маршрут маршрутизатора по умолчанию (ключ!). последний добавленный
ip route add 0.0.0.0/1 via 10.1.0.2
ip route add 128.0.0.0/1 via 10.1.0.2
Здесь 0.0.0.0/1
и 128.0.0.1/1
охватывают весь сегмент сети. Эффект эквивалентен значению по умолчанию, но не перезаписывает маршрут по умолчанию. Если туннель закрывается ненормально, все связанные маршруты будут автоматически удалены, что очень стабильно.
Вы можете написать его как скрипт и запустить, используя параметр -up
. Мой сценарий выглядит следующим образом:
#! /bin/sh
# curl -S https://cdn.jsdelivr.net/gh/misakaio/chnroutes2@master/chnroutes.txt|grep -v '#'|xargs -I % ip route add % via $DEFAULT_GW 2>/dev/null
VPN_IP= $( ping your-server-name -c 1 | grep from | cut -d ' ' -f4 | cut -d: -f1 )
DEFAULT_GW= $( ip route | grep default | cut -d ' ' -f3 )
ip route add $VPN_IP /32 via $DEFAULT_GW
ip route add 0.0.0.0/1 via $PEER_IP
ip route add 128.0.0.0/1 via $PEER_IP