Coverage Report

Created: 2025-12-31 06:43

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
73
#define KEYWORD_NAME "quic.cyu.hash"
42
73
#define KEYWORD_DOC  "quic-cyu.html#quic-cyu-hash"
43
438
#define BUFFER_NAME  "quic.cyu.hash"
44
73
#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
2.06k
{
54
2.06k
    if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0)
55
16
        return -1;
56
57
2.04k
    if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0)
58
441
        return -1;
59
60
1.60k
    return 0;
61
2.04k
}
62
63
static InspectionBuffer *QuicHashGetData(DetectEngineThreadCtx *det_ctx,
64
        const DetectEngineTransforms *transforms, Flow *f, struct QuicHashGetDataArgs *cbdata,
65
        int list_id)
66
1.69k
{
67
1.69k
    SCEnter();
68
69
1.69k
    InspectionBuffer *buffer =
70
1.69k
            InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id);
71
1.69k
    if (buffer == NULL)
72
0
        return NULL;
73
1.69k
    if (buffer->initialized)
74
304
        return buffer;
75
76
1.39k
    const uint8_t *data;
77
1.39k
    uint32_t data_len;
78
1.39k
    if (rs_quic_tx_get_cyu_hash(cbdata->txv, (uint16_t)cbdata->local_id, &data, &data_len) == 0) {
79
1.08k
        InspectionBufferSetupMultiEmpty(buffer);
80
1.08k
        return NULL;
81
1.08k
    }
82
83
310
    InspectionBufferSetupMulti(buffer, transforms, data, data_len);
84
85
310
    SCReturnPtr(buffer, "InspectionBuffer");
86
1.39k
}
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
304
{
92
304
    uint32_t local_id = 0;
93
94
304
    const DetectEngineTransforms *transforms = NULL;
95
304
    if (!engine->mpm) {
96
0
        transforms = engine->v2.transforms;
97
0
    }
98
99
304
    while (1) {
100
304
        struct QuicHashGetDataArgs cbdata = {
101
304
            local_id,
102
304
            txv,
103
304
        };
104
304
        InspectionBuffer *buffer =
105
304
                QuicHashGetData(det_ctx, transforms, f, &cbdata, engine->sm_list);
106
304
        if (buffer == NULL || buffer->inspect == NULL)
107
0
            break;
108
109
304
        det_ctx->buffer_offset = 0;
110
304
        det_ctx->discontinue_matching = 0;
111
304
        det_ctx->inspection_recursion_counter = 0;
112
113
304
        const int match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f,
114
304
                (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset,
115
304
                DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE);
116
304
        if (match == 1) {
117
304
            return DETECT_ENGINE_INSPECT_SIG_MATCH;
118
304
        }
119
0
        local_id++;
120
0
    }
121
0
    return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
122
304
}
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.08k
{
141
1.08k
    SCEnter();
142
143
1.08k
    const PrefilterMpmQuicHash *ctx = (const PrefilterMpmQuicHash *)pectx;
144
1.08k
    const MpmCtx *mpm_ctx = ctx->mpm_ctx;
145
1.08k
    const int list_id = ctx->list_id;
146
147
1.08k
    uint32_t local_id = 0;
148
1.39k
    while (1) {
149
        // loop until we get a NULL
150
151
1.39k
        struct QuicHashGetDataArgs cbdata = { local_id, txv };
152
1.39k
        InspectionBuffer *buffer = QuicHashGetData(det_ctx, ctx->transforms, f, &cbdata, list_id);
153
1.39k
        if (buffer == NULL)
154
1.08k
            break;
155
156
310
        if (buffer->inspect_len >= mpm_ctx->minlen) {
157
310
            (void)mpm_table[mpm_ctx->mpm_type].Search(
158
310
                    mpm_ctx, &det_ctx->mtcu, &det_ctx->pmq, buffer->inspect, buffer->inspect_len);
159
310
            PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len);
160
310
        }
161
162
310
        local_id++;
163
310
    }
164
1.08k
}
165
166
static void PrefilterMpmQuicHashFree(void *ptr)
167
42
{
168
42
    SCFree(ptr);
169
42
}
170
171
static int PrefilterMpmQuicHashRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
172
        const DetectBufferMpmRegistry *mpm_reg, int list_id)
173
42
{
174
42
    PrefilterMpmQuicHash *pectx = SCCalloc(1, sizeof(*pectx));
175
42
    if (pectx == NULL)
176
0
        return -1;
177
42
    pectx->list_id = list_id;
178
42
    pectx->mpm_ctx = mpm_ctx;
179
42
    pectx->transforms = &mpm_reg->transforms;
180
181
42
    return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxQuicHash, mpm_reg->app_v2.alproto,
182
42
            mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmQuicHashFree, mpm_reg->pname);
183
42
}
184
185
static bool DetectQuicHashValidateCallback(const Signature *s, const char **sigerror)
186
235
{
187
634
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
188
421
        if (s->init_data->buffers[x].id != (uint32_t)g_buffer_id)
189
186
            continue;
190
235
        const SigMatch *sm = s->init_data->buffers[x].head;
191
448
        for (; sm != NULL; sm = sm->next) {
192
235
            if (sm->type != DETECT_CONTENT)
193
0
                continue;
194
195
235
            const DetectContentData *cd = (DetectContentData *)sm->ctx;
196
197
235
            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
235
            if (cd->content_len != 32) {
205
17
                *sigerror = "Invalid length of the specified" BUFFER_NAME " (should "
206
17
                            "be 32 characters long). This rule will therefore "
207
17
                            "never match.";
208
17
                SCLogWarning("rule %u: %s", s->id, *sigerror);
209
17
                return false;
210
17
            }
211
7.04k
            for (size_t i = 0; i < cd->content_len; ++i) {
212
6.83k
                if (!isxdigit(cd->content[i])) {
213
5
                    *sigerror = "Invalid " BUFFER_NAME
214
5
                                " string (should be string of hexadecimal characters)."
215
5
                                "This rule will therefore never match.";
216
5
                    SCLogWarning("rule %u: %s", s->id, *sigerror);
217
5
                    return false;
218
5
                }
219
6.83k
            }
220
218
        }
221
235
    }
222
213
    return true;
223
235
}
224
225
void DetectQuicCyuHashRegister(void)
226
73
{
227
    /* quic.cyu.hash sticky buffer */
228
73
    sigmatch_table[DETECT_AL_QUIC_CYU_HASH].name = KEYWORD_NAME;
229
73
    sigmatch_table[DETECT_AL_QUIC_CYU_HASH].desc = "sticky buffer to match on the QUIC CYU hash";
230
73
    sigmatch_table[DETECT_AL_QUIC_CYU_HASH].url = "/rules/" KEYWORD_DOC;
231
73
    sigmatch_table[DETECT_AL_QUIC_CYU_HASH].Setup = DetectQuicCyuHashSetup;
232
73
    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
73
    DetectAppLayerMpmRegister2(
238
73
            BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterMpmQuicHashRegister, NULL, ALPROTO_QUIC, 1);
239
240
73
    DetectAppLayerInspectEngineRegister2(
241
73
            BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 0, DetectEngineInspectQuicHash, NULL);
242
243
73
    DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
244
245
73
    g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
246
247
73
    DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, DetectQuicHashValidateCallback);
248
249
73
    DetectBufferTypeSupportsMultiInstance(BUFFER_NAME);
250
73
}
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 */