Permalink
Browse files

updated: platypus plugin renamed to echidna and aligned to the new co…

…mmand and sumbmission protocols.
  • Loading branch information...
1 parent 8de8124 commit ae7c627ea2948d8884c020e46032e269c98441e2 @firnsy committed Nov 4, 2012
View
35 configure.in
@@ -1035,6 +1035,41 @@ if test "$with_tcl" != "no"; then
fi
fi
+#
+# OUTPUT PLUGIN - ECHIDNA
+
+AC_ARG_ENABLE(plugin-echidna,
+[ --enable-plugin-echidna Enable echidna plugin (experimental)],
+ enable_plugin_echidna="$enableval", enable_plugin_echidna="no")
+if test "x$enable_plugin_echidna" = "xyes"; then
+ CPPFLAGS="$CPPFLAGS -DENABLE_PLUGIN_ECHIDNA"
+ LIBS="$LIBS -lwebsockets -ljson -lcurl"
+
+ AC_CHECK_LIB(curl, curl_easy_setopt,, LCURL="no")
+ if test "x$LCURL" = "xno"; then
+ echo
+ echo " ERROR! libcurl not found!"
+ echo
+ exit 1
+ fi
+
+ AC_CHECK_LIB(websockets, libwebsocket_create_context,, LWEBSOCKETS="no")
+ if test "x$LWEBSOCKETS" = "xno"; then
+ echo
+ echo " ERROR! libwebsockets not found."
+ echo
+ exit 1
+ fi
+
+ AC_CHECK_LIB(json, json_tokener_parse,, LJSON="no")
+ if test "x$LJSON" = "xno"; then
+ echo
+ echo " ERROR! libjson not found."
+ echo
+ exit 1
+ fi
+
+fi
# let's make some fixes..
View
2 src/output-plugins/Makefile.am
@@ -19,8 +19,8 @@ spo_common.c spo_common.h \
spo_log_ascii.c spo_log_ascii.h \
spo_log_null.c spo_log_null.h \
spo_log_tcpdump.c spo_log_tcpdump.h \
-spo_platypus.c spo_platypus.h \
spo_sguil.c spo_sguil.h \
+spo_echidna.c spo_echidna.h \
spo_syslog_full.c spo_syslog.full.h \
spo_database.c spo_database.h \
spo_database_cache.c spo_database_cache.h
View
858 src/output-plugins/spo_echidna.c
@@ -0,0 +1,858 @@
+/*
+** Copyright (C) 2008-2012 Ian Firns (SecurixLive) <dev@securixlive.com>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License Version 2 as
+** published by the Free Software Foundation. You may not use, modify or
+** distribute this program under any other version of the GNU General
+** Public License.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+**
+*/
+
+/*
+** INCLUDES
+*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef ENABLE_PLUGIN_ECHIDNA
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <time.h>
+#include <errno.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <libwebsockets.h>
+#include <curl/curl.h>
+#include <json/json.h>
+#include <json/json_tokener.h>
+
+
+#include "barnyard2.h"
+#include "debug.h"
+#include "decode.h"
+#include "map.h"
+#include "mstring.h"
+#include "plugbase.h"
+#include "strlcpyu.h"
+#include "unified2.h"
+#include "util.h"
+
+
+typedef struct _SpoEchidnaData
+{
+ char *agent_name;
+ u_int16_t sensor_id;
+ int agent_sock;
+
+ u_int32_t event_id;
+
+ char *args;
+
+ char *node_address;
+ u_int16_t node_port;
+
+ int use_ssl;
+} SpoEchidnaData;
+
+static int session_state = 0;
+struct libwebsocket_context *context;
+static struct libwebsocket *wsi_echidna;
+
+static char *node_id;
+static char *session_key;
+static char *session_uri;
+
+
+enum echidna_protocols {
+ PROTOCOL_LWS_ECHIDNA,
+};
+
+/* constants */
+#define KEYWORD_NODEADDRESS "address"
+#define KEYWORD_NODEPORT "port"
+#define KEYWORD_NODENAME "name"
+#define KEYWORD_USESSL "ssl"
+
+#define DEFAULT_NODEADDRESS "127.0.0.1"
+#define DEFAULT_NODEPORT 6968
+
+#define MAX_MSG_LEN 2048
+#define TMP_BUFFER 128
+
+/* output plug-in API functions */
+void EchidnaInit(char *args);
+void EchidnaInitFinalize(int unused, void *arg);
+
+SpoEchidnaData *InitEchidnaData(char *);
+void ParseEchidnaArgs(SpoEchidnaData *spd_data);
+
+void EchidnaCleanExitFunc(int, void *);
+void EchidnaRestartFunc(int, void *);
+
+
+/* internal echidna functions */
+void Echidna(Packet *, void *, u_int32_t, void *);
+
+int EchidnaNodeConnect(SpoEchidnaData *);
+
+char *EchidnaTimestamp(u_int32_t, u_int32_t);
+
+int EchidnaEventIPHeaderDataAppend(json_object *, Packet *);
+int EchidnaEventICMPDataAppend(json_object *, Packet *);
+int EchidnaEventTCPDataAppend(json_object *, Packet *);
+int EchidnaEventUDPDataAppend(json_object *, Packet *);
+
+void EchidnaEventSubmit(SpoEchidnaData *, json_object *);
+
+
+
+static int
+callback_lws_mirror(struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len)
+{
+ unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 + LWS_SEND_BUFFER_POST_PADDING];
+ int l;
+ json_object *json;
+ char *key;
+ json_object *val;
+ struct lh_entry *entry;
+ enum json_type type;
+
+
+ switch (reason) {
+
+ case LWS_CALLBACK_CLOSED:
+ fprintf(stderr, "echidna: LWS_CALLBACK_CLOSED\n");
+ wsi_echidna = NULL;
+
+ /* session key is invalidated */
+ if( session_key != NULL )
+ free(session_key);
+
+ session_state = 0;
+
+ break;
+
+ case LWS_CALLBACK_CLIENT_ESTABLISHED:
+ /*
+ * start the ball rolling,
+ * LWS_CALLBACK_CLIENT_WRITEABLE will come next service
+ */
+ fprintf(stderr, "Connection established ...\n");
+
+ libwebsocket_callback_on_writable(this, wsi);
+ break;
+
+ case LWS_CALLBACK_CLIENT_RECEIVE:
+ fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in);
+
+
+ json = json_tokener_parse( in );
+
+ /* decode the message */
+
+ if( session_state == 0 )
+ {
+ for(entry = json_object_get_object(json)->head; ({ if(entry) { key = (char*)entry->k; val = (struct json_object*)entry->v; } ; entry; }); entry = entry->next )
+ {
+ type = json_object_get_type(val);
+ if( strncmp( key, "node_id", 7 ) == 0 && ( type == json_type_string ) )
+ {
+ /* cleanup previous value */
+ if( node_id != NULL )
+ free(node_id);
+
+ node_id = SnortStrdup( json_object_get_string(val) );
+
+ fprintf(stderr, "NODE ID: %s\n", node_id);
+ }
+ else if( strncmp( key, "session_key", 11 ) == 0 && ( type == json_type_string ) )
+ {
+ /* cleanup previous value */
+ if( session_key != NULL )
+ free(session_key);
+
+ session_key = SnortStrdup( json_object_get_string(val) );
+ fprintf(stderr, "SESSION KEY: %s\n", session_key);
+ }
+ else if( strncmp( key, "session_uri", 11 ) == 0 && ( type == json_type_string ) )
+ {
+ /* cleanup previous value */
+ if( session_uri != NULL )
+ free(session_uri);
+
+ session_uri = SnortStrdup( json_object_get_string(val) );
+ fprintf(stderr, "SESSION URI: %s\n", session_uri);
+ }
+ }
+
+ /* determine if a session is active */
+ if( ( node_id != NULL ) &&
+ ( session_key != NULL ) &&
+ ( session_uri != NULL ) )
+ {
+ session_state = 1;
+ }
+ }
+
+ json_object_put(json);
+
+ break;
+
+ case LWS_CALLBACK_CLIENT_WRITEABLE:
+ if( session_state == 0 )
+ {
+ /* send our auth request */
+ l = sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING], "{\"type\":\"by2_auth_request\",\"key\":\"password\"}");
+ libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], l, LWS_WRITE_TEXT);
+ }
+
+ /* get notified as soon as we can write again */
+ libwebsocket_callback_on_writable(this, wsi);
+
+ usleep(200);
+ break;
+
+ case LWS_CALLBACK_ESTABLISHED:
+ fprintf(stderr, " LWS_CALLBACK_ESTABLISHED\n");
+ break;
+ case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+ fprintf(stderr, " LWS_CALLBACK_CLIENT_CONNECTION_ERROR\n");
+ break;
+ case LWS_CALLBACK_RECEIVE:
+ fprintf(stderr, " LWS_CALLBACK_RECEIVE\n");
+ break;
+ case LWS_CALLBACK_CLIENT_RECEIVE_PONG:
+ fprintf(stderr, " LWS_CALLBACK_CLIENT_RECEIVE_PONG\n");
+ break;
+ case LWS_CALLBACK_SERVER_WRITEABLE:
+ fprintf(stderr, " LWS_CALLBACK_SERVER_WRITEABLE\n");
+ break;
+ case LWS_CALLBACK_HTTP:
+ fprintf(stderr, " LWS_CALLBACK_HTTP\n");
+ break;
+ case LWS_CALLBACK_BROADCAST:
+ fprintf(stderr, " LWS_CALLBACK_BROADCAST\n");
+ break;
+ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
+ fprintf(stderr, " LWS_CALLBACK_FILTER_NETWORK_CONNECTION\n");
+ break;
+ case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
+ fprintf(stderr, " LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION\n");
+ break;
+ case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS:
+ fprintf(stderr, " LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS\n");
+ break;
+ case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS:
+ fprintf(stderr, " LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS\n");
+ break;
+ case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION:
+ fprintf(stderr, " LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION\n");
+ break;
+ case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
+ fprintf(stderr, " LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER\n");
+ break;
+ case LWS_CALLBACK_CONFIRM_EXTENSION_OKAY:
+ fprintf(stderr, " LWS_CALLBACK_CONFIRM_EXTENSION_OKAY\n");
+ break;
+ case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:
+ fprintf(stderr, " LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED\n");
+ break;
+
+ case LWS_CALLBACK_ADD_POLL_FD:
+ case LWS_CALLBACK_DEL_POLL_FD:
+ case LWS_CALLBACK_SET_MODE_POLL_FD:
+ case LWS_CALLBACK_CLEAR_MODE_POLL_FD:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+/* list of supported protocols and callbacks */
+struct libwebsocket_protocols protocols[] = {
+ {
+ "lws-mirror-protocol",
+ callback_lws_mirror,
+ 0,
+ },
+ {
+ NULL,
+ NULL,
+ 0
+ }
+};
+
+
+/* init routine makes this processor available for dataprocessor directives */
+void EchidnaSetup()
+{
+ /* link the preprocessor keyword to the init function in
+ the preproc list */
+ RegisterOutputPlugin("echidna", OUTPUT_TYPE_FLAG__ALERT, EchidnaInit);
+
+ DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Output: Echidna is setup\n"););
+}
+
+void EchidnaInit(char *args)
+{
+ SpoEchidnaData *spd_data;
+
+ DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Output: Echidna initialized\n"););
+
+ /* parse the argument list from the rules file`*/
+ spd_data = InitEchidnaData(args);
+
+ AddFuncToPostConfigList(EchidnaInitFinalize, spd_data);
+}
+
+SpoEchidnaData *InitEchidnaData(char *args)
+{
+ SpoEchidnaData *data;
+
+ /* setup the internal structures and parse any arguments */
+ data = (SpoEchidnaData *)SnortAlloc(sizeof(SpoEchidnaData));
+
+ /* store args for later parsing */
+ if( args != NULL )
+ data->args = SnortStrdup(args);
+
+ return data;
+}
+
+void EchidnaInitFinalize(int unused, void *arg)
+{
+ SpoEchidnaData *spd_data = (SpoEchidnaData *)arg;
+
+ if( spd_data == NULL )
+ FatalError("echidna: data uninitialized\n");
+
+ ParseEchidnaArgs(spd_data);
+
+ /* identify the agent_name */
+ if( spd_data->agent_name == NULL )
+ spd_data->agent_name = SnortStrdup(GetUniqueName(PRINT_INTERFACE(barnyard2_conf->interface)));
+
+ if( spd_data->node_address == NULL )
+ spd_data->node_address = SnortStrdup(DEFAULT_NODEADDRESS);
+
+ if( ! BcLogQuiet() )
+ {
+ LogMessage("echidna: host = %s\n", spd_data->node_address);
+ LogMessage("echidna: port = %u\n", spd_data->node_port);
+ }
+
+ /* connect to the sensor agent (SnortAgent) */
+ if( EchidnaNodeConnect(spd_data) == 0 )
+ {
+ /* initialise the sensor agent - get sid/eid */
+ if( BcLogVerbose() )
+ LogMessage("echidna: waiting for sid/eid from Node.\n");
+
+ }
+ else
+ FatalError("echidna: unable to connect to agent\n");
+
+ /* in windows, this will init the winsock stuff */
+ curl_global_init(CURL_GLOBAL_ALL);
+
+ /* set the preprocessor function into the function list */
+ AddFuncToOutputList(Echidna, OUTPUT_TYPE__ALERT, spd_data);
+ AddFuncToCleanExitList(EchidnaCleanExitFunc, spd_data);
+ AddFuncToRestartList(EchidnaRestartFunc, spd_data);
+}
+
+void Echidna(Packet *p, void *event, u_int32_t event_type, void *arg)
+{
+ json_object *json;
+
+ char *data_msg;
+
+ char sip4[INET_ADDRSTRLEN];
+ char dip4[INET_ADDRSTRLEN];
+ char sip6[INET6_ADDRSTRLEN];
+ char dip6[INET6_ADDRSTRLEN];
+
+ SpoEchidnaData *data;
+ SigNode *sn = NULL;
+ ClassType *cn = NULL;
+
+ if( event == NULL || arg == NULL )
+ return;
+
+ data = (SpoEchidnaData *)arg;
+
+ /* grab the appropriate signature and classification information */
+ sn = GetSigByGidSid(ntohl(((Unified2EventCommon *)event)->generator_id),
+ ntohl(((Unified2EventCommon *)event)->signature_id));
+ cn = ClassTypeLookupById(barnyard2_conf, ntohl(((Unified2EventCommon *)event)->classification_id));
+
+ /* initialise our json object */
+ json = json_object_new_object();
+
+ json_object_object_add(json, "node_id", json_object_new_string(node_id));
+ json_object_object_add(json, "meta_u2_event_id", json_object_new_int( ntohl(((Unified2EventCommon *)event)->event_id) ));
+
+ /* snort event reference time */
+ json_object_object_add(json, "timestamp", json_object_new_string(
+ EchidnaTimestamp(
+ ntohl(((Unified2EventCommon *)event)->event_second),
+ ntohl(((Unified2EventCommon *)event)->event_microsecond)
+ )
+ ));
+
+ /* generator ID */
+ json_object_object_add(json, "sig_type", json_object_new_int( ntohl(((Unified2EventCommon *)event)->generator_id) ));
+
+ /* signature ID */
+ json_object_object_add(json, "sig_id,", json_object_new_int( ntohl(((Unified2EventCommon *)event)->signature_id) ));
+
+ /* signature revision */
+ json_object_object_add(json, "sig_rev", json_object_new_int( ntohl(((Unified2EventCommon *)event)->signature_revision) ));
+
+ /* signature message */
+ json_object_object_add(json, "sig_message", json_object_new_string( sn->msg ));
+
+ /* alert priority */
+ json_object_object_add(json, "sig_priority", json_object_new_int( ntohl(((Unified2EventCommon *)event)->priority_id) ));
+
+ /* alert classification */
+ json_object_object_add(json, "sig_category", json_object_new_string( cn != NULL ? cn->type : "unknown" ));
+
+ /* IP version, addresses, ports and protocol */
+ switch( event_type )
+ {
+ case UNIFIED2_IDS_EVENT:
+ case UNIFIED2_IDS_EVENT_MPLS:
+ case UNIFIED2_IDS_EVENT_VLAN:
+ inet_ntop(AF_INET, &((Unified2IDSEvent*)event)->ip_source, sip4, INET_ADDRSTRLEN);
+ inet_ntop(AF_INET, &((Unified2IDSEvent*)event)->ip_destination, dip4, INET_ADDRSTRLEN);
+
+ json_object_object_add(json, "net_version", json_object_new_int( 4 ));
+ json_object_object_add(json, "net_src_ip", json_object_new_string( sip4 ));
+ json_object_object_add(json, "net_src_port", json_object_new_int( ntohs(((Unified2IDSEvent *)event)->sport_itype) ));
+ json_object_object_add(json, "net_dst_ip", json_object_new_string( sip4 ));
+ json_object_object_add(json, "net_dst_port", json_object_new_int( ntohs(((Unified2IDSEvent *)event)->dport_icode) ));
+ json_object_object_add(json, "net_version", json_object_new_int( ((Unified2IDSEvent *)event)->protocol ));
+ break;
+ case UNIFIED2_IDS_EVENT_IPV6:
+ case UNIFIED2_IDS_EVENT_IPV6_MPLS:
+ case UNIFIED2_IDS_EVENT_IPV6_VLAN:
+ inet_ntop(AF_INET6, &((Unified2IDSEventIPv6 *)event)->ip_source, sip6, INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET6, &((Unified2IDSEventIPv6 *)event)->ip_destination, dip6, INET6_ADDRSTRLEN);
+
+ json_object_object_add(json, "net_version", json_object_new_int( 6 ));
+ json_object_object_add(json, "net_src_ip", json_object_new_string( sip6 ));
+ json_object_object_add(json, "net_src_port", json_object_new_int( ntohs(((Unified2IDSEventIPv6 *)event)->sport_itype) ));
+ json_object_object_add(json, "net_dst_ip", json_object_new_string( sip6 ));
+ json_object_object_add(json, "net_dst_port", json_object_new_int( ntohs(((Unified2IDSEventIPv6 *)event)->dport_icode) ));
+ json_object_object_add(json, "net_version", json_object_new_int( ((Unified2IDSEventIPv6 *)event)->protocol ));
+ break;
+ }
+
+ /* pull decoded info from the packet */
+ if( p != NULL )
+ {
+ if( p->iph != NULL )
+ {
+ /* add IP header */
+ EchidnaEventIPHeaderDataAppend(json, p);
+
+ /* add ICMP || UDP || TCP data */
+ if( ! (p->packet_flags & PKT_REBUILT_FRAG) )
+ {
+ switch( p->iph->ip_proto )
+ {
+ case IPPROTO_ICMP:
+ EchidnaEventICMPDataAppend(json, p);
+ break;
+
+ case IPPROTO_TCP:
+ EchidnaEventTCPDataAppend(json, p);
+ break;
+
+ case IPPROTO_UDP:
+ EchidnaEventUDPDataAppend(json, p);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ /* add payload data */
+ if( p->dsize )
+ {
+ data_msg = fasthex(p->data, p->dsize);
+ if( data_msg != NULL )
+ {
+ json_object_object_add(json, "payload", json_object_new_string( data_msg ));
+ free(data_msg);
+ }
+ }
+ }
+
+ /* send msg to sensor_agent */
+ EchidnaEventSubmit(data, json);
+ json_object_put( json );
+}
+
+int EchidnaEventIPHeaderDataAppend(json_object *json, Packet *p)
+{
+ json_object_object_add(json, "ip_hdr_hlen", json_object_new_int( IP_HLEN(p->iph) ));
+ json_object_object_add(json, "ip_hdr_tos", json_object_new_int( p->iph->ip_tos ));
+ json_object_object_add(json, "ip_hdr_len", json_object_new_int( p->iph->ip_len ));
+ json_object_object_add(json, "ip_hdr_id", json_object_new_int( p->iph->ip_id ));
+
+#if defined(WORDS_BIGENDIAN)
+ json_object_object_add(json, "ip_hdr_id", json_object_new_int( ((p->iph->ip_off & 0xe000) >> 13) ));
+ json_object_object_add(json, "ip_hdr_id", json_object_new_int( htons(p->iph->ip_off & 0x1fff) ));
+#else
+ json_object_object_add(json, "ip_hdr_id", json_object_new_int( ((p->iph->ip_off & 0x00e0) >> 5) ));
+ json_object_object_add(json, "ip_hdr_id", json_object_new_int( htons(p->iph->ip_off & 0xff1f) ));
+#endif
+
+ json_object_object_add(json, "ip_hdr_ttl", json_object_new_int( p->iph->ip_ttl) );
+ json_object_object_add(json, "ip_hdr_csum", json_object_new_int( htons(p->iph->ip_csum) ));
+
+ return 0;
+}
+
+int EchidnaEventICMPDataAppend(json_object *json, Packet *p)
+{
+ {
+ /* ICMP checksum */
+ json_object_object_add(json, "icmp_csum", json_object_new_int( ntohs(p->icmph->csum) ));
+
+ /* Append other ICMP data if we have it */
+ if( p->icmph->type == ICMP_ECHOREPLY || p->icmph->type == ICMP_ECHO ||
+ p->icmph->type == ICMP_TIMESTAMP || p->icmph->type == ICMP_TIMESTAMPREPLY ||
+ p->icmph->type == ICMP_INFO_REQUEST || p->icmph->type == ICMP_INFO_REPLY )
+ {
+ /* ICMP ID */
+ json_object_object_add(json, "icmp_id", json_object_new_int( htonl(p->icmph->icmp_hun.idseq.id) ));
+
+ /* ICMP sequence */
+ json_object_object_add(json, "icmp_seq", json_object_new_int( htonl(p->icmph->icmp_hun.idseq.id) ));
+ }
+ }
+
+ return 0;
+}
+
+int EchidnaEventTCPDataAppend(json_object *json, Packet *p)
+{
+ json_object_object_add(json, "tcp_seq", json_object_new_int( ntohl(p->tcph->th_seq) ));
+ json_object_object_add(json, "tcp_ack", json_object_new_int( ntohl(p->tcph->th_ack) ));
+ json_object_object_add(json, "tcp_off", json_object_new_int( TCP_OFFSET(p->tcph) ));
+ json_object_object_add(json, "tcp_x2", json_object_new_int( TCP_X2(p->tcph) ));
+ json_object_object_add(json, "tcp_flags", json_object_new_int( p->tcph->th_flags ));
+ json_object_object_add(json, "tcp_win", json_object_new_int( ntohl(p->tcph->th_win) ));
+ json_object_object_add(json, "tcp_sum", json_object_new_int( ntohl(p->tcph->th_sum) ));
+ json_object_object_add(json, "tcp_urp", json_object_new_int( ntohl(p->tcph->th_urp) ));
+
+ return 0;
+}
+
+int EchidnaEventUDPDataAppend(json_object *json, Packet *p)
+{
+ json_object_object_add(json, "udp_len", json_object_new_int( ntohs(p->udph->uh_len) ));
+ json_object_object_add(json, "udp_chk", json_object_new_int( ntohs(p->udph->uh_chk) ));
+
+ return 0;
+}
+
+int EchidnaNodeConnect(SpoEchidnaData *spd_data)
+{
+ int ws_ret;
+ int tries = 10;
+
+ DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "echidna: creating context ... \n"););
+
+ /* create the websockt context */
+ context = libwebsocket_create_context(
+ CONTEXT_PORT_NO_LISTEN,
+ NULL,
+ protocols,
+ libwebsocket_internal_extensions,
+ NULL,
+ NULL,
+ -1,
+ -1,
+ 0,
+ NULL
+ );
+
+ if (context == NULL)
+ {
+ FatalError("echidna: unable to create websocket context.\n");
+ }
+
+ DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "echidna: context created: %s %d %d %s\n",
+ spd_data->node_address,
+ spd_data->node_port,
+ spd_data->use_ssl,
+ protocols[PROTOCOL_LWS_ECHIDNA].name
+ ););
+
+
+ /* loop until we have a session key */
+ while( exit_signal == 0 && session_state == 0 && ws_ret >= 0 )
+ {
+ if (wsi_echidna == NULL)
+ {
+ /* create a client websocket using mirror protocol */
+ wsi_echidna = libwebsocket_client_connect(
+ context,
+ spd_data->node_address,
+ spd_data->node_port,
+ spd_data->use_ssl,
+ "/control",
+ spd_data->node_address,
+ spd_data->node_address,
+ protocols[PROTOCOL_LWS_ECHIDNA].name,
+ -1 // latest
+ );
+
+ DEBUG_WRAP(DebugMessage(DEBUG_LOG,"echidna: websocket connection opened."););
+
+ if ( wsi_echidna == NULL ) {
+ sleep(15);
+ if( BcTestMode() && --tries < 0 )
+ FatalError("echidna: failed to connect after 10 attempts.\n");
+ }
+
+ }
+ else
+ {
+ ws_ret = libwebsocket_service(context, 1000);
+ usleep(100000);
+ }
+ }
+
+ return ( session_state == 1 ) ? 0 : 1;
+}
+
+size_t _curl_dummy_write(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+ return size * nmemb;
+}
+
+/*
+ * Function: void EchidnaEventSubmit(SpoEchidnaData *spd_data, char *msg)
+ *
+ * Purpose: Submit the JSON event structure to the REST node.
+ *
+ * Arguments: args => argument list
+ *
+ * Returns: void function
+ *
+ */
+void EchidnaEventSubmit(SpoEchidnaData *spd_data, json_object *json)
+{
+ CURL *curl;
+ CURLcode res;
+ long rc = 0;
+
+ /* get a curl handle */
+ curl = curl_easy_init();
+
+ if(curl)
+ {
+ fprintf(stderr, "submitting %s => %s failed\n", session_uri, json_object_to_json_string( json ));
+
+ curl_easy_setopt(curl, CURLOPT_URL, session_uri);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_object_to_json_string( json ) );
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &_curl_dummy_write);
+
+ while( rc != 200 )
+ {
+ if( ( res = curl_easy_perform(curl) ) == CURLE_OK )
+ {
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &rc);
+ fprintf(stderr, "RC: %lu\n", rc);
+ }
+ else if( rc == 403 )
+ {
+ fprintf(stderr, "forbidden. TODO: reconnect\n");
+ }
+ else
+ {
+ fprintf(stderr, "curl_easy_perform() failed: %s\n",
+ curl_easy_strerror(res));
+ }
+
+ sleep(15);
+ }
+
+ fprintf(stderr, "cleaning up curl\n");
+
+ /* always cleanup */
+ curl_easy_cleanup(curl);
+ }
+}
+
+
+/*
+ * Function: ParseEchidnaArgs(char *)
+ *
+ * Purpose: Process the preprocessor arguements from the rules file and
+ * initialize the preprocessor's data struct. This function doesn't
+ * have to exist if it makes sense to parse the args in the init
+ * function.
+ *
+ * Arguments: args => argument list
+ *
+ * Returns: void function
+ *
+ */
+void ParseEchidnaArgs(SpoEchidnaData *spd_data)
+{
+ char **toks;
+ int num_toks;
+ int i;
+
+ /* initialise appropariate values to defaults */
+ spd_data->node_port = DEFAULT_NODEPORT;
+ spd_data->use_ssl = 0;
+
+ if( spd_data->args == NULL )
+ {
+ //FatalError("echidna: you must supply arguments for echidna plugin.\n");
+ return;
+ }
+
+ /* parse out the args */
+ toks = mSplit(spd_data->args, ", ", 31, &num_toks, '\\');
+
+ for( i=0; i<num_toks; ++i )
+ {
+ char **stoks;
+ int num_stoks;
+ char *index = toks[i];
+
+ while( isspace((int)*index) )
+ ++index;
+
+ stoks = mSplit(index, "=", 2, &num_stoks, 0);
+
+ if( !strncasecmp(stoks[0], KEYWORD_NODEPORT, strlen(KEYWORD_NODEPORT)) )
+ {
+ if( num_stoks > 1 )
+ spd_data->node_port = atoi(stoks[1]);
+ else
+ LogMessage("echidna: node_port error\n");
+ }
+ else if( !strncasecmp(stoks[0], KEYWORD_NODEADDRESS, strlen(KEYWORD_NODEADDRESS)) )
+ {
+ if( num_stoks > 1 && spd_data->node_address == NULL )
+ spd_data->agent_name = SnortStrdup(stoks[1]);
+ else
+ LogMessage("echidna: node_address error\n");
+ }
+ else if( !strncasecmp(stoks[0], KEYWORD_NODENAME, strlen(KEYWORD_NODENAME)) )
+ {
+ if( num_stoks > 1 && spd_data->agent_name == NULL )
+ spd_data->agent_name = SnortStrdup(stoks[1]);
+ else
+ LogMessage("echidna: agent_name error\n");
+ }
+ else
+ {
+ FatalError("echidna: unrecognised plugin argument \"%s\"!\n", index);
+ }
+
+ /* free your mSplit tokens */
+ mSplitFree(&stoks, num_stoks);
+ }
+
+ /* free your mSplit tokens */
+ mSplitFree(&toks, num_toks);
+}
+
+char *EchidnaTimestamp(u_int32_t sec, u_int32_t usec)
+{
+ struct tm *lt; /* localtime */
+ char *buf;
+ time_t time = sec;
+
+ buf = (char *)SnortAlloc(TMP_BUFFER * sizeof(char));
+
+ if( BcOutputUseUtc() )
+ lt = gmtime(&time);
+ else
+ lt = localtime(&time);
+
+ SnortSnprintf(buf, TMP_BUFFER, "%04i-%02i-%02i %02i:%02i:%02i.%06i",
+ 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday,
+ lt->tm_hour, lt->tm_min, lt->tm_sec, usec);
+
+ return buf;
+}
+
+void EchidnaClose(void *arg)
+{
+ SpoEchidnaData *spd_data = (SpoEchidnaData *)arg;
+
+ /* free allocated memory from SpoEchidnaData */
+ if( spd_data != NULL )
+ {
+
+ fprintf(stderr, "Exiting\n");
+
+
+
+ if( spd_data->agent_name )
+ free(spd_data->agent_name);
+
+ if( spd_data->args )
+ free(spd_data->args);
+
+ free(spd_data);
+ }
+
+ /* cleanup the websocket contexts */
+ libwebsocket_close_and_free_session(context, wsi_echidna, LWS_CLOSE_STATUS_GOINGAWAY);
+ libwebsocket_context_destroy(context);
+
+ /* clean up curl */
+ curl_global_cleanup();
+}
+
+void EchidnaCleanExitFunc(int signal, void *arg)
+{
+ DEBUG_WRAP(DebugMessage(DEBUG_LOG,"echidna: exiting...\n"););
+
+ EchidnaClose(arg);
+}
+
+void EchidnaRestartFunc(int signal, void *arg)
+{
+ DEBUG_WRAP(DebugMessage(DEBUG_LOG,"echidna: restarting...\n"););
+
+ EchidnaClose(arg);
+}
+
+#endif /* ENABLE_OUTPUT_PLUGIN */
View
10 src/output-plugins/spo_platypus.h → src/output-plugins/spo_echidna.h
@@ -1,4 +1,4 @@
-/*
+/*
** Copyright (C) 2008-2012 Ian Firns (SecurixLive) <dev@securixlive.com>
**
** This program is free software; you can redistribute it and/or modify
@@ -20,9 +20,9 @@
*/
-#ifndef __SPO_PLATYPUS_H__
-#define __SPO_PLATYPUS_H__
+#ifndef __SPO_ECHIDNA_H__
+#define __SPO_ECHIDNA_H__
-void PlatypusSetup();
+void EchidnaSetup();
-#endif /* __SPO_PLATYPUS_H__ */
+#endif /* __SPO_ECHIDNA_H__ */
View
862 src/output-plugins/spo_platypus.c
@@ -1,862 +0,0 @@
-/*
-** Copyright (C) 2008-2012 Ian Firns (SecurixLive) <dev@securixlive.com>
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License Version 2 as
-** published by the Free Software Foundation. You may not use, modify or
-** distribute this program under any other version of the GNU General
-** Public License.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-**
-**
-*/
-
-/*
-** INCLUDES
-*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <time.h>
-#include <errno.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-
-#include "barnyard2.h"
-#include "debug.h"
-#include "decode.h"
-#include "map.h"
-#include "mstring.h"
-#include "plugbase.h"
-#include "strlcpyu.h"
-#include "unified2.h"
-#include "util.h"
-
-typedef struct _SpoPlatypusData
-{
- char *agent_name;
- u_int16_t sensor_id;
- u_int16_t agent_port;
- int agent_sock;
-
- u_int32_t event_id;
-
- char *args;
-} SpoPlatypusData;
-
-/* constants */
-#define KEYWORD_AGENTPORT "agent_port"
-#define KEYWORD_AGENTNAME "agent_name"
-
-#define DEFAULT_AGENTPORT 7060
-
-#define MAX_MSG_LEN 2048
-#define TMP_BUFFER 128
-
-/* output plug-in API functions */
-void PlatypusInit(char *args);
-void PlatypusInitFinalize(int unused, void *arg);
-
-SpoPlatypusData *InitPlatypusData(char *);
-void ParsePlatypusArgs(SpoPlatypusData *spd_data);
-
-void PlatypusCleanExitFunc(int, void *);
-void PlatypusRestartFunc(int, void *);
-
-
-/* internal platypus functions */
-void Platypus(Packet *, void *, u_int32_t, void *);
-
-int PlatypusAgentConnect(SpoPlatypusData *);
-int PlatypusAgentInit(SpoPlatypusData *);
-int PlatypusAgentEventSend(SpoPlatypusData *, char *);
-int PlatypusAgentSend(SpoPlatypusData *, char *);
-int PlatypusAgentReceive(SpoPlatypusData *, char *);
-
-char *PlatypusTimestamp(u_int32_t, u_int32_t);
-
-int PlatypusEventIPHeaderDataAppend(char *, Packet *);
-int PlatypusEventICMPDataAppend(char *, Packet *);
-int PlatypusEventTCPDataAppend(char *, Packet *);
-int PlatypusEventUDPDataAppend(char *, Packet *);
-
-/* init routine makes this processor available for dataprocessor directives */
-void PlatypusSetup()
-{
- /* link the preprocessor keyword to the init function in
- the preproc list */
- RegisterOutputPlugin("platypus", OUTPUT_TYPE_FLAG__ALERT, PlatypusInit);
-
- DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Output: Platypus is setup\n"););
-}
-
-void PlatypusInit(char *args)
-{
- SpoPlatypusData *spd_data;
-
- DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Output: Platypus initialized\n"););
-
- /* parse the argument list from the rules file`*/
- spd_data = InitPlatypusData(args);
-
- AddFuncToPostConfigList(PlatypusInitFinalize, spd_data);
-}
-
-SpoPlatypusData *InitPlatypusData(char *args)
-{
- SpoPlatypusData *data;
-
- /* setup the internal structures and parse any arguments */
- data = (SpoPlatypusData *)SnortAlloc(sizeof(SpoPlatypusData));
-
- /* store args for later parsing */
- if( args != NULL )
- data->args = SnortStrdup(args);
-
- return data;
-}
-
-void PlatypusInitFinalize(int unused, void *arg)
-{
- SpoPlatypusData *spd_data = (SpoPlatypusData *)arg;
-
- if( spd_data == NULL )
- FatalError("platypus: data uninitialized\n");
-
- ParsePlatypusArgs(spd_data);
-
- /* identify the agent_name */
- if( spd_data->agent_name == NULL )
- spd_data->agent_name = SnortStrdup(GetUniqueName(PRINT_INTERFACE(barnyard2_conf->interface)));
-
- if( ! BcLogQuiet() )
- LogMessage("platypus: agent port = %u\n", spd_data->agent_port);
-
- /* connect to the sensor agent (SnortAgent) */
- if (PlatypusAgentConnect(spd_data) == 0)
- {
- /* initialise the sensor agent - get sid/eid */
- if( BcLogVerbose() )
- LogMessage("platypus: waiting for sid/eid from SnortAgent.\n");
-
- PlatypusAgentInit(spd_data);
- }
- else
- FatalError("platypus: unable to connect to agent\n");
-
- /* set the preprocessor function into the function list */
- AddFuncToOutputList(Platypus, OUTPUT_TYPE__ALERT, spd_data);
- AddFuncToCleanExitList(PlatypusCleanExitFunc, spd_data);
- AddFuncToRestartList(PlatypusRestartFunc, spd_data);
-}
-
-void Platypus(Packet *p, void *event, u_int32_t event_type, void *arg)
-{
- char *evt_msg;
- char *data_msg;
-
- char sip4[INET_ADDRSTRLEN];
- char dip4[INET_ADDRSTRLEN];
- char sip6[INET6_ADDRSTRLEN];
- char dip6[INET6_ADDRSTRLEN];
-
- SpoPlatypusData *data;
- SigNode *sn = NULL;
- ClassType *cn = NULL;
-
- if( event == NULL || arg == NULL )
- return;
-
- if( p != NULL && p->dsize > 0 )
- evt_msg = SnortAlloc(sizeof(char) * ((p->dsize>>2)+MAX_MSG_LEN));
- else
- evt_msg = SnortAlloc(sizeof(char) * MAX_MSG_LEN);
-
- data = (SpoPlatypusData *)arg;
-
- /* grab the appropriate signature and classification information */
- sn = GetSigByGidSid(ntohl(((Unified2EventCommon *)event)->generator_id),
- ntohl(((Unified2EventCommon *)event)->signature_id),
- ntohl(((Unified2EventCommon *)event)->signature_revision));
-
- cn = ClassTypeLookupById(barnyard2_conf, ntohl(((Unified2EventCommon *)event)->classification_id));
-
- /*
- ** 0 1 2 3 4 5 6 7 8 (9)
- ** BY2_EVT|SID|EID|SNORT EID|TIMESTAMP|SIG_GEN|SIG_ID|SIG_REV|SIG_MSG|
- **
- ** 9 10 11 12 13 14 15 16 (8)
- ** PRIORITY|CLASS TYPE|IP_VER|SIP|SPORT_ICODE|DIP|DPORT_ICODE|IP_PROTO|
- **
- ** 17 18 19 20 21 22 23 24 25 (9)
- ** IP_VER|IP_HLEN|IP_TOS|IP_LEN|IP_ID|IP_FLAGS|IP_OFF|IP_TTL|IP_CSUM|
- **
- ** 26 27 28 (3)
- ** ICMP_CSUM|ICMP_ID|ICMP_SEQ|
- **
- ** 29 30 31 32 33 34 35 36 (8)
- ** TCP_SEQ|TCP_ACK|TCP_OFF|TCP_RES|TCP_FLAGS|TCP_WIN|TCP_CSUM|TCP_URP
- **
- ** 37 38 (2)
- ** UDP_LEN|UDP_CSUM|
- **
- ** 39 (1)
- ** DATA
- */
-
- /* initialise the string */
- SnortSnprintf(evt_msg, MAX_MSG_LEN, "EVENT|");
-
- /* sensor ID (sid) */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", data->sensor_id);
-
- /* event ID (eid) */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", data->event_id);
-
- /* snort event ID */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|",
- ntohl(((Unified2EventCommon *)event)->event_id));
-
- /* snort event reference time */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%s|",
- PlatypusTimestamp(
- ntohl(((Unified2EventCommon *)event)->event_second),
- ntohl(((Unified2EventCommon *)event)->event_microsecond)
- )
- );
-
- /* generator ID */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%d|",
- ntohl(((Unified2EventCommon *)event)->generator_id));
-
- /* signature ID */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%d|",
- ntohl(((Unified2EventCommon *)event)->signature_id));
-
- /* signature revision */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%d|",
- ntohl(((Unified2EventCommon *)event)->signature_revision));
-
- /* signature message */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%s|", sn->msg);
-
- /* alert priority */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|",
- ntohl(((Unified2EventCommon *)event)->priority_id));
-
- /* alert classification */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%s|", cn != NULL ? cn->type : "unknown");
-
- /* IP version, addresses, ports and protocol */
- switch( event_type )
- {
- case UNIFIED2_IDS_EVENT:
- case UNIFIED2_IDS_EVENT_MPLS:
- case UNIFIED2_IDS_EVENT_VLAN:
- inet_ntop(AF_INET, &((Unified2IDSEvent*)event)->ip_source, sip4, INET_ADDRSTRLEN);
- inet_ntop(AF_INET, &((Unified2IDSEvent*)event)->ip_destination, dip4, INET_ADDRSTRLEN);
-
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "4|%s|%u|%s|%u|%u|",
- sip4, ntohs(((Unified2IDSEvent *)event)->sport_itype),
- dip4, ntohs(((Unified2IDSEvent *)event)->dport_icode),
- ((Unified2IDSEvent *)event)->protocol);
- break;
- case UNIFIED2_IDS_EVENT_IPV6:
- case UNIFIED2_IDS_EVENT_IPV6_MPLS:
- case UNIFIED2_IDS_EVENT_IPV6_VLAN:
- inet_ntop(AF_INET6, &((Unified2IDSEventIPv6 *)event)->ip_source, sip6, INET6_ADDRSTRLEN);
- inet_ntop(AF_INET6, &((Unified2IDSEventIPv6 *)event)->ip_destination, dip6, INET6_ADDRSTRLEN);
-
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "6|%s|%u|%s|%u|%u|",
- sip6,
- ntohs(((Unified2IDSEventIPv6 *)event)->sport_itype),
- dip6,
- ntohs(((Unified2IDSEventIPv6 *)event)->dport_icode),
- ((Unified2IDSEventIPv6 *)event)->protocol);
- break;
- default:
- printf("Type: %d\n", event_type);
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "0||||||");
- break;
- }
-
- /* pull decoded info from the packet */
- if( p != NULL )
- {
- if( p->iph != NULL )
- {
- /* IP version and protocol */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", IP_VER(p->iph));
-
- /* add IP header */
- PlatypusEventIPHeaderDataAppend(evt_msg, p);
-
- /* add ICMP || UDP || TCP data */
- if( ! (p->packet_flags & PKT_REBUILT_FRAG) )
- {
- switch( p->iph->ip_proto )
- {
- case IPPROTO_ICMP:
- PlatypusEventICMPDataAppend(evt_msg, p);
- break;
-
- case IPPROTO_TCP:
- PlatypusEventTCPDataAppend(evt_msg, p);
- break;
-
- case IPPROTO_UDP:
- PlatypusEventUDPDataAppend(evt_msg, p);
- break;
-
- default:
- /* append 13 fillers */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "|||||||||||||");
- break;
- }
- }
- else
- {
- /* null out TCP/UDP/ICMP fields */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "|||||||||||||");
- }
- }
- else
- {
- /* no IP Header. */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "||||||||||||||||||||||");
- }
-
- /* add payload data */
- if( p->dsize )
- {
- data_msg = fasthex(p->data, p->dsize);
- SnortSnprintfAppend(evt_msg, (p->dsize>>2)+MAX_MSG_LEN, "%s", data_msg);
- free(data_msg);
- }
- }
- else
- {
- /* ack! an event without a packet. Append 23 fillers */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "||||||||||||||||||||||");
- }
-
- /* send msg to sensor_agent */
- if( PlatypusAgentEventSend(data, evt_msg) )
- FatalError("platypus: unable to send real-time events to SnortAgent!\n");
-
- /* free the mallocs! */
- free(evt_msg);
-}
-
-int PlatypusAgentEventSend(SpoPlatypusData *data, char *msg)
-{
- char rcv_msg[MAX_MSG_LEN];
-
- /* send the real-time event message */
- PlatypusAgentSend(data, msg);
-
- /* get the reply */
- memset(rcv_msg, 0x0, MAX_MSG_LEN);
- if( PlatypusAgentReceive(data, rcv_msg) == 1 )
- {
- if( BcLogVerbose() )
- LogMessage("platypus: retrying...\n");
-
- PlatypusAgentEventSend(data, msg);
- }
- else
- {
- char **toks;
- int num_toks;
-
- DEBUG_WRAP(DebugMessage(DEBUG_LOG,"platypus: received \"%s\"", rcv_msg););
-
- /* parse the reply */
- toks = mSplit(rcv_msg, "|", 2, &num_toks, 0);
- if( strncasecmp(toks[0], "BY2_EVT_CFM", 11) != 0 )
- FatalError("platypus: expected BY2_EVT_CFM|%u and got: \"%s\"\n", data->event_id, rcv_msg);
- else
- {
- if ( (num_toks == 2) && (atoi(toks[1]) != data->event_id) )
- {
- FatalError("platypus: expected BY2_EVT_CFM|%u and got: \"%s\" (%u)\n", data->event_id, rcv_msg, atoi(toks[1]));
- }
- }
-
- mSplitFree(&toks, num_toks);
-
- /* bump the event id on confirmation only */
- data->event_id++;
- }
-
- return 0;
-}
-
-int PlatypusEventIPHeaderDataAppend(char *evt_msg, Packet *p)
-{
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", IP_HLEN(p->iph));
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", p->iph->ip_tos);
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", ntohs(p->iph->ip_len));
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", ntohs(p->iph->ip_id));
-
-#if defined(WORDS_BIGENDIAN)
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", ((p->iph->ip_off & 0xe000) >> 13));
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", htons(p->iph->ip_off & 0x1fff));
-#else
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", ((p->iph->ip_off & 0x00e0) >> 5));
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", htons(p->iph->ip_off & 0xff1f));
-#endif
-
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", p->iph->ip_ttl);
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", htons(p->iph->ip_csum));
-
- return 0;
-}
-
-int PlatypusEventICMPDataAppend(char *evt_msg, Packet *p)
-{
- /* null out ICMP fields */
- if( p->icmph != NULL )
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "|||");
- else
- {
- /* ICMP checksum */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", ntohs(p->icmph->csum));
-
- /* Append other ICMP data if we have it */
- if( p->icmph->type == ICMP_ECHOREPLY || p->icmph->type == ICMP_ECHO ||
- p->icmph->type == ICMP_TIMESTAMP || p->icmph->type == ICMP_TIMESTAMPREPLY ||
- p->icmph->type == ICMP_INFO_REQUEST || p->icmph->type == ICMP_INFO_REPLY )
- {
- /* ICMP ID */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", htonl(p->icmph->icmp_hun.idseq.id));
-
- /* ICMP sequence */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", htonl(p->icmph->icmp_hun.idseq.seq));
- }
- /* add two empty elements */
- else
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "||");
- }
-
- /* blank out TCP / UDP elements */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "||||||||||");
-
- return 0;
-}
-
-int PlatypusEventTCPDataAppend(char *evt_msg, Packet *p)
-{
- /* empty elements for icmp data */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "|||");
-
- /* null out TCP fields */
- if( p->tcph!= NULL )
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "||||||||");
- else
- {
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", ntohl(p->tcph->th_seq));
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", ntohl(p->tcph->th_ack));
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", TCP_OFFSET(p->tcph));
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", TCP_X2(p->tcph));
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", p->tcph->th_flags);
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", ntohl(p->tcph->th_win));
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", ntohl(p->tcph->th_sum));
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|", ntohl(p->tcph->th_urp));
- }
-
- /* empty elements for UDP data */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "||");
-
- return 0;
-}
-
-int PlatypusEventUDPDataAppend(char *evt_msg, Packet *p)
-{
- /* empty elements for ICMP data */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "|||");
-
- /* empty elements for TCP data */
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "||||||||");
-
- /* null out UDP info */
- if( p->udph != NULL )
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "||");
- else
- {
- SnortSnprintfAppend(evt_msg, MAX_MSG_LEN, "%u|%u|",
- ntohs(p->udph->uh_len),
- ntohs(p->udph->uh_chk));
- }
-
- return 0;
-}
-
-int PlatypusAgentConnect(SpoPlatypusData *spd_data)
-{
- int srv_sock;
- struct sockaddr_in srv_saddr;
- u_int8_t tries = 5;
-
- /* loop listening for external signals */
- while( exit_signal == 0 )
- {
-
- if( (srv_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
- {
- FatalError("platypus: Can't open a local socket.\n");
- return 1;
- }
-
- srv_saddr.sin_family = AF_INET;
- srv_saddr.sin_port = htons(spd_data->agent_port);
- srv_saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
- memset(&(srv_saddr.sin_zero), '\0', 8);
-
- if( connect(srv_sock, (struct sockaddr *)&srv_saddr, sizeof(struct sockaddr)) < 0 )
- {
- LogMessage("platypus: can't connect to localhost:%u.\n",
- spd_data->agent_port);
- close(srv_sock);
-
- /* only perform 4 tries when testing the configuration */
- if( (BcTestMode()) && (tries-- == 0) )
- {
- FatalError("platypus: unable to connect after 5 attempts\n");
- }
-
- LogMessage("platypus: will try again in 15 seconds.\n");
-
- /* sleep for allocated time before retrying */
- sleep(15);
- }
- else
- {
- spd_data->agent_sock = srv_sock;
- LogMessage("platypus: connected to localhost:%u.\n",
- spd_data->agent_port);
- return 0;
- }
- }
-
- return 1;
-}
-
-/* request sensor ID (sid) and last event ID (eid) from the server, via the SnortAgent */
-int PlatypusAgentInit(SpoPlatypusData *spd_data)
-{
- char snd_msg[MAX_MSG_LEN];
- char rcv_msg[MAX_MSG_LEN];
-
- /* send our request */
- SnortSnprintf(snd_msg, MAX_MSG_LEN, "BY2_SEID_REQ|%s", spd_data->agent_name);
- PlatypusAgentSend(spd_data, snd_msg);
-
- /* get the reply */
- memset(rcv_msg, 0x0, MAX_MSG_LEN);
- if( PlatypusAgentReceive(spd_data, rcv_msg) == 1 )
- PlatypusAgentInit(spd_data);
- else
- {
- char **toks;
- int num_toks;
-
- DEBUG_WRAP(DebugMessage(DEBUG_LOG,"platypus: received \"%s\" (%d)\n", rcv_msg, strlen(rcv_msg)););
-
- /* check we actually received something */
- if( strlen(rcv_msg) == 0 )
- FatalError("platypus: expected BY2_SEID_RSP but got \"%s\"\n", rcv_msg);
-
- /* parse the response */
- toks = mSplit(rcv_msg, "|", 3, &num_toks, 0);
-
- if( strncasecmp("BY2_SEID_RSP", toks[0], 11) == 0 )
- {
- spd_data->sensor_id = atoi(toks[1]);
- spd_data->event_id = atoi(toks[2]);
- }
- else
- FatalError("platypus: expected BY2_SEID_RSP but got \"%s\"\n", rcv_msg);
-
- mSplitFree(&toks, num_toks);
-
- if( BcLogVerbose() )
- {
- LogMessage("platypus: sensor ID = %u\n", spd_data->sensor_id);
- LogMessage("platypus: event ID = %u\n", spd_data->event_id);
- }
-
- /* increment event ID */
- spd_data->event_id++;
- }
-
- return 0;
-}
-
-int PlatypusAgentSend(SpoPlatypusData *data, char *out)
-{
- char *snd_msg;
- size_t snd_len;
-
- /* calculate length + 2 (ie. account for terminated \n and \0 */
- snd_len = strlen(out)+2;
- snd_msg = SnortAlloc(snd_len);
- SnortSnprintf(snd_msg, snd_len, "%s\n", out);
-
- if ( send(data->agent_sock, snd_msg, sizeof(char)*snd_len, 0) == -1 )
- {
- if( BcLogVerbose() )
- LogMessage("platypus: lost connection to SnortAgent.\n");
-
- /* free the buffer allocation */
- free(snd_msg);
-
- /* resend our message */
- PlatypusAgentSend(data, out);
- }
-
- DEBUG_WRAP(DebugMessage(DEBUG_LOG,"platypus: sent \"%s\"\n", out););
-
- /* free the buffer allocation */
- free(snd_msg);
-
- return 0;
-}
-
-/* I love google. http://pont.net/socket/prog/tcpServer.c */
-int PlatypusAgentReceive(SpoPlatypusData *spd_data, char *in)
-{
- static int rcv_idx = 0;
- static char rcv_msg[MAX_MSG_LEN];
- static int rcv_len;
- struct timeval rcv_tv;
- fd_set rcv_fds;
- int in_off;
-
- in_off = 0;
-
- /* wait up to 15 secs for our response */
- rcv_tv.tv_sec = 15;
- rcv_tv.tv_usec = 0;
-
- FD_ZERO(&rcv_fds);
- FD_SET(spd_data->agent_sock, &rcv_fds);
-
- /* loop listening for external signals */
- while( exit_signal == 0 )
- {
- /* wait for response from SnortAgent */
- select(spd_data->agent_sock+1, &rcv_fds, NULL, NULL, &rcv_tv);
-
- if( ! (FD_ISSET(spd_data->agent_sock, &rcv_fds)) )
- {
- /* timed out */
- if( BcLogVerbose() )
- LogMessage("platypus: timed out waiting for response.\n");
-
- return 1;
- }
- else
- {
- if( rcv_idx == 0 )
- {
- memset(rcv_msg, 0x0, MAX_MSG_LEN);
- rcv_len = recv(spd_data->agent_sock, rcv_msg, MAX_MSG_LEN, 0);
-
- if( rcv_len < 0 )
- {
- LogMessage("platypus: unable to read data!\n");
-
- /* reconnect to sensor_agent */
- PlatypusAgentConnect(spd_data);
- }
- else if( rcv_len == 0 )
- {
- LogMessage("platypus: connecton closed by client!\n");
- close(spd_data->agent_sock);
-
- /* reconnect to sensor_agent */
- PlatypusAgentConnect(spd_data);
- }
- }
-
- /* copy line into 'in' */
- while( *(rcv_msg+rcv_idx) != 0x0a && rcv_idx < rcv_len )
- {
- memcpy(in+in_off, rcv_msg+rcv_idx, 1);
- in_off++;
- rcv_idx++;
- }
-
- /* we have reached the end of the line and the end of buffer, */
- /* return the line and reset the buffer index pointer */
- if( rcv_idx == rcv_len-1 )
- {
- /* set last byte to END_LINE */
- *(in+in_off) = 0x0a;
- rcv_idx = 0;
-
- return ++in_off;
- }
-
- /* we have reached the end of line but still have some data in */
- /* buffer, return the line and increment the buffer index pointer */
- if( rcv_idx < rcv_len-1 )
- {
- /* set last byte to END_LINE */
- *(in+in_off) = 0x0a;
- rcv_idx++;
-
- return ++in_off;
- }
-
- /* we have reached the end of buffer but the line has not ended, */
- /* wait for more data to arrive on socket */
- if( rcv_idx == rcv_len )
- rcv_idx = 0;
- }
- }
-
- return 0;
-}
-
-/*
- * Function: ParsePlatypusArgs(char *)
- *
- * Purpose: Process the preprocessor arguements from the rules file and
- * initialize the preprocessor's data struct. This function doesn't
- * have to exist if it makes sense to parse the args in the init
- * function.
- *
- * Arguments: args => argument list
- *
- * Returns: void function
- *
- */
-void ParsePlatypusArgs(SpoPlatypusData *spd_data)
-{
- char **toks;
- int num_toks;
- int i;
-
- /* initialise appropariate values to defaults */
- spd_data->agent_port = DEFAULT_AGENTPORT;
-
- if( spd_data->args == NULL )
- {
- //FatalError("platypus: you must supply arguments for platypus plugin.\n");
- return;
- }
-
- /* parse out the args */
- toks = mSplit(spd_data->args, ", ", 31, &num_toks, '\\');
-
- for( i=0; i<num_toks; ++i )
- {
- char **stoks;
- int num_stoks;
- char *index = toks[i];
-
- while( isspace((int)*index) )
- ++index;
-
- stoks = mSplit(index, "=", 2, &num_stoks, 0);
-
- if( !strncasecmp(stoks[0], KEYWORD_AGENTPORT, strlen(KEYWORD_AGENTPORT)) )
- {
- if( num_stoks > 1 )
- spd_data->agent_port = atoi(stoks[1]);
- else
- LogMessage("platypus: agent_port error\n");
- }
- else if( !strncasecmp(stoks[0], KEYWORD_AGENTNAME, strlen(KEYWORD_AGENTNAME)) )
- {
- if( num_stoks > 1 && spd_data->agent_name == NULL )
- spd_data->agent_name = SnortStrdup(stoks[1]);
- else
- LogMessage("platypus: agent_name error\n");
- }
- else
- {
- FatalError("platypus: unrecognised plugin argument \"%s\"!\n", index);
- }
-
- /* free your mSplit tokens */
- mSplitFree(&stoks, num_stoks);
- }
-
- /* free your mSplit tokens */
- mSplitFree(&toks, num_toks);
-}
-
-char *PlatypusTimestamp(u_int32_t sec, u_int32_t usec)
-{
- struct tm *lt; /* localtime */
- char *buf;
- time_t time = sec;
-
- buf = (char *)SnortAlloc(TMP_BUFFER * sizeof(char));
-
- if( BcOutputUseUtc() )
- lt = gmtime(&time);
- else
- lt = localtime(&time);
-
- SnortSnprintf(buf, TMP_BUFFER, "%04i-%02i-%02i %02i:%02i:%02i.%06i",
- 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday,
- lt->tm_hour, lt->tm_min, lt->tm_sec, usec);
-
- return buf;
-}
-
-void PlatypusClose(void *arg)
-{
- SpoPlatypusData *spd_data = (SpoPlatypusData *)arg;
-
- /* free allocated memory from SpoPlatypusData */
- if( spd_data != NULL )
- {
- if( spd_data->agent_name )
- free(spd_data->agent_name);
-
- if( spd_data->args )
- free(spd_data->args);
-
- free(spd_data);
- }
-}
-
-void PlatypusCleanExitFunc(int signal, void *arg)
-{
- DEBUG_WRAP(DebugMessage(DEBUG_LOG,"platypus: exiting...\n"););
-
- PlatypusClose(arg);
-}
-
-void PlatypusRestartFunc(int signal, void *arg)
-{
- DEBUG_WRAP(DebugMessage(DEBUG_LOG,"platypus: restarting...\n"););
-
- PlatypusClose(arg);
-}
-
-
View
7 src/plugbase.c
@@ -70,7 +70,7 @@
#include "output-plugins/spo_log_ascii.h"
#include "output-plugins/spo_log_null.h"
#include "output-plugins/spo_log_tcpdump.h"
-#include "output-plugins/spo_platypus.h"
+#include "output-plugins/spo_echidna.h"
#include "output-plugins/spo_sguil.h"
#include "output-plugins/spo_syslog_full.h"
@@ -355,7 +355,10 @@ void RegisterOutputPlugins(void)
AlertTestSetup();
- PlatypusSetup();
+#ifdef ENABLE_PLUGIN_ECHIDNA
+ EchidnaSetup();
+#endif
+
SguilSetup();
OpSyslog_Setup();

0 comments on commit ae7c627

Please sign in to comment.