JavaのInetAddressクラスのgetHostName()やgetCanonicalHostName()で、IPアドレスからホスト名への名前解決(逆引き)を実行すると、裏で正引き(ホスト名⇒IPアドレス)も行われるようだ。詳細は以下の通り。
InetAddressクラスのソースを確認すると、getHostName()とgetCanonicalHostName()は、その延長でInetAddress#getHostFromNameService()をコールする。このgetHostFromNameService()の実装は以下になっている。
private static String getHostFromNameService(InetAddress addr, boolean check) { String host = null; for (NameService nameService : nameServices) { try { // first lookup the hostname host = nameService.getHostByAddr(addr.getAddress()); /* check to see if calling code is allowed to know * the hostname for this IP address, ie, connect to the host */ if (check) { SecurityManager sec = System.getSecurityManager(); if (sec != null) { sec.checkConnect(host, -1); } } // ★★ /* now get all the IP addresses for this hostname, * and make sure one of them matches the original IP * address. We do this to try and prevent spoofing. */ InetAddress[] arr = InetAddress.getAllByName0(host, check); boolean ok = false; if(arr != null) { for(int i = 0; !ok && i < arr.length; i++) { ok = addr.equals(arr[i]); } } // ★★ //XXX: if it looks a spoof just return the address? if (!ok) { host = addr.getHostAddress(); return host; } break; } catch (SecurityException e) { host = addr.getHostAddress(); break; } catch (UnknownHostException e) { host = addr.getHostAddress(); // let next provider resolve the hostname } } return host; }
(JDK 1.8 のInetAddressクラスのソースから抜粋)
上記の ★★ で囲んだ部分で、(名前解決の結果得た)ホスト名からIPアドレス群を取得し、取得したIPアドレス群の中に問い合わせの元となったIPアドレスが存在するか確認している。この処理は、ソースのコメントにもある通り、DNS spoofing対策のために入れらている。
つまり、Javaにおいて名前解決(逆引き)を行う時は正引きも実施され、逆引き・正引きの結果が不整合だと、名前解決に失敗するということになる。
JavaのURLの名前解決で、DNSの逆引きが発生しています。DNSの逆引きを抑止することはできますか?
という記事もあるし、Javaで名前解決処理を含むアプリケーションを動かす場合、正引きと逆引きの結果が一致する環境にした方がアプリケーションの動きは安定しそうな気がする。(まあ、Javaのアプリケーションに限らず、正引きと逆引きは一致させた方が予想外の挙動に悩まされなくて済みそう。)