# # Shorewall 5.2 -- /usr/share/shorewall/lib.cli # # (c) 1999-2018 - 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 . # # This library contains the command processing code common to /sbin/shorewall[6] and # /sbin/shorewall[6]-lite. In Shorewall and Shorewall6, the lib.cli-std library is # loaded after this one and replaces some of the functions declared here. # SHOREWALL_CAPVERSION=50200 if [ -z "$g_basedir" ]; then # # This is modified by the installer when ${SHAREDIR} <> /usr/share # . /usr/share/shorewall/shorewallrc g_basedir=${SHAREDIR}/shorewall fi . ${g_basedir}/lib.core # # Issue an error message and die # startup_error() { echo " ERROR: $@" >&2 kill $$ exit 1 } only_root() { [ "$(id -u)" != 0 ] && fatal_error "The '$COMMAND' command may only be run by root" } # # Display a chain if it exists # showfirstchain() # $1 = name of chain { awk \ 'BEGIN {prnt=0; rslt=1; }; \ /^$/ { next; };\ /^Chain/ {if ( prnt == 1 ) { rslt=0; exit 0; }; };\ /Chain '$1'/ { prnt=1; }; \ { if (prnt == 1) print; };\ END { exit rslt; }' $TMPFILE } showchain() # $1 = name of chain { if [ "$firstchain" = "Yes" ]; then if showfirstchain $1; then firstchain= fi else awk \ 'BEGIN {prnt=0;};\ /^$|^ pkts/ { next; };\ /^Chain/ {if ( prnt == 1 ) exit; };\ /Chain '$1'/ { prnt=1; };\ { if (prnt == 1) print; }' $TMPFILE fi } # # Validate the value of RESTOREFILE # validate_restorefile() # $* = label { [ -n "$RESTOREFILE" ] || RESTOREFILE=restore case $RESTOREFILE in */*) error_message "ERROR: $@ must specify a simple file name: $RESTOREFILE" exit 2 ;; .safe|.try) ;; .*|NONE) error_message "ERROR: Reserved File Name: $RESTOREFILE" exit 2 ;; esac } # # Clear descriptor 1 if it is a terminal # clear_term() { [ -t 1 ] && clear } # # Delay $timeout seconds -- if we're running on a recent bash2 then allow # to terminate the delay # timed_read () { read -t $timeout foo 2> /dev/null test $? -eq 2 && sleep $timeout } # # Determine if 'syslogd -C' or logd -S is running # syslog_circular_buffer() { local pid local tty local flags local time local path local args local arg ps w 2> /dev/null | ( while read pid tty stat time path args; do case $path in syslogd|*/syslogd) for arg in $args; do case $arg in -C*) return 0 ;; esac done ;; logd|*/logd) for arg in $args; do case $arg in -S*) return 0 ;; esac done ;; esac done return 1 ) } setup_logread() { [ -z "$LOGFILE" ] && LOGFILE=/var/log/messages if syslog_circular_buffer; then LOGFILE=logread if qt mywhich tac; then g_logread="logread | tac" else g_logread="logread" fi elif [ "$LOGFILE" = "systemd" ]; then g_logread="journalctl -r" elif [ -r $LOGFILE ]; then if qt mywhich tac; then g_logread="tac $LOGFILE" else g_logread="cat $LOGFILE" fi else fatal_error "LOGFILE ($LOGFILE) does not exist or is not readable!" fi } # # Display the last $1 packets logged # packet_log() # $1 = number of messages { if qt mywhich tac; then if [ -n "$g_showmacs" -o $VERBOSITY -gt 2 ]; then if [ $g_family -eq 4 ]; then $g_logread | grep 'IN=.* OUT=.*SRC=.*\..*DST=' | head -n$1 | tac | sed 's/ kernel://; s/\[.*\] //' | sed s/" $host $LOGFORMAT"/" "/ else $g_logread | grep 'IN=.* OUT=.*SRC=.*:.*DST=' | head -n$1 | tac | sed -r 's/ kernel://; s/\[.*\] //; s/0000:/:/g; s/:::+/::/g; s/:0+/:/g' | sed s/" $host $LOGFORMAT"/" "/ fi elif [ $g_family -eq 4 ]; then $g_logread | grep 'IN=.* OUT=.*SRC=.*\..*DST=' | head -n$1 | tac | sed 's/ kernel://; s/MAC=.* SRC=/SRC=/; s/\[.*\] '// | sed s/" $host $LOGFORMAT"/" "/ else $g_logread | grep 'IN=.* OUT=.*SRC=.*:.*DST=' | head -n$1 | tac | sed -r 's/ kernel://; s/MAC=.* SRC=/SRC=/; s/\[.*\] //; s/0000:/:/g; s/:::+/::/g; s/:0+/:/g' | sed s/" $host $LOGFORMAT"/" "/ fi else if [ -n "$g_showmacs" -o $VERBOSITY -gt 2 ]; then if [ $g_family -eq 4 ]; then $g_logread | grep 'IN=.* OUT=.*SRC=.*\..*DST=' | tail -n$1 | sed 's/ kernel://; s/\[.*\] //' | sed s/" $host $LOGFORMAT"/" "/ else $g_logread | grep 'IN=.* OUT=.*SRC=.*:.*DST=' | tail -n$1 | sed -r 's/ kernel://; s/\[.*\] //; s/0000:/:/g; s/:::+/::/g; s/:0+/:/g' | sed s/" $host $LOGFORMAT"/" "/ fi elif [ $g_family -eq 4 ]; then $g_logread | grep 'IN=.* OUT=.*SRC=.*\..*DST=' | tail -n$1 | sed 's/ kernel://; s/MAC=.* SRC=/SRC=/; s/\[.*\] '// | sed s/" $host $LOGFORMAT"/" "/ else $g_logread | grep 'IN=.* OUT=.*SRC=.*:.*DST=' | tail -n$1 | sed -r 's/ kernel://; s/MAC=.* SRC=/SRC=/; s/\[.*\] //; s/0000:/:/g; s/:::+/::/g; s/:0+/:/g' | sed s/" $host $LOGFORMAT"/" "/ fi fi } search_log() # $1 = IP address to search for { if qt mywhich tac; then if [ -n "$g_showmacs" -o $VERBOSITY -gt 2 ]; then if [ $g_family -eq 4 ]; then $g_logread | grep 'IN=.* OUT=.*SRC=.*\..*DST=' | grep "$1" | tac | sed 's/ kernel://; s/\[.*\] //' | sed s/" $host $LOGFORMAT"/" "/ else $g_logread | grep 'IN=.* OUT=.*SRC=.*\..*DST=' | grep "$1" | tac | sed -r 's/ kernel://; s/\[.*\] //; s/0000:/:/g; s/:::+/::/g; s/:0+/:/g' | sed s/" $host $LOGFORMAT"/" "/ fi elif [ $g_family -eq 4 ]; then $g_logread | grep 'IN=.* OUT=.*SRC=.*\..*DST=' | grep "$1" | tac | sed 's/ kernel://; s/MAC=.* SRC=/SRC=/; s/\[.*\] '// | sed s/" $host $LOGFORMAT"/" "/ else $g_logread | grep 'IN=.* OUT=.*SRC=.*\..*DST=' | grep "$1" | tac | sed -r 's/ kernel://; s/MAC=.* SRC=/SRC=/; s/\[.*\] //; s/0000:/:/g; s/:::+/::/g; s/:0+/:/g' | sed s/" $host $LOGFORMAT"/" "/ fi else if [ -n "$g_showmacs" -o $VERBOSITY -gt 2 ]; then if [ $g_family -eq 4 ]; then $g_logread | grep 'IN=.* OUT=.*SRC=.*\..*DST=' | grep "$1" | sed 's/ kernel://; s/\[.*\] //' | sed s/" $host $LOGFORMAT"/" "/ else $g_logread | grep 'IN=.* OUT=.*SRC=.*\..*DST=' | grep "$1" | sed -r 's/ kernel://; s/\[.*\] //; s/0000:/:/g; s/:::+/::/g; s/:0+/:/g' | sed s/" $host $LOGFORMAT"/" "/ fi elif [ $g_family -eq 4 ]; then $g_logread | grep 'IN=.* OUT=.*SRC=.*\..*DST=' | grep "$1" | sed 's/ kernel://; s/MAC=.* SRC=/SRC=/; s/\[.*\] '// | sed s/" $host $LOGFORMAT"/" "/ else $g_logread | grep 'IN=.* OUT=.*SRC=.*\..*DST=' | grep "$1" | sed -r 's/ kernel://; s/MAC=.* SRC=/SRC=/; s/\[.*\] //; s/0000:/:/g; s/:::+/::/g; s/:0+/:/g' | sed s/" $host $LOGFORMAT"/" "/ fi fi } # # Show traffic control information # show_tc1() { show_one_tc() { local device device=${1%@*} qdisc=$(tc qdisc list dev $device) if [ -n "$qdisc" ]; then echo Device $device: tc -s -d qdisc show dev $device echo tc -s -d class show dev $device echo fi } if [ $# -gt 0 ]; then show_one_tc $1 else ip -o link list | while read inx interface details; do show_one_tc ${interface%:} done fi } show_tc() { echo "$g_product $SHOREWALL_VERSION Traffic Control at $g_hostname - $(date)" echo shift if [ -z "$1" ]; then $g_tool -t mangle -L -n -v | $output_filter echo fi show_tc1 $1 } # # Show classifier information # show_classifiers() { show_one_classifier() { local device device=${1%@*} qdisc=$(tc qdisc list dev $device) if [ -n "$qdisc" ]; then echo Device $device: qt tc -s filter ls root dev $device && tc -s filter ls root dev $device | grep -v '^$' tc filter show dev $device tc class show dev $device | fgrep 'leaf ' | fgrep -v ' hfsc' | sed 's/^.*leaf //;s/ .*//' | while read class; do if [ -n "$class" ]; then echo echo Node $class tc filter show dev $device parent $class fi done echo fi } ip -o link list | while read inx interface details; do show_one_classifier ${interface%:} done } # # Display blacklist chains # blacklist_filter() { awk \ 'BEGIN { prnt=0; }; \ /^Members:/ { print "Dynamic:"; prnt=1; next; }; \ { if (prnt == 1) print; };' } show_bl() { [ -n "$g_blacklistipset" ] && ipset -L $g_blacklistipset | blacklist_filter && echo $g_tool -L $g_ipt_options | \ awk 'BEGIN {prnt=0; }; /^$/ {if (prnt == 1) print ""; prnt=0; }; /Chain .*~ / {prnt=1; }; /Chain dynamic / {prnt=1; }; {if (prnt == 1) print; }; END {if (prnt == 1 ) print "" };' } # # Watch the Firewall Log # logwatch() # $1 = timeout -- if negative, prompt each time that # an 'interesting' packet count changes { setup_logread host=$(echo $g_hostname | sed 's/\..*$//') oldrejects=$($g_tool -L -v -n | grep 'LOG') if [ $1 -lt 0 ]; then timeout=$((- $1)) pause="Yes" else pause="No" timeout=$1 fi qt mywhich awk && haveawk=Yes || haveawk= while true; do clear_term echo "$banner $(date)" echo echo "Dropped/Rejected Packet Log ($LOGFILE)" echo show_reset rejects=$($g_tool -L -v -n | grep 'LOG') if [ "$rejects" != "$oldrejects" ]; then oldrejects="$rejects" printf '\a' packet_log 40 if [ "$pause" = "Yes" ]; then echo printf 'Enter any character to continue: ' read foo else timed_read fi else echo packet_log 40 timed_read fi done } # # Try to find the arptables binary -- sets the variable 'arptables' # resolve_arptables() { arptables="$ARPTABLES" [ -n "${arptables:=arptables}" ] case $arptables in */*) ;; *) arptables=$(mywhich "$arptables") ;; esac } # # Try to run the 'savesets' command # savesets() { local supported supported=$(run_it $g_firewall help | fgrep savesets ) [ -n "$supported" ] && run_it $g_firewall savesets ${g_restorepath}-ipsets } # # Proactive save of the current ipset contents # savesets1() { local supported supported=$(run_it $g_firewall help | fgrep savesets ) [ -n "$supported" ] && run_it $g_firewall savesets ${VARDIR}/ipsets.save && progress_message3 "The ipsets have been saved to ${VARDIR}/ipsets.save" } # # Save currently running configuration # do_save() { local status local arptables status=0 if [ -f $g_firewall ]; then if $iptables_save | grep -v -- '-A dynamic.* -j ACCEPT' > ${VARDIR}/restore-$$; then cp -f $g_firewall $g_restorepath mv -f ${VARDIR}/restore-$$ ${g_restorepath}-iptables chmod 700 $g_restorepath chmod 600 ${g_restorepath}-iptables echo " Currently-running Configuration Saved to $g_restorepath" run_user_exit save else rm -f ${VARDIR}/restore-$$ echo " ERROR: Currently-running Configuration Not Saved" >&2 status=1 fi else echo " ERROR: $g_firewall does not exist" >&2 status=1 fi case ${SAVE_ARPTABLES:=No} in [Yy]es) resolve_arptables if [ -n "$arptables" ]; then if ${arptables}-save > ${VARDIR}/restore-$$; then if grep -q '^-A' ${VARDIR}/restore-$$; then mv -f ${VARDIR}/restore-$$ ${g_restorepath}-arptables chmod 600 ${g_restorepath}-arptables else rm -f ${VARDIR}/restore-$$ fi fi else case "$ARPTABLES" in */*) error_message "ERROR: ARPTABLES=$ARPTABLES does not exist or is not executable - arptables not saved" ;; *) error_message "ERROR: The arptables utility cannot be located - arptables not saved" ;; esac rm -f ${g_restorepath}-arptables fi ;; [Nn]o) rm -f ${g_restorepath}-arptables ;; *) error_message "WARNING: Invalid value ($SAVE_ARPTABLES) for SAVE_ARPTABLES" ;; esac if ! savesets; then case ${SAVE_IPSETS:=No} in [Yy]es) case ${IPSET:=ipset} in */*) if [ ! -x "$IPSET" ]; then error_message "ERROR: IPSET=$IPSET does not exist or is not executable - ipsets are not saved" IPSET= fi ;; *) IPSET="$(mywhich $IPSET)" [ -n "$IPSET" ] || error_message "ERROR: The ipset utility cannot be located - ipsets are not saved" ;; esac if [ -n "$IPSET" ]; then if eval $IPSET -S > ${VARDIR}/ipsets.tmp; then # # Don't save an 'empty' file # grep -qE -- '^(-N|create )' ${VARDIR}/ipsets.tmp && mv -f ${VARDIR}/ipsets.tmp ${g_restorepath}-ipsets && chmod 600 ${g_restorepath}-ipsets fi fi ;; [Nn]o|ipv4|ipv6) ;; *) error_message "WARNING: Invalid value ($SAVE_IPSETS) for SAVE_IPSETS" ;; esac fi return $status } save_config() { local result result=1 iptables_save=${g_tool}-save [ -x $iptables_save ] || echo "$iptables-save does not exist or is not executable" >&2 [ -n "$g_counters" ] && iptables_save="$iptables_save --counters" if product_is_started ; then [ -d ${VARDIR} ] || mkdir -p ${VARDIR} if [ -f $g_restorepath -a ! -x $g_restorepath ]; then echo " ERROR: $g_restorepath exists and is not a saved $g_product configuration" >&2 else case $RESTOREFILE in capabilities|chains|default_route|firewall|firewall.conf|nat|proxyarp|restarted|rt_tables|save|state|undo_routing|zones) echo " ERROR: Reserved file name: $RESTOREFILE" >&2 ;; *) validate_restorefile RESTOREFILE if do_save; then rm -f ${VARDIR}/save result=0 fi ;; esac fi else echo "$g_product isn't started" >&2 fi return $result } # # Recent Linux systems seem to like to print a randomly-ordered # view of routing tables. This hack sorts the output into the # order we all know and love # sort_routes() { local dest local second local rest local vlsm local maxvlsm local rule if [ $g_family -eq 4 ]; then maxvlsm=032 else maxvlsm=128 fi while read dest second rest; do if [ -n "$dest" ]; then rule="$dest $second $rest" case "$dest" in default) echo "000 $rule" ;; blackhole|local) case "$second" in */*) vlsm=${second#*/} printf "%03d %s\n" $vlsm "$rule" ;; *) echo "$maxvlsm $rule" ;; esac ;; */*) vlsm=${dest#*/} printf "%03d %s\n" $vlsm "$rule" ;; *) echo "$maxvlsm $rule" ;; esac fi done | sort -r | while read dest rest; do echo $rest; done } # # Isolate the table in the routing rules being read from stdin. # Piping through sed to remove trailing whitespace works around # recent 'features' in dash and ip. # find_tables() { sed -r 's/[[:space:]]+$//' | while read rule; do echo ${rule##* } done } # # Show routing configuration # show_routing() { local rule local table if [ -n "$(ip -$g_family rule list)" ]; then heading "Routing Rules" ip -$g_family rule list ip -$g_family rule list | find_tables | sort -u | while read table; do heading "Table $table:" if [ $g_family -eq 6 ]; then ip -6 -o route list table $table | grep -vF cache | sort_routes else ip -4 -o route list table $table | sort_routes fi done if [ -n "$g_routecache" ]; then heading "Route Cache" ip -$g_family route list cache fi else heading "Routing Table" if [ $g_family -eq 6 ]; then ip -6 -o route list | grep -vF cache | sort_routes else ip -4 -o route list table $table | sort_routes fi fi } determine_ipset_version() { local setname if [ -z "$IPSET" -o "$IPSET" = "ipset" ]; then IPSET=$(mywhich ipset) [ -n "$IPSET" ] || fatal_error "The ipset utility cannot be located" fi setname=fooX$$ qt ipset -X $setname # Just in case something went wrong the last time if qt ipset -N $setname hash:ip family inet; then qt ipset -X $setname IPSETN="$IPSET" else IPSETN="$IPSET -n" fi } # # 'list dynamic' command executor # find_sets() { local junk local setname $IPSETN -L | egrep "^Name: ${1}(_.+)?$" | while read junk setname; do echo $setname; done } list_zone() { local sets local setname determine_ipset_version if [ $g_family -eq 4 ]; then sets=$($IPSETN -L | egrep "^$1(_.+)?"); else sets=$($IPSETN -L | egrep "^6_$1(_.+)?") fi [ -n "$sets" ] || sets=$(find_sets $1) for setname in $sets; do echo "${setname#${1}_}:" $IPSETN -L $setname | awk 'BEGIN {prnt=0;}; \ /^Members:/ {prnt=1; next; }; \ /^Bindings:/ {prnt=0; }; \ { if (prnt == 1) print " ", $1; };' done } option_error() { fatal_error "The $COMMAND command does not accept this option: -$1" } too_many_arguments() { fatal_error "Too many arguments: $1" } missing_argument() { fatal_error "Missing argument" } missing_option_value() { fatal_error "The $1 option requires a value" } version_command() { local finished finished=0 local all all= local product local compiletime while [ $finished -eq 0 -a $# -gt 0 ]; do option=$1 case $option in -*) option=${option#-} while [ -n "$option" ]; do case $option in -) finished=1 option= ;; a*) all=Yes option=${option#a} ;; *) option_error $option ;; esac done shift ;; *) finished=1 ;; esac done [ $# -gt 0 ] && too_many_arguments if [ -n "$all" ]; then echo "shorewall-core: $(cat ${SHAREDIR}/shorewall/coreversion)" for product in shorewall shorewall6 shorewall-lite shorewall6-lite shorewall-init; do if [ -f ${SHAREDIR}/$product/version ]; then echo "$product: $(cat ${SHAREDIR}/$product/version)" fi done if [ "$(id -u)" -eq 0 -a -f $g_firewall ]; then compiletime=$(run_it $g_firewall info 2>/dev/null) case $compiletime in compiled\ *) echo "$g_firewall was $compiletime" ;; *) echo "$g_firewall was compiled by Shorewall version $(run_it $g_firewall version))" ;; esac fi else echo $SHOREWALL_VERSION fi } # # Show Filter - For Shorewall[6]-lite, if there was an scfilter file at compile-time, # then the compiler generated another version of this function and # embedded it in the firewall.conf file. That version supersedes this # one. # show_connections_filter() { local filter local command local first command=${SHOREWALL_SHELL} filter=$(find_file scfilter) if [ -f $filter ]; then first=$(head -n1 $filter) case $first in \#!*) command=${first#\#!} ;; esac $command $filter else cat - fi } show_nfacct() { if [ -n "$NFACCT" -a ! -x "$NFACCT" ]; then error_message "WARNING: NFACCT=$NFACCT does not exist or is not executable" NFACCT= else NFACCT=$(mywhich nfacct) [ -n "$NFACCT" ] || echo "No NF Accounting defined (nfacct not found)" fi if [ -n "$NFACCT" ]; then $NFACCT list echo fi } show_event() { local address local ttl_label local ttl local last_seen local last local oldest_pkt local oldest local intimes local outtimes1 local outtimes2 local time local count while read address ttl_label ttl last_seen last oldest_pkt oldest intimes; do case $address in *.*) [ $g_family -eq 4 ] || continue ;; *:*) [ $g_family -eq 6 ] || continue ;; *) continue ;; esac outtimes1='' outtimes2='' count=0 last=$((($currenttime - $last)/1000)) for time in $intimes; do time=${time%,} time=$(($currenttime - $time)) if [ $time -lt 10 ]; then time="000$time" elif [ $time -lt 100 ]; then time="00$time" elif [ $time -lt 1000 ]; then time="0$time" fi if [ $count -lt $oldest ]; then outtimes2="$outtimes2 $time" else outtimes1="$outtimes1 $time" fi count=$(($count + 1)) done outtimes1="${outtimes1}${outtimes2}" [ -n "$outtimes1" ] && outtimes1=$(echo "$outtimes1 " | sed -r 's/([[:digit:]]{3}) /\.\1, /g') && outtimes1=${outtimes1%, } echo " $address : ${outtimes1}" done < /proc/net/xt_recent/$1 } show_events() { local file local base local currenttime if [ -f /proc/net/xt_recent/%CURRENTTIME ]; then echo -127.0.0.1 > /proc/net/xt_recent/%CURRENTTIME echo +127.0.0.1 > /proc/net/xt_recent/%CURRENTTIME currenttime=$(cat /proc/net/xt_recent/%CURRENTTIME | cut -d ' ' -f 5 -) # echo Current time: $currenttime # echo else currenttime=0 fi if [ $# -gt 0 ]; then for event in $@ ; do if [ -f /proc/net/xt_recent/$event ]; then echo $event: show_event $event echo else error_message "WARNING: Event $event not found" fi done else for file in /proc/net/xt_recent/*; do base=$(basename $file) if [ "$base" != %CURRENTTIME -a "$base" != "*" ]; then echo $base show_event $base echo fi done fi } show_actions() { if [ -f ${g_confdir}/actions ]; then cat ${g_sharedir}/actions.std ${g_confdir}/actions | grep -Ev '^[#?[:space:]]|^$' else grep -Ev '^[#?[:space:]]|^$' ${g_sharedir}/actions.std fi } show_chain() { echo "$g_product $SHOREWALL_VERSION $([ $# -gt 1 ] && echo "Chains " || [ $# -gt 0 ] && echo "Chain " || echo $table Table)$* at $g_hostname - $(date)" echo show_reset if [ $# -gt 0 ]; then for chain in $*; do $g_tool -t $table -L $chain $g_ipt_options | $output_filter echo done else $g_tool -t $table -L $g_ipt_options | $output_filter fi } show_chains() { echo "$g_product $SHOREWALL_VERSION $([ $# -gt 1 ] && echo "Chains " || echo "Chain ")$* at $g_hostname - $(date)" echo show_reset for chain in $*; do $g_tool -t $table -L $chain $g_ipt_options | $output_filter echo done } show_table() { echo "$g_product $SHOREWALL_VERSION $table Table at $g_hostname - $(date)" echo show_reset $g_tool -t $table -L $g_ipt_options | $output_filter } show_nat() { echo "$g_product $SHOREWALL_VERSION NAT Table at $g_hostname - $(date)" echo show_reset $g_tool -t nat -L $g_ipt_options | $output_filter } show_raw() { echo "$g_product $SHOREWALL_VERSION RAW Table at $g_hostname - $(date)" echo show_reset $g_tool -t raw -L $g_ipt_options | $output_filter } show_mangle() { echo "$g_product $SHOREWALL_VERSION Mangle Table at $g_hostname - $(date)" echo show_reset $g_tool -t mangle -L $g_ipt_options | $output_filter } show_classifiers_command() { echo "$g_product $SHOREWALL_VERSION Classifiers at $g_hostname - $(date)" echo show_classifiers } show_ip_addresses() { echo "$g_product $SHOREWALL_VERSION IP at $g_hostname - $(date)" echo ip -$g_family addr list } show_routing_command() { echo "$g_product $SHOREWALL_VERSION Routing at $g_hostname - $(date)" echo show_routing } show_policies() { echo "$g_product $SHOREWALL_VERSION Policies at $g_hostname - $(date)" echo [ -f ${VARDIR}/policies ] && cat ${VARDIR}/policies } show_ipa() { echo "$g_product $SHOREWALL_VERSION per-IP Accounting at $g_hostname - $(date)" echo perip_accounting } show_arptables() { echo "$g_product $SHOREWALL_VERSION arptables at $g_hostname - $(date)" echo $arptables -L -n -v } show_log() { echo "$g_product $SHOREWALL_VERSION Log ($LOGFILE) at $g_hostname - $(date)" echo show_reset host=$(echo $g_hostname | sed 's/\..*$//') if [ $# -eq 2 ]; then eval search_log $2 elif [ -n "$g_pager" ]; then packet_log 100 else packet_log 20 fi } show_connections() { if [ $g_family -eq 4 ]; then if [ -d /proc/sys/net/netfilter/ ]; then local count local max count=$(cat /proc/sys/net/netfilter/nf_conntrack_count) max=$(cat /proc/sys/net/netfilter/nf_conntrack_max) echo "$g_product $SHOREWALL_VERSION Connections ($count out of $max) at $g_hostname - $(date)" else echo "$g_product $SHOREWALL_VERSION Connections at $g_hostname - $(date)" fi echo if qt mywhich conntrack ; then shift conntrack -f ipv4 -L $@ | show_connections_filter else [ $# -gt 1 ] && too_many_arguments if [ -f /proc/net/ip_conntrack ]; then cat /proc/net/ip_conntrack | show_connections_filter else grep -v '^ipv6' /proc/net/nf_conntrack | show_connections_filter fi fi elif qt mywhich conntrack ; then shift echo "$g_product $SHOREWALL_VERSION Connections at $g_hostname - $(date)" echo conntrack -f ipv6 -L $@ | show_connections_filter else [ $# -gt 1 ] && too_many_arguments if [ -f /proc/sys/net/netfilter/nf_conntrack_count -a -f /proc/sys/net/nf_conntrack ]; then local count=$(cat /proc/sys/net/netfilter/nf_conntrack_count) local max=$(cat /proc/sys/net/netfilter/nf_conntrack_max) echo "$g_product $SHOREWALL_VERSION Connections ($count of $max) at $g_hostname - $(date)" echo grep '^ipv6' /proc/net/nf_conntrack | sed -r 's/0000:/:/g; s/:::+/::/g; s/:0+/:/g' | show_connections_filter fi fi } show_nfacct_command() { echo "$g_product $SHOREWALL_VERSION NF Accounting at $g_hostname - $(date)" echo show_nfacct } show_events_command() { echo "$g_product $SHOREWALL_VERSION events at $g_hostname - $(date)" echo show_events } show_blacklists() { echo "$g_product $SHOREWALL_VERSION blacklist chains at $g_hostname - $(date)" echo show_bl; } show_actions_sorted() { show_actions | sort } show_macros() { for directory in $(split $CONFIG_PATH); do temp= for macro in ${directory}/macro.*; do case $macro in *\*) ;; *) if [ -z "$temp" ]; then echo echo "Macros in $directory:" echo temp=Yes fi show_macro ;; esac done done } show_an_action() { echo "Shorewall $SHOREWALL_VERSION Action $1 at $g_hostname - $(date)" cat ${directory}/action.$1 } show_a_macro() { echo "Shorewall $SHOREWALL_VERSION Macro $1 at $g_hostname - $(date)" cat ${directory}/macro.$1 } # # Don't dump empty SPD entries or entries from the other address family # spd_filter() { # # af = Address Family (4 or 6) # afok = Address Family of entry matches af # p = print the contents of A (entry is not empty) # i = Number of lines stored in A # awk -v af=$g_family \ 'function prnt(A,i, j) { while ( j < i ) print A[j++]; };\ \ /^src / { if (p) prnt( A, i );\ afok = 1;\ p = 0;\ i = 0;\ if ( af == 4 )\ { if ( /:/ ) afok = 0; }\ else\ { if ( /\./ ) afok = 0; }\ };\ { if ( afok ) A[i++] = $0; };\ /tmpl/ { p = afok; };\ \ END { if (p) prnt( A, i ); }' } # # Print a heading with leading and trailing black lines # heading() { echo echo "$@" echo } show_ipsec() { heading "PFKEY SPD" $IP -s -$g_family xfrm policy | spd_filter heading "PFKEY SAD" $IP -s -$g_family xfrm state | egrep -v '[[:space:]]+(auth-trunc|enc )' # Don't divulge the keys } show_ipsec_command() { echo "$g_product $SHOREWALL_VERSION IPSEC at $g_hostname - $(date)" show_ipsec } show_saves_command() { local f local fn local mtime echo "$g_product $SHOREWALL_VERSION Saves at $g_hostname - $(date)" echo "Saved snapshots are:" echo for f in ${VARDIR}/*-iptables; do case $f in *\**) ;; *) fn=$(basename $f) fn=${fn%-iptables} mtime=$(ls -lt $f | tail -n 1 | cut -d ' ' -f '6 7 8' ) [ $fn = "$RESTOREFILE" ] && fn="$fn (default)" echo " $mtime ${fn%-iptables}" ;; esac done echo } # # Show Command Executor # show_command() { local finished finished=0 local table table=filter local table_given table_given= local output_filter output_filter=cat local arptables local macro show_macro() { foo=`grep 'This macro' $macro | sed 's/This macro //'` if [ -n "$foo" ]; then macro=$(basename $macro) macro=${macro#*.} foo=${foo%.*} if [ ${#macro} -gt 5 ]; then printf " $macro\t${foo#\#}\n" else printf " $macro\t\t${foo#\#}\n" fi fi } # eliminates rules which have not been used from ip*tables' output brief_output() { awk \ '/^Chain / { heading1 = $0; getline heading2; printed = 0; next; }; /^ +0 +0 / { next; }; /^$/ { if ( printed == 1 ) { print $0; }; next; }; { if ( printed == 0 ) { print heading1; print heading2; printed = 1 }; }; { print; }'; } while [ $finished -eq 0 -a $# -gt 0 ]; do option=$1 case $option in -*) option=${option#-} while [ -n "$option" ]; do case $option in -) finished=1 option= ;; v*) VERBOSITY=$(($VERBOSITY + 1 )) option=${option#v} ;; x*) g_ipt_options="-xnv" option=${option#x} ;; m*) g_showmacs=Yes option=${option#m} ;; f*) g_filemode=Yes option=${option#f} ;; t) [ $# -eq 1 ] && missing_option_value -t case $2 in mangle|nat|filter|raw) table=$2 table_given=Yes ;; *) fatal_error "Invalid table name ($s)" ;; esac option= shift ;; l*) g_ipt_options1="--line-numbers" option=${option#l} ;; c*) g_routecache=Yes option=${option#c} ;; b*) output_filter=brief_output option=${option#b} ;; *) option_error $option ;; esac done shift ;; *) finished=1 ;; esac done g_ipt_options="$g_ipt_options $g_ipt_options1" [ -n "$g_debugging" ] && set -x COMMAND="$COMMAND $1" case "$1" in connections) only_root eval show_connections $@ $g_pager ;; nat) only_root [ $# -gt 1 ] && too_many_arguments $2 eval show_nat $g_pager ;; raw) only_root [ $# -gt 1 ] && too_many_arguments $2 eval show_raw $g_pager ;; tos|mangle) only_root [ $# -gt 1 ] && too_many_arguments $2 eval show_mangle $g_pager ;; log) [ $# -gt 2 ] && too_many_arguments $2 only_root setup_logread eval show_log $g_pager ;; tc) only_root [ $# -gt 2 ] && too_many_arguments $2 eval show_tc $@ $g_pager ;; classifiers|filters) only_root [ $# -gt 1 ] && too_many_arguments $2 eval show_classifiers_command $g_pager ;; zones) only_root [ $# -gt 1 ] && too_many_arguments $2 if [ -f ${VARDIR}/zones ]; then echo "$g_product $SHOREWALL_VERSION Zones at $g_hostname - $(date)" echo while read zone type hosts; do echo "$zone ($type)" for host in $hosts; do case $host in exclude) echo " exclude:" ;; *) echo " $host" ;; esac done done < ${VARDIR}/zones echo else fatal_error "${VARDIR}/zones does not exist" fi ;; capabilities) only_root [ $# -gt 1 ] && too_many_arguments $2 determine_capabilities VERBOSITY=2 if [ -n "$g_filemode" ]; then eval report_capabilities1 $g_pager else eval report_capabilities $g_pager fi ;; ip) [ $# -gt 1 ] && too_many_arguments $2 eval show_ip_addresses $g_pager ;; routing) [ $# -gt 1 ] && too_many_arguments $2 eval show_routing_command $g_pager ;; config) . ${g_sharedir}/configpath if [ -n "$g_filemode" ]; then echo "CONFIG_PATH=$CONFIG_PATH" echo "VARDIR=$VARDIR" echo "LIBEXEC=${LIBEXECDIR}" echo "SBINDIR=${SBINDIR}" echo "CONFDIR=${CONFDIR}" [ -n "$g_lite" ] && [ ${VARDIR} != /var/lib/$PRODUCT ] && echo "LITEDIR=${VARDIR}" else echo "Default CONFIG_PATH is $CONFIG_PATH" echo "Default VARDIR is /var/lib/$PRODUCT" echo "LIBEXEC is ${LIBEXECDIR}" echo "SBINDIR is ${SBINDIR}" echo "CONFDIR is ${CONFDIR}" [ -n "$g_lite" ] && [ ${VARDIR} != /var/lib/$PRODUCT ] && echo "LITEDIR is ${VARDIR}" fi ;; chain) only_root shift eval show_chain $@ $g_pager ;; vardir) echo $VARDIR; ;; rc) shift [ $# -gt 1 ] && too_many_arguments $2 if [ -n "$1" -a -d "$1" ]; then cat $1/shorewallrc elif [ -n "$g_basedir" -a -d "$g_basedir" ]; then cat $g_basedir/shorewallrc else fatal_error "Can not determine the location of the shorewallrc file." fi ;; policies) only_root [ $# -gt 1 ] && too_many_arguments $2 eval show_policies $g_pager ;; ipa) only_root [ $g_family -eq 4 ] || fatal_error "'show ipa' is now available in $g_product" [ $# -gt 1 ] && too_many_arguments $2 eval show_ipa $g_pager ;; marks) [ $# -gt 1 ] && too_many_arguments $2 only_root echo "$g_product $SHOREWALL_VERSION Mark Layout at $g_hostname - $(date)" echo [ -f ${VARDIR}/marks ] && cat ${VARDIR}/marks; ;; nfacct) [ $# -gt 1 ] && too_many_arguments $2 only_root eval show_nfacct_command $g_pager ;; arptables) [ $# -gt 1 ] && too_many_arguments $2 only_root resolve_arptables if [ -n "$arptables" -a -x $arptables ]; then eval show_arptables $g_pager else error_message "Cannot locate the arptables executable" fi ;; event) [ $# -gt 1 ] || too_many_arguments $2 only_root echo "$g_product $SHOREWALL_VERSION events at $g_hostname - $(date)" echo shift show_events $@ ;; events) [ $# -gt 1 ] && too_many_arguments $2 only_root eval show_events_command $g_pager ;; bl|blacklists) [ $# -gt 1 ] && too_many_arguments $2 only_root setup_dbl eval show_blacklists $g_pager ;; opens) [ $# -gt 1 ] && too_many_arguments $2 only_root echo "$g_product $SHOREWALL_VERSION Temporarily opened connections at $g_hostname - $(date)" if chain_exists dynamic; then g_ipt_options="$g_ipt_options --line-numbers" $g_tool -t filter -L dynamic $g_ipt_options | head -n2 $g_tool -t filter -L dynamic $g_ipt_options | fgrep ACCEPT | $output_filter fi ;; ipsec) [ $# -gt 1 ] && too_many_arguments $2 only_root eval show_ipsec_command $g_pager ;; saves) [ $# -gt 1 ] && too_many_arguments $2 show_saves_command ;; *) case "$PRODUCT" in *-lite) ;; *) case $1 in action) [ $# -lt 2 ] && fatal_error 'Missing ' [ $# -gt 2 ] && too_many_arguments $2 for directory in $(split $CONFIG_PATH); do if [ -f ${directory}/action.$2 ]; then eval show_an_action $2 $g_pager return fi done echo " WARNING: Action $2 not found" >&2 return ;; actions) [ $# -gt 1 ] && too_many_arguments $2 eval show_actions_sorted $g_pager return ;; macro) [ $# -lt 2 ] && fatal_error 'Missing ' [ $# -ne 2 ] && too_many_arguments $2 for directory in $(split $CONFIG_PATH); do if [ -f ${directory}/macro.$2 ]; then eval show_a_macro $2 $g_pager return fi done echo " WARNING: Macro $2 not found" >&2 return ;; macros) [ $# -gt 1 ] && too_many_arguments $2 eval show_macros $g_pager return ;; esac ;; esac only_root if [ $# -gt 0 ]; then if [ $1 = dynamic -a $# -gt 1 ]; then shift [ $# -eq 1 ] || too_many_arguments $2 list_zone $1 return; fi [ -n "$table_given" ] || for chain in $*; do if ! qt $g_tool -t $table -L $chain $g_ipt_options; then error_message "ERROR: Chain '$chain' is not recognized by $g_tool." exit 1 fi done eval show_chains $@ $g_pager else eval show_table $g_pager fi ;; esac } perip_accounting() { if qt mywhich iptaccount; then local hnames local hname hnames=$(iptaccount -a | grep '^Found table:' | cut -d ' ' -f 3) if [ -n "$hnames" ]; then for hname in $hnames; do iptaccount -l $hname | egrep '^IP:|^Show' echo done else echo " No IP Accounting Tables Defined" echo fi else echo " iptaccount is not installed" fi } # # Dump Filter - For Shorewall-lite, if there was a dumpfilter file at compile-time, # then the compiler generated another version of this function and # embedded it in the firewall.conf file. That version supersedes this # one. # dump_filter() { local filter local command local first command=${SHOREWALL_SHELL} filter=$(find_file dumpfilter) if [ -f $filter ]; then first=$(head -n1 $filter) case $first in \#!*) command=${first#\#!} ;; esac eval $command $filter $g_pager else cat - fi } dump_filter_wrapper() { eval dump_filter $g_pager } show_status() { local compiletime local state if product_is_started ; then [ $VERBOSITY -ge 1 ] && echo "$g_product is running" status=0 else [ $VERBOSITY -ge 1 ] && echo "$g_product is stopped" status=4 fi if [ -f ${VARDIR}/state ]; then state="$(cat ${VARDIR}/state)" case $state in Stopped*|Closed*|Clear*) status=3 ;; esac else state=Unknown fi if [ $VERBOSITY -ge 1 ]; then if [ -f $g_firewall ]; then compiletime=$(run_it $g_firewall info 2>/dev/null) case $compiletime in compiled\ *) state="$state ($g_firewall $compiletime)" ;; *) state="$state ($g_firewall compiled by Shorewall version $(run_it $g_firewall version))" ;; esac fi echo "State:$state" echo fi } # # Dump Command Executor # do_dump_command() { local finished finished=0 local arptables resolve_arptables while [ $finished -eq 0 -a $# -gt 0 ]; do option=$1 case $option in -*) option=${option#-} while [ -n "$option" ]; do case $option in -) finished=1 option= ;; x*) g_ipt_options="-xnv" option=${option#x} ;; m*) g_showmacs=Yes option=${option#m} ;; l*) g_ipt_options1="--line-numbers" option=${option#l} ;; c*) g_routecache=Yes option=${option#c} ;; *) option_error $option ;; esac done shift ;; *) finished=1 ;; esac done setup_logread g_ipt_options="$g_ipt_options $g_ipt_options1" [ $VERBOSITY -lt 2 ] && VERBOSITY=2 [ -n "$g_debugging" ] && set -x [ $# -eq 0 ] || too_many_arguments $1 clear_term echo "$g_product $SHOREWALL_VERSION Dump at $g_hostname - $(date)" echo if [ $g_family -eq 6 ] && [ -f ${SHAREDIR}/shorewall/version ]; then echo " Shorewall $(cat ${SHAREDIR}/shorewall/version)" echo fi show_status show_reset host=$(echo $g_hostname | sed 's/\..*$//') $g_tool -L $g_ipt_options if [ -n "$arptables" -a -x "$arptables" ]; then heading "ARP rules" $arptables -L -n -v fi heading "Log ($LOGFILE)" packet_log 20 if qt $g_tool -t nat -L -n; then heading "NAT Table" $g_tool -t nat -L $g_ipt_options fi if qt $g_tool -t mangle -L -n; then heading "Mangle Table" $g_tool -t mangle -L $g_ipt_options fi if qt $g_tool -t raw -L -n; then heading "Raw Table" $g_tool -t raw -L $g_ipt_options fi local count local max if [ -f /proc/sys/net/netfilter/nf_conntrack_count ]; then count=$(cat /proc/sys/net/netfilter/nf_conntrack_count) max=$(cat /proc/sys/net/netfilter/nf_conntrack_max) heading "Conntrack Table ($count out of $max)" elif [ -f /proc/sys/net/ipv4/netfilter/ip_conntrack_count ]; then count=$(cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count) max=$(cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max) heading "Conntrack Table ($count out of $max)" else heading "Conntrack Table" fi if qt mywhich conntrack; then conntrack -f ipv${g_family} -L 2> /dev/null elif [ $g_family -eq 4 ]; then [ -f /proc/net/ip_conntrack ] && cat /proc/net/ip_conntrack || grep -v '^ipv6' /proc/net/nf_conntrack else grep '^ipv6' /proc/net/nf_conntrack fi heading "IP Configuration" ip -$g_family addr list heading "IP Stats" ip -stat link list if qt mywhich brctl; then heading "Bridges" brctl show fi show_routing if [ $g_family -eq 4 ]; then heading "Per-IP Counters" perip_accounting fi heading "NF Accounting" show_nfacct heading "Events" show_events show_ipsec heading "/proc" show_proc /proc/version if [ $g_family -eq 4 ]; then show_proc /proc/sys/net/ipv4/ip_forward show_proc /proc/sys/net/ipv4/icmp_echo_ignore_all for directory in /proc/sys/net/ipv4/conf/*; do for file in proxy_arp arp_filter arp_ignore rp_filter log_martians; do show_proc $directory/$file done done else for directory in /proc/sys/net/ipv6/conf/*; do for file in forwarding proxy_ra proxy_ndp; do show_proc $directory/$file done done fi if [ $g_family -eq 4 ]; then heading "ARP" if qt mywhich arp; then arp -na else ip -4 neigh ls ip -4 neigh ls proxy fi else heading "Neighbors" ip -6 neigh ls fi if qt mywhich lsmod; then heading "Modules" if [ $g_family -eq 4 ]; then lsmod | grep -E '^(ip_|ipt_|iptable_|nf_|xt_)' | sort else lsmod | grep -E '^(x_|ip6|nf_|xt_)' | sort fi fi determine_capabilities echo report_capabilities echo qt mywhich ss && ss -${g_family}tunap || { qt mywhich netstat && netstat -tunap; } if [ -n "$TC_ENABLED" ]; then heading "Traffic Control" show_tc1 heading "TC Filters" show_classifiers fi } dump_command() { do_dump_command $@ | dump_filter_wrapper } # # Restore Comand Executor # restore_command() { local finished finished=0 local result while [ $finished -eq 0 -a $# -gt 0 ]; do option=$1 case $option in -*) option=${option#-} while [ -n "$option" ]; do case $option in -) finished=1 option= ;; n*) g_noroutes=Yes option=${option#n} ;; p*) [ -n "$(which conntrack)" ] || fatal_error "The '-p' option requires the conntrack utility which does not appear to be installed on this system" g_purge=Yes option=${option%p} ;; C*) g_counters=Yes option=${option#C} ;; *) option_error ;; esac done shift ;; *) finished=1 ;; esac done case $# in 0) ;; 1) RESTOREFILE="$1" validate_restorefile '' ;; *) too_many_arguments $2 ;; esac if [ -z "$STARTUP_ENABLED" ]; then error_message "ERROR: Startup is disabled" exit 6 fi g_restorepath=${VARDIR}/$RESTOREFILE [ -n "$g_nolock" ] || mutex_on if [ -x $g_restorepath ]; then progress_message3 "Restoring $g_product..." run_it $g_restorepath restore && progress_message3 "$g_product restored from ${VARDIR}/$RESTOREFILE" result=$? [ -n "$g_nolock" ] || mutex_off exit $result else echo "File $g_restorepath: file not found" [ -n "$g_nolock" ] || mutex_off exit 2 fi } # # Display the time that the counters were last reset # show_reset() { [ -f ${VARDIR}/restarted ] && \ echo "Counters reset $(cat ${VARDIR}/restarted)" && \ echo } # # Display's the passed file name followed by "=" and the file's contents. # show_proc() # $1 = name of a file { [ -f $1 ] && echo " $1 = $(cat $1)" } # # Create the appropriate -q option to pass onward # make_verbose() { local v v=$g_verbose_offset local option option=- if [ -n "$g_use_verbosity" ]; then echo "-v$g_use_verbosity" elif [ $g_verbose_offset -gt 0 ]; then while [ $v -gt 0 ]; do option="${option}v" v=$(($v - 1)) done echo $option elif [ $g_verbose_offset -lt 0 ]; then while [ $v -lt 0 ]; do option="${option}q" v=$(($v + 1)) done echo $option fi } # # Executor for drop,reject,... commands # block() # $1 = command, $2 = Finished, $3 - $n addresses { local chain chain=$1 local finished finished=$2 local which which='-s' local range range='--src-range' if ! chain_exists dynamic; then echo "Dynamic blacklisting is not enabled in the current $g_product configuration" >&2 [ -n "$g_nolock" ] || mutex_off exit 2 fi shift 3 while [ $# -gt 0 ]; do case $1 in from) which='-s' range='--src-range' shift continue ;; to) which='-d' range='--dst-range' shift continue ;; *-*) qt $g_tool -D dynamic -m iprange $range $1 -j reject qt $g_tool -D dynamic -m iprange $range $1 -j DROP qt $g_tool -D dynamic -m iprange $range $1 -j logreject qt $g_tool -D dynamic -m iprange $range $1 -j logdrop $g_tool -A dynamic -m iprange $range $1 -j $chain || break 1 ;; *) qt $g_tool -D dynamic $which $1 -j reject qt $g_tool -D dynamic $which $1 -j DROP qt $g_tool -D dynamic $which $1 -j logreject qt $g_tool -D dynamic $which $1 -j logdrop $g_tool -A dynamic $which $1 -j $chain || break 1 ;; esac echo "$1 $finished" shift done } # # Replace commas with spaces and echo the result # separate_list() { local list list="$@" local part local newlist local firstpart local lastpart local enclosure case "$list" in *,|,*|*,,*|*[[:space:]]*) # # 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. # 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 \,*) case $firstpart in *\,) echo "$(separate_list ${firstpart%,}) [$enclosure] $(separate_list ${lastpart#,})" ;; *) echo "$(separate_list $firstpart)[$enclosure] $(separate_list ${lastpart#,})" ;; esac ;; *) case $firstpart in *\,) echo "$(separate_list ${firstpart%,}) [$enclosure]$(separate_list $lastpart)" ;; *) echo "$(separate_list $firstpart)[$enclosure]$(separate_list $lastpart)" ;; esac ;; esac return ;; esac list="$@" part="${list%%,*}" newlist="$part" while [ "x$part" != "x$list" ]; do list="${list#*,}"; part="${list%%,*}"; newlist="$newlist $part"; done echo "$newlist" } # # add command executor # add_command() { local interface host hostlist zone ipset if ! product_is_started ; then fatal_error "$g_product Not Started" fi determine_ipset_version case $1 in *:*) while [ $# -gt 1 ]; do if [ $g_family -eq 4 ]; then interface=${1%%:*} host=${1#*:} else interface=${1%%|*} host=${1#*|} fi [ "$host" = "$1" ] && host= if [ -z "$host" ]; then if [ $g_family -eq 4 ]; then hostlist="$hostlist $interface:0.0.0.0/0" else hostlist="$hostlist $interface:::/0" fi else for h in $(separate_list $host); do hostlist="$hostlist $interface:$h" done fi shift done ;; *) ipset=$1 shift while [ $# -gt 0 ]; do for h in $(separate_list $1); do hostlist="$hostlist $h" done shift done ;; esac zone=$1 if [ -n "$zone" ]; then for host in $hostlist; do if [ $g_family -eq 4 ]; then interface=${host%:*} ipset=${zone}_${interface}; else interface=${host%%:*} ipset=6_${zone}_${interface}; fi ipset=$(echo $ipset | sed 's/\./_/g'); if ! qt $IPSET -L $ipset; then fatal_error "Zone $zone, interface $interface does not have a dynamic host list" fi host=${host#*:} if $IPSET -A $ipset $host; then echo "Host $interface:$host added to zone $zone" else fatal_error "Unable to add $interface:$host to zone $zone" fi done else qt $IPSET -L $ipset || fatal_error "Zone $ipset is not dynamic" for host in $hostlist; do if $IPSET -A $ipset $host; then echo "Host $host added to zone $ipset" else fatal_error "Unable to add $host to zone $ipset" fi done fi } # # delete command executor # delete_command() { local interface host hostent hostlist zone ipset if ! product_is_started ; then fatal_error "$g_product Not Started" fi determine_ipset_version case $1 in *:*) while [ $# -gt 1 ]; do if [ $g_family -eq 4 ]; then interface=${1%%:*} host=${1#*:} else interface=${1%%|*} host=${1#*|} fi [ "$host" = "$1" ] && host= if [ -z "$host" ]; then if [ $g_family -eq 4 ]; then hostlist="$hostlist $interface:0.0.0.0/0" else hostlist="$hostlist $interface:::/0" fi else for h in $(separate_list $host); do hostlist="$hostlist $interface:$h" done fi shift done ;; *) ipset=$1 shift while [ $# -gt 0 ]; do for h in $(separate_list $1); do hostlist="$hostlist $h" done shift done ;; esac zone=$1 if [ -n "$zone" ]; then for host in $hostlist; do if [ $g_family -eq 4 ]; then interface=${host%:*} ipset=${zone}_${interface}; else interface=${host%%:*} ipset=6_${zone}_${interface}; fi ipset=$(echo $ipset | sed 's/./_/g'); if ! qt $IPSET -L $ipset -n; then fatal_error "Zone $zone, interface $interface does not have a dynamic host list" fi host=${host#*:} if $IPSET -D $ipset $host; then echo "Host $host deleted from zone $zone" else echo " WARNING: Unable to delete host $hostent to zone $zone" >&2 fi done else qt $IPSET -L $ipset -n || fatal_error "Zone $ipset is not dynamic" for host in $hostlist; do if $IPSET -D $ipset $host; then echo "Host $host deleted from to zone $ipset" else echo " WARNING: Unable to delete host $host from zone $zone" >&2 fi done fi } open_close_command() { local command local desc local proto local icmptype open_close_setup() { [ -n "$g_nolock" ] || mutex_on if ! product_is_started ; then [ -n "$g_nolock" ] || mutex_off fatal_error "The $COMMAND command requires the firewall to be running" fi if ! chain_exists dynamic; then [ -n "$g_nolock" ] || mutex_off fatal_error "The $COMMAND command requires DYNAMIC_BLACKLIST=Yes in the running configuration" fi } [ $# -le 4 ] || fatal_error "Too many parameters" if [ $COMMAND = open ]; then [ $# -ge 2 ] || fatal_error "Too few parameters" else [ $# -ge 1 ] || fatal_error "Too few parameters" fi if [ $# -eq 1 ]; then # # close # case $1 in [1-9]|[1-9][0-9]|[1-9][0-9][0-9]*) ;; *) fatal_error "$1 is not a valid temporary open number" ;; esac open_close_setup #Conditionally acquires mutex if $g_tool -L dynamic --line-numbers | grep -q "^$1 .* ACCEPT "; then if $g_tool -D dynamic $1; then [ -n "$g_nolock" ] || mutex_off echo "Temporary open #$1 closed" return 0 fi [ -n "$g_nolock" ] || mutex_off return 2 else [ -n "$g_nolock" ] || mutex_off fatal_error "$1 is not a valid temporary open number" fi else if [ $1 = all ]; then command=dynamic else command="dynamic -s $1" fi if [ $2 != all ]; then command="$command -d $2" fi desc="from $1 to $2" if [ $# -ge 3 ]; then proto=$3 [ $proto = icmp -a $g_family -eq 6 ] && proto=58 command="$command -p $proto" case $3 in [0-9]*) desc="$desc protocol $3" ;; *) desc="$desc $3" ;; esac if [ $g_family -eq 4 ]; then if [ $proto = 6 -o $proto = icmp ]; then proto=icmp icmptype='--icmp-type' fi else if [ $proto = 58 -o $proto = ipv6-icmp ]; then proto=icmp icmptype='--icmpv6-type' fi fi fi if [ $# -eq 4 ]; then if [ $proto = icmp ]; then case $4 in *,*) fatal_error "Only a single ICMP type may be specified" ;; [0-9]*) desc="$desc type $4" ;; *) desc="$desc $4" ;; esac command="$command $icmptype $4" else case $4 in *,*) command="$command -m multiport --dports $4" ;; *) command="$command --dport $4" ;; esac case $4 in [0-9]*,) desc="$desc ports $4" ;; [0-9]*) desc="$desc port $4" ;; *) desc="$desc $4" ;; esac fi fi command="$command -j ACCEPT" open_close_setup #Conditionally acquires mutex if [ $COMMAND = open ]; then if $g_tool -I $command ; then [ -n "$g_nolock" ] || mutex_off echo "Firewall dynamically opened for connections $desc" return 0 fi [ -n "$g_nolock" ] || mutex_off return 2 fi if $g_tool -D $command 2> /dev/null; then [ -n "$g_nolock" ] || mutex_off echo "Firewall dynamically closed for connections $desc (may still be permitted by rules/policies)" return 0 fi [ -n "$g_nolock" ] || mutex_off fatal_error "Connections $desc are not currently opened" fi } # # 'hits' commmand executor # hits_command() { local finished finished=0 local today today= while [ $finished -eq 0 -a $# -gt 0 ]; do option=$1 case $option in -*) option=${option#-} while [ -n "$option" ]; do case $option in -) finished=1 option= ;; t*) today=$(date +'^%b %_d.*') option=${option#t} ;; *) option_error $option ;; esac done shift ;; *) finished=1 ;; esac done [ $# -eq 0 ] || too_many_arguments $1 clear_term echo "$g_product $SHOREWALL_VERSION Hits at $g_hostname - $(date)" echo timeout=30 if $g_logread | grep -q "${today}IN=.* OUT=" ; then echo " HITS IP DATE" echo " ---- --------------- ------" $g_logread | grep "${today}IN=.* OUT=" | sed 's/\(.\{6\}\)\(.*SRC=\)\(.*\)\( DST=.*\)/\3 \1/' | sort | uniq -c | sort -rn | while read count address month day; do printf '%7d %-15s %3s %2d\n' $count $address $month $day done echo "" echo " HITS IP PORT" echo " ---- --------------- -----" $g_logread | grep "${today}IN=.* OUT=" | sed 's/\(.*SRC=\)\(.*\)\( DST=.*DPT=\)\([0-9]\{1,5\}\)\(.*\)/\2 \4/ t s/\(.*SRC=\)\(.*\)\( DST=.*\)/\2/' | sort | uniq -c | sort -rn | while read count address port; do [ -z "$port" ] && port=0 printf '%7d %-15s %d\n' $count $address $port done echo "" echo " HITS DATE" echo " ---- ------" $g_logread | grep "${today}IN=.* OUT=" | sed 's/\(.\{6\}\)\(.*\)/\1/' | sort | uniq -c | sort -rn | while read count month day; do printf '%7d %3s %2d\n' $count $month $day done echo "" echo " HITS PORT SERVICE(S)" echo " ---- ----- ----------" $g_logread | grep "${today}IN=.* OUT=.*DPT" | sed 's/\(.*DPT=\)\([0-9]\{1,5\}\)\(.*\)/\2/' | sort | uniq -c | sort -rn | while read count port ; do # List all services defined for the given port srv=$(grep "^[^#].*\\b$port/" /etc/services | cut -f 1 | cut -f 1 -d' ' | sort -u) srv=$(echo $srv | sed 's/ /,/g') if [ -n "$srv" ] ; then printf '%7d %5d %s\n' $count $port $srv else printf '%7d %5d\n' $count $port fi done fi } # # Issue an error message and terminate if the firewall isn't started # require_started() { if ! product_is_started; then error_message "ERROR: $g_product is not started" exit 2 fi } # # 'allow' command executor # allow_command() { local allowed local which which='-s' local range range='--src-range' local dynexists [ -n "$g_debugging" ] && set -x [ $# -eq 1 ] && missing_argument if [ -n "$g_blacklistipset" ]; then case ${IPSET:=ipset} in */*) if [ ! -x "$IPSET" ]; then fatal_error "IPSET=$IPSET does not exist or is not executable" fi ;; *) IPSET="$(mywhich $IPSET)" [ -n "$IPSET" ] || fatal_error "The ipset utility cannot be located" ;; esac fi if chain_exists dynamic; then dynexists=Yes elif [ -z "$g_blacklistipset" ]; then require_started fatal_error "Dynamic blacklisting is not enabled in the current $g_product configuration" fi [ -n "$g_nolock" ] || mutex_on while [ $# -gt 1 ]; do shift allowed='' case $1 in from) which='-s' range='--src-range' continue ;; to) which='-d' range='--dst-range' continue ;; *-*) if [ -n "$g_blacklistipset" ]; then if qt $IPSET -D $g_blacklistipset $1; then allowed=Yes [ -n "$g_dbllog" ] && mylogger daemon.info "$g_product: $1 Allowed" fi fi if [ -n "$dynexists" ]; then if qt $g_tool -D dynamic -m iprange $range $1 -j reject ||\ qt $g_tool -D dynamic -m iprange $range $1 -j DROP ||\ qt $g_tool -D dynamic -m iprange $range $1 -j logdrop ||\ qt $g_tool -D dynamic -m iprange $range $1 -j logreject then allowed=Yes fi fi ;; *) if [ -n "$g_blacklistipset" ]; then if qt $IPSET -D $g_blacklistipset $1; then [ -n "$g_dbllog" ] && mylogger daemon.info "$g_product: $1 Allowed" allowed=Yes fi fi if [ -n "$dynexists" ]; then if qt $g_tool -D dynamic $which $1 -j reject ||\ qt $g_tool -D dynamic $which $1 -j DROP ||\ qt $g_tool -D dynamic $which $1 -j logdrop ||\ qt $g_tool -D dynamic $which $1 -j logreject then allowed=Yes fi fi ;; esac if [ -n "$allowed" ]; then progress_message2 "$1 Allowed" else error_message "WARNING: $1 already allowed (not dynamically blacklisted)" fi done [ -n "$g_nolock" ] || mutex_off } # # 'logwatch' command executor # logwatch_command() { shift finished=0 while [ $finished -eq 0 -a $# -ne 0 ]; do option=$1 case $option in -*) option=${option#-} while [ -n "$option" ]; do case $option in v*) VERBOSITY=$(($VERBOSITY + 1 )) option=${option#v} ;; q*) VERBOSITY=$(($VERBOSITY - 1 )) option=${option#q} ;; m*) g_showmacs=Yes option=${option#m} ;; -) finished=1 option= ;; *) option_error $option ;; esac done shift ;; *) finished=1 ;; esac done [ -n "$g_debugging" ] && set -x if [ $# -eq 1 ]; then logwatch $1 elif [ $# -eq 0 ]; then logwatch 30 else too_many_arguments $2 fi } # # Determine which optional facilities are supported by iptables/netfilter # determine_capabilities() { local tool local chain local chain1 local arptables local helper if [ -z "$g_tool" ]; then [ $g_family -eq 4 ] && tool=iptables || tool=ip6tables g_tool=$(mywhich $tool) if [ -z "$g_tool" ]; then fatal_error "No executable $tool binary can be found on your PATH" fi fi qt $g_tool -t nat -L -n && NAT_ENABLED=Yes || NAT_ENABLED= qt $g_tool -t mangle -L -n && MANGLE_ENABLED=Yes || MANGLE_ENABLED= [ "$IP" = ip -o -z "$IP" ] && IP=$(which ip) [ -n "$IP" -a -x "$IP" ] || IP= [ "$TC" = tc -o -z "$TC" ] && TC=$(which tc) [ -n "$TC" -a -x "$TC" ] || TC= CONNTRACK_MATCH= NEW_CONNTRACK_MATCH= OLD_CONNTRACK_MATCH= MULTIPORT= XMULTIPORT= EMULTIPORT= POLICY_MATCH= PHYSDEV_MATCH= PHYSDEV_BRIDGE= IPRANGE_MATCH= RECENT_MATCH= REAP_OPTION= OWNER_MATCH= OWNER_NAME_MATCH= IPSET_MATCH= OLD_IPSET_MATCH= IPSET_MATCH_NOMATCH= IPSET_MATCH_COUNTERS= IPSET_V5= CONNMARK= XCONNMARK= CONNMARK_MATCH= XCONNMARK_MATCH= RAW_TABLE= IPP2P_MATCH= OLD_IPP2P_MATCH= LENGTH_MATCH= CLASSIFY_TARGET= ENHANCED_REJECT= KLUDGEFREE= MARK= XMARK= EXMARK= TPROXY_TARGET= MANGLE_FORWARD= COMMENTS= ADDRTYPE= TCPMSS_MATCH= HASHLIMIT_MATCH= NFQUEUE_TARGET= REALM_MATCH= HELPER_MATCH= CONNLIMIT_MATCH= TIME_MATCH= GOTO_TARGET= LOGMARK_TARGET= IPMARK_TARGET= LOG_TARGET= ULOG_TARGET= NFLOG_TARGET= PERSISTENT_SNAT= FLOW_FILTER= FWMARK_RT_MASK= MARK_ANYWHERE= HEADER_MATCH= ACCOUNT_TARGET= AUDIT_TARGET= CONDITION_MATCH= IPTABLES_S= BASIC_FILTER= BASIC_EMATCH= CT_TARGET= STATISTIC_MATCH= IMQ_TARGET= DSCP_MATCH= DSCP_TARGET= GEOIP_MATCH= RPFILTER_MATCH= NFACCT_MATCH= CHECKSUM_TARGET= ARPTABLESJF= MASQUERADE_TGT= UDPLITEREDIRECT= NEW_TOS_MATCH= TARPIT_TARGET= IFACE_MATCH= TCPMSS_TARGET= WAIT_OPTION= CPU_FANOUT= NETMAP_TARGET= NFLOG_SIZE= RESTORE_WAIT_OPTION= AMANDA_HELPER= FTP_HELPER= FTP0_HELPER= IRC_HELPER= IRC0_HELPER= NETBIOS_NS_HELPER= H323_HELPER= PPTP_HELPER= SANE_HELPER= SANE0_HELPER= SIP_HELPER= SIP0_HELPER= SNMP_HELPER= TFTP_HELPER= TFTP0_HELPER= resolve_arptables if [ -n "$arptables" -a -x "$arptables" ]; then qt $arptables -L OUT && ARPTABLESJF=Yes fi [ -z "$(${g_tool}-restore --wait < /dev/null 2>&1)" ] && RESTORE_WAIT_OPTION=Yes if qt $g_tool --wait -t filter -L INPUT -n -v; then WAIT_OPTION=Yes g_tool="$g_tool --wait" fi chain=fooX$$ if [ -n "$NAT_ENABLED" ]; then if qt $g_tool -t nat -N $chain; then if [ $g_family -eq 4 ]; then qt $g_tool -t nat -A $chain -j SNAT --to-source 1.2.3.4 --persistent && PERSISTENT_SNAT=Yes qt $g_tool -t nat -A $chain -j NETMAP --to 1.2.3.0/24 && NETMAP_TARGET=Yes else qt $g_tool -t nat -A $chain -j SNAT --to-source 2001::1 --persistent && PERSISTENT_SNAT=Yes qt $g_tool -t nat -A $chain -j NETMAP --to 2001:470:B:227::/64 && NETMAP_TARGET=Yes fi qt $g_tool -t nat -A $chain -j MASQUERADE && MASQUERADE_TGT=Yes qt $g_tool -t nat -L INPUT -n && NAT_INPUT_CHAIN=Yes qt $g_tool -t nat -A $chain -p udplite -m multiport --dport 33 -j REDIRECT --to-port 22 && UDPREDIRECT=Yes qt $g_tool -t nat -F $chain qt $g_tool -t nat -X $chain fi fi qt $g_tool -F $chain qt $g_tool -X $chain if ! $g_tool -N $chain; then fatal_error "The command \"$g_tool -N $chain\" failed" fi chain1=${chain}1 qt $g_tool -F $chain1 qt $g_tool -X $chain1 if ! $g_tool -N $chain1; then qt $g_tool -X $CHAIN fatal_error "The command \"$g_tool -N $chain1\" failed" fi if ! qt $g_tool -A $chain -m state --state ESTABLISHED,RELATED -j ACCEPT && ! qt $g_tool -A $chain -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT; then qt $g_tool -x $chain qt $g_tool -x $chain1 fatal_error "Your kernel lacks connection tracking and/or state matching -- $g_product will not run on this system" fi if [ $g_family -eq 4 ]; then qt $g_tool -A $chain -m conntrack --ctorigdst 192.168.1.1 -j ACCEPT && CONNTRACK_MATCH=Yes else qt $g_tool -A $chain -m conntrack --ctorigdst ::1 -j ACCEPT && CONNTRACK_MATCH=Yes fi if [ -n "$CONNTRACK_MATCH" ]; then qt $g_tool -A $chain -m conntrack -p tcp --ctorigdstport 22 -j ACCEPT && NEW_CONNTRACK_MATCH=Yes if [ $g_family -eq 4 ]; then qt $g_tool -A $chain -m conntrack ! --ctorigdst 1.2.3.4 || OLD_CONNTRACK_MATCH=Yes else qt $g_tool -A $chain -m conntrack ! --ctorigdst ::1 || OLD_CONNTRACK_MATCH=Yes fi fi if qt $g_tool -A $chain -p tcp -m multiport --dports 21,22 -j ACCEPT; then MULTIPORT=Yes qt $g_tool -A $chain -p tcp -m multiport --sports 60 -m multiport --dports 99 -j ACCEPT && KLUDEFREE=Yes fi qt $g_tool -A $chain -p tcp -m multiport --dports 21:22 -j ACCEPT && XMULTIPORT=Yes qt $g_tool -A $chain -p sctp -m multiport --dports 21,22 -j ACCEPT && EMULTIPORT=Yes qt $g_tool -A $chain -m policy --pol ipsec --mode tunnel --dir in -j ACCEPT && POLICY_MATCH=Yes if qt $g_tool -A $chain -m physdev --physdev-out eth0 -j ACCEPT; then PHYSDEV_MATCH=Yes qt $g_tool -A $chain -m physdev --physdev-is-bridged --physdev-in eth0 --physdev-out eth0 -j ACCEPT && PHYSDEV_BRIDGE=Yes if [ -z "${KLUDGEFREE}" ]; then qt $g_tool -A $chain -m physdev --physdev-in eth0 -m physdev --physdev-out eth0 -j ACCEPT && KLUDGEFREE=Yes fi fi if [ $g_family -eq 4 ]; then if qt $g_tool -A $chain -m iprange --src-range 192.168.1.5-192.168.1.124 -j ACCEPT; then IPRANGE_MATCH=Yes if [ -z "${KLUDGEFREE}" ]; then qt $g_tool -A $chain -m iprange --src-range 192.168.1.5-192.168.1.124 -m iprange --dst-range 192.168.1.5-192.168.1.124 -j ACCEPT && KLUDGEFREE=Yes fi fi elif qt $g_tool -A $chain -m iprange --src-range ::1-::2 -j ACCEPT; then IPRANGE_MATCH=Yes if [ -z "${KLUDGEFREE}" ]; then qt $g_tool -A $chain -m iprange --src-range ::1-::2 -m iprange --dst-range ::1-::2 -j ACCEPT && KLUDGEFREE=Yes fi fi if qt $g_tool -A $chain -m recent --update -j ACCEPT; then RECENT_MATCH=Yes qt $g_tool -A $chain -m recent --rcheck --seconds 10 --reap && REAP_OPTION=Yes fi qt $g_tool -A $chain -m owner --uid-owner 0 -j ACCEPT && OWNER_MATCH=Yes local name name=$(id -un 2> /dev/null) [ -n "$name" ] && qt $g_tool -A $chain -m owner --uid-owner $name -j ACCEPT && OWNER_NAME_MATCH=Yes if qt $g_tool -A $chain -m connmark --mark 2 -j ACCEPT; then CONNMARK_MATCH=Yes qt $g_tool -A $chain -m connmark --mark 2/0xFF -j ACCEPT && XCONNMARK_MATCH=Yes fi qt $g_tool -A $chain -p tcp -m ipp2p --edk -j ACCEPT && IPP2P_MATCH=Yes if [ -n "$IPP2P_MATCH" ]; then qt $g_tool -A $chain -p tcp -m ipp2p --ipp2p -j ACCEPT && OLD_IPP2P_MATCH=Yes fi qt $g_tool -A $chain -m length --length 10:20 -j ACCEPT && LENGTH_MATCH=Yes if [ $g_family -eq 4 ]; then qt $g_tool -A $chain -j REJECT --reject-with icmp-host-prohibited && ENHANCED_REJECT=Yes else qt $g_tool -A $chain -j REJECT --reject-with icmp6-adm-prohibited && ENHANCED_REJECT=Yes fi qt $g_tool -A $chain -j ACCEPT -m comment --comment "This is a comment" && COMMENTS=Yes if [ -n "$NFACCT" -a ! -x "$NFACCT" ]; then error_message "WARNING: NFACCT=$NFACCT does not exist or is not executable" NFACCT= else NFACCT=$(mywhich nfacct) fi if [ -n "$NFACCT" ] && qt $NFACCT add $chain; then qt $g_tool -A $chain -m nfacct --nfacct-name $chain && NFACCT_MATCH=Yes qt $g_tool -D $chain -m nfacct --nfacct-name $chain qt $NFACCT del $chain fi qt $g_tool -A $chain -p tcp -j TARPIT && TARPIT_TARGET=Yes qt $g_tool -A $chain -m iface --iface lo --loopback && IFACE_MATCH=Yes qt $g_tool -A $chain -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu && TCPMSS_TARGET=Yes if [ -n "$MANGLE_ENABLED" ]; then qt $g_tool -t mangle -N $chain if qt $g_tool -t mangle -A $chain -j MARK --set-mark 1; then MARK=Yes qt $g_tool -t mangle -A $chain -j MARK --and-mark 0xFF && XMARK=Yes qt $g_tool -t mangle -A $chain -j MARK --set-mark 1/0xFF && EXMARK=Yes fi if qt $g_tool -t mangle -A $chain -j CONNMARK --save-mark; then CONNMARK=Yes qt $g_tool -t mangle -A $chain -j CONNMARK --save-mark --mask 0xFF && XCONNMARK=Yes fi qt $g_tool -t mangle -A $chain -j CLASSIFY --set-class 1:1 && CLASSIFY_TARGET=Yes qt $g_tool -t mangle -A $chain -j IPMARK --addr src && IPMARK_TARGET=Yes qt $g_tool -t mangle -A $chain -p tcp -j TPROXY --on-port 0 --tproxy-mark 1 && TPROXY_TARGET=Yes qt $g_tool -t mangle -A $chain -j IMQ --todev 0 && IMQ_TARGET=Yes qt $g_tool -t mangle -A $chain -m dscp --dscp 0 && DSCP_MATCH=Yes qt $g_tool -t mangle -A $chain -j DSCP --set-dscp 0 && DSCP_TARGET=Yes qt $g_tool -t mangle -A $chain -m rpfilter && RPFILTER_MATCH=Yes qt $g_tool -t mangle -A $chain -j CHECKSUM --checksum-fill && CHECKSUM_TARGET=Yes qt $g_tool -t mangle -A $chain -m tos --tos 0x10/0xff && NEW_TOS_MATCH=Yes qt $g_tool -t mangle -F $chain qt $g_tool -t mangle -X $chain qt $g_tool -t mangle -L FORWARD -n && MANGLE_FORWARD=Yes fi qt $g_tool -t raw -L -n && RAW_TABLE=Yes if [ -n "$RAW_TABLE" ]; then qt $g_tool -t raw -F $chain qt $g_tool -t raw -X $chain qt $g_tool -t raw -N $chain if qt $g_tool -t raw -A $chain -j CT --notrack; then CT_TARGET=Yes; for helper in amanda ftp ftp0 h323 irc irc0 netbios_ns pptp sane sane0 sip sip0 snmp tftp tftp0; do eval ${helper}_ENABLED='' done if [ -n "$HELPERS" ]; then for helper in $(split_list "$HELPERS"); do case $helper in none) ;; amanda|ftp|ftp0|h323|irc|irc0|netbios_ns|pptp|sane|sane0|sip|sip0|snmp|tftp|tftp0) eval ${helper}_ENABLED=Yes ;; *) error_message "WARNING: Invalid helper ($helper) ignored" ;; esac done else for helper in amanda ftp ftp0 h323 irc irc0 netbios_ns pptp sane sane0 sip sip0 snmp tftp tftp0; do eval ${helper}_ENABLED=Yes done fi [ -n "$amanda_ENABLED" ] && qt $g_tool -t raw -A $chain -p udp --dport 10080 -j CT --helper amanda && AMANDA_HELPER=Yes [ -n "$ftp_ENABLED" ] && qt $g_tool -t raw -A $chain -p tcp --dport 21 -j CT --helper ftp && FTP_HELPER=Yes [ -n "$ftp0_ENABLED" ] && qt $g_tool -t raw -A $chain -p tcp --dport 21 -j CT --helper ftp-0 && FTP0_HELPER=Yes [ -n "$h323_ENABLED" ] && qt $g_tool -t raw -A $chain -p udp --dport 1719 -j CT --helper RAS && H323_HELPER=Yes [ -n "$irc_ENABLED" ] && qt $g_tool -t raw -A $chain -p tcp --dport 6667 -j CT --helper irc && IRC_HELPER=Yes [ -n "$irc0_ENABLED" ] && qt $g_tool -t raw -A $chain -p tcp --dport 6667 -j CT --helper irc-0 && IRC0_HELPER=Yes [ -n "$netbios_ns_ENABLED" ] && qt $g_tool -t raw -A $chain -p udp --dport 137 -j CT --helper netbios-ns && NETBIOS_NS_HELPER=Yes [ -n "$pptp_ENABLED" ] && qt $g_tool -t raw -A $chain -p tcp --dport 1729 -j CT --helper pptp && PPTP_HELPER=Yes [ -n "$sane_ENABLED" ] && qt $g_tool -t raw -A $chain -p tcp --dport 6566 -j CT --helper sane && SANE_HELPER=Yes [ -n "$sane0_ENABLED" ] && qt $g_tool -t raw -A $chain -p tcp --dport 6566 -j CT --helper sane-0 && SANE0_HELPER=Yes [ -n "$sip_ENABLED" ] && qt $g_tool -t raw -A $chain -p udp --dport 5060 -j CT --helper sip && SIP_HELPER=Yes [ -n "$sip0_ENABLED" ] && qt $g_tool -t raw -A $chain -p udp --dport 5060 -j CT --helper sip-0 && SIP0_HELPER=Yes [ -n "$snmp_ENABLED" ] && qt $g_tool -t raw -A $chain -p udp --dport 161 -j CT --helper snmp && SNMP_HELPER=Yes [ -n "$tftp_ENABLED" ] && qt $g_tool -t raw -A $chain -p udp --dport 69 -j CT --helper tftp && TFTP_HELPER=Yes [ -n "$tftp0_ENABLED" ] && qt $g_tool -t raw -A $chain -p udp --dport 69 -j CT --helper tftp-0 && TFTP0_HELPER=Yes fi qt $g_tool -t raw -F $chain qt $g_tool -t raw -X $chain fi if qt mywhich ipset; then qt ipset -X $chain # Just in case something went wrong the last time local have_ipset if [ $g_family -eq 4 ]; then if qt ipset -N $chain hash:ip family inet; then IPSET_V5=Yes have_ipset=Yes elif qt ipset -N $chain iphash ; then have_ipset=Yes fi if [ -n "$have_ipset" ]; then if qt $g_tool -A $chain -m set --match-set $chain src -j ACCEPT; then qt $g_tool -A $chain -m set --match-set $chain src --return-nomatch -j ACCEPT && IPSET_MATCH_NOMATCH=Yes qt $g_tool -A $chain -m set --match-set $chain src --packets-lt 100 -j ACCEPT && IPSET_MATCH_COUNTERS=Yes qt $g_tool -F $chain IPSET_MATCH=Yes elif qt $g_tool -A $chain -m set --set $chain src -j ACCEPT; then qt $g_tool -F $chain IPSET_MATCH=Yes OLD_IPSET_MATCH=Yes fi qt ipset -X $chain fi elif qt ipset -N $chain hash:ip family inet6; then IPSET_V5=Yes if qt $g_tool -A $chain -m set --match-set $chain src -j ACCEPT; then qt $g_tool -F $chain IPSET_MATCH=Yes elif qt $g_tool -A $chain -m set --set $chain src -j ACCEPT; then qt $g_tool -F $chain IPSET_MATCH=Yes OLD_IPSET_MATCH=Yes fi qt ipset -X $chain fi fi qt $g_tool -A $chain -m addrtype --src-type BROADCAST -j ACCEPT && ADDRTYPE=Yes qt $g_tool -A $chain -p tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1000:1500 -j ACCEPT && TCPMSS_MATCH=Yes qt $g_tool -A $chain -m hashlimit --hashlimit-upto 4 --hashlimit-burst 5 --hashlimit-name $chain --hashlimit-mode dstip -j ACCEPT && HASHLIMIT_MATCH=Yes if [ -z "$HASHLIMIT_MATCH" ]; then qt $g_tool -A $chain -m hashlimit --hashlimit 4 --hashlimit-burst 5 --hashlimit-name $chain --hashlimit-mode dstip -j ACCEPT && OLD_HL_MATCH=Yes HASHLIMIT_MATCH=$OLD_HL_MATCH fi if qt $g_tool -A $chain -j NFQUEUE --queue-num 4; then NFQUEUE_TARGET=Yes qt $g_tool -A $chain -j NFQUEUE --queue-balance 0:3 --queue-cpu-fanout && CPU_FANOUT=Yes fi qt $g_tool -A $chain -m realm --realm 4 && REALM_MATCH=Yes # # -m helper doesn't verify the existence of the specified helper :-( # if qt $g_tool -A $chain -p tcp --dport 21 -m helper --helper ftp; then HELPER_MATCH=Yes if [ -z "$CT_TARGET" ]; then AMANDA_HELPER=Yes FTP_HELPER=Yes FTP_HELPER=Yes H323_HELPER=Yes IRC_HELPER=Yes NS_HELPER=Yes PPTP_HELPER=Yes SANE_HELPER=Yes SIP_HELPER=Yes SNMP_HELPER=Yes TFTP_HELPER=Yes fi fi qt $g_tool -A $chain -m connlimit --connlimit-above 8 -j DROP && CONNLIMIT_MATCH=Yes qt $g_tool -A $chain -m time --timestart 23:00 -j DROP && TIME_MATCH=Yes qt $g_tool -A $chain -g $chain1 && GOTO_TARGET=Yes qt $g_tool -A $chain -j LOGMARK && LOGMARK_TARGET=Yes qt $g_tool -A $chain -j LOG && LOG_TARGET=Yes qt $g_tool -A $chain -j ULOG && ULOG_TARGET=Yes qt $g_tool -A $chain -j MARK --set-mark 5 && MARK_ANYWHERE=Yes qt $g_tool -A $chain -m statistic --mode nth --every 2 --packet 1 && STATISTIC_MATCH=Yes qt $g_tool -A $chain -m geoip --src-cc US && GEOIP_MATCH=Yes if qt $g_tool -A $chain -j NFLOG; then NFLOG_TARGET=Yes qt $g_tool -A $chain -j NFLOG --nflog-size 64 && NFLOG_SIZE=Yes fi if [ $g_family -eq 4 ]; then qt $g_tool -A $chain -j ACCOUNT --addr 192.168.1.0/29 --tname $chain && ACCOUNT_TARGET=Yes else qt $g_tool -A $chain -m ipv6header --header 255 && HEADER_MATCH=Yes qt $g_tool -A $chain -j ACCOUNT --addr ::1/122 --tname $chain && ACCOUNT_TARGET=Yes fi qt $g_tool -A $chain -j AUDIT --type drop && AUDIT_TARGET=Yes qt $g_tool -A $chain -m condition --condition foo && CONDITION_MATCH=Yes qt $g_tool -S INPUT && IPTABLES_S=Yes qt $g_tool -F $chain qt $g_tool -X $chain qt $g_tool -F $chain1 qt $g_tool -X $chain1 if [ -n "$TC" ]; then $TC filter add flow help 2>&1 | grep -q ^Usage && FLOW_FILTER=Yes if $TC filter add basic help 2>&1 | grep -q ^Usage; then BASIC_FILTER=Yes $TC filter add basic help 2>&1 | egrep -q match && BASIC_EMATCH=Yes fi fi [ -n "$IP" ] && $IP rule add help 2>&1 | grep -q /MASK && FWMARK_RT_MASK=Yes CAPVERSION=$SHOREWALL_CAPVERSION KERNELVERSION=$(uname -r 2> /dev/null | sed -e 's/-.*//') case "$KERNELVERSION" in *.*.*) KERNELVERSION=$(printf "%d%02d%02d" $(echo $KERNELVERSION | sed -e 's/^\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\).*$/\1 \2 \3/g')) ;; *) KERNELVERSION=$(printf "%d%02d00" $(echo $KERNELVERSION | sed -e 's/^\([0-9][0-9]*\)\.\([0-9][0-9]*\).*$/\1 \2/g')) ;; esac } report_capabilities_unsorted() { report_capability() # $1 = Capability Description , $2 Capability Setting (if any) { local setting setting= [ "x$2" = "xYes" ] && setting="Available" || setting="Not available" echo " " $1: $setting } report_capability "NAT (NAT_ENABLED)" $NAT_ENABLED report_capability "Packet Mangling (MANGLE_ENABLED)" $MANGLE_ENABLED report_capability "Multi-port Match (MULTIPORT)" $MULTIPORT [ -n "$MULTIPORT" ] && report_capability "Extended Multi-port Match (XMULIPORT)" $XMULTIPORT [ -n "$EMULTIPORT" ] && report_capability "Enhanced Multi-port Match (EMULIPORT)" $EMULTIPORT report_capability "Connection Tracking Match (CONNTRACK_MATCH)" $CONNTRACK_MATCH if [ -n "$CONNTRACK_MATCH" ]; then report_capability "Extended Connection Tracking Match Support (NEW_CONNTRACK_MATCH)" $NEW_CONNTRACK_MATCH [ -n "$OLD_CONNTRACK_MATCH" ] && report_capability "Old Connection Tracking Match Syntax (OLD_CONNTRACK_MATCH)" $OLD_CONNTRACK_MATCH fi report_capability "Policy Match (POLICY_MATCH)" $POLICY_MATCH report_capability "Physdev Match (PHYSDEV_MATCH)" $PHYSDEV_MATCH report_capability "Physdev-is-bridged Support (PHYSDEV_BRIDGE)" $PHYSDEV_BRIDGE report_capability "Packet length Match (LENGTH_MATCH)" $LENGTH_MATCH report_capability "IP range Match(IPRANGE_MATCH)" $IPRANGE_MATCH report_capability "Recent Match (RECENT_MATCH)" $RECENT_MATCH [ -n "$RECENT_MATCH" ] && report_capability 'Recent Match "--reap" option (REAP_OPTION)' $REAP_OPTION report_capability "Owner Match (OWNER_MATCH)" $OWNER_MATCH report_capability "Owner Name Match (OWNER_NAME_MATCH)" $OWNER_NAME_MATCH report_capability "Ipset Match (IPSET_MATCH)" $IPSET_MATCH if [ -n "$IPSET_MATCH" ]; then [ -n "$OLD_IPSET_MATCH" ] && report_capability "OLD_Ipset Match (OLD_IPSET_MATCH)" $OLD_IPSET_MATCH [ -n "$IPSET_MATCH_NOMATCH" ] && report_capability "Ipset Match Nomatch (IPSET_MATCH_NOMATCH)" $IPSET_MATCH_NOMATCH [ -n "$IPSET_MATCH_NOMATCH" ] && report_capability "Ipset Match Counters (IPSET_MATCH_COUNTERS)" $IPSET_MATCH_COUNTERS fi report_capability "CONNMARK Target (CONNMARK)" $CONNMARK [ -n "$CONNMARK" ] && report_capability "Extended CONNMARK Target (XCONNMARK)" $XCONNMARK report_capability "Connmark Match (CONNMARK_MATCH)" $CONNMARK_MATCH [ -n "$CONNMARK_MATCH" ] && report_capability "Extended Connmark Match (XCONNMARK_MATCH)" $XCONNMARK_MATCH report_capability "Raw Table (RAW_TABLE)" $RAW_TABLE report_capability "IPP2P Match (IPP2P_MATCH)" $IPP2P_MATCH [ -n "$OLD_IPP2P_MATCH" ] && report_capability "Old IPP2P Match Syntax (OLD_IPP2P_MATCH)" $OLD_IPP2P_MATCH report_capability "CLASSIFY Target (CLASSIFY_TARGET)" $CLASSIFY_TARGET report_capability "Extended REJECT (ENHANCED_REJECT)" $ENHANCED_REJECT report_capability "Repeat match (KLUDGEFREE)" $KLUDGEFREE report_capability "MARK Target (MARK)" $MARK [ -n "$MARK" ] && report_capability "Extended MARK Target (XMARK)" $XMARK [ -n "$XMARK" ] && report_capability "Extended MARK Target 2 (EXMARK)" $EXMARK report_capability "Mangle FORWARD Chain (MANGLE_FORWARD)" $MANGLE_FORWARD report_capability "Comments (COMMENTS)" $COMMENTS report_capability "Address Type Match (ADDRTYPE)" $ADDRTYPE report_capability "TCPMSS Match (TCPMSS_MATCH)" $TCPMSS_MATCH report_capability "Hashlimit Match (HASHLIMIT_MATCH)" $HASHLIMIT_MATCH [ -n "$OLD_HL_MATCH" ] && report_capability "Old Hashlimit Match (OLD_HL_MATCH)" $OLD_HL_MATCH report_capability "NFQUEUE Target (NFQUEUE_TARGET)" $NFQUEUE_TARGET report_capability "Realm Match (REALM_MATCH)" $REALM_MATCH report_capability "Helper Match (HELPER_MATCH)" $HELPER_MATCH report_capability "Connlimit Match (CONNLIMIT_MATCH)" $CONNLIMIT_MATCH report_capability "Time Match (TIME_MATCH)" $TIME_MATCH report_capability "Goto Support (GOTO_TARGET)" $GOTO_TARGET report_capability "LOGMARK Target (LOGMARK_TARGET)" $LOGMARK_TARGET report_capability "IPMARK Target (IPMARK_TARGET)" $IPMARK_TARGET report_capability "LOG Target (LOG_TARGET)" $LOG_TARGET report_capability "ULOG Target (ULOG_TARGET)" $ULOG_TARGET report_capability "NFLOG Target (NFLOG_TARGET)" $NFLOG_TARGET report_capability "Persistent SNAT (PERSISTENT_SNAT)" $PERSISTENT_SNAT report_capability "TPROXY Target (TPROXY_TARGET)" $TPROXY_TARGET report_capability "FLOW Classifier (FLOW_FILTER)" $FLOW_FILTER report_capability "fwmark route mask (FWMARK_RT_MASK)" $FWMARK_RT_MASK report_capability "Mark in the filter table (MARK_ANYWHERE)" $MARK_ANYWHERE report_capability "Header Match (HEADER_MATCH)" $HEADER_MATCH report_capability "ACCOUNT Target (ACCOUNT_TARGET)" $ACCOUNT_TARGET report_capability "AUDIT Target (AUDIT_TARGET)" $AUDIT_TARGET report_capability "ipset V5 (IPSET_V5)" $IPSET_V5 report_capability "Condition Match (CONDITION_MATCH)" $CONDITION_MATCH report_capability "Statistic Match (STATISTIC_MATCH)" $STATISTIC_MATCH report_capability "IMQ Target (IMQ_TARGET)" $IMQ_TARGET report_capability "DSCP Match (DSCP_MATCH)" $DSCP_MATCH report_capability "DSCP Target (DSCP_TARGET)" $DSCP_TARGET report_capability "Geo IP Match (GEOIP_MATCH)" $GEOIP_MATCH report_capability "RPFilter Match (RPFILTER_MATCH)" $RPFILTER_MATCH report_capability "NFAcct Match" $NFACCT_MATCH report_capability "Checksum Target (CHECKSUM_TARGET)" $CHECKSUM_TARGET report_capability "Arptables JF (ARPTABLESJF)" $ARPTABLESJF report_capability "MASQUERADE Target (MASQUERADE_TGT)" $MASQUERADE_TGT report_capability "UDPLITE Port Redirection (UDPLITEREDIRECT)" $UDPLITEREDIRECT report_capability "New tos Match (NEW_TOS_MATCH)" $NEW_TOS_MATCH report_capability "TARPIT Target (TARPIT_TARGET)" $TARPIT_TARGET report_capability "Iface Match (IFACE_MATCH)" $IFACE_MATCH report_capability "TCPMSS Target (TCPMSS_TARGET)" $TCPMSS_TARGET report_capability "Amanda Helper" $AMANDA_HELPER report_capability "FTP Helper" $FTP_HELPER report_capability "FTP-0 Helper" $FTP0_HELPER report_capability "IRC Helper" $IRC_HELPER report_capability "IRC-0 Helper" $IRC0_HELPER report_capability "Netbios_ns Helper" $NETBIOS_NS_HELPER report_capability "H323 Helper" $H323_HELPER report_capability "PPTP Helper" $PPTP_HELPER report_capability "SANE Helper" $SANE_HELPER report_capability "SANE-0 Helper" $SANE0_HELPER report_capability "SIP Helper" $SIP_HELPER report_capability "SIP-0 Helper" $SIP0_HELPER report_capability "SNMP Helper" $SNMP_HELPER report_capability "TFTP Helper" $TFTP_HELPER report_capability "TFTP-0 Helper" $TFTP0_HELPER if [ $g_family -eq 4 ]; then report_capability "iptables -S (IPTABLES_S)" $IPTABLES_S report_capability "iptables --wait option (WAIT_OPTION)" $WAIT_OPTION report_capability "iptables-restore --wait option (RESTORE_WAIT_OPTION)" $RESTORE_WAIT_OPTION else report_capability "ip6tables -S (IPTABLES_S)" $IPTABLES_S report_capability "ip6tables --wait option (WAIT_OPTION)" $WAIT_OPTION report_capability "ip6tables-restore --wait option (RESTORE_WAIT_OPTION)" $RESTORE_WAIT_OPTION fi report_capability "Basic Filter (BASIC_FILTER)" $BASIC_FILTER report_capability "Basic Ematch (BASIC_EMATCH)" $BASIC_EMATCH report_capability "CT Target (CT_TARGET)" $CT_TARGET report_capability "NFQUEUE CPU Fanout (CPU_FANOUT)" $CPU_FANOUT report_capability "NETMAP Target (NETMAP_TARGET)" $NETMAP_TARGET report_capability "--nflog-size support (NFLOG_SIZE)" $NFLOG_SIZE report_capability "INPUT chain in nat table (NAT_INPUT_CHAIN)" $NAT_INPUT_CHAIN echo " Kernel Version (KERNELVERSION): $KERNELVERSION" echo " Capabilities Version (CAPVERSION): $CAPVERSION" } report_capabilities() { if [ $VERBOSITY -gt 1 ]; then echo "$g_product has detected the following iptables/netfilter capabilities:" report_capabilities_unsorted | sort fi } report_capabilities_unsorted1() { report_capability1() # $1 = Capability { eval echo $1=\$$1 } report_capability1 NAT_ENABLED report_capability1 MANGLE_ENABLED report_capability1 MULTIPORT report_capability1 XMULTIPORT report_capability1 EMULTIPORT report_capability1 CONNTRACK_MATCH report_capability1 NEW_CONNTRACK_MATCH report_capability1 OLD_CONNTRACK_MATCH report_capability1 POLICY_MATCH report_capability1 PHYSDEV_MATCH report_capability1 PHYSDEV_BRIDGE report_capability1 LENGTH_MATCH report_capability1 IPRANGE_MATCH report_capability1 RECENT_MATCH report_capability1 REAP_OPTION report_capability1 OWNER_MATCH report_capability1 OWNER_NAME_MATCH report_capability1 IPSET_MATCH report_capability1 OLD_IPSET_MATCH report_capability1 IPSET_MATCH_NOMATCH report_capability1 IPSET_MATCH_COUNTERS report_capability1 CONNMARK report_capability1 XCONNMARK report_capability1 CONNMARK_MATCH report_capability1 XCONNMARK_MATCH report_capability1 RAW_TABLE report_capability1 IPP2P_MATCH report_capability1 OLD_IPP2P_MATCH report_capability1 CLASSIFY_TARGET report_capability1 ENHANCED_REJECT report_capability1 KLUDGEFREE report_capability1 MARK report_capability1 XMARK report_capability1 EXMARK report_capability1 MANGLE_FORWARD report_capability1 COMMENTS report_capability1 ADDRTYPE report_capability1 TCPMSS_MATCH report_capability1 HASHLIMIT_MATCH report_capability1 OLD_HL_MATCH report_capability1 NFQUEUE_TARGET report_capability1 REALM_MATCH report_capability1 HELPER_MATCH report_capability1 CONNLIMIT_MATCH report_capability1 TIME_MATCH report_capability1 GOTO_TARGET report_capability1 LOGMARK_TARGET report_capability1 IPMARK_TARGET report_capability1 LOG_TARGET report_capability1 ULOG_TARGET report_capability1 NFLOG_TARGET report_capability1 PERSISTENT_SNAT report_capability1 TPROXY_TARGET report_capability1 FLOW_FILTER report_capability1 FWMARK_RT_MASK report_capability1 MARK_ANYWHERE report_capability1 HEADER_MATCH report_capability1 ACCOUNT_TARGET report_capability1 AUDIT_TARGET report_capability1 IPSET_V5 report_capability1 CONDITION_MATCH report_capability1 IPTABLES_S report_capability1 BASIC_FILTER report_capability1 BASIC_EMATCH report_capability1 CT_TARGET report_capability1 STATISTIC_MATCH report_capability1 IMQ_TARGET report_capability1 DSCP_MATCH report_capability1 DSCP_TARGET report_capability1 GEOIP_MATCH report_capability1 RPFILTER_MATCH report_capability1 NFACCT_MATCH report_capability1 CHECKSUM_TARGET report_capability1 ARPTABLESJF report_capability1 MASQUERADE_TGT report_capability1 UDPLITEREDIRECT report_capability1 NEW_TOS_MATCH report_capability1 TARPIT_TARGET report_capability1 IFACE_MATCH report_capability1 TCPMSS_TARGET report_capability1 WAIT_OPTION report_capability1 CPU_FANOUT report_capability1 NETMAP_TARGET report_capability1 NFLOG_SIZE report_capability1 RESTORE_WAIT_OPTION report_capability1 NAT_INPUT_CHAIN report_capability1 AMANDA_HELPER report_capability1 FTP_HELPER report_capability1 FTP0_HELPER report_capability1 IRC_HELPER report_capability1 IRC0_HELPER report_capability1 NETBIOS_NS_HELPER report_capability1 H323_HELPER report_capability1 PPTP_HELPER report_capability1 SANE_HELPER report_capability1 SANE0_HELPER report_capability1 SIP_HELPER report_capability1 SIP0_HELPER report_capability1 SNMP_HELPER report_capability1 TFTP_HELPER report_capability1 TFTP0_HELPER echo CAPVERSION=$SHOREWALL_CAPVERSION echo KERNELVERSION=$KERNELVERSION } report_capabilities1() { echo "#" echo "# $g_product $SHOREWALL_VERSION detected the following iptables/netfilter capabilities - $(date)" echo "#" report_capabilities_unsorted1 | sort } interface_status() { case $(cat $1) in 0) echo Enabled ;; 1) echo Disabled ;; *) echo Unknown ;; esac } show_interfaces() { local f local interface local printed for f in ${VARDIR}/*.status; do if [ -f $f ]; then interface=$(basename $f) echo " Interface ${interface%.status} is $(interface_status $f)" printed=Yes fi done [ -n "$printed" ] && echo } status_command() { local finished finished=0 local option local interfaces while [ $finished -eq 0 -a $# -gt 0 ]; do option=$1 case $option in -*) option=${option#-} while [ -n "$option" ]; do case $option in -) finished=1 option= ;; i*) interfaces=Yes option=${option#i} ;; *) option_error $option ;; esac done shift ;; *) finished=1 ;; esac done [ $# -eq 0 ] || missing_argument [ $VERBOSITY -ge 1 ] && echo "${g_product}-$SHOREWALL_VERSION Status at $g_hostname - $(date)" && echo show_status [ -n "$interfaces" ] && show_interfaces exit $status } drop_command() { if product_is_started ; then if ! chain_exists dynamic; then echo "Dynamic blacklisting is not supported in the current $g_product configuration" exit 2 fi [ -n "$g_nolock" ] || mutex_on block DROP Dropped $* [ -n "$g_nolock" ] || mutex_off else fatal_error "$g_product is not started" fi } logdrop_command() { if product_is_started ; then if ! chain_exists dynamic; then echo "Dynamic blacklisting is not supported in the current $g_product configuration" exit 2 fi [ -n "$g_nolock" ] || mutex_on block logdrop Dropped $* [ -n "$g_nolock" ] || mutex_off else fatal_error "$g_product is not started" fi } reject_command() { if product_is_started ; then [ -n "$g_nolock" ] || mutex_on block $1 Rejected $* [ -n "$g_nolock" ] || mutex_off else fatal_error "$g_product is not started" fi } blacklist_command() { local family local timeout [ $# -gt 0 ] || fatal_error "Missing address" [ -z "$g_blacklistipset" ] && fatal_error "The blacklist command is not supported in the current $g_product configuration" case ${IPSET:=ipset} in */*) if [ ! -x "$IPSET" ]; then fatal_error "IPSET=$IPSET does not exist or is not executable" fi ;; *) IPSET="$(mywhich $IPSET)" [ -n "$IPSET" ] || fatal_error "The ipset utility cannot be located" ;; esac if [ $COMMAND = 'blacklist!' ]; then timeout='timeout 0' else echo "$@" | fgrep -q ' timeout ' || timeout="timeout $g_dbltimeout" fi if $IPSET -A $g_blacklistipset $@ $timeout -exist; then local message progress_message2 "$1 Blacklisted" [ -n "$g_dbllog" ] && mylogger daemon.info "$g_product: $1 Blacklisted" if [ -n "$g_disconnect" ]; then message="$(conntrack -D -s $1 2>&1)" if [ -n "$message" -a $VERBOSITY -gt 0 ]; then if [ $VERBOSITY -gt 1 ]; then echo "$message" | awk '/have been deleted/ { sub( /^.*: /, "" ); sub( / /, " src " ); }; { print; }' else echo "$message" | head -n1 | sed 's/^.*: //; s/ / src /' fi fi if [ $g_disconnect = src-dst ]; then message="$(conntrack -D -d $1 2>&1)" if [ -n "$message" -a $VERBOSITY -gt 0 ]; then if [ $VERBOSITY -gt 1 ]; then echo "$message" | awk '/have been deleted/ { sub( /^.*: /, "" ); sub( / /, " dst " ); }; { print; }' else echo "$message" | head -n1 | sed 's/^.*: //; s/ / dst /' fi fi fi fi else error_message "ERROR: Address $1 not blacklisted" return 1 fi return 0 } save_command() { local finished finished=0 shift while [ $finished -eq 0 -a $# -gt 0 ]; do option=$1 case $option in -*) option=${option#-} while [ -n "$option" ]; do case $option in -) finished=1 option= ;; C*) g_counters=Yes option=${option#C} ;; *) option_error $option ;; esac done shift ;; *) finished=1 ;; esac done case $# in 0) ;; 1) RESTOREFILE="$1" validate_restorefile '' ;; *) too_many_arguments $2 ;; esac g_restorepath=${VARDIR}/$RESTOREFILE [ -n "$g_nolock" ] || mutex_on save_config result=$? [ -n "$g_nolock" ] || mutex_off exit $result } forget_command() { case $# in 0) missing_argument ;; 1) ;; 2) RESTOREFILE="$2" validate_restorefile '' ;; *) too_many_arguments $3 ;; esac g_restorepath=${VARDIR}/$RESTOREFILE if [ -x $g_restorepath ]; then rm -f $g_restorepath rm -f ${g_restorepath}-iptables rm -f ${g_restorepath}-ipsets rm -f ${g_restorepath}-arptables echo " $g_restorepath removed" elif [ -f $g_restorepath ]; then echo " $g_restorepath exists and is not a saved $g_product configuration" fi rm -f ${VARDIR}/save } ipcalc_command() { local address local vlsm [ $g_family -eq 6 ] && fatal_error "$g_product does not support the ipcalc command" if [ $# -eq 2 ]; then address=${2%/*} vlsm=${2#*/} elif [ $# -eq 3 ]; then address=$2 vlsm=$(ip_vlsm $3) elif [ $# -eq 1 ]; then missing_argument else too_many_arguments $4 fi valid_address $address || fatal_error "Invalid IP address: $address" [ -z "$vlsm" ] && fatal_error "Missing VLSM" [ "x$address" = "x$vlsm" ] && fatal_error "Invalid VLSM" [ $vlsm -gt 32 ] && fatal_error "Invalid VLSM: /$vlsm" address=$address/$vlsm echo " CIDR=$address" temp=$(ip_netmask $address); echo " NETMASK=$(encodeaddr $temp)" temp=$(ip_network $address); echo " NETWORK=$temp" temp=$(broadcastaddress $address); echo " BROADCAST=$temp" } iprange_command() { local range [ $g_family -eq 6 ] && fatal_error "$g_product does not support the iprange command" range='' while [ $# -gt 0 ]; do shift range="${range}${1}" done case $range in *.*.*.*-*.*.*.*) for address in ${range%-*} ${range#*-}; do valid_address $address || fatal_error "Invalid IP address: $address" done ip_range $range ;; *) fatal_error "Invalid ip range: $range" ;; esac } ipdecimal_command() { if [ $# -eq 1 ]; then missing_argument else [ $# -eq 2 ] || too_many_arguments $3 fi [ $g_family -eq 6 ] && fatal_error "$g_product does not support the iprange command" case $2 in *.*.*.*) valid_address $2 || fatal_error "Invalid IP address: $2" echo " $(decodeaddr $2)" ;; *) echo " $(encodeaddr $2)" ;; esac } iptrace_command() { if product_is_started ; then $g_tool -t raw -A PREROUTING $@ -j TRACE $g_tool -t raw -A OUTPUT $@ -j TRACE else fatal_error "$g_product is not started" fi } noiptrace_command() { if product_is_started ; then $g_tool -t raw -D PREROUTING $@ -j TRACE $g_tool -t raw -D OUTPUT $@ -j TRACE else fatal_error "$g_product is not started" fi } # # Verify that we have a compiled firewall script # verify_firewall_script() { if [ ! -f $g_firewall ]; then echo " ERROR: $g_product is not properly installed" >&2 if [ -h $g_firewall ]; then echo " $g_firewall is a symbolic link to a" >&2 echo " non-existant file" >&2 else echo " The file $g_firewall does not exist" >&2 fi exit 2 fi } setup_dbl() { local original original=$DYNAMIC_BLACKLIST case $DYNAMIC_BLACKLIST in *:*,) fatal_error "Invalid value ($original) for DYNAMIC_BLACKLIST" ;; ipset*,disconnect*) if qt mywhich conntrack; then g_disconnect=src DYNAMIC_BLACKLIST=$(echo $DYNAMIC_BLACKLIST | sed 's/,disconnect//') else fatal_error "The 'disconnect' option requires that the conntrack utility be installed" fi ;; esac case $DYNAMIC_BLACKLIST in ipset*,src-dst*) # # Capture 'src-dst' # DYNAMIC_BLACKLIST=$(echo $DYNAMIC_BLACKLIST | sed 's/,src-dst//') [ -n "$g_disconnect" ] && g_disconnect=src-dst ;; esac case $DYNAMIC_BLACKLIST in ipset*,log*) # # Capture 'log' # DYNAMIC_BLACKLIST=$(echo $DYNAMIC_BLACKLIST | sed 's/,log//') g_dbllog=Yes ;; esac case $DYNAMIC_BLACKLIST in ipset*,noupdate*) # # This utility doesn't use this option # DYNAMIC_BLACKLIST=$(echo $DYNAMIC_BLACKLIST | sed 's/,noupdate//') ;; esac case $DYNAMIC_BLACKLIST in ipset*,timeout*) # # Capture timeout # local ifs local f ifs=$IFS IFS=',' for f in $DYNAMIC_BLACKLIST; do case $f in timeout=*) g_dbltimeout=${f#timeout=} g_dbltimeout=${g_dbltimeout%%:*} break ;; esac done IFS=$ifs DYNAMIC_BLACKLIST=$(echo $DYNAMIC_BLACKLIST | sed -r 's/,timeout=[[:digit:]]+//') ;; esac case $DYNAMIC_BLACKLIST in [Nn]o) DYNAMIC_BLACKLIST=''; ;; [Yy]es) ;; ipset|ipset::*|ipset-only|ipset-only::*) g_blacklistipset=SW_DBL$g_family ;; ipset:[a-zA-Z]*) g_blacklistipset=${DYNAMIC_BLACKLIST#ipset:} g_blacklistipset=${g_blacklistipset%%:*} ;; ipset-only:[a-zA-Z]*) g_blacklistipset=${DYNAMIC_BLACKLIST#ipset-only:} g_blacklistipset=${g_blacklistipset%%:*} ;; *) fatal_error "Invalid value ($original) for DYNAMIC_BLACKLIST" ;; esac } ################################################################################ # The remaining functions are used by the Lite cli - they are overloaded by # the Standard CLI by loading lib.cli-std ################################################################################ # # Set the configuration variables from shorewall[6]-lite.conf. # get_config() { local config local lib ensure_config_path config=$(find_file ${PRODUCT}.conf) if [ -f $config ]; then if [ -r $config ]; then . $config else fatal_error "Cannot read $config! (Hint: Are you root?)" fi else fatal_error "$config does not exist!" fi ensure_config_path [ -f $g_firewall.conf ] && . ${VARDIR}/firewall.conf [ -n "$PATH" ] || PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin setup_logread # # See if we have a real version of "tail" -- use separate redirection so # that ash (aka /bin/sh on LRP) doesn't crap # if ( tail -n5 /dev/null > /dev/null 2> /dev/null ) ; then realtail="Yes" else realtail="" fi [ -n "$FW" ] || FW=fw if [ $g_family -eq 4 ]; then if [ -n "$IPTABLES" ]; then if [ ! -x "$IPTABLES" ]; then fatal_error "The program specified in IPTABLES does not exist or is not executable" fi else IPTABLES=$(mywhich iptables 2> /dev/null) if [ -z "$IPTABLES" ] ; then fatal_error "Can't find iptables executable" fi fi g_tool=$IPTABLES else if [ -n "$IP6TABLES" ]; then if [ ! -x "$IP6TABLES" ]; then fatal_error "The program specified in IP6TABLES does not exist or is not executable" fi else IP6TABLES=$(mywhich ip6tables 2> /dev/null) if [ -z "$IP6TABLES" ] ; then fatal_error "Can't find ip6tables executable" fi fi g_tool=$IP6TABLES fi if [ -n "$SHOREWALL_SHELL" ]; then if [ ! -x "$SHOREWALL_SHELL" ]; then echo " WARNING: The program specified in SHOREWALL_SHELL does not exist or is not executable; falling back to /bin/sh" >&2 SHOREWALL_SHELL=/bin/sh fi fi [ -n "$RESTOREFILE" ] || RESTOREFILE=restore validate_restorefile RESTOREFILE [ -n "${VERBOSITY:=2}" ] [ -n "$g_use_verbosity" ] && VERBOSITY=$g_use_verbosity || VERBOSITY=$(($g_verbose_offset + $VERBOSITY)) if [ $VERBOSITY -lt -1 ]; then VERBOSITY=-1 elif [ $VERBOSITY -gt 2 ]; then VERBOSITY=2 fi if qt mywhich hostname; then g_hostname=$(hostname 2> /dev/null) elif qt mywhich uname; then g_hostname=$(uname -n 2> /dev/null) else g_hostname=localhost fi if [ -n "$IPSET" ]; then case "$IPSET" in */*) if [ ! -x "$IPSET" ] ; then fatal_error "The program specified in IPSET ($IPSET) does not exist or is not executable" fi ;; *) prog="$(mywhich $IPSET 2> /dev/null)" if [ -z "$prog" ] ; then fatal_error "Can't find $IPSET executable" fi IPSET=$prog ;; esac else IPSET='' fi if [ -n "$WORKAROUNDS" ]; then case $WORKAROUNDS in [Yy]es) ;; [Nn]o) WORKAROUNDS='' ;; *) fatal_error "Invalid setting ($WORKAROUNDS) for WORKAROUNDS" ;; esac fi TC=tc IP=$(mywhich ip 2> /dev/null) g_loopback=$(find_loopback_interfaces) if [ -z "$g_nopager" ]; then [ -n "$PAGER" ] || PAGER=$DEFAULT_PAGER if [ -n "$PAGER" -a -t 1 ]; then case $PAGER in /*) g_pager="$PAGER" [ -f "$g_pager" ] || fatal_error "PAGER=$PAGER does not exist" ;; *) g_pager=$(mywhich $PAGER 2> /dev/null) [ -n "$g_pager" ] || fatal_error "PAGER=$PAGER does not exist" ;; esac [ -x "$g_pager" ] || fatal_error "PAGER $g_pager is not executable" g_pager="| $g_pager" fi fi if [ -n "$DYNAMIC_BLACKLIST" ]; then setup_dbl fi lib=$(find_file lib.cli-user) [ -f $lib ] && . $lib } # # Start Command Executor # start_command() { local finished finished=0 do_it() { local rc rc=0 [ -n "$g_nolock" ] || mutex_on if [ -x $g_firewall ]; then if [ -n "$g_fast" -a -x ${VARDIR}/${RESTOREFILE} -a ! $g_firewall -nt ${VARDIR}/${RESTOREFILE} ]; then run_it ${VARDIR}/${RESTOREFILE} restore else run_it $g_firewall start fi rc=$? else error_message "$g_firewall is missing or is not executable" mylogger kern.err "ERROR:$g_product start failed" rc=6 fi [ -n "$g_nolock" ] || mutex_off exit $rc } verify_firewall_script if product_is_started; then if [ $g_family -eq 4 ]; then error_message "Shorewall is already running" else error_message "Shorewall6 is already running" fi exit 0 fi while [ $finished -eq 0 -a $# -gt 0 ]; do option=$1 case $option in -*) option=${option#-} while [ -n "$option" ]; do case $option in -) finished=1 option= ;; f*) g_fast=Yes option=${option#f} ;; C*) g_counters=Yes option=${option#C} ;; p*) [ -n "$(which conntrack)" ] || fatal_error "The '-p' option requires the conntrack utility which does not appear to be installed on this system" g_purge=Yes option=${option%p} ;; *) option_error $option ;; esac done shift ;; *) finished=1 ;; esac done case $# in 0) ;; *) too_many_arguments $1 ;; esac do_it } # # Reload/Restart Command Executor # restart_command() { local finished finished=0 local rc rc=0 verify_firewall_script while [ $finished -eq 0 -a $# -gt 0 ]; do option=$1 case $option in -*) option=${option#-} while [ -n "$option" ]; do case $option in -) finished=1 option= ;; n*) g_noroutes=Yes option=${option#n} ;; p*) [ -n "$(mywhich conntrack)" ] || fatal_error "The '-p' option requires the conntrack utility which does not appear to be installed on this system" g_purge=Yes option=${option%p} ;; C*) g_counters=Yes option=${option#C} ;; *) option_error $option ;; esac done shift ;; *) finished=1 ;; esac done case $# in 0) ;; *) too_many_arguments $1 ;; esac [ -n "$g_nolock" ] || mutex_on if [ -x $g_firewall ]; then run_it $g_firewall $COMMAND rc=$? else error_message "$g_firewall is missing or is not executable" mylogger kern.err "ERROR:$g_product $COMMAND failed" rc=6 fi [ -n "$g_nolock" ] || mutex_off return $rc } run_command() { if [ -x $g_firewall ] ; then run_it $g_firewall $@ else fatal_error "$g_firewall does not exist or is not executable" fi } # # Echo the parameters if product is Shorewall or Shorewall6 # ecko() { [ -z "$g_lite" ] && echo "$@" } # # Give Usage Information # usage() # $1 = exit status { echo "Usage: $(basename $0) [ -T ] [ -D ] [ -N ] [ -q ] [ -v[-1|{0-2}] ] [ -t ] " echo " -T : Direct the generated script to produce a shell trace to standard error" echo " -D : Debug iptables commands" echo " -N : Don't take the master shorewall lock" echo " -q : Standard Shorewall verbosity control" echo " -v : Standard Shorewall verbosity control" echo " -t : Timestamp all messages" echo "where is one of:" echo " add [:] ... " echo " allow
..." echo " blacklist
[