InetAddress.getcanonicalhostname () retourne IP au lieu de Hostname
j'ai cherché comment faire la recherche IP dans Java on Stack Overflow mais les réponses correspondent à ce que je fais déjà et ne résolvent pas mon problème.
Voici mon code:
public void printHostname( String ip ) {
System.out.println( InetAddresses.forString( ip ).getCanonicalHostName( ) );
}
InetAddresses
est juste une classe utilitaire de goyave bibliothèque pour obtenir un InetAdress
.
le problème: ce code fonctionne comme prévu avec certaines adresses IP et pas avec d'autres.
exemple pratique
par exemple, pour IP 157.55.39.29, la sortie est:
msnbot-157-55-39-29.search.msn.com
ce résultat semble correct selon Linux host
commande:
> host 157.55.39.29
29.39.55.157.in-addr.arpa domain name pointer msnbot-157-55-39-29.search.msn.com.
un exemple qui ne fonctionne pas
pour IP 123.125.71.75, la commande host
retourne:
> host 123.125.71.75
75.71.125.123.in-addr.arpa domain name pointer baiduspider-123-125-71-75.crawl.baidu.com.
mais la sortie de mon code Java est:
123.125.71.75
alors que la production attendue devrait être
baiduspider-123-125-71-75.crawl.baidu.com
La javadoc de getCanonicalHostName méthode dit:
Retourne:
le nom de domaine complet pour cette adresse IP, ou si l'opération n'est pas autorisée par la vérification de sécurité, la représentation textuelle de l'adresse IP.
mais je suis assez sûr que ce n'est pas vraiment un problème avec un contrôle de sécurité... ou je ne comprends pas ce qui est mal.
avez-vous une suggestion pour expliquer ce comportement? Avez-vous une solution?
EDIT #1
en cherchant une solution, j'ai essayé de déboguer pas à pas l'implémentation dans 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);
dans ce code, la variable host
contient la valeur correcte, mais le dernier énoncé appelant getAllByName0
lance un UnknownHostException
qui est traité en retournant seulement L'adresse IP demandée. L'exception est lancée par la méthode interne getAddressesFromNameService
avec message:
"java.net.UnknownHostException: baiduspider-123-125-71-75.crawl.baidu.com"
je ne sais pas pourquoi.
puis-je obtenir la valeur de la variable host
, en contournant l'exception interne?
2 réponses
le problème réside dans le fait que le java.net.InetAdress
dispose d'une certaine procédure contre ip-spoofing.
il résout d'abord le nom en (une) adresse(s) ip. Cela fonctionne très bien.
Dans votre cas, le résultat sont deux adresses IP. InetAdress
vérifie ensuite si (au moins une de ces adresses) se résout au nom d'entrée original.
S'ils ne le font pas, il renvoie simplement l'adresse ip originale. L'image suivante montre la situation après le contrôle pour baiduspider-123-125-71-75.crawl.baidu.com
Note: les adresses IP résolues par getAllByName0
sont les mêmes que via nslookup
, à savoir:
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 solution serait d'utiliser la bibliothèque dnsjava . Il échappe au contrôle de mystification et fonctionne donc très bien.
exemple de dnsjava:
String addr = Address.getHostName(InetAddress.getByName("123.125.71.75"));
résultats escomptés baiduspider-123-125-71-75.crawl.baidu.com
clause de non-responsabilité: étant donné que je suis un développeur Java et non un expert en sécurité, je ne suis pas totalement conscient des implications en matière de sécurité de l'utilisation d'une adresse ip usurpée.
Je n'ai pas beaucoup creusé dans ce donc je ne sais pas pourquoi il se produit, mais certains outils en ligne ( comme celui-ci ) qui vérifie la santé des serveurs DNS indique qu'ils ont certains problèmes qui peuvent ou ne peuvent pas être liés.
comme @jah l'a dit, Java essaie de vérifier deux fois si le nom d'hôte a l'ip qu'il dit avoir. L'exception est levée sur le code natif, tout en essayant de le faire. En fait, dans mon cas, essayer de verify sur la ligne de commande, le nslookup ne parvient pas à obtenir l'ip à partir du nom, ce qui indique une certaine configuration empêchant cela sur le serveur DNS (peut-être exprès? Je ne suis pas un expert en DNS non plus).
quand ça marche:
$ 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
quand il ne fonctionne pas:
$ 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
quand ça marche:
$ getent hosts msnbot-157-55-39-29.search.msn.com
157.55.39.29 msnbot-157-55-39-29.search.msn.com
Quand ce n'est pas:
$ getent hosts baiduspider-123-125-71-75.crawl.baidu.com
$
Comme alternative, vous pouvez utiliser un Fournisseur de Service DNS pour JNDI . La documentation a un exemple, mais je vous laisse un extrait de travail à tester:
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());