check-tool.c revision 1.4
1/*	$NetBSD: check-tool.c,v 1.4 2019/11/27 05:48:39 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
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 http://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
15/*! \file */
16
17#include <config.h>
18
19#include <stdbool.h>
20#include <stdio.h>
21#include <inttypes.h>
22
23#ifdef _WIN32
24#include <Winsock2.h>
25#endif
26
27#include "check-tool.h"
28#include <isc/buffer.h>
29#include <isc/log.h>
30#include <isc/mem.h>
31#include <isc/netdb.h>
32#include <isc/net.h>
33#include <isc/print.h>
34#include <isc/region.h>
35#include <isc/stdio.h>
36#include <isc/string.h>
37#include <isc/symtab.h>
38#include <isc/types.h>
39#include <isc/util.h>
40
41#include <dns/db.h>
42#include <dns/dbiterator.h>
43#include <dns/fixedname.h>
44#include <dns/log.h>
45#include <dns/name.h>
46#include <dns/rdata.h>
47#include <dns/rdataclass.h>
48#include <dns/rdataset.h>
49#include <dns/rdatasetiter.h>
50#include <dns/rdatatype.h>
51#include <dns/result.h>
52#include <dns/types.h>
53#include <dns/zone.h>
54
55#include <isccfg/log.h>
56
57#include <ns/log.h>
58
59#ifndef CHECK_SIBLING
60#define CHECK_SIBLING 1
61#endif
62
63#ifndef CHECK_LOCAL
64#define CHECK_LOCAL 1
65#endif
66
67#define CHECK(r) \
68	do { \
69		result = (r); \
70		if (result != ISC_R_SUCCESS) \
71			goto cleanup; \
72	} while (/*CONSTCOND*/0)
73
74#define ERR_IS_CNAME 1
75#define ERR_NO_ADDRESSES 2
76#define ERR_LOOKUP_FAILURE 3
77#define ERR_EXTRA_A 4
78#define ERR_EXTRA_AAAA 5
79#define ERR_MISSING_GLUE 5
80#define ERR_IS_MXCNAME 6
81#define ERR_IS_SRVCNAME 7
82
83static const char *dbtype[] = { "rbt" };
84
85int debug = 0;
86const char *journal = NULL;
87bool nomerge = true;
88#if CHECK_LOCAL
89bool docheckmx = true;
90bool dochecksrv = true;
91bool docheckns = true;
92#else
93bool docheckmx = false;
94bool dochecksrv = false;
95bool docheckns = false;
96#endif
97dns_zoneopt_t zone_options = DNS_ZONEOPT_CHECKNS |
98			     DNS_ZONEOPT_CHECKMX |
99			     DNS_ZONEOPT_MANYERRORS |
100			     DNS_ZONEOPT_CHECKNAMES |
101			     DNS_ZONEOPT_CHECKINTEGRITY |
102#if CHECK_SIBLING
103			     DNS_ZONEOPT_CHECKSIBLING |
104#endif
105			     DNS_ZONEOPT_CHECKWILDCARD |
106			     DNS_ZONEOPT_WARNMXCNAME |
107			     DNS_ZONEOPT_WARNSRVCNAME;
108
109/*
110 * This needs to match the list in bin/named/log.c.
111 */
112static isc_logcategory_t categories[] = {
113	{ "",		     0 },
114	{ "unmatched", 	     0 },
115	{ NULL,		     0 }
116};
117
118static isc_symtab_t *symtab = NULL;
119static isc_mem_t *sym_mctx;
120
121static void
122freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
123	UNUSED(type);
124	UNUSED(value);
125	isc_mem_free(userarg, key);
126}
127
128static void
129add(char *key, int value) {
130	isc_result_t result;
131	isc_symvalue_t symvalue;
132
133	if (sym_mctx == NULL) {
134		result = isc_mem_create(0, 0, &sym_mctx);
135		if (result != ISC_R_SUCCESS)
136			return;
137	}
138
139	if (symtab == NULL) {
140		result = isc_symtab_create(sym_mctx, 100, freekey, sym_mctx,
141					   false, &symtab);
142		if (result != ISC_R_SUCCESS)
143			return;
144	}
145
146	key = isc_mem_strdup(sym_mctx, key);
147	if (key == NULL)
148		return;
149
150	symvalue.as_pointer = NULL;
151	result = isc_symtab_define(symtab, key, value, symvalue,
152				   isc_symexists_reject);
153	if (result != ISC_R_SUCCESS)
154		isc_mem_free(sym_mctx, key);
155}
156
157static bool
158logged(char *key, int value) {
159	isc_result_t result;
160
161	if (symtab == NULL)
162		return (false);
163
164	result = isc_symtab_lookup(symtab, key, value, NULL);
165	if (result == ISC_R_SUCCESS)
166		return (true);
167	return (false);
168}
169
170static bool
171checkns(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner,
172	dns_rdataset_t *a, dns_rdataset_t *aaaa)
173{
174	dns_rdataset_t *rdataset;
175	dns_rdata_t rdata = DNS_RDATA_INIT;
176	struct addrinfo hints, *ai, *cur;
177	char namebuf[DNS_NAME_FORMATSIZE + 1];
178	char ownerbuf[DNS_NAME_FORMATSIZE];
179	char addrbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
180	bool answer = true;
181	bool match;
182	const char *type;
183	void *ptr = NULL;
184	int result;
185
186	REQUIRE(a == NULL || !dns_rdataset_isassociated(a) ||
187		a->type == dns_rdatatype_a);
188	REQUIRE(aaaa == NULL || !dns_rdataset_isassociated(aaaa) ||
189		aaaa->type == dns_rdatatype_aaaa);
190
191	if (a == NULL || aaaa == NULL)
192		return (answer);
193
194	memset(&hints, 0, sizeof(hints));
195	hints.ai_flags = AI_CANONNAME;
196	hints.ai_family = PF_UNSPEC;
197	hints.ai_socktype = SOCK_STREAM;
198	hints.ai_protocol = IPPROTO_TCP;
199
200	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
201	/*
202	 * Turn off search.
203	 */
204	if (dns_name_countlabels(name) > 1U) {
205		strlcat(namebuf, ".", sizeof(namebuf));
206	}
207	dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
208
209	result = getaddrinfo(namebuf, NULL, &hints, &ai);
210	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
211	switch (result) {
212	case 0:
213		/*
214		 * Work around broken getaddrinfo() implementations that
215		 * fail to set ai_canonname on first entry.
216		 */
217		cur = ai;
218		while (cur != NULL && cur->ai_canonname == NULL &&
219		       cur->ai_next != NULL)
220			cur = cur->ai_next;
221		if (cur != NULL && cur->ai_canonname != NULL &&
222		    strcasecmp(cur->ai_canonname, namebuf) != 0 &&
223		    !logged(namebuf, ERR_IS_CNAME)) {
224			dns_zone_log(zone, ISC_LOG_ERROR,
225				     "%s/NS '%s' (out of zone) "
226				     "is a CNAME '%s' (illegal)",
227				     ownerbuf, namebuf,
228				     cur->ai_canonname);
229			/* XXX950 make fatal for 9.5.0 */
230			/* answer = false; */
231			add(namebuf, ERR_IS_CNAME);
232		}
233		break;
234	case EAI_NONAME:
235#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
236	case EAI_NODATA:
237#endif
238		if (!logged(namebuf, ERR_NO_ADDRESSES)) {
239			dns_zone_log(zone, ISC_LOG_ERROR,
240				     "%s/NS '%s' (out of zone) "
241				     "has no addresses records (A or AAAA)",
242				     ownerbuf, namebuf);
243			add(namebuf, ERR_NO_ADDRESSES);
244		}
245		/* XXX950 make fatal for 9.5.0 */
246		return (true);
247
248	default:
249		if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
250			dns_zone_log(zone, ISC_LOG_WARNING,
251				     "getaddrinfo(%s) failed: %s",
252				     namebuf, gai_strerror(result));
253			add(namebuf, ERR_LOOKUP_FAILURE);
254		}
255		return (true);
256	}
257
258	/*
259	 * Check that all glue records really exist.
260	 */
261	if (!dns_rdataset_isassociated(a))
262		goto checkaaaa;
263	result = dns_rdataset_first(a);
264	while (result == ISC_R_SUCCESS) {
265		dns_rdataset_current(a, &rdata);
266		match = false;
267		for (cur = ai; cur != NULL; cur = cur->ai_next) {
268			if (cur->ai_family != AF_INET)
269				continue;
270			ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
271			if (memcmp(ptr, rdata.data, rdata.length) == 0) {
272				match = true;
273				break;
274			}
275		}
276		if (!match && !logged(namebuf, ERR_EXTRA_A)) {
277			dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
278				     "extra GLUE A record (%s)",
279				     ownerbuf, namebuf,
280				     inet_ntop(AF_INET, rdata.data,
281					       addrbuf, sizeof(addrbuf)));
282			add(namebuf, ERR_EXTRA_A);
283			/* XXX950 make fatal for 9.5.0 */
284			/* answer = false; */
285		}
286		dns_rdata_reset(&rdata);
287		result = dns_rdataset_next(a);
288	}
289
290 checkaaaa:
291	if (!dns_rdataset_isassociated(aaaa))
292		goto checkmissing;
293	result = dns_rdataset_first(aaaa);
294	while (result == ISC_R_SUCCESS) {
295		dns_rdataset_current(aaaa, &rdata);
296		match = false;
297		for (cur = ai; cur != NULL; cur = cur->ai_next) {
298			if (cur->ai_family != AF_INET6)
299				continue;
300			ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
301			if (memcmp(ptr, rdata.data, rdata.length) == 0) {
302				match = true;
303				break;
304			}
305		}
306		if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) {
307			dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
308				     "extra GLUE AAAA record (%s)",
309				     ownerbuf, namebuf,
310				     inet_ntop(AF_INET6, rdata.data,
311					       addrbuf, sizeof(addrbuf)));
312			add(namebuf, ERR_EXTRA_AAAA);
313			/* XXX950 make fatal for 9.5.0. */
314			/* answer = false; */
315		}
316		dns_rdata_reset(&rdata);
317		result = dns_rdataset_next(aaaa);
318	}
319
320 checkmissing:
321	/*
322	 * Check that all addresses appear in the glue.
323	 */
324	if (!logged(namebuf, ERR_MISSING_GLUE)) {
325		bool missing_glue = false;
326		for (cur = ai; cur != NULL; cur = cur->ai_next) {
327			switch (cur->ai_family) {
328			case AF_INET:
329				rdataset = a;
330				ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
331				type = "A";
332				break;
333			case AF_INET6:
334				rdataset = aaaa;
335				ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
336				type = "AAAA";
337				break;
338			default:
339				 continue;
340			}
341			match = false;
342			if (dns_rdataset_isassociated(rdataset))
343				result = dns_rdataset_first(rdataset);
344			else
345				result = ISC_R_FAILURE;
346			while (result == ISC_R_SUCCESS && !match) {
347				dns_rdataset_current(rdataset, &rdata);
348				if (memcmp(ptr, rdata.data, rdata.length) == 0)
349					match = true;
350				dns_rdata_reset(&rdata);
351				result = dns_rdataset_next(rdataset);
352			}
353			if (!match) {
354				dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
355					     "missing GLUE %s record (%s)",
356					     ownerbuf, namebuf, type,
357					     inet_ntop(cur->ai_family, ptr,
358						       addrbuf, sizeof(addrbuf)));
359				/* XXX950 make fatal for 9.5.0. */
360				/* answer = false; */
361				missing_glue = true;
362			}
363		}
364		if (missing_glue)
365			add(namebuf, ERR_MISSING_GLUE);
366	}
367	freeaddrinfo(ai);
368	return (answer);
369}
370
371static bool
372checkmx(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
373	struct addrinfo hints, *ai, *cur;
374	char namebuf[DNS_NAME_FORMATSIZE + 1];
375	char ownerbuf[DNS_NAME_FORMATSIZE];
376	int result;
377	int level = ISC_LOG_ERROR;
378	bool answer = true;
379
380	memset(&hints, 0, sizeof(hints));
381	hints.ai_flags = AI_CANONNAME;
382	hints.ai_family = PF_UNSPEC;
383	hints.ai_socktype = SOCK_STREAM;
384	hints.ai_protocol = IPPROTO_TCP;
385
386	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
387	/*
388	 * Turn off search.
389	 */
390	if (dns_name_countlabels(name) > 1U) {
391		strlcat(namebuf, ".", sizeof(namebuf));
392	}
393	dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
394
395	result = getaddrinfo(namebuf, NULL, &hints, &ai);
396	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
397	switch (result) {
398	case 0:
399		/*
400		 * Work around broken getaddrinfo() implementations that
401		 * fail to set ai_canonname on first entry.
402		 */
403		cur = ai;
404		while (cur != NULL && cur->ai_canonname == NULL &&
405		       cur->ai_next != NULL)
406			cur = cur->ai_next;
407		if (cur != NULL && cur->ai_canonname != NULL &&
408		    strcasecmp(cur->ai_canonname, namebuf) != 0) {
409			if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0)
410				level = ISC_LOG_WARNING;
411			if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) {
412				if (!logged(namebuf, ERR_IS_MXCNAME)) {
413					dns_zone_log(zone, level,
414						     "%s/MX '%s' (out of zone)"
415						     " is a CNAME '%s' "
416						     "(illegal)",
417						     ownerbuf, namebuf,
418						     cur->ai_canonname);
419					add(namebuf, ERR_IS_MXCNAME);
420				}
421				if (level == ISC_LOG_ERROR)
422					answer = false;
423			}
424		}
425		freeaddrinfo(ai);
426		return (answer);
427
428	case EAI_NONAME:
429#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
430	case EAI_NODATA:
431#endif
432		if (!logged(namebuf, ERR_NO_ADDRESSES)) {
433			dns_zone_log(zone, ISC_LOG_ERROR,
434				     "%s/MX '%s' (out of zone) "
435				     "has no addresses records (A or AAAA)",
436				     ownerbuf, namebuf);
437			add(namebuf, ERR_NO_ADDRESSES);
438		}
439		/* XXX950 make fatal for 9.5.0. */
440		return (true);
441
442	default:
443		if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
444			dns_zone_log(zone, ISC_LOG_WARNING,
445			     "getaddrinfo(%s) failed: %s",
446			     namebuf, gai_strerror(result));
447			add(namebuf, ERR_LOOKUP_FAILURE);
448		}
449		return (true);
450	}
451}
452
453static bool
454checksrv(dns_zone_t *zone, const dns_name_t *name, const dns_name_t *owner) {
455	struct addrinfo hints, *ai, *cur;
456	char namebuf[DNS_NAME_FORMATSIZE + 1];
457	char ownerbuf[DNS_NAME_FORMATSIZE];
458	int result;
459	int level = ISC_LOG_ERROR;
460	bool answer = true;
461
462	memset(&hints, 0, sizeof(hints));
463	hints.ai_flags = AI_CANONNAME;
464	hints.ai_family = PF_UNSPEC;
465	hints.ai_socktype = SOCK_STREAM;
466	hints.ai_protocol = IPPROTO_TCP;
467
468	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
469	/*
470	 * Turn off search.
471	 */
472	if (dns_name_countlabels(name) > 1U) {
473		strlcat(namebuf, ".", sizeof(namebuf));
474	}
475	dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
476
477	result = getaddrinfo(namebuf, NULL, &hints, &ai);
478	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
479	switch (result) {
480	case 0:
481		/*
482		 * Work around broken getaddrinfo() implementations that
483		 * fail to set ai_canonname on first entry.
484		 */
485		cur = ai;
486		while (cur != NULL && cur->ai_canonname == NULL &&
487		       cur->ai_next != NULL)
488			cur = cur->ai_next;
489		if (cur != NULL && cur->ai_canonname != NULL &&
490		    strcasecmp(cur->ai_canonname, namebuf) != 0) {
491			if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0)
492				level = ISC_LOG_WARNING;
493			if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) {
494				if (!logged(namebuf, ERR_IS_SRVCNAME)) {
495					dns_zone_log(zone, level, "%s/SRV '%s'"
496						     " (out of zone) is a "
497						     "CNAME '%s' (illegal)",
498						     ownerbuf, namebuf,
499						     cur->ai_canonname);
500					add(namebuf, ERR_IS_SRVCNAME);
501				}
502				if (level == ISC_LOG_ERROR)
503					answer = false;
504			}
505		}
506		freeaddrinfo(ai);
507		return (answer);
508
509	case EAI_NONAME:
510#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
511	case EAI_NODATA:
512#endif
513		if (!logged(namebuf, ERR_NO_ADDRESSES)) {
514			dns_zone_log(zone, ISC_LOG_ERROR,
515				     "%s/SRV '%s' (out of zone) "
516				     "has no addresses records (A or AAAA)",
517				     ownerbuf, namebuf);
518			add(namebuf, ERR_NO_ADDRESSES);
519		}
520		/* XXX950 make fatal for 9.5.0. */
521		return (true);
522
523	default:
524		if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
525			dns_zone_log(zone, ISC_LOG_WARNING,
526				     "getaddrinfo(%s) failed: %s",
527				     namebuf, gai_strerror(result));
528			add(namebuf, ERR_LOOKUP_FAILURE);
529		}
530		return (true);
531	}
532}
533
534isc_result_t
535setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) {
536	isc_logdestination_t destination;
537	isc_logconfig_t *logconfig = NULL;
538	isc_log_t *log = NULL;
539
540	RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS);
541	isc_log_registercategories(log, categories);
542	isc_log_setcontext(log);
543	dns_log_init(log);
544	dns_log_setcontext(log);
545	cfg_log_init(log);
546	ns_log_init(log);
547
548	destination.file.stream = errout;
549	destination.file.name = NULL;
550	destination.file.versions = ISC_LOG_ROLLNEVER;
551	destination.file.maximum_size = 0;
552	RUNTIME_CHECK(isc_log_createchannel(logconfig, "stderr",
553				       ISC_LOG_TOFILEDESC,
554				       ISC_LOG_DYNAMIC,
555				       &destination, 0) == ISC_R_SUCCESS);
556	RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr",
557					 NULL, NULL) == ISC_R_SUCCESS);
558
559	*logp = log;
560	return (ISC_R_SUCCESS);
561}
562
563/*% scan the zone for oversize TTLs */
564static isc_result_t
565check_ttls(dns_zone_t *zone, dns_ttl_t maxttl) {
566	isc_result_t result;
567	dns_db_t *db = NULL;
568	dns_dbversion_t *version = NULL;
569	dns_dbnode_t *node = NULL;
570	dns_dbiterator_t *dbiter = NULL;
571	dns_rdatasetiter_t *rdsiter = NULL;
572	dns_rdataset_t rdataset;
573	dns_fixedname_t fname;
574	dns_name_t *name;
575	name = dns_fixedname_initname(&fname);
576	dns_rdataset_init(&rdataset);
577
578	CHECK(dns_zone_getdb(zone, &db));
579	INSIST(db != NULL);
580
581	CHECK(dns_db_newversion(db, &version));
582	CHECK(dns_db_createiterator(db, 0, &dbiter));
583
584	for (result = dns_dbiterator_first(dbiter);
585	     result == ISC_R_SUCCESS;
586	     result = dns_dbiterator_next(dbiter)) {
587		result = dns_dbiterator_current(dbiter, &node, name);
588		if (result == DNS_R_NEWORIGIN)
589			result = ISC_R_SUCCESS;
590		CHECK(result);
591
592		CHECK(dns_db_allrdatasets(db, node, version, 0, &rdsiter));
593		for (result = dns_rdatasetiter_first(rdsiter);
594		     result == ISC_R_SUCCESS;
595		     result = dns_rdatasetiter_next(rdsiter)) {
596			dns_rdatasetiter_current(rdsiter, &rdataset);
597			if (rdataset.ttl > maxttl) {
598				char nbuf[DNS_NAME_FORMATSIZE];
599				char tbuf[255];
600				isc_buffer_t b;
601				isc_region_t r;
602
603				dns_name_format(name, nbuf, sizeof(nbuf));
604				isc_buffer_init(&b, tbuf, sizeof(tbuf) - 1);
605				CHECK(dns_rdatatype_totext(rdataset.type, &b));
606				isc_buffer_usedregion(&b, &r);
607				r.base[r.length] = 0;
608
609				dns_zone_log(zone, ISC_LOG_ERROR,
610					     "%s/%s TTL %d exceeds "
611					     "maximum TTL %d",
612					     nbuf, tbuf, rdataset.ttl, maxttl);
613				dns_rdataset_disassociate(&rdataset);
614				CHECK(ISC_R_RANGE);
615			}
616			dns_rdataset_disassociate(&rdataset);
617		}
618		if (result == ISC_R_NOMORE)
619			result = ISC_R_SUCCESS;
620		CHECK(result);
621
622		dns_rdatasetiter_destroy(&rdsiter);
623		dns_db_detachnode(db, &node);
624	}
625
626	if (result == ISC_R_NOMORE)
627		result = ISC_R_SUCCESS;
628
629 cleanup:
630	if (node != NULL)
631		dns_db_detachnode(db, &node);
632	if (rdsiter != NULL)
633		dns_rdatasetiter_destroy(&rdsiter);
634	if (dbiter != NULL)
635		dns_dbiterator_destroy(&dbiter);
636	if (version != NULL)
637		dns_db_closeversion(db, &version, false);
638	if (db != NULL)
639		dns_db_detach(&db);
640
641	return (result);
642}
643
644/*% load the zone */
645isc_result_t
646load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
647	  dns_masterformat_t fileformat, const char *classname,
648	  dns_ttl_t maxttl, dns_zone_t **zonep)
649{
650	isc_result_t result;
651	dns_rdataclass_t rdclass;
652	isc_textregion_t region;
653	isc_buffer_t buffer;
654	dns_fixedname_t fixorigin;
655	dns_name_t *origin;
656	dns_zone_t *zone = NULL;
657
658	REQUIRE(zonep == NULL || *zonep == NULL);
659
660	if (debug)
661		fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
662			zonename, filename, classname);
663
664	CHECK(dns_zone_create(&zone, mctx));
665
666	dns_zone_settype(zone, dns_zone_master);
667
668	isc_buffer_constinit(&buffer, zonename, strlen(zonename));
669	isc_buffer_add(&buffer, strlen(zonename));
670	origin = dns_fixedname_initname(&fixorigin);
671	CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL));
672	CHECK(dns_zone_setorigin(zone, origin));
673	CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype));
674	CHECK(dns_zone_setfile(zone, filename, fileformat,
675			       &dns_master_style_default));
676	if (journal != NULL)
677		CHECK(dns_zone_setjournal(zone, journal));
678
679	DE_CONST(classname, region.base);
680	region.length = strlen(classname);
681	CHECK(dns_rdataclass_fromtext(&rdclass, &region));
682
683	dns_zone_setclass(zone, rdclass);
684	dns_zone_setoption(zone, zone_options, true);
685	dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);
686
687	dns_zone_setmaxttl(zone, maxttl);
688
689	if (docheckmx)
690		dns_zone_setcheckmx(zone, checkmx);
691	if (docheckns)
692		dns_zone_setcheckns(zone, checkns);
693	if (dochecksrv)
694		dns_zone_setchecksrv(zone, checksrv);
695
696	CHECK(dns_zone_load(zone, false));
697
698	/*
699	 * When loading map files we can't catch oversize TTLs during
700	 * load, so we check for them here.
701	 */
702	if (fileformat == dns_masterformat_map && maxttl != 0) {
703		CHECK(check_ttls(zone, maxttl));
704	}
705
706	if (zonep != NULL) {
707		*zonep = zone;
708		zone = NULL;
709	}
710
711 cleanup:
712	if (zone != NULL)
713		dns_zone_detach(&zone);
714	return (result);
715}
716
717/*% dump the zone */
718isc_result_t
719dump_zone(const char *zonename, dns_zone_t *zone, const char *filename,
720	  dns_masterformat_t fileformat, const dns_master_style_t *style,
721	  const uint32_t rawversion)
722{
723	isc_result_t result;
724	FILE *output = stdout;
725	const char *flags;
726
727	flags = (fileformat == dns_masterformat_text) ? "w" : "wb";
728
729	if (debug) {
730		if (filename != NULL && strcmp(filename, "-") != 0)
731			fprintf(stderr, "dumping \"%s\" to \"%s\"\n",
732				zonename, filename);
733		else
734			fprintf(stderr, "dumping \"%s\"\n", zonename);
735	}
736
737	if (filename != NULL && strcmp(filename, "-") != 0) {
738		result = isc_stdio_open(filename, flags, &output);
739
740		if (result != ISC_R_SUCCESS) {
741			fprintf(stderr, "could not open output "
742				"file \"%s\" for writing\n", filename);
743			return (ISC_R_FAILURE);
744		}
745	}
746
747	result = dns_zone_dumptostream(zone, output, fileformat, style,
748				       rawversion);
749	if (output != stdout)
750		(void)isc_stdio_close(output);
751
752	return (result);
753}
754
755#ifdef _WIN32
756void
757InitSockets(void) {
758	WORD wVersionRequested;
759	WSADATA wsaData;
760	int err;
761
762	wVersionRequested = MAKEWORD(2, 0);
763
764	err = WSAStartup( wVersionRequested, &wsaData );
765	if (err != 0) {
766		fprintf(stderr, "WSAStartup() failed: %d\n", err);
767		exit(1);
768	}
769}
770
771void
772DestroySockets(void) {
773	WSACleanup();
774}
775#endif
776