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