/** * \brief Append a chunk of body to the HtpBody struct * * \param body pointer to the HtpBody holding the list * \param data pointer to the data of the chunk * \param len length of the chunk pointed by data * * \retval 0 ok * \retval -1 error */ int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body, const uint8_t *data, uint32_t len) { SCEnter(); HtpBodyChunk *bd = NULL; if (len == 0 || data == NULL) { SCReturnInt(0); } if (body->sb == NULL) { const StreamingBufferConfig *cfg = hcfg ? &hcfg->sbcfg : &default_cfg; body->sb = StreamingBufferInit(cfg); if (body->sb == NULL) SCReturnInt(-1); } if (body->first == NULL) { /* New chunk */ bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); if (bd == NULL) { SCReturnInt(-1); } if (StreamingBufferAppend(body->sb, &bd->sbseg, data, len) != 0) { HTPFree(bd, sizeof(HtpBodyChunk)); SCReturnInt(-1); } body->first = body->last = bd; body->content_len_so_far = len; } else { bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); if (bd == NULL) { SCReturnInt(-1); } if (StreamingBufferAppend(body->sb, &bd->sbseg, data, len) != 0) { HTPFree(bd, sizeof(HtpBodyChunk)); SCReturnInt(-1); } body->last->next = bd; body->last = bd; body->content_len_so_far += len; } SCLogDebug("body %p", body); SCReturnInt(0); }
/** * \brief Free the information held in the request body * \param body pointer to the HtpBody holding the list * \retval none */ void HtpBodyFree(HtpBody *body) { SCEnter(); if (body->first == NULL) return; 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; prev = body->first; while (prev != NULL) { cur = prev->next; if (prev->data != NULL) HTPFree(prev->data, prev->len); HTPFree(prev, sizeof(HtpBodyChunk)); prev = cur; } body->first = body->last = NULL; }
/** * \brief Free the information held in the request body * \param body pointer to the HtpBody holding the list * \retval none */ void HtpBodyFree(HtpBody *body) { SCEnter(); SCLogDebug("removing chunks of body %p", body); HtpBodyChunk *cur = NULL; HtpBodyChunk *prev = NULL; prev = body->first; while (prev != NULL) { cur = prev->next; HTPFree(prev, sizeof(HtpBodyChunk)); prev = cur; } body->first = body->last = NULL; StreamingBufferFree(body->sb); }
/** * \brief Free request body chunks that are already fully parsed. * * \param state htp_state, with reference to our config * \param body the body to prune * \param direction STREAM_TOSERVER (request), STREAM_TOCLIENT (response) * * \retval none */ void HtpBodyPrune(HtpState *state, HtpBody *body, int direction) { SCEnter(); if (body == NULL || body->first == NULL) { SCReturn; } if (body->body_parsed == 0) { SCReturn; } /* get the configured inspect sizes. Default to response values */ uint32_t min_size = state->cfg->response.inspect_min_size; uint32_t window = state->cfg->response.inspect_window; if (direction == STREAM_TOSERVER) { min_size = state->cfg->request.inspect_min_size; window = state->cfg->request.inspect_window; } uint64_t max_window = ((min_size > window) ? min_size : window); uint64_t in_flight = body->content_len_so_far - body->body_inspected; /* Special case. If body_inspected is not being updated, we make sure that * we prune the body. We allow for some extra size/room as we may be called * multiple times on uninspected body chunk additions if a large block of * data was ack'd at once. Want to avoid pruning before inspection. */ if (in_flight > (max_window * 3)) { body->body_inspected = body->content_len_so_far - max_window; } else if (body->body_inspected < max_window) { SCReturn; } uint64_t left_edge = body->body_inspected; if (left_edge <= min_size || left_edge <= window) left_edge = 0; if (left_edge) left_edge -= window; if (left_edge) { SCLogDebug("sliding body to offset %"PRIu64, left_edge); StreamingBufferSlideToOffset(body->sb, left_edge); } SCLogDebug("pruning chunks of body %p", body); HtpBodyChunk *cur = body->first; while (cur != NULL) { HtpBodyChunk *next = cur->next; SCLogDebug("cur %p", cur); if (!StreamingBufferSegmentIsBeforeWindow(body->sb, &cur->sbseg)) { SCLogDebug("not removed"); break; } body->first = next; if (body->last == cur) { body->last = next; } HTPFree(cur, sizeof(HtpBodyChunk)); cur = next; SCLogDebug("removed"); } SCReturn; }
/** * \brief Append a chunk of body to the HtpBody struct * * \param body pointer to the HtpBody holding the list * \param data pointer to the data of the chunk * \param len length of the chunk pointed by data * * \retval 0 ok * \retval -1 error */ int HtpBodyAppendChunk(HtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32_t len) { SCEnter(); HtpBodyChunk *bd = NULL; if (len == 0 || data == NULL) { SCReturnInt(0); } if (body->first == NULL) { /* New chunk */ bd = (HtpBodyChunk *)HTPMalloc(sizeof(HtpBodyChunk)); if (bd == NULL) goto error; bd->len = len; bd->stream_offset = 0; bd->next = NULL; bd->logged = 0; bd->data = HTPMalloc(len); if (bd->data == NULL) { goto error; } memcpy(bd->data, data, len); body->first = body->last = bd; body->content_len_so_far = len; } else { bd = (HtpBodyChunk *)HTPMalloc(sizeof(HtpBodyChunk)); if (bd == NULL) goto error; bd->len = len; bd->stream_offset = body->content_len_so_far; bd->next = NULL; bd->logged = 0; bd->data = HTPMalloc(len); if (bd->data == NULL) { goto error; } memcpy(bd->data, data, len); body->last->next = bd; body->last = bd; body->content_len_so_far += len; } SCLogDebug("Body %p; data %p, len %"PRIu32, body, bd->data, (uint32_t)bd->len); SCReturnInt(0); error: if (bd != NULL) { if (bd->data != NULL) { HTPFree(bd->data, bd->len); } HTPFree(bd, sizeof(HtpBodyChunk)); } SCReturnInt(-1); }
/** * \brief Free request body chunks that are already fully parsed. * * \param state htp_state, with reference to our config * \param body the body to prune * \param direction STREAM_TOSERVER (request), STREAM_TOCLIENT (response) * * \retval none */ void HtpBodyPrune(HtpState *state, HtpBody *body, int direction) { SCEnter(); if (body == NULL || body->first == NULL) { SCReturn; } if (body->body_parsed == 0) { SCReturn; } /* get the configured inspect sizes. Default to response values */ uint32_t min_size = state->cfg->response_inspect_min_size; uint32_t window = state->cfg->response_inspect_window; if (direction == STREAM_TOSERVER) { min_size = state->cfg->request_inspect_min_size; window = state->cfg->request_inspect_window; } if (body->body_inspected < (min_size > window) ? min_size : window) { SCReturn; } 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) { HtpBodyChunk *next = cur->next; SCLogDebug("cur->stream_offset %"PRIu64" + cur->len %u = %"PRIu64", " "body->body_parsed %"PRIu64, cur->stream_offset, cur->len, cur->stream_offset + cur->len, body->body_parsed); uint64_t left_edge = body->body_inspected; if (left_edge <= min_size || left_edge <= window) left_edge = 0; if (left_edge) left_edge -= window; if (cur->stream_offset + cur->len > left_edge) { break; } body->first = next; if (body->last == cur) { body->last = next; } if (cur->data != NULL) { HTPFree(cur->data, cur->len); } HTPFree(cur, sizeof(HtpBodyChunk)); cur = next; } SCReturn; }