dnstt — DNS-туннель для TCP-трафика. Трафик кодируется внутри DNS-запросов и ответов, проходя через публичный рекурсивный резолвер. Это позволяет обходить блокировки, не требуя собственного VPN-протокола или специального порта.
Форк оригинального dnstt (David Fifield), расширенный новыми транспортами, встроенным SOCKS5-прокси, аутентификацией, rate-limiting, TLS-маскировкой и операционным инструментарием.
┌──────────┐ ┌──────────────┐ ┌──────────┐
│ Client │◄─DoH/DoT──►│ Recursive │◄──UDP 53──►│ Server │
│ (you) │ /DoQ/UDP │ Resolver │ │ (yours) │
└────┬─────┘ └──────────────┘ └─────┬────┘
│ TCP :7000 │ TCP
┌────┴─────┐ ┌─────┴────┐
│ Your │ │ Upstream │
│ App │ │ Service │
└──────────┘ └──────────┘
Трафик вашего приложения → TCP → dnstt-client → DNS-запросы → резолвер → dnstt-server → TCP → целевой сервис.
- Как это работает
- Стек технологий
- DNS-зона: предварительная настройка
- Сборка и запуск — сервер
- Сборка и запуск — клиент
- Развёртывание через Docker
- Все флаги сервера
- Все флаги клиента
- Файл конфигурации
- Шифрование и аутентификация
- Примеры использования
DNS-туннель эксплуатирует свойство DNS: большинство сетей разрешают исходящие DNS-запросы, в том числе через DoH/DoT (порт 443/853), чтобы обеспечить базовое разрешение имён.
Клиент кодирует TCP-данные в поддомены зоны, делегированной серверу
(<payload>.t.example.com), и шлёт их запросами типа TXT. Ответ сервера
несёт данные в обратном направлении в TXT-записях.
Сервер запущен как авторитативный NS для выбранного поддомена, принимает UDP-запросы от рекурсивного резолвера, декодирует данные и форвардирует потоки TCP к целевому сервису.
Стек поверх DNS:
Ваше приложение (TCP)
↕
smux v2 — мультиплексирование нескольких потоков в одном сеансе
↕
Noise_NK — E2E-шифрование и аутентификация сервера
↕
KCP — надёжная доставка поверх UDP-подобного канала
↕
DNS-сообщения (TXT/AAAA)
↕
DoH / DoT / DoQ / UDP
| Компонент | Библиотека | Назначение |
|---|---|---|
| KCP | github.com/xtaci/kcp-go/v5 |
Надёжная упорядоченная доставка поверх пакетного DNS-канала. Аналог TCP поверх UDP. Управляет повторными передачами, окном, перегрузкой |
| smux | github.com/xtaci/smux |
Мультиплексор потоков (v2). Несколько TCP-соединений клиента объединяются в один KCP-сеанс, экономя handshake-overhead |
| Noise_NK | github.com/flynn/noise |
Протокол Noise, паттерн NK: сервер аутентифицирован публичным ключом, клиент анонимен. Шифр: ChaChaPoly. Хэш: BLAKE2s. DH: X25519 |
| DNS over QUIC | github.com/quic-go/quic-go |
RFC 9250. Каждый запрос — отдельный QUIC-стрим; 0-RTT там, где возможно |
| DNS over TLS | стандартная библиотека + uTLS | RFC 7858. Пайплайнинг: 8 одновременных отправителей на соединение |
| DNS over HTTPS | net/http + uTLS |
RFC 8484. POST application/dns-message. Retry-After поддерживается |
| uTLS | github.com/refraction-networking/utls |
Камуфляж TLS-fingerprint под браузер (Firefox, Chrome, iOS…), чтобы DoT/DoH-трафик не отличался от обычного браузерного |
| FEC | github.com/klauspost/reedsolomon (через kcp-go) |
Reed-Solomon Forward Error Correction для восстановления потерянных пакетов без ретрансмиссии |
| YAML-конфиг | gopkg.in/yaml.v3 |
Конфигурационный файл сервера |
| Криптография | golang.org/x/crypto |
X25519 DH, ChaCha20-Poly1305, BLAKE2s |
| Сжатие | compress/zlib (stdlib) |
Опциональное сжатие потоков. Враппер zlibFlushWriter принудительно делает Flush() после каждой записи — без этого интерактивные сессии (SSH) зависали бы |
| Метрики | expvar (stdlib) |
Счётчики запросов, сессий, dropped-пакетов на /debug/vars |
| Профилировщик | net/http/pprof (stdlib) |
CPU/heap/goroutine профили на /debug/pprof |
| Логирование | log/slog (stdlib, Go 1.21+) |
Структурированные логи с фильтрацией по уровню и UTC-временем |
| SOCKS5 | собственная реализация | RFC 1928. Только CONNECT без аутентификации |
Сервер должен быть авторитативным NS для выбранного поддомена.
Пусть ваш домен — example.com, IP сервера — 203.0.113.2.
Добавьте в DNS вашего домена:
; Глейу-запись для NS-сервера
tns.example.com. A 203.0.113.2
tns.example.com. AAAA 2001:db8::2 ; если есть IPv6
; Делегирование зоны туннеля
t.example.com. NS tns.example.com.
Проверка (после распространения записей):
dig NS t.example.com
# ожидаем: tns.example.com
dig TXT anything.t.example.com @203.0.113.2
# если сервер уже запущен — ответитВажно: держите метку зоны (
t) короткой. DNS-имена ограничены 255 байтами; чем длиннее домен, тем меньше полезной нагрузки в каждом запросе.
- Go 1.24 или новее
- Права на порт UDP 53 (либо iptables REDIRECT с непривилегированного порта)
git clone https://github.com/IvanTopGaming/dnstt
cd dnstt
# Сборка сервера
go build -o dnstt-server ./dnstt-server
# Сборка клиента
go build -o dnstt-client ./dnstt-clientИли оба сразу:
go build ./...
# бинарники появятся в dnstt-server/ и dnstt-client/./dnstt-server/dnstt-server -gen-key \
-privkey-file server.key \
-pubkey-file server.pub
# Или без файлов — ключи выводятся в stdout
./dnstt-server/dnstt-server -gen-key
# privkey 0123456789abcdef0123...
# pubkey fedcba9876543210fedc...server.key (приватный) — только на сервере, режим 0400.
server.pub (публичный) — передать клиентам, не секрет.
./dnstt-server/dnstt-server \
-udp :53 \
-privkey-file server.key \
-socks5 \
t.example.comВ этом режиме клиент сам указывает куда подключаться (через SOCKS5-запрос). Отдельный прокси-сервис не нужен.
# Форвардинг к SSH
./dnstt-server/dnstt-server \
-udp :53 \
-privkey-file server.key \
t.example.com 127.0.0.1:22
# Форвардинг к HTTP-прокси
./dnstt-server/dnstt-server \
-udp :53 \
-privkey-file server.key \
t.example.com 127.0.0.1:3128# Запуск на непривилегированном порту
./dnstt-server/dnstt-server -udp :5353 -privkey-file server.key -socks5 t.example.com
# Перенаправление порта 53 → 5353
sudo iptables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5353
sudo ip6tables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5353Создайте /etc/systemd/system/dnstt-server.service:
[Unit]
Description=dnstt DNS tunnel server
After=network.target
[Service]
ExecStart=/usr/local/bin/dnstt-server \
-udp :53 \
-privkey-file /etc/dnstt/server.key \
-socks5 \
-log-level info \
t.example.com
Restart=on-failure
RestartSec=5
User=nobody
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
[Install]
WantedBy=multi-user.targetsudo systemctl enable --now dnstt-server
sudo journalctl -u dnstt-server -fgo build -o dnstt-client ./dnstt-client| Транспорт | Флаг | Скрытность | Скорость | Когда использовать |
|---|---|---|---|---|
| DNS over QUIC | -doq resolver:853 |
Высокая | Высокая | Современные резолверы, QUIC не заблокирован |
| DNS over TLS | -dot resolver:853 |
Высокая | Средняя | Универсальный выбор |
| DNS over HTTPS | -doh https://…/dns-query |
Высокая | Средняя | Через HTTP-прокси, порт 443 |
| UDP | -udp resolver:53 |
Нет | Средняя | Только для отладки |
| Авто | -auto + адреса |
— | — | Пробует DoQ→DoT→DoH→UDP |
| Мультипуть | -multipath |
Высокая | Высокая | Одновременно несколько транспортов |
Публичные резолверы:
- Cloudflare:
1.1.1.1:853(DoT/DoQ),https://1.1.1.1/dns-query(DoH) - Google:
8.8.8.8:853(DoT),https://dns.google/dns-query(DoH) - Quad9:
9.9.9.9:853(DoT/DoQ),https://dns.quad9.net/dns-query(DoH)
# DNS over QUIC
./dnstt-client -doq 1.1.1.1:853 \
-pubkey-file server.pub \
t.example.com 127.0.0.1:7000
# DNS over TLS
./dnstt-client -dot 1.1.1.1:853 \
-pubkey-file server.pub \
t.example.com 127.0.0.1:7000
# DNS over HTTPS
./dnstt-client -doh https://1.1.1.1/dns-query \
-pubkey-file server.pub \
t.example.com 127.0.0.1:7000
# Авто — пробует DoQ, затем DoT, затем DoH
./dnstt-client -auto \
-doq 1.1.1.1:853 \
-dot 1.1.1.1:853 \
-doh https://1.1.1.1/dns-query \
-pubkey-file server.pub \
t.example.com 127.0.0.1:7000После запуска клиент слушает TCP на 127.0.0.1:7000. Настройте своё
приложение на этот адрес как SOCKS5-прокси (если сервер в -socks5 режиме)
или как обычный TCP-форвард.
# Проверка: HTTP через SOCKS5
curl --proxy socks5h://127.0.0.1:7000/ https://example.com/
# Проверка: SSH через форвард
ssh -p 7000 user@127.0.0.1- Docker Engine 24+ и Docker Compose v2
- Порт UDP 53 свободен на хосте
Шаг 1. Создайте файл .env с именем вашей зоны:
echo "DNSTT_DOMAIN=t.example.com" > .envШаг 2. Сгенерируйте ключи (записываются в ./keys/):
docker compose run --rm keygenПроверьте:
ls -la keys/
# server.key (0400) server.pubШаг 3. Запустите сервер:
docker compose up -d
docker compose logs -fШаг 4. Скопируйте keys/server.pub на клиентские машины.
# Этап 1: сборка
FROM golang:1.24-alpine AS builder
# компилирует dnstt-server с CGO_ENABLED=0 и -trimpath
# Этап 2: итоговый образ
FROM scratch AS server
# только бинарник, без ОС, без shell, без пакетного менеджера
# пользователь: nobody (uid 65534)
# возможности: только NET_BIND_SERVICE (привязка порта 53)Итоговый образ весит ~7 МБ.
По умолчанию сервер запускается в режиме -socks5.
Чтобы форвардировать к конкретному сервису, отредактируйте command::
# docker-compose.yml
services:
dnstt-server:
build:
context: .
target: server
restart: unless-stopped
ports:
- "53:53/udp"
volumes:
- ./keys:/keys:ro
user: "65534:65534"
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
command:
- -udp
- ":53"
- -privkey-file
- /keys/server.key
# Режим SOCKS5 (клиент выбирает куда подключаться):
- -socks5
- "${DNSTT_DOMAIN}"
# Или форвардинг к конкретному адресу (убрать -socks5):
# - 127.0.0.1:8000Добавьте нужные флаги в command: — каждый флаг и его значение
как отдельная строка YAML:
command:
- -udp
- ":53"
- -privkey-file
- /keys/server.key
- -socks5
- -rate-limit
- "20"
- -rate-burst
- "100"
- -log-level
- debug
- -paranoia
- "${DNSTT_DOMAIN}"# Запустить в фоне
docker compose up -d
# Посмотреть логи
docker compose logs -f dnstt-server
# Перегенерировать ключи (осторожно: клиенты нужно перенастроить)
docker compose run --rm keygen
# Остановить
docker compose down
# Пересобрать образ после изменений кода
docker compose build --no-cache
docker compose up -d# Собрать образ
docker build --target server -t dnstt-server:latest .
# Запустить
docker run -d \
--name dnstt \
-p 53:53/udp \
-v $(pwd)/keys:/keys:ro \
--user 65534:65534 \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
dnstt-server:latest \
-udp :53 \
-privkey-file /keys/server.key \
-socks5 \
t.example.comdnstt-server -gen-key [-privkey-file FILE] [-pubkey-file FILE]
| Флаг | Описание |
|---|---|
-gen-key |
Сгенерировать пару ключей и выйти. Без -privkey-file/-pubkey-file выводит hex-строки в stdout |
-privkey-file FILE |
С -gen-key: сохранить приватный ключ в файл (режим 0400). В рабочем режиме: прочитать ключ из файла |
-pubkey-file FILE |
С -gen-key: сохранить публичный ключ в файл. В рабочем режиме не используется |
dnstt-server -udp ADDR [-privkey-file FILE | -privkey HEX] [OPTIONS] DOMAIN [UPSTREAM]
| Флаг | Описание |
|---|---|
-udp ADDR |
UDP-адрес для приёма DNS-запросов. Обычно :53. Без этого флага сервер не запустится |
DOMAIN |
Корень DNS-зоны туннеля (t.example.com). Позиционный аргумент |
UPSTREAM |
TCP-адрес для форвардинга потоков (127.0.0.1:8000). Позиционный аргумент. Не используется с -socks5 |
| Флаг | Описание |
|---|---|
-privkey HEX |
Приватный ключ как строка из 64 hex-символов |
-privkey-file FILE |
Читать приватный ключ из файла. Если ни -privkey, ни -privkey-file не заданы, сервер генерирует временный ключ и логирует публичный |
| Флаг | По умолчанию | Описание |
|---|---|---|
-socks5 |
false |
Встроенный SOCKS5-прокси. Каждый поток выполняет SOCKS5-handshake, сервер подключается к адресу, указанному клиентом. При использовании UPSTREAM не нужен |
-mtu N |
1232 |
Максимальный размер UDP-ответа в байтах. Уменьшайте, если резолвер жалуется: FORMERR: requester payload size 512 is too small |
-paranoia |
false |
Возвращать правдоподобные поддельные A/AAAA-ответы на нетуннельные запросы, скрывая факт наличия туннеля от пассивного наблюдателя |
| Флаг | По умолчанию | Описание |
|---|---|---|
-auth-keys FILE |
— | Файл авторизованных токенов: по одному 64-символьному hex-токену на строку. Клиент должен предъявить совпадающий токен (-auth-token) после Noise-handshake. Если флаг не задан — все клиенты принимаются |
| Флаг | По умолчанию | Описание |
|---|---|---|
-kcp-mode MODE |
normal |
Режим KCP: fast (низкая задержка, больше трафика), normal (баланс), slow (экономия полосы) |
-fec-data N |
0 |
Количество шардов данных для Reed-Solomon FEC. 0 — отключено. Требует согласования с клиентом |
-fec-parity N |
0 |
Количество шардов чётности FEC. При N data и M parity — теряемо до M пакетов из каждого блока |
-compress |
false |
Сжимать данные потоков (zlib). Должно совпадать с клиентом |
-rate-limit RATE |
0 |
Максимум DNS-запросов в секунду на клиента (token bucket). 0 — без ограничений |
-rate-burst N |
50 |
Размер всплеска для -rate-limit. Позволяет кратковременно превышать лимит |
| Флаг | По умолчанию | Описание |
|---|---|---|
-config FILE |
— | Загрузить значения флагов из YAML-файла до разбора аргументов командной строки. CLI-флаги перекрывают файл |
-debug-addr ADDR |
— | HTTP-сервер с /debug/vars (счётчики) и /debug/pprof (профили). Не открывать публично |
-log-level LEVEL |
info |
Минимальный уровень логирования: debug, info, warn, error |
dnstt-client [-doh URL|-dot ADDR|-doq ADDR|-udp ADDR|-auto] \
-pubkey-file FILE \
[OPTIONS] \
DOMAIN LOCALADDR
| Флаг | Позиционный аргумент |
|---|---|
DOMAIN |
DNS-зона туннеля (t.example.com) |
LOCALADDR |
TCP-адрес для прослушивания локальных подключений (127.0.0.1:7000) |
| Флаг | Описание |
|---|---|
-doh URL |
DNS over HTTPS. URL резолвера с путём (https://1.1.1.1/dns-query) |
-doh-addr ADDR:PORT |
Переопределить адрес для dial в DoH. SNI берётся из URL. Полезно при cert-pinning или когда DNS недоступен |
-dot ADDR:PORT |
DNS over TLS (RFC 7858). Стандартный порт 853 |
-doq ADDR:PORT |
DNS over QUIC (RFC 9250). Стандартный порт 853 |
-udp ADDR:PORT |
Обычный DNS over UDP. Только для отладки — нет скрытности |
-auto |
Автовыбор: пробует DoQ→DoT→DoH→UDP, использует первый работающий. Требует хотя бы одного из флагов выше |
-multipath |
Отправлять данные через все указанные транспорты одновременно (DoH+DoT+UDP). Повышает надёжность и пропускную способность. DoQ не поддерживается в мультипуть-режиме. Требует минимум два транспорта |
| Флаг | Описание |
|---|---|
-pubkey HEX |
Публичный ключ сервера как 64 hex-символа |
-pubkey-file FILE |
Читать публичный ключ из файла |
| Флаг | По умолчанию | Описание |
|---|---|---|
-utls SPEC |
4*random,3*Firefox_120,... |
Выбрать TLS-fingerprint из взвешенного распределения. Маскирует DoH/DoT-подключения под браузерный трафик. none — отключить uTLS. random — случайный fingerprint каждый раз. Формат: 3*Firefox,2*Chrome,1*iOS |
-pin-cert PINS |
— | Comma-separated SHA256-пины сертификатов (SHA256:aabbcc…). Принимать только сертификаты с совпадающим fingerprint. Применяется к DoT/DoH/DoQ |
-obfuscate |
false |
Вставлять случайные AAAA/A-запросы (~20%) между туннельными TXT-запросами. Делает паттерн трафика менее характерным |
-rotate-id N |
0 |
Обновлять ClientID каждые N минут. Меняет идентификатор туннельного сеанса, затрудняя долгосрочную корреляцию. 0 — отключено |
-auth-token HEX |
— | 64-символьный hex-токен для аутентификации на сервере. Должен совпадать с одной из записей в серверном -auth-keys |
| Флаг | По умолчанию | Описание |
|---|---|---|
-kcp-mode MODE |
normal |
Режим KCP: fast, normal, slow. Должен совпадать с сервером |
-fec-data N |
0 |
FEC data shards. 0 — отключено |
-fec-parity N |
0 |
FEC parity shards |
-compress |
false |
Сжатие потоков (zlib). Должно совпадать с сервером |
| Флаг | По умолчанию | Описание |
|---|---|---|
-config FILE |
— | Загрузить флаги из файла key = value до разбора аргументов |
-debug-addr ADDR |
— | HTTP-сервер с /debug/vars и /debug/pprof |
-log-level LEVEL |
info |
debug, info, warn, error |
Флаг -config FILE указывает YAML-файл. CLI-флаги всегда перекрывают файл.
Полный пример server.yaml:
# server.yaml — конфигурация dnstt-server
# Сеть
udp: ":53" # UDP-адрес для DNS-запросов
mtu: 1232 # максимальный размер UDP-ответа
# Ключ (один из двух вариантов)
privkey-file: /etc/dnstt/server.key
# privkey: "0123456789abcdef..." # или напрямую hex-строка
# Режим работы
socks5: true # встроенный SOCKS5-прокси
# Если socks5: false — DOMAIN и UPSTREAM передаются позиционно в CLI
# Безопасность
paranoia: false # поддельные ответы для нетуннельных запросов
auth-keys: /etc/dnstt/tokens.txt # файл авторизованных токенов
# Rate limiting
rate-limit: 20.0 # запросов/сек на клиента (0 = без ограничений)
rate-burst: 100 # всплеск
# Производительность
kcp-mode: normal # fast | normal | slow
fec-data: 0 # Reed-Solomon data shards (0 = выключено)
fec-parity: 0 # Reed-Solomon parity shards
compress: false # zlib-сжатие потоков
# Операционные
debug-addr: "" # "127.0.0.1:6060" для включения
log-level: info # debug | info | warn | errorЗапуск с файлом:
./dnstt-server -config server.yaml t.example.comМинимальный файл (SOCKS5-режим):
udp: ":53"
privkey-file: /etc/dnstt/server.key
socks5: true
log-level: infoФлаг -config FILE указывает файл формата ключ = значение, по одному на строку.
Комментарии начинаются с #.
Полный пример client.conf:
# client.conf — конфигурация dnstt-client
# Транспорт (один из: doh, dot, doq, udp; или auto=true с несколькими)
dot = 1.1.1.1:853
# doh = https://1.1.1.1/dns-query
# doh-addr = 1.1.1.1:443 # переопределить IP для DoH
# doq = 1.1.1.1:853
# udp = 1.1.1.1:53
# auto = true # попробовать все по порядку
# multipath = true # все транспорты одновременно
# Ключ сервера
pubkey-file = /etc/dnstt/server.pub
# pubkey = fedcba9876543210... # или hex-строка
# Аутентификация
# auth-token = aabbcc...64hexchars... # если сервер требует токен
# TLS-маскировка (для DoT/DoH)
utls = 4*random,3*Firefox_120,1*Chrome_120 # по умолчанию
# Безопасность
# pin-cert = SHA256:aabbccddeeff... # пин сертификата резолвера
obfuscate = true # случайные AAAA/A-запросы-приманки
rotate-id = 30 # обновлять ClientID каждые 30 минут
# Производительность
kcp-mode = normal # fast | normal | slow
# fec-data = 4
# fec-parity = 2
# compress = false
# Операционные
log-level = info
# debug-addr = 127.0.0.1:6060Запуск с файлом:
./dnstt-client -config client.conf t.example.com 127.0.0.1:7000Файл для -auth-keys содержит по одному токену на строку.
Пустые строки и строки начинающиеся с # игнорируются.
Генерация токенов:
# Linux/macOS
openssl rand -hex 32
# или через Go
python3 -c "import secrets; print(secrets.token_hex(32))"Пример tokens.txt:
# Авторизованные клиенты dnstt
# Формат: 64 hex-символа (32 байта)
a3f1c2e4d5b6a7f8e9d0c1b2a3f4e5d6c7b8a9f0e1d2c3b4a5f6e7d8c9b0a1f2
deadbeef0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d
Клиент использует токен:
./dnstt-client -auth-token a3f1c2e4d5b6a7f8... \
-dot 1.1.1.1:853 -pubkey-file server.pub \
t.example.com 127.0.0.1:7000Туннель использует криптографический протокол Noise, паттерн NK:
- N — клиент анонимен (ephemeral-only)
- K — сервер аутентифицирован заранее известным публичным ключом
| Примитив | Алгоритм | Назначение |
|---|---|---|
| DH | X25519 | Обмен ключами Диффи–Хеллмана |
| Шифр | ChaCha20-Poly1305 (AEAD) | Шифрование и целостность данных |
| Хэш | BLAKE2s | Вывод ключей, MAC |
Это означает:
- Содержимое туннеля зашифровано и защищено от подмены end-to-end
- Сервер аутентифицирован: клиент проверяет, что подключается к серверу с правильным ключом, а не к MitM
- Клиент анонимен: сервер не знает, кто именно подключается
(если не используется
-auth-keys) - Шифрование независимо от DoH/DoT/DoQ: даже если транспортный уровень скомпрометирован, содержимое туннеля остаётся защищённым
# Сгенерировать и сохранить в файлы
./dnstt-server -gen-key -privkey-file server.key -pubkey-file server.pub
# Только вывод в stdout (для ручного распределения)
./dnstt-server -gen-key
# privkey 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
# pubkey fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210
# Использовать ключ напрямую (без файла)
./dnstt-server -privkey 0123...abcdef t.example.com 127.0.0.1:8000
./dnstt-client -pubkey fedcba...3210 -dot 1.1.1.1:853 t.example.com 127.0.0.1:7000Если сервер запускается без ключа, он автоматически генерирует временный и логирует публичный ключ. Клиентов нужно перенастраивать при каждом перезапуске.
# Сервер: форвардинг к SSH
./dnstt-server -udp :53 -privkey-file server.key t.example.com 127.0.0.1:22
# Клиент: поднять туннель
./dnstt-client -dot 1.1.1.1:853 -pubkey-file server.pub t.example.com 127.0.0.1:7000
# Подключиться по SSH через туннель
ssh -p 7000 user@127.0.0.1# Сервер
./dnstt-server -udp :53 -privkey-file server.key -socks5 t.example.com
# Клиент
./dnstt-client -dot 1.1.1.1:853 -pubkey-file server.pub t.example.com 127.0.0.1:7000
# Использование
curl --proxy socks5h://127.0.0.1:7000/ https://ifconfig.me/
# В браузере: прокси SOCKS5 → 127.0.0.1:7000# Клиент с максимальной маскировкой
./dnstt-client \
-auto \
-doq 1.1.1.1:853 \
-dot 1.1.1.1:853 \
-doh https://1.1.1.1/dns-query \
-utls '3*Firefox_120,2*Chrome_120,1*iOS_14' \
-obfuscate \
-rotate-id 15 \
-pin-cert SHA256:$(openssl s_client -connect 1.1.1.1:853 </dev/null 2>/dev/null | \
openssl x509 -fingerprint -sha256 -noout | cut -d= -f2 | tr -d ':') \
-pubkey-file server.pub \
t.example.com 127.0.0.1:7000# Генерация токена
TOKEN=$(openssl rand -hex 32)
echo $TOKEN >> /etc/dnstt/tokens.txt
# Сервер с аутентификацией
./dnstt-server -udp :53 -privkey-file server.key \
-auth-keys /etc/dnstt/tokens.txt \
-socks5 t.example.com
# Клиент с токеном
./dnstt-client -dot 1.1.1.1:853 \
-auth-token $TOKEN \
-pubkey-file server.pub \
t.example.com 127.0.0.1:7000# Сервер с FEC
./dnstt-server -udp :53 -privkey-file server.key \
-fec-data 4 -fec-parity 2 \
-kcp-mode fast \
-socks5 t.example.com
# Клиент с мультипутём и FEC
./dnstt-client \
-multipath \
-doh https://1.1.1.1/dns-query \
-dot 1.1.1.1:853 \
-fec-data 4 -fec-parity 2 \
-kcp-mode fast \
-pubkey-file server.pub \
t.example.com 127.0.0.1:7000При запуске оба бинарника логируют effective MTU N — полезная нагрузка
в байтах на один DNS-запрос/ответ. Чем короче домен, тем больше MTU.
Типичные значения:
- Клиент (запросы): 100–200 байт на запрос
- Сервер (ответы): 900–1100 байт на ответ
# Запустить с debug-сервером
./dnstt-server -debug-addr 127.0.0.1:6060 ...
# Счётчики (запросы, сессии, dropped-пакеты)
curl http://127.0.0.1:6060/debug/vars | jq .
# CPU-профиль (30 секунд)
go tool pprof http://127.0.0.1:6060/debug/pprof/profile?seconds=30
# Горутины
curl http://127.0.0.1:6060/debug/pprof/goroutine?debug=1./dnstt-server -log-level debug ...
./dnstt-client -log-level debug ...Оригинальный проект: dnstt by David Fifield — public domain.
Данный форк добавляет DoQ, SOCKS5, rate limiting, аутентификацию, обфускацию, cert pinning, ClientID rotation, пайплайнинг, FEC, мультипуть, Docker-поддержку и исправляет ряд багов. Все дополнения также выпускаются в public domain.