Monday, January 21, 2013

DenyHosts Remove / Delete an IP Address

If you got here from a search, it's because you're looking for a way to remove an IP address from the tables used by the DenyHosts program.  Read on!

DenyHosts is a nifty Python program that monitors Unix/Linux log files for failed SSH logins and, after a configurable number of attempts, adds the source IP address to /etc/hosts.deny.  It's a simple but effective intrusion prevention system for SSH servers.

I'm a college teacher and I operate a server that my students use via SSH.  I run DenyHosts to stop SSH hacking, which happens all the time from all over the world.  At the beginning of each semester, it's not unusual for several students to lock themselves out due to multiple failed login attempts.  The DenyHosts FAQ gives instructions for removing addresses that should not have been added.  It's a fiddly, time-consuming process, and I wanted to automate it.  I wanted to be able to type:
and have the address removed from all the places from which it should be removed.  (The IP address in the example is an obvious fake for obvious reasons!)

Here is a bash script that will do that.

The Script

echo Removing $1 from denyhosts tables
IP=`echo $1 | sed 's/\./\\\\./g'`
service denyhosts stop
eval "sed -i /$IP/d /etc/hosts.deny"
eval "sed -i /$IP/d ${WORK_DIR}hosts"
eval "sed -i /$IP/d ${WORK_DIR}hosts-restricted"
eval "sed -i /$IP/d ${WORK_DIR}hosts-root"
eval "sed -i /$IP/d ${WORK_DIR}hosts-valid"
eval "sed -i /$IP/d ${WORK_DIR}users-hosts"
echo $1 >> ${WORK_DIR}allowed-hosts
service denyhosts start

That's it; copy and paste this into a file in the root user's space, make it executable, and you're good to go!  But before you copy-paste it (which you are encouraged to do) please read my notes below and any comments there may be.

The Notes

First let me say that I do not spend my days writing bash shell scripts. I am absolutely, positively certain this can be improved upon.  I'm certain it's not bullet-proof, and it's probably not even bullet-resistant.

If you can help by improving on it, please make comments below.  You'll help me and everyone who finds this page and considers using this script.

There's no error checking in what's above.  I'm not even sure what should be checked, much less how to go about checking it.  Deletion of lines will fail silently if the script is given a bogus IP address or a correctly-formed address that doesn't exist in the files edited.  However, it will add whatever is given as an argument to the end of the allowed_hosts file; That's probably not what is wanted if the argument to the script is bad.

There should probably at least be a check for the argument being empty because that'll create an empty line in the allowed-hosts file. Ideally, one would validate that the argument was four numbers 0-255 separated by periods.

One could go even further and exclude 127.0.0.* and any IP address with a zero first octet.  There may be other things that should be excluded.

There may be a way to set WORK_DIR for a specific installation.  I used the default, and so the script will have to be edited for those who did not.

How it Works

Most things should be pretty obvious.  The fourth line, where $IP is defined, escapes the periods in the IP address so the address can be used in a regular expression.  The lines that begin with "eval" delete any line with the given IP address from the file specified. The -i switch instructs sed to write the edited file back to the input.  I understand that not all versions of sed support -i.  Be sure to test.

Beware! The second-from-last line:
echo $1 >> ${WORK_DIR}allowed-hosts
appends the given IP address to the allowed-hosts file.  This will keep it from being blacklisted again.  That may not be what you want to do in general, and it's certainly not what you want to do if you run this with an invalid IP address. Remove or comment that line of you want to allow an address to be listed again, and be sure to edit the allowed-hosts file if you accidentally run the script with an invalid address.