1/*
2 * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2002  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: check-tool.c,v 1.44 2011/12/22 07:32:39 each Exp $ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <stdio.h>
25
26#ifdef _WIN32
27#include <Winsock2.h>
28#endif
29
30#include "check-tool.h"
31#include <isc/buffer.h>
32#include <isc/log.h>
33#include <isc/mem.h>
34#include <isc/netdb.h>
35#include <isc/net.h>
36#include <isc/region.h>
37#include <isc/stdio.h>
38#include <isc/string.h>
39#include <isc/symtab.h>
40#include <isc/types.h>
41#include <isc/util.h>
42
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/types.h>
50#include <dns/zone.h>
51
52#include <isccfg/log.h>
53
54#ifndef CHECK_SIBLING
55#define CHECK_SIBLING 1
56#endif
57
58#ifndef CHECK_LOCAL
59#define CHECK_LOCAL 1
60#endif
61
62#ifdef HAVE_ADDRINFO
63#ifdef HAVE_GETADDRINFO
64#ifdef HAVE_GAISTRERROR
65#define USE_GETADDRINFO
66#endif
67#endif
68#endif
69
70#define CHECK(r) \
71	do { \
72		result = (r); \
73		if (result != ISC_R_SUCCESS) \
74			goto cleanup; \
75	} while (0)
76
77#define ERR_IS_CNAME 1
78#define ERR_NO_ADDRESSES 2
79#define ERR_LOOKUP_FAILURE 3
80#define ERR_EXTRA_A 4
81#define ERR_EXTRA_AAAA 5
82#define ERR_MISSING_GLUE 5
83#define ERR_IS_MXCNAME 6
84#define ERR_IS_SRVCNAME 7
85
86static const char *dbtype[] = { "rbt" };
87
88int debug = 0;
89isc_boolean_t nomerge = ISC_TRUE;
90#if CHECK_LOCAL
91isc_boolean_t docheckmx = ISC_TRUE;
92isc_boolean_t dochecksrv = ISC_TRUE;
93isc_boolean_t docheckns = ISC_TRUE;
94#else
95isc_boolean_t docheckmx = ISC_FALSE;
96isc_boolean_t dochecksrv = ISC_FALSE;
97isc_boolean_t docheckns = ISC_FALSE;
98#endif
99unsigned int zone_options = DNS_ZONEOPT_CHECKNS |
100			    DNS_ZONEOPT_CHECKMX |
101			    DNS_ZONEOPT_MANYERRORS |
102			    DNS_ZONEOPT_CHECKNAMES |
103			    DNS_ZONEOPT_CHECKINTEGRITY |
104#if CHECK_SIBLING
105			    DNS_ZONEOPT_CHECKSIBLING |
106#endif
107			    DNS_ZONEOPT_CHECKWILDCARD |
108			    DNS_ZONEOPT_WARNMXCNAME |
109			    DNS_ZONEOPT_WARNSRVCNAME;
110
111/*
112 * This needs to match the list in bin/named/log.c.
113 */
114static isc_logcategory_t categories[] = {
115	{ "",		     0 },
116	{ "client",	     0 },
117	{ "network",	     0 },
118	{ "update",	     0 },
119	{ "queries",	     0 },
120	{ "unmatched", 	     0 },
121	{ "update-security", 0 },
122	{ "query-errors",    0 },
123	{ NULL,		     0 }
124};
125
126static isc_symtab_t *symtab = NULL;
127static isc_mem_t *sym_mctx;
128
129static void
130freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
131	UNUSED(type);
132	UNUSED(value);
133	isc_mem_free(userarg, key);
134}
135
136static void
137add(char *key, int value) {
138	isc_result_t result;
139	isc_symvalue_t symvalue;
140
141	if (sym_mctx == NULL) {
142		result = isc_mem_create(0, 0, &sym_mctx);
143		if (result != ISC_R_SUCCESS)
144			return;
145	}
146
147	if (symtab == NULL) {
148		result = isc_symtab_create(sym_mctx, 100, freekey, sym_mctx,
149					   ISC_FALSE, &symtab);
150		if (result != ISC_R_SUCCESS)
151			return;
152	}
153
154	key = isc_mem_strdup(sym_mctx, key);
155	if (key == NULL)
156		return;
157
158	symvalue.as_pointer = NULL;
159	result = isc_symtab_define(symtab, key, value, symvalue,
160				   isc_symexists_reject);
161	if (result != ISC_R_SUCCESS)
162		isc_mem_free(sym_mctx, key);
163}
164
165static isc_boolean_t
166logged(char *key, int value) {
167	isc_result_t result;
168
169	if (symtab == NULL)
170		return (ISC_FALSE);
171
172	result = isc_symtab_lookup(symtab, key, value, NULL);
173	if (result == ISC_R_SUCCESS)
174		return (ISC_TRUE);
175	return (ISC_FALSE);
176}
177
178static isc_boolean_t
179checkns(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner,
180	dns_rdataset_t *a, dns_rdataset_t *aaaa)
181{
182#ifdef USE_GETADDRINFO
183	dns_rdataset_t *rdataset;
184	dns_rdata_t rdata = DNS_RDATA_INIT;
185	struct addrinfo hints, *ai, *cur;
186	char namebuf[DNS_NAME_FORMATSIZE + 1];
187	char ownerbuf[DNS_NAME_FORMATSIZE];
188	char addrbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
189	isc_boolean_t answer = ISC_TRUE;
190	isc_boolean_t match;
191	const char *type;
192	void *ptr = NULL;
193	int result;
194
195	REQUIRE(a == NULL || !dns_rdataset_isassociated(a) ||
196		a->type == dns_rdatatype_a);
197	REQUIRE(aaaa == NULL || !dns_rdataset_isassociated(aaaa) ||
198		aaaa->type == dns_rdatatype_aaaa);
199
200	if (a == NULL || aaaa == NULL)
201		return (answer);
202
203	memset(&hints, 0, sizeof(hints));
204	hints.ai_flags = AI_CANONNAME;
205	hints.ai_family = PF_UNSPEC;
206	hints.ai_socktype = SOCK_STREAM;
207	hints.ai_protocol = IPPROTO_TCP;
208
209	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
210	/*
211	 * Turn off search.
212	 */
213	if (dns_name_countlabels(name) > 1U)
214		strcat(namebuf, ".");
215	dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
216
217	result = getaddrinfo(namebuf, NULL, &hints, &ai);
218	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
219	switch (result) {
220	case 0:
221		/*
222		 * Work around broken getaddrinfo() implementations that
223		 * fail to set ai_canonname on first entry.
224		 */
225		cur = ai;
226		while (cur != NULL && cur->ai_canonname == NULL &&
227		       cur->ai_next != NULL)
228			cur = cur->ai_next;
229		if (cur != NULL && cur->ai_canonname != NULL &&
230		    strcasecmp(cur->ai_canonname, namebuf) != 0 &&
231		    !logged(namebuf, ERR_IS_CNAME)) {
232			dns_zone_log(zone, ISC_LOG_ERROR,
233				     "%s/NS '%s' (out of zone) "
234				     "is a CNAME '%s' (illegal)",
235				     ownerbuf, namebuf,
236				     cur->ai_canonname);
237			/* XXX950 make fatal for 9.5.0 */
238			/* answer = ISC_FALSE; */
239			add(namebuf, ERR_IS_CNAME);
240		}
241		break;
242	case EAI_NONAME:
243#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
244	case EAI_NODATA:
245#endif
246		if (!logged(namebuf, ERR_NO_ADDRESSES)) {
247			dns_zone_log(zone, ISC_LOG_ERROR,
248				     "%s/NS '%s' (out of zone) "
249				     "has no addresses records (A or AAAA)",
250				     ownerbuf, namebuf);
251			add(namebuf, ERR_NO_ADDRESSES);
252		}
253		/* XXX950 make fatal for 9.5.0 */
254		return (ISC_TRUE);
255
256	default:
257		if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
258			dns_zone_log(zone, ISC_LOG_WARNING,
259				     "getaddrinfo(%s) failed: %s",
260				     namebuf, gai_strerror(result));
261			add(namebuf, ERR_LOOKUP_FAILURE);
262		}
263		return (ISC_TRUE);
264	}
265
266	/*
267	 * Check that all glue records really exist.
268	 */
269	if (!dns_rdataset_isassociated(a))
270		goto checkaaaa;
271	result = dns_rdataset_first(a);
272	while (result == ISC_R_SUCCESS) {
273		dns_rdataset_current(a, &rdata);
274		match = ISC_FALSE;
275		for (cur = ai; cur != NULL; cur = cur->ai_next) {
276			if (cur->ai_family != AF_INET)
277				continue;
278			ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
279			if (memcmp(ptr, rdata.data, rdata.length) == 0) {
280				match = ISC_TRUE;
281				break;
282			}
283		}
284		if (!match && !logged(namebuf, ERR_EXTRA_A)) {
285			dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
286				     "extra GLUE A record (%s)",
287				     ownerbuf, namebuf,
288				     inet_ntop(AF_INET, rdata.data,
289					       addrbuf, sizeof(addrbuf)));
290			add(namebuf, ERR_EXTRA_A);
291			/* XXX950 make fatal for 9.5.0 */
292			/* answer = ISC_FALSE; */
293		}
294		dns_rdata_reset(&rdata);
295		result = dns_rdataset_next(a);
296	}
297
298 checkaaaa:
299	if (!dns_rdataset_isassociated(aaaa))
300		goto checkmissing;
301	result = dns_rdataset_first(aaaa);
302	while (result == ISC_R_SUCCESS) {
303		dns_rdataset_current(aaaa, &rdata);
304		match = ISC_FALSE;
305		for (cur = ai; cur != NULL; cur = cur->ai_next) {
306			if (cur->ai_family != AF_INET6)
307				continue;
308			ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
309			if (memcmp(ptr, rdata.data, rdata.length) == 0) {
310				match = ISC_TRUE;
311				break;
312			}
313		}
314		if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) {
315			dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
316				     "extra GLUE AAAA record (%s)",
317				     ownerbuf, namebuf,
318				     inet_ntop(AF_INET6, rdata.data,
319					       addrbuf, sizeof(addrbuf)));
320			add(namebuf, ERR_EXTRA_AAAA);
321			/* XXX950 make fatal for 9.5.0. */
322			/* answer = ISC_FALSE; */
323		}
324		dns_rdata_reset(&rdata);
325		result = dns_rdataset_next(aaaa);
326	}
327
328 checkmissing:
329	/*
330	 * Check that all addresses appear in the glue.
331	 */
332	if (!logged(namebuf, ERR_MISSING_GLUE)) {
333		isc_boolean_t missing_glue = ISC_FALSE;
334		for (cur = ai; cur != NULL; cur = cur->ai_next) {
335			switch (cur->ai_family) {
336			case AF_INET:
337				rdataset = a;
338				ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
339				type = "A";
340				break;
341			case AF_INET6:
342				rdataset = aaaa;
343				ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
344				type = "AAAA";
345				break;
346			default:
347				 continue;
348			}
349			match = ISC_FALSE;
350			if (dns_rdataset_isassociated(rdataset))
351				result = dns_rdataset_first(rdataset);
352			else
353				result = ISC_R_FAILURE;
354			while (result == ISC_R_SUCCESS && !match) {
355				dns_rdataset_current(rdataset, &rdata);
356				if (memcmp(ptr, rdata.data, rdata.length) == 0)
357					match = ISC_TRUE;
358				dns_rdata_reset(&rdata);
359				result = dns_rdataset_next(rdataset);
360			}
361			if (!match) {
362				dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
363					     "missing GLUE %s record (%s)",
364					     ownerbuf, namebuf, type,
365					     inet_ntop(cur->ai_family, ptr,
366						       addrbuf, sizeof(addrbuf)));
367				/* XXX950 make fatal for 9.5.0. */
368				/* answer = ISC_FALSE; */
369				missing_glue = ISC_TRUE;
370			}
371		}
372		if (missing_glue)
373			add(namebuf, ERR_MISSING_GLUE);
374	}
375	freeaddrinfo(ai);
376	return (answer);
377#else
378	return (ISC_TRUE);
379#endif
380}
381
382static isc_boolean_t
383checkmx(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
384#ifdef USE_GETADDRINFO
385	struct addrinfo hints, *ai, *cur;
386	char namebuf[DNS_NAME_FORMATSIZE + 1];
387	char ownerbuf[DNS_NAME_FORMATSIZE];
388	int result;
389	int level = ISC_LOG_ERROR;
390	isc_boolean_t answer = ISC_TRUE;
391
392	memset(&hints, 0, sizeof(hints));
393	hints.ai_flags = AI_CANONNAME;
394	hints.ai_family = PF_UNSPEC;
395	hints.ai_socktype = SOCK_STREAM;
396	hints.ai_protocol = IPPROTO_TCP;
397
398	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
399	/*
400	 * Turn off search.
401	 */
402	if (dns_name_countlabels(name) > 1U)
403		strcat(namebuf, ".");
404	dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
405
406	result = getaddrinfo(namebuf, NULL, &hints, &ai);
407	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
408	switch (result) {
409	case 0:
410		/*
411		 * Work around broken getaddrinfo() implementations that
412		 * fail to set ai_canonname on first entry.
413		 */
414		cur = ai;
415		while (cur != NULL && cur->ai_canonname == NULL &&
416		       cur->ai_next != NULL)
417			cur = cur->ai_next;
418		if (cur != NULL && cur->ai_canonname != NULL &&
419		    strcasecmp(cur->ai_canonname, namebuf) != 0) {
420			if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0)
421				level = ISC_LOG_WARNING;
422			if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) {
423				if (!logged(namebuf, ERR_IS_MXCNAME)) {
424					dns_zone_log(zone, level,
425						     "%s/MX '%s' (out of zone)"
426						     " is a CNAME '%s' "
427						     "(illegal)",
428						     ownerbuf, namebuf,
429						     cur->ai_canonname);
430					add(namebuf, ERR_IS_MXCNAME);
431				}
432				if (level == ISC_LOG_ERROR)
433					answer = ISC_FALSE;
434			}
435		}
436		freeaddrinfo(ai);
437		return (answer);
438
439	case EAI_NONAME:
440#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
441	case EAI_NODATA:
442#endif
443		if (!logged(namebuf, ERR_NO_ADDRESSES)) {
444			dns_zone_log(zone, ISC_LOG_ERROR,
445				     "%s/MX '%s' (out of zone) "
446				     "has no addresses records (A or AAAA)",
447				     ownerbuf, namebuf);
448			add(namebuf, ERR_NO_ADDRESSES);
449		}
450		/* XXX950 make fatal for 9.5.0. */
451		return (ISC_TRUE);
452
453	default:
454		if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
455			dns_zone_log(zone, ISC_LOG_WARNING,
456			     "getaddrinfo(%s) failed: %s",
457			     namebuf, gai_strerror(result));
458			add(namebuf, ERR_LOOKUP_FAILURE);
459		}
460		return (ISC_TRUE);
461	}
462#else
463	return (ISC_TRUE);
464#endif
465}
466
467static isc_boolean_t
468checksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
469#ifdef USE_GETADDRINFO
470	struct addrinfo hints, *ai, *cur;
471	char namebuf[DNS_NAME_FORMATSIZE + 1];
472	char ownerbuf[DNS_NAME_FORMATSIZE];
473	int result;
474	int level = ISC_LOG_ERROR;
475	isc_boolean_t answer = ISC_TRUE;
476
477	memset(&hints, 0, sizeof(hints));
478	hints.ai_flags = AI_CANONNAME;
479	hints.ai_family = PF_UNSPEC;
480	hints.ai_socktype = SOCK_STREAM;
481	hints.ai_protocol = IPPROTO_TCP;
482
483	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
484	/*
485	 * Turn off search.
486	 */
487	if (dns_name_countlabels(name) > 1U)
488		strcat(namebuf, ".");
489	dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
490
491	result = getaddrinfo(namebuf, NULL, &hints, &ai);
492	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
493	switch (result) {
494	case 0:
495		/*
496		 * Work around broken getaddrinfo() implementations that
497		 * fail to set ai_canonname on first entry.
498		 */
499		cur = ai;
500		while (cur != NULL && cur->ai_canonname == NULL &&
501		       cur->ai_next != NULL)
502			cur = cur->ai_next;
503		if (cur != NULL && cur->ai_canonname != NULL &&
504		    strcasecmp(cur->ai_canonname, namebuf) != 0) {
505			if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0)
506				level = ISC_LOG_WARNING;
507			if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) {
508				if (!logged(namebuf, ERR_IS_SRVCNAME)) {
509					dns_zone_log(zone, level, "%s/SRV '%s'"
510						     " (out of zone) is a "
511						     "CNAME '%s' (illegal)",
512						     ownerbuf, namebuf,
513						     cur->ai_canonname);
514					add(namebuf, ERR_IS_SRVCNAME);
515				}
516				if (level == ISC_LOG_ERROR)
517					answer = ISC_FALSE;
518			}
519		}
520		freeaddrinfo(ai);
521		return (answer);
522
523	case EAI_NONAME:
524#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
525	case EAI_NODATA:
526#endif
527		if (!logged(namebuf, ERR_NO_ADDRESSES)) {
528			dns_zone_log(zone, ISC_LOG_ERROR,
529				     "%s/SRV '%s' (out of zone) "
530				     "has no addresses records (A or AAAA)",
531				     ownerbuf, namebuf);
532			add(namebuf, ERR_NO_ADDRESSES);
533		}
534		/* XXX950 make fatal for 9.5.0. */
535		return (ISC_TRUE);
536
537	default:
538		if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
539			dns_zone_log(zone, ISC_LOG_WARNING,
540				     "getaddrinfo(%s) failed: %s",
541				     namebuf, gai_strerror(result));
542			add(namebuf, ERR_LOOKUP_FAILURE);
543		}
544		return (ISC_TRUE);
545	}
546#else
547	return (ISC_TRUE);
548#endif
549}
550
551isc_result_t
552setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) {
553	isc_logdestination_t destination;
554	isc_logconfig_t *logconfig = NULL;
555	isc_log_t *log = NULL;
556
557	RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS);
558	isc_log_registercategories(log, categories);
559	isc_log_setcontext(log);
560	dns_log_init(log);
561	dns_log_setcontext(log);
562	cfg_log_init(log);
563
564	destination.file.stream = errout;
565	destination.file.name = NULL;
566	destination.file.versions = ISC_LOG_ROLLNEVER;
567	destination.file.maximum_size = 0;
568	RUNTIME_CHECK(isc_log_createchannel(logconfig, "stderr",
569				       ISC_LOG_TOFILEDESC,
570				       ISC_LOG_DYNAMIC,
571				       &destination, 0) == ISC_R_SUCCESS);
572	RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr",
573					 NULL, NULL) == ISC_R_SUCCESS);
574
575	*logp = log;
576	return (ISC_R_SUCCESS);
577}
578
579/*% load the zone */
580isc_result_t
581load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
582	  dns_masterformat_t fileformat, const char *classname,
583	  dns_zone_t **zonep)
584{
585	isc_result_t result;
586	dns_rdataclass_t rdclass;
587	isc_textregion_t region;
588	isc_buffer_t buffer;
589	dns_fixedname_t fixorigin;
590	dns_name_t *origin;
591	dns_zone_t *zone = NULL;
592
593	REQUIRE(zonep == NULL || *zonep == NULL);
594
595	if (debug)
596		fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
597			zonename, filename, classname);
598
599	CHECK(dns_zone_create(&zone, mctx));
600
601	dns_zone_settype(zone, dns_zone_master);
602
603	isc_buffer_constinit(&buffer, zonename, strlen(zonename));
604	isc_buffer_add(&buffer, strlen(zonename));
605	dns_fixedname_init(&fixorigin);
606	origin = dns_fixedname_name(&fixorigin);
607	CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL));
608	CHECK(dns_zone_setorigin(zone, origin));
609	CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype));
610	CHECK(dns_zone_setfile2(zone, filename, fileformat));
611
612	DE_CONST(classname, region.base);
613	region.length = strlen(classname);
614	CHECK(dns_rdataclass_fromtext(&rdclass, &region));
615
616	dns_zone_setclass(zone, rdclass);
617	dns_zone_setoption(zone, zone_options, ISC_TRUE);
618	dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);
619	if (docheckmx)
620		dns_zone_setcheckmx(zone, checkmx);
621	if (docheckns)
622		dns_zone_setcheckns(zone, checkns);
623	if (dochecksrv)
624		dns_zone_setchecksrv(zone, checksrv);
625
626	CHECK(dns_zone_load(zone));
627	if (zonep != NULL) {
628		*zonep = zone;
629		zone = NULL;
630	}
631
632 cleanup:
633	if (zone != NULL)
634		dns_zone_detach(&zone);
635	return (result);
636}
637
638/*% dump the zone */
639isc_result_t
640dump_zone(const char *zonename, dns_zone_t *zone, const char *filename,
641	  dns_masterformat_t fileformat, const dns_master_style_t *style,
642	  const isc_uint32_t rawversion)
643{
644	isc_result_t result;
645	FILE *output = stdout;
646	const char *flags;
647
648	flags = (fileformat == dns_masterformat_text) ? "w+" : "wb+";
649
650	if (debug) {
651		if (filename != NULL && strcmp(filename, "-") != 0)
652			fprintf(stderr, "dumping \"%s\" to \"%s\"\n",
653				zonename, filename);
654		else
655			fprintf(stderr, "dumping \"%s\"\n", zonename);
656	}
657
658	if (filename != NULL && strcmp(filename, "-") != 0) {
659		result = isc_stdio_open(filename, flags, &output);
660
661		if (result != ISC_R_SUCCESS) {
662			fprintf(stderr, "could not open output "
663				"file \"%s\" for writing\n", filename);
664			return (ISC_R_FAILURE);
665		}
666	}
667
668	result = dns_zone_dumptostream3(zone, output, fileformat, style,
669					rawversion);
670	if (output != stdout)
671		(void)isc_stdio_close(output);
672
673	return (result);
674}
675
676#ifdef _WIN32
677void
678InitSockets(void) {
679	WORD wVersionRequested;
680	WSADATA wsaData;
681	int err;
682
683	wVersionRequested = MAKEWORD(2, 0);
684
685	err = WSAStartup( wVersionRequested, &wsaData );
686	if (err != 0) {
687		fprintf(stderr, "WSAStartup() failed: %d\n", err);
688		exit(1);
689	}
690}
691
692void
693DestroySockets(void) {
694	WSACleanup();
695}
696#endif
697
698