1/*
2 * Copyright (C) 2004-2010  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.41 2010/09/07 23:46:59 tbox 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	memset(&hints, 0, sizeof(hints));
200	hints.ai_flags = AI_CANONNAME;
201	hints.ai_family = PF_UNSPEC;
202	hints.ai_socktype = SOCK_STREAM;
203	hints.ai_protocol = IPPROTO_TCP;
204
205	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
206	/*
207	 * Turn off search.
208	 */
209	if (dns_name_countlabels(name) > 1U)
210		strcat(namebuf, ".");
211	dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
212
213	result = getaddrinfo(namebuf, NULL, &hints, &ai);
214	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
215	switch (result) {
216	case 0:
217		/*
218		 * Work around broken getaddrinfo() implementations that
219		 * fail to set ai_canonname on first entry.
220		 */
221		cur = ai;
222		while (cur != NULL && cur->ai_canonname == NULL &&
223		       cur->ai_next != NULL)
224			cur = cur->ai_next;
225		if (cur != NULL && cur->ai_canonname != NULL &&
226		    strcasecmp(cur->ai_canonname, namebuf) != 0 &&
227		    !logged(namebuf, ERR_IS_CNAME)) {
228			dns_zone_log(zone, ISC_LOG_ERROR,
229				     "%s/NS '%s' (out of zone) "
230				     "is a CNAME '%s' (illegal)",
231				     ownerbuf, namebuf,
232				     cur->ai_canonname);
233			/* XXX950 make fatal for 9.5.0 */
234			/* answer = ISC_FALSE; */
235			add(namebuf, ERR_IS_CNAME);
236		}
237		break;
238	case EAI_NONAME:
239#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
240	case EAI_NODATA:
241#endif
242		if (!logged(namebuf, ERR_NO_ADDRESSES)) {
243			dns_zone_log(zone, ISC_LOG_ERROR,
244				     "%s/NS '%s' (out of zone) "
245				     "has no addresses records (A or AAAA)",
246				     ownerbuf, namebuf);
247			add(namebuf, ERR_NO_ADDRESSES);
248		}
249		/* XXX950 make fatal for 9.5.0 */
250		return (ISC_TRUE);
251
252	default:
253		if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
254			dns_zone_log(zone, ISC_LOG_WARNING,
255				     "getaddrinfo(%s) failed: %s",
256				     namebuf, gai_strerror(result));
257			add(namebuf, ERR_LOOKUP_FAILURE);
258		}
259		return (ISC_TRUE);
260	}
261	if (a == NULL || aaaa == NULL)
262		return (answer);
263	/*
264	 * Check that all glue records really exist.
265	 */
266	if (!dns_rdataset_isassociated(a))
267		goto checkaaaa;
268	result = dns_rdataset_first(a);
269	while (result == ISC_R_SUCCESS) {
270		dns_rdataset_current(a, &rdata);
271		match = ISC_FALSE;
272		for (cur = ai; cur != NULL; cur = cur->ai_next) {
273			if (cur->ai_family != AF_INET)
274				continue;
275			ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
276			if (memcmp(ptr, rdata.data, rdata.length) == 0) {
277				match = ISC_TRUE;
278				break;
279			}
280		}
281		if (!match && !logged(namebuf, ERR_EXTRA_A)) {
282			dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
283				     "extra GLUE A record (%s)",
284				     ownerbuf, namebuf,
285				     inet_ntop(AF_INET, rdata.data,
286					       addrbuf, sizeof(addrbuf)));
287			add(namebuf, ERR_EXTRA_A);
288			/* XXX950 make fatal for 9.5.0 */
289			/* answer = ISC_FALSE; */
290		}
291		dns_rdata_reset(&rdata);
292		result = dns_rdataset_next(a);
293	}
294
295 checkaaaa:
296	if (!dns_rdataset_isassociated(aaaa))
297		goto checkmissing;
298	result = dns_rdataset_first(aaaa);
299	while (result == ISC_R_SUCCESS) {
300		dns_rdataset_current(aaaa, &rdata);
301		match = ISC_FALSE;
302		for (cur = ai; cur != NULL; cur = cur->ai_next) {
303			if (cur->ai_family != AF_INET6)
304				continue;
305			ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
306			if (memcmp(ptr, rdata.data, rdata.length) == 0) {
307				match = ISC_TRUE;
308				break;
309			}
310		}
311		if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) {
312			dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
313				     "extra GLUE AAAA record (%s)",
314				     ownerbuf, namebuf,
315				     inet_ntop(AF_INET6, rdata.data,
316					       addrbuf, sizeof(addrbuf)));
317			add(namebuf, ERR_EXTRA_AAAA);
318			/* XXX950 make fatal for 9.5.0. */
319			/* answer = ISC_FALSE; */
320		}
321		dns_rdata_reset(&rdata);
322		result = dns_rdataset_next(aaaa);
323	}
324
325 checkmissing:
326	/*
327	 * Check that all addresses appear in the glue.
328	 */
329	if (!logged(namebuf, ERR_MISSING_GLUE)) {
330		isc_boolean_t missing_glue = ISC_FALSE;
331		for (cur = ai; cur != NULL; cur = cur->ai_next) {
332			switch (cur->ai_family) {
333			case AF_INET:
334				rdataset = a;
335				ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
336				type = "A";
337				break;
338			case AF_INET6:
339				rdataset = aaaa;
340				ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
341				type = "AAAA";
342				break;
343			default:
344				 continue;
345			}
346			match = ISC_FALSE;
347			if (dns_rdataset_isassociated(rdataset))
348				result = dns_rdataset_first(rdataset);
349			else
350				result = ISC_R_FAILURE;
351			while (result == ISC_R_SUCCESS && !match) {
352				dns_rdataset_current(rdataset, &rdata);
353				if (memcmp(ptr, rdata.data, rdata.length) == 0)
354					match = ISC_TRUE;
355				dns_rdata_reset(&rdata);
356				result = dns_rdataset_next(rdataset);
357			}
358			if (!match) {
359				dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
360					     "missing GLUE %s record (%s)",
361					     ownerbuf, namebuf, type,
362					     inet_ntop(cur->ai_family, ptr,
363						       addrbuf, sizeof(addrbuf)));
364				/* XXX950 make fatal for 9.5.0. */
365				/* answer = ISC_FALSE; */
366				missing_glue = ISC_TRUE;
367			}
368		}
369		if (missing_glue)
370			add(namebuf, ERR_MISSING_GLUE);
371	}
372	freeaddrinfo(ai);
373	return (answer);
374#else
375	return (ISC_TRUE);
376#endif
377}
378
379static isc_boolean_t
380checkmx(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
381#ifdef USE_GETADDRINFO
382	struct addrinfo hints, *ai, *cur;
383	char namebuf[DNS_NAME_FORMATSIZE + 1];
384	char ownerbuf[DNS_NAME_FORMATSIZE];
385	int result;
386	int level = ISC_LOG_ERROR;
387	isc_boolean_t answer = ISC_TRUE;
388
389	memset(&hints, 0, sizeof(hints));
390	hints.ai_flags = AI_CANONNAME;
391	hints.ai_family = PF_UNSPEC;
392	hints.ai_socktype = SOCK_STREAM;
393	hints.ai_protocol = IPPROTO_TCP;
394
395	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
396	/*
397	 * Turn off search.
398	 */
399	if (dns_name_countlabels(name) > 1U)
400		strcat(namebuf, ".");
401	dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
402
403	result = getaddrinfo(namebuf, NULL, &hints, &ai);
404	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
405	switch (result) {
406	case 0:
407		/*
408		 * Work around broken getaddrinfo() implementations that
409		 * fail to set ai_canonname on first entry.
410		 */
411		cur = ai;
412		while (cur != NULL && cur->ai_canonname == NULL &&
413		       cur->ai_next != NULL)
414			cur = cur->ai_next;
415		if (cur != NULL && cur->ai_canonname != NULL &&
416		    strcasecmp(cur->ai_canonname, namebuf) != 0) {
417			if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0)
418				level = ISC_LOG_WARNING;
419			if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) {
420				if (!logged(namebuf, ERR_IS_MXCNAME)) {
421					dns_zone_log(zone, level,
422						     "%s/MX '%s' (out of zone)"
423						     " is a CNAME '%s' "
424						     "(illegal)",
425						     ownerbuf, namebuf,
426						     cur->ai_canonname);
427					add(namebuf, ERR_IS_MXCNAME);
428				}
429				if (level == ISC_LOG_ERROR)
430					answer = ISC_FALSE;
431			}
432		}
433		freeaddrinfo(ai);
434		return (answer);
435
436	case EAI_NONAME:
437#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
438	case EAI_NODATA:
439#endif
440		if (!logged(namebuf, ERR_NO_ADDRESSES)) {
441			dns_zone_log(zone, ISC_LOG_ERROR,
442				     "%s/MX '%s' (out of zone) "
443				     "has no addresses records (A or AAAA)",
444				     ownerbuf, namebuf);
445			add(namebuf, ERR_NO_ADDRESSES);
446		}
447		/* XXX950 make fatal for 9.5.0. */
448		return (ISC_TRUE);
449
450	default:
451		if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
452			dns_zone_log(zone, ISC_LOG_WARNING,
453			     "getaddrinfo(%s) failed: %s",
454			     namebuf, gai_strerror(result));
455			add(namebuf, ERR_LOOKUP_FAILURE);
456		}
457		return (ISC_TRUE);
458	}
459#else
460	return (ISC_TRUE);
461#endif
462}
463
464static isc_boolean_t
465checksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
466#ifdef USE_GETADDRINFO
467	struct addrinfo hints, *ai, *cur;
468	char namebuf[DNS_NAME_FORMATSIZE + 1];
469	char ownerbuf[DNS_NAME_FORMATSIZE];
470	int result;
471	int level = ISC_LOG_ERROR;
472	isc_boolean_t answer = ISC_TRUE;
473
474	memset(&hints, 0, sizeof(hints));
475	hints.ai_flags = AI_CANONNAME;
476	hints.ai_family = PF_UNSPEC;
477	hints.ai_socktype = SOCK_STREAM;
478	hints.ai_protocol = IPPROTO_TCP;
479
480	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
481	/*
482	 * Turn off search.
483	 */
484	if (dns_name_countlabels(name) > 1U)
485		strcat(namebuf, ".");
486	dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
487
488	result = getaddrinfo(namebuf, NULL, &hints, &ai);
489	dns_name_format(name, namebuf, sizeof(namebuf) - 1);
490	switch (result) {
491	case 0:
492		/*
493		 * Work around broken getaddrinfo() implementations that
494		 * fail to set ai_canonname on first entry.
495		 */
496		cur = ai;
497		while (cur != NULL && cur->ai_canonname == NULL &&
498		       cur->ai_next != NULL)
499			cur = cur->ai_next;
500		if (cur != NULL && cur->ai_canonname != NULL &&
501		    strcasecmp(cur->ai_canonname, namebuf) != 0) {
502			if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0)
503				level = ISC_LOG_WARNING;
504			if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) {
505				if (!logged(namebuf, ERR_IS_SRVCNAME)) {
506					dns_zone_log(zone, level, "%s/SRV '%s'"
507						     " (out of zone) is a "
508						     "CNAME '%s' (illegal)",
509						     ownerbuf, namebuf,
510						     cur->ai_canonname);
511					add(namebuf, ERR_IS_SRVCNAME);
512				}
513				if (level == ISC_LOG_ERROR)
514					answer = ISC_FALSE;
515			}
516		}
517		freeaddrinfo(ai);
518		return (answer);
519
520	case EAI_NONAME:
521#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
522	case EAI_NODATA:
523#endif
524		if (!logged(namebuf, ERR_NO_ADDRESSES)) {
525			dns_zone_log(zone, ISC_LOG_ERROR,
526				     "%s/SRV '%s' (out of zone) "
527				     "has no addresses records (A or AAAA)",
528				     ownerbuf, namebuf);
529			add(namebuf, ERR_NO_ADDRESSES);
530		}
531		/* XXX950 make fatal for 9.5.0. */
532		return (ISC_TRUE);
533
534	default:
535		if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
536			dns_zone_log(zone, ISC_LOG_WARNING,
537				     "getaddrinfo(%s) failed: %s",
538				     namebuf, gai_strerror(result));
539			add(namebuf, ERR_LOOKUP_FAILURE);
540		}
541		return (ISC_TRUE);
542	}
543#else
544	return (ISC_TRUE);
545#endif
546}
547
548isc_result_t
549setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) {
550	isc_logdestination_t destination;
551	isc_logconfig_t *logconfig = NULL;
552	isc_log_t *log = NULL;
553
554	RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS);
555	isc_log_registercategories(log, categories);
556	isc_log_setcontext(log);
557	dns_log_init(log);
558	dns_log_setcontext(log);
559	cfg_log_init(log);
560
561	destination.file.stream = errout;
562	destination.file.name = NULL;
563	destination.file.versions = ISC_LOG_ROLLNEVER;
564	destination.file.maximum_size = 0;
565	RUNTIME_CHECK(isc_log_createchannel(logconfig, "stderr",
566				       ISC_LOG_TOFILEDESC,
567				       ISC_LOG_DYNAMIC,
568				       &destination, 0) == ISC_R_SUCCESS);
569	RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr",
570					 NULL, NULL) == ISC_R_SUCCESS);
571
572	*logp = log;
573	return (ISC_R_SUCCESS);
574}
575
576/*% load the zone */
577isc_result_t
578load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
579	  dns_masterformat_t fileformat, const char *classname,
580	  dns_zone_t **zonep)
581{
582	isc_result_t result;
583	dns_rdataclass_t rdclass;
584	isc_textregion_t region;
585	isc_buffer_t buffer;
586	dns_fixedname_t fixorigin;
587	dns_name_t *origin;
588	dns_zone_t *zone = NULL;
589
590	REQUIRE(zonep == NULL || *zonep == NULL);
591
592	if (debug)
593		fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
594			zonename, filename, classname);
595
596	CHECK(dns_zone_create(&zone, mctx));
597
598	dns_zone_settype(zone, dns_zone_master);
599
600	isc_buffer_init(&buffer, zonename, strlen(zonename));
601	isc_buffer_add(&buffer, strlen(zonename));
602	dns_fixedname_init(&fixorigin);
603	origin = dns_fixedname_name(&fixorigin);
604	CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL));
605	CHECK(dns_zone_setorigin(zone, origin));
606	CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype));
607	CHECK(dns_zone_setfile2(zone, filename, fileformat));
608
609	DE_CONST(classname, region.base);
610	region.length = strlen(classname);
611	CHECK(dns_rdataclass_fromtext(&rdclass, &region));
612
613	dns_zone_setclass(zone, rdclass);
614	dns_zone_setoption(zone, zone_options, ISC_TRUE);
615	dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);
616	if (docheckmx)
617		dns_zone_setcheckmx(zone, checkmx);
618	if (docheckns)
619		dns_zone_setcheckns(zone, checkns);
620	if (dochecksrv)
621		dns_zone_setchecksrv(zone, checksrv);
622
623	CHECK(dns_zone_load(zone));
624	if (zonep != NULL) {
625		*zonep = zone;
626		zone = NULL;
627	}
628
629 cleanup:
630	if (zone != NULL)
631		dns_zone_detach(&zone);
632	return (result);
633}
634
635/*% dump the zone */
636isc_result_t
637dump_zone(const char *zonename, dns_zone_t *zone, const char *filename,
638	  dns_masterformat_t fileformat, const dns_master_style_t *style)
639{
640	isc_result_t result;
641	FILE *output = stdout;
642
643	if (debug) {
644		if (filename != NULL && strcmp(filename, "-") != 0)
645			fprintf(stderr, "dumping \"%s\" to \"%s\"\n",
646				zonename, filename);
647		else
648			fprintf(stderr, "dumping \"%s\"\n", zonename);
649	}
650
651	if (filename != NULL && strcmp(filename, "-") != 0) {
652		result = isc_stdio_open(filename, "w+", &output);
653
654		if (result != ISC_R_SUCCESS) {
655			fprintf(stderr, "could not open output "
656				"file \"%s\" for writing\n", filename);
657			return (ISC_R_FAILURE);
658		}
659	}
660
661	result = dns_zone_dumptostream2(zone, output, fileformat, style);
662
663	if (output != stdout)
664		(void)isc_stdio_close(output);
665
666	return (result);
667}
668
669#ifdef _WIN32
670void
671InitSockets(void) {
672	WORD wVersionRequested;
673	WSADATA wsaData;
674	int err;
675
676	wVersionRequested = MAKEWORD(2, 0);
677
678	err = WSAStartup( wVersionRequested, &wsaData );
679	if (err != 0) {
680		fprintf(stderr, "WSAStartup() failed: %d\n", err);
681		exit(1);
682	}
683}
684
685void
686DestroySockets(void) {
687	WSACleanup();
688}
689#endif
690
691