2 * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or 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.
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.
18 /* $Id: adb.c,v 1.254.14.4 2011-03-13 03:36:47 marka Exp $ */
23 * In finds, if task == NULL, no events will be generated, and no events
24 * have been sent. If task != NULL but taskaction == NULL, an event has been
25 * posted but not yet freed. If neither are NULL, no event was posted.
33 #include <isc/mutexblock.h>
34 #include <isc/netaddr.h>
35 #include <isc/random.h>
36 #include <isc/stats.h>
37 #include <isc/string.h> /* Required for HP/UX (and others?) */
43 #include <dns/events.h>
45 #include <dns/rdata.h>
46 #include <dns/rdataset.h>
47 #include <dns/rdatastruct.h>
48 #include <dns/rdatatype.h>
49 #include <dns/resolver.h>
50 #include <dns/result.h>
51 #include <dns/stats.h>
53 #define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b')
54 #define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
55 #define DNS_ADBNAME_MAGIC ISC_MAGIC('a', 'd', 'b', 'N')
56 #define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
57 #define DNS_ADBNAMEHOOK_MAGIC ISC_MAGIC('a', 'd', 'N', 'H')
58 #define DNS_ADBNAMEHOOK_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
59 #define DNS_ADBLAMEINFO_MAGIC ISC_MAGIC('a', 'd', 'b', 'Z')
60 #define DNS_ADBLAMEINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBLAMEINFO_MAGIC)
61 #define DNS_ADBENTRY_MAGIC ISC_MAGIC('a', 'd', 'b', 'E')
62 #define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
63 #define DNS_ADBFETCH_MAGIC ISC_MAGIC('a', 'd', 'F', '4')
64 #define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
65 #define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6')
66 #define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
69 * For type 3 negative cache entries, we will remember that the address is
70 * broken for this long. XXXMLG This is also used for actual addresses, too.
71 * The intent is to keep us from constantly asking about A/AAAA records
72 * if the zone has extremely low TTLs.
74 #define ADB_CACHE_MINIMUM 10 /*%< seconds */
75 #define ADB_CACHE_MAXIMUM 86400 /*%< seconds (86400 = 24 hours) */
76 #define ADB_ENTRY_WINDOW 1800 /*%< seconds */
79 * The period in seconds after which an ADB name entry is regarded as stale
80 * and forced to be cleaned up.
81 * TODO: This should probably be configurable at run-time.
83 #ifndef ADB_STALE_MARGIN
84 #define ADB_STALE_MARGIN 1800
87 #define FREE_ITEMS 64 /*%< free count for memory pools */
88 #define FILL_COUNT 16 /*%< fill count for memory pools */
90 #define DNS_ADB_INVALIDBUCKET (-1) /*%< invalid bucket address */
92 #define DNS_ADB_MINADBSIZE (1024*1024) /*%< 1 Megabyte */
94 typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
95 typedef struct dns_adbnamehook dns_adbnamehook_t;
96 typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
97 typedef struct dns_adblameinfo dns_adblameinfo_t;
98 typedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t;
99 typedef struct dns_adbfetch dns_adbfetch_t;
100 typedef struct dns_adbfetch6 dns_adbfetch6_t;
102 /*% dns adb structure */
107 isc_mutex_t reflock; /*%< Covers irefcnt, erefcnt */
108 isc_mutex_t overmemlock; /*%< Covers overmem */
112 isc_taskmgr_t *taskmgr;
115 isc_interval_t tick_interval;
116 int next_cleanbucket;
118 unsigned int irefcnt;
119 unsigned int erefcnt;
122 isc_mempool_t *nmp; /*%< dns_adbname_t */
123 isc_mempool_t *nhmp; /*%< dns_adbnamehook_t */
124 isc_mempool_t *limp; /*%< dns_adblameinfo_t */
125 isc_mempool_t *emp; /*%< dns_adbentry_t */
126 isc_mempool_t *ahmp; /*%< dns_adbfind_t */
127 isc_mempool_t *aimp; /*%< dns_adbaddrinfo_t */
128 isc_mempool_t *afmp; /*%< dns_adbfetch_t */
131 * Bucketized locks and lists for names.
133 * XXXRTH Have a per-bucket structure that contains all of these?
136 isc_mutex_t namescntlock;
137 unsigned int namescnt;
138 dns_adbnamelist_t *names;
139 dns_adbnamelist_t *deadnames;
140 isc_mutex_t *namelocks;
141 isc_boolean_t *name_sd;
142 unsigned int *name_refcnt;
145 * Bucketized locks and lists for entries.
147 * XXXRTH Have a per-bucket structure that contains all of these?
149 unsigned int nentries;
150 isc_mutex_t entriescntlock;
151 unsigned int entriescnt;
152 dns_adbentrylist_t *entries;
153 dns_adbentrylist_t *deadentries;
154 isc_mutex_t *entrylocks;
155 isc_boolean_t *entry_sd; /*%< shutting down */
156 unsigned int *entry_refcnt;
159 isc_boolean_t cevent_sent;
160 isc_boolean_t shutting_down;
161 isc_eventlist_t whenshutdown;
162 isc_event_t growentries;
163 isc_boolean_t growentries_sent;
164 isc_event_t grownames;
165 isc_boolean_t grownames_sent;
169 * XXXMLG Document these structures.
172 /*% dns_adbname structure */
177 unsigned int partial_result;
181 isc_stdtime_t expire_target;
182 isc_stdtime_t expire_v4;
183 isc_stdtime_t expire_v6;
185 dns_adbnamehooklist_t v4;
186 dns_adbnamehooklist_t v6;
187 dns_adbfetch_t *fetch_a;
188 dns_adbfetch_t *fetch_aaaa;
189 unsigned int fetch_err;
190 unsigned int fetch6_err;
191 dns_adbfindlist_t finds;
192 /* for LRU-based management */
193 isc_stdtime_t last_used;
195 ISC_LINK(dns_adbname_t) plink;
198 /*% The adbfetch structure */
199 struct dns_adbfetch {
202 dns_rdataset_t rdataset;
206 * This is a small widget that dangles off a dns_adbname_t. It contains a
207 * pointer to the address information about this host, and a link to the next
208 * namehook that will contain the next address this host has.
210 struct dns_adbnamehook {
212 dns_adbentry_t *entry;
213 ISC_LINK(dns_adbnamehook_t) plink;
217 * This is a small widget that holds qname-specific information about an
218 * address. Currently limited to lameness, but could just as easily be
219 * extended to other types of information about zones.
221 struct dns_adblameinfo {
225 dns_rdatatype_t qtype;
226 isc_stdtime_t lame_timer;
228 ISC_LINK(dns_adblameinfo_t) plink;
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
236 struct dns_adbentry {
244 isc_sockaddr_t sockaddr;
246 isc_stdtime_t expires;
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
255 ISC_LIST(dns_adblameinfo_t) lameinfo;
256 ISC_LINK(dns_adbentry_t) plink;
260 * Internal functions (and prototypes).
262 static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
263 static inline void free_adbname(dns_adb_t *, dns_adbname_t **);
264 static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
266 static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
267 static inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *, dns_name_t *,
269 static inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **);
270 static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
271 static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
272 static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
273 static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
274 static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
276 static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
277 static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
278 static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
279 unsigned int, int *);
280 static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
281 isc_sockaddr_t *, int *,
283 static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t);
284 static void print_dns_name(FILE *, dns_name_t *);
285 static void print_namehook_list(FILE *, const char *legend,
286 dns_adbnamehooklist_t *list,
289 static void print_find_list(FILE *, dns_adbname_t *);
290 static void print_fetch_list(FILE *, dns_adbname_t *);
291 static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
292 static inline void inc_adb_irefcnt(dns_adb_t *);
293 static inline void inc_adb_erefcnt(dns_adb_t *);
294 static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
296 static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, isc_boolean_t,
297 dns_adbentry_t *, isc_boolean_t);
298 static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
299 static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
300 static void clean_target(dns_adb_t *, dns_name_t *);
301 static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
303 static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
304 static isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **,
306 static void cancel_fetches_at_name(dns_adbname_t *);
307 static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
309 static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
311 static inline void check_exit(dns_adb_t *);
312 static void destroy(dns_adb_t *);
313 static isc_boolean_t shutdown_names(dns_adb_t *);
314 static isc_boolean_t shutdown_entries(dns_adb_t *);
315 static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
316 static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *);
317 static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
318 static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
319 static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
320 static void water(void *, int);
321 static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t);
324 * MUST NOT overlap DNS_ADBFIND_* flags!
326 #define FIND_EVENT_SENT 0x40000000
327 #define FIND_EVENT_FREED 0x80000000
328 #define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0)
329 #define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0)
331 #define NAME_NEEDS_POKE 0x80000000
332 #define NAME_IS_DEAD 0x40000000
333 #define NAME_HINT_OK DNS_ADBFIND_HINTOK
334 #define NAME_GLUE_OK DNS_ADBFIND_GLUEOK
335 #define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE
336 #define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0)
337 #define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0)
338 #define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0)
339 #define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0)
342 * Private flag(s) for entries.
343 * MUST NOT overlap FCTX_ADDRINFO_xxx and DNS_FETCHOPT_NOEDNS0.
345 #define ENTRY_IS_DEAD 0x80000000
348 * To the name, address classes are all that really exist. If it has a
349 * V6 address it doesn't care if it came from a AAAA query.
351 #define NAME_HAS_V4(n) (!ISC_LIST_EMPTY((n)->v4))
352 #define NAME_HAS_V6(n) (!ISC_LIST_EMPTY((n)->v6))
353 #define NAME_HAS_ADDRS(n) (NAME_HAS_V4(n) || NAME_HAS_V6(n))
356 * Fetches are broken out into A and AAAA types. In some cases,
357 * however, it makes more sense to test for a particular class of fetches,
358 * like V4 or V6 above.
359 * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA
360 * are now equal to FETCH_V4 and FETCH_V6, respectively.
362 #define NAME_FETCH_A(n) ((n)->fetch_a != NULL)
363 #define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL)
364 #define NAME_FETCH_V4(n) (NAME_FETCH_A(n))
365 #define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n))
366 #define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
369 * Find options and tests to see if there are addresses on the list.
371 #define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
372 #define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
373 #define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
375 #define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \
377 #define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
378 #define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
379 #define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list))
380 #define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
383 * These are currently used on simple unsigned ints, so they are
384 * not really associated with any particular type.
386 #define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0)
387 #define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0)
389 #define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now))
392 * Find out if the flags on a name (nf) indicate if it is a hint or
393 * glue, and compare this to the appropriate bits set in o, to see if
396 #define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0))
397 #define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0))
398 #define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o))
399 #define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \
400 ((o) & DNS_ADBFIND_STARTATZONE))
402 #define ENTER_LEVEL ISC_LOG_DEBUG(50)
403 #define EXIT_LEVEL ENTER_LEVEL
404 #define CLEAN_LEVEL ISC_LOG_DEBUG(100)
405 #define DEF_LEVEL ISC_LOG_DEBUG(5)
406 #define NCACHE_LEVEL ISC_LOG_DEBUG(20)
408 #define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \
409 (r) == DNS_R_NCACHENXRRSET)
410 #define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \
411 (r) == DNS_R_NXRRSET)
412 #define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \
413 (r) == DNS_R_NCACHENXDOMAIN)
414 #define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \
415 (r) == DNS_R_NXRRSET || \
416 (r) == DNS_R_HINTNXRRSET)
419 * Error state rankings.
422 #define FIND_ERR_SUCCESS 0 /* highest rank */
423 #define FIND_ERR_CANCELED 1
424 #define FIND_ERR_FAILURE 2
425 #define FIND_ERR_NXDOMAIN 3
426 #define FIND_ERR_NXRRSET 4
427 #define FIND_ERR_UNEXPECTED 5
428 #define FIND_ERR_NOTFOUND 6
429 #define FIND_ERR_MAX 7
431 static const char *errnames[] = {
441 #define NEWERR(old, new) (ISC_MIN((old), (new)))
443 static isc_result_t find_err_map[FIND_ERR_MAX] = {
450 ISC_R_NOTFOUND /* not YET found */
454 DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
457 DP(int level, const char *format, ...) {
460 va_start(args, format);
461 isc_log_vwrite(dns_lctx,
462 DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
463 level, format, args);
468 * Increment resolver-related statistics counters.
471 inc_stats(dns_adb_t *adb, isc_statscounter_t counter) {
472 if (adb->view->resstats != NULL)
473 isc_stats_increment(adb->view->resstats, counter);
476 static inline dns_ttl_t
477 ttlclamp(dns_ttl_t ttl) {
478 if (ttl < ADB_CACHE_MINIMUM)
479 ttl = ADB_CACHE_MINIMUM;
480 if (ttl > ADB_CACHE_MAXIMUM)
481 ttl = ADB_CACHE_MAXIMUM;
487 * Hashing is most efficient if the number of buckets is prime.
488 * The sequence below is the closest previous primes to 2^n and
489 * 1.5 * 2^n, for values of n from 10 to 28. (The tables will
490 * no longer grow beyond 2^28 entries.)
492 static const unsigned nbuckets[] = { 1021, 1531, 2039, 3067, 4093, 6143,
493 8191, 12281, 16381, 24571, 32749,
494 49193, 65521, 98299, 131071, 199603,
495 262139, 393209, 524287, 768431, 1048573,
496 1572853, 2097143, 3145721, 4194301,
497 6291449, 8388593, 12582893, 16777213,
498 25165813, 33554393, 50331599, 67108859,
499 100663291, 134217689, 201326557,
503 grow_entries(isc_task_t *task, isc_event_t *ev) {
506 dns_adbentrylist_t *newdeadentries = NULL;
507 dns_adbentrylist_t *newentries = NULL;
508 isc_boolean_t *newentry_sd = NULL;
509 isc_mutex_t *newentrylocks = NULL;
511 unsigned int *newentry_refcnt = NULL;
512 unsigned int i, n, bucket;
515 INSIST(DNS_ADB_VALID(adb));
519 isc_task_beginexclusive(task);
522 while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i])
524 if (nbuckets[i] != 0)
529 DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n);
532 * Are we shutting down?
534 for (i = 0; i < adb->nentries; i++)
535 if (adb->entry_sd[i])
539 * Grab all the resources we need.
541 newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n);
542 newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n);
543 newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n);
544 newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n);
545 newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n);
546 if (newentries == NULL || newdeadentries == NULL ||
547 newentrylocks == NULL || newentry_sd == NULL ||
548 newentry_refcnt == NULL)
552 * Initialise the new resources.
554 result = isc_mutexblock_init(newentrylocks, n);
555 if (result != ISC_R_SUCCESS)
558 for (i = 0; i < n; i++) {
559 ISC_LIST_INIT(newentries[i]);
560 ISC_LIST_INIT(newdeadentries[i]);
561 newentry_sd[i] = ISC_FALSE;
562 newentry_refcnt[i] = 0;
567 * Move entries to new arrays.
569 for (i = 0; i < adb->nentries; i++) {
570 e = ISC_LIST_HEAD(adb->entries[i]);
572 ISC_LIST_UNLINK(adb->entries[i], e, plink);
573 bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
574 e->lock_bucket = bucket;
575 ISC_LIST_APPEND(newentries[bucket], e, plink);
576 INSIST(adb->entry_refcnt[i] > 0);
577 adb->entry_refcnt[i]--;
578 newentry_refcnt[bucket]++;
579 e = ISC_LIST_HEAD(adb->entries[i]);
581 e = ISC_LIST_HEAD(adb->deadentries[i]);
583 ISC_LIST_UNLINK(adb->deadentries[i], e, plink);
584 bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
585 e->lock_bucket = bucket;
586 ISC_LIST_APPEND(newdeadentries[bucket], e, plink);
587 INSIST(adb->entry_refcnt[i] > 0);
588 adb->entry_refcnt[i]--;
589 newentry_refcnt[bucket]++;
590 e = ISC_LIST_HEAD(adb->deadentries[i]);
592 INSIST(adb->entry_refcnt[i] == 0);
597 * Cleanup old resources.
599 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
600 isc_mem_put(adb->mctx, adb->entries,
601 sizeof(*adb->entries) * adb->nentries);
602 isc_mem_put(adb->mctx, adb->deadentries,
603 sizeof(*adb->deadentries) * adb->nentries);
604 isc_mem_put(adb->mctx, adb->entrylocks,
605 sizeof(*adb->entrylocks) * adb->nentries);
606 isc_mem_put(adb->mctx, adb->entry_sd,
607 sizeof(*adb->entry_sd) * adb->nentries);
608 isc_mem_put(adb->mctx, adb->entry_refcnt,
609 sizeof(*adb->entry_refcnt) * adb->nentries);
612 * Install new resources.
614 adb->entries = newentries;
615 adb->deadentries = newdeadentries;
616 adb->entrylocks = newentrylocks;
617 adb->entry_sd = newentry_sd;
618 adb->entry_refcnt = newentry_refcnt;
622 * Only on success do we set adb->growentries_sent to ISC_FALSE.
623 * This will prevent us being continuously being called on error.
625 adb->growentries_sent = ISC_FALSE;
629 if (newentries != NULL)
630 isc_mem_put(adb->mctx, newentries,
631 sizeof(*newentries) * n);
632 if (newdeadentries != NULL)
633 isc_mem_put(adb->mctx, newdeadentries,
634 sizeof(*newdeadentries) * n);
635 if (newentrylocks != NULL)
636 isc_mem_put(adb->mctx, newentrylocks,
637 sizeof(*newentrylocks) * n);
638 if (newentry_sd != NULL)
639 isc_mem_put(adb->mctx, newentry_sd,
640 sizeof(*newentry_sd) * n);
641 if (newentry_refcnt != NULL)
642 isc_mem_put(adb->mctx, newentry_refcnt,
643 sizeof(*newentry_refcnt) * n);
645 isc_task_endexclusive(task);
648 if (dec_adb_irefcnt(adb))
651 DP(ISC_LOG_INFO, "adb: grow_entries finished");
655 grow_names(isc_task_t *task, isc_event_t *ev) {
658 dns_adbnamelist_t *newdeadnames = NULL;
659 dns_adbnamelist_t *newnames = NULL;
660 isc_boolean_t *newname_sd = NULL;
661 isc_mutex_t *newnamelocks = NULL;
663 unsigned int *newname_refcnt = NULL;
664 unsigned int i, n, bucket;
667 INSIST(DNS_ADB_VALID(adb));
671 isc_task_beginexclusive(task);
674 while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i])
676 if (nbuckets[i] != 0)
681 DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n);
684 * Are we shutting down?
686 for (i = 0; i < adb->nnames; i++)
691 * Grab all the resources we need.
693 newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n);
694 newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n);
695 newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n);
696 newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n);
697 newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n);
698 if (newnames == NULL || newdeadnames == NULL ||
699 newnamelocks == NULL || newname_sd == NULL ||
700 newname_refcnt == NULL)
704 * Initialise the new resources.
706 result = isc_mutexblock_init(newnamelocks, n);
707 if (result != ISC_R_SUCCESS)
710 for (i = 0; i < n; i++) {
711 ISC_LIST_INIT(newnames[i]);
712 ISC_LIST_INIT(newdeadnames[i]);
713 newname_sd[i] = ISC_FALSE;
714 newname_refcnt[i] = 0;
719 * Move names to new arrays.
721 for (i = 0; i < adb->nnames; i++) {
722 name = ISC_LIST_HEAD(adb->names[i]);
723 while (name != NULL) {
724 ISC_LIST_UNLINK(adb->names[i], name, plink);
725 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
726 name->lock_bucket = bucket;
727 ISC_LIST_APPEND(newnames[bucket], name, plink);
728 INSIST(adb->name_refcnt[i] > 0);
729 adb->name_refcnt[i]--;
730 newname_refcnt[bucket]++;
731 name = ISC_LIST_HEAD(adb->names[i]);
733 name = ISC_LIST_HEAD(adb->deadnames[i]);
734 while (name != NULL) {
735 ISC_LIST_UNLINK(adb->deadnames[i], name, plink);
736 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
737 name->lock_bucket = bucket;
738 ISC_LIST_APPEND(newdeadnames[bucket], name, plink);
739 INSIST(adb->name_refcnt[i] > 0);
740 adb->name_refcnt[i]--;
741 newname_refcnt[bucket]++;
742 name = ISC_LIST_HEAD(adb->deadnames[i]);
744 INSIST(adb->name_refcnt[i] == 0);
749 * Cleanup old resources.
751 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
752 isc_mem_put(adb->mctx, adb->names,
753 sizeof(*adb->names) * adb->nnames);
754 isc_mem_put(adb->mctx, adb->deadnames,
755 sizeof(*adb->deadnames) * adb->nnames);
756 isc_mem_put(adb->mctx, adb->namelocks,
757 sizeof(*adb->namelocks) * adb->nnames);
758 isc_mem_put(adb->mctx, adb->name_sd,
759 sizeof(*adb->name_sd) * adb->nnames);
760 isc_mem_put(adb->mctx, adb->name_refcnt,
761 sizeof(*adb->name_refcnt) * adb->nnames);
764 * Install new resources.
766 adb->names = newnames;
767 adb->deadnames = newdeadnames;
768 adb->namelocks = newnamelocks;
769 adb->name_sd = newname_sd;
770 adb->name_refcnt = newname_refcnt;
774 * Only on success do we set adb->grownames_sent to ISC_FALSE.
775 * This will prevent us being continuously being called on error.
777 adb->grownames_sent = ISC_FALSE;
781 if (newnames != NULL)
782 isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n);
783 if (newdeadnames != NULL)
784 isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n);
785 if (newnamelocks != NULL)
786 isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n);
787 if (newname_sd != NULL)
788 isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n);
789 if (newname_refcnt != NULL)
790 isc_mem_put(adb->mctx, newname_refcnt,
791 sizeof(*newname_refcnt) * n);
793 isc_task_endexclusive(task);
796 if (dec_adb_irefcnt(adb))
799 DP(ISC_LOG_INFO, "adb: grow_names finished");
803 * Requires the adbname bucket be locked and that no entry buckets be locked.
805 * This code handles A and AAAA rdatasets only.
808 import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
813 dns_adbnamehook_t *nh;
814 dns_adbnamehook_t *anh;
815 dns_rdata_t rdata = DNS_RDATA_INIT;
817 struct in6_addr in6a;
818 isc_sockaddr_t sockaddr;
819 dns_adbentry_t *foundentry; /* NO CLEAN UP! */
821 isc_boolean_t new_addresses_added;
822 dns_rdatatype_t rdtype;
823 unsigned int findoptions;
824 dns_adbnamehooklist_t *hookhead;
826 INSIST(DNS_ADBNAME_VALID(adbname));
828 INSIST(DNS_ADB_VALID(adb));
830 rdtype = rdataset->type;
831 INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
832 if (rdtype == dns_rdatatype_a)
833 findoptions = DNS_ADBFIND_INET;
835 findoptions = DNS_ADBFIND_INET6;
837 addr_bucket = DNS_ADB_INVALIDBUCKET;
838 new_addresses_added = ISC_FALSE;
841 result = dns_rdataset_first(rdataset);
842 while (result == ISC_R_SUCCESS) {
843 dns_rdata_reset(&rdata);
844 dns_rdataset_current(rdataset, &rdata);
845 if (rdtype == dns_rdatatype_a) {
846 INSIST(rdata.length == 4);
847 memcpy(&ina.s_addr, rdata.data, 4);
848 isc_sockaddr_fromin(&sockaddr, &ina, 0);
849 hookhead = &adbname->v4;
851 INSIST(rdata.length == 16);
852 memcpy(in6a.s6_addr, rdata.data, 16);
853 isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
854 hookhead = &adbname->v6;
858 nh = new_adbnamehook(adb, NULL);
860 adbname->partial_result |= findoptions;
861 result = ISC_R_NOMEMORY;
865 foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket,
867 if (foundentry == NULL) {
868 dns_adbentry_t *entry;
870 entry = new_adbentry(adb);
872 adbname->partial_result |= findoptions;
873 result = ISC_R_NOMEMORY;
877 entry->sockaddr = sockaddr;
882 link_entry(adb, addr_bucket, entry);
884 for (anh = ISC_LIST_HEAD(*hookhead);
886 anh = ISC_LIST_NEXT(anh, plink))
887 if (anh->entry == foundentry)
890 foundentry->refcnt++;
891 nh->entry = foundentry;
893 free_adbnamehook(adb, &nh);
896 new_addresses_added = ISC_TRUE;
898 ISC_LIST_APPEND(*hookhead, nh, plink);
900 result = dns_rdataset_next(rdataset);
905 free_adbnamehook(adb, &nh);
907 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
908 UNLOCK(&adb->entrylocks[addr_bucket]);
910 if (rdataset->trust == dns_trust_glue ||
911 rdataset->trust == dns_trust_additional)
912 rdataset->ttl = ADB_CACHE_MINIMUM;
913 else if (rdataset->trust == dns_trust_ultimate)
916 rdataset->ttl = ttlclamp(rdataset->ttl);
918 if (rdtype == dns_rdatatype_a) {
919 DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
920 adbname->expire_v4, now + rdataset->ttl);
921 adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
922 now + rdataset->ttl);
924 DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
925 adbname->expire_v6, now + rdataset->ttl);
926 adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
927 now + rdataset->ttl);
930 if (new_addresses_added) {
932 * Lie a little here. This is more or less so code that cares
933 * can find out if any new information was added or not.
935 return (ISC_R_SUCCESS);
942 * Requires the name's bucket be locked.
945 kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
947 isc_boolean_t result = ISC_FALSE;
948 isc_boolean_t result4, result6;
955 INSIST(DNS_ADBNAME_VALID(name));
957 INSIST(DNS_ADB_VALID(adb));
959 DP(DEF_LEVEL, "killing name %p", name);
962 * If we're dead already, just check to see if we should go
965 if (NAME_DEAD(name) && !NAME_FETCH(name)) {
966 result = unlink_name(adb, name);
967 free_adbname(adb, &name);
969 result = dec_adb_irefcnt(adb);
974 * Clean up the name's various lists. These two are destructive
975 * in that they will always empty the list.
977 clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
978 result4 = clean_namehooks(adb, &name->v4);
979 result6 = clean_namehooks(adb, &name->v6);
980 clean_target(adb, &name->target);
981 result = ISC_TF(result4 || result6);
984 * If fetches are running, cancel them. If none are running, we can
985 * just kill the name here.
987 if (!NAME_FETCH(name)) {
988 INSIST(result == ISC_FALSE);
989 result = unlink_name(adb, name);
990 free_adbname(adb, &name);
992 result = dec_adb_irefcnt(adb);
994 cancel_fetches_at_name(name);
995 if (!NAME_DEAD(name)) {
996 bucket = name->lock_bucket;
997 ISC_LIST_UNLINK(adb->names[bucket], name, plink);
998 ISC_LIST_APPEND(adb->deadnames[bucket], name, plink);
999 name->flags |= NAME_IS_DEAD;
1006 * Requires the name's bucket be locked and no entry buckets be locked.
1008 static isc_boolean_t
1009 check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
1011 isc_boolean_t result4 = ISC_FALSE;
1012 isc_boolean_t result6 = ISC_FALSE;
1014 INSIST(DNS_ADBNAME_VALID(name));
1016 INSIST(DNS_ADB_VALID(adb));
1019 * Check to see if we need to remove the v4 addresses
1021 if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) {
1022 if (NAME_HAS_V4(name)) {
1023 DP(DEF_LEVEL, "expiring v4 for name %p", name);
1024 result4 = clean_namehooks(adb, &name->v4);
1025 name->partial_result &= ~DNS_ADBFIND_INET;
1027 name->expire_v4 = INT_MAX;
1028 name->fetch_err = FIND_ERR_UNEXPECTED;
1032 * Check to see if we need to remove the v6 addresses
1034 if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) {
1035 if (NAME_HAS_V6(name)) {
1036 DP(DEF_LEVEL, "expiring v6 for name %p", name);
1037 result6 = clean_namehooks(adb, &name->v6);
1038 name->partial_result &= ~DNS_ADBFIND_INET6;
1040 name->expire_v6 = INT_MAX;
1041 name->fetch6_err = FIND_ERR_UNEXPECTED;
1045 * Check to see if we need to remove the alias target.
1047 if (EXPIRE_OK(name->expire_target, now)) {
1048 clean_target(adb, &name->target);
1049 name->expire_target = INT_MAX;
1051 return (ISC_TF(result4 || result6));
1055 * Requires the name's bucket be locked.
1058 link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
1059 INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
1061 ISC_LIST_PREPEND(adb->names[bucket], name, plink);
1062 name->lock_bucket = bucket;
1063 adb->name_refcnt[bucket]++;
1067 * Requires the name's bucket be locked.
1069 static inline isc_boolean_t
1070 unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
1072 isc_boolean_t result = ISC_FALSE;
1074 bucket = name->lock_bucket;
1075 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
1077 if (NAME_DEAD(name))
1078 ISC_LIST_UNLINK(adb->deadnames[bucket], name, plink);
1080 ISC_LIST_UNLINK(adb->names[bucket], name, plink);
1081 name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1082 INSIST(adb->name_refcnt[bucket] > 0);
1083 adb->name_refcnt[bucket]--;
1084 if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
1090 * Requires the entry's bucket be locked.
1093 link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
1097 if (isc_mem_isovermem(adb->mctx)) {
1098 for (i = 0; i < 2; i++) {
1099 e = ISC_LIST_TAIL(adb->entries[bucket]);
1102 if (e->refcnt == 0) {
1103 unlink_entry(adb, e);
1104 free_adbentry(adb, &e);
1107 INSIST((e->flags & ENTRY_IS_DEAD) == 0);
1108 e->flags |= ENTRY_IS_DEAD;
1109 ISC_LIST_UNLINK(adb->entries[bucket], e, plink);
1110 ISC_LIST_PREPEND(adb->deadentries[bucket], e, plink);
1114 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
1115 entry->lock_bucket = bucket;
1116 adb->entry_refcnt[bucket]++;
1120 * Requires the entry's bucket be locked.
1122 static inline isc_boolean_t
1123 unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
1125 isc_boolean_t result = ISC_FALSE;
1127 bucket = entry->lock_bucket;
1128 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
1130 if ((entry->flags & ENTRY_IS_DEAD) != 0)
1131 ISC_LIST_UNLINK(adb->deadentries[bucket], entry, plink);
1133 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
1134 entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1135 INSIST(adb->entry_refcnt[bucket] > 0);
1136 adb->entry_refcnt[bucket]--;
1137 if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
1143 violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
1144 if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
1152 * The ADB _MUST_ be locked before calling. Also, exit conditions must be
1153 * checked after calling this function.
1155 static isc_boolean_t
1156 shutdown_names(dns_adb_t *adb) {
1157 unsigned int bucket;
1158 isc_boolean_t result = ISC_FALSE;
1159 dns_adbname_t *name;
1160 dns_adbname_t *next_name;
1162 for (bucket = 0; bucket < adb->nnames; bucket++) {
1163 LOCK(&adb->namelocks[bucket]);
1164 adb->name_sd[bucket] = ISC_TRUE;
1166 name = ISC_LIST_HEAD(adb->names[bucket]);
1169 * This bucket has no names. We must decrement the
1170 * irefcnt ourselves, since it will not be
1171 * automatically triggered by a name being unlinked.
1173 INSIST(result == ISC_FALSE);
1174 result = dec_adb_irefcnt(adb);
1177 * Run through the list. For each name, clean up finds
1178 * found there, and cancel any fetches running. When
1179 * all the fetches are canceled, the name will destroy
1182 while (name != NULL) {
1183 next_name = ISC_LIST_NEXT(name, plink);
1184 INSIST(result == ISC_FALSE);
1185 result = kill_name(&name,
1186 DNS_EVENT_ADBSHUTDOWN);
1191 UNLOCK(&adb->namelocks[bucket]);
1197 * The ADB _MUST_ be locked before calling. Also, exit conditions must be
1198 * checked after calling this function.
1200 static isc_boolean_t
1201 shutdown_entries(dns_adb_t *adb) {
1202 unsigned int bucket;
1203 isc_boolean_t result = ISC_FALSE;
1204 dns_adbentry_t *entry;
1205 dns_adbentry_t *next_entry;
1207 for (bucket = 0; bucket < adb->nentries; bucket++) {
1208 LOCK(&adb->entrylocks[bucket]);
1209 adb->entry_sd[bucket] = ISC_TRUE;
1211 entry = ISC_LIST_HEAD(adb->entries[bucket]);
1212 if (adb->entry_refcnt[bucket] == 0) {
1214 * This bucket has no entries. We must decrement the
1215 * irefcnt ourselves, since it will not be
1216 * automatically triggered by an entry being unlinked.
1218 result = dec_adb_irefcnt(adb);
1221 * Run through the list. Cleanup any entries not
1222 * associated with names, and which are not in use.
1224 while (entry != NULL) {
1225 next_entry = ISC_LIST_NEXT(entry, plink);
1226 if (entry->refcnt == 0 &&
1227 entry->expires != 0) {
1228 result = unlink_entry(adb, entry);
1229 free_adbentry(adb, &entry);
1231 result = dec_adb_irefcnt(adb);
1237 UNLOCK(&adb->entrylocks[bucket]);
1243 * Name bucket must be locked
1246 cancel_fetches_at_name(dns_adbname_t *name) {
1247 if (NAME_FETCH_A(name))
1248 dns_resolver_cancelfetch(name->fetch_a->fetch);
1250 if (NAME_FETCH_AAAA(name))
1251 dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
1255 * Assumes the name bucket is locked.
1257 static isc_boolean_t
1258 clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
1259 dns_adbentry_t *entry;
1260 dns_adbnamehook_t *namehook;
1262 isc_boolean_t result = ISC_FALSE;
1263 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
1265 addr_bucket = DNS_ADB_INVALIDBUCKET;
1266 namehook = ISC_LIST_HEAD(*namehooks);
1267 while (namehook != NULL) {
1268 INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
1271 * Clean up the entry if needed.
1273 entry = namehook->entry;
1274 if (entry != NULL) {
1275 INSIST(DNS_ADBENTRY_VALID(entry));
1277 if (addr_bucket != entry->lock_bucket) {
1278 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1279 UNLOCK(&adb->entrylocks[addr_bucket]);
1280 addr_bucket = entry->lock_bucket;
1281 LOCK(&adb->entrylocks[addr_bucket]);
1284 result = dec_entry_refcnt(adb, overmem, entry,
1291 namehook->entry = NULL;
1292 ISC_LIST_UNLINK(*namehooks, namehook, plink);
1293 free_adbnamehook(adb, &namehook);
1295 namehook = ISC_LIST_HEAD(*namehooks);
1298 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1299 UNLOCK(&adb->entrylocks[addr_bucket]);
1304 clean_target(dns_adb_t *adb, dns_name_t *target) {
1305 if (dns_name_countlabels(target) > 0) {
1306 dns_name_free(target, adb->mctx);
1307 dns_name_init(target, NULL);
1312 set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
1313 dns_rdataset_t *rdataset, dns_name_t *target)
1315 isc_result_t result;
1316 dns_namereln_t namereln;
1317 unsigned int nlabels;
1319 dns_rdata_t rdata = DNS_RDATA_INIT;
1320 dns_fixedname_t fixed1, fixed2;
1321 dns_name_t *prefix, *new_target;
1323 REQUIRE(dns_name_countlabels(target) == 0);
1325 if (rdataset->type == dns_rdatatype_cname) {
1326 dns_rdata_cname_t cname;
1329 * Copy the CNAME's target into the target name.
1331 result = dns_rdataset_first(rdataset);
1332 if (result != ISC_R_SUCCESS)
1334 dns_rdataset_current(rdataset, &rdata);
1335 result = dns_rdata_tostruct(&rdata, &cname, NULL);
1336 if (result != ISC_R_SUCCESS)
1338 result = dns_name_dup(&cname.cname, adb->mctx, target);
1339 dns_rdata_freestruct(&cname);
1340 if (result != ISC_R_SUCCESS)
1343 dns_rdata_dname_t dname;
1345 INSIST(rdataset->type == dns_rdatatype_dname);
1346 namereln = dns_name_fullcompare(name, fname, &order, &nlabels);
1347 INSIST(namereln == dns_namereln_subdomain);
1349 * Get the target name of the DNAME.
1351 result = dns_rdataset_first(rdataset);
1352 if (result != ISC_R_SUCCESS)
1354 dns_rdataset_current(rdataset, &rdata);
1355 result = dns_rdata_tostruct(&rdata, &dname, NULL);
1356 if (result != ISC_R_SUCCESS)
1359 * Construct the new target name.
1361 dns_fixedname_init(&fixed1);
1362 prefix = dns_fixedname_name(&fixed1);
1363 dns_fixedname_init(&fixed2);
1364 new_target = dns_fixedname_name(&fixed2);
1365 dns_name_split(name, nlabels, prefix, NULL);
1366 result = dns_name_concatenate(prefix, &dname.dname, new_target,
1368 dns_rdata_freestruct(&dname);
1369 if (result != ISC_R_SUCCESS)
1371 result = dns_name_dup(new_target, adb->mctx, target);
1372 if (result != ISC_R_SUCCESS)
1376 return (ISC_R_SUCCESS);
1380 * Assumes nothing is locked, since this is called by the client.
1383 event_free(isc_event_t *event) {
1384 dns_adbfind_t *find;
1386 INSIST(event != NULL);
1387 find = event->ev_destroy_arg;
1388 INSIST(DNS_ADBFIND_VALID(find));
1391 find->flags |= FIND_EVENT_FREED;
1392 event->ev_destroy_arg = NULL;
1393 UNLOCK(&find->lock);
1397 * Assumes the name bucket is locked.
1400 clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
1405 dns_adbfind_t *find;
1406 dns_adbfind_t *next_find;
1407 isc_boolean_t process;
1408 unsigned int wanted, notify;
1411 "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
1412 name, evtype, addrs);
1414 find = ISC_LIST_HEAD(name->finds);
1415 while (find != NULL) {
1417 next_find = ISC_LIST_NEXT(find, plink);
1419 process = ISC_FALSE;
1420 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1421 notify = wanted & addrs;
1424 case DNS_EVENT_ADBMOREADDRESSES:
1425 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES");
1426 if ((notify) != 0) {
1427 find->flags &= ~addrs;
1431 case DNS_EVENT_ADBNOMOREADDRESSES:
1432 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES");
1433 find->flags &= ~addrs;
1434 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1439 find->flags &= ~addrs;
1444 DP(DEF_LEVEL, "cfan: processing find %p", find);
1446 * Unlink the find from the name, letting the caller
1447 * call dns_adb_destroyfind() on it to clean it up
1450 ISC_LIST_UNLINK(name->finds, find, plink);
1451 find->adbname = NULL;
1452 find->name_bucket = DNS_ADB_INVALIDBUCKET;
1454 INSIST(!FIND_EVENTSENT(find));
1457 task = ev->ev_sender;
1458 ev->ev_sender = find;
1459 find->result_v4 = find_err_map[name->fetch_err];
1460 find->result_v6 = find_err_map[name->fetch6_err];
1461 ev->ev_type = evtype;
1462 ev->ev_destroy = event_free;
1463 ev->ev_destroy_arg = find;
1466 "sending event %p to task %p for find %p",
1469 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
1471 DP(DEF_LEVEL, "cfan: skipping find %p", find);
1474 UNLOCK(&find->lock);
1478 DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
1482 check_exit(dns_adb_t *adb) {
1485 * The caller must be holding the adb lock.
1487 if (adb->shutting_down) {
1489 * If there aren't any external references either, we're
1490 * done. Send the control event to initiate shutdown.
1492 INSIST(!adb->cevent_sent); /* Sanity check. */
1493 event = &adb->cevent;
1494 isc_task_send(adb->task, &event);
1495 adb->cevent_sent = ISC_TRUE;
1499 static inline isc_boolean_t
1500 dec_adb_irefcnt(dns_adb_t *adb) {
1503 isc_boolean_t result = ISC_FALSE;
1505 LOCK(&adb->reflock);
1507 INSIST(adb->irefcnt > 0);
1510 if (adb->irefcnt == 0) {
1511 event = ISC_LIST_HEAD(adb->whenshutdown);
1512 while (event != NULL) {
1513 ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
1514 etask = event->ev_sender;
1515 event->ev_sender = adb;
1516 isc_task_sendanddetach(&etask, &event);
1517 event = ISC_LIST_HEAD(adb->whenshutdown);
1521 if (adb->irefcnt == 0 && adb->erefcnt == 0)
1523 UNLOCK(&adb->reflock);
1528 inc_adb_irefcnt(dns_adb_t *adb) {
1529 LOCK(&adb->reflock);
1531 UNLOCK(&adb->reflock);
1535 inc_adb_erefcnt(dns_adb_t *adb) {
1536 LOCK(&adb->reflock);
1538 UNLOCK(&adb->reflock);
1542 inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
1545 bucket = entry->lock_bucket;
1548 LOCK(&adb->entrylocks[bucket]);
1553 UNLOCK(&adb->entrylocks[bucket]);
1556 static inline isc_boolean_t
1557 dec_entry_refcnt(dns_adb_t *adb, isc_boolean_t overmem, dns_adbentry_t *entry,
1561 isc_boolean_t destroy_entry;
1562 isc_boolean_t result = ISC_FALSE;
1564 bucket = entry->lock_bucket;
1567 LOCK(&adb->entrylocks[bucket]);
1569 INSIST(entry->refcnt > 0);
1572 destroy_entry = ISC_FALSE;
1573 if (entry->refcnt == 0 &&
1574 (adb->entry_sd[bucket] || entry->expires == 0 || overmem ||
1575 (entry->flags & ENTRY_IS_DEAD) != 0)) {
1576 destroy_entry = ISC_TRUE;
1577 result = unlink_entry(adb, entry);
1581 UNLOCK(&adb->entrylocks[bucket]);
1586 entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1588 free_adbentry(adb, &entry);
1590 result = dec_adb_irefcnt(adb);
1595 static inline dns_adbname_t *
1596 new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
1597 dns_adbname_t *name;
1599 name = isc_mempool_get(adb->nmp);
1603 dns_name_init(&name->name, NULL);
1604 if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
1605 isc_mempool_put(adb->nmp, name);
1608 dns_name_init(&name->target, NULL);
1609 name->magic = DNS_ADBNAME_MAGIC;
1611 name->partial_result = 0;
1613 name->expire_v4 = INT_MAX;
1614 name->expire_v6 = INT_MAX;
1615 name->expire_target = INT_MAX;
1617 name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1618 ISC_LIST_INIT(name->v4);
1619 ISC_LIST_INIT(name->v6);
1620 name->fetch_a = NULL;
1621 name->fetch_aaaa = NULL;
1622 name->fetch_err = FIND_ERR_UNEXPECTED;
1623 name->fetch6_err = FIND_ERR_UNEXPECTED;
1624 ISC_LIST_INIT(name->finds);
1625 ISC_LINK_INIT(name, plink);
1627 LOCK(&adb->namescntlock);
1629 if (!adb->grownames_sent && adb->namescnt > (adb->nnames * 8)) {
1630 isc_event_t *event = &adb->grownames;
1631 inc_adb_irefcnt(adb);
1632 isc_task_send(adb->task, &event);
1633 adb->grownames_sent = ISC_TRUE;
1635 UNLOCK(&adb->namescntlock);
1641 free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
1644 INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
1648 INSIST(!NAME_HAS_V4(n));
1649 INSIST(!NAME_HAS_V6(n));
1650 INSIST(!NAME_FETCH(n));
1651 INSIST(ISC_LIST_EMPTY(n->finds));
1652 INSIST(!ISC_LINK_LINKED(n, plink));
1653 INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
1654 INSIST(n->adb == adb);
1657 dns_name_free(&n->name, adb->mctx);
1659 isc_mempool_put(adb->nmp, n);
1660 LOCK(&adb->namescntlock);
1662 UNLOCK(&adb->namescntlock);
1665 static inline dns_adbnamehook_t *
1666 new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) {
1667 dns_adbnamehook_t *nh;
1669 nh = isc_mempool_get(adb->nhmp);
1673 nh->magic = DNS_ADBNAMEHOOK_MAGIC;
1675 ISC_LINK_INIT(nh, plink);
1681 free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) {
1682 dns_adbnamehook_t *nh;
1684 INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
1688 INSIST(nh->entry == NULL);
1689 INSIST(!ISC_LINK_LINKED(nh, plink));
1692 isc_mempool_put(adb->nhmp, nh);
1695 static inline dns_adblameinfo_t *
1696 new_adblameinfo(dns_adb_t *adb, dns_name_t *qname, dns_rdatatype_t qtype) {
1697 dns_adblameinfo_t *li;
1699 li = isc_mempool_get(adb->limp);
1703 dns_name_init(&li->qname, NULL);
1704 if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) {
1705 isc_mempool_put(adb->limp, li);
1708 li->magic = DNS_ADBLAMEINFO_MAGIC;
1711 ISC_LINK_INIT(li, plink);
1717 free_adblameinfo(dns_adb_t *adb, dns_adblameinfo_t **lameinfo) {
1718 dns_adblameinfo_t *li;
1720 INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo));
1724 INSIST(!ISC_LINK_LINKED(li, plink));
1726 dns_name_free(&li->qname, adb->mctx);
1730 isc_mempool_put(adb->limp, li);
1733 static inline dns_adbentry_t *
1734 new_adbentry(dns_adb_t *adb) {
1738 e = isc_mempool_get(adb->emp);
1742 e->magic = DNS_ADBENTRY_MAGIC;
1743 e->lock_bucket = DNS_ADB_INVALIDBUCKET;
1747 e->srtt = (r & 0x1f) + 1;
1749 ISC_LIST_INIT(e->lameinfo);
1750 ISC_LINK_INIT(e, plink);
1751 LOCK(&adb->entriescntlock);
1753 if (!adb->growentries_sent &&
1754 adb->entriescnt > (adb->nentries * 8)) {
1755 isc_event_t *event = &adb->growentries;
1756 inc_adb_irefcnt(adb);
1757 isc_task_send(adb->task, &event);
1758 adb->growentries_sent = ISC_TRUE;
1760 UNLOCK(&adb->entriescntlock);
1766 free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
1768 dns_adblameinfo_t *li;
1770 INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
1774 INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
1775 INSIST(e->refcnt == 0);
1776 INSIST(!ISC_LINK_LINKED(e, plink));
1780 li = ISC_LIST_HEAD(e->lameinfo);
1781 while (li != NULL) {
1782 ISC_LIST_UNLINK(e->lameinfo, li, plink);
1783 free_adblameinfo(adb, &li);
1784 li = ISC_LIST_HEAD(e->lameinfo);
1787 isc_mempool_put(adb->emp, e);
1788 LOCK(&adb->entriescntlock);
1790 UNLOCK(&adb->entriescntlock);
1793 static inline dns_adbfind_t *
1794 new_adbfind(dns_adb_t *adb) {
1796 isc_result_t result;
1798 h = isc_mempool_get(adb->ahmp);
1807 h->partial_result = 0;
1810 h->result_v4 = ISC_R_UNEXPECTED;
1811 h->result_v6 = ISC_R_UNEXPECTED;
1812 ISC_LINK_INIT(h, publink);
1813 ISC_LINK_INIT(h, plink);
1814 ISC_LIST_INIT(h->list);
1816 h->name_bucket = DNS_ADB_INVALIDBUCKET;
1821 result = isc_mutex_init(&h->lock);
1822 if (result != ISC_R_SUCCESS) {
1823 isc_mempool_put(adb->ahmp, h);
1827 ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
1830 inc_adb_irefcnt(adb);
1831 h->magic = DNS_ADBFIND_MAGIC;
1835 static inline dns_adbfetch_t *
1836 new_adbfetch(dns_adb_t *adb) {
1839 f = isc_mempool_get(adb->afmp);
1846 dns_rdataset_init(&f->rdataset);
1848 f->magic = DNS_ADBFETCH_MAGIC;
1854 free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) {
1857 INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
1863 if (dns_rdataset_isassociated(&f->rdataset))
1864 dns_rdataset_disassociate(&f->rdataset);
1866 isc_mempool_put(adb->afmp, f);
1869 static inline isc_boolean_t
1870 free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
1871 dns_adbfind_t *find;
1873 INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
1877 INSIST(!FIND_HAS_ADDRS(find));
1878 INSIST(!ISC_LINK_LINKED(find, publink));
1879 INSIST(!ISC_LINK_LINKED(find, plink));
1880 INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
1881 INSIST(find->adbname == NULL);
1885 DESTROYLOCK(&find->lock);
1886 isc_mempool_put(adb->ahmp, find);
1887 return (dec_adb_irefcnt(adb));
1891 * Copy bits from the entry into the newly allocated addrinfo. The entry
1892 * must be locked, and the reference count must be bumped up by one
1893 * if this function returns a valid pointer.
1895 static inline dns_adbaddrinfo_t *
1896 new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
1897 dns_adbaddrinfo_t *ai;
1899 ai = isc_mempool_get(adb->aimp);
1903 ai->magic = DNS_ADBADDRINFO_MAGIC;
1904 ai->sockaddr = entry->sockaddr;
1905 isc_sockaddr_setport(&ai->sockaddr, port);
1906 ai->srtt = entry->srtt;
1907 ai->flags = entry->flags;
1909 ISC_LINK_INIT(ai, publink);
1915 free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
1916 dns_adbaddrinfo_t *ai;
1918 INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
1922 INSIST(ai->entry == NULL);
1923 INSIST(!ISC_LINK_LINKED(ai, publink));
1927 isc_mempool_put(adb->aimp, ai);
1931 * Search for the name. NOTE: The bucket is kept locked on both
1932 * success and failure, so it must always be unlocked by the caller!
1934 * On the first call to this function, *bucketp must be set to
1935 * DNS_ADB_INVALIDBUCKET.
1937 static inline dns_adbname_t *
1938 find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
1939 unsigned int options, int *bucketp)
1941 dns_adbname_t *adbname;
1944 bucket = dns_name_fullhash(name, ISC_FALSE) % adb->nnames;
1946 if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1947 LOCK(&adb->namelocks[bucket]);
1949 } else if (*bucketp != bucket) {
1950 UNLOCK(&adb->namelocks[*bucketp]);
1951 LOCK(&adb->namelocks[bucket]);
1955 adbname = ISC_LIST_HEAD(adb->names[bucket]);
1956 while (adbname != NULL) {
1957 if (!NAME_DEAD(adbname)) {
1958 if (dns_name_equal(name, &adbname->name)
1959 && GLUEHINT_OK(adbname, options)
1960 && STARTATZONE_MATCHES(adbname, options))
1963 adbname = ISC_LIST_NEXT(adbname, plink);
1970 * Search for the address. NOTE: The bucket is kept locked on both
1971 * success and failure, so it must always be unlocked by the caller.
1973 * On the first call to this function, *bucketp must be set to
1974 * DNS_ADB_INVALIDBUCKET. This will cause a lock to occur. On
1975 * later calls (within the same "lock path") it can be left alone, so
1976 * if this function is called multiple times locking is only done if
1977 * the bucket changes.
1979 static inline dns_adbentry_t *
1980 find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp,
1983 dns_adbentry_t *entry, *entry_next;
1986 bucket = isc_sockaddr_hash(addr, ISC_TRUE) % adb->nentries;
1988 if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1989 LOCK(&adb->entrylocks[bucket]);
1991 } else if (*bucketp != bucket) {
1992 UNLOCK(&adb->entrylocks[*bucketp]);
1993 LOCK(&adb->entrylocks[bucket]);
1997 /* Search the list, while cleaning up expired entries. */
1998 for (entry = ISC_LIST_HEAD(adb->entries[bucket]);
2000 entry = entry_next) {
2001 entry_next = ISC_LIST_NEXT(entry, plink);
2002 (void)check_expire_entry(adb, &entry, now);
2003 if (entry != NULL &&
2004 isc_sockaddr_equal(addr, &entry->sockaddr)) {
2005 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
2006 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
2015 * Entry bucket MUST be locked!
2017 static isc_boolean_t
2018 entry_is_lame(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *qname,
2019 dns_rdatatype_t qtype, isc_stdtime_t now)
2021 dns_adblameinfo_t *li, *next_li;
2022 isc_boolean_t is_bad;
2026 li = ISC_LIST_HEAD(entry->lameinfo);
2029 while (li != NULL) {
2030 next_li = ISC_LIST_NEXT(li, plink);
2033 * Has the entry expired?
2035 if (li->lame_timer < now) {
2036 ISC_LIST_UNLINK(entry->lameinfo, li, plink);
2037 free_adblameinfo(adb, &li);
2041 * Order tests from least to most expensive.
2043 * We do not break out of the main loop here as
2044 * we use the loop for house keeping.
2046 if (li != NULL && !is_bad && li->qtype == qtype &&
2047 dns_name_equal(qname, &li->qname))
2057 copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname,
2058 dns_rdatatype_t qtype, dns_adbname_t *name,
2061 dns_adbnamehook_t *namehook;
2062 dns_adbaddrinfo_t *addrinfo;
2063 dns_adbentry_t *entry;
2066 bucket = DNS_ADB_INVALIDBUCKET;
2068 if (find->options & DNS_ADBFIND_INET) {
2069 namehook = ISC_LIST_HEAD(name->v4);
2070 while (namehook != NULL) {
2071 entry = namehook->entry;
2072 bucket = entry->lock_bucket;
2073 LOCK(&adb->entrylocks[bucket]);
2075 if (!FIND_RETURNLAME(find)
2076 && entry_is_lame(adb, entry, qname, qtype, now)) {
2077 find->options |= DNS_ADBFIND_LAMEPRUNED;
2080 addrinfo = new_adbaddrinfo(adb, entry, find->port);
2081 if (addrinfo == NULL) {
2082 find->partial_result |= DNS_ADBFIND_INET;
2086 * Found a valid entry. Add it to the find's list.
2088 inc_entry_refcnt(adb, entry, ISC_FALSE);
2089 ISC_LIST_APPEND(find->list, addrinfo, publink);
2092 UNLOCK(&adb->entrylocks[bucket]);
2093 bucket = DNS_ADB_INVALIDBUCKET;
2094 namehook = ISC_LIST_NEXT(namehook, plink);
2098 if (find->options & DNS_ADBFIND_INET6) {
2099 namehook = ISC_LIST_HEAD(name->v6);
2100 while (namehook != NULL) {
2101 entry = namehook->entry;
2102 bucket = entry->lock_bucket;
2103 LOCK(&adb->entrylocks[bucket]);
2105 if (!FIND_RETURNLAME(find)
2106 && entry_is_lame(adb, entry, qname, qtype, now)) {
2107 find->options |= DNS_ADBFIND_LAMEPRUNED;
2110 addrinfo = new_adbaddrinfo(adb, entry, find->port);
2111 if (addrinfo == NULL) {
2112 find->partial_result |= DNS_ADBFIND_INET6;
2116 * Found a valid entry. Add it to the find's list.
2118 inc_entry_refcnt(adb, entry, ISC_FALSE);
2119 ISC_LIST_APPEND(find->list, addrinfo, publink);
2122 UNLOCK(&adb->entrylocks[bucket]);
2123 bucket = DNS_ADB_INVALIDBUCKET;
2124 namehook = ISC_LIST_NEXT(namehook, plink);
2129 if (bucket != DNS_ADB_INVALIDBUCKET)
2130 UNLOCK(&adb->entrylocks[bucket]);
2134 shutdown_task(isc_task_t *task, isc_event_t *ev) {
2140 INSIST(DNS_ADB_VALID(adb));
2142 isc_event_free(&ev);
2144 * Wait for lock around check_exit() call to be released.
2152 * Name bucket must be locked; adb may be locked; no other locks held.
2154 static isc_boolean_t
2155 check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
2156 dns_adbname_t *name;
2157 isc_boolean_t result = ISC_FALSE;
2159 INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
2162 if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
2164 if (NAME_FETCH(name))
2166 if (!EXPIRE_OK(name->expire_v4, now))
2168 if (!EXPIRE_OK(name->expire_v6, now))
2170 if (!EXPIRE_OK(name->expire_target, now))
2174 * The name is empty. Delete it.
2176 result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
2180 * Our caller, or one of its callers, will be calling check_exit() at
2181 * some point, so we don't need to do it here.
2187 * Examine the tail entry of the LRU list to see if it expires or is stale
2188 * (unused for some period); if so, the name entry will be freed. If the ADB
2189 * is in the overmem condition, the tail and the next to tail entries
2190 * will be unconditionally removed (unless they have an outstanding fetch).
2191 * We don't care about a race on 'overmem' at the risk of causing some
2192 * collateral damage or a small delay in starting cleanup, so we don't bother
2193 * to lock ADB (if it's not locked).
2195 * Name bucket must be locked; adb may be locked; no other locks held.
2198 check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2199 int victims, max_victims;
2200 dns_adbname_t *victim, *next_victim;
2201 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
2204 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2206 max_victims = overmem ? 2 : 1;
2209 * We limit the number of scanned entries to 10 (arbitrary choice)
2210 * in order to avoid examining too many entries when there are many
2211 * tail entries that have fetches (this should be rare, but could
2214 victim = ISC_LIST_TAIL(adb->names[bucket]);
2216 victim != NULL && victims < max_victims && scans < 10;
2217 victim = next_victim) {
2218 INSIST(!NAME_DEAD(victim));
2220 next_victim = ISC_LIST_PREV(victim, plink);
2221 (void)check_expire_name(&victim, now);
2222 if (victim == NULL) {
2227 if (!NAME_FETCH(victim) &&
2228 (overmem || victim->last_used + ADB_STALE_MARGIN <= now)) {
2229 RUNTIME_CHECK(kill_name(&victim,
2230 DNS_EVENT_ADBCANCELED) ==
2242 * Entry bucket must be locked; adb may be locked; no other locks held.
2244 static isc_boolean_t
2245 check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
2247 dns_adbentry_t *entry;
2248 isc_boolean_t result = ISC_FALSE;
2250 INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
2253 if (entry->refcnt != 0)
2256 if (entry->expires == 0 || entry->expires > now)
2260 * The entry is not in use. Delete it.
2262 DP(DEF_LEVEL, "killing entry %p", entry);
2263 INSIST(ISC_LINK_LINKED(entry, plink));
2264 result = unlink_entry(adb, entry);
2265 free_adbentry(adb, &entry);
2267 dec_adb_irefcnt(adb);
2273 * ADB must be locked, and no other locks held.
2275 static isc_boolean_t
2276 cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2277 dns_adbname_t *name;
2278 dns_adbname_t *next_name;
2279 isc_boolean_t result = ISC_FALSE;
2281 DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
2283 LOCK(&adb->namelocks[bucket]);
2284 if (adb->name_sd[bucket]) {
2285 UNLOCK(&adb->namelocks[bucket]);
2289 name = ISC_LIST_HEAD(adb->names[bucket]);
2290 while (name != NULL) {
2291 next_name = ISC_LIST_NEXT(name, plink);
2292 INSIST(result == ISC_FALSE);
2293 result = check_expire_namehooks(name, now);
2295 result = check_expire_name(&name, now);
2298 UNLOCK(&adb->namelocks[bucket]);
2303 * ADB must be locked, and no other locks held.
2305 static isc_boolean_t
2306 cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2307 dns_adbentry_t *entry, *next_entry;
2308 isc_boolean_t result = ISC_FALSE;
2310 DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
2312 LOCK(&adb->entrylocks[bucket]);
2313 entry = ISC_LIST_HEAD(adb->entries[bucket]);
2314 while (entry != NULL) {
2315 next_entry = ISC_LIST_NEXT(entry, plink);
2316 INSIST(result == ISC_FALSE);
2317 result = check_expire_entry(adb, &entry, now);
2320 UNLOCK(&adb->entrylocks[bucket]);
2325 destroy(dns_adb_t *adb) {
2328 isc_task_detach(&adb->task);
2330 isc_mempool_destroy(&adb->nmp);
2331 isc_mempool_destroy(&adb->nhmp);
2332 isc_mempool_destroy(&adb->limp);
2333 isc_mempool_destroy(&adb->emp);
2334 isc_mempool_destroy(&adb->ahmp);
2335 isc_mempool_destroy(&adb->aimp);
2336 isc_mempool_destroy(&adb->afmp);
2338 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
2339 isc_mem_put(adb->mctx, adb->entries,
2340 sizeof(*adb->entries) * adb->nentries);
2341 isc_mem_put(adb->mctx, adb->deadentries,
2342 sizeof(*adb->deadentries) * adb->nentries);
2343 isc_mem_put(adb->mctx, adb->entrylocks,
2344 sizeof(*adb->entrylocks) * adb->nentries);
2345 isc_mem_put(adb->mctx, adb->entry_sd,
2346 sizeof(*adb->entry_sd) * adb->nentries);
2347 isc_mem_put(adb->mctx, adb->entry_refcnt,
2348 sizeof(*adb->entry_refcnt) * adb->nentries);
2350 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
2351 isc_mem_put(adb->mctx, adb->names,
2352 sizeof(*adb->names) * adb->nnames);
2353 isc_mem_put(adb->mctx, adb->deadnames,
2354 sizeof(*adb->deadnames) * adb->nnames);
2355 isc_mem_put(adb->mctx, adb->namelocks,
2356 sizeof(*adb->namelocks) * adb->nnames);
2357 isc_mem_put(adb->mctx, adb->name_sd,
2358 sizeof(*adb->name_sd) * adb->nnames);
2359 isc_mem_put(adb->mctx, adb->name_refcnt,
2360 sizeof(*adb->name_refcnt) * adb->nnames);
2362 DESTROYLOCK(&adb->reflock);
2363 DESTROYLOCK(&adb->lock);
2364 DESTROYLOCK(&adb->mplock);
2365 DESTROYLOCK(&adb->overmemlock);
2366 DESTROYLOCK(&adb->entriescntlock);
2367 DESTROYLOCK(&adb->namescntlock);
2369 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2378 dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
2379 isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
2382 isc_result_t result;
2385 REQUIRE(mem != NULL);
2386 REQUIRE(view != NULL);
2387 REQUIRE(timermgr != NULL); /* this is actually unused */
2388 REQUIRE(taskmgr != NULL);
2389 REQUIRE(newadb != NULL && *newadb == NULL);
2393 adb = isc_mem_get(mem, sizeof(dns_adb_t));
2395 return (ISC_R_NOMEMORY);
2398 * Initialize things here that cannot fail, and especially things
2399 * that must be NULL for the error return to work properly.
2414 adb->taskmgr = taskmgr;
2415 adb->next_cleanbucket = 0;
2416 ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
2417 DNS_EVENT_ADBCONTROL, shutdown_task, adb,
2419 adb->cevent_sent = ISC_FALSE;
2420 adb->shutting_down = ISC_FALSE;
2421 ISC_LIST_INIT(adb->whenshutdown);
2423 adb->nentries = nbuckets[0];
2424 adb->entriescnt = 0;
2425 adb->entries = NULL;
2426 adb->deadentries = NULL;
2427 adb->entry_sd = NULL;
2428 adb->entry_refcnt = NULL;
2429 adb->entrylocks = NULL;
2430 ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL,
2431 DNS_EVENT_ADBGROWENTRIES, grow_entries, adb,
2433 adb->growentries_sent = ISC_FALSE;
2435 adb->nnames = nbuckets[0];
2438 adb->deadnames = NULL;
2439 adb->name_sd = NULL;
2440 adb->name_refcnt = NULL;
2441 adb->namelocks = NULL;
2442 ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL,
2443 DNS_EVENT_ADBGROWNAMES, grow_names, adb,
2445 adb->grownames_sent = ISC_FALSE;
2447 isc_mem_attach(mem, &adb->mctx);
2449 result = isc_mutex_init(&adb->lock);
2450 if (result != ISC_R_SUCCESS)
2453 result = isc_mutex_init(&adb->mplock);
2454 if (result != ISC_R_SUCCESS)
2457 result = isc_mutex_init(&adb->reflock);
2458 if (result != ISC_R_SUCCESS)
2461 result = isc_mutex_init(&adb->overmemlock);
2462 if (result != ISC_R_SUCCESS)
2465 result = isc_mutex_init(&adb->entriescntlock);
2466 if (result != ISC_R_SUCCESS)
2469 result = isc_mutex_init(&adb->namescntlock);
2470 if (result != ISC_R_SUCCESS)
2473 #define ALLOCENTRY(adb, el) \
2475 (adb)->el = isc_mem_get((adb)->mctx, \
2476 sizeof(*(adb)->el) * (adb)->nentries); \
2477 if ((adb)->el == NULL) { \
2478 result = ISC_R_NOMEMORY; \
2482 ALLOCENTRY(adb, entries);
2483 ALLOCENTRY(adb, deadentries);
2484 ALLOCENTRY(adb, entrylocks);
2485 ALLOCENTRY(adb, entry_sd);
2486 ALLOCENTRY(adb, entry_refcnt);
2489 #define ALLOCNAME(adb, el) \
2491 (adb)->el = isc_mem_get((adb)->mctx, \
2492 sizeof(*(adb)->el) * (adb)->nnames); \
2493 if ((adb)->el == NULL) { \
2494 result = ISC_R_NOMEMORY; \
2498 ALLOCNAME(adb, names);
2499 ALLOCNAME(adb, deadnames);
2500 ALLOCNAME(adb, namelocks);
2501 ALLOCNAME(adb, name_sd);
2502 ALLOCNAME(adb, name_refcnt);
2506 * Initialize the bucket locks for names and elements.
2507 * May as well initialize the list heads, too.
2509 result = isc_mutexblock_init(adb->namelocks, adb->nnames);
2510 if (result != ISC_R_SUCCESS)
2512 for (i = 0; i < adb->nnames; i++) {
2513 ISC_LIST_INIT(adb->names[i]);
2514 ISC_LIST_INIT(adb->deadnames[i]);
2515 adb->name_sd[i] = ISC_FALSE;
2516 adb->name_refcnt[i] = 0;
2519 for (i = 0; i < adb->nentries; i++) {
2520 ISC_LIST_INIT(adb->entries[i]);
2521 ISC_LIST_INIT(adb->deadentries[i]);
2522 adb->entry_sd[i] = ISC_FALSE;
2523 adb->entry_refcnt[i] = 0;
2526 result = isc_mutexblock_init(adb->entrylocks, adb->nentries);
2527 if (result != ISC_R_SUCCESS)
2533 #define MPINIT(t, p, n) do { \
2534 result = isc_mempool_create(mem, sizeof(t), &(p)); \
2535 if (result != ISC_R_SUCCESS) \
2537 isc_mempool_setfreemax((p), FREE_ITEMS); \
2538 isc_mempool_setfillcount((p), FILL_COUNT); \
2539 isc_mempool_setname((p), n); \
2540 isc_mempool_associatelock((p), &adb->mplock); \
2543 MPINIT(dns_adbname_t, adb->nmp, "adbname");
2544 MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
2545 MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo");
2546 MPINIT(dns_adbentry_t, adb->emp, "adbentry");
2547 MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
2548 MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
2549 MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
2554 * Allocate an internal task.
2556 result = isc_task_create(adb->taskmgr, 0, &adb->task);
2557 if (result != ISC_R_SUCCESS)
2559 isc_task_setname(adb->task, "ADB", adb);
2564 adb->magic = DNS_ADB_MAGIC;
2566 return (ISC_R_SUCCESS);
2569 if (adb->task != NULL)
2570 isc_task_detach(&adb->task);
2572 /* clean up entrylocks */
2573 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
2575 fail2: /* clean up namelocks */
2576 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
2578 fail1: /* clean up only allocated memory */
2579 if (adb->entries != NULL)
2580 isc_mem_put(adb->mctx, adb->entries,
2581 sizeof(*adb->entries) * adb->nentries);
2582 if (adb->deadentries != NULL)
2583 isc_mem_put(adb->mctx, adb->deadentries,
2584 sizeof(*adb->deadentries) * adb->nentries);
2585 if (adb->entrylocks != NULL)
2586 isc_mem_put(adb->mctx, adb->entrylocks,
2587 sizeof(*adb->entrylocks) * adb->nentries);
2588 if (adb->entry_sd != NULL)
2589 isc_mem_put(adb->mctx, adb->entry_sd,
2590 sizeof(*adb->entry_sd) * adb->nentries);
2591 if (adb->entry_refcnt != NULL)
2592 isc_mem_put(adb->mctx, adb->entry_refcnt,
2593 sizeof(*adb->entry_refcnt) * adb->nentries);
2594 if (adb->names != NULL)
2595 isc_mem_put(adb->mctx, adb->names,
2596 sizeof(*adb->names) * adb->nnames);
2597 if (adb->deadnames != NULL)
2598 isc_mem_put(adb->mctx, adb->deadnames,
2599 sizeof(*adb->deadnames) * adb->nnames);
2600 if (adb->namelocks != NULL)
2601 isc_mem_put(adb->mctx, adb->namelocks,
2602 sizeof(*adb->namelocks) * adb->nnames);
2603 if (adb->name_sd != NULL)
2604 isc_mem_put(adb->mctx, adb->name_sd,
2605 sizeof(*adb->name_sd) * adb->nnames);
2606 if (adb->name_refcnt != NULL)
2607 isc_mem_put(adb->mctx, adb->name_refcnt,
2608 sizeof(*adb->name_refcnt) * adb->nnames);
2609 if (adb->nmp != NULL)
2610 isc_mempool_destroy(&adb->nmp);
2611 if (adb->nhmp != NULL)
2612 isc_mempool_destroy(&adb->nhmp);
2613 if (adb->limp != NULL)
2614 isc_mempool_destroy(&adb->limp);
2615 if (adb->emp != NULL)
2616 isc_mempool_destroy(&adb->emp);
2617 if (adb->ahmp != NULL)
2618 isc_mempool_destroy(&adb->ahmp);
2619 if (adb->aimp != NULL)
2620 isc_mempool_destroy(&adb->aimp);
2621 if (adb->afmp != NULL)
2622 isc_mempool_destroy(&adb->afmp);
2624 DESTROYLOCK(&adb->namescntlock);
2626 DESTROYLOCK(&adb->entriescntlock);
2628 DESTROYLOCK(&adb->overmemlock);
2630 DESTROYLOCK(&adb->reflock);
2632 DESTROYLOCK(&adb->mplock);
2634 DESTROYLOCK(&adb->lock);
2636 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2642 dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
2644 REQUIRE(DNS_ADB_VALID(adb));
2645 REQUIRE(adbx != NULL && *adbx == NULL);
2647 inc_adb_erefcnt(adb);
2652 dns_adb_detach(dns_adb_t **adbx) {
2654 isc_boolean_t need_exit_check;
2656 REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
2661 INSIST(adb->erefcnt > 0);
2663 LOCK(&adb->reflock);
2665 need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
2666 UNLOCK(&adb->reflock);
2668 if (need_exit_check) {
2670 INSIST(adb->shutting_down);
2677 dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
2680 isc_boolean_t zeroirefcnt = ISC_FALSE;
2683 * Send '*eventp' to 'task' when 'adb' has shutdown.
2686 REQUIRE(DNS_ADB_VALID(adb));
2687 REQUIRE(eventp != NULL);
2694 LOCK(&adb->reflock);
2695 zeroirefcnt = ISC_TF(adb->irefcnt == 0);
2697 if (adb->shutting_down && zeroirefcnt &&
2698 isc_mempool_getallocated(adb->ahmp) == 0) {
2700 * We're already shutdown. Send the event.
2702 event->ev_sender = adb;
2703 isc_task_send(task, &event);
2706 isc_task_attach(task, &clone);
2707 event->ev_sender = clone;
2708 ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
2711 UNLOCK(&adb->reflock);
2716 dns_adb_shutdown(dns_adb_t *adb) {
2717 isc_boolean_t need_check_exit;
2725 if (!adb->shutting_down) {
2726 adb->shutting_down = ISC_TRUE;
2727 isc_mem_setwater(adb->mctx, water, adb, 0, 0);
2728 need_check_exit = shutdown_names(adb);
2729 if (!need_check_exit)
2730 need_check_exit = shutdown_entries(adb);
2731 if (need_check_exit)
2739 dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
2740 void *arg, dns_name_t *name, dns_name_t *qname,
2741 dns_rdatatype_t qtype, unsigned int options,
2742 isc_stdtime_t now, dns_name_t *target,
2743 in_port_t port, dns_adbfind_t **findp)
2745 dns_adbfind_t *find;
2746 dns_adbname_t *adbname;
2748 isc_boolean_t want_event, start_at_zone, alias, have_address;
2749 isc_result_t result;
2750 unsigned int wanted_addresses;
2751 unsigned int wanted_fetches;
2752 unsigned int query_pending;
2754 REQUIRE(DNS_ADB_VALID(adb));
2756 REQUIRE(action != NULL);
2758 REQUIRE(name != NULL);
2759 REQUIRE(qname != NULL);
2760 REQUIRE(findp != NULL && *findp == NULL);
2761 REQUIRE(target == NULL || dns_name_hasbuffer(target));
2763 REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
2765 result = ISC_R_UNEXPECTED;
2767 wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
2770 want_event = ISC_FALSE;
2771 start_at_zone = ISC_FALSE;
2775 isc_stdtime_get(&now);
2778 * XXXMLG Move this comment somewhere else!
2780 * Look up the name in our internal database.
2782 * Possibilities: Note that these are not always exclusive.
2784 * No name found. In this case, allocate a new name header and
2785 * an initial namehook or two. If any of these allocations
2786 * fail, clean up and return ISC_R_NOMEMORY.
2788 * Name found, valid addresses present. Allocate one addrinfo
2789 * structure for each found and append it to the linked list
2790 * of addresses for this header.
2792 * Name found, queries pending. In this case, if a task was
2793 * passed in, allocate a job id, attach it to the name's job
2794 * list and remember to tell the caller that there will be
2795 * more info coming later.
2798 find = new_adbfind(adb);
2800 return (ISC_R_NOMEMORY);
2805 * Remember what types of addresses we are interested in.
2807 find->options = options;
2808 find->flags |= wanted_addresses;
2809 if (FIND_WANTEVENT(find)) {
2810 REQUIRE(task != NULL);
2814 * Try to see if we know anything about this name at all.
2816 bucket = DNS_ADB_INVALIDBUCKET;
2817 adbname = find_name_and_lock(adb, name, find->options, &bucket);
2818 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2819 if (adb->name_sd[bucket]) {
2821 "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
2822 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2823 result = ISC_R_SHUTTINGDOWN;
2828 * Nothing found. Allocate a new adbname structure for this name.
2830 if (adbname == NULL) {
2832 * See if there is any stale name at the end of list, and purge
2835 check_stale_name(adb, bucket, now);
2837 adbname = new_adbname(adb, name);
2838 if (adbname == NULL) {
2839 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2840 result = ISC_R_NOMEMORY;
2843 link_name(adb, bucket, adbname);
2844 if (FIND_HINTOK(find))
2845 adbname->flags |= NAME_HINT_OK;
2846 if (FIND_GLUEOK(find))
2847 adbname->flags |= NAME_GLUE_OK;
2848 if (FIND_STARTATZONE(find))
2849 adbname->flags |= NAME_STARTATZONE;
2851 /* Move this name forward in the LRU list */
2852 ISC_LIST_UNLINK(adb->names[bucket], adbname, plink);
2853 ISC_LIST_PREPEND(adb->names[bucket], adbname, plink);
2855 adbname->last_used = now;
2858 * Expire old entries, etc.
2860 RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE);
2863 * Do we know that the name is an alias?
2865 if (!EXPIRE_OK(adbname->expire_target, now)) {
2870 "dns_adb_createfind: name %p is an alias (cached)",
2877 * Try to populate the name from the database and/or
2878 * start fetches. First try looking for an A record
2881 if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
2882 && WANT_INET(wanted_addresses)) {
2883 result = dbfind_name(adbname, now, dns_rdatatype_a);
2884 if (result == ISC_R_SUCCESS) {
2886 "dns_adb_createfind: found A for name %p in db",
2892 * Did we get a CNAME or DNAME?
2894 if (result == DNS_R_ALIAS) {
2896 "dns_adb_createfind: name %p is an alias",
2903 * If the name doesn't exist at all, don't bother with
2904 * v6 queries; they won't work.
2906 * If the name does exist but we didn't get our data, go
2907 * ahead and try AAAA.
2909 * If the result is neither of these, try a fetch for A.
2911 if (NXDOMAIN_RESULT(result))
2913 else if (NXRRSET_RESULT(result))
2916 if (!NAME_FETCH_V4(adbname))
2917 wanted_fetches |= DNS_ADBFIND_INET;
2921 if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
2922 && WANT_INET6(wanted_addresses)) {
2923 result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
2924 if (result == ISC_R_SUCCESS) {
2926 "dns_adb_createfind: found AAAA for name %p",
2932 * Did we get a CNAME or DNAME?
2934 if (result == DNS_R_ALIAS) {
2936 "dns_adb_createfind: name %p is an alias",
2943 * Listen to negative cache hints, and don't start
2946 if (NCACHE_RESULT(result) || AUTH_NX(result))
2949 if (!NAME_FETCH_V6(adbname))
2950 wanted_fetches |= DNS_ADBFIND_INET6;
2954 if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
2955 (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
2956 have_address = ISC_TRUE;
2958 have_address = ISC_FALSE;
2959 if (wanted_fetches != 0 &&
2960 ! (FIND_AVOIDFETCHES(find) && have_address)) {
2962 * We're missing at least one address family. Either the
2963 * caller hasn't instructed us to avoid fetches, or we don't
2964 * know anything about any of the address families that would
2965 * be acceptable so we have to launch fetches.
2968 if (FIND_STARTATZONE(find))
2969 start_at_zone = ISC_TRUE;
2974 if (WANT_INET(wanted_fetches) &&
2975 fetch_name(adbname, start_at_zone,
2976 dns_rdatatype_a) == ISC_R_SUCCESS) {
2978 "dns_adb_createfind: started A fetch for name %p",
2985 if (WANT_INET6(wanted_fetches) &&
2986 fetch_name(adbname, start_at_zone,
2987 dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
2989 "dns_adb_createfind: "
2990 "started AAAA fetch for name %p",
2996 * Run through the name and copy out the bits we are
2999 copy_namehook_lists(adb, find, qname, qtype, adbname, now);
3002 if (NAME_FETCH_V4(adbname))
3003 query_pending |= DNS_ADBFIND_INET;
3004 if (NAME_FETCH_V6(adbname))
3005 query_pending |= DNS_ADBFIND_INET6;
3008 * Attach to the name's query list if there are queries
3009 * already running, and we have been asked to.
3011 want_event = ISC_TRUE;
3012 if (!FIND_WANTEVENT(find))
3013 want_event = ISC_FALSE;
3014 if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
3015 want_event = ISC_FALSE;
3016 if ((wanted_addresses & query_pending) == 0)
3017 want_event = ISC_FALSE;
3019 want_event = ISC_FALSE;
3021 find->adbname = adbname;
3022 find->name_bucket = bucket;
3023 ISC_LIST_APPEND(adbname->finds, find, plink);
3024 find->query_pending = (query_pending & wanted_addresses);
3025 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
3026 find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
3027 DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
3031 * Remove the flag so the caller knows there will never
3032 * be an event, and set internal flags to fake that
3033 * the event was sent and freed, so dns_adb_destroyfind() will
3034 * do the right thing.
3036 find->query_pending = (query_pending & wanted_addresses);
3037 find->options &= ~DNS_ADBFIND_WANTEVENT;
3038 find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
3039 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
3042 find->partial_result |= (adbname->partial_result & wanted_addresses);
3044 if (target != NULL) {
3045 result = dns_name_copy(&adbname->target, target, NULL);
3046 if (result != ISC_R_SUCCESS)
3049 result = DNS_R_ALIAS;
3051 result = ISC_R_SUCCESS;
3054 * Copy out error flags from the name structure into the find.
3056 find->result_v4 = find_err_map[adbname->fetch_err];
3057 find->result_v6 = find_err_map[adbname->fetch6_err];
3066 INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
3068 isc_task_attach(task, &taskp);
3069 find->event.ev_sender = taskp;
3070 find->event.ev_action = action;
3071 find->event.ev_arg = arg;
3075 UNLOCK(&adb->namelocks[bucket]);
3081 dns_adb_destroyfind(dns_adbfind_t **findp) {
3082 dns_adbfind_t *find;
3083 dns_adbentry_t *entry;
3084 dns_adbaddrinfo_t *ai;
3087 isc_boolean_t overmem;
3089 REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
3095 DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
3098 REQUIRE(DNS_ADB_VALID(adb));
3100 REQUIRE(FIND_EVENTFREED(find));
3102 bucket = find->name_bucket;
3103 INSIST(bucket == DNS_ADB_INVALIDBUCKET);
3105 UNLOCK(&find->lock);
3108 * The find doesn't exist on any list, and nothing is locked.
3109 * Return the find to the memory pool, and decrement the adb's
3112 overmem = isc_mem_isovermem(adb->mctx);
3113 ai = ISC_LIST_HEAD(find->list);
3114 while (ai != NULL) {
3115 ISC_LIST_UNLINK(find->list, ai, publink);
3118 INSIST(DNS_ADBENTRY_VALID(entry));
3119 RUNTIME_CHECK(dec_entry_refcnt(adb, overmem, entry, ISC_TRUE) ==
3121 free_adbaddrinfo(adb, &ai);
3122 ai = ISC_LIST_HEAD(find->list);
3126 * WARNING: The find is freed with the adb locked. This is done
3127 * to avoid a race condition where we free the find, some other
3128 * thread tests to see if it should be destroyed, detects it should
3129 * be, destroys it, and then we try to lock it for our check, but the
3130 * lock is destroyed.
3133 if (free_adbfind(adb, &find))
3139 dns_adb_cancelfind(dns_adbfind_t *find) {
3148 DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
3151 REQUIRE(DNS_ADB_VALID(adb));
3153 REQUIRE(!FIND_EVENTFREED(find));
3154 REQUIRE(FIND_WANTEVENT(find));
3156 bucket = find->name_bucket;
3157 if (bucket == DNS_ADB_INVALIDBUCKET)
3161 * We need to get the adbname's lock to unlink the find.
3163 unlock_bucket = bucket;
3164 violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
3165 bucket = find->name_bucket;
3166 if (bucket != DNS_ADB_INVALIDBUCKET) {
3167 ISC_LIST_UNLINK(find->adbname->finds, find, plink);
3168 find->adbname = NULL;
3169 find->name_bucket = DNS_ADB_INVALIDBUCKET;
3171 UNLOCK(&adb->namelocks[unlock_bucket]);
3172 bucket = DNS_ADB_INVALIDBUCKET;
3177 if (!FIND_EVENTSENT(find)) {
3179 task = ev->ev_sender;
3180 ev->ev_sender = find;
3181 ev->ev_type = DNS_EVENT_ADBCANCELED;
3182 ev->ev_destroy = event_free;
3183 ev->ev_destroy_arg = find;
3184 find->result_v4 = ISC_R_CANCELED;
3185 find->result_v6 = ISC_R_CANCELED;
3187 DP(DEF_LEVEL, "sending event %p to task %p for find %p",
3190 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
3193 UNLOCK(&find->lock);
3197 dns_adb_dump(dns_adb_t *adb, FILE *f) {
3201 REQUIRE(DNS_ADB_VALID(adb));
3205 * Lock the adb itself, lock all the name buckets, then lock all
3206 * the entry buckets. This should put the adb into a state where
3207 * nothing can change, so we can iterate through everything and
3208 * print at our leisure.
3212 isc_stdtime_get(&now);
3214 for (i = 0; i < adb->nnames; i++)
3215 RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE);
3216 for (i = 0; i < adb->nentries; i++)
3217 RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE);
3219 dump_adb(adb, f, ISC_FALSE, now);
3224 dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
3225 if (value == INT_MAX)
3227 fprintf(f, " [%s TTL %d]", legend, value - now);
3231 dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
3233 dns_adbname_t *name;
3234 dns_adbentry_t *entry;
3236 fprintf(f, ";\n; Address database dump\n;\n");
3238 fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
3239 adb, adb->erefcnt, adb->irefcnt,
3240 isc_mempool_getallocated(adb->nhmp));
3242 for (i = 0; i < adb->nnames; i++)
3243 LOCK(&adb->namelocks[i]);
3244 for (i = 0; i < adb->nentries; i++)
3245 LOCK(&adb->entrylocks[i]);
3250 for (i = 0; i < adb->nnames; i++) {
3251 name = ISC_LIST_HEAD(adb->names[i]);
3255 fprintf(f, "; bucket %d\n", i);
3258 name = ISC_LIST_NEXT(name, plink))
3261 fprintf(f, "; name %p (flags %08x)\n",
3265 print_dns_name(f, &name->name);
3266 if (dns_name_countlabels(&name->target) > 0) {
3267 fprintf(f, " alias ");
3268 print_dns_name(f, &name->target);
3271 dump_ttl(f, "v4", name->expire_v4, now);
3272 dump_ttl(f, "v6", name->expire_v6, now);
3273 dump_ttl(f, "target", name->expire_target, now);
3275 fprintf(f, " [v4 %s] [v6 %s]",
3276 errnames[name->fetch_err],
3277 errnames[name->fetch6_err]);
3281 print_namehook_list(f, "v4", &name->v4, debug, now);
3282 print_namehook_list(f, "v6", &name->v6, debug, now);
3285 print_fetch_list(f, name);
3287 print_find_list(f, name);
3292 fprintf(f, ";\n; Unassociated entries\n;\n");
3294 for (i = 0; i < adb->nentries; i++) {
3295 entry = ISC_LIST_HEAD(adb->entries[i]);
3296 while (entry != NULL) {
3297 if (entry->refcnt == 0)
3298 dump_entry(f, entry, debug, now);
3299 entry = ISC_LIST_NEXT(entry, plink);
3306 for (i = 0; i < adb->nentries; i++)
3307 UNLOCK(&adb->entrylocks[i]);
3308 for (i = 0; i < adb->nnames; i++)
3309 UNLOCK(&adb->namelocks[i]);
3313 dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug,
3316 char addrbuf[ISC_NETADDR_FORMATSIZE];
3317 char typebuf[DNS_RDATATYPE_FORMATSIZE];
3318 isc_netaddr_t netaddr;
3319 dns_adblameinfo_t *li;
3321 isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
3322 isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
3325 fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
3327 fprintf(f, ";\t%s [srtt %u] [flags %08x]",
3328 addrbuf, entry->srtt, entry->flags);
3329 if (entry->expires != 0)
3330 fprintf(f, " [ttl %d]", entry->expires - now);
3332 for (li = ISC_LIST_HEAD(entry->lameinfo);
3334 li = ISC_LIST_NEXT(li, plink)) {
3335 fprintf(f, ";\t\t");
3336 print_dns_name(f, &li->qname);
3337 dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf));
3338 fprintf(f, " %s [lame TTL %d]\n", typebuf,
3339 li->lame_timer - now);
3344 dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
3347 dns_adbaddrinfo_t *ai;
3351 * Not used currently, in the API Just In Case we
3352 * want to dump out the name and/or entries too.
3357 fprintf(f, ";Find %p\n", find);
3358 fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
3359 find->query_pending, find->partial_result,
3360 find->options, find->flags);
3361 fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
3362 find->name_bucket, find->adbname, find->event.ev_sender);
3364 ai = ISC_LIST_HEAD(find->list);
3366 fprintf(f, "\tAddresses:\n");
3367 while (ai != NULL) {
3369 switch (sa->type.sa.sa_family) {
3371 tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
3375 tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
3383 tmpp = "BadAddress";
3385 fprintf(f, "\t\tentry %p, flags %08x"
3386 " srtt %u addr %s\n",
3387 ai->entry, ai->flags, ai->srtt, tmpp);
3389 ai = ISC_LIST_NEXT(ai, publink);
3392 UNLOCK(&find->lock);
3396 print_dns_name(FILE *f, dns_name_t *name) {
3397 char buf[DNS_NAME_FORMATSIZE];
3401 dns_name_format(name, buf, sizeof(buf));
3402 fprintf(f, "%s", buf);
3406 print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list,
3407 isc_boolean_t debug, isc_stdtime_t now)
3409 dns_adbnamehook_t *nh;
3411 for (nh = ISC_LIST_HEAD(*list);
3413 nh = ISC_LIST_NEXT(nh, plink))
3416 fprintf(f, ";\tHook(%s) %p\n", legend, nh);
3417 dump_entry(f, nh->entry, debug, now);
3422 print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) {
3423 fprintf(f, "\t\tFetch(%s): %p -> { fetch %p }\n",
3424 type, ft, ft->fetch);
3428 print_fetch_list(FILE *f, dns_adbname_t *n) {
3429 if (NAME_FETCH_A(n))
3430 print_fetch(f, n->fetch_a, "A");
3431 if (NAME_FETCH_AAAA(n))
3432 print_fetch(f, n->fetch_aaaa, "AAAA");
3436 print_find_list(FILE *f, dns_adbname_t *name) {
3437 dns_adbfind_t *find;
3439 find = ISC_LIST_HEAD(name->finds);
3440 while (find != NULL) {
3441 dns_adb_dumpfind(find, f);
3442 find = ISC_LIST_NEXT(find, plink);
3447 dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype)
3449 isc_result_t result;
3450 dns_rdataset_t rdataset;
3452 dns_fixedname_t foundname;
3455 INSIST(DNS_ADBNAME_VALID(adbname));
3457 INSIST(DNS_ADB_VALID(adb));
3458 INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
3460 dns_fixedname_init(&foundname);
3461 fname = dns_fixedname_name(&foundname);
3462 dns_rdataset_init(&rdataset);
3464 if (rdtype == dns_rdatatype_a)
3465 adbname->fetch_err = FIND_ERR_UNEXPECTED;
3467 adbname->fetch6_err = FIND_ERR_UNEXPECTED;
3470 * We need to specify whether to search static-stub zones (if
3471 * configured) depending on whether this is a "start at zone" lookup,
3472 * i.e., whether it's a "bailiwick" glue. If it's bailiwick (in which
3473 * case NAME_STARTATZONE is set) we need to stop the search at any
3474 * matching static-stub zone without looking into the cache to honor
3475 * the configuration on which server we should send queries to.
3477 result = dns_view_find2(adb->view, &adbname->name, rdtype, now,
3478 NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0,
3479 ISC_TF(NAME_HINTOK(adbname)),
3480 (adbname->flags & NAME_STARTATZONE) != 0 ?
3481 ISC_TRUE : ISC_FALSE,
3482 NULL, NULL, fname, &rdataset, NULL);
3484 /* XXXVIX this switch statement is too sparse to gen a jump table. */
3490 * Found in the database. Even if we can't copy out
3491 * any information, return success, or else a fetch
3492 * will be made, which will only make things worse.
3494 if (rdtype == dns_rdatatype_a)
3495 adbname->fetch_err = FIND_ERR_SUCCESS;
3497 adbname->fetch6_err = FIND_ERR_SUCCESS;
3498 result = import_rdataset(adbname, &rdataset, now);
3500 case DNS_R_NXDOMAIN:
3503 * We're authoritative and the data doesn't exist.
3504 * Make up a negative cache entry so we don't ask again
3507 * XXXRTH What time should we use? I'm putting in 30 seconds
3510 if (rdtype == dns_rdatatype_a) {
3511 adbname->expire_v4 = now + 30;
3513 "adb name %p: Caching auth negative entry for A",
3515 if (result == DNS_R_NXDOMAIN)
3516 adbname->fetch_err = FIND_ERR_NXDOMAIN;
3518 adbname->fetch_err = FIND_ERR_NXRRSET;
3521 "adb name %p: Caching auth negative entry for AAAA",
3523 adbname->expire_v6 = now + 30;
3524 if (result == DNS_R_NXDOMAIN)
3525 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3527 adbname->fetch6_err = FIND_ERR_NXRRSET;
3530 case DNS_R_NCACHENXDOMAIN:
3531 case DNS_R_NCACHENXRRSET:
3533 * We found a negative cache entry. Pull the TTL from it
3534 * so we won't ask again for a while.
3536 rdataset.ttl = ttlclamp(rdataset.ttl);
3537 if (rdtype == dns_rdatatype_a) {
3538 adbname->expire_v4 = rdataset.ttl + now;
3539 if (result == DNS_R_NCACHENXDOMAIN)
3540 adbname->fetch_err = FIND_ERR_NXDOMAIN;
3542 adbname->fetch_err = FIND_ERR_NXRRSET;
3544 "adb name %p: Caching negative entry for A (ttl %u)",
3545 adbname, rdataset.ttl);
3548 "adb name %p: Caching negative entry for AAAA (ttl %u)",
3549 adbname, rdataset.ttl);
3550 adbname->expire_v6 = rdataset.ttl + now;
3551 if (result == DNS_R_NCACHENXDOMAIN)
3552 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3554 adbname->fetch6_err = FIND_ERR_NXRRSET;
3560 * Clear the hint and glue flags, so this will match
3563 adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
3565 rdataset.ttl = ttlclamp(rdataset.ttl);
3566 clean_target(adb, &adbname->target);
3567 adbname->expire_target = INT_MAX;
3568 result = set_target(adb, &adbname->name, fname, &rdataset,
3570 if (result == ISC_R_SUCCESS) {
3571 result = DNS_R_ALIAS;
3573 "adb name %p: caching alias target",
3575 adbname->expire_target = rdataset.ttl + now;
3577 if (rdtype == dns_rdatatype_a)
3578 adbname->fetch_err = FIND_ERR_SUCCESS;
3580 adbname->fetch6_err = FIND_ERR_SUCCESS;
3584 if (dns_rdataset_isassociated(&rdataset))
3585 dns_rdataset_disassociate(&rdataset);
3591 fetch_callback(isc_task_t *task, isc_event_t *ev) {
3592 dns_fetchevent_t *dev;
3593 dns_adbname_t *name;
3595 dns_adbfetch_t *fetch;
3597 isc_eventtype_t ev_status;
3599 isc_result_t result;
3600 unsigned int address_type;
3601 isc_boolean_t want_check_exit = ISC_FALSE;
3605 INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
3606 dev = (dns_fetchevent_t *)ev;
3608 INSIST(DNS_ADBNAME_VALID(name));
3610 INSIST(DNS_ADB_VALID(adb));
3612 bucket = name->lock_bucket;
3613 LOCK(&adb->namelocks[bucket]);
3615 INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
3617 if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
3618 address_type = DNS_ADBFIND_INET;
3619 fetch = name->fetch_a;
3620 name->fetch_a = NULL;
3621 } else if (NAME_FETCH_AAAA(name)
3622 && (name->fetch_aaaa->fetch == dev->fetch)) {
3623 address_type = DNS_ADBFIND_INET6;
3624 fetch = name->fetch_aaaa;
3625 name->fetch_aaaa = NULL;
3629 INSIST(address_type != 0 && fetch != NULL);
3631 dns_resolver_destroyfetch(&fetch->fetch);
3634 ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
3637 * Cleanup things we don't care about.
3639 if (dev->node != NULL)
3640 dns_db_detachnode(dev->db, &dev->node);
3641 if (dev->db != NULL)
3642 dns_db_detach(&dev->db);
3645 * If this name is marked as dead, clean up, throwing away
3646 * potentially good data.
3648 if (NAME_DEAD(name)) {
3649 free_adbfetch(adb, &fetch);
3650 isc_event_free(&ev);
3652 want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
3654 UNLOCK(&adb->namelocks[bucket]);
3656 if (want_check_exit) {
3665 isc_stdtime_get(&now);
3668 * If we got a negative cache response, remember it.
3670 if (NCACHE_RESULT(dev->result)) {
3671 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3672 if (address_type == DNS_ADBFIND_INET) {
3673 DP(NCACHE_LEVEL, "adb fetch name %p: "
3674 "caching negative entry for A (ttl %u)",
3675 name, dev->rdataset->ttl);
3676 name->expire_v4 = ISC_MIN(name->expire_v4,
3677 dev->rdataset->ttl + now);
3678 if (dev->result == DNS_R_NCACHENXDOMAIN)
3679 name->fetch_err = FIND_ERR_NXDOMAIN;
3681 name->fetch_err = FIND_ERR_NXRRSET;
3682 inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
3684 DP(NCACHE_LEVEL, "adb fetch name %p: "
3685 "caching negative entry for AAAA (ttl %u)",
3686 name, dev->rdataset->ttl);
3687 name->expire_v6 = ISC_MIN(name->expire_v6,
3688 dev->rdataset->ttl + now);
3689 if (dev->result == DNS_R_NCACHENXDOMAIN)
3690 name->fetch6_err = FIND_ERR_NXDOMAIN;
3692 name->fetch6_err = FIND_ERR_NXRRSET;
3693 inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
3699 * Handle CNAME/DNAME.
3701 if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
3702 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3703 clean_target(adb, &name->target);
3704 name->expire_target = INT_MAX;
3705 result = set_target(adb, &name->name,
3706 dns_fixedname_name(&dev->foundname),
3709 if (result == ISC_R_SUCCESS) {
3711 "adb fetch name %p: caching alias target",
3713 name->expire_target = dev->rdataset->ttl + now;
3719 * Did we get back junk? If so, and there are no more fetches
3720 * sitting out there, tell all the finds about it.
3722 if (dev->result != ISC_R_SUCCESS) {
3723 char buf[DNS_NAME_FORMATSIZE];
3725 dns_name_format(&name->name, buf, sizeof(buf));
3726 DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
3727 buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
3728 dns_result_totext(dev->result));
3729 /* XXXMLG Don't pound on bad servers. */
3730 if (address_type == DNS_ADBFIND_INET) {
3731 name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
3732 name->fetch_err = FIND_ERR_FAILURE;
3733 inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
3735 name->expire_v6 = ISC_MIN(name->expire_v6, now + 300);
3736 name->fetch6_err = FIND_ERR_FAILURE;
3737 inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
3743 * We got something potentially useful.
3745 result = import_rdataset(name, &fetch->rdataset, now);
3748 if (result == ISC_R_SUCCESS) {
3749 ev_status = DNS_EVENT_ADBMOREADDRESSES;
3750 if (address_type == DNS_ADBFIND_INET)
3751 name->fetch_err = FIND_ERR_SUCCESS;
3753 name->fetch6_err = FIND_ERR_SUCCESS;
3757 free_adbfetch(adb, &fetch);
3758 isc_event_free(&ev);
3760 clean_finds_at_name(name, ev_status, address_type);
3762 UNLOCK(&adb->namelocks[bucket]);
3766 fetch_name(dns_adbname_t *adbname,
3767 isc_boolean_t start_at_zone,
3768 dns_rdatatype_t type)
3770 isc_result_t result;
3771 dns_adbfetch_t *fetch = NULL;
3773 dns_fixedname_t fixed;
3775 dns_rdataset_t rdataset;
3776 dns_rdataset_t *nameservers;
3777 unsigned int options;
3779 INSIST(DNS_ADBNAME_VALID(adbname));
3781 INSIST(DNS_ADB_VALID(adb));
3783 INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
3784 (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
3786 adbname->fetch_err = FIND_ERR_NOTFOUND;
3790 dns_rdataset_init(&rdataset);
3792 options = DNS_FETCHOPT_NOVALIDATE;
3793 if (start_at_zone) {
3795 "fetch_name: starting at zone for name %p",
3797 dns_fixedname_init(&fixed);
3798 name = dns_fixedname_name(&fixed);
3799 result = dns_view_findzonecut2(adb->view, &adbname->name, name,
3800 0, 0, ISC_TRUE, ISC_FALSE,
3802 if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
3804 nameservers = &rdataset;
3805 options |= DNS_FETCHOPT_UNSHARED;
3808 fetch = new_adbfetch(adb);
3809 if (fetch == NULL) {
3810 result = ISC_R_NOMEMORY;
3814 result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
3815 type, name, nameservers, NULL,
3816 options, adb->task, fetch_callback,
3817 adbname, &fetch->rdataset, NULL,
3819 if (result != ISC_R_SUCCESS)
3822 if (type == dns_rdatatype_a) {
3823 adbname->fetch_a = fetch;
3824 inc_stats(adb, dns_resstatscounter_gluefetchv4);
3826 adbname->fetch_aaaa = fetch;
3827 inc_stats(adb, dns_resstatscounter_gluefetchv6);
3829 fetch = NULL; /* Keep us from cleaning this up below. */
3833 free_adbfetch(adb, &fetch);
3834 if (dns_rdataset_isassociated(&rdataset))
3835 dns_rdataset_disassociate(&rdataset);
3841 * XXXMLG Needs to take a find argument and an address info, no zone or adb,
3842 * since these can be extracted from the find itself.
3845 dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname,
3846 dns_rdatatype_t qtype, isc_stdtime_t expire_time)
3848 dns_adblameinfo_t *li;
3850 isc_result_t result = ISC_R_SUCCESS;
3852 REQUIRE(DNS_ADB_VALID(adb));
3853 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3854 REQUIRE(qname != NULL);
3856 bucket = addr->entry->lock_bucket;
3857 LOCK(&adb->entrylocks[bucket]);
3858 li = ISC_LIST_HEAD(addr->entry->lameinfo);
3859 while (li != NULL &&
3860 (li->qtype != qtype || !dns_name_equal(qname, &li->qname)))
3861 li = ISC_LIST_NEXT(li, plink);
3863 if (expire_time > li->lame_timer)
3864 li->lame_timer = expire_time;
3867 li = new_adblameinfo(adb, qname, qtype);
3869 result = ISC_R_NOMEMORY;
3873 li->lame_timer = expire_time;
3875 ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink);
3877 UNLOCK(&adb->entrylocks[bucket]);
3883 dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3884 unsigned int rtt, unsigned int factor)
3887 unsigned int new_srtt;
3890 REQUIRE(DNS_ADB_VALID(adb));
3891 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3892 REQUIRE(factor <= 10);
3894 bucket = addr->entry->lock_bucket;
3895 LOCK(&adb->entrylocks[bucket]);
3897 if (factor == DNS_ADB_RTTADJAGE)
3898 new_srtt = addr->entry->srtt * 98 / 100;
3900 new_srtt = (addr->entry->srtt / 10 * factor)
3901 + (rtt / 10 * (10 - factor));
3903 addr->entry->srtt = new_srtt;
3904 addr->srtt = new_srtt;
3906 isc_stdtime_get(&now);
3907 addr->entry->expires = now + ADB_ENTRY_WINDOW;
3909 UNLOCK(&adb->entrylocks[bucket]);
3913 dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3914 unsigned int bits, unsigned int mask)
3918 REQUIRE(DNS_ADB_VALID(adb));
3919 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3921 bucket = addr->entry->lock_bucket;
3922 LOCK(&adb->entrylocks[bucket]);
3924 addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
3926 * Note that we do not update the other bits in addr->flags with
3927 * the most recent values from addr->entry->flags.
3929 addr->flags = (addr->flags & ~mask) | (bits & mask);
3931 UNLOCK(&adb->entrylocks[bucket]);
3935 dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
3936 dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
3939 dns_adbentry_t *entry;
3940 dns_adbaddrinfo_t *addr;
3941 isc_result_t result;
3944 REQUIRE(DNS_ADB_VALID(adb));
3945 REQUIRE(addrp != NULL && *addrp == NULL);
3949 result = ISC_R_SUCCESS;
3950 bucket = DNS_ADB_INVALIDBUCKET;
3951 entry = find_entry_and_lock(adb, sa, &bucket, now);
3952 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
3953 if (adb->entry_sd[bucket]) {
3954 result = ISC_R_SHUTTINGDOWN;
3957 if (entry == NULL) {
3959 * We don't know anything about this address.
3961 entry = new_adbentry(adb);
3962 if (entry == NULL) {
3963 result = ISC_R_NOMEMORY;
3966 entry->sockaddr = *sa;
3967 link_entry(adb, bucket, entry);
3968 DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
3970 DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
3972 port = isc_sockaddr_getport(sa);
3973 addr = new_adbaddrinfo(adb, entry, port);
3975 result = ISC_R_NOMEMORY;
3977 inc_entry_refcnt(adb, entry, ISC_FALSE);
3982 UNLOCK(&adb->entrylocks[bucket]);
3988 dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
3989 dns_adbaddrinfo_t *addr;
3990 dns_adbentry_t *entry;
3993 isc_boolean_t want_check_exit = ISC_FALSE;
3994 isc_boolean_t overmem;
3996 REQUIRE(DNS_ADB_VALID(adb));
3997 REQUIRE(addrp != NULL);
3999 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4000 entry = addr->entry;
4001 REQUIRE(DNS_ADBENTRY_VALID(entry));
4003 isc_stdtime_get(&now);
4006 overmem = isc_mem_isovermem(adb->mctx);
4008 bucket = addr->entry->lock_bucket;
4009 LOCK(&adb->entrylocks[bucket]);
4011 entry->expires = now + ADB_ENTRY_WINDOW;
4013 want_check_exit = dec_entry_refcnt(adb, overmem, entry, ISC_FALSE);
4015 UNLOCK(&adb->entrylocks[bucket]);
4018 free_adbaddrinfo(adb, &addr);
4020 if (want_check_exit) {
4028 dns_adb_flush(dns_adb_t *adb) {
4031 INSIST(DNS_ADB_VALID(adb));
4036 * Call our cleanup routines.
4038 for (i = 0; i < adb->nnames; i++)
4039 RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
4040 for (i = 0; i < adb->nentries; i++)
4041 RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
4043 #ifdef DUMP_ADB_AFTER_CLEANING
4044 dump_adb(adb, stdout, ISC_TRUE, INT_MAX);
4051 dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
4052 dns_adbname_t *adbname;
4053 dns_adbname_t *nextname;
4056 INSIST(DNS_ADB_VALID(adb));
4059 bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames;
4060 LOCK(&adb->namelocks[bucket]);
4061 adbname = ISC_LIST_HEAD(adb->names[bucket]);
4062 while (adbname != NULL) {
4063 nextname = ISC_LIST_NEXT(adbname, plink);
4064 if (!NAME_DEAD(adbname) &&
4065 dns_name_equal(name, &adbname->name)) {
4066 RUNTIME_CHECK(kill_name(&adbname,
4067 DNS_EVENT_ADBCANCELED) ==
4072 UNLOCK(&adb->namelocks[bucket]);
4077 water(void *arg, int mark) {
4079 * We're going to change the way to handle overmem condition: use
4080 * isc_mem_isovermem() instead of storing the state via this callback,
4081 * since the latter way tends to cause race conditions.
4082 * To minimize the change, and in case we re-enable the callback
4083 * approach, however, keep this function at the moment.
4086 dns_adb_t *adb = arg;
4087 isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
4089 REQUIRE(DNS_ADB_VALID(adb));
4091 DP(ISC_LOG_DEBUG(1),
4092 "adb reached %s water mark", overmem ? "high" : "low");
4096 dns_adb_setadbsize(dns_adb_t *adb, isc_uint32_t size) {
4097 isc_uint32_t hiwater;
4098 isc_uint32_t lowater;
4100 INSIST(DNS_ADB_VALID(adb));
4102 if (size != 0 && size < DNS_ADB_MINADBSIZE)
4103 size = DNS_ADB_MINADBSIZE;
4105 hiwater = size - (size >> 3); /* Approximately 7/8ths. */
4106 lowater = size - (size >> 2); /* Approximately 3/4ths. */
4108 if (size == 0 || hiwater == 0 || lowater == 0)
4109 isc_mem_setwater(adb->mctx, water, adb, 0, 0);
4111 isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);