suricata
detect-http-raw-header.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2018 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  * \ingroup httplayer
20  *
21  * @{
22  */
23 
24 
25 /**
26  * \file
27  *
28  * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
29  *
30  * Implements support for http_raw_header keyword.
31  */
32 
33 #include "suricata-common.h"
34 #include "threads.h"
35 #include "decode.h"
36 
37 #include "detect.h"
38 #include "detect-parse.h"
39 #include "detect-engine.h"
40 #include "detect-engine-mpm.h"
42 #include "detect-content.h"
43 
44 #include "flow.h"
45 #include "flow-var.h"
46 #include "flow-util.h"
47 
48 #include "util-debug.h"
49 
50 #include "app-layer.h"
51 #include "app-layer-parser.h"
52 #include "app-layer-htp.h"
53 #include "detect-http-raw-header.h"
54 
55 static int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, const char *);
56 static int DetectHttpRawHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str);
57 #ifdef UNITTESTS
58 static void DetectHttpRawHeaderRegisterTests(void);
59 #endif
60 static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s, const char **sigerror);
61 static int g_http_raw_header_buffer_id = 0;
62 static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
63  const DetectEngineTransforms *transforms, Flow *_f,
64  const uint8_t flow_flags, void *txv, const int list_id);
65 
66 static int PrefilterMpmHttpHeaderRawRequestRegister(DetectEngineCtx *de_ctx,
67  SigGroupHead *sgh, MpmCtx *mpm_ctx,
68  const DetectMpmAppLayerRegistery *mpm_reg, int list_id);
69 static int PrefilterMpmHttpHeaderRawResponseRegister(DetectEngineCtx *de_ctx,
70  SigGroupHead *sgh, MpmCtx *mpm_ctx,
71  const DetectMpmAppLayerRegistery *mpm_reg, int list_id);
72 
73 /**
74  * \brief Registers the keyword handlers for the "http_raw_header" keyword.
75  */
77 {
78  /* http_raw_header content modifier */
79  sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].name = "http_raw_header";
80  sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetup;
81 #ifdef UNITTESTS
83 #endif
86 
87  /* http.header.raw sticky buffer */
88  sigmatch_table[DETECT_HTTP_RAW_HEADER].name = "http.header.raw";
89  sigmatch_table[DETECT_HTTP_RAW_HEADER].desc = "sticky buffer to match the raw HTTP header buffer";
90  sigmatch_table[DETECT_HTTP_RAW_HEADER].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-raw-header";
91  sigmatch_table[DETECT_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetupSticky;
94 
96  SIG_FLAG_TOSERVER, HTP_REQUEST_HEADERS+1,
99  SIG_FLAG_TOCLIENT, HTP_RESPONSE_HEADERS+1,
101 
102  DetectAppLayerMpmRegister2("http_raw_header", SIG_FLAG_TOSERVER, 2,
103  PrefilterMpmHttpHeaderRawRequestRegister, NULL, ALPROTO_HTTP,
104  0); /* progress handled in register */
105  DetectAppLayerMpmRegister2("http_raw_header", SIG_FLAG_TOCLIENT, 2,
106  PrefilterMpmHttpHeaderRawResponseRegister, NULL, ALPROTO_HTTP,
107  0); /* progress handled in register */
108 
109  DetectBufferTypeSetDescriptionByName("http_raw_header",
110  "raw http headers");
111 
113  DetectHttpRawHeaderValidateCallback);
114 
115  g_http_raw_header_buffer_id = DetectBufferTypeGetByName("http_raw_header");
116 }
117 
118 /**
119  * \brief The setup function for the http_raw_header keyword for a signature.
120  *
121  * \param de_ctx Pointer to the detection engine context.
122  * \param s Pointer to signature for the current Signature being parsed
123  * from the rules.
124  * \param m Pointer to the head of the SigMatchs for the current rule
125  * being parsed.
126  * \param arg Pointer to the string holding the keyword value.
127  *
128  * \retval 0 On success.
129  * \retval -1 On failure.
130  */
131 int DetectHttpRawHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
132 {
133  return DetectEngineContentModifierBufferSetup(de_ctx, s, arg,
135  g_http_raw_header_buffer_id,
136  ALPROTO_HTTP);
137 }
138 
139 /**
140  * \brief this function setup the http.header.raw keyword used in the rule
141  *
142  * \param de_ctx Pointer to the Detection Engine Context
143  * \param s Pointer to the Signature to which the current keyword belongs
144  * \param str Should hold an empty string always
145  *
146  * \retval 0 On success
147  */
148 static int DetectHttpRawHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
149 {
150  if (DetectBufferSetActiveList(s, g_http_raw_header_buffer_id) < 0)
151  return -1;
153  return -1;
154  return 0;
155 }
156 
157 static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s, const char **sigerror)
158 {
160  *sigerror = "http_raw_header signature "
161  "without a flow direction. Use flow:to_server for "
162  "inspecting request headers or flow:to_client for "
163  "inspecting response headers.";
164 
165  SCLogError(SC_ERR_INVALID_SIGNATURE, "%s", *sigerror);
167  }
168  return TRUE;
169 }
170 
171 static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
172  const DetectEngineTransforms *transforms, Flow *_f,
173  const uint8_t flow_flags, void *txv, const int list_id)
174 {
175  InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
176  if (buffer->inspect == NULL) {
177  htp_tx_t *tx = (htp_tx_t *)txv;
178 
179  HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
180  if (tx_ud == NULL)
181  return NULL;
182 
183  const bool ts = ((flow_flags & STREAM_TOSERVER) != 0);
184  const uint8_t *data = ts ?
186  if (data == NULL)
187  return NULL;
188  const uint8_t data_len = ts ?
190 
191  InspectionBufferSetup(buffer, data, data_len);
192  InspectionBufferApplyTransforms(buffer, transforms);
193  }
194 
195  return buffer;
196 }
197 
199  int list_id;
200  const MpmCtx *mpm_ctx;
203 
204 /** \brief Generic Mpm prefilter callback
205  *
206  * \param det_ctx detection engine thread ctx
207  * \param p packet to inspect
208  * \param f flow to inspect
209  * \param txv tx to inspect
210  * \param pectx inspection context
211  */
212 static void PrefilterMpmHttpHeaderRaw(DetectEngineThreadCtx *det_ctx,
213  const void *pectx,
214  Packet *p, Flow *f, void *txv,
215  const uint64_t idx, const uint8_t flags)
216 {
217  SCEnter();
218 
219  const PrefilterMpmHttpHeaderRawCtx *ctx = pectx;
220  const MpmCtx *mpm_ctx = ctx->mpm_ctx;
221  SCLogDebug("running on list %d", ctx->list_id);
222 
223  const int list_id = ctx->list_id;
224 
225  InspectionBuffer *buffer = GetData(det_ctx, ctx->transforms, f,
226  flags, txv, list_id);
227  if (buffer == NULL)
228  return;
229 
230  const uint32_t data_len = buffer->inspect_len;
231  const uint8_t *data = buffer->inspect;
232 
233  SCLogDebug("mpm'ing buffer:");
234  //PrintRawDataFp(stdout, data, data_len);
235 
236  if (data != NULL && data_len >= mpm_ctx->minlen) {
237  (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx,
238  &det_ctx->mtcu, &det_ctx->pmq, data, data_len);
239  }
240 }
241 
242 static void PrefilterMpmHttpTrailerRaw(DetectEngineThreadCtx *det_ctx,
243  const void *pectx,
244  Packet *p, Flow *f, void *txv,
245  const uint64_t idx, const uint8_t flags)
246 {
247  SCEnter();
248 
249  htp_tx_t *tx = txv;
250  const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx);
251  /* if the request wasn't flagged as having a trailer, we skip */
252  if (htud && (
253  ((flags & STREAM_TOSERVER) && !htud->request_has_trailers) ||
254  ((flags & STREAM_TOCLIENT) && !htud->response_has_trailers))) {
255  SCReturn;
256  }
257  PrefilterMpmHttpHeaderRaw(det_ctx, pectx, p, f, txv, idx, flags);
258  SCReturn;
259 }
260 
261 static void PrefilterMpmHttpHeaderRawFree(void *ptr)
262 {
263  SCFree(ptr);
264 }
265 
266 static int PrefilterMpmHttpHeaderRawRequestRegister(DetectEngineCtx *de_ctx,
267  SigGroupHead *sgh, MpmCtx *mpm_ctx,
268  const DetectMpmAppLayerRegistery *mpm_reg, int list_id)
269 {
270  SCEnter();
271 
272  /* header */
273  PrefilterMpmHttpHeaderRawCtx *pectx = SCCalloc(1, sizeof(*pectx));
274  if (pectx == NULL)
275  return -1;
276  pectx->list_id = list_id;
277  pectx->mpm_ctx = mpm_ctx;
278  pectx->transforms = &mpm_reg->v2.transforms;
279 
280  int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeaderRaw,
281  mpm_reg->v2.alproto, HTP_REQUEST_HEADERS+1,
282  pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
283  if (r != 0) {
284  SCFree(pectx);
285  return r;
286  }
287 
288  /* trailer */
289  pectx = SCCalloc(1, sizeof(*pectx));
290  if (pectx == NULL)
291  return -1;
292  pectx->list_id = list_id;
293  pectx->mpm_ctx = mpm_ctx;
294  pectx->transforms = &mpm_reg->v2.transforms;
295 
296  r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailerRaw,
297  mpm_reg->v2.alproto, HTP_REQUEST_TRAILER+1,
298  pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
299  if (r != 0) {
300  SCFree(pectx);
301  }
302  return r;
303 }
304 
305 static int PrefilterMpmHttpHeaderRawResponseRegister(DetectEngineCtx *de_ctx,
306  SigGroupHead *sgh, MpmCtx *mpm_ctx,
307  const DetectMpmAppLayerRegistery *mpm_reg, int list_id)
308 {
309  SCEnter();
310 
311  /* header */
312  PrefilterMpmHttpHeaderRawCtx *pectx = SCCalloc(1, sizeof(*pectx));
313  if (pectx == NULL)
314  return -1;
315  pectx->list_id = list_id;
316  pectx->mpm_ctx = mpm_ctx;
317  pectx->transforms = &mpm_reg->v2.transforms;
318 
319  int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeaderRaw,
320  mpm_reg->v2.alproto, HTP_RESPONSE_HEADERS,
321  pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
322  if (r != 0) {
323  SCFree(pectx);
324  return r;
325  }
326 
327  /* trailer */
328  pectx = SCCalloc(1, sizeof(*pectx));
329  if (pectx == NULL)
330  return -1;
331  pectx->list_id = list_id;
332  pectx->mpm_ctx = mpm_ctx;
333  pectx->transforms = &mpm_reg->v2.transforms;
334 
335  r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailerRaw,
336  mpm_reg->v2.alproto, HTP_RESPONSE_TRAILER,
337  pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
338  if (r != 0) {
339  SCFree(pectx);
340  }
341  return r;
342 }
343 
344 /************************************Unittests*********************************/
345 
346 #ifdef UNITTESTS
348 #endif
349 
350 /**
351  * @}
352  */
void DetectHttpRawHeaderRegister(void)
Registers the keyword handlers for the "http_raw_header" keyword.
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1403
uint32_t request_headers_raw_len
uint16_t flags
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1146
#define SCLogDebug(...)
Definition: util-debug.h:335
int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
uint16_t minlen
Definition: util-mpm.h:95
uint32_t flags
Definition: detect.h:493
#define FALSE
const DetectEngineTransforms * transforms
one time registration of keywords at start up
Definition: detect.h:567
Handle HTTP raw header match.
Container for matching data for a signature group.
Definition: detect.h:1295
InspectionBuffer * InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id)
const char * name
Definition: detect.h:1160
Signature container.
Definition: detect.h:492
#define TRUE
uint8_t response_has_trailers
uint8_t * request_headers_raw
main detection engine ctx
Definition: detect.h:720
int DetectBufferTypeGetByName(const char *name)
#define str(s)
#define SCCalloc(nm, a)
Definition: util-mem.h:205
#define SIG_FLAG_TOCLIENT
Definition: detect.h:244
#define SIGMATCH_INFO_STICKY_BUFFER
Definition: detect.h:1352
uint16_t mpm_type
Definition: util-mpm.h:84
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
#define SIG_FLAG_TOSERVER
Definition: detect.h:243
#define SCEnter(...)
Definition: util-debug.h:337
void DetectAppLayerInspectEngineRegister2(const char *name, AppProto alproto, uint32_t dir, int progress, InspectEngineFuncPtr2 Callback2, InspectionBufferGetDataPtr GetData)
register inspect engine at start up time
PrefilterRuleStore pmq
Definition: detect.h:1061
uint16_t alternative
Definition: detect.h:1158
#define STREAM_TOCLIENT
Definition: stream.h:32
int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg, int sm_type, int sm_list, AppProto alproto)
Definition: detect-parse.c:143
int DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
#define SCReturnInt(x)
Definition: util-debug.h:341
const char * desc
Definition: detect.h:1162
uint8_t request_has_trailers
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.h:165
#define SCFree(a)
Definition: util-mem.h:236
DetectEngineTransforms transforms
Definition: detect.h:585
void InspectionBufferSetup(InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
setup the buffer with our initial data
MpmThreadCtx mtcu
Definition: detect.h:1059
uint8_t * response_headers_raw
void InspectionBufferApplyTransforms(InspectionBuffer *buffer, const DetectEngineTransforms *transforms)
uint64_t ts
#define SIGMATCH_NOOPT
Definition: detect.h:1328
struct DetectMpmAppLayerRegistery_::@101 v2
const char * url
Definition: detect.h:1163
void DetectHttpRawHeaderRegisterTests(void)
#define STREAM_TOSERVER
Definition: stream.h:31
struct PrefilterMpmHttpHeaderRawCtx PrefilterMpmHttpHeaderRawCtx
uint32_t inspect_len
Definition: detect.h:350
int DetectBufferSetActiveList(Signature *s, const int list)
const uint8_t * inspect
Definition: detect.h:349
#define DOC_URL
Definition: suricata.h:86
void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc)
uint32_t response_headers_raw_len
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:158
#define SCReturn
Definition: util-debug.h:339
int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, void(*PrefilterTxFunc)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f, void *tx, const uint64_t idx, const uint8_t flags), AppProto alproto, int tx_min_progress, void *pectx, void(*FreeFunc)(void *pectx), const char *name)
void DetectBufferTypeRegisterValidateCallback(const char *name, _Bool(*ValidateCallback)(const Signature *, const char **sigerror))
#define DOC_VERSION
Definition: suricata.h:91
uint16_t flags
Definition: detect.h:1154
Flow data structure.
Definition: flow.h:327
void(* RegisterTests)(void)
Definition: detect.h:1152
void DetectAppLayerMpmRegister2(const char *name, int direction, int priority, int(*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectMpmAppLayerRegistery *mpm_reg, int list_id), InspectionBufferGetDataPtr GetData, AppProto alproto, int tx_min_progress)
register a MPM engine