#!/bin/ksh
####################################################################
#
# pf_admin Ver: 04.0100
#
# Package: None
#
# PreReq: None
#
# 06/24/09 04.0100 Chgs:
# - Added logic to handle prot of 'both'
# 06/24/09 04.0000 Chgs:
# - Rewrote
# - added table logic
# 01/09/09 03.0000 Chgs:
# - Moved calls to Add_Rule
# - Log rules to output file
# 05/02/08 02.0502 Added Remote Port ot logging
# 01/10/08 02.0501 Shortened log-prefix
# 01/10/08 02.0500 Log port forwards
# 01/10/08 02.0401 Make prot case insensitive
# 01/10/08 02.0400 Figure out default EXTDEV
# 11/15/06 02.0300 Massaged a bit
# 04/08/03 02.02 Add forwarding rule
# 12/13/02 02.01 Added "-if" parm & fixed syntax error
# 04/18/02 02.00 Rewrote for iptables
#
####################################################################
[ -x /etc/path ] && . /etc/path
[ -x /etc/env ] && . /etc/env
VER=$(grep "Ver:" $0|head -1|sed -e 's/^.*Ver: //g')
# --------------------------------------------------
# Standard Dir locations (for use by install pkg)
# --------------------------------------------------
# --- bindir
#BINDIR=B_Z_INXDIR
BINDIR=/sysadmin/bin
#
# --- configdir
#DATADIR=D_Z_ATAXDIR
DATADIR=/sysadmin/data
#
# --- logdir
#LOGDIR=L_Z_OGXDIR
LOGDIR=/sysadmin/logs
#
# --- reportdir
#RPTDIR=R_Z_PTXDIR
RPTDIR=/sysadmin/reports
PATH=$PATH:$BINDIR:/usr/local/bin # Std paths
#-----------------------------------------------------------
# usage
#-----------------------------------------------------------
function usage
{
echo "\nVer: $VER"
echo "Usage: pf_admin "
echo " {-tbl <file containing rules> |"
echo " -s <server to forward to>"
echo " -lp <local port on firewall>"
echo " [-rp <remote port> (def=local port)]"
echo " [-c <external client> (def=$ECLIENT)]"
echo " [-p {TCP|tcp|UDP|udp} (def=$PROT)]"
echo " }"
echo ""
echo " [-if <interface to listen on (def=$EXTDEV)"
echo " [-f (flush all)]"
echo " [-l (list current)]"
echo " [-q (quiet)]"
echo ""
echo " [-o <output file for rules> (Def $PFRULE_FILE)"
echo " [-app (Append to output file instead of overwrite)]"
echo ""
echo " [-prev]"
echo " [-ver]"
echo ""
ECHO="off";all_done 4
}
#-----------------------------------------------------------
# log_it
#-----------------------------------------------------------
function log_it
{
DD=$(date +"%D %H:%M:%S")
[ "$ECHO" = "on" ] && echo "$DD > $*"
[ "$LOGIT" = "on" ] && echo "$DD > $*" >> $LOGFILE
}
#-----------------------------------------------------------
# trace_it
#-----------------------------------------------------------
function trace_it
{
if [ "$TRACE" = "on" ];then log_it "<TRACE> $*";fi
}
#-----------------------------------------------------------
# debug_it
#-----------------------------------------------------------
function debug_it
{
if [ "$DEBUG" = "on" ];then log_it "<<DEBUG>> $*";fi
}
#-----------------------------------------------------------
# echo_it
#-----------------------------------------------------------
function echo_it
{
[ "$SILENT" != "on" ] && echo "$*"
log_it "$*"
}
#-----------------------------------------------------------
# get_tmpfile
#-----------------------------------------------------------
function get_tmpfile
{
integer TMP_CNTR=0
while [ -f $TMPDIR/${TMPFILE}${TMP_CNTR}.$$ ];do TMP_CNTR=$TMP_CNTR+1;done
touch $TMPDIR/${TMPFILE}${TMP_CNTR}.$$
echo $TMPDIR/${TMPFILE}${TMP_CNTR}.$$
}
#-----------------------------------------------------------
# free_tmpfile
#-----------------------------------------------------------
function free_tmpfile
{
rm $* 2>/dev/null
}
#-----------------------------------------------------------
# abend
#-----------------------------------------------------------
function abend
{
echo "\n$*\n"
ECHO="off";LOGIT="off"
usage
}
#-----------------------------------------------------------
# abend_nou
#-----------------------------------------------------------
function abend_nou
{
echo "\n$*\n"
ECHO="off";LOGIT="off"
all_done 12
}
#-----------------------------------------------------------
# all_done
#-----------------------------------------------------------
function all_done
{
#
# --- Clean up tmp files
#
rm $TMPDIR/$TMPFILE*.$$ 2> /dev/null
RC=0;[ $# -ne 0 ] && RC=$1
log_it ""
log_it "Done: RC=$RC"
exit $RC
}
#-----------------------------------------------------------
# do_cmd
#-----------------------------------------------------------
function do_cmd
{
trace_it "$0: Entry"
THE_CMD="$*"
debug_it "$THE_CMD"
if [ "$PREV" = "off" ];then
#$THE_CMD;STATUS=$?
#eval $THE_CMD 1>dev/null 2>&1;STATUS=$?
#eval $THE_CMD;STATUS=$?
MSG=$(eval $THE_CMD);STATUS=$?
else
log_it "[PREV] CMD: $THE_CMD"
STATUS=0
fi
trace_it "$0: Exit"
return $STATUS
}
#-----------------------------------------------------------
# mail_it
#-----------------------------------------------------------
function mail_it
{
trace_it "$0: Entry"
[ "$MAIL" != "on" ] && return
log_it "Mailing report to $MAILTO"
SUBJ="pf_admin report from $(hostname)"
if [ $RC -eq 0 ];then
SUBJ="OK - $SUBJ - $(hostname)"
else
SUBJ="ERROR - $SUBJ - $(hostname) RC=$RC"
fi
log_it "+ SUBJ: $SUBJ"
log_it "+ BODY: \n$(cat $MAILFILE)"
cat $MAILFILE | mail -s "$SUBJ" $MAILTO
free_tmpfile $MAIL_FILE
trace_it "$0: Exit"
}
#-----------------------------------------------------------
# initialize
# - Sets $OS, $OSF
# - Sets IPTABLES
# - Gest default ext device
#-----------------------------------------------------------
function initialize
{
trace_it "$0: Entry"
# --- Get OS Flavor
OS=$(uname);OSF=$OS
if [ "$OS" = "Linux" ];then
for F in redhat fedora SuSE; do [ -f /etc/${F}-release ] && OSF="$F";done
fi
# --- Set iptables
case $OSF in
"redhat"|"fedora") IPTABLES="/sbin/iptables";;
"SuSE") IPTABLES="/usr/sbin/iptables";;
esac
# --- Default net device
EXTDEV=$(netstat -rn|grep "^0.0.0.0"|awk '{print $8}')
trace_it "$0: Exit"
}
#-----------------------------------------------------------
# initialize2
# - Sets $PMSG
# - Gets $EXTIP
# - Prep PFRULE_FILE
#-----------------------------------------------------------
function initialize2
{
trace_it "$0: Entry"
# --- set PMSG
PMSG="[PREV]";[ "$PREV" = "off" ] && PMSG=""
# --- Get IP of $EXTDEV
EXTIP=$(ifconfig $EXTDEV | grep "inet addr:"|awk -F: '{print $2}'|awk '{print $1}')
# --- Prep logged rule file
if [ "$PREV" = "off" -a "$ACTN" != "LIST" ];then
[ "$APPEND" = "off" ] && > $PFRULE_FILE
chown 0.0 $PFRULE_FILE;chmod 0700 $PFRULE_FILE
fi
trace_it "$0: Exit"
}
#-----------------------------------------------
# log_rule
#-----------------------------------------------
function log_rule
{
[ "$LOG_PFRULES" != "on" ] && return
echo "$*" >> $PFRULE_FILE
}
#-----------------------------------------------
# Add_Rule
#-----------------------------------------------
function Add_Rule
{
R="$*"
do_cmd "$IPTABLES $R"
[ "$PREV" != "on" ] && log_rule $IPTABLES $R
}
#-----------------------------------------------------------
# list_rules
#
# Lists current forwarding rules
#-----------------------------------------------------------
function list_rules
{
trace_it "$0: Entry"
do_cmd "$IPTABLES -nvL PREROUTING -t nat"
[ "$PREV" != "on" ] && echo_it "$MSG"
trace_it "$0: Exit"
}
#-----------------------------------------------------------
# flush_rules
#-----------------------------------------------------------
function flush_rules
{
trace_it "$0: Entry"
echo_it "...Flushing...$PMSG"
Add_Rule -F PREROUTING -t nat
trace_it "$0: Exit"
}
#-----------------------------------------------------------
# add_single_rule
#
# Expects this to be set:
# - $1 : External client (ie originating traffic)
# - $2 : Client to forward traffic to
# - $3 : Protocol
# - $4 : Source port on external client
# - $5 : Dest port on forward-to client
#-----------------------------------------------------------
function add_single_rule
{
trace_it "$0: Entry [$*]"
_srcIP="$1"
_dstIP="$2"
_prot="$3"
_lp="$4"
_rp="$5"
# --- Get _rp if not explicitly set. Correct for ranges
[ -z "$_rp" ] && _rp=$_lp
_rp=$(echo $_rp|sed -e 's/:/-/g')
log_it "";log_it "Adding Single rule"
log_it "_srcIP : $_srcIP"
log_it "_dstIP : $_dstIP"
log_it "_prot : $_prot"
log_it "_lp : $_lp"
log_it "_rp : $_rp"
_effective_prots="$_prot";[ "$_prot" = "both" ] && _effective_prots="tcp udp"
# --- loop in case of multiple protocols
for _prot in $_effective_prots; do
echo_it "Redirecting $_prot traffic from $_srcIP on [$EXTDEV]$EXTIP:$_lp to $_dstIP:$_rp $PMSG\n"
# --- Log-prefix must be <= 29
LogP="PortFW:$_lp:$_dstIP:$_rp "
if [ $(echo $LogP|wc -c) -gt 29 ];then
LogP=$(expr substr $LogP 1 29)
fi
#
Add_Rule -t nat -A PREROUTING -i $EXTDEV -p $_prot -s $_srcIP --dport $_lp -j LOG --log-prefix \"$LogP\"
Add_Rule -A FORWARD -p $_prot --dport $_lp -s $_srcIP -j ACCEPT
Add_Rule -t nat -A POSTROUTING -s $_srcIP -j MASQUERADE
Add_Rule -t nat -A PREROUTING -i $EXTDEV -p $_prot -s $_srcIP -j DNAT \
--dport $_lp --to-destination $_dstIP:$_rp
done
trace_it "$0: Exit"
}
#-----------------------------------------------------------
# process_tbl
#
# Processes stanzas in $PORT_FORWARDS, assuming this format:
#
# ALLOWED_HOSTS|PROT|INBOUND_PORT:n|OUTBOUND_PORT-n|OUTBOUND_SRVR
#-----------------------------------------------------------
function process_tbl
{
trace_it "$0: Entry"
[ ! -e "$TBL" ] && abend_nou "+ $TBL not found..."
log_it "";log_it "Processing $TBL"
. $TBL
for _stanza in $PORT_FORWARDS;do
log_it "+ $_stanza"
_stanza=$(echo $_stanza|sed -e 's/|/ /g');set $_stanza
add_single_rule "$1" "$5" "$2" "$3" "$4"
done
trace_it "$0: Exit"
}
...