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  * \brief Store a chunk of data in the flow
155  *
156  * \param s http state
157  * \param data data chunk (if any)
158  * \param data_len length of the data portion
159  * \param direction flow direction
160  *
161  * \retval 0 ok
162  * \retval -1 error
163  * \retval -2 file doesn't need storing
164  */
165 int HTPFileStoreChunk(HtpState *s, const uint8_t *data, uint32_t data_len,
166  uint8_t direction)
167 {
168  SCEnter();
169 
170  int retval = 0;
171  int result = 0;
172  FileContainer *files = NULL;
173 
174  if (s == NULL) {
175  SCReturnInt(-1);
176  }
177 
178  if (direction & STREAM_TOCLIENT) {
179  files = s->files_tc;
180  } else {
181  files = s->files_ts;
182  }
183 
184  if (files == NULL) {
185  SCLogDebug("no files in state");
186  retval = -1;
187  goto end;
188  }
189 
190  result = FileAppendData(files, data, data_len);
191  if (result == -1) {
192  SCLogDebug("appending data failed");
193  retval = -1;
194  } else if (result == -2) {
195  retval = -2;
196  }
197 
198  FilePrune(files);
199 end:
200  SCReturnInt(retval);
201 }
202 
203 /**
204  * \brief Close the file in the flow
205  *
206  * \param s http state
207  * \param data data chunk if any
208  * \param data_len length of the data portion
209  * \param flags flags to indicate events
210  * \param direction flow direction
211  *
212  * Currently on the FLOW_FILE_TRUNCATED flag is implemented, indicating
213  * that the file isn't complete but we're stopping storing it.
214  *
215  * \retval 0 ok
216  * \retval -1 error
217  * \retval -2 not storing files on this flow/tx
218  */
219 int HTPFileClose(HtpState *s, const uint8_t *data, uint32_t data_len,
220  uint8_t flags, uint8_t direction)
221 {
222  SCEnter();
223 
224  int retval = 0;
225  int result = 0;
226  FileContainer *files = NULL;
227 
228  if (s == NULL) {
229  SCReturnInt(-1);
230  }
231 
232  if (direction & STREAM_TOCLIENT) {
233  files = s->files_tc;
234  } else {
235  files = s->files_ts;
236  }
237 
238  if (files == NULL) {
239  retval = -1;
240  goto end;
241  }
242 
243  result = FileCloseFile(files, data, data_len, flags);
244  if (result == -1) {
245  retval = -1;
246  } else if (result == -2) {
247  retval = -2;
248  }
249 
250  FilePrune(files);
251 end:
252  SCReturnInt(retval);
253 }
254 
255 #ifdef UNITTESTS
256 static int HTPFileParserTest01(void)
257 {
258  int result = 0;
259  Flow *f = NULL;
260  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
261  "Host: www.server.lan\r\n"
262  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
263  "Content-Length: 215\r\n"
264  "\r\n"
265  "-----------------------------277531038314945\r\n"
266  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
267  "Content-Type: image/jpeg\r\n"
268  "\r\n";
269 
270  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
271  uint8_t httpbuf2[] = "filecontent\r\n"
272  "-----------------------------277531038314945--";
273  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
274 
275  TcpSession ssn;
277  HtpState *http_state = NULL;
278  memset(&ssn, 0, sizeof(ssn));
279 
280  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
281  if (f == NULL)
282  goto end;
283  f->protoctx = &ssn;
284  f->proto = IPPROTO_TCP;
285  f->alproto = ALPROTO_HTTP;
286 
288 
289  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
290  FLOWLOCK_WRLOCK(f);
291  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
292  STREAM_TOSERVER | STREAM_START, httpbuf1,
293  httplen1);
294  if (r != 0) {
295  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
296  result = 0;
297  FLOWLOCK_UNLOCK(f);
298  goto end;
299  }
300  FLOWLOCK_UNLOCK(f);
301 
302  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
303  FLOWLOCK_WRLOCK(f);
304  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
305  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
306  if (r != 0) {
307  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
308  result = 0;
309  FLOWLOCK_UNLOCK(f);
310  goto end;
311  }
312  FLOWLOCK_UNLOCK(f);
313 
314  http_state = f->alstate;
315  if (http_state == NULL) {
316  printf("no http state: ");
317  result = 0;
318  goto end;
319  }
320 
321  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
322  if (tx == NULL) {
323  goto end;
324  }
325 
326  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
327  {
328  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
329  goto end;
330  }
331 
332  result = 1;
333 end:
334  if (alp_tctx != NULL)
335  AppLayerParserThreadCtxFree(alp_tctx);
337  UTHFreeFlow(f);
338  return result;
339 }
340 
341 static int HTPFileParserTest02(void)
342 {
343  int result = 0;
344  Flow *f = NULL;
345  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
346  "Host: www.server.lan\r\n"
347  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
348  "Content-Length: 337\r\n"
349  "\r\n";
350  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
351 
352  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
353  "Content-Disposition: form-data; name=\"email\"\r\n"
354  "\r\n"
355  "someaddress@somedomain.lan\r\n";
356  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
357 
358  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
359  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
360  "Content-Type: image/jpeg\r\n"
361  "\r\n";
362  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
363 
364  uint8_t httpbuf4[] = "filecontent\r\n"
365  "-----------------------------277531038314945--";
366  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
367 
368  TcpSession ssn;
369  HtpState *http_state = NULL;
371 
372  memset(&ssn, 0, sizeof(ssn));
373 
374  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
375  if (f == NULL)
376  goto end;
377  f->protoctx = &ssn;
378  f->proto = IPPROTO_TCP;
379  f->alproto = ALPROTO_HTTP;
380 
382 
383  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
384  FLOWLOCK_WRLOCK(f);
385  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
386  STREAM_TOSERVER | STREAM_START, httpbuf1,
387  httplen1);
388  if (r != 0) {
389  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
390  result = 0;
391  FLOWLOCK_UNLOCK(f);
392  goto end;
393  }
394  FLOWLOCK_UNLOCK(f);
395 
396  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
397  FLOWLOCK_WRLOCK(f);
398  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
399  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
400  if (r != 0) {
401  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
402  result = 0;
403  FLOWLOCK_UNLOCK(f);
404  goto end;
405  }
406  FLOWLOCK_UNLOCK(f);
407 
408  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
409  FLOWLOCK_WRLOCK(f);
410  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
411  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
412  if (r != 0) {
413  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
414  result = 0;
415  FLOWLOCK_UNLOCK(f);
416  goto end;
417  }
418  FLOWLOCK_UNLOCK(f);
419 
420  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
421  FLOWLOCK_WRLOCK(f);
422  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
423  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
424  if (r != 0) {
425  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
426  result = 0;
427  FLOWLOCK_UNLOCK(f);
428  goto end;
429  }
430  FLOWLOCK_UNLOCK(f);
431 
432  http_state = f->alstate;
433  if (http_state == NULL) {
434  printf("no http state: ");
435  result = 0;
436  goto end;
437  }
438 
439  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
440  if (tx == NULL) {
441  goto end;
442  }
443 
444  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
445  {
446  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
447  goto end;
448  }
449 
450  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
451  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
452  goto end;
453  }
454 
455  result = 1;
456 end:
457  if (alp_tctx != NULL)
458  AppLayerParserThreadCtxFree(alp_tctx);
460  UTHFreeFlow(f);
461  return result;
462 }
463 
464 static int HTPFileParserTest03(void)
465 {
466  int result = 0;
467  Flow *f = NULL;
468  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
469  "Host: www.server.lan\r\n"
470  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
471  "Content-Length: 337\r\n"
472  "\r\n";
473  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
474 
475  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
476  "Content-Disposition: form-data; name=\"email\"\r\n"
477  "\r\n"
478  "someaddress@somedomain.lan\r\n";
479  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
480 
481  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
482  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
483  "Content-Type: image/jpeg\r\n"
484  "\r\n";
485  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
486 
487  uint8_t httpbuf4[] = "file";
488  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
489 
490  uint8_t httpbuf5[] = "content\r\n";
491  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
492 
493  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
494  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
495 
496  TcpSession ssn;
497  HtpState *http_state = NULL;
499 
500  memset(&ssn, 0, sizeof(ssn));
501 
502  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
503  if (f == NULL)
504  goto end;
505  f->protoctx = &ssn;
506  f->proto = IPPROTO_TCP;
507  f->alproto = ALPROTO_HTTP;
508 
510 
511  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
512  FLOWLOCK_WRLOCK(f);
513  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
514  STREAM_TOSERVER | STREAM_START, httpbuf1,
515  httplen1);
516  if (r != 0) {
517  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
518  result = 0;
519  FLOWLOCK_UNLOCK(f);
520  goto end;
521  }
522  FLOWLOCK_UNLOCK(f);
523 
524  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
525  FLOWLOCK_WRLOCK(f);
526  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
527  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
528  if (r != 0) {
529  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
530  result = 0;
531  FLOWLOCK_UNLOCK(f);
532  goto end;
533  }
534  FLOWLOCK_UNLOCK(f);
535 
536  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
537  FLOWLOCK_WRLOCK(f);
538  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
539  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
540  if (r != 0) {
541  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
542  result = 0;
543  FLOWLOCK_UNLOCK(f);
544  goto end;
545  }
546  FLOWLOCK_UNLOCK(f);
547 
548  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
549  FLOWLOCK_WRLOCK(f);
550  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
551  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
552  if (r != 0) {
553  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
554  result = 0;
555  FLOWLOCK_UNLOCK(f);
556  goto end;
557  }
558  FLOWLOCK_UNLOCK(f);
559 
560  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
561  FLOWLOCK_WRLOCK(f);
562  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
563  STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
564  if (r != 0) {
565  printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
566  result = 0;
567  FLOWLOCK_UNLOCK(f);
568  goto end;
569  }
570  FLOWLOCK_UNLOCK(f);
571 
572  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
573  FLOWLOCK_WRLOCK(f);
574  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
575  STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
576  if (r != 0) {
577  printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
578  result = 0;
579  FLOWLOCK_UNLOCK(f);
580  goto end;
581  }
582  FLOWLOCK_UNLOCK(f);
583 
584  http_state = f->alstate;
585  if (http_state == NULL) {
586  printf("no http state: ");
587  result = 0;
588  goto end;
589  }
590 
591  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
592  if (tx == NULL) {
593  goto end;
594  }
595 
596  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
597  {
598  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
599  goto end;
600  }
601 
602  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
603  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
604  goto end;
605  }
606 
607  if (http_state->files_ts->head == NULL ||
608  FileDataSize(http_state->files_ts->head) != 11)
609  {
610  if (http_state->files_ts->head != NULL)
611  printf("filedata len not 11 but %"PRIu64": ",
612  FileDataSize(http_state->files_ts->head));
613  goto end;
614  }
615 
616  result = 1;
617 end:
618  if (alp_tctx != NULL)
619  AppLayerParserThreadCtxFree(alp_tctx);
621  UTHFreeFlow(f);
622  return result;
623 }
624 
625 static int HTPFileParserTest04(void)
626 {
627  int result = 0;
628  Flow *f = NULL;
629  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
630  "Host: www.server.lan\r\n"
631  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
632  "Content-Length: 373\r\n"
633  "\r\n";
634  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
635 
636  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
637  "Content-Disposition: form-data; name=\"email\"\r\n"
638  "\r\n"
639  "someaddress@somedomain.lan\r\n";
640  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
641 
642  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
643  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
644  "Content-Type: image/jpeg\r\n"
645  "\r\n";
646  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
647 
648  uint8_t httpbuf4[] = "file0123456789abcdefghijklmnopqrstuvwxyz";
649  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
650 
651  uint8_t httpbuf5[] = "content\r\n";
652  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
653 
654  uint8_t httpbuf6[] = "-----------------------------277531038314945--";
655  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
656 
657  TcpSession ssn;
658  HtpState *http_state = NULL;
660 
661  memset(&ssn, 0, sizeof(ssn));
662 
663  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
664  if (f == NULL)
665  goto end;
666  f->protoctx = &ssn;
667  f->proto = IPPROTO_TCP;
668  f->alproto = ALPROTO_HTTP;
669 
671 
672  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
673  FLOWLOCK_WRLOCK(f);
674  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
675  STREAM_TOSERVER | STREAM_START, httpbuf1,
676  httplen1);
677  if (r != 0) {
678  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
679  result = 0;
680  FLOWLOCK_UNLOCK(f);
681  goto end;
682  }
683  FLOWLOCK_UNLOCK(f);
684 
685  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
686  FLOWLOCK_WRLOCK(f);
687  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
688  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
689  if (r != 0) {
690  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
691  result = 0;
692  FLOWLOCK_UNLOCK(f);
693  goto end;
694  }
695  FLOWLOCK_UNLOCK(f);
696 
697  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
698  FLOWLOCK_WRLOCK(f);
699  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
700  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
701  if (r != 0) {
702  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
703  result = 0;
704  FLOWLOCK_UNLOCK(f);
705  goto end;
706  }
707  FLOWLOCK_UNLOCK(f);
708 
709  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
710  FLOWLOCK_WRLOCK(f);
711  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
712  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
713  if (r != 0) {
714  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
715  result = 0;
716  FLOWLOCK_UNLOCK(f);
717  goto end;
718  }
719  FLOWLOCK_UNLOCK(f);
720 
721  SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5);
722  FLOWLOCK_WRLOCK(f);
723  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
724  STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5);
725  if (r != 0) {
726  printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
727  result = 0;
728  FLOWLOCK_UNLOCK(f);
729  goto end;
730  }
731  FLOWLOCK_UNLOCK(f);
732 
733  SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6);
734  FLOWLOCK_WRLOCK(f);
735  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
736  STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6);
737  if (r != 0) {
738  printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
739  result = 0;
740  FLOWLOCK_UNLOCK(f);
741  goto end;
742  }
743  FLOWLOCK_UNLOCK(f);
744 
745  http_state = f->alstate;
746  if (http_state == NULL) {
747  printf("no http state: ");
748  result = 0;
749  goto end;
750  }
751 
752  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
753  if (tx == NULL) {
754  goto end;
755  }
756 
757  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
758  {
759  printf("expected method POST, got %s: ", bstr_util_strdup_to_c(tx->request_method));
760  goto end;
761  }
762 
763  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
764  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
765  goto end;
766  }
767 
768  result = 1;
769 end:
770  if (alp_tctx != NULL)
771  AppLayerParserThreadCtxFree(alp_tctx);
773  UTHFreeFlow(f);
774  return result;
775 }
776 
777 static int HTPFileParserTest05(void)
778 {
779  int result = 0;
780  Flow *f = NULL;
781  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
782  "Host: www.server.lan\r\n"
783  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
784  "Content-Length: 544\r\n"
785  "\r\n"
786  "-----------------------------277531038314945\r\n"
787  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
788  "Content-Type: image/jpeg\r\n"
789  "\r\n"
790  "filecontent\r\n"
791  "-----------------------------277531038314945\r\n";
792  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
793  uint8_t httpbuf2[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
794  "Content-Type: image/jpeg\r\n"
795  "\r\n"
796  "FILECONTENT\r\n"
797  "-----------------------------277531038314945--";
798  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
799 
800  TcpSession ssn;
801  HtpState *http_state = NULL;
803 
804  memset(&ssn, 0, sizeof(ssn));
805 
806  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
807  if (f == NULL)
808  goto end;
809  f->protoctx = &ssn;
810  f->proto = IPPROTO_TCP;
811  f->alproto = ALPROTO_HTTP;
812 
814 
815  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
816  FLOWLOCK_WRLOCK(f);
817  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
818  STREAM_TOSERVER | STREAM_START, httpbuf1,
819  httplen1);
820  if (r != 0) {
821  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
822  result = 0;
823  FLOWLOCK_UNLOCK(f);
824  goto end;
825  }
826  FLOWLOCK_UNLOCK(f);
827 
828  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
829  FLOWLOCK_WRLOCK(f);
830  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
831  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
832  if (r != 0) {
833  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
834  result = 0;
835  FLOWLOCK_UNLOCK(f);
836  goto end;
837  }
838  FLOWLOCK_UNLOCK(f);
839 
840  http_state = f->alstate;
841  if (http_state == NULL) {
842  printf("no http state: ");
843  result = 0;
844  goto end;
845  }
846 
847  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
848  if (tx == NULL) {
849  goto end;
850  }
851 
852  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
853  {
854  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
855  goto end;
856  }
857 
858  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
859  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
860  goto end;
861  }
862 
863  if (http_state->files_ts->head == http_state->files_ts->tail)
864  goto end;
865 
866  if (http_state->files_ts->head->next != http_state->files_ts->tail)
867  goto end;
868 
869  if (StreamingBufferCompareRawData(http_state->files_ts->head->sb,
870  (uint8_t *)"filecontent", 11) != 1)
871  {
872  goto end;
873  }
874 
875  if (StreamingBufferCompareRawData(http_state->files_ts->tail->sb,
876  (uint8_t *)"FILECONTENT", 11) != 1)
877  {
878  goto end;
879  }
880 
881  result = 1;
882 end:
883  if (alp_tctx != NULL)
884  AppLayerParserThreadCtxFree(alp_tctx);
886  UTHFreeFlow(f);
887  return result;
888 }
889 
890 /** \test first multipart part contains file but doesn't end in first chunk */
891 static int HTPFileParserTest06(void)
892 {
893  int result = 0;
894  Flow *f = NULL;
895  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
896  "Host: www.server.lan\r\n"
897  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
898  "Content-Length: 544\r\n"
899  "\r\n"
900  "-----------------------------277531038314945\r\n"
901  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
902  "Content-Type: image/jpeg\r\n"
903  "\r\n"
904  "filecontent\r\n"
905  "-----------------------------27753103831494";
906  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
907  uint8_t httpbuf2[] = "5\r\nContent-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
908  "Content-Type: image/jpeg\r\n"
909  "\r\n"
910  "FILECONTENT\r\n"
911  "-----------------------------277531038314945--";
912  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
913 
914  TcpSession ssn;
915  HtpState *http_state = NULL;
917 
918  memset(&ssn, 0, sizeof(ssn));
919 
920  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
921  if (f == NULL)
922  goto end;
923  f->protoctx = &ssn;
924  f->proto = IPPROTO_TCP;
925  f->alproto = ALPROTO_HTTP;
926 
928 
929  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
930  FLOWLOCK_WRLOCK(f);
931  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
932  STREAM_TOSERVER | STREAM_START, httpbuf1,
933  httplen1);
934  if (r != 0) {
935  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
936  result = 0;
937  FLOWLOCK_UNLOCK(f);
938  goto end;
939  }
940  FLOWLOCK_UNLOCK(f);
941 
942  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
943  FLOWLOCK_WRLOCK(f);
944  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
945  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
946  if (r != 0) {
947  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
948  result = 0;
949  FLOWLOCK_UNLOCK(f);
950  goto end;
951  }
952  FLOWLOCK_UNLOCK(f);
953 
954  http_state = f->alstate;
955  if (http_state == NULL) {
956  printf("no http state: ");
957  result = 0;
958  goto end;
959  }
960 
961  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
962  if (tx == NULL) {
963  goto end;
964  }
965 
966  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
967  {
968  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
969  goto end;
970  }
971 
972  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
973  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
974  goto end;
975  }
976 
977  if (http_state->files_ts->head == http_state->files_ts->tail)
978  goto end;
979 
980  if (http_state->files_ts->head->next != http_state->files_ts->tail)
981  goto end;
982 
983  if (StreamingBufferCompareRawData(http_state->files_ts->head->sb,
984  (uint8_t *)"filecontent", 11) != 1)
985  {
986  goto end;
987  }
988 
989  if (StreamingBufferCompareRawData(http_state->files_ts->tail->sb,
990  (uint8_t *)"FILECONTENT", 11) != 1)
991  {
992  goto end;
993  }
994 
995  result = 1;
996 end:
997  if (alp_tctx != NULL)
998  AppLayerParserThreadCtxFree(alp_tctx);
1000  UTHFreeFlow(f);
1001  return result;
1002 }
1003 
1004 /** \test POST, but not multipart */
1005 static int HTPFileParserTest07(void)
1006 {
1007  int result = 0;
1008  Flow *f = NULL;
1009  uint8_t httpbuf1[] = "POST /filename HTTP/1.1\r\n"
1010  "Host: www.server.lan\r\n"
1011  "Content-Length: 11\r\n"
1012  "\r\n";
1013  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1014  uint8_t httpbuf2[] = "FILECONTENT";
1015  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1016 
1017  TcpSession ssn;
1018  HtpState *http_state = NULL;
1020 
1021  memset(&ssn, 0, sizeof(ssn));
1022 
1023  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1024  if (f == NULL)
1025  goto end;
1026  f->protoctx = &ssn;
1027  f->proto = IPPROTO_TCP;
1028  f->alproto = ALPROTO_HTTP;
1029 
1031 
1032  SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1);
1033  FLOWLOCK_WRLOCK(f);
1034  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1035  STREAM_TOSERVER | STREAM_START, httpbuf1,
1036  httplen1);
1037  if (r != 0) {
1038  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1039  result = 0;
1040  FLOWLOCK_UNLOCK(f);
1041  goto end;
1042  }
1043  FLOWLOCK_UNLOCK(f);
1044 
1045  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1046  FLOWLOCK_WRLOCK(f);
1047  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1048  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1049  if (r != 0) {
1050  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1051  result = 0;
1052  FLOWLOCK_UNLOCK(f);
1053  goto end;
1054  }
1055  FLOWLOCK_UNLOCK(f);
1056 
1057  http_state = f->alstate;
1058  if (http_state == NULL) {
1059  printf("no http state: ");
1060  result = 0;
1061  goto end;
1062  }
1063 
1064  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
1065  if (tx == NULL) {
1066  goto end;
1067  }
1068 
1069  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
1070  {
1071  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
1072  goto end;
1073  }
1074 
1075  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
1076  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
1077  printf("state != FILE_STATE_CLOSED");
1078  goto end;
1079  }
1080 
1081  if (StreamingBufferCompareRawData(http_state->files_ts->tail->sb,
1082  (uint8_t *)"FILECONTENT", 11) != 1)
1083  {
1084  goto end;
1085  }
1086 
1087  result = 1;
1088 end:
1089  if (alp_tctx != NULL)
1090  AppLayerParserThreadCtxFree(alp_tctx);
1092  UTHFreeFlow(f);
1093  return result;
1094 }
1095 
1096 static int HTPFileParserTest08(void)
1097 {
1098  int result = 0;
1099  Flow *f = NULL;
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: 215\r\n"
1104  "\r\n"
1105  "-----------------------------277531038314945\r\n"
1106  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1107  "Content-Type: image/jpeg\r\n";
1108 
1109  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1110  uint8_t httpbuf2[] = "filecontent\r\n\r\n"
1111  "-----------------------------277531038314945--";
1112  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1113 
1114  TcpSession ssn;
1116  HtpState *http_state = NULL;
1117  memset(&ssn, 0, sizeof(ssn));
1118 
1119  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1120  if (f == NULL)
1121  goto end;
1122  f->protoctx = &ssn;
1123  f->proto = IPPROTO_TCP;
1124  f->alproto = ALPROTO_HTTP;
1125 
1127 
1128  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1129  FLOWLOCK_WRLOCK(f);
1130  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1131  STREAM_TOSERVER | STREAM_START, httpbuf1,
1132  httplen1);
1133  if (r != 0) {
1134  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1135  result = 0;
1136  FLOWLOCK_UNLOCK(f);
1137  goto end;
1138  }
1139  FLOWLOCK_UNLOCK(f);
1140 
1141  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1142  FLOWLOCK_WRLOCK(f);
1143  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1144  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1145  if (r != 0) {
1146  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1147  result = 0;
1148  FLOWLOCK_UNLOCK(f);
1149  goto end;
1150  }
1151  FLOWLOCK_UNLOCK(f);
1152 
1153  http_state = f->alstate;
1154  if (http_state == NULL) {
1155  printf("no http state: ");
1156  result = 0;
1157  goto end;
1158  }
1159 
1160  FLOWLOCK_WRLOCK(f);
1161  AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
1162  if (decoder_events == NULL) {
1163  printf("no app events: ");
1164  FLOWLOCK_UNLOCK(f);
1165  goto end;
1166  }
1167  FLOWLOCK_UNLOCK(f);
1168 
1169  if (decoder_events->cnt != 2) {
1170  printf("expected 2 events: ");
1171  goto end;
1172  }
1173 
1174  result = 1;
1175 end:
1176  if (alp_tctx != NULL)
1177  AppLayerParserThreadCtxFree(alp_tctx);
1179  UTHFreeFlow(f);
1180  return result;
1181 }
1182 
1183 /** \test invalid header: Somereallylongheaderstr: has no value */
1184 static int HTPFileParserTest09(void)
1185 {
1186  int result = 0;
1187  Flow *f = NULL;
1188  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1189  "Host: www.server.lan\r\n"
1190  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1191  "Content-Length: 337\r\n"
1192  "\r\n";
1193  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1194 
1195  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
1196  "Content-Disposition: form-data; name=\"email\"\r\n"
1197  "\r\n"
1198  "someaddress@somedomain.lan\r\n";
1199  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1200 
1201  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
1202  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1203  "Somereallylongheaderstr:\r\n"
1204  "\r\n";
1205  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1206 
1207  uint8_t httpbuf4[] = "filecontent\r\n"
1208  "-----------------------------277531038314945--";
1209  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1210 
1211  TcpSession ssn;
1212  HtpState *http_state = NULL;
1214 
1215  memset(&ssn, 0, sizeof(ssn));
1216 
1217  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1218  if (f == NULL)
1219  goto end;
1220  f->protoctx = &ssn;
1221  f->proto = IPPROTO_TCP;
1222  f->alproto = ALPROTO_HTTP;
1223 
1225 
1226  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1227  FLOWLOCK_WRLOCK(f);
1228  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1229  STREAM_TOSERVER | STREAM_START, httpbuf1,
1230  httplen1);
1231  if (r != 0) {
1232  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1233  result = 0;
1234  FLOWLOCK_UNLOCK(f);
1235  goto end;
1236  }
1237  FLOWLOCK_UNLOCK(f);
1238 
1239  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1240  FLOWLOCK_WRLOCK(f);
1241  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1242  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1243  if (r != 0) {
1244  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1245  result = 0;
1246  FLOWLOCK_UNLOCK(f);
1247  goto end;
1248  }
1249  FLOWLOCK_UNLOCK(f);
1250 
1251  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1252  FLOWLOCK_WRLOCK(f);
1253  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1254  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1255  if (r != 0) {
1256  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1257  result = 0;
1258  FLOWLOCK_UNLOCK(f);
1259  goto end;
1260  }
1261  FLOWLOCK_UNLOCK(f);
1262 
1263  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1264  FLOWLOCK_WRLOCK(f);
1265  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1266  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1267  if (r != 0) {
1268  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
1269  result = 0;
1270  FLOWLOCK_UNLOCK(f);
1271  goto end;
1272  }
1273  FLOWLOCK_UNLOCK(f);
1274 
1275  http_state = f->alstate;
1276  if (http_state == NULL) {
1277  printf("no http state: ");
1278  result = 0;
1279  goto end;
1280  }
1281 
1282  FLOWLOCK_WRLOCK(f);
1283  AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
1284  if (decoder_events == NULL) {
1285  printf("no app events: ");
1286  FLOWLOCK_UNLOCK(f);
1287  goto end;
1288  }
1289  FLOWLOCK_UNLOCK(f);
1290 
1291  if (decoder_events->cnt != 1) {
1292  printf("expected 1 event: ");
1293  goto end;
1294  }
1295 
1296  result = 1;
1297 end:
1298  if (alp_tctx != NULL)
1299  AppLayerParserThreadCtxFree(alp_tctx);
1301  UTHFreeFlow(f);
1302  return result;
1303 }
1304 
1305 /** \test empty entries */
1306 static int HTPFileParserTest10(void)
1307 {
1308  int result = 0;
1309  Flow *f = NULL;
1310  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1311  "Host: www.server.lan\r\n"
1312  "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1313  "Content-Length: 337\r\n"
1314  "\r\n";
1315  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1316 
1317  uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n"
1318  "\r\n";
1319  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1320 
1321  uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n"
1322  "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1323  "Somereallylongheaderstr: with a good value\r\n"
1324  "\r\n";
1325  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1326 
1327  uint8_t httpbuf4[] = "filecontent\r\n"
1328  "-----------------------------277531038314945--";
1329  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1330 
1331  TcpSession ssn;
1332  HtpState *http_state = NULL;
1334 
1335  memset(&ssn, 0, sizeof(ssn));
1336 
1337  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1338  if (f == NULL)
1339  goto end;
1340  f->protoctx = &ssn;
1341  f->proto = IPPROTO_TCP;
1342  f->alproto = ALPROTO_HTTP;
1343 
1345 
1346  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1347  FLOWLOCK_WRLOCK(f);
1348  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1349  STREAM_TOSERVER | STREAM_START, httpbuf1,
1350  httplen1);
1351  if (r != 0) {
1352  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1353  result = 0;
1354  FLOWLOCK_UNLOCK(f);
1355  goto end;
1356  }
1357  FLOWLOCK_UNLOCK(f);
1358 
1359  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1360  FLOWLOCK_WRLOCK(f);
1361  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1362  STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1363  if (r != 0) {
1364  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1365  result = 0;
1366  FLOWLOCK_UNLOCK(f);
1367  goto end;
1368  }
1369  FLOWLOCK_UNLOCK(f);
1370 
1371  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1372  FLOWLOCK_WRLOCK(f);
1373  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1374  STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
1375  if (r != 0) {
1376  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1377  result = 0;
1378  FLOWLOCK_UNLOCK(f);
1379  goto end;
1380  }
1381  FLOWLOCK_UNLOCK(f);
1382 
1383  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1384  FLOWLOCK_WRLOCK(f);
1385  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1386  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1387  if (r != 0) {
1388  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
1389  result = 0;
1390  FLOWLOCK_UNLOCK(f);
1391  goto end;
1392  }
1393  FLOWLOCK_UNLOCK(f);
1394 
1395  http_state = f->alstate;
1396  if (http_state == NULL) {
1397  printf("no http state: ");
1398  result = 0;
1399  goto end;
1400  }
1401 
1402  FLOWLOCK_WRLOCK(f);
1403  AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
1404  if (decoder_events != NULL) {
1405  printf("app events: ");
1406  FLOWLOCK_UNLOCK(f);
1407  goto end;
1408  }
1409  FLOWLOCK_UNLOCK(f);
1410 
1411  result = 1;
1412 end:
1413  if (alp_tctx != NULL)
1414  AppLayerParserThreadCtxFree(alp_tctx);
1416  UTHFreeFlow(f);
1417  return result;
1418 }
1419 
1420 /** \test filedata cut in two pieces */
1421 static int HTPFileParserTest11(void)
1422 {
1423  int result = 0;
1424  Flow *f = NULL;
1425  uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1426  "Host: www.server.lan\r\n"
1427  "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1428  "Content-Length: 1102\r\n"
1429  "\r\n";
1430  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1431 
1432  uint8_t httpbuf2[] = "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n";
1433  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1434 
1435  uint8_t httpbuf3[] = "Content-Disposition: form-data; name=\"PROGRESS_URL\"\r\n"
1436  "\r\n"
1437  "http://somserver.com/progress.php?UPLOAD_IDENTIFIER=XXXXXXXXX.XXXXXXXXXX.XXXXXXXX.XX.X\r\n"
1438  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1439  "Content-Disposition: form-data; name=\"DESTINATION_DIR\"\r\n"
1440  "\r\n"
1441  "10\r\n"
1442  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1443  "Content-Disposition: form-data; name=\"js_enabled\"\r\n"
1444  "\r\n"
1445  "1"
1446  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1447  "Content-Disposition: form-data; name=\"signature\"\r\n"
1448  "\r\n"
1449  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"
1450  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1451  "Content-Disposition: form-data; name=\"upload_files\"\r\n"
1452  "\r\n"
1453  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1454  "Content-Disposition: form-data; name=\"terms\"\r\n"
1455  "\r\n"
1456  "1"
1457  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1458  "Content-Disposition: form-data; name=\"file[]\"\r\n"
1459  "\r\n"
1460  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1461  "Content-Disposition: form-data; name=\"description[]\"\r\n"
1462  "\r\n"
1463  "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"
1464  "Content-Disposition: form-data; name=\"upload_file[]\"; filename=\"filename.doc\"\r\n"
1465  "Content-Type: application/msword\r\n"
1466  "\r\n"
1467  "FILE";
1468  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1469 
1470  uint8_t httpbuf4[] = "CONTENT\r\n"
1471  "------WebKitFormBoundaryBRDbP74mBhBxsIdo--";
1472  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1473 
1474  TcpSession ssn;
1475  HtpState *http_state = NULL;
1477 
1478  memset(&ssn, 0, sizeof(ssn));
1479 
1480  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1481  if (f == NULL)
1482  goto end;
1483  f->protoctx = &ssn;
1484  f->proto = IPPROTO_TCP;
1485  f->alproto = ALPROTO_HTTP;
1486 
1488 
1489  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
1490  FLOWLOCK_WRLOCK(f);
1491  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1492  STREAM_TOSERVER | STREAM_START, httpbuf1,
1493  httplen1);
1494  if (r != 0) {
1495  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1496  FLOWLOCK_UNLOCK(f);
1497  goto end;
1498  }
1499  FLOWLOCK_UNLOCK(f);
1500 
1501  SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2);
1502  FLOWLOCK_WRLOCK(f);
1503  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
1504  httpbuf2, httplen2);
1505  if (r != 0) {
1506  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1507  FLOWLOCK_UNLOCK(f);
1508  goto end;
1509  }
1510  FLOWLOCK_UNLOCK(f);
1511 
1512  SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3);
1513  FLOWLOCK_WRLOCK(f);
1514  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
1515  httpbuf3, httplen3);
1516  if (r != 0) {
1517  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1518  FLOWLOCK_UNLOCK(f);
1519  goto end;
1520  }
1521  FLOWLOCK_UNLOCK(f);
1522 
1523  SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4);
1524  FLOWLOCK_WRLOCK(f);
1525  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
1526  STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1527  if (r != 0) {
1528  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
1529  FLOWLOCK_UNLOCK(f);
1530  goto end;
1531  }
1532  FLOWLOCK_UNLOCK(f);
1533 
1534  http_state = f->alstate;
1535  if (http_state == NULL) {
1536  printf("no http state: ");
1537  goto end;
1538  }
1539 
1540  FLOWLOCK_WRLOCK(f);
1541  AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
1542  if (decoder_events != NULL) {
1543  printf("app events: ");
1544  FLOWLOCK_UNLOCK(f);
1545  goto end;
1546  }
1547  FLOWLOCK_UNLOCK(f);
1548 
1549  htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0);
1550  if (tx == NULL) {
1551  goto end;
1552  }
1553 
1554  if (tx->request_method == NULL || memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0)
1555  {
1556  printf("expected method POST, got %s \n", bstr_util_strdup_to_c(tx->request_method));
1557  goto end;
1558  }
1559 
1560  if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL ||
1561  http_state->files_ts->tail->state != FILE_STATE_CLOSED) {
1562  printf("state != FILE_STATE_CLOSED: ");
1563  goto end;
1564  }
1565 
1566  if (StreamingBufferCompareRawData(http_state->files_ts->head->sb,
1567  (uint8_t *)"FILECONTENT", 11) != 1)
1568  {
1569  goto end;
1570  }
1571 
1572  result = 1;
1573 end:
1574  if (alp_tctx != NULL)
1575  AppLayerParserThreadCtxFree(alp_tctx);
1577  UTHFreeFlow(f);
1578  return result;
1579 }
1580 
1581 #endif /* UNITTESTS */
1582 
1584 {
1585 #ifdef UNITTESTS
1586  UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01);
1587  UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02);
1588  UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03);
1589  UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04);
1590  UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05);
1591  UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06);
1592  UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07);
1593  UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08);
1594  UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09);
1595  UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10);
1596  UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11);
1597 #endif /* UNITTESTS */
1598 }
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:346
FileContainer * FileContainerAlloc(void)
allocate a FileContainer
Definition: util-file.c:380
HTPCfgDir response
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:235
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:756
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:232
#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:398
StreamingBuffer * sb
Definition: util-file.h:68
void * alstate
Definition: flow.h:436
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
File * head
Definition: util-file.h:99
#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 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:112
#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:941
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)
uint16_t file_flags
Definition: flow.h:379
AppProto alproto
application level protocol
Definition: flow.h:407
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:113
Flow data structure.
Definition: flow.h:327
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)