
Un sandbox de red determinista para probar reglas de nftables. Utiliza espacios de nombres de red de Linux efímeros (netns) y Scapy para validar la lógica del firewall de forma segura.
¿Por qué NSE? • Características • Requisitos • Instalación • Inicio rápido • Cómo funciona • Estructura del proyecto
Probar conjuntos de reglas de cortafuegos en un sistema Linux en producción conlleva riesgos significativos: reglas mal formadas pueden cortar sesiones de gestión SSH, filtrar tráfico en texto claro durante las pruebas o dejar tablas de cortafuegos huérfanas activas en el host.
Network Sandbox Engine (NSE) proporciona un entorno de pruebas seguro y reproducible. Construye espacios de nombres de red Linux efímeros, conecta pares de ethernet virtuales, compila conjuntos de reglas nftables e inyecta paquetes sintéticos de Capa 2 y Capa 3 usando Scapy. Toda la evaluación ocurre dentro del espacio de nombres del sandbox: el estado del cortafuegos del host nunca se modifica.
Propiedades arquitectónicas clave:
nse_<uuid>) y se eliminan por completo durante el desmontaje.nse/ tiene ~1150 sentencias con 98% de cobertura de pruebas.NSE crea espacios de nombres de red, carga conjuntos de reglas nftables y lee eventos de rastreo del kernel, por lo que se ejecuta como root. No abre un socket, un puerto ni un endpoint RPC de ningún tipo — es una biblioteca y una CLI que usted invoca, y mantiene privilegios solo durante la duración de una ejecución.
La versión 2.1.0 eliminó la interfaz web FastAPI/Svelte que incluían las versiones anteriores.
Esa interfaz se ejecutaba en proceso como root desde la 2.0.0 en adelante, lo que representaba una
gran superficie de ataque para una herramienta de pruebas; el código permanece en el historial de git en la
etiqueta v2.0.0 si lo necesita.
Una prueba de cortafuegos es una aserción negativa — "este paquete no pasó" — y una aserción negativa no vale nada a menos que se sepa que el instrumento funciona. Un monitor de rastreo que nunca se conectó al kernel y un cortafuegos que bloqueó todo producen una salida idéntica byte a byte.
Por lo tanto, NSE se niega a informar un veredicto que no pueda demostrar que midió:
| Garantía | Mecanismo |
|---|---|
| El monitor estaba conectado antes del primer paquete de prueba | Se inyecta un canario de preparación y se reinyecta hasta que se observe su rastro en el kernel. Sin observación, no hay ejecución. |
| El monitor seguía conectado después del último | Se ejecuta un canario de vitalidad después de la inyección. Si se pierde, el flujo de veredictos se declara truncado. |
| El analizador entendió lo que dijo el kernel | Las líneas de rastreo que ningún patrón coincide se cuentan, y cualquier recuento superior a cero es un error en lugar de un registro de depuración. |
| El monitor no murió silenciosamente | El bucle de lectura registra por qué terminó — parada limpia, EOF inesperado, tiempo de espera o fallo — y solo una parada limpia es aceptable. |
| Un veredicto ausente no es un aprobado | El ejecutor de la CLI falla cuando el número de veredictos observados difiere del número esperado, en cualquier dirección. |
Los paquetes canario se excluyen de los resultados por id de rastreo, por lo que nunca aparecen en su flujo de veredictos.
La suite demuestra que esto se cumple, en lugar de afirmarlo: make test-blind fuerza
al analizador a no entender nada, y la compilación falla a menos que el ejecutor salga
con un código distinto de cero. Ese trabajo se ejecuta en CI en cada push.
run_test_pipeline) que devuelve modelos Pydantic estructurados (TestRequest, TraceEvent).nse_<id>) conectado directamente al host.nse_router_<id>) y Servidor (nse_server_<id>) para pruebas de reenvío y NAT.nse-runner). Sale con un código distinto de cero ante un veredicto incorrecto y ante un veredicto que no pudo observar.mypy --strict), aplicación de límites arquitectónicos (import-linter), formateo con ruff y un trinquete de cobertura (make test-cov, mínimo 98%).nft)ip)ip netns y operaciones de rastreo del kernel)En sistemas Debian o Ubuntu:
sudo apt update && sudo apt install -y nftables iproute2 conntrack
Instale el motor principal con soporte de CLI:
pip install "network-sandbox-engine[cli]"
Para desarrollo local:
git clone https://github.com/onyks-os/NetworkSandboxEngine.git
cd NetworkSandboxEngine
make setup
import asyncio
from nse.core.netns_controller import NetnsController
from nse.core.pipeline import run_test_pipeline
from nse.models.test_request import TestRequest, PacketSpec
rules = """
table ip filter {
chain input {
type filter hook input priority 0; policy drop;
tcp dport 80 accept
}
}
"""
request = TestRequest(
rules=rules,
packets=[
PacketSpec(protocol="tcp", src_ip="10.0.0.1", dst_ip="10.0.0.2", dst_port=80),
PacketSpec(protocol="tcp", src_ip="10.0.0.1", dst_ip="10.0.0.2", dst_port=22),
],
)
async def main():
controller = NetnsController()
events = await run_test_pipeline(request=request, controller=controller)
for evt in events:
if evt.verdict:
print(f"[{evt.chain}] Verdict: {evt.verdict}")
asyncio.run(main())
Cree un archivo de prueba firewall_test.yaml:
tests:
- name: "Allow HTTP Port 80, Drop SSH Port 22"
topology: simple
rules: |
table ip filter {
chain input {
type filter hook input priority 0; policy drop;
tcp dport 80 accept
}
}
packets:
- protocol: tcp
src_ip: 10.0.0.1
dst_ip: 10.0.0.2
dst_port: 80
expected_verdict: ACCEPT
- protocol: tcp
src_ip: 10.0.0.1
dst_ip: 10.0.0.2
dst_port: 22
expected_verdict: DROP
expected_verdict es por paquete. Las claves desconocidas se rechazan en lugar de
usar valores predeterminados, por lo que un error tipográfico hace fallar la suite en lugar de convertirse silenciosamente en una expectativa
que usted nunca escribió.
Ejecute la suite con privilegios de root:
sudo nse-runner --file firewall_test.yaml
Códigos de salida: 0 todos los paquetes coincidieron; 1 un veredicto fue incorrecto o el motor
no pudo observar uno. Los errores del oráculo se informan por separado de los fallos del cortafuegos,
porque significan que la medición se rompió, no el conjunto de reglas.
podman build -t nse .
podman run --rm --cap-add=NET_ADMIN --cap-add=NET_RAW \
-v "$PWD/firewall_test.yaml:/suite.yaml:ro" nse --file /suite.yaml
Útil para fijar la versión de nftables contra la que se prueban sus reglas.
NSE orquesta los subsistemas de red del kernel de Linux y las interfaces de rastreo a través de una canalización de ejecución estructurada de múltiples etapas:
graph TD
subgraph Step1["1. Test Specification"]
Req["<b>TestRequest</b><br/>ruleset + packets + topology"]
end
subgraph Step2["2. Ephemeral Netns Sandbox"]
direction TB
Netns["<b>Netns Setup</b><br/>nse_<id> & veth links"]
RuleEng["<b>Rule Engine</b><br/>validate & load nftables"]
Inject["<b>Scapy Injector</b><br/>L2/L3 packet injection"]
NFT["<b>Kernel nftables</b><br/>meta nftrace set 1"]
Netns --> RuleEng
RuleEng --> Inject
Inject --> NFT
end
subgraph Step3["3. Trace Evaluation & Oracle"]
direction TB
Harvester["<b>Trace Harvester</b><br/>nft monitor trace stream"]
Oracle["<b>Deterministic Oracle</b><br/>TraceEvents & verdicts"]
Harvester --> Oracle
end
Step1 --> Step2
Step2 --> Step3RuleEngine.validate() ejecuta en seco el conjunto de reglas usando nft --check -f.NetnsController crea el espacio de nombres de red aislado y configura las interfaces de ethernet virtual (veth).meta nftrace set 1).ScapyInjector inyecta tramas sintéticas a través del enlace veth.TraceHarvester captura eventos de nft monitor trace y devuelve objetos TraceEvent estructurados.Para especificaciones técnicas completas, consulte la Guía de arquitectura técnica.
NetworkSandboxEngine/
├── nse/ # Core PyPI package (network-sandbox-engine)
│ ├── core/ # Kernel primitives, pipeline, and naming rules
│ ├── models/ # Pydantic models (TestRequest, PacketSpec, TraceEvent)
│ └── cli/ # Headless YAML runner entrypoint
├── docs/ # Architecture specs and MkDocs web documentation
├── tests/ # Unit, golden file, and privileged e2e tests
│ └── fixtures/nft_trace/ # Golden `nft monitor trace` corpus
├── pyproject.toml # Build backend configuration
└── Makefile # Local automation and CI workflow
Una etiqueta. git push origin vX.Y.Z compila, firma con Sigstore, publica la
GitHub Release, sube a TestPyPI, instala desde TestPyPI y lo prueba de humo,
y solo entonces sube a PyPI. Ensaye con make release-dry.
Consulte docs/RELEASING.md.
La documentación web interactiva completa está disponible en:
https://onyks-os.github.io/nse/
Compile la documentación localmente:
make docs
Sirva la documentación con recarga en caliente en http://127.0.0.1:8000:
make docs-serve
Ejecute el linting estático y las pruebas unitarias:
make verify
Ejecute la verificación completa de CI local (incluye linting, pruebas unitarias, compilación del frontend, compilación de la documentación, prueba de humo de PyPI y pruebas de integración con privilegios):
make ci-local
Este proyecto está licenciado bajo la Licencia MIT.