Files
AuraVPN/docs/deployment.md
T
xah30 5ea643a9e5 feat(cli,tunnel,docs): full Windows support — OS routes + wintun audit
Windows is now first-class for client use:

- aura-cli::os_routes Windows path is no longer a stub. Real install via
  `route ADD <net> MASK <mask> <gw> METRIC 1` for DIRECT bypass (rollback:
  `route DELETE ...`) and `netsh interface ipv4 add route <cidr> "Aura"
  <tun_local_ip> store=active` for VPN default/CIDR (rollback: `netsh ...
  delete route ...`). Default-gateway detection by parsing `route print 0`
  output via parse_windows_route_print_default; rejects `On-link` rows. Dry
  run works on every host.
- aura-tunnel::tun wintun audit fixed a real bug: AuraTun was holding only
  Arc<Session> while Session does NOT keep Arc<Adapter> alive (only the
  Wintun DLL handle). On Drop the adapter was being closed under the
  session. Fixed by adding _adapter: Arc<wintun::Adapter> to AuraTun, with
  field order ensuring Session is dropped before Adapter so end-session
  precedes close-adapter. Also wired mtu into write_packet (hard limit) +
  read_packet (warn).
- Cross-compile verified: cargo check --target x86_64-pc-windows-gnu
  --workspace and clippy on the windows target are both clean (added
  mingw-w64 + x86_64-pc-windows-gnu via rustup).
- docs/deployment.md: §6 updated (Windows OS-routes now Done), new §8
  «Windows как клиент» with download wintun.dll, Admin run, [tunnel.os_routes]
  enabled, known no-ops (run_as, [server.nat]).

9 new tests (7 parser/plan/undo unit + 1 windows dry-run integration + 1
existing). Workspace: 293 tests passed (+9), clippy -D warnings clean, fmt
clean. macOS host + windows-gnu cross-target both green.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 21:14:23 +03:00

866 lines
49 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Развёртывание Aura VPN
Этот документ — пошаговое руководство, по которому вы поднимаете сервер Aura на удалённой машине,
провижините на нём сертификат для клиента и подключаете клиент (десктоп) к этому серверу. Все
команды и поля конфигов взяты из фактического кода и поставляемых примеров в `config/`.
> Полезные сопутствующие документы: [`protocol.md`](protocol.md) (wire-протокол),
> [`pki.md`](pki.md) (CA и сертификаты), [`split-tunnel.md`](split-tunnel.md) (правила
> маршрутизации), [`sing-box.md`](sing-box.md) (интеграция с sing-box, план).
---
## 1. Обзор схемы
Сервер Aura на удалённой машине провижинит сертификат для клиента (десктопа или, в будущем,
телефона через sing-box), отдаёт клиенту бандл сертификатов и трастового якоря, и клиент
подключается к серверу по протоколу AuraVPN.
На проводе по умолчанию используется **собственный UDP-транспорт Aura с пост-квантовой
криптографией** (без QUIC и без внешнего TLS на основном пути); fallback'и — это TCP/443 и QUIC.
Всё рукопожатие пост-квантовое: **гибридное X25519 + ML-KEM-768** с взаимной X.509-аутентификацией.
Для данных используется AEAD **ChaCha20-Poly1305** с explicit-nonce. Обфускация — это паддинг
датаграмм до «корзин» размера, характерных для HTTPS.
```
[клиент-десктоп] [удалённый сервер aura]
client.toml + PEM-бандл server.toml + PKI (CA + server leaf)
| |
| UDP (основной) / TCP/443 / QUIC |
| гибридное PQ-рукопожатие |
| ChaCha20-Poly1305 |
+--------------------------------------->
AuraVPN
```
---
## 2. Сервер (удалённый хост)
### 2.1. Установка бинаря
В корне репозитория:
```bash
cargo build --release
# -> target/release/aura
```
Скопируйте получившийся бинарь `target/release/aura` на сервер (например в `/usr/local/bin/aura`)
либо соберите его прямо на сервере (требуется Rust toolchain).
### 2.2. Поднять PKI
Эти три команды создают CA и выпускают листовые сертификаты для сервера и клиента. Все они
проверены против реализации в `crates/aura-pki/src/{ca,cert,store}.rs` и
`crates/aura-cli/src/pki.rs`.
```bash
# 1) Создать CA Aura.
aura pki init --ca-name "Aura Root CA" --out /etc/aura/pki
# -> /etc/aura/pki/ca.crt
# -> /etc/aura/pki/ca.key # секрет, защищайте правами файловой системы
# 2) Выпустить сертификат сервера. --domain должен совпадать с тем именем,
# которое клиент будет ожидать в [client] sni (это же имя проверяется по SAN).
aura pki issue-server \
--domain vpn.example.com \
--out /etc/aura/pki/server \
--ca /etc/aura/pki
# -> /etc/aura/pki/server/server.crt
# -> /etc/aura/pki/server/server.key # секрет
# 3) Выпустить сертификат клиента (по одному на устройство).
# --id становится Common Name'ом и проверенным peer_id, который видит сервер.
aura pki issue-client \
--id phone-1 \
--out /etc/aura/clients/phone-1 \
--ca /etc/aura/pki
# -> /etc/aura/clients/phone-1/client.crt
# -> /etc/aura/clients/phone-1/client.key # секрет
```
Подробности (включая `aura pki revoke` / `list`) — см. [`pki.md`](pki.md).
### 2.3. `server.toml`
Раскладка ниже взята из `config/server.toml.example` и поставляемых serde-структур
(`crates/aura-cli/src/config.rs`). Скопируйте пример и поправьте под себя.
```toml
[server]
# Человекочитаемое имя (также внутренняя identity сервера в рукопожатии).
name = "aura-edge-1"
# UDP/TCP listen-сокет. ":443" мимикрирует под HTTPS; для его биндинга нужны привилегии.
# IP отсюда переиспользуется как listen-IP для каждого включённого транспорта.
listen = "0.0.0.0:443"
# Число accept-воркеров (в v1 носит совещательный характер).
workers = 4
[pki]
# Trust anchor (Aura CA) и листовая пара сервера, все PEM.
ca_cert = "/etc/aura/pki/ca.crt"
cert = "/etc/aura/pki/server/server.crt"
key = "/etc/aura/pki/server/server.key"
[tunnel]
# Адресный пул для клиентов; в v1 на сервере один общий TUN в этой сети.
pool_cidr = "10.7.0.0/24"
# MTU TUN-устройства (запас под QUIC + framing Aura).
mtu = 1420
# DNS, анонсируемый клиентам (в v1 информационно).
dns = "10.7.0.1"
[mimicry]
# Hostname, под который мимикрирует внешний TLS-слой (для QUIC).
sni = "cdn.example.com"
# Паддинг для размытия размеров пакетов под «корзины» HTTPS.
padding = true
[transport]
# Набор и порядок транспортов, биндящихся одновременно. UDP — основной; TCP/443 и
# QUIC (мимикрия H3) — fallback'и. При отсутствии всей секции включаются udp/tcp/quic
# на 443/443/444.
order = ["udp", "tcp", "quic"]
# UDP-транспорт и QUIC оба используют UDP, поэтому udp_port и quic_port ДОЛЖНЫ
# различаться. TCP может занимать тот же номер порта (другой протокол).
udp_port = 443
tcp_port = 443
quic_port = 444
# UDP: дополнять датаграммы до «корзин» размера HTTPS, чтобы размыть распределение размеров.
obfuscate = true
# TCP: добавлять минимальный HTTP/1.1-преамбулу (Host = [mimicry] sni), чтобы открытие
# выглядело как обычный HTTP.
masquerade = true
```
Пути могут начинаться с `~` (раскрывается в домашнюю директорию).
### 2.4. Сеть на сервере
#### Файрвол
Откройте те порты, которые перечислены у вас в `[transport]`. С приведённой выше конфигурацией:
- UDP **443** — основной транспорт Aura.
- TCP **443** — fallback Aura поверх TCP.
- UDP **444** — fallback Aura поверх QUIC.
Важно: UDP-транспорт и QUIC — это **оба UDP**, поэтому их порты обязательно должны различаться
(в примере: udp_port=443, quic_port=444). Конфиг-валидатор `transport.modes()` отвергает совпадение.
#### IP-форвардинг и NAT (для выхода клиентов в интернет)
В v1 настройка egress на стороне сервера — **обязательный ручной шаг**. На Linux:
```bash
# 1) Включить IP-форвардинг.
sudo sysctl -w net.ipv4.ip_forward=1
# (для постоянства добавьте в /etc/sysctl.conf или /etc/sysctl.d/*)
# 2) MASQUERADE для исходящего трафика клиентов на интернет-интерфейсе (например eth0).
sudo iptables -t nat -A POSTROUTING \
-s 10.7.0.0/24 \
-o eth0 \
-j MASQUERADE
```
Подставьте свой `pool_cidr` и имя интернет-интерфейса.
### 2.5. Запуск сервера
```bash
sudo aura server --config /etc/aura/server.toml
```
`sudo` нужен для создания TUN-устройства и для биндинга привилегированных портов (`:443`).
Можно опционально указать путь admin-сокета:
```bash
sudo aura server \
--config /etc/aura/server.toml \
--admin-socket /var/run/aura-admin.sock
```
По умолчанию admin-сокет — `/tmp/aura-admin.sock`.
---
## 3. Что вы получаете для клиента (бандл)
Отдайте клиенту **три PEM-файла**:
- `ca.crt` (из `/etc/aura/pki/ca.crt`) — trust anchor;
- `client.crt` (из `/etc/aura/clients/<id>/client.crt`) — листовой сертификат клиента;
- `client.key` (из `/etc/aura/clients/<id>/client.key`) — **секрет**, приватный ключ клиента.
И сообщите ему два параметра:
- **Адрес сервера** (например `203.0.113.10`).
- **`sni`** — то DNS-имя, которое вы указали в `aura pki issue-server --domain`. Оно же
ожидается в SAN серверного сертификата и проверяется в `verify_server_cert`.
Эти три файла плюс два параметра — это всё, что нужно клиенту для подключения.
---
## 4. Клиент (десктоп)
Путь для телефона — через sing-box; пока нативного клиента нет, см. раздел 6 ниже.
### 4.1. `client.toml`
Раскладка взята из `config/client.toml.example` и `crates/aura-cli/src/config.rs`.
```toml
[client]
# Человекочитаемое имя/id клиента.
name = "laptop"
# UDP-сокет сервера. IP отсюда переиспользуется как server-IP для каждого транспорта.
server_addr = "203.0.113.10:443"
# Внешний TLS-SNI (hostname-камуфляж), предъявляемый серверу. Он же проверяется
# внутри рукопожатия Aura против SAN серверного сертификата.
sni = "cdn.example.com"
[pki]
# Trust anchor (Aura CA) и листовая пара клиента, все PEM.
ca_cert = "~/.aura/ca.crt"
cert = "~/.aura/client.crt"
key = "~/.aura/client.key"
[tunnel]
# Запрошенное имя TUN-интерфейса (на macOS совещательно — ядро назначает utunN).
tun_name = "aura0"
# Локальный адрес для TUN и длина префикса.
local_ip = "10.7.0.2"
prefix = 24
# MTU TUN.
mtu = 1420
# DNS, используемый туннельным резолвером (в v1 информационно; реально используется
# системный резолвер).
dns = "10.7.0.1"
# Split-tunnel: действие по умолчанию плюс точечные правила.
[tunnel.split]
default = "VPN"
[[tunnel.split.direct]]
cidr = "192.168.0.0/16"
[[tunnel.split.direct]]
cidr = "10.0.0.0/8"
[[tunnel.split.direct]]
domain = "intranet.example.com"
# Более узкий префикс возвращает поддиапазон обратно в VPN (longest-prefix бьёт /8).
[[tunnel.split.vpn]]
cidr = "10.7.0.0/24"
[mimicry]
padding = false
[transport]
# Порядок fallback'а (handover), пробуется слева направо: первый удавшийся побеждает.
# При отсутствии всей секции — ["udp","tcp","quic"] на 443/443/444.
order = ["udp", "tcp", "quic"]
udp_port = 443
tcp_port = 443
quic_port = 444
obfuscate = true
masquerade = true
```
Подробности про `[tunnel.split]` — в [`split-tunnel.md`](split-tunnel.md).
### 4.2. Запуск клиента
```bash
sudo aura client --config client.toml
```
`sudo` нужен для поднятия TUN-устройства. Клиент:
1. Загружает PEM-файлы из `[pki]` и строит `aura_proto::ClientConfig`.
2. Строит таблицу маршрутизации из `[tunnel.split]`.
3. Дозванивается до сервера, перебирая транспорты в `[transport] order`
(handover UDP → TCP → QUIC); первый, который удался, побеждает.
4. Разрезолвит доменные правила split-tunnel'а в host-маршруты (best-effort).
5. Создаёт TUN, передаёт его маршрутизатору и начинает гонять трафик.
В логе при успехе вы увидите строку с выбранным транспортом:
```
INFO connected and authenticated to server peer=Some("cdn.example.com") mode=udp
```
`mode` принимает значения `udp`, `tcp` или `quic`.
### 4.3. Управление на лету
После запуска клиента (или сервера) admin-сокет позволяет менять правила и смотреть статус без
перезапуска:
```bash
# Добавить CIDR на лету.
aura route add --cidr 8.8.8.0/24 --action direct
# Завернуть домен через VPN.
aura route add --domain example.com --action vpn
# Перечислить правила.
aura route list
# Удалить CIDR-правило.
aura route remove --cidr 8.8.8.0/24
# Статус и счётчики.
aura status
# Aura tunnel status
# peer: cdn.example.com
# default: vpn
# rules: 2
# rx packets: 0
# tx packets: 0
```
Если сокет лежит не там, добавьте `--admin-socket <PATH>` к каждой команде. Полная спецификация
команд и wire-протокола admin'а — в [`split-tunnel.md`](split-tunnel.md).
---
## 5. Что идёт по проводу (резюме)
- **Основной**: собственный UDP-транспорт Aura (в примере — `443/udp`). Один UDP-сокет несёт
обе фазы, различимые по первому байту:
- `0x01` HS — рукопожатие с надёжным DTLS-подобным слоем поверх (повторы, ack, упорядочивание);
- `0x02` DATA — датаграммы данных с explicit-nonce AEAD; обфускация = паддинг до «корзин»
HTTPS (`[64, 128, 256, 512, 1024, 1280, 1460]`).
- **Fallback TCP/443**: настоящий **outer TLS-443** (rustls) поверх TCP — на проводе неотличимо
от валидного HTTPS, ALPN `[h2, http/1.1]`. Внутри TLS — тот же Aura-handshake. Клиент
использует `AcceptAnyServerCert` (security гарантирует только внутренний Aura-handshake).
- **Fallback QUIC**: внешний TLS-камуфляж под HTTP/3 + внутреннее Aura-рукопожатие.
- Клиент пробует транспорты по `order`, переключается при отказе или таймауте подключения
(по умолчанию 8 с). Сервер слушает все включённые транспорты одновременно (`MultiServer`).
Подробный wire-протокол — в [`protocol.md`](protocol.md).
---
## 6. v2 — что устранено и что остаётся
### Устранено в v2 (по сравнению с v1)
-**Мульти-клиент UDP-сервер.** `UdpServer` теперь демультиплексирует датаграммы по адресу
пира: один сокет обслуживает много клиентов параллельно, каждый со своим `ReliableHsAdapter` и
своим `UdpConnection`. `MultiServer::accept` выдаёт по соединению на каждого нового клиента
(в любом из включённых транспортов).
-**IP-пул + per-client маршрутизация на сервере.** Новая секция `[server.pool]`
(`cidr`, `strategy`, `static`) выдаёт каждому клиенту IP при accept; `ServerRouter` держит
карту `client_ip → Arc<dyn PacketConnection>`, читает с TUN, диспатчит пакеты по `dst_ip` в
нужное подключение, а параллельные per-conn-задачи пишут входящий трафик обратно в TUN.
-**`send_direct` устранён.** Новое `[tunnel.os_routes]` (по умолчанию `enabled = true`)
программирует **системную таблицу маршрутов**: DIRECT-цели идут мимо TUN через изначальный
default-gateway, через TUN попадает только VPN-трафик. RAII-guard откатывает все добавленные
маршруты при остановке клиента.
-**Настоящий TLS-443 в TCP-транспорте.** Вместо лёгкой HTTP/1.1-преамбулы — полный outer
rustls handshake (ALPN `[h2, http/1.1]`); клиент с `AcceptAnyServerCert`, поэтому SNI на
внешнем слое не верифицируется (это камуфляж), а вся реальная аутентификация — внутри
Aura-рукопожатия. На проводе неотличимо от валидного HTTPS.
-**Авто-NAT на сервере.** `[server.nat] {auto, egress_iface, dry_run}` поднимает
IP-форвардинг + MASQUERADE на старте (Linux: `sysctl ip_forward` + `iptables -t nat
MASQUERADE`; macOS: `sysctl ip.forwarding` + `pfctl`). RAII-guard откатывает изменения при
остановке. Опциональный `dry_run = true` логирует команды без выполнения — для отладки.
-**Privilege drop.** `[server]/[client] run_as = "nobody"` — после поднятия TUN и
привилегированных портов euid/gid сбрасываются в нерутового пользователя (Linux:
`setresuid/setresgid`; macOS: `setgid` + `setuid` permanent drop). Минимизирует время
процесса под root.
-**Admin-сокет на Windows.** Cfg-gated транспорт: на Unix — Unix socket
(`/tmp/aura-admin.sock`), на Windows — Tokio named pipe (`\\.\pipe\aura-admin`).
JSON-протокол и команды (`route add/list/remove`, `status`) идентичны.
-**In-band CRL.** Сервер сразу после handshake пушит подписанный CA CRL клиенту
через мультиплексированный control-envelope с magic-префиксом
`[0xAA,0xAA,0xC0,0x01]` (не конфликтует с IPv4/v6, которые начинаются с
`0x4X`/`0x6X`). Клиент проверяет подпись ECDSA-P256 против CA, применяет к
`AuraCertVerifier`, кэширует на диск. Конфиг `[pki] crl_push = true` /
`accept_pushed_crl = true` (по умолчанию).
-**Анти-надзор v2 (NEW в ответ на дрегнет операторов):**
- **Port-knocking** на UDP-транспорте: сервер молчит на скан-зондах, отвечает
только на валидный 16-байтный HMAC-SHA256 «стук» с ±1-минутным окном (ключ
из CA fingerprint). Сканер видит закрытый порт. `[transport.knock]
enabled = true`.
- **Cover traffic / chaff**: при простое UDP-соединение шлёт `Ping` каждые
~500мс±50% (jitter). Defeats volume/timing-fingerprinting. Под нагрузкой
подавляется автоматически. `[transport.cover] enabled = true`.
-**Автоматизация развёртывания:**
- `aura server-init --domain ... --pki-dir ...` — одна команда: CA +
серверный cert + готовый `server.toml` (с авто-определением egress-iface).
- `aura provision-client --id <UUID> --out <dir>` — выпускает client cert и
собирает готовый бандл (`ca.crt` + `client.crt` + `client.key` +
`client.toml`). `--id` опционален — дефолт UUID v4 (имя пользователя не
привязано к сертификату).
-**Минимизация идентификаторов:**
- `[server] no_logs = true` / `[client] no_logs = true` — поля `peer_id`,
`client_ip`, `source_addr`, `client_id`, `local_ip`, `user`, `id`,
`assigned_ip` редактируются из tracing-вывода через field-level фильтр
(события фиксируются, идентификаторы вычищаются).
- `[client] bridges = [...]` — список запасных серверов, клиент пробует
случайный порядок. Блокировка одного IP не убивает доступ.
-**НОВОЕ: ежедневная ротация масок в 05:00 МСК.** Внешний фингерпринт (SNI/UA/Server-
header/UDP padding-профиль) детерминированно меняется раз в сутки. И сервер, и клиент
выводят одинаковый `MaskSet` из общего seed (SHA-256 от CA-сертификата) + UTC-даты через
HKDF-SHA256, без сетевой координации. Конфиг: `[transport.masks] enabled = true` (по
умолчанию). Новые подключения берут текущую маску; уже установленные остаются на своих.
Палитры: 16 SNI default + 15 SNI russian, 10 User-Agent, 5 Server-headers, 4 padding-профиля;
профиль 0 байт-в-байт совместим с v1-паддингом (бэк-совместимость). v3.2 добавляет
`palette = "default" | "russian" | "mixed"` для случая, когда нужно, чтобы outer SNI выглядел
как обращение к российскому сайту (см. сценарий в §7).
-**Multi-hop / onion routing v3.1 + v3.2.** Цепочка из 2-3 хопов: client →
entry-relay → (опционально middle) → exit. Entry-relay не знает destination, exit-узел не
знает клиентский IP. v3.2: per-hop client cert (CN entry и exit различаются — нельзя
слинковать handshakes по identity), cell padding (constant-size cells устраняют per-packet
size-fingerprinting), CIDR whitelist на relay'е. Конфиг — `[client.circuit]` /
`[server.relay]`. См. сценарий §7 для деплоймента «российский entry, иностранный exit».
-**Let's Encrypt outer-TLS cert.** `[server.outer_cert] cert_path / key_path` — outer-TLS
слой QUIC и TCP использует настоящий CA-trusted сертификат вместо self-signed Aura cert;
внутренний Aura mutual-auth handshake продолжает аутентификацию против Aura CA.
### v3.3 — Windows-as-client стал first-class
-**Windows OS-маршруты реализованы.** `[tunnel.os_routes] enabled = true` теперь работает
на Windows: `route ADD <net> MASK <mask> <gw> METRIC 1` для DIRECT-обходов, `netsh interface
ipv4 add route <prefix> "Aura" <tun_local_ip> store=active` для VPN-маршрутов через wintun-
адаптер. Дефолт-GW автодетектится через `route print 0`. Rollback подменяет `ADD``DELETE` и
`add``delete` на обоих путях. Подробности и пошаговый запуск — в §8.
-**wintun audit.** Найден и устранён баг: `Arc<wintun::Adapter>` больше не дропается раньше
`Session` (поле `_adapter` в `AuraTun` держит адаптер живым на всё время сессии).
-**Cross-compile.** Весь workspace проверен под `cargo check --target
x86_64-pc-windows-gnu` без warnings.
### Остающиеся честные ограничения
- **TUN всё ещё требует root / Администратор** для **создания** интерфейса (это OS-уровень). На
Linux/macOS privilege drop минимизирует окно работы под root; на Windows аналога нет — клиент
работает от Администратора до выхода (warning в логе).
- **IPv6 в OS-маршрутах и iptables MASQUERADE** не реализован — только IPv4 (план v3.4).
- **Windows-as-server не первоклассный.** `[server.nat]` (IP-форвардинг + MASQUERADE) на
Windows не реализован; роль сервера / relay лучше держать на Linux/macOS. Windows клиент
работает с любым сервером.
- **Нативного Go-клиента для телефона нет** — через sing-box (Option B нативный Go-outbound,
по `protocol.md` + KAT из Rust, см. [`sing-box.md`](sing-box.md)). Сейчас доступен только
десктоп-клиент / process-bridge. Это явно исключённый из v2 пункт.
- **Bridge-discovery без хардкода IP в конфиге** — план v3.3. Сейчас `[client] bridges`
хардкодит список запасных IP; если их все заблокируют (включая российские entry-узлы из
сценария §7), восстановление требует обновления конфига клиента вручную.
---
## 7. Сценарий: российский entry-узел против тарификации иностранного трафика
### 7.1. Контекст и угроза
Российские операторы связи могут начать тарифицировать «иностранный трафик» отдельно: классификация
выполняется по destination IP исходящего пакета пользователя. Если первый IP, к которому
обращается устройство, — российский, биллинг считает соединение «российским», даже если внутри
этого соединения трафик уходит дальше за рубеж. Цель в этом сценарии — добиться того, чтобы
оператор биллил трафик пользователя как «российский», при этом сохраняя VPN-выход за рубежом.
Решение опирается на три компонента, уже реализованные в AuraVPN:
1. **Multi-hop / onion routing v3.1+** (`[client.circuit]` / `[server.relay]`) — entry-узел в РФ
не знает destination, exit-узел за рубежом не знает клиентский IP.
2. **Палитра SNI «russian»** (v3.2) — `[transport.masks] palette = "russian"` ротирует outer-TLS
SNI среди крупных российских доменов (`vk.com`, `www.ozon.ru`, `mail.yandex.ru`, ...).
3. **OS-уровень kill-switch** (`[tunnel.os_routes] enabled = true`) — гарантия, что системный
трафик (push-уведомления, OS-сервисы) не обходит туннель и не попадает напрямую к иностранным
серверам в обход entry-узла.
### 7.2. Топология
```
[устройство]
|
| весь трафик через TUN (kill-switch)
v
[оператор] <-- видит только UDP/443 на RU_VPS_IP, SNI = "vk.com"
|
v
[Russian VPS / entry-relay] <-- v3.1 relay: forward to next hop, never decodes IP packets
|
| inner Aura handshake (PQ-encrypted, opaque)
v
[Foreign VPS / exit] <-- настоящий VPN-выход в интернет
|
v
[internet]
```
Оператор видит только трафик до **entry-узла**: один UDP-поток с SNI крупного российского сайта.
Внутри этого потока — зашифрованный многохоп; entry-relay не имеет ключей внутреннего рукопожатия
и видит только AEAD-ciphertext, который он форвардит на exit. Exit видит только IP entry-узла, а
не IP клиентского устройства.
### 7.3. Что покупать
**Подходящие провайдеры для entry-узла в РФ** (юрисдикция РФ, IP в российских AS):
- **Selectel** (Москва, СПб).
- **Beget** (СПб).
- **Yandex.Cloud** (Москва).
- **VK Cloud** (бывш. Mail.ru Cloud Solutions).
- **Timeweb Cloud**.
**Неподходящие для роли entry-узла в РФ**:
- **Hetzner** (Германия/Финляндия) — IP классифицируется как «иностранный».
- **DigitalOcean / Vultr / Linode** (США/EU) — то же самое.
- **AWS / GCP / Azure** даже с российскими DC-локациями — IP-блоки за пределами российских AS у
большинства операторов.
Для **exit-узла** наоборот — берите любой удобный иностранный VPS (Hetzner, DigitalOcean, Vultr,
любой подходящий по юрисдикции и пропускной способности).
### 7.4. Конфиг сервера в РФ (entry-relay)
`server.toml` на российском VPS (например, Selectel с IP `RUSSIAN_VPS_IP`):
```toml
[server]
name = "aura-ru-entry-1"
listen = "0.0.0.0:443"
[pki]
ca_cert = "/etc/aura/pki/ca.crt"
cert = "/etc/aura/pki/server/server.crt"
key = "/etc/aura/pki/server/server.key"
[tunnel]
# Pool нужен формально (для v1-fallback-пути), но в роли чистого relay он не используется —
# bridged-клиенты не получают IP из пула и не регистрируются в ServerRouter.
pool_cidr = "10.7.0.0/24"
mtu = 1420
# v3.1: relay-режим. Принимаем ExtendBridge от клиента и сплайсим на foreign exit.
[server.relay]
enabled = true
allow_extend_to = ["EXIT_FOREIGN_IP:443"] # IP вашего иностранного exit-узла
# v3.2 cell padding: relay сам не декодирует — это сквозной байт-форвардинг. Знаки опции тут
# для симметрии конфига; реальный декод цельных ячеек — на exit'е.
cell_padding = true
cell_size = 1280
[transport.masks]
enabled = true
# v3.2: outer-TLS SNI крутится среди крупных российских доменов. Каждый день — другой домен.
palette = "russian"
# Опционально: настоящий outer-TLS сертификат (Let's Encrypt) поверх UDP/QUIC и TCP. Без него
# работает self-signed Aura, но с настоящим LE-сертификатом outer-handshake становится
# неотличим от обычного HTTPS на CA-trusted сайт.
[server.outer_cert]
cert_path = "/etc/letsencrypt/live/relay.example.ru/fullchain.pem"
key_path = "/etc/letsencrypt/live/relay.example.ru/privkey.pem"
```
И аналогичный `server.toml` на **иностранном exit-узле** — обычный VPN-сервер БЕЗ `[server.relay]`,
но с `cell_padding_for_circuit_clients = true` в секции `[server]`, чтобы он понимал
constant-size cells от клиента:
```toml
[server]
name = "aura-exit-1"
listen = "0.0.0.0:443"
# v3.2: exit для cell-padded клиентов — декодирует ячейки внутреннего рукопожатия.
cell_padding_for_circuit_clients = true
[pki]
ca_cert = "/etc/aura/pki/ca.crt"
cert = "/etc/aura/pki/server/exit.crt"
key = "/etc/aura/pki/server/exit.key"
[tunnel]
pool_cidr = "10.7.0.0/24"
[server.nat]
auto = true # включить IP-форвардинг и MASQUERADE на egress-интерфейсе
egress_iface = "eth0"
[transport.masks]
# На exit'е SNI палитра не критична (клиент видит exit только через relay) — оставим default.
palette = "default"
```
### 7.5. Конфиг клиента
```toml
[client]
name = "laptop"
server_addr = "RUSSIAN_VPS_IP:443" # entry-узел в РФ; именно этот IP видит оператор
sni = "relay.example.ru" # SAN серверного outer-TLS сертификата (если есть LE)
[pki]
ca_cert = "~/.aura/ca.crt"
cert = "~/.aura/client.crt"
key = "~/.aura/client.key"
[tunnel]
tun_name = "aura0"
local_ip = "10.7.0.2"
prefix = 24
mtu = 1420
[tunnel.split]
default = "VPN"
# КРИТИЧНО: kill-switch — весь трафик через TUN, OS-уровень. Без этого push-уведомления и
# OS-сервисы могут уйти напрямую в иностранные сервера в обход entry-узла, и оператор
# зачтёт это как «иностранный» трафик.
[tunnel.os_routes]
enabled = true
# v3.1 / v3.2: цепочка хопов client -> RU_entry -> foreign_exit.
[client.circuit]
enabled = true
cell_padding = true
cell_size = 1280
[[client.circuit.hops]]
addr = "RUSSIAN_VPS_IP:443" # entry в РФ — то, что видит оператор
cert_path = "~/.aura/circuit/entry.crt"
key_path = "~/.aura/circuit/entry.key"
[[client.circuit.hops]]
addr = "EXIT_FOREIGN_IP:443" # exit за рубежом, к которому привязаны DNS/маршруты внутри VPN
cert_path = "~/.aura/circuit/exit.crt"
key_path = "~/.aura/circuit/exit.key"
[transport.masks]
enabled = true
# Должно совпадать с palette = "russian" на entry-узле — иначе SNI в логах двух сторон
# не будут симметричны (на проводе это не ошибка, но удобнее для отладки).
palette = "russian"
```
Сертификаты двух хопов — разные (`entry.crt` != `exit.crt`). Это v3.2 identity-unlinkability:
entry-relay видит только клиентский cert для роли entry, exit-узел видит только cert для роли
exit, и они не пересекаются (см. `aura provision-client --circuit-hops 2 ...`).
### 7.6. Что это даёт
- **Оператор биллит как «российский».** На проводе оператор видит один UDP-поток на
`RUSSIAN_VPS_IP:443` — это российский IP в российской AS, классификатор биллинга его не
обозначает как иностранный.
- **SNI выглядит как обращение к российскому сайту.** В пакетах outer-TLS / outer-QUIC
hostname-камуфляж берётся из `SNI_PALETTE_RUSSIAN`: каждый день — другой домен (`vk.com`,
`www.ozon.ru`, `mail.yandex.ru`, ...). DPI видит «нормальный HTTPS на крупный российский
сайт».
- **Реальный VPN-выход — за рубежом.** Внутри multi-hop клиент дозванивается до иностранного
exit-узла; именно его IP видят внешние ресурсы. Entry-узел в РФ форвардит зашифрованный
трафик, не зная destination и не имея ключей внутреннего рукопожатия.
- **Kill-switch предотвращает обход.** `[tunnel.os_routes] enabled = true` программирует
системную таблицу маршрутов так, что весь трафик идёт через TUN — push-уведомления, OS-сервисы
и любые «прямые» обращения в обход VPN заблокированы, поэтому ничто из устройства не уйдёт
напрямую к иностранному IP в обход entry-узла.
### 7.7. Что это НЕ даёт (честное ограничение)
- **Не скрывает сам факт VPN-использования** от российских органов. DPI с deep-inspection может
по статистическим паттернам трафика (timing, размеры, поведение в течение сессии) узнать
Aura-протокол; ротация масок и `palette = "russian"` маскирует пассивного наблюдателя, но не
активного аналитика. Для дополнительной защиты включайте `[transport.knock]` и
`[transport.cover]` (port-knocking + cover traffic).
- **Не освобождает от ответственности за заходы на запрещённые ресурсы.** Кто и за что отвечает
при заходе на запрещённый ресурс через VPN — вопрос юрисдикции exit-узла и применимого
законодательства, не технический.
- **Не защищает от блокировки самого entry-IP.** Если СОРМ-система или Роскомнадзор начнут
активно блокировать конкретные VPS-IP, придётся ротировать IP / bridges. Сейчас это решается
через `[client] bridges = [...]` — список запасных российских entry-узлов; клиент пробует их
в случайном порядке при отказе primary. Полноценный bridge-discovery (без хардкода IP в
конфиге) — план v3.3.
- **Cell padding не скрывает наличие туннеля.** Constant-size cells устраняют per-packet
size-fingerprinting внутри multi-hop, но не делают сам поток неотличимым от HTTPS — общий
объём и временные паттерны остаются. Это компромисс между обфускацией и накладными расходами.
### 7.8. Что менять при ротации
При смене IP entry-узла (например, при блокировке текущего) обновите три места:
1. `[[client.circuit.hops]] addr` первого хопа → новый `RUSSIAN_VPS_IP:443`.
2. `[client] server_addr` → тот же новый IP.
3. На новом VPS — поднять PKI, выпустить cert для entry-роли, перенести `server.toml` с
`[server.relay]` и `palette = "russian"`.
Перевыпускать сертификаты двух хопов не нужно — они остаются те же, меняется только wire-адрес
entry-узла. На сертификате entry-сервера должен быть SAN, совпадающий с `[client] sni`
(см. `aura pki issue-server --domain relay.example.ru`).
---
## 8. Windows как клиент
Windows-клиент стал first-class в v3.3. Сервер на Windows не поддерживается на уровне
автонастройки сети — `[server.nat]` (IP-форвардинг + MASQUERADE) реализован только для
Linux/macOS. Эта секция — про **клиент**.
### 8.1. Требования
- Windows 10 / 11 (или Server 2019+) с правами **Администратора** для процесса `aura.exe` —
поднятие wintun-адаптера и программирование таблицы маршрутов требуют привилегий.
- **wintun.dll** рядом с `aura.exe`. Скачать с официального сайта
[https://www.wintun.net/](https://www.wintun.net/) (драйвер от автора WireGuard);
распаковать `wintun/bin/amd64/wintun.dll` в каталог `aura.exe`.
### 8.2. Сборка / получение бинаря
Если у вас есть Rust toolchain на Windows — `cargo build --release` соберёт `target\release\aura.exe`.
С macOS / Linux можно собрать кросс-компиляцией (нужен mingw-w64):
```bash
rustup target add x86_64-pc-windows-gnu
# (на macOS) brew install mingw-w64
cargo build --release --target x86_64-pc-windows-gnu
# -> target/x86_64-pc-windows-gnu/release/aura.exe
```
### 8.3. PKI и провижининг
Команды `aura.exe pki ...` и `aura.exe provision-client ...` работают идентично Unix-версии
(см. §2.2). Бандл для клиента — те же три PEM-файла (`ca.crt`, `client.crt`, `client.key`)
плюс `client.toml`. PowerShell-форма:
```powershell
.\aura.exe pki init --ca-name "Aura Root CA" --out C:\ProgramData\Aura\pki
.\aura.exe pki issue-server --domain vpn.example.com --out C:\ProgramData\Aura\pki\server `
--ca C:\ProgramData\Aura\pki
.\aura.exe provision-client --id laptop-1 --out C:\Users\me\.aura
```
### 8.4. `client.toml` на Windows
Раскладка идентична §4.1. Имя TUN — это **отображаемое имя wintun-адаптера**: указанное в
`tun_name` имя становится `Display Name` адаптера в Device Manager (а также используется в
командах `netsh interface ipv4 add route ... "Aura"` — см. §8.5).
```toml
[client]
name = "laptop"
server_addr = "203.0.113.10:443"
sni = "vpn.example.com"
# run_as на Windows — no-op (нет аналога setresuid; warning в логе).
[pki]
ca_cert = "C:\\Users\\me\\.aura\\ca.crt"
cert = "C:\\Users\\me\\.aura\\client.crt"
key = "C:\\Users\\me\\.aura\\client.key"
[tunnel]
tun_name = "Aura" # имя wintun-адаптера; то же имя используется в netsh-командах ниже
local_ip = "10.7.0.2"
prefix = 24
mtu = 1420
[tunnel.split]
default = "VPN"
[[tunnel.split.direct]]
cidr = "192.168.0.0/16"
# v3.3: OS-уровень kill-switch теперь работает на Windows.
[tunnel.os_routes]
enabled = true
# Опционально: pin gateway + interface IP (читается `route print 0` если не задано).
# gateway = "192.168.1.1"
# egress_iface = "192.168.1.42"
[transport]
order = ["udp", "tcp", "quic"]
udp_port = 443
tcp_port = 443
quic_port = 444
```
### 8.5. Что делает `[tunnel.os_routes]` на Windows
На Linux/macOS клиент программирует системную таблицу маршрутов через `ip` / `route`. На
Windows — через `route ADD` (для DIRECT-обходов через исходный default-GW) и `netsh interface
ipv4 add route` (для VPN-маршрутов через wintun-адаптер).
**Auto-detect default GW:** клиент выполняет `route print 0` и парсит row `0.0.0.0 0.0.0.0
<gw> <interface_ip> <metric>` из IPv4 Active Routes. Если автодетект не сработал (например,
у машины несколько NIC и нет default'а в IPv4-таблице) — задайте `gateway` и `egress_iface`
явно в `[tunnel.os_routes]`. На Windows `egress_iface` — это **IP** upstream-интерфейса
(не имя), как в колонке `Interface` в `route print`.
**Что реально выполняется** (с пулом DIRECT `192.168.0.0/16` и default = VPN):
```
netsh interface ipv4 add route 0.0.0.0/0 "Aura" 10.7.0.2 store=active
route ADD 192.168.0.0 MASK 255.255.0.0 192.168.1.1 METRIC 1
```
**Что выполняется при выходе клиента** (Drop порядка LIFO):
```
route DELETE 192.168.0.0 MASK 255.255.0.0
netsh interface ipv4 delete route 0.0.0.0/0 "Aura"
```
`store=active` указывает Windows не сохранять маршрут в персистентном store — он привязан к
TUN, который исчезает на выходе клиента. Параметр `METRIC 1` обеспечивает приоритет
DIRECT-обхода над любыми существующими маршрутами с большей метрикой.
### 8.6. Запуск
PowerShell как Администратор:
```powershell
cd C:\Aura
.\aura.exe client --config .\client.toml
```
В логе при успехе:
```
INFO connected and authenticated to server peer=Some("vpn.example.com") mode=udp
INFO OS-level split-tunnel routes installed (DIRECT traffic now bypasses the TUN)
INFO running: netsh interface ipv4 add route 0.0.0.0/0 "Aura" 10.7.0.2 store=active
INFO running: route ADD 192.168.0.0 MASK 255.255.0.0 192.168.1.1 METRIC 1
```
Прервать через `Ctrl+C` — выводящийся guard корректно вызывает `route DELETE` / `netsh ...
delete route` и затем закрывает wintun-сессию + адаптер (см. §8.7).
### 8.7. Cleanup на Windows (что происходит при остановке клиента)
Порядок dropping:
1. **OsRouteGuard::drop** — выполняет rollback-команды в LIFO-порядке (`route DELETE ...`,
затем `netsh ... delete route ...`). Ошибки логируются warn-ом, дальнейший rollback
продолжается — один сбойный шаг не остановит зачистку остальных маршрутов.
2. **wintun::Session::drop**`WintunEndSession` завершает сессию (закрывает ring buffer).
3. **wintun::Adapter::drop**`WintunCloseAdapter` снимает адаптер с системы. Drop порядка
полей в `AuraTun` гарантирует, что Session завершается до Adapter (поле `inner` объявлено
раньше `_adapter`).
Если процесс упал без graceful shutdown (kill -9 / BSOD): wintun-адаптер останется
зарегистрированным в системе, и при следующем запуске `Adapter::create` найдёт его по имени и
переиспользует. Орфанных системных маршрутов в персистентном store не будет — все наши
маршруты идут через `store=active`, которые система очищает на reboot.
### 8.8. Известные ограничения Windows-клиента
- **`run_as`** на Windows — no-op. Аналога `setresuid` для безпрепятственного drop'а к
service-account во время работы нет; рекомендация — запустить `aura.exe` как Windows
Service от выделенной учётной записи (см. документацию `sc.exe create`), либо просто из
PowerShell-сессии Администратора.
- **`[server.nat]`** на Windows не реализован — Windows-as-server не первоклассный сценарий.
Используйте Linux/macOS для роли сервера / relay.
- **IPv6 routes** программируются через `netsh interface ipv6 add route` для VPN, но IPv6
DIRECT-обходы попадают в тот же `netsh ipv6` путь (а не в IPv4-only `route ADD`). Для
чистой IPv4-only установки это не имеет значения.
- **Mixed-mode** (часть транспортов в одну сеть, часть в другую) на Windows не тестировался
глубоко — `netsh ... store=active` маршруты могут конфликтовать с существующими VPN-
клиентами (WireGuard, OpenVPN) если те уже захватили default-route. Отключите конкурирующие
VPN перед запуском aura-клиента.