# Firewall Validation Log — Red Bear OS Phase 4 **Created:** 2026-07-26 **Author:** Red Bear OS networking systematic fix plan, Phase 4 **Component:** `redbear-firewall-check` + `test-firewall-scenarios.sh` **Requires:** `redbear-mini` ISO, `netfilter` scheme (base netstack), UID 0 (root) ## Overview This document records the design, expected behavior, and validation procedure for each of the six firewall validation scenarios. The scenarios exercise the `netfilter:` scheme control plane in Red Bear OS — the packet-filter and NAT subsystem in the `base` netstack daemon. The validation harness has three parts: | Part | Location | Purpose | |------|----------|---------| | `redbear-firewall-check` | `local/recipes/system/redbear-hwutils/source/src/bin/redbear-firewall-check.rs` | In-guest binary that runs all 6 scenarios against `/scheme/netfilter` | | `test-firewall-scenarios.sh` | `local/scripts/test-firewall-scenarios.sh` | Host-side QEMU launcher for 3-VM topology | | `FIREWALL-VALIDATION-LOG.md` | `local/docs/FIREWALL-VALIDATION-LOG.md` | This document | ## Netfilter Scheme Interface The netfilter scheme (`/scheme/netfilter/`) exposes a filesystem-style API authenticated by UID 0 (root). Operations: | Path | Mode | Description | |------|------|-------------| | `rule/list` | Read | Text dump of all filter rules (mirrors `iptables -L -n -v`) | | `rule/add` | Write | Append one rule (mirrors `iptables -A`) | | `rule/del` | Write | Remove one rule by numeric id | | `nat/list` | Read | Text dump of all NAT rules | | `nat/add` | Write | Append one NAT rule | | `nat/del` | Write | Remove one NAT rule by numeric id | | `policy/` | Read/Write | Default policy for INPUT, OUTPUT, FORWARD, PREROUTING, POSTROUTING | | `reset` | Write | Clear all rules, restore default ACCEPT policies, reset conntrack | | `stats` | Read | Per-chain packet/byte counters, rule counts, NAT counts, conntrack summary | | `conntrack/list` | Read | Per-connection entry dump with 5-tuple + packet/byte counters | | `conntrack/stats` | Read | Per-protocol/state breakdown (TCP SYN/EST/FIN/TW/Close, UDP, ICMP) + `over_limit` + `max_entries` | | `counters/reset` | Write | Zero per-chain and per-rule counters (preserves rules) | | `log` | Read | Last 20 LOG verdict entries | ### Rule Grammar ``` ACTION CHAIN [-i IFACE] [-o IFACE] [-p PROTO] [-s ADDR[/LEN]] [-d ADDR[/LEN]] [--sport PORT] [--dport PORT] [state STATE|--ctstate STATE[,STATE...]] ``` **Actions:** ACCEPT, DROP, LOG, REJECT **Chains:** input, output, forward, prerouting, postrouting **Protocols:** tcp, udp, icmp, icmp6, or number **States:** new, established, related, invalid (comma-separated for --ctstate) Examples: - `ACCEPT input --ctstate ESTABLISHED,RELATED` - `DROP input -s 10.0.0.0/8` - `ACCEPT input -p tcp --dport 22` - `ACCEPT output -d 192.168.1.0/24 --sport 1024` ### NAT Rule Grammar ``` SNAT|DNAT hook to ADDR [port N] [match-src ADDR] [match-dst ADDR] ``` Examples: - `SNAT postrouting to 10.0.2.15` — masquerade outgoing traffic - `DNAT prerouting to 10.0.0.2 port 8080` — port forward 80→8080 - `SNAT postrouting to 10.0.2.15 match-src 10.0.0.1` — source-specific SNAT --- ## Scenario A: AcceptEstablished ### Purpose Verify that the default-deny INPUT + ACCEPT ESTABLISHED/RELATED pattern works. This is the most common iptables pattern: drop all incoming new connections, but allow responses to locally-initiated outbound traffic. ### Prereq netcfg state - Firewall reset to defaults (all policies ACCEPT, no rules). - No network interfaces need to be configured at this level — the test validates the rule parser and scheme, not actual packet flow. ### Exact ufw/netfilter commands ```bash # Via scheme writes (equivalent to these netfilter scheme operations): echo "DROP" > /scheme/netfilter/policy/input echo "ACCEPT input --ctstate ESTABLISHED,RELATED" > /scheme/netfilter/rule/add echo "1" > /scheme/netfilter/reset ``` ### What the test does 1. Resets firewall. 2. Sets INPUT policy to DROP. 3. Verifies INPUT policy reads back as "DROP". 4. Verifies OUTPUT policy remains "ACCEPT" (default). 5. Adds `ACCEPT input --ctstate ESTABLISHED,RELATED` rule. 6. Verifies the rule appears in `rule/list` with a valid numeric id. 7. Verifies `stats` endpoint returns chain counters for both input and output. 8. Resets firewall. ### Expected output ``` Scenario A (AcceptEstablished) ... pass SCENARIO_A=pass ``` ### Cleanup - Firewall reset to defaults (all policies ACCEPT, empty rules). --- ## Scenario B: SSHAllow ### Purpose Verify port-specific ACCEPT rules coexist correctly with the established-connections rule. This simulates opening a single service port (SSH on 22) while keeping the rest of INPUT denied. ### Prereq netcfg state - Firewall reset to defaults. ### Exact ufw/netfilter commands ```bash echo "DROP" > /scheme/netfilter/policy/input echo "ACCEPT input -p tcp --dport 22" > /scheme/netfilter/rule/add echo "ACCEPT input --ctstate ESTABLISHED,RELATED" > /scheme/netfilter/rule/add echo "1" > /scheme/netfilter/reset ``` ### What the test does 1. Resets firewall. 2. Sets INPUT policy to DROP. 3. Adds ACCEPT rule for tcp/22. 4. Adds ACCEPT rule for ESTABLISHED,RELATED. 5. Verifies both rules appear in `rule/list`. 6. Verifies the SSH rule contains `dport=22` but NOT `dport=80` (no rule leakage). 7. Resets firewall. ### Expected output ``` Scenario B (SSHAllow) ... pass SCENARIO_B=pass ``` ### Cleanup - Firewall reset to defaults. --- ## Scenario C: SNATMASQ ### Purpose Verify Source NAT (masquerade) rule configuration. This simulates a router with an internal subnet 10.0.0.0/24 whose outbound traffic is rewritten to use the router's external IP. ### Prereq netcfg state - Firewall reset to defaults. - No actual routing needed — the test validates the NAT table control plane. ### Exact ufw/netfilter commands ```bash echo "SNAT postrouting to 10.0.2.15 match-src 10.0.0.1" > /scheme/netfilter/nat/add echo "1" > /scheme/netfilter/reset ``` ### What the test does 1. Resets firewall. 2. Adds SNAT rule: `SNAT postrouting to 10.0.2.15 match-src 10.0.0.1`. 3. Reads `nat/list` and verifies the rule appears with `Snat` type and `10.0.2.15` target. 4. Verifies `nat/list` header (`Nat table:`) is present. 5. Reads `stats` and verifies it includes `snat=` and `dnat=` counters. 6. Resets firewall. ### Expected output ``` Scenario C (SNATMASQ) ... pass SCENARIO_C=pass ``` ### Cleanup - Firewall reset to defaults. --- ## Scenario D: DNATPortFwd ### Purpose Verify Destination NAT (port forwarding) rule configuration. This simulates redirecting incoming traffic on the router's public IP port 80 to an internal server at 10.0.0.2:8080. ### Prereq netcfg state - Firewall reset to defaults. ### Exact ufw/netfilter commands ```bash echo "DNAT prerouting to 10.0.0.2 port 8080" > /scheme/netfilter/nat/add echo "SNAT postrouting to 10.0.2.15" > /scheme/netfilter/nat/add echo "1" > /scheme/netfilter/reset ``` ### What the test does 1. Resets firewall. 2. Adds DNAT rule: `DNAT prerouting to 10.0.0.2 port 8080`. 3. Verifies the rule appears in `nat/list` with `Dnat`, `10.0.0.2`, and `8080`. 4. Verifies port info (`8080`) is present in the formatted output. 5. Adds a second NAT rule (SNAT) to verify coexistence. 6. Verifies both SNAT and DNAT rules appear in the combined NAT table. 7. Resets firewall. ### Expected output ``` Scenario D (DNATPortFwd) ... pass SCENARIO_D=pass ``` ### Cleanup - Firewall reset to defaults. --- ## Scenario E: ConntrackLifecycle ### Purpose Verify that the connection tracking (conntrack) module is initialized and reporting statistics. The conntrack table tracks TCP state transitions (SYN_SENT → SYN_RECV → ESTABLISHED → FIN_WAIT → TIME_WAIT), UDP streams, and ICMP echo exchanges. ### Prereq netcfg state - Firewall reset to defaults. - Conntrack module auto-initialized (FilterTable::new creates ConntrackTable). ### Exact ufw/netfilter commands ```bash cat /scheme/netfilter/conntrack/stats cat /scheme/netfilter/conntrack/list ``` ### What the test does 1. Resets firewall. 2. Reads `conntrack/stats` and verifies all required fields: - `tcp_entries:` (with state breakdown in parentheses) - `udp_entries:` - `icmp_entries:` - `over_limit:` (parsed as u64) - `total_entries:` (parsed as u64) - `max_entries:` (must be > 0) 3. Reads `conntrack/list` and verifies the header (`conntrack entries:`) is present. 4. Verifies the `total_entries` value is a valid u64 number. 5. Resets firewall. ### Expected output ``` Scenario E (ConntrackLifecycle) ... pass SCENARIO_E=pass ``` ### Cleanup - Firewall reset to defaults (also resets conntrack table). --- ## Scenario F: SYNFlood ### Purpose Verify that the SYN rate-limiting infrastructure is wired into the conntrack module. The conntrack table has a per-source-IP SYN counter (limit: 100 SYN/sec, window: 1 second) that increments the `over_limit` counter when a source exceeds the threshold. ### Prereq netcfg state - Firewall reset to defaults. ### Exact ufw/netfilter commands ```bash cat /scheme/netfilter/conntrack/stats cat /scheme/netfilter/stats ``` ### What the test does 1. Resets firewall. 2. Reads `conntrack/stats` and verifies `over_limit` field exists and parses as u64. 3. Logs the initial `over_limit` value (expected 0; non-zero accepted as traffic residue). 4. Reads `max_entries` and verifies it is > 0 (table is enabled, not size-0). 5. Verifies `icmp_errors` field exists (independent rate limit structure from SYN limit). 6. Reads `stats` and verifies `rules:` field exists. 7. Resets firewall. ### Expected output ``` Scenario F (SYNFlood) ... pass SCENARIO_F=pass ``` ### Cleanup - Firewall reset to defaults. --- ## 3-VM QEMU Topology The `test-firewall-scenarios.sh` script creates three VMs connected by AF_UNIX socket pairs, simulating a routed network: ``` ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ VM-A │ │ Router-VM │ │ VM-B │ │ (internal) │◄───►│ 2 NICs │◄───►│ (external) │ │ 10.0.0.2/24 │ │ eth0: 10.0.0.1 │ │ 10.0.2.200/24│ └─────────────┘ │ eth1: 10.0.2.100│ └─────────────┘ └─────────────┘ ``` ### Network configuration | VM | NIC | MAC | Subnet | Role | |----|-----|-----|--------|------| | Router-VM | eth0 | 52:54:00:12:34:01 | 10.0.0.0/24 | Internal gateway | | Router-VM | eth1 | 52:54:00:12:34:02 | 10.0.2.0/24 | External NAT interface | | VM-A | eth0 | 52:54:00:12:34:0A | 10.0.0.0/24 | Internal client | | VM-B | eth0 | 52:54:00:12:34:0B | 10.0.2.0/24 | External peer | ### Packet capture Each NIC has a QEMU `filter-dump` object that writes a pcap file: - `artifacts/firewall-/router-eth0.pcap` — Internal subnet traffic - `artifacts/firewall-/router-eth1.pcap` — External subnet traffic - `artifacts/firewall-/vm-a-net0.pcap` — Internal peer traffic - `artifacts/firewall-/vm-b-net0.pcap` — External peer traffic ### Automated check mode ```bash # Build the ISO first: ./local/scripts/build-redbear.sh redbear-mini # Run the automated firewall check: ./local/scripts/test-firewall-scenarios.sh --check redbear-mini ``` This boots the Router-VM, logs in via expect, runs `redbear-firewall-check`, captures all 6 scenario results, and exits with code 0 only if all pass. ### Interactive mode ```bash ./local/scripts/test-firewall-scenarios.sh redbear-mini ``` All three VMs boot and wait. Log into Router-VM manually and run `redbear-firewall-check`. Press Ctrl+C to stop all VMs. --- ## Recipe Integration The `redbear-firewall-check` binary is part of the `redbear-hwutils` crate. It is built alongside other validation binaries (lspci, redbear-phase5-*, etc.) via the `[[bin]]` entry in `Cargo.toml` and mapped to a `/usr/bin` path in `recipe.toml` under `[package.files]`. ### Files modified | File | Change | |------|--------| | `local/recipes/system/redbear-hwutils/source/Cargo.toml` | Added `[[bin]]` entry | | `local/recipes/system/redbear-hwutils/recipe.toml` | Added `/usr/bin/redbear-firewall-check` line | | `local/recipes/system/redbear-hwutils/source/src/bin/redbear-firewall-check.rs` | New file — 6 scenarios | | `local/scripts/test-firewall-scenarios.sh` | New file — 3-VM QEMU launcher | | `local/docs/FIREWALL-VALIDATION-LOG.md` | New file — this document | --- ## Limitations 1. **Control-plane validation only.** The `redbear-firewall-check` binary validates the netfilter scheme control plane (rule add/del, NAT add/del, policy read/write, stats read, conntrack stats read). It does NOT generate actual network traffic through the netstack's filter evaluation path. End-to-end traffic validation requires the 3-VM QEMU topology with real packet flow and pcap capture. 2. **SYN flood detection.** The test verifies the `over_limit` counter and rate-limit infrastructure exist. Actual SYN flood trigger requires >100 SYN packets in <1 second from a single source through the netstack — this is validated by the pcap captures in the 3-VM topology, not by the in-guest binary alone. 3. **NAT packet rewriting.** The test verifies NAT rules are parsed and stored. Actual IP/port rewriting by `rewrite_src_ipv4` / `rewrite_dst_ipv4` / `rewrite_port_ipv4` requires real packets routed through the netstack, which is validated by the 3-VM QEMU topology. 4. **No per-scenario network traffic generation.** Each scenario resets the firewall, configures rules, and reads back the state. Generating and capturing meaningful test traffic across the 3-VM topology is a separate phase (manual or scripted from inside each guest VM). --- ## Future Work - **Phase 4.1:** Add packet generation from inside each guest VM (e.g., `nc` / `socat` / `curl` with the Red Bear netstack socket API) to generate actual test traffic through the filter. - **Phase 4.2:** Add per-scenario pcap verification — the `filter-dump` captures can be analyzed by host-side scripts to verify that packets were/were not transmitted according to filter rules. - **Phase 4.3:** Add `redbear-firewall-check --traffic` mode that spawns real TCP/UDP/ICMP traffic inside the guest and measures conntrack state transitions and rule match counts. - **Phase 4.4:** Integrate with the existing network test framework (`test-phase5-network-qemu.sh`) for combined network+firewall validation.