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