docs: rewrite all documentation in Russian + add deployment guide

- docs/protocol.md, pki.md, split-tunnel.md, sing-box.md переведены на русский
  и сверены с текущим кодом (транспорт v2: свой UDP + TCP/443 + QUIC fallback,
  handover; PKI; split-tunnel; sing-box-план).
- docs/deployment.md (новый, 369 строк): пошаговое руководство для удалённого
  сервера — сборка, PKI init/issue-server/issue-client (проверено бинарём),
  server.toml/client.toml на основе фактических config/*.example, firewall +
  NAT/IP-форвардинг, sudo-запуск, бандл клиента (ca.crt + client.crt + client.key
  + server addr/sni), на каком транспорте идёт трафик, ограничения v1.
- README.md (новый, корень): краткий обзор + таблица крейтов + быстрый старт.

Всё на русском (проза); команды/идентификаторы/конфиги — как есть.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
xah30
2026-05-26 10:42:08 +03:00
parent d5b9a8611d
commit 083c441e4c
6 changed files with 1075 additions and 515 deletions
+119 -115
View File
@@ -1,121 +1,124 @@
# Aura Split Tunnel
# Split tunnel Aura
Split tunneling decides, per destination IP, whether a packet travels **through the encrypted
VPN** or **egresses directly** (bypassing the tunnel). It lets you keep, say, RFC1918 LAN
traffic local while sending the rest through Aura — or the reverse.
Split-tunneling решает для каждого назначения IP, идёт ли пакет **через шифрованный VPN** или
**уходит напрямую** (минуя туннель). Это позволяет, например, оставить трафик к RFC1918-сетям
локальным, а остальное пустить через Aura — или наоборот.
It is implemented in the `aura-tunnel` crate (`routes.rs`, `router.rs`, `dns.rs`), configured
statically via the `[tunnel.split]` section of `client.toml`
(`crates/aura-cli/src/config.rs`), and managed live via the `aura route` / `aura status`
admin commands (`crates/aura-cli/src/admin.rs`).
Реализация лежит в крейте `aura-tunnel` (`routes.rs`, `router.rs`, `dns.rs`), статически
настраивается секцией `[tunnel.split]` в `client.toml` (`crates/aura-cli/src/config.rs`), а
управляется на лету командами `aura route` / `aura status` через admin-сокет
(`crates/aura-cli/src/admin.rs`).
---
## Concept: VPN vs DIRECT
## Концепция: VPN или DIRECT
Every outbound IP packet read from the TUN device is classified into one of two actions
Каждый исходящий IP-пакет, прочитанный с TUN-устройства, классифицируется в одно из двух действий
(`RouteAction`):
- **`Vpn`** — encrypt and send the packet over the Aura connection to the server.
- **`Direct`** — let the packet egress directly, bypassing the tunnel.
- **`Vpn`** — зашифровать и отправить пакет по соединению Aura на сервер.
- **`Direct`** — выпустить пакет напрямую, минуя туннель.
The router (`AuraRouter::run`, `router.rs`) parses each packet's destination IP, classifies
it, and dispatches:
Маршрутизатор (`AuraRouter::run`, `router.rs`) парсит у каждого пакета IP назначения,
классифицирует его и диспетчеризует:
```
TUN read --> parse dst IP --> RouteTable.classify(dst) --> Vpn? -> conn.send_packet()
\ Direct? -> send_direct() (v1 stub)
\ Direct? -> send_direct() (заглушка в v1)
```
> **v1 limitation — `Direct` is a stub.** `send_direct` currently **logs and drops** the
> packet; real raw-socket / OS-stack re-injection is out of scope for v1. The method is
> already `async` and fallible so a real egress path can slot in without changing call sites.
> The VPN path is fully functional end-to-end. Packets whose destination cannot be parsed
> (not IPv4/IPv6, or too short) are dropped with a trace.
> **Ограничение v1 — `Direct` это заглушка.** Текущая реализация `send_direct` **логирует и
> отбрасывает** пакет; реальный raw-socket / реинъекция в стек ОС в объём v1 не входят. Метод уже
> объявлен `async` и возвращает `Result`, чтобы реальный путь egress подключился без изменения
> вызывающего кода. Путь через VPN полностью работоспособен сквозным образом. Пакеты, у которых
> не получилось разобрать назначение (не IPv4/IPv6 или слишком короткие), отбрасываются с trace-
> сообщением.
The inbound direction is straightforward: decrypted IP packets received from the peer are
written back to the TUN device.
Входящее направление прямолинейно: расшифрованные IP-пакеты, полученные от пира, пишутся обратно
на TUN-устройство.
---
## Rules
## Правила
The routing table (`RouteTable`, `routes.rs`) holds three things: a set of **CIDR rules**, a
set of **domain rules**, and a **default action**.
Таблица маршрутизации (`RouteTable`, `routes.rs`) хранит три вещи: набор **CIDR-правил**, набор
**доменных правил** и **действие по умолчанию**.
### CIDR rules
### CIDR-правила
A CIDR rule is an `IpNetwork` (e.g. `10.0.0.0/8`) plus an action. CIDR rules are keyed by
network, so re-adding the same network **overwrites** its action.
CIDR-правило — это `IpNetwork` (например `10.0.0.0/8`) плюс действие. CIDR-правила
ключуются сетью, поэтому повторное добавление той же сети **перезаписывает** её действие.
### Domain rules
### Доменные правила
A domain rule is a domain name plus an action. Domains do **not** match IPs directly. Instead
`AuraDns` (`dns.rs`) resolves the domain via the system resolver (hickory) and inserts each
resulting address as a **host route**`/32` for IPv4, `/128` for IPv6 — so it participates
in the normal longest-prefix match. Resolution results are cached.
Доменное правило — это доменное имя плюс действие. Домены **не** сопоставляются с IP напрямую.
Вместо этого `AuraDns` (`dns.rs`) резолвит домен через системный резолвер (hickory) и вставляет
каждый получившийся адрес как **host-маршрут**`/32` для IPv4, `/128` для IPv6,так что они
участвуют в обычном longest-prefix matching. Результаты резолва кэшируются.
> Because domain rules become host routes at resolution time, they only take effect once the
> domain has been resolved (at startup, or on demand). They reflect the addresses seen at
> resolution time and are not continuously re-resolved in v1.
> Поскольку доменные правила становятся host-маршрутами в момент резолва, они действуют только
> после того, как домен был разрешён (при старте или по требованию). Они отражают адреса,
> увиденные в момент резолва, и не перерезолвятся непрерывно в v1.
### Default action
### Действие по умолчанию
If no CIDR rule (including resolved domain host routes) matches a destination, the table's
**default action** applies.
Если ни одно CIDR-правило (включая host-маршруты от резолва доменов) не совпало с назначением,
применяется **действие по умолчанию** таблицы.
---
## Longest-prefix precedence
## Приоритет longest-prefix
`classify(dst_ip)` performs a **longest-prefix match** (`routes.rs`):
`classify(dst_ip)` выполняет **longest-prefix match** (`routes.rs`):
> Among all CIDR rules whose network contains the destination, the rule with the **largest
> prefix length** (most specific) wins. If no rule matches, the default action is returned.
> Среди всех CIDR-правил, чьи сети содержат назначение, побеждает правило с **наибольшей длиной
> префикса** (наиболее специфичное). Если ни одно правило не совпало, возвращается действие по
> умолчанию.
This lets a specific range override a broader one regardless of insertion order. IPv4 rules
only match IPv4 destinations and IPv6 rules only match IPv6 destinations.
Так специфичный диапазон может перекрыть более широкий независимо от порядка вставки. IPv4-правила
совпадают только с IPv4-назначениями, а IPv6 — только с IPv6.
Example (from the shipped config): with `default = VPN`, `10.0.0.0/8 = Direct`, and
Пример (из поставляемой конфигурации): при `default = VPN`, `10.0.0.0/8 = Direct` и
`10.7.0.0/24 = Vpn`:
| Destination | Matched rule | Action |
|--------------|----------------------|--------|
| `10.1.2.3` | `10.0.0.0/8` | Direct |
| `10.7.0.9` | `10.7.0.0/24` (more specific, wins over `/8`) | Vpn |
| `192.168.1.1`| `192.168.0.0/16` | Direct |
| `8.8.8.8` | (none) → default | Vpn |
| Назначение | Сработавшее правило | Действие |
|--------------|----------------------------------------------|----------|
| `10.1.2.3` | `10.0.0.0/8` | Direct |
| `10.7.0.9` | `10.7.0.0/24` (более специфичное, бьёт `/8`) | Vpn |
| `192.168.1.1`| `192.168.0.0/16` | Direct |
| `8.8.8.8` | (нет) → действие по умолчанию | Vpn |
> Edge case: if two rules share the **same** prefix length, the **last-inserted** one wins
> (it overwrites the earlier entry, since rules are keyed by network).
> Крайний случай: если два правила имеют **одинаковую** длину префикса, побеждает
> **вставленное последним** (оно перезатирает предыдущее, потому что правила ключуются сетью).
---
## Static config: `[tunnel.split]`
## Статическая конфигурация: `[tunnel.split]`
The split tunnel is configured in `client.toml` under `[tunnel.split]`
(`crates/aura-cli/src/config.rs`). `build_route_table` turns it into a `RouteTable`: CIDR
rules are applied directly; domain rules are recorded and returned for the client to resolve
at startup.
Split-tunnel настраивается в `client.toml` в секции `[tunnel.split]`
(`crates/aura-cli/src/config.rs`). `build_route_table` превращает её в `RouteTable`: CIDR-правила
применяются напрямую; доменные правила сохраняются и возвращаются, чтобы клиент мог разрезолвить
их на старте.
### Schema
### Схема
| Key | Type | Default | Meaning |
|------------------------------|-----------------|---------|----------------------------------------------------|
| `default` | string | `"VPN"` | Action when no rule matches: `VPN` / `DIRECT` (case-insensitive) |
| `[[tunnel.split.direct]]` | array of rules | `[]` | Rules forcing matching destinations to **Direct** |
| `[[tunnel.split.vpn]]` | array of rules | `[]` | Rules forcing matching destinations through the **VPN** |
| Ключ | Тип | По умолчанию | Смысл |
|------------------------------|---------------------|--------------|------------------------------------------------|
| `default` | строка | `"VPN"` | Действие, когда ни одно правило не совпало: `VPN` / `DIRECT` (регистронезависимо) |
| `[[tunnel.split.direct]]` | массив правил | `[]` | Правила, отправляющие совпавшие назначения в **Direct** |
| `[[tunnel.split.vpn]]` | массив правил | `[]` | Правила, отправляющие совпавшие назначения **через VPN** |
Each rule in `direct` / `vpn` is a table with **exactly one** of:
Каждое правило в `direct` / `vpn` — это таблица с **ровно одним** из ключей:
| Key | Type | Example |
|----------|--------|---------------------|
| `cidr` | string | `"192.168.0.0/16"` |
| `domain` | string | `"intranet.example.com"` |
| Ключ | Тип | Пример |
|----------|--------|--------------------------|
| `cidr` | строка | `"192.168.0.0/16"` |
| `domain` | строка | `"intranet.example.com"` |
A rule with both `cidr` and `domain`, or neither, is rejected when the route table is built.
Правило, у которого указаны и `cidr`, и `domain` (или ни того ни другого), отвергается на этапе
построения таблицы маршрутизации.
### Example
### Пример
```toml
# Split-tunnel routing: the default action plus per-destination overrides.
@@ -139,23 +142,23 @@ domain = "intranet.example.com"
cidr = "10.7.0.0/24"
```
This is the configuration shipped in `config/client.toml.example`.
Это и есть та конфигурация, что поставляется в `config/client.toml.example`.
---
## Live management: `aura route` / `aura status`
## Управление на лету: `aura route` / `aura status`
A running `aura client` (or `aura server`) hosts an **admin socket**a tiny JSON
line-protocol over a **Unix domain socket** (`crates/aura-cli/src/admin.rs`). The `aura
route` and `aura status` subcommands connect to it to inspect and mutate the live routing
table without restarting the tunnel. The default socket path is `/tmp/aura-admin.sock`
(override with `--admin-socket`).
Работающий `aura client` (или `aura server`) поднимает **admin-сокет**крошечный построчный
JSON-протокол поверх **Unix domain socket** (`crates/aura-cli/src/admin.rs`). Подкоманды `aura
route` и `aura status` подключаются к нему, чтобы инспектировать и менять живую таблицу
маршрутизации, не перезапуская туннель. Путь сокета по умолчанию — `/tmp/aura-admin.sock`
(перекрывается через `--admin-socket`).
> Platform note: the admin socket uses Unix domain sockets (Linux/macOS). On Windows it is a
> `cfg`-gated stub that returns an explanatory error (a named-pipe transport is future work),
> so the rest of the CLI still compiles there.
> Замечание про платформу: admin-сокет использует Unix domain sockets (Linux/macOS). На Windows
> это `cfg`-заглушка, возвращающая поясняющую ошибку (named-pipe-транспорт — будущая работа), —
> остальная часть CLI там по-прежнему собирается.
### Commands
### Команды
```
aura route add (--cidr <CIDR> | --domain <DOMAIN>) --action <vpn|direct> [--admin-socket <PATH>]
@@ -164,29 +167,29 @@ aura route remove --cidr <CIDR> [--a
aura status [--admin-socket <PATH>]
```
`route add` takes **exactly one** of `--cidr` / `--domain` (they are mutually exclusive, and
one is required), plus `--action vpn` or `--action direct`.
`route add` принимает **ровно один** из ключей `--cidr` / `--domain` (они взаимоисключающие, и
один из них обязателен), плюс `--action vpn` или `--action direct`.
```bash
# Send a CIDR directly, live.
# Отправить CIDR напрямую, на лету.
aura route add --cidr 8.8.8.0/24 --action direct
# ok
# Route a domain through the VPN (resolved into host routes).
# Завернуть домен через VPN (разрезолвится в host-маршруты).
aura route add --domain example.com --action vpn
# ok
# Inspect the current rules and default.
# Посмотреть текущие правила и действие по умолчанию.
aura route list
# default: vpn
# cidr 8.8.8.0/24 direct
# domain example.com vpn
# Remove a CIDR rule.
# Удалить CIDR-правило.
aura route remove --cidr 8.8.8.0/24
# ok (removed) # or: "ok (nothing to remove)" if it wasn't present
# ok (removed) # или: "ok (nothing to remove)", если его не было
# Tunnel status / counters.
# Статус туннеля и счётчики.
aura status
# Aura tunnel status
# peer: client-1
@@ -196,22 +199,23 @@ aura status
# tx packets: 0
```
### Behavior notes
### Особенности поведения
- **`route remove` only removes CIDR rules** — it takes `--cidr` and has no domain form. The
library `RouteTable` has no per-rule remove API, so a removal **rebuilds** the table from
the surviving rules (preserving the default). Domain rules are re-added on rebuild, but
their previously resolved host routes are dropped and re-resolved on demand.
- **`route list` enumerates a rule mirror.** The live `RouteTable` is the source of truth for
classification but does not expose iteration, so the admin layer keeps a parallel mirror in
lockstep with every mutation; `list` echoes that mirror while `classify` still uses the real
table.
- **`status`** reports the verified peer id, the default action, the total rule count
(CIDR + domain), and inbound/outbound packet counters.
- **`route remove` удаляет только CIDR-правила** — он принимает `--cidr` и не имеет доменной
формы. У библиотечного `RouteTable` нет API для покнопочного удаления, поэтому удаление
**перестраивает** таблицу из оставшихся правил (с сохранением действия по умолчанию). Доменные
правила добавляются заново при перестройке, но их ранее разрезолвенные host-маршруты
сбрасываются и перерезолвятся по требованию.
- **`route list` перечисляет зеркало правил.** Истиной для классификации остаётся живой
`RouteTable`, но он не отдаёт итерацию по правилам, поэтому admin-слой ведёт параллельное
зеркало, синхронизированное с каждой мутацией; `list` отдаёт это зеркало, а `classify`
по-прежнему ходит в реальную таблицу.
- **`status`** сообщает проверенный peer id, действие по умолчанию, суммарное число правил
(CIDR + домены), а также счётчики пакетов на вход/выход.
### Wire protocol (for reference)
### Wire-протокол (для справки)
One JSON object per line, request then response (`crates/aura-cli/src/admin.rs`):
По одному JSON-объекту в строке: сначала запрос, затем ответ (`crates/aura-cli/src/admin.rs`):
```text
-> {"cmd":"route_add","cidr":"8.8.8.0/24","action":"direct"}
@@ -224,18 +228,18 @@ One JSON object per line, request then response (`crates/aura-cli/src/admin.rs`)
<- {"ok":true,"peer_id":"client-1","rx_packets":0,"tx_packets":0,"default":"vpn","rules":1}
```
On error the response is `{"ok":false,"error":"..."}`.
При ошибке ответ имеет вид `{"ok":false,"error":"..."}`.
---
## v1 limitations summary
## Сводка ограничений v1
- **`Direct` egress is a stub** — `Direct` packets are logged and dropped, not re-injected to
the OS stack. The VPN path is fully functional.
- **Domain rules are resolved once** (at startup / on demand) into host routes; no continuous
re-resolution.
- **`route remove` is CIDR-only** and rebuilds the table (domain host routes are re-resolved
on demand afterward).
- **Admin socket is Unix-only**; Windows is a `cfg`-gated stub.
- The server is a **single shared TUN** in v1, and the tunnel resolver `dns` config field is
informational (the system resolver is used).
- **`Direct` — заглушка**: пакеты с действием `Direct` логируются и отбрасываются, а не
реинъецируются в стек ОС. Путь через VPN полностью функционален.
- **Доменные правила резолвятся один раз** (на старте или по требованию) в host-маршруты;
непрерывного перерезолва нет.
- **`route remove` работает только с CIDR** и перестраивает таблицу (доменные host-маршруты потом
разрезолвятся по требованию).
- **Admin-сокет только под Unix**; на Windows `cfg`-заглушка.
- Сервер в v1 — это **один общий TUN**, а поле `dns` в конфигурации туннеля носит информационный
характер (используется системный резолвер).