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