/src/suricata8/src/util-reference-config.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2022 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | /** |
19 | | * \file |
20 | | * |
21 | | * \author Anoop Saldanha <anoopsaldanha@gmail.com> |
22 | | */ |
23 | | |
24 | | #include "suricata-common.h" |
25 | | #include "detect.h" |
26 | | #include "detect-engine.h" |
27 | | #include "util-hash.h" |
28 | | |
29 | | #include "util-reference-config.h" |
30 | | #include "conf.h" |
31 | | #include "util-unittest.h" |
32 | | #include "util-debug.h" |
33 | | #include "util-fmemopen.h" |
34 | | |
35 | | /* Regex to parse each line from reference.config file. The first substring |
36 | | * is for the system name and the second for the url */ |
37 | | /*-----------------------------------------------------------system-------------------url----*/ |
38 | 148k | #define SC_RCONF_REGEX "^\\s*config\\s+reference\\s*:\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s+(.+)\\s*$" |
39 | | |
40 | | /* Default path for the reference.conf file */ |
41 | 148k | #define SC_RCONF_DEFAULT_FILE_PATH CONFIG_DIR "/reference.config" |
42 | | |
43 | | /* the hash functions */ |
44 | | uint32_t SCRConfReferenceHashFunc(HashTable *ht, void *data, uint16_t datalen); |
45 | | char SCRConfReferenceHashCompareFunc(void *data1, uint16_t datalen1, |
46 | | void *data2, uint16_t datalen2); |
47 | | void SCRConfReferenceHashFree(void *ch); |
48 | | |
49 | | /* used to get the reference.config file path */ |
50 | | static const char *SCRConfGetConfFilename(const DetectEngineCtx *de_ctx); |
51 | | |
52 | | void SCReferenceSCConfInit(DetectEngineCtx *de_ctx) |
53 | 148k | { |
54 | 148k | int en; |
55 | 148k | PCRE2_SIZE eo; |
56 | 148k | int opts = 0; |
57 | | |
58 | 148k | de_ctx->reference_conf_regex = |
59 | 148k | pcre2_compile((PCRE2_SPTR8)SC_RCONF_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); |
60 | 148k | if (de_ctx->reference_conf_regex == NULL) { |
61 | 0 | PCRE2_UCHAR errbuffer[256]; |
62 | 0 | pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); |
63 | 0 | SCLogWarning("pcre2 compile of \"%s\" failed at " |
64 | 0 | "offset %d: %s", |
65 | 0 | SC_RCONF_REGEX, (int)eo, errbuffer); |
66 | 0 | return; |
67 | 0 | } |
68 | 148k | de_ctx->reference_conf_regex_match = |
69 | 148k | pcre2_match_data_create_from_pattern(de_ctx->reference_conf_regex, NULL); |
70 | 148k | } |
71 | | |
72 | | void SCReferenceConfDeinit(DetectEngineCtx *de_ctx) |
73 | 148k | { |
74 | 148k | if (de_ctx->reference_conf_regex != NULL) { |
75 | 148k | pcre2_code_free(de_ctx->reference_conf_regex); |
76 | 148k | de_ctx->reference_conf_regex = NULL; |
77 | 148k | } |
78 | 148k | if (de_ctx->reference_conf_regex_match != NULL) { |
79 | 148k | pcre2_match_data_free(de_ctx->reference_conf_regex_match); |
80 | 148k | de_ctx->reference_conf_regex_match = NULL; |
81 | 148k | } |
82 | 148k | } |
83 | | |
84 | | |
85 | | /** |
86 | | * \brief Inits the context to be used by the Reference Config parsing API. |
87 | | * |
88 | | * This function initializes the hash table to be used by the Detection |
89 | | * Engine Context to hold the data from reference.config file, |
90 | | * obtains the file descriptor to parse the reference.config file, and |
91 | | * inits the regex used to parse the lines from reference.config file. |
92 | | * |
93 | | * \param de_ctx Pointer to the Detection Engine Context. |
94 | | * |
95 | | * \note if file open fails, we leave de_ctx->reference_conf_ht initialized |
96 | | * |
97 | | * \retval 0 On success. |
98 | | * \retval -1 On failure. |
99 | | */ |
100 | | static FILE *SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) |
101 | 148k | { |
102 | | /* init the hash table to be used by the reference config references */ |
103 | 148k | de_ctx->reference_conf_ht = HashTableInit(128, SCRConfReferenceHashFunc, |
104 | 148k | SCRConfReferenceHashCompareFunc, |
105 | 148k | SCRConfReferenceHashFree); |
106 | 148k | if (de_ctx->reference_conf_ht == NULL) { |
107 | 0 | SCLogError("Error initializing the hash " |
108 | 0 | "table"); |
109 | 0 | return NULL; |
110 | 0 | } |
111 | | |
112 | | /* if it is not NULL, use the file descriptor. The hack so that we can |
113 | | * avoid using a dummy reference file for testing purposes and |
114 | | * instead use an input stream against a buffer containing the |
115 | | * reference strings */ |
116 | 148k | if (fd == NULL) { |
117 | 148k | const char *filename = SCRConfGetConfFilename(de_ctx); |
118 | 148k | if ((fd = fopen(filename, "r")) == NULL) { |
119 | | #ifdef UNITTESTS |
120 | | if (RunmodeIsUnittests()) { |
121 | | return NULL; // silently fail |
122 | | } |
123 | | #endif |
124 | 148k | SCLogError("Error opening file: \"%s\": %s", filename, strerror(errno)); |
125 | 148k | return NULL; |
126 | 148k | } |
127 | 148k | } |
128 | | |
129 | 0 | return fd; |
130 | 148k | } |
131 | | |
132 | | |
133 | | /** |
134 | | * \brief Returns the path for the Reference Config file. We check if we |
135 | | * can retrieve the path from the yaml conf file. If it is not present, |
136 | | * return the default path for the reference.config file which is |
137 | | * "./reference.config". |
138 | | * |
139 | | * \retval log_filename Pointer to a string containing the path for the |
140 | | * reference.config file. |
141 | | */ |
142 | | static const char *SCRConfGetConfFilename(const DetectEngineCtx *de_ctx) |
143 | 148k | { |
144 | 148k | const char *path = NULL; |
145 | | |
146 | 148k | if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { |
147 | 0 | char config_value[256]; |
148 | 0 | snprintf(config_value, sizeof(config_value), |
149 | 0 | "%s.reference-config-file", de_ctx->config_prefix); |
150 | | |
151 | | /* try loading prefix setting, fall back to global if that |
152 | | * fails. */ |
153 | 0 | if (SCConfGetNonNull(config_value, &path) != 1) { |
154 | 0 | if (SCConfGetNonNull("reference-config-file", &path) != 1) { |
155 | 0 | return (char *)SC_RCONF_DEFAULT_FILE_PATH; |
156 | 0 | } |
157 | 0 | } |
158 | 148k | } else { |
159 | 148k | if (SCConfGetNonNull("reference-config-file", &path) != 1) { |
160 | 148k | return (char *)SC_RCONF_DEFAULT_FILE_PATH; |
161 | 148k | } |
162 | 148k | } |
163 | 0 | return path; |
164 | 148k | } |
165 | | |
166 | | /** |
167 | | * \brief Releases local resources used by the Reference Config API. |
168 | | */ |
169 | | static void SCRConfDeInitLocalResources(FILE *fd) |
170 | 0 | { |
171 | 0 | if (fd != NULL) { |
172 | 0 | fclose(fd); |
173 | 0 | } |
174 | 0 | } |
175 | | |
176 | | /** |
177 | | * \brief Releases de_ctx resources related to Reference Config API. |
178 | | */ |
179 | | void SCRConfDeInitContext(DetectEngineCtx *de_ctx) |
180 | 148k | { |
181 | 148k | if (de_ctx->reference_conf_ht != NULL) |
182 | 148k | HashTableFree(de_ctx->reference_conf_ht); |
183 | | |
184 | 148k | de_ctx->reference_conf_ht = NULL; |
185 | 148k | } |
186 | | |
187 | | /** |
188 | | * \brief Converts a string to lowercase. |
189 | | * |
190 | | * \param str Pointer to the string to be converted. |
191 | | */ |
192 | | static char *SCRConfStringToLowercase(const char *str) |
193 | 348k | { |
194 | 348k | char *new_str = NULL; |
195 | 348k | char *temp_str = NULL; |
196 | | |
197 | 348k | if ((new_str = SCStrdup(str)) == NULL) { |
198 | 0 | return NULL; |
199 | 0 | } |
200 | | |
201 | 348k | temp_str = new_str; |
202 | 1.45M | while (*temp_str != '\0') { |
203 | 1.10M | *temp_str = u8_tolower((unsigned char)*temp_str); |
204 | 1.10M | temp_str++; |
205 | 1.10M | } |
206 | | |
207 | 348k | return new_str; |
208 | 348k | } |
209 | | |
210 | | /** |
211 | | * \brief Parses a line from the reference config file and adds it to Reference |
212 | | * Config hash table DetectEngineCtx->reference_conf_ht. |
213 | | * |
214 | | * \param rawstr Pointer to the string to be parsed. |
215 | | * \param de_ctx Pointer to the Detection Engine Context. |
216 | | * |
217 | | * \retval 0 On success. |
218 | | * \retval -1 On failure. |
219 | | */ |
220 | | int SCRConfAddReference(DetectEngineCtx *de_ctx, const char *line) |
221 | 9.60k | { |
222 | 9.60k | char system[REFERENCE_SYSTEM_NAME_MAX]; |
223 | 9.60k | char url[REFERENCE_CONTENT_NAME_MAX]; |
224 | | |
225 | 9.60k | SCRConfReference *ref_new = NULL; |
226 | 9.60k | SCRConfReference *ref_lookup = NULL; |
227 | | |
228 | 9.60k | int ret = 0; |
229 | | |
230 | 9.60k | ret = pcre2_match(de_ctx->reference_conf_regex, (PCRE2_SPTR8)line, strlen(line), 0, 0, |
231 | 9.60k | de_ctx->reference_conf_regex_match, NULL); |
232 | 9.60k | if (ret < 0) { |
233 | 345 | SCLogError("Invalid Reference Config in " |
234 | 345 | "reference.config file"); |
235 | 345 | goto error; |
236 | 345 | } |
237 | | |
238 | | /* retrieve the reference system */ |
239 | 9.25k | size_t copylen = sizeof(system); |
240 | 9.25k | ret = pcre2_substring_copy_bynumber( |
241 | 9.25k | de_ctx->reference_conf_regex_match, 1, (PCRE2_UCHAR8 *)system, ©len); |
242 | 9.25k | if (ret < 0) { |
243 | 0 | SCLogError("pcre2_substring_copy_bynumber() failed"); |
244 | 0 | goto error; |
245 | 0 | } |
246 | | |
247 | | /* retrieve the reference url */ |
248 | 9.25k | copylen = sizeof(url); |
249 | 9.25k | ret = pcre2_substring_copy_bynumber( |
250 | 9.25k | de_ctx->reference_conf_regex_match, 2, (PCRE2_UCHAR8 *)url, ©len); |
251 | 9.25k | if (ret < 0) { |
252 | 0 | SCLogError("pcre2_substring_copy_bynumber() failed"); |
253 | 0 | goto error; |
254 | 0 | } |
255 | | |
256 | | /* Create a new instance of the parsed Reference string */ |
257 | 9.25k | ref_new = SCRConfAllocSCRConfReference(system, url); |
258 | 9.25k | if (ref_new == NULL) |
259 | 0 | goto error; |
260 | | |
261 | | /* Check if the Reference is present in the HashTable. In case it's present |
262 | | * ignore it, as it's a duplicate. If not present, add it to the table */ |
263 | 9.25k | ref_lookup = HashTableLookup(de_ctx->reference_conf_ht, ref_new, 0); |
264 | 9.25k | if (ref_lookup == NULL) { |
265 | 9.25k | if (HashTableAdd(de_ctx->reference_conf_ht, ref_new, 0) < 0) { |
266 | 0 | SCLogDebug("HashTable Add failed"); |
267 | 0 | } |
268 | 9.25k | } else { |
269 | 0 | SCLogDebug("Duplicate reference found inside reference.config"); |
270 | 0 | SCRConfDeAllocSCRConfReference(ref_new); |
271 | 0 | } |
272 | | |
273 | 9.25k | return 0; |
274 | | |
275 | 345 | error: |
276 | 345 | return -1; |
277 | 9.25k | } |
278 | | |
279 | | /** |
280 | | * \brief Checks if a string is a comment or a blank line. |
281 | | * |
282 | | * Comments lines are lines of the following format - |
283 | | * "# This is a comment string" or |
284 | | * " # This is a comment string". |
285 | | * |
286 | | * \param line String that has to be checked. |
287 | | * |
288 | | * \retval 1 On the argument string being a comment or blank line. |
289 | | * \retval 0 Otherwise. |
290 | | */ |
291 | | static int SCRConfIsLineBlankOrComment(char *line) |
292 | 0 | { |
293 | 0 | while (*line != '\0') { |
294 | | /* we have a comment */ |
295 | 0 | if (*line == '#') |
296 | 0 | return 1; |
297 | | |
298 | | /* this line is neither a comment line, nor a blank line */ |
299 | 0 | if (!isspace((unsigned char)*line)) |
300 | 0 | return 0; |
301 | | |
302 | 0 | line++; |
303 | 0 | } |
304 | | |
305 | | /* we have a blank line */ |
306 | 0 | return 1; |
307 | 0 | } |
308 | | |
309 | | /** |
310 | | * \brief Parses the Reference Config file and updates the |
311 | | * DetectionEngineCtx->reference_conf_ht with the Reference information. |
312 | | * |
313 | | * \param de_ctx Pointer to the Detection Engine Context. |
314 | | */ |
315 | | static bool SCRConfParseFile(DetectEngineCtx *de_ctx, FILE *fd) |
316 | 0 | { |
317 | 0 | char line[1024]; |
318 | 0 | int runmode = SCRunmodeGet(); |
319 | 0 | bool is_conf_test_mode = runmode == RUNMODE_CONF_TEST; |
320 | 0 | while (fgets(line, sizeof(line), fd) != NULL) { |
321 | 0 | if (SCRConfIsLineBlankOrComment(line)) |
322 | 0 | continue; |
323 | | |
324 | 0 | if (SCRConfAddReference(de_ctx, line) != 0) { |
325 | 0 | if (is_conf_test_mode) { |
326 | 0 | return false; |
327 | 0 | } |
328 | 0 | } |
329 | 0 | } |
330 | | |
331 | | #ifdef UNITTESTS |
332 | | if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) |
333 | | SCLogInfo("tenant id %d: Added \"%d\" reference types from the reference.config file", |
334 | | de_ctx->tenant_id, de_ctx->reference_conf_ht->count); |
335 | | else |
336 | | SCLogInfo("Added \"%d\" reference types from the reference.config file", |
337 | | de_ctx->reference_conf_ht->count); |
338 | | #endif /* UNITTESTS */ |
339 | 0 | return true; |
340 | 0 | } |
341 | | |
342 | | /** |
343 | | * \brief Returns a new SCRConfReference instance. The reference string |
344 | | * is converted into lowercase, before being assigned to the instance. |
345 | | * |
346 | | * \param system Pointer to the system. |
347 | | * \param url Pointer to the reference url. |
348 | | * |
349 | | * \retval ref Pointer to the new instance of SCRConfReference. |
350 | | */ |
351 | | SCRConfReference *SCRConfAllocSCRConfReference(const char *system, |
352 | | const char *url) |
353 | 348k | { |
354 | 348k | SCRConfReference *ref = NULL; |
355 | | |
356 | 348k | if (system == NULL) { |
357 | 0 | SCLogError("Invalid arguments. system NULL"); |
358 | 0 | return NULL; |
359 | 0 | } |
360 | | |
361 | 348k | if ((ref = SCCalloc(1, sizeof(SCRConfReference))) == NULL) { |
362 | 0 | return NULL; |
363 | 0 | } |
364 | | |
365 | 348k | if ((ref->system = SCRConfStringToLowercase(system)) == NULL) { |
366 | 0 | SCFree(ref); |
367 | 0 | return NULL; |
368 | 0 | } |
369 | | |
370 | 348k | if (url != NULL && (ref->url = SCStrdup(url)) == NULL) { |
371 | 0 | SCFree(ref->system); |
372 | 0 | SCFree(ref); |
373 | 0 | return NULL; |
374 | 0 | } |
375 | | |
376 | 348k | return ref; |
377 | 348k | } |
378 | | |
379 | | /** |
380 | | * \brief Frees a SCRConfReference instance. |
381 | | * |
382 | | * \param Pointer to the SCRConfReference instance that has to be freed. |
383 | | */ |
384 | | void SCRConfDeAllocSCRConfReference(SCRConfReference *ref) |
385 | 348k | { |
386 | 348k | if (ref != NULL) { |
387 | 348k | if (ref->system != NULL) |
388 | 348k | SCFree(ref->system); |
389 | | |
390 | 348k | if (ref->url != NULL) |
391 | 9.21k | SCFree(ref->url); |
392 | | |
393 | 348k | SCFree(ref); |
394 | 348k | } |
395 | 348k | } |
396 | | |
397 | | /** |
398 | | * \brief Hashing function to be used to hash the Reference name. Would be |
399 | | * supplied as an argument to the HashTableInit function for |
400 | | * DetectEngineCtx->reference_conf_ht. |
401 | | * |
402 | | * \param ht Pointer to the HashTable. |
403 | | * \param data Pointer to the data to be hashed. In this case, the data |
404 | | * would be a pointer to a SCRConfReference instance. |
405 | | * \param datalen Not used by this function. |
406 | | */ |
407 | | uint32_t SCRConfReferenceHashFunc(HashTable *ht, void *data, uint16_t datalen) |
408 | 357k | { |
409 | 357k | SCRConfReference *ref = (SCRConfReference *)data; |
410 | 357k | uint32_t hash = 0; |
411 | 357k | size_t i = 0; |
412 | | |
413 | 357k | size_t len = strlen(ref->system); |
414 | | |
415 | 1.49M | for (i = 0; i < len; i++) |
416 | 1.13M | hash += u8_tolower((unsigned char)ref->system[i]); |
417 | | |
418 | 357k | hash = hash % ht->array_size; |
419 | | |
420 | 357k | return hash; |
421 | 357k | } |
422 | | |
423 | | /** |
424 | | * \brief Used to compare two References that have been stored in the HashTable. |
425 | | * This function is supplied as an argument to the HashTableInit function |
426 | | * for DetectionEngineCtx->reference_conf_ct. |
427 | | * |
428 | | * \param data1 Pointer to the first SCRConfReference to be compared. |
429 | | * \param len1 Not used by this function. |
430 | | * \param data2 Pointer to the second SCRConfReference to be compared. |
431 | | * \param len2 Not used by this function. |
432 | | * |
433 | | * \retval 1 On data1 and data2 being equal. |
434 | | * \retval 0 On data1 and data2 not being equal. |
435 | | */ |
436 | | char SCRConfReferenceHashCompareFunc(void *data1, uint16_t datalen1, |
437 | | void *data2, uint16_t datalen2) |
438 | 286k | { |
439 | 286k | SCRConfReference *ref1 = (SCRConfReference *)data1; |
440 | 286k | SCRConfReference *ref2 = (SCRConfReference *)data2; |
441 | 286k | size_t len1 = 0; |
442 | 286k | size_t len2 = 0; |
443 | | |
444 | 286k | if (ref1 == NULL || ref2 == NULL) |
445 | 0 | return 0; |
446 | | |
447 | 286k | if (ref1->system == NULL || ref2->system == NULL) |
448 | 0 | return 0; |
449 | | |
450 | 286k | len1 = strlen(ref1->system); |
451 | 286k | len2 = strlen(ref2->system); |
452 | | |
453 | 286k | if (len1 == len2 && memcmp(ref1->system, ref2->system, len1) == 0) { |
454 | 242k | SCLogDebug("Match found inside Reference-Config hash function"); |
455 | 242k | return 1; |
456 | 242k | } |
457 | | |
458 | 43.5k | return 0; |
459 | 286k | } |
460 | | |
461 | | /** |
462 | | * \brief Used to free the Reference Config Hash Data that was stored in |
463 | | * DetectEngineCtx->reference_conf_ht Hashtable. |
464 | | * |
465 | | * \param data Pointer to the data that has to be freed. |
466 | | */ |
467 | | void SCRConfReferenceHashFree(void *data) |
468 | 9.21k | { |
469 | 9.21k | SCRConfDeAllocSCRConfReference(data); |
470 | 9.21k | } |
471 | | |
472 | | /** |
473 | | * \brief Loads the Reference info from the reference.config file. |
474 | | * |
475 | | * The reference.config file contains references that can be used in |
476 | | * Signatures. Each line of the file should have the following format - |
477 | | * config reference: system_name, reference_url. |
478 | | * |
479 | | * \param de_ctx Pointer to the Detection Engine Context that should be updated |
480 | | * with reference information. |
481 | | * |
482 | | * \retval 0 On success. |
483 | | * \retval -1 On failure. |
484 | | */ |
485 | | int SCRConfLoadReferenceConfigFile(DetectEngineCtx *de_ctx, FILE *fd) |
486 | 148k | { |
487 | 148k | fd = SCRConfInitContextAndLocalResources(de_ctx, fd); |
488 | 148k | if (fd == NULL) { |
489 | | #ifdef UNITTESTS |
490 | | if (RunmodeIsUnittests()) { |
491 | | return -1; |
492 | | } |
493 | | #endif |
494 | 148k | SCLogError("please check the \"reference-config-file\" " |
495 | 148k | "option in your suricata.yaml file"); |
496 | 148k | return -1; |
497 | 148k | } |
498 | | |
499 | 148k | bool rc = SCRConfParseFile(de_ctx, fd); |
500 | 0 | SCRConfDeInitLocalResources(fd); |
501 | |
|
502 | 0 | return rc ? 0 : -1; |
503 | 148k | } |
504 | | |
505 | | /** |
506 | | * \brief Gets the reference config from the corresponding hash table stored |
507 | | * in the Detection Engine Context's reference conf ht, given the |
508 | | * reference name. |
509 | | * |
510 | | * \param ct_name Pointer to the reference name that has to be looked up. |
511 | | * \param de_ctx Pointer to the Detection Engine Context. |
512 | | * |
513 | | * \retval lookup_rconf_info Pointer to the SCRConfReference instance from |
514 | | * the hash table on success; NULL on failure. |
515 | | */ |
516 | | SCRConfReference *SCRConfGetReference(const char *rconf_name, |
517 | | DetectEngineCtx *de_ctx) |
518 | 339k | { |
519 | 339k | SCRConfReference *ref_conf = SCRConfAllocSCRConfReference(rconf_name, NULL); |
520 | 339k | if (ref_conf == NULL) |
521 | 0 | return NULL; |
522 | 339k | SCRConfReference *lookup_ref_conf = HashTableLookup(de_ctx->reference_conf_ht, |
523 | 339k | ref_conf, 0); |
524 | | |
525 | 339k | SCRConfDeAllocSCRConfReference(ref_conf); |
526 | 339k | return lookup_ref_conf; |
527 | 339k | } |
528 | | |
529 | | /*----------------------------------Unittests---------------------------------*/ |
530 | | |
531 | | |
532 | | #ifdef UNITTESTS |
533 | | |
534 | | /** |
535 | | * \brief Creates a dummy reference config, with all valid references, for |
536 | | * testing purposes. |
537 | | */ |
538 | | FILE *SCRConfGenerateValidDummyReferenceConfigFD01(void) |
539 | | { |
540 | | const char *buffer = |
541 | | "config reference: one http://www.one.com\n" |
542 | | "config reference: two http://www.two.com\n" |
543 | | "config reference: three http://www.three.com\n" |
544 | | "config reference: one http://www.one.com\n" |
545 | | "config reference: three http://www.three.com\n"; |
546 | | |
547 | | FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); |
548 | | if (fd == NULL) |
549 | | SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); |
550 | | |
551 | | return fd; |
552 | | } |
553 | | |
554 | | /** |
555 | | * \brief Creates a dummy reference config, with some valid references and a |
556 | | * couple of invalid references, for testing purposes. |
557 | | */ |
558 | | FILE *SCRConfGenerateInvalidDummyReferenceConfigFD02(void) |
559 | | { |
560 | | const char *buffer = |
561 | | "config reference: one http://www.one.com\n" |
562 | | "config_ reference: two http://www.two.com\n" |
563 | | "config reference_: three http://www.three.com\n" |
564 | | "config reference: four\n" |
565 | | "config reference five http://www.five.com\n"; |
566 | | |
567 | | FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); |
568 | | if (fd == NULL) |
569 | | SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); |
570 | | |
571 | | return fd; |
572 | | } |
573 | | |
574 | | /** |
575 | | * \brief Creates a dummy reference config, with all invalid references, for |
576 | | * testing purposes. |
577 | | */ |
578 | | FILE *SCRConfGenerateInvalidDummyReferenceConfigFD03(void) |
579 | | { |
580 | | const char *buffer = |
581 | | "config reference one http://www.one.com\n" |
582 | | "config_ reference: two http://www.two.com\n" |
583 | | "config reference_: three http://www.three.com\n" |
584 | | "config reference: four\n"; |
585 | | |
586 | | FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); |
587 | | if (fd == NULL) |
588 | | SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); |
589 | | |
590 | | return fd; |
591 | | } |
592 | | |
593 | | /** |
594 | | * \test Check that the reference file is loaded and the detection engine |
595 | | * content reference_conf_ht loaded with the reference data. |
596 | | */ |
597 | | static int SCRConfTest01(void) |
598 | | { |
599 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
600 | | int result = 0; |
601 | | |
602 | | if (de_ctx == NULL) |
603 | | return result; |
604 | | |
605 | | FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); |
606 | | SCRConfLoadReferenceConfigFile(de_ctx, fd); |
607 | | |
608 | | if (de_ctx->reference_conf_ht == NULL) |
609 | | goto end; |
610 | | |
611 | | result = (de_ctx->reference_conf_ht->count == 3); |
612 | | if (result == 0) |
613 | | printf("FAILED: de_ctx->reference_conf_ht->count %u: ", de_ctx->reference_conf_ht->count); |
614 | | |
615 | | end: |
616 | | if (de_ctx != NULL) |
617 | | DetectEngineCtxFree(de_ctx); |
618 | | return result; |
619 | | } |
620 | | |
621 | | /** |
622 | | * \test Check that invalid references present in the reference.config file |
623 | | * aren't loaded. |
624 | | */ |
625 | | static int SCRConfTest02(void) |
626 | | { |
627 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
628 | | int result = 0; |
629 | | |
630 | | if (de_ctx == NULL) |
631 | | return result; |
632 | | |
633 | | FILE *fd = SCRConfGenerateInvalidDummyReferenceConfigFD03(); |
634 | | SCRConfLoadReferenceConfigFile(de_ctx, fd); |
635 | | |
636 | | if (de_ctx->reference_conf_ht == NULL) |
637 | | goto end; |
638 | | |
639 | | result = (de_ctx->reference_conf_ht->count == 0); |
640 | | |
641 | | |
642 | | end: |
643 | | if (de_ctx != NULL) |
644 | | DetectEngineCtxFree(de_ctx); |
645 | | return result; |
646 | | } |
647 | | |
648 | | /** |
649 | | * \test Check that only valid references are loaded into the hash table from |
650 | | * the reference.config file. |
651 | | */ |
652 | | static int SCRConfTest03(void) |
653 | | { |
654 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
655 | | int result = 0; |
656 | | |
657 | | if (de_ctx == NULL) |
658 | | return result; |
659 | | |
660 | | FILE *fd = SCRConfGenerateInvalidDummyReferenceConfigFD02(); |
661 | | SCRConfLoadReferenceConfigFile(de_ctx, fd); |
662 | | |
663 | | if (de_ctx->reference_conf_ht == NULL) |
664 | | goto end; |
665 | | |
666 | | result = (de_ctx->reference_conf_ht->count == 1); |
667 | | |
668 | | end: |
669 | | if (de_ctx != NULL) |
670 | | DetectEngineCtxFree(de_ctx); |
671 | | return result; |
672 | | } |
673 | | |
674 | | /** |
675 | | * \test Check if the reference info from the reference.config file have |
676 | | * been loaded into the hash table. |
677 | | */ |
678 | | static int SCRConfTest04(void) |
679 | | { |
680 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
681 | | int result = 1; |
682 | | |
683 | | if (de_ctx == NULL) |
684 | | return 0; |
685 | | |
686 | | FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); |
687 | | SCRConfLoadReferenceConfigFile(de_ctx, fd); |
688 | | |
689 | | if (de_ctx->reference_conf_ht == NULL) |
690 | | goto end; |
691 | | |
692 | | result = (de_ctx->reference_conf_ht->count == 3); |
693 | | |
694 | | result &= (SCRConfGetReference("one", de_ctx) != NULL); |
695 | | result &= (SCRConfGetReference("two", de_ctx) != NULL); |
696 | | result &= (SCRConfGetReference("three", de_ctx) != NULL); |
697 | | result &= (SCRConfGetReference("four", de_ctx) == NULL); |
698 | | |
699 | | end: |
700 | | if (de_ctx != NULL) |
701 | | DetectEngineCtxFree(de_ctx); |
702 | | return result; |
703 | | } |
704 | | |
705 | | /** |
706 | | * \test Check if the reference info from the invalid reference.config file |
707 | | * have not been loaded into the hash table, and cross verify to check |
708 | | * that the hash table contains no reference data. |
709 | | */ |
710 | | static int SCRConfTest05(void) |
711 | | { |
712 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
713 | | int result = 1; |
714 | | |
715 | | if (de_ctx == NULL) |
716 | | return 0; |
717 | | |
718 | | FILE *fd = SCRConfGenerateInvalidDummyReferenceConfigFD03(); |
719 | | SCRConfLoadReferenceConfigFile(de_ctx, fd); |
720 | | |
721 | | if (de_ctx->reference_conf_ht == NULL) |
722 | | goto end; |
723 | | |
724 | | result = (de_ctx->reference_conf_ht->count == 0); |
725 | | |
726 | | result &= (SCRConfGetReference("one", de_ctx) == NULL); |
727 | | result &= (SCRConfGetReference("two", de_ctx) == NULL); |
728 | | result &= (SCRConfGetReference("three", de_ctx) == NULL); |
729 | | result &= (SCRConfGetReference("four", de_ctx) == NULL); |
730 | | result &= (SCRConfGetReference("five", de_ctx) == NULL); |
731 | | |
732 | | end: |
733 | | if (de_ctx != NULL) |
734 | | DetectEngineCtxFree(de_ctx); |
735 | | return result; |
736 | | } |
737 | | |
738 | | /** |
739 | | * \test Check if the reference info from the reference.config file have |
740 | | * been loaded into the hash table. |
741 | | */ |
742 | | static int SCRConfTest06(void) |
743 | | { |
744 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
745 | | int result = 1; |
746 | | |
747 | | if (de_ctx == NULL) |
748 | | return 0; |
749 | | |
750 | | FILE *fd = SCRConfGenerateInvalidDummyReferenceConfigFD02(); |
751 | | SCRConfLoadReferenceConfigFile(de_ctx, fd); |
752 | | |
753 | | if (de_ctx->reference_conf_ht == NULL) |
754 | | goto end; |
755 | | |
756 | | result = (de_ctx->reference_conf_ht->count == 1); |
757 | | |
758 | | result &= (SCRConfGetReference("one", de_ctx) != NULL); |
759 | | result &= (SCRConfGetReference("two", de_ctx) == NULL); |
760 | | result &= (SCRConfGetReference("three", de_ctx) == NULL); |
761 | | result &= (SCRConfGetReference("four", de_ctx) == NULL); |
762 | | result &= (SCRConfGetReference("five", de_ctx) == NULL); |
763 | | |
764 | | end: |
765 | | if (de_ctx != NULL) |
766 | | DetectEngineCtxFree(de_ctx); |
767 | | return result; |
768 | | } |
769 | | |
770 | | #endif /* UNITTESTS */ |
771 | | |
772 | | /** |
773 | | * \brief This function registers unit tests for Reference Config API. |
774 | | */ |
775 | | void SCRConfRegisterTests(void) |
776 | 0 | { |
777 | |
|
778 | | #ifdef UNITTESTS |
779 | | UtRegisterTest("SCRConfTest01", SCRConfTest01); |
780 | | UtRegisterTest("SCRConfTest02", SCRConfTest02); |
781 | | UtRegisterTest("SCRConfTest03", SCRConfTest03); |
782 | | UtRegisterTest("SCRConfTest04", SCRConfTest04); |
783 | | UtRegisterTest("SCRConfTest05", SCRConfTest05); |
784 | | UtRegisterTest("SCRConfTest06", SCRConfTest06); |
785 | | #endif /* UNITTESTS */ |
786 | 0 | } |