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