2 * Copyright (C) 2004-2012 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.
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;
261 * Internal functions (and prototypes).
263 static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
264 static inline void free_adbname(dns_adb_t *, dns_adbname_t **);
265 static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
267 static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
268 static inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *, dns_name_t *,
270 static inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **);
271 static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
272 static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
273 static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
274 static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
275 static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
277 static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
278 static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
279 static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
280 unsigned int, int *);
281 static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
282 isc_sockaddr_t *, int *,
284 static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t);
285 static void print_dns_name(FILE *, dns_name_t *);
286 static void print_namehook_list(FILE *, const char *legend,
287 dns_adbnamehooklist_t *list,
290 static void print_find_list(FILE *, dns_adbname_t *);
291 static void print_fetch_list(FILE *, dns_adbname_t *);
292 static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
293 static inline void inc_adb_irefcnt(dns_adb_t *);
294 static inline void inc_adb_erefcnt(dns_adb_t *);
295 static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
297 static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, isc_boolean_t,
298 dns_adbentry_t *, isc_boolean_t);
299 static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
300 static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
301 static void clean_target(dns_adb_t *, dns_name_t *);
302 static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
304 static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
305 static isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **,
307 static void cancel_fetches_at_name(dns_adbname_t *);
308 static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
310 static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
312 static inline void check_exit(dns_adb_t *);
313 static void destroy(dns_adb_t *);
314 static isc_boolean_t shutdown_names(dns_adb_t *);
315 static isc_boolean_t shutdown_entries(dns_adb_t *);
316 static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
317 static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *);
318 static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
319 static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
320 static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
321 static void water(void *, int);
322 static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t);
325 * MUST NOT overlap DNS_ADBFIND_* flags!
327 #define FIND_EVENT_SENT 0x40000000
328 #define FIND_EVENT_FREED 0x80000000
329 #define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0)
330 #define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0)
332 #define NAME_NEEDS_POKE 0x80000000
333 #define NAME_IS_DEAD 0x40000000
334 #define NAME_HINT_OK DNS_ADBFIND_HINTOK
335 #define NAME_GLUE_OK DNS_ADBFIND_GLUEOK
336 #define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE
337 #define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0)
338 #define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0)
339 #define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0)
340 #define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0)
343 * Private flag(s) for entries.
344 * MUST NOT overlap FCTX_ADDRINFO_xxx and DNS_FETCHOPT_NOEDNS0.
346 #define ENTRY_IS_DEAD 0x80000000
349 * To the name, address classes are all that really exist. If it has a
350 * V6 address it doesn't care if it came from a AAAA query.
352 #define NAME_HAS_V4(n) (!ISC_LIST_EMPTY((n)->v4))
353 #define NAME_HAS_V6(n) (!ISC_LIST_EMPTY((n)->v6))
354 #define NAME_HAS_ADDRS(n) (NAME_HAS_V4(n) || NAME_HAS_V6(n))
357 * Fetches are broken out into A and AAAA types. In some cases,
358 * however, it makes more sense to test for a particular class of fetches,
359 * like V4 or V6 above.
360 * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA
361 * are now equal to FETCH_V4 and FETCH_V6, respectively.
363 #define NAME_FETCH_A(n) ((n)->fetch_a != NULL)
364 #define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL)
365 #define NAME_FETCH_V4(n) (NAME_FETCH_A(n))
366 #define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n))
367 #define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
370 * Find options and tests to see if there are addresses on the list.
372 #define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
373 #define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
374 #define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
376 #define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \
378 #define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
379 #define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
380 #define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list))
381 #define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
384 * These are currently used on simple unsigned ints, so they are
385 * not really associated with any particular type.
387 #define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0)
388 #define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0)
390 #define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now))
393 * Find out if the flags on a name (nf) indicate if it is a hint or
394 * glue, and compare this to the appropriate bits set in o, to see if
397 #define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0))
398 #define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0))
399 #define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o))
400 #define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \
401 ((o) & DNS_ADBFIND_STARTATZONE))
403 #define ENTER_LEVEL ISC_LOG_DEBUG(50)
404 #define EXIT_LEVEL ENTER_LEVEL
405 #define CLEAN_LEVEL ISC_LOG_DEBUG(100)
406 #define DEF_LEVEL ISC_LOG_DEBUG(5)
407 #define NCACHE_LEVEL ISC_LOG_DEBUG(20)
409 #define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \
410 (r) == DNS_R_NCACHENXRRSET)
411 #define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \
412 (r) == DNS_R_NXRRSET)
413 #define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \
414 (r) == DNS_R_NCACHENXDOMAIN)
415 #define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \
416 (r) == DNS_R_NXRRSET || \
417 (r) == DNS_R_HINTNXRRSET)
420 * Error state rankings.
423 #define FIND_ERR_SUCCESS 0 /* highest rank */
424 #define FIND_ERR_CANCELED 1
425 #define FIND_ERR_FAILURE 2
426 #define FIND_ERR_NXDOMAIN 3
427 #define FIND_ERR_NXRRSET 4
428 #define FIND_ERR_UNEXPECTED 5
429 #define FIND_ERR_NOTFOUND 6
430 #define FIND_ERR_MAX 7
432 static const char *errnames[] = {
442 #define NEWERR(old, new) (ISC_MIN((old), (new)))
444 static isc_result_t find_err_map[FIND_ERR_MAX] = {
451 ISC_R_NOTFOUND /* not YET found */
455 DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
458 DP(int level, const char *format, ...) {
461 va_start(args, format);
462 isc_log_vwrite(dns_lctx,
463 DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
464 level, format, args);
469 * Increment resolver-related statistics counters.
472 inc_stats(dns_adb_t *adb, isc_statscounter_t counter) {
473 if (adb->view->resstats != NULL)
474 isc_stats_increment(adb->view->resstats, counter);
477 static inline dns_ttl_t
478 ttlclamp(dns_ttl_t ttl) {
479 if (ttl < ADB_CACHE_MINIMUM)
480 ttl = ADB_CACHE_MINIMUM;
481 if (ttl > ADB_CACHE_MAXIMUM)
482 ttl = ADB_CACHE_MAXIMUM;
488 * Hashing is most efficient if the number of buckets is prime.
489 * The sequence below is the closest previous primes to 2^n and
490 * 1.5 * 2^n, for values of n from 10 to 28. (The tables will
491 * no longer grow beyond 2^28 entries.)
493 static const unsigned nbuckets[] = { 1021, 1531, 2039, 3067, 4093, 6143,
494 8191, 12281, 16381, 24571, 32749,
495 49193, 65521, 98299, 131071, 199603,
496 262139, 393209, 524287, 768431, 1048573,
497 1572853, 2097143, 3145721, 4194301,
498 6291449, 8388593, 12582893, 16777213,
499 25165813, 33554393, 50331599, 67108859,
500 100663291, 134217689, 201326557,
504 grow_entries(isc_task_t *task, isc_event_t *ev) {
507 dns_adbentrylist_t *newdeadentries = NULL;
508 dns_adbentrylist_t *newentries = NULL;
509 isc_boolean_t *newentry_sd = NULL;
510 isc_mutex_t *newentrylocks = NULL;
512 unsigned int *newentry_refcnt = NULL;
513 unsigned int i, n, bucket;
516 INSIST(DNS_ADB_VALID(adb));
520 isc_task_beginexclusive(task);
523 while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i])
525 if (nbuckets[i] != 0)
530 DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n);
533 * Are we shutting down?
535 for (i = 0; i < adb->nentries; i++)
536 if (adb->entry_sd[i])
540 * Grab all the resources we need.
542 newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n);
543 newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n);
544 newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n);
545 newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n);
546 newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n);
547 if (newentries == NULL || newdeadentries == NULL ||
548 newentrylocks == NULL || newentry_sd == NULL ||
549 newentry_refcnt == NULL)
553 * Initialise the new resources.
555 result = isc_mutexblock_init(newentrylocks, n);
556 if (result != ISC_R_SUCCESS)
559 for (i = 0; i < n; i++) {
560 ISC_LIST_INIT(newentries[i]);
561 ISC_LIST_INIT(newdeadentries[i]);
562 newentry_sd[i] = ISC_FALSE;
563 newentry_refcnt[i] = 0;
568 * Move entries to new arrays.
570 for (i = 0; i < adb->nentries; i++) {
571 e = ISC_LIST_HEAD(adb->entries[i]);
573 ISC_LIST_UNLINK(adb->entries[i], e, plink);
574 bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
575 e->lock_bucket = bucket;
576 ISC_LIST_APPEND(newentries[bucket], e, plink);
577 INSIST(adb->entry_refcnt[i] > 0);
578 adb->entry_refcnt[i]--;
579 newentry_refcnt[bucket]++;
580 e = ISC_LIST_HEAD(adb->entries[i]);
582 e = ISC_LIST_HEAD(adb->deadentries[i]);
584 ISC_LIST_UNLINK(adb->deadentries[i], e, plink);
585 bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
586 e->lock_bucket = bucket;
587 ISC_LIST_APPEND(newdeadentries[bucket], e, plink);
588 INSIST(adb->entry_refcnt[i] > 0);
589 adb->entry_refcnt[i]--;
590 newentry_refcnt[bucket]++;
591 e = ISC_LIST_HEAD(adb->deadentries[i]);
593 INSIST(adb->entry_refcnt[i] == 0);
598 * Cleanup old resources.
600 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
601 isc_mem_put(adb->mctx, adb->entries,
602 sizeof(*adb->entries) * adb->nentries);
603 isc_mem_put(adb->mctx, adb->deadentries,
604 sizeof(*adb->deadentries) * adb->nentries);
605 isc_mem_put(adb->mctx, adb->entrylocks,
606 sizeof(*adb->entrylocks) * adb->nentries);
607 isc_mem_put(adb->mctx, adb->entry_sd,
608 sizeof(*adb->entry_sd) * adb->nentries);
609 isc_mem_put(adb->mctx, adb->entry_refcnt,
610 sizeof(*adb->entry_refcnt) * adb->nentries);
613 * Install new resources.
615 adb->entries = newentries;
616 adb->deadentries = newdeadentries;
617 adb->entrylocks = newentrylocks;
618 adb->entry_sd = newentry_sd;
619 adb->entry_refcnt = newentry_refcnt;
623 * Only on success do we set adb->growentries_sent to ISC_FALSE.
624 * This will prevent us being continuously being called on error.
626 adb->growentries_sent = ISC_FALSE;
630 if (newentries != NULL)
631 isc_mem_put(adb->mctx, newentries,
632 sizeof(*newentries) * n);
633 if (newdeadentries != NULL)
634 isc_mem_put(adb->mctx, newdeadentries,
635 sizeof(*newdeadentries) * n);
636 if (newentrylocks != NULL)
637 isc_mem_put(adb->mctx, newentrylocks,
638 sizeof(*newentrylocks) * n);
639 if (newentry_sd != NULL)
640 isc_mem_put(adb->mctx, newentry_sd,
641 sizeof(*newentry_sd) * n);
642 if (newentry_refcnt != NULL)
643 isc_mem_put(adb->mctx, newentry_refcnt,
644 sizeof(*newentry_refcnt) * n);
646 isc_task_endexclusive(task);
649 if (dec_adb_irefcnt(adb))
652 DP(ISC_LOG_INFO, "adb: grow_entries finished");
656 grow_names(isc_task_t *task, isc_event_t *ev) {
659 dns_adbnamelist_t *newdeadnames = NULL;
660 dns_adbnamelist_t *newnames = NULL;
661 isc_boolean_t *newname_sd = NULL;
662 isc_mutex_t *newnamelocks = NULL;
664 unsigned int *newname_refcnt = NULL;
665 unsigned int i, n, bucket;
668 INSIST(DNS_ADB_VALID(adb));
672 isc_task_beginexclusive(task);
675 while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i])
677 if (nbuckets[i] != 0)
682 DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n);
685 * Are we shutting down?
687 for (i = 0; i < adb->nnames; i++)
692 * Grab all the resources we need.
694 newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n);
695 newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n);
696 newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n);
697 newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n);
698 newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n);
699 if (newnames == NULL || newdeadnames == NULL ||
700 newnamelocks == NULL || newname_sd == NULL ||
701 newname_refcnt == NULL)
705 * Initialise the new resources.
707 result = isc_mutexblock_init(newnamelocks, n);
708 if (result != ISC_R_SUCCESS)
711 for (i = 0; i < n; i++) {
712 ISC_LIST_INIT(newnames[i]);
713 ISC_LIST_INIT(newdeadnames[i]);
714 newname_sd[i] = ISC_FALSE;
715 newname_refcnt[i] = 0;
720 * Move names to new arrays.
722 for (i = 0; i < adb->nnames; i++) {
723 name = ISC_LIST_HEAD(adb->names[i]);
724 while (name != NULL) {
725 ISC_LIST_UNLINK(adb->names[i], name, plink);
726 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
727 name->lock_bucket = bucket;
728 ISC_LIST_APPEND(newnames[bucket], name, plink);
729 INSIST(adb->name_refcnt[i] > 0);
730 adb->name_refcnt[i]--;
731 newname_refcnt[bucket]++;
732 name = ISC_LIST_HEAD(adb->names[i]);
734 name = ISC_LIST_HEAD(adb->deadnames[i]);
735 while (name != NULL) {
736 ISC_LIST_UNLINK(adb->deadnames[i], name, plink);
737 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
738 name->lock_bucket = bucket;
739 ISC_LIST_APPEND(newdeadnames[bucket], name, plink);
740 INSIST(adb->name_refcnt[i] > 0);
741 adb->name_refcnt[i]--;
742 newname_refcnt[bucket]++;
743 name = ISC_LIST_HEAD(adb->deadnames[i]);
745 INSIST(adb->name_refcnt[i] == 0);
750 * Cleanup old resources.
752 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
753 isc_mem_put(adb->mctx, adb->names,
754 sizeof(*adb->names) * adb->nnames);
755 isc_mem_put(adb->mctx, adb->deadnames,
756 sizeof(*adb->deadnames) * adb->nnames);
757 isc_mem_put(adb->mctx, adb->namelocks,
758 sizeof(*adb->namelocks) * adb->nnames);
759 isc_mem_put(adb->mctx, adb->name_sd,
760 sizeof(*adb->name_sd) * adb->nnames);
761 isc_mem_put(adb->mctx, adb->name_refcnt,
762 sizeof(*adb->name_refcnt) * adb->nnames);
765 * Install new resources.
767 adb->names = newnames;
768 adb->deadnames = newdeadnames;
769 adb->namelocks = newnamelocks;
770 adb->name_sd = newname_sd;
771 adb->name_refcnt = newname_refcnt;
775 * Only on success do we set adb->grownames_sent to ISC_FALSE.
776 * This will prevent us being continuously being called on error.
778 adb->grownames_sent = ISC_FALSE;
782 if (newnames != NULL)
783 isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n);
784 if (newdeadnames != NULL)
785 isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n);
786 if (newnamelocks != NULL)
787 isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n);
788 if (newname_sd != NULL)
789 isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n);
790 if (newname_refcnt != NULL)
791 isc_mem_put(adb->mctx, newname_refcnt,
792 sizeof(*newname_refcnt) * n);
794 isc_task_endexclusive(task);
797 if (dec_adb_irefcnt(adb))
800 DP(ISC_LOG_INFO, "adb: grow_names finished");
804 * Requires the adbname bucket be locked and that no entry buckets be locked.
806 * This code handles A and AAAA rdatasets only.
809 import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
814 dns_adbnamehook_t *nh;
815 dns_adbnamehook_t *anh;
816 dns_rdata_t rdata = DNS_RDATA_INIT;
818 struct in6_addr in6a;
819 isc_sockaddr_t sockaddr;
820 dns_adbentry_t *foundentry; /* NO CLEAN UP! */
822 isc_boolean_t new_addresses_added;
823 dns_rdatatype_t rdtype;
824 unsigned int findoptions;
825 dns_adbnamehooklist_t *hookhead;
827 INSIST(DNS_ADBNAME_VALID(adbname));
829 INSIST(DNS_ADB_VALID(adb));
831 rdtype = rdataset->type;
832 INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
833 if (rdtype == dns_rdatatype_a)
834 findoptions = DNS_ADBFIND_INET;
836 findoptions = DNS_ADBFIND_INET6;
838 addr_bucket = DNS_ADB_INVALIDBUCKET;
839 new_addresses_added = ISC_FALSE;
842 result = dns_rdataset_first(rdataset);
843 while (result == ISC_R_SUCCESS) {
844 dns_rdata_reset(&rdata);
845 dns_rdataset_current(rdataset, &rdata);
846 if (rdtype == dns_rdatatype_a) {
847 INSIST(rdata.length == 4);
848 memcpy(&ina.s_addr, rdata.data, 4);
849 isc_sockaddr_fromin(&sockaddr, &ina, 0);
850 hookhead = &adbname->v4;
852 INSIST(rdata.length == 16);
853 memcpy(in6a.s6_addr, rdata.data, 16);
854 isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
855 hookhead = &adbname->v6;
859 nh = new_adbnamehook(adb, NULL);
861 adbname->partial_result |= findoptions;
862 result = ISC_R_NOMEMORY;
866 foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket,
868 if (foundentry == NULL) {
869 dns_adbentry_t *entry;
871 entry = new_adbentry(adb);
873 adbname->partial_result |= findoptions;
874 result = ISC_R_NOMEMORY;
878 entry->sockaddr = sockaddr;
883 link_entry(adb, addr_bucket, entry);
885 for (anh = ISC_LIST_HEAD(*hookhead);
887 anh = ISC_LIST_NEXT(anh, plink))
888 if (anh->entry == foundentry)
891 foundentry->refcnt++;
892 nh->entry = foundentry;
894 free_adbnamehook(adb, &nh);
897 new_addresses_added = ISC_TRUE;
899 ISC_LIST_APPEND(*hookhead, nh, plink);
901 result = dns_rdataset_next(rdataset);
906 free_adbnamehook(adb, &nh);
908 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
909 UNLOCK(&adb->entrylocks[addr_bucket]);
911 if (rdataset->trust == dns_trust_glue ||
912 rdataset->trust == dns_trust_additional)
913 rdataset->ttl = ADB_CACHE_MINIMUM;
914 else if (rdataset->trust == dns_trust_ultimate)
917 rdataset->ttl = ttlclamp(rdataset->ttl);
919 if (rdtype == dns_rdatatype_a) {
920 DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
921 adbname->expire_v4, now + rdataset->ttl);
922 adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
923 now + rdataset->ttl);
925 DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
926 adbname->expire_v6, now + rdataset->ttl);
927 adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
928 now + rdataset->ttl);
931 if (new_addresses_added) {
933 * Lie a little here. This is more or less so code that cares
934 * can find out if any new information was added or not.
936 return (ISC_R_SUCCESS);
943 * Requires the name's bucket be locked.
946 kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
948 isc_boolean_t result = ISC_FALSE;
949 isc_boolean_t result4, result6;
956 INSIST(DNS_ADBNAME_VALID(name));
958 INSIST(DNS_ADB_VALID(adb));
960 DP(DEF_LEVEL, "killing name %p", name);
963 * If we're dead already, just check to see if we should go
966 if (NAME_DEAD(name) && !NAME_FETCH(name)) {
967 result = unlink_name(adb, name);
968 free_adbname(adb, &name);
970 result = dec_adb_irefcnt(adb);
975 * Clean up the name's various lists. These two are destructive
976 * in that they will always empty the list.
978 clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
979 result4 = clean_namehooks(adb, &name->v4);
980 result6 = clean_namehooks(adb, &name->v6);
981 clean_target(adb, &name->target);
982 result = ISC_TF(result4 || result6);
985 * If fetches are running, cancel them. If none are running, we can
986 * just kill the name here.
988 if (!NAME_FETCH(name)) {
989 INSIST(result == ISC_FALSE);
990 result = unlink_name(adb, name);
991 free_adbname(adb, &name);
993 result = dec_adb_irefcnt(adb);
995 cancel_fetches_at_name(name);
996 if (!NAME_DEAD(name)) {
997 bucket = name->lock_bucket;
998 ISC_LIST_UNLINK(adb->names[bucket], name, plink);
999 ISC_LIST_APPEND(adb->deadnames[bucket], name, plink);
1000 name->flags |= NAME_IS_DEAD;
1007 * Requires the name's bucket be locked and no entry buckets be locked.
1009 static isc_boolean_t
1010 check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
1012 isc_boolean_t result4 = ISC_FALSE;
1013 isc_boolean_t result6 = ISC_FALSE;
1015 INSIST(DNS_ADBNAME_VALID(name));
1017 INSIST(DNS_ADB_VALID(adb));
1020 * Check to see if we need to remove the v4 addresses
1022 if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) {
1023 if (NAME_HAS_V4(name)) {
1024 DP(DEF_LEVEL, "expiring v4 for name %p", name);
1025 result4 = clean_namehooks(adb, &name->v4);
1026 name->partial_result &= ~DNS_ADBFIND_INET;
1028 name->expire_v4 = INT_MAX;
1029 name->fetch_err = FIND_ERR_UNEXPECTED;
1033 * Check to see if we need to remove the v6 addresses
1035 if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) {
1036 if (NAME_HAS_V6(name)) {
1037 DP(DEF_LEVEL, "expiring v6 for name %p", name);
1038 result6 = clean_namehooks(adb, &name->v6);
1039 name->partial_result &= ~DNS_ADBFIND_INET6;
1041 name->expire_v6 = INT_MAX;
1042 name->fetch6_err = FIND_ERR_UNEXPECTED;
1046 * Check to see if we need to remove the alias target.
1048 if (EXPIRE_OK(name->expire_target, now)) {
1049 clean_target(adb, &name->target);
1050 name->expire_target = INT_MAX;
1052 return (ISC_TF(result4 || result6));
1056 * Requires the name's bucket be locked.
1059 link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
1060 INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
1062 ISC_LIST_PREPEND(adb->names[bucket], name, plink);
1063 name->lock_bucket = bucket;
1064 adb->name_refcnt[bucket]++;
1068 * Requires the name's bucket be locked.
1070 static inline isc_boolean_t
1071 unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
1073 isc_boolean_t result = ISC_FALSE;
1075 bucket = name->lock_bucket;
1076 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
1078 if (NAME_DEAD(name))
1079 ISC_LIST_UNLINK(adb->deadnames[bucket], name, plink);
1081 ISC_LIST_UNLINK(adb->names[bucket], name, plink);
1082 name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1083 INSIST(adb->name_refcnt[bucket] > 0);
1084 adb->name_refcnt[bucket]--;
1085 if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
1091 * Requires the entry's bucket be locked.
1094 link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
1098 if (isc_mem_isovermem(adb->mctx)) {
1099 for (i = 0; i < 2; i++) {
1100 e = ISC_LIST_TAIL(adb->entries[bucket]);
1103 if (e->refcnt == 0) {
1104 unlink_entry(adb, e);
1105 free_adbentry(adb, &e);
1108 INSIST((e->flags & ENTRY_IS_DEAD) == 0);
1109 e->flags |= ENTRY_IS_DEAD;
1110 ISC_LIST_UNLINK(adb->entries[bucket], e, plink);
1111 ISC_LIST_PREPEND(adb->deadentries[bucket], e, plink);
1115 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
1116 entry->lock_bucket = bucket;
1117 adb->entry_refcnt[bucket]++;
1121 * Requires the entry's bucket be locked.
1123 static inline isc_boolean_t
1124 unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
1126 isc_boolean_t result = ISC_FALSE;
1128 bucket = entry->lock_bucket;
1129 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
1131 if ((entry->flags & ENTRY_IS_DEAD) != 0)
1132 ISC_LIST_UNLINK(adb->deadentries[bucket], entry, plink);
1134 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
1135 entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1136 INSIST(adb->entry_refcnt[bucket] > 0);
1137 adb->entry_refcnt[bucket]--;
1138 if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
1144 violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
1145 if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
1153 * The ADB _MUST_ be locked before calling. Also, exit conditions must be
1154 * checked after calling this function.
1156 static isc_boolean_t
1157 shutdown_names(dns_adb_t *adb) {
1158 unsigned int bucket;
1159 isc_boolean_t result = ISC_FALSE;
1160 dns_adbname_t *name;
1161 dns_adbname_t *next_name;
1163 for (bucket = 0; bucket < adb->nnames; bucket++) {
1164 LOCK(&adb->namelocks[bucket]);
1165 adb->name_sd[bucket] = ISC_TRUE;
1167 name = ISC_LIST_HEAD(adb->names[bucket]);
1170 * This bucket has no names. We must decrement the
1171 * irefcnt ourselves, since it will not be
1172 * automatically triggered by a name being unlinked.
1174 INSIST(result == ISC_FALSE);
1175 result = dec_adb_irefcnt(adb);
1178 * Run through the list. For each name, clean up finds
1179 * found there, and cancel any fetches running. When
1180 * all the fetches are canceled, the name will destroy
1183 while (name != NULL) {
1184 next_name = ISC_LIST_NEXT(name, plink);
1185 INSIST(result == ISC_FALSE);
1186 result = kill_name(&name,
1187 DNS_EVENT_ADBSHUTDOWN);
1192 UNLOCK(&adb->namelocks[bucket]);
1198 * The ADB _MUST_ be locked before calling. Also, exit conditions must be
1199 * checked after calling this function.
1201 static isc_boolean_t
1202 shutdown_entries(dns_adb_t *adb) {
1203 unsigned int bucket;
1204 isc_boolean_t result = ISC_FALSE;
1205 dns_adbentry_t *entry;
1206 dns_adbentry_t *next_entry;
1208 for (bucket = 0; bucket < adb->nentries; bucket++) {
1209 LOCK(&adb->entrylocks[bucket]);
1210 adb->entry_sd[bucket] = ISC_TRUE;
1212 entry = ISC_LIST_HEAD(adb->entries[bucket]);
1213 if (adb->entry_refcnt[bucket] == 0) {
1215 * This bucket has no entries. We must decrement the
1216 * irefcnt ourselves, since it will not be
1217 * automatically triggered by an entry being unlinked.
1219 result = dec_adb_irefcnt(adb);
1222 * Run through the list. Cleanup any entries not
1223 * associated with names, and which are not in use.
1225 while (entry != NULL) {
1226 next_entry = ISC_LIST_NEXT(entry, plink);
1227 if (entry->refcnt == 0 &&
1228 entry->expires != 0) {
1229 result = unlink_entry(adb, entry);
1230 free_adbentry(adb, &entry);
1232 result = dec_adb_irefcnt(adb);
1238 UNLOCK(&adb->entrylocks[bucket]);
1244 * Name bucket must be locked
1247 cancel_fetches_at_name(dns_adbname_t *name) {
1248 if (NAME_FETCH_A(name))
1249 dns_resolver_cancelfetch(name->fetch_a->fetch);
1251 if (NAME_FETCH_AAAA(name))
1252 dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
1256 * Assumes the name bucket is locked.
1258 static isc_boolean_t
1259 clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
1260 dns_adbentry_t *entry;
1261 dns_adbnamehook_t *namehook;
1263 isc_boolean_t result = ISC_FALSE;
1264 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
1266 addr_bucket = DNS_ADB_INVALIDBUCKET;
1267 namehook = ISC_LIST_HEAD(*namehooks);
1268 while (namehook != NULL) {
1269 INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
1272 * Clean up the entry if needed.
1274 entry = namehook->entry;
1275 if (entry != NULL) {
1276 INSIST(DNS_ADBENTRY_VALID(entry));
1278 if (addr_bucket != entry->lock_bucket) {
1279 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1280 UNLOCK(&adb->entrylocks[addr_bucket]);
1281 addr_bucket = entry->lock_bucket;
1282 LOCK(&adb->entrylocks[addr_bucket]);
1285 result = dec_entry_refcnt(adb, overmem, entry,
1292 namehook->entry = NULL;
1293 ISC_LIST_UNLINK(*namehooks, namehook, plink);
1294 free_adbnamehook(adb, &namehook);
1296 namehook = ISC_LIST_HEAD(*namehooks);
1299 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1300 UNLOCK(&adb->entrylocks[addr_bucket]);
1305 clean_target(dns_adb_t *adb, dns_name_t *target) {
1306 if (dns_name_countlabels(target) > 0) {
1307 dns_name_free(target, adb->mctx);
1308 dns_name_init(target, NULL);
1313 set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
1314 dns_rdataset_t *rdataset, dns_name_t *target)
1316 isc_result_t result;
1317 dns_namereln_t namereln;
1318 unsigned int nlabels;
1320 dns_rdata_t rdata = DNS_RDATA_INIT;
1321 dns_fixedname_t fixed1, fixed2;
1322 dns_name_t *prefix, *new_target;
1324 REQUIRE(dns_name_countlabels(target) == 0);
1326 if (rdataset->type == dns_rdatatype_cname) {
1327 dns_rdata_cname_t cname;
1330 * Copy the CNAME's target into the target name.
1332 result = dns_rdataset_first(rdataset);
1333 if (result != ISC_R_SUCCESS)
1335 dns_rdataset_current(rdataset, &rdata);
1336 result = dns_rdata_tostruct(&rdata, &cname, NULL);
1337 if (result != ISC_R_SUCCESS)
1339 result = dns_name_dup(&cname.cname, adb->mctx, target);
1340 dns_rdata_freestruct(&cname);
1341 if (result != ISC_R_SUCCESS)
1344 dns_rdata_dname_t dname;
1346 INSIST(rdataset->type == dns_rdatatype_dname);
1347 namereln = dns_name_fullcompare(name, fname, &order, &nlabels);
1348 INSIST(namereln == dns_namereln_subdomain);
1350 * Get the target name of the DNAME.
1352 result = dns_rdataset_first(rdataset);
1353 if (result != ISC_R_SUCCESS)
1355 dns_rdataset_current(rdataset, &rdata);
1356 result = dns_rdata_tostruct(&rdata, &dname, NULL);
1357 if (result != ISC_R_SUCCESS)
1360 * Construct the new target name.
1362 dns_fixedname_init(&fixed1);
1363 prefix = dns_fixedname_name(&fixed1);
1364 dns_fixedname_init(&fixed2);
1365 new_target = dns_fixedname_name(&fixed2);
1366 dns_name_split(name, nlabels, prefix, NULL);
1367 result = dns_name_concatenate(prefix, &dname.dname, new_target,
1369 dns_rdata_freestruct(&dname);
1370 if (result != ISC_R_SUCCESS)
1372 result = dns_name_dup(new_target, adb->mctx, target);
1373 if (result != ISC_R_SUCCESS)
1377 return (ISC_R_SUCCESS);
1381 * Assumes nothing is locked, since this is called by the client.
1384 event_free(isc_event_t *event) {
1385 dns_adbfind_t *find;
1387 INSIST(event != NULL);
1388 find = event->ev_destroy_arg;
1389 INSIST(DNS_ADBFIND_VALID(find));
1392 find->flags |= FIND_EVENT_FREED;
1393 event->ev_destroy_arg = NULL;
1394 UNLOCK(&find->lock);
1398 * Assumes the name bucket is locked.
1401 clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
1406 dns_adbfind_t *find;
1407 dns_adbfind_t *next_find;
1408 isc_boolean_t process;
1409 unsigned int wanted, notify;
1412 "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
1413 name, evtype, addrs);
1415 find = ISC_LIST_HEAD(name->finds);
1416 while (find != NULL) {
1418 next_find = ISC_LIST_NEXT(find, plink);
1420 process = ISC_FALSE;
1421 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1422 notify = wanted & addrs;
1425 case DNS_EVENT_ADBMOREADDRESSES:
1426 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES");
1427 if ((notify) != 0) {
1428 find->flags &= ~addrs;
1432 case DNS_EVENT_ADBNOMOREADDRESSES:
1433 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES");
1434 find->flags &= ~addrs;
1435 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1440 find->flags &= ~addrs;
1445 DP(DEF_LEVEL, "cfan: processing find %p", find);
1447 * Unlink the find from the name, letting the caller
1448 * call dns_adb_destroyfind() on it to clean it up
1451 ISC_LIST_UNLINK(name->finds, find, plink);
1452 find->adbname = NULL;
1453 find->name_bucket = DNS_ADB_INVALIDBUCKET;
1455 INSIST(!FIND_EVENTSENT(find));
1458 task = ev->ev_sender;
1459 ev->ev_sender = find;
1460 find->result_v4 = find_err_map[name->fetch_err];
1461 find->result_v6 = find_err_map[name->fetch6_err];
1462 ev->ev_type = evtype;
1463 ev->ev_destroy = event_free;
1464 ev->ev_destroy_arg = find;
1467 "sending event %p to task %p for find %p",
1470 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
1472 DP(DEF_LEVEL, "cfan: skipping find %p", find);
1475 UNLOCK(&find->lock);
1479 DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
1483 check_exit(dns_adb_t *adb) {
1486 * The caller must be holding the adb lock.
1488 if (adb->shutting_down) {
1490 * If there aren't any external references either, we're
1491 * done. Send the control event to initiate shutdown.
1493 INSIST(!adb->cevent_sent); /* Sanity check. */
1494 event = &adb->cevent;
1495 isc_task_send(adb->task, &event);
1496 adb->cevent_sent = ISC_TRUE;
1500 static inline isc_boolean_t
1501 dec_adb_irefcnt(dns_adb_t *adb) {
1504 isc_boolean_t result = ISC_FALSE;
1506 LOCK(&adb->reflock);
1508 INSIST(adb->irefcnt > 0);
1511 if (adb->irefcnt == 0) {
1512 event = ISC_LIST_HEAD(adb->whenshutdown);
1513 while (event != NULL) {
1514 ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
1515 etask = event->ev_sender;
1516 event->ev_sender = adb;
1517 isc_task_sendanddetach(&etask, &event);
1518 event = ISC_LIST_HEAD(adb->whenshutdown);
1522 if (adb->irefcnt == 0 && adb->erefcnt == 0)
1524 UNLOCK(&adb->reflock);
1529 inc_adb_irefcnt(dns_adb_t *adb) {
1530 LOCK(&adb->reflock);
1532 UNLOCK(&adb->reflock);
1536 inc_adb_erefcnt(dns_adb_t *adb) {
1537 LOCK(&adb->reflock);
1539 UNLOCK(&adb->reflock);
1543 inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
1546 bucket = entry->lock_bucket;
1549 LOCK(&adb->entrylocks[bucket]);
1554 UNLOCK(&adb->entrylocks[bucket]);
1557 static inline isc_boolean_t
1558 dec_entry_refcnt(dns_adb_t *adb, isc_boolean_t overmem, dns_adbentry_t *entry,
1562 isc_boolean_t destroy_entry;
1563 isc_boolean_t result = ISC_FALSE;
1565 bucket = entry->lock_bucket;
1568 LOCK(&adb->entrylocks[bucket]);
1570 INSIST(entry->refcnt > 0);
1573 destroy_entry = ISC_FALSE;
1574 if (entry->refcnt == 0 &&
1575 (adb->entry_sd[bucket] || entry->expires == 0 || overmem ||
1576 (entry->flags & ENTRY_IS_DEAD) != 0)) {
1577 destroy_entry = ISC_TRUE;
1578 result = unlink_entry(adb, entry);
1582 UNLOCK(&adb->entrylocks[bucket]);
1587 entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1589 free_adbentry(adb, &entry);
1591 result = dec_adb_irefcnt(adb);
1596 static inline dns_adbname_t *
1597 new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
1598 dns_adbname_t *name;
1600 name = isc_mempool_get(adb->nmp);
1604 dns_name_init(&name->name, NULL);
1605 if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
1606 isc_mempool_put(adb->nmp, name);
1609 dns_name_init(&name->target, NULL);
1610 name->magic = DNS_ADBNAME_MAGIC;
1612 name->partial_result = 0;
1614 name->expire_v4 = INT_MAX;
1615 name->expire_v6 = INT_MAX;
1616 name->expire_target = INT_MAX;
1618 name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1619 ISC_LIST_INIT(name->v4);
1620 ISC_LIST_INIT(name->v6);
1621 name->fetch_a = NULL;
1622 name->fetch_aaaa = NULL;
1623 name->fetch_err = FIND_ERR_UNEXPECTED;
1624 name->fetch6_err = FIND_ERR_UNEXPECTED;
1625 ISC_LIST_INIT(name->finds);
1626 ISC_LINK_INIT(name, plink);
1628 LOCK(&adb->namescntlock);
1630 if (!adb->grownames_sent && adb->namescnt > (adb->nnames * 8)) {
1631 isc_event_t *event = &adb->grownames;
1632 inc_adb_irefcnt(adb);
1633 isc_task_send(adb->task, &event);
1634 adb->grownames_sent = ISC_TRUE;
1636 UNLOCK(&adb->namescntlock);
1642 free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
1645 INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
1649 INSIST(!NAME_HAS_V4(n));
1650 INSIST(!NAME_HAS_V6(n));
1651 INSIST(!NAME_FETCH(n));
1652 INSIST(ISC_LIST_EMPTY(n->finds));
1653 INSIST(!ISC_LINK_LINKED(n, plink));
1654 INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
1655 INSIST(n->adb == adb);
1658 dns_name_free(&n->name, adb->mctx);
1660 isc_mempool_put(adb->nmp, n);
1661 LOCK(&adb->namescntlock);
1663 UNLOCK(&adb->namescntlock);
1666 static inline dns_adbnamehook_t *
1667 new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) {
1668 dns_adbnamehook_t *nh;
1670 nh = isc_mempool_get(adb->nhmp);
1674 nh->magic = DNS_ADBNAMEHOOK_MAGIC;
1676 ISC_LINK_INIT(nh, plink);
1682 free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) {
1683 dns_adbnamehook_t *nh;
1685 INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
1689 INSIST(nh->entry == NULL);
1690 INSIST(!ISC_LINK_LINKED(nh, plink));
1693 isc_mempool_put(adb->nhmp, nh);
1696 static inline dns_adblameinfo_t *
1697 new_adblameinfo(dns_adb_t *adb, dns_name_t *qname, dns_rdatatype_t qtype) {
1698 dns_adblameinfo_t *li;
1700 li = isc_mempool_get(adb->limp);
1704 dns_name_init(&li->qname, NULL);
1705 if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) {
1706 isc_mempool_put(adb->limp, li);
1709 li->magic = DNS_ADBLAMEINFO_MAGIC;
1712 ISC_LINK_INIT(li, plink);
1718 free_adblameinfo(dns_adb_t *adb, dns_adblameinfo_t **lameinfo) {
1719 dns_adblameinfo_t *li;
1721 INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo));
1725 INSIST(!ISC_LINK_LINKED(li, plink));
1727 dns_name_free(&li->qname, adb->mctx);
1731 isc_mempool_put(adb->limp, li);
1734 static inline dns_adbentry_t *
1735 new_adbentry(dns_adb_t *adb) {
1739 e = isc_mempool_get(adb->emp);
1743 e->magic = DNS_ADBENTRY_MAGIC;
1744 e->lock_bucket = DNS_ADB_INVALIDBUCKET;
1748 e->srtt = (r & 0x1f) + 1;
1750 ISC_LIST_INIT(e->lameinfo);
1751 ISC_LINK_INIT(e, plink);
1752 LOCK(&adb->entriescntlock);
1754 if (!adb->growentries_sent &&
1755 adb->entriescnt > (adb->nentries * 8)) {
1756 isc_event_t *event = &adb->growentries;
1757 inc_adb_irefcnt(adb);
1758 isc_task_send(adb->task, &event);
1759 adb->growentries_sent = ISC_TRUE;
1761 UNLOCK(&adb->entriescntlock);
1767 free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
1769 dns_adblameinfo_t *li;
1771 INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
1775 INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
1776 INSIST(e->refcnt == 0);
1777 INSIST(!ISC_LINK_LINKED(e, plink));
1781 li = ISC_LIST_HEAD(e->lameinfo);
1782 while (li != NULL) {
1783 ISC_LIST_UNLINK(e->lameinfo, li, plink);
1784 free_adblameinfo(adb, &li);
1785 li = ISC_LIST_HEAD(e->lameinfo);
1788 isc_mempool_put(adb->emp, e);
1789 LOCK(&adb->entriescntlock);
1791 UNLOCK(&adb->entriescntlock);
1794 static inline dns_adbfind_t *
1795 new_adbfind(dns_adb_t *adb) {
1797 isc_result_t result;
1799 h = isc_mempool_get(adb->ahmp);
1808 h->partial_result = 0;
1811 h->result_v4 = ISC_R_UNEXPECTED;
1812 h->result_v6 = ISC_R_UNEXPECTED;
1813 ISC_LINK_INIT(h, publink);
1814 ISC_LINK_INIT(h, plink);
1815 ISC_LIST_INIT(h->list);
1817 h->name_bucket = DNS_ADB_INVALIDBUCKET;
1822 result = isc_mutex_init(&h->lock);
1823 if (result != ISC_R_SUCCESS) {
1824 isc_mempool_put(adb->ahmp, h);
1828 ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
1831 inc_adb_irefcnt(adb);
1832 h->magic = DNS_ADBFIND_MAGIC;
1836 static inline dns_adbfetch_t *
1837 new_adbfetch(dns_adb_t *adb) {
1840 f = isc_mempool_get(adb->afmp);
1847 dns_rdataset_init(&f->rdataset);
1849 f->magic = DNS_ADBFETCH_MAGIC;
1855 free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) {
1858 INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
1864 if (dns_rdataset_isassociated(&f->rdataset))
1865 dns_rdataset_disassociate(&f->rdataset);
1867 isc_mempool_put(adb->afmp, f);
1870 static inline isc_boolean_t
1871 free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
1872 dns_adbfind_t *find;
1874 INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
1878 INSIST(!FIND_HAS_ADDRS(find));
1879 INSIST(!ISC_LINK_LINKED(find, publink));
1880 INSIST(!ISC_LINK_LINKED(find, plink));
1881 INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
1882 INSIST(find->adbname == NULL);
1886 DESTROYLOCK(&find->lock);
1887 isc_mempool_put(adb->ahmp, find);
1888 return (dec_adb_irefcnt(adb));
1892 * Copy bits from the entry into the newly allocated addrinfo. The entry
1893 * must be locked, and the reference count must be bumped up by one
1894 * if this function returns a valid pointer.
1896 static inline dns_adbaddrinfo_t *
1897 new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
1898 dns_adbaddrinfo_t *ai;
1900 ai = isc_mempool_get(adb->aimp);
1904 ai->magic = DNS_ADBADDRINFO_MAGIC;
1905 ai->sockaddr = entry->sockaddr;
1906 isc_sockaddr_setport(&ai->sockaddr, port);
1907 ai->srtt = entry->srtt;
1908 ai->flags = entry->flags;
1910 ISC_LINK_INIT(ai, publink);
1916 free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
1917 dns_adbaddrinfo_t *ai;
1919 INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
1923 INSIST(ai->entry == NULL);
1924 INSIST(!ISC_LINK_LINKED(ai, publink));
1928 isc_mempool_put(adb->aimp, ai);
1932 * Search for the name. NOTE: The bucket is kept locked on both
1933 * success and failure, so it must always be unlocked by the caller!
1935 * On the first call to this function, *bucketp must be set to
1936 * DNS_ADB_INVALIDBUCKET.
1938 static inline dns_adbname_t *
1939 find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
1940 unsigned int options, int *bucketp)
1942 dns_adbname_t *adbname;
1945 bucket = dns_name_fullhash(name, ISC_FALSE) % adb->nnames;
1947 if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1948 LOCK(&adb->namelocks[bucket]);
1950 } else if (*bucketp != bucket) {
1951 UNLOCK(&adb->namelocks[*bucketp]);
1952 LOCK(&adb->namelocks[bucket]);
1956 adbname = ISC_LIST_HEAD(adb->names[bucket]);
1957 while (adbname != NULL) {
1958 if (!NAME_DEAD(adbname)) {
1959 if (dns_name_equal(name, &adbname->name)
1960 && GLUEHINT_OK(adbname, options)
1961 && STARTATZONE_MATCHES(adbname, options))
1964 adbname = ISC_LIST_NEXT(adbname, plink);
1971 * Search for the address. NOTE: The bucket is kept locked on both
1972 * success and failure, so it must always be unlocked by the caller.
1974 * On the first call to this function, *bucketp must be set to
1975 * DNS_ADB_INVALIDBUCKET. This will cause a lock to occur. On
1976 * later calls (within the same "lock path") it can be left alone, so
1977 * if this function is called multiple times locking is only done if
1978 * the bucket changes.
1980 static inline dns_adbentry_t *
1981 find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp,
1984 dns_adbentry_t *entry, *entry_next;
1987 bucket = isc_sockaddr_hash(addr, ISC_TRUE) % adb->nentries;
1989 if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1990 LOCK(&adb->entrylocks[bucket]);
1992 } else if (*bucketp != bucket) {
1993 UNLOCK(&adb->entrylocks[*bucketp]);
1994 LOCK(&adb->entrylocks[bucket]);
1998 /* Search the list, while cleaning up expired entries. */
1999 for (entry = ISC_LIST_HEAD(adb->entries[bucket]);
2001 entry = entry_next) {
2002 entry_next = ISC_LIST_NEXT(entry, plink);
2003 (void)check_expire_entry(adb, &entry, now);
2004 if (entry != NULL &&
2005 isc_sockaddr_equal(addr, &entry->sockaddr)) {
2006 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
2007 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
2016 * Entry bucket MUST be locked!
2018 static isc_boolean_t
2019 entry_is_lame(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *qname,
2020 dns_rdatatype_t qtype, isc_stdtime_t now)
2022 dns_adblameinfo_t *li, *next_li;
2023 isc_boolean_t is_bad;
2027 li = ISC_LIST_HEAD(entry->lameinfo);
2030 while (li != NULL) {
2031 next_li = ISC_LIST_NEXT(li, plink);
2034 * Has the entry expired?
2036 if (li->lame_timer < now) {
2037 ISC_LIST_UNLINK(entry->lameinfo, li, plink);
2038 free_adblameinfo(adb, &li);
2042 * Order tests from least to most expensive.
2044 * We do not break out of the main loop here as
2045 * we use the loop for house keeping.
2047 if (li != NULL && !is_bad && li->qtype == qtype &&
2048 dns_name_equal(qname, &li->qname))
2058 copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname,
2059 dns_rdatatype_t qtype, dns_adbname_t *name,
2062 dns_adbnamehook_t *namehook;
2063 dns_adbaddrinfo_t *addrinfo;
2064 dns_adbentry_t *entry;
2067 bucket = DNS_ADB_INVALIDBUCKET;
2069 if (find->options & DNS_ADBFIND_INET) {
2070 namehook = ISC_LIST_HEAD(name->v4);
2071 while (namehook != NULL) {
2072 entry = namehook->entry;
2073 bucket = entry->lock_bucket;
2074 LOCK(&adb->entrylocks[bucket]);
2076 if (!FIND_RETURNLAME(find)
2077 && entry_is_lame(adb, entry, qname, qtype, now)) {
2078 find->options |= DNS_ADBFIND_LAMEPRUNED;
2081 addrinfo = new_adbaddrinfo(adb, entry, find->port);
2082 if (addrinfo == NULL) {
2083 find->partial_result |= DNS_ADBFIND_INET;
2087 * Found a valid entry. Add it to the find's list.
2089 inc_entry_refcnt(adb, entry, ISC_FALSE);
2090 ISC_LIST_APPEND(find->list, addrinfo, publink);
2093 UNLOCK(&adb->entrylocks[bucket]);
2094 bucket = DNS_ADB_INVALIDBUCKET;
2095 namehook = ISC_LIST_NEXT(namehook, plink);
2099 if (find->options & DNS_ADBFIND_INET6) {
2100 namehook = ISC_LIST_HEAD(name->v6);
2101 while (namehook != NULL) {
2102 entry = namehook->entry;
2103 bucket = entry->lock_bucket;
2104 LOCK(&adb->entrylocks[bucket]);
2106 if (!FIND_RETURNLAME(find)
2107 && entry_is_lame(adb, entry, qname, qtype, now)) {
2108 find->options |= DNS_ADBFIND_LAMEPRUNED;
2111 addrinfo = new_adbaddrinfo(adb, entry, find->port);
2112 if (addrinfo == NULL) {
2113 find->partial_result |= DNS_ADBFIND_INET6;
2117 * Found a valid entry. Add it to the find's list.
2119 inc_entry_refcnt(adb, entry, ISC_FALSE);
2120 ISC_LIST_APPEND(find->list, addrinfo, publink);
2123 UNLOCK(&adb->entrylocks[bucket]);
2124 bucket = DNS_ADB_INVALIDBUCKET;
2125 namehook = ISC_LIST_NEXT(namehook, plink);
2130 if (bucket != DNS_ADB_INVALIDBUCKET)
2131 UNLOCK(&adb->entrylocks[bucket]);
2135 shutdown_task(isc_task_t *task, isc_event_t *ev) {
2141 INSIST(DNS_ADB_VALID(adb));
2143 isc_event_free(&ev);
2145 * Wait for lock around check_exit() call to be released.
2153 * Name bucket must be locked; adb may be locked; no other locks held.
2155 static isc_boolean_t
2156 check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
2157 dns_adbname_t *name;
2158 isc_boolean_t result = ISC_FALSE;
2160 INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
2163 if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
2165 if (NAME_FETCH(name))
2167 if (!EXPIRE_OK(name->expire_v4, now))
2169 if (!EXPIRE_OK(name->expire_v6, now))
2171 if (!EXPIRE_OK(name->expire_target, now))
2175 * The name is empty. Delete it.
2177 result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
2181 * Our caller, or one of its callers, will be calling check_exit() at
2182 * some point, so we don't need to do it here.
2188 * Examine the tail entry of the LRU list to see if it expires or is stale
2189 * (unused for some period); if so, the name entry will be freed. If the ADB
2190 * is in the overmem condition, the tail and the next to tail entries
2191 * will be unconditionally removed (unless they have an outstanding fetch).
2192 * We don't care about a race on 'overmem' at the risk of causing some
2193 * collateral damage or a small delay in starting cleanup, so we don't bother
2194 * to lock ADB (if it's not locked).
2196 * Name bucket must be locked; adb may be locked; no other locks held.
2199 check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2200 int victims, max_victims;
2201 dns_adbname_t *victim, *next_victim;
2202 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
2205 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2207 max_victims = overmem ? 2 : 1;
2210 * We limit the number of scanned entries to 10 (arbitrary choice)
2211 * in order to avoid examining too many entries when there are many
2212 * tail entries that have fetches (this should be rare, but could
2215 victim = ISC_LIST_TAIL(adb->names[bucket]);
2217 victim != NULL && victims < max_victims && scans < 10;
2218 victim = next_victim) {
2219 INSIST(!NAME_DEAD(victim));
2221 next_victim = ISC_LIST_PREV(victim, plink);
2222 (void)check_expire_name(&victim, now);
2223 if (victim == NULL) {
2228 if (!NAME_FETCH(victim) &&
2229 (overmem || victim->last_used + ADB_STALE_MARGIN <= now)) {
2230 RUNTIME_CHECK(kill_name(&victim,
2231 DNS_EVENT_ADBCANCELED) ==
2243 * Entry bucket must be locked; adb may be locked; no other locks held.
2245 static isc_boolean_t
2246 check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
2248 dns_adbentry_t *entry;
2249 isc_boolean_t result = ISC_FALSE;
2251 INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
2254 if (entry->refcnt != 0)
2257 if (entry->expires == 0 || entry->expires > now)
2261 * The entry is not in use. Delete it.
2263 DP(DEF_LEVEL, "killing entry %p", entry);
2264 INSIST(ISC_LINK_LINKED(entry, plink));
2265 result = unlink_entry(adb, entry);
2266 free_adbentry(adb, &entry);
2268 dec_adb_irefcnt(adb);
2274 * ADB must be locked, and no other locks held.
2276 static isc_boolean_t
2277 cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2278 dns_adbname_t *name;
2279 dns_adbname_t *next_name;
2280 isc_boolean_t result = ISC_FALSE;
2282 DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
2284 LOCK(&adb->namelocks[bucket]);
2285 if (adb->name_sd[bucket]) {
2286 UNLOCK(&adb->namelocks[bucket]);
2290 name = ISC_LIST_HEAD(adb->names[bucket]);
2291 while (name != NULL) {
2292 next_name = ISC_LIST_NEXT(name, plink);
2293 INSIST(result == ISC_FALSE);
2294 result = check_expire_namehooks(name, now);
2296 result = check_expire_name(&name, now);
2299 UNLOCK(&adb->namelocks[bucket]);
2304 * ADB must be locked, and no other locks held.
2306 static isc_boolean_t
2307 cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2308 dns_adbentry_t *entry, *next_entry;
2309 isc_boolean_t result = ISC_FALSE;
2311 DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
2313 LOCK(&adb->entrylocks[bucket]);
2314 entry = ISC_LIST_HEAD(adb->entries[bucket]);
2315 while (entry != NULL) {
2316 next_entry = ISC_LIST_NEXT(entry, plink);
2317 INSIST(result == ISC_FALSE);
2318 result = check_expire_entry(adb, &entry, now);
2321 UNLOCK(&adb->entrylocks[bucket]);
2326 destroy(dns_adb_t *adb) {
2329 isc_task_detach(&adb->task);
2331 isc_mempool_destroy(&adb->nmp);
2332 isc_mempool_destroy(&adb->nhmp);
2333 isc_mempool_destroy(&adb->limp);
2334 isc_mempool_destroy(&adb->emp);
2335 isc_mempool_destroy(&adb->ahmp);
2336 isc_mempool_destroy(&adb->aimp);
2337 isc_mempool_destroy(&adb->afmp);
2339 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
2340 isc_mem_put(adb->mctx, adb->entries,
2341 sizeof(*adb->entries) * adb->nentries);
2342 isc_mem_put(adb->mctx, adb->deadentries,
2343 sizeof(*adb->deadentries) * adb->nentries);
2344 isc_mem_put(adb->mctx, adb->entrylocks,
2345 sizeof(*adb->entrylocks) * adb->nentries);
2346 isc_mem_put(adb->mctx, adb->entry_sd,
2347 sizeof(*adb->entry_sd) * adb->nentries);
2348 isc_mem_put(adb->mctx, adb->entry_refcnt,
2349 sizeof(*adb->entry_refcnt) * adb->nentries);
2351 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
2352 isc_mem_put(adb->mctx, adb->names,
2353 sizeof(*adb->names) * adb->nnames);
2354 isc_mem_put(adb->mctx, adb->deadnames,
2355 sizeof(*adb->deadnames) * adb->nnames);
2356 isc_mem_put(adb->mctx, adb->namelocks,
2357 sizeof(*adb->namelocks) * adb->nnames);
2358 isc_mem_put(adb->mctx, adb->name_sd,
2359 sizeof(*adb->name_sd) * adb->nnames);
2360 isc_mem_put(adb->mctx, adb->name_refcnt,
2361 sizeof(*adb->name_refcnt) * adb->nnames);
2363 DESTROYLOCK(&adb->reflock);
2364 DESTROYLOCK(&adb->lock);
2365 DESTROYLOCK(&adb->mplock);
2366 DESTROYLOCK(&adb->overmemlock);
2367 DESTROYLOCK(&adb->entriescntlock);
2368 DESTROYLOCK(&adb->namescntlock);
2370 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2379 dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
2380 isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
2383 isc_result_t result;
2386 REQUIRE(mem != NULL);
2387 REQUIRE(view != NULL);
2388 REQUIRE(timermgr != NULL); /* this is actually unused */
2389 REQUIRE(taskmgr != NULL);
2390 REQUIRE(newadb != NULL && *newadb == NULL);
2394 adb = isc_mem_get(mem, sizeof(dns_adb_t));
2396 return (ISC_R_NOMEMORY);
2399 * Initialize things here that cannot fail, and especially things
2400 * that must be NULL for the error return to work properly.
2415 adb->taskmgr = taskmgr;
2416 adb->next_cleanbucket = 0;
2417 ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
2418 DNS_EVENT_ADBCONTROL, shutdown_task, adb,
2420 adb->cevent_sent = ISC_FALSE;
2421 adb->shutting_down = ISC_FALSE;
2422 ISC_LIST_INIT(adb->whenshutdown);
2424 adb->nentries = nbuckets[0];
2425 adb->entriescnt = 0;
2426 adb->entries = NULL;
2427 adb->deadentries = NULL;
2428 adb->entry_sd = NULL;
2429 adb->entry_refcnt = NULL;
2430 adb->entrylocks = NULL;
2431 ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL,
2432 DNS_EVENT_ADBGROWENTRIES, grow_entries, adb,
2434 adb->growentries_sent = ISC_FALSE;
2436 adb->nnames = nbuckets[0];
2439 adb->deadnames = NULL;
2440 adb->name_sd = NULL;
2441 adb->name_refcnt = NULL;
2442 adb->namelocks = NULL;
2443 ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL,
2444 DNS_EVENT_ADBGROWNAMES, grow_names, adb,
2446 adb->grownames_sent = ISC_FALSE;
2448 isc_mem_attach(mem, &adb->mctx);
2450 result = isc_mutex_init(&adb->lock);
2451 if (result != ISC_R_SUCCESS)
2454 result = isc_mutex_init(&adb->mplock);
2455 if (result != ISC_R_SUCCESS)
2458 result = isc_mutex_init(&adb->reflock);
2459 if (result != ISC_R_SUCCESS)
2462 result = isc_mutex_init(&adb->overmemlock);
2463 if (result != ISC_R_SUCCESS)
2466 result = isc_mutex_init(&adb->entriescntlock);
2467 if (result != ISC_R_SUCCESS)
2470 result = isc_mutex_init(&adb->namescntlock);
2471 if (result != ISC_R_SUCCESS)
2474 #define ALLOCENTRY(adb, el) \
2476 (adb)->el = isc_mem_get((adb)->mctx, \
2477 sizeof(*(adb)->el) * (adb)->nentries); \
2478 if ((adb)->el == NULL) { \
2479 result = ISC_R_NOMEMORY; \
2483 ALLOCENTRY(adb, entries);
2484 ALLOCENTRY(adb, deadentries);
2485 ALLOCENTRY(adb, entrylocks);
2486 ALLOCENTRY(adb, entry_sd);
2487 ALLOCENTRY(adb, entry_refcnt);
2490 #define ALLOCNAME(adb, el) \
2492 (adb)->el = isc_mem_get((adb)->mctx, \
2493 sizeof(*(adb)->el) * (adb)->nnames); \
2494 if ((adb)->el == NULL) { \
2495 result = ISC_R_NOMEMORY; \
2499 ALLOCNAME(adb, names);
2500 ALLOCNAME(adb, deadnames);
2501 ALLOCNAME(adb, namelocks);
2502 ALLOCNAME(adb, name_sd);
2503 ALLOCNAME(adb, name_refcnt);
2507 * Initialize the bucket locks for names and elements.
2508 * May as well initialize the list heads, too.
2510 result = isc_mutexblock_init(adb->namelocks, adb->nnames);
2511 if (result != ISC_R_SUCCESS)
2513 for (i = 0; i < adb->nnames; i++) {
2514 ISC_LIST_INIT(adb->names[i]);
2515 ISC_LIST_INIT(adb->deadnames[i]);
2516 adb->name_sd[i] = ISC_FALSE;
2517 adb->name_refcnt[i] = 0;
2520 for (i = 0; i < adb->nentries; i++) {
2521 ISC_LIST_INIT(adb->entries[i]);
2522 ISC_LIST_INIT(adb->deadentries[i]);
2523 adb->entry_sd[i] = ISC_FALSE;
2524 adb->entry_refcnt[i] = 0;
2527 result = isc_mutexblock_init(adb->entrylocks, adb->nentries);
2528 if (result != ISC_R_SUCCESS)
2534 #define MPINIT(t, p, n) do { \
2535 result = isc_mempool_create(mem, sizeof(t), &(p)); \
2536 if (result != ISC_R_SUCCESS) \
2538 isc_mempool_setfreemax((p), FREE_ITEMS); \
2539 isc_mempool_setfillcount((p), FILL_COUNT); \
2540 isc_mempool_setname((p), n); \
2541 isc_mempool_associatelock((p), &adb->mplock); \
2544 MPINIT(dns_adbname_t, adb->nmp, "adbname");
2545 MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
2546 MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo");
2547 MPINIT(dns_adbentry_t, adb->emp, "adbentry");
2548 MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
2549 MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
2550 MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
2555 * Allocate an internal task.
2557 result = isc_task_create(adb->taskmgr, 0, &adb->task);
2558 if (result != ISC_R_SUCCESS)
2560 isc_task_setname(adb->task, "ADB", adb);
2565 adb->magic = DNS_ADB_MAGIC;
2567 return (ISC_R_SUCCESS);
2570 if (adb->task != NULL)
2571 isc_task_detach(&adb->task);
2573 /* clean up entrylocks */
2574 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
2576 fail2: /* clean up namelocks */
2577 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
2579 fail1: /* clean up only allocated memory */
2580 if (adb->entries != NULL)
2581 isc_mem_put(adb->mctx, adb->entries,
2582 sizeof(*adb->entries) * adb->nentries);
2583 if (adb->deadentries != NULL)
2584 isc_mem_put(adb->mctx, adb->deadentries,
2585 sizeof(*adb->deadentries) * adb->nentries);
2586 if (adb->entrylocks != NULL)
2587 isc_mem_put(adb->mctx, adb->entrylocks,
2588 sizeof(*adb->entrylocks) * adb->nentries);
2589 if (adb->entry_sd != NULL)
2590 isc_mem_put(adb->mctx, adb->entry_sd,
2591 sizeof(*adb->entry_sd) * adb->nentries);
2592 if (adb->entry_refcnt != NULL)
2593 isc_mem_put(adb->mctx, adb->entry_refcnt,
2594 sizeof(*adb->entry_refcnt) * adb->nentries);
2595 if (adb->names != NULL)
2596 isc_mem_put(adb->mctx, adb->names,
2597 sizeof(*adb->names) * adb->nnames);
2598 if (adb->deadnames != NULL)
2599 isc_mem_put(adb->mctx, adb->deadnames,
2600 sizeof(*adb->deadnames) * adb->nnames);
2601 if (adb->namelocks != NULL)
2602 isc_mem_put(adb->mctx, adb->namelocks,
2603 sizeof(*adb->namelocks) * adb->nnames);
2604 if (adb->name_sd != NULL)
2605 isc_mem_put(adb->mctx, adb->name_sd,
2606 sizeof(*adb->name_sd) * adb->nnames);
2607 if (adb->name_refcnt != NULL)
2608 isc_mem_put(adb->mctx, adb->name_refcnt,
2609 sizeof(*adb->name_refcnt) * adb->nnames);
2610 if (adb->nmp != NULL)
2611 isc_mempool_destroy(&adb->nmp);
2612 if (adb->nhmp != NULL)
2613 isc_mempool_destroy(&adb->nhmp);
2614 if (adb->limp != NULL)
2615 isc_mempool_destroy(&adb->limp);
2616 if (adb->emp != NULL)
2617 isc_mempool_destroy(&adb->emp);
2618 if (adb->ahmp != NULL)
2619 isc_mempool_destroy(&adb->ahmp);
2620 if (adb->aimp != NULL)
2621 isc_mempool_destroy(&adb->aimp);
2622 if (adb->afmp != NULL)
2623 isc_mempool_destroy(&adb->afmp);
2625 DESTROYLOCK(&adb->namescntlock);
2627 DESTROYLOCK(&adb->entriescntlock);
2629 DESTROYLOCK(&adb->overmemlock);
2631 DESTROYLOCK(&adb->reflock);
2633 DESTROYLOCK(&adb->mplock);
2635 DESTROYLOCK(&adb->lock);
2637 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2643 dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
2645 REQUIRE(DNS_ADB_VALID(adb));
2646 REQUIRE(adbx != NULL && *adbx == NULL);
2648 inc_adb_erefcnt(adb);
2653 dns_adb_detach(dns_adb_t **adbx) {
2655 isc_boolean_t need_exit_check;
2657 REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
2662 INSIST(adb->erefcnt > 0);
2664 LOCK(&adb->reflock);
2666 need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
2667 UNLOCK(&adb->reflock);
2669 if (need_exit_check) {
2671 INSIST(adb->shutting_down);
2678 dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
2681 isc_boolean_t zeroirefcnt = ISC_FALSE;
2684 * Send '*eventp' to 'task' when 'adb' has shutdown.
2687 REQUIRE(DNS_ADB_VALID(adb));
2688 REQUIRE(eventp != NULL);
2695 LOCK(&adb->reflock);
2696 zeroirefcnt = ISC_TF(adb->irefcnt == 0);
2698 if (adb->shutting_down && zeroirefcnt &&
2699 isc_mempool_getallocated(adb->ahmp) == 0) {
2701 * We're already shutdown. Send the event.
2703 event->ev_sender = adb;
2704 isc_task_send(task, &event);
2707 isc_task_attach(task, &clone);
2708 event->ev_sender = clone;
2709 ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
2712 UNLOCK(&adb->reflock);
2717 dns_adb_shutdown(dns_adb_t *adb) {
2718 isc_boolean_t need_check_exit;
2726 if (!adb->shutting_down) {
2727 adb->shutting_down = ISC_TRUE;
2728 isc_mem_setwater(adb->mctx, water, adb, 0, 0);
2729 need_check_exit = shutdown_names(adb);
2730 if (!need_check_exit)
2731 need_check_exit = shutdown_entries(adb);
2732 if (need_check_exit)
2740 dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
2741 void *arg, dns_name_t *name, dns_name_t *qname,
2742 dns_rdatatype_t qtype, unsigned int options,
2743 isc_stdtime_t now, dns_name_t *target,
2744 in_port_t port, dns_adbfind_t **findp)
2746 dns_adbfind_t *find;
2747 dns_adbname_t *adbname;
2749 isc_boolean_t want_event, start_at_zone, alias, have_address;
2750 isc_result_t result;
2751 unsigned int wanted_addresses;
2752 unsigned int wanted_fetches;
2753 unsigned int query_pending;
2755 REQUIRE(DNS_ADB_VALID(adb));
2757 REQUIRE(action != NULL);
2759 REQUIRE(name != NULL);
2760 REQUIRE(qname != NULL);
2761 REQUIRE(findp != NULL && *findp == NULL);
2762 REQUIRE(target == NULL || dns_name_hasbuffer(target));
2764 REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
2766 result = ISC_R_UNEXPECTED;
2768 wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
2771 want_event = ISC_FALSE;
2772 start_at_zone = ISC_FALSE;
2776 isc_stdtime_get(&now);
2779 * XXXMLG Move this comment somewhere else!
2781 * Look up the name in our internal database.
2783 * Possibilities: Note that these are not always exclusive.
2785 * No name found. In this case, allocate a new name header and
2786 * an initial namehook or two. If any of these allocations
2787 * fail, clean up and return ISC_R_NOMEMORY.
2789 * Name found, valid addresses present. Allocate one addrinfo
2790 * structure for each found and append it to the linked list
2791 * of addresses for this header.
2793 * Name found, queries pending. In this case, if a task was
2794 * passed in, allocate a job id, attach it to the name's job
2795 * list and remember to tell the caller that there will be
2796 * more info coming later.
2799 find = new_adbfind(adb);
2801 return (ISC_R_NOMEMORY);
2806 * Remember what types of addresses we are interested in.
2808 find->options = options;
2809 find->flags |= wanted_addresses;
2810 if (FIND_WANTEVENT(find)) {
2811 REQUIRE(task != NULL);
2815 * Try to see if we know anything about this name at all.
2817 bucket = DNS_ADB_INVALIDBUCKET;
2818 adbname = find_name_and_lock(adb, name, find->options, &bucket);
2819 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2820 if (adb->name_sd[bucket]) {
2822 "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
2823 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2824 result = ISC_R_SHUTTINGDOWN;
2829 * Nothing found. Allocate a new adbname structure for this name.
2831 if (adbname == NULL) {
2833 * See if there is any stale name at the end of list, and purge
2836 check_stale_name(adb, bucket, now);
2838 adbname = new_adbname(adb, name);
2839 if (adbname == NULL) {
2840 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2841 result = ISC_R_NOMEMORY;
2844 link_name(adb, bucket, adbname);
2845 if (FIND_HINTOK(find))
2846 adbname->flags |= NAME_HINT_OK;
2847 if (FIND_GLUEOK(find))
2848 adbname->flags |= NAME_GLUE_OK;
2849 if (FIND_STARTATZONE(find))
2850 adbname->flags |= NAME_STARTATZONE;
2852 /* Move this name forward in the LRU list */
2853 ISC_LIST_UNLINK(adb->names[bucket], adbname, plink);
2854 ISC_LIST_PREPEND(adb->names[bucket], adbname, plink);
2856 adbname->last_used = now;
2859 * Expire old entries, etc.
2861 RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE);
2864 * Do we know that the name is an alias?
2866 if (!EXPIRE_OK(adbname->expire_target, now)) {
2871 "dns_adb_createfind: name %p is an alias (cached)",
2878 * Try to populate the name from the database and/or
2879 * start fetches. First try looking for an A record
2882 if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
2883 && WANT_INET(wanted_addresses)) {
2884 result = dbfind_name(adbname, now, dns_rdatatype_a);
2885 if (result == ISC_R_SUCCESS) {
2887 "dns_adb_createfind: found A for name %p in db",
2893 * Did we get a CNAME or DNAME?
2895 if (result == DNS_R_ALIAS) {
2897 "dns_adb_createfind: name %p is an alias",
2904 * If the name doesn't exist at all, don't bother with
2905 * v6 queries; they won't work.
2907 * If the name does exist but we didn't get our data, go
2908 * ahead and try AAAA.
2910 * If the result is neither of these, try a fetch for A.
2912 if (NXDOMAIN_RESULT(result))
2914 else if (NXRRSET_RESULT(result))
2917 if (!NAME_FETCH_V4(adbname))
2918 wanted_fetches |= DNS_ADBFIND_INET;
2922 if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
2923 && WANT_INET6(wanted_addresses)) {
2924 result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
2925 if (result == ISC_R_SUCCESS) {
2927 "dns_adb_createfind: found AAAA for name %p",
2933 * Did we get a CNAME or DNAME?
2935 if (result == DNS_R_ALIAS) {
2937 "dns_adb_createfind: name %p is an alias",
2944 * Listen to negative cache hints, and don't start
2947 if (NCACHE_RESULT(result) || AUTH_NX(result))
2950 if (!NAME_FETCH_V6(adbname))
2951 wanted_fetches |= DNS_ADBFIND_INET6;
2955 if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
2956 (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
2957 have_address = ISC_TRUE;
2959 have_address = ISC_FALSE;
2960 if (wanted_fetches != 0 &&
2961 ! (FIND_AVOIDFETCHES(find) && have_address)) {
2963 * We're missing at least one address family. Either the
2964 * caller hasn't instructed us to avoid fetches, or we don't
2965 * know anything about any of the address families that would
2966 * be acceptable so we have to launch fetches.
2969 if (FIND_STARTATZONE(find))
2970 start_at_zone = ISC_TRUE;
2975 if (WANT_INET(wanted_fetches) &&
2976 fetch_name(adbname, start_at_zone,
2977 dns_rdatatype_a) == ISC_R_SUCCESS) {
2979 "dns_adb_createfind: started A fetch for name %p",
2986 if (WANT_INET6(wanted_fetches) &&
2987 fetch_name(adbname, start_at_zone,
2988 dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
2990 "dns_adb_createfind: "
2991 "started AAAA fetch for name %p",
2997 * Run through the name and copy out the bits we are
3000 copy_namehook_lists(adb, find, qname, qtype, adbname, now);
3003 if (NAME_FETCH_V4(adbname))
3004 query_pending |= DNS_ADBFIND_INET;
3005 if (NAME_FETCH_V6(adbname))
3006 query_pending |= DNS_ADBFIND_INET6;
3009 * Attach to the name's query list if there are queries
3010 * already running, and we have been asked to.
3012 want_event = ISC_TRUE;
3013 if (!FIND_WANTEVENT(find))
3014 want_event = ISC_FALSE;
3015 if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
3016 want_event = ISC_FALSE;
3017 if ((wanted_addresses & query_pending) == 0)
3018 want_event = ISC_FALSE;
3020 want_event = ISC_FALSE;
3022 find->adbname = adbname;
3023 find->name_bucket = bucket;
3024 ISC_LIST_APPEND(adbname->finds, find, plink);
3025 find->query_pending = (query_pending & wanted_addresses);
3026 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
3027 find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
3028 DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
3032 * Remove the flag so the caller knows there will never
3033 * be an event, and set internal flags to fake that
3034 * the event was sent and freed, so dns_adb_destroyfind() will
3035 * do the right thing.
3037 find->query_pending = (query_pending & wanted_addresses);
3038 find->options &= ~DNS_ADBFIND_WANTEVENT;
3039 find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
3040 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
3043 find->partial_result |= (adbname->partial_result & wanted_addresses);
3045 if (target != NULL) {
3046 result = dns_name_copy(&adbname->target, target, NULL);
3047 if (result != ISC_R_SUCCESS)
3050 result = DNS_R_ALIAS;
3052 result = ISC_R_SUCCESS;
3055 * Copy out error flags from the name structure into the find.
3057 find->result_v4 = find_err_map[adbname->fetch_err];
3058 find->result_v6 = find_err_map[adbname->fetch6_err];
3067 INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
3069 isc_task_attach(task, &taskp);
3070 find->event.ev_sender = taskp;
3071 find->event.ev_action = action;
3072 find->event.ev_arg = arg;
3076 UNLOCK(&adb->namelocks[bucket]);
3082 dns_adb_destroyfind(dns_adbfind_t **findp) {
3083 dns_adbfind_t *find;
3084 dns_adbentry_t *entry;
3085 dns_adbaddrinfo_t *ai;
3088 isc_boolean_t overmem;
3090 REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
3096 DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
3099 REQUIRE(DNS_ADB_VALID(adb));
3101 REQUIRE(FIND_EVENTFREED(find));
3103 bucket = find->name_bucket;
3104 INSIST(bucket == DNS_ADB_INVALIDBUCKET);
3106 UNLOCK(&find->lock);
3109 * The find doesn't exist on any list, and nothing is locked.
3110 * Return the find to the memory pool, and decrement the adb's
3113 overmem = isc_mem_isovermem(adb->mctx);
3114 ai = ISC_LIST_HEAD(find->list);
3115 while (ai != NULL) {
3116 ISC_LIST_UNLINK(find->list, ai, publink);
3119 INSIST(DNS_ADBENTRY_VALID(entry));
3120 RUNTIME_CHECK(dec_entry_refcnt(adb, overmem, entry, ISC_TRUE) ==
3122 free_adbaddrinfo(adb, &ai);
3123 ai = ISC_LIST_HEAD(find->list);
3127 * WARNING: The find is freed with the adb locked. This is done
3128 * to avoid a race condition where we free the find, some other
3129 * thread tests to see if it should be destroyed, detects it should
3130 * be, destroys it, and then we try to lock it for our check, but the
3131 * lock is destroyed.
3134 if (free_adbfind(adb, &find))
3140 dns_adb_cancelfind(dns_adbfind_t *find) {
3149 DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
3152 REQUIRE(DNS_ADB_VALID(adb));
3154 REQUIRE(!FIND_EVENTFREED(find));
3155 REQUIRE(FIND_WANTEVENT(find));
3157 bucket = find->name_bucket;
3158 if (bucket == DNS_ADB_INVALIDBUCKET)
3162 * We need to get the adbname's lock to unlink the find.
3164 unlock_bucket = bucket;
3165 violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
3166 bucket = find->name_bucket;
3167 if (bucket != DNS_ADB_INVALIDBUCKET) {
3168 ISC_LIST_UNLINK(find->adbname->finds, find, plink);
3169 find->adbname = NULL;
3170 find->name_bucket = DNS_ADB_INVALIDBUCKET;
3172 UNLOCK(&adb->namelocks[unlock_bucket]);
3173 bucket = DNS_ADB_INVALIDBUCKET;
3178 if (!FIND_EVENTSENT(find)) {
3180 task = ev->ev_sender;
3181 ev->ev_sender = find;
3182 ev->ev_type = DNS_EVENT_ADBCANCELED;
3183 ev->ev_destroy = event_free;
3184 ev->ev_destroy_arg = find;
3185 find->result_v4 = ISC_R_CANCELED;
3186 find->result_v6 = ISC_R_CANCELED;
3188 DP(DEF_LEVEL, "sending event %p to task %p for find %p",
3191 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
3194 UNLOCK(&find->lock);
3198 dns_adb_dump(dns_adb_t *adb, FILE *f) {
3202 REQUIRE(DNS_ADB_VALID(adb));
3206 * Lock the adb itself, lock all the name buckets, then lock all
3207 * the entry buckets. This should put the adb into a state where
3208 * nothing can change, so we can iterate through everything and
3209 * print at our leisure.
3213 isc_stdtime_get(&now);
3215 for (i = 0; i < adb->nnames; i++)
3216 RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE);
3217 for (i = 0; i < adb->nentries; i++)
3218 RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE);
3220 dump_adb(adb, f, ISC_FALSE, now);
3225 dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
3226 if (value == INT_MAX)
3228 fprintf(f, " [%s TTL %d]", legend, value - now);
3232 dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
3234 dns_adbname_t *name;
3235 dns_adbentry_t *entry;
3237 fprintf(f, ";\n; Address database dump\n;\n");
3239 fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
3240 adb, adb->erefcnt, adb->irefcnt,
3241 isc_mempool_getallocated(adb->nhmp));
3243 for (i = 0; i < adb->nnames; i++)
3244 LOCK(&adb->namelocks[i]);
3245 for (i = 0; i < adb->nentries; i++)
3246 LOCK(&adb->entrylocks[i]);
3251 for (i = 0; i < adb->nnames; i++) {
3252 name = ISC_LIST_HEAD(adb->names[i]);
3256 fprintf(f, "; bucket %d\n", i);
3259 name = ISC_LIST_NEXT(name, plink))
3262 fprintf(f, "; name %p (flags %08x)\n",
3266 print_dns_name(f, &name->name);
3267 if (dns_name_countlabels(&name->target) > 0) {
3268 fprintf(f, " alias ");
3269 print_dns_name(f, &name->target);
3272 dump_ttl(f, "v4", name->expire_v4, now);
3273 dump_ttl(f, "v6", name->expire_v6, now);
3274 dump_ttl(f, "target", name->expire_target, now);
3276 fprintf(f, " [v4 %s] [v6 %s]",
3277 errnames[name->fetch_err],
3278 errnames[name->fetch6_err]);
3282 print_namehook_list(f, "v4", &name->v4, debug, now);
3283 print_namehook_list(f, "v6", &name->v6, debug, now);
3286 print_fetch_list(f, name);
3288 print_find_list(f, name);
3293 fprintf(f, ";\n; Unassociated entries\n;\n");
3295 for (i = 0; i < adb->nentries; i++) {
3296 entry = ISC_LIST_HEAD(adb->entries[i]);
3297 while (entry != NULL) {
3298 if (entry->refcnt == 0)
3299 dump_entry(f, entry, debug, now);
3300 entry = ISC_LIST_NEXT(entry, plink);
3307 for (i = 0; i < adb->nentries; i++)
3308 UNLOCK(&adb->entrylocks[i]);
3309 for (i = 0; i < adb->nnames; i++)
3310 UNLOCK(&adb->namelocks[i]);
3314 dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug,
3317 char addrbuf[ISC_NETADDR_FORMATSIZE];
3318 char typebuf[DNS_RDATATYPE_FORMATSIZE];
3319 isc_netaddr_t netaddr;
3320 dns_adblameinfo_t *li;
3322 isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
3323 isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
3326 fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
3328 fprintf(f, ";\t%s [srtt %u] [flags %08x]",
3329 addrbuf, entry->srtt, entry->flags);
3330 if (entry->expires != 0)
3331 fprintf(f, " [ttl %d]", entry->expires - now);
3333 for (li = ISC_LIST_HEAD(entry->lameinfo);
3335 li = ISC_LIST_NEXT(li, plink)) {
3336 fprintf(f, ";\t\t");
3337 print_dns_name(f, &li->qname);
3338 dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf));
3339 fprintf(f, " %s [lame TTL %d]\n", typebuf,
3340 li->lame_timer - now);
3345 dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
3348 dns_adbaddrinfo_t *ai;
3352 * Not used currently, in the API Just In Case we
3353 * want to dump out the name and/or entries too.
3358 fprintf(f, ";Find %p\n", find);
3359 fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
3360 find->query_pending, find->partial_result,
3361 find->options, find->flags);
3362 fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
3363 find->name_bucket, find->adbname, find->event.ev_sender);
3365 ai = ISC_LIST_HEAD(find->list);
3367 fprintf(f, "\tAddresses:\n");
3368 while (ai != NULL) {
3370 switch (sa->type.sa.sa_family) {
3372 tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
3376 tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
3384 tmpp = "BadAddress";
3386 fprintf(f, "\t\tentry %p, flags %08x"
3387 " srtt %u addr %s\n",
3388 ai->entry, ai->flags, ai->srtt, tmpp);
3390 ai = ISC_LIST_NEXT(ai, publink);
3393 UNLOCK(&find->lock);
3397 print_dns_name(FILE *f, dns_name_t *name) {
3398 char buf[DNS_NAME_FORMATSIZE];
3402 dns_name_format(name, buf, sizeof(buf));
3403 fprintf(f, "%s", buf);
3407 print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list,
3408 isc_boolean_t debug, isc_stdtime_t now)
3410 dns_adbnamehook_t *nh;
3412 for (nh = ISC_LIST_HEAD(*list);
3414 nh = ISC_LIST_NEXT(nh, plink))
3417 fprintf(f, ";\tHook(%s) %p\n", legend, nh);
3418 dump_entry(f, nh->entry, debug, now);
3423 print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) {
3424 fprintf(f, "\t\tFetch(%s): %p -> { fetch %p }\n",
3425 type, ft, ft->fetch);
3429 print_fetch_list(FILE *f, dns_adbname_t *n) {
3430 if (NAME_FETCH_A(n))
3431 print_fetch(f, n->fetch_a, "A");
3432 if (NAME_FETCH_AAAA(n))
3433 print_fetch(f, n->fetch_aaaa, "AAAA");
3437 print_find_list(FILE *f, dns_adbname_t *name) {
3438 dns_adbfind_t *find;
3440 find = ISC_LIST_HEAD(name->finds);
3441 while (find != NULL) {
3442 dns_adb_dumpfind(find, f);
3443 find = ISC_LIST_NEXT(find, plink);
3448 dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype)
3450 isc_result_t result;
3451 dns_rdataset_t rdataset;
3453 dns_fixedname_t foundname;
3456 INSIST(DNS_ADBNAME_VALID(adbname));
3458 INSIST(DNS_ADB_VALID(adb));
3459 INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
3461 dns_fixedname_init(&foundname);
3462 fname = dns_fixedname_name(&foundname);
3463 dns_rdataset_init(&rdataset);
3465 if (rdtype == dns_rdatatype_a)
3466 adbname->fetch_err = FIND_ERR_UNEXPECTED;
3468 adbname->fetch6_err = FIND_ERR_UNEXPECTED;
3471 * We need to specify whether to search static-stub zones (if
3472 * configured) depending on whether this is a "start at zone" lookup,
3473 * i.e., whether it's a "bailiwick" glue. If it's bailiwick (in which
3474 * case NAME_STARTATZONE is set) we need to stop the search at any
3475 * matching static-stub zone without looking into the cache to honor
3476 * the configuration on which server we should send queries to.
3478 result = dns_view_find2(adb->view, &adbname->name, rdtype, now,
3479 NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0,
3480 ISC_TF(NAME_HINTOK(adbname)),
3481 (adbname->flags & NAME_STARTATZONE) != 0 ?
3482 ISC_TRUE : ISC_FALSE,
3483 NULL, NULL, fname, &rdataset, NULL);
3485 /* XXXVIX this switch statement is too sparse to gen a jump table. */
3491 * Found in the database. Even if we can't copy out
3492 * any information, return success, or else a fetch
3493 * will be made, which will only make things worse.
3495 if (rdtype == dns_rdatatype_a)
3496 adbname->fetch_err = FIND_ERR_SUCCESS;
3498 adbname->fetch6_err = FIND_ERR_SUCCESS;
3499 result = import_rdataset(adbname, &rdataset, now);
3501 case DNS_R_NXDOMAIN:
3504 * We're authoritative and the data doesn't exist.
3505 * Make up a negative cache entry so we don't ask again
3508 * XXXRTH What time should we use? I'm putting in 30 seconds
3511 if (rdtype == dns_rdatatype_a) {
3512 adbname->expire_v4 = now + 30;
3514 "adb name %p: Caching auth negative entry for A",
3516 if (result == DNS_R_NXDOMAIN)
3517 adbname->fetch_err = FIND_ERR_NXDOMAIN;
3519 adbname->fetch_err = FIND_ERR_NXRRSET;
3522 "adb name %p: Caching auth negative entry for AAAA",
3524 adbname->expire_v6 = now + 30;
3525 if (result == DNS_R_NXDOMAIN)
3526 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3528 adbname->fetch6_err = FIND_ERR_NXRRSET;
3531 case DNS_R_NCACHENXDOMAIN:
3532 case DNS_R_NCACHENXRRSET:
3534 * We found a negative cache entry. Pull the TTL from it
3535 * so we won't ask again for a while.
3537 rdataset.ttl = ttlclamp(rdataset.ttl);
3538 if (rdtype == dns_rdatatype_a) {
3539 adbname->expire_v4 = rdataset.ttl + now;
3540 if (result == DNS_R_NCACHENXDOMAIN)
3541 adbname->fetch_err = FIND_ERR_NXDOMAIN;
3543 adbname->fetch_err = FIND_ERR_NXRRSET;
3545 "adb name %p: Caching negative entry for A (ttl %u)",
3546 adbname, rdataset.ttl);
3549 "adb name %p: Caching negative entry for AAAA (ttl %u)",
3550 adbname, rdataset.ttl);
3551 adbname->expire_v6 = rdataset.ttl + now;
3552 if (result == DNS_R_NCACHENXDOMAIN)
3553 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3555 adbname->fetch6_err = FIND_ERR_NXRRSET;
3561 * Clear the hint and glue flags, so this will match
3564 adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
3566 rdataset.ttl = ttlclamp(rdataset.ttl);
3567 clean_target(adb, &adbname->target);
3568 adbname->expire_target = INT_MAX;
3569 result = set_target(adb, &adbname->name, fname, &rdataset,
3571 if (result == ISC_R_SUCCESS) {
3572 result = DNS_R_ALIAS;
3574 "adb name %p: caching alias target",
3576 adbname->expire_target = rdataset.ttl + now;
3578 if (rdtype == dns_rdatatype_a)
3579 adbname->fetch_err = FIND_ERR_SUCCESS;
3581 adbname->fetch6_err = FIND_ERR_SUCCESS;
3585 if (dns_rdataset_isassociated(&rdataset))
3586 dns_rdataset_disassociate(&rdataset);
3592 fetch_callback(isc_task_t *task, isc_event_t *ev) {
3593 dns_fetchevent_t *dev;
3594 dns_adbname_t *name;
3596 dns_adbfetch_t *fetch;
3598 isc_eventtype_t ev_status;
3600 isc_result_t result;
3601 unsigned int address_type;
3602 isc_boolean_t want_check_exit = ISC_FALSE;
3606 INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
3607 dev = (dns_fetchevent_t *)ev;
3609 INSIST(DNS_ADBNAME_VALID(name));
3611 INSIST(DNS_ADB_VALID(adb));
3613 bucket = name->lock_bucket;
3614 LOCK(&adb->namelocks[bucket]);
3616 INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
3618 if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
3619 address_type = DNS_ADBFIND_INET;
3620 fetch = name->fetch_a;
3621 name->fetch_a = NULL;
3622 } else if (NAME_FETCH_AAAA(name)
3623 && (name->fetch_aaaa->fetch == dev->fetch)) {
3624 address_type = DNS_ADBFIND_INET6;
3625 fetch = name->fetch_aaaa;
3626 name->fetch_aaaa = NULL;
3630 INSIST(address_type != 0 && fetch != NULL);
3632 dns_resolver_destroyfetch(&fetch->fetch);
3635 ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
3638 * Cleanup things we don't care about.
3640 if (dev->node != NULL)
3641 dns_db_detachnode(dev->db, &dev->node);
3642 if (dev->db != NULL)
3643 dns_db_detach(&dev->db);
3646 * If this name is marked as dead, clean up, throwing away
3647 * potentially good data.
3649 if (NAME_DEAD(name)) {
3650 free_adbfetch(adb, &fetch);
3651 isc_event_free(&ev);
3653 want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
3655 UNLOCK(&adb->namelocks[bucket]);
3657 if (want_check_exit) {
3666 isc_stdtime_get(&now);
3669 * If we got a negative cache response, remember it.
3671 if (NCACHE_RESULT(dev->result)) {
3672 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3673 if (address_type == DNS_ADBFIND_INET) {
3674 DP(NCACHE_LEVEL, "adb fetch name %p: "
3675 "caching negative entry for A (ttl %u)",
3676 name, dev->rdataset->ttl);
3677 name->expire_v4 = ISC_MIN(name->expire_v4,
3678 dev->rdataset->ttl + now);
3679 if (dev->result == DNS_R_NCACHENXDOMAIN)
3680 name->fetch_err = FIND_ERR_NXDOMAIN;
3682 name->fetch_err = FIND_ERR_NXRRSET;
3683 inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
3685 DP(NCACHE_LEVEL, "adb fetch name %p: "
3686 "caching negative entry for AAAA (ttl %u)",
3687 name, dev->rdataset->ttl);
3688 name->expire_v6 = ISC_MIN(name->expire_v6,
3689 dev->rdataset->ttl + now);
3690 if (dev->result == DNS_R_NCACHENXDOMAIN)
3691 name->fetch6_err = FIND_ERR_NXDOMAIN;
3693 name->fetch6_err = FIND_ERR_NXRRSET;
3694 inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
3700 * Handle CNAME/DNAME.
3702 if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
3703 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3704 clean_target(adb, &name->target);
3705 name->expire_target = INT_MAX;
3706 result = set_target(adb, &name->name,
3707 dns_fixedname_name(&dev->foundname),
3710 if (result == ISC_R_SUCCESS) {
3712 "adb fetch name %p: caching alias target",
3714 name->expire_target = dev->rdataset->ttl + now;
3720 * Did we get back junk? If so, and there are no more fetches
3721 * sitting out there, tell all the finds about it.
3723 if (dev->result != ISC_R_SUCCESS) {
3724 char buf[DNS_NAME_FORMATSIZE];
3726 dns_name_format(&name->name, buf, sizeof(buf));
3727 DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
3728 buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
3729 dns_result_totext(dev->result));
3730 /* XXXMLG Don't pound on bad servers. */
3731 if (address_type == DNS_ADBFIND_INET) {
3732 name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
3733 name->fetch_err = FIND_ERR_FAILURE;
3734 inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
3736 name->expire_v6 = ISC_MIN(name->expire_v6, now + 300);
3737 name->fetch6_err = FIND_ERR_FAILURE;
3738 inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
3744 * We got something potentially useful.
3746 result = import_rdataset(name, &fetch->rdataset, now);
3749 if (result == ISC_R_SUCCESS) {
3750 ev_status = DNS_EVENT_ADBMOREADDRESSES;
3751 if (address_type == DNS_ADBFIND_INET)
3752 name->fetch_err = FIND_ERR_SUCCESS;
3754 name->fetch6_err = FIND_ERR_SUCCESS;
3758 free_adbfetch(adb, &fetch);
3759 isc_event_free(&ev);
3761 clean_finds_at_name(name, ev_status, address_type);
3763 UNLOCK(&adb->namelocks[bucket]);
3767 fetch_name(dns_adbname_t *adbname,
3768 isc_boolean_t start_at_zone,
3769 dns_rdatatype_t type)
3771 isc_result_t result;
3772 dns_adbfetch_t *fetch = NULL;
3774 dns_fixedname_t fixed;
3776 dns_rdataset_t rdataset;
3777 dns_rdataset_t *nameservers;
3778 unsigned int options;
3780 INSIST(DNS_ADBNAME_VALID(adbname));
3782 INSIST(DNS_ADB_VALID(adb));
3784 INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
3785 (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
3787 adbname->fetch_err = FIND_ERR_NOTFOUND;
3791 dns_rdataset_init(&rdataset);
3793 options = DNS_FETCHOPT_NOVALIDATE;
3794 if (start_at_zone) {
3796 "fetch_name: starting at zone for name %p",
3798 dns_fixedname_init(&fixed);
3799 name = dns_fixedname_name(&fixed);
3800 result = dns_view_findzonecut2(adb->view, &adbname->name, name,
3801 0, 0, ISC_TRUE, ISC_FALSE,
3803 if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
3805 nameservers = &rdataset;
3806 options |= DNS_FETCHOPT_UNSHARED;
3809 fetch = new_adbfetch(adb);
3810 if (fetch == NULL) {
3811 result = ISC_R_NOMEMORY;
3815 result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
3816 type, name, nameservers, NULL,
3817 options, adb->task, fetch_callback,
3818 adbname, &fetch->rdataset, NULL,
3820 if (result != ISC_R_SUCCESS)
3823 if (type == dns_rdatatype_a) {
3824 adbname->fetch_a = fetch;
3825 inc_stats(adb, dns_resstatscounter_gluefetchv4);
3827 adbname->fetch_aaaa = fetch;
3828 inc_stats(adb, dns_resstatscounter_gluefetchv6);
3830 fetch = NULL; /* Keep us from cleaning this up below. */
3834 free_adbfetch(adb, &fetch);
3835 if (dns_rdataset_isassociated(&rdataset))
3836 dns_rdataset_disassociate(&rdataset);
3842 * XXXMLG Needs to take a find argument and an address info, no zone or adb,
3843 * since these can be extracted from the find itself.
3846 dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname,
3847 dns_rdatatype_t qtype, isc_stdtime_t expire_time)
3849 dns_adblameinfo_t *li;
3851 isc_result_t result = ISC_R_SUCCESS;
3853 REQUIRE(DNS_ADB_VALID(adb));
3854 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3855 REQUIRE(qname != NULL);
3857 bucket = addr->entry->lock_bucket;
3858 LOCK(&adb->entrylocks[bucket]);
3859 li = ISC_LIST_HEAD(addr->entry->lameinfo);
3860 while (li != NULL &&
3861 (li->qtype != qtype || !dns_name_equal(qname, &li->qname)))
3862 li = ISC_LIST_NEXT(li, plink);
3864 if (expire_time > li->lame_timer)
3865 li->lame_timer = expire_time;
3868 li = new_adblameinfo(adb, qname, qtype);
3870 result = ISC_R_NOMEMORY;
3874 li->lame_timer = expire_time;
3876 ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink);
3878 UNLOCK(&adb->entrylocks[bucket]);
3884 dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3885 unsigned int rtt, unsigned int factor)
3888 unsigned int new_srtt;
3891 REQUIRE(DNS_ADB_VALID(adb));
3892 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3893 REQUIRE(factor <= 10);
3895 bucket = addr->entry->lock_bucket;
3896 LOCK(&adb->entrylocks[bucket]);
3898 if (factor == DNS_ADB_RTTADJAGE)
3899 new_srtt = addr->entry->srtt * 98 / 100;
3901 new_srtt = (addr->entry->srtt / 10 * factor)
3902 + (rtt / 10 * (10 - factor));
3904 addr->entry->srtt = new_srtt;
3905 addr->srtt = new_srtt;
3907 isc_stdtime_get(&now);
3908 addr->entry->expires = now + ADB_ENTRY_WINDOW;
3910 UNLOCK(&adb->entrylocks[bucket]);
3914 dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3915 unsigned int bits, unsigned int mask)
3919 REQUIRE(DNS_ADB_VALID(adb));
3920 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3922 bucket = addr->entry->lock_bucket;
3923 LOCK(&adb->entrylocks[bucket]);
3925 addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
3927 * Note that we do not update the other bits in addr->flags with
3928 * the most recent values from addr->entry->flags.
3930 addr->flags = (addr->flags & ~mask) | (bits & mask);
3932 UNLOCK(&adb->entrylocks[bucket]);
3936 dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
3937 dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
3940 dns_adbentry_t *entry;
3941 dns_adbaddrinfo_t *addr;
3942 isc_result_t result;
3945 REQUIRE(DNS_ADB_VALID(adb));
3946 REQUIRE(addrp != NULL && *addrp == NULL);
3950 result = ISC_R_SUCCESS;
3951 bucket = DNS_ADB_INVALIDBUCKET;
3952 entry = find_entry_and_lock(adb, sa, &bucket, now);
3953 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
3954 if (adb->entry_sd[bucket]) {
3955 result = ISC_R_SHUTTINGDOWN;
3958 if (entry == NULL) {
3960 * We don't know anything about this address.
3962 entry = new_adbentry(adb);
3963 if (entry == NULL) {
3964 result = ISC_R_NOMEMORY;
3967 entry->sockaddr = *sa;
3968 link_entry(adb, bucket, entry);
3969 DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
3971 DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
3973 port = isc_sockaddr_getport(sa);
3974 addr = new_adbaddrinfo(adb, entry, port);
3976 result = ISC_R_NOMEMORY;
3978 inc_entry_refcnt(adb, entry, ISC_FALSE);
3983 UNLOCK(&adb->entrylocks[bucket]);
3989 dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
3990 dns_adbaddrinfo_t *addr;
3991 dns_adbentry_t *entry;
3994 isc_boolean_t want_check_exit = ISC_FALSE;
3995 isc_boolean_t overmem;
3997 REQUIRE(DNS_ADB_VALID(adb));
3998 REQUIRE(addrp != NULL);
4000 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4001 entry = addr->entry;
4002 REQUIRE(DNS_ADBENTRY_VALID(entry));
4004 isc_stdtime_get(&now);
4007 overmem = isc_mem_isovermem(adb->mctx);
4009 bucket = addr->entry->lock_bucket;
4010 LOCK(&adb->entrylocks[bucket]);
4012 entry->expires = now + ADB_ENTRY_WINDOW;
4014 want_check_exit = dec_entry_refcnt(adb, overmem, entry, ISC_FALSE);
4016 UNLOCK(&adb->entrylocks[bucket]);
4019 free_adbaddrinfo(adb, &addr);
4021 if (want_check_exit) {
4029 dns_adb_flush(dns_adb_t *adb) {
4032 INSIST(DNS_ADB_VALID(adb));
4037 * Call our cleanup routines.
4039 for (i = 0; i < adb->nnames; i++)
4040 RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
4041 for (i = 0; i < adb->nentries; i++)
4042 RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
4044 #ifdef DUMP_ADB_AFTER_CLEANING
4045 dump_adb(adb, stdout, ISC_TRUE, INT_MAX);
4052 dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
4053 dns_adbname_t *adbname;
4054 dns_adbname_t *nextname;
4057 INSIST(DNS_ADB_VALID(adb));
4060 bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames;
4061 LOCK(&adb->namelocks[bucket]);
4062 adbname = ISC_LIST_HEAD(adb->names[bucket]);
4063 while (adbname != NULL) {
4064 nextname = ISC_LIST_NEXT(adbname, plink);
4065 if (!NAME_DEAD(adbname) &&
4066 dns_name_equal(name, &adbname->name)) {
4067 RUNTIME_CHECK(kill_name(&adbname,
4068 DNS_EVENT_ADBCANCELED) ==
4073 UNLOCK(&adb->namelocks[bucket]);
4078 water(void *arg, int mark) {
4080 * We're going to change the way to handle overmem condition: use
4081 * isc_mem_isovermem() instead of storing the state via this callback,
4082 * since the latter way tends to cause race conditions.
4083 * To minimize the change, and in case we re-enable the callback
4084 * approach, however, keep this function at the moment.
4087 dns_adb_t *adb = arg;
4088 isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
4090 REQUIRE(DNS_ADB_VALID(adb));
4092 DP(ISC_LOG_DEBUG(1),
4093 "adb reached %s water mark", overmem ? "high" : "low");
4097 dns_adb_setadbsize(dns_adb_t *adb, isc_uint32_t size) {
4098 isc_uint32_t hiwater;
4099 isc_uint32_t lowater;
4101 INSIST(DNS_ADB_VALID(adb));
4103 if (size != 0 && size < DNS_ADB_MINADBSIZE)
4104 size = DNS_ADB_MINADBSIZE;
4106 hiwater = size - (size >> 3); /* Approximately 7/8ths. */
4107 lowater = size - (size >> 2); /* Approximately 3/4ths. */
4109 if (size == 0 || hiwater == 0 || lowater == 0)
4110 isc_mem_setwater(adb->mctx, water, adb, 0, 0);
4112 isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);