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  htp_tx_destroy(s->connp, id);
540 }
541 
542 /**
543  * \brief Sets a flag that informs the HTP app layer that some module in the
544  * engine needs the http request body data.
545  * \initonly
546  */
548 {
549  SCEnter();
550 
551  SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_BODY);
552  SCReturn;
553 }
554 
555 /**
556  * \brief Sets a flag that informs the HTP app layer that some module in the
557  * engine needs the http request body data.
558  * \initonly
559  */
561 {
562  SCEnter();
563 
564  SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_RESPONSE_BODY);
565  SCReturn;
566 }
567 
568 /**
569  * \brief Sets a flag that informs the HTP app layer that some module in the
570  * engine needs the http request file.
571  *
572  * \initonly
573  */
575 {
576  SCEnter();
579 
580  SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_FILE);
581  SCReturn;
582 }
583 
584 static void AppLayerHtpSetStreamDepthFlag(void *tx, const uint8_t flags)
585 {
586  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data((htp_tx_t *)tx);
587  SCLogDebug("setting HTP_STREAM_DEPTH_SET, flags %02x", flags);
588  if (flags & STREAM_TOCLIENT) {
589  tx_ud->tcflags |= HTP_STREAM_DEPTH_SET;
590  } else {
591  tx_ud->tsflags |= HTP_STREAM_DEPTH_SET;
592  }
593 }
594 
595 static bool AppLayerHtpCheckDepth(const HTPCfgDir *cfg, HtpBody *body, uint8_t flags)
596 {
597  SCLogDebug("cfg->body_limit %u stream_depth %u body->content_len_so_far %" PRIu64,
599  if (flags & HTP_STREAM_DEPTH_SET) {
600  uint32_t stream_depth = FileReassemblyDepth();
601  if (body->content_len_so_far < (uint64_t)stream_depth || stream_depth == 0) {
602  SCLogDebug("true");
603  return true;
604  }
605  } else {
606  if (cfg->body_limit == 0 || body->content_len_so_far < cfg->body_limit) {
607  return true;
608  }
609  }
610  SCLogDebug("false");
611  return false;
612 }
613 
614 static uint32_t AppLayerHtpComputeChunkLength(uint64_t content_len_so_far, uint32_t body_limit,
615  uint32_t stream_depth, uint8_t flags, uint32_t data_len)
616 {
617  uint32_t chunk_len = 0;
618  if (!(flags & HTP_STREAM_DEPTH_SET) && body_limit > 0 &&
619  (content_len_so_far < (uint64_t)body_limit) &&
620  (content_len_so_far + (uint64_t)data_len) > body_limit)
621  {
622  chunk_len = (uint32_t)(body_limit - content_len_so_far);
623  } else if ((flags & HTP_STREAM_DEPTH_SET) && stream_depth > 0 &&
624  (content_len_so_far < (uint64_t)stream_depth) &&
625  (content_len_so_far + (uint64_t)data_len) > stream_depth)
626  {
627  chunk_len = (uint32_t)(stream_depth - content_len_so_far);
628  }
629  SCLogDebug("len %u", chunk_len);
630  return (chunk_len == 0 ? data_len : chunk_len);
631 }
632 
633 /**
634  * \internal
635  *
636  * \brief Check state for errors, warnings and add any as events
637  *
638  * \param s state
639  * \param dir direction: STREAM_TOSERVER or STREAM_TOCLIENT
640  */
641 static void HTPHandleError(HtpState *s, const uint8_t dir)
642 {
643  if (s == NULL || s->conn == NULL || s->htp_messages_count >= HTP_MAX_MESSAGES) {
644  // ignore further messages
645  return;
646  }
647 
648  htp_log_t *log = htp_conn_next_log(s->conn);
649  while (log != NULL) {
650  char *msg = htp_log_message(log);
651  if (msg == NULL) {
652  htp_log_free(log);
653  log = htp_conn_next_log(s->conn);
654  continue;
655  }
656 
657  SCLogDebug("message %s", msg);
658 
659  htp_log_code_t id = htp_log_code(log);
660  if (id != HTP_LOG_CODE_UNKNOWN && id != HTP_LOG_CODE_ERROR) {
661  HTPSetEvent(s, NULL, dir, (uint8_t)id);
662  }
663  htp_free_cstring(msg);
664  htp_log_free(log);
665  s->htp_messages_count++;
667  // only once per HtpState
668  HTPSetEvent(s, NULL, dir, HTTP_DECODER_EVENT_TOO_MANY_WARNINGS);
669  // too noisy in fuzzing
670  // DEBUG_VALIDATE_BUG_ON("Too many libhtp messages");
671  break;
672  }
673  log = htp_conn_next_log(s->conn);
674  }
675  SCLogDebug("s->htp_messages_count %u", s->htp_messages_count);
676 }
677 
678 static inline void HTPErrorCheckTxRequestFlags(HtpState *s, const htp_tx_t *tx)
679 {
680 #ifdef DEBUG
681  BUG_ON(s == NULL || tx == NULL);
682 #endif
683  if (htp_tx_flags(tx) & (HTP_FLAGS_REQUEST_INVALID_T_E | HTP_FLAGS_REQUEST_INVALID_C_L |
684  HTP_FLAGS_HOST_MISSING | HTP_FLAGS_HOST_AMBIGUOUS |
685  HTP_FLAGS_HOSTU_INVALID | HTP_FLAGS_HOSTH_INVALID)) {
686  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
687 
688  if (htp_tx_flags(tx) & HTP_FLAGS_REQUEST_INVALID_T_E)
689  HTPSetEvent(s, htud, STREAM_TOSERVER,
690  HTP_LOG_CODE_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST);
691  if (htp_tx_flags(tx) & HTP_FLAGS_REQUEST_INVALID_C_L)
692  HTPSetEvent(
693  s, htud, STREAM_TOSERVER, HTP_LOG_CODE_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST);
694  if (htp_tx_flags(tx) & HTP_FLAGS_HOST_MISSING)
695  HTPSetEvent(s, htud, STREAM_TOSERVER, HTP_LOG_CODE_MISSING_HOST_HEADER);
696  if (htp_tx_flags(tx) & HTP_FLAGS_HOST_AMBIGUOUS)
697  HTPSetEvent(s, htud, STREAM_TOSERVER, HTP_LOG_CODE_HOST_HEADER_AMBIGUOUS);
698  if (htp_tx_flags(tx) & HTP_FLAGS_HOSTU_INVALID)
699  HTPSetEvent(s, htud, STREAM_TOSERVER, HTP_LOG_CODE_URI_HOST_INVALID);
700  if (htp_tx_flags(tx) & HTP_FLAGS_HOSTH_INVALID)
701  HTPSetEvent(s, htud, STREAM_TOSERVER, HTP_LOG_CODE_HEADER_HOST_INVALID);
702  }
703  if (htp_tx_request_auth_type(tx) == HTP_AUTH_TYPE_UNRECOGNIZED) {
704  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
705  HTPSetEvent(s, htud, STREAM_TOSERVER, HTP_LOG_CODE_AUTH_UNRECOGNIZED);
706  }
707  if (htp_tx_is_protocol_0_9(tx) && htp_tx_request_method_number(tx) == HTP_METHOD_UNKNOWN &&
708  (htp_tx_request_protocol_number(tx) == HTP_PROTOCOL_INVALID ||
709  htp_tx_request_protocol_number(tx) == HTP_PROTOCOL_UNKNOWN)) {
710  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
711  HTPSetEvent(s, htud, STREAM_TOSERVER, HTP_LOG_CODE_REQUEST_LINE_INVALID);
712  }
713 }
714 
715 static int Setup(Flow *f, HtpState *hstate)
716 {
717  /* store flow ref in state so callbacks can access it */
718  hstate->f = f;
719 
720  HTPCfgRec *htp_cfg_rec = &cfglist;
721  htp_cfg_t *htp = cfglist.cfg; /* Default to the global HTP config */
722  void *user_data = NULL;
723 
724  if (FLOW_IS_IPV4(f)) {
725  SCLogDebug("Looking up HTP config for ipv4 %08x", *GET_IPV4_DST_ADDR_PTR(f));
727  &cfgtree.ipv4, (uint8_t *)GET_IPV4_DST_ADDR_PTR(f), &user_data);
728  }
729  else if (FLOW_IS_IPV6(f)) {
730  SCLogDebug("Looking up HTP config for ipv6");
731  (void)SCRadix6TreeFindBestMatch(&cfgtree.ipv6, (uint8_t *)GET_IPV6_DST_ADDR(f), &user_data);
732  }
733  else {
734  SCLogError("unknown address family, bug!");
735  goto error;
736  }
737 
738  if (user_data != NULL) {
739  htp_cfg_rec = user_data;
740  htp = htp_cfg_rec->cfg;
741  SCLogDebug("LIBHTP using config: %p", htp);
742  } else {
743  SCLogDebug("Using default HTP config: %p", htp);
744  }
745 
746  if (NULL == htp) {
747 #ifdef DEBUG_VALIDATION
748  BUG_ON(htp == NULL);
749 #endif
750  /* should never happen if HTPConfigure is properly invoked */
751  goto error;
752  }
753 
754  hstate->connp = htp_connp_create(htp);
755  if (hstate->connp == NULL) {
756  goto error;
757  }
758 
759  hstate->conn = (htp_conn_t *)htp_connp_connection(hstate->connp);
760 
761  htp_connp_set_user_data(hstate->connp, (void *)hstate);
762  hstate->cfg = htp_cfg_rec;
763 
764  SCLogDebug("New hstate->connp %p", hstate->connp);
765 
766  struct timeval tv = { SCTIME_SECS(f->startts), SCTIME_USECS(f->startts) };
767  htp_connp_open(hstate->connp, NULL, f->sp, NULL, f->dp, &tv);
768 
770  htp_cfg_rec->request.inspect_min_size);
772  htp_cfg_rec->response.inspect_min_size);
773  return 0;
774 error:
775  return -1;
776 }
777 
778 /**
779  * \brief Function to handle the reassembled data from client and feed it to
780  * the HTP library to process it.
781  *
782  * \param flow Pointer to the flow the data belong to
783  * \param htp_state Pointer the state in which the parsed value to be stored
784  * \param pstate Application layer parser state for this session
785  *
786  * \retval On success returns 1 or on failure returns -1.
787  */
788 static AppLayerResult HTPHandleRequestData(Flow *f, void *htp_state, AppLayerParserState *pstate,
789  StreamSlice stream_slice, void *local_data)
790 {
791  SCEnter();
792  int ret = 0;
793  HtpState *hstate = (HtpState *)htp_state;
794 
795  /* On the first invocation, create the connection parser structure to
796  * be used by HTP library. This is looked up via IP in the radix
797  * tree. Failing that, the default HTP config is used.
798  */
799  if (NULL == hstate->conn) {
800  if (Setup(f, hstate) != 0) {
802  }
803  }
804  DEBUG_VALIDATE_BUG_ON(hstate->connp == NULL);
805  hstate->slice = &stream_slice;
806 
807  const uint8_t *input = StreamSliceGetData(&stream_slice);
808  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
809 
810  struct timeval ts = { SCTIME_SECS(f->startts), SCTIME_USECS(f->startts) };
811  /* pass the new data to the htp parser */
812  if (input_len > 0) {
813  const int r = htp_connp_request_data(hstate->connp, &ts, input, input_len);
814  switch (r) {
815  case HTP_STREAM_STATE_ERROR:
816  ret = -1;
817  break;
818  default:
819  break;
820  }
821  HTPHandleError(hstate, STREAM_TOSERVER);
822  }
823 
824  /* if the TCP connection is closed, then close the HTTP connection */
826  !(hstate->flags & HTP_FLAG_STATE_CLOSED_TS))
827  {
828  htp_connp_request_close(hstate->connp, &ts);
829  hstate->flags |= HTP_FLAG_STATE_CLOSED_TS;
830  SCLogDebug("stream eof encountered, closing htp handle for ts");
831  }
832 
833  SCLogDebug("hstate->connp %p", hstate->connp);
834  hstate->slice = NULL;
835 
836  if (ret < 0) {
838  }
840 }
841 
842 /**
843  * \brief Function to handle the reassembled data from server and feed it to
844  * the HTP library to process it.
845  *
846  * \param flow Pointer to the flow the data belong to
847  * \param htp_state Pointer the state in which the parsed value to be stored
848  * \param pstate Application layer parser state for this session
849  * \param input Pointer the received HTTP server data
850  * \param input_len Length in bytes of the received data
851  * \param output Pointer to the output (not used in this function)
852  *
853  * \retval On success returns 1 or on failure returns -1
854  */
855 static AppLayerResult HTPHandleResponseData(Flow *f, void *htp_state, AppLayerParserState *pstate,
856  StreamSlice stream_slice, void *local_data)
857 {
858  SCEnter();
859  int ret = 0;
860  HtpState *hstate = (HtpState *)htp_state;
861 
862  const uint8_t *input = StreamSliceGetData(&stream_slice);
863  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
864 
865  /* On the first invocation, create the connection parser structure to
866  * be used by HTP library. This is looked up via IP in the radix
867  * tree. Failing that, the default HTP config is used.
868  */
869  if (NULL == hstate->conn) {
870  if (Setup(f, hstate) != 0) {
872  }
873  }
874  DEBUG_VALIDATE_BUG_ON(hstate->connp == NULL);
875  hstate->slice = &stream_slice;
876 
877  struct timeval ts = { SCTIME_SECS(f->startts), SCTIME_USECS(f->startts) };
878  const htp_tx_t *tx = NULL;
879  uint32_t consumed = 0;
880  if (input_len > 0) {
881  const int r = htp_connp_response_data(hstate->connp, &ts, input, input_len);
882  switch (r) {
883  case HTP_STREAM_STATE_ERROR:
884  ret = -1;
885  break;
886  case HTP_STREAM_STATE_TUNNEL:
887  tx = htp_connp_get_response_tx(hstate->connp);
888  if (tx != NULL && htp_tx_response_status_number(tx) == 101) {
889  const htp_header_t *h = htp_tx_response_header(tx, "Upgrade");
890  if (h == NULL) {
891  break;
892  }
893  uint16_t dp = 0;
894  if (htp_tx_request_port_number(tx) != -1) {
895  dp = (uint16_t)htp_tx_request_port_number(tx);
896  }
897  consumed = (uint32_t)htp_connp_response_data_consumed(hstate->connp);
898  if (bstr_cmp_c(htp_header_value(h), "h2c") == 0) {
900  // if HTTP2 is disabled, keep the HTP_STREAM_STATE_TUNNEL mode
901  break;
902  }
903  hstate->slice = NULL;
904  if (!AppLayerRequestProtocolChange(hstate->f, dp, ALPROTO_HTTP2)) {
905  HTPSetEvent(hstate, NULL, STREAM_TOCLIENT,
907  }
908  // During HTTP2 upgrade, we may consume the HTTP1 part of the data
909  // and we need to parser the remaining part with HTTP2
910  if (consumed > 0 && consumed < input_len) {
911  SCReturnStruct(APP_LAYER_INCOMPLETE(consumed, input_len - consumed));
912  }
914  } else if (bstr_cmp_c_nocase(htp_header_value(h), "WebSocket")) {
916  // if WS is disabled, keep the HTP_STREAM_STATE_TUNNEL mode
917  break;
918  }
919  hstate->slice = NULL;
921  HTPSetEvent(hstate, NULL, STREAM_TOCLIENT,
923  }
924  // During WS upgrade, we may consume the HTTP1 part of the data
925  // and we need to parser the remaining part with WS
926  if (consumed > 0 && consumed < input_len) {
927  SCReturnStruct(APP_LAYER_INCOMPLETE(consumed, input_len - consumed));
928  }
930  }
931  }
932  break;
933  default:
934  break;
935  }
936  HTPHandleError(hstate, STREAM_TOCLIENT);
937  }
938 
939  /* if we the TCP connection is closed, then close the HTTP connection */
941  !(hstate->flags & HTP_FLAG_STATE_CLOSED_TC))
942  {
943  htp_connp_close(hstate->connp, &ts);
944  hstate->flags |= HTP_FLAG_STATE_CLOSED_TC;
945  }
946 
947  SCLogDebug("hstate->connp %p", hstate->connp);
948  hstate->slice = NULL;
949 
950  if (ret < 0) {
952  }
954 }
955 
956 /**
957  * \param name /Lowercase/ version of the variable name
958  */
959 static int HTTPParseContentDispositionHeader(const uint8_t *name, size_t name_len,
960  const uint8_t *data, size_t len, uint8_t const **retptr, size_t *retlen)
961 {
962 #ifdef PRINT
963  printf("DATA START: \n");
964  PrintRawDataFp(stdout, data, len);
965  printf("DATA END: \n");
966 #endif
967  size_t x;
968  int quote = 0;
969 
970  for (x = 0; x < len; x++) {
971  if (!(isspace(data[x])))
972  break;
973  }
974 
975  if (x >= len)
976  return 0;
977 
978  const uint8_t *line = data + x;
979  size_t line_len = len-x;
980  size_t offset = 0;
981 #ifdef PRINT
982  printf("LINE START: \n");
983  PrintRawDataFp(stdout, line, line_len);
984  printf("LINE END: \n");
985 #endif
986  for (x = 0 ; x < line_len; x++) {
987  if (x > 0) {
988  if (line[x - 1] != '\\' && line[x] == '\"') {
989  quote++;
990  }
991 
992  if (((line[x - 1] != '\\' && line[x] == ';') || ((x + 1) == line_len)) && (quote == 0 || quote % 2 == 0)) {
993  const uint8_t *token = line + offset;
994  size_t token_len = x - offset;
995 
996  if ((x + 1) == line_len) {
997  token_len++;
998  }
999 
1000  offset = x + 1;
1001 
1002  while (offset < line_len && isspace(line[offset])) {
1003  x++;
1004  offset++;
1005  }
1006 #ifdef PRINT
1007  printf("TOKEN START: \n");
1008  PrintRawDataFp(stdout, token, token_len);
1009  printf("TOKEN END: \n");
1010 #endif
1011  if (token_len > name_len) {
1012  if (name == NULL || SCMemcmpLowercase(name, token, name_len) == 0) {
1013  const uint8_t *value = token + name_len;
1014  size_t value_len = token_len - name_len;
1015 
1016  if (value[0] == '\"') {
1017  value++;
1018  value_len--;
1019  }
1020  if (value[value_len-1] == '\"') {
1021  value_len--;
1022  }
1023 #ifdef PRINT
1024  printf("VALUE START: \n");
1025  PrintRawDataFp(stdout, value, value_len);
1026  printf("VALUE END: \n");
1027 #endif
1028  *retptr = value;
1029  *retlen = value_len;
1030  return 1;
1031  }
1032  }
1033  }
1034  }
1035  }
1036 
1037  return 0;
1038 }
1039 
1040 /**
1041  * \brief setup multipart parsing: extract boundary and store it
1042  *
1043  * \param d HTTP transaction
1044  * \param htud transaction userdata
1045  *
1046  * \retval 1 ok, multipart set up
1047  * \retval 0 ok, not multipart though
1048  * \retval -1 error: problem with the boundary
1049  *
1050  * If the request contains a multipart message, this function will
1051  * set the HTP_BOUNDARY_SET in the transaction.
1052  */
1053 static int HtpRequestBodySetupMultipart(const htp_tx_t *tx, HtpTxUserData *htud)
1054 {
1055  const htp_header_t *h = htp_tx_request_header(tx, "Content-Type");
1056  if (h != NULL && htp_header_value_len(h) > 0) {
1057  htud->mime_state =
1058  SCMimeStateInit(htp_header_value_ptr(h), (uint32_t)htp_header_value_len(h));
1059  if (htud->mime_state) {
1060  htud->tsflags |= HTP_BOUNDARY_SET;
1061  SCReturnInt(1);
1062  }
1063  }
1064  SCReturnInt(0);
1065 }
1066 
1067 /**
1068  * \brief Create a single buffer from the HtpBodyChunks in our list
1069  *
1070  * \param htud transaction user data
1071  * \param chunks_buffers pointer to pass back the buffer to the caller
1072  * \param chunks_buffer_len pointer to pass back the buffer length to the caller
1073  */
1074 static void HtpRequestBodyReassemble(HtpTxUserData *htud,
1075  const uint8_t **chunks_buffer, uint32_t *chunks_buffer_len)
1076 {
1078  chunks_buffer, chunks_buffer_len,
1079  htud->request_body.body_parsed);
1080 }
1081 
1082 static void FlagDetectStateNewFile(HtpTxUserData *tx, int dir)
1083 {
1084  SCEnter();
1085  if (tx && tx->tx_data.de_state) {
1086  if (dir == STREAM_TOSERVER) {
1087  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set");
1088  tx->tx_data.de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW;
1089  } else if (dir == STREAM_TOCLIENT) {
1090  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set");
1091  tx->tx_data.de_state->dir_state[1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW;
1092  }
1093  }
1094 }
1095 
1096 static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, const void *tx,
1097  const uint8_t *chunks_buffer, uint32_t chunks_buffer_len, bool eof)
1098 {
1099 #ifdef PRINT
1100  printf("CHUNK START: \n");
1101  PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
1102  printf("CHUNK END: \n");
1103 #endif
1104 
1105  // libhtp will not call us back too late
1106  // should libhtp send a callback eof for 0 chunked ?
1108  STREAM_TOSERVER) >= HTP_REQUEST_PROGRESS_COMPLETE);
1109 
1110  const uint8_t *cur_buf = chunks_buffer;
1111  uint32_t cur_buf_len = chunks_buffer_len;
1112 
1113  if (eof) {
1114  // abrupt end of connection
1115  if (htud->tsflags & HTP_FILENAME_SET && !(htud->tsflags & HTP_DONTSTORE)) {
1116  /* we currently only handle multipart for ts. When we support it for tc,
1117  * we will need to supply right direction */
1118  HTPFileClose(htud, cur_buf, cur_buf_len, FILE_TRUNCATED, STREAM_TOSERVER);
1119  }
1120  htud->tsflags &= ~HTP_FILENAME_SET;
1121  goto end;
1122  }
1123 
1124  uint32_t consumed;
1125  uint32_t warnings;
1126  int result = 0;
1127  const uint8_t *filename = NULL;
1128  uint16_t filename_len = 0;
1129 
1130  // keep parsing mime and use callbacks when needed
1131  while (cur_buf_len > 0) {
1132  MimeParserResult r =
1133  SCMimeParse(htud->mime_state, cur_buf, cur_buf_len, &consumed, &warnings);
1134  DEBUG_VALIDATE_BUG_ON(consumed > cur_buf_len);
1135  htud->request_body.body_parsed += consumed;
1136  if (warnings) {
1137  if (warnings & MIME_EVENT_FLAG_INVALID_HEADER) {
1138  HTPSetEvent(
1139  hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER);
1140  }
1141  if (warnings & MIME_EVENT_FLAG_NO_FILEDATA) {
1142  HTPSetEvent(
1143  hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA);
1144  }
1145  }
1146  switch (r) {
1147  case MimeNeedsMore:
1148  // there is not enough data, wait for more next time
1149  goto end;
1150  case MimeFileOpen:
1151  // get filename owned by mime state
1152  SCMimeStateGetFilename(htud->mime_state, &filename, &filename_len);
1153  if (filename_len > 0) {
1154  htud->tsflags |= HTP_FILENAME_SET;
1155  htud->tsflags &= ~HTP_DONTSTORE;
1156  result = HTPFileOpen(
1157  hstate, htud, filename, filename_len, NULL, 0, STREAM_TOSERVER);
1158  if (result == -1) {
1159  goto end;
1160  } else if (result == -2) {
1161  htud->tsflags |= HTP_DONTSTORE;
1162  }
1163  FlagDetectStateNewFile(htud, STREAM_TOSERVER);
1164  }
1165  break;
1166  case MimeFileChunk:
1167  if (htud->tsflags & HTP_FILENAME_SET && !(htud->tsflags & HTP_DONTSTORE)) {
1168  result = HTPFileStoreChunk(htud, cur_buf, consumed, STREAM_TOSERVER);
1169  if (result == -1) {
1170  goto end;
1171  } else if (result == -2) {
1172  /* we know for sure we're not storing the file */
1173  htud->tsflags |= HTP_DONTSTORE;
1174  }
1175  }
1176  break;
1177  case MimeFileClose:
1178  if (htud->tsflags & HTP_FILENAME_SET && !(htud->tsflags & HTP_DONTSTORE)) {
1179  uint32_t lastsize = consumed;
1180  if (lastsize > 0 && cur_buf[lastsize - 1] == '\n') {
1181  lastsize--;
1182  if (lastsize > 0 && cur_buf[lastsize - 1] == '\r') {
1183  lastsize--;
1184  }
1185  }
1186  HTPFileClose(htud, cur_buf, lastsize, 0, STREAM_TOSERVER);
1187  }
1188  htud->tsflags &= ~HTP_FILENAME_SET;
1189  break;
1190  }
1191  cur_buf += consumed;
1192  cur_buf_len -= consumed;
1193  }
1194 
1195 end:
1196  SCLogDebug("htud->request_body.body_parsed %"PRIu64, htud->request_body.body_parsed);
1197  return 0;
1198 }
1199 
1200 /** \internal
1201  * \brief Handle POST or PUT, no multipart body data
1202  */
1203 static int HtpRequestBodyHandlePOSTorPUT(HtpState *hstate, HtpTxUserData *htud, const htp_tx_t *tx,
1204  const uint8_t *data, uint32_t data_len)
1205 {
1206  int result = 0;
1207 
1208  /* see if we need to open the file */
1209  if (!(htud->tsflags & HTP_FILENAME_SET))
1210  {
1211  uint8_t *filename = NULL;
1212  size_t filename_len = 0;
1213 
1214  /* get the name */
1215  if (htp_uri_path(htp_tx_parsed_uri(tx)) != NULL) {
1216  filename = (uint8_t *)bstr_ptr(htp_uri_path(htp_tx_parsed_uri(tx)));
1217  filename_len = bstr_len(htp_uri_path(htp_tx_parsed_uri(tx)));
1218  }
1219 
1220  if (filename != NULL) {
1221  if (filename_len > SC_FILENAME_MAX) {
1222  // explicitly truncate the file name if too long
1223  filename_len = SC_FILENAME_MAX;
1224  HTPSetEvent(hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG);
1225  }
1226  result = HTPFileOpen(hstate, htud, filename, (uint16_t)filename_len, data, data_len,
1227  STREAM_TOSERVER);
1228  if (result == -1) {
1229  goto end;
1230  } else if (result == -2) {
1231  htud->tsflags |= HTP_DONTSTORE;
1232  } else {
1233  FlagDetectStateNewFile(htud, STREAM_TOSERVER);
1234  htud->tsflags |= HTP_FILENAME_SET;
1235  htud->tsflags &= ~HTP_DONTSTORE;
1236  }
1237  }
1238  }
1239  else
1240  {
1241  /* otherwise, just store the data */
1242 
1243  if (!(htud->tsflags & HTP_DONTSTORE)) {
1244  result = HTPFileStoreChunk(htud, data, data_len, STREAM_TOSERVER);
1245  if (result == -1) {
1246  goto end;
1247  } else if (result == -2) {
1248  /* we know for sure we're not storing the file */
1249  htud->tsflags |= HTP_DONTSTORE;
1250  }
1251  }
1252  }
1253 
1254  return 0;
1255 end:
1256  return -1;
1257 }
1258 
1259 static int HtpResponseBodyHandle(HtpState *hstate, HtpTxUserData *htud, const htp_tx_t *tx,
1260  const uint8_t *data, uint32_t data_len)
1261 {
1262  SCEnter();
1263 
1264  int result = 0;
1265 
1266  /* see if we need to open the file
1267  * we check for htp_tx_response_line(tx) in case of junk
1268  * interpreted as body before response line
1269  */
1270  if (!(htud->tcflags & HTP_FILENAME_SET)) {
1271  SCLogDebug("setting up file name");
1272 
1273  const uint8_t *filename = NULL;
1274  size_t filename_len = 0;
1275 
1276  /* try Content-Disposition header first */
1277  const htp_header_t *h = htp_tx_response_header(tx, "Content-Disposition");
1278  if (h != NULL && htp_header_value_len(h) > 0) {
1279  /* parse content-disposition */
1280  (void)HTTPParseContentDispositionHeader((uint8_t *)"filename=", 9,
1281  htp_header_value_ptr(h), htp_header_value_len(h), &filename, &filename_len);
1282  }
1283 
1284  /* fall back to name from the uri */
1285  if (filename == NULL) {
1286  /* get the name */
1287  if (htp_uri_path(htp_tx_parsed_uri(tx)) != NULL) {
1288  filename = (uint8_t *)bstr_ptr(htp_uri_path(htp_tx_parsed_uri(tx)));
1289  filename_len = bstr_len(htp_uri_path(htp_tx_parsed_uri(tx)));
1290  }
1291  }
1292 
1293  if (filename != NULL) {
1294  // set range if present
1295  const htp_header_t *h_content_range = htp_tx_response_header(tx, "content-range");
1296  if (filename_len > SC_FILENAME_MAX) {
1297  // explicitly truncate the file name if too long
1298  filename_len = SC_FILENAME_MAX;
1299  HTPSetEvent(hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG);
1300  }
1301  if (h_content_range != NULL) {
1302  result = HTPFileOpenWithRange(hstate, htud, filename, (uint16_t)filename_len, data,
1303  data_len, tx, htp_header_value(h_content_range), htud);
1304  } else {
1305  result = HTPFileOpen(hstate, htud, filename, (uint16_t)filename_len, data, data_len,
1306  STREAM_TOCLIENT);
1307  }
1308  SCLogDebug("result %d", result);
1309  if (result == -1) {
1310  goto end;
1311  } else if (result == -2) {
1312  htud->tcflags |= HTP_DONTSTORE;
1313  } else {
1314  FlagDetectStateNewFile(htud, STREAM_TOCLIENT);
1315  htud->tcflags |= HTP_FILENAME_SET;
1316  htud->tcflags &= ~HTP_DONTSTORE;
1317  }
1318  }
1319  } else {
1320  /* otherwise, just store the data */
1321 
1322  if (!(htud->tcflags & HTP_DONTSTORE)) {
1323  result = HTPFileStoreChunk(htud, data, data_len, STREAM_TOCLIENT);
1324  SCLogDebug("result %d", result);
1325  if (result == -1) {
1326  goto end;
1327  } else if (result == -2) {
1328  /* we know for sure we're not storing the file */
1329  htud->tcflags |= HTP_DONTSTORE;
1330  }
1331  }
1332  }
1333 
1334  htud->response_body.body_parsed += data_len;
1335  return 0;
1336 end:
1337  return -1;
1338 }
1339 
1340 /**
1341  * \brief Function callback to append chunks for Requests
1342  * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
1343  * \retval int HTP_STATUS_OK if all goes well
1344  */
1345 static int HTPCallbackRequestBodyData(const htp_connp_t *connp, htp_tx_data_t *d)
1346 {
1347  SCEnter();
1348 
1349  const htp_tx_t *tx = htp_tx_data_tx(d);
1350 
1351  if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_REQUEST_BODY))
1352  SCReturnInt(HTP_STATUS_OK);
1353 
1354  if (htp_tx_data_is_empty(d))
1355  SCReturnInt(HTP_STATUS_OK);
1356 
1357 #ifdef PRINT
1358  printf("HTPBODY START: \n");
1359  PrintRawDataFp(stdout, (uint8_t *)htp_tx_data_data(d), htp_tx_data_len(d));
1360  printf("HTPBODY END: \n");
1361 #endif
1362 
1363  HtpState *hstate = htp_connp_user_data(connp);
1364  if (hstate == NULL) {
1365  SCReturnInt(HTP_STATUS_ERROR);
1366  }
1367 
1368  SCLogDebug("New request body data available at %p -> %p -> %p, bodylen "
1369  "%" PRIu32 "",
1370  hstate, d, htp_tx_data_data(d), (uint32_t)htp_tx_data_len(d));
1371 
1372  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1373  if (tx_ud == NULL) {
1374  SCReturnInt(HTP_STATUS_OK);
1375  }
1376  tx_ud->tx_data.updated_ts = true;
1377  SCTxDataUpdateFileFlags(&tx_ud->tx_data, hstate->state_data.file_flags);
1378 
1379  if (!tx_ud->response_body_init) {
1380  tx_ud->response_body_init = 1;
1381 
1382  if (htp_tx_request_method_number(tx) == HTP_METHOD_POST) {
1383  SCLogDebug("POST");
1384  int r = HtpRequestBodySetupMultipart(tx, tx_ud);
1385  if (r == 1) {
1387  } else if (r == 0) {
1389  SCLogDebug("not multipart");
1390  }
1391  } else if (htp_tx_request_method_number(tx) == HTP_METHOD_PUT) {
1393  }
1394  }
1395 
1396  /* see if we can get rid of htp body chunks */
1397  HtpBodyPrune(hstate, &tx_ud->request_body, STREAM_TOSERVER);
1398 
1399  SCLogDebug("tx_ud->request_body.content_len_so_far %"PRIu64, tx_ud->request_body.content_len_so_far);
1400  SCLogDebug("hstate->cfg->request.body_limit %u", hstate->cfg->request.body_limit);
1401 
1402  /* within limits, add the body chunk to the state. */
1403  if (AppLayerHtpCheckDepth(&hstate->cfg->request, &tx_ud->request_body, tx_ud->tsflags)) {
1404  uint32_t stream_depth = FileReassemblyDepth();
1405  uint32_t len = AppLayerHtpComputeChunkLength(tx_ud->request_body.content_len_so_far,
1406  hstate->cfg->request.body_limit, stream_depth, tx_ud->tsflags,
1407  (uint32_t)htp_tx_data_len(d));
1408  BUG_ON(len > (uint32_t)htp_tx_data_len(d));
1409 
1410  HtpBodyAppendChunk(&tx_ud->request_body, htp_tx_data_data(d), len);
1411 
1412  const uint8_t *chunks_buffer = NULL;
1413  uint32_t chunks_buffer_len = 0;
1414 
1416  /* multi-part body handling starts here */
1417  if (!(tx_ud->tsflags & HTP_BOUNDARY_SET)) {
1418  goto end;
1419  }
1420 
1421  HtpRequestBodyReassemble(tx_ud, &chunks_buffer, &chunks_buffer_len);
1422  if (chunks_buffer == NULL) {
1423  goto end;
1424  }
1425 #ifdef PRINT
1426  printf("REASSCHUNK START: \n");
1427  PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
1428  printf("REASSCHUNK END: \n");
1429 #endif
1430 
1431  HtpRequestBodyHandleMultipart(hstate, tx_ud, htp_tx_data_tx(d), chunks_buffer,
1432  chunks_buffer_len, (htp_tx_data_data(d) == NULL && htp_tx_data_len(d) == 0));
1433 
1434  } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_POST ||
1436  HtpRequestBodyHandlePOSTorPUT(
1437  hstate, tx_ud, htp_tx_data_tx(d), htp_tx_data_data(d), len);
1438  }
1439 
1440  } else {
1441  if (tx_ud->tsflags & HTP_FILENAME_SET) {
1442  SCLogDebug("closing file that was being stored");
1443  (void)HTPFileClose(tx_ud, NULL, 0, FILE_TRUNCATED, STREAM_TOSERVER);
1444  tx_ud->tsflags &= ~HTP_FILENAME_SET;
1445  }
1446  }
1447 
1448 end:
1449  if (hstate->conn != NULL) {
1450  SCLogDebug("checking body size %" PRIu64 " against inspect limit %u (cur %" PRIu64
1451  ", last %" PRIu64 ")",
1453  (uint64_t)htp_conn_request_data_counter(hstate->conn),
1454  hstate->last_request_data_stamp);
1455 
1456  /* if we reach the inspect_min_size we'll trigger inspection,
1457  * so make sure that raw stream is also inspected. Set the
1458  * data to be used to the amount of raw bytes we've seen to
1459  * get here. */
1460  if (tx_ud->request_body.body_inspected == 0 &&
1462  if ((uint64_t)htp_conn_request_data_counter(hstate->conn) >
1463  hstate->last_request_data_stamp &&
1464  (uint64_t)htp_conn_request_data_counter(hstate->conn) -
1465  hstate->last_request_data_stamp <
1466  (uint64_t)UINT_MAX) {
1467  uint32_t data_size =
1468  (uint32_t)((uint64_t)htp_conn_request_data_counter(hstate->conn) -
1469  hstate->last_request_data_stamp);
1470  const uint32_t depth = MIN(data_size, hstate->cfg->request.inspect_min_size);
1471 
1472  /* body still in progress, but due to min inspect size we need to inspect now */
1473  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, depth);
1474  AppLayerParserTriggerRawStreamInspection(hstate->f, STREAM_TOSERVER);
1475  }
1476  /* after the start of the body, disable the depth logic */
1477  } else if (tx_ud->request_body.body_inspected > 0) {
1478  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, 0);
1479  }
1480  }
1481  SCReturnInt(HTP_STATUS_OK);
1482 }
1483 
1484 /**
1485  * \brief Function callback to append chunks for Responses
1486  * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
1487  * \retval int HTP_STATUS_OK if all goes well
1488  */
1489 static int HTPCallbackResponseBodyData(const htp_connp_t *connp, htp_tx_data_t *d)
1490 {
1491  SCEnter();
1492 
1493  const htp_tx_t *tx = htp_tx_data_tx(d);
1494 
1495  if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_RESPONSE_BODY))
1496  SCReturnInt(HTP_STATUS_OK);
1497 
1498  if (htp_tx_data_is_empty(d))
1499  SCReturnInt(HTP_STATUS_OK);
1500 
1501  HtpState *hstate = htp_connp_user_data(connp);
1502  if (hstate == NULL) {
1503  SCReturnInt(HTP_STATUS_ERROR);
1504  }
1505 
1506  SCLogDebug("New response body data available at %p -> %p -> %p, bodylen "
1507  "%" PRIu32 "",
1508  hstate, d, htp_tx_data_data(d), (uint32_t)htp_tx_data_len(d));
1509 
1510  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1511  tx_ud->tx_data.updated_tc = true;
1512  SCTxDataUpdateFileFlags(&tx_ud->tx_data, hstate->state_data.file_flags);
1513  if (!tx_ud->request_body_init) {
1514  tx_ud->request_body_init = 1;
1515  }
1516 
1517  /* see if we can get rid of htp body chunks */
1518  HtpBodyPrune(hstate, &tx_ud->response_body, STREAM_TOCLIENT);
1519 
1520  SCLogDebug("tx_ud->response_body.content_len_so_far %"PRIu64, tx_ud->response_body.content_len_so_far);
1521  SCLogDebug("hstate->cfg->response.body_limit %u", hstate->cfg->response.body_limit);
1522 
1523  /* within limits, add the body chunk to the state. */
1524  if (AppLayerHtpCheckDepth(&hstate->cfg->response, &tx_ud->response_body, tx_ud->tcflags)) {
1525  uint32_t stream_depth = FileReassemblyDepth();
1526  uint32_t len = AppLayerHtpComputeChunkLength(tx_ud->response_body.content_len_so_far,
1527  hstate->cfg->response.body_limit, stream_depth, tx_ud->tcflags,
1528  (uint32_t)htp_tx_data_len(d));
1529  BUG_ON(len > (uint32_t)htp_tx_data_len(d));
1530 
1531  HtpBodyAppendChunk(&tx_ud->response_body, htp_tx_data_data(d), len);
1532 
1533  HtpResponseBodyHandle(hstate, tx_ud, htp_tx_data_tx(d), htp_tx_data_data(d), len);
1534  } else {
1535  if (tx_ud->tcflags & HTP_FILENAME_SET) {
1536  SCLogDebug("closing file that was being stored");
1537  (void)HTPFileClose(tx_ud, NULL, 0, FILE_TRUNCATED, STREAM_TOCLIENT);
1538  tx_ud->tcflags &= ~HTP_FILENAME_SET;
1539  }
1540  }
1541 
1542  if (hstate->conn != NULL) {
1543  SCLogDebug("checking body size %" PRIu64 " against inspect limit %u (cur %" PRIu64
1544  ", last %" PRIu64 ")",
1546  (uint64_t)htp_conn_request_data_counter(hstate->conn),
1547  hstate->last_response_data_stamp);
1548  /* if we reach the inspect_min_size we'll trigger inspection,
1549  * so make sure that raw stream is also inspected. Set the
1550  * data to be used to the amount of raw bytes we've seen to
1551  * get here. */
1552  if (tx_ud->response_body.body_inspected == 0 &&
1554  if ((uint64_t)htp_conn_response_data_counter(hstate->conn) >
1555  hstate->last_response_data_stamp &&
1556  (uint64_t)htp_conn_response_data_counter(hstate->conn) -
1557  hstate->last_response_data_stamp <
1558  (uint64_t)UINT_MAX) {
1559  uint32_t data_size =
1560  (uint32_t)((uint64_t)htp_conn_response_data_counter(hstate->conn) -
1561  hstate->last_response_data_stamp);
1562  const uint32_t depth = MIN(data_size, hstate->cfg->response.inspect_min_size);
1563 
1564  /* body still in progress, but due to min inspect size we need to inspect now */
1565  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, depth);
1566  AppLayerParserTriggerRawStreamInspection(hstate->f, STREAM_TOCLIENT);
1567  }
1568  /* after the start of the body, disable the depth logic */
1569  } else if (tx_ud->response_body.body_inspected > 0) {
1570  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, 0);
1571  }
1572  }
1573  SCReturnInt(HTP_STATUS_OK);
1574 }
1575 
1576 /**
1577  * \brief Print the stats of the HTTP requests
1578  */
1580 {
1581 #ifdef DEBUG
1582  SCEnter();
1583  SCMutexLock(&htp_state_mem_lock);
1584  SCLogDebug("http_state_memcnt %"PRIu64", http_state_memuse %"PRIu64"",
1585  htp_state_memcnt, htp_state_memuse);
1586  SCMutexUnlock(&htp_state_mem_lock);
1587  SCReturn;
1588 #endif
1589 }
1590 
1591 /** \brief Clears the HTTP server configuration memory used by HTP library */
1592 void HTPFreeConfig(void)
1593 {
1594  SCEnter();
1595 
1596  if (!AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "http") ||
1597  !AppLayerParserConfParserEnabled("tcp", "http"))
1598  {
1599  SCReturn;
1600  }
1601 
1602  HTPCfgRec *nextrec = cfglist.next;
1603  htp_config_destroy(cfglist.cfg);
1604  while (nextrec != NULL) {
1605  HTPCfgRec *htprec = nextrec;
1606  nextrec = nextrec->next;
1607 
1608  htp_config_destroy(htprec->cfg);
1609  SCFree(htprec);
1610  }
1611  SCRadix4TreeRelease(&cfgtree.ipv4, &htp_radix4_cfg);
1612  SCRadix6TreeRelease(&cfgtree.ipv6, &htp_radix6_cfg);
1613  SCReturn;
1614 }
1615 
1616 static int HTPCallbackRequestHasTrailer(const htp_connp_t *connp, htp_tx_t *tx)
1617 {
1618  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1619  htud->tx_data.updated_ts = true;
1620  htud->request_has_trailers = 1;
1621  return HTP_STATUS_OK;
1622 }
1623 
1624 static int HTPCallbackResponseHasTrailer(const htp_connp_t *connp, htp_tx_t *tx)
1625 {
1626  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1627  htud->tx_data.updated_tc = true;
1628  htud->response_has_trailers = 1;
1629  return HTP_STATUS_OK;
1630 }
1631 
1632 static void *HTPCallbackTxCreate(bool request)
1633 {
1634  HtpTxUserData *tx_ud = HTPCalloc(1, sizeof(HtpTxUserData));
1635  if (unlikely(tx_ud == NULL)) {
1636  return NULL;
1637  }
1638  if (request) {
1639  // each http tx may xfer files
1640  tx_ud->tx_data.file_tx = STREAM_TOSERVER | STREAM_TOCLIENT;
1641  } else {
1642  tx_ud->tx_data.file_tx = STREAM_TOCLIENT; // Toserver already missed.
1643  }
1644  return tx_ud;
1645 }
1646 
1647 /**\internal
1648  * \brief called at start of request
1649  * Set min inspect size.
1650  */
1651 static int HTPCallbackRequestStart(const htp_connp_t *connp, htp_tx_t *tx)
1652 {
1653  HtpState *hstate = htp_connp_user_data(connp);
1654  if (hstate == NULL) {
1655  SCReturnInt(HTP_STATUS_ERROR);
1656  }
1657 
1658  uint64_t consumed = hstate->slice->offset + htp_connp_request_data_consumed(hstate->connp);
1659  SCLogDebug("HTTP request start: data offset %" PRIu64 ", in_data_counter %" PRIu64, consumed,
1660  (uint64_t)htp_conn_request_data_counter(hstate->conn));
1661  /* app-layer-frame-documentation tag start: frame registration http request */
1663  hstate->f, hstate->slice, consumed, -1, 0, HTTP_FRAME_REQUEST);
1664  if (frame) {
1665  SCLogDebug("frame %p/%" PRIi64, frame, frame->id);
1666  hstate->request_frame_id = frame->id;
1667  AppLayerFrameSetTxId(frame, HtpGetActiveRequestTxID(hstate));
1668  }
1669  /* app-layer-frame-documentation tag end: frame registration http request */
1670 
1671  if (hstate->cfg)
1672  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER,
1673  hstate->cfg->request.inspect_min_size);
1674 
1675  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1676  tx_ud->tx_data.updated_ts = true;
1677  SCReturnInt(HTP_STATUS_OK);
1678 }
1679 
1680 /**\internal
1681  * \brief called at start of response
1682  * Set min inspect size.
1683  */
1684 static int HTPCallbackResponseStart(const htp_connp_t *connp, htp_tx_t *tx)
1685 {
1686  HtpState *hstate = htp_connp_user_data(connp);
1687  if (hstate == NULL) {
1688  SCReturnInt(HTP_STATUS_ERROR);
1689  }
1690 
1691  uint64_t consumed = hstate->slice->offset + htp_connp_response_data_consumed(hstate->connp);
1692  SCLogDebug("HTTP response start: data offset %" PRIu64 ", out_data_counter %" PRIu64, consumed,
1693  (uint64_t)htp_conn_response_data_counter(hstate->conn));
1694 
1696  hstate->f, hstate->slice, consumed, -1, 1, HTTP_FRAME_RESPONSE);
1697  if (frame) {
1698  SCLogDebug("frame %p/%" PRIi64, frame, frame->id);
1699  hstate->response_frame_id = frame->id;
1700  AppLayerFrameSetTxId(frame, HtpGetActiveResponseTxID(hstate));
1701  }
1702 
1703  if (hstate->cfg)
1704  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT,
1705  hstate->cfg->response.inspect_min_size);
1706 
1707  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1708  tx_ud->tx_data.updated_tc = true;
1709  SCReturnInt(HTP_STATUS_OK);
1710 }
1711 
1712 /**
1713  * \brief callback for request to store the recent incoming request
1714  into the recent_request_tx for the given htp state
1715  * \param connp pointer to the current connection parser which has the htp
1716  * state in it as user data
1717  */
1718 static int HTPCallbackRequestComplete(const htp_connp_t *connp, htp_tx_t *tx)
1719 {
1720  SCEnter();
1721 
1722  if (tx == NULL) {
1723  SCReturnInt(HTP_STATUS_ERROR);
1724  }
1725 
1726  HtpState *hstate = htp_connp_user_data(connp);
1727  if (hstate == NULL) {
1728  SCReturnInt(HTP_STATUS_ERROR);
1729  }
1730 
1731  const uint64_t abs_right_edge =
1732  hstate->slice->offset + htp_connp_request_data_consumed(hstate->connp);
1733 
1734  /* app-layer-frame-documentation tag start: updating frame->len */
1735  if (hstate->request_frame_id > 0) {
1736  Frame *frame = AppLayerFrameGetById(hstate->f, 0, hstate->request_frame_id);
1737  if (frame) {
1738  const uint64_t request_size = abs_right_edge - hstate->last_request_data_stamp;
1739 
1740  SCLogDebug("HTTP request complete: data offset %" PRIu64 ", request_size %" PRIu64,
1741  hstate->last_request_data_stamp, request_size);
1742  SCLogDebug("frame %p/%" PRIi64 " setting len to %" PRIu64, frame, frame->id,
1743  request_size);
1744  frame->len = (int64_t)request_size;
1745  /* app-layer-frame-documentation tag end: updating frame->len */
1746  }
1747  hstate->request_frame_id = 0;
1748  }
1749 
1750  SCLogDebug("transaction_cnt %"PRIu64", list_size %"PRIu64,
1751  hstate->transaction_cnt, HTPStateGetTxCnt(hstate));
1752 
1753  SCLogDebug("HTTP request completed");
1754 
1755  HTPErrorCheckTxRequestFlags(hstate, tx);
1756 
1757  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1758  htud->tx_data.updated_ts = true;
1759  if (htud->tsflags & HTP_FILENAME_SET) {
1760  SCLogDebug("closing file that was being stored");
1761  (void)HTPFileClose(htud, NULL, 0, 0, STREAM_TOSERVER);
1762  htud->tsflags &= ~HTP_FILENAME_SET;
1763  if (abs_right_edge < (uint64_t)UINT32_MAX) {
1765  hstate->f->protoctx, STREAM_TOSERVER, (uint32_t)abs_right_edge);
1766  }
1767  }
1768 
1769  hstate->last_request_data_stamp = abs_right_edge;
1770  /* request done, do raw reassembly now to inspect state and stream
1771  * at the same time. */
1772  AppLayerParserTriggerRawStreamInspection(hstate->f, STREAM_TOSERVER);
1773  SCReturnInt(HTP_STATUS_OK);
1774 }
1775 
1776 /**
1777  * \brief callback for response to remove the recent received requests
1778  from the recent_request_tx for the given htp state
1779  * \param connp pointer to the current connection parser which has the htp
1780  * state in it as user data
1781  */
1782 static int HTPCallbackResponseComplete(const htp_connp_t *connp, htp_tx_t *tx)
1783 {
1784  SCEnter();
1785 
1786  HtpState *hstate = htp_connp_user_data(connp);
1787  if (hstate == NULL) {
1788  SCReturnInt(HTP_STATUS_ERROR);
1789  }
1790 
1791  /* we have one whole transaction now */
1792  hstate->transaction_cnt++;
1793 
1794  const uint64_t abs_right_edge =
1795  hstate->slice->offset + htp_connp_response_data_consumed(hstate->connp);
1796 
1797  if (hstate->response_frame_id > 0) {
1798  Frame *frame = AppLayerFrameGetById(hstate->f, 1, hstate->response_frame_id);
1799  if (frame) {
1800  const uint64_t response_size = abs_right_edge - hstate->last_response_data_stamp;
1801 
1802  SCLogDebug("HTTP response complete: data offset %" PRIu64 ", response_size %" PRIu64,
1803  hstate->last_response_data_stamp, response_size);
1804  SCLogDebug("frame %p/%" PRIi64 " setting len to %" PRIu64, frame, frame->id,
1805  response_size);
1806  frame->len = (int64_t)response_size;
1807  }
1808  hstate->response_frame_id = 0;
1809  }
1810 
1811  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1812  htud->tx_data.updated_tc = true;
1813  if (htud->tcflags & HTP_FILENAME_SET) {
1814  SCLogDebug("closing file that was being stored");
1815  (void)HTPFileClose(htud, NULL, 0, 0, STREAM_TOCLIENT);
1816  htud->tcflags &= ~HTP_FILENAME_SET;
1817  }
1818 
1819  /* response done, do raw reassembly now to inspect state and stream
1820  * at the same time. */
1821  AppLayerParserTriggerRawStreamInspection(hstate->f, STREAM_TOCLIENT);
1822 
1823  /* handle HTTP CONNECT */
1824  if (htp_tx_request_method_number(tx) == HTP_METHOD_CONNECT) {
1825  /* any 2XX status response implies that the connection will become
1826  a tunnel immediately after this packet (RFC 7230, 3.3.3). */
1827  if ((htp_tx_response_status_number(tx) >= 200) &&
1828  (htp_tx_response_status_number(tx) < 300) && (hstate->transaction_cnt == 1)) {
1829  uint16_t dp = 0;
1830  if (htp_tx_request_port_number(tx) != -1) {
1831  dp = (uint16_t)htp_tx_request_port_number(tx);
1832  }
1833  // both ALPROTO_HTTP1 and ALPROTO_TLS are normal options
1834  if (!AppLayerRequestProtocolChange(hstate->f, dp, ALPROTO_UNKNOWN)) {
1835  HTPSetEvent(
1836  hstate, htud, STREAM_TOCLIENT, HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE);
1837  }
1838  }
1839  }
1840 
1841  hstate->last_response_data_stamp = abs_right_edge;
1842  SCReturnInt(HTP_STATUS_OK);
1843 }
1844 
1845 static int HTPCallbackRequestLine(const htp_connp_t *connp, htp_tx_t *tx)
1846 {
1847  HtpState *hstate = htp_connp_user_data(connp);
1848 
1849  if (htp_tx_flags(tx)) {
1850  HTPErrorCheckTxRequestFlags(hstate, tx);
1851  }
1852  return HTP_STATUS_OK;
1853 }
1854 
1855 static int HTPCallbackRequestHeaderData(const htp_connp_t *connp, htp_tx_data_t *tx_data)
1856 {
1857  void *ptmp;
1858  const htp_tx_t *tx = htp_tx_data_tx(tx_data);
1859  if (htp_tx_data_is_empty(tx_data) || tx == NULL)
1860  return HTP_STATUS_OK;
1861 
1862  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1864  tx_ud->request_headers_raw_len + htp_tx_data_len(tx_data));
1865  if (ptmp == NULL) {
1866  return HTP_STATUS_OK;
1867  }
1868  tx_ud->request_headers_raw = ptmp;
1869  tx_ud->tx_data.updated_ts = true;
1870 
1871  memcpy(tx_ud->request_headers_raw + tx_ud->request_headers_raw_len, htp_tx_data_data(tx_data),
1872  htp_tx_data_len(tx_data));
1873  tx_ud->request_headers_raw_len += htp_tx_data_len(tx_data);
1874 
1875  if (tx && htp_tx_flags(tx)) {
1876  HtpState *hstate = htp_connp_user_data(connp);
1877  HTPErrorCheckTxRequestFlags(hstate, tx);
1878  }
1879  return HTP_STATUS_OK;
1880 }
1881 
1882 static int HTPCallbackResponseHeaderData(const htp_connp_t *connp, htp_tx_data_t *tx_data)
1883 {
1884  void *ptmp;
1885  const htp_tx_t *tx = htp_tx_data_tx(tx_data);
1886  if (htp_tx_data_is_empty(tx_data) || tx == NULL)
1887  return HTP_STATUS_OK;
1888 
1889  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1890  tx_ud->tx_data.updated_tc = true;
1892  tx_ud->response_headers_raw_len + htp_tx_data_len(tx_data));
1893  if (ptmp == NULL) {
1894  return HTP_STATUS_OK;
1895  }
1896  tx_ud->response_headers_raw = ptmp;
1897 
1898  memcpy(tx_ud->response_headers_raw + tx_ud->response_headers_raw_len, htp_tx_data_data(tx_data),
1899  htp_tx_data_len(tx_data));
1900  tx_ud->response_headers_raw_len += htp_tx_data_len(tx_data);
1901 
1902  return HTP_STATUS_OK;
1903 }
1904 
1905 /*
1906  * We have a similar set function called HTPConfigSetDefaultsPhase1.
1907  */
1908 static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec)
1909 {
1910  htp_config_set_normalized_uri_include_all(cfg_prec->cfg, false);
1917 
1918  if (!g_disable_randomness) {
1920  } else {
1921  cfg_prec->randomize = 0;
1922  }
1924 
1925  htp_config_register_request_header_data(cfg_prec->cfg, HTPCallbackRequestHeaderData);
1926  htp_config_register_request_trailer_data(cfg_prec->cfg, HTPCallbackRequestHeaderData);
1927  htp_config_register_response_header_data(cfg_prec->cfg, HTPCallbackResponseHeaderData);
1928  htp_config_register_response_trailer_data(cfg_prec->cfg, HTPCallbackResponseHeaderData);
1929 
1930  htp_config_register_request_trailer(cfg_prec->cfg, HTPCallbackRequestHasTrailer);
1931  htp_config_register_response_trailer(cfg_prec->cfg, HTPCallbackResponseHasTrailer);
1932 
1933  htp_config_register_request_body_data(cfg_prec->cfg, HTPCallbackRequestBodyData);
1934  htp_config_register_response_body_data(cfg_prec->cfg, HTPCallbackResponseBodyData);
1935 
1936  htp_config_register_tx_create(cfg_prec->cfg, HTPCallbackTxCreate);
1937  htp_config_register_tx_destroy(cfg_prec->cfg, HtpTxUserDataFree);
1938 
1939  htp_config_register_request_start(cfg_prec->cfg, HTPCallbackRequestStart);
1940  htp_config_register_request_complete(cfg_prec->cfg, HTPCallbackRequestComplete);
1941 
1942  htp_config_register_response_start(cfg_prec->cfg, HTPCallbackResponseStart);
1943  htp_config_register_response_complete(cfg_prec->cfg, HTPCallbackResponseComplete);
1944 
1945  htp_config_set_parse_request_cookies(cfg_prec->cfg, 0);
1946  htp_config_set_allow_space_uri(cfg_prec->cfg, 1);
1947 
1948  /* don't convert + to space by default */
1949  htp_config_set_plusspace_decode(cfg_prec->cfg, 0);
1950  // enables request decompression
1951  htp_config_set_request_decompression(cfg_prec->cfg, 1);
1952  htp_config_set_lzma_layers(cfg_prec->cfg, HTP_CONFIG_DEFAULT_LZMA_LAYERS);
1953  htp_config_set_lzma_memlimit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_LZMA_MEMLIMIT);
1954  htp_config_set_compression_bomb_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_COMPRESSION_BOMB_LIMIT);
1955  htp_config_set_compression_time_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_COMPRESSION_TIME_LIMIT);
1956 #define HTP_CONFIG_DEFAULT_MAX_TX_LIMIT 512
1957  htp_config_set_max_tx(cfg_prec->cfg, HTP_CONFIG_DEFAULT_MAX_TX_LIMIT);
1958 #define HTP_CONFIG_DEFAULT_HEADERS_LIMIT 1024
1959  htp_config_set_number_headers_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_HEADERS_LIMIT);
1960  htp_config_set_field_limit(cfg_prec->cfg, (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT);
1961 }
1962 
1963 /* hack: htp random range code expects random values in range of 0-RAND_MAX,
1964  * but we can get both <0 and >RAND_MAX values from RandomGet
1965  */
1966 static int RandomGetWrap(void)
1967 {
1968  unsigned long r;
1969 
1970  do {
1971  r = RandomGet();
1972  } while(r >= ULONG_MAX - (ULONG_MAX % RAND_MAX));
1973 
1974  return r % RAND_MAX;
1975 }
1976 
1977 /*
1978  * We have this splitup so that in case double decoding has been enabled
1979  * for query and path, they would be called first on the callback queue,
1980  * before the callback set by Phase2() is called. We need this, since
1981  * the callback in Phase2() generates the normalized uri which utilizes
1982  * the query and path. */
1983 static void HTPConfigSetDefaultsPhase2(const char *name, HTPCfgRec *cfg_prec)
1984 {
1985  /* randomize inspection size if needed */
1986  if (cfg_prec->randomize) {
1987  int rdrange = cfg_prec->randomize_range;
1988 
1989  long int r = RandomGetWrap();
1990  cfg_prec->request.inspect_min_size += (int)(cfg_prec->request.inspect_min_size *
1991  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
1992 
1993  r = RandomGetWrap();
1994  cfg_prec->request.inspect_window += (int)(cfg_prec->request.inspect_window *
1995  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
1996  SCLogConfig("'%s' server has 'request-body-minimal-inspect-size' set to"
1997  " %u and 'request-body-inspect-window' set to %u after"
1998  " randomization.",
1999  name, cfg_prec->request.inspect_min_size, cfg_prec->request.inspect_window);
2000 
2001  r = RandomGetWrap();
2002  cfg_prec->response.inspect_min_size += (int)(cfg_prec->response.inspect_min_size *
2003  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
2004 
2005  r = RandomGetWrap();
2006  cfg_prec->response.inspect_window += (int)(cfg_prec->response.inspect_window *
2007  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
2008 
2009  SCLogConfig("'%s' server has 'response-body-minimal-inspect-size' set to"
2010  " %u and 'response-body-inspect-window' set to %u after"
2011  " randomization.",
2012  name, cfg_prec->response.inspect_min_size, cfg_prec->response.inspect_window);
2013  }
2014 
2015  htp_config_register_request_line(cfg_prec->cfg, HTPCallbackRequestLine);
2016 }
2017 
2018 static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, SCConfNode *s, struct HTPConfigTree *tree)
2019 {
2020  if (cfg_prec == NULL || s == NULL || tree == NULL)
2021  return;
2022 
2023  SCConfNode *p = NULL;
2024 
2025  /* Default Parameters */
2026  TAILQ_FOREACH (p, &s->head, next) {
2027  if (strcasecmp("address", p->name) == 0) {
2028  SCConfNode *pval;
2029  /* Addresses */
2030  TAILQ_FOREACH(pval, &p->head, next) {
2031  SCLogDebug("LIBHTP server %s: %s=%s", s->name, p->name, pval->val);
2032  /* IPV6 or IPV4? */
2033  if (strchr(pval->val, ':') != NULL) {
2034  SCLogDebug("LIBHTP adding ipv6 server %s at %s: %p",
2035  s->name, pval->val, cfg_prec->cfg);
2037  &tree->ipv6, &htp_radix6_cfg, pval->val, cfg_prec)) {
2038  SCLogWarning("LIBHTP failed to add ipv6 server %s, ignoring", pval->val);
2039  }
2040  } else {
2041  SCLogDebug("LIBHTP adding ipv4 server %s at %s: %p",
2042  s->name, pval->val, cfg_prec->cfg);
2044  &tree->ipv4, &htp_radix4_cfg, pval->val, cfg_prec)) {
2045  SCLogWarning("LIBHTP failed to add ipv4 server %s, ignoring", pval->val);
2046  }
2047  } /* else - if (strchr(pval->val, ':') != NULL) */
2048  } /* TAILQ_FOREACH(pval, &p->head, next) */
2049 
2050  } else if (strcasecmp("personality", p->name) == 0) {
2051  /* Personalities */
2052  int personality = HTPLookupPersonality(p->val);
2053  SCLogDebug("LIBHTP default: %s = %s", p->name, p->val);
2054  SCLogDebug("LIBHTP default: %s = %s", p->name, p->val);
2055 
2056  if (personality >= 0) {
2057  SCLogDebug("LIBHTP default: %s=%s (%d)", p->name, p->val,
2058  personality);
2059  if (htp_config_set_server_personality(cfg_prec->cfg, personality) ==
2060  HTP_STATUS_ERROR) {
2061  SCLogWarning("LIBHTP Failed adding "
2062  "personality \"%s\", ignoring",
2063  p->val);
2064  } else {
2065  SCLogDebug("LIBHTP personality set to %s",
2066  HTPLookupPersonalityString(personality));
2067  }
2068 
2069  /* The IDS personality by default converts the path (and due to
2070  * our query string callback also the query string) to lowercase.
2071  * Signatures do not expect this, so override it. */
2072  htp_config_set_convert_lowercase(cfg_prec->cfg, 0);
2073  } else {
2074  SCLogWarning("LIBHTP Unknown personality "
2075  "\"%s\", ignoring",
2076  p->val);
2077  continue;
2078  }
2079 
2080  } else if (strcasecmp("request-body-limit", p->name) == 0 ||
2081  strcasecmp("request_body_limit", p->name) == 0) {
2082  if (ParseSizeStringU32(p->val, &cfg_prec->request.body_limit) < 0) {
2083  SCLogError("Error parsing request-body-limit "
2084  "from conf file - %s. Killing engine",
2085  p->val);
2086  exit(EXIT_FAILURE);
2087  }
2088 
2089  } else if (strcasecmp("response-body-limit", p->name) == 0) {
2090  if (ParseSizeStringU32(p->val, &cfg_prec->response.body_limit) < 0) {
2091  SCLogError("Error parsing response-body-limit "
2092  "from conf file - %s. Killing engine",
2093  p->val);
2094  exit(EXIT_FAILURE);
2095  }
2096 
2097  } else if (strcasecmp("request-body-minimal-inspect-size", p->name) == 0) {
2098  if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_min_size) < 0) {
2099  SCLogError("Error parsing request-body-minimal-inspect-size "
2100  "from conf file - %s. Killing engine",
2101  p->val);
2102  exit(EXIT_FAILURE);
2103  }
2104 
2105  } else if (strcasecmp("request-body-inspect-window", p->name) == 0) {
2106  if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_window) < 0) {
2107  SCLogError("Error parsing request-body-inspect-window "
2108  "from conf file - %s. Killing engine",
2109  p->val);
2110  exit(EXIT_FAILURE);
2111  }
2112 
2113  } else if (strcasecmp("double-decode-query", p->name) == 0) {
2114  htp_config_set_double_decode_normalized_query(cfg_prec->cfg, SCConfValIsTrue(p->val));
2115  } else if (strcasecmp("double-decode-path", p->name) == 0) {
2116  htp_config_set_double_decode_normalized_path(cfg_prec->cfg, SCConfValIsTrue(p->val));
2117  } else if (strcasecmp("response-body-minimal-inspect-size", p->name) == 0) {
2118  if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_min_size) < 0) {
2119  SCLogError("Error parsing response-body-minimal-inspect-size "
2120  "from conf file - %s. Killing engine",
2121  p->val);
2122  exit(EXIT_FAILURE);
2123  }
2124 
2125  } else if (strcasecmp("response-body-inspect-window", p->name) == 0) {
2126  if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_window) < 0) {
2127  SCLogError("Error parsing response-body-inspect-window "
2128  "from conf file - %s. Killing engine",
2129  p->val);
2130  exit(EXIT_FAILURE);
2131  }
2132 
2133  } else if (strcasecmp("response-body-decompress-layer-limit", p->name) == 0) {
2134  uint32_t value = 2;
2135  if (ParseSizeStringU32(p->val, &value) < 0) {
2136  SCLogError("Error parsing response-body-inspect-window "
2137  "from conf file - %s. Killing engine",
2138  p->val);
2139  exit(EXIT_FAILURE);
2140  }
2141  htp_config_set_decompression_layer_limit(cfg_prec->cfg, value);
2142  } else if (strcasecmp("path-convert-backslash-separators", p->name) == 0) {
2143  htp_config_set_backslash_convert_slashes(cfg_prec->cfg, SCConfValIsTrue(p->val));
2144  } else if (strcasecmp("path-bestfit-replacement-char", p->name) == 0) {
2145  if (strlen(p->val) == 1) {
2146  htp_config_set_bestfit_replacement_byte(cfg_prec->cfg, p->val[0]);
2147  } else {
2148  SCLogError("Invalid entry "
2149  "for libhtp param path-bestfit-replacement-char");
2150  }
2151  } else if (strcasecmp("path-convert-lowercase", p->name) == 0) {
2152  htp_config_set_convert_lowercase(cfg_prec->cfg, SCConfValIsTrue(p->val));
2153  } else if (strcasecmp("path-nul-encoded-terminates", p->name) == 0) {
2154  htp_config_set_nul_encoded_terminates(cfg_prec->cfg, SCConfValIsTrue(p->val));
2155  } else if (strcasecmp("path-nul-raw-terminates", p->name) == 0) {
2156  htp_config_set_nul_raw_terminates(cfg_prec->cfg, SCConfValIsTrue(p->val));
2157  } else if (strcasecmp("path-separators-compress", p->name) == 0) {
2158  htp_config_set_path_separators_compress(cfg_prec->cfg, SCConfValIsTrue(p->val));
2159  } else if (strcasecmp("path-separators-decode", p->name) == 0) {
2160  htp_config_set_path_separators_decode(cfg_prec->cfg, SCConfValIsTrue(p->val));
2161  } else if (strcasecmp("path-u-encoding-decode", p->name) == 0) {
2162  htp_config_set_u_encoding_decode(cfg_prec->cfg, SCConfValIsTrue(p->val));
2163  } else if (strcasecmp("path-url-encoding-invalid-handling", p->name) == 0) {
2164  enum htp_url_encoding_handling_t handling;
2165  if (strcasecmp(p->val, "preserve_percent") == 0) {
2166  handling = HTP_URL_ENCODING_HANDLING_PRESERVE_PERCENT;
2167  } else if (strcasecmp(p->val, "remove_percent") == 0) {
2168  handling = HTP_URL_ENCODING_HANDLING_REMOVE_PERCENT;
2169  } else if (strcasecmp(p->val, "decode_invalid") == 0) {
2170  handling = HTP_URL_ENCODING_HANDLING_PROCESS_INVALID;
2171  } else {
2172  SCLogError("Invalid entry "
2173  "for libhtp param path-url-encoding-invalid-handling");
2174  return;
2175  }
2176  htp_config_set_url_encoding_invalid_handling(cfg_prec->cfg, handling);
2177  } else if (strcasecmp("path-utf8-convert-bestfit", p->name) == 0) {
2178  htp_config_set_utf8_convert_bestfit(cfg_prec->cfg, SCConfValIsTrue(p->val));
2179  } else if (strcasecmp("uri-include-all", p->name) == 0) {
2180  htp_config_set_normalized_uri_include_all(cfg_prec->cfg, SCConfValIsTrue(p->val));
2181  SCLogDebug("uri-include-all %s", SCConfValIsTrue(p->val) ? "enabled" : "disabled");
2182  } else if (strcasecmp("query-plusspace-decode", p->name) == 0) {
2183  htp_config_set_plusspace_decode(cfg_prec->cfg, SCConfValIsTrue(p->val));
2184  } else if (strcasecmp("meta-field-limit", p->name) == 0) {
2185  uint32_t limit = 0;
2186  if (ParseSizeStringU32(p->val, &limit) < 0) {
2187  SCLogError("Error meta-field-limit "
2188  "from conf file - %s. Killing engine",
2189  p->val);
2190  exit(EXIT_FAILURE);
2191  }
2192  if (limit == 0) {
2193  FatalError("Error meta-field-limit "
2194  "from conf file cannot be 0. Killing engine");
2195  }
2196  /* set default soft-limit with our new hard limit */
2197  htp_config_set_field_limit(cfg_prec->cfg, (size_t)limit);
2198  } else if (strcasecmp("lzma-memlimit", p->name) == 0) {
2199  uint32_t limit = 0;
2200  if (ParseSizeStringU32(p->val, &limit) < 0) {
2201  FatalError("failed to parse 'lzma-memlimit' "
2202  "from conf file - %s.",
2203  p->val);
2204  }
2205  if (limit == 0) {
2206  FatalError("'lzma-memlimit' "
2207  "from conf file cannot be 0.");
2208  }
2209  /* set default soft-limit with our new hard limit */
2210  SCLogConfig("Setting HTTP LZMA memory limit to %"PRIu32" bytes", limit);
2211  htp_config_set_lzma_memlimit(cfg_prec->cfg, (size_t)limit);
2212  } else if (strcasecmp("lzma-enabled", p->name) == 0) {
2213  if (SCConfValIsTrue(p->val)) {
2214  htp_config_set_lzma_layers(cfg_prec->cfg, 1);
2215  } else if (!SCConfValIsFalse(p->val)) {
2216  int8_t limit;
2217  if (StringParseInt8(&limit, 10, 0, (const char *)p->val) < 0) {
2218  FatalError("failed to parse 'lzma-enabled' "
2219  "from conf file - %s.",
2220  p->val);
2221  }
2222  SCLogConfig("Setting HTTP LZMA decompression layers to %" PRIu32 "", (int)limit);
2223  htp_config_set_lzma_layers(cfg_prec->cfg, limit);
2224  }
2225  } else if (strcasecmp("compression-bomb-limit", p->name) == 0) {
2226  uint32_t limit = 0;
2227  if (ParseSizeStringU32(p->val, &limit) < 0) {
2228  FatalError("failed to parse 'compression-bomb-limit' "
2229  "from conf file - %s.",
2230  p->val);
2231  }
2232  if (limit == 0) {
2233  FatalError("'compression-bomb-limit' "
2234  "from conf file cannot be 0.");
2235  }
2236  /* set default soft-limit with our new hard limit */
2237  SCLogConfig("Setting HTTP compression bomb limit to %"PRIu32" bytes", limit);
2238  htp_config_set_compression_bomb_limit(cfg_prec->cfg, (size_t)limit);
2239  } else if (strcasecmp("decompression-time-limit", p->name) == 0) {
2240  uint32_t limit = 0;
2241  // between 1 usec and 1 second
2242  if (StringParseU32RangeCheck(&limit, 10, 0, p->val, 1, 1000000) < 0) {
2243  FatalError("failed to parse 'decompression-time-limit' "
2244  "from conf file - %s.",
2245  p->val);
2246  }
2247  SCLogConfig("Setting HTTP decompression time limit to %" PRIu32 " usec", limit);
2248  htp_config_set_compression_time_limit(cfg_prec->cfg, limit);
2249  } else if (strcasecmp("max-tx", p->name) == 0) {
2250  uint32_t limit = 0;
2251  if (ParseSizeStringU32(p->val, &limit) < 0) {
2252  FatalError("failed to parse 'max-tx' "
2253  "from conf file - %s.",
2254  p->val);
2255  }
2256  /* set default soft-limit with our new hard limit */
2257  SCLogConfig("Setting HTTP max-tx limit to %" PRIu32 " bytes", limit);
2258  htp_config_set_max_tx(cfg_prec->cfg, limit);
2259  } else if (strcasecmp("headers-limit", p->name) == 0) {
2260  uint32_t limit = 0;
2261  if (ParseSizeStringU32(p->val, &limit) < 0) {
2262  FatalError("failed to parse 'headers-limit' "
2263  "from conf file - %s.",
2264  p->val);
2265  }
2266  SCLogConfig("Setting HTTP headers limit to %" PRIu32, limit);
2267  htp_config_set_number_headers_limit(cfg_prec->cfg, limit);
2268  } else if (strcasecmp("randomize-inspection-sizes", p->name) == 0) {
2269  if (!g_disable_randomness) {
2270  cfg_prec->randomize = SCConfValIsTrue(p->val);
2271  }
2272  } else if (strcasecmp("randomize-inspection-range", p->name) == 0) {
2273  uint32_t range;
2274  if (StringParseU32RangeCheck(&range, 10, 0,
2275  (const char *)p->val, 0, 100) < 0) {
2276  SCLogError("Invalid value for randomize"
2277  "-inspection-range setting from conf file - \"%s\"."
2278  " It should be a valid integer less than or equal to 100."
2279  " Killing engine",
2280  p->val);
2281  exit(EXIT_FAILURE);
2282  }
2283  cfg_prec->randomize_range = range;
2284  } else if (strcasecmp("http-body-inline", p->name) == 0) {
2285  if (SCConfValIsTrue(p->val)) {
2286  cfg_prec->http_body_inline = 1;
2287  } else if (SCConfValIsFalse(p->val)) {
2288  cfg_prec->http_body_inline = 0;
2289  } else {
2290  if (strcmp("auto", p->val) != 0) {
2291  WarnInvalidConfEntry("http_body_inline", "%s", "auto");
2292  }
2293  if (EngineModeIsIPS()) {
2294  cfg_prec->http_body_inline = 1;
2295  } else {
2296  cfg_prec->http_body_inline = 0;
2297  }
2298  }
2299  } else if (strcasecmp("swf-decompression", p->name) == 0) {
2300  SCConfNode *pval;
2301 
2302  TAILQ_FOREACH(pval, &p->head, next) {
2303  if (strcasecmp("enabled", pval->name) == 0) {
2304  if (SCConfValIsTrue(pval->val)) {
2305  cfg_prec->swf_decompression_enabled = 1;
2306  } else if (SCConfValIsFalse(pval->val)) {
2307  cfg_prec->swf_decompression_enabled = 0;
2308  } else {
2309  WarnInvalidConfEntry("swf-decompression.enabled", "%s", "no");
2310  }
2311  } else if (strcasecmp("type", pval->name) == 0) {
2312  if (strcasecmp("no", pval->val) == 0) {
2314  } else if (strcasecmp("deflate", pval->val) == 0) {
2316  } else if (strcasecmp("lzma", pval->val) == 0) {
2318  } else if (strcasecmp("both", pval->val) == 0) {
2320  } else {
2321  SCLogError("Invalid entry for "
2322  "swf-decompression.type: %s - "
2323  "Killing engine",
2324  pval->val);
2325  exit(EXIT_FAILURE);
2326  }
2327  } else if (strcasecmp("compress-depth", pval->name) == 0) {
2328  if (ParseSizeStringU32(pval->val, &cfg_prec->swf_compress_depth) < 0) {
2329  SCLogError("Error parsing swf-decompression.compression-depth "
2330  "from conf file - %s. Killing engine",
2331  p->val);
2332  exit(EXIT_FAILURE);
2333  }
2334  } else if (strcasecmp("decompress-depth", pval->name) == 0) {
2335  if (ParseSizeStringU32(pval->val, &cfg_prec->swf_decompress_depth) < 0) {
2336  SCLogError("Error parsing swf-decompression.decompression-depth "
2337  "from conf file - %s. Killing engine",
2338  p->val);
2339  exit(EXIT_FAILURE);
2340  }
2341  } else {
2342  SCLogWarning("Ignoring unknown param %s", pval->name);
2343  }
2344  }
2345  } else {
2346  SCLogWarning("LIBHTP Ignoring unknown "
2347  "default config: %s",
2348  p->name);
2349  }
2350  } /* TAILQ_FOREACH(p, &default_config->head, next) */
2351 }
2352 
2353 void HTPConfigure(void)
2354 {
2355  SCEnter();
2356 
2357  cfglist.next = NULL;
2358 
2362 
2363  /* Default Config */
2364  cfglist.cfg = htp_config_create();
2365  if (NULL == cfglist.cfg) {
2366  FatalError("Failed to create HTP default config");
2367  }
2368  SCLogDebug("LIBHTP default config: %p", cfglist.cfg);
2369  HTPConfigSetDefaultsPhase1(&cfglist);
2370  if (SCConfGetNode("app-layer.protocols.http.libhtp") == NULL) {
2371  HTPConfigParseParameters(&cfglist, SCConfGetNode("libhtp.default-config"), &cfgtree);
2372  } else {
2373  HTPConfigParseParameters(&cfglist,
2374  SCConfGetNode("app-layer.protocols.http.libhtp.default-config"), &cfgtree);
2375  }
2376  HTPConfigSetDefaultsPhase2("default", &cfglist);
2377 
2378  HTPParseMemcap();
2379 
2380  /* Read server config and create a parser for each IP in radix tree */
2381  SCConfNode *server_config = SCConfGetNode("app-layer.protocols.http.libhtp.server-config");
2382  if (server_config == NULL) {
2383  server_config = SCConfGetNode("libhtp.server-config");
2384  if (server_config == NULL) {
2385  SCLogDebug("LIBHTP Configuring %p", server_config);
2386  SCReturn;
2387  }
2388  }
2389  SCLogDebug("LIBHTP Configuring %p", server_config);
2390 
2391  SCConfNode *si;
2392  /* Server Nodes */
2393  TAILQ_FOREACH(si, &server_config->head, next) {
2394  /* Need the named node, not the index */
2395  SCConfNode *s = TAILQ_FIRST(&si->head);
2396  if (NULL == s) {
2397  SCLogDebug("LIBHTP s NULL");
2398  continue;
2399  }
2400 
2401  SCLogDebug("LIBHTP server %s", s->name);
2402 
2403  HTPCfgRec *nextrec = cfglist.next;
2404  HTPCfgRec *htprec = SCCalloc(1, sizeof(HTPCfgRec));
2405  if (NULL == htprec)
2406  exit(EXIT_FAILURE);
2407 
2408  cfglist.next = htprec;
2409 
2410  cfglist.next->next = nextrec;
2411  cfglist.next->cfg = htp_config_create();
2412  if (NULL == cfglist.next->cfg) {
2413  FatalError("Failed to create HTP server config");
2414  }
2415 
2416  HTPConfigSetDefaultsPhase1(htprec);
2417  HTPConfigParseParameters(htprec, s, &cfgtree);
2418  HTPConfigSetDefaultsPhase2(s->name, htprec);
2419  }
2420 
2421  SCReturn;
2422 }
2423 
2425 {
2426 #ifdef DEBUG
2427  SCMutexLock(&htp_state_mem_lock);
2428  SCLogPerf("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
2429  SCMutexUnlock(&htp_state_mem_lock);
2430 #endif
2431 }
2432 
2433 /** \internal
2434  * \brief get files callback
2435  * \param state state ptr
2436  * \param direction flow direction
2437  * \retval files files ptr
2438  */
2439 static AppLayerGetFileState HTPGetTxFiles(void *txv, uint8_t direction)
2440 {
2441  AppLayerGetFileState files = { .fc = NULL, .cfg = &htp_sbcfg };
2442  htp_tx_t *tx = (htp_tx_t *)txv;
2443  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
2444  if (direction & STREAM_TOCLIENT) {
2445  files.fc = &tx_ud->files_tc;
2446  } else {
2447  files.fc = &tx_ud->files_ts;
2448  }
2449  return files;
2450 }
2451 
2452 static int HTPStateGetAlstateProgress(void *tx, uint8_t direction)
2453 {
2454  if (direction & STREAM_TOSERVER)
2455  return htp_tx_request_progress((htp_tx_t *)tx);
2456  else
2457  return htp_tx_response_progress((htp_tx_t *)tx);
2458 }
2459 
2460 static uint64_t HTPStateGetTxCnt(void *alstate)
2461 {
2462  HtpState *http_state = (HtpState *)alstate;
2463 
2464  if (http_state != NULL && http_state->connp != NULL) {
2465  const int64_t size = htp_connp_tx_size(http_state->connp);
2466  if (size < 0)
2467  return 0ULL;
2468  SCLogDebug("size %"PRIu64, size);
2469  return (uint64_t)size;
2470  } else {
2471  return 0ULL;
2472  }
2473 }
2474 
2475 static void *HTPStateGetTx(void *alstate, uint64_t tx_id)
2476 {
2477  HtpState *http_state = (HtpState *)alstate;
2478 
2479  if (http_state != NULL && http_state->connp != NULL)
2480  return (void *)htp_connp_tx(http_state->connp, tx_id);
2481  else
2482  return NULL;
2483 }
2484 
2485 static AppLayerGetTxIterTuple HTPGetTxIterator(const uint8_t ipproto, const AppProto alproto,
2486  void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state)
2487 {
2488  HtpState *http_state = (HtpState *)alstate;
2489  uint64_t size = HTPStateGetTxCnt(alstate);
2490  AppLayerGetTxIterTuple no_tuple = { NULL, 0, false };
2491  if (http_state) {
2492  while (state->un.u64 < size) {
2493  htp_tx_t *tx = htp_connp_tx_index(http_state->connp, state->un.u64);
2494  if (!tx) {
2495  return no_tuple;
2496  }
2497  uint64_t tx_id = htp_tx_index(tx);
2498  if (tx_id < min_tx_id) {
2499  state->un.u64++;
2500  continue;
2501  }
2502  AppLayerGetTxIterTuple tuple = {
2503  .tx_ptr = tx,
2504  .tx_id = tx_id,
2505  .has_next = state->un.u64 < size,
2506  };
2507  return tuple;
2508  }
2509  }
2510  return no_tuple;
2511 }
2512 
2513 void *HtpGetTxForH2(void *alstate)
2514 {
2515  // gets last transaction
2516  HtpState *http_state = (HtpState *)alstate;
2517  if (http_state != NULL && http_state->connp != NULL) {
2518  size_t txid = htp_connp_tx_size(http_state->connp);
2519  if (txid > 0) {
2520  return (void *)htp_connp_tx(http_state->connp, txid - 1);
2521  }
2522  }
2523  return NULL;
2524 }
2525 
2526 static int HTPStateGetEventInfo(
2527  const char *event_name, uint8_t *event_id, AppLayerEventType *event_type)
2528 {
2529  if (SCAppLayerGetEventIdByName(event_name, http_decoder_event_table, event_id) == 0) {
2530  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
2531  return 0;
2532  }
2533  return -1;
2534 }
2535 
2536 static int HTPStateGetEventInfoById(
2537  uint8_t event_id, const char **event_name, AppLayerEventType *event_type)
2538 {
2539  *event_name = SCMapEnumValueToName(event_id, http_decoder_event_table);
2540  if (*event_name == NULL) {
2541  SCLogError("event \"%d\" not present in "
2542  "http's enum map table.",
2543  event_id);
2544  /* this should be treated as fatal */
2545  return -1;
2546  }
2547 
2548  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
2549 
2550  return 0;
2551 }
2552 
2553 static AppLayerTxData *HTPGetTxData(void *vtx)
2554 {
2555  htp_tx_t *tx = (htp_tx_t *)vtx;
2556  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
2557  return &tx_ud->tx_data;
2558 }
2559 
2560 static AppLayerStateData *HTPGetStateData(void *vstate)
2561 {
2562  HtpState *s = vstate;
2563  return &s->state_data;
2564 }
2565 
2566 static int HTPRegisterPatternsForProtocolDetection(void)
2567 {
2568  const char *methods[] = { "GET", "PUT", "POST", "HEAD", "TRACE", "OPTIONS",
2569  "CONNECT", "DELETE", "PATCH", "PROPFIND", "PROPPATCH", "MKCOL",
2570  "COPY", "MOVE", "LOCK", "UNLOCK", "CHECKOUT", "UNCHECKOUT", "CHECKIN",
2571  "UPDATE", "LABEL", "REPORT", "MKWORKSPACE", "MKACTIVITY", "MERGE",
2572  "INVALID", "VERSION-CONTROL", "BASELINE-CONTROL", NULL};
2573  const char *spacings[] = { "|20|", "|09|", NULL };
2574  const char *versions[] = { "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", NULL };
2575 
2576  int methods_pos;
2577  int spacings_pos;
2578  int versions_pos;
2579  int register_result;
2580  char method_buffer[32] = "";
2581 
2582  /* Loop through all the methods ands spacings and register the patterns */
2583  for (methods_pos = 0; methods[methods_pos]; methods_pos++) {
2584  for (spacings_pos = 0; spacings[spacings_pos]; spacings_pos++) {
2585 
2586  /* Combine the method name and the spacing */
2587  snprintf(method_buffer, sizeof(method_buffer), "%s%s", methods[methods_pos], spacings[spacings_pos]);
2588 
2589  /* Register the new method+spacing pattern
2590  * 3 is subtracted from the length since the spacing is hex typed as |xx|
2591  * but the pattern matching should only be one char
2592  */
2593  register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1,
2594  method_buffer, (uint16_t)strlen(method_buffer) - 3, 0, STREAM_TOSERVER);
2595  if (register_result < 0) {
2596  return -1;
2597  }
2598  }
2599  }
2600 
2601  /* Loop through all the http version patterns that are TO_CLIENT */
2602  for (versions_pos = 0; versions[versions_pos]; versions_pos++) {
2603  register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1,
2604  versions[versions_pos], (uint16_t)strlen(versions[versions_pos]), 0,
2605  STREAM_TOCLIENT);
2606  if (register_result < 0) {
2607  return -1;
2608  }
2609  }
2610 
2611  return 0;
2612 }
2613 
2614 /**
2615  * \brief Register the HTTP protocol and state handling functions to APP layer
2616  * of the engine.
2617  */
2619 {
2620  SCEnter();
2621 
2622  const char *proto_name = "http";
2623 
2624  /** HTTP */
2625  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
2627  if (HTPRegisterPatternsForProtocolDetection() < 0)
2628  return;
2629  } else {
2630  SCLogInfo("Protocol detection and parser disabled for %s protocol",
2631  proto_name);
2632  return;
2633  }
2634 
2635  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
2636  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateAlloc, HTPStateFree);
2637  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateTransactionFree);
2638  AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxFiles);
2640  IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetAlstateProgress);
2641  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTxCnt);
2642  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTx);
2643  AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxIterator);
2645  ALPROTO_HTTP1, HTP_REQUEST_PROGRESS_COMPLETE, HTP_RESPONSE_PROGRESS_COMPLETE);
2646  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfo);
2648  IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfoById);
2649 
2650  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxData);
2651  AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetStateData);
2652 
2654  IPPROTO_TCP, ALPROTO_HTTP1, AppLayerHtpSetStreamDepthFlag);
2655 
2657  IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER, HTPHandleRequestData);
2659  IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOCLIENT, HTPHandleResponseData);
2660  SC_ATOMIC_INIT(htp_config_flags);
2661  /* This parser accepts gaps. */
2665  IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_TOCLIENT);
2666  /* app-layer-frame-documentation tag start: registering relevant callbacks */
2668  IPPROTO_TCP, ALPROTO_HTTP1, HTTPGetFrameIdByName, HTTPGetFrameNameById);
2669  /* app-layer-frame-documentation tag end: registering relevant callbacks */
2671  IPPROTO_TCP, ALPROTO_HTTP1, HtpStateGetStateIdByName, HtpStateGetStateNameById);
2672 
2673  HTPConfigure();
2674  } else {
2675  SCLogInfo("Parser disabled for %s protocol. Protocol detection still on.", proto_name);
2676  }
2677 #ifdef UNITTESTS
2678  AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_HTTP1, HTPParserRegisterTests);
2679 #endif
2680 
2681  SCReturn;
2682 }
2683 
2684 #ifdef UNITTESTS
2685 #include "detect-engine-alert.h"
2686 
2687 static HTPCfgRec cfglist_backup;
2688 
2690 {
2691  cfglist_backup = cfglist;
2692 }
2693 
2695 {
2696  cfglist = cfglist_backup;
2697 }
2698 
2699 /** \test Test case where chunks are sent in smaller chunks and check the
2700  * response of the parser from HTP library. */
2701 static int HTPParserTest01(void)
2702 {
2703  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
2704  " Data is c0oL!";
2705  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2706 
2707  TcpSession ssn;
2708  memset(&ssn, 0, sizeof(ssn));
2709 
2712 
2713  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2714  FAIL_IF_NULL(f);
2715  f->protoctx = &ssn;
2716  f->proto = IPPROTO_TCP;
2717  f->alproto = ALPROTO_HTTP1;
2718 
2719  StreamTcpInitConfig(true);
2720 
2721  uint32_t u;
2722  for (u = 0; u < httplen1; u++) {
2723  uint8_t flags = 0;
2724 
2725  if (u == 0)
2726  flags = STREAM_TOSERVER|STREAM_START;
2727  else if (u == (httplen1 - 1))
2728  flags = STREAM_TOSERVER|STREAM_EOF;
2729  else
2730  flags = STREAM_TOSERVER;
2731 
2732  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
2733  FAIL_IF(r != 0);
2734  }
2735 
2736  HtpState *htp_state = f->alstate;
2737  FAIL_IF_NULL(htp_state);
2738 
2739  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2740  FAIL_IF_NULL(tx);
2741 
2742  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2743  FAIL_IF_NULL(h);
2744 
2745  FAIL_IF(bstr_cmp_c(htp_header_value(h), "Victor/1.0"));
2746  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_POST);
2747  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2748 
2749  UTHFreeFlow(f);
2751  StreamTcpFreeConfig(true);
2752  PASS;
2753 }
2754 
2755 /** \test Test folding in 1 read case */
2756 static int HTPParserTest01b(void)
2757 {
2758  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost"
2759  " Data is c0oL!";
2760  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2761 
2762  TcpSession ssn;
2763  memset(&ssn, 0, sizeof(ssn));
2764 
2767 
2768  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2769  FAIL_IF_NULL(f);
2770  f->protoctx = &ssn;
2771  f->proto = IPPROTO_TCP;
2772  f->alproto = ALPROTO_HTTP1;
2773 
2774  StreamTcpInitConfig(true);
2775 
2776  uint8_t flags =STREAM_TOSERVER|STREAM_START|STREAM_EOF;
2777  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1);
2778  FAIL_IF(r != 0);
2779 
2780  HtpState *htp_state = f->alstate;
2781  FAIL_IF_NULL(htp_state);
2782 
2783  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2784  FAIL_IF_NULL(tx);
2785 
2786  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2787  FAIL_IF_NULL(h);
2788 
2789  FAIL_IF(strcmp(bstr_util_strdup_to_c(htp_header_value(h)), "Victor/1.0"));
2790  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_POST);
2791  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2792 
2793  UTHFreeFlow(f);
2795  StreamTcpFreeConfig(true);
2796  PASS;
2797 }
2798 
2799 /** \test Test folding in 1byte per read case */
2800 static int HTPParserTest01c(void)
2801 {
2802  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost"
2803  " Data is c0oL!";
2804  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2805 
2806  TcpSession ssn;
2807  memset(&ssn, 0, sizeof(ssn));
2808 
2811 
2812  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2813  FAIL_IF_NULL(f);
2814  f->protoctx = &ssn;
2815  f->proto = IPPROTO_TCP;
2816  f->alproto = ALPROTO_HTTP1;
2817 
2818  StreamTcpInitConfig(true);
2819 
2820  uint32_t u;
2821  for (u = 0; u < httplen1; u++) {
2822  uint8_t flags = 0;
2823 
2824  if (u == 0)
2825  flags = STREAM_TOSERVER|STREAM_START;
2826  else if (u == (httplen1 - 1))
2827  flags = STREAM_TOSERVER|STREAM_EOF;
2828  else
2829  flags = STREAM_TOSERVER;
2830 
2831  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
2832  FAIL_IF(r != 0);
2833  }
2834 
2835  HtpState *htp_state = f->alstate;
2836  FAIL_IF_NULL(htp_state);
2837 
2838  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2839  FAIL_IF_NULL(tx);
2840 
2841  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2842  FAIL_IF_NULL(h);
2843 
2844  FAIL_IF(strcmp(bstr_util_strdup_to_c(htp_header_value(h)), "Victor/1.0"));
2845  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_POST);
2846  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2847 
2848  UTHFreeFlow(f);
2850  StreamTcpFreeConfig(true);
2851  PASS;
2852 }
2853 
2854 /** \test Test case where chunks are sent in smaller chunks and check the
2855  * response of the parser from HTP library. */
2856 static int HTPParserTest01a(void)
2857 {
2858  Flow *f = NULL;
2859  uint8_t httpbuf1[] = " POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
2860  " Data is c0oL!";
2861  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2862  TcpSession ssn;
2863  HtpState *htp_state = NULL;
2865 
2866  memset(&ssn, 0, sizeof(ssn));
2867 
2868  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2869  FAIL_IF_NULL(f);
2870  f->protoctx = &ssn;
2871  f->proto = IPPROTO_TCP;
2872  f->alproto = ALPROTO_HTTP1;
2873 
2874  StreamTcpInitConfig(true);
2875 
2876  uint32_t u;
2877  for (u = 0; u < httplen1; u++) {
2878  uint8_t flags = 0;
2879 
2880  if (u == 0)
2881  flags = STREAM_TOSERVER|STREAM_START;
2882  else if (u == (httplen1 - 1))
2883  flags = STREAM_TOSERVER|STREAM_EOF;
2884  else
2885  flags = STREAM_TOSERVER;
2886 
2887  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
2888  FAIL_IF(r != 0);
2889  }
2890 
2891  htp_state = f->alstate;
2892  FAIL_IF_NULL(htp_state);
2893 
2894  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2895  FAIL_IF_NULL(tx);
2896 
2897  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2898  FAIL_IF_NULL(h);
2899 
2900  FAIL_IF(strcmp(bstr_util_strdup_to_c(htp_header_value(h)), "Victor/1.0"));
2901  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_POST);
2902  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2903 
2904  UTHFreeFlow(f);
2906  StreamTcpFreeConfig(true);
2907  PASS;
2908 }
2909 
2910 /** \test See how it deals with an incomplete request. */
2911 static int HTPParserTest02(void)
2912 {
2913  Flow *f = NULL;
2914  uint8_t httpbuf1[] = "POST";
2915  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2916  TcpSession ssn;
2917  HtpState *http_state = NULL;
2919 
2920  memset(&ssn, 0, sizeof(ssn));
2921 
2922  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2923  FAIL_IF_NULL(f);
2924  f->protoctx = &ssn;
2925  f->proto = IPPROTO_TCP;
2926  f->alproto = ALPROTO_HTTP1;
2927 
2928  StreamTcpInitConfig(true);
2929 
2930  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
2931  STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
2932  FAIL_IF(r != 0);
2933 
2934  http_state = f->alstate;
2935  FAIL_IF_NULL(http_state);
2936 
2937  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
2938  FAIL_IF_NULL(tx);
2939  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2940  FAIL_IF_NOT_NULL(h);
2941 
2942  FAIL_IF_NULL(htp_tx_request_method(tx));
2943  char *method = bstr_util_strdup_to_c(htp_tx_request_method(tx));
2944  FAIL_IF_NULL(method);
2945 
2946  FAIL_IF(strcmp(method, "POST") != 0);
2947  SCFree(method);
2948 
2949  UTHFreeFlow(f);
2951  StreamTcpFreeConfig(true);
2952  PASS;
2953 }
2954 
2955 /** \test Test case where method is invalid and data is sent in smaller chunks
2956  * and check the response of the parser from HTP library. */
2957 static int HTPParserTest03(void)
2958 {
2959  Flow *f = NULL;
2960  uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n";
2961  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2962  TcpSession ssn;
2963  HtpState *htp_state = NULL;
2965 
2966  memset(&ssn, 0, sizeof(ssn));
2967 
2968  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2969  FAIL_IF_NULL(f);
2970  f->protoctx = &ssn;
2971  f->proto = IPPROTO_TCP;
2972  f->alproto = ALPROTO_HTTP1;
2973 
2974  StreamTcpInitConfig(true);
2975 
2976  uint32_t u;
2977  for (u = 0; u < httplen1; u++) {
2978  uint8_t flags = 0;
2979 
2980  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
2981  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
2982  else flags = STREAM_TOSERVER;
2983 
2984  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
2985  FAIL_IF(r != 0);
2986  }
2987  htp_state = f->alstate;
2988  FAIL_IF_NULL(htp_state);
2989 
2990  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2991  FAIL_IF_NULL(tx);
2992 
2993  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2994  FAIL_IF_NOT_NULL(h);
2995  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_UNKNOWN);
2996  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2997 
2998  UTHFreeFlow(f);
3000  StreamTcpFreeConfig(true);
3001  PASS;
3002 }
3003 
3004 /** \test Test case where invalid data is sent and check the response of the
3005  * parser from HTP library. */
3006 static int HTPParserTest04(void)
3007 {
3008  Flow *f = NULL;
3009  HtpState *htp_state = NULL;
3010  uint8_t httpbuf1[] = "World!\r\n";
3011  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3012  TcpSession ssn;
3014 
3015  memset(&ssn, 0, sizeof(ssn));
3016 
3017  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3018  FAIL_IF_NULL(f);
3019  f->protoctx = &ssn;
3020  f->proto = IPPROTO_TCP;
3021  f->alproto = ALPROTO_HTTP1;
3022 
3023  StreamTcpInitConfig(true);
3024 
3025  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
3026  STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
3027  FAIL_IF(r != 0);
3028 
3029  htp_state = f->alstate;
3030  FAIL_IF_NULL(htp_state);
3031 
3032  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3033  FAIL_IF_NULL(tx);
3034  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3035  FAIL_IF_NOT_NULL(h);
3036  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_UNKNOWN);
3037  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V0_9);
3038 
3039  UTHFreeFlow(f);
3041  StreamTcpFreeConfig(true);
3042  PASS;
3043 }
3044 
3045 /** \test Test both sides of a http stream mixed up to see if the HTP parser
3046  * properly parsed them and also keeps them separated. */
3047 static int HTPParserTest05(void)
3048 {
3049  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\nContent-Length: 17\r\n\r\n";
3050  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3051  uint8_t httpbuf2[] = "Post D";
3052  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3053  uint8_t httpbuf3[] = "ata is c0oL!";
3054  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
3055 
3056  uint8_t httpbuf4[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
3057  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
3058  uint8_t httpbuf5[] = "post R";
3059  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3060  uint8_t httpbuf6[] = "esults are tha bomb!";
3061  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
3062 
3063  TcpSession ssn;
3064  memset(&ssn, 0, sizeof(ssn));
3065 
3068 
3069  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3070  FAIL_IF_NULL(f);
3071  f->protoctx = &ssn;
3072  f->proto = IPPROTO_TCP;
3073  f->alproto = ALPROTO_HTTP1;
3074 
3075  StreamTcpInitConfig(true);
3076 
3077  int r = AppLayerParserParse(
3078  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
3079  FAIL_IF(r != 0);
3080 
3081  r = AppLayerParserParse(
3082  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf4, httplen4);
3083  FAIL_IF(r != 0);
3084 
3085  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf5, httplen5);
3086  FAIL_IF(r != 0);
3087 
3088  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
3089  FAIL_IF(r != 0);
3090 
3091  r = AppLayerParserParse(
3092  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
3093  FAIL_IF(r != 0);
3094 
3095  r = AppLayerParserParse(
3096  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_EOF, httpbuf6, httplen6);
3097  FAIL_IF(r != 0);
3098 
3099  HtpState *http_state = f->alstate;
3100  FAIL_IF_NULL(http_state);
3101 
3102  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
3103  FAIL_IF_NULL(tx);
3104  FAIL_IF_NOT(htp_tx_request_method_number(tx) == HTP_METHOD_POST);
3105  FAIL_IF_NOT(htp_tx_request_protocol_number(tx) == HTP_PROTOCOL_V1_0);
3106 
3107  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3108  FAIL_IF_NULL(h);
3109 
3110  FAIL_IF_NOT(htp_tx_response_status_number(tx) == 200);
3111 
3112  UTHFreeFlow(f);
3114  StreamTcpFreeConfig(true);
3115  PASS;
3116 }
3117 
3118 /** \test Test proper chunked encoded response body
3119  */
3120 static int HTPParserTest06(void)
3121 {
3122  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
3123  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
3124  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
3125  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3126  uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nDate: Sat, 03 Oct 2009 10:16:02 "
3127  "GMT\r\n"
3128  "Server: Apache/1.3.37 (Unix) mod_ssl/2.8.28 "
3129  "OpenSSL/0.9.7a PHP/4.4.7 mod_perl/1.29 "
3130  "FrontPage/5.0.2.2510\r\n"
3131  "X-Powered-By: PHP/4.4.7\r\nTransfer-Encoding: "
3132  "chunked\r\n"
3133  "Content-Type: text/html\r\n\r\n"
3134  "580\r\n"
3135  "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu"
3136  "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN"
3137  "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N"
3138  "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk"
3139  "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l"
3140  "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN"
3141  "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt"
3142  "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz"
3143  "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw"
3144  "aG9uZTM9DQpsb2dpbjM9DQpwYXNzd29yZDM9DQpwaG9uZTQ9DQps"
3145  "b2dpbjQ9DQpwYXNzd29yZDQ9DQpwaG9uZTU9DQpsb2dpbjU9DQpw"
3146  "YXNzd29yZDU9DQpwaG9uZTY9DQpsb2dpbjY9DQpwYXNzd29yZDY9"
3147  "DQpjYWxsX3RpbWUxPQ0KY2FsbF90aW1lMj0NCmRheV9saW1pdD0N"
3148  "Cm1vbnRoX2xpbWl0PQ0KW2dyb3VwM10NCnBob25lMT0NCmxvZ2lu"
3149  "MT0NCnBhc3N3b3JkMT0NCnBob25lMj0NCmxvZ2luMj0NCnBhc3N3"
3150  "b3JkMj0NCnBob25lMz0NCmxvZ2luMz0NCnBhc3N3b3JkMz0NCnBo"
3151  "b25lND0NCmxvZ2luND0NCnBhc3N3b3JkND0NCnBob25lNT0NCmxv"
3152  "Z2luNT0NCnBhc3N3b3JkNT0NCnBob25lNj0NCmxvZ2luNj0NCnBh"
3153  "c3N3b3JkNj0NCmNhbGxfdGltZTE9DQpjYWxsX3RpbWUyPQ0KZGF5"
3154  "X2xpbWl0PQ0KbW9udGhfbGltaXQ9DQpbZ3JvdXA0XQ0KcGhvbmUx"
3155  "PQ0KbG9naW4xPQ0KcGFzc3dvcmQxPQ0KcGhvbmUyPQ0KbG9naW4y"
3156  "PQ0KcGFzc3dvcmQyPQ0KcGhvbmUzPQ0KbG9naW4zPQ0KcGFzc3dv"
3157  "cmQzPQ0KcGhvbmU0PQ0KbG9naW40PQ0KcGFzc3dvcmQ0PQ0KcGhv"
3158  "bmU1PQ0KbG9naW41PQ0KcGFzc3dvcmQ1PQ0KcGhvbmU2PQ0KbG9n"
3159  "aW42PQ0KcGFzc3dvcmQ2PQ0KY2FsbF90aW1lMT0NCmNhbGxfdGlt"
3160  "ZTI9DQpkYXlfbGltaXQ9DQptb250aF9saW1pdD0NCltmaWxlc10N"
3161  "Cmxpbms9aHR0cDovLzIwOS4yMDUuMTk2LjE2L2xkL2dldGJvdC5w"
3162  "aHA=\r\n0\r\n\r\n";
3163  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3164  TcpSession ssn;
3165 
3168 
3169  memset(&ssn, 0, sizeof(ssn));
3170 
3171  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3172  FAIL_IF_NULL(f);
3173  f->protoctx = &ssn;
3174  f->proto = IPPROTO_TCP;
3175  f->alproto = ALPROTO_HTTP1;
3176 
3177  StreamTcpInitConfig(true);
3178 
3179  int r = AppLayerParserParse(
3180  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
3181  FAIL_IF(r != 0);
3182  r = AppLayerParserParse(
3183  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
3184  FAIL_IF(r != 0);
3185 
3186  HtpState *http_state = f->alstate;
3187  FAIL_IF_NULL(http_state);
3188 
3189  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
3190  FAIL_IF_NULL(tx);
3191 
3192  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
3193  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
3194 
3195  FAIL_IF(htp_tx_response_status_number(tx) != 200);
3196  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
3197 
3198  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3199  FAIL_IF_NULL(h);
3200 
3201  UTHFreeFlow(f);
3203  StreamTcpFreeConfig(true);
3204  PASS;
3205 }
3206 
3207 /** \test
3208  */
3209 static int HTPParserTest07(void)
3210 {
3211  Flow *f = NULL;
3212  uint8_t httpbuf1[] = "GET /awstats.pl?/migratemigrate%20=%20| HTTP/1.0\r\n\r\n";
3213  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3214  TcpSession ssn;
3215  HtpState *htp_state = NULL;
3217 
3218  memset(&ssn, 0, sizeof(ssn));
3219 
3220  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3221  FAIL_IF_NULL(f);
3222  f->protoctx = &ssn;
3223  f->proto = IPPROTO_TCP;
3224  f->alproto = ALPROTO_HTTP1;
3225 
3226  StreamTcpInitConfig(true);
3227 
3228  uint32_t u;
3229  for (u = 0; u < httplen1; u++) {
3230  uint8_t flags = 0;
3231 
3232  if (u == 0)
3233  flags = STREAM_TOSERVER|STREAM_START;
3234  else if (u == (httplen1 - 1))
3235  flags = STREAM_TOSERVER|STREAM_EOF;
3236  else
3237  flags = STREAM_TOSERVER;
3238 
3239  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3240  FAIL_IF(r != 0);
3241  }
3242 
3243  htp_state = f->alstate;
3244  FAIL_IF_NULL(htp_state);
3245 
3246  uint8_t ref[] = "/awstats.pl?/migratemigrate = |";
3247  size_t reflen = sizeof(ref) - 1;
3248 
3249  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3250  FAIL_IF_NULL(tx);
3251  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3252  FAIL_IF_NULL(request_uri_normalized);
3253  FAIL_IF(reflen != bstr_len(request_uri_normalized));
3254 
3255  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref, bstr_len(request_uri_normalized)) != 0);
3256 
3257  UTHFreeFlow(f);
3259  StreamTcpFreeConfig(true);
3260  PASS;
3261 }
3262 
3263 #include "conf-yaml-loader.h"
3264 
3265 /** \test Abort
3266  */
3267 static int HTPParserTest08(void)
3268 {
3269  Flow *f = NULL;
3270  uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
3271  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3272  TcpSession ssn;
3274 
3275  char input[] = "\
3276 %YAML 1.1\n\
3277 ---\n\
3278 libhtp:\n\
3279 \n\
3280  default-config:\n\
3281  personality: IDS\n\
3282 ";
3283 
3285  SCConfInit();
3287 
3288  SCConfYamlLoadString(input, strlen(input));
3289  HTPConfigure();
3290 
3291  HtpState *htp_state = NULL;
3292  memset(&ssn, 0, sizeof(ssn));
3293 
3294  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3295  FAIL_IF_NULL(f);
3296  f->protoctx = &ssn;
3297  f->proto = IPPROTO_TCP;
3298  f->alproto = ALPROTO_HTTP1;
3299 
3300  StreamTcpInitConfig(true);
3301 
3302  uint8_t flags = STREAM_TOSERVER | STREAM_START | STREAM_EOF;
3303 
3304  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1);
3305  FAIL_IF(r != 0);
3306 
3307  htp_state = f->alstate;
3308  FAIL_IF_NULL(htp_state);
3309 
3310  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3311  FAIL_IF_NULL(tx);
3312  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3313  FAIL_IF_NULL(request_uri_normalized);
3314  PrintRawDataFp(stdout, bstr_ptr(request_uri_normalized), bstr_len(request_uri_normalized));
3315 
3316  UTHFreeFlow(f);
3318  StreamTcpFreeConfig(true);
3319  HTPFreeConfig();
3320  SCConfDeInit();
3323  PASS;
3324 }
3325 
3326 /** \test Abort
3327  */
3328 static int HTPParserTest09(void)
3329 {
3330  Flow *f = NULL;
3331  uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
3332  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3333  TcpSession ssn;
3335 
3336  char input[] = "\
3337 %YAML 1.1\n\
3338 ---\n\
3339 libhtp:\n\
3340 \n\
3341  default-config:\n\
3342  personality: Apache_2_2\n\
3343 ";
3344 
3346  SCConfInit();
3348 
3349  SCConfYamlLoadString(input, strlen(input));
3350  HTPConfigure();
3351 
3352  HtpState *htp_state = NULL;
3353 
3354  memset(&ssn, 0, sizeof(ssn));
3355 
3356  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3357  FAIL_IF_NULL(f);
3358  f->protoctx = &ssn;
3359  f->proto = IPPROTO_TCP;
3360  f->alproto = ALPROTO_HTTP1;
3361 
3362  StreamTcpInitConfig(true);
3363 
3364  uint8_t flags = STREAM_TOSERVER | STREAM_START | STREAM_EOF;
3365 
3366  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1);
3367  FAIL_IF(r != 0);
3368 
3369  htp_state = f->alstate;
3370  FAIL_IF_NULL(htp_state);
3371 
3372  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3373  FAIL_IF_NULL(tx);
3374  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3375  FAIL_IF_NULL(request_uri_normalized);
3376  PrintRawDataFp(stdout, bstr_ptr(request_uri_normalized), bstr_len(request_uri_normalized));
3377 
3378  UTHFreeFlow(f);
3380  StreamTcpFreeConfig(true);
3381  HTPFreeConfig();
3382  SCConfDeInit();
3385  PASS;
3386 }
3387 
3388 /** \test Host:www.google.com <- missing space between name:value (rfc violation)
3389  */
3390 static int HTPParserTest10(void)
3391 {
3392 
3393  Flow *f = NULL;
3394  uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\r\n\r\n";
3395  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3396  TcpSession ssn;
3397  HtpState *htp_state = NULL;
3399 
3400  memset(&ssn, 0, sizeof(ssn));
3401 
3402  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3403  FAIL_IF_NULL(f);
3404  f->protoctx = &ssn;
3405  f->proto = IPPROTO_TCP;
3406  f->alproto = ALPROTO_HTTP1;
3407 
3408  StreamTcpInitConfig(true);
3409 
3410  uint32_t u;
3411  for (u = 0; u < httplen1; u++) {
3412  uint8_t flags = 0;
3413 
3414  if (u == 0)
3415  flags = STREAM_TOSERVER|STREAM_START;
3416  else if (u == (httplen1 - 1))
3417  flags = STREAM_TOSERVER|STREAM_EOF;
3418  else
3419  flags = STREAM_TOSERVER;
3420 
3421  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3422  FAIL_IF(r != 0);
3423  }
3424 
3425  htp_state = f->alstate;
3426  FAIL_IF_NULL(htp_state);
3427 
3428  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3429  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3430  FAIL_IF_NULL(h);
3431 
3432  char *name = bstr_util_strdup_to_c(htp_header_name(h));
3433  FAIL_IF_NULL(name);
3434  FAIL_IF(strcmp(name, "Host") != 0);
3435 
3436  char *value = bstr_util_strdup_to_c(htp_header_value(h));
3437  FAIL_IF_NULL(value);
3438  FAIL_IF(strcmp(value, "www.google.com") != 0);
3439 
3440  UTHFreeFlow(f);
3442  StreamTcpFreeConfig(true);
3443  SCFree(name);
3444  SCFree(value);
3445  PASS;
3446 }
3447 
3448 /** \test double encoding in path
3449  */
3450 static int HTPParserTest11(void)
3451 {
3452  Flow *f = NULL;
3453  uint8_t httpbuf1[] = "GET /%2500 HTTP/1.0\r\n\r\n";
3454  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3455  TcpSession ssn;
3456  HtpState *htp_state = NULL;
3458 
3459  memset(&ssn, 0, sizeof(ssn));
3460 
3461  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3462  FAIL_IF_NULL(f);
3463  f->protoctx = &ssn;
3464  f->proto = IPPROTO_TCP;
3465  f->alproto = ALPROTO_HTTP1;
3466 
3467  StreamTcpInitConfig(true);
3468 
3469  uint32_t u;
3470  for (u = 0; u < httplen1; u++) {
3471  uint8_t flags = 0;
3472 
3473  if (u == 0)
3474  flags = STREAM_TOSERVER|STREAM_START;
3475  else if (u == (httplen1 - 1))
3476  flags = STREAM_TOSERVER|STREAM_EOF;
3477  else
3478  flags = STREAM_TOSERVER;
3479 
3480  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3481  FAIL_IF(r != 0);
3482  }
3483 
3484  htp_state = f->alstate;
3485  FAIL_IF_NULL(htp_state);
3486 
3487  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3488  FAIL_IF_NULL(tx);
3489  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3490  FAIL_IF_NULL(request_uri_normalized);
3491 
3492  FAIL_IF(bstr_len(request_uri_normalized) != 4);
3493  FAIL_IF(bstr_ptr(request_uri_normalized)[0] != '/');
3494  FAIL_IF(bstr_ptr(request_uri_normalized)[1] != '%');
3495  FAIL_IF(bstr_ptr(request_uri_normalized)[2] != '0');
3496  FAIL_IF(bstr_ptr(request_uri_normalized)[3] != '0');
3497 
3498  UTHFreeFlow(f);
3500  StreamTcpFreeConfig(true);
3501  PASS;
3502 }
3503 
3504 /** \test double encoding in query
3505  */
3506 static int HTPParserTest12(void)
3507 {
3508  Flow *f = NULL;
3509  uint8_t httpbuf1[] = "GET /?a=%2500 HTTP/1.0\r\n\r\n";
3510  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3511  TcpSession ssn;
3512  HtpState *htp_state = NULL;
3514 
3515  memset(&ssn, 0, sizeof(ssn));
3516 
3517  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3518  FAIL_IF_NULL(f);
3519  f->protoctx = &ssn;
3520  f->proto = IPPROTO_TCP;
3521  f->alproto = ALPROTO_HTTP1;
3522 
3523  StreamTcpInitConfig(true);
3524 
3525  uint32_t u;
3526  for (u = 0; u < httplen1; u++) {
3527  uint8_t flags = 0;
3528 
3529  if (u == 0)
3530  flags = STREAM_TOSERVER|STREAM_START;
3531  else if (u == (httplen1 - 1))
3532  flags = STREAM_TOSERVER|STREAM_EOF;
3533  else
3534  flags = STREAM_TOSERVER;
3535 
3536  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3537  FAIL_IF(r != 0);
3538  }
3539 
3540  htp_state = f->alstate;
3541  FAIL_IF_NULL(htp_state);
3542 
3543  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3544  FAIL_IF_NULL(tx);
3545  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3546  FAIL_IF_NULL(request_uri_normalized);
3547 
3548  FAIL_IF(bstr_len(request_uri_normalized) != 7);
3549  FAIL_IF(bstr_ptr(request_uri_normalized)[0] != '/');
3550  FAIL_IF(bstr_ptr(request_uri_normalized)[1] != '?');
3551  FAIL_IF(bstr_ptr(request_uri_normalized)[2] != 'a');
3552  FAIL_IF(bstr_ptr(request_uri_normalized)[3] != '=');
3553  FAIL_IF(bstr_ptr(request_uri_normalized)[4] != '%');
3554  FAIL_IF(bstr_ptr(request_uri_normalized)[5] != '0');
3555  FAIL_IF(bstr_ptr(request_uri_normalized)[6] != '0');
3556 
3557  UTHFreeFlow(f);
3559  StreamTcpFreeConfig(true);
3560  PASS;
3561 }
3562 
3563 /** \test Host:www.google.com0dName: Value0d0a <- missing space between name:value (rfc violation)
3564  */
3565 static int HTPParserTest13(void)
3566 {
3567  Flow *f = NULL;
3568  uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\rName: Value\r\n\r\n";
3569  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3570  TcpSession ssn;
3571  HtpState *htp_state = NULL;
3573 
3574  memset(&ssn, 0, sizeof(ssn));
3575 
3576  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3577  FAIL_IF_NULL(f);
3578  f->protoctx = &ssn;
3579  f->proto = IPPROTO_TCP;
3580  f->alproto = ALPROTO_HTTP1;
3581 
3582  StreamTcpInitConfig(true);
3583 
3584  uint32_t u;
3585  for (u = 0; u < httplen1; u++) {
3586  uint8_t flags = 0;
3587 
3588  if (u == 0)
3589  flags = STREAM_TOSERVER|STREAM_START;
3590  else if (u == (httplen1 - 1))
3591  flags = STREAM_TOSERVER|STREAM_EOF;
3592  else
3593  flags = STREAM_TOSERVER;
3594 
3595  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3596  FAIL_IF(r != 0);
3597  }
3598 
3599  htp_state = f->alstate;
3600  FAIL_IF_NULL(htp_state);
3601  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3602  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3603  FAIL_IF_NULL(h);
3604 
3605  char *name = bstr_util_strdup_to_c(htp_header_name(h));
3606  FAIL_IF_NULL(name);
3607  FAIL_IF(strcmp(name, "Host") != 0);
3608 
3609  char *value = bstr_util_strdup_to_c(htp_header_value(h));
3610  FAIL_IF_NULL(value);
3611  FAIL_IF(strcmp(value, "www.google.com\rName: Value") != 0);
3612 
3613  UTHFreeFlow(f);
3615  StreamTcpFreeConfig(true);
3616  SCFree(name);
3617  SCFree(value);
3618 
3619  PASS;
3620 }
3621 
3622 /** \test Test basic config */
3623 static int HTPParserConfigTest01(void)
3624 {
3625  char input[] = "\
3626 %YAML 1.1\n\
3627 ---\n\
3628 libhtp:\n\
3629 \n\
3630  default-config:\n\
3631  personality: IDS\n\
3632 \n\
3633  server-config:\n\
3634 \n\
3635  - apache-tomcat:\n\
3636  address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
3637  personality: Tomcat_6_0\n\
3638 \n\
3639  - iis7:\n\
3640  address: \n\
3641  - 192.168.0.0/24\n\
3642  - 192.168.10.0/24\n\
3643  personality: IIS_7_0\n\
3644 ";
3645 
3647  SCConfInit();
3648 
3649  SCConfYamlLoadString(input, strlen(input));
3650 
3651  SCConfNode *outputs;
3652  outputs = SCConfGetNode("libhtp.default-config.personality");
3653  FAIL_IF_NULL(outputs);
3654 
3655  outputs = SCConfGetNode("libhtp.server-config");
3656  FAIL_IF_NULL(outputs);
3657 
3658  SCConfNode *node = TAILQ_FIRST(&outputs->head);
3659  FAIL_IF_NULL(node);
3660  FAIL_IF(strcmp(node->name, "0") != 0);
3661  node = TAILQ_FIRST(&node->head);
3662  FAIL_IF_NULL(node);
3663  FAIL_IF(strcmp(node->name, "apache-tomcat") != 0);
3664 
3665  int i = 0;
3666  SCConfNode *n;
3667 
3668  SCConfNode *node2 = SCConfNodeLookupChild(node, "personality");
3669  FAIL_IF_NULL(node2);
3670  FAIL_IF(strcmp(node2->val, "Tomcat_6_0") != 0);
3671 
3672  node = SCConfNodeLookupChild(node, "address");
3673  FAIL_IF_NULL(node);
3674 
3675  TAILQ_FOREACH (n, &node->head, next) {
3676  FAIL_IF_NULL(n);
3677  switch(i) {
3678  case 0:
3679  FAIL_IF(strcmp(n->name, "0") != 0);
3680  FAIL_IF(strcmp(n->val, "192.168.1.0/24") != 0);
3681  break;
3682  case 1:
3683  FAIL_IF(strcmp(n->name, "1") != 0);
3684  FAIL_IF(strcmp(n->val, "127.0.0.0/8") != 0);
3685  break;
3686  case 2:
3687  FAIL_IF(strcmp(n->name, "2") != 0);
3688  FAIL_IF(strcmp(n->val, "::1") != 0);
3689  break;
3690  default:
3691  FAIL;
3692  }
3693  i++;
3694  }
3695 
3696  outputs = SCConfGetNode("libhtp.server-config");
3697  FAIL_IF_NULL(outputs);
3698  node = TAILQ_FIRST(&outputs->head);
3699  node = TAILQ_NEXT(node, next);
3700  FAIL_IF_NULL(node);
3701  FAIL_IF(strcmp(node->name, "1") != 0);
3702  node = TAILQ_FIRST(&node->head);
3703  FAIL_IF_NULL(node);
3704  FAIL_IF(strcmp(node->name, "iis7") != 0);
3705 
3706  node2 = SCConfNodeLookupChild(node, "personality");
3707  FAIL_IF_NULL(node2);
3708  FAIL_IF(strcmp(node2->val, "IIS_7_0") != 0);
3709 
3710  node = SCConfNodeLookupChild(node, "address");
3711  FAIL_IF_NULL(node);
3712 
3713  i = 0;
3714  TAILQ_FOREACH(n, &node->head, next) {
3715  FAIL_IF_NULL(n);
3716 
3717  switch(i) {
3718  case 0:
3719  FAIL_IF(strcmp(n->name, "0") != 0);
3720  FAIL_IF(strcmp(n->val, "192.168.0.0/24") != 0);
3721  break;
3722  case 1:
3723  FAIL_IF(strcmp(n->name, "1") != 0);
3724  FAIL_IF(strcmp(n->val, "192.168.10.0/24") != 0);
3725  break;
3726  default:
3727  FAIL;
3728  }
3729  i++;
3730  }
3731 
3732  SCConfDeInit();
3734 
3735  PASS;
3736 }
3737 
3738 /** \test Test config builds radix correctly */
3739 static int HTPParserConfigTest02(void)
3740 {
3741  char input[] = "\
3742 %YAML 1.1\n\
3743 ---\n\
3744 libhtp:\n\
3745 \n\
3746  default-config:\n\
3747  personality: IDS\n\
3748 \n\
3749  server-config:\n\
3750 \n\
3751  - apache-tomcat:\n\
3752  address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
3753  personality: Tomcat_6_0\n\
3754 \n\
3755  - iis7:\n\
3756  address: \n\
3757  - 192.168.0.0/24\n\
3758  - 192.168.10.0/24\n\
3759  personality: IIS_7_0\n\
3760 ";
3761 
3763  SCConfInit();
3765  SCConfYamlLoadString(input, strlen(input));
3766  HTPConfigure();
3767  FAIL_IF_NULL(cfglist.cfg);
3768  FAIL_IF_NULL(cfgtree.ipv4.head);
3769  FAIL_IF_NULL(cfgtree.ipv6.head);
3770 
3771  htp_cfg_t *htp = cfglist.cfg;
3772  uint8_t buf[128];
3773  const char *addr;
3774  void *user_data = NULL;
3775 
3776  addr = "192.168.10.42";
3777  FAIL_IF(inet_pton(AF_INET, addr, buf) != 1);
3778  (void)SCRadix4TreeFindBestMatch(&cfgtree.ipv4, buf, &user_data);
3779  FAIL_IF_NULL(user_data);
3780  HTPCfgRec *htp_cfg_rec = user_data;
3781  htp = htp_cfg_rec->cfg;
3782  FAIL_IF_NULL(htp);
3783  SCLogDebug("LIBHTP using config: %p", htp);
3784 
3785  user_data = NULL;
3786  addr = "::1";
3787  FAIL_IF(inet_pton(AF_INET6, addr, buf) != 1);
3788  (void)SCRadix6TreeFindBestMatch(&cfgtree.ipv6, buf, &user_data);
3789  FAIL_IF_NULL(user_data);
3790  htp_cfg_rec = user_data;
3791  htp = htp_cfg_rec->cfg;
3792  FAIL_IF_NULL(htp);
3793  SCLogDebug("LIBHTP using config: %p", htp);
3794 
3795  HTPFreeConfig();
3796  SCConfDeInit();
3799 
3800  PASS;
3801 }
3802 
3803 /** \test Test traffic is handled by the correct htp config */
3804 static int HTPParserConfigTest03(void)
3805 {
3806  Flow *f = NULL;
3807  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
3808  " Data is c0oL!";
3809  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3810  TcpSession ssn;
3812 
3813  HtpState *htp_state = NULL;
3814  char input[] = "\
3815 %YAML 1.1\n\
3816 ---\n\
3817 libhtp:\n\
3818 \n\
3819  default-config:\n\
3820  personality: IDS\n\
3821 \n\
3822  server-config:\n\
3823 \n\
3824  - apache-tomcat:\n\
3825  address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
3826  personality: Tomcat_6_0\n\
3827 \n\
3828  - iis7:\n\
3829  address: \n\
3830  - 192.168.0.0/24\n\
3831  - 192.168.10.0/24\n\
3832  personality: IIS_7_0\n\
3833 ";
3834 
3836  SCConfInit();
3838 
3839  SCConfYamlLoadString(input, strlen(input));
3840 
3841  HTPConfigure();
3842 
3843  const char *addr = "192.168.10.42";
3844 
3845  memset(&ssn, 0, sizeof(ssn));
3846 
3847  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
3848  FAIL_IF_NULL(f);
3849  f->protoctx = &ssn;
3850  f->proto = IPPROTO_TCP;
3851  f->alproto = ALPROTO_HTTP1;
3852 
3853  htp_cfg_t *htp = cfglist.cfg;
3854  FAIL_IF_NULL(htp);
3855 
3856  void *user_data = NULL;
3857  (void)SCRadix4TreeFindBestMatch(&cfgtree.ipv4, (uint8_t *)f->dst.addr_data32, &user_data);
3858  FAIL_IF_NULL(user_data);
3859 
3860  HTPCfgRec *htp_cfg_rec = user_data;
3861  htp = htp_cfg_rec->cfg;
3862  FAIL_IF_NULL(user_data);
3863  SCLogDebug("LIBHTP using config: %p", htp);
3864 
3865  StreamTcpInitConfig(true);
3866 
3867  uint32_t u;
3868  for (u = 0; u < httplen1; u++) {
3869  uint8_t flags = 0;
3870 
3871  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
3872  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
3873  else flags = STREAM_TOSERVER;
3874 
3875  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3876  FAIL_IF(r != 0);
3877  }
3878 
3879  htp_state = f->alstate;
3880  FAIL_IF_NULL(htp_state);
3881 
3882  FAIL_IF(HTPStateGetTxCnt(htp_state) != 2);
3883 
3884  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3885  FAIL_IF_NULL(tx);
3886  tx = HTPStateGetTx(htp_state, 1);
3887  FAIL_IF_NULL(tx);
3888 
3889  UTHFreeFlow(f);
3891  HTPFreeConfig();
3892  SCConfDeInit();
3895  StreamTcpFreeConfig(true);
3896  PASS;
3897 }
3898 
3899 /** \test Test %2f decoding in profile Apache_2_2
3900  *
3901  * %2f in path is left untouched
3902  * %2f in query string is normalized to %2F
3903  * %252f in query string is decoded/normalized to %2F
3904  */
3905 static int HTPParserDecodingTest01(void)
3906 {
3907  uint8_t httpbuf1[] =
3908  "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
3909  "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
3910  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
3911  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3912  TcpSession ssn;
3915 
3916  char input[] = "\
3917 %YAML 1.1\n\
3918 ---\n\
3919 libhtp:\n\
3920 \n\
3921  default-config:\n\
3922  personality: Apache_2\n\
3923 ";
3924 
3926  SCConfInit();
3928  SCConfYamlLoadString(input, strlen(input));
3929  HTPConfigure();
3930  const char *addr = "4.3.2.1";
3931  memset(&ssn, 0, sizeof(ssn));
3932 
3933  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
3934  FAIL_IF_NULL(f);
3935  f->protoctx = &ssn;
3936  f->proto = IPPROTO_TCP;
3937  f->alproto = ALPROTO_HTTP1;
3938 
3939  StreamTcpInitConfig(true);
3940 
3941  for (uint32_t u = 0; u < httplen1; u++) {
3942  uint8_t flags = 0;
3943  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
3944  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
3945  else flags = STREAM_TOSERVER;
3946 
3947  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3948  FAIL_IF(r != 0);
3949  }
3950 
3951  HtpState *htp_state = f->alstate;
3952  FAIL_IF_NULL(htp_state);
3953 
3954  uint8_t ref1[] = "/abc%2fdef";
3955  size_t reflen = sizeof(ref1) - 1;
3956 
3957  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3958  FAIL_IF_NULL(tx);
3959 
3960  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
3961  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3962  FAIL_IF_NULL(tx_ud);
3963  FAIL_IF_NULL(request_uri_normalized);
3964  FAIL_IF(reflen != bstr_len(request_uri_normalized));
3965  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
3966 
3967  uint8_t ref2[] = "/abc/def?ghi/jkl";
3968  reflen = sizeof(ref2) - 1;
3969 
3970  tx = HTPStateGetTx(htp_state, 1);
3971  FAIL_IF_NULL(tx);
3972 
3973  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
3974  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3975  FAIL_IF_NULL(tx_ud);
3976  FAIL_IF_NULL(request_uri_normalized);
3977  FAIL_IF(reflen != bstr_len(request_uri_normalized));
3978  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref2, bstr_len(request_uri_normalized)) != 0);
3979 
3980  uint8_t ref3[] = "/abc/def?ghi%2fjkl";
3981  reflen = sizeof(ref3) - 1;
3982  tx = HTPStateGetTx(htp_state, 2);
3983  FAIL_IF_NULL(tx);
3984 
3985  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
3986  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3987  FAIL_IF_NULL(tx_ud);
3988  FAIL_IF_NULL(request_uri_normalized);
3989  FAIL_IF(reflen != bstr_len(request_uri_normalized));
3990  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref3, bstr_len(request_uri_normalized)) != 0);
3991 
3992  UTHFreeFlow(f);
3994  HTPFreeConfig();
3995  SCConfDeInit();
3998  StreamTcpFreeConfig(true);
3999  PASS;
4000 }
4001 
4002 static int HTPParserDecodingTest01a(void)
4003 {
4004  uint8_t httpbuf1[] = "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4005  "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4006  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4007  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4008  TcpSession ssn;
4011 
4012  char input[] = "\
4013 %YAML 1.1\n\
4014 ---\n\
4015 libhtp:\n\
4016 \n\
4017  default-config:\n\
4018  personality: Apache_2\n\
4019 ";
4020 
4022  SCConfInit();
4024  SCConfYamlLoadString(input, strlen(input));
4025  HTPConfigure();
4026  const char *addr = "4.3.2.1";
4027  memset(&ssn, 0, sizeof(ssn));
4028 
4029  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4030  FAIL_IF_NULL(f);
4031  f->protoctx = &ssn;
4032  f->proto = IPPROTO_TCP;
4033  f->alproto = ALPROTO_HTTP1;
4034 
4035  StreamTcpInitConfig(true);
4036 
4037  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
4038  (STREAM_TOSERVER | STREAM_START | STREAM_EOF), httpbuf1, httplen1);
4039  FAIL_IF(r != 0);
4040 
4041  HtpState *htp_state = f->alstate;
4042  FAIL_IF_NULL(htp_state);
4043 
4044  uint8_t ref1[] = "/abc%2fdef";
4045  size_t reflen = sizeof(ref1) - 1;
4046 
4047  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4048  FAIL_IF_NULL(tx);
4049 
4050  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4051  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4052  FAIL_IF_NULL(tx_ud);
4053  FAIL_IF_NULL(request_uri_normalized);
4054  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4055  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4056 
4057  uint8_t ref2[] = "/abc/def?ghi/jkl";
4058  reflen = sizeof(ref2) - 1;
4059 
4060  tx = HTPStateGetTx(htp_state, 1);
4061  FAIL_IF_NULL(tx);
4062  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4063  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4064  FAIL_IF_NULL(tx_ud);
4065  FAIL_IF_NULL(request_uri_normalized);
4066  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4067 
4068  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref2, bstr_len(request_uri_normalized)) != 0);
4069 
4070  uint8_t ref3[] = "/abc/def?ghi%2fjkl";
4071  reflen = sizeof(ref3) - 1;
4072  tx = HTPStateGetTx(htp_state, 2);
4073  FAIL_IF_NULL(tx);
4074  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4075  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4076  FAIL_IF_NULL(tx_ud);
4077  FAIL_IF_NULL(request_uri_normalized);
4078  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4079 
4080  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref3, bstr_len(request_uri_normalized)) != 0);
4081 
4082  UTHFreeFlow(f);
4084  HTPFreeConfig();
4085  SCConfDeInit();
4088  StreamTcpFreeConfig(true);
4089  PASS;
4090 }
4091 
4092 /** \test Test %2f decoding in profile IDS
4093  *
4094  * %2f in path decoded to /
4095  * %2f in query string is decoded to /
4096  * %252f in query string is decoded to %2F
4097  */
4098 static int HTPParserDecodingTest02(void)
4099 {
4100  Flow *f = NULL;
4101  uint8_t httpbuf1[] =
4102  "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4103  "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4104  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4105  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4106  TcpSession ssn;
4108 
4109  HtpState *htp_state = NULL;
4110  char input[] = "\
4111 %YAML 1.1\n\
4112 ---\n\
4113 libhtp:\n\
4114 \n\
4115  default-config:\n\
4116  personality: IDS\n\
4117  double-decode-path: no\n\
4118  double-decode-query: no\n\
4119 ";
4120 
4122  SCConfInit();
4124  SCConfYamlLoadString(input, strlen(input));
4125  HTPConfigure();
4126  const char *addr = "4.3.2.1";
4127  memset(&ssn, 0, sizeof(ssn));
4128 
4129  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4130  FAIL_IF_NULL(f);
4131  f->protoctx = &ssn;
4132  f->proto = IPPROTO_TCP;
4133  f->alproto = ALPROTO_HTTP1;
4134 
4135  StreamTcpInitConfig(true);
4136 
4137  uint32_t u;
4138  for (u = 0; u < httplen1; u++) {
4139  uint8_t flags = 0;
4140 
4141  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4142  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4143  else flags = STREAM_TOSERVER;
4144 
4145  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4146  FAIL_IF(r != 0);
4147  }
4148 
4149  htp_state = f->alstate;
4150  FAIL_IF_NULL(htp_state);
4151 
4152  uint8_t ref1[] = "/abc/def";
4153  size_t reflen = sizeof(ref1) - 1;
4154 
4155  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4156  FAIL_IF_NULL(tx);
4157  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4158  FAIL_IF_NULL(request_uri_normalized);
4159  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4160  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4161 
4162  uint8_t ref2[] = "/abc/def?ghi/jkl";
4163  reflen = sizeof(ref2) - 1;
4164 
4165  tx = HTPStateGetTx(htp_state, 1);
4166  FAIL_IF_NULL(tx);
4167  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4168  FAIL_IF_NULL(request_uri_normalized);
4169  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4170 
4171  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref2, bstr_len(request_uri_normalized)) != 0);
4172 
4173  uint8_t ref3[] = "/abc/def?ghi%2fjkl";
4174  reflen = sizeof(ref3) - 1;
4175  tx = HTPStateGetTx(htp_state, 2);
4176  FAIL_IF_NULL(tx);
4177  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4178  FAIL_IF_NULL(request_uri_normalized);
4179  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4180 
4181  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref3, bstr_len(request_uri_normalized)) != 0);
4182 
4183  UTHFreeFlow(f);
4185  HTPFreeConfig();
4186  SCConfDeInit();
4189  StreamTcpFreeConfig(true);
4190  PASS;
4191 }
4192 
4193 /** \test Test %2f decoding in profile IDS with double-decode-* options
4194  *
4195  * %252f in path decoded to /
4196  * %252f in query string is decoded to /
4197  */
4198 static int HTPParserDecodingTest03(void)
4199 {
4200  Flow *f = NULL;
4201  uint8_t httpbuf1[] =
4202  "GET /abc%252fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4203  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4204  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4205  TcpSession ssn;
4207 
4208  HtpState *htp_state = NULL;
4209  char input[] = "\
4210 %YAML 1.1\n\
4211 ---\n\
4212 libhtp:\n\
4213 \n\
4214  default-config:\n\
4215  personality: IDS\n\
4216  double-decode-path: yes\n\
4217  double-decode-query: yes\n\
4218 ";
4219 
4221  SCConfInit();
4223  SCConfYamlLoadString(input, strlen(input));
4224  HTPConfigure();
4225  const char *addr = "4.3.2.1";
4226  memset(&ssn, 0, sizeof(ssn));
4227 
4228  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4229  FAIL_IF_NULL(f);
4230  f->protoctx = &ssn;
4231  f->proto = IPPROTO_TCP;
4232  f->alproto = ALPROTO_HTTP1;
4233 
4234  StreamTcpInitConfig(true);
4235 
4236  uint32_t u;
4237  for (u = 0; u < httplen1; u++) {
4238  uint8_t flags = 0;
4239 
4240  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4241  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4242  else flags = STREAM_TOSERVER;
4243 
4244  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4245  FAIL_IF(r != 0);
4246  }
4247 
4248  htp_state = f->alstate;
4249  FAIL_IF_NULL(htp_state);
4250 
4251  uint8_t ref1[] = "/abc/def";
4252  size_t reflen = sizeof(ref1) - 1;
4253 
4254  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4255  FAIL_IF_NULL(tx);
4256  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4257  FAIL_IF_NULL(request_uri_normalized);
4258  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4259 
4260  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4261 
4262  uint8_t ref2[] = "/abc/def?ghi/jkl";
4263  reflen = sizeof(ref2) - 1;
4264 
4265  tx = HTPStateGetTx(htp_state, 1);
4266  FAIL_IF_NULL(tx);
4267  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4268  FAIL_IF_NULL(request_uri_normalized);
4269  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4270 
4271  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref2, bstr_len(request_uri_normalized)) != 0);
4272 
4273  UTHFreeFlow(f);
4275  HTPFreeConfig();
4276  SCConfDeInit();
4279  StreamTcpFreeConfig(true);
4280  PASS;
4281 }
4282 
4283 /** \test Test http:// in query profile IDS
4284  */
4285 static int HTPParserDecodingTest04(void)
4286 {
4287  Flow *f = NULL;
4288  uint8_t httpbuf1[] =
4289  "GET /abc/def?a=http://www.abc.com/ HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4290  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4291  TcpSession ssn;
4293 
4294  HtpState *htp_state = NULL;
4295  char input[] = "\
4296 %YAML 1.1\n\
4297 ---\n\
4298 libhtp:\n\
4299 \n\
4300  default-config:\n\
4301  personality: IDS\n\
4302  double-decode-path: yes\n\
4303  double-decode-query: yes\n\
4304 ";
4305 
4307  SCConfInit();
4309  SCConfYamlLoadString(input, strlen(input));
4310  HTPConfigure();
4311  const char *addr = "4.3.2.1";
4312  memset(&ssn, 0, sizeof(ssn));
4313 
4314  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4315  FAIL_IF_NULL(f);
4316  f->protoctx = &ssn;
4317  f->proto = IPPROTO_TCP;
4318  f->alproto = ALPROTO_HTTP1;
4319 
4320  StreamTcpInitConfig(true);
4321 
4322  uint32_t u;
4323  for (u = 0; u < httplen1; u++) {
4324  uint8_t flags = 0;
4325 
4326  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4327  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4328  else flags = STREAM_TOSERVER;
4329 
4330  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4331  FAIL_IF(r != 0);
4332  }
4333 
4334  htp_state = f->alstate;
4335  FAIL_IF_NULL(htp_state);
4336 
4337  uint8_t ref1[] = "/abc/def?a=http://www.abc.com/";
4338  size_t reflen = sizeof(ref1) - 1;
4339 
4340  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4341  FAIL_IF_NULL(tx);
4342  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4343  FAIL_IF_NULL(request_uri_normalized);
4344  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4345 
4346  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4347 
4348  UTHFreeFlow(f);
4350  HTPFreeConfig();
4351  SCConfDeInit();
4354  StreamTcpFreeConfig(true);
4355  PASS;
4356 }
4357 
4358 /** \test Test \ char in query profile IDS. Bug 739
4359  */
4360 static int HTPParserDecodingTest05(void)
4361 {
4362  Flow *f = NULL;
4363  uint8_t httpbuf1[] =
4364  "GET /index?id=\\\"<script>alert(document.cookie)</script> HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4365  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4366  TcpSession ssn;
4368 
4369  HtpState *htp_state = NULL;
4370  char input[] = "\
4371 %YAML 1.1\n\
4372 ---\n\
4373 libhtp:\n\
4374 \n\
4375  default-config:\n\
4376  personality: IDS\n\
4377  double-decode-path: yes\n\
4378  double-decode-query: yes\n\
4379 ";
4380 
4382  SCConfInit();
4384  SCConfYamlLoadString(input, strlen(input));
4385  HTPConfigure();
4386  const char *addr = "4.3.2.1";
4387  memset(&ssn, 0, sizeof(ssn));
4388 
4389  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4390  FAIL_IF_NULL(f);
4391  f->protoctx = &ssn;
4392  f->proto = IPPROTO_TCP;
4393  f->alproto = ALPROTO_HTTP1;
4394 
4395  StreamTcpInitConfig(true);
4396 
4397  uint32_t u;
4398  for (u = 0; u < httplen1; u++) {
4399  uint8_t flags = 0;
4400 
4401  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4402  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4403  else flags = STREAM_TOSERVER;
4404 
4405  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4406  FAIL_IF(r != 0);
4407  }
4408 
4409  htp_state = f->alstate;
4410  FAIL_IF_NULL(htp_state);
4411 
4412  uint8_t ref1[] = "/index?id=\\\"<script>alert(document.cookie)</script>";
4413  size_t reflen = sizeof(ref1) - 1;
4414 
4415  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4416  FAIL_IF_NULL(tx);
4417  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4418  FAIL_IF_NULL(request_uri_normalized);
4419  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4420 
4421  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4422 
4423  UTHFreeFlow(f);
4425  HTPFreeConfig();
4426  SCConfDeInit();
4429  StreamTcpFreeConfig(true);
4430  PASS;
4431 }
4432 
4433 /** \test Test + char in query. Bug 1035
4434  */
4435 static int HTPParserDecodingTest06(void)
4436 {
4437  Flow *f = NULL;
4438  uint8_t httpbuf1[] =
4439  "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4440  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4441  TcpSession ssn;
4443 
4444  HtpState *htp_state = NULL;
4445  char input[] = "\
4446 %YAML 1.1\n\
4447 ---\n\
4448 libhtp:\n\
4449 \n\
4450  default-config:\n\
4451  personality: IDS\n\
4452  double-decode-path: yes\n\
4453  double-decode-query: yes\n\
4454 ";
4455 
4457  SCConfInit();
4459  SCConfYamlLoadString(input, strlen(input));
4460  HTPConfigure();
4461  const char *addr = "4.3.2.1";
4462  memset(&ssn, 0, sizeof(ssn));
4463 
4464  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4465  FAIL_IF_NULL(f);
4466  f->protoctx = &ssn;
4467  f->proto = IPPROTO_TCP;
4468  f->alproto = ALPROTO_HTTP1;
4469 
4470  StreamTcpInitConfig(true);
4471 
4472  uint32_t u;
4473  for (u = 0; u < httplen1; u++) {
4474  uint8_t flags = 0;
4475 
4476  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4477  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4478  else flags = STREAM_TOSERVER;
4479 
4480  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4481  FAIL_IF(r != 0);
4482  }
4483 
4484  htp_state = f->alstate;
4485  FAIL_IF_NULL(htp_state);
4486 
4487  uint8_t ref1[] = "/put.php?ip=1.2.3.4&port=+6000";
4488  size_t reflen = sizeof(ref1) - 1;
4489 
4490  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4491  FAIL_IF_NULL(tx);
4492  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4493  FAIL_IF_NULL(request_uri_normalized);
4494  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4495 
4496  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4497 
4498  UTHFreeFlow(f);
4500  HTPFreeConfig();
4501  SCConfDeInit();
4504  StreamTcpFreeConfig(true);
4505  PASS;
4506 }
4507 
4508 /** \test Test + char in query. Bug 1035
4509  */
4510 static int HTPParserDecodingTest07(void)
4511 {
4512  Flow *f = NULL;
4513  uint8_t httpbuf1[] =
4514  "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4515  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4516  TcpSession ssn;
4518 
4519  HtpState *htp_state = NULL;
4520  char input[] = "\
4521 %YAML 1.1\n\
4522 ---\n\
4523 libhtp:\n\
4524 \n\
4525  default-config:\n\
4526  personality: IDS\n\
4527  double-decode-path: yes\n\
4528  double-decode-query: yes\n\
4529  query-plusspace-decode: yes\n\
4530 ";
4531 
4533  SCConfInit();
4535  SCConfYamlLoadString(input, strlen(input));
4536  HTPConfigure();
4537  const char *addr = "4.3.2.1";
4538  memset(&ssn, 0, sizeof(ssn));
4539 
4540  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4541  FAIL_IF_NULL(f);
4542  f->protoctx = &ssn;
4543  f->proto = IPPROTO_TCP;
4544  f->alproto = ALPROTO_HTTP1;
4545 
4546  StreamTcpInitConfig(true);
4547 
4548  uint32_t u;
4549  for (u = 0; u < httplen1; u++) {
4550  uint8_t flags = 0;
4551 
4552  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4553  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4554  else flags = STREAM_TOSERVER;
4555 
4556  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4557  FAIL_IF(r != 0);
4558  }
4559 
4560  htp_state = f->alstate;
4561  FAIL_IF_NULL(htp_state);
4562 
4563  uint8_t ref1[] = "/put.php?ip=1.2.3.4&port= 6000";
4564  size_t reflen = sizeof(ref1) - 1;
4565 
4566  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4567  FAIL_IF_NULL(tx);
4568  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4569  FAIL_IF_NULL(request_uri_normalized);
4570  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4571 
4572  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4573 
4574  UTHFreeFlow(f);
4576  HTPFreeConfig();
4577  SCConfDeInit();
4580  StreamTcpFreeConfig(true);
4581  PASS;
4582 }
4583 
4584 /** \test Test 'proxy' URI normalization. Ticket 1008
4585  */
4586 static int HTPParserDecodingTest08(void)
4587 {
4588  Flow *f = NULL;
4589  uint8_t httpbuf1[] =
4590  "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n";
4591  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4592  TcpSession ssn;
4594 
4595  HtpState *htp_state = NULL;
4596  char input[] = "\
4597 %YAML 1.1\n\
4598 ---\n\
4599 libhtp:\n\
4600 \n\
4601  default-config:\n\
4602  personality: IDS\n\
4603 ";
4604 
4606  SCConfInit();
4608  SCConfYamlLoadString(input, strlen(input));
4609  HTPConfigure();
4610  const char *addr = "4.3.2.1";
4611  memset(&ssn, 0, sizeof(ssn));
4612 
4613  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4614  FAIL_IF_NULL(f);
4615  f->protoctx = &ssn;
4616  f->proto = IPPROTO_TCP;
4617  f->alproto = ALPROTO_HTTP1;
4618 
4619  StreamTcpInitConfig(true);
4620 
4621  uint32_t u;
4622  for (u = 0; u < httplen1; u++) {
4623  uint8_t flags = 0;
4624 
4625  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4626  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4627  else flags = STREAM_TOSERVER;
4628 
4629  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4630  FAIL_IF(r != 0);
4631  }
4632 
4633  htp_state = f->alstate;
4634  FAIL_IF_NULL(htp_state);
4635 
4636  uint8_t ref1[] = "/blah/";
4637  size_t reflen = sizeof(ref1) - 1;
4638 
4639  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4640  FAIL_IF_NULL(tx);
4641  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4642  FAIL_IF_NULL(request_uri_normalized);
4643  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4644 
4645  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4646 
4647  UTHFreeFlow(f);
4649  HTPFreeConfig();
4650  SCConfDeInit();
4653  StreamTcpFreeConfig(true);
4654  PASS;
4655 }
4656 
4657 /** \test Test 'proxy' URI normalization. Ticket 1008
4658  */
4659 static int HTPParserDecodingTest09(void)
4660 {
4661  Flow *f = NULL;
4662  uint8_t httpbuf1[] =
4663  "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n";
4664  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4665  TcpSession ssn;
4667 
4668  HtpState *htp_state = NULL;
4669  char input[] = "\
4670 %YAML 1.1\n\
4671 ---\n\
4672 libhtp:\n\
4673 \n\
4674  default-config:\n\
4675  personality: IDS\n\
4676  uri-include-all: true\n\
4677 ";
4678 
4680  SCConfInit();
4682  SCConfYamlLoadString(input, strlen(input));
4683  HTPConfigure();
4684  const char *addr = "4.3.2.1";
4685  memset(&ssn, 0, sizeof(ssn));
4686 
4687  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4688  FAIL_IF_NULL(f);
4689  f->protoctx = &ssn;
4690  f->proto = IPPROTO_TCP;
4691  f->alproto = ALPROTO_HTTP1;
4692 
4693  StreamTcpInitConfig(true);
4694 
4695  uint32_t u;
4696  for (u = 0; u < httplen1; u++) {
4697  uint8_t flags = 0;
4698 
4699  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4700  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4701  else flags = STREAM_TOSERVER;
4702 
4703  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4704  FAIL_IF(r != 0);
4705  }
4706 
4707  htp_state = f->alstate;
4708  FAIL_IF_NULL(htp_state);
4709 
4710  uint8_t ref1[] = "http://suricata-ids.org/blah/";
4711  size_t reflen = sizeof(ref1) - 1;
4712 
4713  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4714  FAIL_IF_NULL(tx);
4715  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4716  FAIL_IF_NULL(request_uri_normalized);
4717  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4718 
4719  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4720 
4721  UTHFreeFlow(f);
4723  HTPFreeConfig();
4724  SCConfDeInit();
4727  StreamTcpFreeConfig(true);
4728  PASS;
4729 }
4730 
4731 /** \test BG box crash -- chunks are messed up. Observed for real. */
4732 static int HTPBodyReassemblyTest01(void)
4733 {
4734  HtpTxUserData htud;
4735  memset(&htud, 0x00, sizeof(htud));
4736  HtpState hstate;
4737  memset(&hstate, 0x00, sizeof(hstate));
4738  Flow flow;
4739  memset(&flow, 0x00, sizeof(flow));
4741  htp_cfg_t *cfg = htp_config_create();
4742  BUG_ON(cfg == NULL);
4743  htp_connp_t *connp = htp_connp_create(cfg);
4744  BUG_ON(connp == NULL);
4745  const htp_tx_t *tx = htp_connp_get_request_tx(connp);
4746  BUG_ON(tx == NULL);
4747 
4748  hstate.f = &flow;
4749  flow.alparser = parser;
4750 
4751  uint8_t chunk1[] = "--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r";
4752  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";
4753 
4754  int r = HtpBodyAppendChunk(&htud.request_body, chunk1, sizeof(chunk1) - 1);
4755  BUG_ON(r != 0);
4756  r = HtpBodyAppendChunk(&htud.request_body, chunk2, sizeof(chunk2) - 1);
4757  BUG_ON(r != 0);
4758 
4759  const uint8_t *chunks_buffer = NULL;
4760  uint32_t chunks_buffer_len = 0;
4761 
4762  HtpRequestBodyReassemble(&htud, &chunks_buffer, &chunks_buffer_len);
4763  FAIL_IF_NULL(chunks_buffer);
4764 #ifdef PRINT
4765  printf("REASSCHUNK START: \n");
4766  PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
4767  printf("REASSCHUNK END: \n");
4768 #endif
4769 
4770  htud.mime_state = SCMimeStateInit((const uint8_t *)"multipart/form-data; boundary=toto",
4771  strlen("multipart/form-data; boundary=toto"));
4772  FAIL_IF_NULL(htud.mime_state);
4773  htud.tsflags |= HTP_BOUNDARY_SET;
4774  HtpRequestBodyHandleMultipart(&hstate, &htud, &tx, chunks_buffer, chunks_buffer_len, false);
4775 
4777 
4779 
4780  PASS;
4781 }
4782 
4783 /** \test BG crash */
4784 static int HTPSegvTest01(void)
4785 {
4786  Flow *f = NULL;
4787  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";
4788  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4789  char input[] = "\
4790 %YAML 1.1\n\
4791 ---\n\
4792 libhtp:\n\
4793 \n\
4794  default-config:\n\
4795  personality: IDS\n\
4796  double-decode-path: no\n\
4797  double-decode-query: no\n\
4798  request-body-limit: 0\n\
4799  response-body-limit: 0\n\
4800 ";
4801 
4803  SCConfInit();
4805  SCConfYamlLoadString(input, strlen(input));
4806  HTPConfigure();
4807 
4808  TcpSession ssn;
4809  HtpState *http_state = NULL;
4811 
4812  memset(&ssn, 0, sizeof(ssn));
4813 
4814  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4815  FAIL_IF_NULL(f);
4816  f->protoctx = &ssn;
4817  f->proto = IPPROTO_TCP;
4818  f->alproto = ALPROTO_HTTP1;
4819 
4820  StreamTcpInitConfig(true);
4821 
4822  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
4823  int r = AppLayerParserParse(
4824  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
4825  FAIL_IF(r != 0);
4826  SCLogDebug("\n>>>> processing chunk 1 again <<<<\n");
4827  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
4828  FAIL_IF(r != 0);
4829 
4830  http_state = f->alstate;
4831  FAIL_IF_NULL(http_state);
4832 
4834  FAIL_IF_NOT_NULL(decoder_events);
4835 
4836  UTHFreeFlow(f);
4838  HTPFreeConfig();
4839  SCConfDeInit();
4842  StreamTcpFreeConfig(true);
4843  PASS;
4844 }
4845 
4846 /** \test Test really long request, this should result in HTP_LOG_CODE_REQUEST_FIELD_TOO_LONG */
4847 static int HTPParserTest14(void)
4848 {
4849  size_t len = 18887;
4850  TcpSession ssn;
4851  char input[] = "\
4852 %YAML 1.1\n\
4853 ---\n\
4854 libhtp:\n\
4855 \n\
4856  default-config:\n\
4857  personality: IDS\n\
4858  double-decode-path: no\n\
4859  double-decode-query: no\n\
4860  request-body-limit: 0\n\
4861  response-body-limit: 0\n\
4862 ";
4865 
4866  memset(&ssn, 0, sizeof(ssn));
4867 
4869  SCConfInit();
4871  SCConfYamlLoadString(input, strlen(input));
4872  HTPConfigure();
4873 
4874  char *httpbuf = SCMalloc(len);
4875  FAIL_IF_NULL(httpbuf);
4876  memset(httpbuf, 0x00, len);
4877 
4878  /* create the request with a longer than 18k cookie */
4879  strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n"
4880  "Host: myhost.lan\r\n"
4881  "Connection: keep-alive\r\n"
4882  "Accept: */*\r\n"
4883  "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"
4884  "Referer: http://blah.lan/\r\n"
4885  "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
4886  "Cookie: ", len);
4887  size_t o = strlen(httpbuf);
4888  for ( ; o < len - 4; o++) {
4889  httpbuf[o] = 'A';
4890  }
4891  httpbuf[len - 4] = '\r';
4892  httpbuf[len - 3] = '\n';
4893  httpbuf[len - 2] = '\r';
4894  httpbuf[len - 1] = '\n';
4895 
4896  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4897  FAIL_IF_NULL(f);
4898  f->protoctx = &ssn;
4899  f->alproto = ALPROTO_HTTP1;
4900  f->proto = IPPROTO_TCP;
4901 
4902  StreamTcpInitConfig(true);
4903 
4904  uint32_t u;
4905  for (u = 0; u < len; u++) {
4906  uint8_t flags = 0;
4907 
4908  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4909  else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4910  else flags = STREAM_TOSERVER;
4911 
4912  (void)AppLayerParserParse(
4913  NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)&httpbuf[u], 1);
4914  }
4915  HtpState *htp_state = f->alstate;
4916  FAIL_IF_NULL(htp_state);
4917 
4918  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4919  FAIL_IF_NULL(tx);
4920  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
4921  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
4922 
4923  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
4924  AppLayerDecoderEvents *decoder_events =
4925  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
4926  FAIL_IF_NULL(decoder_events);
4927 
4928  FAIL_IF(decoder_events->events[0] != HTP_LOG_CODE_REQUEST_FIELD_TOO_LONG);
4929 
4930  UTHFreeFlow(f);
4932  StreamTcpFreeConfig(true);
4933  SCFree(httpbuf);
4934  HTPFreeConfig();
4935  SCConfDeInit();
4938  PASS;
4939 }
4940 
4941 /** \test Test really long request (same as HTPParserTest14), now with config
4942  * update to allow it */
4943 static int HTPParserTest15(void)
4944 {
4945  Flow *f = NULL;
4946  char *httpbuf = NULL;
4947  size_t len = 18887;
4948  TcpSession ssn;
4949  HtpState *htp_state = NULL;
4950  char input[] = "\
4951 %YAML 1.1\n\
4952 ---\n\
4953 libhtp:\n\
4954 \n\
4955  default-config:\n\
4956  personality: IDS\n\
4957  double-decode-path: no\n\
4958  double-decode-query: no\n\
4959  request-body-limit: 0\n\
4960  response-body-limit: 0\n\
4961  meta-field-limit: 20000\n\
4962 ";
4964 
4965  memset(&ssn, 0, sizeof(ssn));
4966 
4968  SCConfInit();
4970  SCConfYamlLoadString(input, strlen(input));
4971  HTPConfigure();
4972 
4973  httpbuf = SCMalloc(len);
4974  FAIL_IF_NULL(httpbuf);
4975 
4976  memset(httpbuf, 0x00, len);
4977 
4978  /* create the request with a longer than 18k cookie */
4979  strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n"
4980  "Host: myhost.lan\r\n"
4981  "Connection: keep-alive\r\n"
4982  "Accept: */*\r\n"
4983  "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"
4984  "Referer: http://blah.lan/\r\n"
4985  "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
4986  "Cookie: ", len);
4987  size_t o = strlen(httpbuf);
4988  for ( ; o < len - 4; o++) {
4989  httpbuf[o] = 'A';
4990  }
4991  httpbuf[len - 4] = '\r';
4992  httpbuf[len - 3] = '\n';
4993  httpbuf[len - 2] = '\r';
4994  httpbuf[len - 1] = '\n';
4995 
4996  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4997  FAIL_IF_NULL(f);
4998  f->protoctx = &ssn;
4999  f->proto = IPPROTO_TCP;
5000  f->alproto = ALPROTO_HTTP1;
5001 
5002  StreamTcpInitConfig(true);
5003 
5004  uint32_t u;
5005  for (u = 0; u < len; u++) {
5006  uint8_t flags = 0;
5007 
5008  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5009  else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5010  else flags = STREAM_TOSERVER;
5011 
5012  int r = AppLayerParserParse(
5013  NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)&httpbuf[u], 1);
5014  FAIL_IF(r != 0);
5015  }
5016  htp_state = f->alstate;
5017  FAIL_IF_NULL(htp_state);
5018 
5019  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5020  FAIL_IF_NULL(tx);
5021  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5022  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5023 
5024  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
5025  AppLayerDecoderEvents *decoder_events =
5026  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
5027  FAIL_IF_NOT_NULL(decoder_events);
5028 
5029  UTHFreeFlow(f);
5031  StreamTcpFreeConfig(true);
5032  SCFree(httpbuf);
5033  HTPFreeConfig();
5034  SCConfDeInit();
5037  PASS;
5038 }
5039 
5040 /** \test Test unusual delims in request line HTP_LOG_CODE_REQUEST_FIELD_TOO_LONG */
5041 static int HTPParserTest16(void)
5042 {
5043  Flow *f = NULL;
5044  TcpSession ssn;
5045  HtpState *htp_state = NULL;
5047 
5048  memset(&ssn, 0, sizeof(ssn));
5049 
5050  uint8_t httpbuf[] = "GET\f/blah/\fHTTP/1.1\r\n"
5051  "Host: myhost.lan\r\n"
5052  "Connection: keep-alive\r\n"
5053  "Accept: */*\r\n"
5054  "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"
5055  "Referer: http://blah.lan/\r\n"
5056  "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
5057  "Cookie: blah\r\n\r\n";
5058  size_t len = sizeof(httpbuf) - 1;
5059 
5060  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5061  FAIL_IF_NULL(f);
5062  f->protoctx = &ssn;
5063  f->proto = IPPROTO_TCP;
5064  f->alproto = ALPROTO_HTTP1;
5065 
5066  StreamTcpInitConfig(true);
5067 
5068  uint8_t flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
5069 
5070  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)httpbuf, len);
5071  FAIL_IF(r != 0);
5072 
5073  htp_state = f->alstate;
5074  FAIL_IF_NULL(htp_state);
5075 
5076  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5077  FAIL_IF_NULL(tx);
5078  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5079  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5080 
5081 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
5082 //these events are disabled during fuzzing as they are too noisy and consume much resource
5083  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
5084  AppLayerDecoderEvents *decoder_events =
5085  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
5086 
5087  FAIL_IF_NULL(decoder_events);
5088  FAIL_IF(decoder_events->events[0] != HTP_LOG_CODE_METHOD_DELIM_NON_COMPLIANT);
5089  FAIL_IF(decoder_events->events[1] != HTP_LOG_CODE_URI_DELIM_NON_COMPLIANT);
5090 #endif
5091 
5092  UTHFreeFlow(f);
5094  StreamTcpFreeConfig(true);
5095  PASS;
5096 }
5097 
5098 /** \test Test response not HTTP
5099  */
5100 static int HTPParserTest20(void)
5101 {
5102  Flow *f = NULL;
5103  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5104  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5105  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5106  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5107  uint8_t httpbuf2[] = "NOTHTTP\r\nSOMEOTHERDATA";
5108  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5109  uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA";
5110  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
5111  TcpSession ssn;
5112  HtpState *http_state = NULL;
5115 
5116  memset(&ssn, 0, sizeof(ssn));
5117 
5118  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5119  FAIL_IF_NULL(f);
5120  f->protoctx = &ssn;
5121  f->proto = IPPROTO_TCP;
5122  f->alproto = ALPROTO_HTTP1;
5123 
5124  StreamTcpInitConfig(true);
5125 
5126  int r = AppLayerParserParse(
5127  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5128  FAIL_IF(r != 0);
5129 
5130  r = AppLayerParserParse(
5131  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5132  FAIL_IF(r != 0);
5133 
5134  r = AppLayerParserParse(
5135  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf3, httplen3);
5136  FAIL_IF(r != 0);
5137 
5138  http_state = f->alstate;
5139  FAIL_IF_NULL(http_state);
5140  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5141  FAIL_IF_NULL(tx);
5142  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5143  FAIL_IF_NULL(h);
5144 
5145  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5146  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5147 
5148  FAIL_IF(htp_tx_response_status_number(tx) != 0);
5149  FAIL_IF(htp_tx_response_protocol_number(tx) != -1);
5150 
5151  UTHFreeFlow(f);
5153  StreamTcpFreeConfig(true);
5154  PASS;
5155 }
5156 
5157 /** \test Test response not HTTP
5158  */
5159 static int HTPParserTest21(void)
5160 {
5161  Flow *f = NULL;
5162  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5163  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5164  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5165  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5166  uint8_t httpbuf2[] = "999 NOTHTTP REALLY\r\nSOMEOTHERDATA\r\n";
5167  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5168  uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA";
5169  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
5170  TcpSession ssn;
5171  HtpState *http_state = NULL;
5174 
5175  memset(&ssn, 0, sizeof(ssn));
5176 
5177  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5178  FAIL_IF_NULL(f);
5179  f->protoctx = &ssn;
5180  f->proto = IPPROTO_TCP;
5181  f->alproto = ALPROTO_HTTP1;
5182 
5183  StreamTcpInitConfig(true);
5184 
5185  int r = AppLayerParserParse(
5186  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5187  FAIL_IF(r != 0);
5188 
5189  r = AppLayerParserParse(
5190  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5191  FAIL_IF(r != 0);
5192 
5193  r = AppLayerParserParse(
5194  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf3, httplen3);
5195  FAIL_IF(r != 0);
5196 
5197  http_state = f->alstate;
5198  FAIL_IF_NULL(http_state);
5199  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5200  FAIL_IF_NULL(tx);
5201  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5202  FAIL_IF_NULL(h);
5203 
5204  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5205  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5206 
5207  FAIL_IF(htp_tx_response_status_number(tx) != 0);
5208  FAIL_IF(htp_tx_response_protocol_number(tx) != -1);
5209 
5210  UTHFreeFlow(f);
5212  StreamTcpFreeConfig(true);
5213  PASS;
5214 }
5215 
5216 /** \test Test response not HTTP
5217  */
5218 static int HTPParserTest22(void)
5219 {
5220  Flow *f = NULL;
5221  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5222  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5223  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5224  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5225  uint8_t httpbuf2[] = "\r\n0000=0000000/ASDF3_31.zip, 456723\r\n"
5226  "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
5227  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5228  TcpSession ssn;
5229  HtpState *http_state = NULL;
5232 
5233  memset(&ssn, 0, sizeof(ssn));
5234 
5235  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5236  FAIL_IF_NULL(f);
5237  f->protoctx = &ssn;
5238  f->proto = IPPROTO_TCP;
5239  f->alproto = ALPROTO_HTTP1;
5240 
5241  StreamTcpInitConfig(true);
5242 
5243  int r = AppLayerParserParse(
5244  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5245  FAIL_IF(r != 0);
5246 
5247  r = AppLayerParserParse(
5248  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5249  FAIL_IF(r != 0);
5250 
5251  http_state = f->alstate;
5252  FAIL_IF_NULL(http_state);
5253  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5254  FAIL_IF_NULL(tx);
5255  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5256  FAIL_IF_NULL(h);
5257 
5258  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5259  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5260 
5261  FAIL_IF(htp_tx_response_status_number(tx) != -0);
5262  FAIL_IF(htp_tx_response_protocol_number(tx) != -1);
5263 
5264  UTHFreeFlow(f);
5266  StreamTcpFreeConfig(true);
5267  PASS;
5268 }
5269 
5270 /** \test Test response not HTTP
5271  */
5272 static int HTPParserTest23(void)
5273 {
5274  Flow *f = NULL;
5275  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5276  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5277  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5278  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5279  uint8_t httpbuf2[] = "HTTP0000=0000000/ASDF3_31.zip, 456723\r\n"
5280  "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
5281  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5282  TcpSession ssn;
5283  HtpState *http_state = NULL;
5286 
5287  memset(&ssn, 0, sizeof(ssn));
5288 
5289  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5290  FAIL_IF_NULL(f);
5291  f->protoctx = &ssn;
5292  f->proto = IPPROTO_TCP;
5293  f->alproto = ALPROTO_HTTP1;
5294 
5295  StreamTcpInitConfig(true);
5296 
5297  int r = AppLayerParserParse(
5298  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5299  FAIL_IF(r != 0);
5300 
5301  r = AppLayerParserParse(
5302  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5303  FAIL_IF(r != 0);
5304 
5305  http_state = f->alstate;
5306  FAIL_IF_NULL(http_state);
5307  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5308  FAIL_IF_NULL(tx);
5309  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5310  FAIL_IF_NULL(h);
5311 
5312  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5313  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5314 
5315  FAIL_IF(htp_tx_response_status_number(tx) != -1);
5316  FAIL_IF(htp_tx_response_protocol_number(tx) != -2);
5317 
5318  UTHFreeFlow(f);
5319 
5321  StreamTcpFreeConfig(true);
5322  PASS;
5323 }
5324 
5325 /** \test Test response not HTTP
5326  */
5327 static int HTPParserTest24(void)
5328 {
5329  Flow *f = NULL;
5330  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5331  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5332  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5333  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5334  uint8_t httpbuf2[] = "HTTP/1.0 0000=0000000/ASDF3_31.zip, 456723\r\n"
5335  "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
5336  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5337  TcpSession ssn;
5338  HtpState *http_state = NULL;
5341 
5342  memset(&ssn, 0, sizeof(ssn));
5343 
5344  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5345  FAIL_IF_NULL(f);
5346  f->protoctx = &ssn;
5347  f->proto = IPPROTO_TCP;
5348  f->alproto = ALPROTO_HTTP1;
5349 
5350  StreamTcpInitConfig(true);
5351 
5352  int r = AppLayerParserParse(
5353  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5354  FAIL_IF(r != 0);
5355 
5356  r = AppLayerParserParse(
5357  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5358  FAIL_IF(r != 0);
5359 
5360  http_state = f->alstate;
5361  FAIL_IF_NULL(http_state);
5362  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5363  FAIL_IF_NULL(tx);
5364  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5365  FAIL_IF_NULL(h);
5366 
5367  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5368  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5369 
5370  FAIL_IF(htp_tx_response_status_number(tx) != -1);
5371  FAIL_IF(htp_tx_response_protocol_number(tx) != HTP_PROTOCOL_V1_0);
5372 
5373  UTHFreeFlow(f);
5374 
5376  StreamTcpFreeConfig(true);
5377  PASS;
5378 }
5379 
5380 /** \test multi transactions and cleanup */
5381 static int HTPParserTest25(void)
5382 {
5385 
5386  StreamTcpInitConfig(true);
5387  TcpSession ssn;
5388  memset(&ssn, 0, sizeof(ssn));
5389 
5390  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5391  FAIL_IF_NULL(f);
5392  f->protoctx = &ssn;
5393  f->proto = IPPROTO_TCP;
5394  f->alproto = ALPROTO_HTTP1;
5396 
5397  const char *str = "GET / HTTP/1.1\r\nHost: www.google.com\r\nUser-Agent: Suricata/1.0\r\n\r\n";
5398  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START,
5399  (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  r = AppLayerParserParse(
5408  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5409  FAIL_IF_NOT(r == 0);
5410  r = AppLayerParserParse(
5411  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5412  FAIL_IF_NOT(r == 0);
5413  r = AppLayerParserParse(
5414  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5415  FAIL_IF_NOT(r == 0);
5416  r = AppLayerParserParse(
5417  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5418  FAIL_IF_NOT(r == 0);
5419  r = AppLayerParserParse(
5420  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5421  FAIL_IF_NOT(r == 0);
5422 
5423  str = "HTTP 1.1 200 OK\r\nServer: Suricata/1.0\r\nContent-Length: 8\r\n\r\nSuricata";
5424  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START,
5425  (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  r = AppLayerParserParse(
5434  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5435  FAIL_IF_NOT(r == 0);
5436  r = AppLayerParserParse(
5437  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5438  FAIL_IF_NOT(r == 0);
5439  r = AppLayerParserParse(
5440  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5441  FAIL_IF_NOT(r == 0);
5442  r = AppLayerParserParse(
5443  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5444  FAIL_IF_NOT(r == 0);
5445  r = AppLayerParserParse(
5446  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5447  FAIL_IF_NOT(r == 0);
5448 
5449  AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
5450 
5451  uint64_t ret[4];
5452  UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
5453  FAIL_IF_NOT(ret[0] == 8); // inspect_id[0]
5454  FAIL_IF_NOT(ret[1] == 8); // inspect_id[1]
5455  FAIL_IF_NOT(ret[2] == 8); // log_id
5456  FAIL_IF_NOT(ret[3] == 8); // min_id
5457 
5458  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF,
5459  (uint8_t *)str, strlen(str));
5460  FAIL_IF_NOT(r == 0);
5461  AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
5462 
5463  UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
5464  FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] not updated by ..Cleanup() until full tx is done
5465  FAIL_IF_NOT(ret[1] == 8); // inspect_id[1]
5466  FAIL_IF_NOT(ret[2] == 8); // log_id
5467  FAIL_IF_NOT(ret[3] == 8); // min_id
5468 
5469  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_EOF,
5470  (uint8_t *)str, strlen(str));
5471  FAIL_IF_NOT(r == 0);
5472  AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
5473 
5474  UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
5475  FAIL_IF_NOT(ret[0] == 9); // inspect_id[0]
5476  FAIL_IF_NOT(ret[1] == 9); // inspect_id[1]
5477  FAIL_IF_NOT(ret[2] == 9); // log_id
5478  FAIL_IF_NOT(ret[3] == 9); // min_id
5479 
5480  HtpState *http_state = f->alstate;
5481  FAIL_IF_NULL(http_state);
5482 
5483  UTHFreeFlow(f);
5484 
5486  StreamTcpFreeConfig(true);
5487 
5488  PASS;
5489 }
5490 
5491 static int HTPParserTest26(void)
5492 {
5493  char input[] = "\
5494 %YAML 1.1\n\
5495 ---\n\
5496 libhtp:\n\
5497 \n\
5498  default-config:\n\
5499  personality: IDS\n\
5500  request-body-limit: 1\n\
5501  response-body-limit: 1\n\
5502 ";
5504  SCConfInit();
5506  SCConfYamlLoadString(input, strlen(input));
5507  HTPConfigure();
5508 
5509  Packet *p1 = NULL;
5510  Packet *p2 = NULL;
5511  ThreadVars th_v;
5512  DetectEngineCtx *de_ctx = NULL;
5513  DetectEngineThreadCtx *det_ctx = NULL;
5514  Flow f;
5515  uint8_t httpbuf1[] = "GET /alice.txt HTTP/1.1\r\n\r\n";
5516  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5517  uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\n"
5518  "Content-Type: text/plain\r\n"
5519  "Content-Length: 228\r\n\r\n"
5520  "Alice was beginning to get very tired of sitting by her sister on the bank."
5521  "Alice was beginning to get very tired of sitting by her sister on the bank.";
5522  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5523  uint8_t httpbuf3[] = "Alice was beginning to get very tired of sitting by her sister on the bank.\r\n\r\n";
5524  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
5525  TcpSession ssn;
5526  HtpState *http_state = NULL;
5529 
5530  memset(&th_v, 0, sizeof(th_v));
5531  memset(&f, 0, sizeof(f));
5532  memset(&ssn, 0, sizeof(ssn));
5533 
5534  p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
5535  p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
5536 
5537  FLOW_INITIALIZE(&f);
5538  f.protoctx = (void *)&ssn;
5539  f.proto = IPPROTO_TCP;
5540  f.flags |= FLOW_IPV4;
5541 
5542  p1->flow = &f;
5546  p2->flow = &f;
5550  f.alproto = ALPROTO_HTTP1;
5551 
5552  StreamTcpInitConfig(true);
5553 
5556 
5557  de_ctx->flags |= DE_QUIET;
5558 
5559  de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any "
5560  "(filestore; sid:1; rev:1;)");
5562 
5564  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
5565 
5566  int r = AppLayerParserParse(
5567  &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
5568  FAIL_IF(r != 0);
5569 
5570  http_state = f.alstate;
5571  FAIL_IF_NULL(http_state);
5572 
5573  /* do detect */
5574  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
5575 
5576  FAIL_IF((PacketAlertCheck(p1, 1)));
5577 
5578  /* do detect */
5579  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
5580 
5581  FAIL_IF((PacketAlertCheck(p1, 1)));
5582 
5583  r = AppLayerParserParse(
5584  &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf2, httplen2);
5585  FAIL_IF(r != 0);
5586 
5587  http_state = f.alstate;
5588  FAIL_IF_NULL(http_state);
5589 
5590  /* do detect */
5591  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
5592 
5593  FAIL_IF(!(PacketAlertCheck(p2, 1)));
5594 
5595  r = AppLayerParserParse(
5596  &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf3, httplen3);
5597  FAIL_IF(r != 0);
5598 
5599  http_state = f.alstate;
5600  FAIL_IF_NULL(http_state);
5601 
5602  void *tx_ptr = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
5603  FAIL_IF_NULL(tx_ptr);
5604 
5605  AppLayerGetFileState files = HTPGetTxFiles(tx_ptr, STREAM_TOCLIENT);
5606  FileContainer *ffc = files.fc;
5607  FAIL_IF_NULL(ffc);
5608 
5609  File *ptr = ffc->head;
5610  FAIL_IF(ptr->state != FILE_STATE_CLOSED);
5611 
5612  FLOW_DESTROY(&f);
5613  UTHFreePackets(&p1, 1);
5614  UTHFreePackets(&p2, 1);
5615 
5617  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
5619  StreamTcpFreeConfig(true);
5620 
5621  HTPFreeConfig();
5622  SCConfDeInit();
5625  PASS;
5626 }
5627 
5628 static int HTPParserTest27(void)
5629 {
5630  HTPCfgDir cfg;
5631  memset(&cfg, 0, sizeof(cfg));
5632  cfg.body_limit = 1500;
5634 
5635  uint32_t len = 1000;
5636 
5637  HtpTxUserData *tx_ud = SCMalloc(sizeof(HtpTxUserData));
5638  FAIL_IF_NULL(tx_ud);
5639 
5640  tx_ud->tsflags |= HTP_STREAM_DEPTH_SET;
5641  tx_ud->request_body.content_len_so_far = 2500;
5642 
5643  FAIL_IF(AppLayerHtpCheckDepth(&cfg, &tx_ud->request_body, tx_ud->tsflags));
5644 
5645  len = AppLayerHtpComputeChunkLength(tx_ud->request_body.content_len_so_far,
5646  0,
5648  tx_ud->tsflags,
5649  len);
5650  FAIL_IF(len != 1000);
5651 
5652  SCFree(tx_ud);
5653 
5654  PASS;
5655 }
5656 
5657 /**
5658  * \brief Register the Unit tests for the HTTP protocol
5659  */
5660 static void HTPParserRegisterTests(void)
5661 {
5662  UtRegisterTest("HTPParserTest01", HTPParserTest01);
5663  UtRegisterTest("HTPParserTest01a", HTPParserTest01a);
5664  UtRegisterTest("HTPParserTest01b", HTPParserTest01b);
5665  UtRegisterTest("HTPParserTest01c", HTPParserTest01c);
5666  UtRegisterTest("HTPParserTest02", HTPParserTest02);
5667  UtRegisterTest("HTPParserTest03", HTPParserTest03);
5668  UtRegisterTest("HTPParserTest04", HTPParserTest04);
5669  UtRegisterTest("HTPParserTest05", HTPParserTest05);
5670  UtRegisterTest("HTPParserTest06", HTPParserTest06);
5671  UtRegisterTest("HTPParserTest07", HTPParserTest07);
5672  UtRegisterTest("HTPParserTest08", HTPParserTest08);
5673  UtRegisterTest("HTPParserTest09", HTPParserTest09);
5674  UtRegisterTest("HTPParserTest10", HTPParserTest10);
5675  UtRegisterTest("HTPParserTest11", HTPParserTest11);
5676  UtRegisterTest("HTPParserTest12", HTPParserTest12);
5677  UtRegisterTest("HTPParserTest13", HTPParserTest13);
5678  UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01);
5679  UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02);
5680  UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03);
5681 
5682  UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01);
5683  UtRegisterTest("HTPParserDecodingTest01a", HTPParserDecodingTest01a);
5684  UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02);
5685  UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03);
5686  UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04);
5687  UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05);
5688  UtRegisterTest("HTPParserDecodingTest06", HTPParserDecodingTest06);
5689  UtRegisterTest("HTPParserDecodingTest07", HTPParserDecodingTest07);
5690  UtRegisterTest("HTPParserDecodingTest08", HTPParserDecodingTest08);
5691  UtRegisterTest("HTPParserDecodingTest09", HTPParserDecodingTest09);
5692 
5693  UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01);
5694 
5695  UtRegisterTest("HTPSegvTest01", HTPSegvTest01);
5696 
5697  UtRegisterTest("HTPParserTest14", HTPParserTest14);
5698  UtRegisterTest("HTPParserTest15", HTPParserTest15);
5699  UtRegisterTest("HTPParserTest16", HTPParserTest16);
5700  UtRegisterTest("HTPParserTest20", HTPParserTest20);
5701  UtRegisterTest("HTPParserTest21", HTPParserTest21);
5702  UtRegisterTest("HTPParserTest22", HTPParserTest22);
5703  UtRegisterTest("HTPParserTest23", HTPParserTest23);
5704  UtRegisterTest("HTPParserTest24", HTPParserTest24);
5705  UtRegisterTest("HTPParserTest25", HTPParserTest25);
5706  UtRegisterTest("HTPParserTest26", HTPParserTest26);
5707  UtRegisterTest("HTPParserTest27", HTPParserTest27);
5708 
5711 }
5712 #endif /* UNITTESTS */
5713 
5714 /**
5715  * @}
5716  */
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:574
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:1253
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:270
FLOW_SGH_TOCLIENT
#define FLOW_SGH_TOCLIENT
Definition: flow.h:75
AppLayerHtpPrintStats
void AppLayerHtpPrintStats(void)
Definition: app-layer-htp.c:2424
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:86
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
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:2174
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:2513
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:919
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:2624
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:330
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:2349
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
AppLayerGetTxIterState::u64
uint64_t u64
Definition: app-layer-parser.h:124
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:2353
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
AppLayerParserTriggerRawStreamInspection
void AppLayerParserTriggerRawStreamInspection(Flow *f, int direction)
Definition: app-layer-parser.c:1556
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:2689
HTP_CONFIG_DEFAULT_FIELD_LIMIT
#define HTP_CONFIG_DEFAULT_FIELD_LIMIT
Definition: app-layer-htp.h:48
DetectEngineThreadCtx_
Definition: detect.h:1211
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:547
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:272
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:3350
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:1579
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:250
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:2996
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:274
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:1840
HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT
#define HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT
Definition: app-layer-htp.h:42
app-layer-htp-body.h
AppLayerGetTxIterState
Definition: app-layer-parser.h:121
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:288
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:560
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:225
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:2130
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:1485
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:292
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:3576
HTP_BOUNDARY_SET
#define HTP_BOUNDARY_SET
Definition: app-layer-htp.h:144
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:231
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:503
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:928
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:2694
StreamingBufferConfig_
Definition: util-streaming-buffer.h:65
FileContainerRecycle
void FileContainerRecycle(FileContainer *ffc, const StreamingBufferConfig *cfg)
Recycle a FileContainer.
Definition: util-file.c:496
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
AppLayerParserRegisterGetTxIterator
void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto, AppLayerGetTxIteratorFunc Func)
Definition: app-layer-parser.c:539
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:262
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:2618
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:2585
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:921
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:1592
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:1829
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:276
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:1249
AppLayerGetTxIterState::un
union AppLayerGetTxIterState::@7 un
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