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