suricata
detect-datarep.c
Go to the documentation of this file.
1/* Copyright (C) 2018-2020 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 datarep keyword
24 */
25
26#include "suricata-common.h"
27#include "decode.h"
28#include "detect.h"
29#include "threads.h"
30#include "datasets.h"
31#include "detect-datarep.h"
32
33#include "detect-parse.h"
34#include "detect-engine.h"
36#include "detect-engine-mpm.h"
37#include "detect-engine-state.h"
38
39#include "util-byte.h"
40#include "util-debug.h"
41#include "util-print.h"
42#include "util-misc.h"
43#include "util-path.h"
44
45#define PARSE_REGEX "([a-z]+)(?:,\\s*([\\-_A-z0-9\\s\\.]+)){1,4}"
46static DetectParseRegex parse_regex;
47
49 const Signature *, const SigMatchCtx *);
50static int DetectDatarepSetup (DetectEngineCtx *, Signature *, const char *);
51void DetectDatarepFree (DetectEngineCtx *, void *);
52
54{
56 sigmatch_table[DETECT_DATAREP].desc = "operate on datasets (experimental)";
57 sigmatch_table[DETECT_DATAREP].url = "/rules/dataset-keywords.html#datarep";
58 sigmatch_table[DETECT_DATAREP].Setup = DetectDatarepSetup;
60
62}
63
64/*
65 1 match
66 0 no match
67 -1 can't match
68 */
70 const DetectDatarepData *sd,
71 const uint8_t *data, const uint32_t data_len)
72{
73 if (data == NULL || data_len == 0)
74 return 0;
75
76 DataRepResultType r = DatasetLookupwRep(sd->set, data, data_len, &sd->rep);
77 if (!r.found)
78 return 0;
79
80 switch (sd->op) {
81 case DATAREP_OP_GT:
82 if (r.rep.value > sd->rep.value)
83 return 1;
84 break;
85 case DATAREP_OP_LT:
86 if (r.rep.value < sd->rep.value)
87 return 1;
88 break;
89 case DATAREP_OP_EQ:
90 if (r.rep.value == sd->rep.value)
91 return 1;
92 break;
93 }
94 return 0;
95}
96
97static int DetectDatarepParse(const char *str, char *cmd, int cmd_len, char *name, int name_len,
98 enum DatasetTypes *type, char *load, size_t load_size, uint16_t *rep_value,
99 uint64_t *memcap, uint32_t *hashsize)
100{
101 bool cmd_set = false;
102 bool name_set = false;
103 bool value_set = false;
104
105 char copy[strlen(str)+1];
106 strlcpy(copy, str, sizeof(copy));
107 char *xsaveptr = NULL;
108 char *key = strtok_r(copy, ",", &xsaveptr);
109 while (key != NULL) {
110 while (*key != '\0' && isblank(*key)) {
111 key++;
112 }
113 char *val = strchr(key, ' ');
114 if (val != NULL) {
115 *val++ = '\0';
116 while (*val != '\0' && isblank(*val)) {
117 val++;
118 SCLogDebug("cmd %s val %s", key, val);
119 }
120 } else {
121 SCLogDebug("cmd %s", key);
122 }
123
124 if (strlen(key) == 0) {
125 goto next;
126 }
127
128 if (!name_set) {
129 if (val) {
130 return -1;
131 }
132 strlcpy(name, key, name_len);
133 name_set = true;
134 } else if (!cmd_set) {
135 if (val) {
136 return -1;
137 }
138 strlcpy(cmd, key, cmd_len);
139 cmd_set = true;
140 } else if (!value_set) {
141 if (val) {
142 return -1;
143 }
144
145 if (StringParseUint16(rep_value, 10, 0, key) < 0)
146 return -1;
147
148 value_set = true;
149 } else {
150 if (val == NULL) {
151 return -1;
152 }
153
154 if (strcmp(key, "type") == 0) {
155 SCLogDebug("type %s", val);
156
157 if (strcmp(val, "md5") == 0) {
159 } else if (strcmp(val, "sha256") == 0) {
161 } else if (strcmp(val, "string") == 0) {
163 } else if (strcmp(val, "ipv4") == 0) {
165 } else if (strcmp(val, "ip") == 0) {
167 } else if (strcmp(val, "ipv6") == 0) {
169 } else {
170 SCLogDebug("bad type %s", val);
171 return -1;
172 }
173
174 } else if (strcmp(key, "load") == 0) {
175 SCLogDebug("load %s", val);
176 strlcpy(load, val, load_size);
177 }
178 if (strcmp(key, "memcap") == 0) {
179 if (ParseSizeStringU64(val, memcap) < 0) {
180 SCLogWarning("invalid value for memcap: %s,"
181 " resetting to default",
182 val);
183 *memcap = 0;
184 }
185 }
186 if (strcmp(key, "hashsize") == 0) {
187 if (ParseSizeStringU32(val, hashsize) < 0) {
188 SCLogWarning("invalid value for hashsize: %s,"
189 " resetting to default",
190 val);
191 *hashsize = 0;
192 }
193 }
194 }
195
196 SCLogDebug("key: %s, value: %s", key, val);
197
198 next:
199 key = strtok_r(NULL, ",", &xsaveptr);
200 }
201
202 if (strlen(load) > 0 && *type == DATASET_TYPE_NOTSET) {
203 SCLogError("if load is used type must be set as well");
204 return 0;
205 }
206
207 if (!name_set || !cmd_set || !value_set) {
208 SCLogError("missing values");
209 return 0;
210 }
211
212 /* Trim trailing whitespace. */
213 while (strlen(name) > 0 && isblank(name[strlen(name) - 1])) {
214 name[strlen(name) - 1] = '\0';
215 }
216
217 /* Validate name, spaces are not allowed. */
218 for (size_t i = 0; i < strlen(name); i++) {
219 if (isblank(name[i])) {
220 SCLogError("spaces not allowed in dataset names");
221 return 0;
222 }
223 }
224
225 return 1;
226}
227
228/** \brief wrapper around dirname that does leave input untouched */
229static void GetDirName(const char *in, char *out, size_t outs)
230{
231 if (strlen(in) == 0) {
232 return;
233 }
234
235 size_t size = strlen(in) + 1;
236 char tmp[size];
237 strlcpy(tmp, in, size);
238
239 char *dir = dirname(tmp);
240 BUG_ON(dir == NULL);
241 strlcpy(out, dir, outs);
242}
243
244static int SetupLoadPath(const DetectEngineCtx *de_ctx,
245 char *load, size_t load_size)
246{
247 SCLogDebug("load %s", load);
248
249 if (PathIsAbsolute(load)) {
250 return 0;
251 }
252
253 bool done = false;
254#ifdef HAVE_LIBGEN_H
255 BUG_ON(de_ctx->rule_file == NULL);
256
257 char dir[PATH_MAX] = "";
258 GetDirName(de_ctx->rule_file, dir, sizeof(dir));
259
260 SCLogDebug("rule_file %s dir %s", de_ctx->rule_file, dir);
261 char path[PATH_MAX];
262 if (snprintf(path, sizeof(path), "%s/%s", dir, load) >= (int)sizeof(path)) // TODO windows path
263 return -1;
264
265 if (SCPathExists(path)) {
266 done = true;
267 strlcpy(load, path, load_size);
268 SCLogDebug("using path '%s' (HAVE_LIBGEN_H)", load);
269 } else {
270 SCLogDebug("path '%s' does not exist (HAVE_LIBGEN_H)", path);
271 }
272#endif
273 if (!done) {
274 char *loadp = DetectLoadCompleteSigPath(de_ctx, load);
275 if (loadp == NULL) {
276 return -1;
277 }
278 SCLogDebug("loadp %s", loadp);
279
280 if (SCPathExists(loadp)) {
281 strlcpy(load, loadp, load_size);
282 SCLogDebug("using path '%s' (non-HAVE_LIBGEN_H)", load);
283 } else {
284 SCLogDebug("path '%s' does not exist (non-HAVE_LIBGEN_H)", loadp);
285 }
286 SCFree(loadp);
287
288 // TODO try data-dir as well?
289 }
290 return 0;
291}
292
293static int DetectDatarepSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
294{
295 char cmd_str[16] = "", name[64] = "";
297 char load[PATH_MAX] = "";
298 uint16_t value = 0;
299 uint64_t memcap = 0;
300 uint32_t hashsize = 0;
301
302 if (DetectBufferGetActiveList(de_ctx, s) == -1) {
303 SCLogError("datarep is only supported for sticky buffers");
304 SCReturnInt(-1);
305 }
306
307 int list = s->init_data->list;
308 if (list == DETECT_SM_LIST_NOTSET) {
309 SCLogError("datarep is only supported for sticky buffers");
310 SCReturnInt(-1);
311 }
312
313 if (!DetectDatarepParse(rawstr, cmd_str, sizeof(cmd_str), name, sizeof(name), &type, load,
314 sizeof(load), &value, &memcap, &hashsize)) {
315 return -1;
316 }
317
318 if (strlen(load) != 0) {
319 if (SetupLoadPath(de_ctx, load, sizeof(load)) != 0)
320 return -1;
321 }
322
323 enum DetectDatarepOp op;
324 if (strcmp(cmd_str,">") == 0) {
325 op = DATAREP_OP_GT;
326 } else if (strcmp(cmd_str,"<") == 0) {
327 op = DATAREP_OP_LT;
328 } else if (strcmp(cmd_str,"==") == 0) {
329 op = DATAREP_OP_EQ;
330 } else {
331 SCLogError("datarep operation \"%s\" is not supported.", cmd_str);
332 return -1;
333 }
334
335 Dataset *set = DatasetGet(name, type, /* no save */ NULL, load, memcap, hashsize);
336 if (set == NULL) {
337 SCLogError("failed to set up datarep set '%s'.", name);
338 return -1;
339 }
340
342 if (unlikely(cd == NULL))
343 goto error;
344
345 cd->set = set;
346 cd->op = op;
347 cd->rep.value = value;
348
349 SCLogDebug("cmd %s, name %s",
350 cmd_str, strlen(name) ? name : "(none)");
351
352 /* Okay so far so good, lets get this into a SigMatch
353 * and put it in the Signature. */
354
355 if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_DATAREP, (SigMatchCtx *)cd, list) == NULL) {
356 goto error;
357 }
358 return 0;
359
360error:
361 if (cd != NULL)
362 SCFree(cd);
363 return -1;
364}
365
367{
369
370 if (fd == NULL)
371 return;
372
373 SCFree(fd);
374}
struct HtpBodyChunk_ * next
DataRepResultType DatasetLookupwRep(Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep)
Definition datasets.c:1124
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
uint16_t type
void DetectDatarepFree(DetectEngineCtx *, void *)
int DetectDatarepBufferMatch(DetectEngineThreadCtx *det_ctx, const DetectDatarepData *sd, const uint8_t *data, const uint32_t data_len)
void DetectDatarepRegister(void)
#define PARSE_REGEX
int DetectDatarepMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
DetectDatarepOp
@ DATAREP_OP_LT
@ DATAREP_OP_EQ
@ DATAREP_OP_GT
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.
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
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
DetectEngineCtx * de_ctx
enum DetectDatarepOp op
main detection engine ctx
Definition detect.h:932
const char * rule_file
Definition detect.h:1024
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
Per thread variable structure.
Definition threadvars.h:58
#define BUG_ON(x)
#define str(s)
size_t strlcpy(char *dst, const char *src, size_t siz)
const char * name
int StringParseUint16(uint16_t *res, int base, size_t len, const char *str)
Definition util-byte.c:337
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#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 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