Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/detect-bytemath.c
Line
Count
Source
1
/* Copyright (C) 2020-2026 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 Jeff Lucovsky <jeff@lucovsky.org>
22
 */
23
24
/*
25
 * Refer to the Snort manual, section 3.5.34 for details.
26
 */
27
28
#include "suricata-common.h"
29
#include "threads.h"
30
#include "decode.h"
31
32
#include "rust.h"
33
#include "app-layer-parser.h"
34
#include "app-layer-protos.h"
35
36
#include "detect.h"
37
#include "detect-parse.h"
38
#include "detect-engine.h"
39
#include "detect-engine-buffer.h"
40
#include "detect-engine-mpm.h"
41
#include "detect-engine-state.h"
42
#include "detect-engine-build.h"
43
44
#include "detect-content.h"
45
#include "detect-pcre.h"
46
#include "detect-byte.h"
47
#include "detect-bytemath.h"
48
49
#include "flow.h"
50
#include "flow-var.h"
51
#include "flow-util.h"
52
53
#include "util-byte.h"
54
#include "util-debug.h"
55
#include "util-unittest.h"
56
#include "util-unittest-helper.h"
57
#include "util-spm.h"
58
59
static int DetectByteMathSetup(DetectEngineCtx *, Signature *, const char *);
60
#ifdef UNITTESTS
61
#define DETECT_BYTEMATH_ENDIAN_DEFAULT (uint8_t) BigEndian
62
#define DETECT_BYTEMATH_BASE_DEFAULT   (uint8_t) BaseDec
63
64
static void DetectByteMathRegisterTests(void);
65
#endif
66
static void DetectByteMathFree(DetectEngineCtx *, void *);
67
68
/**
69
 * \brief Registers the keyword handlers for the "byte_math" keyword.
70
 */
71
void DetectBytemathRegister(void)
72
79
{
73
79
    sigmatch_table[DETECT_BYTEMATH].name = "byte_math";
74
79
    sigmatch_table[DETECT_BYTEMATH].Match = NULL;
75
79
    sigmatch_table[DETECT_BYTEMATH].Setup = DetectByteMathSetup;
76
79
    sigmatch_table[DETECT_BYTEMATH].Free = DetectByteMathFree;
77
79
    sigmatch_table[DETECT_BYTEMATH].desc = "used to perform mathematical operations on byte values";
78
79
    sigmatch_table[DETECT_BYTEMATH].url = "/rules/payload-keywords.html#byte-math";
79
#ifdef UNITTESTS
80
    sigmatch_table[DETECT_BYTEMATH].RegisterTests = DetectByteMathRegisterTests;
81
#endif
82
79
}
83
84
static inline bool DetectByteMathValidateNbytesOnly(const DetectByteMathData *data, int32_t nbytes)
85
5.23k
{
86
5.23k
    return nbytes >= 1 &&
87
5.23k
           (((data->flags & DETECT_BYTEMATH_FLAG_STRING) && nbytes <= 10) || (nbytes <= 4));
88
5.23k
}
89
90
int DetectByteMathDoMatch(DetectEngineThreadCtx *det_ctx, const DetectByteMathData *data,
91
        const Signature *s, const uint8_t *payload, const uint32_t payload_len, uint8_t nbytes,
92
        uint64_t rvalue, uint64_t *value, uint8_t endian)
93
5.23k
{
94
5.23k
    if (payload_len == 0) {
95
0
        return 0;
96
0
    }
97
98
5.23k
    if (!DetectByteMathValidateNbytesOnly(data, nbytes)) {
99
0
        return 0;
100
0
    }
101
102
5.23k
    const uint8_t *ptr;
103
5.23k
    int32_t len;
104
5.23k
    uint64_t val;
105
5.23k
    int extbytes;
106
107
    /* Calculate the ptr value for the byte-math op and length remaining in
108
     * the packet from that point.
109
     */
110
5.23k
    if (data->flags & DETECT_BYTEMATH_FLAG_RELATIVE) {
111
0
        SCLogDebug("relative, working with det_ctx->buffer_offset %" PRIu32 ", "
112
0
                   "data->offset %" PRIi32 "",
113
0
                det_ctx->buffer_offset, data->offset);
114
115
0
        ptr = payload + det_ctx->buffer_offset;
116
0
        len = payload_len - det_ctx->buffer_offset;
117
118
0
        ptr += data->offset;
119
0
        len -= data->offset;
120
121
        /* No match if there is no relative base */
122
0
        if (len <= 0) {
123
0
            return 0;
124
0
        }
125
5.23k
    } else {
126
5.23k
        SCLogDebug("absolute, data->offset %" PRIi32 "", data->offset);
127
128
5.23k
        ptr = payload + data->offset;
129
5.23k
        len = payload_len - data->offset;
130
5.23k
    }
131
132
    /* Validate that the to-be-extracted is within the packet */
133
5.23k
    if (ptr < payload || nbytes > len) {
134
0
        SCLogDebug("Data not within payload pkt=%p, ptr=%p, len=%" PRIu32 ", nbytes=%d", payload,
135
0
                ptr, len, nbytes);
136
0
        return 0;
137
0
    }
138
139
    /* Extract the byte data */
140
5.23k
    if (data->flags & DETECT_BYTEMATH_FLAG_STRING) {
141
0
        extbytes = ByteExtractStringUint64(&val, data->base, nbytes, (const char *)ptr);
142
0
        if (extbytes <= 0) {
143
0
            if (val == 0) {
144
0
                SCLogDebug("No Numeric value");
145
0
                return 0;
146
0
            } else {
147
0
                SCLogDebug("error extracting %d bytes of string data: %d", nbytes, extbytes);
148
0
                return -1;
149
0
            }
150
0
        }
151
5.23k
    } else {
152
5.23k
        ByteEndian bme = endian;
153
5.23k
        int endianness = (bme == BigEndian) ? BYTE_BIG_ENDIAN : BYTE_LITTLE_ENDIAN;
154
5.23k
        extbytes = ByteExtractUint64(&val, endianness, nbytes, ptr);
155
5.23k
        if (extbytes != nbytes) {
156
0
            SCLogDebug("error extracting %d bytes of numeric data: %d", nbytes, extbytes);
157
0
            return 0;
158
0
        }
159
5.23k
    }
160
161
5.23k
    DEBUG_VALIDATE_BUG_ON(extbytes > len);
162
163
5.23k
    ptr += extbytes;
164
165
5.23k
    switch (data->oper) {
166
0
        case OperatorNone:
167
0
            break;
168
825
        case Addition:
169
825
            val += rvalue;
170
825
            break;
171
4.40k
        case Subtraction:
172
4.40k
            val -= rvalue;
173
4.40k
            break;
174
0
        case Division:
175
0
            if (rvalue == 0) {
176
0
                SCLogDebug("avoiding division by zero");
177
0
                return 0;
178
0
            }
179
0
            val /= rvalue;
180
0
            break;
181
0
        case Multiplication:
182
0
            val *= rvalue;
183
0
            break;
184
2
        case LeftShift:
185
2
            if (rvalue < 64) {
186
2
                val <<= rvalue;
187
2
            } else {
188
0
                val = 0;
189
0
            }
190
2
            break;
191
3
        case RightShift:
192
3
            if (rvalue < 64) {
193
0
                val >>= rvalue;
194
3
            } else {
195
3
                val = 0;
196
3
            }
197
3
            break;
198
5.23k
    }
199
200
5.23k
    det_ctx->buffer_offset = (uint32_t)(ptr - payload);
201
202
5.23k
    if (data->flags & DETECT_BYTEMATH_FLAG_BITMASK) {
203
0
        val &= data->bitmask_val;
204
0
        if (val && data->bitmask_shift_count) {
205
0
            val = val >> data->bitmask_shift_count;
206
0
        }
207
0
    }
208
209
5.23k
    *value = val;
210
5.23k
    return 1;
211
5.23k
}
212
213
/**
214
 * \internal
215
 * \brief Used to parse byte_math arg.
216
 *
217
 * \param arg The argument to parse.
218
 * \param rvalue May be NULL. When non-null, will contain the variable
219
 *              name of rvalue (iff rvalue is not a scalar value)
220
 *
221
 * \retval bmd On success an instance containing the parsed data.
222
 *            On failure, NULL.
223
 */
224
static DetectByteMathData *DetectByteMathParse(
225
        DetectEngineCtx *de_ctx, const char *arg, char **nbytes, char **rvalue)
226
16.5k
{
227
16.5k
    DetectByteMathData *bmd;
228
16.5k
    if ((bmd = SCByteMathParse(arg)) == NULL) {
229
6.76k
        SCLogError("invalid bytemath values");
230
6.76k
        return NULL;
231
6.76k
    }
232
233
9.77k
    if (bmd->nbytes_str) {
234
97
        if (nbytes == NULL) {
235
0
            SCLogError("byte_math supplied with "
236
0
                       "var name for nbytes. \"nbytes\" argument supplied to "
237
0
                       "this function must be non-NULL");
238
0
            goto error;
239
0
        }
240
97
        *nbytes = SCStrdup(bmd->nbytes_str);
241
97
        if (*nbytes == NULL) {
242
0
            goto error;
243
0
        }
244
97
    }
245
246
9.77k
    if (bmd->rvalue_str) {
247
5.18k
        if (rvalue == NULL) {
248
0
            SCLogError("byte_math supplied with "
249
0
                       "var name for rvalue. \"rvalue\" argument supplied to "
250
0
                       "this function must be non-NULL");
251
0
            goto error;
252
0
        }
253
5.18k
        *rvalue = SCStrdup(bmd->rvalue_str);
254
5.18k
        if (*rvalue == NULL) {
255
0
            goto error;
256
0
        }
257
5.18k
    }
258
259
9.77k
    if (bmd->flags & DETECT_BYTEMATH_FLAG_BITMASK) {
260
0
        if (bmd->bitmask_val) {
261
0
            uint32_t bmask = bmd->bitmask_val;
262
0
            while (!(bmask & 0x1)){
263
0
                bmask = bmask >> 1;
264
0
                bmd->bitmask_shift_count++;
265
0
            }
266
0
        }
267
0
    }
268
269
9.77k
    return bmd;
270
271
0
 error:
272
0
    if (bmd != NULL)
273
0
        DetectByteMathFree(de_ctx, bmd);
274
0
    return NULL;
275
9.77k
}
276
277
/**
278
 * \brief The setup function for the byte_math keyword for a signature.
279
 *
280
 * \param de_ctx Pointer to the detection engine context.
281
 * \param s      Pointer to signature for the current Signature being parsed
282
 *               from the rules.
283
 * \param arg    Pointer to the string holding the keyword value.
284
 *
285
 * \retval  0 On success.
286
 * \retval -1 On failure.
287
 */
288
static int DetectByteMathSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
289
2.16k
{
290
2.16k
    SigMatch *prev_pm = NULL;
291
2.16k
    DetectByteMathData *data;
292
2.16k
    char *rvalue = NULL;
293
2.16k
    char *nbytes = NULL;
294
2.16k
    int ret = -1;
295
296
2.16k
    data = DetectByteMathParse(de_ctx, arg, &nbytes, &rvalue);
297
2.16k
    if (data == NULL)
298
910
        goto error;
299
300
    /* A shift of 64 or more clears the 64 bit value being shifted, so the
301
     * result is 0 for every packet. Only a literal rvalue can be checked
302
     * here; a variable one is read from the payload at match time. */
303
1.25k
    if ((data->oper == LeftShift || data->oper == RightShift) &&
304
455
            !(data->flags & DETECT_BYTEMATH_FLAG_RVALUE_VAR) && data->rvalue >= 64) {
305
0
        if (SigMatchStrictEnabled(DETECT_BYTEMATH)) {
306
0
            SCLogError("byte_math rvalue %u is 64 or more, so \"%s\" always gives 0", data->rvalue,
307
0
                    data->oper == LeftShift ? "<<" : ">>");
308
0
            goto error;
309
0
        }
310
0
        if (s->id > 0) {
311
0
            SCLogWarning("signature sid:%u: byte_math rvalue %u is 64 or more, so \"%s\" "
312
0
                         "always gives 0",
313
0
                    s->id, data->rvalue, data->oper == LeftShift ? "<<" : ">>");
314
0
        } else if (de_ctx->rule_file != NULL) {
315
0
            SCLogWarning("signature at %s:%u: byte_math rvalue %u is 64 or more, so \"%s\" "
316
0
                         "always gives 0",
317
0
                    de_ctx->rule_file, de_ctx->rule_line, data->rvalue,
318
0
                    data->oper == LeftShift ? "<<" : ">>");
319
0
        } else {
320
0
            SCLogWarning("byte_math rvalue %u is 64 or more, so \"%s\" always gives 0",
321
0
                    data->rvalue, data->oper == LeftShift ? "<<" : ">>");
322
0
        }
323
0
    }
324
325
1.25k
    int sm_list;
326
1.25k
    if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
327
752
        if (DetectBufferGetActiveList(de_ctx, s) == -1)
328
0
            goto error;
329
330
752
        sm_list = s->init_data->list;
331
332
752
        if (data->flags & DETECT_BYTEMATH_FLAG_RELATIVE) {
333
20
            prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1);
334
20
            if (!prev_pm) {
335
11
                SCLogError("relative specified without "
336
11
                           "previous pattern match");
337
11
                goto error;
338
11
            }
339
20
        }
340
752
    } else if (data->endian == EndianDCE) {
341
0
        if (data->flags & DETECT_BYTEMATH_FLAG_RELATIVE) {
342
0
            prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE,
343
0
                                               DETECT_BYTETEST, DETECT_BYTEJUMP,
344
0
                                               DETECT_BYTE_EXTRACT,
345
0
                                               DETECT_BYTEMATH,
346
0
                                               DETECT_ISDATAAT, -1);
347
0
            if (prev_pm == NULL) {
348
0
                sm_list = DETECT_SM_LIST_PMATCH;
349
0
            } else {
350
0
                sm_list = SigMatchListSMBelongsTo(s, prev_pm);
351
0
                if (sm_list < 0)
352
0
                    goto error;
353
0
            }
354
0
        } else {
355
0
            sm_list = DETECT_SM_LIST_PMATCH;
356
0
        }
357
358
0
        if (SCDetectSignatureSetAppProto(s, ALPROTO_DCERPC) < 0)
359
0
            goto error;
360
361
500
    } else if (data->flags & DETECT_BYTEMATH_FLAG_RELATIVE) {
362
349
        prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE,
363
349
                                           DETECT_BYTETEST, DETECT_BYTEJUMP,
364
349
                                           DETECT_BYTE_EXTRACT, DETECT_BYTEMATH,
365
349
                                           DETECT_ISDATAAT, -1);
366
349
        if (prev_pm == NULL) {
367
0
            sm_list = DETECT_SM_LIST_PMATCH;
368
349
        } else {
369
349
            sm_list = SigMatchListSMBelongsTo(s, prev_pm);
370
349
            if (sm_list < 0)
371
0
                goto error;
372
349
        }
373
374
349
    } else {
375
151
        sm_list = DETECT_SM_LIST_PMATCH;
376
151
    }
377
378
1.24k
    if (data->endian == EndianDCE) {
379
0
        if (SCDetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0)
380
0
            goto error;
381
382
0
        if ((data->flags & DETECT_BYTEMATH_FLAG_STRING) || (data->base == BaseDec) ||
383
0
                (data->base == BaseHex) || (data->base == BaseOct)) {
384
0
            SCLogError("Invalid option. "
385
0
                       "A bytemath keyword with dce holds other invalid modifiers.");
386
0
            goto error;
387
0
        }
388
0
    }
389
390
1.24k
    if (nbytes != NULL) {
391
6
        DetectByteIndexType index;
392
6
        if (!DetectByteRetrieveSMVar(nbytes, s, sm_list, &index)) {
393
5
            SCLogError("unknown byte_ keyword var seen in byte_math - %s", nbytes);
394
5
            goto error;
395
5
        }
396
1
        data->nbytes = index;
397
1
        data->flags |= DETECT_BYTEMATH_FLAG_NBYTES_VAR;
398
1
        SCFree(nbytes);
399
1
        nbytes = NULL;
400
1
    }
401
402
1.23k
    if (rvalue != NULL) {
403
805
        DetectByteIndexType index;
404
805
        if (!DetectByteRetrieveSMVar(rvalue, s, sm_list, &index)) {
405
253
            SCLogError("unknown byte_ keyword var seen in byte_math - %s", rvalue);
406
253
            goto error;
407
253
        }
408
        /* rvalue becomes a byte_values[] index here, so a check on the
409
         * literal count has to run above this point. */
410
552
        data->rvalue = index;
411
552
        data->flags |= DETECT_BYTEMATH_FLAG_RVALUE_VAR;
412
552
        SCFree(rvalue);
413
552
        rvalue = NULL;
414
552
    }
415
416
983
    SigMatch *prev_bmd_sm = DetectGetLastSMByListId(s, sm_list,
417
983
            DETECT_BYTEMATH, -1);
418
983
    if (prev_bmd_sm == NULL) {
419
975
        data->local_id = 0;
420
975
    } else {
421
8
        data->local_id = ((DetectByteMathData *)prev_bmd_sm->ctx)->local_id + 1;
422
8
    }
423
983
    if (data->local_id > de_ctx->byte_extract_max_local_id) {
424
1
        de_ctx->byte_extract_max_local_id = data->local_id;
425
1
    }
426
427
983
    if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_BYTEMATH, (SigMatchCtx *)data, sm_list) ==
428
983
            NULL) {
429
0
        goto error;
430
0
    }
431
432
983
    if (!(data->flags & DETECT_BYTEMATH_FLAG_RELATIVE))
433
625
        goto okay;
434
435
358
    if (prev_pm == NULL)
436
0
        goto okay;
437
438
358
    if (prev_pm->type == DETECT_CONTENT) {
439
1
        DetectContentData *cd = (DetectContentData *)prev_pm->ctx;
440
1
        cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
441
357
    } else if (prev_pm->type == DETECT_PCRE) {
442
8
        DetectPcreData *pd = (DetectPcreData *)prev_pm->ctx;
443
8
        pd->flags |= DETECT_PCRE_RELATIVE_NEXT;
444
8
    }
445
446
983
 okay:
447
983
    return 0;
448
449
1.17k
 error:
450
1.17k
    if (rvalue)
451
260
        SCFree(rvalue);
452
1.17k
    if (nbytes)
453
5
        SCFree(nbytes);
454
1.17k
    DetectByteMathFree(de_ctx, data);
455
1.17k
    return ret;
456
358
}
457
458
/**
459
 * \brief Used to free instances of DetectByteMathractData.
460
 *
461
 * \param ptr Instance of DetectByteMathData to be freed.
462
 */
463
static void DetectByteMathFree(DetectEngineCtx *de_ctx, void *ptr)
464
16.5k
{
465
16.5k
    SCByteMathFree(ptr);
466
16.5k
}
467
468
/**
469
 * \brief Lookup the SigMatch for a named byte_math variable.
470
 *
471
 * \param arg The name of the byte_math variable to lookup.
472
 * \param s Pointer the signature to look in.
473
 *
474
 * \retval A pointer to the SigMatch if found, otherwise NULL.
475
 */
476
SigMatch *DetectByteMathRetrieveSMVar(const char *arg, int sm_list, const Signature *s)
477
12.9k
{
478
17.3k
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
479
6.93k
        SigMatch *sm = s->init_data->buffers[x].head;
480
17.5k
        while (sm != NULL) {
481
13.2k
            if (sm->type == DETECT_BYTEMATH) {
482
3.42k
                const DetectByteMathData *bmd = (const DetectByteMathData *)sm->ctx;
483
3.42k
                if (strcmp(bmd->result, arg) == 0) {
484
2.58k
                    SCLogDebug("Retrieved SM for \"%s\"", arg);
485
2.58k
                    return sm;
486
2.58k
                }
487
3.42k
            }
488
10.6k
            sm = sm->next;
489
10.6k
        }
490
6.93k
    }
491
492
76.0k
    for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
493
66.8k
        SigMatch *sm = s->init_data->smlists[list];
494
87.2k
        while (sm != NULL) {
495
            // Make sure that the linked buffers ore on the same list
496
21.6k
            if (sm->type == DETECT_BYTEMATH && (sm_list == -1 || sm_list == list)) {
497
1.59k
                const DetectByteMathData *bmd = (const DetectByteMathData *)sm->ctx;
498
1.59k
                if (strcmp(bmd->result, arg) == 0) {
499
1.19k
                    SCLogDebug("Retrieved SM for \"%s\"", arg);
500
1.19k
                    return sm;
501
1.19k
                }
502
1.59k
            }
503
20.4k
            sm = sm->next;
504
20.4k
        }
505
66.8k
    }
506
507
9.18k
    return NULL;
508
10.3k
}
509
510
/*************************************Unittests********************************/
511
#ifdef UNITTESTS
512
#include "detect-engine-alert.h"
513
514
static int DetectByteMathParseTest01(void)
515
{
516
517
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
518
            "bytes 4, offset 2, oper +,"
519
            "rvalue 10, result bar",
520
            NULL, NULL);
521
    FAIL_IF(bmd == NULL);
522
523
    FAIL_IF_NOT(bmd->nbytes == 4);
524
    FAIL_IF_NOT(bmd->offset == 2);
525
    FAIL_IF_NOT(bmd->oper == Addition);
526
    FAIL_IF_NOT(bmd->rvalue == 10);
527
    FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
528
    FAIL_IF_NOT(bmd->endian == DETECT_BYTEMATH_ENDIAN_DEFAULT);
529
    FAIL_IF_NOT(bmd->base == DETECT_BYTEMATH_BASE_DEFAULT);
530
531
    DetectByteMathFree(NULL, bmd);
532
533
    PASS;
534
}
535
536
static int DetectByteMathParseTest02(void)
537
{
538
    /* bytes value invalid */
539
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
540
            "bytes 257, offset 2, oper +, "
541
            "rvalue 39, result bar",
542
            NULL, NULL);
543
544
    FAIL_IF_NOT(bmd == NULL);
545
546
    PASS;
547
}
548
549
static int DetectByteMathParseTest03(void)
550
{
551
    /* bytes value invalid */
552
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
553
            "bytes 11, offset 2, oper +, "
554
            "rvalue 39, result bar",
555
            NULL, NULL);
556
    FAIL_IF_NOT(bmd == NULL);
557
558
    PASS;
559
}
560
561
static int DetectByteMathParseTest04(void)
562
{
563
    /* offset value invalid */
564
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
565
            "bytes 4, offset 70000, oper +,"
566
            " rvalue 39, result bar",
567
            NULL, NULL);
568
569
    FAIL_IF_NOT(bmd == NULL);
570
571
    PASS;
572
}
573
574
static int DetectByteMathParseTest05(void)
575
{
576
    /* oper value invalid */
577
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
578
            "bytes 11, offset 16, oper &,"
579
            "rvalue 39, result bar",
580
            NULL, NULL);
581
    FAIL_IF_NOT(bmd == NULL);
582
583
    PASS;
584
}
585
586
static int DetectByteMathParseTest06(void)
587
{
588
    uint8_t flags = DETECT_BYTEMATH_FLAG_RELATIVE;
589
    char *rvalue = NULL;
590
591
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
592
            "bytes 4, offset 0, oper +,"
593
            "rvalue 248, result var, relative",
594
            NULL, &rvalue);
595
596
    FAIL_IF(bmd == NULL);
597
    FAIL_IF_NOT(bmd->nbytes == 4);
598
    FAIL_IF_NOT(bmd->offset == 0);
599
    FAIL_IF_NOT(bmd->oper == Addition);
600
    FAIL_IF_NOT(bmd->rvalue == 248);
601
    FAIL_IF_NOT(strcmp(bmd->result, "var") == 0);
602
    FAIL_IF_NOT(bmd->flags == flags);
603
    FAIL_IF_NOT(bmd->endian == DETECT_BYTEMATH_ENDIAN_DEFAULT);
604
    FAIL_IF_NOT(bmd->base == DETECT_BYTEMATH_BASE_DEFAULT);
605
606
    DetectByteMathFree(NULL, bmd);
607
608
    PASS;
609
}
610
611
static int DetectByteMathParseTest07(void)
612
{
613
    char *rvalue = NULL;
614
615
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
616
            "bytes 4, offset 2, oper +,"
617
            "rvalue foo, result bar",
618
            NULL, &rvalue);
619
    FAIL_IF_NOT(rvalue);
620
    FAIL_IF_NOT(bmd->nbytes == 4);
621
    FAIL_IF_NOT(bmd->offset == 2);
622
    FAIL_IF_NOT(bmd->oper == Addition);
623
    FAIL_IF_NOT(strcmp(rvalue, "foo") == 0);
624
    FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
625
    FAIL_IF_NOT(bmd->endian == DETECT_BYTEMATH_ENDIAN_DEFAULT);
626
    FAIL_IF_NOT(bmd->base == DETECT_BYTEMATH_BASE_DEFAULT);
627
628
    DetectByteMathFree(NULL, bmd);
629
630
    SCFree(rvalue);
631
632
    PASS;
633
}
634
635
static int DetectByteMathParseTest08(void)
636
{
637
    /* ensure Parse checks the pointer value when rvalue is a var */
638
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
639
            "bytes 4, offset 2, oper +,"
640
            "rvalue foo, result bar",
641
            NULL, NULL);
642
    FAIL_IF_NOT(bmd == NULL);
643
644
    PASS;
645
}
646
647
static int DetectByteMathParseTest09(void)
648
{
649
    uint8_t flags = DETECT_BYTEMATH_FLAG_RELATIVE;
650
651
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
652
            "bytes 4, offset 2, oper +,"
653
            "rvalue 39, result bar, relative",
654
            NULL, NULL);
655
    FAIL_IF(bmd == NULL);
656
657
    FAIL_IF_NOT(bmd->nbytes == 4);
658
    FAIL_IF_NOT(bmd->offset == 2);
659
    FAIL_IF_NOT(bmd->oper == Addition);
660
    FAIL_IF_NOT(bmd->rvalue == 39);
661
    FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
662
    FAIL_IF_NOT(bmd->flags == flags);
663
    FAIL_IF_NOT(bmd->endian == DETECT_BYTEMATH_ENDIAN_DEFAULT);
664
    FAIL_IF_NOT(bmd->base == DETECT_BYTEMATH_BASE_DEFAULT);
665
666
    DetectByteMathFree(NULL, bmd);
667
668
    PASS;
669
}
670
671
static int DetectByteMathParseTest10(void)
672
{
673
    uint8_t flags = DETECT_BYTEMATH_FLAG_ENDIAN;
674
675
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
676
            "bytes 4, offset 2, oper +,"
677
            "rvalue 39, result bar, endian"
678
            " big",
679
            NULL, NULL);
680
681
    FAIL_IF(bmd == NULL);
682
    FAIL_IF_NOT(bmd->nbytes == 4);
683
    FAIL_IF_NOT(bmd->offset == 2);
684
    FAIL_IF_NOT(bmd->oper == Addition);
685
    FAIL_IF_NOT(bmd->rvalue == 39);
686
    FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
687
    FAIL_IF_NOT(bmd->flags == flags);
688
    FAIL_IF_NOT(bmd->endian == BigEndian);
689
    FAIL_IF_NOT(bmd->base == DETECT_BYTEMATH_BASE_DEFAULT);
690
691
    DetectByteMathFree(NULL, bmd);
692
693
    PASS;
694
}
695
696
static int DetectByteMathParseTest11(void)
697
{
698
    uint8_t flags = DETECT_BYTEMATH_FLAG_ENDIAN;
699
700
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
701
            "bytes 4, offset 2, oper +, "
702
            "rvalue 39, result bar, dce",
703
            NULL, NULL);
704
705
    FAIL_IF(bmd == NULL);
706
    FAIL_IF_NOT(bmd->nbytes == 4);
707
    FAIL_IF_NOT(bmd->offset == 2);
708
    FAIL_IF_NOT(bmd->oper == Addition);
709
    FAIL_IF_NOT(bmd->rvalue == 39);
710
    FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
711
    FAIL_IF_NOT(bmd->flags == flags);
712
    FAIL_IF_NOT(bmd->endian == EndianDCE);
713
    FAIL_IF_NOT(bmd->base == DETECT_BYTEMATH_BASE_DEFAULT);
714
715
    DetectByteMathFree(NULL, bmd);
716
717
    PASS;
718
}
719
720
static int DetectByteMathParseTest12(void)
721
{
722
    uint8_t flags = DETECT_BYTEMATH_FLAG_RELATIVE | DETECT_BYTEMATH_FLAG_STRING;
723
724
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
725
            "bytes 4, offset 2, oper +,"
726
            "rvalue 39, result bar, "
727
            "relative, string dec",
728
            NULL, NULL);
729
730
    FAIL_IF(bmd == NULL);
731
    FAIL_IF_NOT(bmd->nbytes == 4);
732
    FAIL_IF_NOT(bmd->offset == 2);
733
    FAIL_IF_NOT(bmd->oper == Addition);
734
    FAIL_IF_NOT(bmd->rvalue == 39);
735
    FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
736
    FAIL_IF_NOT(bmd->flags == flags);
737
    FAIL_IF_NOT(bmd->endian == BigEndian);
738
    FAIL_IF_NOT(bmd->base == BaseDec);
739
740
    DetectByteMathFree(NULL, bmd);
741
742
    PASS;
743
}
744
745
static int DetectByteMathParseTest13(void)
746
{
747
    uint8_t flags = DETECT_BYTEMATH_FLAG_STRING |
748
                    DETECT_BYTEMATH_FLAG_RELATIVE |
749
                    DETECT_BYTEMATH_FLAG_BITMASK;
750
751
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
752
            "bytes 4, offset 2, oper +, "
753
            "rvalue 39, result bar, "
754
            "relative,  string dec, bitmask "
755
            "0x8f40",
756
            NULL, NULL);
757
758
    FAIL_IF(bmd == NULL);
759
    FAIL_IF_NOT(bmd->nbytes == 4);
760
    FAIL_IF_NOT(bmd->offset == 2);
761
    FAIL_IF_NOT(bmd->oper == Addition);
762
    FAIL_IF_NOT(bmd->rvalue == 39);
763
    FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
764
    FAIL_IF_NOT(bmd->bitmask_val == 0x8f40);
765
    FAIL_IF_NOT(bmd->bitmask_shift_count == 6);
766
    FAIL_IF_NOT(bmd->flags == flags);
767
    FAIL_IF_NOT(bmd->endian == BigEndian);
768
    FAIL_IF_NOT(bmd->base == BaseDec);
769
770
    DetectByteMathFree(NULL, bmd);
771
772
    PASS;
773
}
774
775
776
static int DetectByteMathParseTest14(void)
777
{
778
    /* incomplete */
779
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
780
            "bytes 4, offset 2, oper +,"
781
            "rvalue foo",
782
            NULL, NULL);
783
784
    FAIL_IF_NOT(bmd == NULL);
785
786
    PASS;
787
}
788
789
static int DetectByteMathParseTest15(void)
790
{
791
792
    /* incomplete */
793
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
794
            "bytes 4, offset 2, oper +, "
795
            "result bar",
796
            NULL, NULL);
797
798
    FAIL_IF_NOT(bmd == NULL);
799
800
    PASS;
801
}
802
803
static int DetectByteMathParseTest16(void)
804
{
805
    uint8_t flags = DETECT_BYTEMATH_FLAG_STRING | DETECT_BYTEMATH_FLAG_RELATIVE |
806
                    DETECT_BYTEMATH_FLAG_BITMASK;
807
808
    DetectByteMathData *bmd = DetectByteMathParse(NULL,
809
            "bytes 4, offset -2, oper +, "
810
            "rvalue 39, result bar, "
811
            "relative,  string dec, bitmask "
812
            "0x8f40",
813
            NULL, NULL);
814
815
    FAIL_IF(bmd == NULL);
816
    FAIL_IF_NOT(bmd->nbytes == 4);
817
    FAIL_IF_NOT(bmd->offset == -2);
818
    FAIL_IF_NOT(bmd->oper == Addition);
819
    FAIL_IF_NOT(bmd->rvalue == 39);
820
    FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
821
    FAIL_IF_NOT(bmd->bitmask_val == 0x8f40);
822
    FAIL_IF_NOT(bmd->bitmask_shift_count == 6);
823
    FAIL_IF_NOT(bmd->flags == flags);
824
    FAIL_IF_NOT(bmd->endian == BigEndian);
825
    FAIL_IF_NOT(bmd->base == BaseDec);
826
827
    DetectByteMathFree(NULL, bmd);
828
829
    PASS;
830
}
831
832
static int DetectByteMathPacket01(void)
833
{
834
    uint8_t buf[] = { 0x38, 0x35, 0x6d, 0x00, 0x00, 0x01,
835
                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
836
                      0x00, 0x00, 0x6d, 0x00, 0x01, 0x00 };
837
    Flow f;
838
    void *dns_state = NULL;
839
    Packet *p = NULL;
840
    Signature *s = NULL;
841
    ThreadVars tv;
842
    DetectEngineThreadCtx *det_ctx = NULL;
843
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
844
845
    memset(&tv, 0, sizeof(ThreadVars));
846
    memset(&f, 0, sizeof(Flow));
847
848
    p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP,
849
                           "192.168.1.5", "192.168.1.1",
850
                           41424, 53);
851
    FAIL_IF_NULL(p);
852
853
    FLOW_INITIALIZE(&f);
854
    f.flags |= FLOW_IPV4;
855
    f.proto = IPPROTO_UDP;
856
    f.protomap = FlowGetProtoMapping(f.proto);
857
858
    p->flow = &f;
859
    p->flags |= PKT_HAS_FLOW;
860
    p->flowflags |= FLOW_PKT_TOSERVER;
861
    f.alproto = ALPROTO_DNS;
862
863
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
864
    FAIL_IF_NULL(de_ctx);
865
866
    de_ctx->mpm_matcher = mpm_default_matcher;
867
    de_ctx->flags |= DE_QUIET;
868
869
    /*
870
     * byte_extract: Extract 1 byte from offset 0 --> 0x0038
871
     * byte_math: Extract 1 byte from offset 2 (0x35)
872
     *            Add 0x35 + 0x38 = 109 (0x6d)
873
     * byte_test: Compare 2 bytes at offset 13 bytes from last
874
     *            match and compare with 0x6d
875
     */
876
    s = DetectEngineAppendSig(de_ctx, "alert udp any any -> any any "
877
                              "(byte_extract: 1, 0, extracted_val, relative;"
878
                              "byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var;"
879
                              "byte_test: 2, =, var, 13;"
880
                              "msg:\"Byte extract and byte math with byte test verification\";"
881
                              "sid:1;)");
882
    FAIL_IF_NULL(s);
883
884
    /* this rule should not alert */
885
    s = DetectEngineAppendSig(de_ctx, "alert udp any any -> any any "
886
                              "(byte_extract: 1, 0, extracted_val, relative;"
887
                              "byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var;"
888
                              "byte_test: 2, !=, var, 13;"
889
                              "msg:\"Byte extract and byte math with byte test verification\";"
890
                              "sid:2;)");
891
    FAIL_IF_NULL(s);
892
893
    /*
894
     * this rule should alert:
895
     * compares offset 15 with var ... 1 (offset 15) < 0x6d (var)
896
     */
897
    s = DetectEngineAppendSig(de_ctx, "alert udp any any -> any any "
898
                              "(byte_extract: 1, 0, extracted_val, relative;"
899
                              "byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var;"
900
                              "byte_test: 2, <, var, 15;"
901
                              "msg:\"Byte extract and byte math with byte test verification\";"
902
                              "sid:3;)");
903
    FAIL_IF_NULL(s);
904
905
    SigGroupBuild(de_ctx);
906
    DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
907
    FAIL_IF_NULL(det_ctx);
908
909
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS,
910
                                STREAM_TOSERVER, buf, sizeof(buf));
911
    FAIL_IF_NOT(r == 0);
912
913
    dns_state = f.alstate;
914
    FAIL_IF_NULL(dns_state);
915
916
    /* do detect */
917
    SigMatchSignatures(&tv, de_ctx, det_ctx, p);
918
919
    /* ensure sids 1 & 3 alerted */
920
    FAIL_IF_NOT(PacketAlertCheck(p, 1));
921
    FAIL_IF(PacketAlertCheck(p, 2));
922
    FAIL_IF_NOT(PacketAlertCheck(p, 3));
923
924
    AppLayerParserThreadCtxFree(alp_tctx);
925
    DetectEngineThreadCtxDeinit(&tv, det_ctx);
926
    DetectEngineCtxFree(de_ctx);
927
928
    FLOW_DESTROY(&f);
929
    UTHFreePacket(p);
930
931
    PASS;
932
}
933
934
static int DetectByteMathPacket02(void)
935
{
936
    uint8_t buf[] = { 0x38, 0x35, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
937
        0x00, 0x70, 0x00, 0x01, 0x00 };
938
    Flow f;
939
    void *dns_state = NULL;
940
    Packet *p = NULL;
941
    Signature *s = NULL;
942
    ThreadVars tv;
943
    DetectEngineThreadCtx *det_ctx = NULL;
944
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
945
946
    memset(&tv, 0, sizeof(ThreadVars));
947
    memset(&f, 0, sizeof(Flow));
948
949
    p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 53);
950
    FAIL_IF_NULL(p);
951
952
    FLOW_INITIALIZE(&f);
953
    f.flags |= FLOW_IPV4;
954
    f.proto = IPPROTO_UDP;
955
    f.protomap = FlowGetProtoMapping(f.proto);
956
957
    p->flow = &f;
958
    p->flags |= PKT_HAS_FLOW;
959
    p->flowflags |= FLOW_PKT_TOSERVER;
960
    f.alproto = ALPROTO_DNS;
961
962
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
963
    FAIL_IF_NULL(de_ctx);
964
965
    de_ctx->mpm_matcher = mpm_default_matcher;
966
    de_ctx->flags |= DE_QUIET;
967
968
    /*
969
     * byte_extract: Extract 1 byte from offset 0 --> 0x38
970
     * byte_math: Extract 1 byte from offset -1 (0x38)
971
     *            Add 0x38 + 0x38 = 112 (0x70)
972
     * byte_test: Compare 2 bytes at offset 13 bytes from last
973
     *            match and compare with 0x70
974
     */
975
    s = DetectEngineAppendSig(de_ctx,
976
            "alert udp any any -> any any "
977
            "(byte_extract: 1, 0, extracted_val, relative;"
978
            "byte_math: bytes 1, offset -1, oper +, rvalue extracted_val, result var, relative;"
979
            "byte_test: 2, =, var, 13;"
980
            "msg:\"Byte extract and byte math with byte test verification\";"
981
            "sid:1;)");
982
    FAIL_IF_NULL(s);
983
984
    /* this rule should not alert */
985
    s = DetectEngineAppendSig(de_ctx,
986
            "alert udp any any -> any any "
987
            "(byte_extract: 1, 0, extracted_val, relative;"
988
            "byte_math: bytes 1, offset -1, oper +,  rvalue extracted_val, result var, relative;"
989
            "byte_test: 2, !=, var, 13;"
990
            "msg:\"Byte extract and byte math with byte test verification\";"
991
            "sid:2;)");
992
    FAIL_IF_NULL(s);
993
994
    /*
995
     * this rule should alert:
996
     * compares offset 15 with var ... 1 (offset 15) < 0x70 (var)
997
     */
998
    s = DetectEngineAppendSig(de_ctx,
999
            "alert udp any any -> any any "
1000
            "(byte_extract: 1, 0, extracted_val, relative;"
1001
            "byte_math: bytes 1, offset -1, oper +, rvalue extracted_val, result var, relative;"
1002
            "byte_test: 2, <, var, 15;"
1003
            "msg:\"Byte extract and byte math with byte test verification\";"
1004
            "sid:3;)");
1005
    FAIL_IF_NULL(s);
1006
1007
    SigGroupBuild(de_ctx);
1008
    DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1009
    FAIL_IF_NULL(det_ctx);
1010
1011
    int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf));
1012
    FAIL_IF_NOT(r == 0);
1013
1014
    dns_state = f.alstate;
1015
    FAIL_IF_NULL(dns_state);
1016
1017
    /* do detect */
1018
    SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1019
1020
    /* ensure sids 1 & 3 alerted */
1021
    FAIL_IF_NOT(PacketAlertCheck(p, 1));
1022
    FAIL_IF(PacketAlertCheck(p, 2));
1023
    FAIL_IF_NOT(PacketAlertCheck(p, 3));
1024
1025
    AppLayerParserThreadCtxFree(alp_tctx);
1026
    DetectEngineThreadCtxDeinit(&tv, det_ctx);
1027
    DetectEngineCtxFree(de_ctx);
1028
1029
    FLOW_DESTROY(&f);
1030
    UTHFreePacket(p);
1031
1032
    PASS;
1033
}
1034
1035
/**
1036
 * \test A payload-supplied shift count of 64 or more yields 0 instead of
1037
 *       shifting a uint64_t by its own width.
1038
 */
1039
static int DetectByteMathPacket03(void)
1040
{
1041
    /* byte 0 is the shift count (64), byte 1 the value shifted, byte 2 the
1042
     * expected result */
1043
    uint8_t buf[] = { 0x40, 0xff, 0x00 };
1044
1045
    Packet *p = UTHBuildPacket(buf, sizeof(buf), IPPROTO_UDP);
1046
    FAIL_IF_NULL(p);
1047
1048
    /* 0xff >> 64 is 0 */
1049
    FAIL_IF_NOT(UTHPacketMatchSig(p, "alert udp any any -> any any "
1050
                                     "(byte_extract: 1, 0, shift;"
1051
                                     "byte_math: bytes 1, offset 1, oper >>, rvalue shift, result "
1052
                                     "var;"
1053
                                     "byte_test: 1, =, var, 2;"
1054
                                     "sid:1;)"));
1055
    UTHFreePacket(p);
1056
1057
    PASS;
1058
}
1059
1060
/**
1061
 * \test A literal shift count of 64 or more parses and keeps its value, so
1062
 *       DetectByteMathSetup() can warn about it.
1063
 */
1064
static int DetectByteMathParseTest17(void)
1065
{
1066
    DetectByteMathData *bmd = DetectByteMathParse(
1067
            NULL, "bytes 4, offset 2, oper >>, rvalue 64, result foo", NULL, NULL);
1068
    FAIL_IF_NULL(bmd);
1069
    FAIL_IF_NOT(bmd->oper == RightShift);
1070
    FAIL_IF_NOT(bmd->rvalue == 64);
1071
    DetectByteMathFree(NULL, bmd);
1072
1073
    bmd = DetectByteMathParse(
1074
            NULL, "bytes 4, offset 2, oper <<, rvalue 100, result foo", NULL, NULL);
1075
    FAIL_IF_NULL(bmd);
1076
    FAIL_IF_NOT(bmd->oper == LeftShift);
1077
    FAIL_IF_NOT(bmd->rvalue == 100);
1078
    DetectByteMathFree(NULL, bmd);
1079
1080
    bmd = DetectByteMathParse(
1081
            NULL, "bytes 4, offset 2, oper >>, rvalue 63, result foo", NULL, NULL);
1082
    FAIL_IF_NULL(bmd);
1083
    DetectByteMathFree(NULL, bmd);
1084
1085
    PASS;
1086
}
1087
1088
static int DetectByteMathContext01(void)
1089
{
1090
    DetectEngineCtx *de_ctx = NULL;
1091
    Signature *s = NULL;
1092
    SigMatch *sm = NULL;
1093
    DetectContentData *cd = NULL;
1094
    DetectByteMathData *bmd = NULL;
1095
1096
    de_ctx = DetectEngineCtxInit();
1097
    FAIL_IF(de_ctx == NULL);
1098
1099
    de_ctx->flags |= DE_QUIET;
1100
    s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
1101
                                           "(msg:\"Testing bytemath_body\"; "
1102
                                           "content:\"|00 04 93 F3|\"; "
1103
                                           "content:\"|00 00 00 07|\"; distance:4; within:4;"
1104
                                           "byte_math:bytes 4, offset 0, oper +, rvalue "
1105
                                           "248, result var, relative; sid:1;)");
1106
1107
    FAIL_IF(de_ctx->sig_list == NULL);
1108
1109
    FAIL_IF(s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL);
1110
1111
    sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH];
1112
    FAIL_IF(sm->type != DETECT_CONTENT);
1113
    cd = (DetectContentData *)sm->ctx;
1114
    FAIL_IF(cd->flags & DETECT_CONTENT_WITHIN);
1115
    FAIL_IF(cd->flags & DETECT_CONTENT_DISTANCE);
1116
    FAIL_IF(cd->content_len != 4);
1117
1118
    sm = sm->next;
1119
    FAIL_IF(sm->type != DETECT_CONTENT);
1120
    sm = sm->next;
1121
    FAIL_IF(sm->type != DETECT_BYTEMATH);
1122
1123
    FAIL_IF(sm->ctx == NULL);
1124
1125
    bmd = (DetectByteMathData *)sm->ctx;
1126
    FAIL_IF_NOT(bmd->nbytes == 4);
1127
    FAIL_IF_NOT(bmd->offset == 0);
1128
    FAIL_IF_NOT(bmd->rvalue == 248);
1129
    FAIL_IF_NOT(strcmp(bmd->result, "var") == 0);
1130
    FAIL_IF_NOT(bmd->flags == DETECT_BYTEMATH_FLAG_RELATIVE);
1131
    FAIL_IF_NOT(bmd->endian == BigEndian);
1132
    FAIL_IF_NOT(bmd->oper == Addition);
1133
    FAIL_IF_NOT(bmd->base == BaseDec);
1134
1135
    DetectEngineCtxFree(de_ctx);
1136
1137
    PASS;
1138
}
1139
1140
static void DetectByteMathRegisterTests(void)
1141
{
1142
    UtRegisterTest("DetectByteMathParseTest01", DetectByteMathParseTest01);
1143
    UtRegisterTest("DetectByteMathParseTest02", DetectByteMathParseTest02);
1144
    UtRegisterTest("DetectByteMathParseTest03", DetectByteMathParseTest03);
1145
    UtRegisterTest("DetectByteMathParseTest04", DetectByteMathParseTest04);
1146
    UtRegisterTest("DetectByteMathParseTest05", DetectByteMathParseTest05);
1147
    UtRegisterTest("DetectByteMathParseTest06", DetectByteMathParseTest06);
1148
    UtRegisterTest("DetectByteMathParseTest07", DetectByteMathParseTest07);
1149
    UtRegisterTest("DetectByteMathParseTest08", DetectByteMathParseTest08);
1150
    UtRegisterTest("DetectByteMathParseTest09", DetectByteMathParseTest09);
1151
    UtRegisterTest("DetectByteMathParseTest10", DetectByteMathParseTest10);
1152
    UtRegisterTest("DetectByteMathParseTest11", DetectByteMathParseTest11);
1153
    UtRegisterTest("DetectByteMathParseTest12", DetectByteMathParseTest12);
1154
    UtRegisterTest("DetectByteMathParseTest13", DetectByteMathParseTest13);
1155
    UtRegisterTest("DetectByteMathParseTest14", DetectByteMathParseTest14);
1156
    UtRegisterTest("DetectByteMathParseTest15", DetectByteMathParseTest15);
1157
    UtRegisterTest("DetectByteMathParseTest16", DetectByteMathParseTest16);
1158
    UtRegisterTest("DetectByteMathParseTest17", DetectByteMathParseTest17);
1159
    UtRegisterTest("DetectByteMathPacket01", DetectByteMathPacket01);
1160
    UtRegisterTest("DetectByteMathPacket02", DetectByteMathPacket02);
1161
    UtRegisterTest("DetectByteMathPacket03", DetectByteMathPacket03);
1162
    UtRegisterTest("DetectByteMathContext01", DetectByteMathContext01);
1163
}
1164
#endif /* UNITTESTS */