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