1 /* $NetBSD: builtin.c,v 1.8 2025/01/26 16:24:33 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file 17 * \brief 18 * The built-in "version", "hostname", "id", "authors" and "empty" databases. 19 */ 20 21 #include <stdio.h> 22 #include <string.h> 23 24 #include <isc/lex.h> 25 #include <isc/mem.h> 26 #include <isc/result.h> 27 #include <isc/util.h> 28 29 #include <dns/callbacks.h> 30 #include <dns/dbiterator.h> 31 #include <dns/rdatalist.h> 32 #include <dns/rdatasetiter.h> 33 #include <dns/types.h> 34 35 #include <named/builtin.h> 36 #include <named/globals.h> 37 #include <named/os.h> 38 #include <named/server.h> 39 40 #define BDBNODE_MAGIC ISC_MAGIC('B', 'D', 'B', 'N') 41 #define VALID_BDBNODE(bdbl) ISC_MAGIC_VALID(bdbl, BDBNODE_MAGIC) 42 43 /*% 44 * Note that "impmagic" is not the first four bytes of the struct, so 45 * ISC_MAGIC_VALID cannot be used here. 46 */ 47 #define BDB_MAGIC ISC_MAGIC('B', 'D', 'B', '-') 48 #define VALID_BDB(bdb) ((bdb) != NULL && (bdb)->common.impmagic == BDB_MAGIC) 49 50 #define BDB_DNS64 0x00000001U 51 52 typedef struct bdbimplementation { 53 unsigned int flags; 54 dns_dbimplementation_t *dbimp; 55 } bdbimplementation_t; 56 57 typedef struct bdbnode bdbnode_t; 58 typedef struct bdb { 59 dns_db_t common; 60 bdbimplementation_t *implementation; 61 isc_result_t (*lookup)(bdbnode_t *node); 62 char *server; 63 char *contact; 64 } bdb_t; 65 66 struct bdbnode { 67 unsigned int magic; 68 isc_refcount_t references; 69 bdb_t *bdb; 70 ISC_LIST(dns_rdatalist_t) lists; 71 ISC_LIST(isc_buffer_t) buffers; 72 dns_name_t *name; 73 ISC_LINK(bdbnode_t) link; 74 dns_rdatacallbacks_t callbacks; 75 }; 76 77 typedef struct bdb_rdatasetiter { 78 dns_rdatasetiter_t common; 79 dns_rdatalist_t *current; 80 } bdb_rdatasetiter_t; 81 82 static isc_result_t 83 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 84 dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now, 85 dns_rdataset_t *rdataset, 86 dns_rdataset_t *sigrdataset DNS__DB_FLARG); 87 88 static void 89 attachnode(dns_db_t *db, dns_dbnode_t *source, 90 dns_dbnode_t **targetp DNS__DB_FLARG); 91 92 static void 93 detachnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG); 94 95 /* 96 * Helper functions to convert text to wire forma. 97 */ 98 static isc_result_t 99 putrdata(bdbnode_t *node, dns_rdatatype_t typeval, dns_ttl_t ttl, 100 const unsigned char *rdatap, unsigned int rdlen) { 101 dns_rdatalist_t *rdatalist = NULL; 102 dns_rdata_t *rdata = NULL; 103 isc_buffer_t *rdatabuf = NULL; 104 isc_mem_t *mctx = NULL; 105 isc_region_t region; 106 107 mctx = node->bdb->common.mctx; 108 109 rdatalist = ISC_LIST_HEAD(node->lists); 110 while (rdatalist != NULL) { 111 if (rdatalist->type == typeval) { 112 break; 113 } 114 rdatalist = ISC_LIST_NEXT(rdatalist, link); 115 } 116 117 if (rdatalist == NULL) { 118 rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t)); 119 dns_rdatalist_init(rdatalist); 120 rdatalist->rdclass = node->bdb->common.rdclass; 121 rdatalist->type = typeval; 122 rdatalist->ttl = ttl; 123 ISC_LIST_APPEND(node->lists, rdatalist, link); 124 } else if (rdatalist->ttl != ttl) { 125 return DNS_R_BADTTL; 126 } 127 128 rdata = isc_mem_get(mctx, sizeof(dns_rdata_t)); 129 130 isc_buffer_allocate(mctx, &rdatabuf, rdlen); 131 region.base = UNCONST(rdatap); 132 region.length = rdlen; 133 isc_buffer_copyregion(rdatabuf, ®ion); 134 isc_buffer_usedregion(rdatabuf, ®ion); 135 dns_rdata_init(rdata); 136 dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type, 137 ®ion); 138 ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 139 ISC_LIST_APPEND(node->buffers, rdatabuf, link); 140 141 return ISC_R_SUCCESS; 142 } 143 144 static isc_result_t 145 putrr(bdbnode_t *node, const char *type, dns_ttl_t ttl, const char *data) { 146 isc_result_t result; 147 dns_rdatatype_t typeval; 148 isc_lex_t *lex = NULL; 149 isc_mem_t *mctx = NULL; 150 const dns_name_t *origin = NULL; 151 isc_buffer_t *rb = NULL; 152 isc_buffer_t b; 153 154 REQUIRE(VALID_BDBNODE(node)); 155 REQUIRE(type != NULL); 156 REQUIRE(data != NULL); 157 158 mctx = node->bdb->common.mctx; 159 origin = &node->bdb->common.origin; 160 161 isc_constregion_t r = { .base = type, .length = strlen(type) }; 162 result = dns_rdatatype_fromtext(&typeval, (isc_textregion_t *)&r); 163 if (result != ISC_R_SUCCESS) { 164 return result; 165 } 166 167 isc_lex_create(mctx, 64, &lex); 168 169 size_t datalen = strlen(data); 170 isc_buffer_constinit(&b, data, datalen); 171 isc_buffer_add(&b, datalen); 172 173 result = isc_lex_openbuffer(lex, &b); 174 if (result != ISC_R_SUCCESS) { 175 return result; 176 } 177 178 isc_buffer_allocate(mctx, &rb, DNS_RDATA_MAXLENGTH); 179 result = dns_rdata_fromtext(NULL, node->bdb->common.rdclass, typeval, 180 lex, origin, 0, mctx, rb, &node->callbacks); 181 isc_lex_destroy(&lex); 182 183 if (result == ISC_R_SUCCESS) { 184 result = putrdata(node, typeval, ttl, isc_buffer_base(rb), 185 isc_buffer_usedlength(rb)); 186 } 187 188 isc_buffer_free(&rb); 189 190 return result; 191 } 192 193 /* Reasonable default SOA values */ 194 #define DEFAULT_REFRESH 28800U /* 8 hours */ 195 #define DEFAULT_RETRY 7200U /* 2 hours */ 196 #define DEFAULT_EXPIRE 604800U /* 7 days */ 197 #define DEFAULT_MINIMUM 86400U /* 1 day */ 198 #define DEFAULT_TTL (60 * 60 * 24) 199 200 static isc_result_t 201 putsoa(bdbnode_t *node, const char *mname, const char *rname, uint32_t serial) { 202 char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7]; 203 int n; 204 205 REQUIRE(mname != NULL); 206 REQUIRE(rname != NULL); 207 208 n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u", mname, rname, 209 serial, DEFAULT_REFRESH, DEFAULT_RETRY, DEFAULT_EXPIRE, 210 DEFAULT_MINIMUM); 211 if (n >= (int)sizeof(str) || n < 0) { 212 return ISC_R_NOSPACE; 213 } 214 return putrr(node, "SOA", DEFAULT_TTL, str); 215 } 216 217 static isc_result_t 218 puttxt(bdbnode_t *node, const char *text) { 219 unsigned char buf[256]; 220 unsigned int len = strlen(text); 221 222 if (len > 255) { 223 len = 255; /* Silently truncate */ 224 } 225 buf[0] = len; 226 memmove(&buf[1], text, len); 227 return putrdata(node, dns_rdatatype_txt, 0, buf, len + 1); 228 } 229 230 /* 231 * Builtin database implementation functions. 232 */ 233 234 /* Precomputed HEX * 16 or 1 table. */ 235 static const unsigned char hex16[256] = { 236 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*00*/ 237 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 238 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*20*/ 239 0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 1, 1, 1, 1, 1, 1, /*30*/ 240 1, 160, 176, 192, 208, 224, 240, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ 241 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*50*/ 242 1, 160, 176, 192, 208, 224, 240, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*60*/ 243 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ 244 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ 245 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ 246 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*A0*/ 247 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*B0*/ 248 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*C0*/ 249 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*D0*/ 250 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*E0*/ 251 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /*F0*/ 252 }; 253 254 static const unsigned char decimal[] = "0123456789"; 255 static const unsigned char ipv4only[] = "\010ipv4only\004arpa"; 256 257 static size_t 258 dns64_rdata(unsigned char *v, size_t start, unsigned char *rdata) { 259 size_t i, j = 0; 260 261 for (i = 0; i < 4U; i++) { 262 unsigned char c = v[start++]; 263 if (start == 7U) { 264 start++; 265 } 266 if (c > 99) { 267 rdata[j++] = 3; 268 rdata[j++] = decimal[c / 100]; 269 c = c % 100; 270 rdata[j++] = decimal[c / 10]; 271 c = c % 10; 272 rdata[j++] = decimal[c]; 273 } else if (c > 9) { 274 rdata[j++] = 2; 275 rdata[j++] = decimal[c / 10]; 276 c = c % 10; 277 rdata[j++] = decimal[c]; 278 } else { 279 rdata[j++] = 1; 280 rdata[j++] = decimal[c]; 281 } 282 } 283 memmove(&rdata[j], "\07in-addr\04arpa", 14); 284 return j + 14; 285 } 286 287 static isc_result_t 288 dns64_cname(const dns_name_t *zone, const dns_name_t *name, bdbnode_t *node) { 289 size_t zlen, nlen, j, len; 290 unsigned char v[16], n; 291 unsigned int i; 292 unsigned char rdata[sizeof("123.123.123.123.in-addr.arpa.")]; 293 unsigned char *ndata; 294 295 /* 296 * The combined length of the zone and name is 74. 297 * 298 * The minimum zone length is 10 ((3)ip6(4)arpa(0)). 299 * 300 * The length of name should always be even as we are expecting 301 * a series of nibbles. 302 */ 303 zlen = zone->length; 304 nlen = name->length; 305 if ((zlen + nlen) > 74U || zlen < 10U || (nlen % 2) != 0U) { 306 return ISC_R_NOTFOUND; 307 } 308 309 /* 310 * Check that name is a series of nibbles. 311 * Compute the byte values that correspond to the nibbles as we go. 312 * 313 * Shift the final result 4 bits, by setting 'i' to 1, if we if we 314 * have a odd number of nibbles so that "must be zero" tests below 315 * are byte aligned and we correctly return ISC_R_NOTFOUND or 316 * ISC_R_SUCCESS. We will not generate a CNAME in this case. 317 */ 318 ndata = name->ndata; 319 i = (nlen % 4) == 2U ? 1 : 0; 320 j = nlen; 321 memset(v, 0, sizeof(v)); 322 while (j != 0U) { 323 INSIST((i / 2) < sizeof(v)); 324 if (ndata[0] != 1) { 325 return ISC_R_NOTFOUND; 326 } 327 n = hex16[ndata[1] & 0xff]; 328 if (n == 1) { 329 return ISC_R_NOTFOUND; 330 } 331 v[i / 2] = n | (v[i / 2] >> 4); 332 j -= 2; 333 ndata += 2; 334 i++; 335 } 336 337 /* 338 * If we get here then we know name only consisted of nibbles. 339 * Now we need to determine if the name exists or not and whether 340 * it corresponds to a empty node in the zone or there should be 341 * a CNAME. 342 */ 343 #define ZLEN(x) (10 + (x) / 2) 344 switch (zlen) { 345 case ZLEN(32): /* prefix len 32 */ 346 /* 347 * The nibbles that map to this byte must be zero for 'name' 348 * to exist in the zone. 349 */ 350 if (nlen > 16U && v[(nlen - 1) / 4 - 4] != 0) { 351 return ISC_R_NOTFOUND; 352 } 353 /* 354 * If the total length is not 74 then this is a empty node 355 * so return success. 356 */ 357 if (nlen + zlen != 74U) { 358 return ISC_R_SUCCESS; 359 } 360 len = dns64_rdata(v, 8, rdata); 361 break; 362 case ZLEN(40): /* prefix len 40 */ 363 /* 364 * The nibbles that map to this byte must be zero for 'name' 365 * to exist in the zone. 366 */ 367 if (nlen > 12U && v[(nlen - 1) / 4 - 3] != 0) { 368 return ISC_R_NOTFOUND; 369 } 370 /* 371 * If the total length is not 74 then this is a empty node 372 * so return success. 373 */ 374 if (nlen + zlen != 74U) { 375 return ISC_R_SUCCESS; 376 } 377 len = dns64_rdata(v, 6, rdata); 378 break; 379 case ZLEN(48): /* prefix len 48 */ 380 /* 381 * The nibbles that map to this byte must be zero for 'name' 382 * to exist in the zone. 383 */ 384 if (nlen > 8U && v[(nlen - 1) / 4 - 2] != 0) { 385 return ISC_R_NOTFOUND; 386 } 387 /* 388 * If the total length is not 74 then this is a empty node 389 * so return success. 390 */ 391 if (nlen + zlen != 74U) { 392 return ISC_R_SUCCESS; 393 } 394 len = dns64_rdata(v, 5, rdata); 395 break; 396 case ZLEN(56): /* prefix len 56 */ 397 /* 398 * The nibbles that map to this byte must be zero for 'name' 399 * to exist in the zone. 400 */ 401 if (nlen > 4U && v[(nlen - 1) / 4 - 1] != 0) { 402 return ISC_R_NOTFOUND; 403 } 404 /* 405 * If the total length is not 74 then this is a empty node 406 * so return success. 407 */ 408 if (nlen + zlen != 74U) { 409 return ISC_R_SUCCESS; 410 } 411 len = dns64_rdata(v, 4, rdata); 412 break; 413 case ZLEN(64): /* prefix len 64 */ 414 /* 415 * The nibbles that map to this byte must be zero for 'name' 416 * to exist in the zone. 417 */ 418 if (v[(nlen - 1) / 4] != 0) { 419 return ISC_R_NOTFOUND; 420 } 421 /* 422 * If the total length is not 74 then this is a empty node 423 * so return success. 424 */ 425 if (nlen + zlen != 74U) { 426 return ISC_R_SUCCESS; 427 } 428 len = dns64_rdata(v, 3, rdata); 429 break; 430 case ZLEN(96): /* prefix len 96 */ 431 /* 432 * If the total length is not 74 then this is a empty node 433 * so return success. 434 */ 435 if (nlen + zlen != 74U) { 436 return ISC_R_SUCCESS; 437 } 438 len = dns64_rdata(v, 0, rdata); 439 break; 440 default: 441 /* 442 * This should never be reached unless someone adds a 443 * zone declaration with this internal type to named.conf. 444 */ 445 return ISC_R_NOTFOUND; 446 } 447 448 /* 449 * Reverse of 192.0.0.170 or 192.0.0.171 maps to ipv4only.arpa. 450 */ 451 if ((v[0] == 170 || v[0] == 171) && v[1] == 0 && v[2] == 0 && 452 v[3] == 192) 453 { 454 return putrdata(node, dns_rdatatype_ptr, 3600, ipv4only, 455 sizeof(ipv4only)); 456 } 457 458 return putrdata(node, dns_rdatatype_cname, 600, rdata, 459 (unsigned int)len); 460 } 461 462 static isc_result_t 463 builtin_lookup(bdb_t *bdb, const dns_name_t *name, bdbnode_t *node) { 464 if (name->labels == 0 && name->length == 0) { 465 return bdb->lookup(node); 466 } else if ((node->bdb->implementation->flags & BDB_DNS64) != 0) { 467 return dns64_cname(&bdb->common.origin, name, node); 468 } else { 469 return ISC_R_NOTFOUND; 470 } 471 } 472 473 static isc_result_t 474 builtin_authority(bdb_t *bdb, bdbnode_t *node) { 475 isc_result_t result; 476 const char *contact = "hostmaster"; 477 const char *server = "@"; 478 479 if (bdb->server != NULL) { 480 server = bdb->server; 481 } 482 if (bdb->contact != NULL) { 483 contact = bdb->contact; 484 } 485 486 result = putsoa(node, server, contact, 0); 487 if (result != ISC_R_SUCCESS) { 488 return ISC_R_FAILURE; 489 } 490 491 result = putrr(node, "NS", 0, server); 492 if (result != ISC_R_SUCCESS) { 493 return ISC_R_FAILURE; 494 } 495 496 return ISC_R_SUCCESS; 497 } 498 499 static isc_result_t 500 version_lookup(bdbnode_t *node) { 501 if (named_g_server->version_set) { 502 if (named_g_server->version == NULL) { 503 return ISC_R_SUCCESS; 504 } else { 505 return puttxt(node, named_g_server->version); 506 } 507 } else { 508 return puttxt(node, PACKAGE_VERSION); 509 } 510 } 511 512 static isc_result_t 513 hostname_lookup(bdbnode_t *node) { 514 if (named_g_server->hostname_set) { 515 if (named_g_server->hostname == NULL) { 516 return ISC_R_SUCCESS; 517 } else { 518 return puttxt(node, named_g_server->hostname); 519 } 520 } else { 521 char buf[256]; 522 if (gethostname(buf, sizeof(buf)) != 0) { 523 return ISC_R_FAILURE; 524 } 525 return puttxt(node, buf); 526 } 527 } 528 529 static isc_result_t 530 authors_lookup(bdbnode_t *node) { 531 isc_result_t result; 532 const char **p = NULL; 533 static const char *authors[] = { 534 "Mark Andrews", "Curtis Blackburn", 535 "James Brister", "Ben Cottrell", 536 "John H. DuBois III", "Francis Dupont", 537 "Michael Graff", "Andreas Gustafsson", 538 "Bob Halley", "Evan Hunt", 539 "JINMEI Tatuya", "Witold Krecicki", 540 "David Lawrence", "Scott Mann", 541 "Danny Mayer", "Aydin Mercan", 542 "Damien Neil", "Matt Nelson", 543 "Jeremy C. Reed", "Michael Sawyer", 544 "Brian Wellington", NULL 545 }; 546 547 /* 548 * If a version string is specified, disable the authors.bind zone. 549 */ 550 if (named_g_server->version_set) { 551 return ISC_R_SUCCESS; 552 } 553 554 for (p = authors; *p != NULL; p++) { 555 result = puttxt(node, *p); 556 if (result != ISC_R_SUCCESS) { 557 return result; 558 } 559 } 560 return ISC_R_SUCCESS; 561 } 562 563 static isc_result_t 564 id_lookup(bdbnode_t *node) { 565 if (named_g_server->sctx->usehostname) { 566 char buf[256]; 567 if (gethostname(buf, sizeof(buf)) != 0) { 568 return ISC_R_FAILURE; 569 } 570 return puttxt(node, buf); 571 } else if (named_g_server->sctx->server_id != NULL) { 572 return puttxt(node, named_g_server->sctx->server_id); 573 } else { 574 return ISC_R_SUCCESS; 575 } 576 } 577 578 static isc_result_t 579 empty_lookup(bdbnode_t *node) { 580 UNUSED(node); 581 582 return ISC_R_SUCCESS; 583 } 584 585 static isc_result_t 586 ipv4only_lookup(bdbnode_t *node) { 587 isc_result_t result; 588 unsigned char data[2][4] = { { 192, 0, 0, 170 }, { 192, 0, 0, 171 } }; 589 590 for (int i = 0; i < 2; i++) { 591 result = putrdata(node, dns_rdatatype_a, 3600, data[i], 4); 592 if (result != ISC_R_SUCCESS) { 593 return result; 594 } 595 } 596 return ISC_R_SUCCESS; 597 } 598 599 static isc_result_t 600 ipv4reverse_lookup(bdbnode_t *node) { 601 isc_result_t result; 602 603 result = putrdata(node, dns_rdatatype_ptr, 3600, ipv4only, 604 sizeof(ipv4only)); 605 return result; 606 } 607 608 /* 609 * Rdataset implementation methods. An rdataset in the builtin databases is 610 * implemented as an rdatalist which holds a reference to the dbnode, 611 * to prevent the node being freed while the rdataset is still in use, so 612 * we need local implementations of clone and disassociate but the rest of 613 * the implementation can be the same as dns_rdatalist.. 614 */ 615 static void 616 disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) { 617 dns_dbnode_t *node = rdataset->rdlist.node; 618 bdbnode_t *bdbnode = (bdbnode_t *)node; 619 dns_db_t *db = (dns_db_t *)bdbnode->bdb; 620 621 detachnode(db, &node DNS__DB_FLARG_PASS); 622 dns_rdatalist_disassociate(rdataset DNS__DB_FLARG_PASS); 623 } 624 625 static void 626 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) { 627 dns_dbnode_t *node = source->rdlist.node; 628 bdbnode_t *bdbnode = (bdbnode_t *)node; 629 dns_db_t *db = (dns_db_t *)bdbnode->bdb; 630 631 dns_rdatalist_clone(source, target DNS__DB_FLARG_PASS); 632 attachnode(db, node, &target->rdlist.node DNS__DB_FLARG_PASS); 633 } 634 635 static dns_rdatasetmethods_t bdb_rdataset_methods = { 636 .disassociate = disassociate, 637 .first = dns_rdatalist_first, 638 .next = dns_rdatalist_next, 639 .current = dns_rdatalist_current, 640 .clone = rdataset_clone, 641 .count = dns_rdatalist_count, 642 .addnoqname = dns_rdatalist_addnoqname, 643 .getnoqname = dns_rdatalist_getnoqname, 644 }; 645 646 static void 647 new_rdataset(dns_rdatalist_t *rdatalist, dns_db_t *db, dns_dbnode_t *node, 648 dns_rdataset_t *rdataset) { 649 dns_rdatalist_tordataset(rdatalist, rdataset); 650 651 rdataset->methods = &bdb_rdataset_methods; 652 dns_db_attachnode(db, node, &rdataset->rdlist.node); 653 } 654 655 /* 656 * Rdataset iterator methods 657 */ 658 659 static void 660 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { 661 bdb_rdatasetiter_t *bdbiterator = (bdb_rdatasetiter_t *)(*iteratorp); 662 detachnode(bdbiterator->common.db, 663 &bdbiterator->common.node DNS__DB_FLARG_PASS); 664 isc_mem_put(bdbiterator->common.db->mctx, bdbiterator, 665 sizeof(bdb_rdatasetiter_t)); 666 *iteratorp = NULL; 667 } 668 669 static isc_result_t 670 rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { 671 bdb_rdatasetiter_t *bdbiterator = (bdb_rdatasetiter_t *)iterator; 672 bdbnode_t *bdbnode = (bdbnode_t *)iterator->node; 673 674 if (ISC_LIST_EMPTY(bdbnode->lists)) { 675 return ISC_R_NOMORE; 676 } 677 bdbiterator->current = ISC_LIST_HEAD(bdbnode->lists); 678 return ISC_R_SUCCESS; 679 } 680 681 static isc_result_t 682 rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { 683 bdb_rdatasetiter_t *bdbiterator = (bdb_rdatasetiter_t *)iterator; 684 685 bdbiterator->current = ISC_LIST_NEXT(bdbiterator->current, link); 686 if (bdbiterator->current == NULL) { 687 return ISC_R_NOMORE; 688 } else { 689 return ISC_R_SUCCESS; 690 } 691 } 692 693 static void 694 rdatasetiter_current(dns_rdatasetiter_t *iterator, 695 dns_rdataset_t *rdataset DNS__DB_FLARG) { 696 bdb_rdatasetiter_t *bdbiterator = (bdb_rdatasetiter_t *)iterator; 697 698 new_rdataset(bdbiterator->current, iterator->db, iterator->node, 699 rdataset); 700 } 701 702 static dns_rdatasetitermethods_t rdatasetiter_methods = { 703 rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next, 704 rdatasetiter_current 705 }; 706 707 /* 708 * Database implementation methods 709 */ 710 static void 711 destroy(dns_db_t *db) { 712 bdb_t *bdb = (bdb_t *)db; 713 isc_refcount_destroy(&bdb->common.references); 714 715 if (bdb->server != NULL) { 716 isc_mem_free(named_g_mctx, bdb->server); 717 } 718 if (bdb->contact != NULL) { 719 isc_mem_free(named_g_mctx, bdb->contact); 720 } 721 722 bdb->common.magic = 0; 723 bdb->common.impmagic = 0; 724 725 dns_name_free(&bdb->common.origin, bdb->common.mctx); 726 727 isc_mem_putanddetach(&bdb->common.mctx, bdb, sizeof(bdb_t)); 728 } 729 730 /* 731 * A dummy 'version' value is used so that dns_db_createversion() 732 * can return a non-NULL version to the caller, but there can only be 733 * one version of these databases, so the version value is never used. 734 */ 735 static int dummy; 736 737 static void 738 currentversion(dns_db_t *db, dns_dbversion_t **versionp) { 739 bdb_t *bdb = (bdb_t *)db; 740 741 REQUIRE(VALID_BDB(bdb)); 742 743 *versionp = (void *)&dummy; 744 return; 745 } 746 747 static void 748 attachversion(dns_db_t *db, dns_dbversion_t *source, 749 dns_dbversion_t **targetp) { 750 bdb_t *bdb = (bdb_t *)db; 751 752 REQUIRE(VALID_BDB(bdb)); 753 REQUIRE(source != NULL && source == (void *)&dummy); 754 REQUIRE(targetp != NULL && *targetp == NULL); 755 756 *targetp = source; 757 return; 758 } 759 760 static void 761 closeversion(dns_db_t *db, dns_dbversion_t **versionp, 762 bool commit DNS__DB_FLARG) { 763 bdb_t *bdb = (bdb_t *)db; 764 765 REQUIRE(VALID_BDB(bdb)); 766 REQUIRE(versionp != NULL && *versionp == (void *)&dummy); 767 REQUIRE(!commit); 768 769 *versionp = NULL; 770 } 771 772 static isc_result_t 773 createnode(bdb_t *bdb, bdbnode_t **nodep) { 774 bdbnode_t *node = NULL; 775 776 REQUIRE(VALID_BDB(bdb)); 777 778 node = isc_mem_get(bdb->common.mctx, sizeof(bdbnode_t)); 779 *node = (bdbnode_t){ 780 .lists = ISC_LIST_INITIALIZER, 781 .buffers = ISC_LIST_INITIALIZER, 782 .link = ISC_LINK_INITIALIZER, 783 }; 784 785 dns_db_attach((dns_db_t *)bdb, (dns_db_t **)&node->bdb); 786 dns_rdatacallbacks_init(&node->callbacks); 787 788 isc_refcount_init(&node->references, 1); 789 node->magic = BDBNODE_MAGIC; 790 791 *nodep = node; 792 return ISC_R_SUCCESS; 793 } 794 795 static void 796 destroynode(bdbnode_t *node) { 797 dns_rdatalist_t *list = NULL; 798 dns_rdata_t *rdata = NULL; 799 isc_buffer_t *b = NULL; 800 bdb_t *bdb = NULL; 801 isc_mem_t *mctx = NULL; 802 803 bdb = node->bdb; 804 mctx = bdb->common.mctx; 805 806 while (!ISC_LIST_EMPTY(node->lists)) { 807 list = ISC_LIST_HEAD(node->lists); 808 while (!ISC_LIST_EMPTY(list->rdata)) { 809 rdata = ISC_LIST_HEAD(list->rdata); 810 ISC_LIST_UNLINK(list->rdata, rdata, link); 811 isc_mem_put(mctx, rdata, sizeof(dns_rdata_t)); 812 } 813 ISC_LIST_UNLINK(node->lists, list, link); 814 isc_mem_put(mctx, list, sizeof(dns_rdatalist_t)); 815 } 816 817 while (!ISC_LIST_EMPTY(node->buffers)) { 818 b = ISC_LIST_HEAD(node->buffers); 819 ISC_LIST_UNLINK(node->buffers, b, link); 820 isc_buffer_free(&b); 821 } 822 823 if (node->name != NULL) { 824 dns_name_free(node->name, mctx); 825 isc_mem_put(mctx, node->name, sizeof(dns_name_t)); 826 } 827 828 node->magic = 0; 829 isc_mem_put(mctx, node, sizeof(bdbnode_t)); 830 dns_db_detach((dns_db_t **)(void *)&bdb); 831 } 832 833 static isc_result_t 834 getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) { 835 bdb_t *bdb = (bdb_t *)db; 836 bdbnode_t *node = NULL; 837 isc_result_t result; 838 dns_name_t relname; 839 dns_name_t *name = NULL; 840 841 REQUIRE(VALID_BDB(bdb)); 842 REQUIRE(nodep != NULL && *nodep == NULL); 843 844 dns_name_init(&relname, NULL); 845 name = &relname; 846 847 result = createnode(bdb, &node); 848 if (result != ISC_R_SUCCESS) { 849 return result; 850 } 851 852 result = builtin_lookup(bdb, name, node); 853 if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { 854 destroynode(node); 855 return result; 856 } 857 858 result = builtin_authority(bdb, node); 859 if (result != ISC_R_SUCCESS) { 860 destroynode(node); 861 return result; 862 } 863 864 *nodep = node; 865 return ISC_R_SUCCESS; 866 } 867 868 static isc_result_t 869 findnode(dns_db_t *db, const dns_name_t *name, bool create, 870 dns_dbnode_t **nodep DNS__DB_FLARG) { 871 bdb_t *bdb = (bdb_t *)db; 872 bdbnode_t *node = NULL; 873 isc_result_t result; 874 bool isorigin; 875 dns_name_t relname; 876 unsigned int labels; 877 878 REQUIRE(VALID_BDB(bdb)); 879 REQUIRE(nodep != NULL && *nodep == NULL); 880 881 UNUSED(create); 882 883 isorigin = dns_name_equal(name, &bdb->common.origin); 884 885 labels = dns_name_countlabels(name) - dns_name_countlabels(&db->origin); 886 dns_name_init(&relname, NULL); 887 dns_name_getlabelsequence(name, 0, labels, &relname); 888 name = &relname; 889 890 result = createnode(bdb, &node); 891 if (result != ISC_R_SUCCESS) { 892 return result; 893 } 894 895 result = builtin_lookup(bdb, name, node); 896 if (result != ISC_R_SUCCESS && (!isorigin || result != ISC_R_NOTFOUND)) 897 { 898 destroynode(node); 899 return result; 900 } 901 902 if (isorigin) { 903 result = builtin_authority(bdb, node); 904 if (result != ISC_R_SUCCESS) { 905 destroynode(node); 906 return result; 907 } 908 } 909 910 *nodep = node; 911 return ISC_R_SUCCESS; 912 } 913 914 static isc_result_t 915 find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, 916 dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, 917 dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, 918 dns_rdataset_t *sigrdataset DNS__DB_FLARG) { 919 bdb_t *bdb = (bdb_t *)db; 920 isc_result_t result; 921 dns_dbnode_t *node = NULL; 922 dns_fixedname_t fname; 923 dns_rdataset_t xrdataset; 924 dns_name_t *xname = NULL; 925 unsigned int nlabels, olabels, i; 926 bool dns64; 927 928 REQUIRE(VALID_BDB(bdb)); 929 REQUIRE(nodep == NULL || *nodep == NULL); 930 REQUIRE(version == NULL || version == (void *)&dummy); 931 932 if (!dns_name_issubdomain(name, &db->origin)) { 933 return DNS_R_NXDOMAIN; 934 } 935 936 olabels = dns_name_countlabels(&db->origin); 937 nlabels = dns_name_countlabels(name); 938 939 xname = dns_fixedname_initname(&fname); 940 941 if (rdataset == NULL) { 942 dns_rdataset_init(&xrdataset); 943 rdataset = &xrdataset; 944 } 945 946 result = DNS_R_NXDOMAIN; 947 dns64 = ((bdb->implementation->flags & BDB_DNS64) != 0); 948 for (i = (dns64 ? nlabels : olabels); i <= nlabels; i++) { 949 /* 950 * Look up the next label. 951 */ 952 dns_name_getlabelsequence(name, nlabels - i, i, xname); 953 result = findnode(db, xname, false, &node DNS__DB_FLARG_PASS); 954 if (result == ISC_R_NOTFOUND) { 955 /* 956 * No data at zone apex? 957 */ 958 if (i == olabels) { 959 return DNS_R_BADDB; 960 } 961 result = DNS_R_NXDOMAIN; 962 continue; 963 } 964 if (result != ISC_R_SUCCESS) { 965 return result; 966 } 967 968 /* 969 * DNS64 zones don't have DNAME or NS records. 970 */ 971 if (dns64) { 972 goto skip; 973 } 974 975 /* 976 * Look for a DNAME at the current label, unless this is 977 * the qname. 978 */ 979 if (i < nlabels) { 980 result = findrdataset( 981 db, node, version, dns_rdatatype_dname, 0, now, 982 rdataset, sigrdataset DNS__DB_FLARG_PASS); 983 if (result == ISC_R_SUCCESS) { 984 result = DNS_R_DNAME; 985 break; 986 } 987 } 988 989 /* 990 * Look for an NS at the current label, unless this is the 991 * origin or glue is ok. 992 */ 993 if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) { 994 result = findrdataset( 995 db, node, version, dns_rdatatype_ns, 0, now, 996 rdataset, sigrdataset DNS__DB_FLARG_PASS); 997 if (result == ISC_R_SUCCESS) { 998 if (i == nlabels && type == dns_rdatatype_any) { 999 result = DNS_R_ZONECUT; 1000 dns_rdataset_disassociate(rdataset); 1001 if (sigrdataset != NULL && 1002 dns_rdataset_isassociated( 1003 sigrdataset)) 1004 { 1005 dns_rdataset_disassociate( 1006 sigrdataset); 1007 } 1008 } else { 1009 result = DNS_R_DELEGATION; 1010 } 1011 break; 1012 } 1013 } 1014 1015 /* 1016 * If the current name is not the qname, add another label 1017 * and try again. 1018 */ 1019 if (i < nlabels) { 1020 destroynode(node); 1021 node = NULL; 1022 continue; 1023 } 1024 1025 skip: 1026 /* 1027 * If we're looking for ANY, we're done. 1028 */ 1029 if (type == dns_rdatatype_any) { 1030 result = ISC_R_SUCCESS; 1031 break; 1032 } 1033 1034 /* 1035 * Look for the qtype. 1036 */ 1037 result = findrdataset(db, node, version, type, 0, now, rdataset, 1038 sigrdataset DNS__DB_FLARG_PASS); 1039 if (result == ISC_R_SUCCESS) { 1040 break; 1041 } 1042 1043 /* 1044 * Look for a CNAME. 1045 */ 1046 if (type != dns_rdatatype_cname) { 1047 result = findrdataset( 1048 db, node, version, dns_rdatatype_cname, 0, now, 1049 rdataset, sigrdataset DNS__DB_FLARG_PASS); 1050 if (result == ISC_R_SUCCESS) { 1051 result = DNS_R_CNAME; 1052 break; 1053 } 1054 } 1055 1056 result = DNS_R_NXRRSET; 1057 break; 1058 } 1059 1060 if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset)) { 1061 dns_rdataset_disassociate(rdataset); 1062 } 1063 1064 if (foundname != NULL) { 1065 dns_name_copy(xname, foundname); 1066 } 1067 1068 if (nodep != NULL) { 1069 *nodep = node; 1070 } else if (node != NULL) { 1071 detachnode(db, &node DNS__DB_FLARG_PASS); 1072 } 1073 1074 return result; 1075 } 1076 1077 static void 1078 attachnode(dns_db_t *db, dns_dbnode_t *source, 1079 dns_dbnode_t **targetp DNS__DB_FLARG) { 1080 bdb_t *bdb = (bdb_t *)db; 1081 bdbnode_t *node = (bdbnode_t *)source; 1082 1083 REQUIRE(VALID_BDB(bdb)); 1084 1085 isc_refcount_increment(&node->references); 1086 1087 *targetp = source; 1088 } 1089 1090 static void 1091 detachnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) { 1092 bdb_t *bdb = (bdb_t *)db; 1093 bdbnode_t *node = NULL; 1094 1095 REQUIRE(VALID_BDB(bdb)); 1096 REQUIRE(nodep != NULL && *nodep != NULL); 1097 1098 node = (bdbnode_t *)(*nodep); 1099 *nodep = NULL; 1100 1101 if (isc_refcount_decrement(&node->references) == 1) { 1102 destroynode(node); 1103 } 1104 } 1105 1106 static isc_result_t 1107 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 1108 dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now, 1109 dns_rdataset_t *rdataset, 1110 dns_rdataset_t *sigrdataset DNS__DB_FLARG) { 1111 bdbnode_t *bdbnode = (bdbnode_t *)node; 1112 dns_rdatalist_t *list = NULL; 1113 1114 REQUIRE(VALID_BDBNODE(bdbnode)); 1115 1116 UNUSED(version); 1117 UNUSED(covers); 1118 UNUSED(now); 1119 UNUSED(sigrdataset); 1120 1121 if (type == dns_rdatatype_rrsig) { 1122 return ISC_R_NOTIMPLEMENTED; 1123 } 1124 1125 list = ISC_LIST_HEAD(bdbnode->lists); 1126 while (list != NULL) { 1127 if (list->type == type) { 1128 break; 1129 } 1130 list = ISC_LIST_NEXT(list, link); 1131 } 1132 if (list == NULL) { 1133 return ISC_R_NOTFOUND; 1134 } 1135 1136 new_rdataset(list, db, node, rdataset); 1137 1138 return ISC_R_SUCCESS; 1139 } 1140 1141 static isc_result_t 1142 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 1143 unsigned int options, isc_stdtime_t now, 1144 dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { 1145 bdb_rdatasetiter_t *iterator = NULL; 1146 1147 REQUIRE(version == NULL || version == &dummy); 1148 1149 iterator = isc_mem_get(db->mctx, sizeof(bdb_rdatasetiter_t)); 1150 *iterator = (bdb_rdatasetiter_t){ 1151 .common.methods = &rdatasetiter_methods, 1152 .common.db = db, 1153 .common.version = version, 1154 .common.options = options, 1155 .common.now = now, 1156 .common.magic = DNS_RDATASETITER_MAGIC, 1157 }; 1158 1159 attachnode(db, node, &iterator->common.node DNS__DB_FLARG_PASS); 1160 1161 *iteratorp = (dns_rdatasetiter_t *)iterator; 1162 1163 return ISC_R_SUCCESS; 1164 } 1165 1166 static dns_dbmethods_t bdb_methods = { 1167 .destroy = destroy, 1168 .currentversion = currentversion, 1169 .attachversion = attachversion, 1170 .closeversion = closeversion, 1171 .attachnode = attachnode, 1172 .detachnode = detachnode, 1173 .findrdataset = findrdataset, 1174 .allrdatasets = allrdatasets, 1175 .getoriginnode = getoriginnode, 1176 .findnode = findnode, 1177 .find = find, 1178 }; 1179 1180 static isc_result_t 1181 create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, 1182 dns_rdataclass_t rdclass, unsigned int argc, char *argv[], 1183 void *implementation, dns_db_t **dbp) { 1184 isc_result_t result; 1185 bool needargs = false; 1186 bdb_t *bdb = NULL; 1187 1188 REQUIRE(implementation != NULL); 1189 1190 if (type != dns_dbtype_zone) { 1191 return ISC_R_NOTIMPLEMENTED; 1192 } 1193 1194 bdb = isc_mem_get(mctx, sizeof(*bdb)); 1195 *bdb = (bdb_t){ 1196 .common = { .methods = &bdb_methods, .rdclass = rdclass }, 1197 .implementation = implementation, 1198 }; 1199 1200 isc_refcount_init(&bdb->common.references, 1); 1201 isc_mem_attach(mctx, &bdb->common.mctx); 1202 dns_name_init(&bdb->common.origin, NULL); 1203 dns_name_dupwithoffsets(origin, mctx, &bdb->common.origin); 1204 1205 INSIST(argc >= 1); 1206 if (strcmp(argv[0], "authors") == 0) { 1207 bdb->lookup = authors_lookup; 1208 } else if (strcmp(argv[0], "hostname") == 0) { 1209 bdb->lookup = hostname_lookup; 1210 } else if (strcmp(argv[0], "id") == 0) { 1211 bdb->lookup = id_lookup; 1212 } else if (strcmp(argv[0], "version") == 0) { 1213 bdb->lookup = version_lookup; 1214 } else if (strcmp(argv[0], "dns64") == 0) { 1215 needargs = true; 1216 bdb->lookup = empty_lookup; 1217 } else if (strcmp(argv[0], "empty") == 0) { 1218 needargs = true; 1219 bdb->lookup = empty_lookup; 1220 } else if (strcmp(argv[0], "ipv4only") == 0) { 1221 needargs = true; 1222 bdb->lookup = ipv4only_lookup; 1223 } else { 1224 needargs = true; 1225 bdb->lookup = ipv4reverse_lookup; 1226 } 1227 1228 if (needargs) { 1229 if (argc != 3) { 1230 result = DNS_R_SYNTAX; 1231 goto cleanup; 1232 } 1233 1234 bdb->server = isc_mem_strdup(named_g_mctx, argv[1]); 1235 bdb->contact = isc_mem_strdup(named_g_mctx, argv[2]); 1236 } else if (argc != 1) { 1237 result = DNS_R_SYNTAX; 1238 goto cleanup; 1239 } 1240 1241 bdb->common.magic = DNS_DB_MAGIC; 1242 bdb->common.impmagic = BDB_MAGIC; 1243 1244 *dbp = (dns_db_t *)bdb; 1245 1246 return ISC_R_SUCCESS; 1247 1248 cleanup: 1249 dns_name_free(&bdb->common.origin, mctx); 1250 if (bdb->server != NULL) { 1251 isc_mem_free(named_g_mctx, bdb->server); 1252 } 1253 if (bdb->contact != NULL) { 1254 isc_mem_free(named_g_mctx, bdb->contact); 1255 } 1256 1257 isc_mem_putanddetach(&bdb->common.mctx, bdb, sizeof(bdb_t)); 1258 return result; 1259 } 1260 1261 /* 1262 * Builtin database registration functions 1263 */ 1264 static bdbimplementation_t builtin = { .flags = 0 }; 1265 static bdbimplementation_t dns64 = { .flags = BDB_DNS64 }; 1266 1267 isc_result_t 1268 named_builtin_init(void) { 1269 isc_result_t result; 1270 1271 result = dns_db_register("_builtin", create, &builtin, named_g_mctx, 1272 &builtin.dbimp); 1273 if (result != ISC_R_SUCCESS) { 1274 return result; 1275 } 1276 1277 result = dns_db_register("_dns64", create, &dns64, named_g_mctx, 1278 &dns64.dbimp); 1279 if (result != ISC_R_SUCCESS) { 1280 dns_db_unregister(&builtin.dbimp); 1281 return result; 1282 } 1283 1284 return ISC_R_SUCCESS; 1285 } 1286 1287 void 1288 named_builtin_deinit(void) { 1289 if (builtin.dbimp != NULL) { 1290 dns_db_unregister(&builtin.dbimp); 1291 } 1292 if (dns64.dbimp != NULL) { 1293 dns_db_unregister(&dns64.dbimp); 1294 } 1295 } 1296