DenyHosts is a Python script used to aid in securing SSH access to a Unix/Linux system. I won't go into the details, or the complex configuration options, but basically it monitors failed login attempts via SSH. After a configurable number of failed login attempts, DenyHosts adds the originating host (IP) to hosts.deny, thereby preventing further attempts. I implemented this in mid-2006 after experiencing brute-force attacks from a Chinese IP, with over 1,500 login attempts in under 15 minutes. For a residential connection and dynamic IP, I thought this was a bit excessive. DenyHosts also allows access to be restored after a configurable interval (mine is set to 1 week, for reasons described below).
Of interest to me, DenyHosts also allows integration with a global DenyHosts database. Every hour, (configurable, of course) my DenyHosts daemon uploads the list of all IPs that it has blocked since the last sync to the denyhosts.net server. It also downloads a list of all IPs blocked by other participating DenyHosts daemons. It is configured to automatically add any IPs blocked by 15 or more instances to hosts.deny - therefore many brute-force attackers are blocked before they ever get to my machine. Of course, participation is optional, and this is all highly configurable. While I generally don't like the idea of global blacklists (though my SpamAssassin is running Pyzor), this database is pretty much guaranteed to contain only unsavory characters.
DenyHosts blocks access attempts based on IP address. I *think* it attempts to reverse-validate. The problem remains, though, that a botnet attack, or any other attacker with access to many IPs, would render the system virtually useless. Your user accounts should have some sort of mandatory lockout with X incorrect passwords, to at least slow down the attack, and notify you to take action.
Blocking Legitimate IPs
DenyHosts will, at times, block legitimate IPs. I've occasionally been blocked from a remote site when I was *sure* that I didn't make 6 incorrect tries. As mentioned above, my DenyHosts configuration blocks for one week. I haven't found this to me a problem for me yet. I have access to about a dozen Internet-accessible hosts. About half of them (that are actually under my direct control) are permanently added to hosts.allow and DenyHosts will not block them. So, even if DenyHosts blocks the machine that I'm working from, I can SSH to my home box from an allowed intermediary and make the necessary changes.
The DenyHosts web site has a FAQ on what to do if it blocks a legitimate user. The basic idea is to create a file called "allowed-hosts" in your DenyHosts WORKDIR (on my SuSE 9.3 system, this is
/usr/share/denyhosts/data) and add the host's IP, one per line, to that file. If you legitimate host gets blocked, simply add that IP to allowed-hosts and then remove the corresponding entry from
/etc/hosts.deny (or wherever that file lives). If you're using Daemon Synchronization, your hosts.deny can get *very* large, so grepping for the IP will be your best bet. If you don't want to edit it, you can be cool and do something like
cat hosts.deny | grep -v X.X.X.X > hosts.temp; mv hosts.temp hosts.deny. You will have to restart the DenyHosts daemon after changing the allowed-hosts file in order for it to update. If you don't, it will just keep adding the host in question back into hosts.deny.