denyhosts on Mac OS X

I just spent some time figuring out how to set up denyhosts on Snow Leopard. I’ve used denyhosts before, but never felt like I had things set up properly for Mac OS. Now I think I have it figured out, so here it is. This is for 10.6, your mileage may vary on earlier versions.

I had three goals – get denyhosts working, get it to start automatically at boot time, and to deal with rotating the logs.

1. Installation
Easiest first – installing denyhosts. Note that you need to be root to do this. Pretty much just follow the directions. These are the three main settings to worry about.

SECURE_LOG = /private/var/log/secure.log
LOCK_FILE = /var/run/
DAEMON_LOG = /var/log/denyhosts

Note that you also may need to create the file /etc/hosts.deny:

touch /etc/hosts.deny

Using touch will create a zero-length file if it’s not there. It won’t affect the contents if it is there.

2. Log rotation

Mac OS 10.6 uses newsyslog to rotate some log files (I’m not sure why, but apache logs don’t seem to be dealt with by newsyslog). To add your own to the mix, just put a file into /etc/newsyslog.d/ following the format for newsyslog.conf(5). I called mine local.conf

# logfilename          [owner:group]            mode count size when  flags [/pid_file] [sig_num]
/var/log/denyhosts                              640   5     *    $D0     J

The trouble is, this rotated the log just fine, but then denyhosts stopped logging because newsyslog essentially pulls the rug out from under denyhosts by moving the file.

One design difference between newsyslog and logrotate is the way they deal with notifying processes that logs have been rotated. Logrotate uses prerotate and postrotate scripts, which would be ideal for denyhosts. The way you start and stop it is with

daemon-control start

daemon-control stop

daemon-control stop actually sends a SIGTERM to the denyhosts process, but that won’t do any good in the newsyslog config file since once stopped, you need a command line to start it up again. So I decided to tweak the daemon-control script to do this. I replaced the start() function with the one here:

def start(*args):
    cmd = "%s --daemon " % DENYHOSTS_BIN
    if args: cmd += ' '.join(args)

    print "starting DenyHosts:   ", cmd

    while True:

        while True:
            pid = getpid()
            if pid >= 0:

This just keeps daemon-control running rather than letting it exit after it starts denyhosts. The outer loop starts denyhosts running and later restarts it. The inner loop just waits until it sees the pid file go away. That’s a sure sign that denyhosts stopped running, most likely because of the SIGHUP it will get from newsyslog. Now all I needed to do was add the signal info to my /etc/denyhosts.d/local.conf /etc/newsyslog.d/local.conf file:

# logfilename          [owner:group]            mode count size when  flags [/pid_file] [sig_num]
/var/log/denyhosts                              640   30     *  $D0     BJ  /var/run/ 15

I’ve also changed it to keep 30 days of logs, and added the B flag to prevent newsyslog from adding a line to the file saying it’s rotated the logs. Note that I changed the name to daemon-control2 so if I update denyhosts later, my changes don’t get clobbered.

3. Start at boot time

It turns out that modifying daemon-control to never exit is also just the ticket for running it under launchd. Launchd doesn’t work well on scripts that launch daemonized processes. It watches the script and notices that it’s exited, then tries to start it again.

I made a file called /Library/LaunchDaemons/net.hosts.deny.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "">
<plist version="1.0">
    <string>Lauch denyhosts</string>

Get it started with launchctl:

launchctl load /Library/LaunchDaemons/net.hosts.deny.plist

My /etc/hosts.deny has about 8500 hosts in it right now. Many of those are probably from the denyhosts synchronization feature pulling in IP addresses from the central server.

Update 2010-03-26: Added some links and clarified some bits.

Update 2010-06-06: Note that /etc/hosts.deny must be present. denyhosts won’t create it.

Posted in Mac, Random
8 comments on “denyhosts on Mac OS X
  1. chris says:

    “so I decided to tweak the daemon-control script to do this”

    where is this script? thx

  2. Allan says:

    daemon-control is in /usr/share/denyhosts

    I copied it to daemon-control2, then modified that, and refer to that in the launchd plist file.

  3. chris says:

    i found the file i asked about in my previous comment:

    in step 2, you refer to: /etc/newsyslog.d/local.conf

    then in step 3 you refer to: /etc/denyhosts.d/local.conf

  4. Allan says:

    Whoops.. that should be /etc/newsyslog.d/local.conf

    (And thanks for noticing!)

  5. dmure says:

    I am glad that I found this, it was really helpful.

    I believe that I have almost got it working the way I want, how ever it seems to be spamming my logs once it starts, say that it can to run because of the lock file. I believe that it /is/ runnng, but the way the launchdaemon is set up, it keeps polling, and thus spamming… any suggestions?

  6. Allan says:

    dmure: It sounds like something is going wrong with the daemon-control modifications from the second half of step two above. launchd will keep re-running the script if it exits.

  7. Cary Jones says:

    I’m getting an syntax error at if pid >= 0:

  8. Allan says:

    Cary, did you use >= or &gt;= ?

    I’m struggling with the formatting on the blog. It keeps reverting to the wrong thing. It should be >=

1 Pings/Trackbacks for "denyhosts on Mac OS X"
  1. […] denyhosts on Mac OS X […]