mirror of
https://gitlab.com/shorewall/code.git
synced 2024-12-25 07:38:57 +01:00
b66929a65e
1) Elimination of the "shorewall monitor" command. 2) The /etc/shorewall/ipsec and /etc/shorewall/zones file are combined into a single /etc/shorewall/zones file. This is done in an upwardly-compatible way so that current users can continue to use their existing files. 3) Support has been added for the arp_ignore interface option. 4) DROPINVALID has been removed from shorewall.conf. Behavior is as if DROPINVALID=No was specified. 5) The 'nobogons' option and BOGON_LOG_LEVEL are removed. 6) Error and warning messages have been made easier to spot by using capitalization (e.g., ERROR: and WARNING:). 7) The /etc/shorewall/policy file now contains a new connection policy and a policy for ESTABLISHED packets. Useful for users of snort-inline who want to pass all packets to the QUEUE target. 8) A new 'critical' option has been added to /etc/shorewall/routestopped. Shorewall insures communication between the firewall and 'critical' hosts throughout start, restart, stop and clear. Useful for diskless firewall's with NFS-mounted file systems, LDAP servers, Crossbow, etc. 9) Macros. Macros are very similar to actions but are easier to use, allow parameter substitution and are more efficient. Almost all of the standard actions have been converted to macros in the EXPERIMENTAL branch. 10) The default value of ADD_IP_ALIASES in shorewall.conf is changed to No. 11) If you have 'make' installed on your firewall, then when you use the '-f' option to 'shorewall start' (as happens when you reboot), if your /etc/shorewall/ directory contains files that were modified after Shorewall was last restarted then Shorewall is started using the config files rather than using the saved configuration. git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@2409 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
787 lines
14 KiB
Bash
Executable File
787 lines
14 KiB
Bash
Executable File
#!/bin/sh
|
|
#
|
|
# Shorewall 2.6 -- /usr/share/shorewall/functions
|
|
|
|
# Function to truncate a string -- It uses 'cut -b -<n>'
|
|
# rather than ${v:first:last} because light-weight shells like ash and
|
|
# dash do not support that form of expansion.
|
|
#
|
|
|
|
truncate() # $1 = length
|
|
{
|
|
cut -b -${1}
|
|
}
|
|
|
|
#
|
|
# Split a colon-separated list into a space-separated list
|
|
#
|
|
split() {
|
|
local ifs=$IFS
|
|
IFS=:
|
|
set -- $1
|
|
echo $*
|
|
IFS=$ifs
|
|
}
|
|
|
|
#
|
|
# Search a list looking for a match -- returns zero if a match found
|
|
# 1 otherwise
|
|
#
|
|
list_search() # $1 = element to search for , $2-$n = list
|
|
{
|
|
local e=$1
|
|
|
|
while [ $# -gt 1 ]; do
|
|
shift
|
|
[ "x$e" = "x$1" ] && return 0
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
#
|
|
# Functions to count list elements
|
|
# - - - - - - - - - - - - - - - -
|
|
# Whitespace-separated list
|
|
#
|
|
list_count1() {
|
|
echo $#
|
|
}
|
|
#
|
|
# Comma-separated list
|
|
#
|
|
list_count() {
|
|
list_count1 $(separate_list $1)
|
|
}
|
|
|
|
#
|
|
# Conditionally produce message
|
|
#
|
|
progress_message() # $* = Message
|
|
{
|
|
[ -n "$QUIET" ] || echo "$@"
|
|
}
|
|
|
|
#
|
|
# Suppress all output for a command
|
|
#
|
|
qt()
|
|
{
|
|
"$@" >/dev/null 2>&1
|
|
}
|
|
|
|
#
|
|
# Perform variable substitution on the passed argument and echo the result
|
|
#
|
|
expand() # $@ = contents of variable which may be the name of another variable
|
|
{
|
|
eval echo \"$@\"
|
|
}
|
|
|
|
#
|
|
# Perform variable substitition on the values of the passed list of variables
|
|
#
|
|
expandv() # $* = list of variable names
|
|
{
|
|
local varval
|
|
|
|
while [ $# -gt 0 ]; do
|
|
eval varval=\$${1}
|
|
eval $1=\"$varval\"
|
|
shift
|
|
done
|
|
}
|
|
|
|
#
|
|
# Replace all leading "!" with "! " in the passed argument list
|
|
#
|
|
|
|
fix_bang() {
|
|
local i;
|
|
|
|
for i in $@; do
|
|
case $i in
|
|
!*)
|
|
echo "! ${i#!}"
|
|
;;
|
|
*)
|
|
echo $i
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
#
|
|
# Set default config path
|
|
#
|
|
ensure_config_path() {
|
|
local F=/usr/share/shorewall/configpath
|
|
if [ -z "$CONFIG_PATH" ]; then
|
|
[ -f $F ] || { echo " ERROR: $F does not exist"; exit 2; }
|
|
. $F
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Find a File -- For relative file name, look first in $SHOREWALL_DIR then in /etc/shorewall
|
|
#
|
|
find_file()
|
|
{
|
|
local saveifs= directory
|
|
|
|
case $1 in
|
|
/*)
|
|
echo $1
|
|
;;
|
|
*)
|
|
if [ -n "$SHOREWALL_DIR" -a -f $SHOREWALL_DIR/$1 ]; then
|
|
echo $SHOREWALL_DIR/$1
|
|
else
|
|
saveifs=$IFS
|
|
IFS=:
|
|
for directory in $CONFIG_PATH; do
|
|
if [ -f $directory/$1 ]; then
|
|
echo $directory/$1
|
|
IFS=$saveifs
|
|
return
|
|
fi
|
|
done
|
|
|
|
IFS=$saveifs
|
|
|
|
echo /etc/shorewall/$1
|
|
fi
|
|
;;
|
|
esac
|
|
}
|
|
|
|
#
|
|
# Replace commas with spaces and echo the result
|
|
#
|
|
separate_list() {
|
|
local list="$@"
|
|
local part
|
|
local newlist
|
|
local firstpart
|
|
local lastpart
|
|
local enclosure
|
|
#
|
|
# There's been whining about us not catching embedded white space in
|
|
# comma-separated lists. This is an attempt to snag some of the cases.
|
|
#
|
|
# The 'terminator' function will be set by the 'firewall' script to
|
|
# either 'startup_error' or 'fatal_error' depending on the command and
|
|
# command phase
|
|
#
|
|
case "$list" in
|
|
*,|,*|*,,*|*[[:space:]]*)
|
|
[ -n "$terminator" ] && \
|
|
$terminator "Invalid comma-separated list \"$@\""
|
|
echo "Warning -- invalid comma-separated list \"$@\"" >&2
|
|
;;
|
|
*\[*\]*)
|
|
#
|
|
# Where we need to embed comma-separated lists within lists, we enclose them
|
|
# within square brackets
|
|
#
|
|
firstpart=${list%%\[*}
|
|
lastpart=${list#*\[}
|
|
enclosure=${lastpart%\]*}
|
|
lastpart=${lastpart#*\]}
|
|
case $lastpart in
|
|
\,*)
|
|
echo "$(separate_list $firstpart)[$enclosure] $(separate_list ${lastpart#,})"
|
|
;;
|
|
*)
|
|
echo "$(separate_list $firstpart)[$enclosure]$(separate_list $lastpart)"
|
|
;;
|
|
esac
|
|
return
|
|
;;
|
|
esac
|
|
|
|
list="$@"
|
|
part="${list%%,*}"
|
|
newlist="$part"
|
|
|
|
while [ "x$part" != "x$list" ]; do
|
|
list="${list#*,}";
|
|
part="${list%%,*}";
|
|
newlist="$newlist $part";
|
|
done
|
|
|
|
echo "$newlist"
|
|
}
|
|
|
|
#
|
|
# Load a Kernel Module
|
|
#
|
|
loadmodule() # $1 = module name, $2 - * arguments
|
|
{
|
|
local modulename=$1
|
|
local modulefile
|
|
local suffix
|
|
moduleloader=modprobe
|
|
|
|
if ! qt which modprobe; then
|
|
moduleloader=insmod
|
|
fi
|
|
|
|
if [ -z "$(lsmod | grep $modulename)" ]; then
|
|
shift
|
|
|
|
for suffix in $MODULE_SUFFIX ; do
|
|
modulefile=$MODULESDIR/${modulename}.${suffix}
|
|
|
|
if [ -f $modulefile ]; then
|
|
case $moduleloader in
|
|
insmod)
|
|
insmod $modulefile $*
|
|
;;
|
|
*)
|
|
modprobe $modulename $*
|
|
;;
|
|
esac
|
|
|
|
return
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Reload the Modules
|
|
#
|
|
reload_kernel_modules() {
|
|
|
|
[ -z "$MODULESDIR" ] && MODULESDIR=/lib/modules/$(uname -r)/kernel/net/ipv4/netfilter
|
|
|
|
while read command; do
|
|
eval $command
|
|
done
|
|
|
|
}
|
|
|
|
#
|
|
# Call this function to assert MUTEX with Shorewall. If you invoke the
|
|
# /sbin/shorewall program while holding MUTEX, you should pass "nolock" as
|
|
# the first argument. Example "shorewall nolock refresh"
|
|
#
|
|
# This function uses the lockfile utility from procmail if it exists.
|
|
# Otherwise, it uses a somewhat race-prone algorithm to attempt to simulate the
|
|
# behavior of lockfile.
|
|
#
|
|
mutex_on()
|
|
{
|
|
local try=0
|
|
local lockf=/var/lib/shorewall/lock
|
|
|
|
MUTEX_TIMEOUT=${MUTEX_TIMEOUT:-60}
|
|
|
|
if [ $MUTEX_TIMEOUT -gt 0 ]; then
|
|
|
|
[ -d /var/lib/shorewall ] || mkdir -p /var/lib/shorewall
|
|
|
|
if qt which lockfile; then
|
|
lockfile -${MUTEX_TIMEOUT} -r1 ${lockf}
|
|
else
|
|
while [ -f ${lockf} -a ${try} -lt ${MUTEX_TIMEOUT} ] ; do
|
|
sleep 1
|
|
try=$((${try} + 1))
|
|
done
|
|
|
|
if [ ${try} -lt ${MUTEX_TIMEOUT} ] ; then
|
|
# Create the lockfile
|
|
echo $$ > ${lockf}
|
|
else
|
|
echo "Giving up on lock file ${lockf}" >&2
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Call this function to release MUTEX
|
|
#
|
|
mutex_off()
|
|
{
|
|
rm -f /var/lib/shorewall/lock
|
|
}
|
|
|
|
#
|
|
# Determine which version of mktemp is present (if any) and set MKTEMP accortingly:
|
|
#
|
|
# None - No mktemp
|
|
# BSD - BSD mktemp (Mandrake)
|
|
# STD - mktemp.org mktemp
|
|
#
|
|
find_mktemp() {
|
|
local mktemp=`which mktemp 2> /dev/null`
|
|
|
|
if [ -n "$mktemp" ]; then
|
|
if qt mktemp -V ; then
|
|
MKTEMP=STD
|
|
else
|
|
MKTEMP=BSD
|
|
fi
|
|
else
|
|
MKTEMP=None
|
|
fi
|
|
}
|
|
|
|
#
|
|
# create a temporary file. If a directory name is passed, the file will be created in
|
|
# that directory. Otherwise, it will be created in a temporary directory.
|
|
#
|
|
mktempfile() {
|
|
|
|
[ -z "$MKTEMP" ] && find_mktemp
|
|
|
|
if [ $# -gt 0 ]; then
|
|
case "$MKTEMP" in
|
|
BSD)
|
|
mktemp $1/shorewall.XXXXXX
|
|
;;
|
|
STD)
|
|
mktemp -p $1 shorewall.XXXXXX
|
|
;;
|
|
None)
|
|
> $1/shorewall-$$ && echo $1/shorewall-$$
|
|
;;
|
|
*)
|
|
echo " ERROR:Internal error in mktempfile" >&2
|
|
;;
|
|
esac
|
|
else
|
|
case "$MKTEMP" in
|
|
BSD)
|
|
mktemp /tmp/shorewall.XXXXXX
|
|
;;
|
|
STD)
|
|
mktemp -t shorewall.XXXXXX
|
|
;;
|
|
None)
|
|
rm -f /tmp/shorewall-$$
|
|
> /tmp/shorewall-$$ && echo /tmp/shorewall-$$
|
|
;;
|
|
*)
|
|
echo " ERROR:Internal error in mktempfile" >&2
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
#
|
|
# create a temporary directory
|
|
#
|
|
mktempdir() {
|
|
|
|
[ -z "$MKTEMP" ] && find_mktemp
|
|
|
|
case "$MKTEMP" in
|
|
STD)
|
|
mktemp -td shorewall.XXXXXX
|
|
;;
|
|
None|BSD)
|
|
#
|
|
# Not all versions of the BSD mktemp support the -d option under Linux
|
|
#
|
|
mkdir /tmp/shorewall-$$ && chmod 700 /tmp/shorewall-$$ && echo /tmp/shorewall-$$
|
|
;;
|
|
*)
|
|
echo " ERROR:Internal error in mktempdir" >&2
|
|
;;
|
|
esac
|
|
}
|
|
|
|
#
|
|
# Read a file and handle "INCLUDE" directives
|
|
#
|
|
|
|
read_file() # $1 = file name, $2 = nest count
|
|
{
|
|
local first rest
|
|
|
|
if [ -f $1 ]; then
|
|
while read first rest; do
|
|
if [ "x$first" = "xINCLUDE" ]; then
|
|
if [ $2 -lt 4 ]; then
|
|
read_file $(find_file $(expand ${rest%#*})) $(($2 + 1))
|
|
else
|
|
echo " WARNING: INCLUDE in $1 ignored (nested too deeply)" >&2
|
|
fi
|
|
else
|
|
echo "$first $rest"
|
|
fi
|
|
done < $1
|
|
else
|
|
[ -n "$terminator" ] && $terminator "No such file: $1"
|
|
echo "Warning -- No such file: $1"
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Function for including one file into another
|
|
#
|
|
INCLUDE() {
|
|
. $(find_file $(expand $@))
|
|
}
|
|
|
|
#
|
|
# Strip comments and blank lines from a file and place the result in the
|
|
# temporary directory
|
|
#
|
|
strip_file() # $1 = Base Name of the file, $2 = Full Name of File (optional)
|
|
{
|
|
local fname
|
|
|
|
[ $# = 1 ] && fname=$(find_file $1) || fname=$2
|
|
|
|
if [ -f $fname ]; then
|
|
read_file $fname 0 | cut -d'#' -f1 | grep -v '^[[:space:]]*$' > $TMP_DIR/$1
|
|
else
|
|
> $TMP_DIR/$1
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Note: The following set of IP address manipulation functions have anomalous
|
|
# behavior when the shell only supports 32-bit signed arithmatic and
|
|
# the IP address is 128.0.0.0 or 128.0.0.1.
|
|
#
|
|
#
|
|
# So that emacs doesn't get lost, we use $LEFTSHIFT rather than <<
|
|
#
|
|
LEFTSHIFT='<<'
|
|
|
|
#
|
|
# Convert an IP address in dot quad format to an integer
|
|
#
|
|
decodeaddr() {
|
|
local x
|
|
local temp=0
|
|
local ifs=$IFS
|
|
|
|
IFS=.
|
|
|
|
for x in $1; do
|
|
temp=$(( $(( $temp $LEFTSHIFT 8 )) | $x ))
|
|
done
|
|
|
|
echo $temp
|
|
|
|
IFS=$ifs
|
|
}
|
|
|
|
#
|
|
# convert an integer to dot quad format
|
|
#
|
|
encodeaddr() {
|
|
addr=$1
|
|
local x
|
|
local y=$(($addr & 255))
|
|
|
|
for x in 1 2 3 ; do
|
|
addr=$(($addr >> 8))
|
|
y=$(($addr & 255)).$y
|
|
done
|
|
|
|
echo $y
|
|
}
|
|
|
|
#
|
|
# Enumerate the members of an IP range -- When using a shell supporting only
|
|
# 32-bit signed arithmetic, the range cannot span 128.0.0.0.
|
|
#
|
|
# Comes in two flavors:
|
|
#
|
|
# ip_range() - produces a mimimal list of network/host addresses that spans
|
|
# the range.
|
|
#
|
|
# ip_range_explicit() - explicitly enumerates the range.
|
|
#
|
|
ip_range() {
|
|
local first last l x y z vlsm
|
|
|
|
case $1 in
|
|
!*)
|
|
#
|
|
# Let iptables complain if it's a range
|
|
#
|
|
echo $1
|
|
return
|
|
;;
|
|
[0-9]*.*.*.*-*.*.*.*)
|
|
;;
|
|
*)
|
|
echo $1
|
|
return
|
|
;;
|
|
esac
|
|
|
|
first=$(decodeaddr ${1%-*})
|
|
last=$(decodeaddr ${1#*-})
|
|
|
|
if [ $first -gt $last ]; then
|
|
fatal_error "Invalid IP address range: $1"
|
|
fi
|
|
|
|
l=$(( $last + 1 ))
|
|
|
|
while [ $first -le $last ]; do
|
|
vlsm=
|
|
x=31
|
|
y=2
|
|
z=1
|
|
|
|
while [ $(( $first % $y )) -eq 0 -a $(( $first + $y )) -le $l ]; do
|
|
vlsm=/$x
|
|
x=$(( $x - 1 ))
|
|
z=$y
|
|
y=$(( $y * 2 ))
|
|
done
|
|
|
|
echo $(encodeaddr $first)$vlsm
|
|
first=$(($first + $z))
|
|
done
|
|
}
|
|
|
|
ip_range_explicit() {
|
|
local first last
|
|
|
|
case $1 in
|
|
[0-9]*.*.*.*-*.*.*.*)
|
|
;;
|
|
*)
|
|
echo $1
|
|
return
|
|
;;
|
|
esac
|
|
|
|
first=$(decodeaddr ${1%-*})
|
|
last=$(decodeaddr ${1#*-})
|
|
|
|
if [ $first -gt $last ]; then
|
|
fatal_error "Invalid IP address range: $1"
|
|
fi
|
|
|
|
while [ $first -le $last ]; do
|
|
echo $(encodeaddr $first)
|
|
first=$(($first + 1))
|
|
done
|
|
}
|
|
|
|
#
|
|
# Netmask from CIDR
|
|
#
|
|
ip_netmask() {
|
|
local vlsm=${1#*/}
|
|
|
|
[ $vlsm -eq 0 ] && echo 0 || echo $(( -1 $LEFTSHIFT $(( 32 - $vlsm )) ))
|
|
}
|
|
|
|
#
|
|
# Network address from CIDR
|
|
#
|
|
ip_network() {
|
|
local decodedaddr=$(decodeaddr ${1%/*})
|
|
local netmask=$(ip_netmask $1)
|
|
|
|
echo $(encodeaddr $(($decodedaddr & $netmask)))
|
|
}
|
|
|
|
#
|
|
# The following hack is supplied to compensate for the fact that many of
|
|
# the popular light-weight Bourne shell derivatives don't support XOR ("^").
|
|
#
|
|
|
|
ip_broadcast() {
|
|
local x=$(( 32 - ${1#*/} ))
|
|
|
|
[ $x -eq 0 ] && echo -1 || echo $(( $(( 1 $LEFTSHIFT $x )) - 1 ))
|
|
}
|
|
|
|
#
|
|
# Calculate broadcast address from CIDR
|
|
#
|
|
broadcastaddress() {
|
|
local decodedaddr=$(decodeaddr ${1%/*})
|
|
local netmask=$(ip_netmask $1)
|
|
local broadcast=$(ip_broadcast $1)
|
|
|
|
echo $(encodeaddr $(( $(($decodedaddr & $netmask)) | $broadcast )))
|
|
}
|
|
|
|
#
|
|
# Test for network membership
|
|
#
|
|
in_network() # $1 = IP address, $2 = CIDR network
|
|
{
|
|
local netmask=$(ip_netmask $2)
|
|
|
|
test $(( $(decodeaddr $1) & $netmask)) -eq $(( $(decodeaddr ${2%/*}) & $netmask ))
|
|
}
|
|
|
|
#
|
|
# Netmask to VLSM
|
|
#
|
|
ip_vlsm() {
|
|
local mask=$(decodeaddr $1)
|
|
local vlsm=0
|
|
local x=$(( 128 $LEFTSHIFT 24 )) # 0x80000000
|
|
|
|
while [ $(( $x & $mask )) -ne 0 ]; do
|
|
[ $mask -eq $x ] && mask=0 || mask=$(( $mask $LEFTSHIFT 1 )) # Not all shells shift 0x80000000 left properly.
|
|
vlsm=$(($vlsm + 1))
|
|
done
|
|
|
|
if [ $(( $mask & 2147483647 )) -ne 0 ]; then # 2147483647 = 0x7fffffff
|
|
echo "Invalid net mask: $1" >&2
|
|
else
|
|
echo $vlsm
|
|
fi
|
|
}
|
|
|
|
|
|
#
|
|
# Chain name base for an interface -- replace all periods with underscores in the passed name.
|
|
# The result is echoed (less trailing "+").
|
|
#
|
|
chain_base() #$1 = interface
|
|
{
|
|
local c=${1%%+}
|
|
|
|
while true; do
|
|
case $c in
|
|
*.*)
|
|
c="${c%.*}_${c##*.}"
|
|
;;
|
|
*-*)
|
|
c="${c%-*}_${c##*-}"
|
|
;;
|
|
*%*)
|
|
c="${c%\%*}_${c##*%}"
|
|
;;
|
|
*)
|
|
echo ${c:=common}
|
|
return
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
#
|
|
# Loosly Match the name of an interface
|
|
#
|
|
|
|
if_match() # $1 = Name in interfaces file - may end in "+"
|
|
# $2 = Full interface name - may also end in "+"
|
|
{
|
|
local pattern=${1%+}
|
|
|
|
case $1 in
|
|
*+)
|
|
test "x$(echo $2 | truncate ${#pattern} )" = "x${pattern}"
|
|
;;
|
|
*)
|
|
test "x$1" = "x$2"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
#
|
|
# Find the value 'dev' in the passed arguments then echo the next value
|
|
#
|
|
|
|
find_device() {
|
|
while [ $# -gt 1 ]; do
|
|
[ "x$1" = xdev ] && echo $2 && return
|
|
shift
|
|
done
|
|
}
|
|
|
|
#
|
|
# Find the value 'via' in the passed arguments then echo the next value
|
|
#
|
|
|
|
find_gateway() {
|
|
while [ $# -gt 1 ]; do
|
|
[ "x$1" = xvia ] && echo $2 && return
|
|
shift
|
|
done
|
|
}
|
|
|
|
#
|
|
# Find the value 'peer' in the passed arguments then echo the next value up to
|
|
# "/"
|
|
#
|
|
|
|
find_peer() {
|
|
while [ $# -gt 1 ]; do
|
|
[ "x$1" = xpeer ] && echo ${2%/*} && return
|
|
shift
|
|
done
|
|
}
|
|
|
|
#
|
|
# Find the interfaces that have a route to the passed address - the default
|
|
# route is not used.
|
|
#
|
|
|
|
find_rt_interface() {
|
|
ip route ls | while read addr rest; do
|
|
case $addr in
|
|
*/*)
|
|
in_network ${1%/*} $addr && echo $(find_device $rest)
|
|
;;
|
|
default)
|
|
;;
|
|
*)
|
|
if [ "$addr" = "$1" -o "$addr/32" = "$1" ]; then
|
|
echo $(find_device $rest)
|
|
fi
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
#
|
|
# Try to find the gateway through an interface looking for 'nexthop'
|
|
|
|
find_nexthop() # $1 = interface
|
|
{
|
|
echo $(find_gateway `ip route ls | grep "[[:space:]]nexthop.* $1"`)
|
|
}
|
|
|
|
#
|
|
# Find the default route's interface
|
|
#
|
|
find_default_interface() {
|
|
ip route ls | while read first rest; do
|
|
[ "$first" = default ] && echo $(find_device $rest) && return
|
|
done
|
|
}
|
|
|
|
#
|
|
# Echo the name of the interface(s) that will be used to send to the
|
|
# passed address
|
|
#
|
|
|
|
find_interface_by_address() {
|
|
local dev="$(find_rt_interface $1)"
|
|
local first rest
|
|
|
|
[ -z "$dev" ] && dev=$(find_default_interface)
|
|
|
|
[ -n "$dev" ] && echo $dev
|
|
}
|
|
|
|
#
|
|
# Find interface addresses--returns the set of addresses assigned to the passed
|
|
# device
|
|
#
|
|
find_interface_addresses() # $1 = interface
|
|
{
|
|
ip -f inet addr show $1 | grep inet | sed 's/inet //;s/\/.*//;s/ peer.*//'
|
|
}
|