#!/bin/bash
#
# Spot reappearing spammers

# Database file
DATABASE=/tmp/qmail_ip.db

# Max amount of connections to be seen before block
# Set to 0 to disable
LIMIT=0

#  Some output code
COL1=11
COL2=18
COL3=39
COL4=57
COL5=65
COL1="\\033[${COL1}G"
COL2="\\033[${COL2}G"
COL3="\\033[${COL3}G"
COL4="\\033[${COL4}G"
COL5="\\033[${COL5}G"
RED="\\033[0;31m"
GREEN="\\033[0;32m"
YELLOW="\\033[1;33m"
BLUE="\\033[0;34m"
VIOLET="\\033[0;35m"
CYAN="\\033[0;36m"
WHITE="\\033[1;37m"
NORMAL="\033[0m"

# Trap STRG+C and SIGTERM to start exit_ instead
trap 'exit_' 2
trap 'exit_' SIGTERM

function parser {
	# read input from STDIN
	# Parse line for spamdyke output
	while read Time Program Line; do
		if [[ $Line =~ "(.*) (from.*)? origin_ip: (.*) origin_rdns: (.*) auth" ]]; then
			addlist "${BASH_REMATCH[3]}" "${BASH_REMATCH[4]}" "${BASH_REMATCH[1]}"
		fi
	done
}

function addlist() {
	local IP=$1
	local RDNS=$2
	local TYPE=$3

	# is IP in database already
	if COUNT=`grep -w "$IP" $DATABASE`; then
		# Get the counter
		COUNT=${COUNT##*:}
		# Is it not firewalled already ...
		if [[ $COUNT != "X" ]]; then
			# ... then increase its count
			((COUNT=$COUNT+1))
			if [[ $COUNT -ge $LIMIT && $LIMIT != 0 ]]; then
				# it should be firewalled
				((IPTABLES=$IPTABLES+1))
				echo -e "${RED}iptables${NORMAL}${COL2}${WHITE}${TYPE}${NORMAL}${COL3}${IP}${COL5}$RDNS" 
				iptables -I SPAMDYKE-Filter-INPUT 1 -s $IP -j REJECT --reject-with icmp-host-prohibited
				sed -i "s/$IP:.*/$IP:X/" $DATABASE
			else
				# increase counter in database
				((MATCHED=$MATCHED+1))
				echo -e "${YELLOW}found${NORMAL}${COL1}${MATCHED}${COL2}${WHITE}${TYPE}${NORMAL}${COL3}${IP}${COL4}${COUNT}${COL5}${RDNS}" 
				sed -i "s/$IP:.*/$IP:$COUNT/" $DATABASE
			fi
		fi
	else
		# stats
		case $TYPE in
			ALLOWED)
				((OK=$OK+1))
				echo -e "${GREEN}ok${NORMAL}${COL1}${OK}${COL2}${WHITE}${TYPE}${NORMAL}${COL3}${IP}${COL5}${RDNS}"
			;;
			DENIED_GRAYLISTED)
				((GRAYLISTED=$GRAYLISTED+1))
				echo -e "${VIOLET}graylist${NORMAL}${COL1}${GRAYLISTED}${COL2}${WHITE}${TYPE}${NORMAL}${COL3}${IP}${COL5}${RDNS}"
			;;
			TIMEOUT)
				((TIMEOUT=$TIMEOUT+1))
				echo -e "${CYAN}timeout${NORMAL}${COL1}${TIMEOUT}${COL2}${WHITE}${TYPE}${NORMAL}${COL3}${IP}${COL5}${RDNS}"
				echo "$IP:1" >> $DATABASE
			;;
			DENIED_RBL_MATCH)
				((DENIED_RBL_MATCH=$DENIED_RBL_MATCH+1))
				echo -e "${BLUE}added${NORMAL}${COL1}${DENIED_RBL_MATCH}${COL2}${WHITE}${TYPE}${NORMAL}${COL3}${IP}${COL5}${RDNS}"
				echo "$IP:1" >> $DATABASE
			;;
			DENIED_RDNS_MISSING)
				((DENIED_RDNS_MISSING=$DENIED_RDNS_MISSING+1))
				echo -e "${BLUE}added${NORMAL}${COL1}${DENIED_RDNS_MISSING}${COL2}${WHITE}${TYPE}${NORMAL}${COL3}${IP}${COL5}${RDNS}"
				echo "$IP:1" >> $DATABASE
			;;
			DENIED_SENDER_NO_MX)
				((DENIED_SENDER_NO_MX=$DENIED_SENDER_NO_MX+1))
				echo -e "${BLUE}added${NORMAL}${COL1}${DENIED_SENDER_NO_MX}${COL2}${WHITE}${TYPE}${NORMAL}${COL3}${IP}${COL5}${RDNS}"
				echo "$IP:1" >> $DATABASE
			;;
		esac
	fi
}

function create_rules {
	# Create rules for the firewall
	if ! iptables -L SPAMDYKE-Filter-INPUT >/dev/null; then
		echo "Created firwall rule SPAMDYKE-Filter-INPUT"
		iptables -N SPAMDYKE-Filter-INPUT
		iptables -I INPUT 1 -p tcp --dport 25 -j SPAMDYKE-Filter-INPUT
	fi
}

function check_database {
	# Create the database if it doesn't exist
	if [[ ! -e $DATABASE ]]; then
		echo "Database '$DATABASE' does not exist, creating it"
		if ! touch $DATABASE; then
			echo "Could not create database : '$DATABASE'"
			exit 1
		fi
	fi
}

function exit_ {
	echo
	echo "Shutting down ..."
	[[ $LIMIT -gt 0 ]] && delete_rules && update_database
}

function update_database {
	# remove entries that have been firewall during process from database
	echo "  removing firewalled hosts from database"
	sed -i -e "/.*:X/d" $DATABASE
}

function delete_rules {
	# delete the custom firewall rule
	echo "  deleting firewall rules"
	iptables -F SPAMDYKE-Filter-INPUT
	iptables -D INPUT -p tcp --dport 25 -j SPAMDYKE-Filter-INPUT
}

function main() {
	# main() - maybe used later for something more complex
	echo -e "${WHITE}ACTION${COL1}TCOUNT${COL2}TYPE${COL3}IP${COL4}IPCOUNT${COL5}RDNS${NORMAL}" 
	check_database
	[[ $LIMIT -gt 0 ]] && create_rules
	# start the loop
	parser
}

main $@
