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