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