download this file: traceroute.php view text/plain: traceroute.php file encoding: UTF-8 [goback]
#!/usr/bin/php
<?


define
('MICROSECOND'1000000); // 1 second in microseconds

define('SOL_IP'0);
define('IP_TTL'2);


function 
checksum($data) {
  
$bit unpack('n*'$data);
  
$sum array_sum($bit);

  if (
strlen($data) % 2) {
    
$temp unpack('C*'$data[strlen($data) - 1]);
    
$sum += $temp[1];
  }

  
$sum  = ($sum >> 16) + ($sum 0xffff);
  
$sum += ($sum >> 16);

  return 
pack('n*', ~$sum);
}




if (!isset(
$argv[1])) {
  die(
"usage: traceroute.php [-n] destination\n");
}

$host  end($argv); // Destination should always be the last argument.
$names = !in_array('-n'$argv); // Print hostnames or ip's.

// Is it an IP or hostname?
if (long2ip(ip2long($host)) === $host) {
  
$ip $host;
} else {
  
$ip gethostbyname($host);

  if (
$ip === $host) {
    die(
"invalid destination: $host\n");
  }
}


$sock = @socket_create(AF_INETSOCK_RAWgetprotobyname('icmp'));

if (
$sock === false) {
  die(
"Failed to create raw socket. Make sure you run this as root\n");
}


if (
$names) {
  
$host gethostbyaddr($ip);
}

echo 
"TRACEROUTE $host ($ip)\n";

$id  rand(00xFFFF);
$seq 1;

for (;;) {
  
socket_set_option($sockSOL_IPIP_TTL$seq);

  echo 
"$seq\t";

  
$packet '';
  
$packet .= chr(8); // Type
  
$packet .= chr(0); // Code
  
$packet .= chr(0); // Header Checksum
  
$packet .= chr(0);
  
$packet .= chr($id 0xFF); // Identifier
  
$packet .= chr($id >> 8  );
  
$packet .= chr($seq 0xFF); // Sequence Number
  
$packet .= chr($seq >> 8  );

  for (
$i 0$i 56; ++$i) { // Add 56 bytes of data
    
$packet .= chr(0);
  }

  
$checksum checksum($packet);

  
$packet[2] = $checksum[0];
  
$packet[3] = $checksum[1];
  
  
$start   microtime(true) * MICROSECOND;
  
$timeout $start MICROSECOND;
  
  
socket_sendto($sock$packetstrlen($packet), 0$ip0); // ICMP doesn't have a port so just use 0

  
for (;;) {
    
$now microtime(true) * MICROSECOND;

    if (
$now >= $timeout) {
      echo 
" *\n";
      break;
    }

    
$read  = array($sock);
    
$other = array();

    
$selected socket_select($read$other$other0$timeout $now);

    if (
$selected === 0) {
      echo 
" *\n";
      break;
    } else {
      
socket_recvfrom($sock$data655350$rip$rport);

      
$data unpack('C*'$data);

      if (
$data[10] != 1) { // ICMP
        
continue;
      }

      
$found 0;

      
// Is this our packet?
      
if (($data[21] == 0) && // Echo Reply
          
($data[25] == ($id 0xFF)) &&
          (
$data[26] == ($id >> 8))   &&
          (
$data[27] == ($seq 0xFF)) &&
          (
$data[28] == ($seq >> 8))) {
        
$found 1;
      } else if ((
$data[21] == 11) && // Time Exceeded
                 
(count($data) >= 56) &&
                 (
$data[53] == ($id 0xFF)) &&
                 (
$data[54] == ($id >> 8))   &&
                 (
$data[55] == ($seq 0xFF)) &&
                 (
$data[56] == ($seq >> 8))) {
        
$found 2;
      }

      if (
$found) {
        if (
$names) {
          
$rip gethostbyaddr($rip);
        }
        
        
$now  microtime(true) * MICROSECOND;
        
$time round(($now $start) / 10002); // ms

        
echo "$rip time=$time ms\n"// the header is 20 bytes

        
if ($found == 1) { // destination reached
          
die;
        }

        break;
      }
    }
  }

  ++
$seq;
}