]> git.ipfire.org Git - people/ms/suricata.git/blame - src/app-layer-htp.c
stream: init global config after flow engine
[people/ms/suricata.git] / src / app-layer-htp.c
CommitLineData
5532af46 1/* Copyright (C) 2007-2013 Open Information Security Foundation
ce019275
WM
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 */
07f7ba55 17
60a99915
EL
18/**
19 * \ingroup httplayer
20 *
21 * @{
22 */
23
07f7ba55 24/**
ce019275 25 * \file
07f7ba55 26 *
9d5d46c4 27 * \author Victor Julien <victor@inliniac.net>
07f7ba55 28 * \author Gurvinder Singh <gurvindersinghdahiya@gmail.com>
0165b3f0 29 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
a9cdd2bb 30 * \author Brian Rectanus <brectanu@gmail.com>
5e2d9dbd 31 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
07f7ba55 32 *
ce019275 33 * This file provides a HTTP protocol support for the engine using HTP library.
07f7ba55
GS
34 */
35
5c6a65dc 36#include "suricata.h"
ecf86f9c 37#include "suricata-common.h"
07f7ba55
GS
38#include "debug.h"
39#include "decode.h"
40#include "threads.h"
07f7ba55
GS
41
42#include "util-print.h"
43#include "util-pool.h"
a9cdd2bb 44#include "util-radix-tree.h"
e1022ee5 45#include "util-file.h"
07f7ba55
GS
46
47#include "stream-tcp-private.h"
48#include "stream-tcp-reassemble.h"
6a53ab9c 49#include "stream-tcp.h"
07f7ba55
GS
50#include "stream.h"
51
52#include "app-layer-protos.h"
53#include "app-layer-parser.h"
a0ee6ade 54
429c6388 55#include "app-layer.h"
fc2f7f29 56#include "app-layer-htp.h"
a0ee6ade
VJ
57#include "app-layer-htp-body.h"
58#include "app-layer-htp-file.h"
48cf0585 59#include "app-layer-htp-libhtp.h"
07f7ba55 60
705471e4 61#include "util-spm.h"
07f7ba55 62#include "util-debug.h"
fc2f7f29 63#include "util-time.h"
e0c13434 64#include "util-misc.h"
07f7ba55 65
06a65cb4
PR
66#include "util-unittest.h"
67#include "util-unittest-helper.h"
68#include "flow-util.h"
69
70#include "detect-engine.h"
71#include "detect-engine-state.h"
72#include "detect-parse.h"
73
5e2d9dbd 74#include "decode-events.h"
a9cdd2bb
BR
75#include "conf.h"
76
4537f889
VJ
77#include "util-memcmp.h"
78
6d225378
EL
79#ifndef HAVE_HTP_SET_PATH_DECODE_U_ENCODING
80void htp_config_set_path_decode_u_encoding(htp_cfg_t *cfg, int decode_u_encoding);
81#endif
82
32fb9f37
VJ
83//#define PRINT
84
ead13bda 85/** Fast lookup tree (radix) for the various HTP configurations */
a9cdd2bb 86static SCRadixTree *cfgtree;
ead13bda 87/** List of HTP configurations. */
a9cdd2bb
BR
88static HTPCfgRec cfglist;
89
07f7ba55 90#ifdef DEBUG
5532af46 91static SCMutex htp_state_mem_lock = SCMUTEX_INITIALIZER;
07f7ba55
GS
92static uint64_t htp_state_memuse = 0;
93static uint64_t htp_state_memcnt = 0;
94#endif
97d49d8f 95
f713b653
VJ
96SCEnumCharMap http_decoder_event_table[ ] = {
97 { "UNKNOWN_ERROR",
98 HTTP_DECODER_EVENT_UNKNOWN_ERROR},
99 { "GZIP_DECOMPRESSION_FAILED",
100 HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED},
101 { "REQUEST_FIELD_MISSING_COLON",
102 HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON},
93d121bf
VJ
103 { "RESPONSE_FIELD_MISSING_COLON",
104 HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON},
f713b653
VJ
105 { "INVALID_REQUEST_CHUNK_LEN",
106 HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN},
107 { "INVALID_RESPONSE_CHUNK_LEN",
108 HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN},
109 { "INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST",
110 HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST},
111 { "INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE",
112 HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE},
113 { "INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST",
114 HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST},
115 { "INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE",
116 HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE},
117 { "100_CONTINUE_ALREADY_SEEN",
118 HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN},
119 { "UNABLE_TO_MATCH_RESPONSE_TO_REQUEST",
120 HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST},
121 { "INVALID_SERVER_PORT_IN_REQUEST",
122 HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST},
123 { "INVALID_AUTHORITY_PORT",
124 HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT},
93d121bf 125 { "REQUEST_HEADER_INVALID",
f713b653 126 HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID},
93d121bf
VJ
127 { "RESPONSE_HEADER_INVALID",
128 HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID},
f713b653
VJ
129 { "MISSING_HOST_HEADER",
130 HTTP_DECODER_EVENT_MISSING_HOST_HEADER},
131 { "HOST_HEADER_AMBIGUOUS",
132 HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS},
133 { "INVALID_REQUEST_FIELD_FOLDING",
134 HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING},
135 { "INVALID_RESPONSE_FIELD_FOLDING",
136 HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING},
137 { "REQUEST_FIELD_TOO_LONG",
138 HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG},
139 { "RESPONSE_FIELD_TOO_LONG",
140 HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG},
9f519e95
VJ
141 { "REQUEST_SERVER_PORT_TCP_PORT_MISMATCH",
142 HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH},
cb150003
VJ
143 { "REQUEST_URI_HOST_INVALID",
144 HTTP_DECODER_EVENT_URI_HOST_INVALID},
145 { "REQUEST_HEADER_HOST_INVALID",
146 HTTP_DECODER_EVENT_HEADER_HOST_INVALID},
147
e21d8cdf
VJ
148 /* suricata warnings/errors */
149 { "MULTIPART_GENERIC_ERROR",
150 HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR},
151 { "MULTIPART_NO_FILEDATA",
152 HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA},
153 { "MULTIPART_INVALID_HEADER",
154 HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER},
155
f713b653
VJ
156 { NULL, -1 },
157};
158
d4d18e31
AS
159static void *HTPStateGetTx(void *alstate, uint64_t tx_id);
160static int HTPStateGetAlstateProgress(void *tx, uint8_t direction);
161static uint64_t HTPStateGetTxCnt(void *alstate);
162static int HTPStateGetAlstateProgressCompletionStatus(uint8_t direction);
163
9a58a025 164#ifdef DEBUG
a9cdd2bb
BR
165/**
166 * \internal
167 *
168 * \brief Lookup the HTP personality string from the numeric personality.
169 *
170 * \todo This needs to be a libhtp function.
171 */
172static const char *HTPLookupPersonalityString(int p)
173{
174#define CASE_HTP_PERSONALITY_STRING(p) \
175 case HTP_SERVER_ ## p: return #p
176
177 switch (p) {
178 CASE_HTP_PERSONALITY_STRING(MINIMAL);
179 CASE_HTP_PERSONALITY_STRING(GENERIC);
180 CASE_HTP_PERSONALITY_STRING(IDS);
181 CASE_HTP_PERSONALITY_STRING(IIS_4_0);
182 CASE_HTP_PERSONALITY_STRING(IIS_5_0);
183 CASE_HTP_PERSONALITY_STRING(IIS_5_1);
184 CASE_HTP_PERSONALITY_STRING(IIS_6_0);
185 CASE_HTP_PERSONALITY_STRING(IIS_7_0);
186 CASE_HTP_PERSONALITY_STRING(IIS_7_5);
48cf0585 187 CASE_HTP_PERSONALITY_STRING(APACHE_2);
a9cdd2bb
BR
188 }
189
190 return NULL;
191}
9a58a025 192#endif /* DEBUG */
a9cdd2bb
BR
193
194/**
195 * \internal
196 *
197 * \brief Lookup the numeric HTP personality from a string.
198 *
199 * \todo This needs to be a libhtp function.
200 */
201static int HTPLookupPersonality(const char *str)
202{
203#define IF_HTP_PERSONALITY_NUM(p) \
204 if (strcasecmp(#p, str) == 0) return HTP_SERVER_ ## p
205
206 IF_HTP_PERSONALITY_NUM(MINIMAL);
207 IF_HTP_PERSONALITY_NUM(GENERIC);
208 IF_HTP_PERSONALITY_NUM(IDS);
209 IF_HTP_PERSONALITY_NUM(IIS_4_0);
210 IF_HTP_PERSONALITY_NUM(IIS_5_0);
211 IF_HTP_PERSONALITY_NUM(IIS_5_1);
212 IF_HTP_PERSONALITY_NUM(IIS_6_0);
213 IF_HTP_PERSONALITY_NUM(IIS_7_0);
214 IF_HTP_PERSONALITY_NUM(IIS_7_5);
48cf0585 215 IF_HTP_PERSONALITY_NUM(APACHE_2);
51c2e1ea 216 if (strcasecmp("TOMCAT_6_0", str) == 0) {
48cf0585
AS
217 SCLogError(SC_WARN_OPTION_OBSOLETE, "Personality %s no "
218 "longer supported by libhtp.", str);
219 return -1;
51c2e1ea
VJ
220 } else if ((strcasecmp("APACHE", str) == 0) ||
221 (strcasecmp("APACHE_2_2", str) == 0))
222 {
223 SCLogWarning(SC_WARN_OPTION_OBSOLETE, "Personality %s no "
224 "longer supported by libhtp, failing back to "
225 "Apache2 personality.", str);
226 return HTP_SERVER_APACHE_2;
48cf0585 227 }
a9cdd2bb
BR
228
229 return -1;
230}
231
3f5acc54
VJ
232void HTPSetEvent(HtpState *s, HtpTxUserData *htud, uint8_t e)
233{
234 SCLogDebug("setting event %u", e);
235
236 if (htud) {
237 AppLayerDecoderEventsSetEventRaw(&htud->decoder_events, e);
238 s->events++;
239 return;
240 }
241
242 htp_tx_t *tx = HTPStateGetTx(s, s->transaction_cnt);
243 if (tx != NULL) {
244 htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
245 if (htud != NULL) {
246 AppLayerDecoderEventsSetEventRaw(&htud->decoder_events, e);
247 s->events++;
248 return;
249 }
250 }
251 SCLogDebug("couldn't set event %u", e);
252}
253
8f1d7503
KS
254static int HTPHasEvents(void *state)
255{
3f5acc54
VJ
256 HtpState *htp_state = (HtpState *)state;
257 return (htp_state->events > 0);
258}
259
260static AppLayerDecoderEvents *HTPGetEvents(void *state, uint64_t tx_id)
261{
262 SCLogDebug("get HTTP events for TX %"PRIu64, tx_id);
263
264 HtpState *s = (HtpState *)state;
265 htp_tx_t *tx = HTPStateGetTx(s, tx_id);
266 if (tx != NULL) {
267 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
268 if (htud != NULL) {
269 SCLogDebug("has htud, htud->decoder_events %p", htud->decoder_events);
270 return htud->decoder_events;
271 }
272 }
273 return NULL;
274}
275
07f7ba55
GS
276/** \brief Function to allocates the HTTP state memory and also creates the HTTP
277 * connection parser to be used by the HTP library
278 */
279static void *HTPStateAlloc(void)
280{
48248687
VJ
281 SCEnter();
282
ced01da8 283 HtpState *s = HTPMalloc(sizeof(HtpState));
e176be6f 284 if (unlikely(s == NULL))
48248687 285 goto error;
07f7ba55 286
48248687 287 memset(s, 0x00, sizeof(HtpState));
07f7ba55 288
187949b9
VJ
289#ifdef DEBUG
290 SCMutexLock(&htp_state_mem_lock);
291 htp_state_memcnt++;
292 htp_state_memuse += sizeof(HtpState);
6fca55e0 293 SCLogDebug("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
187949b9
VJ
294 SCMutexUnlock(&htp_state_mem_lock);
295#endif
70b32f73 296
48248687
VJ
297 SCReturnPtr((void *)s, "void");
298
299error:
187949b9 300 if (s != NULL) {
ced01da8 301 HTPFree(s, sizeof(HtpState));
187949b9 302 }
48248687
VJ
303
304 SCReturnPtr(NULL, "void");
07f7ba55
GS
305}
306
8f1d7503
KS
307static void HtpTxUserDataFree(HtpTxUserData *htud)
308{
6f2cb141
VJ
309 if (htud) {
310 HtpBodyFree(&htud->request_body);
311 HtpBodyFree(&htud->response_body);
312 bstr_free(htud->request_uri_normalized);
313 if (htud->request_headers_raw)
ced01da8 314 HTPFree(htud->request_headers_raw, htud->request_headers_raw_len);
6f2cb141 315 if (htud->response_headers_raw)
ced01da8 316 HTPFree(htud->response_headers_raw, htud->response_headers_raw_len);
3f5acc54 317 AppLayerDecoderEventsFreeEvents(&htud->decoder_events);
6f2cb141 318 if (htud->boundary)
ced01da8
EL
319 HTPFree(htud->boundary, htud->boundary_len);
320 HTPFree(htud, sizeof(HtpTxUserData));
6f2cb141
VJ
321 }
322}
323
07f7ba55
GS
324/** \brief Function to frees the HTTP state memory and also frees the HTTP
325 * connection parser memory which was used by the HTP library
326 */
25a3a5c6 327void HTPStateFree(void *state)
07f7ba55 328{
48248687
VJ
329 SCEnter();
330
331 HtpState *s = (HtpState *)state;
a56592e5
GIG
332 if (s == NULL) {
333 SCReturn;
334 }
48248687 335
06a65cb4
PR
336 /* Unset the body inspection */
337 s->flags &=~ HTP_FLAG_NEW_BODY_SET;
338
07f7ba55 339 /* free the connection parser memory used by HTP library */
a56592e5 340 if (s->connp != NULL) {
6fca55e0
VJ
341 SCLogDebug("freeing HTP state");
342
d4d18e31
AS
343 uint64_t tx_id;
344 uint64_t total_txs = HTPStateGetTxCnt(state);
bc55fb27 345 /* free the list of body chunks */
48cf0585 346 if (s->conn != NULL) {
d4d18e31
AS
347 for (tx_id = 0; tx_id < total_txs; tx_id++) {
348 htp_tx_t *tx = HTPStateGetTx(s, tx_id);
bc55fb27 349 if (tx != NULL) {
66a3cd96 350 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
bc55fb27 351 if (htud != NULL) {
6f2cb141 352 HtpTxUserDataFree(htud);
b402d971 353 htp_tx_set_user_data(tx, NULL);
06a65cb4
PR
354 }
355 }
356 }
48248687 357 }
bc55fb27 358 htp_connp_destroy_all(s->connp);
48248687 359 }
07f7ba55 360
d59ca75e
VJ
361 FileContainerFree(s->files_ts);
362 FileContainerFree(s->files_tc);
ced01da8 363 HTPFree(s, sizeof(HtpState));
48248687 364
07f7ba55 365#ifdef DEBUG
e26833be 366 SCMutexLock(&htp_state_mem_lock);
07f7ba55 367 htp_state_memcnt--;
187949b9 368 htp_state_memuse -= sizeof(HtpState);
6fca55e0 369 SCLogDebug("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
e26833be 370 SCMutexUnlock(&htp_state_mem_lock);
07f7ba55 371#endif
48248687
VJ
372
373 SCReturn;
07f7ba55
GS
374}
375
70b32f73
VJ
376/**
377 * \brief HTP transaction cleanup callback
378 *
379 * \warning We cannot actually free the transactions here. It seems that
380 * HTP only accepts freeing of transactions in the response callback.
381 */
8f1d7503
KS
382static void HTPStateTransactionFree(void *state, uint64_t id)
383{
70b32f73
VJ
384 SCEnter();
385
386 HtpState *s = (HtpState *)state;
387
f59f9033 388 SCLogDebug("state %p, id %"PRIu64, s, id);
70b32f73 389
0fd9b0c4
VJ
390 htp_tx_t *tx = HTPStateGetTx(s, id);
391 if (tx != NULL) {
392 /* This will remove obsolete body chunks */
393 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
394 if (htud != NULL) {
6f2cb141 395 HtpTxUserDataFree(htud);
0fd9b0c4
VJ
396 htp_tx_set_user_data(tx, NULL);
397 }
70b32f73 398
0fd9b0c4
VJ
399 htp_tx_destroy(tx);
400 }
70b32f73
VJ
401}
402
97d49d8f
AS
403/**
404 * \brief Sets a flag that informs the HTP app layer that some module in the
405 * engine needs the http request body data.
bc55fb27 406 * \initonly
97d49d8f
AS
407 */
408void AppLayerHtpEnableRequestBodyCallback(void)
409{
70b32f73 410 SCEnter();
92679442
EL
411
412 SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_BODY);
70b32f73 413 SCReturn;
97d49d8f
AS
414}
415
b402d971
VJ
416/**
417 * \brief Sets a flag that informs the HTP app layer that some module in the
418 * engine needs the http request body data.
419 * \initonly
420 */
421void AppLayerHtpEnableResponseBodyCallback(void)
422{
423 SCEnter();
92679442
EL
424
425 SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_RESPONSE_BODY);
b402d971
VJ
426 SCReturn;
427}
428
6d60b3a7
PR
429/**
430 * \brief Sets a flag that informs the HTP app layer that some module in the
ef053679
VJ
431 * engine needs the http request multi part header.
432 *
6d60b3a7
PR
433 * \initonly
434 */
8f1d7503
KS
435void AppLayerHtpNeedMultipartHeader(void)
436{
6d60b3a7 437 SCEnter();
ef053679
VJ
438 AppLayerHtpEnableRequestBodyCallback();
439
92679442 440 SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_MULTIPART);
21acd72a
VJ
441 SCReturn;
442}
443
ef053679
VJ
444/**
445 * \brief Sets a flag that informs the HTP app layer that some module in the
446 * engine needs the http request file.
447 *
448 * \initonly
449 */
450void AppLayerHtpNeedFileInspection(void)
451{
21acd72a 452 SCEnter();
ef053679 453 AppLayerHtpNeedMultipartHeader();
b402d971
VJ
454 AppLayerHtpEnableRequestBodyCallback();
455 AppLayerHtpEnableResponseBodyCallback();
ef053679 456
92679442 457 SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_FILE);
6d60b3a7
PR
458 SCReturn;
459}
460
43b39d33 461/* below error messages updated up to libhtp 0.5.7 (git 379632278b38b9a792183694a4febb9e0dbd1e7a) */
f713b653
VJ
462struct {
463 char *msg;
464 int de;
465} htp_errors[] = {
466 { "GZip decompressor: inflateInit2 failed", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED},
467 { "Request field invalid: colon missing", HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON},
43b39d33 468 { "Response field invalid: missing colon", HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON},
f713b653
VJ
469 { "Request chunk encoding: Invalid chunk length", HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN},
470 { "Response chunk encoding: Invalid chunk length", HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN},
43b39d33
VJ
471/* { "Invalid T-E value in request", HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST}, <- tx flag HTP_REQUEST_INVALID_T_E
472 { "Invalid T-E value in response", HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE}, <- nothing to replace it */
473/* { "Invalid C-L field in request", HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST}, <- tx flag HTP_REQUEST_INVALID_C_L */
f713b653
VJ
474 { "Invalid C-L field in response", HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE},
475 { "Already seen 100-Continue", HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN},
476 { "Unable to match response to request", HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST},
477 { "Invalid server port information in request", HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST},
43b39d33 478/* { "Invalid authority port", HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT}, htp no longer returns this error */
63679175
VJ
479 { "Request buffer over", HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG},
480 { "Response buffer over", HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG},
f713b653
VJ
481};
482
483struct {
484 char *msg;
485 int de;
486} htp_warnings[] = {
487 { "GZip decompressor:", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED},
488 { "Request field invalid", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID},
93d121bf 489 { "Response field invalid", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID},
f713b653 490 { "Request header name is not a token", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID},
93d121bf 491 { "Response header name is not a token", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID},
43b39d33
VJ
492/* { "Host information in request headers required by HTTP/1.1", HTTP_DECODER_EVENT_MISSING_HOST_HEADER}, <- tx flag HTP_HOST_MISSING
493 { "Host information ambiguous", HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS}, <- tx flag HTP_HOST_AMBIGUOUS */
f713b653
VJ
494 { "Invalid request field folding", HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING},
495 { "Invalid response field folding", HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING},
43b39d33
VJ
496 /* line is now: htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request server port=%d number differs from the actual TCP port=%d", port, connp->conn->server_port);
497 * luckily, "Request server port=" is unique */
498/* { "Request server port number differs from the actual TCP port", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, */
499 { "Request server port=", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH},
f713b653
VJ
500};
501
502#define HTP_ERROR_MAX (sizeof(htp_errors) / sizeof(htp_errors[0]))
503#define HTP_WARNING_MAX (sizeof(htp_warnings) / sizeof(htp_warnings[0]))
504
505/**
506 * \internal
507 *
508 * \brief Get the warning id for the warning msg.
509 *
510 * \param msg warning message
511 *
512 * \retval id the id or 0 in case of not found
513 */
8f1d7503
KS
514static int HTPHandleWarningGetId(const char *msg)
515{
00948c86 516 SCLogDebug("received warning \"%s\"", msg);
f713b653
VJ
517 size_t idx;
518 for (idx = 0; idx < HTP_WARNING_MAX; idx++) {
519 if (strncmp(htp_warnings[idx].msg, msg,
520 strlen(htp_warnings[idx].msg)) == 0)
521 {
522 return htp_warnings[idx].de;
523 }
524 }
525
526 return 0;
527}
528
529/**
530 * \internal
531 *
532 * \brief Get the error id for the error msg.
533 *
534 * \param msg error message
535 *
536 * \retval id the id or 0 in case of not found
537 */
8f1d7503
KS
538static int HTPHandleErrorGetId(const char *msg)
539{
00948c86
VJ
540 SCLogDebug("received error \"%s\"", msg);
541
f713b653
VJ
542 size_t idx;
543 for (idx = 0; idx < HTP_ERROR_MAX; idx++) {
544 if (strncmp(htp_errors[idx].msg, msg,
545 strlen(htp_errors[idx].msg)) == 0)
546 {
547 return htp_errors[idx].de;
548 }
549 }
550
551 return 0;
552}
553
554/**
555 * \internal
556 *
557 * \brief Check state for errors, warnings and add any as events
558 *
559 * \param s state
560 */
8f1d7503
KS
561static void HTPHandleError(HtpState *s)
562{
48cf0585
AS
563 if (s == NULL || s->conn == NULL ||
564 s->conn->messages == NULL) {
f713b653
VJ
565 return;
566 }
567
48cf0585 568 size_t size = htp_list_size(s->conn->messages);
f713b653
VJ
569 size_t msg;
570
3f5acc54 571 for (msg = s->htp_messages_offset; msg < size; msg++) {
48cf0585 572 htp_log_t *log = htp_list_get(s->conn->messages, msg);
f713b653
VJ
573 if (log == NULL)
574 continue;
575
3f5acc54
VJ
576 HtpTxUserData *htud = NULL;
577 htp_tx_t *tx = log->tx; // will be NULL in <=0.5.9
578 if (tx != NULL)
579 htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
580
43544345
VJ
581 SCLogDebug("message %s", log->msg);
582
f713b653 583 int id = HTPHandleErrorGetId(log->msg);
3f5acc54 584 if (id == 0) {
f713b653 585 id = HTPHandleWarningGetId(log->msg);
3f5acc54
VJ
586 if (id == 0)
587 id = HTTP_DECODER_EVENT_UNKNOWN_ERROR;
f713b653 588 }
f713b653 589
f713b653 590 if (id > 0) {
3f5acc54 591 HTPSetEvent(s, htud, id);
f713b653
VJ
592 }
593 }
3f5acc54
VJ
594 s->htp_messages_offset = (uint16_t)msg;
595 SCLogDebug("s->htp_messages_offset %u", s->htp_messages_offset);
f713b653 596}
97d49d8f 597
43b39d33
VJ
598static inline void HTPErrorCheckTxRequestFlags(HtpState *s, htp_tx_t *tx)
599{
600#ifdef DEBUG
601 BUG_ON(s == NULL || tx == NULL);
602#endif
603 if (tx->flags & ( HTP_REQUEST_INVALID_T_E|HTP_REQUEST_INVALID_C_L|
cb150003
VJ
604 HTP_HOST_MISSING|HTP_HOST_AMBIGUOUS|HTP_HOSTU_INVALID|
605 HTP_HOSTH_INVALID))
43b39d33 606 {
3f5acc54
VJ
607 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
608 if (htud == NULL)
609 return;
610
43b39d33 611 if (tx->flags & HTP_REQUEST_INVALID_T_E)
3f5acc54 612 HTPSetEvent(s, htud,
43b39d33
VJ
613 HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST);
614 if (tx->flags & HTP_REQUEST_INVALID_C_L)
3f5acc54 615 HTPSetEvent(s, htud,
43b39d33
VJ
616 HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST);
617 if (tx->flags & HTP_HOST_MISSING)
3f5acc54 618 HTPSetEvent(s, htud,
43b39d33
VJ
619 HTTP_DECODER_EVENT_MISSING_HOST_HEADER);
620 if (tx->flags & HTP_HOST_AMBIGUOUS)
3f5acc54 621 HTPSetEvent(s, htud,
43b39d33 622 HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS);
cb150003 623 if (tx->flags & HTP_HOSTU_INVALID)
3f5acc54 624 HTPSetEvent(s, htud,
cb150003
VJ
625 HTTP_DECODER_EVENT_URI_HOST_INVALID);
626 if (tx->flags & HTP_HOSTH_INVALID)
3f5acc54 627 HTPSetEvent(s, htud,
cb150003 628 HTTP_DECODER_EVENT_HEADER_HOST_INVALID);
43b39d33
VJ
629 }
630}
631
07f7ba55
GS
632/**
633 * \brief Function to handle the reassembled data from client and feed it to
634 * the HTP library to process it.
635 *
92d74fd4 636 * \param flow Pointer to the flow the data belong to
07f7ba55
GS
637 * \param htp_state Pointer the state in which the parsed value to be stored
638 * \param pstate Application layer parser state for this session
639 * \param input Pointer the received HTTP client data
640 * \param input_len Length in bytes of the received data
641 * \param output Pointer to the output (not used in this function)
642 *
48cf0585 643 * \retval On success returns 1 or on failure returns -1.
07f7ba55 644 */
fc2f7f29 645static int HTPHandleRequestData(Flow *f, void *htp_state,
9634e60e 646 AppLayerParserState *pstate,
07f7ba55 647 uint8_t *input, uint32_t input_len,
429c6388 648 void *local_data)
07f7ba55 649{
1b39e602 650 SCEnter();
0a85fd67
GS
651 int r = -1;
652 int ret = 1;
70b32f73 653
b8fec77f
VJ
654 //PrintRawDataFp(stdout, input, input_len);
655
07f7ba55 656 HtpState *hstate = (HtpState *)htp_state;
6d60b3a7 657 hstate->f = f;
a9cdd2bb
BR
658
659 /* On the first invocation, create the connection parser structure to
660 * be used by HTP library. This is looked up via IP in the radix
661 * tree. Failing that, the default HTP config is used.
662 */
48cf0585 663 if (NULL == hstate->conn) {
2763a612 664 HTPCfgRec *htp_cfg_rec = &cfglist;
ead13bda 665 htp_cfg_t *htp = cfglist.cfg; /* Default to the global HTP config */
d0a26c6a 666 void *user_data = NULL;
ead13bda 667
262a7300 668 if (FLOW_IS_IPV4(f)) {
a9cdd2bb 669 SCLogDebug("Looking up HTP config for ipv4 %08x", *GET_IPV4_DST_ADDR_PTR(f));
d0a26c6a 670 (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)GET_IPV4_DST_ADDR_PTR(f), cfgtree, &user_data);
a9cdd2bb 671 }
262a7300 672 else if (FLOW_IS_IPV6(f)) {
a9cdd2bb 673 SCLogDebug("Looking up HTP config for ipv6");
d0a26c6a 674 (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)GET_IPV6_DST_ADDR(f), cfgtree, &user_data);
a9cdd2bb 675 }
78e15ea7
VJ
676 else {
677 SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown address family, bug!");
678 goto error;
679 }
680
d0a26c6a
VJ
681 if (user_data != NULL) {
682 htp_cfg_rec = user_data;
683 htp = htp_cfg_rec->cfg;
684 SCLogDebug("LIBHTP using config: %p", htp);
a9cdd2bb
BR
685 } else {
686 SCLogDebug("Using default HTP config: %p", htp);
687 }
688
689 if (NULL == htp) {
4129146a 690 BUG_ON(htp == NULL);
ead13bda 691 /* should never happen if HTPConfigure is properly invoked */
a9cdd2bb
BR
692 goto error;
693 }
694
695 hstate->connp = htp_connp_create(htp);
696 if (hstate->connp == NULL) {
697 goto error;
698 }
699
48cf0585
AS
700 hstate->conn = htp_connp_get_connection(hstate->connp);
701
a9cdd2bb 702 htp_connp_set_user_data(hstate->connp, (void *)hstate);
2763a612 703 hstate->cfg = htp_cfg_rec;
a9cdd2bb
BR
704
705 SCLogDebug("New hstate->connp %p", hstate->connp);
706 }
07f7ba55 707
4129146a
VJ
708 /* the code block above should make sure connp is never NULL here */
709 BUG_ON(hstate->connp == NULL);
710
0165b3f0
PR
711 /* Unset the body inspection (the callback should
712 * reactivate it if necessary) */
70b32f73 713 hstate->flags &=~ HTP_FLAG_NEW_BODY_SET;
0165b3f0 714
fc2f7f29 715 /* Open the HTTP connection on receiving the first request */
ba7e8012 716 if (!(hstate->flags & HTP_FLAG_STATE_OPEN)) {
48248687 717 SCLogDebug("opening htp handle at %p", hstate->connp);
ba7e8012 718
080c15b3 719 htp_connp_open(hstate->connp, NULL, f->sp, NULL, f->dp, &f->startts);
fc2f7f29 720 hstate->flags |= HTP_FLAG_STATE_OPEN;
ba7e8012 721 } else {
48248687 722 SCLogDebug("using existing htp handle at %p", hstate->connp);
fc2f7f29 723 }
07f7ba55 724
7acea2c6 725 htp_time_t ts = { f->lastts.tv_sec, f->lastts.tv_usec };
70b32f73 726 /* pass the new data to the htp parser */
080c15b3 727 r = htp_connp_req_data(hstate->connp, &ts, input, input_len);
148883ce 728
bf236e45 729 switch(r) {
48cf0585 730 case HTP_STREAM_ERROR:
f713b653 731
bf236e45
GS
732 hstate->flags |= HTP_FLAG_STATE_ERROR;
733 hstate->flags &= ~HTP_FLAG_STATE_DATA;
50f7d0a8 734 hstate->flags &= ~HTP_FLAG_NEW_BODY_SET;
bf236e45
GS
735 ret = -1;
736 break;
48cf0585
AS
737 case HTP_STREAM_DATA:
738 case HTP_STREAM_DATA_OTHER:
f713b653 739
004b5dde 740 hstate->flags |= HTP_FLAG_STATE_DATA;
bf236e45 741 break;
48cf0585
AS
742 case HTP_STREAM_TUNNEL:
743 break;
bf236e45
GS
744 default:
745 hstate->flags &= ~HTP_FLAG_STATE_DATA;
50f7d0a8 746 hstate->flags &= ~HTP_FLAG_NEW_BODY_SET;
70b32f73 747 }
9e4eec20 748 HTPHandleError(hstate);
07f7ba55 749
a9cdd2bb 750 /* if the TCP connection is closed, then close the HTTP connection */
8527b8e0 751 if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF) &&
429c6388
AS
752 !(hstate->flags & HTP_FLAG_STATE_CLOSED_TS))
753 {
48cf0585 754 htp_connp_close(hstate->connp, &ts);
64625675
AS
755 hstate->flags |= HTP_FLAG_STATE_CLOSED_TS;
756 SCLogDebug("stream eof encountered, closing htp handle for ts");
fc2f7f29
GS
757 }
758
48248687 759 SCLogDebug("hstate->connp %p", hstate->connp);
0a85fd67 760 SCReturnInt(ret);
a9cdd2bb
BR
761
762error:
763 SCReturnInt(-1);
07f7ba55
GS
764}
765
766/**
767 * \brief Function to handle the reassembled data from server and feed it to
768 * the HTP library to process it.
769 *
92d74fd4 770 * \param flow Pointer to the flow the data belong to
07f7ba55
GS
771 * \param htp_state Pointer the state in which the parsed value to be stored
772 * \param pstate Application layer parser state for this session
773 * \param input Pointer the received HTTP server data
774 * \param input_len Length in bytes of the received data
775 * \param output Pointer to the output (not used in this function)
776 *
2d6cf71d 777 * \retval On success returns 1 or on failure returns -1
07f7ba55 778 */
fc2f7f29 779static int HTPHandleResponseData(Flow *f, void *htp_state,
9634e60e 780 AppLayerParserState *pstate,
429c6388
AS
781 uint8_t *input, uint32_t input_len,
782 void *local_data)
07f7ba55 783{
1b39e602 784 SCEnter();
0a85fd67
GS
785 int r = -1;
786 int ret = 1;
787
07f7ba55 788 HtpState *hstate = (HtpState *)htp_state;
6d60b3a7 789 hstate->f = f;
4129146a 790 if (hstate->connp == NULL) {
eff85aba 791 SCLogDebug("HTP state has no connp");
1ea5d275
AS
792 /* till we have the new libhtp changes that allow response first,
793 * let's take response in first. */
eff85aba
VJ
794 //BUG_ON(1);
795 SCReturnInt(-1);
4129146a 796 }
07f7ba55 797
0165b3f0
PR
798 /* Unset the body inspection (the callback should
799 * reactivate it if necessary) */
70b32f73 800 hstate->flags &=~ HTP_FLAG_NEW_BODY_SET;
0165b3f0 801
7acea2c6 802 htp_time_t ts = { f->lastts.tv_sec, f->lastts.tv_usec };
080c15b3 803 r = htp_connp_res_data(hstate->connp, &ts, input, input_len);
bf236e45 804 switch(r) {
48cf0585 805 case HTP_STREAM_ERROR:
bf236e45
GS
806 hstate->flags = HTP_FLAG_STATE_ERROR;
807 hstate->flags &= ~HTP_FLAG_STATE_DATA;
50f7d0a8 808 hstate->flags &= ~HTP_FLAG_NEW_BODY_SET;
bf236e45
GS
809 ret = -1;
810 break;
48cf0585
AS
811 case HTP_STREAM_DATA:
812 case HTP_STREAM_DATA_OTHER:
004b5dde 813 hstate->flags |= HTP_FLAG_STATE_DATA;
bf236e45 814 break;
48cf0585
AS
815 case HTP_STREAM_TUNNEL:
816 break;
bf236e45
GS
817 default:
818 hstate->flags &= ~HTP_FLAG_STATE_DATA;
50f7d0a8 819 hstate->flags &= ~HTP_FLAG_NEW_BODY_SET;
bf236e45 820 }
3f5acc54 821 HTPHandleError(hstate);
07f7ba55 822
fc2f7f29 823 /* if we the TCP connection is closed, then close the HTTP connection */
8527b8e0 824 if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF) &&
429c6388
AS
825 !(hstate->flags & HTP_FLAG_STATE_CLOSED_TC))
826 {
48cf0585 827 htp_connp_close(hstate->connp, &ts);
64625675 828 hstate->flags |= HTP_FLAG_STATE_CLOSED_TC;
fc2f7f29
GS
829 }
830
48248687 831 SCLogDebug("hstate->connp %p", hstate->connp);
0a85fd67 832 SCReturnInt(ret);
07f7ba55
GS
833}
834
4537f889
VJ
835/**
836 * \param name /Lowercase/ version of the variable name
837 */
838static int HTTPParseContentDispositionHeader(uint8_t *name, size_t name_len,
839 uint8_t *data, size_t len, uint8_t **retptr, size_t *retlen)
840{
32fb9f37 841#ifdef PRINT
4537f889
VJ
842 printf("DATA START: \n");
843 PrintRawDataFp(stdout, data, len);
844 printf("DATA END: \n");
845#endif
846 size_t x;
847 int quote = 0;
848
849 for (x = 0; x < len; x++) {
850 if (!(isspace(data[x])))
851 break;
852 }
853
854 if (x >= len)
855 return 0;
856
857 uint8_t *line = data+x;
858 size_t line_len = len-x;
859 size_t offset = 0;
32fb9f37 860#ifdef PRINT
4537f889
VJ
861 printf("LINE START: \n");
862 PrintRawDataFp(stdout, line, line_len);
863 printf("LINE END: \n");
864#endif
865 for (x = 0 ; x < line_len; x++) {
866 if (x > 0) {
867 if (line[x - 1] != '\\' && line[x] == '\"') {
868 quote++;
869 }
870
871 if (((line[x - 1] != '\\' && line[x] == ';') || ((x + 1) == line_len)) && (quote == 0 || quote % 2 == 0)) {
872 uint8_t *token = line + offset;
873 size_t token_len = x - offset;
874
875 if ((x + 1) == line_len) {
876 token_len++;
877 }
878
879 offset = x + 1;
880
881 while (offset < line_len && isspace(line[offset])) {
882 x++;
883 offset++;
884 }
32fb9f37 885#ifdef PRINT
4537f889
VJ
886 printf("TOKEN START: \n");
887 PrintRawDataFp(stdout, token, token_len);
888 printf("TOKEN END: \n");
889#endif
890 if (token_len > name_len) {
891 if (name == NULL || SCMemcmpLowercase(name, token, name_len) == 0) {
892 uint8_t *value = token + name_len;
893 size_t value_len = token_len - name_len;
894
895 if (value[0] == '\"') {
896 value++;
897 value_len--;
898 }
899 if (value[value_len-1] == '\"') {
900 value_len--;
901 }
32fb9f37 902#ifdef PRINT
4537f889
VJ
903 printf("VALUE START: \n");
904 PrintRawDataFp(stdout, value, value_len);
905 printf("VALUE END: \n");
906#endif
907 *retptr = value;
908 *retlen = value_len;
909 return 1;
910 }
911 }
912 }
913 }
914 }
915
916 return 0;
917}
918
919/**
920 * \param name /Lowercase/ version of the variable name
921 */
922static int HTTPParseContentTypeHeader(uint8_t *name, size_t name_len,
923 uint8_t *data, size_t len, uint8_t **retptr, size_t *retlen)
924{
925 SCEnter();
32fb9f37 926#ifdef PRINT
4537f889
VJ
927 printf("DATA START: \n");
928 PrintRawDataFp(stdout, data, len);
929 printf("DATA END: \n");
930#endif
931 size_t x;
932 int quote = 0;
933
934 for (x = 0; x < len; x++) {
935 if (!(isspace(data[x])))
936 break;
937 }
938
a0ee6ade
VJ
939 if (x >= len) {
940 SCReturnInt(0);
941 }
4537f889
VJ
942
943 uint8_t *line = data+x;
944 size_t line_len = len-x;
945 size_t offset = 0;
32fb9f37 946#ifdef PRINT
4537f889
VJ
947 printf("LINE START: \n");
948 PrintRawDataFp(stdout, line, line_len);
949 printf("LINE END: \n");
950#endif
951 for (x = 0 ; x < line_len; x++) {
952 if (x > 0) {
953 if (line[x - 1] != '\\' && line[x] == '\"') {
954 quote++;
955 }
956
957 if (((line[x - 1] != '\\' && line[x] == ';') || ((x + 1) == line_len)) && (quote == 0 || quote % 2 == 0)) {
958 uint8_t *token = line + offset;
959 size_t token_len = x - offset;
960
961 if ((x + 1) == line_len) {
962 token_len++;
963 }
964
965 offset = x + 1;
966
967 while (offset < line_len && isspace(line[offset])) {
968 x++;
969 offset++;
970 }
32fb9f37 971#ifdef PRINT
4537f889
VJ
972 printf("TOKEN START: \n");
973 PrintRawDataFp(stdout, token, token_len);
974 printf("TOKEN END: \n");
975#endif
976 if (token_len > name_len) {
977 if (name == NULL || SCMemcmpLowercase(name, token, name_len) == 0) {
978 uint8_t *value = token + name_len;
979 size_t value_len = token_len - name_len;
980
981 if (value[0] == '\"') {
982 value++;
983 value_len--;
984 }
985 if (value[value_len-1] == '\"') {
986 value_len--;
987 }
32fb9f37 988#ifdef PRINT
4537f889
VJ
989 printf("VALUE START: \n");
990 PrintRawDataFp(stdout, value, value_len);
991 printf("VALUE END: \n");
992#endif
993 *retptr = value;
994 *retlen = value_len;
a0ee6ade 995 SCReturnInt(1);
4537f889
VJ
996 }
997 }
998 }
999 }
1000 }
1001
a0ee6ade 1002 SCReturnInt(0);
4537f889
VJ
1003}
1004
ef053679
VJ
1005/**
1006 * \brief setup multipart parsing: extract boundary and store it
1007 *
1008 * \param d HTTP transaction
1009 * \param htud transaction userdata
1010 *
3702a33a
VJ
1011 * \retval 1 ok, multipart set up
1012 * \retval 0 ok, not multipart though
ef053679
VJ
1013 * \retval -1 error: problem with the boundary
1014 *
1015 * If the request contains a multipart message, this function will
1016 * set the HTP_BOUNDARY_SET in the transaction.
1017 */
8f1d7503
KS
1018static int HtpRequestBodySetupMultipart(htp_tx_data_t *d, HtpTxUserData *htud)
1019{
48cf0585 1020 htp_header_t *h = (htp_header_t *)htp_table_get_c(d->tx->request_headers,
21acd72a
VJ
1021 "Content-Type");
1022 if (h != NULL && bstr_len(h->value) > 0) {
1023 uint8_t *boundary = NULL;
1024 size_t boundary_len = 0;
1025
1026 int r = HTTPParseContentTypeHeader((uint8_t *)"boundary=", 9,
1027 (uint8_t *) bstr_ptr(h->value), bstr_len(h->value),
1028 &boundary, &boundary_len);
1029 if (r == 1) {
1030#ifdef PRINT
1031 printf("BOUNDARY START: \n");
1032 PrintRawDataFp(stdout, boundary, boundary_len);
1033 printf("BOUNDARY END: \n");
1034#endif
1035 if (boundary_len < HTP_BOUNDARY_MAX) {
ced01da8 1036 htud->boundary = HTPMalloc(boundary_len);
21acd72a
VJ
1037 if (htud->boundary == NULL) {
1038 return -1;
1039 }
1040 htud->boundary_len = (uint8_t)boundary_len;
1041 memcpy(htud->boundary, boundary, boundary_len);
1042
43c7fd75 1043 htud->tsflags |= HTP_BOUNDARY_SET;
21acd72a
VJ
1044 } else {
1045 SCLogDebug("invalid boundary");
1046 return -1;
1047 }
c85674b0 1048 SCReturnInt(1);
21acd72a 1049 }
c85674b0 1050 //SCReturnInt(1);
21acd72a 1051 }
3702a33a 1052 SCReturnInt(0);
21acd72a
VJ
1053}
1054
ef053679
VJ
1055/**
1056 * \brief Setup boundary buffers
1057 */
66a3cd96 1058static int HtpRequestBodySetupBoundary(HtpTxUserData *htud,
21acd72a
VJ
1059 uint8_t **expected_boundary, uint8_t *expected_boundary_len,
1060 uint8_t **expected_boundary_end, uint8_t *expected_boundary_end_len)
1061{
1062 uint8_t *eb = NULL;
1063 uint8_t *ebe = NULL;
1064
1065 uint8_t eb_len = htud->boundary_len + 2;
ced01da8 1066 eb = (uint8_t *)HTPMalloc(eb_len);
21acd72a
VJ
1067 if (eb == NULL) {
1068 goto error;
1069 }
1070 memset(eb, '-', eb_len);
1071 memcpy(eb + 2, htud->boundary, htud->boundary_len);
1072
1073 uint8_t ebe_len = htud->boundary_len + 4;
ced01da8 1074 ebe = (uint8_t *)HTPMalloc(ebe_len);
21acd72a
VJ
1075 if (ebe == NULL) {
1076 goto error;
1077 }
1078 memset(ebe, '-', ebe_len);
1079 memcpy(ebe + 2, htud->boundary, htud->boundary_len);
1080
1081 *expected_boundary = eb;
1082 *expected_boundary_len = eb_len;
1083 *expected_boundary_end = ebe;
1084 *expected_boundary_end_len = ebe_len;
1085
1086 SCReturnInt(0);
1087
1088error:
1089 if (eb != NULL) {
ced01da8 1090 HTPFree(eb, eb_len);
21acd72a
VJ
1091 }
1092 if (ebe != NULL) {
ced01da8 1093 HTPFree(ebe, ebe_len);
21acd72a
VJ
1094 }
1095 SCReturnInt(-1);
1096}
1097
4537f889
VJ
1098#define C_D_HDR "content-disposition:"
1099#define C_D_HDR_LEN 20
1100#define C_T_HDR "content-type:"
1101#define C_T_HDR_LEN 13
1102
e21d8cdf 1103static void HtpRequestBodyMultipartParseHeader(HtpState *hstate,
3f5acc54 1104 HtpTxUserData *htud,
e21d8cdf 1105 uint8_t *header, uint32_t header_len,
21acd72a
VJ
1106 uint8_t **filename, uint16_t *filename_len,
1107 uint8_t **filetype, uint16_t *filetype_len)
1108{
1109 uint8_t *fn = NULL;
1110 size_t fn_len = 0;
1111 uint8_t *ft = NULL;
1112 size_t ft_len = 0;
1113
1114#ifdef PRINT
1115 printf("HEADER START: \n");
1116 PrintRawDataFp(stdout, header, header_len);
1117 printf("HEADER END: \n");
1118#endif
1119
1120 while (header_len > 0) {
1121 uint8_t *next_line = Bs2bmSearch(header, header_len, (uint8_t *)"\r\n", 2);
1122 uint8_t *line = header;
1123 uint32_t line_len;
1124
1125 if (next_line == NULL) {
1126 line_len = header_len;
1127 } else {
1128 line_len = next_line - header;
1129 }
e21d8cdf
VJ
1130 uint8_t *sc = (uint8_t *)memchr(line, ':', line_len);
1131 if (sc == NULL) {
3f5acc54 1132 HTPSetEvent(hstate, htud,
e21d8cdf 1133 HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER);
e21d8cdf
VJ
1134 /* if the : we found is the final char, it means we have
1135 * no value */
fcc21ae4 1136 } else if (line_len > 0 && sc == &line[line_len - 1]) {
3f5acc54 1137 HTPSetEvent(hstate, htud,
fcc21ae4
VJ
1138 HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER);
1139 } else {
21acd72a 1140#ifdef PRINT
fcc21ae4
VJ
1141 printf("LINE START: \n");
1142 PrintRawDataFp(stdout, line, line_len);
1143 printf("LINE END: \n");
21acd72a 1144#endif
fcc21ae4
VJ
1145 if (line_len >= C_D_HDR_LEN &&
1146 SCMemcmpLowercase(C_D_HDR, line, C_D_HDR_LEN) == 0) {
1147 uint8_t *value = line + C_D_HDR_LEN;
1148 uint32_t value_len = line_len - C_D_HDR_LEN;
1149
1150 /* parse content-disposition */
1151 (void)HTTPParseContentDispositionHeader((uint8_t *)"filename=", 9,
1152 value, value_len, &fn, &fn_len);
1153 } else if (line_len >= C_T_HDR_LEN &&
1154 SCMemcmpLowercase(C_T_HDR, line, C_T_HDR_LEN) == 0) {
1155 SCLogDebug("content-type line");
1156 uint8_t *value = line + C_T_HDR_LEN;
1157 uint32_t value_len = line_len - C_T_HDR_LEN;
1158
1159 (void)HTTPParseContentTypeHeader(NULL, 0,
1160 value, value_len, &ft, &ft_len);
1161 }
21acd72a
VJ
1162 }
1163
1164 if (next_line == NULL) {
1165 SCLogDebug("no next_line");
1166 break;
1167 }
21acd72a
VJ
1168 header_len -= ((next_line + 2) - header);
1169 header = next_line + 2;
1170 } /* while (header_len > 0) */
1171
1172 if (fn_len > USHRT_MAX)
1173 fn_len = USHRT_MAX;
1174 if (ft_len > USHRT_MAX)
1175 ft_len = USHRT_MAX;
1176
1177 *filename = fn;
1178 *filename_len = fn_len;
1179 *filetype = ft;
1180 *filetype_len = ft_len;
1181}
1182
ef053679
VJ
1183/**
1184 * \brief Create a single buffer from the HtpBodyChunks in our list
1185 *
1186 * \param htud transaction user data
1187 * \param chunks_buffers pointer to pass back the buffer to the caller
1188 * \param chunks_buffer_len pointer to pass back the buffer length to the caller
1189 */
66a3cd96 1190static void HtpRequestBodyReassemble(HtpTxUserData *htud,
21acd72a
VJ
1191 uint8_t **chunks_buffer, uint32_t *chunks_buffer_len)
1192{
1193 uint8_t *buf = NULL;
1f07d152 1194 uint8_t *pbuf = NULL;
21acd72a 1195 uint32_t buf_len = 0;
66a3cd96 1196 HtpBodyChunk *cur = htud->request_body.first;
21acd72a
VJ
1197
1198 for ( ; cur != NULL; cur = cur->next) {
a6e75aff
VJ
1199 SCLogDebug("chunk %p", cur);
1200
21acd72a 1201 /* skip body chunks entirely before what we parsed already */
48cf0585 1202 if ((uint64_t )cur->stream_offset + cur->len <= htud->request_body.body_parsed) {
a6e75aff 1203 SCLogDebug("skipping chunk");
21acd72a 1204 continue;
a6e75aff
VJ
1205 }
1206
1207 SCLogDebug("cur->stream_offset %"PRIu64", cur->len %"PRIu32", body_parsed %"PRIu64,
1208 cur->stream_offset, cur->len, htud->request_body.body_parsed);
21acd72a 1209
b402d971
VJ
1210 if (cur->stream_offset < htud->request_body.body_parsed &&
1211 cur->stream_offset + cur->len >= htud->request_body.body_parsed) {
a6e75aff 1212 SCLogDebug("use part");
21acd72a 1213
b402d971
VJ
1214 uint32_t toff = htud->request_body.body_parsed - cur->stream_offset;
1215 uint32_t tlen = (cur->stream_offset + cur->len) - htud->request_body.body_parsed;
1f07d152 1216 uint8_t *pbuf = NULL;
21acd72a
VJ
1217
1218 buf_len += tlen;
ced01da8
EL
1219 if ((pbuf = HTPRealloc(buf, buf_len - tlen, buf_len)) == NULL) {
1220 HTPFree(buf, buf_len - tlen);
1f07d152 1221 buf = NULL;
21acd72a
VJ
1222 buf_len = 0;
1223 break;
1224 }
1f07d152 1225 buf = pbuf;
21acd72a
VJ
1226 memcpy(buf + buf_len - tlen, cur->data + toff, tlen);
1227
1228 } else {
a6e75aff
VJ
1229 SCLogDebug("use entire chunk");
1230
21acd72a 1231 buf_len += cur->len;
ced01da8
EL
1232 if ((pbuf = HTPRealloc(buf, buf_len - cur->len, buf_len)) == NULL) {
1233 HTPFree(buf, buf_len - cur->len);
1f07d152 1234 buf = NULL;
21acd72a
VJ
1235 buf_len = 0;
1236 break;
1237 }
1f07d152 1238 buf = pbuf;
21acd72a
VJ
1239 memcpy(buf + buf_len - cur->len, cur->data, cur->len);
1240 }
1241 }
1242
1243 *chunks_buffer = buf;
1244 *chunks_buffer_len = buf_len;
1245}
1246
66a3cd96 1247int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud,
94e25276 1248 void *tx, uint8_t *chunks_buffer, uint32_t chunks_buffer_len)
403b2788 1249{
23e01d23
VJ
1250 int result = 0;
1251 uint8_t *expected_boundary = NULL;
1252 uint8_t *expected_boundary_end = NULL;
1253 uint8_t expected_boundary_len = 0;
1254 uint8_t expected_boundary_end_len = 0;
94e25276 1255 int tx_progress = 0;
23e01d23 1256
403b2788
VJ
1257#ifdef PRINT
1258 printf("CHUNK START: \n");
1259 PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
1260 printf("CHUNK END: \n");
1261#endif
1262
403b2788
VJ
1263 if (HtpRequestBodySetupBoundary(htud, &expected_boundary, &expected_boundary_len,
1264 &expected_boundary_end, &expected_boundary_end_len) < 0) {
1265 goto end;
1266 }
1267
1268 /* search for the header start, header end and form end */
1269 uint8_t *header_start = Bs2bmSearch(chunks_buffer, chunks_buffer_len,
1270 expected_boundary, expected_boundary_len);
1271 uint8_t *header_end = NULL;
1272 if (header_start != NULL) {
1273 header_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer),
1274 (uint8_t *)"\r\n\r\n", 4);
1275 }
1276 uint8_t *form_end = Bs2bmSearch(chunks_buffer, chunks_buffer_len,
1277 expected_boundary_end, expected_boundary_end_len);
1278
fcc21ae4
VJ
1279 SCLogDebug("header_start %p, header_end %p, form_end %p", header_start,
1280 header_end, form_end);
1281
94e25276
AS
1282 /* we currently only handle multipart for ts. When we support it for tc,
1283 * we will need to supply right direction */
429c6388 1284 tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER);
403b2788 1285 /* if we're in the file storage process, deal with that now */
43c7fd75 1286 if (htud->tsflags & HTP_FILENAME_SET) {
94e25276 1287 if (header_start != NULL || form_end != NULL || (tx_progress > HTP_REQUEST_BODY)) {
403b2788
VJ
1288 SCLogDebug("reached the end of the file");
1289
1290 uint8_t *filedata = chunks_buffer;
1291 uint32_t filedata_len = 0;
1292 uint8_t flags = 0;
1293
1294 if (header_start < form_end || (header_start != NULL && form_end == NULL)) {
1295 filedata_len = header_start - filedata - 2; /* 0d 0a */
1296 } else if (form_end != NULL && form_end < header_start) {
1297 filedata_len = form_end - filedata;
1298 } else if (form_end != NULL && form_end == header_start) {
1299 filedata_len = form_end - filedata - 2; /* 0d 0a */
94e25276 1300 } else if (tx_progress > HTP_RESPONSE_BODY) {
403b2788 1301 filedata_len = chunks_buffer_len;
e1022ee5 1302 flags = FILE_TRUNCATED;
403b2788
VJ
1303 }
1304
e21d8cdf 1305 if (filedata_len > chunks_buffer_len) {
3f5acc54 1306 HTPSetEvent(hstate, htud,
e21d8cdf
VJ
1307 HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR);
1308 goto end;
1309 }
403b2788
VJ
1310#ifdef PRINT
1311 printf("FILEDATA (final chunk) START: \n");
1312 PrintRawDataFp(stdout, filedata, filedata_len);
1313 printf("FILEDATA (final chunk) END: \n");
1314#endif
43c7fd75 1315 if (!(htud->tsflags & HTP_DONTSTORE)) {
d59ca75e
VJ
1316 if (HTPFileClose(hstate, filedata, filedata_len, flags,
1317 STREAM_TOSERVER) == -1)
23e01d23
VJ
1318 {
1319 goto end;
1320 }
403b2788
VJ
1321 }
1322
43c7fd75 1323 htud->tsflags &=~ HTP_FILENAME_SET;
403b2788
VJ
1324
1325 /* fall through */
1326 } else {
1327 SCLogDebug("not yet at the end of the file");
1328
1329 if (chunks_buffer_len > expected_boundary_end_len) {
1330 uint8_t *filedata = chunks_buffer;
1331 uint32_t filedata_len = chunks_buffer_len - expected_boundary_len;
1332#ifdef PRINT
1333 printf("FILEDATA (part) START: \n");
1334 PrintRawDataFp(stdout, filedata, filedata_len);
1335 printf("FILEDATA (part) END: \n");
1336#endif
23e01d23 1337
43c7fd75 1338 if (!(htud->tsflags & HTP_DONTSTORE)) {
d59ca75e
VJ
1339 result = HTPFileStoreChunk(hstate, filedata,
1340 filedata_len, STREAM_TOSERVER);
23e01d23
VJ
1341 if (result == -1) {
1342 goto end;
1343 } else if (result == -2) {
1344 /* we know for sure we're not storing the file */
43c7fd75 1345 htud->tsflags |= HTP_DONTSTORE;
23e01d23 1346 }
403b2788
VJ
1347 }
1348
b402d971 1349 htud->request_body.body_parsed += filedata_len;
403b2788
VJ
1350 } else {
1351 SCLogDebug("chunk too small to already process in part");
1352 }
1353
1354 goto end;
1355 }
1356 }
1357
1358 while (header_start != NULL && header_end != NULL &&
1359 header_end != form_end &&
1360 header_start < (chunks_buffer + chunks_buffer_len) &&
1361 header_end < (chunks_buffer + chunks_buffer_len) &&
1362 header_start < header_end)
1363 {
1364 uint8_t *filename = NULL;
1365 uint16_t filename_len = 0;
1366 uint8_t *filetype = NULL;
1367 uint16_t filetype_len = 0;
1368
1369 uint32_t header_len = header_end - header_start;
1370 SCLogDebug("header_len %u", header_len);
33848124 1371 uint8_t *header = header_start;
403b2788 1372
18837dce
VJ
1373 /* skip empty records */
1374 if (expected_boundary_len == header_len) {
1375 goto next;
1376 } else if ((uint32_t)(expected_boundary_len + 2) <= header_len) {
33848124
VJ
1377 header_len -= (expected_boundary_len + 2);
1378 header = header_start + (expected_boundary_len + 2); // + for 0d 0a
1379 }
403b2788 1380
3f5acc54 1381 HtpRequestBodyMultipartParseHeader(hstate, htud, header, header_len,
e21d8cdf 1382 &filename, &filename_len, &filetype, &filetype_len);
403b2788
VJ
1383
1384 if (filename != NULL) {
1385 uint8_t *filedata = NULL;
1386 uint32_t filedata_len = 0;
1387
1388 SCLogDebug("we have a filename");
1389
43c7fd75
VJ
1390 htud->tsflags |= HTP_FILENAME_SET;
1391 htud->tsflags &= ~HTP_DONTSTORE;
403b2788
VJ
1392
1393 SCLogDebug("header_end %p", header_end);
1394 SCLogDebug("form_end %p", form_end);
1395
1396 /* everything until the final boundary is the file */
1397 if (form_end != NULL) {
1398 filedata = header_end + 4;
e21d8cdf 1399 if (form_end == filedata) {
3f5acc54 1400 HTPSetEvent(hstate, htud,
e21d8cdf
VJ
1401 HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA);
1402 goto end;
1403 } else if (form_end < filedata) {
3f5acc54 1404 HTPSetEvent(hstate, htud,
e21d8cdf
VJ
1405 HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR);
1406 goto end;
1407 }
1408
403b2788 1409 filedata_len = form_end - (header_end + 4 + 2);
e21d8cdf 1410 SCLogDebug("filedata_len %"PRIuMAX, (uintmax_t)filedata_len);
403b2788
VJ
1411
1412 /* or is it? */
1413 uint8_t *header_next = Bs2bmSearch(filedata, filedata_len,
1414 expected_boundary, expected_boundary_len);
1415 if (header_next != NULL) {
1416 filedata_len -= (form_end - header_next);
1417 }
1418
e21d8cdf 1419 if (filedata_len > chunks_buffer_len) {
3f5acc54 1420 HTPSetEvent(hstate, htud,
e21d8cdf
VJ
1421 HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR);
1422 goto end;
1423 }
403b2788 1424 SCLogDebug("filedata_len %"PRIuMAX, (uintmax_t)filedata_len);
403b2788
VJ
1425#ifdef PRINT
1426 printf("FILEDATA START: \n");
1427 PrintRawDataFp(stdout, filedata, filedata_len);
1428 printf("FILEDATA END: \n");
1429#endif
1430
e1022ee5 1431 result = HTPFileOpen(hstate, filename, filename_len,
d59ca75e
VJ
1432 filedata, filedata_len, hstate->transaction_cnt,
1433 STREAM_TOSERVER);
23e01d23 1434 if (result == -1) {
403b2788 1435 goto end;
23e01d23 1436 } else if (result == -2) {
43c7fd75 1437 htud->tsflags |= HTP_DONTSTORE;
23e01d23 1438 } else {
d59ca75e 1439 if (HTPFileClose(hstate, NULL, 0, 0, STREAM_TOSERVER) == -1) {
23e01d23
VJ
1440 goto end;
1441 }
403b2788 1442 }
a6e75aff
VJ
1443
1444 htud->request_body.body_parsed += (header_end - chunks_buffer);
43c7fd75 1445 htud->tsflags &= ~HTP_FILENAME_SET;
403b2788 1446 } else {
a6e75aff
VJ
1447 SCLogDebug("chunk doesn't contain form end");
1448
1449 filedata = header_end + 4;
1450 filedata_len = chunks_buffer_len - (filedata - chunks_buffer);
1451 SCLogDebug("filedata_len %u (chunks_buffer_len %u)", filedata_len, chunks_buffer_len);
1452
e21d8cdf 1453 if (filedata_len > chunks_buffer_len) {
3f5acc54 1454 HTPSetEvent(hstate, htud,
e21d8cdf
VJ
1455 HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR);
1456 goto end;
1457 }
1458
a6e75aff
VJ
1459#ifdef PRINT
1460 printf("FILEDATA START: \n");
1461 PrintRawDataFp(stdout, filedata, filedata_len);
1462 printf("FILEDATA END: \n");
1463#endif
1464 /* form doesn't end in this chunk, but part might. Lets
1465 * see if have another coming up */
1466 uint8_t *header_next = Bs2bmSearch(filedata, filedata_len,
1467 expected_boundary, expected_boundary_len);
1468 SCLogDebug("header_next %p", header_next);
1469 if (header_next == NULL) {
1470 /* no, but we'll handle the file data when we see the
1471 * form_end */
403b2788 1472
a6e75aff 1473 SCLogDebug("more file data to come");
403b2788 1474
a6e75aff
VJ
1475 uint32_t offset = (header_end + 4) - chunks_buffer;
1476 SCLogDebug("offset %u", offset);
1477 htud->request_body.body_parsed += offset;
1c934acc 1478
a6e75aff
VJ
1479 result = HTPFileOpen(hstate, filename, filename_len,
1480 NULL, 0, hstate->transaction_cnt,
1481 STREAM_TOSERVER);
1482 if (result == -1) {
1483 goto end;
1484 } else if (result == -2) {
43c7fd75 1485 htud->tsflags |= HTP_DONTSTORE;
a6e75aff 1486 }
fcc21ae4 1487 } else if (header_next - filedata > 2) {
a6e75aff
VJ
1488 filedata_len = header_next - filedata - 2;
1489 SCLogDebug("filedata_len %u", filedata_len);
1490
1491 result = HTPFileOpen(hstate, filename, filename_len,
d59ca75e
VJ
1492 filedata, filedata_len, hstate->transaction_cnt,
1493 STREAM_TOSERVER);
a6e75aff
VJ
1494 if (result == -1) {
1495 goto end;
1496 } else if (result == -2) {
43c7fd75 1497 htud->tsflags |= HTP_DONTSTORE;
a6e75aff
VJ
1498 } else {
1499 if (HTPFileClose(hstate, NULL, 0, 0, STREAM_TOSERVER) == -1) {
1500 goto end;
1501 }
1502 }
1503
43c7fd75 1504 htud->tsflags &= ~HTP_FILENAME_SET;
a6e75aff 1505 htud->request_body.body_parsed += (header_end - chunks_buffer);
403b2788
VJ
1506 }
1507 }
403b2788 1508 }
18837dce 1509next:
403b2788
VJ
1510 SCLogDebug("header_start %p, header_end %p, form_end %p",
1511 header_start, header_end, form_end);
1512
1513 /* Search next boundary entry after the start of body */
1514 uint32_t cursizeread = header_end - chunks_buffer;
1515 header_start = Bs2bmSearch(header_end + 4,
1516 chunks_buffer_len - (cursizeread + 4),
1517 expected_boundary, expected_boundary_len);
1518 if (header_start != NULL) {
1519 header_end = Bs2bmSearch(header_end + 4,
1520 chunks_buffer_len - (cursizeread + 4),
1521 (uint8_t *) "\r\n\r\n", 4);
1522 }
1523 }
1524end:
1525 if (expected_boundary != NULL) {
ced01da8 1526 HTPFree(expected_boundary, expected_boundary_len);
403b2788
VJ
1527 }
1528 if (expected_boundary_end != NULL) {
ced01da8 1529 HTPFree(expected_boundary_end, expected_boundary_end_len);
403b2788 1530 }
a6e75aff
VJ
1531
1532 SCLogDebug("htud->request_body.body_parsed %"PRIu64, htud->request_body.body_parsed);
403b2788
VJ
1533 return 0;
1534}
1535
1536/** \brief setup things for put request
1537 * \todo really needed? */
8f1d7503
KS
1538int HtpRequestBodySetupPUT(htp_tx_data_t *d, HtpTxUserData *htud)
1539{
403b2788
VJ
1540// if (d->tx->parsed_uri == NULL || d->tx->parsed_uri->path == NULL) {
1541// return -1;
1542// }
1543
1544 /* filename is d->tx->parsed_uri->path */
1545
1546 return 0;
1547}
1548
3702a33a
VJ
1549/** \internal
1550 * \brief Handle POST, no multipart body data
1551 */
1552static int HtpRequestBodyHandlePOST(HtpState *hstate, HtpTxUserData *htud,
1553 htp_tx_t *tx, uint8_t *data, uint32_t data_len)
1554{
1555 int result = 0;
1556
1557 /* see if we need to open the file */
43c7fd75 1558 if (!(htud->tsflags & HTP_FILENAME_SET))
3702a33a
VJ
1559 {
1560 uint8_t *filename = NULL;
fe9258f0 1561 size_t filename_len = 0;
3702a33a
VJ
1562
1563 /* get the name */
1564 if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) {
1565 filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path);
1566 filename_len = bstr_len(tx->parsed_uri->path);
1567 }
1568
e3935a2a 1569 if (filename != NULL) {
fe9258f0 1570 result = HTPFileOpen(hstate, filename, (uint32_t)filename_len, data, data_len,
e3935a2a
VJ
1571 hstate->transaction_cnt, STREAM_TOSERVER);
1572 if (result == -1) {
1573 goto end;
1574 } else if (result == -2) {
43c7fd75 1575 htud->tsflags |= HTP_DONTSTORE;
e3935a2a 1576 } else {
43c7fd75
VJ
1577 htud->tsflags |= HTP_FILENAME_SET;
1578 htud->tsflags &= ~HTP_DONTSTORE;
e3935a2a 1579 }
3702a33a
VJ
1580 }
1581 }
1582 else
1583 {
1584 /* otherwise, just store the data */
1585
43c7fd75 1586 if (!(htud->tsflags & HTP_DONTSTORE)) {
3702a33a
VJ
1587 result = HTPFileStoreChunk(hstate, data, data_len, STREAM_TOSERVER);
1588 if (result == -1) {
1589 goto end;
1590 } else if (result == -2) {
1591 /* we know for sure we're not storing the file */
43c7fd75 1592 htud->tsflags |= HTP_DONTSTORE;
3702a33a
VJ
1593 }
1594 }
1595 }
1596
1597 return 0;
1598end:
1599 return -1;
1600}
1601
1602/** \internal
1603 * \brief Handle PUT body data
1604 */
1605static int HtpRequestBodyHandlePUT(HtpState *hstate, HtpTxUserData *htud,
403b2788
VJ
1606 htp_tx_t *tx, uint8_t *data, uint32_t data_len)
1607{
23e01d23
VJ
1608 int result = 0;
1609
403b2788 1610 /* see if we need to open the file */
43c7fd75 1611 if (!(htud->tsflags & HTP_FILENAME_SET))
403b2788
VJ
1612 {
1613 uint8_t *filename = NULL;
fe9258f0 1614 size_t filename_len = 0;
403b2788
VJ
1615
1616 /* get the name */
1617 if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) {
1618 filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path);
1619 filename_len = bstr_len(tx->parsed_uri->path);
1620 }
1621
e3935a2a 1622 if (filename != NULL) {
fe9258f0 1623 result = HTPFileOpen(hstate, filename, (uint32_t)filename_len, data, data_len,
e3935a2a
VJ
1624 hstate->transaction_cnt, STREAM_TOSERVER);
1625 if (result == -1) {
1626 goto end;
1627 } else if (result == -2) {
43c7fd75 1628 htud->tsflags |= HTP_DONTSTORE;
e3935a2a 1629 } else {
43c7fd75
VJ
1630 htud->tsflags |= HTP_FILENAME_SET;
1631 htud->tsflags &= ~HTP_DONTSTORE;
e3935a2a 1632 }
b402d971
VJ
1633 }
1634 }
1635 else
1636 {
1637 /* otherwise, just store the data */
1638
43c7fd75 1639 if (!(htud->tsflags & HTP_DONTSTORE)) {
d59ca75e 1640 result = HTPFileStoreChunk(hstate, data, data_len, STREAM_TOSERVER);
b402d971
VJ
1641 if (result == -1) {
1642 goto end;
1643 } else if (result == -2) {
1644 /* we know for sure we're not storing the file */
43c7fd75 1645 htud->tsflags |= HTP_DONTSTORE;
b402d971
VJ
1646 }
1647 }
1648 }
1649
1650 return 0;
1651end:
1652 return -1;
1653}
1654
1655int HtpResponseBodyHandle(HtpState *hstate, HtpTxUserData *htud,
1656 htp_tx_t *tx, uint8_t *data, uint32_t data_len)
1657{
1658 SCEnter();
1659
1660 int result = 0;
1661
1662 /* see if we need to open the file */
43c7fd75 1663 if (!(htud->tcflags & HTP_FILENAME_SET))
b402d971
VJ
1664 {
1665 SCLogDebug("setting up file name");
1666
1667 uint8_t *filename = NULL;
fe9258f0 1668 size_t filename_len = 0;
b402d971 1669
64827e38 1670 /* try Content-Disposition header first */
48cf0585 1671 htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers,
64827e38
VJ
1672 "Content-Disposition");
1673 if (h != NULL && bstr_len(h->value) > 0) {
1674 /* parse content-disposition */
1675 (void)HTTPParseContentDispositionHeader((uint8_t *)"filename=", 9,
fe9258f0 1676 (uint8_t *) bstr_ptr(h->value), bstr_len(h->value), &filename, &filename_len);
64827e38
VJ
1677 }
1678
1679 /* fall back to name from the uri */
1680 if (filename == NULL) {
1681 /* get the name */
1682 if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) {
1683 filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path);
1684 filename_len = bstr_len(tx->parsed_uri->path);
1685 }
b402d971
VJ
1686 }
1687
e3935a2a 1688 if (filename != NULL) {
fe9258f0 1689 result = HTPFileOpen(hstate, filename, (uint32_t)filename_len,
d59ca75e 1690 data, data_len, hstate->transaction_cnt, STREAM_TOCLIENT);
e3935a2a
VJ
1691 SCLogDebug("result %d", result);
1692 if (result == -1) {
1693 goto end;
1694 } else if (result == -2) {
43c7fd75 1695 htud->tcflags |= HTP_DONTSTORE;
e3935a2a 1696 } else {
43c7fd75
VJ
1697 htud->tcflags |= HTP_FILENAME_SET;
1698 htud->tcflags &= ~HTP_DONTSTORE;
e3935a2a 1699 }
403b2788 1700 }
403b2788
VJ
1701 }
1702 else
1703 {
1704 /* otherwise, just store the data */
1705
43c7fd75 1706 if (!(htud->tcflags & HTP_DONTSTORE)) {
d59ca75e 1707 result = HTPFileStoreChunk(hstate, data, data_len, STREAM_TOCLIENT);
b402d971 1708 SCLogDebug("result %d", result);
23e01d23
VJ
1709 if (result == -1) {
1710 goto end;
1711 } else if (result == -2) {
1712 /* we know for sure we're not storing the file */
43c7fd75 1713 htud->tcflags |= HTP_DONTSTORE;
23e01d23 1714 }
403b2788
VJ
1715 }
1716 }
1717
1718 return 0;
1719end:
1720 return -1;
1721}
1722
0165b3f0 1723/**
a9cdd2bb 1724 * \brief Function callback to append chunks for Requests
0165b3f0 1725 * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
48cf0585 1726 * \retval int HTP_OK if all goes well
0165b3f0
PR
1727 */
1728int HTPCallbackRequestBodyData(htp_tx_data_t *d)
1729{
1730 SCEnter();
6d60b3a7 1731
92679442 1732 if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_REQUEST_BODY))
48cf0585
AS
1733 SCReturnInt(HTP_OK);
1734
1735 if (d->data == NULL || d->len == 0)
1736 SCReturnInt(HTP_OK);
66a083da 1737
a6e75aff
VJ
1738#ifdef PRINT
1739 printf("HTPBODY START: \n");
1740 PrintRawDataFp(stdout, (uint8_t *)d->data, d->len);
1741 printf("HTPBODY END: \n");
1742#endif
1743
48cf0585 1744 HtpState *hstate = htp_connp_get_user_data(d->tx->connp);
4537f889 1745 if (hstate == NULL) {
48cf0585 1746 SCReturnInt(HTP_ERROR);
4537f889
VJ
1747 }
1748
23e01d23 1749 SCLogDebug("New request body data available at %p -> %p -> %p, bodylen "
0165b3f0
PR
1750 "%"PRIu32"", hstate, d, d->data, (uint32_t)d->len);
1751
48cf0585
AS
1752 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(d->tx);
1753 if (tx_ud == NULL) {
ced01da8 1754 tx_ud = HTPMalloc(sizeof(HtpTxUserData));
48cf0585
AS
1755 if (unlikely(tx_ud == NULL)) {
1756 SCReturnInt(HTP_OK);
06a65cb4 1757 }
48cf0585 1758 memset(tx_ud, 0, sizeof(HtpTxUserData));
0165b3f0 1759
48cf0585
AS
1760 /* Set the user data for handling body chunks on this transaction */
1761 htp_tx_set_user_data(d->tx, tx_ud);
1762 }
1763 if (!tx_ud->response_body_init) {
1764 tx_ud->response_body_init = 1;
1765 tx_ud->operation = HTP_BODY_REQUEST;
1766
1767 if (d->tx->request_method_number == HTP_M_POST) {
3702a33a 1768 SCLogDebug("POST");
48cf0585 1769 int r = HtpRequestBodySetupMultipart(d, tx_ud);
3702a33a 1770 if (r == 1) {
48cf0585 1771 tx_ud->request_body_type = HTP_BODY_REQUEST_MULTIPART;
3702a33a 1772 } else if (r == 0) {
48cf0585 1773 tx_ud->request_body_type = HTP_BODY_REQUEST_POST;
3702a33a 1774 SCLogDebug("not multipart");
403b2788 1775 }
48cf0585
AS
1776 } else if (d->tx->request_method_number == HTP_M_PUT) {
1777 if (HtpRequestBodySetupPUT(d, tx_ud) == 0) {
1778 tx_ud->request_body_type = HTP_BODY_REQUEST_PUT;
403b2788
VJ
1779 }
1780 }
0165b3f0 1781 }
0165b3f0 1782
48cf0585 1783 SCLogDebug("tx_ud->request_body.content_len_so_far %"PRIu64, tx_ud->request_body.content_len_so_far);
5cd46433 1784 SCLogDebug("hstate->cfg->request_body_limit %u", hstate->cfg->request_body_limit);
6ebe7b7c
VJ
1785
1786 /* within limits, add the body chunk to the state. */
48cf0585 1787 if (hstate->cfg->request_body_limit == 0 || tx_ud->request_body.content_len_so_far < hstate->cfg->request_body_limit)
6ebe7b7c
VJ
1788 {
1789 uint32_t len = (uint32_t)d->len;
1790
5cd46433 1791 if (hstate->cfg->request_body_limit > 0 &&
48cf0585 1792 (tx_ud->request_body.content_len_so_far + len) > hstate->cfg->request_body_limit)
dbe291bc 1793 {
48cf0585 1794 len = hstate->cfg->request_body_limit - tx_ud->request_body.content_len_so_far;
6ebe7b7c
VJ
1795 BUG_ON(len > (uint32_t)d->len);
1796 }
6ebe7b7c
VJ
1797 SCLogDebug("len %u", len);
1798
94e25276 1799 HtpBodyAppendChunk(tx_ud, &tx_ud->request_body, (uint8_t *)d->data, len);
6ebe7b7c 1800
403b2788
VJ
1801 uint8_t *chunks_buffer = NULL;
1802 uint32_t chunks_buffer_len = 0;
a0ee6ade 1803
48cf0585 1804 if (tx_ud->request_body_type == HTP_BODY_REQUEST_MULTIPART) {
403b2788 1805 /* multi-part body handling starts here */
48cf0585 1806 if (!(tx_ud->tsflags & HTP_BOUNDARY_SET)) {
a0ee6ade
VJ
1807 goto end;
1808 }
4723f072 1809
48cf0585 1810 HtpRequestBodyReassemble(tx_ud, &chunks_buffer, &chunks_buffer_len);
403b2788
VJ
1811 if (chunks_buffer == NULL) {
1812 goto end;
6d60b3a7 1813 }
a6e75aff 1814#ifdef PRINT
3702a33a
VJ
1815 printf("REASSCHUNK START: \n");
1816 PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
1817 printf("REASSCHUNK END: \n");
a6e75aff 1818#endif
a0ee6ade 1819
94e25276 1820 HtpRequestBodyHandleMultipart(hstate, tx_ud, d->tx, chunks_buffer, chunks_buffer_len);
a0ee6ade 1821
403b2788 1822 if (chunks_buffer != NULL) {
ced01da8 1823 HTPFree(chunks_buffer, chunks_buffer_len);
a0ee6ade 1824 }
48cf0585
AS
1825 } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_POST) {
1826 HtpRequestBodyHandlePOST(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len);
1827 } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_PUT) {
1828 HtpRequestBodyHandlePUT(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len);
6d60b3a7
PR
1829 }
1830
a0ee6ade
VJ
1831 }
1832
6d60b3a7 1833end:
ef053679 1834 /* see if we can get rid of htp body chunks */
48cf0585 1835 HtpBodyPrune(&tx_ud->request_body);
b402d971
VJ
1836
1837 /* set the new chunk flag */
1838 hstate->flags |= HTP_FLAG_NEW_BODY_SET;
1839
48cf0585 1840 SCReturnInt(HTP_OK);
b402d971
VJ
1841}
1842
1843/**
1844 * \brief Function callback to append chunks for Responses
1845 * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
48cf0585 1846 * \retval int HTP_OK if all goes well
b402d971
VJ
1847 */
1848int HTPCallbackResponseBodyData(htp_tx_data_t *d)
1849{
1850 SCEnter();
1851
92679442 1852 if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_RESPONSE_BODY))
48cf0585 1853 SCReturnInt(HTP_OK);
66a083da 1854
48cf0585
AS
1855 if (d->data == NULL || d->len == 0)
1856 SCReturnInt(HTP_OK);
1857
1858 HtpState *hstate = htp_connp_get_user_data(d->tx->connp);
b402d971 1859 if (hstate == NULL) {
48cf0585 1860 SCReturnInt(HTP_ERROR);
b402d971
VJ
1861 }
1862
1863 SCLogDebug("New response body data available at %p -> %p -> %p, bodylen "
1864 "%"PRIu32"", hstate, d, d->data, (uint32_t)d->len);
1865
48cf0585
AS
1866 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(d->tx);
1867 if (tx_ud == NULL) {
ced01da8 1868 tx_ud = HTPMalloc(sizeof(HtpTxUserData));
48cf0585
AS
1869 if (unlikely(tx_ud == NULL)) {
1870 SCReturnInt(HTP_OK);
b402d971 1871 }
48cf0585
AS
1872 memset(tx_ud, 0, sizeof(HtpTxUserData));
1873
1874 /* Set the user data for handling body chunks on this transaction */
1875 htp_tx_set_user_data(d->tx, tx_ud);
1876 }
1877 if (!tx_ud->request_body_init) {
1878 tx_ud->request_body_init = 1;
1879 tx_ud->operation = HTP_BODY_RESPONSE;
b402d971
VJ
1880 }
1881
48cf0585 1882 SCLogDebug("tx_ud->response_body.content_len_so_far %"PRIu64, tx_ud->response_body.content_len_so_far);
5cd46433 1883 SCLogDebug("hstate->cfg->response_body_limit %u", hstate->cfg->response_body_limit);
b402d971
VJ
1884
1885 /* within limits, add the body chunk to the state. */
48cf0585 1886 if (hstate->cfg->response_body_limit == 0 || tx_ud->response_body.content_len_so_far < hstate->cfg->response_body_limit)
b402d971
VJ
1887 {
1888 uint32_t len = (uint32_t)d->len;
1889
5cd46433 1890 if (hstate->cfg->response_body_limit > 0 &&
48cf0585 1891 (tx_ud->response_body.content_len_so_far + len) > hstate->cfg->response_body_limit)
b402d971 1892 {
48cf0585 1893 len = hstate->cfg->response_body_limit - tx_ud->response_body.content_len_so_far;
b402d971
VJ
1894 BUG_ON(len > (uint32_t)d->len);
1895 }
1896 SCLogDebug("len %u", len);
1897
94e25276 1898 HtpBodyAppendChunk(tx_ud, &tx_ud->response_body, (uint8_t *)d->data, len);
b402d971 1899
48cf0585 1900 HtpResponseBodyHandle(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len);
b402d971
VJ
1901 }
1902
1903 /* see if we can get rid of htp body chunks */
48cf0585 1904 HtpBodyPrune(&tx_ud->response_body);
6ebe7b7c 1905
a0ee6ade
VJ
1906 /* set the new chunk flag */
1907 hstate->flags |= HTP_FLAG_NEW_BODY_SET;
1908
48cf0585 1909 SCReturnInt(HTP_OK);
0165b3f0
PR
1910}
1911
fc2f7f29
GS
1912/**
1913 * \brief Print the stats of the HTTP requests
1914 */
1915void HTPAtExitPrintStats(void)
1916{
1917#ifdef DEBUG
a9cdd2bb 1918 SCEnter();
fc2f7f29
GS
1919 SCMutexLock(&htp_state_mem_lock);
1920 SCLogDebug("http_state_memcnt %"PRIu64", http_state_memuse %"PRIu64"",
1921 htp_state_memcnt, htp_state_memuse);
1922 SCMutexUnlock(&htp_state_mem_lock);
a9cdd2bb 1923 SCReturn;
fc2f7f29
GS
1924#endif
1925}
1926
1927/** \brief Clears the HTTP server configuration memory used by HTP library */
1928void HTPFreeConfig(void)
1929{
a9cdd2bb
BR
1930 SCEnter();
1931
429c6388
AS
1932 if (!AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "http") ||
1933 !AppLayerParserConfParserEnabled("tcp", "http"))
1934 {
ddde572f 1935 SCReturn;
429c6388 1936 }
ddde572f 1937
a9cdd2bb
BR
1938 HTPCfgRec *nextrec = cfglist.next;
1939 SCRadixReleaseRadixTree(cfgtree);
7f8d256e 1940 cfgtree = NULL;
a0fa924c 1941 htp_config_destroy(cfglist.cfg);
a9cdd2bb
BR
1942 while (nextrec != NULL) {
1943 HTPCfgRec *htprec = nextrec;
47a47e8a 1944 nextrec = nextrec->next;
a9cdd2bb 1945
a0fa924c 1946 htp_config_destroy(htprec->cfg);
a9cdd2bb 1947 SCFree(htprec);
a9cdd2bb
BR
1948 }
1949 SCReturn;
fc2f7f29
GS
1950}
1951
356a8bf3
GS
1952/**
1953 * \brief callback for request to store the recent incoming request
1954 in to the recent_in_tx for the given htp state
1955 * \param connp pointer to the current connection parser which has the htp
1956 * state in it as user data
1957 */
8f1d7503
KS
1958static int HTPCallbackRequest(htp_tx_t *tx)
1959{
356a8bf3 1960 SCEnter();
187949b9 1961
2b734b8d
VJ
1962 if (tx == NULL) {
1963 SCReturnInt(HTP_ERROR);
1964 }
1965
48cf0585 1966 HtpState *hstate = htp_connp_get_user_data(tx->connp);
187949b9 1967 if (hstate == NULL) {
48cf0585 1968 SCReturnInt(HTP_ERROR);
187949b9 1969 }
70b32f73 1970
d4d18e31
AS
1971 SCLogDebug("transaction_cnt %"PRIu64", list_size %"PRIu64,
1972 hstate->transaction_cnt, HTPStateGetTxCnt(hstate));
70b32f73
VJ
1973
1974 SCLogDebug("HTTP request completed");
1975
2b734b8d 1976 HTPErrorCheckTxRequestFlags(hstate, tx);
43b39d33 1977
2b734b8d
VJ
1978 HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
1979 if (htud != NULL) {
1980 if (htud->tsflags & HTP_FILENAME_SET) {
1981 SCLogDebug("closing file that was being stored");
1982 (void)HTPFileClose(hstate, NULL, 0, 0, STREAM_TOSERVER);
1983 htud->tsflags &= ~HTP_FILENAME_SET;
403b2788
VJ
1984 }
1985 }
1986
16cfae2f
VJ
1987 /* request done, do raw reassembly now to inspect state and stream
1988 * at the same time. */
429c6388 1989 AppLayerParserTriggerRawStreamReassembly(hstate->f);
48cf0585 1990 SCReturnInt(HTP_OK);
356a8bf3
GS
1991}
1992
1993/**
1994 * \brief callback for response to remove the recent received requests
1995 from the recent_in_tx for the given htp state
1996 * \param connp pointer to the current connection parser which has the htp
1997 * state in it as user data
1998 */
8f1d7503
KS
1999static int HTPCallbackResponse(htp_tx_t *tx)
2000{
356a8bf3 2001 SCEnter();
187949b9 2002
48cf0585 2003 HtpState *hstate = htp_connp_get_user_data(tx->connp);
187949b9 2004 if (hstate == NULL) {
48cf0585 2005 SCReturnInt(HTP_ERROR);
187949b9 2006 }
356a8bf3 2007
b406af45
AS
2008 /* we have one whole transaction now */
2009 hstate->transaction_cnt++;
2010
06a65cb4
PR
2011 /* Unset the body inspection (if any) */
2012 hstate->flags &=~ HTP_FLAG_NEW_BODY_SET;
0165b3f0 2013
76d3cb55
VJ
2014 HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
2015 if (htud != NULL) {
2016 if (htud->tcflags & HTP_FILENAME_SET) {
2017 SCLogDebug("closing file that was being stored");
2018 (void)HTPFileClose(hstate, NULL, 0, 0, STREAM_TOCLIENT);
2019 htud->tcflags &= ~HTP_FILENAME_SET;
b402d971
VJ
2020 }
2021 }
2022
16cfae2f
VJ
2023 /* response done, do raw reassembly now to inspect state and stream
2024 * at the same time. */
429c6388 2025 AppLayerParserTriggerRawStreamReassembly(hstate->f);
48cf0585 2026 SCReturnInt(HTP_OK);
356a8bf3
GS
2027}
2028
48cf0585
AS
2029static int HTPCallbackRequestLine(htp_tx_t *tx)
2030{
2031 HtpTxUserData *tx_ud;
2032 bstr *request_uri_normalized;
a8b971c7
VJ
2033 HtpState *hstate = htp_connp_get_user_data(tx->connp);
2034 HTPCfgRec *cfg = hstate->cfg;
48cf0585 2035
a8b971c7 2036 request_uri_normalized = SCHTPGenerateNormalizedUri(tx, tx->parsed_uri, cfg->uri_include_all);
48cf0585
AS
2037 if (request_uri_normalized == NULL)
2038 return HTP_OK;
2039
0416a842
VJ
2040 tx_ud = htp_tx_get_user_data(tx);
2041 if (likely(tx_ud == NULL)) {
2042 tx_ud = HTPMalloc(sizeof(*tx_ud));
2043 if (unlikely(tx_ud == NULL)) {
2044 bstr_free(request_uri_normalized);
2045 return HTP_OK;
2046 }
2047 memset(tx_ud, 0, sizeof(*tx_ud));
2048 htp_tx_set_user_data(tx, tx_ud);
67c12c61 2049 }
0416a842
VJ
2050 if (unlikely(tx_ud->request_uri_normalized != NULL))
2051 bstr_free(tx_ud->request_uri_normalized);
48cf0585 2052 tx_ud->request_uri_normalized = request_uri_normalized;
48cf0585 2053
afaa10b3 2054 if (tx->flags) {
43b39d33
VJ
2055 HTPErrorCheckTxRequestFlags(hstate, tx);
2056 }
48cf0585
AS
2057 return HTP_OK;
2058}
2059
2060static int HTPCallbackDoubleDecodeQuery(htp_tx_t *tx)
2061{
2062 if (tx->parsed_uri == NULL || tx->parsed_uri->query == NULL)
2063 return HTP_OK;
2064
2065 uint64_t flags = 0;
2066 htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, tx->parsed_uri->query, &flags);
2067
2068 return HTP_OK;
2069}
2070
2071static int HTPCallbackDoubleDecodePath(htp_tx_t *tx)
2072{
2073 if (tx->parsed_uri == NULL || tx->parsed_uri->path == NULL)
2074 return HTP_OK;
2075
2076 uint64_t flags = 0;
2077 htp_urldecode_inplace(tx->cfg, HTP_DECODER_URL_PATH, tx->parsed_uri->path, &flags);
2078
2079 return HTP_OK;
2080}
2081
2082static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data)
2083{
1f07d152 2084 void *ptmp;
48cf0585
AS
2085 if (tx_data->len == 0)
2086 return HTP_OK;
2087
2088 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx);
2089 if (tx_ud == NULL) {
ced01da8 2090 tx_ud = HTPMalloc(sizeof(*tx_ud));
79fcf137 2091 if (unlikely(tx_ud == NULL))
48cf0585
AS
2092 return HTP_OK;
2093 memset(tx_ud, 0, sizeof(*tx_ud));
2094 htp_tx_set_user_data(tx_data->tx, tx_ud);
2095 }
ced01da8
EL
2096 ptmp = HTPRealloc(tx_ud->request_headers_raw,
2097 tx_ud->request_headers_raw_len,
1f07d152
EL
2098 tx_ud->request_headers_raw_len + tx_data->len);
2099 if (ptmp == NULL) {
ced01da8 2100 HTPFree(tx_ud->request_headers_raw, tx_ud->request_headers_raw_len);
1f07d152 2101 tx_ud->request_headers_raw = NULL;
48cf0585 2102 tx_ud->request_headers_raw_len = 0;
6f2cb141 2103 HtpTxUserDataFree(tx_ud);
48cf0585 2104 htp_tx_set_user_data(tx_data->tx, NULL);
48cf0585
AS
2105 return HTP_OK;
2106 }
1f07d152
EL
2107 tx_ud->request_headers_raw = ptmp;
2108
48cf0585
AS
2109 memcpy(tx_ud->request_headers_raw + tx_ud->request_headers_raw_len,
2110 tx_data->data, tx_data->len);
2111 tx_ud->request_headers_raw_len += tx_data->len;
2112
43b39d33
VJ
2113 if (tx_data->tx && tx_data->tx->flags) {
2114 HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp);
2115 HTPErrorCheckTxRequestFlags(hstate, tx_data->tx);
2116 }
48cf0585
AS
2117 return HTP_OK;
2118}
2119
2120static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data)
2121{
1f07d152 2122 void *ptmp;
48cf0585
AS
2123 if (tx_data->len == 0)
2124 return HTP_OK;
2125
2126 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx);
2127 if (tx_ud == NULL) {
ced01da8 2128 tx_ud = HTPMalloc(sizeof(*tx_ud));
79fcf137 2129 if (unlikely(tx_ud == NULL))
48cf0585
AS
2130 return HTP_OK;
2131 memset(tx_ud, 0, sizeof(*tx_ud));
2132 htp_tx_set_user_data(tx_data->tx, tx_ud);
2133 }
ced01da8
EL
2134 ptmp = HTPRealloc(tx_ud->response_headers_raw,
2135 tx_ud->response_headers_raw_len,
1f07d152
EL
2136 tx_ud->response_headers_raw_len + tx_data->len);
2137 if (ptmp == NULL) {
ced01da8 2138 HTPFree(tx_ud->response_headers_raw, tx_ud->response_headers_raw_len);
1f07d152 2139 tx_ud->response_headers_raw = NULL;
48cf0585 2140 tx_ud->response_headers_raw_len = 0;
6f2cb141 2141 HtpTxUserDataFree(tx_ud);
48cf0585 2142 htp_tx_set_user_data(tx_data->tx, NULL);
48cf0585
AS
2143 return HTP_OK;
2144 }
1f07d152
EL
2145 tx_ud->response_headers_raw = ptmp;
2146
48cf0585
AS
2147 memcpy(tx_ud->response_headers_raw + tx_ud->response_headers_raw_len,
2148 tx_data->data, tx_data->len);
2149 tx_ud->response_headers_raw_len += tx_data->len;
2150
2151 return HTP_OK;
2152}
2153
2154/*
2155 * We have a similar set function called HTPConfigSetDefaultsPhase1.
2156 */
2157static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec)
a9cdd2bb 2158{
a8b971c7 2159 cfg_prec->uri_include_all = FALSE;
340542c4
AS
2160 cfg_prec->request_body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT;
2161 cfg_prec->response_body_limit = HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT;
2763a612
VJ
2162 cfg_prec->request_inspect_min_size = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE;
2163 cfg_prec->request_inspect_window = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW;
2164 cfg_prec->response_inspect_min_size = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE;
2165 cfg_prec->response_inspect_window = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW;
ff784075
EL
2166 cfg_prec->randomize = HTP_CONFIG_DEFAULT_RANDOMIZE;
2167 cfg_prec->randomize_range = HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE;
48cf0585
AS
2168
2169 htp_config_register_request_header_data(cfg_prec->cfg, HTPCallbackRequestHeaderData);
2170 htp_config_register_request_trailer_data(cfg_prec->cfg, HTPCallbackRequestHeaderData);
2171 htp_config_register_response_header_data(cfg_prec->cfg, HTPCallbackResponseHeaderData);
2172 htp_config_register_response_trailer_data(cfg_prec->cfg, HTPCallbackResponseHeaderData);
2173
340542c4
AS
2174 htp_config_register_request_body_data(cfg_prec->cfg, HTPCallbackRequestBodyData);
2175 htp_config_register_response_body_data(cfg_prec->cfg, HTPCallbackResponseBodyData);
a9cdd2bb 2176
48cf0585
AS
2177 htp_config_register_request_complete(cfg_prec->cfg, HTPCallbackRequest);
2178 htp_config_register_response_complete(cfg_prec->cfg, HTPCallbackResponse);
2179
2180 htp_config_set_parse_request_cookies(cfg_prec->cfg, 0);
2181 htp_config_set_parse_request_auth(cfg_prec->cfg, 0);
2182
9a7353e1
VJ
2183 /* don't convert + to space by default */
2184 htp_config_set_plusspace_decode(cfg_prec->cfg, HTP_DECODER_URLENCODED, 0);
2185
fb496791
VJ
2186 /* libhtp <= 0.5.9 doesn't use soft limit, but it's impossible to set
2187 * only the hard limit. So we set both here to the (current) htp defaults.
2188 * The reason we do this is that if the user sets the hard limit in the
2189 * config, we have to set the soft limit as well. If libhtp starts using
2190 * the soft limit in the future, we at least make sure we control what
2191 * it's value is. */
2192 htp_config_set_field_limits(cfg_prec->cfg,
2193 (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT,
2194 (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_HARD);
48cf0585
AS
2195 return;
2196}
2197
2198/*
2199 * We have this splitup so that in case double decoding has been enabled
2200 * for query and path, they would be called first on the callback queue,
2201 * before the callback set by Phase2() is called. We need this, since
2202 * the callback in Phase2() generates the normalized uri which utilizes
2203 * the query and path. */
72954067 2204static void HTPConfigSetDefaultsPhase2(char *name, HTPCfgRec *cfg_prec)
48cf0585 2205{
ff784075
EL
2206 /* randomize inspection size if needed */
2207 if (cfg_prec->randomize) {
2208 int rdrange = cfg_prec->randomize_range;
2209
2210 cfg_prec->request_inspect_min_size +=
2211 (int) (cfg_prec->request_inspect_min_size *
2212 (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
2213 cfg_prec->request_inspect_window +=
2214 (int) (cfg_prec->request_inspect_window *
2215 (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
72954067
EL
2216 SCLogInfo("'%s' server has 'request-body-minimal-inspect-size' set to"
2217 " %d and 'request-body-inspect-window' set to %d after"
2218 " randomization.",
2219 name,
2220 cfg_prec->request_inspect_min_size,
2221 cfg_prec->request_inspect_window);
2222
ff784075
EL
2223
2224 cfg_prec->response_inspect_min_size +=
2225 (int) (cfg_prec->response_inspect_min_size *
2226 (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
2227 cfg_prec->response_inspect_window +=
2228 (int) (cfg_prec->response_inspect_window *
2229 (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
72954067
EL
2230
2231 SCLogInfo("'%s' server has 'response-body-minimal-inspect-size' set to"
2232 " %d and 'response-body-inspect-window' set to %d after"
2233 " randomization.",
2234 name,
2235 cfg_prec->response_inspect_min_size,
2236 cfg_prec->response_inspect_window);
ff784075
EL
2237 }
2238
48cf0585
AS
2239 htp_config_register_request_line(cfg_prec->cfg, HTPCallbackRequestLine);
2240
340542c4
AS
2241 return;
2242}
a9cdd2bb 2243
028c6c17 2244static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s,
340542c4
AS
2245 SCRadixTree *tree)
2246{
028c6c17 2247 if (cfg_prec == NULL || s == NULL || tree == NULL)
340542c4 2248 return;
a9cdd2bb 2249
340542c4
AS
2250 ConfNode *p = NULL;
2251
2252 /* Default Parameters */
028c6c17 2253 TAILQ_FOREACH(p, &s->head, next) {
340542c4
AS
2254
2255 if (strcasecmp("address", p->name) == 0) {
2256 ConfNode *pval;
2257 /* Addresses */
2258 TAILQ_FOREACH(pval, &p->head, next) {
2259 SCLogDebug("LIBHTP server %s: %s=%s", s->name, p->name,
2260 pval->val);
2261
2262 /* IPV6 or IPV4? */
2263 if (strchr(pval->val, ':') != NULL) {
2264 SCLogDebug("LIBHTP adding ipv6 server %s at %s: %p",
028c6c17 2265 s->name, pval->val, cfg_prec->cfg);
340542c4
AS
2266 if (SCRadixAddKeyIPV6String(pval->val, tree, cfg_prec) == NULL) {
2267 SCLogWarning(SC_ERR_INVALID_VALUE, "LIBHTP failed to "
2268 "add ipv6 server %s, ignoring", pval->val);
2269 }
2270 } else {
2271 SCLogDebug("LIBHTP adding ipv4 server %s at %s: %p",
028c6c17 2272 s->name, pval->val, cfg_prec->cfg);
340542c4
AS
2273 if (SCRadixAddKeyIPV4String(pval->val, tree, cfg_prec) == NULL) {
2274 SCLogWarning(SC_ERR_INVALID_VALUE, "LIBHTP failed "
2275 "to add ipv4 server %s, ignoring",
2276 pval->val);
2277 }
2278 } /* else - if (strchr(pval->val, ':') != NULL) */
2279 } /* TAILQ_FOREACH(pval, &p->head, next) */
2280
2281 } else if (strcasecmp("personality", p->name) == 0) {
2282 /* Personalities */
2283 int personality = HTPLookupPersonality(p->val);
2284 SCLogDebug("LIBHTP default: %s = %s", p->name, p->val);
2285 SCLogDebug("LIBHTP default: %s = %s", p->name, p->val);
2286
2287 if (personality >= 0) {
2288 SCLogDebug("LIBHTP default: %s=%s (%d)", p->name, p->val,
2289 personality);
2290 if (htp_config_set_server_personality(cfg_prec->cfg, personality) == HTP_ERROR){
2291 SCLogWarning(SC_ERR_INVALID_VALUE, "LIBHTP Failed adding "
2292 "personality \"%s\", ignoring", p->val);
2293 } else {
2294 SCLogDebug("LIBHTP personality set to %s",
2295 HTPLookupPersonalityString(personality));
2296 }
a9cdd2bb 2297
340542c4
AS
2298 /* The IDS personality by default converts the path (and due to
2299 * our query string callback also the query string) to lowercase.
2300 * Signatures do not expect this, so override it. */
48cf0585 2301 htp_config_set_convert_lowercase(cfg_prec->cfg, HTP_DECODER_URL_PATH, 0);
340542c4
AS
2302 } else {
2303 SCLogWarning(SC_ERR_UNKNOWN_VALUE, "LIBHTP Unknown personality "
2304 "\"%s\", ignoring", p->val);
2305 continue;
2306 }
a9cdd2bb 2307
340542c4
AS
2308 } else if (strcasecmp("request-body-limit", p->name) == 0 ||
2309 strcasecmp("request_body_limit", p->name) == 0) {
2310 if (ParseSizeStringU32(p->val, &cfg_prec->request_body_limit) < 0) {
2311 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-limit "
2312 "from conf file - %s. Killing engine", p->val);
2313 exit(EXIT_FAILURE);
2314 }
a9cdd2bb 2315
340542c4
AS
2316 } else if (strcasecmp("response-body-limit", p->name) == 0) {
2317 if (ParseSizeStringU32(p->val, &cfg_prec->response_body_limit) < 0) {
2318 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-limit "
2319 "from conf file - %s. Killing engine", p->val);
2320 exit(EXIT_FAILURE);
2321 }
48cf0585 2322
2763a612
VJ
2323 } else if (strcasecmp("request-body-minimal-inspect-size", p->name) == 0) {
2324 if (ParseSizeStringU32(p->val, &cfg_prec->request_inspect_min_size) < 0) {
2325 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-minimal-inspect-size "
2326 "from conf file - %s. Killing engine", p->val);
2327 exit(EXIT_FAILURE);
2328 }
2329
2330 } else if (strcasecmp("request-body-inspect-window", p->name) == 0) {
2331 if (ParseSizeStringU32(p->val, &cfg_prec->request_inspect_window) < 0) {
2332 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-inspect-window "
2333 "from conf file - %s. Killing engine", p->val);
2334 exit(EXIT_FAILURE);
2335 }
2336
48cf0585
AS
2337 } else if (strcasecmp("double-decode-path", p->name) == 0) {
2338 if (ConfValIsTrue(p->val)) {
2339 htp_config_register_request_line(cfg_prec->cfg,
2340 HTPCallbackDoubleDecodeQuery);
2341 }
2342
2343 } else if (strcasecmp("double-decode-query", p->name) == 0) {
2344 if (ConfValIsTrue(p->val)) {
2345 htp_config_register_request_line(cfg_prec->cfg,
2346 HTPCallbackDoubleDecodePath);
2347 }
2348
2763a612
VJ
2349 } else if (strcasecmp("response-body-minimal-inspect-size", p->name) == 0) {
2350 if (ParseSizeStringU32(p->val, &cfg_prec->response_inspect_min_size) < 0) {
2351 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-minimal-inspect-size "
2352 "from conf file - %s. Killing engine", p->val);
2353 exit(EXIT_FAILURE);
2354 }
2355
2356 } else if (strcasecmp("response-body-inspect-window", p->name) == 0) {
2357 if (ParseSizeStringU32(p->val, &cfg_prec->response_inspect_window) < 0) {
2358 SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-inspect-window "
2359 "from conf file - %s. Killing engine", p->val);
2360 exit(EXIT_FAILURE);
2361 }
bde55578 2362
48cf0585
AS
2363 } else if (strcasecmp("path-convert-backslash-separators", p->name) == 0) {
2364 htp_config_set_backslash_convert_slashes(cfg_prec->cfg,
2365 HTP_DECODER_URL_PATH,
2366 ConfValIsTrue(p->val));
2367 } else if (strcasecmp("path-bestfit-replacement-char", p->name) == 0) {
2368 if (strlen(p->val) == 1) {
2369 htp_config_set_bestfit_replacement_byte(cfg_prec->cfg,
2370 HTP_DECODER_URL_PATH,
2371 p->val[0]);
028c6c17
AS
2372 } else {
2373 SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry "
48cf0585 2374 "for libhtp param path-bestfit-replacement-char");
028c6c17 2375 }
48cf0585
AS
2376 } else if (strcasecmp("path-convert-lowercase", p->name) == 0) {
2377 htp_config_set_convert_lowercase(cfg_prec->cfg,
2378 HTP_DECODER_URL_PATH,
2379 ConfValIsTrue(p->val));
2380 } else if (strcasecmp("path-nul-encoded-terminates", p->name) == 0) {
2381 htp_config_set_nul_encoded_terminates(cfg_prec->cfg,
2382 HTP_DECODER_URL_PATH,
2383 ConfValIsTrue(p->val));
2384 } else if (strcasecmp("path-nul-raw-terminates", p->name) == 0) {
2385 htp_config_set_nul_raw_terminates(cfg_prec->cfg,
2386 HTP_DECODER_URL_PATH,
2387 ConfValIsTrue(p->val));
2388 } else if (strcasecmp("path-separators-compress", p->name) == 0) {
2389 htp_config_set_path_separators_compress(cfg_prec->cfg,
2390 HTP_DECODER_URL_PATH,
2391 ConfValIsTrue(p->val));
2392 } else if (strcasecmp("path-separators-decode", p->name) == 0) {
2393 htp_config_set_path_separators_decode(cfg_prec->cfg,
2394 HTP_DECODER_URL_PATH,
2395 ConfValIsTrue(p->val));
2396 } else if (strcasecmp("path-u-encoding-decode", p->name) == 0) {
2397 htp_config_set_u_encoding_decode(cfg_prec->cfg,
2398 HTP_DECODER_URL_PATH,
2399 ConfValIsTrue(p->val));
2400 } else if (strcasecmp("path-url-encoding-invalid-handling", p->name) == 0) {
2401 enum htp_url_encoding_handling_t handling;
028c6c17 2402 if (strcasecmp(p->val, "preserve_percent") == 0) {
48cf0585 2403 handling = HTP_URL_DECODE_PRESERVE_PERCENT;
028c6c17 2404 } else if (strcasecmp(p->val, "remove_percent") == 0) {
48cf0585 2405 handling = HTP_URL_DECODE_REMOVE_PERCENT;
028c6c17 2406 } else if (strcasecmp(p->val, "decode_invalid") == 0) {
48cf0585 2407 handling = HTP_URL_DECODE_PROCESS_INVALID;
028c6c17
AS
2408 } else {
2409 SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry "
48cf0585
AS
2410 "for libhtp param path-url-encoding-invalid-handling");
2411 return;
028c6c17 2412 }
48cf0585
AS
2413 htp_config_set_url_encoding_invalid_handling(cfg_prec->cfg,
2414 HTP_DECODER_URL_PATH,
2415 handling);
2416 } else if (strcasecmp("path-utf8-convert-bestfit", p->name) == 0) {
2417 htp_config_set_utf8_convert_bestfit(cfg_prec->cfg,
2418 HTP_DECODER_URL_PATH,
2419 ConfValIsTrue(p->val));
a8b971c7
VJ
2420 } else if (strcasecmp("uri-include-all", p->name) == 0) {
2421 cfg_prec->uri_include_all = ConfValIsTrue(p->val);
2422 SCLogDebug("uri-include-all %s",
2423 cfg_prec->uri_include_all ? "enabled" : "disabled");
9a7353e1
VJ
2424 } else if (strcasecmp("query-plusspace-decode", p->name) == 0) {
2425 htp_config_set_plusspace_decode(cfg_prec->cfg,
2426 HTP_DECODER_URLENCODED,
2427 ConfValIsTrue(p->val));
fb496791
VJ
2428 } else if (strcasecmp("meta-field-limit", p->name) == 0) {
2429 uint32_t limit = 0;
2430 if (ParseSizeStringU32(p->val, &limit) < 0) {
2431 SCLogError(SC_ERR_SIZE_PARSE, "Error meta-field-limit "
2432 "from conf file - %s. Killing engine", p->val);
2433 exit(EXIT_FAILURE);
2434 }
2435 if (limit == 0) {
2436 SCLogError(SC_ERR_SIZE_PARSE, "Error meta-field-limit "
2437 "from conf file cannot be 0. Killing engine");
2438 exit(EXIT_FAILURE);
2439 }
2440 /* set default soft-limit with our new hard limit */
2441 htp_config_set_field_limits(cfg_prec->cfg,
2442 (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT,
2443 (size_t)limit);
ff784075
EL
2444 } else if (strcasecmp("randomize-inspection-sizes", p->name) == 0) {
2445 cfg_prec->randomize = ConfValIsTrue(p->val);
2446 } else if (strcasecmp("randomize-inspection-range", p->name) == 0) {
2447 uint32_t range = atoi(p->val);
2448 if (range > 100) {
2449 SCLogError(SC_ERR_SIZE_PARSE, "Invalid value for randomize"
2450 " inspection range setting from conf file - %s."
2451 " It should be inferior to 100."
2452 " Killing engine",
2453 p->val);
2454 exit(EXIT_FAILURE);
2455 }
2456 cfg_prec->randomize_range = range;
340542c4
AS
2457 } else {
2458 SCLogWarning(SC_ERR_UNKNOWN_VALUE, "LIBHTP Ignoring unknown "
2459 "default config: %s", p->name);
a9cdd2bb 2460 }
340542c4
AS
2461 } /* TAILQ_FOREACH(p, &default_config->head, next) */
2462
2463 return;
2464}
2465
ab4b15c2 2466void HTPConfigure(void)
340542c4
AS
2467{
2468 SCEnter();
2469
2470 cfglist.next = NULL;
2471
2472 cfgtree = SCRadixCreateRadixTree(NULL, NULL);
2473 if (NULL == cfgtree)
2474 exit(EXIT_FAILURE);
2475
2476 /* Default Config */
2477 cfglist.cfg = htp_config_create();
2478 if (NULL == cfglist.cfg) {
2479 SCLogError(SC_ERR_MEM_ALLOC, "Failed to create HTP default config");
2480 exit(EXIT_FAILURE);
a9cdd2bb 2481 }
340542c4 2482 SCLogDebug("LIBHTP default config: %p", cfglist.cfg);
48cf0585 2483 HTPConfigSetDefaultsPhase1(&cfglist);
ddde572f
AS
2484 if (ConfGetNode("app-layer.protocols.http.libhtp") == NULL) {
2485 HTPConfigParseParameters(&cfglist, ConfGetNode("libhtp.default-config"),
2486 cfgtree);
2487 } else {
2488 HTPConfigParseParameters(&cfglist, ConfGetNode("app-layer.protocols.http.libhtp.default-config"), cfgtree);
2489 }
72954067 2490 HTPConfigSetDefaultsPhase2("default", &cfglist);
a9cdd2bb 2491
ced01da8
EL
2492 HTPParseMemcap();
2493
a9cdd2bb 2494 /* Read server config and create a parser for each IP in radix tree */
ddde572f
AS
2495 ConfNode *server_config = ConfGetNode("app-layer.protocols.http.libhtp.server-config");
2496 if (server_config == NULL) {
2497 server_config = ConfGetNode("libhtp.server-config");
2498 if (server_config == NULL) {
2499 SCLogDebug("LIBHTP Configuring %p", server_config);
2500 SCReturn;
2501 }
2502 }
a9cdd2bb 2503 SCLogDebug("LIBHTP Configuring %p", server_config);
a9cdd2bb 2504
340542c4
AS
2505 ConfNode *si;
2506 /* Server Nodes */
2507 TAILQ_FOREACH(si, &server_config->head, next) {
2508 /* Need the named node, not the index */
2509 ConfNode *s = TAILQ_FIRST(&si->head);
2510 if (NULL == s) {
2511 SCLogDebug("LIBHTP s NULL");
2512 continue;
2513 }
a9cdd2bb 2514
340542c4 2515 SCLogDebug("LIBHTP server %s", s->name);
a9cdd2bb 2516
340542c4 2517 HTPCfgRec *nextrec = cfglist.next;
28c5c681 2518 HTPCfgRec *htprec = SCMalloc(sizeof(HTPCfgRec));
340542c4
AS
2519 if (NULL == htprec)
2520 exit(EXIT_FAILURE);
a8b971c7
VJ
2521 memset(htprec, 0x00, sizeof(*htprec));
2522
28c5c681
EL
2523 cfglist.next = htprec;
2524
340542c4
AS
2525 cfglist.next->next = nextrec;
2526 cfglist.next->cfg = htp_config_create();
2527 if (NULL == cfglist.next->cfg) {
2528 SCLogError(SC_ERR_MEM_ALLOC, "Failed to create HTP server config");
2529 exit(EXIT_FAILURE);
2530 }
bde55578 2531
48cf0585 2532 HTPConfigSetDefaultsPhase1(htprec);
340542c4 2533 HTPConfigParseParameters(htprec, s, cfgtree);
72954067 2534 HTPConfigSetDefaultsPhase2(s->name, htprec);
a9cdd2bb
BR
2535 }
2536
2537 SCReturn;
2538}
2539
8f1d7503
KS
2540void AppLayerHtpPrintStats(void)
2541{
6fca55e0
VJ
2542#ifdef DEBUG
2543 SCMutexLock(&htp_state_mem_lock);
2544 SCLogInfo("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
2545 SCMutexUnlock(&htp_state_mem_lock);
2546#endif
2547}
2548
d59ca75e
VJ
2549/** \internal
2550 * \brief get files callback
2551 * \param state state ptr
2552 * \param direction flow direction
2553 * \retval files files ptr
2554 */
8f1d7503
KS
2555static FileContainer *HTPStateGetFiles(void *state, uint8_t direction)
2556{
e1022ee5
VJ
2557 if (state == NULL)
2558 return NULL;
2559
2560 HtpState *http_state = (HtpState *)state;
d59ca75e
VJ
2561
2562 if (direction & STREAM_TOCLIENT) {
2563 SCReturnPtr(http_state->files_tc, "FileContainer");
2564 } else {
2565 SCReturnPtr(http_state->files_ts, "FileContainer");
2566 }
e1022ee5
VJ
2567}
2568
d4d18e31
AS
2569static int HTPStateGetAlstateProgress(void *tx, uint8_t direction)
2570{
429c6388 2571 if (direction & STREAM_TOSERVER)
080c15b3
VJ
2572 return ((htp_tx_t *)tx)->request_progress;
2573 else
2574 return ((htp_tx_t *)tx)->response_progress;
d4d18e31
AS
2575}
2576
2577static uint64_t HTPStateGetTxCnt(void *alstate)
2578{
896b6145
VJ
2579 HtpState *http_state = (HtpState *)alstate;
2580
2581 if (http_state != NULL && http_state->conn != NULL)
2582 return (uint64_t)htp_list_size(http_state->conn->transactions);
2583 else
2584 return 0ULL;
d4d18e31
AS
2585}
2586
2587static void *HTPStateGetTx(void *alstate, uint64_t tx_id)
2588{
896b6145
VJ
2589 HtpState *http_state = (HtpState *)alstate;
2590
2591 if (http_state != NULL && http_state->conn != NULL)
2592 return htp_list_get(http_state->conn->transactions, tx_id);
2593 else
2594 return NULL;
d4d18e31
AS
2595}
2596
2597static int HTPStateGetAlstateProgressCompletionStatus(uint8_t direction)
2598{
429c6388 2599 return (direction & STREAM_TOSERVER) ? HTP_REQUEST_COMPLETE : HTP_RESPONSE_COMPLETE;
d4d18e31
AS
2600}
2601
5e2d9dbd
AS
2602int HTPStateGetEventInfo(const char *event_name,
2603 int *event_id, AppLayerEventType *event_type)
2604{
2605 *event_id = SCMapEnumNameToValue(event_name, http_decoder_event_table);
2606 if (*event_id == -1) {
2607 SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
2608 "http's enum map table.", event_name);
2609 /* this should be treated as fatal */
2610 return -1;
2611 }
2612
3f5acc54 2613 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
5e2d9dbd
AS
2614
2615 return 0;
2616}
2617
429c6388
AS
2618static void HTPStateTruncate(void *state, uint8_t direction)
2619{
2620 FileContainer *fc = HTPStateGetFiles(state, direction);
869109a6
VJ
2621 if (fc != NULL) {
2622 FileTruncateAllOpenFiles(fc);
2623 }
2624}
2625
429c6388
AS
2626static int HTPRegisterPatternsForProtocolDetection(void)
2627{
2628 /* toserver */
2629 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2630 "GET|20|", 4, 0, STREAM_TOSERVER) < 0)
2631 {
2632 return -1;
2633 }
2634 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2635 "GET|09|", 4, 0, STREAM_TOSERVER) < 0)
2636 {
2637 return -1;
2638 }
2639 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2640 "PUT|20|", 4, 0, STREAM_TOSERVER) < 0)
2641 {
2642 return -1;
2643 }
2644 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2645 "PUT|09|", 4, 0, STREAM_TOSERVER) < 0)
2646 {
2647 return -1;
2648 }
2649 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2650 "POST|20|", 5, 0, STREAM_TOSERVER) < 0)
2651 {
2652 return -1;
2653 }
2654 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2655 "POST|09|", 5, 0, STREAM_TOSERVER) < 0)
2656 {
2657 return -1;
2658 }
2659 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2660 "HEAD|20|", 5, 0, STREAM_TOSERVER) < 0)
2661 {
2662 return -1;
2663 }
2664 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2665 "HEAD|09|", 5, 0, STREAM_TOSERVER) < 0)
2666 {
2667 return -1;
2668 }
2669 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2670 "TRACE|20|", 6, 0, STREAM_TOSERVER) < 0)
2671 {
2672 return -1;
2673 }
2674 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2675 "TRACE|09|", 6, 0, STREAM_TOSERVER) < 0)
2676 {
2677 return -1;
2678 }
2679 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2680 "OPTIONS|20|", 8, 0, STREAM_TOSERVER) < 0)
2681 {
2682 return -1;
2683 }
2684 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2685 "OPTIONS|09|", 8, 0, STREAM_TOSERVER) < 0)
2686 {
2687 return -1;
2688 }
2689 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2690 "CONNECT|20|", 8, 0, STREAM_TOSERVER) < 0)
2691 {
2692 return -1;
2693 }
2694 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2695 "CONNECT|09|", 8, 0, STREAM_TOSERVER) < 0)
2696 {
2697 return -1;
2698 }
2699
2700 /* toclient */
2701 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2702 "HTTP/0.9", 8, 0, STREAM_TOCLIENT) < 0)
2703 {
2704 return -1;
2705 }
2706 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2707 "HTTP/1.0", 8, 0, STREAM_TOCLIENT) < 0)
2708 {
2709 return -1;
2710 }
2711 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP,
2712 "HTTP/1.1", 8, 0, STREAM_TOCLIENT) < 0)
2713 {
2714 return -1;
2715 }
2716
2717 return 0;
2718}
2719
07f7ba55
GS
2720/**
2721 * \brief Register the HTTP protocol and state handling functions to APP layer
2722 * of the engine.
2723 */
2724void RegisterHTPParsers(void)
2725{
a9cdd2bb 2726 SCEnter();
000ce98c 2727
10966245
AS
2728 char *proto_name = "http";
2729
000ce98c 2730 /** HTTP */
429c6388
AS
2731 if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
2732 AppLayerProtoDetectRegisterProtocol(ALPROTO_HTTP, proto_name);
2733 if (HTPRegisterPatternsForProtocolDetection() < 0)
2734 return;
ddde572f
AS
2735 } else {
2736 SCLogInfo("Protocol detection and parser disabled for %s protocol",
2737 proto_name);
2738 return;
2739 }
2740
429c6388
AS
2741 if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
2742 AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_HTTP, HTPStateAlloc, HTPStateFree);
2743 AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateTransactionFree);
2744 AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetFiles);
2745 AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetAlstateProgress);
2746 AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTxCnt);
2747 AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTx);
2748 AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_HTTP,
2749 HTPStateGetAlstateProgressCompletionStatus);
3f5acc54
VJ
2750 AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPHasEvents);
2751 AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPGetEvents);
429c6388 2752 AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetEventInfo);
ddde572f 2753
429c6388 2754 AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateTruncate);
ddde572f 2755
429c6388
AS
2756 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_HTTP, STREAM_TOSERVER,
2757 HTPHandleRequestData);
2758 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_HTTP, STREAM_TOCLIENT,
2759 HTPHandleResponseData);
ddde572f 2760 SC_ATOMIC_INIT(htp_config_flags);
429c6388 2761 AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_HTTP, STREAM_TOSERVER);
ddde572f
AS
2762 HTPConfigure();
2763 } else {
2764 SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
2765 "still on.", proto_name);
2766 }
9faa4b74 2767#ifdef UNITTESTS
429c6388 2768 AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_HTTP, HTPParserRegisterTests);
9faa4b74 2769#endif
07f7ba55 2770
a9cdd2bb 2771 SCReturn;
07f7ba55
GS
2772}
2773
c352bff6 2774#ifdef UNITTESTS
99fca038
VJ
2775static HTPCfgRec cfglist_backup;
2776
ab4b15c2 2777void HtpConfigCreateBackup(void)
99fca038 2778{
dcdcbd97 2779 cfglist_backup = cfglist;
99fca038
VJ
2780
2781 return;
2782}
2783
ab4b15c2 2784void HtpConfigRestoreBackup(void)
99fca038 2785{
dcdcbd97 2786 cfglist = cfglist_backup;
99fca038
VJ
2787
2788 return;
2789}
a9cdd2bb 2790
07f7ba55
GS
2791/** \test Test case where chunks are sent in smaller chunks and check the
2792 * response of the parser from HTP library. */
8f1d7503
KS
2793int HTPParserTest01(void)
2794{
07f7ba55 2795 int result = 1;
262a7300 2796 Flow *f = NULL;
fc2f7f29 2797 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
07f7ba55
GS
2798 " Data is c0oL!";
2799 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2800 TcpSession ssn;
25a3a5c6 2801 HtpState *htp_state = NULL;
07f7ba55 2802 int r = 0;
8dbf7a0d 2803 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
262a7300 2804
07f7ba55 2805 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
2806
2807 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2808 if (f == NULL)
2809 goto end;
2810 f->protoctx = &ssn;
429c6388 2811 f->proto = IPPROTO_TCP;
07f7ba55 2812
6a53ab9c 2813 StreamTcpInitConfig(TRUE);
6a53ab9c 2814
07f7ba55
GS
2815 uint32_t u;
2816 for (u = 0; u < httplen1; u++) {
2817 uint8_t flags = 0;
2818
59cda9a3
VJ
2819 if (u == 0)
2820 flags = STREAM_TOSERVER|STREAM_START;
2821 else if (u == (httplen1 - 1))
2822 flags = STREAM_TOSERVER|STREAM_EOF;
2823 else
2824 flags = STREAM_TOSERVER;
07f7ba55 2825
cd3e32ce 2826 SCMutexLock(&f->m);
429c6388 2827 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
07f7ba55
GS
2828 if (r != 0) {
2829 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
2830 " 0: ", u, r);
2831 result = 0;
cd3e32ce 2832 SCMutexUnlock(&f->m);
07f7ba55
GS
2833 goto end;
2834 }
cd3e32ce 2835 SCMutexUnlock(&f->m);
07f7ba55
GS
2836 }
2837
262a7300 2838 htp_state = f->alstate;
07f7ba55
GS
2839 if (htp_state == NULL) {
2840 printf("no http state: ");
2841 result = 0;
2842 goto end;
2843 }
2844
d4d18e31 2845 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
2846 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
2847 if (strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0")
2848 || tx->request_method_number != HTP_M_POST ||
2849 tx->request_protocol_number != HTP_PROTOCOL_1_0)
07f7ba55 2850 {
2d6cf71d 2851 printf("expected header value: Victor/1.0 and got %s: and expected"
fc2f7f29 2852 " method: POST and got %s, expected protocol number HTTP/1.0"
48cf0585
AS
2853 " and got: %s \n", bstr_util_strdup_to_c(h->value),
2854 bstr_util_strdup_to_c(tx->request_method),
2855 bstr_util_strdup_to_c(tx->request_protocol));
07f7ba55
GS
2856 result = 0;
2857 goto end;
2858 }
2859
2860end:
429c6388 2861 if (alp_tctx != NULL)
fdefb65b 2862 AppLayerParserThreadCtxFree(alp_tctx);
6a53ab9c 2863 StreamTcpFreeConfig(TRUE);
25a3a5c6
PR
2864 if (htp_state != NULL)
2865 HTPStateFree(htp_state);
262a7300 2866 UTHFreeFlow(f);
07f7ba55
GS
2867 return result;
2868}
2869
2d6cf71d 2870/** \test See how it deals with an incomplete request. */
8f1d7503
KS
2871int HTPParserTest02(void)
2872{
2d6cf71d 2873 int result = 1;
262a7300 2874 Flow *f = NULL;
2d6cf71d
GS
2875 uint8_t httpbuf1[] = "POST";
2876 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2877 TcpSession ssn;
25a3a5c6 2878 HtpState *http_state = NULL;
8dbf7a0d 2879 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
2d6cf71d 2880
2d6cf71d 2881 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
2882
2883 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2884 if (f == NULL)
2885 goto end;
2886 f->protoctx = &ssn;
429c6388 2887 f->proto = IPPROTO_TCP;
2d6cf71d 2888
6a53ab9c 2889 StreamTcpInitConfig(TRUE);
6a53ab9c 2890
cd3e32ce 2891 SCMutexLock(&f->m);
429c6388
AS
2892 int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|
2893 STREAM_EOF, httpbuf1, httplen1);
2d6cf71d
GS
2894 if (r != 0) {
2895 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2896 result = 0;
cd3e32ce 2897 SCMutexUnlock(&f->m);
2d6cf71d
GS
2898 goto end;
2899 }
cd3e32ce 2900 SCMutexUnlock(&f->m);
2d6cf71d 2901
262a7300 2902 http_state = f->alstate;
2d6cf71d
GS
2903 if (http_state == NULL) {
2904 printf("no http state: ");
2905 result = 0;
2906 goto end;
2907 }
2908
d4d18e31 2909 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
48cf0585 2910 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
2d6cf71d
GS
2911 if ((tx->request_method) != NULL || h != NULL)
2912 {
48cf0585 2913 printf("expected method NULL, got %s \n", bstr_util_strdup_to_c(tx->request_method));
2d6cf71d
GS
2914 result = 0;
2915 goto end;
2916 }
2917
2918end:
429c6388 2919 if (alp_tctx != NULL)
fdefb65b 2920 AppLayerParserThreadCtxFree(alp_tctx);
6a53ab9c 2921 StreamTcpFreeConfig(TRUE);
25a3a5c6
PR
2922 if (http_state != NULL)
2923 HTPStateFree(http_state);
262a7300 2924 UTHFreeFlow(f);
2d6cf71d
GS
2925 return result;
2926}
2927
2928/** \test Test case where method is invalid and data is sent in smaller chunks
2929 * and check the response of the parser from HTP library. */
8f1d7503
KS
2930int HTPParserTest03(void)
2931{
2d6cf71d 2932 int result = 1;
262a7300 2933 Flow *f = NULL;
2d6cf71d
GS
2934 uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n";
2935 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2936 TcpSession ssn;
25a3a5c6
PR
2937
2938 HtpState *htp_state = NULL;
2d6cf71d 2939 int r = 0;
8dbf7a0d 2940 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
429c6388 2941
2d6cf71d 2942 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
2943
2944 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
2945 if (f == NULL)
2946 goto end;
2947 f->protoctx = &ssn;
429c6388 2948 f->proto = IPPROTO_TCP;
2d6cf71d 2949
6a53ab9c 2950 StreamTcpInitConfig(TRUE);
6a53ab9c 2951
2d6cf71d
GS
2952 uint32_t u;
2953 for (u = 0; u < httplen1; u++) {
2954 uint8_t flags = 0;
2955
2956 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
2957 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
2958 else flags = STREAM_TOSERVER;
2959
cd3e32ce 2960 SCMutexLock(&f->m);
429c6388 2961 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
2d6cf71d
GS
2962 if (r != 0) {
2963 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
2964 " 0: ", u, r);
2965 result = 0;
cd3e32ce 2966 SCMutexUnlock(&f->m);
2d6cf71d
GS
2967 goto end;
2968 }
cd3e32ce 2969 SCMutexUnlock(&f->m);
2d6cf71d 2970 }
262a7300 2971 htp_state = f->alstate;
2d6cf71d
GS
2972 if (htp_state == NULL) {
2973 printf("no http state: ");
2974 result = 0;
2975 goto end;
2976 }
2977
d4d18e31 2978 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
2d6cf71d 2979
48cf0585
AS
2980 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
2981 if (tx->request_method_number != HTP_M_UNKNOWN ||
2982 h != NULL || tx->request_protocol_number != HTP_PROTOCOL_1_0)
2d6cf71d
GS
2983 {
2984 printf("expected method M_UNKNOWN and got %s: , expected protocol "
48cf0585
AS
2985 "HTTP/1.0 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
2986 bstr_util_strdup_to_c(tx->request_protocol));
2d6cf71d
GS
2987 result = 0;
2988 goto end;
2989 }
2990
2991end:
429c6388 2992 if (alp_tctx != NULL)
fdefb65b 2993 AppLayerParserThreadCtxFree(alp_tctx);
6a53ab9c 2994 StreamTcpFreeConfig(TRUE);
25a3a5c6
PR
2995 if (htp_state != NULL)
2996 HTPStateFree(htp_state);
262a7300 2997 UTHFreeFlow(f);
2d6cf71d
GS
2998 return result;
2999}
3000
3001/** \test Test case where invalid data is sent and check the response of the
3002 * parser from HTP library. */
8f1d7503
KS
3003int HTPParserTest04(void)
3004{
2d6cf71d 3005 int result = 1;
262a7300 3006 Flow *f = NULL;
25a3a5c6 3007 HtpState *htp_state = NULL;
2d6cf71d
GS
3008 uint8_t httpbuf1[] = "World!\r\n";
3009 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3010 TcpSession ssn;
3011 int r = 0;
8dbf7a0d 3012 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
262a7300 3013
2d6cf71d 3014 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
3015
3016 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3017 if (f == NULL)
3018 goto end;
3019 f->protoctx = &ssn;
429c6388 3020 f->proto = IPPROTO_TCP;
2d6cf71d 3021
6a53ab9c 3022 StreamTcpInitConfig(TRUE);
6a53ab9c 3023
cd3e32ce 3024 SCMutexLock(&f->m);
429c6388
AS
3025 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|
3026 STREAM_EOF, httpbuf1, httplen1);
2d16abcf 3027 if (r != 0) {
cd3e32ce 3028 SCMutexUnlock(&f->m);
2d16abcf
VJ
3029 goto end;
3030 }
cd3e32ce 3031 SCMutexUnlock(&f->m);
2d6cf71d 3032
262a7300 3033 htp_state = f->alstate;
2d6cf71d
GS
3034 if (htp_state == NULL) {
3035 printf("no http state: ");
3036 result = 0;
3037 goto end;
3038 }
3039
d4d18e31 3040 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
3041 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3042 if (tx->request_method_number != HTP_M_UNKNOWN ||
3043 h != NULL || tx->request_protocol_number != HTP_PROTOCOL_0_9)
2d6cf71d
GS
3044 {
3045 printf("expected method M_UNKNOWN and got %s: , expected protocol "
48cf0585
AS
3046 "NULL and got %s \n", bstr_util_strdup_to_c(tx->request_method),
3047 bstr_util_strdup_to_c(tx->request_protocol));
2d6cf71d
GS
3048 result = 0;
3049 goto end;
3050 }
3051
3052end:
429c6388 3053 if (alp_tctx != NULL)
fdefb65b 3054 AppLayerParserThreadCtxFree(alp_tctx);
6a53ab9c 3055 StreamTcpFreeConfig(TRUE);
25a3a5c6
PR
3056 if (htp_state != NULL)
3057 HTPStateFree(htp_state);
262a7300 3058 UTHFreeFlow(f);
2d6cf71d
GS
3059 return result;
3060}
3061
3062/** \test Test both sides of a http stream mixed up to see if the HTP parser
3063 * properly parsed them and also keeps them separated. */
8f1d7503
KS
3064int HTPParserTest05(void)
3065{
2d6cf71d 3066 int result = 1;
262a7300 3067 Flow *f = NULL;
25a3a5c6 3068 HtpState *http_state = NULL;
fc2f7f29 3069 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\n";
2d6cf71d
GS
3070 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3071 uint8_t httpbuf2[] = "Post D";
3072 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3073 uint8_t httpbuf3[] = "ata is c0oL!";
3074 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
3075
fc2f7f29 3076 uint8_t httpbuf4[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
2d6cf71d
GS
3077 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
3078 uint8_t httpbuf5[] = "post R";
3079 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3080 uint8_t httpbuf6[] = "esults are tha bomb!";
3081 uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
3082 TcpSession ssn;
8dbf7a0d 3083 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
2d6cf71d 3084
2d6cf71d 3085 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
3086
3087 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3088 if (f == NULL)
3089 goto end;
3090 f->protoctx = &ssn;
429c6388 3091 f->proto = IPPROTO_TCP;
2d6cf71d 3092
6a53ab9c 3093 StreamTcpInitConfig(TRUE);
6a53ab9c 3094
cd3e32ce 3095 SCMutexLock(&f->m);
429c6388
AS
3096 int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START,
3097 httpbuf1, httplen1);
2d6cf71d
GS
3098 if (r != 0) {
3099 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
3100 result = 0;
cd3e32ce 3101 SCMutexUnlock(&f->m);
2d6cf71d
GS
3102 goto end;
3103 }
3104
429c6388
AS
3105 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf4,
3106 httplen4);
2d6cf71d
GS
3107 if (r != 0) {
3108 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
3109 result = 0;
cd3e32ce 3110 SCMutexUnlock(&f->m);
2d6cf71d
GS
3111 goto end;
3112 }
3113
429c6388 3114 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf5, httplen5);
2d6cf71d
GS
3115 if (r != 0) {
3116 printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
3117 result = 0;
cd3e32ce 3118 SCMutexUnlock(&f->m);
2d6cf71d
GS
3119 goto end;
3120 }
3121
429c6388 3122 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
2d6cf71d
GS
3123 if (r != 0) {
3124 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
3125 result = 0;
cd3e32ce 3126 SCMutexUnlock(&f->m);
2d6cf71d
GS
3127 goto end;
3128 }
3129
429c6388
AS
3130 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3,
3131 httplen3);
2d6cf71d
GS
3132 if (r != 0) {
3133 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
3134 result = 0;
cd3e32ce 3135 SCMutexUnlock(&f->m);
2d6cf71d
GS
3136 goto end;
3137 }
3138
429c6388
AS
3139 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf6,
3140 httplen6);
2d6cf71d
GS
3141 if (r != 0) {
3142 printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
3143 result = 0;
cd3e32ce 3144 SCMutexUnlock(&f->m);
2d6cf71d
GS
3145 goto end;
3146 }
cd3e32ce 3147 SCMutexUnlock(&f->m);
2d6cf71d 3148
262a7300 3149 http_state = f->alstate;
2d6cf71d
GS
3150 if (http_state == NULL) {
3151 printf("no http state: ");
3152 result = 0;
3153 goto end;
3154 }
3155
d4d18e31 3156 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
48cf0585
AS
3157 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3158 if (tx->request_method_number != HTP_M_POST ||
3159 h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_0)
2d6cf71d
GS
3160 {
3161 printf("expected method M_POST and got %s: , expected protocol "
48cf0585
AS
3162 "HTTP/1.0 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
3163 bstr_util_strdup_to_c(tx->request_protocol));
2d6cf71d
GS
3164 result = 0;
3165 goto end;
3166 }
3167
f862de2e 3168 if (tx->response_status_number != 200) {
2d6cf71d 3169 printf("expected response 200 OK and got %"PRId32" %s: , expected protocol "
fc2f7f29 3170 "HTTP/1.0 and got %s \n", tx->response_status_number,
48cf0585
AS
3171 bstr_util_strdup_to_c(tx->response_message),
3172 bstr_util_strdup_to_c(tx->response_protocol));
2d6cf71d
GS
3173 result = 0;
3174 goto end;
3175 }
3176end:
429c6388 3177 if (alp_tctx != NULL)
fdefb65b 3178 AppLayerParserThreadCtxFree(alp_tctx);
6a53ab9c 3179 StreamTcpFreeConfig(TRUE);
25a3a5c6
PR
3180 if (http_state != NULL)
3181 HTPStateFree(http_state);
262a7300 3182 UTHFreeFlow(f);
2d6cf71d
GS
3183 return result;
3184}
3185
fc2f7f29
GS
3186/** \test Test proper chunked encoded response body
3187 */
8f1d7503
KS
3188int HTPParserTest06(void)
3189{
fc2f7f29 3190 int result = 1;
262a7300 3191 Flow *f = NULL;
fc2f7f29
GS
3192 uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
3193 "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
3194 "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
3195 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3196 uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nDate: Sat, 03 Oct 2009 10:16:02 "
3197 "GMT\r\n"
3198 "Server: Apache/1.3.37 (Unix) mod_ssl/2.8.28 "
3199 "OpenSSL/0.9.7a PHP/4.4.7 mod_perl/1.29 "
3200 "FrontPage/5.0.2.2510\r\n"
3201 "X-Powered-By: PHP/4.4.7\r\nTransfer-Encoding: "
3202 "chunked\r\n"
3203 "Content-Type: text/html\r\n\r\n"
56143131 3204 "580\r\n"
fc2f7f29
GS
3205 "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu"
3206 "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN"
3207 "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N"
3208 "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk"
3209 "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l"
3210 "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN"
3211 "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt"
3212 "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz"
3213 "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw"
3214 "aG9uZTM9DQpsb2dpbjM9DQpwYXNzd29yZDM9DQpwaG9uZTQ9DQps"
3215 "b2dpbjQ9DQpwYXNzd29yZDQ9DQpwaG9uZTU9DQpsb2dpbjU9DQpw"
3216 "YXNzd29yZDU9DQpwaG9uZTY9DQpsb2dpbjY9DQpwYXNzd29yZDY9"
3217 "DQpjYWxsX3RpbWUxPQ0KY2FsbF90aW1lMj0NCmRheV9saW1pdD0N"
3218 "Cm1vbnRoX2xpbWl0PQ0KW2dyb3VwM10NCnBob25lMT0NCmxvZ2lu"
3219 "MT0NCnBhc3N3b3JkMT0NCnBob25lMj0NCmxvZ2luMj0NCnBhc3N3"
3220 "b3JkMj0NCnBob25lMz0NCmxvZ2luMz0NCnBhc3N3b3JkMz0NCnBo"
3221 "b25lND0NCmxvZ2luND0NCnBhc3N3b3JkND0NCnBob25lNT0NCmxv"
3222 "Z2luNT0NCnBhc3N3b3JkNT0NCnBob25lNj0NCmxvZ2luNj0NCnBh"
3223 "c3N3b3JkNj0NCmNhbGxfdGltZTE9DQpjYWxsX3RpbWUyPQ0KZGF5"
3224 "X2xpbWl0PQ0KbW9udGhfbGltaXQ9DQpbZ3JvdXA0XQ0KcGhvbmUx"
3225 "PQ0KbG9naW4xPQ0KcGFzc3dvcmQxPQ0KcGhvbmUyPQ0KbG9naW4y"
3226 "PQ0KcGFzc3dvcmQyPQ0KcGhvbmUzPQ0KbG9naW4zPQ0KcGFzc3dv"
3227 "cmQzPQ0KcGhvbmU0PQ0KbG9naW40PQ0KcGFzc3dvcmQ0PQ0KcGhv"
3228 "bmU1PQ0KbG9naW41PQ0KcGFzc3dvcmQ1PQ0KcGhvbmU2PQ0KbG9n"
3229 "aW42PQ0KcGFzc3dvcmQ2PQ0KY2FsbF90aW1lMT0NCmNhbGxfdGlt"
3230 "ZTI9DQpkYXlfbGltaXQ9DQptb250aF9saW1pdD0NCltmaWxlc10N"
3231 "Cmxpbms9aHR0cDovLzIwOS4yMDUuMTk2LjE2L2xkL2dldGJvdC5w"
56143131 3232 "aHA=\r\n0\r\n\r\n";
fc2f7f29
GS
3233 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3234 TcpSession ssn;
25a3a5c6 3235 HtpState *http_state = NULL;
8dbf7a0d 3236 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
fc2f7f29 3237
fc2f7f29 3238 memset(&ssn, 0, sizeof(ssn));
78e15ea7 3239
262a7300
VJ
3240 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3241 if (f == NULL)
3242 goto end;
3243 f->protoctx = &ssn;
429c6388 3244 f->proto = IPPROTO_TCP;
fc2f7f29 3245
6a53ab9c 3246 StreamTcpInitConfig(TRUE);
6a53ab9c 3247
cd3e32ce 3248 SCMutexLock(&f->m);
429c6388
AS
3249 int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START,
3250 httpbuf1, httplen1);
fc2f7f29
GS
3251 if (r != 0) {
3252 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
3253 result = 0;
cd3e32ce 3254 SCMutexUnlock(&f->m);
fc2f7f29
GS
3255 goto end;
3256 }
3257
429c6388
AS
3258 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2,
3259 httplen2);
fc2f7f29 3260 if (r != 0) {
a64eea96 3261 printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r);
fc2f7f29 3262 result = 0;
cd3e32ce 3263 SCMutexUnlock(&f->m);
fc2f7f29
GS
3264 goto end;
3265 }
cd3e32ce 3266 SCMutexUnlock(&f->m);
fc2f7f29 3267
262a7300 3268 http_state = f->alstate;
fc2f7f29
GS
3269 if (http_state == NULL) {
3270 printf("no http state: ");
3271 result = 0;
3272 goto end;
3273 }
3274
d4d18e31 3275 htp_tx_t *tx = HTPStateGetTx(http_state, 0);
48cf0585
AS
3276 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
3277 if (tx->request_method_number != HTP_M_GET ||
3278 h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1)
fc2f7f29
GS
3279 {
3280 printf("expected method M_GET and got %s: , expected protocol "
48cf0585
AS
3281 "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
3282 bstr_util_strdup_to_c(tx->request_protocol));
fc2f7f29
GS
3283 result = 0;
3284 goto end;
3285 }
3286
3287 if (tx->response_status_number != 200 ||
48cf0585 3288 h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1)
fc2f7f29
GS
3289 {
3290 printf("expected response 200 OK and got %"PRId32" %s: , expected proto"
3291 "col HTTP/1.1 and got %s \n", tx->response_status_number,
48cf0585
AS
3292 bstr_util_strdup_to_c(tx->response_message),
3293 bstr_util_strdup_to_c(tx->response_protocol));
fc2f7f29
GS
3294 result = 0;
3295 goto end;
3296 }
3297end:
429c6388 3298 if (alp_tctx != NULL)
fdefb65b 3299 AppLayerParserThreadCtxFree(alp_tctx);
6a53ab9c 3300 StreamTcpFreeConfig(TRUE);
25a3a5c6
PR
3301 if (http_state != NULL)
3302 HTPStateFree(http_state);
262a7300 3303 UTHFreeFlow(f);
fc2f7f29
GS
3304 return result;
3305}
a9cdd2bb 3306
15ce8503
VJ
3307/** \test
3308 */
8f1d7503
KS
3309int HTPParserTest07(void)
3310{
36917c7d 3311 int result = 0;
262a7300 3312 Flow *f = NULL;
15ce8503
VJ
3313 uint8_t httpbuf1[] = "GET /awstats.pl?/migratemigrate%20=%20| HTTP/1.0\r\n\r\n";
3314 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3315 TcpSession ssn;
15ce8503
VJ
3316 HtpState *htp_state = NULL;
3317 int r = 0;
8dbf7a0d 3318 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
262a7300 3319
15ce8503 3320 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
3321
3322 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3323 if (f == NULL)
3324 goto end;
3325 f->protoctx = &ssn;
429c6388 3326 f->proto = IPPROTO_TCP;
15ce8503
VJ
3327
3328 StreamTcpInitConfig(TRUE);
15ce8503
VJ
3329
3330 uint32_t u;
3331 for (u = 0; u < httplen1; u++) {
3332 uint8_t flags = 0;
3333
36917c7d
VJ
3334 if (u == 0)
3335 flags = STREAM_TOSERVER|STREAM_START;
3336 else if (u == (httplen1 - 1))
3337 flags = STREAM_TOSERVER|STREAM_EOF;
3338 else
3339 flags = STREAM_TOSERVER;
15ce8503 3340
cd3e32ce 3341 SCMutexLock(&f->m);
429c6388 3342 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
15ce8503
VJ
3343 if (r != 0) {
3344 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
3345 " 0: ", u, r);
cd3e32ce 3346 SCMutexUnlock(&f->m);
15ce8503
VJ
3347 goto end;
3348 }
cd3e32ce 3349 SCMutexUnlock(&f->m);
15ce8503
VJ
3350 }
3351
262a7300 3352 htp_state = f->alstate;
15ce8503
VJ
3353 if (htp_state == NULL) {
3354 printf("no http state: ");
15ce8503
VJ
3355 goto end;
3356 }
3357
36917c7d
VJ
3358 uint8_t ref[] = "/awstats.pl?/migratemigrate = |";
3359 size_t reflen = sizeof(ref) - 1;
3360
d4d18e31 3361 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
3362 if (tx == NULL)
3363 goto end;
3364 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
3365 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
3366 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
0625d542 3367 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 3368 (uintmax_t)reflen,
d5fdfa4b 3369 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
36917c7d
VJ
3370 goto end;
3371 }
3372
48cf0585
AS
3373 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref,
3374 bstr_len(tx_ud->request_uri_normalized)) != 0)
36917c7d 3375 {
0625d542 3376 printf("normalized uri \"");
48cf0585 3377 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
0625d542
VJ
3378 printf("\" != \"");
3379 PrintRawUriFp(stdout, ref, reflen);
3380 printf("\": ");
36917c7d
VJ
3381 goto end;
3382 }
15ce8503
VJ
3383 }
3384
36917c7d 3385 result = 1;
15ce8503 3386end:
429c6388 3387 if (alp_tctx != NULL)
fdefb65b 3388 AppLayerParserThreadCtxFree(alp_tctx);
15ce8503
VJ
3389 StreamTcpFreeConfig(TRUE);
3390 if (htp_state != NULL)
3391 HTPStateFree(htp_state);
262a7300 3392 UTHFreeFlow(f);
15ce8503
VJ
3393 return result;
3394}
3395
a9cdd2bb
BR
3396#include "conf-yaml-loader.h"
3397
326047ee
VJ
3398/** \test Abort
3399 */
8f1d7503
KS
3400int HTPParserTest08(void)
3401{
326047ee 3402 int result = 0;
262a7300 3403 Flow *f = NULL;
326047ee
VJ
3404 uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
3405 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3406 TcpSession ssn;
8dbf7a0d 3407 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
326047ee
VJ
3408
3409 char input[] = "\
3410%YAML 1.1\n\
3411---\n\
3412libhtp:\n\
3413\n\
3414 default-config:\n\
3415 personality: IDS\n\
3416";
3417
3418 ConfCreateContextBackup();
3419 ConfInit();
63f6de58
VJ
3420 HtpConfigCreateBackup();
3421
326047ee
VJ
3422 ConfYamlLoadString(input, strlen(input));
3423 HTPConfigure();
3424
3425 HtpState *htp_state = NULL;
3426 int r = 0;
326047ee 3427 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
3428
3429 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3430 if (f == NULL)
3431 goto end;
3432 f->protoctx = &ssn;
429c6388 3433 f->proto = IPPROTO_TCP;
326047ee
VJ
3434
3435 StreamTcpInitConfig(TRUE);
326047ee
VJ
3436
3437 uint8_t flags = 0;
3438 flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
3439
cd3e32ce 3440 SCMutexLock(&f->m);
429c6388 3441 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1, httplen1);
326047ee
VJ
3442 if (r != 0) {
3443 printf("toserver chunk returned %" PRId32 ", expected"
3444 " 0: ", r);
3445 result = 0;
cd3e32ce 3446 SCMutexUnlock(&f->m);
326047ee
VJ
3447 goto end;
3448 }
cd3e32ce 3449 SCMutexUnlock(&f->m);
326047ee 3450
262a7300 3451 htp_state = f->alstate;
326047ee
VJ
3452 if (htp_state == NULL) {
3453 printf("no http state: ");
3454 result = 0;
3455 goto end;
3456 }
3457
d4d18e31 3458 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
3459 if (tx == NULL)
3460 goto end;
3461 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
3462 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
3463 //printf("uri %s\n", bstr_util_strdup_to_c(tx->request_uri_normalized));
3464 PrintRawDataFp(stdout, bstr_ptr(tx_ud->request_uri_normalized),
3465 bstr_len(tx_ud->request_uri_normalized));
326047ee
VJ
3466 }
3467
3468 result = 1;
3469end:
429c6388 3470 if (alp_tctx != NULL)
fdefb65b 3471 AppLayerParserThreadCtxFree(alp_tctx);
326047ee
VJ
3472 StreamTcpFreeConfig(TRUE);
3473 if (htp_state != NULL)
3474 HTPStateFree(htp_state);
3475
63f6de58 3476 HTPFreeConfig();
326047ee
VJ
3477 ConfDeInit();
3478 ConfRestoreContextBackup();
63f6de58 3479 HtpConfigRestoreBackup();
262a7300 3480 UTHFreeFlow(f);
326047ee
VJ
3481 return result;
3482}
3483
3484/** \test Abort
3485 */
8f1d7503
KS
3486int HTPParserTest09(void)
3487{
326047ee 3488 int result = 0;
262a7300 3489 Flow *f = NULL;
326047ee
VJ
3490 uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
3491 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3492 TcpSession ssn;
8dbf7a0d 3493 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
326047ee
VJ
3494
3495 char input[] = "\
3496%YAML 1.1\n\
3497---\n\
3498libhtp:\n\
3499\n\
3500 default-config:\n\
3501 personality: Apache_2_2\n\
3502";
3503
3504 ConfCreateContextBackup();
3505 ConfInit();
63f6de58
VJ
3506 HtpConfigCreateBackup();
3507
326047ee
VJ
3508 ConfYamlLoadString(input, strlen(input));
3509 HTPConfigure();
3510
3511 HtpState *htp_state = NULL;
3512 int r = 0;
262a7300 3513
326047ee 3514 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
3515
3516 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3517 if (f == NULL)
3518 goto end;
3519 f->protoctx = &ssn;
429c6388 3520 f->proto = IPPROTO_TCP;
326047ee
VJ
3521
3522 StreamTcpInitConfig(TRUE);
326047ee
VJ
3523
3524 uint8_t flags = 0;
3525 flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
3526
cd3e32ce 3527 SCMutexLock(&f->m);
429c6388 3528 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1, httplen1);
326047ee
VJ
3529 if (r != 0) {
3530 printf("toserver chunk returned %" PRId32 ", expected"
3531 " 0: ", r);
3532 result = 0;
cd3e32ce 3533 SCMutexUnlock(&f->m);
326047ee
VJ
3534 goto end;
3535 }
cd3e32ce 3536 SCMutexUnlock(&f->m);
326047ee 3537
262a7300 3538 htp_state = f->alstate;
326047ee
VJ
3539 if (htp_state == NULL) {
3540 printf("no http state: ");
3541 result = 0;
3542 goto end;
3543 }
3544
d4d18e31 3545 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
3546 if (tx == NULL)
3547 goto end;
3548 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
3549 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
3550 //printf("uri %s\n", bstr_util_strdup_to_c(tx->request_uri_normalized));
3551 PrintRawDataFp(stdout, bstr_ptr(tx_ud->request_uri_normalized),
3552 bstr_len(tx_ud->request_uri_normalized));
326047ee
VJ
3553 }
3554
3555 result = 1;
3556end:
429c6388 3557 if (alp_tctx != NULL)
fdefb65b 3558 AppLayerParserThreadCtxFree(alp_tctx);
326047ee
VJ
3559 StreamTcpFreeConfig(TRUE);
3560 if (htp_state != NULL)
3561 HTPStateFree(htp_state);
3562
63f6de58 3563 HTPFreeConfig();
326047ee
VJ
3564 ConfDeInit();
3565 ConfRestoreContextBackup();
63f6de58 3566 HtpConfigRestoreBackup();
262a7300 3567 UTHFreeFlow(f);
326047ee
VJ
3568 return result;
3569}
3570
f2f8dfd8
VJ
3571/** \test Host:www.google.com <- missing space between name:value (rfc violation)
3572 */
8f1d7503
KS
3573int HTPParserTest10(void)
3574{
f2f8dfd8
VJ
3575 int result = 0;
3576 Flow *f = NULL;
3577 uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\r\n\r\n";
3578 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3579 TcpSession ssn;
3580 HtpState *htp_state = NULL;
3581 int r = 0;
8dbf7a0d 3582 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
f2f8dfd8
VJ
3583
3584 memset(&ssn, 0, sizeof(ssn));
3585
3586 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3587 if (f == NULL)
3588 goto end;
3589 f->protoctx = &ssn;
429c6388 3590 f->proto = IPPROTO_TCP;
f2f8dfd8
VJ
3591
3592 StreamTcpInitConfig(TRUE);
3593
3594 uint32_t u;
3595 for (u = 0; u < httplen1; u++) {
3596 uint8_t flags = 0;
3597
3598 if (u == 0)
3599 flags = STREAM_TOSERVER|STREAM_START;
3600 else if (u == (httplen1 - 1))
3601 flags = STREAM_TOSERVER|STREAM_EOF;
3602 else
3603 flags = STREAM_TOSERVER;
3604
cd3e32ce 3605 SCMutexLock(&f->m);
429c6388 3606 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
f2f8dfd8
VJ
3607 if (r != 0) {
3608 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
3609 " 0: ", u, r);
cd3e32ce 3610 SCMutexUnlock(&f->m);
f2f8dfd8
VJ
3611 goto end;
3612 }
cd3e32ce 3613 SCMutexUnlock(&f->m);
f2f8dfd8
VJ
3614 }
3615
3616 htp_state = f->alstate;
3617 if (htp_state == NULL) {
3618 printf("no http state: ");
3619 goto end;
3620 }
3621
d4d18e31 3622 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585 3623 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
f2f8dfd8
VJ
3624 if (h == NULL) {
3625 goto end;
3626 }
3627
48cf0585 3628 char *name = bstr_util_strdup_to_c(h->name);
f2f8dfd8
VJ
3629 if (name == NULL) {
3630 goto end;
3631 }
3632
3633 if (strcmp(name, "Host") != 0) {
3634 printf("header name not \"Host\", instead \"%s\": ", name);
3635 free(name);
3636 goto end;
3637 }
3638 free(name);
3639
48cf0585 3640 char *value = bstr_util_strdup_to_c(h->value);
f2f8dfd8
VJ
3641 if (value == NULL) {
3642 goto end;
3643 }
3644
3645 if (strcmp(value, "www.google.com") != 0) {
3646 printf("header value not \"www.google.com\", instead \"%s\": ", value);
3647 free(value);
3648 goto end;
3649 }
3650 free(value);
3651
3652 result = 1;
3653end:
429c6388 3654 if (alp_tctx != NULL)
fdefb65b 3655 AppLayerParserThreadCtxFree(alp_tctx);
f2f8dfd8
VJ
3656 StreamTcpFreeConfig(TRUE);
3657 if (htp_state != NULL)
3658 HTPStateFree(htp_state);
3659 UTHFreeFlow(f);
3660 return result;
3661}
3662
ab3fcb01
VJ
3663/** \test double encoding in path
3664 */
8f1d7503
KS
3665static int HTPParserTest11(void)
3666{
ab3fcb01
VJ
3667 int result = 0;
3668 Flow *f = NULL;
3669 uint8_t httpbuf1[] = "GET /%2500 HTTP/1.0\r\n\r\n";
3670 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3671 TcpSession ssn;
3672 HtpState *htp_state = NULL;
3673 int r = 0;
8dbf7a0d 3674 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
ab3fcb01
VJ
3675
3676 memset(&ssn, 0, sizeof(ssn));
3677
3678 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3679 if (f == NULL)
3680 goto end;
3681 f->protoctx = &ssn;
429c6388 3682 f->proto = IPPROTO_TCP;
ab3fcb01
VJ
3683
3684 StreamTcpInitConfig(TRUE);
3685
3686 uint32_t u;
3687 for (u = 0; u < httplen1; u++) {
3688 uint8_t flags = 0;
3689
3690 if (u == 0)
3691 flags = STREAM_TOSERVER|STREAM_START;
3692 else if (u == (httplen1 - 1))
3693 flags = STREAM_TOSERVER|STREAM_EOF;
3694 else
3695 flags = STREAM_TOSERVER;
3696
cd3e32ce 3697 SCMutexLock(&f->m);
429c6388 3698 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
ab3fcb01
VJ
3699 if (r != 0) {
3700 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
3701 " 0: ", u, r);
cd3e32ce 3702 SCMutexUnlock(&f->m);
ab3fcb01
VJ
3703 goto end;
3704 }
cd3e32ce 3705 SCMutexUnlock(&f->m);
ab3fcb01
VJ
3706 }
3707
3708 htp_state = f->alstate;
3709 if (htp_state == NULL) {
3710 printf("no http state: ");
3711 goto end;
3712 }
3713
d4d18e31 3714 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
3715 if (tx == NULL)
3716 goto end;
3717 HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
3718 if (tx != NULL && tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
3719 if (4 != bstr_len(tx_ud->request_uri_normalized)) {
ab3fcb01 3720 printf("normalized uri len should be 2, is %"PRIuMAX,
d5fdfa4b 3721 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ab3fcb01
VJ
3722 goto end;
3723 }
3724
48cf0585
AS
3725 if (bstr_ptr(tx_ud->request_uri_normalized)[0] != '/' ||
3726 bstr_ptr(tx_ud->request_uri_normalized)[1] != '%' ||
3727 bstr_ptr(tx_ud->request_uri_normalized)[2] != '0' ||
3728 bstr_ptr(tx_ud->request_uri_normalized)[3] != '0')
ab3fcb01
VJ
3729 {
3730 printf("normalized uri \"");
48cf0585 3731 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ab3fcb01
VJ
3732 printf("\": ");
3733 goto end;
3734 }
3735 }
3736
3737 result = 1;
3738end:
429c6388 3739 if (alp_tctx != NULL)
fdefb65b 3740 AppLayerParserThreadCtxFree(alp_tctx);
ab3fcb01
VJ
3741 StreamTcpFreeConfig(TRUE);
3742 if (htp_state != NULL)
3743 HTPStateFree(htp_state);
3744 UTHFreeFlow(f);
3745 return result;
3746}
3747
3748/** \test double encoding in query
3749 */
8f1d7503
KS
3750static int HTPParserTest12(void)
3751{
ab3fcb01
VJ
3752 int result = 0;
3753 Flow *f = NULL;
3754 uint8_t httpbuf1[] = "GET /?a=%2500 HTTP/1.0\r\n\r\n";
3755 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3756 TcpSession ssn;
3757 HtpState *htp_state = NULL;
3758 int r = 0;
8dbf7a0d 3759 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
ab3fcb01
VJ
3760
3761 memset(&ssn, 0, sizeof(ssn));
3762
3763 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3764 if (f == NULL)
3765 goto end;
3766 f->protoctx = &ssn;
429c6388 3767 f->proto = IPPROTO_TCP;
ab3fcb01
VJ
3768
3769 StreamTcpInitConfig(TRUE);
3770
3771 uint32_t u;
3772 for (u = 0; u < httplen1; u++) {
3773 uint8_t flags = 0;
3774
3775 if (u == 0)
3776 flags = STREAM_TOSERVER|STREAM_START;
3777 else if (u == (httplen1 - 1))
3778 flags = STREAM_TOSERVER|STREAM_EOF;
3779 else
3780 flags = STREAM_TOSERVER;
3781
cd3e32ce 3782 SCMutexLock(&f->m);
429c6388 3783 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
ab3fcb01
VJ
3784 if (r != 0) {
3785 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
3786 " 0: ", u, r);
cd3e32ce 3787 SCMutexUnlock(&f->m);
ab3fcb01
VJ
3788 goto end;
3789 }
cd3e32ce 3790 SCMutexUnlock(&f->m);
ab3fcb01
VJ
3791 }
3792
3793 htp_state = f->alstate;
3794 if (htp_state == NULL) {
3795 printf("no http state: ");
3796 goto end;
3797 }
3798
d4d18e31 3799 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
3800 if (tx == NULL)
3801 goto end;
3802 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
3803 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
3804 if (7 != bstr_len(tx_ud->request_uri_normalized)) {
ab3fcb01 3805 printf("normalized uri len should be 5, is %"PRIuMAX,
d5fdfa4b 3806 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ab3fcb01
VJ
3807 goto end;
3808 }
3809
48cf0585
AS
3810 if (bstr_ptr(tx_ud->request_uri_normalized)[0] != '/' ||
3811 bstr_ptr(tx_ud->request_uri_normalized)[1] != '?' ||
3812 bstr_ptr(tx_ud->request_uri_normalized)[2] != 'a' ||
3813 bstr_ptr(tx_ud->request_uri_normalized)[3] != '=' ||
3814 bstr_ptr(tx_ud->request_uri_normalized)[4] != '%' ||
3815 bstr_ptr(tx_ud->request_uri_normalized)[5] != '0' ||
3816 bstr_ptr(tx_ud->request_uri_normalized)[6] != '0')
ab3fcb01
VJ
3817 {
3818 printf("normalized uri \"");
48cf0585 3819 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ab3fcb01
VJ
3820 printf("\": ");
3821 goto end;
3822 }
3823 }
3824
3825 result = 1;
429c6388
AS
3826 end:
3827 if (alp_tctx != NULL)
fdefb65b 3828 AppLayerParserThreadCtxFree(alp_tctx);
ab3fcb01
VJ
3829 StreamTcpFreeConfig(TRUE);
3830 if (htp_state != NULL)
3831 HTPStateFree(htp_state);
3832 UTHFreeFlow(f);
3833 return result;
3834}
3835
0c98980e
VJ
3836/** \test Host:www.google.com0dName: Value0d0a <- missing space between name:value (rfc violation)
3837 */
8f1d7503
KS
3838int HTPParserTest13(void)
3839{
0c98980e
VJ
3840 int result = 0;
3841 Flow *f = NULL;
3842 uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\rName: Value\r\n\r\n";
3843 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3844 TcpSession ssn;
3845 HtpState *htp_state = NULL;
3846 int r = 0;
8dbf7a0d 3847 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
0c98980e
VJ
3848
3849 memset(&ssn, 0, sizeof(ssn));
3850
3851 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
3852 if (f == NULL)
3853 goto end;
3854 f->protoctx = &ssn;
429c6388 3855 f->proto = IPPROTO_TCP;
0c98980e
VJ
3856
3857 StreamTcpInitConfig(TRUE);
3858
3859 uint32_t u;
3860 for (u = 0; u < httplen1; u++) {
3861 uint8_t flags = 0;
3862
3863 if (u == 0)
3864 flags = STREAM_TOSERVER|STREAM_START;
3865 else if (u == (httplen1 - 1))
3866 flags = STREAM_TOSERVER|STREAM_EOF;
3867 else
3868 flags = STREAM_TOSERVER;
3869
cd3e32ce 3870 SCMutexLock(&f->m);
429c6388 3871 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
0c98980e
VJ
3872 if (r != 0) {
3873 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
3874 " 0: ", u, r);
cd3e32ce 3875 SCMutexUnlock(&f->m);
0c98980e
VJ
3876 goto end;
3877 }
cd3e32ce 3878 SCMutexUnlock(&f->m);
0c98980e
VJ
3879 }
3880
3881 htp_state = f->alstate;
3882 if (htp_state == NULL) {
3883 printf("no http state: ");
3884 goto end;
3885 }
3886
d4d18e31 3887 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585 3888 htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
0c98980e
VJ
3889 if (h == NULL) {
3890 goto end;
3891 }
3892
48cf0585 3893 char *name = bstr_util_strdup_to_c(h->name);
0c98980e
VJ
3894 if (name == NULL) {
3895 goto end;
3896 }
3897
3898 if (strcmp(name, "Host") != 0) {
3899 printf("header name not \"Host\", instead \"%s\": ", name);
3900 free(name);
3901 goto end;
3902 }
3903 free(name);
3904
48cf0585 3905 char *value = bstr_util_strdup_to_c(h->value);
0c98980e
VJ
3906 if (value == NULL) {
3907 goto end;
3908 }
3909
3910 if (strcmp(value, "www.google.com\rName: Value") != 0) {
3911 printf("header value not \"www.google.com\", instead \"");
3912 PrintRawUriFp(stdout, (uint8_t *)value, strlen(value));
3913 printf("\": ");
3914 free(value);
3915 goto end;
3916 }
3917 free(value);
3918
3919 result = 1;
3920end:
429c6388 3921 if (alp_tctx != NULL)
fdefb65b 3922 AppLayerParserThreadCtxFree(alp_tctx);
0c98980e
VJ
3923 StreamTcpFreeConfig(TRUE);
3924 if (htp_state != NULL)
3925 HTPStateFree(htp_state);
3926 UTHFreeFlow(f);
3927 return result;
3928}
3929
a9cdd2bb
BR
3930/** \test Test basic config */
3931int HTPParserConfigTest01(void)
3932{
3933 int ret = 0;
3934 char input[] = "\
3935%YAML 1.1\n\
3936---\n\
3937libhtp:\n\
3938\n\
3939 default-config:\n\
3940 personality: IDS\n\
3941\n\
3942 server-config:\n\
3943\n\
3944 - apache-tomcat:\n\
3945 address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
3946 personality: Tomcat_6_0\n\
3947\n\
3948 - iis7:\n\
3949 address: \n\
3950 - 192.168.0.0/24\n\
3951 - 192.168.10.0/24\n\
3952 personality: IIS_7_0\n\
3953";
3954
3955 ConfCreateContextBackup();
3956 ConfInit();
3957
3958 ConfYamlLoadString(input, strlen(input));
3959
3960 ConfNode *outputs;
3961 outputs = ConfGetNode("libhtp.default-config.personality");
3962 if (outputs == NULL) {
3963 goto end;
3964 }
3965
3966 outputs = ConfGetNode("libhtp.server-config");
3967 if (outputs == NULL) {
3968 goto end;
3969 }
3970
3971 ConfNode *node = TAILQ_FIRST(&outputs->head);
3972 if (node == NULL) {
3973 goto end;
3974 }
3975 if (strcmp(node->name, "0") != 0) {
3976 goto end;
3977 }
3978 node = TAILQ_FIRST(&node->head);
3979 if (node == NULL) {
3980 goto end;
3981 }
3982 if (strcmp(node->name, "apache-tomcat") != 0) {
3983 goto end;
3984 }
3985
3986 int i = 0;
3987 ConfNode *n;
3988
3989 ConfNode *node2 = ConfNodeLookupChild(node, "personality");
3990 if (node2 == NULL) {
3991 goto end;
3992 }
3993 if (strcmp(node2->val, "Tomcat_6_0") != 0) {
3994 goto end;
3995 }
3996
3997 node = ConfNodeLookupChild(node, "address");
3998 if (node == NULL) {
3999 goto end;
4000 }
4001 TAILQ_FOREACH(n, &node->head, next) {
4002 if (n == NULL) {
4003 goto end;
4004 }
4005
4006 switch(i) {
4007 case 0:
4008 if (strcmp(n->name, "0") != 0) {
4009 goto end;
4010 }
4011 if (strcmp(n->val, "192.168.1.0/24") != 0) {
4012 goto end;
4013 }
4014 break;
4015 case 1:
4016 if (strcmp(n->name, "1") != 0) {
4017 goto end;
4018 }
4019 if (strcmp(n->val, "127.0.0.0/8") != 0) {
4020 goto end;
4021 }
4022 break;
4023 case 2:
4024 if (strcmp(n->name, "2") != 0) {
4025 goto end;
4026 }
4027 if (strcmp(n->val, "::1") != 0) {
4028 goto end;
4029 }
4030 break;
4031 default:
4032 goto end;
4033 }
4034 i++;
4035 }
4036
4037 outputs = ConfGetNode("libhtp.server-config");
4038 if (outputs == NULL) {
4039 goto end;
4040 }
4041
4042 node = TAILQ_FIRST(&outputs->head);
4043 node = TAILQ_NEXT(node, next);
4044 if (node == NULL) {
4045 goto end;
4046 }
4047 if (strcmp(node->name, "1") != 0) {
4048 goto end;
4049 }
4050 node = TAILQ_FIRST(&node->head);
4051 if (node == NULL) {
4052 goto end;
4053 }
4054 if (strcmp(node->name, "iis7") != 0) {
4055 goto end;
4056 }
4057
4058 node2 = ConfNodeLookupChild(node, "personality");
4059 if (node2 == NULL) {
4060 goto end;
4061 }
4062 if (strcmp(node2->val, "IIS_7_0") != 0) {
4063 goto end;
4064 }
4065
4066 node = ConfNodeLookupChild(node, "address");
4067 if (node == NULL) {
4068 goto end;
4069 }
4070
4071 i = 0;
4072 TAILQ_FOREACH(n, &node->head, next) {
4073 if (n == NULL) {
4074 goto end;
4075 }
4076
4077 switch(i) {
4078 case 0:
4079 if (strcmp(n->name, "0") != 0) {
4080 goto end;
4081 }
4082 if (strcmp(n->val, "192.168.0.0/24") != 0) {
4083 goto end;
4084 }
4085 break;
4086 case 1:
4087 if (strcmp(n->name, "1") != 0) {
4088 goto end;
4089 }
4090 if (strcmp(n->val, "192.168.10.0/24") != 0) {
4091 goto end;
4092 }
4093 break;
4094 default:
4095 goto end;
4096 }
4097 i++;
4098 }
4099
4100 ret = 1;
4101
4102end:
4103 ConfDeInit();
4104 ConfRestoreContextBackup();
4105
4106 return ret;
4107}
4108
4109/** \test Test config builds radix correctly */
4110int HTPParserConfigTest02(void)
4111{
4112 int ret = 0;
4113 char input[] = "\
4114%YAML 1.1\n\
4115---\n\
4116libhtp:\n\
4117\n\
4118 default-config:\n\
4119 personality: IDS\n\
4120\n\
4121 server-config:\n\
4122\n\
4123 - apache-tomcat:\n\
4124 address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
4125 personality: Tomcat_6_0\n\
4126\n\
4127 - iis7:\n\
4128 address: \n\
4129 - 192.168.0.0/24\n\
4130 - 192.168.10.0/24\n\
4131 personality: IIS_7_0\n\
4132";
4133
4134 ConfCreateContextBackup();
4135 ConfInit();
5c6a65dc 4136 HtpConfigCreateBackup();
a9cdd2bb
BR
4137
4138 ConfYamlLoadString(input, strlen(input));
4139
4140 HTPConfigure();
4141
4142 if (cfglist.cfg == NULL) {
4143 printf("No default config created.\n");
4144 goto end;
4145 }
4146
4147 if (cfgtree == NULL) {
4148 printf("No config tree created.\n");
4149 goto end;
4150 }
4151
a9cdd2bb
BR
4152 htp_cfg_t *htp = cfglist.cfg;
4153 uint8_t buf[128];
4154 const char *addr;
d0a26c6a 4155 void *user_data = NULL;
a9cdd2bb
BR
4156
4157 addr = "192.168.10.42";
4158 if (inet_pton(AF_INET, addr, buf) == 1) {
d0a26c6a
VJ
4159 (void)SCRadixFindKeyIPV4BestMatch(buf, cfgtree, &user_data);
4160 if (user_data != NULL) {
4161 HTPCfgRec *htp_cfg_rec = user_data;
4162 htp = htp_cfg_rec->cfg;
4163 SCLogDebug("LIBHTP using config: %p", htp);
69a4fee7 4164 }
a9cdd2bb
BR
4165 if (htp == NULL) {
4166 printf("Could not get config for: %s\n", addr);
4167 goto end;
4168 }
4169 }
4170 else {
4171 printf("Failed to parse address: %s\n", addr);
4172 goto end;
4173 }
4174
d0a26c6a 4175 user_data = NULL;
a9cdd2bb
BR
4176 addr = "::1";
4177 if (inet_pton(AF_INET6, addr, buf) == 1) {
d0a26c6a
VJ
4178 (void)SCRadixFindKeyIPV6BestMatch(buf, cfgtree, &user_data);
4179 if (user_data != NULL) {
4180 HTPCfgRec *htp_cfg_rec = user_data;
4181 htp = htp_cfg_rec->cfg;
4182 SCLogDebug("LIBHTP using config: %p", htp);
69a4fee7 4183 }
a9cdd2bb
BR
4184 if (htp == NULL) {
4185 printf("Could not get config for: %s\n", addr);
4186 goto end;
4187 }
4188 }
4189 else {
4190 printf("Failed to parse address: %s\n", addr);
4191 goto end;
4192 }
4193
4194 ret = 1;
4195
4196end:
5c6a65dc 4197 HTPFreeConfig();
a9cdd2bb
BR
4198 ConfDeInit();
4199 ConfRestoreContextBackup();
5c6a65dc 4200 HtpConfigRestoreBackup();
a9cdd2bb
BR
4201
4202 return ret;
4203}
4204
4205/** \test Test traffic is handled by the correct htp config */
4206int HTPParserConfigTest03(void)
4207{
4208 int result = 1;
262a7300 4209 Flow *f = NULL;
a9cdd2bb
BR
4210 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
4211 " Data is c0oL!";
4212 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4213 TcpSession ssn;
8dbf7a0d 4214 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
a9cdd2bb
BR
4215
4216 HtpState *htp_state = NULL;
4217 int r = 0;
4218 char input[] = "\
4219%YAML 1.1\n\
4220---\n\
4221libhtp:\n\
4222\n\
4223 default-config:\n\
4224 personality: IDS\n\
4225\n\
4226 server-config:\n\
4227\n\
4228 - apache-tomcat:\n\
4229 address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
4230 personality: Tomcat_6_0\n\
4231\n\
4232 - iis7:\n\
4233 address: \n\
4234 - 192.168.0.0/24\n\
4235 - 192.168.10.0/24\n\
4236 personality: IIS_7_0\n\
4237";
4238
4239 ConfCreateContextBackup();
4240 ConfInit();
5c6a65dc 4241 HtpConfigCreateBackup();
a9cdd2bb
BR
4242
4243 ConfYamlLoadString(input, strlen(input));
4244
4245 HTPConfigure();
4246
262a7300 4247 char *addr = "192.168.10.42";
a9cdd2bb 4248
a9cdd2bb 4249 memset(&ssn, 0, sizeof(ssn));
262a7300
VJ
4250
4251 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4252 if (f == NULL)
4253 goto end;
4254 f->protoctx = &ssn;
429c6388 4255 f->proto = IPPROTO_TCP;
a9cdd2bb 4256
a9cdd2bb 4257 htp_cfg_t *htp = cfglist.cfg;
262a7300 4258
d0a26c6a
VJ
4259 void *user_data = NULL;
4260 (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)f->dst.addr_data32, cfgtree, &user_data);
4261 if (user_data != NULL) {
4262 HTPCfgRec *htp_cfg_rec = user_data;
4263 htp = htp_cfg_rec->cfg;
4264 SCLogDebug("LIBHTP using config: %p", htp);
69a4fee7 4265 }
a9cdd2bb
BR
4266 if (htp == NULL) {
4267 printf("Could not get config for: %s\n", addr);
4268 goto end;
4269 }
4270
4271 StreamTcpInitConfig(TRUE);
a9cdd2bb
BR
4272
4273 uint32_t u;
4274 for (u = 0; u < httplen1; u++) {
4275 uint8_t flags = 0;
4276
4277 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4278 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4279 else flags = STREAM_TOSERVER;
4280
cd3e32ce 4281 SCMutexLock(&f->m);
429c6388 4282 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
a9cdd2bb
BR
4283 if (r != 0) {
4284 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4285 " 0: ", u, r);
4286 result = 0;
cd3e32ce 4287 SCMutexUnlock(&f->m);
a9cdd2bb
BR
4288 goto end;
4289 }
cd3e32ce 4290 SCMutexUnlock(&f->m);
a9cdd2bb
BR
4291 }
4292
262a7300 4293 htp_state = f->alstate;
a9cdd2bb
BR
4294 if (htp_state == NULL) {
4295 printf("no http state: ");
4296 result = 0;
4297 goto end;
4298 }
4299
48cf0585
AS
4300 if (HTPStateGetTxCnt(htp_state) != 2) {
4301 printf("HTPStateGetTxCnt(htp_state) failure\n");
4302 goto end;
4303 }
4304
4305 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
4306 if (tx == NULL)
4307 goto end;
4308 if (tx->cfg != htp) {
a9cdd2bb 4309 printf("wrong HTP config (%p instead of %p - default=%p): ",
48cf0585
AS
4310 tx->cfg, htp, cfglist.cfg);
4311 goto end;
4312 }
4313 tx = HTPStateGetTx(htp_state, 1);
4314 if (tx == NULL)
4315 goto end;
4316 if (tx->cfg != htp) {
4317 printf("wrong HTP config (%p instead of %p - default=%p): ",
4318 tx->cfg, htp, cfglist.cfg);
a9cdd2bb
BR
4319 goto end;
4320 }
4321
4322end:
429c6388 4323 if (alp_tctx != NULL)
fdefb65b 4324 AppLayerParserThreadCtxFree(alp_tctx);
5c6a65dc 4325 HTPFreeConfig();
a9cdd2bb
BR
4326 ConfDeInit();
4327 ConfRestoreContextBackup();
5c6a65dc 4328 HtpConfigRestoreBackup();
a9cdd2bb 4329
a9cdd2bb
BR
4330 StreamTcpFreeConfig(TRUE);
4331 if (htp_state != NULL)
4332 HTPStateFree(htp_state);
262a7300 4333 UTHFreeFlow(f);
a9cdd2bb
BR
4334 return result;
4335}
06a65cb4 4336
48cf0585
AS
4337/* disabled when we upgraded to libhtp 0.5.x */
4338#if 0
028c6c17
AS
4339int HTPParserConfigTest04(void)
4340{
4341 int result = 0;
4342
4343 char input[] = "\
4344%YAML 1.1\n\
4345---\n\
4346libhtp:\n\
4347\n\
4348 default-config:\n\
4349 personality: IDS\n\
4350 path-control-char-handling: status_400\n\
4351 path-convert-utf8: yes\n\
4352 path-invalid-encoding-handling: remove_percent\n\
4353\n\
4354 server-config:\n\
4355\n\
4356 - apache-tomcat:\n\
4357 personality: Tomcat_6_0\n\
4358 path-invalid-utf8-handling: none\n\
4359 path-nul-encoded-handling: status_404\n\
4360 path-nul-raw-handling: status_400\n\
4361\n\
4362 - iis7:\n\
4363 personality: IIS_7_0\n\
4364 path-replacement-char: o\n\
4365 path-unicode-mapping: status_400\n\
4366";
4367
4368 ConfCreateContextBackup();
4369 ConfInit();
4370 HtpConfigCreateBackup();
4371
4372 ConfYamlLoadString(input, strlen(input));
4373
4374 HTPConfigure();
4375
4376 HTPCfgRec *cfg_rec = &cfglist;
4377 if (cfg_rec->cfg->path_control_char_handling != STATUS_400 ||
4378 cfg_rec->cfg->path_convert_utf8 != 1 ||
4379 cfg_rec->cfg->path_invalid_encoding_handling != URL_DECODER_REMOVE_PERCENT) {
4380 printf("failed 1\n");
4381 goto end;
4382 }
4383
4384 cfg_rec = cfg_rec->next;
080c15b3 4385 if (cfg_rec->cfg->bestfit_replacement_char != 'o' ||
028c6c17
AS
4386 cfg_rec->cfg->path_unicode_mapping != STATUS_400) {
4387 printf("failed 2\n");
4388 goto end;
4389 }
4390
4391 cfg_rec = cfg_rec->next;
4392 if (cfg_rec->cfg->path_invalid_utf8_handling != NONE ||
4393 cfg_rec->cfg->path_nul_encoded_handling != STATUS_404 ||
4394 cfg_rec->cfg->path_nul_raw_handling != STATUS_400) {
4395 printf("failed 3\n");
4396 goto end;
4397 }
4398
4399 result = 1;
4400
4401end:
4402 HTPFreeConfig();
4403 ConfDeInit();
4404 ConfRestoreContextBackup();
4405 HtpConfigRestoreBackup();
4406
4407 return result;
4408}
48cf0585 4409#endif
028c6c17 4410
ad827ad0
VJ
4411/** \test Test %2f decoding in profile Apache_2_2
4412 *
4413 * %2f in path is left untouched
4414 * %2f in query string is normalized to %2F
4415 * %252f in query string is decoded/normalized to %2F
4416 */
4417static int HTPParserDecodingTest01(void)
4418{
4419 int result = 0;
4420 Flow *f = NULL;
4421 uint8_t httpbuf1[] =
4422 "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4423 "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4424 "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4425 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4426 TcpSession ssn;
8dbf7a0d 4427 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
ad827ad0
VJ
4428
4429 HtpState *htp_state = NULL;
4430 int r = 0;
4431 char input[] = "\
4432%YAML 1.1\n\
4433---\n\
4434libhtp:\n\
4435\n\
4436 default-config:\n\
48cf0585 4437 personality: Apache_2\n\
ad827ad0
VJ
4438";
4439
4440 ConfCreateContextBackup();
4441 ConfInit();
4442 HtpConfigCreateBackup();
4443 ConfYamlLoadString(input, strlen(input));
4444 HTPConfigure();
4445 char *addr = "4.3.2.1";
4446 memset(&ssn, 0, sizeof(ssn));
4447
4448 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4449 if (f == NULL)
4450 goto end;
4451 f->protoctx = &ssn;
429c6388 4452 f->proto = IPPROTO_TCP;
ad827ad0
VJ
4453
4454 StreamTcpInitConfig(TRUE);
4455
4456 uint32_t u;
4457 for (u = 0; u < httplen1; u++) {
4458 uint8_t flags = 0;
4459
4460 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4461 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4462 else flags = STREAM_TOSERVER;
4463
cd3e32ce 4464 SCMutexLock(&f->m);
429c6388 4465 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
ad827ad0
VJ
4466 if (r != 0) {
4467 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4468 " 0: ", u, r);
4469 result = 0;
cd3e32ce 4470 SCMutexUnlock(&f->m);
ad827ad0
VJ
4471 goto end;
4472 }
cd3e32ce 4473 SCMutexUnlock(&f->m);
ad827ad0
VJ
4474 }
4475
4476 htp_state = f->alstate;
4477 if (htp_state == NULL) {
4478 printf("no http state: ");
4479 result = 0;
4480 goto end;
4481 }
4482
4483 uint8_t ref1[] = "/abc%2fdef";
4484 size_t reflen = sizeof(ref1) - 1;
4485
d4d18e31 4486 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
4487 if (tx == NULL)
4488 goto end;
4489 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
4490 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4491 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
ad827ad0 4492 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 4493 (uintmax_t)reflen,
d5fdfa4b 4494 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4495 goto end;
4496 }
4497
48cf0585
AS
4498 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
4499 bstr_len(tx_ud->request_uri_normalized)) != 0)
ad827ad0
VJ
4500 {
4501 printf("normalized uri \"");
48cf0585 4502 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4503 printf("\" != \"");
4504 PrintRawUriFp(stdout, ref1, reflen);
4505 printf("\": ");
4506 goto end;
4507 }
4508 }
4509
48cf0585 4510 uint8_t ref2[] = "/abc/def?ghi/jkl";
ad827ad0
VJ
4511 reflen = sizeof(ref2) - 1;
4512
d4d18e31 4513 tx = HTPStateGetTx(htp_state, 1);
48cf0585
AS
4514 if (tx == NULL)
4515 goto end;
4516 tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4517 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4518 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
ad827ad0 4519 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 4520 (uintmax_t)reflen,
d5fdfa4b 4521 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4522 goto end;
4523 }
4524
48cf0585
AS
4525 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2,
4526 bstr_len(tx_ud->request_uri_normalized)) != 0)
ad827ad0
VJ
4527 {
4528 printf("normalized uri \"");
48cf0585 4529 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4530 printf("\" != \"");
4531 PrintRawUriFp(stdout, ref2, reflen);
4532 printf("\": ");
4533 goto end;
4534 }
4535 }
4536
48cf0585
AS
4537 uint8_t ref3[] = "/abc/def?ghi%2fjkl";
4538 reflen = sizeof(ref3) - 1;
d4d18e31 4539 tx = HTPStateGetTx(htp_state, 2);
48cf0585
AS
4540 if (tx == NULL)
4541 goto end;
4542 tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
4543 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4544 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
ad827ad0 4545 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 4546 (uintmax_t)reflen,
d5fdfa4b 4547 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4548 goto end;
4549 }
4550
48cf0585
AS
4551 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3,
4552 bstr_len(tx_ud->request_uri_normalized)) != 0)
ad827ad0
VJ
4553 {
4554 printf("normalized uri \"");
48cf0585 4555 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4556 printf("\" != \"");
4557 PrintRawUriFp(stdout, ref3, reflen);
4558 printf("\": ");
4559 goto end;
4560 }
4561 }
4562
4563 result = 1;
4564
4565end:
429c6388 4566 if (alp_tctx != NULL)
fdefb65b 4567 AppLayerParserThreadCtxFree(alp_tctx);
ad827ad0
VJ
4568 HTPFreeConfig();
4569 ConfDeInit();
4570 ConfRestoreContextBackup();
4571 HtpConfigRestoreBackup();
4572
4573 StreamTcpFreeConfig(TRUE);
4574 if (htp_state != NULL)
4575 HTPStateFree(htp_state);
4576 UTHFreeFlow(f);
4577 return result;
4578}
4579
4580/** \test Test %2f decoding in profile IDS
4581 *
4582 * %2f in path decoded to /
4583 * %2f in query string is decoded to /
e839cea9 4584 * %252f in query string is decoded to %2F
ad827ad0
VJ
4585 */
4586static int HTPParserDecodingTest02(void)
4587{
4588 int result = 0;
4589 Flow *f = NULL;
4590 uint8_t httpbuf1[] =
4591 "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4592 "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4593 "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4594 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4595 TcpSession ssn;
8dbf7a0d 4596 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
ad827ad0
VJ
4597
4598 HtpState *htp_state = NULL;
4599 int r = 0;
4600 char input[] = "\
4601%YAML 1.1\n\
4602---\n\
4603libhtp:\n\
4604\n\
4605 default-config:\n\
4606 personality: IDS\n\
e839cea9
VJ
4607 double-decode-path: no\n\
4608 double-decode-query: no\n\
ad827ad0
VJ
4609";
4610
4611 ConfCreateContextBackup();
4612 ConfInit();
4613 HtpConfigCreateBackup();
4614 ConfYamlLoadString(input, strlen(input));
4615 HTPConfigure();
4616 char *addr = "4.3.2.1";
4617 memset(&ssn, 0, sizeof(ssn));
4618
4619 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4620 if (f == NULL)
4621 goto end;
4622 f->protoctx = &ssn;
429c6388 4623 f->proto = IPPROTO_TCP;
ad827ad0
VJ
4624
4625 StreamTcpInitConfig(TRUE);
4626
4627 uint32_t u;
4628 for (u = 0; u < httplen1; u++) {
4629 uint8_t flags = 0;
4630
4631 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4632 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4633 else flags = STREAM_TOSERVER;
4634
cd3e32ce 4635 SCMutexLock(&f->m);
429c6388 4636 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
ad827ad0
VJ
4637 if (r != 0) {
4638 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4639 " 0: ", u, r);
4640 result = 0;
cd3e32ce 4641 SCMutexUnlock(&f->m);
ad827ad0
VJ
4642 goto end;
4643 }
cd3e32ce 4644 SCMutexUnlock(&f->m);
ad827ad0
VJ
4645 }
4646
4647 htp_state = f->alstate;
4648 if (htp_state == NULL) {
4649 printf("no http state: ");
4650 result = 0;
4651 goto end;
4652 }
4653
4654 uint8_t ref1[] = "/abc/def";
4655 size_t reflen = sizeof(ref1) - 1;
4656
d4d18e31 4657 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
4658 if (tx == NULL)
4659 goto end;
4660 HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4661 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4662 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
ad827ad0 4663 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 4664 (uintmax_t)reflen,
d5fdfa4b 4665 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4666 goto end;
4667 }
4668
48cf0585
AS
4669 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
4670 bstr_len(tx_ud->request_uri_normalized)) != 0)
ad827ad0
VJ
4671 {
4672 printf("normalized uri \"");
48cf0585 4673 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4674 printf("\" != \"");
4675 PrintRawUriFp(stdout, ref1, reflen);
4676 printf("\": ");
4677 goto end;
4678 }
4679 }
4680
4681 uint8_t ref2[] = "/abc/def?ghi/jkl";
4682 reflen = sizeof(ref2) - 1;
4683
d4d18e31 4684 tx = HTPStateGetTx(htp_state, 1);
48cf0585
AS
4685 if (tx == NULL)
4686 goto end;
4687 tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4688 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4689 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
ad827ad0 4690 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 4691 (uintmax_t)reflen,
d5fdfa4b 4692 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4693 goto end;
4694 }
4695
48cf0585
AS
4696 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2,
4697 bstr_len(tx_ud->request_uri_normalized)) != 0)
ad827ad0
VJ
4698 {
4699 printf("normalized uri \"");
48cf0585 4700 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4701 printf("\" != \"");
4702 PrintRawUriFp(stdout, ref2, reflen);
4703 printf("\": ");
4704 goto end;
4705 }
4706 }
4707
48cf0585 4708 uint8_t ref3[] = "/abc/def?ghi%2fjkl";
e839cea9 4709 reflen = sizeof(ref3) - 1;
d4d18e31 4710 tx = HTPStateGetTx(htp_state, 2);
48cf0585
AS
4711 if (tx == NULL)
4712 goto end;
4713 tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
4714 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4715 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
e839cea9 4716 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX" (3): ",
48cf0585 4717 (uintmax_t)reflen,
d5fdfa4b 4718 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4719 goto end;
4720 }
4721
48cf0585
AS
4722 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3,
4723 bstr_len(tx_ud->request_uri_normalized)) != 0)
ad827ad0
VJ
4724 {
4725 printf("normalized uri \"");
48cf0585 4726 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
ad827ad0
VJ
4727 printf("\" != \"");
4728 PrintRawUriFp(stdout, ref3, reflen);
4729 printf("\": ");
4730 goto end;
4731 }
4732 }
4733
4734 result = 1;
4735
4736end:
429c6388 4737 if (alp_tctx != NULL)
fdefb65b 4738 AppLayerParserThreadCtxFree(alp_tctx);
ad827ad0
VJ
4739 HTPFreeConfig();
4740 ConfDeInit();
4741 ConfRestoreContextBackup();
4742 HtpConfigRestoreBackup();
4743
4744 StreamTcpFreeConfig(TRUE);
4745 if (htp_state != NULL)
4746 HTPStateFree(htp_state);
4747 UTHFreeFlow(f);
4748 return result;
4749}
4750
e839cea9
VJ
4751/** \test Test %2f decoding in profile IDS with double-decode-* options
4752 *
4753 * %252f in path decoded to /
4754 * %252f in query string is decoded to /
4755 */
4756static int HTPParserDecodingTest03(void)
4757{
4758 int result = 0;
4759 Flow *f = NULL;
4760 uint8_t httpbuf1[] =
4761 "GET /abc%252fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"
4762 "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4763 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4764 TcpSession ssn;
8dbf7a0d 4765 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
e839cea9
VJ
4766
4767 HtpState *htp_state = NULL;
4768 int r = 0;
4769 char input[] = "\
4770%YAML 1.1\n\
4771---\n\
4772libhtp:\n\
4773\n\
4774 default-config:\n\
4775 personality: IDS\n\
4776 double-decode-path: yes\n\
4777 double-decode-query: yes\n\
4778";
4779
4780 ConfCreateContextBackup();
4781 ConfInit();
4782 HtpConfigCreateBackup();
4783 ConfYamlLoadString(input, strlen(input));
4784 HTPConfigure();
4785 char *addr = "4.3.2.1";
4786 memset(&ssn, 0, sizeof(ssn));
4787
4788 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4789 if (f == NULL)
4790 goto end;
4791 f->protoctx = &ssn;
429c6388 4792 f->proto = IPPROTO_TCP;
e839cea9
VJ
4793
4794 StreamTcpInitConfig(TRUE);
4795
4796 uint32_t u;
4797 for (u = 0; u < httplen1; u++) {
4798 uint8_t flags = 0;
4799
4800 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4801 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4802 else flags = STREAM_TOSERVER;
4803
cd3e32ce 4804 SCMutexLock(&f->m);
429c6388 4805 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
e839cea9
VJ
4806 if (r != 0) {
4807 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4808 " 0: ", u, r);
4809 result = 0;
cd3e32ce 4810 SCMutexUnlock(&f->m);
e839cea9
VJ
4811 goto end;
4812 }
cd3e32ce 4813 SCMutexUnlock(&f->m);
e839cea9
VJ
4814 }
4815
4816 htp_state = f->alstate;
4817 if (htp_state == NULL) {
4818 printf("no http state: ");
4819 result = 0;
4820 goto end;
4821 }
4822
4823 uint8_t ref1[] = "/abc/def";
4824 size_t reflen = sizeof(ref1) - 1;
4825
d4d18e31 4826 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
4827 if (tx == NULL)
4828 goto end;
4829 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
4830 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4831 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
e839cea9 4832 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 4833 (uintmax_t)reflen,
d5fdfa4b 4834 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
e839cea9
VJ
4835 goto end;
4836 }
4837
48cf0585
AS
4838 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
4839 bstr_len(tx_ud->request_uri_normalized)) != 0)
e839cea9
VJ
4840 {
4841 printf("normalized uri \"");
48cf0585 4842 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
e839cea9
VJ
4843 printf("\" != \"");
4844 PrintRawUriFp(stdout, ref1, reflen);
4845 printf("\": ");
4846 goto end;
4847 }
4848 }
4849
4850 uint8_t ref2[] = "/abc/def?ghi/jkl";
4851 reflen = sizeof(ref2) - 1;
4852
d4d18e31 4853 tx = HTPStateGetTx(htp_state, 1);
48cf0585
AS
4854 if (tx == NULL)
4855 goto end;
4856 tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx);
4857 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4858 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
e839cea9 4859 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 4860 (uintmax_t)reflen,
d5fdfa4b 4861 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
e839cea9
VJ
4862 goto end;
4863 }
4864
48cf0585
AS
4865 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2,
4866 bstr_len(tx_ud->request_uri_normalized)) != 0)
e839cea9
VJ
4867 {
4868 printf("normalized uri \"");
48cf0585 4869 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
e839cea9
VJ
4870 printf("\" != \"");
4871 PrintRawUriFp(stdout, ref2, reflen);
4872 printf("\": ");
4873 goto end;
4874 }
4875 }
4876
4877 result = 1;
4878
4879end:
429c6388 4880 if (alp_tctx != NULL)
fdefb65b 4881 AppLayerParserThreadCtxFree(alp_tctx);
e839cea9
VJ
4882 HTPFreeConfig();
4883 ConfDeInit();
4884 ConfRestoreContextBackup();
4885 HtpConfigRestoreBackup();
4886
4887 StreamTcpFreeConfig(TRUE);
4888 if (htp_state != NULL)
4889 HTPStateFree(htp_state);
4890 UTHFreeFlow(f);
4891 return result;
4892}
4893
cc51eec5
VJ
4894/** \test Test http:// in query profile IDS
4895 */
4896static int HTPParserDecodingTest04(void)
4897{
4898 int result = 0;
4899 Flow *f = NULL;
4900 uint8_t httpbuf1[] =
4901 "GET /abc/def?a=http://www.abc.com/ HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
4902 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
4903 TcpSession ssn;
8dbf7a0d 4904 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
cc51eec5
VJ
4905
4906 HtpState *htp_state = NULL;
4907 int r = 0;
4908 char input[] = "\
4909%YAML 1.1\n\
4910---\n\
4911libhtp:\n\
4912\n\
4913 default-config:\n\
4914 personality: IDS\n\
4915 double-decode-path: yes\n\
4916 double-decode-query: yes\n\
4917";
4918
4919 ConfCreateContextBackup();
4920 ConfInit();
4921 HtpConfigCreateBackup();
4922 ConfYamlLoadString(input, strlen(input));
4923 HTPConfigure();
4924 char *addr = "4.3.2.1";
4925 memset(&ssn, 0, sizeof(ssn));
4926
4927 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
4928 if (f == NULL)
4929 goto end;
4930 f->protoctx = &ssn;
429c6388 4931 f->proto = IPPROTO_TCP;
cc51eec5
VJ
4932
4933 StreamTcpInitConfig(TRUE);
4934
4935 uint32_t u;
4936 for (u = 0; u < httplen1; u++) {
4937 uint8_t flags = 0;
4938
4939 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
4940 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
4941 else flags = STREAM_TOSERVER;
4942
cd3e32ce 4943 SCMutexLock(&f->m);
429c6388 4944 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
cc51eec5
VJ
4945 if (r != 0) {
4946 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
4947 " 0: ", u, r);
4948 result = 0;
cd3e32ce 4949 SCMutexUnlock(&f->m);
cc51eec5
VJ
4950 goto end;
4951 }
cd3e32ce 4952 SCMutexUnlock(&f->m);
cc51eec5
VJ
4953 }
4954
4955 htp_state = f->alstate;
4956 if (htp_state == NULL) {
4957 printf("no http state: ");
4958 result = 0;
4959 goto end;
4960 }
4961
4962 uint8_t ref1[] = "/abc/def?a=http://www.abc.com/";
4963 size_t reflen = sizeof(ref1) - 1;
4964
d4d18e31 4965 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
4966 if (tx == NULL)
4967 goto end;
4968 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
4969 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
4970 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
cc51eec5 4971 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 4972 (uintmax_t)reflen,
d5fdfa4b 4973 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
cc51eec5
VJ
4974 goto end;
4975 }
4976
48cf0585
AS
4977 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
4978 bstr_len(tx_ud->request_uri_normalized)) != 0)
cc51eec5
VJ
4979 {
4980 printf("normalized uri \"");
48cf0585 4981 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
cc51eec5
VJ
4982 printf("\" != \"");
4983 PrintRawUriFp(stdout, ref1, reflen);
4984 printf("\": ");
4985 goto end;
4986 }
4987 }
4988
4989 result = 1;
4990
4991end:
429c6388 4992 if (alp_tctx != NULL)
fdefb65b 4993 AppLayerParserThreadCtxFree(alp_tctx);
cc51eec5
VJ
4994 HTPFreeConfig();
4995 ConfDeInit();
4996 ConfRestoreContextBackup();
4997 HtpConfigRestoreBackup();
4998
4999 StreamTcpFreeConfig(TRUE);
5000 if (htp_state != NULL)
5001 HTPStateFree(htp_state);
5002 UTHFreeFlow(f);
5003 return result;
5004}
5005
5006/** \test Test \ char in query profile IDS. Bug 739
5007 */
5008static int HTPParserDecodingTest05(void)
5009{
5010 int result = 0;
5011 Flow *f = NULL;
5012 uint8_t httpbuf1[] =
5013 "GET /index?id=\\\"<script>alert(document.cookie)</script> HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5014 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5015 TcpSession ssn;
8dbf7a0d 5016 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
cc51eec5
VJ
5017
5018 HtpState *htp_state = NULL;
5019 int r = 0;
5020 char input[] = "\
5021%YAML 1.1\n\
5022---\n\
5023libhtp:\n\
5024\n\
5025 default-config:\n\
5026 personality: IDS\n\
5027 double-decode-path: yes\n\
5028 double-decode-query: yes\n\
5029";
5030
5031 ConfCreateContextBackup();
5032 ConfInit();
5033 HtpConfigCreateBackup();
5034 ConfYamlLoadString(input, strlen(input));
5035 HTPConfigure();
5036 char *addr = "4.3.2.1";
5037 memset(&ssn, 0, sizeof(ssn));
5038
5039 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5040 if (f == NULL)
5041 goto end;
5042 f->protoctx = &ssn;
429c6388 5043 f->proto = IPPROTO_TCP;
cc51eec5
VJ
5044
5045 StreamTcpInitConfig(TRUE);
5046
5047 uint32_t u;
5048 for (u = 0; u < httplen1; u++) {
5049 uint8_t flags = 0;
5050
5051 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5052 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5053 else flags = STREAM_TOSERVER;
5054
cd3e32ce 5055 SCMutexLock(&f->m);
429c6388 5056 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
cc51eec5
VJ
5057 if (r != 0) {
5058 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5059 " 0: ", u, r);
5060 result = 0;
cd3e32ce 5061 SCMutexUnlock(&f->m);
cc51eec5
VJ
5062 goto end;
5063 }
cd3e32ce 5064 SCMutexUnlock(&f->m);
cc51eec5
VJ
5065 }
5066
5067 htp_state = f->alstate;
5068 if (htp_state == NULL) {
5069 printf("no http state: ");
5070 result = 0;
5071 goto end;
5072 }
5073
5074 uint8_t ref1[] = "/index?id=\\\"<script>alert(document.cookie)</script>";
5075 size_t reflen = sizeof(ref1) - 1;
5076
d4d18e31 5077 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
48cf0585
AS
5078 if (tx == NULL)
5079 goto end;
5080 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5081 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5082 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
cc51eec5 5083 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
48cf0585 5084 (uintmax_t)reflen,
d5fdfa4b 5085 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
cc51eec5
VJ
5086 goto end;
5087 }
5088
48cf0585
AS
5089 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5090 bstr_len(tx_ud->request_uri_normalized)) != 0)
cc51eec5
VJ
5091 {
5092 printf("normalized uri \"");
48cf0585 5093 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
cc51eec5
VJ
5094 printf("\" != \"");
5095 PrintRawUriFp(stdout, ref1, reflen);
5096 printf("\": ");
5097 goto end;
5098 }
5099 }
5100
5101 result = 1;
5102
5103end:
429c6388 5104 if (alp_tctx != NULL)
fdefb65b 5105 AppLayerParserThreadCtxFree(alp_tctx);
cc51eec5
VJ
5106 HTPFreeConfig();
5107 ConfDeInit();
5108 ConfRestoreContextBackup();
5109 HtpConfigRestoreBackup();
5110
5111 StreamTcpFreeConfig(TRUE);
5112 if (htp_state != NULL)
5113 HTPStateFree(htp_state);
5114 UTHFreeFlow(f);
5115 return result;
5116}
5117
9a7353e1
VJ
5118/** \test Test + char in query. Bug 1035
5119 */
5120static int HTPParserDecodingTest06(void)
5121{
5122 int result = 0;
5123 Flow *f = NULL;
5124 uint8_t httpbuf1[] =
5125 "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5126 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5127 TcpSession ssn;
8dbf7a0d 5128 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
9a7353e1
VJ
5129
5130 HtpState *htp_state = NULL;
5131 int r = 0;
5132 char input[] = "\
5133%YAML 1.1\n\
5134---\n\
5135libhtp:\n\
5136\n\
5137 default-config:\n\
5138 personality: IDS\n\
5139 double-decode-path: yes\n\
5140 double-decode-query: yes\n\
5141";
5142
5143 ConfCreateContextBackup();
5144 ConfInit();
5145 HtpConfigCreateBackup();
5146 ConfYamlLoadString(input, strlen(input));
5147 HTPConfigure();
5148 char *addr = "4.3.2.1";
5149 memset(&ssn, 0, sizeof(ssn));
5150
5151 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5152 if (f == NULL)
5153 goto end;
5154 f->protoctx = &ssn;
429c6388 5155 f->proto = IPPROTO_TCP;
9a7353e1
VJ
5156
5157 StreamTcpInitConfig(TRUE);
5158
5159 uint32_t u;
5160 for (u = 0; u < httplen1; u++) {
5161 uint8_t flags = 0;
5162
5163 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5164 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5165 else flags = STREAM_TOSERVER;
5166
5167 SCMutexLock(&f->m);
429c6388 5168 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
9a7353e1
VJ
5169 if (r != 0) {
5170 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5171 " 0: ", u, r);
5172 result = 0;
5173 SCMutexUnlock(&f->m);
5174 goto end;
5175 }
5176 SCMutexUnlock(&f->m);
5177 }
5178
5179 htp_state = f->alstate;
5180 if (htp_state == NULL) {
5181 printf("no http state: ");
5182 result = 0;
5183 goto end;
5184 }
5185
5186 uint8_t ref1[] = "/put.php?ip=1.2.3.4&port=+6000";
5187 size_t reflen = sizeof(ref1) - 1;
5188
5189 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5190 if (tx == NULL)
5191 goto end;
5192 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5193 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5194 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5195 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5196 (uintmax_t)reflen,
d5fdfa4b 5197 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
9a7353e1
VJ
5198 goto end;
5199 }
5200
5201 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5202 bstr_len(tx_ud->request_uri_normalized)) != 0)
5203 {
5204 printf("normalized uri \"");
5205 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5206 printf("\" != \"");
5207 PrintRawUriFp(stdout, ref1, reflen);
5208 printf("\": ");
5209 goto end;
5210 }
5211 }
5212
5213 result = 1;
5214
5215end:
429c6388 5216 if (alp_tctx != NULL)
fdefb65b 5217 AppLayerParserThreadCtxFree(alp_tctx);
9a7353e1
VJ
5218 HTPFreeConfig();
5219 ConfDeInit();
5220 ConfRestoreContextBackup();
5221 HtpConfigRestoreBackup();
5222
5223 StreamTcpFreeConfig(TRUE);
5224 if (htp_state != NULL)
5225 HTPStateFree(htp_state);
5226 UTHFreeFlow(f);
5227 return result;
5228}
5229
5230/** \test Test + char in query. Bug 1035
5231 */
5232static int HTPParserDecodingTest07(void)
5233{
5234 int result = 0;
5235 Flow *f = NULL;
5236 uint8_t httpbuf1[] =
5237 "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n";
5238 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5239 TcpSession ssn;
8dbf7a0d 5240 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
9a7353e1
VJ
5241
5242 HtpState *htp_state = NULL;
5243 int r = 0;
5244 char input[] = "\
5245%YAML 1.1\n\
5246---\n\
5247libhtp:\n\
5248\n\
5249 default-config:\n\
5250 personality: IDS\n\
5251 double-decode-path: yes\n\
5252 double-decode-query: yes\n\
5253 query-plusspace-decode: yes\n\
5254";
5255
5256 ConfCreateContextBackup();
5257 ConfInit();
5258 HtpConfigCreateBackup();
5259 ConfYamlLoadString(input, strlen(input));
5260 HTPConfigure();
5261 char *addr = "4.3.2.1";
5262 memset(&ssn, 0, sizeof(ssn));
5263
5264 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5265 if (f == NULL)
5266 goto end;
5267 f->protoctx = &ssn;
429c6388 5268 f->proto = IPPROTO_TCP;
9a7353e1
VJ
5269
5270 StreamTcpInitConfig(TRUE);
5271
5272 uint32_t u;
5273 for (u = 0; u < httplen1; u++) {
5274 uint8_t flags = 0;
5275
5276 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5277 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5278 else flags = STREAM_TOSERVER;
5279
5280 SCMutexLock(&f->m);
429c6388 5281 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
9a7353e1
VJ
5282 if (r != 0) {
5283 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5284 " 0: ", u, r);
5285 result = 0;
5286 SCMutexUnlock(&f->m);
5287 goto end;
5288 }
5289 SCMutexUnlock(&f->m);
5290 }
5291
5292 htp_state = f->alstate;
5293 if (htp_state == NULL) {
5294 printf("no http state: ");
5295 result = 0;
5296 goto end;
5297 }
5298
5299 uint8_t ref1[] = "/put.php?ip=1.2.3.4&port= 6000";
5300 size_t reflen = sizeof(ref1) - 1;
5301
5302 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5303 if (tx == NULL)
5304 goto end;
5305 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5306 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5307 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5308 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5309 (uintmax_t)reflen,
d5fdfa4b 5310 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
9a7353e1
VJ
5311 goto end;
5312 }
5313
5314 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5315 bstr_len(tx_ud->request_uri_normalized)) != 0)
5316 {
5317 printf("normalized uri \"");
5318 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5319 printf("\" != \"");
5320 PrintRawUriFp(stdout, ref1, reflen);
5321 printf("\": ");
5322 goto end;
5323 }
5324 }
5325
5326 result = 1;
5327
5328end:
429c6388 5329 if (alp_tctx != NULL)
fdefb65b 5330 AppLayerParserThreadCtxFree(alp_tctx);
9a7353e1
VJ
5331 HTPFreeConfig();
5332 ConfDeInit();
5333 ConfRestoreContextBackup();
5334 HtpConfigRestoreBackup();
5335
5336 StreamTcpFreeConfig(TRUE);
5337 if (htp_state != NULL)
5338 HTPStateFree(htp_state);
5339 UTHFreeFlow(f);
5340 return result;
5341}
5342
a8b971c7
VJ
5343/** \test Test 'proxy' URI normalization. Ticket 1008
5344 */
5345static int HTPParserDecodingTest08(void)
5346{
5347 int result = 0;
5348 Flow *f = NULL;
5349 uint8_t httpbuf1[] =
5350 "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n";
5351 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5352 TcpSession ssn;
8dbf7a0d 5353 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
a8b971c7
VJ
5354
5355 HtpState *htp_state = NULL;
5356 int r = 0;
5357 char input[] = "\
5358%YAML 1.1\n\
5359---\n\
5360libhtp:\n\
5361\n\
5362 default-config:\n\
5363 personality: IDS\n\
5364";
5365
5366 ConfCreateContextBackup();
5367 ConfInit();
5368 HtpConfigCreateBackup();
5369 ConfYamlLoadString(input, strlen(input));
5370 HTPConfigure();
5371 char *addr = "4.3.2.1";
5372 memset(&ssn, 0, sizeof(ssn));
5373
5374 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5375 if (f == NULL)
5376 goto end;
5377 f->protoctx = &ssn;
429c6388 5378 f->proto = IPPROTO_TCP;
a8b971c7
VJ
5379
5380 StreamTcpInitConfig(TRUE);
5381
5382 uint32_t u;
5383 for (u = 0; u < httplen1; u++) {
5384 uint8_t flags = 0;
5385
5386 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5387 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5388 else flags = STREAM_TOSERVER;
5389
5390 SCMutexLock(&f->m);
429c6388 5391 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
a8b971c7
VJ
5392 if (r != 0) {
5393 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5394 " 0: ", u, r);
5395 result = 0;
5396 SCMutexUnlock(&f->m);
5397 goto end;
5398 }
5399 SCMutexUnlock(&f->m);
5400 }
5401
5402 htp_state = f->alstate;
5403 if (htp_state == NULL) {
5404 printf("no http state: ");
5405 result = 0;
5406 goto end;
5407 }
5408
5409 uint8_t ref1[] = "/blah/";
5410 size_t reflen = sizeof(ref1) - 1;
5411
5412 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5413 if (tx == NULL)
5414 goto end;
5415 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5416 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5417 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5418 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5419 (uintmax_t)reflen,
d5fdfa4b 5420 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
a8b971c7
VJ
5421 goto end;
5422 }
5423
5424 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5425 bstr_len(tx_ud->request_uri_normalized)) != 0)
5426 {
5427 printf("normalized uri \"");
5428 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5429 printf("\" != \"");
5430 PrintRawUriFp(stdout, ref1, reflen);
5431 printf("\": ");
5432 goto end;
5433 }
5434 }
5435
5436 result = 1;
5437
5438end:
429c6388 5439 if (alp_tctx != NULL)
fdefb65b 5440 AppLayerParserThreadCtxFree(alp_tctx);
a8b971c7
VJ
5441 HTPFreeConfig();
5442 ConfDeInit();
5443 ConfRestoreContextBackup();
5444 HtpConfigRestoreBackup();
5445
5446 StreamTcpFreeConfig(TRUE);
5447 if (htp_state != NULL)
5448 HTPStateFree(htp_state);
5449 UTHFreeFlow(f);
5450 return result;
5451}
5452
5453/** \test Test 'proxy' URI normalization. Ticket 1008
5454 */
5455static int HTPParserDecodingTest09(void)
5456{
5457 int result = 0;
5458 Flow *f = NULL;
5459 uint8_t httpbuf1[] =
5460 "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n";
5461 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5462 TcpSession ssn;
8dbf7a0d 5463 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
a8b971c7
VJ
5464
5465 HtpState *htp_state = NULL;
5466 int r = 0;
5467 char input[] = "\
5468%YAML 1.1\n\
5469---\n\
5470libhtp:\n\
5471\n\
5472 default-config:\n\
5473 personality: IDS\n\
5474 uri-include-all: true\n\
5475";
5476
5477 ConfCreateContextBackup();
5478 ConfInit();
5479 HtpConfigCreateBackup();
5480 ConfYamlLoadString(input, strlen(input));
5481 HTPConfigure();
5482 char *addr = "4.3.2.1";
5483 memset(&ssn, 0, sizeof(ssn));
5484
5485 f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80);
5486 if (f == NULL)
5487 goto end;
5488 f->protoctx = &ssn;
429c6388 5489 f->proto = IPPROTO_TCP;
a8b971c7
VJ
5490
5491 StreamTcpInitConfig(TRUE);
5492
5493 uint32_t u;
5494 for (u = 0; u < httplen1; u++) {
5495 uint8_t flags = 0;
5496
5497 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5498 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5499 else flags = STREAM_TOSERVER;
5500
5501 SCMutexLock(&f->m);
429c6388 5502 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
a8b971c7
VJ
5503 if (r != 0) {
5504 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5505 " 0: ", u, r);
5506 result = 0;
5507 SCMutexUnlock(&f->m);
5508 goto end;
5509 }
5510 SCMutexUnlock(&f->m);
5511 }
5512
5513 htp_state = f->alstate;
5514 if (htp_state == NULL) {
5515 printf("no http state: ");
5516 result = 0;
5517 goto end;
5518 }
5519
5520 uint8_t ref1[] = "http://suricata-ids.org/blah/";
5521 size_t reflen = sizeof(ref1) - 1;
5522
5523 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5524 if (tx == NULL)
5525 goto end;
5526 HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx);
5527 if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) {
5528 if (reflen != bstr_len(tx_ud->request_uri_normalized)) {
5529 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
5530 (uintmax_t)reflen,
d5fdfa4b 5531 (uintmax_t)bstr_len(tx_ud->request_uri_normalized));
a8b971c7
VJ
5532 goto end;
5533 }
5534
5535 if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1,
5536 bstr_len(tx_ud->request_uri_normalized)) != 0)
5537 {
5538 printf("normalized uri \"");
5539 PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized));
5540 printf("\" != \"");
5541 PrintRawUriFp(stdout, ref1, reflen);
5542 printf("\": ");
5543 goto end;
5544 }
5545 }
5546
5547 result = 1;
5548
5549end:
429c6388 5550 if (alp_tctx != NULL)
fdefb65b 5551 AppLayerParserThreadCtxFree(alp_tctx);
a8b971c7
VJ
5552 HTPFreeConfig();
5553 ConfDeInit();
5554 ConfRestoreContextBackup();
5555 HtpConfigRestoreBackup();
5556
5557 StreamTcpFreeConfig(TRUE);
5558 if (htp_state != NULL)
5559 HTPStateFree(htp_state);
5560 UTHFreeFlow(f);
5561 return result;
5562}
5563
fcc21ae4
VJ
5564/** \test BG box crash -- chunks are messed up. Observed for real. */
5565static int HTPBodyReassemblyTest01(void)
5566{
5567 int result = 0;
5568 HtpTxUserData htud;
5569 memset(&htud, 0x00, sizeof(htud));
5570 HtpState hstate;
5571 memset(&hstate, 0x00, sizeof(hstate));
5572 Flow flow;
5573 memset(&flow, 0x00, sizeof(flow));
9634e60e 5574 AppLayerParserState *parser = AppLayerParserStateAlloc();
94e25276
AS
5575 htp_tx_t tx;
5576 memset(&tx, 0, sizeof(tx));
fcc21ae4
VJ
5577
5578 hstate.f = &flow;
c7ae662d 5579 flow.alparser = parser;
fcc21ae4
VJ
5580
5581 uint8_t chunk1[] = "--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r";
5582 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";
5583
5584 int r = HtpBodyAppendChunk(&htud, &htud.request_body, (uint8_t *)chunk1, sizeof(chunk1)-1);
5585 BUG_ON(r != 0);
5586 r = HtpBodyAppendChunk(&htud, &htud.request_body, (uint8_t *)chunk2, sizeof(chunk2)-1);
5587 BUG_ON(r != 0);
5588
5589 uint8_t *chunks_buffer = NULL;
5590 uint32_t chunks_buffer_len = 0;
5591
5592 HtpRequestBodyReassemble(&htud, &chunks_buffer, &chunks_buffer_len);
5593 if (chunks_buffer == NULL) {
5594 goto end;
5595 }
5596#ifdef PRINT
5597 printf("REASSCHUNK START: \n");
5598 PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
5599 printf("REASSCHUNK END: \n");
5600#endif
5601
94e25276 5602 HtpRequestBodyHandleMultipart(&hstate, &htud, &tx, chunks_buffer, chunks_buffer_len);
fcc21ae4
VJ
5603
5604 if (htud.request_body.content_len_so_far != 669) {
5605 printf("htud.request_body.content_len_so_far %"PRIu64": ", htud.request_body.content_len_so_far);
5606 goto end;
5607 }
5608
5609 if (hstate.files_ts != NULL)
5610 goto end;
5611
5612 result = 1;
5613end:
5614 return result;
5615}
5616
5617/** \test BG crash */
8f1d7503
KS
5618static int HTPSegvTest01(void)
5619{
fcc21ae4
VJ
5620 int result = 0;
5621 Flow *f = NULL;
5622 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";
5623 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5624 char input[] = "\
5625%YAML 1.1\n\
5626---\n\
5627libhtp:\n\
5628\n\
5629 default-config:\n\
5630 personality: IDS\n\
5631 double-decode-path: no\n\
5632 double-decode-query: no\n\
5633 request-body-limit: 0\n\
5634 response-body-limit: 0\n\
5635";
5636
5637 ConfCreateContextBackup();
5638 ConfInit();
5639 HtpConfigCreateBackup();
5640 ConfYamlLoadString(input, strlen(input));
5641 HTPConfigure();
5642
5643 TcpSession ssn;
5644 HtpState *http_state = NULL;
8dbf7a0d 5645 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
fcc21ae4
VJ
5646
5647 memset(&ssn, 0, sizeof(ssn));
5648
5649 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5650 if (f == NULL)
5651 goto end;
5652 f->protoctx = &ssn;
429c6388 5653 f->proto = IPPROTO_TCP;
fcc21ae4
VJ
5654
5655 StreamTcpInitConfig(TRUE);
5656
5657 SCLogDebug("\n>>>> processing chunk 1 <<<<\n");
cd3e32ce 5658 SCMutexLock(&f->m);
429c6388 5659 int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1);
fcc21ae4
VJ
5660 if (r != 0) {
5661 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
5662 result = 0;
cd3e32ce 5663 SCMutexUnlock(&f->m);
fcc21ae4
VJ
5664 goto end;
5665 }
cd3e32ce 5666 SCMutexUnlock(&f->m);
fcc21ae4 5667 SCLogDebug("\n>>>> processing chunk 1 again <<<<\n");
cd3e32ce 5668 SCMutexLock(&f->m);
429c6388 5669 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
fcc21ae4
VJ
5670 if (r != 0) {
5671 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
5672 result = 0;
cd3e32ce 5673 SCMutexUnlock(&f->m);
fcc21ae4
VJ
5674 goto end;
5675 }
cd3e32ce 5676 SCMutexUnlock(&f->m);
fcc21ae4
VJ
5677
5678 http_state = f->alstate;
5679 if (http_state == NULL) {
5680 printf("no http state: ");
5681 result = 0;
5682 goto end;
5683 }
5684
cd3e32ce 5685 SCMutexLock(&f->m);
429c6388 5686 AppLayerDecoderEvents *decoder_events = AppLayerParserGetDecoderEvents(f->alparser);
fcc21ae4
VJ
5687 if (decoder_events != NULL) {
5688 printf("app events: ");
cd3e32ce 5689 SCMutexUnlock(&f->m);
fcc21ae4
VJ
5690 goto end;
5691 }
cd3e32ce 5692 SCMutexUnlock(&f->m);
fcc21ae4
VJ
5693 result = 1;
5694end:
429c6388 5695 if (alp_tctx != NULL)
fdefb65b 5696 AppLayerParserThreadCtxFree(alp_tctx);
fcc21ae4
VJ
5697 HTPFreeConfig();
5698 ConfDeInit();
5699 ConfRestoreContextBackup();
5700 HtpConfigRestoreBackup();
5701 StreamTcpFreeConfig(TRUE);
5702 if (http_state != NULL)
5703 HTPStateFree(http_state);
5704 UTHFreeFlow(f);
5705 return result;
5706}
5707
129b6a65 5708/** \test Test really long request, this should result in HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG */
8f1d7503
KS
5709int HTPParserTest14(void)
5710{
129b6a65
VJ
5711 int result = 0;
5712 Flow *f = NULL;
5713 char *httpbuf = NULL;
5714 size_t len = 18887;
5715 TcpSession ssn;
5716 HtpState *htp_state = NULL;
5717 int r = 0;
5718 char input[] = "\
5719%YAML 1.1\n\
5720---\n\
5721libhtp:\n\
5722\n\
5723 default-config:\n\
5724 personality: IDS\n\
5725 double-decode-path: no\n\
5726 double-decode-query: no\n\
5727 request-body-limit: 0\n\
5728 response-body-limit: 0\n\
5729";
8dbf7a0d 5730 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
129b6a65
VJ
5731
5732 memset(&ssn, 0, sizeof(ssn));
5733
5734 ConfCreateContextBackup();
5735 ConfInit();
5736 HtpConfigCreateBackup();
5737 ConfYamlLoadString(input, strlen(input));
5738 HTPConfigure();
5739
5740 httpbuf = SCMalloc(len);
79fcf137 5741 if (unlikely(httpbuf == NULL))
129b6a65
VJ
5742 goto end;
5743 memset(httpbuf, 0x00, len);
5744
5745 /* create the request with a longer than 18k cookie */
5746 strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n"
5747 "Host: myhost.lan\r\n"
5748 "Connection: keep-alive\r\n"
5749 "Accept: */*\r\n"
5750 "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"
5751 "Referer: http://blah.lan/\r\n"
5752 "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
5753 "Cookie: ", len);
5754 size_t o = strlen(httpbuf);
5755 for ( ; o < len - 4; o++) {
5756 httpbuf[o] = 'A';
5757 }
5758 httpbuf[len - 4] = '\r';
5759 httpbuf[len - 3] = '\n';
5760 httpbuf[len - 2] = '\r';
5761 httpbuf[len - 1] = '\n';
5762
5763 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5764 if (f == NULL)
5765 goto end;
5766 f->protoctx = &ssn;
429c6388 5767 f->proto = IPPROTO_TCP;
129b6a65
VJ
5768
5769 StreamTcpInitConfig(TRUE);
5770
5771 uint32_t u;
5772 for (u = 0; u < len; u++) {
5773 uint8_t flags = 0;
5774
5775 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5776 else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5777 else flags = STREAM_TOSERVER;
5778
5779 SCMutexLock(&f->m);
429c6388 5780 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)&httpbuf[u], 1);
129b6a65
VJ
5781 if (u < 18294) { /* first 18294 bytes should result in 0 */
5782 if (r != 0) {
5783 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5784 " 0: ", u, r);
5785 result = 0;
5786 SCMutexUnlock(&f->m);
5787 goto end;
5788 }
5789 } else if (u == 18294UL) { /* byte 18294 should result in error */
5790 if (r != -1) {
5791 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5792 " -1: ", u, r);
5793 result = 0;
5794 SCMutexUnlock(&f->m);
5795 goto end;
5796 }
5797
5798 /* break out, htp state is in error state now */
5799 SCMutexUnlock(&f->m);
5800 break;
5801 }
5802 SCMutexUnlock(&f->m);
5803 }
5804 htp_state = f->alstate;
5805 if (htp_state == NULL) {
5806 printf("no http state: ");
5807 goto end;
5808 }
5809
5810 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5811 if (tx == NULL || tx->request_method_number != HTP_M_GET || tx->request_protocol_number != HTP_PROTOCOL_1_1)
5812 {
5813 printf("expected method M_GET and got %s: , expected protocol "
5814 "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
5815 bstr_util_strdup_to_c(tx->request_protocol));
5816 goto end;
5817 }
5818
5819 SCMutexLock(&f->m);
3f5acc54 5820 AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
129b6a65
VJ
5821 if (decoder_events == NULL) {
5822 printf("no app events: ");
5823 SCMutexUnlock(&f->m);
5824 goto end;
5825 }
5826 SCMutexUnlock(&f->m);
5827
63679175
VJ
5828 if (decoder_events->events[0] != HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG) {
5829 printf("HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG not set: ");
129b6a65
VJ
5830 goto end;
5831 }
5832
5833 result = 1;
5834end:
429c6388 5835 if (alp_tctx != NULL)
fdefb65b 5836 AppLayerParserThreadCtxFree(alp_tctx);
129b6a65
VJ
5837 StreamTcpFreeConfig(TRUE);
5838 if (htp_state != NULL)
5839 HTPStateFree(htp_state);
5840 UTHFreeFlow(f);
5841 if (httpbuf != NULL)
5842 SCFree(httpbuf);
5843 HTPFreeConfig();
5844 ConfDeInit();
5845 ConfRestoreContextBackup();
5846 HtpConfigRestoreBackup();
5847 return result;
5848}
fb496791
VJ
5849
5850/** \test Test really long request (same as HTPParserTest14), now with config
5851 * update to allow it */
8f1d7503
KS
5852int HTPParserTest15(void)
5853{
fb496791
VJ
5854 int result = 0;
5855 Flow *f = NULL;
5856 char *httpbuf = NULL;
5857 size_t len = 18887;
5858 TcpSession ssn;
5859 HtpState *htp_state = NULL;
5860 int r = 0;
5861 char input[] = "\
5862%YAML 1.1\n\
5863---\n\
5864libhtp:\n\
5865\n\
5866 default-config:\n\
5867 personality: IDS\n\
5868 double-decode-path: no\n\
5869 double-decode-query: no\n\
5870 request-body-limit: 0\n\
5871 response-body-limit: 0\n\
5872 meta-field-limit: 20000\n\
5873";
8dbf7a0d 5874 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
fb496791
VJ
5875
5876 memset(&ssn, 0, sizeof(ssn));
5877
5878 ConfCreateContextBackup();
5879 ConfInit();
5880 HtpConfigCreateBackup();
5881 ConfYamlLoadString(input, strlen(input));
5882 HTPConfigure();
5883
5884 httpbuf = SCMalloc(len);
5885 if (unlikely(httpbuf == NULL))
5886 goto end;
5887 memset(httpbuf, 0x00, len);
5888
5889 /* create the request with a longer than 18k cookie */
5890 strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n"
5891 "Host: myhost.lan\r\n"
5892 "Connection: keep-alive\r\n"
5893 "Accept: */*\r\n"
5894 "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"
5895 "Referer: http://blah.lan/\r\n"
5896 "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n"
5897 "Cookie: ", len);
5898 size_t o = strlen(httpbuf);
5899 for ( ; o < len - 4; o++) {
5900 httpbuf[o] = 'A';
5901 }
5902 httpbuf[len - 4] = '\r';
5903 httpbuf[len - 3] = '\n';
5904 httpbuf[len - 2] = '\r';
5905 httpbuf[len - 1] = '\n';
5906
5907 f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
5908 if (f == NULL)
5909 goto end;
5910 f->protoctx = &ssn;
429c6388 5911 f->proto = IPPROTO_TCP;
fb496791
VJ
5912
5913 StreamTcpInitConfig(TRUE);
5914
5915 uint32_t u;
5916 for (u = 0; u < len; u++) {
5917 uint8_t flags = 0;
5918
5919 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
5920 else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
5921 else flags = STREAM_TOSERVER;
5922
5923 SCMutexLock(&f->m);
429c6388 5924 r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)&httpbuf[u], 1);
fb496791
VJ
5925 if (r != 0) {
5926 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
5927 " 0: ", u, r);
5928 result = 0;
5929 SCMutexUnlock(&f->m);
5930 goto end;
5931 }
5932 SCMutexUnlock(&f->m);
5933 }
5934 htp_state = f->alstate;
5935 if (htp_state == NULL) {
5936 printf("no http state: ");
5937 goto end;
5938 }
5939
5940 htp_tx_t *tx = HTPStateGetTx(htp_state, 0);
5941 if (tx == NULL || tx->request_method_number != HTP_M_GET || tx->request_protocol_number != HTP_PROTOCOL_1_1)
5942 {
5943 printf("expected method M_GET and got %s: , expected protocol "
5944 "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
5945 bstr_util_strdup_to_c(tx->request_protocol));
5946 goto end;
5947 }
5948
5949 SCMutexLock(&f->m);
3f5acc54 5950 AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0);
fb496791
VJ
5951 if (decoder_events != NULL) {
5952 printf("app events: ");
5953 SCMutexUnlock(&f->m);
5954 goto end;
5955 }
5956 SCMutexUnlock(&f->m);
5957
5958 result = 1;
5959end:
429c6388 5960 if (alp_tctx != NULL)
fdefb65b 5961 AppLayerParserThreadCtxFree(alp_tctx);
fb496791
VJ
5962 StreamTcpFreeConfig(TRUE);
5963 if (htp_state != NULL)
5964 HTPStateFree(htp_state);
5965 UTHFreeFlow(f);
5966 if (httpbuf != NULL)
5967 SCFree(httpbuf);
5968 HTPFreeConfig();
5969 ConfDeInit();
5970 ConfRestoreContextBackup();
5971 HtpConfigRestoreBackup();
5972 return result;
5973}
c352bff6
VJ
5974#endif /* UNITTESTS */
5975
07f7ba55
GS
5976/**
5977 * \brief Register the Unit tests for the HTTP protocol
5978 */
8f1d7503
KS
5979void HTPParserRegisterTests(void)
5980{
07f7ba55
GS
5981#ifdef UNITTESTS
5982 UtRegisterTest("HTPParserTest01", HTPParserTest01, 1);
2d6cf71d
GS
5983 UtRegisterTest("HTPParserTest02", HTPParserTest02, 1);
5984 UtRegisterTest("HTPParserTest03", HTPParserTest03, 1);
5985 UtRegisterTest("HTPParserTest04", HTPParserTest04, 1);
5986 UtRegisterTest("HTPParserTest05", HTPParserTest05, 1);
fc2f7f29 5987 UtRegisterTest("HTPParserTest06", HTPParserTest06, 1);
15ce8503 5988 UtRegisterTest("HTPParserTest07", HTPParserTest07, 1);
326047ee
VJ
5989 UtRegisterTest("HTPParserTest08", HTPParserTest08, 1);
5990 UtRegisterTest("HTPParserTest09", HTPParserTest09, 1);
f2f8dfd8 5991 UtRegisterTest("HTPParserTest10", HTPParserTest10, 1);
ab3fcb01
VJ
5992 UtRegisterTest("HTPParserTest11", HTPParserTest11, 1);
5993 UtRegisterTest("HTPParserTest12", HTPParserTest12, 1);
0c98980e 5994 UtRegisterTest("HTPParserTest13", HTPParserTest13, 1);
a9cdd2bb
BR
5995 UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01, 1);
5996 UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02, 1);
5997 UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03, 1);
48cf0585 5998#if 0 /* disabled when we upgraded to libhtp 0.5.x */
028c6c17 5999 UtRegisterTest("HTPParserConfigTest04", HTPParserConfigTest04, 1);
48cf0585 6000#endif
a0ee6ade 6001
ad827ad0
VJ
6002 UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01, 1);
6003 UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02, 1);
e839cea9 6004 UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03, 1);
cc51eec5
VJ
6005 UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04, 1);
6006 UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05, 1);
9a7353e1
VJ
6007 UtRegisterTest("HTPParserDecodingTest06", HTPParserDecodingTest06, 1);
6008 UtRegisterTest("HTPParserDecodingTest07", HTPParserDecodingTest07, 1);
a8b971c7
VJ
6009 UtRegisterTest("HTPParserDecodingTest08", HTPParserDecodingTest08, 1);
6010 UtRegisterTest("HTPParserDecodingTest09", HTPParserDecodingTest09, 1);
ad827ad0 6011
fcc21ae4
VJ
6012 UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01, 1);
6013
6014 UtRegisterTest("HTPSegvTest01", HTPSegvTest01, 1);
fb496791 6015
129b6a65 6016 UtRegisterTest("HTPParserTest14", HTPParserTest14, 1);
fb496791 6017 UtRegisterTest("HTPParserTest15", HTPParserTest15, 1);
fcc21ae4 6018
a0ee6ade 6019 HTPFileParserRegisterTests();
07f7ba55
GS
6020#endif /* UNITTESTS */
6021}
6022
60a99915
EL
6023/**
6024 * @}
6025 */