suricata
app-layer-htp.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2024 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  * \ingroup httplayer
20  *
21  * @{
22  */
23 
24 /**
25  * \file
26  *
27  * \author Victor Julien <victor@inliniac.net>
28  * \author Gurvinder Singh <gurvindersinghdahiya@gmail.com>
29  * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
30  * \author Brian Rectanus <brectanu@gmail.com>
31  * \author Anoop Saldanha <anoopsaldanha@gmail.com>
32  *
33  * This file provides a HTTP protocol support for the engine using HTP library.
34  */
35 
36 #include "suricata.h"
37 #include "suricata-common.h"
38 #include "conf.h"
39 #include "decode.h"
40 
41 #include "util-print.h"
42 #include "util-byte.h"
43 
44 #include "stream-tcp.h"
45 
46 #include "app-layer-protos.h"
47 #include "app-layer-parser.h"
48 
49 #include "app-layer.h"
50 #include "app-layer-detect-proto.h"
51 #include "app-layer-frames.h"
52 #include "app-layer-htp.h"
53 #include "app-layer-htp-body.h"
54 #include "app-layer-htp-file.h"
55 #include "app-layer-htp-xff.h"
56 #include "app-layer-htp-range.h"
57 #include "app-layer-htp-mem.h"
58 
59 #include "util-debug.h"
60 #include "util-misc.h"
61 
62 #include "util-unittest.h"
63 #include "util-unittest-helper.h"
64 #include "flow-util.h"
65 
66 #include "detect-engine.h"
67 #include "detect-engine-build.h"
68 #include "detect-engine-state.h"
69 #include "detect-parse.h"
70 
71 #include "util-memcmp.h"
72 #include "util-random.h"
73 #include "util-validate.h"
74 
75 //#define PRINT
76 
77 /** Fast lookup tree (radix) for the various HTP configurations */
78 static struct HTPConfigTree {
79  SCRadix4Tree ipv4;
80  SCRadix6Tree ipv6;
81 } cfgtree = {
84 };
85 SCRadix4Config htp_radix4_cfg = { NULL, NULL };
86 SCRadix6Config htp_radix6_cfg = { NULL, NULL };
87 
88 /** List of HTP configurations. */
89 static HTPCfgRec cfglist;
90 
92 
93 /** Limit to the number of libhtp messages that can be handled */
94 #define HTP_MAX_MESSAGES 512
95 
96 SC_ATOMIC_DECLARE(uint32_t, htp_config_flags);
97 
98 #ifdef DEBUG
99 static SCMutex htp_state_mem_lock = SCMUTEX_INITIALIZER;
100 static uint64_t htp_state_memuse = 0;
101 static uint64_t htp_state_memcnt = 0;
102 #endif
103 
105  { "UNKNOWN_ERROR", HTP_LOG_CODE_UNKNOWN },
106  { "GZIP_DECOMPRESSION_FAILED", HTP_LOG_CODE_GZIP_DECOMPRESSION_FAILED },
107  { "REQUEST_FIELD_MISSING_COLON", HTP_LOG_CODE_REQUEST_FIELD_MISSING_COLON },
108  { "RESPONSE_FIELD_MISSING_COLON", HTP_LOG_CODE_RESPONSE_FIELD_MISSING_COLON },
109  { "INVALID_REQUEST_CHUNK_LEN", HTP_LOG_CODE_INVALID_REQUEST_CHUNK_LEN },
110  { "INVALID_RESPONSE_CHUNK_LEN", HTP_LOG_CODE_INVALID_RESPONSE_CHUNK_LEN },
111  { "INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST",
112  HTP_LOG_CODE_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST },
113  { "INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE",
114  HTP_LOG_CODE_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE },
115  { "INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST",
116  HTP_LOG_CODE_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST },
117  { "INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE",
118  HTP_LOG_CODE_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE },
119  { "DUPLICATE_CONTENT_LENGTH_FIELD_IN_REQUEST",
120  HTP_LOG_CODE_DUPLICATE_CONTENT_LENGTH_FIELD_IN_REQUEST },
121  { "DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE",
122  HTP_LOG_CODE_DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE },
123  { "100_CONTINUE_ALREADY_SEEN", HTP_LOG_CODE_CONTINUE_ALREADY_SEEN },
124  { "UNABLE_TO_MATCH_RESPONSE_TO_REQUEST", HTP_LOG_CODE_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST },
125  { "INVALID_SERVER_PORT_IN_REQUEST", HTP_LOG_CODE_INVALID_SERVER_PORT_IN_REQUEST },
126  { "INVALID_AUTHORITY_PORT", HTP_LOG_CODE_INVALID_AUTHORITY_PORT },
127  { "REQUEST_HEADER_INVALID", HTP_LOG_CODE_REQUEST_HEADER_INVALID },
128  { "RESPONSE_HEADER_INVALID", HTP_LOG_CODE_RESPONSE_HEADER_INVALID },
129  { "MISSING_HOST_HEADER", HTP_LOG_CODE_MISSING_HOST_HEADER },
130  { "HOST_HEADER_AMBIGUOUS", HTP_LOG_CODE_HOST_HEADER_AMBIGUOUS },
131  { "INVALID_REQUEST_FIELD_FOLDING", HTP_LOG_CODE_INVALID_REQUEST_FIELD_FOLDING },
132  { "INVALID_RESPONSE_FIELD_FOLDING", HTP_LOG_CODE_INVALID_RESPONSE_FIELD_FOLDING },
133  { "REQUEST_FIELD_TOO_LONG", HTP_LOG_CODE_REQUEST_FIELD_TOO_LONG },
134  { "RESPONSE_FIELD_TOO_LONG", HTP_LOG_CODE_RESPONSE_FIELD_TOO_LONG },
135  { "REQUEST_LINE_INVALID", HTP_LOG_CODE_REQUEST_LINE_INVALID },
136  { "REQUEST_BODY_UNEXPECTED", HTP_LOG_CODE_REQUEST_BODY_UNEXPECTED },
137  { "RESPONSE_BODY_UNEXPECTED", HTP_LOG_CODE_RESPONSE_BODY_UNEXPECTED },
138  { "REQUEST_SERVER_PORT_TCP_PORT_MISMATCH", HTP_LOG_CODE_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH },
139  { "REQUEST_URI_HOST_INVALID", HTP_LOG_CODE_URI_HOST_INVALID },
140  { "REQUEST_HEADER_HOST_INVALID", HTP_LOG_CODE_HEADER_HOST_INVALID },
141  { "REQUEST_AUTH_UNRECOGNIZED", HTP_LOG_CODE_AUTH_UNRECOGNIZED },
142  { "REQUEST_HEADER_REPETITION", HTP_LOG_CODE_REQUEST_HEADER_REPETITION },
143  { "RESPONSE_HEADER_REPETITION", HTP_LOG_CODE_RESPONSE_HEADER_REPETITION },
144  { "DOUBLE_ENCODED_URI", HTP_LOG_CODE_DOUBLE_ENCODED_URI },
145  { "URI_DELIM_NON_COMPLIANT", HTP_LOG_CODE_URI_DELIM_NON_COMPLIANT },
146  { "METHOD_DELIM_NON_COMPLIANT", HTP_LOG_CODE_METHOD_DELIM_NON_COMPLIANT },
147  { "REQUEST_LINE_LEADING_WHITESPACE", HTP_LOG_CODE_REQUEST_LINE_LEADING_WHITESPACE },
148  { "TOO_MANY_ENCODING_LAYERS", HTP_LOG_CODE_TOO_MANY_ENCODING_LAYERS },
149  { "REQUEST_TOO_MANY_LZMA_LAYERS", HTP_LOG_CODE_REQUEST_TOO_MANY_LZMA_LAYERS },
150  { "RESPONSE_TOO_MANY_LZMA_LAYERS", HTP_LOG_CODE_RESPONSE_TOO_MANY_LZMA_LAYERS },
151  { "ABNORMAL_CE_HEADER", HTP_LOG_CODE_ABNORMAL_CE_HEADER },
152  { "RESPONSE_MULTIPART_BYTERANGES", HTP_LOG_CODE_RESPONSE_MULTIPART_BYTERANGES },
153  { "RESPONSE_ABNORMAL_TRANSFER_ENCODING", HTP_LOG_CODE_RESPONSE_ABNORMAL_TRANSFER_ENCODING },
154  { "RESPONSE_CHUNKED_OLD_PROTO", HTP_LOG_CODE_RESPONSE_CHUNKED_OLD_PROTO },
155  { "RESPONSE_INVALID_PROTOCOL", HTP_LOG_CODE_RESPONSE_INVALID_PROTOCOL },
156  { "RESPONSE_INVALID_STATUS", HTP_LOG_CODE_RESPONSE_INVALID_STATUS },
157  { "REQUEST_LINE_INCOMPLETE", HTP_LOG_CODE_REQUEST_LINE_INCOMPLETE },
158  { "PROTOCOL_CONTAINS_EXTRA_DATA", HTP_LOG_CODE_PROTOCOL_CONTAINS_EXTRA_DATA },
159  {
160  "CONTENT_LENGTH_EXTRA_DATA_START",
161  HTP_LOG_CODE_CONTENT_LENGTH_EXTRA_DATA_START,
162  },
163  {
164  "CONTENT_LENGTH_EXTRA_DATA_END",
165  HTP_LOG_CODE_CONTENT_LENGTH_EXTRA_DATA_END,
166  },
167  {
168  "CONTENT_LENGTH_EXTRA_DATA_END",
169  HTP_LOG_CODE_CONTENT_LENGTH_EXTRA_DATA_END,
170  },
171  { "SWITCHING_PROTO_WITH_CONTENT_LENGTH", HTP_LOG_CODE_SWITCHING_PROTO_WITH_CONTENT_LENGTH },
172  { "DEFORMED_EOL", HTP_LOG_CODE_DEFORMED_EOL },
173  { "PARSER_STATE_ERROR", HTP_LOG_CODE_PARSER_STATE_ERROR },
174  { "MISSING_OUTBOUND_TRANSACTION_DATA", HTP_LOG_CODE_MISSING_OUTBOUND_TRANSACTION_DATA },
175  { "MISSING_INBOUND_TRANSACTION_DATA", HTP_LOG_CODE_MISSING_INBOUND_TRANSACTION_DATA },
176  { "MISSING_INBOUND_TRANSACTION_DATA", HTP_LOG_CODE_MISSING_INBOUND_TRANSACTION_DATA },
177  { "ZERO_LENGTH_DATA_CHUNKS", HTP_LOG_CODE_ZERO_LENGTH_DATA_CHUNKS },
178  { "REQUEST_LINE_UNKNOWN_METHOD", HTP_LOG_CODE_REQUEST_LINE_UNKNOWN_METHOD },
179  { "REQUEST_LINE_UNKNOWN_METHOD", HTP_LOG_CODE_REQUEST_LINE_UNKNOWN_METHOD },
180  { "REQUEST_LINE_UNKNOWN_METHOD_NO_PROTOCOL",
181  HTP_LOG_CODE_REQUEST_LINE_UNKNOWN_METHOD_NO_PROTOCOL },
182  { "REQUEST_LINE_UNKNOWN_METHOD_INVALID_PROTOCOL",
183  HTP_LOG_CODE_REQUEST_LINE_UNKNOWN_METHOD_INVALID_PROTOCOL },
184  { "REQUEST_LINE_MISSING_PROTOCOL", HTP_LOG_CODE_REQUEST_LINE_NO_PROTOCOL },
185  { "RESPONSE_LINE_INVALID_PROTOCOL", HTP_LOG_CODE_RESPONSE_LINE_INVALID_PROTOCOL },
186  { "RESPONSE_LINE_INVALID_RESPONSE_STATUS", HTP_LOG_CODE_RESPONSE_LINE_INVALID_RESPONSE_STATUS },
187  { "RESPONSE_BODY_INTERNAL_ERROR", HTP_LOG_CODE_RESPONSE_BODY_INTERNAL_ERROR },
188  { "REQUEST_BODY_DATA_CALLBACK_ERROR", HTP_LOG_CODE_REQUEST_BODY_DATA_CALLBACK_ERROR },
189  { "RESPONSE_INVALID_EMPTY_NAME", HTP_LOG_CODE_RESPONSE_INVALID_EMPTY_NAME },
190  { "REQUEST_INVALID_EMPTY_NAME", HTP_LOG_CODE_REQUEST_INVALID_EMPTY_NAME },
191  { "RESPONSE_INVALID_LWS_AFTER_NAME", HTP_LOG_CODE_RESPONSE_INVALID_LWS_AFTER_NAME },
192  { "RESPONSE_HEADER_NAME_NOT_TOKEN", HTP_LOG_CODE_RESPONSE_HEADER_NAME_NOT_TOKEN },
193  { "REQUEST_INVALID_LWS_AFTER_NAME", HTP_LOG_CODE_REQUEST_INVALID_LWS_AFTER_NAME },
194  { "LZMA_DECOMPRESSION_DISABLED", HTP_LOG_CODE_LZMA_DECOMPRESSION_DISABLED },
195  { "CONNECTION_ALREADY_OPEN", HTP_LOG_CODE_CONNECTION_ALREADY_OPEN },
196  { "COMPRESSION_BOMB_DOUBLE_LZMA", HTP_LOG_CODE_COMPRESSION_BOMB_DOUBLE_LZMA },
197  { "INVALID_CONTENT_ENCODING", HTP_LOG_CODE_INVALID_CONTENT_ENCODING },
198  { "INVALID_GAP", HTP_LOG_CODE_INVALID_GAP },
199  { "REQUEST_CHUNK_EXTENSION", HTP_LOG_CODE_REQUEST_CHUNK_EXTENSION },
200  { "RESPONSE_CHUNK_EXTENSION", HTP_LOG_CODE_RESPONSE_CHUNK_EXTENSION },
201 
202  { "LZMA_MEMLIMIT_REACHED", HTP_LOG_CODE_LZMA_MEMLIMIT_REACHED },
203  { "COMPRESSION_BOMB", HTP_LOG_CODE_COMPRESSION_BOMB },
204 
205  { "REQUEST_TOO_MANY_HEADERS", HTP_LOG_CODE_REQUEST_TOO_MANY_HEADERS },
206  { "RESPONSE_TOO_MANY_HEADERS", HTP_LOG_CODE_RESPONSE_TOO_MANY_HEADERS },
207 
208  /* suricata warnings/errors */
209  { "MULTIPART_GENERIC_ERROR", HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR },
210  { "MULTIPART_NO_FILEDATA", HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA },
211  { "MULTIPART_INVALID_HEADER", HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER },
212  { "TOO_MANY_WARNINGS", HTTP_DECODER_EVENT_TOO_MANY_WARNINGS },
213  { "RANGE_INVALID", HTTP_DECODER_EVENT_RANGE_INVALID },
214  { "FILE_NAME_TOO_LONG", HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG },
215  { "FAILED_PROTOCOL_CHANGE", HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE },
216 
217  { NULL, -1 },
218 };
219 
220 /* app-layer-frame-documentation tag start: HttpFrameTypes */
224 };
225 
227  {
228  "request",
230  },
231  {
232  "response",
234  },
235  { NULL, -1 },
236 };
237 /* app-layer-frame-documentation tag end: HttpFrameTypes */
238 
239 static int HTTPGetFrameIdByName(const char *frame_name)
240 {
241  int id = SCMapEnumNameToValue(frame_name, http_frame_table);
242  if (id < 0) {
243  return -1;
244  }
245  return id;
246 }
247 
248 static const char *HTTPGetFrameNameById(const uint8_t frame_id)
249 {
250  const char *name = SCMapEnumValueToName(frame_id, http_frame_table);
251  return name;
252 }
253 
254 static SCEnumCharMap http_state_client_table[] = {
255  {
256  // name this "request_started" as the tx has been created
257  "request_started",
258  HTP_REQUEST_PROGRESS_NOT_STARTED,
259  },
260  {
261  "request_line",
262  HTP_REQUEST_PROGRESS_LINE,
263  },
264  {
265  "request_headers",
266  HTP_REQUEST_PROGRESS_HEADERS,
267  },
268  {
269  "request_body",
270  HTP_REQUEST_PROGRESS_BODY,
271  },
272  {
273  "request_trailer",
274  HTP_REQUEST_PROGRESS_TRAILER,
275  },
276  {
277  "request_complete",
278  HTP_REQUEST_PROGRESS_COMPLETE,
279  },
280  { NULL, -1 },
281 };
282 
283 static SCEnumCharMap http_state_server_table[] = {
284  {
285  // name this "response_started" as the tx has been created
286  "response_started",
287  HTP_RESPONSE_PROGRESS_NOT_STARTED,
288  },
289  {
290  "response_line",
291  HTP_RESPONSE_PROGRESS_LINE,
292  },
293  {
294  "response_headers",
295  HTP_RESPONSE_PROGRESS_HEADERS,
296  },
297  {
298  "response_body",
299  HTP_RESPONSE_PROGRESS_BODY,
300  },
301  {
302  "response_trailer",
303  HTP_RESPONSE_PROGRESS_TRAILER,
304  },
305  {
306  "response_complete",
307  HTP_RESPONSE_PROGRESS_COMPLETE,
308  },
309  { NULL, -1 },
310 };
311 
312 static int HtpStateGetStateIdByName(const char *name, const uint8_t direction)
313 {
314  SCEnumCharMap *map =
315  direction == STREAM_TOSERVER ? http_state_client_table : http_state_server_table;
316 
317  int id = SCMapEnumNameToValue(name, map);
318  if (id < 0) {
319  return -1;
320  }
321  return id;
322 }
323 
324 static const char *HtpStateGetStateNameById(const int id, const uint8_t direction)
325 {
326  SCEnumCharMap *map =
327  direction == STREAM_TOSERVER ? http_state_client_table : http_state_server_table;
328  const char *name = SCMapEnumValueToName(id, map);
329  return name;
330 }
331 
332 static void *HTPStateGetTx(void *alstate, uint64_t tx_id);
333 static int HTPStateGetAlstateProgress(void *tx, uint8_t direction);
334 static uint64_t HTPStateGetTxCnt(void *alstate);
335 #ifdef UNITTESTS
336 static void HTPParserRegisterTests(void);
337 #endif
338 
339 static inline uint64_t HtpGetActiveRequestTxID(HtpState *s)
340 {
341  uint64_t id = HTPStateGetTxCnt(s);
342  BUG_ON(id == 0);
343  return id - 1;
344 }
345 
346 static inline uint64_t HtpGetActiveResponseTxID(HtpState *s)
347 {
348  return s->transaction_cnt;
349 }
350 
351 #ifdef DEBUG
352 /**
353  * \internal
354  *
355  * \brief Lookup the HTP personality string from the numeric personality.
356  *
357  * \todo This needs to be a libhtp function.
358  */
359 static const char *HTPLookupPersonalityString(int p)
360 {
361 #define CASE_HTP_PERSONALITY_STRING(p) \
362  case HTP_SERVER_PERSONALITY_##p: \
363  return #p
364 
365  switch (p) {
366  CASE_HTP_PERSONALITY_STRING(MINIMAL);
367  CASE_HTP_PERSONALITY_STRING(GENERIC);
368  CASE_HTP_PERSONALITY_STRING(IDS);
369  CASE_HTP_PERSONALITY_STRING(IIS_4_0);
370  CASE_HTP_PERSONALITY_STRING(IIS_5_0);
371  CASE_HTP_PERSONALITY_STRING(IIS_5_1);
372  CASE_HTP_PERSONALITY_STRING(IIS_6_0);
373  CASE_HTP_PERSONALITY_STRING(IIS_7_0);
374  CASE_HTP_PERSONALITY_STRING(IIS_7_5);
375  CASE_HTP_PERSONALITY_STRING(APACHE_2);
376  }
377 
378  return NULL;
379 }
380 #endif /* DEBUG */
381 
382 /**
383  * \internal
384  *
385  * \brief Lookup the numeric HTP personality from a string.
386  *
387  * \todo This needs to be a libhtp function.
388  */
389 static int HTPLookupPersonality(const char *str)
390 {
391 #define IF_HTP_PERSONALITY_NUM(p) \
392  if (strcasecmp(#p, str) == 0) \
393  return HTP_SERVER_PERSONALITY_##p
394 
395  IF_HTP_PERSONALITY_NUM(MINIMAL);
396  IF_HTP_PERSONALITY_NUM(GENERIC);
398  IF_HTP_PERSONALITY_NUM(IIS_4_0);
399  IF_HTP_PERSONALITY_NUM(IIS_5_0);
400  IF_HTP_PERSONALITY_NUM(IIS_5_1);
401  IF_HTP_PERSONALITY_NUM(IIS_6_0);
402  IF_HTP_PERSONALITY_NUM(IIS_7_0);
403  IF_HTP_PERSONALITY_NUM(IIS_7_5);
404  IF_HTP_PERSONALITY_NUM(APACHE_2);
405  if (strcasecmp("TOMCAT_6_0", str) == 0) {
406  SCLogError("Personality %s no "
407  "longer supported by libhtp.",
408  str);
409  return -1;
410  } else if ((strcasecmp("APACHE", str) == 0) ||
411  (strcasecmp("APACHE_2_2", str) == 0))
412  {
413  SCLogWarning("Personality %s no "
414  "longer supported by libhtp, failing back to "
415  "Apache2 personality.",
416  str);
417  return HTP_SERVER_PERSONALITY_APACHE_2;
418  }
419 
420  return -1;
421 }
422 
423 static void HTPSetEvent(HtpState *s, HtpTxUserData *htud,
424  const uint8_t dir, const uint8_t e)
425 {
426  SCLogDebug("setting event %u", e);
427 
428  if (htud) {
429  AppLayerDecoderEventsSetEventRaw(&htud->tx_data.events, e);
430  s->events++;
431  return;
432  }
433 
434  const uint64_t tx_id = (dir == STREAM_TOSERVER) ?
435  HtpGetActiveRequestTxID(s) : HtpGetActiveResponseTxID(s);
436 
437  htp_tx_t *tx = HTPStateGetTx(s, tx_id);
438  if (tx == NULL && tx_id > 0)
439  tx = HTPStateGetTx(s, tx_id - 1);
440  if (tx != NULL) {
441  htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
442  AppLayerDecoderEventsSetEventRaw(&htud->tx_data.events, e);
443  s->events++;
444  return;
445  }
446  SCLogDebug("couldn't set event %u", e);
447 }
448 
449 /** \brief Function to allocates the HTTP state memory and also creates the HTTP
450  * connection parser to be used by the HTP library
451  */
452 static void *HTPStateAlloc(void *orig_state, AppProto proto_orig)
453 {
454  SCEnter();
455 
456  HtpState *s = HTPMalloc(sizeof(HtpState));
457  if (unlikely(s == NULL)) {
458  SCReturnPtr(NULL, "void");
459  }
460 
461  memset(s, 0x00, sizeof(HtpState));
462 
463 #ifdef DEBUG
464  SCMutexLock(&htp_state_mem_lock);
465  htp_state_memcnt++;
466  htp_state_memuse += sizeof(HtpState);
467  SCLogDebug("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
468  SCMutexUnlock(&htp_state_mem_lock);
469 #endif
470 
471  SCReturnPtr((void *)s, "void");
472 }
473 
474 static void HtpTxUserDataFree(void *txud)
475 {
476  HtpTxUserData *htud = (HtpTxUserData *)txud;
477  if (likely(htud)) {
478  HtpBodyFree(&htud->request_body);
479  HtpBodyFree(&htud->response_body);
480  if (htud->request_headers_raw)
482  if (htud->response_headers_raw)
484  if (htud->mime_state)
485  SCMimeStateFree(htud->mime_state);
486  SCAppLayerTxDataCleanup(&htud->tx_data);
487  if (htud->file_range) {
488  HTPFileCloseHandleRange(&htp_sbcfg, &htud->files_tc, 0, htud->file_range, NULL, 0);
490  }
493  HTPFree(htud, sizeof(HtpTxUserData));
494  }
495 }
496 
497 /** \brief Function to frees the HTTP state memory and also frees the HTTP
498  * connection parser memory which was used by the HTP library
499  */
500 void HTPStateFree(void *state)
501 {
502  SCEnter();
503 
504  HtpState *s = (HtpState *)state;
505  if (s == NULL) {
506  SCReturn;
507  }
508 
509  /* free the connection parser memory used by HTP library */
510  if (s->connp != NULL) {
511  SCLogDebug("freeing HTP state");
512  htp_connp_destroy_all(s->connp);
513  }
514 
515  HTPFree(s, sizeof(HtpState));
516 
517 #ifdef DEBUG
518  SCMutexLock(&htp_state_mem_lock);
519  htp_state_memcnt--;
520  htp_state_memuse -= sizeof(HtpState);
521  SCLogDebug("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
522  SCMutexUnlock(&htp_state_mem_lock);
523 #endif
524 
525  SCReturn;
526 }
527 
528 /**
529  * \brief HTP transaction cleanup callback
530  *
531  */
532 static void HTPStateTransactionFree(void *state, uint64_t id)
533 {
534  SCEnter();
535 
536  HtpState *s = (HtpState *)state;
537 
538  SCLogDebug("state %p, id %"PRIu64, s, id);
539 
540  htp_tx_t *tx = HTPStateGetTx(s, id);
541  if (tx != NULL) {
542  htp_tx_destroy(s->connp, tx);
543  }
544 }
545 
546 /**
547  * \brief Sets a flag that informs the HTP app layer that some module in the
548  * engine needs the http request body data.
549  * \initonly
550  */
552 {
553  SCEnter();
554 
555  SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_BODY);
556  SCReturn;
557 }
558 
559 /**
560  * \brief Sets a flag that informs the HTP app layer that some module in the
561  * engine needs the http request body data.
562  * \initonly
563  */
565 {
566  SCEnter();
567 
568  SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_RESPONSE_BODY);
569  SCReturn;
570 }
571 
572 /**
573  * \brief Sets a flag that informs the HTP app layer that some module in the
574  * engine needs the http request file.
575  *
576  * \initonly
577  */
579 {
580  SCEnter();
583 
584  SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_FILE);
585  SCReturn;
586 }
587 
588 static void AppLayerHtpSetStreamDepthFlag(void *tx, const uint8_t flags)
589 {
590  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data((htp_tx_t *)tx);
591  SCLogDebug("setting HTP_STREAM_DEPTH_SET, flags %02x", flags);
592  if (flags & STREAM_TOCLIENT) {
593  tx_ud->tcflags |= HTP_STREAM_DEPTH_SET;
594  } else {
595  tx_ud->tsflags |= HTP_STREAM_DEPTH_SET;
596  }
597 }
598 
599 static bool AppLayerHtpCheckDepth(const HTPCfgDir *cfg, HtpBody *body, uint8_t flags)
600 {
601  SCLogDebug("cfg->body_limit %u stream_depth %u body->content_len_so_far %" PRIu64,
603  if (flags & HTP_STREAM_DEPTH_SET) {
604  uint32_t stream_depth = FileReassemblyDepth();
605  if (body->content_len_so_far < (uint64_t)stream_depth || stream_depth == 0) {
606  SCLogDebug("true");
607  return true;
608  }
609  } else {
610  if (cfg->body_limit == 0 || body->content_len_so_far < cfg->body_limit) {
611  return true;
612  }
613  }
614  SCLogDebug("false");
615  return false;
616 }
617 
618 static uint32_t AppLayerHtpComputeChunkLength(uint64_t content_len_so_far, uint32_t body_limit,
619  uint32_t stream_depth, uint8_t flags, uint32_t data_len)
620 {
621  uint32_t chunk_len = 0;
622  if (!(flags & HTP_STREAM_DEPTH_SET) && body_limit > 0 &&
623  (content_len_so_far < (uint64_t)body_limit) &&
624  (content_len_so_far + (uint64_t)data_len) > body_limit)
625  {
626  chunk_len = (uint32_t)(body_limit - content_len_so_far);
627  } else if ((flags & HTP_STREAM_DEPTH_SET) && stream_depth > 0 &&
628  (content_len_so_far < (uint64_t)stream_depth) &&
629  (content_len_so_far + (uint64_t)data_len) > stream_depth)
630  {
631  chunk_len = (uint32_t)(stream_depth - content_len_so_far);
632  }
633  SCLogDebug("len %u", chunk_len);
634  return (chunk_len == 0 ? data_len : chunk_len);
635 }
636 
637 /**
638  * \internal
639  *
640  * \brief Check state for errors, warnings and add any as events
641  *
642  * \param s state
643  * \param dir direction: STREAM_TOSERVER or STREAM_TOCLIENT
644  */
645 static void HTPHandleError(HtpState *s, const uint8_t dir)
646 {
647  if (s == NULL || s->conn == NULL || s->htp_messages_count >= HTP_MAX_MESSAGES) {
648  // ignore further messages
649  return;
650  }
651 
652  htp_log_t *log = htp_conn_next_log(s->conn);
653  while (log != NULL) {
654  char *msg = htp_log_message(log);
655  if (msg == NULL) {
656  htp_log_free(log);
657  log = htp_conn_next_log(s->conn);
658  continue;
659  }
660 
661  SCLogDebug("message %s", msg);
662 
663  htp_log_code_t id = htp_log_code(log);
664  if (id != HTP_LOG_CODE_UNKNOWN && id != HTP_LOG_CODE_ERROR) {
665  HTPSetEvent(s, NULL, dir, (uint8_t)id);
666  }
667  htp_free_cstring(msg);
668  htp_log_free(log);
669  s->htp_messages_count++;
671  // only once per HtpState
672  HTPSetEvent(s, NULL, dir, HTTP_DECODER_EVENT_TOO_MANY_WARNINGS);
673  // too noisy in fuzzing
674  // DEBUG_VALIDATE_BUG_ON("Too many libhtp messages");
675  break;
676  }
677  log = htp_conn_next_log(s->conn);
678  }
679  SCLogDebug("s->htp_messages_count %u", s->htp_messages_count);
680 }
681 
682 static inline void HTPErrorCheckTxRequestFlags(HtpState *s, const htp_tx_t *tx)
683 {
684 #ifdef DEBUG
685  BUG_ON(s == NULL || tx == NULL);
686 #endif
687  if (htp_tx_flags(tx) & (HTP_FLAGS_REQUEST_INVALID_T_E | HTP_FLAGS_REQUEST_INVALID_C_L |
688  HTP_FLAGS_HOST_MISSING | HTP_FLAGS_HOST_AMBIGUOUS |
689  HTP_FLAGS_HOSTU_INVALID | HTP_FLAGS_HOSTH_INVALID)) {
690  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
691 
692  if (htp_tx_flags(tx) & HTP_FLAGS_REQUEST_INVALID_T_E)
693  HTPSetEvent(s, htud, STREAM_TOSERVER,
694  HTP_LOG_CODE_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST);
695  if (htp_tx_flags(tx) & HTP_FLAGS_REQUEST_INVALID_C_L)
696  HTPSetEvent(
697  s, htud, STREAM_TOSERVER, HTP_LOG_CODE_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST);
698  if (htp_tx_flags(tx) & HTP_FLAGS_HOST_MISSING)
699  HTPSetEvent(s, htud, STREAM_TOSERVER, HTP_LOG_CODE_MISSING_HOST_HEADER);
700  if (htp_tx_flags(tx) & HTP_FLAGS_HOST_AMBIGUOUS)
701  HTPSetEvent(s, htud, STREAM_TOSERVER, HTP_LOG_CODE_HOST_HEADER_AMBIGUOUS);
702  if (htp_tx_flags(tx) & HTP_FLAGS_HOSTU_INVALID)
703  HTPSetEvent(s, htud, STREAM_TOSERVER, HTP_LOG_CODE_URI_HOST_INVALID);
704  if (htp_tx_flags(tx) & HTP_FLAGS_HOSTH_INVALID)
705  HTPSetEvent(s, htud, STREAM_TOSERVER, HTP_LOG_CODE_HEADER_HOST_INVALID);
706  }
707  if (htp_tx_request_auth_type(tx) == HTP_AUTH_TYPE_UNRECOGNIZED) {
708  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
709  HTPSetEvent(s, htud, STREAM_TOSERVER, HTP_LOG_CODE_AUTH_UNRECOGNIZED);
710  }
711  if (htp_tx_is_protocol_0_9(tx) && htp_tx_request_method_number(tx) == HTP_METHOD_UNKNOWN &&
712  (htp_tx_request_protocol_number(tx) == HTP_PROTOCOL_INVALID ||
713  htp_tx_request_protocol_number(tx) == HTP_PROTOCOL_UNKNOWN)) {
714  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
715  HTPSetEvent(s, htud, STREAM_TOSERVER, HTP_LOG_CODE_REQUEST_LINE_INVALID);
716  }
717 }
718 
719 static int Setup(Flow *f, HtpState *hstate)
720 {
721  /* store flow ref in state so callbacks can access it */
722  hstate->f = f;
723 
724  HTPCfgRec *htp_cfg_rec = &cfglist;
725  htp_cfg_t *htp = cfglist.cfg; /* Default to the global HTP config */
726  void *user_data = NULL;
727 
728  if (FLOW_IS_IPV4(f)) {
729  SCLogDebug("Looking up HTP config for ipv4 %08x", *GET_IPV4_DST_ADDR_PTR(f));
731  &cfgtree.ipv4, (uint8_t *)GET_IPV4_DST_ADDR_PTR(f), &user_data);
732  }
733  else if (FLOW_IS_IPV6(f)) {
734  SCLogDebug("Looking up HTP config for ipv6");
735  (void)SCRadix6TreeFindBestMatch(&cfgtree.ipv6, (uint8_t *)GET_IPV6_DST_ADDR(f), &user_data);
736  }
737  else {
738  SCLogError("unknown address family, bug!");
739  goto error;
740  }
741 
742  if (user_data != NULL) {
743  htp_cfg_rec = user_data;
744  htp = htp_cfg_rec->cfg;
745  SCLogDebug("LIBHTP using config: %p", htp);
746  } else {
747  SCLogDebug("Using default HTP config: %p", htp);
748  }
749 
750  if (NULL == htp) {
751 #ifdef DEBUG_VALIDATION
752  BUG_ON(htp == NULL);
753 #endif
754  /* should never happen if HTPConfigure is properly invoked */
755  goto error;
756  }
757 
758  hstate->connp = htp_connp_create(htp);
759  if (hstate->connp == NULL) {
760  goto error;
761  }
762 
763  hstate->conn = (htp_conn_t *)htp_connp_connection(hstate->connp);
764 
765  htp_connp_set_user_data(hstate->connp, (void *)hstate);
766  hstate->cfg = htp_cfg_rec;
767 
768  SCLogDebug("New hstate->connp %p", hstate->connp);
769 
770  struct timeval tv = { SCTIME_SECS(f->startts), SCTIME_USECS(f->startts) };
771  htp_connp_open(hstate->connp, NULL, f->sp, NULL, f->dp, &tv);
772 
774  htp_cfg_rec->request.inspect_min_size);
776  htp_cfg_rec->response.inspect_min_size);
777  return 0;
778 error:
779  return -1;
780 }
781 
782 /**
783  * \brief Function to handle the reassembled data from client and feed it to
784  * the HTP library to process it.
785  *
786  * \param flow Pointer to the flow the data belong to
787  * \param htp_state Pointer the state in which the parsed value to be stored
788  * \param pstate Application layer parser state for this session
789  *
790  * \retval On success returns 1 or on failure returns -1.
791  */
792 static AppLayerResult HTPHandleRequestData(Flow *f, void *htp_state, AppLayerParserState *pstate,
793  StreamSlice stream_slice, void *local_data)
794 {
795  SCEnter();
796  int ret = 0;
797  HtpState *hstate = (HtpState *)htp_state;
798 
799  /* On the first invocation, create the connection parser structure to
800  * be used by HTP library. This is looked up via IP in the radix
801  * tree. Failing that, the default HTP config is used.
802  */
803  if (NULL == hstate->conn) {
804  if (Setup(f, hstate) != 0) {
806  }
807  }
808  DEBUG_VALIDATE_BUG_ON(hstate->connp == NULL);
809  hstate->slice = &stream_slice;
810 
811  const uint8_t *input = StreamSliceGetData(&stream_slice);
812  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
813 
814  struct timeval ts = { SCTIME_SECS(f->startts), SCTIME_USECS(f->startts) };
815  /* pass the new data to the htp parser */
816  if (input_len > 0) {
817  const int r = htp_connp_request_data(hstate->connp, &ts, input, input_len);
818  switch (r) {
819  case HTP_STREAM_STATE_ERROR:
820  ret = -1;
821  break;
822  default:
823  break;
824  }
825  HTPHandleError(hstate, STREAM_TOSERVER);
826  }
827 
828  /* if the TCP connection is closed, then close the HTTP connection */
830  !(hstate->flags & HTP_FLAG_STATE_CLOSED_TS))
831  {
832  htp_connp_request_close(hstate->connp, &ts);
833  hstate->flags |= HTP_FLAG_STATE_CLOSED_TS;
834  SCLogDebug("stream eof encountered, closing htp handle for ts");
835  }
836 
837  SCLogDebug("hstate->connp %p", hstate->connp);
838  hstate->slice = NULL;
839 
840  if (ret < 0) {
842  }
844 }
845 
846 /**
847  * \brief Function to handle the reassembled data from server and feed it to
848  * the HTP library to process it.
849  *
850  * \param flow Pointer to the flow the data belong to
851  * \param htp_state Pointer the state in which the parsed value to be stored
852  * \param pstate Application layer parser state for this session
853  * \param input Pointer the received HTTP server data
854  * \param input_len Length in bytes of the received data
855  * \param output Pointer to the output (not used in this function)
856  *
857  * \retval On success returns 1 or on failure returns -1
858  */
859 static AppLayerResult HTPHandleResponseData(Flow *f, void *htp_state, AppLayerParserState *pstate,
860  StreamSlice stream_slice, void *local_data)
861 {
862  SCEnter();
863  int ret = 0;
864  HtpState *hstate = (HtpState *)htp_state;
865 
866  const uint8_t *input = StreamSliceGetData(&stream_slice);
867  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
868 
869  /* On the first invocation, create the connection parser structure to
870  * be used by HTP library. This is looked up via IP in the radix
871  * tree. Failing that, the default HTP config is used.
872  */
873  if (NULL == hstate->conn) {
874  if (Setup(f, hstate) != 0) {
876  }
877  }
878  DEBUG_VALIDATE_BUG_ON(hstate->connp == NULL);
879  hstate->slice = &stream_slice;
880 
881  struct timeval ts = { SCTIME_SECS(f->startts), SCTIME_USECS(f->startts) };
882  const htp_tx_t *tx = NULL;
883  uint32_t consumed = 0;
884  if (input_len > 0) {
885  const int r = htp_connp_response_data(hstate->connp, &ts, input, input_len);
886  switch (r) {
887  case HTP_STREAM_STATE_ERROR:
888  ret = -1;
889  break;
890  case HTP_STREAM_STATE_TUNNEL:
891  tx = htp_connp_get_response_tx(hstate->connp);
892  if (tx != NULL && htp_tx_response_status_number(tx) == 101) {
893  const htp_header_t *h = htp_tx_response_header(tx, "Upgrade");
894  if (h == NULL) {
895  break;
896  }
897  uint16_t dp = 0;
898  if (htp_tx_request_port_number(tx) != -1) {
899  dp = (uint16_t)htp_tx_request_port_number(tx);
900  }
901  consumed = (uint32_t)htp_connp_response_data_consumed(hstate->connp);
902  if (bstr_cmp_c(htp_header_value(h), "h2c") == 0) {
904  // if HTTP2 is disabled, keep the HTP_STREAM_STATE_TUNNEL mode
905  break;
906  }
907  hstate->slice = NULL;
908  if (!AppLayerRequestProtocolChange(hstate->f, dp, ALPROTO_HTTP2)) {
909  HTPSetEvent(hstate, NULL, STREAM_TOCLIENT,
911  }
912  // During HTTP2 upgrade, we may consume the HTTP1 part of the data
913  // and we need to parser the remaining part with HTTP2
914  if (consumed > 0 && consumed < input_len) {
915  SCReturnStruct(APP_LAYER_INCOMPLETE(consumed, input_len - consumed));
916  }
918  } else if (bstr_cmp_c_nocase(htp_header_value(h), "WebSocket")) {
920  // if WS is disabled, keep the HTP_STREAM_STATE_TUNNEL mode
921  break;
922  }
923  hstate->slice = NULL;
925  HTPSetEvent(hstate, NULL, STREAM_TOCLIENT,
927  }
928  // During WS upgrade, we may consume the HTTP1 part of the data
929  // and we need to parser the remaining part with WS
930  if (consumed > 0 && consumed < input_len) {
931  SCReturnStruct(APP_LAYER_INCOMPLETE(consumed, input_len - consumed));
932  }
934  }
935  }
936  break;
937  default:
938  break;
939  }
940  HTPHandleError(hstate, STREAM_TOCLIENT);
941  }
942 
943  /* if we the TCP connection is closed, then close the HTTP connection */
945  !(hstate->flags & HTP_FLAG_STATE_CLOSED_TC))
946  {
947  htp_connp_close(hstate->connp, &ts);
948  hstate->flags |= HTP_FLAG_STATE_CLOSED_TC;
949  }
950 
951  SCLogDebug("hstate->connp %p", hstate->connp);
952  hstate->slice = NULL;
953 
954  if (ret < 0) {
956  }
958 }
959 
960 /**
961  * \param name /Lowercase/ version of the variable name
962  */
963 static int HTTPParseContentDispositionHeader(const uint8_t *name, size_t name_len,
964  const uint8_t *data, size_t len, uint8_t const **retptr, size_t *retlen)
965 {
966 #ifdef PRINT
967  printf("DATA START: \n");
968  PrintRawDataFp(stdout, data, len);
969  printf("DATA END: \n");
970 #endif
971  size_t x;
972  int quote = 0;
973 
974  for (x = 0; x < len; x++) {
975  if (!(isspace(data[x])))
976  break;
977  }
978 
979  if (x >= len)
980  return 0;
981 
982  const uint8_t *line = data + x;
983  size_t line_len = len-x;
984  size_t offset = 0;
985 #ifdef PRINT
986  printf("LINE START: \n");
987  PrintRawDataFp(stdout, line, line_len);
988  printf("LINE END: \n");
989 #endif
990  for (x = 0 ; x < line_len; x++) {
991  if (x > 0) {
992  if (line[x - 1] != '\\' && line[x] == '\"') {
993  quote++;
994  }
995 
996  if (((line[x - 1] != '\\' && line[x] == ';') || ((x + 1) == line_len)) && (quote == 0 || quote % 2 == 0)) {
997  const uint8_t *token = line + offset;
998  size_t token_len = x - offset;
999 
1000  if ((x + 1) == line_len) {
1001  token_len++;
1002  }
1003 
1004  offset = x + 1;
1005 
1006  while (offset < line_len && isspace(line[offset])) {
1007  x++;
1008  offset++;
1009  }
1010 #ifdef PRINT
1011  printf("TOKEN START: \n");
1012  PrintRawDataFp(stdout, token, token_len);
1013  printf("TOKEN END: \n");
1014 #endif
1015  if (token_len > name_len) {
1016  if (name == NULL || SCMemcmpLowercase(name, token, name_len) == 0) {
1017  const uint8_t *value = token + name_len;
1018  size_t value_len = token_len - name_len;
1019 
1020  if (value[0] == '\"') {
1021  value++;
1022  value_len--;
1023  }
1024  if (value[value_len-1] == '\"') {
1025  value_len--;
1026  }
1027 #ifdef PRINT
1028  printf("VALUE START: \n");
1029  PrintRawDataFp(stdout, value, value_len);
1030  printf("VALUE END: \n");
1031 #endif
1032  *retptr = value;
1033  *retlen = value_len;
1034  return 1;
1035  }
1036  }
1037  }
1038  }
1039  }
1040 
1041  return 0;
1042 }
1043 
1044 /**
1045  * \brief setup multipart parsing: extract boundary and store it
1046  *
1047  * \param d HTTP transaction
1048  * \param htud transaction userdata
1049  *
1050  * \retval 1 ok, multipart set up
1051  * \retval 0 ok, not multipart though
1052  * \retval -1 error: problem with the boundary
1053  *
1054  * If the request contains a multipart message, this function will
1055  * set the HTP_BOUNDARY_SET in the transaction.
1056  */
1057 static int HtpRequestBodySetupMultipart(const htp_tx_t *tx, HtpTxUserData *htud)
1058 {
1059  const htp_header_t *h = htp_tx_request_header(tx, "Content-Type");
1060  if (h != NULL && htp_header_value_len(h) > 0) {
1061  htud->mime_state =
1062  SCMimeStateInit(htp_header_value_ptr(h), (uint32_t)htp_header_value_len(h));
1063  if (htud->mime_state) {
1064  htud->tsflags |= HTP_BOUNDARY_SET;
1065  SCReturnInt(1);
1066  }
1067  }
1068  SCReturnInt(0);
1069 }
1070 
1071 /**
1072  * \brief Create a single buffer from the HtpBodyChunks in our list
1073  *
1074  * \param htud transaction user data
1075  * \param chunks_buffers pointer to pass back the buffer to the caller
1076  * \param chunks_buffer_len pointer to pass back the buffer length to the caller
1077  */
1078 static void HtpRequestBodyReassemble(HtpTxUserData *htud,
1079  const uint8_t **chunks_buffer, uint32_t *chunks_buffer_len)
1080 {
1082  chunks_buffer, chunks_buffer_len,
1083  htud->request_body.body_parsed);
1084 }
1085 
1086 static void FlagDetectStateNewFile(HtpTxUserData *tx, int dir)
1087 {
1088  SCEnter();
1089  if (tx && tx->tx_data.de_state) {
1090  if (dir == STREAM_TOSERVER) {
1091  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set");
1092  tx->tx_data.de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW;
1093  } else if (dir == STREAM_TOCLIENT) {
1094  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set");
1095  tx->tx_data.de_state->dir_state[1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW;
1096  }
1097  }
1098 }
1099 
1100 static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, const void *tx,
1101  const uint8_t *chunks_buffer, uint32_t chunks_buffer_len, bool eof)
1102 {
1103 #ifdef PRINT
1104  printf("CHUNK START: \n");
1105  PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
1106  printf("CHUNK END: \n");
1107 #endif
1108 
1109  // libhtp will not call us back too late
1110  // should libhtp send a callback eof for 0 chunked ?
1112  STREAM_TOSERVER) >= HTP_REQUEST_PROGRESS_COMPLETE);
1113 
1114  const uint8_t *cur_buf = chunks_buffer;
1115  uint32_t cur_buf_len = chunks_buffer_len;
1116 
1117  if (eof) {
1118  // abrupt end of connection
1119  if (htud->tsflags & HTP_FILENAME_SET && !(htud->tsflags & HTP_DONTSTORE)) {
1120  /* we currently only handle multipart for ts. When we support it for tc,
1121  * we will need to supply right direction */
1122  HTPFileClose(htud, cur_buf, cur_buf_len, FILE_TRUNCATED, STREAM_TOSERVER);
1123  }
1124  htud->tsflags &= ~HTP_FILENAME_SET;
1125  goto end;
1126  }
1127 
1128  uint32_t consumed;
1129  uint32_t warnings;
1130  int result = 0;
1131  const uint8_t *filename = NULL;
1132  uint16_t filename_len = 0;
1133 
1134  // keep parsing mime and use callbacks when needed
1135  while (cur_buf_len > 0) {
1136  MimeParserResult r =
1137  SCMimeParse(htud->mime_state, cur_buf, cur_buf_len, &consumed, &warnings);
1138  DEBUG_VALIDATE_BUG_ON(consumed > cur_buf_len);
1139  htud->request_body.body_parsed += consumed;
1140  if (warnings) {
1141  if (warnings & MIME_EVENT_FLAG_INVALID_HEADER) {
1142  HTPSetEvent(
1143  hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER);
1144  }
1145  if (warnings & MIME_EVENT_FLAG_NO_FILEDATA) {
1146  HTPSetEvent(
1147  hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA);
1148  }
1149  }
1150  switch (r) {
1151  case MimeNeedsMore:
1152  // there is not enough data, wait for more next time
1153  goto end;
1154  case MimeFileOpen:
1155  // get filename owned by mime state
1156  SCMimeStateGetFilename(htud->mime_state, &filename, &filename_len);
1157  if (filename_len > 0) {
1158  htud->tsflags |= HTP_FILENAME_SET;
1159  htud->tsflags &= ~HTP_DONTSTORE;
1160  result = HTPFileOpen(
1161  hstate, htud, filename, filename_len, NULL, 0, STREAM_TOSERVER);
1162  if (result == -1) {
1163  goto end;
1164  } else if (result == -2) {
1165  htud->tsflags |= HTP_DONTSTORE;
1166  }
1167  FlagDetectStateNewFile(htud, STREAM_TOSERVER);
1168  }
1169  break;
1170  case MimeFileChunk:
1171  if (htud->tsflags & HTP_FILENAME_SET && !(htud->tsflags & HTP_DONTSTORE)) {
1172  result = HTPFileStoreChunk(htud, cur_buf, consumed, STREAM_TOSERVER);
1173  if (result == -1) {
1174  goto end;
1175  } else if (result == -2) {
1176  /* we know for sure we're not storing the file */
1177  htud->tsflags |= HTP_DONTSTORE;
1178  }
1179  }
1180  break;
1181  case MimeFileClose:
1182  if (htud->tsflags & HTP_FILENAME_SET && !(htud->tsflags & HTP_DONTSTORE)) {
1183  uint32_t lastsize = consumed;
1184  if (lastsize > 0 && cur_buf[lastsize - 1] == '\n') {
1185  lastsize--;
1186  if (lastsize > 0 && cur_buf[lastsize - 1] == '\r') {
1187  lastsize--;
1188  }
1189  }
1190  HTPFileClose(htud, cur_buf, lastsize, 0, STREAM_TOSERVER);
1191  }
1192  htud->tsflags &= ~HTP_FILENAME_SET;
1193  break;
1194  }
1195  cur_buf += consumed;
1196  cur_buf_len -= consumed;
1197  }
1198 
1199 end:
1200  SCLogDebug("htud->request_body.body_parsed %"PRIu64, htud->request_body.body_parsed);
1201  return 0;
1202 }
1203 
1204 /** \internal
1205  * \brief Handle POST or PUT, no multipart body data
1206  */
1207 static int HtpRequestBodyHandlePOSTorPUT(HtpState *hstate, HtpTxUserData *htud, const htp_tx_t *tx,
1208  const uint8_t *data, uint32_t data_len)
1209 {
1210  int result = 0;
1211 
1212  /* see if we need to open the file */
1213  if (!(htud->tsflags & HTP_FILENAME_SET))
1214  {
1215  uint8_t *filename = NULL;
1216  size_t filename_len = 0;
1217 
1218  /* get the name */
1219  if (htp_uri_path(htp_tx_parsed_uri(tx)) != NULL) {
1220  filename = (uint8_t *)bstr_ptr(htp_uri_path(htp_tx_parsed_uri(tx)));
1221  filename_len = bstr_len(htp_uri_path(htp_tx_parsed_uri(tx)));
1222  }
1223 
1224  if (filename != NULL) {
1225  if (filename_len > SC_FILENAME_MAX) {
1226  // explicitly truncate the file name if too long
1227  filename_len = SC_FILENAME_MAX;
1228  HTPSetEvent(hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG);
1229  }
1230  result = HTPFileOpen(hstate, htud, filename, (uint16_t)filename_len, data, data_len,
1231  STREAM_TOSERVER);
1232  if (result == -1) {
1233  goto end;
1234  } else if (result == -2) {
1235  htud->tsflags |= HTP_DONTSTORE;
1236  } else {
1237  FlagDetectStateNewFile(htud, STREAM_TOSERVER);
1238  htud->tsflags |= HTP_FILENAME_SET;
1239  htud->tsflags &= ~HTP_DONTSTORE;
1240  }
1241  }
1242  }
1243  else
1244  {
1245  /* otherwise, just store the data */
1246 
1247  if (!(htud->tsflags & HTP_DONTSTORE)) {
1248  result = HTPFileStoreChunk(htud, data, data_len, STREAM_TOSERVER);
1249  if (result == -1) {
1250  goto end;
1251  } else if (result == -2) {
1252  /* we know for sure we're not storing the file */
1253  htud->tsflags |= HTP_DONTSTORE;
1254  }
1255  }
1256  }
1257 
1258  return 0;
1259 end:
1260  return -1;
1261 }
1262 
1263 static int HtpResponseBodyHandle(HtpState *hstate, HtpTxUserData *htud, const htp_tx_t *tx,
1264  const uint8_t *data, uint32_t data_len)
1265 {
1266  SCEnter();
1267 
1268  int result = 0;
1269 
1270  /* see if we need to open the file
1271  * we check for htp_tx_response_line(tx) in case of junk
1272  * interpreted as body before response line
1273  */
1274  if (!(htud->tcflags & HTP_FILENAME_SET)) {
1275  SCLogDebug("setting up file name");
1276 
1277  const uint8_t *filename = NULL;
1278  size_t filename_len = 0;
1279 
1280  /* try Content-Disposition header first */
1281  const htp_header_t *h = htp_tx_response_header(tx, "Content-Disposition");
1282  if (h != NULL && htp_header_value_len(h) > 0) {
1283  /* parse content-disposition */
1284  (void)HTTPParseContentDispositionHeader((uint8_t *)"filename=", 9,
1285  htp_header_value_ptr(h), htp_header_value_len(h), &filename, &filename_len);
1286  }
1287 
1288  /* fall back to name from the uri */
1289  if (filename == NULL) {
1290  /* get the name */
1291  if (htp_uri_path(htp_tx_parsed_uri(tx)) != NULL) {
1292  filename = (uint8_t *)bstr_ptr(htp_uri_path(htp_tx_parsed_uri(tx)));
1293  filename_len = bstr_len(htp_uri_path(htp_tx_parsed_uri(tx)));
1294  }
1295  }
1296 
1297  if (filename != NULL) {
1298  // set range if present
1299  const htp_header_t *h_content_range = htp_tx_response_header(tx, "content-range");
1300  if (filename_len > SC_FILENAME_MAX) {
1301  // explicitly truncate the file name if too long
1302  filename_len = SC_FILENAME_MAX;
1303  HTPSetEvent(hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG);
1304  }
1305  if (h_content_range != NULL) {
1306  result = HTPFileOpenWithRange(hstate, htud, filename, (uint16_t)filename_len, data,
1307  data_len, tx, htp_header_value(h_content_range), htud);
1308  } else {
1309  result = HTPFileOpen(hstate, htud, filename, (uint16_t)filename_len, data, data_len,
1310  STREAM_TOCLIENT);
1311  }
1312  SCLogDebug("result %d", result);
1313  if (result == -1) {
1314  goto end;
1315  } else if (result == -2) {
1316  htud->tcflags |= HTP_DONTSTORE;
1317  } else {
1318  FlagDetectStateNewFile(htud, STREAM_TOCLIENT);
1319  htud->tcflags |= HTP_FILENAME_SET;
1320  htud->tcflags &= ~HTP_DONTSTORE;
1321  }
1322  }
1323  } else {
1324  /* otherwise, just store the data */
1325 
1326  if (!(htud->tcflags & HTP_DONTSTORE)) {
1327  result = HTPFileStoreChunk(htud, data, data_len, STREAM_TOCLIENT);
1328  SCLogDebug("result %d", result);
1329  if (result == -1) {
1330  goto end;
1331  } else if (result == -2) {
1332  /* we know for sure we're not storing the file */
1333  htud->tcflags |= HTP_DONTSTORE;
1334  }
1335  }
1336  }
1337 
1338  htud->response_body.body_parsed += data_len;
1339  return 0;
1340 end:
1341  return -1;
1342 }
1343 
1344 /**
1345  * \brief Function callback to append chunks for Requests
1346  * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
1347  * \retval int HTP_STATUS_OK if all goes well
1348  */
1349 static int HTPCallbackRequestBodyData(const htp_connp_t *connp, htp_tx_data_t *d)
1350 {
1351  SCEnter();
1352 
1353  const htp_tx_t *tx = htp_tx_data_tx(d);
1354 
1355  if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_REQUEST_BODY))
1356  SCReturnInt(HTP_STATUS_OK);
1357 
1358  if (htp_tx_data_is_empty(d))
1359  SCReturnInt(HTP_STATUS_OK);
1360 
1361 #ifdef PRINT
1362  printf("HTPBODY START: \n");
1363  PrintRawDataFp(stdout, (uint8_t *)htp_tx_data_data(d), htp_tx_data_len(d));
1364  printf("HTPBODY END: \n");
1365 #endif
1366 
1367  HtpState *hstate = htp_connp_user_data(connp);
1368  if (hstate == NULL) {
1369  SCReturnInt(HTP_STATUS_ERROR);
1370  }
1371 
1372  SCLogDebug("New request body data available at %p -> %p -> %p, bodylen "
1373  "%" PRIu32 "",
1374  hstate, d, htp_tx_data_data(d), (uint32_t)htp_tx_data_len(d));
1375 
1376  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1377  if (tx_ud == NULL) {
1378  SCReturnInt(HTP_STATUS_OK);
1379  }
1380  tx_ud->tx_data.updated_ts = true;
1381  SCTxDataUpdateFileFlags(&tx_ud->tx_data, hstate->state_data.file_flags);
1382 
1383  if (!tx_ud->response_body_init) {
1384  tx_ud->response_body_init = 1;
1385 
1386  if (htp_tx_request_method_number(tx) == HTP_METHOD_POST) {
1387  SCLogDebug("POST");
1388  int r = HtpRequestBodySetupMultipart(tx, tx_ud);
1389  if (r == 1) {
1391  } else if (r == 0) {
1393  SCLogDebug("not multipart");
1394  }
1395  } else if (htp_tx_request_method_number(tx) == HTP_METHOD_PUT) {
1397  }
1398  }
1399 
1400  /* see if we can get rid of htp body chunks */
1401  HtpBodyPrune(hstate, &tx_ud->request_body, STREAM_TOSERVER);
1402 
1403  SCLogDebug("tx_ud->request_body.content_len_so_far %"PRIu64, tx_ud->request_body.content_len_so_far);
1404  SCLogDebug("hstate->cfg->request.body_limit %u", hstate->cfg->request.body_limit);
1405 
1406  /* within limits, add the body chunk to the state. */
1407  if (AppLayerHtpCheckDepth(&hstate->cfg->request, &tx_ud->request_body, tx_ud->tsflags)) {
1408  uint32_t stream_depth = FileReassemblyDepth();
1409  uint32_t len = AppLayerHtpComputeChunkLength(tx_ud->request_body.content_len_so_far,
1410  hstate->cfg->request.body_limit, stream_depth, tx_ud->tsflags,
1411  (uint32_t)htp_tx_data_len(d));
1412  BUG_ON(len > (uint32_t)htp_tx_data_len(d));
1413 
1414  HtpBodyAppendChunk(&tx_ud->request_body, htp_tx_data_data(d), len);
1415 
1416  const uint8_t *chunks_buffer = NULL;
1417  uint32_t chunks_buffer_len = 0;
1418 
1420  /* multi-part body handling starts here */
1421  if (!(tx_ud->tsflags & HTP_BOUNDARY_SET)) {
1422  goto end;
1423  }
1424 
1425  HtpRequestBodyReassemble(tx_ud, &chunks_buffer, &chunks_buffer_len);
1426  if (chunks_buffer == NULL) {
1427  goto end;
1428  }
1429 #ifdef PRINT
1430  printf("REASSCHUNK START: \n");
1431  PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
1432  printf("REASSCHUNK END: \n");
1433 #endif
1434 
1435  HtpRequestBodyHandleMultipart(hstate, tx_ud, htp_tx_data_tx(d), chunks_buffer,
1436  chunks_buffer_len, (htp_tx_data_data(d) == NULL && htp_tx_data_len(d) == 0));
1437 
1438  } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_POST ||
1440  HtpRequestBodyHandlePOSTorPUT(
1441  hstate, tx_ud, htp_tx_data_tx(d), htp_tx_data_data(d), len);
1442  }
1443 
1444  } else {
1445  if (tx_ud->tsflags & HTP_FILENAME_SET) {
1446  SCLogDebug("closing file that was being stored");
1447  (void)HTPFileClose(tx_ud, NULL, 0, FILE_TRUNCATED, STREAM_TOSERVER);
1448  tx_ud->tsflags &= ~HTP_FILENAME_SET;
1449  }
1450  }
1451 
1452 end:
1453  if (hstate->conn != NULL) {
1454  SCLogDebug("checking body size %" PRIu64 " against inspect limit %u (cur %" PRIu64
1455  ", last %" PRIu64 ")",
1457  (uint64_t)htp_conn_request_data_counter(hstate->conn),
1458  hstate->last_request_data_stamp);
1459 
1460  /* if we reach the inspect_min_size we'll trigger inspection,
1461  * so make sure that raw stream is also inspected. Set the
1462  * data to be used to the amount of raw bytes we've seen to
1463  * get here. */
1464  if (tx_ud->request_body.body_inspected == 0 &&
1466  if ((uint64_t)htp_conn_request_data_counter(hstate->conn) >
1467  hstate->last_request_data_stamp &&
1468  (uint64_t)htp_conn_request_data_counter(hstate->conn) -
1469  hstate->last_request_data_stamp <
1470  (uint64_t)UINT_MAX) {
1471  uint32_t data_size =
1472  (uint32_t)((uint64_t)htp_conn_request_data_counter(hstate->conn) -
1473  hstate->last_request_data_stamp);
1474  const uint32_t depth = MIN(data_size, hstate->cfg->request.inspect_min_size);
1475 
1476  /* body still in progress, but due to min inspect size we need to inspect now */
1477  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, depth);
1478  AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOSERVER);
1479  }
1480  /* after the start of the body, disable the depth logic */
1481  } else if (tx_ud->request_body.body_inspected > 0) {
1482  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, 0);
1483  }
1484  }
1485  SCReturnInt(HTP_STATUS_OK);
1486 }
1487 
1488 /**
1489  * \brief Function callback to append chunks for Responses
1490  * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
1491  * \retval int HTP_STATUS_OK if all goes well
1492  */
1493 static int HTPCallbackResponseBodyData(const htp_connp_t *connp, htp_tx_data_t *d)
1494 {
1495  SCEnter();
1496 
1497  const htp_tx_t *tx = htp_tx_data_tx(d);
1498 
1499  if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_RESPONSE_BODY))
1500  SCReturnInt(HTP_STATUS_OK);
1501 
1502  if (htp_tx_data_is_empty(d))
1503  SCReturnInt(HTP_STATUS_OK);
1504 
1505  HtpState *hstate = htp_connp_user_data(connp);
1506  if (hstate == NULL) {
1507  SCReturnInt(HTP_STATUS_ERROR);
1508  }
1509 
1510  SCLogDebug("New response body data available at %p -> %p -> %p, bodylen "
1511  "%" PRIu32 "",
1512  hstate, d, htp_tx_data_data(d), (uint32_t)htp_tx_data_len(d));
1513 
1514  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1515  tx_ud->tx_data.updated_tc = true;
1516  SCTxDataUpdateFileFlags(&tx_ud->tx_data, hstate->state_data.file_flags);
1517  if (!tx_ud->request_body_init) {
1518  tx_ud->request_body_init = 1;
1519  }
1520 
1521  /* see if we can get rid of htp body chunks */
1522  HtpBodyPrune(hstate, &tx_ud->response_body, STREAM_TOCLIENT);
1523 
1524  SCLogDebug("tx_ud->response_body.content_len_so_far %"PRIu64, tx_ud->response_body.content_len_so_far);
1525  SCLogDebug("hstate->cfg->response.body_limit %u", hstate->cfg->response.body_limit);
1526 
1527  /* within limits, add the body chunk to the state. */
1528  if (AppLayerHtpCheckDepth(&hstate->cfg->response, &tx_ud->response_body, tx_ud->tcflags)) {
1529  uint32_t stream_depth = FileReassemblyDepth();
1530  uint32_t len = AppLayerHtpComputeChunkLength(tx_ud->response_body.content_len_so_far,
1531  hstate->cfg->response.body_limit, stream_depth, tx_ud->tcflags,
1532  (uint32_t)htp_tx_data_len(d));
1533  BUG_ON(len > (uint32_t)htp_tx_data_len(d));
1534 
1535  HtpBodyAppendChunk(&tx_ud->response_body, htp_tx_data_data(d), len);
1536 
1537  HtpResponseBodyHandle(hstate, tx_ud, htp_tx_data_tx(d), htp_tx_data_data(d), len);
1538  } else {
1539  if (tx_ud->tcflags & HTP_FILENAME_SET) {
1540  SCLogDebug("closing file that was being stored");
1541  (void)HTPFileClose(tx_ud, NULL, 0, FILE_TRUNCATED, STREAM_TOCLIENT);
1542  tx_ud->tcflags &= ~HTP_FILENAME_SET;
1543  }
1544  }
1545 
1546  if (hstate->conn != NULL) {
1547  SCLogDebug("checking body size %" PRIu64 " against inspect limit %u (cur %" PRIu64
1548  ", last %" PRIu64 ")",
1550  (uint64_t)htp_conn_request_data_counter(hstate->conn),
1551  hstate->last_response_data_stamp);
1552  /* if we reach the inspect_min_size we'll trigger inspection,
1553  * so make sure that raw stream is also inspected. Set the
1554  * data to be used to the amount of raw bytes we've seen to
1555  * get here. */
1556  if (tx_ud->response_body.body_inspected == 0 &&
1558  if ((uint64_t)htp_conn_response_data_counter(hstate->conn) >
1559  hstate->last_response_data_stamp &&
1560  (uint64_t)htp_conn_response_data_counter(hstate->conn) -
1561  hstate->last_response_data_stamp <
1562  (uint64_t)UINT_MAX) {
1563  uint32_t data_size =
1564  (uint32_t)((uint64_t)htp_conn_response_data_counter(hstate->conn) -
1565  hstate->last_response_data_stamp);
1566  const uint32_t depth = MIN(data_size, hstate->cfg->response.inspect_min_size);
1567 
1568  /* body still in progress, but due to min inspect size we need to inspect now */
1569  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, depth);
1570  AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOCLIENT);
1571  }
1572  /* after the start of the body, disable the depth logic */
1573  } else if (tx_ud->response_body.body_inspected > 0) {
1574  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, 0);
1575  }
1576  }
1577  SCReturnInt(HTP_STATUS_OK);
1578 }
1579 
1580 /**
1581  * \brief Print the stats of the HTTP requests
1582  */
1584 {
1585 #ifdef DEBUG
1586  SCEnter();
1587  SCMutexLock(&htp_state_mem_lock);
1588  SCLogDebug("http_state_memcnt %"PRIu64", http_state_memuse %"PRIu64"",
1589  htp_state_memcnt, htp_state_memuse);
1590  SCMutexUnlock(&htp_state_mem_lock);
1591  SCReturn;
1592 #endif
1593 }
1594 
1595 /** \brief Clears the HTTP server configuration memory used by HTP library */
1596 void HTPFreeConfig(void)
1597 {
1598  SCEnter();
1599 
1600  if (!AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "http") ||
1601  !AppLayerParserConfParserEnabled("tcp", "http"))
1602  {
1603  SCReturn;
1604  }
1605 
1606  HTPCfgRec *nextrec = cfglist.next;
1607  htp_config_destroy(cfglist.cfg);
1608  while (nextrec != NULL) {
1609  HTPCfgRec *htprec = nextrec;
1610  nextrec = nextrec->next;
1611 
1612  htp_config_destroy(htprec->cfg);
1613  SCFree(htprec);
1614  }
1615  SCRadix4TreeRelease(&cfgtree.ipv4, &htp_radix4_cfg);
1616  SCRadix6TreeRelease(&cfgtree.ipv6, &htp_radix6_cfg);
1617  SCReturn;
1618 }
1619 
1620 static int HTPCallbackRequestHasTrailer(const htp_connp_t *connp, htp_tx_t *tx)
1621 {
1622  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1623  htud->tx_data.updated_ts = true;
1624  htud->request_has_trailers = 1;
1625  return HTP_STATUS_OK;
1626 }
1627 
1628 static int HTPCallbackResponseHasTrailer(const htp_connp_t *connp, htp_tx_t *tx)
1629 {
1630  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1631  htud->tx_data.updated_tc = true;
1632  htud->response_has_trailers = 1;
1633  return HTP_STATUS_OK;
1634 }
1635 
1636 static void *HTPCallbackTxCreate(bool request)
1637 {
1638  HtpTxUserData *tx_ud = HTPCalloc(1, sizeof(HtpTxUserData));
1639  if (unlikely(tx_ud == NULL)) {
1640  return NULL;
1641  }
1642  if (request) {
1643  // each http tx may xfer files
1644  tx_ud->tx_data.file_tx = STREAM_TOSERVER | STREAM_TOCLIENT;
1645  } else {
1646  tx_ud->tx_data.file_tx = STREAM_TOCLIENT; // Toserver already missed.
1647  }
1648  return tx_ud;
1649 }
1650 
1651 /**\internal
1652  * \brief called at start of request
1653  * Set min inspect size.
1654  */
1655 static int HTPCallbackRequestStart(const htp_connp_t *connp, htp_tx_t *tx)
1656 {
1657  HtpState *hstate = htp_connp_user_data(connp);
1658  if (hstate == NULL) {
1659  SCReturnInt(HTP_STATUS_ERROR);
1660  }
1661 
1662  uint64_t consumed = hstate->slice->offset + htp_connp_request_data_consumed(hstate->connp);
1663  SCLogDebug("HTTP request start: data offset %" PRIu64 ", in_data_counter %" PRIu64, consumed,
1664  (uint64_t)htp_conn_request_data_counter(hstate->conn));
1665  /* app-layer-frame-documentation tag start: frame registration http request */
1667  hstate->f, hstate->slice, consumed, -1, 0, HTTP_FRAME_REQUEST);
1668  if (frame) {
1669  SCLogDebug("frame %p/%" PRIi64, frame, frame->id);
1670  hstate->request_frame_id = frame->id;
1671  AppLayerFrameSetTxId(frame, HtpGetActiveRequestTxID(hstate));
1672  }
1673  /* app-layer-frame-documentation tag end: frame registration http request */
1674 
1675  if (hstate->cfg)
1676  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER,
1677  hstate->cfg->request.inspect_min_size);
1678 
1679  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1680  tx_ud->tx_data.updated_ts = true;
1681  SCReturnInt(HTP_STATUS_OK);
1682 }
1683 
1684 /**\internal
1685  * \brief called at start of response
1686  * Set min inspect size.
1687  */
1688 static int HTPCallbackResponseStart(const htp_connp_t *connp, htp_tx_t *tx)
1689 {
1690  HtpState *hstate = htp_connp_user_data(connp);
1691  if (hstate == NULL) {
1692  SCReturnInt(HTP_STATUS_ERROR);
1693  }
1694 
1695  uint64_t consumed = hstate->slice->offset + htp_connp_response_data_consumed(hstate->connp);
1696  SCLogDebug("HTTP response start: data offset %" PRIu64 ", out_data_counter %" PRIu64, consumed,
1697  (uint64_t)htp_conn_response_data_counter(hstate->conn));
1698 
1700  hstate->f, hstate->slice, consumed, -1, 1, HTTP_FRAME_RESPONSE);
1701  if (frame) {
1702  SCLogDebug("frame %p/%" PRIi64, frame, frame->id);
1703  hstate->response_frame_id = frame->id;
1704  AppLayerFrameSetTxId(frame, HtpGetActiveResponseTxID(hstate));
1705  }
1706 
1707  if (hstate->cfg)
1708  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT,
1709  hstate->cfg->response.inspect_min_size);
1710 
1711  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1712  tx_ud->tx_data.updated_tc = true;
1713  SCReturnInt(HTP_STATUS_OK);
1714 }
1715 
1716 /**
1717  * \brief callback for request to store the recent incoming request
1718  into the recent_request_tx for the given htp state
1719  * \param connp pointer to the current connection parser which has the htp
1720  * state in it as user data
1721  */
1722 static int HTPCallbackRequestComplete(const htp_connp_t *connp, htp_tx_t *tx)
1723 {
1724  SCEnter();
1725 
1726  if (tx == NULL) {
1727  SCReturnInt(HTP_STATUS_ERROR);
1728  }
1729 
1730  HtpState *hstate = htp_connp_user_data(connp);
1731  if (hstate == NULL) {
1732  SCReturnInt(HTP_STATUS_ERROR);
1733  }
1734 
1735  const uint64_t abs_right_edge =
1736  hstate->slice->offset + htp_connp_request_data_consumed(hstate->connp);
1737 
1738  /* app-layer-frame-documentation tag start: updating frame->len */
1739  if (hstate->request_frame_id > 0) {
1740  Frame *frame = AppLayerFrameGetById(hstate->f, 0, hstate->request_frame_id);
1741  if (frame) {
1742  const uint64_t request_size = abs_right_edge - hstate->last_request_data_stamp;
1743 
1744  SCLogDebug("HTTP request complete: data offset %" PRIu64 ", request_size %" PRIu64,
1745  hstate->last_request_data_stamp, request_size);
1746  SCLogDebug("frame %p/%" PRIi64 " setting len to %" PRIu64, frame, frame->id,
1747  request_size);
1748  frame->len = (int64_t)request_size;
1749  /* app-layer-frame-documentation tag end: updating frame->len */
1750  }
1751  hstate->request_frame_id = 0;
1752  }
1753 
1754  SCLogDebug("transaction_cnt %"PRIu64", list_size %"PRIu64,
1755  hstate->transaction_cnt, HTPStateGetTxCnt(hstate));
1756 
1757  SCLogDebug("HTTP request completed");
1758 
1759  HTPErrorCheckTxRequestFlags(hstate, tx);
1760 
1761  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1762  htud->tx_data.updated_ts = true;
1763  if (htud->tsflags & HTP_FILENAME_SET) {
1764  SCLogDebug("closing file that was being stored");
1765  (void)HTPFileClose(htud, NULL, 0, 0, STREAM_TOSERVER);
1766  htud->tsflags &= ~HTP_FILENAME_SET;
1767  if (abs_right_edge < (uint64_t)UINT32_MAX) {
1769  hstate->f->protoctx, STREAM_TOSERVER, (uint32_t)abs_right_edge);
1770  }
1771  }
1772 
1773  hstate->last_request_data_stamp = abs_right_edge;
1774  /* request done, do raw reassembly now to inspect state and stream
1775  * at the same time. */
1776  AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOSERVER);
1777  SCReturnInt(HTP_STATUS_OK);
1778 }
1779 
1780 /**
1781  * \brief callback for response to remove the recent received requests
1782  from the recent_request_tx for the given htp state
1783  * \param connp pointer to the current connection parser which has the htp
1784  * state in it as user data
1785  */
1786 static int HTPCallbackResponseComplete(const htp_connp_t *connp, htp_tx_t *tx)
1787 {
1788  SCEnter();
1789 
1790  HtpState *hstate = htp_connp_user_data(connp);
1791  if (hstate == NULL) {
1792  SCReturnInt(HTP_STATUS_ERROR);
1793  }
1794 
1795  /* we have one whole transaction now */
1796  hstate->transaction_cnt++;
1797 
1798  const uint64_t abs_right_edge =
1799  hstate->slice->offset + htp_connp_response_data_consumed(hstate->connp);
1800 
1801  if (hstate->response_frame_id > 0) {
1802  Frame *frame = AppLayerFrameGetById(hstate->f, 1, hstate->response_frame_id);
1803  if (frame) {
1804  const uint64_t response_size = abs_right_edge - hstate->last_response_data_stamp;
1805 
1806  SCLogDebug("HTTP response complete: data offset %" PRIu64 ", response_size %" PRIu64,
1807  hstate->last_response_data_stamp, response_size);
1808  SCLogDebug("frame %p/%" PRIi64 " setting len to %" PRIu64, frame, frame->id,
1809  response_size);
1810  frame->len = (int64_t)response_size;
1811  }
1812  hstate->response_frame_id = 0;
1813  }
1814 
1815  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1816  htud->tx_data.updated_tc = true;
1817  if (htud->tcflags & HTP_FILENAME_SET) {
1818  SCLogDebug("closing file that was being stored");
1819  (void)HTPFileClose(htud, NULL, 0, 0, STREAM_TOCLIENT);
1820  htud->tcflags &= ~HTP_FILENAME_SET;
1821  }
1822 
1823  /* response done, do raw reassembly now to inspect state and stream
1824  * at the same time. */
1825  AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOCLIENT);
1826 
1827  /* handle HTTP CONNECT */
1828  if (htp_tx_request_method_number(tx) == HTP_METHOD_CONNECT) {
1829  /* any 2XX status response implies that the connection will become
1830  a tunnel immediately after this packet (RFC 7230, 3.3.3). */
1831  if ((htp_tx_response_status_number(tx) >= 200) &&
1832  (htp_tx_response_status_number(tx) < 300) && (hstate->transaction_cnt == 1)) {
1833  uint16_t dp = 0;
1834  if (htp_tx_request_port_number(tx) != -1) {
1835  dp = (uint16_t)htp_tx_request_port_number(tx);
1836  }
1837  // both ALPROTO_HTTP1 and ALPROTO_TLS are normal options
1838  if (!AppLayerRequestProtocolChange(hstate->f, dp, ALPROTO_UNKNOWN)) {
1839  HTPSetEvent(
1840  hstate, htud, STREAM_TOCLIENT, HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE);
1841  }
1842  }
1843  }
1844 
1845  hstate->last_response_data_stamp = abs_right_edge;
1846  SCReturnInt(HTP_STATUS_OK);
1847 }
1848 
1849 static int HTPCallbackRequestLine(const htp_connp_t *connp, htp_tx_t *tx)
1850 {
1851  HtpState *hstate = htp_connp_user_data(connp);
1852 
1853  if (htp_tx_flags(tx)) {
1854  HTPErrorCheckTxRequestFlags(hstate, tx);
1855  }
1856  return HTP_STATUS_OK;
1857 }
1858 
1859 static int HTPCallbackRequestHeaderData(const htp_connp_t *connp, htp_tx_data_t *tx_data)
1860 {
1861  void *ptmp;
1862  const htp_tx_t *tx = htp_tx_data_tx(tx_data);
1863  if (htp_tx_data_is_empty(tx_data) || tx == NULL)
1864  return HTP_STATUS_OK;
1865 
1866  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1868  tx_ud->request_headers_raw_len + htp_tx_data_len(tx_data));
1869  if (ptmp == NULL) {
1870  return HTP_STATUS_OK;
1871  }
1872  tx_ud->request_headers_raw = ptmp;
1873  tx_ud->tx_data.updated_ts = true;
1874 
1875  memcpy(tx_ud->request_headers_raw + tx_ud->request_headers_raw_len, htp_tx_data_data(tx_data),
1876  htp_tx_data_len(tx_data));
1877  tx_ud->request_headers_raw_len += htp_tx_data_len(tx_data);
1878 
1879  if (tx && htp_tx_flags(tx)) {
1880  HtpState *hstate = htp_connp_user_data(connp);
1881  HTPErrorCheckTxRequestFlags(hstate, tx);
1882  }
1883  return HTP_STATUS_OK;
1884 }
1885 
1886 static int HTPCallbackResponseHeaderData(const htp_connp_t *connp, htp_tx_data_t *tx_data)
1887 {
1888  void *ptmp;
1889  const htp_tx_t *tx = htp_tx_data_tx(tx_data);
1890  if (htp_tx_data_is_empty(tx_data) || tx == NULL)
1891  return HTP_STATUS_OK;
1892 
1893  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1894  tx_ud->tx_data.updated_tc = true;
1896  tx_ud->response_headers_raw_len + htp_tx_data_len(tx_data));
1897  if (ptmp == NULL) {
1898  return HTP_STATUS_OK;
1899  }
1900  tx_ud->response_headers_raw = ptmp;
1901 
1902  memcpy(tx_ud->response_headers_raw + tx_ud->response_headers_raw_len, htp_tx_data_data(tx_data),
1903  htp_tx_data_len(tx_data));
1904  tx_ud->response_headers_raw_len += htp_tx_data_len(tx_data);
1905 
1906  return HTP_STATUS_OK;
1907 }
1908 
1909 /*
1910  * We have a similar set function called HTPConfigSetDefaultsPhase1.
1911  */
1912 static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec)
1913 {
1914  htp_config_set_normalized_uri_include_all(cfg_prec->cfg, false);
1921 
1922  if (!g_disable_randomness) {
1924  } else {
1925  cfg_prec->randomize = 0;
1926  }
1928 
1929  htp_config_register_request_header_data(cfg_prec->cfg, HTPCallbackRequestHeaderData);
1930  htp_config_register_request_trailer_data(cfg_prec->cfg, HTPCallbackRequestHeaderData);
1931  htp_config_register_response_header_data(cfg_prec->cfg, HTPCallbackResponseHeaderData);
1932  htp_config_register_response_trailer_data(cfg_prec->cfg, HTPCallbackResponseHeaderData);
1933 
1934  htp_config_register_request_trailer(cfg_prec->cfg, HTPCallbackRequestHasTrailer);
1935  htp_config_register_response_trailer(cfg_prec->cfg, HTPCallbackResponseHasTrailer);
1936 
1937  htp_config_register_request_body_data(cfg_prec->cfg, HTPCallbackRequestBodyData);
1938  htp_config_register_response_body_data(cfg_prec->cfg, HTPCallbackResponseBodyData);
1939 
1940  htp_config_register_tx_create(cfg_prec->cfg, HTPCallbackTxCreate);
1941  htp_config_register_tx_destroy(cfg_prec->cfg, HtpTxUserDataFree);
1942 
1943  htp_config_register_request_start(cfg_prec->cfg, HTPCallbackRequestStart);
1944  htp_config_register_request_complete(cfg_prec->cfg, HTPCallbackRequestComplete);
1945 
1946  htp_config_register_response_start(cfg_prec->cfg, HTPCallbackResponseStart);
1947  htp_config_register_response_complete(cfg_prec->cfg, HTPCallbackResponseComplete);
1948 
1949  htp_config_set_parse_request_cookies(cfg_prec->cfg, 0);
1950  htp_config_set_allow_space_uri(cfg_prec->cfg, 1);
1951 
1952  /* don't convert + to space by default */
1953  htp_config_set_plusspace_decode(cfg_prec->cfg, 0);
1954  // enables request decompression
1955  htp_config_set_request_decompression(cfg_prec->cfg, 1);
1956  htp_config_set_lzma_layers(cfg_prec->cfg, HTP_CONFIG_DEFAULT_LZMA_LAYERS);
1957  htp_config_set_lzma_memlimit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_LZMA_MEMLIMIT);
1958  htp_config_set_compression_bomb_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_COMPRESSION_BOMB_LIMIT);
1959  htp_config_set_compression_time_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_COMPRESSION_TIME_LIMIT);
1960 #define HTP_CONFIG_DEFAULT_MAX_TX_LIMIT 512
1961  htp_config_set_max_tx(cfg_prec->cfg, HTP_CONFIG_DEFAULT_MAX_TX_LIMIT);
1962 #define HTP_CONFIG_DEFAULT_HEADERS_LIMIT 1024
1963  htp_config_set_number_headers_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_HEADERS_LIMIT);
1964  htp_config_set_field_limit(cfg_prec->cfg, (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT);
1965 }
1966 
1967 /* hack: htp random range code expects random values in range of 0-RAND_MAX,
1968  * but we can get both <0 and >RAND_MAX values from RandomGet
1969  */
1970 static int RandomGetWrap(void)
1971 {
1972  unsigned long r;
1973 
1974  do {
1975  r = RandomGet();
1976  } while(r >= ULONG_MAX - (ULONG_MAX % RAND_MAX));
1977 
1978  return r % RAND_MAX;
1979 }
1980 
1981 /*
1982  * We have this splitup so that in case double decoding has been enabled
1983  * for query and path, they would be called first on the callback queue,
1984  * before the callback set by Phase2() is called. We need this, since
1985  * the callback in Phase2() generates the normalized uri which utilizes
1986  * the query and path. */
1987 static void HTPConfigSetDefaultsPhase2(const char *name, HTPCfgRec *cfg_prec)
1988 {
1989  /* randomize inspection size if needed */
1990  if (cfg_prec->randomize) {
1991  int rdrange = cfg_prec->randomize_range;
1992 
1993  long int r = RandomGetWrap();
1994  cfg_prec->request.inspect_min_size += (int)(cfg_prec->request.inspect_min_size *
1995  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
1996 
1997  r = RandomGetWrap();
1998  cfg_prec->request.inspect_window += (int)(cfg_prec->request.inspect_window *
1999  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
2000  SCLogConfig("'%s' server has 'request-body-minimal-inspect-size' set to"
2001  " %u and 'request-body-inspect-window' set to %u after"
2002  " randomization.",
2003  name, cfg_prec->request.inspect_min_size, cfg_prec->request.inspect_window);
2004 
2005  r = RandomGetWrap();
2006  cfg_prec->response.inspect_min_size += (int)(cfg_prec->response.inspect_min_size *
2007  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
2008 
2009  r = RandomGetWrap();
2010  cfg_prec->response.inspect_window += (int)(cfg_prec->response.inspect_window *
2011  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
2012 
2013  SCLogConfig("'%s' server has 'response-body-minimal-inspect-size' set to"
2014  " %u and 'response-body-inspect-window' set to %u after"
2015  " randomization.",
2016  name, cfg_prec->response.inspect_min_size, cfg_prec->response.inspect_window);
2017  }
2018 
2019  htp_config_register_request_line(cfg_prec->cfg, HTPCallbackRequestLine);
2020 }
2021 
2022 static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, SCConfNode *s, struct HTPConfigTree *tree)
2023 {
2024  if (cfg_prec == NULL || s == NULL || tree == NULL)
2025  return;
2026 
2027  SCConfNode *p = NULL;
2028 
2029  /* Default Parameters */
2030  TAILQ_FOREACH (p, &s->head, next) {
2031  if (strcasecmp("address", p->name) == 0) {
2032  SCConfNode *pval;
2033  /* Addresses */
2034  TAILQ_FOREACH(pval, &p->head, next) {
2035  SCLogDebug("LIBHTP server %s: %s=%s", s->name, p->name, pval->val);
2036  /* IPV6 or IPV4? */
2037  if (strchr(pval->val, ':') != NULL) {
2038  SCLogDebug("LIBHTP adding ipv6 server %s at %s: %p",
2039  s->name, pval->val, cfg_prec->cfg);
2041  &tree->ipv6, &htp_radix6_cfg, pval->val, cfg_prec)) {
2042  SCLogWarning("LIBHTP failed to add ipv6 server %s, ignoring", pval->val);
2043  }
2044  } else {
2045  SCLogDebug("LIBHTP adding ipv4 server %s at %s: %p",
2046  s->name, pval->val, cfg_prec->cfg);
2048  &tree->ipv4, &htp_radix4_cfg, pval->val, cfg_prec)) {
2049  SCLogWarning("LIBHTP failed to add ipv4 server %s, ignoring", pval->val);
2050  }
2051  } /* else - if (strchr(pval->val, ':') != NULL) */
2052  } /* TAILQ_FOREACH(pval, &p->head, next) */
2053 
2054  } else if (strcasecmp("personality", p->name) == 0) {
2055  /* Personalities */
2056  int personality = HTPLookupPersonality(p->val);
2057  SCLogDebug("LIBHTP default: %s = %s", p->name, p->val);
2058  SCLogDebug("LIBHTP default: %s = %s", p->name, p->val);
2059 
2060  if (personality >= 0) {
2061  SCLogDebug("LIBHTP default: %s=%s (%d)", p->name, p->val,
2062  personality);
2063  if (htp_config_set_server_personality(cfg_prec->cfg, personality) ==
2064  HTP_STATUS_ERROR) {
2065  SCLogWarning("LIBHTP Failed adding "
2066  "personality \"%s\", ignoring",
2067  p->val);
2068  } else {
2069  SCLogDebug("LIBHTP personality set to %s",
2070  HTPLookupPersonalityString(personality));
2071  }
2072 
2073  /* The IDS personality by default converts the path (and due to
2074  * our query string callback also the query string) to lowercase.
2075  * Signatures do not expect this, so override it. */
2076  htp_config_set_convert_lowercase(cfg_prec->cfg, 0);
2077  } else {
2078  SCLogWarning("LIBHTP Unknown personality "
2079  "\"%s\", ignoring",
2080  p->val);
2081  continue;
2082  }
2083 
2084  } else if (strcasecmp("request-body-limit", p->name) == 0 ||
2085  strcasecmp("request_body_limit", p->name) == 0) {
2086  if (ParseSizeStringU32(p->val, &cfg_prec->request.body_limit) < 0) {
2087  SCLogError("Error parsing request-body-limit "
2088  "from conf file - %s. Killing engine",
2089  p->val);
2090  exit(EXIT_FAILURE);
2091  }
2092 
2093  } else if (strcasecmp("response-body-limit", p->name) == 0) {
2094  if (ParseSizeStringU32(p->val, &cfg_prec->response.body_limit) < 0) {
2095  SCLogError("Error parsing response-body-limit "
2096  "from conf file - %s. Killing engine",
2097  p->val);
2098  exit(EXIT_FAILURE);
2099  }
2100 
2101  } else if (strcasecmp("request-body-minimal-inspect-size", p->name) == 0) {
2102  if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_min_size) < 0) {
2103  SCLogError("Error parsing request-body-minimal-inspect-size "
2104  "from conf file - %s. Killing engine",
2105  p->val);
2106  exit(EXIT_FAILURE);
2107  }
2108 
2109  } else if (strcasecmp("request-body-inspect-window", p->name) == 0) {
2110  if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_window) < 0) {
2111  SCLogError("Error parsing request-body-inspect-window "
2112  "from conf file - %s. Killing engine",
2113  p->val);
2114  exit(EXIT_FAILURE);
2115  }
2116 
2117  } else if (strcasecmp("double-decode-query", p->name) == 0) {
2118  htp_config_set_double_decode_normalized_query(cfg_prec->cfg, SCConfValIsTrue(p->val));
2119  } else if (strcasecmp("double-decode-path", p->name) == 0) {
2120  htp_config_set_double_decode_normalized_path(cfg_prec->cfg, SCConfValIsTrue(p->val));
2121  } else if (strcasecmp("response-body-minimal-inspect-size", p->name) == 0) {
2122  if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_min_size) < 0) {
2123  SCLogError("Error parsing response-body-minimal-inspect-size "
2124  "from conf file - %s. Killing engine",
2125  p->val);
2126  exit(EXIT_FAILURE);
2127  }
2128 
2129  } else if (strcasecmp("response-body-inspect-window", p->name) == 0) {
2130  if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_window) < 0) {
2131  SCLogError("Error parsing response-body-inspect-window "
2132  "from conf file - %s. Killing engine",
2133  p->val);
2134  exit(EXIT_FAILURE);
2135  }
2136 
2137  } else if (strcasecmp("response-body-decompress-layer-limit", p->name) == 0) {
2138  uint32_t value = 2;
2139  if (ParseSizeStringU32(p->val, &value) < 0) {
2140  SCLogError("Error parsing response-body-inspect-window "
2141  "from conf file - %s. Killing engine",
2142  p->val);
2143  exit(EXIT_FAILURE);
2144  }
2145  htp_config_set_decompression_layer_limit(cfg_prec->cfg, value);
2146  } else if (strcasecmp("path-convert-backslash-separators", p->name) == 0) {
2147  htp_config_set_backslash_convert_slashes(cfg_prec->cfg, SCConfValIsTrue(p->val));
2148  } else if (strcasecmp("path-bestfit-replacement-char", p->name) == 0) {
2149  if (strlen(p->val) == 1) {
2150  htp_config_set_bestfit_replacement_byte(cfg_prec->cfg, p->val[0]);
2151  } else {
2152  SCLogError("Invalid entry "
2153  "for libhtp param path-bestfit-replacement-char");
2154  }
2155  } else if (strcasecmp("path-convert-lowercase", p->name) == 0) {
2156  htp_config_set_convert_lowercase(cfg_prec->cfg, SCConfValIsTrue(p->val));
2157  } else if (strcasecmp("path-nul-encoded-terminates", p->name) == 0) {
2158  htp_config_set_nul_encoded_terminates(cfg_prec->cfg, SCConfValIsTrue(p->val));
2159  } else if (strcasecmp("path-nul-raw-terminates", p->name) == 0) {
2160  htp_config_set_nul_raw_terminates(cfg_prec->cfg, SCConfValIsTrue(p->val));
2161  } else if (strcasecmp("path-separators-compress", p->name) == 0) {
2162  htp_config_set_path_separators_compress(cfg_prec->cfg, SCConfValIsTrue(p->val));
2163  } else if (strcasecmp("path-separators-decode", p->name) == 0) {
2164  htp_config_set_path_separators_decode(cfg_prec->cfg, SCConfValIsTrue(p->val));
2165  } else if (strcasecmp("path-u-encoding-decode", p->name) == 0) {
2166  htp_config_set_u_encoding_decode(cfg_prec->cfg, SCConfValIsTrue(p->val));
2167  } else if (strcasecmp("path-url-encoding-invalid-handling", p->name) == 0) {
2168  enum htp_url_encoding_handling_t handling;
2169  if (strcasecmp(p->val, "preserve_percent") == 0) {
2170  handling = HTP_URL_ENCODING_HANDLING_PRESERVE_PERCENT;
2171  } else if (strcasecmp(p->val, "remove_percent") == 0) {
2172  handling = HTP_URL_ENCODING_HANDLING_REMOVE_PERCENT;
2173  } else if (strcasecmp(p->val, "decode_invalid") == 0) {
2174  handling = HTP_URL_ENCODING_HANDLING_PROCESS_INVALID;
2175  } else {
2176  SCLogError("Invalid entry "
2177  "for libhtp param path-url-encoding-invalid-handling");
2178  return;
2179  }
2180  htp_config_set_url_encoding_invalid_handling(cfg_prec->cfg, handling);
2181  } else if (strcasecmp("path-utf8-convert-bestfit", p->name) == 0) {
2182  htp_config_set_utf8_convert_bestfit(cfg_prec->cfg, SCConfValIsTrue(p->val));
2183  } else if (strcasecmp("uri-include-all", p->name) == 0) {
2184  htp_config_set_normalized_uri_include_all(cfg_prec->cfg, SCConfValIsTrue(p->val));
2185  SCLogDebug("uri-include-all %s", SCConfValIsTrue(p->val) ? "enabled" : "disabled");
2186  } else if (strcasecmp("query-plusspace-decode", p->name) == 0) {
2187  htp_config_set_plusspace_decode(cfg_prec->cfg, SCConfValIsTrue(p->val));
2188  } else if (strcasecmp("meta-field-limit", p->name) == 0) {
2189  uint32_t limit = 0;
2190  if (ParseSizeStringU32(p->val, &limit) < 0) {
2191  SCLogError("Error meta-field-limit "
2192  "from conf file - %s. Killing engine",
2193  p->val);
2194  exit(EXIT_FAILURE);
2195  }
2196  if (limit == 0) {
2197  FatalError("Error meta-field-limit "
2198  "from conf file cannot be 0. Killing engine");
2199  }
2200  /* set default soft-limit with our new hard limit */
2201  htp_config_set_field_limit(cfg_prec->cfg, (size_t)limit);
2202  } else if (strcasecmp("lzma-memlimit", p->name) == 0) {
2203  uint32_t limit = 0;
2204  if (ParseSizeStringU32(p->val, &limit) < 0) {
2205  FatalError("failed to parse 'lzma-memlimit' "
2206  "from conf file - %s.",
2207  p->val);
2208  }
2209  if (limit == 0) {
2210  FatalError("'lzma-memlimit' "
2211  "from conf file cannot be 0.");
2212  }
2213  /* set default soft-limit with our new hard limit */
2214  SCLogConfig("Setting HTTP LZMA memory limit to %"PRIu32" bytes", limit);
2215  htp_config_set_lzma_memlimit(cfg_prec->cfg, (size_t)limit);
2216  } else if (strcasecmp("lzma-enabled", p->name) == 0) {
2217  if (SCConfValIsTrue(p->val)) {
2218  htp_config_set_lzma_layers(cfg_prec->cfg, 1);
2219  } else if (!SCConfValIsFalse(p->val)) {
2220  int8_t limit;
2221  if (StringParseInt8(&limit, 10, 0, (const char *)p->val) < 0) {
2222  FatalError("failed to parse 'lzma-enabled' "
2223  "from conf file - %s.",
2224  p->val);
2225  }
2226  SCLogConfig("Setting HTTP LZMA decompression layers to %" PRIu32 "", (int)limit);
2227  htp_config_set_lzma_layers(cfg_prec->cfg, limit);
2228  }
2229  } else if (strcasecmp("compression-bomb-limit", p->name) == 0) {
2230  uint32_t limit = 0;
2231  if (ParseSizeStringU32(p->val, &limit) < 0) {
2232  FatalError("failed to parse 'compression-bomb-limit' "
2233  "from conf file - %s.",
2234  p->val);
2235  }
2236  if (limit == 0) {
2237  FatalError("'compression-bomb-limit' "
2238  "from conf file cannot be 0.");
2239  }
2240  /* set default soft-limit with our new hard limit */
2241  SCLogConfig("Setting HTTP compression bomb limit to %"PRIu32" bytes", limit);
2242  htp_config_set_compression_bomb_limit(cfg_prec->cfg, (size_t)limit);
2243  } else if (strcasecmp("decompression-time-limit", p->name) == 0) {
2244  uint32_t limit = 0;
2245  // between 1 usec and 1 second
2246  if (StringParseU32RangeCheck(&limit, 10, 0, p->val, 1, 1000000) < 0) {
2247  FatalError("failed to parse 'decompression-time-limit' "
2248  "from conf file - %s.",
2249  p->val);
2250  }
2251  SCLogConfig("Setting HTTP decompression time limit to %" PRIu32 " usec", limit);
2252  htp_config_set_compression_time_limit(cfg_prec->cfg, limit);
2253  } else if (strcasecmp("max-tx", p->name) == 0) {
2254  uint32_t limit = 0;
2255  if (ParseSizeStringU32(p->val, &limit) < 0) {
2256  FatalError("failed to parse 'max-tx' "
2257  "from conf file - %s.",
2258  p->val);
2259  }
2260  /* set default soft-limit with our new hard limit */
2261  SCLogConfig("Setting HTTP max-tx limit to %" PRIu32 " bytes", limit);
2262  htp_config_set_max_tx(cfg_prec->cfg, limit);
2263  } else if (strcasecmp("headers-limit", p->name) == 0) {
2264  uint32_t limit = 0;
2265  if (ParseSizeStringU32(p->val, &limit) < 0) {
2266  FatalError("failed to parse 'headers-limit' "
2267  "from conf file - %s.",
2268  p->val);
2269  }
2270  SCLogConfig("Setting HTTP headers limit to %" PRIu32, limit);
2271  htp_config_set_number_headers_limit(cfg_prec->cfg, limit);
2272  } else if (strcasecmp("randomize-inspection-sizes", p->name) == 0) {
2273  if (!g_disable_randomness) {
2274  cfg_prec->randomize = SCConfValIsTrue(p->val);
2275  }
2276  } else if (strcasecmp("randomize-inspection-range", p->name) == 0) {
2277  uint32_t range;
2278  if (StringParseU32RangeCheck(&range, 10, 0,
2279  (const char *)p->val, 0, 100) < 0) {
2280  SCLogError("Invalid value for randomize"
2281  "-inspection-range setting from conf file - \"%s\"."
2282  " It should be a valid integer less than or equal to 100."
2283  " Killing engine",
2284  p->val);
2285  exit(EXIT_FAILURE);
2286  }
2287  cfg_prec->randomize_range = range;
2288  } else if (strcasecmp("http-body-inline", p->name) == 0) {
2289  if (SCConfValIsTrue(p->val)) {
2290  cfg_prec->http_body_inline = 1;
2291  } else if (SCConfValIsFalse(p->val)) {
2292  cfg_prec->http_body_inline = 0;
2293  } else {
2294  if (strcmp("auto", p->val) != 0) {
2295  WarnInvalidConfEntry("http_body_inline", "%s", "auto");
2296  }
2297  if (EngineModeIsIPS()) {
2298  cfg_prec->http_body_inline = 1;
2299  } else {
2300  cfg_prec->http_body_inline = 0;
2301  }
2302  }
2303  } else if (strcasecmp("swf-decompression", p->name) == 0) {
2304  SCConfNode *pval;
2305 
2306  TAILQ_FOREACH(pval, &p->head, next) {
2307  if (strcasecmp("enabled", pval->name) == 0) {
2308  if (SCConfValIsTrue(pval->val)) {
2309  cfg_prec->swf_decompression_enabled = 1;
2310  } else if (SCConfValIsFalse(pval->val)) {
2311  cfg_prec->swf_decompression_enabled = 0;
2312  } else {
2313  WarnInvalidConfEntry("swf-decompression.enabled", "%s", "no");
2314  }
2315  } else if (strcasecmp("type", pval->name) == 0) {
2316  if (strcasecmp("no", pval->val) == 0) {
2318  } else if (strcasecmp("deflate", pval->val) == 0) {
2320  } else if (strcasecmp("lzma", pval->val) == 0) {
2322  } else if (strcasecmp("both", pval->val) == 0) {
2324  } else {
2325  SCLogError("Invalid entry for "
2326  "swf-decompression.type: %s - "
2327  "Killing engine",
2328  pval->val);
2329  exit(EXIT_FAILURE);
2330  }
2331  } else if (strcasecmp("compress-depth", pval->name) == 0) {
2332  if (ParseSizeStringU32(pval->val, &cfg_prec->swf_compress_depth) < 0) {
2333  SCLogError("Error parsing swf-decompression.compression-depth "
2334  "from conf file - %s. Killing engine",
2335  p->val);
2336  exit(EXIT_FAILURE);
2337  }
2338  } else if (strcasecmp("decompress-depth", pval->name) == 0) {
2339  if (ParseSizeStringU32(pval->val, &cfg_prec->swf_decompress_depth) < 0) {
2340  SCLogError("Error parsing swf-decompression.decompression-depth "
2341  "from conf file - %s. Killing engine",
2342  p->val);
2343  exit(EXIT_FAILURE);
2344  }
2345  } else {
2346  SCLogWarning("Ignoring unknown param %s", pval->name);
2347  }
2348  }
2349  } else {
2350  SCLogWarning("LIBHTP Ignoring unknown "
2351  "default config: %s",
2352  p->name);
2353  }
2354  } /* TAILQ_FOREACH(p, &default_config->head, next) */
2355 }
2356 
2357 void HTPConfigure(void)
2358 {
2359  SCEnter();
2360 
2361  cfglist.next = NULL;
2362 
2366 
2367  /* Default Config */
2368  cfglist.cfg = htp_config_create();
2369  if (NULL == cfglist.cfg) {
2370  FatalError("Failed to create HTP default config");
2371  }
2372  SCLogDebug("LIBHTP default config: %p", cfglist.cfg);
2373  HTPConfigSetDefaultsPhase1(&cfglist);
2374  if (SCConfGetNode("app-layer.protocols.http.libhtp") == NULL) {
2375  HTPConfigParseParameters(&cfglist, SCConfGetNode("libhtp.default-config"), &cfgtree);
2376  } else {
2377  HTPConfigParseParameters(&cfglist,
2378  SCConfGetNode("app-layer.protocols.http.libhtp.default-config"), &cfgtree);
2379  }
2380  HTPConfigSetDefaultsPhase2("default", &cfglist);
2381 
2382  HTPParseMemcap();
2383 
2384  /* Read server config and create a parser for each IP in radix tree */
2385  SCConfNode *server_config = SCConfGetNode("app-layer.protocols.http.libhtp.server-config");
2386  if (server_config == NULL) {
2387  server_config = SCConfGetNode("libhtp.server-config");
2388  if (server_config == NULL) {
2389  SCLogDebug("LIBHTP Configuring %p", server_config);
2390  SCReturn;
2391  }
2392  }
2393  SCLogDebug("LIBHTP Configuring %p", server_config);
2394 
2395  SCConfNode *si;
2396  /* Server Nodes */
2397  TAILQ_FOREACH(si, &server_config->head, next) {
2398  /* Need the named node, not the index */
2399  SCConfNode *s = TAILQ_FIRST(&si->head);
2400  if (NULL == s) {
2401  SCLogDebug("LIBHTP s NULL");
2402  continue;
2403  }
2404 
2405  SCLogDebug("LIBHTP server %s", s->name);
2406 
2407  HTPCfgRec *nextrec = cfglist.next;
2408  HTPCfgRec *htprec = SCCalloc(1, sizeof(HTPCfgRec));
2409  if (NULL == htprec)
2410  exit(EXIT_FAILURE);
2411 
2412  cfglist.next = htprec;
2413 
2414  cfglist.next->next = nextrec;
2415  cfglist.next->cfg = htp_config_create();
2416  if (NULL == cfglist.next->cfg) {
2417  FatalError("Failed to create HTP server config");
2418  }
2419 
2420  HTPConfigSetDefaultsPhase1(htprec);
2421  HTPConfigParseParameters(htprec, s, &cfgtree);
2422  HTPConfigSetDefaultsPhase2(s->name, htprec);
2423  }
2424 
2425  SCReturn;
2426 }
2427 
2429 {
2430 #ifdef DEBUG
2431  SCMutexLock(&htp_state_mem_lock);
2432  SCLogPerf("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
2433  SCMutexUnlock(&htp_state_mem_lock);
2434 #endif
2435 }
2436 
2437 /** \internal
2438  * \brief get files callback
2439  * \param state state ptr
2440  * \param direction flow direction
2441  * \retval files files ptr
2442  */
2443 static AppLayerGetFileState HTPGetTxFiles(void *txv, uint8_t direction)
2444 {
2445  AppLayerGetFileState files = { .fc = NULL, .cfg = &htp_sbcfg };
2446  htp_tx_t *tx = (htp_tx_t *)txv;
2447  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
2448  if (direction & STREAM_TOCLIENT) {
2449  files.fc = &tx_ud->files_tc;
2450  } else {
2451  files.fc = &tx_ud->files_ts;
2452  }
2453  return files;
2454 }
2455 
2456 static int HTPStateGetAlstateProgress(void *tx, uint8_t direction)
2457 {
2458  if (direction & STREAM_TOSERVER)
2459  return htp_tx_request_progress((htp_tx_t *)tx);
2460  else
2461  return htp_tx_response_progress((htp_tx_t *)tx);
2462 }
2463 
2464 static uint64_t HTPStateGetTxCnt(void *alstate)
2465 {
2466  HtpState *http_state = (HtpState *)alstate;
2467 
2468  if (http_state != NULL && http_state->connp != NULL) {
2469  const int64_t size = htp_connp_tx_size(http_state->connp);
2470  if (size < 0)
2471  return 0ULL;
2472  SCLogDebug("size %"PRIu64, size);
2473  return (uint64_t)size;
2474  } else {
2475  return 0ULL;
2476  }
2477 }
2478 
2479 static void *HTPStateGetTx(void *alstate, uint64_t tx_id)
2480 {
2481  HtpState *http_state = (HtpState *)alstate;
2482 
2483  if (http_state != NULL && http_state->connp != NULL)
2484  return (void *)htp_connp_tx(http_state->connp, tx_id);
2485  else
2486  return NULL;
2487 }
2488 
2489 void *HtpGetTxForH2(void *alstate)
2490 {
2491  // gets last transaction
2492  HtpState *http_state = (HtpState *)alstate;
2493  if (http_state != NULL && http_state->connp != NULL) {
2494  size_t txid = htp_connp_tx_size(http_state->connp);
2495  if (txid > 0) {
2496  return (void *)htp_connp_tx(http_state->connp, txid - 1);
2497  }
2498  }
2499  return NULL;
2500 }
2501 
2502 static int HTPStateGetEventInfo(
2503  const char *event_name, uint8_t *event_id, AppLayerEventType *event_type)
2504 {
2505  if (SCAppLayerGetEventIdByName(event_name, http_decoder_event_table, event_id) == 0) {
2506  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
2507  return 0;
2508  }
2509  return -1;
2510 }
2511 
2512 static int HTPStateGetEventInfoById(
2513  uint8_t event_id, const char **event_name, AppLayerEventType *event_type)
2514 {
2515  *event_name = SCMapEnumValueToName(event_id, http_decoder_event_table);
2516  if (*event_name == NULL) {
2517  SCLogError("event \"%d\" not present in "
2518  "http's enum map table.",
2519  event_id);
2520  /* this should be treated as fatal */
2521  return -1;
2522  }
2523 
2524  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
2525 
2526  return 0;
2527 }
2528 
2529 static AppLayerTxData *HTPGetTxData(void *vtx)
2530 {
2531  htp_tx_t *tx = (htp_tx_t *)vtx;
2532  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
2533  return &tx_ud->tx_data;
2534 }
2535 
2536 static AppLayerStateData *HTPGetStateData(void *vstate)
2537 {
2538  HtpState *s = vstate;
2539  return &s->state_data;
2540 }
2541 
2542 static int HTPRegisterPatternsForProtocolDetection(void)
2543 {
2544  const char *methods[] = { "GET", "PUT", "POST", "HEAD", "TRACE", "OPTIONS",
2545  "CONNECT", "DELETE", "PATCH", "PROPFIND", "PROPPATCH", "MKCOL",
2546  "COPY", "MOVE", "LOCK", "UNLOCK", "CHECKOUT", "UNCHECKOUT", "CHECKIN",
2547  "UPDATE", "LABEL", "REPORT", "MKWORKSPACE", "MKACTIVITY", "MERGE",
2548  "INVALID", "VERSION-CONTROL", "BASELINE-CONTROL", NULL};
2549  const char *spacings[] = { "|20|", "|09|", NULL };
2550  const char *versions[] = { "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", NULL };
2551 
2552  int methods_pos;
2553  int spacings_pos;
2554  int versions_pos;
2555  int register_result;
2556  char method_buffer[32] = "";
2557 
2558  /* Loop through all the methods ands spacings and register the patterns */
2559  for (methods_pos = 0; methods[methods_pos]; methods_pos++) {
2560  for (spacings_pos = 0; spacings[spacings_pos]; spacings_pos++) {
2561 
2562  /* Combine the method name and the spacing */
2563  snprintf(method_buffer, sizeof(method_buffer), "%s%s", methods[methods_pos], spacings[spacings_pos]);
2564 
2565  /* Register the new method+spacing pattern
2566  * 3 is subtracted from the length since the spacing is hex typed as |xx|
2567  * but the pattern matching should only be one char
2568  */
2569  register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1,
2570  method_buffer, (uint16_t)strlen(method_buffer) - 3, 0, STREAM_TOSERVER);
2571  if (register_result < 0) {
2572  return -1;
2573  }
2574  }
2575  }
2576 
2577  /* Loop through all the http version patterns that are TO_CLIENT */
2578  for (versions_pos = 0; versions[versions_pos]; versions_pos++) {
2579  register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1,
2580  versions[versions_pos], (uint16_t)strlen(versions[versions_pos]), 0,
2581  STREAM_TOCLIENT);
2582  if (register_result < 0) {
2583  return -1;
2584  }
2585  }
2586 
2587  return 0;
2588 }
2589 
2590 /**
2591  * \brief Register the HTTP protocol and state handling functions to APP layer
2592  * of the engine.
2593  */
2595 {
2596  SCEnter();
2597 
2598  const char *proto_name = "http";
2599 
2600  /** HTTP */
2601  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
2603  if (HTPRegisterPatternsForProtocolDetection() < 0)
2604  return;
2605  } else {
2606  SCLogInfo("Protocol detection and parser disabled for %s protocol",
2607  proto_name);
2608  return;
2609  }
2610 
2611  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
2612  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateAlloc, HTPStateFree);
2613  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateTransactionFree);
2614  AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxFiles);
2616  IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetAlstateProgress);
2617  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTxCnt);
2618  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTx);
2619 
2621  ALPROTO_HTTP1, HTP_REQUEST_PROGRESS_COMPLETE, HTP_RESPONSE_PROGRESS_COMPLETE);
2622  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfo);
2624  IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfoById);
2625 
2626  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxData);
2627  AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetStateData);
2628 
2630  IPPROTO_TCP, ALPROTO_HTTP1, AppLayerHtpSetStreamDepthFlag);
2631 
2633  IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER, HTPHandleRequestData);
2635  IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOCLIENT, HTPHandleResponseData);
2636  SC_ATOMIC_INIT(htp_config_flags);
2637  /* This parser accepts gaps. */
2641  IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_TOCLIENT);
2642  /* app-layer-frame-documentation tag start: registering relevant callbacks */
2644  IPPROTO_TCP, ALPROTO_HTTP1, HTTPGetFrameIdByName, HTTPGetFrameNameById);
2645  /* app-layer-frame-documentation tag end: registering relevant callbacks */
2647  IPPROTO_TCP, ALPROTO_HTTP1, HtpStateGetStateIdByName, HtpStateGetStateNameById);
2648 
2649  HTPConfigure();
2650  } else {
2651  SCLogInfo("Parser disabled for %s protocol. Protocol detection still on.", proto_name);
2652  }
2653 #ifdef UNITTESTS
2654  AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_HTTP1, HTPParserRegisterTests);
2655 #endif
2656 
2657  SCReturn;
2658 }
2659 
2660 #ifdef UNITTESTS
2661 #include "detect-engine-alert.h"
2662 
2663 static HTPCfgRec cfglist_backup;
2664 
2666 {
2667  cfglist_backup = cfglist;
2668 }
2669 
2671 {
2672  cfglist = cfglist_backup;
2673 }
2674 
2675 /** \test Test case where chunks are sent in smaller chunks and check the
2676  * response of the parser from HTP library. */
2677 static int HTPParserTest01(void)
2678 {
2679  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
2680  " Data is c0oL!";
2681  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2682 
2683  TcpSession ssn;
2684  memset(&ssn, 0, sizeof(ssn));
2685 
2688 
2689  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2690  FAIL_IF_NULL(f);
2691  f->protoctx = &ssn;
2692  f->proto = IPPROTO_TCP;
2693  f->alproto = ALPROTO_HTTP1;
2694 
2695  StreamTcpInitConfig(true);
2696 
2697  uint32_t u;
2698  for (u = 0; u < httplen1; u++) {
2699  uint8_t flags = 0;
2700 
2701  if (u == 0)
2702  flags = STREAM_TOSERVER|STREAM_START;
2703  else if (u == (httplen1 - 1))
2704  flags = STREAM_TOSERVER|STREAM_EOF;
2705  else
2706  flags = STREAM_TOSERVER;
2707 
2708  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
2709  FAIL_IF(r != 0);
2710  }
2711 
2712  HtpState *htp_state = f->alstate;
2713  FAIL_IF_NULL(htp_state);
2714 
2715  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2716  FAIL_IF_NULL(tx);
2717 
2718  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2719  FAIL_IF_NULL(h);
2720 
2721  FAIL_IF(bstr_cmp_c(htp_header_value(h), "Victor/1.0"));
2722  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_POST);
2723  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2724 
2726  StreamTcpFreeConfig(true);
2727  UTHFreeFlow(f);
2728  PASS;
2729 }
2730 
2731 /** \test Test folding in 1 read case */
2732 static int HTPParserTest01b(void)
2733 {
2734  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost"
2735  " Data is c0oL!";
2736  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2737 
2738  TcpSession ssn;
2739  memset(&ssn, 0, sizeof(ssn));
2740 
2743 
2744  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2745  FAIL_IF_NULL(f);
2746  f->protoctx = &ssn;
2747  f->proto = IPPROTO_TCP;
2748  f->alproto = ALPROTO_HTTP1;
2749 
2750  StreamTcpInitConfig(true);
2751 
2752  uint8_t flags =STREAM_TOSERVER|STREAM_START|STREAM_EOF;
2753  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1);
2754  FAIL_IF(r != 0);
2755 
2756  HtpState *htp_state = f->alstate;
2757  FAIL_IF_NULL(htp_state);
2758 
2759  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2760  FAIL_IF_NULL(tx);
2761 
2762  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2763  FAIL_IF_NULL(h);
2764 
2765  FAIL_IF(strcmp(bstr_util_strdup_to_c(htp_header_value(h)), "Victor/1.0"));
2766  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_POST);
2767  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2768 
2770  StreamTcpFreeConfig(true);
2771  UTHFreeFlow(f);
2772  PASS;
2773 }
2774 
2775 /** \test Test folding in 1byte per read case */
2776 static int HTPParserTest01c(void)
2777 {
2778  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost"
2779  " Data is c0oL!";
2780  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2781 
2782  TcpSession ssn;
2783  memset(&ssn, 0, sizeof(ssn));
2784 
2787 
2788  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2789  FAIL_IF_NULL(f);
2790  f->protoctx = &ssn;
2791  f->proto = IPPROTO_TCP;
2792  f->alproto = ALPROTO_HTTP1;
2793 
2794  StreamTcpInitConfig(true);
2795 
2796  uint32_t u;
2797  for (u = 0; u < httplen1; u++) {
2798  uint8_t flags = 0;
2799 
2800  if (u == 0)
2801  flags = STREAM_TOSERVER|STREAM_START;
2802  else if (u == (httplen1 - 1))
2803  flags = STREAM_TOSERVER|STREAM_EOF;
2804  else
2805  flags = STREAM_TOSERVER;
2806 
2807  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
2808  FAIL_IF(r != 0);
2809  }
2810 
2811  HtpState *htp_state = f->alstate;
2812  FAIL_IF_NULL(htp_state);
2813 
2814  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2815  FAIL_IF_NULL(tx);
2816 
2817  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2818  FAIL_IF_NULL(h);
2819 
2820  FAIL_IF(strcmp(bstr_util_strdup_to_c(htp_header_value(h)), "Victor/1.0"));
2821  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_POST);
2822  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2823 
2825  StreamTcpFreeConfig(true);
2826  UTHFreeFlow(f);
2827  PASS;
2828 }
2829 
2830 /** \test Test case where chunks are sent in smaller chunks and check the
2831  * response of the parser from HTP library. */
2832 static int HTPParserTest01a(void)
2833 {
2834  Flow *f = NULL;
2835  uint8_t httpbuf1[] = " POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
2836  " Data is c0oL!";
2837  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2838  TcpSession ssn;
2839  HtpState *htp_state = NULL;
2841 
2842  memset(&ssn, 0, sizeof(ssn));
2843 
2844  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2845  FAIL_IF_NULL(f);
2846  f->protoctx = &ssn;
2847  f->proto = IPPROTO_TCP;
2848  f->alproto = ALPROTO_HTTP1;
2849 
2850  StreamTcpInitConfig(true);
2851 
2852  uint32_t u;
2853  for (u = 0; u < httplen1; u++) {
2854  uint8_t flags = 0;
2855 
2856  if (u == 0)
2857  flags = STREAM_TOSERVER|STREAM_START;
2858  else if (u == (httplen1 - 1))
2859  flags = STREAM_TOSERVER|STREAM_EOF;
2860  else
2861  flags = STREAM_TOSERVER;
2862 
2863  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
2864  FAIL_IF(r != 0);
2865  }
2866 
2867  htp_state = f->alstate;
2868  FAIL_IF_NULL(htp_state);
2869 
2870  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2871  FAIL_IF_NULL(tx);
2872 
2873  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2874  FAIL_IF_NULL(h);
2875 
2876  FAIL_IF(strcmp(bstr_util_strdup_to_c(htp_header_value(h)), "Victor/1.0"));
2877  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_POST);
2878  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2879 
2881  StreamTcpFreeConfig(true);
2882  UTHFreeFlow(f);
2883  PASS;
2884 }
2885 
2886 /** \test See how it deals with an incomplete request. */
2887 static int HTPParserTest02(void)
2888 {
2889  Flow *f = NULL;
2890  uint8_t httpbuf1[] = "POST";
2891  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2892  TcpSession ssn;
2893  HtpState *http_state = NULL;
2895 
2896  memset(&ssn, 0, sizeof(ssn));
2897 
2898  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2899  FAIL_IF_NULL(f);
2900  f->protoctx = &ssn;
2901  f->proto = IPPROTO_TCP;
2902  f->alproto = ALPROTO_HTTP1;
2903 
2904  StreamTcpInitConfig(true);
2905 
2906  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
2907  STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
2908  FAIL_IF(r != 0);
2909 
2910  http_state = f->alstate;
2911  FAIL_IF_NULL(http_state);
2912 
2913  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
2914  FAIL_IF_NULL(tx);
2915  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2916  FAIL_IF_NOT_NULL(h);
2917 
2918  FAIL_IF_NULL(htp_tx_request_method(tx));
2919  char *method = bstr_util_strdup_to_c(htp_tx_request_method(tx));
2920  FAIL_IF_NULL(method);
2921 
2922  FAIL_IF(strcmp(method, "POST") != 0);
2923  SCFree(method);
2924 
2926  StreamTcpFreeConfig(true);
2927  UTHFreeFlow(f);
2928  PASS;
2929 }
2930 
2931 /** \test Test case where method is invalid and data is sent in smaller chunks
2932  * and check the response of the parser from HTP library. */
2933 static int HTPParserTest03(void)
2934 {
2935  Flow *f = NULL;
2936  uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n";
2937  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2938  TcpSession ssn;
2939  HtpState *htp_state = NULL;
2941 
2942  memset(&ssn, 0, sizeof(ssn));
2943 
2944  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2945  FAIL_IF_NULL(f);
2946  f->protoctx = &ssn;
2947  f->proto = IPPROTO_TCP;
2948  f->alproto = ALPROTO_HTTP1;
2949 
2950  StreamTcpInitConfig(true);
2951 
2952  uint32_t u;
2953  for (u = 0; u < httplen1; u++) {
2954  uint8_t flags = 0;
2955 
2956  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
2957  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
2958  else flags = STREAM_TOSERVER;
2959 
2960  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
2961  FAIL_IF(r != 0);
2962  }
2963  htp_state = f->alstate;
2964  FAIL_IF_NULL(htp_state);
2965 
2966  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2967  FAIL_IF_NULL(tx);
2968 
2969  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2970  FAIL_IF_NOT_NULL(h);
2971  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_UNKNOWN);
2972  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2973 
2975  StreamTcpFreeConfig(true);
2976  UTHFreeFlow(f);
2977  PASS;
2978 }
2979 
2980 /** \test Test case where invalid data is sent and check the response of the
2981  * parser from HTP library. */
2982 static int HTPParserTest04(void)
2983 {
2984  Flow *f = NULL;
2985  HtpState *htp_state = NULL;
2986  uint8_t httpbuf1[] = "World!\r\n";
2987  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2988  TcpSession ssn;
2990 
2991  memset(&ssn, 0, sizeof(ssn));
2992 
2993  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2994  FAIL_IF_NULL(f);
2995  f->protoctx = &ssn;
2996  f->proto = IPPROTO_TCP;
2997  f->alproto = ALPROTO_HTTP1;
2998 
2999  StreamTcpInitConfig(true);
3000 
3001  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
3002  STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
3003  FAIL_IF(r != 0);
3004 
3005  htp_state = f->alstate;
3006  FAIL_IF_NULL(htp_state);
3007 
3008  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3009  FAIL_IF_NULL(tx);
3010  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3011  FAIL_IF_NOT_NULL(h);
3012  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_UNKNOWN);
3013  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V0_9);
3014 
3016  StreamTcpFreeConfig(true);
3017  UTHFreeFlow(f);
3018  PASS;
3019 }
3020 
3021 /** \test Test both sides of a http stream mixed up to see if the HTP parser
3022  * properly parsed them and also keeps them separated. */
3023 static int HTPParserTest05(void)
3024 {
3025  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\nContent-Length: 17\r\n\r\n";
3026  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3027  uint8_t httpbuf2[] = "Post D";
3028  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3029  uint8_t httpbuf3[] = "ata is c0oL!";
3030  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
3031 
3032  uint8_t httpbuf4[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
3033  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
3034  uint8_t httpbuf5[] = "post R";
3035  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3036  uint8_t httpbuf6[] = "esults are tha bomb!";
3037  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
3038 
3039  TcpSession ssn;
3040  memset(&ssn, 0, sizeof(ssn));
3041 
3044 
3045  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3046  FAIL_IF_NULL(f);
3047  f->protoctx = &ssn;
3048  f->proto = IPPROTO_TCP;
3049  f->alproto = ALPROTO_HTTP1;
3050 
3051  StreamTcpInitConfig(true);
3052 
3053  int r = AppLayerParserParse(
3054  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
3055  FAIL_IF(r != 0);
3056 
3057  r = AppLayerParserParse(
3058  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf4, httplen4);
3059  FAIL_IF(r != 0);
3060 
3061  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf5, httplen5);
3062  FAIL_IF(r != 0);
3063 
3064  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
3065  FAIL_IF(r != 0);
3066 
3067  r = AppLayerParserParse(
3068  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
3069  FAIL_IF(r != 0);
3070 
3071  r = AppLayerParserParse(
3072  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_EOF, httpbuf6, httplen6);
3073  FAIL_IF(r != 0);
3074 
3075  HtpState *http_state = f->alstate;
3076  FAIL_IF_NULL(http_state);
3077 
3078  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
3079  FAIL_IF_NULL(tx);
3080  FAIL_IF_NOT(htp_tx_request_method_number(tx) == HTP_METHOD_POST);
3081  FAIL_IF_NOT(htp_tx_request_protocol_number(tx) == HTP_PROTOCOL_V1_0);
3082 
3083  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3084  FAIL_IF_NULL(h);
3085 
3086  FAIL_IF_NOT(htp_tx_response_status_number(tx) == 200);
3087 
3089  StreamTcpFreeConfig(true);
3090  UTHFreeFlow(f);
3091  PASS;
3092 }
3093 
3094 /** \test Test proper chunked encoded response body
3095  */
3096 static int HTPParserTest06(void)
3097 {
3098  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
3099  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
3100  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
3101  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3102  uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nDate: Sat, 03 Oct 2009 10:16:02 "
3103  "GMT\r\n"
3104  "Server: Apache/1.3.37 (Unix) mod_ssl/2.8.28 "
3105  "OpenSSL/0.9.7a PHP/4.4.7 mod_perl/1.29 "
3106  "FrontPage/5.0.2.2510\r\n"
3107  "X-Powered-By: PHP/4.4.7\r\nTransfer-Encoding: "
3108  "chunked\r\n"
3109  "Content-Type: text/html\r\n\r\n"
3110  "580\r\n"
3111  "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu"
3112  "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN"
3113  "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N"
3114  "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk"
3115  "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l"
3116  "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN"
3117  "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt"
3118  "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz"
3119  "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw"
3120  "aG9uZTM9DQpsb2dpbjM9DQpwYXNzd29yZDM9DQpwaG9uZTQ9DQps"
3121  "b2dpbjQ9DQpwYXNzd29yZDQ9DQpwaG9uZTU9DQpsb2dpbjU9DQpw"
3122  "YXNzd29yZDU9DQpwaG9uZTY9DQpsb2dpbjY9DQpwYXNzd29yZDY9"
3123  "DQpjYWxsX3RpbWUxPQ0KY2FsbF90aW1lMj0NCmRheV9saW1pdD0N"
3124  "Cm1vbnRoX2xpbWl0PQ0KW2dyb3VwM10NCnBob25lMT0NCmxvZ2lu"
3125  "MT0NCnBhc3N3b3JkMT0NCnBob25lMj0NCmxvZ2luMj0NCnBhc3N3"
3126  "b3JkMj0NCnBob25lMz0NCmxvZ2luMz0NCnBhc3N3b3JkMz0NCnBo"
3127  "b25lND0NCmxvZ2luND0NCnBhc3N3b3JkND0NCnBob25lNT0NCmxv"
3128  "Z2luNT0NCnBhc3N3b3JkNT0NCnBob25lNj0NCmxvZ2luNj0NCnBh"
3129  "c3N3b3JkNj0NCmNhbGxfdGltZTE9DQpjYWxsX3RpbWUyPQ0KZGF5"
3130  "X2xpbWl0PQ0KbW9udGhfbGltaXQ9DQpbZ3JvdXA0XQ0KcGhvbmUx"
3131  "PQ0KbG9naW4xPQ0KcGFzc3dvcmQxPQ0KcGhvbmUyPQ0KbG9naW4y"
3132  "PQ0KcGFzc3dvcmQyPQ0KcGhvbmUzPQ0KbG9naW4zPQ0KcGFzc3dv"
3133  "cmQzPQ0KcGhvbmU0PQ0KbG9naW40PQ0KcGFzc3dvcmQ0PQ0KcGhv"
3134  "bmU1PQ0KbG9naW41PQ0KcGFzc3dvcmQ1PQ0KcGhvbmU2PQ0KbG9n"
3135  "aW42PQ0KcGFzc3dvcmQ2PQ0KY2FsbF90aW1lMT0NCmNhbGxfdGlt"
3136  "ZTI9DQpkYXlfbGltaXQ9DQptb250aF9saW1pdD0NCltmaWxlc10N"
3137  "Cmxpbms9aHR0cDovLzIwOS4yMDUuMTk2LjE2L2xkL2dldGJvdC5w"
3138  "aHA=\r\n0\r\n\r\n";
3139  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3140  TcpSession ssn;
3141 
3144 
3145  memset(&ssn, 0, sizeof(ssn));
3146 
3147  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3148  FAIL_IF_NULL(f);
3149  f->protoctx = &ssn;
3150  f->proto = IPPROTO_TCP;
3151  f->alproto = ALPROTO_HTTP1;
3152 
3153  StreamTcpInitConfig(true);
3154 
3155  int r = AppLayerParserParse(
3156  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
3157  FAIL_IF(r != 0);
3158  r = AppLayerParserParse(
3159  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
3160  FAIL_IF(r != 0);
3161 
3162  HtpState *http_state = f->alstate;
3163  FAIL_IF_NULL(http_state);
3164 
3165  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
3166  FAIL_IF_NULL(tx);
3167 
3168  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
3169  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
3170 
3171  FAIL_IF(htp_tx_response_status_number(tx) != 200);
3172  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
3173 
3174  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3175  FAIL_IF_NULL(h);
3176 
3178  StreamTcpFreeConfig(true);
3179  UTHFreeFlow(f);
3180  PASS;
3181 }
3182 
3183 /** \test
3184  */
3185 static int HTPParserTest07(void)
3186 {
3187  Flow *f = NULL;
3188  uint8_t httpbuf1[] = "GET /awstats.pl?/migratemigrate%20=%20| HTTP/1.0\r\n\r\n";
3189  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3190  TcpSession ssn;
3191  HtpState *htp_state = NULL;
3193 
3194  memset(&ssn, 0, sizeof(ssn));
3195 
3196  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3197  FAIL_IF_NULL(f);
3198  f->protoctx = &ssn;
3199  f->proto = IPPROTO_TCP;
3200  f->alproto = ALPROTO_HTTP1;
3201 
3202  StreamTcpInitConfig(true);
3203 
3204  uint32_t u;
3205  for (u = 0; u < httplen1; u++) {
3206  uint8_t flags = 0;
3207 
3208  if (u == 0)
3209  flags = STREAM_TOSERVER|STREAM_START;
3210  else if (u == (httplen1 - 1))
3211  flags = STREAM_TOSERVER|STREAM_EOF;
3212  else
3213  flags = STREAM_TOSERVER;
3214 
3215  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3216  FAIL_IF(r != 0);
3217  }
3218 
3219  htp_state = f->alstate;
3220  FAIL_IF_NULL(htp_state);
3221 
3222  uint8_t ref[] = "/awstats.pl?/migratemigrate = |";
3223  size_t reflen = sizeof(ref) - 1;
3224 
3225  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3226  FAIL_IF_NULL(tx);
3227  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3228  FAIL_IF_NULL(request_uri_normalized);
3229  FAIL_IF(reflen != bstr_len(request_uri_normalized));
3230 
3231  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref, bstr_len(request_uri_normalized)) != 0);
3232 
3234  StreamTcpFreeConfig(true);
3235  UTHFreeFlow(f);
3236  PASS;
3237 }
3238 
3239 #include "conf-yaml-loader.h"
3240 
3241 /** \test Abort
3242  */
3243 static int HTPParserTest08(void)
3244 {
3245  Flow *f = NULL;
3246  uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
3247  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3248  TcpSession ssn;
3250 
3251  char input[] = "\
3252 %YAML 1.1\n\
3253 ---\n\
3254 libhtp:\n\
3255 \n\
3256  default-config:\n\
3257  personality: IDS\n\
3258 ";
3259 
3261  SCConfInit();
3263 
3264  SCConfYamlLoadString(input, strlen(input));
3265  HTPConfigure();
3266 
3267  HtpState *htp_state = NULL;
3268  memset(&ssn, 0, sizeof(ssn));
3269 
3270  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3271  FAIL_IF_NULL(f);
3272  f->protoctx = &ssn;
3273  f->proto = IPPROTO_TCP;
3274  f->alproto = ALPROTO_HTTP1;
3275 
3276  StreamTcpInitConfig(true);
3277 
3278  uint8_t flags = STREAM_TOSERVER | STREAM_START | STREAM_EOF;
3279 
3280  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1);
3281  FAIL_IF(r != 0);
3282 
3283  htp_state = f->alstate;
3284  FAIL_IF_NULL(htp_state);
3285 
3286  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3287  FAIL_IF_NULL(tx);
3288  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3289  FAIL_IF_NULL(request_uri_normalized);
3290  PrintRawDataFp(stdout, bstr_ptr(request_uri_normalized), bstr_len(request_uri_normalized));
3291 
3293  StreamTcpFreeConfig(true);
3294  HTPFreeConfig();
3295  SCConfDeInit();
3298  UTHFreeFlow(f);
3299  PASS;
3300 }
3301 
3302 /** \test Abort
3303  */
3304 static int HTPParserTest09(void)
3305 {
3306  Flow *f = NULL;
3307  uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
3308  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3309  TcpSession ssn;
3311 
3312  char input[] = "\
3313 %YAML 1.1\n\
3314 ---\n\
3315 libhtp:\n\
3316 \n\
3317  default-config:\n\
3318  personality: Apache_2_2\n\
3319 ";
3320 
3322  SCConfInit();
3324 
3325  SCConfYamlLoadString(input, strlen(input));
3326  HTPConfigure();
3327 
3328  HtpState *htp_state = NULL;
3329 
3330  memset(&ssn, 0, sizeof(ssn));
3331 
3332  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3333  FAIL_IF_NULL(f);
3334  f->protoctx = &ssn;
3335  f->proto = IPPROTO_TCP;
3336  f->alproto = ALPROTO_HTTP1;
3337 
3338  StreamTcpInitConfig(true);
3339 
3340  uint8_t flags = STREAM_TOSERVER | STREAM_START | STREAM_EOF;
3341 
3342  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1);
3343  FAIL_IF(r != 0);
3344 
3345  htp_state = f->alstate;
3346  FAIL_IF_NULL(htp_state);
3347 
3348  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3349  FAIL_IF_NULL(tx);
3350  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3351  FAIL_IF_NULL(request_uri_normalized);
3352  PrintRawDataFp(stdout, bstr_ptr(request_uri_normalized), bstr_len(request_uri_normalized));
3353 
3355  StreamTcpFreeConfig(true);
3356  HTPFreeConfig();
3357  SCConfDeInit();
3360  UTHFreeFlow(f);
3361  PASS;
3362 }
3363 
3364 /** \test Host:www.google.com <- missing space between name:value (rfc violation)
3365  */
3366 static int HTPParserTest10(void)
3367 {
3368 
3369  Flow *f = NULL;
3370  uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\r\n\r\n";
3371  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3372  TcpSession ssn;
3373  HtpState *htp_state = NULL;
3375 
3376  memset(&ssn, 0, sizeof(ssn));
3377 
3378  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3379  FAIL_IF_NULL(f);
3380  f->protoctx = &ssn;
3381  f->proto = IPPROTO_TCP;
3382  f->alproto = ALPROTO_HTTP1;
3383 
3384  StreamTcpInitConfig(true);
3385 
3386  uint32_t u;
3387  for (u = 0; u < httplen1; u++) {
3388  uint8_t flags = 0;
3389 
3390  if (u == 0)
3391  flags = STREAM_TOSERVER|STREAM_START;
3392  else if (u == (httplen1 - 1))
3393  flags = STREAM_TOSERVER|STREAM_EOF;
3394  else
3395  flags = STREAM_TOSERVER;
3396 
3397  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3398  FAIL_IF(r != 0);
3399  }
3400 
3401  htp_state = f->alstate;
3402  FAIL_IF_NULL(htp_state);
3403 
3404  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3405  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3406  FAIL_IF_NULL(h);
3407 
3408  char *name = bstr_util_strdup_to_c(htp_header_name(h));
3409  FAIL_IF_NULL(name);
3410  FAIL_IF(strcmp(name, "Host") != 0);
3411 
3412  char *value = bstr_util_strdup_to_c(htp_header_value(h));
3413  FAIL_IF_NULL(value);
3414  FAIL_IF(strcmp(value, "www.google.com") != 0);
3415 
3417  StreamTcpFreeConfig(true);
3418  UTHFreeFlow(f);
3419  SCFree(name);
3420  SCFree(value);
3421  PASS;
3422 }
3423 
3424 /** \test double encoding in path
3425  */
3426 static int HTPParserTest11(void)
3427 {
3428  Flow *f = NULL;
3429  uint8_t httpbuf1[] = "GET /%2500 HTTP/1.0\r\n\r\n";
3430  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3431  TcpSession ssn;
3432  HtpState *htp_state = NULL;
3434 
3435  memset(&ssn, 0, sizeof(ssn));
3436 
3437  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3438  FAIL_IF_NULL(f);
3439  f->protoctx = &ssn;
3440  f->proto = IPPROTO_TCP;
3441  f->alproto = ALPROTO_HTTP1;
3442 
3443  StreamTcpInitConfig(true);
3444 
3445  uint32_t u;
3446  for (u = 0; u < httplen1; u++) {
3447  uint8_t flags = 0;
3448 
3449  if (u == 0)
3450  flags = STREAM_TOSERVER|STREAM_START;
3451  else if (u == (httplen1 - 1))
3452  flags = STREAM_TOSERVER|STREAM_EOF;
3453  else
3454  flags = STREAM_TOSERVER;
3455 
3456  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3457  FAIL_IF(r != 0);
3458  }
3459 
3460  htp_state = f->alstate;
3461  FAIL_IF_NULL(htp_state);
3462 
3463  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3464  FAIL_IF_NULL(tx);
3465  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3466  FAIL_IF_NULL(request_uri_normalized);
3467 
3468  FAIL_IF(bstr_len(request_uri_normalized) != 4);
3469  FAIL_IF(bstr_ptr(request_uri_normalized)[0] != '/');
3470  FAIL_IF(bstr_ptr(request_uri_normalized)[1] != '%');
3471  FAIL_IF(bstr_ptr(request_uri_normalized)[2] != '0');
3472  FAIL_IF(bstr_ptr(request_uri_normalized)[3] != '0');
3473 
3475  StreamTcpFreeConfig(true);
3476  UTHFreeFlow(f);
3477  PASS;
3478 }
3479 
3480 /** \test double encoding in query
3481  */
3482 static int HTPParserTest12(void)
3483 {
3484  Flow *f = NULL;
3485  uint8_t httpbuf1[] = "GET /?a=%2500 HTTP/1.0\r\n\r\n";
3486  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3487  TcpSession ssn;
3488  HtpState *htp_state = NULL;
3490 
3491  memset(&ssn, 0, sizeof(ssn));
3492 
3493  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3494  FAIL_IF_NULL(f);
3495  f->protoctx = &ssn;
3496  f->proto = IPPROTO_TCP;
3497  f->alproto = ALPROTO_HTTP1;
3498 
3499  StreamTcpInitConfig(true);
3500 
3501  uint32_t u;
3502  for (u = 0; u < httplen1; u++) {
3503  uint8_t flags = 0;
3504 
3505  if (u == 0)
3506  flags = STREAM_TOSERVER|STREAM_START;
3507  else if (u == (httplen1 - 1))
3508  flags = STREAM_TOSERVER|STREAM_EOF;
3509  else
3510  flags = STREAM_TOSERVER;
3511 
3512  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3513  FAIL_IF(r != 0);
3514  }
3515 
3516  htp_state = f->alstate;
3517  FAIL_IF_NULL(htp_state);
3518 
3519  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3520  FAIL_IF_NULL(tx);
3521  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3522  FAIL_IF_NULL(request_uri_normalized);
3523 
3524  FAIL_IF(bstr_len(request_uri_normalized) != 7);
3525  FAIL_IF(bstr_ptr(request_uri_normalized)[0] != '/');
3526  FAIL_IF(bstr_ptr(request_uri_normalized)[1] != '?');
3527  FAIL_IF(bstr_ptr(request_uri_normalized)[2] != 'a');
3528  FAIL_IF(bstr_ptr(request_uri_normalized)[3] != '=');
3529  FAIL_IF(bstr_ptr(request_uri_normalized)[4] != '%');
3530  FAIL_IF(bstr_ptr(request_uri_normalized)[5] != '0');
3531  FAIL_IF(bstr_ptr(request_uri_normalized)[6] != '0');
3532 
3534  StreamTcpFreeConfig(true);
3535  UTHFreeFlow(f);
3536  PASS;
3537 }
3538 
3539 /** \test Host:www.google.com0dName: Value0d0a <- missing space between name:value (rfc violation)
3540  */
3541 static int HTPParserTest13(void)
3542 {
3543  Flow *f = NULL;
3544  uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\rName: Value\r\n\r\n";
3545  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3546  TcpSession ssn;
3547  HtpState *htp_state = NULL;
3549 
3550  memset(&ssn, 0, sizeof(ssn));
3551 
3552  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3553  FAIL_IF_NULL(f);
3554  f->protoctx = &ssn;
3555  f->proto = IPPROTO_TCP;
3556  f->alproto = ALPROTO_HTTP1;
3557 
3558  StreamTcpInitConfig(true);
3559 
3560  uint32_t u;
3561  for (u = 0; u < httplen1; u++) {
3562  uint8_t flags = 0;
3563 
3564  if (u == 0)
3565  flags = STREAM_TOSERVER|STREAM_START;
3566  else if (u == (httplen1 - 1))
3567  flags = STREAM_TOSERVER|STREAM_EOF;
3568  else
3569  flags = STREAM_TOSERVER;
3570 
3571  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3572  FAIL_IF(r != 0);
3573  }
3574 
3575  htp_state = f->alstate;
3576  FAIL_IF_NULL(htp_state);
3577  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3578  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3579  FAIL_IF_NULL(h);
3580 
3581  char *name = bstr_util_strdup_to_c(htp_header_name(h));
3582  FAIL_IF_NULL(name);
3583  FAIL_IF(strcmp(name, "Host") != 0);
3584 
3585  char *value = bstr_util_strdup_to_c(htp_header_value(h));
3586  FAIL_IF_NULL(value);
3587  FAIL_IF(strcmp(value, "www.google.com\rName: Value") != 0);
3588 
3590  StreamTcpFreeConfig(true);
3591  UTHFreeFlow(f);
3592  SCFree(name);
3593  SCFree(value);
3594 
3595  PASS;
3596 }
3597 
3598 /** \test Test basic config */
3599 static int HTPParserConfigTest01(void)
3600 {
3601  char input[] = "\
3602 %YAML 1.1\n\
3603 ---\n\
3604 libhtp:\n\
3605 \n\
3606  default-config:\n\
3607  personality: IDS\n\
3608 \n\
3609  server-config:\n\
3610 \n\
3611  - apache-tomcat:\n\
3612  address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
3613  personality: Tomcat_6_0\n\
3614 \n\
3615  - iis7:\n\
3616  address: \n\
3617  - 192.168.0.0/24\n\
3618  - 192.168.10.0/24\n\
3619  personality: IIS_7_0\n\
3620 ";
3621 
3623  SCConfInit();
3624 
3625  SCConfYamlLoadString(input, strlen(input));
3626 
3627  SCConfNode *outputs;
3628  outputs = SCConfGetNode("libhtp.default-config.personality");
3629  FAIL_IF_NULL(outputs);
3630 
3631  outputs = SCConfGetNode("libhtp.server-config");
3632  FAIL_IF_NULL(outputs);
3633 
3634  SCConfNode *node = TAILQ_FIRST(&outputs->head);
3635  FAIL_IF_NULL(node);
3636  FAIL_IF(strcmp(node->name, "0") != 0);
3637  node = TAILQ_FIRST(&node->head);
3638  FAIL_IF_NULL(node);
3639  FAIL_IF(strcmp(node->name, "apache-tomcat") != 0);
3640 
3641  int i = 0;
3642  SCConfNode *n;
3643 
3644  SCConfNode *node2 = SCConfNodeLookupChild(node, "personality");
3645  FAIL_IF_NULL(node2);
3646  FAIL_IF(strcmp(node2->val, "Tomcat_6_0") != 0);
3647 
3648  node = SCConfNodeLookupChild(node, "address");
3649  FAIL_IF_NULL(node);
3650 
3651  TAILQ_FOREACH (n, &node->head, next) {
3652  FAIL_IF_NULL(n);
3653  switch(i) {
3654  case 0:
3655  FAIL_IF(strcmp(n->name, "0") != 0);
3656  FAIL_IF(strcmp(n->val, "192.168.1.0/24") != 0);
3657  break;
3658  case 1:
3659  FAIL_IF(strcmp(n->name, "1") != 0);
3660  FAIL_IF(strcmp(n->val, "127.0.0.0/8") != 0);
3661  break;
3662  case 2:
3663  FAIL_IF(strcmp(n->name, "2") != 0);
3664  FAIL_IF(strcmp(n->val, "::1") != 0);
3665  break;
3666  default:
3667  FAIL;
3668  }
3669  i++;
3670  }
3671 
3672  outputs = SCConfGetNode("libhtp.server-config");
3673  FAIL_IF_NULL(outputs);
3674  node = TAILQ_FIRST(&outputs->head);
3675  node = TAILQ_NEXT(node, next);
3676  FAIL_IF_NULL(node);
3677  FAIL_IF(strcmp(node->name, "1") != 0);
3678  node = TAILQ_FIRST(&node->head);
3679  FAIL_IF_NULL(node);
3680  FAIL_IF(strcmp(node->name, "iis7") != 0);
3681 
3682  node2 = SCConfNodeLookupChild(node, "personality");
3683  FAIL_IF_NULL(node2);
3684  FAIL_IF(strcmp(node2->val, "IIS_7_0") != 0);
3685 
3686  node = SCConfNodeLookupChild(node, "address");
3687  FAIL_IF_NULL(node);
3688 
3689  i = 0;
3690  TAILQ_FOREACH(n, &node->head, next) {
3691  FAIL_IF_NULL(n);
3692 
3693  switch(i) {
3694  case 0:
3695  FAIL_IF(strcmp(n->name, "0") != 0);
3696  FAIL_IF(strcmp(n->val, "192.168.0.0/24") != 0);
3697  break;
3698  case 1:
3699  FAIL_IF(strcmp(n->name, "1") != 0);
3700  FAIL_IF(strcmp(n->val, "192.168.10.0/24") != 0);
3701  break;
3702  default:
3703  FAIL;
3704  }
3705  i++;
3706  }
3707 
3708  SCConfDeInit();
3710 
3711  PASS;
3712 }
3713 
3714 /** \test Test config builds radix correctly */
3715 static int HTPParserConfigTest02(void)
3716 {
3717  char input[] = "\
3718 %YAML 1.1\n\
3719 ---\n\
3720 libhtp:\n\
3721 \n\
3722  default-config:\n\
3723  personality: IDS\n\
3724 \n\
3725  server-config:\n\
3726 \n\
3727  - apache-tomcat:\n\
3728  address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
3729  personality: Tomcat_6_0\n\
3730 \n\
3731  - iis7:\n\
3732  address: \n\
3733  - 192.168.0.0/24\n\
3734  - 192.168.10.0/24\n\
3735  personality: IIS_7_0\n\
3736 ";
3737 
3739  SCConfInit();
3741  SCConfYamlLoadString(input, strlen(input));
3742  HTPConfigure();
3743  FAIL_IF_NULL(cfglist.cfg);
3744  FAIL_IF_NULL(cfgtree.ipv4.head);
3745  FAIL_IF_NULL(cfgtree.ipv6.head);
3746 
3747  htp_cfg_t *htp = cfglist.cfg;
3748  uint8_t buf[128];
3749  const char *addr;
3750  void *user_data = NULL;
3751 
3752  addr = "192.168.10.42";
3753  FAIL_IF(inet_pton(AF_INET, addr, buf) != 1);
3754  (void)SCRadix4TreeFindBestMatch(&cfgtree.ipv4, buf, &user_data);
3755  FAIL_IF_NULL(user_data);
3756  HTPCfgRec *htp_cfg_rec = user_data;
3757  htp = htp_cfg_rec->cfg;
3758  FAIL_IF_NULL(htp);
3759  SCLogDebug("LIBHTP using config: %p", htp);
3760 
3761  user_data = NULL;
3762  addr = "::1";
3763  FAIL_IF(inet_pton(AF_INET6, addr, buf) != 1);
3764  (void)SCRadix6TreeFindBestMatch(&cfgtree.ipv6, buf, &user_data);
3765  FAIL_IF_NULL(user_data);
3766  htp_cfg_rec = user_data;
3767  htp = htp_cfg_rec->cfg;
3768  FAIL_IF_NULL(htp);
3769  SCLogDebug("LIBHTP using config: %p", htp);
3770 
3771  HTPFreeConfig();
3772  SCConfDeInit();
3775 
3776  PASS;
3777 }
3778 
3779 /** \test Test traffic is handled by the correct htp config */
3780 static int HTPParserConfigTest03(void)
3781 {
3782  Flow *f = NULL;
3783  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
3784  " Data is c0oL!";
3785  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3786  TcpSession ssn;
3788 
3789  HtpState *htp_state = NULL;
3790  char input[] = "\
3791 %YAML 1.1\n\
3792 ---\n\
3793 libhtp:\n\
3794 \n\
3795  default-config:\n\
3796  personality: IDS\n\
3797 \n\
3798  server-config:\n\
3799 \n\
3800  - apache-tomcat:\n\
3801  address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
3802  personality: Tomcat_6_0\n\
3803 \n\
3804  - iis7:\n\
3805  address: \n\
3806  - 192.168.0.0/24\n\
3807  - 192.168.10.0/24\n\
3808  personality: IIS_7_0\n\
3809 ";
3810 
3812  SCConfInit();
3814 
3815  SCConfYamlLoadString(input, strlen(input));
3816 
3817  HTPConfigure();
3818 
3819  const char *addr = "192.168.10.42";
3820 
3821  memset(&ssn, 0, sizeof(ssn));
3822 
3823  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
3824  FAIL_IF_NULL(f);
3825  f->protoctx = &ssn;
3826  f->proto = IPPROTO_TCP;
3827  f->alproto = ALPROTO_HTTP1;
3828 
3829  htp_cfg_t *htp = cfglist.cfg;
3830  FAIL_IF_NULL(htp);
3831 
3832  void *user_data = NULL;
3833  (void)SCRadix4TreeFindBestMatch(&cfgtree.ipv4, (uint8_t *)f->dst.addr_data32, &user_data);
3834  FAIL_IF_NULL(user_data);
3835 
3836  HTPCfgRec *htp_cfg_rec = user_data;
3837  htp = htp_cfg_rec->cfg;
3838  FAIL_IF_NULL(user_data);
3839  SCLogDebug("LIBHTP using config: %p", htp);
3840 
3841  StreamTcpInitConfig(true);
3842 
3843  uint32_t u;
3844  for (u = 0; u < httplen1; u++) {
3845  uint8_t flags = 0;
3846 
3847  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
3848  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
3849  else flags = STREAM_TOSERVER;
3850 
3851  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3852  FAIL_IF(r != 0);
3853  }
3854 
3855  htp_state = f->alstate;
3856  FAIL_IF_NULL(htp_state);
3857 
3858  FAIL_IF(HTPStateGetTxCnt(htp_state) != 2);
3859 
3860  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3861  FAIL_IF_NULL(tx);
3862  tx = HTPStateGetTx(htp_state, 1);
3863  FAIL_IF_NULL(tx);
3864 
3866  HTPFreeConfig();
3867  SCConfDeInit();
3870 
3871  StreamTcpFreeConfig(true);
3872  UTHFreeFlow(f);
3873  PASS;
3874 }
3875 
3876 /** \test Test %2f decoding in profile Apache_2_2
3877  *
3878  * %2f in path is left untouched
3879  * %2f in query string is normalized to %2F
3880  * %252f in query string is decoded/normalized to %2F
3881  */
3882 static int HTPParserDecodingTest01(void)
3883 {
3884  uint8_t httpbuf1[] =
3885  "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
3886  "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
3887  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
3888  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3889  TcpSession ssn;
3892 
3893  char input[] = "\
3894 %YAML 1.1\n\
3895 ---\n\
3896 libhtp:\n\
3897 \n\
3898  default-config:\n\
3899  personality: Apache_2\n\
3900 ";
3901 
3903  SCConfInit();
3905  SCConfYamlLoadString(input, strlen(input));
3906  HTPConfigure();
3907  const char *addr = "4.3.2.1";
3908  memset(&ssn, 0, sizeof(ssn));
3909 
3910  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
3911  FAIL_IF_NULL(f);
3912  f->protoctx = &ssn;
3913  f->proto = IPPROTO_TCP;
3914  f->alproto = ALPROTO_HTTP1;
3915 
3916  StreamTcpInitConfig(true);
3917 
3918  for (uint32_t u = 0; u < httplen1; u++) {
3919  uint8_t flags = 0;
3920  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
3921  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
3922  else flags = STREAM_TOSERVER;
3923 
3924  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3925  FAIL_IF(r != 0);
3926  }
3927 
3928  HtpState *htp_state = f->alstate;
3929  FAIL_IF_NULL(htp_state);
3930 
3931  uint8_t ref1[] = "/abc%2fdef";
3932  size_t reflen = sizeof(ref1) - 1;
3933 
3934  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3935  FAIL_IF_NULL(tx);
3936 
3937  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
3938  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3939  FAIL_IF_NULL(tx_ud);
3940  FAIL_IF_NULL(request_uri_normalized);
3941  FAIL_IF(reflen != bstr_len(request_uri_normalized));
3942  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
3943 
3944  uint8_t ref2[] = "/abc/def?ghi/jkl";
3945  reflen = sizeof(ref2) - 1;
3946 
3947  tx = HTPStateGetTx(htp_state, 1);
3948  FAIL_IF_NULL(tx);
3949 
3950  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
3951  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3952  FAIL_IF_NULL(tx_ud);
3953  FAIL_IF_NULL(request_uri_normalized);
3954  FAIL_IF(reflen != bstr_len(request_uri_normalized));
3955  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref2, bstr_len(request_uri_normalized)) != 0);
3956 
3957  uint8_t ref3[] = "/abc/def?ghi%2fjkl";
3958  reflen = sizeof(ref3) - 1;
3959  tx = HTPStateGetTx(htp_state, 2);
3960  FAIL_IF_NULL(tx);
3961 
3962  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
3963  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3964  FAIL_IF_NULL(tx_ud);
3965  FAIL_IF_NULL(request_uri_normalized);
3966  FAIL_IF(reflen != bstr_len(request_uri_normalized));
3967  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref3, bstr_len(request_uri_normalized)) != 0);
3968 
3970  HTPFreeConfig();
3971  SCConfDeInit();
3974 
3975  StreamTcpFreeConfig(true);
3976  UTHFreeFlow(f);
3977  PASS;
3978 }
3979 
3980 static int HTPParserDecodingTest01a(void)
3981 {
3982  uint8_t httpbuf1[] = "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
3983  "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
3984  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
3985  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3986  TcpSession ssn;
3989 
3990  char input[] = "\
3991 %YAML 1.1\n\
3992 ---\n\
3993 libhtp:\n\
3994 \n\
3995  default-config:\n\
3996  personality: Apache_2\n\
3997 ";
3998 
4000  SCConfInit();
4002  SCConfYamlLoadString(input, strlen(input));
4003  HTPConfigure();
4004  const char *addr = "4.3.2.1";
4005  memset(&ssn, 0, sizeof(ssn));
4006 
4007  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4008  FAIL_IF_NULL(f);
4009  f->protoctx = &ssn;
4010  f->proto = IPPROTO_TCP;
4011  f->alproto = ALPROTO_HTTP1;
4012 
4013  StreamTcpInitConfig(true);
4014 
4015  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
4016  (STREAM_TOSERVER | STREAM_START | STREAM_EOF), httpbuf1, httplen1);
4017  FAIL_IF(r != 0);
4018 
4019  HtpState *htp_state = f->alstate;
4020  FAIL_IF_NULL(htp_state);
4021 
4022  uint8_t ref1[] = "/abc%2fdef";
4023  size_t reflen = sizeof(ref1) - 1;
4024 
4025  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4026  FAIL_IF_NULL(tx);
4027 
4028  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4029  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4030  FAIL_IF_NULL(tx_ud);
4031  FAIL_IF_NULL(request_uri_normalized);
4032  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4033  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4034 
4035  uint8_t ref2[] = "/abc/def?ghi/jkl";
4036  reflen = sizeof(ref2) - 1;
4037 
4038  tx = HTPStateGetTx(htp_state, 1);
4039  FAIL_IF_NULL(tx);
4040  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4041  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4042  FAIL_IF_NULL(tx_ud);
4043  FAIL_IF_NULL(request_uri_normalized);
4044  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4045 
4046  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref2, bstr_len(request_uri_normalized)) != 0);
4047 
4048  uint8_t ref3[] = "/abc/def?ghi%2fjkl";
4049  reflen = sizeof(ref3) - 1;
4050  tx = HTPStateGetTx(htp_state, 2);
4051  FAIL_IF_NULL(tx);
4052  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4053  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4054  FAIL_IF_NULL(tx_ud);
4055  FAIL_IF_NULL(request_uri_normalized);
4056  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4057 
4058  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref3, bstr_len(request_uri_normalized)) != 0);
4059 
4061  HTPFreeConfig();
4062  SCConfDeInit();
4065 
4066  StreamTcpFreeConfig(true);
4067  UTHFreeFlow(f);
4068  PASS;
4069 }
4070 
4071 /** \test Test %2f decoding in profile IDS
4072  *
4073  * %2f in path decoded to /
4074  * %2f in query string is decoded to /
4075  * %252f in query string is decoded to %2F
4076  */
4077 static int HTPParserDecodingTest02(void)
4078 {
4079  Flow *f = NULL;
4080  uint8_t httpbuf1[] =
4081  "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4082  "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4083  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4084  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4085  TcpSession ssn;
4087 
4088  HtpState *htp_state = NULL;
4089  char input[] = "\
4090 %YAML 1.1\n\
4091 ---\n\
4092 libhtp:\n\
4093 \n\
4094  default-config:\n\
4095  personality: IDS\n\
4096  double-decode-path: no\n\
4097  double-decode-query: no\n\
4098 ";
4099 
4101  SCConfInit();
4103  SCConfYamlLoadString(input, strlen(input));
4104  HTPConfigure();
4105  const char *addr = "4.3.2.1";
4106  memset(&ssn, 0, sizeof(ssn));
4107 
4108  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4109  FAIL_IF_NULL(f);
4110  f->protoctx = &ssn;
4111  f->proto = IPPROTO_TCP;
4112  f->alproto = ALPROTO_HTTP1;
4113 
4114  StreamTcpInitConfig(true);
4115 
4116  uint32_t u;
4117  for (u = 0; u < httplen1; u++) {
4118  uint8_t flags = 0;
4119 
4120  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4121  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4122  else flags = STREAM_TOSERVER;
4123 
4124  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4125  FAIL_IF(r != 0);
4126  }
4127 
4128  htp_state = f->alstate;
4129  FAIL_IF_NULL(htp_state);
4130 
4131  uint8_t ref1[] = "/abc/def";
4132  size_t reflen = sizeof(ref1) - 1;
4133 
4134  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4135  FAIL_IF_NULL(tx);
4136  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4137  FAIL_IF_NULL(request_uri_normalized);
4138  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4139  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4140 
4141  uint8_t ref2[] = "/abc/def?ghi/jkl";
4142  reflen = sizeof(ref2) - 1;
4143 
4144  tx = HTPStateGetTx(htp_state, 1);
4145  FAIL_IF_NULL(tx);
4146  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4147  FAIL_IF_NULL(request_uri_normalized);
4148  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4149 
4150  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref2, bstr_len(request_uri_normalized)) != 0);
4151 
4152  uint8_t ref3[] = "/abc/def?ghi%2fjkl";
4153  reflen = sizeof(ref3) - 1;
4154  tx = HTPStateGetTx(htp_state, 2);
4155  FAIL_IF_NULL(tx);
4156  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4157  FAIL_IF_NULL(request_uri_normalized);
4158  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4159 
4160  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref3, bstr_len(request_uri_normalized)) != 0);
4161 
4163  HTPFreeConfig();
4164  SCConfDeInit();
4167 
4168  StreamTcpFreeConfig(true);
4169  UTHFreeFlow(f);
4170  PASS;
4171 }
4172 
4173 /** \test Test %2f decoding in profile IDS with double-decode-* options
4174  *
4175  * %252f in path decoded to /
4176  * %252f in query string is decoded to /
4177  */
4178 static int HTPParserDecodingTest03(void)
4179 {
4180  Flow *f = NULL;
4181  uint8_t httpbuf1[] =
4182  "GET /abc%252fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4183  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4184  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4185  TcpSession ssn;
4187 
4188  HtpState *htp_state = NULL;
4189  char input[] = "\
4190 %YAML 1.1\n\
4191 ---\n\
4192 libhtp:\n\
4193 \n\
4194  default-config:\n\
4195  personality: IDS\n\
4196  double-decode-path: yes\n\
4197  double-decode-query: yes\n\
4198 ";
4199 
4201  SCConfInit();
4203  SCConfYamlLoadString(input, strlen(input));
4204  HTPConfigure();
4205  const char *addr = "4.3.2.1";
4206  memset(&ssn, 0, sizeof(ssn));
4207 
4208  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4209  FAIL_IF_NULL(f);
4210  f->protoctx = &ssn;
4211  f->proto = IPPROTO_TCP;
4212  f->alproto = ALPROTO_HTTP1;
4213 
4214  StreamTcpInitConfig(true);
4215 
4216  uint32_t u;
4217  for (u = 0; u < httplen1; u++) {
4218  uint8_t flags = 0;
4219 
4220  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4221  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4222  else flags = STREAM_TOSERVER;
4223 
4224  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4225  FAIL_IF(r != 0);
4226  }
4227 
4228  htp_state = f->alstate;
4229  FAIL_IF_NULL(htp_state);
4230 
4231  uint8_t ref1[] = "/abc/def";
4232  size_t reflen = sizeof(ref1) - 1;
4233 
4234  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4235  FAIL_IF_NULL(tx);
4236  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4237  FAIL_IF_NULL(request_uri_normalized);
4238  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4239 
4240  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4241 
4242  uint8_t ref2[] = "/abc/def?ghi/jkl";
4243  reflen = sizeof(ref2) - 1;
4244 
4245  tx = HTPStateGetTx(htp_state, 1);
4246  FAIL_IF_NULL(tx);
4247  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4248  FAIL_IF_NULL(request_uri_normalized);
4249  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4250 
4251  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref2, bstr_len(request_uri_normalized)) != 0);
4252 
4254  HTPFreeConfig();
4255  SCConfDeInit();
4258 
4259  StreamTcpFreeConfig(true);
4260  UTHFreeFlow(f);
4261  PASS;
4262 }
4263 
4264 /** \test Test http:// in query profile IDS
4265  */
4266 static int HTPParserDecodingTest04(void)
4267 {
4268  Flow *f = NULL;
4269  uint8_t httpbuf1[] =
4270  "GET /abc/def?a=http://www.abc.com/ HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4271  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4272  TcpSession ssn;
4274 
4275  HtpState *htp_state = NULL;
4276  char input[] = "\
4277 %YAML 1.1\n\
4278 ---\n\
4279 libhtp:\n\
4280 \n\
4281  default-config:\n\
4282  personality: IDS\n\
4283  double-decode-path: yes\n\
4284  double-decode-query: yes\n\
4285 ";
4286 
4288  SCConfInit();
4290  SCConfYamlLoadString(input, strlen(input));
4291  HTPConfigure();
4292  const char *addr = "4.3.2.1";
4293  memset(&ssn, 0, sizeof(ssn));
4294 
4295  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4296  FAIL_IF_NULL(f);
4297  f->protoctx = &ssn;
4298  f->proto = IPPROTO_TCP;
4299  f->alproto = ALPROTO_HTTP1;
4300 
4301  StreamTcpInitConfig(true);
4302 
4303  uint32_t u;
4304  for (u = 0; u < httplen1; u++) {
4305  uint8_t flags = 0;
4306 
4307  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4308  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4309  else flags = STREAM_TOSERVER;
4310 
4311  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4312  FAIL_IF(r != 0);
4313  }
4314 
4315  htp_state = f->alstate;
4316  FAIL_IF_NULL(htp_state);
4317 
4318  uint8_t ref1[] = "/abc/def?a=http://www.abc.com/";
4319  size_t reflen = sizeof(ref1) - 1;
4320 
4321  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4322  FAIL_IF_NULL(tx);
4323  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4324  FAIL_IF_NULL(request_uri_normalized);
4325  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4326 
4327  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4328 
4330  HTPFreeConfig();
4331  SCConfDeInit();
4334 
4335  StreamTcpFreeConfig(true);
4336  UTHFreeFlow(f);
4337  PASS;
4338 }
4339 
4340 /** \test Test \ char in query profile IDS. Bug 739
4341  */
4342 static int HTPParserDecodingTest05(void)
4343 {
4344  Flow *f = NULL;
4345  uint8_t httpbuf1[] =
4346  "GET /index?id=\\\"<script>alert(document.cookie)</script> HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4347  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4348  TcpSession ssn;
4350 
4351  HtpState *htp_state = NULL;
4352  char input[] = "\
4353 %YAML 1.1\n\
4354 ---\n\
4355 libhtp:\n\
4356 \n\
4357  default-config:\n\
4358  personality: IDS\n\
4359  double-decode-path: yes\n\
4360  double-decode-query: yes\n\
4361 ";
4362 
4364  SCConfInit();
4366  SCConfYamlLoadString(input, strlen(input));
4367  HTPConfigure();
4368  const char *addr = "4.3.2.1";
4369  memset(&ssn, 0, sizeof(ssn));
4370 
4371  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4372  FAIL_IF_NULL(f);
4373  f->protoctx = &ssn;
4374  f->proto = IPPROTO_TCP;
4375  f->alproto = ALPROTO_HTTP1;
4376 
4377  StreamTcpInitConfig(true);
4378 
4379  uint32_t u;
4380  for (u = 0; u < httplen1; u++) {
4381  uint8_t flags = 0;
4382 
4383  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4384  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4385  else flags = STREAM_TOSERVER;
4386 
4387  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4388  FAIL_IF(r != 0);
4389  }
4390 
4391  htp_state = f->alstate;
4392  FAIL_IF_NULL(htp_state);
4393 
4394  uint8_t ref1[] = "/index?id=\\\"<script>alert(document.cookie)</script>";
4395  size_t reflen = sizeof(ref1) - 1;
4396 
4397  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4398  FAIL_IF_NULL(tx);
4399  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4400  FAIL_IF_NULL(request_uri_normalized);
4401  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4402 
4403  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4404 
4406  HTPFreeConfig();
4407  SCConfDeInit();
4410 
4411  StreamTcpFreeConfig(true);
4412  UTHFreeFlow(f);
4413  PASS;
4414 }
4415 
4416 /** \test Test + char in query. Bug 1035
4417  */
4418 static int HTPParserDecodingTest06(void)
4419 {
4420  Flow *f = NULL;
4421  uint8_t httpbuf1[] =
4422  "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4423  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4424  TcpSession ssn;
4426 
4427  HtpState *htp_state = NULL;
4428  char input[] = "\
4429 %YAML 1.1\n\
4430 ---\n\
4431 libhtp:\n\
4432 \n\
4433  default-config:\n\
4434  personality: IDS\n\
4435  double-decode-path: yes\n\
4436  double-decode-query: yes\n\
4437 ";
4438 
4440  SCConfInit();
4442  SCConfYamlLoadString(input, strlen(input));
4443  HTPConfigure();
4444  const char *addr = "4.3.2.1";
4445  memset(&ssn, 0, sizeof(ssn));
4446 
4447  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4448  FAIL_IF_NULL(f);
4449  f->protoctx = &ssn;
4450  f->proto = IPPROTO_TCP;
4451  f->alproto = ALPROTO_HTTP1;
4452 
4453  StreamTcpInitConfig(true);
4454 
4455  uint32_t u;
4456  for (u = 0; u < httplen1; u++) {
4457  uint8_t flags = 0;
4458 
4459  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4460  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4461  else flags = STREAM_TOSERVER;
4462 
4463  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4464  FAIL_IF(r != 0);
4465  }
4466 
4467  htp_state = f->alstate;
4468  FAIL_IF_NULL(htp_state);
4469 
4470  uint8_t ref1[] = "/put.php?ip=1.2.3.4&port=+6000";
4471  size_t reflen = sizeof(ref1) - 1;
4472 
4473  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4474  FAIL_IF_NULL(tx);
4475  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4476  FAIL_IF_NULL(request_uri_normalized);
4477  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4478 
4479  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4480 
4482  HTPFreeConfig();
4483  SCConfDeInit();
4486 
4487  StreamTcpFreeConfig(true);
4488  UTHFreeFlow(f);
4489  PASS;
4490 }
4491 
4492 /** \test Test + char in query. Bug 1035
4493  */
4494 static int HTPParserDecodingTest07(void)
4495 {
4496  Flow *f = NULL;
4497  uint8_t httpbuf1[] =
4498  "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4499  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4500  TcpSession ssn;
4502 
4503  HtpState *htp_state = NULL;
4504  char input[] = "\
4505 %YAML 1.1\n\
4506 ---\n\
4507 libhtp:\n\
4508 \n\
4509  default-config:\n\
4510  personality: IDS\n\
4511  double-decode-path: yes\n\
4512  double-decode-query: yes\n\
4513  query-plusspace-decode: yes\n\
4514 ";
4515 
4517  SCConfInit();
4519  SCConfYamlLoadString(input, strlen(input));
4520  HTPConfigure();
4521  const char *addr = "4.3.2.1";
4522  memset(&ssn, 0, sizeof(ssn));
4523 
4524  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4525  FAIL_IF_NULL(f);
4526  f->protoctx = &ssn;
4527  f->proto = IPPROTO_TCP;
4528  f->alproto = ALPROTO_HTTP1;
4529 
4530  StreamTcpInitConfig(true);
4531 
4532  uint32_t u;
4533  for (u = 0; u < httplen1; u++) {
4534  uint8_t flags = 0;
4535 
4536  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4537  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4538  else flags = STREAM_TOSERVER;
4539 
4540  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4541  FAIL_IF(r != 0);
4542  }
4543 
4544  htp_state = f->alstate;
4545  FAIL_IF_NULL(htp_state);
4546 
4547  uint8_t ref1[] = "/put.php?ip=1.2.3.4&port= 6000";
4548  size_t reflen = sizeof(ref1) - 1;
4549 
4550  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4551  FAIL_IF_NULL(tx);
4552  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4553  FAIL_IF_NULL(request_uri_normalized);
4554  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4555 
4556  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4557 
4559  HTPFreeConfig();
4560  SCConfDeInit();
4563 
4564  StreamTcpFreeConfig(true);
4565  UTHFreeFlow(f);
4566  PASS;
4567 }
4568 
4569 /** \test Test 'proxy' URI normalization. Ticket 1008
4570  */
4571 static int HTPParserDecodingTest08(void)
4572 {
4573  Flow *f = NULL;
4574  uint8_t httpbuf1[] =
4575  "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n";
4576  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4577  TcpSession ssn;
4579 
4580  HtpState *htp_state = NULL;
4581  char input[] = "\
4582 %YAML 1.1\n\
4583 ---\n\
4584 libhtp:\n\
4585 \n\
4586  default-config:\n\
4587  personality: IDS\n\
4588 ";
4589 
4591  SCConfInit();
4593  SCConfYamlLoadString(input, strlen(input));
4594  HTPConfigure();
4595  const char *addr = "4.3.2.1";
4596  memset(&ssn, 0, sizeof(ssn));
4597 
4598  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4599  FAIL_IF_NULL(f);
4600  f->protoctx = &ssn;
4601  f->proto = IPPROTO_TCP;
4602  f->alproto = ALPROTO_HTTP1;
4603 
4604  StreamTcpInitConfig(true);
4605 
4606  uint32_t u;
4607  for (u = 0; u < httplen1; u++) {
4608  uint8_t flags = 0;
4609 
4610  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4611  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4612  else flags = STREAM_TOSERVER;
4613 
4614  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4615  FAIL_IF(r != 0);
4616  }
4617 
4618  htp_state = f->alstate;
4619  FAIL_IF_NULL(htp_state);
4620 
4621  uint8_t ref1[] = "/blah/";
4622  size_t reflen = sizeof(ref1) - 1;
4623 
4624  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4625  FAIL_IF_NULL(tx);
4626  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4627  FAIL_IF_NULL(request_uri_normalized);
4628  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4629 
4630  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4631 
4633  HTPFreeConfig();
4634  SCConfDeInit();
4637 
4638  StreamTcpFreeConfig(true);
4639  UTHFreeFlow(f);
4640  PASS;
4641 }
4642 
4643 /** \test Test 'proxy' URI normalization. Ticket 1008
4644  */
4645 static int HTPParserDecodingTest09(void)
4646 {
4647  Flow *f = NULL;
4648  uint8_t httpbuf1[] =
4649  "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n";
4650  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4651  TcpSession ssn;
4653 
4654  HtpState *htp_state = NULL;
4655  char input[] = "\
4656 %YAML 1.1\n\
4657 ---\n\
4658 libhtp:\n\
4659 \n\
4660  default-config:\n\
4661  personality: IDS\n\
4662  uri-include-all: true\n\
4663 ";
4664 
4666  SCConfInit();
4668  SCConfYamlLoadString(input, strlen(input));
4669  HTPConfigure();
4670  const char *addr = "4.3.2.1";
4671  memset(&ssn, 0, sizeof(ssn));
4672 
4673  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4674  FAIL_IF_NULL(f);
4675  f->protoctx = &ssn;
4676  f->proto = IPPROTO_TCP;
4677  f->alproto = ALPROTO_HTTP1;
4678 
4679  StreamTcpInitConfig(true);
4680 
4681  uint32_t u;
4682  for (u = 0; u < httplen1; u++) {
4683  uint8_t flags = 0;
4684 
4685  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4686  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4687  else flags = STREAM_TOSERVER;
4688 
4689  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4690  FAIL_IF(r != 0);
4691  }
4692 
4693  htp_state = f->alstate;
4694  FAIL_IF_NULL(htp_state);
4695 
4696  uint8_t ref1[] = "http://suricata-ids.org/blah/";
4697  size_t reflen = sizeof(ref1) - 1;
4698 
4699  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4700  FAIL_IF_NULL(tx);
4701  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4702  FAIL_IF_NULL(request_uri_normalized);
4703  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4704 
4705  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4706 
4708  HTPFreeConfig();
4709  SCConfDeInit();
4712 
4713  StreamTcpFreeConfig(true);
4714  UTHFreeFlow(f);
4715  PASS;
4716 }
4717 
4718 /** \test BG box crash -- chunks are messed up. Observed for real. */
4719 static int HTPBodyReassemblyTest01(void)
4720 {
4721  HtpTxUserData htud;
4722  memset(&htud, 0x00, sizeof(htud));
4723  HtpState hstate;
4724  memset(&hstate, 0x00, sizeof(hstate));
4725  Flow flow;
4726  memset(&flow, 0x00, sizeof(flow));
4728  htp_cfg_t *cfg = htp_config_create();
4729  BUG_ON(cfg == NULL);
4730  htp_connp_t *connp = htp_connp_create(cfg);
4731  BUG_ON(connp == NULL);
4732  const htp_tx_t *tx = htp_connp_get_request_tx(connp);
4733  BUG_ON(tx == NULL);
4734 
4735  hstate.f = &flow;
4736  flow.alparser = parser;
4737 
4738  uint8_t chunk1[] = "--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r";
4739  uint8_t chunk2[] = "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: keep-alive\r\nContent-length: 68102\r\nReferer: http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r";
4740 
4741  int r = HtpBodyAppendChunk(&htud.request_body, chunk1, sizeof(chunk1) - 1);
4742  BUG_ON(r != 0);
4743  r = HtpBodyAppendChunk(&htud.request_body, chunk2, sizeof(chunk2) - 1);
4744  BUG_ON(r != 0);
4745 
4746  const uint8_t *chunks_buffer = NULL;
4747  uint32_t chunks_buffer_len = 0;
4748 
4749  HtpRequestBodyReassemble(&htud, &chunks_buffer, &chunks_buffer_len);
4750  FAIL_IF_NULL(chunks_buffer);
4751 #ifdef PRINT
4752  printf("REASSCHUNK START: \n");
4753  PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
4754  printf("REASSCHUNK END: \n");
4755 #endif
4756 
4757  htud.mime_state = SCMimeStateInit((const uint8_t *)"multipart/form-data; boundary=toto",
4758  strlen("multipart/form-data; boundary=toto"));
4759  FAIL_IF_NULL(htud.mime_state);
4760  htud.tsflags |= HTP_BOUNDARY_SET;
4761  HtpRequestBodyHandleMultipart(&hstate, &htud, &tx, chunks_buffer, chunks_buffer_len, false);
4762 
4764 
4766 
4767  PASS;
4768 }
4769 
4770 /** \test BG crash */
4771 static int HTPSegvTest01(void)
4772 {
4773  Flow *f = NULL;
4774  uint8_t httpbuf1[] = "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: keep-alive\r\nContent-length: 68102\r\nReferer: http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r";
4775  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4776  char input[] = "\
4777 %YAML 1.1\n\
4778 ---\n\
4779 libhtp:\n\
4780 \n\
4781  default-config:\n\
4782  personality: IDS\n\
4783  double-decode-path: no\n\
4784  double-decode-query: no\n\
4785  request-body-limit: 0\n\
4786  response-body-limit: 0\n\
4787 ";
4788 
4790  SCConfInit();
4792  SCConfYamlLoadString(input, strlen(input));
4793  HTPConfigure();
4794 
4795  TcpSession ssn;
4796  HtpState *http_state = NULL;
4798 
4799  memset(&ssn, 0, sizeof(ssn));
4800 
4801  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4802  FAIL_IF_NULL(f);
4803  f->protoctx = &ssn;
4804  f->proto = IPPROTO_TCP;
4805  f->alproto = ALPROTO_HTTP1;
4806 
4807  StreamTcpInitConfig(true);
4808 
4809  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
4810  int r = AppLayerParserParse(
4811  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
4812  FAIL_IF(r != 0);
4813  SCLogDebug("\n>>>> processing chunk 1 again <<<<\n");
4814  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
4815  FAIL_IF(r != 0);
4816 
4817  http_state = f->alstate;
4818  FAIL_IF_NULL(http_state);
4819 
4821  FAIL_IF_NOT_NULL(decoder_events);
4822 
4824  HTPFreeConfig();
4825  SCConfDeInit();
4828  StreamTcpFreeConfig(true);
4829  UTHFreeFlow(f);
4830  PASS;
4831 }
4832 
4833 /** \test Test really long request, this should result in HTP_LOG_CODE_REQUEST_FIELD_TOO_LONG */
4834 static int HTPParserTest14(void)
4835 {
4836  size_t len = 18887;
4837  TcpSession ssn;
4838  char input[] = "\
4839 %YAML 1.1\n\
4840 ---\n\
4841 libhtp:\n\
4842 \n\
4843  default-config:\n\
4844  personality: IDS\n\
4845  double-decode-path: no\n\
4846  double-decode-query: no\n\
4847  request-body-limit: 0\n\
4848  response-body-limit: 0\n\
4849 ";
4852 
4853  memset(&ssn, 0, sizeof(ssn));
4854 
4856  SCConfInit();
4858  SCConfYamlLoadString(input, strlen(input));
4859  HTPConfigure();
4860 
4861  char *httpbuf = SCMalloc(len);
4862  FAIL_IF_NULL(httpbuf);
4863  memset(httpbuf, 0x00, len);
4864 
4865  /* create the request with a longer than 18k cookie */
4866  strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n"
4867  "Host: myhost.lan\r\n"
4868  "Connection: keep-alive\r\n"
4869  "Accept: */*\r\n"
4870  "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n"
4871  "Referer: http://blah.lan/\r\n"
4872  "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
4873  "Cookie: ", len);
4874  size_t o = strlen(httpbuf);
4875  for ( ; o < len - 4; o++) {
4876  httpbuf[o] = 'A';
4877  }
4878  httpbuf[len - 4] = '\r';
4879  httpbuf[len - 3] = '\n';
4880  httpbuf[len - 2] = '\r';
4881  httpbuf[len - 1] = '\n';
4882 
4883  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4884  FAIL_IF_NULL(f);
4885  f->protoctx = &ssn;
4886  f->alproto = ALPROTO_HTTP1;
4887  f->proto = IPPROTO_TCP;
4888 
4889  StreamTcpInitConfig(true);
4890 
4891  uint32_t u;
4892  for (u = 0; u < len; u++) {
4893  uint8_t flags = 0;
4894 
4895  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4896  else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4897  else flags = STREAM_TOSERVER;
4898 
4899  (void)AppLayerParserParse(
4900  NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)&httpbuf[u], 1);
4901  }
4902  HtpState *htp_state = f->alstate;
4903  FAIL_IF_NULL(htp_state);
4904 
4905  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4906  FAIL_IF_NULL(tx);
4907  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
4908  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
4909 
4910  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
4911  AppLayerDecoderEvents *decoder_events =
4912  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
4913  FAIL_IF_NULL(decoder_events);
4914 
4915  FAIL_IF(decoder_events->events[0] != HTP_LOG_CODE_REQUEST_FIELD_TOO_LONG);
4916 
4918  StreamTcpFreeConfig(true);
4919  UTHFreeFlow(f);
4920  SCFree(httpbuf);
4921  HTPFreeConfig();
4922  SCConfDeInit();
4925  PASS;
4926 }
4927 
4928 /** \test Test really long request (same as HTPParserTest14), now with config
4929  * update to allow it */
4930 static int HTPParserTest15(void)
4931 {
4932  Flow *f = NULL;
4933  char *httpbuf = NULL;
4934  size_t len = 18887;
4935  TcpSession ssn;
4936  HtpState *htp_state = NULL;
4937  char input[] = "\
4938 %YAML 1.1\n\
4939 ---\n\
4940 libhtp:\n\
4941 \n\
4942  default-config:\n\
4943  personality: IDS\n\
4944  double-decode-path: no\n\
4945  double-decode-query: no\n\
4946  request-body-limit: 0\n\
4947  response-body-limit: 0\n\
4948  meta-field-limit: 20000\n\
4949 ";
4951 
4952  memset(&ssn, 0, sizeof(ssn));
4953 
4955  SCConfInit();
4957  SCConfYamlLoadString(input, strlen(input));
4958  HTPConfigure();
4959 
4960  httpbuf = SCMalloc(len);
4961  FAIL_IF_NULL(httpbuf);
4962 
4963  memset(httpbuf, 0x00, len);
4964 
4965  /* create the request with a longer than 18k cookie */
4966  strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n"
4967  "Host: myhost.lan\r\n"
4968  "Connection: keep-alive\r\n"
4969  "Accept: */*\r\n"
4970  "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n"
4971  "Referer: http://blah.lan/\r\n"
4972  "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
4973  "Cookie: ", len);
4974  size_t o = strlen(httpbuf);
4975  for ( ; o < len - 4; o++) {
4976  httpbuf[o] = 'A';
4977  }
4978  httpbuf[len - 4] = '\r';
4979  httpbuf[len - 3] = '\n';
4980  httpbuf[len - 2] = '\r';
4981  httpbuf[len - 1] = '\n';
4982 
4983  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4984  FAIL_IF_NULL(f);
4985  f->protoctx = &ssn;
4986  f->proto = IPPROTO_TCP;
4987  f->alproto = ALPROTO_HTTP1;
4988 
4989  StreamTcpInitConfig(true);
4990 
4991  uint32_t u;
4992  for (u = 0; u < len; u++) {
4993  uint8_t flags = 0;
4994 
4995  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4996  else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4997  else flags = STREAM_TOSERVER;
4998 
4999  int r = AppLayerParserParse(
5000  NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)&httpbuf[u], 1);
5001  FAIL_IF(r != 0);
5002  }
5003  htp_state = f->alstate;
5004  FAIL_IF_NULL(htp_state);
5005 
5006  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5007  FAIL_IF_NULL(tx);
5008  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5009  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5010 
5011  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
5012  AppLayerDecoderEvents *decoder_events =
5013  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
5014  FAIL_IF_NOT_NULL(decoder_events);
5015 
5017  StreamTcpFreeConfig(true);
5018  UTHFreeFlow(f);
5019  SCFree(httpbuf);
5020  HTPFreeConfig();
5021  SCConfDeInit();
5024  PASS;
5025 }
5026 
5027 /** \test Test unusual delims in request line HTP_LOG_CODE_REQUEST_FIELD_TOO_LONG */
5028 static int HTPParserTest16(void)
5029 {
5030  Flow *f = NULL;
5031  TcpSession ssn;
5032  HtpState *htp_state = NULL;
5034 
5035  memset(&ssn, 0, sizeof(ssn));
5036 
5037  uint8_t httpbuf[] = "GET\f/blah/\fHTTP/1.1\r\n"
5038  "Host: myhost.lan\r\n"
5039  "Connection: keep-alive\r\n"
5040  "Accept: */*\r\n"
5041  "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n"
5042  "Referer: http://blah.lan/\r\n"
5043  "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
5044  "Cookie: blah\r\n\r\n";
5045  size_t len = sizeof(httpbuf) - 1;
5046 
5047  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5048  FAIL_IF_NULL(f);
5049  f->protoctx = &ssn;
5050  f->proto = IPPROTO_TCP;
5051  f->alproto = ALPROTO_HTTP1;
5052 
5053  StreamTcpInitConfig(true);
5054 
5055  uint8_t flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
5056 
5057  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)httpbuf, len);
5058  FAIL_IF(r != 0);
5059 
5060  htp_state = f->alstate;
5061  FAIL_IF_NULL(htp_state);
5062 
5063  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5064  FAIL_IF_NULL(tx);
5065  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5066  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5067 
5068 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
5069 //these events are disabled during fuzzing as they are too noisy and consume much resource
5070  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
5071  AppLayerDecoderEvents *decoder_events =
5072  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
5073 
5074  FAIL_IF_NULL(decoder_events);
5075  FAIL_IF(decoder_events->events[0] != HTP_LOG_CODE_METHOD_DELIM_NON_COMPLIANT);
5076  FAIL_IF(decoder_events->events[1] != HTP_LOG_CODE_URI_DELIM_NON_COMPLIANT);
5077 #endif
5078 
5080  StreamTcpFreeConfig(true);
5081  UTHFreeFlow(f);
5082  PASS;
5083 }
5084 
5085 /** \test Test response not HTTP
5086  */
5087 static int HTPParserTest20(void)
5088 {
5089  Flow *f = NULL;
5090  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5091  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5092  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5093  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5094  uint8_t httpbuf2[] = "NOTHTTP\r\nSOMEOTHERDATA";
5095  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5096  uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA";
5097  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
5098  TcpSession ssn;
5099  HtpState *http_state = NULL;
5102 
5103  memset(&ssn, 0, sizeof(ssn));
5104 
5105  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5106  FAIL_IF_NULL(f);
5107  f->protoctx = &ssn;
5108  f->proto = IPPROTO_TCP;
5109  f->alproto = ALPROTO_HTTP1;
5110 
5111  StreamTcpInitConfig(true);
5112 
5113  int r = AppLayerParserParse(
5114  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5115  FAIL_IF(r != 0);
5116 
5117  r = AppLayerParserParse(
5118  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5119  FAIL_IF(r != 0);
5120 
5121  r = AppLayerParserParse(
5122  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf3, httplen3);
5123  FAIL_IF(r != 0);
5124 
5125  http_state = f->alstate;
5126  FAIL_IF_NULL(http_state);
5127  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5128  FAIL_IF_NULL(tx);
5129  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5130  FAIL_IF_NULL(h);
5131 
5132  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5133  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5134 
5135  FAIL_IF(htp_tx_response_status_number(tx) != 0);
5136  FAIL_IF(htp_tx_response_protocol_number(tx) != -1);
5137 
5139  StreamTcpFreeConfig(true);
5140  UTHFreeFlow(f);
5141  PASS;
5142 }
5143 
5144 /** \test Test response not HTTP
5145  */
5146 static int HTPParserTest21(void)
5147 {
5148  Flow *f = NULL;
5149  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5150  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5151  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5152  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5153  uint8_t httpbuf2[] = "999 NOTHTTP REALLY\r\nSOMEOTHERDATA\r\n";
5154  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5155  uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA";
5156  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
5157  TcpSession ssn;
5158  HtpState *http_state = NULL;
5161 
5162  memset(&ssn, 0, sizeof(ssn));
5163 
5164  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5165  FAIL_IF_NULL(f);
5166  f->protoctx = &ssn;
5167  f->proto = IPPROTO_TCP;
5168  f->alproto = ALPROTO_HTTP1;
5169 
5170  StreamTcpInitConfig(true);
5171 
5172  int r = AppLayerParserParse(
5173  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5174  FAIL_IF(r != 0);
5175 
5176  r = AppLayerParserParse(
5177  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5178  FAIL_IF(r != 0);
5179 
5180  r = AppLayerParserParse(
5181  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf3, httplen3);
5182  FAIL_IF(r != 0);
5183 
5184  http_state = f->alstate;
5185  FAIL_IF_NULL(http_state);
5186  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5187  FAIL_IF_NULL(tx);
5188  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5189  FAIL_IF_NULL(h);
5190 
5191  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5192  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5193 
5194  FAIL_IF(htp_tx_response_status_number(tx) != 0);
5195  FAIL_IF(htp_tx_response_protocol_number(tx) != -1);
5196 
5198  StreamTcpFreeConfig(true);
5199  UTHFreeFlow(f);
5200  PASS;
5201 }
5202 
5203 /** \test Test response not HTTP
5204  */
5205 static int HTPParserTest22(void)
5206 {
5207  Flow *f = NULL;
5208  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5209  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5210  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5211  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5212  uint8_t httpbuf2[] = "\r\n0000=0000000/ASDF3_31.zip, 456723\r\n"
5213  "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
5214  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5215  TcpSession ssn;
5216  HtpState *http_state = NULL;
5219 
5220  memset(&ssn, 0, sizeof(ssn));
5221 
5222  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5223  FAIL_IF_NULL(f);
5224  f->protoctx = &ssn;
5225  f->proto = IPPROTO_TCP;
5226  f->alproto = ALPROTO_HTTP1;
5227 
5228  StreamTcpInitConfig(true);
5229 
5230  int r = AppLayerParserParse(
5231  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5232  FAIL_IF(r != 0);
5233 
5234  r = AppLayerParserParse(
5235  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5236  FAIL_IF(r != 0);
5237 
5238  http_state = f->alstate;
5239  FAIL_IF_NULL(http_state);
5240  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5241  FAIL_IF_NULL(tx);
5242  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5243  FAIL_IF_NULL(h);
5244 
5245  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5246  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5247 
5248  FAIL_IF(htp_tx_response_status_number(tx) != -0);
5249  FAIL_IF(htp_tx_response_protocol_number(tx) != -1);
5250 
5252  StreamTcpFreeConfig(true);
5253  UTHFreeFlow(f);
5254  PASS;
5255 }
5256 
5257 /** \test Test response not HTTP
5258  */
5259 static int HTPParserTest23(void)
5260 {
5261  Flow *f = NULL;
5262  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5263  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5264  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5265  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5266  uint8_t httpbuf2[] = "HTTP0000=0000000/ASDF3_31.zip, 456723\r\n"
5267  "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
5268  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5269  TcpSession ssn;
5270  HtpState *http_state = NULL;
5273 
5274  memset(&ssn, 0, sizeof(ssn));
5275 
5276  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5277  FAIL_IF_NULL(f);
5278  f->protoctx = &ssn;
5279  f->proto = IPPROTO_TCP;
5280  f->alproto = ALPROTO_HTTP1;
5281 
5282  StreamTcpInitConfig(true);
5283 
5284  int r = AppLayerParserParse(
5285  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5286  FAIL_IF(r != 0);
5287 
5288  r = AppLayerParserParse(
5289  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5290  FAIL_IF(r != 0);
5291 
5292  http_state = f->alstate;
5293  FAIL_IF_NULL(http_state);
5294  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5295  FAIL_IF_NULL(tx);
5296  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5297  FAIL_IF_NULL(h);
5298 
5299  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5300  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5301 
5302  FAIL_IF(htp_tx_response_status_number(tx) != -1);
5303  FAIL_IF(htp_tx_response_protocol_number(tx) != -2);
5304 
5306  StreamTcpFreeConfig(true);
5307  UTHFreeFlow(f);
5308  PASS;
5309 }
5310 
5311 /** \test Test response not HTTP
5312  */
5313 static int HTPParserTest24(void)
5314 {
5315  Flow *f = NULL;
5316  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5317  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5318  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5319  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5320  uint8_t httpbuf2[] = "HTTP/1.0 0000=0000000/ASDF3_31.zip, 456723\r\n"
5321  "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
5322  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5323  TcpSession ssn;
5324  HtpState *http_state = NULL;
5327 
5328  memset(&ssn, 0, sizeof(ssn));
5329 
5330  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5331  FAIL_IF_NULL(f);
5332  f->protoctx = &ssn;
5333  f->proto = IPPROTO_TCP;
5334  f->alproto = ALPROTO_HTTP1;
5335 
5336  StreamTcpInitConfig(true);
5337 
5338  int r = AppLayerParserParse(
5339  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5340  FAIL_IF(r != 0);
5341 
5342  r = AppLayerParserParse(
5343  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5344  FAIL_IF(r != 0);
5345 
5346  http_state = f->alstate;
5347  FAIL_IF_NULL(http_state);
5348  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5349  FAIL_IF_NULL(tx);
5350  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5351  FAIL_IF_NULL(h);
5352 
5353  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5354  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5355 
5356  FAIL_IF(htp_tx_response_status_number(tx) != -1);
5357  FAIL_IF(htp_tx_response_protocol_number(tx) != HTP_PROTOCOL_V1_0);
5358 
5360  StreamTcpFreeConfig(true);
5361  UTHFreeFlow(f);
5362  PASS;
5363 }
5364 
5365 /** \test multi transactions and cleanup */
5366 static int HTPParserTest25(void)
5367 {
5370 
5371  StreamTcpInitConfig(true);
5372  TcpSession ssn;
5373  memset(&ssn, 0, sizeof(ssn));
5374 
5375  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5376  FAIL_IF_NULL(f);
5377  f->protoctx = &ssn;
5378  f->proto = IPPROTO_TCP;
5379  f->alproto = ALPROTO_HTTP1;
5381 
5382  const char *str = "GET / HTTP/1.1\r\nHost: www.google.com\r\nUser-Agent: Suricata/1.0\r\n\r\n";
5383  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START,
5384  (uint8_t *)str, strlen(str));
5385  FAIL_IF_NOT(r == 0);
5386  r = AppLayerParserParse(
5387  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5388  FAIL_IF_NOT(r == 0);
5389  r = AppLayerParserParse(
5390  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5391  FAIL_IF_NOT(r == 0);
5392  r = AppLayerParserParse(
5393  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5394  FAIL_IF_NOT(r == 0);
5395  r = AppLayerParserParse(
5396  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5397  FAIL_IF_NOT(r == 0);
5398  r = AppLayerParserParse(
5399  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5400  FAIL_IF_NOT(r == 0);
5401  r = AppLayerParserParse(
5402  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5403  FAIL_IF_NOT(r == 0);
5404  r = AppLayerParserParse(
5405  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5406  FAIL_IF_NOT(r == 0);
5407 
5408  str = "HTTP 1.1 200 OK\r\nServer: Suricata/1.0\r\nContent-Length: 8\r\n\r\nSuricata";
5409  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START,
5410  (uint8_t *)str, strlen(str));
5411  FAIL_IF_NOT(r == 0);
5412  r = AppLayerParserParse(
5413  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5414  FAIL_IF_NOT(r == 0);
5415  r = AppLayerParserParse(
5416  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5417  FAIL_IF_NOT(r == 0);
5418  r = AppLayerParserParse(
5419  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5420  FAIL_IF_NOT(r == 0);
5421  r = AppLayerParserParse(
5422  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5423  FAIL_IF_NOT(r == 0);
5424  r = AppLayerParserParse(
5425  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5426  FAIL_IF_NOT(r == 0);
5427  r = AppLayerParserParse(
5428  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5429  FAIL_IF_NOT(r == 0);
5430  r = AppLayerParserParse(
5431  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5432  FAIL_IF_NOT(r == 0);
5433 
5434  AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
5435 
5436  uint64_t ret[4];
5437  UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
5438  FAIL_IF_NOT(ret[0] == 8); // inspect_id[0]
5439  FAIL_IF_NOT(ret[1] == 8); // inspect_id[1]
5440  FAIL_IF_NOT(ret[2] == 8); // log_id
5441  FAIL_IF_NOT(ret[3] == 8); // min_id
5442 
5443  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF,
5444  (uint8_t *)str, strlen(str));
5445  FAIL_IF_NOT(r == 0);
5446  AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
5447 
5448  UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
5449  FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] not updated by ..Cleanup() until full tx is done
5450  FAIL_IF_NOT(ret[1] == 8); // inspect_id[1]
5451  FAIL_IF_NOT(ret[2] == 8); // log_id
5452  FAIL_IF_NOT(ret[3] == 8); // min_id
5453 
5454  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_EOF,
5455  (uint8_t *)str, strlen(str));
5456  FAIL_IF_NOT(r == 0);
5457  AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
5458 
5459  UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
5460  FAIL_IF_NOT(ret[0] == 9); // inspect_id[0]
5461  FAIL_IF_NOT(ret[1] == 9); // inspect_id[1]
5462  FAIL_IF_NOT(ret[2] == 9); // log_id
5463  FAIL_IF_NOT(ret[3] == 9); // min_id
5464 
5465  HtpState *http_state = f->alstate;
5466  FAIL_IF_NULL(http_state);
5467 
5469  StreamTcpFreeConfig(true);
5470  UTHFreeFlow(f);
5471 
5472  PASS;
5473 }
5474 
5475 static int HTPParserTest26(void)
5476 {
5477  char input[] = "\
5478 %YAML 1.1\n\
5479 ---\n\
5480 libhtp:\n\
5481 \n\
5482  default-config:\n\
5483  personality: IDS\n\
5484  request-body-limit: 1\n\
5485  response-body-limit: 1\n\
5486 ";
5488  SCConfInit();
5490  SCConfYamlLoadString(input, strlen(input));
5491  HTPConfigure();
5492 
5493  Packet *p1 = NULL;
5494  Packet *p2 = NULL;
5495  ThreadVars th_v;
5496  DetectEngineCtx *de_ctx = NULL;
5497  DetectEngineThreadCtx *det_ctx = NULL;
5498  Flow f;
5499  uint8_t httpbuf1[] = "GET /alice.txt HTTP/1.1\r\n\r\n";
5500  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5501  uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\n"
5502  "Content-Type: text/plain\r\n"
5503  "Content-Length: 228\r\n\r\n"
5504  "Alice was beginning to get very tired of sitting by her sister on the bank."
5505  "Alice was beginning to get very tired of sitting by her sister on the bank.";
5506  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5507  uint8_t httpbuf3[] = "Alice was beginning to get very tired of sitting by her sister on the bank.\r\n\r\n";
5508  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
5509  TcpSession ssn;
5510  HtpState *http_state = NULL;
5513 
5514  memset(&th_v, 0, sizeof(th_v));
5515  memset(&f, 0, sizeof(f));
5516  memset(&ssn, 0, sizeof(ssn));
5517 
5518  p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
5519  p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
5520 
5521  FLOW_INITIALIZE(&f);
5522  f.protoctx = (void *)&ssn;
5523  f.proto = IPPROTO_TCP;
5524  f.flags |= FLOW_IPV4;
5525 
5526  p1->flow = &f;
5530  p2->flow = &f;
5534  f.alproto = ALPROTO_HTTP1;
5535 
5536  StreamTcpInitConfig(true);
5537 
5540 
5541  de_ctx->flags |= DE_QUIET;
5542 
5543  de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any "
5544  "(filestore; sid:1; rev:1;)");
5546 
5548  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
5549 
5550  int r = AppLayerParserParse(
5551  &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
5552  FAIL_IF(r != 0);
5553 
5554  http_state = f.alstate;
5555  FAIL_IF_NULL(http_state);
5556 
5557  /* do detect */
5558  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
5559 
5560  FAIL_IF((PacketAlertCheck(p1, 1)));
5561 
5562  /* do detect */
5563  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
5564 
5565  FAIL_IF((PacketAlertCheck(p1, 1)));
5566 
5567  r = AppLayerParserParse(
5568  &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf2, httplen2);
5569  FAIL_IF(r != 0);
5570 
5571  http_state = f.alstate;
5572  FAIL_IF_NULL(http_state);
5573 
5574  /* do detect */
5575  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
5576 
5577  FAIL_IF(!(PacketAlertCheck(p2, 1)));
5578 
5579  r = AppLayerParserParse(
5580  &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf3, httplen3);
5581  FAIL_IF(r != 0);
5582 
5583  http_state = f.alstate;
5584  FAIL_IF_NULL(http_state);
5585 
5586  void *tx_ptr = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
5587  FAIL_IF_NULL(tx_ptr);
5588 
5589  AppLayerGetFileState files = HTPGetTxFiles(tx_ptr, STREAM_TOCLIENT);
5590  FileContainer *ffc = files.fc;
5591  FAIL_IF_NULL(ffc);
5592 
5593  File *ptr = ffc->head;
5594  FAIL_IF(ptr->state != FILE_STATE_CLOSED);
5595 
5597  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
5599  StreamTcpFreeConfig(true);
5600 
5601  HTPFreeConfig();
5602  FLOW_DESTROY(&f);
5603  UTHFreePackets(&p1, 1);
5604  UTHFreePackets(&p2, 1);
5605  SCConfDeInit();
5608  PASS;
5609 }
5610 
5611 static int HTPParserTest27(void)
5612 {
5613  HTPCfgDir cfg;
5614  memset(&cfg, 0, sizeof(cfg));
5615  cfg.body_limit = 1500;
5617 
5618  uint32_t len = 1000;
5619 
5620  HtpTxUserData *tx_ud = SCMalloc(sizeof(HtpTxUserData));
5621  FAIL_IF_NULL(tx_ud);
5622 
5623  tx_ud->tsflags |= HTP_STREAM_DEPTH_SET;
5624  tx_ud->request_body.content_len_so_far = 2500;
5625 
5626  FAIL_IF(AppLayerHtpCheckDepth(&cfg, &tx_ud->request_body, tx_ud->tsflags));
5627 
5628  len = AppLayerHtpComputeChunkLength(tx_ud->request_body.content_len_so_far,
5629  0,
5631  tx_ud->tsflags,
5632  len);
5633  FAIL_IF(len != 1000);
5634 
5635  SCFree(tx_ud);
5636 
5637  PASS;
5638 }
5639 
5640 /**
5641  * \brief Register the Unit tests for the HTTP protocol
5642  */
5643 static void HTPParserRegisterTests(void)
5644 {
5645  UtRegisterTest("HTPParserTest01", HTPParserTest01);
5646  UtRegisterTest("HTPParserTest01a", HTPParserTest01a);
5647  UtRegisterTest("HTPParserTest01b", HTPParserTest01b);
5648  UtRegisterTest("HTPParserTest01c", HTPParserTest01c);
5649  UtRegisterTest("HTPParserTest02", HTPParserTest02);
5650  UtRegisterTest("HTPParserTest03", HTPParserTest03);
5651  UtRegisterTest("HTPParserTest04", HTPParserTest04);
5652  UtRegisterTest("HTPParserTest05", HTPParserTest05);
5653  UtRegisterTest("HTPParserTest06", HTPParserTest06);
5654  UtRegisterTest("HTPParserTest07", HTPParserTest07);
5655  UtRegisterTest("HTPParserTest08", HTPParserTest08);
5656  UtRegisterTest("HTPParserTest09", HTPParserTest09);
5657  UtRegisterTest("HTPParserTest10", HTPParserTest10);
5658  UtRegisterTest("HTPParserTest11", HTPParserTest11);
5659  UtRegisterTest("HTPParserTest12", HTPParserTest12);
5660  UtRegisterTest("HTPParserTest13", HTPParserTest13);
5661  UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01);
5662  UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02);
5663  UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03);
5664 
5665  UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01);
5666  UtRegisterTest("HTPParserDecodingTest01a", HTPParserDecodingTest01a);
5667  UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02);
5668  UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03);
5669  UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04);
5670  UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05);
5671  UtRegisterTest("HTPParserDecodingTest06", HTPParserDecodingTest06);
5672  UtRegisterTest("HTPParserDecodingTest07", HTPParserDecodingTest07);
5673  UtRegisterTest("HTPParserDecodingTest08", HTPParserDecodingTest08);
5674  UtRegisterTest("HTPParserDecodingTest09", HTPParserDecodingTest09);
5675 
5676  UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01);
5677 
5678  UtRegisterTest("HTPSegvTest01", HTPSegvTest01);
5679 
5680  UtRegisterTest("HTPParserTest14", HTPParserTest14);
5681  UtRegisterTest("HTPParserTest15", HTPParserTest15);
5682  UtRegisterTest("HTPParserTest16", HTPParserTest16);
5683  UtRegisterTest("HTPParserTest20", HTPParserTest20);
5684  UtRegisterTest("HTPParserTest21", HTPParserTest21);
5685  UtRegisterTest("HTPParserTest22", HTPParserTest22);
5686  UtRegisterTest("HTPParserTest23", HTPParserTest23);
5687  UtRegisterTest("HTPParserTest24", HTPParserTest24);
5688  UtRegisterTest("HTPParserTest25", HTPParserTest25);
5689  UtRegisterTest("HTPParserTest26", HTPParserTest26);
5690  UtRegisterTest("HTPParserTest27", HTPParserTest27);
5691 
5694 }
5695 #endif /* UNITTESTS */
5696 
5697 /**
5698  * @}
5699  */
HtpState
struct HtpState_ HtpState
HtpState_::cfg
const struct HTPCfgRec_ * cfg
Definition: app-layer-htp.h:188
HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT
#define HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT
Definition: app-layer-htp.h:43
util-byte.h
SCConfYamlLoadString
int SCConfYamlLoadString(const char *string, size_t len)
Load configuration from a YAML string.
Definition: conf-yaml-loader.c:523
FILE_TRUNCATED
#define FILE_TRUNCATED
Definition: util-file.h:45
AppLayerParserRegisterGetStateProgressFunc
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
Definition: app-layer-parser.c:499
FileContainer_
Definition: util-file.h:113
HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR
@ HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR
Definition: app-layer-htp.h:77
HTP_BODY_REQUEST_POST
@ HTP_BODY_REQUEST_POST
Definition: app-layer-htp.h:71
len
uint8_t len
Definition: app-layer-dnp3.h:2
ts
uint64_t ts
Definition: source-erf-file.c:55
SCConfValIsTrue
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:551
app-layer-htp-range.h
AppLayerHtpNeedFileInspection
void AppLayerHtpNeedFileInspection(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request file...
Definition: app-layer-htp.c:578
detect-engine.h
HTPFileCloseHandleRange
bool HTPFileCloseHandleRange(const StreamingBufferConfig *sbcfg, 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:267
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
HTP_MAX_MESSAGES
#define HTP_MAX_MESSAGES
Definition: app-layer-htp.c:94
HtpState_::slice
StreamSlice * slice
Definition: app-layer-htp.h:195
AppLayerProtoDetectPMRegisterPatternCI
int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction)
Registers a case-insensitive pattern for protocol detection.
Definition: app-layer-detect-proto.c:1668
FLOW_IS_IPV6
#define FLOW_IS_IPV6(f)
Definition: flow.h:172
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1250
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
AppLayerParserRegisterOptionFlags
void AppLayerParserRegisterOptionFlags(uint8_t ipproto, AppProto alproto, uint32_t flags)
Definition: app-layer-parser.c:424
flow-util.h
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:314
htp_radix4_cfg
SCRadix4Config htp_radix4_cfg
Definition: app-layer-htp.c:85
Flow_::startts
SCTime_t startts
Definition: flow.h:493
HtpTxUserData_::request_headers_raw_len
uint32_t request_headers_raw_len
Definition: app-layer-htp.h:169
StreamingBufferConfig_::Calloc
void *(* Calloc)(size_t n, size_t size)
Definition: util-streaming-buffer.h:69
FileReassemblyDepthEnable
void FileReassemblyDepthEnable(uint32_t size)
Definition: util-file.c:127
stream-tcp.h
HTPCfgDir_
Definition: app-layer-htp.h:94
SCRadix6TreeFindBestMatch
SCRadix6Node * SCRadix6TreeFindBestMatch(const SCRadix6Tree *tree, const uint8_t *key, void **user_data)
Definition: util-radix6-tree.c:173
HtpBody_::sb
StreamingBuffer * sb
Definition: app-layer-htp.h:134
HtpTxUserData_::files_tc
FileContainer files_tc
Definition: app-layer-htp.h:178
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
HTPFileStoreChunk
int HTPFileStoreChunk(HtpTxUserData *tx, 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:223
AppLayerParserTransactionsCleanup
void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir)
remove obsolete (inspected and logged) transactions
Definition: app-layer-parser.c:902
HTPCfgRec_::response
HTPCfgDir response
Definition: app-layer-htp.h:116
SCRadix4AddKeyIPV4String
bool SCRadix4AddKeyIPV4String(SCRadix4Tree *tree, const SCRadix4Config *config, const char *str, void *user)
Adds a new IPV4/netblock to the Radix4 tree from a string.
Definition: util-radix4-tree.c:227
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
FLOW_SGH_TOCLIENT
#define FLOW_SGH_TOCLIENT
Definition: flow.h:75
AppLayerHtpPrintStats
void AppLayerHtpPrintStats(void)
Definition: app-layer-htp.c:2428
AppLayerParserGetEventsByTx
AppLayerDecoderEvents * AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *tx)
Definition: app-layer-parser.c:856
HTPCfgDir_::body_limit
uint32_t body_limit
Definition: app-layer-htp.h:95
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
Flow_::proto
uint8_t proto
Definition: flow.h:378
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:85
AppLayerParserConfParserEnabled
int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests
Definition: app-layer-parser.c:343
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:141
AppLayerParserGetStateProgress
int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t flags)
get the progress value for a tx/protocol
Definition: app-layer-parser.c:1086
AppLayerParserTriggerRawStreamReassembly
void AppLayerParserTriggerRawStreamReassembly(Flow *f, int direction)
Definition: app-layer-parser.c:1556
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:2178
STREAMING_BUFFER_CONFIG_INITIALIZER
#define STREAMING_BUFFER_CONFIG_INITIALIZER
Definition: util-streaming-buffer.h:74
HtpTxUserData_::mime_state
MimeStateHTTP * mime_state
Definition: app-layer-htp.h:172
Packet_::flags
uint32_t flags
Definition: decode.h:535
Frame
Definition: app-layer-frames.h:45
Flow_
Flow data structure.
Definition: flow.h:356
File_::state
FileState state
Definition: util-file.h:82
HtpGetTxForH2
void * HtpGetTxForH2(void *alstate)
Definition: app-layer-htp.c:2489
HtpState_::flags
uint16_t flags
Definition: app-layer-htp.h:189
HtpState_::f
Flow * f
Definition: app-layer-htp.h:186
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:931
AppLayerParserRegisterStateProgressCompletionStatus
void AppLayerParserRegisterStateProgressCompletionStatus(AppProto alproto, const int ts, const int tc)
Definition: app-layer-parser.c:547
AppLayerParserRegisterParserAcceptableDataDirection
void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppProto alproto, uint8_t direction)
Definition: app-layer-parser.c:413
AppLayerParserRegisterTxFreeFunc
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
Definition: app-layer-parser.c:509
AppLayerFrameSetTxId
void AppLayerFrameSetTxId(Frame *r, uint64_t tx_id)
Definition: app-layer-frames.c:679
Frame::id
int64_t id
Definition: app-layer-frames.h:53
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2674
HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW
#define HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW
Definition: app-layer-htp.h:45
HtpTxUserData_::request_body
HtpBody request_body
Definition: app-layer-htp.h:164
AppLayerRequestProtocolChange
bool AppLayerRequestProtocolChange(Flow *f, uint16_t dp, AppProto expect_proto)
request applayer to wrap up this protocol and rerun protocol detection.
Definition: app-layer-detect-proto.c:1823
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:322
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:233
MIN
#define MIN(x, y)
Definition: suricata-common.h:408
HTTP_SWF_COMPRESSION_ZLIB
@ HTTP_SWF_COMPRESSION_ZLIB
Definition: app-layer-htp.h:89
AppLayerParserRegisterGetStateFuncs
void AppLayerParserRegisterGetStateFuncs(uint8_t ipproto, AppProto alproto, AppLayerParserGetStateIdByNameFn GetIdByNameFunc, AppLayerParserGetStateNameByIdFn GetNameByIdFunc)
Definition: app-layer-parser.c:574
DE_QUIET
#define DE_QUIET
Definition: detect.h:329
SCConfValIsFalse
int SCConfValIsFalse(const char *val)
Check if a value is false.
Definition: conf.c:576
HTP_BODY_REQUEST_PUT
@ HTP_BODY_REQUEST_PUT
Definition: app-layer-htp.h:72
UTHBuildPacket
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
Definition: util-unittest-helper.c:365
HTPRealloc
void * HTPRealloc(void *ptr, size_t orig_size, size_t size)
Definition: app-layer-htp-mem.c:174
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:2347
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
RandomGet
long int RandomGet(void)
Definition: util-random.c:130
Flow_::dp
Port dp
Definition: flow.h:372
HtpState_::transaction_cnt
uint64_t transaction_cnt
Definition: app-layer-htp.h:187
HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE
#define HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE
Definition: app-layer-htp.h:44
HTPCfgRec_::swf_compress_depth
uint32_t swf_compress_depth
Definition: app-layer-htp.h:113
StreamingBufferGetDataAtOffset
int StreamingBufferGetDataAtOffset(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t offset)
Definition: util-streaming-buffer.c:1830
AppLayerFrameNewByAbsoluteOffset
Frame * AppLayerFrameNewByAbsoluteOffset(Flow *f, const StreamSlice *stream_slice, const uint64_t frame_start, const int64_t len, int dir, uint8_t frame_type)
create new frame using the absolute offset from the start of the stream
Definition: app-layer-frames.c:598
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:523
HTPStateFree
void HTPStateFree(void *state)
Function to frees the HTTP state memory and also frees the HTTP connection parser memory which was us...
Definition: app-layer-htp.c:500
APP_LAYER_PARSER_EOF_TS
#define APP_LAYER_PARSER_EOF_TS
Definition: app-layer-parser.h:39
Flow_::protoctx
void * protoctx
Definition: flow.h:441
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:100
GET_IPV6_DST_ADDR
#define GET_IPV6_DST_ADDR(p)
Definition: decode.h:204
HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG
@ HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG
Definition: app-layer-htp.h:83
AppLayerDecoderEvents_
Data structure to store app layer decoder events.
Definition: app-layer-events.h:36
HTPCfgDir_::inspect_window
uint32_t inspect_window
Definition: app-layer-htp.h:97
util-unittest.h
HTPConfigure
void HTPConfigure(void)
Definition: app-layer-htp.c:2357
HTTP_DECODER_EVENT_TOO_MANY_WARNINGS
@ HTTP_DECODER_EVENT_TOO_MANY_WARNINGS
Definition: app-layer-htp.h:81
HtpState_
Definition: app-layer-htp.h:181
HTPParseMemcap
void HTPParseMemcap(void)
Definition: app-layer-htp-mem.c:43
StringParseU32RangeCheck
int StringParseU32RangeCheck(uint32_t *res, int base, size_t len, const char *str, uint32_t min, uint32_t max)
Definition: util-byte.c:404
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
SCRadix4TreeRelease
void SCRadix4TreeRelease(SCRadix4Tree *tree, const SCRadix4Config *config)
Definition: util-radix4-tree.c:172
HTPFileOpen
int HTPFileOpen(HtpState *s, HtpTxUserData *tx, const uint8_t *filename, uint16_t filename_len, const uint8_t *data, uint32_t data_len, uint8_t direction)
Open the file with "filename" and pass the first chunk of data if any.
Definition: app-layer-htp-file.c:50
app-layer-htp-xff.h
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
app-layer-htp-file.h
util-memcmp.h
HtpBody_::content_len_so_far
uint64_t content_len_so_far
Definition: app-layer-htp.h:137
HtpState_::response_frame_id
FrameId response_frame_id
Definition: app-layer-htp.h:197
SCRadix4Tree_
Structure for the radix tree.
Definition: util-radix4-tree.h:66
SCConfInit
void SCConfInit(void)
Initialize the configuration system.
Definition: conf.c:120
HTP_CONFIG_DEFAULT_HEADERS_LIMIT
#define HTP_CONFIG_DEFAULT_HEADERS_LIMIT
Flow_::alparser
AppLayerParserState * alparser
Definition: flow.h:478
Flow_::dst
FlowAddress dst
Definition: flow.h:359
HtpTxUserData_::file_range
HttpRangeContainerBlock * file_range
Definition: app-layer-htp.h:174
app-layer-detect-proto.h
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:488
UTHBuildFlow
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
Definition: util-unittest-helper.c:488
FLOW_INITIALIZE
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:38
app-layer-htp.h
HTP_FILENAME_SET
#define HTP_FILENAME_SET
Definition: app-layer-htp.h:145
APP_LAYER_INCOMPLETE
#define APP_LAYER_INCOMPLETE(c, n)
Definition: app-layer-parser.h:75
HTP_CONFIG_DEFAULT_LZMA_MEMLIMIT
#define HTP_CONFIG_DEFAULT_LZMA_MEMLIMIT
Definition: app-layer-htp.h:52
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
HtpState_::last_request_data_stamp
uint64_t last_request_data_stamp
Definition: app-layer-htp.h:193
TAILQ_FIRST
#define TAILQ_FIRST(head)
Definition: queue.h:250
HtpBody_::body_parsed
uint64_t body_parsed
Definition: app-layer-htp.h:139
HTPCfgRec_::http_body_inline
int http_body_inline
Definition: app-layer-htp.h:108
AppLayerParserState_
Definition: app-layer-parser.c:133
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
HTPCfgRec_::randomize_range
int randomize_range
Definition: app-layer-htp.h:107
GET_IPV4_DST_ADDR_PTR
#define GET_IPV4_DST_ADDR_PTR(p)
Definition: decode.h:199
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
HTP_FLAG_STATE_CLOSED_TC
#define HTP_FLAG_STATE_CLOSED_TC
Definition: app-layer-htp.h:64
HTTP_SWF_COMPRESSION_NONE
@ HTTP_SWF_COMPRESSION_NONE
Definition: app-layer-htp.h:88
HtpConfigCreateBackup
void HtpConfigCreateBackup(void)
Definition: app-layer-htp.c:2665
HTP_CONFIG_DEFAULT_FIELD_LIMIT
#define HTP_CONFIG_DEFAULT_FIELD_LIMIT
Definition: app-layer-htp.h:48
DetectEngineThreadCtx_
Definition: detect.h:1223
SC_FILENAME_MAX
#define SC_FILENAME_MAX
Definition: util-file.h:62
HTP_CONFIG_DEFAULT_COMPRESSION_TIME_LIMIT
#define HTP_CONFIG_DEFAULT_COMPRESSION_TIME_LIMIT
Definition: app-layer-htp.h:55
HTPCfgRec_::randomize
int randomize
Definition: app-layer-htp.h:106
HTPCfgDir_::inspect_min_size
uint32_t inspect_min_size
Definition: app-layer-htp.h:96
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
AppLayerHtpEnableRequestBodyCallback
void AppLayerHtpEnableRequestBodyCallback(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request body...
Definition: app-layer-htp.c:551
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:22
util-print.h
AppLayerParserRegisterGetFrameFuncs
void AppLayerParserRegisterGetFrameFuncs(uint8_t ipproto, AppProto alproto, AppLayerParserGetFrameIdByNameFn GetIdByNameFunc, AppLayerParserGetFrameNameByIdFn GetNameByIdFunc)
Definition: app-layer-parser.c:584
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
FileContainer_::head
File * head
Definition: util-file.h:114
http_decoder_event_table
SCEnumCharMap http_decoder_event_table[]
Definition: app-layer-htp.c:104
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
HtpTxUserData_::response_has_trailers
uint8_t response_has_trailers
Definition: app-layer-htp.h:157
HtpTxUserData_::request_headers_raw
uint8_t * request_headers_raw
Definition: app-layer-htp.h:167
HtpState_::conn
htp_conn_t * conn
Definition: app-layer-htp.h:185
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3400
HTPCfgRec_::swf_decompress_depth
uint32_t swf_decompress_depth
Definition: app-layer-htp.h:112
AppLayerParserRegisterStateFuncs
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void *, AppProto), void(*StateFree)(void *))
Definition: app-layer-parser.c:434
HTPCfgRec_::swf_decompression_enabled
int swf_decompression_enabled
Definition: app-layer-htp.h:110
HtpTxUserData_::tx_data
AppLayerTxData tx_data
Definition: app-layer-htp.h:176
HtpState_::state_data
AppLayerStateData state_data
Definition: app-layer-htp.h:198
HTPCalloc
void * HTPCalloc(size_t n, size_t size)
Definition: app-layer-htp-mem.c:153
HTPAtExitPrintStats
void HTPAtExitPrintStats(void)
Print the stats of the HTTP requests.
Definition: app-layer-htp.c:1583
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:249
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:3097
PrintRawDataFp
void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen)
Definition: util-print.c:112
HTP_CONFIG_DEFAULT_LZMA_LAYERS
#define HTP_CONFIG_DEFAULT_LZMA_LAYERS
Definition: app-layer-htp.h:50
app-layer-parser.h
HTPFileParserRegisterTests
void HTPFileParserRegisterTests(void)
Definition: app-layer-htp-file.c:1218
HTTP_DECODER_EVENT_RANGE_INVALID
@ HTTP_DECODER_EVENT_RANGE_INVALID
Definition: app-layer-htp.h:82
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:317
HtpTxUserData_::request_has_trailers
uint8_t request_has_trailers
Definition: app-layer-htp.h:156
FLOW_IS_IPV4
#define FLOW_IS_IPV4(f)
Definition: flow.h:170
HTP_FLAG_STATE_CLOSED_TS
#define HTP_FLAG_STATE_CLOSED_TS
Definition: app-layer-htp.h:61
AppLayerParserRegisterGetEventInfo
void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfo)(const char *event_name, uint8_t *event_id, AppLayerEventType *event_type))
Definition: app-layer-parser.c:594
HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE
#define HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE
Definition: app-layer-htp.h:46
FileReassemblyDepth
uint32_t FileReassemblyDepth(void)
Definition: util-file.c:133
SCReturn
#define SCReturn
Definition: util-debug.h:273
SC_ATOMIC_DECLARE
SC_ATOMIC_DECLARE(uint32_t, htp_config_flags)
AppLayerParserRegisterProtocolUnittests
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
Definition: app-layer-parser.c:1839
HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT
#define HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT
Definition: app-layer-htp.h:42
app-layer-htp-body.h
Packet_
Definition: decode.h:492
detect-engine-build.h
conf-yaml-loader.h
APP_LAYER_PARSER_EOF_TC
#define APP_LAYER_PARSER_EOF_TC
Definition: app-layer-parser.h:40
detect-engine-alert.h
conf.h
HtpState_::htp_messages_count
uint16_t htp_messages_count
Definition: app-layer-htp.h:191
Frame::len
int64_t len
Definition: app-layer-frames.h:52
SC_RADIX4_TREE_INITIALIZER
#define SC_RADIX4_TREE_INITIALIZER
Definition: util-radix4-tree.h:78
name
const char * name
Definition: tm-threads.c:2123
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:287
HtpBodyPrune
void HtpBodyPrune(HtpState *state, HtpBody *body, int direction)
Free request body chunks that are already fully parsed.
Definition: app-layer-htp-body.c:128
AppLayerParserRegisterGetTxFilesFunc
void AppLayerParserRegisterGetTxFilesFunc(uint8_t ipproto, AppProto alproto, AppLayerGetFileState(*GetTxFiles)(void *, uint8_t))
Definition: app-layer-parser.c:471
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
AppLayerProtoDetectRegisterProtocol
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
Definition: app-layer-detect-proto.c:1763
HTP_STREAM_DEPTH_SET
#define HTP_STREAM_DEPTH_SET
Definition: app-layer-htp.h:147
AppLayerHtpEnableResponseBodyCallback
void AppLayerHtpEnableResponseBodyCallback(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request body...
Definition: app-layer-htp.c:564
AppLayerParserRegisterSetStreamDepthFlag
void AppLayerParserRegisterSetStreamDepthFlag(uint8_t ipproto, AppProto alproto, void(*SetStreamDepthFlag)(void *tx, uint8_t flags))
Definition: app-layer-parser.c:635
SCConfCreateContextBackup
void SCConfCreateContextBackup(void)
Creates a backup of the conf_hash hash_table used by the conf API.
Definition: conf.c:684
IF_HTP_PERSONALITY_NUM
#define IF_HTP_PERSONALITY_NUM(p)
HTPCfgRec_::swf_compression_type
HtpSwfCompressType swf_compression_type
Definition: app-layer-htp.h:111
ALPROTO_HTTP2
@ ALPROTO_HTTP2
Definition: app-layer-protos.h:69
HTP_REQUIRE_RESPONSE_BODY
#define HTP_REQUIRE_RESPONSE_BODY
Definition: app-layer-htp.h:206
FLOW_PKT_TOCLIENT
#define FLOW_PKT_TOCLIENT
Definition: flow.h:234
HtpBodyFree
void HtpBodyFree(HtpBody *body)
Print the information and chunks of a Body.
Definition: app-layer-htp-body.c:99
HtpTxUserData_::response_body
HtpBody response_body
Definition: app-layer-htp.h:165
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:224
AppLayerParserGetTx
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
Definition: app-layer-parser.c:1108
AppLayerParserRegisterParser
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
Definition: app-layer-parser.c:401
WarnInvalidConfEntry
#define WarnInvalidConfEntry(param_name, format, value)
Generic API that can be used by all to log an invalid conf entry.
Definition: util-misc.h:35
DETECT_ENGINE_STATE_FLAG_FILE_NEW
#define DETECT_ENGINE_STATE_FLAG_FILE_NEW
Definition: detect-engine-state.h:70
HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE
@ HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE
Definition: app-layer-htp.h:84
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2129
HTPCfgRec_::next
struct HTPCfgRec_ * next
Definition: app-layer-htp.h:103
UTHFreeFlow
void UTHFreeFlow(Flow *flow)
Definition: util-unittest-helper.c:493
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:295
AppLayerParserRegisterGetTx
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
Definition: app-layer-parser.c:529
htp_sbcfg
StreamingBufferConfig htp_sbcfg
Definition: app-layer-htp.c:91
SCConfNodeLookupChild
SCConfNode * SCConfNodeLookupChild(const SCConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition: conf.c:796
HttpFrameTypes
HttpFrameTypes
Definition: app-layer-htp.c:221
FILE_STATE_CLOSED
@ FILE_STATE_CLOSED
Definition: util-file.h:71
File_
Definition: util-file.h:79
APP_LAYER_OK
#define APP_LAYER_OK
Definition: app-layer-parser.h:63
AppLayerTxData
struct AppLayerTxData AppLayerTxData
Definition: detect.h:1494
HtpTxUserData_::request_body_type
uint8_t request_body_type
Definition: app-layer-htp.h:162
HTPCfgRec_::cfg
htp_cfg_t * cfg
Definition: app-layer-htp.h:102
app-layer-frames.h
SCMapEnumValueToName
const char * SCMapEnumValueToName(int enum_value, SCEnumCharMap *table)
Maps an enum value to a string name, from the supplied table.
Definition: util-enum.c:68
Packet_::flow
struct Flow_ * flow
Definition: decode.h:537
SCReturnStruct
#define SCReturnStruct(x)
Definition: util-debug.h:291
SCRadix6Config_
Definition: util-radix6-tree.h:69
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
HtpBody_
Definition: app-layer-htp.h:130
StreamTcpFreeConfig
void StreamTcpFreeConfig(bool quiet)
Definition: stream-tcp.c:859
SCMapEnumNameToValue
int SCMapEnumNameToValue(const char *enum_name, SCEnumCharMap *table)
Maps a string name to an enum value from the supplied table. Please specify the last element of any m...
Definition: util-enum.c:40
HTPXFFParserRegisterTests
void HTPXFFParserRegisterTests(void)
Definition: app-layer-htp-xff.c:332
flags
uint8_t flags
Definition: decode-gre.h:0
HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA
@ HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA
Definition: app-layer-htp.h:78
SCRadix4Config_
Definition: util-radix4-tree.h:71
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:1290
suricata-common.h
HTPCfgRec_::request
HTPCfgDir request
Definition: app-layer-htp.h:115
HTP_REQUIRE_REQUEST_BODY
#define HTP_REQUIRE_REQUEST_BODY
Definition: app-layer-htp.h:202
HtpTxUserData_::response_headers_raw
uint8_t * response_headers_raw
Definition: app-layer-htp.h:168
SCEnumCharMap_
Definition: util-enum.h:27
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:36
AppLayerDecoderEventsSetEventRaw
void AppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t event)
Set an app layer decoder event.
Definition: app-layer-events.c:94
HtpState_::connp
htp_connp_t * connp
Definition: app-layer-htp.h:183
TAILQ_NEXT
#define TAILQ_NEXT(elm, field)
Definition: queue.h:307
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3626
HTP_BOUNDARY_SET
#define HTP_BOUNDARY_SET
Definition: app-layer-htp.h:144
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:230
HtpTxUserData_::tcflags
uint8_t tcflags
Definition: app-layer-htp.h:160
SCTIME_SECS
#define SCTIME_SECS(t)
Definition: util-time.h:57
AppLayerParserRegisterStateDataFunc
void AppLayerParserRegisterStateDataFunc(uint8_t ipproto, AppProto alproto, AppLayerStateData *(*GetStateData)(void *state))
Definition: app-layer-parser.c:615
htp_radix6_cfg
SCRadix6Config htp_radix6_cfg
Definition: app-layer-htp.c:86
HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER
@ HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER
Definition: app-layer-htp.h:79
SCConfDeInit
void SCConfDeInit(void)
De-initializes the configuration system.
Definition: conf.c:703
FatalError
#define FatalError(...)
Definition: util-debug.h:502
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:940
AppLayerParserRegisterTxDataFunc
void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto, AppLayerTxData *(*GetTxData)(void *tx))
Definition: app-layer-parser.c:605
ALPROTO_WEBSOCKET
@ ALPROTO_WEBSOCKET
Definition: app-layer-protos.h:64
HTP_DONTSTORE
#define HTP_DONTSTORE
Definition: app-layer-htp.h:146
HTP_CONFIG_DEFAULT_RANDOMIZE
#define HTP_CONFIG_DEFAULT_RANDOMIZE
Definition: app-layer-htp.h:57
HtpTxUserData_
Definition: app-layer-htp.h:151
HtpState_::last_response_data_stamp
uint64_t last_response_data_stamp
Definition: app-layer-htp.h:194
AppLayerFrameGetById
Frame * AppLayerFrameGetById(Flow *f, const int dir, const FrameId frame_id)
Definition: app-layer-frames.c:694
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
SCRadix4TreeFindBestMatch
SCRadix4Node * SCRadix4TreeFindBestMatch(const SCRadix4Tree *tree, const uint8_t *key, void **user_data)
Definition: util-radix4-tree.c:154
ParseSizeStringU32
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition: util-misc.c:173
util-validate.h
HtpConfigRestoreBackup
void HtpConfigRestoreBackup(void)
Definition: app-layer-htp.c:2670
StreamingBufferConfig_
Definition: util-streaming-buffer.h:65
FileContainerRecycle
void FileContainerRecycle(FileContainer *ffc, const StreamingBufferConfig *cfg)
Recycle a FileContainer.
Definition: util-file.c:513
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
HtpState_::events
uint16_t events
Definition: app-layer-htp.h:190
APP_LAYER_PARSER_OPT_ACCEPT_GAPS
#define APP_LAYER_PARSER_OPT_ACCEPT_GAPS
Definition: app-layer-parser.h:46
HttpRangeFreeBlock
void HttpRangeFreeBlock(HttpRangeContainerBlock *b)
Definition: app-layer-htp-range.c:607
HtpTxUserData_::response_body_init
uint8_t response_body_init
Definition: app-layer-htp.h:154
HTTP_FRAME_RESPONSE
@ HTTP_FRAME_RESPONSE
Definition: app-layer-htp.c:223
str
#define str(s)
Definition: suricata-common.h:308
HTP_CONFIG_DEFAULT_COMPRESSION_BOMB_LIMIT
#define HTP_CONFIG_DEFAULT_COMPRESSION_BOMB_LIMIT
Definition: app-layer-htp.h:53
SCConfGetNode
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition: conf.c:181
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
FLOW_SGH_TOSERVER
#define FLOW_SGH_TOSERVER
Definition: flow.h:73
SCRadix6Tree_
Structure for the radix tree.
Definition: util-radix6-tree.h:64
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Flow_::alstate
void * alstate
Definition: flow.h:479
Flow_::flags
uint32_t flags
Definition: flow.h:421
AppLayerParserGetDecoderEvents
AppLayerDecoderEvents * AppLayerParserGetDecoderEvents(AppLayerParserState *pstate)
Definition: app-layer-parser.c:848
SCConfRestoreContextBackup
void SCConfRestoreContextBackup(void)
Restores the backup of the hash_table present in backup_conf_hash back to conf_hash.
Definition: conf.c:694
StreamingBufferConfig_::Free
void(* Free)(void *ptr, size_t size)
Definition: util-streaming-buffer.h:71
detect-parse.h
FAIL
#define FAIL
Fail a test.
Definition: util-unittest.h:60
HTTP_SWF_COMPRESSION_BOTH
@ HTTP_SWF_COMPRESSION_BOTH
Definition: app-layer-htp.h:91
UTHAppLayerParserStateGetIds
void UTHAppLayerParserStateGetIds(void *ptr, uint64_t *i1, uint64_t *i2, uint64_t *log, uint64_t *min)
Definition: app-layer-parser.c:212
HTPCfgRec_
Definition: app-layer-htp.h:101
HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW
#define HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW
Definition: app-layer-htp.h:47
RegisterHTPParsers
void RegisterHTPParsers(void)
Register the HTTP protocol and state handling functions to APP layer of the engine.
Definition: app-layer-htp.c:2594
SCRadix6AddKeyIPV6String
bool SCRadix6AddKeyIPV6String(SCRadix6Tree *tree, const SCRadix6Config *config, const char *str, void *user)
Adds a new IPV6/netblock to the Radix6 tree from a string.
Definition: util-radix6-tree.c:262
HTTP_SWF_COMPRESSION_LZMA
@ HTTP_SWF_COMPRESSION_LZMA
Definition: app-layer-htp.h:90
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
util-random.h
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:235
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2635
AppLayerParserStateAlloc
AppLayerParserState * AppLayerParserStateAlloc(void)
Definition: app-layer-parser.c:233
HtpState_::request_frame_id
FrameId request_frame_id
Definition: app-layer-htp.h:196
app-layer-protos.h
app-layer-htp-mem.h
EngineModeIsIPS
int EngineModeIsIPS(void)
Definition: suricata.c:234
HTP_BODY_REQUEST_MULTIPART
@ HTP_BODY_REQUEST_MULTIPART
Definition: app-layer-htp.h:70
suricata.h
HTPMalloc
void * HTPMalloc(size_t size)
Definition: app-layer-htp-mem.c:132
AppLayerParserRegisterGetTxCnt
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
Definition: app-layer-parser.c:519
HTTP_FRAME_REQUEST
@ HTTP_FRAME_REQUEST
Definition: app-layer-htp.c:222
StringParseInt8
int StringParseInt8(int8_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:672
APP_LAYER_ERROR
#define APP_LAYER_ERROR
Definition: app-layer-parser.h:67
SCConfNode_::name
char * name
Definition: conf.h:38
AppLayerParserRegisterGetEventInfoById
void AppLayerParserRegisterGetEventInfoById(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfoById)(uint8_t event_id, const char **event_name, AppLayerEventType *event_type))
Definition: app-layer-parser.c:562
SCRadix6TreeRelease
void SCRadix6TreeRelease(SCRadix6Tree *tree, const SCRadix6Config *config)
Definition: util-radix6-tree.c:366
SC_RADIX6_TREE_INITIALIZER
#define SC_RADIX6_TREE_INITIALIZER
Definition: util-radix6-tree.h:76
likely
#define likely(expr)
Definition: util-optimize.h:32
id
uint32_t id
Definition: detect-flowbits.c:933
HTPFileClose
int HTPFileClose(HtpTxUserData *tx, 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:309
HtpTxUserData_::files_ts
FileContainer files_ts
Definition: app-layer-htp.h:177
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:933
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:58
HTPFree
void HTPFree(void *ptr, size_t size)
Definition: app-layer-htp-mem.c:198
Flow_::sp
Port sp
Definition: flow.h:361
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:375
TcpSession_
Definition: stream-tcp-private.h:283
util-misc.h
HTPFreeConfig
void HTPFreeConfig(void)
Clears the HTTP server configuration memory used by HTP library.
Definition: app-layer-htp.c:1596
HtpTxUserData_::response_headers_raw_len
uint32_t response_headers_raw_len
Definition: app-layer-htp.h:170
AppLayerParserStateIssetFlag
uint16_t AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:1828
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:450
HtpTxUserData_::request_body_init
uint8_t request_body_init
Definition: app-layer-htp.h:153
HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE
#define HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE
Definition: app-layer-htp.h:58
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
SCConfNode_
Definition: conf.h:37
HTPFileOpenWithRange
int HTPFileOpenWithRange(HtpState *s, HtpTxUserData *txud, const uint8_t *filename, uint16_t filename_len, const uint8_t *data, uint32_t data_len, const htp_tx_t *tx, const bstr *rawvalue, HtpTxUserData *htud)
Sets range for a file.
Definition: app-layer-htp-file.c:149
http_frame_table
SCEnumCharMap http_frame_table[]
Definition: app-layer-htp.c:226
SCConfNode_::val
char * val
Definition: conf.h:39
AppLayerProtoDetectConfProtoDetectionEnabled
int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
Definition: app-layer-detect-proto.c:1964
HTP_CONFIG_DEFAULT_MAX_TX_LIMIT
#define HTP_CONFIG_DEFAULT_MAX_TX_LIMIT
AppLayerDecoderEvents_::events
uint8_t * events
Definition: app-layer-events.h:38
SCMutex
#define SCMutex
Definition: threads-debug.h:114
HtpBodyAppendChunk
int HtpBodyAppendChunk(HtpBody *body, const uint8_t *data, uint32_t len)
Append a chunk of body to the HtpBody struct.
Definition: app-layer-htp-body.c:48
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:119
SCAppLayerGetEventIdByName
int SCAppLayerGetEventIdByName(const char *event_name, SCEnumCharMap *table, uint8_t *event_id)
Definition: app-layer-events.c:28
HTP_REQUIRE_REQUEST_FILE
#define HTP_REQUIRE_REQUEST_FILE
Definition: app-layer-htp.h:204
StreamingBufferConfig_::Realloc
void *(* Realloc)(void *ptr, size_t orig_size, size_t size)
Definition: util-streaming-buffer.h:70
HtpTxUserData_::tsflags
uint8_t tsflags
Definition: app-layer-htp.h:159
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1247
HtpBody_::body_inspected
uint64_t body_inspected
Definition: app-layer-htp.h:141
AppLayerProtoDetectGetProtoName
const char * AppLayerProtoDetectGetProtoName(AppProto alproto)
Definition: app-layer-detect-proto.c:2093
SC_ATOMIC_OR
#define SC_ATOMIC_OR(name, val)
Bitwise OR a value to our atomic variable.
Definition: util-atomic.h:350
app-layer.h
SCTIME_USECS
#define SCTIME_USECS(t)
Definition: util-time.h:56
g_disable_randomness
int g_disable_randomness
Definition: suricata.c:194
UTHFreePackets
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Definition: util-unittest-helper.c:456