1/* $NetBSD: rootns.c,v 1.2.6.1 2012/06/05 21:15:02 bouyer Exp $ */ 2 3/* 4 * Copyright (C) 2004, 2005, 2007, 2008, 2010 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2002 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20/* Id: rootns.c,v 1.40 2010/06/18 05:36:24 marka Exp */ 21 22/*! \file */ 23 24#include <config.h> 25 26#include <isc/buffer.h> 27#include <isc/string.h> /* Required for HP/UX (and others?) */ 28#include <isc/util.h> 29 30#include <dns/callbacks.h> 31#include <dns/db.h> 32#include <dns/dbiterator.h> 33#include <dns/fixedname.h> 34#include <dns/log.h> 35#include <dns/master.h> 36#include <dns/rdata.h> 37#include <dns/rdata.h> 38#include <dns/rdataset.h> 39#include <dns/rdatasetiter.h> 40#include <dns/rdatastruct.h> 41#include <dns/rdatatype.h> 42#include <dns/result.h> 43#include <dns/rootns.h> 44#include <dns/view.h> 45 46static char root_ns[] = 47";\n" 48"; Internet Root Nameservers\n" 49";\n" 50"$TTL 518400\n" 51". 518400 IN NS A.ROOT-SERVERS.NET.\n" 52". 518400 IN NS B.ROOT-SERVERS.NET.\n" 53". 518400 IN NS C.ROOT-SERVERS.NET.\n" 54". 518400 IN NS D.ROOT-SERVERS.NET.\n" 55". 518400 IN NS E.ROOT-SERVERS.NET.\n" 56". 518400 IN NS F.ROOT-SERVERS.NET.\n" 57". 518400 IN NS G.ROOT-SERVERS.NET.\n" 58". 518400 IN NS H.ROOT-SERVERS.NET.\n" 59". 518400 IN NS I.ROOT-SERVERS.NET.\n" 60". 518400 IN NS J.ROOT-SERVERS.NET.\n" 61". 518400 IN NS K.ROOT-SERVERS.NET.\n" 62". 518400 IN NS L.ROOT-SERVERS.NET.\n" 63". 518400 IN NS M.ROOT-SERVERS.NET.\n" 64"A.ROOT-SERVERS.NET. 3600000 IN A 198.41.0.4\n" 65"A.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:503:BA3E::2:30\n" 66"B.ROOT-SERVERS.NET. 3600000 IN A 192.228.79.201\n" 67"C.ROOT-SERVERS.NET. 3600000 IN A 192.33.4.12\n" 68"D.ROOT-SERVERS.NET. 3600000 IN A 128.8.10.90\n" 69"E.ROOT-SERVERS.NET. 3600000 IN A 192.203.230.10\n" 70"F.ROOT-SERVERS.NET. 3600000 IN A 192.5.5.241\n" 71"F.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:500:2F::F\n" 72"G.ROOT-SERVERS.NET. 3600000 IN A 192.112.36.4\n" 73"H.ROOT-SERVERS.NET. 3600000 IN A 128.63.2.53\n" 74"H.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:500:1::803F:235\n" 75"I.ROOT-SERVERS.NET. 3600000 IN A 192.36.148.17\n" 76"I.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:7fe::53\n" 77"J.ROOT-SERVERS.NET. 3600000 IN A 192.58.128.30\n" 78"J.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:503:C27::2:30\n" 79"K.ROOT-SERVERS.NET. 3600000 IN A 193.0.14.129\n" 80"K.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:7FD::1\n" 81"L.ROOT-SERVERS.NET. 3600000 IN A 199.7.83.42\n" 82"L.ROOT-SERVERS.NET. 604800 IN AAAA 2001:500:3::42\n" 83"M.ROOT-SERVERS.NET. 3600000 IN A 202.12.27.33\n" 84"M.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:DC3::35\n"; 85 86static isc_result_t 87in_rootns(dns_rdataset_t *rootns, dns_name_t *name) { 88 isc_result_t result; 89 dns_rdata_t rdata = DNS_RDATA_INIT; 90 dns_rdata_ns_t ns; 91 92 if (!dns_rdataset_isassociated(rootns)) 93 return (ISC_R_NOTFOUND); 94 95 result = dns_rdataset_first(rootns); 96 while (result == ISC_R_SUCCESS) { 97 dns_rdataset_current(rootns, &rdata); 98 result = dns_rdata_tostruct(&rdata, &ns, NULL); 99 if (result != ISC_R_SUCCESS) 100 return (result); 101 if (dns_name_compare(name, &ns.name) == 0) 102 return (ISC_R_SUCCESS); 103 result = dns_rdataset_next(rootns); 104 dns_rdata_reset(&rdata); 105 } 106 if (result == ISC_R_NOMORE) 107 result = ISC_R_NOTFOUND; 108 return (result); 109} 110 111static isc_result_t 112check_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 break; 128 case dns_rdatatype_ns: 129 if (dns_name_compare(name, dns_rootname) == 0) 130 break; 131 /*FALLTHROUGH*/ 132 default: 133 result = ISC_R_FAILURE; 134 goto cleanup; 135 } 136 dns_rdataset_disassociate(&rdataset); 137 result = dns_rdatasetiter_next(rdsiter); 138 } 139 if (result == ISC_R_NOMORE) 140 result = ISC_R_SUCCESS; 141 cleanup: 142 if (dns_rdataset_isassociated(&rdataset)) 143 dns_rdataset_disassociate(&rdataset); 144 return (result); 145} 146 147static isc_result_t 148check_hints(dns_db_t *db) { 149 isc_result_t result; 150 dns_rdataset_t rootns; 151 dns_dbiterator_t *dbiter = NULL; 152 dns_dbnode_t *node = NULL; 153 isc_stdtime_t now; 154 dns_fixedname_t fixname; 155 dns_name_t *name; 156 dns_rdatasetiter_t *rdsiter = NULL; 157 158 isc_stdtime_get(&now); 159 160 dns_fixedname_init(&fixname); 161 name = dns_fixedname_name(&fixname); 162 163 dns_rdataset_init(&rootns); 164 (void)dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0, 165 now, NULL, name, &rootns, NULL); 166 result = dns_db_createiterator(db, 0, &dbiter); 167 if (result != ISC_R_SUCCESS) 168 goto cleanup; 169 result = dns_dbiterator_first(dbiter); 170 while (result == ISC_R_SUCCESS) { 171 result = dns_dbiterator_current(dbiter, &node, name); 172 if (result != ISC_R_SUCCESS) 173 goto cleanup; 174 result = dns_db_allrdatasets(db, node, NULL, now, &rdsiter); 175 if (result != ISC_R_SUCCESS) 176 goto cleanup; 177 result = check_node(&rootns, name, rdsiter); 178 if (result != ISC_R_SUCCESS) 179 goto cleanup; 180 dns_rdatasetiter_destroy(&rdsiter); 181 dns_db_detachnode(db, &node); 182 result = dns_dbiterator_next(dbiter); 183 } 184 if (result == ISC_R_NOMORE) 185 result = ISC_R_SUCCESS; 186 187 cleanup: 188 if (dns_rdataset_isassociated(&rootns)) 189 dns_rdataset_disassociate(&rootns); 190 if (rdsiter != NULL) 191 dns_rdatasetiter_destroy(&rdsiter); 192 if (node != NULL) 193 dns_db_detachnode(db, &node); 194 if (dbiter != NULL) 195 dns_dbiterator_destroy(&dbiter); 196 return (result); 197} 198 199isc_result_t 200dns_rootns_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, 201 const char *filename, dns_db_t **target) 202{ 203 isc_result_t result, eresult; 204 isc_buffer_t source; 205 size_t len; 206 dns_rdatacallbacks_t callbacks; 207 dns_db_t *db = NULL; 208 209 REQUIRE(target != NULL && *target == NULL); 210 211 result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone, 212 rdclass, 0, NULL, &db); 213 if (result != ISC_R_SUCCESS) 214 return (result); 215 216 dns_rdatacallbacks_init(&callbacks); 217 218 len = strlen(root_ns); 219 isc_buffer_init(&source, root_ns, len); 220 isc_buffer_add(&source, len); 221 222 result = dns_db_beginload(db, &callbacks.add, 223 &callbacks.add_private); 224 if (result != ISC_R_SUCCESS) 225 return (result); 226 if (filename != NULL) { 227 /* 228 * Load the hints from the specified filename. 229 */ 230 result = dns_master_loadfile(filename, &db->origin, 231 &db->origin, db->rdclass, 232 DNS_MASTER_HINT, 233 &callbacks, db->mctx); 234 } else if (rdclass == dns_rdataclass_in) { 235 /* 236 * Default to using the Internet root servers. 237 */ 238 result = dns_master_loadbuffer(&source, &db->origin, 239 &db->origin, db->rdclass, 240 DNS_MASTER_HINT, 241 &callbacks, db->mctx); 242 } else 243 result = ISC_R_NOTFOUND; 244 eresult = dns_db_endload(db, &callbacks.add_private); 245 if (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE) 246 result = eresult; 247 if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) 248 goto db_detach; 249 if (check_hints(db) != ISC_R_SUCCESS) 250 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 251 DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, 252 "extra data in root hints '%s'", 253 (filename != NULL) ? filename : "<BUILT-IN>"); 254 *target = db; 255 return (ISC_R_SUCCESS); 256 257 db_detach: 258 dns_db_detach(&db); 259 260 return (result); 261} 262 263static void 264report(dns_view_t *view, dns_name_t *name, isc_boolean_t missing, 265 dns_rdata_t *rdata) 266{ 267 const char *viewname = "", *sep = ""; 268 char namebuf[DNS_NAME_FORMATSIZE]; 269 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 270 char databuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")]; 271 isc_buffer_t buffer; 272 isc_result_t result; 273 274 if (strcmp(view->name, "_bind") != 0 && 275 strcmp(view->name, "_default") != 0) { 276 viewname = view->name; 277 sep = ": view "; 278 } 279 280 dns_name_format(name, namebuf, sizeof(namebuf)); 281 dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf)); 282 isc_buffer_init(&buffer, databuf, sizeof(databuf) - 1); 283 result = dns_rdata_totext(rdata, NULL, &buffer); 284 RUNTIME_CHECK(result == ISC_R_SUCCESS); 285 databuf[isc_buffer_usedlength(&buffer)] = '\0'; 286 287 if (missing) 288 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 289 DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, 290 "checkhints%s%s: %s/%s (%s) missing from hints", 291 sep, viewname, namebuf, typebuf, databuf); 292 else 293 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 294 DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, 295 "checkhints%s%s: %s/%s (%s) extra record " 296 "in hints", sep, viewname, namebuf, typebuf, 297 databuf); 298} 299 300static isc_boolean_t 301inrrset(dns_rdataset_t *rrset, dns_rdata_t *rdata) { 302 isc_result_t result; 303 dns_rdata_t current = DNS_RDATA_INIT; 304 305 result = dns_rdataset_first(rrset); 306 while (result == ISC_R_SUCCESS) { 307 dns_rdataset_current(rrset, ¤t); 308 if (dns_rdata_compare(rdata, ¤t) == 0) 309 return (ISC_TRUE); 310 dns_rdata_reset(¤t); 311 result = dns_rdataset_next(rrset); 312 } 313 return (ISC_FALSE); 314} 315 316/* 317 * Check that the address RRsets match. 318 * 319 * Note we don't complain about missing glue records. 320 */ 321 322static void 323check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db, 324 dns_name_t *name, isc_stdtime_t now) 325{ 326 isc_result_t hresult, rresult, result; 327 dns_rdataset_t hintrrset, rootrrset; 328 dns_rdata_t rdata = DNS_RDATA_INIT; 329 dns_name_t *foundname; 330 dns_fixedname_t fixed; 331 332 dns_rdataset_init(&hintrrset); 333 dns_rdataset_init(&rootrrset); 334 dns_fixedname_init(&fixed); 335 foundname = dns_fixedname_name(&fixed); 336 337 hresult = dns_db_find(hints, name, NULL, dns_rdatatype_a, 0, 338 now, NULL, foundname, &hintrrset, NULL); 339 rresult = dns_db_find(db, name, NULL, dns_rdatatype_a, 340 DNS_DBFIND_GLUEOK, now, NULL, foundname, 341 &rootrrset, NULL); 342 if (hresult == ISC_R_SUCCESS && 343 (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) { 344 result = dns_rdataset_first(&rootrrset); 345 while (result == ISC_R_SUCCESS) { 346 dns_rdata_reset(&rdata); 347 dns_rdataset_current(&rootrrset, &rdata); 348 if (!inrrset(&hintrrset, &rdata)) 349 report(view, name, ISC_TRUE, &rdata); 350 result = dns_rdataset_next(&rootrrset); 351 } 352 result = dns_rdataset_first(&hintrrset); 353 while (result == ISC_R_SUCCESS) { 354 dns_rdata_reset(&rdata); 355 dns_rdataset_current(&hintrrset, &rdata); 356 if (!inrrset(&rootrrset, &rdata)) 357 report(view, name, ISC_FALSE, &rdata); 358 result = dns_rdataset_next(&hintrrset); 359 } 360 } 361 if (hresult == ISC_R_NOTFOUND && 362 (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) { 363 result = dns_rdataset_first(&rootrrset); 364 while (result == ISC_R_SUCCESS) { 365 dns_rdata_reset(&rdata); 366 dns_rdataset_current(&rootrrset, &rdata); 367 report(view, name, ISC_TRUE, &rdata); 368 result = dns_rdataset_next(&rootrrset); 369 } 370 } 371 if (dns_rdataset_isassociated(&rootrrset)) 372 dns_rdataset_disassociate(&rootrrset); 373 if (dns_rdataset_isassociated(&hintrrset)) 374 dns_rdataset_disassociate(&hintrrset); 375 376 /* 377 * Check AAAA records. 378 */ 379 hresult = dns_db_find(hints, name, NULL, dns_rdatatype_aaaa, 0, 380 now, NULL, foundname, &hintrrset, NULL); 381 rresult = dns_db_find(db, name, NULL, dns_rdatatype_aaaa, 382 DNS_DBFIND_GLUEOK, now, NULL, foundname, 383 &rootrrset, NULL); 384 if (hresult == ISC_R_SUCCESS && 385 (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) { 386 result = dns_rdataset_first(&rootrrset); 387 while (result == ISC_R_SUCCESS) { 388 dns_rdata_reset(&rdata); 389 dns_rdataset_current(&rootrrset, &rdata); 390 if (!inrrset(&hintrrset, &rdata)) 391 report(view, name, ISC_TRUE, &rdata); 392 dns_rdata_reset(&rdata); 393 result = dns_rdataset_next(&rootrrset); 394 } 395 result = dns_rdataset_first(&hintrrset); 396 while (result == ISC_R_SUCCESS) { 397 dns_rdata_reset(&rdata); 398 dns_rdataset_current(&hintrrset, &rdata); 399 if (!inrrset(&rootrrset, &rdata)) 400 report(view, name, ISC_FALSE, &rdata); 401 dns_rdata_reset(&rdata); 402 result = dns_rdataset_next(&hintrrset); 403 } 404 } 405 if (hresult == ISC_R_NOTFOUND && 406 (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) { 407 result = dns_rdataset_first(&rootrrset); 408 while (result == ISC_R_SUCCESS) { 409 dns_rdata_reset(&rdata); 410 dns_rdataset_current(&rootrrset, &rdata); 411 report(view, name, ISC_TRUE, &rdata); 412 dns_rdata_reset(&rdata); 413 result = dns_rdataset_next(&rootrrset); 414 } 415 } 416 if (dns_rdataset_isassociated(&rootrrset)) 417 dns_rdataset_disassociate(&rootrrset); 418 if (dns_rdataset_isassociated(&hintrrset)) 419 dns_rdataset_disassociate(&hintrrset); 420} 421 422void 423dns_root_checkhints(dns_view_t *view, dns_db_t *hints, dns_db_t *db) { 424 isc_result_t result; 425 dns_rdata_t rdata = DNS_RDATA_INIT; 426 dns_rdata_ns_t ns; 427 dns_rdataset_t hintns, rootns; 428 const char *viewname = "", *sep = ""; 429 isc_stdtime_t now; 430 dns_name_t *name; 431 dns_fixedname_t fixed; 432 433 REQUIRE(hints != NULL); 434 REQUIRE(db != NULL); 435 REQUIRE(view != NULL); 436 437 isc_stdtime_get(&now); 438 439 if (strcmp(view->name, "_bind") != 0 && 440 strcmp(view->name, "_default") != 0) { 441 viewname = view->name; 442 sep = ": view "; 443 } 444 445 dns_rdataset_init(&hintns); 446 dns_rdataset_init(&rootns); 447 dns_fixedname_init(&fixed); 448 name = dns_fixedname_name(&fixed); 449 450 result = dns_db_find(hints, dns_rootname, NULL, dns_rdatatype_ns, 0, 451 now, NULL, name, &hintns, NULL); 452 if (result != ISC_R_SUCCESS) { 453 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 454 DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, 455 "checkhints%s%s: unable to get root NS rrset " 456 "from hints: %s", sep, viewname, 457 dns_result_totext(result)); 458 goto cleanup; 459 } 460 461 result = dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0, 462 now, NULL, name, &rootns, NULL); 463 if (result != ISC_R_SUCCESS) { 464 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 465 DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, 466 "checkhints%s%s: unable to get root NS rrset " 467 "from cache: %s", sep, viewname, 468 dns_result_totext(result)); 469 goto cleanup; 470 } 471 472 /* 473 * Look for missing root NS names. 474 */ 475 result = dns_rdataset_first(&rootns); 476 while (result == ISC_R_SUCCESS) { 477 dns_rdataset_current(&rootns, &rdata); 478 result = dns_rdata_tostruct(&rdata, &ns, NULL); 479 RUNTIME_CHECK(result == ISC_R_SUCCESS); 480 result = in_rootns(&hintns, &ns.name); 481 if (result != ISC_R_SUCCESS) { 482 char namebuf[DNS_NAME_FORMATSIZE]; 483 /* missing from hints */ 484 dns_name_format(&ns.name, namebuf, sizeof(namebuf)); 485 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 486 DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, 487 "checkhints%s%s: unable to find root " 488 "NS '%s' in hints", sep, viewname, 489 namebuf); 490 } else 491 check_address_records(view, hints, db, &ns.name, now); 492 dns_rdata_reset(&rdata); 493 result = dns_rdataset_next(&rootns); 494 } 495 if (result != ISC_R_NOMORE) { 496 goto cleanup; 497 } 498 499 /* 500 * Look for extra root NS names. 501 */ 502 result = dns_rdataset_first(&hintns); 503 while (result == ISC_R_SUCCESS) { 504 dns_rdataset_current(&hintns, &rdata); 505 result = dns_rdata_tostruct(&rdata, &ns, NULL); 506 RUNTIME_CHECK(result == ISC_R_SUCCESS); 507 result = in_rootns(&rootns, &ns.name); 508 if (result != ISC_R_SUCCESS) { 509 char namebuf[DNS_NAME_FORMATSIZE]; 510 /* extra entry in hints */ 511 dns_name_format(&ns.name, namebuf, sizeof(namebuf)); 512 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 513 DNS_LOGMODULE_HINTS, ISC_LOG_WARNING, 514 "checkhints%s%s: extra NS '%s' in hints", 515 sep, viewname, namebuf); 516 } 517 dns_rdata_reset(&rdata); 518 result = dns_rdataset_next(&hintns); 519 } 520 if (result != ISC_R_NOMORE) { 521 goto cleanup; 522 } 523 524 cleanup: 525 if (dns_rdataset_isassociated(&rootns)) 526 dns_rdataset_disassociate(&rootns); 527 if (dns_rdataset_isassociated(&hintns)) 528 dns_rdataset_disassociate(&hintns); 529} 530