suricata
app-layer-htp-file.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  * \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 "util-validate.h"
31 #include "decode.h"
32 #include "threads.h"
33 
34 #include "util-print.h"
35 #include "util-pool.h"
36 #include "util-radix-tree.h"
37 
38 #include "stream-tcp-private.h"
39 #include "stream-tcp-reassemble.h"
40 #include "stream-tcp.h"
41 #include "stream.h"
42 
43 #include "app-layer.h"
44 #include "app-layer-protos.h"
45 #include "app-layer-parser.h"
46 #include "app-layer-htp.h"
47 #include "app-layer-htp-file.h"
48 
49 #include "util-spm.h"
50 #include "util-debug.h"
51 #include "util-time.h"
52 
53 #include "util-unittest.h"
54 #include "util-unittest-helper.h"
55 #include "flow-util.h"
56 
57 #include "detect-engine.h"
58 #include "detect-engine-state.h"
59 #include "detect-parse.h"
60 
61 #include "conf.h"
62 
63 #include "util-memcmp.h"
64 
65 /**
66  * \brief Open the file with "filename" and pass the first chunk
67  * of data if any.
68  *
69  * \param s http state
70  * \param filename name of the file
71  * \param filename_len length of the name
72  * \param data data chunk (if any)
73  * \param data_len length of the data portion
74  * \param direction flow direction
75  *
76  * \retval 0 ok
77  * \retval -1 error
78  * \retval -2 not handling files on this flow
79  */
80 int HTPFileOpen(HtpState *s, HtpTxUserData *tx, const uint8_t *filename, uint16_t filename_len,
81  const uint8_t *data, uint32_t data_len, 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  // we shall not open a new file if there is a current one
118  DEBUG_VALIDATE_BUG_ON(s->file_range != NULL);
119  } else {
120  if (s->files_ts == NULL) {
122  if (s->files_ts == NULL) {
123  retval = -1;
124  goto end;
125  }
126  }
127 
128  files = s->files_ts;
129 
130  flags = FileFlowToFlags(s->f, STREAM_TOSERVER);
131  if ((s->flags & HTP_FLAG_STORE_FILES_TC) ||
132  ((s->flags & HTP_FLAG_STORE_FILES_TX_TC) && txid == s->store_tx_id)) {
133  flags |= FILE_STORE;
134  flags &= ~FILE_NOSTORE;
135  } else if (!(flags & FILE_STORE) && (s->f->file_flags & FLOWFILE_NO_STORE_TS)) {
136  flags |= FILE_NOSTORE;
137  }
138 
139  sbcfg = &s->cfg->request.sbcfg;
140  }
141 
142  if (FileOpenFileWithId(files, sbcfg, s->file_track_id++,
143  filename, filename_len,
144  data, data_len, flags) != 0)
145  {
146  retval = -1;
147  }
148 
149  FileSetTx(files->tail, txid);
150  tx->tx_data.files_opened++;
151 
152 end:
153  SCReturnInt(retval);
154 }
155 
156 /**
157  * Performs parsing of the content-range value
158  *
159  * @param[in] rawvalue
160  * @param[out] range
161  *
162  * @return HTP_OK on success, HTP_ERROR on failure.
163  */
164 int HTPParseContentRange(bstr *rawvalue, HTTPContentRange *range)
165 {
166  uint32_t len = bstr_len(rawvalue);
167  return rs_http_parse_content_range(range, bstr_ptr(rawvalue), len);
168 }
169 
170 /**
171  * Performs parsing + checking of the content-range value
172  *
173  * @param[in] rawvalue
174  * @param[out] range
175  *
176  * @return HTP_OK on success, HTP_ERROR, -2, -3 on failure.
177  */
178 static int HTPParseAndCheckContentRange(
179  bstr *rawvalue, HTTPContentRange *range, HtpState *s, HtpTxUserData *htud)
180 {
181  int r = HTPParseContentRange(rawvalue, range);
182  if (r != 0) {
184  s->events++;
185  SCLogDebug("parsing range failed, going back to normal file");
186  return r;
187  }
188  /* crparsed.end <= 0 means a range with only size
189  * this is the answer to an unsatisfied range with the whole file
190  * crparsed.size <= 0 means an unknown size, so we do not know
191  * when to close it...
192  */
193  if (range->end <= 0 || range->size <= 0) {
194  SCLogDebug("range without all information");
195  return -2;
196  } else if (range->end == range->size - 1 && range->start == 0) {
197  SCLogDebug("range without all information");
198  return -3;
199  } else if (range->start > range->end || range->end > range->size - 1) {
201  s->events++;
202  SCLogDebug("invalid range");
203  return -4;
204  }
205  return r;
206 }
207 
208 /**
209  * \brief Sets range for a file
210  *
211  * \param s http state
212  * \param rawvalue raw header value
213  *
214  * \retval 0 ok
215  * \retval -1 error
216  */
217 int HTPFileOpenWithRange(HtpState *s, HtpTxUserData *txud, const uint8_t *filename,
218  uint16_t filename_len, const uint8_t *data, uint32_t data_len, uint64_t txid,
219  bstr *rawvalue, HtpTxUserData *htud)
220 {
221  SCEnter();
222  uint16_t flags;
223 
224  DEBUG_VALIDATE_BUG_ON(s == NULL);
225 
226  // This function is only called STREAM_TOCLIENT from HtpResponseBodyHandle
227  HTTPContentRange crparsed;
228  if (HTPParseAndCheckContentRange(rawvalue, &crparsed, s, htud) != 0) {
229  // range is invalid, fall back to classic open
230  return HTPFileOpen(s, txud, filename, filename_len, data, data_len, txid, STREAM_TOCLIENT);
231  }
232  flags = FileFlowToFlags(s->f, STREAM_TOCLIENT);
233  if ((s->flags & HTP_FLAG_STORE_FILES_TS) ||
234  ((s->flags & HTP_FLAG_STORE_FILES_TX_TS) && txid == s->store_tx_id)) {
235  flags |= FILE_STORE;
236  flags &= ~FILE_NOSTORE;
237  } else if (!(flags & FILE_STORE) && (s->f->file_flags & FLOWFILE_NO_STORE_TC)) {
238  flags |= FILE_NOSTORE;
239  }
240 
241  FileContainer * files = s->files_tc;
242  if (files == NULL) {
244  if (s->files_tc == NULL) {
245  // no need to fall back to classic open if we cannot allocate the file container
246  SCReturnInt(-1);
247  }
248  files = s->files_tc;
249  }
250 
251  // we open a file for this specific range
252  if (FileOpenFileWithId(files, &s->cfg->response.sbcfg, s->file_track_id++, filename,
253  filename_len, data, data_len, flags) != 0) {
254  SCReturnInt(-1);
255  }
256  FileSetTx(files->tail, txid);
257  txud->tx_data.files_opened++;
258 
259  if (FileSetRange(files, crparsed.start, crparsed.end) < 0) {
260  SCLogDebug("set range failed");
261  }
262 
263  // Then, we will try to handle reassembly of different ranges of the same file
264  htp_tx_t *tx = htp_list_get(s->conn->transactions, txid);
265  if (!tx) {
266  SCReturnInt(-1);
267  }
268  uint8_t *keyurl;
269  uint32_t keylen;
270  if (tx->request_hostname != NULL) {
271  keylen = bstr_len(tx->request_hostname) + filename_len;
272  keyurl = SCMalloc(keylen);
273  if (keyurl == NULL) {
274  SCReturnInt(-1);
275  }
276  memcpy(keyurl, bstr_ptr(tx->request_hostname), bstr_len(tx->request_hostname));
277  memcpy(keyurl + bstr_len(tx->request_hostname), filename, filename_len);
278  } else {
279  // do not reassemble file without host info
280  SCReturnInt(0);
281  }
283  s->file_range = HttpRangeContainerOpenFile(keyurl, keylen, s->f, &crparsed,
284  &s->cfg->response.sbcfg, filename, filename_len, flags, data, data_len);
285  SCFree(keyurl);
286  if (s->file_range == NULL) {
287  SCReturnInt(-1);
288  }
289  SCReturnInt(0);
290 }
291 
292 /**
293  * \brief Store a chunk of data in the flow
294  *
295  * \param s http state
296  * \param data data chunk (if any)
297  * \param data_len length of the data portion
298  * \param direction flow direction
299  *
300  * \retval 0 ok
301  * \retval -1 error
302  * \retval -2 file doesn't need storing
303  */
304 int HTPFileStoreChunk(HtpState *s, const uint8_t *data, uint32_t data_len,
305  uint8_t direction)
306 {
307  SCEnter();
308 
309  int retval = 0;
310  int result = 0;
311  FileContainer *files = NULL;
312 
313  if (s == NULL) {
314  SCReturnInt(-1);
315  }
316 
317  if (direction & STREAM_TOCLIENT) {
318  files = s->files_tc;
319  } else {
320  files = s->files_ts;
321  }
322 
323  if (files == NULL) {
324  SCLogDebug("no files in state");
325  retval = -1;
326  goto end;
327  }
328 
329  if (s->file_range != NULL) {
330  if (HttpRangeAppendData(s->file_range, data, data_len) < 0) {
331  SCLogDebug("Failed to append data");
332  }
333  }
334 
335  result = FileAppendData(files, data, data_len);
336  if (result == -1) {
337  SCLogDebug("appending data failed");
338  retval = -1;
339  } else if (result == -2) {
340  retval = -2;
341  }
342 
343 end:
344  SCReturnInt(retval);
345 }
346 
347 /** \brief close range, add reassembled file if possible
348  * \retval true if reassembled file was added
349  * \retval false if no reassembled file was added
350  */
352  const uint8_t *data, uint32_t data_len)
353 {
354  bool added = false;
355  if (HttpRangeAppendData(c, data, data_len) < 0) {
356  SCLogDebug("Failed to append data");
357  }
358  if (c->container) {
359  // we only call HttpRangeClose if we may some new data
360  // ie we do not call it if we skipped all this range request
361  THashDataLock(c->container->hdata);
362  if (c->container->error) {
363  SCLogDebug("range in ERROR state");
364  }
365  File *ranged = HttpRangeClose(c, flags);
366  if (ranged && files) {
367  /* HtpState owns the constructed file now */
368  FileContainerAdd(files, ranged);
369  added = true;
370  }
371  DEBUG_VALIDATE_BUG_ON(ranged && !files);
372  THashDataUnlock(c->container->hdata);
373  }
374  return added;
375 }
376 
377 /**
378  * \brief Close the file in the flow
379  *
380  * \param s http state
381  * \param data data chunk if any
382  * \param data_len length of the data portion
383  * \param flags flags to indicate events
384  * \param direction flow direction
385  *
386  * Currently on the FLOW_FILE_TRUNCATED flag is implemented, indicating
387  * that the file isn't complete but we're stopping storing it.
388  *
389  * \retval 0 ok
390  * \retval -1 error
391  * \retval -2 not storing files on this flow/tx
392  */
393 int HTPFileClose(HtpState *s, HtpTxUserData *htud, const uint8_t *data, uint32_t data_len,
394  uint8_t flags, uint8_t direction)
395 {
396  SCEnter();
397 
398  int retval = 0;
399  int result = 0;
400  FileContainer *files = NULL;
401 
402  if (s == NULL) {
403  SCReturnInt(-1);
404  }
405 
406  if (direction & STREAM_TOCLIENT) {
407  files = s->files_tc;
408  } else {
409  files = s->files_ts;
410  }
411 
412  if (files == NULL) {
413  retval = -1;
414  goto end;
415  }
416 
417  result = FileCloseFile(files, data, data_len, flags);
418  if (result == -1) {
419  retval = -1;
420  } else if (result == -2) {
421  retval = -2;
422  }
423 
424  if (s->file_range != NULL) {
425  bool added = HTPFileCloseHandleRange(files, flags, s->file_range, data, data_len);
426  if (added) {
427  htud->tx_data.files_opened++;
428  }
430  s->file_range = NULL;
431  }
432 
433 end:
434  SCReturnInt(retval);
435 }
436 
437 #ifdef UNITTESTS
438 static int HTPFileParserTest01(void)
439 {
440  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
441  "Host: www.server.lan\r\n"
442  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
443  "Content-Length: 215\r\n"
444  "\r\n"
445  "-----------------------------277531038314945\r\n"
446  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
447  "Content-Type: image/jpeg\r\n"
448  "\r\n";
449 
450  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
451  uint8_t httpbuf2[] = "filecontent\r\n"
452  "-----------------------------277531038314945--";
453  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
454 
455  TcpSession ssn;
457  HtpState *http_state = NULL;
458  memset(&ssn, 0, sizeof(ssn));
459 
460  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
461  FAIL_IF_NULL(f);
462  f->protoctx = &ssn;
463  f->proto = IPPROTO_TCP;
464  f->alproto = ALPROTO_HTTP1;
465 
466  StreamTcpInitConfig(true);
467 
468  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
469  int r = AppLayerParserParse(
470  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
471  FAIL_IF_NOT(r == 0);
472 
473  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
475  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
476  FAIL_IF_NOT(r == 0);
477 
478  http_state = f->alstate;
479  FAIL_IF_NULL(http_state);
480 
481  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
482  FAIL_IF_NULL(tx);
483  FAIL_IF_NULL(tx->request_method);
484 
485  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
486 
488  StreamTcpFreeConfig(true);
489  UTHFreeFlow(f);
490  PASS;
491 }
492 
493 static int HTPFileParserTest02(void)
494 {
495  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
496  "Host: www.server.lan\r\n"
497  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
498  "Content-Length: 337\r\n"
499  "\r\n";
500  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
501 
502  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
503  "Content-Disposition: form-data; name=\"email\"\r\n"
504  "\r\n"
505  "someaddress@somedomain.lan\r\n";
506  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
507 
508  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
509  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
510  "Content-Type: image/jpeg\r\n"
511  "\r\n";
512  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
513 
514  uint8_t httpbuf4[] = "filecontent\r\n"
515  "-----------------------------277531038314945--";
516  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
517 
518  TcpSession ssn;
519  HtpState *http_state = NULL;
521 
522  memset(&ssn, 0, sizeof(ssn));
523 
524  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
525  FAIL_IF_NULL(f);
526  f->protoctx = &ssn;
527  f->proto = IPPROTO_TCP;
528  f->alproto = ALPROTO_HTTP1;
529 
530  StreamTcpInitConfig(true);
531 
532  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
533  int r = AppLayerParserParse(
534  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
535  FAIL_IF_NOT(r == 0);
536 
537  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
539  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
540  FAIL_IF_NOT(r == 0);
541 
542  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
544  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
545  FAIL_IF_NOT(r == 0);
546 
547  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
549  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
550  FAIL_IF_NOT(r == 0);
551 
552  http_state = f->alstate;
553  FAIL_IF_NULL(http_state);
554 
555  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
556  FAIL_IF_NULL(tx);
557  FAIL_IF_NULL(tx->request_method);
558  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
559  FAIL_IF_NULL(http_state->files_ts);
560  FAIL_IF_NULL(http_state->files_ts->tail);
561  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
562 
564  StreamTcpFreeConfig(true);
565  UTHFreeFlow(f);
566  PASS;
567 }
568 
569 static int HTPFileParserTest03(void)
570 {
571  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
572  "Host: www.server.lan\r\n"
573  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
574  "Content-Length: 337\r\n"
575  "\r\n";
576  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
577 
578  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
579  "Content-Disposition: form-data; name=\"email\"\r\n"
580  "\r\n"
581  "someaddress@somedomain.lan\r\n";
582  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
583 
584  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
585  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
586  "Content-Type: image/jpeg\r\n"
587  "\r\n";
588  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
589 
590  uint8_t httpbuf4[] = "file";
591  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
592 
593  uint8_t httpbuf5[] = "content\r\n";
594  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
595 
596  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
597  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
598 
599  TcpSession ssn;
600  HtpState *http_state = NULL;
602 
603  memset(&ssn, 0, sizeof(ssn));
604 
605  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
606  FAIL_IF_NULL(f);
607  f->protoctx = &ssn;
608  f->proto = IPPROTO_TCP;
609  f->alproto = ALPROTO_HTTP1;
610 
611  StreamTcpInitConfig(true);
612 
613  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
614  int r = AppLayerParserParse(
615  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
616  FAIL_IF_NOT(r == 0);
617 
618  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
620  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
621  FAIL_IF_NOT(r == 0);
622 
623  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
625  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
626  FAIL_IF_NOT(r == 0);
627 
628  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
630  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
631  FAIL_IF_NOT(r == 0);
632 
633  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
635  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
636  FAIL_IF_NOT(r == 0);
637 
638  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
640  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
641  FAIL_IF_NOT(r == 0);
642 
643  http_state = f->alstate;
644  FAIL_IF_NULL(http_state);
645 
646  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
647  FAIL_IF_NULL(tx);
648  FAIL_IF_NULL(tx->request_method);
649 
650  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
651 
652  FAIL_IF_NULL(http_state->files_ts);
653  FAIL_IF_NULL(http_state->files_ts->head);
654  FAIL_IF_NULL(http_state->files_ts->tail);
655  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
656  FAIL_IF(FileDataSize(http_state->files_ts->head) != 11);
657 
659  StreamTcpFreeConfig(true);
660  UTHFreeFlow(f);
661  PASS;
662 }
663 
664 static int HTPFileParserTest04(void)
665 {
666  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
667  "Host: www.server.lan\r\n"
668  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
669  "Content-Length: 373\r\n"
670  "\r\n";
671  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
672 
673  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
674  "Content-Disposition: form-data; name=\"email\"\r\n"
675  "\r\n"
676  "someaddress@somedomain.lan\r\n";
677  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
678 
679  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
680  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
681  "Content-Type: image/jpeg\r\n"
682  "\r\n";
683  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
684 
685  uint8_t httpbuf4[] = "file0123456789abcdefghijklmnopqrstuvwxyz";
686  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
687 
688  uint8_t httpbuf5[] = "content\r\n";
689  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
690 
691  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
692  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
693 
694  TcpSession ssn;
695  HtpState *http_state = NULL;
697 
698  memset(&ssn, 0, sizeof(ssn));
699 
700  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
701  FAIL_IF_NULL(f);
702  f->protoctx = &ssn;
703  f->proto = IPPROTO_TCP;
704  f->alproto = ALPROTO_HTTP1;
705 
706  StreamTcpInitConfig(true);
707 
708  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
709  int r = AppLayerParserParse(
710  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
711  FAIL_IF_NOT(r == 0);
712 
713  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
715  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
716  FAIL_IF_NOT(r == 0);
717 
718  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
720  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
721  FAIL_IF_NOT(r == 0);
722 
723  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
725  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
726  FAIL_IF_NOT(r == 0);
727 
728  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
730  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
731  FAIL_IF_NOT(r == 0);
732 
733  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
735  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
736  FAIL_IF_NOT(r == 0);
737 
738  http_state = f->alstate;
739  FAIL_IF_NULL(http_state);
740 
741  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
742  FAIL_IF_NULL(tx);
743  FAIL_IF_NULL(tx->request_method);
744 
745  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
746 
747  FAIL_IF_NULL(http_state->files_ts);
748  FAIL_IF_NULL(http_state->files_ts->head);
749  FAIL_IF_NULL(http_state->files_ts->tail);
750  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
751 
753  StreamTcpFreeConfig(true);
754  UTHFreeFlow(f);
755  PASS;
756 }
757 
758 static int HTPFileParserTest05(void)
759 {
760  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
761  "Host: www.server.lan\r\n"
762  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
763  "Content-Length: 544\r\n"
764  "\r\n"
765  "-----------------------------277531038314945\r\n"
766  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
767  "Content-Type: image/jpeg\r\n"
768  "\r\n"
769  "filecontent\r\n"
770  "-----------------------------277531038314945\r\n";
771  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
772  uint8_t httpbuf2[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
773  "Content-Type: image/jpeg\r\n"
774  "\r\n"
775  "FILECONTENT\r\n"
776  "-----------------------------277531038314945--";
777  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
778 
779  TcpSession ssn;
780  HtpState *http_state = NULL;
782 
783  memset(&ssn, 0, sizeof(ssn));
784 
785  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
786  FAIL_IF_NULL(f);
787  f->protoctx = &ssn;
788  f->proto = IPPROTO_TCP;
789  f->alproto = ALPROTO_HTTP1;
790 
791  StreamTcpInitConfig(true);
792 
793  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
794  int r = AppLayerParserParse(
795  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
796  FAIL_IF_NOT(r == 0);
797 
798  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
800  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
801  FAIL_IF_NOT(r == 0);
802 
803  http_state = f->alstate;
804  FAIL_IF_NULL(http_state);
805 
806  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
807  FAIL_IF_NULL(tx);
808  FAIL_IF_NULL(tx->request_method);
809 
810  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
811 
812  FAIL_IF_NULL(http_state->files_ts);
813  FAIL_IF_NULL(http_state->files_ts->head);
814  FAIL_IF_NULL(http_state->files_ts->tail);
815  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
816 
817  FAIL_IF(http_state->files_ts->head == http_state->files_ts->tail);
818  FAIL_IF(http_state->files_ts->head->next != http_state->files_ts->tail);
819 
821  (uint8_t *)"filecontent", 11) != 1);
822 
824  (uint8_t *)"FILECONTENT", 11) != 1);
826  StreamTcpFreeConfig(true);
827  UTHFreeFlow(f);
828  PASS;
829 }
830 
831 /** \test first multipart part contains file but doesn't end in first chunk */
832 static int HTPFileParserTest06(void)
833 {
834  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
835  "Host: www.server.lan\r\n"
836  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
837  "Content-Length: 544\r\n"
838  "\r\n"
839  "-----------------------------277531038314945\r\n"
840  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
841  "Content-Type: image/jpeg\r\n"
842  "\r\n"
843  "filecontent\r\n"
844  "-----------------------------27753103831494";
845  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
846  uint8_t httpbuf2[] = "5\r\nContent-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
847  "Content-Type: image/jpeg\r\n"
848  "\r\n"
849  "FILECONTENT\r\n"
850  "-----------------------------277531038314945--";
851  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
852 
853  TcpSession ssn;
854  HtpState *http_state = NULL;
856 
857  memset(&ssn, 0, sizeof(ssn));
858 
859  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
860  FAIL_IF_NULL(f);
861  f->protoctx = &ssn;
862  f->proto = IPPROTO_TCP;
863  f->alproto = ALPROTO_HTTP1;
864 
865  StreamTcpInitConfig(true);
866 
867  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
868  int r = AppLayerParserParse(
869  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
870  FAIL_IF_NOT(r == 0);
871 
872  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
874  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
875  FAIL_IF_NOT(r == 0);
876 
877  http_state = f->alstate;
878  FAIL_IF_NULL(http_state);
879 
880  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
881  FAIL_IF_NULL(tx);
882  FAIL_IF_NULL(tx->request_method);
883 
884  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
885 
886  FAIL_IF_NULL(http_state->files_ts);
887  FAIL_IF_NULL(http_state->files_ts->head);
888  FAIL_IF_NULL(http_state->files_ts->tail);
889  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
890 
891  FAIL_IF(http_state->files_ts->head == http_state->files_ts->tail);
892  FAIL_IF(http_state->files_ts->head->next != http_state->files_ts->tail);
893 
895  (uint8_t *)"filecontent", 11) != 1);
896 
898  (uint8_t *)"FILECONTENT", 11) != 1);
899 
901  StreamTcpFreeConfig(true);
902  UTHFreeFlow(f);
903  PASS;
904 }
905 
906 /** \test POST, but not multipart */
907 static int HTPFileParserTest07(void)
908 {
909  uint8_t httpbuf1[] = "POST /filename HTTP/1.1\r\n"
910  "Host: www.server.lan\r\n"
911  "Content-Length: 11\r\n"
912  "\r\n";
913  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
914  uint8_t httpbuf2[] = "FILECONTENT";
915  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
916 
917  TcpSession ssn;
918  HtpState *http_state = NULL;
920 
921  memset(&ssn, 0, sizeof(ssn));
922 
923  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
924  FAIL_IF_NULL(f);
925  f->protoctx = &ssn;
926  f->proto = IPPROTO_TCP;
927  f->alproto = ALPROTO_HTTP1;
928 
929  StreamTcpInitConfig(true);
930 
931  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
932  int r = AppLayerParserParse(
933  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
934  FAIL_IF_NOT(r == 0);
935 
936  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
938  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
939  FAIL_IF_NOT(r == 0);
940 
941  http_state = f->alstate;
942  FAIL_IF_NULL(http_state);
943 
944  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
945  FAIL_IF_NULL(tx);
946  FAIL_IF_NULL(tx->request_method);
947  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
948 
949  FAIL_IF_NULL(http_state->files_ts);
950  FAIL_IF_NULL(http_state->files_ts->tail);
951  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
952 
954  (uint8_t *)"FILECONTENT", 11) != 1);
955 
957  StreamTcpFreeConfig(true);
958  UTHFreeFlow(f);
959  PASS;
960 }
961 
962 static int HTPFileParserTest08(void)
963 {
964  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
965  "Host: www.server.lan\r\n"
966  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
967  "Content-Length: 215\r\n"
968  "\r\n"
969  "-----------------------------277531038314945\r\n"
970  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
971  "Content-Type: image/jpeg\r\n";
972 
973  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
974  uint8_t httpbuf2[] = "filecontent\r\n\r\n"
975  "-----------------------------277531038314945--";
976  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
977 
978  TcpSession ssn;
980  HtpState *http_state = NULL;
981  memset(&ssn, 0, sizeof(ssn));
982 
983  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
984  FAIL_IF_NULL(f);
985  f->protoctx = &ssn;
986  f->proto = IPPROTO_TCP;
987  f->alproto = ALPROTO_HTTP1;
988 
989  StreamTcpInitConfig(true);
990 
991  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
992  int r = AppLayerParserParse(
993  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
994  FAIL_IF_NOT(r == 0);
995 
996  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
998  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
999  FAIL_IF_NOT(r == 0);
1000 
1001  http_state = f->alstate;
1002  FAIL_IF_NULL(http_state);
1003 
1004  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1005  FAIL_IF_NULL(tx);
1006 
1007  AppLayerDecoderEvents *decoder_events =
1008  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx);
1009  FAIL_IF_NULL(decoder_events);
1010 
1011  FAIL_IF(decoder_events->cnt != 2);
1012 
1014  StreamTcpFreeConfig(true);
1015  UTHFreeFlow(f);
1016  PASS;
1017 }
1018 
1019 /** \test invalid header: Somereallylongheaderstr: has no value */
1020 static int HTPFileParserTest09(void)
1021 {
1022  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1023  "Host: www.server.lan\r\n"
1024  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1025  "Content-Length: 337\r\n"
1026  "\r\n";
1027  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1028 
1029  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
1030  "Content-Disposition: form-data; name=\"email\"\r\n"
1031  "\r\n"
1032  "someaddress@somedomain.lan\r\n";
1033  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1034 
1035  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
1036  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1037  "Somereallylongheaderstr:\r\n"
1038  "\r\n";
1039  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1040 
1041  uint8_t httpbuf4[] = "filecontent\r\n"
1042  "-----------------------------277531038314945--";
1043  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1044 
1045  TcpSession ssn;
1046  HtpState *http_state = NULL;
1048 
1049  memset(&ssn, 0, sizeof(ssn));
1050 
1051  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1052  FAIL_IF_NULL(f);
1053  f->protoctx = &ssn;
1054  f->proto = IPPROTO_TCP;
1055  f->alproto = ALPROTO_HTTP1;
1056 
1057  StreamTcpInitConfig(true);
1058 
1059  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1060  int r = AppLayerParserParse(
1061  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1062  FAIL_IF_NOT(r == 0);
1063 
1064  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1065  r = AppLayerParserParse(
1066  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1067  FAIL_IF_NOT(r == 0);
1068 
1069  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1070  r = AppLayerParserParse(
1071  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1072  FAIL_IF_NOT(r == 0);
1073 
1074  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1075  r = AppLayerParserParse(
1076  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1077  FAIL_IF_NOT(r == 0);
1078 
1079  http_state = f->alstate;
1080  FAIL_IF_NULL(http_state);
1081 
1082  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1083  FAIL_IF_NULL(tx);
1084 
1085  AppLayerDecoderEvents *decoder_events =
1086  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx);
1087  FAIL_IF_NULL(decoder_events);
1088 
1089  FAIL_IF(decoder_events->cnt != 1);
1090 
1092  StreamTcpFreeConfig(true);
1093  UTHFreeFlow(f);
1094  PASS;
1095 }
1096 
1097 /** \test empty entries */
1098 static int HTPFileParserTest10(void)
1099 {
1100  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1101  "Host: www.server.lan\r\n"
1102  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1103  "Content-Length: 337\r\n"
1104  "\r\n";
1105  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1106 
1107  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
1108  "\r\n";
1109  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1110 
1111  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
1112  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1113  "Somereallylongheaderstr: with a good value\r\n"
1114  "\r\n";
1115  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1116 
1117  uint8_t httpbuf4[] = "filecontent\r\n"
1118  "-----------------------------277531038314945--";
1119  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1120 
1121  TcpSession ssn;
1122  HtpState *http_state = NULL;
1124 
1125  memset(&ssn, 0, sizeof(ssn));
1126 
1127  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1128  FAIL_IF_NULL(f);
1129  f->protoctx = &ssn;
1130  f->proto = IPPROTO_TCP;
1131  f->alproto = ALPROTO_HTTP1;
1132 
1133  StreamTcpInitConfig(true);
1134 
1135  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1136  int r = AppLayerParserParse(
1137  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1138  FAIL_IF_NOT(r == 0);
1139 
1140  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1141  r = AppLayerParserParse(
1142  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1143  FAIL_IF_NOT(r == 0);
1144 
1145  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1146  r = AppLayerParserParse(
1147  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1148  FAIL_IF_NOT(r == 0);
1149 
1150  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1151  r = AppLayerParserParse(
1152  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1153  FAIL_IF_NOT(r == 0);
1154 
1155  http_state = f->alstate;
1156  FAIL_IF_NULL(http_state);
1157 
1158  void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1159  FAIL_IF_NULL(tx);
1160  AppLayerDecoderEvents *decoder_events =
1161  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx);
1162  FAIL_IF_NOT_NULL(decoder_events);
1163 
1165  StreamTcpFreeConfig(true);
1166  UTHFreeFlow(f);
1167  PASS;
1168 }
1169 
1170 /** \test filedata cut in two pieces */
1171 static int HTPFileParserTest11(void)
1172 {
1173  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1174  "Host: www.server.lan\r\n"
1175  "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1176  "Content-Length: 1102\r\n"
1177  "\r\n";
1178  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1179 
1180  uint8_t httpbuf2[] = "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n";
1181  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1182 
1183  uint8_t httpbuf3[] = "Content-Disposition: form-data; name=\"PROGRESS_URL\"\r\n"
1184  "\r\n"
1185  "http://somserver.com/progress.php?UPLOAD_IDENTIFIER=XXXXXXXXX.XXXXXXXXXX.XXXXXXXX.XX.X\r\n"
1186  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1187  "Content-Disposition: form-data; name=\"DESTINATION_DIR\"\r\n"
1188  "\r\n"
1189  "10\r\n"
1190  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1191  "Content-Disposition: form-data; name=\"js_enabled\"\r\n"
1192  "\r\n"
1193  "1"
1194  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1195  "Content-Disposition: form-data; name=\"signature\"\r\n"
1196  "\r\n"
1197  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"
1198  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1199  "Content-Disposition: form-data; name=\"upload_files\"\r\n"
1200  "\r\n"
1201  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1202  "Content-Disposition: form-data; name=\"terms\"\r\n"
1203  "\r\n"
1204  "1"
1205  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1206  "Content-Disposition: form-data; name=\"file[]\"\r\n"
1207  "\r\n"
1208  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1209  "Content-Disposition: form-data; name=\"description[]\"\r\n"
1210  "\r\n"
1211  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1212  "Content-Disposition: form-data; name=\"upload_file[]\"; filename=\"filename.doc\"\r\n"
1213  "Content-Type: application/msword\r\n"
1214  "\r\n"
1215  "FILE";
1216  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1217 
1218  uint8_t httpbuf4[] = "CONTENT\r\n"
1219  "------WebKitFormBoundaryBRDbP74mBhBxsIdo--";
1220  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1221 
1222  TcpSession ssn;
1223  HtpState *http_state = NULL;
1225 
1226  memset(&ssn, 0, sizeof(ssn));
1227 
1228  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1229  FAIL_IF_NULL(f);
1230  f->protoctx = &ssn;
1231  f->proto = IPPROTO_TCP;
1232  f->alproto = ALPROTO_HTTP1;
1233 
1234  StreamTcpInitConfig(true);
1235 
1236  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1237  int r = AppLayerParserParse(
1238  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1239  FAIL_IF_NOT(r == 0);
1240 
1241  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1242  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1243  FAIL_IF_NOT(r == 0);
1244 
1245  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1246  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1247  FAIL_IF_NOT(r == 0);
1248 
1249  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1250  r = AppLayerParserParse(
1251  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1252  FAIL_IF_NOT(r == 0);
1253 
1254  http_state = f->alstate;
1255  FAIL_IF_NULL(http_state);
1256 
1257  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1258  FAIL_IF_NULL(txtmp);
1259 
1260  AppLayerDecoderEvents *decoder_events =
1261  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
1262  FAIL_IF_NOT_NULL(decoder_events);
1263 
1264  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
1265  FAIL_IF_NULL(tx);
1266  FAIL_IF_NULL(tx->request_method);
1267 
1268  FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0);
1269 
1270  FAIL_IF_NULL(http_state->files_ts);
1271  FAIL_IF_NULL(http_state->files_ts->tail);
1272  FAIL_IF(http_state->files_ts->tail->state != FILE_STATE_CLOSED);
1273 
1275  (uint8_t *)"FILECONTENT", 11) != 1);
1276 
1278  StreamTcpFreeConfig(true);
1279  UTHFreeFlow(f);
1280  PASS;
1281 }
1282 
1283 void AppLayerHtpFileRegisterTests (void);
1284 #include "tests/app-layer-htp-file.c"
1285 #endif /* UNITTESTS */
1286 
1288 {
1289 #ifdef UNITTESTS
1290  UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01);
1291  UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02);
1292  UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03);
1293  UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04);
1294  UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05);
1295  UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06);
1296  UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07);
1297  UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08);
1298  UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09);
1299  UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10);
1300  UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11);
1302 #endif /* UNITTESTS */
1303 }
HtpState_::cfg
const struct HTPCfgRec_ * cfg
Definition: app-layer-htp.h:257
FileContainer_
Definition: util-file.h:110
len
uint8_t len
Definition: app-layer-dnp3.h:2
detect-engine.h
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
flow-util.h
FileContainerAdd
void FileContainerAdd(FileContainer *ffc, File *ff)
Definition: util-file.c:540
FileContainerAlloc
FileContainer * FileContainerAlloc(void)
allocate a FileContainer
Definition: util-file.c:426
stream-tcp.h
HTPCfgRec_::response
HTPCfgDir response
Definition: app-layer-htp.h:179
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
app-layer-htp-file.c
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
AppLayerParserGetEventsByTx
AppLayerDecoderEvents * AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *tx)
Definition: app-layer-parser.c:871
Flow_::proto
uint8_t proto
Definition: flow.h:375
threads.h
Flow_
Flow data structure.
Definition: flow.h:353
File_::state
FileState state
Definition: util-file.h:78
HtpState_::flags
uint16_t flags
Definition: app-layer-htp.h:258
HtpState_::f
Flow * f
Definition: app-layer-htp.h:252
FILE_STORE
#define FILE_STORE
Definition: util-file.h:55
FileSetTx
int FileSetTx(File *ff, uint64_t txid)
Set the TX id for a file.
Definition: util-file.c:567
HttpRangeContainerFile::error
bool error
Definition: app-layer-htp-range.h:81
HtpState_::file_range
HttpRangeContainerBlock * file_range
Definition: app-layer-htp.h:262
HttpRangeContainerOpenFile
HttpRangeContainerBlock * HttpRangeContainerOpenFile(const uint8_t *key, uint32_t keylen, const Flow *f, const HTTPContentRange *crparsed, const StreamingBufferConfig *sbcfg, const uint8_t *name, uint16_t name_len, uint16_t flags, const uint8_t *data, uint32_t data_len)
Definition: app-layer-htp-range.c:362
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:320
FileContainer_::tail
File * tail
Definition: util-file.h:112
stream-tcp-reassemble.h
HTP_FLAG_STORE_FILES_TX_TC
#define HTP_FLAG_STORE_FILES_TX_TC
Definition: app-layer-htp.h:77
Flow_::protoctx
void * protoctx
Definition: flow.h:451
FileAppendData
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:720
AppLayerDecoderEvents_
Data structure to store app layer decoder events.
Definition: app-layer-events.h:34
util-unittest.h
HTPParseContentRange
int HTPParseContentRange(bstr *rawvalue, HTTPContentRange *range)
Definition: app-layer-htp-file.c:164
HtpState_
Definition: app-layer-htp.h:247
util-unittest-helper.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
File_::sb
StreamingBuffer * sb
Definition: util-file.h:79
app-layer-htp-file.h
util-memcmp.h
HttpRangeContainerBlock
Definition: app-layer-htp-range.h:89
HTPFileClose
int HTPFileClose(HtpState *s, HtpTxUserData *htud, const uint8_t *data, uint32_t data_len, uint8_t flags, uint8_t direction)
Close the file in the flow.
Definition: app-layer-htp-file.c:393
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:357
UTHBuildFlow
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
Definition: util-unittest-helper.c:521
app-layer-htp.h
decode.h
FAIL_IF_NOT_NULL
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
util-debug.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
AppLayerHtpFileRegisterTests
void AppLayerHtpFileRegisterTests(void)
this function registers unit tests for AppLayerHtpFile
Definition: app-layer-htp-file.c:87
FileFlowToFlags
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition: util-file.c:234
HtpState_::file_track_id
uint32_t file_track_id
Definition: app-layer-htp.h:261
HttpRangeClose
File * HttpRangeClose(HttpRangeContainerBlock *c, uint16_t flags)
Definition: app-layer-htp-range.c:467
FLOWFILE_NO_STORE_TS
#define FLOWFILE_NO_STORE_TS
Definition: flow.h:126
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:20
util-print.h
HTPFileCloseHandleRange
bool HTPFileCloseHandleRange(FileContainer *files, const uint16_t flags, HttpRangeContainerBlock *c, const uint8_t *data, uint32_t data_len)
close range, add reassembled file if possible
Definition: app-layer-htp-file.c:351
SCEnter
#define SCEnter(...)
Definition: util-debug.h:300
FileContainer_::head
File * head
Definition: util-file.h:111
HtpState_::conn
htp_conn_t * conn
Definition: app-layer-htp.h:251
HtpTxUserData_::tx_data
AppLayerTxData tx_data
Definition: app-layer-htp.h:244
util-time.h
app-layer-parser.h
HTPFileParserRegisterTests
void HTPFileParserRegisterTests(void)
Definition: app-layer-htp-file.c:1287
AppLayerDecoderEvents_::cnt
uint8_t cnt
Definition: app-layer-events.h:38
stream.h
HTPCfgDir_::sbcfg
StreamingBufferConfig sbcfg
Definition: app-layer-htp.h:158
stream-tcp-private.h
conf.h
StreamingBufferCompareRawData
int StreamingBufferCompareRawData(const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len)
Definition: util-streaming-buffer.c:872
util-radix-tree.h
FileOpenFileWithId
int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, 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:920
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
HTPFileStoreChunk
int HTPFileStoreChunk(HtpState *s, const uint8_t *data, uint32_t data_len, uint8_t direction)
Store a chunk of data in the flow.
Definition: app-layer-htp-file.c:304
HTP_FLAG_STORE_FILES_TS
#define HTP_FLAG_STORE_FILES_TS
Definition: app-layer-htp.h:74
AppLayerParserGetTx
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
Definition: app-layer-parser.c:1116
HTP_FLAG_STORE_FILES_TX_TS
#define HTP_FLAG_STORE_FILES_TX_TS
Definition: app-layer-htp.h:76
FileDataSize
uint64_t FileDataSize(const File *file)
get the size of the file data
Definition: util-file.c:294
HttpRangeContainerFile::hdata
THashData * hdata
Definition: app-layer-htp-range.h:69
UTHFreeFlow
void UTHFreeFlow(Flow *flow)
Definition: util-unittest-helper.c:526
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:299
HttpRangeContainerBlock::container
HttpRangeContainerFile * container
Definition: app-layer-htp-range.h:95
FILE_STATE_CLOSED
@ FILE_STATE_CLOSED
Definition: util-file.h:67
File_
Definition: util-file.h:75
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
StreamTcpFreeConfig
void StreamTcpFreeConfig(bool quiet)
Definition: stream-tcp.c:662
flags
uint8_t flags
Definition: decode-gre.h:0
AppLayerParserParse
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
Definition: app-layer-parser.c:1237
suricata-common.h
HTPCfgRec_::request
HTPCfgDir request
Definition: app-layer-htp.h:178
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:30
AppLayerDecoderEventsSetEventRaw
void AppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t event)
Set an app layer decoder event.
Definition: app-layer-events.c:89
File_::next
struct File_ * next
Definition: util-file.h:89
util-spm.h
FileSetRange
int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end)
Sets the offset range for a file.
Definition: util-file.c:812
HtpTxUserData_
Definition: app-layer-htp.h:214
FLOWFILE_NO_STORE_TC
#define FLOWFILE_NO_STORE_TC
Definition: flow.h:127
util-validate.h
StreamingBufferConfig_
Definition: util-streaming-buffer.h:64
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
HtpState_::events
uint16_t events
Definition: app-layer-htp.h:259
HTPFileOpen
int HTPFileOpen(HtpState *s, HtpTxUserData *tx, 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.
Definition: app-layer-htp-file.c:80
HttpRangeFreeBlock
void HttpRangeFreeBlock(HttpRangeContainerBlock *b)
Definition: app-layer-htp-range.c:611
HTTP_DECODER_EVENT_RANGE_INVALID
@ HTTP_DECODER_EVENT_RANGE_INVALID
Definition: app-layer-htp.h:137
HtpState_::files_tc
FileContainer * files_tc
Definition: app-layer-htp.h:256
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Flow_::alstate
void * alstate
Definition: flow.h:486
detect-parse.h
HTPFileOpenWithRange
int HTPFileOpenWithRange(HtpState *s, HtpTxUserData *txud, const uint8_t *filename, uint16_t filename_len, const uint8_t *data, uint32_t data_len, uint64_t txid, bstr *rawvalue, HtpTxUserData *htud)
Sets range for a file.
Definition: app-layer-htp-file.c:217
HttpRangeAppendData
int HttpRangeAppendData(HttpRangeContainerBlock *c, const uint8_t *data, uint32_t len)
Definition: app-layer-htp-range.c:396
app-layer-protos.h
suricata.h
HtpState_::files_ts
FileContainer * files_ts
Definition: app-layer-htp.h:255
FILE_NOSTORE
#define FILE_NOSTORE
Definition: util-file.h:54
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:86
TcpSession_
Definition: stream-tcp-private.h:260
HTP_FLAG_STORE_FILES_TC
#define HTP_FLAG_STORE_FILES_TC
Definition: app-layer-htp.h:75
Flow_::file_flags
uint16_t file_flags
Definition: flow.h:433
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:460
util-pool.h
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:304
FileCloseFile
int FileCloseFile(FileContainer *ffc, const uint8_t *data, uint32_t data_len, uint16_t flags)
Close a File.
Definition: util-file.c:1008
HtpState_::store_tx_id
uint64_t store_tx_id
Definition: app-layer-htp.h:254
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:111
debug.h
app-layer.h