From eee23281210ce6b4c3c9202dc275d0fd6649b09c Mon Sep 17 00:00:00 2001 From: arjen Date: Fri, 6 Dec 2002 07:08:04 +0000 Subject: [PATCH] New Gnucomo application: gcm_daemon. Scans for new log entries and processes the content. --- src/gcm_daemon/classes/configuration.class.php | 114 ++++++++++++ src/gcm_daemon/classes/gnucomo.process_log.php | 227 ++++++++++++++++++++++++ src/gcm_daemon/classes/gnucomo_config.class.php | 67 +++++++ src/gcm_daemon/classes/gnucomo_db_version.php | 128 +++++++++++++ src/gcm_daemon/gcm_daemon.php | 203 +++++++++++++++++++++ src/phpclasses/db.class.php | 60 +++++++ src/phpclasses/db.postgres.php | 106 +++++++++++ 7 files changed, 905 insertions(+) create mode 100755 src/gcm_daemon/classes/configuration.class.php create mode 100644 src/gcm_daemon/classes/gnucomo.process_log.php create mode 100644 src/gcm_daemon/classes/gnucomo_config.class.php create mode 100644 src/gcm_daemon/classes/gnucomo_db_version.php create mode 100755 src/gcm_daemon/gcm_daemon.php create mode 100644 src/phpclasses/db.class.php create mode 100644 src/phpclasses/db.postgres.php diff --git a/src/gcm_daemon/classes/configuration.class.php b/src/gcm_daemon/classes/configuration.class.php new file mode 100755 index 0000000..fa25a7d --- /dev/null +++ b/src/gcm_daemon/classes/configuration.class.php @@ -0,0 +1,114 @@ +type == XML_ELEMENT_NODE && $node[$i]->tagname == $tag) + { + $element = $node[$i]; + } + $i++; + } + + return $element; + } + + function read($app_name) + { + $filename = "/etc/" . $app_name . ".conf"; + $this->system = xmldocfile($filename); + + if (!$this->system) + { + $filename = "/usr/local/etc/" . $app_name . ".conf"; + $this->system = xmldocfile($filename); + } + + if ($this->system) + { + $root = $this->system->root(); + + if ($root->tagname != $app_name) + { + print("Configuration error: Wrong configuration file.
"); + $this->system = false; + } + } + else + { + print("Configuration error: Configuration file for $app_name not found.
"); + } + } + + function find_parameter($section, $parameter) + { + $param_value = ""; + + if ($this->system) + { + $root_node = $this->system->root(); + $section_node = $this->xmlFindTag($root_node->children(), $section); + if ($section_node) + { + $param_node = $this->xmlFindTag($section_node->children(), $parameter); + if ($param_node) + { + $param_node = $param_node->children(); + } + if ($param_node && $param_node[0]->type == XML_TEXT_NODE) + { + $param_value = $param_node[0]->content; + } + } + } + + return $param_value; + } +} + +?> diff --git a/src/gcm_daemon/classes/gnucomo.process_log.php b/src/gcm_daemon/classes/gnucomo.process_log.php new file mode 100644 index 0000000..83c30aa --- /dev/null +++ b/src/gcm_daemon/classes/gnucomo.process_log.php @@ -0,0 +1,227 @@ +db_result_row[6]); + $local_logline_array = explode (" ", $local_log_string); + + switch (strtolower($local_logline_array[4])) { + case "kernel:": + //This is a kernel logline now discover which type kernel-record we have + + //Detect if this is a network-line + if (strtolower(substr($local_logline_array[5],0,3)) == "in=") { + //this is a networkline call the processing the routines + $local_result = linux_kernel_network(); + return $local_result; + } else { + $local_failing_string = "Failing string: ".$dbms->db_result_row[5]; + syslog (LOG_INFO, "Unrecognized kernelline"); + syslog (LOG_INFO, $local_failing_string); + return "FALSE"; + } + break; + default: + break; + } + } + +function linux_kernel_network() { + + /* This function is able to deal with the output of kernel-network messages + * coming from iptables and other similar tools. When elements are found + * that cannot be identified a notification will be written to the logbook + * for easy expansion of this routine. + * INPUT : NONE + * GLOBALS : $dmbs + * OUTPUT : "TRUE" for success and "FALSE" for failure. + */ + global $dbms; + + $local_log_string = str_replace(" ", " ", $dbms->db_result_row[6]); + $local_logline_array = explode (" ", $local_log_string); + $local_sql_1 = "INSERT INTO log_adv_kernel_network"; //BASIC STATEMENT + $local_sql_2 = "logid, detailed_table"; //FIELDS + $local_sql_3 = "'".$dbms->db_result_row[0]."', 'kernel_network'"; //VALUES + $local_len = 0; + $local_id = 0; + + $local_dbms = copy_db_class($dbms); + + for ($i = 4; $i <= ( count($local_logline_array) - 1); $i++) { + //Process each element by exploding this based on the sign: = + $local_element = explode("=", $local_logline_array[$i]); + switch (strtolower($local_element[0])) { + + case "in": + $local_sql_2 .= ", device_in"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "out": + $local_sql_2 .= ", device_out"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "mac": + $local_sql_2 .= ", hw_address"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "src": + $local_sql_2 .= ", source_ip"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "dst": + $local_sql_2 .= ", destination_ip"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "len": + if ($local_len == 0) { + $local_sql_2 .= ", packet_length"; + $local_len++; + } else { + $local_sql_2 .= ", body_len"; + } + + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + + case "tos": + $local_sql_2 .= ", tos_bit"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "prec": + $local_sql_2 .= ", prec_bit"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "ttl": + $local_sql_2 .= ", ttl"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "id": + + if ($local_id == 0) { + $local_sql_2 .= ", header_id"; + $local_sql_3 .= ", '".$local_element[1]."'"; + $local_id = 1; + } + break; + + case "proto": + $local_sql_2 .= ", protocol"; + $local_sql_3 .= ", '".$local_element[1]."'"; + if ($local_element[1] == 'ICMP') { + $local_icmp = true; + } + break; + + case "spt": + $local_sql_2 .= ", destination_port"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "dpt": + $local_sql_2 .= ", source_port"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "window": + $local_sql_2 .= ", window"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "urgp": + $local_sql_2 .= ", urgp"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "rst": + $local_sql_2 .= ", rst"; + $local_sql_3 .= ", true"; + break; + + case "syn": + $local_sql_2 .= ", syn"; + $local_sql_3 .= ", true"; + break; + + case "df": + $local_sql_2 .= ", df"; + $local_sql_3 .= ", true"; + break; + + case "type": + $local_sql_2 .= ", type"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "code": + $local_sql_2 .= ", code"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "seq": + $local_sql_2 .= ", sequence_number"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "res": + $local_sql_2 .= ", res"; + $local_sql_3 .= ", '".$local_element[1]."'"; + break; + + case "[src": + /*This record is different. In ICMP information is sometimes returned on an original packet. + * When the brackets are used a second line will be added to the + * log_adv_kernel_network-table. For that reason the processing into the database will be + * done here as well. After that a new insert-string will be created. + */ + + //Enter the data into the database + $local_sql = $local_sql_1." (".$local_sql_2.") VALUES (".$local_sql_3.")"; + $local_dbms->query($local_sql); + + $local_sql_1 = "INSERT INTO log_adv_kernel_network"; //BASIC STATEMENT + $local_sql_2 = "logid, detailed_table"; //FIELDS + $local_sql_3 = "'".$dbms->db_result_row[0]."', 'kernel_network'"; //VALUES + $local_len = 0; + $local_id = 0; + break; + default: + $local_element[0]; + syslog(LOG_INFO, "Unrecognized kernel/network entry: ".$local_element[0]); + } + + } + + + //Now that the data is complete create the SQL-statement + $local_sql = $local_sql_1." (".$local_sql_2.") VALUES (".$local_sql_3.")"; + $local_dbms->query($local_sql); + RETURN "TRUE"; + + } + +?> diff --git a/src/gcm_daemon/classes/gnucomo_config.class.php b/src/gcm_daemon/classes/gnucomo_config.class.php new file mode 100644 index 0000000..8453adb --- /dev/null +++ b/src/gcm_daemon/classes/gnucomo_config.class.php @@ -0,0 +1,67 @@ +find_parameter("database", "name"); + if ($param != "") + { + $access_string .= "dbname=" . $param; + } + + $param = $this->find_parameter("database", "user"); + if ($param != "") + { + $access_string .= " user=" . $param; + } + + $param = $this->find_parameter("database", "password"); + if ($param != "") + { + $access_string .= " password=" . $param; + } + + $param = $this->find_parameter("database", "host"); + if ($param != "") + { + $access_string .= " host=" . $param; + } + + $param = $this->find_parameter("database", "port"); + if ($param != "") + { + $access_string .= " port=" . $param; + } + return $access_string; + } +}; +?> diff --git a/src/gcm_daemon/classes/gnucomo_db_version.php b/src/gcm_daemon/classes/gnucomo_db_version.php new file mode 100644 index 0000000..2346e96 --- /dev/null +++ b/src/gcm_daemon/classes/gnucomo_db_version.php @@ -0,0 +1,128 @@ +query($local_sql); + + case 2: + //In the log table processed should be false by default + $local_sql = "UPDATE log SET processed = false"; + $dbms->query($local_sql); + + case 3: + //In the log_adv a column is added that indicates where the detailed + //data has been written to + $local_sql = "ALTER TABLE log_adv ADD COLUMN detailed_table VARCHAR(75)"; + $dbms->query($local_sql); + + case 4: + //Create a log_adv_kernel_network table that recognizes the log-records + //that have come from the kernel-network interface (typically iptables). + $local_sql = "CREATE TABLE log_adv_kernel_network ("; + $local_sql .= "device_in VARCHAR(15), device_out VARCHAR(15), hw_address MACADDR, "; + $local_sql .= "source_ip INET, destination_ip INET, packet_length BIGINT, "; + $local_sql .= "tos_bit VARCHAR(5), "; + $local_sql .= "prec_bit VARCHAR(5), ttl INT, header_id BIGINT, source_port INT, "; + $local_sql .= "destination_port INT, body_length INT, protocol VARCHAR(5), "; + $local_sql .= "body_len INT"; + $local_sql .= ") INHERITS (log_adv)"; + $dbms->query($local_sql); + + case 5: + //Add the operating system to the object-table + //COLUMN os (VARCHAR - 25) + //COLUMN os_version (VARCHAR - 15) + $local_sql = "ALTER TABLE object ADD COLUMN os TEXT"; + $dbms->query($local_sql); + + $local_sql = "ALTER TABLE object ADD COLUMN os_version TEXT"; + $dbms->query($local_sql); + + $local_sql = "CREATE INDEX os ON object (os)"; + $dbms->query($local_sql); + + $local_sql = "CREATE INDEX os_version ON object (os, os_version)"; + $dbms->query($local_sql); + + case 6: + //Create a table with supported operating systems. Only after a implementation of a + //log-processing application a new OS will be added. This ensures the correctness of + //the entire system. + $local_sql = "CREATE TABLE supported_os (os_name TEXT, remarks TEXT)"; + $dbms->query($local_sql); + + $local_sql = "CREATE UNIQUE INDEX spp_os ON supported_os (os_name)"; + $dbms->query($local_sql); + + case 7: + //Create a column in the log table that indicates if the daemon did recognize the + //log-record. This makes it easier to trace which log-records still have to be added + //to the daemon. + $local_sql = "ALTER TABLE log ADD COLUMN recognized BOOLEAN"; + $dbms->query($local_sql); + + $local_sql = "ALTER TABLE log ALTER COLUMN recognized SET DEFAULT FALSE"; + $dbms->query($local_sql); + + case 8: + //Set the default value of processed to FALSE + $local_sql = "ALTER TABLE log ALTER COLUMN processed SET DEFAULT FALSE"; + $dbms->query($local_sql); + + case 9: + $local_sql = "ALTER TABLE log_adv_kernel_network ADD COLUMN window TEXT"; + $dbms->query($local_sql); + + $local_sql = "ALTER TABLE log_adv_kernel_network ADD COLUMN urgp INT"; + $dbms->query($local_sql); + + $local_sql = "ALTER TABLE log_adv_kernel_network ADD COLUMN syn BOOLEAN"; + $dbms->query($local_sql); + + $local_sql = "ALTER TABLE log_adv_kernel_network ALTER COLUMN syn SET DEFAULT FALSE"; + $dbms->query($local_sql); + + case 10: + + $local_sql = "ALTER TABLE log_adv_kernel_network ADD COLUMN type INT"; + $dbms->query($local_sql); + + $local_sql = "ALTER TABLE log_adv_kernel_network ADD COLUMN code INT"; + $dbms->query($local_sql); + + $local_sql = "ALTER TABLE log_adv_kernel_network ADD COLUMN sequence_number INT"; + $dbms->query($local_sql); + + case 11: + $local_sql = "ALTER TABLE log_adv_kernel_network ADD COLUMN res varchar(5)"; + $dbms->query($local_sql); + + $local_sql = "ALTER TABLE log_adv_kernel_network ADD COLUMN rst BOOLEAN"; + $dbms->query($local_sql); + + $local_sql = "ALTER TABLE log_adv_kernel_network ADD COLUMN df BOOLEAN"; + $dbms->query($local_sql); + + case 12: + $local_sql = "INSERT INTO db_value VALUES ('gcm_daemon_version', '1')"; + $dbms->query($local_sql); + } + + $active_version++; + $local_sql = "UPDATE db_value SET setting_value = ".$active_version." WHERE setting = 'db_version'"; + $dbms->query($local_sql); + + +?> diff --git a/src/gcm_daemon/gcm_daemon.php b/src/gcm_daemon/gcm_daemon.php new file mode 100755 index 0000000..8d56920 --- /dev/null +++ b/src/gcm_daemon/gcm_daemon.php @@ -0,0 +1,203 @@ +read($project_name); +$class_settings->database(); + +//Open an connection to the database +$dbms_type = $class_settings->find_parameter("database", "type"); +$dbms_host = $class_settings->find_parameter("database", "host"); +$dbms_name = $class_settings->find_parameter("database", "name"); +$dbms_user = $class_settings->find_parameter("gcm_daemon", "user"); +$dbms_password = $class_settings->find_parameter("gcm_daemon", "password"); + +db_select($dbms_type); +$dbms = new db(); +$dbms->db_host = $dbms_host; +$dbms->db_name = $dbms_name; +$dbms->db_user = $dbms_user; +$dbms->db_password = $dbms_password; +$dbms->db_connect(); + +if ($dbms->have_db_connection() == "FALSE") { + exit ("Database connection failed."); +} +//The database connection has been made. + +//Verify if the database is up-to-date by checking the versionnumber +$local_sql = "SELECT setting_value FROM db_value WHERE setting = 'db_version'"; +$dbms->query($local_sql); + +if ($dbms->fetch_row() == "TRUE") { + $active_version = $dbms->db_result_row[0]; + + //Update the database to the most recent version. + if ($active_version < $db_version) { + include ("classes/gnucomo_db_version.php"); + } +} else { + syslog (LOG_INFO, "Couldn't initialize database version. Is this a gnucomo database?"); + die ("Couldn't initialize database version.\n"); +} + +//If there is a new gcm_daemon_version the logrecords that couldn't be understood can be +//reprocessed. For this reason processed is now changed to false again for not recognized +//records. +$local_sql = " SELECT setting_value FROM db_value WHERE setting = 'gcm_daemon_version'"; +$dbms->query($local_sql); + +if ($dbms->fetch_row() == "TRUE") { + if ($dbms->db_result_row[0] < $gcmd_version) { + //Reactive log-records that weren't understood earlier. + $local_sql = "UPDATE log SET processed = false WHERE recognized = false"; + $dbms->query($local_sql); + + //Update de gcm_daemon version in the database + $local_sql = "UPDATE db_value SET setting_value = '".$gcmd_version; + $local_sql .= "' WHERE setting = 'gcm_daemon_version'"; + $dbms->query($local_sql); + + } + +} + + + +//At this place we start processing new log-lines +process_log (); + +//Tell the log that we're ending our efforts in a nice way +syslog (LOG_INFO, "gcm_daemon ended nicely"); + +function process_log () { + + /* This function will walk through the log-records that haven't been processed + * first a snapshot will be created of a the non-processed records. + * sequentially each record will dealt with. By doing that changes will be made + * in several log_adv_xxx tables + * INPUT : NONE + * OUTPUT : NONE + */ + global $dbms; + + //Find open records. + $local_sql = "SELECT * FROM log WHERE processed = FALSE"; + $dbms->query($local_sql); + $local_counter = 0; + + if ($dbms->num_rows() > 0) { + + //Create a database connection for changes in the database. + $dbms_changes = copy_db_class($dbms); + if ($dbms_changes->have_db_connection() == 'TRUE') { + + $local_sql = 0; + $local_object_os = ""; + $local_object_os_version = ""; + + //Walk through all the log-records. + + while ($local_counter < $dbms->num_rows()) { + $local_return_row = $dbms->fetch_row(); + if ($local_return_row == 'TRUE') { + //Work on active rows + $local_log_id = $dbms->db_result_row[0]; + + //If this is the first time get information about the object + if ($local_object_os == "") { + //No OS has been given yet, so let's find the objectid. + $local_findobject_db = copy_db_class($dbms); + + $local_sql_findobject = "SELECT os, os_version FROM object WHERE objectid = '".$dbms->db_result_row[0]."'"; + $local_findobject_db->query($local_sql_findobject); + $local_findobject_result = $local_findobject_db->fetch_row(); + if ($local_findobject_result == 'TRUE') { + $local_object_os = $local_findobject_db->db_result_row[0]; + if ($local_object_os == "") { + $local_object_os = "Linux"; + $local_object_os_version = "Unknown assuming Linux"; + } else { + $local_object_os_version = $local_findobject_db->db_result_row[1]; + } + } else { + syslog (LOG_INFO, "Couldn't find object for log-records"); + die("Couldn't match log-records to any existing object"); + } + } + + switch (strtolower($local_object_os)) { + case "linux": + $local_process_return = linux_log (); + break; + default: + syslog (LOG_INFO, "Couldn't find suitable OS for processing the logline"); + break; + } + + //Now that the processing took place change the processing state if processing was + //completed successfully. + if ($local_process_return == 'TRUE') { + $local_sql_processed = "UPDATE log SET recognized = TRUE where logid = $local_log_id"; + $dbms_changes->query($local_sql_processed); + } + + //Change the status of the log-record to processed. + $local_sql_processed = "UPDATE log SET processed = TRUE WHERE logid = $local_log_id"; + $dbms_changes->query($local_sql_processed); + + } else { + + break; + + } + $local_counter++; + } + } else { + syslog (LOG_INFO, "Couldn't clone database connection."); + die ("Couldn't reconnect to the database.\n"); + } + } +} + +?> + + diff --git a/src/phpclasses/db.class.php b/src/phpclasses/db.class.php new file mode 100644 index 0000000..5878a05 --- /dev/null +++ b/src/phpclasses/db.class.php @@ -0,0 +1,60 @@ + "xxxxx") { + require_once ("classes/db.".$local_db_type.".php"); + } + + function copy_db_class ($inp_class) { + /* This function takes a database class, sets the values for the connection, + * opens the connection and returns the new cloned class + * INPUT : inp_class - Typically a database class + * OUTPUT : Class - with cloned database. + */ + + $new_class = new db(); + $new_class->db_host = $inp_class->db_host; + $new_class->db_name = $inp_class->db_name; + $new_class->db_user = $inp_class->db_user; + $new_class->db_password = $inp_class->db_password; + $new_class->db_connect(); + return $new_class; + + } + + } +?> diff --git a/src/phpclasses/db.postgres.php b/src/phpclasses/db.postgres.php new file mode 100644 index 0000000..1ca3302 --- /dev/null +++ b/src/phpclasses/db.postgres.php @@ -0,0 +1,106 @@ +db_host == '') { + $local_connection_string .= "host=$this->db_host "; + } + + $local_connection_string = "dbname=$this->db_name user=$this->db_user "; + if ($this->db_password == '') { + $local_connection_string .= $this->db_password; + } + + $this->db_connection = @pg_pconnect($local_connection_string); + if ($this->have_db_connection() == "FALSE") { + syslog (LOG_INFO, "Failed to make a connection to Postgres"); + die ("connection to Postgres failed"); + } else { + syslog (LOG_INFO, "Connection to Postgres was made correctly"); + } + } + + function have_db_connection () { + /* This simple function verifies if a connection has succesfully been made + * Output: Returns TRUE if the connection was successfully (else it will be FALSE) + */ + // PHP-> 4.2.Xcode if (pg_connection_status($this->db_connection) == PGSQL_CONNECTION_BAD) { + if ($this->db_connection == '') { + return "FALSE"; + } else { + return "TRUE"; + } + } + + function query ($inp_sql_query) { + /* This function executes a query against the active database connection + * INPUT: + * - $inp_sql_query: The is the string with the SQL to execute + * OUTPUT: Resultstring + */ + $this->db_result = pg_exec ($this->db_connection, $inp_sql_query); + $this->db_row_number = 0; + } + + function fetch_row() { + /* This function returns a single row as a result of a query if the last record has been reached + * the result will be FALSE otherwise it will be TRUE + * INPUT : NONE (everything is available within the class) + * OUTPUT : Success TRUE/FALSE + * VALUES SET : + */ + unset ($this->db_result_row); + if (pg_num_rows($this->db_result) < $this->db_row_number) { + $this->db_row_number=-1; + return "FALSE"; + } else { + $this->db_result_row = pg_fetch_row($this->db_result); + return "TRUE"; + } + } + + function num_rows() { + /* This functions returns the number of rows in a resultset + * INPUT : NONE + * OUTPUT : Number of rows (number) + */ + return pg_numrows($this->db_result); + // 4.2.X return pg_num_rows($this->db_result); + } + + function num_fields() { + /* This function returns the number of fields in the resultset + * INPUT : NONE + * OUTPUT : Number of fields (number) + */ + return pg_numfields($this->db_result); + //4.2.X return pg_num_fields($this->db_result); + } + +} + +?> -- 2.11.0