Linux – shouldn’t /etc/hosts.deny be intercepting this before it hits ssh logs

linuxnetworkingSecuritysshUbuntu

I'm using a combination of /etc/hosts.deny and ufw on my ubuntu 10.04.04 server. Most days, I see failed ssh attempts from machines in the .com.cn domain, reported like so:

Failed logins from:
112.114.63.139 (139.63.114.112.broad.km.yn.dynamic.163data.com.cn): 1 time

However, in /etc/hosts.deny, I have this rule:

ALL: .com.cn

Shouldn't this be blocking the connection before it even hits ssh? I've tested it via blocking my home machine, and it certainly denies me a connection right away before I get a login prompt (and yes, I've moved my ssh keys away so those aren't involved).

Is this working as intended?

Edit: James Sneeringer prompted me to look more closely at the logs, and perhaps I see why this is happening. From auth.log:

Nov  5 09:38:40 mymachine sshd[22864]: warning: /etc/hosts.deny, line 21: can't verify hostname: getaddrinfo(139.63.114.112.broad.km.yn.dynamic.163data.com.cn, AF_INET) failed
Nov  5 09:38:44 mymachine sshd[22864]: reverse mapping checking getaddrinfo for 139.63.114.112.broad.km.yn.dynamic.163data.com.cn [112.114.63.139] failed - POSSIBLE BREAK-IN ATTEMPT!
Nov  5 09:38:45 mymachine sshd[22864]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=112.114.63.139  user=root
Nov  5 09:38:47 mymachine sshd[22864]: Failed password for root from 112.114.63.139 port 37245 ssh2
Nov  5 09:38:47 mymachine sshd[22866]: Connection closed by 112.114.63.139

This implies to me that if sshd isn't sure about the IP->name lookup, then it errs on the side of caution and does not block that host. Is that right?

Best Answer

This is expected for sshd because it is linked directly to libwrap, so sshd is actually what performs the host check. If you want to block the connection before sshd is invoked, you'll need to place something in front of it to handle the connection attempt before passing it off to sshd. A couple options would be:

  • Run sshd under inetd (or xinetd). This will allow you to invoke sshd as an argument to tcpd, and tcpd is what ends up performing the actual host check.

  • Run sshd under xinetd, which has only_from and no_access service options that provide functionality similar to /etc/hosts.allow and /etc/hosts.deny.

The sshd manpage discourages these approaches, though:

 -i      Specifies that sshd is being run from inetd(8).  sshd is normally
         not run from inetd because it needs to generate the server key
         before it can respond to the client, and this may take tens of
         seconds.  Clients would have to wait too long if the key was
         regenerated every time.  However, with small key sizes (e.g. 512)
         using sshd from inetd may be feasible.

Using iptables or placing a firewall in front of your server might seem like a good alternative, but most do not perform any name resolution, so you're limited to controlling access by IP address. This isn't necessarily a bad thing, but it doesn't help with what you're trying to accomplish.