1135446Strhodes/*
2254402Serwin * Copyright (C) 2004, 2005, 2007, 2008, 2010, 2012, 2013  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1999-2002  Internet Software Consortium.
4135446Strhodes *
5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id: rootns.c,v 1.40 2010/06/18 05:36:24 marka Exp $ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <isc/buffer.h>
25135446Strhodes#include <isc/string.h>		/* Required for HP/UX (and others?) */
26135446Strhodes#include <isc/util.h>
27135446Strhodes
28135446Strhodes#include <dns/callbacks.h>
29135446Strhodes#include <dns/db.h>
30135446Strhodes#include <dns/dbiterator.h>
31170222Sdougb#include <dns/fixedname.h>
32135446Strhodes#include <dns/log.h>
33135446Strhodes#include <dns/master.h>
34135446Strhodes#include <dns/rdata.h>
35170222Sdougb#include <dns/rdata.h>
36170222Sdougb#include <dns/rdataset.h>
37135446Strhodes#include <dns/rdatasetiter.h>
38135446Strhodes#include <dns/rdatastruct.h>
39170222Sdougb#include <dns/rdatatype.h>
40135446Strhodes#include <dns/result.h>
41135446Strhodes#include <dns/rootns.h>
42170222Sdougb#include <dns/view.h>
43135446Strhodes
44135446Strhodesstatic char root_ns[] =
45135446Strhodes";\n"
46135446Strhodes"; Internet Root Nameservers\n"
47135446Strhodes";\n"
48135446Strhodes"$TTL 518400\n"
49135446Strhodes".                       518400  IN      NS      A.ROOT-SERVERS.NET.\n"
50135446Strhodes".                       518400  IN      NS      B.ROOT-SERVERS.NET.\n"
51135446Strhodes".                       518400  IN      NS      C.ROOT-SERVERS.NET.\n"
52135446Strhodes".                       518400  IN      NS      D.ROOT-SERVERS.NET.\n"
53135446Strhodes".                       518400  IN      NS      E.ROOT-SERVERS.NET.\n"
54135446Strhodes".                       518400  IN      NS      F.ROOT-SERVERS.NET.\n"
55135446Strhodes".                       518400  IN      NS      G.ROOT-SERVERS.NET.\n"
56135446Strhodes".                       518400  IN      NS      H.ROOT-SERVERS.NET.\n"
57135446Strhodes".                       518400  IN      NS      I.ROOT-SERVERS.NET.\n"
58135446Strhodes".                       518400  IN      NS      J.ROOT-SERVERS.NET.\n"
59135446Strhodes".                       518400  IN      NS      K.ROOT-SERVERS.NET.\n"
60135446Strhodes".                       518400  IN      NS      L.ROOT-SERVERS.NET.\n"
61135446Strhodes".                       518400  IN      NS      M.ROOT-SERVERS.NET.\n"
62135446Strhodes"A.ROOT-SERVERS.NET.     3600000 IN      A       198.41.0.4\n"
63186462Sdougb"A.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:503:BA3E::2:30\n"
64135446Strhodes"B.ROOT-SERVERS.NET.     3600000 IN      A       192.228.79.201\n"
65135446Strhodes"C.ROOT-SERVERS.NET.     3600000 IN      A       192.33.4.12\n"
66254402Serwin"D.ROOT-SERVERS.NET.     3600000 IN      A       199.7.91.13\n"
67254402Serwin"D.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:500:2d::d\n"
68135446Strhodes"E.ROOT-SERVERS.NET.     3600000 IN      A       192.203.230.10\n"
69135446Strhodes"F.ROOT-SERVERS.NET.     3600000 IN      A       192.5.5.241\n"
70186462Sdougb"F.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:500:2F::F\n"
71135446Strhodes"G.ROOT-SERVERS.NET.     3600000 IN      A       192.112.36.4\n"
72135446Strhodes"H.ROOT-SERVERS.NET.     3600000 IN      A       128.63.2.53\n"
73186462Sdougb"H.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:500:1::803F:235\n"
74135446Strhodes"I.ROOT-SERVERS.NET.     3600000 IN      A       192.36.148.17\n"
75218384Sdougb"I.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:7fe::53\n"
76135446Strhodes"J.ROOT-SERVERS.NET.     3600000 IN      A       192.58.128.30\n"
77186462Sdougb"J.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:503:C27::2:30\n"
78135446Strhodes"K.ROOT-SERVERS.NET.     3600000 IN      A       193.0.14.129\n"
79186462Sdougb"K.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:7FD::1\n"
80174187Sdougb"L.ROOT-SERVERS.NET.     3600000 IN      A       199.7.83.42\n"
81218384Sdougb"L.ROOT-SERVERS.NET.     604800  IN      AAAA    2001:500:3::42\n"
82186462Sdougb"M.ROOT-SERVERS.NET.     3600000 IN      A       202.12.27.33\n"
83186462Sdougb"M.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:DC3::35\n";
84135446Strhodes
85135446Strhodesstatic isc_result_t
86135446Strhodesin_rootns(dns_rdataset_t *rootns, dns_name_t *name) {
87135446Strhodes	isc_result_t result;
88135446Strhodes	dns_rdata_t rdata = DNS_RDATA_INIT;
89135446Strhodes	dns_rdata_ns_t ns;
90186462Sdougb
91135446Strhodes	if (!dns_rdataset_isassociated(rootns))
92135446Strhodes		return (ISC_R_NOTFOUND);
93135446Strhodes
94135446Strhodes	result = dns_rdataset_first(rootns);
95135446Strhodes	while (result == ISC_R_SUCCESS) {
96135446Strhodes		dns_rdataset_current(rootns, &rdata);
97135446Strhodes		result = dns_rdata_tostruct(&rdata, &ns, NULL);
98135446Strhodes		if (result != ISC_R_SUCCESS)
99135446Strhodes			return (result);
100135446Strhodes		if (dns_name_compare(name, &ns.name) == 0)
101135446Strhodes			return (ISC_R_SUCCESS);
102135446Strhodes		result = dns_rdataset_next(rootns);
103193149Sdougb		dns_rdata_reset(&rdata);
104135446Strhodes	}
105135446Strhodes	if (result == ISC_R_NOMORE)
106135446Strhodes		result = ISC_R_NOTFOUND;
107135446Strhodes	return (result);
108135446Strhodes}
109135446Strhodes
110186462Sdougbstatic isc_result_t
111135446Strhodescheck_node(dns_rdataset_t *rootns, dns_name_t *name,
112135446Strhodes	   dns_rdatasetiter_t *rdsiter) {
113135446Strhodes	isc_result_t result;
114135446Strhodes	dns_rdataset_t rdataset;
115135446Strhodes
116135446Strhodes	dns_rdataset_init(&rdataset);
117135446Strhodes	result = dns_rdatasetiter_first(rdsiter);
118135446Strhodes	while (result == ISC_R_SUCCESS) {
119135446Strhodes		dns_rdatasetiter_current(rdsiter, &rdataset);
120135446Strhodes		switch (rdataset.type) {
121135446Strhodes		case dns_rdatatype_a:
122135446Strhodes		case dns_rdatatype_aaaa:
123135446Strhodes			result = in_rootns(rootns, name);
124135446Strhodes			if (result != ISC_R_SUCCESS)
125135446Strhodes				goto cleanup;
126135446Strhodes			break;
127135446Strhodes		case dns_rdatatype_ns:
128135446Strhodes			if (dns_name_compare(name, dns_rootname) == 0)
129135446Strhodes				break;
130135446Strhodes			/*FALLTHROUGH*/
131135446Strhodes		default:
132135446Strhodes			result = ISC_R_FAILURE;
133135446Strhodes			goto cleanup;
134135446Strhodes		}
135135446Strhodes		dns_rdataset_disassociate(&rdataset);
136135446Strhodes		result = dns_rdatasetiter_next(rdsiter);
137135446Strhodes	}
138135446Strhodes	if (result == ISC_R_NOMORE)
139135446Strhodes		result = ISC_R_SUCCESS;
140135446Strhodes cleanup:
141135446Strhodes	if (dns_rdataset_isassociated(&rdataset))
142135446Strhodes		dns_rdataset_disassociate(&rdataset);
143135446Strhodes	return (result);
144135446Strhodes}
145135446Strhodes
146135446Strhodesstatic isc_result_t
147135446Strhodescheck_hints(dns_db_t *db) {
148135446Strhodes	isc_result_t result;
149135446Strhodes	dns_rdataset_t rootns;
150135446Strhodes	dns_dbiterator_t *dbiter = NULL;
151135446Strhodes	dns_dbnode_t *node = NULL;
152135446Strhodes	isc_stdtime_t now;
153135446Strhodes	dns_fixedname_t fixname;
154135446Strhodes	dns_name_t *name;
155135446Strhodes	dns_rdatasetiter_t *rdsiter = NULL;
156135446Strhodes
157135446Strhodes	isc_stdtime_get(&now);
158135446Strhodes
159135446Strhodes	dns_fixedname_init(&fixname);
160135446Strhodes	name = dns_fixedname_name(&fixname);
161135446Strhodes
162135446Strhodes	dns_rdataset_init(&rootns);
163135446Strhodes	(void)dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0,
164135446Strhodes			  now, NULL, name, &rootns, NULL);
165193149Sdougb	result = dns_db_createiterator(db, 0, &dbiter);
166135446Strhodes	if (result != ISC_R_SUCCESS)
167135446Strhodes		goto cleanup;
168135446Strhodes	result = dns_dbiterator_first(dbiter);
169135446Strhodes	while (result == ISC_R_SUCCESS) {
170135446Strhodes		result = dns_dbiterator_current(dbiter, &node, name);
171135446Strhodes		if (result != ISC_R_SUCCESS)
172135446Strhodes			goto cleanup;
173135446Strhodes		result = dns_db_allrdatasets(db, node, NULL, now, &rdsiter);
174135446Strhodes		if (result != ISC_R_SUCCESS)
175135446Strhodes			goto cleanup;
176135446Strhodes		result = check_node(&rootns, name, rdsiter);
177135446Strhodes		if (result != ISC_R_SUCCESS)
178135446Strhodes			goto cleanup;
179135446Strhodes		dns_rdatasetiter_destroy(&rdsiter);
180135446Strhodes		dns_db_detachnode(db, &node);
181135446Strhodes		result = dns_dbiterator_next(dbiter);
182135446Strhodes	}
183135446Strhodes	if (result == ISC_R_NOMORE)
184135446Strhodes		result = ISC_R_SUCCESS;
185135446Strhodes
186135446Strhodes cleanup:
187135446Strhodes	if (dns_rdataset_isassociated(&rootns))
188135446Strhodes		dns_rdataset_disassociate(&rootns);
189135446Strhodes	if (rdsiter != NULL)
190135446Strhodes		dns_rdatasetiter_destroy(&rdsiter);
191135446Strhodes	if (node != NULL)
192135446Strhodes		dns_db_detachnode(db, &node);
193135446Strhodes	if (dbiter != NULL)
194135446Strhodes		dns_dbiterator_destroy(&dbiter);
195135446Strhodes	return (result);
196135446Strhodes}
197135446Strhodes
198135446Strhodesisc_result_t
199135446Strhodesdns_rootns_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
200135446Strhodes		  const char *filename, dns_db_t **target)
201135446Strhodes{
202135446Strhodes	isc_result_t result, eresult;
203135446Strhodes	isc_buffer_t source;
204262706Serwin	unsigned int len;
205135446Strhodes	dns_rdatacallbacks_t callbacks;
206135446Strhodes	dns_db_t *db = NULL;
207135446Strhodes
208135446Strhodes	REQUIRE(target != NULL && *target == NULL);
209135446Strhodes
210135446Strhodes	result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
211135446Strhodes			       rdclass, 0, NULL, &db);
212135446Strhodes	if (result != ISC_R_SUCCESS)
213135446Strhodes		return (result);
214135446Strhodes
215135446Strhodes	dns_rdatacallbacks_init(&callbacks);
216135446Strhodes
217135446Strhodes	len = strlen(root_ns);
218135446Strhodes	isc_buffer_init(&source, root_ns, len);
219135446Strhodes	isc_buffer_add(&source, len);
220135446Strhodes
221135446Strhodes	result = dns_db_beginload(db, &callbacks.add,
222135446Strhodes				  &callbacks.add_private);
223135446Strhodes	if (result != ISC_R_SUCCESS)
224135446Strhodes		return (result);
225135446Strhodes	if (filename != NULL) {
226135446Strhodes		/*
227135446Strhodes		 * Load the hints from the specified filename.
228135446Strhodes		 */
229135446Strhodes		result = dns_master_loadfile(filename, &db->origin,
230135446Strhodes					     &db->origin, db->rdclass,
231135446Strhodes					     DNS_MASTER_HINT,
232135446Strhodes					     &callbacks, db->mctx);
233135446Strhodes	} else if (rdclass == dns_rdataclass_in) {
234135446Strhodes		/*
235135446Strhodes		 * Default to using the Internet root servers.
236135446Strhodes		 */
237135446Strhodes		result = dns_master_loadbuffer(&source, &db->origin,
238186462Sdougb					       &db->origin, db->rdclass,
239135446Strhodes					       DNS_MASTER_HINT,
240135446Strhodes					       &callbacks, db->mctx);
241135446Strhodes	} else
242135446Strhodes		result = ISC_R_NOTFOUND;
243135446Strhodes	eresult = dns_db_endload(db, &callbacks.add_private);
244135446Strhodes	if (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE)
245135446Strhodes		result = eresult;
246135446Strhodes	if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
247135446Strhodes		goto db_detach;
248135446Strhodes	if (check_hints(db) != ISC_R_SUCCESS)
249135446Strhodes		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
250135446Strhodes			      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
251135446Strhodes			      "extra data in root hints '%s'",
252135446Strhodes			      (filename != NULL) ? filename : "<BUILT-IN>");
253135446Strhodes	*target = db;
254135446Strhodes	return (ISC_R_SUCCESS);
255135446Strhodes
256135446Strhodes db_detach:
257135446Strhodes	dns_db_detach(&db);
258135446Strhodes
259135446Strhodes	return (result);
260135446Strhodes}
261170222Sdougb
262170222Sdougbstatic void
263170222Sdougbreport(dns_view_t *view, dns_name_t *name, isc_boolean_t missing,
264170222Sdougb       dns_rdata_t *rdata)
265170222Sdougb{
266170222Sdougb	const char *viewname = "", *sep = "";
267170222Sdougb	char namebuf[DNS_NAME_FORMATSIZE];
268170222Sdougb	char typebuf[DNS_RDATATYPE_FORMATSIZE];
269170222Sdougb	char databuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
270170222Sdougb	isc_buffer_t buffer;
271170222Sdougb	isc_result_t result;
272170222Sdougb
273186462Sdougb	if (strcmp(view->name, "_bind") != 0 &&
274186462Sdougb	    strcmp(view->name, "_default") != 0) {
275186462Sdougb		viewname = view->name;
276186462Sdougb		sep = ": view ";
277186462Sdougb	}
278170222Sdougb
279170222Sdougb	dns_name_format(name, namebuf, sizeof(namebuf));
280170222Sdougb	dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf));
281170222Sdougb	isc_buffer_init(&buffer, databuf, sizeof(databuf) - 1);
282170222Sdougb	result = dns_rdata_totext(rdata, NULL, &buffer);
283170222Sdougb	RUNTIME_CHECK(result == ISC_R_SUCCESS);
284170222Sdougb	databuf[isc_buffer_usedlength(&buffer)] = '\0';
285170222Sdougb
286170222Sdougb	if (missing)
287170222Sdougb		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
288170222Sdougb			      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
289170222Sdougb			      "checkhints%s%s: %s/%s (%s) missing from hints",
290170222Sdougb			      sep, viewname, namebuf, typebuf, databuf);
291170222Sdougb	else
292170222Sdougb		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
293170222Sdougb			      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
294170222Sdougb			      "checkhints%s%s: %s/%s (%s) extra record "
295170222Sdougb			      "in hints", sep, viewname, namebuf, typebuf,
296170222Sdougb			      databuf);
297170222Sdougb}
298170222Sdougb
299170222Sdougbstatic isc_boolean_t
300170222Sdougbinrrset(dns_rdataset_t *rrset, dns_rdata_t *rdata) {
301170222Sdougb	isc_result_t result;
302170222Sdougb	dns_rdata_t current = DNS_RDATA_INIT;
303170222Sdougb
304170222Sdougb	result = dns_rdataset_first(rrset);
305170222Sdougb	while (result == ISC_R_SUCCESS) {
306170222Sdougb		dns_rdataset_current(rrset, &current);
307170222Sdougb		if (dns_rdata_compare(rdata, &current) == 0)
308170222Sdougb			return (ISC_TRUE);
309170222Sdougb		dns_rdata_reset(&current);
310170222Sdougb		result = dns_rdataset_next(rrset);
311170222Sdougb	}
312170222Sdougb	return (ISC_FALSE);
313170222Sdougb}
314170222Sdougb
315170222Sdougb/*
316170222Sdougb * Check that the address RRsets match.
317170222Sdougb *
318170222Sdougb * Note we don't complain about missing glue records.
319170222Sdougb */
320170222Sdougb
321170222Sdougbstatic void
322170222Sdougbcheck_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db,
323170222Sdougb		      dns_name_t *name, isc_stdtime_t now)
324170222Sdougb{
325170222Sdougb	isc_result_t hresult, rresult, result;
326170222Sdougb	dns_rdataset_t hintrrset, rootrrset;
327170222Sdougb	dns_rdata_t rdata = DNS_RDATA_INIT;
328170222Sdougb	dns_name_t *foundname;
329170222Sdougb	dns_fixedname_t fixed;
330170222Sdougb
331170222Sdougb	dns_rdataset_init(&hintrrset);
332170222Sdougb	dns_rdataset_init(&rootrrset);
333170222Sdougb	dns_fixedname_init(&fixed);
334170222Sdougb	foundname = dns_fixedname_name(&fixed);
335170222Sdougb
336170222Sdougb	hresult = dns_db_find(hints, name, NULL, dns_rdatatype_a, 0,
337170222Sdougb			      now, NULL, foundname, &hintrrset, NULL);
338170222Sdougb	rresult = dns_db_find(db, name, NULL, dns_rdatatype_a,
339170222Sdougb			      DNS_DBFIND_GLUEOK, now, NULL, foundname,
340170222Sdougb			      &rootrrset, NULL);
341170222Sdougb	if (hresult == ISC_R_SUCCESS &&
342170222Sdougb	    (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
343170222Sdougb		result = dns_rdataset_first(&rootrrset);
344170222Sdougb		while (result == ISC_R_SUCCESS) {
345193149Sdougb			dns_rdata_reset(&rdata);
346170222Sdougb			dns_rdataset_current(&rootrrset, &rdata);
347170222Sdougb			if (!inrrset(&hintrrset, &rdata))
348170222Sdougb				report(view, name, ISC_TRUE, &rdata);
349170222Sdougb			result = dns_rdataset_next(&rootrrset);
350170222Sdougb		}
351170222Sdougb		result = dns_rdataset_first(&hintrrset);
352170222Sdougb		while (result == ISC_R_SUCCESS) {
353193149Sdougb			dns_rdata_reset(&rdata);
354170222Sdougb			dns_rdataset_current(&hintrrset, &rdata);
355170222Sdougb			if (!inrrset(&rootrrset, &rdata))
356170222Sdougb				report(view, name, ISC_FALSE, &rdata);
357170222Sdougb			result = dns_rdataset_next(&hintrrset);
358170222Sdougb		}
359186462Sdougb	}
360170222Sdougb	if (hresult == ISC_R_NOTFOUND &&
361170222Sdougb	    (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
362170222Sdougb		result = dns_rdataset_first(&rootrrset);
363170222Sdougb		while (result == ISC_R_SUCCESS) {
364193149Sdougb			dns_rdata_reset(&rdata);
365170222Sdougb			dns_rdataset_current(&rootrrset, &rdata);
366170222Sdougb			report(view, name, ISC_TRUE, &rdata);
367170222Sdougb			result = dns_rdataset_next(&rootrrset);
368170222Sdougb		}
369170222Sdougb	}
370170222Sdougb	if (dns_rdataset_isassociated(&rootrrset))
371170222Sdougb		dns_rdataset_disassociate(&rootrrset);
372170222Sdougb	if (dns_rdataset_isassociated(&hintrrset))
373170222Sdougb		dns_rdataset_disassociate(&hintrrset);
374170222Sdougb
375170222Sdougb	/*
376170222Sdougb	 * Check AAAA records.
377170222Sdougb	 */
378170222Sdougb	hresult = dns_db_find(hints, name, NULL, dns_rdatatype_aaaa, 0,
379170222Sdougb			      now, NULL, foundname, &hintrrset, NULL);
380170222Sdougb	rresult = dns_db_find(db, name, NULL, dns_rdatatype_aaaa,
381170222Sdougb			      DNS_DBFIND_GLUEOK, now, NULL, foundname,
382170222Sdougb			      &rootrrset, NULL);
383170222Sdougb	if (hresult == ISC_R_SUCCESS &&
384170222Sdougb	    (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
385170222Sdougb		result = dns_rdataset_first(&rootrrset);
386170222Sdougb		while (result == ISC_R_SUCCESS) {
387193149Sdougb			dns_rdata_reset(&rdata);
388170222Sdougb			dns_rdataset_current(&rootrrset, &rdata);
389170222Sdougb			if (!inrrset(&hintrrset, &rdata))
390170222Sdougb				report(view, name, ISC_TRUE, &rdata);
391170222Sdougb			dns_rdata_reset(&rdata);
392170222Sdougb			result = dns_rdataset_next(&rootrrset);
393170222Sdougb		}
394170222Sdougb		result = dns_rdataset_first(&hintrrset);
395170222Sdougb		while (result == ISC_R_SUCCESS) {
396193149Sdougb			dns_rdata_reset(&rdata);
397170222Sdougb			dns_rdataset_current(&hintrrset, &rdata);
398170222Sdougb			if (!inrrset(&rootrrset, &rdata))
399170222Sdougb				report(view, name, ISC_FALSE, &rdata);
400170222Sdougb			dns_rdata_reset(&rdata);
401170222Sdougb			result = dns_rdataset_next(&hintrrset);
402170222Sdougb		}
403186462Sdougb	}
404170222Sdougb	if (hresult == ISC_R_NOTFOUND &&
405170222Sdougb	    (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
406170222Sdougb		result = dns_rdataset_first(&rootrrset);
407170222Sdougb		while (result == ISC_R_SUCCESS) {
408193149Sdougb			dns_rdata_reset(&rdata);
409170222Sdougb			dns_rdataset_current(&rootrrset, &rdata);
410170222Sdougb			report(view, name, ISC_TRUE, &rdata);
411170222Sdougb			dns_rdata_reset(&rdata);
412170222Sdougb			result = dns_rdataset_next(&rootrrset);
413170222Sdougb		}
414170222Sdougb	}
415170222Sdougb	if (dns_rdataset_isassociated(&rootrrset))
416170222Sdougb		dns_rdataset_disassociate(&rootrrset);
417170222Sdougb	if (dns_rdataset_isassociated(&hintrrset))
418170222Sdougb		dns_rdataset_disassociate(&hintrrset);
419170222Sdougb}
420170222Sdougb
421170222Sdougbvoid
422170222Sdougbdns_root_checkhints(dns_view_t *view, dns_db_t *hints, dns_db_t *db) {
423170222Sdougb	isc_result_t result;
424170222Sdougb	dns_rdata_t rdata = DNS_RDATA_INIT;
425170222Sdougb	dns_rdata_ns_t ns;
426170222Sdougb	dns_rdataset_t hintns, rootns;
427170222Sdougb	const char *viewname = "", *sep = "";
428170222Sdougb	isc_stdtime_t now;
429170222Sdougb	dns_name_t *name;
430170222Sdougb	dns_fixedname_t fixed;
431170222Sdougb
432170222Sdougb	REQUIRE(hints != NULL);
433170222Sdougb	REQUIRE(db != NULL);
434170222Sdougb	REQUIRE(view != NULL);
435170222Sdougb
436170222Sdougb	isc_stdtime_get(&now);
437170222Sdougb
438186462Sdougb	if (strcmp(view->name, "_bind") != 0 &&
439186462Sdougb	    strcmp(view->name, "_default") != 0) {
440186462Sdougb		viewname = view->name;
441186462Sdougb		sep = ": view ";
442186462Sdougb	}
443170222Sdougb
444170222Sdougb	dns_rdataset_init(&hintns);
445170222Sdougb	dns_rdataset_init(&rootns);
446170222Sdougb	dns_fixedname_init(&fixed);
447170222Sdougb	name = dns_fixedname_name(&fixed);
448170222Sdougb
449170222Sdougb	result = dns_db_find(hints, dns_rootname, NULL, dns_rdatatype_ns, 0,
450170222Sdougb			     now, NULL, name, &hintns, NULL);
451170222Sdougb	if (result != ISC_R_SUCCESS) {
452170222Sdougb		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
453170222Sdougb			      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
454170222Sdougb			      "checkhints%s%s: unable to get root NS rrset "
455170222Sdougb			      "from hints: %s", sep, viewname,
456170222Sdougb			      dns_result_totext(result));
457170222Sdougb		goto cleanup;
458170222Sdougb	}
459170222Sdougb
460170222Sdougb	result = dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0,
461170222Sdougb			     now, NULL, name, &rootns, NULL);
462170222Sdougb	if (result != ISC_R_SUCCESS) {
463170222Sdougb		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
464170222Sdougb			      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
465170222Sdougb			      "checkhints%s%s: unable to get root NS rrset "
466170222Sdougb			      "from cache: %s", sep, viewname,
467170222Sdougb			      dns_result_totext(result));
468170222Sdougb		goto cleanup;
469170222Sdougb	}
470186462Sdougb
471170222Sdougb	/*
472170222Sdougb	 * Look for missing root NS names.
473170222Sdougb	 */
474170222Sdougb	result = dns_rdataset_first(&rootns);
475170222Sdougb	while (result == ISC_R_SUCCESS) {
476170222Sdougb		dns_rdataset_current(&rootns, &rdata);
477170222Sdougb		result = dns_rdata_tostruct(&rdata, &ns, NULL);
478170222Sdougb		RUNTIME_CHECK(result == ISC_R_SUCCESS);
479170222Sdougb		result = in_rootns(&hintns, &ns.name);
480170222Sdougb		if (result != ISC_R_SUCCESS) {
481170222Sdougb			char namebuf[DNS_NAME_FORMATSIZE];
482170222Sdougb			/* missing from hints */
483170222Sdougb			dns_name_format(&ns.name, namebuf, sizeof(namebuf));
484170222Sdougb			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
485170222Sdougb				      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
486170222Sdougb				      "checkhints%s%s: unable to find root "
487170222Sdougb				      "NS '%s' in hints", sep, viewname,
488170222Sdougb				      namebuf);
489186462Sdougb		} else
490170222Sdougb			check_address_records(view, hints, db, &ns.name, now);
491170222Sdougb		dns_rdata_reset(&rdata);
492170222Sdougb		result = dns_rdataset_next(&rootns);
493170222Sdougb	}
494170222Sdougb	if (result != ISC_R_NOMORE) {
495170222Sdougb		goto cleanup;
496170222Sdougb	}
497170222Sdougb
498170222Sdougb	/*
499170222Sdougb	 * Look for extra root NS names.
500170222Sdougb	 */
501170222Sdougb	result = dns_rdataset_first(&hintns);
502170222Sdougb	while (result == ISC_R_SUCCESS) {
503170222Sdougb		dns_rdataset_current(&hintns, &rdata);
504170222Sdougb		result = dns_rdata_tostruct(&rdata, &ns, NULL);
505170222Sdougb		RUNTIME_CHECK(result == ISC_R_SUCCESS);
506170222Sdougb		result = in_rootns(&rootns, &ns.name);
507170222Sdougb		if (result != ISC_R_SUCCESS) {
508170222Sdougb			char namebuf[DNS_NAME_FORMATSIZE];
509170222Sdougb			/* extra entry in hints */
510170222Sdougb			dns_name_format(&ns.name, namebuf, sizeof(namebuf));
511170222Sdougb			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
512170222Sdougb				      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
513170222Sdougb				      "checkhints%s%s: extra NS '%s' in hints",
514170222Sdougb				      sep, viewname, namebuf);
515170222Sdougb		}
516170222Sdougb		dns_rdata_reset(&rdata);
517170222Sdougb		result = dns_rdataset_next(&hintns);
518170222Sdougb	}
519170222Sdougb	if (result != ISC_R_NOMORE) {
520170222Sdougb		goto cleanup;
521170222Sdougb	}
522170222Sdougb
523170222Sdougb cleanup:
524170222Sdougb	if (dns_rdataset_isassociated(&rootns))
525170222Sdougb		dns_rdataset_disassociate(&rootns);
526170222Sdougb	if (dns_rdataset_isassociated(&hintns))
527170222Sdougb		dns_rdataset_disassociate(&hintns);
528170222Sdougb}
529