在网络中获取一个IP地址的所有主机名

4

我有一个要求,即一个IP地址可以映射到多个主机名。我试图查看 InetAddress.getAllByName("10.33.28.55"),但我没有得到想要的结果,它只返回了一个条目。nslookup 在该IP地址上返回所有DNS条目。如何在Java中检索与此IP地址相关联的所有主机名?


你是在与Java代码运行在同一台机器上运行nslookup吗? InetAddress.getAllByName() 应该 可以实现你所要求的功能。 - Brian Roach
@BrianRoach:起初我没有,但是当我在与nslookup相同的机器上运行InetAddress.getAllByName()时,它仍然在数组中返回1个条目,而我期望有2个。有趣的是,getCanonicalHostName()getHostName()函数返回了2个不同的值。我原以为这2个值会作为数组中的2个元素分别出现。 - devang
2
实际上...查看InetAddress.getAllByName()的源代码...如果它是一个IP地址,它实际上不会进行查找,呵呵。你会得到一个包含你提供的IP的单个InetAddress对象。每天都学到新东西;我想我从来没有尝试过这样做。 - Brian Roach
@BrianRoach:很有趣。让我看看如果我使用主机名会返回什么。 - devang
我相信我已经弄清楚了你需要什么,看看我的修订答案。 - Brian Roach
我不懂Java,所以这不是你要找的答案。在Linux中,您可以查看Posix标准中的man页面gethostbyname。 返回的struct hostent中有“h_addr_list”。在Python中,您可以使用socket.gethostbyname_ex(name)来获取_ip,_alias,ips,其中ips是列表,而_ip是列表的一个条目。 - frostyplanet
3个回答

4

查看InetAddress.getAllByName()的源代码,你会发现如果提供的String是 IP 地址的文本表示形式,它实际上不会执行 DNS 查询。它只返回一个包含单个 IP 的 InetAddress 对象的数组。甚至在该方法中还有一个方便的注释:

// if host is an IP address, we won't do further lookup

(参见:http:// javasourcecode.org / html / open-source / jdk / jdk-6u23 / java.net / InetAddress.java.html
如果只提供文字 IP 地址,则仅检查地址格式的有效性。但我认为这并不能告诉你它不会被查找。然而,在考虑 InetAddress 的情况下,它的意义就显而易见了——该类封装了一个 IP 地址,而您只有一个。它真的需要 getHostNames()getAllCanonicalNames()(请注意复数)方法来执行您所需的操作。我正在考虑提交问题或补丁。
话虽如此,目前似乎没有内置方法可以进行支持多个 PTR 记录的 RDNS 查询。所有其他查找方法都只是简单地削减返回的第一个记录,这是您得到的内容。 您将不得不寻找 Java 的第三方 DNS 库(抱歉,我没有使用任何这些库的经验)。 补充编辑: 我喜欢解决问题。我没有一个有多个 PTR 记录的 IP 可以测试,但它应该能够完成任务。
import java.io.IOException;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.InitialDirContext;

public class App
{
    public static void main(String[] args) throws IOException, NamingException
    {
        Properties env = new Properties();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
        InitialDirContext idc = new InitialDirContext(env);

        String ipAddr = "74.125.225.196";

        // Turn the IP into an in-addr.arpa name
        // 196.225.125.74.in-addr.arpa.
        String[] quads = ipAddr.split("\\.");
        StringBuilder sb = new StringBuilder();
        for (int i = quads.length - 1; i >= 0; i--) 
        {
            sb.append(quads[i]).append(".");
        }
        sb.append("in-addr.arpa.");
        ipAddr = sb.toString();

        Attributes attrs = idc.getAttributes(ipAddr, new String[] {"PTR"});
        Attribute attr = attrs.get("PTR");

        if (attr != null) 
        {
            for (int i = 0; i < attr.size(); i++)
            {
                System.out.println((String)attr.get(i));
            }
        }
    }  
}

这是很棒的东西。不过,我回去写了一个小脚本来帮我完成这些事情。非常感谢。 - devang
也许你可以通过JNDI进行反向查找。 - user207421
非常好,但我认为你应该承认使用JNDI的想法来源。 - user207421
我已经在主机文件中添加了条目,并尝试执行javax.naming.NameNotFoundException: DNS名称未找到[响应代码3]。 - Santoshkumar Kalasa

0

这个答案可能会有帮助:https://dev59.com/QGUo5IYBdhLWcg3wvRtF#24205035

使用DNSNameServicelookupAllHostAddr方法对我很有效,可以按主机名返回所有IP地址。也许它还有助于通过IP地址找到所有主机名,但这似乎取决于DNS服务器配置。在我的情况下,我甚至无法使用nslookup找到所有主机名,因此我无法测试它,所以对这个解决方案不确定。

一个建议是lookupAllHostAddr不是静态方法,因此您应该像这样使用它:

InetAddress[] ipAddress = new DNSNameService().lookupAllHostAddr("hostname")

此外,从我的角度来看,这个链接可能会很有趣(它也是我上面提到的同一个答案线程中的信息,我只是简要总结了一下)。

https://docs.oracle.com/javase/8/docs/technotes/guides/net/properties.html

在链接的页面上,您可以找到禁用查找缓存的属性:

  • sun.net.inetaddr.ttl - 您应该将其添加到JVM启动命令行中,如下所示:-Dsun.net.inetaddr.ttl=0,这里的0表示主机名将被缓存0秒
  • networkaddress.cache.ttl - 您应该将所需值添加到位于%JRE%\lib\security的java.security文件中

此外,还可以在此处找到更多信息:

http://www.rgagnon.com/javadetails/java-0445.html


0

好的,只有一种好的方法:从Java进程中调用nslookup或dig或其他类似命令。

使用Runtime.getRuntime().exec(..)

或者更好地使用ProcessBuilder...


我知道这个问题,我一直在试图避免这样做,以便不必进行解析并依赖Java返回。看来我必须采用这种方法,使用“nslookup”或“host”命令获取列表并进行必要的解析。 - devang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接