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