diff options
Diffstat (limited to 'fw/lib')
| -rw-r--r-- | fw/lib/example.ndb | 42 | ||||
| -rw-r--r-- | fw/lib/fw.ndb | 13 | ||||
| -rwxr-xr-x | fw/lib/fw.rc | 27 | ||||
| -rwxr-xr-x | fw/lib/fwstart | 61 | ||||
| -rw-r--r-- | fw/lib/local.ndb | 7 | ||||
| -rw-r--r-- | fw/lib/none.ndb | 3 | ||||
| -rw-r--r-- | fw/lib/web.ndb | 7 |
7 files changed, 160 insertions, 0 deletions
diff --git a/fw/lib/example.ndb b/fw/lib/example.ndb new file mode 100644 index 0000000..60f5119 --- /dev/null +++ b/fw/lib/example.ndb @@ -0,0 +1,42 @@ +# +# every attribute fw understands. an attribute that is absent does +# not constrain, so there is never a "*" to write; it is accepted, but +# leaving the attribute out says the same thing more quietly. +# +# allow=<dir> the rule permits. dir is in, out or * +# deny=<dir> the rule refuses +# proto=<name> a protocol: tcp, udp, icmp, ... +# port=<n> the port at the far end +# lport=<n> the port at this end +# ip=<addr> the address at the far end, optionally with a /mask +# ipmask=<mask> the mask, if you would rather write it separately +# +# in and out are directions, not layers: the same rule means the same +# thing whether fw is matching it against a packet on a wire or against +# a connection a program asked for. connect and announce are accepted +# as older spellings of out and in. +# +# rules are matched top to bottom and the first one that matches wins. +# nothing matching means deny, so a file with no rules permits nothing. +# + +# deny before allow, since the first match wins +deny=out ip=1.1.1.1 +deny=out ip=8.8.8.8 + +# the two spellings of a masked address are the same rule +allow=out ip=10.0.2.0/24 +allow=out ip=192.168.0.0 ipmask=/16 + +# v6 needs no distinguishing: it is the same attribute +allow=out ip=2001:db8::/32 + +# an entry may also be spread over indented continuation lines +allow=out + proto=tcp + port=443 + +# answer on one port, but never call out on it. lport is our end, so +# this is the port we serve; port would be the caller's, which we do not +# get to know until they call. +allow=in proto=tcp lport=17019 diff --git a/fw/lib/fw.ndb b/fw/lib/fw.ndb new file mode 100644 index 0000000..0292f53 --- /dev/null +++ b/fw/lib/fw.ndb @@ -0,0 +1,13 @@ +# +# Which cards are firewalled, and with what. Read by fwstart(8) at +# boot. The address is not named here: fw reads it from the card it +# takes over, so this file and ipconfig(8) cannot drift apart. +# +# One entry per card. Everything the card sends or receives is +# filtered; see fwrules(6) for the rule files themselves. +# + +fw=ether0 rules=/lib/fw/host.ndb + +# a second card, if this machine has one +#fw=ether1 rules=/lib/fw/lan.ndb diff --git a/fw/lib/fw.rc b/fw/lib/fw.rc new file mode 100755 index 0000000..09f2960 --- /dev/null +++ b/fw/lib/fw.rc @@ -0,0 +1,27 @@ +#!/bin/rc +# fw.rc - run a command behind a firewall of its own. +# +# fw.rc rules.ndb cmd [arg ...] +# +# Order matters. The namespace is made private first, the firewall is +# mounted second, and the devices are dropped last: once dropped they +# cannot be regained by this process or any child, so fw has to +# already be serving by then. +# +# The devices dropped are the ones that reach a network without going +# through /net: +# I the IP stack itself - bind -a '#I' /net undoes everything +# l ethernet +# u usb, which can carry an ether device +# σ shr, where nusb publishes usbnet +# Relax that set only if you know the machine has no other way out. +rfork ne +if(~ $#* 0 1){ + echo usage: fw.rc rules.ndb cmd [arg ...] >[1=2] + exit usage +} +rules=$1 +shift +fw $rules || exit 'fw failed' +echo chdev '&~' 'Iluσ' >/dev/drivers || exit 'cannot drop devices' +exec $* diff --git a/fw/lib/fwstart b/fw/lib/fwstart new file mode 100755 index 0000000..00b4d3a --- /dev/null +++ b/fw/lib/fwstart @@ -0,0 +1,61 @@ +#!/bin/rc +# fwstart [cfg] - start a firewall for each card named in /lib/ndb/fw. +# +# Run this after the network is configured and before anything dials. +# fw reads each card's address from the card itself, so the addresses +# have to be there already; and a program that connects before fw is up +# is a program that was never filtered. +rfork e + +cfg=/lib/ndb/fw +if(! ~ $#* 0) + cfg=$1 +if(! test -f $cfg){ + echo fwstart: no $cfg, nothing to do >[1=2] + exit +} + +# the cards named in the config +fn cards { + awk ' + /^[ \t]*#/ { next } + { for(i = 1; i <= NF; i++) if($i ~ /^fw=/) print substr($i, 4) } + ' $cfg +} + +# the rule file for one card +fn rulesfor { + awk -v 'want='^$1 ' + /^[ \t]*#/ { next } + { + dev = ""; rules = "" + for(i = 1; i <= NF; i++){ + if($i ~ /^fw=/) dev = substr($i, 4) + if($i ~ /^rules=/) rules = substr($i, 7) + } + if(dev == want && rules != ""){ print rules; exit } + } + ' $cfg +} + +# each card gets its own control directory; mntgen makes them appear +if(! test -d /mnt/fw) + mntgen /mnt/fw + +for(name in `{cards}){ + dev=/net/$name + rules=`{rulesfor $name} + if(! test -e $dev) + echo fwstart: no $dev, skipped >[1=2] + if not if(~ $#rules 0) + echo fwstart: no rules given for $name, skipped >[1=2] + if not if(! test -f $rules) + echo fwstart: $rules missing, $name skipped >[1=2] + if not { + fw -m /mnt/fw/$name -e $dev $rules + if(~ $status '') + echo fwstart: $name filtered by $rules + if not + echo fwstart: $name failed to start >[1=2] + } +} diff --git a/fw/lib/local.ndb b/fw/lib/local.ndb new file mode 100644 index 0000000..2b846c4 --- /dev/null +++ b/fw/lib/local.ndb @@ -0,0 +1,7 @@ +# +# the local network, and one port to answer on. +# +allow=out ip=10.0.2.0/24 +allow=out ip=192.168.0.0/16 +allow=out ip=fe80::/10 +allow=in proto=tcp lport=17019 diff --git a/fw/lib/none.ndb b/fw/lib/none.ndb new file mode 100644 index 0000000..c12c0aa --- /dev/null +++ b/fw/lib/none.ndb @@ -0,0 +1,3 @@ +# +# no rules. the default is deny, so this program gets no network at all. +# diff --git a/fw/lib/web.ndb b/fw/lib/web.ndb new file mode 100644 index 0000000..709df98 --- /dev/null +++ b/fw/lib/web.ndb @@ -0,0 +1,7 @@ +# +# a browser: name resolution and the web, nothing else. +# +allow=out proto=udp port=53 +allow=out proto=tcp port=53 +allow=out proto=tcp port=80 +allow=out proto=tcp port=443 |
