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?

11
demandé sur Toby Speight 2016-01-17 22:32:25

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

The debugger after the check for `original ip reverse lookup - name - dns lookup of name

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.

10
répondu jah 2016-01-28 13:36:12

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());
4
répondu ahirata 2016-01-21 15:56:39