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, ¤t); 330 if (dns_rdata_compare(rdata, ¤t) == 0) { 331 return (true); 332 } 333 dns_rdata_reset(¤t); 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