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"
35 #include "detect-engine-mpm.h"
36 #include "detect-engine-state.h"
37 
38 #include "util-byte.h"
39 #include "util-debug.h"
40 #include "util-print.h"
41 
42 #define PARSE_REGEX "([a-z]+)(?:,\\s*([\\-_A-z0-9\\s\\.]+)){1,4}"
43 static DetectParseRegex parse_regex;
44 
46  const Signature *, const SigMatchCtx *);
47 static int DetectDatarepSetup (DetectEngineCtx *, Signature *, const char *);
48 void DetectDatarepFree (void *);
49 
51 {
52  sigmatch_table[DETECT_DATAREP].name = "datarep";
53  sigmatch_table[DETECT_DATAREP].desc = "operate on datasets (experimental)";
54  sigmatch_table[DETECT_DATAREP].url = DOC_URL DOC_VERSION "/rules/dataset-keywords.html#datarep";
55  sigmatch_table[DETECT_DATAREP].Setup = DetectDatarepSetup;
57 
58  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
59 }
60 
61 /*
62  1 match
63  0 no match
64  -1 can't match
65  */
67  const DetectDatarepData *sd,
68  const uint8_t *data, const uint32_t data_len)
69 {
70  if (data == NULL || data_len == 0)
71  return 0;
72 
73  DataRepResultType r = DatasetLookupwRep(sd->set, data, data_len, &sd->rep);
74  if (!r.found)
75  return 0;
76 
77  switch (sd->op) {
78  case DATAREP_OP_GT:
79  if (r.rep.value > sd->rep.value)
80  return 1;
81  break;
82  case DATAREP_OP_LT:
83  if (r.rep.value < sd->rep.value)
84  return 1;
85  break;
86  case DATAREP_OP_EQ:
87  if (r.rep.value == sd->rep.value)
88  return 1;
89  break;
90  }
91  return 0;
92 }
93 
94 static int DetectDatarepParse(const char *str,
95  char *cmd, int cmd_len,
96  char *name, int name_len,
97  enum DatasetTypes *type,
98  char *load, size_t load_size,
99  uint16_t *rep_value)
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 {
164  SCLogDebug("bad type %s", val);
165  return -1;
166  }
167 
168  } else if (strcmp(key, "load") == 0) {
169  SCLogDebug("load %s", val);
170  strlcpy(load, val, load_size);
171  }
172  }
173 
174  SCLogDebug("key: %s, value: %s", key, val);
175 
176  next:
177  key = strtok_r(NULL, ",", &xsaveptr);
178  }
179 
180  if (strlen(load) > 0 && *type == DATASET_TYPE_NOTSET) {
182  "if load is used type must be set as well");
183  return 0;
184  }
185 
186  if (!name_set || !cmd_set || !value_set) {
188  "missing values");
189  return 0;
190  }
191 
192  /* Trim trailing whitespace. */
193  while (strlen(name) > 0 && isblank(name[strlen(name) - 1])) {
194  name[strlen(name) - 1] = '\0';
195  }
196 
197  /* Validate name, spaces are not allowed. */
198  for (size_t i = 0; i < strlen(name); i++) {
199  if (isblank(name[i])) {
201  "spaces not allowed in dataset names");
202  return 0;
203  }
204  }
205 
206  return 1;
207 }
208 
209 /** \brief wrapper around dirname that does leave input untouched */
210 static void GetDirName(const char *in, char *out, size_t outs)
211 {
212  if (strlen(in) == 0) {
213  return;
214  }
215 
216  size_t size = strlen(in) + 1;
217  char tmp[size];
218  strlcpy(tmp, in, size);
219 
220  char *dir = dirname(tmp);
221  BUG_ON(dir == NULL);
222  strlcpy(out, dir, outs);
223  return;
224 }
225 
226 static int SetupLoadPath(const DetectEngineCtx *de_ctx,
227  char *load, size_t load_size)
228 {
229  SCLogDebug("load %s", load);
230 
231  if (PathIsAbsolute(load)) {
232  return 0;
233  }
234 
235  bool done = false;
236 #ifdef HAVE_LIBGEN_H
237  BUG_ON(de_ctx->rule_file == NULL);
238 
239  char dir[PATH_MAX] = "";
240  GetDirName(de_ctx->rule_file, dir, sizeof(dir));
241 
242  SCLogDebug("rule_file %s dir %s", de_ctx->rule_file, dir);
243  char path[PATH_MAX];
244  if (snprintf(path, sizeof(path), "%s/%s", dir, load) >= (int)sizeof(path)) // TODO windows path
245  return -1;
246 
247  if (SCPathExists(path)) {
248  done = true;
249  strlcpy(load, path, load_size);
250  SCLogDebug("using path '%s' (HAVE_LIBGEN_H)", load);
251  } else {
252  SCLogDebug("path '%s' does not exist (HAVE_LIBGEN_H)", path);
253  }
254 #endif
255  if (!done) {
256  char *loadp = DetectLoadCompleteSigPath(de_ctx, load);
257  if (loadp == NULL) {
258  return -1;
259  }
260  SCLogDebug("loadp %s", loadp);
261 
262  if (SCPathExists(loadp)) {
263  strlcpy(load, loadp, load_size);
264  SCLogDebug("using path '%s' (non-HAVE_LIBGEN_H)", load);
265  } else {
266  SCLogDebug("path '%s' does not exist (non-HAVE_LIBGEN_H)", loadp);
267  }
268  SCFree(loadp);
269 
270  // TODO try data-dir as well?
271  }
272  return 0;
273 }
274 
275 static int DetectDatarepSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
276 {
277  SigMatch *sm = NULL;
278  char cmd_str[16] = "", name[64] = "";
280  char load[PATH_MAX];
281  uint16_t value = 0;
282 
283  if (DetectBufferGetActiveList(de_ctx, s) == -1) {
285  "datarep is only supported for sticky buffers");
286  SCReturnInt(-1);
287  }
288 
289  int list = s->init_data->list;
290  if (list == DETECT_SM_LIST_NOTSET) {
292  "datarep is only supported for sticky buffers");
293  SCReturnInt(-1);
294  }
295 
296  if (!DetectDatarepParse(rawstr, cmd_str, sizeof(cmd_str), name,
297  sizeof(name), &type, load, sizeof(load), &value)) {
298  return -1;
299  }
300 
301  if (strlen(load) != 0) {
302  if (SetupLoadPath(de_ctx, load, sizeof(load)) != 0)
303  return -1;
304  }
305 
306  enum DetectDatarepOp op;
307  if (strcmp(cmd_str,">") == 0) {
308  op = DATAREP_OP_GT;
309  } else if (strcmp(cmd_str,"<") == 0) {
310  op = DATAREP_OP_LT;
311  } else if (strcmp(cmd_str,"==") == 0) {
312  op = DATAREP_OP_EQ;
313  } else {
315  "datarep operation \"%s\" is not supported.", cmd_str);
316  return -1;
317  }
318 
319  Dataset *set = DatasetGet(name, type, /* no save */ NULL, load);
320  if (set == NULL) {
322  "failed to set up datarep set '%s'.", name);
323  return -1;
324  }
325 
326  DetectDatarepData *cd = SCCalloc(1, sizeof(DetectDatarepData));
327  if (unlikely(cd == NULL))
328  goto error;
329 
330  cd->set = set;
331  cd->op = op;
332  cd->rep.value = value;
333 
334  SCLogDebug("cmd %s, name %s",
335  cmd_str, strlen(name) ? name : "(none)");
336 
337  /* Okay so far so good, lets get this into a SigMatch
338  * and put it in the Signature. */
339  sm = SigMatchAlloc();
340  if (sm == NULL)
341  goto error;
342 
343  sm->type = DETECT_DATAREP;
344  sm->ctx = (SigMatchCtx *)cd;
345  SigMatchAppendSMToList(s, sm, list);
346  return 0;
347 
348 error:
349  if (cd != NULL)
350  SCFree(cd);
351  if (sm != NULL)
352  SCFree(sm);
353  return -1;
354 }
355 
356 void DetectDatarepFree (void *ptr)
357 {
359 
360  if (fd == NULL)
361  return;
362 
363  SCFree(fd);
364 }
util-byte.h
SigTableElmt_::url
const char * url
Definition: detect.h:1204
detect-engine.h
StringParseUint16
int StringParseUint16(uint16_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:324
DataRepResultType::rep
DataRepType rep
Definition: datasets-reputation.h:33
SigTableElmt_::desc
const char * desc
Definition: detect.h:1203
SigTableElmt_::name
const char * name
Definition: detect.h:1201
DetectEngineCtx_::rule_file
char * rule_file
Definition: detect.h:865
SCFree
#define SCFree(a)
Definition: util-mem.h:322
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:335
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:2
DetectDatarepData_
Definition: detect-datarep.h:36
threads.h
DetectDatarepMatch
int DetectDatarepMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:761
DETECT_DATAREP
@ DETECT_DATAREP
Definition: detect-engine-register.h:98
DataRepResultType::found
bool found
Definition: datasets-reputation.h:32
SC_ERR_INVALID_SIGNATURE
@ SC_ERR_INVALID_SIGNATURE
Definition: util-error.h:69
DATASET_TYPE_SHA256
@ DATASET_TYPE_SHA256
Definition: datasets.h:32
DetectDatarepRegister
void DetectDatarepRegister(void)
Definition: detect-datarep.c:50
SigTableElmt_::Free
void(* Free)(void *)
Definition: detect.h:1192
DATAREP_OP_EQ
@ DATAREP_OP_EQ
Definition: detect-datarep.h:33
DetectBufferGetActiveList
int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine.c:985
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1187
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
DataRepResultType
Definition: datasets-reputation.h:31
datasets.h
decode.h
util-debug.h
type
uint8_t type
Definition: decode-icmpv4.h:2
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:16
DetectEngineThreadCtx_
Definition: detect.h:1004
SC_ERR_UNKNOWN_VALUE
@ SC_ERR_UNKNOWN_VALUE
Definition: util-error.h:159
DetectDatarepData_::rep
DataRepType rep
Definition: detect-datarep.h:40
DATASET_TYPE_NOTSET
#define DATASET_TYPE_NOTSET
Definition: datasets.h:29
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:2440
SignatureInitData_::list
int list
Definition: detect.h:498
util-print.h
DatasetGet
Dataset * DatasetGet(const char *name, enum DatasetTypes type, const char *save, const char *load)
Definition: datasets.c:408
detect-engine-mpm.h
DetectDatarepOp
DetectDatarepOp
Definition: detect-datarep.h:30
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:321
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:265
Packet_
Definition: decode.h:408
DATAREP_OP_LT
@ DATAREP_OP_LT
Definition: detect-datarep.h:32
SCCalloc
#define SCCalloc(nm, a)
Definition: util-mem.h:253
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:591
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:235
SigMatch_::type
uint8_t type
Definition: detect.h:319
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:313
DETECT_SM_LIST_NOTSET
#define DETECT_SM_LIST_NOTSET
Definition: detect.h:115
SCPathExists
bool SCPathExists(const char *path)
Check if a path exists.
Definition: util-path.c:132
DatasetTypes
DatasetTypes
Definition: datasets.h:28
DetectDatarepBufferMatch
int DetectDatarepBufferMatch(DetectEngineThreadCtx *det_ctx, const DetectDatarepData *sd, const uint8_t *data, const uint32_t data_len)
Definition: detect-datarep.c:66
suricata-common.h
DATAREP_OP_GT
@ DATAREP_OP_GT
Definition: detect-datarep.h:31
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:73
DetectParseRegex_
Definition: detect-parse.h:42
PathIsAbsolute
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition: util-path.c:39
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
DOC_URL
#define DOC_URL
Definition: suricata.h:86
DetectDatarepData_::set
Dataset * set
Definition: detect-datarep.h:37
DataRepType::value
uint16_t value
Definition: datasets-reputation.h:28
str
#define str(s)
Definition: suricata-common.h:256
detect-datarep.h
detect-parse.h
Signature_
Signature container.
Definition: detect.h:522
SigMatch_
a single match condition for a signature
Definition: detect.h:318
DATASET_TYPE_MD5
@ DATASET_TYPE_MD5
Definition: datasets.h:31
DATASET_TYPE_STRING
@ DATASET_TYPE_STRING
Definition: datasets.h:30
DetectLoadCompleteSigPath
char * DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, const char *sig_file)
Create the path if default-rule-path was specified.
Definition: detect-engine-loader.c:60
Dataset
Definition: datasets.h:36
DetectDatarepData_::op
enum DetectDatarepOp op
Definition: detect-datarep.h:39
PARSE_REGEX
#define PARSE_REGEX
Definition: detect-datarep.c:42
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:341
SigMatchAppendSMToList
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:349
DOC_VERSION
#define DOC_VERSION
Definition: suricata.h:91
DetectDatarepFree
void DetectDatarepFree(void *)
Definition: detect-datarep.c:356
DatasetLookupwRep
DataRepResultType DatasetLookupwRep(Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep)
Definition: datasets.c:835