blog

«
»

Get an IP range for a domain using PHP

One of my server hosting providers tells me that outgoing traffic from their data center can have any IP address within a /22 range.  So starting with the domain, I wanted to create a list of all of the IP addresses within that range to put in a whitelist.  This was actually a bit trickier than it sounds.  I ended up using a lot of binary operators and bitwise masking.  Since PHP doesn’t support unsigned int’s, I had to do a bit of extra masking to account for a possible sign bit.  So here’s my code (below).  I execute an nslookup and then parse the results for the IP address.  I then apply the range mask and create an array of IP addresses.  This code works for both Windows and Linux.


<?php
define ('CRLF', "\r\n");
setlocale(LC_ALL, 'us');
date_default_timezone_set("UTC");

header('Content-Type: text/plain');

$ips = getip('pmierau.com/30');
foreach ($ips as $ip)
  print $ip.CRLF;

exit;

/*
 * Get the array of IP addresses for a specific domain
 * 
 * If a range is specified for the domain (i.e. xyz.com/24), the returned array returns
 * IP aaddresses for the entire range (i.e. 256 addresses for a /24 range)
 */
function getip($url)
{
  $ips = array();
  
  $urlparts = explode('/', $url);
  if (isset($urlparts[1]))
  {
    $range = (int)$urlparts[1];
    $url = $urlparts[0];
  }
  else
  {
    $range = 0;
  }
  
  $cmd = 'nslookup '.$url;
  $descriptorspec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"));
  $process = proc_open($cmd, $descriptorspec, $pipes);
  if (is_resource($process))
  {
    $results = stream_get_contents($pipes[1]);
    $results .= stream_get_contents($pipes[2]);

    fclose($pipes[0]);
    fclose($pipes[1]);
    fclose($pipes[2]);

    $return_value = proc_close($process);
    
    // Parse the font information
    $lines = explode("\n", $results);
    $answer = false;
    foreach ($lines as $line)
    {
      $line = trim($line);
      
      if (false !== strpos($line, $url))
      {
        $answer = true;
      }
      elseif ($answer && ((false !== strpos($line, 'Address:')) || (false !== strpos($line, 'Addresses:'))))
      {
        $parts = explode(':', $line);
        $ip = trim($parts[1]);
        
        if ($range == 0)
        {
          $ips[] = $ip;
        }
        else
        {
          $binaryip = binaryip($ip);
          $mask = (0xffffffff << (32 - $range)) & 0xffffffff;
          $startbinaryip = $binaryip & $mask;
          $n = (~$mask) + 1;
          
          for ($ip = $startbinaryip, $i = $n; $i != 0; $ip++, $i--)
            $ips[] = ipv4ip($ip);
        }
        
        return $ips;
      }
    }
  }

  $ips[] = '?.?.?.?';
  return $ips;
}

/*
 * Convert an IPV4 address to it's binary equivalent
 */
function binaryip($ip)
{
  $ipparts = explode('.', $ip);
  $binaryip = 0;
  foreach ($ipparts as $ippart)
  {
    $binaryip = $binaryip << 8;
    $binaryip |= (int)$ippart;
  }
  
  return $binaryip;
}

/*
 * Convert a binary IP address to traditional IPV4 format
 */
function ipv4ip($binaryip)
{
  $ip1 = (($binaryip & 0xff000000) >> 24) & 0x000000ff;
  $ip2 = ($binaryip & 0x00ff0000) >> 16;
  $ip3 = ($binaryip & 0x0000ff00) >> 8;
  $ip4 = ($binaryip & 0x000000ff);
  
  return $ip1.'.'.$ip2.'.'.$ip3.'.'.$ip4;
}

?>

This entry was posted on Thursday, March 8th, 2012 at 5:39 pm and is filed under Software Development . You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply