mirror of https://github.com/OISF/suricata
libsuricata: add library runmode
Add library source and runmode modules. Reorganized library example to create a worker thread and replay a pcap file using the library mode. No API layer is added at this stage. Edits by Jason Ish: - fix guard - add copyright/license headers Ticket: #7240pull/12891/head
parent
d8c6a56a62
commit
ee9714e593
@ -1,12 +1,16 @@
|
|||||||
LIBSURICATA_CONFIG ?= @CONFIGURE_PREFIX@/bin/libsuricata-config
|
LIBSURICATA_CONFIG ?= @CONFIGURE_PREFIX@/bin/libsuricata-config
|
||||||
|
|
||||||
SURICATA_LIBS = `$(LIBSURICATA_CONFIG) --libs`
|
SURICATA_LIBS = `$(LIBSURICATA_CONFIG) --libs --static`
|
||||||
SURICATA_CFLAGS := `$(LIBSURICATA_CONFIG) --cflags`
|
SURICATA_CFLAGS := `$(LIBSURICATA_CONFIG) --cflags`
|
||||||
|
|
||||||
|
# Currently the Suricata logging system requires this to be even for
|
||||||
|
# plugins.
|
||||||
|
CPPFLAGS += "-D__SCFILENAME__=\"$(*F)\""
|
||||||
|
|
||||||
all: simple
|
all: simple
|
||||||
|
|
||||||
simple: main.c
|
simple: main.c
|
||||||
$(CC) -o $@ $^ $(CFLAGS) $(SURICATA_CFLAGS) $(SURICATA_LIBS)
|
$(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(SURICATA_CFLAGS) $(SURICATA_LIBS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f simple
|
rm -f simple
|
||||||
|
@ -0,0 +1,154 @@
|
|||||||
|
/* Copyright (C) 2023-2024 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 Angelo Mirabella <angelo.mirabella@broadcom.com>
|
||||||
|
*
|
||||||
|
* Library runmode.
|
||||||
|
*/
|
||||||
|
#include "suricata-common.h"
|
||||||
|
#include "runmode-lib.h"
|
||||||
|
#include "runmodes.h"
|
||||||
|
#include "tm-threads.h"
|
||||||
|
#include "util-device.h"
|
||||||
|
|
||||||
|
static int g_thread_id = 0;
|
||||||
|
|
||||||
|
/** \brief register runmodes for suricata as a library */
|
||||||
|
void RunModeIdsLibRegister(void)
|
||||||
|
{
|
||||||
|
RunModeRegisterNewRunMode(RUNMODE_LIB, "offline", "Library offline mode (pcap replaying)",
|
||||||
|
RunModeIdsLibOffline, NULL);
|
||||||
|
RunModeRegisterNewRunMode(RUNMODE_LIB, "live", "Library live mode", RunModeIdsLibLive, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief runmode for offline packet processing (pcap files) */
|
||||||
|
int RunModeIdsLibOffline(void)
|
||||||
|
{
|
||||||
|
TimeModeSetOffline();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief runmode for live packet processing */
|
||||||
|
int RunModeIdsLibLive(void)
|
||||||
|
{
|
||||||
|
TimeModeSetLive();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *RunModeLibGetDefaultMode(void)
|
||||||
|
{
|
||||||
|
return "live";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief create a "fake" worker thread in charge of processing the packets.
|
||||||
|
*
|
||||||
|
* This method just creates a context representing the worker, which is handled from the library
|
||||||
|
* client. No actual thread (pthread_t) is created.
|
||||||
|
*
|
||||||
|
* \return Pointer to ThreadVars structure representing the worker thread */
|
||||||
|
void *RunModeCreateWorker(void)
|
||||||
|
{
|
||||||
|
char tname[TM_THREAD_NAME_MAX];
|
||||||
|
TmModule *tm_module = NULL;
|
||||||
|
snprintf(tname, sizeof(tname), "%s#%02d", thread_name_workers, ++g_thread_id);
|
||||||
|
|
||||||
|
ThreadVars *tv = TmThreadCreatePacketHandler(
|
||||||
|
tname, "packetpool", "packetpool", "packetpool", "packetpool", "lib");
|
||||||
|
if (tv == NULL) {
|
||||||
|
SCLogError("TmThreadsCreate failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tm_module = TmModuleGetByName("DecodeLib");
|
||||||
|
if (tm_module == NULL) {
|
||||||
|
SCLogError("TmModuleGetByName DecodeLib failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
TmSlotSetFuncAppend(tv, tm_module, NULL);
|
||||||
|
|
||||||
|
tm_module = TmModuleGetByName("FlowWorker");
|
||||||
|
if (tm_module == NULL) {
|
||||||
|
SCLogError("TmModuleGetByName for FlowWorker failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
TmSlotSetFuncAppend(tv, tm_module, NULL);
|
||||||
|
|
||||||
|
TmThreadAppend(tv, tv->type);
|
||||||
|
|
||||||
|
return tv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief start the "fake" worker.
|
||||||
|
*
|
||||||
|
* This method performs all the initialization tasks.
|
||||||
|
*/
|
||||||
|
int RunModeSpawnWorker(void *td)
|
||||||
|
{
|
||||||
|
ThreadVars *tv = (ThreadVars *)td;
|
||||||
|
|
||||||
|
if (TmThreadLibSpawn(tv) != TM_ECODE_OK) {
|
||||||
|
SCLogError("TmThreadLibSpawn failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TmThreadsSetFlag(tv, THV_RUNNING);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief destroy a worker thread */
|
||||||
|
void RunModeDestroyWorker(void *td)
|
||||||
|
{
|
||||||
|
ThreadVars *tv = (ThreadVars *)td;
|
||||||
|
TmSlot *s = tv->tm_slots;
|
||||||
|
TmEcode r;
|
||||||
|
TmSlot *slot = NULL;
|
||||||
|
|
||||||
|
StatsSyncCounters(tv);
|
||||||
|
|
||||||
|
TmThreadsSetFlag(tv, THV_FLOW_LOOP);
|
||||||
|
|
||||||
|
/* process all pseudo packets the flow timeout may throw at us */
|
||||||
|
TmThreadTimeoutLoop(tv, s);
|
||||||
|
|
||||||
|
TmThreadsSetFlag(tv, THV_RUNNING_DONE);
|
||||||
|
TmThreadWaitForFlag(tv, THV_DEINIT);
|
||||||
|
|
||||||
|
PacketPoolDestroy();
|
||||||
|
|
||||||
|
for (slot = s; slot != NULL; slot = slot->slot_next) {
|
||||||
|
if (slot->SlotThreadExitPrintStats != NULL) {
|
||||||
|
slot->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(slot->slot_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot->SlotThreadDeinit != NULL) {
|
||||||
|
r = slot->SlotThreadDeinit(tv, SC_ATOMIC_GET(slot->slot_data));
|
||||||
|
if (r != TM_ECODE_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tv->stream_pq = NULL;
|
||||||
|
--g_thread_id;
|
||||||
|
SCLogDebug("%s ending", tv->name);
|
||||||
|
TmThreadsSetFlag(tv, THV_CLOSED);
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/* Copyright (C) 2023-2024 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 Angelo Mirabella <angelo.mirabella@broadcom.com>
|
||||||
|
*
|
||||||
|
* Library runmode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SURICATA_RUNMODE_LIB_H
|
||||||
|
#define SURICATA_RUNMODE_LIB_H
|
||||||
|
|
||||||
|
/** \brief register runmodes for suricata as a library */
|
||||||
|
void RunModeIdsLibRegister(void);
|
||||||
|
|
||||||
|
/** \brief runmode for live packet processing */
|
||||||
|
int RunModeIdsLibLive(void);
|
||||||
|
|
||||||
|
/** \brief runmode for offline packet processing (pcap files) */
|
||||||
|
int RunModeIdsLibOffline(void);
|
||||||
|
|
||||||
|
/** \brief runmode default mode (live) */
|
||||||
|
const char *RunModeLibGetDefaultMode(void);
|
||||||
|
|
||||||
|
/** \brief create a "fake" worker thread in charge of processing the packets.
|
||||||
|
*
|
||||||
|
* This method just creates a context representing the worker, which is handled from the library
|
||||||
|
* client. No actual thread (pthread_t) is created.
|
||||||
|
*
|
||||||
|
* \return Pointer to ThreadVars structure representing the worker thread */
|
||||||
|
void *RunModeCreateWorker(void);
|
||||||
|
|
||||||
|
/** \brief start the "fake" worker.
|
||||||
|
*
|
||||||
|
* This method performs all the initialization tasks.
|
||||||
|
*/
|
||||||
|
int RunModeSpawnWorker(void *);
|
||||||
|
|
||||||
|
/** \brief destroy a worker thread */
|
||||||
|
void RunModeDestroyWorker(void *);
|
||||||
|
|
||||||
|
#endif /* SURICATA_RUNMODE_LIB_H */
|
@ -0,0 +1,180 @@
|
|||||||
|
/* Copyright (C) 2023-2024 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 Angelo Mirabella <angelo.mirabella@broadcom.com>
|
||||||
|
*
|
||||||
|
* LIB packet and stream decoding support
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "suricata-common.h"
|
||||||
|
#include "source-lib.h"
|
||||||
|
#include "util-device.h"
|
||||||
|
|
||||||
|
static TmEcode DecodeLibThreadInit(ThreadVars *tv, const void *initdata, void **data);
|
||||||
|
static TmEcode DecodeLibThreadDeinit(ThreadVars *tv, void *data);
|
||||||
|
static TmEcode DecodeLib(ThreadVars *tv, Packet *p, void *data);
|
||||||
|
|
||||||
|
/* Set time to the first packet timestamp when replaying a PCAP. */
|
||||||
|
static bool time_set = false;
|
||||||
|
|
||||||
|
/** \brief register a "Decode" module for suricata as a library.
|
||||||
|
*
|
||||||
|
* The "Decode" module is the first module invoked when processing a packet */
|
||||||
|
void TmModuleDecodeLibRegister(void)
|
||||||
|
{
|
||||||
|
tmm_modules[TMM_DECODELIB].name = "DecodeLib";
|
||||||
|
tmm_modules[TMM_DECODELIB].ThreadInit = DecodeLibThreadInit;
|
||||||
|
tmm_modules[TMM_DECODELIB].Func = DecodeLib;
|
||||||
|
tmm_modules[TMM_DECODELIB].ThreadExitPrintStats = NULL;
|
||||||
|
tmm_modules[TMM_DECODELIB].ThreadDeinit = DecodeLibThreadDeinit;
|
||||||
|
tmm_modules[TMM_DECODELIB].cap_flags = 0;
|
||||||
|
tmm_modules[TMM_DECODELIB].flags = TM_FLAG_DECODE_TM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief initialize the "Decode" module.
|
||||||
|
*
|
||||||
|
* \param tv Pointer to the per-thread structure.
|
||||||
|
* \param initdata Pointer to initialization context.
|
||||||
|
* \param data Pointer to the initialized context.
|
||||||
|
* \return Error code.
|
||||||
|
*/
|
||||||
|
TmEcode DecodeLibThreadInit(ThreadVars *tv, const void *initdata, void **data)
|
||||||
|
{
|
||||||
|
SCEnter();
|
||||||
|
DecodeThreadVars *dtv = NULL;
|
||||||
|
|
||||||
|
dtv = DecodeThreadVarsAlloc(tv);
|
||||||
|
|
||||||
|
if (dtv == NULL)
|
||||||
|
SCReturnInt(TM_ECODE_FAILED);
|
||||||
|
|
||||||
|
DecodeRegisterPerfCounters(dtv, tv);
|
||||||
|
|
||||||
|
*data = (void *)dtv;
|
||||||
|
|
||||||
|
SCReturnInt(TM_ECODE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief deinitialize the "Decode" module.
|
||||||
|
*
|
||||||
|
* \param tv Pointer to the per-thread structure.
|
||||||
|
* \param data Pointer to the context.
|
||||||
|
* \return Error code.
|
||||||
|
*/
|
||||||
|
TmEcode DecodeLibThreadDeinit(ThreadVars *tv, void *data)
|
||||||
|
{
|
||||||
|
if (data != NULL)
|
||||||
|
DecodeThreadVarsFree(tv, data);
|
||||||
|
|
||||||
|
time_set = false;
|
||||||
|
SCReturnInt(TM_ECODE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief main decoding function.
|
||||||
|
*
|
||||||
|
* This method receives a packet and tries to identify layer 2 to 4 layers.
|
||||||
|
*
|
||||||
|
* \param tv Pointer to the per-thread structure.
|
||||||
|
* \param p Pointer to the packet.
|
||||||
|
* \param data Pointer to the context.
|
||||||
|
* \return Error code.
|
||||||
|
*/
|
||||||
|
TmEcode DecodeLib(ThreadVars *tv, Packet *p, void *data)
|
||||||
|
{
|
||||||
|
SCEnter();
|
||||||
|
DecodeThreadVars *dtv = (DecodeThreadVars *)data;
|
||||||
|
|
||||||
|
BUG_ON(PKT_IS_PSEUDOPKT(p));
|
||||||
|
|
||||||
|
/* update counters */
|
||||||
|
DecodeUpdatePacketCounters(tv, dtv, p);
|
||||||
|
|
||||||
|
/* If suri has set vlan during reading, we increase vlan counter */
|
||||||
|
if (p->vlan_idx) {
|
||||||
|
StatsIncr(tv, dtv->counter_vlan);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call the decoder */
|
||||||
|
DecodeLinkLayer(tv, dtv, p->datalink, p, GET_PKT_DATA(p), GET_PKT_LEN(p));
|
||||||
|
|
||||||
|
PacketDecodeFinalize(tv, dtv, p);
|
||||||
|
|
||||||
|
SCReturnInt(TM_ECODE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief process a single packet.
|
||||||
|
*
|
||||||
|
* \param tv Pointer to the per-thread structure.
|
||||||
|
* \param data Pointer to the raw packet.
|
||||||
|
* \param datalink Datalink type.
|
||||||
|
* \param ts Timeval structure.
|
||||||
|
* \param len Packet length.
|
||||||
|
* \param tenant_id Tenant id of the detection engine to use.
|
||||||
|
* \param flags Packet flags (packet checksum, rule profiling...).
|
||||||
|
* \param iface Sniffing interface this packet comes from (can be NULL).
|
||||||
|
* \return Error code.
|
||||||
|
*/
|
||||||
|
int TmModuleLibHandlePacket(ThreadVars *tv, const uint8_t *data, int datalink, struct timeval ts,
|
||||||
|
uint32_t len, uint32_t tenant_id, uint32_t flags, const char *iface)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* If the packet is NULL, consider it as a read timeout. */
|
||||||
|
if (data == NULL) {
|
||||||
|
TmThreadsSetFlag(tv, THV_CAPTURE_INJECT_PKT);
|
||||||
|
TmThreadsCaptureHandleTimeout(tv, NULL);
|
||||||
|
SCReturnInt(TM_ECODE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet *p = PacketGetFromQueueOrAlloc();
|
||||||
|
if (unlikely(p == NULL)) {
|
||||||
|
SCReturnInt(TM_ECODE_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we are processing a PCAP and it is the first packet we need to set the timestamp. */
|
||||||
|
SCTime_t timestamp = SCTIME_FROM_TIMEVAL(&ts);
|
||||||
|
if (!time_set && !TimeModeIsLive()) {
|
||||||
|
TmThreadsInitThreadsTimestamp(timestamp);
|
||||||
|
time_set = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PKT_SET_SRC(p, PKT_SRC_WIRE);
|
||||||
|
p->ts = timestamp;
|
||||||
|
p->datalink = datalink;
|
||||||
|
p->tenant_id = tenant_id;
|
||||||
|
p->flags |= flags;
|
||||||
|
|
||||||
|
/* Set the sniffing interface. */
|
||||||
|
if (iface) {
|
||||||
|
p->livedev = LiveGetDevice(iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PacketSetData(p, data, len) == -1) {
|
||||||
|
TmqhOutputPacketpool(tv, p);
|
||||||
|
SCReturnInt(TM_ECODE_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", GET_PKT_LEN(p), p, GET_PKT_DATA(p));
|
||||||
|
|
||||||
|
if (TmThreadsSlotProcessPkt(tv, tv->tm_slots, p) != TM_ECODE_OK) {
|
||||||
|
SCReturnInt(TM_ECODE_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCReturnInt(TM_ECODE_OK);
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/* Copyright (C) 2023-2024 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 Angelo Mirabella <angelo.mirabella@broadcom.com>
|
||||||
|
*
|
||||||
|
* LIB packet and stream decoding support
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SURICATA_SOURCE_LIB_H
|
||||||
|
#define SURICATA_SOURCE_LIB_H
|
||||||
|
|
||||||
|
#include "tm-threads.h"
|
||||||
|
|
||||||
|
/** \brief register a "Decode" module for suricata as a library.
|
||||||
|
*
|
||||||
|
* The "Decode" module is the first module invoked when processing a packet */
|
||||||
|
void TmModuleDecodeLibRegister(void);
|
||||||
|
|
||||||
|
/** \brief process a single packet.
|
||||||
|
*
|
||||||
|
* \param tv Pointer to the per-thread structure.
|
||||||
|
* \param data Pointer to the raw packet.
|
||||||
|
* \param datalink Datalink type.
|
||||||
|
* \param ts Timeval structure.
|
||||||
|
* \param len Packet length.
|
||||||
|
* \param tenant_id Tenant id of the detection engine to use.
|
||||||
|
* \param flags Packet flags (packet checksum, rule profiling...).
|
||||||
|
* \param iface Sniffing interface this packet comes from (can be NULL).
|
||||||
|
* \return Error code.
|
||||||
|
*/
|
||||||
|
int TmModuleLibHandlePacket(ThreadVars *tv, const uint8_t *data, int datalink, struct timeval ts,
|
||||||
|
uint32_t len, uint32_t tenant_id, uint32_t flags, const char *iface);
|
||||||
|
|
||||||
|
#endif /* SURICATA_SOURCE_LIB_H */
|
Loading…
Reference in New Issue