Protección contra abusos del relé ciego
Los límites que aplica un nodo de AeroNyx antes de reenviar tráfico de relé cifrado: límites de frecuencia y cuarentena del salto anterior, supresión de la repetición de rutas que sobrevive a reinicios, reintentos acotados y admisión de CPU, usando solo metadatos firmados y contadores agregados.
La protección contra abusos del relé ciego (Blind Relay Abuse Guard) es el conjunto de límites que aplica un nodo de AeroNyx antes de reenviar tráfico de relé cifrado para otro nodo. Contiene a los pares abusivos o inestables usando únicamente metadatos de enrutamiento firmados y contadores locales. Nunca analiza el texto cifrado, no guarda historiales de rutas ni expone quién habla con quién.
Alcance
| Control | Estado |
|---|---|
| Reenvío de cargas útiles opacas | Implementado |
| Comprobaciones de vigencia firmadas y supresión de la repetición de rutas | Implementado. El estado antirrepetición sobrevive a los reinicios cuando el almacén del relé de chat del nodo está habilitado |
| Límite de frecuencia y cuarentena del salto anterior | Implementado |
| Límites de admisión de solicitudes y de criptografía para todo el proceso | Implementado |
| Evidencia agregada de funcionamiento en el estado del nodo y en Nodeboard | Implementado |
| Inspección del texto plano o de las cargas útiles | No se realiza, por diseño |
| Analítica por usuario, por ruta o del grafo social | No se realiza, por diseño |
La regla del nodo ciego
Un relé puede autenticar los metadatos de enrutamiento, aplicar una política acotada, reenviar un sobre opaco y devolver un acuse de recibo firmado. Nunca debe inspeccionar la carga útil ni exponer metadatos que puedan reconstruir una ruta, la identidad de un usuario o una relación. En particular, los relés no registran ni exponen:
- el texto plano de mensajes, paquetes, medios o memoria
- consultas DNS, destinos, dominios, URL ni historial de navegación
- ID de ruta, rutas completas, URL de endpoints ni direcciones IP de clientes
- claves públicas completas, identidades de destinatarios, ID de mensajes ni aristas del grafo social
- claves privadas, secretos de vales, tráfico a nivel de billetera ni material de descifrado
Proceso de admisión
Cada solicitud pasa por estas comprobaciones antes de poder usar capacidad de reenvío. Los pasos 1 a 6 se ejecutan en este orden. En el paso 7, una solicitud dirigida a este nodo pasa a su propio tratamiento terminal o cebolla, mientras que una solicitud para otro nodo se reserva después de resolver su siguiente salto.
1. request gate: process-wide admission window and in-flight limit (64 requests)
2. crypto admission: a free slot for signature and onion work, or Backpressure
3. authenticate the signed previous hop and envelope
4. previous-hop rate limit and quarantine check
5. envelope metadata: size, age and future-skew limits
6. self-loop check
7. route loop, TTL and next-hop descriptor checks, plus the route replay reservation
8. forward the opaque ciphertext, or peel the terminal layer and deliver
Cada decisión usa metadatos de enrutamiento firmados y estado agregado local, nunca contenido descifrado.
Límites de funcionamiento
Estos son los valores predeterminados actuales en el código fuente del nodo. Son valores operativos, no promesas permanentes del protocolo.
| Constante | Valor predeterminado |
|---|---|
BLIND_RELAY_ROUTE_REPLAY_CAPACITY | 8192 rutas activas |
BLIND_RELAY_ROUTE_REPLAY_TTL_SECS | 600 segundos |
PREVIOUS_HOP_RATE_LIMIT por PREVIOUS_HOP_RATE_WINDOW_SECS | 120 solicitudes por 60 segundos |
PREVIOUS_HOP_FAILURE_THRESHOLD por PREVIOUS_HOP_FAILURE_WINDOW_SECS | 12 fallos puntuados por 300 segundos |
PREVIOUS_HOP_QUARANTINE_SECS | 300 segundos |
MAX_PREVIOUS_HOP_BUCKETS | 4096 buckets |
BLIND_RELAY_MAX_ENVELOPE_AGE_SECS | 600 segundos |
BLIND_RELAY_MAX_FUTURE_SKEW_SECS | 120 segundos |
BLIND_RELAY_DELIVERY_RECEIPT_MAX_AGE_SECS | 120 segundos |
DEFAULT_MAX_ATTEMPTS (reintentos de reenvío) | 3 intentos |
MAX_IN_FLIGHT_BLIND_RELAY_REQUESTS | 64 solicitudes |
Límite de frecuencia y cuarentena del salto anterior
Los límites de frecuencia se asocian a la identidad firmada del salto anterior. Más de 120 solicitudes de un mismo salto anterior en 60 segundos inician una cuarentena local de cinco minutos para ese salto. Una puntuación de fallos independiente inicia la misma cuarentena tras 12 fallos puntuados en cinco minutos. Solo estos motivos cuentan para la puntuación:
invalid_previous_hop | invalid_signature | self_loop | route_loop | ttl_exhausted
Los tiempos de espera agotados del transporte, los acuses perdidos, los reintentos duplicados y los conflictos de repetición no suman a la puntuación, de modo que un par en buen estado no queda en cuarentena por problemas de red. El almacén de buckets está acotado y los buckets inactivos se desalojan, por lo que la protección no puede convertirse en un grafo de comunicaciones a largo plazo.
Repetición de rutas y reintentos
Cada solicitud de relé lleva un ID de ruta. Cuando el almacén del relé de chat del nodo está habilitado ([memchain.chat_relay] enabled = true), las reservas de rutas y las respuestas completadas se guardan en su base de datos SQLite, por lo que la protección contra repeticiones sobrevive a un reinicio. En caso contrario, el nodo usa un registro en memoria con la misma capacidad y la misma ventana. Si las 8192 posiciones contienen rutas activas, las rutas nuevas se rechazan con replay_capacity hasta que caduquen posiciones.
Un ID de ruta repetido tiene uno de cuatro resultados:
| Situación | Respuesta | Efecto sobre el salto anterior |
|---|---|---|
| Misma solicitud; el primer intento ha finalizado | Se reproduce la respuesta almacenada, incluido cualquier acuse firmado por el nodo terminal. No se entrega ni se reenvía nada por segunda vez (duplicate_route) | Se cuenta como éxito |
| Misma solicitud; el primer intento sigue en curso | HTTP 503 route_in_flight. El remitente puede reintentar | Ninguno |
| Solicitud distinta con el mismo ID de ruta | HTTP 400 replay_conflict | Se registra en el estado del par. No suma a la puntuación de cuarentena |
| Misma solicitud, pero la respuesta almacenada tiene más de 120 segundos | HTTP 409 replay_response_expired. La ruta sigue reservada durante el resto de su ventana de 600 segundos, por lo que no puede volver a ejecutarse | Ninguno |
El último resultado se aplica al almacén persistente. Los acuses firmados solo son válidos como evidencia reciente, por lo que el nodo no reproduce uno pasados 120 segundos.
Cuando el reenvío al siguiente salto falla por un tiempo de espera agotado, un error de conexión o un error de solicitud, el nodo reintenta hasta un total de tres intentos. La breve espera antes de cada reintento se deriva del ID de ruta, del siguiente salto y del número de intento. Los fallos que el nodo posterior notifica como rechazos definitivos no se reintentan.
Admisión criptográfica (nota de capacidad para operadores)
Las comprobaciones de firmas, el pelado de capas cebolla y la firma de acuses consumen CPU, por lo que cada proceso de nodo los limita:
- Posiciones totales: la mitad de los hilos de CPU que indica el host, redondeada hacia arriba, con un mínimo de 4 y un máximo de 8, de modo que incluso un host de uno o dos hilos obtiene 4 posiciones.
- Solicitudes entrantes: una posición menos que el total, para que la creación de rutas salientes y la finalización de acuses siempre puedan avanzar. Por tanto, en los hosts más pequeños las solicitudes entrantes obtienen 3 posiciones.
- Cuando todas las posiciones están ocupadas: la solicitud se rechaza de inmediato con HTTP 429 y el motivo
backpressure. No espera en una cola.
Por tanto, en un host pequeño, un relé descarta carga pronto ante ráfagas. Un contador backpressure_dropped en aumento significa que el nodo necesita más CPU o menos tráfico de relé.
Contadores agregados de funcionamiento
Los nodos notifican contadores acumulados aproximados y marcas de tiempo de vigencia en su latido, bajo:
system_stats.discovery_status.peer_store.runtime.blind_relay
system_stats.discovery_status.peer_store.blind_relay_quality
system_stats.discovery_status.peer_store.peer_health_summary
| Grupo de contadores | Campos |
|---|---|
| Entrada y disposición | received, terminal, forwarded, rejected |
| Validación y protección | invalid_signature, envelope_too_large, ttl_exhausted, no_route, invalid_endpoint, loop_detected, replay_dropped, timestamp_rejected, rate_limited, quarantined, quarantine_started |
| Transporte y reintentos | backpressure_dropped, forward_failed, retry_attempted, retry_succeeded, retry_exhausted |
| Sondas sintéticas | probe_attempted, probe_succeeded, probe_failed, two_hop_probe_attempted, two_hop_probe_succeeded, two_hop_probe_failed |
| Entrega real y vigencia | verified_client_onion_deliveries, last_verified_client_onion_delivery_at, last_accepted_at, last_event_at |
Estos contadores describen el funcionamiento del nodo. No son registros de mensajes ni datos de facturación, y no demuestran que haya tenido lugar ninguna conversación concreta.
Calidad de la evidencia
El resumen de calidad mantiene separados cuatro tipos de evidencia: el trabajo de relé opaco aceptado, las sondas sintéticas de accesibilidad, las sondas sintéticas de dos saltos y los acuses firmados por el nodo terminal para entregas originadas por clientes. real_relay_ready requiere un acuse de entrega de cliente reciente y autenticado. La evidencia sintética nunca se notifica como tráfico de usuarios.
status | Significado |
|---|---|
idle | Todavía no hay actividad de relé ni de sondas |
observing | Existe algo de evidencia, pero la disponibilidad no está establecida |
stale | La evidencia de éxito anterior ya no es reciente |
ready | Trabajo aceptado reciente o una prueba válida, sin ningún problema de transporte activo |
protecting | Las protecciones contra abusos se han activado mientras el relé sigue funcionando |
degraded | Los fallos de reenvío o de sondas requieren investigación |
attention | La contrapresión o los reintentos agotados requieren la atención inmediata del operador |
proof_scope indica la evidencia más sólida observada: client_message_delivery, relay_acceptance, message_delivery, control_plane, single_hop_control_plane, attempted o none.
Estado de los pares sin relaciones de tráfico
peer_health_summary permite a los operadores encontrar un par que falla o que está en cuarentena sin ver quién se comunica con quién.
Incluido: un prefijo abreviado del ID del nodo, el estado aproximado de salud y del descriptor, la vigencia de la difusión y del éxito de rutas, los recuentos agregados de éxitos y fallos de rutas, el estado de cuarentena, el tiempo restante y categorías aproximadas de motivos.
Nunca incluido: claves públicas completas de nodos, ID de ruta, listas de endpoints, bloques cifrados ni hashes de cargas útiles, ID de mensajes, identidades de destinatarios, direcciones IP de clientes, destinos, datos DNS ni aristas del grafo social.
Mapa del código fuente
| Capa | Ruta en el repositorio del nodo | Función |
|---|---|---|
| Orquestación del relé | crates/aeronyx-server/src/api/chat_peer/blind_relay.rs | Control de solicitudes, admisión criptográfica, autenticación, comprobaciones de bucles y TTL, resultados de repetición, reenvío y tratamiento terminal |
| Superficie HTTP y límites | crates/aeronyx-server/src/api/chat_peer.rs | Rutas, límites de cuerpo y de solicitudes en curso, códigos de error y categorías de motivos |
| Política contra abusos | crates/aeronyx-server/src/api/chat_peer_abuse_guard.rs | Límites de frecuencia del salto anterior, puntuación de fallos y cuarentena |
| Registro de repeticiones | crates/aeronyx-server/src/api/chat_peer_replay.rs | Registro en memoria y formato de la respuesta almacenada |
| Almacén persistente de repeticiones | crates/aeronyx-server/src/services/chat_relay_blind_route_store.rs | Reservas de rutas y respuestas en SQLite |
| Política de reintentos | crates/aeronyx-server/src/api/chat_peer_retry.rs | Fallos reintentables frente a definitivos y tiempos de reintento |
| Contadores y calidad | crates/aeronyx-server/src/services/peer_store.rs y services/peer_store/status.rs | Contadores agregados, disponibilidad y clasificación de pruebas |
| Notificación del estado | crates/aeronyx-server/src/api/vpn_health.rs y management/reporter.rs | JSON de estado local y carga útil del latido |
El software de nodo es de código abierto bajo la AGPL-3.0 en github.com/AeroNyxNetwork/AeroNyx. Consulte Descubrimiento de nodos y relé cifrado multisalto para saber cómo se construyen las rutas.
<!-- faq:start -->Preguntas frecuentes
¿Puede un nodo relé leer o registrar el tráfico que reenvía?
No. Un relé comprueba metadatos de enrutamiento firmados y reenvía un sobre opaco. Solo guarda contadores agregados, nunca cargas útiles, historiales de rutas ni identidades de destinatarios.
¿Qué ocurre cuando un nodo reintenta la misma ruta?
Si el primer intento ha terminado, el nodo reproduce su respuesta almacenada y no entrega nada por segunda vez. Si el primer intento sigue en curso, el nodo devuelve un route_in_flight reintentable. Una solicitud distinta con el mismo ID de ruta se rechaza como replay_conflict.
¿La protección contra repeticiones sobrevive a un reinicio del nodo?
Sí, cuando el almacén del relé de chat del nodo está habilitado. En ese caso, las reservas de rutas y las respuestas completadas se guardan en SQLite. Sin ese almacén, el nodo usa un registro en memoria que se borra al reiniciar.
¿Por qué se pone en cuarentena a un par?
Un par queda en cuarentena durante cinco minutos tras enviar más de 120 solicitudes en 60 segundos, o tras 12 fallos de validación puntuados en cinco minutos. Los tiempos de espera agotados, los acuses perdidos y los reintentos duplicados no cuentan como fallos.
¿Por qué mi nodo devuelve backpressure bajo carga?
Todas sus posiciones criptográficas de relé estaban ocupadas. Un nodo dedica aproximadamente la mitad de sus hilos de CPU (como mínimo 4 y como máximo 8) al trabajo de firmas y de capas cebolla, y rechaza de inmediato las solicitudes sobrantes en lugar de ponerlas en cola.
<!-- faq:end -->