26 KiB
uTun — Руководство пользователя
uTun — децентрализованная VPN-система с шифрованием, надёжной доставкой данных, поддержкой mesh-сетей и встроенным TCP-прокси. Работает поверх UDP (основной транспорт) и TCP (STCP-резерв). Всё шифруется через X25519 + AES-128-CCM. Топология узлов обменивается автоматически (BGP-подобный протокол).
1. Быстрый старт
1.1. Сборка
git clone <репозиторий> && cd utun3
./build.sh --full -j4 # autoreconf + configure + make
Зависимости: gcc, make, autotools (autoconf/automake/libtool), OpenSSL (libssl-dev).
1.2. Генерация ключей
Ключи генерируются автоматически, если их нет в конфиге. Достаточно указать my_node_name — config_updater создаст пару X25519 и node_id:
[global]
my_node_name=my-first-node
После первого запуска ключи пропишутся в конфиг автоматически.
1.3. Первый запуск
sudo ./src/utun -f -c myconfig.conf
-f— foreground (без демонизации, видно логи в консоли)-c myconfig.conf— путь к конфигу-p /var/run/utun.pid— PID-файл-l /var/log/utun.log— лог-файл
Без -f процесс уходит в демон (fork + setsid).
1.4. Проверка работы
ip addr show tun3 # TUN-интерфейс создан?
ping 10.23.1.1 # пингуем TUN-IP узла
ss -uln | grep 1333 # UDP-сокет слушает?
2. Архитектура (кратко)
uTun — однопоточная асинхронная система. Один event loop (epoll/poll) на поток. Никаких sleep(), никакого блокирующего I/O.
Стек протоколов (5 уровней):
| Уровень | Назначение |
|---|---|
| 1. UDP/TUN/STCP | Физический транспорт: UDP-сокеты, TUN-интерфейс, TCP-резерв |
| 2. secure_channel | X25519 ECDH + AES-128-CCM шифрование + Ed25519 подписи |
| 3. ETCP | Надёжный транспорт (inflight, ACK, ретрансмиссии, BBR congestion control) |
| 4. LoadBalancer | Multi-link балансировка (min inflight + round-robin) |
| 5. etcp_router | Сервисная маршрутизация (seq, dedup, reorder, transit forwarding) |
Два уровня надёжности:
- ETCP — per-connection, RTT-based ретрансмиссии
- etcp_router — per-service, 300ms ретрансмиссии с 17 попытками (~5 сек)
Node identity: SHA256(private_key) → первые 8 байт → 63-bit node_id.
3. Конфигурация
Формат: INI-style. Секции [section], строки key=value, комментарии #.
3.1. [global] — Идентичность и базовые настройки
[global]
my_node_name=home-server # имя узла (человекочитаемое)
my_node_id=5f75c7445af88e1f # ID узла (авто-генерируется)
my_private_key=d065b784...4fe441 # X25519 приватный ключ (hex, 64 символа)
my_public_key=86b51a8b...6a2d19 # X25519 публичный ключ (hex, 64 символа)
tun_enabled=yes # создавать TUN-интерфейс (по умолчанию yes)
tun_ifname=tun3 # имя TUN (по умолчанию tun0)
tun_ip=10.23.1.1 # IP на TUN-интерфейсе
mtu=1500 # MTU для всех соединений
debug_level=error # глобальный уровень отладки (none/error/warn/info/debug/trace)
log_file=/var/log/utun.log # путь к лог-файлу
3.2. [server:NAME] — Локальные UDP-сокеты
[server: lan1]
addr=192.168.1.10:1333 # IP:порт для приёма входящих
type=public # public / nat / private / local
transport=udp # udp (по умолчанию) или tcp (STCP)
mtu=1400 # MTU для этого канала
so_mark=100 # SO_MARK для policy routing
netif=eth0 # привязка к интерфейсу
only_local=0 # 1 = только локальные подключения
Типы адресов:
public— узел на публичном IP (прямая связь)nat— узел за NAT (нужен NAT traversal)private— локальная сеть (только соседи в том же сегменте)local— только loopback/локальные подключения
3.3. [client:NAME] — Подключение к удалённым узлам
[client: aeza]
link=lan1:85.192.42.96:1333 # server_name:ip:port (можно несколько link=)
link=lan1:85.192.42.96:1433 # второй канал к тому же узлу
peer_public_key=0206dbee...fbcc16 # публичный ключ удалённого узла
keepalive=1 # интервал keepalive (сек)
Формат link: локальный_сервер:удалённый_ip:удалённый_порт. Серверная секция должна быть объявлена выше по файлу.
3.4. [routing] — Маршруты
[routing]
my_subnet=10.23.1.0/24 # своя подсеть — анонсируется соседям через BGP
route_subnet=10.23.0.0/16 # добавляется в системную таблицу маршрутов через TUN
route_subnet=fd00:1234::/32 # IPv6-подсеть
3.5. [debug] — Настройка отладки
Формат: категория=уровень. Уровни: none, error, warn, info, debug, trace.
[debug]
etcp=trace # всё про ETCP
crypto=info # криптографические операции
bgp=info # обмен топологией
connection=info # сокеты и линки
general=info # общая информация
Основные категории (всего 26): uasync, ll_queue, connection, etcp, crypto, memory, timing, config, tun, routing, timers, normalizer, bgp, socket, control, dump, traffic, debug, general, nat, keepalive, etcпroute, bbr, etcp_dump.
3.6. [firewall] — Правила фильтрации
[firewall]
allow=all # разрешить всё (bypass)
allow=192.168.1.0/24 # разрешить подсеть
allow=10.0.0.1:80 # разрешить конкретный IP:порт
3.7. [nat] — EIM NAT
[nat]
nat_enabled=yes
nat_tun_ifname=tun_external # внешний TUN (выход в интернет)
nat_via=gateway_ip # шлюз
port_start=10000
port_end=20000
forward=tcp:10.0.0.5:80:8080 # проброс: протокол:ip:внутр_порт:внеш_порт
3.8. [tcp_proxy_client] / [tcp_proxy_server] — TCP-прокси
Клиент (выход через exit-узел):
[tcp_proxy_client]
enabled=yes
tun_name=tun_proxy # имя TUN для прокси-трафика
tun_ip=10.200.30.1 # IP клиентского TUN
via_node=50e9e88658e91977 # node_id exit-узла
socks_enabled=yes # встроенный SOCKS5-прокси
socks_addr=127.0.0.1:1082 # слушать SOCKS5 здесь
http_proxy_enabled=yes # встроенный HTTP CONNECT-прокси
http_proxy_addr=127.0.0.1:8080
Exit-узел (сервер):
[tcp_proxy_server]
enabled=yes
Клиент настраивает браузер на SOCKS5 127.0.0.1:1082 — весь TCP-трафик идёт через exit-узел.
3.9. [control] — Сервер мониторинга
[control]
control_ip=192.168.29.117 # IP для приёма подключений etcpmon
control_port=9090
control_allow=192.168.0.0/16 # разрешённые подсети (можно несколько)
3.10. [allowed_keys] — Ограничение подключений
[allowed_keys]
allow_all=1 # разрешить все ключи
# key=86b51a8b...6a2d19 # разрешить конкретный pubkey
3.11. [ntp] — Синхронизация времени
[ntp]
enabled=yes
server=pool.ntp.org
server=time.google.com
interval=3600 # интервал синхронизации (сек)
3.12. [network:NAME] — Именованные сети
[network: mynet]
id=5f75c7445af88e1f # 56-bit ID сети
pubkey=86b51a8b...6a2d19 # публичный ключ сети
signing_key=d065b784...4fe441 # ключ подписи (Ed25519)
3.13. Серверный vs клиентский конфиг
| Параметр | Сервер | Клиент |
|---|---|---|
[server] секция |
Обязательна (свои сокеты) | Обязательна (свои сокеты) |
[client] секция |
Нет | Обязательна (к кому подключаться) |
peer_public_key |
Нет | Обязателен в [client] |
my_private_key |
Свой | Свой |
my_public_key |
Свой | Свой |
Важно: [server] обязателен в обоих случаях — это рабочий сокет узла. Клиент дополнительно указывает [client] с peer_public_key и link.
4. Сценарии использования
4.1. VPN между двумя узлами
Сервер (публичный IP 85.192.42.96):
[global]
my_node_name=server
my_private_key=<hex>
my_public_key=<hex>
tun_ip=10.23.1.1
[server: main]
addr=85.192.42.96:1333
type=public
[routing]
my_subnet=10.23.1.0/24
Клиент (за NAT, подключается к серверу):
[global]
my_node_name=client
my_private_key=<hex>
my_public_key=<hex>
tun_ip=10.23.2.1
[server: uplink]
addr=0.0.0.0:1333 # можно 0.0.0.0 — клиенту не нужен фиксированный порт
type=nat
[client: server]
link=uplink:85.192.42.96:1333
peer_public_key=<pubkey_сервера>
keepalive=1
[routing]
my_subnet=10.23.2.0/24
Проверка связности:
# На сервере
ping 10.23.2.1
# На клиенте
ping 10.23.1.1
4.2. Mesh-сеть из нескольких узлов
Каждый узел = сервер (свои сокеты) + клиент (подключения к соседям). Пример для узла B, который подключается к A и C:
[global]
my_node_name=node-b
my_private_key=<hex>
my_public_key=<hex>
tun_ip=10.23.2.1
[server: main]
addr=0.0.0.0:1333
type=public
[client: node-a]
link=main:85.192.42.96:1333
peer_public_key=<pubkey_A>
[client: node-c]
link=main:203.0.113.10:1333
peer_public_key=<pubkey_C>
[routing]
my_subnet=10.23.2.0/24
Что происходит автоматически:
- B устанавливает ETCP-соединения с A и C
- Через BGP A узнаёт о подсетях C (и наоборот)
- Узел A может отправлять пакеты к подсети C через B (transit forwarding)
etcp_routerобеспечивает надёжную маршрутизацию через промежуточные узлы
4.3. Exit-прокси (выход в интернет через удалённый узел)
Exit-узел (с прямым выходом в интернет):
[global]
my_node_name=exit-node
my_private_key=<hex>
my_public_key=<hex>
[server: main]
addr=85.192.42.96:1333
type=public
[tcp_proxy_server]
enabled=yes
Клиент (выходит в интернет через exit-узел):
[global]
my_node_name=client
my_private_key=<hex>
my_public_key=<hex>
[server: main]
addr=0.0.0.0:1333
[client: exit]
link=main:85.192.42.96:1333
peer_public_key=<pubkey_exit>
[tcp_proxy_client]
enabled=yes
tun_name=tun_proxy
tun_ip=10.200.30.1
via_node=<node_id_exit>
socks_enabled=yes
socks_addr=127.0.0.1:1082
Настройка браузера: SOCKS5 proxy 127.0.0.1:1082. TCP-трафик идёт: браузер → SOCKS5 → lwIP → ETCP → exit-узел → интернет.
4.4. EIM NAT (раздача интернета через NAT)
[nat]
nat_enabled=yes
nat_tun_ifname=eth0 # внешний интерфейс
port_start=20000
port_end=30000
forward=tcp:192.168.1.100:80:8080 # проброс порта 8080 → 192.168.1.100:80
forward=udp:192.168.1.100:53:53 # проброс DNS
4.5. Чат (chatgui)
Chatgui — десктопный GUI-чат (Qt 6) со встроенным uTun-узлом. Вся связь — напрямую между узлами (P2P), без центральных серверов.
Сборка:
sudo apt install librlottie-dev zlib1g-dev qt6-base-dev
cd tools/chatgui && mkdir -p build && cd build
cmake .. && make -j4
./chatgui
Запуск:
setsid env DISPLAY=:1.0 QT_ACCESSIBILITY=1 ./chatgui & disown
Chatgui работает в двух потоках:
- GUI-поток — Qt, отрисовка, чтение из SQLite
- uasync-поток — uTun-узел, сеть, криптография, ETCP, запись в SQLite
Основные возможности:
- Создание каналов и групп
- Обмен сообщениями с анимированными эмодзи (TGS)
- Invite-ссылки (
utun://...) с QR-кодами - P2P синхронизация через Merkle-деревья
- Авто-подключение к известным узлам из БД
5. Топология сети
5.1. Типы адресов
| Тип | Описание | Пример |
|---|---|---|
INTERFACE |
Адрес на сетевом интерфейсе | eth0: 192.168.1.10 |
NAT |
Внешний адрес после NAT (детектируется) | 85.192.42.96:54321 |
REAL |
Публичный адрес (совпадает interface == NAT) | 85.192.42.96:1333 |
5.2. Как узлы находят друг друга
- Прямое подключение — через
[client]секцию с явным IP:портом - BGP-обмен — при подключении к одному узлу, узнаёшь о всех его соседях
- Локальное сканирование —
conn_mgrпериодически сканирует локальную сеть - Invite-ссылки —
utun://ссылки с закодированными адресами и ключами
5.3. NAT traversal
conn_mgr реализует трёхфазное подключение:
- DIRECT (5 сек) — прямое INIT-рукопожатие со всеми известными адресами
- REVERSE (15 сек) — если клиент за NAT, сервер с прямым IP: клиент шлёт свои адреса через BGP, сервер подключается сам
- INDIRECT (15 сек) — оба за NAT: выбираются общие кандидаты-посредники по min RTT, трафик идёт через
etcp_router
Типы NAT, которые определяет uTun:
- EIM (Endpoint-Independent Mapping) — один внешний порт для всех назначений
- Strict (Address/Restricted/Symmetric) — разные порты
5.4. Группы
Два типа групп:
- UTUN (
group_id=0x8000000000000000) — VPN-сеть: обмен подсетями, маршруты - CHAT — чат-группа: только узлы, без подсетей, персистентность в SQLite
Узлы разных групп изолированы.
6. Мониторинг и отладка
6.1. Уровни отладки
none < error < warn < info < debug < trace
Настройка через -d в CLI (имеет приоритет) или секцию [debug] в конфиге:
./src/utun -f -c myconfig.conf -d "etcp=trace,crypto=info"
Или эквивалент в конфиге:
[debug]
etcp=trace
crypto=info
bgp=info
6.2. Категории отладки (26 шт)
| Категория | Что логирует |
|---|---|
etcp |
Протокол ETCP: очереди, retrans, ACK, RTT |
crypto |
Шифрование/дешифрование, ключи, nonce |
connection |
Сокеты, линки, INIT handshake, keepalive |
bgp |
Обмен топологией (NODEINFO, WITHDRAW) |
routing |
Таблица маршрутов, поиск путей |
tun |
TUN-интерфейс: чтение/запись |
traffic |
Данные трафика |
general |
Общая информация |
bbr |
BBR congestion control |
keepalive |
Адаптивный keepalive |
memory |
Выделение/освобождение памяти |
dump |
Hex-дампы пакетов |
etcp_dump |
Декодирование ETCP-пакетов |
6.3. etcpmon — Windows GUI монитор
Подключается к control_server узла по TCP (порт из control_port). Показывает:
- Список соединений и их состояние
- RTT, потери, inflight
- Графики метрик
- Дамп пакетов
6.4. control_server — TCP API
[control]
control_ip=0.0.0.0
control_port=9090
control_allow=192.168.0.0/16
Любой TCP-клиент может подключиться и получать события в реальном времени (JSON-подобный формат).
6.5. Логи и дампы
Лог-файл указывается через -l:
./src/utun -f -c myconfig.conf -l /tmp/utun.log
Hex-дамп пакетов включается категорией dump=trace:
[debug]
dump=trace
7. NAT и Firewall
7.1. Как uTun определяет тип NAT
- Клиент подключается к серверу
- Сервер видит внешний IP:порт клиента (из UDP-пакета)
- Сервер через третий узел (посредник) пингует клиента на этот внешний IP:порт
- Если клиент ответил — NAT EIM (один mapping для всех)
- Если нет — NAT Strict
Результат сохраняется в link->nat_type и broadcast-ится всем соседям через BGP.
7.2. Firewall
[firewall]
allow=all # всё разрешено
allow=10.0.0.0/8 # разрешить подсеть
allow=192.168.1.5:22 # разрешить IP:порт
По умолчанию без секции [firewall] — фильтрация выключена.
7.3. Проброс портов
[nat]
forward=tcp:192.168.1.100:80:8080 # входящий порт 8080 → 192.168.1.100:80
forward=udp:10.0.0.53:53:53 # DNS
8. Устранение неполадок
8.1. Нет связи — проверка INIT handshake
Включите:
[debug]
connection=debug
crypto=debug
В логах ищите:
INIT_REQUEST sent to .../INIT_RESPONSE received from ...— handshakesession_ready=1— ключи согласованы, шифрование работаетETCP_KEEPALIVE— keepalive-пакеты идут- Если нет — проверьте firewall на портах, доступность IP
8.2. Пакеты теряются — проверка метрик
# В логах с etcp=debug смотрите:
grep "retrans" /tmp/utun.log # ретрансмиссии
grep "rtt=" /tmp/utun.log # задержки
grep "lost" /tmp/utun.log # потери
Каждые 10 минут пишутся гистограммы метрик с RTT-бакетами и loss-бакетами.
8.3. Высокая задержка — keepalive
Адаптивный keepalive: период растёт от 200ms до 10s при отсутствии трафика, сбрасывается к 200ms при появлении. Таймаут = период × 10.
Проверьте:
[debug]
keepalive=debug
8.4. Утечки памяти — проверка пулов
[debug]
memory=debug
При завершении u_report_unfreed_blocks() показывает все неосвобождённые блоки.
8.5. Дамп состояния
ETCP предоставляет функцию etcp_dump_all_conns() для вывода полного состояния всех соединений (очереди, inflight, счётчики). Включается через etcp_dump=trace.
8.6. ASAN-сборка (поиск повреждений памяти)
./build.sh --asan -j4
ASAN_OPTIONS=detect_leaks=0:halt_on_error=0 ./src/utun -f -c myconfig.conf
Краш-логи ASAN пишутся в /tmp/utun_asan.<pid>.
9. Производительность
9.1. BBR congestion control
BBR работает per-link. Основные настройки:
[global]
bbr_max_cwnd=1048576 # максимум окна перегрузки (1MB по умолчанию)
BBR автоматически измеряет пропускную способность через burst-измерения (12 пакетов пачкой, замер inter-packet gap). Периодичность burst — не чаще 500ms.
9.2. Memory pools
Три пула в UTUN_INSTANCE:
data_pool— данные пакетов (payload)pkt_pool—struct ETCP_DGRAM(сетевые пакеты)ack_pool—struct ACK_PACKET(подтверждения)
Пулы аллоцируются upfront при старте. Статистику можно посмотреть через control_server.
9.3. Multi-link балансировка
LoadBalancer выбирает линк с минимальным inflight, с round-robin для равных. Traffic shaper ограничивает отправку до optimal_inflight:
timeout = (rtt_avg_10 * 32 + jitter * 32) / 16
Оптимальное окно: optimal_inflight = sum(inflight_lim_bytes)
9.4. Keepalive
Адаптивный режим:
- Начальный период =
keepaliveиз[client](сек) - При трафике → сброс к начальному
- Без трафика → растёт ×1.05 до 10 секунд
- Таймаут = период × 10
10. CLI-справка
utun [опции]
Опции:
-f Foreground (без демонизации)
-c FILE Конфигурационный файл (по умолчанию: utun.conf)
-p FILE PID-файл (по умолчанию: /var/run/utun.pid)
-l FILE Лог-файл (по умолчанию: utun.log)
-d CONFIG Отладка: категория=уровень,... (переопределяет конфиг)
-h Справка
Сигналы:
SIGTERM/SIGINT— graceful shutdown (закрытие соединений, освобождение ресурсов)SIGHUP— reload конфига (селективный: меняются только изменённые сокеты/клиенты; полный — при изменении ключей или TUN)
11. Типовые конфигурации
Минимальный сервер
[global]
my_node_name=server
tun_ip=10.23.1.1
[server: main]
addr=0.0.0.0:1333
Минимальный клиент
[global]
my_node_name=client
tun_ip=10.23.2.1
[server: main]
addr=0.0.0.0:1333
[client: server]
link=main:85.192.42.96:1333
peer_public_key=<pubkey_сервера>
Mesh-узел с несколькими пирами
[global]
my_node_name=mesh-node-3
tun_ip=10.23.3.1
[server: main]
addr=0.0.0.0:1333
[client: node-1]
link=main:10.0.0.1:1333
peer_public_key=<pubkey_1>
[client: node-2]
link=main:10.0.0.2:1333
peer_public_key=<pubkey_2>
[routing]
my_subnet=10.23.3.0/24
Exit-узел с TCP-прокси
[global]
my_node_name=exit-eu
tun_ip=10.23.100.1
[server: main]
addr=85.192.42.96:1333
type=public
[tcp_proxy_server]
enabled=yes
[routing]
my_subnet=10.23.100.0/24
Клиент с SOCKS5-прокси
[global]
my_node_name=home-laptop
[server: main]
addr=0.0.0.0:1333
[client: exit]
link=main:85.192.42.96:1333
peer_public_key=<pubkey_exit>
[tcp_proxy_client]
enabled=yes
socks_enabled=yes
socks_addr=127.0.0.1:1082
via_node=<node_id_exit>