Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/datasets.c
Line
Count
Source
1
/* Copyright (C) 2017-2024 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
24
#include "suricata-common.h"
25
#include "suricata.h"
26
#include "rust.h"
27
#include "conf.h"
28
#include "datasets.h"
29
#include "datasets-string.h"
30
#include "datasets-ipv4.h"
31
#include "datasets-ipv6.h"
32
#include "datasets-md5.h"
33
#include "datasets-sha256.h"
34
#include "datasets-reputation.h"
35
#include "datasets-context-json.h"
36
#include "util-conf.h"
37
#include "util-mem.h"
38
#include "util-thash.h"
39
#include "util-print.h"
40
#include "util-byte.h"
41
#include "util-misc.h"
42
#include "util-path.h"
43
#include "util-debug.h"
44
#include "util-validate.h"
45
46
SCMutex sets_lock = SCMUTEX_INITIALIZER;
47
static Dataset *sets = NULL;
48
static uint32_t set_ids = 0;
49
50
uint32_t dataset_max_one_hashsize = 65536;
51
uint32_t dataset_max_total_hashsize = 16777216;
52
uint32_t dataset_used_hashsize = 0;
53
54
int DatasetAddwRep(Dataset *set, const uint8_t *data, const uint32_t data_len, DataRepType *rep);
55
static void DatasetUpdateHashsize(const char *name, uint32_t hash_size);
56
57
static inline void DatasetUnlockData(THashData *d)
58
129k
{
59
129k
    (void) THashDecrUsecnt(d);
60
129k
    THashDataUnlock(d);
61
129k
}
62
static bool DatasetIsStatic(const char *save, const char *load);
63
64
enum DatasetTypes DatasetGetTypeFromString(const char *s)
65
0
{
66
0
    if (strcasecmp("md5", s) == 0)
67
0
        return DATASET_TYPE_MD5;
68
0
    if (strcasecmp("sha256", s) == 0)
69
0
        return DATASET_TYPE_SHA256;
70
0
    if (strcasecmp("string", s) == 0)
71
0
        return DATASET_TYPE_STRING;
72
0
    if (strcasecmp("ipv4", s) == 0)
73
0
        return DATASET_TYPE_IPV4;
74
0
    if (strcasecmp("ip", s) == 0)
75
0
        return DATASET_TYPE_IPV6;
76
0
    return DATASET_TYPE_NOTSET;
77
0
}
78
79
int DatasetAppendSet(Dataset *set)
80
1.03k
{
81
82
1.03k
    if (set->hash == NULL) {
83
0
        return -1;
84
0
    }
85
86
1.03k
    if (SC_ATOMIC_GET(set->hash->memcap_reached)) {
87
0
        SCLogError("dataset too large for set memcap");
88
0
        return -1;
89
0
    }
90
91
1.03k
    SCLogDebug(
92
1.03k
            "set %p/%s type %u save %s load %s", set, set->name, set->type, set->save, set->load);
93
94
1.03k
    set->next = sets;
95
1.03k
    sets = set;
96
97
    /* hash size accounting */
98
1.03k
    DatasetUpdateHashsize(set->name, set->hash->config.hash_size);
99
1.03k
    return 0;
100
1.03k
}
101
102
void DatasetLock(void)
103
237k
{
104
237k
    SCMutexLock(&sets_lock);
105
237k
}
106
107
void DatasetUnlock(void)
108
239k
{
109
239k
    SCMutexUnlock(&sets_lock);
110
239k
}
111
112
Dataset *DatasetAlloc(const char *name)
113
15.8k
{
114
15.8k
    Dataset *set = SCCalloc(1, sizeof(*set));
115
15.8k
    if (set) {
116
15.8k
        set->id = set_ids++;
117
15.8k
    }
118
15.8k
    return set;
119
15.8k
}
120
121
Dataset *DatasetSearchByName(const char *name)
122
73.1k
{
123
73.1k
    Dataset *set = sets;
124
7.54M
    while (set) {
125
7.51M
        if (strcasecmp(name, set->name) == 0 && !set->hidden) {
126
49.8k
            return set;
127
49.8k
        }
128
7.46M
        set = set->next;
129
7.46M
    }
130
23.2k
    return NULL;
131
73.1k
}
132
133
static int DatasetLoadIPv4(Dataset *set)
134
238
{
135
238
    if (strlen(set->load) == 0)
136
93
        return 0;
137
138
145
    SCLogConfig("dataset: %s loading from '%s'", set->name, set->load);
139
145
    const char *fopen_mode = "r";
140
145
    if (strlen(set->save) > 0 && strcmp(set->save, set->load) == 0) {
141
15
        fopen_mode = "a+";
142
15
    }
143
144
145
    int retval = ParseDatasets(set, set->name, set->load, fopen_mode, DSIpv4);
145
145
    if (retval == -2) {
146
10
        FatalErrorOnInit("dataset %s could not be processed", set->name);
147
135
    } else if (retval == -1) {
148
133
        return -1;
149
133
    }
150
151
12
    THashConsolidateMemcap(set->hash);
152
153
12
    return 0;
154
145
}
155
156
int DatasetParseIpv6String(Dataset *set, const char *line, struct in6_addr *in6)
157
0
{
158
    /* Checking IPv6 case */
159
0
    const char *got_colon = strchr(line, ':');
160
0
    if (got_colon) {
161
0
        uint32_t ip6addr[4];
162
0
        if (inet_pton(AF_INET6, line, in6) != 1) {
163
0
            FatalErrorOnInit("dataset data parse failed %s/%s: %s", set->name, set->load, line);
164
0
            return -1;
165
0
        }
166
0
        memcpy(&ip6addr, in6->s6_addr, sizeof(ip6addr));
167
        /* IPv4 in IPv6 notation needs transformation to internal Suricata storage */
168
0
        if (ip6addr[0] == 0 && ip6addr[1] == 0 && ip6addr[2] == 0xFFFF0000) {
169
0
            ip6addr[0] = ip6addr[3];
170
0
            ip6addr[2] = 0;
171
0
            ip6addr[3] = 0;
172
0
            memcpy(in6, ip6addr, sizeof(struct in6_addr));
173
0
        }
174
0
    } else {
175
        /* IPv4 case */
176
0
        struct in_addr in;
177
0
        if (inet_pton(AF_INET, line, &in) != 1) {
178
0
            FatalErrorOnInit("dataset data parse failed %s/%s: %s", set->name, set->load, line);
179
0
            return -1;
180
0
        }
181
0
        memset(in6, 0, sizeof(struct in6_addr));
182
0
        memcpy(in6, &in, sizeof(struct in_addr));
183
0
    }
184
0
    return 0;
185
0
}
186
187
static int DatasetLoadIPv6(Dataset *set)
188
168
{
189
168
    if (strlen(set->load) == 0)
190
67
        return 0;
191
192
101
    SCLogConfig("dataset: %s loading from '%s'", set->name, set->load);
193
101
    const char *fopen_mode = "r";
194
101
    if (strlen(set->save) > 0 && strcmp(set->save, set->load) == 0) {
195
10
        fopen_mode = "a+";
196
10
    }
197
198
101
    int retval = ParseDatasets(set, set->name, set->load, fopen_mode, DSIpv6);
199
101
    if (retval == -2) {
200
4
        FatalErrorOnInit("dataset %s could not be processed", set->name);
201
97
    } else if (retval == -1) {
202
83
        return -1;
203
83
    }
204
205
18
    THashConsolidateMemcap(set->hash);
206
207
18
    return 0;
208
101
}
209
210
static int DatasetLoadMd5(Dataset *set)
211
8.99k
{
212
8.99k
    if (strlen(set->load) == 0)
213
217
        return 0;
214
215
8.77k
    SCLogConfig("dataset: %s loading from '%s'", set->name, set->load);
216
8.77k
    const char *fopen_mode = "r";
217
8.77k
    if (strlen(set->save) > 0 && strcmp(set->save, set->load) == 0) {
218
291
        fopen_mode = "a+";
219
291
    }
220
221
8.77k
    int retval = ParseDatasets(set, set->name, set->load, fopen_mode, DSMd5);
222
8.77k
    if (retval == -2) {
223
22
        FatalErrorOnInit("dataset %s could not be processed", set->name);
224
8.75k
    } else if (retval == -1) {
225
8.63k
        return -1;
226
8.63k
    }
227
228
142
    THashConsolidateMemcap(set->hash);
229
230
142
    return 0;
231
8.77k
}
232
233
static int DatasetLoadSha256(Dataset *set)
234
2.18k
{
235
2.18k
    if (strlen(set->load) == 0)
236
60
        return 0;
237
238
2.12k
    SCLogConfig("dataset: %s loading from '%s'", set->name, set->load);
239
2.12k
    const char *fopen_mode = "r";
240
2.12k
    if (strlen(set->save) > 0 && strcmp(set->save, set->load) == 0) {
241
107
        fopen_mode = "a+";
242
107
    }
243
244
2.12k
    int retval = ParseDatasets(set, set->name, set->load, fopen_mode, DSSha256);
245
2.12k
    if (retval == -2) {
246
1
        FatalErrorOnInit("dataset %s could not be processed", set->name);
247
2.11k
    } else if (retval == -1) {
248
2.11k
        return -1;
249
2.11k
    }
250
251
6
    THashConsolidateMemcap(set->hash);
252
253
6
    return 0;
254
2.12k
}
255
256
static int DatasetLoadString(Dataset *set)
257
3.93k
{
258
3.93k
    if (strlen(set->load) == 0)
259
256
        return 0;
260
261
3.67k
    SCLogConfig("dataset: %s loading from '%s'", set->name, set->load);
262
263
3.67k
    const char *fopen_mode = "r";
264
3.67k
    if (strlen(set->save) > 0 && strcmp(set->save, set->load) == 0) {
265
54
        fopen_mode = "a+";
266
54
    }
267
268
3.67k
    int retval = ParseDatasets(set, set->name, set->load, fopen_mode, DSString);
269
3.67k
    if (retval == -2) {
270
1
        FatalErrorOnInit("dataset %s could not be processed", set->name);
271
3.67k
    } else if (retval == -1) {
272
3.67k
        return -1;
273
3.67k
    }
274
275
1
    THashConsolidateMemcap(set->hash);
276
277
1
    return 0;
278
3.67k
}
279
280
extern bool g_system;
281
282
enum DatasetGetPathType {
283
    TYPE_STATE,
284
    TYPE_LOAD,
285
};
286
287
static void DatasetGetPath(
288
        const char *in_path, char *out_path, size_t out_size, enum DatasetGetPathType type)
289
0
{
290
0
    char path[PATH_MAX];
291
0
    struct stat st;
292
293
0
    if (PathIsAbsolute(in_path)) {
294
0
        strlcpy(path, in_path, sizeof(path));
295
0
        strlcpy(out_path, path, out_size);
296
0
        return;
297
0
    }
298
299
0
    const char *data_dir = ConfigGetDataDirectory();
300
0
    if (stat(data_dir, &st) != 0) {
301
0
        SCLogDebug("data-dir '%s': %s", data_dir, strerror(errno));
302
0
        return;
303
0
    }
304
305
0
    snprintf(path, sizeof(path), "%s/%s", data_dir, in_path); // TODO WINDOWS
306
307
0
    if (type == TYPE_LOAD) {
308
0
        if (stat(path, &st) != 0) {
309
0
            SCLogDebug("path %s: %s", path, strerror(errno));
310
0
            if (!g_system) {
311
0
                snprintf(path, sizeof(path), "%s", in_path);
312
0
            }
313
0
        }
314
0
    }
315
0
    strlcpy(out_path, path, out_size);
316
0
    SCLogDebug("in_path \'%s\' => \'%s\'", in_path, out_path);
317
0
}
318
319
/** \brief look for set by name without creating it */
320
Dataset *DatasetFind(const char *name, enum DatasetTypes type)
321
0
{
322
0
    DatasetLock();
323
0
    Dataset *set = DatasetSearchByName(name);
324
0
    if (set) {
325
0
        if (set->type != type) {
326
0
            DatasetUnlock();
327
0
            return NULL;
328
0
        }
329
0
    }
330
0
    DatasetUnlock();
331
0
    return set;
332
0
}
333
334
static bool DatasetCheckHashsize(const char *name, uint32_t hash_size)
335
17.1k
{
336
17.1k
    if (dataset_max_one_hashsize > 0 && hash_size > dataset_max_one_hashsize) {
337
1.28k
        SCLogError("hashsize %u in dataset '%s' exceeds configured 'single-hashsize' limit (%u)",
338
1.28k
                hash_size, name, dataset_max_one_hashsize);
339
1.28k
        return false;
340
1.28k
    }
341
    // we cannot underflow as we know from conf loading that
342
    // dataset_max_total_hashsize >= dataset_max_one_hashsize if dataset_max_total_hashsize > 0
343
15.8k
    if (dataset_max_total_hashsize > 0 &&
344
15.8k
            dataset_max_total_hashsize - hash_size < dataset_used_hashsize) {
345
0
        SCLogError("hashsize %u in dataset '%s' exceeds configured 'total-hashsizes' limit (%u, in "
346
0
                   "use %u)",
347
0
                hash_size, name, dataset_max_total_hashsize, dataset_used_hashsize);
348
0
        return false;
349
0
    }
350
351
15.8k
    return true;
352
15.8k
}
353
354
static void DatasetUpdateHashsize(const char *name, uint32_t hash_size)
355
1.03k
{
356
1.03k
    if (dataset_max_total_hashsize > 0) {
357
1.03k
        dataset_used_hashsize += hash_size;
358
1.03k
        SCLogDebug("set %s adding with hash_size %u", name, hash_size);
359
1.03k
    }
360
1.03k
}
361
362
/**
363
 * \return -1 on error
364
 * \return 0 on successful creation
365
 * \return 1 if the dataset already exists
366
 *
367
 * Calling function is responsible for locking via DatasetLock()
368
 */
369
int DatasetGetOrCreate(const char *name, enum DatasetTypes type, const char *save, const char *load,
370
        uint64_t *memcap, uint32_t *hashsize, Dataset **ret_set)
371
73.1k
{
372
73.1k
    uint64_t default_memcap = 0;
373
73.1k
    uint32_t default_hashsize = 0;
374
73.1k
    if (strlen(name) > DATASET_NAME_MAX_LEN) {
375
0
        return -1;
376
0
    }
377
378
73.1k
    Dataset *set = DatasetSearchByName(name);
379
73.1k
    if (set) {
380
49.8k
        if (type != DATASET_TYPE_NOTSET && set->type != type) {
381
1.49k
            SCLogError("dataset %s already "
382
1.49k
                       "exists and is of type %u",
383
1.49k
                    set->name, set->type);
384
1.49k
            return -1;
385
1.49k
        }
386
387
48.3k
        if ((save == NULL || strlen(save) == 0) &&
388
44.3k
            (load == NULL || strlen(load) == 0)) {
389
            // OK, rule keyword doesn't have to set state/load,
390
            // even when yaml set has set it.
391
32.2k
        } else {
392
16.1k
            if ((save == NULL && strlen(set->save) > 0) ||
393
16.1k
                    (save != NULL && strcmp(set->save, save) != 0)) {
394
1.97k
                SCLogError("dataset %s save mismatch: %s != %s", set->name, set->save, save);
395
1.97k
                DatasetUnlock();
396
1.97k
                return -1;
397
1.97k
            }
398
14.1k
            if ((load == NULL && strlen(set->load) > 0) ||
399
14.1k
                    (load != NULL && strcmp(set->load, load) != 0)) {
400
10.5k
                SCLogError("dataset %s load mismatch: %s != %s", set->name, set->load, load);
401
10.5k
                return -1;
402
10.5k
            }
403
14.1k
        }
404
405
35.8k
        *ret_set = set;
406
35.8k
        return 1;
407
48.3k
    }
408
409
23.2k
    if (type == DATASET_TYPE_NOTSET) {
410
6.12k
        SCLogError("dataset %s not defined", name);
411
6.12k
        goto out_err;
412
6.12k
    }
413
414
17.1k
    DatasetGetDefaultMemcap(&default_memcap, &default_hashsize);
415
17.1k
    if (*hashsize == 0) {
416
10.4k
        *hashsize = default_hashsize;
417
10.4k
    }
418
17.1k
    if (*memcap == 0) {
419
16.9k
        *memcap = default_memcap;
420
16.9k
    }
421
422
17.1k
    if (!DatasetCheckHashsize(name, *hashsize)) {
423
1.28k
        goto out_err;
424
1.28k
    }
425
426
15.8k
    set = DatasetAlloc(name);
427
15.8k
    if (set == NULL) {
428
0
        goto out_err;
429
0
    }
430
431
15.8k
    strlcpy(set->name, name, sizeof(set->name));
432
15.8k
    set->type = type;
433
15.8k
    if (save && strlen(save)) {
434
555
        strlcpy(set->save, save, sizeof(set->save));
435
555
        SCLogDebug("name %s save '%s'", name, set->save);
436
555
    }
437
15.8k
    if (load && strlen(load)) {
438
15.1k
        strlcpy(set->load, load, sizeof(set->load));
439
15.1k
        SCLogDebug("set \'%s\' loading \'%s\' from \'%s\'", set->name, load, set->load);
440
15.1k
    }
441
442
15.8k
    *ret_set = set;
443
15.8k
    return 0;
444
7.41k
out_err:
445
7.41k
    if (set) {
446
0
        SCFree(set);
447
0
    }
448
7.41k
    return -1;
449
15.8k
}
450
451
Dataset *DatasetGet(const char *name, enum DatasetTypes type, const char *save, const char *load,
452
        uint64_t memcap, uint32_t hashsize)
453
72.4k
{
454
72.4k
    Dataset *set = NULL;
455
456
72.4k
    DatasetLock();
457
72.4k
    int ret = DatasetGetOrCreate(name, type, save, load, &memcap, &hashsize, &set);
458
72.4k
    if (ret < 0) {
459
21.2k
        SCLogError("dataset %s creation failed", name);
460
21.2k
        DatasetUnlock();
461
21.2k
        return NULL;
462
21.2k
    }
463
51.1k
    if (ret == 1) {
464
35.4k
        SCLogDebug("dataset %s already exists", name);
465
35.4k
        DatasetUnlock();
466
35.4k
        return set;
467
35.4k
    }
468
469
15.7k
    char cnf_name[128];
470
15.7k
    snprintf(cnf_name, sizeof(cnf_name), "datasets.%s.hash", name);
471
15.7k
    switch (type) {
472
8.99k
        case DATASET_TYPE_MD5:
473
8.99k
            set->hash = THashInit(cnf_name, sizeof(Md5Type), Md5StrSet, Md5StrFree, Md5StrHash,
474
8.99k
                    Md5StrCompare, NULL, NULL, load != NULL ? 1 : 0, memcap, hashsize);
475
8.99k
            if (set->hash == NULL)
476
4
                goto out_err;
477
8.99k
            if (DatasetLoadMd5(set) < 0)
478
8.63k
                goto out_err;
479
359
            break;
480
4.02k
        case DATASET_TYPE_STRING:
481
4.02k
            set->hash = THashInit(cnf_name, sizeof(StringType), StringSet, StringFree, StringHash,
482
4.02k
                    StringCompare, NULL, StringGetLength, load != NULL ? 1 : 0, memcap, hashsize);
483
4.02k
            if (set->hash == NULL)
484
91
                goto out_err;
485
3.93k
            if (DatasetLoadString(set) < 0)
486
3.67k
                goto out_err;
487
257
            break;
488
2.26k
        case DATASET_TYPE_SHA256:
489
2.26k
            set->hash = THashInit(cnf_name, sizeof(Sha256Type), Sha256StrSet, Sha256StrFree,
490
2.26k
                    Sha256StrHash, Sha256StrCompare, NULL, NULL, load != NULL ? 1 : 0, memcap,
491
2.26k
                    hashsize);
492
2.26k
            if (set->hash == NULL)
493
80
                goto out_err;
494
2.18k
            if (DatasetLoadSha256(set) < 0)
495
2.11k
                goto out_err;
496
66
            break;
497
244
        case DATASET_TYPE_IPV4:
498
244
            set->hash = THashInit(cnf_name, sizeof(IPv4Type), IPv4Set, IPv4Free, IPv4Hash,
499
244
                    IPv4Compare, NULL, NULL, load != NULL ? 1 : 0, memcap, hashsize);
500
244
            if (set->hash == NULL)
501
6
                goto out_err;
502
238
            if (DatasetLoadIPv4(set) < 0)
503
133
                goto out_err;
504
105
            break;
505
176
        case DATASET_TYPE_IPV6:
506
176
            set->hash = THashInit(cnf_name, sizeof(IPv6Type), IPv6Set, IPv6Free, IPv6Hash,
507
176
                    IPv6Compare, NULL, NULL, load != NULL ? 1 : 0, memcap, hashsize);
508
176
            if (set->hash == NULL)
509
8
                goto out_err;
510
168
            if (DatasetLoadIPv6(set) < 0)
511
83
                goto out_err;
512
85
            break;
513
15.7k
    }
514
515
872
    if (DatasetAppendSet(set) < 0) {
516
0
        SCLogError("dataset %s append failed", name);
517
0
        goto out_err;
518
0
    }
519
520
872
    DatasetUnlock();
521
872
    return set;
522
14.8k
out_err:
523
14.8k
    if (set->hash) {
524
14.6k
        THashShutdown(set->hash);
525
14.6k
    }
526
14.8k
    SCFree(set);
527
14.8k
    DatasetUnlock();
528
14.8k
    return NULL;
529
872
}
530
531
static bool DatasetIsStatic(const char *save, const char *load)
532
173k
{
533
    /* A set is static if it does not have any dynamic properties like
534
     * save and/or state defined but has load defined.
535
     * */
536
173k
    if ((load != NULL && strlen(load) > 0) &&
537
2
            (save == NULL || strlen(save) == 0)) {
538
2
        return true;
539
2
    }
540
173k
    return false;
541
173k
}
542
543
void DatasetReload(void)
544
82.2k
{
545
    /* In order to reload the datasets, just mark the current sets as hidden
546
     * and clean them up later.
547
     * New datasets shall be created with the rule reload and do not require
548
     * any intervention.
549
     * */
550
82.2k
    DatasetLock();
551
82.2k
    Dataset *set = sets;
552
3.08M
    while (set) {
553
3.00M
        if (!DatasetIsStatic(set->save, set->load) || set->from_yaml) {
554
3.00M
            SCLogDebug("Not a static set, skipping %s", set->name);
555
3.00M
            set = set->next;
556
3.00M
            continue;
557
3.00M
        }
558
168
        set->hidden = true;
559
168
        if (dataset_max_total_hashsize > 0) {
560
168
            DEBUG_VALIDATE_BUG_ON(set->hash->config.hash_size > dataset_used_hashsize);
561
168
            dataset_used_hashsize -= set->hash->config.hash_size;
562
168
        }
563
168
        SCLogDebug("Set %s at %p hidden successfully", set->name, set);
564
168
        set = set->next;
565
168
    }
566
82.2k
    DatasetUnlock();
567
82.2k
}
568
569
void DatasetPostReloadCleanup(void)
570
82.2k
{
571
82.2k
    DatasetLock();
572
82.2k
    SCLogDebug("Post Reload Cleanup starting.. Hidden sets will be removed");
573
82.2k
    Dataset *cur = sets;
574
82.2k
    Dataset *prev = NULL;
575
3.08M
    while (cur) {
576
3.00M
        Dataset *next = cur->next;
577
3.00M
        if (!cur->hidden) {
578
3.00M
            prev = cur;
579
3.00M
            cur = next;
580
3.00M
            continue;
581
3.00M
        }
582
        // Delete the set in case it was hidden
583
168
        if (prev != NULL) {
584
3
            prev->next = next;
585
165
        } else {
586
165
            sets = next;
587
165
        }
588
168
        THashShutdown(cur->hash);
589
168
        SCFree(cur);
590
168
        cur = next;
591
168
    }
592
82.2k
    DatasetUnlock();
593
82.2k
}
594
595
/* Value reflects THASH_DEFAULT_HASHSIZE which is what the default was earlier,
596
 * despite 2048 commented out in the default yaml. */
597
17.1k
#define DATASETS_HASHSIZE_DEFAULT 4096
598
599
void DatasetGetDefaultMemcap(uint64_t *memcap, uint32_t *hashsize)
600
17.1k
{
601
17.1k
    const char *str = NULL;
602
17.1k
    if (SCConfGetNonNull("datasets.defaults.memcap", &str) == 1) {
603
0
        if (ParseSizeStringU64(str, memcap) < 0) {
604
0
            SCLogWarning("memcap value cannot be deduced: %s,"
605
0
                         " resetting to default",
606
0
                    str);
607
0
            *memcap = 0;
608
0
        }
609
0
    }
610
611
17.1k
    *hashsize = (uint32_t)DATASETS_HASHSIZE_DEFAULT;
612
17.1k
    if (SCConfGetNonNull("datasets.defaults.hashsize", &str) == 1) {
613
0
        if (ParseSizeStringU32(str, hashsize) < 0) {
614
0
            *hashsize = (uint32_t)DATASETS_HASHSIZE_DEFAULT;
615
0
            SCLogWarning("hashsize value cannot be deduced: %s,"
616
0
                         " resetting to default: %u",
617
0
                    str, *hashsize);
618
0
        }
619
0
    }
620
17.1k
}
621
622
int DatasetsInit(void)
623
5
{
624
5
    SCLogDebug("datasets start");
625
5
    SCConfNode *datasets = SCConfGetNode("datasets");
626
5
    uint64_t default_memcap = 0;
627
5
    uint32_t default_hashsize = 0;
628
5
    DatasetGetDefaultMemcap(&default_memcap, &default_hashsize);
629
5
    if (datasets != NULL) {
630
4
        const char *str = NULL;
631
4
        if (SCConfGetNonNull("datasets.limits.total-hashsizes", &str) == 1) {
632
0
            if (ParseSizeStringU32(str, &dataset_max_total_hashsize) < 0) {
633
0
                FatalError("failed to parse datasets.limits.total-hashsizes value: %s", str);
634
0
            }
635
0
        }
636
4
        if (SCConfGetNonNull("datasets.limits.single-hashsize", &str) == 1) {
637
0
            if (ParseSizeStringU32(str, &dataset_max_one_hashsize) < 0) {
638
0
                FatalError("failed to parse datasets.limits.single-hashsize value: %s", str);
639
0
            }
640
0
        }
641
4
        if (dataset_max_total_hashsize > 0 &&
642
4
                dataset_max_total_hashsize < dataset_max_one_hashsize) {
643
0
            FatalError("total-hashsizes (%u) cannot be smaller than single-hashsize (%u)",
644
0
                    dataset_max_total_hashsize, dataset_max_one_hashsize);
645
0
        }
646
4
        if (dataset_max_total_hashsize > 0 && dataset_max_one_hashsize == 0) {
647
            // the total limit also applies for single limit
648
0
            dataset_max_one_hashsize = dataset_max_total_hashsize;
649
0
        }
650
651
4
        int list_pos = 0;
652
4
        SCConfNode *iter = NULL;
653
4
        TAILQ_FOREACH(iter, &datasets->head, next) {
654
4
            if (iter->name == NULL) {
655
0
                list_pos++;
656
0
                continue;
657
0
            }
658
659
4
            char save[PATH_MAX] = "";
660
4
            char load[PATH_MAX] = "";
661
4
            uint64_t memcap = 0;
662
4
            uint32_t hashsize = 0;
663
664
4
            const char *set_name = iter->name;
665
4
            if (strlen(set_name) > DATASET_NAME_MAX_LEN) {
666
0
                FatalErrorOnInit(
667
0
                        "set name '%s' too long, max %d chars", set_name, DATASET_NAME_MAX_LEN);
668
0
                continue;
669
0
            }
670
671
4
            SCConfNode *set_type = SCConfNodeLookupChild(iter, "type");
672
4
            if (set_type == NULL) {
673
4
                list_pos++;
674
4
                continue;
675
4
            }
676
677
0
            SCConfNode *set_save = SCConfNodeLookupChild(iter, "state");
678
0
            if (set_save) {
679
0
                DatasetGetPath(set_save->val, save, sizeof(save), TYPE_STATE);
680
0
                strlcpy(load, save, sizeof(load));
681
0
            } else {
682
0
                SCConfNode *set_load = SCConfNodeLookupChild(iter, "load");
683
0
                if (set_load) {
684
0
                    DatasetGetPath(set_load->val, load, sizeof(load), TYPE_LOAD);
685
0
                }
686
0
            }
687
688
0
            SCConfNode *set_memcap = SCConfNodeLookupChild(iter, "memcap");
689
0
            if (set_memcap) {
690
0
                if (ParseSizeStringU64(set_memcap->val, &memcap) < 0) {
691
0
                    SCLogWarning("memcap value cannot be"
692
0
                                 " deduced: %s, resetting to default",
693
0
                            set_memcap->val);
694
0
                    memcap = 0;
695
0
                }
696
0
            }
697
0
            SCConfNode *set_hashsize = SCConfNodeLookupChild(iter, "hashsize");
698
0
            if (set_hashsize) {
699
0
                if (ParseSizeStringU32(set_hashsize->val, &hashsize) < 0) {
700
0
                    SCLogWarning("hashsize value cannot be"
701
0
                                 " deduced: %s, resetting to default",
702
0
                            set_hashsize->val);
703
0
                    hashsize = 0;
704
0
                }
705
0
            }
706
0
            char conf_str[1024];
707
0
            snprintf(conf_str, sizeof(conf_str), "datasets.%d.%s", list_pos, set_name);
708
709
0
            SCLogDebug("set %s type %s. Conf %s", set_name, set_type->val, conf_str);
710
711
0
            if (strcmp(set_type->val, "md5") == 0) {
712
0
                Dataset *dset = DatasetGet(set_name, DATASET_TYPE_MD5, save, load,
713
0
                        memcap > 0 ? memcap : default_memcap,
714
0
                        hashsize > 0 ? hashsize : default_hashsize);
715
0
                if (dset == NULL) {
716
0
                    FatalErrorOnInit("failed to setup dataset for %s", set_name);
717
0
                    continue;
718
0
                }
719
0
                SCLogDebug("dataset %s: id %u type %s", set_name, dset->id, set_type->val);
720
0
                dset->from_yaml = true;
721
722
0
            } else if (strcmp(set_type->val, "sha256") == 0) {
723
0
                Dataset *dset = DatasetGet(set_name, DATASET_TYPE_SHA256, save, load,
724
0
                        memcap > 0 ? memcap : default_memcap,
725
0
                        hashsize > 0 ? hashsize : default_hashsize);
726
0
                if (dset == NULL) {
727
0
                    FatalErrorOnInit("failed to setup dataset for %s", set_name);
728
0
                    continue;
729
0
                }
730
0
                SCLogDebug("dataset %s: id %u type %s", set_name, dset->id, set_type->val);
731
0
                dset->from_yaml = true;
732
733
0
            } else if (strcmp(set_type->val, "string") == 0) {
734
0
                Dataset *dset = DatasetGet(set_name, DATASET_TYPE_STRING, save, load,
735
0
                        memcap > 0 ? memcap : default_memcap,
736
0
                        hashsize > 0 ? hashsize : default_hashsize);
737
0
                if (dset == NULL) {
738
0
                    FatalErrorOnInit("failed to setup dataset for %s", set_name);
739
0
                    continue;
740
0
                }
741
0
                SCLogDebug("dataset %s: id %u type %s", set_name, dset->id, set_type->val);
742
0
                dset->from_yaml = true;
743
744
0
            } else if (strcmp(set_type->val, "ipv4") == 0) {
745
0
                Dataset *dset = DatasetGet(set_name, DATASET_TYPE_IPV4, save, load,
746
0
                        memcap > 0 ? memcap : default_memcap,
747
0
                        hashsize > 0 ? hashsize : default_hashsize);
748
0
                if (dset == NULL) {
749
0
                    FatalErrorOnInit("failed to setup dataset for %s", set_name);
750
0
                    continue;
751
0
                }
752
0
                SCLogDebug("dataset %s: id %u type %s", set_name, dset->id, set_type->val);
753
0
                dset->from_yaml = true;
754
755
0
            } else if (strcmp(set_type->val, "ip") == 0) {
756
0
                Dataset *dset = DatasetGet(set_name, DATASET_TYPE_IPV6, save, load,
757
0
                        memcap > 0 ? memcap : default_memcap,
758
0
                        hashsize > 0 ? hashsize : default_hashsize);
759
0
                if (dset == NULL) {
760
0
                    FatalErrorOnInit("failed to setup dataset for %s", set_name);
761
0
                    continue;
762
0
                }
763
0
                SCLogDebug("dataset %s: id %u type %s", set_name, dset->id, set_type->val);
764
0
                dset->from_yaml = true;
765
0
            }
766
767
0
            list_pos++;
768
0
        }
769
4
    }
770
5
    SCLogDebug("datasets done: %p", datasets);
771
5
    return 0;
772
5
}
773
774
void DatasetsDestroy(void)
775
0
{
776
0
    DatasetLock();
777
0
    SCLogDebug("destroying datasets: %p", sets);
778
0
    Dataset *set = sets;
779
0
    while (set) {
780
0
        SCLogDebug("destroying set %s", set->name);
781
0
        Dataset *next = set->next;
782
0
        THashShutdown(set->hash);
783
0
        SCFree(set);
784
0
        set = next;
785
0
    }
786
0
    sets = NULL;
787
0
    DatasetUnlock();
788
0
    SCLogDebug("destroying datasets done: %p", sets);
789
0
}
790
791
static int SaveCallback(void *ctx, const uint8_t *data, const uint32_t data_len)
792
0
{
793
0
    FILE *fp = ctx;
794
    //PrintRawDataFp(fp, data, data_len);
795
0
    if (fp) {
796
0
        return (int)fwrite(data, data_len, 1, fp);
797
0
    }
798
0
    return 0;
799
0
}
800
801
static int Md5AsAscii(const void *s, char *out, size_t out_size)
802
0
{
803
0
    const Md5Type *md5 = s;
804
0
    char str[256];
805
0
    PrintHexString(str, sizeof(str), (uint8_t *)md5->md5, sizeof(md5->md5));
806
0
    strlcat(out, str, out_size);
807
0
    strlcat(out, "\n", out_size);
808
0
    return (int)strlen(out);
809
0
}
810
811
static int Sha256AsAscii(const void *s, char *out, size_t out_size)
812
0
{
813
0
    const Sha256Type *sha = s;
814
0
    char str[256];
815
0
    PrintHexString(str, sizeof(str), (uint8_t *)sha->sha256, sizeof(sha->sha256));
816
0
    strlcat(out, str, out_size);
817
0
    strlcat(out, "\n", out_size);
818
0
    return (int)strlen(out);
819
0
}
820
821
static int IPv4AsAscii(const void *s, char *out, size_t out_size)
822
0
{
823
0
    const IPv4Type *ip4 = s;
824
0
    char str[256];
825
0
    PrintInet(AF_INET, ip4->ipv4, str, sizeof(str));
826
0
    strlcat(out, str, out_size);
827
0
    strlcat(out, "\n", out_size);
828
0
    return (int)strlen(out);
829
0
}
830
831
static int IPv6AsAscii(const void *s, char *out, size_t out_size)
832
0
{
833
0
    const IPv6Type *ip6 = s;
834
0
    char str[256];
835
0
    bool is_ipv4 = true;
836
0
    for (int i = 4; i <= 15; i++) {
837
0
        if (ip6->ipv6[i] != 0) {
838
0
            is_ipv4 = false;
839
0
            break;
840
0
        }
841
0
    }
842
0
    if (is_ipv4) {
843
0
        PrintInet(AF_INET, ip6->ipv6, str, sizeof(str));
844
0
    } else {
845
0
        PrintInet(AF_INET6, ip6->ipv6, str, sizeof(str));
846
0
    }
847
0
    strlcat(out, str, out_size);
848
0
    strlcat(out, "\n", out_size);
849
0
    return (int)strlen(out);
850
0
}
851
852
void DatasetsSave(void)
853
0
{
854
0
    DatasetLock();
855
0
    SCLogDebug("saving datasets: %p", sets);
856
0
    Dataset *set = sets;
857
0
    while (set) {
858
0
        if (strlen(set->save) == 0)
859
0
            goto next;
860
861
0
        FILE *fp = fopen(set->save, "w");
862
0
        if (fp == NULL)
863
0
            goto next;
864
865
0
        SCLogDebug("dumping %s to %s", set->name, set->save);
866
867
0
        switch (set->type) {
868
0
            case DATASET_TYPE_STRING:
869
0
                THashWalk(set->hash, StringAsBase64, SaveCallback, fp);
870
0
                break;
871
0
            case DATASET_TYPE_MD5:
872
0
                THashWalk(set->hash, Md5AsAscii, SaveCallback, fp);
873
0
                break;
874
0
            case DATASET_TYPE_SHA256:
875
0
                THashWalk(set->hash, Sha256AsAscii, SaveCallback, fp);
876
0
                break;
877
0
            case DATASET_TYPE_IPV4:
878
0
                THashWalk(set->hash, IPv4AsAscii, SaveCallback, fp);
879
0
                break;
880
0
            case DATASET_TYPE_IPV6:
881
0
                THashWalk(set->hash, IPv6AsAscii, SaveCallback, fp);
882
0
                break;
883
0
        }
884
885
0
        fclose(fp);
886
887
0
    next:
888
0
        set = set->next;
889
0
    }
890
0
    DatasetUnlock();
891
0
}
892
893
static int DatasetLookupString(Dataset *set, const uint8_t *data, const uint32_t data_len)
894
12
{
895
12
    if (set == NULL)
896
0
        return -1;
897
898
12
    StringType lookup = { .ptr = (uint8_t *)data, .len = data_len, .rep.value = 0 };
899
12
    THashData *rdata = THashLookupFromHash(set->hash, &lookup);
900
12
    if (rdata) {
901
0
        DatasetUnlockData(rdata);
902
0
        return 1;
903
0
    }
904
12
    return 0;
905
12
}
906
907
static DataRepResultType DatasetLookupStringwRep(Dataset *set,
908
        const uint8_t *data, const uint32_t data_len, const DataRepType *rep)
909
107
{
910
107
    DataRepResultType rrep = { .found = false, .rep = { .value = 0 }};
911
912
107
    if (set == NULL)
913
0
        return rrep;
914
915
107
    StringType lookup = { .ptr = (uint8_t *)data, .len = data_len, .rep = *rep };
916
107
    THashData *rdata = THashLookupFromHash(set->hash, &lookup);
917
107
    if (rdata) {
918
0
        StringType *found = rdata->data;
919
0
        rrep.found = true;
920
0
        rrep.rep = found->rep;
921
0
        DatasetUnlockData(rdata);
922
0
        return rrep;
923
0
    }
924
107
    return rrep;
925
107
}
926
927
static int DatasetLookupIPv4(Dataset *set, const uint8_t *data, const uint32_t data_len)
928
1.82k
{
929
1.82k
    if (set == NULL)
930
0
        return -1;
931
932
1.82k
    if (data_len != 4)
933
6
        return -1;
934
935
1.82k
    IPv4Type lookup = { .rep.value = 0 };
936
1.82k
    memcpy(lookup.ipv4, data, 4);
937
1.82k
    THashData *rdata = THashLookupFromHash(set->hash, &lookup);
938
1.82k
    if (rdata) {
939
0
        DatasetUnlockData(rdata);
940
0
        return 1;
941
0
    }
942
1.82k
    return 0;
943
1.82k
}
944
945
static DataRepResultType DatasetLookupIPv4wRep(
946
        Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep)
947
0
{
948
0
    DataRepResultType rrep = { .found = false, .rep = { .value = 0 } };
949
950
0
    if (set == NULL)
951
0
        return rrep;
952
953
0
    if (data_len != 4)
954
0
        return rrep;
955
956
0
    IPv4Type lookup = { .rep.value = 0 };
957
0
    memcpy(lookup.ipv4, data, data_len);
958
0
    THashData *rdata = THashLookupFromHash(set->hash, &lookup);
959
0
    if (rdata) {
960
0
        IPv4Type *found = rdata->data;
961
0
        rrep.found = true;
962
0
        rrep.rep = found->rep;
963
0
        DatasetUnlockData(rdata);
964
0
        return rrep;
965
0
    }
966
0
    return rrep;
967
0
}
968
969
static int DatasetLookupIPv6(Dataset *set, const uint8_t *data, const uint32_t data_len)
970
402
{
971
402
    if (set == NULL)
972
0
        return -1;
973
974
402
    if (data_len != 16 && data_len != 4)
975
0
        return -1;
976
977
402
    IPv6Type lookup = { .rep.value = 0 };
978
402
    memcpy(lookup.ipv6, data, data_len);
979
402
    THashData *rdata = THashLookupFromHash(set->hash, &lookup);
980
402
    if (rdata) {
981
0
        DatasetUnlockData(rdata);
982
0
        return 1;
983
0
    }
984
402
    return 0;
985
402
}
986
987
static DataRepResultType DatasetLookupIPv6wRep(
988
        Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep)
989
0
{
990
0
    DataRepResultType rrep = { .found = false, .rep = { .value = 0 } };
991
992
0
    if (set == NULL)
993
0
        return rrep;
994
995
0
    if (data_len != 16 && data_len != 4)
996
0
        return rrep;
997
998
0
    IPv6Type lookup = { .rep.value = 0 };
999
0
    memcpy(lookup.ipv6, data, data_len);
1000
0
    THashData *rdata = THashLookupFromHash(set->hash, &lookup);
1001
0
    if (rdata) {
1002
0
        IPv6Type *found = rdata->data;
1003
0
        rrep.found = true;
1004
0
        rrep.rep = found->rep;
1005
0
        DatasetUnlockData(rdata);
1006
0
        return rrep;
1007
0
    }
1008
0
    return rrep;
1009
0
}
1010
1011
static int DatasetLookupMd5(Dataset *set, const uint8_t *data, const uint32_t data_len)
1012
6
{
1013
6
    if (set == NULL)
1014
0
        return -1;
1015
1016
6
    if (data_len != 16)
1017
6
        return -1;
1018
1019
0
    Md5Type lookup = { .rep.value = 0 };
1020
0
    memcpy(lookup.md5, data, data_len);
1021
0
    THashData *rdata = THashLookupFromHash(set->hash, &lookup);
1022
0
    if (rdata) {
1023
0
        DatasetUnlockData(rdata);
1024
0
        return 1;
1025
0
    }
1026
0
    return 0;
1027
0
}
1028
1029
static DataRepResultType DatasetLookupMd5wRep(Dataset *set,
1030
        const uint8_t *data, const uint32_t data_len, const DataRepType *rep)
1031
7
{
1032
7
    DataRepResultType rrep = { .found = false, .rep = { .value = 0 }};
1033
1034
7
    if (set == NULL)
1035
0
        return rrep;
1036
1037
7
    if (data_len != 16)
1038
3
        return rrep;
1039
1040
4
    Md5Type lookup = { .rep.value = 0};
1041
4
    memcpy(lookup.md5, data, data_len);
1042
4
    THashData *rdata = THashLookupFromHash(set->hash, &lookup);
1043
4
    if (rdata) {
1044
0
        Md5Type *found = rdata->data;
1045
0
        rrep.found = true;
1046
0
        rrep.rep = found->rep;
1047
0
        DatasetUnlockData(rdata);
1048
0
        return rrep;
1049
0
    }
1050
4
    return rrep;
1051
4
}
1052
1053
static int DatasetLookupSha256(Dataset *set, const uint8_t *data, const uint32_t data_len)
1054
0
{
1055
0
    if (set == NULL)
1056
0
        return -1;
1057
1058
0
    if (data_len != 32)
1059
0
        return -1;
1060
1061
0
    Sha256Type lookup = { .rep.value = 0 };
1062
0
    memcpy(lookup.sha256, data, data_len);
1063
0
    THashData *rdata = THashLookupFromHash(set->hash, &lookup);
1064
0
    if (rdata) {
1065
0
        DatasetUnlockData(rdata);
1066
0
        return 1;
1067
0
    }
1068
0
    return 0;
1069
0
}
1070
1071
static DataRepResultType DatasetLookupSha256wRep(Dataset *set,
1072
        const uint8_t *data, const uint32_t data_len, const DataRepType *rep)
1073
136
{
1074
136
    DataRepResultType rrep = { .found = false, .rep = { .value = 0 }};
1075
1076
136
    if (set == NULL)
1077
0
        return rrep;
1078
1079
136
    if (data_len != 32)
1080
35
        return rrep;
1081
1082
101
    Sha256Type lookup = { .rep.value = 0 };
1083
101
    memcpy(lookup.sha256, data, data_len);
1084
101
    THashData *rdata = THashLookupFromHash(set->hash, &lookup);
1085
101
    if (rdata) {
1086
0
        Sha256Type *found = rdata->data;
1087
0
        rrep.found = true;
1088
0
        rrep.rep = found->rep;
1089
0
        DatasetUnlockData(rdata);
1090
0
        return rrep;
1091
0
    }
1092
101
    return rrep;
1093
101
}
1094
1095
/**
1096
 *  \brief see if \a data is part of the set
1097
 *  \param set dataset
1098
 *  \param data data to look up
1099
 *  \param data_len length in bytes of \a data
1100
 *  \retval -1 error
1101
 *  \retval 0 not found
1102
 *  \retval 1 found
1103
 */
1104
int DatasetLookup(Dataset *set, const uint8_t *data, const uint32_t data_len)
1105
2.24k
{
1106
2.24k
    if (set == NULL)
1107
0
        return -1;
1108
1109
2.24k
    switch (set->type) {
1110
12
        case DATASET_TYPE_STRING:
1111
12
            return DatasetLookupString(set, data, data_len);
1112
6
        case DATASET_TYPE_MD5:
1113
6
            return DatasetLookupMd5(set, data, data_len);
1114
0
        case DATASET_TYPE_SHA256:
1115
0
            return DatasetLookupSha256(set, data, data_len);
1116
1.82k
        case DATASET_TYPE_IPV4:
1117
1.82k
            return DatasetLookupIPv4(set, data, data_len);
1118
402
        case DATASET_TYPE_IPV6:
1119
402
            return DatasetLookupIPv6(set, data, data_len);
1120
2.24k
    }
1121
0
    return -1;
1122
2.24k
}
1123
1124
DataRepResultType DatasetLookupwRep(Dataset *set, const uint8_t *data, const uint32_t data_len,
1125
        const DataRepType *rep)
1126
250
{
1127
250
    DataRepResultType rrep = { .found = false, .rep = { .value = 0 }};
1128
250
    if (set == NULL)
1129
0
        return rrep;
1130
1131
250
    switch (set->type) {
1132
107
        case DATASET_TYPE_STRING:
1133
107
            return DatasetLookupStringwRep(set, data, data_len, rep);
1134
7
        case DATASET_TYPE_MD5:
1135
7
            return DatasetLookupMd5wRep(set, data, data_len, rep);
1136
136
        case DATASET_TYPE_SHA256:
1137
136
            return DatasetLookupSha256wRep(set, data, data_len, rep);
1138
0
        case DATASET_TYPE_IPV4:
1139
0
            return DatasetLookupIPv4wRep(set, data, data_len, rep);
1140
0
        case DATASET_TYPE_IPV6:
1141
0
            return DatasetLookupIPv6wRep(set, data, data_len, rep);
1142
250
    }
1143
0
    return rrep;
1144
250
}
1145
1146
/**
1147
 *  \retval 1 data was added to the hash
1148
 *  \retval 0 data was not added to the hash as it is already there
1149
 *  \retval -1 failed to add data to the hash
1150
 */
1151
static int DatasetAddString(Dataset *set, const uint8_t *data, const uint32_t data_len)
1152
106k
{
1153
106k
    if (set == NULL)
1154
0
        return -1;
1155
1156
106k
    StringType lookup = { .ptr = (uint8_t *)data, .len = data_len,
1157
106k
        .rep.value = 0 };
1158
106k
    struct THashDataGetResult res = THashGetFromHash(set->hash, &lookup);
1159
106k
    if (res.data) {
1160
106k
        DatasetUnlockData(res.data);
1161
106k
        return res.is_new ? 1 : 0;
1162
106k
    }
1163
0
    return -1;
1164
106k
}
1165
1166
/**
1167
 *  \retval 1 data was added to the hash
1168
 *  \retval 0 data was not added to the hash as it is already there
1169
 *  \retval -1 failed to add data to the hash
1170
 */
1171
static int DatasetAddStringwRep(
1172
        Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep)
1173
0
{
1174
0
    if (set == NULL)
1175
0
        return -1;
1176
1177
0
    StringType lookup = { .ptr = (uint8_t *)data, .len = data_len,
1178
0
        .rep = *rep };
1179
0
    struct THashDataGetResult res = THashGetFromHash(set->hash, &lookup);
1180
0
    if (res.data) {
1181
0
        DatasetUnlockData(res.data);
1182
0
        return res.is_new ? 1 : 0;
1183
0
    }
1184
0
    return -1;
1185
0
}
1186
1187
static int DatasetAddIPv4(Dataset *set, const uint8_t *data, const uint32_t data_len)
1188
22.7k
{
1189
22.7k
    if (set == NULL) {
1190
0
        return -1;
1191
0
    }
1192
1193
22.7k
    if (data_len < 4) {
1194
0
        return -2;
1195
0
    }
1196
1197
22.7k
    IPv4Type lookup = { .rep.value = 0 };
1198
22.7k
    memcpy(lookup.ipv4, data, 4);
1199
22.7k
    struct THashDataGetResult res = THashGetFromHash(set->hash, &lookup);
1200
22.7k
    if (res.data) {
1201
22.7k
        DatasetUnlockData(res.data);
1202
22.7k
        return res.is_new ? 1 : 0;
1203
22.7k
    }
1204
0
    return -1;
1205
22.7k
}
1206
1207
static int DatasetAddIPv6(Dataset *set, const uint8_t *data, const uint32_t data_len)
1208
839
{
1209
839
    if (set == NULL) {
1210
0
        return -1;
1211
0
    }
1212
1213
839
    if (data_len != 16 && data_len != 4) {
1214
0
        return -2;
1215
0
    }
1216
1217
839
    IPv6Type lookup = { .rep.value = 0 };
1218
839
    memcpy(lookup.ipv6, data, data_len);
1219
839
    struct THashDataGetResult res = THashGetFromHash(set->hash, &lookup);
1220
839
    if (res.data) {
1221
839
        DatasetUnlockData(res.data);
1222
839
        return res.is_new ? 1 : 0;
1223
839
    }
1224
0
    return -1;
1225
839
}
1226
1227
static int DatasetAddIPv4wRep(
1228
        Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep)
1229
0
{
1230
0
    if (set == NULL)
1231
0
        return -1;
1232
1233
0
    if (data_len < 4)
1234
0
        return -2;
1235
1236
0
    IPv4Type lookup = { .rep = *rep };
1237
0
    memcpy(lookup.ipv4, data, 4);
1238
0
    struct THashDataGetResult res = THashGetFromHash(set->hash, &lookup);
1239
0
    if (res.data) {
1240
0
        DatasetUnlockData(res.data);
1241
0
        return res.is_new ? 1 : 0;
1242
0
    }
1243
0
    return -1;
1244
0
}
1245
1246
static int DatasetAddIPv6wRep(
1247
        Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep)
1248
0
{
1249
0
    if (set == NULL)
1250
0
        return -1;
1251
1252
0
    if (data_len != 16)
1253
0
        return -2;
1254
1255
0
    IPv6Type lookup = { .rep = *rep };
1256
0
    memcpy(lookup.ipv6, data, 16);
1257
0
    struct THashDataGetResult res = THashGetFromHash(set->hash, &lookup);
1258
0
    if (res.data) {
1259
0
        DatasetUnlockData(res.data);
1260
0
        return res.is_new ? 1 : 0;
1261
0
    }
1262
0
    return -1;
1263
0
}
1264
1265
static int DatasetAddMd5(Dataset *set, const uint8_t *data, const uint32_t data_len)
1266
4
{
1267
4
    if (set == NULL)
1268
0
        return -1;
1269
1270
4
    if (data_len != 16)
1271
4
        return -2;
1272
1273
0
    Md5Type lookup = { .rep.value = 0 };
1274
0
    memcpy(lookup.md5, data, 16);
1275
0
    struct THashDataGetResult res = THashGetFromHash(set->hash, &lookup);
1276
0
    if (res.data) {
1277
0
        DatasetUnlockData(res.data);
1278
0
        return res.is_new ? 1 : 0;
1279
0
    }
1280
0
    return -1;
1281
0
}
1282
1283
static int DatasetAddMd5wRep(
1284
        Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep)
1285
0
{
1286
0
    if (set == NULL)
1287
0
        return -1;
1288
1289
0
    if (data_len != 16)
1290
0
        return -2;
1291
1292
0
    Md5Type lookup = { .rep = *rep };
1293
0
    memcpy(lookup.md5, data, 16);
1294
0
    struct THashDataGetResult res = THashGetFromHash(set->hash, &lookup);
1295
0
    if (res.data) {
1296
0
        DatasetUnlockData(res.data);
1297
0
        return res.is_new ? 1 : 0;
1298
0
    }
1299
0
    return -1;
1300
0
}
1301
1302
static int DatasetAddSha256wRep(
1303
        Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep)
1304
0
{
1305
0
    if (set == NULL)
1306
0
        return -1;
1307
1308
0
    if (data_len != 32)
1309
0
        return -2;
1310
1311
0
    Sha256Type lookup = { .rep = *rep };
1312
0
    memcpy(lookup.sha256, data, 32);
1313
0
    struct THashDataGetResult res = THashGetFromHash(set->hash, &lookup);
1314
0
    if (res.data) {
1315
0
        DatasetUnlockData(res.data);
1316
0
        return res.is_new ? 1 : 0;
1317
0
    }
1318
0
    return -1;
1319
0
}
1320
1321
static int DatasetAddSha256(Dataset *set, const uint8_t *data, const uint32_t data_len)
1322
13
{
1323
13
    if (set == NULL)
1324
0
        return -1;
1325
1326
13
    if (data_len != 32)
1327
13
        return -2;
1328
1329
0
    Sha256Type lookup = { .rep.value = 0 };
1330
0
    memcpy(lookup.sha256, data, 32);
1331
0
    struct THashDataGetResult res = THashGetFromHash(set->hash, &lookup);
1332
0
    if (res.data) {
1333
0
        DatasetUnlockData(res.data);
1334
0
        return res.is_new ? 1 : 0;
1335
0
    }
1336
0
    return -1;
1337
0
}
1338
1339
int DatasetAdd(Dataset *set, const uint8_t *data, const uint32_t data_len)
1340
212
{
1341
212
    if (set == NULL)
1342
0
        return -1;
1343
1344
212
    switch (set->type) {
1345
0
        case DATASET_TYPE_STRING:
1346
0
            return DatasetAddString(set, data, data_len);
1347
0
        case DATASET_TYPE_MD5:
1348
0
            return DatasetAddMd5(set, data, data_len);
1349
0
        case DATASET_TYPE_SHA256:
1350
0
            return DatasetAddSha256(set, data, data_len);
1351
0
        case DATASET_TYPE_IPV4:
1352
0
            return DatasetAddIPv4(set, data, data_len);
1353
212
        case DATASET_TYPE_IPV6:
1354
212
            return DatasetAddIPv6(set, data, data_len);
1355
212
    }
1356
0
    return -1;
1357
212
}
1358
1359
int DatasetAddwRep(Dataset *set, const uint8_t *data, const uint32_t data_len, DataRepType *rep)
1360
0
{
1361
0
    if (set == NULL)
1362
0
        return -1;
1363
1364
0
    switch (set->type) {
1365
0
        case DATASET_TYPE_STRING:
1366
0
            return DatasetAddStringwRep(set, data, data_len, rep);
1367
0
        case DATASET_TYPE_MD5:
1368
0
            return DatasetAddMd5wRep(set, data, data_len, rep);
1369
0
        case DATASET_TYPE_SHA256:
1370
0
            return DatasetAddSha256wRep(set, data, data_len, rep);
1371
0
        case DATASET_TYPE_IPV4:
1372
0
            return DatasetAddIPv4wRep(set, data, data_len, rep);
1373
0
        case DATASET_TYPE_IPV6:
1374
0
            return DatasetAddIPv6wRep(set, data, data_len, rep);
1375
0
    }
1376
0
    return -1;
1377
0
}
1378
1379
typedef int (*DatasetOpFunc)(Dataset *set, const uint8_t *data, const uint32_t data_len);
1380
1381
static int DatasetOpSerialized(Dataset *set, const char *string, DatasetOpFunc DatasetOpString,
1382
        DatasetOpFunc DatasetOpMd5, DatasetOpFunc DatasetOpSha256, DatasetOpFunc DatasetOpIPv4,
1383
        DatasetOpFunc DatasetOpIPv6)
1384
0
{
1385
0
    if (set == NULL)
1386
0
        return -1;
1387
0
    if (strlen(string) == 0)
1388
0
        return -1;
1389
1390
0
    switch (set->type) {
1391
0
        case DATASET_TYPE_STRING: {
1392
0
            if (strlen(string) > UINT16_MAX) {
1393
                // size check before cast and stack allocation
1394
0
                return -1;
1395
0
            }
1396
0
            uint32_t decoded_size = SCBase64DecodeBufferSize((uint32_t)strlen(string));
1397
0
            uint8_t decoded[decoded_size];
1398
0
            uint32_t num_decoded = SCBase64Decode(
1399
0
                    (const uint8_t *)string, strlen(string), SCBase64ModeStrict, decoded);
1400
0
            if (num_decoded == 0) {
1401
0
                return -2;
1402
0
            }
1403
1404
0
            return DatasetOpString(set, decoded, num_decoded);
1405
0
        }
1406
0
        case DATASET_TYPE_MD5: {
1407
0
            if (strlen(string) != 32)
1408
0
                return -2;
1409
0
            uint8_t hash[16];
1410
0
            if (HexToRaw((const uint8_t *)string, 32, hash, sizeof(hash)) < 0)
1411
0
                return -2;
1412
0
            return DatasetOpMd5(set, hash, 16);
1413
0
        }
1414
0
        case DATASET_TYPE_SHA256: {
1415
0
            if (strlen(string) != 64)
1416
0
                return -2;
1417
0
            uint8_t hash[32];
1418
0
            if (HexToRaw((const uint8_t *)string, 64, hash, sizeof(hash)) < 0)
1419
0
                return -2;
1420
0
            return DatasetOpSha256(set, hash, 32);
1421
0
        }
1422
0
        case DATASET_TYPE_IPV4: {
1423
0
            struct in_addr in;
1424
0
            if (inet_pton(AF_INET, string, &in) != 1)
1425
0
                return -2;
1426
0
            return DatasetOpIPv4(set, (uint8_t *)&in.s_addr, 4);
1427
0
        }
1428
0
        case DATASET_TYPE_IPV6: {
1429
0
            struct in6_addr in6;
1430
0
            if (DatasetParseIpv6String(set, string, &in6) != 0) {
1431
0
                SCLogError("Dataset failed to import %s as IPv6", string);
1432
0
                return -2;
1433
0
            }
1434
0
            return DatasetOpIPv6(set, (uint8_t *)&in6.s6_addr, 16);
1435
0
        }
1436
0
    }
1437
0
    return -1;
1438
0
}
1439
1440
/** \brief add serialized data to set
1441
 *  \retval int 1 added
1442
 *  \retval int 0 already in hash
1443
 *  \retval int -1 API error (not added)
1444
 *  \retval int -2 DATA error
1445
 */
1446
int DatasetAddSerialized(Dataset *set, const char *string)
1447
0
{
1448
0
    return DatasetOpSerialized(set, string, DatasetAddString, DatasetAddMd5, DatasetAddSha256,
1449
0
            DatasetAddIPv4, DatasetAddIPv6);
1450
0
}
1451
1452
/** \brief add serialized data to set
1453
 *  \retval int 1 added
1454
 *  \retval int 0 already in hash
1455
 *  \retval int -1 API error (not added)
1456
 *  \retval int -2 DATA error
1457
 */
1458
int DatasetLookupSerialized(Dataset *set, const char *string)
1459
0
{
1460
0
    return DatasetOpSerialized(set, string, DatasetLookupString, DatasetLookupMd5,
1461
0
            DatasetLookupSha256, DatasetLookupIPv4, DatasetLookupIPv6);
1462
0
}
1463
1464
/**
1465
 *  \retval 1 data was removed from the hash
1466
 *  \retval 0 data not removed (busy)
1467
 *  \retval -1 data not found
1468
 */
1469
static int DatasetRemoveString(Dataset *set, const uint8_t *data, const uint32_t data_len)
1470
0
{
1471
0
    if (set == NULL)
1472
0
        return -1;
1473
1474
0
    StringType lookup = { .ptr = (uint8_t *)data, .len = data_len,
1475
0
        .rep.value = 0 };
1476
0
    return THashRemoveFromHash(set->hash, &lookup);
1477
0
}
1478
1479
static int DatasetRemoveIPv4(Dataset *set, const uint8_t *data, const uint32_t data_len)
1480
0
{
1481
0
    if (set == NULL)
1482
0
        return -1;
1483
1484
0
    if (data_len != 4)
1485
0
        return -2;
1486
1487
0
    IPv4Type lookup = { .rep.value = 0 };
1488
0
    memcpy(lookup.ipv4, data, 4);
1489
0
    return THashRemoveFromHash(set->hash, &lookup);
1490
0
}
1491
1492
static int DatasetRemoveIPv6(Dataset *set, const uint8_t *data, const uint32_t data_len)
1493
0
{
1494
0
    if (set == NULL)
1495
0
        return -1;
1496
1497
0
    if (data_len != 16)
1498
0
        return -2;
1499
1500
0
    IPv6Type lookup = { .rep.value = 0 };
1501
0
    memcpy(lookup.ipv6, data, 16);
1502
0
    return THashRemoveFromHash(set->hash, &lookup);
1503
0
}
1504
1505
static int DatasetRemoveMd5(Dataset *set, const uint8_t *data, const uint32_t data_len)
1506
0
{
1507
0
    if (set == NULL)
1508
0
        return -1;
1509
1510
0
    if (data_len != 16)
1511
0
        return -2;
1512
1513
0
    Md5Type lookup = { .rep.value = 0 };
1514
0
    memcpy(lookup.md5, data, 16);
1515
0
    return THashRemoveFromHash(set->hash, &lookup);
1516
0
}
1517
1518
static int DatasetRemoveSha256(Dataset *set, const uint8_t *data, const uint32_t data_len)
1519
0
{
1520
0
    if (set == NULL)
1521
0
        return -1;
1522
1523
0
    if (data_len != 32)
1524
0
        return -2;
1525
1526
0
    Sha256Type lookup = { .rep.value = 0 };
1527
0
    memcpy(lookup.sha256, data, 32);
1528
0
    return THashRemoveFromHash(set->hash, &lookup);
1529
0
}
1530
1531
/** \brief remove serialized data from set
1532
 *  \retval int 1 removed
1533
 *  \retval int 0 found but busy (not removed)
1534
 *  \retval int -1 API error (not removed)
1535
 *  \retval int -2 DATA error */
1536
int DatasetRemoveSerialized(Dataset *set, const char *string)
1537
0
{
1538
0
    return DatasetOpSerialized(set, string, DatasetRemoveString, DatasetRemoveMd5,
1539
0
            DatasetRemoveSha256, DatasetRemoveIPv4, DatasetRemoveIPv6);
1540
0
}
1541
1542
int DatasetRemove(Dataset *set, const uint8_t *data, const uint32_t data_len)
1543
0
{
1544
0
    if (set == NULL)
1545
0
        return -1;
1546
1547
0
    switch (set->type) {
1548
0
        case DATASET_TYPE_STRING:
1549
0
            return DatasetRemoveString(set, data, data_len);
1550
0
        case DATASET_TYPE_MD5:
1551
0
            return DatasetRemoveMd5(set, data, data_len);
1552
0
        case DATASET_TYPE_SHA256:
1553
0
            return DatasetRemoveSha256(set, data, data_len);
1554
0
        case DATASET_TYPE_IPV4:
1555
0
            return DatasetRemoveIPv4(set, data, data_len);
1556
0
        case DATASET_TYPE_IPV6:
1557
0
            return DatasetRemoveIPv6(set, data, data_len);
1558
0
    }
1559
0
    return -1;
1560
0
}