# fw: open items Ranked. Item 1 is the only thing between this and running it on a machine you care about. ## 1. A dead fw takes the network with it **Severity: blocks use.** Taking a card is destructive and is not undone. The `pkt` interface that replaces it is `unbindonclose`, so when `fw` stops the interface goes and the address goes with it. The machine is left with a card bound to nothing and no network. Worse, `fw` cannot restart unaided: the address it would read off the card is the address that just vanished. So it exits, and a supervisor with `restart=always` would spin. `fw` tries to put the card back as it exits (`putback`, via `atexit` and `threadnotify`). That covers an orderly stop. **It did not fire on a kill in testing** and I did not chase it further — a cleanup that works sometimes is worse than none, because you would trust it. The fix is probably not more note handling. Whatever restarts `fw` has to be able to configure the card first, which means the address has to survive somewhere `fw` does not own. That is a supervisor's job. This is also what blocks `svc` supervision (item 3), so one fix, two payoffs. ## 2. Broadcast handling is written but unwitnessed Broadcast and multicast are addressed directly rather than resolved: `255.255.255.255` and the subnet broadcast to `ff:ff:ff:ff:ff:ff`, `224/4` to `01:00:5e:...`, `ff00::/8` to `33:33:...`. Without this a DHCP renewal would be ARPed for the gateway and unicast there, and the lease would quietly never renew. The mapping is the standard one and normal traffic is unaffected, but **I never managed to get a broadcast to cross `fw` to confirm it.** Reviewed, not observed. Related and unfixed: `fw` reads the address once at startup, so a lease that *changes* the address goes unnoticed until restart. ## 3. fw daemonizes, so svc cannot supervise it The process you exec returns immediately and leaves the server behind. `svc` would see an instant exit and, with `restart=always`, spin. Needs a foreground mode where the process started is the process that stays. `svc`'s `ready=srv:name` fits: `fw -s fw.ether0` already posts to `/srv`. `fwstart` is the wrong shape and should probably go. `svc` already does dependency ordering and per-service supervision; `fwstart` re-implements the loop in rc and then exits, so `svc` would be supervising a process that has already gone. One service per card is the right shape. ## 4. One card per fw, and rules cannot name a card Two cards means two `fw`s with two rule files. Tested and it works, but a rule cannot say `ifc=ether0`, so one file cannot express different policy for different cards. Wants repeatable `-e` and an `ifc=` attribute, and those go together. ## 5. Tflush is not implemented A request `fw` is blocked on cannot be abandoned, so killing a program that is waiting for an inbound connection does not reach `fw`. Only affects the namespace mode; nothing in packet mode blocks indefinitely. Doable: record the worker's pid against the Req, post an `interrupt` note on flush, catch it with `threadnotify` so the syscall returns `interrupted` rather than killing the proc. Maybe 80 lines. There is a race that cannot be fully closed — between the syscall returning and the handler clearing its entry, a note may already be in flight and land on a worker that has moved on, failing an unrelated request. Rare, unreproducible, and the reason to do it deliberately. ## 6. Positional delete renumbers `delete n` counts lines of `rules`, so numbers shift after each delete and `delete 3` twice removes two different rules. Inherent to positional deletion — iptables has it too — but it should be said out loud. ## 7. Untested at the edges - The gateway has only been tested between two synthetic stacks on one machine. `run.sh` has `-gw`/`-lan` for a two-VM test; the client VM was never built. - No IPv6 traffic has been pushed through any mode. The code paths exist and parse v6, but nothing has exercised them. - No test with a real second NIC carrying real traffic. ## Deliberately not doing **NAT.** See design.md. A 9front client imports `/net`; anything else behind an IPv4 gateway with one address is the only case that needs it, and that case can wait for someone who actually has it. **Rate limiting, fragment logic, ICMP type matching, deep IPv6.** Scope, not difficulty. The useful firewall is the one that ships.