dnstt — это DNS-туннель (VPN over DNS), который может использовать резолверы DNS через HTTPS (DoH) и DNS через TLS (DoT). Проект написан на языке Go.
Руководство будет включать:
Как работает DNSTT
Настройку DNS для домена
Настройку туннеля dnstt на сервере
Настройку клиента dnstt на OpenWRT
Настройку автозапуска сервера, клиента и tun2socks
1. Как работает DNSTT
DNS-туннель – это один из способов обойти сетевую цензуру. Цель рекурсивного DNS-резолвера — получать пакеты и пересылать их куда-то еще — по сути, работая как своего рода сетевой прокси. DNS-туннели через UDP с открытым текстом обычно считаются легко обнаруживаемыми из-за необычных DNS-сообщений, которые они используют. Однако DoH и DoT зашифрованы — внешний наблюдатель может видеть, что вы общаетесь с общедоступным резолвером, но не может расшифровать сообщения DNS и убедиться, что они являются частью туннельного протокола. (Сам резолвер все равно может легко определить, что вы используете туннель.)
dnstt по умолчанию использует сквозное шифрование и аутентификацию между клиентом туннеля и сервером туннеля. По словам создателей структура протокола обеспечивает более высокую производительность, чем другие туннели DNS. (на практике удалось добиться скорости около 1.5 Мбит/с на DOWN/UP при использовании резолвера DoH Google)
dnstt не предлагает сетевой интерфейс TUN/TAP или даже интерфейс прокси-сервера SOCKS или HTTP, а только соединение типа netcat между локальным сокетом TCP и удаленным сокетом TCP. Однако довольно легко заставить туннель действовать как стандартный прокси-сервер, запустив прокси на туннельном сервере.
DNS-туннель работает за счет того, что туннельный сервер выступает в качестве авторитетного резолвера для определенного доменного имени. Рекурсивный DNS преобразователь посередине действует как прокси, перенаправляя запросы для этого домена на туннельный сервер. Чтобы настроить DNS-туннель, вам понадобится доменное имя и хост, который может принимать UDP-пакеты, на котором вы запускаете туннельный сервер. Рассмотрим следующий пример настройки:
Ваше доменное имя example.com (вам понадобится уже зарегистрированный домен)
IPv4-адрес вашего сервера 203.0.113.2.
IPv6-адрес вашего сервера 2001:db8::2 (опционально)
2. Настройка DNS
Зайдите в панель конфигурации вашего регистратора имен и добавьте три записи:
Тип | Имя | Данные |
A | 203.0.113.2 | |
AAAA | 2001:db8::2 | |
NS |
Метки «tns» и «t» могут быть любыми, но метка «tns» не должна быть субдоменом метки «t» (все, что находится под этим субдоменом, зарезервировано для полезных данных туннеля). Метка «t» должна быть короткой, поскольку пространство в DNS-сообщении ограничено, и часть его занимает имя домена.
3. Настройка туннеля на сервере Linux
В качестве примера используем сервер на Debian 10 (amd64)
Скачиваем бинарный файл с Github:
wget https://github.com/1andrevich/dnstt/releases/download/v0.20210424.0server/dnstt-server-amd64-linux.zip -O dnstt-server.zip
Альтернативно можно воспользоваться инструкцией по сборке пакета из официального руководства
Распаковываем:
unzip dnstt-server.zip
Разрешаем запуск исполняемого файла:
chmod +x dnstt-server-amd64-linux
Сначала вам необходимо сгенерировать секретный и открытый ключи для сквозного шифрования туннеля:
./dnstt-server-amd64-linux -gen-key -privkey-file server.key -pubkey-file server.pub
127.0.0.1:8000 — это TCP-адрес, на который будут перенаправляться входящие туннелированные потоки («удаленное приложение» на схеме).
Запускаем сервер:
./dnstt-server-amd64-linux -udp :5300 -privkey-file server.key t.example.com 127.0.0.1:8000
Туннельный сервер должен быть доступен через UDP-порт 53. Вы можете напрямую привязать его к порту 53 (-udp :53), но для этого вам потребуется запустить сервер от имени пользователя root. Лучше запустить сервер на непривилегированном порту, как показано выше, и использовать переадресацию портов для перенаправления на него порта 53. В Linux эти команды перенаправят порт 53 на порт 5300:
sudo iptables -I INPUT -p udp --dport 5300 -j ACCEPT
sudo iptables -t nat -I PREROUTING -i enp1s0 -p udp --dport 53 -j REDIRECT --to-ports 5300
sudo ip6tables -I INPUT -p udp --dport 5300 -j ACCEPT
sudo ip6tables -t nat -I PREROUTING -i enp1s0 -p udp --dport 53 -j REDIRECT --to-ports 5300
Для сохранения правил iptables после перезагрузки воспользуйтесь пакетом iptables-persistent или иным способом
Впишите ваш интерфейс по умолчанию вместо enp1s0 если у вас он другой (eth0, enp2s0 и т.д.)
Вам потребуется запущенная служба по адресу 127.0.0.1:8000, к чему туннельный сервер мог бы подключиться. Ниже приведены инструкции по запуску прокси-сервера. В целях тестирования вы можете использовать Ncat для вывода входящих данных на терминал:
sudo apt install ncat
ncat -l -k -v 127.0.0.1 8000
По умолчанию dnstt-server предполагает, что рекурсивный преобразователь поддерживает ответы DNS до определенного размера, а именно 1232 байта. Если выбранный вами резолвер не поддерживает такие большие ответы (в выходных данных сервера будут сообщения об ошибках), вы можете указать меньший предел, используя опцию -mtu, например -mtu 512.
4. Настройка клиента на OpenWRT
Рекомендуется роутер минимум с 128 МБ RAM (256 предпочтительно) и памятью более 16 Мб
Необходимо скачать с Github файл клиента для архитектуры вашего роутера
Определяем архитектуру:
grep "OPENWRT_ARCH" /etc/os-release | awk -F '"' '{print $2> }'
На выходе получаем ответ похожего вида (В моём случае TP-Link Archer C6U):
mipsel_24kc
Далее ищем пакет для архитектуры MIPS - Release v0.20210424.0 Binary Client · 1andrevich/dnstt (github.com)
Так как в репозитории Github есть версии для Mips и mipsle рекомендую сверится с OpenWRT Table of Hardware Wiki для вашего устройства
Для TP-Link Archer C6U - архитектура mipsle (он же mipsel)
Скачиваем по ссылке на роутер при помощи wget:
cd /tmp
wget https://github.com/1andrevich/dnstt/releases/download/v0.20210424.0/dnstt-client-mipsle-softfloat-linux.zip -O dnstt-client.zip
В моём случае подошла версия mipsle-softfloat, если на более позднем этапе установки выдаст ошибку "line 1: syntax error: unexpected "(" , то сверьтесь ещё раз с OpenWRT wiki и попробуйте версию hardfloat.
Далее файл необходимо будет распаковать, для экономии постоянной памяти установим пакет unzip в ОЗУ (он удалится при перезагрузке устройства)
opkg update
opkg install unzip -d ram
Распакуем архив с dnstt-client
/tmp/usr/bin/unzip dnstt-client.zip -d /tmp/dnstt-client
Разрешаем запуск исполняемого файла:
chmod +x /tmp/dnstt-client/ddnstt-client-mipsle-softfloat-linux
Проверяем работу программы:
./tmp/dnstt-client/dnstt-client-mipsle-softfloat-linux
Если выдаёт справку по командам то движемся дальше, если выдаёт ошибку "line 1: syntax error: unexpected "(" то возвращаемся к началу п.3
Перенесите содержимое файла server.pub с сервера на клиент, например скопировав его содержимое через буфер обмена.
Чтобы использовать резолвер DNS over HTTPS (DoH), используйте опцию -doh:
./tmp/dnstt-client/dnstt-client-mipsle-softfloat-linux -doh https://doh.example/dns-query -pubkey-file server.pub t.example.com 127.0.0.1:7000
Чтобы использовать резолвер DNS over TLS (DoT), используйте -dot:
./tmp/dnstt-client/dnstt-client-mipsle-softfloat-linux -dot dot.example:853 -pubkey-file server.pub t.example.com 127.0.0.1:7000
Проверяем соединение:
Для дальнейшей настройки, на сервере:
Ncat HTTP-прокси
Для тестирования довольно удобно использовать режим HTTP-прокси-сервера Ncat. Но имейте в виду, что прокси-сервер Ncat не предназначен для использования ненадежными клиентами; например, это не помешает им подключаться к портам локального хоста на туннельном сервере.
tunnel-server$ ncat -l -k --proxy-type http 127.0.0.1 8000
tunnel-server$ ./dnstt-server-amd64-linux -udp :5300 -privkey-file server.key t.example.com 127.0.0.1:8000
SSH SOCKS-прокси
OpenSSH имеет встроенный прокси-сервер SOCKS, который позволяет легко добавить прокси-сервер SOCKS на сервер, на котором уже установлен sshd.
На сервере установите SSH-соединение с локальным хостом, используя опцию -D, чтобы открыть SOCKS на порту 8000. Затем настройте туннельный сервер для перенаправления входящих подключений на порт 8000. Пусть туннельный клиент прослушивает свой собственный локальный порт 7000.
tunnel-server$ ssh -N -D 127.0.0.1:8000 -o NoHostAuthenticationForLocalhost=yes 127.0.0.1
#Введите пароль локального пользователя на сервере
tunnel-server$ ./dnstt-server-amd64-linux -udp :5300 -privkey-file server.key t.example.com 127.0.0.1:8000
Для HTTP и SOCKS Прокси на клиенте:
./tmp/dnstt-client/dnstt-client-mipsle-softfloat-linux -doh https://doh.example/dns-query -pubkey-file server.pub t.example.com 127.0.0.1:7000
5. Настройку автозапуска сервера, клиента и tun2socks
Если всё заработало, и вы хотите автоматизировать процесс запуска, то на сервере создаем службу systemd (Пример подходит для дистрибутивов Ubuntu, Debian и основанных на них)
Копируем файл в /usr/bin
sudo cp dnstt-server-amd64-linux /usr/bin/dnstt-server
Копируем server.key и server.pub в /etc/ssl/dnstt-server
sudo mkdir /etc/ssl/dnstt-server
sudo cp server.key /etc/ssl/dnstt-server/server.key
sudo cp server.pub /etc/ssl/dnstt-server/server.pub
Создаём службу systemd:
sudo nano /etc/systemd/system/dnstt-service.service
Содержимое /etc/systemd/system/dnstt-service.service:
[Unit]
Description=dnstt-server
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
#Service variables
Environment=SSH_PORT="22"
Environment=PORT=":5300"
Environment=DOMAIN="t.example.com"
Environment=KEY="/etc/ssl/dnstt-server/server.key"
Environment=PUB="/etc/ssl/dnstt-server/server.pub"
ExecStart=/usr/bin/dnstt-server -udp $PORT -privkey-file $KEY $DOMAIN 127.0.0.1:8000
#For HTTP-Proxy (Uncomment)
ExecStartPost=/bin/sh -c '/usr/bin/ncat -l -k --proxy-type http 127.0.0.1 8000 >> /var/log/dnstt-server.log'
#For SSH SOCKS Proxy (Uncomment)
#ExecStartPost=/usr/bin/ssh -p$SSH_PORT -i ~/.ssh/id_rsa -N -f -D 127.0.0.1:8000 -o NoHostAuthenticationForLocalhost=yes 127.0.0.1
# optional items below
Restart=always
[Install]
WantedBy=multi-user.target
Запускаем службу:
sudo systemctl daemon-reload
sudo systemctl enable dnstt-service.service
sudo systemctl start dnstt-service.service
C настройкой сервера окончено.
Переходим к настройке клиента.
Создадим службу для dnstt-client в OpenWRT.
Для этого перенесём файл /tmp/dnstt-client/dnstt-client-mipsle-softfloat-linux в /usr/bin/ (ПЗУ)
cp /tmp/dnstt-client/dnstt-client-mipsle-softfloat-linux /usr/bin/dnstt-client
Не забываем указать путь к файлу server.pub, в примере файл будет находится в папке /etc/ssl/dnstt
mkdir /etc/ssl/dnstt
cp /tmp/server.pub /etc/ssl/dnstt/server.pub
Создаём файл /etc/init.d/dnstt-client следующего содержания, например при помощи vi:
#!/bin/sh /etc/rc.common
USE_PROCD=1
# starts after network starts
START=98 #Number in rc.d queue
# stops before networking stops
STOP=90
PROG=/usr/bin/dnstt-client
DOMAIN="t.example.com"
PUB="/etc/ssl/dnstt/server.pub"
DOH="https://cloudflare-dns.com/dns-query"
DOT="cloudflare-dns.com"
DOT_PORT="853"
start_service() {
procd_open_instance
procd_set_param user root
#For DNS over HTTPS
procd_set_param command "$PROG" -doh "$DOH" -pubkey-file "$PUB" "$DOMAIN" 127.0.0.1:7000
#For DNS over TLS
#procd_set_param command "$PROG" -dot "$DOT":"$DOT_PORT" -pubkey-file ""$PUB" ""$DOMAIN" 127.0.0.1:7000
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
procd_close_instance
echo "dnstt-client is working!"
}
stop_service() {
service_stop $PROG
echo "dnstt-client has stopped!"
}
reload_service() {
stop
sleep 5s
echo "dnstt-client restarted!"
start
}
Делаем файл исполняемым:
chmod +x /etc/init.d/dnstt-client
Делаем автозапуск:
ln -s /etc/init.d/dnstt-client /etc/rc.d/S98dnstt-client
Запускаем:
/etc/init.d/dnstt-client start
Далее настраиваем tun2socks.
Ищем пакет tun2socks для архитектуры MIPS - mipsle softfloat (подробнее в п.3) - Release v2.5.1 · xjasonlyu/tun2socks (github.com).
Скачиваем по ссылке на роутер при помощи wget:
cd /tmp
wget https://github.com/xjasonlyu/tun2socks/releases/download/v2.5.1/tun2socks-linux-mipsle-softfloat.zip -O tun2socks.zip
В моём случае подошла версия mipsle-softfloat, если на более позднем этапе установки выдаст ошибку "line 1: syntax error: unexpected "(" , то сверьтесь ещё раз с OpenWRT wiki и попробуйте версию hardfloat.
Распакуем архив с tun2socks
/tmp/usr/bin/unzip tun2socks.zip -d /tmp/tun2socks
Если выдаёт ошибку убедитесь что unzip установлен ( opkg install unzip -d ram
)
Убедимся в наличии файла:
ls /tmp/tun2socks
Результат:
Проверяем работу программы:
/tmp/tun2socks/tun2socks-linux-mipsle-softfloat --help
Если выдаёт справку по командам то движемся дальше, если выдаёт ошибку "line 1: syntax error: unexpected "(" то возвращаемся к началу п.4.
Согласно документации tun2socks рекомендуется присвоить интерфейсу ip адрес (на практике маршрутизация работает и перенаправлением в dev tun3).
Для этого в /etc/config/network добавим следующее содержание:
config interface 'tunnel'
option device 'tun3'
option proto 'static'
option ipaddr '172.16.11.1'
option netmask '255.255.255.252'
Диапазон 172.16.11.0/30 выбран случайно, может быть любой диапазон частных адресов
Так же создаём зону и правило в /etc/config/firewall
config zone
option name 'dnsproxy'
option forward 'REJECT'
option output 'ACCEPT'
option input 'REJECT'
option masq '1'
option mtu_fix '1'
option device 'tun3'
option family 'ipv4'
config forwarding
option name 'lan-dnsproxy'
option dest 'dnsproxy'
option src 'lan'
option family 'ipv4'
Перезагружаем сеть
/etc/init.d/network restart
Далее проверяем работоспособность туннеля tun2socks:
/tmp/tun2socks/tun2socks-linux-mipsle-softfloat -device tun3 -proxy http://127.0.0.1:7000 -loglevel debug
Запустится туннель с логированием:
Где tun3 наименование туннеля.
proxy - адрес http прокси на порту 7000.
Проверяем доступность интерфейса:
ping -n 172.16.11.2
Для проверки работоспособности можно временно добавить маршрут к сайту ipecho.net (не закрывая tun2socks, в параллельной вкладке).
ip route add 34.160.111.0/24 dev tun3
Обращаемся к сайту и смотрим логи:
wget -qO- http://ipecho.net/plain | xargs echo
Если всё работает, команда вернёт IP вашего прокси DNSTT.
Можно закрывать tun2socks и удалить маршрут:
ip route del 34.160.111.0/24
Теперь перенесём файл в постоянную память устройства
mv /tmp/tun2socks/tun2socks-linux-mipsle-softfloat /usr/bin/tun2socks
Теперь настроим службу, чтобы интерфейс начинал работать при загрузке роутера.
В файл /etc/init.d/tun2socks вносим следующее содержание, например при помощи vi:
vi /etc/init.d/tun2socks
#!/bin/sh /etc/rc.common
USE_PROCD=1
# starts after network starts
START=99 #Number in rc.d queue
# stops before networking stops
STOP=89
PROG=/usr/bin/tun2socks
IF="tun3"
HOST="127.0.0.1"
PORT="7000"
start_service() {
procd_open_instance
procd_set_param user root
#For HTTP Proxy
procd_set_param command "$PROG" -device "$IF" -proxy http://"$HOST":"$PORT"
# For SSH SOCKS Proxy
#procd_set_param command "$PROG" -device "$IF" -proxy "$HOST":"$PORT"
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
procd_close_instance
#ip route save default > /tmp/defroute.save #Saves existing default route
#ip route del default #Deletes existing default route
echo "tun2socks is working!"
}
#ip route add default via 172.16.11.2 dev "$IF" #Creates default route through the proxy
stop_service() {
service_stop $PROG
#ip route restore default < /tmp/defroute.save #Restores saved default route
echo "tun2socks has stopped!"
}
reload_service() {
stop
sleep 5s
echo "tun2socks restarted!"
start
}
Где IF - интерфейс, в данном примере tun3 (вместо tun0) чтобы избежать конфликтов с существующими туннелями.
PORT - Порт туннеля DNSTT-Клиента (по умолчанию 7000).
Если требуется перенаправлять весь трафик в DNSTT (чего делать не рекомендую, т.к. DNSTT всё же сильно режет скорость), уберите # перед строками 22, 23 и 26 и 29. Перед этим убедитесь что указали статический маршрут до сервера DNSTT через шлюз по умолчанию (подробнее здесь).
Для правильной работы скрипта (сохранение и восстановление маршрута по умолчанию) потребуется установить пакет ip-full
opkg install ip-full
Делаем файл исполняемым:
chmod +x /etc/init.d/tun2socks
Делаем автозапуск:
ln -s /etc/init.d/tun2socks /etc/rc.d/S99tun2socks
Запускаем:
/etc/init.d/tun2socks start
Проверяем, что интерфейс заработал:
ip a | grep 'tun3'
Если заработал, выдаст подобный результат:
tun3: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
inet 172.16.11.1/30 brd 172.16.11.3 scope global tun3
Если нет, ответ будет пустым.
Далее необходимо настроить маршруты к которым роутер будет обращаться через прокси.
Можно настроить маршрут по умолчанию для всего трафика (убрать # перед строками, не рекомендую), либо настроить точечный обход блокировок (в конце статьи)
Если настроен маршрут по умолчанию, проверяем работоспособность:
wget -qO- http://ipecho.net/plain | xargs echo
Команда вернёт IP адрес сервера DNSTT.
Для точечного обхода блокировок и настройки таких маршрутов:
Точечный обход блокировок на роутере OpenWrt c помощью BGP / Хабр (habr.com) С помощью BGP (bird2).
Точечный обход блокировок PKH на роутере с OpenWrt с помощью WireGuard и DNSCrypt / Хабр (habr.com) (путём скачивания списков и настройкой маршрутов в iptables, nftables).
По клиентам для других платформ всё не очень разнообразно:
есть консольные утилиты для Linux, Windows, MacOS (Darwin)
Для Android плагин к TLS Tunnel TLS Tunnel DNSTT Plugin - Apps on Google Play (программа позволяет подключатся к собственным серверам, но требуется дополнительная настройка)
для iOS клиентов не нашёл