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