Annotation of src/external/mpl/bind/dist/lib/dns/tests/dnstest.c, Revision 1.1.1.9
1.1 christos 1: /* $NetBSD$ */
2:
3: /*
4: * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5: *
1.1.1.9 ! christos 6: * SPDX-License-Identifier: MPL-2.0
! 7: *
1.1 christos 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
1.1.1.7 christos 10: * file, you can obtain one at https://mozilla.org/MPL/2.0/.
1.1 christos 11: *
12: * See the COPYRIGHT file distributed with this work for additional
13: * information regarding copyright ownership.
14: */
15:
16: /*! \file */
17:
1.1.1.2 christos 18: #include <inttypes.h>
1.1.1.4 christos 19: #include <sched.h> /* IWYU pragma: keep */
1.1.1.6 christos 20: #include <setjmp.h>
21: #include <stdarg.h>
1.1.1.2 christos 22: #include <stdbool.h>
1.1.1.6 christos 23: #include <stddef.h>
1.1 christos 24: #include <stdlib.h>
1.1.1.4 christos 25: #include <string.h>
1.1 christos 26: #include <time.h>
27: #include <unistd.h>
28:
1.1.1.2 christos 29: #if HAVE_CMOCKA
30: #define UNIT_TESTING
31: #include <cmocka.h>
32:
1.1 christos 33: #include <isc/app.h>
34: #include <isc/buffer.h>
35: #include <isc/file.h>
36: #include <isc/hash.h>
37: #include <isc/hex.h>
38: #include <isc/lex.h>
1.1.1.8 christos 39: #include <isc/managers.h>
1.1 christos 40: #include <isc/mem.h>
41: #include <isc/os.h>
42: #include <isc/print.h>
43: #include <isc/socket.h>
44: #include <isc/stdio.h>
1.1.1.6 christos 45: #include <isc/string.h>
1.1 christos 46: #include <isc/task.h>
47: #include <isc/timer.h>
48: #include <isc/util.h>
49:
1.1.1.2 christos 50: #include <dns/callbacks.h>
1.1 christos 51: #include <dns/db.h>
52: #include <dns/fixedname.h>
53: #include <dns/log.h>
54: #include <dns/name.h>
55: #include <dns/result.h>
56: #include <dns/view.h>
57: #include <dns/zone.h>
58:
59: #include "dnstest.h"
60:
1.1.1.6 christos 61: #define CHECK(r) \
62: do { \
63: result = (r); \
64: if (result != ISC_R_SUCCESS) { \
65: goto cleanup; \
66: } \
67: } while (0)
68:
69: isc_mem_t *dt_mctx = NULL;
1.1 christos 70: isc_log_t *lctx = NULL;
1.1.1.8 christos 71: isc_nm_t *netmgr = NULL;
1.1 christos 72: isc_taskmgr_t *taskmgr = NULL;
73: isc_task_t *maintask = NULL;
74: isc_timermgr_t *timermgr = NULL;
75: isc_socketmgr_t *socketmgr = NULL;
76: dns_zonemgr_t *zonemgr = NULL;
1.1.1.2 christos 77: bool app_running = false;
1.1 christos 78: int ncpus;
1.1.1.2 christos 79: bool debug_mem_record = true;
1.1 christos 80:
1.1.1.2 christos 81: static bool dst_active = false;
82: static bool test_running = false;
1.1 christos 83:
84: /*
85: * Logging categories: this needs to match the list in bin/named/log.c.
86: */
1.1.1.6 christos 87: static isc_logcategory_t categories[] = { { "", 0 },
88: { "client", 0 },
89: { "network", 0 },
90: { "update", 0 },
91: { "queries", 0 },
92: { "unmatched", 0 },
93: { "update-security", 0 },
94: { "query-errors", 0 },
95: { NULL, 0 } };
1.1 christos 96:
97: static void
98: cleanup_managers(void) {
1.1.1.2 christos 99: if (maintask != NULL) {
100: isc_task_shutdown(maintask);
1.1 christos 101: isc_task_destroy(&maintask);
1.1.1.2 christos 102: }
1.1.1.8 christos 103:
104: isc_managers_destroy(netmgr == NULL ? NULL : &netmgr,
105: taskmgr == NULL ? NULL : &taskmgr);
106:
1.1.1.2 christos 107: if (socketmgr != NULL) {
108: isc_socketmgr_destroy(&socketmgr);
109: }
110: if (timermgr != NULL) {
1.1 christos 111: isc_timermgr_destroy(&timermgr);
1.1.1.2 christos 112: }
113: if (app_running) {
114: isc_app_finish();
115: }
1.1 christos 116: }
117:
118: static isc_result_t
119: create_managers(void) {
120: isc_result_t result;
121: ncpus = isc_os_ncpus();
122:
1.1.1.8 christos 123: CHECK(isc_managers_create(dt_mctx, ncpus, 0, &netmgr, &taskmgr));
1.1.1.6 christos 124: CHECK(isc_timermgr_create(dt_mctx, &timermgr));
125: CHECK(isc_socketmgr_create(dt_mctx, &socketmgr));
1.1.1.8 christos 126: CHECK(isc_task_create_bound(taskmgr, 0, &maintask, 0));
1.1 christos 127: return (ISC_R_SUCCESS);
128:
1.1.1.6 christos 129: cleanup:
1.1 christos 130: cleanup_managers();
131: return (result);
132: }
133:
134: isc_result_t
1.1.1.2 christos 135: dns_test_begin(FILE *logfile, bool start_managers) {
1.1 christos 136: isc_result_t result;
137:
1.1.1.2 christos 138: INSIST(!test_running);
139: test_running = true;
140:
141: if (start_managers) {
1.1 christos 142: CHECK(isc_app_start());
1.1.1.2 christos 143: }
144: if (debug_mem_record) {
1.1 christos 145: isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
1.1.1.2 christos 146: }
147:
1.1.1.6 christos 148: INSIST(dt_mctx == NULL);
149: isc_mem_create(&dt_mctx);
1.1 christos 150:
1.1.1.2 christos 151: /* Don't check the memory leaks as they hide the assertions */
1.1.1.6 christos 152: isc_mem_setdestroycheck(dt_mctx, false);
1.1 christos 153:
1.1.1.2 christos 154: INSIST(!dst_active);
1.1.1.6 christos 155: CHECK(dst_lib_init(dt_mctx, NULL));
1.1.1.2 christos 156: dst_active = true;
1.1 christos 157:
158: if (logfile != NULL) {
159: isc_logdestination_t destination;
160: isc_logconfig_t *logconfig = NULL;
161:
1.1.1.2 christos 162: INSIST(lctx == NULL);
1.1.1.6 christos 163: isc_log_create(dt_mctx, &lctx, &logconfig);
1.1 christos 164: isc_log_registercategories(lctx, categories);
165: isc_log_setcontext(lctx);
166: dns_log_init(lctx);
167: dns_log_setcontext(lctx);
168:
169: destination.file.stream = logfile;
170: destination.file.name = NULL;
171: destination.file.versions = ISC_LOG_ROLLNEVER;
172: destination.file.maximum_size = 0;
1.1.1.6 christos 173: isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC,
174: ISC_LOG_DYNAMIC, &destination, 0);
1.1 christos 175: CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL));
176: }
177:
178: dns_result_register();
179:
1.1.1.2 christos 180: if (start_managers) {
1.1 christos 181: CHECK(create_managers());
1.1.1.2 christos 182: }
1.1 christos 183:
184: /*
1.1.1.2 christos 185: * The caller might run from another directory, so tests
1.1 christos 186: * that access test data files must first chdir to the proper
187: * location.
188: */
1.1.1.2 christos 189: if (chdir(TESTS) == -1) {
1.1 christos 190: CHECK(ISC_R_FAILURE);
1.1.1.2 christos 191: }
1.1 christos 192:
193: return (ISC_R_SUCCESS);
194:
1.1.1.6 christos 195: cleanup:
1.1 christos 196: dns_test_end();
197: return (result);
198: }
199:
200: void
201: dns_test_end(void) {
202: cleanup_managers();
203:
1.1.1.2 christos 204: dst_lib_destroy();
205: dst_active = false;
206:
207: if (lctx != NULL) {
1.1 christos 208: isc_log_destroy(&lctx);
1.1.1.2 christos 209: }
1.1 christos 210:
1.1.1.6 christos 211: if (dt_mctx != NULL) {
212: isc_mem_destroy(&dt_mctx);
1.1.1.2 christos 213: }
214:
215: test_running = false;
1.1 christos 216: }
217:
218: /*
219: * Create a view.
220: */
221: isc_result_t
222: dns_test_makeview(const char *name, dns_view_t **viewp) {
223: isc_result_t result;
224: dns_view_t *view = NULL;
225:
1.1.1.6 christos 226: CHECK(dns_view_create(dt_mctx, dns_rdataclass_in, name, &view));
1.1 christos 227: *viewp = view;
228:
229: return (ISC_R_SUCCESS);
230:
1.1.1.6 christos 231: cleanup:
232: if (view != NULL) {
1.1 christos 233: dns_view_detach(&view);
1.1.1.6 christos 234: }
1.1 christos 235: return (result);
236: }
237:
238: isc_result_t
239: dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view,
1.1.1.6 christos 240: bool createview) {
1.1 christos 241: dns_fixedname_t fixed_origin;
242: dns_zone_t *zone = NULL;
243: isc_result_t result;
244: dns_name_t *origin;
245:
246: REQUIRE(view == NULL || !createview);
247:
248: /*
249: * Create the zone structure.
250: */
1.1.1.6 christos 251: result = dns_zone_create(&zone, dt_mctx);
1.1 christos 252: if (result != ISC_R_SUCCESS) {
253: return (result);
254: }
255:
256: /*
257: * Set zone type and origin.
258: */
1.1.1.9 ! christos 259: dns_zone_settype(zone, dns_zone_primary);
1.1 christos 260: origin = dns_fixedname_initname(&fixed_origin);
261: result = dns_name_fromstring(origin, name, 0, NULL);
262: if (result != ISC_R_SUCCESS) {
263: goto detach_zone;
264: }
265: result = dns_zone_setorigin(zone, origin);
266: if (result != ISC_R_SUCCESS) {
267: goto detach_zone;
268: }
269:
270: /*
271: * If requested, create a view.
272: */
273: if (createview) {
274: result = dns_test_makeview("view", &view);
275: if (result != ISC_R_SUCCESS) {
276: goto detach_zone;
277: }
278: }
279:
280: /*
281: * If a view was passed as an argument or created above, attach the
282: * created zone to it. Otherwise, set the zone's class to IN.
283: */
284: if (view != NULL) {
285: dns_zone_setview(zone, view);
286: dns_zone_setclass(zone, view->rdclass);
287: dns_view_addzone(view, zone);
288: } else {
289: dns_zone_setclass(zone, dns_rdataclass_in);
290: }
291:
292: *zonep = zone;
293:
294: return (ISC_R_SUCCESS);
295:
1.1.1.6 christos 296: detach_zone:
1.1 christos 297: dns_zone_detach(&zone);
298:
299: return (result);
300: }
301:
302: isc_result_t
303: dns_test_setupzonemgr(void) {
304: isc_result_t result;
305: REQUIRE(zonemgr == NULL);
306:
1.1.1.6 christos 307: result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr,
1.1 christos 308: &zonemgr);
309: return (result);
310: }
311:
312: isc_result_t
313: dns_test_managezone(dns_zone_t *zone) {
314: isc_result_t result;
315: REQUIRE(zonemgr != NULL);
316:
317: result = dns_zonemgr_setsize(zonemgr, 1);
1.1.1.6 christos 318: if (result != ISC_R_SUCCESS) {
1.1 christos 319: return (result);
1.1.1.6 christos 320: }
1.1 christos 321:
322: result = dns_zonemgr_managezone(zonemgr, zone);
323: return (result);
324: }
325:
326: void
327: dns_test_releasezone(dns_zone_t *zone) {
328: REQUIRE(zonemgr != NULL);
329: dns_zonemgr_releasezone(zonemgr, zone);
330: }
331:
332: void
333: dns_test_closezonemgr(void) {
334: REQUIRE(zonemgr != NULL);
335:
336: dns_zonemgr_shutdown(zonemgr);
337: dns_zonemgr_detach(&zonemgr);
338: }
339:
340: /*
341: * Sleep for 'usec' microseconds.
342: */
343: void
1.1.1.2 christos 344: dns_test_nap(uint32_t usec) {
1.1 christos 345: struct timespec ts;
346:
347: ts.tv_sec = usec / 1000000;
348: ts.tv_nsec = (usec % 1000000) * 1000;
349: nanosleep(&ts, NULL);
350: }
351:
352: isc_result_t
353: dns_test_loaddb(dns_db_t **db, dns_dbtype_t dbtype, const char *origin,
1.1.1.6 christos 354: const char *testfile) {
355: isc_result_t result;
356: dns_fixedname_t fixed;
357: dns_name_t *name;
1.1 christos 358:
359: name = dns_fixedname_initname(&fixed);
360:
361: result = dns_name_fromstring(name, origin, 0, NULL);
1.1.1.6 christos 362: if (result != ISC_R_SUCCESS) {
363: return (result);
364: }
1.1 christos 365:
1.1.1.6 christos 366: result = dns_db_create(dt_mctx, "rbt", name, dbtype, dns_rdataclass_in,
1.1 christos 367: 0, NULL, db);
1.1.1.6 christos 368: if (result != ISC_R_SUCCESS) {
1.1 christos 369: return (result);
1.1.1.6 christos 370: }
1.1 christos 371:
1.1.1.2 christos 372: result = dns_db_load(*db, testfile, dns_masterformat_text, 0);
1.1 christos 373: return (result);
374: }
375:
376: static int
377: fromhex(char c) {
1.1.1.6 christos 378: if (c >= '0' && c <= '9') {
1.1 christos 379: return (c - '0');
1.1.1.6 christos 380: } else if (c >= 'a' && c <= 'f') {
1.1 christos 381: return (c - 'a' + 10);
1.1.1.6 christos 382: } else if (c >= 'A' && c <= 'F') {
1.1 christos 383: return (c - 'A' + 10);
1.1.1.6 christos 384: }
1.1 christos 385:
386: printf("bad input format: %02x\n", c);
387: exit(3);
388: }
389:
390: /*
391: * Format contents of given memory region as a hex string, using the buffer
392: * of length 'buflen' pointed to by 'buf'. 'buflen' must be at least three
393: * times 'len'. Always returns 'buf'.
394: */
395: char *
1.1.1.6 christos 396: dns_test_tohex(const unsigned char *data, size_t len, char *buf,
397: size_t buflen) {
398: isc_constregion_t source = { .base = data, .length = len };
1.1 christos 399: isc_buffer_t target;
400: isc_result_t result;
401:
402: memset(buf, 0, buflen);
403: isc_buffer_init(&target, buf, buflen);
404: result = isc_hex_totext((isc_region_t *)&source, 1, " ", &target);
1.1.1.2 christos 405: assert_int_equal(result, ISC_R_SUCCESS);
1.1 christos 406:
407: return (buf);
408: }
409:
410: isc_result_t
1.1.1.6 christos 411: dns_test_getdata(const char *file, unsigned char *buf, size_t bufsiz,
412: size_t *sizep) {
1.1 christos 413: isc_result_t result;
414: unsigned char *bp;
415: char *rp, *wp;
416: char s[BUFSIZ];
417: size_t len, i;
418: FILE *f = NULL;
419: int n;
420:
421: result = isc_stdio_open(file, "r", &f);
1.1.1.6 christos 422: if (result != ISC_R_SUCCESS) {
1.1 christos 423: return (result);
1.1.1.6 christos 424: }
1.1 christos 425:
426: bp = buf;
427: while (fgets(s, sizeof(s), f) != NULL) {
428: rp = s;
429: wp = s;
430: len = 0;
431: while (*rp != '\0') {
1.1.1.6 christos 432: if (*rp == '#') {
1.1 christos 433: break;
1.1.1.6 christos 434: }
435: if (*rp != ' ' && *rp != '\t' && *rp != '\r' &&
436: *rp != '\n') {
1.1 christos 437: *wp++ = *rp;
438: len++;
439: }
440: rp++;
441: }
1.1.1.6 christos 442: if (len == 0U) {
1.1 christos 443: continue;
1.1.1.6 christos 444: }
445: if (len % 2 != 0U) {
1.1 christos 446: CHECK(ISC_R_UNEXPECTEDEND);
1.1.1.6 christos 447: }
448: if (len > bufsiz * 2) {
1.1 christos 449: CHECK(ISC_R_NOSPACE);
1.1.1.6 christos 450: }
1.1 christos 451: rp = s;
452: for (i = 0; i < len; i += 2) {
453: n = fromhex(*rp++);
454: n *= 16;
455: n += fromhex(*rp++);
456: *bp++ = n;
457: }
458: }
459:
460: *sizep = bp - buf;
461:
462: result = ISC_R_SUCCESS;
463:
1.1.1.6 christos 464: cleanup:
1.1 christos 465: isc_stdio_close(f);
466: return (result);
467: }
468:
1.1.1.2 christos 469: static void
470: nullmsg(dns_rdatacallbacks_t *cb, const char *fmt, ...) {
471: UNUSED(cb);
472: UNUSED(fmt);
473: }
474:
1.1 christos 475: isc_result_t
476: dns_test_rdatafromstring(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
477: dns_rdatatype_t rdtype, unsigned char *dst,
1.1.1.6 christos 478: size_t dstlen, const char *src, bool warnings) {
1.1.1.2 christos 479: dns_rdatacallbacks_t callbacks;
1.1 christos 480: isc_buffer_t source, target;
481: isc_lex_t *lex = NULL;
1.1.1.4 christos 482: isc_lexspecials_t specials = { 0 };
1.1 christos 483: isc_result_t result;
484: size_t length;
485:
486: REQUIRE(rdata != NULL);
487: REQUIRE(DNS_RDATA_INITIALIZED(rdata));
488: REQUIRE(dst != NULL);
489: REQUIRE(src != NULL);
490:
491: /*
492: * Set up source to hold the input string.
493: */
494: length = strlen(src);
495: isc_buffer_constinit(&source, src, length);
496: isc_buffer_add(&source, length);
497:
498: /*
499: * Create a lexer as one is required by dns_rdata_fromtext().
500: */
1.1.1.6 christos 501: result = isc_lex_create(dt_mctx, 64, &lex);
1.1 christos 502: if (result != ISC_R_SUCCESS) {
503: return (result);
504: }
505:
506: /*
1.1.1.4 christos 507: * Set characters which will be treated as valid multi-line RDATA
508: * delimiters while reading the source string. These should match
509: * specials from lib/dns/master.c.
510: */
511: specials[0] = 1;
512: specials['('] = 1;
513: specials[')'] = 1;
514: specials['"'] = 1;
515: isc_lex_setspecials(lex, specials);
516:
517: /*
518: * Expect DNS masterfile comments.
519: */
520: isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
521:
522: /*
1.1 christos 523: * Point lexer at source.
524: */
525: result = isc_lex_openbuffer(lex, &source);
526: if (result != ISC_R_SUCCESS) {
527: goto destroy_lexer;
528: }
529:
530: /*
531: * Set up target for storing uncompressed wire form of provided RDATA.
532: */
533: isc_buffer_init(&target, dst, dstlen);
534:
535: /*
1.1.1.2 christos 536: * Set up callbacks so warnings and errors are not printed.
537: */
538: if (!warnings) {
539: dns_rdatacallbacks_init(&callbacks);
540: callbacks.warn = callbacks.error = nullmsg;
541: }
542:
543: /*
1.1 christos 544: * Parse input string, determining result.
545: */
546: result = dns_rdata_fromtext(rdata, rdclass, rdtype, lex, dns_rootname,
1.1.1.6 christos 547: 0, dt_mctx, &target, &callbacks);
1.1 christos 548:
1.1.1.6 christos 549: destroy_lexer:
1.1 christos 550: isc_lex_destroy(&lex);
551:
552: return (result);
553: }
554:
555: void
556: dns_test_namefromstring(const char *namestr, dns_fixedname_t *fname) {
557: size_t length;
558: isc_buffer_t *b = NULL;
559: isc_result_t result;
560: dns_name_t *name;
561:
562: length = strlen(namestr);
563:
1.1.1.2 christos 564: name = dns_fixedname_initname(fname);
565:
1.1.1.6 christos 566: isc_buffer_allocate(dt_mctx, &b, length);
1.1 christos 567:
1.1.1.6 christos 568: isc_buffer_putmem(b, (const unsigned char *)namestr, length);
1.1 christos 569: result = dns_name_fromtext(name, b, dns_rootname, 0, NULL);
1.1.1.2 christos 570: assert_int_equal(result, ISC_R_SUCCESS);
1.1 christos 571:
572: isc_buffer_free(&b);
573: }
574:
575: isc_result_t
1.1.1.2 christos 576: dns_test_difffromchanges(dns_diff_t *diff, const zonechange_t *changes,
1.1.1.6 christos 577: bool warnings) {
1.1 christos 578: isc_result_t result = ISC_R_SUCCESS;
579: unsigned char rdata_buf[1024];
580: dns_difftuple_t *tuple = NULL;
581: isc_consttextregion_t region;
582: dns_rdatatype_t rdatatype;
583: dns_fixedname_t fixedname;
584: dns_rdata_t rdata;
585: dns_name_t *name;
586: size_t i;
587:
588: REQUIRE(diff != NULL);
589: REQUIRE(changes != NULL);
590:
1.1.1.6 christos 591: dns_diff_init(dt_mctx, diff);
1.1 christos 592:
593: for (i = 0; changes[i].owner != NULL; i++) {
594: /*
595: * Parse owner name.
596: */
597: name = dns_fixedname_initname(&fixedname);
1.1.1.6 christos 598: result = dns_name_fromstring(name, changes[i].owner, 0,
599: dt_mctx);
1.1 christos 600: if (result != ISC_R_SUCCESS) {
601: break;
602: }
603:
604: /*
605: * Parse RDATA type.
606: */
607: region.base = changes[i].type;
608: region.length = strlen(changes[i].type);
609: result = dns_rdatatype_fromtext(&rdatatype,
610: (isc_textregion_t *)®ion);
611: if (result != ISC_R_SUCCESS) {
612: break;
613: }
614:
615: /*
616: * Parse RDATA.
617: */
618: dns_rdata_init(&rdata);
1.1.1.6 christos 619: result = dns_test_rdatafromstring(
620: &rdata, dns_rdataclass_in, rdatatype, rdata_buf,
621: sizeof(rdata_buf), changes[i].rdata, warnings);
1.1 christos 622: if (result != ISC_R_SUCCESS) {
623: break;
624: }
625:
626: /*
627: * Create a diff tuple for the parsed change and append it to
628: * the diff.
629: */
1.1.1.6 christos 630: result = dns_difftuple_create(dt_mctx, changes[i].op, name,
1.1 christos 631: changes[i].ttl, &rdata, &tuple);
632: if (result != ISC_R_SUCCESS) {
633: break;
634: }
635: dns_diff_append(diff, &tuple);
636: }
637:
638: if (result != ISC_R_SUCCESS) {
639: dns_diff_clear(diff);
640: }
641:
642: return (result);
643: }
1.1.1.2 christos 644: #endif /* HAVE_CMOCKA */
CVSweb <webmaster@jp.NetBSD.org>