mirror of
https://github.com/BlackLight/Snort_AIPreproc.git
synced 2024-11-27 22:25:12 +01:00
Python support added
This commit is contained in:
parent
521aeef342
commit
95db8a6486
13 changed files with 1030 additions and 14 deletions
|
@ -72,7 +72,8 @@ fi
|
|||
install -m 0644 "${PWD}/htdocs/manual_uncorrelations.xml" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0755 "${PWD}/htdocs/pcap.cgi" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0755 "${PWD}/htdocs/correlate.cgi" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0755 "${PWD}/htdocs/default.xsl" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0755 "${PWD}/htdocs/alerts.cgi" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0644 "${PWD}/htdocs/default.xsl" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0644 "${PWD}/htdocs/js/Curry-1.0.1.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
install -m 0644 "${PWD}/htdocs/js/dracula_algorithms.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
install -m 0644 "${PWD}/htdocs/js/dracula_graffle.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
|
|
|
@ -877,7 +877,8 @@ fi
|
|||
install -m 0644 "${PWD}/htdocs/manual_uncorrelations.xml" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0755 "${PWD}/htdocs/pcap.cgi" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0755 "${PWD}/htdocs/correlate.cgi" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0755 "${PWD}/htdocs/default.xsl" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0755 "${PWD}/htdocs/alerts.cgi" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0644 "${PWD}/htdocs/default.xsl" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0644 "${PWD}/htdocs/js/Curry-1.0.1.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
install -m 0644 "${PWD}/htdocs/js/dracula_algorithms.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
install -m 0644 "${PWD}/htdocs/js/dracula_graffle.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
|
|
37
README
37
README
|
@ -132,7 +132,14 @@ by tools like tcpdump and Wireshark
|
|||
|
||||
- XML::Simple Perl module (RECOMMENDED), used by 'correlate.cgi' CGI script for
|
||||
reading and writing manual (un)correlations XML files. A quick way for
|
||||
installing it on a Unix system is by using CPAN:
|
||||
installing it on a Unix system is by using CPAN.
|
||||
|
||||
- Python 2.6 (OPTIONAL), used for interfacing SnortAI module to Python scripts
|
||||
through snortai module (see README file in pymodule/) and writing new
|
||||
correlation modules (see example.py in corr_modules/).
|
||||
Compile the module passing --with-python option to the ./configure script if you
|
||||
want this feature. You need Python interpreter and libpython2.6 installed on
|
||||
your system.
|
||||
|
||||
# cpan XML::Simple
|
||||
|
||||
|
@ -574,6 +581,34 @@ libsf_ai_preproc.la if you want to use some of the functions from the module,
|
|||
for example, for reading the alerts stored in the history file, in the
|
||||
database, the current correlations, and so on.
|
||||
|
||||
It is also possible to write your own modules in Python language. See the file
|
||||
'example.py' in corr_modules/ for a quick overview. All you need to do is to
|
||||
declare in your module the functions AI_corr_index (taking two arguments, two
|
||||
alert descriptions) and AI_corr_index_weight (taking no argument),
|
||||
both returning a real value descibing, respectively, the correlation
|
||||
value between the two alerts and the weight of that index, both between
|
||||
0 and 1. You can also access the alert information and all the alerts
|
||||
acquired so far by the module by importing in your Python code the
|
||||
'snortai' module. You can compile it and install it by moving to
|
||||
'pymodule/' directory and running
|
||||
|
||||
$ python setup.py build
|
||||
$ [sudo] python setup.py install
|
||||
|
||||
You can acquire the current alerts by writing a code like the following:
|
||||
|
||||
import snortai
|
||||
|
||||
alerts = snortai.alerts()
|
||||
|
||||
for alert in alerts:
|
||||
# Access the alerts information
|
||||
|
||||
The fields in the alert class can be viewed in pymodule/module.py and
|
||||
corr_modules/example.py examples. Take these files as guides for interfacing
|
||||
your Python scripts with SnortAI module or writing new correlation modules in
|
||||
Python.
|
||||
|
||||
|
||||
===========================
|
||||
9. Additional documentation
|
||||
|
|
28
corr_modules/example.py
Normal file
28
corr_modules/example.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Example correlation index in Python
|
||||
|
||||
# XXX You may have an 'undefined reference to PyNone_Struct
|
||||
# after running Snort with your module, you're facing an
|
||||
# annoying bug due to the dynamically linked Python library.
|
||||
# I'm sorry, but I'm still looking for a solution for this,
|
||||
# and anyway it only happens when you import the module
|
||||
# 'snortai'
|
||||
|
||||
# import snortai
|
||||
|
||||
# Function that takes two alerts as arguments (arguments of
|
||||
# alert object:
|
||||
# id, gid, sid, rev, description, priority, classification,
|
||||
# timestamp, from, to, from_port, to_port, latitude,
|
||||
# longitude, alerts_count) and returns a correlation index
|
||||
# between 0 and 1 expressing how correlated these two alerts are
|
||||
|
||||
def AI_corr_index ( alert1, alert2 ):
|
||||
return 0.0
|
||||
|
||||
# Return the weight of this index, between 0 and 1
|
||||
|
||||
def AI_corr_index_weight():
|
||||
return 0.0
|
||||
|
102
correlation.c
102
correlation.c
|
@ -32,6 +32,25 @@
|
|||
#include <gvc.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBPYTHON2_6
|
||||
/*******************************************/
|
||||
/* Avoid conflicts with Snort header files */
|
||||
#ifdef _POSIX_C_SOURCE
|
||||
#undef _POSIX_C_SOURCE
|
||||
#endif
|
||||
|
||||
#ifdef _XOPEN_C_SOURCE
|
||||
#undef _XOPEN_C_SOURCE
|
||||
#endif
|
||||
|
||||
#ifdef _XOPEN_SOURCE
|
||||
#undef _XOPEN_SOURCE
|
||||
#endif
|
||||
/*******************************************/
|
||||
|
||||
#include <Python.h>
|
||||
#endif
|
||||
|
||||
/** \defgroup correlation Module for the correlation of security alerts
|
||||
* @{ */
|
||||
|
||||
|
@ -365,8 +384,27 @@ AI_alert_correlation_thread ( void *arg )
|
|||
double (**corr_functions)( const AI_snort_alert*, const AI_snort_alert* ) = NULL;
|
||||
double (**corr_weights)() = NULL;
|
||||
|
||||
#ifdef HAVE_LIBPYTHON2_6
|
||||
PyAlert *pyA = NULL,
|
||||
*pyB = NULL;
|
||||
|
||||
PyObject *pArgs = NULL,
|
||||
*pRet = NULL;
|
||||
|
||||
PyObject **py_corr_functions = NULL;
|
||||
PyObject **py_weight_functions = NULL;
|
||||
|
||||
size_t n_py_corr_functions = 0;
|
||||
size_t n_py_weight_functions = 0;
|
||||
|
||||
double py_value = 0.0,
|
||||
py_weight = 0.0;
|
||||
#endif
|
||||
|
||||
corr_functions = AI_get_corr_functions ( &n_corr_functions );
|
||||
corr_weights = AI_get_corr_weights ( &n_corr_weights );
|
||||
py_corr_functions = AI_get_py_functions ( &n_py_corr_functions );
|
||||
py_weight_functions = AI_get_py_weights ( &n_py_weight_functions );
|
||||
|
||||
pthread_mutex_init ( &mutex, NULL );
|
||||
|
||||
|
@ -466,6 +504,64 @@ AI_alert_correlation_thread ( void *arg )
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBPYTHON2_6
|
||||
if (( py_corr_functions ))
|
||||
{
|
||||
pyA = AI_alert_to_pyalert ( corr_key.a );
|
||||
pyB = AI_alert_to_pyalert ( corr_key.b );
|
||||
|
||||
if ( pyA && pyB )
|
||||
{
|
||||
for ( i=0; i < n_py_corr_functions; i++ )
|
||||
{
|
||||
if ( !( pArgs = Py_BuildValue ( "(OO)", pyA, pyB )))
|
||||
{
|
||||
PyErr_Print();
|
||||
AI_fatal_err ( "Could not initialize the Python arguments for the call", __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
if ( !( pRet = PyEval_CallObject ( py_corr_functions[i], pArgs )))
|
||||
{
|
||||
PyErr_Print();
|
||||
AI_fatal_err ( "Could not call the correlation function from the Python module", __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
if ( !( PyArg_Parse ( pRet, "d", &py_value )))
|
||||
{
|
||||
PyErr_Print();
|
||||
AI_fatal_err ( "Could not parse the correlation value out of the Python correlation function", __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
Py_DECREF ( pRet );
|
||||
Py_DECREF ( pArgs );
|
||||
|
||||
if ( !( pRet = PyEval_CallObject ( py_weight_functions[i], (PyObject*) NULL )))
|
||||
{
|
||||
PyErr_Print();
|
||||
AI_fatal_err ( "Could not call the correlation function from the Python module", __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
if ( !( PyArg_Parse ( pRet, "d", &py_weight )))
|
||||
{
|
||||
PyErr_Print();
|
||||
AI_fatal_err ( "Could not parse the correlation weight out of the Python correlation function", __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
Py_DECREF ( pRet );
|
||||
|
||||
if ( py_weight != 0.0 )
|
||||
{
|
||||
corr->correlation += py_weight * py_value;
|
||||
n_correlations++;
|
||||
}
|
||||
}
|
||||
|
||||
free ( pyA ); free ( pyB );
|
||||
pyA = NULL; pyB = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( n_correlations != 0 )
|
||||
{
|
||||
corr->correlation /= (double) n_correlations;
|
||||
|
@ -548,10 +644,12 @@ AI_alert_correlation_thread ( void *arg )
|
|||
)
|
||||
)
|
||||
) {
|
||||
if ( !( corr->key.a->derived_alerts = ( AI_snort_alert** ) realloc ( corr->key.a->derived_alerts, (++corr->key.a->n_derived_alerts) * sizeof ( AI_snort_alert* ))))
|
||||
if ( !( corr->key.a->derived_alerts = ( AI_snort_alert** ) realloc ( corr->key.a->derived_alerts,
|
||||
(++corr->key.a->n_derived_alerts) * sizeof ( AI_snort_alert* ))))
|
||||
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
||||
|
||||
if ( !( corr->key.b->parent_alerts = ( AI_snort_alert** ) realloc ( corr->key.b->parent_alerts, (++corr->key.b->n_parent_alerts) * sizeof ( AI_snort_alert* ))))
|
||||
if ( !( corr->key.b->parent_alerts = ( AI_snort_alert** ) realloc ( corr->key.b->parent_alerts,
|
||||
(++corr->key.b->n_parent_alerts) * sizeof ( AI_snort_alert* ))))
|
||||
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
||||
|
||||
corr->key.a->derived_alerts[ corr->key.a->n_derived_alerts - 1 ] = corr->key.b;
|
||||
|
|
86
htdocs/alerts.cgi
Executable file
86
htdocs/alerts.cgi
Executable file
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
use Env qw(DOCUMENT_ROOT QUERY_STRING);
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $method = 'xml';
|
||||
|
||||
if ( $QUERY_STRING )
|
||||
{
|
||||
if ( $QUERY_STRING =~ /method=([a-z]+)/ )
|
||||
{
|
||||
if ( $1 eq 'json' or $1 eq 'xml' )
|
||||
{
|
||||
$method = $1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my %mon2num = qw( jan 1 feb 2 mar 3 apr 4 may 5 jun 6 jul 7 aug 8 sep 9 oct 10 nov 11 dec 12 );
|
||||
my $json_file = (( $DOCUMENT_ROOT ) ? $DOCUMENT_ROOT : '.' ).'/correlation_graph.json';
|
||||
my $json_string = '';
|
||||
|
||||
open IN, $json_file or die "Alert JSON file not found";
|
||||
$json_string .= $_ while ( <IN> );
|
||||
close IN;
|
||||
|
||||
if ( $method eq 'json' )
|
||||
{
|
||||
print "Content-Type: application/json\n\n";
|
||||
print $json_string;
|
||||
} elsif ( $method eq 'xml' ) {
|
||||
use JSON;
|
||||
use Time::Local;
|
||||
|
||||
my @json = @{JSON->new->utf8->decode ( $json_string )};
|
||||
print "Content-Type: application/xml\n\n".
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n".
|
||||
"<alerts>\n";
|
||||
|
||||
for ( @json )
|
||||
{
|
||||
print "\t<alert";
|
||||
my %element = %$_;
|
||||
|
||||
for my $key ( keys %element )
|
||||
{
|
||||
if ( $key !~ /[^a-zA-Z0-9_]/ and !UNIVERSAL::isa ( $element{$key}, "ARRAY" ) and !UNIVERSAL::isa ( $element{$key}, "HASH" ))
|
||||
{
|
||||
my $k = $key;
|
||||
|
||||
if ( $key eq 'snortSID' or $key eq 'snortGID' or $key eq 'snortREV' )
|
||||
{
|
||||
$k =~ s/^snort//;
|
||||
$k = lc $k;
|
||||
} elsif ( $key eq 'to' or $key eq 'from' ) {
|
||||
if ( $element{$key} =~ /:([1-9][0-9]*)$/ )
|
||||
{
|
||||
my $port = $1;
|
||||
$element{$key} =~ s/^(.*):[1-9][0-9]*$/$1/;
|
||||
print " ${key}_port=\"$port\"";
|
||||
}
|
||||
} elsif ( $key eq 'date' ) {
|
||||
if ( $element{$key} =~ /^\s*[a-z]+\s+([a-z]+)\s+([0-9]+)\s+([0-9]+):([0-9]+):([0-9]+)\s+([0-9]+)\s*$/i )
|
||||
{
|
||||
my $mon = $mon2num{ lc substr ( $1, 0, 3 )} - 1;
|
||||
my $day = $2;
|
||||
my $hour = $3;
|
||||
my $min = $4;
|
||||
my $sec = $5;
|
||||
my $year = $6;
|
||||
$element{$key} = timelocal ( $sec, $min, $hour, $day, $mon, $year );
|
||||
}
|
||||
}
|
||||
|
||||
$element{$key} =~ s/(^|[^\\])"/$1\\"/g;
|
||||
print " $k=\"".$element{$key}."\"";
|
||||
}
|
||||
}
|
||||
|
||||
print "></alert>\n";
|
||||
}
|
||||
|
||||
print "</alerts>\n";
|
||||
}
|
||||
|
133
modules.c
133
modules.c
|
@ -33,6 +33,16 @@ PRIVATE size_t n_corr_functions = 0;
|
|||
PRIVATE double (**weight_functions)() = NULL;
|
||||
PRIVATE size_t n_weight_functions = 0;
|
||||
|
||||
#ifdef HAVE_LIBPYTHON2_6
|
||||
|
||||
PRIVATE PyObject **py_corr_functions = NULL;
|
||||
PRIVATE size_t n_py_corr_functions = 0;
|
||||
|
||||
PRIVATE PyObject **py_weight_functions = NULL;
|
||||
PRIVATE size_t n_py_weight_functions = 0;
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Get the correlation functions from the extra correlation modules as array of function pointers
|
||||
* \param n_functions Number of function pointers in the array
|
||||
|
@ -59,6 +69,71 @@ double
|
|||
return weight_functions;
|
||||
} /* ----- end of function AI_get_corr_weights ----- */
|
||||
|
||||
#ifdef HAVE_LIBPYTHON2_6
|
||||
/**
|
||||
* \brief Get the correlation functions from the Python modules, if Python support is enabled
|
||||
* \param n_functions Reference to the number of functions in the array
|
||||
* \return The array of Python correlation functions as PyObject**
|
||||
*/
|
||||
|
||||
PyObject**
|
||||
AI_get_py_functions ( size_t *n_functions )
|
||||
{
|
||||
*n_functions = n_py_corr_functions;
|
||||
return py_corr_functions;
|
||||
} /* ----- end of function AI_get_py_functions ----- */
|
||||
|
||||
/**
|
||||
* \brief Get the correlation index weights from the Python modules, if Python support is enabled
|
||||
* \param n_functions Reference to the number of correlation weight functions in the array
|
||||
* \return The array of correlation weight functions as PyObject**
|
||||
*/
|
||||
|
||||
PyObject**
|
||||
AI_get_py_weights ( size_t *n_functions )
|
||||
{
|
||||
*n_functions = n_py_weight_functions;
|
||||
return py_weight_functions;
|
||||
} /* ----- end of function AI_get_py_weights ----- */
|
||||
|
||||
/**
|
||||
* \brief Convert an AI_snort_alert object to a PyAlert object that can be managed by a Python module
|
||||
* \param alert AI_snort_alert object to be converted
|
||||
* \return A PyAlert object wrapping the original AI_snort_alert object
|
||||
*/
|
||||
|
||||
PyAlert*
|
||||
AI_alert_to_pyalert ( AI_snort_alert *alert )
|
||||
{
|
||||
PyAlert *pyalert = NULL;
|
||||
char src_addr[INET_ADDRSTRLEN] = { 0 },
|
||||
dst_addr[INET_ADDRSTRLEN] = { 0 };
|
||||
|
||||
if ( !( pyalert = (PyAlert*) malloc ( sizeof ( PyAlert ))))
|
||||
{
|
||||
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
inet_ntop ( AF_INET, &(alert->ip_src_addr), src_addr, INET_ADDRSTRLEN );
|
||||
inet_ntop ( AF_INET, &(alert->ip_dst_addr), dst_addr, INET_ADDRSTRLEN );
|
||||
|
||||
pyalert->classification = alert->classification ? PyString_FromString ( alert->classification ) : Py_None;
|
||||
pyalert->clusteredAlertsCount = alert->grouped_alerts_count;
|
||||
pyalert->desc = alert->desc ? PyString_FromString ( alert->desc ) : Py_None;
|
||||
pyalert->gid = alert->gid;
|
||||
pyalert->ip_src_addr = ( strlen ( src_addr ) > 0 ) ? PyString_FromString ( src_addr ) : Py_None;
|
||||
pyalert->ip_dst_addr = ( strlen ( dst_addr ) > 0 ) ? PyString_FromString ( dst_addr ) : Py_None;
|
||||
pyalert->priority = alert->priority;
|
||||
pyalert->rev = alert->rev;
|
||||
pyalert->sid = alert->sid;
|
||||
pyalert->tcp_src_port = ntohs ( alert->tcp_src_port );
|
||||
pyalert->tcp_dst_port = ntohs ( alert->tcp_dst_port );
|
||||
pyalert->timestamp = alert->timestamp;
|
||||
|
||||
return pyalert;
|
||||
} /* ----- end of function AI_alert_to_pyalert ----- */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Initialize the extra modules provided by the user
|
||||
*/
|
||||
|
@ -73,6 +148,12 @@ AI_init_corr_modules ()
|
|||
size_t n_dl_handles = 0;
|
||||
struct dirent *dir_info = NULL;
|
||||
|
||||
#ifdef HAVE_LIBPYTHON2_6
|
||||
char *pyPath = NULL;
|
||||
PyObject *pObj = NULL;
|
||||
BOOL isPyInit = false;
|
||||
#endif
|
||||
|
||||
if ( !( dir = opendir ( config->corr_modules_dir )))
|
||||
{
|
||||
return;
|
||||
|
@ -141,6 +222,58 @@ AI_init_corr_modules ()
|
|||
|
||||
AI_fatal_err ( "dlsym error", __FILE__, __LINE__ );
|
||||
}
|
||||
} else if ( preg_match ( "\\.py$", dir_info->d_name, NULL, NULL )) {
|
||||
#ifdef HAVE_LIBPYTHON2_6
|
||||
|
||||
if ( !( pyPath = (char*) malloc ( strlen ( config->corr_modules_dir ) + strlen ( Py_GetPath() ) + 4 )))
|
||||
{
|
||||
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
fname = strdup ( dir_info->d_name );
|
||||
fname[strlen ( fname ) - 3] = 0;
|
||||
|
||||
if ( !isPyInit )
|
||||
{
|
||||
Py_Initialize();
|
||||
isPyInit = true;
|
||||
}
|
||||
|
||||
sprintf ( pyPath, "%s:%s", config->corr_modules_dir, Py_GetPath() );
|
||||
PySys_SetPath ( pyPath );
|
||||
|
||||
if ( !( pObj = PyImport_ImportModule ( fname )))
|
||||
{
|
||||
PyErr_Print();
|
||||
AI_fatal_err ( "Could not load a Python correlation module", __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
free ( fname );
|
||||
fname = NULL;
|
||||
|
||||
if ( !( py_corr_functions = (PyObject**) realloc ( py_corr_functions, (++n_py_corr_functions) * sizeof ( PyObject* ))))
|
||||
{
|
||||
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
if ( !( py_corr_functions[ n_py_corr_functions - 1 ] = PyObject_GetAttrString ( pObj, "AI_corr_index" )))
|
||||
{
|
||||
AI_fatal_err ( "AI_corr_index() method not found in the Python correlation module", __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
if ( !( py_weight_functions = (PyObject**) realloc ( py_weight_functions, (++n_py_weight_functions) * sizeof ( PyObject* ))))
|
||||
{
|
||||
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
if ( !( py_weight_functions[ n_py_weight_functions - 1 ] = PyObject_GetAttrString ( pObj, "AI_corr_index_weight" )))
|
||||
{
|
||||
AI_fatal_err ( "AI_corr_index_weight() method not found in the Python correlation module", __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
Py_DECREF ( pObj );
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
20
pymodule/README
Normal file
20
pymodule/README
Normal file
|
@ -0,0 +1,20 @@
|
|||
Python module for interfacing with SnortAI. Compile it and install it through
|
||||
|
||||
$ python setup.py build
|
||||
$ [sudo] python setup.py install
|
||||
|
||||
You can then access the alerts information captured by Snort simply by writing a
|
||||
code like the following (also see module.py):
|
||||
|
||||
import snortai
|
||||
|
||||
alerts = snortai.alerts()
|
||||
|
||||
for alert in alerts:
|
||||
# Access the information
|
||||
|
||||
The alert class has the following members:
|
||||
|
||||
# id, gid, sid, rev, description, priority, classification, timestamp
|
||||
# from, to, from_port, to_port, latitude, longitude, alerts_count
|
||||
|
21
pymodule/module.py
Normal file
21
pymodule/module.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Compile snortai module by typing, in pymodule directory:
|
||||
# $ python setup.py build
|
||||
# $ [sudo] python setup.py install
|
||||
import snortai
|
||||
|
||||
# Get the alerts from Snort module as tuple
|
||||
# (IMPORTANT: Snort and SnortAI module, as well as
|
||||
# the web server running on top of the module, must
|
||||
# be running in order to have this call successful)
|
||||
alerts = snortai.alerts()
|
||||
|
||||
# Navigate the tuple of alerts
|
||||
# Fields:
|
||||
# id, gid, sid, rev, description, priority, classification,
|
||||
# timestamp, from, to, from_port, to_port, latitude,
|
||||
# longitude, alerts_count
|
||||
for alert in alerts:
|
||||
print alert.gid, alert.sid, alert.rev, alert.description
|
||||
|
34
pymodule/setup.py
Normal file
34
pymodule/setup.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from distutils.core import setup, Extension
|
||||
import commands
|
||||
import re
|
||||
|
||||
xml_include = commands.getoutput ( 'pkg-config --cflags libxml-2.0' )
|
||||
m = re.match ( '^-I\s*(.+?)\s*$', xml_include )
|
||||
|
||||
if m:
|
||||
xml_include = m.group ( 1 )
|
||||
|
||||
xml_libs = commands.getoutput ( 'pkg-config --libs libxml-2.0' )
|
||||
m = re.match ( '^-l\s*(.+?)\s*$', xml_libs )
|
||||
|
||||
if m:
|
||||
xml_libs = m.group ( 1 )
|
||||
|
||||
setup (
|
||||
name = 'snortai',
|
||||
version = '0.1',
|
||||
description = 'Python interface to SnortAI module',
|
||||
author = 'Fabio "BlackLight" Manganiello',
|
||||
author_email = 'blacklight@autistici.org',
|
||||
ext_modules = [
|
||||
Extension (
|
||||
'snortai',
|
||||
sources = ['snortai_module.c'],
|
||||
include_dirs = ['..', '../include', '../uthash', xml_include],
|
||||
libraries = [xml_libs]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
496
pymodule/snortai_module.c
Normal file
496
pymodule/snortai_module.c
Normal file
|
@ -0,0 +1,496 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: snortai_module.c
|
||||
*
|
||||
* Description: Python module for interfacing to SnortAI
|
||||
*
|
||||
* Version: 0.1
|
||||
* Created: 28/01/2011 21:33:57
|
||||
* 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!
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef HAVE_LIBPYTHON2_6
|
||||
#define HAVE_LIBPYTHON2_6 1
|
||||
#endif
|
||||
|
||||
#include "spp_ai.h"
|
||||
|
||||
#include <libxml/xmlreader.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <structmember.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifndef LIBXML_READER_ENABLED
|
||||
#error "libxml2 reader not enabled\n"
|
||||
#endif
|
||||
|
||||
#ifndef PyMODINIT_FUNC
|
||||
#define PyMODINIT_FUNC void
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_WEBSERV
|
||||
#define DEFAULT_WEBSERV "localhost"
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_WEBPORT
|
||||
#define DEFAULT_WEBPORT 7654
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_RESOURCE
|
||||
#define DEFAULT_RESOURCE "/alerts.cgi"
|
||||
#endif
|
||||
|
||||
/** Enumeration for managing XML response tags */
|
||||
enum { inAlerts, inAlert, ALERT_TAG_NUM };
|
||||
|
||||
static PyObject* Py_alerts ( PyObject *self, PyObject *args );
|
||||
static PyObject* PyAlert_new ( PyTypeObject *type, PyObject *args, PyObject *kwds );
|
||||
static int PyAlert_init ( PyAlert *self, PyObject *args, PyObject *kwds );
|
||||
static void PyAlerts_free ( PyAlert *self );
|
||||
PyMODINIT_FUNC initsnortai ( void );
|
||||
|
||||
char resource[1024] = DEFAULT_RESOURCE;
|
||||
char webserv[1024] = DEFAULT_WEBSERV;
|
||||
short int webport = DEFAULT_WEBPORT;
|
||||
PyObject *exception = NULL;
|
||||
|
||||
/** Members of the Python binded alert object */
|
||||
static PyMemberDef alert_members[] = {
|
||||
{ "gid", T_INT, offsetof ( PyAlert, gid ), 0, "Snort alert gID" },
|
||||
{ "sid", T_INT, offsetof ( PyAlert, sid ), 0, "Snort alert sID" },
|
||||
{ "rev", T_INT, offsetof ( PyAlert, rev ), 0, "Snort alert revision number" },
|
||||
{ "priority", T_INT, offsetof ( PyAlert, priority ), 0, "Snort alert priority" },
|
||||
{ "description", T_OBJECT_EX, offsetof ( PyAlert, desc ), 0, "Snort alert description" },
|
||||
{ "classification", T_OBJECT_EX, offsetof ( PyAlert, classification ), 0, "Snort alert classification" },
|
||||
{ "timestamp", T_INT, offsetof ( PyAlert, timestamp ), 0, "Snort alert timestamp" },
|
||||
{ "from", T_OBJECT_EX, offsetof ( PyAlert, ip_src_addr ), 0, "Source IP address" },
|
||||
{ "to", T_OBJECT_EX, offsetof ( PyAlert, ip_dst_addr ), 0, "Destination IP address" },
|
||||
{ "from_port", T_INT, offsetof ( PyAlert, tcp_src_port ), 0, "Source port" },
|
||||
{ "to_port", T_INT, offsetof ( PyAlert, tcp_dst_port ), 0, "Destination port" },
|
||||
{ "latitude", T_DOUBLE, offsetof ( PyAlert, latitude ), 0, "Geographical latitude, if available" },
|
||||
{ "longitude", T_DOUBLE, offsetof ( PyAlert, longitude ), 0, "Geographical longitude, if available" },
|
||||
{ "alert_count", T_INT, offsetof ( PyAlert, clusteredAlertsCount ), 0, "Number of alerts clustered in this object" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/** Methods inside of the Python binded alert object */
|
||||
static PyMethodDef alert_methods[] = {{ NULL }};
|
||||
|
||||
/** Module methods */
|
||||
static PyMethodDef module_methods[] = {
|
||||
{ "alerts", (PyCFunction) Py_alerts, METH_VARARGS, "Return the list of SnortAI alerts" },
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
/** Definition of the Python binded alert object */
|
||||
static PyTypeObject alert_type = {
|
||||
PyObject_HEAD_INIT(NULL)
|
||||
0, /* ob_size*/
|
||||
"snortai.__alert", /* tp_name*/
|
||||
sizeof(PyAlert), /* tp_basicsize*/
|
||||
0, /* tp_itemsize*/
|
||||
(destructor)PyAlerts_free, /* tp_dealloc*/
|
||||
0, /* tp_print*/
|
||||
0, /* tp_getattr*/
|
||||
0, /* tp_setattr*/
|
||||
0, /* tp_compare*/
|
||||
0, /* tp_repr*/
|
||||
0, /* tp_as_number*/
|
||||
0, /* tp_as_sequence*/
|
||||
0, /* tp_as_mapping*/
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call*/
|
||||
0, /* tp_str*/
|
||||
0, /* tp_getattro*/
|
||||
0, /* tp_setattro*/
|
||||
0, /* tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags*/
|
||||
"SnortAI alert type", /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
alert_methods, /* tp_methods */
|
||||
alert_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc)PyAlert_init, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
PyAlert_new, /* tp_new */
|
||||
};
|
||||
|
||||
static PyObject*
|
||||
Py_alerts ( PyObject *module, PyObject *args )
|
||||
{
|
||||
int i, sd, len = 0, xml_offset = -1;
|
||||
char addr[INET_ADDRSTRLEN] = { 0 };
|
||||
char *response = NULL;
|
||||
unsigned int response_len = 1;
|
||||
unsigned int n_alerts = 0;
|
||||
FILE *fsock = NULL;
|
||||
struct sockaddr_in server;
|
||||
struct hostent *host;
|
||||
PyAlert *alerts = NULL, *cur_alert = NULL, *prev_alert = NULL;
|
||||
PyObject *self = NULL;
|
||||
|
||||
BOOL xmlFlags[ALERT_TAG_NUM] = { false };
|
||||
xmlTextReaderPtr xml;
|
||||
const xmlChar *tagname;
|
||||
|
||||
/* Connect to the web server and get the XML containing the alerts */
|
||||
if ( !( host = gethostbyname ( webserv )))
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not resolve web server name" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( !( host->h_addr ))
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not resolve web server name" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf ( addr, sizeof ( addr ), "%u.%u.%u.%u",
|
||||
(unsigned char) host->h_addr[0],
|
||||
(unsigned char) host->h_addr[1],
|
||||
(unsigned char) host->h_addr[2],
|
||||
(unsigned char) host->h_addr[3] );
|
||||
|
||||
if (( sd = socket ( AF_INET, SOCK_STREAM, IPPROTO_IP )) < 0 )
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not initialize the socket" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_port = htons ( webport );
|
||||
server.sin_addr.s_addr = inet_addr ( addr );
|
||||
|
||||
if ( connect ( sd, ( struct sockaddr* ) &server, sizeof ( struct sockaddr )) < 0 )
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not connect to the web server" );
|
||||
close ( sd );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( !( fsock = fdopen ( sd, "r+" )))
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not open the socket" );
|
||||
close ( sd );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fprintf ( fsock,
|
||||
"GET %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
"User-Agent: Python SnortAI request\r\n"
|
||||
"Connection: close\r\n\r\n",
|
||||
resource, webserv );
|
||||
|
||||
while ( !feof ( fsock ))
|
||||
{
|
||||
if ( !( response = (char*) realloc ( response, ++response_len )))
|
||||
{
|
||||
PyErr_SetString ( exception, "Dynamic memory allocation error" );
|
||||
fclose ( fsock );
|
||||
close ( sd );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
response[ response_len - 2 ] = fgetc ( fsock );
|
||||
}
|
||||
|
||||
response[ (--response_len) - 1 ] = 0;
|
||||
fclose ( fsock );
|
||||
close ( sd );
|
||||
/*****************************/
|
||||
|
||||
/* Remove the HTTP headers from the response */
|
||||
if (( xml_offset = (int) strstr ( response, "\n\n" ) - (int) response ) >= 0 ) {}
|
||||
else if (( xml_offset = (int) strstr ( response, "\r\n\r\n" ) - (int) response ) >= 0 ) {}
|
||||
else {
|
||||
PyErr_SetString ( exception, "The HTTP response provided by the server has no valid HTTP header" );
|
||||
free ( response );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = strlen ( response );
|
||||
|
||||
for ( i=0; i < len - xml_offset; i++ )
|
||||
{
|
||||
response[i] = response [i + xml_offset];
|
||||
}
|
||||
|
||||
response [len - xml_offset] = 0;
|
||||
|
||||
for ( xml_offset=0; response[xml_offset] != '<'; xml_offset++ );
|
||||
for ( i=0; i < len - xml_offset; i++ )
|
||||
{
|
||||
response[i] = response[i + xml_offset];
|
||||
}
|
||||
|
||||
response [len - xml_offset] = 0;
|
||||
/*****************************/
|
||||
|
||||
/* Parse the XML document */
|
||||
LIBXML_TEST_VERSION
|
||||
|
||||
if ( !( xml = xmlReaderForMemory ( response, strlen ( response ), NULL, NULL, 0 )))
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not initialize the XML reader object" );
|
||||
free ( response );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ( xmlTextReaderRead ( xml ))
|
||||
{
|
||||
if ( !( tagname = xmlTextReaderConstName ( xml )))
|
||||
continue;
|
||||
|
||||
if ( xmlTextReaderNodeType ( xml ) == XML_READER_TYPE_ELEMENT )
|
||||
{
|
||||
if ( !strcasecmp ((const char*) tagname, "alerts" ))
|
||||
{
|
||||
if ( xmlFlags[inAlerts] )
|
||||
{
|
||||
PyErr_SetString ( exception, "Parse error in received XML: 'alerts' tag opened twice" );
|
||||
free ( response );
|
||||
return NULL;
|
||||
} else {
|
||||
xmlFlags[inAlerts] = true;
|
||||
}
|
||||
} else if ( !strcasecmp ((const char*) tagname, "alert" ))
|
||||
{
|
||||
if ( xmlFlags[inAlert] )
|
||||
{
|
||||
PyErr_SetString ( exception, "Parse error in received XML: 'alert' tag opened inside of another 'alert' tag" );
|
||||
free ( response );
|
||||
return NULL;
|
||||
} else {
|
||||
xmlFlags[inAlert] = true;
|
||||
|
||||
/* Fill the PyObject */
|
||||
if ( !( cur_alert = (PyAlert*) alert_type.tp_alloc ( &alert_type, 0 )))
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not initialize the PyAlert object" );
|
||||
free ( response );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( !alerts )
|
||||
{
|
||||
alerts = cur_alert;
|
||||
}
|
||||
|
||||
if ( prev_alert )
|
||||
{
|
||||
prev_alert->next = cur_alert;
|
||||
}
|
||||
|
||||
n_alerts++;
|
||||
cur_alert->next = NULL;
|
||||
|
||||
cur_alert->id = ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "id" )) ?
|
||||
(unsigned int) strtol ((const char*) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "id" ), NULL, 10 ) : 0;
|
||||
cur_alert->gid = ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "gid" )) ?
|
||||
(unsigned int) strtol ((const char*) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "gid" ), NULL, 10 ) : 0;
|
||||
cur_alert->sid = ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "sid" )) ?
|
||||
(unsigned int) strtol ((const char*) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "sid" ), NULL, 10 ) : 0;
|
||||
cur_alert->rev = ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "rev" )) ?
|
||||
(unsigned int) strtol ((const char*) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "rev" ), NULL, 10 ) : 0;
|
||||
cur_alert->priority = ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "priority" )) ?
|
||||
(unsigned int) strtol ((const char*) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "priority" ), NULL, 10 ) : 0;
|
||||
cur_alert->timestamp = ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "timestamp" )) ?
|
||||
(time_t) strtol ((const char*) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "timestamp" ), NULL, 10 ) : (time_t) 0;
|
||||
cur_alert->tcp_src_port = ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "from_port" )) ?
|
||||
(unsigned short) strtol ((const char*) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "from_port" ), NULL, 10 ) : 0;
|
||||
cur_alert->tcp_dst_port = ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "to_port" )) ?
|
||||
(unsigned short) strtol ((const char*) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "to_port" ), NULL, 10 ) : 0;
|
||||
cur_alert->latitude = ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "latitude" )) ?
|
||||
strtod ((const char*) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "latitude" ), NULL ) : 0.0;
|
||||
cur_alert->longitude = ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "longitude" )) ?
|
||||
strtod ((const char*) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "longitude" ), NULL ) : 0.0;
|
||||
|
||||
if ( !( cur_alert->desc =
|
||||
xmlTextReaderGetAttribute ( xml, (const xmlChar*) "label" ) ?
|
||||
PyString_FromString ((char*) ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "label" ))) : Py_None ))
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not initialize a field in PyAlert object" );
|
||||
free ( response );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( !( cur_alert->classification =
|
||||
xmlTextReaderGetAttribute ( xml, (const xmlChar*) "classification" ) ?
|
||||
PyString_FromString ((char*) ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "classification" ))) : Py_None ))
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not initialize a field in PyAlert object" );
|
||||
free ( response );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( !( cur_alert->ip_src_addr =
|
||||
xmlTextReaderGetAttribute ( xml, (const xmlChar*) "from" ) ?
|
||||
PyString_FromString ((char*) ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "from" ))) : Py_None ))
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not initialize a field in PyAlert object" );
|
||||
free ( response );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( !( cur_alert->ip_dst_addr =
|
||||
xmlTextReaderGetAttribute ( xml, (const xmlChar*) "to" ) ?
|
||||
PyString_FromString ((char*) ( xmlTextReaderGetAttribute ( xml, (const xmlChar*) "to" ))) : Py_None ))
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not initialize a field in PyAlert object" );
|
||||
free ( response );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
prev_alert = cur_alert;
|
||||
}
|
||||
} else {
|
||||
PyErr_SetString ( exception, "Unrecognized XML tag in received response" );
|
||||
free ( response );
|
||||
return NULL;
|
||||
}
|
||||
} else if ( xmlTextReaderNodeType ( xml ) == XML_READER_TYPE_END_ELEMENT ) {
|
||||
if ( !strcasecmp ((const char*) tagname, "alerts" ))
|
||||
{
|
||||
if ( !xmlFlags[inAlerts] )
|
||||
{
|
||||
PyErr_SetString ( exception, "'alerts' tag closed, but never opened" );
|
||||
free ( response );
|
||||
return NULL;
|
||||
} else {
|
||||
xmlFlags[inAlerts] = false;
|
||||
}
|
||||
} else if ( !strcasecmp ((const char*) tagname, "alert" )) {
|
||||
if ( !xmlFlags[inAlert] )
|
||||
{
|
||||
PyErr_SetString ( exception, "'alert' tag closed, but never opened" );
|
||||
free ( response );
|
||||
return NULL;
|
||||
} else {
|
||||
xmlFlags[inAlert] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xmlFreeTextReader ( xml );
|
||||
xmlCleanupParser();
|
||||
free ( response );
|
||||
/*****************************/
|
||||
|
||||
/* Build the alerts tuple */
|
||||
if ( n_alerts > 0 )
|
||||
{
|
||||
if ( !( self = PyTuple_New ( n_alerts )))
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not initialize the vector of alerts" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( i=0, cur_alert = alerts; cur_alert; cur_alert = cur_alert->next, i++ )
|
||||
{
|
||||
PyTuple_SetItem ( self, i, Py_BuildValue ( "O", cur_alert ));
|
||||
Py_INCREF ((PyObject*) cur_alert );
|
||||
}
|
||||
} else {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static int
|
||||
PyAlert_init ( PyAlert *self, PyObject *args, PyObject *kwds )
|
||||
{
|
||||
static char *kwlist[] = {
|
||||
"gid", "sid", "rev",
|
||||
"priority", "description", "classifcation",
|
||||
"timestamp", "from", "to", "from_port", "to_port",
|
||||
"latitude", "longitude", "alert_count", NULL
|
||||
};
|
||||
|
||||
if ( !( PyArg_ParseTupleAndKeywords ( args, kwds, "|iiiiOOiOOiiddi", kwlist,
|
||||
&self->gid, &self->sid, &self->rev, &self->priority, &self->desc,
|
||||
&self->classification, &self->timestamp,
|
||||
&self->ip_src_addr, &self->ip_dst_addr, &self->tcp_src_port, &self->tcp_dst_port,
|
||||
&self->latitude, &self->longitude, &self->clusteredAlertsCount )))
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not initialize a PyAlert object" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
PyAlert_new ( PyTypeObject *type, PyObject *args, PyObject *kwds )
|
||||
{
|
||||
PyAlert *self = NULL;
|
||||
|
||||
if ( !( self = (PyAlert*) type->tp_alloc ( type, 0 )))
|
||||
{
|
||||
PyErr_SetString ( exception, "Could not allocate a PyAlert object" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject*) self;
|
||||
}
|
||||
|
||||
static void
|
||||
PyAlerts_free ( PyAlert *self )
|
||||
{
|
||||
Py_XDECREF ( self->classification );
|
||||
Py_XDECREF ( self->desc );
|
||||
self->ob_type->tp_free (( PyObject* ) self );
|
||||
}
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initsnortai ( void )
|
||||
{
|
||||
PyObject *m = NULL;
|
||||
|
||||
if ( PyType_Ready ( &alert_type ) < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !( m = Py_InitModule ( "snortai", module_methods )))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !exception )
|
||||
{
|
||||
exception = PyErr_NewException ( "snortai.error", NULL, NULL );
|
||||
Py_INCREF ( exception );
|
||||
}
|
||||
|
||||
Py_INCREF ( &alert_type );
|
||||
PyModule_AddObject ( m, "resource", PyString_FromString ( resource ));
|
||||
PyModule_AddObject ( m, "webserv", PyString_FromString ( webserv ));
|
||||
PyModule_AddObject ( m, "webport", PyInt_FromLong ((long int) webport ));
|
||||
/* PyModule_AddObject ( m, "alerts", (PyObject*) &alert_type ); */
|
||||
}
|
||||
|
77
spp_ai.h
77
spp_ai.h
|
@ -543,7 +543,60 @@ typedef struct {
|
|||
UT_hash_handle hh;
|
||||
} AI_alert_type_pair;
|
||||
/*****************************************************************/
|
||||
#ifdef HAVE_LIBPYTHON2_6
|
||||
|
||||
/*******************************************/
|
||||
/* Avoid conflicts with Snort header files */
|
||||
#ifdef _POSIX_C_SOURCE
|
||||
#undef _POSIX_C_SOURCE
|
||||
#endif
|
||||
|
||||
#ifdef _XOPEN_C_SOURCE
|
||||
#undef _XOPEN_C_SOURCE
|
||||
#endif
|
||||
|
||||
#ifdef _XOPEN_SOURCE
|
||||
#undef _XOPEN_SOURCE
|
||||
#endif
|
||||
/*******************************************/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
/** Definition of the alert type for Python binding */
|
||||
typedef struct _PyAlert
|
||||
{
|
||||
PyObject_HEAD
|
||||
|
||||
unsigned int id;
|
||||
|
||||
/* Identifiers of the alert */
|
||||
unsigned int gid;
|
||||
unsigned int sid;
|
||||
unsigned int rev;
|
||||
|
||||
/* Snort priority, description,
|
||||
* classification and timestamp
|
||||
* of the alert */
|
||||
unsigned short priority;
|
||||
PyObject* desc;
|
||||
PyObject* classification;
|
||||
time_t timestamp;
|
||||
|
||||
PyObject* ip_src_addr;
|
||||
PyObject* ip_dst_addr;
|
||||
unsigned short tcp_src_port;
|
||||
unsigned short tcp_dst_port;
|
||||
|
||||
double latitude;
|
||||
double longitude;
|
||||
|
||||
unsigned int clusteredAlertsCount;
|
||||
|
||||
struct _PyAlert *next;
|
||||
} PyAlert;
|
||||
|
||||
#endif
|
||||
/*****************************************************************/
|
||||
|
||||
|
||||
/** Enumeration for describing the table in the output database */
|
||||
|
@ -585,7 +638,7 @@ void AI_pkt_enqueue ( SFSnortPacket* );
|
|||
void AI_set_stream_observed ( struct pkt_key key );
|
||||
void AI_hierarchies_build ( hierarchy_node**, int );
|
||||
void AI_free_alerts ( AI_snort_alert *node );
|
||||
void AI_init_corr_modules ();
|
||||
void AI_init_corr_modules ( void );
|
||||
|
||||
struct pkt_info* AI_get_stream_by_key ( struct pkt_key );
|
||||
AI_snort_alert* AI_get_alerts ( void );
|
||||
|
@ -594,32 +647,40 @@ AI_snort_alert* AI_get_clustered_alerts ( void );
|
|||
void AI_serialize_alerts ( AI_snort_alert**, unsigned int );
|
||||
void AI_serializer ( AI_snort_alert* );
|
||||
|
||||
void* AI_deserialize_alerts ();
|
||||
void* AI_deserialize_alerts ( void );
|
||||
void* AI_alerts_pool_thread ( void* );
|
||||
void* AI_neural_thread ( void* );
|
||||
void* AI_manual_correlations_parsing_thread ( void* );
|
||||
void* AI_neural_clustering_thread ( void* );
|
||||
|
||||
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 ( void );
|
||||
|
||||
double AI_alert_bayesian_correlation ( const AI_snort_alert*, const AI_snort_alert* );
|
||||
double AI_alert_neural_som_correlation ( const AI_snort_alert*, const AI_snort_alert* );
|
||||
double AI_kb_correlation_coefficient ( const AI_snort_alert*, const AI_snort_alert* );
|
||||
|
||||
double AI_neural_correlation_weight ();
|
||||
double AI_bayesian_correlation_weight ();
|
||||
double AI_neural_correlation_weight ( void );
|
||||
double AI_bayesian_correlation_weight ( void );
|
||||
int AI_geoinfobyaddr ( const char*, double** );
|
||||
|
||||
void AI_outdb_mutex_initialize ();
|
||||
void AI_outdb_mutex_initialize ( void );
|
||||
void AI_store_alert_to_db ( AI_snort_alert* );
|
||||
void AI_store_cluster_to_db ( AI_alerts_couple* );
|
||||
void AI_store_correlation_to_db ( AI_alert_correlation* );
|
||||
void AI_kb_index_init ( AI_snort_alert* );
|
||||
AI_alerts_per_neuron* AI_get_alerts_per_neuron ();
|
||||
AI_alerts_per_neuron* AI_get_alerts_per_neuron ( void );
|
||||
|
||||
double(**AI_get_corr_functions ( size_t* ))(const AI_snort_alert*, const AI_snort_alert*);
|
||||
double(**AI_get_corr_weights ( size_t* ))();
|
||||
double(**AI_get_corr_weights ( size_t* ))( void );
|
||||
|
||||
#ifdef HAVE_LIBPYTHON2_6
|
||||
|
||||
PyObject** AI_get_py_functions ( size_t* );
|
||||
PyObject** AI_get_py_weights ( size_t* );
|
||||
PyAlert* AI_alert_to_pyalert ( AI_snort_alert* );
|
||||
|
||||
#endif
|
||||
|
||||
/** Function pointer to the function used for getting the alert list (from log file, db, ...) */
|
||||
extern AI_snort_alert* (*get_alerts)(void);
|
||||
|
|
|
@ -385,6 +385,8 @@ __AI_webservlet_thread ( void *arg )
|
|||
strncpy ( content_type, "application/x-javascript", sizeof ( content_type ));
|
||||
} else if ( !strcasecmp ( extension, "json" )) {
|
||||
strncpy ( content_type, "application/json", sizeof ( content_type ));
|
||||
} else if ( !strcasecmp ( extension, "xml" )) {
|
||||
strncpy ( content_type, "application/xml", sizeof ( content_type ));
|
||||
} else if ( !strcasecmp ( extension, "jpg" ) || !strcasecmp ( extension, "jpeg" )) {
|
||||
strncpy ( content_type, "image/jpeg", sizeof ( content_type ));
|
||||
} else if ( !strcasecmp ( extension, "cgi" )) {
|
||||
|
|
Loading…
Reference in a new issue