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