# uTun — защищённый VPN-туннель поверх UDP uTun создаёт виртуальный TUN-интерфейс и маршрутизирует IP-трафик через зашифрованные UDP-каналы по протоколу **ETCP** (Extended TCP) — комбинация TCP-надёжности + QUIC-мультиплексирования + multi-link балансировки. ## Возможности | Возможность | Описание | |---|---| | **Шифрование** | X25519 обмен ключами + AES-128-CCM с аутентификацией | | **Целостность** | CRC32 внутри зашифрованного payload | | **Multi-link** | Одно подключение через несколько UDP-каналов одновременно | | **Балансировка** | Выбор канала с минимальным inflight + round-robin при равенстве | | **Bandwidth shaping** | Ограничение полосы на каждом канале с автооценкой | | **Inflight control** | Динамическое ограничение байт в полёте для предотвращения перегрузки | | **Retransmission** | Адаптивный таймаут: RTT_avg × k₁ + jitter × k₂ | | **Keepalive** | Двусторонний, с настраиваемым интервалом и таймаутом | | **Фрагментация/сборка** | Normalizer: упаковка мелких пакетов вместе, разбиение крупных | | **Маршрутизация** | Локальная (через TUN + системные маршруты) и распределённая (BGP-обмен) | | **NAT-детекция** | Определение типа NAT (open/restricted) через ping-пробы | | **Файрвол** | Белый список IP:port для трафика через туннель | | **Control server** | TCP-сервер для мониторинга метрик в реальном времени (GUI-клиент) | | **Горячая перезагрузка** | SIGHUP — выборочное обновление конфига (сравнение сокетов/клиентов/линков) | | **Авто-ключи** | При первом запуске генерирует X25519-пару и node_id, записывает в конфиг | | **Демонизация** | fork/setsid на Linux; foreground-режим `-f` для отладки | | **Кроссплатформенность** | Linux (epoll), Windows (wintun), FreeBSD | | **Эмуляция потерь** | `loss_rate=N` в конфиге сокета — для тестирования | ## Архитектура (кратко) ``` Приложение/ОС ↓ IP-пакеты TUN interface (tun_if) ↓ queue Routing (routing.c) — поиск маршрута ↓ (если удалённый) Normalizer (pkt_normalizer.c) — фрагментация/упаковка ↓ ETCP (etcp.c) — seq/ack, retransmit, reassembly ↓ LoadBalancer (etcp_loadbalancer.c) — выбор канала ↓ Encrypt + UDP send (etcp_connections.c) ↓ Сеть (UDP) ``` ## Конфигурация (INI-формат) ### CLI-запуск ``` utun -c utun.conf [-p /var/run/utun.pid] [-l utun.log] [-f] [-d "etcp:debug"] ``` - `-c` — путь к конфигу (по умолчанию `utun.conf`) - `-p` — PID-файл - `-l` — лог-файл (по умолчанию `utun.log`) - `-f` — foreground (не демонизироваться) - `-d` — отладочный конфиг на лету, формат: `"категория:уровень,..."` ### Секции конфига #### `[global]` — основные параметры | Ключ | Значение | По умолчанию | |---|---|---| | `my_node_name` | Имя узла (до 15 символов) | — | | `my_node_id` | 64-битный ID узла (hex, 16 символов) | авто | | `my_private_key` | Приватный ключ X25519 (64 hex символа) | авто | | `my_public_key` | Публичный ключ X25519 (64 hex символа) | авто | | `tun_ifname` | Имя TUN-интерфейса | `tun0` | | `tun_ip` | IP-адрес TUN-интерфейса | — | | `mtu` | MTU для всех подключений | `1500` | | `keepalive_timeout` | Таймаут keepalive (мс) | `2000` | | `keepalive_interval` | Интервал keepalive (мс) | `200` | | `log_file` | Путь к лог-файлу | — | | `debug_level` | Уровень отладки: `error`, `warn`, `info`, `debug`, `trace` | `error` | | `tun_test_mode` | 1 — не создавать реальный TUN (тесты) | `0` | | `enable_timestamp` | Метки времени в логах | `1` | | `enable_function_names` | Имена функций в логах | `1` | | `enable_file_lines` | Файл:строка в логах | `0` | | `enable_colors` | ANSI-цвета в терминале | `0` | #### `[debug]` — по-категорийные уровни (переопределяют `debug_level`) Доступные категории: `uasync`, `ll_queue`, `connection`, `etcp`, `crypto`, `memory`, `timing`, `config`, `tun`, `routing`, `timers`, `normalizer`, `bgp`, `socket`, `general`, `control`, `dump`, `traffic` Пример: ```ini [debug] etcp=info routing=trace bgp=trace crypto=error ``` #### `[server: ИМЯ]` — локальные UDP-сокеты (обязательно хотя бы один) | Ключ | Значение | По умолчанию | |---|---|---| | `addr` | `IP:port` для bind | **обязателен** | | `type` | `public`, `nat`, `private` | `unknown` | | `mtu` | MTU для этого сокета | из `[global]` | | `loss_rate` | % потерь пакетов (0–100) | `0` | | `so_mark` | Linux SO_MARK для policy routing | — | | `netif` | Привязка к интерфейсу (по имени) | — | | `fib` | FreeBSD FIB (таблица маршрутизации) | `-1` (не задан) | | `only_local` | 1 — только локальные соединения, без forwarding | `0` | Пример: ```ini [server: lan1] addr=192.168.29.117:1333 type=public ``` #### `[client: ИМЯ]` — исходящие подключения к пиру | Ключ | Значение | По умолчанию | |---|---|---| | `link` | `сервер:удалённый_IP:порт` (можно несколько) | **обязателен** | | `peer_public_key` | Публичный ключ пира (64 hex) | **обязателен** | | `keepalive` | 1 — включить keepalive | `1` | Пример: ```ini [client: aeza] link=lan1:85.192.42.96:1333 peer_public_key=04c1cae041a8e6bfba5245f6669c73f0793d7f9929300a2ba2e123ca55260d6e47... ``` > **Важно:** в серверном конфиге секции `[client]` нет. В клиентском — есть свои ключи + `peer_public_key` каждого сервера в `[client]`. #### `[routing]` — маршруты | Ключ | Значение | |---|---| | `route_subnet` | Подсеть, доступная через этот TUN (добавляется в системную таблицу маршрутизации). Можно несколько | | `my_subnet` | Своя подсеть, анонсируемая через BGP | Пример: ```ini [routing] route_subnet=10.23.0.0/16 route_subnet=10.24.0.0/16 my_subnet=10.23.1.0/24 ``` #### `[firewall]` — контроль доступа | Ключ | Значение | |---|---| | `allow` | `all` — разрешить всё. Или `IP` / `IP:port` (можно несколько) | По умолчанию: deny all (если нет allow=all). Пример: ```ini [firewall] allow=192.168.1.100 allow=10.0.0.0/8:443 ``` #### `[control]` — сервер мониторинга | Ключ | Значение | По умолчанию | |---|---|---| | `control_ip` | IP для прослушивания | `127.0.0.1` | | `control_port` | Порт | — | | `control_allow` | `IP/mask` (можно несколько) | deny all | Пример: ```ini [control] control_ip=192.168.29.117 control_port=9090 control_allow=192.168.0.0/16 ``` #### `[allowed_keys]` — белый список публичных ключей пиров | Ключ | Значение | По умолчанию | |---|---|---| | `allow_all` | 1 — разрешить все ключи | — | | `key` | Публичный ключ (64 hex, можно несколько) | — | Поведение: - Секция отсутствует: разрешить все (совместимость) - `allow_all=0` + нет ключей: запретить все - `allow_all=0` + ключи: только перечисленные ключи Пример: ```ini [allowed_keys] key=c6c8a8a9616ffa6cf44d4757e2bc9f7bd78a1d3cbbe75cffaf3cab8885ad48e7677b... key=04c1cae041a8e6bfba5245f6669c73f0793d7f9929300a2ba2e123ca55260d6e4748... ``` ### Пример минимального конфига ```ini [global] tun_ip=10.23.1.1 my_node_name=vmL1 my_node_id=5f75c7445af88e1f my_private_key=d065b784a8386f9b37f07b4c16c3ab83ddce5885e78f79c5d2a6d1f9954fe441 my_public_key=c6c8a8a9616ffa6cf44d4757e2bc9f7bd78a1d3cbbe75cffaf3cab8885ad48e7677b... [server: lan1] addr=192.168.29.117:1333 type=public [routing] route_subnet=10.23.0.0/16 my_subnet=10.23.1.0/24 ```