Initial commit: Rampart v0.2.0

Multi-layer DDoS protection for Minecraft servers.

- rampart-core: Edge node with XDP/eBPF + Rust L7 filtering
- rampart-manager: REST API with JWT auth, Redis sync
- rampart-cli: CLI tool for operators
- velocity-plugin: Domain check, HMAC verify, server registry, load balancer
- paper-plugin: Auto-registration, heartbeat, HMAC verify
- dashboard: React + Vite web UI for management
This commit is contained in:
loki5512344 2026-07-20 20:53:32 +02:00
commit cf9608ce5d
Signed by: boba
GPG key ID: 253067914055423B
159 changed files with 15341 additions and 0 deletions

337
docs/research/networking.md Normal file
View file

@ -0,0 +1,337 @@
# Networking - WireGuard, BGP Anycast, QUIC, MTU
> Актуально: v0.1+ (WireGuard), v0.5+ (BGP), v0.4+ (QUIC)
---
## WireGuard - hub-and-spoke (v0.1-v0.3)
### Адресация
```
10.0.0.1 Manager + Redis + NATS (главный дедик)
10.0.0.2-21 Velocity 1-20
10.0.1.1-100 Hub 1-100
10.0.2.x Survival серверы
10.0.3.x Skyblock серверы
10.0.100.x Edge ноды (EU, US, AS...)
```
### Конфиг Manager ноды (Hub)
```ini
# /etc/wireguard/wg0.conf
[Interface]
Address = 10.0.0.1/16
PrivateKey = <MANAGER_PRIVATE_KEY>
ListenPort = 51820
# Edge нода EU
[Peer]
PublicKey = <EDGE_EU_PUBLIC_KEY>
AllowedIPs = 10.0.100.1/32
# Edge нода US
[Peer]
PublicKey = <EDGE_US_PUBLIC_KEY>
AllowedIPs = 10.0.100.2/32
# Velocity 1
[Peer]
PublicKey = <VEL1_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32
# Hub 1
[Peer]
PublicKey = <HUB1_PUBLIC_KEY>
AllowedIPs = 10.0.1.1/32
# ... и так для каждой ноды
```
### Конфиг Spoke ноды (edge, velocity, hub, game server)
```ini
# /etc/wireguard/wg0.conf на любой spoke ноде
[Interface]
Address = 10.0.100.1/32 # свой адрес в mesh
PrivateKey = <THIS_NODE_PRIVATE_KEY>
# Только один пир - Manager (Hub)
[Peer]
PublicKey = <MANAGER_PUBLIC_KEY>
Endpoint = <MANAGER_PUBLIC_IP>:51820
AllowedIPs = 10.0.0.0/16 # весь internal диапазон через hub
PersistentKeepalive = 25 # держим туннель через NAT
```
### Авто-генерация конфигов через CLI
```bash
# rampart CLI генерирует wg конфиги для всех нод
rampart wg init --network 10.0.0.0/16 --hub 185.200.100.1
rampart wg add-node --role edge --name edge-eu-1 --public-ip 45.200.10.1
rampart wg add-node --role velocity --name vel-1
rampart wg add-node --role hub --name hub-1
# Генерирует файлы:
# wg-configs/edge-eu-1/wg0.conf
# wg-configs/vel-1/wg0.conf
# ...
# Деплой на ноду
scp wg-configs/edge-eu-1/wg0.conf root@45.200.10.1:/etc/wireguard/
ssh root@45.200.10.1 'systemctl enable --now wg-quick@wg0'
```
---
## MTU - важный нюанс
```
Стандартный MTU Ethernet: 1500 байт
WireGuard overhead: ~80 байт (заголовок + шифрование)
Effective MTU в WG туннеле: 1420 байт
Если Minecraft пакет > 1420 байт → фрагментация → производительность падает.
Minecraft пакеты:
Handshake: ~50-300 байт ✅ (безопасно)
LoginStart: ~30-50 байт ✅
Chunk Data: может быть > 1420 байт ⚠️
Для chunk data: MC клиент и сервер обрабатывают фрагментацию на уровне TCP.
Для нашего edge проксирования: мы просто туннелируем TCP стрим,
фрагментация прозрачна. Проблем нет.
Настройка MTU:
```
```ini
# /etc/wireguard/wg0.conf
[Interface]
MTU = 1420 # явно указываем чтобы не было auto-discovery проблем
```
---
## Firewall - полный набор правил
```bash
#!/bin/bash
# /etc/rampart/firewall.sh
# ── Edge нода ──
setup_edge_firewall() {
iptables -F INPUT
iptables -F FORWARD
iptables -P INPUT DROP
iptables -P FORWARD DROP
# Localhost
iptables -A INPUT -i lo -j ACCEPT
# Established соединения
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# WireGuard
iptables -A INPUT -p udp --dport 51820 -j ACCEPT
# Minecraft от всех (мы принимаем атаки здесь и фильтруем)
iptables -A INPUT -p tcp --dport 25565 -j ACCEPT
# SSH (только с нашего IP управления)
iptables -A INPUT -p tcp --dport 22 -s ${MGMT_IP} -j ACCEPT
# Prometheus от Manager
iptables -A INPUT -p tcp --dport 9090 -s 10.0.0.1 -j ACCEPT
# HAProxy stats (для Prometheus)
iptables -A INPUT -p tcp --dport 8404 -s 10.0.0.0/16 -j ACCEPT
# Всё остальное - дроп
iptables -A INPUT -j DROP
}
# ── Velocity / HAProxy нода ──
setup_backend_firewall() {
iptables -F INPUT
iptables -P INPUT DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# WireGuard
iptables -A INPUT -p udp --dport 51820 -j ACCEPT
# Minecraft только от edge нод через WireGuard
iptables -A INPUT -i wg0 -p tcp --dport 25565 -s 10.0.100.0/24 -j ACCEPT
# SSH
iptables -A INPUT -p tcp --dport 22 -s ${MGMT_IP} -j ACCEPT
# Prometheus сервисы (внутри WG)
iptables -A INPUT -p tcp --dport 9091 -s 10.0.0.0/16 -j ACCEPT
iptables -A INPUT -j DROP
}
# ── Game сервер ──
setup_game_firewall() {
iptables -F INPUT
iptables -P INPUT DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# WireGuard
iptables -A INPUT -p udp --dport 51820 -j ACCEPT
# Minecraft только от Velocity нод
iptables -A INPUT -i wg0 -p tcp --dport 25565 -s 10.0.0.2/28 -j ACCEPT
# SSH
iptables -A INPUT -p tcp --dport 22 -s ${MGMT_IP} -j ACCEPT
# Prometheus метрики Paper
iptables -A INPUT -p tcp --dport 9092 -s 10.0.0.0/16 -j ACCEPT
iptables -A INPUT -j DROP
}
```
```
---
## QUIC - канал Edge ↔ Manager (v0.4+)
### Зачем для управляющего канала
```
TCP проблема: Head-of-line blocking
Большой blacklist update → блокирует heartbeat → edge думает что manager упал
QUIC решение: независимые streams
Stream 0: heartbeat (5 сек) - не блокируется
Stream 1: blacklist updates (push) - независимо
Stream 2: metrics (1 сек) - независимо
Stream 3: команды (drain/reload) - независимо
+ 0-RTT reconnect после разрыва (важно для мобильных VDS с нестабильным uplink)
+ Встроенный TLS 1.3 (не нужен отдельный слой)
```
### Реализация (quinn)
```toml
[dependencies]
quinn = "0.11"
```
```rust
// manager/src/quic.rs
pub async fn start_quic_server(config: Arc<Config>) -> Result<()> {
let tls = build_quic_server_tls(&config.tls);
let endpoint = quinn::Endpoint::server(tls, "0.0.0.0:7777".parse()?)?;
while let Some(incoming) = endpoint.accept().await {
let conn = incoming.await?;
// Получаем identity подключившейся edge ноды из сертификата
let node_id = extract_node_id(&conn);
tokio::spawn(handle_edge(conn, node_id));
}
Ok(())
}
async fn handle_edge(conn: quinn::Connection, node_id: String) {
// Открываем исходящие streams для push уведомлений
let blacklist_tx = conn.open_uni().await.unwrap();
// Слушаем входящие streams (heartbeat, metrics)
loop {
match conn.accept_bi().await {
Ok((tx, rx)) => {
tokio::spawn(handle_stream(tx, rx, node_id.clone()));
}
Err(_) => {
tracing::warn!("Edge нода {} отключилась", node_id);
break;
}
}
}
}
```
---
## BGP Anycast (v0.6+)
> Только если проект вырастет до 10+ edge нод и нужен настоящий anycast.
### Что нужно
```
1. Свой AS номер - получить через RIPE NCC (Европа) или ARIN (США)
Стоимость: ~500€/год членский взнос в RIPE
Плюс: купить через LIR (Local Internet Registry) - дешевле
2. Своя /24 подсеть - 256 IP адресов
Получить вместе с AS через RIPE
Стоимость: включено в RIPE членство
3. VDS с поддержкой BGP сессий
Vultr, Hetzner (не все локации), Leaseweb, OVH Premium
Проверять явно: "BGP sessions supported"
4. FRRouting на каждой edge ноде
```
### FRRouting конфиг
```ini
# /etc/frr/frr.conf на edge ноде
router bgp 65001
bgp router-id 185.200.100.1
# BGP сессия с upstream провайдером
neighbor 149.248.2.1 remote-as 20473
neighbor 149.248.2.1 description "Vultr upstream"
address-family ipv4 unicast
# Анонсируем свою подсеть с этой edge ноды
network 185.200.100.0/24
# NO_EXPORT - не распространяем анонс дальше (только к upstream)
neighbor 149.248.2.1 route-map SET_COMMUNITY out
exit-address-family
route-map SET_COMMUNITY permit 10
set community no-export
! Когда edge нода падает - FRRouting перестаёт анонсировать
! BGP withdraw → трафик автоматически идёт на другую ноду
! Время failover: ~30-60 сек (BGP convergence)
```
### Как это работает
```
play.server.com → 185.200.100.1 (один IP, твоя подсеть)
Игрок из Европы:
BGP → ближайшая нода которая анонсирует 185.200.100.0/24 → edge-eu-1
Игрок из США:
BGP → ближайшая нода → edge-us-1
edge-eu-1 упала → FRRouting делает withdraw →
Европейский трафик → автоматически → edge-us-1 или edge-as-1
Время: 30-60 сек
```