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

include_once("acid_stat_common.php");
include_once("acid_log_error.inc");

function UpdateDNSCache($db)
{
  GLOBAL $debug_mode, $dns_cache_lifetime;

  $cnt = 0;

  $ip_result = $db->acidExecute("SELECT DISTINCT ip_src FROM acid_event ".
                                "LEFT JOIN acid_ip_cache ON ipc_ip = ip_src ".
                                "WHERE ipc_fqdn IS NULL");

  while ( ($row = $ip_result->acidFetchRow()) != NULL )
  {
     if ( $debug_mode > 0 )  
        echo $row[0]." - ".acidLong2IP($row[0])."<BR>";
     acidGetHostByAddr(acidLong2IP($row[0]), $db, $dns_cache_lifetime);
     ++$cnt;
  }
  $ip_result->acidFreeRows();

  $ip_result = $db->acidExecute("SELECT DISTINCT ip_dst FROM acid_event ".
                                "LEFT JOIN acid_ip_cache ON ipc_ip = ip_dst ".
                                "WHERE ipc_fqdn IS NULL");
  while ( ($row = $ip_result->acidFetchRow()) != NULL )
  {
     if ( $debug_mode > 0 )  
        echo $row[0]." - ".acidLong2IP($row[0])."<BR>";  
     acidGetHostByAddr(acidLong2IP($row[0]), $db, $dns_cache_lifetime);
     ++$cnt;
  }
  $ip_result->acidFreeRows();

  ErrorMessage("Added ".$cnt." hostnames to the IP DNS cache");
}

function UpdateWhoisCache($db)
{
  GLOBAL $debug_mode, $whois_cache_lifetime;

  $cnt = 0;

  $ip_result = $db->acidExecute("SELECT DISTINCT ip_src FROM acid_event ".
                                "LEFT JOIN acid_ip_cache ON ipc_ip = ip_src ".
                                "WHERE ipc_whois IS NULL");

  while ( ($row = $ip_result->acidFetchRow()) != NULL )
  {
     if ( $debug_mode > 0 )  echo $row[0]." - ".acidLong2IP($row[0])."<BR>";
     acidGetWhois(acidLong2IP($row[0]), $db, $whois_cache_lifetime);
     ++$cnt;
  }
  $ip_result->acidFreeRows();

  $ip_result = $db->acidExecute("SELECT DISTINCT ip_dst FROM acid_event ".
                                "LEFT JOIN acid_ip_cache ON ipc_ip = ip_dst ".
                                "WHERE ipc_whois IS NULL");

  while ( ($row = $ip_result->acidFetchRow()) != NULL )
  {
     if ( $debug_mode > 0 )  echo $row[0]." - ".acidLong2IP($row[0])."<BR>";  
     acidGetWhois(acidLong2IP($row[0]), $db, $whois_cache_lifetime);
     ++$cnt;
  }
  $ip_result->acidFreeRows();

  ErrorMessage("Added ".$cnt." hostnames to the Whois cache");
}

function CacheAlert($sid, $cid, $db)
{
  $signature = $timestamp = $ip_src = $ip_dst = null;
  $ip_proto = $sport = $dport = $sig_name = null;
  $sig_class_id = $sig_priority = null;

  $sql = "SELECT signature, timestamp, ip_src, ip_dst, ip_proto FROM event ".
         "LEFT JOIN iphdr ON (event.sid=iphdr.sid AND event.cid = iphdr.cid) ".
         "WHERE (event.sid='".$sid."' AND event.cid='".$cid."') ORDER BY event.cid";

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

  $row = $result->acidFetchRow();
  if ( $row )
  {
     $signature = $row[0];
     $timestamp = $row[1];
     $ip_src    = $row[2];
     $ip_dst    = $row[3];
     $ip_proto  = $row[4];
     $result->acidFreeRows();

     if ( $ip_proto == TCP )
     {
        $result = $db->acidExecute("SELECT tcp_sport, tcp_dport FROM
                                    tcphdr WHERE sid='".$sid."' AND cid='".$cid."'");
        $row = $result->acidFetchRow();
        if ( $row )
        {
           $sport = $row[0];
           $dport = $row[1];
           $result->acidFreeRows();
        }
     }

     else if ( $ip_proto == UDP )
     {
        $result = $db->acidExecute("SELECT udp_sport, udp_dport FROM
                                    udphdr WHERE sid='".$sid."' AND cid='".$cid."'");
        $row = $result->acidFetchRow();
        if ( $row )
        {
           $sport = $row[0];
           $dport = $row[1];
           $result->acidFreeRows();
        }
     }

     if ( $db->acidGetDBVersion() >= 100 )
     {
        if ( $db->acidGetDBVersion() >= 103 )
           $result = $db->acidExecute("SELECT sig_name, sig_class_id, sig_priority ".
                                      " FROM signature ".
                                      "WHERE sig_id = '".$signature."'");
        else
           $result = $db->acidExecute("SELECT sig_name FROM signature ".
                                      "WHERE sig_id = '".$signature."'");
        $row = $result->acidFetchRow();
        if ( $row )
        {
           $sig_name = $row[0];
           if ( $db->acidGetDBVersion() >= 103 )
           {
              $sig_class_id = $row[1];
              $sig_priority = $row[2];
           }
           $result->acidFreeRows();
        } 
     }
  }
  else
  {
    ErrorMessage("Caching ERROR: NULL event row found?");
    echo "<PRE>".$sql."</PRE>";
  }


/*  GLOBAL $batch_sql, $batch_cnt;

  $batch_sql = $batch_sql."\n".
         "INSERT INTO acid_event (sid, cid, signature, sig_name, ".
         "timestamp, ip_src, ip_dst, ip_proto, layer4_sport, ".
         "layer4_dport) VALUES ('$sid', '$cid', '$signature', ".
         "'$sig_name','$timestamp','$ip_src','$ip_dst', ".
         "'$ip_proto', '$layer4_sport', '$layer4_dport');";
  $batch_cnt++;

  if ( $batch_cnt > 1000 )
  {
    $db->acidExecute($batch_sql);
    $batch_cnt = 0;
  } */

  if ( $db->acidGetDBVersion() >= 100 )
  {
    $sql = "INSERT INTO acid_event (sid, cid, signature, sig_name, ".
           "sig_class_id, sig_priority, ".
           "timestamp, ip_src, ip_dst, ip_proto, layer4_sport, ".
           "layer4_dport) VALUES ('$sid', '$cid', '$signature', ".
           "'$sig_name','$sig_class_id','$sig_priority',".
           "'$timestamp','$ip_src','$ip_dst', ".
           "'$ip_proto', '$layer4_sport', '$layer4_dport')";
  }
  else
  {
    $sql = "INSERT INTO acid_event (sid, cid, signature, ".
           "timestamp, ip_src, ip_dst, ip_proto, layer4_sport, ".
           "layer4_dport) VALUES ('$sid', '$cid', '$signature', ".
           "'$timestamp','$ip_src','$ip_dst', ".
           "'$ip_proto', '$layer4_sport', '$layer4_dport')";
  }

  $db->acidExecute($sql); 

  if ( $db->acidErrorMessage() != "" )
     return 0;
  else 
     return 1;
}

function CacheSensor($sid, $cid, $db)
/*
  Caches all alerts for sensor $sid newer than the event $cid
 */
{
  $schema_specific = array(2);

  $schema_specific[0] = "";
  $schema_specific[1] = "";
  $schema_specific[2] = "";

  if ( $db->acidGetDBVersion() >= 100 ) 
  {
     $schema_specific[1] = ", sig_name"; 
     $schema_specific[2] = " INNER JOIN signature ON (signature = signature.sig_id)";
  }
  if ( $db->acidGetDBVersion() >= 103 )
  {
     $schema_specific[0] = $schema_specific[0].", sig_priority, sig_class_id";
     $schema_specific[1] = $schema_specific[1].", sig_priority, sig_class_id"; 
     $schema_specific[2] = $schema_specific[2]."";
  }
  if ( $db->acidGetDBVersion() < 100 )
     $schema_specific[1] = $schema_specific[1].", signature";

  $update_sql = array(4);
  
  /* TCP events */
  $update_sql[0] =
    "INSERT INTO acid_event (sid,cid,signature,timestamp,
                             ip_src,ip_dst,ip_proto,
                             layer4_sport,layer4_dport,
                             sig_name".
                             $schema_specific[0].")
     SELECT event.sid as sid, event.cid as cid, signature, timestamp, 
            ip_src, ip_dst, ip_proto,
            tcp_sport as layer4_sport, tcp_dport as layer4_dport".
            $schema_specific[1]."
    FROM event
    ".$schema_specific[2]." 
    INNER JOIN iphdr ON (event.sid=iphdr.sid AND event.cid=iphdr.cid) 
    LEFT JOIN tcphdr ON (event.sid=tcphdr.sid AND event.cid=tcphdr.cid)
    WHERE (event.sid = $sid AND event.cid > $cid) AND ip_proto = 6";
  /* UDP events */

  $update_sql[1] = 
    "INSERT INTO acid_event (sid,cid,signature,timestamp,
                             ip_src,ip_dst,ip_proto,
                             layer4_sport,layer4_dport,
                             sig_name".
                             $schema_specific[0].")
     SELECT event.sid as sid, event.cid as cid, signature, timestamp,
            ip_src, ip_dst, ip_proto,
            udp_sport as layer4_sport, udp_dport as layer4_dport".
            $schema_specific[1]."
     FROM event
     ".$schema_specific[2]."
     INNER JOIN iphdr ON (event.sid=iphdr.sid AND event.cid=iphdr.cid)
     LEFT JOIN udphdr ON (event.sid=udphdr.sid AND event.cid=udphdr.cid)
     WHERE (event.sid = $sid AND event.cid > $cid) AND ip_proto = 17";

   /* ICMP events */
   $update_sql[2] = 
     "INSERT INTO acid_event (sid,cid,signature,timestamp,
                              ip_src,ip_dst,ip_proto,
                              sig_name".
                              $schema_specific[0].")
      SELECT event.sid as sid, event.cid as cid, signature, timestamp,
             ip_src, ip_dst, ip_proto".
             $schema_specific[1]."
      FROM event
      ".$schema_specific[2]."
      INNER JOIN iphdr ON (event.sid=iphdr.sid AND event.cid=iphdr.cid)
      LEFT JOIN icmphdr ON (event.sid=icmphdr.sid AND event.cid=icmphdr.cid)
      WHERE (event.sid = $sid AND event.cid > $cid) and ip_proto = 1";

   /* IP events only */
   if ( $db->acidGetDBVersion() >= 100 )
      $schema_specific[3] = " (sig_name LIKE 'spp_%') ";
   else
      $schema_specific[3] = " (signature LIKE 'spp_%') ";

   $update_sql[3] = 
     "INSERT INTO acid_event (sid,cid,signature,timestamp,
                              ip_src,ip_dst,ip_proto,
                              sig_name".
                              $schema_specific[0].")
      SELECT event.sid as sid, event.cid as cid, signature, timestamp,
             ip_src, ip_dst, ip_proto".
             $schema_specific[1]."
      FROM event
      ".$schema_specific[2]."
      LEFT JOIN iphdr ON (event.sid=iphdr.sid AND event.cid=iphdr.cid)
      WHERE (NOT (ip_proto IN (1, 6, 17))) AND ".
            " ( NOT ".$schema_specific[3].") AND
            (event.sid = $sid AND event.cid > $cid)";

   /* Event only -- pre-processor alerts */
   $update_sql[4] = 
     "INSERT INTO acid_event (sid,cid,signature,timestamp,
                              ip_src,ip_dst,ip_proto,
                              sig_name".
                              $schema_specific[0].")
      SELECT event.sid as sid, event.cid as cid, signature, timestamp,
             ip_src, ip_dst, ip_proto".
             $schema_specific[1]."
      FROM event
      ".$schema_specific[2]."
      LEFT JOIN iphdr ON (event.sid=iphdr.sid AND event.cid=iphdr.cid)
      WHERE ".$schema_specific[3]." AND 
      (event.sid = $sid AND event.cid > $cid)";
      //"WHERE ip_src IS NULL AND (event.sid = $sid AND event.cid > $cid)";

   $update_cnt = count($update_sql);
   for ( $i = 0; $i < $update_cnt; $i++ )
   {
       $db->acidExecute($update_sql[$i]); 
       // echo "<HR noshade><PRE>".$update_sql[$i]."</PRE>";

       if ( $db->acidErrorMessage() != "" )
          ErrorMessage("EVENT CACHING ERROR: [sensor #$sid][event type $i]".
                       " Could not update event cache");
   }

}

function UpdateAlertCache($db)
{
  GLOBAL $debug_mode;

  $batch_sql = "";
  $batch_cnt = 0;

  $updated_cache_cnt = 0;

  $sensor_lst = $db->acidExecute("SELECT sid FROM sensor");
  
  /* Iterate through all sensors in the SENSOR table */
  while ( ($sid_row = $sensor_lst->acidFetchRow()) != NULL )
  {
     $sid = $sid_row[0];

     /* Get highest CID for a given sensor */
     $cid_lst = $db->acidExecute("SELECT MAX(cid) FROM event WHERE sid='".$sid."'");
     $cid_row = $cid_lst->acidFetchRow();
     $cid = $cid_row[0];
     if ( $cid == NULL ) $cid = 0;

     /* Get highest CID for a given sensor in the cache */
     $ccid_lst = $db->acidExecute("SELECT MAX(cid) FROM acid_event WHERE sid='".$sid."'");
     $ccid_row = $ccid_lst->acidFetchRow();
     $ccid = $ccid_row[0];
     if ( $ccid == NULL ) $ccid = 0;

     if ( $debug_mode > 0 )
        echo "sensor #$sid: event.cid = $cid, acid_event.cid = $ccid";

     /* if the CID in the cache < the CID in the event table 
      *  then there are events which have NOT been added to the cache 
      */
     if ( $cid > $ccid )
     {
        $before_cnt = EventCntBySensor($sid, $db);        
        CacheSensor($sid, $ccid, $db);
        $updated_cache_cnt += EventCntBySensor($sid, $db) - $before_cnt;

        //$uncached_sql = "SELECT cid FROM event WHERE (sid='".$sid."' AND cid > '".$ccid."')".
                        " ORDER BY sid, cid"; 
        //echo $uncached_sql;
        //$uncached_lst = $db->acidExecute($uncached_sql);
        //while ( ($uncached_row = $uncached_lst->acidFetchRow()) != NULL )
        //{
           //echo "<BR>&nbsp;&nbsp;&nbsp;&nbsp;".$uncached_row[0];    
        //   $updated_cache_cnt += CacheAlert($sid, $uncached_row[0], $db);
        //}
        //$uncached_lst->acidFreeRows();        
     }

     if ( $debug_mode > 0 )
        echo "<BR>";

     $cid_lst->acidFreeRows();
     $ccid_lst->acidFreeRows();
  }  

  ErrorMessage("Added ".$updated_cache_cnt." alert(s) to the Alert cache");
}

function DropAlertCache($db)
{
  $db->acidExecute("DELETE FROM acid_event");
}

function DropDNSCache($db)
{
  $db->acidExecute("UPDATE acid_ip_cache SET ipc_fqdn = NULL, ipc_dns_timestamp = NULL");
}

function DropWhoisCache($db)
{
  $db->acidExecute("UPDATE acid_ip_cache SET ipc_whois = NULL, ipc_whois_timestamp = NULL");
}
?>
