Supporting alerts and packets info output to db

This commit is contained in:
BlackLight 2010-10-01 19:32:34 +02:00
parent a454d15d29
commit f28830d744
10 changed files with 594 additions and 81 deletions

View file

@ -23,6 +23,7 @@ cluster.c \
correlation.c \ correlation.c \
db.c \ db.c \
mysql.c \ mysql.c \
outdb.c \
postgresql.c \ postgresql.c \
regex.c \ regex.c \
spp_ai.c \ spp_ai.c \

View file

@ -79,9 +79,9 @@ am_libsf_ai_preproc_la_OBJECTS = libsf_ai_preproc_la-alert_history.lo \
libsf_ai_preproc_la-alert_parser.lo \ libsf_ai_preproc_la-alert_parser.lo \
libsf_ai_preproc_la-bayesian.lo libsf_ai_preproc_la-cluster.lo \ libsf_ai_preproc_la-bayesian.lo libsf_ai_preproc_la-cluster.lo \
libsf_ai_preproc_la-correlation.lo libsf_ai_preproc_la-db.lo \ libsf_ai_preproc_la-correlation.lo libsf_ai_preproc_la-db.lo \
libsf_ai_preproc_la-mysql.lo libsf_ai_preproc_la-postgresql.lo \ libsf_ai_preproc_la-mysql.lo libsf_ai_preproc_la-outdb.lo \
libsf_ai_preproc_la-regex.lo libsf_ai_preproc_la-spp_ai.lo \ libsf_ai_preproc_la-postgresql.lo libsf_ai_preproc_la-regex.lo \
libsf_ai_preproc_la-stream.lo libsf_ai_preproc_la-spp_ai.lo libsf_ai_preproc_la-stream.lo
nodist_libsf_ai_preproc_la_OBJECTS = \ nodist_libsf_ai_preproc_la_OBJECTS = \
libsf_ai_preproc_la-sf_dynamic_preproc_lib.lo \ libsf_ai_preproc_la-sf_dynamic_preproc_lib.lo \
libsf_ai_preproc_la-sfPolicyUserData.lo libsf_ai_preproc_la-sfPolicyUserData.lo
@ -258,6 +258,7 @@ cluster.c \
correlation.c \ correlation.c \
db.c \ db.c \
mysql.c \ mysql.c \
outdb.c \
postgresql.c \ postgresql.c \
regex.c \ regex.c \
spp_ai.c \ spp_ai.c \
@ -395,6 +396,9 @@ libsf_ai_preproc_la-db.lo: db.c
libsf_ai_preproc_la-mysql.lo: mysql.c libsf_ai_preproc_la-mysql.lo: mysql.c
$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_ai_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_ai_preproc_la-mysql.lo `test -f 'mysql.c' || echo '$(srcdir)/'`mysql.c $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_ai_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_ai_preproc_la-mysql.lo `test -f 'mysql.c' || echo '$(srcdir)/'`mysql.c
libsf_ai_preproc_la-outdb.lo: outdb.c
$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_ai_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_ai_preproc_la-outdb.lo `test -f 'outdb.c' || echo '$(srcdir)/'`outdb.c
libsf_ai_preproc_la-postgresql.lo: postgresql.c libsf_ai_preproc_la-postgresql.lo: postgresql.c
$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_ai_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_ai_preproc_la-postgresql.lo `test -f 'postgresql.c' || echo '$(srcdir)/'`postgresql.c $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_ai_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_ai_preproc_la-postgresql.lo `test -f 'postgresql.c' || echo '$(srcdir)/'`postgresql.c

View file

@ -145,8 +145,10 @@ AI_file_alertparser_thread ( void* arg )
AI_snort_alert *alert = NULL; AI_snort_alert *alert = NULL;
AI_snort_alert *tmp = NULL; AI_snort_alert *tmp = NULL;
BOOL in_alert = false; BOOL in_alert = false;
pthread_t alerts_pool_thread; pthread_t alerts_pool_thread;
pthread_t serializer_thread; pthread_t serializer_thread;
pthread_t db_thread;
/* Initialize the mutex lock, so nobody can read the alerts while we write there */ /* Initialize the mutex lock, so nobody can read the alerts while we write there */
pthread_mutex_init ( &alert_mutex, NULL ); pthread_mutex_init ( &alert_mutex, NULL );
@ -241,8 +243,6 @@ AI_file_alertparser_thread ( void* arg )
fseek ( alert_fp, 0, SEEK_END ); fseek ( alert_fp, 0, SEEK_END );
#endif #endif
/* Set the lock flag to true until it's done with alert parsing */
while ( !feof ( alert_fp )) while ( !feof ( alert_fp ))
{ {
fgets ( line, sizeof(line), alert_fp ); fgets ( line, sizeof(line), alert_fp );
@ -285,6 +285,12 @@ AI_file_alertparser_thread ( void* arg )
if ( pthread_create ( &serializer_thread, NULL, AI_serializer_thread, alert ) != 0 ) if ( pthread_create ( &serializer_thread, NULL, AI_serializer_thread, alert ) != 0 )
_dpd.fatalMsg ( "Failed to create the alerts' serializer thread\n" ); _dpd.fatalMsg ( "Failed to create the alerts' serializer thread\n" );
if ( config->outdbtype != outdb_none )
{
if ( pthread_create ( &db_thread, NULL, AI_store_alert_to_db_thread, alert ) != 0 )
_dpd.fatalMsg ( "Failed to create the alert to db storing thread\n" );
}
in_alert = false; in_alert = false;
alert = NULL; alert = NULL;
} }

21
db.h
View file

@ -28,13 +28,22 @@
typedef MYSQL_ROW DB_row; typedef MYSQL_ROW DB_row;
#define DB_init mysql_do_init #define DB_init mysql_do_init
#define DB_is_init mysql_is_init
#define DB_query mysql_do_query #define DB_query mysql_do_query
#define DB_num_rows mysql_num_rows #define DB_num_rows mysql_num_rows
#define DB_fetch_row mysql_fetch_row #define DB_fetch_row mysql_fetch_row
#define DB_free_result mysql_free_result #define DB_free_result mysql_free_result
#define DB_escape_string mysql_do_escape_string
#define DB_close mysql_do_close #define DB_close mysql_do_close
#define DB_out_init mysql_do_out_init
#define DB_is_out_init mysql_is_out_init
#define DB_out_query mysql_do_out_query
#define DB_out_escape_string mysql_do_out_escape_string
#define DB_out_close mysql_do_out_close
DB_result* DB_query ( const char* ); DB_result* DB_query ( const char* );
DB_result* DB_out_query ( const char* );
#endif #endif
#ifdef HAVE_LIBPQ #ifdef HAVE_LIBPQ
@ -50,21 +59,33 @@
typedef char** DB_row; typedef char** DB_row;
#define DB_init postgresql_do_init #define DB_init postgresql_do_init
#define DB_is_init postgresql_is_init
#define DB_query postgresql_do_query #define DB_query postgresql_do_query
#define DB_num_rows postgresql_num_rows #define DB_num_rows postgresql_num_rows
#define DB_fetch_row postgresql_fetch_row #define DB_fetch_row postgresql_fetch_row
#define DB_free_result postgresql_free_result #define DB_free_result postgresql_free_result
#define DB_close postgresql_do_close #define DB_close postgresql_do_close
#define DB_out_init postgresql_do_out_init
#define DB_is_out_init postgresql_is_out_init
#define DB_out_query postgresql_do_out_query
#define DB_out_close postgresql_do_out_close
int DB_num_rows ( PSQL_result *res ); int DB_num_rows ( PSQL_result *res );
DB_row DB_fetch_row ( PSQL_result *res ); DB_row DB_fetch_row ( PSQL_result *res );
void DB_free_result ( PSQL_result *res ); void DB_free_result ( PSQL_result *res );
DB_result DB_query ( const char* ); DB_result DB_query ( const char* );
DB_result DB_out_query ( const char* );
#endif #endif
void* DB_init(); void* DB_init();
unsigned long DB_escape_string();
void DB_close(); void DB_close();
void* DB_out_init();
unsigned long DB_out_escape_string();
void DB_out_close();
#endif #endif
#endif #endif

154
mysql.c
View file

@ -25,56 +25,146 @@
/** \defgroup mysql Module for the interface with a MySQL DBMS /** \defgroup mysql Module for the interface with a MySQL DBMS
* @{ */ * @{ */
/***************************/
/* Database descriptors */
PRIVATE MYSQL *db = NULL; PRIVATE MYSQL *db = NULL;
PRIVATE MYSQL *outdb = NULL;
/***************************/
/*************************************************************/
/* Private functions (operating on the database descriptors) */
PRIVATE BOOL
__mysql_is_init ( MYSQL *__DB )
{
return ( __DB != NULL );
}
PRIVATE void*
__mysql_do_init ( MYSQL **__DB, BOOL is_out )
{
if ( __mysql_is_init ( *__DB ) )
return (void*) *__DB;
if ( !( *__DB = (MYSQL*) malloc ( sizeof ( MYSQL ))))
return NULL;
if ( !( mysql_init ( *__DB )))
return NULL;
if ( is_out )
{
if ( !mysql_real_connect ( *__DB, config->outdbhost, config->outdbuser, config->outdbpass, NULL, 0, NULL, 0 ))
return NULL;
if ( mysql_select_db ( *__DB, config->outdbname ))
return NULL;
} else {
if ( !mysql_real_connect ( *__DB, config->dbhost, config->dbuser, config->dbpass, NULL, 0, NULL, 0 ))
return NULL;
if ( mysql_select_db ( *__DB, config->dbname ))
return NULL;
}
return (void*) *__DB;
}
PRIVATE MYSQL_RES*
__mysql_do_query ( MYSQL *__DB, const char *query )
{
MYSQL_RES *res = NULL;
if ( mysql_query ( __DB, query ))
return NULL;
if ( !( res = mysql_store_result ( __DB )))
return NULL;
return res;
}
PRIVATE void
__mysql_do_close ( MYSQL **__DB )
{
if ( *__DB )
mysql_close ( *__DB );
free ( *__DB );
*__DB = NULL;
}
/* End of private functions */
/****************************/
/********************/
/* Public functions */
BOOL
mysql_is_init ()
{
return __mysql_is_init ( db );
}
void* void*
mysql_do_init () mysql_do_init ()
{ {
if ( !( db = (MYSQL*) malloc ( sizeof ( MYSQL )))) return __mysql_do_init ( &db, false );
return NULL;
if ( !( mysql_init ( db )))
return NULL;
if ( !mysql_real_connect ( db, config->dbhost, config->dbuser, config->dbpass, NULL, 0, NULL, 0 ))
return NULL;
if ( mysql_select_db ( db, config->dbname ))
return NULL;
return (void*) db;
} }
MYSQL_RES* MYSQL_RES*
mysql_do_query ( const char *query ) mysql_do_query ( const char *query )
{ {
MYSQL_RES *res = NULL; return __mysql_do_query ( db, query );
}
if ( mysql_query ( db, query )) unsigned long
{ mysql_do_escape_string ( char **to, const char *from, unsigned long length )
mysql_close ( db ); {
return NULL; return mysql_real_escape_string ( db, *to, from, length );
}
if ( !( res = mysql_store_result ( db )))
{
mysql_close ( db );
return NULL;
}
return res;
} }
void void
mysql_do_close () mysql_do_close ()
{ {
if ( db ) __mysql_do_close ( &db );
mysql_close ( db );
free ( db );
db = NULL;
} }
/* Output database functions */
BOOL
mysql_is_out_init ()
{
return __mysql_is_init ( outdb );
}
void*
mysql_do_out_init ()
{
return __mysql_do_init ( &outdb, true );
}
MYSQL_RES*
mysql_do_out_query ( const char *query )
{
return __mysql_do_query ( outdb, query );
}
unsigned long
mysql_do_out_escape_string ( char **to, const char *from, unsigned long length )
{
return mysql_real_escape_string ( outdb, *to, from, length );
}
void
mysql_do_out_close ()
{
__mysql_do_close ( &outdb );
}
/* End of public functions */
/***************************/
/** @} */ /** @} */
#endif #endif

211
outdb.c Normal file
View file

@ -0,0 +1,211 @@
/*
* =====================================================================================
*
* Filename: outdb.c
*
* Description: Module for writing to a database the outputs (alerts, hyperalerts,
* clustered alerts, correlated alerts, alerts' TCP streams) from the
* preprocessor module
*
* Version: 0.1
* Created: 30/09/2010 20:02:17
* Revision: none
* Compiler: gcc
*
* Author: BlackLight (http://0x00.ath.cx), <blacklight@autistici.org>
* Licence: GNU GPL v.3
* Company: DO WHAT YOU WANT CAUSE A PIRATE IS FREE, YOU ARE A PIRATE!
*
* =====================================================================================
*/
#include "spp_ai.h"
/** \defgroup outdb Storing alerts, packets, clusters and correlations information on a database
* @{ */
#ifdef HAVE_DB
#include "db.h"
#include <alloca.h>
#include <pthread.h>
enum { ALERTS_TABLE, IPV4_HEADERS_TABLE, TCP_HEADERS_TABLE, PACKET_STREAMS_TABLE, CLUSTERED_ALERTS_TABLE, CORRELATED_ALERTS_TABLE, N_TABLES };
static const char *outdb_config[] = {
"ca_alerts", "ca_ipv4_headers", "ca_tcp_headers",
"ca_packet_streams", "ca_clustered_alerts", "ca_correlated_alerts"
};
PRIVATE pthread_mutex_t mutex;
/**
* \brief Thread for storing an alert to the database
* \param arg Alert to be stored
*/
void*
AI_store_alert_to_db_thread ( void *arg )
{
char srcip[INET_ADDRSTRLEN], dstip[INET_ADDRSTRLEN];
char query[65535] = { 0 };
unsigned char *pkt_data = NULL;
unsigned long latest_ip_hdr_id = 0,
latest_tcp_hdr_id = 0,
latest_alert_id = 0,
pkt_size = 0,
pkt_size_offset = 0;
struct pkt_info *pkt = NULL;
DB_result res;
DB_row row;
AI_snort_alert *alert = (AI_snort_alert*) arg;
pthread_mutex_init ( &mutex, NULL );
if ( !DB_out_init() )
_dpd.fatalMsg ( "AIPreproc: Unable to connect to output database '%s'\n", config->outdbname );
pthread_mutex_lock ( &mutex );
inet_ntop ( AF_INET, &(alert->ip_src_addr), srcip, INET_ADDRSTRLEN );
inet_ntop ( AF_INET, &(alert->ip_dst_addr), dstip, INET_ADDRSTRLEN );
/* Store the IP header information */
memset ( query, 0, sizeof ( query ));
snprintf ( query, sizeof ( query ), "INSERT INTO %s (ip_tos, ip_len, ip_id, ip_ttl, ip_proto, ip_src_addr, ip_dst_addr) "
"VALUES (%u, %u, %u, %u, %u, '%s', '%s')",
outdb_config[IPV4_HEADERS_TABLE],
alert->ip_tos,
ntohs (alert->ip_len ),
ntohs (alert->ip_id ),
alert->ip_ttl,
alert->ip_proto,
srcip,
dstip );
DB_out_query ( query );
memset ( query, 0, sizeof ( query ));
snprintf ( query, sizeof ( query ), "SELECT MAX(ip_hdr_id) FROM %s", outdb_config[IPV4_HEADERS_TABLE] );
if ( !( res = (DB_result) DB_out_query ( query )))
{
_dpd.logMsg ( "AIPreproc: Warning: error in executing query: '%s'\n", query );
pthread_exit ((void*) 0);
}
if ( !( row = (DB_row) DB_fetch_row ( res )))
{
pthread_exit ((void*) 0);
}
latest_ip_hdr_id = strtoul ( row[0], NULL, 10 );
DB_free_result ( res );
if ( alert->ip_proto == IPPROTO_TCP || alert->ip_proto == IPPROTO_UDP )
{
/* Store the TCP header information */
memset ( query, 0, sizeof ( query ));
snprintf ( query, sizeof ( query ), "INSERT INTO %s (tcp_src_port, tcp_dst_port, tcp_seq, tcp_ack, tcp_flags, tcp_window, tcp_len) "
"VALUES (%u, %u, %u, %u, %u, %u, %u)",
outdb_config[TCP_HEADERS_TABLE],
ntohs (alert->tcp_src_port ),
ntohs (alert->tcp_dst_port ),
ntohl (alert->tcp_seq ),
ntohl (alert->tcp_ack ),
alert->tcp_flags,
ntohs (alert->tcp_window ),
ntohs (alert->tcp_len ));
DB_out_query ( query );
memset ( query, 0, sizeof ( query ));
snprintf ( query, sizeof ( query ), "SELECT MAX(tcp_hdr_id) FROM %s", outdb_config[TCP_HEADERS_TABLE] );
if ( !( res = (DB_result) DB_out_query ( query )))
{
_dpd.logMsg ( "AIPreproc: Warning: error in executing query: '%s'\n", query );
pthread_exit ((void*) 0);
}
if ( !( row = (DB_row) DB_fetch_row ( res )))
{
pthread_exit ((void*) 0);
}
latest_tcp_hdr_id = strtoul ( row[0], NULL, 10 );
DB_free_result ( res );
}
memset ( query, 0, sizeof ( query ));
snprintf ( query, sizeof ( query ), "INSERT INTO %s (gid, sid, rev, priority, description, classification, timestamp, ip_hdr, tcp_hdr) "
"VALUES (%u, %u, %u, %u, '%s', '%s', from_unixtime('%lu'), %lu, %lu)",
outdb_config[ALERTS_TABLE],
alert->gid,
alert->sid,
alert->rev,
alert->priority,
((alert->desc) ? alert->desc : ""),
((alert->classification) ? alert->classification : ""),
alert->timestamp,
latest_ip_hdr_id,
((alert->ip_proto == IPPROTO_TCP || alert->ip_proto == IPPROTO_UDP) ? latest_tcp_hdr_id : 0));
DB_out_query ( query );
memset ( query, 0, sizeof ( query ));
snprintf ( query, sizeof ( query ), "SELECT MAX(alert_id) FROM %s", outdb_config[ALERTS_TABLE] );
if ( !( res = (DB_result) DB_out_query ( query )))
{
_dpd.logMsg ( "AIPreproc: Warning: error in executing query: '%s'\n", query );
pthread_exit ((void*) 0);
}
if ( !( row = (DB_row) DB_fetch_row ( res )))
{
pthread_exit ((void*) 0);
}
latest_alert_id = strtoul ( row[0], NULL, 10 );
alert->alert_id = latest_alert_id;
DB_free_result ( res );
if ( alert->stream )
{
for ( pkt = alert->stream; pkt; pkt = pkt->next )
{
pkt_data = NULL;
pkt_size = pkt->pkt->pcap_cap_len;
pkt_size_offset = 0;
if ( !( pkt_data = (unsigned char*) alloca ( 2 * (pkt->pkt->pcap_header->len + pkt->pkt->payload_size) + 1 )))
_dpd.fatalMsg ( "AIPreproc: Fatal dynamic allocation memory at %s:%d\n", __FILE__, __LINE__ );
DB_out_escape_string ( &pkt_data,
pkt->pkt->pkt_data,
pkt->pkt->pcap_header->len + pkt->pkt->payload_size );
memset ( query, 0, sizeof ( query ));
snprintf ( query, sizeof ( query ), "INSERT INTO %s (alert_id, pkt_len, timestamp, content) "
"VALUES (%lu, %u, from_unixtime('%lu'), '%s')",
outdb_config[PACKET_STREAMS_TABLE],
latest_alert_id,
pkt->pkt->pcap_header->len + pkt->pkt->payload_size,
pkt->timestamp,
pkt_data );
DB_out_query ( query );
}
}
pthread_mutex_unlock ( &mutex );
pthread_exit ((void*) 0);
return (void*) 0;
}
#endif
/** @} */

View file

@ -27,22 +27,58 @@
/** \defgroup postgresql Module for the interface with a PostgreSQL DBMS /** \defgroup postgresql Module for the interface with a PostgreSQL DBMS
* @{ */ * @{ */
/***************************/
/* Database descriptors */
PRIVATE PGconn *db = NULL; PRIVATE PGconn *db = NULL;
PRIVATE PGconn *outdb = NULL;
/***************************/
void* /*************************************************************/
postgresql_do_init () /* Private functions (operating on the database descriptors) */
PRIVATE BOOL
__postgresql_is_init ( PGconn *__DB )
{
return ( __DB != NULL );
}
PRIVATE void*
__postgresql_do_init ( PGconn **__DB, BOOL is_out )
{ {
char *conninfo = NULL; char *conninfo = NULL;
int conninfo_max_length = int conninfo_max_length =
( is_out ?
((config->outdbhost) ? strlen ( config->outdbhost ) : 0) +
((config->outdbuser) ? strlen ( config->outdbuser ) : 0) +
((config->outdbpass) ? strlen ( config->outdbpass ) : 0) +
((config->outdbname) ? strlen ( config->outdbname ) : 0) :
((config->dbhost) ? strlen ( config->dbhost ) : 0) + ((config->dbhost) ? strlen ( config->dbhost ) : 0) +
((config->dbuser) ? strlen ( config->dbuser ) : 0) + ((config->dbuser) ? strlen ( config->dbuser ) : 0) +
((config->dbpass) ? strlen ( config->dbpass ) : 0) + ((config->dbpass) ? strlen ( config->dbpass ) : 0) +
((config->dbname) ? strlen ( config->dbname ) : 0) + 100; ((config->dbname) ? strlen ( config->dbname ) : 0)) + 100;
if ( postgresql_is_init ( *__DB ))
return (void*) *__DB;
if ( !( conninfo = (char*) alloca ( conninfo_max_length ))) if ( !( conninfo = (char*) alloca ( conninfo_max_length )))
_dpd.fatalMsg ( "AIPreproc: Fatal dynamic memory allocation error at %s:%d\n", __FILE__, __LINE__ ); _dpd.fatalMsg ( "AIPreproc: Fatal dynamic memory allocation error at %s:%d\n", __FILE__, __LINE__ );
memset ( conninfo, 0, conninfo_max_length ); memset ( conninfo, 0, conninfo_max_length );
if ( is_out )
{
snprintf ( conninfo, conninfo_max_length, "dbname=%s", config->outdbname );
if ( config->outdbuser )
sprintf ( conninfo, "%s user=%s", conninfo, config->outdbuser );
if ( config->outdbpass )
sprintf ( conninfo, "%s password=%s", conninfo, config->outdbpass );
if ( config->outdbhost )
sprintf ( conninfo, "%s hostaddr=%s", conninfo, config->outdbhost );
} else {
snprintf ( conninfo, conninfo_max_length, "dbname=%s", config->dbname ); snprintf ( conninfo, conninfo_max_length, "dbname=%s", config->dbname );
if ( config->dbuser ) if ( config->dbuser )
@ -53,15 +89,16 @@ postgresql_do_init ()
if ( config->dbhost ) if ( config->dbhost )
sprintf ( conninfo, "%s hostaddr=%s", conninfo, config->dbhost ); sprintf ( conninfo, "%s hostaddr=%s", conninfo, config->dbhost );
}
if ( PQstatus ( db = PQconnectdb ( conninfo )) != CONNECTION_OK ) if ( PQstatus ( *__DB = PQconnectdb ( conninfo )) != CONNECTION_OK )
return NULL; return NULL;
return (void*) db; return (void*) *__DB;
} }
PSQL_result* PRIVATE PSQL_result*
postgresql_do_query ( const char *query ) __postgresql_do_query ( PGconn *__DB, const char *query )
{ {
int i, j, ntuples, nfields; int i, j, ntuples, nfields;
PSQL_result *res = NULL; PSQL_result *res = NULL;
@ -69,9 +106,9 @@ postgresql_do_query ( const char *query )
if ( !( res = (PSQL_result*) malloc ( sizeof ( PSQL_result )))) if ( !( res = (PSQL_result*) malloc ( sizeof ( PSQL_result ))))
_dpd.fatalMsg ( "AIPreproc: Fatal dynamic memory allocation error at %s:%d\n", __FILE__, __LINE__ ); _dpd.fatalMsg ( "AIPreproc: Fatal dynamic memory allocation error at %s:%d\n", __FILE__, __LINE__ );
if ( PQresultStatus ( res->res = PQexec( db, query )) != PGRES_TUPLES_OK ) if ( PQresultStatus ( res->res = PQexec( __DB, query )) != PGRES_TUPLES_OK )
{ {
PQfinish ( db ); PQfinish ( __DB );
return NULL; return NULL;
} }
@ -131,15 +168,74 @@ postgresql_free_result ( PSQL_result *res )
} }
} }
PRIVATE void
__postgresql_do_close ( PGconn **__DB )
{
if ( *__DB )
PQfinish ( *__DB );
*__DB = NULL;
}
/* End of private functions */
/****************************/
/********************/
/* Public functions */
BOOL
postgresql_is_init ()
{
return __postgresql_is_init ( db );
}
void*
postgresql_do_init ()
{
return __postgresql_do_init ( &db, false );
}
PSQL_result*
postgresql_do_query ( const char *query )
{
return __postgresql_do_query ( db, query );
}
void void
postgresql_do_close () postgresql_do_close ()
{ {
if ( db ) __postgresql_do_close ( &db );
PQfinish ( db );
db = NULL;
} }
/* Output database functions */
BOOL
postgresql_is_out_init ()
{
return __postgresql_is_init ( outdb );
}
void*
postgresql_do_out_init ()
{
return __postgresql_do_init ( &outdb, true );
}
PSQL_result*
postgresql_do_out_query ( const char *query )
{
return __postgresql_do_query ( outdb, query );
}
void
postgresql_do_out_close ()
{
__postgresql_do_close ( &outdb );
}
/* End of public functions */
/***************************/
/* @} */ /* @} */
#endif #endif

82
schemas/mysql.sql Normal file
View file

@ -0,0 +1,82 @@
DROP TABLE IF EXISTS ca_ipv4_headers;
CREATE TABLE ca_ipv4_headers (
ip_hdr_id integer auto_increment,
ip_tos integer,
ip_len integer,
ip_id integer,
ip_ttl integer,
ip_proto integer,
ip_src_addr varchar(32),
ip_dst_addr varchar(32),
primary key(ip_hdr_id)
);
DROP TABLE IF EXISTS ca_tcp_headers;
CREATE TABLE ca_tcp_headers (
tcp_hdr_id integer auto_increment,
tcp_src_port integer,
tcp_dst_port integer,
tcp_seq integer,
tcp_ack integer,
tcp_flags integer,
tcp_window integer,
tcp_len integer,
primary key(tcp_hdr_id)
);
DROP TABLE IF EXISTS ca_packet_streams;
CREATE TABLE ca_packet_streams (
pkt_id integer auto_increment,
alert_id integer,
pkt_len integer,
timestamp datetime,
content longblob,
primary key(pkt_id),
foreign key(alert_id) references ca_alerts(alert_id)
);
DROP TABLE IF EXISTS ca_alerts;
CREATE TABLE ca_alerts (
alert_id integer auto_increment,
gid integer,
sid integer,
rev integer,
priority integer,
description varchar(255),
classification varchar(255),
timestamp datetime,
ip_hdr integer,
tcp_hdr integer,
cluster_id integer,
primary key(alert_id),
foreign key(ip_hdr) references ca_ip_headers(ip_hdr_id),
foreign key(tcp_hdr) references ca_tcp_headers(tcp_hdr_id),
foreign key(cluster_id) references ca_clustered_alerts(cluster_id)
);
DROP TABLE IF EXISTS ca_clustered_alerts;
CREATE TABLE ca_clustered_alerts (
cluster_id integer auto_increment,
clustered_srcip varchar(255) default null,
clustered_dstip varchar(255) default null,
clustered_srcport varchar(255) default null,
clustered_dstport varchar(255) default null,
primary key(cluster_id)
);
DROP TABLE IF EXISTS ca_correlated_alerts;
CREATE TABLE ca_correlated_alerts (
cluster1 integer,
cluster2 integer,
correlation_coeff double,
primary key(cluster1, cluster2),
foreign key(cluster1) references ca_clustered_alerts(cluster_id),
foreign key(cluster2) references ca_clustered_alerts(cluster_id)
);

View file

@ -654,8 +654,9 @@ static AI_config * AI_parse(char *args)
_dpd.logMsg(" Reading alerts from the database %s\n", config->dbname ); _dpd.logMsg(" Reading alerts from the database %s\n", config->dbname );
} }
/* Parsing output_database option */ /* Parsing output_database option */
config->outdbtype = outdb_none;
if ( preg_match ( "\\s*output_database\\s*\\(\\s*([^\\)]+)\\)", args, &matches, &nmatches ) > 0 ) if ( preg_match ( "\\s*output_database\\s*\\(\\s*([^\\)]+)\\)", args, &matches, &nmatches ) > 0 )
{ {
if ( ! has_database_output ) if ( ! has_database_output )
@ -671,24 +672,21 @@ static AI_config * AI_parse(char *args)
if ( preg_match ( "type\\s*=\\s*\"([^\"]+)\"", match, &matches, &nmatches ) > 0 ) if ( preg_match ( "type\\s*=\\s*\"([^\"]+)\"", match, &matches, &nmatches ) > 0 )
{ {
if ( strcasecmp ( matches[0], "mysql" ) && strcasecmp ( matches[0], "postgresql" ))
{
_dpd.fatalMsg ( "AIPreproc: Not supported database '%s' (supported types: mysql, postgresql)\n", matches[0] );
}
if ( !strcasecmp ( matches[0], "mysql" )) if ( !strcasecmp ( matches[0], "mysql" ))
{ {
#ifndef HAVE_LIBMYSQLCLIENT #ifndef HAVE_LIBMYSQLCLIENT
_dpd.fatalMsg ( "AIPreproc: mysql output set in 'output_database' option but the module was not compiled through --with-mysql option\n" ); _dpd.fatalMsg ( "AIPreproc: mysql output set in 'output_database' option but the module was not compiled through --with-mysql option\n" );
#else #else
config->outdbtype = mysql; config->outdbtype = outdb_mysql;
#endif #endif
} else if ( !strcasecmp ( matches[0], "postgresql" )) { } else if ( !strcasecmp ( matches[0], "postgresql" )) {
#ifndef HAVE_LIBPQ #ifndef HAVE_LIBPQ
_dpd.fatalMsg ( "AIPreproc: postgresql output set in 'output_database' option but the module was not compiled through --with-postgresql option\n" ); _dpd.fatalMsg ( "AIPreproc: postgresql output set in 'output_database' option but the module was not compiled through --with-postgresql option\n" );
#else #else
config->outdbtype = postgresql; config->outdbtype = outdb_postgresql;
#endif #endif
} else {
_dpd.fatalMsg ( "AIPreproc: Not supported database '%s' (supported types: mysql, postgresql)\n", matches[0] );
} }
for ( i=0; i < nmatches; i++ ) for ( i=0; i < nmatches; i++ )

View file

@ -206,7 +206,7 @@ typedef struct
/** Output database type, if clustered alerts and /** Output database type, if clustered alerts and
* correlations are saved to a database as well */ * correlations are saved to a database as well */
enum { mysql, postgresql } outdbtype; enum { outdb_none, outdb_mysql, outdb_postgresql, OUTDBTYPE_NUM } outdbtype;
/** Output database name, if clustered alerts and /** Output database name, if clustered alerts and
* correlations are saved to a database as well */ * correlations are saved to a database as well */
@ -338,6 +338,10 @@ typedef struct _AI_snort_alert {
/** Number of derived alerts */ /** Number of derived alerts */
unsigned int n_derived_alerts; unsigned int n_derived_alerts;
/** Alert ID on the database, if the alerts
* are stored on a database as well */
unsigned long int alert_id;
} AI_snort_alert; } AI_snort_alert;
/*****************************************************************/ /*****************************************************************/
/** Key for the AI_alert_event structure, containing the Snort ID of the alert */ /** Key for the AI_alert_event structure, containing the Snort ID of the alert */
@ -355,8 +359,6 @@ typedef struct _AI_alert_event {
struct _AI_alert_event *next; struct _AI_alert_event *next;
UT_hash_handle hh; UT_hash_handle hh;
} AI_alert_event; } AI_alert_event;
/*****************************************************************/
int preg_match ( const char*, char*, char***, int* ); int preg_match ( const char*, char*, char***, int* );
char* str_replace ( char*, char*, char *); char* str_replace ( char*, char*, char *);
@ -389,6 +391,8 @@ const AI_alert_event* AI_get_alert_events_by_key ( AI_alert_event_key );
unsigned int AI_get_history_alert_number (); unsigned int AI_get_history_alert_number ();
double AI_alert_bayesian_correlation ( AI_snort_alert *a, AI_snort_alert *b ); double AI_alert_bayesian_correlation ( AI_snort_alert *a, AI_snort_alert *b );
void* AI_store_alert_to_db_thread ( void* );
/** Function pointer to the function used for getting the alert list (from log file, db, ...) */ /** Function pointer to the function used for getting the alert list (from log file, db, ...) */
extern AI_snort_alert* (*get_alerts)(void); extern AI_snort_alert* (*get_alerts)(void);