<?php
/*******************************************************************************
** Basic Analysis and Security Engine (BASE)
** Copyright (C) 2004 BASE Project Team
** Copyright (C) 2000 Carnegie Mellon University
**
** (see the file 'base_main.php' for license details)
**
** Project Lead: Kevin Johnson <kjohnson@secureideas.net>
** Built upon work by Roman Danyliw <rdd@cert.org>, <roman@danyliw.com>
**
** Purpose: IP DNS, whois, event cache library   
********************************************************************************
** Authors:
********************************************************************************
** Kevin Johnson <kjohnson@secureideas.net
**
********************************************************************************
*/
/** The below check is to make sure that the conf file has been loaded before this one....
 **  This should prevent someone from accessing the page directly. -- Kevin
 **/
defined( '_BASE_INC' ) or die( 'Accessing this file directly is not allowed.' );

include_once("$BASE_path/base_stat_common.php");
include_once("$BASE_path/includes/base_log_error.inc.php");

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

  $cnt = 0;

  $ip_result = $db->baseExecute("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->baseFetchRow()) != NULL )
  {
     if ( $debug_mode > 0 )  
        echo $row[0]." - ".baseLong2IP($row[0])."<BR>";
     baseGetHostByAddr(baseLong2IP($row[0]), $db, $dns_cache_lifetime);
     ++$cnt;
  }
  $ip_result->baseFreeRows();

  $ip_result = $db->baseExecute("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->baseFetchRow()) != NULL )
  {
     if ( $debug_mode > 0 )  
        echo $row[0]." - ".baseLong2IP($row[0])."<BR>";  
     baseGetHostByAddr(baseLong2IP($row[0]), $db, $dns_cache_lifetime);
     ++$cnt;
  }
  $ip_result->baseFreeRows();

  ErrorMessage(_ADDED.$cnt._HOSTNAMESDNS);
}

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

  $cnt = 0;

  $ip_result = $db->baseExecute("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->baseFetchRow()) != NULL )
  {
     if ( $debug_mode > 0 )  echo $row[0]." - ".baseLong2IP($row[0])."<BR>";
     baseGetWhois(baseLong2IP($row[0]), $db, $whois_cache_lifetime);
     ++$cnt;
  }
  $ip_result->baseFreeRows();

  $ip_result = $db->baseExecute("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->baseFetchRow()) != NULL )
  {
     if ( $debug_mode > 0 )  echo $row[0]." - ".baseLong2IP($row[0])."<BR>";  
     baseGetWhois(baseLong2IP($row[0]), $db, $whois_cache_lifetime);
     ++$cnt;
  }
  $ip_result->baseFreeRows();

  ErrorMessage(_ADDED.$cnt._HOSTNAMESWHOIS);
}

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->baseExecute($sql);

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

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

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

     if ( $db->baseGetDBversion() >= 100 )
     {
        if ( $db->baseGetDBversion() >= 103 )
           $result = $db->baseExecute("SELECT sig_name, sig_class_id, sig_priority ".
                                      " FROM signature ".
                                      "WHERE sig_id = '".$signature."'");
        else
           $result = $db->baseExecute("SELECT sig_name FROM signature ".
                                      "WHERE sig_id = '".$signature."'");
        $row = $result->baseFetchRow();
        if ( $row )
        {
           $sig_name = $row[0];
           if ( $db->baseGetDBversion() >= 103 )
           {
              $sig_class_id = $row[1];
              $sig_priority = $row[2];
           }
           $result->baseFreeRows();
        } 
     }
  }
  else
  {
    ErrorMessage(_ERRCACHENULL);
    echo "<PRE>".$sql."</PRE>";
  }

  if ( $db->baseGetDBversion() >= 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->baseExecute($sql); 

  if ( $db->baseErrorMessage() != "" )
     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->baseGetDBversion() >= 100 ) 
  {
     $schema_specific[1] = ", sig_name"; 
     $schema_specific[2] = " INNER JOIN signature ON (signature = signature.sig_id)";
  }
  if ( $db->baseGetDBversion() >= 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->baseGetDBversion() < 100 )
     $schema_specific[1] = $schema_specific[1].", signature";

  $update_sql = array(4);

  /* IP events only */
   if ( $db->baseGetDBversion() >= 100 )
      $schema_specific[3] = " (sig_name LIKE 'spp_%') ";
   else
      $schema_specific[3] = " (signature LIKE 'spp_%') ";
  
  /* 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
    AND ( NOT ".$schema_specific[3].")";
  /* 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
     AND ( NOT ".$schema_specific[3].")";

   /* 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
      AND ( NOT ".$schema_specific[3].")";

   $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)";

   $update_cnt = count($update_sql);
   for ( $i = 0; $i < $update_cnt; $i++ )
   {
       $db->baseExecute($update_sql[$i]); 

       if ( $db->baseErrorMessage() != "" )
          ErrorMessage(_ERRCACHEERROR." ["._SENSOR." #$sid]["._EVENTTYPE." $i]".
                       " "._ERRCACHEUPDATE);
   }

}

function UpdateAlertCache($db)
{
  GLOBAL $debug_mode;

  $batch_sql = "";
  $batch_cnt = 0;

  $updated_cache_cnt = 0;

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

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

     /* Get highest CID for a given sensor in the cache */
     $ccid_lst = $db->baseExecute("SELECT MAX(cid) FROM acid_event WHERE sid='".$sid."'");
     $ccid_row = $ccid_lst->baseFetchRow();
     $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;
     }

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

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

 if ( preg_match("/base_main.php/", $_SERVER['REQUEST_URI']) )
       ErrorMessage(_ADDED.$updated_cache_cnt._ALERTSCACHE, "yellow");
 else
       ErrorMessage(_ADDED.$updated_cache_cnt._ALERTSCACHE);
}

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

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

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