guard/docs/research/networking.md
loki5512344 cf9608ce5d
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
2026-07-20 20:53:32 +02:00

9.6 KiB
Raw Permalink Blame History

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)

# /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)

# /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

# 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:
# /etc/wireguard/wg0.conf
[Interface]
MTU = 1420    # явно указываем чтобы не было auto-discovery проблем

Firewall - полный набор правил

#!/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"
// 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 конфиг

# /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 сек