2 * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
23 * In finds, if task == NULL, no events will be generated, and no events
24 * have been sent. If task != NULL but taskaction == NULL, an event has been
25 * posted but not yet freed. If neither are NULL, no event was posted.
33 #include <isc/mutexblock.h>
34 #include <isc/netaddr.h>
35 #include <isc/random.h>
36 #include <isc/stats.h>
37 #include <isc/string.h> /* Required for HP/UX (and others?) */
43 #include <dns/events.h>
45 #include <dns/rdata.h>
46 #include <dns/rdataset.h>
47 #include <dns/rdatastruct.h>
48 #include <dns/rdatatype.h>
49 #include <dns/resolver.h>
50 #include <dns/result.h>
51 #include <dns/stats.h>
53 #define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b')
54 #define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
55 #define DNS_ADBNAME_MAGIC ISC_MAGIC('a', 'd', 'b', 'N')
56 #define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
57 #define DNS_ADBNAMEHOOK_MAGIC ISC_MAGIC('a', 'd', 'N', 'H')
58 #define DNS_ADBNAMEHOOK_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
59 #define DNS_ADBLAMEINFO_MAGIC ISC_MAGIC('a', 'd', 'b', 'Z')
60 #define DNS_ADBLAMEINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBLAMEINFO_MAGIC)
61 #define DNS_ADBENTRY_MAGIC ISC_MAGIC('a', 'd', 'b', 'E')
62 #define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
63 #define DNS_ADBFETCH_MAGIC ISC_MAGIC('a', 'd', 'F', '4')
64 #define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
65 #define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6')
66 #define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
69 * For type 3 negative cache entries, we will remember that the address is
70 * broken for this long. XXXMLG This is also used for actual addresses, too.
71 * The intent is to keep us from constantly asking about A/AAAA records
72 * if the zone has extremely low TTLs.
74 #define ADB_CACHE_MINIMUM 10 /*%< seconds */
75 #define ADB_CACHE_MAXIMUM 86400 /*%< seconds (86400 = 24 hours) */
76 #define ADB_ENTRY_WINDOW 1800 /*%< seconds */
79 * The period in seconds after which an ADB name entry is regarded as stale
80 * and forced to be cleaned up.
81 * TODO: This should probably be configurable at run-time.
83 #ifndef ADB_STALE_MARGIN
84 #define ADB_STALE_MARGIN 1800
87 #define FREE_ITEMS 64 /*%< free count for memory pools */
88 #define FILL_COUNT 16 /*%< fill count for memory pools */
90 #define DNS_ADB_INVALIDBUCKET (-1) /*%< invalid bucket address */
92 #define DNS_ADB_MINADBSIZE (1024*1024) /*%< 1 Megabyte */
94 typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
95 typedef struct dns_adbnamehook dns_adbnamehook_t;
96 typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
97 typedef struct dns_adblameinfo dns_adblameinfo_t;
98 typedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t;
99 typedef struct dns_adbfetch dns_adbfetch_t;
100 typedef struct dns_adbfetch6 dns_adbfetch6_t;
102 /*% dns adb structure */
107 isc_mutex_t reflock; /*%< Covers irefcnt, erefcnt */
108 isc_mutex_t overmemlock; /*%< Covers overmem */
112 isc_taskmgr_t *taskmgr;
115 isc_interval_t tick_interval;
116 int next_cleanbucket;
118 unsigned int irefcnt;
119 unsigned int erefcnt;
122 isc_mempool_t *nmp; /*%< dns_adbname_t */
123 isc_mempool_t *nhmp; /*%< dns_adbnamehook_t */
124 isc_mempool_t *limp; /*%< dns_adblameinfo_t */
125 isc_mempool_t *emp; /*%< dns_adbentry_t */
126 isc_mempool_t *ahmp; /*%< dns_adbfind_t */
127 isc_mempool_t *aimp; /*%< dns_adbaddrinfo_t */
128 isc_mempool_t *afmp; /*%< dns_adbfetch_t */
131 * Bucketized locks and lists for names.
133 * XXXRTH Have a per-bucket structure that contains all of these?
136 isc_mutex_t namescntlock;
137 unsigned int namescnt;
138 dns_adbnamelist_t *names;
139 dns_adbnamelist_t *deadnames;
140 isc_mutex_t *namelocks;
141 isc_boolean_t *name_sd;
142 unsigned int *name_refcnt;
145 * Bucketized locks and lists for entries.
147 * XXXRTH Have a per-bucket structure that contains all of these?
149 unsigned int nentries;
150 isc_mutex_t entriescntlock;
151 unsigned int entriescnt;
152 dns_adbentrylist_t *entries;
153 dns_adbentrylist_t *deadentries;
154 isc_mutex_t *entrylocks;
155 isc_boolean_t *entry_sd; /*%< shutting down */
156 unsigned int *entry_refcnt;
159 isc_boolean_t cevent_sent;
160 isc_boolean_t shutting_down;
161 isc_eventlist_t whenshutdown;
162 isc_event_t growentries;
163 isc_boolean_t growentries_sent;
164 isc_event_t grownames;
165 isc_boolean_t grownames_sent;
169 * XXXMLG Document these structures.
172 /*% dns_adbname structure */
177 unsigned int partial_result;
181 isc_stdtime_t expire_target;
182 isc_stdtime_t expire_v4;
183 isc_stdtime_t expire_v6;
185 dns_adbnamehooklist_t v4;
186 dns_adbnamehooklist_t v6;
187 dns_adbfetch_t *fetch_a;
188 dns_adbfetch_t *fetch_aaaa;
189 unsigned int fetch_err;
190 unsigned int fetch6_err;
191 dns_adbfindlist_t finds;
192 /* for LRU-based management */
193 isc_stdtime_t last_used;
195 ISC_LINK(dns_adbname_t) plink;
198 /*% The adbfetch structure */
199 struct dns_adbfetch {
202 dns_rdataset_t rdataset;
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, unsigned int);
304 static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
305 static isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **,
307 static void cancel_fetches_at_name(dns_adbname_t *);
308 static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
310 static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
311 unsigned int, isc_counter_t *qc,
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 isc_task_beginexclusive(task);
524 while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i])
526 if (nbuckets[i] != 0)
531 DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n);
534 * Are we shutting down?
536 for (i = 0; i < adb->nentries; i++)
537 if (adb->entry_sd[i])
541 * Grab all the resources we need.
543 newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n);
544 newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n);
545 newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n);
546 newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n);
547 newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n);
548 if (newentries == NULL || newdeadentries == NULL ||
549 newentrylocks == NULL || newentry_sd == NULL ||
550 newentry_refcnt == NULL)
554 * Initialise the new resources.
556 result = isc_mutexblock_init(newentrylocks, n);
557 if (result != ISC_R_SUCCESS)
560 for (i = 0; i < n; i++) {
561 ISC_LIST_INIT(newentries[i]);
562 ISC_LIST_INIT(newdeadentries[i]);
563 newentry_sd[i] = ISC_FALSE;
564 newentry_refcnt[i] = 0;
569 * Move entries to new arrays.
571 for (i = 0; i < adb->nentries; i++) {
572 e = ISC_LIST_HEAD(adb->entries[i]);
574 ISC_LIST_UNLINK(adb->entries[i], e, plink);
575 bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
576 e->lock_bucket = bucket;
577 ISC_LIST_APPEND(newentries[bucket], e, plink);
578 INSIST(adb->entry_refcnt[i] > 0);
579 adb->entry_refcnt[i]--;
580 newentry_refcnt[bucket]++;
581 e = ISC_LIST_HEAD(adb->entries[i]);
583 e = ISC_LIST_HEAD(adb->deadentries[i]);
585 ISC_LIST_UNLINK(adb->deadentries[i], e, plink);
586 bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
587 e->lock_bucket = bucket;
588 ISC_LIST_APPEND(newdeadentries[bucket], e, plink);
589 INSIST(adb->entry_refcnt[i] > 0);
590 adb->entry_refcnt[i]--;
591 newentry_refcnt[bucket]++;
592 e = ISC_LIST_HEAD(adb->deadentries[i]);
594 INSIST(adb->entry_refcnt[i] == 0);
599 * Cleanup old resources.
601 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
602 isc_mem_put(adb->mctx, adb->entries,
603 sizeof(*adb->entries) * adb->nentries);
604 isc_mem_put(adb->mctx, adb->deadentries,
605 sizeof(*adb->deadentries) * adb->nentries);
606 isc_mem_put(adb->mctx, adb->entrylocks,
607 sizeof(*adb->entrylocks) * adb->nentries);
608 isc_mem_put(adb->mctx, adb->entry_sd,
609 sizeof(*adb->entry_sd) * adb->nentries);
610 isc_mem_put(adb->mctx, adb->entry_refcnt,
611 sizeof(*adb->entry_refcnt) * adb->nentries);
614 * Install new resources.
616 adb->entries = newentries;
617 adb->deadentries = newdeadentries;
618 adb->entrylocks = newentrylocks;
619 adb->entry_sd = newentry_sd;
620 adb->entry_refcnt = newentry_refcnt;
624 * Only on success do we set adb->growentries_sent to ISC_FALSE.
625 * This will prevent us being continuously being called on error.
627 adb->growentries_sent = ISC_FALSE;
631 if (newentries != NULL)
632 isc_mem_put(adb->mctx, newentries,
633 sizeof(*newentries) * n);
634 if (newdeadentries != NULL)
635 isc_mem_put(adb->mctx, newdeadentries,
636 sizeof(*newdeadentries) * n);
637 if (newentrylocks != NULL)
638 isc_mem_put(adb->mctx, newentrylocks,
639 sizeof(*newentrylocks) * n);
640 if (newentry_sd != NULL)
641 isc_mem_put(adb->mctx, newentry_sd,
642 sizeof(*newentry_sd) * n);
643 if (newentry_refcnt != NULL)
644 isc_mem_put(adb->mctx, newentry_refcnt,
645 sizeof(*newentry_refcnt) * n);
647 isc_task_endexclusive(task);
650 if (dec_adb_irefcnt(adb))
653 DP(ISC_LOG_INFO, "adb: grow_entries finished");
657 grow_names(isc_task_t *task, isc_event_t *ev) {
660 dns_adbnamelist_t *newdeadnames = NULL;
661 dns_adbnamelist_t *newnames = NULL;
662 isc_boolean_t *newname_sd = NULL;
663 isc_mutex_t *newnamelocks = NULL;
665 unsigned int *newname_refcnt = NULL;
666 unsigned int i, n, bucket;
669 INSIST(DNS_ADB_VALID(adb));
673 isc_task_beginexclusive(task);
676 while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i])
678 if (nbuckets[i] != 0)
683 DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n);
686 * Are we shutting down?
688 for (i = 0; i < adb->nnames; i++)
693 * Grab all the resources we need.
695 newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n);
696 newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n);
697 newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n);
698 newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n);
699 newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n);
700 if (newnames == NULL || newdeadnames == NULL ||
701 newnamelocks == NULL || newname_sd == NULL ||
702 newname_refcnt == NULL)
706 * Initialise the new resources.
708 result = isc_mutexblock_init(newnamelocks, n);
709 if (result != ISC_R_SUCCESS)
712 for (i = 0; i < n; i++) {
713 ISC_LIST_INIT(newnames[i]);
714 ISC_LIST_INIT(newdeadnames[i]);
715 newname_sd[i] = ISC_FALSE;
716 newname_refcnt[i] = 0;
721 * Move names to new arrays.
723 for (i = 0; i < adb->nnames; i++) {
724 name = ISC_LIST_HEAD(adb->names[i]);
725 while (name != NULL) {
726 ISC_LIST_UNLINK(adb->names[i], name, plink);
727 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
728 name->lock_bucket = bucket;
729 ISC_LIST_APPEND(newnames[bucket], name, plink);
730 INSIST(adb->name_refcnt[i] > 0);
731 adb->name_refcnt[i]--;
732 newname_refcnt[bucket]++;
733 name = ISC_LIST_HEAD(adb->names[i]);
735 name = ISC_LIST_HEAD(adb->deadnames[i]);
736 while (name != NULL) {
737 ISC_LIST_UNLINK(adb->deadnames[i], name, plink);
738 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
739 name->lock_bucket = bucket;
740 ISC_LIST_APPEND(newdeadnames[bucket], name, plink);
741 INSIST(adb->name_refcnt[i] > 0);
742 adb->name_refcnt[i]--;
743 newname_refcnt[bucket]++;
744 name = ISC_LIST_HEAD(adb->deadnames[i]);
746 INSIST(adb->name_refcnt[i] == 0);
751 * Cleanup old resources.
753 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
754 isc_mem_put(adb->mctx, adb->names,
755 sizeof(*adb->names) * adb->nnames);
756 isc_mem_put(adb->mctx, adb->deadnames,
757 sizeof(*adb->deadnames) * adb->nnames);
758 isc_mem_put(adb->mctx, adb->namelocks,
759 sizeof(*adb->namelocks) * adb->nnames);
760 isc_mem_put(adb->mctx, adb->name_sd,
761 sizeof(*adb->name_sd) * adb->nnames);
762 isc_mem_put(adb->mctx, adb->name_refcnt,
763 sizeof(*adb->name_refcnt) * adb->nnames);
766 * Install new resources.
768 adb->names = newnames;
769 adb->deadnames = newdeadnames;
770 adb->namelocks = newnamelocks;
771 adb->name_sd = newname_sd;
772 adb->name_refcnt = newname_refcnt;
776 * Only on success do we set adb->grownames_sent to ISC_FALSE.
777 * This will prevent us being continuously being called on error.
779 adb->grownames_sent = ISC_FALSE;
783 if (newnames != NULL)
784 isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n);
785 if (newdeadnames != NULL)
786 isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n);
787 if (newnamelocks != NULL)
788 isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n);
789 if (newname_sd != NULL)
790 isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n);
791 if (newname_refcnt != NULL)
792 isc_mem_put(adb->mctx, newname_refcnt,
793 sizeof(*newname_refcnt) * n);
795 isc_task_endexclusive(task);
798 if (dec_adb_irefcnt(adb))
801 DP(ISC_LOG_INFO, "adb: grow_names finished");
805 * Requires the adbname bucket be locked and that no entry buckets be locked.
807 * This code handles A and AAAA rdatasets only.
810 import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
815 dns_adbnamehook_t *nh;
816 dns_adbnamehook_t *anh;
817 dns_rdata_t rdata = DNS_RDATA_INIT;
819 struct in6_addr in6a;
820 isc_sockaddr_t sockaddr;
821 dns_adbentry_t *foundentry; /* NO CLEAN UP! */
823 isc_boolean_t new_addresses_added;
824 dns_rdatatype_t rdtype;
825 unsigned int findoptions;
826 dns_adbnamehooklist_t *hookhead;
828 INSIST(DNS_ADBNAME_VALID(adbname));
830 INSIST(DNS_ADB_VALID(adb));
832 rdtype = rdataset->type;
833 INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
834 if (rdtype == dns_rdatatype_a)
835 findoptions = DNS_ADBFIND_INET;
837 findoptions = DNS_ADBFIND_INET6;
839 addr_bucket = DNS_ADB_INVALIDBUCKET;
840 new_addresses_added = ISC_FALSE;
843 result = dns_rdataset_first(rdataset);
844 while (result == ISC_R_SUCCESS) {
845 dns_rdata_reset(&rdata);
846 dns_rdataset_current(rdataset, &rdata);
847 if (rdtype == dns_rdatatype_a) {
848 INSIST(rdata.length == 4);
849 memcpy(&ina.s_addr, rdata.data, 4);
850 isc_sockaddr_fromin(&sockaddr, &ina, 0);
851 hookhead = &adbname->v4;
853 INSIST(rdata.length == 16);
854 memcpy(in6a.s6_addr, rdata.data, 16);
855 isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
856 hookhead = &adbname->v6;
860 nh = new_adbnamehook(adb, NULL);
862 adbname->partial_result |= findoptions;
863 result = ISC_R_NOMEMORY;
867 foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket,
869 if (foundentry == NULL) {
870 dns_adbentry_t *entry;
872 entry = new_adbentry(adb);
874 adbname->partial_result |= findoptions;
875 result = ISC_R_NOMEMORY;
879 entry->sockaddr = sockaddr;
884 link_entry(adb, addr_bucket, entry);
886 for (anh = ISC_LIST_HEAD(*hookhead);
888 anh = ISC_LIST_NEXT(anh, plink))
889 if (anh->entry == foundentry)
892 foundentry->refcnt++;
893 nh->entry = foundentry;
895 free_adbnamehook(adb, &nh);
898 new_addresses_added = ISC_TRUE;
900 ISC_LIST_APPEND(*hookhead, nh, plink);
902 result = dns_rdataset_next(rdataset);
907 free_adbnamehook(adb, &nh);
909 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
910 UNLOCK(&adb->entrylocks[addr_bucket]);
912 if (rdataset->trust == dns_trust_glue ||
913 rdataset->trust == dns_trust_additional)
914 rdataset->ttl = ADB_CACHE_MINIMUM;
915 else if (rdataset->trust == dns_trust_ultimate)
918 rdataset->ttl = ttlclamp(rdataset->ttl);
920 if (rdtype == dns_rdatatype_a) {
921 DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
922 adbname->expire_v4, now + rdataset->ttl);
923 adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
924 now + rdataset->ttl);
926 DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
927 adbname->expire_v6, now + rdataset->ttl);
928 adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
929 now + rdataset->ttl);
932 if (new_addresses_added) {
934 * Lie a little here. This is more or less so code that cares
935 * can find out if any new information was added or not.
937 return (ISC_R_SUCCESS);
944 * Requires the name's bucket be locked.
947 kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
949 isc_boolean_t result = ISC_FALSE;
950 isc_boolean_t result4, result6;
957 INSIST(DNS_ADBNAME_VALID(name));
959 INSIST(DNS_ADB_VALID(adb));
961 DP(DEF_LEVEL, "killing name %p", name);
964 * If we're dead already, just check to see if we should go
967 if (NAME_DEAD(name) && !NAME_FETCH(name)) {
968 result = unlink_name(adb, name);
969 free_adbname(adb, &name);
971 result = dec_adb_irefcnt(adb);
976 * Clean up the name's various lists. These two are destructive
977 * in that they will always empty the list.
979 clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
980 result4 = clean_namehooks(adb, &name->v4);
981 result6 = clean_namehooks(adb, &name->v6);
982 clean_target(adb, &name->target);
983 result = ISC_TF(result4 || result6);
986 * If fetches are running, cancel them. If none are running, we can
987 * just kill the name here.
989 if (!NAME_FETCH(name)) {
990 INSIST(result == ISC_FALSE);
991 result = unlink_name(adb, name);
992 free_adbname(adb, &name);
994 result = dec_adb_irefcnt(adb);
996 cancel_fetches_at_name(name);
997 if (!NAME_DEAD(name)) {
998 bucket = name->lock_bucket;
999 ISC_LIST_UNLINK(adb->names[bucket], name, plink);
1000 ISC_LIST_APPEND(adb->deadnames[bucket], name, plink);
1001 name->flags |= NAME_IS_DEAD;
1008 * Requires the name's bucket be locked and no entry buckets be locked.
1010 static isc_boolean_t
1011 check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
1013 isc_boolean_t result4 = ISC_FALSE;
1014 isc_boolean_t result6 = ISC_FALSE;
1016 INSIST(DNS_ADBNAME_VALID(name));
1018 INSIST(DNS_ADB_VALID(adb));
1021 * Check to see if we need to remove the v4 addresses
1023 if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) {
1024 if (NAME_HAS_V4(name)) {
1025 DP(DEF_LEVEL, "expiring v4 for name %p", name);
1026 result4 = clean_namehooks(adb, &name->v4);
1027 name->partial_result &= ~DNS_ADBFIND_INET;
1029 name->expire_v4 = INT_MAX;
1030 name->fetch_err = FIND_ERR_UNEXPECTED;
1034 * Check to see if we need to remove the v6 addresses
1036 if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) {
1037 if (NAME_HAS_V6(name)) {
1038 DP(DEF_LEVEL, "expiring v6 for name %p", name);
1039 result6 = clean_namehooks(adb, &name->v6);
1040 name->partial_result &= ~DNS_ADBFIND_INET6;
1042 name->expire_v6 = INT_MAX;
1043 name->fetch6_err = FIND_ERR_UNEXPECTED;
1047 * Check to see if we need to remove the alias target.
1049 if (EXPIRE_OK(name->expire_target, now)) {
1050 clean_target(adb, &name->target);
1051 name->expire_target = INT_MAX;
1053 return (ISC_TF(result4 || result6));
1057 * Requires the name's bucket be locked.
1060 link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
1061 INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
1063 ISC_LIST_PREPEND(adb->names[bucket], name, plink);
1064 name->lock_bucket = bucket;
1065 adb->name_refcnt[bucket]++;
1069 * Requires the name's bucket be locked.
1071 static inline isc_boolean_t
1072 unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
1074 isc_boolean_t result = ISC_FALSE;
1076 bucket = name->lock_bucket;
1077 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
1079 if (NAME_DEAD(name))
1080 ISC_LIST_UNLINK(adb->deadnames[bucket], name, plink);
1082 ISC_LIST_UNLINK(adb->names[bucket], name, plink);
1083 name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1084 INSIST(adb->name_refcnt[bucket] > 0);
1085 adb->name_refcnt[bucket]--;
1086 if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
1092 * Requires the entry's bucket be locked.
1095 link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
1099 if (isc_mem_isovermem(adb->mctx)) {
1100 for (i = 0; i < 2; i++) {
1101 e = ISC_LIST_TAIL(adb->entries[bucket]);
1104 if (e->refcnt == 0) {
1105 unlink_entry(adb, e);
1106 free_adbentry(adb, &e);
1109 INSIST((e->flags & ENTRY_IS_DEAD) == 0);
1110 e->flags |= ENTRY_IS_DEAD;
1111 ISC_LIST_UNLINK(adb->entries[bucket], e, plink);
1112 ISC_LIST_PREPEND(adb->deadentries[bucket], e, plink);
1116 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
1117 entry->lock_bucket = bucket;
1118 adb->entry_refcnt[bucket]++;
1122 * Requires the entry's bucket be locked.
1124 static inline isc_boolean_t
1125 unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
1127 isc_boolean_t result = ISC_FALSE;
1129 bucket = entry->lock_bucket;
1130 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
1132 if ((entry->flags & ENTRY_IS_DEAD) != 0)
1133 ISC_LIST_UNLINK(adb->deadentries[bucket], entry, plink);
1135 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
1136 entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1137 INSIST(adb->entry_refcnt[bucket] > 0);
1138 adb->entry_refcnt[bucket]--;
1139 if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
1145 violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
1146 if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
1154 * The ADB _MUST_ be locked before calling. Also, exit conditions must be
1155 * checked after calling this function.
1157 static isc_boolean_t
1158 shutdown_names(dns_adb_t *adb) {
1159 unsigned int bucket;
1160 isc_boolean_t result = ISC_FALSE;
1161 dns_adbname_t *name;
1162 dns_adbname_t *next_name;
1164 for (bucket = 0; bucket < adb->nnames; bucket++) {
1165 LOCK(&adb->namelocks[bucket]);
1166 adb->name_sd[bucket] = ISC_TRUE;
1168 name = ISC_LIST_HEAD(adb->names[bucket]);
1171 * This bucket has no names. We must decrement the
1172 * irefcnt ourselves, since it will not be
1173 * automatically triggered by a name being unlinked.
1175 INSIST(result == ISC_FALSE);
1176 result = dec_adb_irefcnt(adb);
1179 * Run through the list. For each name, clean up finds
1180 * found there, and cancel any fetches running. When
1181 * all the fetches are canceled, the name will destroy
1184 while (name != NULL) {
1185 next_name = ISC_LIST_NEXT(name, plink);
1186 INSIST(result == ISC_FALSE);
1187 result = kill_name(&name,
1188 DNS_EVENT_ADBSHUTDOWN);
1193 UNLOCK(&adb->namelocks[bucket]);
1199 * The ADB _MUST_ be locked before calling. Also, exit conditions must be
1200 * checked after calling this function.
1202 static isc_boolean_t
1203 shutdown_entries(dns_adb_t *adb) {
1204 unsigned int bucket;
1205 isc_boolean_t result = ISC_FALSE;
1206 dns_adbentry_t *entry;
1207 dns_adbentry_t *next_entry;
1209 for (bucket = 0; bucket < adb->nentries; bucket++) {
1210 LOCK(&adb->entrylocks[bucket]);
1211 adb->entry_sd[bucket] = ISC_TRUE;
1213 entry = ISC_LIST_HEAD(adb->entries[bucket]);
1214 if (adb->entry_refcnt[bucket] == 0) {
1216 * This bucket has no entries. We must decrement the
1217 * irefcnt ourselves, since it will not be
1218 * automatically triggered by an entry being unlinked.
1220 result = dec_adb_irefcnt(adb);
1223 * Run through the list. Cleanup any entries not
1224 * associated with names, and which are not in use.
1226 while (entry != NULL) {
1227 next_entry = ISC_LIST_NEXT(entry, plink);
1228 if (entry->refcnt == 0 &&
1229 entry->expires != 0) {
1230 result = unlink_entry(adb, entry);
1231 free_adbentry(adb, &entry);
1233 result = dec_adb_irefcnt(adb);
1239 UNLOCK(&adb->entrylocks[bucket]);
1245 * Name bucket must be locked
1248 cancel_fetches_at_name(dns_adbname_t *name) {
1249 if (NAME_FETCH_A(name))
1250 dns_resolver_cancelfetch(name->fetch_a->fetch);
1252 if (NAME_FETCH_AAAA(name))
1253 dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
1257 * Assumes the name bucket is locked.
1259 static isc_boolean_t
1260 clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
1261 dns_adbentry_t *entry;
1262 dns_adbnamehook_t *namehook;
1264 isc_boolean_t result = ISC_FALSE;
1265 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
1267 addr_bucket = DNS_ADB_INVALIDBUCKET;
1268 namehook = ISC_LIST_HEAD(*namehooks);
1269 while (namehook != NULL) {
1270 INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
1273 * Clean up the entry if needed.
1275 entry = namehook->entry;
1276 if (entry != NULL) {
1277 INSIST(DNS_ADBENTRY_VALID(entry));
1279 if (addr_bucket != entry->lock_bucket) {
1280 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1281 UNLOCK(&adb->entrylocks[addr_bucket]);
1282 addr_bucket = entry->lock_bucket;
1283 LOCK(&adb->entrylocks[addr_bucket]);
1286 result = dec_entry_refcnt(adb, overmem, entry,
1293 namehook->entry = NULL;
1294 ISC_LIST_UNLINK(*namehooks, namehook, plink);
1295 free_adbnamehook(adb, &namehook);
1297 namehook = ISC_LIST_HEAD(*namehooks);
1300 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1301 UNLOCK(&adb->entrylocks[addr_bucket]);
1306 clean_target(dns_adb_t *adb, dns_name_t *target) {
1307 if (dns_name_countlabels(target) > 0) {
1308 dns_name_free(target, adb->mctx);
1309 dns_name_init(target, NULL);
1314 set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
1315 dns_rdataset_t *rdataset, dns_name_t *target)
1317 isc_result_t result;
1318 dns_namereln_t namereln;
1319 unsigned int nlabels;
1321 dns_rdata_t rdata = DNS_RDATA_INIT;
1322 dns_fixedname_t fixed1, fixed2;
1323 dns_name_t *prefix, *new_target;
1325 REQUIRE(dns_name_countlabels(target) == 0);
1327 if (rdataset->type == dns_rdatatype_cname) {
1328 dns_rdata_cname_t cname;
1331 * Copy the CNAME's target into the target name.
1333 result = dns_rdataset_first(rdataset);
1334 if (result != ISC_R_SUCCESS)
1336 dns_rdataset_current(rdataset, &rdata);
1337 result = dns_rdata_tostruct(&rdata, &cname, NULL);
1338 if (result != ISC_R_SUCCESS)
1340 result = dns_name_dup(&cname.cname, adb->mctx, target);
1341 dns_rdata_freestruct(&cname);
1342 if (result != ISC_R_SUCCESS)
1345 dns_rdata_dname_t dname;
1347 INSIST(rdataset->type == dns_rdatatype_dname);
1348 namereln = dns_name_fullcompare(name, fname, &order, &nlabels);
1349 INSIST(namereln == dns_namereln_subdomain);
1351 * Get the target name of the DNAME.
1353 result = dns_rdataset_first(rdataset);
1354 if (result != ISC_R_SUCCESS)
1356 dns_rdataset_current(rdataset, &rdata);
1357 result = dns_rdata_tostruct(&rdata, &dname, NULL);
1358 if (result != ISC_R_SUCCESS)
1361 * Construct the new target name.
1363 dns_fixedname_init(&fixed1);
1364 prefix = dns_fixedname_name(&fixed1);
1365 dns_fixedname_init(&fixed2);
1366 new_target = dns_fixedname_name(&fixed2);
1367 dns_name_split(name, nlabels, prefix, NULL);
1368 result = dns_name_concatenate(prefix, &dname.dname, new_target,
1370 dns_rdata_freestruct(&dname);
1371 if (result != ISC_R_SUCCESS)
1373 result = dns_name_dup(new_target, adb->mctx, target);
1374 if (result != ISC_R_SUCCESS)
1378 return (ISC_R_SUCCESS);
1382 * Assumes nothing is locked, since this is called by the client.
1385 event_free(isc_event_t *event) {
1386 dns_adbfind_t *find;
1388 INSIST(event != NULL);
1389 find = event->ev_destroy_arg;
1390 INSIST(DNS_ADBFIND_VALID(find));
1393 find->flags |= FIND_EVENT_FREED;
1394 event->ev_destroy_arg = NULL;
1395 UNLOCK(&find->lock);
1399 * Assumes the name bucket is locked.
1402 clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
1407 dns_adbfind_t *find;
1408 dns_adbfind_t *next_find;
1409 isc_boolean_t process;
1410 unsigned int wanted, notify;
1413 "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
1414 name, evtype, addrs);
1416 find = ISC_LIST_HEAD(name->finds);
1417 while (find != NULL) {
1419 next_find = ISC_LIST_NEXT(find, plink);
1421 process = ISC_FALSE;
1422 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1423 notify = wanted & addrs;
1426 case DNS_EVENT_ADBMOREADDRESSES:
1427 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES");
1428 if ((notify) != 0) {
1429 find->flags &= ~addrs;
1433 case DNS_EVENT_ADBNOMOREADDRESSES:
1434 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES");
1435 find->flags &= ~addrs;
1436 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1441 find->flags &= ~addrs;
1446 DP(DEF_LEVEL, "cfan: processing find %p", find);
1448 * Unlink the find from the name, letting the caller
1449 * call dns_adb_destroyfind() on it to clean it up
1452 ISC_LIST_UNLINK(name->finds, find, plink);
1453 find->adbname = NULL;
1454 find->name_bucket = DNS_ADB_INVALIDBUCKET;
1456 INSIST(!FIND_EVENTSENT(find));
1459 task = ev->ev_sender;
1460 ev->ev_sender = find;
1461 find->result_v4 = find_err_map[name->fetch_err];
1462 find->result_v6 = find_err_map[name->fetch6_err];
1463 ev->ev_type = evtype;
1464 ev->ev_destroy = event_free;
1465 ev->ev_destroy_arg = find;
1468 "sending event %p to task %p for find %p",
1471 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
1473 DP(DEF_LEVEL, "cfan: skipping find %p", find);
1476 UNLOCK(&find->lock);
1480 DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
1484 check_exit(dns_adb_t *adb) {
1487 * The caller must be holding the adb lock.
1489 if (adb->shutting_down) {
1491 * If there aren't any external references either, we're
1492 * done. Send the control event to initiate shutdown.
1494 INSIST(!adb->cevent_sent); /* Sanity check. */
1495 event = &adb->cevent;
1496 isc_task_send(adb->task, &event);
1497 adb->cevent_sent = ISC_TRUE;
1501 static inline isc_boolean_t
1502 dec_adb_irefcnt(dns_adb_t *adb) {
1505 isc_boolean_t result = ISC_FALSE;
1507 LOCK(&adb->reflock);
1509 INSIST(adb->irefcnt > 0);
1512 if (adb->irefcnt == 0) {
1513 event = ISC_LIST_HEAD(adb->whenshutdown);
1514 while (event != NULL) {
1515 ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
1516 etask = event->ev_sender;
1517 event->ev_sender = adb;
1518 isc_task_sendanddetach(&etask, &event);
1519 event = ISC_LIST_HEAD(adb->whenshutdown);
1523 if (adb->irefcnt == 0 && adb->erefcnt == 0)
1525 UNLOCK(&adb->reflock);
1530 inc_adb_irefcnt(dns_adb_t *adb) {
1531 LOCK(&adb->reflock);
1533 UNLOCK(&adb->reflock);
1537 inc_adb_erefcnt(dns_adb_t *adb) {
1538 LOCK(&adb->reflock);
1540 UNLOCK(&adb->reflock);
1544 inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
1547 bucket = entry->lock_bucket;
1550 LOCK(&adb->entrylocks[bucket]);
1555 UNLOCK(&adb->entrylocks[bucket]);
1558 static inline isc_boolean_t
1559 dec_entry_refcnt(dns_adb_t *adb, isc_boolean_t overmem, dns_adbentry_t *entry,
1563 isc_boolean_t destroy_entry;
1564 isc_boolean_t result = ISC_FALSE;
1566 bucket = entry->lock_bucket;
1569 LOCK(&adb->entrylocks[bucket]);
1571 INSIST(entry->refcnt > 0);
1574 destroy_entry = ISC_FALSE;
1575 if (entry->refcnt == 0 &&
1576 (adb->entry_sd[bucket] || entry->expires == 0 || overmem ||
1577 (entry->flags & ENTRY_IS_DEAD) != 0)) {
1578 destroy_entry = ISC_TRUE;
1579 result = unlink_entry(adb, entry);
1583 UNLOCK(&adb->entrylocks[bucket]);
1588 entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1590 free_adbentry(adb, &entry);
1592 result = dec_adb_irefcnt(adb);
1597 static inline dns_adbname_t *
1598 new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
1599 dns_adbname_t *name;
1601 name = isc_mempool_get(adb->nmp);
1605 dns_name_init(&name->name, NULL);
1606 if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
1607 isc_mempool_put(adb->nmp, name);
1610 dns_name_init(&name->target, NULL);
1611 name->magic = DNS_ADBNAME_MAGIC;
1613 name->partial_result = 0;
1615 name->expire_v4 = INT_MAX;
1616 name->expire_v6 = INT_MAX;
1617 name->expire_target = INT_MAX;
1619 name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1620 ISC_LIST_INIT(name->v4);
1621 ISC_LIST_INIT(name->v6);
1622 name->fetch_a = NULL;
1623 name->fetch_aaaa = NULL;
1624 name->fetch_err = FIND_ERR_UNEXPECTED;
1625 name->fetch6_err = FIND_ERR_UNEXPECTED;
1626 ISC_LIST_INIT(name->finds);
1627 ISC_LINK_INIT(name, plink);
1629 LOCK(&adb->namescntlock);
1631 if (!adb->grownames_sent && adb->namescnt > (adb->nnames * 8)) {
1632 isc_event_t *event = &adb->grownames;
1633 inc_adb_irefcnt(adb);
1634 isc_task_send(adb->task, &event);
1635 adb->grownames_sent = ISC_TRUE;
1637 UNLOCK(&adb->namescntlock);
1643 free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
1646 INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
1650 INSIST(!NAME_HAS_V4(n));
1651 INSIST(!NAME_HAS_V6(n));
1652 INSIST(!NAME_FETCH(n));
1653 INSIST(ISC_LIST_EMPTY(n->finds));
1654 INSIST(!ISC_LINK_LINKED(n, plink));
1655 INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
1656 INSIST(n->adb == adb);
1659 dns_name_free(&n->name, adb->mctx);
1661 isc_mempool_put(adb->nmp, n);
1662 LOCK(&adb->namescntlock);
1664 UNLOCK(&adb->namescntlock);
1667 static inline dns_adbnamehook_t *
1668 new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) {
1669 dns_adbnamehook_t *nh;
1671 nh = isc_mempool_get(adb->nhmp);
1675 nh->magic = DNS_ADBNAMEHOOK_MAGIC;
1677 ISC_LINK_INIT(nh, plink);
1683 free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) {
1684 dns_adbnamehook_t *nh;
1686 INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
1690 INSIST(nh->entry == NULL);
1691 INSIST(!ISC_LINK_LINKED(nh, plink));
1694 isc_mempool_put(adb->nhmp, nh);
1697 static inline dns_adblameinfo_t *
1698 new_adblameinfo(dns_adb_t *adb, dns_name_t *qname, dns_rdatatype_t qtype) {
1699 dns_adblameinfo_t *li;
1701 li = isc_mempool_get(adb->limp);
1705 dns_name_init(&li->qname, NULL);
1706 if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) {
1707 isc_mempool_put(adb->limp, li);
1710 li->magic = DNS_ADBLAMEINFO_MAGIC;
1713 ISC_LINK_INIT(li, plink);
1719 free_adblameinfo(dns_adb_t *adb, dns_adblameinfo_t **lameinfo) {
1720 dns_adblameinfo_t *li;
1722 INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo));
1726 INSIST(!ISC_LINK_LINKED(li, plink));
1728 dns_name_free(&li->qname, adb->mctx);
1732 isc_mempool_put(adb->limp, li);
1735 static inline dns_adbentry_t *
1736 new_adbentry(dns_adb_t *adb) {
1740 e = isc_mempool_get(adb->emp);
1744 e->magic = DNS_ADBENTRY_MAGIC;
1745 e->lock_bucket = DNS_ADB_INVALIDBUCKET;
1749 e->srtt = (r & 0x1f) + 1;
1751 ISC_LIST_INIT(e->lameinfo);
1752 ISC_LINK_INIT(e, plink);
1753 LOCK(&adb->entriescntlock);
1755 if (!adb->growentries_sent &&
1756 adb->entriescnt > (adb->nentries * 8)) {
1757 isc_event_t *event = &adb->growentries;
1758 inc_adb_irefcnt(adb);
1759 isc_task_send(adb->task, &event);
1760 adb->growentries_sent = ISC_TRUE;
1762 UNLOCK(&adb->entriescntlock);
1768 free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
1770 dns_adblameinfo_t *li;
1772 INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
1776 INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
1777 INSIST(e->refcnt == 0);
1778 INSIST(!ISC_LINK_LINKED(e, plink));
1782 li = ISC_LIST_HEAD(e->lameinfo);
1783 while (li != NULL) {
1784 ISC_LIST_UNLINK(e->lameinfo, li, plink);
1785 free_adblameinfo(adb, &li);
1786 li = ISC_LIST_HEAD(e->lameinfo);
1789 isc_mempool_put(adb->emp, e);
1790 LOCK(&adb->entriescntlock);
1792 UNLOCK(&adb->entriescntlock);
1795 static inline dns_adbfind_t *
1796 new_adbfind(dns_adb_t *adb) {
1798 isc_result_t result;
1800 h = isc_mempool_get(adb->ahmp);
1809 h->partial_result = 0;
1812 h->result_v4 = ISC_R_UNEXPECTED;
1813 h->result_v6 = ISC_R_UNEXPECTED;
1814 ISC_LINK_INIT(h, publink);
1815 ISC_LINK_INIT(h, plink);
1816 ISC_LIST_INIT(h->list);
1818 h->name_bucket = DNS_ADB_INVALIDBUCKET;
1823 result = isc_mutex_init(&h->lock);
1824 if (result != ISC_R_SUCCESS) {
1825 isc_mempool_put(adb->ahmp, h);
1829 ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
1832 inc_adb_irefcnt(adb);
1833 h->magic = DNS_ADBFIND_MAGIC;
1837 static inline dns_adbfetch_t *
1838 new_adbfetch(dns_adb_t *adb) {
1841 f = isc_mempool_get(adb->afmp);
1848 dns_rdataset_init(&f->rdataset);
1850 f->magic = DNS_ADBFETCH_MAGIC;
1856 free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) {
1859 INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
1865 if (dns_rdataset_isassociated(&f->rdataset))
1866 dns_rdataset_disassociate(&f->rdataset);
1868 isc_mempool_put(adb->afmp, f);
1871 static inline isc_boolean_t
1872 free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
1873 dns_adbfind_t *find;
1875 INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
1879 INSIST(!FIND_HAS_ADDRS(find));
1880 INSIST(!ISC_LINK_LINKED(find, publink));
1881 INSIST(!ISC_LINK_LINKED(find, plink));
1882 INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
1883 INSIST(find->adbname == NULL);
1887 DESTROYLOCK(&find->lock);
1888 isc_mempool_put(adb->ahmp, find);
1889 return (dec_adb_irefcnt(adb));
1893 * Copy bits from the entry into the newly allocated addrinfo. The entry
1894 * must be locked, and the reference count must be bumped up by one
1895 * if this function returns a valid pointer.
1897 static inline dns_adbaddrinfo_t *
1898 new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
1899 dns_adbaddrinfo_t *ai;
1901 ai = isc_mempool_get(adb->aimp);
1905 ai->magic = DNS_ADBADDRINFO_MAGIC;
1906 ai->sockaddr = entry->sockaddr;
1907 isc_sockaddr_setport(&ai->sockaddr, port);
1908 ai->srtt = entry->srtt;
1909 ai->flags = entry->flags;
1911 ISC_LINK_INIT(ai, publink);
1917 free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
1918 dns_adbaddrinfo_t *ai;
1920 INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
1924 INSIST(ai->entry == NULL);
1925 INSIST(!ISC_LINK_LINKED(ai, publink));
1929 isc_mempool_put(adb->aimp, ai);
1933 * Search for the name. NOTE: The bucket is kept locked on both
1934 * success and failure, so it must always be unlocked by the caller!
1936 * On the first call to this function, *bucketp must be set to
1937 * DNS_ADB_INVALIDBUCKET.
1939 static inline dns_adbname_t *
1940 find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
1941 unsigned int options, int *bucketp)
1943 dns_adbname_t *adbname;
1946 bucket = dns_name_fullhash(name, ISC_FALSE) % adb->nnames;
1948 if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1949 LOCK(&adb->namelocks[bucket]);
1951 } else if (*bucketp != bucket) {
1952 UNLOCK(&adb->namelocks[*bucketp]);
1953 LOCK(&adb->namelocks[bucket]);
1957 adbname = ISC_LIST_HEAD(adb->names[bucket]);
1958 while (adbname != NULL) {
1959 if (!NAME_DEAD(adbname)) {
1960 if (dns_name_equal(name, &adbname->name)
1961 && GLUEHINT_OK(adbname, options)
1962 && STARTATZONE_MATCHES(adbname, options))
1965 adbname = ISC_LIST_NEXT(adbname, plink);
1972 * Search for the address. NOTE: The bucket is kept locked on both
1973 * success and failure, so it must always be unlocked by the caller.
1975 * On the first call to this function, *bucketp must be set to
1976 * DNS_ADB_INVALIDBUCKET. This will cause a lock to occur. On
1977 * later calls (within the same "lock path") it can be left alone, so
1978 * if this function is called multiple times locking is only done if
1979 * the bucket changes.
1981 static inline dns_adbentry_t *
1982 find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp,
1985 dns_adbentry_t *entry, *entry_next;
1988 bucket = isc_sockaddr_hash(addr, ISC_TRUE) % adb->nentries;
1990 if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1991 LOCK(&adb->entrylocks[bucket]);
1993 } else if (*bucketp != bucket) {
1994 UNLOCK(&adb->entrylocks[*bucketp]);
1995 LOCK(&adb->entrylocks[bucket]);
1999 /* Search the list, while cleaning up expired entries. */
2000 for (entry = ISC_LIST_HEAD(adb->entries[bucket]);
2002 entry = entry_next) {
2003 entry_next = ISC_LIST_NEXT(entry, plink);
2004 (void)check_expire_entry(adb, &entry, now);
2005 if (entry != NULL &&
2006 isc_sockaddr_equal(addr, &entry->sockaddr)) {
2007 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
2008 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
2017 * Entry bucket MUST be locked!
2019 static isc_boolean_t
2020 entry_is_lame(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *qname,
2021 dns_rdatatype_t qtype, isc_stdtime_t now)
2023 dns_adblameinfo_t *li, *next_li;
2024 isc_boolean_t is_bad;
2028 li = ISC_LIST_HEAD(entry->lameinfo);
2031 while (li != NULL) {
2032 next_li = ISC_LIST_NEXT(li, plink);
2035 * Has the entry expired?
2037 if (li->lame_timer < now) {
2038 ISC_LIST_UNLINK(entry->lameinfo, li, plink);
2039 free_adblameinfo(adb, &li);
2043 * Order tests from least to most expensive.
2045 * We do not break out of the main loop here as
2046 * we use the loop for house keeping.
2048 if (li != NULL && !is_bad && li->qtype == qtype &&
2049 dns_name_equal(qname, &li->qname))
2059 copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname,
2060 dns_rdatatype_t qtype, dns_adbname_t *name,
2063 dns_adbnamehook_t *namehook;
2064 dns_adbaddrinfo_t *addrinfo;
2065 dns_adbentry_t *entry;
2068 bucket = DNS_ADB_INVALIDBUCKET;
2070 if (find->options & DNS_ADBFIND_INET) {
2071 namehook = ISC_LIST_HEAD(name->v4);
2072 while (namehook != NULL) {
2073 entry = namehook->entry;
2074 bucket = entry->lock_bucket;
2075 LOCK(&adb->entrylocks[bucket]);
2077 if (!FIND_RETURNLAME(find)
2078 && entry_is_lame(adb, entry, qname, qtype, now)) {
2079 find->options |= DNS_ADBFIND_LAMEPRUNED;
2082 addrinfo = new_adbaddrinfo(adb, entry, find->port);
2083 if (addrinfo == NULL) {
2084 find->partial_result |= DNS_ADBFIND_INET;
2088 * Found a valid entry. Add it to the find's list.
2090 inc_entry_refcnt(adb, entry, ISC_FALSE);
2091 ISC_LIST_APPEND(find->list, addrinfo, publink);
2094 UNLOCK(&adb->entrylocks[bucket]);
2095 bucket = DNS_ADB_INVALIDBUCKET;
2096 namehook = ISC_LIST_NEXT(namehook, plink);
2100 if (find->options & DNS_ADBFIND_INET6) {
2101 namehook = ISC_LIST_HEAD(name->v6);
2102 while (namehook != NULL) {
2103 entry = namehook->entry;
2104 bucket = entry->lock_bucket;
2105 LOCK(&adb->entrylocks[bucket]);
2107 if (!FIND_RETURNLAME(find)
2108 && entry_is_lame(adb, entry, qname, qtype, now)) {
2109 find->options |= DNS_ADBFIND_LAMEPRUNED;
2112 addrinfo = new_adbaddrinfo(adb, entry, find->port);
2113 if (addrinfo == NULL) {
2114 find->partial_result |= DNS_ADBFIND_INET6;
2118 * Found a valid entry. Add it to the find's list.
2120 inc_entry_refcnt(adb, entry, ISC_FALSE);
2121 ISC_LIST_APPEND(find->list, addrinfo, publink);
2124 UNLOCK(&adb->entrylocks[bucket]);
2125 bucket = DNS_ADB_INVALIDBUCKET;
2126 namehook = ISC_LIST_NEXT(namehook, plink);
2131 if (bucket != DNS_ADB_INVALIDBUCKET)
2132 UNLOCK(&adb->entrylocks[bucket]);
2136 shutdown_task(isc_task_t *task, isc_event_t *ev) {
2142 INSIST(DNS_ADB_VALID(adb));
2144 isc_event_free(&ev);
2146 * Wait for lock around check_exit() call to be released.
2154 * Name bucket must be locked; adb may be locked; no other locks held.
2156 static isc_boolean_t
2157 check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
2158 dns_adbname_t *name;
2159 isc_boolean_t result = ISC_FALSE;
2161 INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
2164 if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
2166 if (NAME_FETCH(name))
2168 if (!EXPIRE_OK(name->expire_v4, now))
2170 if (!EXPIRE_OK(name->expire_v6, now))
2172 if (!EXPIRE_OK(name->expire_target, now))
2176 * The name is empty. Delete it.
2178 result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
2182 * Our caller, or one of its callers, will be calling check_exit() at
2183 * some point, so we don't need to do it here.
2189 * Examine the tail entry of the LRU list to see if it expires or is stale
2190 * (unused for some period); if so, the name entry will be freed. If the ADB
2191 * is in the overmem condition, the tail and the next to tail entries
2192 * will be unconditionally removed (unless they have an outstanding fetch).
2193 * We don't care about a race on 'overmem' at the risk of causing some
2194 * collateral damage or a small delay in starting cleanup, so we don't bother
2195 * to lock ADB (if it's not locked).
2197 * Name bucket must be locked; adb may be locked; no other locks held.
2200 check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2201 int victims, max_victims;
2202 dns_adbname_t *victim, *next_victim;
2203 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
2206 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2208 max_victims = overmem ? 2 : 1;
2211 * We limit the number of scanned entries to 10 (arbitrary choice)
2212 * in order to avoid examining too many entries when there are many
2213 * tail entries that have fetches (this should be rare, but could
2216 victim = ISC_LIST_TAIL(adb->names[bucket]);
2218 victim != NULL && victims < max_victims && scans < 10;
2219 victim = next_victim) {
2220 INSIST(!NAME_DEAD(victim));
2222 next_victim = ISC_LIST_PREV(victim, plink);
2223 (void)check_expire_name(&victim, now);
2224 if (victim == NULL) {
2229 if (!NAME_FETCH(victim) &&
2230 (overmem || victim->last_used + ADB_STALE_MARGIN <= now)) {
2231 RUNTIME_CHECK(kill_name(&victim,
2232 DNS_EVENT_ADBCANCELED) ==
2244 * Entry bucket must be locked; adb may be locked; no other locks held.
2246 static isc_boolean_t
2247 check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
2249 dns_adbentry_t *entry;
2250 isc_boolean_t result = ISC_FALSE;
2252 INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
2255 if (entry->refcnt != 0)
2258 if (entry->expires == 0 || entry->expires > now)
2262 * The entry is not in use. Delete it.
2264 DP(DEF_LEVEL, "killing entry %p", entry);
2265 INSIST(ISC_LINK_LINKED(entry, plink));
2266 result = unlink_entry(adb, entry);
2267 free_adbentry(adb, &entry);
2269 dec_adb_irefcnt(adb);
2275 * ADB must be locked, and no other locks held.
2277 static isc_boolean_t
2278 cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2279 dns_adbname_t *name;
2280 dns_adbname_t *next_name;
2281 isc_boolean_t result = ISC_FALSE;
2283 DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
2285 LOCK(&adb->namelocks[bucket]);
2286 if (adb->name_sd[bucket]) {
2287 UNLOCK(&adb->namelocks[bucket]);
2291 name = ISC_LIST_HEAD(adb->names[bucket]);
2292 while (name != NULL) {
2293 next_name = ISC_LIST_NEXT(name, plink);
2294 INSIST(result == ISC_FALSE);
2295 result = check_expire_namehooks(name, now);
2297 result = check_expire_name(&name, now);
2300 UNLOCK(&adb->namelocks[bucket]);
2305 * ADB must be locked, and no other locks held.
2307 static isc_boolean_t
2308 cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2309 dns_adbentry_t *entry, *next_entry;
2310 isc_boolean_t result = ISC_FALSE;
2312 DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
2314 LOCK(&adb->entrylocks[bucket]);
2315 entry = ISC_LIST_HEAD(adb->entries[bucket]);
2316 while (entry != NULL) {
2317 next_entry = ISC_LIST_NEXT(entry, plink);
2318 INSIST(result == ISC_FALSE);
2319 result = check_expire_entry(adb, &entry, now);
2322 UNLOCK(&adb->entrylocks[bucket]);
2327 destroy(dns_adb_t *adb) {
2330 isc_task_detach(&adb->task);
2332 isc_mempool_destroy(&adb->nmp);
2333 isc_mempool_destroy(&adb->nhmp);
2334 isc_mempool_destroy(&adb->limp);
2335 isc_mempool_destroy(&adb->emp);
2336 isc_mempool_destroy(&adb->ahmp);
2337 isc_mempool_destroy(&adb->aimp);
2338 isc_mempool_destroy(&adb->afmp);
2340 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
2341 isc_mem_put(adb->mctx, adb->entries,
2342 sizeof(*adb->entries) * adb->nentries);
2343 isc_mem_put(adb->mctx, adb->deadentries,
2344 sizeof(*adb->deadentries) * adb->nentries);
2345 isc_mem_put(adb->mctx, adb->entrylocks,
2346 sizeof(*adb->entrylocks) * adb->nentries);
2347 isc_mem_put(adb->mctx, adb->entry_sd,
2348 sizeof(*adb->entry_sd) * adb->nentries);
2349 isc_mem_put(adb->mctx, adb->entry_refcnt,
2350 sizeof(*adb->entry_refcnt) * adb->nentries);
2352 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
2353 isc_mem_put(adb->mctx, adb->names,
2354 sizeof(*adb->names) * adb->nnames);
2355 isc_mem_put(adb->mctx, adb->deadnames,
2356 sizeof(*adb->deadnames) * adb->nnames);
2357 isc_mem_put(adb->mctx, adb->namelocks,
2358 sizeof(*adb->namelocks) * adb->nnames);
2359 isc_mem_put(adb->mctx, adb->name_sd,
2360 sizeof(*adb->name_sd) * adb->nnames);
2361 isc_mem_put(adb->mctx, adb->name_refcnt,
2362 sizeof(*adb->name_refcnt) * adb->nnames);
2364 DESTROYLOCK(&adb->reflock);
2365 DESTROYLOCK(&adb->lock);
2366 DESTROYLOCK(&adb->mplock);
2367 DESTROYLOCK(&adb->overmemlock);
2368 DESTROYLOCK(&adb->entriescntlock);
2369 DESTROYLOCK(&adb->namescntlock);
2371 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2380 dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
2381 isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
2384 isc_result_t result;
2387 REQUIRE(mem != NULL);
2388 REQUIRE(view != NULL);
2389 REQUIRE(timermgr != NULL); /* this is actually unused */
2390 REQUIRE(taskmgr != NULL);
2391 REQUIRE(newadb != NULL && *newadb == NULL);
2395 adb = isc_mem_get(mem, sizeof(dns_adb_t));
2397 return (ISC_R_NOMEMORY);
2400 * Initialize things here that cannot fail, and especially things
2401 * that must be NULL for the error return to work properly.
2416 adb->taskmgr = taskmgr;
2417 adb->next_cleanbucket = 0;
2418 ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
2419 DNS_EVENT_ADBCONTROL, shutdown_task, adb,
2421 adb->cevent_sent = ISC_FALSE;
2422 adb->shutting_down = ISC_FALSE;
2423 ISC_LIST_INIT(adb->whenshutdown);
2425 adb->nentries = nbuckets[0];
2426 adb->entriescnt = 0;
2427 adb->entries = NULL;
2428 adb->deadentries = NULL;
2429 adb->entry_sd = NULL;
2430 adb->entry_refcnt = NULL;
2431 adb->entrylocks = NULL;
2432 ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL,
2433 DNS_EVENT_ADBGROWENTRIES, grow_entries, adb,
2435 adb->growentries_sent = ISC_FALSE;
2437 adb->nnames = nbuckets[0];
2440 adb->deadnames = NULL;
2441 adb->name_sd = NULL;
2442 adb->name_refcnt = NULL;
2443 adb->namelocks = NULL;
2444 ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL,
2445 DNS_EVENT_ADBGROWNAMES, grow_names, adb,
2447 adb->grownames_sent = ISC_FALSE;
2449 isc_mem_attach(mem, &adb->mctx);
2451 result = isc_mutex_init(&adb->lock);
2452 if (result != ISC_R_SUCCESS)
2455 result = isc_mutex_init(&adb->mplock);
2456 if (result != ISC_R_SUCCESS)
2459 result = isc_mutex_init(&adb->reflock);
2460 if (result != ISC_R_SUCCESS)
2463 result = isc_mutex_init(&adb->overmemlock);
2464 if (result != ISC_R_SUCCESS)
2467 result = isc_mutex_init(&adb->entriescntlock);
2468 if (result != ISC_R_SUCCESS)
2471 result = isc_mutex_init(&adb->namescntlock);
2472 if (result != ISC_R_SUCCESS)
2475 #define ALLOCENTRY(adb, el) \
2477 (adb)->el = isc_mem_get((adb)->mctx, \
2478 sizeof(*(adb)->el) * (adb)->nentries); \
2479 if ((adb)->el == NULL) { \
2480 result = ISC_R_NOMEMORY; \
2484 ALLOCENTRY(adb, entries);
2485 ALLOCENTRY(adb, deadentries);
2486 ALLOCENTRY(adb, entrylocks);
2487 ALLOCENTRY(adb, entry_sd);
2488 ALLOCENTRY(adb, entry_refcnt);
2491 #define ALLOCNAME(adb, el) \
2493 (adb)->el = isc_mem_get((adb)->mctx, \
2494 sizeof(*(adb)->el) * (adb)->nnames); \
2495 if ((adb)->el == NULL) { \
2496 result = ISC_R_NOMEMORY; \
2500 ALLOCNAME(adb, names);
2501 ALLOCNAME(adb, deadnames);
2502 ALLOCNAME(adb, namelocks);
2503 ALLOCNAME(adb, name_sd);
2504 ALLOCNAME(adb, name_refcnt);
2508 * Initialize the bucket locks for names and elements.
2509 * May as well initialize the list heads, too.
2511 result = isc_mutexblock_init(adb->namelocks, adb->nnames);
2512 if (result != ISC_R_SUCCESS)
2514 for (i = 0; i < adb->nnames; i++) {
2515 ISC_LIST_INIT(adb->names[i]);
2516 ISC_LIST_INIT(adb->deadnames[i]);
2517 adb->name_sd[i] = ISC_FALSE;
2518 adb->name_refcnt[i] = 0;
2521 for (i = 0; i < adb->nentries; i++) {
2522 ISC_LIST_INIT(adb->entries[i]);
2523 ISC_LIST_INIT(adb->deadentries[i]);
2524 adb->entry_sd[i] = ISC_FALSE;
2525 adb->entry_refcnt[i] = 0;
2528 result = isc_mutexblock_init(adb->entrylocks, adb->nentries);
2529 if (result != ISC_R_SUCCESS)
2535 #define MPINIT(t, p, n) do { \
2536 result = isc_mempool_create(mem, sizeof(t), &(p)); \
2537 if (result != ISC_R_SUCCESS) \
2539 isc_mempool_setfreemax((p), FREE_ITEMS); \
2540 isc_mempool_setfillcount((p), FILL_COUNT); \
2541 isc_mempool_setname((p), n); \
2542 isc_mempool_associatelock((p), &adb->mplock); \
2545 MPINIT(dns_adbname_t, adb->nmp, "adbname");
2546 MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
2547 MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo");
2548 MPINIT(dns_adbentry_t, adb->emp, "adbentry");
2549 MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
2550 MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
2551 MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
2556 * Allocate an internal task.
2558 result = isc_task_create(adb->taskmgr, 0, &adb->task);
2559 if (result != ISC_R_SUCCESS)
2561 isc_task_setname(adb->task, "ADB", adb);
2566 adb->magic = DNS_ADB_MAGIC;
2568 return (ISC_R_SUCCESS);
2571 if (adb->task != NULL)
2572 isc_task_detach(&adb->task);
2574 /* clean up entrylocks */
2575 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
2577 fail2: /* clean up namelocks */
2578 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
2580 fail1: /* clean up only allocated memory */
2581 if (adb->entries != NULL)
2582 isc_mem_put(adb->mctx, adb->entries,
2583 sizeof(*adb->entries) * adb->nentries);
2584 if (adb->deadentries != NULL)
2585 isc_mem_put(adb->mctx, adb->deadentries,
2586 sizeof(*adb->deadentries) * adb->nentries);
2587 if (adb->entrylocks != NULL)
2588 isc_mem_put(adb->mctx, adb->entrylocks,
2589 sizeof(*adb->entrylocks) * adb->nentries);
2590 if (adb->entry_sd != NULL)
2591 isc_mem_put(adb->mctx, adb->entry_sd,
2592 sizeof(*adb->entry_sd) * adb->nentries);
2593 if (adb->entry_refcnt != NULL)
2594 isc_mem_put(adb->mctx, adb->entry_refcnt,
2595 sizeof(*adb->entry_refcnt) * adb->nentries);
2596 if (adb->names != NULL)
2597 isc_mem_put(adb->mctx, adb->names,
2598 sizeof(*adb->names) * adb->nnames);
2599 if (adb->deadnames != NULL)
2600 isc_mem_put(adb->mctx, adb->deadnames,
2601 sizeof(*adb->deadnames) * adb->nnames);
2602 if (adb->namelocks != NULL)
2603 isc_mem_put(adb->mctx, adb->namelocks,
2604 sizeof(*adb->namelocks) * adb->nnames);
2605 if (adb->name_sd != NULL)
2606 isc_mem_put(adb->mctx, adb->name_sd,
2607 sizeof(*adb->name_sd) * adb->nnames);
2608 if (adb->name_refcnt != NULL)
2609 isc_mem_put(adb->mctx, adb->name_refcnt,
2610 sizeof(*adb->name_refcnt) * adb->nnames);
2611 if (adb->nmp != NULL)
2612 isc_mempool_destroy(&adb->nmp);
2613 if (adb->nhmp != NULL)
2614 isc_mempool_destroy(&adb->nhmp);
2615 if (adb->limp != NULL)
2616 isc_mempool_destroy(&adb->limp);
2617 if (adb->emp != NULL)
2618 isc_mempool_destroy(&adb->emp);
2619 if (adb->ahmp != NULL)
2620 isc_mempool_destroy(&adb->ahmp);
2621 if (adb->aimp != NULL)
2622 isc_mempool_destroy(&adb->aimp);
2623 if (adb->afmp != NULL)
2624 isc_mempool_destroy(&adb->afmp);
2626 DESTROYLOCK(&adb->namescntlock);
2628 DESTROYLOCK(&adb->entriescntlock);
2630 DESTROYLOCK(&adb->overmemlock);
2632 DESTROYLOCK(&adb->reflock);
2634 DESTROYLOCK(&adb->mplock);
2636 DESTROYLOCK(&adb->lock);
2638 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2644 dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
2646 REQUIRE(DNS_ADB_VALID(adb));
2647 REQUIRE(adbx != NULL && *adbx == NULL);
2649 inc_adb_erefcnt(adb);
2654 dns_adb_detach(dns_adb_t **adbx) {
2656 isc_boolean_t need_exit_check;
2658 REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
2663 INSIST(adb->erefcnt > 0);
2665 LOCK(&adb->reflock);
2667 need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
2668 UNLOCK(&adb->reflock);
2670 if (need_exit_check) {
2672 INSIST(adb->shutting_down);
2679 dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
2682 isc_boolean_t zeroirefcnt = ISC_FALSE;
2685 * Send '*eventp' to 'task' when 'adb' has shutdown.
2688 REQUIRE(DNS_ADB_VALID(adb));
2689 REQUIRE(eventp != NULL);
2696 LOCK(&adb->reflock);
2697 zeroirefcnt = ISC_TF(adb->irefcnt == 0);
2699 if (adb->shutting_down && zeroirefcnt &&
2700 isc_mempool_getallocated(adb->ahmp) == 0) {
2702 * We're already shutdown. Send the event.
2704 event->ev_sender = adb;
2705 isc_task_send(task, &event);
2708 isc_task_attach(task, &clone);
2709 event->ev_sender = clone;
2710 ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
2713 UNLOCK(&adb->reflock);
2718 dns_adb_shutdown(dns_adb_t *adb) {
2719 isc_boolean_t need_check_exit;
2727 if (!adb->shutting_down) {
2728 adb->shutting_down = ISC_TRUE;
2729 isc_mem_setwater(adb->mctx, water, adb, 0, 0);
2730 need_check_exit = shutdown_names(adb);
2731 if (!need_check_exit)
2732 need_check_exit = shutdown_entries(adb);
2733 if (need_check_exit)
2741 dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
2742 void *arg, dns_name_t *name, dns_name_t *qname,
2743 dns_rdatatype_t qtype, unsigned int options,
2744 isc_stdtime_t now, dns_name_t *target,
2745 in_port_t port, dns_adbfind_t **findp)
2747 return (dns_adb_createfind2(adb, task, action, arg, name,
2748 qname, qtype, options, now,
2749 target, port, 0, NULL, findp));
2753 dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
2754 void *arg, dns_name_t *name, dns_name_t *qname,
2755 dns_rdatatype_t qtype, unsigned int options,
2756 isc_stdtime_t now, dns_name_t *target,
2757 in_port_t port, unsigned int depth, isc_counter_t *qc,
2758 dns_adbfind_t **findp)
2760 dns_adbfind_t *find;
2761 dns_adbname_t *adbname;
2763 isc_boolean_t want_event, start_at_zone, alias, have_address;
2764 isc_result_t result;
2765 unsigned int wanted_addresses;
2766 unsigned int wanted_fetches;
2767 unsigned int query_pending;
2769 REQUIRE(DNS_ADB_VALID(adb));
2771 REQUIRE(action != NULL);
2773 REQUIRE(name != NULL);
2774 REQUIRE(qname != NULL);
2775 REQUIRE(findp != NULL && *findp == NULL);
2776 REQUIRE(target == NULL || dns_name_hasbuffer(target));
2778 REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
2780 result = ISC_R_UNEXPECTED;
2782 wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
2785 want_event = ISC_FALSE;
2786 start_at_zone = ISC_FALSE;
2790 isc_stdtime_get(&now);
2793 * XXXMLG Move this comment somewhere else!
2795 * Look up the name in our internal database.
2797 * Possibilities: Note that these are not always exclusive.
2799 * No name found. In this case, allocate a new name header and
2800 * an initial namehook or two. If any of these allocations
2801 * fail, clean up and return ISC_R_NOMEMORY.
2803 * Name found, valid addresses present. Allocate one addrinfo
2804 * structure for each found and append it to the linked list
2805 * of addresses for this header.
2807 * Name found, queries pending. In this case, if a task was
2808 * passed in, allocate a job id, attach it to the name's job
2809 * list and remember to tell the caller that there will be
2810 * more info coming later.
2813 find = new_adbfind(adb);
2815 return (ISC_R_NOMEMORY);
2820 * Remember what types of addresses we are interested in.
2822 find->options = options;
2823 find->flags |= wanted_addresses;
2824 if (FIND_WANTEVENT(find)) {
2825 REQUIRE(task != NULL);
2829 * Try to see if we know anything about this name at all.
2831 bucket = DNS_ADB_INVALIDBUCKET;
2832 adbname = find_name_and_lock(adb, name, find->options, &bucket);
2833 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2834 if (adb->name_sd[bucket]) {
2836 "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
2837 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2838 result = ISC_R_SHUTTINGDOWN;
2843 * Nothing found. Allocate a new adbname structure for this name.
2845 if (adbname == NULL) {
2847 * See if there is any stale name at the end of list, and purge
2850 check_stale_name(adb, bucket, now);
2852 adbname = new_adbname(adb, name);
2853 if (adbname == NULL) {
2854 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2855 result = ISC_R_NOMEMORY;
2858 link_name(adb, bucket, adbname);
2859 if (FIND_HINTOK(find))
2860 adbname->flags |= NAME_HINT_OK;
2861 if (FIND_GLUEOK(find))
2862 adbname->flags |= NAME_GLUE_OK;
2863 if (FIND_STARTATZONE(find))
2864 adbname->flags |= NAME_STARTATZONE;
2866 /* Move this name forward in the LRU list */
2867 ISC_LIST_UNLINK(adb->names[bucket], adbname, plink);
2868 ISC_LIST_PREPEND(adb->names[bucket], adbname, plink);
2870 adbname->last_used = now;
2873 * Expire old entries, etc.
2875 RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE);
2878 * Do we know that the name is an alias?
2880 if (!EXPIRE_OK(adbname->expire_target, now)) {
2885 "dns_adb_createfind: name %p is an alias (cached)",
2892 * Try to populate the name from the database and/or
2893 * start fetches. First try looking for an A record
2896 if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
2897 && WANT_INET(wanted_addresses)) {
2898 result = dbfind_name(adbname, now, dns_rdatatype_a);
2899 if (result == ISC_R_SUCCESS) {
2901 "dns_adb_createfind: found A for name %p in db",
2907 * Did we get a CNAME or DNAME?
2909 if (result == DNS_R_ALIAS) {
2911 "dns_adb_createfind: name %p is an alias",
2918 * If the name doesn't exist at all, don't bother with
2919 * v6 queries; they won't work.
2921 * If the name does exist but we didn't get our data, go
2922 * ahead and try AAAA.
2924 * If the result is neither of these, try a fetch for A.
2926 if (NXDOMAIN_RESULT(result))
2928 else if (NXRRSET_RESULT(result))
2931 if (!NAME_FETCH_V4(adbname))
2932 wanted_fetches |= DNS_ADBFIND_INET;
2936 if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
2937 && WANT_INET6(wanted_addresses)) {
2938 result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
2939 if (result == ISC_R_SUCCESS) {
2941 "dns_adb_createfind: found AAAA for name %p",
2947 * Did we get a CNAME or DNAME?
2949 if (result == DNS_R_ALIAS) {
2951 "dns_adb_createfind: name %p is an alias",
2958 * Listen to negative cache hints, and don't start
2961 if (NCACHE_RESULT(result) || AUTH_NX(result))
2964 if (!NAME_FETCH_V6(adbname))
2965 wanted_fetches |= DNS_ADBFIND_INET6;
2969 if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
2970 (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
2971 have_address = ISC_TRUE;
2973 have_address = ISC_FALSE;
2974 if (wanted_fetches != 0 &&
2975 ! (FIND_AVOIDFETCHES(find) && have_address)) {
2977 * We're missing at least one address family. Either the
2978 * caller hasn't instructed us to avoid fetches, or we don't
2979 * know anything about any of the address families that would
2980 * be acceptable so we have to launch fetches.
2983 if (FIND_STARTATZONE(find))
2984 start_at_zone = ISC_TRUE;
2989 if (WANT_INET(wanted_fetches) &&
2990 fetch_name(adbname, start_at_zone, depth, qc,
2991 dns_rdatatype_a) == ISC_R_SUCCESS) {
2993 "dns_adb_createfind: started A fetch for name %p",
3000 if (WANT_INET6(wanted_fetches) &&
3001 fetch_name(adbname, start_at_zone, depth, qc,
3002 dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
3004 "dns_adb_createfind: "
3005 "started AAAA fetch for name %p",
3011 * Run through the name and copy out the bits we are
3014 copy_namehook_lists(adb, find, qname, qtype, adbname, now);
3017 if (NAME_FETCH_V4(adbname))
3018 query_pending |= DNS_ADBFIND_INET;
3019 if (NAME_FETCH_V6(adbname))
3020 query_pending |= DNS_ADBFIND_INET6;
3023 * Attach to the name's query list if there are queries
3024 * already running, and we have been asked to.
3026 want_event = ISC_TRUE;
3027 if (!FIND_WANTEVENT(find))
3028 want_event = ISC_FALSE;
3029 if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
3030 want_event = ISC_FALSE;
3031 if ((wanted_addresses & query_pending) == 0)
3032 want_event = ISC_FALSE;
3034 want_event = ISC_FALSE;
3036 find->adbname = adbname;
3037 find->name_bucket = bucket;
3038 ISC_LIST_APPEND(adbname->finds, find, plink);
3039 find->query_pending = (query_pending & wanted_addresses);
3040 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
3041 find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
3042 DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
3046 * Remove the flag so the caller knows there will never
3047 * be an event, and set internal flags to fake that
3048 * the event was sent and freed, so dns_adb_destroyfind() will
3049 * do the right thing.
3051 find->query_pending = (query_pending & wanted_addresses);
3052 find->options &= ~DNS_ADBFIND_WANTEVENT;
3053 find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
3054 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
3057 find->partial_result |= (adbname->partial_result & wanted_addresses);
3059 if (target != NULL) {
3060 result = dns_name_copy(&adbname->target, target, NULL);
3061 if (result != ISC_R_SUCCESS)
3064 result = DNS_R_ALIAS;
3066 result = ISC_R_SUCCESS;
3069 * Copy out error flags from the name structure into the find.
3071 find->result_v4 = find_err_map[adbname->fetch_err];
3072 find->result_v6 = find_err_map[adbname->fetch6_err];
3081 INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
3083 isc_task_attach(task, &taskp);
3084 find->event.ev_sender = taskp;
3085 find->event.ev_action = action;
3086 find->event.ev_arg = arg;
3090 UNLOCK(&adb->namelocks[bucket]);
3096 dns_adb_destroyfind(dns_adbfind_t **findp) {
3097 dns_adbfind_t *find;
3098 dns_adbentry_t *entry;
3099 dns_adbaddrinfo_t *ai;
3102 isc_boolean_t overmem;
3104 REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
3110 DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
3113 REQUIRE(DNS_ADB_VALID(adb));
3115 REQUIRE(FIND_EVENTFREED(find));
3117 bucket = find->name_bucket;
3118 INSIST(bucket == DNS_ADB_INVALIDBUCKET);
3120 UNLOCK(&find->lock);
3123 * The find doesn't exist on any list, and nothing is locked.
3124 * Return the find to the memory pool, and decrement the adb's
3127 overmem = isc_mem_isovermem(adb->mctx);
3128 ai = ISC_LIST_HEAD(find->list);
3129 while (ai != NULL) {
3130 ISC_LIST_UNLINK(find->list, ai, publink);
3133 INSIST(DNS_ADBENTRY_VALID(entry));
3134 RUNTIME_CHECK(dec_entry_refcnt(adb, overmem, entry, ISC_TRUE) ==
3136 free_adbaddrinfo(adb, &ai);
3137 ai = ISC_LIST_HEAD(find->list);
3141 * WARNING: The find is freed with the adb locked. This is done
3142 * to avoid a race condition where we free the find, some other
3143 * thread tests to see if it should be destroyed, detects it should
3144 * be, destroys it, and then we try to lock it for our check, but the
3145 * lock is destroyed.
3148 if (free_adbfind(adb, &find))
3154 dns_adb_cancelfind(dns_adbfind_t *find) {
3163 DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
3166 REQUIRE(DNS_ADB_VALID(adb));
3168 REQUIRE(!FIND_EVENTFREED(find));
3169 REQUIRE(FIND_WANTEVENT(find));
3171 bucket = find->name_bucket;
3172 if (bucket == DNS_ADB_INVALIDBUCKET)
3176 * We need to get the adbname's lock to unlink the find.
3178 unlock_bucket = bucket;
3179 violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
3180 bucket = find->name_bucket;
3181 if (bucket != DNS_ADB_INVALIDBUCKET) {
3182 ISC_LIST_UNLINK(find->adbname->finds, find, plink);
3183 find->adbname = NULL;
3184 find->name_bucket = DNS_ADB_INVALIDBUCKET;
3186 UNLOCK(&adb->namelocks[unlock_bucket]);
3187 bucket = DNS_ADB_INVALIDBUCKET;
3192 if (!FIND_EVENTSENT(find)) {
3194 task = ev->ev_sender;
3195 ev->ev_sender = find;
3196 ev->ev_type = DNS_EVENT_ADBCANCELED;
3197 ev->ev_destroy = event_free;
3198 ev->ev_destroy_arg = find;
3199 find->result_v4 = ISC_R_CANCELED;
3200 find->result_v6 = ISC_R_CANCELED;
3202 DP(DEF_LEVEL, "sending event %p to task %p for find %p",
3205 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
3208 UNLOCK(&find->lock);
3212 dns_adb_dump(dns_adb_t *adb, FILE *f) {
3216 REQUIRE(DNS_ADB_VALID(adb));
3220 * Lock the adb itself, lock all the name buckets, then lock all
3221 * the entry buckets. This should put the adb into a state where
3222 * nothing can change, so we can iterate through everything and
3223 * print at our leisure.
3227 isc_stdtime_get(&now);
3229 for (i = 0; i < adb->nnames; i++)
3230 RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE);
3231 for (i = 0; i < adb->nentries; i++)
3232 RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE);
3234 dump_adb(adb, f, ISC_FALSE, now);
3239 dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
3240 if (value == INT_MAX)
3242 fprintf(f, " [%s TTL %d]", legend, value - now);
3246 dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
3248 dns_adbname_t *name;
3249 dns_adbentry_t *entry;
3251 fprintf(f, ";\n; Address database dump\n;\n");
3253 fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
3254 adb, adb->erefcnt, adb->irefcnt,
3255 isc_mempool_getallocated(adb->nhmp));
3257 for (i = 0; i < adb->nnames; i++)
3258 LOCK(&adb->namelocks[i]);
3259 for (i = 0; i < adb->nentries; i++)
3260 LOCK(&adb->entrylocks[i]);
3265 for (i = 0; i < adb->nnames; i++) {
3266 name = ISC_LIST_HEAD(adb->names[i]);
3270 fprintf(f, "; bucket %d\n", i);
3273 name = ISC_LIST_NEXT(name, plink))
3276 fprintf(f, "; name %p (flags %08x)\n",
3280 print_dns_name(f, &name->name);
3281 if (dns_name_countlabels(&name->target) > 0) {
3282 fprintf(f, " alias ");
3283 print_dns_name(f, &name->target);
3286 dump_ttl(f, "v4", name->expire_v4, now);
3287 dump_ttl(f, "v6", name->expire_v6, now);
3288 dump_ttl(f, "target", name->expire_target, now);
3290 fprintf(f, " [v4 %s] [v6 %s]",
3291 errnames[name->fetch_err],
3292 errnames[name->fetch6_err]);
3296 print_namehook_list(f, "v4", &name->v4, debug, now);
3297 print_namehook_list(f, "v6", &name->v6, debug, now);
3300 print_fetch_list(f, name);
3302 print_find_list(f, name);
3307 fprintf(f, ";\n; Unassociated entries\n;\n");
3309 for (i = 0; i < adb->nentries; i++) {
3310 entry = ISC_LIST_HEAD(adb->entries[i]);
3311 while (entry != NULL) {
3312 if (entry->refcnt == 0)
3313 dump_entry(f, entry, debug, now);
3314 entry = ISC_LIST_NEXT(entry, plink);
3321 for (i = 0; i < adb->nentries; i++)
3322 UNLOCK(&adb->entrylocks[i]);
3323 for (i = 0; i < adb->nnames; i++)
3324 UNLOCK(&adb->namelocks[i]);
3328 dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug,
3331 char addrbuf[ISC_NETADDR_FORMATSIZE];
3332 char typebuf[DNS_RDATATYPE_FORMATSIZE];
3333 isc_netaddr_t netaddr;
3334 dns_adblameinfo_t *li;
3336 isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
3337 isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
3340 fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
3342 fprintf(f, ";\t%s [srtt %u] [flags %08x]",
3343 addrbuf, entry->srtt, entry->flags);
3344 if (entry->expires != 0)
3345 fprintf(f, " [ttl %d]", entry->expires - now);
3347 for (li = ISC_LIST_HEAD(entry->lameinfo);
3349 li = ISC_LIST_NEXT(li, plink)) {
3350 fprintf(f, ";\t\t");
3351 print_dns_name(f, &li->qname);
3352 dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf));
3353 fprintf(f, " %s [lame TTL %d]\n", typebuf,
3354 li->lame_timer - now);
3359 dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
3362 dns_adbaddrinfo_t *ai;
3366 * Not used currently, in the API Just In Case we
3367 * want to dump out the name and/or entries too.
3372 fprintf(f, ";Find %p\n", find);
3373 fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
3374 find->query_pending, find->partial_result,
3375 find->options, find->flags);
3376 fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
3377 find->name_bucket, find->adbname, find->event.ev_sender);
3379 ai = ISC_LIST_HEAD(find->list);
3381 fprintf(f, "\tAddresses:\n");
3382 while (ai != NULL) {
3384 switch (sa->type.sa.sa_family) {
3386 tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
3390 tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
3398 tmpp = "BadAddress";
3400 fprintf(f, "\t\tentry %p, flags %08x"
3401 " srtt %u addr %s\n",
3402 ai->entry, ai->flags, ai->srtt, tmpp);
3404 ai = ISC_LIST_NEXT(ai, publink);
3407 UNLOCK(&find->lock);
3411 print_dns_name(FILE *f, dns_name_t *name) {
3412 char buf[DNS_NAME_FORMATSIZE];
3416 dns_name_format(name, buf, sizeof(buf));
3417 fprintf(f, "%s", buf);
3421 print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list,
3422 isc_boolean_t debug, isc_stdtime_t now)
3424 dns_adbnamehook_t *nh;
3426 for (nh = ISC_LIST_HEAD(*list);
3428 nh = ISC_LIST_NEXT(nh, plink))
3431 fprintf(f, ";\tHook(%s) %p\n", legend, nh);
3432 dump_entry(f, nh->entry, debug, now);
3437 print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) {
3438 fprintf(f, "\t\tFetch(%s): %p -> { fetch %p }\n",
3439 type, ft, ft->fetch);
3443 print_fetch_list(FILE *f, dns_adbname_t *n) {
3444 if (NAME_FETCH_A(n))
3445 print_fetch(f, n->fetch_a, "A");
3446 if (NAME_FETCH_AAAA(n))
3447 print_fetch(f, n->fetch_aaaa, "AAAA");
3451 print_find_list(FILE *f, dns_adbname_t *name) {
3452 dns_adbfind_t *find;
3454 find = ISC_LIST_HEAD(name->finds);
3455 while (find != NULL) {
3456 dns_adb_dumpfind(find, f);
3457 find = ISC_LIST_NEXT(find, plink);
3462 dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype)
3464 isc_result_t result;
3465 dns_rdataset_t rdataset;
3467 dns_fixedname_t foundname;
3470 INSIST(DNS_ADBNAME_VALID(adbname));
3472 INSIST(DNS_ADB_VALID(adb));
3473 INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
3475 dns_fixedname_init(&foundname);
3476 fname = dns_fixedname_name(&foundname);
3477 dns_rdataset_init(&rdataset);
3479 if (rdtype == dns_rdatatype_a)
3480 adbname->fetch_err = FIND_ERR_UNEXPECTED;
3482 adbname->fetch6_err = FIND_ERR_UNEXPECTED;
3485 * We need to specify whether to search static-stub zones (if
3486 * configured) depending on whether this is a "start at zone" lookup,
3487 * i.e., whether it's a "bailiwick" glue. If it's bailiwick (in which
3488 * case NAME_STARTATZONE is set) we need to stop the search at any
3489 * matching static-stub zone without looking into the cache to honor
3490 * the configuration on which server we should send queries to.
3492 result = dns_view_find2(adb->view, &adbname->name, rdtype, now,
3493 NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0,
3494 ISC_TF(NAME_HINTOK(adbname)),
3495 (adbname->flags & NAME_STARTATZONE) != 0 ?
3496 ISC_TRUE : ISC_FALSE,
3497 NULL, NULL, fname, &rdataset, NULL);
3499 /* XXXVIX this switch statement is too sparse to gen a jump table. */
3505 * Found in the database. Even if we can't copy out
3506 * any information, return success, or else a fetch
3507 * will be made, which will only make things worse.
3509 if (rdtype == dns_rdatatype_a)
3510 adbname->fetch_err = FIND_ERR_SUCCESS;
3512 adbname->fetch6_err = FIND_ERR_SUCCESS;
3513 result = import_rdataset(adbname, &rdataset, now);
3515 case DNS_R_NXDOMAIN:
3518 * We're authoritative and the data doesn't exist.
3519 * Make up a negative cache entry so we don't ask again
3522 * XXXRTH What time should we use? I'm putting in 30 seconds
3525 if (rdtype == dns_rdatatype_a) {
3526 adbname->expire_v4 = now + 30;
3528 "adb name %p: Caching auth negative entry for A",
3530 if (result == DNS_R_NXDOMAIN)
3531 adbname->fetch_err = FIND_ERR_NXDOMAIN;
3533 adbname->fetch_err = FIND_ERR_NXRRSET;
3536 "adb name %p: Caching auth negative entry for AAAA",
3538 adbname->expire_v6 = now + 30;
3539 if (result == DNS_R_NXDOMAIN)
3540 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3542 adbname->fetch6_err = FIND_ERR_NXRRSET;
3545 case DNS_R_NCACHENXDOMAIN:
3546 case DNS_R_NCACHENXRRSET:
3548 * We found a negative cache entry. Pull the TTL from it
3549 * so we won't ask again for a while.
3551 rdataset.ttl = ttlclamp(rdataset.ttl);
3552 if (rdtype == dns_rdatatype_a) {
3553 adbname->expire_v4 = rdataset.ttl + now;
3554 if (result == DNS_R_NCACHENXDOMAIN)
3555 adbname->fetch_err = FIND_ERR_NXDOMAIN;
3557 adbname->fetch_err = FIND_ERR_NXRRSET;
3559 "adb name %p: Caching negative entry for A (ttl %u)",
3560 adbname, rdataset.ttl);
3563 "adb name %p: Caching negative entry for AAAA (ttl %u)",
3564 adbname, rdataset.ttl);
3565 adbname->expire_v6 = rdataset.ttl + now;
3566 if (result == DNS_R_NCACHENXDOMAIN)
3567 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3569 adbname->fetch6_err = FIND_ERR_NXRRSET;
3575 * Clear the hint and glue flags, so this will match
3578 adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
3580 rdataset.ttl = ttlclamp(rdataset.ttl);
3581 clean_target(adb, &adbname->target);
3582 adbname->expire_target = INT_MAX;
3583 result = set_target(adb, &adbname->name, fname, &rdataset,
3585 if (result == ISC_R_SUCCESS) {
3586 result = DNS_R_ALIAS;
3588 "adb name %p: caching alias target",
3590 adbname->expire_target = rdataset.ttl + now;
3592 if (rdtype == dns_rdatatype_a)
3593 adbname->fetch_err = FIND_ERR_SUCCESS;
3595 adbname->fetch6_err = FIND_ERR_SUCCESS;
3599 if (dns_rdataset_isassociated(&rdataset))
3600 dns_rdataset_disassociate(&rdataset);
3606 fetch_callback(isc_task_t *task, isc_event_t *ev) {
3607 dns_fetchevent_t *dev;
3608 dns_adbname_t *name;
3610 dns_adbfetch_t *fetch;
3612 isc_eventtype_t ev_status;
3614 isc_result_t result;
3615 unsigned int address_type;
3616 isc_boolean_t want_check_exit = ISC_FALSE;
3620 INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
3621 dev = (dns_fetchevent_t *)ev;
3623 INSIST(DNS_ADBNAME_VALID(name));
3625 INSIST(DNS_ADB_VALID(adb));
3627 bucket = name->lock_bucket;
3628 LOCK(&adb->namelocks[bucket]);
3630 INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
3632 if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
3633 address_type = DNS_ADBFIND_INET;
3634 fetch = name->fetch_a;
3635 name->fetch_a = NULL;
3636 } else if (NAME_FETCH_AAAA(name)
3637 && (name->fetch_aaaa->fetch == dev->fetch)) {
3638 address_type = DNS_ADBFIND_INET6;
3639 fetch = name->fetch_aaaa;
3640 name->fetch_aaaa = NULL;
3644 INSIST(address_type != 0 && fetch != NULL);
3646 dns_resolver_destroyfetch(&fetch->fetch);
3649 ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
3652 * Cleanup things we don't care about.
3654 if (dev->node != NULL)
3655 dns_db_detachnode(dev->db, &dev->node);
3656 if (dev->db != NULL)
3657 dns_db_detach(&dev->db);
3660 * If this name is marked as dead, clean up, throwing away
3661 * potentially good data.
3663 if (NAME_DEAD(name)) {
3664 free_adbfetch(adb, &fetch);
3665 isc_event_free(&ev);
3667 want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
3669 UNLOCK(&adb->namelocks[bucket]);
3671 if (want_check_exit) {
3680 isc_stdtime_get(&now);
3683 * If we got a negative cache response, remember it.
3685 if (NCACHE_RESULT(dev->result)) {
3686 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3687 if (address_type == DNS_ADBFIND_INET) {
3688 DP(NCACHE_LEVEL, "adb fetch name %p: "
3689 "caching negative entry for A (ttl %u)",
3690 name, dev->rdataset->ttl);
3691 name->expire_v4 = ISC_MIN(name->expire_v4,
3692 dev->rdataset->ttl + now);
3693 if (dev->result == DNS_R_NCACHENXDOMAIN)
3694 name->fetch_err = FIND_ERR_NXDOMAIN;
3696 name->fetch_err = FIND_ERR_NXRRSET;
3697 inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
3699 DP(NCACHE_LEVEL, "adb fetch name %p: "
3700 "caching negative entry for AAAA (ttl %u)",
3701 name, dev->rdataset->ttl);
3702 name->expire_v6 = ISC_MIN(name->expire_v6,
3703 dev->rdataset->ttl + now);
3704 if (dev->result == DNS_R_NCACHENXDOMAIN)
3705 name->fetch6_err = FIND_ERR_NXDOMAIN;
3707 name->fetch6_err = FIND_ERR_NXRRSET;
3708 inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
3714 * Handle CNAME/DNAME.
3716 if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
3717 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3718 clean_target(adb, &name->target);
3719 name->expire_target = INT_MAX;
3720 result = set_target(adb, &name->name,
3721 dns_fixedname_name(&dev->foundname),
3724 if (result == ISC_R_SUCCESS) {
3726 "adb fetch name %p: caching alias target",
3728 name->expire_target = dev->rdataset->ttl + now;
3734 * Did we get back junk? If so, and there are no more fetches
3735 * sitting out there, tell all the finds about it.
3737 if (dev->result != ISC_R_SUCCESS) {
3738 char buf[DNS_NAME_FORMATSIZE];
3740 dns_name_format(&name->name, buf, sizeof(buf));
3741 DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
3742 buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
3743 dns_result_totext(dev->result));
3745 * Don't record a failure unless this is the initial
3748 if (fetch->depth > 1)
3750 /* XXXMLG Don't pound on bad servers. */
3751 if (address_type == DNS_ADBFIND_INET) {
3752 name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
3753 name->fetch_err = FIND_ERR_FAILURE;
3754 inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
3756 name->expire_v6 = ISC_MIN(name->expire_v6, now + 300);
3757 name->fetch6_err = FIND_ERR_FAILURE;
3758 inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
3764 * We got something potentially useful.
3766 result = import_rdataset(name, &fetch->rdataset, now);
3769 if (result == ISC_R_SUCCESS) {
3770 ev_status = DNS_EVENT_ADBMOREADDRESSES;
3771 if (address_type == DNS_ADBFIND_INET)
3772 name->fetch_err = FIND_ERR_SUCCESS;
3774 name->fetch6_err = FIND_ERR_SUCCESS;
3778 free_adbfetch(adb, &fetch);
3779 isc_event_free(&ev);
3781 clean_finds_at_name(name, ev_status, address_type);
3783 UNLOCK(&adb->namelocks[bucket]);
3787 fetch_name(dns_adbname_t *adbname, isc_boolean_t start_at_zone,
3788 unsigned int depth, isc_counter_t *qc, dns_rdatatype_t type)
3790 isc_result_t result;
3791 dns_adbfetch_t *fetch = NULL;
3793 dns_fixedname_t fixed;
3795 dns_rdataset_t rdataset;
3796 dns_rdataset_t *nameservers;
3797 unsigned int options;
3799 INSIST(DNS_ADBNAME_VALID(adbname));
3801 INSIST(DNS_ADB_VALID(adb));
3803 INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
3804 (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
3806 adbname->fetch_err = FIND_ERR_NOTFOUND;
3810 dns_rdataset_init(&rdataset);
3812 options = DNS_FETCHOPT_NOVALIDATE;
3813 if (start_at_zone) {
3815 "fetch_name: starting at zone for name %p",
3817 dns_fixedname_init(&fixed);
3818 name = dns_fixedname_name(&fixed);
3819 result = dns_view_findzonecut2(adb->view, &adbname->name, name,
3820 0, 0, ISC_TRUE, ISC_FALSE,
3822 if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
3824 nameservers = &rdataset;
3825 options |= DNS_FETCHOPT_UNSHARED;
3828 fetch = new_adbfetch(adb);
3829 if (fetch == NULL) {
3830 result = ISC_R_NOMEMORY;
3833 fetch->depth = depth;
3835 result = dns_resolver_createfetch3(adb->view->resolver, &adbname->name,
3836 type, name, nameservers, NULL,
3837 NULL, 0, options, depth, qc,
3838 adb->task, fetch_callback, adbname,
3839 &fetch->rdataset, NULL,
3841 if (result != ISC_R_SUCCESS)
3844 if (type == dns_rdatatype_a) {
3845 adbname->fetch_a = fetch;
3846 inc_stats(adb, dns_resstatscounter_gluefetchv4);
3848 adbname->fetch_aaaa = fetch;
3849 inc_stats(adb, dns_resstatscounter_gluefetchv6);
3851 fetch = NULL; /* Keep us from cleaning this up below. */
3855 free_adbfetch(adb, &fetch);
3856 if (dns_rdataset_isassociated(&rdataset))
3857 dns_rdataset_disassociate(&rdataset);
3863 * XXXMLG Needs to take a find argument and an address info, no zone or adb,
3864 * since these can be extracted from the find itself.
3867 dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname,
3868 dns_rdatatype_t qtype, isc_stdtime_t expire_time)
3870 dns_adblameinfo_t *li;
3872 isc_result_t result = ISC_R_SUCCESS;
3874 REQUIRE(DNS_ADB_VALID(adb));
3875 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3876 REQUIRE(qname != NULL);
3878 bucket = addr->entry->lock_bucket;
3879 LOCK(&adb->entrylocks[bucket]);
3880 li = ISC_LIST_HEAD(addr->entry->lameinfo);
3881 while (li != NULL &&
3882 (li->qtype != qtype || !dns_name_equal(qname, &li->qname)))
3883 li = ISC_LIST_NEXT(li, plink);
3885 if (expire_time > li->lame_timer)
3886 li->lame_timer = expire_time;
3889 li = new_adblameinfo(adb, qname, qtype);
3891 result = ISC_R_NOMEMORY;
3895 li->lame_timer = expire_time;
3897 ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink);
3899 UNLOCK(&adb->entrylocks[bucket]);
3905 dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3906 unsigned int rtt, unsigned int factor)
3909 unsigned int new_srtt;
3912 REQUIRE(DNS_ADB_VALID(adb));
3913 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3914 REQUIRE(factor <= 10);
3916 bucket = addr->entry->lock_bucket;
3917 LOCK(&adb->entrylocks[bucket]);
3919 if (factor == DNS_ADB_RTTADJAGE)
3920 new_srtt = addr->entry->srtt * 98 / 100;
3922 new_srtt = (addr->entry->srtt / 10 * factor)
3923 + (rtt / 10 * (10 - factor));
3925 addr->entry->srtt = new_srtt;
3926 addr->srtt = new_srtt;
3928 isc_stdtime_get(&now);
3929 addr->entry->expires = now + ADB_ENTRY_WINDOW;
3931 UNLOCK(&adb->entrylocks[bucket]);
3935 dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3936 unsigned int bits, unsigned int mask)
3940 REQUIRE(DNS_ADB_VALID(adb));
3941 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3943 bucket = addr->entry->lock_bucket;
3944 LOCK(&adb->entrylocks[bucket]);
3946 addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
3948 * Note that we do not update the other bits in addr->flags with
3949 * the most recent values from addr->entry->flags.
3951 addr->flags = (addr->flags & ~mask) | (bits & mask);
3953 UNLOCK(&adb->entrylocks[bucket]);
3957 dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
3958 dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
3961 dns_adbentry_t *entry;
3962 dns_adbaddrinfo_t *addr;
3963 isc_result_t result;
3966 REQUIRE(DNS_ADB_VALID(adb));
3967 REQUIRE(addrp != NULL && *addrp == NULL);
3971 result = ISC_R_SUCCESS;
3972 bucket = DNS_ADB_INVALIDBUCKET;
3973 entry = find_entry_and_lock(adb, sa, &bucket, now);
3974 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
3975 if (adb->entry_sd[bucket]) {
3976 result = ISC_R_SHUTTINGDOWN;
3979 if (entry == NULL) {
3981 * We don't know anything about this address.
3983 entry = new_adbentry(adb);
3984 if (entry == NULL) {
3985 result = ISC_R_NOMEMORY;
3988 entry->sockaddr = *sa;
3989 link_entry(adb, bucket, entry);
3990 DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
3992 DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
3994 port = isc_sockaddr_getport(sa);
3995 addr = new_adbaddrinfo(adb, entry, port);
3997 result = ISC_R_NOMEMORY;
3999 inc_entry_refcnt(adb, entry, ISC_FALSE);
4004 UNLOCK(&adb->entrylocks[bucket]);
4010 dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
4011 dns_adbaddrinfo_t *addr;
4012 dns_adbentry_t *entry;
4015 isc_boolean_t want_check_exit = ISC_FALSE;
4016 isc_boolean_t overmem;
4018 REQUIRE(DNS_ADB_VALID(adb));
4019 REQUIRE(addrp != NULL);
4021 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4022 entry = addr->entry;
4023 REQUIRE(DNS_ADBENTRY_VALID(entry));
4025 isc_stdtime_get(&now);
4028 overmem = isc_mem_isovermem(adb->mctx);
4030 bucket = addr->entry->lock_bucket;
4031 LOCK(&adb->entrylocks[bucket]);
4033 entry->expires = now + ADB_ENTRY_WINDOW;
4035 want_check_exit = dec_entry_refcnt(adb, overmem, entry, ISC_FALSE);
4037 UNLOCK(&adb->entrylocks[bucket]);
4040 free_adbaddrinfo(adb, &addr);
4042 if (want_check_exit) {
4050 dns_adb_flush(dns_adb_t *adb) {
4053 INSIST(DNS_ADB_VALID(adb));
4058 * Call our cleanup routines.
4060 for (i = 0; i < adb->nnames; i++)
4061 RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
4062 for (i = 0; i < adb->nentries; i++)
4063 RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
4065 #ifdef DUMP_ADB_AFTER_CLEANING
4066 dump_adb(adb, stdout, ISC_TRUE, INT_MAX);
4073 dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
4074 dns_adbname_t *adbname;
4075 dns_adbname_t *nextname;
4078 INSIST(DNS_ADB_VALID(adb));
4081 bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames;
4082 LOCK(&adb->namelocks[bucket]);
4083 adbname = ISC_LIST_HEAD(adb->names[bucket]);
4084 while (adbname != NULL) {
4085 nextname = ISC_LIST_NEXT(adbname, plink);
4086 if (!NAME_DEAD(adbname) &&
4087 dns_name_equal(name, &adbname->name)) {
4088 RUNTIME_CHECK(kill_name(&adbname,
4089 DNS_EVENT_ADBCANCELED) ==
4094 UNLOCK(&adb->namelocks[bucket]);
4099 water(void *arg, int mark) {
4101 * We're going to change the way to handle overmem condition: use
4102 * isc_mem_isovermem() instead of storing the state via this callback,
4103 * since the latter way tends to cause race conditions.
4104 * To minimize the change, and in case we re-enable the callback
4105 * approach, however, keep this function at the moment.
4108 dns_adb_t *adb = arg;
4109 isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
4111 REQUIRE(DNS_ADB_VALID(adb));
4113 DP(ISC_LOG_DEBUG(1),
4114 "adb reached %s water mark", overmem ? "high" : "low");
4118 dns_adb_setadbsize(dns_adb_t *adb, isc_uint32_t size) {
4119 isc_uint32_t hiwater;
4120 isc_uint32_t lowater;
4122 INSIST(DNS_ADB_VALID(adb));
4124 if (size != 0 && size < DNS_ADB_MINADBSIZE)
4125 size = DNS_ADB_MINADBSIZE;
4127 hiwater = size - (size >> 3); /* Approximately 7/8ths. */
4128 lowater = size - (size >> 2); /* Approximately 3/4ths. */
4130 if (size == 0 || hiwater == 0 || lowater == 0)
4131 isc_mem_setwater(adb->mctx, water, adb, 0, 0);
4133 isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);