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);
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 */
830  if (SCAppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS) &&
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 */
944  if (SCAppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC) &&
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");
1092  } else if (dir == STREAM_TOCLIENT) {
1093  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set");
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_RESP_BODY_SEEN)) {
1274  // make sure we run this only once per tx
1275  // so that we do not retry/refail to parse Content-Disposition header
1276  // which may be expensive if we do it for every packet...
1277  htud->tcflags |= HTP_RESP_BODY_SEEN;
1278  SCLogDebug("setting up file name");
1279 
1280  const uint8_t *filename = NULL;
1281  size_t filename_len = 0;
1282 
1283  /* try Content-Disposition header first */
1284  const htp_header_t *h = htp_tx_response_header(tx, "Content-Disposition");
1285  if (h != NULL && htp_header_value_len(h) > 0) {
1286  /* parse content-disposition */
1287  (void)HTTPParseContentDispositionHeader((uint8_t *)"filename=", 9,
1288  htp_header_value_ptr(h), htp_header_value_len(h), &filename, &filename_len);
1289  }
1290 
1291  /* fall back to name from the uri */
1292  if (filename == NULL) {
1293  /* get the name */
1294  if (htp_uri_path(htp_tx_parsed_uri(tx)) != NULL) {
1295  filename = (uint8_t *)bstr_ptr(htp_uri_path(htp_tx_parsed_uri(tx)));
1296  filename_len = bstr_len(htp_uri_path(htp_tx_parsed_uri(tx)));
1297  }
1298  }
1299 
1300  if (filename != NULL) {
1301  // set range if present
1302  const htp_header_t *h_content_range = htp_tx_response_header(tx, "content-range");
1303  if (filename_len > SC_FILENAME_MAX) {
1304  // explicitly truncate the file name if too long
1305  filename_len = SC_FILENAME_MAX;
1306  HTPSetEvent(hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG);
1307  }
1308  if (h_content_range != NULL) {
1309  result = HTPFileOpenWithRange(hstate, htud, filename, (uint16_t)filename_len, data,
1310  data_len, tx, htp_header_value(h_content_range), htud);
1311  } else {
1312  result = HTPFileOpen(hstate, htud, filename, (uint16_t)filename_len, data, data_len,
1313  STREAM_TOCLIENT);
1314  }
1315  SCLogDebug("result %d", result);
1316  if (result == -1) {
1317  goto end;
1318  } else if (result == -2) {
1319  htud->tcflags |= HTP_DONTSTORE;
1320  } else {
1321  FlagDetectStateNewFile(htud, STREAM_TOCLIENT);
1322  htud->tcflags |= HTP_FILENAME_SET;
1323  htud->tcflags &= ~HTP_DONTSTORE;
1324  }
1325  }
1326  } else {
1327  /* otherwise, just store the data */
1328 
1329  if (!(htud->tcflags & HTP_DONTSTORE)) {
1330  result = HTPFileStoreChunk(htud, data, data_len, STREAM_TOCLIENT);
1331  SCLogDebug("result %d", result);
1332  if (result == -1) {
1333  goto end;
1334  } else if (result == -2) {
1335  /* we know for sure we're not storing the file */
1336  htud->tcflags |= HTP_DONTSTORE;
1337  }
1338  }
1339  }
1340 
1341  htud->response_body.body_parsed += data_len;
1342  return 0;
1343 end:
1344  return -1;
1345 }
1346 
1347 /**
1348  * \brief Function callback to append chunks for Requests
1349  * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
1350  * \retval int HTP_STATUS_OK if all goes well
1351  */
1352 static int HTPCallbackRequestBodyData(const htp_connp_t *connp, htp_tx_data_t *d)
1353 {
1354  SCEnter();
1355 
1356  const htp_tx_t *tx = htp_tx_data_tx(d);
1357 
1358  if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_REQUEST_BODY))
1359  SCReturnInt(HTP_STATUS_OK);
1360 
1361  if (htp_tx_data_is_empty(d))
1362  SCReturnInt(HTP_STATUS_OK);
1363 
1364 #ifdef PRINT
1365  printf("HTPBODY START: \n");
1366  PrintRawDataFp(stdout, (uint8_t *)htp_tx_data_data(d), htp_tx_data_len(d));
1367  printf("HTPBODY END: \n");
1368 #endif
1369 
1370  HtpState *hstate = htp_connp_user_data(connp);
1371  if (hstate == NULL) {
1372  SCReturnInt(HTP_STATUS_ERROR);
1373  }
1374 
1375  SCLogDebug("New request body data available at %p -> %p -> %p, bodylen "
1376  "%" PRIu32 "",
1377  hstate, d, htp_tx_data_data(d), (uint32_t)htp_tx_data_len(d));
1378 
1379  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1380  if (tx_ud == NULL) {
1381  SCReturnInt(HTP_STATUS_OK);
1382  }
1383  tx_ud->tx_data.updated_ts = true;
1384  SCTxDataUpdateFileFlags(&tx_ud->tx_data, hstate->state_data.file_flags);
1385 
1386  if (!tx_ud->response_body_init) {
1387  tx_ud->response_body_init = 1;
1388 
1389  if (htp_tx_request_method_number(tx) == HTP_METHOD_POST) {
1390  SCLogDebug("POST");
1391  int r = HtpRequestBodySetupMultipart(tx, tx_ud);
1392  if (r == 1) {
1394  } else if (r == 0) {
1396  SCLogDebug("not multipart");
1397  }
1398  } else if (htp_tx_request_method_number(tx) == HTP_METHOD_PUT) {
1400  }
1401  }
1402 
1403  /* see if we can get rid of htp body chunks */
1404  HtpBodyPrune(hstate, &tx_ud->request_body, STREAM_TOSERVER);
1405 
1406  SCLogDebug("tx_ud->request_body.content_len_so_far %"PRIu64, tx_ud->request_body.content_len_so_far);
1407  SCLogDebug("hstate->cfg->request.body_limit %u", hstate->cfg->request.body_limit);
1408 
1409  /* within limits, add the body chunk to the state. */
1410  if (AppLayerHtpCheckDepth(&hstate->cfg->request, &tx_ud->request_body, tx_ud->tsflags)) {
1411  uint32_t stream_depth = FileReassemblyDepth();
1412  uint32_t len = AppLayerHtpComputeChunkLength(tx_ud->request_body.content_len_so_far,
1413  hstate->cfg->request.body_limit, stream_depth, tx_ud->tsflags,
1414  (uint32_t)htp_tx_data_len(d));
1415  DEBUG_VALIDATE_BUG_ON(len > (uint32_t)htp_tx_data_len(d));
1416 
1417  HtpBodyAppendChunk(&tx_ud->request_body, htp_tx_data_data(d), len);
1418 
1419  const uint8_t *chunks_buffer = NULL;
1420  uint32_t chunks_buffer_len = 0;
1421 
1423  /* multi-part body handling starts here */
1424  if (!(tx_ud->tsflags & HTP_BOUNDARY_SET)) {
1425  goto end;
1426  }
1427 
1428  HtpRequestBodyReassemble(tx_ud, &chunks_buffer, &chunks_buffer_len);
1429  if (chunks_buffer == NULL) {
1430  goto end;
1431  }
1432 #ifdef PRINT
1433  printf("REASSCHUNK START: \n");
1434  PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
1435  printf("REASSCHUNK END: \n");
1436 #endif
1437 
1438  HtpRequestBodyHandleMultipart(hstate, tx_ud, htp_tx_data_tx(d), chunks_buffer,
1439  chunks_buffer_len, (htp_tx_data_data(d) == NULL && htp_tx_data_len(d) == 0));
1440 
1441  } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_POST ||
1443  HtpRequestBodyHandlePOSTorPUT(
1444  hstate, tx_ud, htp_tx_data_tx(d), htp_tx_data_data(d), len);
1445  }
1446 
1447  } else {
1448  if (tx_ud->tsflags & HTP_FILENAME_SET) {
1449  SCLogDebug("closing file that was being stored");
1450  (void)HTPFileClose(tx_ud, NULL, 0, FILE_TRUNCATED, STREAM_TOSERVER);
1451  tx_ud->tsflags &= ~HTP_FILENAME_SET;
1452  }
1453  }
1454 
1455 end:
1456  if (hstate->conn != NULL) {
1457  SCLogDebug("checking body size %" PRIu64 " against inspect limit %u (cur %" PRIu64
1458  ", last %" PRIu64 ")",
1460  (uint64_t)htp_conn_request_data_counter(hstate->conn),
1461  hstate->last_request_data_stamp);
1462 
1463  /* if we reach the inspect_min_size we'll trigger inspection,
1464  * so make sure that raw stream is also inspected. Set the
1465  * data to be used to the amount of raw bytes we've seen to
1466  * get here. */
1467  if (tx_ud->request_body.body_inspected == 0 &&
1469  if ((uint64_t)htp_conn_request_data_counter(hstate->conn) >
1470  hstate->last_request_data_stamp &&
1471  (uint64_t)htp_conn_request_data_counter(hstate->conn) -
1472  hstate->last_request_data_stamp <
1473  (uint64_t)UINT_MAX) {
1474  uint32_t data_size =
1475  (uint32_t)((uint64_t)htp_conn_request_data_counter(hstate->conn) -
1476  hstate->last_request_data_stamp);
1477  const uint32_t depth = MIN(data_size, hstate->cfg->request.inspect_min_size);
1478 
1479  /* body still in progress, but due to min inspect size we need to inspect now */
1480  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, depth);
1481  SCAppLayerParserTriggerRawStreamInspection(hstate->f, STREAM_TOSERVER);
1482  }
1483  /* after the start of the body, disable the depth logic */
1484  } else if (tx_ud->request_body.body_inspected > 0) {
1485  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, 0);
1486  }
1487  }
1488  SCReturnInt(HTP_STATUS_OK);
1489 }
1490 
1491 /**
1492  * \brief Function callback to append chunks for Responses
1493  * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
1494  * \retval int HTP_STATUS_OK if all goes well
1495  */
1496 static int HTPCallbackResponseBodyData(const htp_connp_t *connp, htp_tx_data_t *d)
1497 {
1498  SCEnter();
1499 
1500  const htp_tx_t *tx = htp_tx_data_tx(d);
1501 
1502  if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_RESPONSE_BODY))
1503  SCReturnInt(HTP_STATUS_OK);
1504 
1505  if (htp_tx_data_is_empty(d))
1506  SCReturnInt(HTP_STATUS_OK);
1507 
1508  HtpState *hstate = htp_connp_user_data(connp);
1509  if (hstate == NULL) {
1510  SCReturnInt(HTP_STATUS_ERROR);
1511  }
1512 
1513  SCLogDebug("New response body data available at %p -> %p -> %p, bodylen "
1514  "%" PRIu32 "",
1515  hstate, d, htp_tx_data_data(d), (uint32_t)htp_tx_data_len(d));
1516 
1517  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1518  tx_ud->tx_data.updated_tc = true;
1519  SCTxDataUpdateFileFlags(&tx_ud->tx_data, hstate->state_data.file_flags);
1520  if (!tx_ud->request_body_init) {
1521  tx_ud->request_body_init = 1;
1522  }
1523 
1524  /* see if we can get rid of htp body chunks */
1525  HtpBodyPrune(hstate, &tx_ud->response_body, STREAM_TOCLIENT);
1526 
1527  SCLogDebug("tx_ud->response_body.content_len_so_far %"PRIu64, tx_ud->response_body.content_len_so_far);
1528  SCLogDebug("hstate->cfg->response.body_limit %u", hstate->cfg->response.body_limit);
1529 
1530  /* within limits, add the body chunk to the state. */
1531  if (AppLayerHtpCheckDepth(&hstate->cfg->response, &tx_ud->response_body, tx_ud->tcflags)) {
1532  uint32_t stream_depth = FileReassemblyDepth();
1533  uint32_t len = AppLayerHtpComputeChunkLength(tx_ud->response_body.content_len_so_far,
1534  hstate->cfg->response.body_limit, stream_depth, tx_ud->tcflags,
1535  (uint32_t)htp_tx_data_len(d));
1536  DEBUG_VALIDATE_BUG_ON(len > (uint32_t)htp_tx_data_len(d));
1537 
1538  HtpBodyAppendChunk(&tx_ud->response_body, htp_tx_data_data(d), len);
1539 
1540  HtpResponseBodyHandle(hstate, tx_ud, htp_tx_data_tx(d), htp_tx_data_data(d), len);
1541  } else {
1542  if (tx_ud->tcflags & HTP_FILENAME_SET) {
1543  SCLogDebug("closing file that was being stored");
1544  (void)HTPFileClose(tx_ud, NULL, 0, FILE_TRUNCATED, STREAM_TOCLIENT);
1545  tx_ud->tcflags &= ~HTP_FILENAME_SET;
1546  }
1547  }
1548 
1549  if (hstate->conn != NULL) {
1550  SCLogDebug("checking body size %" PRIu64 " against inspect limit %u (cur %" PRIu64
1551  ", last %" PRIu64 ")",
1553  (uint64_t)htp_conn_request_data_counter(hstate->conn),
1554  hstate->last_response_data_stamp);
1555  /* if we reach the inspect_min_size we'll trigger inspection,
1556  * so make sure that raw stream is also inspected. Set the
1557  * data to be used to the amount of raw bytes we've seen to
1558  * get here. */
1559  if (tx_ud->response_body.body_inspected == 0 &&
1561  if ((uint64_t)htp_conn_response_data_counter(hstate->conn) >
1562  hstate->last_response_data_stamp &&
1563  (uint64_t)htp_conn_response_data_counter(hstate->conn) -
1564  hstate->last_response_data_stamp <
1565  (uint64_t)UINT_MAX) {
1566  uint32_t data_size =
1567  (uint32_t)((uint64_t)htp_conn_response_data_counter(hstate->conn) -
1568  hstate->last_response_data_stamp);
1569  const uint32_t depth = MIN(data_size, hstate->cfg->response.inspect_min_size);
1570 
1571  /* body still in progress, but due to min inspect size we need to inspect now */
1572  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, depth);
1573  SCAppLayerParserTriggerRawStreamInspection(hstate->f, STREAM_TOCLIENT);
1574  }
1575  /* after the start of the body, disable the depth logic */
1576  } else if (tx_ud->response_body.body_inspected > 0) {
1577  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, 0);
1578  }
1579  }
1580  SCReturnInt(HTP_STATUS_OK);
1581 }
1582 
1583 /**
1584  * \brief Print the stats of the HTTP requests
1585  */
1587 {
1588 #ifdef DEBUG
1589  SCEnter();
1590  SCMutexLock(&htp_state_mem_lock);
1591  SCLogDebug("http_state_memcnt %"PRIu64", http_state_memuse %"PRIu64"",
1592  htp_state_memcnt, htp_state_memuse);
1593  SCMutexUnlock(&htp_state_mem_lock);
1594  SCReturn;
1595 #endif
1596 }
1597 
1598 /** \brief Clears the HTTP server configuration memory used by HTP library */
1599 void HTPFreeConfig(void)
1600 {
1601  SCEnter();
1602 
1603  if (!SCAppLayerProtoDetectConfProtoDetectionEnabled("tcp", "http") ||
1604  !SCAppLayerParserConfParserEnabled("tcp", "http")) {
1605  SCReturn;
1606  }
1607 
1608  HTPCfgRec *nextrec = cfglist.next;
1609  htp_config_destroy(cfglist.cfg);
1610  while (nextrec != NULL) {
1611  HTPCfgRec *htprec = nextrec;
1612  nextrec = nextrec->next;
1613 
1614  htp_config_destroy(htprec->cfg);
1615  SCFree(htprec);
1616  }
1617  SCRadix4TreeRelease(&cfgtree.ipv4, &htp_radix4_cfg);
1618  SCRadix6TreeRelease(&cfgtree.ipv6, &htp_radix6_cfg);
1619  SCReturn;
1620 }
1621 
1622 static int HTPCallbackRequestHasTrailer(const htp_connp_t *connp, htp_tx_t *tx)
1623 {
1624  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1625  htud->tx_data.updated_ts = true;
1626  htud->request_has_trailers = 1;
1627  return HTP_STATUS_OK;
1628 }
1629 
1630 static int HTPCallbackResponseHasTrailer(const htp_connp_t *connp, htp_tx_t *tx)
1631 {
1632  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1633  htud->tx_data.updated_tc = true;
1634  htud->response_has_trailers = 1;
1635  return HTP_STATUS_OK;
1636 }
1637 
1638 static void *HTPCallbackTxCreate(bool request)
1639 {
1640  HtpTxUserData *tx_ud = HTPCalloc(1, sizeof(HtpTxUserData));
1641  if (unlikely(tx_ud == NULL)) {
1642  return NULL;
1643  }
1644  if (request) {
1645  // each http tx may xfer files
1646  tx_ud->tx_data.file_tx = STREAM_TOSERVER | STREAM_TOCLIENT;
1647  } else {
1648  tx_ud->tx_data.file_tx = STREAM_TOCLIENT; // Toserver already missed.
1649  }
1650  return tx_ud;
1651 }
1652 
1653 /**\internal
1654  * \brief called at start of request
1655  * Set min inspect size.
1656  */
1657 static int HTPCallbackRequestStart(const htp_connp_t *connp, htp_tx_t *tx)
1658 {
1659  HtpState *hstate = htp_connp_user_data(connp);
1660  if (hstate == NULL) {
1661  SCReturnInt(HTP_STATUS_ERROR);
1662  }
1663 
1664  uint64_t consumed = hstate->slice->offset + htp_connp_request_data_consumed(hstate->connp);
1665  SCLogDebug("HTTP request start: data offset %" PRIu64 ", in_data_counter %" PRIu64, consumed,
1666  (uint64_t)htp_conn_request_data_counter(hstate->conn));
1667  /* app-layer-frame-documentation tag start: frame registration http request */
1669  hstate->f, hstate->slice, consumed, -1, 0, HTTP_FRAME_REQUEST);
1670  if (frame) {
1671  SCLogDebug("frame %p/%" PRIi64, frame, frame->id);
1672  hstate->request_frame_id = frame->id;
1673  AppLayerFrameSetTxId(frame, HtpGetActiveRequestTxID(hstate));
1674  }
1675  /* app-layer-frame-documentation tag end: frame registration http request */
1676 
1677  if (hstate->cfg)
1678  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER,
1679  hstate->cfg->request.inspect_min_size);
1680 
1681  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1682  tx_ud->tx_data.updated_ts = true;
1683  SCReturnInt(HTP_STATUS_OK);
1684 }
1685 
1686 /**\internal
1687  * \brief called at start of response
1688  * Set min inspect size.
1689  */
1690 static int HTPCallbackResponseStart(const htp_connp_t *connp, htp_tx_t *tx)
1691 {
1692  HtpState *hstate = htp_connp_user_data(connp);
1693  if (hstate == NULL) {
1694  SCReturnInt(HTP_STATUS_ERROR);
1695  }
1696 
1697  uint64_t consumed = hstate->slice->offset + htp_connp_response_data_consumed(hstate->connp);
1698  SCLogDebug("HTTP response start: data offset %" PRIu64 ", out_data_counter %" PRIu64, consumed,
1699  (uint64_t)htp_conn_response_data_counter(hstate->conn));
1700 
1702  hstate->f, hstate->slice, consumed, -1, 1, HTTP_FRAME_RESPONSE);
1703  if (frame) {
1704  SCLogDebug("frame %p/%" PRIi64, frame, frame->id);
1705  hstate->response_frame_id = frame->id;
1706  AppLayerFrameSetTxId(frame, HtpGetActiveResponseTxID(hstate));
1707  }
1708 
1709  if (hstate->cfg)
1710  StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT,
1711  hstate->cfg->response.inspect_min_size);
1712 
1713  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1714  tx_ud->tx_data.updated_tc = true;
1715  SCReturnInt(HTP_STATUS_OK);
1716 }
1717 
1718 /**
1719  * \brief callback for request to store the recent incoming request
1720  into the recent_request_tx for the given htp state
1721  * \param connp pointer to the current connection parser which has the htp
1722  * state in it as user data
1723  */
1724 static int HTPCallbackRequestComplete(const htp_connp_t *connp, htp_tx_t *tx)
1725 {
1726  SCEnter();
1727 
1728  if (tx == NULL) {
1729  SCReturnInt(HTP_STATUS_ERROR);
1730  }
1731 
1732  HtpState *hstate = htp_connp_user_data(connp);
1733  if (hstate == NULL) {
1734  SCReturnInt(HTP_STATUS_ERROR);
1735  }
1736 
1737  const uint64_t abs_right_edge =
1738  hstate->slice->offset + htp_connp_request_data_consumed(hstate->connp);
1739 
1740  /* app-layer-frame-documentation tag start: updating frame->len */
1741  if (hstate->request_frame_id > 0) {
1742  Frame *frame = AppLayerFrameGetById(hstate->f, 0, hstate->request_frame_id);
1743  if (frame) {
1744  const uint64_t request_size = abs_right_edge - hstate->last_request_data_stamp;
1745 
1746  SCLogDebug("HTTP request complete: data offset %" PRIu64 ", request_size %" PRIu64,
1747  hstate->last_request_data_stamp, request_size);
1748  SCLogDebug("frame %p/%" PRIi64 " setting len to %" PRIu64, frame, frame->id,
1749  request_size);
1750  frame->len = (int64_t)request_size;
1751  /* app-layer-frame-documentation tag end: updating frame->len */
1752  }
1753  hstate->request_frame_id = 0;
1754  }
1755 
1756  SCLogDebug("transaction_cnt %"PRIu64", list_size %"PRIu64,
1757  hstate->transaction_cnt, HTPStateGetTxCnt(hstate));
1758 
1759  SCLogDebug("HTTP request completed");
1760 
1761  HTPErrorCheckTxRequestFlags(hstate, tx);
1762 
1763  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1764  htud->tx_data.updated_ts = true;
1765  if (htud->tsflags & HTP_FILENAME_SET) {
1766  SCLogDebug("closing file that was being stored");
1767  (void)HTPFileClose(htud, NULL, 0, 0, STREAM_TOSERVER);
1768  htud->tsflags &= ~HTP_FILENAME_SET;
1769  if (abs_right_edge < (uint64_t)UINT32_MAX) {
1771  hstate->f->protoctx, STREAM_TOSERVER, (uint32_t)abs_right_edge);
1772  }
1773  }
1774 
1775  hstate->last_request_data_stamp = abs_right_edge;
1776  /* request done, do raw reassembly now to inspect state and stream
1777  * at the same time. */
1778  SCAppLayerParserTriggerRawStreamInspection(hstate->f, STREAM_TOSERVER);
1779  SCReturnInt(HTP_STATUS_OK);
1780 }
1781 
1782 /**
1783  * \brief callback for response to remove the recent received requests
1784  from the recent_request_tx for the given htp state
1785  * \param connp pointer to the current connection parser which has the htp
1786  * state in it as user data
1787  */
1788 static int HTPCallbackResponseComplete(const htp_connp_t *connp, htp_tx_t *tx)
1789 {
1790  SCEnter();
1791 
1792  HtpState *hstate = htp_connp_user_data(connp);
1793  if (hstate == NULL) {
1794  SCReturnInt(HTP_STATUS_ERROR);
1795  }
1796 
1797  /* we have one whole transaction now */
1798  hstate->transaction_cnt++;
1799 
1800  const uint64_t abs_right_edge =
1801  hstate->slice->offset + htp_connp_response_data_consumed(hstate->connp);
1802 
1803  if (hstate->response_frame_id > 0) {
1804  Frame *frame = AppLayerFrameGetById(hstate->f, 1, hstate->response_frame_id);
1805  if (frame) {
1806  const uint64_t response_size = abs_right_edge - hstate->last_response_data_stamp;
1807 
1808  SCLogDebug("HTTP response complete: data offset %" PRIu64 ", response_size %" PRIu64,
1809  hstate->last_response_data_stamp, response_size);
1810  SCLogDebug("frame %p/%" PRIi64 " setting len to %" PRIu64, frame, frame->id,
1811  response_size);
1812  frame->len = (int64_t)response_size;
1813  }
1814  hstate->response_frame_id = 0;
1815  }
1816 
1817  HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1818  htud->tx_data.updated_tc = true;
1819  if (htud->tcflags & HTP_FILENAME_SET) {
1820  SCLogDebug("closing file that was being stored");
1821  (void)HTPFileClose(htud, NULL, 0, 0, STREAM_TOCLIENT);
1822  htud->tcflags &= ~HTP_FILENAME_SET;
1823  }
1824 
1825  /* response done, do raw reassembly now to inspect state and stream
1826  * at the same time. */
1827  SCAppLayerParserTriggerRawStreamInspection(hstate->f, STREAM_TOCLIENT);
1828 
1829  /* handle HTTP CONNECT */
1830  if (htp_tx_request_method_number(tx) == HTP_METHOD_CONNECT) {
1831  /* any 2XX status response implies that the connection will become
1832  a tunnel immediately after this packet (RFC 7230, 3.3.3). */
1833  if ((htp_tx_response_status_number(tx) >= 200) &&
1834  (htp_tx_response_status_number(tx) < 300) && (hstate->transaction_cnt == 1)) {
1835  uint16_t dp = 0;
1836  if (htp_tx_request_port_number(tx) != -1) {
1837  dp = (uint16_t)htp_tx_request_port_number(tx);
1838  }
1839  // both ALPROTO_HTTP1 and ALPROTO_TLS are normal options
1840  if (!AppLayerRequestProtocolChange(hstate->f, dp, ALPROTO_UNKNOWN)) {
1841  HTPSetEvent(
1842  hstate, htud, STREAM_TOCLIENT, HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE);
1843  }
1844  }
1845  }
1846 
1847  hstate->last_response_data_stamp = abs_right_edge;
1848  SCReturnInt(HTP_STATUS_OK);
1849 }
1850 
1851 static int HTPCallbackRequestLine(const htp_connp_t *connp, htp_tx_t *tx)
1852 {
1853  HtpState *hstate = htp_connp_user_data(connp);
1854 
1855  if (htp_tx_flags(tx)) {
1856  HTPErrorCheckTxRequestFlags(hstate, tx);
1857  }
1858  return HTP_STATUS_OK;
1859 }
1860 
1861 static int HTPCallbackRequestHeaderData(const htp_connp_t *connp, htp_tx_data_t *tx_data)
1862 {
1863  void *ptmp;
1864  const htp_tx_t *tx = htp_tx_data_tx(tx_data);
1865  if (htp_tx_data_is_empty(tx_data) || tx == NULL)
1866  return HTP_STATUS_OK;
1867 
1868  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1870  tx_ud->request_headers_raw_len + htp_tx_data_len(tx_data));
1871  if (ptmp == NULL) {
1872  return HTP_STATUS_OK;
1873  }
1874  tx_ud->request_headers_raw = ptmp;
1875  tx_ud->tx_data.updated_ts = true;
1876 
1877  memcpy(tx_ud->request_headers_raw + tx_ud->request_headers_raw_len, htp_tx_data_data(tx_data),
1878  htp_tx_data_len(tx_data));
1879  tx_ud->request_headers_raw_len += htp_tx_data_len(tx_data);
1880 
1881  if (tx && htp_tx_flags(tx)) {
1882  HtpState *hstate = htp_connp_user_data(connp);
1883  HTPErrorCheckTxRequestFlags(hstate, tx);
1884  }
1885  return HTP_STATUS_OK;
1886 }
1887 
1888 static int HTPCallbackResponseHeaderData(const htp_connp_t *connp, htp_tx_data_t *tx_data)
1889 {
1890  void *ptmp;
1891  const htp_tx_t *tx = htp_tx_data_tx(tx_data);
1892  if (htp_tx_data_is_empty(tx_data) || tx == NULL)
1893  return HTP_STATUS_OK;
1894 
1895  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1896  tx_ud->tx_data.updated_tc = true;
1898  tx_ud->response_headers_raw_len + htp_tx_data_len(tx_data));
1899  if (ptmp == NULL) {
1900  return HTP_STATUS_OK;
1901  }
1902  tx_ud->response_headers_raw = ptmp;
1903 
1904  memcpy(tx_ud->response_headers_raw + tx_ud->response_headers_raw_len, htp_tx_data_data(tx_data),
1905  htp_tx_data_len(tx_data));
1906  tx_ud->response_headers_raw_len += htp_tx_data_len(tx_data);
1907 
1908  return HTP_STATUS_OK;
1909 }
1910 
1911 /*
1912  * We have a similar set function called HTPConfigSetDefaultsPhase1.
1913  */
1914 static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec)
1915 {
1916  htp_config_set_normalized_uri_include_all(cfg_prec->cfg, false);
1923 
1924  if (!g_disable_randomness) {
1926  } else {
1927  cfg_prec->randomize = 0;
1928  }
1930 
1931  htp_config_register_request_header_data(cfg_prec->cfg, HTPCallbackRequestHeaderData);
1932  htp_config_register_request_trailer_data(cfg_prec->cfg, HTPCallbackRequestHeaderData);
1933  htp_config_register_response_header_data(cfg_prec->cfg, HTPCallbackResponseHeaderData);
1934  htp_config_register_response_trailer_data(cfg_prec->cfg, HTPCallbackResponseHeaderData);
1935 
1936  htp_config_register_request_trailer(cfg_prec->cfg, HTPCallbackRequestHasTrailer);
1937  htp_config_register_response_trailer(cfg_prec->cfg, HTPCallbackResponseHasTrailer);
1938 
1939  htp_config_register_request_body_data(cfg_prec->cfg, HTPCallbackRequestBodyData);
1940  htp_config_register_response_body_data(cfg_prec->cfg, HTPCallbackResponseBodyData);
1941 
1942  htp_config_register_tx_create(cfg_prec->cfg, HTPCallbackTxCreate);
1943  htp_config_register_tx_destroy(cfg_prec->cfg, HtpTxUserDataFree);
1944 
1945  htp_config_register_request_start(cfg_prec->cfg, HTPCallbackRequestStart);
1946  htp_config_register_request_complete(cfg_prec->cfg, HTPCallbackRequestComplete);
1947 
1948  htp_config_register_response_start(cfg_prec->cfg, HTPCallbackResponseStart);
1949  htp_config_register_response_complete(cfg_prec->cfg, HTPCallbackResponseComplete);
1950 
1951  htp_config_set_parse_request_cookies(cfg_prec->cfg, 0);
1952  htp_config_set_allow_space_uri(cfg_prec->cfg, 1);
1953 
1954  /* don't convert + to space by default */
1955  htp_config_set_plusspace_decode(cfg_prec->cfg, 0);
1956  // enables request decompression
1957  htp_config_set_request_decompression(cfg_prec->cfg, 1);
1958  htp_config_set_lzma_layers(cfg_prec->cfg, HTP_CONFIG_DEFAULT_LZMA_LAYERS);
1959  htp_config_set_lzma_memlimit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_LZMA_MEMLIMIT);
1960  htp_config_set_compression_bomb_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_COMPRESSION_BOMB_LIMIT);
1961  htp_config_set_compression_time_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_COMPRESSION_TIME_LIMIT);
1962 #define HTP_CONFIG_DEFAULT_MAX_TX_LIMIT 512
1963  htp_config_set_max_tx(cfg_prec->cfg, HTP_CONFIG_DEFAULT_MAX_TX_LIMIT);
1964 #define HTP_CONFIG_DEFAULT_HEADERS_LIMIT 1024
1965  htp_config_set_number_headers_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_HEADERS_LIMIT);
1966  htp_config_set_field_limit(cfg_prec->cfg, (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT);
1967 }
1968 
1969 /* hack: htp random range code expects random values in range of 0-RAND_MAX,
1970  * but we can get both <0 and >RAND_MAX values from RandomGet
1971  */
1972 static int RandomGetWrap(void)
1973 {
1974  unsigned long r;
1975 
1976  do {
1977  r = RandomGet();
1978  } while(r >= ULONG_MAX - (ULONG_MAX % RAND_MAX));
1979 
1980  return r % RAND_MAX;
1981 }
1982 
1983 /*
1984  * We have this splitup so that in case double decoding has been enabled
1985  * for query and path, they would be called first on the callback queue,
1986  * before the callback set by Phase2() is called. We need this, since
1987  * the callback in Phase2() generates the normalized uri which utilizes
1988  * the query and path. */
1989 static void HTPConfigSetDefaultsPhase2(const char *name, HTPCfgRec *cfg_prec)
1990 {
1991  /* randomize inspection size if needed */
1992  if (cfg_prec->randomize) {
1993  int rdrange = cfg_prec->randomize_range;
1994 
1995  long int r = RandomGetWrap();
1996  cfg_prec->request.inspect_min_size += (int)(cfg_prec->request.inspect_min_size *
1997  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
1998 
1999  r = RandomGetWrap();
2000  cfg_prec->request.inspect_window += (int)(cfg_prec->request.inspect_window *
2001  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
2002  SCLogConfig("'%s' server has 'request-body-minimal-inspect-size' set to"
2003  " %u and 'request-body-inspect-window' set to %u after"
2004  " randomization.",
2005  name, cfg_prec->request.inspect_min_size, cfg_prec->request.inspect_window);
2006 
2007  r = RandomGetWrap();
2008  cfg_prec->response.inspect_min_size += (int)(cfg_prec->response.inspect_min_size *
2009  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
2010 
2011  r = RandomGetWrap();
2012  cfg_prec->response.inspect_window += (int)(cfg_prec->response.inspect_window *
2013  ((double)r / RAND_MAX - 0.5) * rdrange / 100);
2014 
2015  SCLogConfig("'%s' server has 'response-body-minimal-inspect-size' set to"
2016  " %u and 'response-body-inspect-window' set to %u after"
2017  " randomization.",
2018  name, cfg_prec->response.inspect_min_size, cfg_prec->response.inspect_window);
2019  }
2020 
2021  htp_config_register_request_line(cfg_prec->cfg, HTPCallbackRequestLine);
2022 }
2023 
2024 static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, SCConfNode *s, struct HTPConfigTree *tree)
2025 {
2026  if (cfg_prec == NULL || s == NULL || tree == NULL)
2027  return;
2028 
2029  SCConfNode *p = NULL;
2030 
2031  /* Default Parameters */
2032  TAILQ_FOREACH (p, &s->head, next) {
2033  if (strcasecmp("address", p->name) == 0) {
2034  SCConfNode *pval;
2035  /* Addresses */
2036  TAILQ_FOREACH(pval, &p->head, next) {
2037  SCLogDebug("LIBHTP server %s: %s=%s", s->name, p->name, pval->val);
2038  /* IPV6 or IPV4? */
2039  if (strchr(pval->val, ':') != NULL) {
2040  SCLogDebug("LIBHTP adding ipv6 server %s at %s: %p",
2041  s->name, pval->val, cfg_prec->cfg);
2043  &tree->ipv6, &htp_radix6_cfg, pval->val, cfg_prec)) {
2044  SCLogWarning("LIBHTP failed to add ipv6 server %s, ignoring", pval->val);
2045  }
2046  } else {
2047  SCLogDebug("LIBHTP adding ipv4 server %s at %s: %p",
2048  s->name, pval->val, cfg_prec->cfg);
2050  &tree->ipv4, &htp_radix4_cfg, pval->val, cfg_prec)) {
2051  SCLogWarning("LIBHTP failed to add ipv4 server %s, ignoring", pval->val);
2052  }
2053  } /* else - if (strchr(pval->val, ':') != NULL) */
2054  } /* TAILQ_FOREACH(pval, &p->head, next) */
2055 
2056  } else if (strcasecmp("personality", p->name) == 0) {
2057  /* Personalities */
2058  int personality = HTPLookupPersonality(p->val);
2059  SCLogDebug("LIBHTP default: %s = %s", p->name, p->val);
2060  SCLogDebug("LIBHTP default: %s = %s", p->name, p->val);
2061 
2062  if (personality >= 0) {
2063  SCLogDebug("LIBHTP default: %s=%s (%d)", p->name, p->val,
2064  personality);
2065  if (htp_config_set_server_personality(cfg_prec->cfg, personality) ==
2066  HTP_STATUS_ERROR) {
2067  SCLogWarning("LIBHTP Failed adding "
2068  "personality \"%s\", ignoring",
2069  p->val);
2070  } else {
2071  SCLogDebug("LIBHTP personality set to %s",
2072  HTPLookupPersonalityString(personality));
2073  }
2074 
2075  /* The IDS personality by default converts the path (and due to
2076  * our query string callback also the query string) to lowercase.
2077  * Signatures do not expect this, so override it. */
2078  htp_config_set_convert_lowercase(cfg_prec->cfg, 0);
2079  } else {
2080  SCLogWarning("LIBHTP Unknown personality "
2081  "\"%s\", ignoring",
2082  p->val);
2083  continue;
2084  }
2085 
2086  } else if (strcasecmp("request-body-limit", p->name) == 0 ||
2087  strcasecmp("request_body_limit", p->name) == 0) {
2088  if (ParseSizeStringU32(p->val, &cfg_prec->request.body_limit) < 0) {
2089  SCLogError("Error parsing request-body-limit "
2090  "from conf file - %s. Killing engine",
2091  p->val);
2092  exit(EXIT_FAILURE);
2093  }
2094 
2095  } else if (strcasecmp("response-body-limit", p->name) == 0) {
2096  if (ParseSizeStringU32(p->val, &cfg_prec->response.body_limit) < 0) {
2097  SCLogError("Error parsing response-body-limit "
2098  "from conf file - %s. Killing engine",
2099  p->val);
2100  exit(EXIT_FAILURE);
2101  }
2102 
2103  } else if (strcasecmp("request-body-minimal-inspect-size", p->name) == 0) {
2104  if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_min_size) < 0) {
2105  SCLogError("Error parsing request-body-minimal-inspect-size "
2106  "from conf file - %s. Killing engine",
2107  p->val);
2108  exit(EXIT_FAILURE);
2109  }
2110 
2111  } else if (strcasecmp("request-body-inspect-window", p->name) == 0) {
2112  if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_window) < 0) {
2113  SCLogError("Error parsing request-body-inspect-window "
2114  "from conf file - %s. Killing engine",
2115  p->val);
2116  exit(EXIT_FAILURE);
2117  }
2118 
2119  } else if (strcasecmp("double-decode-query", p->name) == 0) {
2120  htp_config_set_double_decode_normalized_query(cfg_prec->cfg, SCConfValIsTrue(p->val));
2121  } else if (strcasecmp("double-decode-path", p->name) == 0) {
2122  htp_config_set_double_decode_normalized_path(cfg_prec->cfg, SCConfValIsTrue(p->val));
2123  } else if (strcasecmp("response-body-minimal-inspect-size", p->name) == 0) {
2124  if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_min_size) < 0) {
2125  SCLogError("Error parsing response-body-minimal-inspect-size "
2126  "from conf file - %s. Killing engine",
2127  p->val);
2128  exit(EXIT_FAILURE);
2129  }
2130 
2131  } else if (strcasecmp("response-body-inspect-window", p->name) == 0) {
2132  if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_window) < 0) {
2133  SCLogError("Error parsing response-body-inspect-window "
2134  "from conf file - %s. Killing engine",
2135  p->val);
2136  exit(EXIT_FAILURE);
2137  }
2138 
2139  } else if (strcasecmp("response-body-decompress-layer-limit", p->name) == 0) {
2140  uint32_t value = 2;
2141  if (ParseSizeStringU32(p->val, &value) < 0) {
2142  SCLogError("Error parsing response-body-inspect-window "
2143  "from conf file - %s. Killing engine",
2144  p->val);
2145  exit(EXIT_FAILURE);
2146  }
2147  htp_config_set_decompression_layer_limit(cfg_prec->cfg, value);
2148  } else if (strcasecmp("path-convert-backslash-separators", p->name) == 0) {
2149  htp_config_set_backslash_convert_slashes(cfg_prec->cfg, SCConfValIsTrue(p->val));
2150  } else if (strcasecmp("path-bestfit-replacement-char", p->name) == 0) {
2151  if (strlen(p->val) == 1) {
2152  htp_config_set_bestfit_replacement_byte(cfg_prec->cfg, p->val[0]);
2153  } else {
2154  SCLogError("Invalid entry "
2155  "for libhtp param path-bestfit-replacement-char");
2156  }
2157  } else if (strcasecmp("path-convert-lowercase", p->name) == 0) {
2158  htp_config_set_convert_lowercase(cfg_prec->cfg, SCConfValIsTrue(p->val));
2159  } else if (strcasecmp("path-nul-encoded-terminates", p->name) == 0) {
2160  htp_config_set_nul_encoded_terminates(cfg_prec->cfg, SCConfValIsTrue(p->val));
2161  } else if (strcasecmp("path-nul-raw-terminates", p->name) == 0) {
2162  htp_config_set_nul_raw_terminates(cfg_prec->cfg, SCConfValIsTrue(p->val));
2163  } else if (strcasecmp("path-separators-compress", p->name) == 0) {
2164  htp_config_set_path_separators_compress(cfg_prec->cfg, SCConfValIsTrue(p->val));
2165  } else if (strcasecmp("path-separators-decode", p->name) == 0) {
2166  htp_config_set_path_separators_decode(cfg_prec->cfg, SCConfValIsTrue(p->val));
2167  } else if (strcasecmp("path-u-encoding-decode", p->name) == 0) {
2168  htp_config_set_u_encoding_decode(cfg_prec->cfg, SCConfValIsTrue(p->val));
2169  } else if (strcasecmp("path-url-encoding-invalid-handling", p->name) == 0) {
2170  enum htp_url_encoding_handling_t handling;
2171  if (strcasecmp(p->val, "preserve_percent") == 0) {
2172  handling = HTP_URL_ENCODING_HANDLING_PRESERVE_PERCENT;
2173  } else if (strcasecmp(p->val, "remove_percent") == 0) {
2174  handling = HTP_URL_ENCODING_HANDLING_REMOVE_PERCENT;
2175  } else if (strcasecmp(p->val, "decode_invalid") == 0) {
2176  handling = HTP_URL_ENCODING_HANDLING_PROCESS_INVALID;
2177  } else {
2178  SCLogError("Invalid entry "
2179  "for libhtp param path-url-encoding-invalid-handling");
2180  return;
2181  }
2182  htp_config_set_url_encoding_invalid_handling(cfg_prec->cfg, handling);
2183  } else if (strcasecmp("path-utf8-convert-bestfit", p->name) == 0) {
2184  htp_config_set_utf8_convert_bestfit(cfg_prec->cfg, SCConfValIsTrue(p->val));
2185  } else if (strcasecmp("uri-include-all", p->name) == 0) {
2186  htp_config_set_normalized_uri_include_all(cfg_prec->cfg, SCConfValIsTrue(p->val));
2187  SCLogDebug("uri-include-all %s", SCConfValIsTrue(p->val) ? "enabled" : "disabled");
2188  } else if (strcasecmp("query-plusspace-decode", p->name) == 0) {
2189  htp_config_set_plusspace_decode(cfg_prec->cfg, SCConfValIsTrue(p->val));
2190  } else if (strcasecmp("meta-field-limit", p->name) == 0) {
2191  uint32_t limit = 0;
2192  if (ParseSizeStringU32(p->val, &limit) < 0) {
2193  SCLogError("Error meta-field-limit "
2194  "from conf file - %s. Killing engine",
2195  p->val);
2196  exit(EXIT_FAILURE);
2197  }
2198  if (limit == 0) {
2199  FatalError("Error meta-field-limit "
2200  "from conf file cannot be 0. Killing engine");
2201  }
2202  /* set default soft-limit with our new hard limit */
2203  htp_config_set_field_limit(cfg_prec->cfg, (size_t)limit);
2204  } else if (strcasecmp("lzma-memlimit", p->name) == 0) {
2205  uint32_t limit = 0;
2206  if (ParseSizeStringU32(p->val, &limit) < 0) {
2207  FatalError("failed to parse 'lzma-memlimit' "
2208  "from conf file - %s.",
2209  p->val);
2210  }
2211  if (limit == 0) {
2212  FatalError("'lzma-memlimit' "
2213  "from conf file cannot be 0.");
2214  }
2215  /* set default soft-limit with our new hard limit */
2216  SCLogConfig("Setting HTTP LZMA memory limit to %"PRIu32" bytes", limit);
2217  htp_config_set_lzma_memlimit(cfg_prec->cfg, (size_t)limit);
2218  } else if (strcasecmp("lzma-enabled", p->name) == 0) {
2219  if (SCConfValIsTrue(p->val)) {
2220  htp_config_set_lzma_layers(cfg_prec->cfg, 1);
2221  } else if (!SCConfValIsFalse(p->val)) {
2222  int8_t limit;
2223  if (StringParseInt8(&limit, 10, 0, (const char *)p->val) < 0) {
2224  FatalError("failed to parse 'lzma-enabled' "
2225  "from conf file - %s.",
2226  p->val);
2227  }
2228  SCLogConfig("Setting HTTP LZMA decompression layers to %" PRIu32 "", (int)limit);
2229  htp_config_set_lzma_layers(cfg_prec->cfg, limit);
2230  }
2231  } else if (strcasecmp("compression-bomb-limit", p->name) == 0) {
2232  uint32_t limit = 0;
2233  if (ParseSizeStringU32(p->val, &limit) < 0) {
2234  FatalError("failed to parse 'compression-bomb-limit' "
2235  "from conf file - %s.",
2236  p->val);
2237  }
2238  if (limit == 0) {
2239  FatalError("'compression-bomb-limit' "
2240  "from conf file cannot be 0.");
2241  }
2242  /* set default soft-limit with our new hard limit */
2243  SCLogConfig("Setting HTTP compression bomb limit to %"PRIu32" bytes", limit);
2244  htp_config_set_compression_bomb_limit(cfg_prec->cfg, (size_t)limit);
2245  } else if (strcasecmp("decompression-time-limit", p->name) == 0) {
2246  uint32_t limit = 0;
2247  // between 1 usec and 1 second
2248  if (StringParseU32RangeCheck(&limit, 10, 0, p->val, 1, 1000000) < 0) {
2249  FatalError("failed to parse 'decompression-time-limit' "
2250  "from conf file - %s.",
2251  p->val);
2252  }
2253  SCLogConfig("Setting HTTP decompression time limit to %" PRIu32 " usec", limit);
2254  htp_config_set_compression_time_limit(cfg_prec->cfg, limit);
2255  } else if (strcasecmp("max-tx", p->name) == 0) {
2256  uint32_t limit = 0;
2257  if (ParseSizeStringU32(p->val, &limit) < 0) {
2258  FatalError("failed to parse 'max-tx' "
2259  "from conf file - %s.",
2260  p->val);
2261  }
2262  /* set default soft-limit with our new hard limit */
2263  SCLogConfig("Setting HTTP max-tx limit to %" PRIu32 " bytes", limit);
2264  htp_config_set_max_tx(cfg_prec->cfg, limit);
2265  } else if (strcasecmp("headers-limit", p->name) == 0) {
2266  uint32_t limit = 0;
2267  if (ParseSizeStringU32(p->val, &limit) < 0) {
2268  FatalError("failed to parse 'headers-limit' "
2269  "from conf file - %s.",
2270  p->val);
2271  }
2272  SCLogConfig("Setting HTTP headers limit to %" PRIu32, limit);
2273  htp_config_set_number_headers_limit(cfg_prec->cfg, limit);
2274  } else if (strcasecmp("randomize-inspection-sizes", p->name) == 0) {
2275  if (!g_disable_randomness) {
2276  cfg_prec->randomize = SCConfValIsTrue(p->val);
2277  }
2278  } else if (strcasecmp("randomize-inspection-range", p->name) == 0) {
2279  uint32_t range;
2280  if (StringParseU32RangeCheck(&range, 10, 0,
2281  (const char *)p->val, 0, 100) < 0) {
2282  SCLogError("Invalid value for randomize"
2283  "-inspection-range setting from conf file - \"%s\"."
2284  " It should be a valid integer less than or equal to 100."
2285  " Killing engine",
2286  p->val);
2287  exit(EXIT_FAILURE);
2288  }
2289  cfg_prec->randomize_range = range;
2290  } else if (strcasecmp("http-body-inline", p->name) == 0) {
2291  if (SCConfValIsTrue(p->val)) {
2292  cfg_prec->http_body_inline = 1;
2293  } else if (SCConfValIsFalse(p->val)) {
2294  cfg_prec->http_body_inline = 0;
2295  } else {
2296  if (strcmp("auto", p->val) != 0) {
2297  WarnInvalidConfEntry("http_body_inline", "%s", "auto");
2298  }
2299  if (EngineModeIsIPS()) {
2300  cfg_prec->http_body_inline = 1;
2301  } else {
2302  cfg_prec->http_body_inline = 0;
2303  }
2304  }
2305  } else if (strcasecmp("swf-decompression", p->name) == 0) {
2306  SCConfNode *pval;
2307 
2308  TAILQ_FOREACH(pval, &p->head, next) {
2309  if (strcasecmp("enabled", pval->name) == 0) {
2310  if (SCConfValIsTrue(pval->val)) {
2311  cfg_prec->swf_decompression_enabled = 1;
2312  } else if (SCConfValIsFalse(pval->val)) {
2313  cfg_prec->swf_decompression_enabled = 0;
2314  } else {
2315  WarnInvalidConfEntry("swf-decompression.enabled", "%s", "no");
2316  }
2317  } else if (strcasecmp("type", pval->name) == 0) {
2318  if (strcasecmp("no", pval->val) == 0) {
2320  } else if (strcasecmp("deflate", pval->val) == 0) {
2322  } else if (strcasecmp("lzma", pval->val) == 0) {
2324  } else if (strcasecmp("both", pval->val) == 0) {
2326  } else {
2327  SCLogError("Invalid entry for "
2328  "swf-decompression.type: %s - "
2329  "Killing engine",
2330  pval->val);
2331  exit(EXIT_FAILURE);
2332  }
2333  } else if (strcasecmp("compress-depth", pval->name) == 0) {
2334  if (ParseSizeStringU32(pval->val, &cfg_prec->swf_compress_depth) < 0) {
2335  SCLogError("Error parsing swf-decompression.compression-depth "
2336  "from conf file - %s. Killing engine",
2337  p->val);
2338  exit(EXIT_FAILURE);
2339  }
2340  } else if (strcasecmp("decompress-depth", pval->name) == 0) {
2341  if (ParseSizeStringU32(pval->val, &cfg_prec->swf_decompress_depth) < 0) {
2342  SCLogError("Error parsing swf-decompression.decompression-depth "
2343  "from conf file - %s. Killing engine",
2344  p->val);
2345  exit(EXIT_FAILURE);
2346  }
2347  } else {
2348  SCLogWarning("Ignoring unknown param %s", pval->name);
2349  }
2350  }
2351  } else {
2352  SCLogWarning("LIBHTP Ignoring unknown "
2353  "default config: %s",
2354  p->name);
2355  }
2356  } /* TAILQ_FOREACH(p, &default_config->head, next) */
2357 }
2358 
2359 void HTPConfigure(void)
2360 {
2361  SCEnter();
2362 
2363  cfglist.next = NULL;
2364 
2368 
2369  /* Default Config */
2370  cfglist.cfg = htp_config_create();
2371  if (NULL == cfglist.cfg) {
2372  FatalError("Failed to create HTP default config");
2373  }
2374  SCLogDebug("LIBHTP default config: %p", cfglist.cfg);
2375  HTPConfigSetDefaultsPhase1(&cfglist);
2376  if (SCConfGetNode("app-layer.protocols.http.libhtp") == NULL) {
2377  HTPConfigParseParameters(&cfglist, SCConfGetNode("libhtp.default-config"), &cfgtree);
2378  } else {
2379  HTPConfigParseParameters(&cfglist,
2380  SCConfGetNode("app-layer.protocols.http.libhtp.default-config"), &cfgtree);
2381  }
2382  HTPConfigSetDefaultsPhase2("default", &cfglist);
2383 
2384  HTPParseMemcap();
2385 
2386  /* Read server config and create a parser for each IP in radix tree */
2387  SCConfNode *server_config = SCConfGetNode("app-layer.protocols.http.libhtp.server-config");
2388  if (server_config == NULL) {
2389  server_config = SCConfGetNode("libhtp.server-config");
2390  if (server_config == NULL) {
2391  SCLogDebug("LIBHTP Configuring %p", server_config);
2392  SCReturn;
2393  }
2394  }
2395  SCLogDebug("LIBHTP Configuring %p", server_config);
2396 
2397  SCConfNode *si;
2398  /* Server Nodes */
2399  TAILQ_FOREACH(si, &server_config->head, next) {
2400  /* Need the named node, not the index */
2401  SCConfNode *s = TAILQ_FIRST(&si->head);
2402  if (NULL == s) {
2403  SCLogDebug("LIBHTP s NULL");
2404  continue;
2405  }
2406 
2407  SCLogDebug("LIBHTP server %s", s->name);
2408 
2409  HTPCfgRec *nextrec = cfglist.next;
2410  HTPCfgRec *htprec = SCCalloc(1, sizeof(HTPCfgRec));
2411  if (NULL == htprec)
2412  exit(EXIT_FAILURE);
2413 
2414  cfglist.next = htprec;
2415 
2416  cfglist.next->next = nextrec;
2417  cfglist.next->cfg = htp_config_create();
2418  if (NULL == cfglist.next->cfg) {
2419  FatalError("Failed to create HTP server config");
2420  }
2421 
2422  HTPConfigSetDefaultsPhase1(htprec);
2423  HTPConfigParseParameters(htprec, s, &cfgtree);
2424  HTPConfigSetDefaultsPhase2(s->name, htprec);
2425  }
2426 
2427  SCReturn;
2428 }
2429 
2431 {
2432 #ifdef DEBUG
2433  SCMutexLock(&htp_state_mem_lock);
2434  SCLogPerf("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
2435  SCMutexUnlock(&htp_state_mem_lock);
2436 #endif
2437 }
2438 
2439 /** \internal
2440  * \brief get files callback
2441  * \param state state ptr
2442  * \param direction flow direction
2443  * \retval files files ptr
2444  */
2445 static AppLayerGetFileState HTPGetTxFiles(void *txv, uint8_t direction)
2446 {
2447  AppLayerGetFileState files = { .fc = NULL, .cfg = &htp_sbcfg };
2448  htp_tx_t *tx = (htp_tx_t *)txv;
2449  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
2450  if (direction & STREAM_TOCLIENT) {
2451  files.fc = &tx_ud->files_tc;
2452  } else {
2453  files.fc = &tx_ud->files_ts;
2454  }
2455  return files;
2456 }
2457 
2458 static int HTPStateGetAlstateProgress(void *tx, uint8_t direction)
2459 {
2460  if (direction & STREAM_TOSERVER)
2461  return htp_tx_request_progress((htp_tx_t *)tx);
2462  else
2463  return htp_tx_response_progress((htp_tx_t *)tx);
2464 }
2465 
2466 static uint64_t HTPStateGetTxCnt(void *alstate)
2467 {
2468  HtpState *http_state = (HtpState *)alstate;
2469 
2470  if (http_state != NULL && http_state->connp != NULL) {
2471  const int64_t size = htp_connp_tx_size(http_state->connp);
2472  if (size < 0)
2473  return 0ULL;
2474  SCLogDebug("size %"PRIu64, size);
2475  return (uint64_t)size;
2476  } else {
2477  return 0ULL;
2478  }
2479 }
2480 
2481 static void *HTPStateGetTx(void *alstate, uint64_t tx_id)
2482 {
2483  HtpState *http_state = (HtpState *)alstate;
2484 
2485  if (http_state != NULL && http_state->connp != NULL)
2486  return (void *)htp_connp_tx(http_state->connp, tx_id);
2487  else
2488  return NULL;
2489 }
2490 
2491 static AppLayerGetTxIterTuple HTPGetTxIterator(const uint8_t ipproto, const AppProto alproto,
2492  void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state)
2493 {
2494  HtpState *http_state = (HtpState *)alstate;
2495  uint64_t size = HTPStateGetTxCnt(alstate);
2496  AppLayerGetTxIterTuple no_tuple = { NULL, 0, false };
2497  if (http_state) {
2498  while (state->un.u64 < size) {
2499  htp_tx_t *tx = htp_connp_tx_index(http_state->connp, state->un.u64);
2500  if (!tx) {
2501  return no_tuple;
2502  }
2503  uint64_t tx_id = htp_tx_index(tx);
2504  if (tx_id < min_tx_id) {
2505  state->un.u64++;
2506  continue;
2507  }
2508  AppLayerGetTxIterTuple tuple = {
2509  .tx_ptr = tx,
2510  .tx_id = tx_id,
2511  .has_next = state->un.u64 < size,
2512  };
2513  return tuple;
2514  }
2515  }
2516  return no_tuple;
2517 }
2518 
2519 void *HtpGetTxForH2(void *alstate)
2520 {
2521  // gets last transaction
2522  HtpState *http_state = (HtpState *)alstate;
2523  if (http_state != NULL && http_state->connp != NULL) {
2524  size_t txid = htp_connp_tx_size(http_state->connp);
2525  if (txid > 0) {
2526  return (void *)htp_connp_tx(http_state->connp, txid - 1);
2527  }
2528  }
2529  return NULL;
2530 }
2531 
2532 static int HTPStateGetEventInfo(
2533  const char *event_name, uint8_t *event_id, AppLayerEventType *event_type)
2534 {
2535  if (SCAppLayerGetEventIdByName(event_name, http_decoder_event_table, event_id) == 0) {
2536  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
2537  return 0;
2538  }
2539  return -1;
2540 }
2541 
2542 static int HTPStateGetEventInfoById(
2543  uint8_t event_id, const char **event_name, AppLayerEventType *event_type)
2544 {
2545  *event_name = SCMapEnumValueToName(event_id, http_decoder_event_table);
2546  if (*event_name == NULL) {
2547  SCLogError("event \"%d\" not present in "
2548  "http's enum map table.",
2549  event_id);
2550  /* this should be treated as fatal */
2551  return -1;
2552  }
2553 
2554  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
2555 
2556  return 0;
2557 }
2558 
2559 static AppLayerTxData *HTPGetTxData(void *vtx)
2560 {
2561  htp_tx_t *tx = (htp_tx_t *)vtx;
2562  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
2563  return &tx_ud->tx_data;
2564 }
2565 
2566 static AppLayerStateData *HTPGetStateData(void *vstate)
2567 {
2568  HtpState *s = vstate;
2569  return &s->state_data;
2570 }
2571 
2572 static int HTPRegisterPatternsForProtocolDetection(void)
2573 {
2574  const char *methods[] = { "GET", "PUT", "POST", "HEAD", "TRACE", "OPTIONS",
2575  "CONNECT", "DELETE", "PATCH", "PROPFIND", "PROPPATCH", "MKCOL",
2576  "COPY", "MOVE", "LOCK", "UNLOCK", "CHECKOUT", "UNCHECKOUT", "CHECKIN",
2577  "UPDATE", "LABEL", "REPORT", "MKWORKSPACE", "MKACTIVITY", "MERGE",
2578  "INVALID", "VERSION-CONTROL", "BASELINE-CONTROL", NULL};
2579  const char *spacings[] = { "|20|", "|09|", NULL };
2580  const char *versions[] = { "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", NULL };
2581 
2582  int methods_pos;
2583  int spacings_pos;
2584  int versions_pos;
2585  int register_result;
2586  char method_buffer[32] = "";
2587 
2588  /* Loop through all the methods ands spacings and register the patterns */
2589  for (methods_pos = 0; methods[methods_pos]; methods_pos++) {
2590  for (spacings_pos = 0; spacings[spacings_pos]; spacings_pos++) {
2591 
2592  /* Combine the method name and the spacing */
2593  snprintf(method_buffer, sizeof(method_buffer), "%s%s", methods[methods_pos], spacings[spacings_pos]);
2594 
2595  /* Register the new method+spacing pattern
2596  * 3 is subtracted from the length since the spacing is hex typed as |xx|
2597  * but the pattern matching should only be one char
2598  */
2599  register_result = SCAppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1,
2600  method_buffer, (uint16_t)strlen(method_buffer) - 3, 0, STREAM_TOSERVER);
2601  if (register_result < 0) {
2602  return -1;
2603  }
2604  }
2605  }
2606 
2607  /* Loop through all the http version patterns that are TO_CLIENT */
2608  for (versions_pos = 0; versions[versions_pos]; versions_pos++) {
2609  register_result = SCAppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1,
2610  versions[versions_pos], (uint16_t)strlen(versions[versions_pos]), 0,
2611  STREAM_TOCLIENT);
2612  if (register_result < 0) {
2613  return -1;
2614  }
2615  }
2616 
2617  return 0;
2618 }
2619 
2620 /**
2621  * \brief Register the HTTP protocol and state handling functions to APP layer
2622  * of the engine.
2623  */
2625 {
2626  SCEnter();
2627 
2628  const char *proto_name = "http";
2629 
2630  /** HTTP */
2631  if (SCAppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
2633  if (HTPRegisterPatternsForProtocolDetection() < 0)
2634  return;
2635  } else {
2636  SCLogInfo("Protocol detection and parser disabled for %s protocol",
2637  proto_name);
2638  return;
2639  }
2640 
2641  if (SCAppLayerParserConfParserEnabled("tcp", proto_name)) {
2642  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateAlloc, HTPStateFree);
2643  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateTransactionFree);
2644  AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxFiles);
2646  IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetAlstateProgress);
2647  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTxCnt);
2648  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTx);
2649  AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxIterator);
2651  ALPROTO_HTTP1, HTP_REQUEST_PROGRESS_COMPLETE, HTP_RESPONSE_PROGRESS_COMPLETE);
2652  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfo);
2654  IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfoById);
2655 
2656  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxData);
2657  AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetStateData);
2658 
2660  IPPROTO_TCP, ALPROTO_HTTP1, AppLayerHtpSetStreamDepthFlag);
2661 
2663  IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER, HTPHandleRequestData);
2665  IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOCLIENT, HTPHandleResponseData);
2666  SC_ATOMIC_INIT(htp_config_flags);
2667  /* This parser accepts gaps. */
2669  IPPROTO_TCP, ALPROTO_HTTP1, APP_LAYER_PARSER_OPT_ACCEPT_GAPS);
2671  IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_TOCLIENT);
2672  /* app-layer-frame-documentation tag start: registering relevant callbacks */
2674  IPPROTO_TCP, ALPROTO_HTTP1, HTTPGetFrameIdByName, HTTPGetFrameNameById);
2675  /* app-layer-frame-documentation tag end: registering relevant callbacks */
2677  IPPROTO_TCP, ALPROTO_HTTP1, HtpStateGetStateIdByName, HtpStateGetStateNameById);
2678 
2679  HTPConfigure();
2680  } else {
2681  SCLogInfo("Parser disabled for %s protocol. Protocol detection still on.", proto_name);
2682  }
2683 #ifdef UNITTESTS
2684  AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_HTTP1, HTPParserRegisterTests);
2685 #endif
2686 
2687  SCReturn;
2688 }
2689 
2690 #ifdef UNITTESTS
2691 #include "detect-engine-alert.h"
2692 
2693 static HTPCfgRec cfglist_backup;
2694 
2696 {
2697  cfglist_backup = cfglist;
2698 }
2699 
2701 {
2702  cfglist = cfglist_backup;
2703 }
2704 
2705 /** \test Test case where chunks are sent in smaller chunks and check the
2706  * response of the parser from HTP library. */
2707 static int HTPParserTest01(void)
2708 {
2709  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
2710  " Data is c0oL!";
2711  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2712 
2713  TcpSession ssn;
2714  memset(&ssn, 0, sizeof(ssn));
2715 
2718 
2719  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2720  FAIL_IF_NULL(f);
2721  f->protoctx = &ssn;
2722  f->proto = IPPROTO_TCP;
2723  f->alproto = ALPROTO_HTTP1;
2724 
2725  StreamTcpInitConfig(true);
2726 
2727  uint32_t u;
2728  for (u = 0; u < httplen1; u++) {
2729  uint8_t flags = 0;
2730 
2731  if (u == 0)
2732  flags = STREAM_TOSERVER|STREAM_START;
2733  else if (u == (httplen1 - 1))
2734  flags = STREAM_TOSERVER|STREAM_EOF;
2735  else
2736  flags = STREAM_TOSERVER;
2737 
2738  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
2739  FAIL_IF(r != 0);
2740  }
2741 
2742  HtpState *htp_state = f->alstate;
2743  FAIL_IF_NULL(htp_state);
2744 
2745  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2746  FAIL_IF_NULL(tx);
2747 
2748  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2749  FAIL_IF_NULL(h);
2750 
2751  FAIL_IF(bstr_cmp_c(htp_header_value(h), "Victor/1.0"));
2752  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_POST);
2753  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2754 
2755  UTHFreeFlow(f);
2757  StreamTcpFreeConfig(true);
2758  PASS;
2759 }
2760 
2761 /** \test Test folding in 1 read case */
2762 static int HTPParserTest01b(void)
2763 {
2764  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost"
2765  " Data is c0oL!";
2766  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2767 
2768  TcpSession ssn;
2769  memset(&ssn, 0, sizeof(ssn));
2770 
2773 
2774  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2775  FAIL_IF_NULL(f);
2776  f->protoctx = &ssn;
2777  f->proto = IPPROTO_TCP;
2778  f->alproto = ALPROTO_HTTP1;
2779 
2780  StreamTcpInitConfig(true);
2781 
2782  uint8_t flags =STREAM_TOSERVER|STREAM_START|STREAM_EOF;
2783  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1);
2784  FAIL_IF(r != 0);
2785 
2786  HtpState *htp_state = f->alstate;
2787  FAIL_IF_NULL(htp_state);
2788 
2789  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2790  FAIL_IF_NULL(tx);
2791 
2792  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2793  FAIL_IF_NULL(h);
2794 
2795  char *v = bstr_util_strdup_to_c(htp_header_value(h));
2796  FAIL_IF(strcmp(v, "Victor/1.0"));
2797  SCFree(v);
2798  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_POST);
2799  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2800 
2801  UTHFreeFlow(f);
2803  StreamTcpFreeConfig(true);
2804  PASS;
2805 }
2806 
2807 /** \test Test folding in 1byte per read case */
2808 static int HTPParserTest01c(void)
2809 {
2810  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost"
2811  " Data is c0oL!";
2812  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2813 
2814  TcpSession ssn;
2815  memset(&ssn, 0, sizeof(ssn));
2816 
2819 
2820  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2821  FAIL_IF_NULL(f);
2822  f->protoctx = &ssn;
2823  f->proto = IPPROTO_TCP;
2824  f->alproto = ALPROTO_HTTP1;
2825 
2826  StreamTcpInitConfig(true);
2827 
2828  uint32_t u;
2829  for (u = 0; u < httplen1; u++) {
2830  uint8_t flags = 0;
2831 
2832  if (u == 0)
2833  flags = STREAM_TOSERVER|STREAM_START;
2834  else if (u == (httplen1 - 1))
2835  flags = STREAM_TOSERVER|STREAM_EOF;
2836  else
2837  flags = STREAM_TOSERVER;
2838 
2839  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
2840  FAIL_IF(r != 0);
2841  }
2842 
2843  HtpState *htp_state = f->alstate;
2844  FAIL_IF_NULL(htp_state);
2845 
2846  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2847  FAIL_IF_NULL(tx);
2848 
2849  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2850  FAIL_IF_NULL(h);
2851 
2852  char *v = bstr_util_strdup_to_c(htp_header_value(h));
2853  FAIL_IF(strcmp(v, "Victor/1.0"));
2854  SCFree(v);
2855  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_POST);
2856  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2857 
2858  UTHFreeFlow(f);
2860  StreamTcpFreeConfig(true);
2861  PASS;
2862 }
2863 
2864 /** \test Test case where chunks are sent in smaller chunks and check the
2865  * response of the parser from HTP library. */
2866 static int HTPParserTest01a(void)
2867 {
2868  Flow *f = NULL;
2869  uint8_t httpbuf1[] = " POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
2870  " Data is c0oL!";
2871  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2872  TcpSession ssn;
2873  HtpState *htp_state = NULL;
2875 
2876  memset(&ssn, 0, sizeof(ssn));
2877 
2878  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2879  FAIL_IF_NULL(f);
2880  f->protoctx = &ssn;
2881  f->proto = IPPROTO_TCP;
2882  f->alproto = ALPROTO_HTTP1;
2883 
2884  StreamTcpInitConfig(true);
2885 
2886  uint32_t u;
2887  for (u = 0; u < httplen1; u++) {
2888  uint8_t flags = 0;
2889 
2890  if (u == 0)
2891  flags = STREAM_TOSERVER|STREAM_START;
2892  else if (u == (httplen1 - 1))
2893  flags = STREAM_TOSERVER|STREAM_EOF;
2894  else
2895  flags = STREAM_TOSERVER;
2896 
2897  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
2898  FAIL_IF(r != 0);
2899  }
2900 
2901  htp_state = f->alstate;
2902  FAIL_IF_NULL(htp_state);
2903 
2904  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2905  FAIL_IF_NULL(tx);
2906 
2907  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2908  FAIL_IF_NULL(h);
2909 
2910  char *v = bstr_util_strdup_to_c(htp_header_value(h));
2911  FAIL_IF(strcmp(v, "Victor/1.0"));
2912  SCFree(v);
2913  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_POST);
2914  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
2915 
2916  UTHFreeFlow(f);
2918  StreamTcpFreeConfig(true);
2919  PASS;
2920 }
2921 
2922 /** \test See how it deals with an incomplete request. */
2923 static int HTPParserTest02(void)
2924 {
2925  Flow *f = NULL;
2926  uint8_t httpbuf1[] = "POST";
2927  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2928  TcpSession ssn;
2929  HtpState *http_state = NULL;
2931 
2932  memset(&ssn, 0, sizeof(ssn));
2933 
2934  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2935  FAIL_IF_NULL(f);
2936  f->protoctx = &ssn;
2937  f->proto = IPPROTO_TCP;
2938  f->alproto = ALPROTO_HTTP1;
2939 
2940  StreamTcpInitConfig(true);
2941 
2942  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
2943  STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
2944  FAIL_IF(r != 0);
2945 
2946  http_state = f->alstate;
2947  FAIL_IF_NULL(http_state);
2948 
2949  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
2950  FAIL_IF_NULL(tx);
2951  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
2952  FAIL_IF_NOT_NULL(h);
2953 
2954  FAIL_IF_NULL(htp_tx_request_method(tx));
2955  char *method = bstr_util_strdup_to_c(htp_tx_request_method(tx));
2956  FAIL_IF_NULL(method);
2957 
2958  FAIL_IF(strcmp(method, "POST") != 0);
2959  SCFree(method);
2960 
2961  UTHFreeFlow(f);
2963  StreamTcpFreeConfig(true);
2964  PASS;
2965 }
2966 
2967 /** \test Test case where method is invalid and data is sent in smaller chunks
2968  * and check the response of the parser from HTP library. */
2969 static int HTPParserTest03(void)
2970 {
2971  Flow *f = NULL;
2972  uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n";
2973  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2974  TcpSession ssn;
2975  HtpState *htp_state = NULL;
2977 
2978  memset(&ssn, 0, sizeof(ssn));
2979 
2980  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2981  FAIL_IF_NULL(f);
2982  f->protoctx = &ssn;
2983  f->proto = IPPROTO_TCP;
2984  f->alproto = ALPROTO_HTTP1;
2985 
2986  StreamTcpInitConfig(true);
2987 
2988  uint32_t u;
2989  for (u = 0; u < httplen1; u++) {
2990  uint8_t flags = 0;
2991 
2992  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
2993  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
2994  else flags = STREAM_TOSERVER;
2995 
2996  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
2997  FAIL_IF(r != 0);
2998  }
2999  htp_state = f->alstate;
3000  FAIL_IF_NULL(htp_state);
3001 
3002  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3003  FAIL_IF_NULL(tx);
3004 
3005  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3006  FAIL_IF_NOT_NULL(h);
3007  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_UNKNOWN);
3008  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_0);
3009 
3010  UTHFreeFlow(f);
3012  StreamTcpFreeConfig(true);
3013  PASS;
3014 }
3015 
3016 /** \test Test case where invalid data is sent and check the response of the
3017  * parser from HTP library. */
3018 static int HTPParserTest04(void)
3019 {
3020  Flow *f = NULL;
3021  HtpState *htp_state = NULL;
3022  uint8_t httpbuf1[] = "World!\r\n";
3023  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3024  TcpSession ssn;
3026 
3027  memset(&ssn, 0, sizeof(ssn));
3028 
3029  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3030  FAIL_IF_NULL(f);
3031  f->protoctx = &ssn;
3032  f->proto = IPPROTO_TCP;
3033  f->alproto = ALPROTO_HTTP1;
3034 
3035  StreamTcpInitConfig(true);
3036 
3037  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
3038  STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
3039  FAIL_IF(r != 0);
3040 
3041  htp_state = f->alstate;
3042  FAIL_IF_NULL(htp_state);
3043 
3044  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3045  FAIL_IF_NULL(tx);
3046  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3047  FAIL_IF_NOT_NULL(h);
3048  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_UNKNOWN);
3049  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V0_9);
3050 
3051  UTHFreeFlow(f);
3053  StreamTcpFreeConfig(true);
3054  PASS;
3055 }
3056 
3057 /** \test Test both sides of a http stream mixed up to see if the HTP parser
3058  * properly parsed them and also keeps them separated. */
3059 static int HTPParserTest05(void)
3060 {
3061  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\nContent-Length: 17\r\n\r\n";
3062  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3063  uint8_t httpbuf2[] = "Post D";
3064  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3065  uint8_t httpbuf3[] = "ata is c0oL!";
3066  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
3067 
3068  uint8_t httpbuf4[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
3069  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
3070  uint8_t httpbuf5[] = "post R";
3071  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3072  uint8_t httpbuf6[] = "esults are tha bomb!";
3073  uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
3074 
3075  TcpSession ssn;
3076  memset(&ssn, 0, sizeof(ssn));
3077 
3080 
3081  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3082  FAIL_IF_NULL(f);
3083  f->protoctx = &ssn;
3084  f->proto = IPPROTO_TCP;
3085  f->alproto = ALPROTO_HTTP1;
3086 
3087  StreamTcpInitConfig(true);
3088 
3089  int r = AppLayerParserParse(
3090  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
3091  FAIL_IF(r != 0);
3092 
3093  r = AppLayerParserParse(
3094  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf4, httplen4);
3095  FAIL_IF(r != 0);
3096 
3097  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf5, httplen5);
3098  FAIL_IF(r != 0);
3099 
3100  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
3101  FAIL_IF(r != 0);
3102 
3103  r = AppLayerParserParse(
3104  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3);
3105  FAIL_IF(r != 0);
3106 
3107  r = AppLayerParserParse(
3108  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_EOF, httpbuf6, httplen6);
3109  FAIL_IF(r != 0);
3110 
3111  HtpState *http_state = f->alstate;
3112  FAIL_IF_NULL(http_state);
3113 
3114  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
3115  FAIL_IF_NULL(tx);
3116  FAIL_IF_NOT(htp_tx_request_method_number(tx) == HTP_METHOD_POST);
3117  FAIL_IF_NOT(htp_tx_request_protocol_number(tx) == HTP_PROTOCOL_V1_0);
3118 
3119  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3120  FAIL_IF_NULL(h);
3121 
3122  FAIL_IF_NOT(htp_tx_response_status_number(tx) == 200);
3123 
3124  UTHFreeFlow(f);
3126  StreamTcpFreeConfig(true);
3127  PASS;
3128 }
3129 
3130 /** \test Test proper chunked encoded response body
3131  */
3132 static int HTPParserTest06(void)
3133 {
3134  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
3135  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
3136  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
3137  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3138  uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nDate: Sat, 03 Oct 2009 10:16:02 "
3139  "GMT\r\n"
3140  "Server: Apache/1.3.37 (Unix) mod_ssl/2.8.28 "
3141  "OpenSSL/0.9.7a PHP/4.4.7 mod_perl/1.29 "
3142  "FrontPage/5.0.2.2510\r\n"
3143  "X-Powered-By: PHP/4.4.7\r\nTransfer-Encoding: "
3144  "chunked\r\n"
3145  "Content-Type: text/html\r\n\r\n"
3146  "580\r\n"
3147  "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu"
3148  "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN"
3149  "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N"
3150  "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk"
3151  "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l"
3152  "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN"
3153  "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt"
3154  "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz"
3155  "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw"
3156  "aG9uZTM9DQpsb2dpbjM9DQpwYXNzd29yZDM9DQpwaG9uZTQ9DQps"
3157  "b2dpbjQ9DQpwYXNzd29yZDQ9DQpwaG9uZTU9DQpsb2dpbjU9DQpw"
3158  "YXNzd29yZDU9DQpwaG9uZTY9DQpsb2dpbjY9DQpwYXNzd29yZDY9"
3159  "DQpjYWxsX3RpbWUxPQ0KY2FsbF90aW1lMj0NCmRheV9saW1pdD0N"
3160  "Cm1vbnRoX2xpbWl0PQ0KW2dyb3VwM10NCnBob25lMT0NCmxvZ2lu"
3161  "MT0NCnBhc3N3b3JkMT0NCnBob25lMj0NCmxvZ2luMj0NCnBhc3N3"
3162  "b3JkMj0NCnBob25lMz0NCmxvZ2luMz0NCnBhc3N3b3JkMz0NCnBo"
3163  "b25lND0NCmxvZ2luND0NCnBhc3N3b3JkND0NCnBob25lNT0NCmxv"
3164  "Z2luNT0NCnBhc3N3b3JkNT0NCnBob25lNj0NCmxvZ2luNj0NCnBh"
3165  "c3N3b3JkNj0NCmNhbGxfdGltZTE9DQpjYWxsX3RpbWUyPQ0KZGF5"
3166  "X2xpbWl0PQ0KbW9udGhfbGltaXQ9DQpbZ3JvdXA0XQ0KcGhvbmUx"
3167  "PQ0KbG9naW4xPQ0KcGFzc3dvcmQxPQ0KcGhvbmUyPQ0KbG9naW4y"
3168  "PQ0KcGFzc3dvcmQyPQ0KcGhvbmUzPQ0KbG9naW4zPQ0KcGFzc3dv"
3169  "cmQzPQ0KcGhvbmU0PQ0KbG9naW40PQ0KcGFzc3dvcmQ0PQ0KcGhv"
3170  "bmU1PQ0KbG9naW41PQ0KcGFzc3dvcmQ1PQ0KcGhvbmU2PQ0KbG9n"
3171  "aW42PQ0KcGFzc3dvcmQ2PQ0KY2FsbF90aW1lMT0NCmNhbGxfdGlt"
3172  "ZTI9DQpkYXlfbGltaXQ9DQptb250aF9saW1pdD0NCltmaWxlc10N"
3173  "Cmxpbms9aHR0cDovLzIwOS4yMDUuMTk2LjE2L2xkL2dldGJvdC5w"
3174  "aHA=\r\n0\r\n\r\n";
3175  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3176  TcpSession ssn;
3177 
3180 
3181  memset(&ssn, 0, sizeof(ssn));
3182 
3183  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3184  FAIL_IF_NULL(f);
3185  f->protoctx = &ssn;
3186  f->proto = IPPROTO_TCP;
3187  f->alproto = ALPROTO_HTTP1;
3188 
3189  StreamTcpInitConfig(true);
3190 
3191  int r = AppLayerParserParse(
3192  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
3193  FAIL_IF(r != 0);
3194  r = AppLayerParserParse(
3195  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
3196  FAIL_IF(r != 0);
3197 
3198  HtpState *http_state = f->alstate;
3199  FAIL_IF_NULL(http_state);
3200 
3201  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
3202  FAIL_IF_NULL(tx);
3203 
3204  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
3205  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
3206 
3207  FAIL_IF(htp_tx_response_status_number(tx) != 200);
3208  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
3209 
3210  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3211  FAIL_IF_NULL(h);
3212 
3213  UTHFreeFlow(f);
3215  StreamTcpFreeConfig(true);
3216  PASS;
3217 }
3218 
3219 /** \test
3220  */
3221 static int HTPParserTest07(void)
3222 {
3223  Flow *f = NULL;
3224  uint8_t httpbuf1[] = "GET /awstats.pl?/migratemigrate%20=%20| HTTP/1.0\r\n\r\n";
3225  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3226  TcpSession ssn;
3227  HtpState *htp_state = NULL;
3229 
3230  memset(&ssn, 0, sizeof(ssn));
3231 
3232  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3233  FAIL_IF_NULL(f);
3234  f->protoctx = &ssn;
3235  f->proto = IPPROTO_TCP;
3236  f->alproto = ALPROTO_HTTP1;
3237 
3238  StreamTcpInitConfig(true);
3239 
3240  uint32_t u;
3241  for (u = 0; u < httplen1; u++) {
3242  uint8_t flags = 0;
3243 
3244  if (u == 0)
3245  flags = STREAM_TOSERVER|STREAM_START;
3246  else if (u == (httplen1 - 1))
3247  flags = STREAM_TOSERVER|STREAM_EOF;
3248  else
3249  flags = STREAM_TOSERVER;
3250 
3251  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3252  FAIL_IF(r != 0);
3253  }
3254 
3255  htp_state = f->alstate;
3256  FAIL_IF_NULL(htp_state);
3257 
3258  uint8_t ref[] = "/awstats.pl?/migratemigrate = |";
3259  size_t reflen = sizeof(ref) - 1;
3260 
3261  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3262  FAIL_IF_NULL(tx);
3263  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3264  FAIL_IF_NULL(request_uri_normalized);
3265  FAIL_IF(reflen != bstr_len(request_uri_normalized));
3266 
3267  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref, bstr_len(request_uri_normalized)) != 0);
3268 
3269  UTHFreeFlow(f);
3271  StreamTcpFreeConfig(true);
3272  PASS;
3273 }
3274 
3275 #include "conf-yaml-loader.h"
3276 
3277 /** \test Abort
3278  */
3279 static int HTPParserTest08(void)
3280 {
3281  Flow *f = NULL;
3282  uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
3283  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3284  TcpSession ssn;
3286 
3287  char input[] = "\
3288 %YAML 1.1\n\
3289 ---\n\
3290 libhtp:\n\
3291 \n\
3292  default-config:\n\
3293  personality: IDS\n\
3294 ";
3295 
3297  SCConfInit();
3299 
3300  SCConfYamlLoadString(input, strlen(input));
3301  HTPConfigure();
3302 
3303  HtpState *htp_state = NULL;
3304  memset(&ssn, 0, sizeof(ssn));
3305 
3306  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3307  FAIL_IF_NULL(f);
3308  f->protoctx = &ssn;
3309  f->proto = IPPROTO_TCP;
3310  f->alproto = ALPROTO_HTTP1;
3311 
3312  StreamTcpInitConfig(true);
3313 
3314  uint8_t flags = STREAM_TOSERVER | STREAM_START | STREAM_EOF;
3315 
3316  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1);
3317  FAIL_IF(r != 0);
3318 
3319  htp_state = f->alstate;
3320  FAIL_IF_NULL(htp_state);
3321 
3322  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3323  FAIL_IF_NULL(tx);
3324  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3325  FAIL_IF_NULL(request_uri_normalized);
3326  PrintRawDataFp(stdout, bstr_ptr(request_uri_normalized), bstr_len(request_uri_normalized));
3327 
3328  UTHFreeFlow(f);
3330  StreamTcpFreeConfig(true);
3331  HTPFreeConfig();
3332  SCConfDeInit();
3335  PASS;
3336 }
3337 
3338 /** \test Abort
3339  */
3340 static int HTPParserTest09(void)
3341 {
3342  Flow *f = NULL;
3343  uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
3344  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3345  TcpSession ssn;
3347 
3348  char input[] = "\
3349 %YAML 1.1\n\
3350 ---\n\
3351 libhtp:\n\
3352 \n\
3353  default-config:\n\
3354  personality: Apache_2_2\n\
3355 ";
3356 
3358  SCConfInit();
3360 
3361  SCConfYamlLoadString(input, strlen(input));
3362  HTPConfigure();
3363 
3364  HtpState *htp_state = NULL;
3365 
3366  memset(&ssn, 0, sizeof(ssn));
3367 
3368  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3369  FAIL_IF_NULL(f);
3370  f->protoctx = &ssn;
3371  f->proto = IPPROTO_TCP;
3372  f->alproto = ALPROTO_HTTP1;
3373 
3374  StreamTcpInitConfig(true);
3375 
3376  uint8_t flags = STREAM_TOSERVER | STREAM_START | STREAM_EOF;
3377 
3378  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1);
3379  FAIL_IF(r != 0);
3380 
3381  htp_state = f->alstate;
3382  FAIL_IF_NULL(htp_state);
3383 
3384  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3385  FAIL_IF_NULL(tx);
3386  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3387  FAIL_IF_NULL(request_uri_normalized);
3388  PrintRawDataFp(stdout, bstr_ptr(request_uri_normalized), bstr_len(request_uri_normalized));
3389 
3390  UTHFreeFlow(f);
3392  StreamTcpFreeConfig(true);
3393  HTPFreeConfig();
3394  SCConfDeInit();
3397  PASS;
3398 }
3399 
3400 /** \test Host:www.google.com <- missing space between name:value (rfc violation)
3401  */
3402 static int HTPParserTest10(void)
3403 {
3404 
3405  Flow *f = NULL;
3406  uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\r\n\r\n";
3407  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3408  TcpSession ssn;
3409  HtpState *htp_state = NULL;
3411 
3412  memset(&ssn, 0, sizeof(ssn));
3413 
3414  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3415  FAIL_IF_NULL(f);
3416  f->protoctx = &ssn;
3417  f->proto = IPPROTO_TCP;
3418  f->alproto = ALPROTO_HTTP1;
3419 
3420  StreamTcpInitConfig(true);
3421 
3422  uint32_t u;
3423  for (u = 0; u < httplen1; u++) {
3424  uint8_t flags = 0;
3425 
3426  if (u == 0)
3427  flags = STREAM_TOSERVER|STREAM_START;
3428  else if (u == (httplen1 - 1))
3429  flags = STREAM_TOSERVER|STREAM_EOF;
3430  else
3431  flags = STREAM_TOSERVER;
3432 
3433  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3434  FAIL_IF(r != 0);
3435  }
3436 
3437  htp_state = f->alstate;
3438  FAIL_IF_NULL(htp_state);
3439 
3440  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3441  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3442  FAIL_IF_NULL(h);
3443 
3444  char *name = bstr_util_strdup_to_c(htp_header_name(h));
3445  FAIL_IF_NULL(name);
3446  FAIL_IF(strcmp(name, "Host") != 0);
3447 
3448  char *value = bstr_util_strdup_to_c(htp_header_value(h));
3449  FAIL_IF_NULL(value);
3450  FAIL_IF(strcmp(value, "www.google.com") != 0);
3451 
3452  UTHFreeFlow(f);
3454  StreamTcpFreeConfig(true);
3455  SCFree(name);
3456  SCFree(value);
3457  PASS;
3458 }
3459 
3460 /** \test double encoding in path
3461  */
3462 static int HTPParserTest11(void)
3463 {
3464  Flow *f = NULL;
3465  uint8_t httpbuf1[] = "GET /%2500 HTTP/1.0\r\n\r\n";
3466  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3467  TcpSession ssn;
3468  HtpState *htp_state = NULL;
3470 
3471  memset(&ssn, 0, sizeof(ssn));
3472 
3473  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3474  FAIL_IF_NULL(f);
3475  f->protoctx = &ssn;
3476  f->proto = IPPROTO_TCP;
3477  f->alproto = ALPROTO_HTTP1;
3478 
3479  StreamTcpInitConfig(true);
3480 
3481  uint32_t u;
3482  for (u = 0; u < httplen1; u++) {
3483  uint8_t flags = 0;
3484 
3485  if (u == 0)
3486  flags = STREAM_TOSERVER|STREAM_START;
3487  else if (u == (httplen1 - 1))
3488  flags = STREAM_TOSERVER|STREAM_EOF;
3489  else
3490  flags = STREAM_TOSERVER;
3491 
3492  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3493  FAIL_IF(r != 0);
3494  }
3495 
3496  htp_state = f->alstate;
3497  FAIL_IF_NULL(htp_state);
3498 
3499  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3500  FAIL_IF_NULL(tx);
3501  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3502  FAIL_IF_NULL(request_uri_normalized);
3503 
3504  FAIL_IF(bstr_len(request_uri_normalized) != 4);
3505  FAIL_IF(bstr_ptr(request_uri_normalized)[0] != '/');
3506  FAIL_IF(bstr_ptr(request_uri_normalized)[1] != '%');
3507  FAIL_IF(bstr_ptr(request_uri_normalized)[2] != '0');
3508  FAIL_IF(bstr_ptr(request_uri_normalized)[3] != '0');
3509 
3510  UTHFreeFlow(f);
3512  StreamTcpFreeConfig(true);
3513  PASS;
3514 }
3515 
3516 /** \test double encoding in query
3517  */
3518 static int HTPParserTest12(void)
3519 {
3520  Flow *f = NULL;
3521  uint8_t httpbuf1[] = "GET /?a=%2500 HTTP/1.0\r\n\r\n";
3522  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3523  TcpSession ssn;
3524  HtpState *htp_state = NULL;
3526 
3527  memset(&ssn, 0, sizeof(ssn));
3528 
3529  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3530  FAIL_IF_NULL(f);
3531  f->protoctx = &ssn;
3532  f->proto = IPPROTO_TCP;
3533  f->alproto = ALPROTO_HTTP1;
3534 
3535  StreamTcpInitConfig(true);
3536 
3537  uint32_t u;
3538  for (u = 0; u < httplen1; u++) {
3539  uint8_t flags = 0;
3540 
3541  if (u == 0)
3542  flags = STREAM_TOSERVER|STREAM_START;
3543  else if (u == (httplen1 - 1))
3544  flags = STREAM_TOSERVER|STREAM_EOF;
3545  else
3546  flags = STREAM_TOSERVER;
3547 
3548  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3549  FAIL_IF(r != 0);
3550  }
3551 
3552  htp_state = f->alstate;
3553  FAIL_IF_NULL(htp_state);
3554 
3555  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3556  FAIL_IF_NULL(tx);
3557  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3558  FAIL_IF_NULL(request_uri_normalized);
3559 
3560  FAIL_IF(bstr_len(request_uri_normalized) != 7);
3561  FAIL_IF(bstr_ptr(request_uri_normalized)[0] != '/');
3562  FAIL_IF(bstr_ptr(request_uri_normalized)[1] != '?');
3563  FAIL_IF(bstr_ptr(request_uri_normalized)[2] != 'a');
3564  FAIL_IF(bstr_ptr(request_uri_normalized)[3] != '=');
3565  FAIL_IF(bstr_ptr(request_uri_normalized)[4] != '%');
3566  FAIL_IF(bstr_ptr(request_uri_normalized)[5] != '0');
3567  FAIL_IF(bstr_ptr(request_uri_normalized)[6] != '0');
3568 
3569  UTHFreeFlow(f);
3571  StreamTcpFreeConfig(true);
3572  PASS;
3573 }
3574 
3575 /** \test Host:www.google.com0dName: Value0d0a <- missing space between name:value (rfc violation)
3576  */
3577 static int HTPParserTest13(void)
3578 {
3579  Flow *f = NULL;
3580  uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\rName: Value\r\n\r\n";
3581  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3582  TcpSession ssn;
3583  HtpState *htp_state = NULL;
3585 
3586  memset(&ssn, 0, sizeof(ssn));
3587 
3588  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3589  FAIL_IF_NULL(f);
3590  f->protoctx = &ssn;
3591  f->proto = IPPROTO_TCP;
3592  f->alproto = ALPROTO_HTTP1;
3593 
3594  StreamTcpInitConfig(true);
3595 
3596  uint32_t u;
3597  for (u = 0; u < httplen1; u++) {
3598  uint8_t flags = 0;
3599 
3600  if (u == 0)
3601  flags = STREAM_TOSERVER|STREAM_START;
3602  else if (u == (httplen1 - 1))
3603  flags = STREAM_TOSERVER|STREAM_EOF;
3604  else
3605  flags = STREAM_TOSERVER;
3606 
3607  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3608  FAIL_IF(r != 0);
3609  }
3610 
3611  htp_state = f->alstate;
3612  FAIL_IF_NULL(htp_state);
3613  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3614  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
3615  FAIL_IF_NULL(h);
3616 
3617  char *name = bstr_util_strdup_to_c(htp_header_name(h));
3618  FAIL_IF_NULL(name);
3619  FAIL_IF(strcmp(name, "Host") != 0);
3620 
3621  char *value = bstr_util_strdup_to_c(htp_header_value(h));
3622  FAIL_IF_NULL(value);
3623  FAIL_IF(strcmp(value, "www.google.com\rName: Value") != 0);
3624 
3625  UTHFreeFlow(f);
3627  StreamTcpFreeConfig(true);
3628  SCFree(name);
3629  SCFree(value);
3630 
3631  PASS;
3632 }
3633 
3634 /** \test Test basic config */
3635 static int HTPParserConfigTest01(void)
3636 {
3637  char input[] = "\
3638 %YAML 1.1\n\
3639 ---\n\
3640 libhtp:\n\
3641 \n\
3642  default-config:\n\
3643  personality: IDS\n\
3644 \n\
3645  server-config:\n\
3646 \n\
3647  - apache-tomcat:\n\
3648  address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
3649  personality: Tomcat_6_0\n\
3650 \n\
3651  - iis7:\n\
3652  address: \n\
3653  - 192.168.0.0/24\n\
3654  - 192.168.10.0/24\n\
3655  personality: IIS_7_0\n\
3656 ";
3657 
3659  SCConfInit();
3660 
3661  SCConfYamlLoadString(input, strlen(input));
3662 
3663  SCConfNode *outputs;
3664  outputs = SCConfGetNode("libhtp.default-config.personality");
3665  FAIL_IF_NULL(outputs);
3666 
3667  outputs = SCConfGetNode("libhtp.server-config");
3668  FAIL_IF_NULL(outputs);
3669 
3670  SCConfNode *node = TAILQ_FIRST(&outputs->head);
3671  FAIL_IF_NULL(node);
3672  FAIL_IF(strcmp(node->name, "0") != 0);
3673  node = TAILQ_FIRST(&node->head);
3674  FAIL_IF_NULL(node);
3675  FAIL_IF(strcmp(node->name, "apache-tomcat") != 0);
3676 
3677  int i = 0;
3678  SCConfNode *n;
3679 
3680  SCConfNode *node2 = SCConfNodeLookupChild(node, "personality");
3681  FAIL_IF_NULL(node2);
3682  FAIL_IF(strcmp(node2->val, "Tomcat_6_0") != 0);
3683 
3684  node = SCConfNodeLookupChild(node, "address");
3685  FAIL_IF_NULL(node);
3686 
3687  TAILQ_FOREACH (n, &node->head, next) {
3688  FAIL_IF_NULL(n);
3689  switch(i) {
3690  case 0:
3691  FAIL_IF(strcmp(n->name, "0") != 0);
3692  FAIL_IF(strcmp(n->val, "192.168.1.0/24") != 0);
3693  break;
3694  case 1:
3695  FAIL_IF(strcmp(n->name, "1") != 0);
3696  FAIL_IF(strcmp(n->val, "127.0.0.0/8") != 0);
3697  break;
3698  case 2:
3699  FAIL_IF(strcmp(n->name, "2") != 0);
3700  FAIL_IF(strcmp(n->val, "::1") != 0);
3701  break;
3702  default:
3703  FAIL;
3704  }
3705  i++;
3706  }
3707 
3708  outputs = SCConfGetNode("libhtp.server-config");
3709  FAIL_IF_NULL(outputs);
3710  node = TAILQ_FIRST(&outputs->head);
3711  node = TAILQ_NEXT(node, next);
3712  FAIL_IF_NULL(node);
3713  FAIL_IF(strcmp(node->name, "1") != 0);
3714  node = TAILQ_FIRST(&node->head);
3715  FAIL_IF_NULL(node);
3716  FAIL_IF(strcmp(node->name, "iis7") != 0);
3717 
3718  node2 = SCConfNodeLookupChild(node, "personality");
3719  FAIL_IF_NULL(node2);
3720  FAIL_IF(strcmp(node2->val, "IIS_7_0") != 0);
3721 
3722  node = SCConfNodeLookupChild(node, "address");
3723  FAIL_IF_NULL(node);
3724 
3725  i = 0;
3726  TAILQ_FOREACH(n, &node->head, next) {
3727  FAIL_IF_NULL(n);
3728 
3729  switch(i) {
3730  case 0:
3731  FAIL_IF(strcmp(n->name, "0") != 0);
3732  FAIL_IF(strcmp(n->val, "192.168.0.0/24") != 0);
3733  break;
3734  case 1:
3735  FAIL_IF(strcmp(n->name, "1") != 0);
3736  FAIL_IF(strcmp(n->val, "192.168.10.0/24") != 0);
3737  break;
3738  default:
3739  FAIL;
3740  }
3741  i++;
3742  }
3743 
3744  SCConfDeInit();
3746 
3747  PASS;
3748 }
3749 
3750 /** \test Test config builds radix correctly */
3751 static int HTPParserConfigTest02(void)
3752 {
3753  char input[] = "\
3754 %YAML 1.1\n\
3755 ---\n\
3756 libhtp:\n\
3757 \n\
3758  default-config:\n\
3759  personality: IDS\n\
3760 \n\
3761  server-config:\n\
3762 \n\
3763  - apache-tomcat:\n\
3764  address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
3765  personality: Tomcat_6_0\n\
3766 \n\
3767  - iis7:\n\
3768  address: \n\
3769  - 192.168.0.0/24\n\
3770  - 192.168.10.0/24\n\
3771  personality: IIS_7_0\n\
3772 ";
3773 
3775  SCConfInit();
3777  SCConfYamlLoadString(input, strlen(input));
3778  HTPConfigure();
3779  FAIL_IF_NULL(cfglist.cfg);
3780  FAIL_IF_NULL(cfgtree.ipv4.head);
3781  FAIL_IF_NULL(cfgtree.ipv6.head);
3782 
3783  htp_cfg_t *htp = cfglist.cfg;
3784  uint8_t buf[128];
3785  const char *addr;
3786  void *user_data = NULL;
3787 
3788  addr = "192.168.10.42";
3789  FAIL_IF(inet_pton(AF_INET, addr, buf) != 1);
3790  (void)SCRadix4TreeFindBestMatch(&cfgtree.ipv4, buf, &user_data);
3791  FAIL_IF_NULL(user_data);
3792  HTPCfgRec *htp_cfg_rec = user_data;
3793  htp = htp_cfg_rec->cfg;
3794  FAIL_IF_NULL(htp);
3795  SCLogDebug("LIBHTP using config: %p", htp);
3796 
3797  user_data = NULL;
3798  addr = "::1";
3799  FAIL_IF(inet_pton(AF_INET6, addr, buf) != 1);
3800  (void)SCRadix6TreeFindBestMatch(&cfgtree.ipv6, buf, &user_data);
3801  FAIL_IF_NULL(user_data);
3802  htp_cfg_rec = user_data;
3803  htp = htp_cfg_rec->cfg;
3804  FAIL_IF_NULL(htp);
3805  SCLogDebug("LIBHTP using config: %p", htp);
3806 
3807  HTPFreeConfig();
3808  SCConfDeInit();
3811 
3812  PASS;
3813 }
3814 
3815 /** \test Test traffic is handled by the correct htp config */
3816 static int HTPParserConfigTest03(void)
3817 {
3818  Flow *f = NULL;
3819  uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
3820  " Data is c0oL!";
3821  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3822  TcpSession ssn;
3824 
3825  HtpState *htp_state = NULL;
3826  char input[] = "\
3827 %YAML 1.1\n\
3828 ---\n\
3829 libhtp:\n\
3830 \n\
3831  default-config:\n\
3832  personality: IDS\n\
3833 \n\
3834  server-config:\n\
3835 \n\
3836  - apache-tomcat:\n\
3837  address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
3838  personality: Tomcat_6_0\n\
3839 \n\
3840  - iis7:\n\
3841  address: \n\
3842  - 192.168.0.0/24\n\
3843  - 192.168.10.0/24\n\
3844  personality: IIS_7_0\n\
3845 ";
3846 
3848  SCConfInit();
3850 
3851  SCConfYamlLoadString(input, strlen(input));
3852 
3853  HTPConfigure();
3854 
3855  const char *addr = "192.168.10.42";
3856 
3857  memset(&ssn, 0, sizeof(ssn));
3858 
3859  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
3860  FAIL_IF_NULL(f);
3861  f->protoctx = &ssn;
3862  f->proto = IPPROTO_TCP;
3863  f->alproto = ALPROTO_HTTP1;
3864 
3865  htp_cfg_t *htp = cfglist.cfg;
3866  FAIL_IF_NULL(htp);
3867 
3868  void *user_data = NULL;
3869  (void)SCRadix4TreeFindBestMatch(&cfgtree.ipv4, (uint8_t *)f->dst.addr_data32, &user_data);
3870  FAIL_IF_NULL(user_data);
3871 
3872  HTPCfgRec *htp_cfg_rec = user_data;
3873  htp = htp_cfg_rec->cfg;
3874  FAIL_IF_NULL(user_data);
3875  SCLogDebug("LIBHTP using config: %p", htp);
3876 
3877  StreamTcpInitConfig(true);
3878 
3879  uint32_t u;
3880  for (u = 0; u < httplen1; u++) {
3881  uint8_t flags = 0;
3882 
3883  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
3884  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
3885  else flags = STREAM_TOSERVER;
3886 
3887  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3888  FAIL_IF(r != 0);
3889  }
3890 
3891  htp_state = f->alstate;
3892  FAIL_IF_NULL(htp_state);
3893 
3894  FAIL_IF(HTPStateGetTxCnt(htp_state) != 2);
3895 
3896  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3897  FAIL_IF_NULL(tx);
3898  tx = HTPStateGetTx(htp_state, 1);
3899  FAIL_IF_NULL(tx);
3900 
3901  UTHFreeFlow(f);
3903  HTPFreeConfig();
3904  SCConfDeInit();
3907  StreamTcpFreeConfig(true);
3908  PASS;
3909 }
3910 
3911 /** \test Test %2f decoding in profile Apache_2_2
3912  *
3913  * %2f in path is left untouched
3914  * %2f in query string is normalized to %2F
3915  * %252f in query string is decoded/normalized to %2F
3916  */
3917 static int HTPParserDecodingTest01(void)
3918 {
3919  uint8_t httpbuf1[] =
3920  "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
3921  "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
3922  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
3923  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3924  TcpSession ssn;
3927 
3928  char input[] = "\
3929 %YAML 1.1\n\
3930 ---\n\
3931 libhtp:\n\
3932 \n\
3933  default-config:\n\
3934  personality: Apache_2\n\
3935 ";
3936 
3938  SCConfInit();
3940  SCConfYamlLoadString(input, strlen(input));
3941  HTPConfigure();
3942  const char *addr = "4.3.2.1";
3943  memset(&ssn, 0, sizeof(ssn));
3944 
3945  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
3946  FAIL_IF_NULL(f);
3947  f->protoctx = &ssn;
3948  f->proto = IPPROTO_TCP;
3949  f->alproto = ALPROTO_HTTP1;
3950 
3951  StreamTcpInitConfig(true);
3952 
3953  for (uint32_t u = 0; u < httplen1; u++) {
3954  uint8_t flags = 0;
3955  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
3956  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
3957  else flags = STREAM_TOSERVER;
3958 
3959  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
3960  FAIL_IF(r != 0);
3961  }
3962 
3963  HtpState *htp_state = f->alstate;
3964  FAIL_IF_NULL(htp_state);
3965 
3966  uint8_t ref1[] = "/abc%2fdef";
3967  size_t reflen = sizeof(ref1) - 1;
3968 
3969  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
3970  FAIL_IF_NULL(tx);
3971 
3972  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
3973  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3974  FAIL_IF_NULL(tx_ud);
3975  FAIL_IF_NULL(request_uri_normalized);
3976  FAIL_IF(reflen != bstr_len(request_uri_normalized));
3977  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
3978 
3979  uint8_t ref2[] = "/abc/def?ghi/jkl";
3980  reflen = sizeof(ref2) - 1;
3981 
3982  tx = HTPStateGetTx(htp_state, 1);
3983  FAIL_IF_NULL(tx);
3984 
3985  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
3986  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3987  FAIL_IF_NULL(tx_ud);
3988  FAIL_IF_NULL(request_uri_normalized);
3989  FAIL_IF(reflen != bstr_len(request_uri_normalized));
3990  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref2, bstr_len(request_uri_normalized)) != 0);
3991 
3992  uint8_t ref3[] = "/abc/def?ghi%2fjkl";
3993  reflen = sizeof(ref3) - 1;
3994  tx = HTPStateGetTx(htp_state, 2);
3995  FAIL_IF_NULL(tx);
3996 
3997  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
3998  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
3999  FAIL_IF_NULL(tx_ud);
4000  FAIL_IF_NULL(request_uri_normalized);
4001  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4002  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref3, bstr_len(request_uri_normalized)) != 0);
4003 
4004  UTHFreeFlow(f);
4006  HTPFreeConfig();
4007  SCConfDeInit();
4010  StreamTcpFreeConfig(true);
4011  PASS;
4012 }
4013 
4014 static int HTPParserDecodingTest01a(void)
4015 {
4016  uint8_t httpbuf1[] = "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4017  "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4018  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4019  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4020  TcpSession ssn;
4023 
4024  char input[] = "\
4025 %YAML 1.1\n\
4026 ---\n\
4027 libhtp:\n\
4028 \n\
4029  default-config:\n\
4030  personality: Apache_2\n\
4031 ";
4032 
4034  SCConfInit();
4036  SCConfYamlLoadString(input, strlen(input));
4037  HTPConfigure();
4038  const char *addr = "4.3.2.1";
4039  memset(&ssn, 0, sizeof(ssn));
4040 
4041  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4042  FAIL_IF_NULL(f);
4043  f->protoctx = &ssn;
4044  f->proto = IPPROTO_TCP;
4045  f->alproto = ALPROTO_HTTP1;
4046 
4047  StreamTcpInitConfig(true);
4048 
4049  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
4050  (STREAM_TOSERVER | STREAM_START | STREAM_EOF), httpbuf1, httplen1);
4051  FAIL_IF(r != 0);
4052 
4053  HtpState *htp_state = f->alstate;
4054  FAIL_IF_NULL(htp_state);
4055 
4056  uint8_t ref1[] = "/abc%2fdef";
4057  size_t reflen = sizeof(ref1) - 1;
4058 
4059  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4060  FAIL_IF_NULL(tx);
4061 
4062  HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4063  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4064  FAIL_IF_NULL(tx_ud);
4065  FAIL_IF_NULL(request_uri_normalized);
4066  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4067  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4068 
4069  uint8_t ref2[] = "/abc/def?ghi/jkl";
4070  reflen = sizeof(ref2) - 1;
4071 
4072  tx = HTPStateGetTx(htp_state, 1);
4073  FAIL_IF_NULL(tx);
4074  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4075  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4076  FAIL_IF_NULL(tx_ud);
4077  FAIL_IF_NULL(request_uri_normalized);
4078  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4079 
4080  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref2, bstr_len(request_uri_normalized)) != 0);
4081 
4082  uint8_t ref3[] = "/abc/def?ghi%2fjkl";
4083  reflen = sizeof(ref3) - 1;
4084  tx = HTPStateGetTx(htp_state, 2);
4085  FAIL_IF_NULL(tx);
4086  tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4087  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4088  FAIL_IF_NULL(tx_ud);
4089  FAIL_IF_NULL(request_uri_normalized);
4090  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4091 
4092  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref3, bstr_len(request_uri_normalized)) != 0);
4093 
4094  UTHFreeFlow(f);
4096  HTPFreeConfig();
4097  SCConfDeInit();
4100  StreamTcpFreeConfig(true);
4101  PASS;
4102 }
4103 
4104 /** \test Test %2f decoding in profile IDS
4105  *
4106  * %2f in path decoded to /
4107  * %2f in query string is decoded to /
4108  * %252f in query string is decoded to %2F
4109  */
4110 static int HTPParserDecodingTest02(void)
4111 {
4112  Flow *f = NULL;
4113  uint8_t httpbuf1[] =
4114  "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4115  "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4116  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4117  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4118  TcpSession ssn;
4120 
4121  HtpState *htp_state = NULL;
4122  char input[] = "\
4123 %YAML 1.1\n\
4124 ---\n\
4125 libhtp:\n\
4126 \n\
4127  default-config:\n\
4128  personality: IDS\n\
4129  double-decode-path: no\n\
4130  double-decode-query: no\n\
4131 ";
4132 
4134  SCConfInit();
4136  SCConfYamlLoadString(input, strlen(input));
4137  HTPConfigure();
4138  const char *addr = "4.3.2.1";
4139  memset(&ssn, 0, sizeof(ssn));
4140 
4141  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4142  FAIL_IF_NULL(f);
4143  f->protoctx = &ssn;
4144  f->proto = IPPROTO_TCP;
4145  f->alproto = ALPROTO_HTTP1;
4146 
4147  StreamTcpInitConfig(true);
4148 
4149  uint32_t u;
4150  for (u = 0; u < httplen1; u++) {
4151  uint8_t flags = 0;
4152 
4153  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4154  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4155  else flags = STREAM_TOSERVER;
4156 
4157  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4158  FAIL_IF(r != 0);
4159  }
4160 
4161  htp_state = f->alstate;
4162  FAIL_IF_NULL(htp_state);
4163 
4164  uint8_t ref1[] = "/abc/def";
4165  size_t reflen = sizeof(ref1) - 1;
4166 
4167  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4168  FAIL_IF_NULL(tx);
4169  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4170  FAIL_IF_NULL(request_uri_normalized);
4171  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4172  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4173 
4174  uint8_t ref2[] = "/abc/def?ghi/jkl";
4175  reflen = sizeof(ref2) - 1;
4176 
4177  tx = HTPStateGetTx(htp_state, 1);
4178  FAIL_IF_NULL(tx);
4179  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4180  FAIL_IF_NULL(request_uri_normalized);
4181  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4182 
4183  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref2, bstr_len(request_uri_normalized)) != 0);
4184 
4185  uint8_t ref3[] = "/abc/def?ghi%2fjkl";
4186  reflen = sizeof(ref3) - 1;
4187  tx = HTPStateGetTx(htp_state, 2);
4188  FAIL_IF_NULL(tx);
4189  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4190  FAIL_IF_NULL(request_uri_normalized);
4191  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4192 
4193  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref3, bstr_len(request_uri_normalized)) != 0);
4194 
4195  UTHFreeFlow(f);
4197  HTPFreeConfig();
4198  SCConfDeInit();
4201  StreamTcpFreeConfig(true);
4202  PASS;
4203 }
4204 
4205 /** \test Test %2f decoding in profile IDS with double-decode-* options
4206  *
4207  * %252f in path decoded to /
4208  * %252f in query string is decoded to /
4209  */
4210 static int HTPParserDecodingTest03(void)
4211 {
4212  Flow *f = NULL;
4213  uint8_t httpbuf1[] =
4214  "GET /abc%252fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4215  "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4216  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4217  TcpSession ssn;
4219 
4220  HtpState *htp_state = NULL;
4221  char input[] = "\
4222 %YAML 1.1\n\
4223 ---\n\
4224 libhtp:\n\
4225 \n\
4226  default-config:\n\
4227  personality: IDS\n\
4228  double-decode-path: yes\n\
4229  double-decode-query: yes\n\
4230 ";
4231 
4233  SCConfInit();
4235  SCConfYamlLoadString(input, strlen(input));
4236  HTPConfigure();
4237  const char *addr = "4.3.2.1";
4238  memset(&ssn, 0, sizeof(ssn));
4239 
4240  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4241  FAIL_IF_NULL(f);
4242  f->protoctx = &ssn;
4243  f->proto = IPPROTO_TCP;
4244  f->alproto = ALPROTO_HTTP1;
4245 
4246  StreamTcpInitConfig(true);
4247 
4248  uint32_t u;
4249  for (u = 0; u < httplen1; u++) {
4250  uint8_t flags = 0;
4251 
4252  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4253  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4254  else flags = STREAM_TOSERVER;
4255 
4256  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4257  FAIL_IF(r != 0);
4258  }
4259 
4260  htp_state = f->alstate;
4261  FAIL_IF_NULL(htp_state);
4262 
4263  uint8_t ref1[] = "/abc/def";
4264  size_t reflen = sizeof(ref1) - 1;
4265 
4266  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4267  FAIL_IF_NULL(tx);
4268  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4269  FAIL_IF_NULL(request_uri_normalized);
4270  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4271 
4272  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4273 
4274  uint8_t ref2[] = "/abc/def?ghi/jkl";
4275  reflen = sizeof(ref2) - 1;
4276 
4277  tx = HTPStateGetTx(htp_state, 1);
4278  FAIL_IF_NULL(tx);
4279  request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4280  FAIL_IF_NULL(request_uri_normalized);
4281  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4282 
4283  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref2, bstr_len(request_uri_normalized)) != 0);
4284 
4285  UTHFreeFlow(f);
4287  HTPFreeConfig();
4288  SCConfDeInit();
4291  StreamTcpFreeConfig(true);
4292  PASS;
4293 }
4294 
4295 /** \test Test http:// in query profile IDS
4296  */
4297 static int HTPParserDecodingTest04(void)
4298 {
4299  Flow *f = NULL;
4300  uint8_t httpbuf1[] =
4301  "GET /abc/def?a=http://www.abc.com/ HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4302  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4303  TcpSession ssn;
4305 
4306  HtpState *htp_state = NULL;
4307  char input[] = "\
4308 %YAML 1.1\n\
4309 ---\n\
4310 libhtp:\n\
4311 \n\
4312  default-config:\n\
4313  personality: IDS\n\
4314  double-decode-path: yes\n\
4315  double-decode-query: yes\n\
4316 ";
4317 
4319  SCConfInit();
4321  SCConfYamlLoadString(input, strlen(input));
4322  HTPConfigure();
4323  const char *addr = "4.3.2.1";
4324  memset(&ssn, 0, sizeof(ssn));
4325 
4326  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4327  FAIL_IF_NULL(f);
4328  f->protoctx = &ssn;
4329  f->proto = IPPROTO_TCP;
4330  f->alproto = ALPROTO_HTTP1;
4331 
4332  StreamTcpInitConfig(true);
4333 
4334  uint32_t u;
4335  for (u = 0; u < httplen1; u++) {
4336  uint8_t flags = 0;
4337 
4338  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4339  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4340  else flags = STREAM_TOSERVER;
4341 
4342  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4343  FAIL_IF(r != 0);
4344  }
4345 
4346  htp_state = f->alstate;
4347  FAIL_IF_NULL(htp_state);
4348 
4349  uint8_t ref1[] = "/abc/def?a=http://www.abc.com/";
4350  size_t reflen = sizeof(ref1) - 1;
4351 
4352  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4353  FAIL_IF_NULL(tx);
4354  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4355  FAIL_IF_NULL(request_uri_normalized);
4356  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4357 
4358  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4359 
4360  UTHFreeFlow(f);
4362  HTPFreeConfig();
4363  SCConfDeInit();
4366  StreamTcpFreeConfig(true);
4367  PASS;
4368 }
4369 
4370 /** \test Test \ char in query profile IDS. Bug 739
4371  */
4372 static int HTPParserDecodingTest05(void)
4373 {
4374  Flow *f = NULL;
4375  uint8_t httpbuf1[] =
4376  "GET /index?id=\\\"<script>alert(document.cookie)</script> HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4377  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4378  TcpSession ssn;
4380 
4381  HtpState *htp_state = NULL;
4382  char input[] = "\
4383 %YAML 1.1\n\
4384 ---\n\
4385 libhtp:\n\
4386 \n\
4387  default-config:\n\
4388  personality: IDS\n\
4389  double-decode-path: yes\n\
4390  double-decode-query: yes\n\
4391 ";
4392 
4394  SCConfInit();
4396  SCConfYamlLoadString(input, strlen(input));
4397  HTPConfigure();
4398  const char *addr = "4.3.2.1";
4399  memset(&ssn, 0, sizeof(ssn));
4400 
4401  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4402  FAIL_IF_NULL(f);
4403  f->protoctx = &ssn;
4404  f->proto = IPPROTO_TCP;
4405  f->alproto = ALPROTO_HTTP1;
4406 
4407  StreamTcpInitConfig(true);
4408 
4409  uint32_t u;
4410  for (u = 0; u < httplen1; u++) {
4411  uint8_t flags = 0;
4412 
4413  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4414  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4415  else flags = STREAM_TOSERVER;
4416 
4417  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4418  FAIL_IF(r != 0);
4419  }
4420 
4421  htp_state = f->alstate;
4422  FAIL_IF_NULL(htp_state);
4423 
4424  uint8_t ref1[] = "/index?id=\\\"<script>alert(document.cookie)</script>";
4425  size_t reflen = sizeof(ref1) - 1;
4426 
4427  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4428  FAIL_IF_NULL(tx);
4429  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4430  FAIL_IF_NULL(request_uri_normalized);
4431  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4432 
4433  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4434 
4435  UTHFreeFlow(f);
4437  HTPFreeConfig();
4438  SCConfDeInit();
4441  StreamTcpFreeConfig(true);
4442  PASS;
4443 }
4444 
4445 /** \test Test + char in query. Bug 1035
4446  */
4447 static int HTPParserDecodingTest06(void)
4448 {
4449  Flow *f = NULL;
4450  uint8_t httpbuf1[] =
4451  "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4452  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4453  TcpSession ssn;
4455 
4456  HtpState *htp_state = NULL;
4457  char input[] = "\
4458 %YAML 1.1\n\
4459 ---\n\
4460 libhtp:\n\
4461 \n\
4462  default-config:\n\
4463  personality: IDS\n\
4464  double-decode-path: yes\n\
4465  double-decode-query: yes\n\
4466 ";
4467 
4469  SCConfInit();
4471  SCConfYamlLoadString(input, strlen(input));
4472  HTPConfigure();
4473  const char *addr = "4.3.2.1";
4474  memset(&ssn, 0, sizeof(ssn));
4475 
4476  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4477  FAIL_IF_NULL(f);
4478  f->protoctx = &ssn;
4479  f->proto = IPPROTO_TCP;
4480  f->alproto = ALPROTO_HTTP1;
4481 
4482  StreamTcpInitConfig(true);
4483 
4484  uint32_t u;
4485  for (u = 0; u < httplen1; u++) {
4486  uint8_t flags = 0;
4487 
4488  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4489  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4490  else flags = STREAM_TOSERVER;
4491 
4492  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4493  FAIL_IF(r != 0);
4494  }
4495 
4496  htp_state = f->alstate;
4497  FAIL_IF_NULL(htp_state);
4498 
4499  uint8_t ref1[] = "/put.php?ip=1.2.3.4&port=+6000";
4500  size_t reflen = sizeof(ref1) - 1;
4501 
4502  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4503  FAIL_IF_NULL(tx);
4504  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4505  FAIL_IF_NULL(request_uri_normalized);
4506  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4507 
4508  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4509 
4510  UTHFreeFlow(f);
4512  HTPFreeConfig();
4513  SCConfDeInit();
4516  StreamTcpFreeConfig(true);
4517  PASS;
4518 }
4519 
4520 /** \test Test + char in query. Bug 1035
4521  */
4522 static int HTPParserDecodingTest07(void)
4523 {
4524  Flow *f = NULL;
4525  uint8_t httpbuf1[] =
4526  "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4527  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4528  TcpSession ssn;
4530 
4531  HtpState *htp_state = NULL;
4532  char input[] = "\
4533 %YAML 1.1\n\
4534 ---\n\
4535 libhtp:\n\
4536 \n\
4537  default-config:\n\
4538  personality: IDS\n\
4539  double-decode-path: yes\n\
4540  double-decode-query: yes\n\
4541  query-plusspace-decode: yes\n\
4542 ";
4543 
4545  SCConfInit();
4547  SCConfYamlLoadString(input, strlen(input));
4548  HTPConfigure();
4549  const char *addr = "4.3.2.1";
4550  memset(&ssn, 0, sizeof(ssn));
4551 
4552  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4553  FAIL_IF_NULL(f);
4554  f->protoctx = &ssn;
4555  f->proto = IPPROTO_TCP;
4556  f->alproto = ALPROTO_HTTP1;
4557 
4558  StreamTcpInitConfig(true);
4559 
4560  uint32_t u;
4561  for (u = 0; u < httplen1; u++) {
4562  uint8_t flags = 0;
4563 
4564  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4565  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4566  else flags = STREAM_TOSERVER;
4567 
4568  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4569  FAIL_IF(r != 0);
4570  }
4571 
4572  htp_state = f->alstate;
4573  FAIL_IF_NULL(htp_state);
4574 
4575  uint8_t ref1[] = "/put.php?ip=1.2.3.4&port= 6000";
4576  size_t reflen = sizeof(ref1) - 1;
4577 
4578  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4579  FAIL_IF_NULL(tx);
4580  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4581  FAIL_IF_NULL(request_uri_normalized);
4582  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4583 
4584  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4585 
4586  UTHFreeFlow(f);
4588  HTPFreeConfig();
4589  SCConfDeInit();
4592  StreamTcpFreeConfig(true);
4593  PASS;
4594 }
4595 
4596 /** \test Test 'proxy' URI normalization. Ticket 1008
4597  */
4598 static int HTPParserDecodingTest08(void)
4599 {
4600  Flow *f = NULL;
4601  uint8_t httpbuf1[] =
4602  "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n";
4603  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4604  TcpSession ssn;
4606 
4607  HtpState *htp_state = NULL;
4608  char input[] = "\
4609 %YAML 1.1\n\
4610 ---\n\
4611 libhtp:\n\
4612 \n\
4613  default-config:\n\
4614  personality: IDS\n\
4615 ";
4616 
4618  SCConfInit();
4620  SCConfYamlLoadString(input, strlen(input));
4621  HTPConfigure();
4622  const char *addr = "4.3.2.1";
4623  memset(&ssn, 0, sizeof(ssn));
4624 
4625  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4626  FAIL_IF_NULL(f);
4627  f->protoctx = &ssn;
4628  f->proto = IPPROTO_TCP;
4629  f->alproto = ALPROTO_HTTP1;
4630 
4631  StreamTcpInitConfig(true);
4632 
4633  uint32_t u;
4634  for (u = 0; u < httplen1; u++) {
4635  uint8_t flags = 0;
4636 
4637  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4638  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4639  else flags = STREAM_TOSERVER;
4640 
4641  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4642  FAIL_IF(r != 0);
4643  }
4644 
4645  htp_state = f->alstate;
4646  FAIL_IF_NULL(htp_state);
4647 
4648  uint8_t ref1[] = "/blah/";
4649  size_t reflen = sizeof(ref1) - 1;
4650 
4651  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4652  FAIL_IF_NULL(tx);
4653  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4654  FAIL_IF_NULL(request_uri_normalized);
4655  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4656 
4657  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4658 
4659  UTHFreeFlow(f);
4661  HTPFreeConfig();
4662  SCConfDeInit();
4665  StreamTcpFreeConfig(true);
4666  PASS;
4667 }
4668 
4669 /** \test Test 'proxy' URI normalization. Ticket 1008
4670  */
4671 static int HTPParserDecodingTest09(void)
4672 {
4673  Flow *f = NULL;
4674  uint8_t httpbuf1[] =
4675  "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n";
4676  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4677  TcpSession ssn;
4679 
4680  HtpState *htp_state = NULL;
4681  char input[] = "\
4682 %YAML 1.1\n\
4683 ---\n\
4684 libhtp:\n\
4685 \n\
4686  default-config:\n\
4687  personality: IDS\n\
4688  uri-include-all: true\n\
4689 ";
4690 
4692  SCConfInit();
4694  SCConfYamlLoadString(input, strlen(input));
4695  HTPConfigure();
4696  const char *addr = "4.3.2.1";
4697  memset(&ssn, 0, sizeof(ssn));
4698 
4699  f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4700  FAIL_IF_NULL(f);
4701  f->protoctx = &ssn;
4702  f->proto = IPPROTO_TCP;
4703  f->alproto = ALPROTO_HTTP1;
4704 
4705  StreamTcpInitConfig(true);
4706 
4707  uint32_t u;
4708  for (u = 0; u < httplen1; u++) {
4709  uint8_t flags = 0;
4710 
4711  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4712  else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4713  else flags = STREAM_TOSERVER;
4714 
4715  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1);
4716  FAIL_IF(r != 0);
4717  }
4718 
4719  htp_state = f->alstate;
4720  FAIL_IF_NULL(htp_state);
4721 
4722  uint8_t ref1[] = "http://suricata-ids.org/blah/";
4723  size_t reflen = sizeof(ref1) - 1;
4724 
4725  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4726  FAIL_IF_NULL(tx);
4727  bstr *request_uri_normalized = (bstr *)htp_tx_normalized_uri(tx);
4728  FAIL_IF_NULL(request_uri_normalized);
4729  FAIL_IF(reflen != bstr_len(request_uri_normalized));
4730 
4731  FAIL_IF(memcmp(bstr_ptr(request_uri_normalized), ref1, bstr_len(request_uri_normalized)) != 0);
4732 
4733  UTHFreeFlow(f);
4735  HTPFreeConfig();
4736  SCConfDeInit();
4739  StreamTcpFreeConfig(true);
4740  PASS;
4741 }
4742 
4743 /** \test BG box crash -- chunks are messed up. Observed for real. */
4744 static int HTPBodyReassemblyTest01(void)
4745 {
4746  HtpTxUserData *htud = HTPCalloc(1, sizeof(*htud));
4747  FAIL_IF_NULL(htud);
4748  HtpState hstate;
4749  memset(&hstate, 0x00, sizeof(hstate));
4750  Flow flow;
4751  memset(&flow, 0x00, sizeof(flow));
4753  htp_cfg_t *cfg = htp_config_create();
4754  FAIL_IF(cfg == NULL);
4755  htp_connp_t *connp = htp_connp_create(cfg);
4756  FAIL_IF(connp == NULL);
4757  const htp_tx_t *tx = htp_connp_get_request_tx(connp);
4758  FAIL_IF(tx == NULL);
4759 
4760  hstate.f = &flow;
4761  flow.alparser = parser;
4762 
4763  uint8_t chunk1[] = "--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r";
4764  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";
4765 
4766  int r = HtpBodyAppendChunk(&htud->request_body, chunk1, sizeof(chunk1) - 1);
4767  FAIL_IF(r != 0);
4768  r = HtpBodyAppendChunk(&htud->request_body, chunk2, sizeof(chunk2) - 1);
4769  FAIL_IF(r != 0);
4770 
4771  const uint8_t *chunks_buffer = NULL;
4772  uint32_t chunks_buffer_len = 0;
4773 
4774  HtpRequestBodyReassemble(htud, &chunks_buffer, &chunks_buffer_len);
4775  FAIL_IF_NULL(chunks_buffer);
4776 #ifdef PRINT
4777  printf("REASSCHUNK START: \n");
4778  PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
4779  printf("REASSCHUNK END: \n");
4780 #endif
4781 
4782  htud->mime_state = SCMimeStateInit((const uint8_t *)"multipart/form-data; boundary=toto",
4783  strlen("multipart/form-data; boundary=toto"));
4784  FAIL_IF_NULL(htud->mime_state);
4785  htud->tsflags |= HTP_BOUNDARY_SET;
4786  HtpRequestBodyHandleMultipart(&hstate, htud, &tx, chunks_buffer, chunks_buffer_len, false);
4787 
4788  FAIL_IF(htud->request_body.content_len_so_far != 669);
4789 
4791 
4792  htp_connp_destroy_all(connp);
4793  HtpTxUserDataFree(htud);
4794  AppLayerParserStateFree(parser);
4795  htp_config_destroy(cfg);
4796  PASS;
4797 }
4798 
4799 /** \test BG crash */
4800 static int HTPSegvTest01(void)
4801 {
4802  Flow *f = NULL;
4803  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";
4804  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4805  char input[] = "\
4806 %YAML 1.1\n\
4807 ---\n\
4808 libhtp:\n\
4809 \n\
4810  default-config:\n\
4811  personality: IDS\n\
4812  double-decode-path: no\n\
4813  double-decode-query: no\n\
4814  request-body-limit: 0\n\
4815  response-body-limit: 0\n\
4816 ";
4817 
4819  SCConfInit();
4821  SCConfYamlLoadString(input, strlen(input));
4822  HTPConfigure();
4823 
4824  TcpSession ssn;
4825  HtpState *http_state = NULL;
4827 
4828  memset(&ssn, 0, sizeof(ssn));
4829 
4830  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4831  FAIL_IF_NULL(f);
4832  f->protoctx = &ssn;
4833  f->proto = IPPROTO_TCP;
4834  f->alproto = ALPROTO_HTTP1;
4835 
4836  StreamTcpInitConfig(true);
4837 
4838  SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
4839  int r = AppLayerParserParse(
4840  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
4841  FAIL_IF(r != 0);
4842  SCLogDebug("\n>>>> processing chunk 1 again <<<<\n");
4843  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
4844  FAIL_IF(r != 0);
4845 
4846  http_state = f->alstate;
4847  FAIL_IF_NULL(http_state);
4848 
4850  FAIL_IF_NOT_NULL(decoder_events);
4851 
4852  UTHFreeFlow(f);
4854  HTPFreeConfig();
4855  SCConfDeInit();
4858  StreamTcpFreeConfig(true);
4859  PASS;
4860 }
4861 
4862 /** \test Test really long request, this should result in HTP_LOG_CODE_REQUEST_FIELD_TOO_LONG */
4863 static int HTPParserTest14(void)
4864 {
4865  size_t len = 18887;
4866  TcpSession ssn;
4867  char input[] = "\
4868 %YAML 1.1\n\
4869 ---\n\
4870 libhtp:\n\
4871 \n\
4872  default-config:\n\
4873  personality: IDS\n\
4874  double-decode-path: no\n\
4875  double-decode-query: no\n\
4876  request-body-limit: 0\n\
4877  response-body-limit: 0\n\
4878 ";
4881 
4882  memset(&ssn, 0, sizeof(ssn));
4883 
4885  SCConfInit();
4887  SCConfYamlLoadString(input, strlen(input));
4888  HTPConfigure();
4889 
4890  char *httpbuf = SCMalloc(len);
4891  FAIL_IF_NULL(httpbuf);
4892  memset(httpbuf, 0x00, len);
4893 
4894  /* create the request with a longer than 18k cookie */
4895  strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n"
4896  "Host: myhost.lan\r\n"
4897  "Connection: keep-alive\r\n"
4898  "Accept: */*\r\n"
4899  "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"
4900  "Referer: http://blah.lan/\r\n"
4901  "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
4902  "Cookie: ", len);
4903  size_t o = strlen(httpbuf);
4904  for ( ; o < len - 4; o++) {
4905  httpbuf[o] = 'A';
4906  }
4907  httpbuf[len - 4] = '\r';
4908  httpbuf[len - 3] = '\n';
4909  httpbuf[len - 2] = '\r';
4910  httpbuf[len - 1] = '\n';
4911 
4912  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
4913  FAIL_IF_NULL(f);
4914  f->protoctx = &ssn;
4915  f->alproto = ALPROTO_HTTP1;
4916  f->proto = IPPROTO_TCP;
4917 
4918  StreamTcpInitConfig(true);
4919 
4920  uint32_t u;
4921  for (u = 0; u < len; u++) {
4922  uint8_t flags = 0;
4923 
4924  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4925  else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4926  else flags = STREAM_TOSERVER;
4927 
4928  (void)AppLayerParserParse(
4929  NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)&httpbuf[u], 1);
4930  }
4931  HtpState *htp_state = f->alstate;
4932  FAIL_IF_NULL(htp_state);
4933 
4934  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4935  FAIL_IF_NULL(tx);
4936  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
4937  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
4938 
4939  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
4940  AppLayerDecoderEvents *decoder_events =
4941  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
4942  FAIL_IF_NULL(decoder_events);
4943 
4944  FAIL_IF(decoder_events->events[0] != HTP_LOG_CODE_REQUEST_FIELD_TOO_LONG);
4945 
4946  UTHFreeFlow(f);
4948  StreamTcpFreeConfig(true);
4949  SCFree(httpbuf);
4950  HTPFreeConfig();
4951  SCConfDeInit();
4954  PASS;
4955 }
4956 
4957 /** \test Test really long request (same as HTPParserTest14), now with config
4958  * update to allow it */
4959 static int HTPParserTest15(void)
4960 {
4961  Flow *f = NULL;
4962  char *httpbuf = NULL;
4963  size_t len = 18887;
4964  TcpSession ssn;
4965  HtpState *htp_state = NULL;
4966  char input[] = "\
4967 %YAML 1.1\n\
4968 ---\n\
4969 libhtp:\n\
4970 \n\
4971  default-config:\n\
4972  personality: IDS\n\
4973  double-decode-path: no\n\
4974  double-decode-query: no\n\
4975  request-body-limit: 0\n\
4976  response-body-limit: 0\n\
4977  meta-field-limit: 20000\n\
4978 ";
4980 
4981  memset(&ssn, 0, sizeof(ssn));
4982 
4984  SCConfInit();
4986  SCConfYamlLoadString(input, strlen(input));
4987  HTPConfigure();
4988 
4989  httpbuf = SCMalloc(len);
4990  FAIL_IF_NULL(httpbuf);
4991 
4992  memset(httpbuf, 0x00, len);
4993 
4994  /* create the request with a longer than 18k cookie */
4995  strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n"
4996  "Host: myhost.lan\r\n"
4997  "Connection: keep-alive\r\n"
4998  "Accept: */*\r\n"
4999  "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"
5000  "Referer: http://blah.lan/\r\n"
5001  "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
5002  "Cookie: ", len);
5003  size_t o = strlen(httpbuf);
5004  for ( ; o < len - 4; o++) {
5005  httpbuf[o] = 'A';
5006  }
5007  httpbuf[len - 4] = '\r';
5008  httpbuf[len - 3] = '\n';
5009  httpbuf[len - 2] = '\r';
5010  httpbuf[len - 1] = '\n';
5011 
5012  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5013  FAIL_IF_NULL(f);
5014  f->protoctx = &ssn;
5015  f->proto = IPPROTO_TCP;
5016  f->alproto = ALPROTO_HTTP1;
5017 
5018  StreamTcpInitConfig(true);
5019 
5020  uint32_t u;
5021  for (u = 0; u < len; u++) {
5022  uint8_t flags = 0;
5023 
5024  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5025  else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5026  else flags = STREAM_TOSERVER;
5027 
5028  int r = AppLayerParserParse(
5029  NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)&httpbuf[u], 1);
5030  FAIL_IF(r != 0);
5031  }
5032  htp_state = f->alstate;
5033  FAIL_IF_NULL(htp_state);
5034 
5035  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5036  FAIL_IF_NULL(tx);
5037  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5038  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5039 
5040  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
5041  AppLayerDecoderEvents *decoder_events =
5042  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
5043  FAIL_IF_NOT_NULL(decoder_events);
5044 
5045  UTHFreeFlow(f);
5047  StreamTcpFreeConfig(true);
5048  SCFree(httpbuf);
5049  HTPFreeConfig();
5050  SCConfDeInit();
5053  PASS;
5054 }
5055 
5056 /** \test Test unusual delims in request line HTP_LOG_CODE_REQUEST_FIELD_TOO_LONG */
5057 static int HTPParserTest16(void)
5058 {
5059  Flow *f = NULL;
5060  TcpSession ssn;
5061  HtpState *htp_state = NULL;
5063 
5064  memset(&ssn, 0, sizeof(ssn));
5065 
5066  uint8_t httpbuf[] = "GET\f/blah/\fHTTP/1.1\r\n"
5067  "Host: myhost.lan\r\n"
5068  "Connection: keep-alive\r\n"
5069  "Accept: */*\r\n"
5070  "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"
5071  "Referer: http://blah.lan/\r\n"
5072  "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
5073  "Cookie: blah\r\n\r\n";
5074  size_t len = sizeof(httpbuf) - 1;
5075 
5076  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5077  FAIL_IF_NULL(f);
5078  f->protoctx = &ssn;
5079  f->proto = IPPROTO_TCP;
5080  f->alproto = ALPROTO_HTTP1;
5081 
5082  StreamTcpInitConfig(true);
5083 
5084  uint8_t flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
5085 
5086  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)httpbuf, len);
5087  FAIL_IF(r != 0);
5088 
5089  htp_state = f->alstate;
5090  FAIL_IF_NULL(htp_state);
5091 
5092  htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5093  FAIL_IF_NULL(tx);
5094  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5095  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5096 
5097 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
5098 //these events are disabled during fuzzing as they are too noisy and consume much resource
5099  void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
5100  AppLayerDecoderEvents *decoder_events =
5101  AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp);
5102 
5103  FAIL_IF_NULL(decoder_events);
5104  FAIL_IF(decoder_events->events[0] != HTP_LOG_CODE_METHOD_DELIM_NON_COMPLIANT);
5105  FAIL_IF(decoder_events->events[1] != HTP_LOG_CODE_URI_DELIM_NON_COMPLIANT);
5106 #endif
5107 
5108  UTHFreeFlow(f);
5110  StreamTcpFreeConfig(true);
5111  PASS;
5112 }
5113 
5114 /** \test Test response not HTTP
5115  */
5116 static int HTPParserTest20(void)
5117 {
5118  Flow *f = NULL;
5119  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5120  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5121  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5122  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5123  uint8_t httpbuf2[] = "NOTHTTP\r\nSOMEOTHERDATA";
5124  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5125  uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA";
5126  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
5127  TcpSession ssn;
5128  HtpState *http_state = NULL;
5131 
5132  memset(&ssn, 0, sizeof(ssn));
5133 
5134  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5135  FAIL_IF_NULL(f);
5136  f->protoctx = &ssn;
5137  f->proto = IPPROTO_TCP;
5138  f->alproto = ALPROTO_HTTP1;
5139 
5140  StreamTcpInitConfig(true);
5141 
5142  int r = AppLayerParserParse(
5143  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5144  FAIL_IF(r != 0);
5145 
5146  r = AppLayerParserParse(
5147  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5148  FAIL_IF(r != 0);
5149 
5150  r = AppLayerParserParse(
5151  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf3, httplen3);
5152  FAIL_IF(r != 0);
5153 
5154  http_state = f->alstate;
5155  FAIL_IF_NULL(http_state);
5156  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5157  FAIL_IF_NULL(tx);
5158  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5159  FAIL_IF_NULL(h);
5160 
5161  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5162  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5163 
5164  FAIL_IF(htp_tx_response_status_number(tx) != 0);
5165  FAIL_IF(htp_tx_response_protocol_number(tx) != -1);
5166 
5167  UTHFreeFlow(f);
5169  StreamTcpFreeConfig(true);
5170  PASS;
5171 }
5172 
5173 /** \test Test response not HTTP
5174  */
5175 static int HTPParserTest21(void)
5176 {
5177  Flow *f = NULL;
5178  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5179  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5180  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5181  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5182  uint8_t httpbuf2[] = "999 NOTHTTP REALLY\r\nSOMEOTHERDATA\r\n";
5183  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5184  uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA";
5185  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
5186  TcpSession ssn;
5187  HtpState *http_state = NULL;
5190 
5191  memset(&ssn, 0, sizeof(ssn));
5192 
5193  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5194  FAIL_IF_NULL(f);
5195  f->protoctx = &ssn;
5196  f->proto = IPPROTO_TCP;
5197  f->alproto = ALPROTO_HTTP1;
5198 
5199  StreamTcpInitConfig(true);
5200 
5201  int r = AppLayerParserParse(
5202  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5203  FAIL_IF(r != 0);
5204 
5205  r = AppLayerParserParse(
5206  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5207  FAIL_IF(r != 0);
5208 
5209  r = AppLayerParserParse(
5210  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf3, httplen3);
5211  FAIL_IF(r != 0);
5212 
5213  http_state = f->alstate;
5214  FAIL_IF_NULL(http_state);
5215  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5216  FAIL_IF_NULL(tx);
5217  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5218  FAIL_IF_NULL(h);
5219 
5220  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5221  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5222 
5223  FAIL_IF(htp_tx_response_status_number(tx) != 0);
5224  FAIL_IF(htp_tx_response_protocol_number(tx) != -1);
5225 
5226  UTHFreeFlow(f);
5228  StreamTcpFreeConfig(true);
5229  PASS;
5230 }
5231 
5232 /** \test Test response not HTTP
5233  */
5234 static int HTPParserTest22(void)
5235 {
5236  Flow *f = NULL;
5237  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5238  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5239  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5240  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5241  uint8_t httpbuf2[] = "\r\n0000=0000000/ASDF3_31.zip, 456723\r\n"
5242  "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
5243  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5244  TcpSession ssn;
5245  HtpState *http_state = NULL;
5248 
5249  memset(&ssn, 0, sizeof(ssn));
5250 
5251  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5252  FAIL_IF_NULL(f);
5253  f->protoctx = &ssn;
5254  f->proto = IPPROTO_TCP;
5255  f->alproto = ALPROTO_HTTP1;
5256 
5257  StreamTcpInitConfig(true);
5258 
5259  int r = AppLayerParserParse(
5260  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5261  FAIL_IF(r != 0);
5262 
5263  r = AppLayerParserParse(
5264  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5265  FAIL_IF(r != 0);
5266 
5267  http_state = f->alstate;
5268  FAIL_IF_NULL(http_state);
5269  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5270  FAIL_IF_NULL(tx);
5271  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5272  FAIL_IF_NULL(h);
5273 
5274  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5275  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5276 
5277  FAIL_IF(htp_tx_response_status_number(tx) != -0);
5278  FAIL_IF(htp_tx_response_protocol_number(tx) != -1);
5279 
5280  UTHFreeFlow(f);
5282  StreamTcpFreeConfig(true);
5283  PASS;
5284 }
5285 
5286 /** \test Test response not HTTP
5287  */
5288 static int HTPParserTest23(void)
5289 {
5290  Flow *f = NULL;
5291  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5292  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5293  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5294  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5295  uint8_t httpbuf2[] = "HTTP0000=0000000/ASDF3_31.zip, 456723\r\n"
5296  "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
5297  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5298  TcpSession ssn;
5299  HtpState *http_state = NULL;
5302 
5303  memset(&ssn, 0, sizeof(ssn));
5304 
5305  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5306  FAIL_IF_NULL(f);
5307  f->protoctx = &ssn;
5308  f->proto = IPPROTO_TCP;
5309  f->alproto = ALPROTO_HTTP1;
5310 
5311  StreamTcpInitConfig(true);
5312 
5313  int r = AppLayerParserParse(
5314  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5315  FAIL_IF(r != 0);
5316 
5317  r = AppLayerParserParse(
5318  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5319  FAIL_IF(r != 0);
5320 
5321  http_state = f->alstate;
5322  FAIL_IF_NULL(http_state);
5323  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5324  FAIL_IF_NULL(tx);
5325  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5326  FAIL_IF_NULL(h);
5327 
5328  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5329  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5330 
5331  FAIL_IF(htp_tx_response_status_number(tx) != -1);
5332  FAIL_IF(htp_tx_response_protocol_number(tx) != -2);
5333 
5334  UTHFreeFlow(f);
5335 
5337  StreamTcpFreeConfig(true);
5338  PASS;
5339 }
5340 
5341 /** \test Test response not HTTP
5342  */
5343 static int HTPParserTest24(void)
5344 {
5345  Flow *f = NULL;
5346  uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
5347  "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
5348  "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
5349  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5350  uint8_t httpbuf2[] = "HTTP/1.0 0000=0000000/ASDF3_31.zip, 456723\r\n"
5351  "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n";
5352  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5353  TcpSession ssn;
5354  HtpState *http_state = NULL;
5357 
5358  memset(&ssn, 0, sizeof(ssn));
5359 
5360  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5361  FAIL_IF_NULL(f);
5362  f->protoctx = &ssn;
5363  f->proto = IPPROTO_TCP;
5364  f->alproto = ALPROTO_HTTP1;
5365 
5366  StreamTcpInitConfig(true);
5367 
5368  int r = AppLayerParserParse(
5369  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
5370  FAIL_IF(r != 0);
5371 
5372  r = AppLayerParserParse(
5373  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2);
5374  FAIL_IF(r != 0);
5375 
5376  http_state = f->alstate;
5377  FAIL_IF_NULL(http_state);
5378  htp_tx_t *tx = HTPStateGetTx(http_state, 0);
5379  FAIL_IF_NULL(tx);
5380  const htp_header_t *h = htp_tx_request_header_index(tx, 0);
5381  FAIL_IF_NULL(h);
5382 
5383  FAIL_IF(htp_tx_request_method_number(tx) != HTP_METHOD_GET);
5384  FAIL_IF(htp_tx_request_protocol_number(tx) != HTP_PROTOCOL_V1_1);
5385 
5386  FAIL_IF(htp_tx_response_status_number(tx) != -1);
5387  FAIL_IF(htp_tx_response_protocol_number(tx) != HTP_PROTOCOL_V1_0);
5388 
5389  UTHFreeFlow(f);
5390 
5392  StreamTcpFreeConfig(true);
5393  PASS;
5394 }
5395 
5396 /** \test multi transactions and cleanup */
5397 static int HTPParserTest25(void)
5398 {
5401 
5402  StreamTcpInitConfig(true);
5403  TcpSession ssn;
5404  memset(&ssn, 0, sizeof(ssn));
5405 
5406  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5407  FAIL_IF_NULL(f);
5408  f->protoctx = &ssn;
5409  f->proto = IPPROTO_TCP;
5410  f->alproto = ALPROTO_HTTP1;
5412 
5413  const char *str = "GET / HTTP/1.1\r\nHost: www.google.com\r\nUser-Agent: Suricata/1.0\r\n\r\n";
5414  int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START,
5415  (uint8_t *)str, strlen(str));
5416  FAIL_IF_NOT(r == 0);
5417  r = AppLayerParserParse(
5418  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5419  FAIL_IF_NOT(r == 0);
5420  r = AppLayerParserParse(
5421  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5422  FAIL_IF_NOT(r == 0);
5423  r = AppLayerParserParse(
5424  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5425  FAIL_IF_NOT(r == 0);
5426  r = AppLayerParserParse(
5427  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5428  FAIL_IF_NOT(r == 0);
5429  r = AppLayerParserParse(
5430  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5431  FAIL_IF_NOT(r == 0);
5432  r = AppLayerParserParse(
5433  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5434  FAIL_IF_NOT(r == 0);
5435  r = AppLayerParserParse(
5436  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str));
5437  FAIL_IF_NOT(r == 0);
5438 
5439  str = "HTTP 1.1 200 OK\r\nServer: Suricata/1.0\r\nContent-Length: 8\r\n\r\nSuricata";
5440  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START,
5441  (uint8_t *)str, strlen(str));
5442  FAIL_IF_NOT(r == 0);
5443  r = AppLayerParserParse(
5444  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5445  FAIL_IF_NOT(r == 0);
5446  r = AppLayerParserParse(
5447  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5448  FAIL_IF_NOT(r == 0);
5449  r = AppLayerParserParse(
5450  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5451  FAIL_IF_NOT(r == 0);
5452  r = AppLayerParserParse(
5453  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5454  FAIL_IF_NOT(r == 0);
5455  r = AppLayerParserParse(
5456  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5457  FAIL_IF_NOT(r == 0);
5458  r = AppLayerParserParse(
5459  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5460  FAIL_IF_NOT(r == 0);
5461  r = AppLayerParserParse(
5462  NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str));
5463  FAIL_IF_NOT(r == 0);
5464 
5465  AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
5466 
5467  uint64_t ret[4];
5468  UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
5469  FAIL_IF_NOT(ret[0] == 8); // inspect_id[0]
5470  FAIL_IF_NOT(ret[1] == 8); // inspect_id[1]
5471  FAIL_IF_NOT(ret[2] == 8); // log_id
5472  FAIL_IF_NOT(ret[3] == 8); // min_id
5473 
5474  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF,
5475  (uint8_t *)str, strlen(str));
5476  FAIL_IF_NOT(r == 0);
5477  AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
5478 
5479  UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
5480  FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] not updated by ..Cleanup() until full tx is done
5481  FAIL_IF_NOT(ret[1] == 8); // inspect_id[1]
5482  FAIL_IF_NOT(ret[2] == 8); // log_id
5483  FAIL_IF_NOT(ret[3] == 8); // min_id
5484 
5485  r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_EOF,
5486  (uint8_t *)str, strlen(str));
5487  FAIL_IF_NOT(r == 0);
5488  AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT);
5489 
5490  UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
5491  FAIL_IF_NOT(ret[0] == 9); // inspect_id[0]
5492  FAIL_IF_NOT(ret[1] == 9); // inspect_id[1]
5493  FAIL_IF_NOT(ret[2] == 9); // log_id
5494  FAIL_IF_NOT(ret[3] == 9); // min_id
5495 
5496  HtpState *http_state = f->alstate;
5497  FAIL_IF_NULL(http_state);
5498 
5499  UTHFreeFlow(f);
5500 
5502  StreamTcpFreeConfig(true);
5503 
5504  PASS;
5505 }
5506 
5507 static int HTPParserTest26(void)
5508 {
5509  char input[] = "\
5510 %YAML 1.1\n\
5511 ---\n\
5512 libhtp:\n\
5513 \n\
5514  default-config:\n\
5515  personality: IDS\n\
5516  request-body-limit: 1\n\
5517  response-body-limit: 1\n\
5518 ";
5520  SCConfInit();
5522  SCConfYamlLoadString(input, strlen(input));
5523  HTPConfigure();
5524 
5525  Packet *p1 = NULL;
5526  Packet *p2 = NULL;
5527  ThreadVars th_v;
5528  DetectEngineCtx *de_ctx = NULL;
5529  DetectEngineThreadCtx *det_ctx = NULL;
5530  Flow f;
5531  uint8_t httpbuf1[] = "GET /alice.txt HTTP/1.1\r\n\r\n";
5532  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5533  uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\n"
5534  "Content-Type: text/plain\r\n"
5535  "Content-Length: 228\r\n\r\n"
5536  "Alice was beginning to get very tired of sitting by her sister on the bank."
5537  "Alice was beginning to get very tired of sitting by her sister on the bank.";
5538  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
5539  uint8_t httpbuf3[] = "Alice was beginning to get very tired of sitting by her sister on the bank.\r\n\r\n";
5540  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
5541  TcpSession ssn;
5542  HtpState *http_state = NULL;
5545 
5546  memset(&th_v, 0, sizeof(th_v));
5547  StatsThreadInit(&th_v.stats);
5548  memset(&f, 0, sizeof(f));
5549  memset(&ssn, 0, sizeof(ssn));
5550 
5551  p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
5552  p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
5553 
5554  FLOW_INITIALIZE(&f);
5555  f.protoctx = (void *)&ssn;
5556  f.proto = IPPROTO_TCP;
5557  f.flags |= FLOW_IPV4;
5558 
5559  p1->flow = &f;
5563  p2->flow = &f;
5567  f.alproto = ALPROTO_HTTP1;
5568 
5569  StreamTcpInitConfig(true);
5570 
5573 
5574  de_ctx->flags |= DE_QUIET;
5575 
5576  de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any "
5577  "(filestore; sid:1; rev:1;)");
5579 
5581  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
5582 
5583  int r = AppLayerParserParse(
5584  &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
5585  FAIL_IF(r != 0);
5586 
5587  http_state = f.alstate;
5588  FAIL_IF_NULL(http_state);
5589 
5590  /* do detect */
5591  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
5592 
5593  FAIL_IF((PacketAlertCheck(p1, 1)));
5594 
5595  /* do detect */
5596  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
5597 
5598  FAIL_IF((PacketAlertCheck(p1, 1)));
5599 
5600  r = AppLayerParserParse(
5601  &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf2, httplen2);
5602  FAIL_IF(r != 0);
5603 
5604  http_state = f.alstate;
5605  FAIL_IF_NULL(http_state);
5606 
5607  /* do detect */
5608  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
5609 
5610  FAIL_IF(!(PacketAlertCheck(p2, 1)));
5611 
5612  r = AppLayerParserParse(
5613  &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf3, httplen3);
5614  FAIL_IF(r != 0);
5615 
5616  http_state = f.alstate;
5617  FAIL_IF_NULL(http_state);
5618 
5619  void *tx_ptr = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0);
5620  FAIL_IF_NULL(tx_ptr);
5621 
5622  AppLayerGetFileState files = HTPGetTxFiles(tx_ptr, STREAM_TOCLIENT);
5623  FileContainer *ffc = files.fc;
5624  FAIL_IF_NULL(ffc);
5625 
5626  File *ptr = ffc->head;
5627  FAIL_IF(ptr->state != FILE_STATE_CLOSED);
5628 
5629  FLOW_DESTROY(&f);
5630  UTHFreePackets(&p1, 1);
5631  UTHFreePackets(&p2, 1);
5632 
5634  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
5636  StreamTcpFreeConfig(true);
5637 
5638  HTPFreeConfig();
5639  SCConfDeInit();
5642  StatsThreadCleanup(&th_v.stats);
5643  PASS;
5644 }
5645 
5646 static int HTPParserTest27(void)
5647 {
5648  HTPCfgDir cfg;
5649  memset(&cfg, 0, sizeof(cfg));
5650  cfg.body_limit = 1500;
5652 
5653  uint32_t len = 1000;
5654 
5655  HtpTxUserData *tx_ud = SCMalloc(sizeof(HtpTxUserData));
5656  FAIL_IF_NULL(tx_ud);
5657 
5658  tx_ud->tsflags |= HTP_STREAM_DEPTH_SET;
5659  tx_ud->request_body.content_len_so_far = 2500;
5660 
5661  FAIL_IF(AppLayerHtpCheckDepth(&cfg, &tx_ud->request_body, tx_ud->tsflags));
5662 
5663  len = AppLayerHtpComputeChunkLength(tx_ud->request_body.content_len_so_far,
5664  0,
5666  tx_ud->tsflags,
5667  len);
5668  FAIL_IF(len != 1000);
5669 
5670  SCFree(tx_ud);
5671 
5672  PASS;
5673 }
5674 
5675 /**
5676  * \brief Register the Unit tests for the HTTP protocol
5677  */
5678 static void HTPParserRegisterTests(void)
5679 {
5680  UtRegisterTest("HTPParserTest01", HTPParserTest01);
5681  UtRegisterTest("HTPParserTest01a", HTPParserTest01a);
5682  UtRegisterTest("HTPParserTest01b", HTPParserTest01b);
5683  UtRegisterTest("HTPParserTest01c", HTPParserTest01c);
5684  UtRegisterTest("HTPParserTest02", HTPParserTest02);
5685  UtRegisterTest("HTPParserTest03", HTPParserTest03);
5686  UtRegisterTest("HTPParserTest04", HTPParserTest04);
5687  UtRegisterTest("HTPParserTest05", HTPParserTest05);
5688  UtRegisterTest("HTPParserTest06", HTPParserTest06);
5689  UtRegisterTest("HTPParserTest07", HTPParserTest07);
5690  UtRegisterTest("HTPParserTest08", HTPParserTest08);
5691  UtRegisterTest("HTPParserTest09", HTPParserTest09);
5692  UtRegisterTest("HTPParserTest10", HTPParserTest10);
5693  UtRegisterTest("HTPParserTest11", HTPParserTest11);
5694  UtRegisterTest("HTPParserTest12", HTPParserTest12);
5695  UtRegisterTest("HTPParserTest13", HTPParserTest13);
5696  UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01);
5697  UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02);
5698  UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03);
5699 
5700  UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01);
5701  UtRegisterTest("HTPParserDecodingTest01a", HTPParserDecodingTest01a);
5702  UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02);
5703  UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03);
5704  UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04);
5705  UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05);
5706  UtRegisterTest("HTPParserDecodingTest06", HTPParserDecodingTest06);
5707  UtRegisterTest("HTPParserDecodingTest07", HTPParserDecodingTest07);
5708  UtRegisterTest("HTPParserDecodingTest08", HTPParserDecodingTest08);
5709  UtRegisterTest("HTPParserDecodingTest09", HTPParserDecodingTest09);
5710 
5711  UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01);
5712 
5713  UtRegisterTest("HTPSegvTest01", HTPSegvTest01);
5714 
5715  UtRegisterTest("HTPParserTest14", HTPParserTest14);
5716  UtRegisterTest("HTPParserTest15", HTPParserTest15);
5717  UtRegisterTest("HTPParserTest16", HTPParserTest16);
5718  UtRegisterTest("HTPParserTest20", HTPParserTest20);
5719  UtRegisterTest("HTPParserTest21", HTPParserTest21);
5720  UtRegisterTest("HTPParserTest22", HTPParserTest22);
5721  UtRegisterTest("HTPParserTest23", HTPParserTest23);
5722  UtRegisterTest("HTPParserTest24", HTPParserTest24);
5723  UtRegisterTest("HTPParserTest25", HTPParserTest25);
5724  UtRegisterTest("HTPParserTest26", HTPParserTest26);
5725  UtRegisterTest("HTPParserTest27", HTPParserTest27);
5726 
5729 }
5730 #endif /* UNITTESTS */
5731 
5732 /**
5733  * @}
5734  */
HtpState
struct HtpState_ HtpState
HtpState_::cfg
const struct HTPCfgRec_ * cfg
Definition: app-layer-htp.h:190
HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT
#define HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT
Definition: app-layer-htp.h:44
util-byte.h
StreamSlice
Definition: app-layer-parser.h:116
SCConfYamlLoadString
int SCConfYamlLoadString(const char *string, size_t len)
Load configuration from a YAML string.
Definition: conf-yaml-loader.c:536
FILE_TRUNCATED
#define FILE_TRUNCATED
Definition: util-file.h:112
AppLayerParserRegisterGetStateProgressFunc
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
Definition: app-layer-parser.c:504
FileContainer_
Definition: util-file.h:37
HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR
@ HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR
Definition: app-layer-htp.h:78
HTP_BODY_REQUEST_POST
@ HTP_BODY_REQUEST_POST
Definition: app-layer-htp.h:72
len
uint8_t len
Definition: app-layer-dnp3.h:2
ts
uint64_t ts
Definition: source-erf-file.c:55
SCConfValIsTrue
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:552
SCAppLayerParserStateIssetFlag
uint16_t SCAppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:1871
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
DetectEngineStateDirection_::flags
uint8_t flags
Definition: detect-engine-state.h:91
HtpState_::slice
StreamSlice * slice
Definition: app-layer-htp.h:197
FLOW_IS_IPV6
#define FLOW_IS_IPV6(f)
Definition: flow.h:163
Flow_::flags
uint64_t flags
Definition: flow.h:396
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1295
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:443
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:486
HtpTxUserData_::request_headers_raw_len
uint32_t request_headers_raw_len
Definition: app-layer-htp.h:171
StreamingBufferConfig_::Calloc
void *(* Calloc)(size_t n, size_t size)
Definition: util-streaming-buffer.h:69
FileReassemblyDepthEnable
void FileReassemblyDepthEnable(uint32_t size)
Definition: util-file.c:127
stream-tcp.h
HTPCfgDir_
Definition: app-layer-htp.h:95
SCRadix6TreeFindBestMatch
SCRadix6Node * SCRadix6TreeFindBestMatch(const SCRadix6Tree *tree, const uint8_t *key, void **user_data)
Definition: util-radix6-tree.c:173
HtpBody_::sb
StreamingBuffer * sb
Definition: app-layer-htp.h:135
HtpTxUserData_::files_tc
FileContainer files_tc
Definition: app-layer-htp.h:180
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
HTPFileStoreChunk
int HTPFileStoreChunk(HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, uint8_t direction)
Store a chunk of data in the flow.
Definition: app-layer-htp-file.c:223
AppLayerParserTransactionsCleanup
void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir)
remove obsolete (inspected and logged) transactions
Definition: app-layer-parser.c:927
HTPCfgRec_::response
HTPCfgDir response
Definition: app-layer-htp.h:117
SCRadix4AddKeyIPV4String
bool SCRadix4AddKeyIPV4String(SCRadix4Tree *tree, const SCRadix4Config *config, const char *str, void *user)
Adds a new IPV4/netblock to the Radix4 tree from a string.
Definition: util-radix4-tree.c:227
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
FLOW_SGH_TOCLIENT
#define FLOW_SGH_TOCLIENT
Definition: flow.h:74
AppLayerHtpPrintStats
void AppLayerHtpPrintStats(void)
Definition: app-layer-htp.c:2430
SCAppLayerTxDataCleanup
void SCAppLayerTxDataCleanup(AppLayerTxData *txd)
Definition: app-layer-parser.c:765
AppLayerParserGetEventsByTx
AppLayerDecoderEvents * AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *tx)
Definition: app-layer-parser.c:881
HTPCfgDir_::body_limit
uint32_t body_limit
Definition: app-layer-htp.h:96
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
AppLayerTxData::de_state
DetectEngineState * de_state
Definition: app-layer-parser.h:203
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:143
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:1111
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:2178
SCAppLayerProtoDetectPMRegisterPatternCI
int SCAppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction)
Registers a case-insensitive pattern for protocol detection.
Definition: app-layer-detect-proto.c:1673
STREAMING_BUFFER_CONFIG_INITIALIZER
#define STREAMING_BUFFER_CONFIG_INITIALIZER
Definition: util-streaming-buffer.h:74
HtpTxUserData_::mime_state
MimeStateHTTP * mime_state
Definition: app-layer-htp.h:174
Packet_::flags
uint32_t flags
Definition: decode.h:551
AppLayerStateData
Definition: app-layer-parser.h:145
Frame
Definition: app-layer-frames.h:43
Flow_
Flow data structure.
Definition: flow.h:347
File_::state
FileState state
Definition: util-file.h:149
HtpGetTxForH2
void * HtpGetTxForH2(void *alstate)
Definition: app-layer-htp.c:2519
HtpState_::flags
uint16_t flags
Definition: app-layer-htp.h:191
HtpState_::f
Flow * f
Definition: app-layer-htp.h:188
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:966
AppLayerParserRegisterStateProgressCompletionStatus
void AppLayerParserRegisterStateProgressCompletionStatus(AppProto alproto, const int ts, const int tc)
Definition: app-layer-parser.c:552
AppLayerParserRegisterTxFreeFunc
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
Definition: app-layer-parser.c:514
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:2652
HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW
#define HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW
Definition: app-layer-htp.h:46
HtpTxUserData_::request_body
HtpBody request_body
Definition: app-layer-htp.h:166
DetectEngineState_::dir_state
DetectEngineStateDirection dir_state[2]
Definition: detect-engine-state.h:96
AppLayerRequestProtocolChange
bool AppLayerRequestProtocolChange(Flow *f, uint16_t dp, AppProto expect_proto)
request applayer to wrap up this protocol and rerun protocol detection.
Definition: app-layer-detect-proto.c:1842
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c: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:90
AppLayerParserRegisterGetStateFuncs
void AppLayerParserRegisterGetStateFuncs(uint8_t ipproto, AppProto alproto, AppLayerParserGetStateIdByNameFn GetIdByNameFunc, AppLayerParserGetStateNameByIdFn GetNameByIdFunc)
Definition: app-layer-parser.c:579
DE_QUIET
#define DE_QUIET
Definition: detect.h:330
SCConfValIsFalse
int SCConfValIsFalse(const char *val)
Check if a value is false.
Definition: conf.c:577
HTP_BODY_REQUEST_PUT
@ HTP_BODY_REQUEST_PUT
Definition: app-layer-htp.h:73
UTHBuildPacket
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
Definition: util-unittest-helper.c: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:2769
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:189
HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE
#define HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE
Definition: app-layer-htp.h:45
HTPCfgRec_::swf_compress_depth
uint32_t swf_compress_depth
Definition: app-layer-htp.h:114
StreamingBufferGetDataAtOffset
int StreamingBufferGetDataAtOffset(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t offset)
Definition: util-streaming-buffer.c:1827
AppLayerFrameNewByAbsoluteOffset
Frame * AppLayerFrameNewByAbsoluteOffset(Flow *f, const StreamSlice *stream_slice, const uint64_t frame_start, const int64_t len, int dir, uint8_t frame_type)
create new frame using the absolute offset from the start of the stream
Definition: app-layer-frames.c:609
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:536
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
Flow_::protoctx
void * protoctx
Definition: flow.h:426
AppLayerGetTxIterTuple::tx_ptr
void * tx_ptr
Definition: app-layer-parser.h:150
AppLayerGetTxIterState::u64
uint64_t u64
Definition: app-layer-parser.h:141
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:99
GET_IPV6_DST_ADDR
#define GET_IPV6_DST_ADDR(p)
Definition: decode.h:205
HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG
@ HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG
Definition: app-layer-htp.h:84
AppLayerDecoderEvents_
Data structure to store app layer decoder events.
Definition: app-layer-events.h:33
HTPCfgDir_::inspect_window
uint32_t inspect_window
Definition: app-layer-htp.h:98
util-unittest.h
HTPConfigure
void HTPConfigure(void)
Definition: app-layer-htp.c:2359
HTTP_DECODER_EVENT_TOO_MANY_WARNINGS
@ HTTP_DECODER_EVENT_TOO_MANY_WARNINGS
Definition: app-layer-htp.h:82
HtpState_
Definition: app-layer-htp.h:183
HTPParseMemcap
void HTPParseMemcap(void)
Definition: app-layer-htp-mem.c:43
StringParseU32RangeCheck
int StringParseU32RangeCheck(uint32_t *res, int base, size_t len, const char *str, uint32_t min, uint32_t max)
Definition: util-byte.c:366
util-unittest-helper.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
SCRadix4TreeRelease
void SCRadix4TreeRelease(SCRadix4Tree *tree, const SCRadix4Config *config)
Definition: util-radix4-tree.c:172
HTPFileOpen
int HTPFileOpen(HtpState *s, HtpTxUserData *tx, const uint8_t *filename, uint16_t filename_len, const uint8_t *data, uint32_t data_len, uint8_t direction)
Open the file with "filename" and pass the first chunk of data if any.
Definition: app-layer-htp-file.c:50
SCAppLayerDecoderEventsSetEventRaw
void SCAppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t event)
Set an app layer decoder event.
Definition: app-layer-events.c:96
app-layer-htp-xff.h
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
app-layer-htp-file.h
util-memcmp.h
SCAppLayerProtoDetectConfProtoDetectionEnabled
int SCAppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
Definition: app-layer-detect-proto.c:1995
HtpBody_::content_len_so_far
uint64_t content_len_so_far
Definition: app-layer-htp.h:138
HtpState_::response_frame_id
FrameId response_frame_id
Definition: app-layer-htp.h:199
SCRadix4Tree_
Structure for the radix tree.
Definition: util-radix4-tree.h:66
SCConfInit
void SCConfInit(void)
Initialize the configuration system.
Definition: conf.c:121
HTP_RESP_BODY_SEEN
#define HTP_RESP_BODY_SEEN
Definition: app-layer-htp.h:149
AppLayerResult
Definition: app-layer-parser.h:110
HTP_CONFIG_DEFAULT_HEADERS_LIMIT
#define HTP_CONFIG_DEFAULT_HEADERS_LIMIT
Flow_::alparser
AppLayerParserState * alparser
Definition: flow.h:471
SCAppLayerParserTriggerRawStreamInspection
void SCAppLayerParserTriggerRawStreamInspection(Flow *f, int direction)
Definition: app-layer-parser.c:1581
Flow_::dst
FlowAddress dst
Definition: flow.h:350
HtpTxUserData_::file_range
HttpRangeContainerBlock * file_range
Definition: app-layer-htp.h:176
app-layer-detect-proto.h
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:498
UTHBuildFlow
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
Definition: util-unittest-helper.c:497
FLOW_INITIALIZE
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:38
app-layer-htp.h
HTP_FILENAME_SET
#define HTP_FILENAME_SET
Definition: app-layer-htp.h:146
APP_LAYER_INCOMPLETE
#define APP_LAYER_INCOMPLETE(c, n)
Definition: app-layer-parser.h:69
HTP_CONFIG_DEFAULT_LZMA_MEMLIMIT
#define HTP_CONFIG_DEFAULT_LZMA_MEMLIMIT
Definition: app-layer-htp.h:53
decode.h
FAIL_IF_NOT_NULL
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
util-debug.h
HtpState_::last_request_data_stamp
uint64_t last_request_data_stamp
Definition: app-layer-htp.h:195
TAILQ_FIRST
#define TAILQ_FIRST(head)
Definition: queue.h:250
HtpBody_::body_parsed
uint64_t body_parsed
Definition: app-layer-htp.h:140
HTPCfgRec_::http_body_inline
int http_body_inline
Definition: app-layer-htp.h:109
AppLayerParserState_
Definition: app-layer-parser.c:135
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
HTPCfgRec_::randomize_range
int randomize_range
Definition: app-layer-htp.h:108
StreamSlice::offset
uint64_t offset
Definition: app-layer-parser.h:121
GET_IPV4_DST_ADDR_PTR
#define GET_IPV4_DST_ADDR_PTR(p)
Definition: decode.h:200
AppLayerTxData
Definition: app-layer-parser.h:162
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:65
HTTP_SWF_COMPRESSION_NONE
@ HTTP_SWF_COMPRESSION_NONE
Definition: app-layer-htp.h:89
SCAppLayerParserConfParserEnabled
int SCAppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests
Definition: app-layer-parser.c:345
HtpConfigCreateBackup
void HtpConfigCreateBackup(void)
Definition: app-layer-htp.c:2695
HTP_CONFIG_DEFAULT_FIELD_LIMIT
#define HTP_CONFIG_DEFAULT_FIELD_LIMIT
Definition: app-layer-htp.h:49
DetectEngineThreadCtx_
Definition: detect.h:1284
SC_FILENAME_MAX
#define SC_FILENAME_MAX
Definition: util-file.h:129
HTP_CONFIG_DEFAULT_COMPRESSION_TIME_LIMIT
#define HTP_CONFIG_DEFAULT_COMPRESSION_TIME_LIMIT
Definition: app-layer-htp.h:56
HTPCfgRec_::randomize
int randomize
Definition: app-layer-htp.h:107
APP_LAYER_EVENT_TYPE_TRANSACTION
@ APP_LAYER_EVENT_TYPE_TRANSACTION
Definition: app-layer-events.h:55
HTPCfgDir_::inspect_min_size
uint32_t inspect_min_size
Definition: app-layer-htp.h:97
AppLayerEventType
AppLayerEventType
Definition: app-layer-events.h:54
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:120
AppLayerHtpEnableRequestBodyCallback
void AppLayerHtpEnableRequestBodyCallback(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request body...
Definition: app-layer-htp.c: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:589
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
FileContainer_::head
File * head
Definition: util-file.h:38
http_decoder_event_table
SCEnumCharMap http_decoder_event_table[]
Definition: app-layer-htp.c:105
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
HtpTxUserData_::response_has_trailers
uint8_t response_has_trailers
Definition: app-layer-htp.h:159
HtpTxUserData_::request_headers_raw
uint8_t * request_headers_raw
Definition: app-layer-htp.h:169
HtpState_::conn
htp_conn_t * conn
Definition: app-layer-htp.h:187
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3387
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:113
AppLayerParserRegisterStateFuncs
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void *, AppProto), void(*StateFree)(void *))
Definition: app-layer-parser.c:453
HTPCfgRec_::swf_decompression_enabled
int swf_decompression_enabled
Definition: app-layer-htp.h:111
HtpTxUserData_::tx_data
AppLayerTxData tx_data
Definition: app-layer-htp.h:178
HtpState_::state_data
AppLayerStateData state_data
Definition: app-layer-htp.h:200
HTPCalloc
void * HTPCalloc(size_t n, size_t size)
Definition: app-layer-htp-mem.c:153
HTPAtExitPrintStats
void HTPAtExitPrintStats(void)
Print the stats of the HTTP requests.
Definition: app-layer-htp.c:1586
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:3198
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:51
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:83
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:158
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:62
AppLayerParserRegisterGetEventInfo
void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfo)(const char *event_name, uint8_t *event_id, AppLayerEventType *event_type))
Definition: app-layer-parser.c:599
HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE
#define HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE
Definition: app-layer-htp.h:47
FileReassemblyDepth
uint32_t FileReassemblyDepth(void)
Definition: util-file.c:133
SCReturn
#define SCReturn
Definition: util-debug.h:286
SC_ATOMIC_DECLARE
SC_ATOMIC_DECLARE(uint32_t, htp_config_flags)
AppLayerParserRegisterProtocolUnittests
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
Definition: app-layer-parser.c:1882
HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT
#define HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT
Definition: app-layer-htp.h:43
app-layer-htp-body.h
AppLayerGetTxIterState
Definition: app-layer-parser.h:138
Packet_
Definition: decode.h:505
detect-engine-build.h
conf-yaml-loader.h
detect-engine-alert.h
conf.h
HtpState_::htp_messages_count
uint16_t htp_messages_count
Definition: app-layer-htp.h:193
Frame::len
int64_t len
Definition: app-layer-frames.h:50
SC_RADIX4_TREE_INITIALIZER
#define SC_RADIX4_TREE_INITIALIZER
Definition: util-radix4-tree.h:78
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:300
HtpBodyPrune
void HtpBodyPrune(HtpState *state, HtpBody *body, int direction)
Free request body chunks that are already fully parsed.
Definition: app-layer-htp-body.c:128
AppLayerParserRegisterGetTxFilesFunc
void AppLayerParserRegisterGetTxFilesFunc(uint8_t ipproto, AppProto alproto, AppLayerGetFileState(*GetTxFiles)(void *, uint8_t))
Definition: app-layer-parser.c:476
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
AppLayerProtoDetectRegisterProtocol
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
Definition: app-layer-detect-proto.c:1782
HTP_STREAM_DEPTH_SET
#define HTP_STREAM_DEPTH_SET
Definition: app-layer-htp.h:148
AppLayerHtpEnableResponseBodyCallback
void AppLayerHtpEnableResponseBodyCallback(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request body...
Definition: app-layer-htp.c:565
AppLayerParserRegisterSetStreamDepthFlag
void AppLayerParserRegisterSetStreamDepthFlag(uint8_t ipproto, AppProto alproto, void(*SetStreamDepthFlag)(void *tx, uint8_t flags))
Definition: app-layer-parser.c:640
SCConfCreateContextBackup
void SCConfCreateContextBackup(void)
Creates a backup of the conf_hash hash_table used by the conf API.
Definition: conf.c:715
AppLayerGetTxIterTuple
Definition: app-layer-parser.h:149
IF_HTP_PERSONALITY_NUM
#define IF_HTP_PERSONALITY_NUM(p)
HTPCfgRec_::swf_compression_type
HtpSwfCompressType swf_compression_type
Definition: app-layer-htp.h:112
ALPROTO_HTTP2
@ ALPROTO_HTTP2
Definition: app-layer-protos.h:69
HTP_REQUIRE_RESPONSE_BODY
#define HTP_REQUIRE_RESPONSE_BODY
Definition: app-layer-htp.h:208
FLOW_PKT_TOCLIENT
#define FLOW_PKT_TOCLIENT
Definition: flow.h: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:167
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:232
AppLayerParserGetTx
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
Definition: app-layer-parser.c:1133
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:420
WarnInvalidConfEntry
#define WarnInvalidConfEntry(param_name, format, value)
Generic API that can be used by all to log an invalid conf entry.
Definition: util-misc.h:35
DETECT_ENGINE_STATE_FLAG_FILE_NEW
#define DETECT_ENGINE_STATE_FLAG_FILE_NEW
Definition: detect-engine-state.h:73
HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE
@ HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE
Definition: app-layer-htp.h:85
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2274
HTPCfgRec_::next
struct HTPCfgRec_ * next
Definition: app-layer-htp.h:104
StatsThreadInit
void StatsThreadInit(StatsThreadContext *stats)
Definition: counters.c:1331
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:534
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:824
HttpFrameTypes
HttpFrameTypes
Definition: app-layer-htp.c:222
FILE_STATE_CLOSED
@ FILE_STATE_CLOSED
Definition: util-file.h:138
File_
Definition: util-file.h:146
APP_LAYER_OK
#define APP_LAYER_OK
Definition: app-layer-parser.h:57
HtpTxUserData_::request_body_type
uint8_t request_body_type
Definition: app-layer-htp.h:164
HTPCfgRec_::cfg
htp_cfg_t * cfg
Definition: app-layer-htp.h:103
app-layer-frames.h
SCMapEnumValueToName
const char * SCMapEnumValueToName(int enum_value, SCEnumCharMap *table)
Maps an enum value to a string name, from the supplied table.
Definition: util-enum.c:68
Packet_::flow
struct Flow_ * flow
Definition: decode.h:553
SCReturnStruct
#define SCReturnStruct(x)
Definition: util-debug.h:304
SCRadix6Config_
Definition: util-radix6-tree.h:69
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
HtpBody_
Definition: app-layer-htp.h:131
StreamTcpFreeConfig
void StreamTcpFreeConfig(bool quiet)
Definition: stream-tcp.c:869
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:79
SCRadix4Config_
Definition: util-radix4-tree.h:71
AppLayerParserParse
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
Definition: app-layer-parser.c:1315
AppLayerGetFileState
Definition: util-file.h:44
suricata-common.h
AppLayerGetFileState::fc
FileContainer * fc
Definition: util-file.h:45
HTPCfgRec_::request
HTPCfgDir request
Definition: app-layer-htp.h:116
AppLayerTxData::updated_tc
bool updated_tc
Definition: app-layer-parser.h:169
HTP_REQUIRE_REQUEST_BODY
#define HTP_REQUIRE_REQUEST_BODY
Definition: app-layer-htp.h:204
HtpTxUserData_::response_headers_raw
uint8_t * response_headers_raw
Definition: app-layer-htp.h:170
SCEnumCharMap_
Definition: util-enum.h:27
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:36
SCAppLayerParserRegisterParserAcceptableDataDirection
void SCAppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppProto alproto, uint8_t direction)
Definition: app-layer-parser.c:432
HtpState_::connp
htp_connp_t * connp
Definition: app-layer-htp.h:185
TAILQ_NEXT
#define TAILQ_NEXT(elm, field)
Definition: queue.h:307
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3626
HTP_BOUNDARY_SET
#define HTP_BOUNDARY_SET
Definition: app-layer-htp.h:145
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:241
HtpTxUserData_::tcflags
uint8_t tcflags
Definition: app-layer-htp.h:162
SCTIME_SECS
#define SCTIME_SECS(t)
Definition: util-time.h:57
AppLayerParserRegisterStateDataFunc
void AppLayerParserRegisterStateDataFunc(uint8_t ipproto, AppProto alproto, AppLayerStateData *(*GetStateData)(void *state))
Definition: app-layer-parser.c:620
htp_radix6_cfg
SCRadix6Config htp_radix6_cfg
Definition: app-layer-htp.c:87
HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER
@ HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER
Definition: app-layer-htp.h:80
SCConfDeInit
void SCConfDeInit(void)
De-initializes the configuration system.
Definition: conf.c:734
FatalError
#define FatalError(...)
Definition: util-debug.h:517
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:975
AppLayerParserRegisterTxDataFunc
void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto, AppLayerTxData *(*GetTxData)(void *tx))
Definition: app-layer-parser.c:610
ALPROTO_WEBSOCKET
@ ALPROTO_WEBSOCKET
Definition: app-layer-protos.h:64
HTP_DONTSTORE
#define HTP_DONTSTORE
Definition: app-layer-htp.h:147
HTP_CONFIG_DEFAULT_RANDOMIZE
#define HTP_CONFIG_DEFAULT_RANDOMIZE
Definition: app-layer-htp.h:58
HtpTxUserData_
Definition: app-layer-htp.h:153
HtpState_::last_response_data_stamp
uint64_t last_response_data_stamp
Definition: app-layer-htp.h:196
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:33
SCRadix4TreeFindBestMatch
SCRadix4Node * SCRadix4TreeFindBestMatch(const SCRadix4Tree *tree, const uint8_t *key, void **user_data)
Definition: util-radix4-tree.c:154
ParseSizeStringU32
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition: util-misc.c:174
app-layer-events.h
util-validate.h
HtpConfigRestoreBackup
void HtpConfigRestoreBackup(void)
Definition: app-layer-htp.c:2700
StreamingBufferConfig_
Definition: util-streaming-buffer.h:65
FileContainerRecycle
void FileContainerRecycle(FileContainer *ffc, const StreamingBufferConfig *cfg)
Recycle a FileContainer.
Definition: util-file.c:495
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
HtpState_::events
uint16_t events
Definition: app-layer-htp.h:192
HtpTxUserData_::response_body_init
uint8_t response_body_init
Definition: app-layer-htp.h:156
HTTP_FRAME_RESPONSE
@ HTTP_FRAME_RESPONSE
Definition: app-layer-htp.c: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:544
HTP_CONFIG_DEFAULT_COMPRESSION_BOMB_LIMIT
#define HTP_CONFIG_DEFAULT_COMPRESSION_BOMB_LIMIT
Definition: app-layer-htp.h:54
SCConfGetNode
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition: conf.c: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:472
AppLayerParserGetDecoderEvents
AppLayerDecoderEvents * AppLayerParserGetDecoderEvents(AppLayerParserState *pstate)
Definition: app-layer-parser.c:873
SCHTPFileCloseHandleRange
bool SCHTPFileCloseHandleRange(const StreamingBufferConfig *sbcfg, FileContainer *files, const uint16_t flags, HttpRangeContainerBlock *c, const uint8_t *data, uint32_t data_len)
close range, add reassembled file if possible
Definition: app-layer-htp-range.c:632
SCConfRestoreContextBackup
void SCConfRestoreContextBackup(void)
Restores the backup of the hash_table present in backup_conf_hash back to conf_hash.
Definition: conf.c: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:92
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:102
HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW
#define HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW
Definition: app-layer-htp.h:48
RegisterHTPParsers
void RegisterHTPParsers(void)
Register the HTTP protocol and state handling functions to APP layer of the engine.
Definition: app-layer-htp.c:2624
SCRadix6AddKeyIPV6String
bool SCRadix6AddKeyIPV6String(SCRadix6Tree *tree, const SCRadix6Config *config, const char *str, void *user)
Adds a new IPV6/netblock to the Radix6 tree from a string.
Definition: util-radix6-tree.c:262
HTTP_SWF_COMPRESSION_LZMA
@ HTTP_SWF_COMPRESSION_LZMA
Definition: app-layer-htp.h:91
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
util-random.h
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:226
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2613
AppLayerParserStateAlloc
AppLayerParserState * AppLayerParserStateAlloc(void)
Definition: app-layer-parser.c:235
SCHttpRangeFreeBlock
void SCHttpRangeFreeBlock(HttpRangeContainerBlock *b)
Definition: app-layer-htp-range.c:605
HtpState_::request_frame_id
FrameId request_frame_id
Definition: app-layer-htp.h:198
app-layer-protos.h
app-layer-htp-mem.h
EngineModeIsIPS
int EngineModeIsIPS(void)
Definition: suricata.c:246
HTP_BODY_REQUEST_MULTIPART
@ HTP_BODY_REQUEST_MULTIPART
Definition: app-layer-htp.h:71
suricata.h
HTPMalloc
void * HTPMalloc(size_t size)
Definition: app-layer-htp-mem.c:132
AppLayerParserRegisterGetTxCnt
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
Definition: app-layer-parser.c:524
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:61
SCConfNode_::name
char * name
Definition: conf.h:38
AppLayerTxData::events
AppLayerDecoderEvents * events
Definition: app-layer-parser.h:204
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:567
SCRadix6TreeRelease
void SCRadix6TreeRelease(SCRadix6Tree *tree, const SCRadix6Config *config)
Definition: util-radix6-tree.c:366
SC_RADIX6_TREE_INITIALIZER
#define SC_RADIX6_TREE_INITIALIZER
Definition: util-radix6-tree.h:76
likely
#define likely(expr)
Definition: util-optimize.h:32
HTPFileClose
int HTPFileClose(HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, uint8_t flags, uint8_t direction)
Close the file in the flow.
Definition: app-layer-htp-file.c:279
HtpTxUserData_::files_ts
FileContainer files_ts
Definition: app-layer-htp.h:179
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:968
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:1599
HtpTxUserData_::response_headers_raw_len
uint32_t response_headers_raw_len
Definition: app-layer-htp.h:172
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:443
HtpTxUserData_::request_body_init
uint8_t request_body_init
Definition: app-layer-htp.h:155
HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE
#define HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE
Definition: app-layer-htp.h:59
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
ThreadVars_::stats
StatsThreadContext stats
Definition: threadvars.h:121
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:288
SCConfNode_
Definition: conf.h:37
HTPFileOpenWithRange
int HTPFileOpenWithRange(HtpState *s, HtpTxUserData *txud, const uint8_t *filename, uint16_t filename_len, const uint8_t *data, uint32_t data_len, const htp_tx_t *tx, const bstr *rawvalue, HtpTxUserData *htud)
Sets range for a file.
Definition: app-layer-htp-file.c:149
http_frame_table
SCEnumCharMap http_frame_table[]
Definition: app-layer-htp.c:227
StatsThreadCleanup
void StatsThreadCleanup(StatsThreadContext *stats)
Definition: counters.c:1427
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:206
AppLayerStateData::file_flags
uint16_t file_flags
Definition: app-layer-parser.h:146
StreamingBufferConfig_::Realloc
void *(* Realloc)(void *ptr, size_t orig_size, size_t size)
Definition: util-streaming-buffer.h:70
HtpTxUserData_::tsflags
uint8_t tsflags
Definition: app-layer-htp.h:161
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1291
AppLayerGetTxIterState::un
union AppLayerGetTxIterState::@7 un
HtpBody_::body_inspected
uint64_t body_inspected
Definition: app-layer-htp.h:142
AppLayerProtoDetectGetProtoName
const char * AppLayerProtoDetectGetProtoName(AppProto alproto)
Definition: app-layer-detect-proto.c:2124
SC_ATOMIC_OR
#define SC_ATOMIC_OR(name, val)
Bitwise OR a value to our atomic variable.
Definition: util-atomic.h:350
AppLayerTxData::file_tx
uint8_t file_tx
Definition: app-layer-parser.h:189
AppLayerTxData::updated_ts
bool updated_ts
Definition: app-layer-parser.h:170
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