adb.c revision 135446
1/* 2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: adb.c,v 1.181.2.11.2.19 2004/09/01 05:19:57 marka Exp $ */ 19 20/* 21 * Implementation notes 22 * -------------------- 23 * 24 * In finds, if task == NULL, no events will be generated, and no events 25 * have been sent. If task != NULL but taskaction == NULL, an event has been 26 * posted but not yet freed. If neither are NULL, no event was posted. 27 * 28 */ 29 30/* 31 * After we have cleaned all buckets, dump the database contents. 32 */ 33#if 0 34#define DUMP_ADB_AFTER_CLEANING 35#endif 36 37#include <config.h> 38 39#include <limits.h> 40 41#include <isc/mutexblock.h> 42#include <isc/netaddr.h> 43#include <isc/random.h> 44#include <isc/string.h> /* Required for HP/UX (and others?) */ 45#include <isc/task.h> 46#include <isc/timer.h> 47#include <isc/util.h> 48 49#include <dns/adb.h> 50#include <dns/db.h> 51#include <dns/events.h> 52#include <dns/log.h> 53#include <dns/rdata.h> 54#include <dns/rdataset.h> 55#include <dns/rdatastruct.h> 56#include <dns/resolver.h> 57#include <dns/result.h> 58 59#define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b') 60#define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC) 61#define DNS_ADBNAME_MAGIC ISC_MAGIC('a', 'd', 'b', 'N') 62#define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC) 63#define DNS_ADBNAMEHOOK_MAGIC ISC_MAGIC('a', 'd', 'N', 'H') 64#define DNS_ADBNAMEHOOK_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC) 65#define DNS_ADBZONEINFO_MAGIC ISC_MAGIC('a', 'd', 'b', 'Z') 66#define DNS_ADBZONEINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBZONEINFO_MAGIC) 67#define DNS_ADBENTRY_MAGIC ISC_MAGIC('a', 'd', 'b', 'E') 68#define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC) 69#define DNS_ADBFETCH_MAGIC ISC_MAGIC('a', 'd', 'F', '4') 70#define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC) 71#define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6') 72#define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC) 73 74/* 75 * The number of buckets needs to be a prime (for good hashing). 76 * 77 * XXXRTH How many buckets do we need? 78 */ 79#define NBUCKETS 1009 /* how many buckets for names/addrs */ 80 81/* 82 * For type 3 negative cache entries, we will remember that the address is 83 * broken for this long. XXXMLG This is also used for actual addresses, too. 84 * The intent is to keep us from constantly asking about A/AAAA records 85 * if the zone has extremely low TTLs. 86 */ 87#define ADB_CACHE_MINIMUM 10 /* seconds */ 88#define ADB_CACHE_MAXIMUM 86400 /* seconds (86400 = 24 hours) */ 89#define ADB_ENTRY_WINDOW 1800 /* seconds */ 90 91/* 92 * Wake up every CLEAN_SECONDS and clean CLEAN_BUCKETS buckets, so that all 93 * buckets are cleaned in CLEAN_PERIOD seconds. 94 */ 95#define CLEAN_PERIOD 3600 96#define CLEAN_SECONDS 30 97#define CLEAN_BUCKETS ((NBUCKETS * CLEAN_SECONDS) / CLEAN_PERIOD) 98 99#define FREE_ITEMS 64 /* free count for memory pools */ 100#define FILL_COUNT 16 /* fill count for memory pools */ 101 102#define DNS_ADB_INVALIDBUCKET (-1) /* invalid bucket address */ 103 104#define DNS_ADB_MINADBSIZE (1024*1024) /* 1 Megabyte */ 105 106typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t; 107typedef struct dns_adbnamehook dns_adbnamehook_t; 108typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t; 109typedef struct dns_adbzoneinfo dns_adbzoneinfo_t; 110typedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t; 111typedef struct dns_adbfetch dns_adbfetch_t; 112typedef struct dns_adbfetch6 dns_adbfetch6_t; 113 114struct dns_adb { 115 unsigned int magic; 116 117 isc_mutex_t lock; 118 isc_mutex_t reflock; /* Covers irefcnt, erefcnt */ 119 isc_mem_t *mctx; 120 dns_view_t *view; 121 isc_timermgr_t *timermgr; 122 isc_timer_t *timer; 123 isc_taskmgr_t *taskmgr; 124 isc_task_t *task; 125 isc_boolean_t overmem; 126 127 isc_interval_t tick_interval; 128 int next_cleanbucket; 129 130 unsigned int irefcnt; 131 unsigned int erefcnt; 132 133 isc_mutex_t mplock; 134 isc_mempool_t *nmp; /* dns_adbname_t */ 135 isc_mempool_t *nhmp; /* dns_adbnamehook_t */ 136 isc_mempool_t *zimp; /* dns_adbzoneinfo_t */ 137 isc_mempool_t *emp; /* dns_adbentry_t */ 138 isc_mempool_t *ahmp; /* dns_adbfind_t */ 139 isc_mempool_t *aimp; /* dns_adbaddrinfo_t */ 140 isc_mempool_t *afmp; /* dns_adbfetch_t */ 141 142 /* 143 * Bucketized locks and lists for names. 144 * 145 * XXXRTH Have a per-bucket structure that contains all of these? 146 */ 147 dns_adbnamelist_t names[NBUCKETS]; 148 isc_mutex_t namelocks[NBUCKETS]; 149 isc_boolean_t name_sd[NBUCKETS]; 150 unsigned int name_refcnt[NBUCKETS]; 151 152 /* 153 * Bucketized locks for entries. 154 * 155 * XXXRTH Have a per-bucket structure that contains all of these? 156 */ 157 dns_adbentrylist_t entries[NBUCKETS]; 158 isc_mutex_t entrylocks[NBUCKETS]; 159 isc_boolean_t entry_sd[NBUCKETS]; /* shutting down */ 160 unsigned int entry_refcnt[NBUCKETS]; 161 162 isc_event_t cevent; 163 isc_boolean_t cevent_sent; 164 isc_boolean_t shutting_down; 165 isc_eventlist_t whenshutdown; 166}; 167 168/* 169 * XXXMLG Document these structures. 170 */ 171 172struct dns_adbname { 173 unsigned int magic; 174 dns_name_t name; 175 dns_adb_t *adb; 176 unsigned int partial_result; 177 unsigned int flags; 178 int lock_bucket; 179 dns_name_t target; 180 isc_stdtime_t expire_target; 181 isc_stdtime_t expire_v4; 182 isc_stdtime_t expire_v6; 183 unsigned int chains; 184 dns_adbnamehooklist_t v4; 185 dns_adbnamehooklist_t v6; 186 dns_adbfetch_t *fetch_a; 187 dns_adbfetch_t *fetch_aaaa; 188 unsigned int fetch_err; 189 unsigned int fetch6_err; 190 dns_adbfindlist_t finds; 191 ISC_LINK(dns_adbname_t) plink; 192}; 193 194struct dns_adbfetch { 195 unsigned int magic; 196 dns_adbnamehook_t *namehook; 197 dns_adbentry_t *entry; 198 dns_fetch_t *fetch; 199 dns_rdataset_t rdataset; 200}; 201 202/* 203 * dns_adbnamehook_t 204 * 205 * This is a small widget that dangles off a dns_adbname_t. It contains a 206 * pointer to the address information about this host, and a link to the next 207 * namehook that will contain the next address this host has. 208 */ 209struct dns_adbnamehook { 210 unsigned int magic; 211 dns_adbentry_t *entry; 212 ISC_LINK(dns_adbnamehook_t) plink; 213}; 214 215/* 216 * dns_adbzoneinfo_t 217 * 218 * This is a small widget that holds zone-specific information about an 219 * address. Currently limited to lameness, but could just as easily be 220 * extended to other types of information about zones. 221 */ 222struct dns_adbzoneinfo { 223 unsigned int magic; 224 225 dns_name_t zone; 226 isc_stdtime_t lame_timer; 227 228 ISC_LINK(dns_adbzoneinfo_t) plink; 229}; 230 231/* 232 * An address entry. It holds quite a bit of information about addresses, 233 * including edns state (in "flags"), rtt, and of course the address of 234 * the host. 235 */ 236struct dns_adbentry { 237 unsigned int magic; 238 239 int lock_bucket; 240 unsigned int refcnt; 241 242 unsigned int flags; 243 unsigned int srtt; 244 isc_sockaddr_t sockaddr; 245 246 isc_stdtime_t expires; 247 /* 248 * A nonzero 'expires' field indicates that the entry should 249 * persist until that time. This allows entries found 250 * using dns_adb_findaddrinfo() to persist for a limited time 251 * even though they are not necessarily associated with a 252 * name. 253 */ 254 255 ISC_LIST(dns_adbzoneinfo_t) zoneinfo; 256 ISC_LINK(dns_adbentry_t) plink; 257}; 258 259/* 260 * Internal functions (and prototypes). 261 */ 262static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *); 263static inline void free_adbname(dns_adb_t *, dns_adbname_t **); 264static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *, 265 dns_adbentry_t *); 266static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **); 267static inline dns_adbzoneinfo_t *new_adbzoneinfo(dns_adb_t *, dns_name_t *); 268static inline void free_adbzoneinfo(dns_adb_t *, dns_adbzoneinfo_t **); 269static inline dns_adbentry_t *new_adbentry(dns_adb_t *); 270static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **); 271static inline dns_adbfind_t *new_adbfind(dns_adb_t *); 272static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **); 273static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *, 274 in_port_t); 275static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *); 276static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **); 277static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *, 278 unsigned int, int *); 279static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *, 280 isc_sockaddr_t *, int *); 281static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug); 282static void print_dns_name(FILE *, dns_name_t *); 283static void print_namehook_list(FILE *, const char *legend, 284 dns_adbnamehooklist_t *list, 285 isc_boolean_t debug, 286 isc_stdtime_t now); 287static void print_find_list(FILE *, dns_adbname_t *); 288static void print_fetch_list(FILE *, dns_adbname_t *); 289static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *); 290static inline void inc_adb_irefcnt(dns_adb_t *); 291static inline void inc_adb_erefcnt(dns_adb_t *); 292static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *, 293 isc_boolean_t); 294static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, dns_adbentry_t *, 295 isc_boolean_t); 296static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *); 297static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *); 298static void clean_target(dns_adb_t *, dns_name_t *); 299static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, 300 unsigned int); 301static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t, 302 isc_boolean_t); 303static void cancel_fetches_at_name(dns_adbname_t *); 304static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t, 305 dns_rdatatype_t); 306static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t, 307 dns_rdatatype_t); 308static inline void check_exit(dns_adb_t *); 309static void timer_cleanup(isc_task_t *, isc_event_t *); 310static void destroy(dns_adb_t *); 311static isc_boolean_t shutdown_names(dns_adb_t *); 312static isc_boolean_t shutdown_entries(dns_adb_t *); 313static inline void link_name(dns_adb_t *, int, dns_adbname_t *); 314static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *); 315static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *); 316static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *); 317static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t); 318static void water(void *arg, int mark); 319 320/* 321 * MUST NOT overlap DNS_ADBFIND_* flags! 322 */ 323#define FIND_EVENT_SENT 0x40000000 324#define FIND_EVENT_FREED 0x80000000 325#define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0) 326#define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0) 327 328#define NAME_NEEDS_POKE 0x80000000 329#define NAME_IS_DEAD 0x40000000 330#define NAME_HINT_OK DNS_ADBFIND_HINTOK 331#define NAME_GLUE_OK DNS_ADBFIND_GLUEOK 332#define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE 333#define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0) 334#define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0) 335#define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0) 336#define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0) 337 338/* 339 * To the name, address classes are all that really exist. If it has a 340 * V6 address it doesn't care if it came from a AAAA query. 341 */ 342#define NAME_HAS_V4(n) (!ISC_LIST_EMPTY((n)->v4)) 343#define NAME_HAS_V6(n) (!ISC_LIST_EMPTY((n)->v6)) 344#define NAME_HAS_ADDRS(n) (NAME_HAS_V4(n) || NAME_HAS_V6(n)) 345 346/* 347 * Fetches are broken out into A and AAAA types. In some cases, 348 * however, it makes more sense to test for a particular class of fetches, 349 * like V4 or V6 above. 350 * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA 351 * are now equal to FETCH_V4 and FETCH_V6, respectively. 352 */ 353#define NAME_FETCH_A(n) ((n)->fetch_a != NULL) 354#define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL) 355#define NAME_FETCH_V4(n) (NAME_FETCH_A(n)) 356#define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n)) 357#define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n)) 358 359/* 360 * Find options and tests to see if there are addresses on the list. 361 */ 362#define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0) 363#define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0) 364#define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \ 365 != 0) 366#define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \ 367 != 0) 368#define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0) 369#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0) 370#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list)) 371#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0) 372 373/* 374 * These are currently used on simple unsigned ints, so they are 375 * not really associated with any particular type. 376 */ 377#define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0) 378#define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0) 379 380#define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now)) 381 382/* 383 * Find out if the flags on a name (nf) indicate if it is a hint or 384 * glue, and compare this to the appropriate bits set in o, to see if 385 * this is ok. 386 */ 387#define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0)) 388#define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0)) 389#define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o)) 390#define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \ 391 ((o) & DNS_ADBFIND_STARTATZONE)) 392 393#define ENTER_LEVEL ISC_LOG_DEBUG(50) 394#define EXIT_LEVEL ENTER_LEVEL 395#define CLEAN_LEVEL ISC_LOG_DEBUG(100) 396#define DEF_LEVEL ISC_LOG_DEBUG(5) 397#define NCACHE_LEVEL ISC_LOG_DEBUG(20) 398 399#define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \ 400 (r) == DNS_R_NCACHENXRRSET) 401#define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \ 402 (r) == DNS_R_NXRRSET) 403#define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \ 404 (r) == DNS_R_NCACHENXDOMAIN) 405#define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \ 406 (r) == DNS_R_NXRRSET || \ 407 (r) == DNS_R_HINTNXRRSET) 408 409/* 410 * Error state rankings. 411 */ 412 413#define FIND_ERR_SUCCESS 0 /* highest rank */ 414#define FIND_ERR_CANCELED 1 415#define FIND_ERR_FAILURE 2 416#define FIND_ERR_NXDOMAIN 3 417#define FIND_ERR_NXRRSET 4 418#define FIND_ERR_UNEXPECTED 5 419#define FIND_ERR_NOTFOUND 6 420#define FIND_ERR_MAX 7 421 422static const char *errnames[] = { 423 "success", 424 "canceled", 425 "failure", 426 "nxdomain", 427 "nxrrset", 428 "unexpected", 429 "not_found" 430}; 431 432#define NEWERR(old, new) (ISC_MIN((old), (new))) 433 434static isc_result_t find_err_map[FIND_ERR_MAX] = { 435 ISC_R_SUCCESS, 436 ISC_R_CANCELED, 437 ISC_R_FAILURE, 438 DNS_R_NXDOMAIN, 439 DNS_R_NXRRSET, 440 ISC_R_UNEXPECTED, 441 ISC_R_NOTFOUND /* not YET found */ 442}; 443 444static void 445DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3); 446 447static void 448DP(int level, const char *format, ...) { 449 va_list args; 450 451 va_start(args, format); 452 isc_log_vwrite(dns_lctx, 453 DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB, 454 level, format, args); 455 va_end(args); 456} 457 458static inline dns_ttl_t 459ttlclamp(dns_ttl_t ttl) { 460 if (ttl < ADB_CACHE_MINIMUM) 461 ttl = ADB_CACHE_MINIMUM; 462 if (ttl > ADB_CACHE_MAXIMUM) 463 ttl = ADB_CACHE_MAXIMUM; 464 465 return (ttl); 466} 467 468/* 469 * Requires the adbname bucket be locked and that no entry buckets be locked. 470 * 471 * This code handles A and AAAA rdatasets only. 472 */ 473static isc_result_t 474import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset, 475 isc_stdtime_t now) 476{ 477 isc_result_t result; 478 dns_adb_t *adb; 479 dns_adbnamehook_t *nh; 480 dns_adbnamehook_t *anh; 481 dns_rdata_t rdata = DNS_RDATA_INIT; 482 struct in_addr ina; 483 struct in6_addr in6a; 484 isc_sockaddr_t sockaddr; 485 dns_adbentry_t *foundentry; /* NO CLEAN UP! */ 486 int addr_bucket; 487 isc_boolean_t new_addresses_added; 488 dns_rdatatype_t rdtype; 489 unsigned int findoptions; 490 491 INSIST(DNS_ADBNAME_VALID(adbname)); 492 adb = adbname->adb; 493 INSIST(DNS_ADB_VALID(adb)); 494 495 rdtype = rdataset->type; 496 INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa)); 497 if (rdtype == dns_rdatatype_a) 498 findoptions = DNS_ADBFIND_INET; 499 else 500 findoptions = DNS_ADBFIND_INET6; 501 502 addr_bucket = DNS_ADB_INVALIDBUCKET; 503 new_addresses_added = ISC_FALSE; 504 505 nh = NULL; 506 result = dns_rdataset_first(rdataset); 507 while (result == ISC_R_SUCCESS) { 508 dns_rdata_reset(&rdata); 509 dns_rdataset_current(rdataset, &rdata); 510 if (rdtype == dns_rdatatype_a) { 511 INSIST(rdata.length == 4); 512 memcpy(&ina.s_addr, rdata.data, 4); 513 isc_sockaddr_fromin(&sockaddr, &ina, 0); 514 } else { 515 INSIST(rdata.length == 16); 516 memcpy(in6a.s6_addr, rdata.data, 16); 517 isc_sockaddr_fromin6(&sockaddr, &in6a, 0); 518 } 519 520 INSIST(nh == NULL); 521 nh = new_adbnamehook(adb, NULL); 522 if (nh == NULL) { 523 adbname->partial_result |= findoptions; 524 result = ISC_R_NOMEMORY; 525 goto fail; 526 } 527 528 foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket); 529 if (foundentry == NULL) { 530 dns_adbentry_t *entry; 531 532 entry = new_adbentry(adb); 533 if (entry == NULL) { 534 adbname->partial_result |= findoptions; 535 result = ISC_R_NOMEMORY; 536 goto fail; 537 } 538 539 entry->sockaddr = sockaddr; 540 entry->refcnt = 1; 541 542 nh->entry = entry; 543 544 link_entry(adb, addr_bucket, entry); 545 } else { 546 for (anh = ISC_LIST_HEAD(adbname->v4); 547 anh != NULL; 548 anh = ISC_LIST_NEXT(anh, plink)) 549 if (anh->entry == foundentry) 550 break; 551 if (anh == NULL) { 552 foundentry->refcnt++; 553 nh->entry = foundentry; 554 } else 555 free_adbnamehook(adb, &nh); 556 } 557 558 new_addresses_added = ISC_TRUE; 559 if (nh != NULL) { 560 if (rdtype == dns_rdatatype_a) 561 ISC_LIST_APPEND(adbname->v4, nh, plink); 562 else 563 ISC_LIST_APPEND(adbname->v6, nh, plink); 564 } 565 nh = NULL; 566 result = dns_rdataset_next(rdataset); 567 } 568 569 fail: 570 if (nh != NULL) 571 free_adbnamehook(adb, &nh); 572 573 if (addr_bucket != DNS_ADB_INVALIDBUCKET) 574 UNLOCK(&adb->entrylocks[addr_bucket]); 575 576 if (rdataset->trust == dns_trust_glue || 577 rdataset->trust == dns_trust_additional) 578 rdataset->ttl = ADB_CACHE_MINIMUM; 579 else 580 rdataset->ttl = ttlclamp(rdataset->ttl); 581 582 if (rdtype == dns_rdatatype_a) { 583 DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset", 584 adbname->expire_v4, now + rdataset->ttl); 585 adbname->expire_v4 = ISC_MIN(adbname->expire_v4, 586 now + rdataset->ttl); 587 } else { 588 DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset", 589 adbname->expire_v6, now + rdataset->ttl); 590 adbname->expire_v6 = ISC_MIN(adbname->expire_v6, 591 now + rdataset->ttl); 592 } 593 594 if (new_addresses_added) { 595 /* 596 * Lie a little here. This is more or less so code that cares 597 * can find out if any new information was added or not. 598 */ 599 return (ISC_R_SUCCESS); 600 } 601 602 return (result); 603} 604 605/* 606 * Requires the name's bucket be locked. 607 */ 608static isc_boolean_t 609kill_name(dns_adbname_t **n, isc_eventtype_t ev) { 610 dns_adbname_t *name; 611 isc_boolean_t result = ISC_FALSE; 612 isc_boolean_t result4, result6; 613 dns_adb_t *adb; 614 615 INSIST(n != NULL); 616 name = *n; 617 *n = NULL; 618 INSIST(DNS_ADBNAME_VALID(name)); 619 adb = name->adb; 620 INSIST(DNS_ADB_VALID(adb)); 621 622 DP(DEF_LEVEL, "killing name %p", name); 623 624 /* 625 * If we're dead already, just check to see if we should go 626 * away now or not. 627 */ 628 if (NAME_DEAD(name) && !NAME_FETCH(name)) { 629 result = unlink_name(adb, name); 630 free_adbname(adb, &name); 631 if (result) 632 result = dec_adb_irefcnt(adb); 633 return (result); 634 } 635 636 /* 637 * Clean up the name's various lists. These two are destructive 638 * in that they will always empty the list. 639 */ 640 clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK); 641 result4 = clean_namehooks(adb, &name->v4); 642 result6 = clean_namehooks(adb, &name->v6); 643 clean_target(adb, &name->target); 644 result = ISC_TF(result4 || result6); 645 646 /* 647 * If fetches are running, cancel them. If none are running, we can 648 * just kill the name here. 649 */ 650 if (!NAME_FETCH(name)) { 651 INSIST(result == ISC_FALSE); 652 result = unlink_name(adb, name); 653 free_adbname(adb, &name); 654 if (result) 655 result = dec_adb_irefcnt(adb); 656 } else { 657 name->flags |= NAME_IS_DEAD; 658 cancel_fetches_at_name(name); 659 } 660 return (result); 661} 662 663/* 664 * Requires the name's bucket be locked and no entry buckets be locked. 665 */ 666static isc_boolean_t 667check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now, 668 isc_boolean_t overmem) 669{ 670 dns_adb_t *adb; 671 isc_boolean_t expire; 672 isc_boolean_t result4 = ISC_FALSE; 673 isc_boolean_t result6 = ISC_FALSE; 674 675 INSIST(DNS_ADBNAME_VALID(name)); 676 adb = name->adb; 677 INSIST(DNS_ADB_VALID(adb)); 678 679 if (overmem) { 680 isc_uint32_t val; 681 682 isc_random_get(&val); 683 684 expire = ISC_TF((val % 4) == 0); 685 } else 686 expire = ISC_FALSE; 687 688 /* 689 * Check to see if we need to remove the v4 addresses 690 */ 691 if (!NAME_FETCH_V4(name) && 692 (expire || EXPIRE_OK(name->expire_v4, now))) { 693 if (NAME_HAS_V4(name)) { 694 DP(DEF_LEVEL, "expiring v4 for name %p", name); 695 result4 = clean_namehooks(adb, &name->v4); 696 name->partial_result &= ~DNS_ADBFIND_INET; 697 } 698 name->expire_v4 = INT_MAX; 699 name->fetch_err = FIND_ERR_UNEXPECTED; 700 } 701 702 /* 703 * Check to see if we need to remove the v6 addresses 704 */ 705 if (!NAME_FETCH_V6(name) && 706 (expire || EXPIRE_OK(name->expire_v6, now))) { 707 if (NAME_HAS_V6(name)) { 708 DP(DEF_LEVEL, "expiring v6 for name %p", name); 709 result6 = clean_namehooks(adb, &name->v6); 710 name->partial_result &= ~DNS_ADBFIND_INET6; 711 } 712 name->expire_v6 = INT_MAX; 713 name->fetch6_err = FIND_ERR_UNEXPECTED; 714 } 715 716 /* 717 * Check to see if we need to remove the alias target. 718 */ 719 if (expire || EXPIRE_OK(name->expire_target, now)) { 720 clean_target(adb, &name->target); 721 name->expire_target = INT_MAX; 722 } 723 return (ISC_TF(result4 || result6)); 724} 725 726/* 727 * Requires the name's bucket be locked. 728 */ 729static inline void 730link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) { 731 INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET); 732 733 ISC_LIST_PREPEND(adb->names[bucket], name, plink); 734 name->lock_bucket = bucket; 735 adb->name_refcnt[bucket]++; 736} 737 738/* 739 * Requires the name's bucket be locked. 740 */ 741static inline isc_boolean_t 742unlink_name(dns_adb_t *adb, dns_adbname_t *name) { 743 int bucket; 744 isc_boolean_t result = ISC_FALSE; 745 746 bucket = name->lock_bucket; 747 INSIST(bucket != DNS_ADB_INVALIDBUCKET); 748 749 ISC_LIST_UNLINK(adb->names[bucket], name, plink); 750 name->lock_bucket = DNS_ADB_INVALIDBUCKET; 751 INSIST(adb->name_refcnt[bucket] > 0); 752 adb->name_refcnt[bucket]--; 753 if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0) 754 result = ISC_TRUE; 755 return (result); 756} 757 758/* 759 * Requires the entry's bucket be locked. 760 */ 761static inline void 762link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) { 763 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink); 764 entry->lock_bucket = bucket; 765 adb->entry_refcnt[bucket]++; 766} 767 768/* 769 * Requires the entry's bucket be locked. 770 */ 771static inline isc_boolean_t 772unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) { 773 int bucket; 774 isc_boolean_t result = ISC_FALSE; 775 776 bucket = entry->lock_bucket; 777 INSIST(bucket != DNS_ADB_INVALIDBUCKET); 778 779 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink); 780 entry->lock_bucket = DNS_ADB_INVALIDBUCKET; 781 INSIST(adb->entry_refcnt[bucket] > 0); 782 adb->entry_refcnt[bucket]--; 783 if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0) 784 result = ISC_TRUE; 785 return (result); 786} 787 788static inline void 789violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) { 790 if (isc_mutex_trylock(want) != ISC_R_SUCCESS) { 791 UNLOCK(have); 792 LOCK(want); 793 LOCK(have); 794 } 795} 796 797/* 798 * The ADB _MUST_ be locked before calling. Also, exit conditions must be 799 * checked after calling this function. 800 */ 801static isc_boolean_t 802shutdown_names(dns_adb_t *adb) { 803 int bucket; 804 isc_boolean_t result = ISC_FALSE; 805 dns_adbname_t *name; 806 dns_adbname_t *next_name; 807 808 for (bucket = 0; bucket < NBUCKETS; bucket++) { 809 LOCK(&adb->namelocks[bucket]); 810 adb->name_sd[bucket] = ISC_TRUE; 811 812 name = ISC_LIST_HEAD(adb->names[bucket]); 813 if (name == NULL) { 814 /* 815 * This bucket has no names. We must decrement the 816 * irefcnt ourselves, since it will not be 817 * automatically triggered by a name being unlinked. 818 */ 819 INSIST(result == ISC_FALSE); 820 result = dec_adb_irefcnt(adb); 821 } else { 822 /* 823 * Run through the list. For each name, clean up finds 824 * found there, and cancel any fetches running. When 825 * all the fetches are canceled, the name will destroy 826 * itself. 827 */ 828 while (name != NULL) { 829 next_name = ISC_LIST_NEXT(name, plink); 830 INSIST(result == ISC_FALSE); 831 result = kill_name(&name, 832 DNS_EVENT_ADBSHUTDOWN); 833 name = next_name; 834 } 835 } 836 837 UNLOCK(&adb->namelocks[bucket]); 838 } 839 return (result); 840} 841 842/* 843 * The ADB _MUST_ be locked before calling. Also, exit conditions must be 844 * checked after calling this function. 845 */ 846static isc_boolean_t 847shutdown_entries(dns_adb_t *adb) { 848 int bucket; 849 isc_boolean_t result = ISC_FALSE; 850 dns_adbentry_t *entry; 851 dns_adbentry_t *next_entry; 852 853 for (bucket = 0; bucket < NBUCKETS; bucket++) { 854 LOCK(&adb->entrylocks[bucket]); 855 adb->entry_sd[bucket] = ISC_TRUE; 856 857 entry = ISC_LIST_HEAD(adb->entries[bucket]); 858 if (entry == NULL) { 859 /* 860 * This bucket has no entries. We must decrement the 861 * irefcnt ourselves, since it will not be 862 * automatically triggered by an entry being unlinked. 863 */ 864 result = dec_adb_irefcnt(adb); 865 } else { 866 /* 867 * Run through the list. Cleanup any entries not 868 * associated with names, and which are not in use. 869 */ 870 while (entry != NULL) { 871 next_entry = ISC_LIST_NEXT(entry, plink); 872 if (entry->refcnt == 0 && 873 entry->expires != 0) { 874 result = unlink_entry(adb, entry); 875 free_adbentry(adb, &entry); 876 if (result) 877 result = dec_adb_irefcnt(adb); 878 } 879 entry = next_entry; 880 } 881 } 882 883 UNLOCK(&adb->entrylocks[bucket]); 884 } 885 return (result); 886} 887 888/* 889 * Name bucket must be locked 890 */ 891static void 892cancel_fetches_at_name(dns_adbname_t *name) { 893 if (NAME_FETCH_A(name)) 894 dns_resolver_cancelfetch(name->fetch_a->fetch); 895 896 if (NAME_FETCH_AAAA(name)) 897 dns_resolver_cancelfetch(name->fetch_aaaa->fetch); 898} 899 900/* 901 * Assumes the name bucket is locked. 902 */ 903static isc_boolean_t 904clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) { 905 dns_adbentry_t *entry; 906 dns_adbnamehook_t *namehook; 907 int addr_bucket; 908 isc_boolean_t result = ISC_FALSE; 909 910 addr_bucket = DNS_ADB_INVALIDBUCKET; 911 namehook = ISC_LIST_HEAD(*namehooks); 912 while (namehook != NULL) { 913 INSIST(DNS_ADBNAMEHOOK_VALID(namehook)); 914 915 /* 916 * Clean up the entry if needed. 917 */ 918 entry = namehook->entry; 919 if (entry != NULL) { 920 INSIST(DNS_ADBENTRY_VALID(entry)); 921 922 if (addr_bucket != entry->lock_bucket) { 923 if (addr_bucket != DNS_ADB_INVALIDBUCKET) 924 UNLOCK(&adb->entrylocks[addr_bucket]); 925 addr_bucket = entry->lock_bucket; 926 LOCK(&adb->entrylocks[addr_bucket]); 927 } 928 929 result = dec_entry_refcnt(adb, entry, ISC_FALSE); 930 } 931 932 /* 933 * Free the namehook 934 */ 935 namehook->entry = NULL; 936 ISC_LIST_UNLINK(*namehooks, namehook, plink); 937 free_adbnamehook(adb, &namehook); 938 939 namehook = ISC_LIST_HEAD(*namehooks); 940 } 941 942 if (addr_bucket != DNS_ADB_INVALIDBUCKET) 943 UNLOCK(&adb->entrylocks[addr_bucket]); 944 return (result); 945} 946 947static void 948clean_target(dns_adb_t *adb, dns_name_t *target) { 949 if (dns_name_countlabels(target) > 0) { 950 dns_name_free(target, adb->mctx); 951 dns_name_init(target, NULL); 952 } 953} 954 955static isc_result_t 956set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname, 957 dns_rdataset_t *rdataset, dns_name_t *target) 958{ 959 isc_result_t result; 960 dns_namereln_t namereln; 961 unsigned int nlabels; 962 int order; 963 dns_rdata_t rdata = DNS_RDATA_INIT; 964 dns_fixedname_t fixed1, fixed2; 965 dns_name_t *prefix, *new_target; 966 967 REQUIRE(dns_name_countlabels(target) == 0); 968 969 if (rdataset->type == dns_rdatatype_cname) { 970 dns_rdata_cname_t cname; 971 972 /* 973 * Copy the CNAME's target into the target name. 974 */ 975 result = dns_rdataset_first(rdataset); 976 if (result != ISC_R_SUCCESS) 977 return (result); 978 dns_rdataset_current(rdataset, &rdata); 979 result = dns_rdata_tostruct(&rdata, &cname, NULL); 980 if (result != ISC_R_SUCCESS) 981 return (result); 982 result = dns_name_dup(&cname.cname, adb->mctx, target); 983 dns_rdata_freestruct(&cname); 984 if (result != ISC_R_SUCCESS) 985 return (result); 986 } else { 987 dns_rdata_dname_t dname; 988 989 INSIST(rdataset->type == dns_rdatatype_dname); 990 namereln = dns_name_fullcompare(name, fname, &order, &nlabels); 991 INSIST(namereln == dns_namereln_subdomain); 992 /* 993 * Get the target name of the DNAME. 994 */ 995 result = dns_rdataset_first(rdataset); 996 if (result != ISC_R_SUCCESS) 997 return (result); 998 dns_rdataset_current(rdataset, &rdata); 999 result = dns_rdata_tostruct(&rdata, &dname, NULL); 1000 if (result != ISC_R_SUCCESS) 1001 return (result); 1002 /* 1003 * Construct the new target name. 1004 */ 1005 dns_fixedname_init(&fixed1); 1006 prefix = dns_fixedname_name(&fixed1); 1007 dns_fixedname_init(&fixed2); 1008 new_target = dns_fixedname_name(&fixed2); 1009 dns_name_split(name, nlabels, prefix, NULL); 1010 result = dns_name_concatenate(prefix, &dname.dname, new_target, 1011 NULL); 1012 dns_rdata_freestruct(&dname); 1013 if (result != ISC_R_SUCCESS) 1014 return (result); 1015 result = dns_name_dup(new_target, adb->mctx, target); 1016 if (result != ISC_R_SUCCESS) 1017 return (result); 1018 } 1019 1020 return (ISC_R_SUCCESS); 1021} 1022 1023/* 1024 * Assumes nothing is locked, since this is called by the client. 1025 */ 1026static void 1027event_free(isc_event_t *event) { 1028 dns_adbfind_t *find; 1029 1030 INSIST(event != NULL); 1031 find = event->ev_destroy_arg; 1032 INSIST(DNS_ADBFIND_VALID(find)); 1033 1034 LOCK(&find->lock); 1035 find->flags |= FIND_EVENT_FREED; 1036 event->ev_destroy_arg = NULL; 1037 UNLOCK(&find->lock); 1038} 1039 1040/* 1041 * Assumes the name bucket is locked. 1042 */ 1043static void 1044clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype, 1045 unsigned int addrs) 1046{ 1047 isc_event_t *ev; 1048 isc_task_t *task; 1049 dns_adbfind_t *find; 1050 dns_adbfind_t *next_find; 1051 isc_boolean_t process; 1052 unsigned int wanted, notify; 1053 1054 DP(ENTER_LEVEL, 1055 "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x", 1056 name, evtype, addrs); 1057 1058 find = ISC_LIST_HEAD(name->finds); 1059 while (find != NULL) { 1060 LOCK(&find->lock); 1061 next_find = ISC_LIST_NEXT(find, plink); 1062 1063 process = ISC_FALSE; 1064 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK; 1065 notify = wanted & addrs; 1066 1067 switch (evtype) { 1068 case DNS_EVENT_ADBMOREADDRESSES: 1069 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES"); 1070 if ((notify) != 0) { 1071 find->flags &= ~addrs; 1072 process = ISC_TRUE; 1073 } 1074 break; 1075 case DNS_EVENT_ADBNOMOREADDRESSES: 1076 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES"); 1077 find->flags &= ~addrs; 1078 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK; 1079 if (wanted == 0) 1080 process = ISC_TRUE; 1081 break; 1082 default: 1083 find->flags &= ~addrs; 1084 process = ISC_TRUE; 1085 } 1086 1087 if (process) { 1088 DP(DEF_LEVEL, "cfan: processing find %p", find); 1089 /* 1090 * Unlink the find from the name, letting the caller 1091 * call dns_adb_destroyfind() on it to clean it up 1092 * later. 1093 */ 1094 ISC_LIST_UNLINK(name->finds, find, plink); 1095 find->adbname = NULL; 1096 find->name_bucket = DNS_ADB_INVALIDBUCKET; 1097 1098 INSIST(!FIND_EVENTSENT(find)); 1099 1100 ev = &find->event; 1101 task = ev->ev_sender; 1102 ev->ev_sender = find; 1103 find->result_v4 = find_err_map[name->fetch_err]; 1104 find->result_v6 = find_err_map[name->fetch6_err]; 1105 ev->ev_type = evtype; 1106 ev->ev_destroy = event_free; 1107 ev->ev_destroy_arg = find; 1108 1109 DP(DEF_LEVEL, 1110 "sending event %p to task %p for find %p", 1111 ev, task, find); 1112 1113 isc_task_sendanddetach(&task, (isc_event_t **)&ev); 1114 } else { 1115 DP(DEF_LEVEL, "cfan: skipping find %p", find); 1116 } 1117 1118 UNLOCK(&find->lock); 1119 find = next_find; 1120 } 1121 1122 DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name); 1123} 1124 1125static inline void 1126check_exit(dns_adb_t *adb) { 1127 isc_event_t *event; 1128 /* 1129 * The caller must be holding the adb lock. 1130 */ 1131 if (adb->shutting_down) { 1132 /* 1133 * If there aren't any external references either, we're 1134 * done. Send the control event to initiate shutdown. 1135 */ 1136 INSIST(!adb->cevent_sent); /* Sanity check. */ 1137 event = &adb->cevent; 1138 isc_task_send(adb->task, &event); 1139 adb->cevent_sent = ISC_TRUE; 1140 } 1141} 1142 1143static inline isc_boolean_t 1144dec_adb_irefcnt(dns_adb_t *adb) { 1145 isc_event_t *event; 1146 isc_task_t *etask; 1147 isc_boolean_t result = ISC_FALSE; 1148 1149 LOCK(&adb->reflock); 1150 1151 INSIST(adb->irefcnt > 0); 1152 adb->irefcnt--; 1153 1154 if (adb->irefcnt == 0) { 1155 event = ISC_LIST_HEAD(adb->whenshutdown); 1156 while (event != NULL) { 1157 ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link); 1158 etask = event->ev_sender; 1159 event->ev_sender = adb; 1160 isc_task_sendanddetach(&etask, &event); 1161 event = ISC_LIST_HEAD(adb->whenshutdown); 1162 } 1163 } 1164 1165 if (adb->irefcnt == 0 && adb->erefcnt == 0) 1166 result = ISC_TRUE; 1167 UNLOCK(&adb->reflock); 1168 return (result); 1169} 1170 1171static inline void 1172inc_adb_irefcnt(dns_adb_t *adb) { 1173 LOCK(&adb->reflock); 1174 adb->irefcnt++; 1175 UNLOCK(&adb->reflock); 1176} 1177 1178static inline void 1179inc_adb_erefcnt(dns_adb_t *adb) { 1180 LOCK(&adb->reflock); 1181 adb->erefcnt++; 1182 UNLOCK(&adb->reflock); 1183} 1184 1185static inline void 1186inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) { 1187 int bucket; 1188 1189 bucket = entry->lock_bucket; 1190 1191 if (lock) 1192 LOCK(&adb->entrylocks[bucket]); 1193 1194 entry->refcnt++; 1195 1196 if (lock) 1197 UNLOCK(&adb->entrylocks[bucket]); 1198} 1199 1200static inline isc_boolean_t 1201dec_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) { 1202 int bucket; 1203 isc_boolean_t destroy_entry; 1204 isc_boolean_t result = ISC_FALSE; 1205 1206 bucket = entry->lock_bucket; 1207 1208 if (lock) 1209 LOCK(&adb->entrylocks[bucket]); 1210 1211 INSIST(entry->refcnt > 0); 1212 entry->refcnt--; 1213 1214 destroy_entry = ISC_FALSE; 1215 if (entry->refcnt == 0 && 1216 (adb->entry_sd[bucket] || entry->expires == 0)) { 1217 destroy_entry = ISC_TRUE; 1218 result = unlink_entry(adb, entry); 1219 } 1220 1221 if (lock) 1222 UNLOCK(&adb->entrylocks[bucket]); 1223 1224 if (!destroy_entry) 1225 return (result); 1226 1227 entry->lock_bucket = DNS_ADB_INVALIDBUCKET; 1228 1229 free_adbentry(adb, &entry); 1230 if (result) 1231 result =dec_adb_irefcnt(adb); 1232 1233 return (result); 1234} 1235 1236static inline dns_adbname_t * 1237new_adbname(dns_adb_t *adb, dns_name_t *dnsname) { 1238 dns_adbname_t *name; 1239 1240 name = isc_mempool_get(adb->nmp); 1241 if (name == NULL) 1242 return (NULL); 1243 1244 dns_name_init(&name->name, NULL); 1245 if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) { 1246 isc_mempool_put(adb->nmp, name); 1247 return (NULL); 1248 } 1249 dns_name_init(&name->target, NULL); 1250 name->magic = DNS_ADBNAME_MAGIC; 1251 name->adb = adb; 1252 name->partial_result = 0; 1253 name->flags = 0; 1254 name->expire_v4 = INT_MAX; 1255 name->expire_v6 = INT_MAX; 1256 name->expire_target = INT_MAX; 1257 name->chains = 0; 1258 name->lock_bucket = DNS_ADB_INVALIDBUCKET; 1259 ISC_LIST_INIT(name->v4); 1260 ISC_LIST_INIT(name->v6); 1261 name->fetch_a = NULL; 1262 name->fetch_aaaa = NULL; 1263 name->fetch_err = FIND_ERR_UNEXPECTED; 1264 name->fetch6_err = FIND_ERR_UNEXPECTED; 1265 ISC_LIST_INIT(name->finds); 1266 ISC_LINK_INIT(name, plink); 1267 1268 return (name); 1269} 1270 1271static inline void 1272free_adbname(dns_adb_t *adb, dns_adbname_t **name) { 1273 dns_adbname_t *n; 1274 1275 INSIST(name != NULL && DNS_ADBNAME_VALID(*name)); 1276 n = *name; 1277 *name = NULL; 1278 1279 INSIST(!NAME_HAS_V4(n)); 1280 INSIST(!NAME_HAS_V6(n)); 1281 INSIST(!NAME_FETCH(n)); 1282 INSIST(ISC_LIST_EMPTY(n->finds)); 1283 INSIST(!ISC_LINK_LINKED(n, plink)); 1284 INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET); 1285 INSIST(n->adb == adb); 1286 1287 n->magic = 0; 1288 dns_name_free(&n->name, adb->mctx); 1289 1290 isc_mempool_put(adb->nmp, n); 1291} 1292 1293static inline dns_adbnamehook_t * 1294new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) { 1295 dns_adbnamehook_t *nh; 1296 1297 nh = isc_mempool_get(adb->nhmp); 1298 if (nh == NULL) 1299 return (NULL); 1300 1301 nh->magic = DNS_ADBNAMEHOOK_MAGIC; 1302 nh->entry = entry; 1303 ISC_LINK_INIT(nh, plink); 1304 1305 return (nh); 1306} 1307 1308static inline void 1309free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) { 1310 dns_adbnamehook_t *nh; 1311 1312 INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook)); 1313 nh = *namehook; 1314 *namehook = NULL; 1315 1316 INSIST(nh->entry == NULL); 1317 INSIST(!ISC_LINK_LINKED(nh, plink)); 1318 1319 nh->magic = 0; 1320 isc_mempool_put(adb->nhmp, nh); 1321} 1322 1323static inline dns_adbzoneinfo_t * 1324new_adbzoneinfo(dns_adb_t *adb, dns_name_t *zone) { 1325 dns_adbzoneinfo_t *zi; 1326 1327 zi = isc_mempool_get(adb->zimp); 1328 if (zi == NULL) 1329 return (NULL); 1330 1331 dns_name_init(&zi->zone, NULL); 1332 if (dns_name_dup(zone, adb->mctx, &zi->zone) != ISC_R_SUCCESS) { 1333 isc_mempool_put(adb->zimp, zi); 1334 return (NULL); 1335 } 1336 1337 zi->magic = DNS_ADBZONEINFO_MAGIC; 1338 zi->lame_timer = 0; 1339 ISC_LINK_INIT(zi, plink); 1340 1341 return (zi); 1342} 1343 1344static inline void 1345free_adbzoneinfo(dns_adb_t *adb, dns_adbzoneinfo_t **zoneinfo) { 1346 dns_adbzoneinfo_t *zi; 1347 1348 INSIST(zoneinfo != NULL && DNS_ADBZONEINFO_VALID(*zoneinfo)); 1349 zi = *zoneinfo; 1350 *zoneinfo = NULL; 1351 1352 INSIST(!ISC_LINK_LINKED(zi, plink)); 1353 1354 dns_name_free(&zi->zone, adb->mctx); 1355 1356 zi->magic = 0; 1357 1358 isc_mempool_put(adb->zimp, zi); 1359} 1360 1361static inline dns_adbentry_t * 1362new_adbentry(dns_adb_t *adb) { 1363 dns_adbentry_t *e; 1364 isc_uint32_t r; 1365 1366 e = isc_mempool_get(adb->emp); 1367 if (e == NULL) 1368 return (NULL); 1369 1370 e->magic = DNS_ADBENTRY_MAGIC; 1371 e->lock_bucket = DNS_ADB_INVALIDBUCKET; 1372 e->refcnt = 0; 1373 e->flags = 0; 1374 isc_random_get(&r); 1375 e->srtt = (r & 0x1f) + 1; 1376 e->expires = 0; 1377 ISC_LIST_INIT(e->zoneinfo); 1378 ISC_LINK_INIT(e, plink); 1379 1380 return (e); 1381} 1382 1383static inline void 1384free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) { 1385 dns_adbentry_t *e; 1386 dns_adbzoneinfo_t *zi; 1387 1388 INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry)); 1389 e = *entry; 1390 *entry = NULL; 1391 1392 INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET); 1393 INSIST(e->refcnt == 0); 1394 INSIST(!ISC_LINK_LINKED(e, plink)); 1395 1396 e->magic = 0; 1397 1398 zi = ISC_LIST_HEAD(e->zoneinfo); 1399 while (zi != NULL) { 1400 ISC_LIST_UNLINK(e->zoneinfo, zi, plink); 1401 free_adbzoneinfo(adb, &zi); 1402 zi = ISC_LIST_HEAD(e->zoneinfo); 1403 } 1404 1405 isc_mempool_put(adb->emp, e); 1406} 1407 1408static inline dns_adbfind_t * 1409new_adbfind(dns_adb_t *adb) { 1410 dns_adbfind_t *h; 1411 isc_result_t result; 1412 1413 h = isc_mempool_get(adb->ahmp); 1414 if (h == NULL) 1415 return (NULL); 1416 1417 /* 1418 * Public members. 1419 */ 1420 h->magic = 0; 1421 h->adb = adb; 1422 h->partial_result = 0; 1423 h->options = 0; 1424 h->flags = 0; 1425 h->result_v4 = ISC_R_UNEXPECTED; 1426 h->result_v6 = ISC_R_UNEXPECTED; 1427 ISC_LINK_INIT(h, publink); 1428 ISC_LINK_INIT(h, plink); 1429 ISC_LIST_INIT(h->list); 1430 h->adbname = NULL; 1431 h->name_bucket = DNS_ADB_INVALIDBUCKET; 1432 1433 /* 1434 * private members 1435 */ 1436 result = isc_mutex_init(&h->lock); 1437 if (result != ISC_R_SUCCESS) { 1438 UNEXPECTED_ERROR(__FILE__, __LINE__, 1439 "isc_mutex_init failed in new_adbfind()"); 1440 isc_mempool_put(adb->ahmp, h); 1441 return (NULL); 1442 } 1443 1444 ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL, 1445 NULL, NULL, h); 1446 1447 inc_adb_irefcnt(adb); 1448 h->magic = DNS_ADBFIND_MAGIC; 1449 return (h); 1450} 1451 1452static inline dns_adbfetch_t * 1453new_adbfetch(dns_adb_t *adb) { 1454 dns_adbfetch_t *f; 1455 1456 f = isc_mempool_get(adb->afmp); 1457 if (f == NULL) 1458 return (NULL); 1459 1460 f->magic = 0; 1461 f->namehook = NULL; 1462 f->entry = NULL; 1463 f->fetch = NULL; 1464 1465 f->namehook = new_adbnamehook(adb, NULL); 1466 if (f->namehook == NULL) 1467 goto err; 1468 1469 f->entry = new_adbentry(adb); 1470 if (f->entry == NULL) 1471 goto err; 1472 1473 dns_rdataset_init(&f->rdataset); 1474 1475 f->magic = DNS_ADBFETCH_MAGIC; 1476 1477 return (f); 1478 1479 err: 1480 if (f->namehook != NULL) 1481 free_adbnamehook(adb, &f->namehook); 1482 if (f->entry != NULL) 1483 free_adbentry(adb, &f->entry); 1484 isc_mempool_put(adb->afmp, f); 1485 return (NULL); 1486} 1487 1488static inline void 1489free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) { 1490 dns_adbfetch_t *f; 1491 1492 INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch)); 1493 f = *fetch; 1494 *fetch = NULL; 1495 1496 f->magic = 0; 1497 1498 if (f->namehook != NULL) 1499 free_adbnamehook(adb, &f->namehook); 1500 if (f->entry != NULL) 1501 free_adbentry(adb, &f->entry); 1502 1503 if (dns_rdataset_isassociated(&f->rdataset)) 1504 dns_rdataset_disassociate(&f->rdataset); 1505 1506 isc_mempool_put(adb->afmp, f); 1507} 1508 1509static inline isc_boolean_t 1510free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) { 1511 dns_adbfind_t *find; 1512 1513 INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp)); 1514 find = *findp; 1515 *findp = NULL; 1516 1517 INSIST(!FIND_HAS_ADDRS(find)); 1518 INSIST(!ISC_LINK_LINKED(find, publink)); 1519 INSIST(!ISC_LINK_LINKED(find, plink)); 1520 INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET); 1521 INSIST(find->adbname == NULL); 1522 1523 find->magic = 0; 1524 1525 DESTROYLOCK(&find->lock); 1526 isc_mempool_put(adb->ahmp, find); 1527 return (dec_adb_irefcnt(adb)); 1528} 1529 1530/* 1531 * Copy bits from the entry into the newly allocated addrinfo. The entry 1532 * must be locked, and the reference count must be bumped up by one 1533 * if this function returns a valid pointer. 1534 */ 1535static inline dns_adbaddrinfo_t * 1536new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) { 1537 dns_adbaddrinfo_t *ai; 1538 1539 ai = isc_mempool_get(adb->aimp); 1540 if (ai == NULL) 1541 return (NULL); 1542 1543 ai->magic = DNS_ADBADDRINFO_MAGIC; 1544 ai->sockaddr = entry->sockaddr; 1545 isc_sockaddr_setport(&ai->sockaddr, port); 1546 ai->srtt = entry->srtt; 1547 ai->flags = entry->flags; 1548 ai->entry = entry; 1549 ISC_LINK_INIT(ai, publink); 1550 1551 return (ai); 1552} 1553 1554static inline void 1555free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) { 1556 dns_adbaddrinfo_t *ai; 1557 1558 INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo)); 1559 ai = *ainfo; 1560 *ainfo = NULL; 1561 1562 INSIST(ai->entry == NULL); 1563 INSIST(!ISC_LINK_LINKED(ai, publink)); 1564 1565 ai->magic = 0; 1566 1567 isc_mempool_put(adb->aimp, ai); 1568} 1569 1570/* 1571 * Search for the name. NOTE: The bucket is kept locked on both 1572 * success and failure, so it must always be unlocked by the caller! 1573 * 1574 * On the first call to this function, *bucketp must be set to 1575 * DNS_ADB_INVALIDBUCKET. 1576 */ 1577static inline dns_adbname_t * 1578find_name_and_lock(dns_adb_t *adb, dns_name_t *name, 1579 unsigned int options, int *bucketp) 1580{ 1581 dns_adbname_t *adbname; 1582 int bucket; 1583 1584 bucket = dns_name_fullhash(name, ISC_FALSE) % NBUCKETS; 1585 1586 if (*bucketp == DNS_ADB_INVALIDBUCKET) { 1587 LOCK(&adb->namelocks[bucket]); 1588 *bucketp = bucket; 1589 } else if (*bucketp != bucket) { 1590 UNLOCK(&adb->namelocks[*bucketp]); 1591 LOCK(&adb->namelocks[bucket]); 1592 *bucketp = bucket; 1593 } 1594 1595 adbname = ISC_LIST_HEAD(adb->names[bucket]); 1596 while (adbname != NULL) { 1597 if (!NAME_DEAD(adbname)) { 1598 if (dns_name_equal(name, &adbname->name) 1599 && GLUEHINT_OK(adbname, options) 1600 && STARTATZONE_MATCHES(adbname, options)) 1601 return (adbname); 1602 } 1603 adbname = ISC_LIST_NEXT(adbname, plink); 1604 } 1605 1606 return (NULL); 1607} 1608 1609/* 1610 * Search for the address. NOTE: The bucket is kept locked on both 1611 * success and failure, so it must always be unlocked by the caller. 1612 * 1613 * On the first call to this function, *bucketp must be set to 1614 * DNS_ADB_INVALIDBUCKET. This will cause a lock to occur. On 1615 * later calls (within the same "lock path") it can be left alone, so 1616 * if this function is called multiple times locking is only done if 1617 * the bucket changes. 1618 */ 1619static inline dns_adbentry_t * 1620find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp) { 1621 dns_adbentry_t *entry; 1622 int bucket; 1623 1624 bucket = isc_sockaddr_hash(addr, ISC_TRUE) % NBUCKETS; 1625 1626 if (*bucketp == DNS_ADB_INVALIDBUCKET) { 1627 LOCK(&adb->entrylocks[bucket]); 1628 *bucketp = bucket; 1629 } else if (*bucketp != bucket) { 1630 UNLOCK(&adb->entrylocks[*bucketp]); 1631 LOCK(&adb->entrylocks[bucket]); 1632 *bucketp = bucket; 1633 } 1634 1635 entry = ISC_LIST_HEAD(adb->entries[bucket]); 1636 while (entry != NULL) { 1637 if (isc_sockaddr_equal(addr, &entry->sockaddr)) 1638 return (entry); 1639 entry = ISC_LIST_NEXT(entry, plink); 1640 } 1641 1642 return (NULL); 1643} 1644 1645/* 1646 * Entry bucket MUST be locked! 1647 */ 1648static isc_boolean_t 1649entry_is_bad_for_zone(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *zone, 1650 isc_stdtime_t now) 1651{ 1652 dns_adbzoneinfo_t *zi, *next_zi; 1653 isc_boolean_t is_bad; 1654 1655 is_bad = ISC_FALSE; 1656 1657 zi = ISC_LIST_HEAD(entry->zoneinfo); 1658 if (zi == NULL) 1659 return (ISC_FALSE); 1660 while (zi != NULL) { 1661 next_zi = ISC_LIST_NEXT(zi, plink); 1662 1663 /* 1664 * Has the entry expired? 1665 */ 1666 if (zi->lame_timer < now) { 1667 ISC_LIST_UNLINK(entry->zoneinfo, zi, plink); 1668 free_adbzoneinfo(adb, &zi); 1669 } 1670 1671 /* 1672 * Order tests from least to most expensive. 1673 */ 1674 if (zi != NULL && !is_bad) { 1675 if (dns_name_equal(zone, &zi->zone)) 1676 is_bad = ISC_TRUE; 1677 } 1678 1679 zi = next_zi; 1680 } 1681 1682 return (is_bad); 1683} 1684 1685static void 1686copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *zone, 1687 dns_adbname_t *name, isc_stdtime_t now) 1688{ 1689 dns_adbnamehook_t *namehook; 1690 dns_adbaddrinfo_t *addrinfo; 1691 dns_adbentry_t *entry; 1692 int bucket; 1693 1694 bucket = DNS_ADB_INVALIDBUCKET; 1695 1696 if (find->options & DNS_ADBFIND_INET) { 1697 namehook = ISC_LIST_HEAD(name->v4); 1698 while (namehook != NULL) { 1699 entry = namehook->entry; 1700 bucket = entry->lock_bucket; 1701 LOCK(&adb->entrylocks[bucket]); 1702 1703 if (!FIND_RETURNLAME(find) 1704 && entry_is_bad_for_zone(adb, entry, zone, now)) { 1705 find->options |= DNS_ADBFIND_LAMEPRUNED; 1706 goto nextv4; 1707 } 1708 addrinfo = new_adbaddrinfo(adb, entry, find->port); 1709 if (addrinfo == NULL) { 1710 find->partial_result |= DNS_ADBFIND_INET; 1711 goto out; 1712 } 1713 /* 1714 * Found a valid entry. Add it to the find's list. 1715 */ 1716 inc_entry_refcnt(adb, entry, ISC_FALSE); 1717 ISC_LIST_APPEND(find->list, addrinfo, publink); 1718 addrinfo = NULL; 1719 nextv4: 1720 UNLOCK(&adb->entrylocks[bucket]); 1721 bucket = DNS_ADB_INVALIDBUCKET; 1722 namehook = ISC_LIST_NEXT(namehook, plink); 1723 } 1724 } 1725 1726 if (find->options & DNS_ADBFIND_INET6) { 1727 namehook = ISC_LIST_HEAD(name->v6); 1728 while (namehook != NULL) { 1729 entry = namehook->entry; 1730 bucket = entry->lock_bucket; 1731 LOCK(&adb->entrylocks[bucket]); 1732 1733 if (entry_is_bad_for_zone(adb, entry, zone, now)) 1734 goto nextv6; 1735 addrinfo = new_adbaddrinfo(adb, entry, find->port); 1736 if (addrinfo == NULL) { 1737 find->partial_result |= DNS_ADBFIND_INET6; 1738 goto out; 1739 } 1740 /* 1741 * Found a valid entry. Add it to the find's list. 1742 */ 1743 inc_entry_refcnt(adb, entry, ISC_FALSE); 1744 ISC_LIST_APPEND(find->list, addrinfo, publink); 1745 addrinfo = NULL; 1746 nextv6: 1747 UNLOCK(&adb->entrylocks[bucket]); 1748 bucket = DNS_ADB_INVALIDBUCKET; 1749 namehook = ISC_LIST_NEXT(namehook, plink); 1750 } 1751 } 1752 1753 out: 1754 if (bucket != DNS_ADB_INVALIDBUCKET) 1755 UNLOCK(&adb->entrylocks[bucket]); 1756} 1757 1758static void 1759shutdown_task(isc_task_t *task, isc_event_t *ev) { 1760 dns_adb_t *adb; 1761 1762 UNUSED(task); 1763 1764 adb = ev->ev_arg; 1765 INSIST(DNS_ADB_VALID(adb)); 1766 1767 /* 1768 * Kill the timer, and then the ADB itself. Note that this implies 1769 * that this task was the one scheduled to get timer events. If 1770 * this is not true (and it is unfortunate there is no way to INSIST() 1771 * this) badness will occur. 1772 */ 1773 LOCK(&adb->lock); 1774 isc_timer_detach(&adb->timer); 1775 UNLOCK(&adb->lock); 1776 isc_event_free(&ev); 1777 destroy(adb); 1778} 1779 1780/* 1781 * Name bucket must be locked; adb may be locked; no other locks held. 1782 */ 1783static isc_boolean_t 1784check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) { 1785 dns_adbname_t *name; 1786 isc_result_t result = ISC_FALSE; 1787 1788 INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep)); 1789 name = *namep; 1790 1791 if (NAME_HAS_V4(name) || NAME_HAS_V6(name)) 1792 return (result); 1793 if (NAME_FETCH(name)) 1794 return (result); 1795 if (!EXPIRE_OK(name->expire_v4, now)) 1796 return (result); 1797 if (!EXPIRE_OK(name->expire_v6, now)) 1798 return (result); 1799 if (!EXPIRE_OK(name->expire_target, now)) 1800 return (result); 1801 1802 /* 1803 * The name is empty. Delete it. 1804 */ 1805 result = kill_name(&name, DNS_EVENT_ADBEXPIRED); 1806 *namep = NULL; 1807 1808 /* 1809 * Our caller, or one of its callers, will be calling check_exit() at 1810 * some point, so we don't need to do it here. 1811 */ 1812 return (result); 1813} 1814 1815/* 1816 * Entry bucket must be locked; adb may be locked; no other locks held. 1817 */ 1818static isc_boolean_t 1819check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now) 1820{ 1821 dns_adbentry_t *entry; 1822 isc_boolean_t expire; 1823 isc_boolean_t result = ISC_FALSE; 1824 1825 INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp)); 1826 entry = *entryp; 1827 1828 if (entry->refcnt != 0) 1829 return (result); 1830 1831 if (adb->overmem) { 1832 isc_uint32_t val; 1833 1834 isc_random_get(&val); 1835 1836 expire = ISC_TF((val % 4) == 0); 1837 } else 1838 expire = ISC_FALSE; 1839 1840 if (entry->expires == 0 || (! expire && entry->expires > now)) 1841 return (result); 1842 1843 /* 1844 * The entry is not in use. Delete it. 1845 */ 1846 DP(DEF_LEVEL, "killing entry %p", entry); 1847 INSIST(ISC_LINK_LINKED(entry, plink)); 1848 result = unlink_entry(adb, entry); 1849 free_adbentry(adb, &entry); 1850 if (result) 1851 dec_adb_irefcnt(adb); 1852 *entryp = NULL; 1853 return (result); 1854} 1855 1856/* 1857 * ADB must be locked, and no other locks held. 1858 */ 1859static isc_boolean_t 1860cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) { 1861 dns_adbname_t *name; 1862 dns_adbname_t *next_name; 1863 isc_result_t result = ISC_FALSE; 1864 1865 DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket); 1866 1867 LOCK(&adb->namelocks[bucket]); 1868 if (adb->name_sd[bucket]) { 1869 UNLOCK(&adb->namelocks[bucket]); 1870 return (result); 1871 } 1872 1873 name = ISC_LIST_HEAD(adb->names[bucket]); 1874 while (name != NULL) { 1875 next_name = ISC_LIST_NEXT(name, plink); 1876 INSIST(result == ISC_FALSE); 1877 result = check_expire_namehooks(name, now, adb->overmem); 1878 if (!result) 1879 result = check_expire_name(&name, now); 1880 name = next_name; 1881 } 1882 UNLOCK(&adb->namelocks[bucket]); 1883 return (result); 1884} 1885 1886/* 1887 * ADB must be locked, and no other locks held. 1888 */ 1889static isc_boolean_t 1890cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) { 1891 dns_adbentry_t *entry, *next_entry; 1892 isc_boolean_t result = ISC_FALSE; 1893 1894 DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket); 1895 1896 LOCK(&adb->entrylocks[bucket]); 1897 entry = ISC_LIST_HEAD(adb->entries[bucket]); 1898 while (entry != NULL) { 1899 next_entry = ISC_LIST_NEXT(entry, plink); 1900 INSIST(result == ISC_FALSE); 1901 result = check_expire_entry(adb, &entry, now); 1902 entry = next_entry; 1903 } 1904 UNLOCK(&adb->entrylocks[bucket]); 1905 return (result); 1906} 1907 1908static void 1909timer_cleanup(isc_task_t *task, isc_event_t *ev) { 1910 dns_adb_t *adb; 1911 isc_stdtime_t now; 1912 unsigned int i; 1913 isc_interval_t interval; 1914 1915 UNUSED(task); 1916 1917 adb = ev->ev_arg; 1918 INSIST(DNS_ADB_VALID(adb)); 1919 1920 LOCK(&adb->lock); 1921 1922 isc_stdtime_get(&now); 1923 1924 for (i = 0; i < CLEAN_BUCKETS; i++) { 1925 /* 1926 * Call our cleanup routines. 1927 */ 1928 RUNTIME_CHECK(cleanup_names(adb, adb->next_cleanbucket, now) == 1929 ISC_FALSE); 1930 RUNTIME_CHECK(cleanup_entries(adb, adb->next_cleanbucket, now) 1931 == ISC_FALSE); 1932 1933 /* 1934 * Set the next bucket to be cleaned. 1935 */ 1936 adb->next_cleanbucket++; 1937 if (adb->next_cleanbucket >= NBUCKETS) { 1938 adb->next_cleanbucket = 0; 1939#ifdef DUMP_ADB_AFTER_CLEANING 1940 dump_adb(adb, stdout, ISC_TRUE); 1941#endif 1942 } 1943 } 1944 1945 /* 1946 * Reset the timer. 1947 * XXXDCL isc_timer_reset might return ISC_R_UNEXPECTED or 1948 * ISC_R_NOMEMORY, but it isn't clear what could be done here 1949 * if either one of those things happened. 1950 */ 1951 interval = adb->tick_interval; 1952 if (adb->overmem) 1953 isc_interval_set(&interval, 0, 1); 1954 (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL, 1955 &interval, ISC_FALSE); 1956 1957 UNLOCK(&adb->lock); 1958 1959 isc_event_free(&ev); 1960} 1961 1962static void 1963destroy(dns_adb_t *adb) { 1964 adb->magic = 0; 1965 1966 /* 1967 * The timer is already dead, from the task's shutdown callback. 1968 */ 1969 isc_task_detach(&adb->task); 1970 1971 isc_mempool_destroy(&adb->nmp); 1972 isc_mempool_destroy(&adb->nhmp); 1973 isc_mempool_destroy(&adb->zimp); 1974 isc_mempool_destroy(&adb->emp); 1975 isc_mempool_destroy(&adb->ahmp); 1976 isc_mempool_destroy(&adb->aimp); 1977 isc_mempool_destroy(&adb->afmp); 1978 1979 DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS); 1980 DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS); 1981 1982 DESTROYLOCK(&adb->reflock); 1983 DESTROYLOCK(&adb->lock); 1984 DESTROYLOCK(&adb->mplock); 1985 1986 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t)); 1987} 1988 1989 1990/* 1991 * Public functions. 1992 */ 1993 1994isc_result_t 1995dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, 1996 isc_taskmgr_t *taskmgr, dns_adb_t **newadb) 1997{ 1998 dns_adb_t *adb; 1999 isc_result_t result; 2000 int i; 2001 2002 REQUIRE(mem != NULL); 2003 REQUIRE(view != NULL); 2004 REQUIRE(timermgr != NULL); 2005 REQUIRE(taskmgr != NULL); 2006 REQUIRE(newadb != NULL && *newadb == NULL); 2007 2008 adb = isc_mem_get(mem, sizeof(dns_adb_t)); 2009 if (adb == NULL) 2010 return (ISC_R_NOMEMORY); 2011 2012 /* 2013 * Initialize things here that cannot fail, and especially things 2014 * that must be NULL for the error return to work properly. 2015 */ 2016 adb->magic = 0; 2017 adb->erefcnt = 1; 2018 adb->irefcnt = 0; 2019 adb->nmp = NULL; 2020 adb->nhmp = NULL; 2021 adb->zimp = NULL; 2022 adb->emp = NULL; 2023 adb->ahmp = NULL; 2024 adb->aimp = NULL; 2025 adb->afmp = NULL; 2026 adb->task = NULL; 2027 adb->timer = NULL; 2028 adb->mctx = NULL; 2029 adb->view = view; 2030 adb->timermgr = timermgr; 2031 adb->taskmgr = taskmgr; 2032 adb->next_cleanbucket = 0; 2033 ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL, 2034 DNS_EVENT_ADBCONTROL, shutdown_task, adb, 2035 adb, NULL, NULL); 2036 adb->cevent_sent = ISC_FALSE; 2037 adb->shutting_down = ISC_FALSE; 2038 adb->overmem = ISC_FALSE; 2039 ISC_LIST_INIT(adb->whenshutdown); 2040 2041 isc_mem_attach(mem, &adb->mctx); 2042 2043 result = isc_mutex_init(&adb->lock); 2044 if (result != ISC_R_SUCCESS) 2045 goto fail0b; 2046 2047 result = isc_mutex_init(&adb->mplock); 2048 if (result != ISC_R_SUCCESS) 2049 goto fail0c; 2050 2051 result = isc_mutex_init(&adb->reflock); 2052 if (result != ISC_R_SUCCESS) 2053 goto fail0d; 2054 2055 /* 2056 * Initialize the bucket locks for names and elements. 2057 * May as well initialize the list heads, too. 2058 */ 2059 result = isc_mutexblock_init(adb->namelocks, NBUCKETS); 2060 if (result != ISC_R_SUCCESS) 2061 goto fail1; 2062 for (i = 0; i < NBUCKETS; i++) { 2063 ISC_LIST_INIT(adb->names[i]); 2064 adb->name_sd[i] = ISC_FALSE; 2065 adb->name_refcnt[i] = 0; 2066 adb->irefcnt++; 2067 } 2068 for (i = 0; i < NBUCKETS; i++) { 2069 ISC_LIST_INIT(adb->entries[i]); 2070 adb->entry_sd[i] = ISC_FALSE; 2071 adb->entry_refcnt[i] = 0; 2072 adb->irefcnt++; 2073 } 2074 result = isc_mutexblock_init(adb->entrylocks, NBUCKETS); 2075 if (result != ISC_R_SUCCESS) 2076 goto fail2; 2077 2078 /* 2079 * Memory pools 2080 */ 2081#define MPINIT(t, p, n) do { \ 2082 result = isc_mempool_create(mem, sizeof(t), &(p)); \ 2083 if (result != ISC_R_SUCCESS) \ 2084 goto fail3; \ 2085 isc_mempool_setfreemax((p), FREE_ITEMS); \ 2086 isc_mempool_setfillcount((p), FILL_COUNT); \ 2087 isc_mempool_setname((p), n); \ 2088 isc_mempool_associatelock((p), &adb->mplock); \ 2089} while (0) 2090 2091 MPINIT(dns_adbname_t, adb->nmp, "adbname"); 2092 MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook"); 2093 MPINIT(dns_adbzoneinfo_t, adb->zimp, "adbzoneinfo"); 2094 MPINIT(dns_adbentry_t, adb->emp, "adbentry"); 2095 MPINIT(dns_adbfind_t, adb->ahmp, "adbfind"); 2096 MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo"); 2097 MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch"); 2098 2099#undef MPINIT 2100 2101 /* 2102 * Allocate a timer and a task for our periodic cleanup. 2103 */ 2104 result = isc_task_create(adb->taskmgr, 0, &adb->task); 2105 if (result != ISC_R_SUCCESS) 2106 goto fail3; 2107 isc_task_setname(adb->task, "ADB", adb); 2108 /* 2109 * XXXMLG When this is changed to be a config file option, 2110 */ 2111 isc_interval_set(&adb->tick_interval, CLEAN_SECONDS, 0); 2112 result = isc_timer_create(adb->timermgr, isc_timertype_once, 2113 NULL, &adb->tick_interval, adb->task, 2114 timer_cleanup, adb, &adb->timer); 2115 if (result != ISC_R_SUCCESS) 2116 goto fail3; 2117 2118 DP(ISC_LOG_DEBUG(5), "cleaning interval for adb: " 2119 "%u buckets every %u seconds, %u buckets in system, %u cl.interval", 2120 CLEAN_BUCKETS, CLEAN_SECONDS, NBUCKETS, CLEAN_PERIOD); 2121 2122 /* 2123 * Normal return. 2124 */ 2125 adb->magic = DNS_ADB_MAGIC; 2126 *newadb = adb; 2127 return (ISC_R_SUCCESS); 2128 2129 fail3: 2130 if (adb->task != NULL) 2131 isc_task_detach(&adb->task); 2132 if (adb->timer != NULL) 2133 isc_timer_detach(&adb->timer); 2134 2135 /* clean up entrylocks */ 2136 DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS); 2137 2138 fail2: /* clean up namelocks */ 2139 DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS); 2140 2141 fail1: /* clean up only allocated memory */ 2142 if (adb->nmp != NULL) 2143 isc_mempool_destroy(&adb->nmp); 2144 if (adb->nhmp != NULL) 2145 isc_mempool_destroy(&adb->nhmp); 2146 if (adb->zimp != NULL) 2147 isc_mempool_destroy(&adb->zimp); 2148 if (adb->emp != NULL) 2149 isc_mempool_destroy(&adb->emp); 2150 if (adb->ahmp != NULL) 2151 isc_mempool_destroy(&adb->ahmp); 2152 if (adb->aimp != NULL) 2153 isc_mempool_destroy(&adb->aimp); 2154 if (adb->afmp != NULL) 2155 isc_mempool_destroy(&adb->afmp); 2156 2157 DESTROYLOCK(&adb->reflock); 2158 fail0d: 2159 DESTROYLOCK(&adb->mplock); 2160 fail0c: 2161 DESTROYLOCK(&adb->lock); 2162 fail0b: 2163 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t)); 2164 2165 return (result); 2166} 2167 2168void 2169dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) { 2170 2171 REQUIRE(DNS_ADB_VALID(adb)); 2172 REQUIRE(adbx != NULL && *adbx == NULL); 2173 2174 inc_adb_erefcnt(adb); 2175 *adbx = adb; 2176} 2177 2178void 2179dns_adb_detach(dns_adb_t **adbx) { 2180 dns_adb_t *adb; 2181 isc_boolean_t need_exit_check; 2182 2183 REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx)); 2184 2185 adb = *adbx; 2186 *adbx = NULL; 2187 2188 INSIST(adb->erefcnt > 0); 2189 2190 LOCK(&adb->reflock); 2191 adb->erefcnt--; 2192 need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0); 2193 UNLOCK(&adb->reflock); 2194 2195 if (need_exit_check) { 2196 LOCK(&adb->lock); 2197 INSIST(adb->shutting_down); 2198 check_exit(adb); 2199 UNLOCK(&adb->lock); 2200 } 2201} 2202 2203void 2204dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) { 2205 isc_task_t *clone; 2206 isc_event_t *event; 2207 isc_boolean_t zeroirefcnt = ISC_FALSE; 2208 2209 /* 2210 * Send '*eventp' to 'task' when 'adb' has shutdown. 2211 */ 2212 2213 REQUIRE(DNS_ADB_VALID(adb)); 2214 REQUIRE(eventp != NULL); 2215 2216 event = *eventp; 2217 *eventp = NULL; 2218 2219 LOCK(&adb->lock); 2220 2221 LOCK(&adb->reflock); 2222 zeroirefcnt = ISC_TF(adb->irefcnt == 0); 2223 2224 if (adb->shutting_down && zeroirefcnt && 2225 isc_mempool_getallocated(adb->ahmp) == 0) { 2226 /* 2227 * We're already shutdown. Send the event. 2228 */ 2229 event->ev_sender = adb; 2230 isc_task_send(task, &event); 2231 } else { 2232 clone = NULL; 2233 isc_task_attach(task, &clone); 2234 event->ev_sender = clone; 2235 ISC_LIST_APPEND(adb->whenshutdown, event, ev_link); 2236 } 2237 2238 UNLOCK(&adb->reflock); 2239 UNLOCK(&adb->lock); 2240} 2241 2242void 2243dns_adb_shutdown(dns_adb_t *adb) { 2244 isc_boolean_t need_check_exit; 2245 2246 /* 2247 * Shutdown 'adb'. 2248 */ 2249 2250 LOCK(&adb->lock); 2251 2252 if (!adb->shutting_down) { 2253 adb->shutting_down = ISC_TRUE; 2254 isc_mem_setwater(adb->mctx, water, adb, 0, 0); 2255 need_check_exit = shutdown_names(adb); 2256 if (!need_check_exit) 2257 need_check_exit = shutdown_entries(adb); 2258 if (need_check_exit) 2259 check_exit(adb); 2260 } 2261 2262 UNLOCK(&adb->lock); 2263} 2264 2265isc_result_t 2266dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, 2267 void *arg, dns_name_t *name, dns_name_t *zone, 2268 unsigned int options, isc_stdtime_t now, dns_name_t *target, 2269 in_port_t port, dns_adbfind_t **findp) 2270{ 2271 dns_adbfind_t *find; 2272 dns_adbname_t *adbname; 2273 int bucket; 2274 isc_boolean_t want_event, start_at_zone, alias, have_address; 2275 isc_result_t result; 2276 unsigned int wanted_addresses; 2277 unsigned int wanted_fetches; 2278 unsigned int query_pending; 2279 2280 REQUIRE(DNS_ADB_VALID(adb)); 2281 if (task != NULL) { 2282 REQUIRE(action != NULL); 2283 } 2284 REQUIRE(name != NULL); 2285 REQUIRE(zone != NULL); 2286 REQUIRE(findp != NULL && *findp == NULL); 2287 REQUIRE(target == NULL || dns_name_hasbuffer(target)); 2288 2289 REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0); 2290 2291 result = ISC_R_UNEXPECTED; 2292 wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK); 2293 wanted_fetches = 0; 2294 query_pending = 0; 2295 want_event = ISC_FALSE; 2296 start_at_zone = ISC_FALSE; 2297 alias = ISC_FALSE; 2298 2299 if (now == 0) 2300 isc_stdtime_get(&now); 2301 2302 /* 2303 * XXXMLG Move this comment somewhere else! 2304 * 2305 * Look up the name in our internal database. 2306 * 2307 * Possibilities: Note that these are not always exclusive. 2308 * 2309 * No name found. In this case, allocate a new name header and 2310 * an initial namehook or two. If any of these allocations 2311 * fail, clean up and return ISC_R_NOMEMORY. 2312 * 2313 * Name found, valid addresses present. Allocate one addrinfo 2314 * structure for each found and append it to the linked list 2315 * of addresses for this header. 2316 * 2317 * Name found, queries pending. In this case, if a task was 2318 * passed in, allocate a job id, attach it to the name's job 2319 * list and remember to tell the caller that there will be 2320 * more info coming later. 2321 */ 2322 2323 find = new_adbfind(adb); 2324 if (find == NULL) 2325 return (ISC_R_NOMEMORY); 2326 2327 find->port = port; 2328 2329 /* 2330 * Remember what types of addresses we are interested in. 2331 */ 2332 find->options = options; 2333 find->flags |= wanted_addresses; 2334 if (FIND_WANTEVENT(find)) { 2335 REQUIRE(task != NULL); 2336 } 2337 2338 /* 2339 * Try to see if we know anything about this name at all. 2340 */ 2341 bucket = DNS_ADB_INVALIDBUCKET; 2342 adbname = find_name_and_lock(adb, name, find->options, &bucket); 2343 if (adb->name_sd[bucket]) { 2344 DP(DEF_LEVEL, 2345 "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN"); 2346 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); 2347 result = ISC_R_SHUTTINGDOWN; 2348 goto out; 2349 } 2350 2351 /* 2352 * Nothing found. Allocate a new adbname structure for this name. 2353 */ 2354 if (adbname == NULL) { 2355 adbname = new_adbname(adb, name); 2356 if (adbname == NULL) { 2357 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); 2358 result = ISC_R_NOMEMORY; 2359 goto out; 2360 } 2361 link_name(adb, bucket, adbname); 2362 if (FIND_HINTOK(find)) 2363 adbname->flags |= NAME_HINT_OK; 2364 if (FIND_GLUEOK(find)) 2365 adbname->flags |= NAME_GLUE_OK; 2366 if (FIND_STARTATZONE(find)) 2367 adbname->flags |= NAME_STARTATZONE; 2368 } 2369 2370 /* 2371 * Expire old entries, etc. 2372 */ 2373 RUNTIME_CHECK(check_expire_namehooks(adbname, now, adb->overmem) == 2374 ISC_FALSE); 2375 2376 /* 2377 * Do we know that the name is an alias? 2378 */ 2379 if (!EXPIRE_OK(adbname->expire_target, now)) { 2380 /* 2381 * Yes, it is. 2382 */ 2383 DP(DEF_LEVEL, 2384 "dns_adb_createfind: name %p is an alias (cached)", 2385 adbname); 2386 alias = ISC_TRUE; 2387 goto post_copy; 2388 } 2389 2390 /* 2391 * Try to populate the name from the database and/or 2392 * start fetches. First try looking for an A record 2393 * in the database. 2394 */ 2395 if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now) 2396 && WANT_INET(wanted_addresses)) { 2397 result = dbfind_name(adbname, now, dns_rdatatype_a); 2398 if (result == ISC_R_SUCCESS) { 2399 DP(DEF_LEVEL, 2400 "dns_adb_createfind: found A for name %p in db", 2401 adbname); 2402 goto v6; 2403 } 2404 2405 /* 2406 * Did we get a CNAME or DNAME? 2407 */ 2408 if (result == DNS_R_ALIAS) { 2409 DP(DEF_LEVEL, 2410 "dns_adb_createfind: name %p is an alias", 2411 adbname); 2412 alias = ISC_TRUE; 2413 goto post_copy; 2414 } 2415 2416 /* 2417 * If the name doesn't exist at all, don't bother with 2418 * v6 queries; they won't work. 2419 * 2420 * If the name does exist but we didn't get our data, go 2421 * ahead and try AAAA. 2422 * 2423 * If the result is neither of these, try a fetch for A. 2424 */ 2425 if (NXDOMAIN_RESULT(result)) 2426 goto fetch; 2427 else if (NXRRSET_RESULT(result)) 2428 goto v6; 2429 2430 if (!NAME_FETCH_V4(adbname)) 2431 wanted_fetches |= DNS_ADBFIND_INET; 2432 } 2433 2434 v6: 2435 if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now) 2436 && WANT_INET6(wanted_addresses)) { 2437 result = dbfind_name(adbname, now, dns_rdatatype_aaaa); 2438 if (result == ISC_R_SUCCESS) { 2439 DP(DEF_LEVEL, 2440 "dns_adb_createfind: found AAAA for name %p", 2441 adbname); 2442 goto fetch; 2443 } 2444 2445 /* 2446 * Did we get a CNAME or DNAME? 2447 */ 2448 if (result == DNS_R_ALIAS) { 2449 DP(DEF_LEVEL, 2450 "dns_adb_createfind: name %p is an alias", 2451 adbname); 2452 alias = ISC_TRUE; 2453 goto post_copy; 2454 } 2455 2456 /* 2457 * Listen to negative cache hints, and don't start 2458 * another query. 2459 */ 2460 if (NCACHE_RESULT(result) || AUTH_NX(result)) 2461 goto fetch; 2462 2463 if (!NAME_FETCH_V6(adbname)) 2464 wanted_fetches |= DNS_ADBFIND_INET6; 2465 } 2466 2467 fetch: 2468 if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) || 2469 (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname))) 2470 have_address = ISC_TRUE; 2471 else 2472 have_address = ISC_FALSE; 2473 if (wanted_fetches != 0 && 2474 ! (FIND_AVOIDFETCHES(find) && have_address)) { 2475 /* 2476 * We're missing at least one address family. Either the 2477 * caller hasn't instructed us to avoid fetches, or we don't 2478 * know anything about any of the address families that would 2479 * be acceptable so we have to launch fetches. 2480 */ 2481 2482 if (FIND_STARTATZONE(find)) 2483 start_at_zone = ISC_TRUE; 2484 2485 /* 2486 * Start V4. 2487 */ 2488 if (WANT_INET(wanted_fetches) && 2489 fetch_name(adbname, start_at_zone, 2490 dns_rdatatype_a) == ISC_R_SUCCESS) { 2491 DP(DEF_LEVEL, 2492 "dns_adb_createfind: started A fetch for name %p", 2493 adbname); 2494 } 2495 2496 /* 2497 * Start V6. 2498 */ 2499 if (WANT_INET6(wanted_fetches) && 2500 fetch_name(adbname, start_at_zone, 2501 dns_rdatatype_aaaa) == ISC_R_SUCCESS) { 2502 DP(DEF_LEVEL, 2503 "dns_adb_createfind: " 2504 "started AAAA fetch for name %p", 2505 adbname); 2506 } 2507 } 2508 2509 /* 2510 * Run through the name and copy out the bits we are 2511 * interested in. 2512 */ 2513 copy_namehook_lists(adb, find, zone, adbname, now); 2514 2515 post_copy: 2516 if (NAME_FETCH_V4(adbname)) 2517 query_pending |= DNS_ADBFIND_INET; 2518 if (NAME_FETCH_V6(adbname)) 2519 query_pending |= DNS_ADBFIND_INET6; 2520 2521 /* 2522 * Attach to the name's query list if there are queries 2523 * already running, and we have been asked to. 2524 */ 2525 want_event = ISC_TRUE; 2526 if (!FIND_WANTEVENT(find)) 2527 want_event = ISC_FALSE; 2528 if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find)) 2529 want_event = ISC_FALSE; 2530 if ((wanted_addresses & query_pending) == 0) 2531 want_event = ISC_FALSE; 2532 if (alias) 2533 want_event = ISC_FALSE; 2534 if (want_event) { 2535 find->adbname = adbname; 2536 find->name_bucket = bucket; 2537 ISC_LIST_APPEND(adbname->finds, find, plink); 2538 find->query_pending = (query_pending & wanted_addresses); 2539 find->flags &= ~DNS_ADBFIND_ADDRESSMASK; 2540 find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK); 2541 DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p", 2542 find, adbname); 2543 } else { 2544 /* 2545 * Remove the flag so the caller knows there will never 2546 * be an event, and set internal flags to fake that 2547 * the event was sent and freed, so dns_adb_destroyfind() will 2548 * do the right thing. 2549 */ 2550 find->query_pending = (query_pending & wanted_addresses); 2551 find->options &= ~DNS_ADBFIND_WANTEVENT; 2552 find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED); 2553 find->flags &= ~DNS_ADBFIND_ADDRESSMASK; 2554 } 2555 2556 find->partial_result |= (adbname->partial_result & wanted_addresses); 2557 if (alias) { 2558 if (target != NULL) { 2559 result = dns_name_copy(&adbname->target, target, NULL); 2560 if (result != ISC_R_SUCCESS) 2561 goto out; 2562 } 2563 result = DNS_R_ALIAS; 2564 } else 2565 result = ISC_R_SUCCESS; 2566 2567 /* 2568 * Copy out error flags from the name structure into the find. 2569 */ 2570 find->result_v4 = find_err_map[adbname->fetch_err]; 2571 find->result_v6 = find_err_map[adbname->fetch6_err]; 2572 2573 out: 2574 if (find != NULL) { 2575 *findp = find; 2576 2577 if (want_event) { 2578 isc_task_t *taskp; 2579 2580 INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0); 2581 taskp = NULL; 2582 isc_task_attach(task, &taskp); 2583 find->event.ev_sender = taskp; 2584 find->event.ev_action = action; 2585 find->event.ev_arg = arg; 2586 } 2587 } 2588 2589 if (bucket != DNS_ADB_INVALIDBUCKET) 2590 UNLOCK(&adb->namelocks[bucket]); 2591 2592 return (result); 2593} 2594 2595void 2596dns_adb_destroyfind(dns_adbfind_t **findp) { 2597 dns_adbfind_t *find; 2598 dns_adbentry_t *entry; 2599 dns_adbaddrinfo_t *ai; 2600 int bucket; 2601 dns_adb_t *adb; 2602 2603 REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp)); 2604 find = *findp; 2605 *findp = NULL; 2606 2607 LOCK(&find->lock); 2608 2609 DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find); 2610 2611 adb = find->adb; 2612 REQUIRE(DNS_ADB_VALID(adb)); 2613 2614 REQUIRE(FIND_EVENTFREED(find)); 2615 2616 bucket = find->name_bucket; 2617 INSIST(bucket == DNS_ADB_INVALIDBUCKET); 2618 2619 UNLOCK(&find->lock); 2620 2621 /* 2622 * The find doesn't exist on any list, and nothing is locked. 2623 * Return the find to the memory pool, and decrement the adb's 2624 * reference count. 2625 */ 2626 ai = ISC_LIST_HEAD(find->list); 2627 while (ai != NULL) { 2628 ISC_LIST_UNLINK(find->list, ai, publink); 2629 entry = ai->entry; 2630 ai->entry = NULL; 2631 INSIST(DNS_ADBENTRY_VALID(entry)); 2632 RUNTIME_CHECK(dec_entry_refcnt(adb, entry, ISC_TRUE) == 2633 ISC_FALSE); 2634 free_adbaddrinfo(adb, &ai); 2635 ai = ISC_LIST_HEAD(find->list); 2636 } 2637 2638 /* 2639 * WARNING: The find is freed with the adb locked. This is done 2640 * to avoid a race condition where we free the find, some other 2641 * thread tests to see if it should be destroyed, detects it should 2642 * be, destroys it, and then we try to lock it for our check, but the 2643 * lock is destroyed. 2644 */ 2645 LOCK(&adb->lock); 2646 if (free_adbfind(adb, &find)) 2647 check_exit(adb); 2648 UNLOCK(&adb->lock); 2649} 2650 2651void 2652dns_adb_cancelfind(dns_adbfind_t *find) { 2653 isc_event_t *ev; 2654 isc_task_t *task; 2655 dns_adb_t *adb; 2656 int bucket; 2657 int unlock_bucket; 2658 2659 LOCK(&find->lock); 2660 2661 DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find); 2662 2663 adb = find->adb; 2664 REQUIRE(DNS_ADB_VALID(adb)); 2665 2666 REQUIRE(!FIND_EVENTFREED(find)); 2667 REQUIRE(FIND_WANTEVENT(find)); 2668 2669 bucket = find->name_bucket; 2670 if (bucket == DNS_ADB_INVALIDBUCKET) 2671 goto cleanup; 2672 2673 /* 2674 * We need to get the adbname's lock to unlink the find. 2675 */ 2676 unlock_bucket = bucket; 2677 violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]); 2678 bucket = find->name_bucket; 2679 if (bucket != DNS_ADB_INVALIDBUCKET) { 2680 ISC_LIST_UNLINK(find->adbname->finds, find, plink); 2681 find->adbname = NULL; 2682 find->name_bucket = DNS_ADB_INVALIDBUCKET; 2683 } 2684 UNLOCK(&adb->namelocks[unlock_bucket]); 2685 bucket = DNS_ADB_INVALIDBUCKET; 2686 2687 cleanup: 2688 2689 if (!FIND_EVENTSENT(find)) { 2690 ev = &find->event; 2691 task = ev->ev_sender; 2692 ev->ev_sender = find; 2693 ev->ev_type = DNS_EVENT_ADBCANCELED; 2694 ev->ev_destroy = event_free; 2695 ev->ev_destroy_arg = find; 2696 find->result_v4 = ISC_R_CANCELED; 2697 find->result_v6 = ISC_R_CANCELED; 2698 2699 DP(DEF_LEVEL, "sending event %p to task %p for find %p", 2700 ev, task, find); 2701 2702 isc_task_sendanddetach(&task, (isc_event_t **)&ev); 2703 } 2704 2705 UNLOCK(&find->lock); 2706} 2707 2708void 2709dns_adb_dump(dns_adb_t *adb, FILE *f) { 2710 REQUIRE(DNS_ADB_VALID(adb)); 2711 REQUIRE(f != NULL); 2712 2713 /* 2714 * Lock the adb itself, lock all the name buckets, then lock all 2715 * the entry buckets. This should put the adb into a state where 2716 * nothing can change, so we can iterate through everything and 2717 * print at our leisure. 2718 */ 2719 2720 LOCK(&adb->lock); 2721 dump_adb(adb, f, ISC_FALSE); 2722 UNLOCK(&adb->lock); 2723} 2724 2725static void 2726dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) { 2727 if (value == INT_MAX) 2728 return; 2729 fprintf(f, " [%s TTL %d]", legend, value - now); 2730} 2731 2732static void 2733dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug) { 2734 int i; 2735 dns_adbname_t *name; 2736 isc_stdtime_t now; 2737 2738 isc_stdtime_get(&now); 2739 2740 fprintf(f, ";\n; Address database dump\n;\n"); 2741 if (debug) 2742 fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n", 2743 adb, adb->erefcnt, adb->irefcnt, 2744 isc_mempool_getallocated(adb->nhmp)); 2745 2746 for (i = 0; i < NBUCKETS; i++) 2747 LOCK(&adb->namelocks[i]); 2748 for (i = 0; i < NBUCKETS; i++) 2749 LOCK(&adb->entrylocks[i]); 2750 2751 /* 2752 * Dump the names 2753 */ 2754 for (i = 0; i < NBUCKETS; i++) { 2755 name = ISC_LIST_HEAD(adb->names[i]); 2756 if (name == NULL) 2757 continue; 2758 if (debug) 2759 fprintf(f, "; bucket %d\n", i); 2760 for (; 2761 name != NULL; 2762 name = ISC_LIST_NEXT(name, plink)) 2763 { 2764 if (debug) 2765 fprintf(f, "; name %p (flags %08x)\n", 2766 name, name->flags); 2767 2768 fprintf(f, "; "); 2769 print_dns_name(f, &name->name); 2770 if (dns_name_countlabels(&name->target) > 0) { 2771 fprintf(f, " alias "); 2772 print_dns_name(f, &name->target); 2773 } 2774 2775 dump_ttl(f, "v4", name->expire_v4, now); 2776 dump_ttl(f, "v6", name->expire_v6, now); 2777 dump_ttl(f, "target", name->expire_target, now); 2778 2779 fprintf(f, " [v4 %s] [v6 %s]", 2780 errnames[name->fetch_err], 2781 errnames[name->fetch6_err]); 2782 2783 fprintf(f, "\n"); 2784 2785 print_namehook_list(f, "v4", &name->v4, debug, now); 2786 print_namehook_list(f, "v6", &name->v6, debug, now); 2787 2788 if (debug) 2789 print_fetch_list(f, name); 2790 if (debug) 2791 print_find_list(f, name); 2792 2793 } 2794 } 2795 2796 /* 2797 * Unlock everything 2798 */ 2799 for (i = 0; i < NBUCKETS; i++) 2800 UNLOCK(&adb->entrylocks[i]); 2801 for (i = 0; i < NBUCKETS; i++) 2802 UNLOCK(&adb->namelocks[i]); 2803} 2804 2805static void 2806dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug, 2807 isc_stdtime_t now) 2808{ 2809 char addrbuf[ISC_NETADDR_FORMATSIZE]; 2810 isc_netaddr_t netaddr; 2811 dns_adbzoneinfo_t *zi; 2812 2813 isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr); 2814 isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf)); 2815 2816 if (debug) 2817 fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt); 2818 2819 fprintf(f, ";\t%s [srtt %u] [flags %08x]", 2820 addrbuf, entry->srtt, entry->flags); 2821 fprintf(f, "\n"); 2822 for (zi = ISC_LIST_HEAD(entry->zoneinfo); 2823 zi != NULL; 2824 zi = ISC_LIST_NEXT(zi, plink)) { 2825 fprintf(f, ";\t\t"); 2826 print_dns_name(f, &zi->zone); 2827 fprintf(f, " [lame TTL %d]\n", zi->lame_timer - now); 2828 } 2829} 2830 2831void 2832dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) { 2833 char tmp[512]; 2834 const char *tmpp; 2835 dns_adbaddrinfo_t *ai; 2836 isc_sockaddr_t *sa; 2837 2838 /* 2839 * Not used currently, in the API Just In Case we 2840 * want to dump out the name and/or entries too. 2841 */ 2842 2843 LOCK(&find->lock); 2844 2845 fprintf(f, ";Find %p\n", find); 2846 fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n", 2847 find->query_pending, find->partial_result, 2848 find->options, find->flags); 2849 fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n", 2850 find->name_bucket, find->adbname, find->event.ev_sender); 2851 2852 ai = ISC_LIST_HEAD(find->list); 2853 if (ai != NULL) 2854 fprintf(f, "\tAddresses:\n"); 2855 while (ai != NULL) { 2856 sa = &ai->sockaddr; 2857 switch (sa->type.sa.sa_family) { 2858 case AF_INET: 2859 tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr, 2860 tmp, sizeof(tmp)); 2861 break; 2862 case AF_INET6: 2863 tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr, 2864 tmp, sizeof(tmp)); 2865 break; 2866 default: 2867 tmpp = "UnkFamily"; 2868 } 2869 2870 if (tmpp == NULL) 2871 tmpp = "BadAddress"; 2872 2873 fprintf(f, "\t\tentry %p, flags %08x" 2874 " srtt %u addr %s\n", 2875 ai->entry, ai->flags, ai->srtt, tmpp); 2876 2877 ai = ISC_LIST_NEXT(ai, publink); 2878 } 2879 2880 UNLOCK(&find->lock); 2881} 2882 2883static void 2884print_dns_name(FILE *f, dns_name_t *name) { 2885 char buf[DNS_NAME_FORMATSIZE]; 2886 2887 INSIST(f != NULL); 2888 2889 dns_name_format(name, buf, sizeof(buf)); 2890 fprintf(f, "%s", buf); 2891} 2892 2893static void 2894print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list, 2895 isc_boolean_t debug, isc_stdtime_t now) 2896{ 2897 dns_adbnamehook_t *nh; 2898 2899 for (nh = ISC_LIST_HEAD(*list); 2900 nh != NULL; 2901 nh = ISC_LIST_NEXT(nh, plink)) 2902 { 2903 if (debug) 2904 fprintf(f, ";\tHook(%s) %p\n", legend, nh); 2905 dump_entry(f, nh->entry, debug, now); 2906 } 2907} 2908 2909static inline void 2910print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) { 2911 fprintf(f, "\t\tFetch(%s): %p -> { nh %p, entry %p, fetch %p }\n", 2912 type, ft, ft->namehook, ft->entry, ft->fetch); 2913} 2914 2915static void 2916print_fetch_list(FILE *f, dns_adbname_t *n) { 2917 if (NAME_FETCH_A(n)) 2918 print_fetch(f, n->fetch_a, "A"); 2919 if (NAME_FETCH_AAAA(n)) 2920 print_fetch(f, n->fetch_aaaa, "AAAA"); 2921} 2922 2923static void 2924print_find_list(FILE *f, dns_adbname_t *name) { 2925 dns_adbfind_t *find; 2926 2927 find = ISC_LIST_HEAD(name->finds); 2928 while (find != NULL) { 2929 dns_adb_dumpfind(find, f); 2930 find = ISC_LIST_NEXT(find, plink); 2931 } 2932} 2933 2934static isc_result_t 2935dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype) 2936{ 2937 isc_result_t result; 2938 dns_rdataset_t rdataset; 2939 dns_adb_t *adb; 2940 dns_fixedname_t foundname; 2941 dns_name_t *fname; 2942 2943 INSIST(DNS_ADBNAME_VALID(adbname)); 2944 adb = adbname->adb; 2945 INSIST(DNS_ADB_VALID(adb)); 2946 INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa); 2947 2948 dns_fixedname_init(&foundname); 2949 fname = dns_fixedname_name(&foundname); 2950 dns_rdataset_init(&rdataset); 2951 2952 if (rdtype == dns_rdatatype_a) 2953 adbname->fetch_err = FIND_ERR_UNEXPECTED; 2954 else 2955 adbname->fetch6_err = FIND_ERR_UNEXPECTED; 2956 2957 result = dns_view_find(adb->view, &adbname->name, rdtype, now, 2958 NAME_GLUEOK(adbname), 2959 ISC_TF(NAME_HINTOK(adbname)), 2960 NULL, NULL, fname, &rdataset, NULL); 2961 2962 /* XXXVIX this switch statement is too sparse to gen a jump table. */ 2963 switch (result) { 2964 case DNS_R_GLUE: 2965 case DNS_R_HINT: 2966 case ISC_R_SUCCESS: 2967 /* 2968 * Found in the database. Even if we can't copy out 2969 * any information, return success, or else a fetch 2970 * will be made, which will only make things worse. 2971 */ 2972 if (rdtype == dns_rdatatype_a) 2973 adbname->fetch_err = FIND_ERR_SUCCESS; 2974 else 2975 adbname->fetch6_err = FIND_ERR_SUCCESS; 2976 result = import_rdataset(adbname, &rdataset, now); 2977 break; 2978 case DNS_R_NXDOMAIN: 2979 case DNS_R_NXRRSET: 2980 /* 2981 * We're authoritative and the data doesn't exist. 2982 * Make up a negative cache entry so we don't ask again 2983 * for a while. 2984 * 2985 * XXXRTH What time should we use? I'm putting in 30 seconds 2986 * for now. 2987 */ 2988 if (rdtype == dns_rdatatype_a) { 2989 adbname->expire_v4 = now + 30; 2990 DP(NCACHE_LEVEL, 2991 "adb name %p: Caching auth negative entry for A", 2992 adbname); 2993 if (result == DNS_R_NXDOMAIN) 2994 adbname->fetch_err = FIND_ERR_NXDOMAIN; 2995 else 2996 adbname->fetch_err = FIND_ERR_NXRRSET; 2997 } else { 2998 DP(NCACHE_LEVEL, 2999 "adb name %p: Caching auth negative entry for AAAA", 3000 adbname); 3001 adbname->expire_v6 = now + 30; 3002 if (result == DNS_R_NXDOMAIN) 3003 adbname->fetch6_err = FIND_ERR_NXDOMAIN; 3004 else 3005 adbname->fetch6_err = FIND_ERR_NXRRSET; 3006 } 3007 break; 3008 case DNS_R_NCACHENXDOMAIN: 3009 case DNS_R_NCACHENXRRSET: 3010 /* 3011 * We found a negative cache entry. Pull the TTL from it 3012 * so we won't ask again for a while. 3013 */ 3014 rdataset.ttl = ttlclamp(rdataset.ttl); 3015 if (rdtype == dns_rdatatype_a) { 3016 adbname->expire_v4 = rdataset.ttl + now; 3017 if (result == DNS_R_NCACHENXDOMAIN) 3018 adbname->fetch_err = FIND_ERR_NXDOMAIN; 3019 else 3020 adbname->fetch_err = FIND_ERR_NXRRSET; 3021 DP(NCACHE_LEVEL, 3022 "adb name %p: Caching negative entry for A (ttl %u)", 3023 adbname, rdataset.ttl); 3024 } else { 3025 DP(NCACHE_LEVEL, 3026 "adb name %p: Caching negative entry for AAAA (ttl %u)", 3027 adbname, rdataset.ttl); 3028 adbname->expire_v6 = rdataset.ttl + now; 3029 if (result == DNS_R_NCACHENXDOMAIN) 3030 adbname->fetch6_err = FIND_ERR_NXDOMAIN; 3031 else 3032 adbname->fetch6_err = FIND_ERR_NXRRSET; 3033 } 3034 break; 3035 case DNS_R_CNAME: 3036 case DNS_R_DNAME: 3037 /* 3038 * Clear the hint and glue flags, so this will match 3039 * more often. 3040 */ 3041 adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK); 3042 3043 rdataset.ttl = ttlclamp(rdataset.ttl); 3044 clean_target(adb, &adbname->target); 3045 adbname->expire_target = INT_MAX; 3046 result = set_target(adb, &adbname->name, fname, &rdataset, 3047 &adbname->target); 3048 if (result == ISC_R_SUCCESS) { 3049 result = DNS_R_ALIAS; 3050 DP(NCACHE_LEVEL, 3051 "adb name %p: caching alias target", 3052 adbname); 3053 adbname->expire_target = rdataset.ttl + now; 3054 } 3055 if (rdtype == dns_rdatatype_a) 3056 adbname->fetch_err = FIND_ERR_SUCCESS; 3057 else 3058 adbname->fetch6_err = FIND_ERR_SUCCESS; 3059 break; 3060 } 3061 3062 if (dns_rdataset_isassociated(&rdataset)) 3063 dns_rdataset_disassociate(&rdataset); 3064 3065 return (result); 3066} 3067 3068static void 3069fetch_callback(isc_task_t *task, isc_event_t *ev) { 3070 dns_fetchevent_t *dev; 3071 dns_adbname_t *name; 3072 dns_adb_t *adb; 3073 dns_adbfetch_t *fetch; 3074 int bucket; 3075 isc_eventtype_t ev_status; 3076 isc_stdtime_t now; 3077 isc_result_t result; 3078 unsigned int address_type; 3079 isc_boolean_t want_check_exit = ISC_FALSE; 3080 3081 UNUSED(task); 3082 3083 INSIST(ev->ev_type == DNS_EVENT_FETCHDONE); 3084 dev = (dns_fetchevent_t *)ev; 3085 name = ev->ev_arg; 3086 INSIST(DNS_ADBNAME_VALID(name)); 3087 adb = name->adb; 3088 INSIST(DNS_ADB_VALID(adb)); 3089 3090 bucket = name->lock_bucket; 3091 LOCK(&adb->namelocks[bucket]); 3092 3093 INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name)); 3094 address_type = 0; 3095 if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) { 3096 address_type = DNS_ADBFIND_INET; 3097 fetch = name->fetch_a; 3098 name->fetch_a = NULL; 3099 } else if (NAME_FETCH_AAAA(name) 3100 && (name->fetch_aaaa->fetch == dev->fetch)) { 3101 address_type = DNS_ADBFIND_INET6; 3102 fetch = name->fetch_aaaa; 3103 name->fetch_aaaa = NULL; 3104 } 3105 INSIST(address_type != 0); 3106 3107 dns_resolver_destroyfetch(&fetch->fetch); 3108 dev->fetch = NULL; 3109 3110 ev_status = DNS_EVENT_ADBNOMOREADDRESSES; 3111 3112 /* 3113 * Cleanup things we don't care about. 3114 */ 3115 if (dev->node != NULL) 3116 dns_db_detachnode(dev->db, &dev->node); 3117 if (dev->db != NULL) 3118 dns_db_detach(&dev->db); 3119 3120 /* 3121 * If this name is marked as dead, clean up, throwing away 3122 * potentially good data. 3123 */ 3124 if (NAME_DEAD(name)) { 3125 free_adbfetch(adb, &fetch); 3126 isc_event_free(&ev); 3127 3128 want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED); 3129 3130 UNLOCK(&adb->namelocks[bucket]); 3131 3132 if (want_check_exit) { 3133 LOCK(&adb->lock); 3134 check_exit(adb); 3135 UNLOCK(&adb->lock); 3136 } 3137 3138 return; 3139 } 3140 3141 isc_stdtime_get(&now); 3142 3143 /* 3144 * If we got a negative cache response, remember it. 3145 */ 3146 if (NCACHE_RESULT(dev->result)) { 3147 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl); 3148 if (address_type == DNS_ADBFIND_INET) { 3149 DP(NCACHE_LEVEL, "adb fetch name %p: " 3150 "caching negative entry for A (ttl %u)", 3151 name, dev->rdataset->ttl); 3152 name->expire_v4 = ISC_MIN(name->expire_v4, 3153 dev->rdataset->ttl + now); 3154 if (dev->result == DNS_R_NCACHENXDOMAIN) 3155 name->fetch_err = FIND_ERR_NXDOMAIN; 3156 else 3157 name->fetch_err = FIND_ERR_NXRRSET; 3158 } else { 3159 DP(NCACHE_LEVEL, "adb fetch name %p: " 3160 "caching negative entry for AAAA (ttl %u)", 3161 name, dev->rdataset->ttl); 3162 name->expire_v6 = ISC_MIN(name->expire_v6, 3163 dev->rdataset->ttl + now); 3164 if (dev->result == DNS_R_NCACHENXDOMAIN) 3165 name->fetch6_err = FIND_ERR_NXDOMAIN; 3166 else 3167 name->fetch6_err = FIND_ERR_NXRRSET; 3168 } 3169 goto out; 3170 } 3171 3172 /* 3173 * Handle CNAME/DNAME. 3174 */ 3175 if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) { 3176 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl); 3177 clean_target(adb, &name->target); 3178 name->expire_target = INT_MAX; 3179 result = set_target(adb, &name->name, 3180 dns_fixedname_name(&dev->foundname), 3181 dev->rdataset, 3182 &name->target); 3183 if (result == ISC_R_SUCCESS) { 3184 DP(NCACHE_LEVEL, 3185 "adb fetch name %p: caching alias target", 3186 name); 3187 name->expire_target = dev->rdataset->ttl + now; 3188 } 3189 goto check_result; 3190 } 3191 3192 /* 3193 * Did we get back junk? If so, and there are no more fetches 3194 * sitting out there, tell all the finds about it. 3195 */ 3196 if (dev->result != ISC_R_SUCCESS) { 3197 char buf[DNS_NAME_FORMATSIZE]; 3198 3199 dns_name_format(&name->name, buf, sizeof(buf)); 3200 DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s", 3201 buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA", 3202 dns_result_totext(dev->result)); 3203 /* XXXMLG Don't pound on bad servers. */ 3204 if (address_type == DNS_ADBFIND_INET) { 3205 name->expire_v4 = ISC_MIN(name->expire_v4, now + 300); 3206 name->fetch_err = FIND_ERR_FAILURE; 3207 } else { 3208 name->expire_v6 = ISC_MIN(name->expire_v6, now + 300); 3209 name->fetch6_err = FIND_ERR_FAILURE; 3210 } 3211 goto out; 3212 } 3213 3214 /* 3215 * We got something potentially useful. 3216 */ 3217 result = import_rdataset(name, &fetch->rdataset, now); 3218 3219 check_result: 3220 if (result == ISC_R_SUCCESS) { 3221 ev_status = DNS_EVENT_ADBMOREADDRESSES; 3222 if (address_type == DNS_ADBFIND_INET) 3223 name->fetch_err = FIND_ERR_SUCCESS; 3224 else 3225 name->fetch6_err = FIND_ERR_SUCCESS; 3226 } 3227 3228 out: 3229 free_adbfetch(adb, &fetch); 3230 isc_event_free(&ev); 3231 3232 clean_finds_at_name(name, ev_status, address_type); 3233 3234 UNLOCK(&adb->namelocks[bucket]); 3235} 3236 3237static isc_result_t 3238fetch_name(dns_adbname_t *adbname, 3239 isc_boolean_t start_at_zone, 3240 dns_rdatatype_t type) 3241{ 3242 isc_result_t result; 3243 dns_adbfetch_t *fetch = NULL; 3244 dns_adb_t *adb; 3245 dns_fixedname_t fixed; 3246 dns_name_t *name; 3247 dns_rdataset_t rdataset; 3248 dns_rdataset_t *nameservers; 3249 unsigned int options; 3250 3251 INSIST(DNS_ADBNAME_VALID(adbname)); 3252 adb = adbname->adb; 3253 INSIST(DNS_ADB_VALID(adb)); 3254 3255 INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) || 3256 (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname))); 3257 3258 adbname->fetch_err = FIND_ERR_NOTFOUND; 3259 3260 name = NULL; 3261 nameservers = NULL; 3262 dns_rdataset_init(&rdataset); 3263 3264 options = DNS_FETCHOPT_NOVALIDATE; 3265 if (start_at_zone) { 3266 DP(ENTER_LEVEL, 3267 "fetch_name: starting at zone for name %p", 3268 adbname); 3269 dns_fixedname_init(&fixed); 3270 name = dns_fixedname_name(&fixed); 3271 result = dns_view_findzonecut2(adb->view, &adbname->name, name, 3272 0, 0, ISC_TRUE, ISC_FALSE, 3273 &rdataset, NULL); 3274 if (result != ISC_R_SUCCESS && result != DNS_R_HINT) 3275 goto cleanup; 3276 nameservers = &rdataset; 3277 options |= DNS_FETCHOPT_UNSHARED; 3278 } 3279 3280 fetch = new_adbfetch(adb); 3281 if (fetch == NULL) { 3282 result = ISC_R_NOMEMORY; 3283 goto cleanup; 3284 } 3285 3286 result = dns_resolver_createfetch(adb->view->resolver, &adbname->name, 3287 type, name, nameservers, NULL, 3288 options, adb->task, fetch_callback, 3289 adbname, &fetch->rdataset, NULL, 3290 &fetch->fetch); 3291 if (result != ISC_R_SUCCESS) 3292 goto cleanup; 3293 3294 if (type == dns_rdatatype_a) 3295 adbname->fetch_a = fetch; 3296 else 3297 adbname->fetch_aaaa = fetch; 3298 fetch = NULL; /* Keep us from cleaning this up below. */ 3299 3300 cleanup: 3301 if (fetch != NULL) 3302 free_adbfetch(adb, &fetch); 3303 if (dns_rdataset_isassociated(&rdataset)) 3304 dns_rdataset_disassociate(&rdataset); 3305 3306 return (result); 3307} 3308 3309/* 3310 * XXXMLG Needs to take a find argument and an address info, no zone or adb, 3311 * since these can be extracted from the find itself. 3312 */ 3313isc_result_t 3314dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *zone, 3315 isc_stdtime_t expire_time) 3316{ 3317 dns_adbzoneinfo_t *zi; 3318 int bucket; 3319 isc_result_t result = ISC_R_SUCCESS; 3320 3321 REQUIRE(DNS_ADB_VALID(adb)); 3322 REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3323 REQUIRE(zone != NULL); 3324 3325 bucket = addr->entry->lock_bucket; 3326 LOCK(&adb->entrylocks[bucket]); 3327 zi = ISC_LIST_HEAD(addr->entry->zoneinfo); 3328 while (zi != NULL && dns_name_equal(zone, &zi->zone)) 3329 zi = ISC_LIST_NEXT(zi, plink); 3330 if (zi != NULL) { 3331 if (expire_time > zi->lame_timer) 3332 zi->lame_timer = expire_time; 3333 goto unlock; 3334 } 3335 zi = new_adbzoneinfo(adb, zone); 3336 if (zi == NULL) { 3337 result = ISC_R_NOMEMORY; 3338 goto unlock; 3339 } 3340 3341 zi->lame_timer = expire_time; 3342 3343 ISC_LIST_PREPEND(addr->entry->zoneinfo, zi, plink); 3344 unlock: 3345 UNLOCK(&adb->entrylocks[bucket]); 3346 3347 return (ISC_R_SUCCESS); 3348} 3349 3350void 3351dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr, 3352 unsigned int rtt, unsigned int factor) 3353{ 3354 int bucket; 3355 unsigned int new_srtt; 3356 isc_stdtime_t now; 3357 3358 REQUIRE(DNS_ADB_VALID(adb)); 3359 REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3360 REQUIRE(factor <= 10); 3361 3362 bucket = addr->entry->lock_bucket; 3363 LOCK(&adb->entrylocks[bucket]); 3364 3365 if (factor == DNS_ADB_RTTADJAGE) 3366 new_srtt = addr->entry->srtt * 98 / 100; 3367 else 3368 new_srtt = (addr->entry->srtt / 10 * factor) 3369 + (rtt / 10 * (10 - factor)); 3370 3371 addr->entry->srtt = new_srtt; 3372 addr->srtt = new_srtt; 3373 3374 isc_stdtime_get(&now); 3375 addr->entry->expires = now + ADB_ENTRY_WINDOW; 3376 3377 UNLOCK(&adb->entrylocks[bucket]); 3378} 3379 3380void 3381dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr, 3382 unsigned int bits, unsigned int mask) 3383{ 3384 int bucket; 3385 3386 REQUIRE(DNS_ADB_VALID(adb)); 3387 REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3388 3389 bucket = addr->entry->lock_bucket; 3390 LOCK(&adb->entrylocks[bucket]); 3391 3392 addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask); 3393 /* 3394 * Note that we do not update the other bits in addr->flags with 3395 * the most recent values from addr->entry->flags. 3396 */ 3397 addr->flags = (addr->flags & ~mask) | (bits & mask); 3398 3399 UNLOCK(&adb->entrylocks[bucket]); 3400} 3401 3402isc_result_t 3403dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa, 3404 dns_adbaddrinfo_t **addrp, isc_stdtime_t now) 3405{ 3406 int bucket; 3407 dns_adbentry_t *entry; 3408 dns_adbaddrinfo_t *addr; 3409 isc_result_t result; 3410 in_port_t port; 3411 3412 REQUIRE(DNS_ADB_VALID(adb)); 3413 REQUIRE(addrp != NULL && *addrp == NULL); 3414 3415 UNUSED(now); 3416 3417 result = ISC_R_SUCCESS; 3418 bucket = DNS_ADB_INVALIDBUCKET; 3419 entry = find_entry_and_lock(adb, sa, &bucket); 3420 if (adb->entry_sd[bucket]) { 3421 result = ISC_R_SHUTTINGDOWN; 3422 goto unlock; 3423 } 3424 if (entry == NULL) { 3425 /* 3426 * We don't know anything about this address. 3427 */ 3428 entry = new_adbentry(adb); 3429 if (entry == NULL) { 3430 result = ISC_R_NOMEMORY; 3431 goto unlock; 3432 } 3433 entry->sockaddr = *sa; 3434 link_entry(adb, bucket, entry); 3435 DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry); 3436 } else 3437 DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry); 3438 3439 port = isc_sockaddr_getport(sa); 3440 addr = new_adbaddrinfo(adb, entry, port); 3441 if (addr != NULL) { 3442 inc_entry_refcnt(adb, entry, ISC_FALSE); 3443 *addrp = addr; 3444 } 3445 3446 unlock: 3447 UNLOCK(&adb->entrylocks[bucket]); 3448 3449 return (result); 3450} 3451 3452void 3453dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) { 3454 dns_adbaddrinfo_t *addr; 3455 dns_adbentry_t *entry; 3456 int bucket; 3457 isc_stdtime_t now; 3458 isc_boolean_t want_check_exit = ISC_FALSE; 3459 3460 REQUIRE(DNS_ADB_VALID(adb)); 3461 REQUIRE(addrp != NULL); 3462 addr = *addrp; 3463 REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3464 entry = addr->entry; 3465 REQUIRE(DNS_ADBENTRY_VALID(entry)); 3466 3467 isc_stdtime_get(&now); 3468 3469 *addrp = NULL; 3470 3471 bucket = addr->entry->lock_bucket; 3472 LOCK(&adb->entrylocks[bucket]); 3473 3474 entry->expires = now + ADB_ENTRY_WINDOW; 3475 3476 want_check_exit = dec_entry_refcnt(adb, entry, ISC_FALSE); 3477 3478 UNLOCK(&adb->entrylocks[bucket]); 3479 3480 addr->entry = NULL; 3481 free_adbaddrinfo(adb, &addr); 3482 3483 if (want_check_exit) { 3484 LOCK(&adb->lock); 3485 check_exit(adb); 3486 UNLOCK(&adb->lock); 3487 } 3488} 3489 3490void 3491dns_adb_flush(dns_adb_t *adb) { 3492 unsigned int i; 3493 3494 INSIST(DNS_ADB_VALID(adb)); 3495 3496 LOCK(&adb->lock); 3497 3498 for (i = 0; i < NBUCKETS; i++) { 3499 /* 3500 * Call our cleanup routines. 3501 */ 3502 RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE); 3503 RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE); 3504 } 3505 3506#ifdef DUMP_ADB_AFTER_CLEANING 3507 dump_adb(adb, stdout, ISC_TRUE); 3508#endif 3509 3510 UNLOCK(&adb->lock); 3511} 3512 3513void 3514dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) { 3515 dns_adbname_t *adbname; 3516 dns_adbname_t *nextname; 3517 int bucket; 3518 3519 INSIST(DNS_ADB_VALID(adb)); 3520 3521 LOCK(&adb->lock); 3522 bucket = dns_name_hash(name, ISC_FALSE) % NBUCKETS; 3523 LOCK(&adb->namelocks[bucket]); 3524 adbname = ISC_LIST_HEAD(adb->names[bucket]); 3525 while (adbname != NULL) { 3526 nextname = ISC_LIST_NEXT(adbname, plink); 3527 if (!NAME_DEAD(adbname) && 3528 dns_name_equal(name, &adbname->name)) { 3529 RUNTIME_CHECK(kill_name(&adbname, 3530 DNS_EVENT_ADBCANCELED) == 3531 ISC_FALSE); 3532 } 3533 adbname = nextname; 3534 } 3535 UNLOCK(&adb->namelocks[bucket]); 3536 UNLOCK(&adb->lock); 3537} 3538 3539static void 3540water(void *arg, int mark) { 3541 dns_adb_t *adb = arg; 3542 isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER); 3543 isc_interval_t interval; 3544 3545 REQUIRE(DNS_ADB_VALID(adb)); 3546 3547 DP(ISC_LOG_DEBUG(1), 3548 "adb reached %s water mark", overmem ? "high" : "low"); 3549 3550 adb->overmem = overmem; 3551 if (overmem) { 3552 isc_interval_set(&interval, 0, 1); 3553 (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL, 3554 &interval, ISC_TRUE); 3555 } 3556} 3557 3558void 3559dns_adb_setadbsize(dns_adb_t *adb, isc_uint32_t size) { 3560 isc_uint32_t hiwater; 3561 isc_uint32_t lowater; 3562 3563 INSIST(DNS_ADB_VALID(adb)); 3564 3565 if (size != 0 && size < DNS_ADB_MINADBSIZE) 3566 size = DNS_ADB_MINADBSIZE; 3567 3568 hiwater = size - (size >> 3); /* Approximately 7/8ths. */ 3569 lowater = size - (size >> 2); /* Approximately 3/4ths. */ 3570 3571 if (size == 0 || hiwater == 0 || lowater == 0) 3572 isc_mem_setwater(adb->mctx, water, adb, 0, 0); 3573 else 3574 isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater); 3575} 3576