suricata
detect-tcp-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-tcp-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(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 = "tcp.window";
63  sigmatch_table[DETECT_WINDOW].desc = "check for a specific TCP window size";
64  sigmatch_table[DETECT_WINDOW].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#window";
65  sigmatch_table[DETECT_WINDOW].Match = DetectWindowMatch;
66  sigmatch_table[DETECT_WINDOW].Setup = DetectWindowSetup;
69 
70  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study);
71 }
72 
73 /**
74  * \brief This function is used to match the window size on a packet
75  *
76  * \param t pointer to thread vars
77  * \param det_ctx pointer to the pattern matcher thread
78  * \param p pointer to the current packet
79  * \param m pointer to the sigmatch that we will cast into DetectWindowData
80  *
81  * \retval 0 no match
82  * \retval 1 match
83  */
84 static int DetectWindowMatch(DetectEngineThreadCtx *det_ctx, Packet *p,
85  const Signature *s, const SigMatchCtx *ctx)
86 {
87  const DetectWindowData *wd = (const DetectWindowData *)ctx;
88 
89  if ( !(PKT_IS_TCP(p)) || wd == NULL || PKT_IS_PSEUDOPKT(p)) {
90  return 0;
91  }
92 
93  if ( (!wd->negated && wd->size == TCP_GET_WINDOW(p)) || (wd->negated && wd->size != TCP_GET_WINDOW(p))) {
94  return 1;
95  }
96 
97  return 0;
98 }
99 
100 /**
101  * \brief This function is used to parse window options passed via window: keyword
102  *
103  * \param windowstr Pointer to the user provided window options (negation! and size)
104  *
105  * \retval wd pointer to DetectWindowData on success
106  * \retval NULL on failure
107  */
108 static DetectWindowData *DetectWindowParse(const char *windowstr)
109 {
110  DetectWindowData *wd = NULL;
111 #define MAX_SUBSTRINGS 30
112  int ret = 0, res = 0;
113  int ov[MAX_SUBSTRINGS];
114 
115  ret = pcre_exec(parse_regex, parse_regex_study, windowstr, strlen(windowstr), 0, 0, ov, MAX_SUBSTRINGS);
116  if (ret < 1 || ret > 3) {
117  SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, windowstr);
118  goto error;
119  }
120 
121  wd = SCMalloc(sizeof(DetectWindowData));
122  if (unlikely(wd == NULL))
123  goto error;
124 
125  if (ret > 1) {
126  char copy_str[128] = "";
127  res = pcre_copy_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 1,
128  copy_str, sizeof(copy_str));
129  if (res < 0) {
130  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
131  goto error;
132  }
133 
134  /* Detect if it's negated */
135  if (copy_str[0] == '!')
136  wd->negated = 1;
137  else
138  wd->negated = 0;
139 
140  if (ret > 2) {
141  res = pcre_copy_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 2,
142  copy_str, sizeof(copy_str));
143  if (res < 0) {
144  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
145  goto error;
146  }
147 
148  /* Get the window size if it's a valid value (in packets, we
149  * should alert if this doesn't happend from decode) */
150  if (-1 == ByteExtractStringUint16(&wd->size, 10, 0, copy_str)) {
151  goto error;
152  }
153  }
154  }
155 
156  return wd;
157 
158 error:
159  if (wd != NULL)
160  DetectWindowFree(wd);
161  return NULL;
162 
163 }
164 
165 /**
166  * \brief this function is used to add the parsed window sizedata into the current signature
167  *
168  * \param de_ctx pointer to the Detection Engine Context
169  * \param s pointer to the Current Signature
170  * \param windowstr pointer to the user provided window options
171  *
172  * \retval 0 on Success
173  * \retval -1 on Failure
174  */
175 static int DetectWindowSetup (DetectEngineCtx *de_ctx, Signature *s, const char *windowstr)
176 {
177  DetectWindowData *wd = NULL;
178  SigMatch *sm = NULL;
179 
180  wd = DetectWindowParse(windowstr);
181  if (wd == NULL) goto error;
182 
183  /* Okay so far so good, lets get this into a SigMatch
184  * and put it in the Signature. */
185  sm = SigMatchAlloc();
186  if (sm == NULL)
187  goto error;
188 
189  sm->type = DETECT_WINDOW;
190  sm->ctx = (SigMatchCtx *)wd;
191 
194 
195  return 0;
196 
197 error:
198  if (wd != NULL) DetectWindowFree(wd);
199  if (sm != NULL) SCFree(sm);
200  return -1;
201 
202 }
203 
204 /**
205  * \brief this function will free memory associated with DetectWindowData
206  *
207  * \param wd pointer to DetectWindowData
208  */
209 void DetectWindowFree(void *ptr)
210 {
211  DetectWindowData *wd = (DetectWindowData *)ptr;
212  SCFree(wd);
213 }
214 
215 #ifdef UNITTESTS /* UNITTESTS */
216 
217 /**
218  * \test DetectWindowTestParse01 is a test to make sure that we set the size correctly
219  * when given valid window opt
220  */
221 static int DetectWindowTestParse01 (void)
222 {
223  int result = 0;
224  DetectWindowData *wd = NULL;
225  wd = DetectWindowParse("35402");
226  if (wd != NULL &&wd->size==35402) {
227  DetectWindowFree(wd);
228  result = 1;
229  }
230 
231  return result;
232 }
233 
234 /**
235  * \test DetectWindowTestParse02 is a test for setting the window opt negated
236  */
237 static int DetectWindowTestParse02 (void)
238 {
239  int result = 0;
240  DetectWindowData *wd = NULL;
241  wd = DetectWindowParse("!35402");
242  if (wd != NULL) {
243  if (wd->negated == 1 && wd->size==35402) {
244  result = 1;
245  } else {
246  printf("expected wd->negated=1 and wd->size=35402\n");
247  }
248  DetectWindowFree(wd);
249  }
250 
251  return result;
252 }
253 
254 /**
255  * \test DetectWindowTestParse03 is a test to check for an empty value
256  */
257 static int DetectWindowTestParse03 (void)
258 {
259  int result = 0;
260  DetectWindowData *wd = NULL;
261  wd = DetectWindowParse("");
262  if (wd == NULL) {
263  result = 1;
264  } else {
265  printf("expected a NULL pointer (It was an empty string)\n");
266  }
267  DetectWindowFree(wd);
268 
269  return result;
270 }
271 
272 /**
273  * \test DetectWindowTestParse03 is a test to check for a big value
274  */
275 static int DetectWindowTestParse04 (void)
276 {
277  int result = 0;
278  DetectWindowData *wd = NULL;
279  wd = DetectWindowParse("1235402");
280  if (wd != NULL) {
281  printf("expected a NULL pointer (It was exceeding the MAX window size)\n");
282  DetectWindowFree(wd);
283  }else
284  result=1;
285 
286  return result;
287 }
288 
289 /**
290  * \test DetectWindowTestPacket01 is a test to check window with constructed packets
291  */
292 static int DetectWindowTestPacket01 (void)
293 {
294  int result = 0;
295  uint8_t *buf = (uint8_t *)"Hi all!";
296  uint16_t buflen = strlen((char *)buf);
297  Packet *p[3];
298  p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
299  p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
300  p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP);
301 
302  if (p[0] == NULL || p[1] == NULL ||p[2] == NULL)
303  goto end;
304 
305  /* TCP wwindow = 40 */
306  p[0]->tcph->th_win = htons(40);
307 
308  /* TCP window = 41 */
309  p[1]->tcph->th_win = htons(41);
310 
311  const char *sigs[2];
312  sigs[0]= "alert tcp any any -> any any (msg:\"Testing window 1\"; window:40; sid:1;)";
313  sigs[1]= "alert tcp any any -> any any (msg:\"Testing window 2\"; window:41; sid:2;)";
314 
315  uint32_t sid[2] = {1, 2};
316 
317  uint32_t results[3][2] = {
318  /* packet 0 match sid 1 but should not match sid 2 */
319  {1, 0},
320  /* packet 1 should not match */
321  {0, 1},
322  /* packet 2 should not match */
323  {0, 0} };
324  result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 2);
325 
326  UTHFreePackets(p, 3);
327 end:
328  return result;
329 }
330 
331 #endif /* UNITTESTS */
332 
333 /**
334  * \brief this function registers unit tests for DetectWindow
335  */
337 {
338  #ifdef UNITTESTS /* UNITTESTS */
339  UtRegisterTest("DetectWindowTestParse01", DetectWindowTestParse01);
340  UtRegisterTest("DetectWindowTestParse02", DetectWindowTestParse02);
341  UtRegisterTest("DetectWindowTestParse03", DetectWindowTestParse03);
342  UtRegisterTest("DetectWindowTestParse04", DetectWindowTestParse04);
343  UtRegisterTest("DetectWindowTestPacket01", DetectWindowTestPacket01);
344  #endif /* UNITTESTS */
345 }
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1447
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1187
uint32_t flags
Definition: detect.h:527
void DetectWindowRegister(void)
Registration function for window: keyword.
#define unlikely(expr)
Definition: util-optimize.h:35
#define TCP_GET_WINDOW(p)
Definition: decode-tcp.h:109
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:228
const char * name
Definition: detect.h:1201
TCPHdr * tcph
Definition: decode.h:522
Signature container.
Definition: detect.h:526
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:764
int ByteExtractStringUint16(uint16_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:264
void(* Free)(void *)
Definition: detect.h:1192
#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.
void DetectWindowFree(void *)
this function will free memory associated with DetectWindowData
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1171
uint8_t type
Definition: detect.h:323
const char * desc
Definition: detect.h:1203
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
const char * alias
Definition: detect.h:1202
#define SCMalloc(a)
Definition: util-mem.h:222
#define MAX_SUBSTRINGS
#define SCFree(a)
Definition: util-mem.h:322
PoolThreadReserved res
#define PKT_IS_TCP(p)
Definition: decode.h:253
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...
const char * url
Definition: detect.h:1204
#define DOC_URL
Definition: suricata.h:86
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1129
#define PARSE_REGEX
Regex for parsing our window option.
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:232
void DetectWindowRegisterTests(void)
this function registers unit tests for DetectWindow
#define DOC_VERSION
Definition: suricata.h:91
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:1193
a single match condition for a signature
Definition: detect.h:322