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