/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 | } |