forked from extern/shorewall_code
5d58b5da72
Signed-off-by: Tom Eastep <teastep@shorewall.net>
448 lines
8.0 KiB
Plaintext
448 lines
8.0 KiB
Plaintext
#
|
|
# Shorewall 5.2 -- /usr/share/shorewall/lib.core
|
|
#
|
|
# (c) 1999-2017 - Tom Eastep (teastep@shorewall.net)
|
|
#
|
|
# Complete documentation is available at https://shorewall.org
|
|
#
|
|
# This program is part of Shorewall.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by the
|
|
# Free Software Foundation, either version 2 of the license or, at your
|
|
# option, any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# This library contains the code common to all Shorewall components except the
|
|
# generated scripts.
|
|
#
|
|
|
|
SHOREWALL_LIBVERSION=50108
|
|
|
|
#
|
|
# Fatal Error
|
|
#
|
|
fatal_error() # $@ = Message
|
|
{
|
|
echo " ERROR: $@" >&2
|
|
exit 2
|
|
}
|
|
|
|
setup_product_environment() { # $1 = if non-empty, source shorewallrc again now that we have the correct product
|
|
g_basedir=${SHAREDIR}/shorewall
|
|
|
|
g_sharedir="$SHAREDIR"/$PRODUCT
|
|
g_confdir="$CONFDIR"/$PRODUCT
|
|
|
|
case $PRODUCT in
|
|
shorewall)
|
|
g_product="Shorewall"
|
|
g_family=4
|
|
g_tool=iptables
|
|
g_lite=
|
|
;;
|
|
shorewall6)
|
|
g_product="Shorewall6"
|
|
g_family=6
|
|
g_tool=ip6tables
|
|
g_lite=
|
|
;;
|
|
shorewall-lite)
|
|
g_product="Shorewall Lite"
|
|
g_family=4
|
|
g_tool=iptables
|
|
g_lite=Yes
|
|
;;
|
|
shorewall6-lite)
|
|
g_product="Shorewall6 Lite"
|
|
g_family=6
|
|
g_tool=ip6tables
|
|
g_lite=Yes
|
|
;;
|
|
*)
|
|
fatal_error "Unknown PRODUCT ($PRODUCT)"
|
|
;;
|
|
esac
|
|
|
|
[ -f ${SHAREDIR}/${PRODUCT}/version ] || fatal_error "$g_product does not appear to be installed on this system"
|
|
#
|
|
# We need to do this again, now that we have the correct product
|
|
#
|
|
[ -n "$1" ] && . ${g_basedir}/shorewallrc
|
|
|
|
if [ -z "${VARLIB}" ]; then
|
|
VARLIB=${VARDIR}
|
|
VARDIR=${VARLIB}/${PRODUCT}
|
|
elif [ -z "${VARDIR}" ]; then
|
|
VARDIR="${VARLIB}/${PRODUCT}"
|
|
fi
|
|
}
|
|
|
|
set_default_product() {
|
|
case $(basename $0) in
|
|
shorewall6)
|
|
PRODUCT=shorewall6
|
|
;;
|
|
shorewall4)
|
|
PRODUCT=shorewall
|
|
;;
|
|
shorewall-lite)
|
|
PRODUCT=shorewall-lite
|
|
;;
|
|
shorewall6-lite)
|
|
PRODUCT=shorewall6-lite
|
|
;;
|
|
*)
|
|
if [ -f ${g_basedir}/version ]; then
|
|
PRODUCT=shorewall
|
|
elif [ -f ${SHAREDIR}/shorewall-lite/version ]; then
|
|
PRODUCT=shorewall-lite
|
|
elif [ -f ${SHAREDIR}/shorewall6-lite/version ]; then
|
|
PRODUCT=shorewall6-lite
|
|
else
|
|
fatal_error "No Shorewall firewall product is installed"
|
|
fi
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Not configured Error
|
|
#
|
|
not_configured_error() # $@ = Message
|
|
{
|
|
echo " ERROR: $@" >&2
|
|
exit 6
|
|
}
|
|
|
|
#
|
|
# Conditionally produce message
|
|
#
|
|
progress_message() # $* = Message
|
|
{
|
|
local timestamp
|
|
timestamp=
|
|
|
|
if [ $VERBOSITY -gt 1 ]; then
|
|
[ -n "$g_timestamp" ] && timestamp="$(date +%H:%M:%S) "
|
|
echo "${timestamp}$@"
|
|
fi
|
|
}
|
|
|
|
progress_message2() # $* = Message
|
|
{
|
|
local timestamp
|
|
timestamp=
|
|
|
|
if [ $VERBOSITY -gt 0 ]; then
|
|
[ -n "$g_timestamp" ] && timestamp="$(date +%H:%M:%S) "
|
|
echo "${timestamp}$@"
|
|
fi
|
|
}
|
|
|
|
progress_message3() # $* = Message
|
|
{
|
|
local timestamp
|
|
timestamp=
|
|
|
|
if [ $VERBOSITY -ge 0 ]; then
|
|
[ -n "$g_timestamp" ] && timestamp="$(date +%H:%M:%S) "
|
|
echo "${timestamp}$@"
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Undo the effect of 'separate_list()'
|
|
#
|
|
combine_list()
|
|
{
|
|
local f
|
|
local o
|
|
o=
|
|
|
|
for f in $* ; do
|
|
o="${o:+$o,}$f"
|
|
done
|
|
|
|
echo $o
|
|
}
|
|
|
|
#
|
|
# Validate an IP address
|
|
#
|
|
valid_address() {
|
|
local x
|
|
local y
|
|
local ifs
|
|
ifs=$IFS
|
|
|
|
IFS=.
|
|
|
|
for x in $1; do
|
|
case $x in
|
|
[0-9]|[0-9][0-9]|[1-2][0-9][0-9])
|
|
[ $x -lt 256 ] || { IFS=$ifs; return 2; }
|
|
;;
|
|
*)
|
|
IFS=$ifs
|
|
return 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
IFS=$ifs
|
|
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# Miserable Hack to work around broken BusyBox ash in OpenWRT
|
|
#
|
|
addr_comp() {
|
|
test $(bc <<EOF
|
|
$1 > $2
|
|
EOF
|
|
) -eq 1
|
|
|
|
}
|
|
|
|
#
|
|
# 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
|
|
local last
|
|
local l
|
|
local x
|
|
local y
|
|
local z
|
|
local 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 addr_comp $first $last; then
|
|
fatal_error "Invalid IP address range: $1"
|
|
fi
|
|
|
|
l=$(( $last + 1 ))
|
|
|
|
while addr_comp $l $first; do
|
|
vlsm=
|
|
x=31
|
|
y=2
|
|
z=1
|
|
|
|
while [ $(( $first % $y )) -eq 0 ] && ! addr_comp $(( $first + $y )) $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
|
|
local last
|
|
|
|
case $1 in
|
|
[0-9]*.*.*.*-*.*.*.*)
|
|
;;
|
|
*)
|
|
echo $1
|
|
return
|
|
;;
|
|
esac
|
|
|
|
first=$(decodeaddr ${1%-*})
|
|
last=$(decodeaddr ${1#*-})
|
|
|
|
if addr_comp $first $last; then
|
|
fatal_error "Invalid IP address range: $1"
|
|
fi
|
|
|
|
while ! addr_comp $first $last; do
|
|
echo $(encodeaddr $first)
|
|
first=$(($first + 1))
|
|
done
|
|
}
|
|
|
|
[ -z "$LEFTSHIFT" ] && . ${g_basedir}/lib.common
|
|
|
|
#
|
|
# Netmask to VLSM
|
|
#
|
|
ip_vlsm() {
|
|
local mask
|
|
mask=$(decodeaddr $1)
|
|
local vlsm
|
|
vlsm=0
|
|
local x
|
|
x=$(( 128 << 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
|
|
}
|
|
|
|
#
|
|
# Set default config path
|
|
#
|
|
ensure_config_path() {
|
|
local F
|
|
F=${g_sharedir}/configpath
|
|
if [ -z "$CONFIG_PATH" ]; then
|
|
[ -f $F ] || { echo " ERROR: $F does not exist"; exit 2; }
|
|
. $F
|
|
fi
|
|
|
|
if [ -n "$g_shorewalldir" ] && [ "${CONFIG_PATH%%:*}" = "$g_shorewalldir" ];then
|
|
case $CONFIG_PATH in
|
|
:*)
|
|
CONFIG_PATH=${g_shorewalldir}${CONFIG_PATH}
|
|
;;
|
|
*)
|
|
CONFIG_PATH=$g_shorewalldir:$CONFIG_PATH
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Get fully-qualified name of file
|
|
#
|
|
resolve_file() # $1 = file name
|
|
{
|
|
local pwd
|
|
pwd=$PWD
|
|
|
|
case $1 in
|
|
/*)
|
|
echo $1
|
|
;;
|
|
.)
|
|
echo $pwd
|
|
;;
|
|
./*)
|
|
echo ${pwd}${1#.}
|
|
;;
|
|
..)
|
|
cd ..
|
|
echo $PWD
|
|
cd $pwd
|
|
;;
|
|
../*)
|
|
cd ..
|
|
resolve_file ${1#../}
|
|
cd $pwd
|
|
;;
|
|
*)
|
|
echo $pwd/$1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# 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
|
|
mktemp=`mywhich 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-$$
|
|
;;
|
|
*)
|
|
error_message "ERROR:Internal error in mktempfile"
|
|
;;
|
|
esac
|
|
else
|
|
case "$MKTEMP" in
|
|
BSD)
|
|
mktemp ${TMPDIR:-/tmp}/shorewall.XXXXXX
|
|
;;
|
|
STD)
|
|
mktemp -t shorewall.XXXXXX
|
|
;;
|
|
None)
|
|
rm -f ${TMPDIR:-/tmp}/shorewall-$$
|
|
> ${TMPDIR:-}/shorewall-$$ && echo ${TMPDIR:-/tmp}/shorewall-$$
|
|
;;
|
|
*)
|
|
error_message "ERROR:Internal error in mktempfile"
|
|
;;
|
|
esac
|
|
fi
|
|
}
|