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