forked from extern/shorewall_code
0c1beb50ae
Signed-off-by: Tom Eastep <teastep@shorewall.net>
473 lines
8.7 KiB
Plaintext
473 lines
8.7 KiB
Plaintext
#
|
|
# Shorewall 4.5 -- /usr/share/shorewall/lib.base
|
|
#
|
|
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
#
|
|
# (c) 1999-2012 - Tom Eastep (teastep@shorewall.net)
|
|
#
|
|
# Complete documentation is available at http://shorewall.net
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of Version 2 of the GNU General Public License
|
|
# as published by the Free Software Foundation.
|
|
#
|
|
# 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, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
#
|
|
# This library contains the code common to all Shorewall components.
|
|
#
|
|
# - It is loaded by /sbin/shorewall.
|
|
# - It is released as part of Shorewall[6] Lite where it is used by /sbin/shorewall[6]-lite
|
|
# and /usr/share/shorewall[6]-lite/shorecap.
|
|
#
|
|
|
|
SHOREWALL_LIBVERSION=40500
|
|
SHOREWALL_CAPVERSION=40501
|
|
|
|
[ -n "${g_program:=shorewall}" ]
|
|
|
|
case $g_program in
|
|
shorewall)
|
|
SHAREDIR=/usr/share/shorewall
|
|
CONFDIR=/etc/shorewall
|
|
g_product="Shorewall"
|
|
g_family=4
|
|
g_tool=
|
|
g_basedir=/usr/share/shorewall
|
|
g_lite=
|
|
;;
|
|
shorewall6)
|
|
SHAREDIR=/usr/share/shorewall6
|
|
CONFDIR=/etc/shorewall6
|
|
g_product="Shorewall6"
|
|
g_family=6
|
|
g_tool=
|
|
g_basedir=/usr/share/shorewall
|
|
g_lite=
|
|
;;
|
|
shorewall-lite)
|
|
SHAREDIR=/usr/share/shorewall-lite
|
|
CONFDIR=/etc/shorewall-lite
|
|
g_product="Shorewall Lite"
|
|
g_family=4
|
|
g_tool=iptables
|
|
g_basedir=/usr/share/shorewall-lite
|
|
g_lite=Yes
|
|
;;
|
|
shorewall6-lite)
|
|
SHAREDIR=/usr/share/shorewall6-lite
|
|
CONFDIR=/etc/shorewall6-lite
|
|
g_product="Shorewall6 Lite"
|
|
g_family=6
|
|
g_tool=ip6tables
|
|
g_basedir=/usr/share/shorewall6-lite
|
|
g_lite=Yes
|
|
;;
|
|
esac
|
|
|
|
#
|
|
# 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
|
|
}
|
|
|
|
#
|
|
# Call this function to assert mutual exclusion with Shorewall. If you invoke the
|
|
# /sbin/shorewall program while holding mutual exclusion, 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
|
|
try=0
|
|
local lockf
|
|
lockf=${LOCKFILE:=${VARDIR}/lock}
|
|
local lockpid
|
|
|
|
MUTEX_TIMEOUT=${MUTEX_TIMEOUT:-60}
|
|
|
|
if [ $MUTEX_TIMEOUT -gt 0 ]; then
|
|
|
|
[ -d ${VARDIR} ] || mkdir -p ${VARDIR}
|
|
|
|
if [ -f $lockf ]; then
|
|
lockpid=`cat ${lockf} 2> /dev/null`
|
|
if [ -z "$lockpid" -o $lockpid = 0 ]; then
|
|
rm -f ${lockf}
|
|
error_message "WARNING: Stale lockfile ${lockf} removed"
|
|
elif ! qt ps p ${lockpid}; then
|
|
rm -f ${lockf}
|
|
error_message "WARNING: Stale lockfile ${lockf} from pid ${lockpid} removed"
|
|
fi
|
|
fi
|
|
|
|
if qt mywhich lockfile; then
|
|
lockfile -${MUTEX_TIMEOUT} -r1 ${lockf}
|
|
chmod u+w ${lockf}
|
|
echo $$ > ${lockf}
|
|
chmod u-w ${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 mutual exclusion
|
|
#
|
|
mutex_off()
|
|
{
|
|
rm -f ${LOCKFILE:=${VARDIR}/lock}
|
|
}
|
|
|
|
[ -z "$LEFTSHIFT" ] && . /usr/share/shorewall/lib.common
|
|
|
|
#
|
|
# 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
|
|
}
|
|
|
|
#
|
|
# 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=${SHAREDIR}/configpath
|
|
if [ -z "$CONFIG_PATH" ]; then
|
|
[ -f $F ] || { echo " ERROR: $F does not exist"; exit 2; }
|
|
. $F
|
|
fi
|
|
|
|
if [ -n "$g_shorewalldir" ]; then
|
|
[ "${CONFIG_PATH%%:*}" = "$g_shorewalldir" ] || CONFIG_PATH=$g_shorewalldir:$CONFIG_PATH
|
|
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 how to do "echo -e"
|
|
#
|
|
|
|
find_echo() {
|
|
local result
|
|
|
|
result=$(echo "a\tb")
|
|
[ ${#result} -eq 3 ] && { echo echo; return; }
|
|
|
|
result=$(echo -e "a\tb")
|
|
[ ${#result} -eq 3 ] && { echo "echo -e"; return; }
|
|
|
|
result=$(which echo)
|
|
[ -n "$result" ] && { echo "$result -e"; return; }
|
|
|
|
echo echo
|
|
}
|
|
|
|
# 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 /tmp/shorewall.XXXXXX
|
|
;;
|
|
STD)
|
|
mktemp -t shorewall.XXXXXX
|
|
;;
|
|
None)
|
|
rm -f /tmp/shorewall-$$
|
|
> /tmp/shorewall-$$ && echo /tmp/shorewall-$$
|
|
;;
|
|
*)
|
|
error_message "ERROR:Internal error in mktempfile"
|
|
;;
|
|
esac
|
|
fi
|
|
}
|