Publié le 12/02/2013
Auteur Fobec
Réseaux sociaux
0 partages
0 tweets
0 plus
0 commentaires

Obtenir le nom d'hote d'une adresse IP

La résolution d'une adresse IP est utilisée pour identifier un périphérique sur le réseau. Contrairement à une adresse IP, le nom d'hote peut contenir des caractères bien souvent un nom de domaine.
Par exemple, le serveur DNS retourne crawl-66-249-65-102.googlebot.com sur l'adresse IP 66.249.65.102.

En PHP, le nom d'hote est obtenu avec la fonction gethostbyaddr(). Dans l'application de localisation d'ip, l'opération est répétée sans cesse pour en apprendre d'avantage sur une adresse ip. La rapidité de la fonction est importante, chaque seconde de perdu réduit les performances des scripts de geolocation.

Function php gethostbyaddr()

Prenons un benchmark pour mesurer les différences de performance de la fonction gethostbyaddr(). Le sigle @ sert à désactiver les warning sur cette fonction.
<?php
//Mesure de perf sur une adresse ip de Google
$t0=microtime(true);
$hostname=@gethostbyaddr('66.249.65.102');
$st=microtime(true)-$t0;
echo "IP 66.249.65.102 <br>nom d'hote :".$hostname."<br>duree :".substr($st,0,4).' sec';
//Mesure de perf sur une adresse ip située en Afrique
$t0=microtime(true);
$hostname=@gethostbyaddr('41.223.184.3 ');
$st=microtime(true)-$t0;
echo "<br>IP 41.223.184.3 <br>nom d'hote :".$hostname."<br>duree :".substr($st,0,4).' sec';
?>
Les mesures peuvent varier d'un serveur à un autre en fonction du serveur DNS utilisé. Dans notre cas, les temps de réponses sont ceux du serveur DNS Orange via de l'ADSL.

Résultats
IP 66.249.65.102
nom d'hote :crawl-66-249-65-102.googlebot.com
duree :0.02 sec
IP 41.223.184.3
nom d'hote :
duree :9.50 sec

L'adresse 41.223.184.3 ne retourne aucun nom d'hote. Le temps de réponse de 9 secondes correspond au timeout de la fonction gethostbyaddr(). Dans le cas des scripts de geoloc, c'est bien trop long !
Comment réduire la durée du Timeout ???
N'ayant pas trouvé de solution, j'ai préféré utiliser d'autres fonctions pour déterminer le nom d'hote d'une adresse ip.

Résolution avec le protocole UDP

Au fil des recherches, il apparait que la resolution du nom d'hote est une fonction de base sur un réseau. Cette fonction traduite à partir d'un code source en C semble parfait. Le timeout peut etre défini et le protocole UDP est en général rapide.
<?php
/**
* Function gethostbyaddr fast resolve Hostname and with Timeout !
*
* @see http://php.net/manual/en/function.gethostbyaddr.php#46869
* @param string $ip IP Address to resolve
* @param string $dns DNS Server IP
* @param int $timeout
* @return string Hostname
*/
function gethostbyaddr_timeout($ip, $dns, $timeout=1000) {
    // random transaction number (for routers etc to get the reply back)
    $data = rand(0, 99);
    // trim it to 2 bytes
    $data = substr($data, 0, 2);
    // request header
    $data .= "11";
    // split IP up
    $bits = explode(".", $ip);
    // error checking
    if (count($bits) != 4) return "ERROR";
    // there is probably a better way to do this bit...
    // loop through each segment
    for ($x=3; $x>=0; $x--) {
        // needs a byte to indicate the length of each segment of the request
        switch (strlen($bits[$x]))
        {
            case 1: // 1 byte long segment
                $data .= "1"; break;
            case 2: // 2 byte long segment
                $data .= "2"; break;
            case 3: // 3 byte long segment
                $data .= "3"; break;
            default: // segment is too big, invalid IP
                return "INVALID";break;
        }
        // and the segment itself
        $data .= $bits[$x];
    }
    // and the final bit of the request
    $data .= "7in-addr4arpa??x0C?1";
    // create UDP socket
    $handle = fsockopen("udp://$dns", 53);
    if (!$handle) {
        return NULL;
    }
    // send our request (and store request size so we can cheat later)
    $requestsize=fwrite($handle, $data);
    socket_set_timeout($handle, $timeout - $timeout00, $timeout00);
    // hope we get a reply
    $response = fread($handle, 1000);
    fclose($handle);
    if ($response == "") {
        return $ip;
    }
    // find the response type
    $type = @unpack("s", substr($response, $requestsize 2));
    if ($type[1] == 0x0C00)  // answer
    {
        // set up our variables
        $host="";
        $len = 0;
        // set our pointer at the beginning of the hostname
        // uses the request size from earlier rather than work it out
        $position=$requestsize 12;
        // reconstruct hostname
        do {
            // get segment size
            $len = unpack("c", substr($response, $position));
            // null terminated string, so length 0 = finished
            if ($len[1] == 0)
            // return the hostname, without the trailing .
            return substr($host, 0, strlen($host) -1);
            // add segment to our host
            $host .= substr($response, $position 1, $len[1]) . ".";
            // move pointer on to the next segment
            $position  = $len[1]   1;
        } while ($len != 0);
        // error - return the hostname we constructed (without the . on the end)
        return $ip;
    }
    return $ip;
}
?>
Le temps de réponse sont très bons sur tout type d'adresse IP, que le nom d'hote existe ou non. Au fil des tests, le script s'est bloqué sans raison à plusieurs reprises. Il suffisait de relancer la boucle, pour les prochaines 500 IP la fonction fonctionnait à merveille et soudain blocage.

Résolution avec la fonction Host de Linux

Les serveurs de Geoloc tournent sur des VM Linux, les scripts PHP ont donc accès aux fonctions de base de l'OS. La fonction suivante est un wrapper de la fonction host avec un timeout fixé à 2 secondes.
<?php
function gethostbyaddr_exec($ip) {
    $output = shell_exec('host -W 2 '.$ip);;
    if (ereg('.*pointer ([A-Za-z0-9.-] )..*',$output,$regs)) {
        return $regs[1];
    }
    return $ip;
}
?>
L'utilisation sous cette forme chargerait un peu le serveur Linux. Peu importe, la fonction retourne correctement le nom d'hotes et fonctionne correctement en boucle. Depuis plusieurs milliers d'IP sont passés à la moulinette et les temps de réponses ne dépassent jamais 2 secondes.

Ajouter un commentaire

Les champs marqués d'un * sont obligatoires, les adresses emails se sont pas publiées.

A lire aussi

Réseaux sociaux
Présentation de l'article
Catégorie
php5 - class
Mise a jour
12/02/2013
Visualisation
vu 7539 fois
Public
Internaute
Auteur de la publication
Fobec
Admin
Auteur de 267 articles
|BIO_PSEUDO|
Commentaires récents

Publié par Christophe dans CMS

en remplacant la ligne:
SHGetFileInfo(PChar(ePath.Text + SearchRec.Name), 0, FileInfo, SizeOf(FileInfo), SHGFI_ICON);
par la ligne
SHGetFileInfo(PChar(ePath.Text + Sear...

Publié par math dans java

Salut, quelle est la modification a faire pour pouvoir utiliser une webcam usb qui n'est pas une logitech?

Publié par tactictoe dans CMS

Erreur ligne 8 et 26:
Lire : Reg.OpenKey('\Software\Microsoft\Internet Explorer\Main\', false);
et non pas Reg.OpenKey('SoftwareMicrosoftInternet ExplorerMain', false);

Publié par Fred dans tuto

J'suis d'accord avec Do, PHP est deja un moteur de template.
Disons que le moteur de template permet de separer le code de la vue pour les debutants qui ont besoin qu'on leur impose des bornes...

Publié par Daxentuut dans java

Avec les imports c'est mieux :

import java.awt.AWTException
import java.awt.Robot
import java.awt.event.KeyEvent
import java.io.IOException
import java.util.logging.Level
import...