java InetAddress.getCanonicalHostName() 返回 IP 而不是主机名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34842698/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
InetAddress.getCanonicalHostName() returns IP instead of Hostname
提问by Prim
I looked for how to do IP lookup in Java on Stack Overflow but the answers match what I am already doing and do not resolve my problem.
我在 Stack Overflow 上寻找如何在 Java 中进行 IP 查找,但答案与我已经在做的事情相匹配,但并没有解决我的问题。
Here is my code:
这是我的代码:
public void printHostname( String ip ) {
System.out.println( InetAddresses.forString( ip ).getCanonicalHostName( ) );
}
InetAddresses
is just a utility class from guava library to get a InetAdress
.
InetAddresses
只是一个来自番石榴库的实用程序类来获取InetAdress
.
The problem: This code works as expected with some IP adresses and not with some others.
问题:此代码在某些 IP 地址上按预期工作,而在其他一些 IP 地址上则无效。
A working example
一个工作示例
For example, for IP 157.55.39.29, the output is:
例如,对于 IP 157.55.39.29,输出为:
msnbot-157-55-39-29.search.msn.com
This result seems correct according to Linux host
command:
根据 Linuxhost
命令,这个结果似乎是正确的:
> host 157.55.39.29
29.39.55.157.in-addr.arpa domain name pointer msnbot-157-55-39-29.search.msn.com.
A not working example
一个不工作的例子
For IP 123.125.71.75, the host
command returns:
对于 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.
But the output of my Java code is:
但是我的 Java 代码的输出是:
123.125.71.75
whereas the expected output should be
而预期的输出应该是
baiduspider-123-125-71-75.crawl.baidu.com
The javadoc of getCanonicalHostNamemethod says:
getCanonicalHostName方法的 javadoc说:
Returns:
the fully qualified domain name for this IP address, or if the operation is not allowed by the security check, the textual representation of the IP address.
返回:
此 IP 地址的完全限定域名,或者如果安全检查不允许操作,则为 IP 地址的文本表示。
but I'm pretty sure it's not really a problem with a security check... or I don't understand what is wrong.
但我很确定这不是安全检查的真正问题……或者我不明白出了什么问题。
Have you any suggestion to explain this behaviour? Do you have a workaround?
你有什么建议来解释这种行为吗?你有解决方法吗?
EDIT #1
编辑#1
When looking for a solution, I tried to step debug the implementation in JDK:
在寻找解决方案时,我尝试逐步调试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);
In this code, variable host
contains the correct value, but the last statement calling getAllByName0
throws an UnknownHostException
which is handled by returning just the requested IP. The exception is thrown by internal method getAddressesFromNameService
with message:
"java.net.UnknownHostException: baiduspider-123-125-71-75.crawl.baidu.com"
在这段代码中,变量host
包含正确的值,但最后一个语句调用getAllByName0
抛出一个 an UnknownHostException
,它通过仅返回请求的 IP 来处理。异常由内部方法抛出,getAddressesFromNameService
并带有消息:
"java.net.UnknownHostException: baiduspider-123-125-71-75.crawl.baidu.com"
I don't know why.
我不知道为什么。
Can I get the host
variable value, bypassing the internal exception?
我可以获得host
变量值,绕过内部异常吗?
采纳答案by jah
The problemlies in the fact that the java.net.InetAdress
has a certain procedure against ip-spoofing.
该问题在于一个事实,即java.net.InetAdress
具有防止IP欺骗一定的程序。
It first resolves the name into (an) ip address(es). This works fine.
In your case the result are two IP adresses. InetAdress
then checks back if (at least one of) these adresses resolve to the original input name.
它首先将名称解析为(一个)IP 地址。这工作正常。在您的情况下,结果是两个 IP 地址。InetAdress
然后检查这些地址(至少其中之一)是否解析为原始输入名称。
If they do not, it just returns the original ip adress. The following picture shows the situation after the check for baiduspider-123-125-71-75.crawl.baidu.com
如果没有,它只返回原始 IP 地址。下图为检查后的情况baiduspider-123-125-71-75.crawl.baidu.com
Note: The ip adresses resolved by getAllByName0
are the same as via nslookup
, namely:
注意:解析的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
A solutionwould be to use the dnsjavalibrary. It skips the spoofing check and therefore works fine.
一个解决方案是使用dnsjava库。它跳过欺骗检查,因此工作正常。
dnsjava example:
dnsjava 示例:
String addr = Address.getHostName(InetAddress.getByName("123.125.71.75"));
outputs just as expected baiduspider-123-125-71-75.crawl.baidu.com
String addr = Address.getHostName(InetAddress.getByName("123.125.71.75"));
输出如预期 baiduspider-123-125-71-75.crawl.baidu.com
Disclaimer:As i am a Java developer and not a security expert, i am not totally aware of the security implications of using a spoofed ip address.
免责声明:由于我是 Java 开发人员而不是安全专家,因此我并不完全了解使用欺骗性 IP 地址的安全隐患。
回答by ahirata
I did not dig a lot into this so I don't know why it is happening, but some online tools (like this one) that checks the health of DNS servers indicates that they have some issues which may or may not be related.
我没有深入研究这个问题,所以我不知道为什么会发生这种情况,但是一些检查 DNS 服务器健康状况的在线工具(例如这个)表明它们存在一些可能相关或不相关的问题。
As @jah said, Java tries to double check to see if the hostname has the ip it said it has. The exception is thrown on the native code while trying to do that. In fact, in my case, trying to verify on the command line, the nslookup fails to get the ip from the name, which indicates some configuration preventing this on the DNS Server (maybe on purpose? I'm no expert in DNS either).
正如@jah 所说,Java 会尝试仔细检查主机名是否具有它所说的 IP。在尝试执行此操作时,本机代码会抛出异常。事实上,就我而言,尝试在命令行上进行验证时,nslookup 无法从名称中获取 ip,这表明 DNS 服务器上的某些配置阻止了这种情况(可能是故意的?我也不是 DNS 专家) .
When it works:
当它工作时:
$ 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
When it doesnt work:
当它不起作用时:
$ 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
When it works:
当它工作时:
$ getent hosts msnbot-157-55-39-29.search.msn.com
157.55.39.29 msnbot-157-55-39-29.search.msn.com
When it doesn't:
当它没有时:
$ getent hosts baiduspider-123-125-71-75.crawl.baidu.com
$
As an alternative, you can use a DNS Service Provider for JNDI. The documentation has an example, but I'll leave a working snippet for you to test:
作为替代方案,您可以为 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());