linuxでmessageログに warning: /etc/hosts.allow, line xx: can't verify hostnameが出る

運用中のlinuxサーバーの/var/log/messageログを見てみたら、多量にvsftpdのwarningが出ていた。

Jul  2 22:13:29 host vsftpd[17947]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:13:31 host vsftpd[17949]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:13:32 host vsftpd[17951]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:13:35 host vsftpd[17953]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:13:37 host vsftpd[17955]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:13:39 host vsftpd[17957]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:13:41 host vsftpd[17959]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:13:47 host vsftpd[17961]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:13:52 host vsftpd[17963]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:13:53 host vsftpd[17965]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:13:56 host vsftpd[17967]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:13:59 host vsftpd[17969]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:14:02 host vsftpd[17971]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:14:03 host vsftpd[17973]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:14:05 host vsftpd[17975]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:14:07 host vsftpd[17977]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed
Jul  2 22:14:09 host vsftpd[17979]: warning: /etc/hosts.allow, line 21: can't verify hostname: getaddrinfo(8.195.26.117.broad.pt.fj.dynamic.163data.com.cn, AF_INET) failed

/etc/hosts.allow, line 21 には

vsftpd : xxx.xxxx.com : allow

となっているので、hosts.allowの記述ミスでも無さそう。

この「8.195.26.117.broad.pt.fj.dynamic.163data.com.cn」を調べてみた。 たぶん、8.195.26.117 をひっくり返して、117.26.195.8がIPアドレスなのでIPを逆引きして、ホスト名を取得。

nslookup 117.26.195.8

名前:    8.195.26.117.broad.pt.fj.dynamic.163data.com.cn
Address:  117.26.195.8

ログと一致するホスト名が取れた。 今度はこのホスト名からIPを引いてみる。

nslookup 8.195.26.117.broad.pt.fj.dynamic.163data.com.cn

*** UnKnown が 8.195.26.117.broad.pt.fj.dynamic.163data.com.cn を見つけられません: Non-existent domain

今度は見つからない。 逆引き→正引き後のIPに一致しないので、弾かれているのかな?

ついでにTCP Wrapperのソースも見てみた。

ftp://ftp.porcupine.org/pub/security/index.html TCP Wrapper (tcp_wrappers_7.6.tar.gz)

grepしてみると、次の箇所が該当していそう。

/* sock_hostname - map endpoint address to host name */

void    sock_hostname(host)
struct host_info *host;
{
    struct sockaddr_in *sin = host->sin;
    struct hostent *hp;
    int     i;

    /*
     * On some systems, for example Solaris 2.3, gethostbyaddr(0.0.0.0) does
     * not fail. Instead it returns "INADDR_ANY". Unfortunately, this does
     * not work the other way around: gethostbyname("INADDR_ANY") fails. We
     * have to special-case 0.0.0.0, in order to avoid false alerts from the
     * host name/address checking code below.
     */
    if (sin != 0 && sin->sin_addr.s_addr != 0
	&& (hp = gethostbyaddr((char *) &(sin->sin_addr),
			       sizeof(sin->sin_addr), AF_INET)) != 0) {

	STRN_CPY(host->name, hp->h_name, sizeof(host->name));

	/*
	 * Verify that the address is a member of the address list returned
	 * by gethostbyname(hostname).
	 * 
	 * Verify also that gethostbyaddr() and gethostbyname() return the same
	 * hostname, or rshd and rlogind may still end up being spoofed.
	 * 
	 * On some sites, gethostbyname("localhost") returns "localhost.domain".
	 * This is a DNS artefact. We treat it as a special case. When we
	 * can't believe the address list from gethostbyname("localhost")
	 * we're in big trouble anyway.
	 */

	if ((hp = gethostbyname(host->name)) == 0) {

	    /*
	     * Unable to verify that the host name matches the address. This
	     * may be a transient problem or a botched name server setup.
	     */

	    tcpd_warn("can't verify hostname: gethostbyname(%s) failed",
		      host->name);

	} else if (STR_NE(host->name, hp->h_name)
		   && STR_NE(host->name, "localhost")) {

	    /*
	     * The gethostbyaddr() and gethostbyname() calls did not return
	     * the same hostname. This could be a nameserver configuration
	     * problem. It could also be that someone is trying to spoof us.
	     */

	    tcpd_warn("host name/name mismatch: %s != %.*s",
		      host->name, STRING_LENGTH, hp->h_name);

	} else {

	    /*
	     * The address should be a member of the address list returned by
	     * gethostbyname(). We should first verify that the h_addrtype
	     * field is AF_INET, but this program has already caused too much
	     * grief on systems with broken library code.
	     */

	    for (i = 0; hp->h_addr_list[i]; i++) {
		if (memcmp(hp->h_addr_list[i],
			   (char *) &sin->sin_addr,
			   sizeof(sin->sin_addr)) == 0)
		    return;			/* name is good, keep it */
	    }

	    /*
	     * The host name does not map to the initial address. Perhaps
	     * someone has messed up. Perhaps someone compromised a name
	     * server.
	     */

	    tcpd_warn("host name/address mismatch: %s != %.*s",
		      inet_ntoa(sin->sin_addr), STRING_LENGTH, hp->h_name);
	}
	strcpy(host->name, paranoid);		/* name is bad, clobber it */
    }
}

この部分のverifyしている部分の処理で警告が出るのだろう。

Verify that the address is a member of the address list returned by gethostbyname(hostname). Verify also that gethostbyaddr() and gethostbyname() return the same hostname, or rshd and rlogind may still end up being spoofed. 結局、設定ミスではなさそうで、アクセス元のIPアドレスが逆引き→正引き後一致しないので弾かれてるので、もちょっとわかりやすいメッセージだといいなぁ。