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