<?php
# @ https://www.askapache.com/php/php-fsockopen-dns-udp/
# Copyright (C) 2013 Free Software Foundation, Inc.
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.



function gethostbyaddr_timeout$ip$dns$timeout ) {
    
// idea from http://www.php.net/manual/en/function.gethostbyaddr.php#46869
    // https://www.askapache.com/pub/php/gethostbyaddr.php
    
    // random transaction number (for routers etc to get the reply back)
    
$data rand1077 ) . "\1\0\0\1\0\0\0\0\0\0";
    
    
// octals in the array, keys are strlen of bit
    
$bitso = array("","\1","\2","\3" );
    foreach( 
array_reverseexplode'.'$ip ) ) as $bit ) {
        
$l=strlen($bit);
        
$data.="{$bitso[$l]}".$bit;
    }
    
    
// and the final bit of the request
    
$data .= "\7in-addr\4arpa\0\0\x0C\0\1";
        
    
// create UDP socket
    
$errno $errstr 0;
    
$fp fsockopen"udp://{$dns}"53$errno$errstr$timeout );
    if( ! 
$fp || ! is_resource$fp ) )
        return 
$errno;

    if( 
function_exists'socket_set_timeout' ) ) {
        
socket_set_timeout$fp$timeout );
    } elseif ( 
function_exists'stream_set_timeout' ) ) {
        
stream_set_timeout$fp$timeout );
    }


    
// send our request (and store request size so we can cheat later)
    
$requestsize fwrite$fp$data );
    
$max_rx $requestsize 3;
    
    
$start time();
    
$responsesize 0;
    while ( 
$received $max_rx && ( ( time() - $start ) < $timeout ) && ($buf fread$fp) ) !== false ) {
        
$responsesize++;
        
$response .= $buf;
    }
    
//echo "[tx: $requestsize bytes]  [rx: {$responsesize} bytes]";

    // hope we get a reply
    
if ( is_resource$fp ) )
        
fclose$fp );

    
// if empty response or bad response, return original ip
    
if ( empty( $response ) || bin2hexsubstr$response$requestsize 2) ) != '000c' )
        return 
$ip;
        
    
// set up our variables
    
$host '';
    
$len $loops 0;
    
    
// set our pointer at the beginning of the hostname uses the request size from earlier rather than work it out
    
$pos $requestsize 12;
    do {
        
// get segment size
        
$len unpack'c'substr$response$pos) );
        
        
// null terminated string, so length 0 = finished - return the hostname, without the trailing .
        
if ( $len[1] == )
            return 
substr$host0, -);
            
        
// add segment to our host
        
$host .= substr$response$pos 1$len[1] ) . '.';
        
        
// move pointer on to the next segment
        
$pos += $len[1] + 1;
        
        
// recursion protection
        
$loops++;
    }
    while ( 
$len[1] != && $loops 20 );
    
    
// return the ip in case 
    
return $ip;
}


?>