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