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