Protection contre les abus du relais aveugle
Comment les nœuds AeroNyx limitent replay, boucles, débit abusif et peers défaillants sans lire le chiffré, avec des preuves opérateur respectueuses de la vie privée.
Blind Relay Abuse Guard est la limite de sécurité du transfert chiffré décentralisé AeroNyx. Il contient les relais abusifs ou instables sans analyser le ciphertext, conserver un historique durable des routes ni transformer l'opérateur en observateur du trafic.
État et périmètre
La protection est implémentée en Rust et ses résultats agrégés sont exposés dans le health metadata et Nodeboard. Elle contient le risque et produit une preuve honnête : travail opaque accepté, protégé, dégradé ou périmé, jamais son contenu.
| Contrôle | État |
|---|---|
| Blind payload forwarding | Implémenté |
| Signed freshness and replay suppression | Implémenté |
| Previous-hop rate limiting and quarantine | Implémenté |
| Privacy-safe runtime evidence | Implémenté |
| Nodeboard operator visibility | Implémenté |
| Plaintext or payload inspection | Interdit |
| User, route, or social-graph analytics | Interdit |
Invariant du nœud aveugle
Un relay peut authentifier la metadata de routage, appliquer une politique bornée, transférer une envelope opaque et retourner un receipt signé par le terminal. Il ne doit ni inspecter ou inférer le payload, ni révéler de metadata permettant de reconstruire route, identité ou relation sociale.
- messages en clair, packet payloads, médias ou MemChain en clair
- DNS, destinations, domaines, URLs ou historique
- route IDs, chemins complets, endpoint URLs ou IP client
- clés publiques complètes, identité receiver, message IDs ou graphe social
- clés privées, voucher secrets, trafic wallet-level ou matériel de déchiffrement
Pipeline d'admission
Chaque request traverse des contrôles bornés avant de consommer de la capacité. L'ordre ci-dessous est conceptuel ; les décisions utilisent uniquement la metadata signée et l'état agrégé local, jamais le contenu déchiffré.
verify signed previous_hop and envelope
apply in-flight backpressure
check timestamp freshness
check route replay cache
apply previous-hop rate/quarantine decision
validate TTL, loop safety, next-hop descriptor, and endpoint
forward opaque ciphertext or terminate into pending store
Protection replay et fraîcheur
La suppression replay est locale, courte et limitée en capacité. Les timestamps signés rejettent les frames trop anciennes ou trop futures. Les valeurs sont les defaults actuels de main, pas des promesses permanentes ; toute modification exige tests et documentation.
| Constante runtime | Valeur actuelle |
|---|---|
MAX_BLIND_RELAY_SEEN_ROUTES | 8192 route IDs |
BLIND_RELAY_ROUTE_REPLAY_WINDOW_SECS | 600 seconds |
BLIND_RELAY_PREVIOUS_HOP_RATE_LIMIT | 120 requests / 60 seconds |
BLIND_RELAY_PREVIOUS_HOP_FAILURE_THRESHOLD | 12 scored failures / 300 seconds |
BLIND_RELAY_PREVIOUS_HOP_QUARANTINE_SECS | 300 seconds |
MAX_BLIND_RELAY_PREVIOUS_HOP_BUCKETS | 4096 buckets |
BLIND_RELAY_MAX_ENVELOPE_AGE_SECS | 600 seconds |
BLIND_RELAY_MAX_FUTURE_SKEW_SECS | 120 seconds |
BLIND_RELAY_DELIVERY_RECEIPT_MAX_AGE_SECS | 120 seconds |
MAX_BLIND_RELAY_FORWARD_ATTEMPTS | 3 attempts |
Limite et quarantaine du saut précédent
Le rate limit est indexé par l'identité signée du saut précédent. Plus de 120 requests en 60 secondes déclenche cinq minutes de quarantaine locale. Un score séparé déclenche la même quarantaine après 12 échecs hostiles en cinq minutes.
invalid_previous_hop | invalid_signature | self_loop | route_loop | ttl_exhausted
Seules les raisons de validation adversariales comptent. Timeouts de transport, ACK perdus et retry d'une route dupliquée ne pénalisent pas un peer sain. Les buckets sont bornés et l'état inactif expire, empêchant la formation d'un graphe durable.
Idempotence et tentatives
Un route ID répété dans la fenêtre reçoit un succès idempotent : un replay drop agrégé est compté, sans seconde livraison ni transfert. Les erreurs transitoires ont au plus trois tentatives avec jitter borné ; les erreurs permanentes ne sont pas retentées.
duplicate route_id -> accepted=true, reason=duplicate_route, no second delivery
transient next-hop failure -> bounded retry with deterministic jitter
permanent validation failure -> no retry
Compteurs runtime agrégés
Rust expose des compteurs cumulatifs grossiers et timestamps de fraîcheur aux deux chemins suivants. Ce sont des preuves opérationnelles du nœud, pas des logs de messages, analytics facturables ou preuve d'une conversation précise.
system_stats.discovery_status.peer_store.runtime.blind_relay
system_stats.discovery_status.peer_store.peer_health_summary
| Groupe de compteurs | Champs |
|---|---|
| Entrée et issue | received, terminal, forwarded, rejected |
| Validation et protection | invalid_signature, envelope_too_large, ttl_exhausted, no_route, invalid_endpoint, loop_detected, replay_dropped, timestamp_rejected, rate_limited, quarantined, quarantine_started |
| Transport et retry | backpressure_dropped, forward_failed, retry_attempted, retry_succeeded, retry_exhausted |
| Preuve synthétique | probe_attempted, probe_succeeded, probe_failed, two_hop_probe_attempted, two_hop_probe_succeeded, two_hop_probe_failed |
| Livraison réelle et fraîcheur | verified_client_onion_deliveries, last_verified_client_onion_delivery_at, last_accepted_at, last_event_at |
Sémantique de qualité des preuves
Le résumé distingue travail opaque accepté, probes synthétiques, proofs synthétiques two-hop et receipts client signés par le terminal. real_relay_ready exige un receipt récent, authentifié, initié par client et signé par le terminal attendu. Une preuve synthétique n'est jamais du trafic App/utilisateur.
status | Signification |
|---|---|
idle | Aucune preuve relay ou probe. |
observing | Une preuve existe, readiness non établie. |
stale | La preuve de succès n'est plus fraîche. |
ready | Travail accepté ou proof frais sans alerte transport active. |
protecting | Les protections sont actives et le relay reste opérationnel. |
degraded | Échecs forwarding ou probe à examiner. |
attention | Backpressure ou retries épuisés exigent une action immédiate. |
proof_scope distingue client_message_delivery, relay_acceptance, message_delivery, control_plane, single_hop_control_plane, attempted et none. Les totaux historiques restent cumulatifs, mais readiness exige une preuve fraîche et tient compte des pannes actives.
Santé des peers respectueuse de la vie privée
peer_health_summary emploie un identifiant abrégé et des buckets grossiers pour isoler un peer défaillant ou en quarantaine sans exposer les relations de trafic. C'est un diagnostic control-plane avec limite de confidentialité explicite.
Autorisé:
node_id_prefixabrégé- health et descriptor state grossiers
- buckets de fraîcheur gossip et route success
- comptes agrégés de succès et échec
- comptes agrégés loop, replay, rate-limit, quarantine
- temps de quarantaine restant et raisons bornées
Interdit:
- clés publiques complètes
- route IDs ou listes d'endpoints
- blobs chiffrés ou payload hashes
- message IDs ou identité receiver
- IP client, destinations ou DNS
- graphe social ou relations de communication
Parcours opérateur
Ouvrez Nodeboard, choisissez le nœud, puis Discovery et Security / Relay Protection. Interprétez les tendances uniquement avec santé, accessibilité, pression de file et fraîcheur des proofs signés.
- Vérifier la fraîcheur des descriptors et du bootstrap recovery.
- Comparer
accepted_total,accepted_percentet l'âge du dernier accepted avant de déclarer ready. - Distinguer
real_relay_readydu synthetic readiness ; seul le premier prouve un receipt terminal authentifié initié par client. - En protecting, degraded ou attention, examiner les buckets agrégés et le transport sans demander de logs utilisateur.
Carte du code source
Les chemins sont relatifs au dépôt afin de rester valides après migration d'hôte. Backend et Nodeboard sont séparés et ne consomment que de la metadata owner-scoped respectueuse de la vie privée.
| Couche | Chemin du dépôt | Rôle |
|---|---|---|
| API relay Rust | crates/aeronyx-server/src/api/chat_peer.rs | Authentifie les envelopes et applique loop, replay, fraîcheur, rate, quarantine, retry et terminal receipt. |
| Rust PeerStore | crates/aeronyx-server/src/services/peer_store.rs | Stocke compteurs bornés, peer health, readiness et classification des proofs. |
| API health Rust | crates/aeronyx-server/src/api/vpn_health.rs | Publie le health JSON local et privé. |
| Reporter Rust | crates/aeronyx-server/src/management/reporter.rs | Transporte le statut agrégé dans le heartbeat. |
| Observabilité backend | privacy_network/api/vpn_observability.py | Retourne la metadata owner-scoped à la console. |
| Types Nodeboard | types/index.ts | Définit les types blind relay et peer health. |
| Détail et i18n Nodeboard | app/dashboard/nodes/[id]/page.tsx and lib/i18n/index.ts | Affiche Security / Relay Protection avec textes localisés de confidentialité. |
Socle du routage multi-hop
Le multi-hop requiert anti-replay, confinement des boucles, retries bornés, quarantaine et preuve non confondue avec le trafic utilisateur. Cette protection prépare le chiffrement en couches et la diversité des routes sans affaiblir l'invariant aveugle.
Règles de développement
Traitez chaque nouveau champ comme une revue de confidentialité. Une métrique doit répondre à une question de fiabilité du nœud sans identifier payload, émetteur, destinataire, route, endpoint ou conversation.
- Garder
payload_b64opaque sur chaque chemin relay. - Ajouter uniquement compteurs agrégés ou reason buckets bornés.
- Ne jamais joindre compteurs avec routes, endpoints, utilisateurs, receivers ou metadata message.
- Exclure les probes synthétiques des totaux messages, paquets et octets chiffrés.
- Mettre à jour tests Rust, types Nodeboard et toutes les langues lors d'un changement de sens.