diff options
Diffstat (limited to 'fw/test/wire.md')
| -rw-r--r-- | fw/test/wire.md | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/fw/test/wire.md b/fw/test/wire.md new file mode 100644 index 0000000..b4494f3 --- /dev/null +++ b/fw/test/wire.md @@ -0,0 +1,105 @@ +# Testing fw on a wire + +`fwtest.rc` runs on one machine and can go no further than the card: it +can take a spare one and watch what fw does to the interfaces, but it +cannot make a neighbour send anything. Everything past that — ARP +against something that will answer, real traffic being filtered, frames +addressed to somebody else — needs a second machine on the same +segment. + +`run.sh` will build one. `-gw` listens, `-lan` connects, and qemu joins +the two into a point-to-point ethernet segment the host is not on. The +LAN card is `ether1` on both. + + ./newvm.sh peer + ./run.sh -headless -gw init-test.qcow2 & + ./run.sh -headless -lan peer.qcow2 & + +The peer can be a plain overlay of the base: it needs no fw, only an +address. Both cards must have distinct ethernet addresses, which +`run.sh` derives from the VM name — before it did that, every guest had +qemu's default and two machines on one segment shared a MAC, which is +invisible point-to-point and makes every check below meaningless. + +## The rig + +On the firewall machine, a stack of its own so the real network is +untouched, and fw on the spare card: + + bind -a '#l1' /net + bind -a '#I63' /tmp/nW + @{ conv=`{cat /fd/0} + echo -n 'bind ether /net/ether1' >[1=0] + echo -n 'add 10.9.9.1 255.255.255.0' >[1=0] } <>[0] /tmp/nW/ipifc/clone + echo 'allow=in proto=icmp' > /tmp/r.ndb + fw -s fw.wire -n /tmp/nW -e /net/ether1 -m /tmp/ctl /tmp/r.ndb \ + </dev/null >/dev/null >[2]/dev/null + +`-s` matters: fw's control files are otherwise only reachable through +the mount in the namespace that started it, and that namespace is gone +by the time you want to look. With a `/srv` name any shell can +`mount /srv/fw.wire /tmp/wctl`. + +Redirect all three descriptors. fw daemonizes, so anything that leaves +it holding a pipe — `fw ... | grep`, or a command substitution around +it — waits for a firewall that is not going to exit. + +On the peer, the other end of the segment: + + bind -a '#l1' /net + bind -a '#I64' /tmp/np + @{ conv=`{cat /fd/0} + echo -n 'bind ether /net/ether1' >[1=0] + echo -n 'add 10.9.9.2 255.255.255.0' >[1=0] } <>[0] /tmp/np/ipifc/clone + rfork n; bind /tmp/np /net + +## What it shows + +**ARP for an address whose card has been taken.** Nothing else is +answering for 10.9.9.1 — the stack that owns it has a `pkt` interface +and no ethernet — so if `ip/ping 10.9.9.1` works at all, fw answered. +The peer's `/net/arp` says whose: + + ether OK 10.9.9.1 52540087c8c1 10.9.9.2 + +which is the firewall's *card*, not the peer's own. The first ping +takes about a second and the rest are sub-millisecond: fw has to ARP +for the peer before it can send the reply, and drops the first one +while it asks. That is the one drop no rule caused, in fw(8) BUGS. + +**Filtering, as against forwarding.** With `allow=in proto=icmp` alone, +a TCP connect from the peer sits for 290 seconds and gives up: + + connection timed out + +Add the rule through the running firewall and the same connect answers +in 2 seconds: + + echo -n 'prepend allow=in proto=tcp lport=17019' > /tmp/wctl/ctl + connection refused + +"Refused" is the far stack's RST, so the packet arrived; "timed out" is +fw dropping it silently. That difference is the whole point of the +program, and it is the only way to see it from outside. + +**Frames addressed to somebody else.** A stack only ever addresses a +frame to the MAC it resolved, so this one has to be forged: +`rawether.c`, in this directory, writes a single frame with whatever +destination you name. + + rawether /net/ether1 52540087c8c1 10.9.9.2 10.9.9.1 # fw's card + rawether /net/ether1 525400aabbcc 10.9.9.2 10.9.9.1 # nobody's + +Watch `passed` in `/tmp/wctl/stats` across each. The card is +promiscuous and has to be, so both frames arrive — a promiscuous reader +on the firewall machine sees both, which is worth confirming first, or +a frame that never arrived looks exactly like one that was filtered: + + 52 54 00 aa bb cc 52 54 00 37 df 23 08 00 45 00 + +With the destination check in `etherin`, the second frame moves nothing. +Without it, both move the counter by the same amount: + + to fw's card to nobody's + no check +3 +3 + with the check +2 0 |
