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