suricata
detect-engine-state.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2013 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  * \defgroup sigstate State support
20  *
21  * State is stored in the ::DetectEngineState structure. This is
22  * basically a containter for storage item of type ::DeStateStore.
23  * They contains an array of ::DeStateStoreItem which store the
24  * state of match for an individual signature identified by
25  * DeStateStoreItem::sid.
26  *
27  * @{
28  */
29 
30 /**
31  * \file
32  *
33  * \author Victor Julien <victor@inliniac.net>
34  * \author Anoop Saldanha <anoopsaldanha@gmail.com>
35  *
36  * \brief State based signature handling.
37  */
38 
39 #include "suricata-common.h"
40 
41 #include "decode.h"
42 
43 #include "detect.h"
44 #include "detect-engine.h"
45 #include "detect-parse.h"
46 #include "detect-engine-state.h"
48 
49 #include "detect-flowvar.h"
50 
51 #include "stream-tcp.h"
52 #include "stream-tcp-private.h"
53 #include "stream-tcp-reassemble.h"
54 
55 #include "app-layer.h"
56 #include "app-layer-parser.h"
57 #include "app-layer-protos.h"
58 #include "app-layer-htp.h"
59 #include "app-layer-smb.h"
61 #include "app-layer-dcerpc.h"
62 #include "app-layer-dns-common.h"
63 
64 #include "util-unittest.h"
65 #include "util-unittest-helper.h"
66 #include "util-profiling.h"
67 
68 #include "flow-util.h"
69 
70 /** convert enum to string */
71 #define CASE_CODE(E) case E: return #E
72 
73 static inline int StateIsValid(uint16_t alproto, void *alstate)
74 {
75  if (alstate != NULL) {
76  if (alproto == ALPROTO_HTTP) {
77  HtpState *htp_state = (HtpState *)alstate;
78  if (htp_state->conn != NULL) {
79  return 1;
80  }
81  } else {
82  return 1;
83  }
84  }
85  return 0;
86 }
87 
88 static DeStateStore *DeStateStoreAlloc(void)
89 {
90  DeStateStore *d = SCMalloc(sizeof(DeStateStore));
91  if (unlikely(d == NULL))
92  return NULL;
93  memset(d, 0, sizeof(DeStateStore));
94 
95  return d;
96 }
97 
98 #ifdef DEBUG_VALIDATION
99 static int DeStateSearchState(DetectEngineState *state, uint8_t direction, SigIntId num)
100 {
101  DetectEngineStateDirection *dir_state = &state->dir_state[direction & STREAM_TOSERVER ? 0 : 1];
102  DeStateStore *tx_store = dir_state->head;
103  SigIntId store_cnt;
104  SigIntId state_cnt = 0;
105 
106  for (; tx_store != NULL; tx_store = tx_store->next) {
107  SCLogDebug("tx_store %p", tx_store);
108  for (store_cnt = 0;
109  store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < dir_state->cnt;
110  store_cnt++, state_cnt++)
111  {
112  DeStateStoreItem *item = &tx_store->store[store_cnt];
113  if (item->sid == num) {
114  SCLogDebug("sid %u already in state: %p %p %p %u %u, direction %s",
115  num, state, dir_state, tx_store, state_cnt,
116  store_cnt, direction & STREAM_TOSERVER ? "toserver" : "toclient");
117  return 1;
118  }
119  }
120  }
121  return 0;
122 }
123 #endif
124 
125 static void DeStateSignatureAppend(DetectEngineState *state,
126  const Signature *s, uint32_t inspect_flags, uint8_t direction)
127 {
128  int jump = 0;
129  int i = 0;
130  DetectEngineStateDirection *dir_state = &state->dir_state[direction & STREAM_TOSERVER ? 0 : 1];
131 
132 #ifdef DEBUG_VALIDATION
133  BUG_ON(DeStateSearchState(state, direction, s->num));
134 #endif
135  DeStateStore *store = dir_state->head;
136 
137  if (store == NULL) {
138  store = DeStateStoreAlloc();
139  if (store != NULL) {
140  dir_state->head = store;
141  dir_state->tail = store;
142  }
143  } else {
144  jump = dir_state->cnt / DE_STATE_CHUNK_SIZE;
145  for (i = 0; i < jump; i++) {
146  store = store->next;
147  }
148  if (store == NULL) {
149  store = DeStateStoreAlloc();
150  if (store != NULL) {
151  dir_state->tail->next = store;
152  dir_state->tail = store;
153  }
154  }
155  }
156 
157  if (store == NULL)
158  return;
159 
160  SigIntId idx = dir_state->cnt++ % DE_STATE_CHUNK_SIZE;
161  store->store[idx].sid = s->num;
162  store->store[idx].flags = inspect_flags;
163 
164  return;
165 }
166 
168 {
170  if (unlikely(d == NULL))
171  return NULL;
172  memset(d, 0, sizeof(DetectEngineState));
173 
174  return d;
175 }
176 
178 {
179  DeStateStore *store;
180  DeStateStore *store_next;
181  int i = 0;
182 
183  for (i = 0; i < 2; i++) {
184  store = state->dir_state[i].head;
185  while (store != NULL) {
186  store_next = store->next;
187  SCFree(store);
188  store = store_next;
189  }
190  }
191  SCFree(state);
192 
193  return;
194 }
195 
196 static void StoreFileNoMatchCnt(DetectEngineState *de_state, uint16_t file_no_match, uint8_t direction)
197 {
198  de_state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].filestore_cnt += file_no_match;
199 
200  return;
201 }
202 
203 static bool StoreFilestoreSigsCantMatch(const SigGroupHead *sgh, const DetectEngineState *de_state, uint8_t direction)
204 {
205  if (de_state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].filestore_cnt == sgh->filestore_cnt)
206  return true;
207  else
208  return false;
209 }
210 
211 static void StoreStateTxHandleFiles(const SigGroupHead *sgh, Flow *f,
212  DetectEngineState *destate, const uint8_t flow_flags,
213  const uint64_t tx_id, const uint16_t file_no_match)
214 {
215  SCLogDebug("tx %"PRIu64", file_no_match %u", tx_id, file_no_match);
216  StoreFileNoMatchCnt(destate, file_no_match, flow_flags);
217  if (StoreFilestoreSigsCantMatch(sgh, destate, flow_flags)) {
219  }
220 }
221 
223  const SigGroupHead *sgh,
224  Flow *f, void *tx, uint64_t tx_id,
225  const Signature *s,
226  uint32_t inspect_flags, uint8_t flow_flags,
227  const uint16_t file_no_match)
228 {
230  if (destate == NULL) {
231  destate = DetectEngineStateAlloc();
232  if (destate == NULL)
233  return;
234  if (AppLayerParserSetTxDetectState(f, tx, destate) < 0) {
235  DetectEngineStateFree(destate);
236  return;
237  }
238  SCLogDebug("destate created for %"PRIu64, tx_id);
239  }
240  DeStateSignatureAppend(destate, s, inspect_flags, flow_flags);
241  StoreStateTxHandleFiles(sgh, f, destate, flow_flags, tx_id, file_no_match);
242 
243  SCLogDebug("Stored for TX %"PRIu64, tx_id);
244 }
245 
246 /** \brief update flow's inspection id's
247  *
248  * \param f unlocked flow
249  * \param flags direction and disruption flags
250  * \param tag_txs_as_inspected if true all 'complete' txs will be marked
251  * 'inspected'
252  *
253  * \note it is possible that f->alstate, f->alparser are NULL */
255  const bool tag_txs_as_inspected)
256 {
257  if (f->alparser && f->alstate) {
259  f->alstate, flags,
260  tag_txs_as_inspected);
261  }
262  return;
263 }
264 
265 /** \brief Reset de state for active tx'
266  * To be used on detect engine reload.
267  * \param f write LOCKED flow
268  */
270 {
271  void *alstate = FlowGetAppState(f);
272  if (!StateIsValid(f->alproto, alstate)) {
273  return;
274  }
275 
278 
279  uint64_t inspect_tx_id = MIN(inspect_ts, inspect_tc);
280 
281  uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate);
282 
283  for ( ; inspect_tx_id < total_txs; inspect_tx_id++) {
284  void *inspect_tx = AppLayerParserGetTx(f->proto, f->alproto, alstate, inspect_tx_id);
285  if (inspect_tx != NULL) {
286  DetectEngineState *tx_de_state = AppLayerParserGetTxDetectState(f->proto, f->alproto, inspect_tx);
287  if (tx_de_state == NULL) {
288  continue;
289  }
290 
291  tx_de_state->dir_state[0].cnt = 0;
292  tx_de_state->dir_state[0].filestore_cnt = 0;
293  tx_de_state->dir_state[0].flags = 0;
294 
295  tx_de_state->dir_state[1].cnt = 0;
296  tx_de_state->dir_state[1].filestore_cnt = 0;
297  tx_de_state->dir_state[1].flags = 0;
298  }
299  }
300 }
301 
302 /*********Unittests*********/
303 
304 #ifdef UNITTESTS
305 
306 static int DeStateTest01(void)
307 {
308  SCLogDebug("sizeof(DetectEngineState)\t\t%"PRIuMAX,
309  (uintmax_t)sizeof(DetectEngineState));
310  SCLogDebug("sizeof(DeStateStore)\t\t\t%"PRIuMAX,
311  (uintmax_t)sizeof(DeStateStore));
312  SCLogDebug("sizeof(DeStateStoreItem)\t\t%"PRIuMAX"",
313  (uintmax_t)sizeof(DeStateStoreItem));
314 
315  return 1;
316 }
317 
318 static int DeStateTest02(void)
319 {
321  FAIL_IF_NULL(state);
322 
323  Signature s;
324  memset(&s, 0x00, sizeof(s));
325 
326  uint8_t direction = STREAM_TOSERVER;
327 
328  s.num = 0;
329  DeStateSignatureAppend(state, &s, 0, direction);
330  s.num = 11;
331  DeStateSignatureAppend(state, &s, 0, direction);
332  s.num = 22;
333  DeStateSignatureAppend(state, &s, 0, direction);
334  s.num = 33;
335  DeStateSignatureAppend(state, &s, 0, direction);
336  s.num = 44;
337  DeStateSignatureAppend(state, &s, 0, direction);
338  s.num = 55;
339  DeStateSignatureAppend(state, &s, 0, direction);
340  s.num = 66;
341  DeStateSignatureAppend(state, &s, 0, direction);
342  s.num = 77;
343  DeStateSignatureAppend(state, &s, 0, direction);
344  s.num = 88;
345  DeStateSignatureAppend(state, &s, 0, direction);
346  s.num = 99;
347  DeStateSignatureAppend(state, &s, 0, direction);
348  s.num = 100;
349  DeStateSignatureAppend(state, &s, 0, direction);
350  s.num = 111;
351  DeStateSignatureAppend(state, &s, 0, direction);
352  s.num = 122;
353  DeStateSignatureAppend(state, &s, 0, direction);
354  s.num = 133;
355  DeStateSignatureAppend(state, &s, 0, direction);
356  s.num = 144;
357  DeStateSignatureAppend(state, &s, 0, direction);
358  s.num = 155;
359  DeStateSignatureAppend(state, &s, 0, direction);
360  s.num = 166;
361  DeStateSignatureAppend(state, &s, 0, direction);
362 
363  FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL);
364  FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 11);
365  FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next == NULL);
366  FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[14].sid != 144);
367  FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next->store[0].sid != 155);
368  FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next->store[1].sid != 166);
369 
370  DetectEngineStateFree(state);
371 
372  PASS;
373 }
374 
375 static int DeStateTest03(void)
376 {
378  FAIL_IF_NULL(state);
379 
380  Signature s;
381  memset(&s, 0x00, sizeof(s));
382 
383  uint8_t direction = STREAM_TOSERVER;
384 
385  s.num = 11;
386  DeStateSignatureAppend(state, &s, 0, direction);
387  s.num = 22;
388  DeStateSignatureAppend(state, &s, BIT_U32(DE_STATE_FLAG_BASE), direction);
389 
390  FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL);
391  FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].sid != 11);
392  FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].flags & BIT_U32(DE_STATE_FLAG_BASE));
393  FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 22);
394  FAIL_IF(!(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].flags & BIT_U32(DE_STATE_FLAG_BASE)));
395 
396  DetectEngineStateFree(state);
397  PASS;
398 }
399 
400 static int DeStateSigTest01(void)
401 {
402  DetectEngineThreadCtx *det_ctx = NULL;
403  ThreadVars th_v;
404  Flow f;
405  TcpSession ssn;
406  Packet *p = NULL;
407  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\n";
408  uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\n";
409  uint8_t httpbuf3[] = "Cookie: dummy\r\nContent-Length: 10\r\n\r\n";
410  uint8_t httpbuf4[] = "Http Body!";
411  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
412  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
413  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
414  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
415 
417  FAIL_IF_NULL(alp_tctx);
418 
419  memset(&th_v, 0, sizeof(th_v));
420  memset(&f, 0, sizeof(f));
421  memset(&ssn, 0, sizeof(ssn));
422 
423  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
424  FAIL_IF_NULL(p);
425 
426  FLOW_INITIALIZE(&f);
427  f.protoctx = (void *)&ssn;
428  f.proto = IPPROTO_TCP;
429  f.flags |= FLOW_IPV4;
430  f.alproto = ALPROTO_HTTP;
431 
432  p->flow = &f;
436 
438 
440  FAIL_IF_NULL(de_ctx);
441  de_ctx->flags |= DE_QUIET;
442 
443  Signature *s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy\"; http_cookie; sid:1; rev:1;)");
444  FAIL_IF_NULL(s);
445 
446  SigGroupBuild(de_ctx);
447  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
448  FAIL_IF_NULL(det_ctx);
449 
450  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
451  STREAM_TOSERVER, httpbuf1, httplen1);
452  FAIL_IF_NOT(r == 0);
453  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
454  FAIL_IF(PacketAlertCheck(p, 1));
455 
456  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
457  STREAM_TOSERVER, httpbuf2, httplen2);
458  FAIL_IF_NOT(r == 0);
459  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
460  FAIL_IF(PacketAlertCheck(p, 1));
461 
462  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
463  STREAM_TOSERVER, httpbuf3, httplen3);
464  FAIL_IF_NOT(r == 0);
465  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
467 
468  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
469  STREAM_TOSERVER, httpbuf4, httplen4);
470  FAIL_IF_NOT(r == 0);
471  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
472  FAIL_IF(PacketAlertCheck(p, 1));
473 
474  AppLayerParserThreadCtxFree(alp_tctx);
475  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
476  DetectEngineCtxFree(de_ctx);
478  FLOW_DESTROY(&f);
479  UTHFreePacket(p);
480  PASS;
481 }
482 
483 /** \test multiple pipelined http transactions */
484 static int DeStateSigTest02(void)
485 {
486  DetectEngineThreadCtx *det_ctx = NULL;
487  ThreadVars th_v;
488  Flow f;
489  TcpSession ssn;
490  Packet *p = NULL;
491  uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
492  uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
493  uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
494  uint8_t httpbuf4[] = "Http Body!";
495  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
496  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
497  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
498  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
499  uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
500  uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
501  uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nHttp Body!";
502  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
503  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
504  uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
506  FAIL_IF_NULL(alp_tctx);
507 
508  memset(&th_v, 0, sizeof(th_v));
509  memset(&f, 0, sizeof(f));
510  memset(&ssn, 0, sizeof(ssn));
511 
512  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
513 
514  FLOW_INITIALIZE(&f);
515  f.protoctx = (void *)&ssn;
516  f.proto = IPPROTO_TCP;
517  f.flags |= FLOW_IPV4;
518 
519  p->flow = &f;
523  f.alproto = ALPROTO_HTTP;
524 
526 
528  FAIL_IF_NULL(de_ctx);
529 
530  de_ctx->flags |= DE_QUIET;
531 
532  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"POST\"; http_method; content:\"/\"; http_uri; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"body\"; nocase; http_client_body; sid:1; rev:1;)");
533  FAIL_IF_NULL(s);
534  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; sid:2; rev:1;)");
535  FAIL_IF_NULL(s);
536 
537  SigGroupBuild(de_ctx);
538  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
539  FAIL_IF_NULL(det_ctx);
540 
541  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
542  STREAM_TOSERVER, httpbuf1, httplen1);
543  FAIL_IF(r != 0);
544  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
545  FAIL_IF(PacketAlertCheck(p, 1));
546 
547  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
548  STREAM_TOSERVER, httpbuf2, httplen2);
549  FAIL_IF(r != 0);
550  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
551  FAIL_IF(PacketAlertCheck(p, 1));
552 
553  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
554  STREAM_TOSERVER, httpbuf3, httplen3);
555  FAIL_IF(r != 0);
556  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
557  FAIL_IF(PacketAlertCheck(p, 1));
558 
559  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, f.alstate, 0);
560  FAIL_IF_NULL(tx);
561 
562  DetectEngineState *tx_de_state = AppLayerParserGetTxDetectState(IPPROTO_TCP, ALPROTO_HTTP, tx);
563  FAIL_IF_NULL(tx_de_state);
564  FAIL_IF(tx_de_state->dir_state[0].cnt != 1);
565  /* http_header(mpm): 5, uri: 3, method: 6, cookie: 7 */
566  uint32_t expected_flags = (BIT_U32(5) | BIT_U32(3) | BIT_U32(6) |BIT_U32(7));
567  FAIL_IF(tx_de_state->dir_state[0].head->store[0].flags != expected_flags);
568 
569  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
570  STREAM_TOSERVER, httpbuf4, httplen4);
571  FAIL_IF(r != 0);
572  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
573  FAIL_IF(!(PacketAlertCheck(p, 1)));
574 
575  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
576  STREAM_TOSERVER, httpbuf5, httplen5);
577  FAIL_IF(r != 0);
578  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
579  FAIL_IF(PacketAlertCheck(p, 1));
580 
581  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
582  STREAM_TOSERVER, httpbuf6, httplen6);
583  FAIL_IF(r != 0);
584  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
585  FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2)));
586 
587  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP,
588  STREAM_TOSERVER, httpbuf7, httplen7);
589  FAIL_IF(r != 0);
590  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
591  FAIL_IF(!(PacketAlertCheck(p, 2)));
592 
593  AppLayerParserThreadCtxFree(alp_tctx);
594  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
595  DetectEngineCtxFree(de_ctx);
597  FLOW_DESTROY(&f);
598  UTHFreePacket(p);
599  PASS;
600 }
601 
602 static int DeStateSigTest03(void)
603 {
604  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
605  "Host: www.server.lan\r\n"
606  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
607  "Content-Length: 215\r\n"
608  "\r\n"
609  "-----------------------------277531038314945\r\n"
610  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
611  "Content-Type: image/jpeg\r\n"
612  "\r\n"
613  "filecontent\r\n"
614  "-----------------------------277531038314945--";
615  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
616  ThreadVars th_v;
617  TcpSession ssn;
618  Flow *f = NULL;
619  Packet *p = NULL;
621  FAIL_IF_NULL(alp_tctx);
622 
623  memset(&th_v, 0, sizeof(th_v));
624  memset(&ssn, 0, sizeof(ssn));
625 
626  DetectEngineThreadCtx *det_ctx = NULL;
628  FAIL_IF_NULL(de_ctx);
629 
630  de_ctx->flags |= DE_QUIET;
631 
632  Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (flow:to_server; content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)");
633  FAIL_IF_NULL(s);
634 
635  SigGroupBuild(de_ctx);
636  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
637 
638  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
639  FAIL_IF_NULL(f);
640  f->protoctx = &ssn;
641  f->proto = IPPROTO_TCP;
642  f->alproto = ALPROTO_HTTP;
643 
644  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
645  FAIL_IF_NULL(p);
646 
647  p->flow = f;
651 
653 
654  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
656  httpbuf1,
657  httplen1);
658  FAIL_IF(r != 0);
659 
660  HtpState *http_state = f->alstate;
661  FAIL_IF_NULL(http_state);
662  FAIL_IF_NULL(http_state->files_ts);
663 
664  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
665  FAIL_IF(!(PacketAlertCheck(p, 1)));
666 
669  FAIL_IF_NULL(files);
670 
671  File *file = files->head;
672  FAIL_IF_NULL(file);
673 
674  FAIL_IF(!(file->flags & FILE_STORE));
675 
676  AppLayerParserThreadCtxFree(alp_tctx);
677  UTHFreeFlow(f);
678 
679  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
680  DetectEngineCtxFree(de_ctx);
682  PASS;
683 }
684 
685 static int DeStateSigTest04(void)
686 {
687  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
688  "Host: www.server.lan\r\n"
689  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
690  "Content-Length: 215\r\n"
691  "\r\n"
692  "-----------------------------277531038314945\r\n"
693  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
694  "Content-Type: image/jpeg\r\n"
695  "\r\n"
696  "filecontent\r\n"
697  "-----------------------------277531038314945--";
698  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
699  ThreadVars th_v;
700  TcpSession ssn;
702  FAIL_IF_NULL(alp_tctx);
703 
704  memset(&th_v, 0, sizeof(th_v));
705  memset(&ssn, 0, sizeof(ssn));
706 
707  DetectEngineThreadCtx *det_ctx = NULL;
709  FAIL_IF_NULL(de_ctx);
710  de_ctx->flags |= DE_QUIET;
711 
712  Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"GET\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)");
713  FAIL_IF_NULL(s);
714 
715  SigGroupBuild(de_ctx);
716  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
717  FAIL_IF_NULL(det_ctx);
718 
719  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
720  FAIL_IF_NULL(f);
721  f->protoctx = &ssn;
722  f->proto = IPPROTO_TCP;
723  f->alproto = ALPROTO_HTTP;
724 
725  Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
726  FAIL_IF_NULL(p);
727  p->flow = f;
731 
733 
734  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
736  httpbuf1, httplen1);
737  FAIL_IF(r != 0);
738  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
739  FAIL_IF(PacketAlertCheck(p, 1));
740 
741  HtpState *http_state = f->alstate;
742  FAIL_IF_NULL(http_state);
743  FAIL_IF_NULL(http_state->files_ts);
744 
747  FAIL_IF_NULL(files);
748  File *file = files->head;
749  FAIL_IF_NULL(file);
750 
751  FAIL_IF(file->flags & FILE_STORE);
752 
753  AppLayerParserThreadCtxFree(alp_tctx);
754  UTHFreeFlow(f);
755  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
756  DetectEngineCtxFree(de_ctx);
758  PASS;
759 }
760 
761 static int DeStateSigTest05(void)
762 {
763  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
764  "Host: www.server.lan\r\n"
765  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
766  "Content-Length: 215\r\n"
767  "\r\n"
768  "-----------------------------277531038314945\r\n"
769  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
770  "Content-Type: image/jpeg\r\n"
771  "\r\n"
772  "filecontent\r\n"
773  "-----------------------------277531038314945--";
774  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
775  ThreadVars th_v;
776  TcpSession ssn;
777 
779  FAIL_IF_NULL(alp_tctx);
780 
781  memset(&th_v, 0, sizeof(th_v));
782  memset(&ssn, 0, sizeof(ssn));
783 
784  DetectEngineThreadCtx *det_ctx = NULL;
786  FAIL_IF_NULL(de_ctx);
787  de_ctx->flags |= DE_QUIET;
788 
789  Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"GET\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"nomatch\"; sid:1; rev:1;)");
790  FAIL_IF_NULL(s);
791 
792  SigGroupBuild(de_ctx);
793  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
794 
795  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
796  FAIL_IF_NULL(f);
797  f->protoctx = &ssn;
798  f->proto = IPPROTO_TCP;
799  f->alproto = ALPROTO_HTTP;
800 
801  Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
802  FAIL_IF_NULL(p);
803  p->flow = f;
807 
809 
810  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
812  httpbuf1,
813  httplen1);
814  FAIL_IF_NOT(r == 0);
815  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
816  FAIL_IF(PacketAlertCheck(p, 1));
817 
818  HtpState *http_state = f->alstate;
819  FAIL_IF_NULL(http_state);
820  FAIL_IF_NULL(http_state->files_ts);
821 
824  FAIL_IF_NULL(files);
825  File *file = files->head;
826  FAIL_IF_NULL(file);
827 
828  FAIL_IF(!(file->flags & FILE_NOSTORE));
829 
830  AppLayerParserThreadCtxFree(alp_tctx);
831  UTHFreeFlow(f);
832  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
833  DetectEngineCtxFree(de_ctx);
835  PASS;
836 }
837 
838 static int DeStateSigTest06(void)
839 {
840  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
841  "Host: www.server.lan\r\n"
842  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
843  "Content-Length: 215\r\n"
844  "\r\n"
845  "-----------------------------277531038314945\r\n"
846  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
847  "Content-Type: image/jpeg\r\n"
848  "\r\n"
849  "filecontent\r\n"
850  "-----------------------------277531038314945--";
851  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
852  ThreadVars th_v;
853  TcpSession ssn;
854 
856  FAIL_IF_NULL(alp_tctx);
857 
858  memset(&th_v, 0, sizeof(th_v));
859  memset(&ssn, 0, sizeof(ssn));
860 
861  DetectEngineThreadCtx *det_ctx = NULL;
863  FAIL_IF_NULL(de_ctx);
864  de_ctx->flags |= DE_QUIET;
865 
866  Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"nomatch\"; filestore; sid:1; rev:1;)");
867  FAIL_IF_NULL(s);
868 
869  SigGroupBuild(de_ctx);
870  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
871  FAIL_IF_NULL(det_ctx);
872 
873  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
874  FAIL_IF_NULL(f);
875  f->protoctx = &ssn;
876  f->proto = IPPROTO_TCP;
877  f->alproto = ALPROTO_HTTP;
878 
879  Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
880  FAIL_IF_NULL(p);
881  p->flow = f;
885 
887 
888  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
890  httpbuf1,
891  httplen1);
892  FAIL_IF(r != 0);
893  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
894  FAIL_IF(PacketAlertCheck(p, 1));
895 
896  HtpState *http_state = f->alstate;
897  FAIL_IF_NULL(http_state);
898  FAIL_IF_NULL(http_state->files_ts);
899 
902  FAIL_IF_NULL(files);
903  File *file = files->head;
904  FAIL_IF_NULL(file);
905  FAIL_IF(!(file->flags & FILE_NOSTORE));
906 
907  AppLayerParserThreadCtxFree(alp_tctx);
908  UTHFreeFlow(f);
909  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
910  DetectEngineCtxFree(de_ctx);
912  PASS;
913 }
914 
915 static int DeStateSigTest07(void)
916 {
917  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
918  "Host: www.server.lan\r\n"
919  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
920  "Content-Length: 215\r\n"
921  "\r\n"
922  "-----------------------------277531038314945\r\n"
923  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
924  "Content-Type: image/jpeg\r\n"
925  "\r\n";
926 
927  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
928  uint8_t httpbuf2[] = "filecontent\r\n"
929  "-----------------------------277531038314945--";
930  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
931  ThreadVars th_v;
932  TcpSession ssn;
933 
935  FAIL_IF_NULL(alp_tctx);
936 
937  memset(&th_v, 0, sizeof(th_v));
938  memset(&ssn, 0, sizeof(ssn));
939 
940  DetectEngineThreadCtx *det_ctx = NULL;
942  FAIL_IF_NULL(de_ctx);
943  de_ctx->flags |= DE_QUIET;
944 
945  Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"GET\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)");
946  FAIL_IF_NULL(s);
947 
948  SigGroupBuild(de_ctx);
949  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
950 
951  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
952  FAIL_IF_NULL(f);
953  f->protoctx = &ssn;
954  f->proto = IPPROTO_TCP;
955  f->alproto = ALPROTO_HTTP;
956 
957  Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
958  FAIL_IF_NULL(p);
959  p->flow = f;
963 
965 
966  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
967  STREAM_TOSERVER | STREAM_START, httpbuf1,
968  httplen1);
969  FAIL_IF(r != 0);
970  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
971  FAIL_IF(PacketAlertCheck(p, 1));
972 
973  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
974  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
975  FAIL_IF(r != 0);
976  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
977  FAIL_IF(PacketAlertCheck(p, 1));
978 
979  HtpState *http_state = f->alstate;
980  FAIL_IF_NULL(http_state);
981  FAIL_IF_NULL(http_state->files_ts);
982 
985  FAIL_IF_NULL(files);
986  File *file = files->head;
987  FAIL_IF_NULL(file);
988  FAIL_IF(file->flags & FILE_STORE);
989 
990  AppLayerParserThreadCtxFree(alp_tctx);
991  UTHFreeFlow(f);
992  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
993  DetectEngineCtxFree(de_ctx);
995  PASS;
996 }
997 
998 /**
999  * \test multiple files in a tx
1000  */
1001 static int DeStateSigTest08(void)
1002 {
1003  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1004  "Host: www.server.lan\r\n"
1005  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1006  "Content-Length: 440\r\n"
1007  "\r\n"
1008  "-----------------------------277531038314945\r\n"
1009  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"AAAApicture1.jpg\"\r\n"
1010  "Content-Type: image/jpeg\r\n"
1011  "\r\n";
1012 
1013  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1014  uint8_t httpbuf2[] = "file";
1015  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1016  uint8_t httpbuf3[] = "content\r\n"
1017  "-----------------------------277531038314945\r\n";
1018  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1019 
1020  uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"BBBBpicture2.jpg\"\r\n"
1021  "Content-Type: image/jpeg\r\n"
1022  "\r\n"
1023  "filecontent2\r\n"
1024  "-----------------------------277531038314945--";
1025  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1026 
1027  ThreadVars th_v;
1028  TcpSession ssn;
1029 
1031  FAIL_IF_NULL(alp_tctx);
1032 
1033  memset(&th_v, 0, sizeof(th_v));
1034  memset(&ssn, 0, sizeof(ssn));
1035 
1036  DetectEngineThreadCtx *det_ctx = NULL;
1038  FAIL_IF_NULL(de_ctx);
1039  de_ctx->flags |= DE_QUIET;
1040 
1041  Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"BBBBpicture\"; filestore; sid:1; rev:1;)");
1042  FAIL_IF_NULL(s);
1043 
1044  SigGroupBuild(de_ctx);
1045  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1046 
1047  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1048  FAIL_IF_NULL(f);
1049  f->protoctx = &ssn;
1050  f->proto = IPPROTO_TCP;
1051  f->alproto = ALPROTO_HTTP;
1052 
1053  Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1054  FAIL_IF_NULL(p);
1055  p->flow = f;
1059 
1061 
1062  /* HTTP request with 1st part of the multipart body */
1063 
1064  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1065  STREAM_TOSERVER | STREAM_START, httpbuf1,
1066  httplen1);
1067  FAIL_IF(r != 0);
1068  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1069  FAIL_IF(PacketAlertCheck(p, 1));
1070 
1071  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1072  STREAM_TOSERVER, httpbuf2, httplen2);
1073  FAIL_IF(r != 0);
1074  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1075  FAIL_IF(PacketAlertCheck(p, 1));
1076 
1077  HtpState *http_state = f->alstate;
1078  FAIL_IF_NULL(http_state);
1079  FAIL_IF_NULL(http_state->files_ts);
1080 
1083  FAIL_IF_NULL(files);
1084  File *file = files->head;
1085  FAIL_IF_NULL(file);
1086  FAIL_IF(file->flags & FILE_STORE);
1087 
1088  /* 2nd multipart body file */
1089 
1090  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1091  STREAM_TOSERVER, httpbuf3, httplen3);
1092  FAIL_IF(r != 0);
1093  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1094  FAIL_IF(PacketAlertCheck(p, 1));
1095 
1096  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1097  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1098  FAIL_IF(r != 0);
1099  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1101 
1102  http_state = f->alstate;
1103  FAIL_IF_NULL(http_state);
1104  FAIL_IF_NULL(http_state->files_ts);
1105 
1106  files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto,
1108  FAIL_IF_NULL(files);
1109  file = files->head;
1110  FAIL_IF_NULL(file);
1111  FAIL_IF_NOT(file->flags & FILE_STORE);
1112 
1113  AppLayerParserThreadCtxFree(alp_tctx);
1114  UTHFreeFlow(f);
1115  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1116  DetectEngineCtxFree(de_ctx);
1118  PASS;
1119 }
1120 
1121 /**
1122  * \test multiple files in a tx. Both files should match
1123  */
1124 static int DeStateSigTest09(void)
1125 {
1126  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1127  "Host: www.server.lan\r\n"
1128  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1129  "Content-Length: 440\r\n"
1130  "\r\n"
1131  "-----------------------------277531038314945\r\n"
1132  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1133  "Content-Type: image/jpeg\r\n"
1134  "\r\n";
1135 
1136  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1137  uint8_t httpbuf2[] = "file";
1138  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1139  uint8_t httpbuf3[] = "content\r\n"
1140  "-----------------------------277531038314945\r\n";
1141  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1142 
1143  uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
1144  "Content-Type: image/jpeg\r\n"
1145  "\r\n"
1146  "filecontent2\r\n"
1147  "-----------------------------277531038314945--";
1148  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1149 
1150  ThreadVars th_v;
1151  TcpSession ssn;
1152 
1154  FAIL_IF_NULL(alp_tctx);
1155 
1156  memset(&th_v, 0, sizeof(th_v));
1157  memset(&ssn, 0, sizeof(ssn));
1158 
1159  DetectEngineThreadCtx *det_ctx = NULL;
1161  FAIL_IF_NULL(de_ctx);
1162  de_ctx->flags |= DE_QUIET;
1163 
1164  Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"somepicture\"; filestore; sid:1; rev:1;)");
1165  FAIL_IF_NULL(s);
1166 
1167  SigGroupBuild(de_ctx);
1168  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1169 
1170  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1171  FAIL_IF_NULL(f);
1172  f->protoctx = &ssn;
1173  f->proto = IPPROTO_TCP;
1174  f->alproto = ALPROTO_HTTP;
1175 
1176  Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1177  FAIL_IF_NULL(p);
1178  p->flow = f;
1182 
1184 
1185  /* HTTP request with 1st part of the multipart body */
1186 
1187  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1188  STREAM_TOSERVER | STREAM_START, httpbuf1,
1189  httplen1);
1190  FAIL_IF(r != 0);
1191  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1193 
1194  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1195  STREAM_TOSERVER, httpbuf2, httplen2);
1196  FAIL_IF(r != 0);
1197  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1198  FAIL_IF(PacketAlertCheck(p, 1));
1199 
1200  HtpState *http_state = f->alstate;
1201  FAIL_IF_NULL(http_state);
1202  FAIL_IF_NULL(http_state->files_ts);
1203 
1206  FAIL_IF_NULL(files);
1207  File *file = files->head;
1208  FAIL_IF_NULL(file);
1209  FAIL_IF_NOT(file->flags & FILE_STORE);
1210 
1211  /* 2nd multipart body file */
1212 
1213  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1214  STREAM_TOSERVER, httpbuf3, httplen3);
1215  FAIL_IF(r != 0);
1216  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1217  FAIL_IF(PacketAlertCheck(p, 1));
1218 
1219  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1220  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1221  FAIL_IF(r != 0);
1222  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1224 
1225  http_state = f->alstate;
1226  FAIL_IF_NULL(http_state);
1227  FAIL_IF_NULL(http_state->files_ts);
1228 
1229  files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto,
1231  FAIL_IF_NULL(files);
1232  file = files->head;
1233  FAIL_IF_NULL(file);
1234  FAIL_IF_NOT(file->flags & FILE_STORE);
1235 
1236  AppLayerParserThreadCtxFree(alp_tctx);
1237  UTHFreeFlow(f);
1238  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1239  DetectEngineCtxFree(de_ctx);
1241  PASS;
1242 }
1243 
1244 /**
1245  * \test multiple files in a tx. Both files should match. No other matches.
1246  */
1247 static int DeStateSigTest10(void)
1248 {
1249  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1250  "Host: www.server.lan\r\n"
1251  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1252  "Content-Length: 440\r\n"
1253  "\r\n"
1254  "-----------------------------277531038314945\r\n"
1255  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1256  "Content-Type: image/jpeg\r\n"
1257  "\r\n";
1258 
1259  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1260  uint8_t httpbuf2[] = "file";
1261  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1262  uint8_t httpbuf3[] = "content\r\n"
1263  "-----------------------------277531038314945\r\n";
1264  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1265 
1266  uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
1267  "Content-Type: image/jpeg\r\n"
1268  "\r\n"
1269  "filecontent2\r\n"
1270  "-----------------------------277531038314945--";
1271  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1272 
1273  ThreadVars th_v;
1274  TcpSession ssn;
1275 
1277  FAIL_IF_NULL(alp_tctx);
1278 
1279  memset(&th_v, 0, sizeof(th_v));
1280  memset(&ssn, 0, sizeof(ssn));
1281 
1282  DetectEngineThreadCtx *det_ctx = NULL;
1284  FAIL_IF_NULL(de_ctx);
1285  de_ctx->flags |= DE_QUIET;
1286 
1287  Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (filename:\"somepicture\"; filestore; sid:1; rev:1;)");
1288  FAIL_IF_NULL(s);
1289 
1290  SigGroupBuild(de_ctx);
1291  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1292 
1293  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1294  FAIL_IF_NULL(f);
1295  f->protoctx = &ssn;
1296  f->proto = IPPROTO_TCP;
1297  f->alproto = ALPROTO_HTTP;
1298 
1299  Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1300  FAIL_IF_NULL(p);
1301  p->flow = f;
1305 
1307 
1308  /* HTTP request with 1st part of the multipart body */
1309 
1310  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1311  STREAM_TOSERVER | STREAM_START, httpbuf1,
1312  httplen1);
1313  FAIL_IF(r != 0);
1314  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1316 
1317  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1318  STREAM_TOSERVER, httpbuf2, httplen2);
1319  FAIL_IF(r != 0);
1320  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1321  FAIL_IF(PacketAlertCheck(p, 1));
1322 
1323  HtpState *http_state = f->alstate;
1324  FAIL_IF_NULL(http_state);
1325  FAIL_IF_NULL(http_state->files_ts);
1326 
1329  FAIL_IF_NULL(files);
1330  File *file = files->head;
1331  FAIL_IF_NULL(file);
1332  FAIL_IF_NOT(file->flags & FILE_STORE);
1333 
1334  /* 2nd multipart body file */
1335 
1336  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1337  STREAM_TOSERVER, httpbuf3, httplen3);
1338  FAIL_IF(r != 0);
1339  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1340  FAIL_IF(PacketAlertCheck(p, 1));
1341 
1342  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1343  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1344  FAIL_IF(r != 0);
1345  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1347 
1348  http_state = f->alstate;
1349  FAIL_IF_NULL(http_state);
1350  FAIL_IF_NULL(http_state->files_ts);
1351 
1352  files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto,
1354  FAIL_IF_NULL(files);
1355  file = files->head;
1356  FAIL_IF_NULL(file);
1357  FAIL_IF_NOT(file->flags & FILE_STORE);
1358 
1359  AppLayerParserThreadCtxFree(alp_tctx);
1360  UTHFreeFlow(f);
1361  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1362  DetectEngineCtxFree(de_ctx);
1364  PASS;
1365 }
1366 
1367 #endif
1368 
1370 {
1371 #ifdef UNITTESTS
1372  UtRegisterTest("DeStateTest01", DeStateTest01);
1373  UtRegisterTest("DeStateTest02", DeStateTest02);
1374  UtRegisterTest("DeStateTest03", DeStateTest03);
1375  UtRegisterTest("DeStateSigTest01", DeStateSigTest01);
1376  UtRegisterTest("DeStateSigTest02", DeStateSigTest02);
1377  UtRegisterTest("DeStateSigTest03", DeStateSigTest03);
1378  UtRegisterTest("DeStateSigTest04", DeStateSigTest04);
1379  UtRegisterTest("DeStateSigTest05", DeStateSigTest05);
1380  UtRegisterTest("DeStateSigTest06", DeStateSigTest06);
1381  UtRegisterTest("DeStateSigTest07", DeStateSigTest07);
1382  UtRegisterTest("DeStateSigTest08", DeStateSigTest08);
1383  UtRegisterTest("DeStateSigTest09", DeStateSigTest09);
1384  UtRegisterTest("DeStateSigTest10", DeStateSigTest10);
1385 #endif
1386 
1387  return;
1388 }
1389 
1390 /**
1391  * @}
1392  */
Signature * DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
uint16_t filestore_cnt
Definition: detect.h:1311
void AppLayerParserSetTransactionInspectId(const Flow *f, AppLayerParserState *pstate, void *alstate, const uint8_t flags, bool tag_txs_as_inspected)
uint16_t flags
void FileDisableStoringForTransaction(Flow *f, uint8_t direction, uint64_t tx_id)
disable file storing for files in a transaction
Definition: util-file.c:1211
#define SCLogDebug(...)
Definition: util-debug.h:335
struct Flow_ * flow
Definition: decode.h:444
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
#define BUG_ON(x)
uint8_t proto
Definition: flow.h:346
#define PASS
Pass the test.
#define unlikely(expr)
Definition: util-optimize.h:35
Signature * SigInit(DetectEngineCtx *, const char *)
Parses a signature and adds it to the Detection Engine Context.
uint64_t AppLayerParserGetTxCnt(const Flow *f, void *alstate)
DetectEngineStateDirection dir_state[2]
Signature * sig_list
Definition: detect.h:726
#define MIN(x, y)
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:195
Container for matching data for a signature group.
Definition: detect.h:1295
void StreamTcpFreeConfig(char quiet)
Definition: stream-tcp.c:669
#define FILE_STORE
Definition: util-file.h:46
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
Signature container.
Definition: detect.h:492
#define TRUE
void DetectRunStoreStateTx(const SigGroupHead *sgh, Flow *f, void *tx, uint64_t tx_id, const Signature *s, uint32_t inspect_flags, uint8_t flow_flags, const uint16_t file_no_match)
void * protoctx
Definition: flow.h:398
struct DeStateStore_ * next
SigIntId num
Definition: detect.h:502
uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint8_t direction)
main detection engine ctx
Definition: detect.h:720
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
void * alstate
Definition: flow.h:436
#define DE_QUIET
Definition: detect.h:298
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
uint16_t flags
Definition: util-file.h:65
uint8_t flags
Definition: detect.h:721
Data structures and function prototypes for keeping state for the detection engine.
#define FLOW_DESTROY(f)
Definition: flow-util.h:115
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
#define STREAM_EOF
Definition: stream.h:30
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void DeStateUpdateInspectTransactionId(Flow *f, const uint8_t flags, const bool tag_txs_as_inspected)
update flow&#39;s inspection id&#39;s
void SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1752
void StreamTcpInitConfig(char)
To initialize the stream global configuration data.
Definition: stream-tcp.c:365
uint8_t flowflags
Definition: decode.h:438
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.
File * head
Definition: util-file.h:95
#define STREAM_TOCLIENT
Definition: stream.h:32
#define FLOW_PKT_TOSERVER
Definition: flow.h:193
htp_conn_t * conn
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol&#39;s parser thread context.
void DetectEngineStateFree(DetectEngineState *state)
Frees a DetectEngineState object.
DetectEngineState * DetectEngineStateAlloc(void)
Alloc a DetectEngineState object.
#define DE_STATE_FLAG_BASE
void DetectEngineStateResetTxs(Flow *f)
Reset de state for active tx&#39; To be used on detect engine reload.
DeStateStoreItem store[DE_STATE_CHUNK_SIZE]
#define SCMalloc(a)
Definition: util-mem.h:174
FileContainer * files_ts
#define SCFree(a)
Definition: util-mem.h:236
uint16_t tx_id
#define STREAM_START
Definition: stream.h:29
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
#define STREAM_TOSERVER
Definition: stream.h:31
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself...
void * FlowGetAppState(const Flow *f)
Definition: flow.c:997
#define PKT_HAS_FLOW
Definition: decode.h:1101
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
#define BIT_U32(n)
void DeStateRegisterTests(void)
Per thread variable structure.
Definition: threadvars.h:57
AppProto alproto
application level protocol
Definition: flow.h:407
uint32_t flags
Definition: decode.h:442
FileContainer * AppLayerParserGetFiles(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t direction)
DetectEngineState * AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx)
#define FILE_NOSTORE
Definition: util-file.h:45
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Flow data structure.
Definition: flow.h:327
#define FLOW_IPV4
Definition: flow.h:93
#define SigIntId
uint32_t flags
Definition: flow.h:377
int AppLayerParserSetTxDetectState(const Flow *f, void *tx, DetectEngineState *s)
#define PKT_STREAM_EST
Definition: decode.h:1099
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
AppLayerParserState * alparser
Definition: flow.h:435
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, uint8_t *input, uint32_t input_len)
void UTHFreeFlow(Flow *flow)
#define DE_STATE_CHUNK_SIZE
DetectEngineCtx * DetectEngineCtxInit(void)