- 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>
14 KiB
Split tunnel Aura
Split-tunneling решает для каждого назначения IP, идёт ли пакет через шифрованный VPN или уходит напрямую (минуя туннель). Это позволяет, например, оставить трафик к RFC1918-сетям локальным, а остальное пустить через Aura — или наоборот.
Реализация лежит в крейте 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).
Концепция: VPN или DIRECT
Каждый исходящий IP-пакет, прочитанный с TUN-устройства, классифицируется в одно из двух действий
(RouteAction):
Vpn— зашифровать и отправить пакет по соединению Aura на сервер.Direct— выпустить пакет напрямую, минуя туннель.
Маршрутизатор (AuraRouter::run, router.rs) парсит у каждого пакета IP назначения,
классифицирует его и диспетчеризует:
TUN read --> parse dst IP --> RouteTable.classify(dst) --> Vpn? -> conn.send_packet()
\ Direct? -> send_direct() (заглушка в v1)
Ограничение v1 —
Directэто заглушка. Текущая реализацияsend_directлогирует и отбрасывает пакет; реальный raw-socket / реинъекция в стек ОС в объём v1 не входят. Метод уже объявленasyncи возвращаетResult, чтобы реальный путь egress подключился без изменения вызывающего кода. Путь через VPN полностью работоспособен сквозным образом. Пакеты, у которых не получилось разобрать назначение (не IPv4/IPv6 или слишком короткие), отбрасываются с trace- сообщением.
Входящее направление прямолинейно: расшифрованные IP-пакеты, полученные от пира, пишутся обратно на TUN-устройство.
Правила
Таблица маршрутизации (RouteTable, routes.rs) хранит три вещи: набор CIDR-правил, набор
доменных правил и действие по умолчанию.
CIDR-правила
CIDR-правило — это IpNetwork (например 10.0.0.0/8) плюс действие. CIDR-правила
ключуются сетью, поэтому повторное добавление той же сети перезаписывает её действие.
Доменные правила
Доменное правило — это доменное имя плюс действие. Домены не сопоставляются с IP напрямую.
Вместо этого AuraDns (dns.rs) резолвит домен через системный резолвер (hickory) и вставляет
каждый получившийся адрес как host-маршрут — /32 для IPv4, /128 для IPv6, — так что они
участвуют в обычном longest-prefix matching. Результаты резолва кэшируются.
Поскольку доменные правила становятся host-маршрутами в момент резолва, они действуют только после того, как домен был разрешён (при старте или по требованию). Они отражают адреса, увиденные в момент резолва, и не перерезолвятся непрерывно в v1.
Действие по умолчанию
Если ни одно CIDR-правило (включая host-маршруты от резолва доменов) не совпало с назначением, применяется действие по умолчанию таблицы.
Приоритет longest-prefix
classify(dst_ip) выполняет longest-prefix match (routes.rs):
Среди всех CIDR-правил, чьи сети содержат назначение, побеждает правило с наибольшей длиной префикса (наиболее специфичное). Если ни одно правило не совпало, возвращается действие по умолчанию.
Так специфичный диапазон может перекрыть более широкий независимо от порядка вставки. IPv4-правила совпадают только с IPv4-назначениями, а IPv6 — только с IPv6.
Пример (из поставляемой конфигурации): при default = VPN, 10.0.0.0/8 = Direct и
10.7.0.0/24 = 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 |
Крайний случай: если два правила имеют одинаковую длину префикса, побеждает вставленное последним (оно перезатирает предыдущее, потому что правила ключуются сетью).
Статическая конфигурация: [tunnel.split]
Split-tunnel настраивается в client.toml в секции [tunnel.split]
(crates/aura-cli/src/config.rs). build_route_table превращает её в RouteTable: CIDR-правила
применяются напрямую; доменные правила сохраняются и возвращаются, чтобы клиент мог разрезолвить
их на старте.
Схема
| Ключ | Тип | По умолчанию | Смысл |
|---|---|---|---|
default |
строка | "VPN" |
Действие, когда ни одно правило не совпало: VPN / DIRECT (регистронезависимо) |
[[tunnel.split.direct]] |
массив правил | [] |
Правила, отправляющие совпавшие назначения в Direct |
[[tunnel.split.vpn]] |
массив правил | [] |
Правила, отправляющие совпавшие назначения через VPN |
Каждое правило в direct / vpn — это таблица с ровно одним из ключей:
| Ключ | Тип | Пример |
|---|---|---|
cidr |
строка | "192.168.0.0/16" |
domain |
строка | "intranet.example.com" |
Правило, у которого указаны и cidr, и domain (или ни того ни другого), отвергается на этапе
построения таблицы маршрутизации.
Пример
# Split-tunnel routing: the default action plus per-destination overrides.
[tunnel.split]
# Default for destinations matching no rule below: "VPN" or "DIRECT".
default = "VPN"
# Send these directly (bypass the tunnel): RFC1918 ranges stay on the LAN...
[[tunnel.split.direct]]
cidr = "192.168.0.0/16"
[[tunnel.split.direct]]
cidr = "10.0.0.0/8"
# ...and a corporate domain egresses directly (resolved to host routes at startup).
[[tunnel.split.direct]]
domain = "intranet.example.com"
# Force a more-specific range back through the VPN (longest-prefix wins over 10.0.0.0/8).
[[tunnel.split.vpn]]
cidr = "10.7.0.0/24"
Это и есть та конфигурация, что поставляется в config/client.toml.example.
Управление на лету: aura route / aura status
Работающий 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).
Замечание про платформу: admin-сокет использует Unix domain sockets (Linux/macOS). На Windows это
cfg-заглушка, возвращающая поясняющую ошибку (named-pipe-транспорт — будущая работа), — остальная часть CLI там по-прежнему собирается.
Команды
aura route add (--cidr <CIDR> | --domain <DOMAIN>) --action <vpn|direct> [--admin-socket <PATH>]
aura route list [--admin-socket <PATH>]
aura route remove --cidr <CIDR> [--admin-socket <PATH>]
aura status [--admin-socket <PATH>]
route add принимает ровно один из ключей --cidr / --domain (они взаимоисключающие, и
один из них обязателен), плюс --action vpn или --action direct.
# Отправить CIDR напрямую, на лету.
aura route add --cidr 8.8.8.0/24 --action direct
# ok
# Завернуть домен через VPN (разрезолвится в host-маршруты).
aura route add --domain example.com --action vpn
# ok
# Посмотреть текущие правила и действие по умолчанию.
aura route list
# default: vpn
# cidr 8.8.8.0/24 direct
# domain example.com vpn
# Удалить CIDR-правило.
aura route remove --cidr 8.8.8.0/24
# ok (removed) # или: "ok (nothing to remove)", если его не было
# Статус туннеля и счётчики.
aura status
# Aura tunnel status
# peer: client-1
# default: vpn
# rules: 1
# rx packets: 0
# tx packets: 0
Особенности поведения
route removeудаляет только CIDR-правила — он принимает--cidrи не имеет доменной формы. У библиотечногоRouteTableнет API для покнопочного удаления, поэтому удаление перестраивает таблицу из оставшихся правил (с сохранением действия по умолчанию). Доменные правила добавляются заново при перестройке, но их ранее разрезолвенные host-маршруты сбрасываются и перерезолвятся по требованию.route listперечисляет зеркало правил. Истиной для классификации остаётся живойRouteTable, но он не отдаёт итерацию по правилам, поэтому admin-слой ведёт параллельное зеркало, синхронизированное с каждой мутацией;listотдаёт это зеркало, аclassifyпо-прежнему ходит в реальную таблицу.statusсообщает проверенный peer id, действие по умолчанию, суммарное число правил (CIDR + домены), а также счётчики пакетов на вход/выход.
Wire-протокол (для справки)
По одному JSON-объекту в строке: сначала запрос, затем ответ (crates/aura-cli/src/admin.rs):
-> {"cmd":"route_add","cidr":"8.8.8.0/24","action":"direct"}
<- {"ok":true}
-> {"cmd":"route_list"}
<- {"ok":true,"default":"vpn","cidrs":[{"cidr":"8.8.8.0/24","action":"direct"}],"domains":[]}
-> {"cmd":"route_remove","cidr":"8.8.8.0/24"}
<- {"ok":true,"removed":true}
-> {"cmd":"status"}
<- {"ok":true,"peer_id":"client-1","rx_packets":0,"tx_packets":0,"default":"vpn","rules":1}
При ошибке ответ имеет вид {"ok":false,"error":"..."}.
Сводка ограничений v1
Direct— заглушка: пакеты с действиемDirectлогируются и отбрасываются, а не реинъецируются в стек ОС. Путь через VPN полностью функционален.- Доменные правила резолвятся один раз (на старте или по требованию) в host-маршруты; непрерывного перерезолва нет.
route removeработает только с CIDR и перестраивает таблицу (доменные host-маршруты потом разрезолвятся по требованию).- Admin-сокет только под Unix; на Windows —
cfg-заглушка. - Сервер в v1 — это один общий TUN, а поле
dnsв конфигурации туннеля носит информационный характер (используется системный резолвер).