suricata
source-pcap-file.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2016 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/**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 *
23 * File based pcap packet acquisition support
24 */
25
26#include "suricata-common.h"
27#include "source-pcap-file.h"
30#include "flow-manager.h"
31#include "util-checksum.h"
32#include "runmode-unix-socket.h"
33#include "suricata.h"
34#include "conf.h"
35#include "util-misc.h"
36
37extern uint32_t max_pending_packets;
39
40/**
41 * Union determining whether the behavior of the thread is file or directory
42 */
48
49/**
50 * Data specific to the thread
51 */
59
60static TmEcode ReceivePcapFileLoop(ThreadVars *, void *, void *);
61static TmEcode ReceivePcapFileThreadInit(ThreadVars *, const void *, void **);
62static void ReceivePcapFileThreadExitStats(ThreadVars *, void *);
63static TmEcode ReceivePcapFileThreadDeinit(ThreadVars *, void *);
64
65static TmEcode DecodePcapFile(ThreadVars *, Packet *, void *);
66static TmEcode DecodePcapFileThreadInit(ThreadVars *, const void *, void **);
67static TmEcode DecodePcapFileThreadDeinit(ThreadVars *tv, void *data);
68
69static void CleanupPcapDirectoryFromThreadVars(PcapFileThreadVars *tv,
71static void CleanupPcapFileFromThreadVars(PcapFileThreadVars *tv, PcapFileFileVars *pfv);
72static void CleanupPcapFileThreadVars(PcapFileThreadVars *tv);
73static TmEcode PcapFileExit(TmEcode status, struct timespec *last_processed);
74
75void CleanupPcapFileFromThreadVars(PcapFileThreadVars *tv, PcapFileFileVars *pfv)
76{
78 if (tv->is_directory == 0) {
79 tv->behavior.file = NULL;
80 }
81}
82
83void CleanupPcapDirectoryFromThreadVars(PcapFileThreadVars *tv, PcapFileDirectoryVars *ptv)
84{
86 if (tv->is_directory == 1) {
87 tv->behavior.directory = NULL;
88 }
89}
90
91void CleanupPcapFileThreadVars(PcapFileThreadVars *ptv)
92{
93 if (ptv != NULL) {
94 if (ptv->is_directory == 0) {
95 if (ptv->behavior.file != NULL) {
96 CleanupPcapFileFromThreadVars(ptv, ptv->behavior.file);
97 }
98 ptv->behavior.file = NULL;
99 } else {
100 if (ptv->behavior.directory != NULL) {
101 CleanupPcapDirectoryFromThreadVars(ptv, ptv->behavior.directory);
102 }
103 ptv->behavior.directory = NULL;
104 }
105 if (ptv->shared.bpf_string != NULL) {
107 ptv->shared.bpf_string = NULL;
108 }
109 SCFree(ptv);
110 }
111}
112
113/**
114 * Pcap File Functionality
115 */
128
139
140#if defined(HAVE_SETVBUF) && defined(OS_LINUX)
141#define PCAP_FILE_BUFFER_SIZE_DEFAULT 131072U // 128 KiB
142#define PCAP_FILE_BUFFER_SIZE_MIN 4096U // 4 KiB
143#define PCAP_FILE_BUFFER_SIZE_MAX 67108864U // 64MiB
144#endif
145
147{
148 memset(&pcap_g, 0x00, sizeof(pcap_g));
149 SC_ATOMIC_INIT(pcap_g.invalid_checksums);
150
151#if defined(HAVE_SETVBUF) && defined(OS_LINUX)
152 pcap_g.read_buffer_size = PCAP_FILE_BUFFER_SIZE_DEFAULT;
153
154 const char *str = NULL;
155 if (SCConfGet("pcap-file.buffer-size", &str) == 1) {
156 uint32_t value = 0;
157 if (ParseSizeStringU32(str, &value) < 0) {
158 SCLogWarning("failed to parse pcap-file.buffer-size %s", str);
159 }
160 if (value >= PCAP_FILE_BUFFER_SIZE_MIN && value <= PCAP_FILE_BUFFER_SIZE_MAX) {
161 SCLogInfo("Pcap-file will use %u buffer size", value);
162 pcap_g.read_buffer_size = value;
163 } else {
164 SCLogWarning("pcap-file.buffer-size value of %u is invalid. Valid range is %u-%u",
165 value, PCAP_FILE_BUFFER_SIZE_MIN, PCAP_FILE_BUFFER_SIZE_MAX);
166 }
167 }
168#endif
169}
170
171TmEcode PcapFileExit(TmEcode status, struct timespec *last_processed)
172{
174 status = UnixSocketPcapFile(status, last_processed);
175 SCReturnInt(status);
176 } else {
177 EngineStop();
178 SCReturnInt(status);
179 }
180}
181
182TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot)
183{
184 SCEnter();
185
186 if(unlikely(data == NULL)) {
187 SCLogError("pcap file reader thread failed to initialize");
188
189 PcapFileExit(TM_ECODE_FAILED, NULL);
190
192 }
193
194 TmEcode status = TM_ECODE_OK;
196 TmSlot *s = (TmSlot *)slot;
197
198 ptv->shared.slot = s->slot_next;
200
201 // Indicate that the thread is actually running its application level code (i.e., it can poll
202 // packets)
204
205 if(ptv->is_directory == 0) {
206 SCLogInfo("Starting file run for %s", ptv->behavior.file->filename);
207 status = PcapFileDispatch(ptv->behavior.file);
208 CleanupPcapFileFromThreadVars(ptv, ptv->behavior.file);
209 } else {
210 SCLogInfo("Starting directory run for %s", ptv->behavior.directory->filename);
212 CleanupPcapDirectoryFromThreadVars(ptv, ptv->behavior.directory);
213 }
214
215 SCLogDebug("Pcap file loop complete with status %u", status);
216
217 status = PcapFileExit(status, &ptv->shared.last_processed);
218 SCReturnInt(status);
219}
220
221TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, const void *initdata, void **data)
222{
223 SCEnter();
224
225 TmEcode status = TM_ECODE_OK;
226 const char *tmpstring = NULL;
227 const char *tmp_bpf_string = NULL;
228
229 if (initdata == NULL) {
230 SCLogError("error: initdata == NULL");
231
233 }
234
236 if (unlikely(ptv == NULL)) {
238 }
239 memset(&ptv->shared.last_processed, 0, sizeof(struct timespec));
240
241 intmax_t tenant = 0;
242 if (SCConfGetInt("pcap-file.tenant-id", &tenant) == 1) {
243 if (tenant > 0 && tenant < UINT_MAX) {
244 ptv->shared.tenant_id = (uint32_t)tenant;
245 SCLogInfo("tenant %u", ptv->shared.tenant_id);
246 } else {
247 SCLogError("tenant out of range");
248 }
249 }
250
251 if (SCConfGet("bpf-filter", &(tmp_bpf_string)) != 1) {
252 SCLogDebug("could not get bpf or none specified");
253 } else {
254 ptv->shared.bpf_string = SCStrdup(tmp_bpf_string);
255 if (unlikely(ptv->shared.bpf_string == NULL)) {
256 SCLogError("Failed to allocate bpf_string");
257
258 CleanupPcapFileThreadVars(ptv);
259
261 }
262 }
263
264 int should_delete = 0;
265 ptv->shared.should_delete = false;
266 if (SCConfGetBool("pcap-file.delete-when-done", &should_delete) == 1) {
267 ptv->shared.should_delete = should_delete == 1;
268 }
269
270 DIR *directory = NULL;
271 SCLogDebug("checking file or directory %s", (char*)initdata);
272 if(PcapDetermineDirectoryOrFile((char *)initdata, &directory) == TM_ECODE_FAILED) {
273 CleanupPcapFileThreadVars(ptv);
275 }
276
277 if(directory == NULL) {
278 SCLogDebug("argument %s was a file", (char *)initdata);
279 const size_t toalloc = sizeof(PcapFileFileVars) + pcap_g.read_buffer_size;
280 PcapFileFileVars *pv = SCCalloc(1, toalloc);
281 if (unlikely(pv == NULL)) {
282 SCLogError("Failed to allocate file vars");
283 CleanupPcapFileThreadVars(ptv);
285 }
286
287 pv->filename = SCStrdup((char *)initdata);
288 if (unlikely(pv->filename == NULL)) {
289 SCLogError("Failed to allocate filename");
291 CleanupPcapFileThreadVars(ptv);
293 }
294
295 pv->shared = &ptv->shared;
296 status = InitPcapFile(pv);
297 if(status == TM_ECODE_OK) {
298 ptv->is_directory = 0;
299 ptv->behavior.file = pv;
300 } else {
301 SCLogWarning("Failed to init pcap file %s, skipping", pv->filename);
303 CleanupPcapFileThreadVars(ptv);
305 }
306 } else {
307 SCLogInfo("Argument %s was a directory", (char *)initdata);
309 if (unlikely(pv == NULL)) {
310 SCLogError("Failed to allocate directory vars");
311 closedir(directory);
312 CleanupPcapFileThreadVars(ptv);
314 }
315
316 pv->filename = SCStrdup((char*)initdata);
317 if (unlikely(pv->filename == NULL)) {
318 SCLogError("Failed to allocate filename");
319 closedir(directory);
321 CleanupPcapFileThreadVars(ptv);
323 }
324
325 int should_recurse;
326 pv->should_recurse = false;
327 if (SCConfGetBool("pcap-file.recursive", &should_recurse) == 1) {
328 pv->should_recurse = (should_recurse == 1);
329 }
330
331 int should_loop = 0;
332 pv->should_loop = false;
333 if (SCConfGetBool("pcap-file.continuous", &should_loop) == 1) {
334 pv->should_loop = (should_loop == 1);
335 }
336
337 if (pv->should_recurse && pv->should_loop) {
338 SCLogError("Error, --pcap-file-continuous and --pcap-file-recursive "
339 "cannot be used together.");
340 closedir(directory);
342 CleanupPcapFileThreadVars(ptv);
344 }
345
346 pv->delay = 30;
347 intmax_t delay = 0;
348 if (SCConfGetInt("pcap-file.delay", &delay) == 1) {
349 if (delay > 0 && delay < UINT_MAX) {
350 pv->delay = (time_t)delay;
351 SCLogDebug("delay %lu", pv->delay);
352 } else {
353 SCLogError("delay out of range");
354 }
355 }
356
357 pv->poll_interval = 5;
358 intmax_t poll_interval = 0;
359 if (SCConfGetInt("pcap-file.poll-interval", &poll_interval) == 1) {
360 if (poll_interval > 0 && poll_interval < UINT_MAX) {
361 pv->poll_interval = (time_t)poll_interval;
362 SCLogDebug("poll-interval %lu", pv->delay);
363 } else {
364 SCLogError("poll-interval out of range");
365 }
366 }
367
368 pv->shared = &ptv->shared;
369 pv->directory = directory;
370 TAILQ_INIT(&pv->directory_content);
371
372 ptv->is_directory = 1;
373 ptv->behavior.directory = pv;
374 }
375
376 if (SCConfGet("pcap-file.checksum-checks", &tmpstring) != 1) {
378 } else {
379 if (strcmp(tmpstring, "auto") == 0) {
381 } else if (SCConfValIsTrue(tmpstring)) {
383 } else if (SCConfValIsFalse(tmpstring)) {
385 }
386 }
388
389 ptv->shared.tv = tv;
390 *data = (void *)ptv;
391
393}
394
395void ReceivePcapFileThreadExitStats(ThreadVars *tv, void *data)
396{
397 SCEnter();
398 if(data != NULL) {
400
403 SC_ATOMIC_GET(pcap_g.invalid_checksums)) {
404 uint64_t chrate = pcap_g.cnt / SC_ATOMIC_GET(pcap_g.invalid_checksums);
405 if (chrate < CHECKSUM_INVALID_RATIO)
406 SCLogWarning("1/%" PRIu64 "th of packets have an invalid checksum,"
407 " consider setting pcap-file.checksum-checks variable to no"
408 " or use '-k none' option on command line.",
409 chrate);
410 else
411 SCLogInfo("1/%" PRIu64 "th of packets have an invalid checksum",
412 chrate);
413 }
414 SCLogNotice("read %" PRIu64 " file%s, %" PRIu64 " packets, %" PRIu64 " bytes",
415 ptv->shared.files, ptv->shared.files == 1 ? "" : "s", ptv->shared.pkts,
416 ptv->shared.bytes);
417 }
418}
419
420TmEcode ReceivePcapFileThreadDeinit(ThreadVars *tv, void *data)
421{
422 SCEnter();
423 if(data != NULL) {
425 CleanupPcapFileThreadVars(ptv);
426 }
428}
429
430static TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data)
431{
432 SCEnter();
434
436
437 /* update counters */
439
440 DecoderFunc decoder;
441 if(ValidateLinkType(p->datalink, &decoder) == TM_ECODE_OK) {
442
443 /* call the decoder */
444 decoder(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p));
445
446#ifdef DEBUG
448#endif
449
451
453 } else {
455 }
456}
457
458TmEcode DecodePcapFileThreadInit(ThreadVars *tv, const void *initdata, void **data)
459{
460 SCEnter();
461 DecodeThreadVars *dtv = NULL;
463
464 if (dtv == NULL)
466
468
469 *data = (void *)dtv;
470
472}
473
474TmEcode DecodePcapFileThreadDeinit(ThreadVars *tv, void *data)
475{
476 if (data != NULL)
479}
480
482{
483 (void) SC_ATOMIC_ADD(pcap_g.invalid_checksums, 1);
484}
485
486/* eof */
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition conf.c:551
int SCConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition conf.c:414
int SCConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition conf.c:497
int SCConfValIsFalse(const char *val)
Check if a value is false.
Definition conf.c:576
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition conf.c:350
@ CHECKSUM_VALIDATION_AUTO
Definition decode.h:45
@ CHECKSUM_VALIDATION_ENABLE
Definition decode.h:44
@ CHECKSUM_VALIDATION_DISABLE
Definition decode.h:43
#define GET_PKT_DATA(p)
Definition decode.h:209
int(* DecoderFunc)(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition decode.h:1180
#define GET_PKT_LEN(p)
Definition decode.h:208
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition decode.h:1321
@ PKT_SRC_WIRE
Definition decode.h:52
@ PKT_SRC_FFR
Definition decode.h:58
DecodeThreadVars * dtv
ThreadVars * tv
uint32_t max_pending_packets
Definition suricata.c:183
void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv)
Definition decode.c:628
void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Finalize decoding of a packet.
Definition decode.c:232
DecodeThreadVars * DecodeThreadVarsAlloc(ThreadVars *tv)
Alloc and setup DecodeThreadVars.
Definition decode.c:804
void DecodeThreadVarsFree(ThreadVars *tv, DecodeThreadVars *dtv)
Definition decode.c:822
void DecodeUpdatePacketCounters(ThreadVars *tv, const DecodeThreadVars *dtv, const Packet *p)
Definition decode.c:770
#define TAILQ_INIT(head)
Definition queue.h:262
TmEcode UnixSocketPcapFile(TmEcode tm, struct timespec *last_processed)
int RunModeUnixSocketIsActive(void)
TmEcode PcapDetermineDirectoryOrFile(char *filename, DIR **directory)
void CleanupPcapFileDirectoryVars(PcapFileDirectoryVars *ptv)
TmEcode PcapDirectoryDispatch(PcapFileDirectoryVars *ptv)
TmEcode InitPcapFile(PcapFileFileVars *pfv)
TmEcode ValidateLinkType(int datalink, DecoderFunc *DecoderFn)
TmEcode PcapFileDispatch(PcapFileFileVars *ptv)
Main PCAP file reading Loop function.
void CleanupPcapFileFileVars(PcapFileFileVars *pfv)
struct PcapFileFileVars_ PcapFileFileVars
void PcapIncreaseInvalidChecksum(void)
void TmModuleReceivePcapFileRegister(void)
union PcapFileBehaviorVar_ PcapFileBehaviorVar
void TmModuleDecodePcapFileRegister(void)
struct PcapFileThreadVars_ PcapFileThreadVars
void PcapFileGlobalInit(void)
PcapFileGlobalVars pcap_g
Structure to hold thread specific data for all decode modules.
Definition decode.h:963
uint8_t pkt_src
Definition decode.h:611
int datalink
Definition decode.h:639
PcapFileSharedVars * shared
ChecksumValidationMode checksum_mode
ChecksumValidationMode conf_checksum_mode
PcapFileBehaviorVar behavior
PcapFileSharedVars shared
Per thread variable structure.
Definition threadvars.h:58
const char * name
Definition tm-modules.h:48
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
Definition tm-modules.h:53
void(* ThreadExitPrintStats)(ThreadVars *, void *)
Definition tm-modules.h:52
TmEcode(* PktAcqBreakLoop)(ThreadVars *, void *)
Definition tm-modules.h:61
uint8_t cap_flags
Definition tm-modules.h:77
TmEcode(* Func)(ThreadVars *, Packet *, void *)
Definition tm-modules.h:56
TmEcode(* PktAcqLoop)(ThreadVars *, void *, void *)
Definition tm-modules.h:58
uint8_t flags
Definition tm-modules.h:80
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
Definition tm-modules.h:51
struct TmSlot_ * slot_next
Definition tm-threads.h:62
#define BUG_ON(x)
#define str(s)
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
#define THV_RUNNING
Definition threadvars.h:55
TmModule tmm_modules[TMM_SIZE]
Definition tm-modules.c:29
#define TM_FLAG_RECEIVE_TM
Definition tm-modules.h:32
#define TM_FLAG_DECODE_TM
Definition tm-modules.h:33
@ TMM_RECEIVEPCAPFILE
@ TMM_DECODEPCAPFILE
@ TM_ECODE_FAILED
@ TM_ECODE_OK
@ TM_ECODE_DONE
void TmThreadsSetFlag(ThreadVars *tv, uint32_t flag)
Set a thread flag.
Definition tm-threads.c:101
PcapFileFileVars * file
PcapFileDirectoryVars * directory
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
#define CHECKSUM_INVALID_RATIO
#define CHECKSUM_SAMPLE_COUNT
#define SCEnter(...)
Definition util-debug.h:277
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition util-debug.h:243
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition util-debug.h:225
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCStrdup(s)
Definition util-mem.h:56
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition util-misc.c:173
#define unlikely(expr)
#define DEBUG_VALIDATE_BUG_ON(exp)