suricata
detect-dataset.c
Go to the documentation of this file.
1/* Copyright (C) 2018-2025 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 * Implements the dataset keyword
24 */
25
26#include "suricata-common.h"
27#include "decode.h"
28#include "detect.h"
29#include "threads.h"
30#include "datasets.h"
32#include "detect-dataset.h"
33
34#include "detect-parse.h"
35#include "detect-engine.h"
37#include "detect-engine-mpm.h"
38#include "detect-engine-state.h"
39
40#include "util-debug.h"
41#include "util-print.h"
42#include "util-misc.h"
43#include "util-path.h"
44#include "util-conf.h"
45#include "util-validate.h"
46
47#define DETECT_DATASET_CMD_SET 0
48#define DETECT_DATASET_CMD_UNSET 1
49#define DETECT_DATASET_CMD_ISNOTSET 2
50#define DETECT_DATASET_CMD_ISSET 3
51
52static int DetectDatasetSetup (DetectEngineCtx *, Signature *, const char *);
53void DetectDatasetFree (DetectEngineCtx *, void *);
54
56{
58 sigmatch_table[DETECT_DATASET].desc = "match sticky buffer against datasets (experimental)";
59 sigmatch_table[DETECT_DATASET].url = "/rules/dataset-keywords.html#dataset";
60 sigmatch_table[DETECT_DATASET].Setup = DetectDatasetSetup;
62}
63
64/*
65 1 match
66 0 no match
67 */
68static int DetectDatajsonBufferMatch(DetectEngineThreadCtx *det_ctx, const DetectDatasetData *sd,
69 const uint8_t *data, const uint32_t data_len)
70{
71 if (data == NULL || data_len == 0)
72 return 0;
73
74 switch (sd->cmd) {
76 // PrintRawDataFp(stdout, data, data_len);
77 DataJsonResultType r = DatajsonLookup(sd->set, data, data_len);
78 SCLogDebug("r found: %d, len: %u", r.found, r.json.len);
79 if (!r.found)
80 return 0;
81 if (r.json.len > 0) {
82 /* we need to add 3 on length check for the added quotes and colon when
83 building the json string */
84 if (r.json.len + strlen(sd->json_key) + 3 < SIG_JSON_CONTENT_ITEM_LEN) {
85 if (DetectEngineThreadCtxGetJsonContext(det_ctx) < 0) {
87 return 0;
88 }
89 snprintf(det_ctx->json_content[det_ctx->json_content_len].json_content,
90 SIG_JSON_CONTENT_ITEM_LEN, "\"%s\":%s", sd->json_key, r.json.value);
91 det_ctx->json_content[det_ctx->json_content_len].id = sd->id;
92 det_ctx->json_content_len++;
93 SCLogDebug("Added json content %u (alloc length %u)", det_ctx->json_content_len,
94 det_ctx->json_content_capacity);
95 }
96 }
98 return 1;
99 }
101 // PrintRawDataFp(stdout, data, data_len);
102 DataJsonResultType r = DatajsonLookup(sd->set, data, data_len);
103 SCLogDebug("r found: %d, len: %u", r.found, r.json.len);
104 if (r.found) {
106 return 0;
107 }
108 return 1;
109 }
110 default:
111 DEBUG_VALIDATE_BUG_ON("unknown dataset with json command");
112 }
113 return 0;
114}
115
116/*
117 1 match
118 0 no match
119 */
121 const DetectDatasetData *sd,
122 const uint8_t *data, const uint32_t data_len)
123{
124 if (data == NULL || data_len == 0)
125 return 0;
126
127 if ((sd->format == DATASET_FORMAT_JSON) || (sd->format == DATASET_FORMAT_NDJSON)) {
128 return DetectDatajsonBufferMatch(det_ctx, sd, data, data_len);
129 }
130
131 switch (sd->cmd) {
133 //PrintRawDataFp(stdout, data, data_len);
134 int r = DatasetLookup(sd->set, data, data_len);
135 SCLogDebug("r %d", r);
136 if (r == 1)
137 return 1;
138 break;
139 }
141 //PrintRawDataFp(stdout, data, data_len);
142 int r = DatasetLookup(sd->set, data, data_len);
143 SCLogDebug("r %d", r);
144 if (r < 1)
145 return 1;
146 break;
147 }
149 //PrintRawDataFp(stdout, data, data_len);
150 int r = DatasetAdd(sd->set, data, data_len);
151 if (r == 1)
152 return 1;
153 break;
154 }
156 int r = DatasetRemove(sd->set, data, data_len);
157 if (r == 1)
158 return 1;
159 break;
160 }
161 default:
162 DEBUG_VALIDATE_BUG_ON("unknown dataset command");
163 }
164 return 0;
165}
166
167static int DetectDatasetParse(const char *str, char *cmd, int cmd_len, char *name, int name_len,
168 enum DatasetTypes *type, char *load, size_t load_size, char *save, size_t save_size,
169 uint64_t *memcap, uint32_t *hashsize, DatasetFormats *format, char *value_key,
170 size_t value_key_size, char *array_key, size_t array_key_size, char *enrichment_key,
171 size_t enrichment_key_size, bool *remove_key)
172{
173 bool cmd_set = false;
174 bool name_set = false;
175 bool load_set = false;
176 bool save_set = false;
177 bool state_set = false;
178 bool format_set = false;
179
180 char copy[strlen(str)+1];
181 strlcpy(copy, str, sizeof(copy));
182 char *xsaveptr = NULL;
183 char *key = strtok_r(copy, ",", &xsaveptr);
184
185 while (key != NULL) {
186 while (*key != '\0' && isblank(*key)) {
187 key++;
188 }
189 char *val = strchr(key, ' ');
190 if (val != NULL) {
191 *val++ = '\0';
192 while (*val != '\0' && isblank(*val)) {
193 val++;
194 SCLogDebug("cmd %s val %s", key, val);
195 }
196 } else {
197 SCLogDebug("cmd %s", key);
198 }
199
200 if (strlen(key) == 0) {
201 goto next;
202 }
203
204 if (!cmd_set) {
205 if (val && strlen(val) != 0) {
206 return -1;
207 }
208 strlcpy(cmd, key, cmd_len);
209 cmd_set = true;
210 } else if (!name_set) {
211 if (val && strlen(val) != 0) {
212 return -1;
213 }
214 strlcpy(name, key, name_len);
215 name_set = true;
216 } else {
217 if (val == NULL) {
218 /* only non fixed place option without value is remove_key */
219 if (strcmp(key, "remove_key") == 0) {
220 *remove_key = true;
221 } else
222 return -1;
223 } else if (strcmp(key, "type") == 0) {
224 SCLogDebug("type %s", val);
225
226 if (strcmp(val, "md5") == 0) {
228 } else if (strcmp(val, "sha256") == 0) {
230 } else if (strcmp(val, "string") == 0) {
232 } else if (strcmp(val, "ipv4") == 0) {
234 } else if (strcmp(val, "ipv6") == 0) {
236 } else if (strcmp(val, "ip") == 0) {
238 } else {
239 SCLogError("bad type %s", val);
240 return -1;
241 }
242
243 } else if (strcmp(key, "save") == 0) {
244 if (save_set) {
245 SCLogError("'save' can only appear once");
246 return -1;
247 }
248 SCLogDebug("save %s", val);
249 strlcpy(save, val, save_size);
250 save_set = true;
251 } else if (strcmp(key, "load") == 0) {
252 if (load_set) {
253 SCLogError("'load' can only appear once");
254 return -1;
255 }
256 SCLogDebug("load %s", val);
257 strlcpy(load, val, load_size);
258 load_set = true;
259 } else if (strcmp(key, "state") == 0) {
260 if (state_set) {
261 SCLogError("'state' can only appear once");
262 return -1;
263 }
264 SCLogDebug("state %s", val);
265 strlcpy(load, val, load_size);
266 strlcpy(save, val, save_size);
267 state_set = true;
268 } else if (strcmp(key, "format") == 0) {
269 if (format_set) {
270 SCLogError("'format' can only appear once");
271 return -1;
272 }
273 SCLogDebug("format %s", val);
274 if (strcmp(val, "csv") == 0) {
275 *format = DATASET_FORMAT_CSV;
276 } else if (strcmp(val, "ndjson") == 0) {
277 *format = DATASET_FORMAT_NDJSON;
278 } else if (strcmp(val, "json") == 0) {
279 *format = DATASET_FORMAT_JSON;
280 } else {
281 SCLogError("unknown format %s", val);
282 return -1;
283 }
284 format_set = true;
285 } else if (strcmp(key, "value_key") == 0) {
286 if (strlen(val) > value_key_size) {
287 SCLogError("'key' value too long (limit is %zu)", value_key_size);
288 return -1;
289 }
290 strlcpy(value_key, val, value_key_size);
291 } else if (strcmp(key, "array_key") == 0) {
292 if (strlen(val) > array_key_size) {
293 SCLogError("'key' value too long (limit is %zu)", array_key_size);
294 return -1;
295 }
296 strlcpy(array_key, val, array_key_size);
297 } else if (strcmp(key, "context_key") == 0) {
298 for (size_t i = 0; i < strlen(val); i++) {
299 if (!isalnum(val[i]) && val[i] != '_') {
300 SCLogError("context_key can only contain alphanumeric characters and "
301 "underscores");
302 return -1;
303 }
304 }
305 if (strlen(val) > enrichment_key_size) {
306 SCLogError("'key' value too long (limit is %zu)", enrichment_key_size);
307 return -1;
308 }
309 strlcpy(enrichment_key, val, enrichment_key_size);
310 }
311
312 if (strcmp(key, "memcap") == 0) {
313 if (ParseSizeStringU64(val, memcap) < 0) {
314 SCLogWarning("invalid value for memcap: %s,"
315 " resetting to default",
316 val);
317 *memcap = 0;
318 }
319 }
320 if (strcmp(key, "hashsize") == 0) {
321 if (ParseSizeStringU32(val, hashsize) < 0) {
322 SCLogWarning("invalid value for hashsize: %s,"
323 " resetting to default",
324 val);
325 *hashsize = 0;
326 }
327 }
328 }
329
330 SCLogDebug("key: %s, value: %s", key, val);
331
332 next:
333 key = strtok_r(NULL, ",", &xsaveptr);
334 }
335
336 if ((load_set || save_set) && state_set) {
337 SCLogError("'state' can not be mixed with 'load' and 'save'");
338 return -1;
339 }
340
341 /* Trim trailing whitespace. */
342 while (strlen(name) > 0 && isblank(name[strlen(name) - 1])) {
343 name[strlen(name) - 1] = '\0';
344 }
345
346 /* Validate name, spaces are not allowed. */
347 for (size_t i = 0; i < strlen(name); i++) {
348 if (isblank(name[i])) {
349 SCLogError("spaces not allowed in dataset names");
350 return 0;
351 }
352 }
353
354 return 1;
355}
356
357/** \brief wrapper around dirname that does leave input untouched */
358static void GetDirName(const char *in, char *out, size_t outs)
359{
360 if (strlen(in) == 0) {
361 return;
362 }
363
364 size_t size = strlen(in) + 1;
365 char tmp[size];
366 strlcpy(tmp, in, size);
367
368 char *dir = dirname(tmp);
369 BUG_ON(dir == NULL);
370 strlcpy(out, dir, outs);
371}
372
373static int SetupLoadPath(const DetectEngineCtx *de_ctx,
374 char *load, size_t load_size)
375{
376 SCLogDebug("load %s", load);
377
378 if (PathIsAbsolute(load)) {
379 return 0;
380 }
381
382 bool done = false;
383#ifdef HAVE_LIBGEN_H
384 BUG_ON(de_ctx->rule_file == NULL);
385
386 char dir[PATH_MAX] = "";
387 GetDirName(de_ctx->rule_file, dir, sizeof(dir));
388
389 SCLogDebug("rule_file %s dir %s", de_ctx->rule_file, dir);
390 char path[PATH_MAX];
391 if (snprintf(path, sizeof(path), "%s/%s", dir, load) >= (int)sizeof(path)) // TODO windows path
392 return -1;
393
394 if (SCPathExists(path)) {
395 done = true;
396 strlcpy(load, path, load_size);
397 SCLogDebug("using path '%s' (HAVE_LIBGEN_H)", load);
398 }
399#endif
400 if (!done) {
401 char *loadp = DetectLoadCompleteSigPath(de_ctx, load);
402 if (loadp == NULL) {
403 return -1;
404 }
405 SCLogDebug("loadp %s", loadp);
406
407 if (SCPathExists(loadp)) {
408 strlcpy(load, loadp, load_size);
409 SCLogDebug("using path '%s' (non-HAVE_LIBGEN_H)", load);
410 }
411 SCFree(loadp);
412 }
413 return 0;
414}
415
416static int SetupSavePath(const DetectEngineCtx *de_ctx,
417 char *save, size_t save_size)
418{
419 SCLogDebug("save %s", save);
420
421 int allow_save = 1;
422 if (SCConfGetBool("datasets.rules.allow-write", &allow_save)) {
423 if (!allow_save) {
424 SCLogError("Rules containing save/state datasets have been disabled");
425 return -1;
426 }
427 }
428
429 int allow_absolute = 0;
430 (void)SCConfGetBool("datasets.rules.allow-absolute-filenames", &allow_absolute);
431 if (allow_absolute) {
432 SCLogNotice("Allowing absolute filename for dataset rule: %s", save);
433 } else {
434 if (PathIsAbsolute(save)) {
435 SCLogError("Absolute paths not allowed: %s", save);
436 return -1;
437 }
438
439 if (SCPathContainsTraversal(save)) {
440 SCLogError("Directory traversals not allowed: %s", save);
441 return -1;
442 }
443 }
444
445 // data dir
446 const char *dir = ConfigGetDataDirectory();
447 BUG_ON(dir == NULL); // should not be able to fail
448 if (!PathIsAbsolute(save)) {
449 char path[PATH_MAX];
450 if (snprintf(path, sizeof(path), "%s/%s", dir, save) >=
451 (int)sizeof(path)) // TODO windows path
452 return -1;
453
454 /* TODO check if location exists and is writable */
455
456 strlcpy(save, path, save_size);
457 }
458
459 return 0;
460}
461
462int DetectDatasetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
463{
464 DetectDatasetData *cd = NULL;
465 uint8_t cmd = 0;
466 uint64_t memcap = 0;
467 uint32_t hashsize = 0;
468 char cmd_str[16] = "", name[DATASET_NAME_MAX_LEN + 1] = "";
470 char load[PATH_MAX] = "";
471 char save[PATH_MAX] = "";
473 char value_key[SIG_JSON_CONTENT_KEY_LEN] = "";
474 char array_key[SIG_JSON_CONTENT_KEY_LEN] = "";
475 char enrichment_key[SIG_JSON_CONTENT_KEY_LEN] = "";
476 bool remove_key = false;
477
478 if (DetectBufferGetActiveList(de_ctx, s) == -1) {
479 SCLogError("datasets are only supported for sticky buffers");
480 SCReturnInt(-1);
481 }
482
483 int list = s->init_data->list;
484 if (list == DETECT_SM_LIST_NOTSET) {
485 SCLogError("datasets are only supported for sticky buffers");
486 SCReturnInt(-1);
487 }
488
489 if (!DetectDatasetParse(rawstr, cmd_str, sizeof(cmd_str), name, sizeof(name), &type, load,
490 sizeof(load), save, sizeof(save), &memcap, &hashsize, &format, value_key,
491 sizeof(value_key), array_key, sizeof(array_key), enrichment_key,
492 sizeof(enrichment_key), &remove_key)) {
493 return -1;
494 }
495
496 if (strcmp(cmd_str,"isset") == 0) {
498 } else if (strcmp(cmd_str,"isnotset") == 0) {
500 } else if (strcmp(cmd_str,"set") == 0) {
501 if ((format == DATASET_FORMAT_JSON) || (format == DATASET_FORMAT_NDJSON)) {
502 SCLogError("json format is not supported for 'set' command");
503 return -1;
504 }
506 } else if (strcmp(cmd_str,"unset") == 0) {
507 if ((format == DATASET_FORMAT_JSON) || (format == DATASET_FORMAT_NDJSON)) {
508 SCLogError("json format is not supported for 'unset' command");
509 return -1;
510 }
512 } else {
513 SCLogError("dataset action \"%s\" is not supported.", cmd_str);
514 return -1;
515 }
516
517 if ((format == DATASET_FORMAT_JSON) || (format == DATASET_FORMAT_NDJSON)) {
518 if (strlen(save) != 0) {
519 SCLogError("json format is not supported with 'save' or 'state' option");
520 return -1;
521 }
522 if (strlen(enrichment_key) == 0) {
523 SCLogError("json format needs a 'context_key' parameter");
524 return -1;
525 }
526 if (strlen(value_key) == 0) {
527 SCLogError("json format needs a 'value_key' parameter");
528 return -1;
529 }
530 }
531
532 /* if just 'load' is set, we load data from the same dir as the
533 * rule file. If load+save is used, we use data dir */
534 if (strlen(save) == 0 && strlen(load) != 0) {
535 if (SetupLoadPath(de_ctx, load, sizeof(load)) != 0)
536 return -1;
537 /* if just 'save' is set, we use either full path or the
538 * data-dir */
539 } else if (strlen(save) != 0 && strlen(load) == 0) {
540 if (SetupSavePath(de_ctx, save, sizeof(save)) != 0)
541 return -1;
542 /* use 'save' logic for 'state', but put the resulting
543 * path into 'load' as well. */
544 } else if (strlen(save) != 0 && strlen(load) != 0 &&
545 strcmp(save, load) == 0) {
546 if (SetupSavePath(de_ctx, save, sizeof(save)) != 0)
547 return -1;
548 strlcpy(load, save, sizeof(load));
549 }
550
551 SCLogDebug("name '%s' load '%s' save '%s'", name, load, save);
552 Dataset *set = NULL;
553
554 if (format == DATASET_FORMAT_JSON) {
555 set = DatajsonGet(name, type, load, memcap, hashsize, value_key, array_key,
556 DATASET_FORMAT_JSON, remove_key);
557 } else if (format == DATASET_FORMAT_NDJSON) {
558 set = DatajsonGet(name, type, load, memcap, hashsize, value_key, NULL,
559 DATASET_FORMAT_NDJSON, remove_key);
560 } else {
561 set = DatasetGet(name, type, save, load, memcap, hashsize);
562 }
563 if (set == NULL) {
564 SCLogError("failed to set up dataset '%s'.", name);
565 return -1;
566 }
567
568 cd = SCCalloc(1, sizeof(DetectDatasetData));
569 if (unlikely(cd == NULL))
570 goto error;
571
572 cd->set = set;
573 cd->cmd = cmd;
574 cd->format = format;
575 if ((format == DATASET_FORMAT_JSON) || (format == DATASET_FORMAT_NDJSON)) {
576 strlcpy(cd->json_key, enrichment_key, sizeof(cd->json_key));
577 }
578 cd->id = s;
579
580 SCLogDebug("cmd %s, name %s",
581 cmd_str, strlen(name) ? name : "(none)");
582
583 /* Okay so far so good, lets get this into a SigMatch
584 * and put it in the Signature. */
585
586 if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_DATASET, (SigMatchCtx *)cd, list) == NULL) {
587 goto error;
588 }
589 return 0;
590
591error:
592 if (cd != NULL)
593 SCFree(cd);
594 return -1;
595}
596
598{
600 if (fd == NULL)
601 return;
602
603 SCFree(fd);
604}
struct HtpBodyChunk_ * next
int SCConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition conf.c:497
Dataset * DatajsonGet(const char *name, enum DatasetTypes type, const char *load, uint64_t memcap, uint32_t hashsize, char *json_key_value, char *json_array_key, DatasetFormats format, bool remove_key)
void DatajsonUnlockElt(DataJsonResultType *r)
DataJsonResultType DatajsonLookup(Dataset *set, const uint8_t *data, const uint32_t data_len)
int DatasetLookup(Dataset *set, const uint8_t *data, const uint32_t data_len)
see if data is part of the set
Definition datasets.c:1104
int DatasetAdd(Dataset *set, const uint8_t *data, const uint32_t data_len)
Definition datasets.c:1339
int DatasetRemove(Dataset *set, const uint8_t *data, const uint32_t data_len)
Definition datasets.c:1542
Dataset * DatasetGet(const char *name, enum DatasetTypes type, const char *save, const char *load, uint64_t memcap, uint32_t hashsize)
Definition datasets.c:451
#define DATASET_TYPE_NOTSET
Definition datasets.h:38
DatasetTypes
Definition datasets.h:37
@ DATASET_TYPE_STRING
Definition datasets.h:39
@ DATASET_TYPE_IPV6
Definition datasets.h:43
@ DATASET_TYPE_IPV4
Definition datasets.h:42
@ DATASET_TYPE_SHA256
Definition datasets.h:41
@ DATASET_TYPE_MD5
Definition datasets.h:40
#define DATASET_NAME_MAX_LEN
Definition datasets.h:46
DatasetFormats
Definition datasets.h:31
@ DATASET_FORMAT_CSV
Definition datasets.h:32
@ DATASET_FORMAT_JSON
Definition datasets.h:33
@ DATASET_FORMAT_NDJSON
Definition datasets.h:34
uint16_t type
int DetectDatasetBufferMatch(DetectEngineThreadCtx *det_ctx, const DetectDatasetData *sd, const uint8_t *data, const uint32_t data_len)
#define DETECT_DATASET_CMD_ISSET
void DetectDatasetRegister(void)
void DetectDatasetFree(DetectEngineCtx *, void *)
#define DETECT_DATASET_CMD_ISNOTSET
#define DETECT_DATASET_CMD_SET
#define DETECT_DATASET_CMD_UNSET
int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s)
char * DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, const char *sig_file)
Create the path if default-rule-path was specified.
Data structures and function prototypes for keeping state for the detection engine.
int DetectEngineThreadCtxGetJsonContext(DetectEngineThreadCtx *det_ctx)
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
SigTableElmt * sigmatch_table
#define DETECT_SM_LIST_NOTSET
Definition detect.h:144
#define SIG_JSON_CONTENT_ITEM_LEN
Definition detect.h:1232
#define SIG_JSON_CONTENT_KEY_LEN
Definition detect.h:1233
DetectEngineCtx * de_ctx
char json_key[SIG_JSON_CONTENT_KEY_LEN]
DatasetFormats format
main detection engine ctx
Definition detect.h:932
const char * rule_file
Definition detect.h:1024
SigJsonContent * json_content
Definition detect.h:1281
uint8_t json_content_capacity
Definition detect.h:1282
char json_content[SIG_JSON_CONTENT_ITEM_LEN]
Definition detect.h:1238
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
const char * url
Definition detect.h:1462
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
const char * desc
Definition detect.h:1461
const char * name
Definition detect.h:1459
Signature container.
Definition detect.h:668
SignatureInitData * init_data
Definition detect.h:747
#define BUG_ON(x)
#define str(s)
size_t strlcpy(char *dst, const char *src, size_t siz)
const char * name
const char * ConfigGetDataDirectory(void)
Definition util-conf.c:80
#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 SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define hashsize(n)
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition util-misc.c:173
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition util-misc.c:190
#define unlikely(expr)
bool SCPathContainsTraversal(const char *path)
Check for directory traversal.
Definition util-path.c:271
bool SCPathExists(const char *path)
Check if a path exists.
Definition util-path.c:183
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition util-path.c:44
#define DEBUG_VALIDATE_BUG_ON(exp)