suricata
app-layer-htp-body.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2011 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 * \author Gurvinder Singh <gurvindersinghdahiya@gmail.com>
23 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
24 * \author Brian Rectanus <brectanu@gmail.com>
25 *
26 * This file provides a HTTP protocol support for the engine using HTP library.
27 */
28
29#include "suricata-common.h"
30#include "app-layer-htp.h"
31#include "app-layer-htp-mem.h"
32#include "app-layer-htp-body.h"
34#include "util-print.h"
35
37
38/**
39 * \brief Append a chunk of body to the HtpBody struct
40 *
41 * \param body pointer to the HtpBody holding the list
42 * \param data pointer to the data of the chunk
43 * \param len length of the chunk pointed by data
44 *
45 * \retval 0 ok
46 * \retval -1 error
47 */
48int HtpBodyAppendChunk(HtpBody *body, const uint8_t *data, uint32_t len)
49{
50 SCEnter();
51
52 HtpBodyChunk *bd = NULL;
53
54 if (len == 0 || data == NULL) {
55 SCReturnInt(0);
56 }
57
58 if (body->sb == NULL) {
60 if (body->sb == NULL)
61 SCReturnInt(-1);
62 }
63
64 /* New chunk */
65 bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk));
66 if (bd == NULL) {
67 SCReturnInt(-1);
68 }
69
70 if (StreamingBufferAppend(body->sb, &htp_sbcfg, &bd->sbseg, data, len) != 0) {
71 HTPFree(bd, sizeof(HtpBodyChunk));
72 SCReturnInt(-1);
73 }
74
75 if (body->first == NULL) {
76 body->first = body->last = bd;
77 } else {
78 body->last->next = bd;
79 body->last = bd;
80 }
81 body->content_len_so_far += len;
82
83 SCLogDebug("body %p", body);
84
85 SCReturnInt(0);
86}
87
88/**
89 * \brief Print the information and chunks of a Body
90 * \param body pointer to the HtpBody holding the list
91 * \retval none
92 */
93
94/**
95 * \brief Free the information held in the request body
96 * \param body pointer to the HtpBody holding the list
97 * \retval none
98 */
100{
101 SCEnter();
102
103 SCLogDebug("removing chunks of body %p", body);
104
105 HtpBodyChunk *cur = NULL;
106 HtpBodyChunk *prev = NULL;
107
108 prev = body->first;
109 while (prev != NULL) {
110 cur = prev->next;
111 HTPFree(prev, sizeof(HtpBodyChunk));
112 prev = cur;
113 }
114 body->first = body->last = NULL;
115
117}
118
119/**
120 * \brief Free request body chunks that are already fully parsed.
121 *
122 * \param state htp_state, with reference to our config
123 * \param body the body to prune
124 * \param direction STREAM_TOSERVER (request), STREAM_TOCLIENT (response)
125 *
126 * \retval none
127 */
128void HtpBodyPrune(HtpState *state, HtpBody *body, int direction)
129{
130 SCEnter();
131
132 if (body == NULL || body->first == NULL) {
133 SCReturn;
134 }
135
136 if (body->body_parsed == 0) {
137 SCReturn;
138 }
139
140 const HTPCfgDir *cfg =
141 (direction == STREAM_TOCLIENT) ? &state->cfg->response : &state->cfg->request;
142 uint32_t min_size = cfg->inspect_min_size;
143 uint32_t window = cfg->inspect_window;
144 uint64_t max_window = ((min_size > window) ? min_size : window);
145 uint64_t in_flight = body->content_len_so_far - body->body_inspected;
146
147 /* Special case. If body_inspected is not being updated, we make sure that
148 * we prune the body. We allow for some extra size/room as we may be called
149 * multiple times on uninspected body chunk additions if a large block of
150 * data was ack'd at once. Want to avoid pruning before inspection. */
151 if (in_flight > (max_window * 3)) {
152 body->body_inspected = body->content_len_so_far - max_window;
153 } else if (body->body_inspected < max_window) {
154 SCReturn;
155 }
156
157 uint64_t left_edge = body->body_inspected;
158 if (left_edge <= min_size || left_edge <= window)
159 left_edge = 0;
160 if (left_edge)
161 left_edge -= window;
162
163 if (left_edge) {
164 SCLogDebug("sliding body to offset %"PRIu64, left_edge);
165 StreamingBufferSlideToOffset(body->sb, &htp_sbcfg, left_edge);
166 }
167
168 SCLogDebug("pruning chunks of body %p", body);
169
170 HtpBodyChunk *cur = body->first;
171 while (cur != NULL) {
172 HtpBodyChunk *next = cur->next;
173 SCLogDebug("cur %p", cur);
174
175 if (!StreamingBufferSegmentIsBeforeWindow(body->sb, &cur->sbseg)) {
176 SCLogDebug("not removed");
177 break;
178 }
179
180 body->first = next;
181 if (body->last == cur) {
182 body->last = next;
183 }
184
185 HTPFree(cur, sizeof(HtpBodyChunk));
186
187 cur = next;
188 SCLogDebug("removed");
189 }
190
191 SCReturn;
192}
uint8_t len
void HtpBodyPrune(HtpState *state, HtpBody *body, int direction)
Free request body chunks that are already fully parsed.
int HtpBodyAppendChunk(HtpBody *body, const uint8_t *data, uint32_t len)
Append a chunk of body to the HtpBody struct.
void HtpBodyFree(HtpBody *body)
Print the information and chunks of a Body.
StreamingBufferConfig htp_sbcfg
void * HTPCalloc(size_t n, size_t size)
void HTPFree(void *ptr, size_t size)
struct HtpBodyChunk_ * next
uint32_t inspect_window
uint32_t inspect_min_size
HTPCfgDir request
HTPCfgDir response
StreamingBufferSegment sbseg
struct HtpBodyChunk_ * next
HtpBodyChunk * last
uint64_t content_len_so_far
HtpBodyChunk * first
uint64_t body_parsed
uint64_t body_inspected
StreamingBuffer * sb
const struct HTPCfgRec_ * cfg
#define SCEnter(...)
Definition util-debug.h:277
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCReturn
Definition util-debug.h:279
int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg, StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len)
StreamingBuffer * StreamingBufferInit(const StreamingBufferConfig *cfg)
void StreamingBufferSlideToOffset(StreamingBuffer *sb, const StreamingBufferConfig *cfg, uint64_t offset)
slide to absolute offset
void StreamingBufferFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg)
int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb, const StreamingBufferSegment *seg)