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