Network Troubleshooting Guide
Diagnosing captive portals, disconnected interfaces, and relay blocks.
Snigdha NetGuard — Automated Testing & Verification Guide
1. Verification Strategy
Static verification of configuration files is insufficient to prove network security invariants. Snigdha NetGuard employs isolated Linux network namespaces (ip netns and unprivileged unshare -n -r) to inject live packets, execute network redirection, test drop policies, and simulate component failure states.
2. Test Suites Overview
The automated test infrastructure is organized into four distinct test layers:
netguard/tests/
├── unit/
│ ├── test_firewall_unit.sh # nftables syntax, table atomicity, table isolation
│ ├── test_tor_config.sh # torrc invariant audits & tor --verify-config
│ └── test_bridge_validator.py # Strict parser tests, injection rejection, redaction
│
├── integration/
│ └── test_netns_firewall.sh # Simulated egress interface, TCP & DNS redirection
│
├── failure/
│ └── test_failure_injection.sh # Tor crash, disconnect, invalid reload resilience
│
└── runner: tests/test-netguard.sh # Master test harness
3. Running the Test Suites
Execute the comprehensive NetGuard test suite via the top-level test runner:
./tests/test-netguard.sh
Or execute via the master build automation target:
make test
4. Test Details and Assertions
4.1 Unit Test Layer
test_firewall_unit.sh
- Assertion 1:
nft -c -f netguard/firewall/snigdha.nftevaluates with exit code 0. - Assertion 2: Ruleset creates table
inet snigdhaatomically in an isolated netns without requiring root privileges. - Assertion 3: Applying
snigdha.nftover an existing unrelated table (table inet unrelated_table) leaves the unrelated table completely intact, confirming zero reliance on destructiveflush ruleset. - Assertion 4: Repeated sequential execution of the ruleset is idempotent and generates zero errors.
test_tor_config.sh
- Assertion 1: Verifies presence of
ClientOnly 1. - Assertion 2: Verifies mandatory
DisableNetwork 1default. - Assertion 3: Verifies dual-stack transparent proxy listeners:
TransPort 127.0.0.1:9040and[::1]:9040. - Assertion 4: Verifies dual-stack DNS proxy listeners:
DNSPort 127.0.0.1:5353and[::1]:5353. - Assertion 5: Verifies
SocksPort 0(unneeded local SOCKS listener disabled). - Assertion 6: Verifies
CookieAuthentication 1and restrictedControlSocket /run/tor/control. - Assertion 7: Verifies volatile data directory
DataDirectory /run/tor/data. - Assertion 8: Executes
tor -f netguard/tor/torrc --verify-configusing the distribution Tor binary.
test_bridge_validator.py
- Assertion 1: Successfully parses vanilla IPv4 bridges (
192.0.2.1:9001) and fingerprints. - Assertion 2: Successfully parses bracketed IPv6 bridges (
[2001:db8::1]:9001). - Assertion 3: Successfully parses pluggable transport bridges (
obfs4,meek,snowflake,webtunnel). - Assertion 4: Rejects shell command injection vectors (
;,&&,|,`,$()). - Assertion 5: Rejects invalid IP ranges, ports outside 1–65535, and empty input.
- Assertion 6: Verifies that
sanitize_bridge_line()masks all IP addresses and fingerprints.
4.2 Integration Test Layer (test_netns_firewall.sh)
The integration test creates an isolated network namespace with a virtual ethernet pair (eth0 <-> veth1) and sets a default route to simulate a real hardware interface:
- Loopback Permitted: Sockets communicating over
127.0.0.1are accepted cleanly. - TCP Transparent Redirection: An application initiating an outbound TCP socket to an external address (
93.184.216.34:80) is intercepted bynat_outputand redirected to127.0.0.1:9040, where a simulated Tor TransPort listener accepts the connection. - DNS Redirection: An application issuing UDP DNS queries to
8.8.8.8:53is intercepted and redirected to127.0.0.1:5353, where a simulated Tor DNSPort listener receives the payload. - Arbitrary UDP Drop: UDP packets destined for port 123 (NTP) or port 443 (QUIC) are dropped by the firewall filter chain.
- Tor Bootstrap DNS Isolation: Populates
@tor_bootstrap_dns_v4with a DHCP server IP. Verifies that only the Tor process can reach the resolver, while non-Tor entities are dropped. - Private Network Drop: Applications attempting direct TCP connections to RFC 1918 private subnets (
192.168.1.1:80) bypass redirection and are dropped fail-closed. - Direct TCP DNS Drop: Direct TCP port 53 connections are dropped fail-closed.
4.3 Failure Injection Test Layer (test_failure_injection.sh)
- Tor Stopped: With no process listening on port 9040, connection attempts receive
ECONNREFUSEDlocally. Packets never escape to clearnet. - Tor Abrupt Crash (SIGKILL): The simulated Tor listener is killed abruptly. The firewall ruleset remains active in kernel netfilter; subsequent connections fail-closed.
- Invalid Firewall Reload: Injects a syntactically malformed ruleset. The atomic loader rejects the replacement, preserving the active ruleset without interruption.
- Interface Flap: Interface disconnection triggers a flush of the bootstrap DNS allowlist. Stale DNS addresses are eliminated immediately.
5. QEMU ISO Verification
To verify full network behavior on the bootable ISO artifact within QEMU:
make run
Inside the booted live desktop:
- Observe Polybar status: displays
NETWORK BLOCKED — TOR DISCONNECTED. - Launch a terminal: attempt
curl https://check.torproject.org-> fails immediately with connection error. - Attempt direct DNS query:
drill archlinux.org @8.8.8.8-> connection refused/timeout. - Open NetGuard menu via
$mod+Shift+nor Polybar click: select "Connect to Tor". - Observe Polybar: transitions to
TOR CONNECTING->TOR BOOTSTRAPPING->TOR CONNECTED — TRAFFIC ROUTED THROUGH TOR. - Open browser or curl: traffic now resolves and transits Tor exits.