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

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

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

43.36
/src/conf.c
1
/* Copyright (C) 2007-2023 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 Endace Technology Limited - Jason Ish <jason.ish@endace.com>
22
 *
23
 * This file provides a basic configuration system for the IDPS
24
 * engine.
25
 *
26
 * NOTE: Setting values should only be done from one thread during
27
 * engine initialization.  Multiple threads should be able access read
28
 * configuration data.  Allowing run time changes to the configuration
29
 * will require some locks.
30
 *
31
 * \todo Consider having the in-memory configuration database a direct
32
 *   reflection of the configuration file and moving command line
33
 *   parameters to a primary lookup table?
34
 *
35
 * \todo Get rid of allow override and go with a simpler first set,
36
 *   stays approach?
37
 */
38

39
#include "suricata-common.h"
40
#include "conf.h"
41
#include "util-unittest.h"
42
#include "util-debug.h"
43
#include "util-path.h"
44
#include "util-conf.h"
45
#include "rust.h"
46

47
/** Maximum size of a complete domain name. */
48
#define NODE_NAME_MAX 1024
49

50
static SCConfNode *root = NULL;
51
static SCConfNode *root_backup = NULL;
52

53
/**
54
 * \brief Helper function to get a node, creating it if it does not
55
 * exist.
56
 *
57
 * This function exits on memory failure as creating configuration
58
 * nodes is usually part of application initialization.
59
 *
60
 * \param parent The node to use as the parent
61
 * \param name The name of the configuration node to get.
62
 * \param final Flag to set created nodes as final or not.
63
 *
64
 * \retval The existing configuration node if it exists, or a newly
65
 *   created node for the provided name.  On error, NULL will be returned.
66
 */
67
SCConfNode *SCConfNodeGetNodeOrCreate(SCConfNode *parent, const char *name, int final)
68
{
74,794✔
69
    SCConfNode *node = NULL;
74,794✔
70
    char node_name[NODE_NAME_MAX];
74,794✔
71
    char *key;
74,794✔
72
    char *next;
74,794✔
73

74
    if (strlcpy(node_name, name, sizeof(node_name)) >= sizeof(node_name)) {
74,794✔
75
        SCLogError("Configuration name too long: %s", name);
37✔
76
        return NULL;
37✔
77
    }
37✔
78

79
    key = node_name;
74,757✔
80

81
    do {
161,998✔
82
        if ((next = strchr(key, '.')) != NULL)
161,998✔
83
            *next++ = '\0';
87,241✔
84
        if ((node = SCConfNodeLookupChild(parent, key)) == NULL) {
161,998✔
85
            node = SCConfNodeNew();
8,609✔
86
            if (unlikely(node == NULL)) {
8,609✔
87
                SCLogWarning("Failed to allocate memory for configuration.");
×
88
                goto end;
×
89
            }
×
90
            node->name = SCStrdup(key);
8,609✔
91
            if (unlikely(node->name == NULL)) {
8,609✔
92
                SCConfNodeFree(node);
×
93
                node = NULL;
×
94
                SCLogWarning("Failed to allocate memory for configuration.");
×
95
                goto end;
×
96
            }
×
97
            node->parent = parent;
8,609✔
98
            node->final = final;
8,609✔
99
            TAILQ_INSERT_TAIL(&parent->head, node, next);
8,609✔
100
        }
8,609✔
101
        key = next;
161,998✔
102
        parent = node;
161,998✔
103
    } while (next != NULL);
161,998✔
104

105
end:
74,757✔
106
    return node;
74,757✔
107
}
74,757✔
108

109
/**
110
 * \brief Wrapper function for SCConfNodeGetNodeOrCreate that operates
111
 *     on the current root node.
112
 */
113
static SCConfNode *SCConfGetNodeOrCreate(const char *name, int final)
114
{
4✔
115
    return SCConfNodeGetNodeOrCreate(root, name, final);
4✔
116
}
4✔
117

118
/**
119
 * \brief Initialize the configuration system.
120
 */
121
void SCConfInit(void)
122
{
7✔
123
    if (root != NULL) {
7✔
124
        SCLogDebug("already initialized");
×
125
        return;
×
126
    }
×
127
    root = SCConfNodeNew();
7✔
128
    if (root == NULL) {
7✔
129
        FatalError("ERROR: Failed to allocate memory for root configuration node, "
×
130
                   "aborting.");
×
131
    }
×
132
    SCLogDebug("configuration module initialized");
7✔
133
}
7✔
134

135
/**
136
 * \brief Allocate a new configuration node.
137
 *
138
 * \retval An allocated configuration node on success, NULL on failure.
139
 */
140
SCConfNode *SCConfNodeNew(void)
141
{
44,461✔
142
    SCConfNode *new;
44,461✔
143

144
    new = SCCalloc(1, sizeof(*new));
44,461✔
145
    if (unlikely(new == NULL)) {
44,461✔
146
        return NULL;
×
147
    }
×
148
    TAILQ_INIT(&new->head);
44,461✔
149

150
    return new;
44,461✔
151
}
44,461✔
152

153
/**
154
 * \brief Free a SCConfNode and all of its children.
155
 *
156
 * \param node The configuration node to SCFree.
157
 */
158
void SCConfNodeFree(SCConfNode *node)
UNCOV
159
{
×
UNCOV
160
    SCConfNode *tmp;
×
161

UNCOV
162
    while ((tmp = TAILQ_FIRST(&node->head))) {
×
UNCOV
163
        TAILQ_REMOVE(&node->head, tmp, next);
×
UNCOV
164
        SCConfNodeFree(tmp);
×
UNCOV
165
    }
×
166

UNCOV
167
    if (node->name != NULL)
×
UNCOV
168
        SCFree(node->name);
×
UNCOV
169
    if (node->val != NULL)
×
UNCOV
170
        SCFree(node->val);
×
UNCOV
171
    SCFree(node);
×
UNCOV
172
}
×
173

174
/**
175
 * \brief Get a SCConfNode by name.
176
 *
177
 * \param name The full name of the configuration node to lookup.
178
 *
179
 * \retval A pointer to SCConfNode is found or NULL if the configuration
180
 *    node does not exist.
181
 */
182
SCConfNode *SCConfGetNode(const char *name)
183
{
14,664,785✔
184
    SCConfNode *node = root;
14,664,785✔
185
    char node_name[NODE_NAME_MAX];
14,664,785✔
186
    char *key;
14,664,785✔
187
    char *next;
14,664,785✔
188

189
    if (strlcpy(node_name, name, sizeof(node_name)) >= sizeof(node_name)) {
14,664,785✔
190
        SCLogError("Configuration name too long: %s", name);
67✔
191
        return NULL;
67✔
192
    }
67✔
193

194
    key = node_name;
14,664,718✔
195
    do {
28,837,694✔
196
        if ((next = strchr(key, '.')) != NULL)
28,837,694✔
197
            *next++ = '\0';
28,246,586✔
198
        node = SCConfNodeLookupChild(node, key);
28,837,694✔
199
        key = next;
28,837,694✔
200
    } while (next != NULL && node != NULL);
28,837,694✔
201

202
    return node;
14,664,718✔
203
}
14,664,785✔
204

205
SCConfNode *SCConfGetFirstNode(const SCConfNode *parent)
UNCOV
206
{
×
UNCOV
207
    return TAILQ_FIRST(&parent->head);
×
UNCOV
208
}
×
209

210
SCConfNode *SCConfGetNextNode(const SCConfNode *node)
UNCOV
211
{
×
UNCOV
212
    return TAILQ_NEXT(node, next);
×
UNCOV
213
}
×
214

215
const char *SCConfGetValueNode(const SCConfNode *node)
UNCOV
216
{
×
UNCOV
217
    return node->val;
×
UNCOV
218
}
×
219

220
/**
221
 * \brief Get the root configuration node.
222
 */
223
SCConfNode *SCConfGetRootNode(void)
224
{
8,464✔
225
    return root;
8,464✔
226
}
8,464✔
227

228
/**
229
 * \brief Set a configuration value.
230
 *
231
 * Configuration values set with this function may be overridden by
232
 * subsequent calls, or if the value appears multiple times in a
233
 * configuration file.
234
 *
235
 * \param name The name of the configuration parameter to set.
236
 * \param val The value of the configuration parameter.
237
 *
238
 * \retval 1 if the value was set otherwise 0.
239
 */
240
int SCConfSet(const char *name, const char *val)
241
{
2✔
242
    SCConfNode *node = SCConfGetNodeOrCreate(name, 0);
2✔
243
    if (node == NULL || node->final) {
2✔
UNCOV
244
        return 0;
×
UNCOV
245
    }
×
246
    if (node->val != NULL)
2✔
247
        SCFree(node->val);
1✔
248
    node->val = SCStrdup(val);
2✔
249
    if (unlikely(node->val == NULL)) {
2✔
250
        return 0;
×
251
    }
×
252
    return 1;
2✔
253
}
2✔
254

255
/**
256
 * \brief Set a configuration parameter from a string.
257
 *
258
 * Where the input string is something like:
259
 *    stream.midstream=true
260
 *
261
 * \param input the input string to be parsed.
262
 *
263
 * \retval 1 if the value of set, otherwise 0.
264
 */
265
int SCConfSetFromString(const char *input, int final)
UNCOV
266
{
×
UNCOV
267
    int retval = 0;
×
UNCOV
268
    char *name = SCStrdup(input), *val = NULL;
×
UNCOV
269
    if (unlikely(name == NULL)) {
×
270
        goto done;
×
271
    }
×
UNCOV
272
    val = strchr(name, '=');
×
UNCOV
273
    if (val == NULL) {
×
274
        goto done;
×
275
    }
×
UNCOV
276
    *val++ = '\0';
×
277

UNCOV
278
    while (isspace((int)name[strlen(name) - 1])) {
×
UNCOV
279
        name[strlen(name) - 1] = '\0';
×
UNCOV
280
    }
×
281

UNCOV
282
    while (isspace((int)*val)) {
×
UNCOV
283
        val++;
×
UNCOV
284
    }
×
285

UNCOV
286
    if (final) {
×
UNCOV
287
        if (!SCConfSetFinal(name, val)) {
×
288
            goto done;
×
289
        }
×
UNCOV
290
    }
×
UNCOV
291
    else {
×
UNCOV
292
        if (!SCConfSet(name, val)) {
×
293
            goto done;
×
294
        }
×
UNCOV
295
    }
×
296

UNCOV
297
    retval = 1;
×
UNCOV
298
done:
×
UNCOV
299
    if (name != NULL) {
×
UNCOV
300
        SCFree(name);
×
UNCOV
301
    }
×
UNCOV
302
    return retval;
×
UNCOV
303
}
×
304

305
/**
306
 * \brief Set a final configuration value.
307
 *
308
 * A final configuration value is a value that cannot be overridden by
309
 * the configuration file.  Its mainly useful for setting values that
310
 * are supplied on the command line prior to the configuration file
311
 * being loaded.  However, a subsequent call to this function can
312
 * override a previously set value.
313
 *
314
 * \param name The name of the configuration parameter to set.
315
 * \param val The value of the configuration parameter.
316
 *
317
 * \retval 1 if the value was set otherwise 0.
318
 */
319
int SCConfSetFinal(const char *name, const char *val)
320
{
2✔
321
    SCConfNode *node = SCConfGetNodeOrCreate(name, 1);
2✔
322
    if (node == NULL) {
2✔
323
        return 0;
×
324
    }
×
325
    if (node->val != NULL)
2✔
UNCOV
326
        SCFree(node->val);
×
327
    node->val = SCStrdup(val);
2✔
328
    if (unlikely(node->val == NULL)) {
2✔
329
        return 0;
×
330
    }
×
331
    node->final = 1;
2✔
332
    return 1;
2✔
333
}
2✔
334

335
/**
336
 * \brief Retrieve the value of a configuration node.
337
 *
338
 * This function will return the value for a configuration node based
339
 * on the full name of the node.  It is possible that the value
340
 * returned could be NULL, this could happen if the requested node
341
 * does exist but is not a node that contains a value, but contains
342
 * children SCConfNodes instead.
343
 *
344
 * \param name Name of configuration parameter to get.
345
 * \param vptr Pointer that will be set to the configuration value parameter.
346
 *   Note that this is just a reference to the actual value, not a copy.
347
 *
348
 * \retval 1 will be returned if the name is found, otherwise 0 will
349
 *   be returned.
350
 */
351
int SCConfGet(const char *name, const char **vptr)
352
{
14,512,732✔
353
    SCConfNode *node = SCConfGetNode(name);
14,512,732✔
354
    if (node == NULL) {
14,512,732✔
355
        SCLogDebug("failed to lookup configuration parameter '%s'", name);
14,467,124✔
356
        return 0;
14,467,124✔
357
    }
14,467,124✔
358
    else {
45,608✔
359
        *vptr = node->val;
45,608✔
360
        return 1;
45,608✔
361
    }
45,608✔
362
}
14,512,732✔
363

364
int SCConfGetChildValue(const SCConfNode *base, const char *name, const char **vptr)
365
{
2✔
366
    SCConfNode *node = SCConfNodeLookupChild(base, name);
2✔
367

368
    if (node == NULL) {
2✔
UNCOV
369
        SCLogDebug("failed to lookup configuration parameter '%s'", name);
×
UNCOV
370
        return 0;
×
UNCOV
371
    }
×
372
    else {
2✔
373
        if (node->val == NULL)
2✔
374
            return 0;
×
375
        *vptr = node->val;
2✔
376
        return 1;
2✔
377
    }
2✔
378
}
2✔
379

380
SCConfNode *SCConfGetChildWithDefault(
381
        const SCConfNode *base, const SCConfNode *dflt, const char *name)
382
{
×
383
    SCConfNode *node = SCConfNodeLookupChild(base, name);
×
384
    if (node != NULL)
×
385
        return node;
×
386

387
    /* Get 'default' value */
388
    if (dflt) {
×
389
        return SCConfNodeLookupChild(dflt, name);
×
390
    }
×
391
    return NULL;
×
392
}
×
393

394
int SCConfGetChildValueWithDefault(
395
        const SCConfNode *base, const SCConfNode *dflt, const char *name, const char **vptr)
UNCOV
396
{
×
UNCOV
397
    int ret = SCConfGetChildValue(base, name, vptr);
×
398
    /* Get 'default' value */
UNCOV
399
    if (ret == 0 && dflt) {
×
UNCOV
400
        return SCConfGetChildValue(dflt, name, vptr);
×
UNCOV
401
    }
×
UNCOV
402
    return ret;
×
UNCOV
403
}
×
404

405
/**
406
 * \brief Retrieve a configuration value as an integer.
407
 *
408
 * \param name Name of configuration parameter to get.
409
 * \param val Pointer to an intmax_t that will be set the
410
 * configuration value.
411
 *
412
 * \retval 1 will be returned if the name is found and was properly
413
 * converted to an integer, otherwise 0 will be returned.
414
 */
415
int SCConfGetInt(const char *name, intmax_t *val)
416
{
98,849✔
417
    const char *strval = NULL;
98,849✔
418
    intmax_t tmpint;
98,849✔
419
    char *endptr;
98,849✔
420

421
    if (SCConfGet(name, &strval) == 0)
98,849✔
422
        return 0;
63,411✔
423

424
    if (strval == NULL) {
35,438✔
425
        SCLogError("malformed integer value "
×
426
                   "for %s: NULL",
×
427
                name);
×
428
        return 0;
×
429
    }
×
430

431
    errno = 0;
35,438✔
432
    tmpint = strtoimax(strval, &endptr, 0);
35,438✔
433
    if (strval[0] == '\0' || *endptr != '\0') {
35,438✔
UNCOV
434
        SCLogError("malformed integer value "
×
UNCOV
435
                   "for %s: '%s'",
×
UNCOV
436
                name, strval);
×
UNCOV
437
        return 0;
×
UNCOV
438
    }
×
439
    if (errno == ERANGE && (tmpint == INTMAX_MAX || tmpint == INTMAX_MIN)) {
35,438✔
440
        SCLogError("integer value for %s out "
×
441
                   "of range: '%s'",
×
442
                name, strval);
×
443
        return 0;
×
444
    }
×
445

446
    *val = tmpint;
35,438✔
447
    return 1;
35,438✔
448
}
35,438✔
449

450
int SCConfGetChildValueInt(const SCConfNode *base, const char *name, intmax_t *val)
451
{
1✔
452
    const char *strval = NULL;
1✔
453
    intmax_t tmpint;
1✔
454
    char *endptr;
1✔
455

456
    if (SCConfGetChildValue(base, name, &strval) == 0)
1✔
UNCOV
457
        return 0;
×
458
    errno = 0;
1✔
459
    tmpint = strtoimax(strval, &endptr, 0);
1✔
460
    if (strval[0] == '\0' || *endptr != '\0') {
1✔
461
        SCLogError("malformed integer value "
×
462
                   "for %s with base %s: '%s'",
×
463
                name, base->name, strval);
×
464
        return 0;
×
465
    }
×
466
    if (errno == ERANGE && (tmpint == INTMAX_MAX || tmpint == INTMAX_MIN)) {
1✔
467
        SCLogError("integer value for %s with "
×
468
                   " base %s out of range: '%s'",
×
469
                name, base->name, strval);
×
470
        return 0;
×
471
    }
×
472

473
    *val = tmpint;
1✔
474
    return 1;
1✔
475
}
1✔
476

477
int SCConfGetChildValueIntWithDefault(
478
        const SCConfNode *base, const SCConfNode *dflt, const char *name, intmax_t *val)
UNCOV
479
{
×
UNCOV
480
    int ret = SCConfGetChildValueInt(base, name, val);
×
481
    /* Get 'default' value */
UNCOV
482
    if (ret == 0 && dflt) {
×
UNCOV
483
        return SCConfGetChildValueInt(dflt, name, val);
×
UNCOV
484
    }
×
UNCOV
485
    return ret;
×
UNCOV
486
}
×
487

488
/**
489
 * \brief Retrieve a configuration value as a boolean.
490
 *
491
 * \param name Name of configuration parameter to get.
492
 * \param val Pointer to an int that will be set to 1 for true, or 0
493
 * for false.
494
 *
495
 * \retval 1 will be returned if the name is found and was properly
496
 * converted to a boolean, otherwise 0 will be returned.
497
 */
498
int SCConfGetBool(const char *name, int *val)
499
{
13,826,354✔
500
    const char *strval = NULL;
13,826,354✔
501

502
    *val = 0;
13,826,354✔
503
    if (SCConfGet(name, &strval) != 1)
13,826,354✔
504
        return 0;
13,826,351✔
505

506
    *val = SCConfValIsTrue(strval);
3✔
507

508
    return 1;
3✔
509
}
13,826,354✔
510

511
/**
512
 * Get a boolean value from the provided SCConfNode.
513
 *
514
 * \retval 1 If the value exists, 0 if not.
515
 */
516
int SCConfGetChildValueBool(const SCConfNode *base, const char *name, int *val)
517
{
1✔
518
    const char *strval = NULL;
1✔
519

520
    *val = 0;
1✔
521
    if (SCConfGetChildValue(base, name, &strval) == 0)
1✔
UNCOV
522
        return 0;
×
523

524
    *val = SCConfValIsTrue(strval);
1✔
525

526
    return 1;
1✔
527
}
1✔
528

529
int SCConfGetChildValueBoolWithDefault(
530
        const SCConfNode *base, const SCConfNode *dflt, const char *name, int *val)
UNCOV
531
{
×
UNCOV
532
    int ret = SCConfGetChildValueBool(base, name, val);
×
533
    /* Get 'default' value */
UNCOV
534
    if (ret == 0 && dflt) {
×
UNCOV
535
        return SCConfGetChildValueBool(dflt, name, val);
×
UNCOV
536
    }
×
UNCOV
537
    return ret;
×
UNCOV
538
}
×
539

540

541
/**
542
 * \brief Check if a value is true.
543
 *
544
 * The value is considered true if it is a string with the value of 1,
545
 * yes, true or on.  The test is not case sensitive, any other value
546
 * is false.
547
 *
548
 * \param val The string to test for a true value.
549
 *
550
 * \retval 1 If the value is true, 0 if not.
551
 */
552
int SCConfValIsTrue(const char *val)
553
{
10,256✔
554
    const char *trues[] = {"1", "yes", "true", "on"};
10,256✔
555
    size_t u;
10,256✔
556

557
    for (u = 0; u < sizeof(trues) / sizeof(trues[0]); u++) {
50,984✔
558
        if (strcasecmp(val, trues[u]) == 0) {
40,827✔
559
            return 1;
99✔
560
        }
99✔
561
    }
40,827✔
562

563
    return 0;
10,157✔
564
}
10,256✔
565

566
/**
567
 * \brief Check if a value is false.
568
 *
569
 * The value is considered false if it is a string with the value of 0,
570
 * no, false or off.  The test is not case sensitive, any other value
571
 * is not false.
572
 *
573
 * \param val The string to test for a false value.
574
 *
575
 * \retval 1 If the value is false, 0 if not.
576
 */
577
int SCConfValIsFalse(const char *val)
578
{
10,158✔
579
    const char *falses[] = {"0", "no", "false", "off"};
10,158✔
580
    size_t u;
10,158✔
581

582
    for (u = 0; u < sizeof(falses) / sizeof(falses[0]); u++) {
20,325✔
583
        if (strcasecmp(val, falses[u]) == 0) {
20,322✔
584
            return 1;
10,155✔
585
        }
10,155✔
586
    }
20,322✔
587

588
    return 0;
3✔
589
}
10,158✔
590

591
/**
592
 * \brief Retrieve a configuration value as a double
593
 *
594
 * \param name Name of configuration parameter to get.
595
 * \param val Pointer to an double that will be set the
596
 * configuration value.
597
 *
598
 * \retval 1 will be returned if the name is found and was properly
599
 * converted to a double, otherwise 0 will be returned.
600
 */
601
int SCConfGetDouble(const char *name, double *val)
602
{
×
603
    const char *strval = NULL;
×
604
    double tmpdo;
×
605
    char *endptr;
×
606

607
    if (SCConfGet(name, &strval) == 0)
×
608
        return 0;
×
609

610
    errno = 0;
×
611
    tmpdo = strtod(strval, &endptr);
×
612
    if (strval[0] == '\0' || *endptr != '\0')
×
613
        return 0;
×
614
    if (errno == ERANGE)
×
615
        return 0;
×
616

617
    *val = tmpdo;
×
618
    return 1;
×
619
}
×
620

621
/**
622
 * \brief Retrieve a configuration value as a float
623
 *
624
 * \param name Name of configuration parameter to get.
625
 * \param val Pointer to an float that will be set the
626
 * configuration value.
627
 *
628
 * \retval 1 will be returned if the name is found and was properly
629
 * converted to a double, otherwise 0 will be returned.
630
 */
631
int SCConfGetFloat(const char *name, float *val)
632
{
1✔
633
    const char *strval = NULL;
1✔
634
    double tmpfl;
1✔
635
    char *endptr;
1✔
636

637
    if (SCConfGet(name, &strval) == 0)
1✔
638
        return 0;
1✔
639

640
    errno = 0;
1✔
UNCOV
641
    tmpfl = strtof(strval, &endptr);
×
UNCOV
642
    if (strval[0] == '\0' || *endptr != '\0')
×
643
        return 0;
×
UNCOV
644
    if (errno == ERANGE)
×
645
        return 0;
×
646

UNCOV
647
    *val = tmpfl;
×
UNCOV
648
    return 1;
×
UNCOV
649
}
×
650

651
/**
652
 * \brief Retrieve a configuration value as a time duration in seconds.
653
 *
654
 * The configuration value is expected to be a string with a number
655
 * followed by an optional time-describing unit (e.g. s, seconds, weeks, years).
656
 * If no unit is specified, seconds are assumed.
657
 *
658
 * \param name Name of configuration parameter to get.
659
 * \param val Pointer to an uint64_t that will be set the
660
 * configuration value in seconds.
661
 *
662
 * \retval 1 will be returned if the name is found and was properly
663
 * converted to a time duration, otherwise 0 will be returned.
664
 */
665
int SCConfGetTime(const char *name, uint64_t *val)
UNCOV
666
{
×
UNCOV
667
    const char *strval = NULL;
×
668

UNCOV
669
    if (SCConfGet(name, &strval) == 0)
×
UNCOV
670
        return 0;
×
671

672
    if (strval == NULL || strval[0] == '\0')
×
673
        return 0;
×
674

675
    if (SCParseTimeDuration(strval, val) != 0)
×
676
        return 0;
×
677

678
    return 1;
×
679
}
×
680

681
/**
682
 * \brief Remove (and SCFree) the provided configuration node.
683
 */
684
void SCConfNodeRemove(SCConfNode *node)
UNCOV
685
{
×
UNCOV
686
    if (node->parent != NULL)
×
UNCOV
687
        TAILQ_REMOVE(&node->parent->head, node, next);
×
UNCOV
688
    SCConfNodeFree(node);
×
UNCOV
689
}
×
690

691
/**
692
 * \brief Remove a configuration parameter from the configuration db.
693
 *
694
 * \param name The name of the configuration parameter to remove.
695
 *
696
 * \retval Returns 1 if the parameter was removed, otherwise 0 is returned
697
 *   most likely indicating the parameter was not set.
698
 */
699
int SCConfRemove(const char *name)
UNCOV
700
{
×
UNCOV
701
    SCConfNode *node;
×
702

UNCOV
703
    node = SCConfGetNode(name);
×
UNCOV
704
    if (node == NULL)
×
705
        return 0;
×
UNCOV
706
    else {
×
UNCOV
707
        SCConfNodeRemove(node);
×
UNCOV
708
        return 1;
×
UNCOV
709
    }
×
UNCOV
710
}
×
711

712
/**
713
 * \brief Creates a backup of the conf_hash hash_table used by the conf API.
714
 */
715
void SCConfCreateContextBackup(void)
UNCOV
716
{
×
UNCOV
717
    root_backup = root;
×
UNCOV
718
    root = NULL;
×
UNCOV
719
}
×
720

721
/**
722
 * \brief Restores the backup of the hash_table present in backup_conf_hash
723
 *        back to conf_hash.
724
 */
725
void SCConfRestoreContextBackup(void)
UNCOV
726
{
×
UNCOV
727
    root = root_backup;
×
UNCOV
728
    root_backup = NULL;
×
UNCOV
729
}
×
730

731
/**
732
 * \brief De-initializes the configuration system.
733
 */
734
void SCConfDeInit(void)
UNCOV
735
{
×
UNCOV
736
    if (root != NULL) {
×
UNCOV
737
        SCConfNodeFree(root);
×
UNCOV
738
        root = NULL;
×
UNCOV
739
    }
×
740

UNCOV
741
    SCLogDebug("configuration module de-initialized");
×
UNCOV
742
}
×
743

744
static char *ConfPrintNameArray(char **name_arr, int level)
UNCOV
745
{
×
UNCOV
746
    static char name[128*128];
×
UNCOV
747
    int i;
×
748

UNCOV
749
    name[0] = '\0';
×
UNCOV
750
    for (i = 0; i <= level; i++) {
×
UNCOV
751
        strlcat(name, name_arr[i], sizeof(name));
×
UNCOV
752
        if (i < level)
×
UNCOV
753
            strlcat(name, ".", sizeof(name));
×
UNCOV
754
    }
×
755

UNCOV
756
    return name;
×
UNCOV
757
}
×
758

759
/**
760
 * \brief Dump a configuration node and all its children.
761
 */
762
void SCConfNodeDump(const SCConfNode *node, const char *prefix)
UNCOV
763
{
×
UNCOV
764
    SCConfNode *child;
×
765

UNCOV
766
    static char *name[128];
×
UNCOV
767
    static int level = -1;
×
768

UNCOV
769
    level++;
×
UNCOV
770
    TAILQ_FOREACH(child, &node->head, next) {
×
UNCOV
771
        name[level] = SCStrdup(child->name);
×
UNCOV
772
        if (unlikely(name[level] == NULL)) {
×
773
            continue;
×
774
        }
×
UNCOV
775
        if (prefix == NULL) {
×
UNCOV
776
            printf("%s = %s\n", ConfPrintNameArray(name, level),
×
UNCOV
777
                child->val);
×
UNCOV
778
        }
×
779
        else {
×
780
            printf("%s.%s = %s\n", prefix,
×
781
                ConfPrintNameArray(name, level), child->val);
×
782
        }
×
UNCOV
783
        SCConfNodeDump(child, prefix);
×
UNCOV
784
        SCFree(name[level]);
×
UNCOV
785
    }
×
UNCOV
786
    level--;
×
UNCOV
787
}
×
788

789
/**
790
 * \brief Dump configuration to stdout.
791
 */
792
void SCConfDump(void)
UNCOV
793
{
×
UNCOV
794
    SCConfNodeDump(root, NULL);
×
UNCOV
795
}
×
796

797
/**
798
 * \brief Check if a node has any children.
799
 *
800
 * Checks if the provided node has any children. Any node that is a
801
 * YAML map or array will have children.
802
 *
803
 * \param node The node to check.
804
 *
805
 * \retval true if node has children
806
 * \retval false if node does not have children
807
 */
808
bool SCConfNodeHasChildren(const SCConfNode *node)
809
{
1✔
810
    if (TAILQ_EMPTY(&node->head)) {
1✔
811
        return false;
1✔
812
    }
1✔
UNCOV
813
    return true;
×
814
}
1✔
815

816
/**
817
 * \brief Lookup a child configuration node by name.
818
 *
819
 * Given a SCConfNode this function will lookup an immediate child
820
 * SCConfNode by name and return the child ConfNode.
821
 *
822
 * \param node The parent configuration node.
823
 * \param name The name of the child node to lookup.
824
 *
825
 * \retval A pointer the child SCConfNode if found otherwise NULL.
826
 */
827
SCConfNode *SCConfNodeLookupChild(const SCConfNode *node, const char *name)
828
{
29,749,293✔
829
    SCConfNode *child;
29,749,293✔
830

831
    if (node == NULL || name == NULL) {
29,749,293✔
832
        return NULL;
4✔
833
    }
4✔
834

835
    TAILQ_FOREACH(child, &node->head, next) {
184,434,817✔
836
        if (child->name != NULL && strcmp(child->name, name) == 0)
184,434,817✔
837
            return child;
15,095,024✔
838
    }
184,434,817✔
839

840
    return NULL;
14,654,265✔
841
}
29,749,289✔
842

843
/**
844
 * \brief Lookup the value of a child configuration node by name.
845
 *
846
 * Given a parent SCConfNode this function will return the value of a
847
 * child configuration node by name returning a reference to that
848
 * value.
849
 *
850
 * \param node The parent configuration node.
851
 * \param name The name of the child node to lookup.
852
 *
853
 * \retval A pointer the child SCConfNodes value if found otherwise NULL.
854
 */
855
const char *SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
856
{
88✔
857
    SCConfNode *child;
88✔
858

859
    child = SCConfNodeLookupChild(node, name);
88✔
860
    if (child != NULL)
88✔
861
        return child->val;
39✔
862

863
    return NULL;
49✔
864
}
88✔
865

866
/**
867
 * \brief Lookup for a key value under a specific node
868
 *
869
 * \return the SCConfNode matching or NULL
870
 */
871

872
SCConfNode *SCConfNodeLookupKeyValue(const SCConfNode *base, const char *key, const char *value)
UNCOV
873
{
×
UNCOV
874
    SCConfNode *child;
×
875

UNCOV
876
    TAILQ_FOREACH(child, &base->head, next) {
×
UNCOV
877
        if (!strncmp(child->val, key, strlen(child->val))) {
×
UNCOV
878
            SCConfNode *subchild;
×
UNCOV
879
            TAILQ_FOREACH(subchild, &child->head, next) {
×
UNCOV
880
                if ((!strcmp(subchild->name, key)) && (!strcmp(subchild->val, value))) {
×
UNCOV
881
                    return child;
×
UNCOV
882
                }
×
UNCOV
883
            }
×
UNCOV
884
        }
×
UNCOV
885
    }
×
886

UNCOV
887
    return NULL;
×
UNCOV
888
}
×
889

890
/**
891
 * \brief Test if a configuration node has a true value.
892
 *
893
 * \param node The parent configuration node.
894
 * \param name The name of the child node to test.
895
 *
896
 * \retval 1 if the child node has a true value, otherwise 0 is
897
 *     returned, even if the child node does not exist.
898
 */
899
int SCConfNodeChildValueIsTrue(const SCConfNode *node, const char *key)
900
{
1✔
901
    const char *val;
1✔
902

903
    val = SCConfNodeLookupChildValue(node, key);
1✔
904

905
    return val != NULL ? SCConfValIsTrue(val) : 0;
1✔
906
}
1✔
907

908
/**
909
 * \brief Test if a configuration node has a false value.
910
 *
911
 * If the field does not exist, or has anything other than a false
912
 * value, this function will return 0.
913
 *
914
 * \param node The parent configuration node.
915
 * \param name The name of the child node to test.
916
 *
917
 * \retval 1 if the child node has a false value, otherwise 0.
918
 */
919
int SCConfNodeChildValueIsFalse(const SCConfNode *node, const char *key)
920
{
×
921
    const char *val;
×
922

923
    val = SCConfNodeLookupChildValue(node, key);
×
924

925
    return val != NULL ? SCConfValIsFalse(val) : 0;
×
926
}
×
927

928
/**
929
 *  \brief Create the path for an include entry
930
 *  \param file The name of the file
931
 *  \retval str Pointer to the string path + sig_file
932
 */
933

934
/**
935
 * \brief Prune a configuration node.
936
 *
937
 * Pruning a configuration is similar to freeing, but only fields that
938
 * may be overridden are, leaving final type parameters.  Additional
939
 * the value of the provided node is also free'd, but the node itself
940
 * is left.
941
 *
942
 * \param node The configuration node to prune.
943
 */
944
void SCConfNodePrune(SCConfNode *node)
945
{
425,889✔
946
    SCConfNode *item, *it;
425,889✔
947

948
    for (item = TAILQ_FIRST(&node->head); item != NULL; item = it) {
464,701✔
949
        it = TAILQ_NEXT(item, next);
38,812✔
950
        if (!item->final) {
38,812✔
951
            SCConfNodePrune(item);
38,812✔
952
            if (TAILQ_EMPTY(&item->head)) {
38,812✔
953
                TAILQ_REMOVE(&node->head, item, next);
38,812✔
954
                if (item->name != NULL)
38,812✔
955
                    SCFree(item->name);
38,812✔
956
                if (item->val != NULL)
38,812✔
957
                    SCFree(item->val);
×
958
                SCFree(item);
38,812✔
959
            }
38,812✔
960
        }
38,812✔
961
    }
38,812✔
962

963
    if (node->val != NULL) {
425,889✔
964
        SCFree(node->val);
11,317✔
965
        node->val = NULL;
11,317✔
966
    }
11,317✔
967
}
425,889✔
968

969
/**
970
 * \brief Check if a node is a sequence or node.
971
 *
972
 * \param node the node to check.
973
 *
974
 * \return 1 if node is a sequence, otherwise 0.
975
 */
976
int SCConfNodeIsSequence(const SCConfNode *node)
977
{
1✔
978
    return node->is_seq == 0 ? 0 : 1;
1✔
979
}
1✔
980

981
/**
982
 * @brief Finds an interface from the list of interfaces.
983
 * @param ifaces_node_name - name of the node which holds a list of interfaces
984
 * @param iface - interfaces name
985
 * @return NULL on failure otherwise a valid pointer
986
 */
987
SCConfNode *SCConfSetIfaceNode(const char *ifaces_node_name, const char *iface)
UNCOV
988
{
×
UNCOV
989
    SCConfNode *if_node;
×
UNCOV
990
    SCConfNode *ifaces_list_node;
×
991
    /* Find initial node which holds all interfaces */
UNCOV
992
    ifaces_list_node = SCConfGetNode(ifaces_node_name);
×
UNCOV
993
    if (ifaces_list_node == NULL) {
×
994
        SCLogError("unable to find %s config", ifaces_node_name);
×
995
        return NULL;
×
996
    }
×
997

UNCOV
998
    if_node = ConfFindDeviceConfig(ifaces_list_node, iface);
×
UNCOV
999
    if (if_node == NULL)
×
UNCOV
1000
        SCLogNotice("unable to find interface %s in DPDK config", iface);
×
1001

UNCOV
1002
    return if_node;
×
UNCOV
1003
}
×
1004

1005
/**
1006
 * @brief Finds and sets root and default node of the interface.
1007
 * @param ifaces_node_name Node which holds list of interfaces
1008
 * @param iface Name of the interface e.g. eth3
1009
 * @param if_root Node which will hold the interface configuration
1010
 * @param if_default Node which is the default configuration in the given list of interfaces
1011
 * @return 0 on success, -ENODEV when neither the root interface nor the default interface was found
1012
 */
1013
int SCConfSetRootAndDefaultNodes(const char *ifaces_node_name, const char *iface,
1014
        SCConfNode **if_root, SCConfNode **if_default)
UNCOV
1015
{
×
UNCOV
1016
    const char *default_iface = "default";
×
UNCOV
1017
    *if_root = SCConfSetIfaceNode(ifaces_node_name, iface);
×
UNCOV
1018
    *if_default = SCConfSetIfaceNode(ifaces_node_name, default_iface);
×
1019

UNCOV
1020
    if (*if_root == NULL && *if_default == NULL) {
×
1021
        SCLogError("unable to find configuration for the interface \"%s\" or the default "
×
1022
                   "configuration (\"%s\")",
×
1023
                iface, default_iface);
×
1024
        return (-ENODEV);
×
1025
    }
×
1026

1027
    /* If there is no setting for current interface use default one as main iface */
UNCOV
1028
    if (*if_root == NULL) {
×
1029
        *if_root = *if_default;
×
1030
        *if_default = NULL;
1031
    }
×
UNCOV
1032
    return 0;
×
UNCOV
1033
}
×
1034

1035
#ifdef UNITTESTS
1036

1037
/**
1038
 * Lookup a non-existant value.
1039
 */
1040
static int ConfTestGetNonExistant(void)
1041
{
1042
    char name[] = "non-existant-value";
1043
    const char *value;
1044

1045
    FAIL_IF(SCConfGet(name, &value));
1046
    PASS;
1047
}
1048

1049
/**
1050
 * Set then lookup a value.
1051
 */
1052
static int ConfTestSetAndGet(void)
1053
{
1054
    char name[] = "some-name";
1055
    char value[] = "some-value";
1056
    const char *value0 = NULL;
1057

1058
    FAIL_IF(SCConfSet(name, value) != 1);
1059
    FAIL_IF(SCConfGet(name, &value0) != 1);
1060
    FAIL_IF(value0 == NULL);
1061
    FAIL_IF(strcmp(value, value0) != 0);
1062

1063
    /* Cleanup. */
1064
    SCConfRemove(name);
1065

1066
    PASS;
1067
}
1068

1069
/**
1070
 * Test that overriding a value is allowed provided allow_override is
1071
 * true and that the config parameter gets the new value.
1072
 */
1073
static int ConfTestOverrideValue1(void)
1074
{
1075
    char name[] = "some-name";
1076
    char value0[] = "some-value";
1077
    char value1[] = "new-value";
1078
    const char *val = NULL;
1079

1080
    FAIL_IF(SCConfSet(name, value0) != 1);
1081
    FAIL_IF(SCConfSet(name, value1) != 1);
1082
    FAIL_IF(SCConfGet(name, &val) != 1);
1083
    FAIL_IF(val == NULL);
1084
    FAIL_IF(strcmp(val, value1) != 0);
1085

1086
    /* Cleanup. */
1087
    SCConfRemove(name);
1088

1089
    PASS;
1090
}
1091

1092
/**
1093
 * Test that a final value will not be overridden by a ConfSet.
1094
 */
1095
static int ConfTestOverrideValue2(void)
1096
{
1097
    char name[] = "some-name";
1098
    char value0[] = "some-value";
1099
    char value1[] = "new-value";
1100
    const char *val = NULL;
1101

1102
    FAIL_IF(SCConfSetFinal(name, value0) != 1);
1103
    FAIL_IF(SCConfSet(name, value1) != 0);
1104
    FAIL_IF(SCConfGet(name, &val) != 1);
1105
    FAIL_IF(val == NULL);
1106
    FAIL_IF(strcmp(val, value0) != 0);
1107

1108
    /* Cleanup. */
1109
    SCConfRemove(name);
1110

1111
    PASS;
1112
}
1113

1114
/**
1115
 * Test retrieving an integer value from the configuration db.
1116
 */
1117
static int ConfTestGetInt(void)
1118
{
1119
    char name[] = "some-int.x";
1120
    intmax_t val;
1121

1122
    FAIL_IF(SCConfSet(name, "0") != 1);
1123
    FAIL_IF(SCConfGetInt(name, &val) != 1);
1124
    FAIL_IF(val != 0);
1125

1126
    FAIL_IF(SCConfSet(name, "-1") != 1);
1127
    FAIL_IF(SCConfGetInt(name, &val) != 1);
1128
    FAIL_IF(val != -1);
1129

1130
    FAIL_IF(SCConfSet(name, "0xffff") != 1);
1131
    FAIL_IF(SCConfGetInt(name, &val) != 1);
1132
    FAIL_IF(val != 0xffff);
1133

1134
    FAIL_IF(SCConfSet(name, "not-an-int") != 1);
1135
    FAIL_IF(SCConfGetInt(name, &val) != 0);
1136

1137
    PASS;
1138
}
1139

1140
/**
1141
 * Test retrieving a boolean value from the configuration db.
1142
 */
1143
static int ConfTestGetBool(void)
1144
{
1145
    char name[] = "some-bool";
1146
    const char *trues[] = {
1147
        "1",
1148
        "on", "ON",
1149
        "yes", "YeS",
1150
        "true", "TRUE",
1151
    };
1152
    const char *falses[] = {
1153
        "0",
1154
        "something",
1155
        "off", "OFF",
1156
        "false", "FalSE",
1157
        "no", "NO",
1158
    };
1159
    int val;
1160
    size_t u;
1161

1162
    for (u = 0; u < sizeof(trues) / sizeof(trues[0]); u++) {
1163
        FAIL_IF(SCConfSet(name, trues[u]) != 1);
1164
        FAIL_IF(SCConfGetBool(name, &val) != 1);
1165
        FAIL_IF(val != 1);
1166
    }
1167

1168
    for (u = 0; u < sizeof(falses) / sizeof(falses[0]); u++) {
1169
        FAIL_IF(SCConfSet(name, falses[u]) != 1);
1170
        FAIL_IF(SCConfGetBool(name, &val) != 1);
1171
        FAIL_IF(val != 0);
1172
    }
1173

1174
    PASS;
1175
}
1176

1177
static int ConfNodeLookupChildTest(void)
1178
{
1179
    const char *test_vals[] = { "one", "two", "three" };
1180
    size_t u;
1181

1182
    SCConfNode *parent = SCConfNodeNew();
1183
    SCConfNode *child;
1184

1185
    for (u = 0; u < sizeof(test_vals)/sizeof(test_vals[0]); u++) {
1186
        child = SCConfNodeNew();
1187
        child->name = SCStrdup(test_vals[u]);
1188
        child->val = SCStrdup(test_vals[u]);
1189
        TAILQ_INSERT_TAIL(&parent->head, child, next);
1190
    }
1191

1192
    child = SCConfNodeLookupChild(parent, "one");
1193
    FAIL_IF(child == NULL);
1194
    FAIL_IF(strcmp(child->name, "one") != 0);
1195
    FAIL_IF(strcmp(child->val, "one") != 0);
1196

1197
    child = SCConfNodeLookupChild(parent, "two");
1198
    FAIL_IF(child == NULL);
1199
    FAIL_IF(strcmp(child->name, "two") != 0);
1200
    FAIL_IF(strcmp(child->val, "two") != 0);
1201

1202
    child = SCConfNodeLookupChild(parent, "three");
1203
    FAIL_IF(child == NULL);
1204
    FAIL_IF(strcmp(child->name, "three") != 0);
1205
    FAIL_IF(strcmp(child->val, "three") != 0);
1206

1207
    child = SCConfNodeLookupChild(parent, "four");
1208
    FAIL_IF(child != NULL);
1209

1210
    FAIL_IF(SCConfNodeLookupChild(NULL, NULL) != NULL);
1211

1212
    if (parent != NULL) {
1213
        SCConfNodeFree(parent);
1214
    }
1215

1216
    PASS;
1217
}
1218

1219
static int ConfNodeLookupChildValueTest(void)
1220
{
1221
    const char *test_vals[] = { "one", "two", "three" };
1222
    size_t u;
1223

1224
    SCConfNode *parent = SCConfNodeNew();
1225
    SCConfNode *child;
1226
    const char *value;
1227

1228
    for (u = 0; u < sizeof(test_vals)/sizeof(test_vals[0]); u++) {
1229
        child = SCConfNodeNew();
1230
        child->name = SCStrdup(test_vals[u]);
1231
        child->val = SCStrdup(test_vals[u]);
1232
        TAILQ_INSERT_TAIL(&parent->head, child, next);
1233
    }
1234

1235
    value = (char *)SCConfNodeLookupChildValue(parent, "one");
1236
    FAIL_IF(value == NULL);
1237
    FAIL_IF(strcmp(value, "one") != 0);
1238

1239
    value = (char *)SCConfNodeLookupChildValue(parent, "two");
1240
    FAIL_IF(value == NULL);
1241
    FAIL_IF(strcmp(value, "two") != 0);
1242

1243
    value = (char *)SCConfNodeLookupChildValue(parent, "three");
1244
    FAIL_IF(value == NULL);
1245
    FAIL_IF(strcmp(value, "three") != 0);
1246

1247
    value = (char *)SCConfNodeLookupChildValue(parent, "four");
1248
    FAIL_IF(value != NULL);
1249

1250
    SCConfNodeFree(parent);
1251

1252
    PASS;
1253
}
1254

1255
static int ConfGetChildValueWithDefaultTest(void)
1256
{
1257
    const char  *val = "";
1258
    SCConfCreateContextBackup();
1259
    SCConfInit();
1260
    SCConfSet("af-packet.0.interface", "eth0");
1261
    SCConfSet("af-packet.1.interface", "default");
1262
    SCConfSet("af-packet.1.cluster-type", "cluster_cpu");
1263

1264
    SCConfNode *myroot = SCConfGetNode("af-packet.0");
1265
    SCConfNode *dflt = SCConfGetNode("af-packet.1");
1266
    SCConfGetChildValueWithDefault(myroot, dflt, "cluster-type", &val);
1267
    FAIL_IF(strcmp(val, "cluster_cpu"));
1268

1269
    SCConfSet("af-packet.0.cluster-type", "cluster_flow");
1270
    SCConfGetChildValueWithDefault(myroot, dflt, "cluster-type", &val);
1271

1272
    FAIL_IF(strcmp(val, "cluster_flow"));
1273

1274
    SCConfDeInit();
1275
    SCConfRestoreContextBackup();
1276
    PASS;
1277
}
1278

1279
static int ConfGetChildValueIntWithDefaultTest(void)
1280
{
1281
    intmax_t val = 0;
1282
    SCConfCreateContextBackup();
1283
    SCConfInit();
1284
    SCConfSet("af-packet.0.interface", "eth0");
1285
    SCConfSet("af-packet.1.interface", "default");
1286
    SCConfSet("af-packet.1.threads", "2");
1287

1288
    SCConfNode *myroot = SCConfGetNode("af-packet.0");
1289
    SCConfNode *dflt = SCConfGetNode("af-packet.1");
1290
    SCConfGetChildValueIntWithDefault(myroot, dflt, "threads", &val);
1291
    FAIL_IF(val != 2);
1292

1293
    SCConfSet("af-packet.0.threads", "1");
1294
    SCConfGetChildValueIntWithDefault(myroot, dflt, "threads", &val);
1295
    FAIL_IF(val != 1);
1296

1297
    SCConfDeInit();
1298
    SCConfRestoreContextBackup();
1299

1300
    PASS;
1301
}
1302

1303
static int ConfGetChildValueBoolWithDefaultTest(void)
1304
{
1305
    int val;
1306
    SCConfCreateContextBackup();
1307
    SCConfInit();
1308
    SCConfSet("af-packet.0.interface", "eth0");
1309
    SCConfSet("af-packet.1.interface", "default");
1310
    SCConfSet("af-packet.1.use-mmap", "yes");
1311

1312
    SCConfNode *myroot = SCConfGetNode("af-packet.0");
1313
    SCConfNode *dflt = SCConfGetNode("af-packet.1");
1314
    SCConfGetChildValueBoolWithDefault(myroot, dflt, "use-mmap", &val);
1315
    FAIL_IF(val == 0);
1316

1317
    SCConfSet("af-packet.0.use-mmap", "no");
1318
    SCConfGetChildValueBoolWithDefault(myroot, dflt, "use-mmap", &val);
1319
    FAIL_IF(val);
1320

1321
    SCConfDeInit();
1322
    SCConfRestoreContextBackup();
1323

1324
    PASS;
1325
}
1326

1327
/**
1328
 * Test the removal of a configuration node.
1329
 */
1330
static int ConfNodeRemoveTest(void)
1331
{
1332
    SCConfCreateContextBackup();
1333
    SCConfInit();
1334

1335
    FAIL_IF(SCConfSet("some.nested.parameter", "blah") != 1);
1336

1337
    SCConfNode *node = SCConfGetNode("some.nested.parameter");
1338
    FAIL_IF(node == NULL);
1339
    SCConfNodeRemove(node);
1340

1341
    node = SCConfGetNode("some.nested.parameter");
1342
    FAIL_IF(node != NULL);
1343

1344
    SCConfDeInit();
1345
    SCConfRestoreContextBackup();
1346

1347
    PASS;
1348
}
1349

1350
static int ConfSetTest(void)
1351
{
1352
    SCConfCreateContextBackup();
1353
    SCConfInit();
1354

1355
    /* Set some value with 2 levels. */
1356
    FAIL_IF(SCConfSet("one.two", "three") != 1);
1357
    SCConfNode *n = SCConfGetNode("one.two");
1358
    FAIL_IF(n == NULL);
1359

1360
    /* Set another 2 level parameter with the same first level, this
1361
     * used to trigger a bug that caused the second level of the name
1362
     * to become a first level node. */
1363
    FAIL_IF(SCConfSet("one.three", "four") != 1);
1364

1365
    n = SCConfGetNode("one.three");
1366
    FAIL_IF(n == NULL);
1367

1368
    /* A top level node of "three" should not exist. */
1369
    n = SCConfGetNode("three");
1370
    FAIL_IF(n != NULL);
1371

1372
    SCConfDeInit();
1373
    SCConfRestoreContextBackup();
1374

1375
    PASS;
1376
}
1377

1378
static int ConfGetNodeOrCreateTest(void)
1379
{
1380
    SCConfNode *node;
1381

1382
    SCConfCreateContextBackup();
1383
    SCConfInit();
1384

1385
    /* Get a node that should not exist, give it a value, re-get it
1386
     * and make sure the second time it returns the existing node. */
1387
    node = SCConfGetNodeOrCreate("node0", 0);
1388
    FAIL_IF(node == NULL);
1389
    FAIL_IF(node->parent == NULL || node->parent != root);
1390
    FAIL_IF(node->val != NULL);
1391
    node->val = SCStrdup("node0");
1392
    node = SCConfGetNodeOrCreate("node0", 0);
1393
    FAIL_IF(node == NULL);
1394
    FAIL_IF(node->val == NULL);
1395
    FAIL_IF(strcmp(node->val, "node0") != 0);
1396

1397
    /* Do the same, but for something deeply nested. */
1398
    node = SCConfGetNodeOrCreate("parent.child.grandchild", 0);
1399
    FAIL_IF(node == NULL);
1400
    FAIL_IF(node->parent == NULL || node->parent == root);
1401
    FAIL_IF(node->val != NULL);
1402
    node->val = SCStrdup("parent.child.grandchild");
1403
    node = SCConfGetNodeOrCreate("parent.child.grandchild", 0);
1404
    FAIL_IF(node == NULL);
1405
    FAIL_IF(node->val == NULL);
1406
    FAIL_IF(strcmp(node->val, "parent.child.grandchild") != 0);
1407

1408
    /* Test that 2 child nodes have the same root. */
1409
    SCConfNode *child1 = SCConfGetNodeOrCreate("parent.kids.child1", 0);
1410
    SCConfNode *child2 = SCConfGetNodeOrCreate("parent.kids.child2", 0);
1411
    FAIL_IF(child1 == NULL || child2 == NULL);
1412
    FAIL_IF(child1->parent != child2->parent);
1413
    FAIL_IF(strcmp(child1->parent->name, "kids") != 0);
1414

1415
    SCConfDeInit();
1416
    SCConfRestoreContextBackup();
1417

1418
    PASS;
1419
}
1420

1421
static int ConfNodePruneTest(void)
1422
{
1423
    SCConfNode *node;
1424

1425
    SCConfCreateContextBackup();
1426
    SCConfInit();
1427

1428
    /* Test that final nodes exist after a prune. */
1429
    FAIL_IF(SCConfSet("node.notfinal", "notfinal") != 1);
1430
    FAIL_IF(SCConfSetFinal("node.final", "final") != 1);
1431
    FAIL_IF(SCConfGetNode("node.notfinal") == NULL);
1432
    FAIL_IF(SCConfGetNode("node.final") == NULL);
1433
    FAIL_IF((node = SCConfGetNode("node")) == NULL);
1434
    SCConfNodePrune(node);
1435
    FAIL_IF(SCConfGetNode("node.notfinal") != NULL);
1436
    FAIL_IF(SCConfGetNode("node.final") == NULL);
1437

1438
    /* Test that everything under a final node exists after a prune. */
1439
    FAIL_IF(SCConfSet("node.final.one", "one") != 1);
1440
    FAIL_IF(SCConfSet("node.final.two", "two") != 1);
1441
    SCConfNodePrune(node);
1442
    FAIL_IF(SCConfNodeLookupChild(node, "final") == NULL);
1443
    FAIL_IF(SCConfGetNode("node.final.one") == NULL);
1444
    FAIL_IF(SCConfGetNode("node.final.two") == NULL);
1445

1446
    SCConfDeInit();
1447
    SCConfRestoreContextBackup();
1448

1449
    PASS;
1450
}
1451

1452
static int ConfNodeIsSequenceTest(void)
1453
{
1454
    SCConfNode *node = SCConfNodeNew();
1455
    FAIL_IF(node == NULL);
1456
    FAIL_IF(SCConfNodeIsSequence(node));
1457
    node->is_seq = 1;
1458
    FAIL_IF(!SCConfNodeIsSequence(node));
1459

1460
    if (node != NULL) {
1461
        SCConfNodeFree(node);
1462
    }
1463
    PASS;
1464
}
1465

1466
static int ConfSetFromStringTest(void)
1467
{
1468
    SCConfNode *n;
1469

1470
    SCConfCreateContextBackup();
1471
    SCConfInit();
1472

1473
    FAIL_IF_NOT(SCConfSetFromString("stream.midstream=true", 0));
1474
    n = SCConfGetNode("stream.midstream");
1475
    FAIL_IF_NULL(n);
1476
    FAIL_IF_NULL(n->val);
1477
    FAIL_IF(strcmp("true", n->val));
1478

1479
    FAIL_IF_NOT(SCConfSetFromString("stream.midstream =false", 0));
1480
    n = SCConfGetNode("stream.midstream");
1481
    FAIL_IF_NULL(n);
1482
    FAIL_IF(n->val == NULL || strcmp("false", n->val));
1483

1484
    FAIL_IF_NOT(SCConfSetFromString("stream.midstream= true", 0));
1485
    n = SCConfGetNode("stream.midstream");
1486
    FAIL_IF_NULL(n);
1487
    FAIL_IF(n->val == NULL || strcmp("true", n->val));
1488

1489
    FAIL_IF_NOT(SCConfSetFromString("stream.midstream = false", 0));
1490
    n = SCConfGetNode("stream.midstream");
1491
    FAIL_IF_NULL(n);
1492
    FAIL_IF(n->val == NULL || strcmp("false", n->val));
1493

1494
    SCConfDeInit();
1495
    SCConfRestoreContextBackup();
1496
    PASS;
1497
}
1498

1499
static int ConfNodeHasChildrenTest(void)
1500
{
1501
    SCConfCreateContextBackup();
1502
    SCConfInit();
1503

1504
    /* Set a plain key with value. */
1505
    SCConfSet("no-children", "value");
1506
    SCConfNode *n = SCConfGetNode("no-children");
1507
    FAIL_IF_NULL(n);
1508
    FAIL_IF(SCConfNodeHasChildren(n));
1509

1510
    /* Set a key with a sub key to a value. This makes the first key a
1511
     * map. */
1512
    SCConfSet("parent.child", "value");
1513
    n = SCConfGetNode("parent");
1514
    FAIL_IF_NULL(n);
1515
    FAIL_IF(!SCConfNodeHasChildren(n));
1516

1517
    SCConfDeInit();
1518
    SCConfRestoreContextBackup();
1519
    PASS;
1520
}
1521

1522
void SCConfRegisterTests(void)
1523
{
1524
    UtRegisterTest("ConfTestGetNonExistant", ConfTestGetNonExistant);
1525
    UtRegisterTest("ConfSetTest", ConfSetTest);
1526
    UtRegisterTest("ConfTestSetAndGet", ConfTestSetAndGet);
1527
    UtRegisterTest("ConfTestOverrideValue1", ConfTestOverrideValue1);
1528
    UtRegisterTest("ConfTestOverrideValue2", ConfTestOverrideValue2);
1529
    UtRegisterTest("ConfTestGetInt", ConfTestGetInt);
1530
    UtRegisterTest("ConfTestGetBool", ConfTestGetBool);
1531
    UtRegisterTest("ConfNodeLookupChildTest", ConfNodeLookupChildTest);
1532
    UtRegisterTest("ConfNodeLookupChildValueTest",
1533
                   ConfNodeLookupChildValueTest);
1534
    UtRegisterTest("ConfNodeRemoveTest", ConfNodeRemoveTest);
1535
    UtRegisterTest("ConfGetChildValueWithDefaultTest",
1536
                   ConfGetChildValueWithDefaultTest);
1537
    UtRegisterTest("ConfGetChildValueIntWithDefaultTest",
1538
                   ConfGetChildValueIntWithDefaultTest);
1539
    UtRegisterTest("ConfGetChildValueBoolWithDefaultTest",
1540
                   ConfGetChildValueBoolWithDefaultTest);
1541
    UtRegisterTest("ConfGetNodeOrCreateTest", ConfGetNodeOrCreateTest);
1542
    UtRegisterTest("ConfNodePruneTest", ConfNodePruneTest);
1543
    UtRegisterTest("ConfNodeIsSequenceTest", ConfNodeIsSequenceTest);
1544
    UtRegisterTest("ConfSetFromStringTest", ConfSetFromStringTest);
1545
    UtRegisterTest("ConfNodeHasChildrenTest", ConfNodeHasChildrenTest);
1546
}
1547

1548
#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