From 5cb91e34272a69d7570225fbec703a8d30c49b93 Mon Sep 17 00:00:00 2001 From: BlackLight Date: Sat, 4 Sep 2010 21:33:53 +0200 Subject: [PATCH] Full support for MySQL (and any?) database alerts --- ChangeLog | 11 + Makefile | 8 +- TODO | 2 - alert_parser.c | 66 +-- cluster.c | 64 +-- db.c | 271 ++++++++++++ db.h | 47 ++ doc/html/alert__parser_8c.html | 126 +----- doc/html/annotated.html | 2 +- doc/html/classes.html | 2 +- doc/html/cluster_8c.html | 443 +------------------ doc/html/db_8c.html | 95 ++++ doc/html/db_8h.html | 140 ++++++ doc/html/db_8h_source.html | 116 +++++ doc/html/files.html | 5 +- doc/html/functions.html | 94 ++-- doc/html/functions_vars.html | 94 ++-- doc/html/globals.html | 141 ++++-- doc/html/globals_defs.html | 5 +- doc/html/globals_enum.html | 2 +- doc/html/globals_eval.html | 2 +- doc/html/globals_func.html | 109 +++-- doc/html/globals_type.html | 2 +- doc/html/globals_vars.html | 29 +- doc/html/group__alert__parser.html | 181 ++++++++ doc/html/group__cluster.html | 488 +++++++++++++++++++++ doc/html/group__mysql.html | 200 +++++++++ doc/html/group__regex.html | 126 ++++++ doc/html/group__sfPolicyConfig.html | 8 +- doc/html/group__spp__ai.html | 222 ++++++++++ doc/html/group__stream.html | 214 +++++++++ doc/html/index.html | 2 +- doc/html/modules.html | 8 +- doc/html/mysql_8c.html | 155 +++++++ doc/html/regex_8c.html | 60 +-- doc/html/search/all_5f.html | 40 +- doc/html/search/all_61.html | 133 +++--- doc/html/search/all_63.html | 8 +- doc/html/search/all_64.html | 106 ++++- doc/html/search/all_65.html | 2 +- doc/html/search/all_67.html | 10 +- doc/html/search/all_68.html | 18 +- doc/html/search/all_69.html | 46 +- doc/html/search/all_6d.html | 23 + doc/html/search/all_70.html | 4 +- doc/html/search/all_73.html | 52 +-- doc/html/search/all_74.html | 64 ++- doc/html/search/defines_64.html | 12 +- doc/html/search/files_64.html | 30 ++ doc/html/search/files_6d.html | 25 ++ doc/html/search/functions_5f.html | 28 +- doc/html/search/functions_61.html | 76 ++-- doc/html/search/functions_64.html | 20 +- doc/html/search/functions_6d.html | 38 ++ doc/html/search/functions_70.html | 4 +- doc/html/search/search.js | 8 +- doc/html/search/variables_5f.html | 2 +- doc/html/search/variables_61.html | 27 +- doc/html/search/variables_63.html | 8 +- doc/html/search/variables_64.html | 53 ++- doc/html/search/variables_65.html | 2 +- doc/html/search/variables_67.html | 10 +- doc/html/search/variables_68.html | 16 +- doc/html/search/variables_69.html | 36 +- doc/html/search/variables_73.html | 28 +- doc/html/search/variables_74.html | 62 ++- doc/html/sfPolicyUserData_8c.html | 6 +- doc/html/sf__dynamic__preproc__lib_8c.html | 2 +- doc/html/sf__preproc__info_8h.html | 28 +- doc/html/sf__preproc__info_8h_source.html | 4 +- doc/html/spp__ai_8c.html | 149 +------ doc/html/spp__ai_8h.html | 347 +++------------ doc/html/spp__ai_8h_source.html | 275 ++++++------ doc/html/stream_8c.html | 175 ++------ doc/html/structAI__config.html | 82 +++- doc/html/struct__AI__snort__alert.html | 280 ++++++------ doc/html/struct__hierarchy__node.html | 2 +- doc/html/structattribute__key.html | 9 +- doc/html/structattribute__value.html | 9 +- doc/html/structpkt__info.html | 10 +- doc/html/structpkt__key.html | 4 +- doc/latex/alert__parser_8c.tex | 79 +--- doc/latex/cluster_8c.tex | 231 +--------- doc/latex/db_8c.tex | 27 ++ doc/latex/db_8h.tex | 44 ++ doc/latex/doxygen.sty | 4 +- doc/latex/files.tex | 3 + doc/latex/group__alert__parser.tex | 85 ++++ doc/latex/group__cluster.tex | 248 +++++++++++ doc/latex/group__mysql.tex | 95 ++++ doc/latex/group__regex.tex | 34 ++ doc/latex/group__sfPolicyConfig.tex | 6 +- doc/latex/group__spp__ai.tex | 103 +++++ doc/latex/group__stream.tex | 103 +++++ doc/latex/modules.tex | 6 + doc/latex/mysql_8c.tex | 58 +++ doc/latex/refman.tex | 11 +- doc/latex/regex_8c.tex | 28 +- doc/latex/sfPolicyUserData_8c.tex | 4 +- doc/latex/sf__preproc__info_8h.tex | 19 +- doc/latex/spp__ai_8c.tex | 88 +--- doc/latex/spp__ai_8h.tex | 211 ++------- doc/latex/stream_8c.tex | 106 +---- doc/latex/structAI__config.tex | 45 +- doc/latex/struct__AI__snort__alert.tex | 159 +++---- doc/latex/structattribute__key.tex | 3 + doc/latex/structattribute__value.tex | 3 + doc/latex/structpkt__info.tex | 15 +- doc/latex/structpkt__key.tex | 3 + mysql.c | 72 +++ regex.c | 14 +- spp_ai.c | 142 +++++- spp_ai.h | 102 ++++- stream.c | 82 +++- tags | 433 ++++++++++++++---- 115 files changed, 5670 insertions(+), 2909 deletions(-) create mode 100644 db.c create mode 100644 db.h create mode 100644 doc/html/db_8c.html create mode 100644 doc/html/db_8h.html create mode 100644 doc/html/db_8h_source.html create mode 100644 doc/html/group__alert__parser.html create mode 100644 doc/html/group__cluster.html create mode 100644 doc/html/group__mysql.html create mode 100644 doc/html/group__regex.html create mode 100644 doc/html/group__spp__ai.html create mode 100644 doc/html/group__stream.html create mode 100644 doc/html/mysql_8c.html create mode 100644 doc/html/search/files_64.html create mode 100644 doc/html/search/files_6d.html create mode 100644 doc/html/search/functions_6d.html create mode 100644 doc/latex/db_8c.tex create mode 100644 doc/latex/db_8h.tex create mode 100644 doc/latex/group__alert__parser.tex create mode 100644 doc/latex/group__cluster.tex create mode 100644 doc/latex/group__mysql.tex create mode 100644 doc/latex/group__regex.tex create mode 100644 doc/latex/group__spp__ai.tex create mode 100644 doc/latex/group__stream.tex create mode 100644 doc/latex/mysql_8c.tex create mode 100644 mysql.c diff --git a/ChangeLog b/ChangeLog index 25c0345..dcabf32 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2010-09-04 Fabio "BlackLight" Manganiello + * mysql.c: This file now only contains the functions for managing MySQL + connections in the database wrapper + * db.c: Renamed from 'mysql.c' to 'db.c', now it should be abstract + enough for allowing the support for any database alerts without any lines + of code should be changed + * db.c: Fixed a stupid malloc() mistake that randomly brought the module + to crash + * db.h: New file, including macros and typedefs for allowing the database + operations wrapping + 2010-16-08 Fabio "BlackLight" Manganiello * cluster.c: Finished clustering algorithm and clustering log management diff --git a/Makefile b/Makefile index 77552cc..579ce5f 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ INCLUDES=-I. -I../../.. -I../include -I./uthash DEFINES=-D_GNU_SOURCE -D_XOPEN_SOURCE -DDYNAMIC_PLUGIN -DSUP_IP6 -DENABLE_MYSQL -DHAVE_CONFIG_H CMDLINE=-g -O2 -fvisibility=hidden -fno-strict-aliasing -Wall -fstack-protector LIBPATH=-L/usr/lib -LDLINKS=-lpthread +LDLINKS=-lpthread -lmysqlclient LIBTOOL=./libtool --tag=CC OUTPUT=libsf_ai_preproc.la LDOPTIONS=-export-dynamic -rpath ${PREPROC_PATH} @@ -18,7 +18,9 @@ spp_ai.lo \ stream.lo \ alert_parser.lo \ regex.lo \ -cluster.lo +cluster.lo \ +db.lo \ +mysql.lo all: /bin/sh ${LIBTOOL} --mode=compile gcc ${CMDLINE} ${INCLUDES} ${DEFINES} -c -o sf_dynamic_preproc_lib.lo sf_dynamic_preproc_lib.c @@ -28,6 +30,8 @@ all: /bin/sh ${LIBTOOL} --mode=compile gcc ${CMDLINE} ${INCLUDES} ${DEFINES} -c -o stream.lo stream.c /bin/sh ${LIBTOOL} --mode=compile gcc ${CMDLINE} ${INCLUDES} ${DEFINES} -c -o spp_ai.lo spp_ai.c /bin/sh ${LIBTOOL} --mode=compile gcc ${CMDLINE} ${INCLUDES} ${DEFINES} -c -o cluster.lo cluster.c + /bin/sh ${LIBTOOL} --mode=compile gcc ${CMDLINE} ${INCLUDES} ${DEFINES} -c -o db.lo db.c + /bin/sh ${LIBTOOL} --mode=compile gcc ${CMDLINE} ${INCLUDES} ${DEFINES} -c -o mysql.lo mysql.c /bin/sh ${LIBTOOL} --mode=link gcc ${CMDLINE} ${LDOPTIONS} ${LIBPATH} -o ${OUTPUT} ${OBJECTS} ${LDLINKS} clean: diff --git a/TODO b/TODO index 536f6bd..3e22cc6 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,4 @@ -- Check cluster ranges are NEVER on the same ranges - Managing clusters for addresses, timestamps (and more?) -- MySQL alert log parsing - Dynamic cluster_min_size algorithm - Alerts for port scan, grouped alerts, UDP and ICMP too diff --git a/alert_parser.c b/alert_parser.c index 25304d1..c156232 100644 --- a/alert_parser.c +++ b/alert_parser.c @@ -24,19 +24,22 @@ #include #include #include +#include PRIVATE AI_snort_alert *alerts = NULL; PRIVATE FILE *alert_fp = NULL; +/** \defgroup alert_parser Parse the alert log into binary structures + * @{ */ + /** - * FUNCTION: AI_alertparser_thread * \brief Thread for parsing Snort's alert file * \param arg void* pointer to module's configuration */ void* -AI_alertparser_thread ( void* arg ) +AI_file_alertparser_thread ( void* arg ) { struct logtime { unsigned short day; @@ -68,8 +71,6 @@ AI_alertparser_thread ( void* arg ) while ( 1 ) { - FILE *fp = fopen ( "/home/blacklight/LOG", "a" ); - if (( ifd = inotify_init() ) < 0 ) { _dpd.fatalMsg ( "Could not initialize an inotify object on the alert log file" ); @@ -101,6 +102,8 @@ AI_alertparser_thread ( void* arg ) fseek ( alert_fp, 0, SEEK_END ); read ( ifd, line, sizeof(line) ); + inotify_rm_watch ( ifd, wd ); + close ( ifd ); while ( !feof ( alert_fp )) { @@ -117,10 +120,10 @@ AI_alertparser_thread ( void* arg ) { if ( in_alert ) { - if ( alert->ipproto == IPPROTO_TCP ) + if ( alert->ip_proto == IPPROTO_TCP ) { - key.src_ip = alert->src_addr; - key.dst_port = alert->dst_port; + key.src_ip = alert->ip_src_addr; + key.dst_port = alert->tcp_dst_port; if (( info = AI_get_stream_by_key ( key ) )) { @@ -211,10 +214,10 @@ AI_alertparser_thread ( void* arg ) strptime ( strtime, "%d/%m/%Y, %H:%M:%S", _tm ); alert->timestamp = mktime ( _tm ); - alert->src_addr = inet_addr ( matches[5] ); - alert->dst_addr = inet_addr ( matches[7] ); - alert->src_port = htons ( atoi( matches[6] )); - alert->dst_port = htons ( atoi( matches[8] )); + alert->ip_src_addr = inet_addr ( matches[5] ); + alert->ip_dst_addr = inet_addr ( matches[7] ); + alert->tcp_src_port = htons ( atoi( matches[6] )); + alert->tcp_dst_port = htons ( atoi( matches[8] )); for ( i=0; i < nmatches; i++ ) free ( matches[i] ); @@ -240,8 +243,8 @@ AI_alertparser_thread ( void* arg ) strptime ( strtime, "%d/%m/%Y, %H:%M:%S", _tm ); alert->timestamp = mktime ( _tm ); - alert->src_addr = inet_addr ( matches[5] ); - alert->dst_addr = inet_addr ( matches[6] ); + alert->ip_src_addr = inet_addr ( matches[5] ); + alert->ip_dst_addr = inet_addr ( matches[6] ); for ( i=0; i < nmatches; i++ ) free ( matches[i] ); @@ -251,26 +254,26 @@ AI_alertparser_thread ( void* arg ) } else if ( preg_match ( "^([^\\s+]+)\\s+TTL:\\s*([0-9]+)\\s+TOS:\\s*0x([0-9A-F]+)\\s+ID:\\s*([0-9]+)\\s+IpLen:\\s*([0-9]+)", line, &matches, &nmatches ) > 0 ) { if ( !strcasecmp ( matches[0], "tcp" ) ) { - alert->ipproto = IPPROTO_TCP; + alert->ip_proto = IPPROTO_TCP; } else if ( !strcasecmp ( matches[0], "udp" ) ) { - alert->ipproto = IPPROTO_UDP; + alert->ip_proto = IPPROTO_UDP; } else if ( !strcasecmp ( matches[0], "icmp" ) ) { - alert->ipproto = IPPROTO_ICMP; + alert->ip_proto = IPPROTO_ICMP; } else { - alert->ipproto = IPPROTO_NONE; + alert->ip_proto = IPPROTO_NONE; } - alert->ttl = htons ( (uint16_t) strtoul ( matches[1], NULL, 10 )); - alert->tos = htons ( (uint16_t) strtoul ( matches[2], NULL, 16 )); - alert->id = htons ( (uint16_t) strtoul ( matches[3], NULL, 10 )); - alert->iplen = htons ( (uint16_t) strtoul ( matches[4], NULL, 10 )); + alert->ip_ttl = htons ( (uint16_t) strtoul ( matches[1], NULL, 10 )); + alert->ip_tos = htons ( (uint16_t) strtoul ( matches[2], NULL, 16 )); + alert->ip_id = htons ( (uint16_t) strtoul ( matches[3], NULL, 10 )); + alert->ip_len = htons ( (uint16_t) strtoul ( matches[4], NULL, 10 )); for ( i=0; i < nmatches; i++ ) free ( matches[i] ); free ( matches ); matches = NULL; - } else if ( preg_match ( "^([\\*UAPRSF]{8})\\s+Seq:\\s*0x([0-9A-F]+)\\s+Ack:\\s*0x([0-9A-F]+)\\s+Win:\\s*0x([0-9A-F]+)\\s+TcpLen:\\s*([0-9]+)", + } else if ( preg_match ( "^([\\*CEUAPRSF]{8})\\s+Seq:\\s*0x([0-9A-F]+)\\s+Ack:\\s*0x([0-9A-F]+)\\s+Win:\\s*0x([0-9A-F]+)\\s+TcpLen:\\s*([0-9]+)", line, &matches, &nmatches ) > 0 ) { alert->tcp_flags = 0; alert->tcp_flags |= ( strstr ( matches[0], "C" ) ) ? TCPHEADER_RES1 : 0; @@ -282,10 +285,10 @@ AI_alertparser_thread ( void* arg ) alert->tcp_flags |= ( strstr ( matches[0], "S" ) ) ? TCPHEADER_SYN : 0; alert->tcp_flags |= ( strstr ( matches[0], "F" ) ) ? TCPHEADER_FIN : 0; - alert->sequence = htonl ( strtoul ( matches[1], NULL, 16 )); - alert->ack = htonl ( strtoul ( matches[2], NULL, 16 )); - alert->window = htons ( (uint16_t) strtoul ( matches[3], NULL, 16 )); - alert->tcplen = htons ( (uint16_t) strtoul ( matches[4], NULL, 10 )); + alert->tcp_seq = htonl ( strtoul ( matches[1], NULL, 16 )); + alert->tcp_ack = htonl ( strtoul ( matches[2], NULL, 16 )); + alert->tcp_window = htons ( (uint16_t) strtoul ( matches[3], NULL, 16 )); + alert->tcp_len = htons ( (uint16_t) strtoul ( matches[4], NULL, 10 )); for ( i=0; i < nmatches; i++ ) free ( matches[i] ); @@ -294,17 +297,14 @@ AI_alertparser_thread ( void* arg ) matches = NULL; } } - - fclose ( fp ); } + pthread_exit ((void*) 0 ); return (void*) 0; -} /* ----- end of function AI_alertparser_thread ----- */ - +} /* ----- end of function AI_file_alertparser_thread ----- */ /** - * FUNCTION: _AI_copy_alerts * \brief Create a copy of the alert log struct (this is done for leaving the alert log structure in this file as read-only) * \param node Starting node (used for the recursion) * \return A copy of the alert log linked list @@ -336,7 +336,6 @@ _AI_copy_alerts ( AI_snort_alert *node ) /** - * FUNCTION: AI_get_alerts * \brief Return the alerts parsed so far as a linked list * \return An AI_snort_alert pointer identifying the list of alerts */ @@ -348,7 +347,6 @@ AI_get_alerts () /** - * FUNCTION: AI_free_alerts * \brief Deallocate the memory of a log alert linked list * \param node Linked list to be freed */ @@ -365,3 +363,5 @@ AI_free_alerts ( AI_snort_alert *node ) node = NULL; } /* ----- end of function AI_free_alerts ----- */ +/** @} */ + diff --git a/cluster.c b/cluster.c index f853be3..53b2e4a 100644 --- a/cluster.c +++ b/cluster.c @@ -5,7 +5,7 @@ * * Description: Module for managing alarm clustering and cluter hierarchies * - * Version: 1.0 + * Version: 0.1 * Created: 12/08/2010 12:43:28 * Revision: none * Compiler: gcc @@ -22,15 +22,18 @@ #include #include #include -#include +#include -/* Identifier key for a cluster attribute value */ +/** \defgroup cluster Manage the clustering of alarms + * @{ */ + +/** Identifier key for a cluster attribute value */ typedef struct { int min; int max; } attribute_key; -/* Representation of a cluster attribute value */ +/** Representation of a cluster attribute value */ typedef struct { attribute_key key; cluster_type type; @@ -45,7 +48,6 @@ PRIVATE AI_snort_alert *alert_log = NULL; /** - * FUNCTION: _heuristic_func * \brief Function that picks up the heuristic value for a clustering attribute in according to Julisch's heuristic (ACM, Vol.2, No.3, 09 2002, pag.124) * \param type Attribute type * \return The heuristic coefficient for that attribute, -1 if no clustering information is available for that attribute @@ -113,7 +115,6 @@ _heuristic_func ( cluster_type type ) } /* ----- end of function _heuristic_func ----- */ /** - * FUNCTION: _hierarchy_node_new * \brief Create a new clustering hierarchy node * \param label Label for the node * \param min_val Minimum value for the range represented by the node @@ -143,7 +144,6 @@ _hierarchy_node_new ( char *label, int min_val, int max_val ) /** - * FUNCTION: _hierarchy_node_append * \brief Append a node to a clustering hierarchy node * \param parent Parent node * \param child Child node @@ -182,7 +182,6 @@ _hierarchy_node_append ( hierarchy_node *parent, hierarchy_node *child ) /** - * FUNCTION: _AI_get_min_hierarchy_node * \brief Get the minimum node in a hierarchy tree that matches a certain value * \param val Value to be matched in the range * \param root Root of the hierarchy @@ -219,7 +218,6 @@ _AI_get_min_hierarchy_node ( int val, hierarchy_node *root ) } /* ----- end of function _AI_get_min_hierarchy_node ----- */ /** - * FUNCTION: _AI_equal_alarms * \brief Check if two alerts are semantically equal * \param a1 First alert * \param a2 Second alert @@ -267,7 +265,6 @@ _AI_equal_alarms ( AI_snort_alert *a1, AI_snort_alert *a2 ) /** - * FUNCTION: _AI_merge_alerts * \brief Merge the alerts marked as equal in the log * \param log Alert log reference * \return The number of merged couples @@ -309,7 +306,6 @@ _AI_merge_alerts ( AI_snort_alert **log ) /** - * FUNCTION: _AI_print_clustered_alerts * \brief Print the clustered alerts to a log file * \param log Log containing the alerts * \param fp File pointer where the alerts will be printed @@ -335,34 +331,34 @@ _AI_print_clustered_alerts ( AI_snort_alert *log, FILE *fp ) timestamp[ strlen(timestamp)-1 ] = 0; fprintf ( fp, "[Grouped alerts: %d] [Starting from: %s]\n", tmp->grouped_alarms_count, timestamp ); - if ( h_root[src_addr] ) + if ( h_root[src_addr] && tmp->h_node[src_addr] ) { - fprintf ( fp, "[%s]:", tmp->h_node[src_addr]->label ); + fprintf ( fp, "[%s]:", (tmp->h_node[src_addr]->label) ? tmp->h_node[src_addr]->label : "no label" ); } else { - inet_ntop ( AF_INET, &(tmp->src_addr), ip, INET_ADDRSTRLEN ); + inet_ntop ( AF_INET, &(tmp->ip_src_addr), ip, INET_ADDRSTRLEN ); fprintf ( fp, "%s:", ip ); } - if ( h_root[src_port] ) + if ( h_root[src_port] && tmp->h_node[src_port] ) { - fprintf ( fp, "[%s] -> ", tmp->h_node[src_port]->label ); + fprintf ( fp, "[%s] -> ", (tmp->h_node[src_port]->label) ? tmp->h_node[src_port]->label : "no label" ); } else { - fprintf ( fp, "%d -> ", htons ( tmp->src_port )); + fprintf ( fp, "%d -> ", htons ( tmp->tcp_src_port )); } - if ( h_root[dst_addr] ) + if ( h_root[dst_addr] && tmp->h_node[dst_addr] ) { - fprintf ( fp, "[%s]:", tmp->h_node[dst_addr]->label ); + fprintf ( fp, "[%s]:", (tmp->h_node[dst_addr]->label) ? tmp->h_node[dst_addr]->label : "no label" ); } else { - inet_ntop ( AF_INET, &(tmp->dst_addr), ip, INET_ADDRSTRLEN ); + inet_ntop ( AF_INET, &(tmp->ip_dst_addr), ip, INET_ADDRSTRLEN ); fprintf ( fp, "%s:", ip ); } - if ( h_root[dst_port] ) + if ( h_root[dst_port] && tmp->h_node[dst_port] ) { - fprintf ( fp, "[%s]\n", tmp->h_node[dst_port]->label ); + fprintf ( fp, "[%s]\n", (tmp->h_node[dst_port]->label) ? tmp->h_node[dst_port]->label : "no label" ); } else { - fprintf ( fp, "%d\n", htons ( tmp->dst_port )); + fprintf ( fp, "%d\n", htons ( tmp->tcp_dst_port )); } fprintf ( fp, "\n" ); @@ -371,7 +367,6 @@ _AI_print_clustered_alerts ( AI_snort_alert *log, FILE *fp ) /** - * FUNCTION: _AI_cluster_thread * \brief Thread for periodically clustering the log information */ PRIVATE void* @@ -400,7 +395,7 @@ _AI_cluster_thread ( void* arg ) /* Free the current alert log and get the latest one */ AI_free_alerts ( alert_log ); - if ( !( alert_log = AI_get_alerts() )) + if ( !( alert_log = get_alerts() )) { continue; } @@ -432,14 +427,14 @@ _AI_cluster_thread ( void* arg ) { case src_addr: case dst_addr: - netval = ( type == src_addr ) ? tmp->src_addr : tmp->dst_addr; + netval = ( type == src_addr ) ? tmp->ip_src_addr : tmp->ip_dst_addr; hostval = ntohl ( netval ); inet_ntop ( AF_INET, &(netval), label, INET_ADDRSTRLEN ); break; case src_port: case dst_port: - netval = ( type == src_port ) ? tmp->src_port : tmp->dst_port; + netval = ( type == src_port ) ? tmp->tcp_src_port : tmp->tcp_dst_port; hostval = ntohs ( netval ); snprintf ( label, sizeof(label), "%d", hostval ); break; @@ -489,9 +484,12 @@ _AI_cluster_thread ( void* arg ) /* For all the alerts, the corresponing clustering value is the parent of the current one in the hierarchy */ for ( tmp = alert_log; tmp; tmp = tmp->next ) { - if ( tmp->h_node[best_type]->parent ) + if ( tmp->h_node[best_type] ) { - tmp->h_node[best_type] = tmp->h_node[best_type]->parent; + if ( tmp->h_node[best_type]->parent ) + { + tmp->h_node[best_type] = tmp->h_node[best_type]->parent; + } } } @@ -503,6 +501,7 @@ _AI_cluster_thread ( void* arg ) if ( !( cluster_fp = fopen ( _config->clusterfile, "w" )) ) { + pthread_exit ((void*) 0 ); return (void*) 0; } @@ -512,17 +511,18 @@ _AI_cluster_thread ( void* arg ) fclose ( fp ); } + pthread_exit ((void*) 0 ); return (void*) 0; } /* ----- end of function AI_cluster_thread ----- */ /** - * FUNCTION: _AI_check_duplicate * \brief Check if a certain node's range (minimum and maximum value) are already present in a clustering hierarchy * \param node Node to be checked * \param root Clustering hierarchy * \return True if 'node' is already in 'root', false otherwise */ + PRIVATE BOOL _AI_check_duplicate ( hierarchy_node *node, hierarchy_node *root ) { @@ -543,8 +543,8 @@ _AI_check_duplicate ( hierarchy_node *node, hierarchy_node *root ) return false; } /* ----- end of function _AI_check_duplicate ----- */ + /** - * FUNCTION: AI_hierarchies_build * \brief Build the clustering hierarchy trees * \param conf Reference to the configuration of the module * \param nodes Nodes containing the information about the clustering ranges @@ -630,3 +630,5 @@ AI_hierarchies_build ( AI_config *conf, hierarchy_node **nodes, int n_nodes ) } } /* ----- end of function AI_hierarchies_build ----- */ +/** @} */ + diff --git a/db.c b/db.c new file mode 100644 index 0000000..6ada2d0 --- /dev/null +++ b/db.c @@ -0,0 +1,271 @@ +/* + * ===================================================================================== + * + * Filename: mysql.c + * + * Description: Parse the alert log saved by Snort on a database + * + * Version: 0.1 + * Created: 17/08/2010 17:29:36 + * Revision: none + * Compiler: gcc + * + * Author: BlackLight (http://0x00.ath.cx), + * Licence: GNU GPL v.3 + * Company: DO WHAT YOU WANT CAUSE A PIRATE IS FREE, YOU ARE A PIRATE! + * + * ===================================================================================== + */ + + +#include "spp_ai.h" +#include "db.h" + +#include +#include +#include + +/** \defgroup mysql Manage alerts on a MySQL database + * @{ */ + + +PRIVATE AI_config *config; +PRIVATE AI_snort_alert *alerts = NULL; + +/** pthread mutex for accessing database data */ +PRIVATE pthread_mutex_t db_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** + * \brief Thread for parsing alerts from MySQL database + * \param arg void* pointer to the module configuration + */ + +void* +AI_mysql_alertparser_thread ( void *arg ) +{ + char query[1024]; + int rows = 0; + int latest_cid = 0; + time_t latest_time = time ( NULL ); + + DB_result res, res2; + DB_row row, row2; + + struct pkt_key key; + struct pkt_info *info = NULL; + AI_snort_alert *alert = NULL; + AI_snort_alert *tmp = NULL; + + if ( !arg ) + { + pthread_exit ((void*) 0 ); + return (void*) 0; + } + + config = ( AI_config* ) arg; + pthread_mutex_lock ( &db_mutex ); + + if ( !DB_init ( config )) + { + _dpd.fatalMsg ( "AIPreproc: Unable to connect to the database '%s' @ '%s'\n", + config->dbname, config->dbhost ); + } + + pthread_mutex_unlock ( &db_mutex ); + + while ( 1 ) + { + sleep ( config->databaseParsingInterval ); + memset ( query, 0, sizeof ( query )); + snprintf ( query, sizeof (query), "select cid, unix_timestamp(timestamp), signature from event where cid > %d " + "and unix_timestamp(timestamp) > %ld order by cid", latest_cid, latest_time ); + + if ( !( res = (DB_result) DB_query ( query ))) + { + DB_close(); + _dpd.fatalMsg ( "AIPreproc: Fatal error while executing a query on the database " + "at %s:%d: '%s'\n", __FILE__, __LINE__, query ); + } + + if (( rows = DB_num_rows ( res )) < 0 ) + { + DB_close(); + _dpd.fatalMsg ( "AIPreproc: Could not store the query result at %s:%d\n", __FILE__, __LINE__ ); + } else if ( rows == 0 ) { + continue; + } + + while (( row = (DB_row) DB_fetch_row ( res ))) + { + if ( !( alert = ( AI_snort_alert* ) malloc ( sizeof ( AI_snort_alert )) )) + { + _dpd.fatalMsg ( "Fatal dynamic memory allocation failure at %s:%d\n", __FILE__, __LINE__ ); + } + + memset ( alert, 0, sizeof ( AI_snort_alert )); + latest_cid = (row[0]) ? strtol ( row[0], NULL, 10 ) : 0; + alert->timestamp = (row[1]) ? ( time_t ) strtol ( row[1], NULL, 10 ) : 0; + + /* Parsing gid, sid, rev, name, timestamp and priority */ + memset ( query, 0, sizeof ( query )); + snprintf ( query, sizeof ( query ), "select sig_gid, sig_sid, sig_rev, sig_name, sig_priority from signature " + "where sig_id='%ld'", strtol ( row[2], NULL, 0 )); + + if ( !( res2 = (DB_result) DB_query ( query ))) + { + DB_close(); + _dpd.fatalMsg ( "AIPreproc: Fatal error while executing a query on the database " + "at %s:%d: '%s'\n", __FILE__, __LINE__, query ); + } + + if (( rows = DB_num_rows ( res2 )) < 0 ) { + DB_close(); + _dpd.fatalMsg ( "AIPreproc: Could not store the query result at %s:%d\n", __FILE__, __LINE__ ); + } else if ( rows > 0 ) { + if (( row2 = (DB_row) DB_fetch_row ( res2 ))) + { + alert->gid = (row2[0]) ? strtol ( row2[0], NULL, 10 ) : 0; + alert->sid = (row2[1]) ? strtol ( row2[1], NULL, 10 ) : 0; + alert->rev = (row2[2]) ? strtol ( row2[2], NULL, 10 ) : 0; + alert->desc = (row2[3]) ? strdup ( row2[3] ) : NULL; + alert->priority = (row2[4]) ? strtol ( row2[4], NULL, 10 ) : 0; + } + + DB_free_result ( res2 ); + } + + /* Parsing IP header information */ + memset ( query, 0, sizeof ( query )); + snprintf ( query, sizeof ( query ), "select ip_tos, ip_len, ip_id, ip_ttl, ip_proto, ip_src, ip_dst " + "from iphdr where cid='%d'", latest_cid); + + if ( !( res2 = (DB_result) DB_query ( query ))) + { + DB_close(); + _dpd.fatalMsg ( "AIPreproc: Fatal error while executing a query on the database " + "at %s:%d: '%s'\n", __FILE__, __LINE__, query ); + } + + if (( rows = DB_num_rows ( res2 )) < 0 ) { + DB_close(); + _dpd.fatalMsg ( "AIPreproc: Could not store the query result at %s:%d\n", __FILE__, __LINE__ ); + } else if ( rows > 0 ) { + if (( row2 = DB_fetch_row ( res2 ))) + { + alert->ip_tos = (row2[0]) ? strtol ( row2[0], NULL, 10 ) : 0; + alert->ip_len = (row2[1]) ? htons ( strtol ( row2[1], NULL, 10 )) : 0; + alert->ip_id = (row2[2]) ? htons ( strtol ( row2[2], NULL, 10 )) : 0; + alert->ip_ttl = (row2[3]) ? strtol ( row2[3], NULL, 10 ) : 0; + alert->ip_proto = (row2[4]) ? strtol ( row2[4], NULL, 10 ) : 0; + alert->ip_src_addr = (row2[5]) ? htonl ( strtoul ( row2[5], NULL, 10 )) : 0; + alert->ip_dst_addr = (row2[6]) ? htonl ( strtoul ( row2[6], NULL, 10 )) : 0; + } + + DB_free_result ( res2 ); + } + + /* Parsing TCP header information */ + memset ( query, 0, sizeof ( query )); + snprintf ( query, sizeof ( query ), "select tcp_sport, tcp_dport, tcp_seq, tcp_ack, tcp_flags, tcp_win " + "from tcphdr where cid='%d'", latest_cid ); + + if ( !( res2 = (DB_result) DB_query ( query ))) + { + DB_close(); + _dpd.fatalMsg ( "AIPreproc: Fatal error while executing a query on the database " + "at %s:%d: '%s'\n", __FILE__, __LINE__, query ); + } + + if (( rows = DB_num_rows ( res2 )) < 0 ) { + DB_close(); + _dpd.fatalMsg ( "AIPreproc: Could not store the query result at %s:%d\n", __FILE__, __LINE__ ); + } else if ( rows > 0 ) { + if (( row2 = DB_fetch_row ( res2 ))) + { + alert->tcp_src_port = (row2[0]) ? htons ( strtol ( row2[0], NULL, 10 )) : 0; + alert->tcp_dst_port = (row2[1]) ? htons ( strtol ( row2[1], NULL, 10 )) : 0; + alert->tcp_seq = (row2[2]) ? htonl ( strtoul ( row2[2], NULL, 10 )) : 0; + alert->tcp_ack = (row2[3]) ? htonl ( strtoul ( row2[3], NULL, 10 )) : 0; + alert->tcp_flags = (row2[4]) ? strtol ( row2[4], NULL, 10 ) : 0; + alert->tcp_window = (row2[5]) ? htons ( strtol ( row2[5], NULL, 10 )) : 0; + } + + DB_free_result ( res2 ); + } + + /* Finding the associated stream info, if any */ + if ( alert->ip_proto == IPPROTO_TCP ) + { + key.src_ip = alert->ip_src_addr; + key.dst_port = alert->tcp_dst_port; + + if (( info = AI_get_stream_by_key ( key ))) + { + AI_set_stream_observed ( key ); + alert->stream = info; + } + } + + /* Creating a new alert log if it doesn't exist, or appending the current alert to the log */ + if ( !alerts ) + { + alerts = alert; + alerts->next = NULL; + } else { + for ( tmp = alerts; tmp->next; tmp = tmp->next ); + tmp->next = alert; + } + } + + DB_free_result ( res ); + latest_time = time ( NULL ); + } + + DB_close(); + pthread_exit ((void*) 0 ); + return (void*) 0; +} /* ----- end of function AI_mysql_alert_parse ----- */ + +/** + * \brief Create a copy of the alert log struct (this is done for leaving the alert log structure in this file as read-only) + * \param node Starting node (used for the recursion) + * \return A copy of the alert log linked list + */ +PRIVATE AI_snort_alert* +_AI_mysql_copy_alerts ( AI_snort_alert *node ) +{ + AI_snort_alert *current = NULL, *next = NULL; + + if ( !node ) + { + return NULL; + } + + if ( node->next ) + { + next = _AI_mysql_copy_alerts ( node->next ); + } + + if ( !( current = ( AI_snort_alert* ) malloc ( sizeof ( AI_snort_alert )) )) + { + _dpd.fatalMsg ( "Fatal dynamic memory allocation failure at %s:%d\n", __FILE__, __LINE__ ); + } + + memcpy ( current, node, sizeof ( AI_snort_alert )); + current->next = next; + return current; +} /* ----- end of function _AI_mysql_copy_alerts ----- */ + + +/** + * \brief Return the alerts parsed so far as a linked list + * \return An AI_snort_alert pointer identifying the list of alerts + */ +AI_snort_alert* +AI_mysql_get_alerts () +{ + return _AI_mysql_copy_alerts ( alerts ); +} /* ----- end of function AI_mysql_get_alerts ----- */ + +/** @} */ + diff --git a/db.h b/db.h new file mode 100644 index 0000000..d2df002 --- /dev/null +++ b/db.h @@ -0,0 +1,47 @@ +/* + * ===================================================================================== + * + * Filename: db.h + * + * Description: Manages the interface to several DBMS's through macros + * + * Version: 0.1 + * Created: 04/09/2010 20:21:06 + * Revision: none + * Compiler: gcc + * + * Author: BlackLight (http://0x00.ath.cx), + * Licence: GNU GPL v.3 + * Company: DO WHAT YOU WANT CAUSE A PIRATE IS FREE, YOU ARE A PIRATE! + * + * ===================================================================================== + */ + +#ifndef _AI_DB_H +#define _AI_DB_H + +#ifdef ENABLE_MYSQL + #include + + typedef MYSQL_RES* DB_result; + typedef MYSQL_ROW DB_row; + + #define DB_init mysql_do_init + #define DB_query mysql_do_query + #define DB_num_rows mysql_num_rows + #define DB_fetch_row mysql_fetch_row + #define DB_free_result mysql_free_result + #define DB_close mysql_do_close +#endif + +/** Initializer for the database */ +void* DB_init ( AI_config* ); + +/** Execute a query on the database and returns the result */ +DB_result* DB_query ( const char* ); + +/** Close the database descriptor */ +void DB_close(); + +#endif + diff --git a/doc/html/alert__parser_8c.html b/doc/html/alert__parser_8c.html index 143afee..9ade03e 100644 --- a/doc/html/alert__parser_8c.html +++ b/doc/html/alert__parser_8c.html @@ -59,127 +59,23 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search'); #include <time.h>
#include <sys/inotify.h>
#include <sys/stat.h>
+#include <pthread.h>
- - - - - - - - + + + + + + + +

Functions

void * AI_alertparser_thread (void *arg)
 Thread for parsing Snort's alert file.
PRIVATE AI_snort_alert_AI_copy_alerts (AI_snort_alert *node)
 Create a copy of the alert log struct (this is done for leaving the alert log structure in this file as read-only).
AI_snort_alertAI_get_alerts ()
 Return the alerts parsed so far as a linked list.
void AI_free_alerts (AI_snort_alert *node)
 Deallocate the memory of a log alert linked list.
void * AI_file_alertparser_thread (void *arg)
 Thread for parsing Snort's alert file.
PRIVATE AI_snort_alert_AI_copy_alerts (AI_snort_alert *node)
 Create a copy of the alert log struct (this is done for leaving the alert log structure in this file as read-only).
AI_snort_alertAI_get_alerts ()
 Return the alerts parsed so far as a linked list.
void AI_free_alerts (AI_snort_alert *node)
 Deallocate the memory of a log alert linked list.

Variables

PRIVATE AI_snort_alertalerts = NULL
PRIVATE FILE * alert_fp = NULL
-

Function Documentation

- -
-
- - - - - - - - - -
PRIVATE AI_snort_alert* _AI_copy_alerts (AI_snort_alert node ) 
-
-
- -

Create a copy of the alert log struct (this is done for leaving the alert log structure in this file as read-only).

-

FUNCTION: _AI_copy_alerts

-
Parameters:
- - -
node Starting node (used for the recursion)
-
-
-
Returns:
A copy of the alert log linked list
- -
-
- -
-
- - - - - - - - - -
void* AI_alertparser_thread (void *  arg ) 
-
-
- -

Thread for parsing Snort's alert file.

-

FUNCTION: AI_alertparser_thread

-
Parameters:
- - -
arg void* pointer to module's configuration
-
-
- -
-
- -
-
- - - - - - - - - -
void AI_free_alerts (AI_snort_alert node ) 
-
-
- -

Deallocate the memory of a log alert linked list.

-

FUNCTION: AI_free_alerts

-
Parameters:
- - -
node Linked list to be freed
-
-
- -
-
- -
-
- - - - - - - - - -
AI_snort_alert* AI_get_alerts (void  ) 
-
-
- -

Return the alerts parsed so far as a linked list.

-

FUNCTION: AI_get_alerts

-
Returns:
An AI_snort_alert pointer identifying the list of alerts
- -
-

Variable Documentation

@@ -199,7 +95,7 @@ Variables
- +
PRIVATE AI_snort_alert* alerts = NULLPRIVATE AI_snort_alert* alerts = NULL
@@ -222,7 +118,7 @@ Variables
-