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