montana/Node/External-Audit/ARCHITECTURE.md
2026-05-21 03:44:38 +03:00

97 lines
6.1 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.

# Архитектура VPN-сети Montana
Версия: **2026-05-18**
## Поток подключения клиента
```
┌──────────────┐ 1. DNS resolve cdn.montana.quest
│ iPhone Happ │ ─────────────────────────────────────┐
└──────┬───────┘ │
│ ▼
│ ┌──────────────────────────┐
│ │ Cloudflare DNS multi-A │
│ │ TTL=120, не proxied │
│ │ → FI 91.132.142.42 │
│ │ → FRA 89.19.208.158 │
│ │ → US 86.104.72.12 │
│ └────────┬─────────────────┘
│ │
│ 2. TLS handshake (Reality) ───────────┘
│ SNI=www.googletagmanager.com
│ pbk=EkTs2aGKnFNgFZ0f7wgft2sJp3VjwFQqIrwkZKM4gD8
┌────────────────────────────────────────────────────┐
│ xray :443 на одном из узлов (любом — один keypair) │
│ vless + xtls-rprx-vision + reality │
│ user=xray:xray, Restart=always, StartLimitBurst │
│ outbound: freedom (direct internet) │
└────────────────────────────────────────────────────┘
```
## Поток управления (health watchdog)
```
┌────────────────────────────────────────────────┐
│ montana-orchestrator.service на Moscow │
│ /opt/montana-orchestrator/server.py :5020 │
│ │
│ Flask: │
│ POST /register {ip, alias, …, secret} │ ← admin
│ POST /deregister {ip, secret} │ ← узел при shutdown
│ GET /pool — CF records + state │ ← аудитор
│ GET /health — кол-во live │ ← мониторинг
│ │
│ Background thread (каждые 30 сек): │
│ for ip in registrypool: │
│ ok = tls_probe(ip:443, SNI) │
│ if ok && success≥2 && not in_pool: │
│ cf_api POST /dns_records │
│ if !ok && fails≥2 && in_pool: │
│ cf_api DELETE /dns_records/<id> │
└────────────────────────────────────────────────┘
Cloudflare API
```
## Компоненты
| Узел | Хост | Роль | Сервисы |
|---|---|---|---|
| Helsinki | 91.132.142.42 | VPN-backend | xray |
| Frankfurt | 89.19.208.158 | VPN-backend | xray |
| New York | 86.104.72.12 | VPN-backend | xray |
| Moscow | 176.124.208.93 | orchestrator + landing + p2p (НЕ VPN) | nginx, montana-orchestrator, montana-node |
## Криптографические параметры
| Параметр | Значение | Где |
|---|---|---|
| Reality protocol | `vless + xtls-rprx-vision` | inbound config |
| Server SNI / dest | `www.googletagmanager.com:443` | realitySettings.dest |
| Universal UUID | `e6d355e2-2d79-4c96-a373-3b0e6b6f4b0d` | clients[0].id |
| Reality publicKey | `EkTs2aGKnFNgFZ0f7wgft2sJp3VjwFQqIrwkZKM4gD8` | URL `pbk=` |
| Reality shortId | `302805bc0c25e504` | URL `sid=` |
| Reality privateKey | (хранится только на узлах) | `/usr/local/etc/xray/config.json` (600) |
## Сетевые потоки
| От | До | Порт | Назначение |
|---|---|---|---|
| Любой клиент | VPN-узел | 443/tcp | Reality VPN |
| Moscow orchestrator | VPN-узел | 443/tcp | watchdog TLS-probe |
| Moscow orchestrator | api.cloudflare.com | 443/tcp | DNS API |
| Узел | Любой destination | 443/tcp etc. | freedom outbound |
| Любой p2p-узел | Любой узел | 8444/tcp | montana-node Bootstrap+VDF |
| Admin | Moscow `montana.quest/vpn/node/register` | 443/tcp | POST с secret |
## Решения и обоснования
- **Universal keypair на всех backends** — Reality требует, чтобы клиент знал `publicKey` сервера. Multi-A pool с разными keypair невозможен без подписки с несколькими `vless://`. Принято: один keypair с trade-off shared-secret (см. THREAT-MODEL.md T-2).
- **DNS multi-A вместо подписки с несколькими URL** — даёт «один ключ распределяет» без логики на клиенте; iOS native resolver сам ротирует ANSWER.
- **TTL 120s** — баланс между скоростью переключения при отказе и нагрузкой на DNS.
- **Watchdog interval 30s, threshold 2** — реакция за 60120 секунд при минимальной нагрузке на узлы (≈ 1 probe в минуту с одной точки).
- **orchestrator на Moscow, не на VPN-узле** — изоляция управления от data-plane; падение orchestrator не роняет существующие подключения.
- **Moscow исключена из VPN pool** — на :443 nginx (efir.org), :2053 — отдельный xray не для публики.