- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll - stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close - utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP), add deferred drain in both Phase J and L - stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39, exchange ed25519_pubkey in both handshake directions - etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb - chat_sync.c: fix lk->conn NULL dereference for TCP links - test_stcp.c: update stcp_server_create/stcp_client_connect callsites - tools/chat_tcp_test: change transport udp→tcp
219 lines
9.4 KiB
Markdown
219 lines
9.4 KiB
Markdown
# 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
|
||
```
|