为什么选择 NSE? • 功能特性 • 环境要求 • 安装 • 快速开始 • 工作原理 • 项目结构
在运行中的 Linux 系统上测试防火墙规则集存在重大风险:格式错误的规则可能会中断 SSH 管理会话、在测试期间泄露明文流量,或在主机上留下孤立的防火墙表。
Network Sandbox Engine (NSE) 提供了一个安全、可复现的测试框架。它构建临时的 Linux 网络命名空间,连接虚拟以太网对,编译 nftables 规则集,并使用 Scapy 注入合成的二层和三层数据包。所有评估都在沙箱命名空间内进行:主机防火墙状态绝不会被修改。
关键架构特性:
nse_<uuid>)中,并在拆除期间被完全移除。nse/ 约 1150 条语句,测试覆盖率 98%。NSE 会创建网络命名空间、加载 nftables 规则集并读取内核跟踪事件,因此它以 root 身份运行。它不会打开任何类型的套接字、端口或 RPC 端点——它是一个由你调用的库和 CLI,并且仅在运行期间持有特权。
2.1.0 版本移除了早期版本附带的 FastAPI/Svelte Web 界面。从 2.0.0 起,该界面以 root 身份在进程内运行,对于测试工具而言这是一个巨大的攻击面;如果你需要,代码仍保留在 git 历史中的 v2.0.0 标签处。
防火墙测试是一种否定性断言——“这个数据包没有通过”——除非已知测量仪器正常工作,否则否定性断言毫无价值。一个从未附加到内核的跟踪监视器和一个阻止一切流量的防火墙会产生字节完全相同的输出。
因此,NSE 拒绝报告它无法证明已测量到的判定:
金丝雀数据包按跟踪 ID 从结果中排除,因此它们绝不会出现在你的判定流中。
测试套件证明这一点成立,而非仅仅断言:make test-blind 强制解析器什么都不理解,除非运行器以非零退出,否则构建失败。该任务在每次推送时都会在 CI 中运行。
run_test_pipeline),返回结构化的 Pydantic 模型(TestRequest、TraceEvent)。nse_<id>)直接连接到主机。nse_router_<id>)和服务器(nse_server_<id>)链,用于转发和 NAT 测试。nse-runner)。在判定错误以及未能观察到判定时以非零退出。mypy --strict)、架构边界强制(import-linter)、ruff 格式化,以及覆盖率棘轮(make test-cov,下限 98%)。nft)ip)ip netns 和内核跟踪操作所需)在 Debian 或 Ubuntu 系统上:
sudo apt update && sudo apt install -y nftables iproute2 conntrack
安装带 CLI 支持的核心引擎:
pip install "network-sandbox-engine[cli]"
用于本地开发:
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())
创建测试文件 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 是按数据包设置的。未知键会被拒绝而非采用默认值,因此拼写错误会导致测试套件失败,而不是悄然变成你从未写过的预期。
以 root 权限运行测试套件:
sudo nse-runner --file firewall_test.yaml
退出码:0 所有数据包匹配;1 判定错误或引擎无法观察到判定。预言机错误与防火墙失败分开报告,因为它们意味着测量出了问题,而非规则集。
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
用于固定你的规则所针对测试的 nftables 版本。
NSE 通过结构化的多阶段执行流水线编排 Linux 内核网络子系统和跟踪接口:
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() 使用 nft --check -f 对规则集进行试运行。NetnsController 创建隔离的网络命名空间并配置虚拟以太网(veth)接口。meta nftrace set 1)。ScapyInjector 通过 veth 链路注入合成帧。TraceHarvester 捕获 nft monitor trace 事件并返回结构化的 TraceEvent 对象。完整技术规范请参见 技术架构指南。
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
一个标签。git push origin vX.Y.Z 会构建、使用 Sigstore 签名、发布 GitHub Release、上传到 TestPyPI、从 TestPyPI 安装并进行冒烟测试,然后才上传到 PyPI。使用 make release-dry 进行演练。
完整的交互式 Web 文档位于:
https://onyks-os.github.io/nse/
在本地构建文档:
make docs
在 http://127.0.0.1:8000 上以热重载方式提供文档:
make docs-serve
运行静态检查和单元测试:
make verify
运行完整的本地 CI 验证(包括静态检查、单元测试、前端构建、文档构建、PyPI 冒烟测试和特权集成测试):
make ci-local
本项目采用 MIT 许可证 授权。
| 保证 | 机制 |
|---|
| 监视器在第一个测试数据包之前已附加 | 注入就绪金丝雀数据包并重复注入,直到观察到其内核跟踪。无观察,则无运行。 |
| 监视器在最后一个数据包之后仍然附加 | 在注入后运行存活金丝雀。如果未捕获到,则判定流被声明为截断。 |
| 解析器理解内核所述内容 | 统计没有模式匹配的跟踪行,任何大于零的计数都是错误,而非调试日志。 |
| 监视器没有悄然死亡 | 读取循环记录其结束的原因——正常停止、意外 EOF、超时或崩溃——只有正常停止是可接受的。 |
| 缺失的判定不是通过 | 当观察到的判定数量与预期数量不一致时(无论哪个方向),CLI 运行器都会失败。 |