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