|
|
|
/* Copyright (C) 2007-2014 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>
|
|
|
|
* \author Ignacio Sanchez <sanchezmartin.ji@gmail.com>
|
|
|
|
* \author Duarte Silva <duarte.silva@serializing.me>
|
|
|
|
*
|
|
|
|
* 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"
|
|
|
|
|
App layer API rewritten. The main files in question are:
app-layer.[ch], app-layer-detect-proto.[ch] and app-layer-parser.[ch].
Things addressed in this commit:
- Brings out a proper separation between protocol detection phase and the
parser phase.
- The dns app layer now is registered such that we don't use "dnstcp" and
"dnsudp" in the rules. A user who previously wrote a rule like this -
"alert dnstcp....." or
"alert dnsudp....."
would now have to use,
alert dns (ipproto:tcp;) or
alert udp (app-layer-protocol:dns;) or
alert ip (ipproto:udp; app-layer-protocol:dns;)
The same rules extend to other another such protocol, dcerpc.
- The app layer parser api now takes in the ipproto while registering
callbacks.
- The app inspection/detection engine also takes an ipproto.
- All app layer parser functions now take direction as STREAM_TOSERVER or
STREAM_TOCLIENT, as opposed to 0 or 1, which was taken by some of the
functions.
- FlowInitialize() and FlowRecycle() now resets proto to 0. This is
needed by unittests, which would try to clean the flow, and that would
call the api, AppLayerParserCleanupParserState(), which would try to
clean the app state, but the app layer now needs an ipproto to figure
out which api to internally call to clean the state, and if the ipproto
is 0, it would return without trying to clean the state.
- A lot of unittests are now updated where if they are using a flow and
they need to use the app layer, we would set a flow ipproto.
- The "app-layer" section in the yaml conf has also been updated as well.
12 years ago
|
|
|
#include "flow.h"
|
|
|
|
|
|
|
|
#include "host.h"
|
|
|
|
#include "util-profiling.h"
|
|
|
|
#include "decode.h"
|
|
|
|
|
|
|
|
#include "util-error.h"
|
|
|
|
#include "util-debug.h"
|
|
|
|
#include "util-time.h"
|
|
|
|
#include "util-byte.h"
|
|
|
|
#include "util-misc.h"
|
Add option on Tile-Gx for logging for fast.log alerts over PCIe
When running on a TILEncore-Gx PCIe card, setting the filetype of fast.log
to pcie, will open a connection over PCIe to a host application caleld
tile-pcie-logd, that receives the alert strings and writes them to a file
on the host. The file name to open is also passed over the PCIe link.
This allows running Suricata on the TILEncore-Gx PCIe card, but have the
alerts logged to the host system's file system efficiently. The PCIe API that
is used is the Tilera Packet Queue (PQ) API which can access PCIe from User
Space, thus avoiding system calls.
Created util-logopenfile-tile.c and util-logopen-tile.h for the TILE
specific PCIe logging functionality.
Using Write() and Close() function pointers in LogFileCtx, which
default to standard write and close for files and sockets, but are
changed to PCIe write and close functions when a PCIe channel is
openned for logging.
Moved Logging contex out of tm-modules.h into util-logopenfile.h,
where it makes more sense. This required including util-logopenfile.h
into a couple of alert-*.c files, which previously were getting the
definitions from tm-modules.h.
The source and Makefile for tile-pcie-logd are added in contrib/tile-pcie-logd.
By default, the file name for fast.log specified in suricata.yaml is used as
the filename on the host. An optional argument to tile-pcie-logd, --prefix=,
can be added to prepend the supplied file path. For example, is the file
in suricata.yaml is specified as "/var/log/fast.log" and --prefix="/tmp",
then the file will be written to "/tmp/var/log/fast.log".
Check for TILERA_ROOT environment variable before building tile_pcie_logd
Building tile_pcie_logd on x86 requires the Tilera MDE for its PCIe libraries
and API header files. Configure now checs for TILERA_ROOT before enabling
builing tile_pcie_logd in contrib/tile_pcie_logd
12 years ago
|
|
|
#include "util-logopenfile.h"
|
|
|
|
|
App layer API rewritten. The main files in question are:
app-layer.[ch], app-layer-detect-proto.[ch] and app-layer-parser.[ch].
Things addressed in this commit:
- Brings out a proper separation between protocol detection phase and the
parser phase.
- The dns app layer now is registered such that we don't use "dnstcp" and
"dnsudp" in the rules. A user who previously wrote a rule like this -
"alert dnstcp....." or
"alert dnsudp....."
would now have to use,
alert dns (ipproto:tcp;) or
alert udp (app-layer-protocol:dns;) or
alert ip (ipproto:udp; app-layer-protocol:dns;)
The same rules extend to other another such protocol, dcerpc.
- The app layer parser api now takes in the ipproto while registering
callbacks.
- The app inspection/detection engine also takes an ipproto.
- All app layer parser functions now take direction as STREAM_TOSERVER or
STREAM_TOCLIENT, as opposed to 0 or 1, which was taken by some of the
functions.
- FlowInitialize() and FlowRecycle() now resets proto to 0. This is
needed by unittests, which would try to clean the flow, and that would
call the api, AppLayerParserCleanupParserState(), which would try to
clean the app state, but the app layer now needs an ipproto to figure
out which api to internally call to clean the state, and if the ipproto
is 0, it would return without trying to clean the state.
- A lot of unittests are now updated where if they are using a flow and
they need to use the app layer, we would set a flow ipproto.
- The "app-layer" section in the yaml conf has also been updated as well.
12 years ago
|
|
|
#include "app-layer-parser.h"
|
|
|
|
#include "app-layer-htp.h"
|
|
|
|
#include "app-layer.h"
|
|
|
|
#include "app-layer-htp-xff.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
|
|
|
|
|
|
|
|
/* Default Sensor ID value */
|
|
|
|
static uint32_t sensor_id = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unified2 Extra Data Header
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
typedef struct Unified2ExtraDataHdr_ {
|
|
|
|
uint32_t event_type;
|
|
|
|
uint32_t event_length;
|
|
|
|
} __attribute__((__packed__)) Unified2ExtraDataHdr;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unified2 Extra Data (currently used only for XFF)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
typedef struct Unified2ExtraData_ {
|
|
|
|
uint32_t sensor_id;
|
|
|
|
uint32_t event_id;
|
|
|
|
uint32_t event_second;
|
|
|
|
uint32_t type; /* EventInfo */
|
|
|
|
uint32_t data_type; /*EventDataType */
|
|
|
|
uint32_t blob_length; /* Length of the data + sizeof(blob_length) + sizeof(data_type)*/
|
|
|
|
} Unified2ExtraData;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
/** Extracted XFF IP is v4 */
|
|
|
|
#define UNIFIED2_ALERT_XFF_IPV4 8
|
|
|
|
/** Extracted XFF IP is v4 */
|
|
|
|
#define UNIFIED2_ALERT_XFF_IPV6 16
|
|
|
|
|
|
|
|
typedef struct Unified2AlertFileCtx_ {
|
|
|
|
LogFileCtx *file_ctx;
|
|
|
|
HttpXFFCfg *xff_cfg;
|
|
|
|
} Unified2AlertFileCtx;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unified2 thread vars
|
|
|
|
*
|
|
|
|
* Used for storing file options.
|
|
|
|
*/
|
|
|
|
typedef struct Unified2AlertThread_ {
|
|
|
|
Unified2AlertFileCtx *unified2alert_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 */
|
|
|
|
uint8_t xff_flags; /**< XFF flags for the current alert */
|
|
|
|
uint32_t xff_ip[4]; /**< The XFF reported IP address for the current alert */
|
|
|
|
uint32_t event_id;
|
|
|
|
} 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 *);
|
|
|
|
static int Unified2IPv4TypeAlert(ThreadVars *, const Packet *, void *);
|
|
|
|
static int Unified2IPv6TypeAlert(ThreadVars *, const Packet *, void *);
|
|
|
|
static int Unified2PacketTypeAlert(Unified2AlertThread *, const Packet *, uint32_t, int);
|
|
|
|
void Unified2RegisterTests(void);
|
|
|
|
int Unified2AlertOpenFileCtx(LogFileCtx *, const char *);
|
|
|
|
static void Unified2AlertDeInitCtx(OutputCtx *);
|
|
|
|
|
|
|
|
int Unified2Condition(ThreadVars *tv, const Packet *p);
|
|
|
|
int Unified2Logger(ThreadVars *tv, void *data, const Packet *p);
|
|
|
|
|
|
|
|
#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;
|
|
|
|
tmm_modules[TMM_ALERTUNIFIED2ALERT].flags = TM_FLAG_LOGAPI_TM;
|
|
|
|
|
|
|
|
//OutputRegisterModule(MODULE_NAME, "unified2-alert", Unified2AlertInitCtx);
|
|
|
|
OutputRegisterPacketModule(MODULE_NAME, "unified2-alert",
|
|
|
|
Unified2AlertInitCtx, Unified2Logger, Unified2Condition);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \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->unified2alert_ctx->file_ctx->fp != NULL) {
|
|
|
|
fclose(aun->unified2alert_ctx->file_ctx->fp);
|
|
|
|
}
|
|
|
|
aun->unified2alert_ctx->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->unified2alert_ctx->file_ctx,aun->unified2alert_ctx->
|
|
|
|
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->unified2alert_ctx->file_ctx->fp);
|
|
|
|
if (ret != 1) {
|
|
|
|
SCLogError(SC_ERR_FWRITE, "Error: fwrite failed: %s", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
aun->unified2alert_ctx->file_ctx->size_current += aun->length;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Unified2Condition(ThreadVars *tv, const Packet *p) {
|
|
|
|
if (likely(p->alerts.cnt == 0 && !(p->flags & PKT_HAS_TAG)))
|
|
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Unified2 main entry function
|
|
|
|
*
|
|
|
|
* \retval TM_ECODE_OK all is good
|
|
|
|
* \retval TM_ECODE_FAILED serious error
|
|
|
|
*/
|
|
|
|
int Unified2Logger(ThreadVars *t, void *data, const Packet *p)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
Unified2AlertThread *aun = (Unified2AlertThread *)data;
|
|
|
|
aun->xff_flags = XFF_DISABLED;
|
|
|
|
|
|
|
|
HttpXFFCfg *xff_cfg = aun->unified2alert_ctx->xff_cfg;
|
|
|
|
|
|
|
|
/* overwrite mode can only work per u2 block, not per individual
|
|
|
|
* alert. So we'll look for an XFF record once */
|
|
|
|
if ((xff_cfg->flags & XFF_OVERWRITE) && p->flow != NULL) {
|
|
|
|
char buffer[XFF_MAXLEN];
|
|
|
|
int have_xff_ip = 0;
|
|
|
|
|
|
|
|
FLOWLOCK_RDLOCK(p->flow);
|
App layer API rewritten. The main files in question are:
app-layer.[ch], app-layer-detect-proto.[ch] and app-layer-parser.[ch].
Things addressed in this commit:
- Brings out a proper separation between protocol detection phase and the
parser phase.
- The dns app layer now is registered such that we don't use "dnstcp" and
"dnsudp" in the rules. A user who previously wrote a rule like this -
"alert dnstcp....." or
"alert dnsudp....."
would now have to use,
alert dns (ipproto:tcp;) or
alert udp (app-layer-protocol:dns;) or
alert ip (ipproto:udp; app-layer-protocol:dns;)
The same rules extend to other another such protocol, dcerpc.
- The app layer parser api now takes in the ipproto while registering
callbacks.
- The app inspection/detection engine also takes an ipproto.
- All app layer parser functions now take direction as STREAM_TOSERVER or
STREAM_TOCLIENT, as opposed to 0 or 1, which was taken by some of the
functions.
- FlowInitialize() and FlowRecycle() now resets proto to 0. This is
needed by unittests, which would try to clean the flow, and that would
call the api, AppLayerParserCleanupParserState(), which would try to
clean the app state, but the app layer now needs an ipproto to figure
out which api to internally call to clean the state, and if the ipproto
is 0, it would return without trying to clean the state.
- A lot of unittests are now updated where if they are using a flow and
they need to use the app layer, we would set a flow ipproto.
- The "app-layer" section in the yaml conf has also been updated as well.
12 years ago
|
|
|
if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) {
|
|
|
|
have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN);
|
|
|
|
}
|
|
|
|
FLOWLOCK_UNLOCK(p->flow);
|
|
|
|
|
|
|
|
if (have_xff_ip) {
|
|
|
|
/** Be sure that we have a nice zeroed buffer */
|
|
|
|
memset(aun->xff_ip, 0, 4 * sizeof(uint32_t));
|
|
|
|
|
|
|
|
/** We can only have override mode if packet IP version matches
|
|
|
|
* the XFF IP version, otherwise fall-back to extra data */
|
|
|
|
if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) {
|
|
|
|
if (PKT_IS_IPV4(p)) {
|
|
|
|
aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|XFF_OVERWRITE);
|
|
|
|
} else {
|
|
|
|
aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|XFF_EXTRADATA);
|
|
|
|
}
|
|
|
|
} else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) {
|
|
|
|
if (PKT_IS_IPV6(p)) {
|
|
|
|
aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|XFF_OVERWRITE);
|
|
|
|
} else {
|
|
|
|
aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|XFF_EXTRADATA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PKT_IS_IPV4(p)) {
|
|
|
|
ret = Unified2IPv4TypeAlert (t, p, data);
|
|
|
|
} else if(PKT_IS_IPV6(p)) {
|
|
|
|
ret = Unified2IPv6TypeAlert (t, p, data);
|
|
|
|
} 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;
|
|
|
|
} __attribute__((__packed__)) FakeIPv4Hdr;
|
|
|
|
|
|
|
|
static int Unified2ForgeFakeIPv4Header(FakeIPv4Hdr *fakehdr, const 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;
|
|
|
|
} __attribute__((__packed__)) FakeIPv6Hdr;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \param payload_len length of the payload
|
|
|
|
*/
|
|
|
|
static int Unified2ForgeFakeIPv6Header(FakeIPv6Hdr *fakehdr, const Packet *p, int payload_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) + payload_len);
|
|
|
|
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(const Packet *p, void *data, uint8_t *buf, uint32_t buflen)
|
|
|
|
{
|
|
|
|
int ret = 1;
|
|
|
|
Unified2AlertThread *aun = (Unified2AlertThread *)data;
|
|
|
|
Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data);
|
|
|
|
Unified2Packet *phdr = (Unified2Packet *)(hdr + 1);
|
|
|
|
/** Prepare the pointers to extra data structures should they be required.
|
|
|
|
* If they are required we will shift the *hdr and the *phdr */
|
|
|
|
Unified2AlertFileHeader *eu2hdr = (Unified2AlertFileHeader*)(aun->data);
|
|
|
|
Unified2ExtraDataHdr *ehdr = (Unified2ExtraDataHdr *)(eu2hdr + 1);
|
|
|
|
Unified2ExtraData *dhdr = (Unified2ExtraData *) (ehdr + 1);
|
|
|
|
uint32_t *edxff = (uint32_t *) (dhdr + 1);
|
|
|
|
|
|
|
|
aun->length = 0;
|
|
|
|
aun->offset = 0;
|
|
|
|
|
|
|
|
// If XFF is in extra data mode...
|
|
|
|
if (aun->xff_flags & XFF_EXTRADATA) {
|
|
|
|
memset(dhdr, 0, sizeof(Unified2ExtraData));
|
|
|
|
|
|
|
|
if (aun->xff_flags & UNIFIED2_ALERT_XFF_IPV4) {
|
|
|
|
eu2hdr->type = htonl (UNIFIED2_IDS_EVENT_EXTRADATA_TYPE);
|
|
|
|
eu2hdr->length = htonl(sizeof (Unified2ExtraDataHdr)
|
|
|
|
+ sizeof (Unified2ExtraData) + sizeof(uint32_t));
|
|
|
|
ehdr->event_type = htonl(UNIFIED2_EXTRADATA_TYPE_EXTRA_DATA);
|
|
|
|
ehdr->event_length = htonl(sizeof (Unified2ExtraDataHdr)
|
|
|
|
+ sizeof (Unified2ExtraData) + sizeof(uint32_t));
|
|
|
|
dhdr->sensor_id = 0;
|
|
|
|
dhdr->event_id = aun->event_id;
|
|
|
|
dhdr->event_second = htonl(p->ts.tv_sec);
|
|
|
|
dhdr->data_type = htonl(UNIFIED2_EXTRADATA_TYPE_BLOB);
|
|
|
|
dhdr->type = htonl(UNIFIED2_EXTRADATA_CLIENT_IPV4_TYPE);
|
|
|
|
dhdr->blob_length = htonl(3 * sizeof(uint32_t));
|
|
|
|
aun->length += sizeof(Unified2AlertFileHeader) + sizeof (Unified2ExtraDataHdr)
|
|
|
|
+ sizeof (Unified2ExtraData) + sizeof(uint32_t);
|
|
|
|
aun->offset += sizeof(Unified2AlertFileHeader) + sizeof (Unified2ExtraDataHdr)
|
|
|
|
+ sizeof (Unified2ExtraData) + sizeof(uint32_t);
|
|
|
|
*edxff=aun->xff_ip[0];
|
|
|
|
/** Shift the *hdr and *phdr pointers */
|
|
|
|
hdr = (Unified2AlertFileHeader*)(edxff + 1);
|
|
|
|
phdr = (Unified2Packet *)(hdr + 1);
|
|
|
|
}
|
|
|
|
else if (aun->xff_flags & UNIFIED2_ALERT_XFF_IPV6) {
|
|
|
|
eu2hdr->type = htonl(UNIFIED2_IDS_EVENT_EXTRADATA_TYPE);
|
|
|
|
eu2hdr->length = htonl(sizeof (Unified2ExtraDataHdr)
|
|
|
|
+ sizeof (Unified2ExtraData) + 4 * sizeof(uint32_t));
|
|
|
|
ehdr->event_type = htonl(UNIFIED2_EXTRADATA_TYPE_EXTRA_DATA);
|
|
|
|
ehdr->event_length = htonl(sizeof (Unified2ExtraDataHdr)
|
|
|
|
+ sizeof (Unified2ExtraData) + 4 * sizeof(uint32_t));
|
|
|
|
dhdr->sensor_id = 0;
|
|
|
|
dhdr->event_id = aun->event_id;
|
|
|
|
dhdr->event_second = htonl(p->ts.tv_sec);
|
|
|
|
dhdr->data_type = htonl(UNIFIED2_EXTRADATA_TYPE_BLOB);
|
|
|
|
dhdr->type = htonl(UNIFIED2_EXTRADATA_CLIENT_IPV6_TYPE);
|
|
|
|
dhdr->blob_length = htonl(6 * sizeof(uint32_t));
|
|
|
|
aun->length += sizeof(Unified2AlertFileHeader) + sizeof (Unified2ExtraDataHdr)
|
|
|
|
+ sizeof (Unified2ExtraData) + 4 * sizeof(uint32_t);
|
|
|
|
aun->offset += sizeof(Unified2AlertFileHeader) + sizeof (Unified2ExtraDataHdr)
|
|
|
|
+ sizeof (Unified2ExtraData) + 4 * sizeof(uint32_t);
|
|
|
|
memcpy(edxff, aun->xff_ip, 4 * sizeof(uint32_t));
|
|
|
|
/** Shift the *hdr and *phdr pointers */
|
|
|
|
hdr = (Unified2AlertFileHeader*)(edxff + 4);
|
|
|
|
phdr = (Unified2Packet *)(hdr + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int ethh_offset = 0;
|
|
|
|
EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) };
|
|
|
|
uint32_t hdr_length = 0;
|
|
|
|
int datalink = p->datalink;
|
|
|
|
|
|
|
|
memset(hdr, 0, sizeof(Unified2AlertFileHeader));
|
|
|
|
memset(phdr, 0, sizeof(Unified2Packet));
|
|
|
|
|
|
|
|
hdr->type = htonl(UNIFIED2_PACKET_TYPE);
|
|
|
|
aun->hdr = hdr;
|
|
|
|
|
|
|
|
phdr->sensor_id = htonl(sensor_id);
|
|
|
|
phdr->linktype = htonl(datalink);
|
|
|
|
phdr->event_id = aun->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 (p->datalink != DLT_EN10MB) {
|
|
|
|
/* We have raw data here */
|
|
|
|
phdr->linktype = htonl(DLT_RAW);
|
|
|
|
datalink = DLT_RAW;
|
|
|
|
}
|
|
|
|
|
|
|
|
aun->length += sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE;
|
|
|
|
aun->offset += sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE;
|
|
|
|
|
|
|
|
/* Include Packet header */
|
|
|
|
if (PKT_IS_IPV4(p)) {
|
|
|
|
FakeIPv4Hdr fakehdr;
|
|
|
|
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");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
ethhdr.eth_type = htons(ETHERNET_TYPE_IP);
|
|
|
|
|
|
|
|
memcpy(aun->data + aun->offset, ðhdr, 14);
|
|
|
|
aun->offset += ethh_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&fakehdr, 0, hdr_length);
|
|
|
|
aun->length += hdr_length;
|
|
|
|
Unified2ForgeFakeIPv4Header(&fakehdr, p, hdr_length + buflen, 0);
|
|
|
|
if (aun->length > aun->datalen) {
|
|
|
|
SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
/** If XFF is in overwrite mode... */
|
|
|
|
if (aun->xff_flags & XFF_OVERWRITE) {
|
|
|
|
BUG_ON(aun->xff_flags & UNIFIED2_ALERT_XFF_IPV6);
|
|
|
|
|
|
|
|
if (p->flowflags & FLOW_PKT_TOCLIENT) {
|
|
|
|
fakehdr.ip4h.s_ip_dst.s_addr = aun->xff_ip[0];
|
|
|
|
} else {
|
|
|
|
fakehdr.ip4h.s_ip_src.s_addr = aun->xff_ip[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(aun->data + aun->offset, &fakehdr, hdr_length);
|
|
|
|
aun->iphdr = (void *)(aun->data + aun->offset);
|
|
|
|
aun->offset += hdr_length;
|
|
|
|
|
|
|
|
} else if (PKT_IS_IPV6(p)) {
|
|
|
|
FakeIPv6Hdr fakehdr;
|
|
|
|
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");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
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, buflen, 1);
|
|
|
|
|
|
|
|
aun->length += hdr_length;
|
|
|
|
if (aun->length > aun->datalen) {
|
|
|
|
SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
/** If XFF is in overwrite mode... */
|
|
|
|
if (aun->xff_flags & XFF_OVERWRITE) {
|
|
|
|
BUG_ON(aun->xff_flags & UNIFIED2_ALERT_XFF_IPV4);
|
|
|
|
|
|
|
|
if (p->flowflags & FLOW_PKT_TOCLIENT) {
|
|
|
|
memcpy(fakehdr.ip6h.s_ip6_dst, aun->xff_ip, 4 * sizeof(uint32_t));
|
|
|
|
} else {
|
|
|
|
memcpy(fakehdr.ip6h.s_ip6_src, aun->xff_ip, 4 * sizeof(uint32_t));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(aun->data + aun->offset, &fakehdr, hdr_length);
|
|
|
|
aun->iphdr = (void *)(aun->data + aun->offset);
|
|
|
|
aun->offset += hdr_length;
|
|
|
|
} else {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update unified2 headers for length */
|
|
|
|
aun->hdr->length = htonl(UNIFIED2_PACKET_SIZE + ethh_offset +
|
|
|
|
hdr_length + buflen);
|
|
|
|
aun->phdr->packet_length = htonl(ethh_offset + hdr_length + buflen);
|
|
|
|
|
|
|
|
/* copy stream segment payload in */
|
|
|
|
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);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(aun->data + aun->offset, buf, buflen);
|
|
|
|
aun->offset += 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));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* write out */
|
|
|
|
ret = Unified2Write(aun);
|
|
|
|
if (ret != 1) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
error:
|
|
|
|
aun->length = 0;
|
|
|
|
aun->offset = 0;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \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
|
|
|
|
* \param event_id unique event id
|
|
|
|
* \param stream state/stream match, try logging stream segments
|
|
|
|
*
|
|
|
|
* \retval 0 on succces
|
|
|
|
* \retval -1 on failure
|
|
|
|
*/
|
|
|
|
static int Unified2PacketTypeAlert(Unified2AlertThread *aun, const Packet *p, uint32_t event_id, int stream)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
/* try stream logging first */
|
|
|
|
if (stream) {
|
|
|
|
SCLogDebug("logging the state");
|
|
|
|
uint8_t flag;
|
|
|
|
|
|
|
|
if (p->flowflags & FLOW_PKT_TOSERVER) {
|
|
|
|
flag = FLOW_PKT_TOCLIENT;
|
|
|
|
} else {
|
|
|
|
flag = FLOW_PKT_TOSERVER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make event id available to callback */
|
|
|
|
aun->event_id = event_id;
|
|
|
|
|
|
|
|
/* run callback for all segments in the stream */
|
|
|
|
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");
|
|
|
|
|
|
|
|
Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data);
|
|
|
|
Unified2Packet *phdr = (Unified2Packet *)(hdr + 1);
|
|
|
|
int len = (sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE);
|
|
|
|
int datalink = p->datalink;
|
|
|
|
#ifdef HAVE_OLD_BARNYARD2
|
|
|
|
int ethh_offset = 0;
|
|
|
|
EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) };
|
|
|
|
#endif
|
|
|
|
memset(hdr, 0, sizeof(Unified2AlertFileHeader));
|
|
|
|
memset(phdr, 0, sizeof(Unified2Packet));
|
|
|
|
|
|
|
|
hdr->type = htonl(UNIFIED2_PACKET_TYPE);
|
|
|
|
aun->hdr = hdr;
|
|
|
|
|
|
|
|
phdr->sensor_id = htonl(sensor_id);
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*
|
|
|
|
* \retval 0 on succces
|
|
|
|
* \retval -1 on failure
|
|
|
|
*/
|
|
|
|
static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data)
|
|
|
|
{
|
|
|
|
Unified2AlertThread *aun = (Unified2AlertThread *)data;
|
|
|
|
Unified2AlertFileHeader hdr;
|
|
|
|
AlertIPv6Unified2 *phdr;
|
|
|
|
AlertIPv6Unified2 gphdr;
|
|
|
|
const PacketAlert *pa;
|
|
|
|
int offset, length;
|
|
|
|
int ret;
|
|
|
|
unsigned int event_id;
|
|
|
|
|
|
|
|
if (likely(p->alerts.cnt == 0 && !(p->flags & PKT_HAS_TAG)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
phdr = (AlertIPv6Unified2 *)(aun->data +
|
|
|
|
sizeof(Unified2AlertFileHeader));
|
|
|
|
|
|
|
|
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 = htonl(sensor_id);
|
|
|
|
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);
|
|
|
|
/** If XFF is in overwrite mode... */
|
|
|
|
if (aun->xff_flags & XFF_OVERWRITE) {
|
|
|
|
BUG_ON(aun->xff_flags & UNIFIED2_ALERT_XFF_IPV4);
|
|
|
|
|
|
|
|
if (p->flowflags & FLOW_PKT_TOCLIENT) {
|
|
|
|
gphdr.dst_ip = *(struct in6_addr*)aun->xff_ip;
|
|
|
|
} else {
|
|
|
|
gphdr.src_ip = *(struct in6_addr*)aun->xff_ip;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
gphdr.protocol = p->proto;
|
|
|
|
|
|
|
|
if(PACKET_TEST_ACTION(p, 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++) {
|
|
|
|
if (i < p->alerts.cnt)
|
|
|
|
pa = &p->alerts.alerts[i];
|
|
|
|
else {
|
|
|
|
if (!(p->flags & PKT_HAS_TAG))
|
|
|
|
break;
|
|
|
|
pa = PacketAlertGetTag();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlikely(pa->s == NULL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
HttpXFFCfg *xff_cfg = aun->unified2alert_ctx->xff_cfg;
|
|
|
|
|
|
|
|
if ((xff_cfg->flags & XFF_EXTRADATA) && p->flow != NULL) {
|
|
|
|
char buffer[XFF_MAXLEN];
|
|
|
|
int have_xff_ip = 0;
|
|
|
|
|
|
|
|
FLOWLOCK_RDLOCK(p->flow);
|
App layer API rewritten. The main files in question are:
app-layer.[ch], app-layer-detect-proto.[ch] and app-layer-parser.[ch].
Things addressed in this commit:
- Brings out a proper separation between protocol detection phase and the
parser phase.
- The dns app layer now is registered such that we don't use "dnstcp" and
"dnsudp" in the rules. A user who previously wrote a rule like this -
"alert dnstcp....." or
"alert dnsudp....."
would now have to use,
alert dns (ipproto:tcp;) or
alert udp (app-layer-protocol:dns;) or
alert ip (ipproto:udp; app-layer-protocol:dns;)
The same rules extend to other another such protocol, dcerpc.
- The app layer parser api now takes in the ipproto while registering
callbacks.
- The app inspection/detection engine also takes an ipproto.
- All app layer parser functions now take direction as STREAM_TOSERVER or
STREAM_TOCLIENT, as opposed to 0 or 1, which was taken by some of the
functions.
- FlowInitialize() and FlowRecycle() now resets proto to 0. This is
needed by unittests, which would try to clean the flow, and that would
call the api, AppLayerParserCleanupParserState(), which would try to
clean the app state, but the app layer now needs an ipproto to figure
out which api to internally call to clean the state, and if the ipproto
is 0, it would return without trying to clean the state.
- A lot of unittests are now updated where if they are using a flow and
they need to use the app layer, we would set a flow ipproto.
- The "app-layer" section in the yaml conf has also been updated as well.
12 years ago
|
|
|
if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) {
|
|
|
|
if (pa->flags & PACKET_ALERT_FLAG_TX) {
|
|
|
|
have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg, buffer, XFF_MAXLEN);
|
|
|
|
} else {
|
|
|
|
have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FLOWLOCK_UNLOCK(p->flow);
|
|
|
|
|
|
|
|
if (have_xff_ip) {
|
|
|
|
memset(aun->xff_ip, 0, 4 * sizeof(uint32_t));
|
|
|
|
|
|
|
|
if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) {
|
|
|
|
aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|XFF_EXTRADATA);
|
|
|
|
} else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) {
|
|
|
|
aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|XFF_EXTRADATA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reset length and offset */
|
|
|
|
aun->offset = offset;
|
|
|
|
aun->length = length;
|
|
|
|
memset(aun->data + aun->offset, 0, aun->datalen - aun->offset);
|
|
|
|
|
|
|
|
/* 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->unified2alert_ctx->file_ctx->fp_mutex);
|
|
|
|
if ((aun->unified2alert_ctx->file_ctx->size_current + length) >
|
|
|
|
aun->unified2alert_ctx->file_ctx->size_limit) {
|
|
|
|
if (Unified2AlertRotateFile(t,aun) < 0) {
|
|
|
|
aun->unified2alert_ctx->file_ctx->alerts += i;
|
|
|
|
SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Unified2Write(aun) != 1) {
|
|
|
|
aun->unified2alert_ctx->file_ctx->alerts += i;
|
|
|
|
SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(aun->data, 0, aun->length);
|
|
|
|
aun->length = 0;
|
|
|
|
aun->offset = 0;
|
|
|
|
|
|
|
|
/* stream flag based on state match, but only for TCP */
|
|
|
|
int stream = (gphdr.protocol == IPPROTO_TCP) ?
|
|
|
|
(pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH) ? 1 : 0) : 0;
|
|
|
|
ret = Unified2PacketTypeAlert(aun, p, phdr->event_id, stream);
|
|
|
|
if (ret != 1) {
|
|
|
|
SCLogError(SC_ERR_FWRITE, "Error: fwrite failed: %s", strerror(errno));
|
|
|
|
aun->unified2alert_ctx->file_ctx->alerts += i;
|
|
|
|
SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
fflush(aun->unified2alert_ctx->file_ctx->fp);
|
|
|
|
aun->unified2alert_ctx->file_ctx->alerts++;
|
|
|
|
SCMutexUnlock(&aun->unified2alert_ctx->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.
|
|
|
|
* \retval 0 on succces
|
|
|
|
* \retval -1 on failure
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data)
|
|
|
|
{
|
|
|
|
Unified2AlertThread *aun = (Unified2AlertThread *)data;
|
|
|
|
Unified2AlertFileHeader hdr;
|
|
|
|
AlertIPv4Unified2 *phdr;
|
|
|
|
AlertIPv4Unified2 gphdr;
|
|
|
|
const PacketAlert *pa;
|
|
|
|
int offset, length;
|
|
|
|
int ret;
|
|
|
|
unsigned int event_id;
|
|
|
|
|
|
|
|
if (likely(p->alerts.cnt == 0 && !(p->flags & PKT_HAS_TAG)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
phdr = (AlertIPv4Unified2 *)(aun->data +
|
|
|
|
sizeof(Unified2AlertFileHeader));
|
|
|
|
|
|
|
|
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 = htonl(sensor_id);
|
|
|
|
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;
|
|
|
|
/** If XFF is in overwrite mode... */
|
|
|
|
if (aun->xff_flags & XFF_OVERWRITE) {
|
|
|
|
BUG_ON(aun->xff_flags & UNIFIED2_ALERT_XFF_IPV6);
|
|
|
|
|
|
|
|
if (p->flowflags & FLOW_PKT_TOCLIENT) {
|
|
|
|
gphdr.dst_ip = aun->xff_ip[0];
|
|
|
|
} else {
|
|
|
|
gphdr.src_ip = aun->xff_ip[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
gphdr.protocol = IPV4_GET_RAW_IPPROTO(p->ip4h);
|
|
|
|
|
|
|
|
if(PACKET_TEST_ACTION(p, 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++) {
|
|
|
|
if (i < p->alerts.cnt)
|
|
|
|
pa = &p->alerts.alerts[i];
|
|
|
|
else {
|
|
|
|
if (!(p->flags & PKT_HAS_TAG))
|
|
|
|
break;
|
|
|
|
pa = PacketAlertGetTag();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlikely(pa->s == NULL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
HttpXFFCfg *xff_cfg = aun->unified2alert_ctx->xff_cfg;
|
|
|
|
|
|
|
|
if ((xff_cfg->flags & XFF_EXTRADATA) && p->flow != NULL) {
|
|
|
|
char buffer[XFF_MAXLEN];
|
|
|
|
int have_xff_ip = 0;
|
|
|
|
|
|
|
|
FLOWLOCK_RDLOCK(p->flow);
|
App layer API rewritten. The main files in question are:
app-layer.[ch], app-layer-detect-proto.[ch] and app-layer-parser.[ch].
Things addressed in this commit:
- Brings out a proper separation between protocol detection phase and the
parser phase.
- The dns app layer now is registered such that we don't use "dnstcp" and
"dnsudp" in the rules. A user who previously wrote a rule like this -
"alert dnstcp....." or
"alert dnsudp....."
would now have to use,
alert dns (ipproto:tcp;) or
alert udp (app-layer-protocol:dns;) or
alert ip (ipproto:udp; app-layer-protocol:dns;)
The same rules extend to other another such protocol, dcerpc.
- The app layer parser api now takes in the ipproto while registering
callbacks.
- The app inspection/detection engine also takes an ipproto.
- All app layer parser functions now take direction as STREAM_TOSERVER or
STREAM_TOCLIENT, as opposed to 0 or 1, which was taken by some of the
functions.
- FlowInitialize() and FlowRecycle() now resets proto to 0. This is
needed by unittests, which would try to clean the flow, and that would
call the api, AppLayerParserCleanupParserState(), which would try to
clean the app state, but the app layer now needs an ipproto to figure
out which api to internally call to clean the state, and if the ipproto
is 0, it would return without trying to clean the state.
- A lot of unittests are now updated where if they are using a flow and
they need to use the app layer, we would set a flow ipproto.
- The "app-layer" section in the yaml conf has also been updated as well.
12 years ago
|
|
|
if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) {
|
|
|
|
if (pa->flags & PACKET_ALERT_FLAG_TX) {
|
|
|
|
have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg, buffer, XFF_MAXLEN);
|
|
|
|
} else {
|
|
|
|
have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FLOWLOCK_UNLOCK(p->flow);
|
|
|
|
|
|
|
|
if (have_xff_ip) {
|
|
|
|
memset(aun->xff_ip, 0, 4 * sizeof(uint32_t));
|
|
|
|
|
|
|
|
if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) {
|
|
|
|
aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|XFF_EXTRADATA);
|
|
|
|
} else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) {
|
|
|
|
aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|XFF_EXTRADATA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reset length and offset */
|
|
|
|
aun->offset = offset;
|
|
|
|
aun->length = length;
|
|
|
|
memset(aun->data + aun->offset, 0, aun->datalen - aun->offset);
|
|
|
|
|
|
|
|
/* 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->unified2alert_ctx->file_ctx->fp_mutex);
|
|
|
|
|
|
|
|
if ((aun->unified2alert_ctx->file_ctx->size_current + length) >
|
|
|
|
aun->unified2alert_ctx->file_ctx->size_limit) {
|
|
|
|
if (Unified2AlertRotateFile(tv,aun) < 0) {
|
|
|
|
aun->unified2alert_ctx->file_ctx->alerts += i;
|
|
|
|
SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Unified2Write(aun) != 1) {
|
|
|
|
aun->unified2alert_ctx->file_ctx->alerts += i;
|
|
|
|
SCMutexUnlock(&aun->unified2alert_ctx->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)
|
|
|
|
*/
|
|
|
|
int stream = (gphdr.protocol == IPPROTO_TCP) ?
|
|
|
|
(pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH) ? 1 : 0) : 0;
|
|
|
|
ret = Unified2PacketTypeAlert(aun, p, event_id, stream);
|
|
|
|
if (ret != 1) {
|
|
|
|
aun->unified2alert_ctx->file_ctx->alerts += i;
|
|
|
|
SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fflush(aun->unified2alert_ctx->file_ctx->fp);
|
|
|
|
aun->unified2alert_ctx->file_ctx->alerts++;
|
|
|
|
SCMutexUnlock(&aun->unified2alert_ctx->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 (unlikely(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->unified2alert_ctx = ((OutputCtx *)initdata)->data;
|
|
|
|
|
|
|
|
aun->data = SCMalloc(sizeof(Unified2AlertFileHeader) + sizeof(Unified2Packet) +
|
|
|
|
IPV4_MAXPACKET_LEN + sizeof(Unified2ExtraDataHdr) + sizeof (Unified2ExtraData));
|
|
|
|
if (aun->data == NULL) {
|
|
|
|
SCFree(aun);
|
|
|
|
return TM_ECODE_FAILED;
|
|
|
|
}
|
|
|
|
aun->datalen = sizeof(Unified2AlertFileHeader) + sizeof(Unified2Packet) +
|
|
|
|
IPV4_MAXPACKET_LEN + sizeof(Unified2ExtraDataHdr) + sizeof(Unified2ExtraData);
|
|
|
|
|
|
|
|
*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->unified2alert_ctx->file_ctx->flags & LOGFILE_ALERTS_PRINTED)) {
|
|
|
|
SCLogInfo("Alert unified2 module wrote %"PRIu64" alerts",
|
|
|
|
aun->unified2alert_ctx->file_ctx->alerts);
|
|
|
|
|
|
|
|
/* Do not print it for each thread */
|
|
|
|
aun->unified2alert_ctx->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;
|
|
|
|
OutputCtx* output_ctx = NULL;
|
|
|
|
HttpXFFCfg *xff_cfg = 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);
|
|
|
|
if (unlikely(file_ctx->prefix == NULL)) {
|
|
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate file prefix");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conf != NULL) {
|
|
|
|
const char *sensor_id_s = NULL;
|
|
|
|
sensor_id_s = ConfNodeLookupChildValue(conf, "sensor-id");
|
|
|
|
if (sensor_id_s != NULL) {
|
|
|
|
if (ByteExtractStringUint32(&sensor_id, 10, 0, sensor_id_s) == -1) {
|
|
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize unified2 output, invalid sensor-id: %s", sensor_id_s);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = Unified2AlertOpenFileCtx(file_ctx, filename);
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
output_ctx = SCCalloc(1, sizeof(OutputCtx));
|
|
|
|
if (unlikely(output_ctx == NULL))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
xff_cfg = SCMalloc(sizeof(HttpXFFCfg));
|
|
|
|
if (unlikely(xff_cfg == NULL)) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
memset(xff_cfg, 0x00, sizeof(HttpXFFCfg));
|
|
|
|
|
|
|
|
if (conf != NULL) {
|
|
|
|
HttpXFFGetCfg(conf, xff_cfg);
|
|
|
|
}
|
|
|
|
|
|
|
|
Unified2AlertFileCtx *unified2alert_ctx = SCMalloc(sizeof(Unified2AlertFileCtx));
|
|
|
|
if (unlikely(unified2alert_ctx == NULL)) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
memset(unified2alert_ctx, 0x00, sizeof(Unified2AlertFileCtx));
|
|
|
|
|
|
|
|
unified2alert_ctx->file_ctx = file_ctx;
|
|
|
|
unified2alert_ctx->xff_cfg = xff_cfg;
|
|
|
|
output_ctx->data = unified2alert_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 (xff_cfg != NULL) {
|
|
|
|
SCFree(xff_cfg);
|
|
|
|
}
|
|
|
|
if (output_ctx != NULL) {
|
|
|
|
SCFree(output_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Unified2AlertDeInitCtx(OutputCtx *output_ctx)
|
|
|
|
{
|
|
|
|
if (output_ctx != NULL) {
|
|
|
|
Unified2AlertFileCtx *unified2alert_ctx = (Unified2AlertFileCtx *) output_ctx->data;
|
|
|
|
if (unified2alert_ctx != NULL) {
|
|
|
|
LogFileCtx *logfile_ctx = unified2alert_ctx->file_ctx;
|
|
|
|
if (logfile_ctx != NULL) {
|
|
|
|
LogFileFreeCtx(logfile_ctx);
|
|
|
|
}
|
|
|
|
HttpXFFCfg *xff_cfg = unified2alert_ctx->xff_cfg;
|
|
|
|
if (xff_cfg != NULL) {
|
|
|
|
SCFree(xff_cfg);
|
|
|
|
}
|
|
|
|
SCFree(unified2alert_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 = SCMalloc(PATH_MAX); /* XXX some sane default? */
|
|
|
|
if (unlikely(filename == NULL))
|
|
|
|
return -1;
|
|
|
|
file_ctx->filename = filename;
|
|
|
|
|
|
|
|
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;
|
|
|
|
log_dir = ConfigGetLogDirectory();
|
|
|
|
|
|
|
|
snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, log_dir, prefix, (uint32_t)ts.tv_sec);
|
|
|
|
|
|
|
|
file_ctx->fp = fopen(filename, "ab");
|
|
|
|
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;
|
|
|
|
Unified2AlertFileCtx *uaf = NULL;
|
|
|
|
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 = PacketGetFromAlloc();
|
|
|
|
if (unlikely(p == NULL))
|
|
|
|
return 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
memset(&dtv, 0, sizeof(DecodeThreadVars));
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
memset(&pq, 0, sizeof(PacketQueue));
|
|
|
|
memset(&s, 0, sizeof(Signature));
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
oc = Unified2AlertInitCtx(NULL);
|
|
|
|
if (oc == NULL) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
uaf = oc->data;
|
|
|
|
if (uaf == NULL)
|
|
|
|
return 0;
|
|
|
|
lf = uaf->file_ctx;
|
|
|
|
if(lf == NULL) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadInit(&tv, oc, &data);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2Logger(&tv, data, p);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadDeinit(&tv, data);
|
|
|
|
if(ret == -1) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
Unified2AlertDeInitCtx(oc);
|
|
|
|
|
|
|
|
PACKET_RECYCLE(p);
|
|
|
|
SCFree(p);
|
|
|
|
FlowShutdown();
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
end:
|
|
|
|
PACKET_RECYCLE(p);
|
|
|
|
SCFree(p);
|
|
|
|
FlowShutdown();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \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;
|
|
|
|
Unified2AlertFileCtx *uaf = NULL;
|
|
|
|
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 = PacketGetFromAlloc();
|
|
|
|
if (unlikely(p == NULL))
|
|
|
|
return 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
memset(&dtv, 0, sizeof(DecodeThreadVars));
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
memset(&pq, 0, sizeof(PacketQueue));
|
|
|
|
memset(&s, 0, sizeof(Signature));
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
oc = Unified2AlertInitCtx(NULL);
|
|
|
|
if (oc == NULL) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
uaf = oc->data;
|
|
|
|
if (uaf == NULL)
|
|
|
|
return 0;
|
|
|
|
lf = uaf->file_ctx;
|
|
|
|
if(lf == NULL) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadInit(&tv, oc, &data);
|
|
|
|
if(ret == -1) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2Logger(&tv, data, p);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadDeinit(&tv, data);
|
|
|
|
if(ret == -1) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
Unified2AlertDeInitCtx(oc);
|
|
|
|
|
|
|
|
PACKET_RECYCLE(p);
|
|
|
|
SCFree(p);
|
|
|
|
FlowShutdown();
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
end:
|
|
|
|
PACKET_RECYCLE(p);
|
|
|
|
SCFree(p);
|
|
|
|
FlowShutdown();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \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;
|
|
|
|
Unified2AlertFileCtx *uaf = NULL;
|
|
|
|
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 = PacketGetFromAlloc();
|
|
|
|
Packet *pkt;
|
|
|
|
if (unlikely(p == NULL))
|
|
|
|
return 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
memset(&dtv, 0, sizeof(DecodeThreadVars));
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
memset(&pq, 0, sizeof(PacketQueue));
|
|
|
|
memset(&s, 0, sizeof(Signature));
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
oc = Unified2AlertInitCtx(NULL);
|
|
|
|
if (oc == NULL) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
uaf = oc->data;
|
|
|
|
if (uaf == NULL)
|
|
|
|
return 0;
|
|
|
|
lf = uaf->file_ctx;
|
|
|
|
if(lf == NULL) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadInit(&tv, oc, &data);
|
|
|
|
if(ret == -1) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2Logger(&tv, data, p);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadDeinit(&tv, data);
|
|
|
|
if(ret == -1) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
Unified2AlertDeInitCtx(oc);
|
|
|
|
|
|
|
|
pkt = PacketDequeue(&pq);
|
|
|
|
while (pkt != NULL) {
|
|
|
|
PACKET_RECYCLE(pkt);
|
|
|
|
SCFree(pkt);
|
|
|
|
pkt = PacketDequeue(&pq);
|
|
|
|
}
|
|
|
|
|
|
|
|
PACKET_RECYCLE(p);
|
|
|
|
SCFree(p);
|
|
|
|
FlowShutdown();
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
end:
|
|
|
|
pkt = PacketDequeue(&pq);
|
|
|
|
while (pkt != NULL) {
|
|
|
|
PACKET_RECYCLE(pkt);
|
|
|
|
SCFree(pkt);
|
|
|
|
pkt = PacketDequeue(&pq);
|
|
|
|
}
|
|
|
|
PACKET_RECYCLE(p);
|
|
|
|
SCFree(p);
|
|
|
|
FlowShutdown();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \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;
|
|
|
|
Unified2AlertFileCtx *uaf = NULL;
|
|
|
|
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 = PacketGetFromAlloc();
|
|
|
|
if (unlikely(p == NULL))
|
|
|
|
return 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
memset(&dtv, 0, sizeof(DecodeThreadVars));
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
memset(&pq, 0, sizeof(PacketQueue));
|
|
|
|
memset(&s, 0, sizeof(Signature));
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
oc = Unified2AlertInitCtx(NULL);
|
|
|
|
if (oc == NULL) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
uaf = oc->data;
|
|
|
|
if (uaf == NULL)
|
|
|
|
return 0;
|
|
|
|
lf = uaf->file_ctx;
|
|
|
|
if(lf == NULL) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadInit(&tv, oc, &data);
|
|
|
|
if(ret == -1) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2Logger(&tv, data, p);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadDeinit(&tv, data);
|
|
|
|
if(ret == -1) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
Unified2AlertDeInitCtx(oc);
|
|
|
|
|
|
|
|
PACKET_RECYCLE(p);
|
|
|
|
SCFree(p);
|
|
|
|
FlowShutdown();
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
end:
|
|
|
|
PACKET_RECYCLE(p);
|
|
|
|
SCFree(p);
|
|
|
|
FlowShutdown();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \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;
|
|
|
|
Unified2AlertFileCtx *uaf = NULL;
|
|
|
|
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 = PacketGetFromAlloc();
|
|
|
|
if (unlikely(p == NULL))
|
|
|
|
return 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
memset(&dtv, 0, sizeof(DecodeThreadVars));
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
memset(&pq, 0, sizeof(PacketQueue));
|
|
|
|
memset(&s, 0, sizeof(Signature));
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
p->action = ACTION_DROP;
|
|
|
|
|
|
|
|
oc = Unified2AlertInitCtx(NULL);
|
|
|
|
if (oc == NULL) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
uaf = oc->data;
|
|
|
|
if (uaf == NULL)
|
|
|
|
return 0;
|
|
|
|
lf = uaf->file_ctx;
|
|
|
|
if(lf == NULL) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadInit(&tv, oc, &data);
|
|
|
|
if(ret == -1) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2Logger(&tv, data, p);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = Unified2AlertThreadDeinit(&tv, data);
|
|
|
|
if(ret == TM_ECODE_FAILED) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
Unified2AlertDeInitCtx(oc);
|
|
|
|
|
|
|
|
PACKET_RECYCLE(p);
|
|
|
|
SCFree(p);
|
|
|
|
FlowShutdown();
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
end:
|
|
|
|
PACKET_RECYCLE(p);
|
|
|
|
SCFree(p);
|
|
|
|
FlowShutdown();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \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;
|
|
|
|
Unified2AlertFileCtx *uaf = NULL;
|
|
|
|
void *data = NULL;
|
|
|
|
char *filename = NULL;
|
|
|
|
|
|
|
|
oc = Unified2AlertInitCtx(NULL);
|
|
|
|
if (oc == NULL)
|
|
|
|
return 0;
|
|
|
|
uaf = oc->data;
|
|
|
|
if (uaf == NULL)
|
|
|
|
return 0;
|
|
|
|
lf = uaf->file_ctx;
|
|
|
|
if (lf == NULL)
|
|
|
|
return 0;
|
|
|
|
filename = SCStrdup(lf->filename);
|
|
|
|
if (unlikely(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)
|
|
|
|
{
|
|
|
|
PacketPoolInit();
|
|
|
|
#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 */
|
|
|
|
}
|