local.m4: Fix whitespace oddity.
[firewall] / functions.m4
index 03f6af5..765a94d 100644 (file)
@@ -109,11 +109,19 @@ clearchain () {
 makeset () {
   set -e
   name=$1; shift
-  if ipset -nL | grep -q "^Name: $name$"; then
-    :
-  else
-    ipset -N "$name" "$@"
-  fi
+  v=$(ipset --version)
+  createp=t
+  case "$v" in
+    "ipset v4"*)
+      if ipset -nL | grep -q "^Name: $name\$"; then createp=nil; fi
+      ;;
+    *)
+      if ipset -n -L | grep -q "^$name\$"; then createp=nil; fi
+      ;;
+  esac
+  case $createp in
+    t) ipset -N "$name" "$@" ;;
+  esac
 }
 
 ## errorchain CHAIN ACTION ARGS ...
@@ -130,7 +138,7 @@ errorchain () {
   clearchain $table:$chain
   run ip46tables -t $table -A $chain -j LOG \
          -m limit --limit 3/minute --limit-burst 10 \
-         --log-prefix "fw: $chain " --log-level notice
+         --log-prefix "fw: $chain " --log-level notice || :
   run ip46tables -t $table -A $chain -j "$@" \
          -m limit --limit 20/second --limit-burst 100
   run ip46tables -t $table -A $chain -j DROP
@@ -231,7 +239,8 @@ m4_divert(38)m4_dnl
 run ip6tables -N accept-non-init-frag
 run ip6tables -A accept-non-init-frag -j RETURN \
        -m frag --fragfirst
-run ip6tables -A accept-non-init-frag -j ACCEPT
+run ip6tables -A accept-non-init-frag -j ACCEPT \
+       -m ipv6header --header frag
 
 m4_divert(20)m4_dnl
 ## allowservices CHAIN PROTO SERVICE ...
@@ -292,8 +301,11 @@ ntpclient () {
   ntpchain=$1; shift
 
   clearchain ntp-servers
-  for ntp; do run iptables -A ntp-servers -j ACCEPT -s $ntp; done
-  run iptables -A $ntpchain -j ntp-servers \
+  for ntp; do
+    case $ntp in *:*) ipt=ip6tables ;; *) ipt=iptables ;; esac
+    run $ipt -A ntp-servers -j ACCEPT -s $ntp;
+  done
+  run ip46tables -A $ntpchain -j ntp-servers \
          -p udp --source-port 123 --destination-port 123
 }
 
@@ -341,6 +353,50 @@ openports () {
   run ip46tables -A $chain -p udp -g interesting --destination-port $1:$2
 }
 
+bcp38_setup=:
+bcp38 () {
+  ipv=$1 ifname=$2; shift 2
+  ## Add rules for BCP38 egress filtering for IP version IPV (either 4 or 6).
+  ## IFNAME is the outgoing interface; the remaining arguments are network
+  ## prefixes.
+
+  ## Sort out which command we're using
+  case $ipv in
+    4) ipt=iptables ;;
+    6) ipt=ip6tables ;;
+    *) echo >&2 "Unknown IP version $ipv"; exit 1 ;;
+  esac
+
+  ## If we've not set up the error chain then do that.
+  case $bcp38_setup in
+    :)
+      errorchain bcp38 DROP
+      clearchain bcp38-check
+      ip46tables -A bcp38-check -g bcp38
+      ;;
+  esac
+
+  ## Stitch our egress filter into the outbound chains if we haven't done
+  ## that yet.  Do this for both IP versions: if we're only ever given
+  ## IPv6 addresses for a particular interface then we assume that IPv4
+  ## packets aren't allowed on it at all.
+  case $bcp38_setup in
+    *:$ifname:*) ;;
+    *)
+      run ip46tables -A OUTPUT -j bcp38-check -o $ifname
+      case $forward in
+       1) run ip46tables -A FORWARD -j bcp38-check -o $ifname ;;
+      esac
+      bcp38_setup=$bcp38_setup$ifname:
+      ;;
+  esac
+
+  ## Finally, add in our allowed networks.
+  for i in "$@"; do
+    run $ipt -I bcp38-check -j RETURN -s $i
+  done
+}
+
 m4_divert(20)m4_dnl
 ###--------------------------------------------------------------------------
 ### Packet classification.
@@ -355,7 +411,7 @@ m4_divert(20)m4_dnl
 ###                    `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_via_NET                List of other networks that this one forwards via.
 ### 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.
@@ -427,9 +483,9 @@ defnetclass () {
        from=$(( $from + $bit ))
       done
       to=$(( ($netclassindex << $BIT_TO) ))
-      tomask=$(( $MASK_MASK ^ (1 << ($netclassindex + $BIT_MASK)) ))
+      tomask=$(( $MASK_TO | $MASK_MASK ^ (1 << ($netclassindex + $BIT_MASK)) ))
       trace "from $name --> set $(printf %08x/%08x $from $frommask)"
-      trace "  to $name --> and $(printf %08x/%08x $to $tomask)"
+      trace "  to $name --> set $(printf %08x/%08x $to $tomask)"
 
       ## Now establish the mark-from-NAME and mark-to-NAME chains.
       clearchain mangle:mark-from-$name mangle:mark-to-$name
@@ -444,7 +500,7 @@ defnetclass () {
 
 ## defnet NET CLASS
 ##
-## Define a network.  Follow by calls to `addr', `forwards', etc. to define
+## Define a network.  Follow by calls to `addr', `via', 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.
@@ -467,11 +523,11 @@ addr () {
   done
 }
 
-## forwards NET ...
+## via NET ...
 ##
 ## Declare that packets from this network are forwarded to the other NETs.
-forwards () {
-  eval "net_fwd_$net=\"$*\""
+via () {
+  eval "net_via_$net=\"$*\""
 }
 
 ## noxit NET ...
@@ -559,15 +615,18 @@ iface () {
   done
 }
 
+## matchnets OPT WIN FLAGS PREPARE BASE SUFFIX NEXT NET [NET ...]
+##
 ## Build rules which match a particular collection of networks.
+##
 ## Specifically, use the address-comparison operator OPT (typically `-s' or
-## `-d') to match the addresses of NOT, writing the rules to the chain
-## BASESUFFIX.  If we find a match, dispatch to WIN-CLASS, where CLASS is
-## the class of the matching network.  In order to deal with networks
-## containing negative address ranges, more chains may need to be
-## constructed; they will be named BASE#Q for sequence numbers Q starting
-## with NEXT.  All of this happens on the `mangle' table, and there isn't
-## (currently) a way to tweak this.
+## `-d') to match the addresses of each NET, writing the rules to the chain
+## BASESUFFIX.  If we find a match, dispatch to WIN-CLASS, where CLASS is the
+## class of the matching network.  In order to deal with networks containing
+## negative address ranges, more chains may need to be constructed; they will
+## be named BASE#Q for sequence numbers Q starting with NEXT.  All of this
+## happens on the `mangle' table, and there isn't (currently) a way to tweak
+## this.
 ##
 ## The FLAGS gather additional interesting information about the job,
 ## separated by colons.  The only flag currently is :default: which means
@@ -718,8 +777,8 @@ net_interfaces () {
     nextnets=""
     any=nil
     for net in $nets; do
-      eval fwd=\$net_fwd_$net
-      for n in $fwd; do
+      eval via=\$net_via_$net
+      for n in $via; do
        case $seen in *":$n:"*) continue ;; esac
        seen=$seen$n:
        eval noxit=\$net_noxit_$n