<?php
/*
 * Analysis Console for Intrusion Databases (ACID)
 *
 * Author: Roman Danyliw <rdd@cert.org>, <roman@danyliw.com>
 *
 * Copyright (C) 2000, 2001, 2002 Carnegie Mellon University
 * (see the file 'acid_main.php' for license details)
 *
 * Purpose: TCP/IP network routines
 */

/****************************************************************************
 *
 * Function: acidIP2long()
 *
 * Purpose: convert a text string IPv4 address into its 32-bit numeric 
 *          equivalent
 *
 :* Arguments: $IP_str => dotted IPv4 address string (e.g. 1.2.3.4)
 *
 * Returns: 32-bit integer equivalent of the dotted address
 *          (e.g. 255.255.255.255 => 4294967295 ) 
 *
 ***************************************************************************/
function acidIP2long($IP_str)
{
   $tmp_long = ip2long($IP_str);
   if ( $tmp_long < 0 )
      $tmp_long = 4294967296 - abs($tmp_long);

   return $tmp_long;
}

/****************************************************************************
 *
 * Function: acidLong2IP()
 *
 * Purpose: convert a 32-bit integer into the corresponding IPv4 address 
 *          in dotted notation
 *
 * Arguments: $long_IP => 32-bit integer representation of IPv4 address
 *
 * Returns: IPv4 dotted address string (e.g. 4294967295 => 255.255.255.255)
 *
 ***************************************************************************/ 
function acidLong2IP($long_IP)
{
   $tmp_IP = $long_IP;
   if ( $long_IP > 2147483647 )
   {
      $tmp_IP = 4294967296 -  $tmp_IP;
      $tmp_IP = $tmp_IP * (-1); 
   }

   $tmp_IP = long2ip($tmp_IP);
   return $tmp_IP;
}

function acidDecBin($num)
{
   $str = decbin($num);
   for ( $i = strlen($str); $i < 8; $i++ )
     $str = "0".$str;

   return $str;
}

function getIPMask($ipaddr, $mask)
{
   if ( $mask == 32 )
      return array($ipaddr, $ipaddr);

   $ip_octets = explode(".", $ipaddr);
   $octet_id = floor($mask/8);
   $octet_bit = $mask % 8;
   $new_octet = $ip_octets[$octet_id];

   //echo "$ipaddr / $mask<BR>";
   //echo "octet_id = $octet_id (".acidDecBin($octet_id).")<BR>";
   //echo "octet_bit = $octet_bit (".acidDecBin($octet_bit).")<BR>";   
   //echo "new_octet = $new_octet (".acidDecBin($new_octet).")<BR>";

   $mask_high = 0;
   for ( $i = 7; $i > 7 - $octet_bit; $i--)
      $mask_high += pow(2, $i);

   $mask_low = 0;
   for ( $i = 0; $i <= 7 - $octet_bit; $i++)
       $mask_low += pow(2, $i);

   $mask_bottom = (integer) $new_octet & (integer) $mask_high;
   $mask_top = (integer) $mask_bottom | (integer) $mask_low;

   //echo "<PRE>".
   //     "IP octet:".acidDecBin($new_octet)." AND \n".
   //     "Mask (H):".acidDecBin($mask_high)."\n".
   //     "------------------------\n".
   //     "Bottom  :".acidDecBin($mask_bottom)." OR \n".
   //     "Mask (L):".acidDecBin($mask_low)." \n".
   //     "------------------------\n".
   //     "Top     :".acidDecBin($mask_top)."\n".
   //     "</PRE>";

   $ip_top = $ip_bottom = $ip_octets;
 
   $ip_bottom[$octet_id] = $mask_bottom;
   $ip_top[$octet_id] = $mask_top;

   for ( $i = $octet_id+1; $i < 4; $i++ )
   {
      $ip_top[$i] = 255;
      $ip_bottom[$i] = 0;
   }
  
   $ip_top_str = implode(".", $ip_top);
   $ip_bottom_str = implode(".", $ip_bottom);

   //echo $ip_bottom_str." -- ".$ip_top_str;

   return array($ip_bottom_str, $ip_top_str);
}

/****************************************************************************
 *
 * Function: acidGetHostByAddr()
 *
 * Purpose: resolves (and caches) an IP address to a hostname
 *
 * Arguments: $ipaddr         => IPv4 address in dotted notation
 *            $db             => DB handle
 *            $cache_lifetime => lifetime of DNS resolution
 *
 * Returns: hostname of $ipaddr
 *          OR an error message indicating resolution was not possible
 *
 ***************************************************************************/
function acidGetHostByAddr($ipaddr, $db, $cache_lifetime)
{
  $ip32 = acidIP2Long($ipaddr);

  $current_unixtime = time();
  $current_time = date("Y-m-d H:i:s",$current_unixtime);
  $sql = "SELECT ipc_ip,ipc_fqdn,".$db->acidSQL_UNIXTIME("(ipc_dns_timestamp)", "","").",ipc_dns_timestamp".
         " FROM acid_ip_cache ".
         " WHERE ipc_ip = '$ip32' ";

  $result = $db->acidExecute($sql);
  $ip_cache = $result->acidFetchRow();

  /* cache miss */
  if ( $ip_cache == "" ) 
  {
     $tmp = gethostbyaddr($ipaddr);

     /* add to cache regardless of whether can resolve */
     $sql = "INSERT INTO acid_ip_cache (ipc_ip, ipc_fqdn, ipc_dns_timestamp) ".
            "VALUES ($ip32, '$tmp', '$current_time')";
     $db->acidExecute($sql);
  }
  else     /* cache hit */
  {
     if ( (( ($ip_cache[2] / 60)+$cache_lifetime ) <= ($current_unixtime / 60)) &&
          ($ip_cache[2] != "") )
     {
        /* valid entry */
        if ( ($ip_cache[2] != "") && ($ip_cache[2] != 0) )
        {
           $tmp = $ip_cache[1];
        }
        else  /* name could not be resolved */
           $tmp = $ipaddr;
     }
     else  /* cache expired */
     {
        $tmp = gethostbyaddr($ipaddr);

        /* Update entry in cache regardless of whether can resolve */
        $sql = "UPDATE acid_ip_cache SET ipc_fqdn='$tmp', ".
               " ipc_dns_timestamp='$current_time' WHERE ipc_ip='$ip32'"; 
        $db->acidExecute($sql);
     }
  }

  if ( $tmp == $ipaddr )
     return "&nbsp;<I>Unable to resolve address</I>&nbsp;";
  else
     return $tmp;
}

/****************************************************************************
 *
 * Function: acidGetWhois()
 *
 * Purpose: Queries the proper whois server to determine info about 
 *          the given IP address
 *
 * Arguments: $ipaddr         => IPv4 address in dotted notation
 *            $db             => DB handle
 *            $cache_lifetime => lifetime of whois lookup
 *
 * Returns: whois information on $ipaddr
 *          OR an error message indicating resolution was not possible
 *
 ***************************************************************************/
function acidGetWhois($ipaddr, $db, $cache_lifetime)
{
  $ip32 = acidIP2Long($ipaddr);
  $current_unixtime = time();
  $current_time = date("Y-m-d H:i:s",$current_unixtime);
  $sql = "SELECT ipc_ip,ipc_whois,".$db->acidSQL_UNIXTIME("(ipc_whois_timestamp)", "","").",ipc_whois_timestamp".
         " FROM acid_ip_cache ".
         " WHERE ipc_ip = '$ip32' ";

  $result = $db->acidExecute($sql);
  $whois_cache = $result->acidFetchRow();

  //echo $whois_cache[0].",".$whois_cache[1].",".$whois_cache[2].
  //     ",".$whois_cache[3].",".$cache_lifetime.",".$current_unixtime;

  /* cache miss */
  if ( $whois_cache == "" )
  {
     $tmp = CallWhoisServer($ipaddr, $whois_server);

     /* add to cache regardless of whether can resolve */
     $sql = "INSERT INTO acid_ip_cache (ipc_ip, ipc_whois, ipc_whois_timestamp) ".
            "VALUES ($ip32, '".getSafeSQLString($tmp)."', '$current_time')";
     $db->acidExecute($sql);
  }
  else     /* cache hit */
  {
     /* cache valid */
     if ( ($whois_cache[2] != "") && ($whois_cache[2] != 0) )
     {
        if ( ($whois_cache[2] / 60 ) <= (($current_unixtime / 60) + $cache_lifetime) )
        {
           $tmp = $whois_cache[1];
           if ( strstr($tmp, "RIPE ") )  $whois_server = "RIPE";
           else if ( strstr($tmp, "www.apnic.net" ) ) $whois_server = "AP";
           else if ( strstr($tmp, "JPNIC database" ) ) $whois_server = "JPNIC";
           else $whois_server = "ARIN";
        }
     }
     else  /* cache expired */
     { 
        $tmp = CallWhoisServer($ipaddr, $whois_server);

        /* Update entry in cache regardless of whether can resolve */
        $sql = "UPDATE acid_ip_cache SET ipc_whois='".getSafeSQLString($tmp)."', ".
               " ipc_whois_timestamp='$current_time' WHERE ipc_ip='$ip32'";
        $db->acidExecute($sql);
     }
  }

  //acidProcessWhoisRaw($tmp, &$org, &$email, $whois_server);
  return $tmp;
}

function GetWhoisRaw($ipaddr, $whois_addr)
{
  $fp = fsockopen ($whois_addr, 43, $errno, $errstr, 15);

  if (!$fp)
  {
     echo "$errstr ($errno)<br>\n";
  }
  else
  {
     $response = "";
     fputs ($fp, "$ipaddr \r\n\r\n");
     while (!feof($fp))
     {
        $response = $response.(fgets ($fp,128));
     }
     fclose ($fp);
  }

  return $response;
}

function CallWhoisServer($ipaddr, &$whois_server)
{
/* IPs of Whois servers (rdd 5/12/2001)
 *
 * Name:    whois.arin.net
 * Addresses:  192.149.252.21, 192.149.252.22
 *
 * Name:    whois4.apnic.net
 * Address:  202.12.29.4
 * Aliases:  whois.apnic.net
 *
 * Name:    whois.ripe.net
 * Address:  193.0.0.135
 *
 * Name:    whois.nic.ad.jp
 * Address:  202.12.30.153
 *
 */

  $arin_ip  = "192.149.252.21";
  $apnic_ip = "202.12.29.4";
  $ripe_ip  = "193.0.0.135";
  $jnic_ip  = "202.12.30.153";

  $whois_server = "ARIN";
  $response = GetWhoisRaw($ipaddr, $arin_ip);

  if ( stristr($response, "Maintainer: RIPE") )
  {
     $response = GetWhoisRaw($ipaddr, $ripe_ip);
     $whois_server = "RIPE";
  }
  else if ( stristr($response, "Maintainer: AP") )
  {
     $response = GetWhoisRaw($ipaddr, $apnic_ip);
     $whois_server = "AP";
  }
  else if ( stristr($response, "Maintainer: JNIC") )
  {
     $response = GetWhoisRaw($ipaddr, $jnic_ip);
     $whois_server = "JNIC";
  }

  return $response;
} 

function acidProcessWhoisRaw($response, &$org, &$email, $server)
{
  if ( $server == "ARIN" )
  {
     $response_l = explode("\n", $response);

     /* organizational name */
     $org = $response_l[0];

    /* email */
    $email = "";
    for ( $i=1; $i < sizeof($response_l); $i++)
    {
        //echo "<BR>$i -- ".$response_l[$i];
        $line = explode(" ", $response_l[$i]);
        for ($j=0; $j < sizeof($line); $j++ )
        {
          //echo "<BR>&nbsp&nbsp&nbsp&nbsp $j -- ".$line[$j];
          if ( eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$", $line[$j]) )
          {
             if ( $email == "" )
                $email = $line[$j];
             else
                $email = $email.", ".$line[$j];
          }
        }
    }
  }
  else if ( $server == "RIPE" )
  {
     $response_l = explode("\n", $response);

     /* organizational name */
     $org = "";
     for ( $i=1; $i < sizeof($response_l); $i++)
     {
        if ( strstr($response_l[$i], "notify: ") )
           $email = chop(strstr($response_l[$i], ": "));
           //$email = substr(chop(strstr($response_l[$i], ": ")), 1, strlen($response_l[$i])-1) );

     }



     /* email */
     $email = "";
     for ( $i=1; $i < sizeof($response_l); $i++)
     {
        if ( strstr($response_l[$i], "notify:") )
        {
           //$email = chop( strstr($response_l[$i], ":") );
           $email = substr( chop( strstr($response_l[$i], ": ") ), 1, strlen($response_l[$i])-1 );
        }
     }

  }  
  else if ( $server == "AP" )
  {
  }
  else if ( $server == "JNIC" )
  {
  }

  echo "<BR><BR>org = $org<BR>email = $email<BR>";
}

function VerifySocketSupport()
{
   return function_exists("fsockopen");
}

?>
