suricata
detect-window.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2010 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 Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
22  *
23  * Implements the window keyword.
24  */
25 
26 #include "suricata-common.h"
27 #include "debug.h"
28 #include "decode.h"
29 
30 #include "detect.h"
31 #include "detect-parse.h"
32 
33 #include "detect-window.h"
34 #include "flow.h"
35 #include "flow-var.h"
36 
37 #include "util-debug.h"
38 #include "util-unittest.h"
39 #include "util-unittest-helper.h"
40 #include "util-byte.h"
41 
42 /**
43  * \brief Regex for parsing our window option
44  */
45 #define PARSE_REGEX "^\\s*([!])?\\s*([0-9]{1,9}+)\\s*$"
46 
47 static pcre *parse_regex;
48 static pcre_extra *parse_regex_study;
49 
50 static int DetectWindowMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *,
51  const Signature *, const SigMatchCtx *);
52 static int DetectWindowSetup(DetectEngineCtx *, Signature *, const char *);
53 void DetectWindowRegisterTests(void);
54 void DetectWindowFree(void *);
55 
56 /**
57  * \brief Registration function for window: keyword
58  */
60 {
61  sigmatch_table[DETECT_WINDOW].name = "window";
62  sigmatch_table[DETECT_WINDOW].desc = "check for a specific TCP window size";
63  sigmatch_table[DETECT_WINDOW].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#window";
64  sigmatch_table[DETECT_WINDOW].Match = DetectWindowMatch;
65  sigmatch_table[DETECT_WINDOW].Setup = DetectWindowSetup;
68 
69  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study);
70 }
71 
72 /**
73  * \brief This function is used to match the window size on a packet
74  *
75  * \param t pointer to thread vars
76  * \param det_ctx pointer to the pattern matcher thread
77  * \param p pointer to the current packet
78  * \param m pointer to the sigmatch that we will cast into DetectWindowData
79  *
80  * \retval 0 no match
81  * \retval 1 match
82  */
83 static int DetectWindowMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p,
84  const Signature *s, const SigMatchCtx *ctx)
85 {
86  const DetectWindowData *wd = (const DetectWindowData *)ctx;
87 
88  if ( !(PKT_IS_TCP(p)) || wd == NULL || PKT_IS_PSEUDOPKT(p)) {
89  return 0;
90  }
91 
92  if ( (!wd->negated && wd->size == TCP_GET_WINDOW(p)) || (wd->negated && wd->size != TCP_GET_WINDOW(p))) {
93  return 1;
94  }
95 
96  return 0;
97 }
98 
99 /**
100  * \brief This function is used to parse window options passed via window: keyword
101  *
102  * \param windowstr Pointer to the user provided window options (negation! and size)
103  *
104  * \retval wd pointer to DetectWindowData on success
105  * \retval NULL on failure
106  */
107 static DetectWindowData *DetectWindowParse(const char *windowstr)
108 {
109  DetectWindowData *wd = NULL;
110 #define MAX_SUBSTRINGS 30
111  int ret = 0, res = 0;
112  int ov[MAX_SUBSTRINGS];
113 
114  ret = pcre_exec(parse_regex, parse_regex_study, windowstr, strlen(windowstr), 0, 0, ov, MAX_SUBSTRINGS);
115  if (ret < 1 || ret > 3) {
116  SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, windowstr);
117  goto error;
118  }
119 
120  wd = SCMalloc(sizeof(DetectWindowData));
121  if (unlikely(wd == NULL))
122  goto error;
123 
124  if (ret > 1) {
125  char copy_str[128] = "";
126  res = pcre_copy_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 1,
127  copy_str, sizeof(copy_str));
128  if (res < 0) {
129  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
130  goto error;
131  }
132 
133  /* Detect if it's negated */
134  if (copy_str[0] == '!')
135  wd->negated = 1;
136  else
137  wd->negated = 0;
138 
139  if (ret > 2) {
140  res = pcre_copy_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 2,
141  copy_str, sizeof(copy_str));
142  if (res < 0) {
143  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
144  goto error;
145  }
146 
147  /* Get the window size if it's a valid value (in packets, we
148  * should alert if this doesn't happend from decode) */
149  if (-1 == ByteExtractStringUint16(&wd->size, 10, 0, copy_str)) {
150  goto error;
151  }
152  }
153  }
154 
155  return wd;
156 
157 error:
158  if (wd != NULL)
159  DetectWindowFree(wd);
160  return NULL;
161 
162 }
163 
164 /**
165  * \brief this function is used to add the parsed window sizedata into the current signature
166  *
167  * \param de_ctx pointer to the Detection Engine Context
168  * \param s pointer to the Current Signature
169  * \param windowstr pointer to the user provided window options
170  *
171  * \retval 0 on Success
172  * \retval -1 on Failure
173  */
174 static int DetectWindowSetup (DetectEngineCtx *de_ctx, Signature *s, const char *windowstr)
175 {
176  DetectWindowData *wd = NULL;
177  SigMatch *sm = NULL;
178 
179  wd = DetectWindowParse(windowstr);
180  if (wd == NULL) goto error;
181 
182  /* Okay so far so good, lets get this into a SigMatch
183  * and put it in the Signature. */
184  sm = SigMatchAlloc();
185  if (sm == NULL)
186  goto error;
187 
188  sm->type = DETECT_WINDOW;
189  sm->ctx = (SigMatchCtx *)wd;
190 
193 
194  return 0;
195 
196 error:
197  if (wd != NULL) DetectWindowFree(wd);
198  if (sm != NULL) SCFree(sm);
199  return -1;
200 
201 }
202 
203 /**
204  * \brief this function will free memory associated with DetectWindowData
205  *
206  * \param wd pointer to DetectWindowData
207  */
208 void DetectWindowFree(void *ptr)
209 {
210  DetectWindowData *wd = (DetectWindowData *)ptr;
211  SCFree(wd);
212 }
213 
214 #ifdef UNITTESTS /* UNITTESTS */
215 
216 /**
217  * \test DetectWindowTestParse01 is a test to make sure that we set the size correctly
218  * when given valid window opt
219  */
220 static int DetectWindowTestParse01 (void)
221 {
222  int result = 0;
223  DetectWindowData *wd = NULL;
224  wd = DetectWindowParse("35402");
225  if (wd != NULL &&wd->size==35402) {
226  DetectWindowFree(wd);
227  result = 1;
228  }
229 
230  return result;
231 }
232 
233 /**
234  * \test DetectWindowTestParse02 is a test for setting the window opt negated
235  */
236 static int DetectWindowTestParse02 (void)
237 {
238  int result = 0;
239  DetectWindowData *wd = NULL;
240  wd = DetectWindowParse("!35402");
241  if (wd != NULL) {
242  if (wd->negated == 1 && wd->size==35402) {
243  result = 1;
244  } else {
245  printf("expected wd->negated=1 and wd->size=35402\n");
246  }
247  DetectWindowFree(wd);
248  }
249 
250  return result;
251 }
252 
253 /**
254  * \test DetectWindowTestParse03 is a test to check for an empty value
255  */
256 static int DetectWindowTestParse03 (void)
257 {
258  int result = 0;
259  DetectWindowData *wd = NULL;
260  wd = DetectWindowParse("");
261  if (wd == NULL) {
262  result = 1;
263  } else {
264  printf("expected a NULL pointer (It was an empty string)\n");
265  }
266  DetectWindowFree(wd);
267 
268  return result;
269 }
270 
271 /**
272  * \test DetectWindowTestParse03 is a test to check for a big value
273  */
274 static int DetectWindowTestParse04 (void)
275 {
276  int result = 0;
277  DetectWindowData *wd = NULL;
278  wd = DetectWindowParse("1235402");
279  if (wd != NULL) {
280  printf("expected a NULL pointer (It was exceeding the MAX window size)\n");
281  DetectWindowFree(wd);
282  }else
283  result=1;
284 
285  return result;
286 }
287 
288 /**
289  * \test DetectWindowTestPacket01 is a test to check window with constructed packets
290  */
291 static int DetectWindowTestPacket01 (void)
292 {
293  int result = 0;
294  uint8_t *buf = (uint8_t *)"Hi all!";
295  uint16_t buflen = strlen((char *)buf);
296  Packet *p[3];
297  p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
298  p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
299  p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP);
300 
301  if (p[0] == NULL || p[1] == NULL ||p[2] == NULL)
302  goto end;
303 
304  /* TCP wwindow = 40 */
305  p[0]->tcph->th_win = htons(40);
306 
307  /* TCP window = 41 */
308  p[1]->tcph->th_win = htons(41);
309 
310  const char *sigs[2];
311  sigs[0]= "alert tcp any any -> any any (msg:\"Testing window 1\"; window:40; sid:1;)";
312  sigs[1]= "alert tcp any any -> any any (msg:\"Testing window 2\"; window:41; sid:2;)";
313 
314  uint32_t sid[2] = {1, 2};
315 
316  uint32_t results[3][2] = {
317  /* packet 0 match sid 1 but should not match sid 2 */
318  {1, 0},
319  /* packet 1 should not match */
320  {0, 1},
321  /* packet 2 should not match */
322  {0, 0} };
323  result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 2);
324 
325  UTHFreePackets(p, 3);
326 end:
327  return result;
328 }
329 
330 #endif /* UNITTESTS */
331 
332 /**
333  * \brief this function registers unit tests for DetectWindow
334  */
336 {
337  #ifdef UNITTESTS /* UNITTESTS */
338  UtRegisterTest("DetectWindowTestParse01", DetectWindowTestParse01);
339  UtRegisterTest("DetectWindowTestParse02", DetectWindowTestParse02);
340  UtRegisterTest("DetectWindowTestParse03", DetectWindowTestParse03);
341  UtRegisterTest("DetectWindowTestParse04", DetectWindowTestParse04);
342  UtRegisterTest("DetectWindowTestPacket01", DetectWindowTestPacket01);
343  #endif /* UNITTESTS */
344 }
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1406
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1149
uint32_t flags
Definition: detect.h:496
#define unlikely(expr)
Definition: util-optimize.h:35
#define PARSE_REGEX
Regex for parsing our window option.
Definition: detect-window.c:45
#define TCP_GET_WINDOW(p)
Definition: decode-tcp.h:108
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:228
const char * name
Definition: detect.h:1163
TCPHdr * tcph
Definition: decode.h:520
Signature container.
Definition: detect.h:495
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:317
main detection engine ctx
Definition: detect.h:723
int ByteExtractStringUint16(uint16_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:264
void(* Free)(void *)
Definition: detect.h:1154
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
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)
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
uint8_t type
Definition: detect.h:323
const char * desc
Definition: detect.h:1165
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:288
SigMatchCtx * ctx
Definition: detect.h:325
#define SCMalloc(a)
Definition: util-mem.h:166
#define SCFree(a)
Definition: util-mem.h:228
PoolThreadReserved res
#define PKT_IS_TCP(p)
Definition: decode.h:251
int UTHGenericTest(Packet **pkt, int numpkts, const char *sigs[], uint32_t sids[], uint32_t *results, int numsigs)
UTHGenericTest: function that perfom a generic check taking care of as maximum common unittest elemen...
int(* Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1132
const char * url
Definition: detect.h:1166
#define MAX_SUBSTRINGS
#define DOC_URL
Definition: suricata.h:86
void DetectWindowRegisterTests(void)
this function registers unit tests for DetectWindow
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1131
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:232
Per thread variable structure.
Definition: threadvars.h:57
void DetectWindowRegister(void)
Registration function for window: keyword.
Definition: detect-window.c:59
#define DOC_VERSION
Definition: suricata.h:91
void DetectWindowFree(void *)
this function will free memory associated with DetectWindowData
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself...
void(* RegisterTests)(void)
Definition: detect.h:1155
a single match condition for a signature
Definition: detect.h:322