InetAddress.getHostName()无法获取远程IP预期反向解析结果的问题
I wrote a simple Java program to print the DNS name of IP addresses:
package p1; import java.net.InetAddress; public class Main { public static void main(String[] args) throws Exception { System.out.println(InetAddress.getByName("201.23.160.63").getHostName()); System.out.println(InetAddress.getByName("191.207.99.75").getHostName()); } }
When I run this program, the output is:
- 201-23-160-63.gprs.claro.net.br
- 191.207.99.75
But when using the host command on Linux, I can get the correct DNS names for both IPs. For 191.207.99.75, the domain name is 191-207-99-75.user.vivozap.com.br.
Why can't InetAddress.getHostName() retrieve the correct DNS name for this IP? How can I implement proper reverse DNS resolution in Java?
Answer
Great question! Let's break down why this happens and how to fix it:
Why getHostName() fails for your second IP
InetAddress.getHostName() has a specific lookup flow that can lead to this behavior:
- It first checks your local system's hosts file (like
/etc/hostson Linux) for a pre-defined IP-to-name mapping. - If no local mapping exists, it performs a reverse DNS lookup—but it may rely on system-level DNS caching, or use the OS's default resolver which might prioritize faster (but incomplete) responses, or even fall back to returning the raw IP if the lookup hits a timeout or non-authoritative record it doesn't trust.
The host command, by contrast, directly queries DNS servers for PTR records (the standard record type for reverse DNS) without some of these shortcuts, which is why it returns the correct name.
How to implement reliable reverse DNS resolution in Java
Approach 1: Use getCanonicalHostName() instead
First, try swapping getHostName() for getCanonicalHostName(). This method skips some local caching and explicitly performs a full reverse DNS lookup to retrieve the fully qualified domain name (FQDN) from the DNS server:
package p1; import java.net.InetAddress; public class Main { public static void main(String[] args) throws Exception { InetAddress addr1 = InetAddress.getByName("201.23.160.63"); System.out.println(addr1.getCanonicalHostName()); InetAddress addr2 = InetAddress.getByName("191.207.99.75"); System.out.println(addr2.getCanonicalHostName()); } }
This often fixes the issue because it prioritizes the authoritative DNS response over any cached or partial results.
Approach 2: Use a dedicated DNS library for full control
If the above still doesn't work, use a library like dnsjava to directly query for PTR records, just like the host command does. This gives you full control over the lookup process, including specifying DNS servers and handling timeouts.
First, add the Maven dependency:
<dependency> <groupId>dnsjava</groupId> <artifactId>dnsjava</artifactId> <version>3.5.3</version> </dependency>
Then, the lookup code:
import org.xbill.DNS.*; public class ReverseDnsLookup { public static void main(String[] args) throws Exception { // Convert the IP to a reverse lookup domain (e.g., 75.99.207.191.in-addr.arpa) Name reverseName = ReverseMap.fromAddress("191.207.99.75"); Record[] ptrRecords = new Lookup(reverseName, Type.PTR).run(); if (ptrRecords != null && ptrRecords.length > 0) { for (Record record : ptrRecords) { PTRRecord ptr = (PTRRecord) record; System.out.println("Reverse DNS result: " + ptr.getTarget().toString()); } } else { System.out.println("No PTR record found for the IP"); } } }
Extra tips
- Check DNS configuration: Java uses your system's default DNS resolver. If the
hostcommand uses a different DNS server, you can force Java to use it by adding a VM argument:-Dsun.net.spi.nameservice.nameservers=8.8.8.8(replace with your preferred DNS server). - Clear caching: Java caches DNS results, so restarting your JVM can help if stale data is causing issues.
内容的提问来源于stack exchange,提问作者cgean

