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