Looking for some feedback on iptables manager script

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi


I have a script that i use to manager my iptables rules, been working on
it a bit, basically for my own use.

I was wondering if I could get some feed back on it suggestions, hints
etc



basically it works on a directory structure to hold the chain for
example

/etc/firewall/DB/<PROFILE>/<TABLE>/<CHAIN>/<RULES>

Profile is optional 
table - corresponds to filter/raw/mangle/nat/...
chain - the default ones and user created ones
rules - are in the format <orderID>Name

where orderID process in

ii<Number>
<number>
aa<number>

all sorted by number

I have used the iptables save and restore to build the changes into a
change file and I use traps to capture any issues and try and put the
tables back to their original state if there is a failure.

I was even thing that i could take the flat files and make then some
sort of tar/bzip/gzip + if you add in some sort of enc + sign you would
end up file a compressed signed file

I have attached the file

thanks

Alex 
#!/bin/dash


# Makefirewall scripts
# uses a file/directory DB to store firewall information
# does an atomic add of rules, using iptables-restore


# Creates a WRKFILE in each directory from the rules
# places all the wrkfiles into a single file 
# and process that with ip[,6]tables-restore
# Any errors will roll back to the original set of rules

#
# Verbose level
# 0x01 - actions
VRBFLG_ACTION=0x01
VERBOSEFLG=${VERBOSEFLG:-"0"}

# Base directory 
BASEDIR=${BASEDIR:-"/etc/firewall"}

# Echo a string and limit it based on the flags
pstr(){
	if [ $(( $VERBOSEFLG & $VRBFLG_ACTION )) -eq 1 ]
	then
		echo $1
	fi
}



# Allow for different policy sets
[ ! -z "$BASE2DIR" ] && BASEDIR="$BASEDIR/$BASE2DIR"

if [ ! -d $BASEDIR ]
then
	pstr "Base directory doesn't exist ($BASEDIR)"
	exit 1
fi

#
# Database directory
DBDIR=${DBDIR:-"./DB"}
DB6DIR=${DB6DIR:-"./DB6"}

#
# DB specific variables names are in ./DB/.variables
VARIABLES=${VARIABLES:-".variables"}

#
# Defined Names
# Names of all the top level 
TABLE_NAMES="filter nat mangle"
TABLE_filter="INPUT OUTPUT FORWARD"
TABLE_nat="PREROUTING POSTROUTING OUTPUT"
TABLE_mangle="PREROUTING INPUT OUTPUT FORWARD POSTROUTING"

TABLE6_NAMES="filter mangle"
TABLE6_filter="INPUT OUTPUT FORWARD"
TABLE6_mangle="PREROUTING INPUT OUTPUT FORWARD POSTROUTING"


# Used in BLOCKED chains
BLOCKED='.blocked'
NOTBLOCKED='.notblocked'


# Chain policy's
POLICY_FILE='.policy'
DEFAULT_POLICY=${DEFAULT_POLICY:-'DROP'}
DEFAULT_CHAIN='.defaultchain'

# Work file name
WRKFILE=${WRKFILE:-'.wrkfile'}

#
# Check for Programs
# Use full paths for the filenames
if [ -x /usr/local/sbin/iptables ]; then
    IPTABLES="/usr/local/sbin/iptables"
else
    IPTABLES="/sbin/iptables"
fi

if [ ! -x $IPTABLES ]
then
	echo "$IPTABLES is not executable"
	exit 1
fi

if [ -x /usr/local/sbin/ip6tables ]; then
    IP6TABLES="/usr/local/sbin/ip6tables"
else
    IP6TABLES="/sbin/ip6tables"
fi

if [ ! -x $IP6TABLES ]
then
	echo "$IP6TABLES is not executable"
	exit 1
fi

if [ -x /usr/local/sbin/iptables-restore ]; then
    IPTABLES_BATCH="/usr/local/sbin/iptables-restore"
else
    IPTABLES_BATCH="/sbin/iptables-restore"
fi

if [ ! -x $IPTABLES_BATCH ]
then
	echo "$IPTABLES_BATCH is not executable"
	exit 1
fi

if [ -x /usr/local/sbin/ip6tables-restore ]; then
    IP6TABLES_BATCH="/usr/local/sbin/ip6tables-restore"
else
    IP6TABLES_BATCH="/sbin/ip6tables-restore"
fi

if [ ! -x $IP6TABLES_BATCH ]
then
	echo "$IP6TABLES_BATCH is not executable"
	exit 1
fi

#if [ $(( $VERBOSEFLG & $VRBFLG_ACTION )) -eq 1 ]
#then
#	IPTABLES_BATCH='>> /tmp/makefirewall.output.debug 2>&1'
#	IP6TABLES_BATCH='>> /tmp/makefirewall.output.debug 2>&1'
#fi

#
# Usage Message
usage (){
	echo $0
	echo "\tcleantables\tClean the iptables tables"
	echo "\tshowtables\tShow the iptables tables"
	echo
	echo "\tsetsecurity\tInsert all the rules (DEFAULT)"
	echo
	echo "\tprocessdirectory\tProcess the current directory"
	echo "\tprocess6directory\tProcess the current directory for ipv6"
	echo
	echo "VARIABLES = name of variables file (.variables)"
	echo "WRKFILE = name of workfile user (.wrkfile)"
	echo "DEFAULT_POLICY = default policy for rules (ACCEPT)"
	echo "DBDIR = directory name where all the rules are. (./DB)"
	echo "DB6DIR = directory name where all the rules are. (./DB6)"
	echo "BASEDIR = directory name program change path to.. (/etc/firewall)"
	echo "BASE2DIR = second level into the DB, allows for profiles.. ('')"
	echo

}

#
# Clean iptables
CleanTables(){

	{ # pipe into iptables-restore

		# Flush and set default Policies First
		for MAINDIR in $TABLE_NAMES; do
			echo "*$MAINDIR"
			echo "-F"
			echo "-X"
			SEC_TABLE="TABLE_$MAINDIR"
			eval "set -- \$$SEC_TABLE"
			for SECDIR do
				echo ":$SECDIR $DEFAULT_POLICY [0:0]"
			done
			echo "COMMIT"
		done
	} | $IPTABLES_BATCH

	{ # pipe into iptables-restore

		# Flush and set default Policies First
		for MAINDIR in $TABLE6_NAMES; do
			echo "*$MAINDIR"
			echo "-F"
			echo "-X"
			SEC_TABLE="TABLE6_$MAINDIR"
			eval "set -- \$$SEC_TABLE"
			for SECDIR do
				echo ":$SECDIR $DEFAULT_POLICY [0:0]"
			done
			echo "COMMIT"
		done
	} | $IP6TABLES_BATCH
}

# Show tables
ShowTables(){
	for MAINDIR in $TABLE_NAMES; do
		pstr "\n=====\nProcessing - table $MAINDIR\n=====\n"
		$IPTABLES -t $MAINDIR -nvL
	done
# IPv6
	for MAINDIR in $TABLE6_NAMES; do
		pstr "\n=====\nProcessing - table6 $MAINDIR\n=====\n"
		$IP6TABLES -t $MAINDIR -nvL
	done
}


#
# Process files in directory
ProcessFiles(){
	# So we can use defined variables we use EVAL

	eval "
		cat <<- EOF
			$(sed "/[[:blank:]]*#/d; /^[[:blank:]]*$/d; s/^\(.*\)#.*$/\\1/; s/^/-A $CHAIN /" \
				$(find ii* ! -name '*.dpkg-old' ! -name '*.dpkg-dist' 2>/dev/null | sort ) \
				$(find [0-9]* ! -name '*.dpkg-old' ! -name '*.dpkg-dist' 2>/dev/null | sort ) \
				$(find aa* ! -name '*.dpkg-old' ! -name '*.dpkg-dist' 2>/dev/null | sort) \
				< /dev/null )
		EOF
	"
}

# Process BLOCK files 
ProcessBlockFiles(){
	if [ -f $BLOCKED ]; then
		eval "
			cat <<- EOF
				$(sed "/[[:blank:]]*#/d; /^[[:blank:]]*\$/d; s/^/-I $CHAIN /g; s/\$/ -j DROP/" $BLOCKED )
			EOF
		"

		# if we have TARPIT use it :)
		grep -q TARPIT /proc/net/ip*_tables_targets > /dev/null 2>&1
		if [ $? -eq 0 ]; then
			eval "
				cat <<- EOF
					$(sed "/[[:blank:]]*#/d; /^[[:blank:]]*\$/d; s/^/-I $CHAIN /g; s/\$/ -p tcp -j TARPIT/" $BLOCKED )
				EOF
			"
		fi
	fi

	if [ -f $NOTBLOCKED ]; then
		eval "
			cat <<- EOF
				$(sed '/[[:blank:]*#/d; /^[[:blank:]]*$/d; s/^/-I $CHAIN /g; s/$/ -j RETURN/' $NOTBLOCKED )
			EOF
		"
	fi

}


#
# Process a ipv4 directory
ProcessDirectory(){
	set +e

	pstr "Working on $MAINDIR $CHAIN"

	{
		echo "*$MAINDIR"
		echo "-F $CHAIN"
		ProcessFiles

		[ "$CHAIN" = "BLOCKED" ] && ProcessBlockFiles


		echo "COMMIT"

	} | tee -a "$IPTNEW" > "$WRKFILE"

	if [ $? -ne 0 ]
	then
		pstr "Current Directory $(pwd)"
		exit 1
	fi
	set -e

}

#
# Process a ipv6 Directory
Process6Directory(){
	set +e

	pstr "Working on $MAINDIR $CHAIN"

	{
		echo "*$MAINDIR"
		echo "-F $CHAIN"

		ProcessFiles

		[ "$CHAIN" = "BLOCKED" ] && ProcessBlockFiles

		echo "COMMIT"

	} | tee -a "$IPTNEW6" > "$WRKFILE"

	if [ $? -ne 0 ]
	then
		pstr "Current Directory $(pwd)"
		exit 1
	fi
	set -e

}

#
# Process the files
SetSecurity(){

	# Change into DBDIR
	if [ -d "$BASEDIR/$DBDIR" ]; then
		cd "$BASEDIR/$DBDIR"
	else
		pstr "\nNo Database Directory ($DBDIR)"
		exit 0
	fi
	

	(
		[ -f ./$VARIABLES ] && . ./$VARIABLES
	
		for MAINDIR in $TABLE_NAMES; do
	
			if [ ! -d $MAINDIR ]; then
				pstr "\nNo Default Directory ($MAINDIR)"
				exit 1
			fi
	
			# Enter table directory
			cd $MAINDIR
	
			# Find all the directories that we are going to process
			SDIRS="$(find -maxdepth 1 -type d ! -name 'CVS' ! -name '.' -printf '%f ' )"
		
			# Process the DEFAULT tables and set their default policy
			{
				echo "*$MAINDIR"
				echo "-F"
				echo "-X"
				for CHAIN in $SDIRS; do
					if [ -f $CHAIN/$POLICY_FILE ]
					then
						POLICY=$(cat $CHAIN/$POLICY_FILE)
						echo ":$CHAIN $POLICY"
					else
						echo ":$CHAIN -"
					fi
				done
				echo "COMMIT"
			} | tee -a "$IPTNEW" > "$WRKFILE"

			# have to process the Chains first and then the rules
			for CHAIN in $SDIRS; do
				# Enter chain Directory
				cd $CHAIN
	
				ProcessDirectory
	
				# Back out chain directory
				cd ..
			done
	
			# Go back a directory from a table directory
			cd ..
		done

		$IPTABLES_BATCH -n < "$IPTNEW"

	)
	if [ $? -ne 0 ]
	then
		exit 1
	fi

	# Change into DBDIR
	if [ -d "$BASEDIR/$DB6DIR" ]; then
		cd "$BASEDIR/$DB6DIR"
	else
		pstr "\nNo Database 6 Directory ($DB6DIR)"
		exit 0
	fi

	(
		[ -f ./$VARIABLES ] && . ./$VARIABLES
	
		for MAINDIR in $TABLE6_NAMES; do
	
			if [ ! -d $MAINDIR ]; then
				pstr "\nNo Default Directory ($MAINDIR)"
				exit 1
			fi
	
			# Enter table directory
			cd $MAINDIR
	
			# Find all the directories that we are going to process
			SDIRS="$(find -maxdepth 1 -type d ! -name 'CVS'  ! -name '.' -printf '%f ' )"
			
			# Process the DEFAULT tables and set their default policy
			{
				echo "*$MAINDIR"
				echo "-F"
				echo "-X"
				for CHAIN in $SDIRS; do
					if [ -f $CHAIN/$POLICY_FILE ]
					then
						POLICY=$(cat $CHAIN/$POLICY_FILE)
						echo ":$CHAIN $POLICY"
					else
						echo ":$CHAIN -"
					fi
				done
				echo "COMMIT"
			} | tee -a "$IPTNEW6"  > "$WRKFILE"

	
			# have to process the Chains first and then the rules for the 
			for CHAIN in $SDIRS; do
				# Enter chain Directory
				cd $CHAIN
	
				Process6Directory
	
				# Back out chain directory
				cd ..
			done
	
			# Go back a directory from table 
			cd ..
		done

		$IP6TABLES_BATCH -n < "$IPTNEW6"
	)
	if [ $? -ne 0 ]
	then
		exit 1
	fi
}


#
# Start of the main script

set +e
# Save current state
IPTSAV="$(tempfile)"
IPTSAV6="$(tempfile)"
iptables-save > $IPTSAV 2> /dev/null
ip6tables-save > $IPTSAV6 2> /dev/null

# new workfiles
IPTNEW="$(tempfile)"
IPTNEW6="$(tempfile)"

# on error exit
set -e
trap "$IPTABLES_BATCH -c < $IPTSAV ;  $IP6TABLES_BATCH -c < $IPTSAV6; rm \"$IPTSAV\" \"$IPTSAV6\" \"$IPTNEW\" \"$IPTNEW6\" " EXIT

#
# change to lower case
ACTION=$( echo $1 | tr A-Z a-z)

# Default action
ACTION=${ACTION:-"setsecurity"}

case $ACTION in
	'cleantables')
		CleanTables
		;;
		
	'showtables')
		ShowTables
		;;

	'setsecurity')
		SetSecurity
		;;

	'processdirectory')
		CHAIN="$(echo $PWD | sed -n 's/.*\/\([^/]*\)/\1/p')"
		MAINDIR="$(echo $PWD| sed -n 's/.*\/\([^/]*\)\/.*/\1/p')"
		$IPTABLES -t $MAINDIR -F $CHAIN
		echo "Chain [$CHAIN]"
		echo "Maindir [$MAINDIR]"
		echo "Pwd [$oldPwd]"
		echo
		(
			[ -f ../../$VARIABLES ] && . ../../$VARIABLES
			ProcessDirectory
			$IPTABLES_BATCH -n < $IPTNEW
		)
		if [ $? -ne 0 ]
		then
			exit 1
		fi
		;;

	'process6directory')
		CHAIN="$(echo $PWD | sed -n 's/.*\/\([^/]*\)/\1/p')"
		MAINDIR="$(echo $PWD| sed -n 's/.*\/\([^/]*\)\/.*/\1/p')"
		$IP6TABLES -t $MAINDIR -F $CHAIN
		echo "Chain [$CHAIN]"
		echo "Maindir [$MAINDIR]"
		echo "Pwd [$oldPwd]"
		echo
		(
			[ -f ../../$VARIABLES ] && . ../../$VARIABLES
			Process6Directory
			$IP6TABLES_BATCH -n < $IPTNEW6
		)
		if [ $? -ne 0 ]
		then
			exit 1
		fi
		;;

	'-h' | '--help')
		usage
		;;
	*)
		usage
		;;
esac


#
# Everything okay do not retore
trap "-" EXIT
rm "$IPTSAV" "$IPTSAV6" "$IPTNEW" "$IPTNEW6"

# Exit
exit 0



Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux