X-Git-Url: https://git.distorted.org.uk/~mdw/firewall/blobdiff_plain/fb7845a892c48e5004dea115bdd6b8a17fea7935..1264e9177da9fb94a1fb85853220dd69a7108f0a:/functions.m4 diff --git a/functions.m4 b/functions.m4 index 0ebba30..16c07c8 100644 --- a/functions.m4 +++ b/functions.m4 @@ -534,6 +534,115 @@ iface () { done } +## 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. +## +## The FLAGS gather additional interesting information about the job, +## separated by colons. The only flag currently is :default: which means +## that the default network was listed. +## +## Finally, there is a hook PREPARE which is called just in advance of +## processing the final network, passing it the argument FLAGS. (The PREPARE +## string will be subjected to shell word-splitting, so it can provide some +## arguments of its own if it wants.) It should set `mode' to indicate how +## the chain should be finished. +## +## goto If no networks matched, then issue a final `goto' to the +## chain named by the variable `fail'. +## +## call Run `$finish CHAIN' to write final rules to the named CHAIN +## (which may be suffixed from the original BASE argument if +## this was necessary). This function will arrange to call +## these rules if no networks match. +## +## ret If no network matches then return (maybe by falling off the +## end of the chain). +matchnets () { + local opt win flags prepare base suffix next net lose splitp + opt=$1 win=$2 flags=$3 prepare=$4 base=$5 suffix=$6 next=$7 net=$8 + shift 8 + + ## If this is the default network, then set the flag. + case "$net" in default) flags=${flags}default: ;; esac + + ## Do an initial pass over the addresses to see whether there are any + ## negative ranges. If so, we'll need to split. See also the standard + ## joke about soup. + splitp=nil + eval "addrs=\"\$net_inet_$net \$net_inet6_$net\"" + for a in $addrs; do case $a in !*) splitp=t; break ;; esac; done + + trace "MATCHNETS [splitp $splitp] $opt $win $flags [$prepare] $base $suffix $next : $net $*" + + ## Work out how to handle matches against negative address ranges. If this + ## is the last network, invoke the PREPARE hook to find out. Otherwise, if + ## we have to split the chain, recursively build the target here. + case $splitp,$# in + t,0 | nil,0) + $prepare $flags + case $splitp,$mode in + *,goto) + lose="-g $fail" + ;; + *,ret) + lose="-j RETURN" + ;; + t,call) + clearchain mangle:$base#$next + lose="-g $base#$next" + ;; + nil,call) + ;; + esac + ;; + t,*) + clearchain mangle:$base#$next + matchnets $opt $win $flags "$prepare" \ + $base \#$next $(( $next + 1 )) "$@" + lose="-g $base#$next" mode=goto + ;; + *) + mode=continue + ;; + esac + + ## Populate the chain with rules to match the necessary networks. + eval addr=\$net_inet_$net addr6=\$net_inet6_$net class=\$net_class_$net + for a in $addr; do + case $a in + !*) run iptables -t mangle -A $base$suffix $lose $opt ${a#!} ;; + *) run iptables -t mangle -A $base$suffix -g $win-$class $opt $a ;; + esac + done + for a in $addr6; do + case $a in + !*) run ip6tables -t mangle -A $base$suffix $lose $opt ${a#!} ;; + *) run ip6tables -t mangle -A $base$suffix -g $win-$class $opt $a ;; + esac + done + + ## Wrap up the chain appropriately. If we didn't split and there are more + ## networks to handle then append the necessary rules now. (If we did + ## split, then we already wrote the rules for them above.) If there are no + ## more networks then consult the `mode' setting to find out what to do. + case $splitp,$#,$mode in + *,0,ret) ;; + *,*,goto) run ip46tables -t mangle -A $base$suffix $lose ;; + t,0,call) $finish $base#$next ;; + nil,0,call) $finish $base$suffix ;; + nil,*,*) + matchnets $opt $win $flags "$prepare" $base "$suffix" $next "$@" + ;; + esac +} + ## net_interfaces HOST NET ## ## Determine the interfaces on which packets may plausibly arrive from the