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