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 7584 fois
Public
Internaute
Auteur de la publication
Fobec
Admin
Auteur de 267 articles
|BIO_PSEUDO|
Commentaires récents

Publié par dotnet dans php5

Cette interface est intéressant par le fait qu'elle soit universelle, donc son intérêt pour moi est qu'elle permet l'accès aux bases de données Microsoft SQL Server....

Publié par brayan dans logiciel

je vous retour modem ip pour configury net firwell

Publié par xnadyx dans php5

Bonjour,

Est ce qu'il y a un autre moyen d'acces aux donnees Microsoft SQL Server?
Je ne trouve pas de tutoriaux sur Internet.

Merci.

Publié par Julie dans logiciel

C'est donc un moteur de recherche specialise. On peut vraiment rechercher tous les domaines que l'on veut. Cela permettrait aux gens de ne plus se faire arnaquer. Quelle bonne idee!

Publié par nico dans java

Petite erreur constate.
Apparemment il faut remplacer :
&mailTo = &?body=Envoyer un email avec Java
par &mailTo = < et commercial sans '<' et '>' &body=Envoyer un email avec Java