2 * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: adb.c,v 1.264 2011/12/05 17:10:51 each Exp $ */
23 * In finds, if task == NULL, no events will be generated, and no events
24 * have been sent. If task != NULL but taskaction == NULL, an event has been
25 * posted but not yet freed. If neither are NULL, no event was posted.
33 #include <isc/mutexblock.h>
34 #include <isc/netaddr.h>
35 #include <isc/random.h>
36 #include <isc/stats.h>
37 #include <isc/string.h> /* Required for HP/UX (and others?) */
43 #include <dns/events.h>
45 #include <dns/rdata.h>
46 #include <dns/rdataset.h>
47 #include <dns/rdatastruct.h>
48 #include <dns/rdatatype.h>
49 #include <dns/resolver.h>
50 #include <dns/result.h>
51 #include <dns/stats.h>
53 #define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b')
54 #define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
55 #define DNS_ADBNAME_MAGIC ISC_MAGIC('a', 'd', 'b', 'N')
56 #define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
57 #define DNS_ADBNAMEHOOK_MAGIC ISC_MAGIC('a', 'd', 'N', 'H')
58 #define DNS_ADBNAMEHOOK_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
59 #define DNS_ADBLAMEINFO_MAGIC ISC_MAGIC('a', 'd', 'b', 'Z')
60 #define DNS_ADBLAMEINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBLAMEINFO_MAGIC)
61 #define DNS_ADBENTRY_MAGIC ISC_MAGIC('a', 'd', 'b', 'E')
62 #define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
63 #define DNS_ADBFETCH_MAGIC ISC_MAGIC('a', 'd', 'F', '4')
64 #define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
65 #define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6')
66 #define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
69 * For type 3 negative cache entries, we will remember that the address is
70 * broken for this long. XXXMLG This is also used for actual addresses, too.
71 * The intent is to keep us from constantly asking about A/AAAA records
72 * if the zone has extremely low TTLs.
74 #define ADB_CACHE_MINIMUM 10 /*%< seconds */
75 #define ADB_CACHE_MAXIMUM 86400 /*%< seconds (86400 = 24 hours) */
76 #define ADB_ENTRY_WINDOW 1800 /*%< seconds */
79 * The period in seconds after which an ADB name entry is regarded as stale
80 * and forced to be cleaned up.
81 * TODO: This should probably be configurable at run-time.
83 #ifndef ADB_STALE_MARGIN
84 #define ADB_STALE_MARGIN 1800
87 #define FREE_ITEMS 64 /*%< free count for memory pools */
88 #define FILL_COUNT 16 /*%< fill count for memory pools */
90 #define DNS_ADB_INVALIDBUCKET (-1) /*%< invalid bucket address */
92 #define DNS_ADB_MINADBSIZE (1024U*1024U) /*%< 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;
116 isc_interval_t tick_interval;
117 int next_cleanbucket;
119 unsigned int irefcnt;
120 unsigned int erefcnt;
123 isc_mempool_t *nmp; /*%< dns_adbname_t */
124 isc_mempool_t *nhmp; /*%< dns_adbnamehook_t */
125 isc_mempool_t *limp; /*%< dns_adblameinfo_t */
126 isc_mempool_t *emp; /*%< dns_adbentry_t */
127 isc_mempool_t *ahmp; /*%< dns_adbfind_t */
128 isc_mempool_t *aimp; /*%< dns_adbaddrinfo_t */
129 isc_mempool_t *afmp; /*%< dns_adbfetch_t */
132 * Bucketized locks and lists for names.
134 * XXXRTH Have a per-bucket structure that contains all of these?
137 isc_mutex_t namescntlock;
138 unsigned int namescnt;
139 dns_adbnamelist_t *names;
140 dns_adbnamelist_t *deadnames;
141 isc_mutex_t *namelocks;
142 isc_boolean_t *name_sd;
143 unsigned int *name_refcnt;
146 * Bucketized locks and lists for entries.
148 * XXXRTH Have a per-bucket structure that contains all of these?
150 unsigned int nentries;
151 isc_mutex_t entriescntlock;
152 unsigned int entriescnt;
153 dns_adbentrylist_t *entries;
154 dns_adbentrylist_t *deadentries;
155 isc_mutex_t *entrylocks;
156 isc_boolean_t *entry_sd; /*%< shutting down */
157 unsigned int *entry_refcnt;
160 isc_boolean_t cevent_sent;
161 isc_boolean_t shutting_down;
162 isc_eventlist_t whenshutdown;
163 isc_event_t growentries;
164 isc_boolean_t growentries_sent;
165 isc_event_t grownames;
166 isc_boolean_t grownames_sent;
170 * XXXMLG Document these structures.
173 /*% dns_adbname structure */
178 unsigned int partial_result;
182 isc_stdtime_t expire_target;
183 isc_stdtime_t expire_v4;
184 isc_stdtime_t expire_v6;
186 dns_adbnamehooklist_t v4;
187 dns_adbnamehooklist_t v6;
188 dns_adbfetch_t *fetch_a;
189 dns_adbfetch_t *fetch_aaaa;
190 unsigned int fetch_err;
191 unsigned int fetch6_err;
192 dns_adbfindlist_t finds;
193 /* for LRU-based management */
194 isc_stdtime_t last_used;
196 ISC_LINK(dns_adbname_t) plink;
199 /*% The adbfetch structure */
200 struct dns_adbfetch {
203 dns_rdataset_t rdataset;
207 * This is a small widget that dangles off a dns_adbname_t. It contains a
208 * pointer to the address information about this host, and a link to the next
209 * namehook that will contain the next address this host has.
211 struct dns_adbnamehook {
213 dns_adbentry_t *entry;
214 ISC_LINK(dns_adbnamehook_t) plink;
218 * This is a small widget that holds qname-specific information about an
219 * address. Currently limited to lameness, but could just as easily be
220 * extended to other types of information about zones.
222 struct dns_adblameinfo {
226 dns_rdatatype_t qtype;
227 isc_stdtime_t lame_timer;
229 ISC_LINK(dns_adblameinfo_t) plink;
233 * An address entry. It holds quite a bit of information about addresses,
234 * including edns state (in "flags"), rtt, and of course the address of
237 struct dns_adbentry {
245 isc_sockaddr_t sockaddr;
247 isc_stdtime_t expires;
249 * A nonzero 'expires' field indicates that the entry should
250 * persist until that time. This allows entries found
251 * using dns_adb_findaddrinfo() to persist for a limited time
252 * even though they are not necessarily associated with a
256 ISC_LIST(dns_adblameinfo_t) lameinfo;
257 ISC_LINK(dns_adbentry_t) plink;
262 * Internal functions (and prototypes).
264 static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
265 static inline void free_adbname(dns_adb_t *, dns_adbname_t **);
266 static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
268 static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
269 static inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *, dns_name_t *,
271 static inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **);
272 static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
273 static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
274 static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
275 static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
276 static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
278 static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
279 static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
280 static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
281 unsigned int, int *);
282 static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
283 isc_sockaddr_t *, int *,
285 static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t);
286 static void print_dns_name(FILE *, dns_name_t *);
287 static void print_namehook_list(FILE *, const char *legend,
288 dns_adbnamehooklist_t *list,
291 static void print_find_list(FILE *, dns_adbname_t *);
292 static void print_fetch_list(FILE *, dns_adbname_t *);
293 static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
294 static inline void inc_adb_irefcnt(dns_adb_t *);
295 static inline void inc_adb_erefcnt(dns_adb_t *);
296 static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
298 static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, isc_boolean_t,
299 dns_adbentry_t *, isc_boolean_t);
300 static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
301 static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
302 static void clean_target(dns_adb_t *, dns_name_t *);
303 static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
305 static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
306 static isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **,
308 static void cancel_fetches_at_name(dns_adbname_t *);
309 static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
311 static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
313 static inline void check_exit(dns_adb_t *);
314 static void destroy(dns_adb_t *);
315 static isc_boolean_t shutdown_names(dns_adb_t *);
316 static isc_boolean_t shutdown_entries(dns_adb_t *);
317 static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
318 static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *);
319 static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
320 static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
321 static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
322 static void water(void *, int);
323 static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t);
326 * MUST NOT overlap DNS_ADBFIND_* flags!
328 #define FIND_EVENT_SENT 0x40000000
329 #define FIND_EVENT_FREED 0x80000000
330 #define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0)
331 #define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0)
333 #define NAME_NEEDS_POKE 0x80000000
334 #define NAME_IS_DEAD 0x40000000
335 #define NAME_HINT_OK DNS_ADBFIND_HINTOK
336 #define NAME_GLUE_OK DNS_ADBFIND_GLUEOK
337 #define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE
338 #define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0)
339 #define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0)
340 #define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0)
341 #define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0)
344 * Private flag(s) for entries.
345 * MUST NOT overlap FCTX_ADDRINFO_xxx and DNS_FETCHOPT_NOEDNS0.
347 #define ENTRY_IS_DEAD 0x80000000
350 * To the name, address classes are all that really exist. If it has a
351 * V6 address it doesn't care if it came from a AAAA query.
353 #define NAME_HAS_V4(n) (!ISC_LIST_EMPTY((n)->v4))
354 #define NAME_HAS_V6(n) (!ISC_LIST_EMPTY((n)->v6))
355 #define NAME_HAS_ADDRS(n) (NAME_HAS_V4(n) || NAME_HAS_V6(n))
358 * Fetches are broken out into A and AAAA types. In some cases,
359 * however, it makes more sense to test for a particular class of fetches,
360 * like V4 or V6 above.
361 * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA
362 * are now equal to FETCH_V4 and FETCH_V6, respectively.
364 #define NAME_FETCH_A(n) ((n)->fetch_a != NULL)
365 #define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL)
366 #define NAME_FETCH_V4(n) (NAME_FETCH_A(n))
367 #define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n))
368 #define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
371 * Find options and tests to see if there are addresses on the list.
373 #define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
374 #define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
375 #define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
377 #define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \
379 #define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
380 #define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
381 #define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list))
382 #define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
385 * These are currently used on simple unsigned ints, so they are
386 * not really associated with any particular type.
388 #define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0)
389 #define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0)
391 #define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now))
394 * Find out if the flags on a name (nf) indicate if it is a hint or
395 * glue, and compare this to the appropriate bits set in o, to see if
398 #define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0))
399 #define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0))
400 #define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o))
401 #define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \
402 ((o) & DNS_ADBFIND_STARTATZONE))
404 #define ENTER_LEVEL ISC_LOG_DEBUG(50)
405 #define EXIT_LEVEL ENTER_LEVEL
406 #define CLEAN_LEVEL ISC_LOG_DEBUG(100)
407 #define DEF_LEVEL ISC_LOG_DEBUG(5)
408 #define NCACHE_LEVEL ISC_LOG_DEBUG(20)
410 #define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \
411 (r) == DNS_R_NCACHENXRRSET)
412 #define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \
413 (r) == DNS_R_NXRRSET)
414 #define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \
415 (r) == DNS_R_NCACHENXDOMAIN)
416 #define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \
417 (r) == DNS_R_NXRRSET || \
418 (r) == DNS_R_HINTNXRRSET)
421 * Error state rankings.
424 #define FIND_ERR_SUCCESS 0 /* highest rank */
425 #define FIND_ERR_CANCELED 1
426 #define FIND_ERR_FAILURE 2
427 #define FIND_ERR_NXDOMAIN 3
428 #define FIND_ERR_NXRRSET 4
429 #define FIND_ERR_UNEXPECTED 5
430 #define FIND_ERR_NOTFOUND 6
431 #define FIND_ERR_MAX 7
433 static const char *errnames[] = {
443 #define NEWERR(old, new) (ISC_MIN((old), (new)))
445 static isc_result_t find_err_map[FIND_ERR_MAX] = {
452 ISC_R_NOTFOUND /* not YET found */
456 DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
459 DP(int level, const char *format, ...) {
462 va_start(args, format);
463 isc_log_vwrite(dns_lctx,
464 DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
465 level, format, args);
470 * Increment resolver-related statistics counters.
473 inc_stats(dns_adb_t *adb, isc_statscounter_t counter) {
474 if (adb->view->resstats != NULL)
475 isc_stats_increment(adb->view->resstats, counter);
478 static inline dns_ttl_t
479 ttlclamp(dns_ttl_t ttl) {
480 if (ttl < ADB_CACHE_MINIMUM)
481 ttl = ADB_CACHE_MINIMUM;
482 if (ttl > ADB_CACHE_MAXIMUM)
483 ttl = ADB_CACHE_MAXIMUM;
489 * Hashing is most efficient if the number of buckets is prime.
490 * The sequence below is the closest previous primes to 2^n and
491 * 1.5 * 2^n, for values of n from 10 to 28. (The tables will
492 * no longer grow beyond 2^28 entries.)
494 static const unsigned nbuckets[] = { 1021, 1531, 2039, 3067, 4093, 6143,
495 8191, 12281, 16381, 24571, 32749,
496 49193, 65521, 98299, 131071, 199603,
497 262139, 393209, 524287, 768431, 1048573,
498 1572853, 2097143, 3145721, 4194301,
499 6291449, 8388593, 12582893, 16777213,
500 25165813, 33554393, 50331599, 67108859,
501 100663291, 134217689, 201326557,
505 grow_entries(isc_task_t *task, isc_event_t *ev) {
508 dns_adbentrylist_t *newdeadentries = NULL;
509 dns_adbentrylist_t *newentries = NULL;
510 isc_boolean_t *newentry_sd = NULL;
511 isc_mutex_t *newentrylocks = NULL;
513 unsigned int *newentry_refcnt = NULL;
514 unsigned int i, n, bucket;
517 INSIST(DNS_ADB_VALID(adb));
521 result = isc_task_beginexclusive(task);
522 if (result != ISC_R_SUCCESS)
526 while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i])
528 if (nbuckets[i] != 0)
533 DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n);
536 * Are we shutting down?
538 for (i = 0; i < adb->nentries; i++)
539 if (adb->entry_sd[i])
543 * Grab all the resources we need.
545 newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n);
546 newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n);
547 newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n);
548 newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n);
549 newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n);
550 if (newentries == NULL || newdeadentries == NULL ||
551 newentrylocks == NULL || newentry_sd == NULL ||
552 newentry_refcnt == NULL)
556 * Initialise the new resources.
558 result = isc_mutexblock_init(newentrylocks, n);
559 if (result != ISC_R_SUCCESS)
562 for (i = 0; i < n; i++) {
563 ISC_LIST_INIT(newentries[i]);
564 ISC_LIST_INIT(newdeadentries[i]);
565 newentry_sd[i] = ISC_FALSE;
566 newentry_refcnt[i] = 0;
571 * Move entries to new arrays.
573 for (i = 0; i < adb->nentries; i++) {
574 e = ISC_LIST_HEAD(adb->entries[i]);
576 ISC_LIST_UNLINK(adb->entries[i], e, plink);
577 bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
578 e->lock_bucket = bucket;
579 ISC_LIST_APPEND(newentries[bucket], e, plink);
580 INSIST(adb->entry_refcnt[i] > 0);
581 adb->entry_refcnt[i]--;
582 newentry_refcnt[bucket]++;
583 e = ISC_LIST_HEAD(adb->entries[i]);
585 e = ISC_LIST_HEAD(adb->deadentries[i]);
587 ISC_LIST_UNLINK(adb->deadentries[i], e, plink);
588 bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
589 e->lock_bucket = bucket;
590 ISC_LIST_APPEND(newdeadentries[bucket], e, plink);
591 INSIST(adb->entry_refcnt[i] > 0);
592 adb->entry_refcnt[i]--;
593 newentry_refcnt[bucket]++;
594 e = ISC_LIST_HEAD(adb->deadentries[i]);
596 INSIST(adb->entry_refcnt[i] == 0);
601 * Cleanup old resources.
603 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
604 isc_mem_put(adb->mctx, adb->entries,
605 sizeof(*adb->entries) * adb->nentries);
606 isc_mem_put(adb->mctx, adb->deadentries,
607 sizeof(*adb->deadentries) * adb->nentries);
608 isc_mem_put(adb->mctx, adb->entrylocks,
609 sizeof(*adb->entrylocks) * adb->nentries);
610 isc_mem_put(adb->mctx, adb->entry_sd,
611 sizeof(*adb->entry_sd) * adb->nentries);
612 isc_mem_put(adb->mctx, adb->entry_refcnt,
613 sizeof(*adb->entry_refcnt) * adb->nentries);
616 * Install new resources.
618 adb->entries = newentries;
619 adb->deadentries = newdeadentries;
620 adb->entrylocks = newentrylocks;
621 adb->entry_sd = newentry_sd;
622 adb->entry_refcnt = newentry_refcnt;
626 * Only on success do we set adb->growentries_sent to ISC_FALSE.
627 * This will prevent us being continuously being called on error.
629 adb->growentries_sent = ISC_FALSE;
633 if (newentries != NULL)
634 isc_mem_put(adb->mctx, newentries,
635 sizeof(*newentries) * n);
636 if (newdeadentries != NULL)
637 isc_mem_put(adb->mctx, newdeadentries,
638 sizeof(*newdeadentries) * n);
639 if (newentrylocks != NULL)
640 isc_mem_put(adb->mctx, newentrylocks,
641 sizeof(*newentrylocks) * n);
642 if (newentry_sd != NULL)
643 isc_mem_put(adb->mctx, newentry_sd,
644 sizeof(*newentry_sd) * n);
645 if (newentry_refcnt != NULL)
646 isc_mem_put(adb->mctx, newentry_refcnt,
647 sizeof(*newentry_refcnt) * n);
649 isc_task_endexclusive(task);
653 if (dec_adb_irefcnt(adb))
656 DP(ISC_LOG_INFO, "adb: grow_entries finished");
660 grow_names(isc_task_t *task, isc_event_t *ev) {
663 dns_adbnamelist_t *newdeadnames = NULL;
664 dns_adbnamelist_t *newnames = NULL;
665 isc_boolean_t *newname_sd = NULL;
666 isc_mutex_t *newnamelocks = NULL;
668 unsigned int *newname_refcnt = NULL;
669 unsigned int i, n, bucket;
672 INSIST(DNS_ADB_VALID(adb));
676 result = isc_task_beginexclusive(task);
677 if (result != ISC_R_SUCCESS)
681 while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i])
683 if (nbuckets[i] != 0)
688 DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n);
691 * Are we shutting down?
693 for (i = 0; i < adb->nnames; i++)
698 * Grab all the resources we need.
700 newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n);
701 newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n);
702 newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n);
703 newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n);
704 newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n);
705 if (newnames == NULL || newdeadnames == NULL ||
706 newnamelocks == NULL || newname_sd == NULL ||
707 newname_refcnt == NULL)
711 * Initialise the new resources.
713 result = isc_mutexblock_init(newnamelocks, n);
714 if (result != ISC_R_SUCCESS)
717 for (i = 0; i < n; i++) {
718 ISC_LIST_INIT(newnames[i]);
719 ISC_LIST_INIT(newdeadnames[i]);
720 newname_sd[i] = ISC_FALSE;
721 newname_refcnt[i] = 0;
726 * Move names to new arrays.
728 for (i = 0; i < adb->nnames; i++) {
729 name = ISC_LIST_HEAD(adb->names[i]);
730 while (name != NULL) {
731 ISC_LIST_UNLINK(adb->names[i], name, plink);
732 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
733 name->lock_bucket = bucket;
734 ISC_LIST_APPEND(newnames[bucket], name, plink);
735 INSIST(adb->name_refcnt[i] > 0);
736 adb->name_refcnt[i]--;
737 newname_refcnt[bucket]++;
738 name = ISC_LIST_HEAD(adb->names[i]);
740 name = ISC_LIST_HEAD(adb->deadnames[i]);
741 while (name != NULL) {
742 ISC_LIST_UNLINK(adb->deadnames[i], name, plink);
743 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
744 name->lock_bucket = bucket;
745 ISC_LIST_APPEND(newdeadnames[bucket], name, plink);
746 INSIST(adb->name_refcnt[i] > 0);
747 adb->name_refcnt[i]--;
748 newname_refcnt[bucket]++;
749 name = ISC_LIST_HEAD(adb->deadnames[i]);
751 INSIST(adb->name_refcnt[i] == 0);
756 * Cleanup old resources.
758 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
759 isc_mem_put(adb->mctx, adb->names,
760 sizeof(*adb->names) * adb->nnames);
761 isc_mem_put(adb->mctx, adb->deadnames,
762 sizeof(*adb->deadnames) * adb->nnames);
763 isc_mem_put(adb->mctx, adb->namelocks,
764 sizeof(*adb->namelocks) * adb->nnames);
765 isc_mem_put(adb->mctx, adb->name_sd,
766 sizeof(*adb->name_sd) * adb->nnames);
767 isc_mem_put(adb->mctx, adb->name_refcnt,
768 sizeof(*adb->name_refcnt) * adb->nnames);
771 * Install new resources.
773 adb->names = newnames;
774 adb->deadnames = newdeadnames;
775 adb->namelocks = newnamelocks;
776 adb->name_sd = newname_sd;
777 adb->name_refcnt = newname_refcnt;
781 * Only on success do we set adb->grownames_sent to ISC_FALSE.
782 * This will prevent us being continuously being called on error.
784 adb->grownames_sent = ISC_FALSE;
788 if (newnames != NULL)
789 isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n);
790 if (newdeadnames != NULL)
791 isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n);
792 if (newnamelocks != NULL)
793 isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n);
794 if (newname_sd != NULL)
795 isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n);
796 if (newname_refcnt != NULL)
797 isc_mem_put(adb->mctx, newname_refcnt,
798 sizeof(*newname_refcnt) * n);
800 isc_task_endexclusive(task);
804 if (dec_adb_irefcnt(adb))
807 DP(ISC_LOG_INFO, "adb: grow_names finished");
811 * Requires the adbname bucket be locked and that no entry buckets be locked.
813 * This code handles A and AAAA rdatasets only.
816 import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
821 dns_adbnamehook_t *nh;
822 dns_adbnamehook_t *anh;
823 dns_rdata_t rdata = DNS_RDATA_INIT;
825 struct in6_addr in6a;
826 isc_sockaddr_t sockaddr;
827 dns_adbentry_t *foundentry; /* NO CLEAN UP! */
829 isc_boolean_t new_addresses_added;
830 dns_rdatatype_t rdtype;
831 unsigned int findoptions;
832 dns_adbnamehooklist_t *hookhead;
834 INSIST(DNS_ADBNAME_VALID(adbname));
836 INSIST(DNS_ADB_VALID(adb));
838 rdtype = rdataset->type;
839 INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
840 if (rdtype == dns_rdatatype_a)
841 findoptions = DNS_ADBFIND_INET;
843 findoptions = DNS_ADBFIND_INET6;
845 addr_bucket = DNS_ADB_INVALIDBUCKET;
846 new_addresses_added = ISC_FALSE;
849 result = dns_rdataset_first(rdataset);
850 while (result == ISC_R_SUCCESS) {
851 dns_rdata_reset(&rdata);
852 dns_rdataset_current(rdataset, &rdata);
853 if (rdtype == dns_rdatatype_a) {
854 INSIST(rdata.length == 4);
855 memmove(&ina.s_addr, rdata.data, 4);
856 isc_sockaddr_fromin(&sockaddr, &ina, 0);
857 hookhead = &adbname->v4;
859 INSIST(rdata.length == 16);
860 memmove(in6a.s6_addr, rdata.data, 16);
861 isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
862 hookhead = &adbname->v6;
866 nh = new_adbnamehook(adb, NULL);
868 adbname->partial_result |= findoptions;
869 result = ISC_R_NOMEMORY;
873 foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket,
875 if (foundentry == NULL) {
876 dns_adbentry_t *entry;
878 entry = new_adbentry(adb);
880 adbname->partial_result |= findoptions;
881 result = ISC_R_NOMEMORY;
885 entry->sockaddr = sockaddr;
890 link_entry(adb, addr_bucket, entry);
892 for (anh = ISC_LIST_HEAD(*hookhead);
894 anh = ISC_LIST_NEXT(anh, plink))
895 if (anh->entry == foundentry)
898 foundentry->refcnt++;
899 nh->entry = foundentry;
901 free_adbnamehook(adb, &nh);
904 new_addresses_added = ISC_TRUE;
906 ISC_LIST_APPEND(*hookhead, nh, plink);
908 result = dns_rdataset_next(rdataset);
913 free_adbnamehook(adb, &nh);
915 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
916 UNLOCK(&adb->entrylocks[addr_bucket]);
918 if (rdataset->trust == dns_trust_glue ||
919 rdataset->trust == dns_trust_additional)
920 rdataset->ttl = ADB_CACHE_MINIMUM;
921 else if (rdataset->trust == dns_trust_ultimate)
924 rdataset->ttl = ttlclamp(rdataset->ttl);
926 if (rdtype == dns_rdatatype_a) {
927 DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
928 adbname->expire_v4, now + rdataset->ttl);
929 adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
930 now + rdataset->ttl);
932 DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
933 adbname->expire_v6, now + rdataset->ttl);
934 adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
935 now + rdataset->ttl);
938 if (new_addresses_added) {
940 * Lie a little here. This is more or less so code that cares
941 * can find out if any new information was added or not.
943 return (ISC_R_SUCCESS);
950 * Requires the name's bucket be locked.
953 kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
955 isc_boolean_t result = ISC_FALSE;
956 isc_boolean_t result4, result6;
963 INSIST(DNS_ADBNAME_VALID(name));
965 INSIST(DNS_ADB_VALID(adb));
967 DP(DEF_LEVEL, "killing name %p", name);
970 * If we're dead already, just check to see if we should go
973 if (NAME_DEAD(name) && !NAME_FETCH(name)) {
974 result = unlink_name(adb, name);
975 free_adbname(adb, &name);
977 result = dec_adb_irefcnt(adb);
982 * Clean up the name's various lists. These two are destructive
983 * in that they will always empty the list.
985 clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
986 result4 = clean_namehooks(adb, &name->v4);
987 result6 = clean_namehooks(adb, &name->v6);
988 clean_target(adb, &name->target);
989 result = ISC_TF(result4 || result6);
992 * If fetches are running, cancel them. If none are running, we can
993 * just kill the name here.
995 if (!NAME_FETCH(name)) {
996 INSIST(result == ISC_FALSE);
997 result = unlink_name(adb, name);
998 free_adbname(adb, &name);
1000 result = dec_adb_irefcnt(adb);
1002 cancel_fetches_at_name(name);
1003 if (!NAME_DEAD(name)) {
1004 bucket = name->lock_bucket;
1005 ISC_LIST_UNLINK(adb->names[bucket], name, plink);
1006 ISC_LIST_APPEND(adb->deadnames[bucket], name, plink);
1007 name->flags |= NAME_IS_DEAD;
1014 * Requires the name's bucket be locked and no entry buckets be locked.
1016 static isc_boolean_t
1017 check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
1019 isc_boolean_t result4 = ISC_FALSE;
1020 isc_boolean_t result6 = ISC_FALSE;
1022 INSIST(DNS_ADBNAME_VALID(name));
1024 INSIST(DNS_ADB_VALID(adb));
1027 * Check to see if we need to remove the v4 addresses
1029 if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) {
1030 if (NAME_HAS_V4(name)) {
1031 DP(DEF_LEVEL, "expiring v4 for name %p", name);
1032 result4 = clean_namehooks(adb, &name->v4);
1033 name->partial_result &= ~DNS_ADBFIND_INET;
1035 name->expire_v4 = INT_MAX;
1036 name->fetch_err = FIND_ERR_UNEXPECTED;
1040 * Check to see if we need to remove the v6 addresses
1042 if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) {
1043 if (NAME_HAS_V6(name)) {
1044 DP(DEF_LEVEL, "expiring v6 for name %p", name);
1045 result6 = clean_namehooks(adb, &name->v6);
1046 name->partial_result &= ~DNS_ADBFIND_INET6;
1048 name->expire_v6 = INT_MAX;
1049 name->fetch6_err = FIND_ERR_UNEXPECTED;
1053 * Check to see if we need to remove the alias target.
1055 if (EXPIRE_OK(name->expire_target, now)) {
1056 clean_target(adb, &name->target);
1057 name->expire_target = INT_MAX;
1059 return (ISC_TF(result4 || result6));
1063 * Requires the name's bucket be locked.
1066 link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
1067 INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
1069 ISC_LIST_PREPEND(adb->names[bucket], name, plink);
1070 name->lock_bucket = bucket;
1071 adb->name_refcnt[bucket]++;
1075 * Requires the name's bucket be locked.
1077 static inline isc_boolean_t
1078 unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
1080 isc_boolean_t result = ISC_FALSE;
1082 bucket = name->lock_bucket;
1083 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
1085 if (NAME_DEAD(name))
1086 ISC_LIST_UNLINK(adb->deadnames[bucket], name, plink);
1088 ISC_LIST_UNLINK(adb->names[bucket], name, plink);
1089 name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1090 INSIST(adb->name_refcnt[bucket] > 0);
1091 adb->name_refcnt[bucket]--;
1092 if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
1098 * Requires the entry's bucket be locked.
1101 link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
1105 if (isc_mem_isovermem(adb->mctx)) {
1106 for (i = 0; i < 2; i++) {
1107 e = ISC_LIST_TAIL(adb->entries[bucket]);
1110 if (e->refcnt == 0) {
1111 unlink_entry(adb, e);
1112 free_adbentry(adb, &e);
1115 INSIST((e->flags & ENTRY_IS_DEAD) == 0);
1116 e->flags |= ENTRY_IS_DEAD;
1117 ISC_LIST_UNLINK(adb->entries[bucket], e, plink);
1118 ISC_LIST_PREPEND(adb->deadentries[bucket], e, plink);
1122 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
1123 entry->lock_bucket = bucket;
1124 adb->entry_refcnt[bucket]++;
1128 * Requires the entry's bucket be locked.
1130 static inline isc_boolean_t
1131 unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
1133 isc_boolean_t result = ISC_FALSE;
1135 bucket = entry->lock_bucket;
1136 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
1138 if ((entry->flags & ENTRY_IS_DEAD) != 0)
1139 ISC_LIST_UNLINK(adb->deadentries[bucket], entry, plink);
1141 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
1142 entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1143 INSIST(adb->entry_refcnt[bucket] > 0);
1144 adb->entry_refcnt[bucket]--;
1145 if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
1151 violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
1152 if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
1160 * The ADB _MUST_ be locked before calling. Also, exit conditions must be
1161 * checked after calling this function.
1163 static isc_boolean_t
1164 shutdown_names(dns_adb_t *adb) {
1165 unsigned int bucket;
1166 isc_boolean_t result = ISC_FALSE;
1167 dns_adbname_t *name;
1168 dns_adbname_t *next_name;
1170 for (bucket = 0; bucket < adb->nnames; bucket++) {
1171 LOCK(&adb->namelocks[bucket]);
1172 adb->name_sd[bucket] = ISC_TRUE;
1174 name = ISC_LIST_HEAD(adb->names[bucket]);
1177 * This bucket has no names. We must decrement the
1178 * irefcnt ourselves, since it will not be
1179 * automatically triggered by a name being unlinked.
1181 INSIST(result == ISC_FALSE);
1182 result = dec_adb_irefcnt(adb);
1185 * Run through the list. For each name, clean up finds
1186 * found there, and cancel any fetches running. When
1187 * all the fetches are canceled, the name will destroy
1190 while (name != NULL) {
1191 next_name = ISC_LIST_NEXT(name, plink);
1192 INSIST(result == ISC_FALSE);
1193 result = kill_name(&name,
1194 DNS_EVENT_ADBSHUTDOWN);
1199 UNLOCK(&adb->namelocks[bucket]);
1205 * The ADB _MUST_ be locked before calling. Also, exit conditions must be
1206 * checked after calling this function.
1208 static isc_boolean_t
1209 shutdown_entries(dns_adb_t *adb) {
1210 unsigned int bucket;
1211 isc_boolean_t result = ISC_FALSE;
1212 dns_adbentry_t *entry;
1213 dns_adbentry_t *next_entry;
1215 for (bucket = 0; bucket < adb->nentries; bucket++) {
1216 LOCK(&adb->entrylocks[bucket]);
1217 adb->entry_sd[bucket] = ISC_TRUE;
1219 entry = ISC_LIST_HEAD(adb->entries[bucket]);
1220 if (adb->entry_refcnt[bucket] == 0) {
1222 * This bucket has no entries. We must decrement the
1223 * irefcnt ourselves, since it will not be
1224 * automatically triggered by an entry being unlinked.
1226 result = dec_adb_irefcnt(adb);
1229 * Run through the list. Cleanup any entries not
1230 * associated with names, and which are not in use.
1232 while (entry != NULL) {
1233 next_entry = ISC_LIST_NEXT(entry, plink);
1234 if (entry->refcnt == 0 &&
1235 entry->expires != 0) {
1236 result = unlink_entry(adb, entry);
1237 free_adbentry(adb, &entry);
1239 result = dec_adb_irefcnt(adb);
1245 UNLOCK(&adb->entrylocks[bucket]);
1251 * Name bucket must be locked
1254 cancel_fetches_at_name(dns_adbname_t *name) {
1255 if (NAME_FETCH_A(name))
1256 dns_resolver_cancelfetch(name->fetch_a->fetch);
1258 if (NAME_FETCH_AAAA(name))
1259 dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
1263 * Assumes the name bucket is locked.
1265 static isc_boolean_t
1266 clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
1267 dns_adbentry_t *entry;
1268 dns_adbnamehook_t *namehook;
1270 isc_boolean_t result = ISC_FALSE;
1271 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
1273 addr_bucket = DNS_ADB_INVALIDBUCKET;
1274 namehook = ISC_LIST_HEAD(*namehooks);
1275 while (namehook != NULL) {
1276 INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
1279 * Clean up the entry if needed.
1281 entry = namehook->entry;
1282 if (entry != NULL) {
1283 INSIST(DNS_ADBENTRY_VALID(entry));
1285 if (addr_bucket != entry->lock_bucket) {
1286 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1287 UNLOCK(&adb->entrylocks[addr_bucket]);
1288 addr_bucket = entry->lock_bucket;
1289 INSIST(addr_bucket != DNS_ADB_INVALIDBUCKET);
1290 LOCK(&adb->entrylocks[addr_bucket]);
1293 result = dec_entry_refcnt(adb, overmem, entry,
1300 namehook->entry = NULL;
1301 ISC_LIST_UNLINK(*namehooks, namehook, plink);
1302 free_adbnamehook(adb, &namehook);
1304 namehook = ISC_LIST_HEAD(*namehooks);
1307 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1308 UNLOCK(&adb->entrylocks[addr_bucket]);
1313 clean_target(dns_adb_t *adb, dns_name_t *target) {
1314 if (dns_name_countlabels(target) > 0) {
1315 dns_name_free(target, adb->mctx);
1316 dns_name_init(target, NULL);
1321 set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
1322 dns_rdataset_t *rdataset, dns_name_t *target)
1324 isc_result_t result;
1325 dns_namereln_t namereln;
1326 unsigned int nlabels;
1328 dns_rdata_t rdata = DNS_RDATA_INIT;
1329 dns_fixedname_t fixed1, fixed2;
1330 dns_name_t *prefix, *new_target;
1332 REQUIRE(dns_name_countlabels(target) == 0);
1334 if (rdataset->type == dns_rdatatype_cname) {
1335 dns_rdata_cname_t cname;
1338 * Copy the CNAME's target into the target name.
1340 result = dns_rdataset_first(rdataset);
1341 if (result != ISC_R_SUCCESS)
1343 dns_rdataset_current(rdataset, &rdata);
1344 result = dns_rdata_tostruct(&rdata, &cname, NULL);
1345 if (result != ISC_R_SUCCESS)
1347 result = dns_name_dup(&cname.cname, adb->mctx, target);
1348 dns_rdata_freestruct(&cname);
1349 if (result != ISC_R_SUCCESS)
1352 dns_rdata_dname_t dname;
1354 INSIST(rdataset->type == dns_rdatatype_dname);
1355 namereln = dns_name_fullcompare(name, fname, &order, &nlabels);
1356 INSIST(namereln == dns_namereln_subdomain);
1358 * Get the target name of the DNAME.
1360 result = dns_rdataset_first(rdataset);
1361 if (result != ISC_R_SUCCESS)
1363 dns_rdataset_current(rdataset, &rdata);
1364 result = dns_rdata_tostruct(&rdata, &dname, NULL);
1365 if (result != ISC_R_SUCCESS)
1368 * Construct the new target name.
1370 dns_fixedname_init(&fixed1);
1371 prefix = dns_fixedname_name(&fixed1);
1372 dns_fixedname_init(&fixed2);
1373 new_target = dns_fixedname_name(&fixed2);
1374 dns_name_split(name, nlabels, prefix, NULL);
1375 result = dns_name_concatenate(prefix, &dname.dname, new_target,
1377 dns_rdata_freestruct(&dname);
1378 if (result != ISC_R_SUCCESS)
1380 result = dns_name_dup(new_target, adb->mctx, target);
1381 if (result != ISC_R_SUCCESS)
1385 return (ISC_R_SUCCESS);
1389 * Assumes nothing is locked, since this is called by the client.
1392 event_free(isc_event_t *event) {
1393 dns_adbfind_t *find;
1395 INSIST(event != NULL);
1396 find = event->ev_destroy_arg;
1397 INSIST(DNS_ADBFIND_VALID(find));
1400 find->flags |= FIND_EVENT_FREED;
1401 event->ev_destroy_arg = NULL;
1402 UNLOCK(&find->lock);
1406 * Assumes the name bucket is locked.
1409 clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
1414 dns_adbfind_t *find;
1415 dns_adbfind_t *next_find;
1416 isc_boolean_t process;
1417 unsigned int wanted, notify;
1420 "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
1421 name, evtype, addrs);
1423 find = ISC_LIST_HEAD(name->finds);
1424 while (find != NULL) {
1426 next_find = ISC_LIST_NEXT(find, plink);
1428 process = ISC_FALSE;
1429 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1430 notify = wanted & addrs;
1433 case DNS_EVENT_ADBMOREADDRESSES:
1434 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES");
1435 if ((notify) != 0) {
1436 find->flags &= ~addrs;
1440 case DNS_EVENT_ADBNOMOREADDRESSES:
1441 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES");
1442 find->flags &= ~addrs;
1443 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1448 find->flags &= ~addrs;
1453 DP(DEF_LEVEL, "cfan: processing find %p", find);
1455 * Unlink the find from the name, letting the caller
1456 * call dns_adb_destroyfind() on it to clean it up
1459 ISC_LIST_UNLINK(name->finds, find, plink);
1460 find->adbname = NULL;
1461 find->name_bucket = DNS_ADB_INVALIDBUCKET;
1463 INSIST(!FIND_EVENTSENT(find));
1466 task = ev->ev_sender;
1467 ev->ev_sender = find;
1468 find->result_v4 = find_err_map[name->fetch_err];
1469 find->result_v6 = find_err_map[name->fetch6_err];
1470 ev->ev_type = evtype;
1471 ev->ev_destroy = event_free;
1472 ev->ev_destroy_arg = find;
1475 "sending event %p to task %p for find %p",
1478 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
1480 DP(DEF_LEVEL, "cfan: skipping find %p", find);
1483 UNLOCK(&find->lock);
1487 DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
1491 check_exit(dns_adb_t *adb) {
1494 * The caller must be holding the adb lock.
1496 if (adb->shutting_down) {
1498 * If there aren't any external references either, we're
1499 * done. Send the control event to initiate shutdown.
1501 INSIST(!adb->cevent_sent); /* Sanity check. */
1502 event = &adb->cevent;
1503 isc_task_send(adb->task, &event);
1504 adb->cevent_sent = ISC_TRUE;
1508 static inline isc_boolean_t
1509 dec_adb_irefcnt(dns_adb_t *adb) {
1512 isc_boolean_t result = ISC_FALSE;
1514 LOCK(&adb->reflock);
1516 INSIST(adb->irefcnt > 0);
1519 if (adb->irefcnt == 0) {
1520 event = ISC_LIST_HEAD(adb->whenshutdown);
1521 while (event != NULL) {
1522 ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
1523 etask = event->ev_sender;
1524 event->ev_sender = adb;
1525 isc_task_sendanddetach(&etask, &event);
1526 event = ISC_LIST_HEAD(adb->whenshutdown);
1530 if (adb->irefcnt == 0 && adb->erefcnt == 0)
1532 UNLOCK(&adb->reflock);
1537 inc_adb_irefcnt(dns_adb_t *adb) {
1538 LOCK(&adb->reflock);
1540 UNLOCK(&adb->reflock);
1544 inc_adb_erefcnt(dns_adb_t *adb) {
1545 LOCK(&adb->reflock);
1547 UNLOCK(&adb->reflock);
1551 inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
1554 bucket = entry->lock_bucket;
1557 LOCK(&adb->entrylocks[bucket]);
1562 UNLOCK(&adb->entrylocks[bucket]);
1565 static inline isc_boolean_t
1566 dec_entry_refcnt(dns_adb_t *adb, isc_boolean_t overmem, dns_adbentry_t *entry,
1570 isc_boolean_t destroy_entry;
1571 isc_boolean_t result = ISC_FALSE;
1573 bucket = entry->lock_bucket;
1576 LOCK(&adb->entrylocks[bucket]);
1578 INSIST(entry->refcnt > 0);
1581 destroy_entry = ISC_FALSE;
1582 if (entry->refcnt == 0 &&
1583 (adb->entry_sd[bucket] || entry->expires == 0 || overmem ||
1584 (entry->flags & ENTRY_IS_DEAD) != 0)) {
1585 destroy_entry = ISC_TRUE;
1586 result = unlink_entry(adb, entry);
1590 UNLOCK(&adb->entrylocks[bucket]);
1595 entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1597 free_adbentry(adb, &entry);
1599 result = dec_adb_irefcnt(adb);
1604 static inline dns_adbname_t *
1605 new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
1606 dns_adbname_t *name;
1608 name = isc_mempool_get(adb->nmp);
1612 dns_name_init(&name->name, NULL);
1613 if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
1614 isc_mempool_put(adb->nmp, name);
1617 dns_name_init(&name->target, NULL);
1618 name->magic = DNS_ADBNAME_MAGIC;
1620 name->partial_result = 0;
1622 name->expire_v4 = INT_MAX;
1623 name->expire_v6 = INT_MAX;
1624 name->expire_target = INT_MAX;
1626 name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1627 ISC_LIST_INIT(name->v4);
1628 ISC_LIST_INIT(name->v6);
1629 name->fetch_a = NULL;
1630 name->fetch_aaaa = NULL;
1631 name->fetch_err = FIND_ERR_UNEXPECTED;
1632 name->fetch6_err = FIND_ERR_UNEXPECTED;
1633 ISC_LIST_INIT(name->finds);
1634 ISC_LINK_INIT(name, plink);
1636 LOCK(&adb->namescntlock);
1638 if (!adb->grownames_sent && adb->excl != NULL &&
1639 adb->namescnt > (adb->nnames * 8))
1641 isc_event_t *event = &adb->grownames;
1642 inc_adb_irefcnt(adb);
1643 isc_task_send(adb->excl, &event);
1644 adb->grownames_sent = ISC_TRUE;
1646 UNLOCK(&adb->namescntlock);
1652 free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
1655 INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
1659 INSIST(!NAME_HAS_V4(n));
1660 INSIST(!NAME_HAS_V6(n));
1661 INSIST(!NAME_FETCH(n));
1662 INSIST(ISC_LIST_EMPTY(n->finds));
1663 INSIST(!ISC_LINK_LINKED(n, plink));
1664 INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
1665 INSIST(n->adb == adb);
1668 dns_name_free(&n->name, adb->mctx);
1670 isc_mempool_put(adb->nmp, n);
1671 LOCK(&adb->namescntlock);
1673 UNLOCK(&adb->namescntlock);
1676 static inline dns_adbnamehook_t *
1677 new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) {
1678 dns_adbnamehook_t *nh;
1680 nh = isc_mempool_get(adb->nhmp);
1684 nh->magic = DNS_ADBNAMEHOOK_MAGIC;
1686 ISC_LINK_INIT(nh, plink);
1692 free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) {
1693 dns_adbnamehook_t *nh;
1695 INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
1699 INSIST(nh->entry == NULL);
1700 INSIST(!ISC_LINK_LINKED(nh, plink));
1703 isc_mempool_put(adb->nhmp, nh);
1706 static inline dns_adblameinfo_t *
1707 new_adblameinfo(dns_adb_t *adb, dns_name_t *qname, dns_rdatatype_t qtype) {
1708 dns_adblameinfo_t *li;
1710 li = isc_mempool_get(adb->limp);
1714 dns_name_init(&li->qname, NULL);
1715 if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) {
1716 isc_mempool_put(adb->limp, li);
1719 li->magic = DNS_ADBLAMEINFO_MAGIC;
1722 ISC_LINK_INIT(li, plink);
1728 free_adblameinfo(dns_adb_t *adb, dns_adblameinfo_t **lameinfo) {
1729 dns_adblameinfo_t *li;
1731 INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo));
1735 INSIST(!ISC_LINK_LINKED(li, plink));
1737 dns_name_free(&li->qname, adb->mctx);
1741 isc_mempool_put(adb->limp, li);
1744 static inline dns_adbentry_t *
1745 new_adbentry(dns_adb_t *adb) {
1749 e = isc_mempool_get(adb->emp);
1753 e->magic = DNS_ADBENTRY_MAGIC;
1754 e->lock_bucket = DNS_ADB_INVALIDBUCKET;
1758 e->srtt = (r & 0x1f) + 1;
1760 ISC_LIST_INIT(e->lameinfo);
1761 ISC_LINK_INIT(e, plink);
1762 LOCK(&adb->entriescntlock);
1764 if (!adb->growentries_sent && adb->growentries_sent &&
1765 adb->entriescnt > (adb->nentries * 8))
1767 isc_event_t *event = &adb->growentries;
1768 inc_adb_irefcnt(adb);
1769 isc_task_send(adb->task, &event);
1770 adb->growentries_sent = ISC_TRUE;
1772 UNLOCK(&adb->entriescntlock);
1778 free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
1780 dns_adblameinfo_t *li;
1782 INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
1786 INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
1787 INSIST(e->refcnt == 0);
1788 INSIST(!ISC_LINK_LINKED(e, plink));
1792 li = ISC_LIST_HEAD(e->lameinfo);
1793 while (li != NULL) {
1794 ISC_LIST_UNLINK(e->lameinfo, li, plink);
1795 free_adblameinfo(adb, &li);
1796 li = ISC_LIST_HEAD(e->lameinfo);
1799 isc_mempool_put(adb->emp, e);
1800 LOCK(&adb->entriescntlock);
1802 UNLOCK(&adb->entriescntlock);
1805 static inline dns_adbfind_t *
1806 new_adbfind(dns_adb_t *adb) {
1808 isc_result_t result;
1810 h = isc_mempool_get(adb->ahmp);
1819 h->partial_result = 0;
1822 h->result_v4 = ISC_R_UNEXPECTED;
1823 h->result_v6 = ISC_R_UNEXPECTED;
1824 ISC_LINK_INIT(h, publink);
1825 ISC_LINK_INIT(h, plink);
1826 ISC_LIST_INIT(h->list);
1828 h->name_bucket = DNS_ADB_INVALIDBUCKET;
1833 result = isc_mutex_init(&h->lock);
1834 if (result != ISC_R_SUCCESS) {
1835 isc_mempool_put(adb->ahmp, h);
1839 ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
1842 inc_adb_irefcnt(adb);
1843 h->magic = DNS_ADBFIND_MAGIC;
1847 static inline dns_adbfetch_t *
1848 new_adbfetch(dns_adb_t *adb) {
1851 f = isc_mempool_get(adb->afmp);
1858 dns_rdataset_init(&f->rdataset);
1860 f->magic = DNS_ADBFETCH_MAGIC;
1866 free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) {
1869 INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
1875 if (dns_rdataset_isassociated(&f->rdataset))
1876 dns_rdataset_disassociate(&f->rdataset);
1878 isc_mempool_put(adb->afmp, f);
1881 static inline isc_boolean_t
1882 free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
1883 dns_adbfind_t *find;
1885 INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
1889 INSIST(!FIND_HAS_ADDRS(find));
1890 INSIST(!ISC_LINK_LINKED(find, publink));
1891 INSIST(!ISC_LINK_LINKED(find, plink));
1892 INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
1893 INSIST(find->adbname == NULL);
1897 DESTROYLOCK(&find->lock);
1898 isc_mempool_put(adb->ahmp, find);
1899 return (dec_adb_irefcnt(adb));
1903 * Copy bits from the entry into the newly allocated addrinfo. The entry
1904 * must be locked, and the reference count must be bumped up by one
1905 * if this function returns a valid pointer.
1907 static inline dns_adbaddrinfo_t *
1908 new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
1909 dns_adbaddrinfo_t *ai;
1911 ai = isc_mempool_get(adb->aimp);
1915 ai->magic = DNS_ADBADDRINFO_MAGIC;
1916 ai->sockaddr = entry->sockaddr;
1917 isc_sockaddr_setport(&ai->sockaddr, port);
1918 ai->srtt = entry->srtt;
1919 ai->flags = entry->flags;
1921 ISC_LINK_INIT(ai, publink);
1927 free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
1928 dns_adbaddrinfo_t *ai;
1930 INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
1934 INSIST(ai->entry == NULL);
1935 INSIST(!ISC_LINK_LINKED(ai, publink));
1939 isc_mempool_put(adb->aimp, ai);
1943 * Search for the name. NOTE: The bucket is kept locked on both
1944 * success and failure, so it must always be unlocked by the caller!
1946 * On the first call to this function, *bucketp must be set to
1947 * DNS_ADB_INVALIDBUCKET.
1949 static inline dns_adbname_t *
1950 find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
1951 unsigned int options, int *bucketp)
1953 dns_adbname_t *adbname;
1956 bucket = dns_name_fullhash(name, ISC_FALSE) % adb->nnames;
1958 if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1959 LOCK(&adb->namelocks[bucket]);
1961 } else if (*bucketp != bucket) {
1962 UNLOCK(&adb->namelocks[*bucketp]);
1963 LOCK(&adb->namelocks[bucket]);
1967 adbname = ISC_LIST_HEAD(adb->names[bucket]);
1968 while (adbname != NULL) {
1969 if (!NAME_DEAD(adbname)) {
1970 if (dns_name_equal(name, &adbname->name)
1971 && GLUEHINT_OK(adbname, options)
1972 && STARTATZONE_MATCHES(adbname, options))
1975 adbname = ISC_LIST_NEXT(adbname, plink);
1982 * Search for the address. NOTE: The bucket is kept locked on both
1983 * success and failure, so it must always be unlocked by the caller.
1985 * On the first call to this function, *bucketp must be set to
1986 * DNS_ADB_INVALIDBUCKET. This will cause a lock to occur. On
1987 * later calls (within the same "lock path") it can be left alone, so
1988 * if this function is called multiple times locking is only done if
1989 * the bucket changes.
1991 static inline dns_adbentry_t *
1992 find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp,
1995 dns_adbentry_t *entry, *entry_next;
1998 bucket = isc_sockaddr_hash(addr, ISC_TRUE) % adb->nentries;
2000 if (*bucketp == DNS_ADB_INVALIDBUCKET) {
2001 LOCK(&adb->entrylocks[bucket]);
2003 } else if (*bucketp != bucket) {
2004 UNLOCK(&adb->entrylocks[*bucketp]);
2005 LOCK(&adb->entrylocks[bucket]);
2009 /* Search the list, while cleaning up expired entries. */
2010 for (entry = ISC_LIST_HEAD(adb->entries[bucket]);
2012 entry = entry_next) {
2013 entry_next = ISC_LIST_NEXT(entry, plink);
2014 (void)check_expire_entry(adb, &entry, now);
2015 if (entry != NULL &&
2016 isc_sockaddr_equal(addr, &entry->sockaddr)) {
2017 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
2018 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
2027 * Entry bucket MUST be locked!
2029 static isc_boolean_t
2030 entry_is_lame(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *qname,
2031 dns_rdatatype_t qtype, isc_stdtime_t now)
2033 dns_adblameinfo_t *li, *next_li;
2034 isc_boolean_t is_bad;
2038 li = ISC_LIST_HEAD(entry->lameinfo);
2041 while (li != NULL) {
2042 next_li = ISC_LIST_NEXT(li, plink);
2045 * Has the entry expired?
2047 if (li->lame_timer < now) {
2048 ISC_LIST_UNLINK(entry->lameinfo, li, plink);
2049 free_adblameinfo(adb, &li);
2053 * Order tests from least to most expensive.
2055 * We do not break out of the main loop here as
2056 * we use the loop for house keeping.
2058 if (li != NULL && !is_bad && li->qtype == qtype &&
2059 dns_name_equal(qname, &li->qname))
2069 copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname,
2070 dns_rdatatype_t qtype, dns_adbname_t *name,
2073 dns_adbnamehook_t *namehook;
2074 dns_adbaddrinfo_t *addrinfo;
2075 dns_adbentry_t *entry;
2078 bucket = DNS_ADB_INVALIDBUCKET;
2080 if (find->options & DNS_ADBFIND_INET) {
2081 namehook = ISC_LIST_HEAD(name->v4);
2082 while (namehook != NULL) {
2083 entry = namehook->entry;
2084 bucket = entry->lock_bucket;
2085 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2086 LOCK(&adb->entrylocks[bucket]);
2088 if (!FIND_RETURNLAME(find)
2089 && entry_is_lame(adb, entry, qname, qtype, now)) {
2090 find->options |= DNS_ADBFIND_LAMEPRUNED;
2093 addrinfo = new_adbaddrinfo(adb, entry, find->port);
2094 if (addrinfo == NULL) {
2095 find->partial_result |= DNS_ADBFIND_INET;
2099 * Found a valid entry. Add it to the find's list.
2101 inc_entry_refcnt(adb, entry, ISC_FALSE);
2102 ISC_LIST_APPEND(find->list, addrinfo, publink);
2105 UNLOCK(&adb->entrylocks[bucket]);
2106 bucket = DNS_ADB_INVALIDBUCKET;
2107 namehook = ISC_LIST_NEXT(namehook, plink);
2111 if (find->options & DNS_ADBFIND_INET6) {
2112 namehook = ISC_LIST_HEAD(name->v6);
2113 while (namehook != NULL) {
2114 entry = namehook->entry;
2115 bucket = entry->lock_bucket;
2116 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2117 LOCK(&adb->entrylocks[bucket]);
2119 if (!FIND_RETURNLAME(find)
2120 && entry_is_lame(adb, entry, qname, qtype, now)) {
2121 find->options |= DNS_ADBFIND_LAMEPRUNED;
2124 addrinfo = new_adbaddrinfo(adb, entry, find->port);
2125 if (addrinfo == NULL) {
2126 find->partial_result |= DNS_ADBFIND_INET6;
2130 * Found a valid entry. Add it to the find's list.
2132 inc_entry_refcnt(adb, entry, ISC_FALSE);
2133 ISC_LIST_APPEND(find->list, addrinfo, publink);
2136 UNLOCK(&adb->entrylocks[bucket]);
2137 bucket = DNS_ADB_INVALIDBUCKET;
2138 namehook = ISC_LIST_NEXT(namehook, plink);
2143 if (bucket != DNS_ADB_INVALIDBUCKET)
2144 UNLOCK(&adb->entrylocks[bucket]);
2148 shutdown_task(isc_task_t *task, isc_event_t *ev) {
2154 INSIST(DNS_ADB_VALID(adb));
2156 isc_event_free(&ev);
2158 * Wait for lock around check_exit() call to be released.
2166 * Name bucket must be locked; adb may be locked; no other locks held.
2168 static isc_boolean_t
2169 check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
2170 dns_adbname_t *name;
2171 isc_boolean_t result = ISC_FALSE;
2173 INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
2176 if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
2178 if (NAME_FETCH(name))
2180 if (!EXPIRE_OK(name->expire_v4, now))
2182 if (!EXPIRE_OK(name->expire_v6, now))
2184 if (!EXPIRE_OK(name->expire_target, now))
2188 * The name is empty. Delete it.
2190 result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
2194 * Our caller, or one of its callers, will be calling check_exit() at
2195 * some point, so we don't need to do it here.
2201 * Examine the tail entry of the LRU list to see if it expires or is stale
2202 * (unused for some period); if so, the name entry will be freed. If the ADB
2203 * is in the overmem condition, the tail and the next to tail entries
2204 * will be unconditionally removed (unless they have an outstanding fetch).
2205 * We don't care about a race on 'overmem' at the risk of causing some
2206 * collateral damage or a small delay in starting cleanup, so we don't bother
2207 * to lock ADB (if it's not locked).
2209 * Name bucket must be locked; adb may be locked; no other locks held.
2212 check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2213 int victims, max_victims;
2214 dns_adbname_t *victim, *next_victim;
2215 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
2218 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2220 max_victims = overmem ? 2 : 1;
2223 * We limit the number of scanned entries to 10 (arbitrary choice)
2224 * in order to avoid examining too many entries when there are many
2225 * tail entries that have fetches (this should be rare, but could
2228 victim = ISC_LIST_TAIL(adb->names[bucket]);
2230 victim != NULL && victims < max_victims && scans < 10;
2231 victim = next_victim) {
2232 INSIST(!NAME_DEAD(victim));
2234 next_victim = ISC_LIST_PREV(victim, plink);
2235 (void)check_expire_name(&victim, now);
2236 if (victim == NULL) {
2241 if (!NAME_FETCH(victim) &&
2242 (overmem || victim->last_used + ADB_STALE_MARGIN <= now)) {
2243 RUNTIME_CHECK(kill_name(&victim,
2244 DNS_EVENT_ADBCANCELED) ==
2256 * Entry bucket must be locked; adb may be locked; no other locks held.
2258 static isc_boolean_t
2259 check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
2261 dns_adbentry_t *entry;
2262 isc_boolean_t result = ISC_FALSE;
2264 INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
2267 if (entry->refcnt != 0)
2270 if (entry->expires == 0 || entry->expires > now)
2274 * The entry is not in use. Delete it.
2276 DP(DEF_LEVEL, "killing entry %p", entry);
2277 INSIST(ISC_LINK_LINKED(entry, plink));
2278 result = unlink_entry(adb, entry);
2279 free_adbentry(adb, &entry);
2281 dec_adb_irefcnt(adb);
2287 * ADB must be locked, and no other locks held.
2289 static isc_boolean_t
2290 cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2291 dns_adbname_t *name;
2292 dns_adbname_t *next_name;
2293 isc_boolean_t result = ISC_FALSE;
2295 DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
2297 LOCK(&adb->namelocks[bucket]);
2298 if (adb->name_sd[bucket]) {
2299 UNLOCK(&adb->namelocks[bucket]);
2303 name = ISC_LIST_HEAD(adb->names[bucket]);
2304 while (name != NULL) {
2305 next_name = ISC_LIST_NEXT(name, plink);
2306 INSIST(result == ISC_FALSE);
2307 result = check_expire_namehooks(name, now);
2309 result = check_expire_name(&name, now);
2312 UNLOCK(&adb->namelocks[bucket]);
2317 * ADB must be locked, and no other locks held.
2319 static isc_boolean_t
2320 cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2321 dns_adbentry_t *entry, *next_entry;
2322 isc_boolean_t result = ISC_FALSE;
2324 DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
2326 LOCK(&adb->entrylocks[bucket]);
2327 entry = ISC_LIST_HEAD(adb->entries[bucket]);
2328 while (entry != NULL) {
2329 next_entry = ISC_LIST_NEXT(entry, plink);
2330 INSIST(result == ISC_FALSE);
2331 result = check_expire_entry(adb, &entry, now);
2334 UNLOCK(&adb->entrylocks[bucket]);
2339 destroy(dns_adb_t *adb) {
2342 isc_task_detach(&adb->task);
2343 if (adb->excl != NULL)
2344 isc_task_detach(&adb->excl);
2346 isc_mempool_destroy(&adb->nmp);
2347 isc_mempool_destroy(&adb->nhmp);
2348 isc_mempool_destroy(&adb->limp);
2349 isc_mempool_destroy(&adb->emp);
2350 isc_mempool_destroy(&adb->ahmp);
2351 isc_mempool_destroy(&adb->aimp);
2352 isc_mempool_destroy(&adb->afmp);
2354 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
2355 isc_mem_put(adb->mctx, adb->entries,
2356 sizeof(*adb->entries) * adb->nentries);
2357 isc_mem_put(adb->mctx, adb->deadentries,
2358 sizeof(*adb->deadentries) * adb->nentries);
2359 isc_mem_put(adb->mctx, adb->entrylocks,
2360 sizeof(*adb->entrylocks) * adb->nentries);
2361 isc_mem_put(adb->mctx, adb->entry_sd,
2362 sizeof(*adb->entry_sd) * adb->nentries);
2363 isc_mem_put(adb->mctx, adb->entry_refcnt,
2364 sizeof(*adb->entry_refcnt) * adb->nentries);
2366 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
2367 isc_mem_put(adb->mctx, adb->names,
2368 sizeof(*adb->names) * adb->nnames);
2369 isc_mem_put(adb->mctx, adb->deadnames,
2370 sizeof(*adb->deadnames) * adb->nnames);
2371 isc_mem_put(adb->mctx, adb->namelocks,
2372 sizeof(*adb->namelocks) * adb->nnames);
2373 isc_mem_put(adb->mctx, adb->name_sd,
2374 sizeof(*adb->name_sd) * adb->nnames);
2375 isc_mem_put(adb->mctx, adb->name_refcnt,
2376 sizeof(*adb->name_refcnt) * adb->nnames);
2378 DESTROYLOCK(&adb->reflock);
2379 DESTROYLOCK(&adb->lock);
2380 DESTROYLOCK(&adb->mplock);
2381 DESTROYLOCK(&adb->overmemlock);
2382 DESTROYLOCK(&adb->entriescntlock);
2383 DESTROYLOCK(&adb->namescntlock);
2385 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2394 dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
2395 isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
2398 isc_result_t result;
2401 REQUIRE(mem != NULL);
2402 REQUIRE(view != NULL);
2403 REQUIRE(timermgr != NULL); /* this is actually unused */
2404 REQUIRE(taskmgr != NULL);
2405 REQUIRE(newadb != NULL && *newadb == NULL);
2409 adb = isc_mem_get(mem, sizeof(dns_adb_t));
2411 return (ISC_R_NOMEMORY);
2414 * Initialize things here that cannot fail, and especially things
2415 * that must be NULL for the error return to work properly.
2431 adb->taskmgr = taskmgr;
2432 adb->next_cleanbucket = 0;
2433 ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
2434 DNS_EVENT_ADBCONTROL, shutdown_task, adb,
2436 adb->cevent_sent = ISC_FALSE;
2437 adb->shutting_down = ISC_FALSE;
2438 ISC_LIST_INIT(adb->whenshutdown);
2440 adb->nentries = nbuckets[0];
2441 adb->entriescnt = 0;
2442 adb->entries = NULL;
2443 adb->deadentries = NULL;
2444 adb->entry_sd = NULL;
2445 adb->entry_refcnt = NULL;
2446 adb->entrylocks = NULL;
2447 ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL,
2448 DNS_EVENT_ADBGROWENTRIES, grow_entries, adb,
2450 adb->growentries_sent = ISC_FALSE;
2452 adb->nnames = nbuckets[0];
2455 adb->deadnames = NULL;
2456 adb->name_sd = NULL;
2457 adb->name_refcnt = NULL;
2458 adb->namelocks = NULL;
2459 ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL,
2460 DNS_EVENT_ADBGROWNAMES, grow_names, adb,
2462 adb->grownames_sent = ISC_FALSE;
2464 result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl);
2465 if (result != ISC_R_SUCCESS) {
2466 DP(ISC_LOG_INFO, "adb: task-exclusive mode unavailable, "
2467 "intializing table sizes to %u\n",
2469 adb->nentries = nbuckets[11];
2470 adb->nnames= nbuckets[11];
2474 isc_mem_attach(mem, &adb->mctx);
2476 result = isc_mutex_init(&adb->lock);
2477 if (result != ISC_R_SUCCESS)
2480 result = isc_mutex_init(&adb->mplock);
2481 if (result != ISC_R_SUCCESS)
2484 result = isc_mutex_init(&adb->reflock);
2485 if (result != ISC_R_SUCCESS)
2488 result = isc_mutex_init(&adb->overmemlock);
2489 if (result != ISC_R_SUCCESS)
2492 result = isc_mutex_init(&adb->entriescntlock);
2493 if (result != ISC_R_SUCCESS)
2496 result = isc_mutex_init(&adb->namescntlock);
2497 if (result != ISC_R_SUCCESS)
2500 #define ALLOCENTRY(adb, el) \
2502 (adb)->el = isc_mem_get((adb)->mctx, \
2503 sizeof(*(adb)->el) * (adb)->nentries); \
2504 if ((adb)->el == NULL) { \
2505 result = ISC_R_NOMEMORY; \
2509 ALLOCENTRY(adb, entries);
2510 ALLOCENTRY(adb, deadentries);
2511 ALLOCENTRY(adb, entrylocks);
2512 ALLOCENTRY(adb, entry_sd);
2513 ALLOCENTRY(adb, entry_refcnt);
2516 #define ALLOCNAME(adb, el) \
2518 (adb)->el = isc_mem_get((adb)->mctx, \
2519 sizeof(*(adb)->el) * (adb)->nnames); \
2520 if ((adb)->el == NULL) { \
2521 result = ISC_R_NOMEMORY; \
2525 ALLOCNAME(adb, names);
2526 ALLOCNAME(adb, deadnames);
2527 ALLOCNAME(adb, namelocks);
2528 ALLOCNAME(adb, name_sd);
2529 ALLOCNAME(adb, name_refcnt);
2533 * Initialize the bucket locks for names and elements.
2534 * May as well initialize the list heads, too.
2536 result = isc_mutexblock_init(adb->namelocks, adb->nnames);
2537 if (result != ISC_R_SUCCESS)
2539 for (i = 0; i < adb->nnames; i++) {
2540 ISC_LIST_INIT(adb->names[i]);
2541 ISC_LIST_INIT(adb->deadnames[i]);
2542 adb->name_sd[i] = ISC_FALSE;
2543 adb->name_refcnt[i] = 0;
2546 for (i = 0; i < adb->nentries; i++) {
2547 ISC_LIST_INIT(adb->entries[i]);
2548 ISC_LIST_INIT(adb->deadentries[i]);
2549 adb->entry_sd[i] = ISC_FALSE;
2550 adb->entry_refcnt[i] = 0;
2553 result = isc_mutexblock_init(adb->entrylocks, adb->nentries);
2554 if (result != ISC_R_SUCCESS)
2560 #define MPINIT(t, p, n) do { \
2561 result = isc_mempool_create(mem, sizeof(t), &(p)); \
2562 if (result != ISC_R_SUCCESS) \
2564 isc_mempool_setfreemax((p), FREE_ITEMS); \
2565 isc_mempool_setfillcount((p), FILL_COUNT); \
2566 isc_mempool_setname((p), n); \
2567 isc_mempool_associatelock((p), &adb->mplock); \
2570 MPINIT(dns_adbname_t, adb->nmp, "adbname");
2571 MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
2572 MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo");
2573 MPINIT(dns_adbentry_t, adb->emp, "adbentry");
2574 MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
2575 MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
2576 MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
2581 * Allocate an internal task.
2583 result = isc_task_create(adb->taskmgr, 0, &adb->task);
2584 if (result != ISC_R_SUCCESS)
2587 isc_task_setname(adb->task, "ADB", adb);
2592 adb->magic = DNS_ADB_MAGIC;
2594 return (ISC_R_SUCCESS);
2597 if (adb->task != NULL)
2598 isc_task_detach(&adb->task);
2600 /* clean up entrylocks */
2601 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
2603 fail2: /* clean up namelocks */
2604 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
2606 fail1: /* clean up only allocated memory */
2607 if (adb->entries != NULL)
2608 isc_mem_put(adb->mctx, adb->entries,
2609 sizeof(*adb->entries) * adb->nentries);
2610 if (adb->deadentries != NULL)
2611 isc_mem_put(adb->mctx, adb->deadentries,
2612 sizeof(*adb->deadentries) * adb->nentries);
2613 if (adb->entrylocks != NULL)
2614 isc_mem_put(adb->mctx, adb->entrylocks,
2615 sizeof(*adb->entrylocks) * adb->nentries);
2616 if (adb->entry_sd != NULL)
2617 isc_mem_put(adb->mctx, adb->entry_sd,
2618 sizeof(*adb->entry_sd) * adb->nentries);
2619 if (adb->entry_refcnt != NULL)
2620 isc_mem_put(adb->mctx, adb->entry_refcnt,
2621 sizeof(*adb->entry_refcnt) * adb->nentries);
2622 if (adb->names != NULL)
2623 isc_mem_put(adb->mctx, adb->names,
2624 sizeof(*adb->names) * adb->nnames);
2625 if (adb->deadnames != NULL)
2626 isc_mem_put(adb->mctx, adb->deadnames,
2627 sizeof(*adb->deadnames) * adb->nnames);
2628 if (adb->namelocks != NULL)
2629 isc_mem_put(adb->mctx, adb->namelocks,
2630 sizeof(*adb->namelocks) * adb->nnames);
2631 if (adb->name_sd != NULL)
2632 isc_mem_put(adb->mctx, adb->name_sd,
2633 sizeof(*adb->name_sd) * adb->nnames);
2634 if (adb->name_refcnt != NULL)
2635 isc_mem_put(adb->mctx, adb->name_refcnt,
2636 sizeof(*adb->name_refcnt) * adb->nnames);
2637 if (adb->nmp != NULL)
2638 isc_mempool_destroy(&adb->nmp);
2639 if (adb->nhmp != NULL)
2640 isc_mempool_destroy(&adb->nhmp);
2641 if (adb->limp != NULL)
2642 isc_mempool_destroy(&adb->limp);
2643 if (adb->emp != NULL)
2644 isc_mempool_destroy(&adb->emp);
2645 if (adb->ahmp != NULL)
2646 isc_mempool_destroy(&adb->ahmp);
2647 if (adb->aimp != NULL)
2648 isc_mempool_destroy(&adb->aimp);
2649 if (adb->afmp != NULL)
2650 isc_mempool_destroy(&adb->afmp);
2652 DESTROYLOCK(&adb->namescntlock);
2654 DESTROYLOCK(&adb->entriescntlock);
2656 DESTROYLOCK(&adb->overmemlock);
2658 DESTROYLOCK(&adb->reflock);
2660 DESTROYLOCK(&adb->mplock);
2662 DESTROYLOCK(&adb->lock);
2664 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2670 dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
2672 REQUIRE(DNS_ADB_VALID(adb));
2673 REQUIRE(adbx != NULL && *adbx == NULL);
2675 inc_adb_erefcnt(adb);
2680 dns_adb_detach(dns_adb_t **adbx) {
2682 isc_boolean_t need_exit_check;
2684 REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
2689 INSIST(adb->erefcnt > 0);
2691 LOCK(&adb->reflock);
2693 need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
2694 UNLOCK(&adb->reflock);
2696 if (need_exit_check) {
2698 INSIST(adb->shutting_down);
2705 dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
2708 isc_boolean_t zeroirefcnt = ISC_FALSE;
2711 * Send '*eventp' to 'task' when 'adb' has shutdown.
2714 REQUIRE(DNS_ADB_VALID(adb));
2715 REQUIRE(eventp != NULL);
2722 LOCK(&adb->reflock);
2723 zeroirefcnt = ISC_TF(adb->irefcnt == 0);
2725 if (adb->shutting_down && zeroirefcnt &&
2726 isc_mempool_getallocated(adb->ahmp) == 0) {
2728 * We're already shutdown. Send the event.
2730 event->ev_sender = adb;
2731 isc_task_send(task, &event);
2734 isc_task_attach(task, &clone);
2735 event->ev_sender = clone;
2736 ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
2739 UNLOCK(&adb->reflock);
2744 dns_adb_shutdown(dns_adb_t *adb) {
2745 isc_boolean_t need_check_exit;
2753 if (!adb->shutting_down) {
2754 adb->shutting_down = ISC_TRUE;
2755 isc_mem_setwater(adb->mctx, water, adb, 0, 0);
2756 need_check_exit = shutdown_names(adb);
2757 if (!need_check_exit)
2758 need_check_exit = shutdown_entries(adb);
2759 if (need_check_exit)
2767 dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
2768 void *arg, dns_name_t *name, dns_name_t *qname,
2769 dns_rdatatype_t qtype, unsigned int options,
2770 isc_stdtime_t now, dns_name_t *target,
2771 in_port_t port, dns_adbfind_t **findp)
2773 dns_adbfind_t *find;
2774 dns_adbname_t *adbname;
2776 isc_boolean_t want_event, start_at_zone, alias, have_address;
2777 isc_result_t result;
2778 unsigned int wanted_addresses;
2779 unsigned int wanted_fetches;
2780 unsigned int query_pending;
2782 REQUIRE(DNS_ADB_VALID(adb));
2784 REQUIRE(action != NULL);
2786 REQUIRE(name != NULL);
2787 REQUIRE(qname != NULL);
2788 REQUIRE(findp != NULL && *findp == NULL);
2789 REQUIRE(target == NULL || dns_name_hasbuffer(target));
2791 REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
2793 result = ISC_R_UNEXPECTED;
2795 wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
2798 want_event = ISC_FALSE;
2799 start_at_zone = ISC_FALSE;
2803 isc_stdtime_get(&now);
2806 * XXXMLG Move this comment somewhere else!
2808 * Look up the name in our internal database.
2810 * Possibilities: Note that these are not always exclusive.
2812 * No name found. In this case, allocate a new name header and
2813 * an initial namehook or two. If any of these allocations
2814 * fail, clean up and return ISC_R_NOMEMORY.
2816 * Name found, valid addresses present. Allocate one addrinfo
2817 * structure for each found and append it to the linked list
2818 * of addresses for this header.
2820 * Name found, queries pending. In this case, if a task was
2821 * passed in, allocate a job id, attach it to the name's job
2822 * list and remember to tell the caller that there will be
2823 * more info coming later.
2826 find = new_adbfind(adb);
2828 return (ISC_R_NOMEMORY);
2833 * Remember what types of addresses we are interested in.
2835 find->options = options;
2836 find->flags |= wanted_addresses;
2837 if (FIND_WANTEVENT(find)) {
2838 REQUIRE(task != NULL);
2842 * Try to see if we know anything about this name at all.
2844 bucket = DNS_ADB_INVALIDBUCKET;
2845 adbname = find_name_and_lock(adb, name, find->options, &bucket);
2846 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2847 if (adb->name_sd[bucket]) {
2849 "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
2850 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2851 result = ISC_R_SHUTTINGDOWN;
2856 * Nothing found. Allocate a new adbname structure for this name.
2858 if (adbname == NULL) {
2860 * See if there is any stale name at the end of list, and purge
2863 check_stale_name(adb, bucket, now);
2865 adbname = new_adbname(adb, name);
2866 if (adbname == NULL) {
2867 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2868 result = ISC_R_NOMEMORY;
2871 link_name(adb, bucket, adbname);
2872 if (FIND_HINTOK(find))
2873 adbname->flags |= NAME_HINT_OK;
2874 if (FIND_GLUEOK(find))
2875 adbname->flags |= NAME_GLUE_OK;
2876 if (FIND_STARTATZONE(find))
2877 adbname->flags |= NAME_STARTATZONE;
2879 /* Move this name forward in the LRU list */
2880 ISC_LIST_UNLINK(adb->names[bucket], adbname, plink);
2881 ISC_LIST_PREPEND(adb->names[bucket], adbname, plink);
2883 adbname->last_used = now;
2886 * Expire old entries, etc.
2888 RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE);
2891 * Do we know that the name is an alias?
2893 if (!EXPIRE_OK(adbname->expire_target, now)) {
2898 "dns_adb_createfind: name %p is an alias (cached)",
2905 * Try to populate the name from the database and/or
2906 * start fetches. First try looking for an A record
2909 if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
2910 && WANT_INET(wanted_addresses)) {
2911 result = dbfind_name(adbname, now, dns_rdatatype_a);
2912 if (result == ISC_R_SUCCESS) {
2914 "dns_adb_createfind: found A for name %p in db",
2920 * Did we get a CNAME or DNAME?
2922 if (result == DNS_R_ALIAS) {
2924 "dns_adb_createfind: name %p is an alias",
2931 * If the name doesn't exist at all, don't bother with
2932 * v6 queries; they won't work.
2934 * If the name does exist but we didn't get our data, go
2935 * ahead and try AAAA.
2937 * If the result is neither of these, try a fetch for A.
2939 if (NXDOMAIN_RESULT(result))
2941 else if (NXRRSET_RESULT(result))
2944 if (!NAME_FETCH_V4(adbname))
2945 wanted_fetches |= DNS_ADBFIND_INET;
2949 if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
2950 && WANT_INET6(wanted_addresses)) {
2951 result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
2952 if (result == ISC_R_SUCCESS) {
2954 "dns_adb_createfind: found AAAA for name %p",
2960 * Did we get a CNAME or DNAME?
2962 if (result == DNS_R_ALIAS) {
2964 "dns_adb_createfind: name %p is an alias",
2971 * Listen to negative cache hints, and don't start
2974 if (NCACHE_RESULT(result) || AUTH_NX(result))
2977 if (!NAME_FETCH_V6(adbname))
2978 wanted_fetches |= DNS_ADBFIND_INET6;
2982 if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
2983 (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
2984 have_address = ISC_TRUE;
2986 have_address = ISC_FALSE;
2987 if (wanted_fetches != 0 &&
2988 ! (FIND_AVOIDFETCHES(find) && have_address)) {
2990 * We're missing at least one address family. Either the
2991 * caller hasn't instructed us to avoid fetches, or we don't
2992 * know anything about any of the address families that would
2993 * be acceptable so we have to launch fetches.
2996 if (FIND_STARTATZONE(find))
2997 start_at_zone = ISC_TRUE;
3002 if (WANT_INET(wanted_fetches) &&
3003 fetch_name(adbname, start_at_zone,
3004 dns_rdatatype_a) == ISC_R_SUCCESS) {
3006 "dns_adb_createfind: started A fetch for name %p",
3013 if (WANT_INET6(wanted_fetches) &&
3014 fetch_name(adbname, start_at_zone,
3015 dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
3017 "dns_adb_createfind: "
3018 "started AAAA fetch for name %p",
3024 * Run through the name and copy out the bits we are
3027 copy_namehook_lists(adb, find, qname, qtype, adbname, now);
3030 if (NAME_FETCH_V4(adbname))
3031 query_pending |= DNS_ADBFIND_INET;
3032 if (NAME_FETCH_V6(adbname))
3033 query_pending |= DNS_ADBFIND_INET6;
3036 * Attach to the name's query list if there are queries
3037 * already running, and we have been asked to.
3039 want_event = ISC_TRUE;
3040 if (!FIND_WANTEVENT(find))
3041 want_event = ISC_FALSE;
3042 if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
3043 want_event = ISC_FALSE;
3044 if ((wanted_addresses & query_pending) == 0)
3045 want_event = ISC_FALSE;
3047 want_event = ISC_FALSE;
3049 find->adbname = adbname;
3050 find->name_bucket = bucket;
3051 ISC_LIST_APPEND(adbname->finds, find, plink);
3052 find->query_pending = (query_pending & wanted_addresses);
3053 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
3054 find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
3055 DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
3059 * Remove the flag so the caller knows there will never
3060 * be an event, and set internal flags to fake that
3061 * the event was sent and freed, so dns_adb_destroyfind() will
3062 * do the right thing.
3064 find->query_pending = (query_pending & wanted_addresses);
3065 find->options &= ~DNS_ADBFIND_WANTEVENT;
3066 find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
3067 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
3070 find->partial_result |= (adbname->partial_result & wanted_addresses);
3072 if (target != NULL) {
3073 result = dns_name_copy(&adbname->target, target, NULL);
3074 if (result != ISC_R_SUCCESS)
3077 result = DNS_R_ALIAS;
3079 result = ISC_R_SUCCESS;
3082 * Copy out error flags from the name structure into the find.
3084 find->result_v4 = find_err_map[adbname->fetch_err];
3085 find->result_v6 = find_err_map[adbname->fetch6_err];
3094 INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
3096 isc_task_attach(task, &taskp);
3097 find->event.ev_sender = taskp;
3098 find->event.ev_action = action;
3099 find->event.ev_arg = arg;
3103 UNLOCK(&adb->namelocks[bucket]);
3109 dns_adb_destroyfind(dns_adbfind_t **findp) {
3110 dns_adbfind_t *find;
3111 dns_adbentry_t *entry;
3112 dns_adbaddrinfo_t *ai;
3115 isc_boolean_t overmem;
3117 REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
3123 DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
3126 REQUIRE(DNS_ADB_VALID(adb));
3128 REQUIRE(FIND_EVENTFREED(find));
3130 bucket = find->name_bucket;
3131 INSIST(bucket == DNS_ADB_INVALIDBUCKET);
3133 UNLOCK(&find->lock);
3136 * The find doesn't exist on any list, and nothing is locked.
3137 * Return the find to the memory pool, and decrement the adb's
3140 overmem = isc_mem_isovermem(adb->mctx);
3141 ai = ISC_LIST_HEAD(find->list);
3142 while (ai != NULL) {
3143 ISC_LIST_UNLINK(find->list, ai, publink);
3146 INSIST(DNS_ADBENTRY_VALID(entry));
3147 RUNTIME_CHECK(dec_entry_refcnt(adb, overmem, entry, ISC_TRUE) ==
3149 free_adbaddrinfo(adb, &ai);
3150 ai = ISC_LIST_HEAD(find->list);
3154 * WARNING: The find is freed with the adb locked. This is done
3155 * to avoid a race condition where we free the find, some other
3156 * thread tests to see if it should be destroyed, detects it should
3157 * be, destroys it, and then we try to lock it for our check, but the
3158 * lock is destroyed.
3161 if (free_adbfind(adb, &find))
3167 dns_adb_cancelfind(dns_adbfind_t *find) {
3176 DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
3179 REQUIRE(DNS_ADB_VALID(adb));
3181 REQUIRE(!FIND_EVENTFREED(find));
3182 REQUIRE(FIND_WANTEVENT(find));
3184 bucket = find->name_bucket;
3185 if (bucket == DNS_ADB_INVALIDBUCKET)
3189 * We need to get the adbname's lock to unlink the find.
3191 unlock_bucket = bucket;
3192 violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
3193 bucket = find->name_bucket;
3194 if (bucket != DNS_ADB_INVALIDBUCKET) {
3195 ISC_LIST_UNLINK(find->adbname->finds, find, plink);
3196 find->adbname = NULL;
3197 find->name_bucket = DNS_ADB_INVALIDBUCKET;
3199 UNLOCK(&adb->namelocks[unlock_bucket]);
3200 bucket = DNS_ADB_INVALIDBUCKET;
3205 if (!FIND_EVENTSENT(find)) {
3207 task = ev->ev_sender;
3208 ev->ev_sender = find;
3209 ev->ev_type = DNS_EVENT_ADBCANCELED;
3210 ev->ev_destroy = event_free;
3211 ev->ev_destroy_arg = find;
3212 find->result_v4 = ISC_R_CANCELED;
3213 find->result_v6 = ISC_R_CANCELED;
3215 DP(DEF_LEVEL, "sending event %p to task %p for find %p",
3218 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
3221 UNLOCK(&find->lock);
3225 dns_adb_dump(dns_adb_t *adb, FILE *f) {
3229 REQUIRE(DNS_ADB_VALID(adb));
3233 * Lock the adb itself, lock all the name buckets, then lock all
3234 * the entry buckets. This should put the adb into a state where
3235 * nothing can change, so we can iterate through everything and
3236 * print at our leisure.
3240 isc_stdtime_get(&now);
3242 for (i = 0; i < adb->nnames; i++)
3243 RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE);
3244 for (i = 0; i < adb->nentries; i++)
3245 RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE);
3247 dump_adb(adb, f, ISC_FALSE, now);
3252 dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
3253 if (value == INT_MAX)
3255 fprintf(f, " [%s TTL %d]", legend, value - now);
3259 dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
3261 dns_adbname_t *name;
3262 dns_adbentry_t *entry;
3264 fprintf(f, ";\n; Address database dump\n;\n");
3266 fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
3267 adb, adb->erefcnt, adb->irefcnt,
3268 isc_mempool_getallocated(adb->nhmp));
3270 for (i = 0; i < adb->nnames; i++)
3271 LOCK(&adb->namelocks[i]);
3272 for (i = 0; i < adb->nentries; i++)
3273 LOCK(&adb->entrylocks[i]);
3278 for (i = 0; i < adb->nnames; i++) {
3279 name = ISC_LIST_HEAD(adb->names[i]);
3283 fprintf(f, "; bucket %d\n", i);
3286 name = ISC_LIST_NEXT(name, plink))
3289 fprintf(f, "; name %p (flags %08x)\n",
3293 print_dns_name(f, &name->name);
3294 if (dns_name_countlabels(&name->target) > 0) {
3295 fprintf(f, " alias ");
3296 print_dns_name(f, &name->target);
3299 dump_ttl(f, "v4", name->expire_v4, now);
3300 dump_ttl(f, "v6", name->expire_v6, now);
3301 dump_ttl(f, "target", name->expire_target, now);
3303 fprintf(f, " [v4 %s] [v6 %s]",
3304 errnames[name->fetch_err],
3305 errnames[name->fetch6_err]);
3309 print_namehook_list(f, "v4", &name->v4, debug, now);
3310 print_namehook_list(f, "v6", &name->v6, debug, now);
3313 print_fetch_list(f, name);
3315 print_find_list(f, name);
3320 fprintf(f, ";\n; Unassociated entries\n;\n");
3322 for (i = 0; i < adb->nentries; i++) {
3323 entry = ISC_LIST_HEAD(adb->entries[i]);
3324 while (entry != NULL) {
3325 if (entry->refcnt == 0)
3326 dump_entry(f, entry, debug, now);
3327 entry = ISC_LIST_NEXT(entry, plink);
3334 for (i = 0; i < adb->nentries; i++)
3335 UNLOCK(&adb->entrylocks[i]);
3336 for (i = 0; i < adb->nnames; i++)
3337 UNLOCK(&adb->namelocks[i]);
3341 dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug,
3344 char addrbuf[ISC_NETADDR_FORMATSIZE];
3345 char typebuf[DNS_RDATATYPE_FORMATSIZE];
3346 isc_netaddr_t netaddr;
3347 dns_adblameinfo_t *li;
3349 isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
3350 isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
3353 fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
3355 fprintf(f, ";\t%s [srtt %u] [flags %08x]",
3356 addrbuf, entry->srtt, entry->flags);
3357 if (entry->expires != 0)
3358 fprintf(f, " [ttl %d]", entry->expires - now);
3360 for (li = ISC_LIST_HEAD(entry->lameinfo);
3362 li = ISC_LIST_NEXT(li, plink)) {
3363 fprintf(f, ";\t\t");
3364 print_dns_name(f, &li->qname);
3365 dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf));
3366 fprintf(f, " %s [lame TTL %d]\n", typebuf,
3367 li->lame_timer - now);
3372 dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
3375 dns_adbaddrinfo_t *ai;
3379 * Not used currently, in the API Just In Case we
3380 * want to dump out the name and/or entries too.
3385 fprintf(f, ";Find %p\n", find);
3386 fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
3387 find->query_pending, find->partial_result,
3388 find->options, find->flags);
3389 fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
3390 find->name_bucket, find->adbname, find->event.ev_sender);
3392 ai = ISC_LIST_HEAD(find->list);
3394 fprintf(f, "\tAddresses:\n");
3395 while (ai != NULL) {
3397 switch (sa->type.sa.sa_family) {
3399 tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
3403 tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
3411 tmpp = "BadAddress";
3413 fprintf(f, "\t\tentry %p, flags %08x"
3414 " srtt %u addr %s\n",
3415 ai->entry, ai->flags, ai->srtt, tmpp);
3417 ai = ISC_LIST_NEXT(ai, publink);
3420 UNLOCK(&find->lock);
3424 print_dns_name(FILE *f, dns_name_t *name) {
3425 char buf[DNS_NAME_FORMATSIZE];
3429 dns_name_format(name, buf, sizeof(buf));
3430 fprintf(f, "%s", buf);
3434 print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list,
3435 isc_boolean_t debug, isc_stdtime_t now)
3437 dns_adbnamehook_t *nh;
3439 for (nh = ISC_LIST_HEAD(*list);
3441 nh = ISC_LIST_NEXT(nh, plink))
3444 fprintf(f, ";\tHook(%s) %p\n", legend, nh);
3445 dump_entry(f, nh->entry, debug, now);
3450 print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) {
3451 fprintf(f, "\t\tFetch(%s): %p -> { fetch %p }\n",
3452 type, ft, ft->fetch);
3456 print_fetch_list(FILE *f, dns_adbname_t *n) {
3457 if (NAME_FETCH_A(n))
3458 print_fetch(f, n->fetch_a, "A");
3459 if (NAME_FETCH_AAAA(n))
3460 print_fetch(f, n->fetch_aaaa, "AAAA");
3464 print_find_list(FILE *f, dns_adbname_t *name) {
3465 dns_adbfind_t *find;
3467 find = ISC_LIST_HEAD(name->finds);
3468 while (find != NULL) {
3469 dns_adb_dumpfind(find, f);
3470 find = ISC_LIST_NEXT(find, plink);
3475 dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype)
3477 isc_result_t result;
3478 dns_rdataset_t rdataset;
3480 dns_fixedname_t foundname;
3483 INSIST(DNS_ADBNAME_VALID(adbname));
3485 INSIST(DNS_ADB_VALID(adb));
3486 INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
3488 dns_fixedname_init(&foundname);
3489 fname = dns_fixedname_name(&foundname);
3490 dns_rdataset_init(&rdataset);
3492 if (rdtype == dns_rdatatype_a)
3493 adbname->fetch_err = FIND_ERR_UNEXPECTED;
3495 adbname->fetch6_err = FIND_ERR_UNEXPECTED;
3498 * We need to specify whether to search static-stub zones (if
3499 * configured) depending on whether this is a "start at zone" lookup,
3500 * i.e., whether it's a "bailiwick" glue. If it's bailiwick (in which
3501 * case NAME_STARTATZONE is set) we need to stop the search at any
3502 * matching static-stub zone without looking into the cache to honor
3503 * the configuration on which server we should send queries to.
3505 result = dns_view_find2(adb->view, &adbname->name, rdtype, now,
3506 NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0,
3507 ISC_TF(NAME_HINTOK(adbname)),
3508 (adbname->flags & NAME_STARTATZONE) != 0 ?
3509 ISC_TRUE : ISC_FALSE,
3510 NULL, NULL, fname, &rdataset, NULL);
3512 /* XXXVIX this switch statement is too sparse to gen a jump table. */
3518 * Found in the database. Even if we can't copy out
3519 * any information, return success, or else a fetch
3520 * will be made, which will only make things worse.
3522 if (rdtype == dns_rdatatype_a)
3523 adbname->fetch_err = FIND_ERR_SUCCESS;
3525 adbname->fetch6_err = FIND_ERR_SUCCESS;
3526 result = import_rdataset(adbname, &rdataset, now);
3528 case DNS_R_NXDOMAIN:
3531 * We're authoritative and the data doesn't exist.
3532 * Make up a negative cache entry so we don't ask again
3535 * XXXRTH What time should we use? I'm putting in 30 seconds
3538 if (rdtype == dns_rdatatype_a) {
3539 adbname->expire_v4 = now + 30;
3541 "adb name %p: Caching auth negative entry for A",
3543 if (result == DNS_R_NXDOMAIN)
3544 adbname->fetch_err = FIND_ERR_NXDOMAIN;
3546 adbname->fetch_err = FIND_ERR_NXRRSET;
3549 "adb name %p: Caching auth negative entry for AAAA",
3551 adbname->expire_v6 = now + 30;
3552 if (result == DNS_R_NXDOMAIN)
3553 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3555 adbname->fetch6_err = FIND_ERR_NXRRSET;
3558 case DNS_R_NCACHENXDOMAIN:
3559 case DNS_R_NCACHENXRRSET:
3561 * We found a negative cache entry. Pull the TTL from it
3562 * so we won't ask again for a while.
3564 rdataset.ttl = ttlclamp(rdataset.ttl);
3565 if (rdtype == dns_rdatatype_a) {
3566 adbname->expire_v4 = rdataset.ttl + now;
3567 if (result == DNS_R_NCACHENXDOMAIN)
3568 adbname->fetch_err = FIND_ERR_NXDOMAIN;
3570 adbname->fetch_err = FIND_ERR_NXRRSET;
3572 "adb name %p: Caching negative entry for A (ttl %u)",
3573 adbname, rdataset.ttl);
3576 "adb name %p: Caching negative entry for AAAA (ttl %u)",
3577 adbname, rdataset.ttl);
3578 adbname->expire_v6 = rdataset.ttl + now;
3579 if (result == DNS_R_NCACHENXDOMAIN)
3580 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3582 adbname->fetch6_err = FIND_ERR_NXRRSET;
3588 * Clear the hint and glue flags, so this will match
3591 adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
3593 rdataset.ttl = ttlclamp(rdataset.ttl);
3594 clean_target(adb, &adbname->target);
3595 adbname->expire_target = INT_MAX;
3596 result = set_target(adb, &adbname->name, fname, &rdataset,
3598 if (result == ISC_R_SUCCESS) {
3599 result = DNS_R_ALIAS;
3601 "adb name %p: caching alias target",
3603 adbname->expire_target = rdataset.ttl + now;
3605 if (rdtype == dns_rdatatype_a)
3606 adbname->fetch_err = FIND_ERR_SUCCESS;
3608 adbname->fetch6_err = FIND_ERR_SUCCESS;
3612 if (dns_rdataset_isassociated(&rdataset))
3613 dns_rdataset_disassociate(&rdataset);
3619 fetch_callback(isc_task_t *task, isc_event_t *ev) {
3620 dns_fetchevent_t *dev;
3621 dns_adbname_t *name;
3623 dns_adbfetch_t *fetch;
3625 isc_eventtype_t ev_status;
3627 isc_result_t result;
3628 unsigned int address_type;
3629 isc_boolean_t want_check_exit = ISC_FALSE;
3633 INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
3634 dev = (dns_fetchevent_t *)ev;
3636 INSIST(DNS_ADBNAME_VALID(name));
3638 INSIST(DNS_ADB_VALID(adb));
3640 bucket = name->lock_bucket;
3641 LOCK(&adb->namelocks[bucket]);
3643 INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
3645 if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
3646 address_type = DNS_ADBFIND_INET;
3647 fetch = name->fetch_a;
3648 name->fetch_a = NULL;
3649 } else if (NAME_FETCH_AAAA(name)
3650 && (name->fetch_aaaa->fetch == dev->fetch)) {
3651 address_type = DNS_ADBFIND_INET6;
3652 fetch = name->fetch_aaaa;
3653 name->fetch_aaaa = NULL;
3657 INSIST(address_type != 0 && fetch != NULL);
3659 dns_resolver_destroyfetch(&fetch->fetch);
3662 ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
3665 * Cleanup things we don't care about.
3667 if (dev->node != NULL)
3668 dns_db_detachnode(dev->db, &dev->node);
3669 if (dev->db != NULL)
3670 dns_db_detach(&dev->db);
3673 * If this name is marked as dead, clean up, throwing away
3674 * potentially good data.
3676 if (NAME_DEAD(name)) {
3677 free_adbfetch(adb, &fetch);
3678 isc_event_free(&ev);
3680 want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
3682 UNLOCK(&adb->namelocks[bucket]);
3684 if (want_check_exit) {
3693 isc_stdtime_get(&now);
3696 * If we got a negative cache response, remember it.
3698 if (NCACHE_RESULT(dev->result)) {
3699 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3700 if (address_type == DNS_ADBFIND_INET) {
3701 DP(NCACHE_LEVEL, "adb fetch name %p: "
3702 "caching negative entry for A (ttl %u)",
3703 name, dev->rdataset->ttl);
3704 name->expire_v4 = ISC_MIN(name->expire_v4,
3705 dev->rdataset->ttl + now);
3706 if (dev->result == DNS_R_NCACHENXDOMAIN)
3707 name->fetch_err = FIND_ERR_NXDOMAIN;
3709 name->fetch_err = FIND_ERR_NXRRSET;
3710 inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
3712 DP(NCACHE_LEVEL, "adb fetch name %p: "
3713 "caching negative entry for AAAA (ttl %u)",
3714 name, dev->rdataset->ttl);
3715 name->expire_v6 = ISC_MIN(name->expire_v6,
3716 dev->rdataset->ttl + now);
3717 if (dev->result == DNS_R_NCACHENXDOMAIN)
3718 name->fetch6_err = FIND_ERR_NXDOMAIN;
3720 name->fetch6_err = FIND_ERR_NXRRSET;
3721 inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
3727 * Handle CNAME/DNAME.
3729 if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
3730 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3731 clean_target(adb, &name->target);
3732 name->expire_target = INT_MAX;
3733 result = set_target(adb, &name->name,
3734 dns_fixedname_name(&dev->foundname),
3737 if (result == ISC_R_SUCCESS) {
3739 "adb fetch name %p: caching alias target",
3741 name->expire_target = dev->rdataset->ttl + now;
3747 * Did we get back junk? If so, and there are no more fetches
3748 * sitting out there, tell all the finds about it.
3750 if (dev->result != ISC_R_SUCCESS) {
3751 char buf[DNS_NAME_FORMATSIZE];
3753 dns_name_format(&name->name, buf, sizeof(buf));
3754 DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
3755 buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
3756 dns_result_totext(dev->result));
3757 /* XXXMLG Don't pound on bad servers. */
3758 if (address_type == DNS_ADBFIND_INET) {
3759 name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
3760 name->fetch_err = FIND_ERR_FAILURE;
3761 inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
3763 name->expire_v6 = ISC_MIN(name->expire_v6, now + 300);
3764 name->fetch6_err = FIND_ERR_FAILURE;
3765 inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
3771 * We got something potentially useful.
3773 result = import_rdataset(name, &fetch->rdataset, now);
3776 if (result == ISC_R_SUCCESS) {
3777 ev_status = DNS_EVENT_ADBMOREADDRESSES;
3778 if (address_type == DNS_ADBFIND_INET)
3779 name->fetch_err = FIND_ERR_SUCCESS;
3781 name->fetch6_err = FIND_ERR_SUCCESS;
3785 free_adbfetch(adb, &fetch);
3786 isc_event_free(&ev);
3788 clean_finds_at_name(name, ev_status, address_type);
3790 UNLOCK(&adb->namelocks[bucket]);
3794 fetch_name(dns_adbname_t *adbname,
3795 isc_boolean_t start_at_zone,
3796 dns_rdatatype_t type)
3798 isc_result_t result;
3799 dns_adbfetch_t *fetch = NULL;
3801 dns_fixedname_t fixed;
3803 dns_rdataset_t rdataset;
3804 dns_rdataset_t *nameservers;
3805 unsigned int options;
3807 INSIST(DNS_ADBNAME_VALID(adbname));
3809 INSIST(DNS_ADB_VALID(adb));
3811 INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
3812 (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
3814 adbname->fetch_err = FIND_ERR_NOTFOUND;
3818 dns_rdataset_init(&rdataset);
3820 options = DNS_FETCHOPT_NOVALIDATE;
3821 if (start_at_zone) {
3823 "fetch_name: starting at zone for name %p",
3825 dns_fixedname_init(&fixed);
3826 name = dns_fixedname_name(&fixed);
3827 result = dns_view_findzonecut2(adb->view, &adbname->name, name,
3828 0, 0, ISC_TRUE, ISC_FALSE,
3830 if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
3832 nameservers = &rdataset;
3833 options |= DNS_FETCHOPT_UNSHARED;
3836 fetch = new_adbfetch(adb);
3837 if (fetch == NULL) {
3838 result = ISC_R_NOMEMORY;
3842 result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
3843 type, name, nameservers, NULL,
3844 options, adb->task, fetch_callback,
3845 adbname, &fetch->rdataset, NULL,
3847 if (result != ISC_R_SUCCESS)
3850 if (type == dns_rdatatype_a) {
3851 adbname->fetch_a = fetch;
3852 inc_stats(adb, dns_resstatscounter_gluefetchv4);
3854 adbname->fetch_aaaa = fetch;
3855 inc_stats(adb, dns_resstatscounter_gluefetchv6);
3857 fetch = NULL; /* Keep us from cleaning this up below. */
3861 free_adbfetch(adb, &fetch);
3862 if (dns_rdataset_isassociated(&rdataset))
3863 dns_rdataset_disassociate(&rdataset);
3869 * XXXMLG Needs to take a find argument and an address info, no zone or adb,
3870 * since these can be extracted from the find itself.
3873 dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname,
3874 dns_rdatatype_t qtype, isc_stdtime_t expire_time)
3876 dns_adblameinfo_t *li;
3878 isc_result_t result = ISC_R_SUCCESS;
3880 REQUIRE(DNS_ADB_VALID(adb));
3881 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3882 REQUIRE(qname != NULL);
3884 bucket = addr->entry->lock_bucket;
3885 LOCK(&adb->entrylocks[bucket]);
3886 li = ISC_LIST_HEAD(addr->entry->lameinfo);
3887 while (li != NULL &&
3888 (li->qtype != qtype || !dns_name_equal(qname, &li->qname)))
3889 li = ISC_LIST_NEXT(li, plink);
3891 if (expire_time > li->lame_timer)
3892 li->lame_timer = expire_time;
3895 li = new_adblameinfo(adb, qname, qtype);
3897 result = ISC_R_NOMEMORY;
3901 li->lame_timer = expire_time;
3903 ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink);
3905 UNLOCK(&adb->entrylocks[bucket]);
3911 dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3912 unsigned int rtt, unsigned int factor)
3915 unsigned int new_srtt;
3918 REQUIRE(DNS_ADB_VALID(adb));
3919 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3920 REQUIRE(factor <= 10);
3922 bucket = addr->entry->lock_bucket;
3923 LOCK(&adb->entrylocks[bucket]);
3925 if (factor == DNS_ADB_RTTADJAGE)
3926 new_srtt = addr->entry->srtt * 98 / 100;
3928 new_srtt = (addr->entry->srtt / 10 * factor)
3929 + (rtt / 10 * (10 - factor));
3931 addr->entry->srtt = new_srtt;
3932 addr->srtt = new_srtt;
3934 if (addr->entry->expires == 0) {
3935 isc_stdtime_get(&now);
3936 addr->entry->expires = now + ADB_ENTRY_WINDOW;
3939 UNLOCK(&adb->entrylocks[bucket]);
3943 dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3944 unsigned int bits, unsigned int mask)
3949 REQUIRE(DNS_ADB_VALID(adb));
3950 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3952 bucket = addr->entry->lock_bucket;
3953 LOCK(&adb->entrylocks[bucket]);
3955 addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
3956 if (addr->entry->expires == 0) {
3957 isc_stdtime_get(&now);
3958 addr->entry->expires = now + ADB_ENTRY_WINDOW;
3962 * Note that we do not update the other bits in addr->flags with
3963 * the most recent values from addr->entry->flags.
3965 addr->flags = (addr->flags & ~mask) | (bits & mask);
3967 UNLOCK(&adb->entrylocks[bucket]);
3971 dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
3972 dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
3975 dns_adbentry_t *entry;
3976 dns_adbaddrinfo_t *addr;
3977 isc_result_t result;
3980 REQUIRE(DNS_ADB_VALID(adb));
3981 REQUIRE(addrp != NULL && *addrp == NULL);
3985 result = ISC_R_SUCCESS;
3986 bucket = DNS_ADB_INVALIDBUCKET;
3987 entry = find_entry_and_lock(adb, sa, &bucket, now);
3988 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
3989 if (adb->entry_sd[bucket]) {
3990 result = ISC_R_SHUTTINGDOWN;
3993 if (entry == NULL) {
3995 * We don't know anything about this address.
3997 entry = new_adbentry(adb);
3998 if (entry == NULL) {
3999 result = ISC_R_NOMEMORY;
4002 entry->sockaddr = *sa;
4003 link_entry(adb, bucket, entry);
4004 DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
4006 DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
4008 port = isc_sockaddr_getport(sa);
4009 addr = new_adbaddrinfo(adb, entry, port);
4011 result = ISC_R_NOMEMORY;
4013 inc_entry_refcnt(adb, entry, ISC_FALSE);
4018 UNLOCK(&adb->entrylocks[bucket]);
4024 dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
4025 dns_adbaddrinfo_t *addr;
4026 dns_adbentry_t *entry;
4029 isc_boolean_t want_check_exit = ISC_FALSE;
4030 isc_boolean_t overmem;
4032 REQUIRE(DNS_ADB_VALID(adb));
4033 REQUIRE(addrp != NULL);
4035 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4036 entry = addr->entry;
4037 REQUIRE(DNS_ADBENTRY_VALID(entry));
4040 overmem = isc_mem_isovermem(adb->mctx);
4042 bucket = addr->entry->lock_bucket;
4043 LOCK(&adb->entrylocks[bucket]);
4045 if (entry->expires == 0) {
4046 isc_stdtime_get(&now);
4047 entry->expires = now + ADB_ENTRY_WINDOW;
4050 want_check_exit = dec_entry_refcnt(adb, overmem, entry, ISC_FALSE);
4052 UNLOCK(&adb->entrylocks[bucket]);
4055 free_adbaddrinfo(adb, &addr);
4057 if (want_check_exit) {
4065 dns_adb_flush(dns_adb_t *adb) {
4068 INSIST(DNS_ADB_VALID(adb));
4073 * Call our cleanup routines.
4075 for (i = 0; i < adb->nnames; i++)
4076 RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
4077 for (i = 0; i < adb->nentries; i++)
4078 RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
4080 #ifdef DUMP_ADB_AFTER_CLEANING
4081 dump_adb(adb, stdout, ISC_TRUE, INT_MAX);
4088 dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
4089 dns_adbname_t *adbname;
4090 dns_adbname_t *nextname;
4093 INSIST(DNS_ADB_VALID(adb));
4096 bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames;
4097 LOCK(&adb->namelocks[bucket]);
4098 adbname = ISC_LIST_HEAD(adb->names[bucket]);
4099 while (adbname != NULL) {
4100 nextname = ISC_LIST_NEXT(adbname, plink);
4101 if (!NAME_DEAD(adbname) &&
4102 dns_name_equal(name, &adbname->name)) {
4103 RUNTIME_CHECK(kill_name(&adbname,
4104 DNS_EVENT_ADBCANCELED) ==
4109 UNLOCK(&adb->namelocks[bucket]);
4114 water(void *arg, int mark) {
4116 * We're going to change the way to handle overmem condition: use
4117 * isc_mem_isovermem() instead of storing the state via this callback,
4118 * since the latter way tends to cause race conditions.
4119 * To minimize the change, and in case we re-enable the callback
4120 * approach, however, keep this function at the moment.
4123 dns_adb_t *adb = arg;
4124 isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
4126 REQUIRE(DNS_ADB_VALID(adb));
4128 DP(ISC_LOG_DEBUG(1),
4129 "adb reached %s water mark", overmem ? "high" : "low");
4133 dns_adb_setadbsize(dns_adb_t *adb, size_t size) {
4134 size_t hiwater, lowater;
4136 INSIST(DNS_ADB_VALID(adb));
4138 if (size != 0U && size < DNS_ADB_MINADBSIZE)
4139 size = DNS_ADB_MINADBSIZE;
4141 hiwater = size - (size >> 3); /* Approximately 7/8ths. */
4142 lowater = size - (size >> 2); /* Approximately 3/4ths. */
4144 if (size == 0U || hiwater == 0U || lowater == 0U)
4145 isc_mem_setwater(adb->mctx, water, adb, 0, 0);
4147 isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);