xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rootns.c (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
1 /*	$NetBSD: rootns.c,v 1.4 2020/05/24 19:46:23 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*! \file */
15 
16 #include <stdbool.h>
17 
18 #include <isc/buffer.h>
19 #include <isc/string.h> /* Required for HP/UX (and others?) */
20 #include <isc/util.h>
21 
22 #include <dns/callbacks.h>
23 #include <dns/db.h>
24 #include <dns/dbiterator.h>
25 #include <dns/fixedname.h>
26 #include <dns/log.h>
27 #include <dns/master.h>
28 #include <dns/rdata.h>
29 #include <dns/rdataset.h>
30 #include <dns/rdatasetiter.h>
31 #include <dns/rdatastruct.h>
32 #include <dns/rdatatype.h>
33 #include <dns/result.h>
34 #include <dns/rootns.h>
35 #include <dns/view.h>
36 
37 static char root_ns[] =
38 	";\n"
39 	"; Internet Root Nameservers\n"
40 	";\n"
41 	"$TTL 518400\n"
42 	".                       518400  IN      NS      A.ROOT-SERVERS.NET.\n"
43 	".                       518400  IN      NS      B.ROOT-SERVERS.NET.\n"
44 	".                       518400  IN      NS      C.ROOT-SERVERS.NET.\n"
45 	".                       518400  IN      NS      D.ROOT-SERVERS.NET.\n"
46 	".                       518400  IN      NS      E.ROOT-SERVERS.NET.\n"
47 	".                       518400  IN      NS      F.ROOT-SERVERS.NET.\n"
48 	".                       518400  IN      NS      G.ROOT-SERVERS.NET.\n"
49 	".                       518400  IN      NS      H.ROOT-SERVERS.NET.\n"
50 	".                       518400  IN      NS      I.ROOT-SERVERS.NET.\n"
51 	".                       518400  IN      NS      J.ROOT-SERVERS.NET.\n"
52 	".                       518400  IN      NS      K.ROOT-SERVERS.NET.\n"
53 	".                       518400  IN      NS      L.ROOT-SERVERS.NET.\n"
54 	".                       518400  IN      NS      M.ROOT-SERVERS.NET.\n"
55 	"A.ROOT-SERVERS.NET.     3600000 IN      A       198.41.0.4\n"
56 	"A.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:503:BA3E::2:30\n"
57 	"B.ROOT-SERVERS.NET.     3600000 IN      A       199.9.14.201\n"
58 	"B.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:500:200::b\n"
59 	"C.ROOT-SERVERS.NET.     3600000 IN      A       192.33.4.12\n"
60 	"C.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:500:2::c\n"
61 	"D.ROOT-SERVERS.NET.     3600000 IN      A       199.7.91.13\n"
62 	"D.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:500:2d::d\n"
63 	"E.ROOT-SERVERS.NET.     3600000 IN      A       192.203.230.10\n"
64 	"E.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:500:a8::e\n"
65 	"F.ROOT-SERVERS.NET.     3600000 IN      A       192.5.5.241\n"
66 	"F.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:500:2F::F\n"
67 	"G.ROOT-SERVERS.NET.     3600000 IN      A       192.112.36.4\n"
68 	"G.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:500:12::d0d\n"
69 	"H.ROOT-SERVERS.NET.     3600000 IN      A       198.97.190.53\n"
70 	"H.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:500:1::53\n"
71 	"I.ROOT-SERVERS.NET.     3600000 IN      A       192.36.148.17\n"
72 	"I.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:7fe::53\n"
73 	"J.ROOT-SERVERS.NET.     3600000 IN      A       192.58.128.30\n"
74 	"J.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:503:C27::2:30\n"
75 	"K.ROOT-SERVERS.NET.     3600000 IN      A       193.0.14.129\n"
76 	"K.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:7FD::1\n"
77 	"L.ROOT-SERVERS.NET.     3600000 IN      A       199.7.83.42\n"
78 	"L.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:500:9f::42\n"
79 	"M.ROOT-SERVERS.NET.     3600000 IN      A       202.12.27.33\n"
80 	"M.ROOT-SERVERS.NET.     3600000 IN      AAAA    2001:DC3::35\n";
81 
82 static isc_result_t
83 in_rootns(dns_rdataset_t *rootns, dns_name_t *name) {
84 	isc_result_t result;
85 	dns_rdata_t rdata = DNS_RDATA_INIT;
86 	dns_rdata_ns_t ns;
87 
88 	if (!dns_rdataset_isassociated(rootns)) {
89 		return (ISC_R_NOTFOUND);
90 	}
91 
92 	result = dns_rdataset_first(rootns);
93 	while (result == ISC_R_SUCCESS) {
94 		dns_rdataset_current(rootns, &rdata);
95 		result = dns_rdata_tostruct(&rdata, &ns, NULL);
96 		if (result != ISC_R_SUCCESS) {
97 			return (result);
98 		}
99 		if (dns_name_compare(name, &ns.name) == 0) {
100 			return (ISC_R_SUCCESS);
101 		}
102 		result = dns_rdataset_next(rootns);
103 		dns_rdata_reset(&rdata);
104 	}
105 	if (result == ISC_R_NOMORE) {
106 		result = ISC_R_NOTFOUND;
107 	}
108 	return (result);
109 }
110 
111 static isc_result_t
112 check_node(dns_rdataset_t *rootns, dns_name_t *name,
113 	   dns_rdatasetiter_t *rdsiter) {
114 	isc_result_t result;
115 	dns_rdataset_t rdataset;
116 
117 	dns_rdataset_init(&rdataset);
118 	result = dns_rdatasetiter_first(rdsiter);
119 	while (result == ISC_R_SUCCESS) {
120 		dns_rdatasetiter_current(rdsiter, &rdataset);
121 		switch (rdataset.type) {
122 		case dns_rdatatype_a:
123 		case dns_rdatatype_aaaa:
124 			result = in_rootns(rootns, name);
125 			if (result != ISC_R_SUCCESS) {
126 				goto cleanup;
127 			}
128 			break;
129 		case dns_rdatatype_ns:
130 			if (dns_name_compare(name, dns_rootname) == 0) {
131 				break;
132 			}
133 		/* FALLTHROUGH */
134 		default:
135 			result = ISC_R_FAILURE;
136 			goto cleanup;
137 		}
138 		dns_rdataset_disassociate(&rdataset);
139 		result = dns_rdatasetiter_next(rdsiter);
140 	}
141 	if (result == ISC_R_NOMORE) {
142 		result = ISC_R_SUCCESS;
143 	}
144 cleanup:
145 	if (dns_rdataset_isassociated(&rdataset)) {
146 		dns_rdataset_disassociate(&rdataset);
147 	}
148 	return (result);
149 }
150 
151 static isc_result_t
152 check_hints(dns_db_t *db) {
153 	isc_result_t result;
154 	dns_rdataset_t rootns;
155 	dns_dbiterator_t *dbiter = NULL;
156 	dns_dbnode_t *node = NULL;
157 	isc_stdtime_t now;
158 	dns_fixedname_t fixname;
159 	dns_name_t *name;
160 	dns_rdatasetiter_t *rdsiter = NULL;
161 
162 	isc_stdtime_get(&now);
163 
164 	name = dns_fixedname_initname(&fixname);
165 
166 	dns_rdataset_init(&rootns);
167 	(void)dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0, now,
168 			  NULL, name, &rootns, NULL);
169 	result = dns_db_createiterator(db, 0, &dbiter);
170 	if (result != ISC_R_SUCCESS) {
171 		goto cleanup;
172 	}
173 	result = dns_dbiterator_first(dbiter);
174 	while (result == ISC_R_SUCCESS) {
175 		result = dns_dbiterator_current(dbiter, &node, name);
176 		if (result != ISC_R_SUCCESS) {
177 			goto cleanup;
178 		}
179 		result = dns_db_allrdatasets(db, node, NULL, now, &rdsiter);
180 		if (result != ISC_R_SUCCESS) {
181 			goto cleanup;
182 		}
183 		result = check_node(&rootns, name, rdsiter);
184 		if (result != ISC_R_SUCCESS) {
185 			goto cleanup;
186 		}
187 		dns_rdatasetiter_destroy(&rdsiter);
188 		dns_db_detachnode(db, &node);
189 		result = dns_dbiterator_next(dbiter);
190 	}
191 	if (result == ISC_R_NOMORE) {
192 		result = ISC_R_SUCCESS;
193 	}
194 
195 cleanup:
196 	if (dns_rdataset_isassociated(&rootns)) {
197 		dns_rdataset_disassociate(&rootns);
198 	}
199 	if (rdsiter != NULL) {
200 		dns_rdatasetiter_destroy(&rdsiter);
201 	}
202 	if (node != NULL) {
203 		dns_db_detachnode(db, &node);
204 	}
205 	if (dbiter != NULL) {
206 		dns_dbiterator_destroy(&dbiter);
207 	}
208 	return (result);
209 }
210 
211 isc_result_t
212 dns_rootns_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
213 		  const char *filename, dns_db_t **target) {
214 	isc_result_t result, eresult;
215 	isc_buffer_t source;
216 	unsigned int len;
217 	dns_rdatacallbacks_t callbacks;
218 	dns_db_t *db = NULL;
219 
220 	REQUIRE(target != NULL && *target == NULL);
221 
222 	result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
223 			       rdclass, 0, NULL, &db);
224 	if (result != ISC_R_SUCCESS) {
225 		goto failure;
226 	}
227 
228 	len = strlen(root_ns);
229 	isc_buffer_init(&source, root_ns, len);
230 	isc_buffer_add(&source, len);
231 
232 	dns_rdatacallbacks_init(&callbacks);
233 	result = dns_db_beginload(db, &callbacks);
234 	if (result != ISC_R_SUCCESS) {
235 		goto failure;
236 	}
237 	if (filename != NULL) {
238 		/*
239 		 * Load the hints from the specified filename.
240 		 */
241 		result = dns_master_loadfile(filename, &db->origin, &db->origin,
242 					     db->rdclass, DNS_MASTER_HINT, 0,
243 					     &callbacks, NULL, NULL, db->mctx,
244 					     dns_masterformat_text, 0);
245 	} else if (rdclass == dns_rdataclass_in) {
246 		/*
247 		 * Default to using the Internet root servers.
248 		 */
249 		result = dns_master_loadbuffer(
250 			&source, &db->origin, &db->origin, db->rdclass,
251 			DNS_MASTER_HINT, &callbacks, db->mctx);
252 	} else {
253 		result = ISC_R_NOTFOUND;
254 	}
255 	eresult = dns_db_endload(db, &callbacks);
256 	if (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE) {
257 		result = eresult;
258 	}
259 	if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) {
260 		goto failure;
261 	}
262 	if (check_hints(db) != ISC_R_SUCCESS) {
263 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
264 			      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
265 			      "extra data in root hints '%s'",
266 			      (filename != NULL) ? filename : "<BUILT-IN>");
267 	}
268 	*target = db;
269 	return (ISC_R_SUCCESS);
270 
271 failure:
272 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_HINTS,
273 		      ISC_LOG_ERROR,
274 		      "could not configure root hints from "
275 		      "'%s': %s",
276 		      (filename != NULL) ? filename : "<BUILT-IN>",
277 		      isc_result_totext(result));
278 
279 	if (db != NULL) {
280 		dns_db_detach(&db);
281 	}
282 
283 	return (result);
284 }
285 
286 static void
287 report(dns_view_t *view, dns_name_t *name, bool missing, dns_rdata_t *rdata) {
288 	const char *viewname = "", *sep = "";
289 	char namebuf[DNS_NAME_FORMATSIZE];
290 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
291 	char databuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
292 	isc_buffer_t buffer;
293 	isc_result_t result;
294 
295 	if (strcmp(view->name, "_bind") != 0 &&
296 	    strcmp(view->name, "_default") != 0) {
297 		viewname = view->name;
298 		sep = ": view ";
299 	}
300 
301 	dns_name_format(name, namebuf, sizeof(namebuf));
302 	dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf));
303 	isc_buffer_init(&buffer, databuf, sizeof(databuf) - 1);
304 	result = dns_rdata_totext(rdata, NULL, &buffer);
305 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
306 	databuf[isc_buffer_usedlength(&buffer)] = '\0';
307 
308 	if (missing) {
309 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
310 			      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
311 			      "checkhints%s%s: %s/%s (%s) missing from hints",
312 			      sep, viewname, namebuf, typebuf, databuf);
313 	} else {
314 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
315 			      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
316 			      "checkhints%s%s: %s/%s (%s) extra record "
317 			      "in hints",
318 			      sep, viewname, namebuf, typebuf, databuf);
319 	}
320 }
321 
322 static bool
323 inrrset(dns_rdataset_t *rrset, dns_rdata_t *rdata) {
324 	isc_result_t result;
325 	dns_rdata_t current = DNS_RDATA_INIT;
326 
327 	result = dns_rdataset_first(rrset);
328 	while (result == ISC_R_SUCCESS) {
329 		dns_rdataset_current(rrset, &current);
330 		if (dns_rdata_compare(rdata, &current) == 0) {
331 			return (true);
332 		}
333 		dns_rdata_reset(&current);
334 		result = dns_rdataset_next(rrset);
335 	}
336 	return (false);
337 }
338 
339 /*
340  * Check that the address RRsets match.
341  *
342  * Note we don't complain about missing glue records.
343  */
344 
345 static void
346 check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db,
347 		      dns_name_t *name, isc_stdtime_t now) {
348 	isc_result_t hresult, rresult, result;
349 	dns_rdataset_t hintrrset, rootrrset;
350 	dns_rdata_t rdata = DNS_RDATA_INIT;
351 	dns_name_t *foundname;
352 	dns_fixedname_t fixed;
353 
354 	dns_rdataset_init(&hintrrset);
355 	dns_rdataset_init(&rootrrset);
356 	foundname = dns_fixedname_initname(&fixed);
357 
358 	hresult = dns_db_find(hints, name, NULL, dns_rdatatype_a, 0, now, NULL,
359 			      foundname, &hintrrset, NULL);
360 	rresult = dns_db_find(db, name, NULL, dns_rdatatype_a,
361 			      DNS_DBFIND_GLUEOK, now, NULL, foundname,
362 			      &rootrrset, NULL);
363 	if (hresult == ISC_R_SUCCESS &&
364 	    (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE))
365 	{
366 		result = dns_rdataset_first(&rootrrset);
367 		while (result == ISC_R_SUCCESS) {
368 			dns_rdata_reset(&rdata);
369 			dns_rdataset_current(&rootrrset, &rdata);
370 			if (!inrrset(&hintrrset, &rdata)) {
371 				report(view, name, true, &rdata);
372 			}
373 			result = dns_rdataset_next(&rootrrset);
374 		}
375 		result = dns_rdataset_first(&hintrrset);
376 		while (result == ISC_R_SUCCESS) {
377 			dns_rdata_reset(&rdata);
378 			dns_rdataset_current(&hintrrset, &rdata);
379 			if (!inrrset(&rootrrset, &rdata)) {
380 				report(view, name, false, &rdata);
381 			}
382 			result = dns_rdataset_next(&hintrrset);
383 		}
384 	}
385 	if (hresult == ISC_R_NOTFOUND &&
386 	    (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE))
387 	{
388 		result = dns_rdataset_first(&rootrrset);
389 		while (result == ISC_R_SUCCESS) {
390 			dns_rdata_reset(&rdata);
391 			dns_rdataset_current(&rootrrset, &rdata);
392 			report(view, name, true, &rdata);
393 			result = dns_rdataset_next(&rootrrset);
394 		}
395 	}
396 	if (dns_rdataset_isassociated(&rootrrset)) {
397 		dns_rdataset_disassociate(&rootrrset);
398 	}
399 	if (dns_rdataset_isassociated(&hintrrset)) {
400 		dns_rdataset_disassociate(&hintrrset);
401 	}
402 
403 	/*
404 	 * Check AAAA records.
405 	 */
406 	hresult = dns_db_find(hints, name, NULL, dns_rdatatype_aaaa, 0, now,
407 			      NULL, foundname, &hintrrset, NULL);
408 	rresult = dns_db_find(db, name, NULL, dns_rdatatype_aaaa,
409 			      DNS_DBFIND_GLUEOK, now, NULL, foundname,
410 			      &rootrrset, NULL);
411 	if (hresult == ISC_R_SUCCESS &&
412 	    (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE))
413 	{
414 		result = dns_rdataset_first(&rootrrset);
415 		while (result == ISC_R_SUCCESS) {
416 			dns_rdata_reset(&rdata);
417 			dns_rdataset_current(&rootrrset, &rdata);
418 			if (!inrrset(&hintrrset, &rdata)) {
419 				report(view, name, true, &rdata);
420 			}
421 			dns_rdata_reset(&rdata);
422 			result = dns_rdataset_next(&rootrrset);
423 		}
424 		result = dns_rdataset_first(&hintrrset);
425 		while (result == ISC_R_SUCCESS) {
426 			dns_rdata_reset(&rdata);
427 			dns_rdataset_current(&hintrrset, &rdata);
428 			if (!inrrset(&rootrrset, &rdata)) {
429 				report(view, name, false, &rdata);
430 			}
431 			dns_rdata_reset(&rdata);
432 			result = dns_rdataset_next(&hintrrset);
433 		}
434 	}
435 	if (hresult == ISC_R_NOTFOUND &&
436 	    (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE))
437 	{
438 		result = dns_rdataset_first(&rootrrset);
439 		while (result == ISC_R_SUCCESS) {
440 			dns_rdata_reset(&rdata);
441 			dns_rdataset_current(&rootrrset, &rdata);
442 			report(view, name, true, &rdata);
443 			dns_rdata_reset(&rdata);
444 			result = dns_rdataset_next(&rootrrset);
445 		}
446 	}
447 	if (dns_rdataset_isassociated(&rootrrset)) {
448 		dns_rdataset_disassociate(&rootrrset);
449 	}
450 	if (dns_rdataset_isassociated(&hintrrset)) {
451 		dns_rdataset_disassociate(&hintrrset);
452 	}
453 }
454 
455 void
456 dns_root_checkhints(dns_view_t *view, dns_db_t *hints, dns_db_t *db) {
457 	isc_result_t result;
458 	dns_rdata_t rdata = DNS_RDATA_INIT;
459 	dns_rdata_ns_t ns;
460 	dns_rdataset_t hintns, rootns;
461 	const char *viewname = "", *sep = "";
462 	isc_stdtime_t now;
463 	dns_name_t *name;
464 	dns_fixedname_t fixed;
465 
466 	REQUIRE(hints != NULL);
467 	REQUIRE(db != NULL);
468 	REQUIRE(view != NULL);
469 
470 	isc_stdtime_get(&now);
471 
472 	if (strcmp(view->name, "_bind") != 0 &&
473 	    strcmp(view->name, "_default") != 0) {
474 		viewname = view->name;
475 		sep = ": view ";
476 	}
477 
478 	dns_rdataset_init(&hintns);
479 	dns_rdataset_init(&rootns);
480 	name = dns_fixedname_initname(&fixed);
481 
482 	result = dns_db_find(hints, dns_rootname, NULL, dns_rdatatype_ns, 0,
483 			     now, NULL, name, &hintns, NULL);
484 	if (result != ISC_R_SUCCESS) {
485 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
486 			      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
487 			      "checkhints%s%s: unable to get root NS rrset "
488 			      "from hints: %s",
489 			      sep, viewname, dns_result_totext(result));
490 		goto cleanup;
491 	}
492 
493 	result = dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0, now,
494 			     NULL, name, &rootns, NULL);
495 	if (result != ISC_R_SUCCESS) {
496 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
497 			      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
498 			      "checkhints%s%s: unable to get root NS rrset "
499 			      "from cache: %s",
500 			      sep, viewname, dns_result_totext(result));
501 		goto cleanup;
502 	}
503 
504 	/*
505 	 * Look for missing root NS names.
506 	 */
507 	result = dns_rdataset_first(&rootns);
508 	while (result == ISC_R_SUCCESS) {
509 		dns_rdataset_current(&rootns, &rdata);
510 		result = dns_rdata_tostruct(&rdata, &ns, NULL);
511 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
512 		result = in_rootns(&hintns, &ns.name);
513 		if (result != ISC_R_SUCCESS) {
514 			char namebuf[DNS_NAME_FORMATSIZE];
515 			/* missing from hints */
516 			dns_name_format(&ns.name, namebuf, sizeof(namebuf));
517 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
518 				      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
519 				      "checkhints%s%s: unable to find root "
520 				      "NS '%s' in hints",
521 				      sep, viewname, namebuf);
522 		} else {
523 			check_address_records(view, hints, db, &ns.name, now);
524 		}
525 		dns_rdata_reset(&rdata);
526 		result = dns_rdataset_next(&rootns);
527 	}
528 	if (result != ISC_R_NOMORE) {
529 		goto cleanup;
530 	}
531 
532 	/*
533 	 * Look for extra root NS names.
534 	 */
535 	result = dns_rdataset_first(&hintns);
536 	while (result == ISC_R_SUCCESS) {
537 		dns_rdataset_current(&hintns, &rdata);
538 		result = dns_rdata_tostruct(&rdata, &ns, NULL);
539 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
540 		result = in_rootns(&rootns, &ns.name);
541 		if (result != ISC_R_SUCCESS) {
542 			char namebuf[DNS_NAME_FORMATSIZE];
543 			/* extra entry in hints */
544 			dns_name_format(&ns.name, namebuf, sizeof(namebuf));
545 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
546 				      DNS_LOGMODULE_HINTS, ISC_LOG_WARNING,
547 				      "checkhints%s%s: extra NS '%s' in hints",
548 				      sep, viewname, namebuf);
549 		}
550 		dns_rdata_reset(&rdata);
551 		result = dns_rdataset_next(&hintns);
552 	}
553 	if (result != ISC_R_NOMORE) {
554 		goto cleanup;
555 	}
556 
557 cleanup:
558 	if (dns_rdataset_isassociated(&rootns)) {
559 		dns_rdataset_disassociate(&rootns);
560 	}
561 	if (dns_rdataset_isassociated(&hintns)) {
562 		dns_rdataset_disassociate(&hintns);
563 	}
564 }
565