From: Mark Wooding Date: Tue, 6 Mar 2012 00:01:11 +0000 (+0000) Subject: Merge branch 'master' into emergency X-Git-Url: https://git.distorted.org.uk/~mdw/firewall/commitdiff_plain/f513127acd3ccf2f6ec695ba5d9396739bd21aba?hp=2861f481552b0cd6c118e7169397e134fde03b15 Merge branch 'master' into emergency * master: functions.m4: Write the netclass ids to the trace output. bookends.m4: If debugging, dump the final tables. Determine forwarding and reverse-path filtering from host definitions. Overhaul address classification. local.m4: Promote the NTP server configuration to a proper variable. Renumber the diversions. fixup! WIP on emergency: 7a108d1 Makefile: New target for tracking diversions. Makefile: New target for tracking diversions. Makefile, base.m4: Inject the target hostname into the generated script. Semantic conflict: The variable `if_dmz' is no longer set, so just hardwire the interface name. --- diff --git a/.gitignore b/.gitignore index 7ba5f27..8bca642 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.sh cruft +divs diff --git a/Makefile b/Makefile index 8f918e5..b0f4612 100644 --- a/Makefile +++ b/Makefile @@ -102,7 +102,8 @@ TARGETS = $(addsuffix .sh,$(HOSTS)) TARGETS += dummy.sh dummy.sh: base.m4 prologue.m4 dummy-payload.m4 - $(V_M4) $^ >$@.new && chmod +x $@.new && mv $@.new $@ + $(V_M4)-DFWHOST=testing $^ >$@.new + $(V_AT)chmod +x $@.new && mv $@.new $@ TARGETS += dummy-inst.sh dummy-inst.sh: dummy.sh @@ -110,16 +111,26 @@ dummy-inst.sh: dummy.sh $(V_AT)chmod +x $@.new && mv $@.new $@ ###-------------------------------------------------------------------------- +### Other utilities. + +## A list of diversions in ascending numerical order. +CLEANFILES += divs +divs: $(M4_SOURCES) $(addsuffix .m4,$(HOSTS)) + $(V_GEN)grep -n m4_divert $^ | \ + grep -v 'm4_divert(-1)' | \ + sort -t\( -k2n >$@ + +###-------------------------------------------------------------------------- ### Building. all: $(TARGETS) .PHONY: all %.sh: %.m4 $(M4_SOURCES) - $(V_M4)base.m4 $*.m4 $(MAIN_M4_SOURCES) >$@.new + $(V_M4)-DFWHOST=$* base.m4 $*.m4 $(MAIN_M4_SOURCES) >$@.new $(V_AT)chmod +x $@.new && mv $@.new $@ -clean:; rm -f $(TARGETS) *.new +clean:; rm -f $(TARGETS) *.new $(CLEANFILES) .PHONY: clean ###-------------------------------------------------------------------------- diff --git a/artist.m4 b/artist.m4 index 1f97e73..a04cc9c 100644 --- a/artist.m4 +++ b/artist.m4 @@ -22,34 +22,9 @@ ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ###-------------------------------------------------------------------------- -### Config settings. - -## This host isn't a router. -setconf(forward, 0) - -## This host is involved in a routing asymmetry. -setconf(rp_filter, 0) -setconf(log_martians, 0) - -###-------------------------------------------------------------------------- -### Network interfaces. - -m4_divert(44)m4_dnl -## Interface definitions. -if_dmz=eth0 -if_trusted=eth1 -if_safe=$if_dmz,$if_trusted -if_untrusted=$if_dmz,$if_trusted -if_vpn=$if_dmz,$if_trusted -if_iodine=$if_dmz,$if_trusted -if_its_mz=$if_dmz,$if_trusted -if_its_pi=$if_dmz,$if_trusted - -m4_divert(-1) -###-------------------------------------------------------------------------- ### artist-specific rules. -m4_divert(82)m4_dnl +m4_divert(84)m4_dnl ## Externally visible services. allowservices inbound tcp \ ssh \ diff --git a/base.m4 b/base.m4 index 5170531..8968025 100644 --- a/base.m4 +++ b/base.m4 @@ -29,24 +29,29 @@ m4_changecom(<:##:>) ### Overall structure. ### ### 0 File header: shebang, do-not-edit warning. [base] -### 5 Configuration. [config] +### 4 Configuration. [config] +### 6 Local settings. [local] ### 10 Prologue: command-line parsing and failsafe. [prologue] ### 20 Function definitions. [functions] -### 25 Port numbers etc. [numbers] +### 24 Port numbers etc. [numbers] +### 26 Networks, hosts and interfaces. [local] ### 30 Initialization. [bookends] ### 30 Clear existing rules. [bookends] ### 32 Set safe IP options. [bookends] ### 34 Error chains. [bookends] -### 36 Give loopback traffic a free pass. [bookends] ### 38 Utility chains. [functions] ### 40 Address classification. [classify] ### 42 Definition of address class policies. [local] ### 44 Definition of interfaces and addresses. [local] ### 46 Handling of default interface. [classify] -### 50 ICMP filtering. [icmp] -### 52 Local configuration. [local] -### 58 Finally accept ICMP, hook onto INPUT and FORWARD. [icmp] -### 60 Local configuration. [local] +### 50 Packet filter. [bookends] +### 60 ICMP filtering. [icmp] +### 62 Local configuration. [local] +### 68 Finally accept ICMP, hook onto INPUT and FORWARD. [icmp] +### 80 Local configuration. [local] +### 84 Locally bound packet inspection. [local] +### 86 Per-host configuration. [HOST] +### 88 Final filtering. [local] ### 90 Finishing touches. [bookends] ### 94 Set final policies. [bookends] ### 99 File footer: do-not-edit warning. [base] @@ -56,6 +61,10 @@ m4_changecom(<:##:>) m4_divert(0)m4_dnl #! /bin/sh +<:###:> Firewall script for FWHOST +### +### *** GENERATED FILE: DO NOT EDIT *** + ### BEGIN INIT INFO # Provides: firewall # Required-Start: mountkernfs @@ -66,10 +75,10 @@ m4_divert(0)m4_dnl # Default-Stop: 0 6 # Description: Provides customized packet filter rules. ### END INIT INFO -### *** GENERATED FILE: DO NOT EDIT *** set -e PATH=/bin:/sbin:/usr/bin:/usr/sbin; export PATH +fwhost=FWHOST m4_divert(99)m4_dnl ### *** GENERATED FILE: DO NOT EDIT *** diff --git a/bookends.m4 b/bookends.m4 index b29047b..69a721e 100644 --- a/bookends.m4 +++ b/bookends.m4 @@ -105,6 +105,10 @@ m4_divert(32)m4_dnl ## Set forwarding options. Apparently setting ip_forward clobbers other ## settings, so put this first. +case $host_type_<::>FWHOST in + router) forward=1 ;; + *) forward=0 ;; +esac setopt ip_forward $forward setdevopt forwarding $forward @@ -129,9 +133,11 @@ if [ -x /sbin/brctl ]; then fi fi -## Turn on the reverse-path filter, and log weird things. -setdevopt rp_filter $rp_filter -setdevopt log_martians $log_martians +## Turn off the reverse-path filter. It's basically useless: the filter does +## nothing at all for single-homed hosts; and multi-homed hosts tend to have +## routing aysmmetries if there's any kind of cycle. +setdevopt rp_filter 0 +setdevopt log_martians 0 ## Turn off things which can mess with our routing decisions. setdevopt accept_source_route 0 @@ -164,7 +170,7 @@ errorchain bad-destination-address REJECT errorchain interesting ACCEPT ## Not an error, just log interesting packets. -m4_divert(36)m4_dnl +m4_divert(50)m4_dnl ###-------------------------------------------------------------------------- ### Standard filtering. @@ -179,26 +185,34 @@ run ip6tables -A INPUT -g bad-destination-address \ -d ::1 ## We shouldn't be asked to forward things with link-local addresses. -run iptables -A FORWARD -g bad-source-address \ - -s 169.254.0.0/16 -run iptables -A FORWARD -g bad-destination-address \ - -d 169.254.0.0/16 -run ip6tables -A FORWARD -g bad-source-address \ - -s fe80::/10 -run ip6tables -A FORWARD -g bad-destination-address \ - -d fe80::/10 +case $forward in + 1) + run iptables -A FORWARD -g bad-source-address \ + -s 169.254.0.0/16 + run iptables -A FORWARD -g bad-destination-address \ + -d 169.254.0.0/16 + run ip6tables -A FORWARD -g bad-source-address \ + -s fe80::/10 + run ip6tables -A FORWARD -g bad-destination-address \ + -d fe80::/10 + ;; +esac ## Also, don't forward link-local broadcast or multicast. -run iptables -A FORWARD -g bad-destination-address \ - -d 255.255.255.255 -run iptables -A FORWARD -g bad-destination-address \ - -m addrtype --dst-type BROADCAST -run iptables -A FORWARD -g bad-destination-address \ - -d 224.0.0.0/24 -for x in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do - run ip6tables -A FORWARD -g bad-destination-address \ - -d fe${x}2::/16 -done +case $forward in + 1) + run iptables -A FORWARD -g bad-destination-address \ + -d 255.255.255.255 + run iptables -A FORWARD -g bad-destination-address \ + -m addrtype --dst-type BROADCAST + run iptables -A FORWARD -g bad-destination-address \ + -d 224.0.0.0/24 + for x in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do + run ip6tables -A FORWARD -g bad-destination-address \ + -d fe${x}2::/16 + done + ;; +esac ## Add a hook for fail2ban. clearchain fail2ban @@ -229,5 +243,17 @@ for ip in ip ip6; do done done +## Dump the resulting configuration. +if [ "$FW_DEBUG" ]; then + for ip in ip ip6; do + for table in mangle filter; do + echo "----- $ip $table -----" + echo + ${ip}tables -t $table -nvL + echo + done + done +fi + m4_divert(-1) ###----- That's all, folks -------------------------------------------------- diff --git a/classify.m4 b/classify.m4 index 6ad069c..8b6a650 100644 --- a/classify.m4 +++ b/classify.m4 @@ -115,34 +115,129 @@ m4_divert(42)m4_dnl done m4_divert(46)m4_dnl -## Mark addresses reachable on non-default interfaces as not reachable on the -## default interface. -trace "nets = $allnets $allnets6" +## Build the input classification chains. There's one chain `in-IFACE' for +## each local interface. This chain does a further dispatch on the source +## address to the appropriate `mark-from-CLASS' chain for the source network +## class. +seen=: +for iface in $host_ifaces_<::>FWHOST; do + ifname=${iface%=*} + case $seen in *:$ifname:*) continue ;; esac + seen=$seen$ifname: + clearchain mangle:in-$ifname + run ip46tables -t mangle -A in-classify -i $ifname -g in-$ifname +done + +## Now populate the `in-IFACE' and `out-classify' chains. We iterate over +## the available networks and add addresses to the appropriate chains. Also, +## build up a map of which interfaces receive from which address ranged so +## that we can finish the chains off properly later. This contains entries +## of the form IFACE=:ADDR:ADDR:...: +ifnets="" for net in $allnets; do - defaultp=nil - for iface in $defaultifaces; do - case $net in $iface:*) defaultp=t ;; esac + + ## Determine the addresses and class for this network, and populate the + ## `out-classify' chains. + eval addr=\$net_inet_$net addr6=\$net_inet6_$net class=\$net_class_$net + case $class in virtual) continue ;; esac + trace "$net : $class" + for a in $addr; do + run iptables -t mangle -A out-classify -g mark-to-$class -d $a done - case $defaultp in - nil) - for iface in $defaultifaces; do - run iptables -t mangle -A in-$iface \ - -s ${net#*:} -g bad-source-address - done - ;; - esac -done -for net in $allnets6; do - defaultp=nil - for iface in $defaultifaces; do - case $net in $iface:*) defaultp=t ;; esac + for a in $addr6; do + run ip6tables -t mangle -A out-classify -g mark-to-$class -d $a done - case $defaultp in - nil) - for iface in $defaultifaces; do - run ip6tables -t mangle -A in-$iface \ - -s ${net#*:} -g bad-source-address + + ## Now work through the interfaces. + for iface in $(net_interfaces FWHOST $net); do + nets="" + case $iface in + + -) + ## A special `no interface' marker: we should not receive packets + ## from this network at all. + continue + ;; + + *-+) + ## A special marker indicating a collection of point-to-point + ## interfaces. We should match an address to a particular interface. + ## Later, we'll cap this chain off by rejecting all other traffic. + eval hosts=\$net_hosts_$net + for host in $hosts; do + eval ha=\$host_inet_$host ha6=\$host_inet6_$host + trace "$host : $class -> $iface" + for a in $ha; do + run iptables -t mangle -A in-$iface \ + -i ${iface%+}$host -s $a -g mark-from-$class + nets=$nets$a: + done + for a in $ha6; do + run ip6tables -t mangle -A in-$iface \ + -i ${iface%+}$host -s $a -g mark-from-$class + nets=$nets$a: + done + done + ;; + + *) + ## A normal interface. Classify incoming traffic according to the + ## source address. + trace "$net : $class -> $iface" + for a in $addr; do + run iptables -t mangle -A in-$iface -g mark-from-$class -s $a + nets=$nets$a: + done + for a in $addr6; do + run ip6tables -t mangle -A in-$iface -g mark-from-$class -s $a + nets=$nets$a: + done + case $net in default) nets=${nets}default: ;; esac + ;; + esac + + ## Record that this interface receives traffic from this network. + unset nifnets + foundp=nil + for ifnet in $ifnets; do + case $ifnet in + $iface=*:$net:*) addword nifnets $ifnet; foundp=t ;; + $iface=*) addword nifnets $ifnet$nets; foundp=t ;; + *) addword nifnets $ifnet ;; + esac + done + case $foundp in nil) addword nifnets $iface=:$nets ;; esac + ifnets=$nifnets + + done +done + +## Wrap up all of the `in-IFACE' chains. A chain which matches the `default' +## net should have unmatched but known networks blocked off, and then chain +## onto `in-default'. Other chains should just chain onto +## `bad-source-address'. +trace "ifnets = $ifnets" +for ifnet in $ifnets; do + iface=${ifnet%%=*} nets=${ifnet#*=} + case $nets in + *:default:*) + for n in $allnets; do + eval addr=\$net_inet_$n addr6=\$net_inet6_$n + for a in $addr; do + case $nets in *:$a:*) continue ;; esac + nets=$nets$a + run iptables -t mangle -A in-$iface -s $a -g bad-source-address + done + for a in $addr6; do + case $nets in *:$a:*) continue ;; esac + nets=$nets$a + run ip6tables -t mangle -A in-$iface -s $a -g bad-source-address + done done + run ip46tables -t mangle -A in-$iface -g in-default + ;; + *) + run ip46tables -t mangle -A in-$iface -g bad-source-address ;; esac done @@ -160,14 +255,15 @@ for addr in \ do run ip6tables -t mangle -A in-default -s $addr -g bad-source-address done +run ip46tables -t mangle -A in-default -g mark-from-$net_class_default m4_divert(92)m4_dnl ## Put the final default decision on the in-default chain, and attach the ## classification chains to the PREROUTING hook. for iface in $defaultifaces; do - run ip46tables -t mangle -A in-$iface -g mark-from-$defaultclass + run ip46tables -t mangle -A in-$iface -g in-default done -run ip46tables -t mangle -A out-classify -g mark-to-$defaultclass +run ip46tables -t mangle -A out-classify -g mark-to-$net_class_default run ip46tables -t mangle -A PREROUTING -j in-classify run ip46tables -t mangle -A PREROUTING -j out-classify diff --git a/config.m4 b/config.m4 index 6756452..ee9ef90 100644 --- a/config.m4 +++ b/config.m4 @@ -21,7 +21,7 @@ ### along with this program; if not, write to the Free Software Foundation, ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -m4_divert(5)m4_dnl +m4_divert(4)m4_dnl ###-------------------------------------------------------------------------- ### Configuration. @@ -39,14 +39,5 @@ defconf(open_port_max, 54999) ## Which chains to preserve. defconf(preserve_chains, ) -## Whether to permit forwarding. -defconf(forward, 1) - -## Whether to turn on the reverse-path filter. -defconf(rp_filter, 1) - -## Whether to turn on logging of martian packets. -defconf(log_martians, 1) - m4_divert(-1) ###----- That's all, folks -------------------------------------------------- diff --git a/fender.m4 b/fender.m4 index ea0fb32..05354bd 100644 --- a/fender.m4 +++ b/fender.m4 @@ -22,31 +22,6 @@ ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ###-------------------------------------------------------------------------- -### Config settings. - -## This host isn't a router. -setconf(forward, 0) - -## This host is involved in a routing asymmetry. -setconf(rp_filter, 0) -setconf(log_martians, 0) - -###-------------------------------------------------------------------------- -### Network interfaces. - -m4_divert(44)m4_dnl -## Interface definitions. -if_untrusted=eth0 -if_dmz=$if_untrusted -if_safe=$if_dmz -if_trusted=$if_dmz -if_vpn=$if_dmz -if_iodine=$if_dmz -if_its_mz=$if_dmz -if_its_pi=$if_dmz - -m4_divert(-1) -###-------------------------------------------------------------------------- ### fender-specific rules. m4_divert(82)m4_dnl diff --git a/functions.m4 b/functions.m4 index 05decbf..d059de6 100644 --- a/functions.m4 +++ b/functions.m4 @@ -58,11 +58,25 @@ defproto () { eval proto_$name=$number } +## addword VAR WORD +## +## Adds WORD to the value of the shell variable VAR, if it's not there +## already. Words are separated by a single space; no leading or trailing +## spaces are introduced. +addword () { + var=$1 word=$2 + eval val=\$$var + case " $val " in + *" $word "*) ;; + *) eval "$var=\${$var:+\$val }\$word" ;; + esac +} + m4_divert(38)m4_dnl ###-------------------------------------------------------------------------- ### Utility chains (used by function definitions). -m4_divert(22)m4_dnl +m4_divert(20)m4_dnl ###-------------------------------------------------------------------------- ### Basic chain constructions. @@ -122,7 +136,7 @@ errorchain () { run ip46tables -t $table -A $chain -j DROP } -m4_divert(24)m4_dnl +m4_divert(20)m4_dnl ###-------------------------------------------------------------------------- ### Basic option setting. @@ -178,7 +192,7 @@ setdevopt () { done } -m4_divert(26)m4_dnl +m4_divert(20)m4_dnl ###-------------------------------------------------------------------------- ### Packet filter construction. @@ -219,7 +233,7 @@ run ip6tables -A accept-non-init-frag -j RETURN \ -m frag --fragfirst run ip6tables -A accept-non-init-frag -j ACCEPT -m4_divert(26)m4_dnl +m4_divert(20)m4_dnl ## allowservices CHAIN PROTO SERVICE ... ## ## Add rules to allow the SERVICES on the CHAIN. @@ -306,9 +320,30 @@ openports () { run ip46tables -A $chain -p udp -g interesting --destination-port $1:$2 } -m4_divert(28)m4_dnl +m4_divert(20)m4_dnl ###-------------------------------------------------------------------------- ### Packet classification. +### +### See `classify.m4' for an explanation of how the firewall machinery for +### packet classification works. +### +### A list of all network names is kept in `allnets'. For each network NET, +### shell variables are defined describing their properties. +### +### net_class_NET The class of the network, as defined by +### `defnetclass'. +### net_inet_NET List of IPv4 address ranges in the network. +### net_inet6_NET List of IPv6 address ranges in the network. +### net_fwd_NET List of other networks that this one forwards to. +### net_hosts_NET List of hosts known to be in the network. +### host_inet_HOST IPv4 address of the named HOST. +### host_inet6_HOST IPv6 address of the named HOST. +### +### Similarly, a list of hosts is kept in `allhosts', and for each host HOST, +### a shell variables are defined: +### +### host_ifaces_HOST List of interfaces for this host and the networks +### they attach to, in the form IFACE=NET. ## defbitfield NAME WIDTH ## @@ -354,6 +389,7 @@ defnetclass () { ## Pass 1. Establish the from_NAME and to_NAME constants, and the ## netclass's mask bit. + trace "netclass $name = $netclassindex" eval from_$name=$(( $netclassindex << $BIT_FROM )) eval to_$name=$(( $netclassindex << $BIT_TO )) eval _mask_$name=$(( 1 << ($netclassindex + $BIT_MASK) )) @@ -385,91 +421,186 @@ defnetclass () { netclassindex=$(( $netclassindex + 1 )) } -## defiface NAME[,NAME,...] NETCLASS:NETWORK/MASK... -## -## Declares network interfaces with the given NAMEs and associates with them -## a number of reachable networks. During source classification, a packet -## arriving on interface NAME from an address in NETWORK/MASK is classified -## as coming from to NETCLASS. During destination classification, all -## packets going to NETWORK/MASK are classified as going to NETCLASS, -## regardless of interface (which is good, because the outgoing interface -## hasn't been determined yet). -## -## As a special case, the NETWORK/MASK can be the string `default', which -## indicates that all addresses not matched elsewhere should be considered. -ifaces=: -defaultifaces="" -allnets= allnets6= -defiface () { - set -e - names=$1; shift - seen=: - for name in $(echo $names | sed 'y/,/ /'); do - case $seen in *:"$name":*) continue ;; esac - seen=$seen$name: - case $ifaces in - *:"$name":*) ;; - *) - clearchain mangle:in-$name - run ip46tables -t mangle -A in-classify -i $name -g in-$name - ;; +## defnet NET CLASS +## +## Define a network. Follow by calls to `addr', `forwards', etc. to define +## properties of the network. Networks are processed in order, so if their +## addresses overlap then the more specific addresses should be defined +## earlier. +defnet () { + net=$1 class=$2 + addword allnets $net + eval net_class_$1=\$class +} + +## addr ADDRESS/LEN ... +## +## Define addresses for the network being defined. ADDRESSes are in +## colon-separated IPv6 or dotted-quad IPv4 form. +addr () { + for i in "$@"; do + case "$i" in + *:*) addword net_inet6_$net $i ;; + *) addword net_inet_$net $i ;; esac - ifaces=$ifaces$name: - for item; do - netclass=${item%:*} addr=${item#*:} - case $addr in - default) - case "$defaultifaces,$defaultclass" in - ,* | *,$netclass) - defaultifaces="$defaultifaces $name" - defaultclass=$netclass - ;; - *) - echo >&2 "$0: inconsistent default netclasses" - exit 1 - ;; - esac - ;; - *:*) - run ip6tables -t mangle -A in-$name -g mark-from-$netclass \ - -s $addr - run ip6tables -t mangle -A out-classify -g mark-to-$netclass \ - -d $addr - allnets6="$allnets6 $name:$addr" - ;; - *) - run iptables -t mangle -A in-$name -g mark-from-$netclass \ - -s $addr - run iptables -t mangle -A out-classify -g mark-to-$netclass \ - -d $addr - allnets="$allnets $name:$addr" - ;; - esac - done done } -## defvpn IFACE CLASS NET HOST:ADDR ... +## forwards NET ... ## -## Defines a VPN interface. If the interface has the form `ROOT+' (i.e., a -## netfilter wildcard) then define a separate interface ROOTHOST routing to -## ADDR; otherwise just write a blanket rule allowing the whole NET. All -## addresses concerned are put in the named CLASS. -defvpn () { - set -e - iface=$1 class=$2 net=$3; shift 3 - case $iface in - *-+) - root=${iface%+} - for host; do - name=${host%%:*} addr=${host#*:} - defiface $root$name $class:$addr - done - ;; - *) - defiface $iface $class:$net - ;; +## Declare that packets from this network are forwarded to the other NETs. +forwards () { + eval "net_fwd_$net=\"$*\"" +} + +## noxit NET ... +## +## Declare that packets from this network must not be forwarded to the other +## NETs. +noxit () { + eval "net_noxit_$net=\"$*\"" +} + +## host HOST ADDR ... +## +## Define the address of an individual host on the current network. The +## ADDRs may be full IPv4 or IPv6 addresses, or offsets from the containing +## network address, which is a simple number for IPv4, or a suffix beginning +## with `::' for IPv6. If an IPv6 base address is provided for the network +## but not for the host then the host's IPv4 address is used as a suffix. +host () { + name=$1; shift + + ## Work out which addresses we've actually been given. + unset a6 + for i in "$@"; do + case "$i" in ::*) a6=$i ;; *) a=$i ;; esac + done + case "${a+t}" in + t) ;; + *) echo >&2 "$0: no address for $name"; exit 1 ;; esac + case "${a6+t}" in t) ;; *) a6=::$a ;; esac + + ## Work out the IPv4 address. + eval nn=\$net_inet_$net + for n in $nn; do + addr=${n%/*} + base=${addr%.*} + offset=${addr##*.} + case $a in *.*) aa=$a ;; *) aa=$base.$(( $offset + $a )) ;; esac + eval host_inet_$name=$aa + done + + ## Work out the IPv6 address. + eval nn=\$net_inet6_$net + for n in $nn; do + addr=${n%/*} + base=${addr%::*} + case $a in ::*) aa=$addr$a ;; *) aa=$a ;; esac + eval host_inet6_$name=$aa + done + + ## Remember the host in the list. + addword net_hosts_$net $name +} + +## defhost NAME +## +## Define a new host. Follow by calls to `iface' to define the host's +## interfaces. +defhost () { + host=$1 + addword allhosts $host + eval host_type_$host=endsys +} + +## router +## +## Declare the host to be a router, so it should forward packets and so on. +router () { + eval host_type_$host=router +} + +## iface IFACE NET ... +## +## Define a host's interfaces. Specifically, declares that the host has an +## interface IFACE attached to the listed NETs. +iface () { + name=$1; shift + for net in "$@"; do + addword host_ifaces_$host $name=$net + done +} + +## net_interfaces HOST NET +## +## Determine the interfaces on which packets may plausibly arrive from the +## named NET. Returns `-' if no such interface exists. +## +## This algorithm is not very clever. It's just about barely good enough to +## deduce transitivity through a simple routed network; with complicated +## networks, it will undoubtedly give wrong answers. Check the results +## carefully, and, if necessary, list the connectivity explicitly; use the +## special interface `-' for networks you know shouldn't send packets to a +## host. +net_interfaces () { + host=$1 startnet=$2 + + ## Determine the locally attached networks. + targets=: + eval ii=\$host_ifaces_$host + for i in $ii; do targets=$targets$i:; done + + ## Determine the transitivity. + seen=: + nets=$startnet + while :; do + + ## First pass. Determine whether any of the networks we're considering + ## are in the target set. If they are, then return the corresponding + ## interfaces. + found="" + for net in $nets; do + tg=$targets + while :; do + any=nil + case $tg in + *"=$net:"*) + n=${tg%=$net:*}; tg=${n%:*}:; n=${n##*:} + addword found $n + any=t + ;; + esac + case $any in nil) break ;; esac + done + done + case "$found" in ?*) echo $found; return ;; esac + + ## No joy. Determine the set of networks which (a) these ones can + ## forward to, and (b) that we've not considered already. These are the + ## nets we'll consider next time around. + nextnets="" + any=nil + for net in $nets; do + eval fwd=\$net_fwd_$net + for n in $fwd; do + case $seen in *":$n:"*) continue ;; esac + seen=$seen$n: + eval noxit=\$net_noxit_$n + case " $noxit " in *" $startnet "*) continue ;; esac + case " $nextnets " in + *" $n "*) ;; + *) addword nextnets $n; any=t ;; + esac + done + done + + ## If we've run out of networks then there's no reachability. Return a + ## failure. + case $any in nil) echo -; return ;; esac + nets=$nextnets + done } m4_divert(-1) diff --git a/gibson.m4 b/gibson.m4 index 1676153..4416aee 100644 --- a/gibson.m4 +++ b/gibson.m4 @@ -22,30 +22,9 @@ ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ###-------------------------------------------------------------------------- -### Config settings. - -## This host isn't a router. -setconf(forward, 0) - -###-------------------------------------------------------------------------- -### Network interfaces. - -m4_divert(44)m4_dnl -## Interface definitions. -if_trusted=eth0 -if_dmz=$if_trusted -if_safe=$if_dmz -if_untrusted=$if_dmz -if_vpn=$if_dmz -if_iodine=$if_dmz -if_its_mz=$if_dmz -if_its_pi=$if_dmz - -m4_divert(-1) -###-------------------------------------------------------------------------- ### gibson-specific rules. -m4_divert(82)m4_dnl +m4_divert(84)m4_dnl ## Externally visible services. allowservices inbound tcp \ ssh \ diff --git a/ibanez.m4 b/ibanez.m4 index 2ec2c1c..93a816e 100644 --- a/ibanez.m4 +++ b/ibanez.m4 @@ -22,34 +22,9 @@ ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ###-------------------------------------------------------------------------- -### Config settings. - -## This host isn't a router. -setconf(forward, 0) - -## This host is involved in a routing asymmetry. -setconf(rp_filter, 0) -setconf(log_martians, 0) - -###-------------------------------------------------------------------------- -### Network interfaces. - -m4_divert(44)m4_dnl -## Interface definitions. -if_dmz=br-dmz -if_trusted=br-unsafe -if_safe=$if_dmz,$if_trusted -if_untrusted=$if_dmz,$if_trusted -if_vpn=$if_dmz,$if_trusted -if_iodine=$if_dmz,$if_trusted -if_its_mz=$if_dmz,$if_trusted -if_its_pi=$if_dmz,$if_trusted - -m4_divert(-1) -###-------------------------------------------------------------------------- ### ibanez-specific rules. -m4_divert(82)m4_dnl +m4_divert(84)m4_dnl ## Externally visible services. allowservices inbound tcp \ ssh \ diff --git a/jem.m4 b/jem.m4 index c91a104..7db1ce5 100644 --- a/jem.m4 +++ b/jem.m4 @@ -22,34 +22,9 @@ ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ###-------------------------------------------------------------------------- -### Config settings. - -## This host isn't a router. -setconf(forward, 0) - -## This host is involved in a routing asymmetry. -setconf(rp_filter, 0) -setconf(log_martians, 0) - -###-------------------------------------------------------------------------- -### Network interfaces. - -m4_divert(44)m4_dnl -## Interface definitions. -if_dmz=eth0 -if_trusted=eth1 -if_safe=$if_dmz,$if_trusted -if_untrusted=$if_dmz,$if_trusted -if_vpn=$if_dmz,$if_trusted -if_iodine=$if_dmz,$if_trusted -if_its_mz=$if_dmz,$if_trusted -if_its_pi=$if_dmz,$if_trusted - -m4_divert(-1) -###-------------------------------------------------------------------------- ### jem-specific rules. -m4_divert(82)m4_dnl +m4_divert(84)m4_dnl ## Set up the SAUCE sinbin. Unfortunately, ipset is a bit brittle. This ## isn't a completely critical part of the firewall security, so don't make ## this fail the entire script. diff --git a/local.m4 b/local.m4 index 2d880b9..b31b649 100644 --- a/local.m4 +++ b/local.m4 @@ -22,6 +22,15 @@ ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ###-------------------------------------------------------------------------- +### Local configuration. + +m4_divert(6)m4_dnl +## Default NTP servers. +defconf(ntp_servers, + "158.152.1.76 158.152.1.204 194.159.253.2 195.173.57.232") + +m4_divert(-1) +###-------------------------------------------------------------------------- ### Packet classification. ## Define the available network classes. @@ -30,81 +39,164 @@ defnetclass untrusted untrusted trusted defnetclass trusted untrusted trusted safe noloop defnetclass safe trusted safe noloop defnetclass noloop trusted safe -m4_divert(-1)m4_dnl +m4_divert(-1) +m4_divert(26)m4_dnl ###-------------------------------------------------------------------------- ### Network layout. -m4_divert(46)m4_dnl -## Networks and routing. - -defiface $if_dmz \ - trusted:62.49.204.144/28 \ - trusted:172.29.199.0/25 \ - untrusted:default -defiface $if_trusted \ - trusted:172.29.199.0/25 \ - untrusted:default -defiface $if_safe safe:172.29.199.192/26 -defiface $if_untrusted \ - untrusted:172.29.198.0/25 -defvpn $if_vpn safe 172.29.199.128/27 \ - crybaby:172.29.199.129 \ - terror:172.29.199.130 -defiface $if_iodine untrusted:172.29.198.128/28 -defiface $if_its_mz safe:172.29.199.160/30 -defiface $if_its_pi safe:192.168.0.0/24 +## House networks. +defnet dmz trusted + addr 62.49.204.144/28 + forwards unsafe untrusted +defnet unsafe trusted + addr 172.29.199.0/25 + forwards househub +defnet safe safe + addr 172.29.199.192/28 + forwards househub +defnet untrusted untrusted + addr 172.29.198.0/25 + forwards househub +defnet vpn safe + addr 172.29.199.128/27 + forwards househub + host crybaby 1 + host terror 2 +defnet iodine untrusted + addr 172.29.198.128/28 -## Default NTP servers. -ntp_servers="158.152.1.76 158.152.1.204 194.159.253.2 195.173.57.232" +defnet househub virtual + forwards housebdry dmz unsafe safe untrusted +defnet housebdry virtual + forwards househub hub + noxit dmz + +## House hosts. +defhost radius + router + iface eth0 dmz + iface eth1 unsafe + iface eth2 safe + iface eth3 untrusted +defhost roadstar + iface eth0 dmz + iface eth1 unsafe +defhost jem + iface eth0 dmz + iface eth1 unsafe +defhost artist + iface eth0 dmz + iface eth1 unsafe +defhost vampire + router + iface eth0.0 dmz + iface eth0.1 unsafe + iface eth0.3 untrusted + iface dns0 dns + iface vpn-+ vpn + iface vpn-precision colobdry vpn +defhost ibanez + iface br-dmz dmz + iface br-unsafe unsafe + +defhost gibson + iface eth0 unsafe + +## Colocated networks. +defnet jump trusted + addr 212.13.198.64/28 + forwards colohub +defnet colo trusted + addr 172.29.199.176/28 + forwards colohub +defnet colohub virtual + forwards colobdry jump colo +defnet colobdry virtual + forwards colohub hub + noxit jump -m4_divert(60)m4_dnl +## Colocated hosts. +defhost fender + iface br-jump jump + iface br-colo colo +defhost precision + router + iface eth0 jump + iface eth1 colo + iface vpn-+ vpn + iface vpn-vampire housebdry vpn +defhost telecaster + iface eth0 jump + iface eth1 colo +defhost stratocaster + iface eth0 jump + iface eth1 colo +defhost jazz + iface eth0 jump + iface eth1 colo + +## Other networks. +defnet hub virtual + forwards housebdry colobdry +defnet default untrusted + addr 62.49.204.144/28 + addr 212.13.198.64/28 + forwards dmz untrusted unsafe jump colo + +m4_divert(80)m4_dnl ###-------------------------------------------------------------------------- ### Special forwarding exemptions. -## Only allow these packets if they're not fragmented. (Don't trust safe -## hosts's fragment reassembly to be robust against malicious fragments.) -## There's a hideous bug in iptables 1.4.11.1 which botches the meaning of -## `! -f', so we do the negation using early return from a subchain. -clearchain fwd-spec-nofrag -run iptables -A fwd-spec-nofrag -j RETURN --fragment -run ip6tables -A fwd-spec-nofrag -j RETURN \ - -m ipv6header --soft --header frag -run iptables -A FORWARD -j fwd-spec-nofrag - -## Allow ping from safe/noloop to untrusted networks. -run iptables -A fwd-spec-nofrag -j ACCEPT \ - -p icmp --icmp-type echo-request \ - -m mark --mark $to_untrusted/$MASK_TO -run iptables -A fwd-spec-nofrag -j ACCEPT \ - -p icmp --icmp-type echo-reply \ - -m mark --mark $from_untrusted/$MASK_FROM \ - -m state --state ESTABLISHED -run ip6tables -A fwd-spec-nofrag -j ACCEPT \ - -p ipv6-icmp --icmpv6-type echo-request \ - -m mark --mark $to_untrusted/$MASK_TO -run ip6tables -A fwd-spec-nofrag -j ACCEPT \ - -p ipv6-icmp --icmpv6-type echo-reply \ - -m mark --mark $from_untrusted/$MASK_FROM \ - -m state --state ESTABLISHED - -## Allow SSH from safe/noloop to untrusted networks. -run iptables -A fwd-spec-nofrag -j ACCEPT \ - -p tcp --destination-port $port_ssh \ - -m mark --mark $to_untrusted/$MASK_TO -run iptables -A fwd-spec-nofrag -j ACCEPT \ - -p tcp --source-port $port_ssh \ - -m mark --mark $from_untrusted/$MASK_FROM \ - -m state --state ESTABLISHED -run ip6tables -A fwd-spec-nofrag -j ACCEPT \ - -p tcp --destination-port $port_ssh \ - -m mark --mark $to_untrusted/$MASK_TO -run ip6tables -A fwd-spec-nofrag -j ACCEPT \ - -p tcp --source-port $port_ssh \ - -m mark --mark $from_untrusted/$MASK_FROM \ - -m state --state ESTABLISHED - -m4_divert(60)m4_dnl +case $forward in + 1) + + ## Only allow these packets if they're not fragmented. (Don't trust safe + ## hosts's fragment reassembly to be robust against malicious fragments.) + ## There's a hideous bug in iptables 1.4.11.1 which botches the meaning + ## of `! -f', so we do the negation using early return from a subchain. + clearchain fwd-spec-nofrag + run iptables -A fwd-spec-nofrag -j RETURN --fragment + run ip6tables -A fwd-spec-nofrag -j RETURN \ + -m ipv6header --soft --header frag + run iptables -A FORWARD -j fwd-spec-nofrag + + ## Allow ping from safe/noloop to untrusted networks. + run iptables -A fwd-spec-nofrag -j ACCEPT \ + -p icmp --icmp-type echo-request \ + -m mark --mark $to_untrusted/$MASK_TO + run iptables -A fwd-spec-nofrag -j ACCEPT \ + -p icmp --icmp-type echo-reply \ + -m mark --mark $from_untrusted/$MASK_FROM \ + -m state --state ESTABLISHED + run ip6tables -A fwd-spec-nofrag -j ACCEPT \ + -p ipv6-icmp --icmpv6-type echo-request \ + -m mark --mark $to_untrusted/$MASK_TO + run ip6tables -A fwd-spec-nofrag -j ACCEPT \ + -p ipv6-icmp --icmpv6-type echo-reply \ + -m mark --mark $from_untrusted/$MASK_FROM \ + -m state --state ESTABLISHED + + ## Allow SSH from safe/noloop to untrusted networks. + run iptables -A fwd-spec-nofrag -j ACCEPT \ + -p tcp --destination-port $port_ssh \ + -m mark --mark $to_untrusted/$MASK_TO + run iptables -A fwd-spec-nofrag -j ACCEPT \ + -p tcp --source-port $port_ssh \ + -m mark --mark $from_untrusted/$MASK_FROM \ + -m state --state ESTABLISHED + run ip6tables -A fwd-spec-nofrag -j ACCEPT \ + -p tcp --destination-port $port_ssh \ + -m mark --mark $to_untrusted/$MASK_TO + run ip6tables -A fwd-spec-nofrag -j ACCEPT \ + -p tcp --source-port $port_ssh \ + -m mark --mark $from_untrusted/$MASK_FROM \ + -m state --state ESTABLISHED + + ;; +esac + +m4_divert(80)m4_dnl ###-------------------------------------------------------------------------- ### Kill things we don't understand properly. ### @@ -114,12 +206,16 @@ m4_divert(60)m4_dnl errorchain poorly-understood REJECT ## Ban multicast destination addresses in forwarding. -run iptables -A FORWARD -g poorly-understood \ - -d 224.0.0.0/4 -run ip6tables -A FORWARD -g poorly-understood \ - -d ff::/8 +case $forward in + 1) + run iptables -A FORWARD -g poorly-understood \ + -d 224.0.0.0/4 + run ip6tables -A FORWARD -g poorly-understood \ + -d ff::/8 + ;; +esac -m4_divert(80)m4_dnl +m4_divert(84)m4_dnl ###-------------------------------------------------------------------------- ### Locally-bound packet inspection. @@ -166,9 +262,12 @@ run ip46tables -A inbound -j forbidden run ip46tables -A INPUT -m mark --mark $from_untrusted/$MASK_FROM -g inbound ## Otherwise process as indicated by the mark. -for i in INPUT FORWARD; do - run ip46tables -A $i -m mark ! --mark 0/$MASK_MASK -j ACCEPT -done +run ip46tables -A INPUT -m mark ! --mark 0/$MASK_MASK -j ACCEPT +case $forward in + 1) + run ip46tables -A FORWARD -m mark ! --mark 0/$MASK_MASK -j ACCEPT + ;; +esac m4_divert(-1) ###----- That's all, folks -------------------------------------------------- diff --git a/numbers.m4 b/numbers.m4 index 4d111da..c94ae5f 100644 --- a/numbers.m4 +++ b/numbers.m4 @@ -21,7 +21,7 @@ ### along with this program; if not, write to the Free Software Foundation, ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -m4_divert(25)m4_dnl +m4_divert(24)m4_dnl ###-------------------------------------------------------------------------- ### Magic numbers. diff --git a/radius.m4 b/radius.m4 index 029d9f1..d698998 100644 --- a/radius.m4 +++ b/radius.m4 @@ -22,31 +22,9 @@ ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ###-------------------------------------------------------------------------- -### Config settings. - -## This router is involved in a routing asymmetry. -setconf(rp_filter, 0) -setconf(log_martians, 0) - -###-------------------------------------------------------------------------- -### Network interfaces. - -m4_divert(44)m4_dnl -## Interface definitions. -if_dmz=eth0 -if_trusted=eth1 -if_safe=eth2 -if_untrusted=eth3 -if_vpn=$if_dmz,$if_trusted -if_iodine=$if_dmz,$if_trusted -if_its_mz=$if_dmz,$if_trusted -if_its_pi=$if_dmz,$if_trusted - -m4_divert(-1) -###-------------------------------------------------------------------------- ### radius-specific rules. -m4_divert(82)m4_dnl +m4_divert(84)m4_dnl ## Externally visible services. allowservices inbound tcp \ ident \ diff --git a/roadstar.m4 b/roadstar.m4 index b2e3301..4947a80 100644 --- a/roadstar.m4 +++ b/roadstar.m4 @@ -22,34 +22,9 @@ ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ###-------------------------------------------------------------------------- -### Config settings. - -## This host isn't a router. -setconf(forward, 0) - -## This host is involved in a routing asymmetry. -setconf(rp_filter, 0) -setconf(log_martians, 0) - -###-------------------------------------------------------------------------- -### Network interfaces. - -m4_divert(44)m4_dnl -## Interface definitions. -if_dmz=eth0 -if_trusted=eth1 -if_safe=$if_dmz,$if_trusted -if_untrusted=$if_dmz,$if_trusted -if_vpn=$if_dmz,$if_trusted -if_iodine=$if_dmz,$if_trusted -if_its_mz=$if_dmz,$if_trusted -if_its_pi=$if_dmz,$if_trusted - -m4_divert(-1) -###-------------------------------------------------------------------------- ### roadstar-specific rules. -m4_divert(82)m4_dnl +m4_divert(84)m4_dnl ## Externally visible services. allowservices inbound tcp \ ssh \ diff --git a/vampire.m4 b/vampire.m4 index 2cf1a13..44eef03 100644 --- a/vampire.m4 +++ b/vampire.m4 @@ -22,31 +22,9 @@ ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ###-------------------------------------------------------------------------- -### Config settings. - -## This router is involved in a routing asymmetry. -setconf(rp_filter, 0) -setconf(log_martians, 0) - -###-------------------------------------------------------------------------- -### Network interfaces. - -m4_divert(44)m4_dnl -## Interface definitions. -if_dmz=eth0.0 -if_trusted=eth0.1 -if_safe=$if_dmz,$if_trusted -if_untrusted=eth0.3 -if_vpn=vpn-+ -if_iodine=dns+ -if_its_mz=$if_dmz,$if_trusted -if_its_pi=$if_dmz,$if_trusted - -m4_divert(-1) -###-------------------------------------------------------------------------- ### vampire-specific rules. -m4_divert(82)m4_dnl +m4_divert(86)m4_dnl ## Externally visible services. allowservices inbound tcp \ finger ident \ @@ -102,7 +80,7 @@ run iptables -t nat -F run iptables -t nat -X run iptables -t nat -N outbound -run iptables -t nat -A outbound -j RETURN ! -o $if_dmz +run iptables -t nat -A outbound -j RETURN ! -o eth0.0 run iptables -t nat -A outbound -j RETURN ! -s 172.29.198.0/23 run iptables -t nat -A outbound -j RETURN -d 62.49.204.144/28 run iptables -t nat -A outbound -j RETURN -d 172.29.198.0/23