suricata
detect-http-raw-header.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2022 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"
41#include "detect-engine-mpm.h"
43#include "detect-content.h"
44
45#include "flow.h"
46#include "flow-var.h"
47#include "flow-util.h"
48
49#include "util-debug.h"
50#include "util-profiling.h"
51
52#include "app-layer.h"
53#include "app-layer-parser.h"
54#include "app-layer-htp.h"
56
57static int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, const char *);
58static int DetectHttpRawHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str);
59#ifdef UNITTESTS
60static void DetectHttpRawHeaderRegisterTests(void);
61#endif
62static bool DetectHttpRawHeaderValidateCallback(
63 const Signature *s, const char **sigerror, const DetectBufferType *dbt);
64static int g_http_raw_header_buffer_id = 0;
65static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
66 const DetectEngineTransforms *transforms, Flow *_f,
67 const uint8_t flow_flags, void *txv, const int list_id);
68static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx,
69 const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv,
70 const int list_id);
71
72static int PrefilterMpmHttpHeaderRawRequestRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
73 MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id);
74static int PrefilterMpmHttpHeaderRawResponseRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
75 MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id);
76
77/**
78 * \brief Registers the keyword handlers for the "http_raw_header" keyword.
79 */
81{
82 /* http_raw_header content modifier */
85 "content modifier to match the raw HTTP header buffer";
87 "/rules/http-keywords.html#http-header-and-http-raw-header";
88 sigmatch_table[DETECT_HTTP_RAW_HEADER_CM].Setup = DetectHttpRawHeaderSetup;
89#ifdef UNITTESTS
91#endif
95
96 /* http.header.raw sticky buffer */
97 sigmatch_table[DETECT_HTTP_RAW_HEADER].name = "http.header.raw";
98 sigmatch_table[DETECT_HTTP_RAW_HEADER].desc = "sticky buffer to match the raw HTTP header buffer";
99 sigmatch_table[DETECT_HTTP_RAW_HEADER].url = "/rules/http-keywords.html#http-header-and-http-raw-header";
100 sigmatch_table[DETECT_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetupSticky;
102
104 HTP_REQUEST_PROGRESS_HEADERS + 1, DetectEngineInspectBufferGeneric, GetData);
106 HTP_RESPONSE_PROGRESS_HEADERS + 1, DetectEngineInspectBufferGeneric, GetData);
107
108 DetectAppLayerMpmRegister("http_raw_header", SIG_FLAG_TOSERVER, 2,
109 PrefilterMpmHttpHeaderRawRequestRegister, NULL, ALPROTO_HTTP1,
110 0); /* progress handled in register */
111 DetectAppLayerMpmRegister("http_raw_header", SIG_FLAG_TOCLIENT, 2,
112 PrefilterMpmHttpHeaderRawResponseRegister, NULL, ALPROTO_HTTP1,
113 0); /* progress handled in register */
114
116 HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2);
118 HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetData2);
119
121 GetData2, ALPROTO_HTTP2, HTTP2StateDataClient);
123 GetData2, ALPROTO_HTTP2, HTTP2StateDataServer);
124
125 DetectBufferTypeSetDescriptionByName("http_raw_header",
126 "raw http headers");
127
129 DetectHttpRawHeaderValidateCallback);
130
131 g_http_raw_header_buffer_id = DetectBufferTypeGetByName("http_raw_header");
132}
133
134/**
135 * \brief The setup function for the http_raw_header keyword for a signature.
136 *
137 * \param de_ctx Pointer to the detection engine context.
138 * \param s Pointer to signature for the current Signature being parsed
139 * from the rules.
140 * \param m Pointer to the head of the SigMatchs for the current rule
141 * being parsed.
142 * \param arg Pointer to the string holding the keyword value.
143 *
144 * \retval 0 On success.
145 * \retval -1 On failure.
146 */
147int DetectHttpRawHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
148{
150 de_ctx, s, arg, DETECT_HTTP_RAW_HEADER_CM, g_http_raw_header_buffer_id, ALPROTO_HTTP1);
151}
152
153/**
154 * \brief this function setup the http.header.raw keyword used in the rule
155 *
156 * \param de_ctx Pointer to the Detection Engine Context
157 * \param s Pointer to the Signature to which the current keyword belongs
158 * \param str Should hold an empty string always
159 *
160 * \retval 0 On success
161 */
162static int DetectHttpRawHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
163{
164 if (SCDetectBufferSetActiveList(de_ctx, s, g_http_raw_header_buffer_id) < 0)
165 return -1;
167 return -1;
168 return 0;
169}
170
171static bool DetectHttpRawHeaderValidateCallback(
172 const Signature *s, const char **sigerror, const DetectBufferType *dbt)
173{
175 *sigerror = "http_raw_header signature "
176 "without a flow direction. Use flow:to_server for "
177 "inspecting request headers or flow:to_client for "
178 "inspecting response headers.";
179
180 SCLogError("%s", *sigerror);
181 SCReturnInt(false);
182 }
183 return true;
184}
185
186static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
187 const DetectEngineTransforms *transforms, Flow *_f,
188 const uint8_t flow_flags, void *txv, const int list_id)
189{
190 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
191 if (buffer->inspect == NULL) {
192 htp_tx_t *tx = (htp_tx_t *)txv;
193
194 HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
195
196 const bool ts = ((flow_flags & STREAM_TOSERVER) != 0);
197 const uint8_t *data = ts ?
199 if (data == NULL)
200 return NULL;
201 const uint32_t data_len = ts ?
203
205 det_ctx, list_id, buffer, data, data_len, transforms);
206 }
207
208 return buffer;
209}
210
211static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx,
212 const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv,
213 const int list_id)
214{
215 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
216 if (buffer->inspect == NULL) {
217 uint32_t b_len = 0;
218 const uint8_t *b = NULL;
219
220 if (SCHttp2TxGetHeadersRaw(txv, flow_flags, &b, &b_len) != 1)
221 return NULL;
222 if (b == NULL || b_len == 0)
223 return NULL;
224
225 InspectionBufferSetupAndApplyTransforms(det_ctx, list_id, buffer, b, b_len, transforms);
226 }
227
228 return buffer;
229}
230
236
237/** \brief Generic Mpm prefilter callback
238 *
239 * \param det_ctx detection engine thread ctx
240 * \param p packet to inspect
241 * \param f flow to inspect
242 * \param txv tx to inspect
243 * \param pectx inspection context
244 */
245static void PrefilterMpmHttpHeaderRaw(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p,
246 Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags)
247{
248 SCEnter();
249
250 const PrefilterMpmHttpHeaderRawCtx *ctx = pectx;
251 const MpmCtx *mpm_ctx = ctx->mpm_ctx;
252 SCLogDebug("running on list %d", ctx->list_id);
253
254 const int list_id = ctx->list_id;
255
256 InspectionBuffer *buffer = GetData(det_ctx, ctx->transforms, f,
257 flags, txv, list_id);
258 if (buffer == NULL)
259 return;
260
261 const uint32_t data_len = buffer->inspect_len;
262 const uint8_t *data = buffer->inspect;
263
264 SCLogDebug("mpm'ing buffer:");
265 //PrintRawDataFp(stdout, data, data_len);
266
267 if (data != NULL && data_len >= mpm_ctx->minlen) {
268 (void)mpm_table[mpm_ctx->mpm_type].Search(
269 mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, data, data_len);
270 PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len);
271 }
272}
273
274static void PrefilterMpmHttpTrailerRaw(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p,
275 Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags)
276{
277 SCEnter();
278
279 htp_tx_t *tx = txv;
280 const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx);
281 /* if the request wasn't flagged as having a trailer, we skip */
282 if (((flags & STREAM_TOSERVER) && !htud->request_has_trailers) ||
283 ((flags & STREAM_TOCLIENT) && !htud->response_has_trailers)) {
284 SCReturn;
285 }
286 PrefilterMpmHttpHeaderRaw(det_ctx, pectx, p, f, txv, idx, _txd, flags);
287 SCReturn;
288}
289
290static void PrefilterMpmHttpHeaderRawFree(void *ptr)
291{
292 SCFree(ptr);
293}
294
295static int PrefilterMpmHttpHeaderRawRequestRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
296 MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
297{
298 SCEnter();
299
300 /* header */
301 PrefilterMpmHttpHeaderRawCtx *pectx = SCCalloc(1, sizeof(*pectx));
302 if (pectx == NULL)
303 return -1;
304 pectx->list_id = list_id;
305 pectx->mpm_ctx = mpm_ctx;
306 pectx->transforms = &mpm_reg->transforms;
307
308 int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeaderRaw, mpm_reg->app_v2.alproto,
309 HTP_REQUEST_PROGRESS_HEADERS + 1, pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
310 if (r != 0) {
311 SCFree(pectx);
312 return r;
313 }
314
315 /* trailer */
316 pectx = SCCalloc(1, sizeof(*pectx));
317 if (pectx == NULL)
318 return -1;
319 pectx->list_id = list_id;
320 pectx->mpm_ctx = mpm_ctx;
321 pectx->transforms = &mpm_reg->transforms;
322
323 r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailerRaw, mpm_reg->app_v2.alproto,
324 HTP_REQUEST_PROGRESS_TRAILER + 1, pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
325 if (r != 0) {
326 SCFree(pectx);
327 }
328 return r;
329}
330
331static int PrefilterMpmHttpHeaderRawResponseRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
332 MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
333{
334 SCEnter();
335
336 /* header */
337 PrefilterMpmHttpHeaderRawCtx *pectx = SCCalloc(1, sizeof(*pectx));
338 if (pectx == NULL)
339 return -1;
340 pectx->list_id = list_id;
341 pectx->mpm_ctx = mpm_ctx;
342 pectx->transforms = &mpm_reg->transforms;
343
344 int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeaderRaw, mpm_reg->app_v2.alproto,
345 HTP_RESPONSE_PROGRESS_HEADERS, pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
346 if (r != 0) {
347 SCFree(pectx);
348 return r;
349 }
350
351 /* trailer */
352 pectx = SCCalloc(1, sizeof(*pectx));
353 if (pectx == NULL)
354 return -1;
355 pectx->list_id = list_id;
356 pectx->mpm_ctx = mpm_ctx;
357 pectx->transforms = &mpm_reg->transforms;
358
359 r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailerRaw, mpm_reg->app_v2.alproto,
360 HTP_RESPONSE_PROGRESS_TRAILER, pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
361 if (r != 0) {
362 SCFree(pectx);
363 }
364 return r;
365}
366
367/************************************Unittests*********************************/
368
369#ifdef UNITTESTS
371#endif
372
373/**
374 * @}
375 */
struct AppLayerTxData AppLayerTxData
@ ALPROTO_HTTP2
@ ALPROTO_HTTP
@ ALPROTO_HTTP1
uint8_t flags
Definition decode-gre.h:0
int SCDetectBufferSetActiveList(DetectEngineCtx *de_ctx, Signature *s, const int list)
void InspectionBufferSetupAndApplyTransforms(DetectEngineThreadCtx *det_ctx, const int list_id, InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len, const DetectEngineTransforms *transforms)
setup the buffer with our initial data
InspectionBuffer * InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id)
void DetectAppLayerMpmRegister(const char *name, int direction, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionBufferGetDataPtr GetData, AppProto alproto, int tx_min_progress)
register an app layer keyword for mpm
int PrefilterGenericMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterTxFn PrefilterTxFunc, AppProto alproto, int tx_min_progress, void *pectx, void(*FreeFunc)(void *pectx), const char *name)
@ DETECT_HTTP_RAW_HEADER
@ DETECT_HTTP_RAW_HEADER_CM
void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc)
uint8_t 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.
void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uint32_t dir, int progress, InspectEngineFuncPtr Callback, InspectionBufferGetDataPtr GetData)
Registers an app inspection engine.
void DetectBufferTypeRegisterValidateCallback(const char *name, bool(*ValidateCallback)(const Signature *, const char **sigerror, const DetectBufferType *))
int DetectBufferTypeGetByName(const char *name)
void DetectHttpRawHeaderRegister(void)
Registers the keyword handlers for the "http_raw_header" keyword.
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg, int sm_type, int sm_list, AppProto alproto)
SigTableElmt * sigmatch_table
#define SIGMATCH_NOOPT
Definition detect.h:1651
#define SIG_FLAG_TOCLIENT
Definition detect.h:272
#define SIGMATCH_INFO_STICKY_BUFFER
Definition detect.h:1676
#define SIG_FLAG_TOSERVER
Definition detect.h:271
#define SIGMATCH_INFO_CONTENT_MODIFIER
Definition detect.h:1674
DetectEngineCtx * de_ctx
struct Thresholds ctx
uint64_t ts
one time registration of keywords at start up
Definition detect.h:762
DetectEngineTransforms transforms
Definition detect.h:775
struct DetectBufferMpmRegistry_::@98::@100 app_v2
main detection engine ctx
Definition detect.h:932
MpmThreadCtx mtc
Definition detect.h:1345
PrefilterRuleStore pmq
Definition detect.h:1349
Flow data structure.
Definition flow.h:356
uint32_t request_headers_raw_len
uint8_t request_has_trailers
uint8_t * request_headers_raw
uint8_t * response_headers_raw
uint8_t response_has_trailers
uint32_t response_headers_raw_len
uint8_t mpm_type
Definition util-mpm.h:95
uint16_t minlen
Definition util-mpm.h:104
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition util-mpm.h:178
const DetectEngineTransforms * transforms
Container for matching data for a signature group.
Definition detect.h:1629
const char * url
Definition detect.h:1462
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
uint16_t alternative
Definition detect.h:1457
uint16_t flags
Definition detect.h:1450
const char * desc
Definition detect.h:1461
void(* RegisterTests)(void)
Definition detect.h:1448
const char * name
Definition detect.h:1459
Signature container.
Definition detect.h:668
uint32_t flags
Definition detect.h:669
#define str(s)
Handle HTTP raw header match.
void DetectHttpRawHeaderRegisterTests(void)
#define SCEnter(...)
Definition util-debug.h:277
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCReturn
Definition util-debug.h:279
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition util-mpm.c:47
#define PREFILTER_PROFILING_ADD_BYTES(det_ctx, bytes)