1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * SPDX-License-Identifier: MPL-2.0
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14 #if HAVE_CMOCKA
15
16 #include <sched.h> /* IWYU pragma: keep */
17 #include <setjmp.h>
18 #include <stdarg.h>
19 #include <stddef.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22
23 #define UNIT_TESTING
24 #include <cmocka.h>
25
26 #include <dns/db.h>
27 #include <dns/dbiterator.h>
28 #include <dns/journal.h>
29 #include <dns/name.h>
30 #include <dns/rdatalist.h>
31
32 #include "dnstest.h"
33
34 static int
_setup(void ** state)35 _setup(void **state) {
36 isc_result_t result;
37
38 UNUSED(state);
39
40 result = dns_test_begin(NULL, false);
41 assert_int_equal(result, ISC_R_SUCCESS);
42
43 return (0);
44 }
45
46 static int
_teardown(void ** state)47 _teardown(void **state) {
48 UNUSED(state);
49
50 dns_test_end();
51
52 return (0);
53 }
54
55 #define BUFLEN 255
56 #define BIGBUFLEN (64 * 1024)
57 #define TEST_ORIGIN "test"
58
59 /*
60 * Individual unit tests
61 */
62
63 /* test multiple calls to dns_db_getoriginnode */
64 static void
getoriginnode_test(void ** state)65 getoriginnode_test(void **state) {
66 dns_db_t *db = NULL;
67 dns_dbnode_t *node = NULL;
68 isc_mem_t *mctx = NULL;
69 isc_result_t result;
70
71 UNUSED(state);
72
73 isc_mem_create(&mctx);
74
75 result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
76 dns_rdataclass_in, 0, NULL, &db);
77 assert_int_equal(result, ISC_R_SUCCESS);
78
79 result = dns_db_getoriginnode(db, &node);
80 assert_int_equal(result, ISC_R_SUCCESS);
81 dns_db_detachnode(db, &node);
82
83 result = dns_db_getoriginnode(db, &node);
84 assert_int_equal(result, ISC_R_SUCCESS);
85 dns_db_detachnode(db, &node);
86
87 dns_db_detach(&db);
88 isc_mem_detach(&mctx);
89 }
90
91 /* test getservestalettl and setservestalettl */
92 static void
getsetservestalettl_test(void ** state)93 getsetservestalettl_test(void **state) {
94 dns_db_t *db = NULL;
95 isc_mem_t *mctx = NULL;
96 isc_result_t result;
97 dns_ttl_t ttl;
98
99 UNUSED(state);
100
101 isc_mem_create(&mctx);
102
103 result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_cache,
104 dns_rdataclass_in, 0, NULL, &db);
105 assert_int_equal(result, ISC_R_SUCCESS);
106
107 ttl = 5000;
108 result = dns_db_getservestalettl(db, &ttl);
109 assert_int_equal(result, ISC_R_SUCCESS);
110 assert_int_equal(ttl, 0);
111
112 ttl = 6 * 3600;
113 result = dns_db_setservestalettl(db, ttl);
114 assert_int_equal(result, ISC_R_SUCCESS);
115
116 ttl = 5000;
117 result = dns_db_getservestalettl(db, &ttl);
118 assert_int_equal(result, ISC_R_SUCCESS);
119 assert_int_equal(ttl, 6 * 3600);
120
121 dns_db_detach(&db);
122 isc_mem_detach(&mctx);
123 }
124
125 /* check DNS_DBFIND_STALEOK works */
126 static void
dns_dbfind_staleok_test(void ** state)127 dns_dbfind_staleok_test(void **state) {
128 dns_db_t *db = NULL;
129 dns_dbnode_t *node = NULL;
130 dns_fixedname_t example_fixed;
131 dns_fixedname_t found_fixed;
132 dns_name_t *example;
133 dns_name_t *found;
134 dns_rdatalist_t rdatalist;
135 dns_rdataset_t rdataset;
136 int count;
137 int pass;
138 isc_mem_t *mctx = NULL;
139 isc_result_t result;
140 unsigned char data[] = { 0x0a, 0x00, 0x00, 0x01 };
141
142 UNUSED(state);
143
144 isc_mem_create(&mctx);
145
146 result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_cache,
147 dns_rdataclass_in, 0, NULL, &db);
148 assert_int_equal(result, ISC_R_SUCCESS);
149
150 example = dns_fixedname_initname(&example_fixed);
151 found = dns_fixedname_initname(&found_fixed);
152
153 result = dns_name_fromstring(example, "example", 0, NULL);
154 assert_int_equal(result, ISC_R_SUCCESS);
155
156 /*
157 * Pass 0: default; no stale processing permitted.
158 * Pass 1: stale processing for 1 second.
159 * Pass 2: stale turned off after being on.
160 */
161 for (pass = 0; pass < 3; pass++) {
162 dns_rdata_t rdata = DNS_RDATA_INIT;
163
164 /* 10.0.0.1 */
165 rdata.data = data;
166 rdata.length = 4;
167 rdata.rdclass = dns_rdataclass_in;
168 rdata.type = dns_rdatatype_a;
169
170 dns_rdatalist_init(&rdatalist);
171 rdatalist.ttl = 2;
172 rdatalist.type = dns_rdatatype_a;
173 rdatalist.rdclass = dns_rdataclass_in;
174 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
175
176 switch (pass) {
177 case 0:
178 /* default: stale processing off */
179 break;
180 case 1:
181 /* turn on stale processing */
182 result = dns_db_setservestalettl(db, 1);
183 assert_int_equal(result, ISC_R_SUCCESS);
184 break;
185 case 2:
186 /* turn off stale processing */
187 result = dns_db_setservestalettl(db, 0);
188 assert_int_equal(result, ISC_R_SUCCESS);
189 break;
190 }
191
192 dns_rdataset_init(&rdataset);
193 result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
194 assert_int_equal(result, ISC_R_SUCCESS);
195
196 result = dns_db_findnode(db, example, true, &node);
197 assert_int_equal(result, ISC_R_SUCCESS);
198
199 result = dns_db_addrdataset(db, node, NULL, 0, &rdataset, 0,
200 NULL);
201 assert_int_equal(result, ISC_R_SUCCESS);
202
203 dns_db_detachnode(db, &node);
204 dns_rdataset_disassociate(&rdataset);
205
206 result = dns_db_find(db, example, NULL, dns_rdatatype_a, 0, 0,
207 &node, found, &rdataset, NULL);
208 assert_int_equal(result, ISC_R_SUCCESS);
209
210 /*
211 * May loop for up to 2 seconds performing non stale lookups.
212 */
213 count = 0;
214 do {
215 count++;
216 assert_in_range(count, 1, 21); /* loop sanity */
217 assert_int_equal(rdataset.attributes &
218 DNS_RDATASETATTR_STALE,
219 0);
220 assert_true(rdataset.ttl > 0);
221 dns_db_detachnode(db, &node);
222 dns_rdataset_disassociate(&rdataset);
223
224 usleep(100000); /* 100 ms */
225
226 result = dns_db_find(db, example, NULL, dns_rdatatype_a,
227 0, 0, &node, found, &rdataset,
228 NULL);
229 } while (result == ISC_R_SUCCESS);
230
231 assert_int_equal(result, ISC_R_NOTFOUND);
232
233 /*
234 * Check whether we can get stale data.
235 */
236 result = dns_db_find(db, example, NULL, dns_rdatatype_a,
237 DNS_DBFIND_STALEOK, 0, &node, found,
238 &rdataset, NULL);
239 switch (pass) {
240 case 0:
241 assert_int_equal(result, ISC_R_NOTFOUND);
242 break;
243 case 1:
244 /*
245 * Should loop for 1 second with stale lookups then
246 * stop.
247 */
248 count = 0;
249 do {
250 count++;
251 assert_in_range(count, 0, 49); /* loop sanity */
252 assert_int_equal(result, ISC_R_SUCCESS);
253 assert_int_equal(rdataset.attributes &
254 DNS_RDATASETATTR_STALE,
255 DNS_RDATASETATTR_STALE);
256 dns_db_detachnode(db, &node);
257 dns_rdataset_disassociate(&rdataset);
258
259 usleep(100000); /* 100 ms */
260
261 result = dns_db_find(
262 db, example, NULL, dns_rdatatype_a,
263 DNS_DBFIND_STALEOK, 0, &node, found,
264 &rdataset, NULL);
265 } while (result == ISC_R_SUCCESS);
266 /*
267 * usleep(100000) can be slightly less than 10ms so
268 * allow the count to reach 11.
269 */
270 assert_in_range(count, 1, 11);
271 assert_int_equal(result, ISC_R_NOTFOUND);
272 break;
273 case 2:
274 assert_int_equal(result, ISC_R_NOTFOUND);
275 break;
276 }
277 }
278
279 dns_db_detach(&db);
280 isc_mem_detach(&mctx);
281 }
282
283 /* database class */
284 static void
class_test(void ** state)285 class_test(void **state) {
286 isc_result_t result;
287 dns_db_t *db = NULL;
288
289 UNUSED(state);
290
291 result = dns_db_create(dt_mctx, "rbt", dns_rootname, dns_dbtype_zone,
292 dns_rdataclass_in, 0, NULL, &db);
293 assert_int_equal(result, ISC_R_SUCCESS);
294
295 result = dns_db_load(db, "testdata/db/data.db", dns_masterformat_text,
296 0);
297 assert_int_equal(result, ISC_R_SUCCESS);
298
299 assert_int_equal(dns_db_class(db), dns_rdataclass_in);
300
301 dns_db_detach(&db);
302 }
303
304 /* database type */
305 static void
dbtype_test(void ** state)306 dbtype_test(void **state) {
307 isc_result_t result;
308 dns_db_t *db = NULL;
309
310 UNUSED(state);
311
312 /* DB has zone semantics */
313 result = dns_db_create(dt_mctx, "rbt", dns_rootname, dns_dbtype_zone,
314 dns_rdataclass_in, 0, NULL, &db);
315 assert_int_equal(result, ISC_R_SUCCESS);
316 result = dns_db_load(db, "testdata/db/data.db", dns_masterformat_text,
317 0);
318 assert_int_equal(result, ISC_R_SUCCESS);
319 assert_true(dns_db_iszone(db));
320 assert_false(dns_db_iscache(db));
321 dns_db_detach(&db);
322
323 /* DB has cache semantics */
324 result = dns_db_create(dt_mctx, "rbt", dns_rootname, dns_dbtype_cache,
325 dns_rdataclass_in, 0, NULL, &db);
326 assert_int_equal(result, ISC_R_SUCCESS);
327 result = dns_db_load(db, "testdata/db/data.db", dns_masterformat_text,
328 0);
329 assert_int_equal(result, ISC_R_SUCCESS);
330 assert_true(dns_db_iscache(db));
331 assert_false(dns_db_iszone(db));
332 dns_db_detach(&db);
333 }
334
335 /* database versions */
336 static void
version_test(void ** state)337 version_test(void **state) {
338 isc_result_t result;
339 dns_fixedname_t fname, ffound;
340 dns_name_t *name, *foundname;
341 dns_db_t *db = NULL;
342 dns_dbversion_t *ver = NULL, *new = NULL;
343 dns_dbnode_t *node = NULL;
344 dns_rdataset_t rdataset;
345
346 UNUSED(state);
347
348 result = dns_test_loaddb(&db, dns_dbtype_zone, "test.test",
349 "testdata/db/data.db");
350 assert_int_equal(result, ISC_R_SUCCESS);
351
352 /* Open current version for reading */
353 dns_db_currentversion(db, &ver);
354 dns_test_namefromstring("b.test.test", &fname);
355 name = dns_fixedname_name(&fname);
356 foundname = dns_fixedname_initname(&ffound);
357 dns_rdataset_init(&rdataset);
358 result = dns_db_find(db, name, ver, dns_rdatatype_a, 0, 0, &node,
359 foundname, &rdataset, NULL);
360 assert_int_equal(result, ISC_R_SUCCESS);
361 dns_rdataset_disassociate(&rdataset);
362 dns_db_detachnode(db, &node);
363 dns_db_closeversion(db, &ver, false);
364
365 /* Open new version for writing */
366 dns_db_currentversion(db, &ver);
367 dns_test_namefromstring("b.test.test", &fname);
368 name = dns_fixedname_name(&fname);
369 foundname = dns_fixedname_initname(&ffound);
370 dns_rdataset_init(&rdataset);
371 result = dns_db_find(db, name, ver, dns_rdatatype_a, 0, 0, &node,
372 foundname, &rdataset, NULL);
373 assert_int_equal(result, ISC_R_SUCCESS);
374
375 result = dns_db_newversion(db, &new);
376 assert_int_equal(result, ISC_R_SUCCESS);
377
378 /* Delete the rdataset from the new version */
379 result = dns_db_deleterdataset(db, node, new, dns_rdatatype_a, 0);
380 assert_int_equal(result, ISC_R_SUCCESS);
381
382 dns_rdataset_disassociate(&rdataset);
383 dns_db_detachnode(db, &node);
384
385 /* This should fail now */
386 result = dns_db_find(db, name, new, dns_rdatatype_a, 0, 0, &node,
387 foundname, &rdataset, NULL);
388 assert_int_equal(result, DNS_R_NXDOMAIN);
389
390 dns_db_closeversion(db, &new, true);
391
392 /* But this should still succeed */
393 result = dns_db_find(db, name, ver, dns_rdatatype_a, 0, 0, &node,
394 foundname, &rdataset, NULL);
395 assert_int_equal(result, ISC_R_SUCCESS);
396 dns_rdataset_disassociate(&rdataset);
397 dns_db_detachnode(db, &node);
398 dns_db_closeversion(db, &ver, false);
399
400 dns_db_detach(&db);
401 }
402
403 int
main(void)404 main(void) {
405 const struct CMUnitTest tests[] = {
406 cmocka_unit_test(getoriginnode_test),
407 cmocka_unit_test(getsetservestalettl_test),
408 cmocka_unit_test(dns_dbfind_staleok_test),
409 cmocka_unit_test_setup_teardown(class_test, _setup, _teardown),
410 cmocka_unit_test_setup_teardown(dbtype_test, _setup, _teardown),
411 cmocka_unit_test_setup_teardown(version_test, _setup,
412 _teardown),
413 };
414
415 return (cmocka_run_group_tests(tests, NULL, NULL));
416 }
417
418 #else /* HAVE_CMOCKA */
419
420 #include <stdio.h>
421
422 int
main(void)423 main(void) {
424 printf("1..0 # Skipped: cmocka not available\n");
425 return (SKIPPED_TEST_EXIT_CODE);
426 }
427
428 #endif /* if HAVE_CMOCKA */
429