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, ¤t); 352 1.4 christos if (dns_rdata_compare(rdata, ¤t) == 0) { 353 1.9 christos return true; 354 1.4 christos } 355 1.1 christos dns_rdata_reset(¤t); 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