dbversion_test.c revision 1.1 1 /* $NetBSD: dbversion_test.c,v 1.1 2024/02/21 21:54:55 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 #include <inttypes.h>
17 #include <sched.h> /* IWYU pragma: keep */
18 #include <setjmp.h>
19 #include <stdarg.h>
20 #include <stddef.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #define UNIT_TESTING
26 #include <cmocka.h>
27
28 #include <isc/file.h>
29 #include <isc/result.h>
30 #include <isc/serial.h>
31 #include <isc/stdtime.h>
32 #include <isc/string.h>
33 #include <isc/util.h>
34
35 #include <dns/db.h>
36 #include <dns/nsec3.h>
37 #include <dns/rdatalist.h>
38 #include <dns/rdataset.h>
39 #include <dns/rdatasetiter.h>
40
41 #include <tests/dns.h>
42
43 static char tempname[11] = "dtXXXXXXXX";
44 static dns_db_t *db1 = NULL, *db2 = NULL;
45 static dns_dbversion_t *v1 = NULL, *v2 = NULL;
46
47 /*
48 * The code below enables us to trap assertion failures for testing
49 * purposes. local_callback() is set as the callback function for
50 * isc_assertion_failed(). It calls mock_assert() so that CMOCKA
51 * will be able to see it, then returns to the calling function via
52 * longjmp() so that the abort() call in isc_assertion_failed() will
53 * never be reached. Use check_assertion() to check for assertions
54 * instead of expect_assert_failure().
55 */
56 jmp_buf assertion;
57
58 #define check_assertion(function_call) \
59 do { \
60 const int r = setjmp(assertion); \
61 if (r == 0) { \
62 expect_assert_failure(function_call); \
63 } \
64 } while (false);
65
66 static void
67 local_callback(const char *file, int line, isc_assertiontype_t type,
68 const char *cond) {
69 UNUSED(type);
70
71 mock_assert(1, cond, file, line);
72 longjmp(assertion, 1);
73 }
74
75 static int
76 setup_test(void **state) {
77 isc_result_t res;
78
79 UNUSED(state);
80
81 isc_assertion_setcallback(local_callback);
82
83 res = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
84 dns_rdataclass_in, 0, NULL, &db1);
85 assert_int_equal(res, ISC_R_SUCCESS);
86 dns_db_newversion(db1, &v1);
87 assert_non_null(v1);
88
89 res = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
90 dns_rdataclass_in, 0, NULL, &db2);
91 assert_int_equal(res, ISC_R_SUCCESS);
92 dns_db_newversion(db2, &v2);
93 assert_non_null(v1);
94
95 return (0);
96 }
97
98 static int
99 teardown_test(void **state) {
100 UNUSED(state);
101
102 if (strcmp(tempname, "dtXXXXXXXX") != 0) {
103 unlink(tempname);
104 }
105
106 if (v1 != NULL) {
107 dns_db_closeversion(db1, &v1, false);
108 assert_null(v1);
109 }
110 if (db1 != NULL) {
111 dns_db_detach(&db1);
112 assert_null(db1);
113 }
114
115 if (v2 != NULL) {
116 dns_db_closeversion(db2, &v2, false);
117 assert_null(v2);
118 }
119 if (db2 != NULL) {
120 dns_db_detach(&db2);
121 assert_null(db2);
122 }
123
124 return (0);
125 }
126
127 /*
128 * Check dns_db_attachversion() passes with matching db and version, and
129 * asserts with mis-matching db and version.
130 */
131 ISC_RUN_TEST_IMPL(attachversion) {
132 dns_dbversion_t *v = NULL;
133
134 UNUSED(state);
135
136 dns_db_attachversion(db1, v1, &v);
137 assert_ptr_equal(v, v1);
138 dns_db_closeversion(db1, &v, false);
139 assert_null(v);
140
141 check_assertion(dns_db_attachversion(db1, v2, &v));
142 }
143
144 /*
145 * Check dns_db_closeversion() passes with matching db and version, and
146 * asserts with mis-matching db and version.
147 */
148 ISC_RUN_TEST_IMPL(closeversion) {
149 UNUSED(state);
150
151 assert_non_null(v1);
152 dns_db_closeversion(db1, &v1, false);
153 assert_null(v1);
154
155 check_assertion(dns_db_closeversion(db1, &v2, false));
156 }
157
158 /*
159 * Check dns_db_find() passes with matching db and version, and
160 * asserts with mis-matching db and version.
161 */
162 ISC_RUN_TEST_IMPL(find) {
163 isc_result_t res;
164 dns_rdataset_t rdataset;
165 dns_fixedname_t fixed;
166 dns_name_t *name = NULL;
167
168 UNUSED(state);
169
170 name = dns_fixedname_initname(&fixed);
171
172 dns_rdataset_init(&rdataset);
173 res = dns_db_find(db1, dns_rootname, v1, dns_rdatatype_soa, 0, 0, NULL,
174 name, &rdataset, NULL);
175 assert_int_equal(res, DNS_R_NXDOMAIN);
176
177 if (dns_rdataset_isassociated(&rdataset)) {
178 dns_rdataset_disassociate(&rdataset);
179 }
180
181 dns_rdataset_init(&rdataset);
182 check_assertion((void)dns_db_find(db1, dns_rootname, v2,
183 dns_rdatatype_soa, 0, 0, NULL, name,
184 &rdataset, NULL));
185 }
186
187 /*
188 * Check dns_db_allrdatasets() passes with matching db and version, and
189 * asserts with mis-matching db and version.
190 */
191 ISC_RUN_TEST_IMPL(allrdatasets) {
192 isc_result_t res;
193 dns_dbnode_t *node = NULL;
194 dns_rdatasetiter_t *iterator = NULL;
195
196 UNUSED(state);
197
198 res = dns_db_findnode(db1, dns_rootname, false, &node);
199 assert_int_equal(res, ISC_R_SUCCESS);
200
201 res = dns_db_allrdatasets(db1, node, v1, 0, 0, &iterator);
202 assert_int_equal(res, ISC_R_SUCCESS);
203
204 check_assertion(dns_db_allrdatasets(db1, node, v2, 0, 0, &iterator));
205
206 dns_rdatasetiter_destroy(&iterator);
207 assert_null(iterator);
208
209 dns_db_detachnode(db1, &node);
210 assert_null(node);
211 }
212
213 /*
214 * Check dns_db_findrdataset() passes with matching db and version, and
215 * asserts with mis-matching db and version.
216 */
217 ISC_RUN_TEST_IMPL(findrdataset) {
218 isc_result_t res;
219 dns_rdataset_t rdataset;
220 dns_dbnode_t *node = NULL;
221
222 UNUSED(state);
223
224 res = dns_db_findnode(db1, dns_rootname, false, &node);
225 assert_int_equal(res, ISC_R_SUCCESS);
226
227 dns_rdataset_init(&rdataset);
228 res = dns_db_findrdataset(db1, node, v1, dns_rdatatype_soa, 0, 0,
229 &rdataset, NULL);
230 assert_int_equal(res, ISC_R_NOTFOUND);
231
232 if (dns_rdataset_isassociated(&rdataset)) {
233 dns_rdataset_disassociate(&rdataset);
234 }
235
236 dns_rdataset_init(&rdataset);
237 check_assertion(dns_db_findrdataset(db1, node, v2, dns_rdatatype_soa, 0,
238 0, &rdataset, NULL));
239
240 dns_db_detachnode(db1, &node);
241 assert_null(node);
242 }
243
244 /*
245 * Check dns_db_deleterdataset() passes with matching db and version, and
246 * asserts with mis-matching db and version.
247 */
248 ISC_RUN_TEST_IMPL(deleterdataset) {
249 isc_result_t res;
250 dns_dbnode_t *node = NULL;
251
252 UNUSED(state);
253
254 res = dns_db_findnode(db1, dns_rootname, false, &node);
255 assert_int_equal(res, ISC_R_SUCCESS);
256
257 res = dns_db_deleterdataset(db1, node, v1, dns_rdatatype_soa, 0);
258 assert_int_equal(res, DNS_R_UNCHANGED);
259
260 check_assertion(
261 dns_db_deleterdataset(db1, node, v2, dns_rdatatype_soa, 0));
262 dns_db_detachnode(db1, &node);
263 assert_null(node);
264 }
265
266 /*
267 * Check dns_db_subtractrdataset() passes with matching db and version, and
268 * asserts with mis-matching db and version.
269 */
270 ISC_RUN_TEST_IMPL(subtract) {
271 isc_result_t res;
272 dns_rdataset_t rdataset;
273 dns_rdatalist_t rdatalist;
274 dns_dbnode_t *node = NULL;
275
276 UNUSED(state);
277
278 dns_rdataset_init(&rdataset);
279 dns_rdatalist_init(&rdatalist);
280
281 rdatalist.rdclass = dns_rdataclass_in;
282
283 res = dns_rdatalist_tordataset(&rdatalist, &rdataset);
284 assert_int_equal(res, ISC_R_SUCCESS);
285
286 res = dns_db_findnode(db1, dns_rootname, false, &node);
287 assert_int_equal(res, ISC_R_SUCCESS);
288
289 res = dns_db_subtractrdataset(db1, node, v1, &rdataset, 0, NULL);
290 assert_int_equal(res, DNS_R_UNCHANGED);
291
292 if (dns_rdataset_isassociated(&rdataset)) {
293 dns_rdataset_disassociate(&rdataset);
294 }
295
296 dns_rdataset_init(&rdataset);
297 res = dns_rdatalist_tordataset(&rdatalist, &rdataset);
298 assert_int_equal(res, ISC_R_SUCCESS);
299
300 check_assertion(
301 dns_db_subtractrdataset(db1, node, v2, &rdataset, 0, NULL));
302
303 dns_db_detachnode(db1, &node);
304 assert_null(node);
305 }
306
307 /*
308 * Check dns_db_dump() passes with matching db and version, and
309 * asserts with mis-matching db and version.
310 */
311 ISC_RUN_TEST_IMPL(dump) {
312 isc_result_t res;
313 FILE *f = NULL;
314
315 UNUSED(state);
316
317 res = isc_file_openunique(tempname, &f);
318 fclose(f);
319 assert_int_equal(res, ISC_R_SUCCESS);
320
321 res = dns_db_dump(db1, v1, tempname);
322 assert_int_equal(res, ISC_R_SUCCESS);
323
324 check_assertion(dns_db_dump(db1, v2, tempname));
325 }
326
327 /*
328 * Check dns_db_addrdataset() passes with matching db and version, and
329 * asserts with mis-matching db and version.
330 */
331 ISC_RUN_TEST_IMPL(addrdataset) {
332 isc_result_t res;
333 dns_rdataset_t rdataset;
334 dns_dbnode_t *node = NULL;
335 dns_rdatalist_t rdatalist;
336
337 UNUSED(state);
338
339 dns_rdataset_init(&rdataset);
340 dns_rdatalist_init(&rdatalist);
341
342 rdatalist.rdclass = dns_rdataclass_in;
343
344 res = dns_rdatalist_tordataset(&rdatalist, &rdataset);
345 assert_int_equal(res, ISC_R_SUCCESS);
346
347 res = dns_db_findnode(db1, dns_rootname, false, &node);
348 assert_int_equal(res, ISC_R_SUCCESS);
349
350 res = dns_db_addrdataset(db1, node, v1, 0, &rdataset, 0, NULL);
351 assert_int_equal(res, ISC_R_SUCCESS);
352
353 check_assertion(
354 dns_db_addrdataset(db1, node, v2, 0, &rdataset, 0, NULL));
355
356 dns_db_detachnode(db1, &node);
357 assert_null(node);
358 }
359
360 /*
361 * Check dns_db_getnsec3parameters() passes with matching db and version,
362 * and asserts with mis-matching db and version.
363 */
364 ISC_RUN_TEST_IMPL(getnsec3parameters) {
365 isc_result_t res;
366 dns_hash_t hash;
367 uint8_t flags;
368 uint16_t iterations;
369 unsigned char salt[DNS_NSEC3_SALTSIZE];
370 size_t salt_length = sizeof(salt);
371
372 UNUSED(state);
373
374 res = dns_db_getnsec3parameters(db1, v1, &hash, &flags, &iterations,
375 salt, &salt_length);
376 assert_int_equal(res, ISC_R_NOTFOUND);
377
378 check_assertion(dns_db_getnsec3parameters(
379 db1, v2, &hash, &flags, &iterations, salt, &salt_length));
380 }
381
382 /*
383 * Check dns_db_resigned() passes with matching db and version, and
384 * asserts with mis-matching db and version.
385 */
386 ISC_RUN_TEST_IMPL(resigned) {
387 isc_result_t res;
388 dns_rdataset_t rdataset, added;
389 dns_dbnode_t *node = NULL;
390 dns_rdatalist_t rdatalist;
391 dns_rdata_rrsig_t rrsig;
392 dns_rdata_t rdata = DNS_RDATA_INIT;
393 isc_buffer_t b;
394 unsigned char buf[1024];
395
396 UNUSED(state);
397
398 /*
399 * Create a dummy RRSIG record and set a resigning time.
400 */
401 dns_rdataset_init(&added);
402 dns_rdataset_init(&rdataset);
403 dns_rdatalist_init(&rdatalist);
404 isc_buffer_init(&b, buf, sizeof(buf));
405
406 DNS_RDATACOMMON_INIT(&rrsig, dns_rdatatype_rrsig, dns_rdataclass_in);
407 rrsig.covered = dns_rdatatype_a;
408 rrsig.algorithm = 100;
409 rrsig.labels = 0;
410 rrsig.originalttl = 0;
411 rrsig.timeexpire = 3600;
412 rrsig.timesigned = 0;
413 rrsig.keyid = 0;
414 dns_name_init(&rrsig.signer, NULL);
415 dns_name_clone(dns_rootname, &rrsig.signer);
416 rrsig.siglen = 0;
417 rrsig.signature = NULL;
418
419 res = dns_rdata_fromstruct(&rdata, dns_rdataclass_in,
420 dns_rdatatype_rrsig, &rrsig, &b);
421 assert_int_equal(res, ISC_R_SUCCESS);
422
423 rdatalist.rdclass = dns_rdataclass_in;
424 rdatalist.type = dns_rdatatype_rrsig;
425 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
426
427 res = dns_rdatalist_tordataset(&rdatalist, &rdataset);
428 assert_int_equal(res, ISC_R_SUCCESS);
429
430 rdataset.attributes |= DNS_RDATASETATTR_RESIGN;
431 rdataset.resign = 7200;
432
433 res = dns_db_findnode(db1, dns_rootname, false, &node);
434 assert_int_equal(res, ISC_R_SUCCESS);
435
436 res = dns_db_addrdataset(db1, node, v1, 0, &rdataset, 0, &added);
437 assert_int_equal(res, ISC_R_SUCCESS);
438
439 dns_db_detachnode(db1, &node);
440 assert_null(node);
441
442 check_assertion(dns_db_resigned(db1, &added, v2));
443
444 dns_db_resigned(db1, &added, v1);
445
446 dns_rdataset_disassociate(&added);
447 }
448
449 ISC_TEST_LIST_START
450 ISC_TEST_ENTRY_CUSTOM(dump, setup_test, teardown_test)
451 ISC_TEST_ENTRY_CUSTOM(find, setup_test, teardown_test)
452 ISC_TEST_ENTRY_CUSTOM(allrdatasets, setup_test, teardown_test)
453 ISC_TEST_ENTRY_CUSTOM(findrdataset, setup_test, teardown_test)
454 ISC_TEST_ENTRY_CUSTOM(deleterdataset, setup_test, teardown_test)
455 ISC_TEST_ENTRY_CUSTOM(subtract, setup_test, teardown_test)
456 ISC_TEST_ENTRY_CUSTOM(addrdataset, setup_test, teardown_test)
457 ISC_TEST_ENTRY_CUSTOM(getnsec3parameters, setup_test, teardown_test)
458 ISC_TEST_ENTRY_CUSTOM(resigned, setup_test, teardown_test)
459 ISC_TEST_ENTRY_CUSTOM(attachversion, setup_test, teardown_test)
460 ISC_TEST_ENTRY_CUSTOM(closeversion, setup_test, teardown_test)
461 ISC_TEST_LIST_END
462
463 ISC_TEST_MAIN
464