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;
116 isc_interval_t tick_interval;
117 int next_cleanbucket;
119 unsigned int irefcnt;
120 unsigned int erefcnt;
123 isc_mempool_t *nmp; /*%< dns_adbname_t */
124 isc_mempool_t *nhmp; /*%< dns_adbnamehook_t */
125 isc_mempool_t *limp; /*%< dns_adblameinfo_t */
126 isc_mempool_t *emp; /*%< dns_adbentry_t */
127 isc_mempool_t *ahmp; /*%< dns_adbfind_t */
128 isc_mempool_t *aimp; /*%< dns_adbaddrinfo_t */
129 isc_mempool_t *afmp; /*%< dns_adbfetch_t */
132 * Bucketized locks and lists for names.
134 * XXXRTH Have a per-bucket structure that contains all of these?
137 isc_mutex_t namescntlock;
138 unsigned int namescnt;
139 dns_adbnamelist_t *names;
140 dns_adbnamelist_t *deadnames;
141 isc_mutex_t *namelocks;
142 isc_boolean_t *name_sd;
143 unsigned int *name_refcnt;
146 * Bucketized locks and lists for entries.
148 * XXXRTH Have a per-bucket structure that contains all of these?
150 unsigned int nentries;
151 isc_mutex_t entriescntlock;
152 unsigned int entriescnt;
153 dns_adbentrylist_t *entries;
154 dns_adbentrylist_t *deadentries;
155 isc_mutex_t *entrylocks;
156 isc_boolean_t *entry_sd; /*%< shutting down */
157 unsigned int *entry_refcnt;
160 isc_boolean_t cevent_sent;
161 isc_boolean_t shutting_down;
162 isc_eventlist_t whenshutdown;
163 isc_event_t growentries;
164 isc_boolean_t growentries_sent;
165 isc_event_t grownames;
166 isc_boolean_t grownames_sent;
170 * XXXMLG Document these structures.
173 /*% dns_adbname structure */
178 unsigned int partial_result;
182 isc_stdtime_t expire_target;
183 isc_stdtime_t expire_v4;
184 isc_stdtime_t expire_v6;
186 dns_adbnamehooklist_t v4;
187 dns_adbnamehooklist_t v6;
188 dns_adbfetch_t *fetch_a;
189 dns_adbfetch_t *fetch_aaaa;
190 unsigned int fetch_err;
191 unsigned int fetch6_err;
192 dns_adbfindlist_t finds;
193 /* for LRU-based management */
194 isc_stdtime_t last_used;
196 ISC_LINK(dns_adbname_t) plink;
199 /*% The adbfetch structure */
200 struct dns_adbfetch {
203 dns_rdataset_t rdataset;
208 * This is a small widget that dangles off a dns_adbname_t. It contains a
209 * pointer to the address information about this host, and a link to the next
210 * namehook that will contain the next address this host has.
212 struct dns_adbnamehook {
214 dns_adbentry_t *entry;
215 ISC_LINK(dns_adbnamehook_t) plink;
219 * This is a small widget that holds qname-specific information about an
220 * address. Currently limited to lameness, but could just as easily be
221 * extended to other types of information about zones.
223 struct dns_adblameinfo {
227 dns_rdatatype_t qtype;
228 isc_stdtime_t lame_timer;
230 ISC_LINK(dns_adblameinfo_t) plink;
234 * An address entry. It holds quite a bit of information about addresses,
235 * including edns state (in "flags"), rtt, and of course the address of
238 struct dns_adbentry {
246 isc_sockaddr_t sockaddr;
248 isc_stdtime_t expires;
250 * A nonzero 'expires' field indicates that the entry should
251 * persist until that time. This allows entries found
252 * using dns_adb_findaddrinfo() to persist for a limited time
253 * even though they are not necessarily associated with a
257 ISC_LIST(dns_adblameinfo_t) lameinfo;
258 ISC_LINK(dns_adbentry_t) plink;
263 * Internal functions (and prototypes).
265 static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
266 static inline void free_adbname(dns_adb_t *, dns_adbname_t **);
267 static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
269 static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
270 static inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *, dns_name_t *,
272 static inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **);
273 static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
274 static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
275 static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
276 static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
277 static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
279 static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
280 static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
281 static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
282 unsigned int, int *);
283 static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
284 isc_sockaddr_t *, int *,
286 static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t);
287 static void print_dns_name(FILE *, dns_name_t *);
288 static void print_namehook_list(FILE *, const char *legend,
289 dns_adbnamehooklist_t *list,
292 static void print_find_list(FILE *, dns_adbname_t *);
293 static void print_fetch_list(FILE *, dns_adbname_t *);
294 static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
295 static inline void inc_adb_irefcnt(dns_adb_t *);
296 static inline void inc_adb_erefcnt(dns_adb_t *);
297 static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
299 static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, isc_boolean_t,
300 dns_adbentry_t *, isc_boolean_t);
301 static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
302 static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
303 static void clean_target(dns_adb_t *, dns_name_t *);
304 static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, unsigned int);
305 static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
306 static isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **,
308 static void cancel_fetches_at_name(dns_adbname_t *);
309 static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
311 static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
312 unsigned int, isc_counter_t *qc,
314 static inline void check_exit(dns_adb_t *);
315 static void destroy(dns_adb_t *);
316 static isc_boolean_t shutdown_names(dns_adb_t *);
317 static isc_boolean_t shutdown_entries(dns_adb_t *);
318 static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
319 static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *);
320 static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
321 static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
322 static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
323 static void water(void *, int);
324 static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t);
327 * MUST NOT overlap DNS_ADBFIND_* flags!
329 #define FIND_EVENT_SENT 0x40000000
330 #define FIND_EVENT_FREED 0x80000000
331 #define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0)
332 #define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0)
334 #define NAME_NEEDS_POKE 0x80000000
335 #define NAME_IS_DEAD 0x40000000
336 #define NAME_HINT_OK DNS_ADBFIND_HINTOK
337 #define NAME_GLUE_OK DNS_ADBFIND_GLUEOK
338 #define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE
339 #define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0)
340 #define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0)
341 #define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0)
342 #define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0)
345 * Private flag(s) for entries.
346 * MUST NOT overlap FCTX_ADDRINFO_xxx and DNS_FETCHOPT_NOEDNS0.
348 #define ENTRY_IS_DEAD 0x80000000
351 * To the name, address classes are all that really exist. If it has a
352 * V6 address it doesn't care if it came from a AAAA query.
354 #define NAME_HAS_V4(n) (!ISC_LIST_EMPTY((n)->v4))
355 #define NAME_HAS_V6(n) (!ISC_LIST_EMPTY((n)->v6))
356 #define NAME_HAS_ADDRS(n) (NAME_HAS_V4(n) || NAME_HAS_V6(n))
359 * Fetches are broken out into A and AAAA types. In some cases,
360 * however, it makes more sense to test for a particular class of fetches,
361 * like V4 or V6 above.
362 * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA
363 * are now equal to FETCH_V4 and FETCH_V6, respectively.
365 #define NAME_FETCH_A(n) ((n)->fetch_a != NULL)
366 #define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL)
367 #define NAME_FETCH_V4(n) (NAME_FETCH_A(n))
368 #define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n))
369 #define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
372 * Find options and tests to see if there are addresses on the list.
374 #define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
375 #define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
376 #define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
378 #define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \
380 #define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
381 #define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
382 #define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list))
383 #define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
386 * These are currently used on simple unsigned ints, so they are
387 * not really associated with any particular type.
389 #define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0)
390 #define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0)
392 #define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now))
395 * Find out if the flags on a name (nf) indicate if it is a hint or
396 * glue, and compare this to the appropriate bits set in o, to see if
399 #define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0))
400 #define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0))
401 #define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o))
402 #define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \
403 ((o) & DNS_ADBFIND_STARTATZONE))
405 #define ENTER_LEVEL ISC_LOG_DEBUG(50)
406 #define EXIT_LEVEL ENTER_LEVEL
407 #define CLEAN_LEVEL ISC_LOG_DEBUG(100)
408 #define DEF_LEVEL ISC_LOG_DEBUG(5)
409 #define NCACHE_LEVEL ISC_LOG_DEBUG(20)
411 #define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \
412 (r) == DNS_R_NCACHENXRRSET)
413 #define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \
414 (r) == DNS_R_NXRRSET)
415 #define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \
416 (r) == DNS_R_NCACHENXDOMAIN)
417 #define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \
418 (r) == DNS_R_NXRRSET || \
419 (r) == DNS_R_HINTNXRRSET)
422 * Error state rankings.
425 #define FIND_ERR_SUCCESS 0 /* highest rank */
426 #define FIND_ERR_CANCELED 1
427 #define FIND_ERR_FAILURE 2
428 #define FIND_ERR_NXDOMAIN 3
429 #define FIND_ERR_NXRRSET 4
430 #define FIND_ERR_UNEXPECTED 5
431 #define FIND_ERR_NOTFOUND 6
432 #define FIND_ERR_MAX 7
434 static const char *errnames[] = {
444 #define NEWERR(old, new) (ISC_MIN((old), (new)))
446 static isc_result_t find_err_map[FIND_ERR_MAX] = {
453 ISC_R_NOTFOUND /* not YET found */
457 DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
460 DP(int level, const char *format, ...) {
463 va_start(args, format);
464 isc_log_vwrite(dns_lctx,
465 DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
466 level, format, args);
471 * Increment resolver-related statistics counters.
474 inc_stats(dns_adb_t *adb, isc_statscounter_t counter) {
475 if (adb->view->resstats != NULL)
476 isc_stats_increment(adb->view->resstats, counter);
479 static inline dns_ttl_t
480 ttlclamp(dns_ttl_t ttl) {
481 if (ttl < ADB_CACHE_MINIMUM)
482 ttl = ADB_CACHE_MINIMUM;
483 if (ttl > ADB_CACHE_MAXIMUM)
484 ttl = ADB_CACHE_MAXIMUM;
490 * Hashing is most efficient if the number of buckets is prime.
491 * The sequence below is the closest previous primes to 2^n and
492 * 1.5 * 2^n, for values of n from 10 to 28. (The tables will
493 * no longer grow beyond 2^28 entries.)
495 static const unsigned nbuckets[] = { 1021, 1531, 2039, 3067, 4093, 6143,
496 8191, 12281, 16381, 24571, 32749,
497 49193, 65521, 98299, 131071, 199603,
498 262139, 393209, 524287, 768431, 1048573,
499 1572853, 2097143, 3145721, 4194301,
500 6291449, 8388593, 12582893, 16777213,
501 25165813, 33554393, 50331599, 67108859,
502 100663291, 134217689, 201326557,
506 grow_entries(isc_task_t *task, isc_event_t *ev) {
509 dns_adbentrylist_t *newdeadentries = NULL;
510 dns_adbentrylist_t *newentries = NULL;
511 isc_boolean_t *newentry_sd = NULL;
512 isc_mutex_t *newentrylocks = NULL;
514 unsigned int *newentry_refcnt = NULL;
515 unsigned int i, n, bucket;
518 INSIST(DNS_ADB_VALID(adb));
522 isc_task_beginexclusive(task);
525 while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i])
527 if (nbuckets[i] != 0)
532 DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n);
535 * Are we shutting down?
537 for (i = 0; i < adb->nentries; i++)
538 if (adb->entry_sd[i])
542 * Grab all the resources we need.
544 newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n);
545 newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n);
546 newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n);
547 newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n);
548 newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n);
549 if (newentries == NULL || newdeadentries == NULL ||
550 newentrylocks == NULL || newentry_sd == NULL ||
551 newentry_refcnt == NULL)
555 * Initialise the new resources.
557 result = isc_mutexblock_init(newentrylocks, n);
558 if (result != ISC_R_SUCCESS)
561 for (i = 0; i < n; i++) {
562 ISC_LIST_INIT(newentries[i]);
563 ISC_LIST_INIT(newdeadentries[i]);
564 newentry_sd[i] = ISC_FALSE;
565 newentry_refcnt[i] = 0;
570 * Move entries to new arrays.
572 for (i = 0; i < adb->nentries; i++) {
573 e = ISC_LIST_HEAD(adb->entries[i]);
575 ISC_LIST_UNLINK(adb->entries[i], e, plink);
576 bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
577 e->lock_bucket = bucket;
578 ISC_LIST_APPEND(newentries[bucket], e, plink);
579 INSIST(adb->entry_refcnt[i] > 0);
580 adb->entry_refcnt[i]--;
581 newentry_refcnt[bucket]++;
582 e = ISC_LIST_HEAD(adb->entries[i]);
584 e = ISC_LIST_HEAD(adb->deadentries[i]);
586 ISC_LIST_UNLINK(adb->deadentries[i], e, plink);
587 bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
588 e->lock_bucket = bucket;
589 ISC_LIST_APPEND(newdeadentries[bucket], e, plink);
590 INSIST(adb->entry_refcnt[i] > 0);
591 adb->entry_refcnt[i]--;
592 newentry_refcnt[bucket]++;
593 e = ISC_LIST_HEAD(adb->deadentries[i]);
595 INSIST(adb->entry_refcnt[i] == 0);
600 * Cleanup old resources.
602 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
603 isc_mem_put(adb->mctx, adb->entries,
604 sizeof(*adb->entries) * adb->nentries);
605 isc_mem_put(adb->mctx, adb->deadentries,
606 sizeof(*adb->deadentries) * adb->nentries);
607 isc_mem_put(adb->mctx, adb->entrylocks,
608 sizeof(*adb->entrylocks) * adb->nentries);
609 isc_mem_put(adb->mctx, adb->entry_sd,
610 sizeof(*adb->entry_sd) * adb->nentries);
611 isc_mem_put(adb->mctx, adb->entry_refcnt,
612 sizeof(*adb->entry_refcnt) * adb->nentries);
615 * Install new resources.
617 adb->entries = newentries;
618 adb->deadentries = newdeadentries;
619 adb->entrylocks = newentrylocks;
620 adb->entry_sd = newentry_sd;
621 adb->entry_refcnt = newentry_refcnt;
625 * Only on success do we set adb->growentries_sent to ISC_FALSE.
626 * This will prevent us being continuously being called on error.
628 adb->growentries_sent = ISC_FALSE;
632 if (newentries != NULL)
633 isc_mem_put(adb->mctx, newentries,
634 sizeof(*newentries) * n);
635 if (newdeadentries != NULL)
636 isc_mem_put(adb->mctx, newdeadentries,
637 sizeof(*newdeadentries) * n);
638 if (newentrylocks != NULL)
639 isc_mem_put(adb->mctx, newentrylocks,
640 sizeof(*newentrylocks) * n);
641 if (newentry_sd != NULL)
642 isc_mem_put(adb->mctx, newentry_sd,
643 sizeof(*newentry_sd) * n);
644 if (newentry_refcnt != NULL)
645 isc_mem_put(adb->mctx, newentry_refcnt,
646 sizeof(*newentry_refcnt) * n);
648 isc_task_endexclusive(task);
651 if (dec_adb_irefcnt(adb))
654 DP(ISC_LOG_INFO, "adb: grow_entries finished");
658 grow_names(isc_task_t *task, isc_event_t *ev) {
661 dns_adbnamelist_t *newdeadnames = NULL;
662 dns_adbnamelist_t *newnames = NULL;
663 isc_boolean_t *newname_sd = NULL;
664 isc_mutex_t *newnamelocks = NULL;
666 unsigned int *newname_refcnt = NULL;
667 unsigned int i, n, bucket;
670 INSIST(DNS_ADB_VALID(adb));
674 isc_task_beginexclusive(task);
677 while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i])
679 if (nbuckets[i] != 0)
684 DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n);
687 * Are we shutting down?
689 for (i = 0; i < adb->nnames; i++)
694 * Grab all the resources we need.
696 newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n);
697 newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n);
698 newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n);
699 newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n);
700 newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n);
701 if (newnames == NULL || newdeadnames == NULL ||
702 newnamelocks == NULL || newname_sd == NULL ||
703 newname_refcnt == NULL)
707 * Initialise the new resources.
709 result = isc_mutexblock_init(newnamelocks, n);
710 if (result != ISC_R_SUCCESS)
713 for (i = 0; i < n; i++) {
714 ISC_LIST_INIT(newnames[i]);
715 ISC_LIST_INIT(newdeadnames[i]);
716 newname_sd[i] = ISC_FALSE;
717 newname_refcnt[i] = 0;
722 * Move names to new arrays.
724 for (i = 0; i < adb->nnames; i++) {
725 name = ISC_LIST_HEAD(adb->names[i]);
726 while (name != NULL) {
727 ISC_LIST_UNLINK(adb->names[i], name, plink);
728 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
729 name->lock_bucket = bucket;
730 ISC_LIST_APPEND(newnames[bucket], name, plink);
731 INSIST(adb->name_refcnt[i] > 0);
732 adb->name_refcnt[i]--;
733 newname_refcnt[bucket]++;
734 name = ISC_LIST_HEAD(adb->names[i]);
736 name = ISC_LIST_HEAD(adb->deadnames[i]);
737 while (name != NULL) {
738 ISC_LIST_UNLINK(adb->deadnames[i], name, plink);
739 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
740 name->lock_bucket = bucket;
741 ISC_LIST_APPEND(newdeadnames[bucket], name, plink);
742 INSIST(adb->name_refcnt[i] > 0);
743 adb->name_refcnt[i]--;
744 newname_refcnt[bucket]++;
745 name = ISC_LIST_HEAD(adb->deadnames[i]);
747 INSIST(adb->name_refcnt[i] == 0);
752 * Cleanup old resources.
754 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
755 isc_mem_put(adb->mctx, adb->names,
756 sizeof(*adb->names) * adb->nnames);
757 isc_mem_put(adb->mctx, adb->deadnames,
758 sizeof(*adb->deadnames) * adb->nnames);
759 isc_mem_put(adb->mctx, adb->namelocks,
760 sizeof(*adb->namelocks) * adb->nnames);
761 isc_mem_put(adb->mctx, adb->name_sd,
762 sizeof(*adb->name_sd) * adb->nnames);
763 isc_mem_put(adb->mctx, adb->name_refcnt,
764 sizeof(*adb->name_refcnt) * adb->nnames);
767 * Install new resources.
769 adb->names = newnames;
770 adb->deadnames = newdeadnames;
771 adb->namelocks = newnamelocks;
772 adb->name_sd = newname_sd;
773 adb->name_refcnt = newname_refcnt;
777 * Only on success do we set adb->grownames_sent to ISC_FALSE.
778 * This will prevent us being continuously being called on error.
780 adb->grownames_sent = ISC_FALSE;
784 if (newnames != NULL)
785 isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n);
786 if (newdeadnames != NULL)
787 isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n);
788 if (newnamelocks != NULL)
789 isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n);
790 if (newname_sd != NULL)
791 isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n);
792 if (newname_refcnt != NULL)
793 isc_mem_put(adb->mctx, newname_refcnt,
794 sizeof(*newname_refcnt) * n);
796 isc_task_endexclusive(task);
799 if (dec_adb_irefcnt(adb))
802 DP(ISC_LOG_INFO, "adb: grow_names finished");
806 * Requires the adbname bucket be locked and that no entry buckets be locked.
808 * This code handles A and AAAA rdatasets only.
811 import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
816 dns_adbnamehook_t *nh;
817 dns_adbnamehook_t *anh;
818 dns_rdata_t rdata = DNS_RDATA_INIT;
820 struct in6_addr in6a;
821 isc_sockaddr_t sockaddr;
822 dns_adbentry_t *foundentry; /* NO CLEAN UP! */
824 isc_boolean_t new_addresses_added;
825 dns_rdatatype_t rdtype;
826 unsigned int findoptions;
827 dns_adbnamehooklist_t *hookhead;
829 INSIST(DNS_ADBNAME_VALID(adbname));
831 INSIST(DNS_ADB_VALID(adb));
833 rdtype = rdataset->type;
834 INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
835 if (rdtype == dns_rdatatype_a)
836 findoptions = DNS_ADBFIND_INET;
838 findoptions = DNS_ADBFIND_INET6;
840 addr_bucket = DNS_ADB_INVALIDBUCKET;
841 new_addresses_added = ISC_FALSE;
844 result = dns_rdataset_first(rdataset);
845 while (result == ISC_R_SUCCESS) {
846 dns_rdata_reset(&rdata);
847 dns_rdataset_current(rdataset, &rdata);
848 if (rdtype == dns_rdatatype_a) {
849 INSIST(rdata.length == 4);
850 memcpy(&ina.s_addr, rdata.data, 4);
851 isc_sockaddr_fromin(&sockaddr, &ina, 0);
852 hookhead = &adbname->v4;
854 INSIST(rdata.length == 16);
855 memcpy(in6a.s6_addr, rdata.data, 16);
856 isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
857 hookhead = &adbname->v6;
861 nh = new_adbnamehook(adb, NULL);
863 adbname->partial_result |= findoptions;
864 result = ISC_R_NOMEMORY;
868 foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket,
870 if (foundentry == NULL) {
871 dns_adbentry_t *entry;
873 entry = new_adbentry(adb);
875 adbname->partial_result |= findoptions;
876 result = ISC_R_NOMEMORY;
880 entry->sockaddr = sockaddr;
885 link_entry(adb, addr_bucket, entry);
887 for (anh = ISC_LIST_HEAD(*hookhead);
889 anh = ISC_LIST_NEXT(anh, plink))
890 if (anh->entry == foundentry)
893 foundentry->refcnt++;
894 nh->entry = foundentry;
896 free_adbnamehook(adb, &nh);
899 new_addresses_added = ISC_TRUE;
901 ISC_LIST_APPEND(*hookhead, nh, plink);
903 result = dns_rdataset_next(rdataset);
908 free_adbnamehook(adb, &nh);
910 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
911 UNLOCK(&adb->entrylocks[addr_bucket]);
913 if (rdataset->trust == dns_trust_glue ||
914 rdataset->trust == dns_trust_additional)
915 rdataset->ttl = ADB_CACHE_MINIMUM;
916 else if (rdataset->trust == dns_trust_ultimate)
919 rdataset->ttl = ttlclamp(rdataset->ttl);
921 if (rdtype == dns_rdatatype_a) {
922 DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
923 adbname->expire_v4, now + rdataset->ttl);
924 adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
925 now + rdataset->ttl);
927 DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
928 adbname->expire_v6, now + rdataset->ttl);
929 adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
930 now + rdataset->ttl);
933 if (new_addresses_added) {
935 * Lie a little here. This is more or less so code that cares
936 * can find out if any new information was added or not.
938 return (ISC_R_SUCCESS);
945 * Requires the name's bucket be locked.
948 kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
950 isc_boolean_t result = ISC_FALSE;
951 isc_boolean_t result4, result6;
958 INSIST(DNS_ADBNAME_VALID(name));
960 INSIST(DNS_ADB_VALID(adb));
962 DP(DEF_LEVEL, "killing name %p", name);
965 * If we're dead already, just check to see if we should go
968 if (NAME_DEAD(name) && !NAME_FETCH(name)) {
969 result = unlink_name(adb, name);
970 free_adbname(adb, &name);
972 result = dec_adb_irefcnt(adb);
977 * Clean up the name's various lists. These two are destructive
978 * in that they will always empty the list.
980 clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
981 result4 = clean_namehooks(adb, &name->v4);
982 result6 = clean_namehooks(adb, &name->v6);
983 clean_target(adb, &name->target);
984 result = ISC_TF(result4 || result6);
987 * If fetches are running, cancel them. If none are running, we can
988 * just kill the name here.
990 if (!NAME_FETCH(name)) {
991 INSIST(result == ISC_FALSE);
992 result = unlink_name(adb, name);
993 free_adbname(adb, &name);
995 result = dec_adb_irefcnt(adb);
997 cancel_fetches_at_name(name);
998 if (!NAME_DEAD(name)) {
999 bucket = name->lock_bucket;
1000 ISC_LIST_UNLINK(adb->names[bucket], name, plink);
1001 ISC_LIST_APPEND(adb->deadnames[bucket], name, plink);
1002 name->flags |= NAME_IS_DEAD;
1009 * Requires the name's bucket be locked and no entry buckets be locked.
1011 static isc_boolean_t
1012 check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
1014 isc_boolean_t result4 = ISC_FALSE;
1015 isc_boolean_t result6 = ISC_FALSE;
1017 INSIST(DNS_ADBNAME_VALID(name));
1019 INSIST(DNS_ADB_VALID(adb));
1022 * Check to see if we need to remove the v4 addresses
1024 if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) {
1025 if (NAME_HAS_V4(name)) {
1026 DP(DEF_LEVEL, "expiring v4 for name %p", name);
1027 result4 = clean_namehooks(adb, &name->v4);
1028 name->partial_result &= ~DNS_ADBFIND_INET;
1030 name->expire_v4 = INT_MAX;
1031 name->fetch_err = FIND_ERR_UNEXPECTED;
1035 * Check to see if we need to remove the v6 addresses
1037 if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) {
1038 if (NAME_HAS_V6(name)) {
1039 DP(DEF_LEVEL, "expiring v6 for name %p", name);
1040 result6 = clean_namehooks(adb, &name->v6);
1041 name->partial_result &= ~DNS_ADBFIND_INET6;
1043 name->expire_v6 = INT_MAX;
1044 name->fetch6_err = FIND_ERR_UNEXPECTED;
1048 * Check to see if we need to remove the alias target.
1050 if (EXPIRE_OK(name->expire_target, now)) {
1051 clean_target(adb, &name->target);
1052 name->expire_target = INT_MAX;
1054 return (ISC_TF(result4 || result6));
1058 * Requires the name's bucket be locked.
1061 link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
1062 INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
1064 ISC_LIST_PREPEND(adb->names[bucket], name, plink);
1065 name->lock_bucket = bucket;
1066 adb->name_refcnt[bucket]++;
1070 * Requires the name's bucket be locked.
1072 static inline isc_boolean_t
1073 unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
1075 isc_boolean_t result = ISC_FALSE;
1077 bucket = name->lock_bucket;
1078 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
1080 if (NAME_DEAD(name))
1081 ISC_LIST_UNLINK(adb->deadnames[bucket], name, plink);
1083 ISC_LIST_UNLINK(adb->names[bucket], name, plink);
1084 name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1085 INSIST(adb->name_refcnt[bucket] > 0);
1086 adb->name_refcnt[bucket]--;
1087 if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
1093 * Requires the entry's bucket be locked.
1096 link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
1100 if (isc_mem_isovermem(adb->mctx)) {
1101 for (i = 0; i < 2; i++) {
1102 e = ISC_LIST_TAIL(adb->entries[bucket]);
1105 if (e->refcnt == 0) {
1106 unlink_entry(adb, e);
1107 free_adbentry(adb, &e);
1110 INSIST((e->flags & ENTRY_IS_DEAD) == 0);
1111 e->flags |= ENTRY_IS_DEAD;
1112 ISC_LIST_UNLINK(adb->entries[bucket], e, plink);
1113 ISC_LIST_PREPEND(adb->deadentries[bucket], e, plink);
1117 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
1118 entry->lock_bucket = bucket;
1119 adb->entry_refcnt[bucket]++;
1123 * Requires the entry's bucket be locked.
1125 static inline isc_boolean_t
1126 unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
1128 isc_boolean_t result = ISC_FALSE;
1130 bucket = entry->lock_bucket;
1131 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
1133 if ((entry->flags & ENTRY_IS_DEAD) != 0)
1134 ISC_LIST_UNLINK(adb->deadentries[bucket], entry, plink);
1136 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
1137 entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1138 INSIST(adb->entry_refcnt[bucket] > 0);
1139 adb->entry_refcnt[bucket]--;
1140 if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
1146 violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
1147 if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
1155 * The ADB _MUST_ be locked before calling. Also, exit conditions must be
1156 * checked after calling this function.
1158 static isc_boolean_t
1159 shutdown_names(dns_adb_t *adb) {
1160 unsigned int bucket;
1161 isc_boolean_t result = ISC_FALSE;
1162 dns_adbname_t *name;
1163 dns_adbname_t *next_name;
1165 for (bucket = 0; bucket < adb->nnames; bucket++) {
1166 LOCK(&adb->namelocks[bucket]);
1167 adb->name_sd[bucket] = ISC_TRUE;
1169 name = ISC_LIST_HEAD(adb->names[bucket]);
1172 * This bucket has no names. We must decrement the
1173 * irefcnt ourselves, since it will not be
1174 * automatically triggered by a name being unlinked.
1176 INSIST(result == ISC_FALSE);
1177 result = dec_adb_irefcnt(adb);
1180 * Run through the list. For each name, clean up finds
1181 * found there, and cancel any fetches running. When
1182 * all the fetches are canceled, the name will destroy
1185 while (name != NULL) {
1186 next_name = ISC_LIST_NEXT(name, plink);
1187 INSIST(result == ISC_FALSE);
1188 result = kill_name(&name,
1189 DNS_EVENT_ADBSHUTDOWN);
1194 UNLOCK(&adb->namelocks[bucket]);
1200 * The ADB _MUST_ be locked before calling. Also, exit conditions must be
1201 * checked after calling this function.
1203 static isc_boolean_t
1204 shutdown_entries(dns_adb_t *adb) {
1205 unsigned int bucket;
1206 isc_boolean_t result = ISC_FALSE;
1207 dns_adbentry_t *entry;
1208 dns_adbentry_t *next_entry;
1210 for (bucket = 0; bucket < adb->nentries; bucket++) {
1211 LOCK(&adb->entrylocks[bucket]);
1212 adb->entry_sd[bucket] = ISC_TRUE;
1214 entry = ISC_LIST_HEAD(adb->entries[bucket]);
1215 if (adb->entry_refcnt[bucket] == 0) {
1217 * This bucket has no entries. We must decrement the
1218 * irefcnt ourselves, since it will not be
1219 * automatically triggered by an entry being unlinked.
1221 result = dec_adb_irefcnt(adb);
1224 * Run through the list. Cleanup any entries not
1225 * associated with names, and which are not in use.
1227 while (entry != NULL) {
1228 next_entry = ISC_LIST_NEXT(entry, plink);
1229 if (entry->refcnt == 0 &&
1230 entry->expires != 0) {
1231 result = unlink_entry(adb, entry);
1232 free_adbentry(adb, &entry);
1234 result = dec_adb_irefcnt(adb);
1240 UNLOCK(&adb->entrylocks[bucket]);
1246 * Name bucket must be locked
1249 cancel_fetches_at_name(dns_adbname_t *name) {
1250 if (NAME_FETCH_A(name))
1251 dns_resolver_cancelfetch(name->fetch_a->fetch);
1253 if (NAME_FETCH_AAAA(name))
1254 dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
1258 * Assumes the name bucket is locked.
1260 static isc_boolean_t
1261 clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
1262 dns_adbentry_t *entry;
1263 dns_adbnamehook_t *namehook;
1265 isc_boolean_t result = ISC_FALSE;
1266 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
1268 addr_bucket = DNS_ADB_INVALIDBUCKET;
1269 namehook = ISC_LIST_HEAD(*namehooks);
1270 while (namehook != NULL) {
1271 INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
1274 * Clean up the entry if needed.
1276 entry = namehook->entry;
1277 if (entry != NULL) {
1278 INSIST(DNS_ADBENTRY_VALID(entry));
1280 if (addr_bucket != entry->lock_bucket) {
1281 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1282 UNLOCK(&adb->entrylocks[addr_bucket]);
1283 addr_bucket = entry->lock_bucket;
1284 LOCK(&adb->entrylocks[addr_bucket]);
1287 result = dec_entry_refcnt(adb, overmem, entry,
1294 namehook->entry = NULL;
1295 ISC_LIST_UNLINK(*namehooks, namehook, plink);
1296 free_adbnamehook(adb, &namehook);
1298 namehook = ISC_LIST_HEAD(*namehooks);
1301 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1302 UNLOCK(&adb->entrylocks[addr_bucket]);
1307 clean_target(dns_adb_t *adb, dns_name_t *target) {
1308 if (dns_name_countlabels(target) > 0) {
1309 dns_name_free(target, adb->mctx);
1310 dns_name_init(target, NULL);
1315 set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
1316 dns_rdataset_t *rdataset, dns_name_t *target)
1318 isc_result_t result;
1319 dns_namereln_t namereln;
1320 unsigned int nlabels;
1322 dns_rdata_t rdata = DNS_RDATA_INIT;
1323 dns_fixedname_t fixed1, fixed2;
1324 dns_name_t *prefix, *new_target;
1326 REQUIRE(dns_name_countlabels(target) == 0);
1328 if (rdataset->type == dns_rdatatype_cname) {
1329 dns_rdata_cname_t cname;
1332 * Copy the CNAME's target into the target name.
1334 result = dns_rdataset_first(rdataset);
1335 if (result != ISC_R_SUCCESS)
1337 dns_rdataset_current(rdataset, &rdata);
1338 result = dns_rdata_tostruct(&rdata, &cname, NULL);
1339 if (result != ISC_R_SUCCESS)
1341 result = dns_name_dup(&cname.cname, adb->mctx, target);
1342 dns_rdata_freestruct(&cname);
1343 if (result != ISC_R_SUCCESS)
1346 dns_rdata_dname_t dname;
1348 INSIST(rdataset->type == dns_rdatatype_dname);
1349 namereln = dns_name_fullcompare(name, fname, &order, &nlabels);
1350 INSIST(namereln == dns_namereln_subdomain);
1352 * Get the target name of the DNAME.
1354 result = dns_rdataset_first(rdataset);
1355 if (result != ISC_R_SUCCESS)
1357 dns_rdataset_current(rdataset, &rdata);
1358 result = dns_rdata_tostruct(&rdata, &dname, NULL);
1359 if (result != ISC_R_SUCCESS)
1362 * Construct the new target name.
1364 dns_fixedname_init(&fixed1);
1365 prefix = dns_fixedname_name(&fixed1);
1366 dns_fixedname_init(&fixed2);
1367 new_target = dns_fixedname_name(&fixed2);
1368 dns_name_split(name, nlabels, prefix, NULL);
1369 result = dns_name_concatenate(prefix, &dname.dname, new_target,
1371 dns_rdata_freestruct(&dname);
1372 if (result != ISC_R_SUCCESS)
1374 result = dns_name_dup(new_target, adb->mctx, target);
1375 if (result != ISC_R_SUCCESS)
1379 return (ISC_R_SUCCESS);
1383 * Assumes nothing is locked, since this is called by the client.
1386 event_free(isc_event_t *event) {
1387 dns_adbfind_t *find;
1389 INSIST(event != NULL);
1390 find = event->ev_destroy_arg;
1391 INSIST(DNS_ADBFIND_VALID(find));
1394 find->flags |= FIND_EVENT_FREED;
1395 event->ev_destroy_arg = NULL;
1396 UNLOCK(&find->lock);
1400 * Assumes the name bucket is locked.
1403 clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
1408 dns_adbfind_t *find;
1409 dns_adbfind_t *next_find;
1410 isc_boolean_t process;
1411 unsigned int wanted, notify;
1414 "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
1415 name, evtype, addrs);
1417 find = ISC_LIST_HEAD(name->finds);
1418 while (find != NULL) {
1420 next_find = ISC_LIST_NEXT(find, plink);
1422 process = ISC_FALSE;
1423 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1424 notify = wanted & addrs;
1427 case DNS_EVENT_ADBMOREADDRESSES:
1428 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES");
1429 if ((notify) != 0) {
1430 find->flags &= ~addrs;
1434 case DNS_EVENT_ADBNOMOREADDRESSES:
1435 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES");
1436 find->flags &= ~addrs;
1437 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1442 find->flags &= ~addrs;
1447 DP(DEF_LEVEL, "cfan: processing find %p", find);
1449 * Unlink the find from the name, letting the caller
1450 * call dns_adb_destroyfind() on it to clean it up
1453 ISC_LIST_UNLINK(name->finds, find, plink);
1454 find->adbname = NULL;
1455 find->name_bucket = DNS_ADB_INVALIDBUCKET;
1457 INSIST(!FIND_EVENTSENT(find));
1460 task = ev->ev_sender;
1461 ev->ev_sender = find;
1462 find->result_v4 = find_err_map[name->fetch_err];
1463 find->result_v6 = find_err_map[name->fetch6_err];
1464 ev->ev_type = evtype;
1465 ev->ev_destroy = event_free;
1466 ev->ev_destroy_arg = find;
1469 "sending event %p to task %p for find %p",
1472 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
1474 DP(DEF_LEVEL, "cfan: skipping find %p", find);
1477 UNLOCK(&find->lock);
1481 DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
1485 check_exit(dns_adb_t *adb) {
1488 * The caller must be holding the adb lock.
1490 if (adb->shutting_down) {
1492 * If there aren't any external references either, we're
1493 * done. Send the control event to initiate shutdown.
1495 INSIST(!adb->cevent_sent); /* Sanity check. */
1496 event = &adb->cevent;
1497 isc_task_send(adb->task, &event);
1498 adb->cevent_sent = ISC_TRUE;
1502 static inline isc_boolean_t
1503 dec_adb_irefcnt(dns_adb_t *adb) {
1506 isc_boolean_t result = ISC_FALSE;
1508 LOCK(&adb->reflock);
1510 INSIST(adb->irefcnt > 0);
1513 if (adb->irefcnt == 0) {
1514 event = ISC_LIST_HEAD(adb->whenshutdown);
1515 while (event != NULL) {
1516 ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
1517 etask = event->ev_sender;
1518 event->ev_sender = adb;
1519 isc_task_sendanddetach(&etask, &event);
1520 event = ISC_LIST_HEAD(adb->whenshutdown);
1524 if (adb->irefcnt == 0 && adb->erefcnt == 0)
1526 UNLOCK(&adb->reflock);
1531 inc_adb_irefcnt(dns_adb_t *adb) {
1532 LOCK(&adb->reflock);
1534 UNLOCK(&adb->reflock);
1538 inc_adb_erefcnt(dns_adb_t *adb) {
1539 LOCK(&adb->reflock);
1541 UNLOCK(&adb->reflock);
1545 inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
1548 bucket = entry->lock_bucket;
1551 LOCK(&adb->entrylocks[bucket]);
1556 UNLOCK(&adb->entrylocks[bucket]);
1559 static inline isc_boolean_t
1560 dec_entry_refcnt(dns_adb_t *adb, isc_boolean_t overmem, dns_adbentry_t *entry,
1564 isc_boolean_t destroy_entry;
1565 isc_boolean_t result = ISC_FALSE;
1567 bucket = entry->lock_bucket;
1570 LOCK(&adb->entrylocks[bucket]);
1572 INSIST(entry->refcnt > 0);
1575 destroy_entry = ISC_FALSE;
1576 if (entry->refcnt == 0 &&
1577 (adb->entry_sd[bucket] || entry->expires == 0 || overmem ||
1578 (entry->flags & ENTRY_IS_DEAD) != 0)) {
1579 destroy_entry = ISC_TRUE;
1580 result = unlink_entry(adb, entry);
1584 UNLOCK(&adb->entrylocks[bucket]);
1589 entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1591 free_adbentry(adb, &entry);
1593 result = dec_adb_irefcnt(adb);
1598 static inline dns_adbname_t *
1599 new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
1600 dns_adbname_t *name;
1602 name = isc_mempool_get(adb->nmp);
1606 dns_name_init(&name->name, NULL);
1607 if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
1608 isc_mempool_put(adb->nmp, name);
1611 dns_name_init(&name->target, NULL);
1612 name->magic = DNS_ADBNAME_MAGIC;
1614 name->partial_result = 0;
1616 name->expire_v4 = INT_MAX;
1617 name->expire_v6 = INT_MAX;
1618 name->expire_target = INT_MAX;
1620 name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1621 ISC_LIST_INIT(name->v4);
1622 ISC_LIST_INIT(name->v6);
1623 name->fetch_a = NULL;
1624 name->fetch_aaaa = NULL;
1625 name->fetch_err = FIND_ERR_UNEXPECTED;
1626 name->fetch6_err = FIND_ERR_UNEXPECTED;
1627 ISC_LIST_INIT(name->finds);
1628 ISC_LINK_INIT(name, plink);
1630 LOCK(&adb->namescntlock);
1632 if (!adb->grownames_sent && adb->excl != NULL &&
1633 adb->namescnt > (adb->nnames * 8))
1635 isc_event_t *event = &adb->grownames;
1636 inc_adb_irefcnt(adb);
1637 isc_task_send(adb->excl, &event);
1638 adb->grownames_sent = ISC_TRUE;
1640 UNLOCK(&adb->namescntlock);
1646 free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
1649 INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
1653 INSIST(!NAME_HAS_V4(n));
1654 INSIST(!NAME_HAS_V6(n));
1655 INSIST(!NAME_FETCH(n));
1656 INSIST(ISC_LIST_EMPTY(n->finds));
1657 INSIST(!ISC_LINK_LINKED(n, plink));
1658 INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
1659 INSIST(n->adb == adb);
1662 dns_name_free(&n->name, adb->mctx);
1664 isc_mempool_put(adb->nmp, n);
1665 LOCK(&adb->namescntlock);
1667 UNLOCK(&adb->namescntlock);
1670 static inline dns_adbnamehook_t *
1671 new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) {
1672 dns_adbnamehook_t *nh;
1674 nh = isc_mempool_get(adb->nhmp);
1678 nh->magic = DNS_ADBNAMEHOOK_MAGIC;
1680 ISC_LINK_INIT(nh, plink);
1686 free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) {
1687 dns_adbnamehook_t *nh;
1689 INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
1693 INSIST(nh->entry == NULL);
1694 INSIST(!ISC_LINK_LINKED(nh, plink));
1697 isc_mempool_put(adb->nhmp, nh);
1700 static inline dns_adblameinfo_t *
1701 new_adblameinfo(dns_adb_t *adb, dns_name_t *qname, dns_rdatatype_t qtype) {
1702 dns_adblameinfo_t *li;
1704 li = isc_mempool_get(adb->limp);
1708 dns_name_init(&li->qname, NULL);
1709 if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) {
1710 isc_mempool_put(adb->limp, li);
1713 li->magic = DNS_ADBLAMEINFO_MAGIC;
1716 ISC_LINK_INIT(li, plink);
1722 free_adblameinfo(dns_adb_t *adb, dns_adblameinfo_t **lameinfo) {
1723 dns_adblameinfo_t *li;
1725 INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo));
1729 INSIST(!ISC_LINK_LINKED(li, plink));
1731 dns_name_free(&li->qname, adb->mctx);
1735 isc_mempool_put(adb->limp, li);
1738 static inline dns_adbentry_t *
1739 new_adbentry(dns_adb_t *adb) {
1743 e = isc_mempool_get(adb->emp);
1747 e->magic = DNS_ADBENTRY_MAGIC;
1748 e->lock_bucket = DNS_ADB_INVALIDBUCKET;
1752 e->srtt = (r & 0x1f) + 1;
1754 ISC_LIST_INIT(e->lameinfo);
1755 ISC_LINK_INIT(e, plink);
1756 LOCK(&adb->entriescntlock);
1758 if (!adb->growentries_sent && adb->growentries_sent &&
1759 adb->entriescnt > (adb->nentries * 8))
1761 isc_event_t *event = &adb->growentries;
1762 inc_adb_irefcnt(adb);
1763 isc_task_send(adb->task, &event);
1764 adb->growentries_sent = ISC_TRUE;
1766 UNLOCK(&adb->entriescntlock);
1772 free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
1774 dns_adblameinfo_t *li;
1776 INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
1780 INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
1781 INSIST(e->refcnt == 0);
1782 INSIST(!ISC_LINK_LINKED(e, plink));
1786 li = ISC_LIST_HEAD(e->lameinfo);
1787 while (li != NULL) {
1788 ISC_LIST_UNLINK(e->lameinfo, li, plink);
1789 free_adblameinfo(adb, &li);
1790 li = ISC_LIST_HEAD(e->lameinfo);
1793 isc_mempool_put(adb->emp, e);
1794 LOCK(&adb->entriescntlock);
1796 UNLOCK(&adb->entriescntlock);
1799 static inline dns_adbfind_t *
1800 new_adbfind(dns_adb_t *adb) {
1802 isc_result_t result;
1804 h = isc_mempool_get(adb->ahmp);
1813 h->partial_result = 0;
1816 h->result_v4 = ISC_R_UNEXPECTED;
1817 h->result_v6 = ISC_R_UNEXPECTED;
1818 ISC_LINK_INIT(h, publink);
1819 ISC_LINK_INIT(h, plink);
1820 ISC_LIST_INIT(h->list);
1822 h->name_bucket = DNS_ADB_INVALIDBUCKET;
1827 result = isc_mutex_init(&h->lock);
1828 if (result != ISC_R_SUCCESS) {
1829 isc_mempool_put(adb->ahmp, h);
1833 ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
1836 inc_adb_irefcnt(adb);
1837 h->magic = DNS_ADBFIND_MAGIC;
1841 static inline dns_adbfetch_t *
1842 new_adbfetch(dns_adb_t *adb) {
1845 f = isc_mempool_get(adb->afmp);
1852 dns_rdataset_init(&f->rdataset);
1854 f->magic = DNS_ADBFETCH_MAGIC;
1860 free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) {
1863 INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
1869 if (dns_rdataset_isassociated(&f->rdataset))
1870 dns_rdataset_disassociate(&f->rdataset);
1872 isc_mempool_put(adb->afmp, f);
1875 static inline isc_boolean_t
1876 free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
1877 dns_adbfind_t *find;
1879 INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
1883 INSIST(!FIND_HAS_ADDRS(find));
1884 INSIST(!ISC_LINK_LINKED(find, publink));
1885 INSIST(!ISC_LINK_LINKED(find, plink));
1886 INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
1887 INSIST(find->adbname == NULL);
1891 DESTROYLOCK(&find->lock);
1892 isc_mempool_put(adb->ahmp, find);
1893 return (dec_adb_irefcnt(adb));
1897 * Copy bits from the entry into the newly allocated addrinfo. The entry
1898 * must be locked, and the reference count must be bumped up by one
1899 * if this function returns a valid pointer.
1901 static inline dns_adbaddrinfo_t *
1902 new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
1903 dns_adbaddrinfo_t *ai;
1905 ai = isc_mempool_get(adb->aimp);
1909 ai->magic = DNS_ADBADDRINFO_MAGIC;
1910 ai->sockaddr = entry->sockaddr;
1911 isc_sockaddr_setport(&ai->sockaddr, port);
1912 ai->srtt = entry->srtt;
1913 ai->flags = entry->flags;
1915 ISC_LINK_INIT(ai, publink);
1921 free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
1922 dns_adbaddrinfo_t *ai;
1924 INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
1928 INSIST(ai->entry == NULL);
1929 INSIST(!ISC_LINK_LINKED(ai, publink));
1933 isc_mempool_put(adb->aimp, ai);
1937 * Search for the name. NOTE: The bucket is kept locked on both
1938 * success and failure, so it must always be unlocked by the caller!
1940 * On the first call to this function, *bucketp must be set to
1941 * DNS_ADB_INVALIDBUCKET.
1943 static inline dns_adbname_t *
1944 find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
1945 unsigned int options, int *bucketp)
1947 dns_adbname_t *adbname;
1950 bucket = dns_name_fullhash(name, ISC_FALSE) % adb->nnames;
1952 if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1953 LOCK(&adb->namelocks[bucket]);
1955 } else if (*bucketp != bucket) {
1956 UNLOCK(&adb->namelocks[*bucketp]);
1957 LOCK(&adb->namelocks[bucket]);
1961 adbname = ISC_LIST_HEAD(adb->names[bucket]);
1962 while (adbname != NULL) {
1963 if (!NAME_DEAD(adbname)) {
1964 if (dns_name_equal(name, &adbname->name)
1965 && GLUEHINT_OK(adbname, options)
1966 && STARTATZONE_MATCHES(adbname, options))
1969 adbname = ISC_LIST_NEXT(adbname, plink);
1976 * Search for the address. NOTE: The bucket is kept locked on both
1977 * success and failure, so it must always be unlocked by the caller.
1979 * On the first call to this function, *bucketp must be set to
1980 * DNS_ADB_INVALIDBUCKET. This will cause a lock to occur. On
1981 * later calls (within the same "lock path") it can be left alone, so
1982 * if this function is called multiple times locking is only done if
1983 * the bucket changes.
1985 static inline dns_adbentry_t *
1986 find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp,
1989 dns_adbentry_t *entry, *entry_next;
1992 bucket = isc_sockaddr_hash(addr, ISC_TRUE) % adb->nentries;
1994 if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1995 LOCK(&adb->entrylocks[bucket]);
1997 } else if (*bucketp != bucket) {
1998 UNLOCK(&adb->entrylocks[*bucketp]);
1999 LOCK(&adb->entrylocks[bucket]);
2003 /* Search the list, while cleaning up expired entries. */
2004 for (entry = ISC_LIST_HEAD(adb->entries[bucket]);
2006 entry = entry_next) {
2007 entry_next = ISC_LIST_NEXT(entry, plink);
2008 (void)check_expire_entry(adb, &entry, now);
2009 if (entry != NULL &&
2010 isc_sockaddr_equal(addr, &entry->sockaddr)) {
2011 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
2012 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
2021 * Entry bucket MUST be locked!
2023 static isc_boolean_t
2024 entry_is_lame(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *qname,
2025 dns_rdatatype_t qtype, isc_stdtime_t now)
2027 dns_adblameinfo_t *li, *next_li;
2028 isc_boolean_t is_bad;
2032 li = ISC_LIST_HEAD(entry->lameinfo);
2035 while (li != NULL) {
2036 next_li = ISC_LIST_NEXT(li, plink);
2039 * Has the entry expired?
2041 if (li->lame_timer < now) {
2042 ISC_LIST_UNLINK(entry->lameinfo, li, plink);
2043 free_adblameinfo(adb, &li);
2047 * Order tests from least to most expensive.
2049 * We do not break out of the main loop here as
2050 * we use the loop for house keeping.
2052 if (li != NULL && !is_bad && li->qtype == qtype &&
2053 dns_name_equal(qname, &li->qname))
2063 copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname,
2064 dns_rdatatype_t qtype, dns_adbname_t *name,
2067 dns_adbnamehook_t *namehook;
2068 dns_adbaddrinfo_t *addrinfo;
2069 dns_adbentry_t *entry;
2072 bucket = DNS_ADB_INVALIDBUCKET;
2074 if (find->options & DNS_ADBFIND_INET) {
2075 namehook = ISC_LIST_HEAD(name->v4);
2076 while (namehook != NULL) {
2077 entry = namehook->entry;
2078 bucket = entry->lock_bucket;
2079 LOCK(&adb->entrylocks[bucket]);
2081 if (!FIND_RETURNLAME(find)
2082 && entry_is_lame(adb, entry, qname, qtype, now)) {
2083 find->options |= DNS_ADBFIND_LAMEPRUNED;
2086 addrinfo = new_adbaddrinfo(adb, entry, find->port);
2087 if (addrinfo == NULL) {
2088 find->partial_result |= DNS_ADBFIND_INET;
2092 * Found a valid entry. Add it to the find's list.
2094 inc_entry_refcnt(adb, entry, ISC_FALSE);
2095 ISC_LIST_APPEND(find->list, addrinfo, publink);
2098 UNLOCK(&adb->entrylocks[bucket]);
2099 bucket = DNS_ADB_INVALIDBUCKET;
2100 namehook = ISC_LIST_NEXT(namehook, plink);
2104 if (find->options & DNS_ADBFIND_INET6) {
2105 namehook = ISC_LIST_HEAD(name->v6);
2106 while (namehook != NULL) {
2107 entry = namehook->entry;
2108 bucket = entry->lock_bucket;
2109 LOCK(&adb->entrylocks[bucket]);
2111 if (!FIND_RETURNLAME(find)
2112 && entry_is_lame(adb, entry, qname, qtype, now)) {
2113 find->options |= DNS_ADBFIND_LAMEPRUNED;
2116 addrinfo = new_adbaddrinfo(adb, entry, find->port);
2117 if (addrinfo == NULL) {
2118 find->partial_result |= DNS_ADBFIND_INET6;
2122 * Found a valid entry. Add it to the find's list.
2124 inc_entry_refcnt(adb, entry, ISC_FALSE);
2125 ISC_LIST_APPEND(find->list, addrinfo, publink);
2128 UNLOCK(&adb->entrylocks[bucket]);
2129 bucket = DNS_ADB_INVALIDBUCKET;
2130 namehook = ISC_LIST_NEXT(namehook, plink);
2135 if (bucket != DNS_ADB_INVALIDBUCKET)
2136 UNLOCK(&adb->entrylocks[bucket]);
2140 shutdown_task(isc_task_t *task, isc_event_t *ev) {
2146 INSIST(DNS_ADB_VALID(adb));
2148 isc_event_free(&ev);
2150 * Wait for lock around check_exit() call to be released.
2158 * Name bucket must be locked; adb may be locked; no other locks held.
2160 static isc_boolean_t
2161 check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
2162 dns_adbname_t *name;
2163 isc_boolean_t result = ISC_FALSE;
2165 INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
2168 if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
2170 if (NAME_FETCH(name))
2172 if (!EXPIRE_OK(name->expire_v4, now))
2174 if (!EXPIRE_OK(name->expire_v6, now))
2176 if (!EXPIRE_OK(name->expire_target, now))
2180 * The name is empty. Delete it.
2182 result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
2186 * Our caller, or one of its callers, will be calling check_exit() at
2187 * some point, so we don't need to do it here.
2193 * Examine the tail entry of the LRU list to see if it expires or is stale
2194 * (unused for some period); if so, the name entry will be freed. If the ADB
2195 * is in the overmem condition, the tail and the next to tail entries
2196 * will be unconditionally removed (unless they have an outstanding fetch).
2197 * We don't care about a race on 'overmem' at the risk of causing some
2198 * collateral damage or a small delay in starting cleanup, so we don't bother
2199 * to lock ADB (if it's not locked).
2201 * Name bucket must be locked; adb may be locked; no other locks held.
2204 check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2205 int victims, max_victims;
2206 dns_adbname_t *victim, *next_victim;
2207 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
2210 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2212 max_victims = overmem ? 2 : 1;
2215 * We limit the number of scanned entries to 10 (arbitrary choice)
2216 * in order to avoid examining too many entries when there are many
2217 * tail entries that have fetches (this should be rare, but could
2220 victim = ISC_LIST_TAIL(adb->names[bucket]);
2222 victim != NULL && victims < max_victims && scans < 10;
2223 victim = next_victim) {
2224 INSIST(!NAME_DEAD(victim));
2226 next_victim = ISC_LIST_PREV(victim, plink);
2227 (void)check_expire_name(&victim, now);
2228 if (victim == NULL) {
2233 if (!NAME_FETCH(victim) &&
2234 (overmem || victim->last_used + ADB_STALE_MARGIN <= now)) {
2235 RUNTIME_CHECK(kill_name(&victim,
2236 DNS_EVENT_ADBCANCELED) ==
2248 * Entry bucket must be locked; adb may be locked; no other locks held.
2250 static isc_boolean_t
2251 check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
2253 dns_adbentry_t *entry;
2254 isc_boolean_t result = ISC_FALSE;
2256 INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
2259 if (entry->refcnt != 0)
2262 if (entry->expires == 0 || entry->expires > now)
2266 * The entry is not in use. Delete it.
2268 DP(DEF_LEVEL, "killing entry %p", entry);
2269 INSIST(ISC_LINK_LINKED(entry, plink));
2270 result = unlink_entry(adb, entry);
2271 free_adbentry(adb, &entry);
2273 dec_adb_irefcnt(adb);
2279 * ADB must be locked, and no other locks held.
2281 static isc_boolean_t
2282 cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2283 dns_adbname_t *name;
2284 dns_adbname_t *next_name;
2285 isc_boolean_t result = ISC_FALSE;
2287 DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
2289 LOCK(&adb->namelocks[bucket]);
2290 if (adb->name_sd[bucket]) {
2291 UNLOCK(&adb->namelocks[bucket]);
2295 name = ISC_LIST_HEAD(adb->names[bucket]);
2296 while (name != NULL) {
2297 next_name = ISC_LIST_NEXT(name, plink);
2298 INSIST(result == ISC_FALSE);
2299 result = check_expire_namehooks(name, now);
2301 result = check_expire_name(&name, now);
2304 UNLOCK(&adb->namelocks[bucket]);
2309 * ADB must be locked, and no other locks held.
2311 static isc_boolean_t
2312 cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2313 dns_adbentry_t *entry, *next_entry;
2314 isc_boolean_t result = ISC_FALSE;
2316 DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
2318 LOCK(&adb->entrylocks[bucket]);
2319 entry = ISC_LIST_HEAD(adb->entries[bucket]);
2320 while (entry != NULL) {
2321 next_entry = ISC_LIST_NEXT(entry, plink);
2322 INSIST(result == ISC_FALSE);
2323 result = check_expire_entry(adb, &entry, now);
2326 UNLOCK(&adb->entrylocks[bucket]);
2331 destroy(dns_adb_t *adb) {
2334 isc_task_detach(&adb->task);
2335 isc_task_detach(&adb->excl);
2337 isc_mempool_destroy(&adb->nmp);
2338 isc_mempool_destroy(&adb->nhmp);
2339 isc_mempool_destroy(&adb->limp);
2340 isc_mempool_destroy(&adb->emp);
2341 isc_mempool_destroy(&adb->ahmp);
2342 isc_mempool_destroy(&adb->aimp);
2343 isc_mempool_destroy(&adb->afmp);
2345 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
2346 isc_mem_put(adb->mctx, adb->entries,
2347 sizeof(*adb->entries) * adb->nentries);
2348 isc_mem_put(adb->mctx, adb->deadentries,
2349 sizeof(*adb->deadentries) * adb->nentries);
2350 isc_mem_put(adb->mctx, adb->entrylocks,
2351 sizeof(*adb->entrylocks) * adb->nentries);
2352 isc_mem_put(adb->mctx, adb->entry_sd,
2353 sizeof(*adb->entry_sd) * adb->nentries);
2354 isc_mem_put(adb->mctx, adb->entry_refcnt,
2355 sizeof(*adb->entry_refcnt) * adb->nentries);
2357 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
2358 isc_mem_put(adb->mctx, adb->names,
2359 sizeof(*adb->names) * adb->nnames);
2360 isc_mem_put(adb->mctx, adb->deadnames,
2361 sizeof(*adb->deadnames) * adb->nnames);
2362 isc_mem_put(adb->mctx, adb->namelocks,
2363 sizeof(*adb->namelocks) * adb->nnames);
2364 isc_mem_put(adb->mctx, adb->name_sd,
2365 sizeof(*adb->name_sd) * adb->nnames);
2366 isc_mem_put(adb->mctx, adb->name_refcnt,
2367 sizeof(*adb->name_refcnt) * adb->nnames);
2369 DESTROYLOCK(&adb->reflock);
2370 DESTROYLOCK(&adb->lock);
2371 DESTROYLOCK(&adb->mplock);
2372 DESTROYLOCK(&adb->overmemlock);
2373 DESTROYLOCK(&adb->entriescntlock);
2374 DESTROYLOCK(&adb->namescntlock);
2376 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2385 dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
2386 isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
2389 isc_result_t result;
2392 REQUIRE(mem != NULL);
2393 REQUIRE(view != NULL);
2394 REQUIRE(timermgr != NULL); /* this is actually unused */
2395 REQUIRE(taskmgr != NULL);
2396 REQUIRE(newadb != NULL && *newadb == NULL);
2400 adb = isc_mem_get(mem, sizeof(dns_adb_t));
2402 return (ISC_R_NOMEMORY);
2405 * Initialize things here that cannot fail, and especially things
2406 * that must be NULL for the error return to work properly.
2422 adb->taskmgr = taskmgr;
2423 adb->next_cleanbucket = 0;
2424 ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
2425 DNS_EVENT_ADBCONTROL, shutdown_task, adb,
2427 adb->cevent_sent = ISC_FALSE;
2428 adb->shutting_down = ISC_FALSE;
2429 ISC_LIST_INIT(adb->whenshutdown);
2431 adb->nentries = nbuckets[0];
2432 adb->entriescnt = 0;
2433 adb->entries = NULL;
2434 adb->deadentries = NULL;
2435 adb->entry_sd = NULL;
2436 adb->entry_refcnt = NULL;
2437 adb->entrylocks = NULL;
2438 ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL,
2439 DNS_EVENT_ADBGROWENTRIES, grow_entries, adb,
2441 adb->growentries_sent = ISC_FALSE;
2443 adb->nnames = nbuckets[0];
2446 adb->deadnames = NULL;
2447 adb->name_sd = NULL;
2448 adb->name_refcnt = NULL;
2449 adb->namelocks = NULL;
2450 ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL,
2451 DNS_EVENT_ADBGROWNAMES, grow_names, adb,
2453 adb->grownames_sent = ISC_FALSE;
2455 result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl);
2456 if (result != ISC_R_SUCCESS) {
2457 DP(ISC_LOG_INFO, "adb: task-exclusive mode unavailable, "
2458 "intializing table sizes to %u\n",
2460 adb->nentries = nbuckets[11];
2461 adb->nnames= nbuckets[11];
2465 isc_mem_attach(mem, &adb->mctx);
2467 result = isc_mutex_init(&adb->lock);
2468 if (result != ISC_R_SUCCESS)
2471 result = isc_mutex_init(&adb->mplock);
2472 if (result != ISC_R_SUCCESS)
2475 result = isc_mutex_init(&adb->reflock);
2476 if (result != ISC_R_SUCCESS)
2479 result = isc_mutex_init(&adb->overmemlock);
2480 if (result != ISC_R_SUCCESS)
2483 result = isc_mutex_init(&adb->entriescntlock);
2484 if (result != ISC_R_SUCCESS)
2487 result = isc_mutex_init(&adb->namescntlock);
2488 if (result != ISC_R_SUCCESS)
2491 #define ALLOCENTRY(adb, el) \
2493 (adb)->el = isc_mem_get((adb)->mctx, \
2494 sizeof(*(adb)->el) * (adb)->nentries); \
2495 if ((adb)->el == NULL) { \
2496 result = ISC_R_NOMEMORY; \
2500 ALLOCENTRY(adb, entries);
2501 ALLOCENTRY(adb, deadentries);
2502 ALLOCENTRY(adb, entrylocks);
2503 ALLOCENTRY(adb, entry_sd);
2504 ALLOCENTRY(adb, entry_refcnt);
2507 #define ALLOCNAME(adb, el) \
2509 (adb)->el = isc_mem_get((adb)->mctx, \
2510 sizeof(*(adb)->el) * (adb)->nnames); \
2511 if ((adb)->el == NULL) { \
2512 result = ISC_R_NOMEMORY; \
2516 ALLOCNAME(adb, names);
2517 ALLOCNAME(adb, deadnames);
2518 ALLOCNAME(adb, namelocks);
2519 ALLOCNAME(adb, name_sd);
2520 ALLOCNAME(adb, name_refcnt);
2524 * Initialize the bucket locks for names and elements.
2525 * May as well initialize the list heads, too.
2527 result = isc_mutexblock_init(adb->namelocks, adb->nnames);
2528 if (result != ISC_R_SUCCESS)
2530 for (i = 0; i < adb->nnames; i++) {
2531 ISC_LIST_INIT(adb->names[i]);
2532 ISC_LIST_INIT(adb->deadnames[i]);
2533 adb->name_sd[i] = ISC_FALSE;
2534 adb->name_refcnt[i] = 0;
2537 for (i = 0; i < adb->nentries; i++) {
2538 ISC_LIST_INIT(adb->entries[i]);
2539 ISC_LIST_INIT(adb->deadentries[i]);
2540 adb->entry_sd[i] = ISC_FALSE;
2541 adb->entry_refcnt[i] = 0;
2544 result = isc_mutexblock_init(adb->entrylocks, adb->nentries);
2545 if (result != ISC_R_SUCCESS)
2551 #define MPINIT(t, p, n) do { \
2552 result = isc_mempool_create(mem, sizeof(t), &(p)); \
2553 if (result != ISC_R_SUCCESS) \
2555 isc_mempool_setfreemax((p), FREE_ITEMS); \
2556 isc_mempool_setfillcount((p), FILL_COUNT); \
2557 isc_mempool_setname((p), n); \
2558 isc_mempool_associatelock((p), &adb->mplock); \
2561 MPINIT(dns_adbname_t, adb->nmp, "adbname");
2562 MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
2563 MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo");
2564 MPINIT(dns_adbentry_t, adb->emp, "adbentry");
2565 MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
2566 MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
2567 MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
2572 * Allocate an internal task.
2574 result = isc_task_create(adb->taskmgr, 0, &adb->task);
2575 if (result != ISC_R_SUCCESS)
2578 isc_task_setname(adb->task, "ADB", adb);
2583 adb->magic = DNS_ADB_MAGIC;
2585 return (ISC_R_SUCCESS);
2588 if (adb->task != NULL)
2589 isc_task_detach(&adb->task);
2591 /* clean up entrylocks */
2592 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
2594 fail2: /* clean up namelocks */
2595 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
2597 fail1: /* clean up only allocated memory */
2598 if (adb->entries != NULL)
2599 isc_mem_put(adb->mctx, adb->entries,
2600 sizeof(*adb->entries) * adb->nentries);
2601 if (adb->deadentries != NULL)
2602 isc_mem_put(adb->mctx, adb->deadentries,
2603 sizeof(*adb->deadentries) * adb->nentries);
2604 if (adb->entrylocks != NULL)
2605 isc_mem_put(adb->mctx, adb->entrylocks,
2606 sizeof(*adb->entrylocks) * adb->nentries);
2607 if (adb->entry_sd != NULL)
2608 isc_mem_put(adb->mctx, adb->entry_sd,
2609 sizeof(*adb->entry_sd) * adb->nentries);
2610 if (adb->entry_refcnt != NULL)
2611 isc_mem_put(adb->mctx, adb->entry_refcnt,
2612 sizeof(*adb->entry_refcnt) * adb->nentries);
2613 if (adb->names != NULL)
2614 isc_mem_put(adb->mctx, adb->names,
2615 sizeof(*adb->names) * adb->nnames);
2616 if (adb->deadnames != NULL)
2617 isc_mem_put(adb->mctx, adb->deadnames,
2618 sizeof(*adb->deadnames) * adb->nnames);
2619 if (adb->namelocks != NULL)
2620 isc_mem_put(adb->mctx, adb->namelocks,
2621 sizeof(*adb->namelocks) * adb->nnames);
2622 if (adb->name_sd != NULL)
2623 isc_mem_put(adb->mctx, adb->name_sd,
2624 sizeof(*adb->name_sd) * adb->nnames);
2625 if (adb->name_refcnt != NULL)
2626 isc_mem_put(adb->mctx, adb->name_refcnt,
2627 sizeof(*adb->name_refcnt) * adb->nnames);
2628 if (adb->nmp != NULL)
2629 isc_mempool_destroy(&adb->nmp);
2630 if (adb->nhmp != NULL)
2631 isc_mempool_destroy(&adb->nhmp);
2632 if (adb->limp != NULL)
2633 isc_mempool_destroy(&adb->limp);
2634 if (adb->emp != NULL)
2635 isc_mempool_destroy(&adb->emp);
2636 if (adb->ahmp != NULL)
2637 isc_mempool_destroy(&adb->ahmp);
2638 if (adb->aimp != NULL)
2639 isc_mempool_destroy(&adb->aimp);
2640 if (adb->afmp != NULL)
2641 isc_mempool_destroy(&adb->afmp);
2643 DESTROYLOCK(&adb->namescntlock);
2645 DESTROYLOCK(&adb->entriescntlock);
2647 DESTROYLOCK(&adb->overmemlock);
2649 DESTROYLOCK(&adb->reflock);
2651 DESTROYLOCK(&adb->mplock);
2653 DESTROYLOCK(&adb->lock);
2655 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2661 dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
2663 REQUIRE(DNS_ADB_VALID(adb));
2664 REQUIRE(adbx != NULL && *adbx == NULL);
2666 inc_adb_erefcnt(adb);
2671 dns_adb_detach(dns_adb_t **adbx) {
2673 isc_boolean_t need_exit_check;
2675 REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
2680 INSIST(adb->erefcnt > 0);
2682 LOCK(&adb->reflock);
2684 need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
2685 UNLOCK(&adb->reflock);
2687 if (need_exit_check) {
2689 INSIST(adb->shutting_down);
2696 dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
2699 isc_boolean_t zeroirefcnt = ISC_FALSE;
2702 * Send '*eventp' to 'task' when 'adb' has shutdown.
2705 REQUIRE(DNS_ADB_VALID(adb));
2706 REQUIRE(eventp != NULL);
2713 LOCK(&adb->reflock);
2714 zeroirefcnt = ISC_TF(adb->irefcnt == 0);
2716 if (adb->shutting_down && zeroirefcnt &&
2717 isc_mempool_getallocated(adb->ahmp) == 0) {
2719 * We're already shutdown. Send the event.
2721 event->ev_sender = adb;
2722 isc_task_send(task, &event);
2725 isc_task_attach(task, &clone);
2726 event->ev_sender = clone;
2727 ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
2730 UNLOCK(&adb->reflock);
2735 dns_adb_shutdown(dns_adb_t *adb) {
2736 isc_boolean_t need_check_exit;
2744 if (!adb->shutting_down) {
2745 adb->shutting_down = ISC_TRUE;
2746 isc_mem_setwater(adb->mctx, water, adb, 0, 0);
2747 need_check_exit = shutdown_names(adb);
2748 if (!need_check_exit)
2749 need_check_exit = shutdown_entries(adb);
2750 if (need_check_exit)
2758 dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
2759 void *arg, dns_name_t *name, dns_name_t *qname,
2760 dns_rdatatype_t qtype, unsigned int options,
2761 isc_stdtime_t now, dns_name_t *target,
2762 in_port_t port, dns_adbfind_t **findp)
2764 return (dns_adb_createfind2(adb, task, action, arg, name,
2765 qname, qtype, options, now,
2766 target, port, 0, NULL, findp));
2770 dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
2771 void *arg, dns_name_t *name, dns_name_t *qname,
2772 dns_rdatatype_t qtype, unsigned int options,
2773 isc_stdtime_t now, dns_name_t *target,
2774 in_port_t port, unsigned int depth, isc_counter_t *qc,
2775 dns_adbfind_t **findp)
2777 dns_adbfind_t *find;
2778 dns_adbname_t *adbname;
2780 isc_boolean_t want_event, start_at_zone, alias, have_address;
2781 isc_result_t result;
2782 unsigned int wanted_addresses;
2783 unsigned int wanted_fetches;
2784 unsigned int query_pending;
2786 REQUIRE(DNS_ADB_VALID(adb));
2788 REQUIRE(action != NULL);
2790 REQUIRE(name != NULL);
2791 REQUIRE(qname != NULL);
2792 REQUIRE(findp != NULL && *findp == NULL);
2793 REQUIRE(target == NULL || dns_name_hasbuffer(target));
2795 REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
2797 result = ISC_R_UNEXPECTED;
2799 wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
2802 want_event = ISC_FALSE;
2803 start_at_zone = ISC_FALSE;
2807 isc_stdtime_get(&now);
2810 * XXXMLG Move this comment somewhere else!
2812 * Look up the name in our internal database.
2814 * Possibilities: Note that these are not always exclusive.
2816 * No name found. In this case, allocate a new name header and
2817 * an initial namehook or two. If any of these allocations
2818 * fail, clean up and return ISC_R_NOMEMORY.
2820 * Name found, valid addresses present. Allocate one addrinfo
2821 * structure for each found and append it to the linked list
2822 * of addresses for this header.
2824 * Name found, queries pending. In this case, if a task was
2825 * passed in, allocate a job id, attach it to the name's job
2826 * list and remember to tell the caller that there will be
2827 * more info coming later.
2830 find = new_adbfind(adb);
2832 return (ISC_R_NOMEMORY);
2837 * Remember what types of addresses we are interested in.
2839 find->options = options;
2840 find->flags |= wanted_addresses;
2841 if (FIND_WANTEVENT(find)) {
2842 REQUIRE(task != NULL);
2846 * Try to see if we know anything about this name at all.
2848 bucket = DNS_ADB_INVALIDBUCKET;
2849 adbname = find_name_and_lock(adb, name, find->options, &bucket);
2850 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2851 if (adb->name_sd[bucket]) {
2853 "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
2854 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2855 result = ISC_R_SHUTTINGDOWN;
2860 * Nothing found. Allocate a new adbname structure for this name.
2862 if (adbname == NULL) {
2864 * See if there is any stale name at the end of list, and purge
2867 check_stale_name(adb, bucket, now);
2869 adbname = new_adbname(adb, name);
2870 if (adbname == NULL) {
2871 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2872 result = ISC_R_NOMEMORY;
2875 link_name(adb, bucket, adbname);
2876 if (FIND_HINTOK(find))
2877 adbname->flags |= NAME_HINT_OK;
2878 if (FIND_GLUEOK(find))
2879 adbname->flags |= NAME_GLUE_OK;
2880 if (FIND_STARTATZONE(find))
2881 adbname->flags |= NAME_STARTATZONE;
2883 /* Move this name forward in the LRU list */
2884 ISC_LIST_UNLINK(adb->names[bucket], adbname, plink);
2885 ISC_LIST_PREPEND(adb->names[bucket], adbname, plink);
2887 adbname->last_used = now;
2890 * Expire old entries, etc.
2892 RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE);
2895 * Do we know that the name is an alias?
2897 if (!EXPIRE_OK(adbname->expire_target, now)) {
2902 "dns_adb_createfind: name %p is an alias (cached)",
2909 * Try to populate the name from the database and/or
2910 * start fetches. First try looking for an A record
2913 if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
2914 && WANT_INET(wanted_addresses)) {
2915 result = dbfind_name(adbname, now, dns_rdatatype_a);
2916 if (result == ISC_R_SUCCESS) {
2918 "dns_adb_createfind: found A for name %p in db",
2924 * Did we get a CNAME or DNAME?
2926 if (result == DNS_R_ALIAS) {
2928 "dns_adb_createfind: name %p is an alias",
2935 * If the name doesn't exist at all, don't bother with
2936 * v6 queries; they won't work.
2938 * If the name does exist but we didn't get our data, go
2939 * ahead and try AAAA.
2941 * If the result is neither of these, try a fetch for A.
2943 if (NXDOMAIN_RESULT(result))
2945 else if (NXRRSET_RESULT(result))
2948 if (!NAME_FETCH_V4(adbname))
2949 wanted_fetches |= DNS_ADBFIND_INET;
2953 if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
2954 && WANT_INET6(wanted_addresses)) {
2955 result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
2956 if (result == ISC_R_SUCCESS) {
2958 "dns_adb_createfind: found AAAA for name %p",
2964 * Did we get a CNAME or DNAME?
2966 if (result == DNS_R_ALIAS) {
2968 "dns_adb_createfind: name %p is an alias",
2975 * Listen to negative cache hints, and don't start
2978 if (NCACHE_RESULT(result) || AUTH_NX(result))
2981 if (!NAME_FETCH_V6(adbname))
2982 wanted_fetches |= DNS_ADBFIND_INET6;
2986 if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
2987 (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
2988 have_address = ISC_TRUE;
2990 have_address = ISC_FALSE;
2991 if (wanted_fetches != 0 &&
2992 ! (FIND_AVOIDFETCHES(find) && have_address)) {
2994 * We're missing at least one address family. Either the
2995 * caller hasn't instructed us to avoid fetches, or we don't
2996 * know anything about any of the address families that would
2997 * be acceptable so we have to launch fetches.
3000 if (FIND_STARTATZONE(find))
3001 start_at_zone = ISC_TRUE;
3006 if (WANT_INET(wanted_fetches) &&
3007 fetch_name(adbname, start_at_zone, depth, qc,
3008 dns_rdatatype_a) == ISC_R_SUCCESS) {
3010 "dns_adb_createfind: started A fetch for name %p",
3017 if (WANT_INET6(wanted_fetches) &&
3018 fetch_name(adbname, start_at_zone, depth, qc,
3019 dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
3021 "dns_adb_createfind: "
3022 "started AAAA fetch for name %p",
3028 * Run through the name and copy out the bits we are
3031 copy_namehook_lists(adb, find, qname, qtype, adbname, now);
3034 if (NAME_FETCH_V4(adbname))
3035 query_pending |= DNS_ADBFIND_INET;
3036 if (NAME_FETCH_V6(adbname))
3037 query_pending |= DNS_ADBFIND_INET6;
3040 * Attach to the name's query list if there are queries
3041 * already running, and we have been asked to.
3043 want_event = ISC_TRUE;
3044 if (!FIND_WANTEVENT(find))
3045 want_event = ISC_FALSE;
3046 if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
3047 want_event = ISC_FALSE;
3048 if ((wanted_addresses & query_pending) == 0)
3049 want_event = ISC_FALSE;
3051 want_event = ISC_FALSE;
3053 find->adbname = adbname;
3054 find->name_bucket = bucket;
3055 ISC_LIST_APPEND(adbname->finds, find, plink);
3056 find->query_pending = (query_pending & wanted_addresses);
3057 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
3058 find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
3059 DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
3063 * Remove the flag so the caller knows there will never
3064 * be an event, and set internal flags to fake that
3065 * the event was sent and freed, so dns_adb_destroyfind() will
3066 * do the right thing.
3068 find->query_pending = (query_pending & wanted_addresses);
3069 find->options &= ~DNS_ADBFIND_WANTEVENT;
3070 find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
3071 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
3074 find->partial_result |= (adbname->partial_result & wanted_addresses);
3076 if (target != NULL) {
3077 result = dns_name_copy(&adbname->target, target, NULL);
3078 if (result != ISC_R_SUCCESS)
3081 result = DNS_R_ALIAS;
3083 result = ISC_R_SUCCESS;
3086 * Copy out error flags from the name structure into the find.
3088 find->result_v4 = find_err_map[adbname->fetch_err];
3089 find->result_v6 = find_err_map[adbname->fetch6_err];
3098 INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
3100 isc_task_attach(task, &taskp);
3101 find->event.ev_sender = taskp;
3102 find->event.ev_action = action;
3103 find->event.ev_arg = arg;
3107 UNLOCK(&adb->namelocks[bucket]);
3113 dns_adb_destroyfind(dns_adbfind_t **findp) {
3114 dns_adbfind_t *find;
3115 dns_adbentry_t *entry;
3116 dns_adbaddrinfo_t *ai;
3119 isc_boolean_t overmem;
3121 REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
3127 DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
3130 REQUIRE(DNS_ADB_VALID(adb));
3132 REQUIRE(FIND_EVENTFREED(find));
3134 bucket = find->name_bucket;
3135 INSIST(bucket == DNS_ADB_INVALIDBUCKET);
3137 UNLOCK(&find->lock);
3140 * The find doesn't exist on any list, and nothing is locked.
3141 * Return the find to the memory pool, and decrement the adb's
3144 overmem = isc_mem_isovermem(adb->mctx);
3145 ai = ISC_LIST_HEAD(find->list);
3146 while (ai != NULL) {
3147 ISC_LIST_UNLINK(find->list, ai, publink);
3150 INSIST(DNS_ADBENTRY_VALID(entry));
3151 RUNTIME_CHECK(dec_entry_refcnt(adb, overmem, entry, ISC_TRUE) ==
3153 free_adbaddrinfo(adb, &ai);
3154 ai = ISC_LIST_HEAD(find->list);
3158 * WARNING: The find is freed with the adb locked. This is done
3159 * to avoid a race condition where we free the find, some other
3160 * thread tests to see if it should be destroyed, detects it should
3161 * be, destroys it, and then we try to lock it for our check, but the
3162 * lock is destroyed.
3165 if (free_adbfind(adb, &find))
3171 dns_adb_cancelfind(dns_adbfind_t *find) {
3180 DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
3183 REQUIRE(DNS_ADB_VALID(adb));
3185 REQUIRE(!FIND_EVENTFREED(find));
3186 REQUIRE(FIND_WANTEVENT(find));
3188 bucket = find->name_bucket;
3189 if (bucket == DNS_ADB_INVALIDBUCKET)
3193 * We need to get the adbname's lock to unlink the find.
3195 unlock_bucket = bucket;
3196 violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
3197 bucket = find->name_bucket;
3198 if (bucket != DNS_ADB_INVALIDBUCKET) {
3199 ISC_LIST_UNLINK(find->adbname->finds, find, plink);
3200 find->adbname = NULL;
3201 find->name_bucket = DNS_ADB_INVALIDBUCKET;
3203 UNLOCK(&adb->namelocks[unlock_bucket]);
3204 bucket = DNS_ADB_INVALIDBUCKET;
3209 if (!FIND_EVENTSENT(find)) {
3211 task = ev->ev_sender;
3212 ev->ev_sender = find;
3213 ev->ev_type = DNS_EVENT_ADBCANCELED;
3214 ev->ev_destroy = event_free;
3215 ev->ev_destroy_arg = find;
3216 find->result_v4 = ISC_R_CANCELED;
3217 find->result_v6 = ISC_R_CANCELED;
3219 DP(DEF_LEVEL, "sending event %p to task %p for find %p",
3222 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
3225 UNLOCK(&find->lock);
3229 dns_adb_dump(dns_adb_t *adb, FILE *f) {
3233 REQUIRE(DNS_ADB_VALID(adb));
3237 * Lock the adb itself, lock all the name buckets, then lock all
3238 * the entry buckets. This should put the adb into a state where
3239 * nothing can change, so we can iterate through everything and
3240 * print at our leisure.
3244 isc_stdtime_get(&now);
3246 for (i = 0; i < adb->nnames; i++)
3247 RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE);
3248 for (i = 0; i < adb->nentries; i++)
3249 RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE);
3251 dump_adb(adb, f, ISC_FALSE, now);
3256 dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
3257 if (value == INT_MAX)
3259 fprintf(f, " [%s TTL %d]", legend, value - now);
3263 dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
3265 dns_adbname_t *name;
3266 dns_adbentry_t *entry;
3268 fprintf(f, ";\n; Address database dump\n;\n");
3270 fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
3271 adb, adb->erefcnt, adb->irefcnt,
3272 isc_mempool_getallocated(adb->nhmp));
3274 for (i = 0; i < adb->nnames; i++)
3275 LOCK(&adb->namelocks[i]);
3276 for (i = 0; i < adb->nentries; i++)
3277 LOCK(&adb->entrylocks[i]);
3282 for (i = 0; i < adb->nnames; i++) {
3283 name = ISC_LIST_HEAD(adb->names[i]);
3287 fprintf(f, "; bucket %d\n", i);
3290 name = ISC_LIST_NEXT(name, plink))
3293 fprintf(f, "; name %p (flags %08x)\n",
3297 print_dns_name(f, &name->name);
3298 if (dns_name_countlabels(&name->target) > 0) {
3299 fprintf(f, " alias ");
3300 print_dns_name(f, &name->target);
3303 dump_ttl(f, "v4", name->expire_v4, now);
3304 dump_ttl(f, "v6", name->expire_v6, now);
3305 dump_ttl(f, "target", name->expire_target, now);
3307 fprintf(f, " [v4 %s] [v6 %s]",
3308 errnames[name->fetch_err],
3309 errnames[name->fetch6_err]);
3313 print_namehook_list(f, "v4", &name->v4, debug, now);
3314 print_namehook_list(f, "v6", &name->v6, debug, now);
3317 print_fetch_list(f, name);
3319 print_find_list(f, name);
3324 fprintf(f, ";\n; Unassociated entries\n;\n");
3326 for (i = 0; i < adb->nentries; i++) {
3327 entry = ISC_LIST_HEAD(adb->entries[i]);
3328 while (entry != NULL) {
3329 if (entry->refcnt == 0)
3330 dump_entry(f, entry, debug, now);
3331 entry = ISC_LIST_NEXT(entry, plink);
3338 for (i = 0; i < adb->nentries; i++)
3339 UNLOCK(&adb->entrylocks[i]);
3340 for (i = 0; i < adb->nnames; i++)
3341 UNLOCK(&adb->namelocks[i]);
3345 dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug,
3348 char addrbuf[ISC_NETADDR_FORMATSIZE];
3349 char typebuf[DNS_RDATATYPE_FORMATSIZE];
3350 isc_netaddr_t netaddr;
3351 dns_adblameinfo_t *li;
3353 isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
3354 isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
3357 fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
3359 fprintf(f, ";\t%s [srtt %u] [flags %08x]",
3360 addrbuf, entry->srtt, entry->flags);
3361 if (entry->expires != 0)
3362 fprintf(f, " [ttl %d]", entry->expires - now);
3364 for (li = ISC_LIST_HEAD(entry->lameinfo);
3366 li = ISC_LIST_NEXT(li, plink)) {
3367 fprintf(f, ";\t\t");
3368 print_dns_name(f, &li->qname);
3369 dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf));
3370 fprintf(f, " %s [lame TTL %d]\n", typebuf,
3371 li->lame_timer - now);
3376 dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
3379 dns_adbaddrinfo_t *ai;
3383 * Not used currently, in the API Just In Case we
3384 * want to dump out the name and/or entries too.
3389 fprintf(f, ";Find %p\n", find);
3390 fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
3391 find->query_pending, find->partial_result,
3392 find->options, find->flags);
3393 fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
3394 find->name_bucket, find->adbname, find->event.ev_sender);
3396 ai = ISC_LIST_HEAD(find->list);
3398 fprintf(f, "\tAddresses:\n");
3399 while (ai != NULL) {
3401 switch (sa->type.sa.sa_family) {
3403 tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
3407 tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
3415 tmpp = "BadAddress";
3417 fprintf(f, "\t\tentry %p, flags %08x"
3418 " srtt %u addr %s\n",
3419 ai->entry, ai->flags, ai->srtt, tmpp);
3421 ai = ISC_LIST_NEXT(ai, publink);
3424 UNLOCK(&find->lock);
3428 print_dns_name(FILE *f, dns_name_t *name) {
3429 char buf[DNS_NAME_FORMATSIZE];
3433 dns_name_format(name, buf, sizeof(buf));
3434 fprintf(f, "%s", buf);
3438 print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list,
3439 isc_boolean_t debug, isc_stdtime_t now)
3441 dns_adbnamehook_t *nh;
3443 for (nh = ISC_LIST_HEAD(*list);
3445 nh = ISC_LIST_NEXT(nh, plink))
3448 fprintf(f, ";\tHook(%s) %p\n", legend, nh);
3449 dump_entry(f, nh->entry, debug, now);
3454 print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) {
3455 fprintf(f, "\t\tFetch(%s): %p -> { fetch %p }\n",
3456 type, ft, ft->fetch);
3460 print_fetch_list(FILE *f, dns_adbname_t *n) {
3461 if (NAME_FETCH_A(n))
3462 print_fetch(f, n->fetch_a, "A");
3463 if (NAME_FETCH_AAAA(n))
3464 print_fetch(f, n->fetch_aaaa, "AAAA");
3468 print_find_list(FILE *f, dns_adbname_t *name) {
3469 dns_adbfind_t *find;
3471 find = ISC_LIST_HEAD(name->finds);
3472 while (find != NULL) {
3473 dns_adb_dumpfind(find, f);
3474 find = ISC_LIST_NEXT(find, plink);
3479 dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype)
3481 isc_result_t result;
3482 dns_rdataset_t rdataset;
3484 dns_fixedname_t foundname;
3487 INSIST(DNS_ADBNAME_VALID(adbname));
3489 INSIST(DNS_ADB_VALID(adb));
3490 INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
3492 dns_fixedname_init(&foundname);
3493 fname = dns_fixedname_name(&foundname);
3494 dns_rdataset_init(&rdataset);
3496 if (rdtype == dns_rdatatype_a)
3497 adbname->fetch_err = FIND_ERR_UNEXPECTED;
3499 adbname->fetch6_err = FIND_ERR_UNEXPECTED;
3502 * We need to specify whether to search static-stub zones (if
3503 * configured) depending on whether this is a "start at zone" lookup,
3504 * i.e., whether it's a "bailiwick" glue. If it's bailiwick (in which
3505 * case NAME_STARTATZONE is set) we need to stop the search at any
3506 * matching static-stub zone without looking into the cache to honor
3507 * the configuration on which server we should send queries to.
3509 result = dns_view_find2(adb->view, &adbname->name, rdtype, now,
3510 NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0,
3511 ISC_TF(NAME_HINTOK(adbname)),
3512 (adbname->flags & NAME_STARTATZONE) != 0 ?
3513 ISC_TRUE : ISC_FALSE,
3514 NULL, NULL, fname, &rdataset, NULL);
3516 /* XXXVIX this switch statement is too sparse to gen a jump table. */
3522 * Found in the database. Even if we can't copy out
3523 * any information, return success, or else a fetch
3524 * will be made, which will only make things worse.
3526 if (rdtype == dns_rdatatype_a)
3527 adbname->fetch_err = FIND_ERR_SUCCESS;
3529 adbname->fetch6_err = FIND_ERR_SUCCESS;
3530 result = import_rdataset(adbname, &rdataset, now);
3532 case DNS_R_NXDOMAIN:
3535 * We're authoritative and the data doesn't exist.
3536 * Make up a negative cache entry so we don't ask again
3539 * XXXRTH What time should we use? I'm putting in 30 seconds
3542 if (rdtype == dns_rdatatype_a) {
3543 adbname->expire_v4 = now + 30;
3545 "adb name %p: Caching auth negative entry for A",
3547 if (result == DNS_R_NXDOMAIN)
3548 adbname->fetch_err = FIND_ERR_NXDOMAIN;
3550 adbname->fetch_err = FIND_ERR_NXRRSET;
3553 "adb name %p: Caching auth negative entry for AAAA",
3555 adbname->expire_v6 = now + 30;
3556 if (result == DNS_R_NXDOMAIN)
3557 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3559 adbname->fetch6_err = FIND_ERR_NXRRSET;
3562 case DNS_R_NCACHENXDOMAIN:
3563 case DNS_R_NCACHENXRRSET:
3565 * We found a negative cache entry. Pull the TTL from it
3566 * so we won't ask again for a while.
3568 rdataset.ttl = ttlclamp(rdataset.ttl);
3569 if (rdtype == dns_rdatatype_a) {
3570 adbname->expire_v4 = rdataset.ttl + now;
3571 if (result == DNS_R_NCACHENXDOMAIN)
3572 adbname->fetch_err = FIND_ERR_NXDOMAIN;
3574 adbname->fetch_err = FIND_ERR_NXRRSET;
3576 "adb name %p: Caching negative entry for A (ttl %u)",
3577 adbname, rdataset.ttl);
3580 "adb name %p: Caching negative entry for AAAA (ttl %u)",
3581 adbname, rdataset.ttl);
3582 adbname->expire_v6 = rdataset.ttl + now;
3583 if (result == DNS_R_NCACHENXDOMAIN)
3584 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3586 adbname->fetch6_err = FIND_ERR_NXRRSET;
3592 * Clear the hint and glue flags, so this will match
3595 adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
3597 rdataset.ttl = ttlclamp(rdataset.ttl);
3598 clean_target(adb, &adbname->target);
3599 adbname->expire_target = INT_MAX;
3600 result = set_target(adb, &adbname->name, fname, &rdataset,
3602 if (result == ISC_R_SUCCESS) {
3603 result = DNS_R_ALIAS;
3605 "adb name %p: caching alias target",
3607 adbname->expire_target = rdataset.ttl + now;
3609 if (rdtype == dns_rdatatype_a)
3610 adbname->fetch_err = FIND_ERR_SUCCESS;
3612 adbname->fetch6_err = FIND_ERR_SUCCESS;
3616 if (dns_rdataset_isassociated(&rdataset))
3617 dns_rdataset_disassociate(&rdataset);
3623 fetch_callback(isc_task_t *task, isc_event_t *ev) {
3624 dns_fetchevent_t *dev;
3625 dns_adbname_t *name;
3627 dns_adbfetch_t *fetch;
3629 isc_eventtype_t ev_status;
3631 isc_result_t result;
3632 unsigned int address_type;
3633 isc_boolean_t want_check_exit = ISC_FALSE;
3637 INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
3638 dev = (dns_fetchevent_t *)ev;
3640 INSIST(DNS_ADBNAME_VALID(name));
3642 INSIST(DNS_ADB_VALID(adb));
3644 bucket = name->lock_bucket;
3645 LOCK(&adb->namelocks[bucket]);
3647 INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
3649 if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
3650 address_type = DNS_ADBFIND_INET;
3651 fetch = name->fetch_a;
3652 name->fetch_a = NULL;
3653 } else if (NAME_FETCH_AAAA(name)
3654 && (name->fetch_aaaa->fetch == dev->fetch)) {
3655 address_type = DNS_ADBFIND_INET6;
3656 fetch = name->fetch_aaaa;
3657 name->fetch_aaaa = NULL;
3661 INSIST(address_type != 0 && fetch != NULL);
3663 dns_resolver_destroyfetch(&fetch->fetch);
3666 ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
3669 * Cleanup things we don't care about.
3671 if (dev->node != NULL)
3672 dns_db_detachnode(dev->db, &dev->node);
3673 if (dev->db != NULL)
3674 dns_db_detach(&dev->db);
3677 * If this name is marked as dead, clean up, throwing away
3678 * potentially good data.
3680 if (NAME_DEAD(name)) {
3681 free_adbfetch(adb, &fetch);
3682 isc_event_free(&ev);
3684 want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
3686 UNLOCK(&adb->namelocks[bucket]);
3688 if (want_check_exit) {
3697 isc_stdtime_get(&now);
3700 * If we got a negative cache response, remember it.
3702 if (NCACHE_RESULT(dev->result)) {
3703 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3704 if (address_type == DNS_ADBFIND_INET) {
3705 DP(NCACHE_LEVEL, "adb fetch name %p: "
3706 "caching negative entry for A (ttl %u)",
3707 name, dev->rdataset->ttl);
3708 name->expire_v4 = ISC_MIN(name->expire_v4,
3709 dev->rdataset->ttl + now);
3710 if (dev->result == DNS_R_NCACHENXDOMAIN)
3711 name->fetch_err = FIND_ERR_NXDOMAIN;
3713 name->fetch_err = FIND_ERR_NXRRSET;
3714 inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
3716 DP(NCACHE_LEVEL, "adb fetch name %p: "
3717 "caching negative entry for AAAA (ttl %u)",
3718 name, dev->rdataset->ttl);
3719 name->expire_v6 = ISC_MIN(name->expire_v6,
3720 dev->rdataset->ttl + now);
3721 if (dev->result == DNS_R_NCACHENXDOMAIN)
3722 name->fetch6_err = FIND_ERR_NXDOMAIN;
3724 name->fetch6_err = FIND_ERR_NXRRSET;
3725 inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
3731 * Handle CNAME/DNAME.
3733 if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
3734 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3735 clean_target(adb, &name->target);
3736 name->expire_target = INT_MAX;
3737 result = set_target(adb, &name->name,
3738 dns_fixedname_name(&dev->foundname),
3741 if (result == ISC_R_SUCCESS) {
3743 "adb fetch name %p: caching alias target",
3745 name->expire_target = dev->rdataset->ttl + now;
3751 * Did we get back junk? If so, and there are no more fetches
3752 * sitting out there, tell all the finds about it.
3754 if (dev->result != ISC_R_SUCCESS) {
3755 char buf[DNS_NAME_FORMATSIZE];
3757 dns_name_format(&name->name, buf, sizeof(buf));
3758 DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
3759 buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
3760 dns_result_totext(dev->result));
3762 * Don't record a failure unless this is the initial
3765 if (fetch->depth > 1)
3767 /* XXXMLG Don't pound on bad servers. */
3768 if (address_type == DNS_ADBFIND_INET) {
3769 name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
3770 name->fetch_err = FIND_ERR_FAILURE;
3771 inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
3773 name->expire_v6 = ISC_MIN(name->expire_v6, now + 300);
3774 name->fetch6_err = FIND_ERR_FAILURE;
3775 inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
3781 * We got something potentially useful.
3783 result = import_rdataset(name, &fetch->rdataset, now);
3786 if (result == ISC_R_SUCCESS) {
3787 ev_status = DNS_EVENT_ADBMOREADDRESSES;
3788 if (address_type == DNS_ADBFIND_INET)
3789 name->fetch_err = FIND_ERR_SUCCESS;
3791 name->fetch6_err = FIND_ERR_SUCCESS;
3795 free_adbfetch(adb, &fetch);
3796 isc_event_free(&ev);
3798 clean_finds_at_name(name, ev_status, address_type);
3800 UNLOCK(&adb->namelocks[bucket]);
3804 fetch_name(dns_adbname_t *adbname, isc_boolean_t start_at_zone,
3805 unsigned int depth, isc_counter_t *qc, dns_rdatatype_t type)
3807 isc_result_t result;
3808 dns_adbfetch_t *fetch = NULL;
3810 dns_fixedname_t fixed;
3812 dns_rdataset_t rdataset;
3813 dns_rdataset_t *nameservers;
3814 unsigned int options;
3816 INSIST(DNS_ADBNAME_VALID(adbname));
3818 INSIST(DNS_ADB_VALID(adb));
3820 INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
3821 (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
3823 adbname->fetch_err = FIND_ERR_NOTFOUND;
3827 dns_rdataset_init(&rdataset);
3829 options = DNS_FETCHOPT_NOVALIDATE;
3830 if (start_at_zone) {
3832 "fetch_name: starting at zone for name %p",
3834 dns_fixedname_init(&fixed);
3835 name = dns_fixedname_name(&fixed);
3836 result = dns_view_findzonecut2(adb->view, &adbname->name, name,
3837 0, 0, ISC_TRUE, ISC_FALSE,
3839 if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
3841 nameservers = &rdataset;
3842 options |= DNS_FETCHOPT_UNSHARED;
3845 fetch = new_adbfetch(adb);
3846 if (fetch == NULL) {
3847 result = ISC_R_NOMEMORY;
3850 fetch->depth = depth;
3852 result = dns_resolver_createfetch3(adb->view->resolver, &adbname->name,
3853 type, name, nameservers, NULL,
3854 NULL, 0, options, depth, qc,
3855 adb->task, fetch_callback, adbname,
3856 &fetch->rdataset, NULL,
3858 if (result != ISC_R_SUCCESS)
3861 if (type == dns_rdatatype_a) {
3862 adbname->fetch_a = fetch;
3863 inc_stats(adb, dns_resstatscounter_gluefetchv4);
3865 adbname->fetch_aaaa = fetch;
3866 inc_stats(adb, dns_resstatscounter_gluefetchv6);
3868 fetch = NULL; /* Keep us from cleaning this up below. */
3872 free_adbfetch(adb, &fetch);
3873 if (dns_rdataset_isassociated(&rdataset))
3874 dns_rdataset_disassociate(&rdataset);
3880 * XXXMLG Needs to take a find argument and an address info, no zone or adb,
3881 * since these can be extracted from the find itself.
3884 dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname,
3885 dns_rdatatype_t qtype, isc_stdtime_t expire_time)
3887 dns_adblameinfo_t *li;
3889 isc_result_t result = ISC_R_SUCCESS;
3891 REQUIRE(DNS_ADB_VALID(adb));
3892 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3893 REQUIRE(qname != NULL);
3895 bucket = addr->entry->lock_bucket;
3896 LOCK(&adb->entrylocks[bucket]);
3897 li = ISC_LIST_HEAD(addr->entry->lameinfo);
3898 while (li != NULL &&
3899 (li->qtype != qtype || !dns_name_equal(qname, &li->qname)))
3900 li = ISC_LIST_NEXT(li, plink);
3902 if (expire_time > li->lame_timer)
3903 li->lame_timer = expire_time;
3906 li = new_adblameinfo(adb, qname, qtype);
3908 result = ISC_R_NOMEMORY;
3912 li->lame_timer = expire_time;
3914 ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink);
3916 UNLOCK(&adb->entrylocks[bucket]);
3922 dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3923 unsigned int rtt, unsigned int factor)
3926 unsigned int new_srtt;
3929 REQUIRE(DNS_ADB_VALID(adb));
3930 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3931 REQUIRE(factor <= 10);
3933 bucket = addr->entry->lock_bucket;
3934 LOCK(&adb->entrylocks[bucket]);
3936 if (factor == DNS_ADB_RTTADJAGE)
3937 new_srtt = addr->entry->srtt * 98 / 100;
3939 new_srtt = (addr->entry->srtt / 10 * factor)
3940 + (rtt / 10 * (10 - factor));
3942 addr->entry->srtt = new_srtt;
3943 addr->srtt = new_srtt;
3945 if (addr->entry->expires == 0) {
3946 isc_stdtime_get(&now);
3947 addr->entry->expires = now + ADB_ENTRY_WINDOW;
3950 UNLOCK(&adb->entrylocks[bucket]);
3954 dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3955 unsigned int bits, unsigned int mask)
3960 REQUIRE(DNS_ADB_VALID(adb));
3961 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3963 bucket = addr->entry->lock_bucket;
3964 LOCK(&adb->entrylocks[bucket]);
3966 addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
3967 if (addr->entry->expires == 0) {
3968 isc_stdtime_get(&now);
3969 addr->entry->expires = now + ADB_ENTRY_WINDOW;
3973 * Note that we do not update the other bits in addr->flags with
3974 * the most recent values from addr->entry->flags.
3976 addr->flags = (addr->flags & ~mask) | (bits & mask);
3978 UNLOCK(&adb->entrylocks[bucket]);
3982 dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
3983 dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
3986 dns_adbentry_t *entry;
3987 dns_adbaddrinfo_t *addr;
3988 isc_result_t result;
3991 REQUIRE(DNS_ADB_VALID(adb));
3992 REQUIRE(addrp != NULL && *addrp == NULL);
3996 result = ISC_R_SUCCESS;
3997 bucket = DNS_ADB_INVALIDBUCKET;
3998 entry = find_entry_and_lock(adb, sa, &bucket, now);
3999 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
4000 if (adb->entry_sd[bucket]) {
4001 result = ISC_R_SHUTTINGDOWN;
4004 if (entry == NULL) {
4006 * We don't know anything about this address.
4008 entry = new_adbentry(adb);
4009 if (entry == NULL) {
4010 result = ISC_R_NOMEMORY;
4013 entry->sockaddr = *sa;
4014 link_entry(adb, bucket, entry);
4015 DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
4017 DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
4019 port = isc_sockaddr_getport(sa);
4020 addr = new_adbaddrinfo(adb, entry, port);
4022 result = ISC_R_NOMEMORY;
4024 inc_entry_refcnt(adb, entry, ISC_FALSE);
4029 UNLOCK(&adb->entrylocks[bucket]);
4035 dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
4036 dns_adbaddrinfo_t *addr;
4037 dns_adbentry_t *entry;
4040 isc_boolean_t want_check_exit = ISC_FALSE;
4041 isc_boolean_t overmem;
4043 REQUIRE(DNS_ADB_VALID(adb));
4044 REQUIRE(addrp != NULL);
4046 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4047 entry = addr->entry;
4048 REQUIRE(DNS_ADBENTRY_VALID(entry));
4051 overmem = isc_mem_isovermem(adb->mctx);
4053 bucket = addr->entry->lock_bucket;
4054 LOCK(&adb->entrylocks[bucket]);
4056 if (entry->expires == 0) {
4057 isc_stdtime_get(&now);
4058 entry->expires = now + ADB_ENTRY_WINDOW;
4061 want_check_exit = dec_entry_refcnt(adb, overmem, entry, ISC_FALSE);
4063 UNLOCK(&adb->entrylocks[bucket]);
4066 free_adbaddrinfo(adb, &addr);
4068 if (want_check_exit) {
4076 dns_adb_flush(dns_adb_t *adb) {
4079 INSIST(DNS_ADB_VALID(adb));
4084 * Call our cleanup routines.
4086 for (i = 0; i < adb->nnames; i++)
4087 RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
4088 for (i = 0; i < adb->nentries; i++)
4089 RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
4091 #ifdef DUMP_ADB_AFTER_CLEANING
4092 dump_adb(adb, stdout, ISC_TRUE, INT_MAX);
4099 dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
4100 dns_adbname_t *adbname;
4101 dns_adbname_t *nextname;
4104 INSIST(DNS_ADB_VALID(adb));
4107 bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames;
4108 LOCK(&adb->namelocks[bucket]);
4109 adbname = ISC_LIST_HEAD(adb->names[bucket]);
4110 while (adbname != NULL) {
4111 nextname = ISC_LIST_NEXT(adbname, plink);
4112 if (!NAME_DEAD(adbname) &&
4113 dns_name_equal(name, &adbname->name)) {
4114 RUNTIME_CHECK(kill_name(&adbname,
4115 DNS_EVENT_ADBCANCELED) ==
4120 UNLOCK(&adb->namelocks[bucket]);
4125 water(void *arg, int mark) {
4127 * We're going to change the way to handle overmem condition: use
4128 * isc_mem_isovermem() instead of storing the state via this callback,
4129 * since the latter way tends to cause race conditions.
4130 * To minimize the change, and in case we re-enable the callback
4131 * approach, however, keep this function at the moment.
4134 dns_adb_t *adb = arg;
4135 isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
4137 REQUIRE(DNS_ADB_VALID(adb));
4139 DP(ISC_LOG_DEBUG(1),
4140 "adb reached %s water mark", overmem ? "high" : "low");
4144 dns_adb_setadbsize(dns_adb_t *adb, isc_uint32_t size) {
4145 isc_uint32_t hiwater;
4146 isc_uint32_t lowater;
4148 INSIST(DNS_ADB_VALID(adb));
4150 if (size != 0 && size < DNS_ADB_MINADBSIZE)
4151 size = DNS_ADB_MINADBSIZE;
4153 hiwater = size - (size >> 3); /* Approximately 7/8ths. */
4154 lowater = size - (size >> 2); /* Approximately 3/4ths. */
4156 if (size == 0 || hiwater == 0 || lowater == 0)
4157 isc_mem_setwater(adb->mctx, water, adb, 0, 0);
4159 isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);