|
|
|
/* Copyright (C) 2007-2011 Open Information Security Foundation
|
|
|
|
*
|
|
|
|
* You can copy, redistribute or modify this Program under the terms of
|
|
|
|
* the GNU General Public License version 2 as published by the Free
|
|
|
|
* Software Foundation.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* version 2 along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
|
|
* 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \file
|
|
|
|
*
|
|
|
|
* \author Breno Silva <breno.silva@gmail.com>
|
|
|
|
* \author Eric Leblond <eric@regit.org>
|
|
|
|
*
|
|
|
|
* Logs alerts in a format compatible to Snort's unified2 format, so it should
|
|
|
|
* be readable by Barnyard2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "suricata-common.h"
|
|
|
|
#include "runmodes.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "detect.h"
|
|
|
|
#include "flow.h"
|
|
|
|
#include "conf.h"
|
|
|
|
#include "pkt-var.h"
|
|
|
|
#include "threads.h"
|
|
|
|
#include "threadvars.h"
|
Add per packet profiling.
Per packet profiling uses tick based accounting. It has 2 outputs, a summary
and a csv file that contains per packet stats.
Stats per packet include:
1) total ticks spent
2) ticks spent per individual thread module
3) "threading overhead" which is simply calculated by subtracting (2) of (1).
A number of changes were made to integrate the new code in a clean way:
a number of generic enums are now placed in tm-threads-common.h so we can
include them from any part of the engine.
Code depends on --enable-profiling just like the rule profiling code.
New yaml parameters:
profiling:
# packet profiling
packets:
# Profiling can be disabled here, but it will still have a
# performance impact if compiled in.
enabled: yes
filename: packet_stats.log
append: yes
# per packet csv output
csv:
# Output can be disabled here, but it will still have a
# performance impact if compiled in.
enabled: no
filename: packet_stats.csv
Example output of summary stats:
IP ver Proto cnt min max avg
------ ----- ------ ------ ---------- -------
IPv4 6 19436 11448 5404365 32993
IPv4 256 4 11511 49968 30575
Per Thread module stats:
Thread Module IP ver Proto cnt min max avg
------------------------ ------ ----- ------ ------ ---------- -------
TMM_DECODEPCAPFILE IPv4 6 19434 1242 47889 1770
TMM_DETECT IPv4 6 19436 1107 137241 1504
TMM_ALERTFASTLOG IPv4 6 19436 90 1323 155
TMM_ALERTUNIFIED2ALERT IPv4 6 19436 108 1359 138
TMM_ALERTDEBUGLOG IPv4 6 19436 90 1134 154
TMM_LOGHTTPLOG IPv4 6 19436 414 5392089 7944
TMM_STREAMTCP IPv4 6 19434 828 1299159 19438
The proto 256 is a counter for handling of pseudo/tunnel packets.
Example output of csv:
pcap_cnt,ipver,ipproto,total,TMM_DECODENFQ,TMM_VERDICTNFQ,TMM_RECEIVENFQ,TMM_RECEIVEPCAP,TMM_RECEIVEPCAPFILE,TMM_DECODEPCAP,TMM_DECODEPCAPFILE,TMM_RECEIVEPFRING,TMM_DECODEPFRING,TMM_DETECT,TMM_ALERTFASTLOG,TMM_ALERTFASTLOG4,TMM_ALERTFASTLOG6,TMM_ALERTUNIFIEDLOG,TMM_ALERTUNIFIEDALERT,TMM_ALERTUNIFIED2ALERT,TMM_ALERTPRELUDE,TMM_ALERTDEBUGLOG,TMM_ALERTSYSLOG,TMM_LOGDROPLOG,TMM_ALERTSYSLOG4,TMM_ALERTSYSLOG6,TMM_RESPONDREJECT,TMM_LOGHTTPLOG,TMM_LOGHTTPLOG4,TMM_LOGHTTPLOG6,TMM_PCAPLOG,TMM_STREAMTCP,TMM_DECODEIPFW,TMM_VERDICTIPFW,TMM_RECEIVEIPFW,TMM_RECEIVEERFFILE,TMM_DECODEERFFILE,TMM_RECEIVEERFDAG,TMM_DECODEERFDAG,threading
1,4,6,172008,0,0,0,0,0,0,47889,0,0,48582,1323,0,0,0,0,1359,0,1134,0,0,0,0,0,8028,0,0,0,49356,0,0,0,0,0,0,0,14337
First line of the file contains labels.
2 example gnuplot scripts added to plot the data.
14 years ago
|
|
|
#include "tm-threads.h"
|
|
|
|
|
|
|
|
#include "util-unittest.h"
|
|
|
|
#include "alert-unified2-alert.h"
|
|
|
|
#include "decode-ipv4.h"
|
|
|
|
|
|
|
|
#include "util-error.h"
|
|
|
|
#include "util-debug.h"
|
|
|
|
#include "util-time.h"
|
|
|
|
#include "util-byte.h"
|
|
|
|
#include "util-misc.h"
|
|
|
|
|
|
|
|
#include "output.h"
|
|
|
|
#include "alert-unified2-alert.h"
|
|
|
|
#include "util-privs.h"
|
|
|
|
|
|
|
|
#include "stream.h"
|
|
|
|
#include "stream-tcp-inline.h"
|
|
|
|
|
|
|
|
#include "util-optimize.h"
|
|
|
|
|
|
|
|
#ifndef IPPROTO_SCTP
|
|
|
|
#define IPPROTO_SCTP 132
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define DEFAULT_LOG_FILENAME "unified2.alert"
|
|
|
|
|
|
|
|
/**< Default log file limit in MB. */
|
|
|
|
#define DEFAULT_LIMIT 32 * 1024 * 1024
|
|
|
|
|
|
|
|
/**< Minimum log file limit in MB. */
|
|
|
|
#define MIN_LIMIT 1 * 1024 * 1024
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unified2 file header struct
|
|
|
|
*
|
|
|
|
* Used for storing file header options.
|
|
|
|
*/
|
|
|
|
typedef struct Unified2AlertFileHeader_ {
|
|
|
|
uint32_t type; /**< unified2 type header */
|
|
|
|
uint32_t length; /**< unified2 struct size length */
|
|
|
|
} Unified2AlertFileHeader;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unified2 Ipv4 struct
|
|
|
|
*
|
|
|
|
* Used for storing ipv4 type values.
|
|
|
|
*/
|
|
|
|
typedef struct AlertIPv4Unified2_ {
|
|
|
|
uint32_t sensor_id; /**< sendor id */
|
|
|
|
uint32_t event_id; /**< event id */
|
|
|
|
uint32_t event_second; /**< event second */
|
|
|
|
uint32_t event_microsecond; /**< event microsecond */
|
|
|
|
uint32_t signature_id; /**< signature id */
|
|
|
|
uint32_t generator_id; /**< generator id */
|
|
|
|
uint32_t signature_revision; /**< signature revision */
|
|
|
|
uint32_t classification_id; /**< classification id */
|
|
|
|
uint32_t priority_id; /**< priority id */
|
|
|
|
uint32_t src_ip; /**< source ip */
|
|
|
|
uint32_t dst_ip; /**< destination ip */
|
|
|
|
uint16_t sp; /**< source port */
|
|
|
|
uint16_t dp; /**< destination port */
|
|
|
|
uint8_t protocol; /**< protocol */
|
|
|
|
uint8_t packet_action; /**< packet action */
|
|
|
|
} AlertIPv4Unified2;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unified2 Ipv6 type struct
|
|
|
|
*
|
|
|
|
* Used for storing ipv6 type values.
|
|
|
|
*/
|
|
|
|
typedef struct AlertIPv6Unified2_ {
|
|
|
|
uint32_t sensor_id; /**< sendor id */
|
|
|
|
uint32_t event_id; /**< event id */
|
|
|
|
uint32_t event_second; /**< event second */
|
|
|
|
uint32_t event_microsecond; /**< event microsecond */
|
|
|
|
uint32_t signature_id; /**< signature id */
|
|
|
|
uint32_t generator_id; /**< generator id */
|
|
|
|
uint32_t signature_revision; /**< signature revision */
|
|
|
|
uint32_t classification_id; /**< classification id */
|
|
|
|
uint32_t priority_id; /**< priority id */
|
|
|
|
struct in6_addr src_ip; /**< source ip */
|
|
|
|
struct in6_addr dst_ip; /**< destination ip */
|
|
|
|
uint16_t sp; /**< source port */
|
|
|
|
uint16_t dp; /**< destination port */
|
|
|
|
uint8_t protocol; /**< protocol */
|
|
|
|
uint8_t packet_action; /**< packet action */
|
|
|
|
} AlertIPv6Unified2;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unified2 packet type struct
|
|
|
|
*
|
|
|
|
* Used for storing packet type values.
|
|
|
|
*/
|
|
|
|
typedef struct AlertUnified2Packet_ {
|
|
|
|
uint32_t sensor_id; /**< sensor id */
|
|
|
|
uint32_t event_id; /**< event id */
|
|
|
|
uint32_t event_second; /**< event second */
|
|
|
|
uint32_t packet_second; /**< packet second */
|
|
|
|
uint32_t packet_microsecond; /**< packet microsecond */
|
|
|
|
uint32_t linktype; /**< link type */
|
|
|
|
uint32_t packet_length; /**< packet length */
|
|
|
|
uint8_t packet_data[4]; /**< packet data */
|
|
|
|
} Unified2Packet;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unified2 thread vars
|
|
|
|
*
|
|
|
|
* Used for storing file options.
|
|
|
|
*/
|
|
|
|
typedef struct Unified2AlertThread_ {
|
|
|
|
LogFileCtx *file_ctx; /**< LogFileCtx pointer */
|
|
|
|
uint8_t *data; /**< Per function and thread data */
|
|
|
|
/** Pointer to the Unified2AlertFileHeader contained in
|
|
|
|
* the pointer data. */
|
|
|
|
Unified2AlertFileHeader *hdr;
|
|
|
|
/** Pointer to the Unified2Packet contained in
|
|
|
|
* the pointer data. */
|
|
|
|
Unified2Packet *phdr;
|
|
|
|
/** Pointer to the IPv4 or IPv6 header contained in
|
|
|
|
* the pointer data. */
|
|
|
|
void *iphdr;
|
|
|
|
int datalen; /**< Length of per function and thread data */
|
|
|
|
int offset; /**< Offset used to now where to fill data */
|
|
|
|
int length; /**< Length of data for current alert */
|
|
|
|
} Unified2AlertThread;
|
|
|
|
|
|
|
|
#define UNIFIED2_PACKET_SIZE (sizeof(Unified2Packet) - 4)
|
|
|
|
|
|
|
|
SC_ATOMIC_DECLARE(unsigned int, unified2_event_id); /**< Atomic counter, to link relative event */
|
|
|
|
|
|
|
|
/** prototypes */
|
|
|
|
TmEcode Unified2Alert (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
|
|
|
|
TmEcode Unified2AlertThreadInit(ThreadVars *, void *, void **);
|
|
|
|
TmEcode Unified2AlertThreadDeinit(ThreadVars *, void *);
|
|
|
|
int Unified2IPv4TypeAlert(ThreadVars *, Packet *, void *, PacketQueue *);
|
|
|
|
int Unified2IPv6TypeAlert(ThreadVars *, Packet *, void *, PacketQueue *);
|
|
|
|
int Unified2PacketTypeAlert(Unified2AlertThread *, Packet *, uint32_t, int);
|
|
|
|
void Unified2RegisterTests();
|
|
|
|
int Unified2AlertOpenFileCtx(LogFileCtx *, const char *);
|
|
|
|
static void Unified2AlertDeInitCtx(OutputCtx *);
|
|
|
|
|
|
|
|
#define MODULE_NAME "Unified2Alert"
|
|
|
|
|
|
|
|
void TmModuleUnified2AlertRegister (void) {
|
|
|
|
tmm_modules[TMM_ALERTUNIFIED2ALERT].name = MODULE_NAME;
|
|
|
|
tmm_modules[TMM_ALERTUNIFIED2ALERT].ThreadInit = Unified2AlertThreadInit;
|
|
|
|
tmm_modules[TMM_ALERTUNIFIED2ALERT].Func = Unified2Alert;
|
|
|
|
tmm_modules[TMM_ALERTUNIFIED2ALERT].ThreadDeinit = Unified2AlertThreadDeinit;
|
|
|
|
tmm_modules[TMM_ALERTUNIFIED2ALERT].RegisterTests = Unified2RegisterTests;
|
|
|
|
tmm_modules[TMM_ALERTUNIFIED2ALERT].cap_flags = 0;
|
|
|
|
|
|
|
|
OutputRegisterModule(MODULE_NAME, "unified2-alert", Unified2AlertInitCtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Function to close unified2 file
|
|
|
|
*
|
|
|
|
* \param t Thread Variable containing input/output queue, cpu affinity etc.
|
|
|
|
* \param aun Unified2 thread variable.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int Unified2AlertCloseFile(ThreadVars *t, Unified2AlertThread *aun) {
|
|
|
|
if (aun->file_ctx->fp != NULL) {
|
|
|
|
fclose(aun->file_ctx->fp);
|
|
|
|
}
|
|
|
|
aun->file_ctx->size_current = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Function to rotate unified2 file
|
|
|
|
*
|
|
|
|
* \param t Thread Variable containing input/output queue, cpu affinity etc.
|
|
|
|
* \param aun Unified2 thread variable.
|
|
|
|
* \retval 0 on succces
|
|
|
|
* \retval -1 on failure
|
|
|
|
*/
|
|
|
|
|
|
|
|
int Unified2AlertRotateFile(ThreadVars *t, Unified2AlertThread *aun) {
|
|
|
|
if (Unified2AlertCloseFile(t,aun) < 0) {
|
|
|
|
SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC,
|
|
|
|
"Error: Unified2AlertCloseFile failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (Unified2AlertOpenFileCtx(aun->file_ctx,aun->file_ctx->prefix) < 0) {
|
|
|
|
SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC,
|
|
|
|
"Error: Unified2AlertOpenFileCtx, open new log file failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Wrapper for fwrite
|
|
|
|
*
|
|
|
|
* This function is basically a wrapper for fwrite which take
|
|
|
|
* in charge a size counter.
|
|
|
|
*
|
|
|
|
* \return 1 in case of success
|
|
|
|
*/
|
|
|
|
static int Unified2Write(Unified2AlertThread *aun)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = fwrite(aun->data, aun->length, 1, aun->file_ctx->fp);
|
|
|
|
if (ret != 1) {
|
|
|
|
SCLogError(SC_ERR_FWRITE, "Error: fwrite failed: %s", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
aun->file_ctx->size_current += aun->length;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Unified2 main entry function
|
|
|
|
*
|
|
|
|
* \retval TM_ECODE_OK all is good
|
|
|
|
* \retval TM_ECODE_FAILED serious error
|
|
|
|
*/
|
|
|
|
TmEcode Unified2Alert (ThreadVars *t, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (PKT_IS_IPV4(p)) {
|
|
|
|
ret = Unified2IPv4TypeAlert (t, p, data, pq);
|
|
|
|
} else if(PKT_IS_IPV6(p)) {
|
|
|
|
ret = Unified2IPv6TypeAlert (t, p, data, pq);
|
|
|
|
} else {
|
|
|
|
/* we're only supporting IPv4 and IPv6 */
|
|
|
|
return TM_ECODE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
return TM_ECODE_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TM_ECODE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct _FakeIPv4Hdr {
|
|
|
|
IPV4Hdr ip4h;
|
|
|
|
TCPHdr tcph;
|
|
|
|
} FakeIPv4Hdr;
|
|
|
|
|
|
|
|
static int Unified2ForgeFakeIPv4Header(FakeIPv4Hdr *fakehdr, Packet *p, int pkt_len, char invert)
|
|
|
|
{
|
|
|
|
fakehdr->ip4h.ip_verhl = p->ip4h->ip_verhl;
|
|
|
|
fakehdr->ip4h.ip_proto = p->ip4h->ip_proto;
|
|
|
|
if (! invert) {
|
|
|
|
fakehdr->ip4h.s_ip_src.s_addr = p->ip4h->s_ip_src.s_addr;
|
|
|
|
fakehdr->ip4h.s_ip_dst.s_addr = p->ip4h->s_ip_dst.s_addr;
|
|
|
|
} else {
|
|
|
|
fakehdr->ip4h.s_ip_dst.s_addr = p->ip4h->s_ip_src.s_addr;
|
|
|
|
fakehdr->ip4h.s_ip_src.s_addr = p->ip4h->s_ip_dst.s_addr;
|
|
|
|
}
|
|
|
|
fakehdr->ip4h.ip_len = htons((uint16_t)pkt_len);
|
|
|
|
|
|
|
|
if (! invert) {
|
|
|
|
fakehdr->tcph.th_sport = p->tcph->th_sport;
|
|
|
|
fakehdr->tcph.th_dport = p->tcph->th_dport;
|
|
|
|
} else {
|
|
|
|
fakehdr->tcph.th_dport = p->tcph->th_sport;
|
|
|
|
fakehdr->tcph.th_sport = p->tcph->th_dport;
|
|
|
|
}
|
|
|
|
fakehdr->tcph.th_offx2 = 0x50; /* just the TCP header, no options */
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct _FakeIPv6Hdr {
|
|
|
|
IPV6Hdr ip6h;
|
|
|
|
TCPHdr tcph;
|
|
|
|
} FakeIPv6Hdr;
|
|
|
|
|
|
|
|
static int Unified2ForgeFakeIPv6Header(FakeIPv6Hdr *fakehdr, Packet *p, int pkt_len, char invert)
|
|
|
|
{
|
|
|
|
fakehdr->ip6h.s_ip6_vfc = p->ip6h->s_ip6_vfc;
|
|
|
|
fakehdr->ip6h.s_ip6_nxt = IPPROTO_TCP;
|
|
|
|
fakehdr->ip6h.s_ip6_plen = htons(sizeof(TCPHdr));
|
|
|
|
if (!invert) {
|
|
|
|
memcpy(fakehdr->ip6h.s_ip6_addrs, p->ip6h->s_ip6_addrs, 32);
|
|
|
|
} else {
|
|
|
|
memcpy(fakehdr->ip6h.s_ip6_src, p->ip6h->s_ip6_dst, 16);
|
|
|
|
memcpy(fakehdr->ip6h.s_ip6_dst, p->ip6h->s_ip6_src, 16);
|
|
|
|
}
|
|
|
|
if (! invert) {
|
|
|
|
fakehdr->tcph.th_sport = p->tcph->th_sport;
|
|
|
|
fakehdr->tcph.th_dport = p->tcph->th_dport;
|
|
|
|
} else {
|
|
|
|
fakehdr->tcph.th_dport = p->tcph->th_sport;
|
|
|
|
fakehdr->tcph.th_sport = p->tcph->th_dport;
|
|
|
|
}
|
|
|
|
fakehdr->tcph.th_offx2 = 0x50; /* just the TCP header, no options */
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Write a faked Packet in unified2 file for each stream segment.
|
|
|
|
*/
|
|
|
|
static int Unified2PrintStreamSegmentCallback(Packet *p, void *data, uint8_t *buf, uint32_t buflen)
|
|
|
|
{
|
|
|
|
int ret = 1;
|
|
|
|
Unified2AlertThread *aun = (Unified2AlertThread *)data;
|
|
|
|
uint32_t hdr_length = 0;
|
|
|
|
uint32_t orig_length = aun->length;
|
|
|
|
|
|
|
|
if (PKT_IS_IPV6(p)) {
|
|
|
|
FakeIPv6Hdr *fakehdr = (FakeIPv6Hdr *)aun->iphdr;
|
|
|
|
hdr_length = sizeof(FakeIPv6Hdr);
|
|
|
|
fakehdr->ip6h.s_ip6_plen = htons((uint16_t) (hdr_length + buflen));
|
|
|
|
} else {
|
|
|
|
FakeIPv4Hdr *fakehdr = (FakeIPv4Hdr *)aun->iphdr;
|
|
|
|
hdr_length = sizeof(FakeIPv4Hdr);
|
|
|
|
fakehdr->ip4h.ip_len = htons((uint16_t) (hdr_length + buflen));
|
|
|
|
}
|
|
|
|
|
|
|
|
aun->hdr->length = htonl(UNIFIED2_PACKET_SIZE +
|
|
|
|
((p->datalink == DLT_EN10MB) ? 14 : 0) +
|
|
|
|
buflen + hdr_length);
|
|
|
|
aun->phdr->packet_length = htonl(buflen + hdr_length +
|
|
|
|
((p->datalink == DLT_EN10MB) ? 14 : 0));
|
|
|
|
|
|
|
|
aun->length += buflen;
|
|
|
|
if (aun->length > aun->datalen) {
|
|
|
|
SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread"
|
|
|
|
" data: %d vs %d", aun->length, aun->datalen);
|
|
|
|
aun->length = orig_length;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memcpy(aun->data + aun->offset, buf, buflen);
|
|
|
|
|
|
|
|
/* rebuild checksum */
|
|
|
|
if (PKT_IS_IPV6(p)) {
|
|
|
|
FakeIPv6Hdr *fakehdr = (FakeIPv6Hdr *)aun->iphdr;
|
|
|
|
|
|
|
|
fakehdr->tcph.th_sum = TCPV6CalculateChecksum(fakehdr->ip6h.s_ip6_addrs,
|
|
|
|
(uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr));
|
|
|
|
} else {
|
|
|
|
FakeIPv4Hdr *fakehdr = (FakeIPv4Hdr *)aun->iphdr;
|
|
|
|
|
|
|
|
fakehdr->tcph.th_sum = TCPCalculateChecksum(fakehdr->ip4h.s_ip_addrs,
|
|
|
|
(uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr));
|
|
|
|
fakehdr->ip4h.ip_csum = IPV4CalculateChecksum((uint16_t *)&fakehdr->ip4h,
|
|
|
|
IPV4_GET_RAW_HLEN(&fakehdr->ip4h));
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = Unified2Write(aun);
|
|
|
|
if (ret != 1) {
|
|
|
|
aun->length = orig_length;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Function to fill unified2 packet format into the file. If the alert
|
|
|
|
* was generated based on a stream chunk we call the stream function
|
|
|
|
* to generate the record.
|
|
|
|
*
|
|
|
|
* Barnyard2 doesn't like DLT_RAW + IPv6, so if we don't have an ethernet
|
|
|
|
* header, we create a fake one.
|
|
|
|
*
|
|
|
|
* No need to lock here, since it's already locked.
|
|
|
|
*
|
|
|
|
* \param aun thread local data
|
|
|
|
* \param p Packet
|
|
|
|
* \param stream pointer to stream chunk
|
|
|
|
*
|
|
|
|
* \retval 0 on succces
|
|
|
|
* \retval -1 on failure
|
|
|
|
*/
|
|
|
|
int Unified2PacketTypeAlert (Unified2AlertThread *aun, Packet *p, uint32_t event_id, int state)
|
|
|
|
{
|
|
|
|
Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data + aun->offset);
|
|
|
|
Unified2Packet *phdr = (Unified2Packet *)(hdr + 1);
|
|
|
|
int ret = 0;
|
|
|
|
int len = aun->offset + (sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE);
|
|
|
|
int datalink = p->datalink;
|
|
|
|
int ethh_offset = 0;
|
|
|
|
EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) };
|
|
|
|
|
|
|
|
memset(hdr, 0, sizeof(Unified2AlertFileHeader));
|
|
|
|
memset(phdr, 0, sizeof(Unified2Packet));
|
|
|
|
|
|
|
|
hdr->type = htonl(UNIFIED2_PACKET_TYPE);
|
|
|
|
aun->hdr = hdr;
|
|
|
|
|
|
|
|
phdr->sensor_id = 0;
|
|
|
|
phdr->linktype = htonl(datalink);
|
|
|
|
phdr->event_id = event_id;
|
|
|
|
phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec);
|
|
|
|
phdr->packet_microsecond = htonl(p->ts.tv_usec);
|
|
|
|
aun->phdr = phdr;
|
|
|
|
|
|
|
|
if (state) {
|
|
|
|
SCLogDebug("logging the state");
|
|
|
|
uint8_t flag;
|
|
|
|
|
|
|
|
if (p->datalink != DLT_EN10MB) {
|
|
|
|
/* We have raw data here */
|
|
|
|
phdr->linktype = htonl(DLT_RAW);
|
|
|
|
}
|
|
|
|
aun->length = len;
|
|
|
|
|
|
|
|
/* IDS mode reverse the data */
|
|
|
|
/** \todo improve the order selection policy */
|
|
|
|
if (!StreamTcpInlineMode()) {
|
|
|
|
if (p->flowflags & FLOW_PKT_TOSERVER) {
|
|
|
|
flag = FLOW_PKT_TOCLIENT;
|
|
|
|
} else {
|
|
|
|
flag = FLOW_PKT_TOSERVER;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (p->flowflags & FLOW_PKT_TOSERVER) {
|
|
|
|
flag = FLOW_PKT_TOSERVER;
|
|
|
|
} else {
|
|
|
|
flag = FLOW_PKT_TOCLIENT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (aun->length > aun->datalen) {
|
|
|
|
SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d",
|
|
|
|
aun->length, aun->datalen);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
aun->offset += sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE;
|
|
|
|
|
|
|
|
/* Include Packet header */
|
|
|
|
if (PKT_IS_IPV4(p)) {
|
|
|
|
FakeIPv4Hdr fakehdr;
|
|
|
|
uint32_t hdr_length = sizeof(FakeIPv4Hdr);
|
|
|
|
|
|
|
|
if (p->datalink == DLT_EN10MB) {
|
|
|
|
/* Fake this */
|
|
|
|
ethh_offset = 14;
|
|
|
|
datalink = DLT_EN10MB;
|
|
|
|
phdr->linktype = htonl(datalink);
|
|
|
|
aun->length += ethh_offset;
|
|
|
|
if (aun->length > aun->datalen) {
|
|
|
|
SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d",
|
|
|
|
len, aun->datalen - aun->offset);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ethhdr.eth_type = htons(ETHERNET_TYPE_IP);
|
|
|
|
|
|
|
|
memcpy(aun->data + aun->offset, ðhdr, 14);
|
|
|
|
aun->offset += ethh_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&fakehdr, 0, hdr_length);
|
|
|
|
Unified2ForgeFakeIPv4Header(&fakehdr, p, hdr_length, 0);
|
|
|
|
memcpy(aun->data + aun->offset, &fakehdr, hdr_length);
|
|
|
|
aun->iphdr = (void *)(aun->data + aun->offset);
|
|
|
|
aun->offset += hdr_length;
|
|
|
|
aun->length += hdr_length;
|
|
|
|
} else { /* Implied IPv6 */
|
|
|
|
FakeIPv6Hdr fakehdr;
|
|
|
|
uint32_t hdr_length = sizeof(FakeIPv6Hdr);
|
|
|
|
|
|
|
|
if (p->datalink == DLT_EN10MB) {
|
|
|
|
/* Fake this */
|
|
|
|
ethh_offset = 14;
|
|
|
|
datalink = DLT_EN10MB;
|
|
|
|
phdr->linktype = htonl(datalink);
|
|
|
|
aun->length += ethh_offset;
|
|
|
|
if (aun->length > aun->datalen) {
|
|
|
|
SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d",
|
|
|
|
len, aun->datalen - aun->offset);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ethhdr.eth_type = htons(ETHERNET_TYPE_IPV6);
|
|
|
|
|
|
|
|
memcpy(aun->data + aun->offset, ðhdr, 14);
|
|
|
|
aun->offset += ethh_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&fakehdr, 0, hdr_length);
|
|
|
|
Unified2ForgeFakeIPv6Header(&fakehdr, p, hdr_length, 1);
|
|
|
|
aun->length += hdr_length;
|
|
|
|
if (aun->length > aun->datalen) {
|
|
|
|
SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d",
|
|
|
|
aun->length, aun->datalen);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memcpy(aun->data + aun->offset, &fakehdr, hdr_length);
|
|
|
|
aun->iphdr = (void *)(aun->data + aun->offset);
|
|
|
|
aun->offset += hdr_length;
|
|
|
|
}
|
|
|
|
ret = StreamSegmentForEach(p, flag, Unified2PrintStreamSegmentCallback, (void *)aun);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* or no segment could been logged or no segment have been logged */
|
|
|
|
if (ret == 0) {
|
|
|
|
SCLogDebug("no stream, no state: falling back to payload logging");
|
|
|
|
|
|
|
|
/* we need to reset offset and length which could
|
|
|
|
* have been modified by the segment logging */
|
|
|
|
aun->offset = len;
|
|
|
|
len += GET_PKT_LEN(p);
|
|
|
|
aun->length = len;
|
|
|
|
|
|
|
|
/* Unified 2 packet header is the one of the packet. */
|
|
|
|
phdr->linktype = htonl(p->datalink);
|
|
|
|
#ifdef HAVE_OLD_BARNYARD2
|
|
|
|
/* Fake datalink to avoid bug with old barnyard2 */
|
|
|
|
if (PKT_IS_IPV6(p) && (!p->ethh)) {
|
|
|
|
/* Fake this */
|
|
|
|
ethh_offset = 14;
|
|
|
|
datalink = DLT_EN10MB;
|
|
|
|
phdr->linktype = htonl(datalink);
|
|
|
|
aun->length += ethh_offset;
|
|
|
|
if (aun->length > aun->datalen) {
|
|
|
|
SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d",
|
|
|
|
len, aun->datalen - aun->offset);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ethhdr.eth_type = htons(ETHERNET_TYPE_IPV6);
|
|
|
|
|
|
|
|
memcpy(aun->data + aun->offset, ðhdr, 14);
|
|
|
|
aun->offset += ethh_offset;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (len > aun->datalen) {
|
|
|
|
SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d",
|
|
|
|
len, aun->datalen - aun->offset);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
hdr->length = htonl(UNIFIED2_PACKET_SIZE + GET_PKT_LEN(p));
|
|
|
|
phdr->packet_length = htonl(GET_PKT_LEN(p));
|
|
|
|
memcpy(aun->data + aun->offset, GET_PKT_DATA(p), GET_PKT_LEN(p));
|
|
|
|
|
|
|
|
ret = Unified2Write(aun);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret < 1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Function to fill unified2 ipv6 ids type format into the file.
|
|
|
|
*
|
|
|
|
* \param t Thread Variable containing input/output queue, cpu affinity etc.
|
|
|
|
* \param p Packet struct used to decide for ipv4 or ipv6
|
|
|
|
* \param data Unified2 thread data.
|
|
|
|
* \param pq Packet queue
|
|
|
|
*
|
|
|
|
* \retval 0 on succces
|
|
|
|
* \retval -1 on failure
|
|
|
|
*/
|
|
|
|
int Unified2IPv6TypeAlert (ThreadVars *t, Packet *p, void *data, PacketQueue *pq)
|
|
|
|
{
|
|
|
|
Unified2AlertThread *aun = (Unified2AlertThread *)data;
|
|
|
|
Unified2AlertFileHeader hdr;
|
|
|
|
AlertIPv6Unified2 *phdr = (AlertIPv6Unified2 *)(aun->data +
|
|
|
|
sizeof(Unified2AlertFileHeader));
|
|
|
|
AlertIPv6Unified2 gphdr;
|
|
|
|
PacketAlert *pa;
|
|
|
|
int offset, length;
|
|
|
|
int ret;
|
|
|
|
unsigned int event_id;
|
|
|
|
|
|
|
|
if (p->alerts.cnt == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
length = (sizeof(Unified2AlertFileHeader) + sizeof(AlertIPv6Unified2));
|
|
|
|
offset = length;
|
|
|
|
|
|
|
|
memset(aun->data, 0, aun->datalen);
|
|
|
|
|
|
|
|
hdr.type = htonl(UNIFIED2_IDS_EVENT_IPV6_TYPE);
|
|
|
|
hdr.length = htonl(sizeof(AlertIPv6Unified2));
|
|
|
|
|
|
|
|
/* fill the gphdr structure with the data of the packet */
|
|
|
|
memset(&gphdr, 0, sizeof(gphdr));
|
|
|
|
/* FIXME this need to be copied for each alert */
|
|
|
|
gphdr.sensor_id = 0;
|
|
|
|
gphdr.event_second = htonl(p->ts.tv_sec);
|
|
|
|
gphdr.event_microsecond = htonl(p->ts.tv_usec);
|
|
|
|
gphdr.src_ip = *(struct in6_addr*)GET_IPV6_SRC_ADDR(p);
|
|
|
|
gphdr.dst_ip = *(struct in6_addr*)GET_IPV6_DST_ADDR(p);
|
|
|
|
gphdr.protocol = p->proto;
|
|
|
|
|
|
|
|
if(p->action & ACTION_DROP)
|
|
|
|
gphdr.packet_action = UNIFIED2_BLOCKED_FLAG;
|
|
|
|
else
|
|
|
|
gphdr.packet_action = 0;
|
|
|
|
|
|
|
|
switch(gphdr.protocol) {
|
|
|
|
case IPPROTO_ICMPV6:
|
|
|
|
if(p->icmpv6h) {
|
|
|
|
gphdr.sp = htons(p->icmpv6h->type);
|
|
|
|
gphdr.dp = htons(p->icmpv6h->code);
|
|
|
|
} else {
|
|
|
|
gphdr.sp = 0;
|
|
|
|
gphdr.dp = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IPPROTO_ICMP:
|
|
|
|
if(p->icmpv4h) {
|
|
|
|
gphdr.sp = htons(p->icmpv4h->type);
|
|
|
|
gphdr.dp = htons(p->icmpv4h->code);
|
|
|
|
} else {
|
|
|
|
gphdr.sp = 0;
|
|
|
|
gphdr.dp = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IPPROTO_UDP:
|
|
|
|
case IPPROTO_TCP:
|
|
|
|
case IPPROTO_SCTP:
|
|
|
|
gphdr.sp = htons(p->sp);
|
|
|
|
gphdr.dp = htons(p->dp);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gphdr.sp = 0;
|
|
|
|
gphdr.dp = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t i = 0;
|
|
|
|
for (; i < p->alerts.cnt + 1; i++) {
|
|
|
|
/* reset length and offset */
|
|
|
|
aun->offset = offset;
|
|
|
|
aun->length = length;
|
|
|
|
memset(aun->data + aun->offset, 0, aun->datalen - aun->offset);
|
|
|
|
|
|
|
|
if (i < p->alerts.cnt)
|
|
|
|
pa = &p->alerts.alerts[i];
|
|
|
|
else
|
|
|
|
if (p->flags & PKT_HAS_TAG)
|
|
|
|
pa = PacketAlertGetTag();
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (unlikely(pa->s == NULL)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy the part common to all alerts */
|
|
|
|
memcpy(aun->data, &hdr, sizeof(hdr));
|
|
|
|
memcpy(phdr, &gphdr, sizeof(gphdr));
|
|
|
|
/* fill the header structure with the data of the alert */
|
|
|
|
event_id = htonl(SC_ATOMIC_ADD(unified2_event_id, 1));
|
|
|
|
phdr->event_id = event_id;
|
|
|
|
phdr->generator_id = htonl(pa->s->gid);
|
|
|
|
phdr->signature_id = htonl(pa->s->id);
|
|
|
|
phdr->signature_revision = htonl(pa->s->rev);
|
|
|
|
phdr->classification_id = htonl(pa->s->class);
|
|
|
|
phdr->priority_id = htonl(pa->s->prio);
|
|
|
|
|
|
|
|
SCMutexLock(&aun->file_ctx->fp_mutex);
|
|
|
|
if ((aun->file_ctx->size_current + (sizeof(hdr) + sizeof(*phdr))) > aun->file_ctx->size_limit) {
|
|
|
|
if (Unified2AlertRotateFile(t,aun) < 0) {
|
|
|
|
aun->file_ctx->alerts += i;
|
|
|
|
SCMutexUnlock(&aun->file_ctx->fp_mutex);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Unified2Write(aun) != 1) {
|
|
|
|
aun->file_ctx->alerts += i;
|
|
|
|
SCMutexUnlock(&aun->file_ctx->fp_mutex);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(aun->data, 0, aun->length);
|
|
|
|
aun->length = 0;
|
|
|
|
aun->offset = 0;
|
|
|
|
|
|
|
|
ret = Unified2PacketTypeAlert(aun, p, phdr->event_id,
|
|
|
|
pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH) ? 1 : 0);
|
|
|
|
if (ret != 1) {
|
|
|
|
SCLogError(SC_ERR_FWRITE, "Error: fwrite failed: %s", strerror(errno));
|
|
|
|
aun->file_ctx->alerts += i;
|
|
|
|
SCMutexUnlock(&aun->file_ctx->fp_mutex);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
fflush(aun->file_ctx->fp);
|
|
|
|
aun->file_ctx->alerts++;
|
|
|
|
SCMutexUnlock(&aun->file_ctx->fp_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Function to fill unified2 ipv4 ids type format into the file.
|
|
|
|
*
|
|
|
|
* \param t Thread Variable containing input/output queue, cpu affinity etc.
|
|
|
|
* \param p Packet struct used to decide for ipv4 or ipv6
|
|
|
|
* \param data Unified2 thread data.
|
|
|
|
* \param pq Packet queue
|
|
|
|
* \retval 0 on succces
|
|
|
|
* \retval -1 on failure
|
|
|
|
*/
|
|
|
|
|
|
|
|
int Unified2IPv4TypeAlert (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq)
|
|
|
|
{
|
|
|
|
Unified2AlertThread *aun = (Unified2AlertThread *)data;
|
|
|
|
Unified2AlertFileHeader hdr;
|
|
|
|
AlertIPv4Unified2 *phdr = (AlertIPv4Unified2 *)(aun->data +
|
|
|
|
sizeof(Unified2AlertFileHeader));
|
|
|
|
AlertIPv4Unified2 gphdr;
|
|
|
|
PacketAlert *pa;
|
|
|
|
int offset, length;
|
|
|
|
int ret;
|
|
|
|
unsigned int event_id;
|
|
|
|
|
|
|
|
if (p->alerts.cnt == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
length = (sizeof(Unified2AlertFileHeader) + sizeof(AlertIPv4Unified2));
|
|
|
|
offset = length;
|
|
|
|
|
|
|
|
memset(aun->data, 0, aun->datalen);
|
|
|
|
|
|
|
|
hdr.type = htonl(UNIFIED2_IDS_EVENT_TYPE);
|
|
|
|
hdr.length = htonl(sizeof(AlertIPv4Unified2));
|
|
|
|
|
|
|
|
/* fill the gphdr structure with the data of the packet */
|
|
|
|
memset(&gphdr, 0, sizeof(gphdr));
|
|
|
|
gphdr.sensor_id = 0;
|
|
|
|
gphdr.event_id = 0;
|
|
|
|
gphdr.event_second = htonl(p->ts.tv_sec);
|
|
|
|
gphdr.event_microsecond = htonl(p->ts.tv_usec);
|
|
|
|
gphdr.src_ip = p->ip4h->s_ip_src.s_addr;
|
|
|
|
gphdr.dst_ip = p->ip4h->s_ip_dst.s_addr;
|
|
|
|
gphdr.protocol = IPV4_GET_RAW_IPPROTO(p->ip4h);
|
|
|
|
|
|
|
|
if(p->action & ACTION_DROP)
|
|
|
|
gphdr.packet_action = UNIFIED2_BLOCKED_FLAG;
|
|
|
|
else
|
|
|
|
gphdr.packet_action = 0;
|
|
|
|
|
|
|
|
/* TODO inverse order if needed, this should be done on a
|
|
|
|
* alert basis */
|
|
|
|
switch(gphdr.protocol) {
|
|
|
|
case IPPROTO_ICMP:
|
|
|
|
if(p->icmpv4h) {
|
|
|
|
gphdr.sp = htons(p->icmpv4h->type);
|
|
|
|
gphdr.dp = htons(p->icmpv4h->code);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IPPROTO_UDP:
|
|
|
|
case IPPROTO_TCP:
|
|
|
|
case IPPROTO_SCTP:
|
|
|
|
gphdr.sp = htons(p->sp);
|
|
|
|
gphdr.dp = htons(p->dp);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gphdr.sp = 0;
|
|
|
|
gphdr.dp = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t i = 0;
|
|
|
|
for (; i < p->alerts.cnt + 1; i++) {
|
|
|
|
/* reset length and offset */
|
|
|
|
aun->offset = offset;
|
|
|
|
aun->length = length;
|
|
|
|
memset(aun->data + aun->offset, 0, aun->datalen - aun->offset);
|
|
|
|
|
|
|
|
if (i < p->alerts.cnt)
|
|
|
|
pa = &p->alerts.alerts[i];
|
|
|
|
else
|
|
|
|
if (p->flags & PKT_HAS_TAG)
|
|
|
|
pa = PacketAlertGetTag();
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (unlikely(pa->s == NULL)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy the part common to all alerts */
|
|
|
|
memcpy(aun->data, &hdr, sizeof(hdr));
|
|
|
|
memcpy(phdr, &gphdr, sizeof(gphdr));
|
|
|
|
|
|
|
|
/* fill the hdr structure with the alert data */
|
|
|
|
event_id = htonl(SC_ATOMIC_ADD(unified2_event_id, 1));
|
|
|
|
phdr->event_id = event_id;
|
|
|
|
phdr->generator_id = htonl(pa->s->gid);
|
|
|
|
phdr->signature_id = htonl(pa->s->id);
|
|
|
|
phdr->signature_revision = htonl(pa->s->rev);
|
|
|
|
phdr->classification_id = htonl(pa->s->class);
|
|
|
|
phdr->priority_id = htonl(pa->s->prio);
|
|
|
|
|
|
|
|
/* check and enforce the filesize limit */
|
|
|
|
SCMutexLock(&aun->file_ctx->fp_mutex);
|
|
|
|
|
|
|
|
if ((aun->file_ctx->size_current + (sizeof(hdr) + sizeof(*phdr))) > aun->file_ctx->size_limit) {
|
|
|
|
if (Unified2AlertRotateFile(tv,aun) < 0) {
|
|
|
|
aun->file_ctx->alerts += i;
|
|
|
|
SCMutexUnlock(&aun->file_ctx->fp_mutex);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Unified2Write(aun) != 1) {
|
|
|
|
aun->file_ctx->alerts += i;
|
|
|
|
SCMutexUnlock(&aun->file_ctx->fp_mutex);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(aun->data, 0, aun->length);
|
|
|
|
aun->length = 0;
|
|
|
|
aun->offset = 0;
|
|
|
|
|
|
|
|
/* Write the alert (it doesn't lock inside, since we
|
|
|
|
* already locked here for rotation check)
|
|
|
|
*/
|
|
|
|
ret = Unified2PacketTypeAlert(aun, p, event_id, pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH) ? 1 : 0);
|
|
|
|
if (ret != 1) {
|
|
|
|
aun->file_ctx->alerts += i;
|
|
|
|
SCMutexUnlock(&aun->file_ctx->fp_mutex);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
fflush(aun->file_ctx->fp);
|
|
|
|
aun->file_ctx->alerts++;
|
|
|
|
SCMutexUnlock(&aun->file_ctx->fp_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Thread init function.
|
|
|
|
*
|
|
|
|
* \param t Thread Variable containing input/output queue, cpu affinity etc.
|
|
|
|
* \param initdata Unified2 thread initial data.
|
|
|
|
* \param data Unified2 thread data.
|
|
|
|
* \retval TM_ECODE_OK on succces
|
|
|
|
* \retval TM_ECODE_FAILED on failure
|
|
|
|
*/
|
|
|
|
|
|
|
|
TmEcode Unified2AlertThreadInit(ThreadVars *t, void *initdata, void **data)
|
|
|
|
{
|
|
|
|
Unified2AlertThread *aun = SCMalloc(sizeof(Unified2AlertThread));
|
|
|
|
if (aun == NULL)
|
|
|
|
return TM_ECODE_FAILED;
|
|
|
|
memset(aun, 0, sizeof(Unified2AlertThread));
|
|
|
|
if(initdata == NULL)
|
|
|
|
{
|
|
|
|
SCLogDebug("Error getting context for Unified2Alert. \"initdata\" argument NULL");
|
|
|
|
SCFree(aun);
|
|
|
|
return TM_ECODE_FAILED;
|
|
|
|
}
|
|
|
|
/** Use the Ouptut Context (file pointer and mutex) */
|
|
|
|
aun->file_ctx = ((OutputCtx *)initdata)->data;
|
|
|
|
|
|
|
|
aun->data = SCMalloc(sizeof(Unified2AlertFileHeader) + sizeof(Unified2Packet) + IPV4_MAXPACKET_LEN);
|
|
|
|
if (aun->data == NULL) {
|
|
|
|
SCFree(aun);
|
|
|
|
return TM_ECODE_FAILED;
|
|
|
|
}
|
|
|
|
aun->datalen = sizeof(Unified2AlertFileHeader) + sizeof(Unified2Packet) + IPV4_MAXPACKET_LEN;
|
|
|
|
|
|
|
|
*data = (void *)aun;
|
|
|
|
|
|
|
|
return TM_ECODE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Thread deinit function.
|
|
|
|
*
|
|
|
|
* \param t Thread Variable containing input/output queue, cpu affinity etc.
|
|
|
|
* \param data Unified2 thread data.
|
|
|
|
* \retval TM_ECODE_OK on succces
|
|
|
|
* \retval TM_ECODE_FAILED on failure
|
|
|
|
*/
|
|
|
|
|
|
|
|
TmEcode Unified2AlertThreadDeinit(ThreadVars *t, void *data)
|
|
|
|
{
|
|
|
|
Unified2AlertThread *aun = (Unified2AlertThread *)data;
|
|
|
|
if (aun == NULL) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(aun->file_ctx->flags & LOGFILE_ALERTS_PRINTED)) {
|
|
|
|
SCLogInfo("Alert unified2 module wrote %"PRIu64" alerts",
|
|
|
|
aun->file_ctx->alerts);
|
|
|
|
|
|
|
|
/* Do not print it for each thread */
|
|
|
|
aun->file_ctx->flags |= LOGFILE_ALERTS_PRINTED;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aun->data != NULL) {
|
|
|
|
SCFree(aun->data);
|
|
|
|
aun->data = NULL;
|
|
|
|
}
|
|
|
|
aun->datalen = 0;
|
|
|
|
/* clear memory */
|
|
|
|
memset(aun, 0, sizeof(Unified2AlertThread));
|
|
|
|
SCFree(aun);
|
|
|
|
return TM_ECODE_OK;
|
|
|
|
|
|
|
|
error:
|
|
|
|
return TM_ECODE_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Create a new LogFileCtx from the provided ConfNode.
|
|
|
|
* \param conf The configuration node for this output.
|
|
|
|
* \return NULL if failure, LogFileCtx* to the file_ctx if succesful
|
|
|
|
* */
|
|
|
|
OutputCtx *Unified2AlertInitCtx(ConfNode *conf)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
LogFileCtx* file_ctx = NULL;
|
|
|
|
|
|
|
|
file_ctx = LogFileNewCtx();
|
|
|
|
if (file_ctx == NULL) {
|
|
|
|
SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC, "Couldn't create new file_ctx");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *filename = NULL;
|
|
|
|
if (conf != NULL) { /* To faciliate unit tests. */
|
|
|
|
filename = ConfNodeLookupChildValue(conf, "filename");
|
|
|
|
}
|
|
|
|
if (filename == NULL)
|
|
|
|
filename = DEFAULT_LOG_FILENAME;
|
|
|
|
file_ctx->prefix = SCStrdup(filename);
|
|
|
|
|
|
|
|
const char *s_limit = NULL;
|
|
|
|
file_ctx->size_limit = DEFAULT_LIMIT;
|
|
|
|
if (conf != NULL) {
|
|
|
|
s_limit = ConfNodeLookupChildValue(conf, "limit");
|
|
|
|
if (s_limit != NULL) {
|
|
|
|
if (ParseSizeStringU64(s_limit, &file_ctx->size_limit) < 0) {
|
|
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT,
|
|
|
|
"Failed to initialize unified2 output, invalid limit: %s",
|
|
|
|
s_limit);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
if (file_ctx->size_limit < 4096) {
|
|
|
|
SCLogInfo("unified2-alert \"limit\" value of %"PRIu64" assumed to be pre-1.2 "
|
|
|
|
"style: setting limit to %"PRIu64"mb", file_ctx->size_limit, file_ctx->size_limit);
|
|
|
|
uint64_t size = file_ctx->size_limit * 1024 * 1024;
|
|
|
|
file_ctx->size_limit = size;
|
|
|
|
} else if (file_ctx->size_limit < MIN_LIMIT) {
|
|
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT,
|
|
|
|
"Failed to initialize unified2 output, limit less than "
|
|
|
|
"allowed minimum: %d.", MIN_LIMIT);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = Unified2AlertOpenFileCtx(file_ctx, filename);
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
|
|
|
|
if (output_ctx == NULL)
|
|
|
|
goto error;
|
|
|
|
output_ctx->data = file_ctx;
|
|
|
|
output_ctx->DeInit = Unified2AlertDeInitCtx;
|
|
|
|
|
|
|
|
SCLogInfo("Unified2-alert initialized: filename %s, limit %"PRIu64" MB",
|
|
|
|
filename, file_ctx->size_limit / (1024*1024));
|
|
|
|
|
|
|
|
SC_ATOMIC_INIT(unified2_event_id);
|
|
|
|
|
|
|
|
return output_ctx;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (file_ctx != NULL) {
|
|
|
|
LogFileFreeCtx(file_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Unified2AlertDeInitCtx(OutputCtx *output_ctx)
|
|
|
|
{
|
|
|
|
if (output_ctx != NULL) {
|
|
|
|
LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data;
|
|
|
|
if (logfile_ctx != NULL) {
|
|
|
|
LogFileFreeCtx(logfile_ctx);
|
|
|
|
}
|
|
|
|
SCFree(output_ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Read the config set the file pointer, open the file
|
|
|
|
* \param file_ctx pointer to a created LogFileCtx using LogFileNewCtx()
|
|
|
|
* \param prefix Prefix of the log file.
|
|
|
|
* \return -1 if failure, 0 if succesful
|
|
|
|
* */
|
|
|
|
int Unified2AlertOpenFileCtx(LogFileCtx *file_ctx, const char *prefix)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
char *filename = NULL;
|
|
|
|
if (file_ctx->filename != NULL)
|
|
|
|
filename = file_ctx->filename;
|
|
|
|
else {
|
|
|
|
filename = file_ctx->filename = SCMalloc(PATH_MAX); /* XXX some sane default? */
|
|
|
|
if (filename == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
memset(filename, 0x00, PATH_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** get the time so we can have a filename with seconds since epoch */
|
|
|
|
struct timeval ts;
|
|
|
|
memset(&ts, 0x00, sizeof(struct timeval));
|
|
|
|
|
|
|
|
extern int run_mode;
|
|
|
|
if (run_mode == RUNMODE_UNITTEST)
|
|
|
|
TimeGet(&ts);
|
|
|
|
else
|
|
|
|
gettimeofday(&ts, NULL);
|
|
|
|
|
|
|
|
/* create the filename to use */
|
|
|
|
char *log_dir;
|
|
|
|
if (ConfGet("default-log-dir", &log_dir) != 1)
|
|
|
|
log_dir = DEFAULT_LOG_DIR;
|
|
|
|
|
|
|
|
snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, log_dir, prefix, (uint32_t)ts.tv_sec);
|
|
|
|
|
|
|
|
file_ctx->fp = fopen(filename, "wb");
|
|
|
|
if (file_ctx->fp == NULL) {
|
|
|
|
SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", filename,
|
|
|
|
strerror(errno));
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef UNITTESTS
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \test Test the ethernet+ipv4+tcp unified2 test
|
|
|
|
*
|
|
|
|
* \retval 1 on succces
|
|
|
|
* \retval 0 on failure
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int Unified2Test01 (void) {
|
|
|
|
ThreadVars tv;
|
|
|
|
DecodeThreadVars dtv;
|
|
|
|
PacketQueue pq;
|
|
|
|
void *data = NULL;
|
|
|
|
OutputCtx *oc;
|
|
|
|
LogFileCtx *lf;
|
|
|
|
Signature s;
|
|
|
|
|
|
|
|
uint8_t raw_ipv4_tcp[] = {
|
|
|
|
0x00, 0x14, 0xbf, 0xe8, 0xcb, 0x26, 0xaa, 0x00,
|
|
|
|
0x04, 0x00, 0x0a, 0x04, 0x08, 0x00, 0x45, 0x00,
|
|
|
|
0x00, 0x3c, 0x8c, 0x55, 0x40, 0x00, 0x40, 0x06,
|
|
|
|
0x69, 0x86, 0xc0, 0xa8, 0x0a, 0x68, 0x4a, 0x7d,
|
|
|
|
0x2f, 0x53, 0xc2, 0x40, 0x00, 0x50, 0x1f, 0x00,
|
|
|
|
0xa4, 0xd4, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
|
|
|
|
0x16, 0xd0, 0x3d, 0x4e, 0x00, 0x00, 0x02, 0x04,
|
|
|
|
0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x00, 0x1c,
|
|
|
|
0x28, 0x81, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03,
|
|
|
|
0x03, 0x06};
|
|
|
|
Packet *p = SCMalloc(SIZE_OF_PACKET);
|
|
|
|
if (p == NULL)
|
|
|
|
return 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
memset(&dtv, 0, sizeof(DecodeThreadVars));
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
memset(&pq, 0, sizeof(PacketQueue));
|
|
|
|
memset(p, 0, SIZE_OF_PACKET);
|
|
|
|
p->pkt = (uint8_t *)(p + 1);
|
|
|
|
memset(&s, 0, sizeof(Signature));
|
|
|
|
|
|
|
|
PACKET_INITIALIZE(p);
|
|
|
|
|
|
|
|
p->alerts.cnt++;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s = &s;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->id = 1;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->gid = 1;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->rev = 1;
|
|
|
|
SET_PKT_LEN(p, sizeof(raw_ipv4_tcp));
|
|
|
|
|
|
|
|
FlowInitConfig(FLOW_QUIET);
|
|
|
|
|
|
|
|
DecodeEthernet(&tv, &dtv, p, raw_ipv4_tcp, sizeof(raw_ipv4_tcp), &pq);
|
|
|
|
|
|
|
|
FlowShutdown();
|
|
|
|
|
|
|
|
oc = Unified2AlertInitCtx(NULL);
|
|
|
|
if (oc == NULL) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
lf = (LogFileCtx *)oc->data;
|
|
|
|
if(lf == NULL) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadInit(&tv, oc, &data);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2Alert(&tv, p, data, &pq, NULL);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadDeinit(&tv, data);
|
|
|
|
if(ret == -1) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Unified2AlertDeInitCtx(oc);
|
|
|
|
|
|
|
|
PACKET_CLEANUP(p);
|
|
|
|
SCFree(p);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \test Test the ethernet+ipv6+tcp unified2 test
|
|
|
|
*
|
|
|
|
* \retval 1 on succces
|
|
|
|
* \retval 0 on failure
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int Unified2Test02 (void) {
|
|
|
|
ThreadVars tv;
|
|
|
|
DecodeThreadVars dtv;
|
|
|
|
PacketQueue pq;
|
|
|
|
void *data = NULL;
|
|
|
|
OutputCtx *oc;
|
|
|
|
LogFileCtx *lf;
|
|
|
|
Signature s;
|
|
|
|
|
|
|
|
uint8_t raw_ipv6_tcp[] = {
|
|
|
|
0x00, 0x11, 0x25, 0x82, 0x95, 0xb5, 0x00, 0xd0,
|
|
|
|
0x09, 0xe3, 0xe8, 0xde, 0x86, 0xdd, 0x60, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x28, 0x06, 0x40, 0x20, 0x01,
|
|
|
|
0x06, 0xf8, 0x10, 0x2d, 0x00, 0x00, 0x02, 0xd0,
|
|
|
|
0x09, 0xff, 0xfe, 0xe3, 0xe8, 0xde, 0x20, 0x01,
|
|
|
|
0x06, 0xf8, 0x09, 0x00, 0x07, 0xc0, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe7, 0x41,
|
|
|
|
0x00, 0x50, 0xab, 0xdc, 0xd6, 0x60, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0xa0, 0x02, 0x16, 0x80, 0x41, 0xa2,
|
|
|
|
0x00, 0x00, 0x02, 0x04, 0x05, 0xa0, 0x04, 0x02,
|
|
|
|
0x08, 0x0a, 0x00, 0x0a, 0x22, 0xa8, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x01, 0x03, 0x03, 0x05 };
|
|
|
|
Packet *p = SCMalloc(SIZE_OF_PACKET);
|
|
|
|
if (p == NULL)
|
|
|
|
return 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
memset(&dtv, 0, sizeof(DecodeThreadVars));
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
memset(&pq, 0, sizeof(PacketQueue));
|
|
|
|
memset(p, 0, SIZE_OF_PACKET);
|
|
|
|
p->pkt = (uint8_t *)(p + 1);
|
|
|
|
memset(&s, 0, sizeof(Signature));
|
|
|
|
|
|
|
|
PACKET_INITIALIZE(p);
|
|
|
|
|
|
|
|
p->alerts.cnt++;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s = &s;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->id = 1;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->gid = 1;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->rev = 1;
|
|
|
|
SET_PKT_LEN(p, sizeof(raw_ipv6_tcp));
|
|
|
|
|
|
|
|
FlowInitConfig(FLOW_QUIET);
|
|
|
|
|
|
|
|
DecodeEthernet(&tv, &dtv, p, raw_ipv6_tcp, sizeof(raw_ipv6_tcp), &pq);
|
|
|
|
|
|
|
|
FlowShutdown();
|
|
|
|
|
|
|
|
oc = Unified2AlertInitCtx(NULL);
|
|
|
|
if (oc == NULL) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
lf = (LogFileCtx *)oc->data;
|
|
|
|
if(lf == NULL) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadInit(&tv, oc, &data);
|
|
|
|
if(ret == -1) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2Alert(&tv, p, data, &pq, NULL);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadDeinit(&tv, data);
|
|
|
|
if(ret == -1) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Unified2AlertDeInitCtx(oc);
|
|
|
|
|
|
|
|
PACKET_CLEANUP(p);
|
|
|
|
SCFree(p);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \test Test the GRE unified2 test
|
|
|
|
*
|
|
|
|
* \retval 1 on succces
|
|
|
|
* \retval 0 on failure
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int Unified2Test03 (void) {
|
|
|
|
ThreadVars tv;
|
|
|
|
DecodeThreadVars dtv;
|
|
|
|
PacketQueue pq;
|
|
|
|
void *data = NULL;
|
|
|
|
OutputCtx *oc;
|
|
|
|
LogFileCtx *lf;
|
|
|
|
Signature s;
|
|
|
|
|
|
|
|
uint8_t raw_gre[] = {
|
|
|
|
0x00, 0x0e, 0x50, 0x06, 0x42, 0x96, 0xaa, 0x00,
|
|
|
|
0x04, 0x00, 0x0a, 0x04, 0x08, 0x00, 0x45, 0x00,
|
|
|
|
0x00, 0x74, 0x35, 0xa2, 0x40, 0x00, 0x40, 0x2f,
|
|
|
|
0xef, 0xcb, 0x0a, 0x00, 0x00, 0x64, 0x0a, 0x00,
|
|
|
|
0x00, 0x8a, 0x30, 0x01, 0x88, 0x0b, 0x00, 0x54,
|
|
|
|
0x00, 0x00, 0x00, 0x18, 0x29, 0x5f, 0xff, 0x03,
|
|
|
|
0x00, 0x21, 0x45, 0x00, 0x00, 0x50, 0xf4, 0x05,
|
|
|
|
0x40, 0x00, 0x3f, 0x06, 0x20, 0xb8, 0x50, 0x7e,
|
|
|
|
0x2b, 0x2d, 0xd4, 0xcc, 0xd6, 0x72, 0x0a, 0x92,
|
|
|
|
0x1a, 0x0b, 0xc9, 0xaf, 0x24, 0x02, 0x8c, 0xdd,
|
|
|
|
0x45, 0xf6, 0x80, 0x18, 0x21, 0xfc, 0x10, 0x7c,
|
|
|
|
0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x08, 0x19,
|
|
|
|
0x1a, 0xda, 0x84, 0xd6, 0xda, 0x3e, 0x50, 0x49,
|
|
|
|
0x4e, 0x47, 0x20, 0x73, 0x74, 0x65, 0x72, 0x6c,
|
|
|
|
0x69, 0x6e, 0x67, 0x2e, 0x66, 0x72, 0x65, 0x65,
|
|
|
|
0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x65, 0x74,
|
|
|
|
0x0d, 0x0a};
|
|
|
|
Packet *p = SCMalloc(SIZE_OF_PACKET);
|
|
|
|
if (p == NULL)
|
|
|
|
return 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
memset(&dtv, 0, sizeof(DecodeThreadVars));
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
memset(&pq, 0, sizeof(PacketQueue));
|
|
|
|
memset(p, 0, SIZE_OF_PACKET);
|
|
|
|
p->pkt = (uint8_t *)(p + 1);
|
|
|
|
memset(&s, 0, sizeof(Signature));
|
|
|
|
|
|
|
|
PACKET_INITIALIZE(p);
|
|
|
|
|
|
|
|
p->alerts.cnt++;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s = &s;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->id = 1;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->gid = 1;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->rev = 1;
|
|
|
|
SET_PKT_LEN(p, sizeof(raw_gre));
|
|
|
|
|
|
|
|
FlowInitConfig(FLOW_QUIET);
|
|
|
|
|
|
|
|
DecodeEthernet(&tv, &dtv, p, raw_gre, sizeof(raw_gre), &pq);
|
|
|
|
|
|
|
|
FlowShutdown();
|
|
|
|
|
|
|
|
oc = Unified2AlertInitCtx(NULL);
|
|
|
|
if (oc == NULL) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
lf = (LogFileCtx *)oc->data;
|
|
|
|
if(lf == NULL) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadInit(&tv, oc, &data);
|
|
|
|
if(ret == -1) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2Alert(&tv, p, data, &pq, NULL);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadDeinit(&tv, data);
|
|
|
|
if(ret == -1) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Unified2AlertDeInitCtx(oc);
|
|
|
|
|
|
|
|
Packet *pkt = PacketDequeue(&pq);
|
|
|
|
while (pkt != NULL) {
|
|
|
|
SCFree(pkt);
|
|
|
|
pkt = PacketDequeue(&pq);
|
|
|
|
}
|
|
|
|
|
|
|
|
PACKET_CLEANUP(p);
|
|
|
|
SCFree(p);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \test Test the PPP unified2 test
|
|
|
|
*
|
|
|
|
* \retval 1 on succces
|
|
|
|
* \retval 0 on failure
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int Unified2Test04 (void) {
|
|
|
|
ThreadVars tv;
|
|
|
|
DecodeThreadVars dtv;
|
|
|
|
PacketQueue pq;
|
|
|
|
void *data = NULL;
|
|
|
|
OutputCtx *oc;
|
|
|
|
LogFileCtx *lf;
|
|
|
|
Signature s;
|
|
|
|
|
|
|
|
uint8_t raw_ppp[] = {
|
|
|
|
0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c,
|
|
|
|
0x4d, 0xed, 0x00, 0x00, 0xff, 0x06, 0xd5, 0x17,
|
|
|
|
0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03,
|
|
|
|
0xea, 0x37, 0x00, 0x17, 0x6d, 0x0b, 0xba, 0xc3,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20,
|
|
|
|
0xdd, 0xe1, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4};
|
|
|
|
Packet *p = SCMalloc(SIZE_OF_PACKET);
|
|
|
|
if (p == NULL)
|
|
|
|
return 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
memset(&dtv, 0, sizeof(DecodeThreadVars));
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
memset(&pq, 0, sizeof(PacketQueue));
|
|
|
|
memset(p, 0, SIZE_OF_PACKET);
|
|
|
|
p->pkt = (uint8_t *)(p + 1);
|
|
|
|
memset(&s, 0, sizeof(Signature));
|
|
|
|
|
|
|
|
PACKET_INITIALIZE(p);
|
|
|
|
|
|
|
|
p->alerts.cnt++;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s = &s;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->id = 1;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->gid = 1;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->rev = 1;
|
|
|
|
SET_PKT_LEN(p, sizeof(raw_ppp));
|
|
|
|
|
|
|
|
FlowInitConfig(FLOW_QUIET);
|
|
|
|
|
|
|
|
DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp), &pq);
|
|
|
|
|
|
|
|
FlowShutdown();
|
|
|
|
|
|
|
|
oc = Unified2AlertInitCtx(NULL);
|
|
|
|
if (oc == NULL) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
lf = (LogFileCtx *)oc->data;
|
|
|
|
if(lf == NULL) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadInit(&tv, oc, &data);
|
|
|
|
if(ret == -1) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2Alert(&tv, p, data, &pq, NULL);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadDeinit(&tv, data);
|
|
|
|
if(ret == -1) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Unified2AlertDeInitCtx(oc);
|
|
|
|
|
|
|
|
PACKET_CLEANUP(p);
|
|
|
|
SCFree(p);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \test Test the ethernet+ipv4+tcp droped unified2 test
|
|
|
|
*
|
|
|
|
* \retval 1 on succces
|
|
|
|
* \retval 0 on failure
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int Unified2Test05 (void) {
|
|
|
|
ThreadVars tv;
|
|
|
|
DecodeThreadVars dtv;
|
|
|
|
PacketQueue pq;
|
|
|
|
void *data = NULL;
|
|
|
|
OutputCtx *oc;
|
|
|
|
LogFileCtx *lf;
|
|
|
|
Signature s;
|
|
|
|
|
|
|
|
uint8_t raw_ipv4_tcp[] = {
|
|
|
|
0x00, 0x14, 0xbf, 0xe8, 0xcb, 0x26, 0xaa, 0x00,
|
|
|
|
0x04, 0x00, 0x0a, 0x04, 0x08, 0x00, 0x45, 0x00,
|
|
|
|
0x00, 0x3c, 0x8c, 0x55, 0x40, 0x00, 0x40, 0x06,
|
|
|
|
0x69, 0x86, 0xc0, 0xa8, 0x0a, 0x68, 0x4a, 0x7d,
|
|
|
|
0x2f, 0x53, 0xc2, 0x40, 0x00, 0x50, 0x1f, 0x00,
|
|
|
|
0xa4, 0xd4, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
|
|
|
|
0x16, 0xd0, 0x3d, 0x4e, 0x00, 0x00, 0x02, 0x04,
|
|
|
|
0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x00, 0x1c,
|
|
|
|
0x28, 0x81, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03,
|
|
|
|
0x03, 0x06};
|
|
|
|
Packet *p = SCMalloc(SIZE_OF_PACKET);
|
|
|
|
if (p == NULL)
|
|
|
|
return 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
memset(&dtv, 0, sizeof(DecodeThreadVars));
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
memset(&pq, 0, sizeof(PacketQueue));
|
|
|
|
memset(p, 0, SIZE_OF_PACKET);
|
|
|
|
p->pkt = (uint8_t *)(p + 1);
|
|
|
|
memset(&s, 0, sizeof(Signature));
|
|
|
|
|
|
|
|
PACKET_INITIALIZE(p);
|
|
|
|
|
|
|
|
p->alerts.cnt++;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s = &s;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->id = 1;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->gid = 1;
|
|
|
|
p->alerts.alerts[p->alerts.cnt-1].s->rev = 1;
|
|
|
|
SET_PKT_LEN(p, sizeof(raw_ipv4_tcp));
|
|
|
|
|
|
|
|
FlowInitConfig(FLOW_QUIET);
|
|
|
|
|
|
|
|
DecodeEthernet(&tv, &dtv, p, raw_ipv4_tcp, sizeof(raw_ipv4_tcp), &pq);
|
|
|
|
|
|
|
|
FlowShutdown();
|
|
|
|
|
|
|
|
p->action = ACTION_DROP;
|
|
|
|
|
|
|
|
oc = Unified2AlertInitCtx(NULL);
|
|
|
|
if (oc == NULL) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
lf = (LogFileCtx *)oc->data;
|
|
|
|
if(lf == NULL) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadInit(&tv, oc, &data);
|
|
|
|
if(ret == -1) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2Alert(&tv, p, data, &pq, NULL);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadDeinit(&tv, data);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
SCFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Unified2AlertDeInitCtx(oc);
|
|
|
|
|
|
|
|
PACKET_CLEANUP(p);
|
|
|
|
SCFree(p);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \test Test the Rotate process
|
|
|
|
*
|
|
|
|
* \retval 1 on succces
|
|
|
|
* \retval 0 on failure
|
|
|
|
*/
|
|
|
|
static int Unified2TestRotate01(void)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int r = 0;
|
|
|
|
ThreadVars tv;
|
|
|
|
OutputCtx *oc;
|
|
|
|
LogFileCtx *lf;
|
|
|
|
void *data = NULL;
|
|
|
|
char *filename = NULL;
|
|
|
|
|
|
|
|
oc = Unified2AlertInitCtx(NULL);
|
|
|
|
if (oc == NULL)
|
|
|
|
return 0;
|
|
|
|
lf = (LogFileCtx *)oc->data;
|
|
|
|
if (lf == NULL)
|
|
|
|
return 0;
|
|
|
|
filename = SCStrdup(lf->filename);
|
|
|
|
if (filename == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
|
|
|
|
ret = Unified2AlertThreadInit(&tv, oc, &data);
|
|
|
|
if (ret == TM_ECODE_FAILED) {
|
|
|
|
LogFileFreeCtx(lf);
|
|
|
|
if (filename != NULL)
|
|
|
|
SCFree(filename);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimeSetIncrementTime(1);
|
|
|
|
|
|
|
|
ret = Unified2AlertRotateFile(&tv, data);
|
|
|
|
if (ret == -1)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (strcmp(filename, lf->filename) == 0) {
|
|
|
|
SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC,
|
|
|
|
"filename \"%s\" == \"%s\": ", filename, lf->filename);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = 1;
|
|
|
|
|
|
|
|
error:
|
|
|
|
ret = Unified2AlertThreadDeinit(&tv, data);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
printf("Unified2AlertThreadDeinit error");
|
|
|
|
}
|
|
|
|
if (oc != NULL)
|
|
|
|
Unified2AlertDeInitCtx(oc);
|
|
|
|
if (filename != NULL)
|
|
|
|
SCFree(filename);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief this function registers unit tests for Unified2
|
|
|
|
*/
|
|
|
|
void Unified2RegisterTests (void) {
|
|
|
|
#ifdef UNITTESTS
|
|
|
|
UtRegisterTest("Unified2Test01 -- Ipv4 test", Unified2Test01, 1);
|
|
|
|
UtRegisterTest("Unified2Test02 -- Ipv6 test", Unified2Test02, 1);
|
|
|
|
UtRegisterTest("Unified2Test03 -- GRE test", Unified2Test03, 1);
|
|
|
|
UtRegisterTest("Unified2Test04 -- PPP test", Unified2Test04, 1);
|
|
|
|
UtRegisterTest("Unified2Test05 -- Inline test", Unified2Test05, 1);
|
|
|
|
UtRegisterTest("Unified2TestRotate01 -- Rotate File", Unified2TestRotate01, 1);
|
|
|
|
#endif /* UNITTESTS */
|
|
|
|
}
|