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.h"
30 #include "suricata-common.h"
31 #include "debug.h"
32 #include "decode.h"
33 #include "threads.h"
34 
35 #include "util-print.h"
36 #include "util-pool.h"
37 #include "util-radix-tree.h"
38 
39 #include "stream-tcp-private.h"
40 #include "stream-tcp-reassemble.h"
41 #include "stream-tcp.h"
42 #include "stream.h"
43 
44 #include "app-layer-protos.h"
45 #include "app-layer-parser.h"
46 #include "app-layer-htp.h"
47 #include "app-layer-htp-body.h"
48 
49 #include "util-spm.h"
50 #include "util-debug.h"
51 #include "app-layer-htp-file.h"
52 #include "util-time.h"
53 
54 #include "util-unittest.h"
55 #include "util-unittest-helper.h"
56 #include "flow-util.h"
57 
58 #include "detect-engine.h"
59 #include "detect-engine-state.h"
60 #include "detect-parse.h"
61 
62 #include "conf.h"
63 
64 #include "util-memcmp.h"
65 
66 static StreamingBufferConfig default_cfg = {
67  0, 0, 3072, HTPMalloc, HTPCalloc, HTPRealloc, HTPFree };
68 
69 /**
70  * \brief Append a chunk of body to the HtpBody struct
71  *
72  * \param body pointer to the HtpBody holding the list
73  * \param data pointer to the data of the chunk
74  * \param len length of the chunk pointed by data
75  *
76  * \retval 0 ok
77  * \retval -1 error
78  */
79 int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body,
80  const uint8_t *data, uint32_t len)
81 {
82  SCEnter();
83 
84  HtpBodyChunk *bd = NULL;
85 
86  if (len == 0 || data == NULL) {
87  SCReturnInt(0);
88  }
89 
90  if (body->sb == NULL) {
91  const StreamingBufferConfig *cfg = hcfg ? &hcfg->sbcfg : &default_cfg;
92  body->sb = StreamingBufferInit(cfg);
93  if (body->sb == NULL)
94  SCReturnInt(-1);
95  }
96 
97  /* New chunk */
98  bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk));
99  if (bd == NULL) {
100  SCReturnInt(-1);
101  }
102 
103  if (StreamingBufferAppend(body->sb, &bd->sbseg, data, len) != 0) {
104  HTPFree(bd, sizeof(HtpBodyChunk));
105  SCReturnInt(-1);
106  }
107 
108  if (body->first == NULL) {
109  body->first = body->last = bd;
110  } else {
111  body->last->next = bd;
112  body->last = bd;
113  }
114  body->content_len_so_far += len;
115 
116  SCLogDebug("body %p", body);
117 
118  SCReturnInt(0);
119 }
120 
121 /**
122  * \brief Print the information and chunks of a Body
123  * \param body pointer to the HtpBody holding the list
124  * \retval none
125  */
127 {
128  if (SCLogDebugEnabled()||1) {
129  SCEnter();
130 
131  if (body->first == NULL)
132  return;
133 
134  HtpBodyChunk *cur = NULL;
135  SCLogDebug("--- Start body chunks at %p ---", body);
136  printf("--- Start body chunks at %p ---\n", body);
137  for (cur = body->first; cur != NULL; cur = cur->next) {
138  const uint8_t *data = NULL;
139  uint32_t data_len = 0;
140  StreamingBufferSegmentGetData(body->sb, &cur->sbseg, &data, &data_len);
141  SCLogDebug("Body %p; data %p, len %"PRIu32, body, data, data_len);
142  printf("Body %p; data %p, len %"PRIu32"\n", body, data, data_len);
143  PrintRawDataFp(stdout, data, data_len);
144  }
145  SCLogDebug("--- End body chunks at %p ---", body);
146  }
147 }
148 
149 /**
150  * \brief Free the information held in the request body
151  * \param body pointer to the HtpBody holding the list
152  * \retval none
153  */
154 void HtpBodyFree(HtpBody *body)
155 {
156  SCEnter();
157 
158  SCLogDebug("removing chunks of body %p", body);
159 
160  HtpBodyChunk *cur = NULL;
161  HtpBodyChunk *prev = NULL;
162 
163  prev = body->first;
164  while (prev != NULL) {
165  cur = prev->next;
166  HTPFree(prev, sizeof(HtpBodyChunk));
167  prev = cur;
168  }
169  body->first = body->last = NULL;
170 
171  StreamingBufferFree(body->sb);
172 }
173 
174 /**
175  * \brief Free request body chunks that are already fully parsed.
176  *
177  * \param state htp_state, with reference to our config
178  * \param body the body to prune
179  * \param direction STREAM_TOSERVER (request), STREAM_TOCLIENT (response)
180  *
181  * \retval none
182  */
183 void HtpBodyPrune(HtpState *state, HtpBody *body, int direction)
184 {
185  SCEnter();
186 
187  if (body == NULL || body->first == NULL) {
188  SCReturn;
189  }
190 
191  if (body->body_parsed == 0) {
192  SCReturn;
193  }
194 
195  /* get the configured inspect sizes. Default to response values */
196  uint32_t min_size = state->cfg->response.inspect_min_size;
197  uint32_t window = state->cfg->response.inspect_window;
198 
199  if (direction == STREAM_TOSERVER) {
200  min_size = state->cfg->request.inspect_min_size;
201  window = state->cfg->request.inspect_window;
202  }
203 
204  uint64_t max_window = ((min_size > window) ? min_size : window);
205  uint64_t in_flight = body->content_len_so_far - body->body_inspected;
206 
207  /* Special case. If body_inspected is not being updated, we make sure that
208  * we prune the body. We allow for some extra size/room as we may be called
209  * multiple times on uninspected body chunk additions if a large block of
210  * data was ack'd at once. Want to avoid pruning before inspection. */
211  if (in_flight > (max_window * 3)) {
212  body->body_inspected = body->content_len_so_far - max_window;
213  } else if (body->body_inspected < max_window) {
214  SCReturn;
215  }
216 
217  uint64_t left_edge = body->body_inspected;
218  if (left_edge <= min_size || left_edge <= window)
219  left_edge = 0;
220  if (left_edge)
221  left_edge -= window;
222 
223  if (left_edge) {
224  SCLogDebug("sliding body to offset %"PRIu64, left_edge);
225  StreamingBufferSlideToOffset(body->sb, left_edge);
226  }
227 
228  SCLogDebug("pruning chunks of body %p", body);
229 
230  HtpBodyChunk *cur = body->first;
231  while (cur != NULL) {
232  HtpBodyChunk *next = cur->next;
233  SCLogDebug("cur %p", cur);
234 
235  if (!StreamingBufferSegmentIsBeforeWindow(body->sb, &cur->sbseg)) {
236  SCLogDebug("not removed");
237  break;
238  }
239 
240  body->first = next;
241  if (body->last == cur) {
242  body->last = next;
243  }
244 
245  HTPFree(cur, sizeof(HtpBodyChunk));
246 
247  cur = next;
248  SCLogDebug("removed");
249  }
250 
251  SCReturn;
252 }
#define SCLogDebug(...)
Definition: util-debug.h:335
void HtpBodyFree(HtpBody *body)
Free the information held in the request body.
StreamingBuffer * StreamingBufferInit(const StreamingBufferConfig *cfg)
struct HtpBodyChunk_ * next
uint32_t inspect_window
struct HtpBodyChunk_ * next
HTPCfgDir response
const struct HTPCfgRec_ * cfg
uint32_t inspect_min_size
void * HTPCalloc(size_t n, size_t size)
StreamingBufferSegment sbseg
void HtpBodyPrune(HtpState *state, HtpBody *body, int direction)
Free request body chunks that are already fully parsed.
void * HTPRealloc(void *ptr, size_t orig_size, size_t size)
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition: util-debug.c:631
void StreamingBufferFree(StreamingBuffer *sb)
int StreamingBufferAppend(StreamingBuffer *sb, StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len)
HTPCfgDir request
uint64_t body_inspected
Data structures and function prototypes for keeping state for the detection engine.
void StreamingBufferSlideToOffset(StreamingBuffer *sb, uint64_t offset)
slide to absolute offset
StreamingBuffer * sb
#define SCEnter(...)
Definition: util-debug.h:337
HtpBodyChunk * last
#define SCReturnInt(x)
Definition: util-debug.h:341
void StreamingBufferSegmentGetData(const StreamingBuffer *sb, const StreamingBufferSegment *seg, const uint8_t **data, uint32_t *data_len)
void HTPFree(void *ptr, size_t size)
StreamingBufferConfig sbcfg
void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen)
Definition: util-print.c:141
uint64_t content_len_so_far
int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb, const StreamingBufferSegment *seg)
int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body, const uint8_t *data, uint32_t len)
Append a chunk of body to the HtpBody struct.
uint64_t body_parsed
#define STREAM_TOSERVER
Definition: stream.h:31
void * HTPMalloc(size_t size)
void HtpBodyPrint(HtpBody *body)
Print the information and chunks of a Body.
HtpBodyChunk * first
#define SCReturn
Definition: util-debug.h:339
uint8_t len