Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-quic-cyu-hash.c
Line
Count
Source
1
/* Copyright (C) 2021-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
 *
20
 * Implements the quic.cyu.hash sticky buffer
21
 */
22
23
#include "suricata-common.h"
24
#include "detect.h"
25
#include "detect-parse.h"
26
#include "detect-content.h"
27
28
#include "detect-engine.h"
29
#include "detect-engine-mpm.h"
30
#include "detect-engine-prefilter.h"
31
#include "detect-engine-content-inspection.h"
32
#include "detect-quic-cyu-hash.h"
33
#include "detect-engine-build.h"
34
#include "rust.h"
35
#include "util-profiling.h"
36
37
#ifdef UNITTESTS
38
static void DetectQuicCyuHashRegisterTests(void);
39
#endif
40
41
34
#define KEYWORD_NAME "quic.cyu.hash"
42
34
#define KEYWORD_DOC  "quic-cyu.html#quic-cyu-hash"
43
204
#define BUFFER_NAME  "quic.cyu.hash"
44
34
#define BUFFER_DESC  "QUIC CYU Hash"
45
static int g_buffer_id = 0;
46
47
struct QuicHashGetDataArgs {
48
    uint32_t local_id; /**< used as index into thread inspect array */
49
    void *txv;
50
};
51
52
static int DetectQuicCyuHashSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
53
638
{
54
638
    if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0)
55
6
        return -1;
56
57
632
    if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0)
58
95
        return -1;
59
60
537
    return 0;
61
632
}
62
63
static InspectionBuffer *QuicHashGetData(DetectEngineThreadCtx *det_ctx,
64
        const DetectEngineTransforms *transforms, Flow *f, struct QuicHashGetDataArgs *cbdata,
65
        int list_id)
66
2.57k
{
67
2.57k
    SCEnter();
68
69
2.57k
    InspectionBuffer *buffer =
70
2.57k
            InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id);
71
2.57k
    if (buffer == NULL)
72
0
        return NULL;
73
2.57k
    if (buffer->initialized)
74
485
        return buffer;
75
76
2.09k
    const uint8_t *data;
77
2.09k
    uint32_t data_len;
78
2.09k
    if (rs_quic_tx_get_cyu_hash(cbdata->txv, (uint16_t)cbdata->local_id, &data, &data_len) == 0) {
79
1.59k
        InspectionBufferSetupMultiEmpty(buffer);
80
1.59k
        return NULL;
81
1.59k
    }
82
83
497
    InspectionBufferSetupMulti(buffer, transforms, data, data_len);
84
85
497
    SCReturnPtr(buffer, "InspectionBuffer");
86
2.09k
}
87
88
static uint8_t DetectEngineInspectQuicHash(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
89
        const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags,
90
        void *alstate, void *txv, uint64_t tx_id)
91
485
{
92
485
    uint32_t local_id = 0;
93
94
485
    const DetectEngineTransforms *transforms = NULL;
95
485
    if (!engine->mpm) {
96
0
        transforms = engine->v2.transforms;
97
0
    }
98
99
485
    while (1) {
100
485
        struct QuicHashGetDataArgs cbdata = {
101
485
            local_id,
102
485
            txv,
103
485
        };
104
485
        InspectionBuffer *buffer =
105
485
                QuicHashGetData(det_ctx, transforms, f, &cbdata, engine->sm_list);
106
485
        if (buffer == NULL || buffer->inspect == NULL)
107
0
            break;
108
109
485
        det_ctx->buffer_offset = 0;
110
485
        det_ctx->discontinue_matching = 0;
111
485
        det_ctx->inspection_recursion_counter = 0;
112
113
485
        const int match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f,
114
485
                (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset,
115
485
                DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE);
116
485
        if (match == 1) {
117
485
            return DETECT_ENGINE_INSPECT_SIG_MATCH;
118
485
        }
119
0
        local_id++;
120
0
    }
121
0
    return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
122
485
}
123
124
typedef struct PrefilterMpmQuicHash {
125
    int list_id;
126
    const MpmCtx *mpm_ctx;
127
    const DetectEngineTransforms *transforms;
128
} PrefilterMpmQuicHash;
129
130
/** \brief QuicHash Mpm prefilter callback
131
 *
132
 *  \param det_ctx detection engine thread ctx
133
 *  \param p packet to inspect
134
 *  \param f flow to inspect
135
 *  \param txv tx to inspect
136
 *  \param pectx inspection context
137
 */
138
static void PrefilterTxQuicHash(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p,
139
        Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags)
140
1.59k
{
141
1.59k
    SCEnter();
142
143
1.59k
    const PrefilterMpmQuicHash *ctx = (const PrefilterMpmQuicHash *)pectx;
144
1.59k
    const MpmCtx *mpm_ctx = ctx->mpm_ctx;
145
1.59k
    const int list_id = ctx->list_id;
146
147
1.59k
    uint32_t local_id = 0;
148
2.09k
    while (1) {
149
        // loop until we get a NULL
150
151
2.09k
        struct QuicHashGetDataArgs cbdata = { local_id, txv };
152
2.09k
        InspectionBuffer *buffer = QuicHashGetData(det_ctx, ctx->transforms, f, &cbdata, list_id);
153
2.09k
        if (buffer == NULL)
154
1.59k
            break;
155
156
497
        if (buffer->inspect_len >= mpm_ctx->minlen) {
157
497
            (void)mpm_table[mpm_ctx->mpm_type].Search(
158
497
                    mpm_ctx, &det_ctx->mtcu, &det_ctx->pmq, buffer->inspect, buffer->inspect_len);
159
497
            PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len);
160
497
        }
161
162
497
        local_id++;
163
497
    }
164
1.59k
}
165
166
static void PrefilterMpmQuicHashFree(void *ptr)
167
61
{
168
61
    SCFree(ptr);
169
61
}
170
171
static int PrefilterMpmQuicHashRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
172
        const DetectBufferMpmRegistry *mpm_reg, int list_id)
173
61
{
174
61
    PrefilterMpmQuicHash *pectx = SCCalloc(1, sizeof(*pectx));
175
61
    if (pectx == NULL)
176
0
        return -1;
177
61
    pectx->list_id = list_id;
178
61
    pectx->mpm_ctx = mpm_ctx;
179
61
    pectx->transforms = &mpm_reg->transforms;
180
181
61
    return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxQuicHash, mpm_reg->app_v2.alproto,
182
61
            mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmQuicHashFree, mpm_reg->pname);
183
61
}
184
185
static bool DetectQuicHashValidateCallback(const Signature *s, const char **sigerror)
186
479
{
187
1.33k
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
188
893
        if (s->init_data->buffers[x].id != (uint32_t)g_buffer_id)
189
414
            continue;
190
479
        const SigMatch *sm = s->init_data->buffers[x].head;
191
919
        for (; sm != NULL; sm = sm->next) {
192
479
            if (sm->type != DETECT_CONTENT)
193
0
                continue;
194
195
479
            const DetectContentData *cd = (DetectContentData *)sm->ctx;
196
197
479
            if (cd->flags & DETECT_CONTENT_NOCASE) {
198
0
                *sigerror = BUFFER_NAME " should not be used together with "
199
0
                                        "nocase, since the rule is automatically "
200
0
                                        "lowercased anyway which makes nocase redundant.";
201
0
                SCLogWarning("rule %u: %s", s->id, *sigerror);
202
0
            }
203
204
479
            if (cd->content_len != 32) {
205
37
                *sigerror = "Invalid length of the specified" BUFFER_NAME " (should "
206
37
                            "be 32 characters long). This rule will therefore "
207
37
                            "never match.";
208
37
                SCLogWarning("rule %u: %s", s->id, *sigerror);
209
37
                return false;
210
37
            }
211
14.5k
            for (size_t i = 0; i < cd->content_len; ++i) {
212
14.0k
                if (!isxdigit(cd->content[i])) {
213
2
                    *sigerror = "Invalid " BUFFER_NAME
214
2
                                " string (should be string of hexadecimal characters)."
215
2
                                "This rule will therefore never match.";
216
2
                    SCLogWarning("rule %u: %s", s->id, *sigerror);
217
2
                    return false;
218
2
                }
219
14.0k
            }
220
442
        }
221
479
    }
222
440
    return true;
223
479
}
224
225
void DetectQuicCyuHashRegister(void)
226
34
{
227
    /* quic.cyu.hash sticky buffer */
228
34
    sigmatch_table[DETECT_AL_QUIC_CYU_HASH].name = KEYWORD_NAME;
229
34
    sigmatch_table[DETECT_AL_QUIC_CYU_HASH].desc = "sticky buffer to match on the QUIC CYU hash";
230
34
    sigmatch_table[DETECT_AL_QUIC_CYU_HASH].url = "/rules/" KEYWORD_DOC;
231
34
    sigmatch_table[DETECT_AL_QUIC_CYU_HASH].Setup = DetectQuicCyuHashSetup;
232
34
    sigmatch_table[DETECT_AL_QUIC_CYU_HASH].flags |= SIGMATCH_NOOPT;
233
#ifdef UNITTESTS
234
    sigmatch_table[DETECT_AL_QUIC_CYU_HASH].RegisterTests = DetectQuicCyuHashRegisterTests;
235
#endif
236
237
34
    DetectAppLayerMpmRegister2(
238
34
            BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterMpmQuicHashRegister, NULL, ALPROTO_QUIC, 1);
239
240
34
    DetectAppLayerInspectEngineRegister2(
241
34
            BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 0, DetectEngineInspectQuicHash, NULL);
242
243
34
    DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
244
245
34
    g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
246
247
34
    DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, DetectQuicHashValidateCallback);
248
249
34
    DetectBufferTypeSupportsMultiInstance(BUFFER_NAME);
250
34
}
251
252
#ifdef UNITTESTS
253
#include "app-layer-parser.h"
254
#include "util-unittest.h"
255
#include "util-unittest-helper.h"
256
#include "flow-util.h"
257
#include "detect-engine-alert.h"
258
259
/**
260
 * \test DetectQuicCyuHashTest01 is a test for a valid quic packet, matching
261
 *   on the cyu hash
262
 *
263
 *  \retval 1 on success
264
 *  \retval 0 on failure
265
 */
266
static int DetectQuicCyuHashTest01(void)
267
{
268
    /* quic packet */
269
    uint8_t buf[] = { 0xc3, 0x51, 0x30, 0x34, 0x36, 0x50, 0x76, 0xd8, 0x63, 0xb7, 0x54, 0xf7, 0xab,
270
        0x32, 0x00, 0x00, 0x00, 0x01, 0x54, 0xfd, 0xf4, 0x79, 0x48, 0x76, 0xd0, 0x87, 0x58, 0x8d,
271
        0x26, 0x8f, 0xa0, 0x01, 0x04, 0x00, 0x43, 0x48, 0x4c, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x50,
272
        0x41, 0x44, 0x00, 0xe4, 0x02, 0x00, 0x00, 0x53, 0x4e, 0x49, 0x00, 0xf7, 0x02, 0x00, 0x00,
273
        0x56, 0x45, 0x52, 0x00, 0xfb, 0x02, 0x00, 0x00, 0x43, 0x43, 0x53, 0x00, 0x0b, 0x03, 0x00,
274
        0x00, 0x55, 0x41, 0x49, 0x44, 0x2c, 0x03, 0x00, 0x00, 0x54, 0x43, 0x49, 0x44, 0x30, 0x03,
275
        0x00, 0x00, 0x50, 0x44, 0x4d, 0x44, 0x34, 0x03, 0x00, 0x00, 0x53, 0x4d, 0x48, 0x4c, 0x38,
276
        0x03, 0x00, 0x00, 0x49, 0x43, 0x53, 0x4c, 0x3c, 0x03, 0x00, 0x00, 0x4e, 0x4f, 0x4e, 0x50,
277
        0x5c, 0x03, 0x00, 0x00, 0x4d, 0x49, 0x44, 0x53, 0x60, 0x03, 0x00, 0x00, 0x53, 0x43, 0x4c,
278
        0x53, 0x64, 0x03, 0x00, 0x00, 0x43, 0x53, 0x43, 0x54, 0x64, 0x03, 0x00, 0x00, 0x43, 0x4f,
279
        0x50, 0x54, 0x64, 0x03, 0x00, 0x00, 0x49, 0x52, 0x54, 0x54, 0x68, 0x03, 0x00, 0x00, 0x43,
280
        0x46, 0x43, 0x57, 0x6c, 0x03, 0x00, 0x00, 0x53, 0x46, 0x43, 0x57, 0x70, 0x03, 0x00, 0x00,
281
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
282
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
283
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
284
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
285
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
286
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
287
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
288
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
289
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
290
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
291
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
292
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
293
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
294
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
295
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
296
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
297
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
298
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
299
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
300
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
301
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
302
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
303
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
304
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
305
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
306
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
307
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
308
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
309
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
310
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
311
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
312
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
313
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
314
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
315
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
316
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
317
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
318
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
319
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
320
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
321
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
322
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
323
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
324
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
325
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
326
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
327
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
328
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
329
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
330
        0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x31, 0x2e, 0x67,
331
        0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x51, 0x30, 0x34, 0x36, 0x01, 0xe8,
332
        0x81, 0x60, 0x92, 0x92, 0x1a, 0xe8, 0x7e, 0xed, 0x80, 0x86, 0xa2, 0x15, 0x82, 0x91, 0x43,
333
        0x68, 0x72, 0x6f, 0x6d, 0x65, 0x2f, 0x37, 0x39, 0x2e, 0x30, 0x2e, 0x33, 0x39, 0x34, 0x35,
334
        0x2e, 0x31, 0x31, 0x37, 0x20, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x78, 0x38, 0x36, 0x5f,
335
        0x36, 0x34, 0x00, 0x00, 0x00, 0x00, 0x58, 0x35, 0x30, 0x39, 0x01, 0x00, 0x00, 0x00, 0x1e,
336
        0x00, 0x00, 0x00, 0x82, 0x88, 0x09, 0x00, 0xfa, 0x0f, 0xde, 0xb7, 0x2e, 0x7e, 0x6c, 0x78,
337
        0xcc, 0x09, 0x65, 0xab, 0x06, 0x0c, 0x31, 0x05, 0xfa, 0xd9, 0xa2, 0x0b, 0xdd, 0x74, 0x5c,
338
        0x28, 0xdf, 0x7b, 0x74, 0x23, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1d, 0x43,
339
        0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
348
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359
        0x00, 0x00 };
360
361
    Flow f;
362
    void *quic_state = NULL;
363
    Packet *p = NULL;
364
    Signature *s = NULL;
365
    ThreadVars tv;
366
    DetectEngineThreadCtx *det_ctx = NULL;
367
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
368
369
    memset(&tv, 0, sizeof(ThreadVars));
370
    memset(&f, 0, sizeof(Flow));
371
372
    p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 443);
373
374
    FLOW_INITIALIZE(&f);
375
    f.flags |= FLOW_IPV4;
376
    f.proto = IPPROTO_UDP;
377
    f.protomap = FlowGetProtoMapping(f.proto);
378
379
    p->flow = &f;
380
    p->flags |= PKT_HAS_FLOW;
381
    p->flowflags |= FLOW_PKT_TOSERVER;
382
    f.alproto = ALPROTO_QUIC;
383
384
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
385
    FAIL_IF_NULL(de_ctx);
386
    de_ctx->mpm_matcher = mpm_default_matcher;
387
    de_ctx->flags |= DE_QUIET;
388
389
    s = DetectEngineAppendSig(de_ctx,
390
            "alert quic any any -> any any "
391
            "(msg:\"Test QUIC CYU hash\"; "
392
            "quic.cyu.hash; content:\"910a5e3a4d51593bd59a44611544f209\"; "
393
            "sid:1;)");
394
    FAIL_IF_NULL(s);
395
396
    SigGroupBuild(de_ctx);
397
    DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
398
399
    int r = AppLayerParserParse(
400
            NULL, alp_tctx, &f, ALPROTO_QUIC, STREAM_TOSERVER, buf, sizeof(buf));
401
    if (r != 0) {
402
        printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
403
        FAIL;
404
    }
405
406
    quic_state = f.alstate;
407
    FAIL_IF_NULL(quic_state);
408
409
    /* do detect */
410
    SigMatchSignatures(&tv, de_ctx, det_ctx, p);
411
412
    if (!(PacketAlertCheck(p, 1))) {
413
        printf("sig 1 didn't alert, but it should have: ");
414
        FAIL;
415
    }
416
417
    if (alp_tctx != NULL)
418
        AppLayerParserThreadCtxFree(alp_tctx);
419
    if (det_ctx != NULL)
420
        DetectEngineThreadCtxDeinit(&tv, det_ctx);
421
    if (de_ctx != NULL)
422
        SigGroupCleanup(de_ctx);
423
    if (de_ctx != NULL)
424
        DetectEngineCtxFree(de_ctx);
425
426
    FLOW_DESTROY(&f);
427
    UTHFreePacket(p);
428
    PASS;
429
}
430
431
static void DetectQuicCyuHashRegisterTests(void)
432
{
433
    UtRegisterTest("DetectQuicCyuHashTest01", DetectQuicCyuHashTest01);
434
}
435
436
#endif /* UNITTESTS */