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