commit a0290e96c9aa2a7feff667b653a5ab9f2094e3c9 Author: Christoph Date: Tue Feb 21 02:29:25 2017 +0100 Initial import diff --git a/iptables_manage_chain.sh b/iptables_manage_chain.sh new file mode 100755 index 0000000..e66a410 --- /dev/null +++ b/iptables_manage_chain.sh @@ -0,0 +1,665 @@ +#!/usr/bin/env bash + +ipt=`which /sbin/iptables` + +default_iptables_chain=custom-`hostname -s` + +function usage() { + echo + [ -n "$1" ] && echo -e "Error: $1\n" + +cat< + Adds the given address to chain. Address can be either a network name, + a hostname, a network IP address (with /mask), or a plain IP address. + If no chain ist given on the command line, (default) chain '$default_iptables_chain' + will be used. + + If no chain for adding the address exists, a chain will be created. + + Prints an error, if the given IP address already exist in chain. + + -F + Cleanup (flush) the chain. All entries for blocking ip-addresises will + be removed from chain + + -f + Reads 'Deny from
' directives from apache style .htaccess file + and adds each found address to chain. + + If no chain for adding the address exists, a chain will be created. + + -h + Prints this help. + + -L + Only affected in conjuction with '-N'. If '-L' is given, an additional + chains for logging the bloccking action into file '/var/log/debug' will + be created. + + -N + Creates a new chain. If no chain is given on the command-line, + chain '$default_iptables_chain' will be created. + + Prints an error, if chain already exist. + + -S + Show a list of dropped ip-addresses by chain. If no chain is given on + the command-line, chain '$default_iptables_chain' will be listed. + + Prints an error, if chain does not exist. + + -X + Deletes a chain. If no chain is given on the command-line, + chain '$default_iptables_chain' will be deleted. + + Prints an error, if chain does not exist. + + -x + Deletes the given address from chain. Address can be either + a network name, a hostname, a network IP address (with /mask), or a plain + IP address. If no chain ist given on the command line, (default) chain + '$default_iptables_chain' will be used. + + Prints an error, if chain does not exist. + Prints also an error, if the given IP address does not exist in chain. + + Example: + + Create a new chain with logging enabled using default name ($default_iptables_chain) + + `basename $0` -L -N + + Create a new chain called 'drop-custom' without logging enabled: + + `basename $0` -N drop-custom + + Add address(es) to block '54.72.0.0/13' (Amazon) to chain 'drop-custom' + + `basename $0` -a 54.72.0.0/13 drop-custom + + Read addresses to block, given as directive in apache style from, file. Add + these addresse to (default) chain '$default_iptables_chain' + + `basename $0` -f /vservers/nd/var/www/html/projekte/nd/htdocs/.htaccess + +EOF +exit 1 +} + + +get_help=false +add_to_chain=false +cleanup_chain=false +read_htaccess_file=false +log_firewall=false +create_chain=false +list_chain=false +drop_chain=false +delete_from_chain=false +while getopts a:Ff:hLNSXx: opt ; do + case $opt in + a) add_to_chain=true + _ban_address=$OPTARG + ;; + F) cleanup_chain=true + ;; + f) read_htaccess_file=true + htaccess_file=$OPTARG + ;; + h) get_help=true + usage + ;; + L) log_firewall=true + ;; + N) create_chain=true + ;; + S) list_chain=true + ;; + X) drop_chain=true + ;; + x) delete_from_chain=true + _unban_address=$OPTARG + ;; + \?) usage + esac +done + +shift `expr $OPTIND - 1` + + + +if $add_to_chain ; then + if $create_chain || $list_chain \ + || $drop_chain || $delete_from_chain \ + || $read_htaccess_file || $cleanup_chain ; then + usage "To many arguments!" + fi +elif $create_chain ; then + if $add_to_chain || $list_chain \ + || $drop_chain || $delete_from_chain \ + || $read_htaccess_file || $cleanup_chain ; then + usage "To many arguments!" + fi +elif $list_chain ; then + if $add_to_chain || $create_chain \ + || $drop_chain || $delete_from_chain \ + || $read_htaccess_file || $cleanup_chain ; then + usage "To many arguments!" + fi +elif $drop_chain ; then + if $add_to_chain || $create_chain \ + || $list_chain || $delete_from_chain \ + || $read_htaccess_file || $cleanup_chain ; then + usage "To many arguments!" + fi +elif $delete_from_chain ; then + if $add_to_chain || $create_chain \ + || $list_chain || $drop_chain \ + || $read_htaccess_file || $cleanup_chain ; then + usage "To many arguments!" + fi +elif $read_htaccess_file ; then + if $add_to_chain || $create_chain \ + || $list_chain || $drop_chain \ + || $delete_from_chain || $cleanup_chain ; then + usage "To many arguments!" + fi +elif $cleanup_chain ; then + if $add_to_chain || $create_chain \ + || $list_chain || $drop_chain \ + || $delete_from_chain || $read_htaccess_file ; then + usage "To many arguments!" + fi +fi + +if ! $add_to_chain && ! $create_chain \ + && ! $list_chain && ! $drop_chain \ + && ! $delete_from_chain \ + && ! $read_htaccess_file && ! $cleanup_chain ; then + usage "No options given!" +fi + + + +iptables_chain=$1 +iptables_chain=${iptables_chain:=$default_iptables_chain} +if [ "$iptables_chain" = "$default_iptables_chain" ]; then + echo -e "\n\tNo chain wa given. Using default chain '$iptables_chain'" +else + echo -e "\n\tUsing iptables chain: $iptables_chain" +fi + +## --- Some functions +## --- + +## Check if a given array (parameter 2) contains a given string (parameter 1) +containsElement () { + local e + for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done + return 1 +} + +get_address () { + if [ "$#" != "1" ]; then + return 1 + fi + + _given=$1 + _ip=${_given%/*} + if [ "$_ip" != "$_given" ]; then + _mask=${_given##*/} + fi + + _ip_1=$(echo ${_ip} | tr "." " " | awk '{ print $1 }') + _ip_2=$(echo ${_ip} | tr "." " " | awk '{ print $2 }') + _ip_3=$(echo ${_ip} | tr "." " " | awk '{ print $3 }') + _ip_4=$(echo ${_ip} | tr "." " " | awk '{ print $4 }') + + if [ -z "$_ip_4" ]; then + if [ -n "$_mask" ]; then + return 1 + fi + _ip_4=0 + _mask=24 + if [ -z "$_ip_3" ]; then + _ip_3=0 + _mask=16 + if [ -z "$_ip_2" ]; then + _ip_2=0 + _mask=8 + fi + fi + elif [ "$_ip_4" = "0" ]; then + if [ -z "$_mask" -o "$_mask" = "32" ] ; then + _mask=24 + fi + fi + + _check_address="$_ip_1.$_ip_2.$_ip_3.$_ip_4" + + if [ -n "$_mask" ]; then + _check_address="${_check_address}/$_mask" + fi + + _ip_address=`sipcalc $_check_address | grep -e "Network address" | awk '{print$4}'` + if [ -z "$_ip_address" ]; then + echo -e "\n\tWrong enty\n" + return 1 + elif [ -n "$_mask" ]; then + _ip_address="${_ip_address}/$_mask" + fi + + echo "$_ip_address" + return 0 +} + + +create_chain () { + $ipt -N $iptables_chain > /dev/null 2>&1 + if [ "$?" != "0" ]; then + return 1 + fi + $ipt -A $iptables_chain -j RETURN > /dev/null 2>&1 + if [ "$?" != "0" ]; then + return 1 + fi + #$ipt -I INPUT -p tcp -m multiport --dports http,https -j $iptables_chain > /dev/null 2>&1 + $ipt -I INPUT -p all -j $iptables_chain > /dev/null 2>&1 + if [ "$?" != "0" ]; then + return 1 + fi + + if $log_firewall ; then + $ipt -N ${iptables_chain}-log > /dev/null 2>&1 + if [ "$?" != "0" ]; then + return 1 + fi + $ipt -I ${iptables_chain}-log -j LOG --log-prefix "$iptables_chain: " --log-level debug > /dev/null 2>&1 + if [ "$?" != "0" ]; then + return 1 + fi + $ipt -A ${iptables_chain}-log -j DROP > /dev/null 2>&1 + if [ "$?" != "0" ]; then + return 1 + fi + fi + + return 0 +} + +remove_chain () { + + if `$ipt -n -L ${iptables_chain}-log > /dev/null 2>&1` ; then + $ipt -F ${iptables_chain}-log > /dev/null 2>&1 + if [ "$?" != "0" ]; then + return 1 + fi + fi + + #$ipt -D INPUT -p tcp -m multiport --dports http,https -j $iptables_chain > /dev/null 2>&1 + $ipt -D INPUT -p all -j $iptables_chain + if [ "$?" != "0" ]; then + return 1 + fi + $ipt -F $iptables_chain > /dev/null 2>&1 + if [ "$?" != "0" ]; then + return 1 + fi + + if `$ipt -n -L ${iptables_chain}-log > /dev/null 2>&1` ; then + $ipt -X ${iptables_chain}-log > /dev/null 2>&1 + if [ "$?" != "0" ]; then + return 1 + fi + fi + + $ipt -X $iptables_chain > /dev/null 2>&1 + if [ "$?" != "0" ]; then + return 1 + fi + + return 0 +} + +flush_chain () { + + if `$ipt -n -L ${iptables_chain}-log > /dev/null 2>&1` ; then + $ipt -F ${iptables_chain}-log > /dev/null 2>&1 + if [ "$?" != "0" ]; then + return 1 + fi + fi + $ipt -F $iptables_chain > /dev/null 2>&1 + if [ "$?" != "0" ]; then + return 1 + fi + + return 0 + +} + +echononl(){ + echo X\\c > /tmp/shprompt$$ + if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then + echo "$*\\c" 1>&2 + else + echo -e -n "$*" 1>&2 + fi + rm /tmp/shprompt$$ +} + +info (){ + echo "" + echo -e "\t[ \033[32m\033[1mInfo\033[m ]: $*" + echo "" +} + +warn (){ + echo "" + echo -e "\t[ \033[33m\033[1mWarning\033[m ]: $*" + echo "" +} + +error (){ + echo "" + echo -e "\t[ \033[31m\033[1mError\033[m ]: $*" + echo "" +} + +echo_ok() { + echo -e "\033[60G[ \033[32mok\033[m ]" +} +echo_failed(){ + echo -e "\033[60G[ \033[1;31mfailed\033[m ]" +} +echo_skipped() { + echo -e "\033[60G[ \033[33m\033[1mskipped\033[m ]" +} +## --- +## --- END: functions + +echo + +if $create_chain ; then + echononl "\tCreate Chain '$iptables_chain'.." + if `$ipt -n -L $iptables_chain > /dev/null 2>&1` ; then + echo_skipped + warn "Chain '$iptables_chain' already exists" + else + create_chain + if [ "$?" = "0" ]; then + echo_ok + else + echo_failed + fi + fi + + echo + exit +fi + +if $cleanup_chain ; then + echononl "\tFlush Chain '$iptables_chain'.." + if ! `$ipt -n -L $iptables_chain > /dev/null 2>&1` ; then + echo_failed + error "Chain '$iptables_chain' does not exist!" + else + flush_chain + if [ "$?" = "0" ]; then + echo_ok + else + echo_failed + fi + fi + + echo + exit +fi + +if $drop_chain ; then + echononl "\tDrop Chain '$iptables_chain'.." + if ! `$ipt -n -L $iptables_chain > /dev/null 2>&1` ; then + echo_skipped + warn "Chain '$iptables_chain' does not exist!" + else + remove_chain + if [ "$?" = "0" ]; then + echo_ok + else + echo_failed + fi + fi + + echo + exit +fi + +if $list_chain ; then + echononl "\tList of dropped IPs (Chain '$iptables_chain').." + if ! `$ipt -n -L $iptables_chain > /dev/null 2>&1` ; then + echo_failed + error "Chain '$iptables_chain' does not exist!" + else + echo_ok + echo + + _tmp_file=`mktemp` + if `$ipt -n -L ${iptables_chain}-log > /dev/null 2>&1` ; then + $ipt -n -L $iptables_chain | grep -i -e "^${iptables_chain}-log\ " > $_tmp_file + else + $ipt -n -L $iptables_chain | grep -i -e "^DROP\ " > $_tmp_file + fi + if [ -z "`cat $_tmp_file`" ]; then + warn "No IPs to drop in Chain '$iptables_chain" + else + while IFS='' read -r line || [[ -n $line ]]; do + echo -e "\t$line" + done < $_tmp_file + + rm -f $_tmp_file + fi + echo + fi + echo + exit +fi + +if $add_to_chain ; then + ban_address=`get_address $_ban_address` + if [ "$?" != "0" ];then + error "Given address may be wrong" + exit 1 + fi + + if ! `$ipt -n -L $iptables_chain > /dev/null 2>&1` ; then + warn "Chain '$iptables_chain' does not exist. Trying to create one.." + echononl "\tCreate chain '$iptables_chain'.." + create_chain + if [ "$?" = "0" ]; then + echo_ok + echo + else + echo_failed + echo + exit 1 + fi + fi + + ## - Create empty array + ## - + _ip_banned_arr=() + + echononl "\tAdd IP '$ban_address' to chain '$iptables_chain'.." + if ! `$ipt -n -L $iptables_chain > /dev/null 2>&1` ; then + echo_skipped + error "Chain '$iptables_chain' does not exist!" + else + _ips_banned=`iptables -n -L $iptables_chain | grep -i -e "^DROP\ " | awk '{print$4}'` + for _ip in $_ips_banned ; do + _ip_banned_arr+=($_ip); + done + if containsElement "$ban_address" "${_ip_banned_arr[@]}" ; then + echo_skipped + warn "Chain '$iptables_chain' contains already IP 'ban_address'" + else + if `$ipt -n -L ${iptables_chain}-log > /dev/null 2>&1` ; then + $ipt -I $iptables_chain 1 -s $ban_address -j ${iptables_chain}-log + else + $ipt -I $iptables_chain 1 -s $ban_address -j DROP + fi + if [ "$?" = "0" ]; then + echo_ok + else + echo_failed + fi + fi + fi + + echo + exit +fi + +if $delete_from_chain ; then + unban_address=`get_address $_unban_address` + if [ "$?" != "0" ];then + error "Given address may be wrong" + exit 1 + fi + + ## - Create empty array + ## - + _ip_banned_arr=() + + echononl "\tRemove IP '$unban_address' from chain '$iptables_chain'.." + if ! `$ipt -n -L $iptables_chain > /dev/null 2>&1` ; then + echo_skipped + warn "Chain '$iptables_chain' does not exist!" + else + + ## - Read list of already blocked addresses + ## - + if `$ipt -n -L ${iptables_chain}-log > /dev/null 2>&1` ; then + _ips_banned=`iptables -n -L $iptables_chain | grep "${iptables_chain}-log" | awk '{print$4}'` + else + _ips_banned=`iptables -n -L $iptables_chain | grep -i -e "^DROP\ " | awk '{print$4}'` + fi + + for _ip in $_ips_banned ; do + _ip_banned_arr+=($_ip); + done + + ## - Check if given address is in list of blocked addresses. If + ## - address is not blocked, nothing to do.. + ## - + if ! containsElement "$unban_address" "${_ip_banned_arr[@]}" ; then + echo_skipped + warn "Chain '$iptables_chain' does not caontain IP '$unban_address'" + else + if `$ipt -n -L ${iptables_chain}-log > /dev/null 2>&1` ; then + $ipt -D $iptables_chain -s $unban_address -j ${iptables_chain}-log + else + $ipt -D $iptables_chain -s $unban_address -j DROP + fi + if [ "$?" = "0" ]; then + echo_ok + else + echo_failed + fi + fi + fi + + echo + exit +fi + +if $read_htaccess_file ; then + if [ ! -f "$htaccess_file" ]; then + error "File '$htaccess_file' not found!" + exit 1 + fi + if ! `$ipt -n -L $iptables_chain > /dev/null 2>&1` ; then + warn "Chain '$iptables_chain' does not exist. Trying to create one.." + echononl "\tCreate chain '$iptables_chain'.." + create_chain + if [ "$?" = "0" ]; then + echo_ok + echo + else + echo_failed + echo + exit 1 + fi + fi + + ## - Read adresses from htaccess file + ## - + _ips_to_ban=`cat $htaccess_file | grep -e "^\s*Deny from " | awk '{print$3}'` + + for _ban_address in $_ips_to_ban ; do + echononl "\tAdd IP '$_ban_address' to chain '$iptables_chain'.." + ban_address=`get_address $_ban_address` + if [ "$?" != "0" ];then + echo_failed + error "Given address may be wrong" + continue + fi + + ## - Read list of already blocked addresses + ## - + if `$ipt -n -L ${iptables_chain}-log > /dev/null 2>&1` ; then + _ips_banned=`iptables -n -L $iptables_chain | grep "${iptables_chain}-log" | awk '{print$4}'` + else + _ips_banned=`iptables -n -L $iptables_chain | grep -i -e "^DROP\ " | awk '{print$4}'` + fi + + + ## - Check if given address is in list of blocked addresses. If + ## - address is already in that list, nothing to do.. + ## - + for _ip in $_ips_banned ; do + _ip_banned_arr+=($_ip); + done + if containsElement "$ban_address" "${_ip_banned_arr[@]}" ; then + echo_skipped + warn "Chain '$iptables_chain' contains already IP 'ban_address'" + else + if `$ipt -n -L ${iptables_chain}-log > /dev/null 2>&1` ; then + $ipt -I $iptables_chain 1 -s $ban_address -j ${iptables_chain}-log > /dev/null 2>&1 + else + $ipt -I $iptables_chain 1 -s $ban_address -j DROP > /dev/null 2>&1 + fi + if [ "$?" = "0" ]; then + echo_ok + else + echo_failed + fi + fi + + done + + echo + exit 0 + +fi + +exit 0 + +for _ip in ${_ip_banned_arr[@]} ; do + echo $_ip +done + +exit 0