SCReturnInt(0);
}
- if (body->nchunks == 0) {
+ if (body->first == NULL) {
/* New chunk */
bd = (HtpBodyChunk *)SCMalloc(sizeof(HtpBodyChunk));
if (bd == NULL)
bd->len = len;
bd->stream_offset = 0;
bd->next = NULL;
- bd->id = 0;
bd->data = SCMalloc(len);
if (bd->data == NULL) {
memcpy(bd->data, data, len);
body->first = body->last = bd;
- body->nchunks++;
body->content_len_so_far = len;
} else {
bd->len = len;
bd->stream_offset = body->content_len_so_far;
bd->next = NULL;
- bd->id = body->nchunks + 1;
bd->data = SCMalloc(len);
if (bd->data == NULL) {
body->last->next = bd;
body->last = bd;
- body->nchunks++;
body->content_len_so_far += len;
}
- SCLogDebug("Body %p; Chunk id: %"PRIu32", data %p, len %"PRIu32"", body,
- bd->id, bd->data, (uint32_t)bd->len);
+ SCLogDebug("Body %p; data %p, len %"PRIu32, body, bd->data, (uint32_t)bd->len);
SCReturnInt(0);
if (SCLogDebugEnabled()||1) {
SCEnter();
- if (body->nchunks == 0)
+ if (body->first == NULL)
return;
HtpBodyChunk *cur = NULL;
SCLogDebug("--- Start body chunks at %p ---", body);
printf("--- Start body chunks at %p ---\n", body);
for (cur = body->first; cur != NULL; cur = cur->next) {
- SCLogDebug("Body %p; Chunk id: %"PRIu32", data %p, len %"PRIu32"\n",
- body, cur->id, cur->data, (uint32_t)cur->len);
- printf("Body %p; Chunk id: %"PRIu32", data %p, len %"PRIu32"\n",
- body, cur->id, cur->data, (uint32_t)cur->len);
+ SCLogDebug("Body %p; data %p, len %"PRIu32, body, cur->data, (uint32_t)cur->len);
+ printf("Body %p; data %p, len %"PRIu32"\n", body, cur->data, (uint32_t)cur->len);
PrintRawDataFp(stdout, (uint8_t*)cur->data, cur->len);
}
SCLogDebug("--- End body chunks at %p ---", body);
{
SCEnter();
- if (body->nchunks == 0)
+ if (body->first == NULL)
return;
- SCLogDebug("Removing chunks of Body %p; Last Chunk id: %"PRIu32", data %p,"
- " len %"PRIu32, body, body->last->id, body->last->data,
- (uint32_t)body->last->len);
- body->nchunks = 0;
+ SCLogDebug("Removing chunks of Body %p; data %p, len %"PRIu32, body,
+ body->last->data, (uint32_t)body->last->len);
HtpBodyChunk *cur = NULL;
HtpBodyChunk *prev = NULL;
{
SCEnter();
- if (body == NULL || body->nchunks == 0) {
+ if (body == NULL || body->first == NULL) {
SCReturn;
}
SCReturn;
}
- SCLogDebug("Pruning chunks of Body %p; Last Chunk id: %"PRIu32", data %p,"
- " len %"PRIu32, body, body->last->id, body->last->data,
- (uint32_t)body->last->len);
+ SCLogDebug("Pruning chunks of Body %p; data %p, len %"PRIu32, body,
+ body->last->data, (uint32_t)body->last->len);
HtpBodyChunk *cur = body->first;
while (cur != NULL) {
"body->body_parsed %"PRIu64, cur->stream_offset, cur->len,
cur->stream_offset + cur->len, body->body_parsed);
- if ((cur->stream_offset + cur->len) >= body->body_parsed) {
+ if (cur->stream_offset >= body->body_inspected) {
break;
}
body->last = next;
}
- if (body->nchunks > 0)
- body->nchunks--;
-
if (cur->data != NULL) {
SCFree(cur->data);
}
/* if we're in the file storage process, deal with that now */
if (htud->flags & HTP_FILENAME_SET) {
- if (header_start != NULL || form_end != NULL || htud->flags & HTP_BODY_COMPLETE) {
+ if (header_start != NULL || form_end != NULL || htud->flags & HTP_REQ_BODY_COMPLETE) {
SCLogDebug("reached the end of the file");
uint8_t *filedata = chunks_buffer;
filedata_len = form_end - filedata;
} else if (form_end != NULL && form_end == header_start) {
filedata_len = form_end - filedata - 2; /* 0d 0a */
- } else if (htud->flags & HTP_BODY_COMPLETE) {
+ } else if (htud->flags & HTP_REQ_BODY_COMPLETE) {
filedata_len = chunks_buffer_len;
flags = FILE_TRUNCATED;
}
SCLogDebug("POST");
int r = HtpRequestBodySetupMultipart(d, htud);
if (r == 1) {
- htud->request_body.type = HTP_BODY_REQUEST_MULTIPART;
+ htud->request_body_type = HTP_BODY_REQUEST_MULTIPART;
} else if (r == 0) {
- htud->request_body.type = HTP_BODY_REQUEST_POST;
+ htud->request_body_type = HTP_BODY_REQUEST_POST;
SCLogDebug("not multipart");
}
} else if (d->tx->request_method_number == M_PUT) {
if (HtpRequestBodySetupPUT(d, htud) == 0) {
- htud->request_body.type = HTP_BODY_REQUEST_PUT;
+ htud->request_body_type = HTP_BODY_REQUEST_PUT;
}
}
int r = HtpBodyAppendChunk(htud, &htud->request_body, (uint8_t *)d->data, len);
if (r < 0) {
- htud->flags |= HTP_BODY_COMPLETE;
+ htud->flags |= HTP_REQ_BODY_COMPLETE;
} else if (hstate->request_body_limit > 0 &&
htud->request_body.content_len_so_far >= hstate->request_body_limit)
{
- htud->flags |= HTP_BODY_COMPLETE;
+ htud->flags |= HTP_REQ_BODY_COMPLETE;
} else if (htud->request_body.content_len_so_far == htud->request_body.content_len) {
- htud->flags |= HTP_BODY_COMPLETE;
+ htud->flags |= HTP_REQ_BODY_COMPLETE;
}
uint8_t *chunks_buffer = NULL;
uint32_t chunks_buffer_len = 0;
- if (htud->request_body.type == HTP_BODY_REQUEST_MULTIPART) {
+ if (htud->request_body_type == HTP_BODY_REQUEST_MULTIPART) {
/* multi-part body handling starts here */
if (!(htud->flags & HTP_BOUNDARY_SET)) {
goto end;
if (chunks_buffer != NULL) {
SCFree(chunks_buffer);
}
- } else if (htud->request_body.type == HTP_BODY_REQUEST_POST) {
+ } else if (htud->request_body_type == HTP_BODY_REQUEST_POST) {
HtpRequestBodyHandlePOST(hstate, htud, d->tx, (uint8_t *)d->data, (uint32_t)d->len);
- } else if (htud->request_body.type == HTP_BODY_REQUEST_PUT) {
+ } else if (htud->request_body_type == HTP_BODY_REQUEST_PUT) {
HtpRequestBodyHandlePUT(hstate, htud, d->tx, (uint8_t *)d->data, (uint32_t)d->len);
}
memset(htud, 0, sizeof(HtpTxUserData));
htud->operation = HTP_BODY_RESPONSE;
+ htp_header_t *cl = table_getc(d->tx->response_headers, "content-length");
+ if (cl != NULL)
+ htud->response_body.content_len = htp_parse_content_length(cl->value);
+
/* Set the user data for handling body chunks on this transaction */
htp_tx_set_user_data(d->tx, htud);
}
int r = HtpBodyAppendChunk(htud, &htud->response_body, (uint8_t *)d->data, len);
if (r < 0) {
- htud->flags |= HTP_BODY_COMPLETE;
+ htud->flags |= HTP_RES_BODY_COMPLETE;
} else if (hstate->response_body_limit > 0 &&
htud->response_body.content_len_so_far >= hstate->response_body_limit)
{
- htud->flags |= HTP_BODY_COMPLETE;
+ htud->flags |= HTP_RES_BODY_COMPLETE;
} else if (htud->response_body.content_len_so_far == htud->response_body.content_len) {
- htud->flags |= HTP_BODY_COMPLETE;
+ htud->flags |= HTP_RES_BODY_COMPLETE;
}
HtpResponseBodyHandle(hstate, htud, d->tx, (uint8_t *)d->data, (uint32_t)d->len);
matched on some rule */
/** Struct used to hold chunks of a body on a request */
-typedef struct HtpBodyChunk_ {
+struct HtpBodyChunk_ {
uint8_t *data; /**< Pointer to the data of the chunk */
- uint32_t len; /**< Length of the chunk */
- uint32_t id; /**< number of chunk of the current body */
struct HtpBodyChunk_ *next; /**< Pointer to the next chunk */
uint64_t stream_offset;
-} HtpBodyChunk;
+ uint32_t len; /**< Length of the chunk */
+} __attribute__((__packed__));
+typedef struct HtpBodyChunk_ HtpBodyChunk;
/** Struct used to hold all the chunks of a body on a request */
typedef struct HtpBody_ {
HtpBodyChunk *first; /**< Pointer to the first chunk */
HtpBodyChunk *last; /**< Pointer to the last chunk */
- uint32_t nchunks; /**< Number of chunks in the current operation */
- uint8_t type;
/* Holds the length of the htp request body */
uint64_t content_len;
/* Holds the length of the htp request body seen so far */
uint64_t content_len_so_far;
-
+ /* parser tracker */
uint64_t body_parsed;
-
- /* pahole: padding: 3 */
+ /* inspection tracker */
+ uint64_t body_inspected;
} HtpBody;
-#define HTP_BODY_COMPLETE 0x01 /**< body is complete or limit is reached,
+#define HTP_REQ_BODY_COMPLETE 0x01 /**< body is complete or limit is reached,
either way, this is it. */
-#define HTP_CONTENTTYPE_SET 0x02 /**< We have the content type */
-#define HTP_BOUNDARY_SET 0x04 /**< We have a boundary string */
-#define HTP_BOUNDARY_OPEN 0x08 /**< We have a boundary string */
-#define HTP_FILENAME_SET 0x10 /**< filename is registered in the flow */
-#define HTP_DONTSTORE 0x20 /**< not storing this file */
+#define HTP_RES_BODY_COMPLETE 0x02
+#define HTP_CONTENTTYPE_SET 0x04 /**< We have the content type */
+#define HTP_BOUNDARY_SET 0x08 /**< We have a boundary string */
+#define HTP_BOUNDARY_OPEN 0x10 /**< We have a boundary string */
+#define HTP_FILENAME_SET 0x20 /**< filename is registered in the flow */
+#define HTP_DONTSTORE 0x40 /**< not storing this file */
#define HTP_TX_HAS_FILE 0x01
#define HTP_TX_HAS_FILENAME 0x02 /**< filename is known at this time */
uint8_t flags;
int16_t operation;
+
+ uint8_t request_body_type;
+ uint8_t response_body_type;
+
} HtpTxUserData;
typedef struct HtpState_ {
-/* Copyright (C) 2007-2010 Open Information Security Foundation
+/* Copyright (C) 2007-2012 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
#include "app-layer-htp.h"
#include "app-layer-protos.h"
+#define BODY_SCAN_WINDOW 4096
+#define BODY_MINIMAL_SIZE 32768
+
/**
* \brief Helps buffer request bodies for different transactions and stores them
* away in detection code.
htp_tx_t *tx = NULL;
int i = 0;
- if (det_ctx->hcbd_buffers_list_len > 0) {
- SCReturn;
- }
-
if (htp_state == NULL) {
SCLogDebug("no HTTP state");
goto end;
/* let's get the transaction count. We need this to hold the client body
* buffer for each transaction */
- det_ctx->hcbd_buffers_list_len = list_size(htp_state->connp->conn->transactions) - tmp_idx;
+ size_t txs = list_size(htp_state->connp->conn->transactions) - tmp_idx;
/* no transactions?! cool. get out of here */
- if (det_ctx->hcbd_buffers_list_len == 0)
+ if (txs == 0) {
goto end;
+ } else if (txs > det_ctx->hcbd_buffers_list_len) {
+ det_ctx->hcbd = SCRealloc(det_ctx->hcbd, txs * sizeof(HttpReassembledBody));
+ if (det_ctx->hcbd == NULL) {
+ goto end;
+ }
- /* assign space to hold buffers. Each per transaction */
- det_ctx->hcbd_buffers = SCMalloc(det_ctx->hcbd_buffers_list_len * sizeof(uint8_t *));
- if (det_ctx->hcbd_buffers == NULL) {
- goto end;
- }
- memset(det_ctx->hcbd_buffers, 0, det_ctx->hcbd_buffers_list_len * sizeof(uint8_t *));
-
- det_ctx->hcbd_buffers_len = SCMalloc(det_ctx->hcbd_buffers_list_len * sizeof(uint32_t));
- if (det_ctx->hcbd_buffers_len == NULL) {
- goto end;
+ memset(det_ctx->hcbd + det_ctx->hcbd_buffers_list_len, 0,
+ (txs - det_ctx->hcbd_buffers_list_len) * sizeof(HttpReassembledBody));
+ det_ctx->hcbd_buffers_list_len = txs;
}
- memset(det_ctx->hcbd_buffers_len, 0, det_ctx->hcbd_buffers_list_len * sizeof(uint32_t));
idx = AppLayerTransactionGetInspectId(f);
if (idx == -1) {
int size = (int)list_size(htp_state->connp->conn->transactions);
for (; idx < size; idx++, i++) {
+ /* already set up */
+ if (det_ctx->hcbd[i].buffer_len > 0) {
+ SCLogDebug("set up already");
+ continue;
+ }
tx = list_get(htp_state->connp->conn->transactions, idx);
- if (tx == NULL)
+ if (tx == NULL) {
+ SCLogDebug("no tx");
continue;
+ }
HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx);
- if (htud == NULL)
+ if (htud == NULL) {
+ SCLogDebug("no htud");
continue;
+ }
- HtpBodyChunk *cur = htud->request_body.first;
+ /* no new data */
+ if (htud->request_body.body_inspected == htud->request_body.content_len_so_far) {
+ SCLogDebug("no new data");
+ continue;
+ }
- if (htud->request_body.nchunks == 0) {
+ HtpBodyChunk *cur = htud->request_body.first;
+ if (cur == NULL) {
SCLogDebug("No http chunks to inspect for this transacation");
continue;
- } else {
- /* no chunks?!! move on to the next transaction */
- if (cur == NULL) {
- SCLogDebug("No http chunks to inspect");
- continue;
- }
+ }
- /* in case of chunked transfer encoding, we don't have the length
- * of the request body until we see a chunk with length 0. This
- * doesn't let us use the request body callback function to
- * figure out the end of request body. Instead we do it here. If
- * the length is 0, and we have already seen content, it indicates
- * chunked transfer. We also check if the parser has truly seen
- * the last chunk by checking the progress state for the
- * transaction. If we are done parsing all the chunks, we would
- * have it set to something other than TX_PROGRESS_REQ_BODY.
- * Either ways we should be moving away from buffering in the end
- * and running content validation on this buffer type of architecture
- * to a stateful inspection, where we can inspect body chunks as and
- * when they come */
- if (htud->request_body.content_len == 0) {
- if ((htud->request_body.content_len_so_far > 0) &&
+ /* in case of chunked transfer encoding, we don't have the length
+ * of the request body until we see a chunk with length 0. This
+ * doesn't let us use the request body callback function to
+ * figure out the end of request body. Instead we do it here. If
+ * the length is 0, and we have already seen content, it indicates
+ * chunked transfer. We also check if the parser has truly seen
+ * the last chunk by checking the progress state for the
+ * transaction. If we are done parsing all the chunks, we would
+ * have it set to something other than TX_PROGRESS_REQ_BODY.
+ * Either ways we should be moving away from buffering in the end
+ * and running content validation on this buffer type of architecture
+ * to a stateful inspection, where we can inspect body chunks as and
+ * when they come */
+ if (htud->request_body.content_len == 0) {
+ if ((htud->request_body.content_len_so_far > 0) &&
tx->progress != TX_PROGRESS_REQ_BODY) {
- /* final length of the body */
- htud->flags |= HTP_BODY_COMPLETE;
+ /* final length of the body */
+ htud->flags |= HTP_REQ_BODY_COMPLETE;
+ }
+ }
+
+ /* inspect the body if the transfer is complete or we have hit
+ * our body size limit */
+ if (htud->request_body.content_len_so_far < BODY_MINIMAL_SIZE &&
+ !(htud->flags & HTP_REQ_BODY_COMPLETE)) {
+ SCLogDebug("we still haven't seen the entire request body. "
+ "Let's defer body inspection till we see the "
+ "entire body.");
+ continue;
+ }
+
+ int first = 1;
+ while (cur != NULL) {
+ /* see if we can filter out chunks */
+ if (htud->request_body.body_inspected > 0) {
+ if (cur->stream_offset < htud->request_body.body_inspected) {
+ if (htud->request_body.body_inspected - cur->stream_offset > BODY_SCAN_WINDOW) {
+ cur = cur->next;
+ continue;
+ } else {
+ /* include this one */
+ }
+ } else {
+ /* include this one */
}
}
- /* inspect the body if the transfer is complete or we have hit
- * our body size limit */
- if (!(htud->flags & HTP_BODY_COMPLETE)) {
- SCLogDebug("we still haven't seen the entire request body. "
- "Let's defer body inspection till we see the "
- "entire body.");
- continue;
+ if (first) {
+ det_ctx->hcbd[i].offset = cur->stream_offset;
+ first = 0;
}
- uint8_t *chunks_buffer = NULL;
- int32_t chunks_buffer_len = 0;
- while (cur != NULL) {
- chunks_buffer_len += cur->len;
- if ( (chunks_buffer = SCRealloc(chunks_buffer, chunks_buffer_len)) == NULL) {
+ /* see if we need to grow the buffer */
+ if (det_ctx->hcbd[i].buffer == NULL || det_ctx->hcbd[i].buffer_len + cur->len > det_ctx->hcbd[i].buffer_size) {
+ det_ctx->hcbd[i].buffer_size += cur->len * 2;
+
+ if ((det_ctx->hcbd[i].buffer = SCRealloc(det_ctx->hcbd[i].buffer, det_ctx->hcbd[i].buffer_size)) == NULL) {
goto end;
}
-
- memcpy(chunks_buffer + chunks_buffer_len - cur->len, cur->data, cur->len);
- cur = cur->next;
}
- /* store the buffers. We will need it for further inspection */
- det_ctx->hcbd_buffers[i] = chunks_buffer;
- det_ctx->hcbd_buffers_len[i] = chunks_buffer_len;
+ memcpy(det_ctx->hcbd[i].buffer + det_ctx->hcbd[i].buffer_len, cur->data, cur->len);
+ det_ctx->hcbd[i].buffer_len += cur->len;
- } /* else - if (htud->body.nchunks == 0) */
+ cur = cur->next;
+ }
+
+ /* update inspected tracker */
+ htud->request_body.body_inspected =
+ htud->request_body.last->stream_offset +
+ htud->request_body.last->len;
} /* for (idx = AppLayerTransactionGetInspectId(f); .. */
end:
int i;
uint32_t cnt = 0;
- /* bail before locking if we have nothing to do */
- if (det_ctx->hcbd_buffers_list_len == 0) {
- FLOWLOCK_WRLOCK(f);
- DetectEngineBufferHttpClientBodies(de_ctx, det_ctx, f, htp_state);
- FLOWLOCK_UNLOCK(f);
- }
+ FLOWLOCK_WRLOCK(f);
+ DetectEngineBufferHttpClientBodies(de_ctx, det_ctx, f, htp_state);
+ FLOWLOCK_UNLOCK(f);
for (i = 0; i < det_ctx->hcbd_buffers_list_len; i++) {
+ if (det_ctx->hcbd[i].buffer_len == 0)
+ continue;
+
cnt += HttpClientBodyPatternSearch(det_ctx,
- det_ctx->hcbd_buffers[i],
- det_ctx->hcbd_buffers_len[i],
+ det_ctx->hcbd[i].buffer,
+ det_ctx->hcbd[i].buffer_len,
flags);
}
int r = 0;
int i = 0;
- /* bail before locking if we have nothing to do */
- if (det_ctx->hcbd_buffers_list_len == 0) {
- FLOWLOCK_WRLOCK(f);
- DetectEngineBufferHttpClientBodies(de_ctx, det_ctx, f, alstate);
- FLOWLOCK_UNLOCK(f);
- }
+ FLOWLOCK_WRLOCK(f);
+ DetectEngineBufferHttpClientBodies(de_ctx, det_ctx, f, alstate);
+ FLOWLOCK_UNLOCK(f);
for (i = 0; i < det_ctx->hcbd_buffers_list_len; i++) {
- uint8_t *hcbd_buffer = det_ctx->hcbd_buffers[i];
- uint32_t hcbd_buffer_len = det_ctx->hcbd_buffers_len[i];
+ uint8_t *hcbd_buffer = det_ctx->hcbd[i].buffer;
+ uint32_t hcbd_buffer_len = det_ctx->hcbd[i].buffer_len;
- if (hcbd_buffer == NULL)
+ if (hcbd_buffer == NULL || hcbd_buffer_len == 0)
continue;
det_ctx->buffer_offset = 0;
hcbd_buffer,
hcbd_buffer_len,
DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCBD, NULL);
- //r = DoInspectHttpClientBody(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HCBDMATCH],
- //hcbd_buffer, hcbd_buffer_len);
if (r == 1) {
break;
}
*/
void DetectEngineCleanHCBDBuffers(DetectEngineThreadCtx *det_ctx)
{
- if (det_ctx->hcbd_buffers_list_len != 0) {
- int i;
- for (i = 0; i < det_ctx->hcbd_buffers_list_len; i++) {
- if (det_ctx->hcbd_buffers[i] != NULL)
- SCFree(det_ctx->hcbd_buffers[i]);
- }
- if (det_ctx->hcbd_buffers != NULL) {
- SCFree(det_ctx->hcbd_buffers);
- det_ctx->hcbd_buffers = NULL;
- }
- if (det_ctx->hcbd_buffers_len != NULL) {
- SCFree(det_ctx->hcbd_buffers_len);
- det_ctx->hcbd_buffers_len = NULL;
- }
- det_ctx->hcbd_buffers_list_len = 0;
+ int i;
+ for (i = 0; i < det_ctx->hcbd_buffers_list_len; i++) {
+ det_ctx->hcbd[i].buffer_len = 0;
}
-
return;
}
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- result = 0;
goto end;
}
http_state = f.alstate;
if (http_state == NULL) {
printf("no http state: \n");
- result = 0;
goto end;
}
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r);
- result = 0;
goto end;
}
#include "app-layer-htp.h"
#include "app-layer-protos.h"
+#define BODY_SCAN_WINDOW 4096
+#define BODY_MINIMAL_SIZE 32768
+
/**
* \brief Helps buffer response bodies for different transactions and stores them
* away in detection code.
htp_tx_t *tx = NULL;
int i = 0;
- if (det_ctx->hsbd_buffers_list_len > 0) {
- SCReturn;
- }
-
if (htp_state == NULL) {
SCLogDebug("no HTTP state");
goto end;
/* let's get the transaction count. We need this to hold the server body
* buffer for each transaction */
- det_ctx->hsbd_buffers_list_len = list_size(htp_state->connp->conn->transactions) - tmp_idx;
+ size_t txs = list_size(htp_state->connp->conn->transactions) - tmp_idx;
/* no transactions?! cool. get out of here */
- if (det_ctx->hsbd_buffers_list_len == 0)
- goto end;
-
- /* assign space to hold buffers. Each per transaction */
- det_ctx->hsbd_buffers = SCMalloc(det_ctx->hsbd_buffers_list_len * sizeof(uint8_t *));
- if (det_ctx->hsbd_buffers == NULL) {
+ if (txs == 0) {
goto end;
- }
- memset(det_ctx->hsbd_buffers, 0, det_ctx->hsbd_buffers_list_len * sizeof(uint8_t *));
+ } else if (txs > det_ctx->hsbd_buffers_list_len) {
+ det_ctx->hsbd = SCRealloc(det_ctx->hsbd, txs * sizeof(HttpReassembledBody));
+ if (det_ctx->hsbd == NULL) {
+ goto end;
+ }
- det_ctx->hsbd_buffers_len = SCMalloc(det_ctx->hsbd_buffers_list_len * sizeof(uint32_t));
- if (det_ctx->hsbd_buffers_len == NULL) {
- goto end;
+ memset(det_ctx->hsbd + det_ctx->hsbd_buffers_list_len, 0,
+ (txs - det_ctx->hsbd_buffers_list_len) * sizeof(HttpReassembledBody));
+ det_ctx->hsbd_buffers_list_len = txs;
}
- memset(det_ctx->hsbd_buffers_len, 0, det_ctx->hsbd_buffers_list_len * sizeof(uint32_t));
idx = AppLayerTransactionGetInspectId(f);
if (idx == -1) {
int size = (int)list_size(htp_state->connp->conn->transactions);
for (; idx < size; idx++, i++) {
+ /* already set up */
+ if (det_ctx->hsbd[i].buffer_len > 0)
+ continue;
tx = list_get(htp_state->connp->conn->transactions, idx);
if (tx == NULL)
if (htud == NULL)
continue;
- HtpBodyChunk *cur = htud->response_body.first;
+ /* no new data */
+ if (htud->response_body.body_inspected == htud->response_body.content_len_so_far) {
+ continue;
+ }
- if (htud->response_body.nchunks == 0) {
+ HtpBodyChunk *cur = htud->response_body.first;
+ if (cur == NULL) {
SCLogDebug("No http chunks to inspect for this transacation");
continue;
- } else {
- /* no chunks?!! move on to the next transaction */
- if (cur == NULL) {
- SCLogDebug("No http chunks to inspect");
- continue;
- }
+ }
- /* in case of chunked transfer encoding, we don't have the length
- * of the response body until we see a chunk with length 0. This
- * doesn't let us use the response body callback function to
- * figure out the end of response body. Instead we do it here. If
- * the length is 0, and we have already seen content, it indicates
- * chunked transfer. We also check if the parser has truly seen
- * the last chunk by checking the progress state for the
- * transaction. If we are done parsing all the chunks, we would
- * have it set to something other than TX_PROGRESS_REQ_BODY.
- * Either ways we should be moving away from buffering in the end
- * and running content validation on this buffer type of architecture
- * to a stateful inspection, where we can inspect body chunks as and
- * when they come */
- if (htud->response_body.content_len == 0) {
- if ((htud->response_body.content_len_so_far > 0) &&
+ /* in case of chunked transfer encoding, we don't have the length
+ * of the response body until we see a chunk with length 0. This
+ * doesn't let us use the response body callback function to
+ * figure out the end of response body. Instead we do it here. If
+ * the length is 0, and we have already seen content, it indicates
+ * chunked transfer. We also check if the parser has truly seen
+ * the last chunk by checking the progress state for the
+ * transaction. If we are done parsing all the chunks, we would
+ * have it set to something other than TX_PROGRESS_REQ_BODY.
+ * Either ways we should be moving away from buffering in the end
+ * and running content validation on this buffer type of architecture
+ * to a stateful inspection, where we can inspect body chunks as and
+ * when they come */
+ if (htud->response_body.content_len == 0) {
+ if ((htud->response_body.content_len_so_far > 0) &&
tx->progress != TX_PROGRESS_REQ_BODY) {
- /* final length of the body */
- htud->flags |= HTP_BODY_COMPLETE;
+ /* final length of the body */
+ htud->flags |= HTP_RES_BODY_COMPLETE;
+ }
+ }
+
+ /* inspect the body if the transfer is complete or we have hit
+ * our body size limit */
+ if (htud->response_body.content_len_so_far < BODY_MINIMAL_SIZE &&
+ !(htud->flags & HTP_RES_BODY_COMPLETE)) {
+ SCLogDebug("we still haven't seen the entire response body. "
+ "Let's defer body inspection till we see the "
+ "entire body.");
+ continue;
+ }
+
+ //SCLogInfo("now we inspect! %"PRIu64, htud->response_body.content_len_so_far);
+
+ int first = 1;
+ while (cur != NULL) {
+ /* see if we can filter out chunks */
+ if (htud->response_body.body_inspected > 0) {
+ if (cur->stream_offset < htud->response_body.body_inspected) {
+ if (htud->response_body.body_inspected - cur->stream_offset > BODY_SCAN_WINDOW) {
+ cur = cur->next;
+ continue;
+ } else {
+ /* include this one */
+ }
+ } else {
+ /* include this one */
}
}
- /* inspect the body if the transfer is complete or we have hit
- * our body size limit */
- if (!(htud->flags & HTP_BODY_COMPLETE)) {
- SCLogDebug("we still haven't seen the entire response body. "
- "Let's defer body inspection till we see the "
- "entire body.");
- continue;
+ if (first) {
+ det_ctx->hsbd[i].offset = cur->stream_offset;
+ first = 0;
}
- uint8_t *chunks_buffer = NULL;
- int32_t chunks_buffer_len = 0;
- while (cur != NULL) {
- chunks_buffer_len += cur->len;
- if ( (chunks_buffer = SCRealloc(chunks_buffer, chunks_buffer_len)) == NULL) {
+ /* see if we need to grow the buffer */
+ if (det_ctx->hsbd[i].buffer == NULL || det_ctx->hsbd[i].buffer_len + cur->len > det_ctx->hsbd[i].buffer_size) {
+ det_ctx->hsbd[i].buffer_size += cur->len * 2;
+
+ if ((det_ctx->hsbd[i].buffer = SCRealloc(det_ctx->hsbd[i].buffer, det_ctx->hsbd[i].buffer_size)) == NULL) {
goto end;
}
-
- memcpy(chunks_buffer + chunks_buffer_len - cur->len, cur->data, cur->len);
- cur = cur->next;
}
- /* store the buffers. We will need it for further inspection */
- det_ctx->hsbd_buffers[i] = chunks_buffer;
- det_ctx->hsbd_buffers_len[i] = chunks_buffer_len;
+ memcpy(det_ctx->hsbd[i].buffer + det_ctx->hsbd[i].buffer_len, cur->data, cur->len);
+ det_ctx->hsbd[i].buffer_len += cur->len;
- } /* else - if (htud->body.nchunks == 0) */
+ cur = cur->next;
+ }
+
+ /* update inspected tracker */
+ htud->response_body.body_inspected =
+ htud->response_body.last->stream_offset +
+ htud->response_body.last->len;
} /* for (idx = AppLayerTransactionGetInspectId(f); .. */
end:
int i;
uint32_t cnt = 0;
- /* bail before locking if we have nothing to do */
- if (det_ctx->hsbd_buffers_list_len == 0) {
- FLOWLOCK_WRLOCK(f);
- DetectEngineBufferHttpServerBodies(de_ctx, det_ctx, f, htp_state);
- FLOWLOCK_UNLOCK(f);
- }
+ FLOWLOCK_WRLOCK(f);
+ DetectEngineBufferHttpServerBodies(de_ctx, det_ctx, f, htp_state);
+ FLOWLOCK_UNLOCK(f);
for (i = 0; i < det_ctx->hsbd_buffers_list_len; i++) {
+ if (det_ctx->hsbd[i].buffer_len == 0)
+ continue;
+
cnt += HttpServerBodyPatternSearch(det_ctx,
- det_ctx->hsbd_buffers[i],
- det_ctx->hsbd_buffers_len[i],
+ det_ctx->hsbd[i].buffer,
+ det_ctx->hsbd[i].buffer_len,
flags);
}
int r = 0;
int i = 0;
- /* bail before locking if we have nothing to do */
- if (det_ctx->hsbd_buffers_list_len == 0) {
- FLOWLOCK_WRLOCK(f);
- DetectEngineBufferHttpServerBodies(de_ctx, det_ctx, f, alstate);
- FLOWLOCK_UNLOCK(f);
- }
+ FLOWLOCK_WRLOCK(f);
+ DetectEngineBufferHttpServerBodies(de_ctx, det_ctx, f, alstate);
+ FLOWLOCK_UNLOCK(f);
for (i = 0; i < det_ctx->hsbd_buffers_list_len; i++) {
- uint8_t *hsbd_buffer = det_ctx->hsbd_buffers[i];
- uint32_t hsbd_buffer_len = det_ctx->hsbd_buffers_len[i];
+ uint8_t *hsbd_buffer = det_ctx->hsbd[i].buffer;
+ uint32_t hsbd_buffer_len = det_ctx->hsbd[i].buffer_len;
- if (hsbd_buffer == NULL)
+ if (hsbd_buffer == NULL || hsbd_buffer_len == 0)
continue;
det_ctx->buffer_offset = 0;
hsbd_buffer,
hsbd_buffer_len,
DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSBD, NULL);
- //r = DoInspectHttpServerBody(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HSBDMATCH],
- //hsbd_buffer, hsbd_buffer_len);
if (r == 1) {
break;
}
*/
void DetectEngineCleanHSBDBuffers(DetectEngineThreadCtx *det_ctx)
{
- if (det_ctx->hsbd_buffers_list_len != 0) {
- int i;
- for (i = 0; i < det_ctx->hsbd_buffers_list_len; i++) {
- if (det_ctx->hsbd_buffers[i] != NULL)
- SCFree(det_ctx->hsbd_buffers[i]);
- }
- if (det_ctx->hsbd_buffers != NULL) {
- SCFree(det_ctx->hsbd_buffers);
- det_ctx->hsbd_buffers = NULL;
- }
- if (det_ctx->hsbd_buffers_len != NULL) {
- SCFree(det_ctx->hsbd_buffers_len);
- det_ctx->hsbd_buffers_len = NULL;
- }
- det_ctx->hsbd_buffers_list_len = 0;
+ int i;
+ for (i = 0; i < det_ctx->hsbd_buffers_list_len; i++) {
+ det_ctx->hsbd[i].buffer_len = 0;
}
-
return;
}
if (det_ctx->bj_values != NULL)
SCFree(det_ctx->bj_values);
+ if (det_ctx->hsbd != NULL) {
+ SCLogDebug("det_ctx hsbd %u", det_ctx->hsbd_buffers_list_len);
+ for (i = 0; i < det_ctx->hsbd_buffers_list_len; i++) {
+ if (det_ctx->hsbd[i].buffer != NULL)
+ SCFree(det_ctx->hsbd[i].buffer);
+ }
+ SCFree(det_ctx->hsbd);
+ }
+
+ if (det_ctx->hcbd != NULL) {
+ SCLogDebug("det_ctx hcbd %u", det_ctx->hcbd_buffers_list_len);
+ for (i = 0; i < det_ctx->hcbd_buffers_list_len; i++) {
+ if (det_ctx->hcbd[i].buffer != NULL)
+ SCFree(det_ctx->hcbd[i].buffer);
+ SCLogDebug("det_ctx->hcbd[i].buffer_size %u", det_ctx->hcbd[i].buffer_size);
+ }
+ SCFree(det_ctx->hcbd);
+ }
+
SCFree(det_ctx);
return TM_ECODE_OK;
HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1);
HtpBodyChunk *cur = htud->request_body.first;
- if (htud->request_body.nchunks == 0) {
+ if (htud->request_body.first == NULL) {
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
htud = (HtpTxUserData *) htp_tx_get_user_data(t2);
cur = htud->request_body.first;
- if (htud->request_body.nchunks == 0) {
+ if (htud->request_body.first == NULL) {
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
int r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf1, http_len1);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- result = 0;
goto end;
}
r = AppLayerParse(NULL, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2);
if (r != 0) {
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
- result = 0;
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
- if (!(PacketAlertCheck(p1, 1))) {
- printf("sid 1 didn't match on p1 but should have: ");
+ if ((PacketAlertCheck(p1, 1))) {
+ printf("sid 1 matched on chunk2 but should have: ");
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
- if (PacketAlertCheck(p2, 1)) {
- printf("sid 1 matched on p2 but shouldn't have: ");
+ if (!(PacketAlertCheck(p2, 1))) {
+ printf("sid 1 didn't match on p2 (chunk3) but should have: ");
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
- if (!(PacketAlertCheck(p1, 1))) {
- printf("sid 1 didn't match on p1 but should have: ");
+ if (PacketAlertCheck(p1, 1)) {
+ printf("sid 1 matched on p1 but should have: ");
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
- if (PacketAlertCheck(p2, 1)) {
- printf("sid 1 matched on p2 but shouldn't have: ");
+ if (!(PacketAlertCheck(p2, 1))) {
+ printf("sid 1 didn't match on p2 but should have: ");
goto end;
}
}
HtpBodyChunk *cur = htud->request_body.first;
- if (htud->request_body.nchunks == 0) {
+ if (htud->request_body.first == NULL) {
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
htud = (HtpTxUserData *) htp_tx_get_user_data(t2);
cur = htud->request_body.first;
- if (htud->request_body.nchunks == 0) {
+ if (htud->request_body.first == NULL) {
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1);
HtpBodyChunk *cur = htud->request_body.first;
- if (htud->request_body.nchunks == 0) {
+ if (htud->request_body.first == NULL) {
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
htud = (HtpTxUserData *) htp_tx_get_user_data(t2);
cur = htud->request_body.first;
- if (htud->request_body.nchunks == 0) {
+ if (htud->request_body.first == NULL) {
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
"%" PRIu32 ")", det_ctx->sgh, det_ctx->sgh->
mpm_uricontent_maxlen, det_ctx->sgh->sig_cnt);
- det_ctx->uris++;
-
- if (det_ctx->sgh->mpm_uricontent_maxlen == 1) det_ctx->pkts_uri_searched1++;
- else if (det_ctx->sgh->mpm_uricontent_maxlen == 2) det_ctx->pkts_uri_searched2++;
- else if (det_ctx->sgh->mpm_uricontent_maxlen == 3) det_ctx->pkts_uri_searched3++;
- else if (det_ctx->sgh->mpm_uricontent_maxlen == 4) det_ctx->pkts_uri_searched4++;
- else det_ctx->pkts_uri_searched++;
-
ret += UriPatternSearch(det_ctx, uri, uri_len, flags);
SCLogDebug("post search: cnt %" PRIu32, ret);
SCLogDebug("pcap_cnt %"PRIu64, p->pcap_cnt);
p->alerts.cnt = 0;
- det_ctx->pkts++;
det_ctx->filestore_cnt = 0;
/* No need to perform any detection on this packet, if the the given flag is set.*/
else
result &= 1;
- if (det_ctx->pkts_searched == 1)
- result &= 0;
-
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
ENGINE_SGH_MPM_FACTORY_CONTEXT_AUTO
};
+typedef struct HttpReassembledBody_ {
+ uint8_t *buffer;
+ uint32_t buffer_size; /**< size of the buffer itself */
+ uint32_t buffer_len; /**< data len in the buffer */
+ uint64_t offset; /**< data offset */
+} HttpReassembledBody;
+
#define DETECT_FILESTORE_MAX 15
/**
/* used by pcre match function alone */
uint32_t pcre_match_start_offset;
- uint8_t **hcbd_buffers;
- uint32_t *hcbd_buffers_len;
- uint16_t hcbd_buffers_list_len;
-
/* counter for the filestore array below -- up here for cache reasons. */
uint16_t filestore_cnt;
uint16_t hhd_buffers_list_len;
+
+ uint16_t hcbd_buffers_list_len;
uint16_t hsbd_buffers_list_len;
- uint8_t **hsbd_buffers;
- uint32_t *hsbd_buffers_len;
+
+ HttpReassembledBody *hsbd;
+ HttpReassembledBody *hcbd;
uint8_t **hhd_buffers;
uint32_t *hhd_buffers_len;
uint16_t discontinue_matching;
uint16_t flags;
+ /** ID of the transaction currently being inspected. */
+ uint16_t tx_id;
+
/* holds the current recursion depth on content inspection */
int inspection_recursion_counter;
PatternMatcherQueue pmq;
PatternMatcherQueue smsg_pmq[256];
- /** ID of the transaction currently being inspected. */
- uint16_t tx_id;
-
- /* counters */
- uint32_t pkts;
- uint32_t pkts_searched;
- uint32_t pkts_searched1;
- uint32_t pkts_searched2;
- uint32_t pkts_searched3;
- uint32_t pkts_searched4;
-
- uint32_t uris;
- uint32_t pkts_uri_searched;
- uint32_t pkts_uri_searched1;
- uint32_t pkts_uri_searched2;
- uint32_t pkts_uri_searched3;
- uint32_t pkts_uri_searched4;
-
/** ip only rules ctx */
DetectEngineIPOnlyThreadCtx io_ctx;