## Take the various IP versions in turn.
unref=nil
for ip in ip ip6; do
+ if [ "$FW_NOACT" ]; then break; fi
+
for table in $(cat /proc/net/${ip}_tables_names); do
## Step 1: clear out the builtin chains.
## Set forwarding options. Apparently setting ip_forward clobbers other
## settings, so put this first.
case $host_type_<::>FWHOST in
- router) forward=1 ;;
- *) forward=0 ;;
+ router) forward=1 host=0 ;;
+ server) forward=0 host=0 ;;
+ client) forward=0 host=1 ;;
esac
setopt ip_forward $forward
setdevopt forwarding $forward
+for i in \
+ accept_ra accept_ra_defrtr accept_ra_pinfo accept_ra_info_max_plen
+do
+ setdevopt $i $host
+done
case $forward in
0) inchains="INPUT" ;;
1) inchains="INPUT FORWARD" ;;
run ip6tables -A check-fwd-multi -g bad-destination-address \
-d ff${x}2::/16
done
- ip6tables -A FORWARD -j check-fwd-multi -d ff00::/8
+ run ip6tables -A FORWARD -j check-fwd-multi -d ff00::/8
;;
esac
for ver in ipv4 ipv6; do
if [ -f /proc/sys/net/$ver/conf/$i/$opt ]; then
any=t
- run sysctl -q net/ipv4/conf/$i/$opt="$val"
+ run sysctl -q net/$ver/conf/$i/$opt="$val"
fi
done
case $any in
defhost () {
host=$1
addword allhosts $host
- eval host_type_$host=endsys
+ eval host_type_$host=server
}
-## router
+## hosttype TYPE
##
-## Declare the host to be a router, so it should forward packets and so on.
-router () {
- eval host_type_$host=router
+## Declare the host to have the given type.
+hosttype () {
+ type=$1
+ case $type in
+ router | server | client) ;;
+ *) echo >&2 "$0: bad host type \`$type'"; exit 1 ;;
+ esac
+ eval host_type_$host=$type
}
## iface IFACE NET ...
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