# Automatically Emailing Abuse Contacts with fail2ban

@ 06 October 2012

Anyone that runs servers knows that every address on the internet is constantly being probed by attackers. A good security measure is to run an automated system like fail2ban that will detect and block attacks.

But I wasn’t satisfied with that.

While working in Network Operations, I would occasionally recieve emails directed to the abuse@ alias. As a NOC Technician, it was important to me that our network remain secure and free of abuse, so I always appreciated these emails. I decided that it might be fun to have fail2ban automatically email other network administrators.

The basic idea is simple:

  • When fail2ban is triggered, the actionban fires my script and passes in the IP address and the log file.
  • The script then performs a whois lookup on the IP address and grabs everything that looks like an email address.
  • It also greps out the relevant log lines.
  • Finally, it builds a small email and sends it off!

This script isn’t perfect, but it has served me well for over 3 years. The main bug is that all email addresses from the WHOIS lookup are contacted and by RFC, I should probably only email the OrgAbuseEmail. However, WHOIS records vary so dramatically that the OrgAbuseEmail is not always populated. In fact, many WHOIS records provide no email contacts at all. Additionally, I don’t follow RWHOIS or handle NET- lookups. (A very friendly NOC Technician in Oregon pointed out the latter issue when I contacted them directly.) I suspect that many ISPs (China, Eastern Europe, Russia) redirect all abuse-related mail to /dev/null


import os, socket, sys
import smtplib
from email.mime.text import MIMEText

# assign the arguments
ip = sys.argv[1]
logfile = sys.argv[2]

# grab the abuse@ and other contacts
fin,fout = os.popen4( "whois " + ip + " | grep -o '[[:alnum:]+\.\_\-]*@[[:alnum:]+\.\_\-]*' | sort | uniq" )
emails = fout.read()

# header
message =   "THIS IS AN AUTOMATED MAILER.\n\n" \
            "The IP " + ip + " was recorded as making multiple brute-force attempts. " \
            "Your email is listed as a contact on the whois information for " + ip + ".\n" \
            "Below are the relevant log lines. All times are Pacific time.\n\n" \

# log entries
fin,fout = os.popen4('grep ' + sys.argv[1] + ' ' + sys.argv[2])
lines = fout.read()

# mail variables
hostname = socket.getfqdn()
src = 'fail2ban@' + hostname
dest = [ 'root@' + hostname ]

for each in emails.split():
print dest

# build the message...
msg = MIMEText(message + lines)
msg['Subject'] = 'Brute Force Attempt from ' + ip
msg['From'] = src
msg['To'] = ', '.join(dest)

# ... and send!
s = smtplib.SMTP('localhost')
s.sendmail(src, dest, msg.as_string())

The hardest part is the fail2ban configuration. I simply modified one of the files in /etc/fail2ban/action.d to contain the following line: actionban = /usr/local/sbin/abuse.py <ip> <logpath>

I later discovered that /etc/fail2ban/action.d/complain actually does everything my script does. One of the most interesting things about systems administration is discovering when you’ve re-invented the wheel. It’s always a good learning experience, both during the re-invention but also in analyzing what others have done before you.

# Hello, World!

@ 05 October 2012

Hello, World!

For some time now, my blog has languished at the bottom of my projects list. At some point, I realized that the ad-hoc blogging I had been doing previously was not satisfying me. The topics I want to write about have become complex enough that they cannot be captured in quick 15 minute post. As I’ve entered the professional world, I’ve realized the importance of publishing quality, technical works. I wanted a place where I could actually draft, revise, edit and publish. My writing process has changed significantly as I’ve discovered new tools and processes. There’s no way to use vim with Wordpress.

To rectify this, I’m re-launching my blog. The old blog will continue to exist, possibly forever. I will be updating, improving and reposting some of the best content from the old blog. The new blog will be primarily technical in nature, documenting the most interesting projects from my personal network and code repository. Occasionally, there may also be posts about technophile home improvement projects, nerdy fatherhood and personal reflection.

Stay tuned for more.