# uTun — Руководство пользователя uTun — децентрализованная VPN-система с шифрованием, надёжной доставкой данных, поддержкой mesh-сетей и встроенным TCP-прокси. Работает поверх UDP (основной транспорт) и TCP (STCP-резерв). Всё шифруется через X25519 + AES-128-CCM. Топология узлов обменивается автоматически (BGP-подобный протокол). --- ## 1. Быстрый старт ### 1.1. Сборка ```bash 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: ```ini [global] my_node_name=my-first-node ``` После первого запуска ключи пропишутся в конфиг автоматически. ### 1.3. Первый запуск ```bash 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. Проверка работы ```bash 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]` — Идентичность и базовые настройки ```ini [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-сокеты ```ini [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]` — Подключение к удалённым узлам ```ini [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]` — Маршруты ```ini [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`. ```ini [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]` — Правила фильтрации ```ini [firewall] allow=all # разрешить всё (bypass) allow=192.168.1.0/24 # разрешить подсеть allow=10.0.0.1:80 # разрешить конкретный IP:порт ``` ### 3.7. `[nat]` — EIM NAT ```ini [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-узел):** ```ini [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-узел (сервер):** ```ini [tcp_proxy_server] enabled=yes ``` Клиент настраивает браузер на SOCKS5 `127.0.0.1:1082` — весь TCP-трафик идёт через exit-узел. ### 3.9. `[control]` — Сервер мониторинга ```ini [control] control_ip=192.168.29.117 # IP для приёма подключений etcpmon control_port=9090 control_allow=192.168.0.0/16 # разрешённые подсети (можно несколько) ``` ### 3.10. `[allowed_keys]` — Ограничение подключений ```ini [allowed_keys] allow_all=1 # разрешить все ключи # key=86b51a8b...6a2d19 # разрешить конкретный pubkey ``` ### 3.11. `[ntp]` — Синхронизация времени ```ini [ntp] enabled=yes server=pool.ntp.org server=time.google.com interval=3600 # интервал синхронизации (сек) ``` ### 3.12. `[network:NAME]` — Именованные сети ```ini [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`): ```ini [global] my_node_name=server my_private_key= my_public_key= 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, подключается к серверу): ```ini [global] my_node_name=client my_private_key= my_public_key= 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= keepalive=1 [routing] my_subnet=10.23.2.0/24 ``` **Проверка связности:** ```bash # На сервере ping 10.23.2.1 # На клиенте ping 10.23.1.1 ``` ### 4.2. Mesh-сеть из нескольких узлов Каждый узел = сервер (свои сокеты) + клиент (подключения к соседям). Пример для узла B, который подключается к A и C: ```ini [global] my_node_name=node-b my_private_key= my_public_key= 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= [client: node-c] link=main:203.0.113.10:1333 peer_public_key= [routing] my_subnet=10.23.2.0/24 ``` Что происходит автоматически: 1. B устанавливает ETCP-соединения с A и C 2. Через BGP A узнаёт о подсетях C (и наоборот) 3. Узел A может отправлять пакеты к подсети C через B (transit forwarding) 4. `etcp_router` обеспечивает надёжную маршрутизацию через промежуточные узлы ### 4.3. Exit-прокси (выход в интернет через удалённый узел) **Exit-узел** (с прямым выходом в интернет): ```ini [global] my_node_name=exit-node my_private_key= my_public_key= [server: main] addr=85.192.42.96:1333 type=public [tcp_proxy_server] enabled=yes ``` **Клиент** (выходит в интернет через exit-узел): ```ini [global] my_node_name=client my_private_key= my_public_key= [server: main] addr=0.0.0.0:1333 [client: exit] link=main:85.192.42.96:1333 peer_public_key= [tcp_proxy_client] enabled=yes tun_name=tun_proxy tun_ip=10.200.30.1 via_node= 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) ```ini [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), без центральных серверов. **Сборка:** ```bash sudo apt install librlottie-dev zlib1g-dev qt6-base-dev cd tools/chatgui && mkdir -p build && cd build cmake .. && make -j4 ./chatgui ``` **Запуск:** ```bash 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. Как узлы находят друг друга 1. **Прямое подключение** — через `[client]` секцию с явным IP:портом 2. **BGP-обмен** — при подключении к одному узлу, узнаёшь о всех его соседях 3. **Локальное сканирование** — `conn_mgr` периодически сканирует локальную сеть 4. **Invite-ссылки** — `utun://` ссылки с закодированными адресами и ключами ### 5.3. NAT traversal `conn_mgr` реализует трёхфазное подключение: 1. **DIRECT** (5 сек) — прямое INIT-рукопожатие со всеми известными адресами 2. **REVERSE** (15 сек) — если клиент за NAT, сервер с прямым IP: клиент шлёт свои адреса через BGP, сервер подключается сам 3. **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]` в конфиге: ```bash ./src/utun -f -c myconfig.conf -d "etcp=trace,crypto=info" ``` Или эквивалент в конфиге: ```ini [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 ```ini [control] control_ip=0.0.0.0 control_port=9090 control_allow=192.168.0.0/16 ``` Любой TCP-клиент может подключиться и получать события в реальном времени (JSON-подобный формат). ### 6.5. Логи и дампы Лог-файл указывается через `-l`: ```bash ./src/utun -f -c myconfig.conf -l /tmp/utun.log ``` Hex-дамп пакетов включается категорией `dump=trace`: ```ini [debug] dump=trace ``` --- ## 7. NAT и Firewall ### 7.1. Как uTun определяет тип NAT 1. Клиент подключается к серверу 2. Сервер видит внешний IP:порт клиента (из UDP-пакета) 3. Сервер через **третий узел** (посредник) пингует клиента на этот внешний IP:порт 4. Если клиент ответил — NAT EIM (один mapping для всех) 5. Если нет — NAT Strict Результат сохраняется в `link->nat_type` и broadcast-ится всем соседям через BGP. ### 7.2. Firewall ```ini [firewall] allow=all # всё разрешено allow=10.0.0.0/8 # разрешить подсеть allow=192.168.1.5:22 # разрешить IP:порт ``` По умолчанию без секции `[firewall]` — фильтрация выключена. ### 7.3. Проброс портов ```ini [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 Включите: ```ini [debug] connection=debug crypto=debug ``` В логах ищите: - `INIT_REQUEST sent to ...` / `INIT_RESPONSE received from ...` — handshake - `session_ready=1` — ключи согласованы, шифрование работает - `ETCP_KEEPALIVE` — keepalive-пакеты идут - Если нет — проверьте firewall на портах, доступность IP ### 8.2. Пакеты теряются — проверка метрик ```bash # В логах с 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. Проверьте: ```ini [debug] keepalive=debug ``` ### 8.4. Утечки памяти — проверка пулов ```ini [debug] memory=debug ``` При завершении `u_report_unfreed_blocks()` показывает все неосвобождённые блоки. ### 8.5. Дамп состояния ETCP предоставляет функцию `etcp_dump_all_conns()` для вывода полного состояния всех соединений (очереди, inflight, счётчики). Включается через `etcp_dump=trace`. ### 8.6. ASAN-сборка (поиск повреждений памяти) ```bash ./build.sh --asan -j4 ASAN_OPTIONS=detect_leaks=0:halt_on_error=0 ./src/utun -f -c myconfig.conf ``` Краш-логи ASAN пишутся в `/tmp/utun_asan.`. --- ## 9. Производительность ### 9.1. BBR congestion control BBR работает per-link. Основные настройки: ```ini [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. Типовые конфигурации ### Минимальный сервер ```ini [global] my_node_name=server tun_ip=10.23.1.1 [server: main] addr=0.0.0.0:1333 ``` ### Минимальный клиент ```ini [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= ``` ### Mesh-узел с несколькими пирами ```ini [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= [client: node-2] link=main:10.0.0.2:1333 peer_public_key= [routing] my_subnet=10.23.3.0/24 ``` ### Exit-узел с TCP-прокси ```ini [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-прокси ```ini [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= [tcp_proxy_client] enabled=yes socks_enabled=yes socks_addr=127.0.0.1:1082 via_node= ```