+ eval host_type_$host=$type
+}
+
+## 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