FREE THOUGHT · FREE SOFTWARE · FREE WORLD

Home » PHP » Better, Faster, Stronger gethostbyaddr

by comment

Wow. where queries must be fast and only consist of a single request followed by a single reply packet

  1. User_Datagram_Protocol
  2. Domain_Name_System
  3. http://technet.microsoft.com/en-us/library/dd197470%28v=ws.10%29.aspx
  4. http://tools.ietf.org/html/rfc1035
  5. http://perplexed.co.uk/948_dns_message_format.htm
  6. http://pear.php.net/package/Net_DNS2/
Reverse lookup A reverse lookup is a query of the DNS for domain names when the IP address is known. Multiple domain names may be associated with an IP address. The DNS stores IP addresses in the form of domain names as specially formatted names in pointer (PTR) records within the infrastructure top-level domain arpa. For IPv4, the domain is in-addr.arpa. For IPv6, the reverse lookup domain is ip6.arpa. The IP address is represented as a name in reverse-ordered octet representation for IPv4, and reverse-ordered nibble representation for IPv6. When performing a reverse lookup, the DNS client converts the address into these formats before querying the name for a PTR record following the delegation chain as for any DNS query. For example, assuming the IPv4 address 208.80.152.2 is assigned to Wikimedia, it is represented as a DNS name in reverse order: 2.152.80.208.in-addr.arpa. When the DNS resolver gets a pointer (PTR) request, it begins by querying the root servers, which point to the servers of American Registry for Internet Numbers (ARIN) for the 208.in-addr.arpa zone. ARIN's servers delegate 152.80.208.in-addr.arpa to Wikimedia to which the resolver sends another query for 2.152.80.208.in-addr.arpa, which results in an authoritative response.
<?php

function get_hostbyaddr( $ip, $dns = '8.8.8.8', $timeout = 1 ) {
  ISCLOG::ti($ip);
  
  static $ips = array();
  
  if ( isset( $ips[ $ip ] ) ) return $ips[ $ip ];
  else $ips[ $ip ] = $ip;
  
  // random transaction number (for routers etc to get the reply back)
  $tx = rand( 10, 77 ) . "\1\0\0\1\0\0\0\0\0\0";
  
  // octals in the array, keys are strlen of bit
  $bitso = array( "", "\1", "\2", "\3" );
  $arpa = '';
  foreach( array_reverse( explode( '.', $ip ) ) as $bit ) {
    $arpa .= $bit . '.';
    $l = strlen( $bit );
    $tx .= "{$bitso[$l]}" . $bit;
  }
  $arpa .= 'in-addr.arpa';
  
  // and the final bit of the request
  $tx .= "\7in-addr\4arpa\0\0\x0C\0\1";

  // create UDP socket
  $errno = $errstr = 0;
  $fp = fsockopen( "udp://{$dns}", 53, $errno, $errstr, 0.5 );
  if( ! $fp || ! is_resource( $fp ) ) return ( $ips[ $ip ] = $ip );
  
  
  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)
  $tx_size = fwrite( $fp, $tx );
  $max_rx = $tx_size * 7;
  
  $start = time();
  $rx_size = $res_len = $stop_at = 0;
  $rx = '';
  
  while ( 
      (
        ( $stop_at > 0 && $rx_size < $stop_at ) || $stop_at == 0
      )
      && ! feof( $fp )
      && $rx_size < $max_rx
      && ( ( time() - $start ) < $timeout )
      && ($b = fread( $fp, 1 ) ) !== false
  ) {
    $rx_size++;
    $rx .= $b;

    if ( $stop_at == 0 && $res_len == 0 && ( $rx_size > $tx_size + 12 ) ) {
      $res_len = hexdec( bin2hex( substr( $rx, $tx_size + 11, 1 ) ) );
      $stop_at = ( $res_len + $tx_size + 12 );
    }
  }
  
  $response_length = hexdec( bin2hex( substr( $rx, $tx_size + 11, 1 ) ) );
  /*
  echo "[response_length]: {$response_length}  C:" .   bin2hex( substr( $rx, $tx_size + $response_length + 11, 1 )) . "  B:" . bin2hex( substr( $rx, -1 ) ) . "\n";
  echo "[tx: $tx_size bytes]  \n" . ISCLOG::hexdump($tx,array('ascii_len'=>50))."\n";
  echo "[rx: {$rx_size} bytes]\n" . ISCLOG::hexdump($rx,array('ascii_len'=>50))."\n";
  */

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

  // if empty response or bad response, return original ip
  if ( empty( $rx ) || bin2hex( substr( $rx, $tx_size + 2, 2 ) ) != '000c' || bin2hex( substr( $rx, -1 ) ) != '00' ) {
    //$hostip = @gethostbyname( $ip );

    echo "!!! [{$ip}  - tx:{$tx_size} rx:{$rx_size} stop:{$stop_at} res_len:{$res_len} ]  " . 
    " 000c:" . bin2hex( substr( $rx, $tx_size + 2, 2 ) ) . " 00:" . bin2hex( substr( $rx, -1 ) ) . "\n";
    //echo ISCLOG::hexdump($rx,array('ascii_len'=>50))."\n";
    //echo ISCLOG::hexdump($tx,array('ascii_len'=>50))."\n" . ISCLOG::hexdump($rx,array('ascii_len'=>50))."\n";
    //$ip = ( $hostip == $ip ) ? $ip : long2ip( ip2long( $ip ) );
  
    return ( $ips[ $ip ] = $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 = $tx_size + 12;
  do {
    $myc = substr( $rx, $pos, 1 );
    
    // get segment size
    if ( strlen( $myc ) > 0 ) $len = unpack( 'c', $myc );
    
    // null terminated string, so length 0 = finished - return the hostname, without the trailing .
    if ( $len[1] == 0 ) return ( $ips[ $ip ] = substr( $host, 0, -1 ) );
    
    // add segment to our host
    $host .= substr( $rx, $pos + 1, abs( $len[1] ) ) . '.';
    //ISCLOG::l($loops . ': '. 'pos:'.$pos. ' len:' . $len[1] . ' ' . $host);

    // move pointer on to the next segment
    $pos += $len[1] + 1;
    
  } while ( $len[1] != 0 && $loops++ < 40 );

  // return the ip in case 
  return ( $ips[ $ip ] = $ip );
}

Tags

Comments Welcome

Information is freedom. Freedom is non-negotiable. So please feel free to modify, copy, republish, sell, or use anything on this site in any way at any time ;)

My Online Tools

Popular Articles
Hacking and Hackers

The use of "hacker" to mean "security breaker" is a confusion on the part of the mass media. We hackers refuse to recognize that meaning, and continue using the word to mean someone who loves to program, someone who enjoys playful cleverness, or the combination of the two.
-- Richard M. Stallman


It's very simple - you read the protocol and write the code. -Bill Joy

Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 3.0 License, just credit with a link.
This site is not supported or endorsed by The Apache Software Foundation (ASF). All software and documentation produced by The ASF is licensed. "Apache" is a trademark of The ASF. NCSA HTTPd.
UNIX ® is a registered Trademark of The Open Group. POSIX ® is a registered Trademark of The IEEE.

+Askapache | htaccess.io | htaccess.guru

Site Map | Contact Webmaster | License and Disclaimer | Terms of Service | @Htaccess

↑ TOPMain