suricata
app-layer-htp-file.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2011 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * This file provides HTTP protocol file handling support for the engine
24  * using HTP library.
25  */
26 
27 #include "suricata.h"
28 #include "suricata-common.h"
29 #include "debug.h"
30 #include "decode.h"
31 #include "threads.h"
32 
33 #include "util-print.h"
34 #include "util-pool.h"
35 #include "util-radix-tree.h"
36 
37 #include "stream-tcp-private.h"
38 #include "stream-tcp-reassemble.h"
39 #include "stream-tcp.h"
40 #include "stream.h"
41 
42 #include "app-layer.h"
43 #include "app-layer-protos.h"
44 #include "app-layer-parser.h"
45 #include "app-layer-htp.h"
46 #include "app-layer-htp-file.h"
47 
48 #include "util-spm.h"
49 #include "util-debug.h"
50 #include "util-time.h"
51 
52 #include "util-unittest.h"
53 #include "util-unittest-helper.h"
54 #include "flow-util.h"
55 
56 #include "detect-engine.h"
57 #include "detect-engine-state.h"
58 #include "detect-parse.h"
59 
60 #include "conf.h"
61 
62 #include "util-memcmp.h"
63 
64 /**
65  * \brief Open the file with "filename" and pass the first chunk
66  * of data if any.
67  *
68  * \param s http state
69  * \param filename name of the file
70  * \param filename_len length of the name
71  * \param data data chunk (if any)
72  * \param data_len length of the data portion
73  * \param direction flow direction
74  *
75  * \retval 0 ok
76  * \retval -1 error
77  * \retval -2 not handling files on this flow
78  */
79 int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len,
80  const uint8_t *data, uint32_t data_len,
81  uint64_t txid, uint8_t direction)
82 {
83  int retval = 0;
84  uint16_t flags = 0;
85  FileContainer *files = NULL;
86  const StreamingBufferConfig *sbcfg = NULL;
87 
88  SCLogDebug("data %p data_len %"PRIu32, data, data_len);
89 
90  if (s == NULL) {
91  SCReturnInt(-1);
92  }
93 
94  if (direction & STREAM_TOCLIENT) {
95  if (s->files_tc == NULL) {
97  if (s->files_tc == NULL) {
98  retval = -1;
99  goto end;
100  }
101  }
102 
103  files = s->files_tc;
104 
105  flags = FileFlowToFlags(s->f, STREAM_TOCLIENT);
106 
107  if ((s->flags & HTP_FLAG_STORE_FILES_TS) ||
108  ((s->flags & HTP_FLAG_STORE_FILES_TX_TS) && txid == s->store_tx_id)) {
109  flags |= FILE_STORE;
110  flags &= ~FILE_NOSTORE;
111  } else if (!(flags & FILE_STORE) && (s->f->file_flags & FLOWFILE_NO_STORE_TC)) {
112  flags |= FILE_NOSTORE;
113  }
114 
115  sbcfg = &s->cfg->response.sbcfg;
116 
117  } else {
118  if (s->files_ts == NULL) {
120  if (s->files_ts == NULL) {
121  retval = -1;
122  goto end;
123  }
124  }
125 
126  files = s->files_ts;
127 
128  flags = FileFlowToFlags(s->f, STREAM_TOSERVER);
129  if ((s->flags & HTP_FLAG_STORE_FILES_TC) ||
130  ((s->flags & HTP_FLAG_STORE_FILES_TX_TC) && txid == s->store_tx_id)) {
131  flags |= FILE_STORE;
132  flags &= ~FILE_NOSTORE;
133  } else if (!(flags & FILE_STORE) && (s->f->file_flags & FLOWFILE_NO_STORE_TS)) {
134  flags |= FILE_NOSTORE;
135  }
136 
137  sbcfg = &s->cfg->request.sbcfg;
138  }
139 
140  if (FileOpenFile(files, sbcfg, filename, filename_len,
141  data, data_len, flags) == NULL)
142  {
143  retval = -1;
144  }
145 
146  FileSetTx(files->tail, txid);
147 
148  FilePrune(files);
149 end:
150  SCReturnInt(retval);
151 }
152 
153 /**
154  * Performs parsing of the content-range value
155  *
156  * @param[in] rawvalue
157  * @param[out] range
158  *
159  * @return HTP_OK on success, HTP_ERROR on failure.
160  */
161 int HTPParseContentRange(bstr * rawvalue, HtpContentRange *range)
162 {
163  unsigned char *data = bstr_ptr(rawvalue);
164  size_t len = bstr_len(rawvalue);
165  size_t pos = 0;
166  size_t last_pos;
167 
168  // skip spaces and units
169  while (pos < len && data[pos] == ' ')
170  pos++;
171  while (pos < len && data[pos] != ' ')
172  pos++;
173  while (pos < len && data[pos] == ' ')
174  pos++;
175 
176  // initialize to unseen
177  range->start = -1;
178  range->end = -1;
179  range->size = -1;
180 
181  if (pos == len) {
182  // missing data
183  return -1;
184  }
185 
186  if (data[pos] == '*') {
187  // case with size only
188  if (len < pos + 1 || data[pos+1] != '/') {
189  range->size = -1;
190  return -1;
191  }
192  pos += 2;
193  range->size = bstr_util_mem_to_pint(data + pos, len - pos, 10, &last_pos);
194  } else {
195  // case with start and end
196  range->start = bstr_util_mem_to_pint(data + pos, len - pos, 10, &last_pos);
197  pos += last_pos;
198  if (len < pos || data[pos] != '-') {
199  return -1;
200  }
201  pos++;
202  range->end = bstr_util_mem_to_pint(data + pos, len - pos, 10, &last_pos);
203  pos += last_pos;
204  if (len < pos || data[pos] != '/') {
205  return -1;
206  }
207  pos++;
208  if (data[pos] != '*') {
209  // case with size
210  range->size = bstr_util_mem_to_pint(data + pos, len - pos, 10, &last_pos);
211  }
212  }
213 
214  return 0;
215 }
216 
217 /**
218  * \brief Sets range for a file
219  *
220  * \param s http state
221  * \param rawvalue raw header value
222  *
223  * \retval 0 ok
224  * \retval -1 error
225  * \retval -2 error parsing
226  * \retval -3 error negative end in range
227  */
228 int HTPFileSetRange(HtpState *s, bstr *rawvalue)
229 {
230  SCEnter();
231 
232  if (s == NULL) {
233  SCReturnInt(-1);
234  }
235 
236  FileContainer * files = s->files_tc;
237  if (files == NULL) {
238  SCLogDebug("no files in state");
239  SCReturnInt(-1);
240  }
241 
242  HtpContentRange crparsed;
243  if (HTPParseContentRange(rawvalue, &crparsed) != 0) {
244  SCLogDebug("parsing range failed");
245  SCReturnInt(-2);
246  }
247  if (crparsed.end <= 0) {
248  SCLogDebug("negative end in range");
249  SCReturnInt(-3);
250  }
251  int retval = FileSetRange(files, crparsed.start, crparsed.end);
252  if (retval == -1) {
253  SCLogDebug("set range failed");
254  }
255  SCReturnInt(retval);
256 }
257 
258 /**
259  * \brief Store a chunk of data in the flow
260  *
261  * \param s http state
262  * \param data data chunk (if any)
263  * \param data_len length of the data portion
264  * \param direction flow direction
265  *
266  * \retval 0 ok
267  * \retval -1 error
268  * \retval -2 file doesn't need storing
269  */
270 int HTPFileStoreChunk(HtpState *s, const uint8_t *data, uint32_t data_len,
271  uint8_t direction)
272 {
273  SCEnter();
274 
275  int retval = 0;
276  int result = 0;
277  FileContainer *files = NULL;
278 
279  if (s == NULL) {
280  SCReturnInt(-1);
281  }
282 
283  if (direction & STREAM_TOCLIENT) {
284  files = s->files_tc;
285  } else {
286  files = s->files_ts;
287  }
288 
289  if (files == NULL) {
290  SCLogDebug("no files in state");
291  retval = -1;
292  goto end;
293  }
294 
295  result = FileAppendData(files, data, data_len);
296  if (result == -1) {
297  SCLogDebug("appending data failed");
298  retval = -1;
299  } else if (result == -2) {
300  retval = -2;
301  }
302 
303  FilePrune(files);
304 end:
305  SCReturnInt(retval);
306 }
307 
308 /**
309  * \brief Close the file in the flow
310  *
311  * \param s http state
312  * \param data data chunk if any
313  * \param data_len length of the data portion
314  * \param flags flags to indicate events
315  * \param direction flow direction
316  *
317  * Currently on the FLOW_FILE_TRUNCATED flag is implemented, indicating
318  * that the file isn't complete but we're stopping storing it.
319  *
320  * \retval 0 ok
321  * \retval -1 error
322  * \retval -2 not storing files on this flow/tx
323  */
324 int HTPFileClose(HtpState *s, const uint8_t *data, uint32_t data_len,
325  uint8_t flags, uint8_t direction)
326 {
327  SCEnter();
328 
329  int retval = 0;
330  int result = 0;
331  FileContainer *files = NULL;
332 
333  if (s == NULL) {
334  SCReturnInt(-1);
335  }
336 
337  if (direction & STREAM_TOCLIENT) {
338  files = s->files_tc;
339  } else {
340  files = s->files_ts;
341  }
342 
343  if (files == NULL) {
344  retval = -1;
345  goto end;
346  }
347 
348  result = FileCloseFile(files, data, data_len, flags);
349  if (result == -1) {
350  retval = -1;
351  } else if (result == -2) {
352  retval = -2;
353  }
354 
355  FilePrune(files);
356 end:
357  SCReturnInt(retval);
358 }
359 
360 #ifdef UNITTESTS
361 static int HTPFileParserTest01(void)
362 {
363  int result = 0;
364  Flow *f = NULL;
365  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
366  "Host: www.server.lan\r\n"
367  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
368  "Content-Length: 215\r\n"
369  "\r\n"
370  "-----------------------------277531038314945\r\n"
371  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
372  "Content-Type: image/jpeg\r\n"
373  "\r\n";
374 
375  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
376  uint8_t httpbuf2[] = "filecontent\r\n"
377  "-----------------------------277531038314945--";
378  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
379 
380  TcpSession ssn;
382  HtpState *http_state = NULL;
383  memset(&ssn, 0, sizeof(ssn));
384 
385  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
386  if (f == NULL)
387  goto end;
388  f->protoctx = &ssn;
389  f->proto = IPPROTO_TCP;
390  f->alproto = ALPROTO_HTTP;
391 
393 
394  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
395  FLOWLOCK_WRLOCK(f);
396  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
397  STREAM_TOSERVER | STREAM_START, httpbuf1,
398  httplen1);
399  if (r != 0) {
400  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
401  result = 0;
402  FLOWLOCK_UNLOCK(f);
403  goto end;
404  }
405  FLOWLOCK_UNLOCK(f);
406 
407  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
408  FLOWLOCK_WRLOCK(f);
409  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
410  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
411  if (r != 0) {
412  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
413  result = 0;
414  FLOWLOCK_UNLOCK(f);
415  goto end;
416  }
417  FLOWLOCK_UNLOCK(f);
418 
419  http_state = f->alstate;
420  if (http_state == NULL) {
421  printf("no http state: ");
422  result = 0;
423  goto end;
424  }
425 
426  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
427  if (tx == NULL) {
428  goto end;
429  }
430 
431  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
432  {
433  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
434  goto end;
435  }
436 
437  result = 1;
438 end:
439  if (alp_tctx != NULL)
440  AppLayerParserThreadCtxFree(alp_tctx);
442  UTHFreeFlow(f);
443  return result;
444 }
445 
446 static int HTPFileParserTest02(void)
447 {
448  int result = 0;
449  Flow *f = NULL;
450  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
451  "Host: www.server.lan\r\n"
452  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
453  "Content-Length: 337\r\n"
454  "\r\n";
455  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
456 
457  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
458  "Content-Disposition: form-data; name=\"email\"\r\n"
459  "\r\n"
460  "someaddress@somedomain.lan\r\n";
461  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
462 
463  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
464  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
465  "Content-Type: image/jpeg\r\n"
466  "\r\n";
467  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
468 
469  uint8_t httpbuf4[] = "filecontent\r\n"
470  "-----------------------------277531038314945--";
471  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
472 
473  TcpSession ssn;
474  HtpState *http_state = NULL;
476 
477  memset(&ssn, 0, sizeof(ssn));
478 
479  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
480  if (f == NULL)
481  goto end;
482  f->protoctx = &ssn;
483  f->proto = IPPROTO_TCP;
484  f->alproto = ALPROTO_HTTP;
485 
487 
488  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
489  FLOWLOCK_WRLOCK(f);
490  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
491  STREAM_TOSERVER | STREAM_START, httpbuf1,
492  httplen1);
493  if (r != 0) {
494  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
495  result = 0;
496  FLOWLOCK_UNLOCK(f);
497  goto end;
498  }
499  FLOWLOCK_UNLOCK(f);
500 
501  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
502  FLOWLOCK_WRLOCK(f);
503  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
504  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
505  if (r != 0) {
506  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
507  result = 0;
508  FLOWLOCK_UNLOCK(f);
509  goto end;
510  }
511  FLOWLOCK_UNLOCK(f);
512 
513  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
514  FLOWLOCK_WRLOCK(f);
515  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
516  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
517  if (r != 0) {
518  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
519  result = 0;
520  FLOWLOCK_UNLOCK(f);
521  goto end;
522  }
523  FLOWLOCK_UNLOCK(f);
524 
525  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
526  FLOWLOCK_WRLOCK(f);
527  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
528  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
529  if (r != 0) {
530  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
531  result = 0;
532  FLOWLOCK_UNLOCK(f);
533  goto end;
534  }
535  FLOWLOCK_UNLOCK(f);
536 
537  http_state = f->alstate;
538  if (http_state == NULL) {
539  printf("no http state: ");
540  result = 0;
541  goto end;
542  }
543 
544  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
545  if (tx == NULL) {
546  goto end;
547  }
548 
549  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
550  {
551  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
552  goto end;
553  }
554 
555  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
556  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
557  goto end;
558  }
559 
560  result = 1;
561 end:
562  if (alp_tctx != NULL)
563  AppLayerParserThreadCtxFree(alp_tctx);
565  UTHFreeFlow(f);
566  return result;
567 }
568 
569 static int HTPFileParserTest03(void)
570 {
571  int result = 0;
572  Flow *f = NULL;
573  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
574  "Host: www.server.lan\r\n"
575  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
576  "Content-Length: 337\r\n"
577  "\r\n";
578  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
579 
580  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
581  "Content-Disposition: form-data; name=\"email\"\r\n"
582  "\r\n"
583  "someaddress@somedomain.lan\r\n";
584  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
585 
586  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
587  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
588  "Content-Type: image/jpeg\r\n"
589  "\r\n";
590  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
591 
592  uint8_t httpbuf4[] = "file";
593  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
594 
595  uint8_t httpbuf5[] = "content\r\n";
596  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
597 
598  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
599  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
600 
601  TcpSession ssn;
602  HtpState *http_state = NULL;
604 
605  memset(&ssn, 0, sizeof(ssn));
606 
607  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
608  if (f == NULL)
609  goto end;
610  f->protoctx = &ssn;
611  f->proto = IPPROTO_TCP;
612  f->alproto = ALPROTO_HTTP;
613 
615 
616  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
617  FLOWLOCK_WRLOCK(f);
618  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
619  STREAM_TOSERVER | STREAM_START, httpbuf1,
620  httplen1);
621  if (r != 0) {
622  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
623  result = 0;
624  FLOWLOCK_UNLOCK(f);
625  goto end;
626  }
627  FLOWLOCK_UNLOCK(f);
628 
629  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
630  FLOWLOCK_WRLOCK(f);
631  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
632  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
633  if (r != 0) {
634  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
635  result = 0;
636  FLOWLOCK_UNLOCK(f);
637  goto end;
638  }
639  FLOWLOCK_UNLOCK(f);
640 
641  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
642  FLOWLOCK_WRLOCK(f);
643  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
644  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
645  if (r != 0) {
646  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
647  result = 0;
648  FLOWLOCK_UNLOCK(f);
649  goto end;
650  }
651  FLOWLOCK_UNLOCK(f);
652 
653  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
654  FLOWLOCK_WRLOCK(f);
655  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
656  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
657  if (r != 0) {
658  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
659  result = 0;
660  FLOWLOCK_UNLOCK(f);
661  goto end;
662  }
663  FLOWLOCK_UNLOCK(f);
664 
665  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
666  FLOWLOCK_WRLOCK(f);
667  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
668  STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
669  if (r != 0) {
670  printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
671  result = 0;
672  FLOWLOCK_UNLOCK(f);
673  goto end;
674  }
675  FLOWLOCK_UNLOCK(f);
676 
677  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
678  FLOWLOCK_WRLOCK(f);
679  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
680  STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
681  if (r != 0) {
682  printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
683  result = 0;
684  FLOWLOCK_UNLOCK(f);
685  goto end;
686  }
687  FLOWLOCK_UNLOCK(f);
688 
689  http_state = f->alstate;
690  if (http_state == NULL) {
691  printf("no http state: ");
692  result = 0;
693  goto end;
694  }
695 
696  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
697  if (tx == NULL) {
698  goto end;
699  }
700 
701  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
702  {
703  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
704  goto end;
705  }
706 
707  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
708  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
709  goto end;
710  }
711 
712  if (http_state->files_ts->head == NULL ||
713  FileDataSize(http_state->files_ts->head) != 11)
714  {
715  if (http_state->files_ts->head != NULL)
716  printf("filedata len not 11 but %"PRIu64": ",
717  FileDataSize(http_state->files_ts->head));
718  goto end;
719  }
720 
721  result = 1;
722 end:
723  if (alp_tctx != NULL)
724  AppLayerParserThreadCtxFree(alp_tctx);
726  UTHFreeFlow(f);
727  return result;
728 }
729 
730 static int HTPFileParserTest04(void)
731 {
732  int result = 0;
733  Flow *f = NULL;
734  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
735  "Host: www.server.lan\r\n"
736  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
737  "Content-Length: 373\r\n"
738  "\r\n";
739  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
740 
741  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
742  "Content-Disposition: form-data; name=\"email\"\r\n"
743  "\r\n"
744  "someaddress@somedomain.lan\r\n";
745  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
746 
747  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
748  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
749  "Content-Type: image/jpeg\r\n"
750  "\r\n";
751  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
752 
753  uint8_t httpbuf4[] = "file0123456789abcdefghijklmnopqrstuvwxyz";
754  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
755 
756  uint8_t httpbuf5[] = "content\r\n";
757  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
758 
759  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
760  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
761 
762  TcpSession ssn;
763  HtpState *http_state = NULL;
765 
766  memset(&ssn, 0, sizeof(ssn));
767 
768  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
769  if (f == NULL)
770  goto end;
771  f->protoctx = &ssn;
772  f->proto = IPPROTO_TCP;
773  f->alproto = ALPROTO_HTTP;
774 
776 
777  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
778  FLOWLOCK_WRLOCK(f);
779  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
780  STREAM_TOSERVER | STREAM_START, httpbuf1,
781  httplen1);
782  if (r != 0) {
783  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
784  result = 0;
785  FLOWLOCK_UNLOCK(f);
786  goto end;
787  }
788  FLOWLOCK_UNLOCK(f);
789 
790  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
791  FLOWLOCK_WRLOCK(f);
792  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
793  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
794  if (r != 0) {
795  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
796  result = 0;
797  FLOWLOCK_UNLOCK(f);
798  goto end;
799  }
800  FLOWLOCK_UNLOCK(f);
801 
802  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
803  FLOWLOCK_WRLOCK(f);
804  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
805  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
806  if (r != 0) {
807  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
808  result = 0;
809  FLOWLOCK_UNLOCK(f);
810  goto end;
811  }
812  FLOWLOCK_UNLOCK(f);
813 
814  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
815  FLOWLOCK_WRLOCK(f);
816  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
817  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
818  if (r != 0) {
819  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
820  result = 0;
821  FLOWLOCK_UNLOCK(f);
822  goto end;
823  }
824  FLOWLOCK_UNLOCK(f);
825 
826  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
827  FLOWLOCK_WRLOCK(f);
828  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
829  STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
830  if (r != 0) {
831  printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
832  result = 0;
833  FLOWLOCK_UNLOCK(f);
834  goto end;
835  }
836  FLOWLOCK_UNLOCK(f);
837 
838  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
839  FLOWLOCK_WRLOCK(f);
840  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
841  STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
842  if (r != 0) {
843  printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
844  result = 0;
845  FLOWLOCK_UNLOCK(f);
846  goto end;
847  }
848  FLOWLOCK_UNLOCK(f);
849 
850  http_state = f->alstate;
851  if (http_state == NULL) {
852  printf("no http state: ");
853  result = 0;
854  goto end;
855  }
856 
857  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
858  if (tx == NULL) {
859  goto end;
860  }
861 
862  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
863  {
864  printf("expected method POST, got %s: ", bstr_util_strdup_to_c(tx->request_method));
865  goto end;
866  }
867 
868  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
869  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
870  goto end;
871  }
872 
873  result = 1;
874 end:
875  if (alp_tctx != NULL)
876  AppLayerParserThreadCtxFree(alp_tctx);
878  UTHFreeFlow(f);
879  return result;
880 }
881 
882 static int HTPFileParserTest05(void)
883 {
884  int result = 0;
885  Flow *f = NULL;
886  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
887  "Host: www.server.lan\r\n"
888  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
889  "Content-Length: 544\r\n"
890  "\r\n"
891  "-----------------------------277531038314945\r\n"
892  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
893  "Content-Type: image/jpeg\r\n"
894  "\r\n"
895  "filecontent\r\n"
896  "-----------------------------277531038314945\r\n";
897  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
898  uint8_t httpbuf2[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
899  "Content-Type: image/jpeg\r\n"
900  "\r\n"
901  "FILECONTENT\r\n"
902  "-----------------------------277531038314945--";
903  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
904 
905  TcpSession ssn;
906  HtpState *http_state = NULL;
908 
909  memset(&ssn, 0, sizeof(ssn));
910 
911  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
912  if (f == NULL)
913  goto end;
914  f->protoctx = &ssn;
915  f->proto = IPPROTO_TCP;
916  f->alproto = ALPROTO_HTTP;
917 
919 
920  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
921  FLOWLOCK_WRLOCK(f);
922  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
923  STREAM_TOSERVER | STREAM_START, httpbuf1,
924  httplen1);
925  if (r != 0) {
926  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
927  result = 0;
928  FLOWLOCK_UNLOCK(f);
929  goto end;
930  }
931  FLOWLOCK_UNLOCK(f);
932 
933  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
934  FLOWLOCK_WRLOCK(f);
935  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
936  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
937  if (r != 0) {
938  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
939  result = 0;
940  FLOWLOCK_UNLOCK(f);
941  goto end;
942  }
943  FLOWLOCK_UNLOCK(f);
944 
945  http_state = f->alstate;
946  if (http_state == NULL) {
947  printf("no http state: ");
948  result = 0;
949  goto end;
950  }
951 
952  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
953  if (tx == NULL) {
954  goto end;
955  }
956 
957  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
958  {
959  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
960  goto end;
961  }
962 
963  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
964  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
965  goto end;
966  }
967 
968  if (http_state->files_ts->head == http_state->files_ts->tail)
969  goto end;
970 
971  if (http_state->files_ts->head->next != http_state->files_ts->tail)
972  goto end;
973 
974  if (StreamingBufferCompareRawData(http_state->files_ts->head->sb,
975  (uint8_t *)"filecontent", 11) != 1)
976  {
977  goto end;
978  }
979 
980  if (StreamingBufferCompareRawData(http_state->files_ts->tail->sb,
981  (uint8_t *)"FILECONTENT", 11) != 1)
982  {
983  goto end;
984  }
985 
986  result = 1;
987 end:
988  if (alp_tctx != NULL)
989  AppLayerParserThreadCtxFree(alp_tctx);
991  UTHFreeFlow(f);
992  return result;
993 }
994 
995 /** \test first multipart part contains file but doesn't end in first chunk */
996 static int HTPFileParserTest06(void)
997 {
998  int result = 0;
999  Flow *f = NULL;
1000  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1001  "Host: www.server.lan\r\n"
1002  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1003  "Content-Length: 544\r\n"
1004  "\r\n"
1005  "-----------------------------277531038314945\r\n"
1006  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1007  "Content-Type: image/jpeg\r\n"
1008  "\r\n"
1009  "filecontent\r\n"
1010  "-----------------------------27753103831494";
1011  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1012  uint8_t httpbuf2[] = "5\r\nContent-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
1013  "Content-Type: image/jpeg\r\n"
1014  "\r\n"
1015  "FILECONTENT\r\n"
1016  "-----------------------------277531038314945--";
1017  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1018 
1019  TcpSession ssn;
1020  HtpState *http_state = NULL;
1022 
1023  memset(&ssn, 0, sizeof(ssn));
1024 
1025  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1026  if (f == NULL)
1027  goto end;
1028  f->protoctx = &ssn;
1029  f->proto = IPPROTO_TCP;
1030  f->alproto = ALPROTO_HTTP;
1031 
1033 
1034  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
1035  FLOWLOCK_WRLOCK(f);
1036  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1037  STREAM_TOSERVER | STREAM_START, httpbuf1,
1038  httplen1);
1039  if (r != 0) {
1040  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1041  result = 0;
1042  FLOWLOCK_UNLOCK(f);
1043  goto end;
1044  }
1045  FLOWLOCK_UNLOCK(f);
1046 
1047  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1048  FLOWLOCK_WRLOCK(f);
1049  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1050  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1051  if (r != 0) {
1052  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1053  result = 0;
1054  FLOWLOCK_UNLOCK(f);
1055  goto end;
1056  }
1057  FLOWLOCK_UNLOCK(f);
1058 
1059  http_state = f->alstate;
1060  if (http_state == NULL) {
1061  printf("no http state: ");
1062  result = 0;
1063  goto end;
1064  }
1065 
1066  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
1067  if (tx == NULL) {
1068  goto end;
1069  }
1070 
1071  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
1072  {
1073  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
1074  goto end;
1075  }
1076 
1077  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
1078  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
1079  goto end;
1080  }
1081 
1082  if (http_state->files_ts->head == http_state->files_ts->tail)
1083  goto end;
1084 
1085  if (http_state->files_ts->head->next != http_state->files_ts->tail)
1086  goto end;
1087 
1088  if (StreamingBufferCompareRawData(http_state->files_ts->head->sb,
1089  (uint8_t *)"filecontent", 11) != 1)
1090  {
1091  goto end;
1092  }
1093 
1094  if (StreamingBufferCompareRawData(http_state->files_ts->tail->sb,
1095  (uint8_t *)"FILECONTENT", 11) != 1)
1096  {
1097  goto end;
1098  }
1099 
1100  result = 1;
1101 end:
1102  if (alp_tctx != NULL)
1103  AppLayerParserThreadCtxFree(alp_tctx);
1105  UTHFreeFlow(f);
1106  return result;
1107 }
1108 
1109 /** \test POST, but not multipart */
1110 static int HTPFileParserTest07(void)
1111 {
1112  int result = 0;
1113  Flow *f = NULL;
1114  uint8_t httpbuf1[] = "POST /filename HTTP/1.1\r\n"
1115  "Host: www.server.lan\r\n"
1116  "Content-Length: 11\r\n"
1117  "\r\n";
1118  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1119  uint8_t httpbuf2[] = "FILECONTENT";
1120  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1121 
1122  TcpSession ssn;
1123  HtpState *http_state = NULL;
1125 
1126  memset(&ssn, 0, sizeof(ssn));
1127 
1128  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1129  if (f == NULL)
1130  goto end;
1131  f->protoctx = &ssn;
1132  f->proto = IPPROTO_TCP;
1133  f->alproto = ALPROTO_HTTP;
1134 
1136 
1137  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
1138  FLOWLOCK_WRLOCK(f);
1139  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1140  STREAM_TOSERVER | STREAM_START, httpbuf1,
1141  httplen1);
1142  if (r != 0) {
1143  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1144  result = 0;
1145  FLOWLOCK_UNLOCK(f);
1146  goto end;
1147  }
1148  FLOWLOCK_UNLOCK(f);
1149 
1150  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1151  FLOWLOCK_WRLOCK(f);
1152  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1153  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1154  if (r != 0) {
1155  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1156  result = 0;
1157  FLOWLOCK_UNLOCK(f);
1158  goto end;
1159  }
1160  FLOWLOCK_UNLOCK(f);
1161 
1162  http_state = f->alstate;
1163  if (http_state == NULL) {
1164  printf("no http state: ");
1165  result = 0;
1166  goto end;
1167  }
1168 
1169  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
1170  if (tx == NULL) {
1171  goto end;
1172  }
1173 
1174  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
1175  {
1176  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
1177  goto end;
1178  }
1179 
1180  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
1181  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
1182  printf("state != FILE_STATE_CLOSED");
1183  goto end;
1184  }
1185 
1186  if (StreamingBufferCompareRawData(http_state->files_ts->tail->sb,
1187  (uint8_t *)"FILECONTENT", 11) != 1)
1188  {
1189  goto end;
1190  }
1191 
1192  result = 1;
1193 end:
1194  if (alp_tctx != NULL)
1195  AppLayerParserThreadCtxFree(alp_tctx);
1197  UTHFreeFlow(f);
1198  return result;
1199 }
1200 
1201 static int HTPFileParserTest08(void)
1202 {
1203  int result = 0;
1204  Flow *f = NULL;
1205  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1206  "Host: www.server.lan\r\n"
1207  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1208  "Content-Length: 215\r\n"
1209  "\r\n"
1210  "-----------------------------277531038314945\r\n"
1211  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1212  "Content-Type: image/jpeg\r\n";
1213 
1214  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1215  uint8_t httpbuf2[] = "filecontent\r\n\r\n"
1216  "-----------------------------277531038314945--";
1217  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1218 
1219  TcpSession ssn;
1221  HtpState *http_state = NULL;
1222  memset(&ssn, 0, sizeof(ssn));
1223 
1224  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1225  if (f == NULL)
1226  goto end;
1227  f->protoctx = &ssn;
1228  f->proto = IPPROTO_TCP;
1229  f->alproto = ALPROTO_HTTP;
1230 
1232 
1233  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1234  FLOWLOCK_WRLOCK(f);
1235  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1236  STREAM_TOSERVER | STREAM_START, httpbuf1,
1237  httplen1);
1238  if (r != 0) {
1239  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1240  result = 0;
1241  FLOWLOCK_UNLOCK(f);
1242  goto end;
1243  }
1244  FLOWLOCK_UNLOCK(f);
1245 
1246  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1247  FLOWLOCK_WRLOCK(f);
1248  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1249  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1250  if (r != 0) {
1251  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1252  result = 0;
1253  FLOWLOCK_UNLOCK(f);
1254  goto end;
1255  }
1256  FLOWLOCK_UNLOCK(f);
1257 
1258  http_state = f->alstate;
1259  if (http_state == NULL) {
1260  printf("no http state: ");
1261  result = 0;
1262  goto end;
1263  }
1264 
1265  FLOWLOCK_WRLOCK(f);
1266  AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
1267  if (decoder_events == NULL) {
1268  printf("no app events: ");
1269  FLOWLOCK_UNLOCK(f);
1270  goto end;
1271  }
1272  FLOWLOCK_UNLOCK(f);
1273 
1274  if (decoder_events->cnt != 2) {
1275  printf("expected 2 events: ");
1276  goto end;
1277  }
1278 
1279  result = 1;
1280 end:
1281  if (alp_tctx != NULL)
1282  AppLayerParserThreadCtxFree(alp_tctx);
1284  UTHFreeFlow(f);
1285  return result;
1286 }
1287 
1288 /** \test invalid header: Somereallylongheaderstr: has no value */
1289 static int HTPFileParserTest09(void)
1290 {
1291  int result = 0;
1292  Flow *f = NULL;
1293  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1294  "Host: www.server.lan\r\n"
1295  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1296  "Content-Length: 337\r\n"
1297  "\r\n";
1298  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1299 
1300  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
1301  "Content-Disposition: form-data; name=\"email\"\r\n"
1302  "\r\n"
1303  "someaddress@somedomain.lan\r\n";
1304  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1305 
1306  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
1307  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1308  "Somereallylongheaderstr:\r\n"
1309  "\r\n";
1310  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1311 
1312  uint8_t httpbuf4[] = "filecontent\r\n"
1313  "-----------------------------277531038314945--";
1314  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1315 
1316  TcpSession ssn;
1317  HtpState *http_state = NULL;
1319 
1320  memset(&ssn, 0, sizeof(ssn));
1321 
1322  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1323  if (f == NULL)
1324  goto end;
1325  f->protoctx = &ssn;
1326  f->proto = IPPROTO_TCP;
1327  f->alproto = ALPROTO_HTTP;
1328 
1330 
1331  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1332  FLOWLOCK_WRLOCK(f);
1333  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1334  STREAM_TOSERVER | STREAM_START, httpbuf1,
1335  httplen1);
1336  if (r != 0) {
1337  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1338  result = 0;
1339  FLOWLOCK_UNLOCK(f);
1340  goto end;
1341  }
1342  FLOWLOCK_UNLOCK(f);
1343 
1344  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1345  FLOWLOCK_WRLOCK(f);
1346  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1347  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1348  if (r != 0) {
1349  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1350  result = 0;
1351  FLOWLOCK_UNLOCK(f);
1352  goto end;
1353  }
1354  FLOWLOCK_UNLOCK(f);
1355 
1356  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1357  FLOWLOCK_WRLOCK(f);
1358  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1359  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1360  if (r != 0) {
1361  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1362  result = 0;
1363  FLOWLOCK_UNLOCK(f);
1364  goto end;
1365  }
1366  FLOWLOCK_UNLOCK(f);
1367 
1368  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1369  FLOWLOCK_WRLOCK(f);
1370  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1371  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1372  if (r != 0) {
1373  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
1374  result = 0;
1375  FLOWLOCK_UNLOCK(f);
1376  goto end;
1377  }
1378  FLOWLOCK_UNLOCK(f);
1379 
1380  http_state = f->alstate;
1381  if (http_state == NULL) {
1382  printf("no http state: ");
1383  result = 0;
1384  goto end;
1385  }
1386 
1387  FLOWLOCK_WRLOCK(f);
1388  AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
1389  if (decoder_events == NULL) {
1390  printf("no app events: ");
1391  FLOWLOCK_UNLOCK(f);
1392  goto end;
1393  }
1394  FLOWLOCK_UNLOCK(f);
1395 
1396  if (decoder_events->cnt != 1) {
1397  printf("expected 1 event: ");
1398  goto end;
1399  }
1400 
1401  result = 1;
1402 end:
1403  if (alp_tctx != NULL)
1404  AppLayerParserThreadCtxFree(alp_tctx);
1406  UTHFreeFlow(f);
1407  return result;
1408 }
1409 
1410 /** \test empty entries */
1411 static int HTPFileParserTest10(void)
1412 {
1413  int result = 0;
1414  Flow *f = NULL;
1415  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1416  "Host: www.server.lan\r\n"
1417  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1418  "Content-Length: 337\r\n"
1419  "\r\n";
1420  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1421 
1422  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
1423  "\r\n";
1424  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1425 
1426  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
1427  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1428  "Somereallylongheaderstr: with a good value\r\n"
1429  "\r\n";
1430  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1431 
1432  uint8_t httpbuf4[] = "filecontent\r\n"
1433  "-----------------------------277531038314945--";
1434  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1435 
1436  TcpSession ssn;
1437  HtpState *http_state = NULL;
1439 
1440  memset(&ssn, 0, sizeof(ssn));
1441 
1442  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1443  if (f == NULL)
1444  goto end;
1445  f->protoctx = &ssn;
1446  f->proto = IPPROTO_TCP;
1447  f->alproto = ALPROTO_HTTP;
1448 
1450 
1451  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1452  FLOWLOCK_WRLOCK(f);
1453  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1454  STREAM_TOSERVER | STREAM_START, httpbuf1,
1455  httplen1);
1456  if (r != 0) {
1457  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1458  result = 0;
1459  FLOWLOCK_UNLOCK(f);
1460  goto end;
1461  }
1462  FLOWLOCK_UNLOCK(f);
1463 
1464  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1465  FLOWLOCK_WRLOCK(f);
1466  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1467  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1468  if (r != 0) {
1469  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1470  result = 0;
1471  FLOWLOCK_UNLOCK(f);
1472  goto end;
1473  }
1474  FLOWLOCK_UNLOCK(f);
1475 
1476  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1477  FLOWLOCK_WRLOCK(f);
1478  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1479  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1480  if (r != 0) {
1481  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1482  result = 0;
1483  FLOWLOCK_UNLOCK(f);
1484  goto end;
1485  }
1486  FLOWLOCK_UNLOCK(f);
1487 
1488  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1489  FLOWLOCK_WRLOCK(f);
1490  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1491  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1492  if (r != 0) {
1493  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
1494  result = 0;
1495  FLOWLOCK_UNLOCK(f);
1496  goto end;
1497  }
1498  FLOWLOCK_UNLOCK(f);
1499 
1500  http_state = f->alstate;
1501  if (http_state == NULL) {
1502  printf("no http state: ");
1503  result = 0;
1504  goto end;
1505  }
1506 
1507  FLOWLOCK_WRLOCK(f);
1508  AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
1509  if (decoder_events != NULL) {
1510  printf("app events: ");
1511  FLOWLOCK_UNLOCK(f);
1512  goto end;
1513  }
1514  FLOWLOCK_UNLOCK(f);
1515 
1516  result = 1;
1517 end:
1518  if (alp_tctx != NULL)
1519  AppLayerParserThreadCtxFree(alp_tctx);
1521  UTHFreeFlow(f);
1522  return result;
1523 }
1524 
1525 /** \test filedata cut in two pieces */
1526 static int HTPFileParserTest11(void)
1527 {
1528  int result = 0;
1529  Flow *f = NULL;
1530  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1531  "Host: www.server.lan\r\n"
1532  "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1533  "Content-Length: 1102\r\n"
1534  "\r\n";
1535  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1536 
1537  uint8_t httpbuf2[] = "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n";
1538  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1539 
1540  uint8_t httpbuf3[] = "Content-Disposition: form-data; name=\"PROGRESS_URL\"\r\n"
1541  "\r\n"
1542  "http://somserver.com/progress.php?UPLOAD_IDENTIFIER=XXXXXXXXX.XXXXXXXXXX.XXXXXXXX.XX.X\r\n"
1543  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1544  "Content-Disposition: form-data; name=\"DESTINATION_DIR\"\r\n"
1545  "\r\n"
1546  "10\r\n"
1547  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1548  "Content-Disposition: form-data; name=\"js_enabled\"\r\n"
1549  "\r\n"
1550  "1"
1551  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1552  "Content-Disposition: form-data; name=\"signature\"\r\n"
1553  "\r\n"
1554  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"
1555  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1556  "Content-Disposition: form-data; name=\"upload_files\"\r\n"
1557  "\r\n"
1558  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1559  "Content-Disposition: form-data; name=\"terms\"\r\n"
1560  "\r\n"
1561  "1"
1562  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1563  "Content-Disposition: form-data; name=\"file[]\"\r\n"
1564  "\r\n"
1565  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1566  "Content-Disposition: form-data; name=\"description[]\"\r\n"
1567  "\r\n"
1568  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1569  "Content-Disposition: form-data; name=\"upload_file[]\"; filename=\"filename.doc\"\r\n"
1570  "Content-Type: application/msword\r\n"
1571  "\r\n"
1572  "FILE";
1573  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1574 
1575  uint8_t httpbuf4[] = "CONTENT\r\n"
1576  "------WebKitFormBoundaryBRDbP74mBhBxsIdo--";
1577  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1578 
1579  TcpSession ssn;
1580  HtpState *http_state = NULL;
1582 
1583  memset(&ssn, 0, sizeof(ssn));
1584 
1585  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1586  if (f == NULL)
1587  goto end;
1588  f->protoctx = &ssn;
1589  f->proto = IPPROTO_TCP;
1590  f->alproto = ALPROTO_HTTP;
1591 
1593 
1594  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1595  FLOWLOCK_WRLOCK(f);
1596  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1597  STREAM_TOSERVER | STREAM_START, httpbuf1,
1598  httplen1);
1599  if (r != 0) {
1600  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1601  FLOWLOCK_UNLOCK(f);
1602  goto end;
1603  }
1604  FLOWLOCK_UNLOCK(f);
1605 
1606  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1607  FLOWLOCK_WRLOCK(f);
1608  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
1609  httpbuf2, httplen2);
1610  if (r != 0) {
1611  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1612  FLOWLOCK_UNLOCK(f);
1613  goto end;
1614  }
1615  FLOWLOCK_UNLOCK(f);
1616 
1617  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1618  FLOWLOCK_WRLOCK(f);
1619  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
1620  httpbuf3, httplen3);
1621  if (r != 0) {
1622  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1623  FLOWLOCK_UNLOCK(f);
1624  goto end;
1625  }
1626  FLOWLOCK_UNLOCK(f);
1627 
1628  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1629  FLOWLOCK_WRLOCK(f);
1630  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1631  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1632  if (r != 0) {
1633  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
1634  FLOWLOCK_UNLOCK(f);
1635  goto end;
1636  }
1637  FLOWLOCK_UNLOCK(f);
1638 
1639  http_state = f->alstate;
1640  if (http_state == NULL) {
1641  printf("no http state: ");
1642  goto end;
1643  }
1644 
1645  FLOWLOCK_WRLOCK(f);
1646  AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
1647  if (decoder_events != NULL) {
1648  printf("app events: ");
1649  FLOWLOCK_UNLOCK(f);
1650  goto end;
1651  }
1652  FLOWLOCK_UNLOCK(f);
1653 
1654  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
1655  if (tx == NULL) {
1656  goto end;
1657  }
1658 
1659  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
1660  {
1661  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
1662  goto end;
1663  }
1664 
1665  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
1666  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
1667  printf("state != FILE_STATE_CLOSED: ");
1668  goto end;
1669  }
1670 
1671  if (StreamingBufferCompareRawData(http_state->files_ts->head->sb,
1672  (uint8_t *)"FILECONTENT", 11) != 1)
1673  {
1674  goto end;
1675  }
1676 
1677  result = 1;
1678 end:
1679  if (alp_tctx != NULL)
1680  AppLayerParserThreadCtxFree(alp_tctx);
1682  UTHFreeFlow(f);
1683  return result;
1684 }
1685 
1686 #endif /* UNITTESTS */
1687 
1689 {
1690 #ifdef UNITTESTS
1691  UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01);
1692  UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02);
1693  UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03);
1694  UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04);
1695  UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05);
1696  UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06);
1697  UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07);
1698  UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08);
1699  UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09);
1700  UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10);
1701  UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11);
1702 #endif /* UNITTESTS */
1703 }
uint16_t flags
int StreamingBufferCompareRawData(const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len)
#define SCLogDebug(...)
Definition: util-debug.h:335
uint16_t flags
uint8_t proto
Definition: flow.h:343
FileContainer * FileContainerAlloc(void)
allocate a FileContainer
Definition: util-file.c:380
HTPCfgDir response
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:242
const struct HTPCfgRec_ * cfg
uint64_t FileDataSize(const File *file)
get the size of the file data
Definition: util-file.c:277
int HTPFileClose(HtpState *s, const uint8_t *data, uint32_t data_len, uint8_t flags, uint8_t direction)
Close the file in the flow.
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
File * FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, uint16_t flags)
Open a new File.
Definition: util-file.c:778
void StreamTcpFreeConfig(char quiet)
Definition: stream-tcp.c:669
#define HTP_FLAG_STORE_FILES_TX_TC
Definition: app-layer-htp.h:70
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:239
#define HTP_FLAG_STORE_FILES_TX_TS
Definition: app-layer-htp.h:69
#define FILE_STORE
Definition: util-file.h:46
struct File_ * next
Definition: util-file.h:79
#define TRUE
void * protoctx
Definition: flow.h:395
StreamingBuffer * sb
Definition: util-file.h:68
void * alstate
Definition: flow.h:433
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
AppLayerDecoderEvents * AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
Data structure to store app layer decoder events.
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
HTPCfgDir request
Data structures and function prototypes for keeping state for the detection engine.
#define STREAM_EOF
Definition: stream.h:30
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define SCEnter(...)
Definition: util-debug.h:337
void StreamTcpInitConfig(char)
To initialize the stream global configuration data.
Definition: stream-tcp.c:365
int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end)
Sets the offset range for a file.
Definition: util-file.c:751
#define STREAM_TOCLIENT
Definition: stream.h:32
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol&#39;s parser thread context.
#define HTP_FLAG_STORE_FILES_TC
Definition: app-layer-htp.h:68
#define SCReturnInt(x)
Definition: util-debug.h:341
void FilePrune(FileContainer *ffc)
Definition: util-file.c:345
int HTPParseContentRange(bstr *rawvalue, HtpContentRange *range)
int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, const uint8_t *data, uint32_t data_len, uint64_t txid, uint8_t direction)
Open the file with "filename" and pass the first chunk of data if any.
int HTPFileStoreChunk(HtpState *s, const uint8_t *data, uint32_t data_len, uint8_t direction)
Store a chunk of data in the flow.
FileContainer * files_ts
StreamingBufferConfig sbcfg
FileContainer * files_tc
#define FLOWFILE_NO_STORE_TS
Definition: flow.h:114
#define STREAM_START
Definition: stream.h:29
#define STREAM_TOSERVER
Definition: stream.h:31
FileState state
Definition: util-file.h:67
int FileCloseFile(FileContainer *ffc, const uint8_t *data, uint32_t data_len, uint16_t flags)
Close a File.
Definition: util-file.c:963
int FileSetTx(File *ff, uint64_t txid)
Set the TX id for a file.
Definition: util-file.c:523
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition: util-file.c:217
uint64_t store_tx_id
void HTPFileParserRegisterTests(void)
uint8_t len
uint16_t file_flags
Definition: flow.h:376
AppProto alproto
application level protocol
Definition: flow.h:404
int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len)
Store/handle a chunk of file data in the File structure The last file in the FileContainer will be us...
Definition: util-file.c:663
#define HTP_FLAG_STORE_FILES_TS
Definition: app-layer-htp.h:67
#define FILE_NOSTORE
Definition: util-file.h:45
#define FLOWFILE_NO_STORE_TC
Definition: flow.h:115
Flow data structure.
Definition: flow.h:324
int HTPFileSetRange(HtpState *s, bstr *rawvalue)
Sets range for a file.
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)