]> git.ipfire.org Git - people/ms/suricata.git/blame - src/app-layer-htp.c
doc: comment link between Flow and application layer.
[people/ms/suricata.git] / src / app-layer-htp.c
CommitLineData
ce019275
WM
1/* Copyright (C) 2007-2010 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
07f7ba55
GS
17
18/**
ce019275 19 * \file
07f7ba55
GS
20 *
21 * \author Gurvinder Singh <gurvindersinghdahiya@gmail.com>
0165b3f0 22 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
a9cdd2bb 23 * \author Brian Rectanus <brectanu@gmail.com>
07f7ba55 24 *
ce019275 25 * This file provides a HTTP protocol support for the engine using HTP library.
07f7ba55
GS
26 */
27
5c6a65dc 28#include "suricata.h"
ecf86f9c 29#include "suricata-common.h"
07f7ba55
GS
30#include "debug.h"
31#include "decode.h"
32#include "threads.h"
07f7ba55
GS
33
34#include "util-print.h"
35#include "util-pool.h"
a9cdd2bb 36#include "util-radix-tree.h"
07f7ba55
GS
37
38#include "stream-tcp-private.h"
39#include "stream-tcp-reassemble.h"
6a53ab9c 40#include "stream-tcp.h"
07f7ba55
GS
41#include "stream.h"
42
43#include "app-layer-protos.h"
44#include "app-layer-parser.h"
fc2f7f29 45#include "app-layer-htp.h"
07f7ba55 46
705471e4 47#include "util-spm.h"
07f7ba55
GS
48#include "util-debug.h"
49#include "app-layer-htp.h"
fc2f7f29 50#include "util-time.h"
25a3a5c6 51#include <htp/htp.h>
07f7ba55 52
06a65cb4
PR
53#include "util-unittest.h"
54#include "util-unittest-helper.h"
55#include "flow-util.h"
56
57#include "detect-engine.h"
58#include "detect-engine-state.h"
59#include "detect-parse.h"
60
a9cdd2bb
BR
61#include "conf.h"
62
ead13bda 63/** Need a linked list in order to keep track of these */
6ebe7b7c
VJ
64typedef struct HTPCfgRec_ {
65 htp_cfg_t *cfg;
66 struct HTPCfgRec_ *next;
67
68 /** max size of the client body we inspect */
69 uint32_t request_body_limit;
70} HTPCfgRec;
a9cdd2bb 71
ead13bda 72/** Fast lookup tree (radix) for the various HTP configurations */
a9cdd2bb 73static SCRadixTree *cfgtree;
ead13bda 74/** List of HTP configurations. */
a9cdd2bb
BR
75static HTPCfgRec cfglist;
76
07f7ba55 77#ifdef DEBUG
e26833be 78static SCMutex htp_state_mem_lock = PTHREAD_MUTEX_INITIALIZER;
07f7ba55
GS
79static uint64_t htp_state_memuse = 0;
80static uint64_t htp_state_memcnt = 0;
81#endif
97d49d8f
AS
82
83static uint8_t need_htp_request_body = 0;
07f7ba55 84
9a58a025 85#ifdef DEBUG
a9cdd2bb
BR
86/**
87 * \internal
88 *
89 * \brief Lookup the HTP personality string from the numeric personality.
90 *
91 * \todo This needs to be a libhtp function.
92 */
93static const char *HTPLookupPersonalityString(int p)
94{
95#define CASE_HTP_PERSONALITY_STRING(p) \
96 case HTP_SERVER_ ## p: return #p
97
98 switch (p) {
99 CASE_HTP_PERSONALITY_STRING(MINIMAL);
100 CASE_HTP_PERSONALITY_STRING(GENERIC);
101 CASE_HTP_PERSONALITY_STRING(IDS);
102 CASE_HTP_PERSONALITY_STRING(IIS_4_0);
103 CASE_HTP_PERSONALITY_STRING(IIS_5_0);
104 CASE_HTP_PERSONALITY_STRING(IIS_5_1);
105 CASE_HTP_PERSONALITY_STRING(IIS_6_0);
106 CASE_HTP_PERSONALITY_STRING(IIS_7_0);
107 CASE_HTP_PERSONALITY_STRING(IIS_7_5);
108 CASE_HTP_PERSONALITY_STRING(TOMCAT_6_0);
109 CASE_HTP_PERSONALITY_STRING(APACHE);
110 CASE_HTP_PERSONALITY_STRING(APACHE_2_2);
111 }
112
113 return NULL;
114}
9a58a025 115#endif /* DEBUG */
a9cdd2bb
BR
116
117/**
118 * \internal
119 *
120 * \brief Lookup the numeric HTP personality from a string.
121 *
122 * \todo This needs to be a libhtp function.
123 */
124static int HTPLookupPersonality(const char *str)
125{
126#define IF_HTP_PERSONALITY_NUM(p) \
127 if (strcasecmp(#p, str) == 0) return HTP_SERVER_ ## p
128
129 IF_HTP_PERSONALITY_NUM(MINIMAL);
130 IF_HTP_PERSONALITY_NUM(GENERIC);
131 IF_HTP_PERSONALITY_NUM(IDS);
132 IF_HTP_PERSONALITY_NUM(IIS_4_0);
133 IF_HTP_PERSONALITY_NUM(IIS_5_0);
134 IF_HTP_PERSONALITY_NUM(IIS_5_1);
135 IF_HTP_PERSONALITY_NUM(IIS_6_0);
136 IF_HTP_PERSONALITY_NUM(IIS_7_0);
137 IF_HTP_PERSONALITY_NUM(IIS_7_5);
138 IF_HTP_PERSONALITY_NUM(TOMCAT_6_0);
139 IF_HTP_PERSONALITY_NUM(APACHE);
140 IF_HTP_PERSONALITY_NUM(APACHE_2_2);
141
142 return -1;
143}
144
07f7ba55
GS
145/** \brief Function to allocates the HTTP state memory and also creates the HTTP
146 * connection parser to be used by the HTP library
147 */
148static void *HTPStateAlloc(void)
149{
48248687
VJ
150 SCEnter();
151
25a3a5c6 152 HtpState *s = SCMalloc(sizeof(HtpState));
9f4fae5b 153 if (s == NULL)
48248687 154 goto error;
07f7ba55 155
48248687 156 memset(s, 0x00, sizeof(HtpState));
07f7ba55 157
187949b9
VJ
158#ifdef DEBUG
159 SCMutexLock(&htp_state_mem_lock);
160 htp_state_memcnt++;
161 htp_state_memuse += sizeof(HtpState);
6fca55e0 162 SCLogDebug("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
187949b9
VJ
163 SCMutexUnlock(&htp_state_mem_lock);
164#endif
70b32f73 165
48248687
VJ
166 SCReturnPtr((void *)s, "void");
167
168error:
187949b9 169 if (s != NULL) {
25a3a5c6 170 SCFree(s);
187949b9 171 }
48248687
VJ
172
173 SCReturnPtr(NULL, "void");
07f7ba55
GS
174}
175
176/** \brief Function to frees the HTTP state memory and also frees the HTTP
177 * connection parser memory which was used by the HTP library
178 */
25a3a5c6 179void HTPStateFree(void *state)
07f7ba55 180{
48248687
VJ
181 SCEnter();
182
183 HtpState *s = (HtpState *)state;
a56592e5
GIG
184 if (s == NULL) {
185 SCReturn;
186 }
48248687 187
06a65cb4
PR
188 /* Unset the body inspection */
189 s->flags &=~ HTP_FLAG_NEW_BODY_SET;
190
07f7ba55 191 /* free the connection parser memory used by HTP library */
a56592e5 192 if (s->connp != NULL) {
6fca55e0
VJ
193 SCLogDebug("freeing HTP state");
194
bc55fb27
VJ
195 size_t i;
196 /* free the list of body chunks */
197 if (s->connp->conn != NULL) {
198 for (i = 0; i < list_size(s->connp->conn->transactions); i++) {
199 htp_tx_t *tx = (htp_tx_t *)list_get(s->connp->conn->transactions, i);
200 if (tx != NULL) {
201 SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(tx);
202 if (htud != NULL) {
203 HtpBodyFree(&htud->body);
204 SCFree(htud);
06a65cb4 205 }
bc55fb27 206 htp_tx_set_user_data(tx, NULL);
06a65cb4
PR
207 }
208 }
48248687 209 }
bc55fb27 210 htp_connp_destroy_all(s->connp);
48248687 211 }
07f7ba55 212
25a3a5c6 213 SCFree(s);
48248687 214
07f7ba55 215#ifdef DEBUG
e26833be 216 SCMutexLock(&htp_state_mem_lock);
07f7ba55 217 htp_state_memcnt--;
187949b9 218 htp_state_memuse -= sizeof(HtpState);
6fca55e0 219 SCLogDebug("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
e26833be 220 SCMutexUnlock(&htp_state_mem_lock);
07f7ba55 221#endif
48248687
VJ
222
223 SCReturn;
07f7ba55
GS
224}
225
70b32f73
VJ
226/**
227 * \brief Update the transaction id based on the http state
228 */
229void HTPStateUpdateTransactionId(void *state, uint16_t *id) {
230 SCEnter();
231
232 HtpState *s = (HtpState *)state;
233
3644e90a
VJ
234 SCLogDebug("original id %"PRIu16", s->transaction_cnt %"PRIu16,
235 *id, (s->transaction_cnt));
70b32f73 236
3644e90a
VJ
237 if ((s->transaction_cnt) > (*id)) {
238 SCLogDebug("original id %"PRIu16", updating with s->transaction_cnt %"PRIu16,
239 *id, (s->transaction_cnt));
70b32f73 240
3644e90a 241 (*id) = (s->transaction_cnt);
70b32f73
VJ
242
243 SCLogDebug("updated id %"PRIu16, *id);
244 }
245
246 SCReturn;
247}
248
249/**
250 * \brief HTP transaction cleanup callback
251 *
252 * \warning We cannot actually free the transactions here. It seems that
253 * HTP only accepts freeing of transactions in the response callback.
254 */
255void HTPStateTransactionFree(void *state, uint16_t id) {
256 SCEnter();
257
258 HtpState *s = (HtpState *)state;
259
260 s->transaction_done = id;
261 SCLogDebug("state %p, id %"PRIu16, s, id);
262
263 /* we can't remove the actual transactions here */
264
265 SCReturn;
266}
267
97d49d8f
AS
268/**
269 * \brief Sets a flag that informs the HTP app layer that some module in the
270 * engine needs the http request body data.
bc55fb27 271 * \initonly
97d49d8f
AS
272 */
273void AppLayerHtpEnableRequestBodyCallback(void)
274{
70b32f73 275 SCEnter();
97d49d8f 276 need_htp_request_body = 1;
70b32f73 277 SCReturn;
97d49d8f
AS
278}
279
280
07f7ba55
GS
281/**
282 * \brief Function to handle the reassembled data from client and feed it to
283 * the HTP library to process it.
284 *
92d74fd4 285 * \param flow Pointer to the flow the data belong to
07f7ba55
GS
286 * \param htp_state Pointer the state in which the parsed value to be stored
287 * \param pstate Application layer parser state for this session
288 * \param input Pointer the received HTTP client data
289 * \param input_len Length in bytes of the received data
290 * \param output Pointer to the output (not used in this function)
291 *
2d6cf71d 292 * \retval On success returns 1 or on failure returns -1
07f7ba55 293 */
fc2f7f29
GS
294static int HTPHandleRequestData(Flow *f, void *htp_state,
295 AppLayerParserState *pstate,
07f7ba55 296 uint8_t *input, uint32_t input_len,
18fe3818 297 AppLayerParserResult *output)
07f7ba55 298{
1b39e602 299 SCEnter();
0a85fd67
GS
300 int r = -1;
301 int ret = 1;
70b32f73 302
b8fec77f
VJ
303 //PrintRawDataFp(stdout, input, input_len);
304
07f7ba55 305 HtpState *hstate = (HtpState *)htp_state;
a9cdd2bb
BR
306
307 /* On the first invocation, create the connection parser structure to
308 * be used by HTP library. This is looked up via IP in the radix
309 * tree. Failing that, the default HTP config is used.
310 */
311 if (NULL == hstate->connp ) {
ead13bda
VJ
312 htp_cfg_t *htp = cfglist.cfg; /* Default to the global HTP config */
313 SCRadixNode *cfgnode = NULL;
314
a9cdd2bb
BR
315 if (AF_INET == f->dst.family) {
316 SCLogDebug("Looking up HTP config for ipv4 %08x", *GET_IPV4_DST_ADDR_PTR(f));
317 cfgnode = SCRadixFindKeyIPV4BestMatch((uint8_t *)GET_IPV4_DST_ADDR_PTR(f), cfgtree);
318 }
78e15ea7 319 else if (AF_INET6 == f->dst.family) {
a9cdd2bb
BR
320 SCLogDebug("Looking up HTP config for ipv6");
321 cfgnode = SCRadixFindKeyIPV6BestMatch((uint8_t *)GET_IPV6_DST_ADDR(f), cfgtree);
322 }
78e15ea7
VJ
323 else {
324 SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown address family, bug!");
325 goto error;
326 }
327
f81fccd6
VJ
328 if (cfgnode != NULL) {
329 HTPCfgRec *htp_cfg_rec = SC_RADIX_NODE_USERDATA(cfgnode, HTPCfgRec);
330 if (htp_cfg_rec != NULL) {
331 htp = htp_cfg_rec->cfg;
332 SCLogDebug("LIBHTP using config: %p", htp);
6ebe7b7c 333
743ed762
VJ
334 hstate->request_body_limit = htp_cfg_rec->request_body_limit;
335 }
a9cdd2bb
BR
336 } else {
337 SCLogDebug("Using default HTP config: %p", htp);
6ebe7b7c
VJ
338
339 hstate->request_body_limit = cfglist.request_body_limit;
a9cdd2bb
BR
340 }
341
342 if (NULL == htp) {
4129146a 343 BUG_ON(htp == NULL);
ead13bda 344 /* should never happen if HTPConfigure is properly invoked */
a9cdd2bb
BR
345 goto error;
346 }
347
348 hstate->connp = htp_connp_create(htp);
349 if (hstate->connp == NULL) {
350 goto error;
351 }
352
353 htp_connp_set_user_data(hstate->connp, (void *)hstate);
354
355 SCLogDebug("New hstate->connp %p", hstate->connp);
356 }
07f7ba55 357
4129146a
VJ
358 /* the code block above should make sure connp is never NULL here */
359 BUG_ON(hstate->connp == NULL);
360
8e444f17
GS
361 if (hstate->connp->in_status == STREAM_STATE_ERROR) {
362 SCLogError(SC_ERR_ALPARSER, "Inbound parser is in error state, no"
363 " need to feed data to libhtp");
364 SCReturnInt(-1);
365 }
366
0165b3f0
PR
367 /* Unset the body inspection (the callback should
368 * reactivate it if necessary) */
70b32f73 369 hstate->flags &=~ HTP_FLAG_NEW_BODY_SET;
0165b3f0 370
fc2f7f29 371 /* Open the HTTP connection on receiving the first request */
ba7e8012 372 if (!(hstate->flags & HTP_FLAG_STATE_OPEN)) {
48248687 373 SCLogDebug("opening htp handle at %p", hstate->connp);
ba7e8012 374
fc2f7f29
GS
375 htp_connp_open(hstate->connp, NULL, f->sp, NULL, f->dp, 0);
376 hstate->flags |= HTP_FLAG_STATE_OPEN;
ba7e8012 377 } else {
48248687 378 SCLogDebug("using existing htp handle at %p", hstate->connp);
fc2f7f29 379 }
07f7ba55 380
70b32f73 381 /* pass the new data to the htp parser */
0a85fd67 382 r = htp_connp_req_data(hstate->connp, 0, input, input_len);
148883ce 383
bf236e45
GS
384 switch(r) {
385 case STREAM_STATE_ERROR:
148883ce 386 if (hstate->connp->last_error != NULL) {
bf236e45
GS
387 SCLogError(SC_ERR_ALPARSER, "Error in parsing HTTP client "
388 "request: [%"PRId32"] [%s] [%"PRId32"] %s",
389 hstate->connp->last_error->level,
390 hstate->connp->last_error->file,
391 hstate->connp->last_error->line,
392 hstate->connp->last_error->msg);
148883ce 393 } else {
bf236e45
GS
394 SCLogError(SC_ERR_ALPARSER, "Error in parsing HTTP client "
395 "request");
148883ce 396 }
bf236e45
GS
397 hstate->flags |= HTP_FLAG_STATE_ERROR;
398 hstate->flags &= ~HTP_FLAG_STATE_DATA;
50f7d0a8 399 hstate->flags &= ~HTP_FLAG_NEW_BODY_SET;
bf236e45
GS
400 ret = -1;
401 break;
402 case STREAM_STATE_DATA:
403 hstate->flags |= HTP_FLAG_STATE_DATA;
404 break;
405 case STREAM_STATE_DATA_OTHER:
406 SCLogDebug("CONNECT not supported yet");
407 hstate->flags |= HTP_FLAG_STATE_ERROR;
408 hstate->flags &= ~HTP_FLAG_STATE_DATA;
50f7d0a8 409 hstate->flags &= ~HTP_FLAG_NEW_BODY_SET;
bf236e45
GS
410 ret = -1;
411 break;
412 default:
413 hstate->flags &= ~HTP_FLAG_STATE_DATA;
50f7d0a8 414 hstate->flags &= ~HTP_FLAG_NEW_BODY_SET;
70b32f73 415 }
07f7ba55 416
a9cdd2bb 417 /* if the TCP connection is closed, then close the HTTP connection */
fc2f7f29 418 if ((pstate->flags & APP_LAYER_PARSER_EOF) &&
0a85fd67
GS
419 ! (hstate->flags & HTP_FLAG_STATE_CLOSED) &&
420 ! (hstate->flags & HTP_FLAG_STATE_DATA))
fc2f7f29
GS
421 {
422 htp_connp_close(hstate->connp, 0);
423 hstate->flags |= HTP_FLAG_STATE_CLOSED;
ba7e8012 424 SCLogDebug("stream eof encountered, closing htp handle");
fc2f7f29
GS
425 }
426
48248687 427 SCLogDebug("hstate->connp %p", hstate->connp);
0a85fd67 428 SCReturnInt(ret);
a9cdd2bb
BR
429
430error:
431 SCReturnInt(-1);
07f7ba55
GS
432}
433
434/**
435 * \brief Function to handle the reassembled data from server and feed it to
436 * the HTP library to process it.
437 *
92d74fd4 438 * \param flow Pointer to the flow the data belong to
07f7ba55
GS
439 * \param htp_state Pointer the state in which the parsed value to be stored
440 * \param pstate Application layer parser state for this session
441 * \param input Pointer the received HTTP server data
442 * \param input_len Length in bytes of the received data
443 * \param output Pointer to the output (not used in this function)
444 *
2d6cf71d 445 * \retval On success returns 1 or on failure returns -1
07f7ba55 446 */
fc2f7f29
GS
447static int HTPHandleResponseData(Flow *f, void *htp_state,
448 AppLayerParserState *pstate,
07f7ba55 449 uint8_t *input, uint32_t input_len,
18fe3818 450 AppLayerParserResult *output)
07f7ba55 451{
1b39e602 452 SCEnter();
0a85fd67
GS
453 int r = -1;
454 int ret = 1;
455
07f7ba55 456 HtpState *hstate = (HtpState *)htp_state;
4129146a
VJ
457 if (hstate->connp == NULL) {
458 SCLogError(SC_ERR_ALPARSER, "HTP state has no connp");
459 SCReturnInt(-1);
460 }
07f7ba55 461
8e444f17
GS
462 if (hstate->connp->out_status == STREAM_STATE_ERROR) {
463 SCLogError(SC_ERR_ALPARSER, "Outbound parser is in error state, no"
464 " need to feed data to libhtp");
465 SCReturnInt(-1);
466 }
467
0165b3f0
PR
468 /* Unset the body inspection (the callback should
469 * reactivate it if necessary) */
70b32f73 470 hstate->flags &=~ HTP_FLAG_NEW_BODY_SET;
0165b3f0 471
0a85fd67 472 r = htp_connp_res_data(hstate->connp, 0, input, input_len);
bf236e45
GS
473 switch(r) {
474 case STREAM_STATE_ERROR:
148883ce 475 if (hstate->connp->last_error != NULL) {
bf236e45
GS
476 SCLogError(SC_ERR_ALPARSER, "Error in parsing HTTP server "
477 "response: [%"PRId32"] [%s] [%"PRId32"] %s",
478 hstate->connp->last_error->level,
479 hstate->connp->last_error->file,
480 hstate->connp->last_error->line,
481 hstate->connp->last_error->msg);
148883ce 482 } else {
bf236e45
GS
483 SCLogError(SC_ERR_ALPARSER, "Error in parsing HTTP server "
484 "response");
148883ce 485 }
bf236e45
GS
486 hstate->flags = HTP_FLAG_STATE_ERROR;
487 hstate->flags &= ~HTP_FLAG_STATE_DATA;
50f7d0a8 488 hstate->flags &= ~HTP_FLAG_NEW_BODY_SET;
bf236e45
GS
489 ret = -1;
490 break;
491 case STREAM_STATE_DATA:
492 hstate->flags |= HTP_FLAG_STATE_DATA;
493 break;
494 case STREAM_STATE_DATA_OTHER:
495 SCLogDebug("CONNECT not supported yet");
496 hstate->flags = HTP_FLAG_STATE_ERROR;
497 hstate->flags &= ~HTP_FLAG_STATE_DATA;
50f7d0a8 498 hstate->flags &= ~HTP_FLAG_NEW_BODY_SET;
bf236e45
GS
499 ret = -1;
500 break;
501 default:
502 hstate->flags &= ~HTP_FLAG_STATE_DATA;
50f7d0a8 503 hstate->flags &= ~HTP_FLAG_NEW_BODY_SET;
bf236e45 504 }
07f7ba55 505
fc2f7f29
GS
506 /* if we the TCP connection is closed, then close the HTTP connection */
507 if ((pstate->flags & APP_LAYER_PARSER_EOF) &&
0a85fd67
GS
508 ! (hstate->flags & HTP_FLAG_STATE_CLOSED) &&
509 ! (hstate->flags & HTP_FLAG_STATE_DATA))
fc2f7f29
GS
510 {
511 htp_connp_close(hstate->connp, 0);
512 hstate->flags |= HTP_FLAG_STATE_CLOSED;
513 }
514
48248687 515 SCLogDebug("hstate->connp %p", hstate->connp);
0a85fd67 516 SCReturnInt(ret);
07f7ba55
GS
517}
518
0165b3f0
PR
519/**
520 * \brief Append a chunk of body to the HtpBody struct
521 * \param body pointer to the HtpBody holding the list
522 * \param data pointer to the data of the chunk
523 * \param len length of the chunk pointed by data
6ebe7b7c
VJ
524 * \retval 0 ok
525 * \retval -1 error
0165b3f0 526 */
6ebe7b7c 527int HtpBodyAppendChunk(SCHtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32_t len)
0165b3f0
PR
528{
529 SCEnter();
7a8cd61f
VJ
530
531 HtpBodyChunk *bd = NULL;
532
6ebe7b7c
VJ
533 if (len == 0 || data == NULL) {
534 SCReturnInt(0);
535 }
44b6380a 536
0165b3f0
PR
537 if (body->nchunks == 0) {
538 /* New chunk */
7a8cd61f 539 bd = (HtpBodyChunk *)SCMalloc(sizeof(HtpBodyChunk));
9f4fae5b 540 if (bd == NULL)
6ebe7b7c 541 goto error;
7a8cd61f 542
0165b3f0 543 bd->len = len;
fe7948a7
PR
544 bd->data = SCMalloc(len);
545 if (bd->data == NULL) {
44b6380a 546 goto error;
fe7948a7 547 }
44b6380a 548
fe7948a7 549 memcpy(bd->data, data, len);
5c6a65dc 550 htud->content_len_so_far = len;
0165b3f0
PR
551 body->first = body->last = bd;
552 body->nchunks++;
553 bd->next = NULL;
554 bd->id = body->nchunks;
555 } else {
6ebe7b7c
VJ
556 bd = (HtpBodyChunk *)SCMalloc(sizeof(HtpBodyChunk));
557 if (bd == NULL)
558 goto error;
44b6380a 559
6ebe7b7c
VJ
560 bd->len = len;
561 bd->data = SCMalloc(len);
562 if (bd->data == NULL) {
563 goto error;
0165b3f0 564 }
6ebe7b7c
VJ
565
566 memcpy(bd->data, data, len);
567 htud->content_len_so_far += len;
568 body->last->next = bd;
569 body->last = bd;
570 body->nchunks++;
571 bd->next = NULL;
572 bd->id = body->nchunks;
0165b3f0 573 }
44b6380a 574 SCLogDebug("Body %p; Chunk id: %"PRIu32", data %p, len %"PRIu32"", body,
0165b3f0 575 bd->id, bd->data, (uint32_t)bd->len);
44b6380a 576
6ebe7b7c 577 SCReturnInt(0);
44b6380a
VJ
578
579error:
580 if (bd != NULL) {
581 if (bd->data != NULL) {
582 SCFree(bd->data);
583 }
c4832814 584 SCFree(bd);
44b6380a 585 }
6ebe7b7c 586 SCReturnInt(-1);
0165b3f0
PR
587}
588
4e44073c
AS
589/**
590 * \brief get the highest loggable transaction id
591 */
592int HtpTransactionGetLoggableId(Flow *f)
593{
594 SCEnter();
595
596 /* Get the parser state (if any) */
597 if (f->aldata == NULL) {
598 SCLogDebug("no aldata");
599 goto error;
600 }
601
602 AppLayerParserStateStore *parser_state_store =
603 (AppLayerParserStateStore *)f->aldata[app_layer_sid];
604
605 if (parser_state_store == NULL) {
606 SCLogDebug("no state store");
607 goto error;
608 }
609
610 int id = 0;
611
612 HtpState *http_state = f->aldata[AlpGetStateIdx(ALPROTO_HTTP)];
613 if (http_state == NULL) {
614 SCLogDebug("no http state");
615 goto error;
616 }
617
618 if (parser_state_store->id_flags & APP_LAYER_TRANSACTION_EOF) {
619 SCLogDebug("eof, return current transaction as well");
620 id = (int)(list_size(http_state->connp->conn->transactions));
621 } else {
622 id = (int)(parser_state_store->avail_id - 1);
623 }
624
625 SCReturnInt(id);
626
627error:
628 SCReturnInt(-1);
629}
630
0165b3f0
PR
631/**
632 * \brief Print the information and chunks of a Body
633 * \param body pointer to the HtpBody holding the list
634 * \retval none
635 */
636void HtpBodyPrint(HtpBody *body)
637{
638 if (SCLogDebugEnabled()) {
639 SCEnter();
640
641 if (body->nchunks == 0)
642 return;
643
7a8cd61f 644 HtpBodyChunk *cur = NULL;
0165b3f0
PR
645 SCLogDebug("--- Start body chunks at %p ---", body);
646 for (cur = body->first; cur != NULL; cur = cur->next) {
647 SCLogDebug("Body %p; Chunk id: %"PRIu32", data %p, len %"PRIu32"\n",
648 body, cur->id, cur->data, (uint32_t)cur->len);
649 PrintRawDataFp(stdout, (uint8_t*)cur->data, cur->len);
650 }
651 SCLogDebug("--- End body chunks at %p ---", body);
652 }
653}
654
655/**
a9cdd2bb 656 * \brief Free the information held in the request body
0165b3f0
PR
657 * \param body pointer to the HtpBody holding the list
658 * \retval none
659 */
660void HtpBodyFree(HtpBody *body)
661{
662 SCEnter();
7a8cd61f 663
0165b3f0
PR
664 if (body->nchunks == 0)
665 return;
666
667 SCLogDebug("Removing chunks of Body %p; Last Chunk id: %"PRIu32", data %p,"
668 " len %"PRIu32"\n", body, body->last->id, body->last->data,
669 (uint32_t)body->last->len);
670 body->nchunks = 0;
671
7a8cd61f
VJ
672 HtpBodyChunk *cur = NULL;
673 HtpBodyChunk *prev = NULL;
674
0165b3f0
PR
675 prev = body->first;
676 while (prev != NULL) {
677 cur = prev->next;
a0fa924c
GS
678 if (prev->data != NULL)
679 SCFree(prev->data);
25a3a5c6 680 SCFree(prev);
0165b3f0
PR
681 prev = cur;
682 }
683 body->first = body->last = NULL;
0165b3f0
PR
684 body->operation = HTP_BODY_NONE;
685}
686
a3e2b355
VJ
687#ifdef HAVE_HTP_URI_NORMALIZE_HOOK
688/**
689 * \brief Normalize the query part of the URI as if it's part of the URI.
690 *
691 * \param c HTP connection pointer
692 *
693 * \retval HOOK_OK we won't fail
694 *
695 * This functionality requires the uri normalize hook introduced in libhtp
696 * version 0.2.5.
697 */
15ce8503
VJ
698static int HTPCallbackRequestUriNormalize(htp_connp_t *c)
699{
700 SCEnter();
701
702 if (c == NULL || c->in_tx == NULL || c->in_tx->parsed_uri == NULL ||
703 c->in_tx->parsed_uri->query == NULL)
704 {
705 SCReturnInt(HOOK_OK);
706 }
707
708 /* uri normalize the query string as well */
709 htp_decode_path_inplace(c->cfg, c->in_tx,
710 c->in_tx->parsed_uri->query);
711
712 SCReturnInt(HOOK_OK);
713}
a3e2b355 714#endif
15ce8503 715
0165b3f0 716/**
a9cdd2bb 717 * \brief Function callback to append chunks for Requests
0165b3f0
PR
718 * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
719 * \retval int HOOK_OK if all goes well
720 */
721int HTPCallbackRequestBodyData(htp_tx_data_t *d)
722{
723 SCEnter();
724 HtpState *hstate = (HtpState *)d->tx->connp->user_data;
725 SCLogDebug("New response body data available at %p -> %p -> %p, bodylen "
726 "%"PRIu32"", hstate, d, d->data, (uint32_t)d->len);
727
728 //PrintRawDataFp(stdout, d->data, d->len);
06a65cb4
PR
729 SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(d->tx);
730 if (htud == NULL) {
731 htud = SCMalloc(sizeof(SCHtpTxUserData));
732 if (htud == NULL) {
06a65cb4
PR
733 SCReturnInt(HOOK_OK);
734 }
735 memset(htud, 0, sizeof(SCHtpTxUserData));
736 htud->body.operation = HTP_BODY_NONE;
0165b3f0 737
5c6a65dc
AS
738 htp_header_t *cl = table_getc(d->tx->request_headers, "content-length");
739 if (cl != NULL)
740 htud->content_len = htp_parse_content_length(cl->value);
741
06a65cb4
PR
742 /* Set the user data for handling body chunks on this transaction */
743 htp_tx_set_user_data(d->tx, htud);
0165b3f0 744 }
0165b3f0 745
06a65cb4 746 htud->body.operation = HTP_BODY_REQUEST;
0165b3f0 747
6ebe7b7c
VJ
748 SCLogDebug("htud->content_len_so_far %u", htud->content_len_so_far);
749 SCLogDebug("hstate->request_body_limit %u", hstate->request_body_limit);
750
751 /* within limits, add the body chunk to the state. */
dbe291bc 752 if (hstate->request_body_limit == 0 || htud->content_len_so_far < hstate->request_body_limit)
6ebe7b7c
VJ
753 {
754 uint32_t len = (uint32_t)d->len;
755
dbe291bc
VJ
756 if (hstate->request_body_limit > 0 &&
757 (htud->content_len_so_far + len) > hstate->request_body_limit)
758 {
6ebe7b7c
VJ
759 len = hstate->request_body_limit - htud->content_len_so_far;
760 BUG_ON(len > (uint32_t)d->len);
761 }
0165b3f0 762
6ebe7b7c
VJ
763 SCLogDebug("len %u", len);
764
765 int r = HtpBodyAppendChunk(htud, &htud->body, (uint8_t*)d->data, len);
766 if (r < 0) {
767 htud->flags |= HTP_BODY_COMPLETE;
dbe291bc
VJ
768 } else if (hstate->request_body_limit > 0 &&
769 htud->content_len_so_far >= hstate->request_body_limit)
770 {
6ebe7b7c
VJ
771 htud->flags |= HTP_BODY_COMPLETE;
772 } else if (htud->content_len_so_far == htud->content_len) {
773 htud->flags |= HTP_BODY_COMPLETE;
774 }
775
6ebe7b7c
VJ
776 /* set the new chunk flag */
777 hstate->flags |= HTP_FLAG_NEW_BODY_SET;
778
779 //if (SCLogDebugEnabled()) {
780 // HtpBodyPrint(&htud->body);
781 //}
782 }
0165b3f0
PR
783
784 SCReturnInt(HOOK_OK);
785}
786
fc2f7f29
GS
787/**
788 * \brief Print the stats of the HTTP requests
789 */
790void HTPAtExitPrintStats(void)
791{
792#ifdef DEBUG
a9cdd2bb 793 SCEnter();
fc2f7f29
GS
794 SCMutexLock(&htp_state_mem_lock);
795 SCLogDebug("http_state_memcnt %"PRIu64", http_state_memuse %"PRIu64"",
796 htp_state_memcnt, htp_state_memuse);
797 SCMutexUnlock(&htp_state_mem_lock);
a9cdd2bb 798 SCReturn;
fc2f7f29
GS
799#endif
800}
801
802/** \brief Clears the HTTP server configuration memory used by HTP library */
803void HTPFreeConfig(void)
804{
a9cdd2bb
BR
805 SCEnter();
806
807 HTPCfgRec *nextrec = cfglist.next;
808 SCRadixReleaseRadixTree(cfgtree);
a0fa924c 809 htp_config_destroy(cfglist.cfg);
a9cdd2bb
BR
810 while (nextrec != NULL) {
811 HTPCfgRec *htprec = nextrec;
47a47e8a 812 nextrec = nextrec->next;
a9cdd2bb 813
a0fa924c 814 htp_config_destroy(htprec->cfg);
a9cdd2bb 815 SCFree(htprec);
a9cdd2bb
BR
816 }
817 SCReturn;
fc2f7f29
GS
818}
819
356a8bf3
GS
820/**
821 * \brief callback for request to store the recent incoming request
822 in to the recent_in_tx for the given htp state
823 * \param connp pointer to the current connection parser which has the htp
824 * state in it as user data
825 */
826static int HTPCallbackRequest(htp_connp_t *connp) {
827 SCEnter();
187949b9 828
356a8bf3 829 HtpState *hstate = (HtpState *)connp->user_data;
187949b9 830 if (hstate == NULL) {
50f7d0a8 831 SCReturnInt(HOOK_ERROR);
187949b9 832 }
70b32f73 833
41d71a6d
AS
834 SCLogDebug("transaction_cnt %"PRIu16", list_size %"PRIuMAX,
835 hstate->transaction_cnt,
836 (uintmax_t)list_size(hstate->connp->conn->transactions));
70b32f73
VJ
837
838 SCLogDebug("HTTP request completed");
839
50f7d0a8 840 SCReturnInt(HOOK_OK);
356a8bf3
GS
841}
842
843/**
844 * \brief callback for response to remove the recent received requests
845 from the recent_in_tx for the given htp state
846 * \param connp pointer to the current connection parser which has the htp
847 * state in it as user data
848 */
849static int HTPCallbackResponse(htp_connp_t *connp) {
850 SCEnter();
187949b9 851
356a8bf3 852 HtpState *hstate = (HtpState *)connp->user_data;
187949b9 853 if (hstate == NULL) {
50f7d0a8 854 SCReturnInt(HOOK_ERROR);
187949b9 855 }
356a8bf3 856
b406af45
AS
857 /* we have one whole transaction now */
858 hstate->transaction_cnt++;
859
06a65cb4
PR
860 /* Unset the body inspection (if any) */
861 hstate->flags &=~ HTP_FLAG_NEW_BODY_SET;
0165b3f0 862
70b32f73
VJ
863 /* remove obsolete transactions */
864 size_t idx;
865 for (idx = 0; idx < hstate->transaction_done; idx++) {
ffd85ac4 866 htp_tx_t *tx = list_get(hstate->connp->conn->transactions, idx);
70b32f73
VJ
867 if (tx == NULL)
868 continue;
869
06a65cb4
PR
870 /* This will remove obsolete body chunks */
871 SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(tx);
872 if (htud != NULL) {
873 HtpBodyFree(&htud->body);
874 htp_tx_set_user_data(tx, NULL);
875 SCFree(htud);
876 }
877
70b32f73 878 htp_tx_destroy(tx);
bf236e45 879 }
50f7d0a8
GS
880
881 SCReturnInt(HOOK_OK);
356a8bf3
GS
882}
883
a9cdd2bb
BR
884static void HTPConfigure(void)
885{
886 SCEnter();
887 ConfNode *default_config;
888 ConfNode *server_config;
889
a9cdd2bb
BR
890 cfglist.next = NULL;
891
892 cfgtree = SCRadixCreateRadixTree(NULL, NULL);
893 if (NULL == cfgtree) {
894 SCLogError(SC_ERR_MEM_ALLOC, "Error initializing HTP config tree");
895
896 if (SCLogDebugEnabled()) {
897 abort();
898 }
899 else {
900 exit(EXIT_FAILURE);
901 }
902 }
903
904 /* Default Config */
905 cfglist.cfg = htp_config_create();
906 if (NULL == cfglist.cfg) {
907 SCLogError(SC_ERR_MEM_ALLOC, "Failed to create HTP default config");
908
909 if (SCLogDebugEnabled()) {
910 abort();
911 }
912 else {
913 exit(EXIT_FAILURE);
914 }
915 }
916
917 SCLogDebug("LIBHTP default config: %p", cfglist.cfg);
918
6ebe7b7c 919 cfglist.request_body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT;
a9cdd2bb
BR
920 htp_config_register_request(cfglist.cfg, HTPCallbackRequest);
921 htp_config_register_response(cfglist.cfg, HTPCallbackResponse);
a3e2b355
VJ
922#ifdef HAVE_HTP_URI_NORMALIZE_HOOK
923 htp_config_register_request_uri_normalize(cfglist.cfg,
924 HTPCallbackRequestUriNormalize);
925#endif
a9cdd2bb
BR
926 htp_config_set_generate_request_uri_normalized(cfglist.cfg, 1);
927
928 default_config = ConfGetNode("libhtp.default-config");
929 if (NULL != default_config) {
930 ConfNode *p = NULL;
931
932 /* Default Parameters */
933 TAILQ_FOREACH(p, &default_config->head, next) {
c8863063 934 //ConfNode *pval;
a9cdd2bb
BR
935
936 if (strcasecmp("personality", p->name) == 0) {
937 /* Personalities */
c8863063 938 int personality = HTPLookupPersonality(p->val);
a9cdd2bb 939
c8863063
VJ
940 SCLogDebug("LIBHTP default: %s=%s",
941 p->name, p->val);
a9cdd2bb
BR
942
943
c8863063
VJ
944 if (personality >= 0) {
945 SCLogDebug("LIBHTP default: %s=%s (%d)",
946 p->name, p->val,
947 personality);
948 if (htp_config_set_server_personality(cfglist.cfg,
a9cdd2bb 949 personality) == HTP_ERROR)
c8863063
VJ
950 {
951 SCLogWarning(SC_ERR_INVALID_VALUE,
952 "LIBHTP Failed adding personality "
953 "\"%s\", ignoring", p->val);
954 } else {
955 SCLogDebug("LIBHTP personality set to %s",
956 HTPLookupPersonalityString(personality));
a9cdd2bb 957 }
bde55578
VJ
958
959 /* The IDS personality by default converts the path (and due to
960 * our query string callback also the query string) to lowercase.
961 * Signatures do not expect this, so override it. */
962 htp_config_set_path_case_insensitive(cfglist.cfg, 0);
c8863063
VJ
963 }
964 else {
965 SCLogWarning(SC_ERR_UNKNOWN_VALUE,
966 "LIBHTP Unknown personality "
967 "\"%s\", ignoring", p->val);
968 continue;
6ebe7b7c 969 }
edeec290
VJ
970 } else if (strcasecmp("request-body-limit", p->name) == 0 ||
971 strcasecmp("request_body_limit", p->name) == 0) {
6ebe7b7c 972
dbe291bc
VJ
973 /* limit */
974 int limit = atoi(p->val);
6ebe7b7c 975
dbe291bc
VJ
976 if (limit >= 0) {
977 SCLogDebug("LIBHTP default: %s=%s (%d)",
978 p->name, p->val, limit);
6ebe7b7c 979
dbe291bc
VJ
980 cfglist.request_body_limit = (uint32_t)limit;
981 }
982 else {
983 SCLogWarning(SC_ERR_UNKNOWN_VALUE,
984 "LIBHTP malformed request_body_limit "
985 "\"%s\", using default %u", p->val,
986 HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT);
987 cfglist.request_body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT;
988 continue;
a9cdd2bb 989 }
dbe291bc 990
a9cdd2bb
BR
991 } else {
992 SCLogWarning(SC_ERR_UNKNOWN_VALUE,
6ebe7b7c
VJ
993 "LIBHTP Ignoring unknown default config: %s",
994 p->name);
a9cdd2bb
BR
995 }
996 }
997 }
998
999 /* Read server config and create a parser for each IP in radix tree */
1000 server_config = ConfGetNode("libhtp.server-config");
1001 SCLogDebug("LIBHTP Configuring %p", server_config);
1002 if (server_config != NULL) {
1003 ConfNode *si;
1004 ConfNode *s;
1005 HTPCfgRec *htprec;
1006 HTPCfgRec *nextrec;
1007 htp_cfg_t *htp;
1008
1009 /* Server Nodes */
1010 TAILQ_FOREACH(si, &server_config->head, next) {
1011 ConfNode *p = NULL;
1012
1013 /* Need the named node, not the index */
1014 s = TAILQ_FIRST(&si->head);
1015 if (NULL == s) {
1016 SCLogDebug("LIBHTP s NULL");
1017 continue;
1018 }
1019
1020 SCLogDebug("LIBHTP server %s", s->name);
1021
1022 nextrec = cfglist.next;
1023 htprec = cfglist.next = SCMalloc(sizeof(HTPCfgRec));
1024 if (NULL == htprec) {
1025 SCLogError(SC_ERR_MEM_ALLOC, "Failed to create HTP server config rec");
1026 if (SCLogDebugEnabled()) {
1027 abort();
1028 }
1029 else {
1030 exit(EXIT_FAILURE);
1031 }
1032 }
1033
1034 cfglist.next->next = nextrec;
1035 htp = cfglist.next->cfg = htp_config_create();
1036 if (NULL == htp) {
1037 SCLogError(SC_ERR_MEM_ALLOC, "Failed to create HTP server config");
1038 if (SCLogDebugEnabled()) {
1039 abort();
1040 }
1041 else {
1042 exit(EXIT_FAILURE);
1043 }
1044 }
1045
6ebe7b7c 1046 htprec->request_body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT;
a9cdd2bb
BR
1047 htp_config_register_request(htp, HTPCallbackRequest);
1048 htp_config_register_response(htp, HTPCallbackResponse);
1049 htp_config_set_generate_request_uri_normalized(htp, 1);
1050
1051 /* Server Parameters */
1052 TAILQ_FOREACH(p, &s->head, next) {
1053 ConfNode *pval;
1054
1055 if (strcasecmp("address", p->name) == 0) {
1056
1057 /* Addresses */
1058 TAILQ_FOREACH(pval, &p->head, next) {
1059 SCLogDebug("LIBHTP server %s: %s=%s",
1060 s->name, p->name, pval->val);
1061
1062 /* IPV6 or IPV4? */
1063 if (strchr(pval->val, ':') != NULL) {
1064 SCLogDebug("LIBHTP adding ipv6 server %s at %s: %p",
1065 s->name, pval->val, htp);
1066 if (SCRadixAddKeyIPV6String(pval->val,
1067 cfgtree, htprec) == NULL)
1068 {
1069 SCLogWarning(SC_ERR_INVALID_VALUE,
1070 "LIBHTP failed to add "
1071 "ipv6 server %s, ignoring",
1072 pval->val);
1073 }
1074 } else {
1075 SCLogDebug("LIBHTP adding ipv4 server %s at %s: %p",
1076 s->name, pval->val, htp);
1077 if (SCRadixAddKeyIPV4String(pval->val,
1078 cfgtree, htprec) == NULL)
1079 {
1080 SCLogWarning(SC_ERR_INVALID_VALUE,
1081 "LIBHTP failed to add "
1082 "ipv4 server %s, ignoring",
1083 pval->val);
1084 }
1085 }
1086 }
1087 } else if (strcasecmp("personality", p->name) == 0) {
c8863063
VJ
1088 /* Personalitie */
1089 int personality = HTPLookupPersonality(p->val);
a9cdd2bb 1090
c8863063
VJ
1091 SCLogDebug("LIBHTP server %s: %s=%s",
1092 s->name, p->name, p->val);
a9cdd2bb
BR
1093
1094
c8863063
VJ
1095 if (personality >= 0) {
1096 SCLogDebug("LIBHTP %s: %s=%s (%d)",
1097 s->name, p->name, p->val,
1098 personality);
1099 if (htp_config_set_server_personality(htp,
a9cdd2bb 1100 personality) == HTP_ERROR)
c8863063
VJ
1101 {
1102 SCLogWarning(SC_ERR_INVALID_VALUE,
1103 "LIBHTP Failed adding personality "
1104 "\"%s\", ignoring", p->val);
1105 } else {
1106 SCLogDebug("LIBHTP personality set to %s",
1107 HTPLookupPersonalityString(personality));
a9cdd2bb 1108 }
bde55578
VJ
1109
1110 /* The IDS personality by default converts the path (and due to
1111 * our query string callback also the query string) to lowercase.
1112 * Signatures do not expect this, so override it. */
1113 htp_config_set_path_case_insensitive(htp, 0);
6ebe7b7c 1114 }
c8863063
VJ
1115 else {
1116 SCLogWarning(SC_ERR_UNKNOWN_VALUE,
1117 "LIBHTP Unknown personality "
1118 "\"%s\", ignoring", p->val);
1119 continue;
1120 }
1121
a3303fcf
VJ
1122 /* VJ the non underscore version was a typo but keeping it for
1123 * compatibility with existing installs */
1124 } else if (strcasecmp("request-body-limit", p->name) == 0 ||
1125 strcasecmp("request_body_limit", p->name) == 0) {
6ebe7b7c 1126 /* limit */
dbe291bc
VJ
1127 SCLogDebug("LIBHTP default: %s=%s",
1128 p->name, p->val);
6ebe7b7c 1129
dbe291bc 1130 int limit = atoi(p->val);
6ebe7b7c 1131
dbe291bc
VJ
1132 if (limit >= 0) {
1133 SCLogDebug("LIBHTP default: %s=%s (%d)",
1134 p->name, p->val, limit);
6ebe7b7c 1135
dbe291bc
VJ
1136 htprec->request_body_limit = (uint32_t)limit;
1137 }
1138 else {
1139 SCLogWarning(SC_ERR_UNKNOWN_VALUE,
1140 "LIBHTP malformed request_body_limit "
1141 "\"%s\", using default %u", p->val,
1142 HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT);
1143 htprec->request_body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT;
1144 continue;
a9cdd2bb
BR
1145 }
1146 } else {
1147 SCLogWarning(SC_ERR_UNKNOWN_VALUE,
1148 "LIBHTP Ignoring unknown server config: %s",
1149 p->name);
1150 }
1151 }
1152 }
1153 }
1154
1155 SCReturn;
1156}
1157
6fca55e0
VJ
1158void AppLayerHtpPrintStats(void) {
1159#ifdef DEBUG
1160 SCMutexLock(&htp_state_mem_lock);
1161 SCLogInfo("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt);
1162 SCMutexUnlock(&htp_state_mem_lock);
1163#endif
1164}
1165
07f7ba55
GS
1166/**
1167 * \brief Register the HTTP protocol and state handling functions to APP layer
1168 * of the engine.
1169 */
1170void RegisterHTPParsers(void)
1171{
a9cdd2bb 1172 SCEnter();
000ce98c
AS
1173
1174 /** HTTP */
1175 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "GET|20|", 4, 0, STREAM_TOSERVER);
1176 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "GET|09|", 4, 0, STREAM_TOSERVER);
1177 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "PUT|20|", 4, 0, STREAM_TOSERVER);
1178 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "PUT|09|", 4, 0, STREAM_TOSERVER);
1179 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "POST|20|", 5, 0, STREAM_TOSERVER);
1180 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "POST|09|", 5, 0, STREAM_TOSERVER);
1181 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "HEAD|20|", 5, 0, STREAM_TOSERVER);
1182 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "HEAD|09|", 5, 0, STREAM_TOSERVER);
1183 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "TRACE|20|", 6, 0, STREAM_TOSERVER);
1184 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "TRACE|09|", 6, 0, STREAM_TOSERVER);
1185 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "OPTIONS|20|", 8, 0, STREAM_TOSERVER);
1186 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "OPTIONS|09|", 8, 0, STREAM_TOSERVER);
1187 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "CONNECT|20|", 8, 0, STREAM_TOSERVER);
1188 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "CONNECT|09|", 8, 0, STREAM_TOSERVER);
149ee6b6 1189 //AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "HTTP/", 5, 0, STREAM_TOCLIENT);
000ce98c 1190
07f7ba55 1191 AppLayerRegisterStateFuncs(ALPROTO_HTTP, HTPStateAlloc, HTPStateFree);
170efc8d 1192 AppLayerRegisterTransactionIdFuncs(ALPROTO_HTTP, HTPStateUpdateTransactionId, HTPStateTransactionFree);
07f7ba55
GS
1193
1194 AppLayerRegisterProto("http", ALPROTO_HTTP, STREAM_TOSERVER,
1195 HTPHandleRequestData);
1196 AppLayerRegisterProto("http", ALPROTO_HTTP, STREAM_TOCLIENT,
1197 HTPHandleResponseData);
1198
a9cdd2bb
BR
1199 HTPConfigure();
1200 SCReturn;
07f7ba55
GS
1201}
1202
0165b3f0 1203/**
97d49d8f
AS
1204 * \brief This function is called at the end of SigLoadSignatures. This function
1205 * enables the htp layer to register a callback for the http request body.
1206 * need_htp_request_body is a flag that informs the htp app layer that
1207 * a module in the engine needs the http request body.
0165b3f0
PR
1208 */
1209void AppLayerHtpRegisterExtraCallbacks(void) {
a9cdd2bb 1210 SCEnter();
0165b3f0 1211 SCLogDebug("Registering extra htp callbacks");
97d49d8f 1212 if (need_htp_request_body == 1) {
0165b3f0 1213 SCLogDebug("Registering callback htp_config_register_request_body_data on htp");
a9cdd2bb
BR
1214 htp_config_register_request_body_data(cfglist.cfg,
1215 HTPCallbackRequestBodyData);
0165b3f0
PR
1216 } else {
1217 SCLogDebug("No htp extra callback needed");
1218 }
a9cdd2bb 1219 SCReturn;
0165b3f0
PR
1220}
1221
c22d4269 1222
c352bff6 1223#ifdef UNITTESTS
99fca038
VJ
1224static HTPCfgRec cfglist_backup;
1225
1226static void HtpConfigCreateBackup(void)
1227{
1228 cfglist_backup.cfg = cfglist.cfg;
1229 cfglist_backup.next = cfglist.next;
1230 cfglist_backup.request_body_limit = cfglist.request_body_limit;
1231
1232 return;
1233}
1234
1235static void HtpConfigRestoreBackup(void)
1236{
1237 cfglist.cfg = cfglist_backup.cfg;
1238 cfglist.next = cfglist_backup.next;
1239 cfglist.request_body_limit = cfglist_backup.request_body_limit;
1240
1241 return;
1242}
a9cdd2bb 1243
07f7ba55
GS
1244/** \test Test case where chunks are sent in smaller chunks and check the
1245 * response of the parser from HTP library. */
1246int HTPParserTest01(void) {
1247 int result = 1;
1248 Flow f;
fc2f7f29 1249 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
07f7ba55
GS
1250 " Data is c0oL!";
1251 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1252 TcpSession ssn;
25a3a5c6
PR
1253
1254 HtpState *htp_state = NULL;
07f7ba55
GS
1255 int r = 0;
1256 memset(&f, 0, sizeof(f));
1257 memset(&ssn, 0, sizeof(ssn));
07f7ba55 1258 f.protoctx = (void *)&ssn;
78e15ea7
VJ
1259 f.src.family = AF_INET;
1260 f.dst.family = AF_INET;
07f7ba55 1261
6a53ab9c 1262 StreamTcpInitConfig(TRUE);
8cc525c9 1263 FlowL7DataPtrInit(&f);
6a53ab9c 1264
07f7ba55
GS
1265 uint32_t u;
1266 for (u = 0; u < httplen1; u++) {
1267 uint8_t flags = 0;
1268
1269 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
1270 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
1271 else flags = STREAM_TOSERVER;
1272
c352bff6 1273 r = AppLayerParse(&f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
07f7ba55
GS
1274 if (r != 0) {
1275 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
1276 " 0: ", u, r);
1277 result = 0;
1278 goto end;
1279 }
1280 }
1281
8cc525c9 1282 htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
07f7ba55
GS
1283 if (htp_state == NULL) {
1284 printf("no http state: ");
1285 result = 0;
1286 goto end;
1287 }
1288
1289 htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0);
1290
1291 bstr *key = NULL;
1292 htp_header_t *h = NULL;
1293 table_iterator_reset(tx->request_headers);
1294 key = table_iterator_next(tx->request_headers, (void **) & h);
1295
2d6cf71d
GS
1296 if (htp_state->connp == NULL || strcmp(bstr_tocstr(h->value), "Victor/1.0")
1297 || tx->request_method_number != M_POST ||
fc2f7f29 1298 tx->request_protocol_number != HTTP_1_0)
07f7ba55 1299 {
2d6cf71d 1300 printf("expected header value: Victor/1.0 and got %s: and expected"
fc2f7f29 1301 " method: POST and got %s, expected protocol number HTTP/1.0"
2d6cf71d
GS
1302 " and got: %s \n", bstr_tocstr(h->value),
1303 bstr_tocstr(tx->request_method),
1304 bstr_tocstr(tx->request_protocol));
07f7ba55
GS
1305 result = 0;
1306 goto end;
1307 }
1308
1309end:
8cc525c9 1310 FlowL7DataPtrFree(&f);
6a53ab9c 1311 StreamTcpFreeConfig(TRUE);
25a3a5c6
PR
1312 if (htp_state != NULL)
1313 HTPStateFree(htp_state);
07f7ba55
GS
1314 return result;
1315}
1316
2d6cf71d
GS
1317/** \test See how it deals with an incomplete request. */
1318int HTPParserTest02(void) {
1319 int result = 1;
1320 Flow f;
1321 uint8_t httpbuf1[] = "POST";
1322 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1323 TcpSession ssn;
25a3a5c6 1324 HtpState *http_state = NULL;
2d6cf71d
GS
1325
1326 memset(&f, 0, sizeof(f));
1327 memset(&ssn, 0, sizeof(ssn));
2d6cf71d 1328 f.protoctx = (void *)&ssn;
78e15ea7
VJ
1329 f.src.family = AF_INET;
1330 f.dst.family = AF_INET;
2d6cf71d 1331
6a53ab9c 1332 StreamTcpInitConfig(TRUE);
8cc525c9 1333 FlowL7DataPtrInit(&f);
6a53ab9c 1334
2d6cf71d 1335 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|
c352bff6 1336 STREAM_EOF, httpbuf1, httplen1);
2d6cf71d
GS
1337 if (r != 0) {
1338 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1339 result = 0;
1340 goto end;
1341 }
1342
8cc525c9 1343 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
2d6cf71d
GS
1344 if (http_state == NULL) {
1345 printf("no http state: ");
1346 result = 0;
1347 goto end;
1348 }
1349
1350 htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0);
1351
1352 bstr *key = NULL;
1353 htp_header_t *h = NULL;
1354 table_iterator_reset(tx->request_headers);
1355 key = table_iterator_next(tx->request_headers, (void **) & h);
1356
1357 if ((tx->request_method) != NULL || h != NULL)
1358 {
1359 printf("expected method NULL, got %s \n", bstr_tocstr(tx->request_method));
1360 result = 0;
1361 goto end;
1362 }
1363
1364end:
8cc525c9 1365 FlowL7DataPtrFree(&f);
6a53ab9c 1366 StreamTcpFreeConfig(TRUE);
25a3a5c6
PR
1367 if (http_state != NULL)
1368 HTPStateFree(http_state);
2d6cf71d
GS
1369 return result;
1370}
1371
1372/** \test Test case where method is invalid and data is sent in smaller chunks
1373 * and check the response of the parser from HTP library. */
1374int HTPParserTest03(void) {
1375 int result = 1;
1376 Flow f;
1377 uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n";
1378 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1379 TcpSession ssn;
25a3a5c6
PR
1380
1381 HtpState *htp_state = NULL;
2d6cf71d
GS
1382 int r = 0;
1383 memset(&f, 0, sizeof(f));
1384 memset(&ssn, 0, sizeof(ssn));
2d6cf71d 1385 f.protoctx = (void *)&ssn;
78e15ea7
VJ
1386 f.src.family = AF_INET;
1387 f.dst.family = AF_INET;
2d6cf71d 1388
6a53ab9c 1389 StreamTcpInitConfig(TRUE);
8cc525c9 1390 FlowL7DataPtrInit(&f);
6a53ab9c 1391
2d6cf71d
GS
1392 uint32_t u;
1393 for (u = 0; u < httplen1; u++) {
1394 uint8_t flags = 0;
1395
1396 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
1397 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
1398 else flags = STREAM_TOSERVER;
1399
c352bff6 1400 r = AppLayerParse(&f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
2d6cf71d
GS
1401 if (r != 0) {
1402 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
1403 " 0: ", u, r);
1404 result = 0;
1405 goto end;
1406 }
1407 }
8cc525c9 1408 htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
2d6cf71d
GS
1409 if (htp_state == NULL) {
1410 printf("no http state: ");
1411 result = 0;
1412 goto end;
1413 }
1414
1415 htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0);
1416
1417 bstr *key = NULL;
1418 htp_header_t *h = NULL;
1419 table_iterator_reset(tx->request_headers);
1420 key = table_iterator_next(tx->request_headers, (void **) & h);
1421
1422 if (htp_state->connp == NULL || tx->request_method_number != M_UNKNOWN ||
1423 h != NULL || tx->request_protocol_number != HTTP_1_0)
1424 {
1425 printf("expected method M_UNKNOWN and got %s: , expected protocol "
1426 "HTTP/1.0 and got %s \n", bstr_tocstr(tx->request_method),
1427 bstr_tocstr(tx->request_protocol));
1428 result = 0;
1429 goto end;
1430 }
1431
1432end:
8cc525c9 1433 FlowL7DataPtrFree(&f);
6a53ab9c 1434 StreamTcpFreeConfig(TRUE);
25a3a5c6
PR
1435 if (htp_state != NULL)
1436 HTPStateFree(htp_state);
2d6cf71d
GS
1437 return result;
1438}
1439
1440/** \test Test case where invalid data is sent and check the response of the
1441 * parser from HTP library. */
1442int HTPParserTest04(void) {
1443 int result = 1;
1444 Flow f;
25a3a5c6 1445 HtpState *htp_state = NULL;
2d6cf71d
GS
1446 uint8_t httpbuf1[] = "World!\r\n";
1447 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1448 TcpSession ssn;
1449 int r = 0;
1450 memset(&f, 0, sizeof(f));
1451 memset(&ssn, 0, sizeof(ssn));
2d6cf71d 1452 f.protoctx = (void *)&ssn;
78e15ea7
VJ
1453 f.src.family = AF_INET;
1454 f.dst.family = AF_INET;
2d6cf71d 1455
6a53ab9c 1456 StreamTcpInitConfig(TRUE);
8cc525c9 1457 FlowL7DataPtrInit(&f);
6a53ab9c 1458
2d6cf71d 1459 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|
c352bff6 1460 STREAM_EOF, httpbuf1, httplen1);
2d6cf71d 1461
8cc525c9 1462 htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
2d6cf71d
GS
1463 if (htp_state == NULL) {
1464 printf("no http state: ");
1465 result = 0;
1466 goto end;
1467 }
1468
1469 htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0);
1470
1471 bstr *key = NULL;
1472 htp_header_t *h = NULL;
1473 table_iterator_reset(tx->request_headers);
1474 key = table_iterator_next(tx->request_headers, (void **) & h);
1475
1476 if (htp_state->connp == NULL || tx->request_method_number != M_UNKNOWN ||
1477 h != NULL || tx->request_protocol_number != PROTOCOL_UNKNOWN)
1478 {
1479 printf("expected method M_UNKNOWN and got %s: , expected protocol "
1480 "NULL and got %s \n", bstr_tocstr(tx->request_method),
1481 bstr_tocstr(tx->request_protocol));
1482 result = 0;
1483 goto end;
1484 }
1485
1486end:
8cc525c9 1487 FlowL7DataPtrFree(&f);
6a53ab9c 1488 StreamTcpFreeConfig(TRUE);
25a3a5c6
PR
1489 if (htp_state != NULL)
1490 HTPStateFree(htp_state);
2d6cf71d
GS
1491 return result;
1492}
1493
1494/** \test Test both sides of a http stream mixed up to see if the HTP parser
1495 * properly parsed them and also keeps them separated. */
1496int HTPParserTest05(void) {
1497 int result = 1;
1498 Flow f;
25a3a5c6 1499 HtpState *http_state = NULL;
fc2f7f29 1500 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\n";
2d6cf71d
GS
1501 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1502 uint8_t httpbuf2[] = "Post D";
1503 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1504 uint8_t httpbuf3[] = "ata is c0oL!";
1505 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1506
fc2f7f29 1507 uint8_t httpbuf4[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
2d6cf71d
GS
1508 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1509 uint8_t httpbuf5[] = "post R";
1510 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
1511 uint8_t httpbuf6[] = "esults are tha bomb!";
1512 uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
1513 TcpSession ssn;
1514
1515 memset(&f, 0, sizeof(f));
1516 memset(&ssn, 0, sizeof(ssn));
2d6cf71d 1517 f.protoctx = (void *)&ssn;
78e15ea7
VJ
1518 f.src.family = AF_INET;
1519 f.dst.family = AF_INET;
2d6cf71d 1520
6a53ab9c 1521 StreamTcpInitConfig(TRUE);
8cc525c9 1522 FlowL7DataPtrInit(&f);
6a53ab9c 1523
2d6cf71d 1524 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START,
c352bff6 1525 httpbuf1, httplen1);
2d6cf71d
GS
1526 if (r != 0) {
1527 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1528 result = 0;
1529 goto end;
1530 }
1531
1532 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf4,
c352bff6 1533 httplen4);
2d6cf71d
GS
1534 if (r != 0) {
1535 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
1536 result = 0;
1537 goto end;
1538 }
1539
c352bff6 1540 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf5, httplen5);
2d6cf71d
GS
1541 if (r != 0) {
1542 printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
1543 result = 0;
1544 goto end;
1545 }
1546
c352bff6 1547 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
2d6cf71d
GS
1548 if (r != 0) {
1549 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1550 result = 0;
1551 goto end;
1552 }
1553
1554 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3,
c352bff6 1555 httplen3);
2d6cf71d
GS
1556 if (r != 0) {
1557 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1558 result = 0;
1559 goto end;
1560 }
1561
1562 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf6,
c352bff6 1563 httplen6);
2d6cf71d
GS
1564 if (r != 0) {
1565 printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
1566 result = 0;
1567 goto end;
1568 }
1569
8cc525c9 1570 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
2d6cf71d
GS
1571 if (http_state == NULL) {
1572 printf("no http state: ");
1573 result = 0;
1574 goto end;
1575 }
1576
1577 htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0);
1578
1579 bstr *key = NULL;
1580 htp_header_t *h = NULL;
1581 table_iterator_reset(tx->request_headers);
1582 key = table_iterator_next(tx->request_headers, (void **) & h);
1583
1584 if (http_state->connp == NULL || tx->request_method_number != M_POST ||
fc2f7f29 1585 h == NULL || tx->request_protocol_number != HTTP_1_0)
2d6cf71d
GS
1586 {
1587 printf("expected method M_POST and got %s: , expected protocol "
fc2f7f29 1588 "HTTP/1.0 and got %s \n", bstr_tocstr(tx->request_method),
2d6cf71d
GS
1589 bstr_tocstr(tx->request_protocol));
1590 result = 0;
1591 goto end;
1592 }
1593
f862de2e 1594 if (tx->response_status_number != 200) {
2d6cf71d 1595 printf("expected response 200 OK and got %"PRId32" %s: , expected protocol "
fc2f7f29 1596 "HTTP/1.0 and got %s \n", tx->response_status_number,
2d6cf71d
GS
1597 bstr_tocstr(tx->response_message),
1598 bstr_tocstr(tx->response_protocol));
1599 result = 0;
1600 goto end;
1601 }
1602end:
8cc525c9 1603 FlowL7DataPtrFree(&f);
6a53ab9c 1604 StreamTcpFreeConfig(TRUE);
25a3a5c6
PR
1605 if (http_state != NULL)
1606 HTPStateFree(http_state);
2d6cf71d
GS
1607 return result;
1608}
1609
fc2f7f29
GS
1610/** \test Test proper chunked encoded response body
1611 */
1612int HTPParserTest06(void) {
1613 int result = 1;
1614 Flow f;
1615 uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
1616 "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
1617 "LD-agent\r\nHost: 209.205.196.16\r\n\r\n";
1618 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1619 uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nDate: Sat, 03 Oct 2009 10:16:02 "
1620 "GMT\r\n"
1621 "Server: Apache/1.3.37 (Unix) mod_ssl/2.8.28 "
1622 "OpenSSL/0.9.7a PHP/4.4.7 mod_perl/1.29 "
1623 "FrontPage/5.0.2.2510\r\n"
1624 "X-Powered-By: PHP/4.4.7\r\nTransfer-Encoding: "
1625 "chunked\r\n"
1626 "Content-Type: text/html\r\n\r\n"
1627 "1408\r\n"
1628 "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu"
1629 "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN"
1630 "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N"
1631 "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk"
1632 "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l"
1633 "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN"
1634 "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt"
1635 "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz"
1636 "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw"
1637 "aG9uZTM9DQpsb2dpbjM9DQpwYXNzd29yZDM9DQpwaG9uZTQ9DQps"
1638 "b2dpbjQ9DQpwYXNzd29yZDQ9DQpwaG9uZTU9DQpsb2dpbjU9DQpw"
1639 "YXNzd29yZDU9DQpwaG9uZTY9DQpsb2dpbjY9DQpwYXNzd29yZDY9"
1640 "DQpjYWxsX3RpbWUxPQ0KY2FsbF90aW1lMj0NCmRheV9saW1pdD0N"
1641 "Cm1vbnRoX2xpbWl0PQ0KW2dyb3VwM10NCnBob25lMT0NCmxvZ2lu"
1642 "MT0NCnBhc3N3b3JkMT0NCnBob25lMj0NCmxvZ2luMj0NCnBhc3N3"
1643 "b3JkMj0NCnBob25lMz0NCmxvZ2luMz0NCnBhc3N3b3JkMz0NCnBo"
1644 "b25lND0NCmxvZ2luND0NCnBhc3N3b3JkND0NCnBob25lNT0NCmxv"
1645 "Z2luNT0NCnBhc3N3b3JkNT0NCnBob25lNj0NCmxvZ2luNj0NCnBh"
1646 "c3N3b3JkNj0NCmNhbGxfdGltZTE9DQpjYWxsX3RpbWUyPQ0KZGF5"
1647 "X2xpbWl0PQ0KbW9udGhfbGltaXQ9DQpbZ3JvdXA0XQ0KcGhvbmUx"
1648 "PQ0KbG9naW4xPQ0KcGFzc3dvcmQxPQ0KcGhvbmUyPQ0KbG9naW4y"
1649 "PQ0KcGFzc3dvcmQyPQ0KcGhvbmUzPQ0KbG9naW4zPQ0KcGFzc3dv"
1650 "cmQzPQ0KcGhvbmU0PQ0KbG9naW40PQ0KcGFzc3dvcmQ0PQ0KcGhv"
1651 "bmU1PQ0KbG9naW41PQ0KcGFzc3dvcmQ1PQ0KcGhvbmU2PQ0KbG9n"
1652 "aW42PQ0KcGFzc3dvcmQ2PQ0KY2FsbF90aW1lMT0NCmNhbGxfdGlt"
1653 "ZTI9DQpkYXlfbGltaXQ9DQptb250aF9saW1pdD0NCltmaWxlc10N"
1654 "Cmxpbms9aHR0cDovLzIwOS4yMDUuMTk2LjE2L2xkL2dldGJvdC5w"
1655 "aHA=0\r\n\r\n";
1656 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1657 TcpSession ssn;
25a3a5c6 1658 HtpState *http_state = NULL;
fc2f7f29
GS
1659
1660 memset(&f, 0, sizeof(f));
1661 memset(&ssn, 0, sizeof(ssn));
78e15ea7 1662
fc2f7f29 1663 f.protoctx = (void *)&ssn;
78e15ea7
VJ
1664 f.src.family = AF_INET;
1665 f.dst.family = AF_INET;
fc2f7f29 1666
6a53ab9c 1667 StreamTcpInitConfig(TRUE);
8cc525c9 1668 FlowL7DataPtrInit(&f);
6a53ab9c 1669
fc2f7f29 1670 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START,
c352bff6 1671 httpbuf1, httplen1);
fc2f7f29
GS
1672 if (r != 0) {
1673 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1674 result = 0;
1675 goto end;
1676 }
1677
1678 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2,
c352bff6 1679 httplen2);
fc2f7f29 1680 if (r != 0) {
a64eea96 1681 printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r);
fc2f7f29
GS
1682 result = 0;
1683 goto end;
1684 }
1685
8cc525c9 1686 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
fc2f7f29
GS
1687 if (http_state == NULL) {
1688 printf("no http state: ");
1689 result = 0;
1690 goto end;
1691 }
1692
1693 htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0);
1694
1695 bstr *key = NULL;
1696 htp_header_t *h = NULL;
1697 table_iterator_reset(tx->request_headers);
1698 key = table_iterator_next(tx->request_headers, (void **) & h);
1699
1700 if (http_state->connp == NULL || tx->request_method_number != M_GET ||
1701 h == NULL || tx->request_protocol_number != HTTP_1_1)
1702 {
1703 printf("expected method M_GET and got %s: , expected protocol "
1704 "HTTP/1.1 and got %s \n", bstr_tocstr(tx->request_method),
1705 bstr_tocstr(tx->request_protocol));
1706 result = 0;
1707 goto end;
1708 }
1709
1710 if (tx->response_status_number != 200 ||
1711 h == NULL || tx->request_protocol_number != HTTP_1_1)
1712 {
1713 printf("expected response 200 OK and got %"PRId32" %s: , expected proto"
1714 "col HTTP/1.1 and got %s \n", tx->response_status_number,
1715 bstr_tocstr(tx->response_message),
1716 bstr_tocstr(tx->response_protocol));
1717 result = 0;
1718 goto end;
1719 }
1720end:
8cc525c9 1721 FlowL7DataPtrFree(&f);
6a53ab9c 1722 StreamTcpFreeConfig(TRUE);
25a3a5c6
PR
1723 if (http_state != NULL)
1724 HTPStateFree(http_state);
fc2f7f29
GS
1725 return result;
1726}
a9cdd2bb 1727
15ce8503
VJ
1728/** \test
1729 */
1730int HTPParserTest07(void) {
36917c7d 1731 int result = 0;
15ce8503
VJ
1732 Flow f;
1733 uint8_t httpbuf1[] = "GET /awstats.pl?/migratemigrate%20=%20| HTTP/1.0\r\n\r\n";
1734 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1735 TcpSession ssn;
1736
1737 HtpState *htp_state = NULL;
1738 int r = 0;
1739 memset(&f, 0, sizeof(f));
1740 memset(&ssn, 0, sizeof(ssn));
1741 f.protoctx = (void *)&ssn;
1742 f.src.family = AF_INET;
1743 f.dst.family = AF_INET;
1744
1745 StreamTcpInitConfig(TRUE);
1746 FlowL7DataPtrInit(&f);
1747
1748 uint32_t u;
1749 for (u = 0; u < httplen1; u++) {
1750 uint8_t flags = 0;
1751
36917c7d
VJ
1752 if (u == 0)
1753 flags = STREAM_TOSERVER|STREAM_START;
1754 else if (u == (httplen1 - 1))
1755 flags = STREAM_TOSERVER|STREAM_EOF;
1756 else
1757 flags = STREAM_TOSERVER;
15ce8503
VJ
1758
1759 r = AppLayerParse(&f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
1760 if (r != 0) {
1761 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
1762 " 0: ", u, r);
15ce8503
VJ
1763 goto end;
1764 }
1765 }
1766
1767 htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
1768 if (htp_state == NULL) {
1769 printf("no http state: ");
15ce8503
VJ
1770 goto end;
1771 }
1772
36917c7d
VJ
1773 uint8_t ref[] = "/awstats.pl?/migratemigrate = |";
1774 size_t reflen = sizeof(ref) - 1;
1775
15ce8503
VJ
1776 htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0);
1777 if (tx != NULL && tx->request_uri_normalized != NULL) {
36917c7d 1778 if (reflen != bstr_size(tx->request_uri_normalized)) {
0625d542
VJ
1779 printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX,
1780 (uintmax_t)reflen,
1781 (uintmax_t)bstr_size(tx->request_uri_normalized));
36917c7d
VJ
1782 goto end;
1783 }
1784
1785 if (memcmp(bstr_ptr(tx->request_uri_normalized), ref,
1786 bstr_size(tx->request_uri_normalized)) != 0)
1787 {
0625d542
VJ
1788 printf("normalized uri \"");
1789 PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized));
1790 printf("\" != \"");
1791 PrintRawUriFp(stdout, ref, reflen);
1792 printf("\": ");
36917c7d
VJ
1793 goto end;
1794 }
15ce8503
VJ
1795 }
1796
36917c7d 1797 result = 1;
15ce8503
VJ
1798end:
1799 FlowL7DataPtrFree(&f);
1800 StreamTcpFreeConfig(TRUE);
1801 if (htp_state != NULL)
1802 HTPStateFree(htp_state);
1803 return result;
1804}
1805
a9cdd2bb
BR
1806#include "conf-yaml-loader.h"
1807
326047ee
VJ
1808/** \test Abort
1809 */
1810int HTPParserTest08(void) {
1811 int result = 0;
1812 Flow f;
1813 uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
1814 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1815 TcpSession ssn;
1816
1817 char input[] = "\
1818%YAML 1.1\n\
1819---\n\
1820libhtp:\n\
1821\n\
1822 default-config:\n\
1823 personality: IDS\n\
1824";
1825
1826 ConfCreateContextBackup();
1827 ConfInit();
63f6de58
VJ
1828 HtpConfigCreateBackup();
1829
326047ee
VJ
1830 ConfYamlLoadString(input, strlen(input));
1831 HTPConfigure();
1832
1833 HtpState *htp_state = NULL;
1834 int r = 0;
1835 memset(&f, 0, sizeof(f));
1836 memset(&ssn, 0, sizeof(ssn));
1837 f.protoctx = (void *)&ssn;
1838 f.src.family = AF_INET;
1839 f.dst.family = AF_INET;
1840
1841 StreamTcpInitConfig(TRUE);
1842 FlowL7DataPtrInit(&f);
1843
1844 uint8_t flags = 0;
1845 flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
1846
1847 r = AppLayerParse(&f, ALPROTO_HTTP, flags, httpbuf1, httplen1);
1848 if (r != 0) {
1849 printf("toserver chunk returned %" PRId32 ", expected"
1850 " 0: ", r);
1851 result = 0;
1852 goto end;
1853 }
1854
1855 htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
1856 if (htp_state == NULL) {
1857 printf("no http state: ");
1858 result = 0;
1859 goto end;
1860 }
1861
1862 htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0);
1863 if (tx != NULL && tx->request_uri_normalized != NULL) {
1864 //printf("uri %s\n", bstr_tocstr(tx->request_uri_normalized));
1865 PrintRawDataFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized),
1866 bstr_len(tx->request_uri_normalized));
1867 }
1868
1869 result = 1;
1870end:
1871 FlowL7DataPtrFree(&f);
1872 StreamTcpFreeConfig(TRUE);
1873 if (htp_state != NULL)
1874 HTPStateFree(htp_state);
1875
63f6de58 1876 HTPFreeConfig();
326047ee
VJ
1877 ConfDeInit();
1878 ConfRestoreContextBackup();
63f6de58 1879 HtpConfigRestoreBackup();
326047ee
VJ
1880 return result;
1881}
1882
1883/** \test Abort
1884 */
1885int HTPParserTest09(void) {
1886 int result = 0;
1887 Flow f;
1888 uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n";
1889 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1890 TcpSession ssn;
1891
1892 char input[] = "\
1893%YAML 1.1\n\
1894---\n\
1895libhtp:\n\
1896\n\
1897 default-config:\n\
1898 personality: Apache_2_2\n\
1899";
1900
1901 ConfCreateContextBackup();
1902 ConfInit();
63f6de58
VJ
1903 HtpConfigCreateBackup();
1904
326047ee
VJ
1905 ConfYamlLoadString(input, strlen(input));
1906 HTPConfigure();
1907
1908 HtpState *htp_state = NULL;
1909 int r = 0;
1910 memset(&f, 0, sizeof(f));
1911 memset(&ssn, 0, sizeof(ssn));
1912 f.protoctx = (void *)&ssn;
1913 f.src.family = AF_INET;
1914 f.dst.family = AF_INET;
1915
1916 StreamTcpInitConfig(TRUE);
1917 FlowL7DataPtrInit(&f);
1918
1919 uint8_t flags = 0;
1920 flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF;
1921
1922 r = AppLayerParse(&f, ALPROTO_HTTP, flags, httpbuf1, httplen1);
1923 if (r != 0) {
1924 printf("toserver chunk returned %" PRId32 ", expected"
1925 " 0: ", r);
1926 result = 0;
1927 goto end;
1928 }
1929
1930 htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
1931 if (htp_state == NULL) {
1932 printf("no http state: ");
1933 result = 0;
1934 goto end;
1935 }
1936
1937 htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0);
1938 if (tx != NULL && tx->request_uri_normalized != NULL) {
1939 //printf("uri %s\n", bstr_tocstr(tx->request_uri_normalized));
1940 PrintRawDataFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized),
1941 bstr_len(tx->request_uri_normalized));
1942 }
1943
1944 result = 1;
1945end:
1946 FlowL7DataPtrFree(&f);
1947 StreamTcpFreeConfig(TRUE);
1948 if (htp_state != NULL)
1949 HTPStateFree(htp_state);
1950
63f6de58 1951 HTPFreeConfig();
326047ee
VJ
1952 ConfDeInit();
1953 ConfRestoreContextBackup();
63f6de58 1954 HtpConfigRestoreBackup();
326047ee
VJ
1955 return result;
1956}
1957
a9cdd2bb
BR
1958/** \test Test basic config */
1959int HTPParserConfigTest01(void)
1960{
1961 int ret = 0;
1962 char input[] = "\
1963%YAML 1.1\n\
1964---\n\
1965libhtp:\n\
1966\n\
1967 default-config:\n\
1968 personality: IDS\n\
1969\n\
1970 server-config:\n\
1971\n\
1972 - apache-tomcat:\n\
1973 address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
1974 personality: Tomcat_6_0\n\
1975\n\
1976 - iis7:\n\
1977 address: \n\
1978 - 192.168.0.0/24\n\
1979 - 192.168.10.0/24\n\
1980 personality: IIS_7_0\n\
1981";
1982
1983 ConfCreateContextBackup();
1984 ConfInit();
1985
1986 ConfYamlLoadString(input, strlen(input));
1987
1988 ConfNode *outputs;
1989 outputs = ConfGetNode("libhtp.default-config.personality");
1990 if (outputs == NULL) {
1991 goto end;
1992 }
1993
1994 outputs = ConfGetNode("libhtp.server-config");
1995 if (outputs == NULL) {
1996 goto end;
1997 }
1998
1999 ConfNode *node = TAILQ_FIRST(&outputs->head);
2000 if (node == NULL) {
2001 goto end;
2002 }
2003 if (strcmp(node->name, "0") != 0) {
2004 goto end;
2005 }
2006 node = TAILQ_FIRST(&node->head);
2007 if (node == NULL) {
2008 goto end;
2009 }
2010 if (strcmp(node->name, "apache-tomcat") != 0) {
2011 goto end;
2012 }
2013
2014 int i = 0;
2015 ConfNode *n;
2016
2017 ConfNode *node2 = ConfNodeLookupChild(node, "personality");
2018 if (node2 == NULL) {
2019 goto end;
2020 }
2021 if (strcmp(node2->val, "Tomcat_6_0") != 0) {
2022 goto end;
2023 }
2024
2025 node = ConfNodeLookupChild(node, "address");
2026 if (node == NULL) {
2027 goto end;
2028 }
2029 TAILQ_FOREACH(n, &node->head, next) {
2030 if (n == NULL) {
2031 goto end;
2032 }
2033
2034 switch(i) {
2035 case 0:
2036 if (strcmp(n->name, "0") != 0) {
2037 goto end;
2038 }
2039 if (strcmp(n->val, "192.168.1.0/24") != 0) {
2040 goto end;
2041 }
2042 break;
2043 case 1:
2044 if (strcmp(n->name, "1") != 0) {
2045 goto end;
2046 }
2047 if (strcmp(n->val, "127.0.0.0/8") != 0) {
2048 goto end;
2049 }
2050 break;
2051 case 2:
2052 if (strcmp(n->name, "2") != 0) {
2053 goto end;
2054 }
2055 if (strcmp(n->val, "::1") != 0) {
2056 goto end;
2057 }
2058 break;
2059 default:
2060 goto end;
2061 }
2062 i++;
2063 }
2064
2065 outputs = ConfGetNode("libhtp.server-config");
2066 if (outputs == NULL) {
2067 goto end;
2068 }
2069
2070 node = TAILQ_FIRST(&outputs->head);
2071 node = TAILQ_NEXT(node, next);
2072 if (node == NULL) {
2073 goto end;
2074 }
2075 if (strcmp(node->name, "1") != 0) {
2076 goto end;
2077 }
2078 node = TAILQ_FIRST(&node->head);
2079 if (node == NULL) {
2080 goto end;
2081 }
2082 if (strcmp(node->name, "iis7") != 0) {
2083 goto end;
2084 }
2085
2086 node2 = ConfNodeLookupChild(node, "personality");
2087 if (node2 == NULL) {
2088 goto end;
2089 }
2090 if (strcmp(node2->val, "IIS_7_0") != 0) {
2091 goto end;
2092 }
2093
2094 node = ConfNodeLookupChild(node, "address");
2095 if (node == NULL) {
2096 goto end;
2097 }
2098
2099 i = 0;
2100 TAILQ_FOREACH(n, &node->head, next) {
2101 if (n == NULL) {
2102 goto end;
2103 }
2104
2105 switch(i) {
2106 case 0:
2107 if (strcmp(n->name, "0") != 0) {
2108 goto end;
2109 }
2110 if (strcmp(n->val, "192.168.0.0/24") != 0) {
2111 goto end;
2112 }
2113 break;
2114 case 1:
2115 if (strcmp(n->name, "1") != 0) {
2116 goto end;
2117 }
2118 if (strcmp(n->val, "192.168.10.0/24") != 0) {
2119 goto end;
2120 }
2121 break;
2122 default:
2123 goto end;
2124 }
2125 i++;
2126 }
2127
2128 ret = 1;
2129
2130end:
2131 ConfDeInit();
2132 ConfRestoreContextBackup();
2133
2134 return ret;
2135}
2136
2137/** \test Test config builds radix correctly */
2138int HTPParserConfigTest02(void)
2139{
2140 int ret = 0;
2141 char input[] = "\
2142%YAML 1.1\n\
2143---\n\
2144libhtp:\n\
2145\n\
2146 default-config:\n\
2147 personality: IDS\n\
2148\n\
2149 server-config:\n\
2150\n\
2151 - apache-tomcat:\n\
2152 address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
2153 personality: Tomcat_6_0\n\
2154\n\
2155 - iis7:\n\
2156 address: \n\
2157 - 192.168.0.0/24\n\
2158 - 192.168.10.0/24\n\
2159 personality: IIS_7_0\n\
2160";
2161
2162 ConfCreateContextBackup();
2163 ConfInit();
5c6a65dc 2164 HtpConfigCreateBackup();
a9cdd2bb
BR
2165
2166 ConfYamlLoadString(input, strlen(input));
2167
2168 HTPConfigure();
2169
2170 if (cfglist.cfg == NULL) {
2171 printf("No default config created.\n");
2172 goto end;
2173 }
2174
2175 if (cfgtree == NULL) {
2176 printf("No config tree created.\n");
2177 goto end;
2178 }
2179
2180 SCRadixNode *cfgnode = NULL;
2181 htp_cfg_t *htp = cfglist.cfg;
2182 uint8_t buf[128];
2183 const char *addr;
2184
2185 addr = "192.168.10.42";
2186 if (inet_pton(AF_INET, addr, buf) == 1) {
2187 cfgnode = SCRadixFindKeyIPV4BestMatch(buf, cfgtree);
f81fccd6
VJ
2188 if (cfgnode != NULL) {
2189 HTPCfgRec *htp_cfg_rec = SC_RADIX_NODE_USERDATA(cfgnode, HTPCfgRec);
2190 if (htp_cfg_rec != NULL) {
2191 htp = htp_cfg_rec->cfg;
2192 SCLogDebug("LIBHTP using config: %p", htp);
2193 }
69a4fee7 2194 }
a9cdd2bb
BR
2195 if (htp == NULL) {
2196 printf("Could not get config for: %s\n", addr);
2197 goto end;
2198 }
2199 }
2200 else {
2201 printf("Failed to parse address: %s\n", addr);
2202 goto end;
2203 }
2204
2205 addr = "::1";
2206 if (inet_pton(AF_INET6, addr, buf) == 1) {
2207 cfgnode = SCRadixFindKeyIPV6BestMatch(buf, cfgtree);
f81fccd6
VJ
2208 if (cfgnode != NULL) {
2209 HTPCfgRec *htp_cfg_rec = SC_RADIX_NODE_USERDATA(cfgnode, HTPCfgRec);
2210 if (htp_cfg_rec != NULL) {
2211 htp = htp_cfg_rec->cfg;
2212 SCLogDebug("LIBHTP using config: %p", htp);
2213 }
69a4fee7 2214 }
a9cdd2bb
BR
2215 if (htp == NULL) {
2216 printf("Could not get config for: %s\n", addr);
2217 goto end;
2218 }
2219 }
2220 else {
2221 printf("Failed to parse address: %s\n", addr);
2222 goto end;
2223 }
2224
2225 ret = 1;
2226
2227end:
5c6a65dc 2228 HTPFreeConfig();
a9cdd2bb
BR
2229 ConfDeInit();
2230 ConfRestoreContextBackup();
5c6a65dc 2231 HtpConfigRestoreBackup();
a9cdd2bb
BR
2232
2233 return ret;
2234}
2235
2236/** \test Test traffic is handled by the correct htp config */
2237int HTPParserConfigTest03(void)
2238{
2239 int result = 1;
2240 Flow f;
06a65cb4 2241 FLOW_INITIALIZE(&f);
a9cdd2bb
BR
2242 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
2243 " Data is c0oL!";
2244 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2245 TcpSession ssn;
2246
2247 HtpState *htp_state = NULL;
2248 int r = 0;
2249 char input[] = "\
2250%YAML 1.1\n\
2251---\n\
2252libhtp:\n\
2253\n\
2254 default-config:\n\
2255 personality: IDS\n\
2256\n\
2257 server-config:\n\
2258\n\
2259 - apache-tomcat:\n\
2260 address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\
2261 personality: Tomcat_6_0\n\
2262\n\
2263 - iis7:\n\
2264 address: \n\
2265 - 192.168.0.0/24\n\
2266 - 192.168.10.0/24\n\
2267 personality: IIS_7_0\n\
2268";
2269
2270 ConfCreateContextBackup();
2271 ConfInit();
5c6a65dc 2272 HtpConfigCreateBackup();
a9cdd2bb
BR
2273
2274 ConfYamlLoadString(input, strlen(input));
2275
2276 HTPConfigure();
2277
2278 const char *addr = "192.168.10.42";
2279
2280 memset(&f, 0, sizeof(f));
2281 memset(&ssn, 0, sizeof(ssn));
2282 f.protoctx = (void *)&ssn;
2283 f.dst.family = AF_INET;
2284 inet_pton(f.dst.family, addr, f.dst.addr_data32);
2285
2286 SCRadixNode *cfgnode = NULL;
2287 htp_cfg_t *htp = cfglist.cfg;
2288 cfgnode = SCRadixFindKeyIPV4BestMatch((uint8_t *)GET_IPV4_DST_ADDR_PTR(&f), cfgtree);
f81fccd6
VJ
2289 if (cfgnode != NULL) {
2290 HTPCfgRec *htp_cfg_rec = SC_RADIX_NODE_USERDATA(cfgnode, HTPCfgRec);
2291 if (htp_cfg_rec != NULL) {
2292 htp = htp_cfg_rec->cfg;
2293 SCLogDebug("LIBHTP using config: %p", htp);
2294 }
69a4fee7 2295 }
a9cdd2bb
BR
2296 if (htp == NULL) {
2297 printf("Could not get config for: %s\n", addr);
2298 goto end;
2299 }
2300
2301 StreamTcpInitConfig(TRUE);
8cc525c9 2302 FlowL7DataPtrInit(&f);
a9cdd2bb
BR
2303
2304 uint32_t u;
2305 for (u = 0; u < httplen1; u++) {
2306 uint8_t flags = 0;
2307
2308 if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
2309 else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
2310 else flags = STREAM_TOSERVER;
2311
2312 r = AppLayerParse(&f, ALPROTO_HTTP, flags, &httpbuf1[u], 1);
2313 if (r != 0) {
2314 printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
2315 " 0: ", u, r);
2316 result = 0;
2317 goto end;
2318 }
2319 }
2320
8cc525c9 2321 htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
a9cdd2bb
BR
2322 if (htp_state == NULL) {
2323 printf("no http state: ");
2324 result = 0;
2325 goto end;
2326 }
2327
2328 /* Check that the HTP state config matches the correct one */
2329 if (htp_state->connp->cfg != htp) {
2330 printf("wrong HTP config (%p instead of %p - default=%p): ",
2331 htp_state->connp->cfg, htp, cfglist.cfg);
2332 result = 0;
2333 goto end;
2334 }
2335
2336end:
5c6a65dc 2337 HTPFreeConfig();
a9cdd2bb
BR
2338 ConfDeInit();
2339 ConfRestoreContextBackup();
5c6a65dc 2340 HtpConfigRestoreBackup();
a9cdd2bb 2341
8cc525c9 2342 FlowL7DataPtrFree(&f);
a9cdd2bb
BR
2343 StreamTcpFreeConfig(TRUE);
2344 if (htp_state != NULL)
2345 HTPStateFree(htp_state);
06a65cb4 2346 FLOW_DESTROY(&f);
a9cdd2bb
BR
2347 return result;
2348}
06a65cb4 2349
c352bff6
VJ
2350#endif /* UNITTESTS */
2351
07f7ba55
GS
2352/**
2353 * \brief Register the Unit tests for the HTTP protocol
2354 */
2355void HTPParserRegisterTests(void) {
2356#ifdef UNITTESTS
2357 UtRegisterTest("HTPParserTest01", HTPParserTest01, 1);
2d6cf71d
GS
2358 UtRegisterTest("HTPParserTest02", HTPParserTest02, 1);
2359 UtRegisterTest("HTPParserTest03", HTPParserTest03, 1);
2360 UtRegisterTest("HTPParserTest04", HTPParserTest04, 1);
2361 UtRegisterTest("HTPParserTest05", HTPParserTest05, 1);
fc2f7f29 2362 UtRegisterTest("HTPParserTest06", HTPParserTest06, 1);
15ce8503 2363 UtRegisterTest("HTPParserTest07", HTPParserTest07, 1);
326047ee
VJ
2364 UtRegisterTest("HTPParserTest08", HTPParserTest08, 1);
2365 UtRegisterTest("HTPParserTest09", HTPParserTest09, 1);
a9cdd2bb
BR
2366 UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01, 1);
2367 UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02, 1);
2368 UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03, 1);
07f7ba55
GS
2369#endif /* UNITTESTS */
2370}
2371