1 /* $NetBSD: dlz_bdbhpt_dynamic.c,v 1.1.1.5 2015/07/08 15:37:45 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the 8 * above copyright notice and this permission notice appear in all 9 * copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET 12 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 13 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 14 * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 15 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 16 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 17 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE 18 * USE OR PERFORMANCE OF THIS SOFTWARE. 19 * 20 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was 21 * conceived and contributed by Rob Butler. 22 * 23 * Permission to use, copy, modify, and distribute this software for any 24 * purpose with or without fee is hereby granted, provided that the 25 * above copyright notice and this permission notice appear in all 26 * copies. 27 * 28 * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER 29 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 31 * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 32 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 33 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 34 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE 35 * USE OR PERFORMANCE OF THIS SOFTWARE. 36 */ 37 38 /* 39 * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") 40 * 41 * Permission to use, copy, modify, and/or distribute this software for any 42 * purpose with or without fee is hereby granted, provided that the above 43 * copyright notice and this permission notice appear in all copies. 44 * 45 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 46 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 47 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 48 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 49 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 50 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 51 * PERFORMANCE OF THIS SOFTWARE. 52 */ 53 54 /* 55 * This is simply a merge of Andrew Tridgell's dlz_example.c and the 56 * original bdb_bdbhpt_driver.c 57 * 58 * This provides the externally loadable bdbhpt DLZ driver, without 59 * update support 60 * 61 */ 62 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <stdarg.h> 67 #include <stdint.h> 68 69 #include <db.h> 70 71 #include "dlz_minimal.h" 72 73 /* should the bdb driver use threads. */ 74 #ifdef ISC_PLATFORM_USETHREADS 75 #define bdbhpt_threads DB_THREAD 76 #else 77 #define bdbhpt_threads 0 78 #endif 79 80 /* bdbhpt database names */ 81 #define dlz_data "dns_data" 82 #define dlz_zone "dns_zone" 83 #define dlz_xfr "dns_xfr" 84 #define dlz_client "dns_client" 85 86 #define dlz_bdbhpt_dynamic_version "0.1" 87 88 /* 89 * This structure contains all our DB handles and helper functions we 90 * inherit from the dlz_dlopen driver 91 * 92 */ 93 typedef struct bdbhpt_instance { 94 DB_ENV *dbenv; /* bdbhpt environment */ 95 DB *data; /* dns_data database handle */ 96 DB *zone; /* zone database handle */ 97 DB *xfr; /* zone xfr database handle */ 98 DB *client; /* client database handle */ 99 100 /* Helper functions from the dlz_dlopen driver */ 101 log_t *log; 102 dns_sdlz_putrr_t *putrr; 103 dns_sdlz_putnamedrr_t *putnamedrr; 104 dns_dlz_writeablezone_t *writeable_zone; 105 } bdbhpt_instance_t; 106 107 typedef struct bdbhpt_parsed_data { 108 char *host; 109 char *type; 110 int ttl; 111 char *data; 112 } bdbhpt_parsed_data_t; 113 114 static void 115 b9_add_helper(struct bdbhpt_instance *db, const char *helper_name, void *ptr); 116 117 /*% 118 * Reverses a string in place. 119 */ 120 static char 121 *bdbhpt_strrev(char *str) { 122 char *p1, *p2; 123 124 if (! str || ! *str) 125 return str; 126 for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) { 127 *p1 ^= *p2; 128 *p2 ^= *p1; 129 *p1 ^= *p2; 130 } 131 return str; 132 } 133 134 /*% 135 * Parses the DBT from the Berkeley DB into a parsed_data record 136 * The parsed_data record should be allocated before and passed into the 137 * bdbhpt_parse_data function. The char (type & data) fields should not 138 * be "free"d as that memory is part of the DBT data field. It will be 139 * "free"d when the DBT is freed. 140 */ 141 142 static isc_result_t 143 bdbhpt_parse_data(log_t *log, char *in, bdbhpt_parsed_data_t *pd) { 144 145 char *endp, *ttlStr; 146 char *tmp = in; 147 char *lastchar = (char *) &tmp[strlen(tmp)]; 148 149 /*% 150 * String should be formatted as: 151 * replication_id 152 * (a space) 153 * host_name 154 * (a space) 155 * ttl 156 * (a space) 157 * type 158 * (a space) 159 * remaining data 160 * 161 * examples: 162 * 163 * 9191 host 10 A 127.0.0.1 164 * server1_212 host 10 A 127.0.0.2 165 * {xxxx-xxxx-xxxx-xxxx-xxxx} host 10 MX 20 mail.example.com 166 */ 167 168 /* 169 * we don't need the replication id, so don't 170 * bother saving a pointer to it. 171 */ 172 173 /* find space after replication id */ 174 tmp = strchr(tmp, ' '); 175 /* verify we found a space */ 176 if (tmp == NULL) 177 return ISC_R_FAILURE; 178 /* make sure it is safe to increment pointer */ 179 if (++tmp > lastchar) 180 return ISC_R_FAILURE; 181 182 /* save pointer to host */ 183 pd->host = tmp; 184 185 /* find space after host and change it to a '\0' */ 186 tmp = strchr(tmp, ' '); 187 /* verify we found a space */ 188 if (tmp == NULL) 189 return ISC_R_FAILURE; 190 /* change the space to a null (string terminator) */ 191 tmp[0] = '\0'; 192 /* make sure it is safe to increment pointer */ 193 if (++tmp > lastchar) 194 return ISC_R_FAILURE; 195 196 /* save pointer to ttl string */ 197 ttlStr = tmp; 198 199 /* find space after ttl and change it to a '\0' */ 200 tmp = strchr(tmp, ' '); 201 /* verify we found a space */ 202 if (tmp == NULL) 203 return ISC_R_FAILURE; 204 /* change the space to a null (string terminator) */ 205 tmp[0] = '\0'; 206 /* make sure it is safe to increment pointer */ 207 if (++tmp > lastchar) 208 return ISC_R_FAILURE; 209 210 /* save pointer to dns type */ 211 pd->type = tmp; 212 213 /* find space after type and change it to a '\0' */ 214 tmp = strchr(tmp, ' '); 215 /* verify we found a space */ 216 if (tmp == NULL) 217 return ISC_R_FAILURE; 218 /* change the space to a null (string terminator) */ 219 tmp[0] = '\0'; 220 /* make sure it is safe to increment pointer */ 221 if (++tmp > lastchar) 222 return ISC_R_FAILURE; 223 224 /* save pointer to remainder of DNS data */ 225 pd->data = tmp; 226 227 /* convert ttl string to integer */ 228 pd->ttl = strtol(ttlStr, &endp, 10); 229 if (*endp != '\0' || pd->ttl < 0) { 230 log(ISC_LOG_ERROR, 231 "bdbhpt_dynamic: " 232 "ttl must be a positive number"); 233 return ISC_R_FAILURE; 234 } 235 236 /* if we get this far everything should have worked. */ 237 return ISC_R_SUCCESS; 238 } 239 240 /* 241 * See if a zone transfer is allowed 242 */ 243 isc_result_t 244 dlz_allowzonexfr(void *dbdata, const char *name, const char *client) { 245 isc_result_t result; 246 bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata; 247 DBT key, data; 248 249 /* check to see if we are authoritative for the zone first. */ 250 #if DLZ_DLOPEN_VERSION >= 3 251 result = dlz_findzonedb(dbdata, name, NULL, NULL); 252 #else 253 result = dlz_findzonedb(dbdata, name); 254 #endif 255 if (result != ISC_R_SUCCESS) 256 return (ISC_R_NOTFOUND); 257 258 memset(&key, 0, sizeof(DBT)); 259 key.flags = DB_DBT_MALLOC; 260 key.data = strdup(name); 261 if (key.data == NULL) { 262 result = ISC_R_NOMEMORY; 263 goto xfr_cleanup; 264 } 265 key.size = strlen(key.data); 266 267 memset(&data, 0, sizeof(DBT)); 268 data.flags = DB_DBT_MALLOC; 269 data.data = strdup(client); 270 if (data.data == NULL) { 271 result = ISC_R_NOMEMORY; 272 goto xfr_cleanup; 273 } 274 data.size = strlen(data.data); 275 276 switch(db->client->get(db->client, NULL, &key, &data, DB_GET_BOTH)) { 277 case DB_NOTFOUND: 278 result = ISC_R_NOTFOUND; 279 break; 280 case 0: 281 result = ISC_R_SUCCESS; 282 break; 283 default: 284 result = ISC_R_FAILURE; 285 } 286 287 xfr_cleanup: 288 /* free any memory duplicate string in the key field */ 289 if (key.data != NULL) 290 free(key.data); 291 292 /* free any memory allocated to the data field. */ 293 if (data.data != NULL) 294 free(data.data); 295 296 return result; 297 } 298 299 /*% 300 * Perform a zone transfer 301 * 302 * BDB does not allow a secondary index on a database that allows 303 * duplicates. We have a few options: 304 * 305 * 1) kill speed by having lookup method use a secondary db which 306 * is associated to the primary DB with the DNS data. Then have 307 * another secondary db for zone transfer which also points to 308 * the dns_data primary. NO - The point of this driver is 309 * lookup performance. 310 * 311 * 2) Blow up database size by storing DNS data twice. Once for 312 * the lookup (dns_data) database, and a second time for the zone 313 * transfer (dns_xfr) database. NO - That would probably require 314 * a larger cache to provide good performance. Also, that would 315 * make the DB larger on disk potentially slowing it as well. 316 * 317 * 3) Loop through the dns_xfr database with a cursor to get 318 * all the different hosts in a zone. Then use the zone & host 319 * together to lookup the data in the dns_data database. YES - 320 * This may slow down zone xfr's a little, but that's ok they 321 * don't happen as often and don't need to be as fast. We can 322 * also use this table when deleting a zone (The BDB driver 323 * is read only - the delete would be used during replication 324 * updates by a separate process). 325 */ 326 isc_result_t 327 dlz_allnodes(const char *zone, void *dbdata, dns_sdlzallnodes_t *allnodes) { 328 isc_result_t result = ISC_R_NOTFOUND; 329 bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata; 330 DBC *xfr_cursor = NULL; 331 DBC *dns_cursor = NULL; 332 DBT xfr_key, xfr_data, dns_key, dns_data; 333 int xfr_flags; 334 int dns_flags; 335 int bdbhptres; 336 bdbhpt_parsed_data_t pd; 337 char *tmp = NULL, *tmp_zone, *tmp_zone_host = NULL; 338 339 memset(&xfr_key, 0, sizeof(DBT)); 340 memset(&xfr_data, 0, sizeof(DBT)); 341 memset(&dns_key, 0, sizeof(DBT)); 342 memset(&dns_data, 0, sizeof(DBT)); 343 344 xfr_key.data = tmp_zone = strdup(zone); 345 if (xfr_key.data == NULL) 346 return (ISC_R_NOMEMORY); 347 348 xfr_key.size = strlen(xfr_key.data); 349 350 /* get a cursor to loop through dns_xfr table */ 351 if (db->xfr->cursor(db->xfr, NULL, &xfr_cursor, 0) != 0) { 352 result = ISC_R_FAILURE; 353 goto allnodes_cleanup; 354 } 355 356 /* get a cursor to loop through dns_data table */ 357 if (db->data->cursor(db->data, NULL, &dns_cursor, 0) != 0) { 358 result = ISC_R_FAILURE; 359 goto allnodes_cleanup; 360 } 361 362 xfr_flags = DB_SET; 363 364 /* loop through xfr table for specified zone. */ 365 while ((bdbhptres = xfr_cursor->c_get(xfr_cursor, &xfr_key, 366 &xfr_data, xfr_flags)) == 0) 367 { 368 xfr_flags = DB_NEXT_DUP; 369 370 /* +1 to allow for space between zone and host names */ 371 dns_key.size = xfr_data.size + xfr_key.size + 1; 372 373 /* +1 to allow for null term at end of string. */ 374 dns_key.data = tmp_zone_host = malloc(dns_key.size + 1); 375 if (dns_key.data == NULL) 376 goto allnodes_cleanup; 377 378 /* 379 * construct search key for dns_data. 380 * zone_name(a space)host_name 381 */ 382 strcpy(dns_key.data, zone); 383 strcat(dns_key.data, " "); 384 strncat(dns_key.data, xfr_data.data, xfr_data.size); 385 386 dns_flags = DB_SET; 387 388 while ((bdbhptres = dns_cursor->c_get(dns_cursor, 389 &dns_key, 390 &dns_data, 391 dns_flags)) == 0) 392 { 393 dns_flags = DB_NEXT_DUP; 394 395 /* +1 to allow for null term at end of string. */ 396 tmp = realloc(tmp, dns_data.size + 1); 397 if (tmp == NULL) 398 goto allnodes_cleanup; 399 400 /* copy data to tmp string, and append null term. */ 401 strncpy(tmp, dns_data.data, dns_data.size); 402 tmp[dns_data.size] = '\0'; 403 404 /* split string into dns data parts. */ 405 if (bdbhpt_parse_data(db->log, 406 tmp, &pd) != ISC_R_SUCCESS) 407 goto allnodes_cleanup; 408 result = db->putnamedrr(allnodes, pd.host, 409 pd.type, pd.ttl, pd.data); 410 if (result != ISC_R_SUCCESS) 411 goto allnodes_cleanup; 412 413 } /* end inner while loop */ 414 415 /* clean up memory */ 416 if (tmp_zone_host != NULL) { 417 free(tmp_zone_host); 418 tmp_zone_host = NULL; 419 } 420 } /* end outer while loop */ 421 422 allnodes_cleanup: 423 /* free any memory */ 424 if (tmp != NULL) 425 free(tmp); 426 427 if (tmp_zone_host != NULL) 428 free(tmp_zone_host); 429 430 if (tmp_zone != NULL) 431 free(tmp_zone); 432 433 /* get rid of cursors */ 434 if (xfr_cursor != NULL) 435 xfr_cursor->c_close(xfr_cursor); 436 437 if (dns_cursor != NULL) 438 dns_cursor->c_close(dns_cursor); 439 440 return result; 441 } 442 443 /*% 444 * Performs bdbhpt cleanup. 445 * Used by bdbhpt_create if there is an error starting up. 446 * Used by bdbhpt_destroy when the driver is shutting down. 447 */ 448 static void 449 bdbhpt_cleanup(bdbhpt_instance_t *db) { 450 /* close databases */ 451 if (db->data != NULL) 452 db->data->close(db->data, 0); 453 if (db->xfr != NULL) 454 db->xfr->close(db->xfr, 0); 455 if (db->zone != NULL) 456 db->zone->close(db->zone, 0); 457 if (db->client != NULL) 458 db->client->close(db->client, 0); 459 460 /* close environment */ 461 if (db->dbenv != NULL) 462 db->dbenv->close(db->dbenv, 0); 463 } 464 465 /* 466 * See if we handle a given zone 467 */ 468 #if DLZ_DLOPEN_VERSION < 3 469 isc_result_t 470 dlz_findzonedb(void *dbdata, const char *name) 471 #else 472 isc_result_t 473 dlz_findzonedb(void *dbdata, const char *name, 474 dns_clientinfomethods_t *methods, 475 dns_clientinfo_t *clientinfo) 476 #endif 477 { 478 isc_result_t result; 479 bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata; 480 DBT key, data; 481 482 memset(&key, 0, sizeof(DBT)); 483 memset(&data, 0, sizeof(DBT)); 484 data.flags = DB_DBT_MALLOC; 485 486 #if DLZ_DLOPEN_VERSION >= 3 487 UNUSED(methods); 488 UNUSED(clientinfo); 489 #endif 490 491 key.data = strdup(name); 492 493 if (key.data == NULL) 494 return (ISC_R_NOMEMORY); 495 496 /* 497 * reverse string to take advantage of BDB locality of reference 498 * if we need futher lookups because the zone doesn't match the 499 * first time. 500 */ 501 key.data = bdbhpt_strrev(key.data); 502 key.size = strlen(key.data); 503 504 switch(db->zone->get(db->zone, NULL, &key, &data, 0)) { 505 case DB_NOTFOUND: 506 result = ISC_R_NOTFOUND; 507 break; 508 case 0: 509 result = ISC_R_SUCCESS; 510 break; 511 default: 512 result = ISC_R_FAILURE; 513 } 514 515 /* free any memory duplicate string in the key field */ 516 if (key.data != NULL) 517 free(key.data); 518 519 /* free any memory allocated to the data field. */ 520 if (data.data != NULL) 521 free(data.data); 522 523 return result; 524 } 525 526 /* 527 * Look up one record in the database. 528 * 529 */ 530 #if DLZ_DLOPEN_VERSION == 1 531 isc_result_t dlz_lookup(const char *zone, const char *name, 532 void *dbdata, dns_sdlzlookup_t *lookup) 533 #else 534 isc_result_t dlz_lookup(const char *zone, const char *name, void *dbdata, 535 dns_sdlzlookup_t *lookup, 536 dns_clientinfomethods_t *methods, 537 dns_clientinfo_t *clientinfo) 538 #endif 539 { 540 isc_result_t result = ISC_R_NOTFOUND; 541 bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata; 542 DBC *data_cursor = NULL; 543 DBT key, data; 544 int bdbhptres; 545 int flags; 546 547 bdbhpt_parsed_data_t pd; 548 char *tmp = NULL; 549 char *keyStr = NULL; 550 551 #if DLZ_DLOPEN_VERSION >= 2 552 UNUSED(methods); 553 UNUSED(clientinfo); 554 #endif 555 556 memset(&key, 0, sizeof(DBT)); 557 memset(&data, 0, sizeof(DBT)); 558 559 key.size = strlen(zone) + strlen(name) + 1; 560 561 /* allocate mem for key */ 562 key.data = keyStr = malloc((key.size + 1) * sizeof(char)); 563 564 if (keyStr == NULL) 565 return ISC_R_NOMEMORY; 566 567 strcpy(keyStr, zone); 568 strcat(keyStr, " "); 569 strcat(keyStr, name); 570 571 /* get a cursor to loop through data */ 572 if (db->data->cursor(db->data, NULL, &data_cursor, 0) != 0) { 573 result = ISC_R_FAILURE; 574 goto lookup_cleanup; 575 } 576 577 result = ISC_R_NOTFOUND; 578 579 flags = DB_SET; 580 while ((bdbhptres = data_cursor->c_get(data_cursor, &key, &data, 581 flags)) == 0) 582 { 583 flags = DB_NEXT_DUP; 584 tmp = realloc(tmp, data.size + 1); 585 if (tmp == NULL) 586 goto lookup_cleanup; 587 588 strncpy(tmp, data.data, data.size); 589 tmp[data.size] = '\0'; 590 591 if (bdbhpt_parse_data(db->log, tmp, &pd) != ISC_R_SUCCESS) 592 goto lookup_cleanup; 593 594 result = db->putrr(lookup, pd.type, pd.ttl, pd.data); 595 if (result != ISC_R_SUCCESS) 596 goto lookup_cleanup; 597 } /* end while loop */ 598 599 lookup_cleanup: 600 /* get rid of cursor */ 601 if (data_cursor != NULL) 602 data_cursor->c_close(data_cursor); 603 604 if (keyStr != NULL) 605 free(keyStr); 606 if (tmp != NULL) 607 free(tmp); 608 609 return result; 610 } 611 612 /*% 613 * Initialises, sets flags and then opens Berkeley databases. 614 */ 615 static isc_result_t 616 bdbhpt_opendb(log_t *log, DB_ENV *db_env, DBTYPE db_type, DB **db, 617 const char *db_name, char *db_file, int flags) 618 { 619 int result; 620 621 /* Initialise the database. */ 622 if ((result = db_create(db, db_env, 0)) != 0) { 623 log(ISC_LOG_ERROR, 624 "bdbhpt_dynamic: could not initialize %s database. " 625 "BerkeleyDB error: %s", 626 db_name, db_strerror(result)); 627 return ISC_R_FAILURE; 628 } 629 630 /* set database flags. */ 631 if ((result = (*db)->set_flags(*db, flags)) != 0) { 632 log(ISC_LOG_ERROR, 633 "bdbhpt_dynamic: could not set flags for %s database. " 634 "BerkeleyDB error: %s", 635 db_name, db_strerror(result)); 636 return ISC_R_FAILURE; 637 } 638 639 /* open the database. */ 640 if ((result = (*db)->open(*db, NULL, db_file, db_name, db_type, 641 DB_RDONLY | bdbhpt_threads, 0)) != 0) { 642 log(ISC_LOG_ERROR, 643 "bdbhpt_dynamic: could not open %s database in %s. " 644 "BerkeleyDB error: %s", 645 db_name, db_file, db_strerror(result)); 646 return ISC_R_FAILURE; 647 } 648 649 return ISC_R_SUCCESS; 650 } 651 652 653 /* 654 * Called to initialize the driver 655 */ 656 isc_result_t 657 dlz_create(const char *dlzname, unsigned int argc, char *argv[], 658 void **dbdata, ...) 659 { 660 isc_result_t result; 661 int bdbhptres; 662 int bdbFlags = 0; 663 bdbhpt_instance_t *db = NULL; 664 665 const char *helper_name; 666 va_list ap; 667 668 UNUSED(dlzname); 669 670 /* Allocate memory for our db structures and helper functions */ 671 db = calloc(1, sizeof(struct bdbhpt_instance)); 672 if (db == NULL) 673 return (ISC_R_NOMEMORY); 674 675 /* Fill in the helper functions */ 676 va_start(ap, dbdata); 677 while ((helper_name = va_arg(ap, const char *)) != NULL) 678 b9_add_helper(db, helper_name, va_arg(ap, void*)); 679 va_end(ap); 680 681 /* verify we have 4 arg's passed to the driver */ 682 if (argc != 4) { 683 db->log(ISC_LOG_ERROR, 684 "bdbhpt_dynamic: please supply 3 command line args. " 685 "You supplied: %s", argc); 686 return (ISC_R_FAILURE); 687 } 688 689 switch((char) *argv[1]) { 690 /* 691 * Transactional mode. Highest safety - lowest speed. 692 */ 693 case 'T': 694 case 't': 695 bdbFlags = DB_INIT_MPOOL | DB_INIT_LOCK | 696 DB_INIT_LOG | DB_INIT_TXN; 697 db->log(ISC_LOG_INFO, 698 "bdbhpt_dynamic: using transactional mode."); 699 break; 700 701 /* 702 * Concurrent mode. Lower safety (no rollback) - 703 * higher speed. 704 */ 705 case 'C': 706 case 'c': 707 bdbFlags = DB_INIT_CDB | DB_INIT_MPOOL; 708 db->log(ISC_LOG_INFO, 709 "bdbhpt_dynamic: using concurrent mode."); 710 break; 711 712 /* 713 * Private mode. No inter-process communication & no locking. 714 * Lowest saftey - highest speed. 715 */ 716 case 'P': 717 case 'p': 718 bdbFlags = DB_PRIVATE | DB_INIT_MPOOL; 719 db->log(ISC_LOG_INFO, 720 "bdbhpt_dynamic: using private mode."); 721 break; 722 default: 723 db->log(ISC_LOG_ERROR, 724 "bdbhpt_dynamic: " 725 "operating mode must be set to P or C or T. " 726 "You specified '%s'", argv[1]); 727 return (ISC_R_FAILURE); 728 } 729 730 /* 731 * create bdbhpt environment 732 * Basically bdbhpt allocates and assigns memory to db->dbenv 733 */ 734 bdbhptres = db_env_create(&db->dbenv, 0); 735 if (bdbhptres != 0) { 736 db->log(ISC_LOG_ERROR, 737 "bdbhpt_dynamic: db environment could not be created. " 738 "BerkeleyDB error: %s", db_strerror(bdbhptres)); 739 result = ISC_R_FAILURE; 740 goto init_cleanup; 741 } 742 743 /* open bdbhpt environment */ 744 bdbhptres = db->dbenv->open(db->dbenv, argv[2], 745 bdbFlags | bdbhpt_threads | DB_CREATE, 0); 746 if (bdbhptres != 0) { 747 db->log(ISC_LOG_ERROR, 748 "bdbhpt_dynamic: " 749 "db environment at '%s' could not be opened. " 750 "BerkeleyDB error: %s", 751 argv[2], db_strerror(bdbhptres)); 752 result = ISC_R_FAILURE; 753 goto init_cleanup; 754 } 755 756 /* open dlz_data database. */ 757 result = bdbhpt_opendb(db->log, db->dbenv, DB_UNKNOWN, &db->data, 758 dlz_data, argv[3], DB_DUP | DB_DUPSORT); 759 if (result != ISC_R_SUCCESS) 760 goto init_cleanup; 761 762 /* open dlz_xfr database. */ 763 result = bdbhpt_opendb(db->log, db->dbenv, DB_UNKNOWN, &db->xfr, 764 dlz_xfr, argv[3], DB_DUP | DB_DUPSORT); 765 if (result != ISC_R_SUCCESS) 766 goto init_cleanup; 767 768 /* open dlz_zone database. */ 769 result = bdbhpt_opendb(db->log, db->dbenv, DB_UNKNOWN, &db->zone, 770 dlz_zone, argv[3], 0); 771 if (result != ISC_R_SUCCESS) 772 goto init_cleanup; 773 774 /* open dlz_client database. */ 775 result = bdbhpt_opendb(db->log, db->dbenv, DB_UNKNOWN, &db->client, 776 dlz_client, argv[3], DB_DUP | DB_DUPSORT); 777 if (result != ISC_R_SUCCESS) 778 goto init_cleanup; 779 780 *dbdata = db; 781 782 db->log(ISC_LOG_INFO, 783 "bdbhpt_dynamic: version %s, started", 784 dlz_bdbhpt_dynamic_version); 785 return(ISC_R_SUCCESS); 786 787 init_cleanup: 788 bdbhpt_cleanup(db); 789 return result; 790 } 791 792 /* 793 * Shut down the backend 794 */ 795 void 796 dlz_destroy(void *dbdata) { 797 struct bdbhpt_instance *db = (struct bdbhpt_instance *)dbdata; 798 799 db->log(ISC_LOG_INFO, 800 "dlz_bdbhpt_dynamic (%s): shutting down", 801 dlz_bdbhpt_dynamic_version); 802 bdbhpt_cleanup((bdbhpt_instance_t *) dbdata); 803 free(db); 804 } 805 806 /* 807 * Return the version of the API 808 */ 809 int 810 dlz_version(unsigned int *flags) { 811 UNUSED(flags); 812 return (DLZ_DLOPEN_VERSION); 813 } 814 815 /* 816 * Register a helper function from the bind9 dlz_dlopen driver 817 */ 818 static void 819 b9_add_helper(struct bdbhpt_instance *db, const char *helper_name, void *ptr) { 820 if (strcmp(helper_name, "log") == 0) 821 db->log = (log_t *)ptr; 822 if (strcmp(helper_name, "putrr") == 0) 823 db->putrr = (dns_sdlz_putrr_t *)ptr; 824 if (strcmp(helper_name, "putnamedrr") == 0) 825 db->putnamedrr = (dns_sdlz_putnamedrr_t *)ptr; 826 if (strcmp(helper_name, "writeable_zone") == 0) 827 db->writeable_zone = (dns_dlz_writeablezone_t *)ptr; 828 } 829 830