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 
2523  /* don't convert + to space by default */
2524  htp_config_set_plusspace_decode(cfg_prec->cfg, HTP_DECODER_URLENCODED, 0);
2525  // enables request decompression
2526  htp_config_set_request_decompression(cfg_prec->cfg, 1);
2527 #ifdef HAVE_HTP_CONFIG_SET_LZMA_LAYERS
2528  // disable by default
2529  htp_config_set_lzma_layers(cfg_prec->cfg, HTP_CONFIG_DEFAULT_LZMA_LAYERS);
2530 #endif
2531 #ifdef HAVE_HTP_CONFIG_SET_LZMA_MEMLIMIT
2532  htp_config_set_lzma_memlimit(cfg_prec->cfg,
2534 #endif
2535 #ifdef HAVE_HTP_CONFIG_SET_COMPRESSION_BOMB_LIMIT
2536  htp_config_set_compression_bomb_limit(cfg_prec->cfg,
2538 #endif
2539 #ifdef HAVE_HTP_CONFIG_SET_COMPRESSION_TIME_LIMIT
2540  htp_config_set_compression_time_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_COMPRESSION_TIME_LIMIT);
2541 #endif
2542 #ifdef HAVE_HTP_CONFIG_SET_MAX_TX
2543 #define HTP_CONFIG_DEFAULT_MAX_TX_LIMIT 512
2544  htp_config_set_max_tx(cfg_prec->cfg, HTP_CONFIG_DEFAULT_MAX_TX_LIMIT);
2545 #endif
2546  /* libhtp <= 0.5.9 doesn't use soft limit, but it's impossible to set
2547  * only the hard limit. So we set both here to the (current) htp defaults.
2548  * The reason we do this is that if the user sets the hard limit in the
2549  * config, we have to set the soft limit as well. If libhtp starts using
2550  * the soft limit in the future, we at least make sure we control what
2551  * it's value is. */
2552  htp_config_set_field_limits(cfg_prec->cfg,
2555  return;
2556 }
2557 
2558 /* hack: htp random range code expects random values in range of 0-RAND_MAX,
2559  * but we can get both <0 and >RAND_MAX values from RandomGet
2560  */
2561 static int RandomGetWrap(void)
2562 {
2563  unsigned long r;
2564 
2565  do {
2566  r = RandomGet();
2567  } while(r >= ULONG_MAX - (ULONG_MAX % RAND_MAX));
2568 
2569  return r % RAND_MAX;
2570 }
2571 
2572 /*
2573  * We have this splitup so that in case double decoding has been enabled
2574  * for query and path, they would be called first on the callback queue,
2575  * before the callback set by Phase2() is called. We need this, since
2576  * the callback in Phase2() generates the normalized uri which utilizes
2577  * the query and path. */
2578 static void HTPConfigSetDefaultsPhase2(const char *name, HTPCfgRec *cfg_prec)
2579 {
2580  /* randomize inspection size if needed */
2581  if (cfg_prec->randomize) {
2582  int rdrange = cfg_prec->randomize_range;
2583 
2584  long int r = RandomGetWrap();
2585  cfg_prec->request.inspect_min_size += (int)(cfg_prec->request.inspect_min_size *
2586  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
2587 
2588  r = RandomGetWrap();
2589  cfg_prec->request.inspect_window += (int)(cfg_prec->request.inspect_window *
2590  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
2591  SCLogConfig("'%s' server has 'request-body-minimal-inspect-size' set to"
2592  " %u and 'request-body-inspect-window' set to %u after"
2593  " randomization.",
2594  name, cfg_prec->request.inspect_min_size, cfg_prec->request.inspect_window);
2595 
2596  r = RandomGetWrap();
2597  cfg_prec->response.inspect_min_size += (int)(cfg_prec->response.inspect_min_size *
2598  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
2599 
2600  r = RandomGetWrap();
2601  cfg_prec->response.inspect_window += (int)(cfg_prec->response.inspect_window *
2602  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
2603 
2604  SCLogConfig("'%s' server has 'response-body-minimal-inspect-size' set to"
2605  " %u and 'response-body-inspect-window' set to %u after"
2606  " randomization.",
2607  name, cfg_prec->response.inspect_min_size, cfg_prec->response.inspect_window);
2608  }
2609 
2610  htp_config_register_request_line(cfg_prec->cfg, HTPCallbackRequestLine);
2611  return;
2612 }
2613 
2614 static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s,
2615  SCRadixTree *tree)
2616 {
2617  if (cfg_prec == NULL || s == NULL || tree == NULL)
2618  return;
2619 
2620  ConfNode *p = NULL;
2621 
2622  /* Default Parameters */
2623  TAILQ_FOREACH(p, &s->head, next) {
2624 
2625  if (strcasecmp("address", p->name) == 0) {
2626  ConfNode *pval;
2627  /* Addresses */
2628  TAILQ_FOREACH(pval, &p->head, next) {
2629  SCLogDebug("LIBHTP server %s: %s=%s", s->name, p->name,
2630  pval->val);
2631 
2632  /* IPV6 or IPV4? */
2633  if (strchr(pval->val, ':') != NULL) {
2634  SCLogDebug("LIBHTP adding ipv6 server %s at %s: %p",
2635  s->name, pval->val, cfg_prec->cfg);
2636  if (!SCRadixAddKeyIPV6String(pval->val, tree, cfg_prec)) {
2637  SCLogWarning("LIBHTP failed to "
2638  "add ipv6 server %s, ignoring",
2639  pval->val);
2640  }
2641  } else {
2642  SCLogDebug("LIBHTP adding ipv4 server %s at %s: %p",
2643  s->name, pval->val, cfg_prec->cfg);
2644  if (!SCRadixAddKeyIPV4String(pval->val, tree, cfg_prec)) {
2645  SCLogWarning("LIBHTP failed "
2646  "to add ipv4 server %s, ignoring",
2647  pval->val);
2648  }
2649  } /* else - if (strchr(pval->val, ':') != NULL) */
2650  } /* TAILQ_FOREACH(pval, &p->head, next) */
2651 
2652  } else if (strcasecmp("personality", p->name) == 0) {
2653  /* Personalities */
2654  int personality = HTPLookupPersonality(p->val);
2655  SCLogDebug("LIBHTP default: %s = %s", p->name, p->val);
2656  SCLogDebug("LIBHTP default: %s = %s", p->name, p->val);
2657 
2658  if (personality >= 0) {
2659  SCLogDebug("LIBHTP default: %s=%s (%d)", p->name, p->val,
2660  personality);
2661  if (htp_config_set_server_personality(cfg_prec->cfg, personality) == HTP_ERROR){
2662  SCLogWarning("LIBHTP Failed adding "
2663  "personality \"%s\", ignoring",
2664  p->val);
2665  } else {
2666  SCLogDebug("LIBHTP personality set to %s",
2667  HTPLookupPersonalityString(personality));
2668  }
2669 
2670  /* The IDS personality by default converts the path (and due to
2671  * our query string callback also the query string) to lowercase.
2672  * Signatures do not expect this, so override it. */
2673  htp_config_set_convert_lowercase(cfg_prec->cfg, HTP_DECODER_URL_PATH, 0);
2674  } else {
2675  SCLogWarning("LIBHTP Unknown personality "
2676  "\"%s\", ignoring",
2677  p->val);
2678  continue;
2679  }
2680 
2681  } else if (strcasecmp("request-body-limit", p->name) == 0 ||
2682  strcasecmp("request_body_limit", p->name) == 0) {
2683  if (ParseSizeStringU32(p->val, &cfg_prec->request.body_limit) < 0) {
2684  SCLogError("Error parsing request-body-limit "
2685  "from conf file - %s. Killing engine",
2686  p->val);
2687  exit(EXIT_FAILURE);
2688  }
2689 
2690  } else if (strcasecmp("response-body-limit", p->name) == 0) {
2691  if (ParseSizeStringU32(p->val, &cfg_prec->response.body_limit) < 0) {
2692  SCLogError("Error parsing response-body-limit "
2693  "from conf file - %s. Killing engine",
2694  p->val);
2695  exit(EXIT_FAILURE);
2696  }
2697 
2698  } else if (strcasecmp("request-body-minimal-inspect-size", p->name) == 0) {
2699  if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_min_size) < 0) {
2700  SCLogError("Error parsing request-body-minimal-inspect-size "
2701  "from conf file - %s. Killing engine",
2702  p->val);
2703  exit(EXIT_FAILURE);
2704  }
2705 
2706  } else if (strcasecmp("request-body-inspect-window", p->name) == 0) {
2707  if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_window) < 0) {
2708  SCLogError("Error parsing request-body-inspect-window "
2709  "from conf file - %s. Killing engine",
2710  p->val);
2711  exit(EXIT_FAILURE);
2712  }
2713 
2714  } else if (strcasecmp("double-decode-query", p->name) == 0) {
2715  if (ConfValIsTrue(p->val)) {
2716  htp_config_register_request_line(cfg_prec->cfg,
2717  HTPCallbackDoubleDecodeQuery);
2718  }
2719 
2720  } else if (strcasecmp("double-decode-path", p->name) == 0) {
2721  if (ConfValIsTrue(p->val)) {
2722  htp_config_register_request_line(cfg_prec->cfg,
2723  HTPCallbackDoubleDecodePath);
2724  }
2725 
2726  } else if (strcasecmp("response-body-minimal-inspect-size", p->name) == 0) {
2727  if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_min_size) < 0) {
2728  SCLogError("Error parsing response-body-minimal-inspect-size "
2729  "from conf file - %s. Killing engine",
2730  p->val);
2731  exit(EXIT_FAILURE);
2732  }
2733 
2734  } else if (strcasecmp("response-body-inspect-window", p->name) == 0) {
2735  if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_window) < 0) {
2736  SCLogError("Error parsing response-body-inspect-window "
2737  "from conf file - %s. Killing engine",
2738  p->val);
2739  exit(EXIT_FAILURE);
2740  }
2741 
2742  } else if (strcasecmp("response-body-decompress-layer-limit", p->name) == 0) {
2743  uint32_t value = 2;
2744  if (ParseSizeStringU32(p->val, &value) < 0) {
2745  SCLogError("Error parsing response-body-inspect-window "
2746  "from conf file - %s. Killing engine",
2747  p->val);
2748  exit(EXIT_FAILURE);
2749  }
2750 #ifdef HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT
2751  htp_config_set_response_decompression_layer_limit(cfg_prec->cfg, value);
2752 #else
2753  SCLogWarning("can't set response-body-decompress-layer-limit "
2754  "to %u, libhtp version too old",
2755  value);
2756 #endif
2757  } else if (strcasecmp("path-convert-backslash-separators", p->name) == 0) {
2758  htp_config_set_backslash_convert_slashes(cfg_prec->cfg,
2759  HTP_DECODER_URL_PATH,
2760  ConfValIsTrue(p->val));
2761  } else if (strcasecmp("path-bestfit-replacement-char", p->name) == 0) {
2762  if (strlen(p->val) == 1) {
2763  htp_config_set_bestfit_replacement_byte(cfg_prec->cfg,
2764  HTP_DECODER_URL_PATH,
2765  p->val[0]);
2766  } else {
2767  SCLogError("Invalid entry "
2768  "for libhtp param path-bestfit-replacement-char");
2769  }
2770  } else if (strcasecmp("path-convert-lowercase", p->name) == 0) {
2771  htp_config_set_convert_lowercase(cfg_prec->cfg,
2772  HTP_DECODER_URL_PATH,
2773  ConfValIsTrue(p->val));
2774  } else if (strcasecmp("path-nul-encoded-terminates", p->name) == 0) {
2775  htp_config_set_nul_encoded_terminates(cfg_prec->cfg,
2776  HTP_DECODER_URL_PATH,
2777  ConfValIsTrue(p->val));
2778  } else if (strcasecmp("path-nul-raw-terminates", p->name) == 0) {
2779  htp_config_set_nul_raw_terminates(cfg_prec->cfg,
2780  HTP_DECODER_URL_PATH,
2781  ConfValIsTrue(p->val));
2782  } else if (strcasecmp("path-separators-compress", p->name) == 0) {
2783  htp_config_set_path_separators_compress(cfg_prec->cfg,
2784  HTP_DECODER_URL_PATH,
2785  ConfValIsTrue(p->val));
2786  } else if (strcasecmp("path-separators-decode", p->name) == 0) {
2787  htp_config_set_path_separators_decode(cfg_prec->cfg,
2788  HTP_DECODER_URL_PATH,
2789  ConfValIsTrue(p->val));
2790  } else if (strcasecmp("path-u-encoding-decode", p->name) == 0) {
2791  htp_config_set_u_encoding_decode(cfg_prec->cfg,
2792  HTP_DECODER_URL_PATH,
2793  ConfValIsTrue(p->val));
2794  } else if (strcasecmp("path-url-encoding-invalid-handling", p->name) == 0) {
2795  enum htp_url_encoding_handling_t handling;
2796  if (strcasecmp(p->val, "preserve_percent") == 0) {
2797  handling = HTP_URL_DECODE_PRESERVE_PERCENT;
2798  } else if (strcasecmp(p->val, "remove_percent") == 0) {
2799  handling = HTP_URL_DECODE_REMOVE_PERCENT;
2800  } else if (strcasecmp(p->val, "decode_invalid") == 0) {
2801  handling = HTP_URL_DECODE_PROCESS_INVALID;
2802  } else {
2803  SCLogError("Invalid entry "
2804  "for libhtp param path-url-encoding-invalid-handling");
2805  return;
2806  }
2807  htp_config_set_url_encoding_invalid_handling(cfg_prec->cfg,
2808  HTP_DECODER_URL_PATH,
2809  handling);
2810  } else if (strcasecmp("path-utf8-convert-bestfit", p->name) == 0) {
2811  htp_config_set_utf8_convert_bestfit(cfg_prec->cfg,
2812  HTP_DECODER_URL_PATH,
2813  ConfValIsTrue(p->val));
2814  } else if (strcasecmp("uri-include-all", p->name) == 0) {
2815  cfg_prec->uri_include_all = (1 == ConfValIsTrue(p->val));
2816  SCLogDebug("uri-include-all %s",
2817  cfg_prec->uri_include_all ? "enabled" : "disabled");
2818  } else if (strcasecmp("query-plusspace-decode", p->name) == 0) {
2819  htp_config_set_plusspace_decode(cfg_prec->cfg,
2820  HTP_DECODER_URLENCODED,
2821  ConfValIsTrue(p->val));
2822  } else if (strcasecmp("meta-field-limit", p->name) == 0) {
2823  uint32_t limit = 0;
2824  if (ParseSizeStringU32(p->val, &limit) < 0) {
2825  SCLogError("Error meta-field-limit "
2826  "from conf file - %s. Killing engine",
2827  p->val);
2828  exit(EXIT_FAILURE);
2829  }
2830  if (limit == 0) {
2831  FatalError("Error meta-field-limit "
2832  "from conf file cannot be 0. Killing engine");
2833  }
2834  /* set default soft-limit with our new hard limit */
2835  htp_config_set_field_limits(cfg_prec->cfg,
2837  (size_t)limit);
2838 #ifdef HAVE_HTP_CONFIG_SET_LZMA_MEMLIMIT
2839  } else if (strcasecmp("lzma-memlimit", p->name) == 0) {
2840  uint32_t limit = 0;
2841  if (ParseSizeStringU32(p->val, &limit) < 0) {
2842  FatalError("failed to parse 'lzma-memlimit' "
2843  "from conf file - %s.",
2844  p->val);
2845  }
2846  if (limit == 0) {
2847  FatalError("'lzma-memlimit' "
2848  "from conf file cannot be 0.");
2849  }
2850  /* set default soft-limit with our new hard limit */
2851  SCLogConfig("Setting HTTP LZMA memory limit to %"PRIu32" bytes", limit);
2852  htp_config_set_lzma_memlimit(cfg_prec->cfg, (size_t)limit);
2853 #endif
2854 #ifdef HAVE_HTP_CONFIG_SET_LZMA_LAYERS
2855  } else if (strcasecmp("lzma-enabled", p->name) == 0) {
2856  if (ConfValIsTrue(p->val)) {
2857  htp_config_set_lzma_layers(cfg_prec->cfg, 1);
2858  } else if (!ConfValIsFalse(p->val)) {
2859  int8_t limit;
2860  if (StringParseInt8(&limit, 10, 0, (const char *)p->val) < 0) {
2861  FatalError("failed to parse 'lzma-enabled' "
2862  "from conf file - %s.",
2863  p->val);
2864  }
2865  SCLogConfig("Setting HTTP LZMA decompression layers to %" PRIu32 "", (int)limit);
2866  htp_config_set_lzma_layers(cfg_prec->cfg, limit);
2867  }
2868 #endif
2869 #ifdef HAVE_HTP_CONFIG_SET_COMPRESSION_BOMB_LIMIT
2870  } else if (strcasecmp("compression-bomb-limit", p->name) == 0) {
2871  uint32_t limit = 0;
2872  if (ParseSizeStringU32(p->val, &limit) < 0) {
2873  FatalError("failed to parse 'compression-bomb-limit' "
2874  "from conf file - %s.",
2875  p->val);
2876  }
2877  if (limit == 0) {
2878  FatalError("'compression-bomb-limit' "
2879  "from conf file cannot be 0.");
2880  }
2881  /* set default soft-limit with our new hard limit */
2882  SCLogConfig("Setting HTTP compression bomb limit to %"PRIu32" bytes", limit);
2883  htp_config_set_compression_bomb_limit(cfg_prec->cfg, (size_t)limit);
2884 #endif
2885 #ifdef HAVE_HTP_CONFIG_SET_COMPRESSION_TIME_LIMIT
2886  } else if (strcasecmp("decompression-time-limit", p->name) == 0) {
2887  uint32_t limit = 0;
2888  // between 1 usec and 1 second
2889  if (StringParseU32RangeCheck(&limit, 10, 0, p->val, 1, 1000000) < 0) {
2890  FatalError("failed to parse 'decompression-time-limit' "
2891  "from conf file - %s.",
2892  p->val);
2893  }
2894  SCLogConfig("Setting HTTP decompression time limit to %" PRIu32 " usec", limit);
2895  htp_config_set_compression_time_limit(cfg_prec->cfg, (size_t)limit);
2896 #endif
2897 #ifdef HAVE_HTP_CONFIG_SET_MAX_TX
2898  } else if (strcasecmp("max-tx", p->name) == 0) {
2899  uint32_t limit = 0;
2900  if (ParseSizeStringU32(p->val, &limit) < 0) {
2901  FatalError("failed to parse 'max-tx' "
2902  "from conf file - %s.",
2903  p->val);
2904  }
2905  /* set default soft-limit with our new hard limit */
2906  SCLogConfig("Setting HTTP max-tx limit to %" PRIu32 " bytes", limit);
2907  htp_config_set_max_tx(cfg_prec->cfg, (size_t)limit);
2908 #endif
2909  } else if (strcasecmp("randomize-inspection-sizes", p->name) == 0) {
2910  if (!g_disable_randomness) {
2911  cfg_prec->randomize = ConfValIsTrue(p->val);
2912  }
2913  } else if (strcasecmp("randomize-inspection-range", p->name) == 0) {
2914  uint32_t range;
2915  if (StringParseU32RangeCheck(&range, 10, 0,
2916  (const char *)p->val, 0, 100) < 0) {
2917  SCLogError("Invalid value for randomize"
2918  "-inspection-range setting from conf file - \"%s\"."
2919  " It should be a valid integer less than or equal to 100."
2920  " Killing engine",
2921  p->val);
2922  exit(EXIT_FAILURE);
2923  }
2924  cfg_prec->randomize_range = range;
2925  } else if (strcasecmp("http-body-inline", p->name) == 0) {
2926  if (ConfValIsTrue(p->val)) {
2927  cfg_prec->http_body_inline = 1;
2928  } else if (ConfValIsFalse(p->val)) {
2929  cfg_prec->http_body_inline = 0;
2930  } else {
2931  if (strcmp("auto", p->val) != 0) {
2932  WarnInvalidConfEntry("http_body_inline", "%s", "auto");
2933  }
2934  if (EngineModeIsIPS()) {
2935  cfg_prec->http_body_inline = 1;
2936  } else {
2937  cfg_prec->http_body_inline = 0;
2938  }
2939  }
2940  } else if (strcasecmp("swf-decompression", p->name) == 0) {
2941  ConfNode *pval;
2942 
2943  TAILQ_FOREACH(pval, &p->head, next) {
2944  if (strcasecmp("enabled", pval->name) == 0) {
2945  if (ConfValIsTrue(pval->val)) {
2946  cfg_prec->swf_decompression_enabled = 1;
2947  } else if (ConfValIsFalse(pval->val)) {
2948  cfg_prec->swf_decompression_enabled = 0;
2949  } else {
2950  WarnInvalidConfEntry("swf-decompression.enabled", "%s", "no");
2951  }
2952  } else if (strcasecmp("type", pval->name) == 0) {
2953  if (strcasecmp("no", pval->val) == 0) {
2955  } else if (strcasecmp("deflate", pval->val) == 0) {
2957  } else if (strcasecmp("lzma", pval->val) == 0) {
2959  } else if (strcasecmp("both", pval->val) == 0) {
2961  } else {
2962  SCLogError("Invalid entry for "
2963  "swf-decompression.type: %s - "
2964  "Killing engine",
2965  pval->val);
2966  exit(EXIT_FAILURE);
2967  }
2968  } else if (strcasecmp("compress-depth", pval->name) == 0) {
2969  if (ParseSizeStringU32(pval->val, &cfg_prec->swf_compress_depth) < 0) {
2970  SCLogError("Error parsing swf-decompression.compression-depth "
2971  "from conf file - %s. Killing engine",
2972  p->val);
2973  exit(EXIT_FAILURE);
2974  }
2975  } else if (strcasecmp("decompress-depth", pval->name) == 0) {
2976  if (ParseSizeStringU32(pval->val, &cfg_prec->swf_decompress_depth) < 0) {
2977  SCLogError("Error parsing swf-decompression.decompression-depth "
2978  "from conf file - %s. Killing engine",
2979  p->val);
2980  exit(EXIT_FAILURE);
2981  }
2982  } else {
2983  SCLogWarning("Ignoring unknown param %s", pval->name);
2984  }
2985  }
2986  } else {
2987  SCLogWarning("LIBHTP Ignoring unknown "
2988  "default config: %s",
2989  p->name);
2990  }
2991  } /* TAILQ_FOREACH(p, &default_config->head, next) */
2992 
2993  return;
2994 }
2995 
2996 void HTPConfigure(void)
2997 {
2998  SCEnter();
2999 
3000  cfglist.next = NULL;
3001 
3005 
3006  cfgtree = SCRadixCreateRadixTree(NULL, NULL);
3007  if (NULL == cfgtree)
3008  exit(EXIT_FAILURE);
3009 
3010  /* Default Config */
3011  cfglist.cfg = htp_config_create();
3012  if (NULL == cfglist.cfg) {
3013  FatalError("Failed to create HTP default config");
3014  }
3015  SCLogDebug("LIBHTP default config: %p", cfglist.cfg);
3016  HTPConfigSetDefaultsPhase1(&cfglist);
3017  if (ConfGetNode("app-layer.protocols.http.libhtp") == NULL) {
3018  HTPConfigParseParameters(&cfglist, ConfGetNode("libhtp.default-config"),
3019  cfgtree);
3020  } else {
3021  HTPConfigParseParameters(&cfglist, ConfGetNode("app-layer.protocols.http.libhtp.default-config"), cfgtree);
3022  }
3023  HTPConfigSetDefaultsPhase2("default", &cfglist);
3024 
3025  HTPParseMemcap();
3026 
3027  /* Read server config and create a parser for each IP in radix tree */
3028  ConfNode *server_config = ConfGetNode("app-layer.protocols.http.libhtp.server-config");
3029  if (server_config == NULL) {
3030  server_config = ConfGetNode("libhtp.server-config");
3031  if (server_config == NULL) {
3032  SCLogDebug("LIBHTP Configuring %p", server_config);
3033  SCReturn;
3034  }
3035  }
3036  SCLogDebug("LIBHTP Configuring %p", server_config);
3037 
3038  ConfNode *si;
3039  /* Server Nodes */
3040  TAILQ_FOREACH(si, &server_config->head, next) {
3041  /* Need the named node, not the index */
3042  ConfNode *s = TAILQ_FIRST(&si->head);
3043  if (NULL == s) {
3044  SCLogDebug("LIBHTP s NULL");
3045  continue;
3046  }
3047 
3048  SCLogDebug("LIBHTP server %s", s->name);
3049 
3050  HTPCfgRec *nextrec = cfglist.next;
3051  HTPCfgRec *htprec = SCCalloc(1, sizeof(HTPCfgRec));
3052  if (NULL == htprec)
3053  exit(EXIT_FAILURE);
3054 
3055  cfglist.next = htprec;
3056 
3057  cfglist.next->next = nextrec;
3058  cfglist.next->cfg = htp_config_create();
3059  if (NULL == cfglist.next->cfg) {
3060  FatalError("Failed to create HTP server config");
3061  }
3062 
3063  HTPConfigSetDefaultsPhase1(htprec);
3064  HTPConfigParseParameters(htprec, s, cfgtree);
3065  HTPConfigSetDefaultsPhase2(s->name, htprec);
3066  }
3067 
3068  SCReturn;
3069 }
3070 
3072 {
3073 #ifdef DEBUG
3074  SCMutexLock(&htp_state_mem_lock);
3075  SCLogPerf("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
3076  SCMutexUnlock(&htp_state_mem_lock);
3077 #endif
3078 }
3079 
3080 /** \internal
3081  * \brief get files callback
3082  * \param state state ptr
3083  * \param direction flow direction
3084  * \retval files files ptr
3085  */
3086 static AppLayerGetFileState HTPGetTxFiles(void *state, void *txv, uint8_t direction)
3087 {
3088  AppLayerGetFileState files = { .fc = NULL, .cfg = &htp_sbcfg };
3089  htp_tx_t *tx = (htp_tx_t *)txv;
3090  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
3091  if (tx_ud) {
3092  if (direction & STREAM_TOCLIENT) {
3093  files.fc = &tx_ud->files_tc;
3094  } else {
3095  files.fc = &tx_ud->files_ts;
3096  }
3097  }
3098  return files;
3099 }
3100 
3101 static int HTPStateGetAlstateProgress(void *tx, uint8_t direction)
3102 {
3103  if (direction & STREAM_TOSERVER)
3104  return ((htp_tx_t *)tx)->request_progress;
3105  else
3106  return ((htp_tx_t *)tx)->response_progress;
3107 }
3108 
3109 static uint64_t HTPStateGetTxCnt(void *alstate)
3110 {
3111  HtpState *http_state = (HtpState *)alstate;
3112 
3113  if (http_state != NULL && http_state->conn != NULL) {
3114  const int64_t size = (int64_t)htp_list_size(http_state->conn->transactions);
3115  if (size < 0)
3116  return 0ULL;
3117  SCLogDebug("size %"PRIu64, size);
3118  return (uint64_t)size + http_state->tx_freed;
3119  } else {
3120  return 0ULL;
3121  }
3122 }
3123 
3124 static void *HTPStateGetTx(void *alstate, uint64_t tx_id)
3125 {
3126  HtpState *http_state = (HtpState *)alstate;
3127 
3128  if (http_state != NULL && http_state->conn != NULL && tx_id >= http_state->tx_freed)
3129  return htp_list_get(http_state->conn->transactions, tx_id - http_state->tx_freed);
3130  else
3131  return NULL;
3132 }
3133 
3134 void *HtpGetTxForH2(void *alstate)
3135 {
3136  // gets last transaction
3137  HtpState *http_state = (HtpState *)alstate;
3138  if (http_state != NULL && http_state->conn != NULL) {
3139  size_t txid = HTPStateGetTxCnt(http_state);
3140  if (txid > http_state->tx_freed) {
3141  return htp_list_get(http_state->conn->transactions, txid - http_state->tx_freed - 1);
3142  }
3143  }
3144  return NULL;
3145 }
3146 
3147 static int HTPStateGetEventInfo(const char *event_name,
3148  int *event_id, AppLayerEventType *event_type)
3149 {
3150  *event_id = SCMapEnumNameToValue(event_name, http_decoder_event_table);
3151  if (*event_id == -1) {
3152  SCLogError("event \"%s\" not present in "
3153  "http's enum map table.",
3154  event_name);
3155  /* this should be treated as fatal */
3156  return -1;
3157  }
3158 
3159  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
3160 
3161  return 0;
3162 }
3163 
3164 static int HTPStateGetEventInfoById(int event_id, const char **event_name,
3165  AppLayerEventType *event_type)
3166 {
3167  *event_name = SCMapEnumValueToName(event_id, http_decoder_event_table);
3168  if (*event_name == NULL) {
3169  SCLogError("event \"%d\" not present in "
3170  "http's enum map table.",
3171  event_id);
3172  /* this should be treated as fatal */
3173  return -1;
3174  }
3175 
3176  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
3177 
3178  return 0;
3179 }
3180 
3181 static AppLayerTxData *HTPGetTxData(void *vtx)
3182 {
3183  htp_tx_t *tx = (htp_tx_t *)vtx;
3184  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
3185  if (tx_ud) {
3186  return &tx_ud->tx_data;
3187  }
3188  return NULL;
3189 }
3190 
3191 static AppLayerStateData *HTPGetStateData(void *vstate)
3192 {
3193  HtpState *s = vstate;
3194  return &s->state_data;
3195 }
3196 
3197 static int HTPRegisterPatternsForProtocolDetection(void)
3198 {
3199  const char *methods[] = { "GET", "PUT", "POST", "HEAD", "TRACE", "OPTIONS",
3200  "CONNECT", "DELETE", "PATCH", "PROPFIND", "PROPPATCH", "MKCOL",
3201  "COPY", "MOVE", "LOCK", "UNLOCK", "CHECKOUT", "UNCHECKOUT", "CHECKIN",
3202  "UPDATE", "LABEL", "REPORT", "MKWORKSPACE", "MKACTIVITY", "MERGE",
3203  "INVALID", "VERSION-CONTROL", "BASELINE-CONTROL", NULL};
3204  const char *spacings[] = { "|20|", "|09|", NULL };
3205  const char *versions[] = { "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", NULL };
3206 
3207  int methods_pos;
3208  int spacings_pos;
3209  int versions_pos;
3210  int register_result;
3211  char method_buffer[32] = "";
3212 
3213  /* Loop through all the methods ands spacings and register the patterns */
3214  for (methods_pos = 0; methods[methods_pos]; methods_pos++) {
3215  for (spacings_pos = 0; spacings[spacings_pos]; spacings_pos++) {
3216 
3217  /* Combine the method name and the spacing */
3218  snprintf(method_buffer, sizeof(method_buffer), "%s%s", methods[methods_pos], spacings[spacings_pos]);
3219 
3220  /* Register the new method+spacing pattern
3221  * 3 is subtracted from the length since the spacing is hex typed as |xx|
3222  * but the pattern matching should only be one char
3223  */
3224  register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1,
3225  method_buffer, (uint16_t)strlen(method_buffer) - 3, 0, STREAM_TOSERVER);
3226  if (register_result < 0) {
3227  return -1;
3228  }
3229  }
3230  }
3231 
3232  /* Loop through all the http version patterns that are TO_CLIENT */
3233  for (versions_pos = 0; versions[versions_pos]; versions_pos++) {
3234  register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1,
3235  versions[versions_pos], (uint16_t)strlen(versions[versions_pos]), 0,
3236  STREAM_TOCLIENT);
3237  if (register_result < 0) {
3238  return -1;
3239  }
3240  }
3241 
3242  return 0;
3243 }
3244 
3245 /**
3246  * \brief Register the HTTP protocol and state handling functions to APP layer
3247  * of the engine.
3248  */
3250 {
3251  SCEnter();
3252 
3253  const char *proto_name = "http";
3254 
3255  /** HTTP */
3256  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
3258  if (HTPRegisterPatternsForProtocolDetection() < 0)
3259  return;
3260  } else {
3261  SCLogInfo("Protocol detection and parser disabled for %s protocol",
3262  proto_name);
3263  return;
3264  }
3265 
3266  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
3267  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateAlloc, HTPStateFree);
3268  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateTransactionFree);
3269  AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxFiles);
3271  IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetAlstateProgress);
3272  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTxCnt);
3273  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTx);
3274 
3276  ALPROTO_HTTP1, HTP_REQUEST_COMPLETE, HTP_RESPONSE_COMPLETE);
3277  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfo);
3279  IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfoById);
3280 
3281  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxData);
3282  AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetStateData);
3283 
3285  IPPROTO_TCP, ALPROTO_HTTP1, AppLayerHtpSetStreamDepthFlag);
3286 
3288  IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER, HTPHandleRequestData);
3290  IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOCLIENT, HTPHandleResponseData);
3291  SC_ATOMIC_INIT(htp_config_flags);
3292  /* This parser accepts gaps. */
3296  IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_TOCLIENT);
3297  /* app-layer-frame-documentation tag start: registering relevant callbacks */
3299  IPPROTO_TCP, ALPROTO_HTTP1, HTTPGetFrameIdByName, HTTPGetFrameNameById);
3300  /* app-layer-frame-documentation tag end: registering relevant callbacks */
3301  HTPConfigure();
3302  } else {
3303  SCLogInfo("Parser disabled for %s protocol. Protocol detection still on.", proto_name);
3304  }
3305 #ifdef UNITTESTS
3306  AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_HTTP1, HTPParserRegisterTests);
3307 #endif
3308 
3309  SCReturn;
3310 }
3311 
3312 #ifdef UNITTESTS
3313 #include "detect-engine-alert.h"
3314 
3315 static HTPCfgRec cfglist_backup;
3316 
3318 {
3319  cfglist_backup = cfglist;
3320 
3321  return;
3322 }
3323 
3325 {
3326  cfglist = cfglist_backup;
3327 
3328  return;
3329 }
3330 
3331 /** \test Test case where chunks are sent in smaller chunks and check the
3332  * response of the parser from HTP library. */
3333 static int HTPParserTest01(void)
3334 {
3335  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
3336  " Data is c0oL!";
3337  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3338 
3339  TcpSession ssn;
3340  memset(&ssn, 0, sizeof(ssn));
3341 
3344 
3345  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3346  FAIL_IF_NULL(f);
3347  f->protoctx = &ssn;
3348  f->proto = IPPROTO_TCP;
3349  f->alproto = ALPROTO_HTTP1;
3350 
3351  StreamTcpInitConfig(true);
3352 
3353  uint32_t u;
3354  for (u = 0; u < httplen1; u++) {
3355  uint8_t flags = 0;
3356 
3357  if (u == 0)
3358  flags = STREAM_TOSERVER|STREAM_START;
3359  else if (u == (httplen1 - 1))
3360  flags = STREAM_TOSERVER|STREAM_EOF;
3361  else
3362  flags = STREAM_TOSERVER;
3363 
3364  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3365  FAIL_IF(r != 0);
3366  }
3367 
3368  HtpState *htp_state = f->alstate;
3369  FAIL_IF_NULL(htp_state);
3370 
3371  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3372  FAIL_IF_NULL(tx);
3373 
3374  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3375  FAIL_IF_NULL(h);
3376 
3377  FAIL_IF(strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0"));
3378  FAIL_IF(tx->request_method_number != HTP_M_POST);
3379  FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_0);
3380 
3382  StreamTcpFreeConfig(true);
3383  UTHFreeFlow(f);
3384  PASS;
3385 }
3386 
3387 /** \test Test folding in 1 read case */
3388 static int HTPParserTest01b(void)
3389 {
3390  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost"
3391  " Data is c0oL!";
3392  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3393 
3394  TcpSession ssn;
3395  memset(&ssn, 0, sizeof(ssn));
3396 
3399 
3400  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3401  FAIL_IF_NULL(f);
3402  f->protoctx = &ssn;
3403  f->proto = IPPROTO_TCP;
3404  f->alproto = ALPROTO_HTTP1;
3405 
3406  StreamTcpInitConfig(true);
3407 
3408  uint8_t flags =STREAM_TOSERVER|STREAM_START|STREAM_EOF;
3409  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1);
3410  FAIL_IF(r != 0);
3411 
3412  HtpState *htp_state = f->alstate;
3413  FAIL_IF_NULL(htp_state);
3414 
3415  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3416  FAIL_IF_NULL(tx);
3417 
3418  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3419  FAIL_IF_NULL(h);
3420 
3421  FAIL_IF(strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0"));
3422  FAIL_IF(tx->request_method_number != HTP_M_POST);
3423  FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_0);
3424 
3426  StreamTcpFreeConfig(true);
3427  UTHFreeFlow(f);
3428  PASS;
3429 }
3430 
3431 /** \test Test folding in 1byte per read case */
3432 static int HTPParserTest01c(void)
3433 {
3434  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost"
3435  " Data is c0oL!";
3436  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3437 
3438  TcpSession ssn;
3439  memset(&ssn, 0, sizeof(ssn));
3440 
3443 
3444  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3445  FAIL_IF_NULL(f);
3446  f->protoctx = &ssn;
3447  f->proto = IPPROTO_TCP;
3448  f->alproto = ALPROTO_HTTP1;
3449 
3450  StreamTcpInitConfig(true);
3451 
3452  uint32_t u;
3453  for (u = 0; u < httplen1; u++) {
3454  uint8_t flags = 0;
3455 
3456  if (u == 0)
3457  flags = STREAM_TOSERVER|STREAM_START;
3458  else if (u == (httplen1 - 1))
3459  flags = STREAM_TOSERVER|STREAM_EOF;
3460  else
3461  flags = STREAM_TOSERVER;
3462 
3463  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3464  FAIL_IF(r != 0);
3465  }
3466 
3467  HtpState *htp_state = f->alstate;
3468  FAIL_IF_NULL(htp_state);
3469 
3470  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3471  FAIL_IF_NULL(tx);
3472 
3473  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3474  FAIL_IF_NULL(h);
3475 
3476  FAIL_IF(strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0"));
3477  FAIL_IF(tx->request_method_number != HTP_M_POST);
3478  FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_0);
3479 
3481  StreamTcpFreeConfig(true);
3482  UTHFreeFlow(f);
3483  PASS;
3484 }
3485 
3486 /** \test Test case where chunks are sent in smaller chunks and check the
3487  * response of the parser from HTP library. */
3488 static int HTPParserTest01a(void)
3489 {
3490  int result = 0;
3491  Flow *f = NULL;
3492  uint8_t httpbuf1[] = " POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
3493  " Data is c0oL!";
3494  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3495  TcpSession ssn;
3496  HtpState *htp_state = NULL;
3497  int r = 0;
3499 
3500  memset(&ssn, 0, sizeof(ssn));
3501 
3502  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3503  if (f == NULL)
3504  goto end;
3505  f->protoctx = &ssn;
3506  f->proto = IPPROTO_TCP;
3507  f->alproto = ALPROTO_HTTP1;
3508 
3509  StreamTcpInitConfig(true);
3510 
3511  uint32_t u;
3512  for (u = 0; u < httplen1; u++) {
3513  uint8_t flags = 0;
3514 
3515  if (u == 0)
3516  flags = STREAM_TOSERVER|STREAM_START;
3517  else if (u == (httplen1 - 1))
3518  flags = STREAM_TOSERVER|STREAM_EOF;
3519  else
3520  flags = STREAM_TOSERVER;
3521 
3522  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3523  if (r != 0) {
3524  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
3525  " 0: ", u, r);
3526  goto end;
3527  }
3528  }
3529 
3530  htp_state = f->alstate;
3531  if (htp_state == NULL) {
3532  printf("no http state: ");
3533  goto end;
3534  }
3535 
3536  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3537  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3538  if (strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0")
3539  || tx->request_method_number != HTP_M_POST ||
3540  tx->request_protocol_number != HTP_PROTOCOL_1_0)
3541  {
3542  printf("expected header value: Victor/1.0 and got %s: and expected"
3543  " method: POST and got %s, expected protocol number HTTP/1.0"
3544  " and got: %s \n", bstr_util_strdup_to_c(h->value),
3545  bstr_util_strdup_to_c(tx->request_method),
3546  bstr_util_strdup_to_c(tx->request_protocol));
3547  goto end;
3548  }
3549  result = 1;
3550 end:
3551  if (alp_tctx != NULL)
3553  StreamTcpFreeConfig(true);
3554  UTHFreeFlow(f);
3555  return result;
3556 }
3557 
3558 /** \test See how it deals with an incomplete request. */
3559 static int HTPParserTest02(void)
3560 {
3561  int result = 0;
3562  Flow *f = NULL;
3563  uint8_t httpbuf1[] = "POST";
3564  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3565  TcpSession ssn;
3566  HtpState *http_state = NULL;
3568 
3569  memset(&ssn, 0, sizeof(ssn));
3570 
3571  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3572  if (f == NULL)
3573  goto end;
3574  f->protoctx = &ssn;
3575  f->proto = IPPROTO_TCP;
3576  f->alproto = ALPROTO_HTTP1;
3577 
3578  StreamTcpInitConfig(true);
3579 
3580  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
3581  STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
3582  if (r != 0) {
3583  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
3584  goto end;
3585  }
3586 
3587  http_state = f->alstate;
3588  if (http_state == NULL) {
3589  printf("no http state: ");
3590  goto end;
3591  }
3592 
3593  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
3594  FAIL_IF_NULL(tx);
3595  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3596  FAIL_IF_NOT_NULL(h);
3597 
3598  FAIL_IF_NULL(tx->request_method);
3599  char *method = bstr_util_strdup_to_c(tx->request_method);
3600  FAIL_IF_NULL(method);
3601 
3602  FAIL_IF(strcmp(method, "POST") != 0);
3603  SCFree(method);
3604 
3605  result = 1;
3606 end:
3607  if (alp_tctx != NULL)
3609  StreamTcpFreeConfig(true);
3610  UTHFreeFlow(f);
3611  return result;
3612 }
3613 
3614 /** \test Test case where method is invalid and data is sent in smaller chunks
3615  * and check the response of the parser from HTP library. */
3616 static int HTPParserTest03(void)
3617 {
3618  int result = 0;
3619  Flow *f = NULL;
3620  uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n";
3621  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3622  TcpSession ssn;
3623  HtpState *htp_state = NULL;
3624  int r = 0;
3626 
3627  memset(&ssn, 0, sizeof(ssn));
3628 
3629  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3630  if (f == NULL)
3631  goto end;
3632  f->protoctx = &ssn;
3633  f->proto = IPPROTO_TCP;
3634  f->alproto = ALPROTO_HTTP1;
3635 
3636  StreamTcpInitConfig(true);
3637 
3638  uint32_t u;
3639  for (u = 0; u < httplen1; u++) {
3640  uint8_t flags = 0;
3641 
3642  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
3643  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
3644  else flags = STREAM_TOSERVER;
3645 
3646  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3647  if (r != 0) {
3648  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
3649  " 0: ", u, r);
3650  goto end;
3651  }
3652  }
3653  htp_state = f->alstate;
3654  if (htp_state == NULL) {
3655  printf("no http state: ");
3656  goto end;
3657  }
3658 
3659  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3660 
3661  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3662  if (tx->request_method_number != HTP_M_UNKNOWN ||
3663  h != NULL || tx->request_protocol_number != HTP_PROTOCOL_1_0)
3664  {
3665  printf("expected method M_UNKNOWN and got %s: , expected protocol "
3666  "HTTP/1.0 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
3667  bstr_util_strdup_to_c(tx->request_protocol));
3668  goto end;
3669  }
3670  result = 1;
3671 end:
3672  if (alp_tctx != NULL)
3674  StreamTcpFreeConfig(true);
3675  UTHFreeFlow(f);
3676  return result;
3677 }
3678 
3679 /** \test Test case where invalid data is sent and check the response of the
3680  * parser from HTP library. */
3681 static int HTPParserTest04(void)
3682 {
3683  int result = 0;
3684  Flow *f = NULL;
3685  HtpState *htp_state = NULL;
3686  uint8_t httpbuf1[] = "World!\r\n";
3687  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3688  TcpSession ssn;
3689  int r = 0;
3691 
3692  memset(&ssn, 0, sizeof(ssn));
3693 
3694  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3695  if (f == NULL)
3696  goto end;
3697  f->protoctx = &ssn;
3698  f->proto = IPPROTO_TCP;
3699  f->alproto = ALPROTO_HTTP1;
3700 
3701  StreamTcpInitConfig(true);
3702 
3704  STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
3705  if (r != 0) {
3706  goto end;
3707  }
3708 
3709  htp_state = f->alstate;
3710  if (htp_state == NULL) {
3711  printf("no http state: ");
3712  goto end;
3713  }
3714 
3715  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3716  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3717  if (tx->request_method_number != HTP_M_UNKNOWN ||
3718  h != NULL || tx->request_protocol_number != HTP_PROTOCOL_0_9)
3719  {
3720  printf("expected method M_UNKNOWN and got %s: , expected protocol "
3721  "NULL and got %s \n", bstr_util_strdup_to_c(tx->request_method),
3722  bstr_util_strdup_to_c(tx->request_protocol));
3723  goto end;
3724  }
3725  result = 1;
3726 end:
3727  if (alp_tctx != NULL)
3729  StreamTcpFreeConfig(true);
3730  UTHFreeFlow(f);
3731  return result;
3732 }
3733 
3734 /** \test Test both sides of a http stream mixed up to see if the HTP parser
3735  * properly parsed them and also keeps them separated. */
3736 static int HTPParserTest05(void)
3737 {
3738  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\nContent-Length: 17\r\n\r\n";
3739  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3740  uint8_t httpbuf2[] = "Post D";
3741  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3742  uint8_t httpbuf3[] = "ata is c0oL!";
3743  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
3744 
3745  uint8_t httpbuf4[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
3746  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
3747  uint8_t httpbuf5[] = "post R";
3748  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3749  uint8_t httpbuf6[] = "esults are tha bomb!";
3750  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
3751 
3752  TcpSession ssn;
3753  memset(&ssn, 0, sizeof(ssn));
3754 
3757 
3758  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3759  FAIL_IF_NULL(f);
3760  f->protoctx = &ssn;
3761  f->proto = IPPROTO_TCP;
3762  f->alproto = ALPROTO_HTTP1;
3763 
3764  StreamTcpInitConfig(true);
3765 
3766  int r = AppLayerParserParse(
3767  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
3768  FAIL_IF(r != 0);
3769 
3770  r = AppLayerParserParse(
3771  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf4, httplen4);
3772  FAIL_IF(r != 0);
3773 
3774  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf5, httplen5);
3775  FAIL_IF(r != 0);
3776 
3777  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
3778  FAIL_IF(r != 0);
3779 
3780  r = AppLayerParserParse(
3781  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
3782  FAIL_IF(r != 0);
3783 
3784  r = AppLayerParserParse(
3785  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_EOF, httpbuf6, httplen6);
3786  FAIL_IF(r != 0);
3787 
3788  HtpState *http_state = f->alstate;
3789  FAIL_IF_NULL(http_state);
3790 
3791  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
3792  FAIL_IF_NULL(tx);
3793  FAIL_IF_NOT(tx->request_method_number == HTP_M_POST);
3794  FAIL_IF_NOT(tx->request_protocol_number == HTP_PROTOCOL_1_0);
3795 
3796  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3797  FAIL_IF_NULL(h);
3798 
3799  FAIL_IF_NOT(tx->response_status_number == 200);
3800 
3802  StreamTcpFreeConfig(true);
3803  UTHFreeFlow(f);
3804  PASS;
3805 }
3806 
3807 /** \test Test proper chunked encoded response body
3808  */
3809 static int HTPParserTest06(void)
3810 {
3811  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
3812  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
3813  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
3814  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3815  uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nDate: Sat, 03 Oct 2009 10:16:02 "
3816  "GMT\r\n"
3817  "Server: Apache/1.3.37 (Unix) mod_ssl/2.8.28 "
3818  "OpenSSL/0.9.7a PHP/4.4.7 mod_perl/1.29 "
3819  "FrontPage/5.0.2.2510\r\n"
3820  "X-Powered-By: PHP/4.4.7\r\nTransfer-Encoding: "
3821  "chunked\r\n"
3822  "Content-Type: text/html\r\n\r\n"
3823  "580\r\n"
3824  "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu"
3825  "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN"
3826  "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N"
3827  "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk"
3828  "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l"
3829  "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN"
3830  "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt"
3831  "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz"
3832  "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw"
3833  "aG9uZTM9DQpsb2dpbjM9DQpwYXNzd29yZDM9DQpwaG9uZTQ9DQps"
3834  "b2dpbjQ9DQpwYXNzd29yZDQ9DQpwaG9uZTU9DQpsb2dpbjU9DQpw"
3835  "YXNzd29yZDU9DQpwaG9uZTY9DQpsb2dpbjY9DQpwYXNzd29yZDY9"
3836  "DQpjYWxsX3RpbWUxPQ0KY2FsbF90aW1lMj0NCmRheV9saW1pdD0N"
3837  "Cm1vbnRoX2xpbWl0PQ0KW2dyb3VwM10NCnBob25lMT0NCmxvZ2lu"
3838  "MT0NCnBhc3N3b3JkMT0NCnBob25lMj0NCmxvZ2luMj0NCnBhc3N3"
3839  "b3JkMj0NCnBob25lMz0NCmxvZ2luMz0NCnBhc3N3b3JkMz0NCnBo"
3840  "b25lND0NCmxvZ2luND0NCnBhc3N3b3JkND0NCnBob25lNT0NCmxv"
3841  "Z2luNT0NCnBhc3N3b3JkNT0NCnBob25lNj0NCmxvZ2luNj0NCnBh"
3842  "c3N3b3JkNj0NCmNhbGxfdGltZTE9DQpjYWxsX3RpbWUyPQ0KZGF5"
3843  "X2xpbWl0PQ0KbW9udGhfbGltaXQ9DQpbZ3JvdXA0XQ0KcGhvbmUx"
3844  "PQ0KbG9naW4xPQ0KcGFzc3dvcmQxPQ0KcGhvbmUyPQ0KbG9naW4y"
3845  "PQ0KcGFzc3dvcmQyPQ0KcGhvbmUzPQ0KbG9naW4zPQ0KcGFzc3dv"
3846  "cmQzPQ0KcGhvbmU0PQ0KbG9naW40PQ0KcGFzc3dvcmQ0PQ0KcGhv"
3847  "bmU1PQ0KbG9naW41PQ0KcGFzc3dvcmQ1PQ0KcGhvbmU2PQ0KbG9n"
3848  "aW42PQ0KcGFzc3dvcmQ2PQ0KY2FsbF90aW1lMT0NCmNhbGxfdGlt"
3849  "ZTI9DQpkYXlfbGltaXQ9DQptb250aF9saW1pdD0NCltmaWxlc10N"
3850  "Cmxpbms9aHR0cDovLzIwOS4yMDUuMTk2LjE2L2xkL2dldGJvdC5w"
3851  "aHA=\r\n0\r\n\r\n";
3852  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3853  TcpSession ssn;
3854 
3857 
3858  memset(&ssn, 0, sizeof(ssn));
3859 
3860  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3861  FAIL_IF_NULL(f);
3862  f->protoctx = &ssn;
3863  f->proto = IPPROTO_TCP;
3864  f->alproto = ALPROTO_HTTP1;
3865 
3866  StreamTcpInitConfig(true);
3867 
3868  int r = AppLayerParserParse(
3869  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
3870  FAIL_IF(r != 0);
3871  r = AppLayerParserParse(
3872  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
3873  FAIL_IF(r != 0);
3874 
3875  HtpState *http_state = f->alstate;
3876  FAIL_IF_NULL(http_state);
3877 
3878  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
3879  FAIL_IF_NULL(tx);
3880 
3881  FAIL_IF(tx->request_method_number != HTP_M_GET);
3882  FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
3883 
3884  FAIL_IF(tx->response_status_number != 200);
3885  FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
3886 
3887  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3888  FAIL_IF_NULL(h);
3889 
3891  StreamTcpFreeConfig(true);
3892  UTHFreeFlow(f);
3893  PASS;
3894 }
3895 
3896 /** \test
3897  */
3898 static int HTPParserTest07(void)
3899 {
3900  int result = 0;
3901  Flow *f = NULL;
3902  uint8_t httpbuf1[] = "GET /awstats.pl?/migratemigrate%20=%20| HTTP/1.0\r\n\r\n";
3903  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3904  TcpSession ssn;
3905  HtpState *htp_state = NULL;
3906  int r = 0;
3908 
3909  memset(&ssn, 0, sizeof(ssn));
3910 
3911  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3912  if (f == NULL)
3913  goto end;
3914  f->protoctx = &ssn;
3915  f->proto = IPPROTO_TCP;
3916  f->alproto = ALPROTO_HTTP1;
3917 
3918  StreamTcpInitConfig(true);
3919 
3920  uint32_t u;
3921  for (u = 0; u < httplen1; u++) {
3922  uint8_t flags = 0;
3923 
3924  if (u == 0)
3925  flags = STREAM_TOSERVER|STREAM_START;
3926  else if (u == (httplen1 - 1))
3927  flags = STREAM_TOSERVER|STREAM_EOF;
3928  else
3929  flags = STREAM_TOSERVER;
3930 
3931  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3932  if (r != 0) {
3933  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
3934  " 0: ", u, r);
3935  goto end;
3936  }
3937  }
3938 
3939  htp_state = f->alstate;
3940  if (htp_state == NULL) {
3941  printf("no http state: ");
3942  goto end;
3943  }
3944 
3945  uint8_t ref[] = "/awstats.pl?/migratemigrate = |";
3946  size_t reflen = sizeof(ref) - 1;
3947 
3948  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3949  if (tx == NULL)
3950  goto end;
3951  HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
3952  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
3953  if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
3954  printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
3955  (uintmax_t)reflen,
3956  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
3957  goto end;
3958  }
3959 
3960  if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref,
3961  bstr_len(tx_ud->request_uri_normalized)) != 0)
3962  {
3963  printf("normalized uri \"");
3964  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
3965  printf("\" != \"");
3966  PrintRawUriFp(stdout, ref, reflen);
3967  printf("\": ");
3968  goto end;
3969  }
3970  }
3971 
3972  result = 1;
3973 end:
3974  if (alp_tctx != NULL)
3976  StreamTcpFreeConfig(true);
3977  UTHFreeFlow(f);
3978  return result;
3979 }
3980 
3981 #include "conf-yaml-loader.h"
3982 
3983 /** \test Abort
3984  */
3985 static int HTPParserTest08(void)
3986 {
3987  int result = 0;
3988  Flow *f = NULL;
3989  uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
3990  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3991  TcpSession ssn;
3993 
3994  char input[] = "\
3995 %YAML 1.1\n\
3996 ---\n\
3997 libhtp:\n\
3998 \n\
3999  default-config:\n\
4000  personality: IDS\n\
4001 ";
4002 
4004  ConfInit();
4006 
4007  ConfYamlLoadString(input, strlen(input));
4008  HTPConfigure();
4009 
4010  HtpState *htp_state = NULL;
4011  int r = 0;
4012  memset(&ssn, 0, sizeof(ssn));
4013 
4014  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4015  if (f == NULL)
4016  goto end;
4017  f->protoctx = &ssn;
4018  f->proto = IPPROTO_TCP;
4019  f->alproto = ALPROTO_HTTP1;
4020 
4021  StreamTcpInitConfig(true);
4022 
4023  uint8_t flags = 0;
4024  flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
4025 
4026  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1);
4027  if (r != 0) {
4028  printf("toserver chunk returned %" PRId32 ", expected"
4029  " 0: ", r);
4030  result = 0;
4031  goto end;
4032  }
4033 
4034  htp_state = f->alstate;
4035  if (htp_state == NULL) {
4036  printf("no http state: ");
4037  result = 0;
4038  goto end;
4039  }
4040 
4041  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4042  if (tx == NULL)
4043  goto end;
4044  HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
4045  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4046  PrintRawDataFp(stdout, bstr_ptr(tx_ud->request_uri_normalized),
4047  bstr_len(tx_ud->request_uri_normalized));
4048  }
4049 
4050  result = 1;
4051 end:
4052  if (alp_tctx != NULL)
4054  StreamTcpFreeConfig(true);
4055  HTPFreeConfig();
4056  ConfDeInit();
4059  UTHFreeFlow(f);
4060  return result;
4061 }
4062 
4063 /** \test Abort
4064  */
4065 static int HTPParserTest09(void)
4066 {
4067  int result = 0;
4068  Flow *f = NULL;
4069  uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
4070  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4071  TcpSession ssn;
4073 
4074  char input[] = "\
4075 %YAML 1.1\n\
4076 ---\n\
4077 libhtp:\n\
4078 \n\
4079  default-config:\n\
4080  personality: Apache_2_2\n\
4081 ";
4082 
4084  ConfInit();
4086 
4087  ConfYamlLoadString(input, strlen(input));
4088  HTPConfigure();
4089 
4090  HtpState *htp_state = NULL;
4091  int r = 0;
4092 
4093  memset(&ssn, 0, sizeof(ssn));
4094 
4095  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4096  if (f == NULL)
4097  goto end;
4098  f->protoctx = &ssn;
4099  f->proto = IPPROTO_TCP;
4100  f->alproto = ALPROTO_HTTP1;
4101 
4102  StreamTcpInitConfig(true);
4103 
4104  uint8_t flags = 0;
4105  flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
4106 
4107  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1);
4108  if (r != 0) {
4109  printf("toserver chunk returned %" PRId32 ", expected"
4110  " 0: ", r);
4111  goto end;
4112  }
4113 
4114  htp_state = f->alstate;
4115  if (htp_state == NULL) {
4116  printf("no http state: ");
4117  goto end;
4118  }
4119 
4120  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4121  if (tx == NULL)
4122  goto end;
4123  HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
4124  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4125  PrintRawDataFp(stdout, bstr_ptr(tx_ud->request_uri_normalized),
4126  bstr_len(tx_ud->request_uri_normalized));
4127  }
4128 
4129  result = 1;
4130 end:
4131  if (alp_tctx != NULL)
4133  StreamTcpFreeConfig(true);
4134  HTPFreeConfig();
4135  ConfDeInit();
4138  UTHFreeFlow(f);
4139  return result;
4140 }
4141 
4142 /** \test Host:www.google.com <- missing space between name:value (rfc violation)
4143  */
4144 static int HTPParserTest10(void)
4145 {
4146  int result = 0;
4147  Flow *f = NULL;
4148  uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\r\n\r\n";
4149  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4150  TcpSession ssn;
4151  HtpState *htp_state = NULL;
4152  int r = 0;
4154 
4155  memset(&ssn, 0, sizeof(ssn));
4156 
4157  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4158  if (f == NULL)
4159  goto end;
4160  f->protoctx = &ssn;
4161  f->proto = IPPROTO_TCP;
4162  f->alproto = ALPROTO_HTTP1;
4163 
4164  StreamTcpInitConfig(true);
4165 
4166  uint32_t u;
4167  for (u = 0; u < httplen1; u++) {
4168  uint8_t flags = 0;
4169 
4170  if (u == 0)
4171  flags = STREAM_TOSERVER|STREAM_START;
4172  else if (u == (httplen1 - 1))
4173  flags = STREAM_TOSERVER|STREAM_EOF;
4174  else
4175  flags = STREAM_TOSERVER;
4176 
4177  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4178  if (r != 0) {
4179  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4180  " 0: ", u, r);
4181  goto end;
4182  }
4183  }
4184 
4185  htp_state = f->alstate;
4186  if (htp_state == NULL) {
4187  printf("no http state: ");
4188  goto end;
4189  }
4190 
4191  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4192  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
4193  if (h == NULL) {
4194  goto end;
4195  }
4196 
4197  char *name = bstr_util_strdup_to_c(h->name);
4198  if (name == NULL) {
4199  goto end;
4200  }
4201 
4202  if (strcmp(name, "Host") != 0) {
4203  printf("header name not \"Host\", instead \"%s\": ", name);
4204  free(name);
4205  goto end;
4206  }
4207  free(name);
4208 
4209  char *value = bstr_util_strdup_to_c(h->value);
4210  if (value == NULL) {
4211  goto end;
4212  }
4213 
4214  if (strcmp(value, "www.google.com") != 0) {
4215  printf("header value not \"www.google.com\", instead \"%s\": ", value);
4216  free(value);
4217  goto end;
4218  }
4219  free(value);
4220 
4221  result = 1;
4222 end:
4223  if (alp_tctx != NULL)
4225  StreamTcpFreeConfig(true);
4226  UTHFreeFlow(f);
4227  return result;
4228 }
4229 
4230 /** \test double encoding in path
4231  */
4232 static int HTPParserTest11(void)
4233 {
4234  int result = 0;
4235  Flow *f = NULL;
4236  uint8_t httpbuf1[] = "GET /%2500 HTTP/1.0\r\n\r\n";
4237  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4238  TcpSession ssn;
4239  HtpState *htp_state = NULL;
4240  int r = 0;
4242 
4243  memset(&ssn, 0, sizeof(ssn));
4244 
4245  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4246  if (f == NULL)
4247  goto end;
4248  f->protoctx = &ssn;
4249  f->proto = IPPROTO_TCP;
4250  f->alproto = ALPROTO_HTTP1;
4251 
4252  StreamTcpInitConfig(true);
4253 
4254  uint32_t u;
4255  for (u = 0; u < httplen1; u++) {
4256  uint8_t flags = 0;
4257 
4258  if (u == 0)
4259  flags = STREAM_TOSERVER|STREAM_START;
4260  else if (u == (httplen1 - 1))
4261  flags = STREAM_TOSERVER|STREAM_EOF;
4262  else
4263  flags = STREAM_TOSERVER;
4264 
4265  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4266  if (r != 0) {
4267  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4268  " 0: ", u, r);
4269  goto end;
4270  }
4271  }
4272 
4273  htp_state = f->alstate;
4274  if (htp_state == NULL) {
4275  printf("no http state: ");
4276  goto end;
4277  }
4278 
4279  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4280  if (tx == NULL)
4281  goto end;
4282  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4283  if (tx != NULL && tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4284  if (4 != bstr_len(tx_ud->request_uri_normalized)) {
4285  printf("normalized uri len should be 2, is %"PRIuMAX,
4286  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
4287  goto end;
4288  }
4289 
4290  if (bstr_ptr(tx_ud->request_uri_normalized)[0] != '/' ||
4291  bstr_ptr(tx_ud->request_uri_normalized)[1] != '%' ||
4292  bstr_ptr(tx_ud->request_uri_normalized)[2] != '0' ||
4293  bstr_ptr(tx_ud->request_uri_normalized)[3] != '0')
4294  {
4295  printf("normalized uri \"");
4296  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
4297  printf("\": ");
4298  goto end;
4299  }
4300  }
4301 
4302  result = 1;
4303 end:
4304  if (alp_tctx != NULL)
4306  StreamTcpFreeConfig(true);
4307  UTHFreeFlow(f);
4308  return result;
4309 }
4310 
4311 /** \test double encoding in query
4312  */
4313 static int HTPParserTest12(void)
4314 {
4315  int result = 0;
4316  Flow *f = NULL;
4317  uint8_t httpbuf1[] = "GET /?a=%2500 HTTP/1.0\r\n\r\n";
4318  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4319  TcpSession ssn;
4320  HtpState *htp_state = NULL;
4321  int r = 0;
4323 
4324  memset(&ssn, 0, sizeof(ssn));
4325 
4326  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4327  if (f == NULL)
4328  goto end;
4329  f->protoctx = &ssn;
4330  f->proto = IPPROTO_TCP;
4331  f->alproto = ALPROTO_HTTP1;
4332 
4333  StreamTcpInitConfig(true);
4334 
4335  uint32_t u;
4336  for (u = 0; u < httplen1; u++) {
4337  uint8_t flags = 0;
4338 
4339  if (u == 0)
4340  flags = STREAM_TOSERVER|STREAM_START;
4341  else if (u == (httplen1 - 1))
4342  flags = STREAM_TOSERVER|STREAM_EOF;
4343  else
4344  flags = STREAM_TOSERVER;
4345 
4346  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4347  if (r != 0) {
4348  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4349  " 0: ", u, r);
4350  goto end;
4351  }
4352  }
4353 
4354  htp_state = f->alstate;
4355  if (htp_state == NULL) {
4356  printf("no http state: ");
4357  goto end;
4358  }
4359 
4360  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4361  if (tx == NULL)
4362  goto end;
4363  HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
4364  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4365  if (7 != bstr_len(tx_ud->request_uri_normalized)) {
4366  printf("normalized uri len should be 5, is %"PRIuMAX,
4367  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
4368  goto end;
4369  }
4370 
4371  if (bstr_ptr(tx_ud->request_uri_normalized)[0] != '/' ||
4372  bstr_ptr(tx_ud->request_uri_normalized)[1] != '?' ||
4373  bstr_ptr(tx_ud->request_uri_normalized)[2] != 'a' ||
4374  bstr_ptr(tx_ud->request_uri_normalized)[3] != '=' ||
4375  bstr_ptr(tx_ud->request_uri_normalized)[4] != '%' ||
4376  bstr_ptr(tx_ud->request_uri_normalized)[5] != '0' ||
4377  bstr_ptr(tx_ud->request_uri_normalized)[6] != '0')
4378  {
4379  printf("normalized uri \"");
4380  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
4381  printf("\": ");
4382  goto end;
4383  }
4384  }
4385 
4386  result = 1;
4387  end:
4388  if (alp_tctx != NULL)
4390  StreamTcpFreeConfig(true);
4391  UTHFreeFlow(f);
4392  return result;
4393 }
4394 
4395 /** \test Host:www.google.com0dName: Value0d0a <- missing space between name:value (rfc violation)
4396  */
4397 static int HTPParserTest13(void)
4398 {
4399  int result = 0;
4400  Flow *f = NULL;
4401  uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\rName: Value\r\n\r\n";
4402  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4403  TcpSession ssn;
4404  HtpState *htp_state = NULL;
4405  int r = 0;
4407 
4408  memset(&ssn, 0, sizeof(ssn));
4409 
4410  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4411  if (f == NULL)
4412  goto end;
4413  f->protoctx = &ssn;
4414  f->proto = IPPROTO_TCP;
4415  f->alproto = ALPROTO_HTTP1;
4416 
4417  StreamTcpInitConfig(true);
4418 
4419  uint32_t u;
4420  for (u = 0; u < httplen1; u++) {
4421  uint8_t flags = 0;
4422 
4423  if (u == 0)
4424  flags = STREAM_TOSERVER|STREAM_START;
4425  else if (u == (httplen1 - 1))
4426  flags = STREAM_TOSERVER|STREAM_EOF;
4427  else
4428  flags = STREAM_TOSERVER;
4429 
4430  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4431  if (r != 0) {
4432  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4433  " 0: ", u, r);
4434  goto end;
4435  }
4436  }
4437 
4438  htp_state = f->alstate;
4439  if (htp_state == NULL) {
4440  printf("no http state: ");
4441  goto end;
4442  }
4443 
4444  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4445  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
4446  if (h == NULL) {
4447  goto end;
4448  }
4449 
4450  char *name = bstr_util_strdup_to_c(h->name);
4451  if (name == NULL) {
4452  goto end;
4453  }
4454 
4455  if (strcmp(name, "Host") != 0) {
4456  printf("header name not \"Host\", instead \"%s\": ", name);
4457  free(name);
4458  goto end;
4459  }
4460  free(name);
4461 
4462  char *value = bstr_util_strdup_to_c(h->value);
4463  if (value == NULL) {
4464  goto end;
4465  }
4466 
4467  if (strcmp(value, "www.google.com\rName: Value") != 0) {
4468  printf("header value not \"www.google.com\", instead \"");
4469  PrintRawUriFp(stdout, (uint8_t *)value, strlen(value));
4470  printf("\": ");
4471  free(value);
4472  goto end;
4473  }
4474  free(value);
4475 
4476  result = 1;
4477 end:
4478  if (alp_tctx != NULL)
4480  StreamTcpFreeConfig(true);
4481  UTHFreeFlow(f);
4482  return result;
4483 }
4484 
4485 /** \test Test basic config */
4486 static int HTPParserConfigTest01(void)
4487 {
4488  int ret = 0;
4489  char input[] = "\
4490 %YAML 1.1\n\
4491 ---\n\
4492 libhtp:\n\
4493 \n\
4494  default-config:\n\
4495  personality: IDS\n\
4496 \n\
4497  server-config:\n\
4498 \n\
4499  - apache-tomcat:\n\
4500  address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
4501  personality: Tomcat_6_0\n\
4502 \n\
4503  - iis7:\n\
4504  address: \n\
4505  - 192.168.0.0/24\n\
4506  - 192.168.10.0/24\n\
4507  personality: IIS_7_0\n\
4508 ";
4509 
4511  ConfInit();
4512 
4513  ConfYamlLoadString(input, strlen(input));
4514 
4515  ConfNode *outputs;
4516  outputs = ConfGetNode("libhtp.default-config.personality");
4517  if (outputs == NULL) {
4518  goto end;
4519  }
4520 
4521  outputs = ConfGetNode("libhtp.server-config");
4522  if (outputs == NULL) {
4523  goto end;
4524  }
4525 
4526  ConfNode *node = TAILQ_FIRST(&outputs->head);
4527  if (node == NULL) {
4528  goto end;
4529  }
4530  if (strcmp(node->name, "0") != 0) {
4531  goto end;
4532  }
4533  node = TAILQ_FIRST(&node->head);
4534  if (node == NULL) {
4535  goto end;
4536  }
4537  if (strcmp(node->name, "apache-tomcat") != 0) {
4538  goto end;
4539  }
4540 
4541  int i = 0;
4542  ConfNode *n;
4543 
4544  ConfNode *node2 = ConfNodeLookupChild(node, "personality");
4545  if (node2 == NULL) {
4546  goto end;
4547  }
4548  if (strcmp(node2->val, "Tomcat_6_0") != 0) {
4549  goto end;
4550  }
4551 
4552  node = ConfNodeLookupChild(node, "address");
4553  if (node == NULL) {
4554  goto end;
4555  }
4556  TAILQ_FOREACH(n, &node->head, next) {
4557  if (n == NULL) {
4558  goto end;
4559  }
4560 
4561  switch(i) {
4562  case 0:
4563  if (strcmp(n->name, "0") != 0) {
4564  goto end;
4565  }
4566  if (strcmp(n->val, "192.168.1.0/24") != 0) {
4567  goto end;
4568  }
4569  break;
4570  case 1:
4571  if (strcmp(n->name, "1") != 0) {
4572  goto end;
4573  }
4574  if (strcmp(n->val, "127.0.0.0/8") != 0) {
4575  goto end;
4576  }
4577  break;
4578  case 2:
4579  if (strcmp(n->name, "2") != 0) {
4580  goto end;
4581  }
4582  if (strcmp(n->val, "::1") != 0) {
4583  goto end;
4584  }
4585  break;
4586  default:
4587  goto end;
4588  }
4589  i++;
4590  }
4591 
4592  outputs = ConfGetNode("libhtp.server-config");
4593  if (outputs == NULL) {
4594  goto end;
4595  }
4596 
4597  node = TAILQ_FIRST(&outputs->head);
4598  node = TAILQ_NEXT(node, next);
4599  if (node == NULL) {
4600  goto end;
4601  }
4602  if (strcmp(node->name, "1") != 0) {
4603  goto end;
4604  }
4605  node = TAILQ_FIRST(&node->head);
4606  if (node == NULL) {
4607  goto end;
4608  }
4609  if (strcmp(node->name, "iis7") != 0) {
4610  goto end;
4611  }
4612 
4613  node2 = ConfNodeLookupChild(node, "personality");
4614  if (node2 == NULL) {
4615  goto end;
4616  }
4617  if (strcmp(node2->val, "IIS_7_0") != 0) {
4618  goto end;
4619  }
4620 
4621  node = ConfNodeLookupChild(node, "address");
4622  if (node == NULL) {
4623  goto end;
4624  }
4625 
4626  i = 0;
4627  TAILQ_FOREACH(n, &node->head, next) {
4628  if (n == NULL) {
4629  goto end;
4630  }
4631 
4632  switch(i) {
4633  case 0:
4634  if (strcmp(n->name, "0") != 0) {
4635  goto end;
4636  }
4637  if (strcmp(n->val, "192.168.0.0/24") != 0) {
4638  goto end;
4639  }
4640  break;
4641  case 1:
4642  if (strcmp(n->name, "1") != 0) {
4643  goto end;
4644  }
4645  if (strcmp(n->val, "192.168.10.0/24") != 0) {
4646  goto end;
4647  }
4648  break;
4649  default:
4650  goto end;
4651  }
4652  i++;
4653  }
4654 
4655  ret = 1;
4656 
4657 end:
4658  ConfDeInit();
4660 
4661  return ret;
4662 }
4663 
4664 /** \test Test config builds radix correctly */
4665 static int HTPParserConfigTest02(void)
4666 {
4667  int ret = 0;
4668  char input[] = "\
4669 %YAML 1.1\n\
4670 ---\n\
4671 libhtp:\n\
4672 \n\
4673  default-config:\n\
4674  personality: IDS\n\
4675 \n\
4676  server-config:\n\
4677 \n\
4678  - apache-tomcat:\n\
4679  address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
4680  personality: Tomcat_6_0\n\
4681 \n\
4682  - iis7:\n\
4683  address: \n\
4684  - 192.168.0.0/24\n\
4685  - 192.168.10.0/24\n\
4686  personality: IIS_7_0\n\
4687 ";
4688 
4690  ConfInit();
4692 
4693  ConfYamlLoadString(input, strlen(input));
4694 
4695  HTPConfigure();
4696 
4697  if (cfglist.cfg == NULL) {
4698  printf("No default config created.\n");
4699  goto end;
4700  }
4701 
4702  if (cfgtree == NULL) {
4703  printf("No config tree created.\n");
4704  goto end;
4705  }
4706 
4707  htp_cfg_t *htp = cfglist.cfg;
4708  uint8_t buf[128];
4709  const char *addr;
4710  void *user_data = NULL;
4711 
4712  addr = "192.168.10.42";
4713  if (inet_pton(AF_INET, addr, buf) == 1) {
4714  (void)SCRadixFindKeyIPV4BestMatch(buf, cfgtree, &user_data);
4715  if (user_data != NULL) {
4716  HTPCfgRec *htp_cfg_rec = user_data;
4717  htp = htp_cfg_rec->cfg;
4718  SCLogDebug("LIBHTP using config: %p", htp);
4719  }
4720  if (htp == NULL) {
4721  printf("Could not get config for: %s\n", addr);
4722  goto end;
4723  }
4724  }
4725  else {
4726  printf("Failed to parse address: %s\n", addr);
4727  goto end;
4728  }
4729 
4730  user_data = NULL;
4731  addr = "::1";
4732  if (inet_pton(AF_INET6, addr, buf) == 1) {
4733  (void)SCRadixFindKeyIPV6BestMatch(buf, cfgtree, &user_data);
4734  if (user_data != NULL) {
4735  HTPCfgRec *htp_cfg_rec = user_data;
4736  htp = htp_cfg_rec->cfg;
4737  SCLogDebug("LIBHTP using config: %p", htp);
4738  }
4739  if (htp == NULL) {
4740  printf("Could not get config for: %s\n", addr);
4741  goto end;
4742  }
4743  }
4744  else {
4745  printf("Failed to parse address: %s\n", addr);
4746  goto end;
4747  }
4748 
4749  ret = 1;
4750 
4751 end:
4752  HTPFreeConfig();
4753  ConfDeInit();
4756 
4757  return ret;
4758 }
4759 
4760 /** \test Test traffic is handled by the correct htp config */
4761 static int HTPParserConfigTest03(void)
4762 {
4763  int result = 1;
4764  Flow *f = NULL;
4765  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
4766  " Data is c0oL!";
4767  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4768  TcpSession ssn;
4770 
4771  HtpState *htp_state = NULL;
4772  int r = 0;
4773  char input[] = "\
4774 %YAML 1.1\n\
4775 ---\n\
4776 libhtp:\n\
4777 \n\
4778  default-config:\n\
4779  personality: IDS\n\
4780 \n\
4781  server-config:\n\
4782 \n\
4783  - apache-tomcat:\n\
4784  address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
4785  personality: Tomcat_6_0\n\
4786 \n\
4787  - iis7:\n\
4788  address: \n\
4789  - 192.168.0.0/24\n\
4790  - 192.168.10.0/24\n\
4791  personality: IIS_7_0\n\
4792 ";
4793 
4795  ConfInit();
4797 
4798  ConfYamlLoadString(input, strlen(input));
4799 
4800  HTPConfigure();
4801 
4802  const char *addr = "192.168.10.42";
4803 
4804  memset(&ssn, 0, sizeof(ssn));
4805 
4806  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4807  if (f == NULL)
4808  goto end;
4809  f->protoctx = &ssn;
4810  f->proto = IPPROTO_TCP;
4811  f->alproto = ALPROTO_HTTP1;
4812 
4813  htp_cfg_t *htp = cfglist.cfg;
4814 
4815  void *user_data = NULL;
4816  (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)f->dst.addr_data32, cfgtree, &user_data);
4817  if (user_data != NULL) {
4818  HTPCfgRec *htp_cfg_rec = user_data;
4819  htp = htp_cfg_rec->cfg;
4820  SCLogDebug("LIBHTP using config: %p", htp);
4821  }
4822  if (htp == NULL) {
4823  printf("Could not get config for: %s\n", addr);
4824  goto end;
4825  }
4826 
4827  StreamTcpInitConfig(true);
4828 
4829  uint32_t u;
4830  for (u = 0; u < httplen1; u++) {
4831  uint8_t flags = 0;
4832 
4833  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4834  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4835  else flags = STREAM_TOSERVER;
4836 
4837  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4838  if (r != 0) {
4839  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4840  " 0: ", u, r);
4841  result = 0;
4842  goto end;
4843  }
4844  }
4845 
4846  htp_state = f->alstate;
4847  if (htp_state == NULL) {
4848  printf("no http state: ");
4849  result = 0;
4850  goto end;
4851  }
4852 
4853  if (HTPStateGetTxCnt(htp_state) != 2) {
4854  printf("HTPStateGetTxCnt(htp_state) failure\n");
4855  goto end;
4856  }
4857 
4858  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4859  if (tx == NULL)
4860  goto end;
4861  if (tx->cfg != htp) {
4862  printf("wrong HTP config (%p instead of %p - default=%p): ",
4863  tx->cfg, htp, cfglist.cfg);
4864  goto end;
4865  }
4866  tx = HTPStateGetTx(htp_state, 1);
4867  if (tx == NULL)
4868  goto end;
4869  if (tx->cfg != htp) {
4870  printf("wrong HTP config (%p instead of %p - default=%p): ",
4871  tx->cfg, htp, cfglist.cfg);
4872  goto end;
4873  }
4874 
4875 end:
4876  if (alp_tctx != NULL)
4878  HTPFreeConfig();
4879  ConfDeInit();
4882 
4883  StreamTcpFreeConfig(true);
4884  UTHFreeFlow(f);
4885  return result;
4886 }
4887 
4888 /** \test Test %2f decoding in profile Apache_2_2
4889  *
4890  * %2f in path is left untouched
4891  * %2f in query string is normalized to %2F
4892  * %252f in query string is decoded/normalized to %2F
4893  */
4894 static int HTPParserDecodingTest01(void)
4895 {
4896  uint8_t httpbuf1[] =
4897  "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4898  "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4899  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4900  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4901  TcpSession ssn;
4904 
4905  char input[] = "\
4906 %YAML 1.1\n\
4907 ---\n\
4908 libhtp:\n\
4909 \n\
4910  default-config:\n\
4911  personality: Apache_2\n\
4912 ";
4913 
4915  ConfInit();
4917  ConfYamlLoadString(input, strlen(input));
4918  HTPConfigure();
4919  const char *addr = "4.3.2.1";
4920  memset(&ssn, 0, sizeof(ssn));
4921 
4922  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4923  FAIL_IF_NULL(f);
4924  f->protoctx = &ssn;
4925  f->proto = IPPROTO_TCP;
4926  f->alproto = ALPROTO_HTTP1;
4927 
4928  StreamTcpInitConfig(true);
4929 
4930  for (uint32_t u = 0; u < httplen1; u++) {
4931  uint8_t flags = 0;
4932  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4933  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4934  else flags = STREAM_TOSERVER;
4935 
4936  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4937  FAIL_IF(r != 0);
4938  }
4939 
4940  HtpState *htp_state = f->alstate;
4941  FAIL_IF_NULL(htp_state);
4942 
4943  uint8_t ref1[] = "/abc%2fdef";
4944  size_t reflen = sizeof(ref1) - 1;
4945 
4946  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4947  FAIL_IF_NULL(tx);
4948 
4949  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4950  FAIL_IF_NULL(tx_ud);
4952  FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized));
4953  FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
4954  bstr_len(tx_ud->request_uri_normalized)) != 0);
4955 
4956  uint8_t ref2[] = "/abc/def?ghi/jkl";
4957  reflen = sizeof(ref2) - 1;
4958 
4959  tx = HTPStateGetTx(htp_state, 1);
4960  FAIL_IF_NULL(tx);
4961  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4962  FAIL_IF_NULL(tx_ud);
4964  FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized));
4965 
4966  FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2,
4967  bstr_len(tx_ud->request_uri_normalized)) != 0);
4968 
4969  uint8_t ref3[] = "/abc/def?ghi%2fjkl";
4970  reflen = sizeof(ref3) - 1;
4971  tx = HTPStateGetTx(htp_state, 2);
4972  FAIL_IF_NULL(tx);
4973  tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
4974  FAIL_IF_NULL(tx_ud);
4976  FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized));
4977 
4978  FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3,
4979  bstr_len(tx_ud->request_uri_normalized)) != 0);
4980 
4982  HTPFreeConfig();
4983  ConfDeInit();
4986 
4987  StreamTcpFreeConfig(true);
4988  UTHFreeFlow(f);
4989  PASS;
4990 }
4991 
4992 static int HTPParserDecodingTest01a(void)
4993 {
4994  uint8_t httpbuf1[] = "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4995  "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4996  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4997  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4998  TcpSession ssn;
5001 
5002  char input[] = "\
5003 %YAML 1.1\n\
5004 ---\n\
5005 libhtp:\n\
5006 \n\
5007  default-config:\n\
5008  personality: Apache_2\n\
5009 ";
5010 
5012  ConfInit();
5014  ConfYamlLoadString(input, strlen(input));
5015  HTPConfigure();
5016  const char *addr = "4.3.2.1";
5017  memset(&ssn, 0, sizeof(ssn));
5018 
5019  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5020  FAIL_IF_NULL(f);
5021  f->protoctx = &ssn;
5022  f->proto = IPPROTO_TCP;
5023  f->alproto = ALPROTO_HTTP1;
5024 
5025  StreamTcpInitConfig(true);
5026 
5027  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
5028  (STREAM_TOSERVER | STREAM_START | STREAM_EOF), httpbuf1, httplen1);
5029  FAIL_IF(r != 0);
5030 
5031  HtpState *htp_state = f->alstate;
5032  FAIL_IF_NULL(htp_state);
5033 
5034  uint8_t ref1[] = "/abc%2fdef";
5035  size_t reflen = sizeof(ref1) - 1;
5036 
5037  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5038  FAIL_IF_NULL(tx);
5039 
5040  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
5041  FAIL_IF_NULL(tx_ud);
5043  FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized));
5044  FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5045  bstr_len(tx_ud->request_uri_normalized)) != 0);
5046 
5047  uint8_t ref2[] = "/abc/def?ghi/jkl";
5048  reflen = sizeof(ref2) - 1;
5049 
5050  tx = HTPStateGetTx(htp_state, 1);
5051  FAIL_IF_NULL(tx);
5052  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
5053  FAIL_IF_NULL(tx_ud);
5055  FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized));
5056 
5057  FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2,
5058  bstr_len(tx_ud->request_uri_normalized)) != 0);
5059 
5060  uint8_t ref3[] = "/abc/def?ghi%2fjkl";
5061  reflen = sizeof(ref3) - 1;
5062  tx = HTPStateGetTx(htp_state, 2);
5063  FAIL_IF_NULL(tx);
5064  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
5065  FAIL_IF_NULL(tx_ud);
5067  FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized));
5068 
5069  FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3,
5070  bstr_len(tx_ud->request_uri_normalized)) != 0);
5071 
5073  HTPFreeConfig();
5074  ConfDeInit();
5077 
5078  StreamTcpFreeConfig(true);
5079  UTHFreeFlow(f);
5080  PASS;
5081 }
5082 
5083 /** \test Test %2f decoding in profile IDS
5084  *
5085  * %2f in path decoded to /
5086  * %2f in query string is decoded to /
5087  * %252f in query string is decoded to %2F
5088  */
5089 static int HTPParserDecodingTest02(void)
5090 {
5091  int result = 0;
5092  Flow *f = NULL;
5093  uint8_t httpbuf1[] =
5094  "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
5095  "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
5096  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5097  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5098  TcpSession ssn;
5100 
5101  HtpState *htp_state = NULL;
5102  int r = 0;
5103  char input[] = "\
5104 %YAML 1.1\n\
5105 ---\n\
5106 libhtp:\n\
5107 \n\
5108  default-config:\n\
5109  personality: IDS\n\
5110  double-decode-path: no\n\
5111  double-decode-query: no\n\
5112 ";
5113 
5115  ConfInit();
5117  ConfYamlLoadString(input, strlen(input));
5118  HTPConfigure();
5119  const char *addr = "4.3.2.1";
5120  memset(&ssn, 0, sizeof(ssn));
5121 
5122  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5123  if (f == NULL)
5124  goto end;
5125  f->protoctx = &ssn;
5126  f->proto = IPPROTO_TCP;
5127  f->alproto = ALPROTO_HTTP1;
5128 
5129  StreamTcpInitConfig(true);
5130 
5131  uint32_t u;
5132  for (u = 0; u < httplen1; u++) {
5133  uint8_t flags = 0;
5134 
5135  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5136  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5137  else flags = STREAM_TOSERVER;
5138 
5139  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
5140  if (r != 0) {
5141  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5142  " 0: ", u, r);
5143  goto end;
5144  }
5145  }
5146 
5147  htp_state = f->alstate;
5148  if (htp_state == NULL) {
5149  printf("no http state: ");
5150  goto end;
5151  }
5152 
5153  uint8_t ref1[] = "/abc/def";
5154  size_t reflen = sizeof(ref1) - 1;
5155 
5156  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5157  if (tx == NULL)
5158  goto end;
5159  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
5160  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5161  if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5162  printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5163  (uintmax_t)reflen,
5164  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
5165  goto end;
5166  }
5167 
5168  if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5169  bstr_len(tx_ud->request_uri_normalized)) != 0)
5170  {
5171  printf("normalized uri \"");
5172  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5173  printf("\" != \"");
5174  PrintRawUriFp(stdout, ref1, reflen);
5175  printf("\": ");
5176  goto end;
5177  }
5178  }
5179 
5180  uint8_t ref2[] = "/abc/def?ghi/jkl";
5181  reflen = sizeof(ref2) - 1;
5182 
5183  tx = HTPStateGetTx(htp_state, 1);
5184  if (tx == NULL)
5185  goto end;
5186  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
5187  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5188  if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5189  printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5190  (uintmax_t)reflen,
5191  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
5192  goto end;
5193  }
5194 
5195  if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2,
5196  bstr_len(tx_ud->request_uri_normalized)) != 0)
5197  {
5198  printf("normalized uri \"");
5199  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5200  printf("\" != \"");
5201  PrintRawUriFp(stdout, ref2, reflen);
5202  printf("\": ");
5203  goto end;
5204  }
5205  }
5206 
5207  uint8_t ref3[] = "/abc/def?ghi%2fjkl";
5208  reflen = sizeof(ref3) - 1;
5209  tx = HTPStateGetTx(htp_state, 2);
5210  if (tx == NULL)
5211  goto end;
5212  tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5213  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5214  if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5215  printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX" (3): ",
5216  (uintmax_t)reflen,
5217  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
5218  goto end;
5219  }
5220 
5221  if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3,
5222  bstr_len(tx_ud->request_uri_normalized)) != 0)
5223  {
5224  printf("normalized uri \"");
5225  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5226  printf("\" != \"");
5227  PrintRawUriFp(stdout, ref3, reflen);
5228  printf("\": ");
5229  goto end;
5230  }
5231  }
5232 
5233  result = 1;
5234 
5235 end:
5236  if (alp_tctx != NULL)
5238  HTPFreeConfig();
5239  ConfDeInit();
5242 
5243  StreamTcpFreeConfig(true);
5244  UTHFreeFlow(f);
5245  return result;
5246 }
5247 
5248 /** \test Test %2f decoding in profile IDS with double-decode-* options
5249  *
5250  * %252f in path decoded to /
5251  * %252f in query string is decoded to /
5252  */
5253 static int HTPParserDecodingTest03(void)
5254 {
5255  int result = 0;
5256  Flow *f = NULL;
5257  uint8_t httpbuf1[] =
5258  "GET /abc%252fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
5259  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5260  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5261  TcpSession ssn;
5263 
5264  HtpState *htp_state = NULL;
5265  int r = 0;
5266  char input[] = "\
5267 %YAML 1.1\n\
5268 ---\n\
5269 libhtp:\n\
5270 \n\
5271  default-config:\n\
5272  personality: IDS\n\
5273  double-decode-path: yes\n\
5274  double-decode-query: yes\n\
5275 ";
5276 
5278  ConfInit();
5280  ConfYamlLoadString(input, strlen(input));
5281  HTPConfigure();
5282  const char *addr = "4.3.2.1";
5283  memset(&ssn, 0, sizeof(ssn));
5284 
5285  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5286  if (f == NULL)
5287  goto end;
5288  f->protoctx = &ssn;
5289  f->proto = IPPROTO_TCP;
5290  f->alproto = ALPROTO_HTTP1;
5291 
5292  StreamTcpInitConfig(true);
5293 
5294  uint32_t u;
5295  for (u = 0; u < httplen1; u++) {
5296  uint8_t flags = 0;
5297 
5298  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5299  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5300  else flags = STREAM_TOSERVER;
5301 
5302  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
5303  if (r != 0) {
5304  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5305  " 0: ", u, r);
5306  goto end;
5307  }
5308  }
5309 
5310  htp_state = f->alstate;
5311  if (htp_state == NULL) {
5312  printf("no http state: ");
5313  goto end;
5314  }
5315 
5316  uint8_t ref1[] = "/abc/def";
5317  size_t reflen = sizeof(ref1) - 1;
5318 
5319  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5320  if (tx == NULL)
5321  goto end;
5322  HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5323  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5324  if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5325  printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5326  (uintmax_t)reflen,
5327  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
5328  goto end;
5329  }
5330 
5331  if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5332  bstr_len(tx_ud->request_uri_normalized)) != 0)
5333  {
5334  printf("normalized uri \"");
5335  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5336  printf("\" != \"");
5337  PrintRawUriFp(stdout, ref1, reflen);
5338  printf("\": ");
5339  goto end;
5340  }
5341  }
5342 
5343  uint8_t ref2[] = "/abc/def?ghi/jkl";
5344  reflen = sizeof(ref2) - 1;
5345 
5346  tx = HTPStateGetTx(htp_state, 1);
5347  if (tx == NULL)
5348  goto end;
5349  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
5350  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5351  if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5352  printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5353  (uintmax_t)reflen,
5354  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
5355  goto end;
5356  }
5357 
5358  if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2,
5359  bstr_len(tx_ud->request_uri_normalized)) != 0)
5360  {
5361  printf("normalized uri \"");
5362  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5363  printf("\" != \"");
5364  PrintRawUriFp(stdout, ref2, reflen);
5365  printf("\": ");
5366  goto end;
5367  }
5368  }
5369 
5370  result = 1;
5371 
5372 end:
5373  if (alp_tctx != NULL)
5375  HTPFreeConfig();
5376  ConfDeInit();
5379 
5380  StreamTcpFreeConfig(true);
5381  UTHFreeFlow(f);
5382  return result;
5383 }
5384 
5385 /** \test Test http:// in query profile IDS
5386  */
5387 static int HTPParserDecodingTest04(void)
5388 {
5389  int result = 0;
5390  Flow *f = NULL;
5391  uint8_t httpbuf1[] =
5392  "GET /abc/def?a=http://www.abc.com/ HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5393  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5394  TcpSession ssn;
5396 
5397  HtpState *htp_state = NULL;
5398  int r = 0;
5399  char input[] = "\
5400 %YAML 1.1\n\
5401 ---\n\
5402 libhtp:\n\
5403 \n\
5404  default-config:\n\
5405  personality: IDS\n\
5406  double-decode-path: yes\n\
5407  double-decode-query: yes\n\
5408 ";
5409 
5411  ConfInit();
5413  ConfYamlLoadString(input, strlen(input));
5414  HTPConfigure();
5415  const char *addr = "4.3.2.1";
5416  memset(&ssn, 0, sizeof(ssn));
5417 
5418  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5419  if (f == NULL)
5420  goto end;
5421  f->protoctx = &ssn;
5422  f->proto = IPPROTO_TCP;
5423  f->alproto = ALPROTO_HTTP1;
5424 
5425  StreamTcpInitConfig(true);
5426 
5427  uint32_t u;
5428  for (u = 0; u < httplen1; u++) {
5429  uint8_t flags = 0;
5430 
5431  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5432  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5433  else flags = STREAM_TOSERVER;
5434 
5435  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
5436  if (r != 0) {
5437  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5438  " 0: ", u, r);
5439  goto end;
5440  }
5441  }
5442 
5443  htp_state = f->alstate;
5444  if (htp_state == NULL) {
5445  printf("no http state: ");
5446  goto end;
5447  }
5448 
5449  uint8_t ref1[] = "/abc/def?a=http://www.abc.com/";
5450  size_t reflen = sizeof(ref1) - 1;
5451 
5452  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5453  if (tx == NULL)
5454  goto end;
5455  HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5456  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5457  if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5458  printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5459  (uintmax_t)reflen,
5460  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
5461  goto end;
5462  }
5463 
5464  if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5465  bstr_len(tx_ud->request_uri_normalized)) != 0)
5466  {
5467  printf("normalized uri \"");
5468  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5469  printf("\" != \"");
5470  PrintRawUriFp(stdout, ref1, reflen);
5471  printf("\": ");
5472  goto end;
5473  }
5474  }
5475 
5476  result = 1;
5477 
5478 end:
5479  if (alp_tctx != NULL)
5481  HTPFreeConfig();
5482  ConfDeInit();
5485 
5486  StreamTcpFreeConfig(true);
5487  UTHFreeFlow(f);
5488  return result;
5489 }
5490 
5491 /** \test Test \ char in query profile IDS. Bug 739
5492  */
5493 static int HTPParserDecodingTest05(void)
5494 {
5495  int result = 0;
5496  Flow *f = NULL;
5497  uint8_t httpbuf1[] =
5498  "GET /index?id=\\\"<script>alert(document.cookie)</script> HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5499  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5500  TcpSession ssn;
5502 
5503  HtpState *htp_state = NULL;
5504  int r = 0;
5505  char input[] = "\
5506 %YAML 1.1\n\
5507 ---\n\
5508 libhtp:\n\
5509 \n\
5510  default-config:\n\
5511  personality: IDS\n\
5512  double-decode-path: yes\n\
5513  double-decode-query: yes\n\
5514 ";
5515 
5517  ConfInit();
5519  ConfYamlLoadString(input, strlen(input));
5520  HTPConfigure();
5521  const char *addr = "4.3.2.1";
5522  memset(&ssn, 0, sizeof(ssn));
5523 
5524  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5525  if (f == NULL)
5526  goto end;
5527  f->protoctx = &ssn;
5528  f->proto = IPPROTO_TCP;
5529  f->alproto = ALPROTO_HTTP1;
5530 
5531  StreamTcpInitConfig(true);
5532 
5533  uint32_t u;
5534  for (u = 0; u < httplen1; u++) {
5535  uint8_t flags = 0;
5536 
5537  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5538  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5539  else flags = STREAM_TOSERVER;
5540 
5541  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
5542  if (r != 0) {
5543  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5544  " 0: ", u, r);
5545  goto end;
5546  }
5547  }
5548 
5549  htp_state = f->alstate;
5550  if (htp_state == NULL) {
5551  printf("no http state: ");
5552  goto end;
5553  }
5554 
5555  uint8_t ref1[] = "/index?id=\\\"<script>alert(document.cookie)</script>";
5556  size_t reflen = sizeof(ref1) - 1;
5557 
5558  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5559  if (tx == NULL)
5560  goto end;
5561  HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5562  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5563  if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5564  printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5565  (uintmax_t)reflen,
5566  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
5567  goto end;
5568  }
5569 
5570  if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5571  bstr_len(tx_ud->request_uri_normalized)) != 0)
5572  {
5573  printf("normalized uri \"");
5574  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5575  printf("\" != \"");
5576  PrintRawUriFp(stdout, ref1, reflen);
5577  printf("\": ");
5578  goto end;
5579  }
5580  }
5581 
5582  result = 1;
5583 
5584 end:
5585  if (alp_tctx != NULL)
5587  HTPFreeConfig();
5588  ConfDeInit();
5591 
5592  StreamTcpFreeConfig(true);
5593  UTHFreeFlow(f);
5594  return result;
5595 }
5596 
5597 /** \test Test + char in query. Bug 1035
5598  */
5599 static int HTPParserDecodingTest06(void)
5600 {
5601  int result = 0;
5602  Flow *f = NULL;
5603  uint8_t httpbuf1[] =
5604  "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5605  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5606  TcpSession ssn;
5608 
5609  HtpState *htp_state = NULL;
5610  int r = 0;
5611  char input[] = "\
5612 %YAML 1.1\n\
5613 ---\n\
5614 libhtp:\n\
5615 \n\
5616  default-config:\n\
5617  personality: IDS\n\
5618  double-decode-path: yes\n\
5619  double-decode-query: yes\n\
5620 ";
5621 
5623  ConfInit();
5625  ConfYamlLoadString(input, strlen(input));
5626  HTPConfigure();
5627  const char *addr = "4.3.2.1";
5628  memset(&ssn, 0, sizeof(ssn));
5629 
5630  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5631  if (f == NULL)
5632  goto end;
5633  f->protoctx = &ssn;
5634  f->proto = IPPROTO_TCP;
5635  f->alproto = ALPROTO_HTTP1;
5636 
5637  StreamTcpInitConfig(true);
5638 
5639  uint32_t u;
5640  for (u = 0; u < httplen1; u++) {
5641  uint8_t flags = 0;
5642 
5643  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5644  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5645  else flags = STREAM_TOSERVER;
5646 
5647  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
5648  if (r != 0) {
5649  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5650  " 0: ", u, r);
5651  goto end;
5652  }
5653  }
5654 
5655  htp_state = f->alstate;
5656  if (htp_state == NULL) {
5657  printf("no http state: ");
5658  goto end;
5659  }
5660 
5661  uint8_t ref1[] = "/put.php?ip=1.2.3.4&port=+6000";
5662  size_t reflen = sizeof(ref1) - 1;
5663 
5664  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5665  if (tx == NULL)
5666  goto end;
5667  HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5668  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5669  if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5670  printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5671  (uintmax_t)reflen,
5672  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
5673  goto end;
5674  }
5675 
5676  if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5677  bstr_len(tx_ud->request_uri_normalized)) != 0)
5678  {
5679  printf("normalized uri \"");
5680  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5681  printf("\" != \"");
5682  PrintRawUriFp(stdout, ref1, reflen);
5683  printf("\": ");
5684  goto end;
5685  }
5686  }
5687 
5688  result = 1;
5689 
5690 end:
5691  if (alp_tctx != NULL)
5693  HTPFreeConfig();
5694  ConfDeInit();
5697 
5698  StreamTcpFreeConfig(true);
5699  UTHFreeFlow(f);
5700  return result;
5701 }
5702 
5703 /** \test Test + char in query. Bug 1035
5704  */
5705 static int HTPParserDecodingTest07(void)
5706 {
5707  int result = 0;
5708  Flow *f = NULL;
5709  uint8_t httpbuf1[] =
5710  "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5711  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5712  TcpSession ssn;
5714 
5715  HtpState *htp_state = NULL;
5716  int r = 0;
5717  char input[] = "\
5718 %YAML 1.1\n\
5719 ---\n\
5720 libhtp:\n\
5721 \n\
5722  default-config:\n\
5723  personality: IDS\n\
5724  double-decode-path: yes\n\
5725  double-decode-query: yes\n\
5726  query-plusspace-decode: yes\n\
5727 ";
5728 
5730  ConfInit();
5732  ConfYamlLoadString(input, strlen(input));
5733  HTPConfigure();
5734  const char *addr = "4.3.2.1";
5735  memset(&ssn, 0, sizeof(ssn));
5736 
5737  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5738  if (f == NULL)
5739  goto end;
5740  f->protoctx = &ssn;
5741  f->proto = IPPROTO_TCP;
5742  f->alproto = ALPROTO_HTTP1;
5743 
5744  StreamTcpInitConfig(true);
5745 
5746  uint32_t u;
5747  for (u = 0; u < httplen1; u++) {
5748  uint8_t flags = 0;
5749 
5750  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5751  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5752  else flags = STREAM_TOSERVER;
5753 
5754  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
5755  if (r != 0) {
5756  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5757  " 0: ", u, r);
5758  goto end;
5759  }
5760  }
5761 
5762  htp_state = f->alstate;
5763  if (htp_state == NULL) {
5764  printf("no http state: ");
5765  goto end;
5766  }
5767 
5768  uint8_t ref1[] = "/put.php?ip=1.2.3.4&port= 6000";
5769  size_t reflen = sizeof(ref1) - 1;
5770 
5771  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5772  if (tx == NULL)
5773  goto end;
5774  HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5775  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5776  if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5777  printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5778  (uintmax_t)reflen,
5779  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
5780  goto end;
5781  }
5782 
5783  if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5784  bstr_len(tx_ud->request_uri_normalized)) != 0)
5785  {
5786  printf("normalized uri \"");
5787  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5788  printf("\" != \"");
5789  PrintRawUriFp(stdout, ref1, reflen);
5790  printf("\": ");
5791  goto end;
5792  }
5793  }
5794 
5795  result = 1;
5796 
5797 end:
5798  if (alp_tctx != NULL)
5800  HTPFreeConfig();
5801  ConfDeInit();
5804 
5805  StreamTcpFreeConfig(true);
5806  UTHFreeFlow(f);
5807  return result;
5808 }
5809 
5810 /** \test Test 'proxy' URI normalization. Ticket 1008
5811  */
5812 static int HTPParserDecodingTest08(void)
5813 {
5814  int result = 0;
5815  Flow *f = NULL;
5816  uint8_t httpbuf1[] =
5817  "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n";
5818  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5819  TcpSession ssn;
5821 
5822  HtpState *htp_state = NULL;
5823  int r = 0;
5824  char input[] = "\
5825 %YAML 1.1\n\
5826 ---\n\
5827 libhtp:\n\
5828 \n\
5829  default-config:\n\
5830  personality: IDS\n\
5831 ";
5832 
5834  ConfInit();
5836  ConfYamlLoadString(input, strlen(input));
5837  HTPConfigure();
5838  const char *addr = "4.3.2.1";
5839  memset(&ssn, 0, sizeof(ssn));
5840 
5841  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5842  if (f == NULL)
5843  goto end;
5844  f->protoctx = &ssn;
5845  f->proto = IPPROTO_TCP;
5846  f->alproto = ALPROTO_HTTP1;
5847 
5848  StreamTcpInitConfig(true);
5849 
5850  uint32_t u;
5851  for (u = 0; u < httplen1; u++) {
5852  uint8_t flags = 0;
5853 
5854  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5855  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5856  else flags = STREAM_TOSERVER;
5857 
5858  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
5859  if (r != 0) {
5860  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5861  " 0: ", u, r);
5862  goto end;
5863  }
5864  }
5865 
5866  htp_state = f->alstate;
5867  if (htp_state == NULL) {
5868  printf("no http state: ");
5869  goto end;
5870  }
5871 
5872  uint8_t ref1[] = "/blah/";
5873  size_t reflen = sizeof(ref1) - 1;
5874 
5875  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5876  if (tx == NULL)
5877  goto end;
5878  HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5879  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5880  if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5881  printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5882  (uintmax_t)reflen,
5883  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
5884  goto end;
5885  }
5886 
5887  if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5888  bstr_len(tx_ud->request_uri_normalized)) != 0)
5889  {
5890  printf("normalized uri \"");
5891  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5892  printf("\" != \"");
5893  PrintRawUriFp(stdout, ref1, reflen);
5894  printf("\": ");
5895  goto end;
5896  }
5897  }
5898 
5899  result = 1;
5900 
5901 end:
5902  if (alp_tctx != NULL)
5904  HTPFreeConfig();
5905  ConfDeInit();
5908 
5909  StreamTcpFreeConfig(true);
5910  UTHFreeFlow(f);
5911  return result;
5912 }
5913 
5914 /** \test Test 'proxy' URI normalization. Ticket 1008
5915  */
5916 static int HTPParserDecodingTest09(void)
5917 {
5918  int result = 0;
5919  Flow *f = NULL;
5920  uint8_t httpbuf1[] =
5921  "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n";
5922  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5923  TcpSession ssn;
5925 
5926  HtpState *htp_state = NULL;
5927  int r = 0;
5928  char input[] = "\
5929 %YAML 1.1\n\
5930 ---\n\
5931 libhtp:\n\
5932 \n\
5933  default-config:\n\
5934  personality: IDS\n\
5935  uri-include-all: true\n\
5936 ";
5937 
5939  ConfInit();
5941  ConfYamlLoadString(input, strlen(input));
5942  HTPConfigure();
5943  const char *addr = "4.3.2.1";
5944  memset(&ssn, 0, sizeof(ssn));
5945 
5946  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5947  if (f == NULL)
5948  goto end;
5949  f->protoctx = &ssn;
5950  f->proto = IPPROTO_TCP;
5951  f->alproto = ALPROTO_HTTP1;
5952 
5953  StreamTcpInitConfig(true);
5954 
5955  uint32_t u;
5956  for (u = 0; u < httplen1; u++) {
5957  uint8_t flags = 0;
5958 
5959  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5960  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5961  else flags = STREAM_TOSERVER;
5962 
5963  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
5964  if (r != 0) {
5965  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5966  " 0: ", u, r);
5967  goto end;
5968  }
5969  }
5970 
5971  htp_state = f->alstate;
5972  if (htp_state == NULL) {
5973  printf("no http state: ");
5974  goto end;
5975  }
5976 
5977  uint8_t ref1[] = "http://suricata-ids.org/blah/";
5978  size_t reflen = sizeof(ref1) - 1;
5979 
5980  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5981  if (tx == NULL)
5982  goto end;
5983  HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5984  if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5985  if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5986  printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5987  (uintmax_t)reflen,
5988  (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
5989  goto end;
5990  }
5991 
5992  if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5993  bstr_len(tx_ud->request_uri_normalized)) != 0)
5994  {
5995  printf("normalized uri \"");
5996  PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5997  printf("\" != \"");
5998  PrintRawUriFp(stdout, ref1, reflen);
5999  printf("\": ");
6000  goto end;
6001  }
6002  }
6003 
6004  result = 1;
6005 
6006 end:
6007  if (alp_tctx != NULL)
6009  HTPFreeConfig();
6010  ConfDeInit();
6013 
6014  StreamTcpFreeConfig(true);
6015  UTHFreeFlow(f);
6016  return result;
6017 }
6018 
6019 /** \test BG box crash -- chunks are messed up. Observed for real. */
6020 static int HTPBodyReassemblyTest01(void)
6021 {
6022  int result = 0;
6023  HtpTxUserData htud;
6024  memset(&htud, 0x00, sizeof(htud));
6025  HtpState hstate;
6026  memset(&hstate, 0x00, sizeof(hstate));
6027  Flow flow;
6028  memset(&flow, 0x00, sizeof(flow));
6030  htp_tx_t tx;
6031  memset(&tx, 0, sizeof(tx));
6032 
6033  hstate.f = &flow;
6034  flow.alparser = parser;
6035 
6036  uint8_t chunk1[] = "--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r";
6037  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";
6038 
6039  int r = HtpBodyAppendChunk(NULL, &htud.request_body, chunk1, sizeof(chunk1)-1);
6040  BUG_ON(r != 0);
6041  r = HtpBodyAppendChunk(NULL, &htud.request_body, chunk2, sizeof(chunk2)-1);
6042  BUG_ON(r != 0);
6043 
6044  const uint8_t *chunks_buffer = NULL;
6045  uint32_t chunks_buffer_len = 0;
6046 
6047  HtpRequestBodyReassemble(&htud, &chunks_buffer, &chunks_buffer_len);
6048  if (chunks_buffer == NULL) {
6049  goto end;
6050  }
6051 #ifdef PRINT
6052  printf("REASSCHUNK START: \n");
6053  PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
6054  printf("REASSCHUNK END: \n");
6055 #endif
6056 
6057  HtpRequestBodyHandleMultipart(&hstate, &htud, &tx, chunks_buffer, chunks_buffer_len);
6058 
6059  if (htud.request_body.content_len_so_far != 669) {
6060  printf("htud.request_body.content_len_so_far %"PRIu64": ", htud.request_body.content_len_so_far);
6061  goto end;
6062  }
6063 
6065 
6066  result = 1;
6067 end:
6068  return result;
6069 }
6070 
6071 /** \test BG crash */
6072 static int HTPSegvTest01(void)
6073 {
6074  int result = 0;
6075  Flow *f = NULL;
6076  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";
6077  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6078  char input[] = "\
6079 %YAML 1.1\n\
6080 ---\n\
6081 libhtp:\n\
6082 \n\
6083  default-config:\n\
6084  personality: IDS\n\
6085  double-decode-path: no\n\
6086  double-decode-query: no\n\
6087  request-body-limit: 0\n\
6088  response-body-limit: 0\n\
6089 ";
6090 
6092  ConfInit();
6094  ConfYamlLoadString(input, strlen(input));
6095  HTPConfigure();
6096 
6097  TcpSession ssn;
6098  HtpState *http_state = NULL;
6100 
6101  memset(&ssn, 0, sizeof(ssn));
6102 
6103  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6104  if (f == NULL)
6105  goto end;
6106  f->protoctx = &ssn;
6107  f->proto = IPPROTO_TCP;
6108  f->alproto = ALPROTO_HTTP1;
6109 
6110  StreamTcpInitConfig(true);
6111 
6112  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
6113  int r = AppLayerParserParse(
6114  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
6115  if (r != 0) {
6116  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
6117  goto end;
6118  }
6119  SCLogDebug("\n>>>> processing chunk 1 again <<<<\n");
6120  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
6121  if (r != 0) {
6122  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
6123  goto end;
6124  }
6125 
6126  http_state = f->alstate;
6127  if (http_state == NULL) {
6128  printf("no http state: ");
6129  goto end;
6130  }
6131 
6133  if (decoder_events != NULL) {
6134  printf("app events: ");
6135  goto end;
6136  }
6137  result = 1;
6138 end:
6139  if (alp_tctx != NULL)
6141  HTPFreeConfig();
6142  ConfDeInit();
6145  StreamTcpFreeConfig(true);
6146  UTHFreeFlow(f);
6147  return result;
6148 }
6149 
6150 /** \test Test really long request, this should result in HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG */
6151 static int HTPParserTest14(void)
6152 {
6153  size_t len = 18887;
6154  TcpSession ssn;
6155  char input[] = "\
6156 %YAML 1.1\n\
6157 ---\n\
6158 libhtp:\n\
6159 \n\
6160  default-config:\n\
6161  personality: IDS\n\
6162  double-decode-path: no\n\
6163  double-decode-query: no\n\
6164  request-body-limit: 0\n\
6165  response-body-limit: 0\n\
6166 ";
6169 
6170  memset(&ssn, 0, sizeof(ssn));
6171 
6173  ConfInit();
6175  ConfYamlLoadString(input, strlen(input));
6176  HTPConfigure();
6177 
6178  char *httpbuf = SCMalloc(len);
6179  FAIL_IF_NULL(httpbuf);
6180  memset(httpbuf, 0x00, len);
6181 
6182  /* create the request with a longer than 18k cookie */
6183  strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n"
6184  "Host: myhost.lan\r\n"
6185  "Connection: keep-alive\r\n"
6186  "Accept: */*\r\n"
6187  "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"
6188  "Referer: http://blah.lan/\r\n"
6189  "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
6190  "Cookie: ", len);
6191  size_t o = strlen(httpbuf);
6192  for ( ; o < len - 4; o++) {
6193  httpbuf[o] = 'A';
6194  }
6195  httpbuf[len - 4] = '\r';
6196  httpbuf[len - 3] = '\n';
6197  httpbuf[len - 2] = '\r';
6198  httpbuf[len - 1] = '\n';
6199 
6200  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6201  FAIL_IF_NULL(f);
6202  f->protoctx = &ssn;
6203  f->alproto = ALPROTO_HTTP1;
6204  f->proto = IPPROTO_TCP;
6205 
6206  StreamTcpInitConfig(true);
6207 
6208  uint32_t u;
6209  for (u = 0; u < len; u++) {
6210  uint8_t flags = 0;
6211 
6212  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
6213  else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
6214  else flags = STREAM_TOSERVER;
6215 
6216  (void)AppLayerParserParse(
6217  NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)&httpbuf[u], 1);
6218  }
6219  HtpState *htp_state = f->alstate;
6220  FAIL_IF_NULL(htp_state);
6221 
6222  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
6223  FAIL_IF_NULL(tx);
6224  FAIL_IF(tx->request_method_number != HTP_M_GET);
6225  FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
6226 
6227  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
6228  AppLayerDecoderEvents *decoder_events =
6229  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
6230  FAIL_IF_NULL(decoder_events);
6231 
6233 
6235  StreamTcpFreeConfig(true);
6236  UTHFreeFlow(f);
6237  SCFree(httpbuf);
6238  HTPFreeConfig();
6239  ConfDeInit();
6242  PASS;
6243 }
6244 
6245 /** \test Test really long request (same as HTPParserTest14), now with config
6246  * update to allow it */
6247 static int HTPParserTest15(void)
6248 {
6249  int result = 0;
6250  Flow *f = NULL;
6251  char *httpbuf = NULL;
6252  size_t len = 18887;
6253  TcpSession ssn;
6254  HtpState *htp_state = NULL;
6255  int r = 0;
6256  char input[] = "\
6257 %YAML 1.1\n\
6258 ---\n\
6259 libhtp:\n\
6260 \n\
6261  default-config:\n\
6262  personality: IDS\n\
6263  double-decode-path: no\n\
6264  double-decode-query: no\n\
6265  request-body-limit: 0\n\
6266  response-body-limit: 0\n\
6267  meta-field-limit: 20000\n\
6268 ";
6270 
6271  memset(&ssn, 0, sizeof(ssn));
6272 
6274  ConfInit();
6276  ConfYamlLoadString(input, strlen(input));
6277  HTPConfigure();
6278 
6279  httpbuf = SCMalloc(len);
6280  if (unlikely(httpbuf == NULL))
6281  goto end;
6282  memset(httpbuf, 0x00, len);
6283 
6284  /* create the request with a longer than 18k cookie */
6285  strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n"
6286  "Host: myhost.lan\r\n"
6287  "Connection: keep-alive\r\n"
6288  "Accept: */*\r\n"
6289  "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"
6290  "Referer: http://blah.lan/\r\n"
6291  "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
6292  "Cookie: ", len);
6293  size_t o = strlen(httpbuf);
6294  for ( ; o < len - 4; o++) {
6295  httpbuf[o] = 'A';
6296  }
6297  httpbuf[len - 4] = '\r';
6298  httpbuf[len - 3] = '\n';
6299  httpbuf[len - 2] = '\r';
6300  httpbuf[len - 1] = '\n';
6301 
6302  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6303  if (f == NULL)
6304  goto end;
6305  f->protoctx = &ssn;
6306  f->proto = IPPROTO_TCP;
6307  f->alproto = ALPROTO_HTTP1;
6308 
6309  StreamTcpInitConfig(true);
6310 
6311  uint32_t u;
6312  for (u = 0; u < len; u++) {
6313  uint8_t flags = 0;
6314 
6315  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
6316  else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
6317  else flags = STREAM_TOSERVER;
6318 
6319  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)&httpbuf[u], 1);
6320  if (r != 0) {
6321  printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
6322  " 0: ", u, r);
6323  goto end;
6324  }
6325  }
6326  htp_state = f->alstate;
6327  if (htp_state == NULL) {
6328  printf("no http state: ");
6329  goto end;
6330  }
6331 
6332  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
6333  if (tx == NULL || tx->request_method_number != HTP_M_GET || tx->request_protocol_number != HTP_PROTOCOL_1_1)
6334  {
6335  printf("expected method M_GET and got %s: , expected protocol "
6336  "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
6337  bstr_util_strdup_to_c(tx->request_protocol));
6338  goto end;
6339  }
6340 
6341  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
6342  AppLayerDecoderEvents *decoder_events =
6343  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
6344  if (decoder_events != NULL) {
6345  printf("app events: ");
6346  goto end;
6347  }
6348 
6349  result = 1;
6350 end:
6351  if (alp_tctx != NULL)
6353  StreamTcpFreeConfig(true);
6354  UTHFreeFlow(f);
6355  if (httpbuf != NULL)
6356  SCFree(httpbuf);
6357  HTPFreeConfig();
6358  ConfDeInit();
6361  return result;
6362 }
6363 
6364 /** \test Test unusual delims in request line HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG */
6365 static int HTPParserTest16(void)
6366 {
6367  int result = 0;
6368  Flow *f = NULL;
6369  TcpSession ssn;
6370  HtpState *htp_state = NULL;
6371  int r = 0;
6373 
6374  memset(&ssn, 0, sizeof(ssn));
6375 
6376  uint8_t httpbuf[] = "GET\f/blah/\fHTTP/1.1\r\n"
6377  "Host: myhost.lan\r\n"
6378  "Connection: keep-alive\r\n"
6379  "Accept: */*\r\n"
6380  "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"
6381  "Referer: http://blah.lan/\r\n"
6382  "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
6383  "Cookie: blah\r\n\r\n";
6384  size_t len = sizeof(httpbuf) - 1;
6385 
6386  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6387  if (f == NULL)
6388  goto end;
6389  f->protoctx = &ssn;
6390  f->proto = IPPROTO_TCP;
6391  f->alproto = ALPROTO_HTTP1;
6392 
6393  StreamTcpInitConfig(true);
6394 
6395  uint8_t flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
6396 
6397  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)httpbuf, len);
6398  if (r != 0) {
6399  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
6400  goto end;
6401  }
6402 
6403  htp_state = f->alstate;
6404  if (htp_state == NULL) {
6405  printf("no http state: ");
6406  goto end;
6407  }
6408 
6409  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
6410  if (tx == NULL || tx->request_method_number != HTP_M_GET || tx->request_protocol_number != HTP_PROTOCOL_1_1)
6411  {
6412  printf("expected method M_GET and got %s: , expected protocol "
6413  "HTTP/1.1 and got %s \n", tx ? bstr_util_strdup_to_c(tx->request_method) : "tx null",
6414  tx ? bstr_util_strdup_to_c(tx->request_protocol) : "tx null");
6415  goto end;
6416  }
6417 
6418 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
6419 //these events are disabled during fuzzing as they are too noisy and consume much resource
6420  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
6421  AppLayerDecoderEvents *decoder_events =
6422  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
6423  if (decoder_events == NULL) {
6424  printf("no app events: ");
6425  goto end;
6426  }
6427 
6428  if (decoder_events->events[0] != HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT) {
6429  printf("HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT not set: ");
6430  goto end;
6431  }
6432 
6433  if (decoder_events->events[1] != HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT) {
6434  printf("HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT not set: ");
6435  goto end;
6436  }
6437 #endif
6438 
6439  result = 1;
6440 end:
6441  if (alp_tctx != NULL)
6443  StreamTcpFreeConfig(true);
6444  UTHFreeFlow(f);
6445  return result;
6446 }
6447 
6448 /** \test Test response not HTTP
6449  */
6450 static int HTPParserTest20(void)
6451 {
6452  Flow *f = NULL;
6453  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
6454  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
6455  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
6456  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6457  uint8_t httpbuf2[] = "NOTHTTP\r\nSOMEOTHERDATA";
6458  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6459  uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA";
6460  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
6461  TcpSession ssn;
6462  HtpState *http_state = NULL;
6465 
6466  memset(&ssn, 0, sizeof(ssn));
6467 
6468  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6469  FAIL_IF_NULL(f);
6470  f->protoctx = &ssn;
6471  f->proto = IPPROTO_TCP;
6472  f->alproto = ALPROTO_HTTP1;
6473 
6474  StreamTcpInitConfig(true);
6475 
6476  int r = AppLayerParserParse(
6477  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
6478  FAIL_IF(r != 0);
6479 
6480  r = AppLayerParserParse(
6481  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
6482  FAIL_IF(r != 0);
6483 
6484  r = AppLayerParserParse(
6485  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf3, httplen3);
6486  FAIL_IF(r != 0);
6487 
6488  http_state = f->alstate;
6489  FAIL_IF_NULL(http_state);
6490  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
6491  FAIL_IF_NULL(tx);
6492  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
6493  FAIL_IF_NULL(h);
6494 
6495  FAIL_IF(tx->request_method_number != HTP_M_GET);
6496  FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
6497 
6498  FAIL_IF(tx->response_status_number != 0);
6499  FAIL_IF(tx->response_protocol_number != -1);
6500 
6502  StreamTcpFreeConfig(true);
6503  UTHFreeFlow(f);
6504  PASS;
6505 }
6506 
6507 /** \test Test response not HTTP
6508  */
6509 static int HTPParserTest21(void)
6510 {
6511  Flow *f = NULL;
6512  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
6513  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
6514  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
6515  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6516  uint8_t httpbuf2[] = "999 NOTHTTP REALLY\r\nSOMEOTHERDATA\r\n";
6517  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6518  uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA";
6519  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
6520  TcpSession ssn;
6521  HtpState *http_state = NULL;
6524 
6525  memset(&ssn, 0, sizeof(ssn));
6526 
6527  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6528  FAIL_IF_NULL(f);
6529  f->protoctx = &ssn;
6530  f->proto = IPPROTO_TCP;
6531  f->alproto = ALPROTO_HTTP1;
6532 
6533  StreamTcpInitConfig(true);
6534 
6535  int r = AppLayerParserParse(
6536  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
6537  FAIL_IF(r != 0);
6538 
6539  r = AppLayerParserParse(
6540  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
6541  FAIL_IF(r != 0);
6542 
6543  r = AppLayerParserParse(
6544  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf3, httplen3);
6545  FAIL_IF(r != 0);
6546 
6547  http_state = f->alstate;
6548  FAIL_IF_NULL(http_state);
6549  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
6550  FAIL_IF_NULL(tx);
6551  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
6552  FAIL_IF_NULL(h);
6553 
6554  FAIL_IF(tx->request_method_number != HTP_M_GET);
6555  FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
6556 
6557  FAIL_IF(tx->response_status_number != 0);
6558  FAIL_IF(tx->response_protocol_number != -1);
6559 
6561  StreamTcpFreeConfig(true);
6562  UTHFreeFlow(f);
6563  PASS;
6564 }
6565 
6566 /** \test Test response not HTTP
6567  */
6568 static int HTPParserTest22(void)
6569 {
6570  Flow *f = NULL;
6571  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
6572  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
6573  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
6574  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6575  uint8_t httpbuf2[] = "\r\n0000=0000000/ASDF3_31.zip, 456723\r\n"
6576  "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
6577  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6578  TcpSession ssn;
6579  HtpState *http_state = NULL;
6582 
6583  memset(&ssn, 0, sizeof(ssn));
6584 
6585  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6586  FAIL_IF_NULL(f);
6587  f->protoctx = &ssn;
6588  f->proto = IPPROTO_TCP;
6589  f->alproto = ALPROTO_HTTP1;
6590 
6591  StreamTcpInitConfig(true);
6592 
6593  int r = AppLayerParserParse(
6594  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
6595  FAIL_IF(r != 0);
6596 
6597  r = AppLayerParserParse(
6598  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
6599  FAIL_IF(r != 0);
6600 
6601  http_state = f->alstate;
6602  FAIL_IF_NULL(http_state);
6603  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
6604  FAIL_IF_NULL(tx);
6605  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
6606  FAIL_IF_NULL(h);
6607 
6608  FAIL_IF(tx->request_method_number != HTP_M_GET);
6609  FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
6610 
6611  FAIL_IF(tx->response_status_number != -0);
6612  FAIL_IF(tx->response_protocol_number != -1);
6613 
6615  StreamTcpFreeConfig(true);
6616  UTHFreeFlow(f);
6617  PASS;
6618 }
6619 
6620 /** \test Test response not HTTP
6621  */
6622 static int HTPParserTest23(void)
6623 {
6624  Flow *f = NULL;
6625  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
6626  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
6627  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
6628  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6629  uint8_t httpbuf2[] = "HTTP0000=0000000/ASDF3_31.zip, 456723\r\n"
6630  "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
6631  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6632  TcpSession ssn;
6633  HtpState *http_state = NULL;
6636 
6637  memset(&ssn, 0, sizeof(ssn));
6638 
6639  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6640  FAIL_IF_NULL(f);
6641  f->protoctx = &ssn;
6642  f->proto = IPPROTO_TCP;
6643  f->alproto = ALPROTO_HTTP1;
6644 
6645  StreamTcpInitConfig(true);
6646 
6647  int r = AppLayerParserParse(
6648  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
6649  FAIL_IF(r != 0);
6650 
6651  r = AppLayerParserParse(
6652  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
6653  FAIL_IF(r != 0);
6654 
6655  http_state = f->alstate;
6656  FAIL_IF_NULL(http_state);
6657  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
6658  FAIL_IF_NULL(tx);
6659  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
6660  FAIL_IF_NULL(h);
6661 
6662  FAIL_IF(tx->request_method_number != HTP_M_GET);
6663  FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
6664 
6665  FAIL_IF(tx->response_status_number != -1);
6666  FAIL_IF(tx->response_protocol_number != -2);
6667 
6669  StreamTcpFreeConfig(true);
6670  UTHFreeFlow(f);
6671  PASS;
6672 }
6673 
6674 /** \test Test response not HTTP
6675  */
6676 static int HTPParserTest24(void)
6677 {
6678  Flow *f = NULL;
6679  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
6680  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
6681  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
6682  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6683  uint8_t httpbuf2[] = "HTTP/1.0 0000=0000000/ASDF3_31.zip, 456723\r\n"
6684  "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
6685  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6686  TcpSession ssn;
6687  HtpState *http_state = NULL;
6690 
6691  memset(&ssn, 0, sizeof(ssn));
6692 
6693  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6694  FAIL_IF_NULL(f);
6695  f->protoctx = &ssn;
6696  f->proto = IPPROTO_TCP;
6697  f->alproto = ALPROTO_HTTP1;
6698 
6699  StreamTcpInitConfig(true);
6700 
6701  int r = AppLayerParserParse(
6702  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
6703  FAIL_IF(r != 0);
6704 
6705  r = AppLayerParserParse(
6706  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
6707  FAIL_IF(r != 0);
6708 
6709  http_state = f->alstate;
6710  FAIL_IF_NULL(http_state);
6711  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
6712  FAIL_IF_NULL(tx);
6713  htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
6714  FAIL_IF_NULL(h);
6715 
6716  FAIL_IF(tx->request_method_number != HTP_M_GET);
6717  FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1);
6718 
6719  FAIL_IF(tx->response_status_number != -1);
6720  FAIL_IF(tx->response_protocol_number != HTP_PROTOCOL_1_0);
6721 
6723  StreamTcpFreeConfig(true);
6724  UTHFreeFlow(f);
6725  PASS;
6726 }
6727 
6728 /** \test multi transactions and cleanup */
6729 static int HTPParserTest25(void)
6730 {
6733 
6734  StreamTcpInitConfig(true);
6735  TcpSession ssn;
6736  memset(&ssn, 0, sizeof(ssn));
6737 
6738  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
6739  FAIL_IF_NULL(f);
6740  f->protoctx = &ssn;
6741  f->proto = IPPROTO_TCP;
6742  f->alproto = ALPROTO_HTTP1;
6743 
6744  const char *str = "GET / HTTP/1.1\r\nHost: www.google.com\r\nUser-Agent: Suricata/1.0\r\n\r\n";
6745  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START,
6746  (uint8_t *)str, strlen(str));
6747  FAIL_IF_NOT(r == 0);
6748  r = AppLayerParserParse(
6749  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (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 
6770  str = "HTTP 1.1 200 OK\r\nServer: Suricata/1.0\r\nContent-Length: 8\r\n\r\nSuricata";
6771  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START,
6772  (uint8_t *)str, strlen(str));
6773  FAIL_IF_NOT(r == 0);
6774  r = AppLayerParserParse(
6775  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (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 
6796  AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
6797 
6798  uint64_t ret[4];
6799  UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
6800  FAIL_IF_NOT(ret[0] == 8); // inspect_id[0]
6801  FAIL_IF_NOT(ret[1] == 8); // inspect_id[1]
6802  FAIL_IF_NOT(ret[2] == 8); // log_id
6803  FAIL_IF_NOT(ret[3] == 8); // min_id
6804 
6805  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF,
6806  (uint8_t *)str, strlen(str));
6807  FAIL_IF_NOT(r == 0);
6808  AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
6809 
6810  UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
6811  FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] not updated by ..Cleanup() until full tx is done
6812  FAIL_IF_NOT(ret[1] == 8); // inspect_id[1]
6813  FAIL_IF_NOT(ret[2] == 8); // log_id
6814  FAIL_IF_NOT(ret[3] == 8); // min_id
6815 
6816  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_EOF,
6817  (uint8_t *)str, strlen(str));
6818  FAIL_IF_NOT(r == 0);
6819  AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
6820 
6821  UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
6822  FAIL_IF_NOT(ret[0] == 9); // inspect_id[0]
6823  FAIL_IF_NOT(ret[1] == 9); // inspect_id[1]
6824  FAIL_IF_NOT(ret[2] == 9); // log_id
6825  FAIL_IF_NOT(ret[3] == 9); // min_id
6826 
6827  HtpState *http_state = f->alstate;
6828  FAIL_IF_NULL(http_state);
6829 
6831  StreamTcpFreeConfig(true);
6832  UTHFreeFlow(f);
6833 
6834  PASS;
6835 }
6836 
6837 static int HTPParserTest26(void)
6838 {
6839  char input[] = "\
6840 %YAML 1.1\n\
6841 ---\n\
6842 libhtp:\n\
6843 \n\
6844  default-config:\n\
6845  personality: IDS\n\
6846  request-body-limit: 1\n\
6847  response-body-limit: 1\n\
6848 ";
6850  ConfInit();
6852  ConfYamlLoadString(input, strlen(input));
6853  HTPConfigure();
6854 
6855  Packet *p1 = NULL;
6856  Packet *p2 = NULL;
6857  ThreadVars th_v;
6858  DetectEngineCtx *de_ctx = NULL;
6859  DetectEngineThreadCtx *det_ctx = NULL;
6860  Flow f;
6861  uint8_t httpbuf1[] = "GET /alice.txt HTTP/1.1\r\n\r\n";
6862  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
6863  uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\n"
6864  "Content-Type: text/plain\r\n"
6865  "Content-Length: 228\r\n\r\n"
6866  "Alice was beginning to get very tired of sitting by her sister on the bank."
6867  "Alice was beginning to get very tired of sitting by her sister on the bank.";
6868  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
6869  uint8_t httpbuf3[] = "Alice was beginning to get very tired of sitting by her sister on the bank.\r\n\r\n";
6870  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
6871  TcpSession ssn;
6872  HtpState *http_state = NULL;
6875 
6876  memset(&th_v, 0, sizeof(th_v));
6877  memset(&f, 0, sizeof(f));
6878  memset(&ssn, 0, sizeof(ssn));
6879 
6880  p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
6881  p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
6882 
6883  FLOW_INITIALIZE(&f);
6884  f.protoctx = (void *)&ssn;
6885  f.proto = IPPROTO_TCP;
6886  f.flags |= FLOW_IPV4;
6887 
6888  p1->flow = &f;
6892  p2->flow = &f;
6896  f.alproto = ALPROTO_HTTP1;
6897 
6898  StreamTcpInitConfig(true);
6899 
6902 
6903  de_ctx->flags |= DE_QUIET;
6904 
6905  de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any "
6906  "(filestore; sid:1; rev:1;)");
6908 
6910  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
6911 
6912  int r = AppLayerParserParse(
6913  &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
6914  FAIL_IF(r != 0);
6915 
6916  http_state = f.alstate;
6917  FAIL_IF_NULL(http_state);
6918 
6919  /* do detect */
6920  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
6921 
6922  FAIL_IF((PacketAlertCheck(p1, 1)));
6923 
6924  /* do detect */
6925  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
6926 
6927  FAIL_IF((PacketAlertCheck(p1, 1)));
6928 
6929  r = AppLayerParserParse(
6930  &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf2, httplen2);
6931  FAIL_IF(r != 0);
6932 
6933  http_state = f.alstate;
6934  FAIL_IF_NULL(http_state);
6935 
6936  /* do detect */
6937  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
6938 
6939  FAIL_IF(!(PacketAlertCheck(p2, 1)));
6940 
6941  r = AppLayerParserParse(
6942  &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf3, httplen3);
6943  FAIL_IF(r != 0);
6944 
6945  http_state = f.alstate;
6946  FAIL_IF_NULL(http_state);
6947 
6948  void *tx_ptr = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
6949  FAIL_IF_NULL(tx_ptr);
6950 
6951  AppLayerGetFileState files = HTPGetTxFiles(http_state, tx_ptr, STREAM_TOCLIENT);
6952  FileContainer *ffc = files.fc;
6953  FAIL_IF_NULL(ffc);
6954 
6955  File *ptr = ffc->head;
6956  FAIL_IF(ptr->state != FILE_STATE_CLOSED);
6957 
6959  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
6961  StreamTcpFreeConfig(true);
6962 
6963  HTPFreeConfig();
6964  FLOW_DESTROY(&f);
6965  UTHFreePackets(&p1, 1);
6966  UTHFreePackets(&p2, 1);
6967  ConfDeInit();
6970  PASS;
6971 }
6972 
6973 static int HTPParserTest27(void)
6974 {
6975  HTPCfgDir cfg;
6976  memset(&cfg, 0, sizeof(cfg));
6977  cfg.body_limit = 1500;
6979 
6980  uint32_t len = 1000;
6981 
6982  HtpTxUserData *tx_ud = SCMalloc(sizeof(HtpTxUserData));
6983  FAIL_IF_NULL(tx_ud);
6984 
6985  tx_ud->tsflags |= HTP_STREAM_DEPTH_SET;
6986  tx_ud->request_body.content_len_so_far = 2500;
6987 
6988  FAIL_IF(AppLayerHtpCheckDepth(&cfg, &tx_ud->request_body, tx_ud->tsflags));
6989 
6990  len = AppLayerHtpComputeChunkLength(tx_ud->request_body.content_len_so_far,
6991  0,
6993  tx_ud->tsflags,
6994  len);
6995  FAIL_IF(len != 1000);
6996 
6997  SCFree(tx_ud);
6998 
6999  PASS;
7000 }
7001 
7002 /**
7003  * \brief Register the Unit tests for the HTTP protocol
7004  */
7005 static void HTPParserRegisterTests(void)
7006 {
7007  UtRegisterTest("HTPParserTest01", HTPParserTest01);
7008  UtRegisterTest("HTPParserTest01a", HTPParserTest01a);
7009  UtRegisterTest("HTPParserTest01b", HTPParserTest01b);
7010  UtRegisterTest("HTPParserTest01c", HTPParserTest01c);
7011  UtRegisterTest("HTPParserTest02", HTPParserTest02);
7012  UtRegisterTest("HTPParserTest03", HTPParserTest03);
7013  UtRegisterTest("HTPParserTest04", HTPParserTest04);
7014  UtRegisterTest("HTPParserTest05", HTPParserTest05);
7015  UtRegisterTest("HTPParserTest06", HTPParserTest06);
7016  UtRegisterTest("HTPParserTest07", HTPParserTest07);
7017  UtRegisterTest("HTPParserTest08", HTPParserTest08);
7018  UtRegisterTest("HTPParserTest09", HTPParserTest09);
7019  UtRegisterTest("HTPParserTest10", HTPParserTest10);
7020  UtRegisterTest("HTPParserTest11", HTPParserTest11);
7021  UtRegisterTest("HTPParserTest12", HTPParserTest12);
7022  UtRegisterTest("HTPParserTest13", HTPParserTest13);
7023  UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01);
7024  UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02);
7025  UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03);
7026 
7027  UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01);
7028  UtRegisterTest("HTPParserDecodingTest01a", HTPParserDecodingTest01a);
7029  UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02);
7030  UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03);
7031  UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04);
7032  UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05);
7033  UtRegisterTest("HTPParserDecodingTest06", HTPParserDecodingTest06);
7034  UtRegisterTest("HTPParserDecodingTest07", HTPParserDecodingTest07);
7035  UtRegisterTest("HTPParserDecodingTest08", HTPParserDecodingTest08);
7036  UtRegisterTest("HTPParserDecodingTest09", HTPParserDecodingTest09);
7037 
7038  UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01);
7039 
7040  UtRegisterTest("HTPSegvTest01", HTPSegvTest01);
7041 
7042  UtRegisterTest("HTPParserTest14", HTPParserTest14);
7043  UtRegisterTest("HTPParserTest15", HTPParserTest15);
7044  UtRegisterTest("HTPParserTest16", HTPParserTest16);
7045  UtRegisterTest("HTPParserTest20", HTPParserTest20);
7046  UtRegisterTest("HTPParserTest21", HTPParserTest21);
7047  UtRegisterTest("HTPParserTest22", HTPParserTest22);
7048  UtRegisterTest("HTPParserTest23", HTPParserTest23);
7049  UtRegisterTest("HTPParserTest24", HTPParserTest24);
7050  UtRegisterTest("HTPParserTest25", HTPParserTest25);
7051  UtRegisterTest("HTPParserTest26", HTPParserTest26);
7052  UtRegisterTest("HTPParserTest27", HTPParserTest27);
7053 
7056 }
7057 #endif /* UNITTESTS */
7058 
7059 /**
7060  * @}
7061  */
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:488
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:1022
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:413
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:490
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:908
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:3071
AppLayerParserGetEventsByTx
AppLayerDecoderEvents * AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *tx)
Definition: app-layer-parser.c:861
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:373
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:81
AppLayerParserConfParserEnabled
int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests
Definition: app-layer-parser.c:332
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:1092
AppLayerParserTriggerRawStreamReassembly
void AppLayerParserTriggerRawStreamReassembly(Flow *f, int direction)
Definition: app-layer-parser.c:1562
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:2125
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:474
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:351
File_::state
FileState state
Definition: util-file.h:82
HtpGetTxForH2
void * HtpGetTxForH2(void *alstate)
Definition: app-layer-htp.c:3134
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:540
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:402
AppLayerParserRegisterTxFreeFunc
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
Definition: app-layer-parser.c:499
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:312
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:223
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:340
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:1897
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:450
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:367
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:468
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:441
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:216
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:2996
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:475
Flow_::dst
FlowAddress dst
Definition: flow.h:354
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:463
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:138
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:211
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:3317
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:567
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:423
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:1877
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:437
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:577
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:619
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:224
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:1114
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:390
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:2149
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:468
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:291
AppLayerParserRegisterGetTx
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
Definition: app-layer-parser.c:521
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:1358
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:476
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:1292
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:3454
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:599
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:589
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:3324
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:476
Flow_::flags
uint32_t flags
Definition: flow.h:421
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:853
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:555
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:215
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:3249
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:225
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2494
AppLayerParserStateAlloc
AppLayerParserState * AppLayerParserStateAlloc(void)
Definition: app-layer-parser.c:236
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:234
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:510
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:65
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:356
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:1794
msg
const char * msg
Definition: app-layer-htp.c:580
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:450
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:103
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:1019
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:198
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:431