feat: velocity routing, server registry and RampartVelocity tests

This commit is contained in:
loki5512344 2026-08-03 10:54:28 +02:00
parent fa6de281fb
commit 29ce6fb8e9
Signed by: boba
GPG key ID: 253067914055423B
41 changed files with 1239 additions and 532 deletions

117
TODO.md
View file

@ -56,17 +56,99 @@
| Компонент | Статус |
|-----------|--------|
| **xdp/xdp_filter.c** | 0% — пустой каталог |
| **PoW Challenge (Layer 2)** | 0% — нужно писать |
| **Аудит-фикс v0.3** | **открыт** — все P0/P1/P2 из code review 2026-08 (см. сек. 2) |
| **GeoIP/ASN reputation** | 0% — enum есть, реализации нет |
| **Velocity physics** (falling + protocol + vehicle) | 0% |
| **Traffic Intelligence (Layer 6)** | 0% — EWMA, 168h profiling |
| **ClickHouse + Grafana** | 0% |
| **Bloom filter blacklist** | 0% |
### ⚠️ Ревизия статусов (после аудита 2026-08)
Прошлые строки «XDP 0%» / «PoW 0%» были устаревшими: код уже написан, но **не докатан**.
Реальное состояние (подробности — в сек. 2):
| Компонент | Реальность |
|-----------|------------|
| **xdp_filter.c + loader** | ~написан, но: не собирается в Docker/CI (feature `xdp` не в default), баги IPv6 (`daddr` вместо `saddr`), dead-код в `DIRECT_READ_LOGIN` |
| **PoW (Layer 2)** | ~написан, но **ломает ванильных клиентов** — по умолчанию никто не войдёт (P0) |
| **Layer 6 (Traffic Intel)** | написан, но **не подключён** ни в один hot path (мёртвый код) |
| **ClickHouse + Grafana** | врайтер написан, вызовов `push()` нет — мёртвый код |
| **Velocity physics** | написан, но **фейк**: не читает позиции, проверка по времени между событиями |
| **CAPTCHA** | написан, но `challenge()` нигде не вызывается — мёртвый код |
---
## 2. 6-слойная архитектура (план)
## 2. Аудит-фикс v0.3 (code review 2026-08) — закрыть до релиза
> Полный список минусов из ревью. Философия: «мёртвый код = баг», «по умолчанию безопасно».
### P0 — Showstopper (блокируют релиз)
- [x] **PoW совместимость с ванильными клиентами.** Решение (a): **PoW off по умолчанию** (`config.rs`), код PoW сохранён, включение только с клиентским модом или MC-совместимым PoW. README + docs + `deploy/config/edge.toml` обновлены. Follow-up (клиентский мод / PoW поверх MC) — в backlog.
- [x] **`API_PASSWORD` без дефолта.** Fail-fast при старте (нет env или `changeme` → ошибка), constant-time сравнение (`subtle`), rate-limit 5/60с на `/api/v1/auth/login` (429), `CorsLayer::permissive()` → `CORS_ORIGIN` из env. Неверный пароль → 401.
- [x] **Чтение полного кадра.** `read_full_frame()` в `tunnel.rs`: накопление по varint-длине, лимит 8192, таймаут, EOF/ошибки → death-code path.
- [x] **IPv6.** Полная поддержка: rate-limit/blacklist/whitelist переведены на `IpAddr` (DashMap<IpAddr>), `redis.rs` парсит через `IpAddr::parse`, whitelist валидируется на старте. Попутно исправлен overflow-panic в redis.rs (octet > 255). XDP остаётся IPv4-only (задокументировано).
### P1 — Безопасность
- [ ] **HMAC**: nonce/timestamp + TTL в подпись; реализовать ротацию ключей (dual-key) и задействовать `key_rotation_interval_secs` (сейчас мёртвый конфиг). Детерминированная подпись = вечная утечка.
- [ ] **RateLimiter**: TTL-эвикция idle bucket'ов (фоновый sweep) + cap размера карты — иначе ботнет съест память.
- [ ] **Blacklist**: вызывать `clear_expired()` по таймеру (сейчас мёртвый код).
- [ ] **Redis IP-parse**: валидировать октеты ≤ 255 (`redis.rs:95`) — сейчас `(ip_u32<<8)|octet` с октетом >255 даёт **panic** в debug.
- [ ] **JWT**: валидация ролей/audience, secret ≥ 32 байт, rate-limit на login.
### P1 — Целостность слоёв
- [ ] **XDP в Docker/CI**: собирать `rampart-core --features xdp`, clang+libbpf в builder-образ, smoke-attach в CI.
- [ ] **Синхронизация blacklist Rust ↔ XDP**: `XdpFilter::ban_ip` вызывать при death-code бане; TTL из конфига, не хардкод 300с.
- [ ] **Подключить Layer 6** (`AttackDetector`/`IpReputation`/`TrafficProfiler`) в hot path: метрики, reputation-скоринг, auto-ban.
- [ ] **Подключить ClickHouse**: реальные `push()` из hot path + flush task + таблица (сейчас мёртвый код).
- [ ] **CAPTCHA**: вызвать `challenge()` на входе ИЛИ удалить (сейчас мёртвый код; `markVerified`/`verifiedPlayers` пишутся, но не читаются).
- [ ] **`routeServer(domain)`**: реализовать доменную маршрутизацию по `ServerInfo` (сейчас параметр игнорируется, только round-robin).
### P2 — Баги и долг
- [ ] **XDP IPv6**: `src_ip = ip6->daddr` (`xdp_filter.c:141`) → исправить на `saddr`; иначе whitelist/blacklist/flow-ключи по чужому IP.
- [ ] **XDP seq-трекинг**: пересмотреть `expected_seq`; убрать dead-код в `DIRECT_READ_LOGIN` (`login_consumed < (end-cursor)` всегда false).
- [ ] **Порядок фильтров**: rate limit ДО PoW (сейчас PoW-работа тратится на rate-limited IP); убрать двойной `check()` на соединение (съедает 2 токена).
- [ ] **`std::sync::Mutex` в async** (`DifficultyAdjuster` в `tunnel.rs`) → `tokio::sync::Mutex`/атомика; whitelist-сравнение по строке → пре-парс IP/CIDR.
- [ ] **`replace_hostname`**: проверка длины подписанного hostname ≤ 255 (добавка сигнатуры выбивает длинные домены).
- [ ] **Physics**: переделать на реальные данные позиций или удалить фейковый falling check; «re-verify» должен реально что-то проверять, а не дисконнектить.
- [ ] **Redis**: `KEYS` → `SCAN` (manager + `ServerRegistry`), TTL на ключи серверов (иначе мусор копится), **reconnect** pubsub-подписчика (сейчас умирает навсегда).
### P2 — Мёртвый код / конфиг
- [ ] Удалить или использовать: `max_connections_per_ip`, `rate_limit_status_pps`, `logging.level/format`, `ACTIVE_CONNECTIONS`, `BLACKLIST_SIZE`, `io-uring`/`tokio-splice`, `ClickHouseWriter` без вызовов.
- [ ] **Manager blacklist**: хранить reason/created/expires, применять `duration_secs` (сейчас фабрикуются фейковые поля).
- [ ] **CLI**: `drain`/`emergency` из заглушек → реальная логика или явный `unimplemented`.
- [ ] **README**: убрать неподтверждённые цифры (io_uring 110k, XDP 15–20M pps), привести в соответствие коду и TODO.
**DoD этапа 0:** все P0 закрыты, P1/P2 закрыты или явно задекларированы как «позже с issue», `cargo test` + `cargo clippy -D warnings` + Java build + Docker (с XDP) зелёные.
---
## 3. Anti-Regression — как не допускать
> Каждая фича обязана пройти чеклист ниже. Мёртвый код, «бумажные слои» и дефолт-секреты = reject на ревью.
### Правила
1. **No dead code**: каждый `pub` в prod-модуле имеет вызов вне `#[cfg(test)]`. Если компонент не вызывается — он не существует (CAPTCHA, ClickHouse, Layer 6).
2. **Config field = потребитель**: нет конфиг-поля без использования. Добавил поле — сразу потребитель (или не добавляй).
3. **Метрика регистрируется → обновляется**: каждый Gauge/Counter имеет единственного «writer»; ревью проверяет, что `inc`/`set` реально вызываются.
4. **Feature flag = сборка в CI**: любое `feature` собирается в CI (`--all-features` уже есть) и в Docker-образе. «Фича не в образе» = фичи нет.
5. **По умолчанию безопасно**: нет дефолтных секретов/паролей; отсутствие обязательного env = fail-fast, а не warn.
6. **Интеграционный тест на слой**: PoW+handshake (симуляция ванильного клиента), XDP attach smoke, Redis sync, router по домену.
7. **Парсеры читают полный кадр**: никогда «один read» для MC-пакета; неполный кадр = accumulate или отказ, но не молчаливый drop валидного клиента.
8. **Listener/Handler = вызывается**: новый Java-listener или Rust-модуль подключается в `main`/plugin `onEnable`, иначе reject.
9. **CI guardrails** (добавить в `.github/workflows/ci.yml`):
- [ ] `cargo clippy --all-targets --all-features -- -D warnings`
- [ ] `cargo test` (уже есть) + сборка XDP (`clang -target bpf`) + Docker build с `--features xdp`
- [ ] grep-проверка отсутствия дефолт-секретов: `changeme`, `password = "` в коде/конфигах
- [ ] Java build (уже есть) + `./gradlew test`
10. **README/TODO не врут**: каждое заявленное число/слой имеет ссылку на код или тест. Нет — не пишем.
---
## 4. 6-слойная архитектура (план)
```
Layer 1: XDP/eBPF (C) TCP state machine, SYN throttle, blacklist, UDP drop
@ -79,7 +161,7 @@ Layer 6: Traffic Intel (Rust) EWMA thresholds, 168h profiling, reputation
---
## 3. Этапы разработки
## 5. Этапы разработки
### Этап 4: XDP/eBPF — Layer 1 (сейчас)
@ -185,7 +267,7 @@ Layer 6: Traffic Intel (Rust) EWMA thresholds, 168h profiling, reputation
---
## 4. Backlog
## 6. Backlog
- [ ] Bedrock / RakNet (UDP модуль)
- [ ] Plugin API через WASM (как Infrarust)
@ -196,21 +278,25 @@ Layer 6: Traffic Intel (Rust) EWMA thresholds, 168h profiling, reputation
---
## 5. Definition of Done
## 7. Definition of Done
```
☐ cargo check / cargo test проходят
☐ cargo clippy -- -D warnings — 0 warnings
☐ cargo fmt --check проходит
☐ Unit тесты покрывают happy path + 2+ error cases
☐ Интеграционный тест проходит
☐ Интеграционный тест проходит (PoW+handshake, XDP smoke, Redis sync)
☐ Нет мёртвого кода: каждый pub-модуль/конфиг-поле/метрика имеют потребителя
☐ Нет дефолтных секретов/паролей (grep-чек в CI)
☐ Docker-образ собирает те же features, что CI (включая XDP)
☐ README соответствует коду (нет «бумажных» цифр/слоёв)
☐ Документация обновлена
☐ CI зелёный
```
---
## 6. Anti-Patterns
## 8. Anti-Patterns
```
❌ Тесты после кода. Пиши до (TDD) или вместе.
@ -221,8 +307,15 @@ Layer 6: Traffic Intel (Rust) EWMA thresholds, 168h profiling, reputation
❌ async где хватит sync.
❌ Секреты в репозитории. Используй .env + SOPS.
❌ Игнор compiler warnings.
❌ Мёртвый код: pub без вызовов, конфиг-поле без потребителя, метрика без writer.
❌ «Бумажный слой»: фича в README/архитектуре, которой нет в коде или она не вызывается.
❌ Дефолтный секрет: `changeme`/`password="..."` в коде или конфиге.
❌ Парсер за «один read» — MC-пакет может прийти фрагментами.
❌ Feature flag, который не собирается в Docker/CI — фичи нет.
```
> Статус секций 5–8: план на будущее. Актуальный приоритет — **Аудит-фикс v0.3 (сек. 2)**: закрыть P0/P1/P2 до релиза.
---
*Версия: 2.0 | Обновлён: июль 2026*
*Версия: 3.0 | Обновлён: август 2026 (аудит-фикс v0.3)*