Coverage Report

Created: 2025-11-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-http2.c
Line
Count
Source
1
/* Copyright (C) 2020-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
 * \file
20
 *
21
 * \author Philippe Antoine <p.antoine@catenacyber.fr>
22
 *
23
 */
24
25
#include "suricata-common.h"
26
27
#include "detect.h"
28
#include "detect-parse.h"
29
#include "detect-content.h"
30
31
#include "detect-engine.h"
32
#include "detect-engine-uint.h"
33
#include "detect-engine-mpm.h"
34
#include "detect-engine-prefilter.h"
35
#include "detect-engine-content-inspection.h"
36
37
#include "detect-http2.h"
38
#include "util-byte.h"
39
#include "rust.h"
40
#include "util-profiling.h"
41
42
#ifdef UNITTESTS
43
void DetectHTTP2frameTypeRegisterTests (void);
44
void DetectHTTP2errorCodeRegisterTests (void);
45
void DetectHTTP2priorityRegisterTests (void);
46
void DetectHTTP2windowRegisterTests (void);
47
void DetectHTTP2settingsRegisterTests (void);
48
void DetectHTTP2sizeUpdateRegisterTests (void);
49
#endif
50
51
/* prototypes */
52
static int DetectHTTP2frametypeMatch(DetectEngineThreadCtx *det_ctx,
53
                                     Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
54
                                     const SigMatchCtx *ctx);
55
static int DetectHTTP2frametypeSetup (DetectEngineCtx *, Signature *, const char *);
56
void DetectHTTP2frametypeFree (DetectEngineCtx *, void *);
57
58
static int DetectHTTP2errorcodeMatch(DetectEngineThreadCtx *det_ctx,
59
                                     Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
60
                                     const SigMatchCtx *ctx);
61
static int DetectHTTP2errorcodeSetup (DetectEngineCtx *, Signature *, const char *);
62
void DetectHTTP2errorcodeFree (DetectEngineCtx *, void *);
63
64
static int DetectHTTP2priorityMatch(DetectEngineThreadCtx *det_ctx,
65
                                     Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
66
                                     const SigMatchCtx *ctx);
67
static int DetectHTTP2prioritySetup (DetectEngineCtx *, Signature *, const char *);
68
void DetectHTTP2priorityFree (DetectEngineCtx *, void *);
69
70
static int DetectHTTP2windowMatch(DetectEngineThreadCtx *det_ctx,
71
                                     Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
72
                                     const SigMatchCtx *ctx);
73
static int DetectHTTP2windowSetup (DetectEngineCtx *, Signature *, const char *);
74
void DetectHTTP2windowFree (DetectEngineCtx *, void *);
75
76
static int DetectHTTP2sizeUpdateMatch(DetectEngineThreadCtx *det_ctx,
77
                                     Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
78
                                     const SigMatchCtx *ctx);
79
static int DetectHTTP2sizeUpdateSetup (DetectEngineCtx *, Signature *, const char *);
80
void DetectHTTP2sizeUpdateFree (DetectEngineCtx *, void *);
81
82
static int DetectHTTP2settingsMatch(DetectEngineThreadCtx *det_ctx,
83
                                     Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
84
                                     const SigMatchCtx *ctx);
85
static int DetectHTTP2settingsSetup (DetectEngineCtx *, Signature *, const char *);
86
void DetectHTTP2settingsFree (DetectEngineCtx *, void *);
87
88
static int DetectHTTP2headerNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg);
89
static int PrefilterMpmHttp2HeaderNameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
90
        MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id);
91
static uint8_t DetectEngineInspectHttp2HeaderName(DetectEngineCtx *de_ctx,
92
        DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine,
93
        const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id);
94
95
#ifdef UNITTESTS
96
void DetectHTTP2RegisterTests (void);
97
#endif
98
99
static int g_http2_match_buffer_id = 0;
100
static int g_http2_header_name_buffer_id = 0;
101
102
/**
103
 * \brief Registration function for HTTP2 keywords
104
 */
105
106
void DetectHttp2Register(void)
107
34
{
108
34
    sigmatch_table[DETECT_HTTP2_FRAMETYPE].name = "http2.frametype";
109
34
    sigmatch_table[DETECT_HTTP2_FRAMETYPE].desc = "match on HTTP2 frame type field";
110
34
    sigmatch_table[DETECT_HTTP2_FRAMETYPE].url = "/rules/http2-keywords.html#frametype";
111
34
    sigmatch_table[DETECT_HTTP2_FRAMETYPE].Match = NULL;
112
34
    sigmatch_table[DETECT_HTTP2_FRAMETYPE].AppLayerTxMatch = DetectHTTP2frametypeMatch;
113
34
    sigmatch_table[DETECT_HTTP2_FRAMETYPE].Setup = DetectHTTP2frametypeSetup;
114
34
    sigmatch_table[DETECT_HTTP2_FRAMETYPE].Free = DetectHTTP2frametypeFree;
115
#ifdef UNITTESTS
116
    sigmatch_table[DETECT_HTTP2_FRAMETYPE].RegisterTests = DetectHTTP2frameTypeRegisterTests;
117
#endif
118
119
34
    sigmatch_table[DETECT_HTTP2_ERRORCODE].name = "http2.errorcode";
120
34
    sigmatch_table[DETECT_HTTP2_ERRORCODE].desc = "match on HTTP2 error code field";
121
34
    sigmatch_table[DETECT_HTTP2_ERRORCODE].url = "/rules/http2-keywords.html#errorcode";
122
34
    sigmatch_table[DETECT_HTTP2_ERRORCODE].Match = NULL;
123
34
    sigmatch_table[DETECT_HTTP2_ERRORCODE].AppLayerTxMatch = DetectHTTP2errorcodeMatch;
124
34
    sigmatch_table[DETECT_HTTP2_ERRORCODE].Setup = DetectHTTP2errorcodeSetup;
125
34
    sigmatch_table[DETECT_HTTP2_ERRORCODE].Free = DetectHTTP2errorcodeFree;
126
#ifdef UNITTESTS
127
    sigmatch_table[DETECT_HTTP2_ERRORCODE].RegisterTests = DetectHTTP2errorCodeRegisterTests;
128
#endif
129
130
34
    sigmatch_table[DETECT_HTTP2_PRIORITY].name = "http2.priority";
131
34
    sigmatch_table[DETECT_HTTP2_PRIORITY].desc = "match on HTTP2 priority weight field";
132
34
    sigmatch_table[DETECT_HTTP2_PRIORITY].url = "/rules/http2-keywords.html#priority";
133
34
    sigmatch_table[DETECT_HTTP2_PRIORITY].Match = NULL;
134
34
    sigmatch_table[DETECT_HTTP2_PRIORITY].AppLayerTxMatch = DetectHTTP2priorityMatch;
135
34
    sigmatch_table[DETECT_HTTP2_PRIORITY].Setup = DetectHTTP2prioritySetup;
136
34
    sigmatch_table[DETECT_HTTP2_PRIORITY].Free = DetectHTTP2priorityFree;
137
#ifdef UNITTESTS
138
    sigmatch_table[DETECT_HTTP2_PRIORITY].RegisterTests = DetectHTTP2priorityRegisterTests;
139
#endif
140
141
34
    sigmatch_table[DETECT_HTTP2_WINDOW].name = "http2.window";
142
34
    sigmatch_table[DETECT_HTTP2_WINDOW].desc = "match on HTTP2 window update size increment field";
143
34
    sigmatch_table[DETECT_HTTP2_WINDOW].url = "/rules/http2-keywords.html#window";
144
34
    sigmatch_table[DETECT_HTTP2_WINDOW].Match = NULL;
145
34
    sigmatch_table[DETECT_HTTP2_WINDOW].AppLayerTxMatch = DetectHTTP2windowMatch;
146
34
    sigmatch_table[DETECT_HTTP2_WINDOW].Setup = DetectHTTP2windowSetup;
147
34
    sigmatch_table[DETECT_HTTP2_WINDOW].Free = DetectHTTP2windowFree;
148
#ifdef UNITTESTS
149
    sigmatch_table[DETECT_HTTP2_WINDOW].RegisterTests = DetectHTTP2windowRegisterTests;
150
#endif
151
152
34
    sigmatch_table[DETECT_HTTP2_SIZEUPDATE].name = "http2.size_update";
153
34
    sigmatch_table[DETECT_HTTP2_SIZEUPDATE].desc = "match on HTTP2 dynamic headers table size update";
154
34
    sigmatch_table[DETECT_HTTP2_SIZEUPDATE].url = "/rules/http2-keywords.html#sizeupdate";
155
34
    sigmatch_table[DETECT_HTTP2_SIZEUPDATE].Match = NULL;
156
34
    sigmatch_table[DETECT_HTTP2_SIZEUPDATE].AppLayerTxMatch = DetectHTTP2sizeUpdateMatch;
157
34
    sigmatch_table[DETECT_HTTP2_SIZEUPDATE].Setup = DetectHTTP2sizeUpdateSetup;
158
34
    sigmatch_table[DETECT_HTTP2_SIZEUPDATE].Free = DetectHTTP2sizeUpdateFree;
159
#ifdef UNITTESTS
160
    sigmatch_table[DETECT_HTTP2_SIZEUPDATE].RegisterTests = DetectHTTP2sizeUpdateRegisterTests;
161
#endif
162
163
34
    sigmatch_table[DETECT_HTTP2_SETTINGS].name = "http2.settings";
164
34
    sigmatch_table[DETECT_HTTP2_SETTINGS].desc = "match on HTTP2 settings identifier and value fields";
165
34
    sigmatch_table[DETECT_HTTP2_SETTINGS].url = "/rules/http2-keywords.html#settings";
166
34
    sigmatch_table[DETECT_HTTP2_SETTINGS].Match = NULL;
167
34
    sigmatch_table[DETECT_HTTP2_SETTINGS].AppLayerTxMatch = DetectHTTP2settingsMatch;
168
34
    sigmatch_table[DETECT_HTTP2_SETTINGS].Setup = DetectHTTP2settingsSetup;
169
34
    sigmatch_table[DETECT_HTTP2_SETTINGS].Free = DetectHTTP2settingsFree;
170
#ifdef UNITTESTS
171
    sigmatch_table[DETECT_HTTP2_SETTINGS].RegisterTests = DetectHTTP2settingsRegisterTests;
172
#endif
173
174
34
    sigmatch_table[DETECT_HTTP2_HEADERNAME].name = "http2.header_name";
175
34
    sigmatch_table[DETECT_HTTP2_HEADERNAME].desc = "sticky buffer to match on one HTTP2 header name";
176
34
    sigmatch_table[DETECT_HTTP2_HEADERNAME].url = "/rules/http2-keywords.html#header_name";
177
34
    sigmatch_table[DETECT_HTTP2_HEADERNAME].Setup = DetectHTTP2headerNameSetup;
178
34
    sigmatch_table[DETECT_HTTP2_HEADERNAME].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
179
180
34
    DetectAppLayerMpmRegister2("http2_header_name", SIG_FLAG_TOCLIENT, 2,
181
34
                               PrefilterMpmHttp2HeaderNameRegister, NULL,
182
34
                               ALPROTO_HTTP2, HTTP2StateOpen);
183
34
    DetectAppLayerInspectEngineRegister2("http2_header_name",
184
34
                                         ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, HTTP2StateOpen,
185
34
                                         DetectEngineInspectHttp2HeaderName, NULL);
186
34
    DetectAppLayerMpmRegister2("http2_header_name", SIG_FLAG_TOSERVER, 2,
187
34
                               PrefilterMpmHttp2HeaderNameRegister, NULL,
188
34
                               ALPROTO_HTTP2, HTTP2StateOpen);
189
34
    DetectAppLayerInspectEngineRegister2("http2_header_name",
190
34
                                         ALPROTO_HTTP2, SIG_FLAG_TOSERVER, HTTP2StateOpen,
191
34
                                         DetectEngineInspectHttp2HeaderName, NULL);
192
34
    DetectBufferTypeSupportsMultiInstance("http2_header_name");
193
34
    DetectBufferTypeSetDescriptionByName("http2_header_name",
194
34
                                         "HTTP2 header name");
195
34
    g_http2_header_name_buffer_id = DetectBufferTypeGetByName("http2_header_name");
196
197
34
    DetectAppLayerInspectEngineRegister2(
198
34
            "http2", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
199
34
    DetectAppLayerInspectEngineRegister2(
200
34
            "http2", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL);
201
202
34
    g_http2_match_buffer_id = DetectBufferTypeRegister("http2");
203
34
    return;
204
34
}
205
206
/**
207
 * \brief This function is used to match HTTP2 frame type rule option on a transaction with those passed via http2.frametype:
208
 *
209
 * \retval 0 no match
210
 * \retval 1 match
211
 */
212
static int DetectHTTP2frametypeMatch(DetectEngineThreadCtx *det_ctx,
213
                               Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
214
                               const SigMatchCtx *ctx)
215
216
7.16k
{
217
7.16k
    uint8_t *detect = (uint8_t *)ctx;
218
219
7.16k
    return rs_http2_tx_has_frametype(txv, flags, *detect);
220
7.16k
}
221
222
static int DetectHTTP2FuncParseFrameType(const char *str, uint8_t *ft)
223
2.46k
{
224
    // first parse numeric value
225
2.46k
    if (ByteExtractStringUint8(ft, 10, (uint16_t)strlen(str), str) > 0) {
226
469
        return 1;
227
469
    }
228
229
    // it it failed so far, parse string value from enumeration
230
1.99k
    int r = rs_http2_parse_frametype(str);
231
1.99k
    if (r >= 0 && r <= UINT8_MAX) {
232
42
        *ft = (uint8_t)r;
233
42
        return 1;
234
42
    }
235
236
1.95k
    return 0;
237
1.99k
}
238
239
/**
240
 * \brief this function is used to attach the parsed http2.frametype data into the current signature
241
 *
242
 * \param de_ctx pointer to the Detection Engine Context
243
 * \param s pointer to the Current Signature
244
 * \param str pointer to the user provided http2.frametype options
245
 *
246
 * \retval 0 on Success
247
 * \retval -1 on Failure
248
 */
249
static int DetectHTTP2frametypeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
250
2.53k
{
251
2.53k
    uint8_t frame_type;
252
253
2.53k
    if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
254
70
        return -1;
255
256
2.46k
    if (!DetectHTTP2FuncParseFrameType(str, &frame_type)) {
257
1.95k
        SCLogError("Invalid argument \"%s\" supplied to http2.frametype keyword.", str);
258
1.95k
        return -1;
259
1.95k
    }
260
261
511
    uint8_t *http2ft = SCCalloc(1, sizeof(uint8_t));
262
511
    if (http2ft == NULL)
263
0
        return -1;
264
511
    *http2ft = frame_type;
265
266
511
    SigMatch *sm = SigMatchAlloc();
267
511
    if (sm == NULL) {
268
0
        DetectHTTP2frametypeFree(NULL, http2ft);
269
0
        return -1;
270
0
    }
271
272
511
    sm->type = DETECT_HTTP2_FRAMETYPE;
273
511
    sm->ctx = (SigMatchCtx *)http2ft;
274
275
511
    SigMatchAppendSMToList(s, sm, g_http2_match_buffer_id);
276
277
511
    return 0;
278
511
}
279
280
/**
281
 * \brief this function will free memory associated with uint8_t
282
 *
283
 * \param ptr pointer to uint8_t
284
 */
285
void DetectHTTP2frametypeFree(DetectEngineCtx *de_ctx, void *ptr)
286
3.75k
{
287
3.75k
    SCFree(ptr);
288
3.75k
}
289
290
/**
291
 * \brief This function is used to match HTTP2 error code rule option on a transaction with those passed via http2.errorcode:
292
 *
293
 * \retval 0 no match
294
 * \retval 1 match
295
 */
296
static int DetectHTTP2errorcodeMatch(DetectEngineThreadCtx *det_ctx,
297
                               Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
298
                               const SigMatchCtx *ctx)
299
300
927
{
301
927
    uint32_t *detect = (uint32_t *)ctx;
302
303
927
    return rs_http2_tx_has_errorcode(txv, flags, *detect);
304
    //TODOask handle negation rules
305
927
}
306
307
static int DetectHTTP2FuncParseErrorCode(const char *str, uint32_t *ec)
308
84
{
309
    // first parse numeric value
310
84
    if (ByteExtractStringUint32(ec, 10, (uint16_t)strlen(str), str) > 0) {
311
69
        return 1;
312
69
    }
313
314
    // it it failed so far, parse string value from enumeration
315
15
    int r = rs_http2_parse_errorcode(str);
316
15
    if (r >= 0) {
317
0
        *ec = r;
318
0
        return 1;
319
0
    }
320
321
15
    return 0;
322
15
}
323
324
/**
325
 * \brief this function is used to attach the parsed http2.errorcode data into the current signature
326
 *
327
 * \param de_ctx pointer to the Detection Engine Context
328
 * \param s pointer to the Current Signature
329
 * \param str pointer to the user provided http2.errorcode options
330
 *
331
 * \retval 0 on Success
332
 * \retval -1 on Failure
333
 */
334
static int DetectHTTP2errorcodeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
335
85
{
336
85
    uint32_t error_code;
337
338
85
    if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
339
1
        return -1;
340
341
84
    if (!DetectHTTP2FuncParseErrorCode(str, &error_code)) {
342
15
        SCLogError("Invalid argument \"%s\" supplied to http2.errorcode keyword.", str);
343
15
        return -1;
344
15
    }
345
346
69
    uint32_t *http2ec = SCCalloc(1, sizeof(uint32_t));
347
69
    if (http2ec == NULL)
348
0
        return -1;
349
69
    *http2ec = error_code;
350
351
69
    SigMatch *sm = SigMatchAlloc();
352
69
    if (sm == NULL) {
353
0
        DetectHTTP2errorcodeFree(NULL, http2ec);
354
0
        return -1;
355
0
    }
356
357
69
    sm->type = DETECT_HTTP2_ERRORCODE;
358
69
    sm->ctx = (SigMatchCtx *)http2ec;
359
360
69
    SigMatchAppendSMToList(s, sm, g_http2_match_buffer_id);
361
362
69
    return 0;
363
69
}
364
365
/**
366
 * \brief this function will free memory associated with uint32_t
367
 *
368
 * \param ptr pointer to uint32_t
369
 */
370
void DetectHTTP2errorcodeFree(DetectEngineCtx *de_ctx, void *ptr)
371
87
{
372
87
    SCFree(ptr);
373
87
}
374
375
/**
376
 * \brief This function is used to match HTTP2 error code rule option on a transaction with those passed via http2.priority:
377
 *
378
 * \retval 0 no match
379
 * \retval 1 match
380
 */
381
static int DetectHTTP2priorityMatch(DetectEngineThreadCtx *det_ctx,
382
                               Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
383
                               const SigMatchCtx *ctx)
384
385
{
386
    uint32_t nb = 0;
387
    int value = rs_http2_tx_get_next_priority(txv, flags, nb);
388
    const DetectU8Data *du8 = (const DetectU8Data *)ctx;
389
    while (value >= 0) {
390
        if (DetectU8Match((uint8_t)value, du8)) {
391
            return 1;
392
        }
393
        nb++;
394
        value = rs_http2_tx_get_next_priority(txv, flags, nb);
395
    }
396
    return 0;
397
}
398
399
/**
400
 * \brief this function is used to attach the parsed http2.priority data into the current signature
401
 *
402
 * \param de_ctx pointer to the Detection Engine Context
403
 * \param s pointer to the Current Signature
404
 * \param str pointer to the user provided http2.priority options
405
 *
406
 * \retval 0 on Success
407
 * \retval -1 on Failure
408
 */
409
static int DetectHTTP2prioritySetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
410
328
{
411
328
    if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
412
28
        return -1;
413
414
300
    DetectU8Data *prio = DetectU8Parse(str);
415
300
    if (prio == NULL)
416
258
        return -1;
417
418
42
    SigMatch *sm = SigMatchAlloc();
419
42
    if (sm == NULL) {
420
0
        rs_detect_u8_free(prio);
421
0
        return -1;
422
0
    }
423
424
42
    sm->type = DETECT_HTTP2_PRIORITY;
425
42
    sm->ctx = (SigMatchCtx *)prio;
426
427
42
    SigMatchAppendSMToList(s, sm, g_http2_match_buffer_id);
428
429
42
    return 0;
430
42
}
431
432
/**
433
 * \brief this function will free memory associated with uint32_t
434
 *
435
 * \param ptr pointer to DetectU8Data
436
 */
437
void DetectHTTP2priorityFree(DetectEngineCtx *de_ctx, void *ptr)
438
42
{
439
42
    rs_detect_u8_free(ptr);
440
42
}
441
442
/**
443
 * \brief This function is used to match HTTP2 window rule option on a transaction with those passed via http2.window:
444
 *
445
 * \retval 0 no match
446
 * \retval 1 match
447
 */
448
static int DetectHTTP2windowMatch(DetectEngineThreadCtx *det_ctx,
449
                               Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
450
                               const SigMatchCtx *ctx)
451
452
1.59k
{
453
1.59k
    uint32_t nb = 0;
454
1.59k
    int value = rs_http2_tx_get_next_window(txv, flags, nb);
455
1.59k
    const DetectU32Data *du32 = (const DetectU32Data *)ctx;
456
1.59k
    while (value >= 0) {
457
4
        if (DetectU32Match(value, du32)) {
458
0
            return 1;
459
0
        }
460
4
        nb++;
461
4
        value = rs_http2_tx_get_next_window(txv, flags, nb);
462
4
    }
463
1.59k
    return 0;
464
1.59k
}
465
466
/**
467
 * \brief this function is used to attach the parsed http2.window data into the current signature
468
 *
469
 * \param de_ctx pointer to the Detection Engine Context
470
 * \param s pointer to the Current Signature
471
 * \param str pointer to the user provided http2.window options
472
 *
473
 * \retval 0 on Success
474
 * \retval -1 on Failure
475
 */
476
static int DetectHTTP2windowSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
477
3.47k
{
478
3.47k
    if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
479
39
        return -1;
480
481
3.43k
    DetectU32Data *wu = DetectU32Parse(str);
482
3.43k
    if (wu == NULL)
483
1.35k
        return -1;
484
485
2.07k
    SigMatch *sm = SigMatchAlloc();
486
2.07k
    if (sm == NULL) {
487
0
        rs_detect_u32_free(wu);
488
0
        return -1;
489
0
    }
490
491
2.07k
    sm->type = DETECT_HTTP2_WINDOW;
492
2.07k
    sm->ctx = (SigMatchCtx *)wu;
493
494
2.07k
    SigMatchAppendSMToList(s, sm, g_http2_match_buffer_id);
495
496
2.07k
    return 0;
497
2.07k
}
498
499
/**
500
 * \brief this function will free memory associated with uint32_t
501
 *
502
 * \param ptr pointer to DetectU8Data
503
 */
504
void DetectHTTP2windowFree(DetectEngineCtx *de_ctx, void *ptr)
505
2.07k
{
506
2.07k
    rs_detect_u32_free(ptr);
507
2.07k
}
508
509
/**
510
 * \brief This function is used to match HTTP2 size update rule option on a transaction with those passed via http2.size_update:
511
 *
512
 * \retval 0 no match
513
 * \retval 1 match
514
 */
515
static int DetectHTTP2sizeUpdateMatch(DetectEngineThreadCtx *det_ctx,
516
                               Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
517
                               const SigMatchCtx *ctx)
518
519
0
{
520
0
    return rs_http2_detect_sizeupdatectx_match(ctx, txv, flags);
521
0
}
522
523
/**
524
 * \brief this function is used to attach the parsed http2.size_update data into the current signature
525
 *
526
 * \param de_ctx pointer to the Detection Engine Context
527
 * \param s pointer to the Current Signature
528
 * \param str pointer to the user provided http2.size_update options
529
 *
530
 * \retval 0 on Success
531
 * \retval -1 on Failure
532
 */
533
static int DetectHTTP2sizeUpdateSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
534
723
{
535
723
    if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
536
163
        return -1;
537
538
560
    void *su = rs_detect_u64_parse(str);
539
560
    if (su == NULL)
540
459
        return -1;
541
542
101
    SigMatch *sm = SigMatchAlloc();
543
101
    if (sm == NULL) {
544
0
        DetectHTTP2settingsFree(NULL, su);
545
0
        return -1;
546
0
    }
547
548
101
    sm->type = DETECT_HTTP2_SIZEUPDATE;
549
101
    sm->ctx = (SigMatchCtx *)su;
550
551
101
    SigMatchAppendSMToList(s, sm, g_http2_match_buffer_id);
552
553
101
    return 0;
554
101
}
555
556
/**
557
 * \brief this function will free memory associated with uint32_t
558
 *
559
 * \param ptr pointer to DetectU8Data
560
 */
561
void DetectHTTP2sizeUpdateFree(DetectEngineCtx *de_ctx, void *ptr)
562
101
{
563
101
    rs_detect_u64_free(ptr);
564
101
}
565
566
/**
567
 * \brief This function is used to match HTTP2 error code rule option on a transaction with those passed via http2.settings:
568
 *
569
 * \retval 0 no match
570
 * \retval 1 match
571
 */
572
static int DetectHTTP2settingsMatch(DetectEngineThreadCtx *det_ctx,
573
                               Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
574
                               const SigMatchCtx *ctx)
575
576
6.60k
{
577
6.60k
    return rs_http2_detect_settingsctx_match(ctx, txv, flags);
578
6.60k
}
579
580
/**
581
 * \brief this function is used to attach the parsed http2.settings data into the current signature
582
 *
583
 * \param de_ctx pointer to the Detection Engine Context
584
 * \param s pointer to the Current Signature
585
 * \param str pointer to the user provided http2.settings options
586
 *
587
 * \retval 0 on Success
588
 * \retval -1 on Failure
589
 */
590
static int DetectHTTP2settingsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
591
18.1k
{
592
18.1k
    if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
593
496
        return -1;
594
595
17.6k
    void *http2set = rs_http2_detect_settingsctx_parse(str);
596
17.6k
    if (http2set == NULL)
597
7.64k
        return -1;
598
599
10.0k
    SigMatch *sm = SigMatchAlloc();
600
10.0k
    if (sm == NULL) {
601
0
        DetectHTTP2settingsFree(NULL, http2set);
602
0
        return -1;
603
0
    }
604
605
10.0k
    sm->type = DETECT_HTTP2_SETTINGS;
606
10.0k
    sm->ctx = (SigMatchCtx *)http2set;
607
608
10.0k
    SigMatchAppendSMToList(s, sm, g_http2_match_buffer_id);
609
610
10.0k
    return 0;
611
10.0k
}
612
613
/**
614
 * \brief this function will free memory associated with rust signature context
615
 *
616
 * \param ptr pointer to rust signature context
617
 */
618
void DetectHTTP2settingsFree(DetectEngineCtx *de_ctx, void *ptr)
619
10.0k
{
620
10.0k
    rs_http2_detect_settingsctx_free(ptr);
621
10.0k
}
622
623
static int DetectHTTP2headerNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
624
352
{
625
352
    if (DetectBufferSetActiveList(de_ctx, s, g_http2_header_name_buffer_id) < 0)
626
3
        return -1;
627
628
349
    if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
629
11
        return -1;
630
631
338
    return 0;
632
349
}
633
634
static void PrefilterMpmHttp2HNameFree(void *ptr)
635
0
{
636
0
    SCFree(ptr);
637
0
}
638
639
static InspectionBuffer *GetHttp2HNameData(DetectEngineThreadCtx *det_ctx, const uint8_t flags,
640
        const DetectEngineTransforms *transforms, Flow *_f, const struct MpmListIdDataArgs *cbdata,
641
        int list_id)
642
0
{
643
0
    SCEnter();
644
645
0
    InspectionBuffer *buffer =
646
0
            InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id);
647
0
    if (buffer == NULL)
648
0
        return NULL;
649
0
    if (buffer->initialized)
650
0
        return buffer;
651
652
0
    uint32_t b_len = 0;
653
0
    const uint8_t *b = NULL;
654
655
0
    if (rs_http2_tx_get_header_name(cbdata->txv, flags, cbdata->local_id, &b, &b_len) != 1) {
656
0
        InspectionBufferSetupMultiEmpty(buffer);
657
0
        return NULL;
658
0
    }
659
0
    if (b == NULL || b_len == 0) {
660
0
        InspectionBufferSetupMultiEmpty(buffer);
661
0
        return NULL;
662
0
    }
663
664
0
    InspectionBufferSetupMulti(buffer, transforms, b, b_len);
665
666
0
    SCReturnPtr(buffer, "InspectionBuffer");
667
0
}
668
669
static void PrefilterTxHttp2HName(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p,
670
        Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags)
671
0
{
672
0
    SCEnter();
673
674
0
    const PrefilterMpmListId *ctx = (const PrefilterMpmListId *)pectx;
675
0
    const MpmCtx *mpm_ctx = ctx->mpm_ctx;
676
0
    const int list_id = ctx->list_id;
677
678
0
    uint32_t local_id = 0;
679
680
0
    while(1) {
681
        // loop until we get a NULL
682
683
0
        struct MpmListIdDataArgs cbdata = { local_id, txv };
684
0
        InspectionBuffer *buffer =
685
0
                GetHttp2HNameData(det_ctx, flags, ctx->transforms, f, &cbdata, list_id);
686
0
        if (buffer == NULL)
687
0
            break;
688
689
0
        if (buffer->inspect_len >= mpm_ctx->minlen) {
690
0
            (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx,
691
0
                    &det_ctx->mtcu, &det_ctx->pmq,
692
0
                    buffer->inspect, buffer->inspect_len);
693
0
            PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len);
694
0
        }
695
696
0
        local_id++;
697
0
    }
698
0
}
699
700
static int PrefilterMpmHttp2HeaderNameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
701
        MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
702
0
{
703
    //TODOask use PrefilterMpmListId elsewhere
704
0
    PrefilterMpmListId *pectx = SCCalloc(1, sizeof(*pectx));
705
0
    if (pectx == NULL)
706
0
        return -1;
707
0
    pectx->list_id = list_id;
708
0
    pectx->mpm_ctx = mpm_ctx;
709
0
    pectx->transforms = &mpm_reg->transforms;
710
711
0
    return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttp2HName,
712
0
            mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress,
713
0
            pectx, PrefilterMpmHttp2HNameFree, mpm_reg->name);
714
0
}
715
716
static uint8_t DetectEngineInspectHttp2HeaderName(DetectEngineCtx *de_ctx,
717
        DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine,
718
        const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
719
0
{
720
0
    uint32_t local_id = 0;
721
722
0
    const DetectEngineTransforms *transforms = NULL;
723
0
    if (!engine->mpm) {
724
0
        transforms = engine->v2.transforms;
725
0
    }
726
727
0
    while (1) {
728
        //TODOask use MpmListIdDataArgs elsewhere
729
0
        struct MpmListIdDataArgs cbdata = { local_id, txv, };
730
0
        InspectionBuffer *buffer =
731
0
                GetHttp2HNameData(det_ctx, flags, transforms, f, &cbdata, engine->sm_list);
732
733
0
        if (buffer == NULL || buffer->inspect == NULL)
734
0
            break;
735
736
0
        det_ctx->buffer_offset = 0;
737
0
        det_ctx->discontinue_matching = 0;
738
0
        det_ctx->inspection_recursion_counter = 0;
739
740
0
        const int match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd,
741
0
                                              NULL, f,
742
0
                                              (uint8_t *)buffer->inspect,
743
0
                                              buffer->inspect_len,
744
0
                                              buffer->inspect_offset, DETECT_CI_FLAGS_SINGLE,
745
0
                                              DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE);
746
0
        if (match == 1) {
747
0
            return DETECT_ENGINE_INSPECT_SIG_MATCH;
748
0
        }
749
0
        local_id++;
750
0
    }
751
752
0
    return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
753
0
}
754
755
#ifdef UNITTESTS
756
#include "tests/detect-http2.c"
757
#endif