suricata
main.c
Go to the documentation of this file.
1 /* Copyright (C) 2024 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 #include "suricata.h"
19 #include "detect.h"
20 #include "detect-engine.h"
21 #include "runmodes.h"
22 #include "conf.h"
23 #include "pcap.h"
24 #include "runmode-lib.h"
25 #include "tm-threads.h"
26 #include "threadvars.h"
27 #include "action-globals.h"
28 #include "packet.h"
29 #include "util-device.h"
30 
31 static int worker_id = 1;
32 
33 /**
34  * Struct to pass arguments into a worker thread.
35  */
36 struct WorkerArgs {
39 };
40 
41 /**
42  * Release packet callback.
43  *
44  * If there is any cleanup that needs to be done when Suricata is done
45  * with a packet, this is the place to do it.
46  *
47  * Important: If using a custom release function, you must also
48  * release or free the packet.
49  *
50  * Optionally this is where you would handle IPS like functionality
51  * such as forwarding the packet, or triggering some other mechanism
52  * to forward the packet.
53  */
54 static void ReleasePacket(Packet *p)
55 {
57  SCLogNotice("Dropping packet!");
58  }
59 
60  /* As we overode the default release function, we must release or
61  * free the packet. */
63 }
64 
65 /**
66  * Suricata worker thread in library mode.
67  * The functions should be wrapped in an API layer.
68  */
69 static void *SimpleWorker(void *arg)
70 {
71  struct WorkerArgs *args = arg;
72  ThreadVars *tv = args->tv;
73 
74  /* Start worker. */
75  if (SCRunModeLibSpawnWorker(tv) != 0) {
76  pthread_exit(NULL);
77  }
78 
79  /* Replay pcap. */
80  pcap_t *fp = pcap_open_offline(args->pcap_filename, NULL);
81  if (fp == NULL) {
82  pthread_exit(NULL);
83  }
84 
85  LiveDevice *device = LiveGetDevice("lib0");
86  assert(device != NULL);
87 
88  int datalink = pcap_datalink(fp);
89  int count = 0;
90  struct pcap_pkthdr pkthdr;
91  const u_char *packet;
92  while ((packet = pcap_next(fp, &pkthdr)) != NULL) {
93 
94  /* Have we been asked to stop? */
96  goto done;
97  }
98 
100  if (unlikely(p == NULL)) {
101  /* Memory allocation error. */
102  goto done;
103  }
104 
105  /* If we are processing a PCAP and it is the first packet we need to set the timestamp. */
106  SCTime_t timestamp = SCTIME_FROM_TIMEVAL(&pkthdr.ts);
107  if (count == 0) {
109  }
110 
111  /* Setup the packet, these will become functions to avoid
112  * internal Packet access. */
114  SCPacketSetTime(p, SCTIME_FROM_TIMEVAL(&pkthdr.ts));
115  SCPacketSetDatalink(p, datalink);
116  SCPacketSetLiveDevice(p, device);
117  SCPacketSetReleasePacket(p, ReleasePacket);
118 
119  if (PacketSetData(p, packet, pkthdr.len) == -1) {
121  goto done;
122  }
123 
124  if (TmThreadsSlotProcessPkt(tv, tv->tm_slots, p) != TM_ECODE_OK) {
126  goto done;
127  }
128 
129  LiveDevicePktsIncr(device);
130  count++;
131  }
132 
133 done:
134  pcap_close(fp);
135 
136  /* Stop the engine. */
137  EngineStop();
138 
139  /* Cleanup.
140  *
141  * Note that there is some thread synchronization between this
142  * function and SuricataShutdown such that they must be run
143  * concurrently at this time before either will exit. */
145 
146  SCLogNotice("Worker thread exiting");
147  pthread_exit(NULL);
148 }
149 
150 static uint8_t RateFilterCallback(const Packet *p, const uint32_t sid, const uint32_t gid,
151  const uint32_t rev, uint8_t original_action, uint8_t new_action, void *arg)
152 {
153  /* Don't change the action. */
154  return new_action;
155 }
156 
157 int main(int argc, char **argv)
158 {
159  SuricataPreInit(argv[0]);
160 
161  /* Parse command line options. This is optional, you could
162  * directly configure Suricata through the Conf API. */
163  SCParseCommandLine(argc, argv);
164 
165  /* Find our list of pcap files, after the "--". */
166  while (argc) {
167  bool end = strncmp(argv[0], "--", 2) == 0;
168  argv++;
169  argc--;
170  if (end) {
171  break;
172  }
173  }
174  if (argc == 0) {
175  fprintf(stderr, "ERROR: No PCAP files provided\n");
176  return 1;
177  }
178 
179  /* Set the runmode to library mode. Perhaps in the future this
180  * should be done in some library bootstrap function. */
182 
183  /* Validate/finalize the runmode. */
184  if (SCFinalizeRunMode() != TM_ECODE_OK) {
185  exit(EXIT_FAILURE);
186  }
187 
188  /* Handle internal runmodes. Typically you wouldn't do this as a
189  * library user, however this example is showing how to replicate
190  * the Suricata application with the library. */
191  switch (SCStartInternalRunMode(argc, argv)) {
192  case TM_ECODE_DONE:
193  exit(EXIT_SUCCESS);
194  case TM_ECODE_FAILED:
195  exit(EXIT_FAILURE);
196  }
197 
198  /* Load configuration file, could be done earlier but must be done
199  * before SuricataInit, but even then its still optional as you
200  * may be programmatically configuration Suricata. */
201  if (SCLoadYamlConfig() != TM_ECODE_OK) {
202  exit(EXIT_FAILURE);
203  }
204 
205  /* Set "offline" runmode to replay a pcap in library mode. */
206  if (!SCConfSetFromString("runmode=offline", 1)) {
207  exit(EXIT_FAILURE);
208  }
209 
210  /* Force logging to the current directory. */
211  SCConfSetFromString("default-log-dir=.", 1);
212 
213  if (LiveRegisterDevice("lib0") < 0) {
214  fprintf(stderr, "LiveRegisterDevice failed");
215  exit(1);
216  }
217 
218  SuricataInit();
219 
220  SCDetectEngineRegisterRateFilterCallback(RateFilterCallback, NULL);
221 
222  /* Create and start worker on its own thread, passing the PCAP
223  * file as argument. This needs to be done in between SuricataInit
224  * and SuricataPostInit. */
225  pthread_t worker;
227  if (!tv) {
228  FatalError("Failed to create ThreadVars");
229  }
230  struct WorkerArgs args = {
231  .tv = tv,
232  .pcap_filename = argv[argc - 1],
233  };
234  if (pthread_create(&worker, NULL, SimpleWorker, &args) != 0) {
235  exit(EXIT_FAILURE);
236  }
237 
239 
240  /* Run the main loop, this just waits for the worker thread to
241  * call EngineStop signalling Suricata that it is done reading the
242  * pcap. */
244 
245  /* Shutdown engine. */
246  SCLogNotice("Shutting down");
247 
248  /* Note that there is some thread synchronization between this
249  * function and SCTmThreadsSlotPacketLoopFinish that require them
250  * to be run concurrently at this time. */
252 
253  GlobalsDestroy();
254 
255  return EXIT_SUCCESS;
256 }
PacketCheckAction
bool PacketCheckAction(const Packet *p, const uint8_t a)
Definition: packet.c:49
SCTmThreadsSlotPacketLoopFinish
bool SCTmThreadsSlotPacketLoopFinish(ThreadVars *tv)
Definition: tm-threads.c:273
tm-threads.h
SuricataMainLoop
void SuricataMainLoop(void)
Definition: suricata.c:2915
detect-engine.h
LiveRegisterDevice
int LiveRegisterDevice(const char *dev)
Add a pcap device for monitoring and create structure.
Definition: util-device.c:132
PacketFreeOrRelease
void PacketFreeOrRelease(Packet *p)
Return a packet to where it was allocated.
Definition: decode.c:276
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SCPacketSetLiveDevice
void SCPacketSetLiveDevice(Packet *p, LiveDevice *device)
Set a packets live device.
Definition: packet.c:177
SuricataInit
void SuricataInit(void)
Definition: suricata.c:3005
TM_ECODE_DONE
@ TM_ECODE_DONE
Definition: tm-threads-common.h:83
action-globals.h
SuricataPostInit
void SuricataPostInit(void)
Definition: suricata.c:3104
LiveDevice_
Definition: util-device-private.h:32
SURICATA_STOP
#define SURICATA_STOP
Definition: suricata.h:94
SCParseCommandLine
TmEcode SCParseCommandLine(int argc, char **argv)
Definition: suricata.c:1364
WorkerArgs
Definition: main.c:36
SuricataShutdown
void SuricataShutdown(void)
Definition: suricata.c:3093
TmqhOutputPacketpool
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
Definition: tmqh-packetpool.c:314
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:82
RUNMODE_LIB
@ RUNMODE_LIB
Definition: runmodes.h:40
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:81
SCPacketSetSource
void SCPacketSetSource(Packet *p, enum PktSrcEnum source)
Set packet source.
Definition: packet.c:192
SCRunmodeSet
void SCRunmodeSet(SCRunMode run_mode)
Set the current run mode.
Definition: suricata.c:284
util-device.h
PKT_SRC_WIRE
@ PKT_SRC_WIRE
Definition: decode.h:52
main
int main(int argc, char **argv)
Definition: main.c:20
ThreadVars_::tm_slots
struct TmSlot_ * tm_slots
Definition: threadvars.h:96
LiveGetDevice
LiveDevice * LiveGetDevice(const char *name)
Get a pointer to the device at idx.
Definition: util-device.c:268
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
SCTIME_FROM_TIMEVAL
#define SCTIME_FROM_TIMEVAL(tv)
Definition: util-time.h:79
SCRunModeLibSpawnWorker
int SCRunModeLibSpawnWorker(void *td)
start the "fake" worker.
Definition: runmode-lib.c:95
SCDetectEngineRegisterRateFilterCallback
void SCDetectEngineRegisterRateFilterCallback(SCDetectRateFilterFunc fn, void *arg)
Register a callback when a rate_filter has been applied to an alert.
Definition: detect-engine.c:5056
Packet_
Definition: decode.h:501
conf.h
SCPacketSetTime
void SCPacketSetTime(Packet *p, SCTime_t ts)
Set the timestamp for a packet.
Definition: packet.c:187
SCTime_t
Definition: util-time.h:40
runmodes.h
SCConfSetFromString
int SCConfSetFromString(const char *input, int final)
Set a configuration parameter from a string.
Definition: conf.c:264
TmThreadsInitThreadsTimestamp
void TmThreadsInitThreadsTimestamp(const SCTime_t ts)
Definition: tm-threads.c:2342
packet.h
WorkerArgs::pcap_filename
char * pcap_filename
Definition: main.c:38
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
SCStartInternalRunMode
int SCStartInternalRunMode(int argc, char **argv)
Definition: suricata.c:2384
SCPacketSetReleasePacket
void SCPacketSetReleasePacket(Packet *p, void(*ReleasePacket)(Packet *p))
Set a packet release function.
Definition: packet.c:172
FatalError
#define FatalError(...)
Definition: util-debug.h:510
EngineStop
void EngineStop(void)
make sure threads can stop the engine by calling this function. Purpose: pcap file mode needs to be a...
Definition: suricata.c:465
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
threadvars.h
SCLoadYamlConfig
TmEcode SCLoadYamlConfig(void)
Definition: suricata.c:1007
SCRunModeLibCreateThreadVars
ThreadVars * SCRunModeLibCreateThreadVars(int worker_id)
Create ThreadVars for use by a user provided thread.
Definition: runmode-lib.c:59
runmode-lib.h
PacketSetData
int PacketSetData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Set data for Packet and set length when zero copy is used.
Definition: decode.c:840
suricata.h
SCPacketSetDatalink
void SCPacketSetDatalink(Packet *p, int datalink)
Set a packets data link type.
Definition: packet.c:182
WorkerArgs::tv
ThreadVars * tv
Definition: main.c:37
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:243
SuricataPreInit
void SuricataPreInit(const char *progname)
Definition: suricata.c:2996
PacketGetFromQueueOrAlloc
Packet * PacketGetFromQueueOrAlloc(void)
Get a packet. We try to get a packet from the packetpool first, but if that is empty we alloc a packe...
Definition: decode.c:293
SCFinalizeRunMode
int SCFinalizeRunMode(void)
Definition: suricata.c:2446
GlobalsDestroy
void GlobalsDestroy(void)
Definition: suricata.c:385
suricata_ctl_flags
volatile uint8_t suricata_ctl_flags
Definition: suricata.c:172
LiveDevicePktsIncr
void LiveDevicePktsIncr(LiveDevice *dev)
Definition: util-device.c:637