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