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

OISF / suricata / 23350122333

20 Mar 2026 03:33PM UTC coverage: 76.492% (-2.8%) from 79.315%
23350122333

Pull #15053

github

web-flow
Merge f5bf69f97 into 6587e363a
Pull Request #15053: Flow queue/v3

113 of 129 new or added lines in 9 files covered. (87.6%)

9534 existing lines in 453 files now uncovered.

256601 of 335461 relevant lines covered (76.49%)

4680806.66 hits per line

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

81.95
/src/detect-hostbits.c
1
/* Copyright (C) 2007-2022 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17

18
/**
19
 * \file
20
 *
21
 *  \author Victor Julien <victor@inliniac.net>
22
 *
23
 * Implements the hostbits keyword
24
 */
25

26
#include "suricata-common.h"
27
#include "decode.h"
28
#include "action-globals.h"
29
#include "detect.h"
30
#include "threads.h"
31
#include "flow.h"
32
#include "flow-util.h"
33
#include "detect-hostbits.h"
34
#include "util-spm.h"
35

36
#include "detect-engine-sigorder.h"
37

38
#include "app-layer-parser.h"
39

40
#include "detect-parse.h"
41
#include "detect-engine.h"
42
#include "detect-engine-mpm.h"
43
#include "detect-engine-state.h"
44
#include "detect-engine-build.h"
45

46
#include "flow-bit.h"
47
#include "host-bit.h"
48
#include "util-var-name.h"
49
#include "util-unittest.h"
50
#include "util-debug.h"
51

52
/*
53
    hostbits:isset,bitname;
54
    hostbits:set,bitname;
55

56
    hostbits:set,bitname,src;
57
    hostbits:set,bitname,dst;
58
TODO:
59
    hostbits:set,bitname,both;
60

61
    hostbits:set,bitname,src,3600;
62
    hostbits:set,bitname,dst,60;
63
    hostbits:set,bitname,both,120;
64
 */
65

66
#define PARSE_REGEX                                                                                \
67
    "^([a-z]+)"                         /* Action */                                               \
2,222✔
68
    "(?:\\s*,\\s*([^\\s,]+))?(?:\\s*)?" /* Name. */                                                \
2,222✔
69
    "(?:\\s*,\\s*([^,\\s]+))?(?:\\s*)?" /* Direction. */                                           \
2,222✔
70
    "(.+)?"                             /* Any remaining data. */
2,222✔
71
static DetectParseRegex parse_regex;
72

73
static int DetectHostbitMatch (DetectEngineThreadCtx *, Packet *,
74
        const Signature *, const SigMatchCtx *);
75
static int DetectHostbitSetup (DetectEngineCtx *, Signature *, const char *);
76
void DetectHostbitFree (DetectEngineCtx *, void *);
77
#ifdef UNITTESTS
78
void HostBitsRegisterTests(void);
79
#endif
80

81
void DetectHostbitsRegister (void)
82
{
2,222✔
83
    sigmatch_table[DETECT_HOSTBITS].name = "hostbits";
2,222✔
84
    sigmatch_table[DETECT_HOSTBITS].desc = "operate on host flag";
2,222✔
85
//    sigmatch_table[DETECT_HOSTBITS].url = "/rules/flow-keywords.html#flowbits";
86
    sigmatch_table[DETECT_HOSTBITS].Match = DetectHostbitMatch;
2,222✔
87
    sigmatch_table[DETECT_HOSTBITS].Setup = DetectHostbitSetup;
2,222✔
88
    sigmatch_table[DETECT_HOSTBITS].Free  = DetectHostbitFree;
2,222✔
89
#ifdef UNITTESTS
3✔
90
    sigmatch_table[DETECT_HOSTBITS].RegisterTests = HostBitsRegisterTests;
3✔
91
#endif
3✔
92
    /* this is compatible to ip-only signatures */
93
    sigmatch_table[DETECT_HOSTBITS].flags |= SIGMATCH_IPONLY_COMPAT;
2,222✔
94

95
    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
2,222✔
96
}
2,222✔
97

98
static int DetectHostbitMatchToggle (Packet *p, const DetectXbitsData *fd)
99
{
2✔
100
    switch (fd->tracker) {
2✔
101
        case DETECT_XBITS_TRACK_IPSRC:
1✔
102
            if (p->host_src == NULL) {
1✔
103
                p->host_src = HostGetHostFromHash(&p->src);
×
104
                if (p->host_src == NULL)
×
105
                    return 0;
×
106
            }
×
107
            else
1✔
108
                HostLock(p->host_src);
1✔
109

110
            HostBitToggle(p->host_src, fd->idx, SCTIME_ADD_SECS(p->ts, fd->expire));
1✔
111
            HostUnlock(p->host_src);
1✔
112
            break;
1✔
113
        case DETECT_XBITS_TRACK_IPDST:
1✔
114
            if (p->host_dst == NULL) {
1✔
115
                p->host_dst = HostGetHostFromHash(&p->dst);
1✔
116
                if (p->host_dst == NULL)
1✔
117
                    return 0;
×
118
            }
1✔
119
            else
×
120
                HostLock(p->host_dst);
×
121

122
            HostBitToggle(p->host_dst, fd->idx, SCTIME_ADD_SECS(p->ts, fd->expire));
1✔
123
            HostUnlock(p->host_dst);
1✔
124
            break;
1✔
125
    }
2✔
126
    return 1;
2✔
127
}
2✔
128

129
/* return true even if bit not found */
130
static int DetectHostbitMatchUnset (Packet *p, const DetectXbitsData *fd)
131
{
1✔
132
    switch (fd->tracker) {
1✔
133
        case DETECT_XBITS_TRACK_IPSRC:
1✔
134
            if (p->host_src == NULL) {
1✔
135
                p->host_src = HostLookupHostFromHash(&p->src);
×
136
                if (p->host_src == NULL)
×
137
                    return 1;
×
138
            } else
×
139
                HostLock(p->host_src);
1✔
140

141
            HostBitUnset(p->host_src,fd->idx);
1✔
142
            HostUnlock(p->host_src);
1✔
143
            break;
1✔
144
        case DETECT_XBITS_TRACK_IPDST:
×
145
            if (p->host_dst == NULL) {
×
146
                p->host_dst = HostLookupHostFromHash(&p->dst);
×
147
                if (p->host_dst == NULL)
×
148
                    return 1;
×
149
            } else
×
150
                HostLock(p->host_dst);
×
151

152
            HostBitUnset(p->host_dst,fd->idx);
×
153
            HostUnlock(p->host_dst);
×
154
            break;
×
155
    }
1✔
156
    return 1;
1✔
157
}
1✔
158

159
static int DetectHostbitMatchSet (Packet *p, const DetectXbitsData *fd)
160
{
4✔
161
    switch (fd->tracker) {
4✔
162
        case DETECT_XBITS_TRACK_IPSRC:
4✔
163
            if (p->host_src == NULL) {
4✔
164
                p->host_src = HostGetHostFromHash(&p->src);
4✔
165
                if (p->host_src == NULL)
4✔
166
                    return 0;
×
167
            } else
4✔
UNCOV
168
                HostLock(p->host_src);
×
169

170
            HostBitSet(p->host_src, fd->idx, SCTIME_ADD_SECS(p->ts, fd->expire));
4✔
171
            HostUnlock(p->host_src);
4✔
172
            break;
4✔
173
        case DETECT_XBITS_TRACK_IPDST:
×
174
            if (p->host_dst == NULL) {
×
175
                p->host_dst = HostGetHostFromHash(&p->dst);
×
176
                if (p->host_dst == NULL)
×
177
                    return 0;
×
178
            } else
×
179
                HostLock(p->host_dst);
×
180

181
            HostBitSet(p->host_dst, fd->idx, SCTIME_ADD_SECS(p->ts, fd->expire));
×
182
            HostUnlock(p->host_dst);
×
183
            break;
×
184
    }
4✔
185
    return 1;
4✔
186
}
4✔
187

188
static int DetectHostbitMatchIsset (Packet *p, const DetectXbitsData *fd)
189
{
188✔
190
    int r = 0;
188✔
191
    switch (fd->tracker) {
188✔
192
        case DETECT_XBITS_TRACK_IPSRC:
5✔
193
            if (p->host_src == NULL) {
5✔
194
                p->host_src = HostLookupHostFromHash(&p->src);
1✔
195
                if (p->host_src == NULL)
1✔
196
                    return 0;
1✔
197
            } else
1✔
198
                HostLock(p->host_src);
4✔
199

200
            r = HostBitIsset(p->host_src, fd->idx, p->ts);
4✔
201
            HostUnlock(p->host_src);
4✔
202
            return r;
4✔
203
        case DETECT_XBITS_TRACK_IPDST:
183✔
204
            if (p->host_dst == NULL) {
183✔
205
                p->host_dst = HostLookupHostFromHash(&p->dst);
183✔
206
                if (p->host_dst == NULL)
183✔
207
                    return 0;
92✔
208
            } else
183✔
209
                HostLock(p->host_dst);
×
210

211
            r = HostBitIsset(p->host_dst, fd->idx, p->ts);
91✔
212
            HostUnlock(p->host_dst);
91✔
213
            return r;
91✔
214
    }
188✔
215
    return 0;
×
216
}
188✔
217

218
static int DetectHostbitMatchIsnotset (Packet *p, const DetectXbitsData *fd)
219
{
1✔
220
    int r = 0;
1✔
221
    switch (fd->tracker) {
1✔
UNCOV
222
        case DETECT_XBITS_TRACK_IPSRC:
×
UNCOV
223
            if (p->host_src == NULL) {
×
UNCOV
224
                p->host_src = HostLookupHostFromHash(&p->src);
×
UNCOV
225
                if (p->host_src == NULL)
×
UNCOV
226
                    return 1;
×
UNCOV
227
            } else
×
228
                HostLock(p->host_src);
×
229

230
            r = HostBitIsnotset(p->host_src, fd->idx, p->ts);
×
231
            HostUnlock(p->host_src);
×
232
            return r;
×
233
        case DETECT_XBITS_TRACK_IPDST:
1✔
234
            if (p->host_dst == NULL) {
1✔
235
                p->host_dst = HostLookupHostFromHash(&p->dst);
1✔
236
                if (p->host_dst == NULL)
1✔
237
                    return 1;
1✔
238
            } else
1✔
239
                HostLock(p->host_dst);
×
240

241
            r = HostBitIsnotset(p->host_dst, fd->idx, p->ts);
×
242
            HostUnlock(p->host_dst);
×
243
            return r;
×
244
    }
1✔
245
    return 0;
×
246
}
1✔
247

248
int DetectXbitMatchHost(Packet *p, const DetectXbitsData *xd)
249
{
196✔
250
    switch (xd->cmd) {
196✔
251
        case DETECT_XBITS_CMD_ISSET:
188✔
252
            return DetectHostbitMatchIsset(p,xd);
188✔
253
        case DETECT_XBITS_CMD_ISNOTSET:
1✔
254
            return DetectHostbitMatchIsnotset(p,xd);
1✔
255
        case DETECT_XBITS_CMD_SET:
4✔
256
            return DetectHostbitMatchSet(p,xd);
4✔
257
        case DETECT_XBITS_CMD_UNSET:
1✔
258
            return DetectHostbitMatchUnset(p,xd);
1✔
259
        case DETECT_XBITS_CMD_TOGGLE:
2✔
260
            return DetectHostbitMatchToggle(p,xd);
2✔
261
        default:
×
262
            SCLogError("unknown cmd %" PRIu32 "", xd->cmd);
×
263
            return 0;
×
264
    }
196✔
265

266
    return 0;
×
267
}
196✔
268

269
/*
270
 * returns 0: no match
271
 *         1: match
272
 *        -1: error
273
 */
274

275
static int DetectHostbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
276
        const Signature *s, const SigMatchCtx *ctx)
277
{
196✔
278
    const DetectXbitsData *xd = (const DetectXbitsData *)ctx;
196✔
279
    if (xd == NULL)
196✔
280
        return 0;
×
281

282
    return DetectXbitMatchHost(p, xd);
196✔
283
}
196✔
284

285
static int DetectHostbitParse(const char *str, char *cmd, int cmd_len,
286
    char *name, int name_len, char *dir, int dir_len)
287
{
35✔
288
    int rc;
35✔
289
    size_t pcre2len;
35✔
290

291
    pcre2_match_data *match = NULL;
35✔
292
    int count = DetectParsePcreExec(&parse_regex, &match, str, 0, 0);
35✔
293
    if (count != 2 && count != 3 && count != 4) {
35✔
294
        SCLogError("\"%s\" is not a valid setting for hostbits.", str);
2✔
295
        goto error;
2✔
296
    }
2✔
297

298
    pcre2len = cmd_len;
33✔
299
    rc = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)cmd, &pcre2len);
33✔
300
    if (rc < 0) {
33✔
UNCOV
301
        SCLogError("pcre2_substring_copy_bynumber failed");
×
UNCOV
302
        goto error;
×
UNCOV
303
    }
×
304

305
    if (count >= 3) {
33✔
306
        pcre2len = name_len;
32✔
307
        rc = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)name, &pcre2len);
32✔
308
        if (rc < 0) {
32✔
UNCOV
309
            SCLogError("pcre2_substring_copy_bynumber failed");
×
UNCOV
310
            goto error;
×
UNCOV
311
        }
×
312
        if (count >= 4) {
32✔
313
            pcre2len = dir_len;
18✔
314
            rc = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)dir, &pcre2len);
18✔
315
            if (rc < 0) {
18✔
UNCOV
316
                SCLogError("pcre2_substring_copy_bynumber failed");
×
UNCOV
317
                goto error;
×
UNCOV
318
            }
×
319
        }
18✔
320
    }
32✔
321

322
    pcre2_match_data_free(match);
33✔
323
    return 1;
33✔
324

325
error:
2✔
326
    if (match) {
2✔
327
        pcre2_match_data_free(match);
2✔
328
    }
2✔
329
    return 0;
2✔
330
}
33✔
331

332
int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
333
{
27✔
334
    DetectXbitsData *cd = NULL;
27✔
335
    uint8_t fb_cmd = 0;
27✔
336
    uint8_t hb_dir = 0;
27✔
337
    char fb_cmd_str[16] = "", fb_name[256] = "";
27✔
338
    char hb_dir_str[16] = "";
27✔
339

340
    if (!DetectHostbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str),
27✔
341
            fb_name, sizeof(fb_name), hb_dir_str, sizeof(hb_dir_str))) {
27✔
342
        return -1;
1✔
343
    }
1✔
344

345
    if (strlen(hb_dir_str) > 0) {
26✔
346
        if (strcmp(hb_dir_str, "src") == 0)
15✔
347
            hb_dir = DETECT_XBITS_TRACK_IPSRC;
4✔
348
        else if (strcmp(hb_dir_str, "dst") == 0)
11✔
349
            hb_dir = DETECT_XBITS_TRACK_IPDST;
11✔
UNCOV
350
        else if (strcmp(hb_dir_str, "both") == 0) {
×
351
            //hb_dir = DETECT_XBITS_TRACK_IPBOTH;
UNCOV
352
            SCLogError("'both' not implemented");
×
UNCOV
353
            goto error;
×
UNCOV
354
        } else {
×
355
            // TODO
UNCOV
356
            goto error;
×
UNCOV
357
        }
×
358
    }
15✔
359

360
    if (strcmp(fb_cmd_str,"noalert") == 0) {
26✔
361
        fb_cmd = DETECT_XBITS_CMD_NOALERT;
1✔
362
    } else if (strcmp(fb_cmd_str,"isset") == 0) {
25✔
363
        fb_cmd = DETECT_XBITS_CMD_ISSET;
13✔
364
    } else if (strcmp(fb_cmd_str,"isnotset") == 0) {
18✔
365
        fb_cmd = DETECT_XBITS_CMD_ISNOTSET;
2✔
366
    } else if (strcmp(fb_cmd_str,"set") == 0) {
10✔
367
        fb_cmd = DETECT_XBITS_CMD_SET;
5✔
368
    } else if (strcmp(fb_cmd_str,"unset") == 0) {
6✔
369
        fb_cmd = DETECT_XBITS_CMD_UNSET;
2✔
370
    } else if (strcmp(fb_cmd_str,"toggle") == 0) {
3✔
371
        fb_cmd = DETECT_XBITS_CMD_TOGGLE;
3✔
372
    } else {
3✔
UNCOV
373
        SCLogError("ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str);
×
UNCOV
374
        goto error;
×
UNCOV
375
    }
×
376

377
    switch (fb_cmd) {
26✔
378
        case DETECT_XBITS_CMD_NOALERT:
1✔
379
            if (strlen(fb_name) != 0)
1✔
UNCOV
380
                goto error;
×
381
            s->action &= ~ACTION_ALERT;
1✔
382
            return 0;
1✔
383
        case DETECT_XBITS_CMD_ISNOTSET:
2✔
384
        case DETECT_XBITS_CMD_ISSET:
15✔
385
        case DETECT_XBITS_CMD_SET:
20✔
386
        case DETECT_XBITS_CMD_UNSET:
22✔
387
        case DETECT_XBITS_CMD_TOGGLE:
25✔
388
        default:
25✔
389
            if (strlen(fb_name) == 0)
25✔
UNCOV
390
                goto error;
×
391
            break;
25✔
392
    }
26✔
393

394
    cd = SCMalloc(sizeof(DetectXbitsData));
25✔
395
    if (unlikely(cd == NULL))
25✔
396
        goto error;
×
397

398
    uint32_t varname_id = VarNameStoreRegister(fb_name, VAR_TYPE_HOST_BIT);
25✔
399
    if (unlikely(varname_id == 0))
25✔
400
        goto error;
×
401
    cd->idx = varname_id;
25✔
402
    cd->cmd = fb_cmd;
25✔
403
    cd->tracker = hb_dir;
25✔
404
    cd->type = VAR_TYPE_HOST_BIT;
25✔
405
    cd->expire = 300;
25✔
406

407
    SCLogDebug("idx %" PRIu32 ", cmd %s, name %s",
25✔
408
        cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)");
25✔
409

410
    /* Okay so far so good, lets get this into a SigMatch
411
     * and put it in the Signature. */
412

413
    switch (fb_cmd) {
25✔
414
        /* case DETECT_XBITS_CMD_NOALERT can't happen here */
415

416
        case DETECT_XBITS_CMD_ISNOTSET:
2✔
417
        case DETECT_XBITS_CMD_ISSET:
15✔
418
            /* checks, so packet list */
419
            if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_HOSTBITS, (SigMatchCtx *)cd,
15✔
420
                        DETECT_SM_LIST_MATCH) == NULL) {
15✔
421
                goto error;
×
422
            }
×
423
            break;
15✔
424

425
        case DETECT_XBITS_CMD_SET:
15✔
426
        case DETECT_XBITS_CMD_UNSET:
7✔
427
        case DETECT_XBITS_CMD_TOGGLE:
10✔
428
            /* modifiers, only run when entire sig has matched */
429
            if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_HOSTBITS, (SigMatchCtx *)cd,
10✔
430
                        DETECT_SM_LIST_POSTMATCH) == NULL) {
10✔
431
                goto error;
×
432
            }
×
433
            break;
10✔
434

435
        // suppress coverity warning as scan-build-7 warns w/o this.
436
        // coverity[deadcode : FALSE]
437
        default:
10✔
438
            goto error;
×
439
    }
25✔
440

441
    return 0;
25✔
442

UNCOV
443
error:
×
UNCOV
444
    if (cd != NULL)
×
445
        SCFree(cd);
×
UNCOV
446
    return -1;
×
447
}
25✔
448

449
void DetectHostbitFree (DetectEngineCtx *de_ctx, void *ptr)
450
{
25✔
451
    DetectXbitsData *fd = (DetectXbitsData *)ptr;
25✔
452

453
    if (fd == NULL)
25✔
454
        return;
×
455
    VarNameStoreUnregister(fd->idx, VAR_TYPE_HOST_BIT);
25✔
456

457
    SCFree(fd);
25✔
458
}
25✔
459

460
#ifdef UNITTESTS
461

462
static void HostBitsTestSetup(void)
463
{
2✔
464
    StorageCleanup();
2✔
465
    StorageInit();
2✔
466
    HostBitInitCtx();
2✔
467
    StorageFinalize();
2✔
468
    HostInitConfig(true);
2✔
469
}
2✔
470

471
static void HostBitsTestShutdown(void)
472
{
2✔
473
    HostShutdown();
2✔
474
    StorageCleanup();
2✔
475
}
2✔
476

477
static int HostBitsTestParse01(void)
478
{
1✔
479
    char cmd[16] = "", name[256] = "", dir[16] = "";
1✔
480

481
    /* No direction. */
482
    FAIL_IF(!DetectHostbitParse("isset,name", cmd, sizeof(cmd), name,
1✔
483
            sizeof(name), dir, sizeof(dir)));
1✔
484
    FAIL_IF(strcmp(cmd, "isset") != 0);
1✔
485
    FAIL_IF(strcmp(name, "name") != 0);
1✔
486
    FAIL_IF(strlen(dir));
1✔
487

488
    /* No direction, leading space. */
489
    *cmd = '\0';
1✔
490
    *name = '\0';
1✔
491
    *dir = '\0';
1✔
492
    FAIL_IF(!DetectHostbitParse("isset, name", cmd, sizeof(cmd), name,
1✔
493
            sizeof(name), dir, sizeof(dir)));
1✔
494
    FAIL_IF(strcmp(cmd, "isset") != 0);
1✔
495
    FAIL_IF(strcmp(name, "name") != 0);
1✔
496

497
    /* No direction, trailing space. */
498
    *cmd = '\0';
1✔
499
    *name = '\0';
1✔
500
    *dir = '\0';
1✔
501
    FAIL_IF(!DetectHostbitParse("isset,name ", cmd, sizeof(cmd), name,
1✔
502
            sizeof(name), dir, sizeof(dir)));
1✔
503
    FAIL_IF(strcmp(cmd, "isset") != 0);
1✔
504
    FAIL_IF(strcmp(name, "name") != 0);
1✔
505

506
    /* No direction, leading and trailing space. */
507
    *cmd = '\0';
1✔
508
    *name = '\0';
1✔
509
    *dir = '\0';
1✔
510
    FAIL_IF(!DetectHostbitParse("isset, name ", cmd, sizeof(cmd), name,
1✔
511
            sizeof(name), dir, sizeof(dir)));
1✔
512
    FAIL_IF(strcmp(cmd, "isset") != 0);
1✔
513
    FAIL_IF(strcmp(name, "name") != 0);
1✔
514

515
    /* With direction. */
516
    *cmd = '\0';
1✔
517
    *name = '\0';
1✔
518
    *dir = '\0';
1✔
519
    FAIL_IF(!DetectHostbitParse("isset,name,src", cmd, sizeof(cmd), name,
1✔
520
            sizeof(name), dir, sizeof(dir)));
1✔
521
    FAIL_IF(strcmp(cmd, "isset") != 0);
1✔
522
    FAIL_IF(strcmp(name, "name") != 0);
1✔
523
    FAIL_IF(strcmp(dir, "src") != 0);
1✔
524

525
    /* With direction - leading and trailing spaces on name. */
526
    *cmd = '\0';
1✔
527
    *name = '\0';
1✔
528
    *dir = '\0';
1✔
529
    FAIL_IF(!DetectHostbitParse("isset, name ,src", cmd, sizeof(cmd), name,
1✔
530
            sizeof(name), dir, sizeof(dir)));
1✔
531
    FAIL_IF(strcmp(cmd, "isset") != 0);
1✔
532
    FAIL_IF(strcmp(name, "name") != 0);
1✔
533
    FAIL_IF(strcmp(dir, "src") != 0);
1✔
534

535
    /* With direction - space around direction. */
536
    *cmd = '\0';
1✔
537
    *name = '\0';
1✔
538
    *dir = '\0';
1✔
539
    FAIL_IF(!DetectHostbitParse("isset, name , src ", cmd, sizeof(cmd), name,
1✔
540
            sizeof(name), dir, sizeof(dir)));
1✔
541
    FAIL_IF(strcmp(cmd, "isset") != 0);
1✔
542
    FAIL_IF(strcmp(name, "name") != 0);
1✔
543
    FAIL_IF(strcmp(dir, "src") != 0);
1✔
544

545
    /* Name with space, no direction - should fail. */
546
    *cmd = '\0';
1✔
547
    *name = '\0';
1✔
548
    *dir = '\0';
1✔
549
    FAIL_IF(DetectHostbitParse("isset, name withspace ", cmd, sizeof(cmd), name,
1✔
550
            sizeof(name), dir, sizeof(dir)));
1✔
551

552
    PASS;
1✔
553
}
1✔
554

555
/**
556
 * \test HostBitsTestSig01 is a test for a valid noalert flowbits option
557
 *
558
 *  \retval 1 on success
559
 *  \retval 0 on failure
560
 */
561

562
static int HostBitsTestSig01(void)
563
{
1✔
564
    uint8_t *buf = (uint8_t *)
1✔
565
                    "GET /one/ HTTP/1.1\r\n"
1✔
566
                    "Host: one.example.org\r\n"
1✔
567
                    "\r\n";
1✔
568
    uint16_t buflen = strlen((char *)buf);
1✔
569
    Packet *p = PacketGetFromAlloc();
1✔
570
    FAIL_IF_NULL(p);
1✔
571
    Signature *s = NULL;
1✔
572
    ThreadVars th_v;
1✔
573
    DetectEngineThreadCtx *det_ctx = NULL;
1✔
574
    DetectEngineCtx *de_ctx = NULL;
1✔
575

576
    memset(&th_v, 0, sizeof(th_v));
1✔
577
    StatsThreadInit(&th_v.stats);
1✔
578
    p->src.family = AF_INET;
1✔
579
    p->dst.family = AF_INET;
1✔
580
    p->payload = buf;
1✔
581
    p->payload_len = buflen;
1✔
582
    p->proto = IPPROTO_TCP;
1✔
583

584
    HostBitsTestSetup();
1✔
585

586
    de_ctx = DetectEngineCtxInit();
1✔
587
    FAIL_IF_NULL(de_ctx);
1✔
588

589
    de_ctx->flags |= DE_QUIET;
1✔
590

591
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (hostbits:set,abc; content:\"GET \"; sid:1;)");
1✔
592
    FAIL_IF_NULL(s);
1✔
593

594
    SigGroupBuild(de_ctx);
1✔
595
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
596

597
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1✔
598

599
    PacketFree(p);
1✔
600
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
601
    DetectEngineCtxFree(de_ctx);
1✔
602
    HostBitsTestShutdown();
1✔
603
    StatsThreadCleanup(&th_v.stats);
1✔
604
    PASS;
1✔
605
}
1✔
606

607
/**
608
 * \test various options
609
 *
610
 *  \retval 1 on success
611
 *  \retval 0 on failure
612
 */
613

614
static int HostBitsTestSig02(void)
615
{
1✔
616
    Signature *s = NULL;
1✔
617
    ThreadVars th_v;
1✔
618
    DetectEngineCtx *de_ctx = NULL;
1✔
619

620
    memset(&th_v, 0, sizeof(th_v));
1✔
621

622
    de_ctx = DetectEngineCtxInit();
1✔
623
    FAIL_IF_NULL(de_ctx);
1✔
624

625
    de_ctx->flags |= DE_QUIET;
1✔
626

627
    s = DetectEngineAppendSig(de_ctx,
1✔
628
            "alert ip any any -> any any (hostbits:isset,abc,src; content:\"GET \"; sid:1;)");
1✔
629
    FAIL_IF_NULL(s);
1✔
630

631
    s = DetectEngineAppendSig(de_ctx,
1✔
632
            "alert ip any any -> any any (hostbits:isnotset,abc,dst; content:\"GET \"; sid:2;)");
1✔
633
    FAIL_IF_NULL(s);
1✔
634

635
    s = DetectEngineAppendSig(de_ctx,
1✔
636
            "alert ip any any -> any any (hostbits:!isset,abc,dst; content:\"GET \"; sid:3;)");
1✔
637
    FAIL_IF_NOT_NULL(s);
1✔
638

639
/* TODO reenable after both is supported
640
    s = DetectEngineAppendSig(de_ctx,
641
            "alert ip any any -> any any (hostbits:set,abc,both; content:\"GET \"; sid:3;)");
642
    FAIL_IF_NULL(s);
643
*/
644
    s = DetectEngineAppendSig(de_ctx,
1✔
645
            "alert ip any any -> any any (hostbits:unset,abc,src; content:\"GET \"; sid:4;)");
1✔
646
    FAIL_IF_NULL(s);
1✔
647

648
    s = DetectEngineAppendSig(de_ctx,
1✔
649
            "alert ip any any -> any any (hostbits:toggle,abc,dst; content:\"GET \"; sid:5;)");
1✔
650
    FAIL_IF_NULL(s);
1✔
651

652
    DetectEngineCtxFree(de_ctx);
1✔
653
    PASS;
1✔
654
}
1✔
655

656
/**
657
 * \test HostBitsTestSig03 is a test check idx value
658
 *
659
 *  \retval 1 on success
660
 *  \retval 0 on failure
661
 */
662

663
static int HostBitsTestSig03(void)
664
{
1✔
665
    uint8_t *buf = (uint8_t *)
1✔
666
                    "GET /one/ HTTP/1.1\r\n"
1✔
667
                    "Host: one.example.org\r\n"
1✔
668
                    "\r\n";
1✔
669
    uint16_t buflen = strlen((char *)buf);
1✔
670
    Packet *p = PacketGetFromAlloc();
1✔
671
    if (unlikely(p == NULL))
1✔
672
        return 0;
673
    Signature *s = NULL;
1✔
674
    ThreadVars th_v;
1✔
675
    DetectEngineThreadCtx *det_ctx = NULL;
1✔
676
    DetectEngineCtx *de_ctx = NULL;
1✔
677
    int idx = 0;
1✔
678

679
    memset(&th_v, 0, sizeof(th_v));
1✔
680
    StatsThreadInit(&th_v.stats);
1✔
681
    p->src.family = AF_INET;
1✔
682
    p->dst.family = AF_INET;
1✔
683
    p->payload = buf;
1✔
684
    p->payload_len = buflen;
1✔
685
    p->proto = IPPROTO_TCP;
1✔
686

687
    HostBitsTestSetup();
1✔
688

689
    de_ctx = DetectEngineCtxInit();
1✔
690
    FAIL_IF_NULL(de_ctx);
1✔
691

692
    de_ctx->flags |= DE_QUIET;
1✔
693

694
    s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; hostbits:isset,fbt; content:\"GET \"; sid:1;)");
1✔
695
    FAIL_IF_NULL(s);
1✔
696

697
    idx = VarNameStoreRegister("fbt", VAR_TYPE_HOST_BIT);
1✔
698
    FAIL_IF(idx == 0);
1✔
699

700
    SigGroupBuild(de_ctx);
1✔
701
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1✔
702

703
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1✔
704

705
    PacketFree(p);
1✔
706
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1✔
707
    DetectEngineCtxFree(de_ctx);
1✔
708
    HostBitsTestShutdown();
1✔
709
    StatsThreadCleanup(&th_v.stats);
1✔
710
    PASS;
1✔
711
}
1✔
712

713
/**
714
 * \brief this function registers unit tests for HostBits
715
 */
716
void HostBitsRegisterTests(void)
717
{
1✔
718
    UtRegisterTest("HostBitsTestParse01", HostBitsTestParse01);
1✔
719
    UtRegisterTest("HostBitsTestSig01", HostBitsTestSig01);
1✔
720
    UtRegisterTest("HostBitsTestSig02", HostBitsTestSig02);
1✔
721
    UtRegisterTest("HostBitsTestSig03", HostBitsTestSig03);
1✔
722
}
1✔
723
#endif /* UNITTESTS */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc