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
|
||||
|
||||
SURICATA_LIBS = `$(LIBSURICATA_CONFIG) --libs`
|
||||
SURICATA_LIBS = `$(LIBSURICATA_CONFIG) --libs --static`
|
||||
SURICATA_CFLAGS := `$(LIBSURICATA_CONFIG) --cflags`
|
||||
|
||||
# Currently the Suricata logging system requires this to be even for
|
||||
# plugins.
|
||||
CPPFLAGS += "-D__SCFILENAME__=\"$(*F)\""
|
||||
|
||||
all: simple
|
||||
|
||||
simple: main.c
|
||||
$(CC) -o $@ $^ $(CFLAGS) $(SURICATA_CFLAGS) $(SURICATA_LIBS)
|
||||
$(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(SURICATA_CFLAGS) $(SURICATA_LIBS)
|
||||
|
||||
clean:
|
||||
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