18

我在 Stack Overflow 上寻找如何在 Java 中进行 IP 查找,但答案与我已经在做的事情相匹配,并且不能解决我的问题。

这是我的代码:

public void printHostname( String ip ) {
    System.out.println( InetAddresses.forString( ip ).getCanonicalHostName( ) );
}

InetAddresses只是来自 guava 库的实用程序类,用于获取InetAdress.

问题:此代码在某些 IP 地址上按预期工作,而在其他一些 IP 地址上则不行。

一个工作示例

例如,对于 IP 157.55.39.29,输出为:

msnbot-157-55-39-29.search.msn.com

根据 Linuxhost命令,这个结果似乎是正确的:

> host 157.55.39.29
29.39.55.157.in-addr.arpa domain name pointer msnbot-157-55-39-29.search.msn.com.

一个不工作的例子

对于 IP 123.125.71.75,host命令返回:

> host 123.125.71.75
75.71.125.123.in-addr.arpa domain name pointer baiduspider-123-125-71-75.crawl.baidu.com.

但是我的 Java 代码的输出是:

123.125.71.75

而预期的输出应该是

baiduspider-123-125-71-75.crawl.baidu.com

getCanonicalHostName方法的 javadoc说:

返回:
此 IP 地址的完全限定域名,或者如果安全检查不允许该操作,则返回 IP 地址的文本表示。

但我很确定这不是安全检查的问题......或者我不明白出了什么问题。

你有什么建议来解释这种行为吗?你有解决方法吗?

编辑#1

在寻找解决方案时,我尝试在 JDK 中逐步调试实现:

// 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);

在此代码中,变量host包含正确的值,但最后一个语句调用getAllByName0抛出一个UnknownHostException通过仅返回请求的 IP 来处理的。异常由内部方法引发,getAddressesFromNameService并带有消息: "java.net.UnknownHostException: baiduspider-123-125-71-75.crawl.baidu.com"

我不知道为什么。

我可以host绕过内部异常获取变量值吗?

4

2 回答 2

15

问题在于它有java.net.InetAdress一定的程序来防止 ip-spoofing。

它首先将名称解析为(一个)IP 地址。这工作正常。在您的情况下,结果是两个 IP 地址。InetAdress然后检查这些地址中的(至少一个)是否解析为原始输入名称。

如果他们不这样做,它只会返回原始 IP 地址。下图为检查后的情况baiduspider-123-125-71-75.crawl.baidu.com

检查`original ip reverse lookup -> name -> dns lookup of name后的调试器

注意:解析的ip地址getAllByName0与via相同nslookup,即:

nslookup baiduspider-123-125-71-75.crawl.baidu.com
Server:     192.168.2.1
Address:    192.168.2.1#53

Non-authoritative answer:
Name:   baiduspider-123-125-71-75.crawl.baidu.com
Address: 62.157.140.133
Name:   baiduspider-123-125-71-75.crawl.baidu.com
Address: 80.156.86.78

一个解决方案是使用dnsjava库。它跳过了欺骗检查,因此工作正常。

dnsjava 示例:

String addr = Address.getHostName(InetAddress.getByName("123.125.71.75")); 输出如预期baiduspider-123-125-71-75.crawl.baidu.com

免责声明:由于我是 Java 开发人员而不是安全专家,因此我并不完全了解使用欺骗性 IP 地址的安全隐患。

于 2016-01-21T14:53:32.073 回答
6

我没有对此进行深入研究,所以我不知道为什么会发生这种情况,但是一些检查 DNS 服务器健康状况的在线工具(例如这个)表明它们存在一些可能相关或不相关的问题。

正如@jah 所说,Java 尝试仔细检查主机名是否具有它所说的 ip。尝试执行此操作时,会在本机代码上引发异常。实际上,就我而言,尝试在命令行上进行验证时,nslookup 无法从名称中获取 ip,这表明某些配置在 DNS 服务器上阻止了此操作(可能是故意的?我也不是 DNS 专家) .

当它工作时:

$ nslookup msnbot-157-55-39-29.search.msn.com
Server:         192.168.1.1
Address:        192.168.1.1#53

Non-authoritative answer:
Name:   msnbot-157-55-39-29.search.msn.com
Address: 157.55.39.29

当它不起作用时:

$ nslookup baiduspider-123-125-71-75.crawl.baidu.com
Server:         192.168.1.1
Address:        192.168.1.1#53

** server can't find baiduspider-123-125-71-75.crawl.baidu.com: NXDOMAIN

当它工作时:

$ getent hosts msnbot-157-55-39-29.search.msn.com
157.55.39.29    msnbot-157-55-39-29.search.msn.com

当它没有时:

$ getent hosts baiduspider-123-125-71-75.crawl.baidu.com
$

作为替代方案,您可以为 JNDI 使用 DNS 服务提供者。该文档有一个示例,但我会留下一个工作片段供您测试:

String[] octets = "123.125.71.75".split("\\.");
String host = String.join(".", octets[3], octets[2], octets[1], octets[0], "in-addr.arpa");

Properties props = new Properties();
props.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
DirContext dirContext = new InitialDirContext(props);

Attributes attrs = dirContext.getAttributes(host, new String[] {"PTR"});

System.out.println(attrs.get("PTR").get());
于 2016-01-21T11:05:56.893 回答