From e406b637f0ef3a9df53690e2a2346490c77ec312 Mon Sep 17 00:00:00 2001 From: BlackLight Date: Fri, 4 Feb 2011 00:43:59 +0100 Subject: [PATCH] Python module rewritten in pure Python --- README | 27 ++++++------ corr_modules/example.py | 28 ------------- corr_modules/example_module.py | 34 +++++++++++++++ correlation.c | 7 ++-- modules.c | 62 ++++++++++++++++++--------- pymodule/README | 3 +- pymodule/module.py | 21 ---------- pymodule/setup.py | 25 +---------- pymodule/snortai/__init__.py | 57 +++++++++++++++++++++++++ pymodule/snortai_module.c | 6 +++ pymodule/test.py | 8 ++++ spp_ai.h | 76 +++++++++------------------------- 12 files changed, 190 insertions(+), 164 deletions(-) delete mode 100644 corr_modules/example.py create mode 100644 corr_modules/example_module.py delete mode 100644 pymodule/module.py create mode 100644 pymodule/snortai/__init__.py create mode 100644 pymodule/test.py diff --git a/README b/README index 6841851..961845a 100644 --- a/README +++ b/README @@ -582,15 +582,16 @@ libsf_ai_preproc.la if you want to use some of the functions from the module, 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 +'example_module.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 @@ -604,10 +605,10 @@ 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. +The fields in the alert class can be viewed in +pymodule/test.py and corr_modules/example_module.py examples. Take these +files as guides for interfacing your Python scripts with SnortAI module +or writing new correlation modules in Python. =========================== diff --git a/corr_modules/example.py b/corr_modules/example.py deleted file mode 100644 index b407fc7..0000000 --- a/corr_modules/example.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/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 - diff --git a/corr_modules/example_module.py b/corr_modules/example_module.py new file mode 100644 index 0000000..ea8acd7 --- /dev/null +++ b/corr_modules/example_module.py @@ -0,0 +1,34 @@ +#!/usr/bin/python + +# Example correlation index in Python +# It simply does nothing (both the correlation index +# and the correlation weight are zero), use it as +# track for writing your own correlation modules + +# Go to pymodule and run +# $ python setup.py build +# $ [sudo] python setup.py install +# in order to build and install the snortai Python module +import snortai + +# Function that takes two alerts as arguments (arguments of +# alert object: +# id, gid, sid, rev, description, priority, classification, +# timestamp, src_addr, dst_addr, src_port, dst_port, latitude, +# longitude) and returns a correlation index between 0 and 1 +# expressing how correlated these two alerts are + +def AI_corr_index ( alert1, alert2 ): + # alerts = snortai.alerts() + # for alert in alerts: + # do_something + # + # print alert1.gid, alert1.sid, alert1.rev + # print alert2.gid, alert2.sid, alert2.rev + return 0.0 + +# Return the weight of this index, between 0 and 1 + +def AI_corr_index_weight(): + return 0.0 + diff --git a/correlation.c b/correlation.c index 3c28052..375ba95 100644 --- a/correlation.c +++ b/correlation.c @@ -385,8 +385,8 @@ AI_alert_correlation_thread ( void *arg ) double (**corr_weights)() = NULL; #ifdef HAVE_LIBPYTHON2_6 - PyAlert *pyA = NULL, - *pyB = NULL; + PyObject *pyA = NULL, + *pyB = NULL; PyObject *pArgs = NULL, *pRet = NULL; @@ -556,7 +556,8 @@ AI_alert_correlation_thread ( void *arg ) } } - free ( pyA ); free ( pyB ); + Py_DECREF ( pyA ); Py_DECREF ( pyB ); + /* free ( pyA ); free ( pyB ); */ pyA = NULL; pyB = NULL; } } diff --git a/modules.c b/modules.c index 1f183b5..46cdc0b 100644 --- a/modules.c +++ b/modules.c @@ -99,37 +99,61 @@ AI_get_py_weights ( size_t *n_functions ) /** * \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 + * \return A PyObject object wrapping the original AI_snort_alert object */ -PyAlert* +PyObject* AI_alert_to_pyalert ( AI_snort_alert *alert ) { - PyAlert *pyalert = NULL; + PyObject *pyalert = NULL; + + PyObject *pMod = NULL, + *pObj = NULL, + *pArgs = NULL; + char src_addr[INET_ADDRSTRLEN] = { 0 }, dst_addr[INET_ADDRSTRLEN] = { 0 }; - if ( !( pyalert = (PyAlert*) malloc ( sizeof ( PyAlert )))) + if ( !( pMod = PyImport_ImportModule ( "snortai" ))) { - AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ ); + PyErr_Print(); + AI_fatal_err ( "Could not load Python module 'snortai'", __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 ); + if ( !( pObj = PyObject_GetAttrString ( pMod, "alert" ))) + { + PyErr_Print(); + AI_fatal_err ( "'alert' object not found in the Python module 'snortai'", __FILE__, __LINE__ ); + } - 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; + Py_DECREF ( pMod ); + if ( !( pArgs = Py_BuildValue ( "(OOOOOOOOOOOOO)", + Py_None, + PyLong_FromUnsignedLong ( alert->gid ), + PyLong_FromUnsignedLong ( alert->sid ), + PyLong_FromUnsignedLong ( alert->rev ), + PyLong_FromUnsignedLong ((long int) alert->priority ), + alert->classification ? PyString_FromString ( alert->classification ) : Py_None, + alert->desc ? PyString_FromString ( alert->desc ) : Py_None, + PyString_FromString ( src_addr ), + PyString_FromString ( dst_addr ), + PyLong_FromLong ((long int) ntohs ( alert->tcp_src_port )), + PyLong_FromLong ((long int) ntohs ( alert->tcp_dst_port )), + Py_None, + Py_None ))) + { + PyErr_Print(); + AI_fatal_err ( "Could not initialize the argument list for calling the Python 'alert' constructor", __FILE__, __LINE__ ); + } + + if ( !( pyalert = PyObject_CallObject ( pObj, pArgs ))) + { + PyErr_Print(); + AI_fatal_err ( "Could not call the constructor over the Python object 'alert'", __FILE__, __LINE__ ); + } + + Py_DECREF ( pArgs ); Py_DECREF ( pObj ); return pyalert; } /* ----- end of function AI_alert_to_pyalert ----- */ #endif diff --git a/pymodule/README b/pymodule/README index 7b4ca19..a91a39f 100644 --- a/pymodule/README +++ b/pymodule/README @@ -12,9 +12,10 @@ alerts = snortai.alerts() for alert in alerts: # Access the information + print alert.gid, alert.sid, alert.rev 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 +# src_addr, dst_addr, src_port, dst_port, latitude, longitude diff --git a/pymodule/module.py b/pymodule/module.py deleted file mode 100644 index 9cbcba7..0000000 --- a/pymodule/module.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/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 - diff --git a/pymodule/setup.py b/pymodule/setup.py index e2f60aa..e2553df 100644 --- a/pymodule/setup.py +++ b/pymodule/setup.py @@ -1,20 +1,6 @@ -#!/usr/bin/python +#!/usr/bin/env 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', @@ -22,13 +8,6 @@ setup ( 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] - ) - ] + packages = ['snortai'] ) diff --git a/pymodule/snortai/__init__.py b/pymodule/snortai/__init__.py new file mode 100644 index 0000000..fcccf10 --- /dev/null +++ b/pymodule/snortai/__init__.py @@ -0,0 +1,57 @@ +#!/usr/bin/python + +import urllib +import xml.dom.minidom as xml + +class alert: + """Class that models a Snort alert type""" + def __init__ ( self, id = None, gid = None, sid = None, rev = None, + priority = None, classification = None, description = None, + src_addr = None, dst_addr = None, src_port = None, dst_port = None, + latitude = None, longitude = None, ): + self.id = id + self.gid = gid + self.sid = sid + self.rev = rev + self.priority = priority + self.latitude = latitude + self.longitude = longitude + self.description = description + self.classification = classification + self.src_addr = src_addr + self.dst_addr = dst_addr + self.src_port = src_port + self.dst_port = dst_port + +resource_url = 'http://localhost:7654/alerts.cgi' +response_text = None; + +def alerts(): + url = urllib.urlopen ( resource_url ) + response_text = url.read() + document = xml.parseString ( response_text ) + alerts = [] + + for element in document.getElementsByTagName ( 'alert' ): + a = alert() + + for attr in element.attributes.keys(): + if attr in ['id', 'gid', 'sid', 'rev', 'priority', 'latitude', 'longitude', 'classification']: + setattr ( a, attr, element.attributes[attr].value ) + elif attr == 'date': + setattr ( a, 'timestamp', element.attributes[attr].value ) + elif attr == 'label': + setattr ( a, 'description', element.attributes[attr].value ) + elif attr == 'from': + setattr ( a, 'src_addr', element.attributes[attr].value ) + elif attr == 'to': + setattr ( a, 'dst_addr', element.attributes[attr].value ) + elif attr == 'from_port': + setattr ( a, 'src_port', element.attributes[attr].value ) + elif attr == 'to_port': + setattr ( a, 'dst_port', element.attributes[attr].value ) + + alerts.append ( a ) + + return alerts + diff --git a/pymodule/snortai_module.c b/pymodule/snortai_module.c index fa7b98c..28a718f 100644 --- a/pymodule/snortai_module.c +++ b/pymodule/snortai_module.c @@ -17,6 +17,12 @@ * ===================================================================================== */ +/* This is the old C-based module for Python interface to SnortAI + * and it is now completely *DEPRECATED* and kept only for + * back-compatibility purposes. Use the pure Python interface + * instead, running python setup.py build && sudo python setup.py install + * will build and install the new Python module */ + #ifndef HAVE_LIBPYTHON2_6 #define HAVE_LIBPYTHON2_6 1 #endif diff --git a/pymodule/test.py b/pymodule/test.py new file mode 100644 index 0000000..56e9ed8 --- /dev/null +++ b/pymodule/test.py @@ -0,0 +1,8 @@ +#!/usr/bin/python + +import snortai + +alerts = snortai.alerts() + +for alert in alerts: + print alert.gid, alert.sid, alert.rev diff --git a/spp_ai.h b/spp_ai.h index 7b1f166..2ebd73b 100644 --- a/spp_ai.h +++ b/spp_ai.h @@ -31,6 +31,25 @@ #include #include +/*******************************************/ +#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 +#endif +/*******************************************/ + #define PRIVATE static /** Default interval in seconds for the thread cleaning up TCP streams */ @@ -543,61 +562,6 @@ 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 - -/** 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 */ enum { ALERTS_TABLE, IPV4_HEADERS_TABLE, TCP_HEADERS_TABLE, PACKET_STREAMS_TABLE, CLUSTERED_ALERTS_TABLE, CORRELATED_ALERTS_TABLE, N_TABLES }; @@ -678,7 +642,7 @@ double(**AI_get_corr_weights ( size_t* ))( void ); PyObject** AI_get_py_functions ( size_t* ); PyObject** AI_get_py_weights ( size_t* ); -PyAlert* AI_alert_to_pyalert ( AI_snort_alert* ); +PyObject* AI_alert_to_pyalert ( AI_snort_alert* ); #endif