Files
RedBear-OS/local/docs/FIREWALL-VALIDATION-LOG.md
T

423 lines
14 KiB
Markdown

# 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/<chain>` | 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-<date>/router-eth0.pcap` — Internal subnet traffic
- `artifacts/firewall-<date>/router-eth1.pcap` — External subnet traffic
- `artifacts/firewall-<date>/vm-a-net0.pcap` — Internal peer traffic
- `artifacts/firewall-<date>/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.