suricata
detect-mark.c
Go to the documentation of this file.
1 /* Copyright (C) 2011 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 Eric Leblond <eric@regit.org>
22  *
23  * Implements the mark keyword. Based on detect-gid
24  * by Breno Silva <breno.silva@gmail.com>
25  */
26 
27 #include "suricata-common.h"
28 #include "suricata.h"
29 #include "decode.h"
30 #include "detect.h"
31 #include "flow-var.h"
32 #include "decode-events.h"
33 
34 #include "detect-mark.h"
35 #include "detect-parse.h"
36 
37 #include "util-unittest.h"
38 #include "util-debug.h"
39 
40 #define PARSE_REGEX "([0x]*[0-9a-f]+)/([0x]*[0-9a-f]+)"
41 
42 static pcre *parse_regex;
43 static pcre_extra *parse_regex_study;
44 
45 static int DetectMarkSetup (DetectEngineCtx *, Signature *, const char *);
46 static int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p,
47  const Signature *s, const SigMatchCtx *ctx);
48 void DetectMarkDataFree(void *ptr);
49 
50 /**
51  * \brief Registration function for nfq_set_mark: keyword
52  */
53 
54 void DetectMarkRegister (void)
55 {
56  sigmatch_table[DETECT_MARK].name = "nfq_set_mark";
57  sigmatch_table[DETECT_MARK].Match = DetectMarkPacket;
58  sigmatch_table[DETECT_MARK].Setup = DetectMarkSetup;
61 
62  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study);
63 }
64 
65 #ifdef NFQ
66 /**
67  * \internal
68  * \brief This function is used to parse mark options passed via mark: keyword
69  *
70  * \param rawstr Pointer to the user provided mark options
71  *
72  * \retval 0 on success
73  * \retval < 0 on failure
74  */
75 static void * DetectMarkParse (const char *rawstr)
76 {
77  int ret = 0, res = 0;
78 #define MAX_SUBSTRINGS 30
79  int ov[MAX_SUBSTRINGS];
80  const char *str_ptr = NULL;
81  char *ptr = NULL;
82  char *endptr = NULL;
83  uint32_t mark;
84  uint32_t mask;
85  DetectMarkData *data;
86 
87  ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS);
88  if (ret < 1) {
89  SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr);
90  return NULL;
91  }
92 
93  res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
94  if (res < 0) {
95  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
96  return NULL;
97  }
98 
99  ptr = (char *)str_ptr;
100 
101  if (ptr == NULL)
102  return NULL;
103 
104  errno = 0;
105  mark = strtoul(ptr, &endptr, 0);
106  if (errno == ERANGE) {
107  SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range");
108  SCFree(ptr);
109  return NULL;
110  } /* If there is no numeric value in the given string then strtoull(), makes
111  endptr equals to ptr and return 0 as result */
112  else if (endptr == ptr && mark == 0) {
113  SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "No numeric value");
114  SCFree(ptr);
115  return NULL;
116  } else if (endptr == ptr) {
117  SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "Invalid numeric value");
118  SCFree(ptr);
119  return NULL;
120  }
121 
122  res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr);
123  if (res < 0) {
124  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
125  return NULL;
126  }
127 
128  SCFree(ptr);
129  ptr = (char *)str_ptr;
130 
131  if (ptr == NULL) {
132  data = SCMalloc(sizeof(DetectMarkData));
133  if (unlikely(data == NULL)) {
134  return NULL;
135  }
136  data->mark = mark;
137  data->mask = 0xffff;
138  return data;
139  }
140 
141  errno = 0;
142  mask = strtoul(ptr, &endptr, 0);
143  if (errno == ERANGE) {
144  SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range");
145  SCFree(ptr);
146  return NULL;
147  } /* If there is no numeric value in the given string then strtoull(), makes
148  endptr equals to ptr and return 0 as result */
149  else if (endptr == ptr && mask == 0) {
150  SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "No numeric value");
151  SCFree(ptr);
152  return NULL;
153  }
154  else if (endptr == ptr) {
155  SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "Invalid numeric value");
156  SCFree(ptr);
157  return NULL;
158  }
159 
160  SCLogDebug("Rule will set mark 0x%x with mask 0x%x", mark, mask);
161  SCFree(ptr);
162 
163  data = SCMalloc(sizeof(DetectMarkData));
164  if (unlikely(data == NULL)) {
165  return NULL;
166  }
167  data->mark = mark;
168  data->mask = mask;
169  return data;
170 }
171 
172 #endif /* NFQ */
173 
174 /**
175  * \internal
176  * \brief this function is used to add the parsed mark into the current signature
177  *
178  * \param de_ctx pointer to the Detection Engine Context
179  * \param s pointer to the Current Signature
180  * \param rawstr pointer to the user provided mark options
181  *
182  * \retval 0 on Success
183  * \retval -1 on Failure
184  */
185 static int DetectMarkSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
186 {
187 #ifdef NFQ
188  DetectMarkData *data = NULL;
189  SigMatch *sm = NULL;
190 
191  data = DetectMarkParse(rawstr);
192 
193  if (data == NULL) {
194  return -1;
195  } else {
196  sm = SigMatchAlloc();
197  if (sm == NULL) {
198  DetectMarkDataFree(data);
199  return -1;
200  }
201 
202  sm->type = DETECT_MARK;
203  sm->ctx = (SigMatchCtx *)data;
204 
205  /* Append it to the list of tags */
207  return 0;
208  }
209 #else
210  return 0;
211 #endif
212 }
213 
214 void DetectMarkDataFree(void *ptr)
215 {
216  DetectMarkData *data = (DetectMarkData *)ptr;
217  SCFree(data);
218 }
219 
220 
221 static int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p,
222  const Signature *s, const SigMatchCtx *ctx)
223 {
224 #ifdef NFQ
225  const DetectMarkData *nf_data = (const DetectMarkData *)ctx;
226  if (nf_data->mask) {
227  if (!(IS_TUNNEL_PKT(p))) {
228  /* coverity[missing_lock] */
229  p->nfq_v.mark = (nf_data->mark & nf_data->mask)
230  | (p->nfq_v.mark & ~(nf_data->mask));
231  p->flags |= PKT_MARK_MODIFIED;
232  } else {
233  /* real tunnels may have multiple flows inside them, so marking
234  * might 'mark' too much. Rebuilt packets from IP fragments
235  * are fine. */
236  if (p->flags & PKT_REBUILT_FRAGMENT) {
237  Packet *tp = p->root ? p->root : p;
239  tp->nfq_v.mark = (nf_data->mark & nf_data->mask)
240  | (tp->nfq_v.mark & ~(nf_data->mask));
241  tp->flags |= PKT_MARK_MODIFIED;
243  }
244  }
245  }
246 #endif
247  return 1;
248 }
249 
250 /*
251  * ONLY TESTS BELOW THIS COMMENT
252  */
253 
254 #if defined UNITTESTS && defined NFQ
255 /**
256  * \test MarkTestParse01 is a test for a valid mark value
257  *
258  * \retval 1 on succces
259  * \retval 0 on failure
260  */
261 static int MarkTestParse01 (void)
262 {
263  DetectMarkData *data;
264 
265  data = DetectMarkParse("1/1");
266 
267  if (data == NULL) {
268  return 0;
269  }
270 
271  DetectMarkDataFree(data);
272  return 1;
273 }
274 
275 /**
276  * \test MarkTestParse02 is a test for an invalid mark value
277  *
278  * \retval 1 on succces
279  * \retval 0 on failure
280  */
281 static int MarkTestParse02 (void)
282 {
283  DetectMarkData *data;
284 
285  data = DetectMarkParse("4");
286 
287  if (data == NULL) {
288  return 1;
289  }
290 
291  DetectMarkDataFree(data);
292  return 0;
293 }
294 
295 /**
296  * \test MarkTestParse03 is a test for a valid mark value
297  *
298  * \retval 1 on succces
299  * \retval 0 on failure
300  */
301 static int MarkTestParse03 (void)
302 {
303  DetectMarkData *data;
304 
305  data = DetectMarkParse("0x10/0xff");
306 
307  if (data == NULL) {
308  return 0;
309  }
310 
311  DetectMarkDataFree(data);
312  return 1;
313 }
314 
315 /**
316  * \test MarkTestParse04 is a test for a invalid mark value
317  *
318  * \retval 1 on succces
319  * \retval 0 on failure
320  */
321 static int MarkTestParse04 (void)
322 {
323  DetectMarkData *data;
324 
325  data = DetectMarkParse("0x1g/0xff");
326 
327  if (data == NULL) {
328  return 1;
329  }
330 
331  DetectMarkDataFree(data);
332  return 0;
333 }
334 
335 
336 
337 #endif /* UNITTESTS */
338 
339 /**
340  * \brief this function registers unit tests for Mark
341  */
343 {
344 #if defined UNITTESTS && defined NFQ
345  UtRegisterTest("MarkTestParse01", MarkTestParse01);
346  UtRegisterTest("MarkTestParse02", MarkTestParse02);
347  UtRegisterTest("MarkTestParse03", MarkTestParse03);
348  UtRegisterTest("MarkTestParse04", MarkTestParse04);
349 #endif /* UNITTESTS */
350 }
void MarkRegisterTests(void)
this function registers unit tests for Mark
Definition: detect-mark.c:342
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1403
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1146
#define SCLogDebug(...)
Definition: util-debug.h:335
void DetectMarkDataFree(void *ptr)
Definition: detect-mark.c:214
#define unlikely(expr)
Definition: util-optimize.h:35
#define PARSE_REGEX
Definition: detect-mark.c:40
#define IS_TUNNEL_PKT(p)
Definition: decode.h:894
const char * name
Definition: detect.h:1160
Signature container.
Definition: detect.h:492
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:319
main detection engine ctx
Definition: detect.h:720
#define SCMutexUnlock(mut)
void(* Free)(void *)
Definition: detect.h:1151
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
#define MAX_SUBSTRINGS
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void DetectSetupParseRegexes(const char *parse_str, pcre **parse_regex, pcre_extra **parse_regex_study)
#define PKT_REBUILT_FRAGMENT
Definition: decode.h:1128
uint8_t type
Definition: detect.h:325
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:282
void DetectMarkRegister(void)
Registration function for nfq_set_mark: keyword.
Definition: detect-mark.c:54
SigMatchCtx * ctx
Definition: detect.h:327
#define SCMalloc(a)
Definition: util-mem.h:174
SCMutex tunnel_mutex
Definition: decode.h:592
#define SCFree(a)
Definition: util-mem.h:236
PoolThreadReserved res
int(* Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1129
#define SCMutexLock(mut)
uint32_t mark
Definition: source-nfq.h:45
NFQPacketVars nfq_v
Definition: decode.h:458
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:226
Per thread variable structure.
Definition: threadvars.h:57
uint32_t mask
Definition: detect-mark.h:46
#define PKT_MARK_MODIFIED
Definition: decode.h:1104
uint32_t flags
Definition: decode.h:442
void(* RegisterTests)(void)
Definition: detect.h:1152
a single match condition for a signature
Definition: detect.h:324
uint32_t mark
Definition: detect-mark.h:45
struct Packet_ * root
Definition: decode.h:582