suricata
detect-engine-state.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2021 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 container 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#include "detect-engine-build.h"
49
50#include "detect-flowvar.h"
51
52#include "stream-tcp.h"
53#include "stream-tcp-private.h"
55
56#include "app-layer.h"
57#include "app-layer-parser.h"
58#include "app-layer-protos.h"
59#include "app-layer-htp.h"
60
61#include "util-unittest.h"
63#include "util-profiling.h"
64
65#include "flow-util.h"
66
67static inline int StateIsValid(uint16_t alproto, void *alstate)
68{
69 if (alstate != NULL) {
70 if (alproto == ALPROTO_HTTP1) {
71 HtpState *htp_state = (HtpState *)alstate;
72 if (htp_state->conn != NULL) {
73 return 1;
74 }
75 } else {
76 return 1;
77 }
78 }
79 return 0;
80}
81
82static DeStateStore *DeStateStoreAlloc(void)
83{
84 DeStateStore *d = SCCalloc(1, sizeof(DeStateStore));
85 if (unlikely(d == NULL))
86 return NULL;
87
88 return d;
89}
90
91#ifdef DEBUG_VALIDATION
92static int DeStateSearchState(DetectEngineState *state, uint8_t direction, SigIntId num)
93{
94 DetectEngineStateDirection *dir_state = &state->dir_state[direction & STREAM_TOSERVER ? 0 : 1];
95 DeStateStore *tx_store = dir_state->head;
96 SigIntId store_cnt;
97 SigIntId state_cnt = 0;
98
99 for (; tx_store != NULL; tx_store = tx_store->next) {
100 SCLogDebug("tx_store %p", tx_store);
101 for (store_cnt = 0;
102 store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < dir_state->cnt;
103 store_cnt++, state_cnt++)
104 {
105 DeStateStoreItem *item = &tx_store->store[store_cnt];
106 if (item->sid == num) {
107 SCLogDebug("sid %u already in state: %p %p %p %u %u, direction %s",
108 num, state, dir_state, tx_store, state_cnt,
109 store_cnt, direction & STREAM_TOSERVER ? "toserver" : "toclient");
110 return 1;
111 }
112 }
113 }
114 return 0;
115}
116#endif
117
118static void DeStateSignatureAppend(DetectEngineState *state,
119 const Signature *s, uint32_t inspect_flags, uint8_t direction)
120{
121 SCEnter();
122
123 DetectEngineStateDirection *dir_state =
124 &state->dir_state[(direction & STREAM_TOSERVER) ? 0 : 1];
125
126#ifdef DEBUG_VALIDATION
127 BUG_ON(DeStateSearchState(state, direction, s->iid));
128#endif
129 DeStateStore *store = dir_state->tail;
130 if (store == NULL) {
131 store = DeStateStoreAlloc();
132 dir_state->head = store;
133 dir_state->cur = store;
134 dir_state->tail = store;
135 } else if (dir_state->cur) {
136 store = dir_state->cur;
137 } else {
138 store = DeStateStoreAlloc();
139 if (store != NULL) {
140 dir_state->tail->next = store;
141 dir_state->tail = store;
142 dir_state->cur = store;
143 }
144 }
145 if (store == NULL)
146 SCReturn;
147
148 SigIntId idx = dir_state->cnt % DE_STATE_CHUNK_SIZE;
149 store->store[idx].sid = s->iid;
150 store->store[idx].flags = inspect_flags;
151 dir_state->cnt++;
152 /* if current chunk is full, progress cur */
153 if (dir_state->cnt % DE_STATE_CHUNK_SIZE == 0) {
154 dir_state->cur = dir_state->cur->next;
155 }
156
157 SCReturn;
158}
159
161{
163 if (unlikely(d == NULL))
164 return NULL;
165
166 return d;
167}
168
170{
171 DeStateStore *store;
172 DeStateStore *store_next;
173 int i = 0;
174
175 for (i = 0; i < 2; i++) {
176 store = state->dir_state[i].head;
177 while (store != NULL) {
178 store_next = store->next;
179 SCFree(store);
180 store = store_next;
181 }
182 }
183 SCFree(state);
184}
185
186static void StoreFileNoMatchCnt(DetectEngineState *de_state, uint16_t file_no_match, uint8_t direction)
187{
188 de_state->dir_state[(direction & STREAM_TOSERVER) ? 0 : 1].filestore_cnt += file_no_match;
189}
190
191static bool StoreFilestoreSigsCantMatch(const SigGroupHead *sgh, const DetectEngineState *de_state, uint8_t direction)
192{
193 if (de_state->dir_state[(direction & STREAM_TOSERVER) ? 0 : 1].filestore_cnt ==
194 sgh->filestore_cnt)
195 return true;
196 else
197 return false;
198}
199
200static void StoreStateTxHandleFiles(const SigGroupHead *sgh, Flow *f, DetectEngineState *destate,
201 const uint8_t flow_flags, void *tx, const uint64_t tx_id, const uint16_t file_no_match)
202{
203 SCLogDebug("tx %"PRIu64", file_no_match %u", tx_id, file_no_match);
204 StoreFileNoMatchCnt(destate, file_no_match, flow_flags);
205 if (StoreFilestoreSigsCantMatch(sgh, destate, flow_flags)) {
206 SCLogDebug("filestore sigs can't match");
208 f, flow_flags & (STREAM_TOCLIENT | STREAM_TOSERVER), tx, tx_id);
209 } else {
210 SCLogDebug("filestore sigs can still match");
211 }
212}
213
215 const SigGroupHead *sgh,
216 Flow *f, void *tx, uint64_t tx_id,
217 const Signature *s,
218 uint32_t inspect_flags, uint8_t flow_flags,
219 const uint16_t file_no_match)
220{
222 if (tx_data->de_state == NULL) {
223 tx_data->de_state = DetectEngineStateAlloc();
224 if (tx_data->de_state == NULL)
225 return;
226 SCLogDebug("destate created for %"PRIu64, tx_id);
227 }
228 DeStateSignatureAppend(tx_data->de_state, s, inspect_flags, flow_flags);
229 if (s->flags & SIG_FLAG_TXBOTHDIR) {
230 // add also in the other DetectEngineStateDirection
231 DeStateSignatureAppend(tx_data->de_state, s, inspect_flags,
232 flow_flags ^ (STREAM_TOSERVER | STREAM_TOCLIENT));
233 }
234 StoreStateTxHandleFiles(sgh, f, tx_data->de_state, flow_flags, tx, tx_id, file_no_match);
235
236 SCLogDebug("Stored for TX %"PRIu64, tx_id);
237}
238
239static inline void ResetTxState(DetectEngineState *s)
240{
241 if (s) {
242 s->dir_state[0].cnt = 0;
243 s->dir_state[0].filestore_cnt = 0;
244 s->dir_state[0].flags = 0;
245 /* reset 'cur' back to the list head */
246 s->dir_state[0].cur = s->dir_state[0].head;
247
248 s->dir_state[1].cnt = 0;
249 s->dir_state[1].filestore_cnt = 0;
250 s->dir_state[1].flags = 0;
251 /* reset 'cur' back to the list head */
252 s->dir_state[1].cur = s->dir_state[1].head;
253 }
254}
255
256/** \brief Reset de state for active tx'
257 * To be used on detect engine reload.
258 * \param f write LOCKED flow
259 */
261{
262 void *alstate = FlowGetAppState(f);
263 if (!StateIsValid(f->alproto, alstate)) {
264 return;
265 }
266
267 uint64_t inspect_ts = AppLayerParserGetTransactionInspectId(f->alparser, STREAM_TOCLIENT);
268 uint64_t inspect_tc = AppLayerParserGetTransactionInspectId(f->alparser, STREAM_TOSERVER);
269
270 uint64_t inspect_tx_id = MIN(inspect_ts, inspect_tc);
271
272 uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate);
273
274 for ( ; inspect_tx_id < total_txs; inspect_tx_id++) {
275 void *inspect_tx = AppLayerParserGetTx(f->proto, f->alproto, alstate, inspect_tx_id);
276 if (inspect_tx != NULL) {
277 AppLayerTxData *txd = AppLayerParserGetTxData(f->proto, f->alproto, inspect_tx);
278 ResetTxState(txd->de_state);
279 }
280 }
281}
282
283/*********Unittests*********/
284
285#ifdef UNITTESTS
286#include "detect-engine-alert.h"
287
288static int DeStateTest01(void)
289{
290 SCLogDebug("sizeof(DetectEngineState)\t\t%"PRIuMAX,
291 (uintmax_t)sizeof(DetectEngineState));
292 SCLogDebug("sizeof(DeStateStore)\t\t\t%"PRIuMAX,
293 (uintmax_t)sizeof(DeStateStore));
294 SCLogDebug("sizeof(DeStateStoreItem)\t\t%"PRIuMAX"",
295 (uintmax_t)sizeof(DeStateStoreItem));
296
297 return 1;
298}
299
300static int DeStateTest02(void)
301{
302 uint8_t direction = STREAM_TOSERVER;
304 FAIL_IF_NULL(state);
305 FAIL_IF_NOT_NULL(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head);
306
307 Signature s;
308 memset(&s, 0x00, sizeof(s));
309
310 s.iid = 0;
311 DeStateSignatureAppend(state, &s, 0, direction);
312 s.iid = 11;
313 DeStateSignatureAppend(state, &s, 0, direction);
314 s.iid = 22;
315 DeStateSignatureAppend(state, &s, 0, direction);
316 s.iid = 33;
317 DeStateSignatureAppend(state, &s, 0, direction);
318 s.iid = 44;
319 DeStateSignatureAppend(state, &s, 0, direction);
320 s.iid = 55;
321 DeStateSignatureAppend(state, &s, 0, direction);
322 s.iid = 66;
323 DeStateSignatureAppend(state, &s, 0, direction);
324 s.iid = 77;
325 DeStateSignatureAppend(state, &s, 0, direction);
326 s.iid = 88;
327 DeStateSignatureAppend(state, &s, 0, direction);
328 s.iid = 99;
329 DeStateSignatureAppend(state, &s, 0, direction);
330 s.iid = 100;
331 DeStateSignatureAppend(state, &s, 0, direction);
332 s.iid = 111;
333 DeStateSignatureAppend(state, &s, 0, direction);
334 s.iid = 122;
335 DeStateSignatureAppend(state, &s, 0, direction);
336 s.iid = 133;
337 DeStateSignatureAppend(state, &s, 0, direction);
338 FAIL_IF_NOT(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head ==
339 state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
340
341 s.iid = 144;
342 DeStateSignatureAppend(state, &s, 0, direction);
343
344 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[14].sid != 144);
345 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head ==
346 state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
347 FAIL_IF_NOT(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur == NULL);
348
349 s.iid = 155;
350 DeStateSignatureAppend(state, &s, 0, direction);
351
352 FAIL_IF_NOT(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].tail ==
353 state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
354
355 s.iid = 166;
356 DeStateSignatureAppend(state, &s, 0, direction);
357
358 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL);
359 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 11);
360 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next == NULL);
361 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[14].sid != 144);
362 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next->store[0].sid != 155);
363 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next->store[1].sid != 166);
364
365 ResetTxState(state);
366
367 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL);
368 FAIL_IF_NOT(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head ==
369 state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
370
371 s.iid = 0;
372 DeStateSignatureAppend(state, &s, 0, direction);
373 s.iid = 11;
374 DeStateSignatureAppend(state, &s, 0, direction);
375 s.iid = 22;
376 DeStateSignatureAppend(state, &s, 0, direction);
377 s.iid = 33;
378 DeStateSignatureAppend(state, &s, 0, direction);
379 s.iid = 44;
380 DeStateSignatureAppend(state, &s, 0, direction);
381 s.iid = 55;
382 DeStateSignatureAppend(state, &s, 0, direction);
383 s.iid = 66;
384 DeStateSignatureAppend(state, &s, 0, direction);
385 s.iid = 77;
386 DeStateSignatureAppend(state, &s, 0, direction);
387 s.iid = 88;
388 DeStateSignatureAppend(state, &s, 0, direction);
389 s.iid = 99;
390 DeStateSignatureAppend(state, &s, 0, direction);
391 s.iid = 100;
392 DeStateSignatureAppend(state, &s, 0, direction);
393 s.iid = 111;
394 DeStateSignatureAppend(state, &s, 0, direction);
395 s.iid = 122;
396 DeStateSignatureAppend(state, &s, 0, direction);
397 s.iid = 133;
398 DeStateSignatureAppend(state, &s, 0, direction);
399 FAIL_IF_NOT(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head ==
400 state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
401 s.iid = 144;
402 DeStateSignatureAppend(state, &s, 0, direction);
403 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[14].sid != 144);
404 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head ==
405 state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
406 FAIL_IF_NOT(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].tail ==
407 state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
408 s.iid = 155;
409 DeStateSignatureAppend(state, &s, 0, direction);
410 s.iid = 166;
411 DeStateSignatureAppend(state, &s, 0, direction);
412
413 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL);
414 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 11);
415 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next == NULL);
416 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[14].sid != 144);
417 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next->store[0].sid != 155);
418 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next->store[1].sid != 166);
419
421
422 PASS;
423}
424
425static int DeStateTest03(void)
426{
428 FAIL_IF_NULL(state);
429
430 Signature s;
431 memset(&s, 0x00, sizeof(s));
432
433 uint8_t direction = STREAM_TOSERVER;
434
435 s.iid = 11;
436 DeStateSignatureAppend(state, &s, 0, direction);
437 s.iid = 22;
438 DeStateSignatureAppend(state, &s, BIT_U32(DE_STATE_FLAG_BASE), direction);
439
440 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL);
441 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].sid != 11);
442 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].flags & BIT_U32(DE_STATE_FLAG_BASE));
443 FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 22);
444 FAIL_IF(!(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].flags & BIT_U32(DE_STATE_FLAG_BASE)));
445
447 PASS;
448}
449
450static int DeStateSigTest01(void)
451{
452 DetectEngineThreadCtx *det_ctx = NULL;
453 ThreadVars th_v;
454 Flow f;
455 TcpSession ssn;
456 Packet *p = NULL;
457 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\n";
458 uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\n";
459 uint8_t httpbuf3[] = "Cookie: dummy\r\nContent-Length: 10\r\n\r\n";
460 uint8_t httpbuf4[] = "Http Body!";
461 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
462 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
463 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
464 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
465
468
469 memset(&th_v, 0, sizeof(th_v));
470 memset(&f, 0, sizeof(f));
471 memset(&ssn, 0, sizeof(ssn));
472
473 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
474 FAIL_IF_NULL(p);
475
476 FLOW_INITIALIZE(&f);
477 f.protoctx = (void *)&ssn;
478 f.proto = IPPROTO_TCP;
479 f.flags |= FLOW_IPV4;
481
482 p->flow = &f;
486
488
492
493 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;)");
494 FAIL_IF_NULL(s);
495
497 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
498 FAIL_IF_NULL(det_ctx);
499
500 int r = AppLayerParserParse(
501 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
502 FAIL_IF_NOT(r == 0);
503 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
505
506 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
507 FAIL_IF_NOT(r == 0);
508 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
510
511 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
512 FAIL_IF_NOT(r == 0);
513 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
515
516 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf4, httplen4);
517 FAIL_IF_NOT(r == 0);
518 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
520
522 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
525 FLOW_DESTROY(&f);
526 UTHFreePacket(p);
527 PASS;
528}
529
530/** \test multiple pipelined http transactions */
531static int DeStateSigTest02(void)
532{
533 DetectEngineThreadCtx *det_ctx = NULL;
534 ThreadVars th_v;
535 Flow f;
536 TcpSession ssn;
537 Packet *p = NULL;
538 uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
539 uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
540 uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
541 uint8_t httpbuf4[] = "Http Body!";
542 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
543 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
544 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
545 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
546 uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
547 uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
548 uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nHttp Body!";
549 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
550 uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
551 uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
554
555 memset(&th_v, 0, sizeof(th_v));
556 memset(&f, 0, sizeof(f));
557 memset(&ssn, 0, sizeof(ssn));
558
559 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
560
561 FLOW_INITIALIZE(&f);
562 f.protoctx = (void *)&ssn;
563 f.proto = IPPROTO_TCP;
564 f.flags |= FLOW_IPV4;
565
566 p->flow = &f;
571
573
576
578
579 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;)");
580 FAIL_IF_NULL(s);
581 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;)");
582 FAIL_IF_NULL(s);
583
585 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
586 FAIL_IF_NULL(det_ctx);
587
588 int r = AppLayerParserParse(
589 NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
590 FAIL_IF(r != 0);
591 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
593
594 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
595 FAIL_IF(r != 0);
596 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
598
599 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
600 FAIL_IF(r != 0);
601 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
603
604 void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f.alstate, 0);
605 FAIL_IF_NULL(tx);
606
607 AppLayerTxData *tx_data = AppLayerParserGetTxData(IPPROTO_TCP, ALPROTO_HTTP1, tx);
608 FAIL_IF_NULL(tx_data);
609 DetectEngineState *tx_de_state = tx_data->de_state;
610 FAIL_IF_NULL(tx_de_state);
611 FAIL_IF(tx_de_state->dir_state[0].cnt != 1);
612 /* http_header(mpm): 5, uri: 3, method: 6, cookie: 7 */
613 uint32_t expected_flags = (BIT_U32(5) | BIT_U32(3) | BIT_U32(6) | BIT_U32(4));
614 FAIL_IF(tx_de_state->dir_state[0].head->store[0].flags != expected_flags);
615
616 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf4, httplen4);
617 FAIL_IF(r != 0);
618 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
619 FAIL_IF(!(PacketAlertCheck(p, 1)));
620
621 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf5, httplen5);
622 FAIL_IF(r != 0);
623 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
625
626 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf6, httplen6);
627 FAIL_IF(r != 0);
628 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
629 FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2)));
630
631 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf7, httplen7);
632 FAIL_IF(r != 0);
633 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
634 FAIL_IF(!(PacketAlertCheck(p, 2)));
635
637 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
640 FLOW_DESTROY(&f);
641 UTHFreePacket(p);
642 PASS;
643}
644
645static int DeStateSigTest03(void)
646{
647 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
648 "Host: www.server.lan\r\n"
649 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
650 "Content-Length: 215\r\n"
651 "\r\n"
652 "-----------------------------277531038314945\r\n"
653 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
654 "Content-Type: image/jpeg\r\n"
655 "\r\n"
656 "filecontent\r\n"
657 "-----------------------------277531038314945--";
658 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
659 ThreadVars th_v;
660 TcpSession ssn;
661 Flow *f = NULL;
662 Packet *p = NULL;
665
666 memset(&th_v, 0, sizeof(th_v));
667 memset(&ssn, 0, sizeof(ssn));
668
669 DetectEngineThreadCtx *det_ctx = NULL;
672
674
675 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;)");
676 FAIL_IF_NULL(s);
677
679 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
680
681 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
682 FAIL_IF_NULL(f);
683 f->protoctx = &ssn;
684 f->proto = IPPROTO_TCP;
686
687 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
688 FAIL_IF_NULL(p);
689
690 p->flow = f;
694
696
698 STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
699 FAIL_IF(r != 0);
700
701 HtpState *http_state = f->alstate;
702 FAIL_IF_NULL(http_state);
703 void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
704 FAIL_IF_NULL(tx);
705 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
706 FAIL_IF_NULL(tx_ud);
707
708 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
709 FAIL_IF(!(PacketAlertCheck(p, 1)));
710
711 AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
712 FileContainer *fc = files.fc;
713 FAIL_IF_NULL(fc);
714
715 File *file = fc->head;
716 FAIL_IF_NULL(file);
717
718 FAIL_IF(!(file->flags & FILE_STORE));
719
721 UTHFreeFlow(f);
722
723 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
726 PASS;
727}
728
729static int DeStateSigTest04(void)
730{
731 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
732 "Host: www.server.lan\r\n"
733 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
734 "Content-Length: 215\r\n"
735 "\r\n"
736 "-----------------------------277531038314945\r\n"
737 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
738 "Content-Type: image/jpeg\r\n"
739 "\r\n"
740 "filecontent\r\n"
741 "-----------------------------277531038314945--";
742 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
743 ThreadVars th_v;
744 TcpSession ssn;
747
748 memset(&th_v, 0, sizeof(th_v));
749 memset(&ssn, 0, sizeof(ssn));
750
751 DetectEngineThreadCtx *det_ctx = NULL;
755
756 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;)");
757 FAIL_IF_NULL(s);
758
760 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
761 FAIL_IF_NULL(det_ctx);
762
763 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
764 FAIL_IF_NULL(f);
765 f->protoctx = &ssn;
766 f->proto = IPPROTO_TCP;
768
769 Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
770 FAIL_IF_NULL(p);
771 p->flow = f;
775
777
779 STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
780 FAIL_IF(r != 0);
781 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
783
784 HtpState *http_state = f->alstate;
785 FAIL_IF_NULL(http_state);
786 void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
787 FAIL_IF_NULL(tx);
788 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
789 FAIL_IF_NULL(tx_ud);
790
791 AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
792 FileContainer *fc = files.fc;
793 FAIL_IF_NULL(fc);
794 File *file = fc->head;
795 FAIL_IF_NULL(file);
796
797 FAIL_IF(file->flags & FILE_STORE);
798
800 UTHFreeFlow(f);
801 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
804 PASS;
805}
806
807static int DeStateSigTest05(void)
808{
809 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
810 "Host: www.server.lan\r\n"
811 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
812 "Content-Length: 215\r\n"
813 "\r\n"
814 "-----------------------------277531038314945\r\n"
815 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
816 "Content-Type: image/jpeg\r\n"
817 "\r\n"
818 "filecontent\r\n"
819 "-----------------------------277531038314945--";
820 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
821 ThreadVars th_v;
822 TcpSession ssn;
823
826
827 memset(&th_v, 0, sizeof(th_v));
828 memset(&ssn, 0, sizeof(ssn));
829
830 DetectEngineThreadCtx *det_ctx = NULL;
834
835 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;)");
836 FAIL_IF_NULL(s);
837
839 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
840
841 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
842 FAIL_IF_NULL(f);
843 f->protoctx = &ssn;
844 f->proto = IPPROTO_TCP;
846
847 Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
848 FAIL_IF_NULL(p);
849 p->flow = f;
853
855
857 STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
858 FAIL_IF_NOT(r == 0);
859 HtpState *http_state = f->alstate;
860 FAIL_IF_NULL(http_state);
861 void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
862 FAIL_IF_NULL(tx);
863 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
864 FAIL_IF_NULL(tx_ud);
865
866 AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
867 FileContainer *fc = files.fc;
868 FAIL_IF_NULL(fc);
869 File *file = fc->head;
870 FAIL_IF_NULL(file);
871 FAIL_IF(http_state->state_data.file_flags & FLOWFILE_NO_STORE_TS);
872
873 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
875
876 /* detect will have set FLOWFILE_NO_STORE_TS, but it won't have had
877 * an opportunity to be applied to the file itself yet */
878 FAIL_IF_NOT(http_state->state_data.file_flags & FLOWFILE_NO_STORE_TS);
879 FAIL_IF(file->flags & FILE_NOSTORE);
880
882 UTHFreeFlow(f);
883 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
886 PASS;
887}
888
889static int DeStateSigTest06(void)
890{
891 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
892 "Host: www.server.lan\r\n"
893 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
894 "Content-Length: 215\r\n"
895 "\r\n"
896 "-----------------------------277531038314945\r\n"
897 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
898 "Content-Type: image/jpeg\r\n"
899 "\r\n"
900 "filecontent\r\n"
901 "-----------------------------277531038314945--";
902 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
903 ThreadVars th_v;
904 TcpSession ssn;
905
908
909 memset(&th_v, 0, sizeof(th_v));
910 memset(&ssn, 0, sizeof(ssn));
911
912 DetectEngineThreadCtx *det_ctx = NULL;
916
917 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;)");
918 FAIL_IF_NULL(s);
919
921 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
922 FAIL_IF_NULL(det_ctx);
923
924 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
925 FAIL_IF_NULL(f);
926 f->protoctx = &ssn;
927 f->proto = IPPROTO_TCP;
929
930 Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
931 FAIL_IF_NULL(p);
932 p->flow = f;
936
938
940 STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
941 FAIL_IF(r != 0);
942 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
944
945 HtpState *http_state = f->alstate;
946 FAIL_IF_NULL(http_state);
947 void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
948 FAIL_IF_NULL(tx);
949 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
950 FAIL_IF_NULL(tx_ud);
951
952 AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
953 FileContainer *fc = files.fc;
954 FAIL_IF_NULL(fc);
955 File *file = fc->head;
956 FAIL_IF_NULL(file);
957 /* detect will have set FLOWFILE_NO_STORE_TS, but it won't have had
958 * an opportunity to be applied to the file itself yet */
959 FAIL_IF_NOT(tx_ud->tx_data.file_flags & FLOWFILE_NO_STORE_TS);
960 FAIL_IF(file->flags & FILE_NOSTORE);
961
963 UTHFreeFlow(f);
964 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
967 PASS;
968}
969
970static int DeStateSigTest07(void)
971{
972 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
973 "Host: www.server.lan\r\n"
974 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
975 "Content-Length: 215\r\n"
976 "\r\n"
977 "-----------------------------277531038314945\r\n"
978 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
979 "Content-Type: image/jpeg\r\n"
980 "\r\n";
981
982 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
983 uint8_t httpbuf2[] = "filecontent\r\n"
984 "-----------------------------277531038314945--";
985 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
986 ThreadVars th_v;
987 TcpSession ssn;
988
991
992 memset(&th_v, 0, sizeof(th_v));
993 memset(&ssn, 0, sizeof(ssn));
994
995 DetectEngineThreadCtx *det_ctx = NULL;
999
1000 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;)");
1001 FAIL_IF_NULL(s);
1002
1004 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1005
1006 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1007 FAIL_IF_NULL(f);
1008 f->protoctx = &ssn;
1009 f->proto = IPPROTO_TCP;
1011
1012 Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1013 FAIL_IF_NULL(p);
1014 p->flow = f;
1018
1019 StreamTcpInitConfig(true);
1020
1021 int r = AppLayerParserParse(
1022 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1023 FAIL_IF(r != 0);
1024 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1026
1028 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1029 FAIL_IF(r != 0);
1030 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1032
1033 HtpState *http_state = f->alstate;
1034 FAIL_IF_NULL(http_state);
1035 void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1036 FAIL_IF_NULL(tx);
1037 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1038 FAIL_IF_NULL(tx_ud);
1039
1040 AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1041 FileContainer *fc = files.fc;
1042 FAIL_IF_NULL(fc);
1043 File *file = fc->head;
1044 FAIL_IF_NULL(file);
1045 FAIL_IF(file->flags & FILE_STORE);
1046
1048 UTHFreeFlow(f);
1049 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1051 StreamTcpFreeConfig(true);
1052 PASS;
1053}
1054
1055/**
1056 * \test multiple files in a tx
1057 */
1058static int DeStateSigTest08(void)
1059{
1060 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1061 "Host: www.server.lan\r\n"
1062 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1063 "Content-Length: 440\r\n"
1064 "\r\n"
1065 "-----------------------------277531038314945\r\n"
1066 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"AAAApicture1.jpg\"\r\n"
1067 "Content-Type: image/jpeg\r\n"
1068 "\r\n";
1069
1070 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1071 uint8_t httpbuf2[] = "file";
1072 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1073 uint8_t httpbuf3[] = "content\r\n"
1074 "-----------------------------277531038314945\r\n";
1075 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1076
1077 uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"BBBBpicture2.jpg\"\r\n"
1078 "Content-Type: image/jpeg\r\n"
1079 "\r\n"
1080 "filecontent2\r\n"
1081 "-----------------------------277531038314945--";
1082 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1083
1084 ThreadVars th_v;
1085 TcpSession ssn;
1086
1089
1090 memset(&th_v, 0, sizeof(th_v));
1091 memset(&ssn, 0, sizeof(ssn));
1092
1093 DetectEngineThreadCtx *det_ctx = NULL;
1096 de_ctx->flags |= DE_QUIET;
1097
1098 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;)");
1099 FAIL_IF_NULL(s);
1100
1102 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1103
1104 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1105 FAIL_IF_NULL(f);
1106 f->protoctx = &ssn;
1107 f->proto = IPPROTO_TCP;
1109
1110 Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1111 FAIL_IF_NULL(p);
1112 p->flow = f;
1116
1117 StreamTcpInitConfig(true);
1118
1119 /* HTTP request with 1st part of the multipart body */
1120
1121 int r = AppLayerParserParse(
1122 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1123 FAIL_IF(r != 0);
1124 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1126
1127 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1128 FAIL_IF(r != 0);
1129 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1131
1132 HtpState *http_state = f->alstate;
1133 FAIL_IF_NULL(http_state);
1134 void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1135 FAIL_IF_NULL(tx);
1136 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1137 FAIL_IF_NULL(tx_ud);
1138
1139 AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1140 FileContainer *fc = files.fc;
1141 FAIL_IF_NULL(fc);
1142 File *file = fc->head;
1143 FAIL_IF_NULL(file);
1144 FAIL_IF(file->flags & FILE_STORE);
1145
1146 /* 2nd multipart body file */
1147
1148 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1149 FAIL_IF(r != 0);
1150 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1152
1154 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1155 FAIL_IF(r != 0);
1156 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1158
1159 http_state = f->alstate;
1160 FAIL_IF_NULL(http_state);
1161 tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1162 FAIL_IF_NULL(tx);
1163 tx_ud = htp_tx_get_user_data(tx);
1164 FAIL_IF_NULL(tx_ud);
1165
1166 files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1167 fc = files.fc;
1168 FAIL_IF_NULL(fc);
1169 file = fc->head;
1170 FAIL_IF_NULL(file);
1171 file = file->next;
1172 FAIL_IF_NULL(file);
1173 FAIL_IF_NOT(file->flags & FILE_STORE);
1174
1176 UTHFreeFlow(f);
1177 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1179 StreamTcpFreeConfig(true);
1180 PASS;
1181}
1182
1183/**
1184 * \test multiple files in a tx. Both files should match
1185 */
1186static int DeStateSigTest09(void)
1187{
1188 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1189 "Host: www.server.lan\r\n"
1190 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1191 "Content-Length: 440\r\n"
1192 "\r\n"
1193 "-----------------------------277531038314945\r\n"
1194 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1195 "Content-Type: image/jpeg\r\n"
1196 "\r\n";
1197
1198 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1199 uint8_t httpbuf2[] = "file";
1200 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1201 uint8_t httpbuf3[] = "content\r\n"
1202 "-----------------------------277531038314945\r\n";
1203 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1204
1205 uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
1206 "Content-Type: image/jpeg\r\n"
1207 "\r\n"
1208 "filecontent2\r\n"
1209 "-----------------------------277531038314945--";
1210 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1211
1212 ThreadVars th_v;
1213 TcpSession ssn;
1214
1217
1218 memset(&th_v, 0, sizeof(th_v));
1219 memset(&ssn, 0, sizeof(ssn));
1220
1221 DetectEngineThreadCtx *det_ctx = NULL;
1224 de_ctx->flags |= DE_QUIET;
1225
1226 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;)");
1227 FAIL_IF_NULL(s);
1228
1230 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1231
1232 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1233 FAIL_IF_NULL(f);
1234 f->protoctx = &ssn;
1235 f->proto = IPPROTO_TCP;
1237
1238 Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1239 FAIL_IF_NULL(p);
1240 p->flow = f;
1244
1245 StreamTcpInitConfig(true);
1246
1247 /* HTTP request with 1st part of the multipart body */
1248
1249 int r = AppLayerParserParse(
1250 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1251 FAIL_IF(r != 0);
1252 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1254
1255 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1256 FAIL_IF(r != 0);
1257 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1259
1260 HtpState *http_state = f->alstate;
1261 FAIL_IF_NULL(http_state);
1262 void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1263 FAIL_IF_NULL(tx);
1264 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1265 FAIL_IF_NULL(tx_ud);
1266
1267 AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1268 FileContainer *fc = files.fc;
1269 FAIL_IF_NULL(fc);
1270 File *file = fc->head;
1271 FAIL_IF_NULL(file);
1272 FAIL_IF_NOT(file->flags & FILE_STORE);
1273
1274 /* 2nd multipart body file */
1275
1276 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1277 FAIL_IF(r != 0);
1278 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1280
1282 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1283 FAIL_IF(r != 0);
1284 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1286
1287 http_state = f->alstate;
1288 FAIL_IF_NULL(http_state);
1289 tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1290 FAIL_IF_NULL(tx);
1291 tx_ud = htp_tx_get_user_data(tx);
1292 FAIL_IF_NULL(tx_ud);
1293
1294 files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1295 fc = files.fc;
1296 FAIL_IF_NULL(fc);
1297 file = fc->head;
1298 FAIL_IF_NULL(file);
1299 FAIL_IF_NOT(file->flags & FILE_STORE);
1300
1302 UTHFreeFlow(f);
1303 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1305 StreamTcpFreeConfig(true);
1306 PASS;
1307}
1308
1309/**
1310 * \test multiple files in a tx. Both files should match. No other matches.
1311 */
1312static int DeStateSigTest10(void)
1313{
1314 uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1315 "Host: www.server.lan\r\n"
1316 "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1317 "Content-Length: 440\r\n"
1318 "\r\n"
1319 "-----------------------------277531038314945\r\n"
1320 "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1321 "Content-Type: image/jpeg\r\n"
1322 "\r\n";
1323
1324 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1325 uint8_t httpbuf2[] = "file";
1326 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1327 uint8_t httpbuf3[] = "content\r\n"
1328 "-----------------------------277531038314945\r\n";
1329 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1330
1331 uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
1332 "Content-Type: image/jpeg\r\n"
1333 "\r\n"
1334 "filecontent2\r\n"
1335 "-----------------------------277531038314945--";
1336 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1337
1338 ThreadVars th_v;
1339 TcpSession ssn;
1340
1343
1344 memset(&th_v, 0, sizeof(th_v));
1345 memset(&ssn, 0, sizeof(ssn));
1346
1347 DetectEngineThreadCtx *det_ctx = NULL;
1350 de_ctx->flags |= DE_QUIET;
1351
1352 Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (filename:\"somepicture\"; filestore; sid:1; rev:1;)");
1353 FAIL_IF_NULL(s);
1354
1356 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1357
1358 Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1359 FAIL_IF_NULL(f);
1360 f->protoctx = &ssn;
1361 f->proto = IPPROTO_TCP;
1363
1364 Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1365 FAIL_IF_NULL(p);
1366 p->flow = f;
1370
1371 StreamTcpInitConfig(true);
1372
1373 /* HTTP request with 1st part of the multipart body */
1374
1375 int r = AppLayerParserParse(
1376 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1377 FAIL_IF(r != 0);
1378 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1380
1381 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1382 FAIL_IF(r != 0);
1383 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1385
1386 HtpState *http_state = f->alstate;
1387 FAIL_IF_NULL(http_state);
1388 void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1389 FAIL_IF_NULL(tx);
1390 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1391 FAIL_IF_NULL(tx_ud);
1392
1393 AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1394 FileContainer *fc = files.fc;
1395 FAIL_IF_NULL(fc);
1396 File *file = fc->head;
1397 FAIL_IF_NULL(file);
1398 FAIL_IF_NOT(file->flags & FILE_STORE);
1399
1400 /* 2nd multipart body file */
1401
1402 r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1403 FAIL_IF(r != 0);
1404 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1406
1408 NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1409 FAIL_IF(r != 0);
1410 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1412
1413 http_state = f->alstate;
1414 FAIL_IF_NULL(http_state);
1415 tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1416 FAIL_IF_NULL(tx);
1417 tx_ud = htp_tx_get_user_data(tx);
1418 FAIL_IF_NULL(tx_ud);
1419
1420 files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1421 fc = files.fc;
1422 FAIL_IF_NULL(fc);
1423 file = fc->head;
1424 FAIL_IF_NULL(file);
1425 FAIL_IF_NOT(file->flags & FILE_STORE);
1426
1428 UTHFreeFlow(f);
1429 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1431 StreamTcpFreeConfig(true);
1432 PASS;
1433}
1434
1435#endif
1436
1438{
1439#ifdef UNITTESTS
1440 UtRegisterTest("DeStateTest01", DeStateTest01);
1441 UtRegisterTest("DeStateTest02", DeStateTest02);
1442 UtRegisterTest("DeStateTest03", DeStateTest03);
1443 UtRegisterTest("DeStateSigTest01", DeStateSigTest01);
1444 UtRegisterTest("DeStateSigTest02", DeStateSigTest02);
1445 UtRegisterTest("DeStateSigTest03", DeStateSigTest03);
1446 UtRegisterTest("DeStateSigTest04", DeStateSigTest04);
1447 UtRegisterTest("DeStateSigTest05", DeStateSigTest05);
1448 UtRegisterTest("DeStateSigTest06", DeStateSigTest06);
1449 UtRegisterTest("DeStateSigTest07", DeStateSigTest07);
1450 UtRegisterTest("DeStateSigTest08", DeStateSigTest08);
1451 UtRegisterTest("DeStateSigTest09", DeStateSigTest09);
1452 UtRegisterTest("DeStateSigTest10", DeStateSigTest10);
1453#endif
1454}
1455
1456/**
1457 * @}
1458 */
struct HtpBodyChunk_ * next
AppLayerTxData * AppLayerParserGetTxData(uint8_t ipproto, AppProto alproto, void *tx)
AppLayerGetFileState AppLayerParserGetTxFiles(const Flow *f, void *tx, const uint8_t direction)
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
uint64_t AppLayerParserGetTxCnt(const Flow *f, void *alstate)
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint8_t direction)
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
struct AppLayerGetFileState AppLayerGetFileState
struct AppLayerTxData AppLayerTxData
@ ALPROTO_HTTP1
uint8_t flags
Definition decode-gre.h:0
#define PKT_HAS_FLOW
Definition decode.h:1266
#define PKT_STREAM_EST
Definition decode.h:1262
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Data structures and function prototypes for keeping state for the detection engine.
#define DE_STATE_CHUNK_SIZE
#define DE_STATE_FLAG_BASE
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition detect.c:2420
#define DE_QUIET
Definition detect.h:330
#define SIG_FLAG_TXBOTHDIR
Definition detect.h:250
Flow * head
Definition flow-hash.h:1
#define FLOW_INITIALIZE(f)
Definition flow-util.h:38
#define FLOW_DESTROY(f)
Definition flow-util.h:119
#define FLOW_PKT_TOSERVER
Definition flow.h:233
#define FLOWFILE_NO_STORE_TS
Definition flow.h:134
#define FLOW_PKT_ESTABLISHED
Definition flow.h:235
#define FLOW_IPV4
Definition flow.h:100
AppLayerParserThreadCtx * alp_tctx
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
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 DeStateRegisterTests(void)
void DetectEngineStateResetTxs(Flow *f)
Reset de state for active tx' To be used on detect engine reload.
DetectEngineState * DetectEngineStateAlloc(void)
Alloc a DetectEngineState object.
void DetectEngineStateFree(DetectEngineState *state)
Frees a DetectEngineState object.
Host * tail
Definition host.h:2
void StreamTcpFreeConfig(bool quiet)
Definition stream-tcp.c:859
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition stream-tcp.c:488
struct DeStateStore_ * next
DeStateStoreItem store[DE_STATE_CHUNK_SIZE]
main detection engine ctx
Definition detect.h:932
uint8_t flags
Definition detect.h:934
Signature * sig_list
Definition detect.h:941
DetectEngineStateDirection dir_state[2]
uint16_t flags
Definition util-file.h:80
struct File_ * next
Definition util-file.h:92
Flow data structure.
Definition flow.h:356
uint8_t proto
Definition flow.h:378
uint32_t flags
Definition flow.h:421
AppProto alproto
application level protocol
Definition flow.h:450
void * alstate
Definition flow.h:479
void * protoctx
Definition flow.h:441
AppLayerParserState * alparser
Definition flow.h:478
AppLayerStateData state_data
htp_conn_t * conn
AppLayerTxData tx_data
uint8_t flowflags
Definition decode.h:532
struct Flow_ * flow
Definition decode.h:546
uint32_t flags
Definition decode.h:544
Container for matching data for a signature group.
Definition detect.h:1629
Signature container.
Definition detect.h:668
uint32_t flags
Definition detect.h:669
SigIntId iid
Definition detect.h:680
Per thread variable structure.
Definition threadvars.h:58
#define BUG_ON(x)
#define SigIntId
#define MIN(x, y)
#define BIT_U32(n)
#define SCEnter(...)
Definition util-debug.h:277
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturn
Definition util-debug.h:279
void FileDisableStoringForTransaction(Flow *f, const uint8_t direction, void *tx, uint64_t tx_id)
disable file storing for files in a transaction
Definition util-file.c:1139
#define FILE_NOSTORE
Definition util-file.h:54
#define FILE_STORE
Definition util-file.h:55
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define unlikely(expr)
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 UTHFreeFlow(Flow *flow)
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself.
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)