The problem of broken DNS servers was causing me a problem because i had a page for user statistics that required around 20 reverse dns lookups to be done, and even as many as 5/6 of them being broken was causing a huge delay in loading the page. so i wrote a function that uses a UDP socket to talk directly to the DNS server (instead of going via the normal gethostbyaddr function) this let me set a timeout.
The only requirement is that your DNS server must be able to do recursive lookups, it wont go to other DNS servers if its told to... and of course you need to know your DNS servers IP address :-)
<?
function gethostbyaddr_timeout($ip, $dns, $timeout=1000)
{
$data = rand(0, 99);
$data = substr($data, 0, 2);
$data .= "\1\0\0\1\0\0\0\0\0\0";
$bits = explode(".", $ip);
if (count($bits) != 4) return "ERROR";
for ($x=3; $x>=0; $x--)
{
switch (strlen($bits[$x]))
{
case 1: $data .= "\1"; break;
case 2: $data .= "\2"; break;
case 3: $data .= "\3"; break;
default: return "INVALID";
}
$data .= $bits[$x];
}
$data .= "\7in-addr\4arpa\0\0\x0C\0\1";
$handle = @fsockopen("udp://$dns", 53);
$requestsize=@fwrite($handle, $data);
@socket_set_timeout($handle, $timeout - $timeout%1000, $timeout%1000);
$response = @fread($handle, 1000);
@fclose($handle);
if ($response == "")
return $ip;
$type = @unpack("s", substr($response, $requestsize+2));
if ($type[1] == 0x0C00) {
$host="";
$len = 0;
$position=$requestsize+12;
do
{
$len = unpack("c", substr($response, $position));
if ($len[1] == 0)
return substr($host, 0, strlen($host) -1);
$host .= substr($response, $position+1, $len[1]) . ".";
$position += $len[1] + 1;
}
while ($len != 0);
return $ip;
}
return $ip;
}
?>
This could be expanded quite a bit and improved but it works and i've seen quite a few people trying various methods to achieve something like this so i decided to post it here. on most servers it should also be more efficient than other methods such as calling nslookup because it doesn't need to run external programs
Note: I'm more a C person than a PHP person, so just ignore it if anything hasn't been done the *recomended* way :-)