InetAddress.getCanonicalHostName() returns IP 而不是主机名
InetAddress.getCanonicalHostName() returns IP instead of Hostname
我在 Stack Overflow 上的 Java 中查找了如何进行 IP 查找,但答案与我已经在做的相符,并没有解决我的问题。
这是我的代码:
public void printHostname( String ip ) {
System.out.println( InetAddresses.forString( ip ).getCanonicalHostName( ) );
}
InetAddresses
只是 guava 库中的一个实用工具 class,用于获取 InetAdress
.
问题:此代码对某些 IP 地址按预期工作,但对其他一些 IP 地址不工作。
一个工作示例
例如,对于 IP 157.55.39.29,输出为:
msnbot-157-55-39-29.search.msn.com
根据 Linux host
命令,这个结果似乎是正确的:
> 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
命令 returns:
> 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 说:
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.
但我很确定这不是安全检查的真正问题...或者我不明白哪里出了问题。
您对解释这种行为有什么建议吗?您有解决方法吗?
编辑 #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
变量值?
我没有深入研究这个问题,所以我不知道为什么会这样,但是一些检查 DNS 服务器健康状况的在线工具 (like this one) 表明它们有一些问题可能相关也可能不相关。
正如@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
$
作为替代方案,您可以使用 DNS Service Provider for JNDI。该文档有一个示例,但我会留下一个工作片段供您测试:
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());
问题在于java.net.InetAdress
对ip-spoofing有一定的程序。
它首先将名称解析为(一个)IP 地址。这很好用。
在您的情况下,结果是两个 IP 地址。 InetAdress
然后检查这些地址(至少其中一个)是否解析为原始输入名称。
如果他们不这样做,它只是 returns 原始 ip 地址。下图为baiduspider-123-125-71-75.crawl.baidu.com
检查后的情况
注:getAllByName0
解析的ip地址与nslookup
解析的ip地址相同,即:
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 地址的安全隐患。
我在 Stack Overflow 上的 Java 中查找了如何进行 IP 查找,但答案与我已经在做的相符,并没有解决我的问题。
这是我的代码:
public void printHostname( String ip ) {
System.out.println( InetAddresses.forString( ip ).getCanonicalHostName( ) );
}
InetAddresses
只是 guava 库中的一个实用工具 class,用于获取 InetAdress
.
问题:此代码对某些 IP 地址按预期工作,但对其他一些 IP 地址不工作。
一个工作示例
例如,对于 IP 157.55.39.29,输出为:
msnbot-157-55-39-29.search.msn.com
根据 Linux host
命令,这个结果似乎是正确的:
> 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
命令 returns:
> 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 说:
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.
但我很确定这不是安全检查的真正问题...或者我不明白哪里出了问题。
您对解释这种行为有什么建议吗?您有解决方法吗?
编辑 #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
变量值?
我没有深入研究这个问题,所以我不知道为什么会这样,但是一些检查 DNS 服务器健康状况的在线工具 (like this one) 表明它们有一些问题可能相关也可能不相关。
正如@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
$
作为替代方案,您可以使用 DNS Service Provider for JNDI。该文档有一个示例,但我会留下一个工作片段供您测试:
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());
问题在于java.net.InetAdress
对ip-spoofing有一定的程序。
它首先将名称解析为(一个)IP 地址。这很好用。
在您的情况下,结果是两个 IP 地址。 InetAdress
然后检查这些地址(至少其中一个)是否解析为原始输入名称。
如果他们不这样做,它只是 returns 原始 ip 地址。下图为baiduspider-123-125-71-75.crawl.baidu.com
注:getAllByName0
解析的ip地址与nslookup
解析的ip地址相同,即:
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 地址的安全隐患。