• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.33
/src/detect-http-raw-header.c
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"
40
#include "detect-engine-buffer.h"
41
#include "detect-engine-mpm.h"
42
#include "detect-engine-prefilter.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"
55
#include "detect-http-raw-header.h"
56

57
static int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, const char *);
58
static int DetectHttpRawHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str);
59
#ifdef UNITTESTS
60
static void DetectHttpRawHeaderRegisterTests(void);
61
#endif
62
static bool DetectHttpRawHeaderValidateCallback(
63
        const Signature *s, const char **sigerror, const DetectBufferType *dbt);
64
static int g_http_raw_header_buffer_id = 0;
65
static int g_http2_thread_id = 0;
66

67
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
68
        const DetectEngineTransforms *transforms, Flow *_f,
69
        const uint8_t flow_flags, void *txv, const int list_id);
70
static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx,
71
        const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv,
72
        const int list_id);
73

74
static int PrefilterMpmHttpHeaderRawRequestRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
75
        MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id);
76
static int PrefilterMpmHttpHeaderRawResponseRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
77
        MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id);
78

79
/**
80
 * \brief Registers the keyword handlers for the "http_raw_header" keyword.
81
 */
82
void DetectHttpRawHeaderRegister(void)
83
{
3✔
84
    /* http_raw_header content modifier */
85
    sigmatch_table[DETECT_HTTP_RAW_HEADER_CM].name = "http_raw_header";
3✔
86
    sigmatch_table[DETECT_HTTP_RAW_HEADER_CM].desc =
3✔
87
            "content modifier to match the raw HTTP header buffer";
3✔
88
    sigmatch_table[DETECT_HTTP_RAW_HEADER_CM].url =
3✔
89
            "/rules/http-keywords.html#http-header-and-http-raw-header";
3✔
90
    sigmatch_table[DETECT_HTTP_RAW_HEADER_CM].Setup = DetectHttpRawHeaderSetup;
3✔
91
#ifdef UNITTESTS
92
    sigmatch_table[DETECT_HTTP_RAW_HEADER_CM].RegisterTests = DetectHttpRawHeaderRegisterTests;
93
#endif
94
    sigmatch_table[DETECT_HTTP_RAW_HEADER_CM].flags |=
3✔
95
            SIGMATCH_NOOPT | SIGMATCH_INFO_CONTENT_MODIFIER;
3✔
96
    sigmatch_table[DETECT_HTTP_RAW_HEADER_CM].alternative = DETECT_HTTP_RAW_HEADER;
3✔
97

98
    /* http.header.raw sticky buffer */
99
    sigmatch_table[DETECT_HTTP_RAW_HEADER].name = "http.header.raw";
3✔
100
    sigmatch_table[DETECT_HTTP_RAW_HEADER].desc = "sticky buffer to match the raw HTTP header buffer";
3✔
101
    sigmatch_table[DETECT_HTTP_RAW_HEADER].url = "/rules/http-keywords.html#http-header-and-http-raw-header";
3✔
102
    sigmatch_table[DETECT_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetupSticky;
3✔
103
    sigmatch_table[DETECT_HTTP_RAW_HEADER].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER;
3✔
104

105
    DetectAppLayerInspectEngineRegister("http_raw_header", ALPROTO_HTTP1, SIG_FLAG_TOSERVER,
3✔
106
            HTP_REQUEST_PROGRESS_HEADERS + 1, DetectEngineInspectBufferGeneric, GetData);
3✔
107
    DetectAppLayerInspectEngineRegister("http_raw_header", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT,
3✔
108
            HTP_RESPONSE_PROGRESS_HEADERS + 1, DetectEngineInspectBufferGeneric, GetData);
3✔
109

110
    DetectAppLayerMpmRegister("http_raw_header", SIG_FLAG_TOSERVER, 2,
3✔
111
            PrefilterMpmHttpHeaderRawRequestRegister, NULL, ALPROTO_HTTP1,
3✔
112
            0); /* progress handled in register */
3✔
113
    DetectAppLayerMpmRegister("http_raw_header", SIG_FLAG_TOCLIENT, 2,
3✔
114
            PrefilterMpmHttpHeaderRawResponseRegister, NULL, ALPROTO_HTTP1,
3✔
115
            0); /* progress handled in register */
3✔
116

117
    DetectAppLayerInspectEngineRegister("http_raw_header", ALPROTO_HTTP2, SIG_FLAG_TOSERVER,
3✔
118
            HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2);
3✔
119
    DetectAppLayerInspectEngineRegister("http_raw_header", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT,
3✔
120
            HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetData2);
3✔
121

122
    DetectAppLayerMpmRegister("http_raw_header", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
3✔
123
            GetData2, ALPROTO_HTTP2, HTTP2StateDataClient);
3✔
124
    DetectAppLayerMpmRegister("http_raw_header", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister,
3✔
125
            GetData2, ALPROTO_HTTP2, HTTP2StateDataServer);
3✔
126

127
    DetectBufferTypeSetDescriptionByName("http_raw_header",
3✔
128
            "raw http headers");
3✔
129

130
    DetectBufferTypeRegisterValidateCallback("http_raw_header",
3✔
131
            DetectHttpRawHeaderValidateCallback);
3✔
132
    g_http2_thread_id = DetectRegisterThreadCtxGlobalFuncs(
3✔
133
            "http2.raw_header", SCHttp2ThreadBufDataInit, NULL, SCHttp2ThreadBufDataFree);
3✔
134

135
    g_http_raw_header_buffer_id = DetectBufferTypeGetByName("http_raw_header");
3✔
136
}
3✔
137

138
/**
139
 * \brief The setup function for the http_raw_header keyword for a signature.
140
 *
141
 * \param de_ctx Pointer to the detection engine context.
142
 * \param s      Pointer to signature for the current Signature being parsed
143
 *               from the rules.
144
 * \param m      Pointer to the head of the SigMatchs for the current rule
145
 *               being parsed.
146
 * \param arg    Pointer to the string holding the keyword value.
147
 *
148
 * \retval  0 On success.
149
 * \retval -1 On failure.
150
 */
151
int DetectHttpRawHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
152
{
276✔
153
    return DetectEngineContentModifierBufferSetup(
276✔
154
            de_ctx, s, arg, DETECT_HTTP_RAW_HEADER_CM, g_http_raw_header_buffer_id, ALPROTO_HTTP1);
276✔
155
}
276✔
156

157
/**
158
 * \brief this function setup the http.header.raw keyword used in the rule
159
 *
160
 * \param de_ctx   Pointer to the Detection Engine Context
161
 * \param s        Pointer to the Signature to which the current keyword belongs
162
 * \param str      Should hold an empty string always
163
 *
164
 * \retval 0       On success
165
 */
166
static int DetectHttpRawHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
167
{
2,717✔
168
    if (SCDetectBufferSetActiveList(de_ctx, s, g_http_raw_header_buffer_id) < 0)
2,717✔
169
        return -1;
28✔
170
    if (SCDetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0)
2,689✔
171
        return -1;
14✔
172
    return 0;
2,675✔
173
}
2,689✔
174

175
static bool DetectHttpRawHeaderValidateCallback(
176
        const Signature *s, const char **sigerror, const DetectBufferType *dbt)
177
{
3,182✔
178
    if ((s->flags & (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) {
3,182✔
179
        *sigerror = "http_raw_header signature "
611✔
180
                "without a flow direction. Use flow:to_server for "
611✔
181
                "inspecting request headers or flow:to_client for "
611✔
182
                "inspecting response headers.";
611✔
183

184
        SCLogError("%s", *sigerror);
611✔
185
        SCReturnInt(false);
611✔
186
    }
611✔
187
    return true;
2,571✔
188
}
3,182✔
189

190
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
191
        const DetectEngineTransforms *transforms, Flow *_f,
192
        const uint8_t flow_flags, void *txv, const int list_id)
193
{
348✔
194
    InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
348✔
195
    if (buffer->inspect == NULL) {
348✔
196
        htp_tx_t *tx = (htp_tx_t *)txv;
188✔
197

198
        HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
188✔
199

200
        const bool ts = ((flow_flags & STREAM_TOSERVER) != 0);
188✔
201
        const uint8_t *data = ts ?
188✔
202
            tx_ud->request_headers_raw : tx_ud->response_headers_raw;
188✔
203
        if (data == NULL)
188✔
204
            return NULL;
42✔
205
        const uint32_t data_len = ts ?
146✔
206
            tx_ud->request_headers_raw_len : tx_ud->response_headers_raw_len;
146✔
207

208
        InspectionBufferSetupAndApplyTransforms(
146✔
209
                det_ctx, list_id, buffer, data, data_len, transforms);
146✔
210
    }
146✔
211

212
    return buffer;
306✔
213
}
348✔
214

215
static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx,
216
        const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv,
217
        const int list_id)
218
{
140✔
219
    InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
140✔
220
    if (buffer->inspect == NULL) {
140✔
221
        uint32_t b_len = 0;
136✔
222
        const uint8_t *b = NULL;
136✔
223

224
        void *thread_buf = DetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, g_http2_thread_id);
136✔
225
        if (thread_buf == NULL)
136✔
226
            return NULL;
×
227
        if (SCHttp2TxGetHeadersRaw(txv, flow_flags, &b, &b_len, thread_buf) != 1)
136✔
228
            return NULL;
88✔
229
        if (b == NULL || b_len == 0)
48✔
230
            return NULL;
×
231

232
        InspectionBufferSetupAndApplyTransforms(det_ctx, list_id, buffer, b, b_len, transforms);
48✔
233
    }
48✔
234

235
    return buffer;
52✔
236
}
140✔
237

238
typedef struct PrefilterMpmHttpHeaderRawCtx {
239
    int list_id;
240
    const MpmCtx *mpm_ctx;
241
    const DetectEngineTransforms *transforms;
242
} PrefilterMpmHttpHeaderRawCtx;
243

244
/** \brief Generic Mpm prefilter callback
245
 *
246
 *  \param det_ctx detection engine thread ctx
247
 *  \param p packet to inspect
248
 *  \param f flow to inspect
249
 *  \param txv tx to inspect
250
 *  \param pectx inspection context
251
 */
252
static void PrefilterMpmHttpHeaderRaw(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p,
253
        Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags)
254
{
190✔
255
    SCEnter();
190✔
256

257
    const PrefilterMpmHttpHeaderRawCtx *ctx = pectx;
190✔
258
    const MpmCtx *mpm_ctx = ctx->mpm_ctx;
190✔
259
    SCLogDebug("running on list %d", ctx->list_id);
190✔
260

261
    const int list_id = ctx->list_id;
190✔
262

263
    InspectionBuffer *buffer = GetData(det_ctx, ctx->transforms, f,
190✔
264
            flags, txv, list_id);
190✔
265
    if (buffer == NULL)
190✔
266
        return;
42✔
267

268
    const uint32_t data_len = buffer->inspect_len;
148✔
269
    const uint8_t *data = buffer->inspect;
148✔
270

271
    SCLogDebug("mpm'ing buffer:");
148✔
272
    //PrintRawDataFp(stdout, data, data_len);
273

274
    if (data != NULL && data_len >= mpm_ctx->minlen) {
148✔
275
        (void)mpm_table[mpm_ctx->mpm_type].Search(
137✔
276
                mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, data, data_len);
137✔
277
        PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len);
137✔
278
    }
137✔
279
}
148✔
280

281
static void PrefilterMpmHttpTrailerRaw(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p,
282
        Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags)
283
{
188✔
284
    SCEnter();
188✔
285

286
    htp_tx_t *tx = txv;
188✔
287
    const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx);
188✔
288
    /* if the request wasn't flagged as having a trailer, we skip */
289
    if (((flags & STREAM_TOSERVER) && !htud->request_has_trailers) ||
188✔
290
            ((flags & STREAM_TOCLIENT) && !htud->response_has_trailers)) {
188✔
291
        SCReturn;
186✔
292
    }
186✔
293
    PrefilterMpmHttpHeaderRaw(det_ctx, pectx, p, f, txv, idx, _txd, flags);
2✔
294
    SCReturn;
2✔
295
}
188✔
296

297
static void PrefilterMpmHttpHeaderRawFree(void *ptr)
298
{
1,071✔
299
    SCFree(ptr);
1,071✔
300
}
1,071✔
301

302
static int PrefilterMpmHttpHeaderRawRequestRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
303
        MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
304
{
357✔
305
    SCEnter();
357✔
306

307
    /* header */
308
    PrefilterMpmHttpHeaderRawCtx *pectx = SCCalloc(1, sizeof(*pectx));
357✔
309
    if (pectx == NULL)
357✔
310
        return -1;
×
311
    pectx->list_id = list_id;
357✔
312
    pectx->mpm_ctx = mpm_ctx;
357✔
313
    pectx->transforms = &mpm_reg->transforms;
357✔
314

315
    int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeaderRaw, mpm_reg->app_v2.alproto,
357✔
316
            HTP_REQUEST_PROGRESS_HEADERS + 1, pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
357✔
317
    if (r != 0) {
357✔
318
        SCFree(pectx);
×
319
        return r;
×
320
    }
×
321

322
    /* trailer */
323
    pectx = SCCalloc(1, sizeof(*pectx));
357✔
324
    if (pectx == NULL)
357✔
325
        return -1;
×
326
    pectx->list_id = list_id;
357✔
327
    pectx->mpm_ctx = mpm_ctx;
357✔
328
    pectx->transforms = &mpm_reg->transforms;
357✔
329

330
    r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailerRaw, mpm_reg->app_v2.alproto,
357✔
331
            HTP_REQUEST_PROGRESS_TRAILER + 1, pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
357✔
332
    if (r != 0) {
357✔
333
        SCFree(pectx);
×
334
    }
×
335
    return r;
357✔
336
}
357✔
337

338
static int PrefilterMpmHttpHeaderRawResponseRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
339
        MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
UNCOV
340
{
×
UNCOV
341
    SCEnter();
×
342

343
    /* header */
UNCOV
344
    PrefilterMpmHttpHeaderRawCtx *pectx = SCCalloc(1, sizeof(*pectx));
×
UNCOV
345
    if (pectx == NULL)
×
346
        return -1;
×
UNCOV
347
    pectx->list_id = list_id;
×
UNCOV
348
    pectx->mpm_ctx = mpm_ctx;
×
UNCOV
349
    pectx->transforms = &mpm_reg->transforms;
×
350

UNCOV
351
    int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeaderRaw, mpm_reg->app_v2.alproto,
×
UNCOV
352
            HTP_RESPONSE_PROGRESS_HEADERS, pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
×
UNCOV
353
    if (r != 0) {
×
354
        SCFree(pectx);
×
355
        return r;
×
356
    }
×
357

358
    /* trailer */
UNCOV
359
    pectx = SCCalloc(1, sizeof(*pectx));
×
UNCOV
360
    if (pectx == NULL)
×
361
        return -1;
×
UNCOV
362
    pectx->list_id = list_id;
×
UNCOV
363
    pectx->mpm_ctx = mpm_ctx;
×
UNCOV
364
    pectx->transforms = &mpm_reg->transforms;
×
365

UNCOV
366
    r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailerRaw, mpm_reg->app_v2.alproto,
×
UNCOV
367
            HTP_RESPONSE_PROGRESS_TRAILER, pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname);
×
UNCOV
368
    if (r != 0) {
×
369
        SCFree(pectx);
×
370
    }
×
UNCOV
371
    return r;
×
UNCOV
372
}
×
373

374
/************************************Unittests*********************************/
375

376
#ifdef UNITTESTS
377
#include "tests/detect-http-raw-header.c"
378
#endif
379

380
/**
381
 * @}
382
 */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc