Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
netfence — Como Envoy xDS, pero para filtros eBPF | Kitploit
Herramientas/GitHubGitHub/danthegoodman1/netfence
Seguridad de Infraestructura en la NubeSeguridad de ContenedoresEvasión de IDS/IPSSeguridad de RedesSeguridad en la NubeDevSecOpsMala ConfiguraciónAnálisis de DNS
GitHubdanthegoodman1/netfence

netfence

Como Envoy xDS, pero para filtros eBPF

Ver Repositorio
10142hace 1 mesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

Netfence

Como Envoy xDS, pero para filtros eBPF.

Netfence se ejecuta como un daemon en tus hosts de VM/contenedores e inyecta automáticamente programas de filtro eBPF en cgroups e interfaces de red, con un servidor DNS integrado que resuelve dominios permitidos y llena la lista de IPs permitidas.

Los daemons de Netfence pueden manejarse a través de su API local de socket Unix, o conectarse a un plano de control central que implementes vía gRPC para sincronizar listas permitidas/denegadas con tu backend.

Tu plano de control envía reglas de red como ALLOW *.pypi.org o ALLOW 10.0.0.0/16 a las interfaces/cgroups adjuntos. Cuando una VM/contenedor consulta DNS, Netfence lo resuelve, añade las IPs al filtro eBPF, y descarta el tráfico hacia IPs desconocidas antes de que salga del host, con una sobrecarga de ruta caliente que es efectivamente indistinguible de una conexión de socket normal en los benchmarks actuales.

Funcionalidades

  • Adjuntar filtros eBPF a interfaces de red (TC) o cgroups
  • Modos de política: desactivado, lista permitida, lista denegada, bloquear todo
  • Soporte para CIDR IPv4 e IPv6 con TTLs opcionales
  • Servidor DNS UDP/TCP por adjunto con lista permitida/denegada de dominios y anulaciones de upstream ordenadas
  • Las reglas de dominio admiten subdominios con coincidencia basada en especificidad (las reglas más específicas ganan)
  • Los dominios resueltos llenan automáticamente el filtro de IPs
  • Metadatos en daemons y adjuntos para asociar con ID de VM, inquilino, etc.
  • Soporte para redirigir consultas DNS al plano de control para tomar decisiones DNS por adjunto

Nota de seguridad: exclusiones por defecto

Descargar herramienta

En modo lista permitida, el enlace local IPv4 (169.254.0.0/16) ya no está permitido automáticamente por defecto — por lo que el servicio de metadatos en la nube (169.254.169.254) está bloqueado a menos que se incluya explícitamente en la lista permitida. Esto es deliberado: el servicio de metadatos es un objetivo de robo de credenciales, y las cargas de trabajo en sandbox no deben poder alcanzarlo implícitamente. Localhost (127.0.0.0/8, ::1) y el descubrimiento de vecinos IPv6 (fe80::/10, ff02::/16) permanecen permitidos por defecto para que la conectividad básica y NDP sigan funcionando. Para permitir el servicio de metadatos para una carga de trabajo, incluya 169.254.169.254/32 en la lista permitida (una anulación de exclusión por adjunto a través del plano de control es un seguimiento planificado).

El broadcast IPv4 (255.255.255.255) y el multicast (224.0.0.0/4) no tienen exclusión y están sujetos a la política, por lo que en modo TC lista permitida el tráfico como las renovaciones DHCP broadcast se bloquea a menos que se incluya explícitamente en la lista permitida. Las comprobaciones de exclusión se ejecutan antes de la lista denegada, por lo que un rango excluido solo puede bloquearse desactivando su exclusión — y dado que el enlace local IPv4 ahora está desactivado por defecto, el modo lista denegada también puede bloquear el servicio de metadatos.

Diferencias con otras opciones

Algunos beneficios importantes de esta solución que otras opciones normalmente no soportan:

  • Corte inmediato de las conexiones existentes cuando las reglas cambian para denegar una IP (solo adjunto a interfaz)
  • Soporte para todos los protocolos de red, y conexión directa a IP. Por ejemplo, el excelente httpjail no permite conectarse directamente a IPs, ni conexiones TCP/UDP directas como las conexiones a bases de datos.
  • Resolución dinámica de DNS y filtrado previo a la resolución (para que no haya exfiltración de secretdata.someattacker.com)

Hasta donde sé, ninguna otra solución ofrece todas estas características juntas.

Limitación conocida: los adjuntos a cgroup filtran a nivel de socket (hooks connect/sendmsg), por lo que un proceso con CAP_NET_RAW puede crear paquetes sin procesar que los eviten. Use un adjunto TC (interfaz), que filtra a nivel de dispositivo, para cargas de trabajo que puedan tener CAP_NET_RAW.

Sin embargo, esto tiene un poco más de sobrecarga que algo como httpjail.

Instantánea de rendimiento

Estos números se midieron en el gate Linux Docker privilegiado en linux/arm64 usando make bench-docker. Los valores son medianas de cinco muestras.

Ruta de socket caliente

El benchmark de socket caliente utiliza sockets UDP conectados para aislar el costo del hook eBPF cgroup/connect4 de la latencia del handshake TCP. En esta ruta, DNS ya ha resuelto el dominio, la IP aún está dentro del TTL, y la IP/CIDR ya está presente en el mapa eBPF.

RutaLatencia mediana
Conexión de socket normal, sin eBPF~2.647 us
Lista permitida caliente, acierto LPM protegido~2.691 us
Lista permitida caliente, acierto de host exacto DNS~2.741 us
Fallo en lista permitida, bloqueo local~1.652 us

La dispersión medida entre las rutas de conexión normal, LPM protegido y host exacto DNS está dentro del ruido de la muestra.

No existe la ruta "fallo en kernel pregunta al proceso padre" hoy. Un fallo en lista permitida de cgroup es decidido localmente por eBPF y se bloquea inmediatamente.

Ruta de consulta DNS

Estos números miden la ruta del servidor DNS, no la ruta de conexión de socket caliente.

RutaLatencia mediana
Consulta proxy en frío, función de política en proceso~31.336 us
Consulta proxy en caliente~27.964 us
Consulta lista permitida en frío con upstream local~53.510 us
Consulta lista permitida en caliente con upstream local~53.432 us

Las filas en frío se sincronizan a través de la barrera de mutación de adjunto real y borran el gráfico de propiedad del benchmark y la instantánea del mapa exacto falsa entre consultas. El temporizador se ejecuta continuamente para preservar la localidad del planificador UDP, mientras que ns/op resta el fixture-reset-ns/op de tiempo de pared reportado por separado (incluyendo cualquier cola del manejador anterior después de que el cliente recibiera su paquete) y por lo tanto mide el Exchange actual del cliente. raw-total-ns/op reporta ambos juntos. El restablecimiento preserva los dominios de política configurados y el almacenamiento de respaldo, y el benchmark afirma una adición física al mapa exacto por consulta. Las filas en caliente preparan la propiedad una vez y afirman una adición física a lo largo de la ejecución.

Los microbenchmarks internos de propiedad a continuación son diagnósticos de escalabilidad, no filas de aceptación de ruta de consulta DNS de extremo a extremo. El helper en caché se conserva solo para pruebas y benchmarks; envuelve un registro a la vez y repite la validación de dominio. Tanto este tráfico como el del resolvedor normal atraviesan la barrera de mutación de adjunto, mientras que el tráfico normal del resolvedor admite cada respuesta completa como una transacción.

Diagnóstico interno de escalabilidadMediana actualMemoria / asignaciones
Admisión de clave nueva en frío, gráfico de propiedad vacío~370.3 ns232 B, 5 allocs/op
Admisión de clave nueva en frío, 4095 entradas no relacionadas~451.2 ns232 B, 5 allocs/op
Presión de capacidad física y reemplazo LRU~3.820 ms~4.23 MB (4,226,243 B), 4,336 allocs/op
Comprobación previa de presupuesto físico agotado~611.9 ns344 B, 9 allocs/op
Presión máxima de bordes, respuesta de 64 direcciones~6.849 ms~7.66 MB (7,658,774 B), 2,233 allocs/op
Guarda de trabajo máximo de gráfico, plan completo permitido~2.763 ms~4.26 MB (4,264,386 B), 3,074 allocs/op
Guarda de trabajo máximo de gráfico, rechazo por proyección agotada~10.935 us8.76 KB (8,760 B), 14 allocs/op
Operación de presupuesto de rotación cerca del techo numérico~18.98 ns0 B, 0 allocs/op
Instantánea coherente de estadísticas de propiedad~2.094 ns0 B, 0 allocs/op
Escaneo de expiración sin operación en 4095 entradas~74.849 us/scan0 B, 0 allocs/op

Diseño

Arquitectura```

+------------------+ +-------------------------+ | Your Control |<------->| Daemon (per host) | | Plane (gRPC) | stream | | +------------------+ | +-------------------+ | | | DNS Server | | | | (per-attachment) | | | +-------------------+ | +-------------------------+ | +------+------+ | | TC Filter Cgroup Filter (veth, eth) (containers)

root@kitploit:~
Cada adjunto obtiene una dirección DNS única (puerto) aprovisionada por el daemon. Los contenedores/VMs deben configurarse para usar su dirección DNS asignada; filtrar el tráfico DNS normal de la carga de trabajo no lo redirige de forma transparente.

### Topología y comportamiento del resolver DNS

`dns.listen_addr` debe identificar una dirección IPv4 o IPv6 concreta a la que cada
carga de trabajo adjunta pueda llegar. Las direcciones comodín se rechazan porque
no pueden ser anunciadas como endpoints del resolver. Un nombre de host configurado se resuelve
una vez que el daemon se inicia y la IP concreta resultante se utiliza para el enlace,
anuncio, persistencia y arranque del filtro. El valor predeterminado `127.0.0.1` es
apropiado solo cuando la carga de trabajo comparte el espacio de nombres de red del daemon; un
contenedor o VM en otro espacio de nombres normalmente necesita una dirección de host/puente alcanzable en su lugar.```yaml
dns:
  listen_addr: 10.0.0.1
  port_min: 11000
  port_max: 11500
  # Daemon-global fallback when DnsConfig.upstream_servers is empty.
  upstream: 1.1.1.1:53
  # Hard daemon ceilings for each attachment's bounded DNS exact ownership.
  # Zero/unset uses these defaults (max_ips_per_family instead derives from
  # filter.max_dns_rule_entries).
  max_ips_per_family: 4096
  max_ips_per_response: 64
  max_ips_per_policy_domain: 1024
  max_tracked_domains: 1024
  max_ownership_edges: 8192
  # Rolling physical-admission/LRU mutation budget and slow-planning work
  # allowance. The window is daemon-global and immutable until restart;
  # DnsConfig.max_churn_units may only lower the daemon ceiling.
  max_churn_units: 8192
  churn_window: 1m

Attach devuelve la dns_address concreta; configure esa dirección exacta como el resolutor de la carga de trabajo. Netfence instala una entrada de permiso /32 o /128 protegida y no caducante para la IP del listener, de modo que el modo de lista blanca pueda arrancar sin una regla DNS-IP del plano de control. Los filtros actuales aplican prefijos IP, no puertos de destino, por lo que esa entrada protegida permite cada puerto en la IP del listener (no solo su puerto DNS); esto es especialmente importante para modelos de amenaza de adjunción a cgroups. Utilice una IP de listener dedicada cuando esa accesibilidad más amplia no sea aceptable.

El punto final asignado sirve tanto UDP como TCP. Las respuestas UDP se truncan al límite de 512 bytes de un cliente heredado o al tamaño EDNS anunciado y llevan TC cuando es necesario, permitiendo que la carga de trabajo reintente el mismo punto final a través de TCP. Para la resolución ascendente, una respuesta UDP truncada se reintenta a través de TCP contra el mismo ascendente primero. Una falla de transporte, SERVFAIL o REFUSED avanza entonces al siguiente ascendente configurado en orden.

DnsConfig.upstream_servers anula el dns.upstream global del daemon para una adjunción. Las entradas usan sintaxis host:port (literales IPv6 entre corchetes), se canonicalizan y deduplican en orden de primera aparición, y están limitadas a ocho servidores únicos. Una lista vacía selecciona la reserva global.

En modos de filtrado, Netfence elimina los parámetros ipv4hint e ipv6hint de las respuestas HTTPS/SVCB, incluyendo sus referencias mandatory correspondientes, porque las direcciones sugeridas no han pasado la admisión del filtro de forma independiente. El modo deshabilitado conserva las respuestas ascendentes sin cambios.

Los contadores de consultas DNS son mutuamente excluyentes: dns_queries_allowed cuenta consultas permitidas por política y respondidas con éxito (incluyendo NXDOMAIN), dns_queries_blocked cuenta respuestas REFUSED por política y dns_queries_errors cuenta resolución, proxy, admisión de filtro, escritura de respuesta y otras rutas de error. Una consulta incrementa exactamente un depósito.

Cada respuesta que lleva direcciones en un modo de filtrado DNS es admitida en el nivel HASH IPv4/IPv6 exacto de la adjunción como una transacción antes de que cualquier dirección A/AAAA de sus secciones de respuesta, autoridad o adicional sea devuelta. Si la respuesta completa no puede ser representada, el resolutor devuelve SERVFAIL sin dirección y conserva el conjunto de trabajo previamente admitido. Las decisiones PROXY que devuelven direcciones deben establecer add_to_filter; de lo contrario también fallan en cerrado como SERVFAIL. El modo DNS deshabilitado es la excepción explícita de paso directo.

Las entradas exactas llevan bordes TTL desde la consulta normalizada hasta el propietario de la política coincidente. Eliminar o denegar un dominio elimina rápidamente sus últimas direcciones exactas solo DNS, mientras que una dirección compartida sobrevive a otro propietario de consulta activo y un CIDR superpuesto del plano de control continúa independientemente en el nivel LPM protegido. Las respuestas de permitir por defecto y permitir explícito de DENYLIST DNS también se rastrean, incluso mientras DENYLIST de paquetes ignora los permitidos exactos, por lo que un cambio posterior a modo ALLOWLIST puede usar direcciones en caché ya devueltas sin una consulta repetida.

Todo el estado de propiedad del espacio de usuario normal/activo está limitado por las cinco configuraciones de propiedad anteriores. Los bordes provisionales sintéticos restaurados están exentos de esos límites lógicos para que no puedan ser olvidados antes de la reconciliación, pero permanecen limitados por los mapas exactos IPv4/IPv6 físicos. Los dominios de política configurados y los dominios de consulta activa comparten max_tracked_domains, y cada registro TTL (consulta, propietario coincidente, IP) consume una ranura max_ownership_edges.

Bajo presión, la admisión proyecta primero los bordes TTL caducados. Luego reclama bordes lógicos completos de consulta/propietario con la menor garantía física antes de la actualidad, seguido de LRU determinista observado por el resolutor (las IP canónicas rompen empates). Una expulsión física elimina toda la clave DNS exacta y todos sus propietarios DNS. La IP física entrante y el borde exacto entrante (IP, consulta, propietario) están protegidos para la transacción de respuesta. La propiedad provisional restaurada protege su clave física hasta la reconciliación autoritativa, pero los metadatos DNS normales no relacionados que comparten esa clave aún pueden ser reclamados. Los permite autoritativos del plano de control/sistema y cada denegación permanecen en niveles LPM separados y nunca son candidatos para la reclamación DNS.

El presupuesto de cambio continuo por adjunción cobra una unidad por una nueva clave física exacta y una por cada clave física DNS activa expulsada; un reemplazo completo de antiguo a nuevo por lo tanto cuesta dos. Las actualizaciones, la reclamación solo lógica, la caducidad y la eliminación por política cuestan cero. Los eventos permanecen activos mientras su edad sea menor que dns.churn_window y caducan en el límite exacto. DnsConfig.max_churn_units solo puede reducir el techo del daemon; cero lo hereda. La ventana no puede ser cambiada por el plano de control, y cambiar el techo/ventana del daemon requiere un reinicio. Reducir y luego aumentar un límite de adjunción no olvida el historial aún activo.

Un libro de trabajo continuo separado limita la costosa planificación del grafo de propiedad. Las actualizaciones rápidas y las admisiones ordinarias nunca lo tocan. Antes de que una ruta de presión clone o analice el grafo, Netfence cobra unidades de trabajo estables derivadas de las claves físicas actuales, bordes de propiedad, dominios rastreados y tamaño de respuesta en relación con sus techos inmutables de daemon/mapa. Ese intento de cobro se retiene incluso cuando el plan resulta imposible o una transacción de mapa exacto posterior falla, cerrando la ruta de reintento sin mutación para presión de CPU/asignación sin cambiar la contabilidad de cambio físico transaccional anterior. Con los techos predeterminados, la asignación admite ocho pases de grafo equivalentes máximos por ventana; reducir DnsConfig.max_churn_units retiene al menos uno. Reducir y luego aumentar el límite nunca reescala u olvida el historial de trabajo activo.

Cuando ningún estado DNS elegible puede satisfacer un límite, o se agota cualquiera de las dos asignaciones continuas, Netfence conserva el conjunto de trabajo admitido y devuelve SERVFAIL sin devolver la dirección no admitida. Las fallas de capacidad incrementan map_full_drops; los estrangulamientos de cambio físico y planificación de trabajo no lo hacen. Los latidos exponen el mapa exacto actual, la capacidad y los valores máximos de generación de procesos más las expulsiones LRU DNS acumuladas, todas las fallas de admisión y un recuento agregado de estrangulamiento de presupuesto que cubre ambas guardas continuas. Los registros de presión/recuperación de capacidad, presupuesto físico y presupuesto de trabajo tienen límite de velocidad independiente. Los operadores pueden esperar la recuperación de TTL/ventana, reducir la rotación de respuesta/dominio o los intentos repetidos de presión de capacidad, o aumentar DnsConfig.max_churn_units hasta el techo daemon dns.max_churn_units. Aumentar el techo del daemon requiere un reinicio; aumentar filter.max_dns_rule_entries también requiere recrear la adjunción porque los mapas fijados no se pueden redimensionar en el lugar.

Capacidad CIDR protegida y recuperación con fallo en cerrado

Los CIDR autoritativos del plano de control y las reglas del sistema del daemon utilizan cuatro mapas LPM independientes y no expulsables: permitir/denegar × IPv4/IPv6. Cada mapa tiene ranuras filter.max_rule_entries. El arranque /32 o /128 del listener DNS es un permiso del sistema y cuenta contra el mapa de permisos protegidos correspondiente. Las entradas de host exacto DNS permanecen en sus mapas separados y no pueden consumir estas ranuras. Ninguna regla protegida se expulsa por LRU: los permisos explícitos, las reglas del sistema y cada denegación permanecen hasta una eliminación autorizada o un reemplazo completo.

Un SubscribedAck o BulkUpdate completo se canonicaliza y su ocupación final se verifica para los cuatro mapas antes de la mutación. La capacidad se basa en el estado final, por lo que reemplazar claves en un mapa lleno es válido; el estado sobredimensionado se rechaza sin expulsar o aceptar parcialmente reglas. Los supervivientes no se eliminan ni se vuelven a agregar. Si una llamada al sistema de mapa posterior falla, Netfence restaura y verifica el inventario exacto de los cuatro mapas anterior a la llamada. El modo probado después de la reversión es el modo antiguo o BLOCK_ALL (normalmente BLOCK_ALL), por lo que el daemon aún mantiene la adjunción en fallo en cerrado hasta que un reintento autoritativo completo tenga éxito.

El estado de seguridad de la política protegida se persiste con la adjunción y se exporta en latidos. BLOCK_ALL por sí mismo es un modo configurado normal y saludable: policy_degraded es falso cuando policy_degraded_reason está vacío. Una mutación protegida riesgosa que comienza mientras BLOCK_ALL está saludable primero registra en diario protected_policy_mutation_in_progress. Esto es un diario de fallos transitorio, no un diagnóstico de fallo estable: la operación en vivo puede publicar su modo previsto antes de la última guarda de borrado del diario, y la finalización exitosa borra el diario mismo. Si el inicio lo encuentra después de un fallo, el inicio primero fuerza y prueba BLOCK_ALL, luego persiste protected_policy_mutation_interrupted. Los códigos de razón de degradación estables son:

  • protected_policy_mutation_interrupted
  • authoritative_protected_policy_failed
  • incremental_deny_install_failed
  • incremental_allow_removal_failed
  • incremental_mode_change_failed

Estas son clasificaciones estables, nunca texto sin procesar de llamada al sistema/almacén. El diario en curso es un límite interno de fallo persistido; las estadísticas de latidos se serializan con la mutación propietaria y por lo tanto observan ya sea su borrado exitoso o una conversión de fallo estable, no el diario intermedio en vivo. Las razones de degradación/interrupción estables mantienen la aplicación de paquetes en BLOCK_ALL probado y rechazan comandos incrementales de CIDR y modo de paquete. Los cambios de configuración DNS independientes y la caducidad TTL DNS pueden continuar bajo esa retención probada, pero no pueden borrar la razón estable ni reactivar la política de paquete. La recuperación de una razón estable requiere un estado deseado completo de LPM y DNS: aplicar BulkUpdate a través del plano de control o la API local (o responder a un Subscribed fresco de una adjunción restaurada con SubscribedAck). Netfence prepara el estado protegido completo, aplica el estado DNS autoritativo, activa el modo solicitado y borra la razón duradera solo después de que cada paso tenga éxito. Prefiera un command_id único en un BulkUpdate de recuperación del plano de control y requiera un CommandResult exitoso; la API local rechaza command_id porque su RPC unario ya informa éxito o fallo.

Los latidos exponen las entradas físicas actuales, la capacidad máxima y el máximo de generación del daemon de forma independiente para los cuatro mapas protegidos. El arranque está incluido; las entradas fijadas adoptadas inicializan el máximo de la nueva generación. map_full_drops es acumulativo e incluye rechazos de capacidad protegida. Si una lectura de ocupación falla, el daemon retiene la última instantánea probada y emite una advertencia como máximo una vez cada 30 segundos en lugar de inventar nuevos recuentos. Para recuperarse de la presión, reduzca las reglas deseadas completas por debajo de cada capacidad por mapa y reintente la actualización completa. Aumentar filter.max_rule_entries es solo en tiempo de carga y requiere recrear una adjunción fijada existente. Si el daemon no puede probar BLOCK_ALL o registrar de forma duradera su marcador de seguridad, detiene la admisión de mutación; repare la falla de mapa/almacén y reinicie en lugar de asumir que la aplicación se reabrió.

Por host

Ejecute el daemon, el cual:

  • Expone una API gRPC local (DaemonService) para adjunciones, política e inspección
  • Opcionalmente se conecta a su plano de control a través de flujo bidireccional (ControlPlane.Connect)
  • Carga y gestiona programas eBPF

Inicie el daemon:```bash

Start with default config

netfenced start

Start with custom config file

netfenced start --config /etc/netfence/config.yaml

root@kitploit:~
**Verificar el estado del daemon:**```bash
netfenced status

Sin un control_plane.url, un nuevo adjunto se confirma en modo paquete/DNS deshabilitado y puede configurarse inmediatamente a través de la API local o CLI. No se requiere ningún proceso de plano de control para el flujo de trabajo independiente documentado en “Por adjunto”.

Límite de confianza del socket Unix local

La API gRPC local no tiene autenticación por RPC. El acceso al sistema de archivos de su socket Unix es el límite de autorización, y cada proceso que pueda conectarse es un administrador de red de host completamente confiable: puede adjuntar o desvincular programas eBPF del host, reemplazar políticas de paquetes y DNS, y abrir o cerrar tráfico de carga de trabajo. Mantenga restringida la membresía del grupo del socket y proteja el directorio padre del socket.```yaml

Defaults to /var/run/netfence.sock.

socket: /run/netfence/netfence.sock

Unix group name or numeric GID. Empty/unset uses the daemon's effective GID.

socket_group: netfence-admin

root@kitploit:~
`NETFENCE_SOCKET` y `NETFENCE_SOCKET_GROUP` son las variables de entorno equivalentes. Al iniciar, el daemon vincula el socket en un directorio de staging privado, establece su grupo y modo `0660` mientras es inalcanzable, y luego lo publica atómicamente. El daemon elimina cualquier socket Unix preexistente en el destino configurado — no distingue un socket obsoleto de uno propiedad de otro daemon activo — por lo que exactamente un daemon debe poseer una ruta de socket. Se niega a eliminar un objetivo que no sea un socket. En Linux, el renombrado sin reemplazo evita sobrescribir una nueva ruta creada después de esa eliminación; el apagado elimina la ruta publicada solo mientras aún identifica el inodo del socket propio del daemon. Un grupo inválido, fallo de propiedad/modo, o un objetivo que no sea un socket, falla al iniciar sin publicar un endpoint permisivo.

### Seguridad del transporte del plano de control (TLS / mTLS / token portador)

El canal del plano de control es la superficie de ataque de mayor valor en el sistema (quien lo controle puede enviar reglas `ALLOW` a cada carga de trabajo), por lo que el daemon **falla cerrado**: si `control_plane.url` está configurado, la configuración debe elegir explícitamente un transporte — ya sea un bloque `control_plane.tls` o `control_plane.insecure: true`. Una URL sin ninguno es rechazada al iniciar; no hay un valor predeterminado implícito en texto plano. (Este es un cambio de comportamiento deliberado: versiones anteriores se conectaban silenciosamente al plano de control sin cifrar.)```yaml
control_plane:
  url: cp.internal:443
  tls:
    # CA bundle used to verify the control-plane server certificate.
    # Path to a PEM file or inline PEM; omit to use the system root pool.
    ca: /etc/netfence/cp-ca.pem
    # Client certificate + key (path or inline PEM). Setting BOTH enables
    # mTLS: the daemon presents this cert to the control plane. Setting only
    # one is a config error.
    cert: /etc/netfence/daemon.pem
    key: /etc/netfence/daemon.key
    # Optional hostname override for server certificate verification (SNI),
    # e.g. when dialing by IP.
    server_name: cp.internal
  # Optional bearer token, sent as `authorization: Bearer <token>` metadata
  # on every control-plane RPC. Refused on a plaintext channel unless
  # `insecure: true` was explicitly set (so a misconfiguration can't leak it).
  auth_token: "..."

TLS solo con raíces del sistema (certificado de servidor emitido por CA pública, sin mTLS) es solo un bloque vacío:```yaml control_plane: url: cp.example.com:443 tls: {}

root@kitploit:~
Plaintext para desarrollo local es una opción explícita (mutuamente excluyente con `tls`):```yaml
control_plane:
  url: localhost:9000
  insecure: true

Los certificados y las claves se cargan una sola vez al inicio, por lo que una ruta/PEM incorrecta provoca un error claro al arrancar en lugar de aparecer en cada reconexión.

Vitalidad del plano de control (keepalive) y retroceso de reconexión

El daemon envía pings keepalive HTTP/2 en la conexión del plano de control para que una ruta muerta silenciosamente (tirón de cable, mapeo NAT caído, ruta agujero negro) sea detectada y derribada en aproximadamente keepalive_time + keepalive_timeout — en lugar de permanecer en CONNECTED durante minutos hasta el tiempo de espera de retransmisión TCP del kernel mientras cada consulta DNS proxyada consume todo su tiempo de espera. Las reconexiones se espacian mediante un retroceso exponencial con fluctuación (comienza en 1s, se duplica, fluctuación ±20%, limitado a reconnect_backoff_max); el retroceso se reinicia al mínimo solo después de que una conexión se haya mantenido saludable durante 30 segundos, por lo que un plano de control que acepta conexiones y las suelta inmediatamente sigue retrocediendo en lugar de ser golpeado en el mínimo.```yaml control_plane:

Send a keepalive ping after this much inactivity… (default 30s; gRPC

clamps the effective interval to a 10s minimum client-side)

keepalive_time: 30s

…and declare the peer dead if no ack arrives within this (default 10s).

keepalive_timeout: 10s

Cap on the jittered exponential reconnect backoff (default 30s).

reconnect_backoff_max: 30s

root@kitploit:~
Los valores cero/no establecidos significan los valores predeterminados — **no** deshabilitan el keepalive ni el backoff. Su plano de control debe permitir esta cadencia de ping en su política de cumplimiento de gRPC keepalive (ver más abajo), o rechazará el daemon con `ENHANCE_YOUR_CALM (too_many_pings)`.

### Reinicios, fallos y actualizaciones del daemon (estado BPF fijado)

El daemon fija los enlaces BPF y los mapas de reglas de cada attachment a bpffs (`filter.bpf_pin_dir`, predeterminado `/sys/fs/bpf/netfence`, un directorio por ID de attachment). Debido a que el estado fijado es mantenido por el kernel — no por el proceso del daemon — **la aplicación continúa mientras el daemon está inactivo**: un fallo (`kill -9`), una parada controlada o una actualización deja aplicando la última política conocida (modo + todas las reglas), y el siguiente inicio del daemon readopta el estado fijado tal cual. La restauración nunca vuelve a adjuntar o reescribe los mapas en vivo, por lo que no hay una ventana en la que una carga de trabajo en lista blanca esté bloqueada o un destino bloqueado esté permitido, y no hay attachment duplicado.

El comportamiento de parada es una configuración explícita (`filter.detach_on_stop`):```yaml
filter:
  # false (default): stopping the daemon KEEPS ENFORCING — filters stay
  # attached via their bpffs pins and are re-adopted on the next start
  # (fail-closed across restarts/upgrades).
  # true: stopping the daemon detaches filters and removes their pins —
  # traffic is unfiltered while the daemon is down (explicit fail-open).
  detach_on_stop: false
  # bpffs directory for pinned state. Must be on a bpffs mount; the daemon
  # mounts bpffs at /sys/fs/bpf if needed (privileged). An explicit "" turns
  # pinning off entirely (BPF state then dies with the process).
  bpf_pin_dir: /sys/fs/bpf/netfence
  # Capacity of each authoritative/system LPM map (allowed/denied per family).
  # Protected entries are non-evictable; the DNS listener bootstrap consumes
  # one slot in its address family. Changing pinned-map capacity requires
  # recreating the attachment.
  max_rule_entries: 4096
  # Independent capacity of each DNS-derived exact-host HASH map (IPv4/IPv6).
  # These entries can never consume or evict authoritative/deny capacity.
  max_dns_rule_entries: 4096

Un Detach explícito (RPC/CLI), o la eliminación de un objetivo activo de propiedad coherente, destruye el estado anclado junto con el attachment. Al reiniciar, la ausencia del objetivo no autoriza suposiciones: los pines persistentes futuros, no confirmados, mixtos o de otro modo no verificables se conservan y el inicio se aborta para inspección.

Los directorios de pines son un formato de persistencia versionado. El marcador de esquema se ancla al final, solo después de que existan todos los mapas y enlaces requeridos. Al actualizar un attachment de nivel pre-exacto, se anclan los dos nuevos mapas exactos vacíos con un marcador en progreso, se reemplaza atómicamente el programa de cada enlace mientras se reutilizan los mapas autoritativos activos, se verifica la identidad programa/mapa y se confirma el marcador al final. Un bloqueo o una actualización ambigua deja el marcador sin confirmar; en el siguiente inicio, se vuelven a actualizar todos los enlaces utilizando los mismos mapas. Las generaciones de programas antiguas y nuevas aplican la misma política LPM autoritativa durante ese estado mixto acotado, por lo que la migración nunca desancla ni recrea un filtro viable. Los conjuntos de pines desconocidos, incompletos o no verificables se conservan y abortan el inicio para inspección, en lugar de ser adivinados.

Notas sobre el estado readoptado:

  • Cada attachment restaurado con éxito se marca para reconciliación autoritativa. En cada conexión del plano de control, el daemon envía primero SyncRequest, luego una declaración Subscribed completa para cada attachment restaurado que aún necesita reconciliación. Responda con un SubscribedAck fresco: su modo, CIDRs, TTL y configuración DNS son el estado deseado completo. El daemon aplica un delta (los CIDR sin cambios nunca se eliminan) y borra el marcador de restauración solo después de que se aplique toda la confirmación. Un tiempo de espera, desconexión o fallo de validación deja la aplicación sin cambios. Un fallo de aplicación de filtro/mapa/DNS/almacenamiento puede dejar un delta parcial, pero la reconciliación no utiliza una limpieza masiva del mapa ni elimina/vuelve a agregar supervivientes sin cambios; el marcador de restauración permanece establecido y el daemon reintenta después de una conexión posterior.
  • Los plazos de TTL de las reglas en sí mismos no se persisten. Las reglas readoptadas se tratan provisionalmente como permanentes hasta que llegue el SubscribedAck fresco; esa confirmación autoritativa reemplaza exactamente sus tiempos de vida, incluido acortar un plazo o convertir una regla provisionalmente permanente nuevamente en una regla de TTL finito. Las claves DNS exactas restauradas se inventarian y representan mediante propietarios provisionales acotados (las capacidades reales del mapa anclado son el límite); la primera configuración DNS autoritativa descarta toda reclamación sintética, elimina las claves que quedan sin propietario y conserva una clave solo cuando tiene por separado un propietario activo normal. Un inventario no canónico/en conflicto aborta la restauración sin adivinar ni publicar parcialmente metadatos de propiedad.
  • No existe un documento de estado deseado local persistido. Si no hay un plano de control configurado o accesible, no se producen cambios automáticos de reglas: un mapa anclado adoptado continúa aplicando sus CIDR protegidos conocidos, representados en el registro del espacio de usuario como provisionales hasta una actualización completa. Una restauración que no puede adoptar pines válidos recrea el attachment en su modo persistido con mapas vacíos (cierre por fallo para lista blanca/bloquear todo). Un orquestador independiente debe reproducir netfenced apply-rules después de cada reinicio del daemon para reemplazar el estado de paquete provisional y restaurar su estado deseado completo y TTL.
  • Las reglas de dominio DNS, las anulaciones de upstream por attachment y los límites de DNS del attachment son estado deseado en tiempo de ejecución proporcionado a través de la API local o el plano de control; no se persisten. Un attachment restaurado cuyo último modo DNS fue ALLOWLIST, DENYLIST o PROXY inicia su resolvedor en una postura ALLOWLIST vacía, devolviendo REFUSED hasta que se aplique un BulkUpdate o SubscribedAck completo. Un modo DNS explícitamente DISABLED permanece reenviando. Si alguno de los listeners UDP/TCP confirmados muere inesperadamente más tarde, el attachment se pone en cuarentena en IP BLOCK_ALL y se reporta como un error de cancelación de suscripción.
  • El servidor DNS por attachment es un componente de espacio de usuario y se detiene con el daemon; mientras el daemon está inactivo, las IP exactas ya resueltas y ancladas siguen funcionando bajo la última política de paquetes conocida, pero no se pueden resolver nuevos nombres a través de él. Sus plazos perdidos en espacio de usuario se tratan provisionalmente en lugar de adivinarse hasta la reconciliación autoritativa.

Por attachment

Su sistema de orquestación llama a la API local del daemon.

RPC:``` DaemonService.Attach(interface_name: "veth123", tc_direction: TC_DIRECTION_INGRESS, metadata: {vm_id: "abc"}) // or DaemonService.Attach(cgroup_path: "/sys/fs/cgroup/...", metadata: {container_id: "xyz"})

root@kitploit:~
**CLI:**```bash
# Attach to a host-side veth peer or VM tap (TC) - use ingress direction
netfenced attach --interface veth123 --direction ingress --metadata vm_id=abc

# Attach to a cgroup
netfenced attach --cgroup /sys/fs/cgroup/... --metadata container_id=xyz

# Attach to an uplink inside the workload's own netns (TC) - egress is the default
netfenced attach --interface eth0 --metadata tenant=acme,env=prod

Dirección de TC: el campo tc_direction (CLI --direction) selecciona a qué hook de TCX se adjunta el filtro, y elegir el correcto depende de en qué lado del enlace se encuentra la interfaz:

InterfazDirección correctaPor qué
Enlace ascendente (p. ej. eth0), o cualquier interfaz dentro del propio netns de la carga de trabajoegress (predeterminado)Los paquetes salientes de la carga de trabajo se transmiten a través de él; su dirección de destino es el destino real.
Par veth del lado del host o VM tap (p. ej. fcr-*)ingressLos paquetes salientes de la carga de trabajo llegan al host en esa interfaz. El egress allí vería en su lugar el tráfico de retorno host→carga de trabajo y filtraría por la dirección propia de la carga de trabajo en lugar del destino real.

La dirección solo se aplica a los adjuntos de interfaz (TC); se ignora para los adjuntos de cgroup.

  • El daemon adjunta un filtro eBPF al objetivo.
  • Cuando se configura control_plane.url, el daemon envía Subscribed{id, target, type, metadata} y espera SubscribedAck con la configuración inicial (modo, CIDRs, reglas DNS). Si el plano de control no responde dentro del tiempo de espera (predeterminado 5s, configurable mediante control_plane.subscribe_ack_timeout), el adjunto se revierte y la llamada de adjunto falla. Las fallas de validación y otras previas a la confirmación siguen la misma regla de reversión ordinaria.
  • Sin plano de control configurado, el adjunto se confirma inmediatamente en modo deshabilitado; use los comandos de política local a continuación para configurarlo.
  • Una política inicial válida que alcanza una falla de mapa/almacén protegido es la excepción deliberada de error confirmado: el daemon retiene el adjunto en BLOCK_ALL duradero en lugar de revertirlo de manera destructiva. Con un tiempo de espera limitado, Attach devuelve un error que contiene el ID del adjunto retenido; el llamante puede descubrir ese ID coincidiendo con el objetivo en List, y el plano de control debe recuperarlo con un BulkUpdate completo.
  • Con subscribe_ack_timeout: 0, un nuevo Attach regresa después de poner en cola Subscribed; un ack posterior aún se valida y aplica. Este valor cero no deshabilita la reconciliación de adjuntos restaurados: los intentos de restauración esperan hasta 5s en segundo plano y reintentan en una conexión posterior si es necesario. Si ese ack posterior encuentra presión protegida, el adjunto ya devuelto se retiene en BLOCK_ALL; SubscribedAck no emite ni CommandResult ni error Unsubscribed, y el daemon no vuelve a impulsar automáticamente la declaración antes del reinicio. Detecte policy_degraded más su razón, ocupación/capacidad y map_full_drops en Heartbeat, luego envíe un BulkUpdate completo con command_id para obtener un resultado de recuperación explícito.
  • El daemon monitorea la eliminación del objetivo y envía Unsubscribed automáticamente

RPC:``` DaemonService.Detach(id)

root@kitploit:~
**CLI:**```bash
netfenced detach --id <attachment-id>

Listar archivos adjuntos:```bash netfenced list netfenced list --all # fetch all pages

root@kitploit:~
### Política local e inspección

Cada mutación local es una codificación CLI delgada de la única RPC
`DaemonService.ApplyCommand(ControlCommand)`. Proporcione el ID de archivo adjunto
devuelto por `attach`:```bash
# Packet policy and protected CIDRs.
netfenced set-mode <id> allowlist
netfenced allow-cidr <id> 10.0.0.0/8
netfenced allow-cidr <id> 192.0.2.10/32 --ttl 5m
netfenced deny-cidr <id> 10.20.0.0/16
netfenced remove-cidr <id> 10.20.0.0/16 --list deny
# --list accepts allow, deny, or both (the default).

# DNS policy.
netfenced set-dns-mode <id> denylist
netfenced allow-domain <id> example.com --subdomains
netfenced deny-domain <id> blocked.example.com
netfenced remove-domain <id> blocked.example.com

# Deterministic current-policy inspection as protobuf JSON.
netfenced rules <id>

Los modos de paquete son disabled, allowlist, denylist y block-all; los modos DNS son disabled, allowlist, denylist y proxy. El modo DNS proxy requiere un plano de control configurado y accesible. La coincidencia de dominios utiliza el sufijo de coincidencia más específico; cuando reglas de permitir y denegar igualmente específicas coinciden, gana la denegación. Las CIDR y los dominios se canonican. Los TTL, enumeraciones, CIDR, dominios, selectores y mensajes anidados negativos, mal formados o de otro modo inválidos son rechazados antes de la mutación, por lo que un comando inválido es una no-operación de política.

Para un reemplazo completo, apply-rules lee la forma JSON existente del protobuf BulkUpdate desde un archivo o stdin:```bash cat >rules.json <<'JSON' { "mode": "POLICY_MODE_ALLOWLIST", "allowCidrs": [{"cidr": "10.0.0.0/8"}], "dns": { "mode": "DNS_MODE_DENYLIST", "denyDomains": [{"domain": "blocked.example.com", "includeSubdomains": true}] } } JSON netfenced apply-rules --file rules.json

Equivalent stdin form:

netfenced apply-rules --file - < rules.json

root@kitploit:~
`ApplyCommand` solo acepta `SetMode`, `AllowCIDR`, `DenyCIDR`, `RemoveCIDR`, `BulkUpdate`, `SetDnsMode`, `AllowDomain`, `DenyDomain` y `RemoveDomain`. Las variantes de sync/ack solo de flujo, comandos desconocidos o vacíos, y valores locales de `command_id` son rechazados. `BulkUpdate` es también la única operación local que puede recuperar una política de paquetes degradada estable; debe contener el estado deseado completo de LPM y DNS.

El selector opcional `ControlCommand.remove_cidr_list` puede apuntar a la lista de permitidos, la lista de denegados, o ambas cuando la variante de comando es `RemoveCIDR`. Su valor heredado no especificado y el explícito `BOTH` ambos eliminan de ambas listas, preservando el comportamiento original del protocolo.

Las mutaciones locales y del plano de control comparten un analizador sintáctico, barrera de mutación, registro TTL, ruta de recuperación de fallo cerrado y propietario de política. Deliberadamente no hay arbitraje de propiedad entre local y plano de control: las operaciones conflictivas en una lista de políticas individual surten efecto en su orden de confirmación, independientemente de la fuente. En particular, una `BulkUpdate` completa posterior del plano de control o `SubscribedAck` puede reemplazar el estado local.

`GetRules`/`netfenced rules` devuelve una instantánea coherente y determinista del registro de espacio de usuario. Cada CIDR reporta lista de permitidos/denegados, `policyOwned` local o del plano de control, `systemOwned` del daemon, `expiresAt` absoluto, `provisional` restaurado, y el último estado `installed` del kernel confirmado. Una entrada instalada sin propietario es un reintento de eliminación fallido, no una política deseada. La salida DNS es la `DnsConfig` efectiva normalizada en vivo. La inspección intencionalmente no enumera mapas protegidos del kernel ni expone entradas de caché de DNS exact-host resueltas dinámicamente; use la telemetría de latido para la ocupación de mapas protegidos.

## En el plano de control (tú implementas esto)

Implementa `ControlPlane.Connect` RPC - un flujo bidireccional:

Configura la política de cumplimiento de keepalive de tu servidor gRPC para permitir la cadencia de ping del daemon (`control_plane.keepalive_time`, por defecto 30s): establece `MinTime` en o por debajo de ese intervalo y `PermitWithoutStream: true`. La política predeterminada de gRPC (5 minutos) trata los pings del daemon como abusivos y cierra la conexión con `ENHANCE_YOUR_CALM (too_many_pings)`. En Go:```go
grpc.NewServer(grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
    MinTime:             10 * time.Second,
    PermitWithoutStream: true,
}))

Recibir del demonio:

  • SyncRequest al conectar/reconectar (enumera los adjuntos actuales)
  • Subscribed cuando se añaden nuevos adjuntos, y después de SyncRequest para adjuntos restaurados que aún necesitan estado autoritativo fresco
  • Unsubscribed cuando se eliminan adjuntos
  • Heartbeat con estadísticas
  • CommandResult{command_id, id, success, error} — resultado de cualquier comando que hayas enviado con un command_id no vacío (nonce de correlación opcional en ControlCommand; los comandos sin uno no producen resultado). success es verdadero solo si el comando se aplicó completamente — un BulkUpdate aplicado parcialmente informa fallo con el error agregado. Los resultados son de mejor esfuerzo: trata un resultado faltante como desconocido, no como fallido.

Enviar al demonio:

  • SyncAck después de recibir SyncRequest
  • SubscribedAck{mode, cidrs, dns_config} después de recibir Subscribed (requerido - el demonio espera esto)
  • SetMode{mode} - cambiar el modo de política de filtro IP
  • AllowCIDR{cidr, ttl} / DenyCIDR / RemoveCIDR (opcionalmente seleccionar permitir, denegar o ambos; no especificado conserva el comportamiento heredado de "ambos")
  • SetDnsMode{mode} - cambiar el modo de filtrado DNS
  • AllowDomain{dominio} / DenyDomain / RemoveDomain (la coincidencia más específica gana; denegar gana en un empate de igual especificidad)
  • BulkUpdate{mode, cidrs, dns_config} - sincronización completa de estado

Cuando el plano de control recibe Subscribed, debe responder con un SubscribedAck completo. Para un nuevo adjunto, el demonio normalmente espera ese acuse antes de devolver éxito al llamante local. Para un adjunto restaurado, el handshake se ejecuta en segundo plano mientras la política fijada conocida sigue aplicándose. Usa los metadatos para identificar la VM/inquilino/contenedor y devolver el modo completo deseado, CIDRs (incluyendo TTLs) y el estado DNS; una configuración DNS omitida significa deshabilitado con listas de dominio vacías.

Reconexiones e idempotencia (requerido)

SyncRequest es el punto de reconciliación autoritativo: en cada (re)conexión es el primer evento en el flujo y lista el conjunto completo de adjuntos actuales del demonio. Reconciliá tu vista contra él — añade adjuntos que no conocías, elimina los que faltan en la lista. Al reconectar, el demonio purga eventos que estaban en cola contra la conexión anterior (la sincronización los reemplaza), por lo que no verás Heartbeats obsoletos, Unsubscribeds para adjuntos ya ausentes de la sincronización, o CommandResults de la conexión muerta reproducidos después. Dos casos límite permanecen por diseño, y tu plano de control DEBE manejarlos idempotentemente:

  • Un Subscribed puede seguir a un SyncRequest que ya lista el mismo id. Esto ocurre cuando el acuse de un nuevo adjunto estaba pendiente durante la reconexión, y deliberadamente para cada adjunto restaurado hasta que un acuse autoritativo se aplique completamente. Trátalo como una actualización, responde con un SubscribedAck completo y fresco, y nunca lo descartes como duplicado. SyncRequest reconcilia el inventario de adjuntos; SubscribedAck reconcilia la política deseada.
  • Un evento generado concurrentemente con la (re)conexión puede competir con la instantánea de sincronización en cualquier dirección. Trata un Unsubscribed para un id de adjunto desconocido o ya eliminado como una no-operación.

Tiempos de vida de las reglas (TTLs)

  • Las entradas CIDR (comandos AllowCIDR/DenyCIDR, y las listas CIDR en SubscribedAck/BulkUpdate) llevan un TTL opcional. Las reglas con TTL son eliminadas por un recolector del demonio una vez que expiran (intervalo de escaneo ttl_janitor_interval, por defecto 1s); las reglas sin TTL son permanentes.
  • Las readiciones incrementales de AllowCIDR/DenyCIDR extienden un CIDR hasta la fecha límite posterior — nunca acortan una — y una readición incremental sin TTL la hace permanente. En contraste, el estado completo en SubscribedAck/BulkUpdate reemplaza exactamente cada vida útil del plano de control, por lo que la reconciliación autoritativa puede acortar un TTL o cambiar permanente a finito sin eliminar/readicionar la entrada del mapa activo. Usa RemoveCIDR para eliminar una regla incremental temprano.
  • Las IPs resueltas por DNS entran solo en el nivel exacto con el TTL del registro limitado por dns.min_filter_ttl (por defecto 60s; cero/no establecido significa el valor por defecto, no "sin límite"). Por lo tanto, un TTL aguas arriba de cero vive durante el límite inferior; un TTL PROXY omitido se establece explícitamente por defecto a 300s antes de aplicar el límite inferior. Una regla CIDR permanente o de mayor duración que cubra la misma dirección permanece instalada independientemente en el nivel LPM protegido cuando la propiedad exacta del DNS expira.
  • Los CIDR de permitir y denegar autoritativos/sistema permanecen en cuatro mapas LPM protegidos y no desalojables, dimensionados por filter.max_rule_entries por adjunto (por defecto 4096 cada uno); ver “Capacidad CIDR protegida y recuperación de fallo-cerrado” arriba. Las direcciones de host derivadas de DNS usan mapas HASH de coincidencia exacta separados, dimensionados por filter.max_dns_rule_entries (por defecto 4096 por familia IP), por lo que no pueden consumir ni desalojar capacidad autoritativa o de denegar. La admisión completa de respuesta DNS valida/canonicaliza cada dirección y verifica la capacidad física y lógica antes de la mutación. Un error del kernel del mapa exacto DNS restaura su instantánea exacta anterior a la llamada; si esa reversión no puede ser probada, el resolvedor suprime la respuesta y pone en cuarentena el adjunto en IP duradero BLOCK_ALL antes de aceptar otra mutación.