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
31static int worker_id = 1;
32
33/**
34 * Struct to pass arguments into a worker thread.
35 */
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 */
54static 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 */
69static 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
133done:
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
150static 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
157int 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. */
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 /* Enable default signal handlers including SIGHUP for log file rotation,
206 * and SIGUSR2 for reloading rules. This should be done with care by a
207 * library user as the application may already have signal handlers
208 * loaded. */
210
211 /* Set "offline" runmode to replay a pcap in library mode. */
212 if (!SCConfSetFromString("runmode=offline", 1)) {
213 exit(EXIT_FAILURE);
214 }
215
216 /* Force logging to the current directory. */
217 SCConfSetFromString("default-log-dir=.", 1);
218
219 if (LiveRegisterDevice("lib0") < 0) {
220 fprintf(stderr, "LiveRegisterDevice failed");
221 exit(1);
222 }
223
224 SuricataInit();
225
226 SCDetectEngineRegisterRateFilterCallback(RateFilterCallback, NULL);
227
228 /* Create and start worker on its own thread, passing the PCAP
229 * file as argument. This needs to be done in between SuricataInit
230 * and SuricataPostInit. */
231 pthread_t worker;
233 if (!tv) {
234 FatalError("Failed to create ThreadVars");
235 }
236 struct WorkerArgs args = {
237 .tv = tv,
238 .pcap_filename = argv[argc - 1],
239 };
240 if (pthread_create(&worker, NULL, SimpleWorker, &args) != 0) {
241 exit(EXIT_FAILURE);
242 }
243
245
246 /* Run the main loop, this just waits for the worker thread to
247 * call EngineStop signalling Suricata that it is done reading the
248 * pcap. */
250
251 /* Shutdown engine. */
252 SCLogNotice("Shutting down");
253
254 /* Note that there is some thread synchronization between this
255 * function and SCTmThreadsSlotPacketLoopFinish that require them
256 * to be run concurrently at this time. */
258
260
261 return EXIT_SUCCESS;
262}
#define ACTION_DROP
int SCConfSetFromString(const char *input, int final)
Set a configuration parameter from a string.
Definition conf.c:264
@ PKT_SRC_WIRE
Definition decode.h:52
void SCDetectEngineRegisterRateFilterCallback(SCDetectRateFilterFunc fn, void *arg)
Register a callback when a rate_filter has been applied to an alert.
int main(int argc, char **argv)
Definition main.c:157
ThreadVars * tv
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
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:842
void PacketFreeOrRelease(Packet *p)
Return a packet to where it was allocated.
Definition decode.c:276
void SCPacketSetLiveDevice(Packet *p, LiveDevice *device)
Set a packets live device.
Definition packet.c:177
void SCPacketSetTime(Packet *p, SCTime_t ts)
Set the timestamp for a packet.
Definition packet.c:187
void SCPacketSetReleasePacket(Packet *p, void(*ReleasePacket)(Packet *p))
Set a packet release function.
Definition packet.c:172
void SCPacketSetSource(Packet *p, enum PktSrcEnum source)
Set packet source.
Definition packet.c:192
void SCPacketSetDatalink(Packet *p, int datalink)
Set a packets data link type.
Definition packet.c:182
bool PacketCheckAction(const Packet *p, const uint8_t a)
Definition packet.c:49
ThreadVars * SCRunModeLibCreateThreadVars(int worker_id)
Create ThreadVars for use by a user provided thread.
Definition runmode-lib.c:59
int SCRunModeLibSpawnWorker(void *td)
start the "fake" worker.
Definition runmode-lib.c:95
@ RUNMODE_LIB
Definition runmodes.h:40
Per thread variable structure.
Definition threadvars.h:58
struct TmSlot_ * tm_slots
Definition threadvars.h:96
char * pcap_filename
Definition main.c:38
ThreadVars * tv
Definition main.c:37
void SuricataInit(void)
Definition suricata.c:3012
void SCEnableDefaultSignalHandlers(void)
Enable default signal handlers.
Definition suricata.c:289
void SuricataShutdown(void)
Definition suricata.c:3100
TmEcode SCLoadYamlConfig(void)
Definition suricata.c:1012
int SCFinalizeRunMode(void)
Definition suricata.c:2451
volatile uint8_t suricata_ctl_flags
Definition suricata.c:172
int SCStartInternalRunMode(int argc, char **argv)
Definition suricata.c:2389
void GlobalsDestroy(void)
Definition suricata.c:390
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:470
void SCRunmodeSet(SCRunMode run_mode)
Set the current run mode.
Definition suricata.c:284
TmEcode SCParseCommandLine(int argc, char **argv)
Definition suricata.c:1369
void SuricataMainLoop(void)
Definition suricata.c:2922
void SuricataPreInit(const char *progname)
Definition suricata.c:3003
void SuricataPostInit(void)
Definition suricata.c:3111
#define SURICATA_STOP
Definition suricata.h:94
@ TM_ECODE_FAILED
@ TM_ECODE_OK
@ TM_ECODE_DONE
bool SCTmThreadsSlotPacketLoopFinish(ThreadVars *tv)
Definition tm-threads.c:273
void TmThreadsInitThreadsTimestamp(const SCTime_t ts)
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
#define FatalError(...)
Definition util-debug.h:510
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition util-debug.h:243
LiveDevice * LiveGetDevice(const char *name)
Get a pointer to the device at idx.
int LiveRegisterDevice(const char *dev)
Add a pcap device for monitoring and create structure.
void LiveDevicePktsIncr(LiveDevice *dev)
#define unlikely(expr)
#define SCTIME_FROM_TIMEVAL(tv)
Definition util-time.h:79