adb.c revision 135446
1/*
2 * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and 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.
8 *
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.
16 */
17
18/* $Id: adb.c,v 1.181.2.11.2.19 2004/09/01 05:19:57 marka Exp $ */
19
20/*
21 * Implementation notes
22 * --------------------
23 *
24 * In finds, if task == NULL, no events will be generated, and no events
25 * have been sent.  If task != NULL but taskaction == NULL, an event has been
26 * posted but not yet freed.  If neither are NULL, no event was posted.
27 *
28 */
29
30/*
31 * After we have cleaned all buckets, dump the database contents.
32 */
33#if 0
34#define DUMP_ADB_AFTER_CLEANING
35#endif
36
37#include <config.h>
38
39#include <limits.h>
40
41#include <isc/mutexblock.h>
42#include <isc/netaddr.h>
43#include <isc/random.h>
44#include <isc/string.h>		/* Required for HP/UX (and others?) */
45#include <isc/task.h>
46#include <isc/timer.h>
47#include <isc/util.h>
48
49#include <dns/adb.h>
50#include <dns/db.h>
51#include <dns/events.h>
52#include <dns/log.h>
53#include <dns/rdata.h>
54#include <dns/rdataset.h>
55#include <dns/rdatastruct.h>
56#include <dns/resolver.h>
57#include <dns/result.h>
58
59#define DNS_ADB_MAGIC		  ISC_MAGIC('D', 'a', 'd', 'b')
60#define DNS_ADB_VALID(x)	  ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
61#define DNS_ADBNAME_MAGIC	  ISC_MAGIC('a', 'd', 'b', 'N')
62#define DNS_ADBNAME_VALID(x)	  ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
63#define DNS_ADBNAMEHOOK_MAGIC	  ISC_MAGIC('a', 'd', 'N', 'H')
64#define DNS_ADBNAMEHOOK_VALID(x)  ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
65#define DNS_ADBZONEINFO_MAGIC	  ISC_MAGIC('a', 'd', 'b', 'Z')
66#define DNS_ADBZONEINFO_VALID(x)  ISC_MAGIC_VALID(x, DNS_ADBZONEINFO_MAGIC)
67#define DNS_ADBENTRY_MAGIC	  ISC_MAGIC('a', 'd', 'b', 'E')
68#define DNS_ADBENTRY_VALID(x)	  ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
69#define DNS_ADBFETCH_MAGIC	  ISC_MAGIC('a', 'd', 'F', '4')
70#define DNS_ADBFETCH_VALID(x)	  ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
71#define DNS_ADBFETCH6_MAGIC	  ISC_MAGIC('a', 'd', 'F', '6')
72#define DNS_ADBFETCH6_VALID(x)	  ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
73
74/*
75 * The number of buckets needs to be a prime (for good hashing).
76 *
77 * XXXRTH  How many buckets do we need?
78 */
79#define NBUCKETS	       1009	/* how many buckets for names/addrs */
80
81/*
82 * For type 3 negative cache entries, we will remember that the address is
83 * broken for this long.  XXXMLG This is also used for actual addresses, too.
84 * The intent is to keep us from constantly asking about A/AAAA records
85 * if the zone has extremely low TTLs.
86 */
87#define ADB_CACHE_MINIMUM	10	/* seconds */
88#define ADB_CACHE_MAXIMUM	86400	/* seconds (86400 = 24 hours) */
89#define ADB_ENTRY_WINDOW	1800	/* seconds */
90
91/*
92 * Wake up every CLEAN_SECONDS and clean CLEAN_BUCKETS buckets, so that all
93 * buckets are cleaned in CLEAN_PERIOD seconds.
94 */
95#define CLEAN_PERIOD		3600
96#define CLEAN_SECONDS		30
97#define CLEAN_BUCKETS		((NBUCKETS * CLEAN_SECONDS) / CLEAN_PERIOD)
98
99#define FREE_ITEMS		64	/* free count for memory pools */
100#define FILL_COUNT		16	/* fill count for memory pools */
101
102#define DNS_ADB_INVALIDBUCKET (-1)	/* invalid bucket address */
103
104#define DNS_ADB_MINADBSIZE	(1024*1024)	/* 1 Megabyte */
105
106typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
107typedef struct dns_adbnamehook dns_adbnamehook_t;
108typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
109typedef struct dns_adbzoneinfo dns_adbzoneinfo_t;
110typedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t;
111typedef struct dns_adbfetch dns_adbfetch_t;
112typedef struct dns_adbfetch6 dns_adbfetch6_t;
113
114struct dns_adb {
115	unsigned int			magic;
116
117	isc_mutex_t			lock;
118	isc_mutex_t			reflock; /* Covers irefcnt, erefcnt */
119	isc_mem_t		       *mctx;
120	dns_view_t		       *view;
121	isc_timermgr_t		       *timermgr;
122	isc_timer_t		       *timer;
123	isc_taskmgr_t		       *taskmgr;
124	isc_task_t		       *task;
125	isc_boolean_t			overmem;
126
127	isc_interval_t			tick_interval;
128	int				next_cleanbucket;
129
130	unsigned int			irefcnt;
131	unsigned int			erefcnt;
132
133	isc_mutex_t			mplock;
134	isc_mempool_t		       *nmp;	/* dns_adbname_t */
135	isc_mempool_t		       *nhmp;	/* dns_adbnamehook_t */
136	isc_mempool_t		       *zimp;	/* dns_adbzoneinfo_t */
137	isc_mempool_t		       *emp;	/* dns_adbentry_t */
138	isc_mempool_t		       *ahmp;	/* dns_adbfind_t */
139	isc_mempool_t		       *aimp;	/* dns_adbaddrinfo_t */
140	isc_mempool_t		       *afmp;	/* dns_adbfetch_t */
141
142	/*
143	 * Bucketized locks and lists for names.
144	 *
145	 * XXXRTH  Have a per-bucket structure that contains all of these?
146	 */
147	dns_adbnamelist_t		names[NBUCKETS];
148	isc_mutex_t			namelocks[NBUCKETS];
149	isc_boolean_t			name_sd[NBUCKETS];
150	unsigned int			name_refcnt[NBUCKETS];
151
152	/*
153	 * Bucketized locks for entries.
154	 *
155	 * XXXRTH  Have a per-bucket structure that contains all of these?
156	 */
157	dns_adbentrylist_t		entries[NBUCKETS];
158	isc_mutex_t			entrylocks[NBUCKETS];
159	isc_boolean_t			entry_sd[NBUCKETS]; /* shutting down */
160	unsigned int			entry_refcnt[NBUCKETS];
161
162	isc_event_t			cevent;
163	isc_boolean_t			cevent_sent;
164	isc_boolean_t			shutting_down;
165	isc_eventlist_t			whenshutdown;
166};
167
168/*
169 * XXXMLG  Document these structures.
170 */
171
172struct dns_adbname {
173	unsigned int			magic;
174	dns_name_t			name;
175	dns_adb_t		       *adb;
176	unsigned int			partial_result;
177	unsigned int			flags;
178	int				lock_bucket;
179	dns_name_t			target;
180	isc_stdtime_t			expire_target;
181	isc_stdtime_t			expire_v4;
182	isc_stdtime_t			expire_v6;
183	unsigned int			chains;
184	dns_adbnamehooklist_t		v4;
185	dns_adbnamehooklist_t		v6;
186	dns_adbfetch_t		       *fetch_a;
187	dns_adbfetch_t		       *fetch_aaaa;
188	unsigned int			fetch_err;
189	unsigned int			fetch6_err;
190	dns_adbfindlist_t		finds;
191	ISC_LINK(dns_adbname_t)		plink;
192};
193
194struct dns_adbfetch {
195	unsigned int			magic;
196	dns_adbnamehook_t	       *namehook;
197	dns_adbentry_t		       *entry;
198	dns_fetch_t		       *fetch;
199	dns_rdataset_t			rdataset;
200};
201
202/*
203 * dns_adbnamehook_t
204 *
205 * This is a small widget that dangles off a dns_adbname_t.  It contains a
206 * pointer to the address information about this host, and a link to the next
207 * namehook that will contain the next address this host has.
208 */
209struct dns_adbnamehook {
210	unsigned int			magic;
211	dns_adbentry_t		       *entry;
212	ISC_LINK(dns_adbnamehook_t)	plink;
213};
214
215/*
216 * dns_adbzoneinfo_t
217 *
218 * This is a small widget that holds zone-specific information about an
219 * address.  Currently limited to lameness, but could just as easily be
220 * extended to other types of information about zones.
221 */
222struct dns_adbzoneinfo {
223	unsigned int			magic;
224
225	dns_name_t			zone;
226	isc_stdtime_t			lame_timer;
227
228	ISC_LINK(dns_adbzoneinfo_t)	plink;
229};
230
231/*
232 * An address entry.  It holds quite a bit of information about addresses,
233 * including edns state (in "flags"), rtt, and of course the address of
234 * the host.
235 */
236struct dns_adbentry {
237	unsigned int			magic;
238
239	int				lock_bucket;
240	unsigned int			refcnt;
241
242	unsigned int			flags;
243	unsigned int			srtt;
244	isc_sockaddr_t			sockaddr;
245
246	isc_stdtime_t			expires;
247	/*
248	 * A nonzero 'expires' field indicates that the entry should
249	 * persist until that time.  This allows entries found
250	 * using dns_adb_findaddrinfo() to persist for a limited time
251	 * even though they are not necessarily associated with a
252	 * name.
253	 */
254
255	ISC_LIST(dns_adbzoneinfo_t)	zoneinfo;
256	ISC_LINK(dns_adbentry_t)	plink;
257};
258
259/*
260 * Internal functions (and prototypes).
261 */
262static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
263static inline void free_adbname(dns_adb_t *, dns_adbname_t **);
264static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
265						 dns_adbentry_t *);
266static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
267static inline dns_adbzoneinfo_t *new_adbzoneinfo(dns_adb_t *, dns_name_t *);
268static inline void free_adbzoneinfo(dns_adb_t *, dns_adbzoneinfo_t **);
269static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
270static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
271static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
272static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
273static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
274						 in_port_t);
275static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
276static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
277static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
278						unsigned int, int *);
279static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
280						  isc_sockaddr_t *, int *);
281static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug);
282static void print_dns_name(FILE *, dns_name_t *);
283static void print_namehook_list(FILE *, const char *legend,
284				dns_adbnamehooklist_t *list,
285				isc_boolean_t debug,
286				isc_stdtime_t now);
287static void print_find_list(FILE *, dns_adbname_t *);
288static void print_fetch_list(FILE *, dns_adbname_t *);
289static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
290static inline void inc_adb_irefcnt(dns_adb_t *);
291static inline void inc_adb_erefcnt(dns_adb_t *);
292static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
293				    isc_boolean_t);
294static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
295					     isc_boolean_t);
296static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
297static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
298static void clean_target(dns_adb_t *, dns_name_t *);
299static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
300				unsigned int);
301static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t,
302					    isc_boolean_t);
303static void cancel_fetches_at_name(dns_adbname_t *);
304static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
305				dns_rdatatype_t);
306static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
307			       dns_rdatatype_t);
308static inline void check_exit(dns_adb_t *);
309static void timer_cleanup(isc_task_t *, isc_event_t *);
310static void destroy(dns_adb_t *);
311static isc_boolean_t shutdown_names(dns_adb_t *);
312static isc_boolean_t shutdown_entries(dns_adb_t *);
313static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
314static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *);
315static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
316static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
317static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
318static void water(void *arg, int mark);
319
320/*
321 * MUST NOT overlap DNS_ADBFIND_* flags!
322 */
323#define FIND_EVENT_SENT		0x40000000
324#define FIND_EVENT_FREED	0x80000000
325#define FIND_EVENTSENT(h)	(((h)->flags & FIND_EVENT_SENT) != 0)
326#define FIND_EVENTFREED(h)	(((h)->flags & FIND_EVENT_FREED) != 0)
327
328#define NAME_NEEDS_POKE		0x80000000
329#define NAME_IS_DEAD		0x40000000
330#define NAME_HINT_OK		DNS_ADBFIND_HINTOK
331#define NAME_GLUE_OK		DNS_ADBFIND_GLUEOK
332#define NAME_STARTATZONE	DNS_ADBFIND_STARTATZONE
333#define NAME_DEAD(n)		(((n)->flags & NAME_IS_DEAD) != 0)
334#define NAME_NEEDSPOKE(n)	(((n)->flags & NAME_NEEDS_POKE) != 0)
335#define NAME_GLUEOK(n)		(((n)->flags & NAME_GLUE_OK) != 0)
336#define NAME_HINTOK(n)		(((n)->flags & NAME_HINT_OK) != 0)
337
338/*
339 * To the name, address classes are all that really exist.  If it has a
340 * V6 address it doesn't care if it came from a AAAA query.
341 */
342#define NAME_HAS_V4(n)		(!ISC_LIST_EMPTY((n)->v4))
343#define NAME_HAS_V6(n)		(!ISC_LIST_EMPTY((n)->v6))
344#define NAME_HAS_ADDRS(n)	(NAME_HAS_V4(n) || NAME_HAS_V6(n))
345
346/*
347 * Fetches are broken out into A and AAAA types.  In some cases,
348 * however, it makes more sense to test for a particular class of fetches,
349 * like V4 or V6 above.
350 * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA
351 * are now equal to FETCH_V4 and FETCH_V6, respectively.
352 */
353#define NAME_FETCH_A(n)		((n)->fetch_a != NULL)
354#define NAME_FETCH_AAAA(n)	((n)->fetch_aaaa != NULL)
355#define NAME_FETCH_V4(n)	(NAME_FETCH_A(n))
356#define NAME_FETCH_V6(n)	(NAME_FETCH_AAAA(n))
357#define NAME_FETCH(n)		(NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
358
359/*
360 * Find options and tests to see if there are addresses on the list.
361 */
362#define FIND_WANTEVENT(fn)	(((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
363#define FIND_WANTEMPTYEVENT(fn)	(((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
364#define FIND_AVOIDFETCHES(fn)	(((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
365				 != 0)
366#define FIND_STARTATZONE(fn)	(((fn)->options & DNS_ADBFIND_STARTATZONE) \
367				 != 0)
368#define FIND_HINTOK(fn)		(((fn)->options & DNS_ADBFIND_HINTOK) != 0)
369#define FIND_GLUEOK(fn)		(((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
370#define FIND_HAS_ADDRS(fn)	(!ISC_LIST_EMPTY((fn)->list))
371#define FIND_RETURNLAME(fn)	(((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
372
373/*
374 * These are currently used on simple unsigned ints, so they are
375 * not really associated with any particular type.
376 */
377#define WANT_INET(x)		(((x) & DNS_ADBFIND_INET) != 0)
378#define WANT_INET6(x)		(((x) & DNS_ADBFIND_INET6) != 0)
379
380#define EXPIRE_OK(exp, now)	((exp == INT_MAX) || (exp < now))
381
382/*
383 * Find out if the flags on a name (nf) indicate if it is a hint or
384 * glue, and compare this to the appropriate bits set in o, to see if
385 * this is ok.
386 */
387#define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0))
388#define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0))
389#define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o))
390#define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \
391				    ((o) & DNS_ADBFIND_STARTATZONE))
392
393#define ENTER_LEVEL		ISC_LOG_DEBUG(50)
394#define EXIT_LEVEL		ENTER_LEVEL
395#define CLEAN_LEVEL		ISC_LOG_DEBUG(100)
396#define DEF_LEVEL		ISC_LOG_DEBUG(5)
397#define NCACHE_LEVEL		ISC_LOG_DEBUG(20)
398
399#define NCACHE_RESULT(r)	((r) == DNS_R_NCACHENXDOMAIN || \
400				 (r) == DNS_R_NCACHENXRRSET)
401#define AUTH_NX(r)		((r) == DNS_R_NXDOMAIN || \
402				 (r) == DNS_R_NXRRSET)
403#define NXDOMAIN_RESULT(r)	((r) == DNS_R_NXDOMAIN || \
404				 (r) == DNS_R_NCACHENXDOMAIN)
405#define NXRRSET_RESULT(r)	((r) == DNS_R_NCACHENXRRSET || \
406				 (r) == DNS_R_NXRRSET || \
407				 (r) == DNS_R_HINTNXRRSET)
408
409/*
410 * Error state rankings.
411 */
412
413#define FIND_ERR_SUCCESS		0  /* highest rank */
414#define FIND_ERR_CANCELED		1
415#define FIND_ERR_FAILURE		2
416#define FIND_ERR_NXDOMAIN		3
417#define FIND_ERR_NXRRSET		4
418#define FIND_ERR_UNEXPECTED		5
419#define FIND_ERR_NOTFOUND		6
420#define FIND_ERR_MAX			7
421
422static const char *errnames[] = {
423	"success",
424	"canceled",
425	"failure",
426	"nxdomain",
427	"nxrrset",
428	"unexpected",
429	"not_found"
430};
431
432#define NEWERR(old, new)	(ISC_MIN((old), (new)))
433
434static isc_result_t find_err_map[FIND_ERR_MAX] = {
435	ISC_R_SUCCESS,
436	ISC_R_CANCELED,
437	ISC_R_FAILURE,
438	DNS_R_NXDOMAIN,
439	DNS_R_NXRRSET,
440	ISC_R_UNEXPECTED,
441	ISC_R_NOTFOUND		/* not YET found */
442};
443
444static void
445DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
446
447static void
448DP(int level, const char *format, ...) {
449	va_list args;
450
451	va_start(args, format);
452	isc_log_vwrite(dns_lctx,
453		       DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
454		       level, format, args);
455	va_end(args);
456}
457
458static inline dns_ttl_t
459ttlclamp(dns_ttl_t ttl) {
460	if (ttl < ADB_CACHE_MINIMUM)
461		ttl = ADB_CACHE_MINIMUM;
462	if (ttl > ADB_CACHE_MAXIMUM)
463		ttl = ADB_CACHE_MAXIMUM;
464
465	return (ttl);
466}
467
468/*
469 * Requires the adbname bucket be locked and that no entry buckets be locked.
470 *
471 * This code handles A and AAAA rdatasets only.
472 */
473static isc_result_t
474import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
475		isc_stdtime_t now)
476{
477	isc_result_t result;
478	dns_adb_t *adb;
479	dns_adbnamehook_t *nh;
480	dns_adbnamehook_t *anh;
481	dns_rdata_t rdata = DNS_RDATA_INIT;
482	struct in_addr ina;
483	struct in6_addr in6a;
484	isc_sockaddr_t sockaddr;
485	dns_adbentry_t *foundentry;  /* NO CLEAN UP! */
486	int addr_bucket;
487	isc_boolean_t new_addresses_added;
488	dns_rdatatype_t rdtype;
489	unsigned int findoptions;
490
491	INSIST(DNS_ADBNAME_VALID(adbname));
492	adb = adbname->adb;
493	INSIST(DNS_ADB_VALID(adb));
494
495	rdtype = rdataset->type;
496	INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
497	if (rdtype == dns_rdatatype_a)
498		findoptions = DNS_ADBFIND_INET;
499	else
500		findoptions = DNS_ADBFIND_INET6;
501
502	addr_bucket = DNS_ADB_INVALIDBUCKET;
503	new_addresses_added = ISC_FALSE;
504
505	nh = NULL;
506	result = dns_rdataset_first(rdataset);
507	while (result == ISC_R_SUCCESS) {
508		dns_rdata_reset(&rdata);
509		dns_rdataset_current(rdataset, &rdata);
510		if (rdtype == dns_rdatatype_a) {
511			INSIST(rdata.length == 4);
512			memcpy(&ina.s_addr, rdata.data, 4);
513			isc_sockaddr_fromin(&sockaddr, &ina, 0);
514		} else {
515			INSIST(rdata.length == 16);
516			memcpy(in6a.s6_addr, rdata.data, 16);
517			isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
518		}
519
520		INSIST(nh == NULL);
521		nh = new_adbnamehook(adb, NULL);
522		if (nh == NULL) {
523			adbname->partial_result |= findoptions;
524			result = ISC_R_NOMEMORY;
525			goto fail;
526		}
527
528		foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket);
529		if (foundentry == NULL) {
530			dns_adbentry_t *entry;
531
532			entry = new_adbentry(adb);
533			if (entry == NULL) {
534				adbname->partial_result |= findoptions;
535				result = ISC_R_NOMEMORY;
536				goto fail;
537			}
538
539			entry->sockaddr = sockaddr;
540			entry->refcnt = 1;
541
542			nh->entry = entry;
543
544			link_entry(adb, addr_bucket, entry);
545		} else {
546			for (anh = ISC_LIST_HEAD(adbname->v4);
547			     anh != NULL;
548			     anh = ISC_LIST_NEXT(anh, plink))
549				if (anh->entry == foundentry)
550					break;
551			if (anh == NULL) {
552				foundentry->refcnt++;
553				nh->entry = foundentry;
554			} else
555				free_adbnamehook(adb, &nh);
556		}
557
558		new_addresses_added = ISC_TRUE;
559		if (nh != NULL) {
560			if (rdtype == dns_rdatatype_a)
561				ISC_LIST_APPEND(adbname->v4, nh, plink);
562			else
563				ISC_LIST_APPEND(adbname->v6, nh, plink);
564		}
565		nh = NULL;
566		result = dns_rdataset_next(rdataset);
567	}
568
569 fail:
570	if (nh != NULL)
571		free_adbnamehook(adb, &nh);
572
573	if (addr_bucket != DNS_ADB_INVALIDBUCKET)
574		UNLOCK(&adb->entrylocks[addr_bucket]);
575
576	if (rdataset->trust == dns_trust_glue ||
577	    rdataset->trust == dns_trust_additional)
578		rdataset->ttl = ADB_CACHE_MINIMUM;
579	else
580		rdataset->ttl = ttlclamp(rdataset->ttl);
581
582	if (rdtype == dns_rdatatype_a) {
583		DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
584		   adbname->expire_v4, now + rdataset->ttl);
585		adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
586					     now + rdataset->ttl);
587	} else {
588		DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
589		   adbname->expire_v6, now + rdataset->ttl);
590		adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
591					     now + rdataset->ttl);
592	}
593
594	if (new_addresses_added) {
595		/*
596		 * Lie a little here.  This is more or less so code that cares
597		 * can find out if any new information was added or not.
598		 */
599		return (ISC_R_SUCCESS);
600	}
601
602	return (result);
603}
604
605/*
606 * Requires the name's bucket be locked.
607 */
608static isc_boolean_t
609kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
610	dns_adbname_t *name;
611	isc_boolean_t result = ISC_FALSE;
612	isc_boolean_t result4, result6;
613	dns_adb_t *adb;
614
615	INSIST(n != NULL);
616	name = *n;
617	*n = NULL;
618	INSIST(DNS_ADBNAME_VALID(name));
619	adb = name->adb;
620	INSIST(DNS_ADB_VALID(adb));
621
622	DP(DEF_LEVEL, "killing name %p", name);
623
624	/*
625	 * If we're dead already, just check to see if we should go
626	 * away now or not.
627	 */
628	if (NAME_DEAD(name) && !NAME_FETCH(name)) {
629		result = unlink_name(adb, name);
630		free_adbname(adb, &name);
631		if (result)
632			result = dec_adb_irefcnt(adb);
633		return (result);
634	}
635
636	/*
637	 * Clean up the name's various lists.  These two are destructive
638	 * in that they will always empty the list.
639	 */
640	clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
641	result4 = clean_namehooks(adb, &name->v4);
642	result6 = clean_namehooks(adb, &name->v6);
643	clean_target(adb, &name->target);
644	result = ISC_TF(result4 || result6);
645
646	/*
647	 * If fetches are running, cancel them.  If none are running, we can
648	 * just kill the name here.
649	 */
650	if (!NAME_FETCH(name)) {
651		INSIST(result == ISC_FALSE);
652		result = unlink_name(adb, name);
653		free_adbname(adb, &name);
654		if (result)
655			result = dec_adb_irefcnt(adb);
656	} else {
657		name->flags |= NAME_IS_DEAD;
658		cancel_fetches_at_name(name);
659	}
660	return (result);
661}
662
663/*
664 * Requires the name's bucket be locked and no entry buckets be locked.
665 */
666static isc_boolean_t
667check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now,
668		       isc_boolean_t overmem)
669{
670	dns_adb_t *adb;
671	isc_boolean_t expire;
672	isc_boolean_t result4 = ISC_FALSE;
673	isc_boolean_t result6 = ISC_FALSE;
674
675	INSIST(DNS_ADBNAME_VALID(name));
676	adb = name->adb;
677	INSIST(DNS_ADB_VALID(adb));
678
679	if (overmem) {
680		isc_uint32_t val;
681
682		isc_random_get(&val);
683
684		expire = ISC_TF((val % 4) == 0);
685	} else
686		expire = ISC_FALSE;
687
688	/*
689	 * Check to see if we need to remove the v4 addresses
690	 */
691	if (!NAME_FETCH_V4(name) &&
692	    (expire || EXPIRE_OK(name->expire_v4, now))) {
693		if (NAME_HAS_V4(name)) {
694			DP(DEF_LEVEL, "expiring v4 for name %p", name);
695			result4 = clean_namehooks(adb, &name->v4);
696			name->partial_result &= ~DNS_ADBFIND_INET;
697		}
698		name->expire_v4 = INT_MAX;
699		name->fetch_err = FIND_ERR_UNEXPECTED;
700	}
701
702	/*
703	 * Check to see if we need to remove the v6 addresses
704	 */
705	if (!NAME_FETCH_V6(name) &&
706	    (expire || EXPIRE_OK(name->expire_v6, now))) {
707		if (NAME_HAS_V6(name)) {
708			DP(DEF_LEVEL, "expiring v6 for name %p", name);
709			result6 = clean_namehooks(adb, &name->v6);
710			name->partial_result &= ~DNS_ADBFIND_INET6;
711		}
712		name->expire_v6 = INT_MAX;
713		name->fetch6_err = FIND_ERR_UNEXPECTED;
714	}
715
716	/*
717	 * Check to see if we need to remove the alias target.
718	 */
719	if (expire || EXPIRE_OK(name->expire_target, now)) {
720		clean_target(adb, &name->target);
721		name->expire_target = INT_MAX;
722	}
723	return (ISC_TF(result4 || result6));
724}
725
726/*
727 * Requires the name's bucket be locked.
728 */
729static inline void
730link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
731	INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
732
733	ISC_LIST_PREPEND(adb->names[bucket], name, plink);
734	name->lock_bucket = bucket;
735	adb->name_refcnt[bucket]++;
736}
737
738/*
739 * Requires the name's bucket be locked.
740 */
741static inline isc_boolean_t
742unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
743	int bucket;
744	isc_boolean_t result = ISC_FALSE;
745
746	bucket = name->lock_bucket;
747	INSIST(bucket != DNS_ADB_INVALIDBUCKET);
748
749	ISC_LIST_UNLINK(adb->names[bucket], name, plink);
750	name->lock_bucket = DNS_ADB_INVALIDBUCKET;
751	INSIST(adb->name_refcnt[bucket] > 0);
752	adb->name_refcnt[bucket]--;
753	if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
754		result = ISC_TRUE;
755	return (result);
756}
757
758/*
759 * Requires the entry's bucket be locked.
760 */
761static inline void
762link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
763	ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
764	entry->lock_bucket = bucket;
765	adb->entry_refcnt[bucket]++;
766}
767
768/*
769 * Requires the entry's bucket be locked.
770 */
771static inline isc_boolean_t
772unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
773	int bucket;
774	isc_boolean_t result = ISC_FALSE;
775
776	bucket = entry->lock_bucket;
777	INSIST(bucket != DNS_ADB_INVALIDBUCKET);
778
779	ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
780	entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
781	INSIST(adb->entry_refcnt[bucket] > 0);
782	adb->entry_refcnt[bucket]--;
783	if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
784		result = ISC_TRUE;
785	return (result);
786}
787
788static inline void
789violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
790	if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
791		UNLOCK(have);
792		LOCK(want);
793		LOCK(have);
794	}
795}
796
797/*
798 * The ADB _MUST_ be locked before calling.  Also, exit conditions must be
799 * checked after calling this function.
800 */
801static isc_boolean_t
802shutdown_names(dns_adb_t *adb) {
803	int bucket;
804	isc_boolean_t result = ISC_FALSE;
805	dns_adbname_t *name;
806	dns_adbname_t *next_name;
807
808	for (bucket = 0; bucket < NBUCKETS; bucket++) {
809		LOCK(&adb->namelocks[bucket]);
810		adb->name_sd[bucket] = ISC_TRUE;
811
812		name = ISC_LIST_HEAD(adb->names[bucket]);
813		if (name == NULL) {
814			/*
815			 * This bucket has no names.  We must decrement the
816			 * irefcnt ourselves, since it will not be
817			 * automatically triggered by a name being unlinked.
818			 */
819			INSIST(result == ISC_FALSE);
820			result = dec_adb_irefcnt(adb);
821		} else {
822			/*
823			 * Run through the list.  For each name, clean up finds
824			 * found there, and cancel any fetches running.  When
825			 * all the fetches are canceled, the name will destroy
826			 * itself.
827			 */
828			while (name != NULL) {
829				next_name = ISC_LIST_NEXT(name, plink);
830				INSIST(result == ISC_FALSE);
831				result = kill_name(&name,
832						   DNS_EVENT_ADBSHUTDOWN);
833				name = next_name;
834			}
835		}
836
837		UNLOCK(&adb->namelocks[bucket]);
838	}
839	return (result);
840}
841
842/*
843 * The ADB _MUST_ be locked before calling.  Also, exit conditions must be
844 * checked after calling this function.
845 */
846static isc_boolean_t
847shutdown_entries(dns_adb_t *adb) {
848	int bucket;
849	isc_boolean_t result = ISC_FALSE;
850	dns_adbentry_t *entry;
851	dns_adbentry_t *next_entry;
852
853	for (bucket = 0; bucket < NBUCKETS; bucket++) {
854		LOCK(&adb->entrylocks[bucket]);
855		adb->entry_sd[bucket] = ISC_TRUE;
856
857		entry = ISC_LIST_HEAD(adb->entries[bucket]);
858		if (entry == NULL) {
859			/*
860			 * This bucket has no entries.  We must decrement the
861			 * irefcnt ourselves, since it will not be
862			 * automatically triggered by an entry being unlinked.
863			 */
864			result = dec_adb_irefcnt(adb);
865		} else {
866			/*
867			 * Run through the list.  Cleanup any entries not
868			 * associated with names, and which are not in use.
869			 */
870			while (entry != NULL) {
871				next_entry = ISC_LIST_NEXT(entry, plink);
872				if (entry->refcnt == 0 &&
873				    entry->expires != 0) {
874					result = unlink_entry(adb, entry);
875					free_adbentry(adb, &entry);
876					if (result)
877						result = dec_adb_irefcnt(adb);
878				}
879				entry = next_entry;
880			}
881		}
882
883		UNLOCK(&adb->entrylocks[bucket]);
884	}
885	return (result);
886}
887
888/*
889 * Name bucket must be locked
890 */
891static void
892cancel_fetches_at_name(dns_adbname_t *name) {
893	if (NAME_FETCH_A(name))
894	    dns_resolver_cancelfetch(name->fetch_a->fetch);
895
896	if (NAME_FETCH_AAAA(name))
897	    dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
898}
899
900/*
901 * Assumes the name bucket is locked.
902 */
903static isc_boolean_t
904clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
905	dns_adbentry_t *entry;
906	dns_adbnamehook_t *namehook;
907	int addr_bucket;
908	isc_boolean_t result = ISC_FALSE;
909
910	addr_bucket = DNS_ADB_INVALIDBUCKET;
911	namehook = ISC_LIST_HEAD(*namehooks);
912	while (namehook != NULL) {
913		INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
914
915		/*
916		 * Clean up the entry if needed.
917		 */
918		entry = namehook->entry;
919		if (entry != NULL) {
920			INSIST(DNS_ADBENTRY_VALID(entry));
921
922			if (addr_bucket != entry->lock_bucket) {
923				if (addr_bucket != DNS_ADB_INVALIDBUCKET)
924					UNLOCK(&adb->entrylocks[addr_bucket]);
925				addr_bucket = entry->lock_bucket;
926				LOCK(&adb->entrylocks[addr_bucket]);
927			}
928
929			result = dec_entry_refcnt(adb, entry, ISC_FALSE);
930		}
931
932		/*
933		 * Free the namehook
934		 */
935		namehook->entry = NULL;
936		ISC_LIST_UNLINK(*namehooks, namehook, plink);
937		free_adbnamehook(adb, &namehook);
938
939		namehook = ISC_LIST_HEAD(*namehooks);
940	}
941
942	if (addr_bucket != DNS_ADB_INVALIDBUCKET)
943		UNLOCK(&adb->entrylocks[addr_bucket]);
944	return (result);
945}
946
947static void
948clean_target(dns_adb_t *adb, dns_name_t *target) {
949	if (dns_name_countlabels(target) > 0) {
950		dns_name_free(target, adb->mctx);
951		dns_name_init(target, NULL);
952	}
953}
954
955static isc_result_t
956set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
957	   dns_rdataset_t *rdataset, dns_name_t *target)
958{
959	isc_result_t result;
960	dns_namereln_t namereln;
961	unsigned int nlabels;
962	int order;
963	dns_rdata_t rdata = DNS_RDATA_INIT;
964	dns_fixedname_t fixed1, fixed2;
965	dns_name_t *prefix, *new_target;
966
967	REQUIRE(dns_name_countlabels(target) == 0);
968
969	if (rdataset->type == dns_rdatatype_cname) {
970		dns_rdata_cname_t cname;
971
972		/*
973		 * Copy the CNAME's target into the target name.
974		 */
975		result = dns_rdataset_first(rdataset);
976		if (result != ISC_R_SUCCESS)
977			return (result);
978		dns_rdataset_current(rdataset, &rdata);
979		result = dns_rdata_tostruct(&rdata, &cname, NULL);
980		if (result != ISC_R_SUCCESS)
981			return (result);
982		result = dns_name_dup(&cname.cname, adb->mctx, target);
983		dns_rdata_freestruct(&cname);
984		if (result != ISC_R_SUCCESS)
985			return (result);
986	} else {
987		dns_rdata_dname_t dname;
988
989		INSIST(rdataset->type == dns_rdatatype_dname);
990		namereln = dns_name_fullcompare(name, fname, &order, &nlabels);
991		INSIST(namereln == dns_namereln_subdomain);
992		/*
993		 * Get the target name of the DNAME.
994		 */
995		result = dns_rdataset_first(rdataset);
996		if (result != ISC_R_SUCCESS)
997			return (result);
998		dns_rdataset_current(rdataset, &rdata);
999		result = dns_rdata_tostruct(&rdata, &dname, NULL);
1000		if (result != ISC_R_SUCCESS)
1001			return (result);
1002		/*
1003		 * Construct the new target name.
1004		 */
1005		dns_fixedname_init(&fixed1);
1006		prefix = dns_fixedname_name(&fixed1);
1007		dns_fixedname_init(&fixed2);
1008		new_target = dns_fixedname_name(&fixed2);
1009		dns_name_split(name, nlabels, prefix, NULL);
1010		result = dns_name_concatenate(prefix, &dname.dname, new_target,
1011					      NULL);
1012		dns_rdata_freestruct(&dname);
1013		if (result != ISC_R_SUCCESS)
1014			return (result);
1015		result = dns_name_dup(new_target, adb->mctx, target);
1016		if (result != ISC_R_SUCCESS)
1017			return (result);
1018	}
1019
1020	return (ISC_R_SUCCESS);
1021}
1022
1023/*
1024 * Assumes nothing is locked, since this is called by the client.
1025 */
1026static void
1027event_free(isc_event_t *event) {
1028	dns_adbfind_t *find;
1029
1030	INSIST(event != NULL);
1031	find = event->ev_destroy_arg;
1032	INSIST(DNS_ADBFIND_VALID(find));
1033
1034	LOCK(&find->lock);
1035	find->flags |= FIND_EVENT_FREED;
1036	event->ev_destroy_arg = NULL;
1037	UNLOCK(&find->lock);
1038}
1039
1040/*
1041 * Assumes the name bucket is locked.
1042 */
1043static void
1044clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
1045		    unsigned int addrs)
1046{
1047	isc_event_t *ev;
1048	isc_task_t *task;
1049	dns_adbfind_t *find;
1050	dns_adbfind_t *next_find;
1051	isc_boolean_t process;
1052	unsigned int wanted, notify;
1053
1054	DP(ENTER_LEVEL,
1055	   "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
1056	   name, evtype, addrs);
1057
1058	find = ISC_LIST_HEAD(name->finds);
1059	while (find != NULL) {
1060		LOCK(&find->lock);
1061		next_find = ISC_LIST_NEXT(find, plink);
1062
1063		process = ISC_FALSE;
1064		wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1065		notify = wanted & addrs;
1066
1067		switch (evtype) {
1068		case DNS_EVENT_ADBMOREADDRESSES:
1069			DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES");
1070			if ((notify) != 0) {
1071				find->flags &= ~addrs;
1072				process = ISC_TRUE;
1073			}
1074			break;
1075		case DNS_EVENT_ADBNOMOREADDRESSES:
1076			DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES");
1077			find->flags &= ~addrs;
1078			wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1079			if (wanted == 0)
1080				process = ISC_TRUE;
1081			break;
1082		default:
1083			find->flags &= ~addrs;
1084			process = ISC_TRUE;
1085		}
1086
1087		if (process) {
1088			DP(DEF_LEVEL, "cfan: processing find %p", find);
1089			/*
1090			 * Unlink the find from the name, letting the caller
1091			 * call dns_adb_destroyfind() on it to clean it up
1092			 * later.
1093			 */
1094			ISC_LIST_UNLINK(name->finds, find, plink);
1095			find->adbname = NULL;
1096			find->name_bucket = DNS_ADB_INVALIDBUCKET;
1097
1098			INSIST(!FIND_EVENTSENT(find));
1099
1100			ev = &find->event;
1101			task = ev->ev_sender;
1102			ev->ev_sender = find;
1103			find->result_v4 = find_err_map[name->fetch_err];
1104			find->result_v6 = find_err_map[name->fetch6_err];
1105			ev->ev_type = evtype;
1106			ev->ev_destroy = event_free;
1107			ev->ev_destroy_arg = find;
1108
1109			DP(DEF_LEVEL,
1110			   "sending event %p to task %p for find %p",
1111			   ev, task, find);
1112
1113			isc_task_sendanddetach(&task, (isc_event_t **)&ev);
1114		} else {
1115			DP(DEF_LEVEL, "cfan: skipping find %p", find);
1116		}
1117
1118		UNLOCK(&find->lock);
1119		find = next_find;
1120	}
1121
1122	DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
1123}
1124
1125static inline void
1126check_exit(dns_adb_t *adb) {
1127	isc_event_t *event;
1128	/*
1129	 * The caller must be holding the adb lock.
1130	 */
1131	if (adb->shutting_down) {
1132		/*
1133		 * If there aren't any external references either, we're
1134		 * done.  Send the control event to initiate shutdown.
1135		 */
1136		INSIST(!adb->cevent_sent);	/* Sanity check. */
1137		event = &adb->cevent;
1138		isc_task_send(adb->task, &event);
1139		adb->cevent_sent = ISC_TRUE;
1140	}
1141}
1142
1143static inline isc_boolean_t
1144dec_adb_irefcnt(dns_adb_t *adb) {
1145	isc_event_t *event;
1146	isc_task_t *etask;
1147	isc_boolean_t result = ISC_FALSE;
1148
1149	LOCK(&adb->reflock);
1150
1151	INSIST(adb->irefcnt > 0);
1152	adb->irefcnt--;
1153
1154	if (adb->irefcnt == 0) {
1155		event = ISC_LIST_HEAD(adb->whenshutdown);
1156		while (event != NULL) {
1157			ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
1158			etask = event->ev_sender;
1159			event->ev_sender = adb;
1160			isc_task_sendanddetach(&etask, &event);
1161			event = ISC_LIST_HEAD(adb->whenshutdown);
1162		}
1163	}
1164
1165	if (adb->irefcnt == 0 && adb->erefcnt == 0)
1166		result = ISC_TRUE;
1167	UNLOCK(&adb->reflock);
1168	return (result);
1169}
1170
1171static inline void
1172inc_adb_irefcnt(dns_adb_t *adb) {
1173	LOCK(&adb->reflock);
1174	adb->irefcnt++;
1175	UNLOCK(&adb->reflock);
1176}
1177
1178static inline void
1179inc_adb_erefcnt(dns_adb_t *adb) {
1180	LOCK(&adb->reflock);
1181	adb->erefcnt++;
1182	UNLOCK(&adb->reflock);
1183}
1184
1185static inline void
1186inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
1187	int bucket;
1188
1189	bucket = entry->lock_bucket;
1190
1191	if (lock)
1192		LOCK(&adb->entrylocks[bucket]);
1193
1194	entry->refcnt++;
1195
1196	if (lock)
1197		UNLOCK(&adb->entrylocks[bucket]);
1198}
1199
1200static inline isc_boolean_t
1201dec_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
1202	int bucket;
1203	isc_boolean_t destroy_entry;
1204	isc_boolean_t result = ISC_FALSE;
1205
1206	bucket = entry->lock_bucket;
1207
1208	if (lock)
1209		LOCK(&adb->entrylocks[bucket]);
1210
1211	INSIST(entry->refcnt > 0);
1212	entry->refcnt--;
1213
1214	destroy_entry = ISC_FALSE;
1215	if (entry->refcnt == 0 &&
1216	    (adb->entry_sd[bucket] || entry->expires == 0)) {
1217		destroy_entry = ISC_TRUE;
1218		result = unlink_entry(adb, entry);
1219	}
1220
1221	if (lock)
1222		UNLOCK(&adb->entrylocks[bucket]);
1223
1224	if (!destroy_entry)
1225		return (result);
1226
1227	entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1228
1229	free_adbentry(adb, &entry);
1230	if (result)
1231		result =dec_adb_irefcnt(adb);
1232
1233	return (result);
1234}
1235
1236static inline dns_adbname_t *
1237new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
1238	dns_adbname_t *name;
1239
1240	name = isc_mempool_get(adb->nmp);
1241	if (name == NULL)
1242		return (NULL);
1243
1244	dns_name_init(&name->name, NULL);
1245	if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
1246		isc_mempool_put(adb->nmp, name);
1247		return (NULL);
1248	}
1249	dns_name_init(&name->target, NULL);
1250	name->magic = DNS_ADBNAME_MAGIC;
1251	name->adb = adb;
1252	name->partial_result = 0;
1253	name->flags = 0;
1254	name->expire_v4 = INT_MAX;
1255	name->expire_v6 = INT_MAX;
1256	name->expire_target = INT_MAX;
1257	name->chains = 0;
1258	name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1259	ISC_LIST_INIT(name->v4);
1260	ISC_LIST_INIT(name->v6);
1261	name->fetch_a = NULL;
1262	name->fetch_aaaa = NULL;
1263	name->fetch_err = FIND_ERR_UNEXPECTED;
1264	name->fetch6_err = FIND_ERR_UNEXPECTED;
1265	ISC_LIST_INIT(name->finds);
1266	ISC_LINK_INIT(name, plink);
1267
1268	return (name);
1269}
1270
1271static inline void
1272free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
1273	dns_adbname_t *n;
1274
1275	INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
1276	n = *name;
1277	*name = NULL;
1278
1279	INSIST(!NAME_HAS_V4(n));
1280	INSIST(!NAME_HAS_V6(n));
1281	INSIST(!NAME_FETCH(n));
1282	INSIST(ISC_LIST_EMPTY(n->finds));
1283	INSIST(!ISC_LINK_LINKED(n, plink));
1284	INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
1285	INSIST(n->adb == adb);
1286
1287	n->magic = 0;
1288	dns_name_free(&n->name, adb->mctx);
1289
1290	isc_mempool_put(adb->nmp, n);
1291}
1292
1293static inline dns_adbnamehook_t *
1294new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) {
1295	dns_adbnamehook_t *nh;
1296
1297	nh = isc_mempool_get(adb->nhmp);
1298	if (nh == NULL)
1299		return (NULL);
1300
1301	nh->magic = DNS_ADBNAMEHOOK_MAGIC;
1302	nh->entry = entry;
1303	ISC_LINK_INIT(nh, plink);
1304
1305	return (nh);
1306}
1307
1308static inline void
1309free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) {
1310	dns_adbnamehook_t *nh;
1311
1312	INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
1313	nh = *namehook;
1314	*namehook = NULL;
1315
1316	INSIST(nh->entry == NULL);
1317	INSIST(!ISC_LINK_LINKED(nh, plink));
1318
1319	nh->magic = 0;
1320	isc_mempool_put(adb->nhmp, nh);
1321}
1322
1323static inline dns_adbzoneinfo_t *
1324new_adbzoneinfo(dns_adb_t *adb, dns_name_t *zone) {
1325	dns_adbzoneinfo_t *zi;
1326
1327	zi = isc_mempool_get(adb->zimp);
1328	if (zi == NULL)
1329		return (NULL);
1330
1331	dns_name_init(&zi->zone, NULL);
1332	if (dns_name_dup(zone, adb->mctx, &zi->zone) != ISC_R_SUCCESS) {
1333		isc_mempool_put(adb->zimp, zi);
1334		return (NULL);
1335	}
1336
1337	zi->magic = DNS_ADBZONEINFO_MAGIC;
1338	zi->lame_timer = 0;
1339	ISC_LINK_INIT(zi, plink);
1340
1341	return (zi);
1342}
1343
1344static inline void
1345free_adbzoneinfo(dns_adb_t *adb, dns_adbzoneinfo_t **zoneinfo) {
1346	dns_adbzoneinfo_t *zi;
1347
1348	INSIST(zoneinfo != NULL && DNS_ADBZONEINFO_VALID(*zoneinfo));
1349	zi = *zoneinfo;
1350	*zoneinfo = NULL;
1351
1352	INSIST(!ISC_LINK_LINKED(zi, plink));
1353
1354	dns_name_free(&zi->zone, adb->mctx);
1355
1356	zi->magic = 0;
1357
1358	isc_mempool_put(adb->zimp, zi);
1359}
1360
1361static inline dns_adbentry_t *
1362new_adbentry(dns_adb_t *adb) {
1363	dns_adbentry_t *e;
1364	isc_uint32_t r;
1365
1366	e = isc_mempool_get(adb->emp);
1367	if (e == NULL)
1368		return (NULL);
1369
1370	e->magic = DNS_ADBENTRY_MAGIC;
1371	e->lock_bucket = DNS_ADB_INVALIDBUCKET;
1372	e->refcnt = 0;
1373	e->flags = 0;
1374	isc_random_get(&r);
1375	e->srtt = (r & 0x1f) + 1;
1376	e->expires = 0;
1377	ISC_LIST_INIT(e->zoneinfo);
1378	ISC_LINK_INIT(e, plink);
1379
1380	return (e);
1381}
1382
1383static inline void
1384free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
1385	dns_adbentry_t *e;
1386	dns_adbzoneinfo_t *zi;
1387
1388	INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
1389	e = *entry;
1390	*entry = NULL;
1391
1392	INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
1393	INSIST(e->refcnt == 0);
1394	INSIST(!ISC_LINK_LINKED(e, plink));
1395
1396	e->magic = 0;
1397
1398	zi = ISC_LIST_HEAD(e->zoneinfo);
1399	while (zi != NULL) {
1400		ISC_LIST_UNLINK(e->zoneinfo, zi, plink);
1401		free_adbzoneinfo(adb, &zi);
1402		zi = ISC_LIST_HEAD(e->zoneinfo);
1403	}
1404
1405	isc_mempool_put(adb->emp, e);
1406}
1407
1408static inline dns_adbfind_t *
1409new_adbfind(dns_adb_t *adb) {
1410	dns_adbfind_t *h;
1411	isc_result_t result;
1412
1413	h = isc_mempool_get(adb->ahmp);
1414	if (h == NULL)
1415		return (NULL);
1416
1417	/*
1418	 * Public members.
1419	 */
1420	h->magic = 0;
1421	h->adb = adb;
1422	h->partial_result = 0;
1423	h->options = 0;
1424	h->flags = 0;
1425	h->result_v4 = ISC_R_UNEXPECTED;
1426	h->result_v6 = ISC_R_UNEXPECTED;
1427	ISC_LINK_INIT(h, publink);
1428	ISC_LINK_INIT(h, plink);
1429	ISC_LIST_INIT(h->list);
1430	h->adbname = NULL;
1431	h->name_bucket = DNS_ADB_INVALIDBUCKET;
1432
1433	/*
1434	 * private members
1435	 */
1436	result = isc_mutex_init(&h->lock);
1437	if (result != ISC_R_SUCCESS) {
1438		UNEXPECTED_ERROR(__FILE__, __LINE__,
1439				 "isc_mutex_init failed in new_adbfind()");
1440		isc_mempool_put(adb->ahmp, h);
1441		return (NULL);
1442	}
1443
1444	ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
1445		       NULL, NULL, h);
1446
1447	inc_adb_irefcnt(adb);
1448	h->magic = DNS_ADBFIND_MAGIC;
1449	return (h);
1450}
1451
1452static inline dns_adbfetch_t *
1453new_adbfetch(dns_adb_t *adb) {
1454	dns_adbfetch_t *f;
1455
1456	f = isc_mempool_get(adb->afmp);
1457	if (f == NULL)
1458		return (NULL);
1459
1460	f->magic = 0;
1461	f->namehook = NULL;
1462	f->entry = NULL;
1463	f->fetch = NULL;
1464
1465	f->namehook = new_adbnamehook(adb, NULL);
1466	if (f->namehook == NULL)
1467		goto err;
1468
1469	f->entry = new_adbentry(adb);
1470	if (f->entry == NULL)
1471		goto err;
1472
1473	dns_rdataset_init(&f->rdataset);
1474
1475	f->magic = DNS_ADBFETCH_MAGIC;
1476
1477	return (f);
1478
1479 err:
1480	if (f->namehook != NULL)
1481		free_adbnamehook(adb, &f->namehook);
1482	if (f->entry != NULL)
1483		free_adbentry(adb, &f->entry);
1484	isc_mempool_put(adb->afmp, f);
1485	return (NULL);
1486}
1487
1488static inline void
1489free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) {
1490	dns_adbfetch_t *f;
1491
1492	INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
1493	f = *fetch;
1494	*fetch = NULL;
1495
1496	f->magic = 0;
1497
1498	if (f->namehook != NULL)
1499		free_adbnamehook(adb, &f->namehook);
1500	if (f->entry != NULL)
1501		free_adbentry(adb, &f->entry);
1502
1503	if (dns_rdataset_isassociated(&f->rdataset))
1504		dns_rdataset_disassociate(&f->rdataset);
1505
1506	isc_mempool_put(adb->afmp, f);
1507}
1508
1509static inline isc_boolean_t
1510free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
1511	dns_adbfind_t *find;
1512
1513	INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
1514	find = *findp;
1515	*findp = NULL;
1516
1517	INSIST(!FIND_HAS_ADDRS(find));
1518	INSIST(!ISC_LINK_LINKED(find, publink));
1519	INSIST(!ISC_LINK_LINKED(find, plink));
1520	INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
1521	INSIST(find->adbname == NULL);
1522
1523	find->magic = 0;
1524
1525	DESTROYLOCK(&find->lock);
1526	isc_mempool_put(adb->ahmp, find);
1527	return (dec_adb_irefcnt(adb));
1528}
1529
1530/*
1531 * Copy bits from the entry into the newly allocated addrinfo.  The entry
1532 * must be locked, and the reference count must be bumped up by one
1533 * if this function returns a valid pointer.
1534 */
1535static inline dns_adbaddrinfo_t *
1536new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
1537	dns_adbaddrinfo_t *ai;
1538
1539	ai = isc_mempool_get(adb->aimp);
1540	if (ai == NULL)
1541		return (NULL);
1542
1543	ai->magic = DNS_ADBADDRINFO_MAGIC;
1544	ai->sockaddr = entry->sockaddr;
1545	isc_sockaddr_setport(&ai->sockaddr, port);
1546	ai->srtt = entry->srtt;
1547	ai->flags = entry->flags;
1548	ai->entry = entry;
1549	ISC_LINK_INIT(ai, publink);
1550
1551	return (ai);
1552}
1553
1554static inline void
1555free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
1556	dns_adbaddrinfo_t *ai;
1557
1558	INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
1559	ai = *ainfo;
1560	*ainfo = NULL;
1561
1562	INSIST(ai->entry == NULL);
1563	INSIST(!ISC_LINK_LINKED(ai, publink));
1564
1565	ai->magic = 0;
1566
1567	isc_mempool_put(adb->aimp, ai);
1568}
1569
1570/*
1571 * Search for the name.  NOTE:  The bucket is kept locked on both
1572 * success and failure, so it must always be unlocked by the caller!
1573 *
1574 * On the first call to this function, *bucketp must be set to
1575 * DNS_ADB_INVALIDBUCKET.
1576 */
1577static inline dns_adbname_t *
1578find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
1579		   unsigned int options, int *bucketp)
1580{
1581	dns_adbname_t *adbname;
1582	int bucket;
1583
1584	bucket = dns_name_fullhash(name, ISC_FALSE) % NBUCKETS;
1585
1586	if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1587		LOCK(&adb->namelocks[bucket]);
1588		*bucketp = bucket;
1589	} else if (*bucketp != bucket) {
1590		UNLOCK(&adb->namelocks[*bucketp]);
1591		LOCK(&adb->namelocks[bucket]);
1592		*bucketp = bucket;
1593	}
1594
1595	adbname = ISC_LIST_HEAD(adb->names[bucket]);
1596	while (adbname != NULL) {
1597		if (!NAME_DEAD(adbname)) {
1598			if (dns_name_equal(name, &adbname->name)
1599			    && GLUEHINT_OK(adbname, options)
1600			    && STARTATZONE_MATCHES(adbname, options))
1601				return (adbname);
1602		}
1603		adbname = ISC_LIST_NEXT(adbname, plink);
1604	}
1605
1606	return (NULL);
1607}
1608
1609/*
1610 * Search for the address.  NOTE:  The bucket is kept locked on both
1611 * success and failure, so it must always be unlocked by the caller.
1612 *
1613 * On the first call to this function, *bucketp must be set to
1614 * DNS_ADB_INVALIDBUCKET.  This will cause a lock to occur.  On
1615 * later calls (within the same "lock path") it can be left alone, so
1616 * if this function is called multiple times locking is only done if
1617 * the bucket changes.
1618 */
1619static inline dns_adbentry_t *
1620find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp) {
1621	dns_adbentry_t *entry;
1622	int bucket;
1623
1624	bucket = isc_sockaddr_hash(addr, ISC_TRUE) % NBUCKETS;
1625
1626	if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1627		LOCK(&adb->entrylocks[bucket]);
1628		*bucketp = bucket;
1629	} else if (*bucketp != bucket) {
1630		UNLOCK(&adb->entrylocks[*bucketp]);
1631		LOCK(&adb->entrylocks[bucket]);
1632		*bucketp = bucket;
1633	}
1634
1635	entry = ISC_LIST_HEAD(adb->entries[bucket]);
1636	while (entry != NULL) {
1637		if (isc_sockaddr_equal(addr, &entry->sockaddr))
1638			return (entry);
1639		entry = ISC_LIST_NEXT(entry, plink);
1640	}
1641
1642	return (NULL);
1643}
1644
1645/*
1646 * Entry bucket MUST be locked!
1647 */
1648static isc_boolean_t
1649entry_is_bad_for_zone(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *zone,
1650		      isc_stdtime_t now)
1651{
1652	dns_adbzoneinfo_t *zi, *next_zi;
1653	isc_boolean_t is_bad;
1654
1655	is_bad = ISC_FALSE;
1656
1657	zi = ISC_LIST_HEAD(entry->zoneinfo);
1658	if (zi == NULL)
1659		return (ISC_FALSE);
1660	while (zi != NULL) {
1661		next_zi = ISC_LIST_NEXT(zi, plink);
1662
1663		/*
1664		 * Has the entry expired?
1665		 */
1666		if (zi->lame_timer < now) {
1667			ISC_LIST_UNLINK(entry->zoneinfo, zi, plink);
1668			free_adbzoneinfo(adb, &zi);
1669		}
1670
1671		/*
1672		 * Order tests from least to most expensive.
1673		 */
1674		if (zi != NULL && !is_bad) {
1675			if (dns_name_equal(zone, &zi->zone))
1676				is_bad = ISC_TRUE;
1677		}
1678
1679		zi = next_zi;
1680	}
1681
1682	return (is_bad);
1683}
1684
1685static void
1686copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *zone,
1687		    dns_adbname_t *name, isc_stdtime_t now)
1688{
1689	dns_adbnamehook_t *namehook;
1690	dns_adbaddrinfo_t *addrinfo;
1691	dns_adbentry_t *entry;
1692	int bucket;
1693
1694	bucket = DNS_ADB_INVALIDBUCKET;
1695
1696	if (find->options & DNS_ADBFIND_INET) {
1697		namehook = ISC_LIST_HEAD(name->v4);
1698		while (namehook != NULL) {
1699			entry = namehook->entry;
1700			bucket = entry->lock_bucket;
1701			LOCK(&adb->entrylocks[bucket]);
1702
1703			if (!FIND_RETURNLAME(find)
1704			    && entry_is_bad_for_zone(adb, entry, zone, now)) {
1705				find->options |= DNS_ADBFIND_LAMEPRUNED;
1706				goto nextv4;
1707			}
1708			addrinfo = new_adbaddrinfo(adb, entry, find->port);
1709			if (addrinfo == NULL) {
1710				find->partial_result |= DNS_ADBFIND_INET;
1711				goto out;
1712			}
1713			/*
1714			 * Found a valid entry.  Add it to the find's list.
1715			 */
1716			inc_entry_refcnt(adb, entry, ISC_FALSE);
1717			ISC_LIST_APPEND(find->list, addrinfo, publink);
1718			addrinfo = NULL;
1719		nextv4:
1720			UNLOCK(&adb->entrylocks[bucket]);
1721			bucket = DNS_ADB_INVALIDBUCKET;
1722			namehook = ISC_LIST_NEXT(namehook, plink);
1723		}
1724	}
1725
1726	if (find->options & DNS_ADBFIND_INET6) {
1727		namehook = ISC_LIST_HEAD(name->v6);
1728		while (namehook != NULL) {
1729			entry = namehook->entry;
1730			bucket = entry->lock_bucket;
1731			LOCK(&adb->entrylocks[bucket]);
1732
1733			if (entry_is_bad_for_zone(adb, entry, zone, now))
1734				goto nextv6;
1735			addrinfo = new_adbaddrinfo(adb, entry, find->port);
1736			if (addrinfo == NULL) {
1737				find->partial_result |= DNS_ADBFIND_INET6;
1738				goto out;
1739			}
1740			/*
1741			 * Found a valid entry.  Add it to the find's list.
1742			 */
1743			inc_entry_refcnt(adb, entry, ISC_FALSE);
1744			ISC_LIST_APPEND(find->list, addrinfo, publink);
1745			addrinfo = NULL;
1746		nextv6:
1747			UNLOCK(&adb->entrylocks[bucket]);
1748			bucket = DNS_ADB_INVALIDBUCKET;
1749			namehook = ISC_LIST_NEXT(namehook, plink);
1750		}
1751	}
1752
1753 out:
1754	if (bucket != DNS_ADB_INVALIDBUCKET)
1755		UNLOCK(&adb->entrylocks[bucket]);
1756}
1757
1758static void
1759shutdown_task(isc_task_t *task, isc_event_t *ev) {
1760	dns_adb_t *adb;
1761
1762	UNUSED(task);
1763
1764	adb = ev->ev_arg;
1765	INSIST(DNS_ADB_VALID(adb));
1766
1767	/*
1768	 * Kill the timer, and then the ADB itself.  Note that this implies
1769	 * that this task was the one scheduled to get timer events.  If
1770	 * this is not true (and it is unfortunate there is no way to INSIST()
1771	 * this) badness will occur.
1772	 */
1773	LOCK(&adb->lock);
1774	isc_timer_detach(&adb->timer);
1775	UNLOCK(&adb->lock);
1776	isc_event_free(&ev);
1777	destroy(adb);
1778}
1779
1780/*
1781 * Name bucket must be locked; adb may be locked; no other locks held.
1782 */
1783static isc_boolean_t
1784check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
1785	dns_adbname_t *name;
1786	isc_result_t result = ISC_FALSE;
1787
1788	INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
1789	name = *namep;
1790
1791	if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
1792		return (result);
1793	if (NAME_FETCH(name))
1794		return (result);
1795	if (!EXPIRE_OK(name->expire_v4, now))
1796		return (result);
1797	if (!EXPIRE_OK(name->expire_v6, now))
1798		return (result);
1799	if (!EXPIRE_OK(name->expire_target, now))
1800		return (result);
1801
1802	/*
1803	 * The name is empty.  Delete it.
1804	 */
1805	result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
1806	*namep = NULL;
1807
1808	/*
1809	 * Our caller, or one of its callers, will be calling check_exit() at
1810	 * some point, so we don't need to do it here.
1811	 */
1812	return (result);
1813}
1814
1815/*
1816 * Entry bucket must be locked; adb may be locked; no other locks held.
1817 */
1818static isc_boolean_t
1819check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
1820{
1821	dns_adbentry_t *entry;
1822	isc_boolean_t expire;
1823	isc_boolean_t result = ISC_FALSE;
1824
1825	INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
1826	entry = *entryp;
1827
1828	if (entry->refcnt != 0)
1829		return (result);
1830
1831	if (adb->overmem) {
1832		isc_uint32_t val;
1833
1834		isc_random_get(&val);
1835
1836		expire = ISC_TF((val % 4) == 0);
1837	} else
1838		expire = ISC_FALSE;
1839
1840	if (entry->expires == 0 || (! expire && entry->expires > now))
1841		return (result);
1842
1843	/*
1844	 * The entry is not in use.  Delete it.
1845	 */
1846	DP(DEF_LEVEL, "killing entry %p", entry);
1847	INSIST(ISC_LINK_LINKED(entry, plink));
1848	result = unlink_entry(adb, entry);
1849	free_adbentry(adb, &entry);
1850	if (result)
1851		dec_adb_irefcnt(adb);
1852	*entryp = NULL;
1853	return (result);
1854}
1855
1856/*
1857 * ADB must be locked, and no other locks held.
1858 */
1859static isc_boolean_t
1860cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
1861	dns_adbname_t *name;
1862	dns_adbname_t *next_name;
1863	isc_result_t result = ISC_FALSE;
1864
1865	DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
1866
1867	LOCK(&adb->namelocks[bucket]);
1868	if (adb->name_sd[bucket]) {
1869		UNLOCK(&adb->namelocks[bucket]);
1870		return (result);
1871	}
1872
1873	name = ISC_LIST_HEAD(adb->names[bucket]);
1874	while (name != NULL) {
1875		next_name = ISC_LIST_NEXT(name, plink);
1876		INSIST(result == ISC_FALSE);
1877		result = check_expire_namehooks(name, now, adb->overmem);
1878		if (!result)
1879			result = check_expire_name(&name, now);
1880		name = next_name;
1881	}
1882	UNLOCK(&adb->namelocks[bucket]);
1883	return (result);
1884}
1885
1886/*
1887 * ADB must be locked, and no other locks held.
1888 */
1889static isc_boolean_t
1890cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
1891	dns_adbentry_t *entry, *next_entry;
1892	isc_boolean_t result = ISC_FALSE;
1893
1894	DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
1895
1896	LOCK(&adb->entrylocks[bucket]);
1897	entry = ISC_LIST_HEAD(adb->entries[bucket]);
1898	while (entry != NULL) {
1899		next_entry = ISC_LIST_NEXT(entry, plink);
1900		INSIST(result == ISC_FALSE);
1901		result = check_expire_entry(adb, &entry, now);
1902		entry = next_entry;
1903	}
1904	UNLOCK(&adb->entrylocks[bucket]);
1905	return (result);
1906}
1907
1908static void
1909timer_cleanup(isc_task_t *task, isc_event_t *ev) {
1910	dns_adb_t *adb;
1911	isc_stdtime_t now;
1912	unsigned int i;
1913	isc_interval_t interval;
1914
1915	UNUSED(task);
1916
1917	adb = ev->ev_arg;
1918	INSIST(DNS_ADB_VALID(adb));
1919
1920	LOCK(&adb->lock);
1921
1922	isc_stdtime_get(&now);
1923
1924	for (i = 0; i < CLEAN_BUCKETS; i++) {
1925		/*
1926		 * Call our cleanup routines.
1927		 */
1928		RUNTIME_CHECK(cleanup_names(adb, adb->next_cleanbucket, now) ==
1929			      ISC_FALSE);
1930		RUNTIME_CHECK(cleanup_entries(adb, adb->next_cleanbucket, now)
1931			      == ISC_FALSE);
1932
1933		/*
1934		 * Set the next bucket to be cleaned.
1935		 */
1936		adb->next_cleanbucket++;
1937		if (adb->next_cleanbucket >= NBUCKETS) {
1938			adb->next_cleanbucket = 0;
1939#ifdef DUMP_ADB_AFTER_CLEANING
1940			dump_adb(adb, stdout, ISC_TRUE);
1941#endif
1942		}
1943	}
1944
1945	/*
1946	 * Reset the timer.
1947	 * XXXDCL isc_timer_reset might return ISC_R_UNEXPECTED or
1948	 * ISC_R_NOMEMORY, but it isn't clear what could be done here
1949	 * if either one of those things happened.
1950	 */
1951	interval = adb->tick_interval;
1952	if (adb->overmem)
1953		isc_interval_set(&interval, 0, 1);
1954	(void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
1955			      &interval, ISC_FALSE);
1956
1957	UNLOCK(&adb->lock);
1958
1959	isc_event_free(&ev);
1960}
1961
1962static void
1963destroy(dns_adb_t *adb) {
1964	adb->magic = 0;
1965
1966	/*
1967	 * The timer is already dead, from the task's shutdown callback.
1968	 */
1969	isc_task_detach(&adb->task);
1970
1971	isc_mempool_destroy(&adb->nmp);
1972	isc_mempool_destroy(&adb->nhmp);
1973	isc_mempool_destroy(&adb->zimp);
1974	isc_mempool_destroy(&adb->emp);
1975	isc_mempool_destroy(&adb->ahmp);
1976	isc_mempool_destroy(&adb->aimp);
1977	isc_mempool_destroy(&adb->afmp);
1978
1979	DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
1980	DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS);
1981
1982	DESTROYLOCK(&adb->reflock);
1983	DESTROYLOCK(&adb->lock);
1984	DESTROYLOCK(&adb->mplock);
1985
1986	isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
1987}
1988
1989
1990/*
1991 * Public functions.
1992 */
1993
1994isc_result_t
1995dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
1996	       isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
1997{
1998	dns_adb_t *adb;
1999	isc_result_t result;
2000	int i;
2001
2002	REQUIRE(mem != NULL);
2003	REQUIRE(view != NULL);
2004	REQUIRE(timermgr != NULL);
2005	REQUIRE(taskmgr != NULL);
2006	REQUIRE(newadb != NULL && *newadb == NULL);
2007
2008	adb = isc_mem_get(mem, sizeof(dns_adb_t));
2009	if (adb == NULL)
2010		return (ISC_R_NOMEMORY);
2011
2012	/*
2013	 * Initialize things here that cannot fail, and especially things
2014	 * that must be NULL for the error return to work properly.
2015	 */
2016	adb->magic = 0;
2017	adb->erefcnt = 1;
2018	adb->irefcnt = 0;
2019	adb->nmp = NULL;
2020	adb->nhmp = NULL;
2021	adb->zimp = NULL;
2022	adb->emp = NULL;
2023	adb->ahmp = NULL;
2024	adb->aimp = NULL;
2025	adb->afmp = NULL;
2026	adb->task = NULL;
2027	adb->timer = NULL;
2028	adb->mctx = NULL;
2029	adb->view = view;
2030	adb->timermgr = timermgr;
2031	adb->taskmgr = taskmgr;
2032	adb->next_cleanbucket = 0;
2033	ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
2034		       DNS_EVENT_ADBCONTROL, shutdown_task, adb,
2035		       adb, NULL, NULL);
2036	adb->cevent_sent = ISC_FALSE;
2037	adb->shutting_down = ISC_FALSE;
2038	adb->overmem = ISC_FALSE;
2039	ISC_LIST_INIT(adb->whenshutdown);
2040
2041	isc_mem_attach(mem, &adb->mctx);
2042
2043	result = isc_mutex_init(&adb->lock);
2044	if (result != ISC_R_SUCCESS)
2045		goto fail0b;
2046
2047	result = isc_mutex_init(&adb->mplock);
2048	if (result != ISC_R_SUCCESS)
2049		goto fail0c;
2050
2051	result = isc_mutex_init(&adb->reflock);
2052	if (result != ISC_R_SUCCESS)
2053		goto fail0d;
2054
2055	/*
2056	 * Initialize the bucket locks for names and elements.
2057	 * May as well initialize the list heads, too.
2058	 */
2059	result = isc_mutexblock_init(adb->namelocks, NBUCKETS);
2060	if (result != ISC_R_SUCCESS)
2061		goto fail1;
2062	for (i = 0; i < NBUCKETS; i++) {
2063		ISC_LIST_INIT(adb->names[i]);
2064		adb->name_sd[i] = ISC_FALSE;
2065		adb->name_refcnt[i] = 0;
2066		adb->irefcnt++;
2067	}
2068	for (i = 0; i < NBUCKETS; i++) {
2069		ISC_LIST_INIT(adb->entries[i]);
2070		adb->entry_sd[i] = ISC_FALSE;
2071		adb->entry_refcnt[i] = 0;
2072		adb->irefcnt++;
2073	}
2074	result = isc_mutexblock_init(adb->entrylocks, NBUCKETS);
2075	if (result != ISC_R_SUCCESS)
2076		goto fail2;
2077
2078	/*
2079	 * Memory pools
2080	 */
2081#define MPINIT(t, p, n) do { \
2082	result = isc_mempool_create(mem, sizeof(t), &(p)); \
2083	if (result != ISC_R_SUCCESS) \
2084		goto fail3; \
2085	isc_mempool_setfreemax((p), FREE_ITEMS); \
2086	isc_mempool_setfillcount((p), FILL_COUNT); \
2087	isc_mempool_setname((p), n); \
2088	isc_mempool_associatelock((p), &adb->mplock); \
2089} while (0)
2090
2091	MPINIT(dns_adbname_t, adb->nmp, "adbname");
2092	MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
2093	MPINIT(dns_adbzoneinfo_t, adb->zimp, "adbzoneinfo");
2094	MPINIT(dns_adbentry_t, adb->emp, "adbentry");
2095	MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
2096	MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
2097	MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
2098
2099#undef MPINIT
2100
2101	/*
2102	 * Allocate a timer and a task for our periodic cleanup.
2103	 */
2104	result = isc_task_create(adb->taskmgr, 0, &adb->task);
2105	if (result != ISC_R_SUCCESS)
2106		goto fail3;
2107	isc_task_setname(adb->task, "ADB", adb);
2108	/*
2109	 * XXXMLG When this is changed to be a config file option,
2110	 */
2111	isc_interval_set(&adb->tick_interval, CLEAN_SECONDS, 0);
2112	result = isc_timer_create(adb->timermgr, isc_timertype_once,
2113				  NULL, &adb->tick_interval, adb->task,
2114				  timer_cleanup, adb, &adb->timer);
2115	if (result != ISC_R_SUCCESS)
2116		goto fail3;
2117
2118	DP(ISC_LOG_DEBUG(5), "cleaning interval for adb: "
2119	   "%u buckets every %u seconds, %u buckets in system, %u cl.interval",
2120	   CLEAN_BUCKETS, CLEAN_SECONDS, NBUCKETS, CLEAN_PERIOD);
2121
2122	/*
2123	 * Normal return.
2124	 */
2125	adb->magic = DNS_ADB_MAGIC;
2126	*newadb = adb;
2127	return (ISC_R_SUCCESS);
2128
2129 fail3:
2130	if (adb->task != NULL)
2131		isc_task_detach(&adb->task);
2132	if (adb->timer != NULL)
2133		isc_timer_detach(&adb->timer);
2134
2135	/* clean up entrylocks */
2136	DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
2137
2138 fail2: /* clean up namelocks */
2139	DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS);
2140
2141 fail1: /* clean up only allocated memory */
2142	if (adb->nmp != NULL)
2143		isc_mempool_destroy(&adb->nmp);
2144	if (adb->nhmp != NULL)
2145		isc_mempool_destroy(&adb->nhmp);
2146	if (adb->zimp != NULL)
2147		isc_mempool_destroy(&adb->zimp);
2148	if (adb->emp != NULL)
2149		isc_mempool_destroy(&adb->emp);
2150	if (adb->ahmp != NULL)
2151		isc_mempool_destroy(&adb->ahmp);
2152	if (adb->aimp != NULL)
2153		isc_mempool_destroy(&adb->aimp);
2154	if (adb->afmp != NULL)
2155		isc_mempool_destroy(&adb->afmp);
2156
2157	DESTROYLOCK(&adb->reflock);
2158 fail0d:
2159	DESTROYLOCK(&adb->mplock);
2160 fail0c:
2161	DESTROYLOCK(&adb->lock);
2162 fail0b:
2163	isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2164
2165	return (result);
2166}
2167
2168void
2169dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
2170
2171	REQUIRE(DNS_ADB_VALID(adb));
2172	REQUIRE(adbx != NULL && *adbx == NULL);
2173
2174	inc_adb_erefcnt(adb);
2175	*adbx = adb;
2176}
2177
2178void
2179dns_adb_detach(dns_adb_t **adbx) {
2180	dns_adb_t *adb;
2181	isc_boolean_t need_exit_check;
2182
2183	REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
2184
2185	adb = *adbx;
2186	*adbx = NULL;
2187
2188	INSIST(adb->erefcnt > 0);
2189
2190	LOCK(&adb->reflock);
2191	adb->erefcnt--;
2192	need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
2193	UNLOCK(&adb->reflock);
2194
2195	if (need_exit_check) {
2196		LOCK(&adb->lock);
2197		INSIST(adb->shutting_down);
2198		check_exit(adb);
2199		UNLOCK(&adb->lock);
2200	}
2201}
2202
2203void
2204dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
2205	isc_task_t *clone;
2206	isc_event_t *event;
2207	isc_boolean_t zeroirefcnt = ISC_FALSE;
2208
2209	/*
2210	 * Send '*eventp' to 'task' when 'adb' has shutdown.
2211	 */
2212
2213	REQUIRE(DNS_ADB_VALID(adb));
2214	REQUIRE(eventp != NULL);
2215
2216	event = *eventp;
2217	*eventp = NULL;
2218
2219	LOCK(&adb->lock);
2220
2221	LOCK(&adb->reflock);
2222	zeroirefcnt = ISC_TF(adb->irefcnt == 0);
2223
2224	if (adb->shutting_down && zeroirefcnt &&
2225	    isc_mempool_getallocated(adb->ahmp) == 0) {
2226		/*
2227		 * We're already shutdown.  Send the event.
2228		 */
2229		event->ev_sender = adb;
2230		isc_task_send(task, &event);
2231	} else {
2232		clone = NULL;
2233		isc_task_attach(task, &clone);
2234		event->ev_sender = clone;
2235		ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
2236	}
2237
2238	UNLOCK(&adb->reflock);
2239	UNLOCK(&adb->lock);
2240}
2241
2242void
2243dns_adb_shutdown(dns_adb_t *adb) {
2244	isc_boolean_t need_check_exit;
2245
2246	/*
2247	 * Shutdown 'adb'.
2248	 */
2249
2250	LOCK(&adb->lock);
2251
2252	if (!adb->shutting_down) {
2253		adb->shutting_down = ISC_TRUE;
2254		isc_mem_setwater(adb->mctx, water, adb, 0, 0);
2255		need_check_exit = shutdown_names(adb);
2256		if (!need_check_exit)
2257			need_check_exit = shutdown_entries(adb);
2258		if (need_check_exit)
2259			check_exit(adb);
2260	}
2261
2262	UNLOCK(&adb->lock);
2263}
2264
2265isc_result_t
2266dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
2267		   void *arg, dns_name_t *name, dns_name_t *zone,
2268		   unsigned int options, isc_stdtime_t now, dns_name_t *target,
2269		   in_port_t port, dns_adbfind_t **findp)
2270{
2271	dns_adbfind_t *find;
2272	dns_adbname_t *adbname;
2273	int bucket;
2274	isc_boolean_t want_event, start_at_zone, alias, have_address;
2275	isc_result_t result;
2276	unsigned int wanted_addresses;
2277	unsigned int wanted_fetches;
2278	unsigned int query_pending;
2279
2280	REQUIRE(DNS_ADB_VALID(adb));
2281	if (task != NULL) {
2282		REQUIRE(action != NULL);
2283	}
2284	REQUIRE(name != NULL);
2285	REQUIRE(zone != NULL);
2286	REQUIRE(findp != NULL && *findp == NULL);
2287	REQUIRE(target == NULL || dns_name_hasbuffer(target));
2288
2289	REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
2290
2291	result = ISC_R_UNEXPECTED;
2292	wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
2293	wanted_fetches = 0;
2294	query_pending = 0;
2295	want_event = ISC_FALSE;
2296	start_at_zone = ISC_FALSE;
2297	alias = ISC_FALSE;
2298
2299	if (now == 0)
2300		isc_stdtime_get(&now);
2301
2302	/*
2303	 * XXXMLG  Move this comment somewhere else!
2304	 *
2305	 * Look up the name in our internal database.
2306	 *
2307	 * Possibilities:  Note that these are not always exclusive.
2308	 *
2309	 *	No name found.  In this case, allocate a new name header and
2310	 *	an initial namehook or two.  If any of these allocations
2311	 *	fail, clean up and return ISC_R_NOMEMORY.
2312	 *
2313	 *	Name found, valid addresses present.  Allocate one addrinfo
2314	 *	structure for each found and append it to the linked list
2315	 *	of addresses for this header.
2316	 *
2317	 *	Name found, queries pending.  In this case, if a task was
2318	 *	passed in, allocate a job id, attach it to the name's job
2319	 *	list and remember to tell the caller that there will be
2320	 *	more info coming later.
2321	 */
2322
2323	find = new_adbfind(adb);
2324	if (find == NULL)
2325		return (ISC_R_NOMEMORY);
2326
2327	find->port = port;
2328
2329	/*
2330	 * Remember what types of addresses we are interested in.
2331	 */
2332	find->options = options;
2333	find->flags |= wanted_addresses;
2334	if (FIND_WANTEVENT(find)) {
2335		REQUIRE(task != NULL);
2336	}
2337
2338	/*
2339	 * Try to see if we know anything about this name at all.
2340	 */
2341	bucket = DNS_ADB_INVALIDBUCKET;
2342	adbname = find_name_and_lock(adb, name, find->options, &bucket);
2343	if (adb->name_sd[bucket]) {
2344		DP(DEF_LEVEL,
2345		   "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
2346		RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2347		result = ISC_R_SHUTTINGDOWN;
2348		goto out;
2349	}
2350
2351	/*
2352	 * Nothing found.  Allocate a new adbname structure for this name.
2353	 */
2354	if (adbname == NULL) {
2355		adbname = new_adbname(adb, name);
2356		if (adbname == NULL) {
2357			RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2358			result = ISC_R_NOMEMORY;
2359			goto out;
2360		}
2361		link_name(adb, bucket, adbname);
2362		if (FIND_HINTOK(find))
2363			adbname->flags |= NAME_HINT_OK;
2364		if (FIND_GLUEOK(find))
2365			adbname->flags |= NAME_GLUE_OK;
2366		if (FIND_STARTATZONE(find))
2367			adbname->flags |= NAME_STARTATZONE;
2368	}
2369
2370	/*
2371	 * Expire old entries, etc.
2372	 */
2373	RUNTIME_CHECK(check_expire_namehooks(adbname, now, adb->overmem) ==
2374		      ISC_FALSE);
2375
2376	/*
2377	 * Do we know that the name is an alias?
2378	 */
2379	if (!EXPIRE_OK(adbname->expire_target, now)) {
2380		/*
2381		 * Yes, it is.
2382		 */
2383		DP(DEF_LEVEL,
2384		   "dns_adb_createfind: name %p is an alias (cached)",
2385		   adbname);
2386		alias = ISC_TRUE;
2387		goto post_copy;
2388	}
2389
2390	/*
2391	 * Try to populate the name from the database and/or
2392	 * start fetches.  First try looking for an A record
2393	 * in the database.
2394	 */
2395	if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
2396	    && WANT_INET(wanted_addresses)) {
2397		result = dbfind_name(adbname, now, dns_rdatatype_a);
2398		if (result == ISC_R_SUCCESS) {
2399			DP(DEF_LEVEL,
2400			   "dns_adb_createfind: found A for name %p in db",
2401			   adbname);
2402			goto v6;
2403		}
2404
2405		/*
2406		 * Did we get a CNAME or DNAME?
2407		 */
2408		if (result == DNS_R_ALIAS) {
2409			DP(DEF_LEVEL,
2410			   "dns_adb_createfind: name %p is an alias",
2411			   adbname);
2412			alias = ISC_TRUE;
2413			goto post_copy;
2414		}
2415
2416		/*
2417		 * If the name doesn't exist at all, don't bother with
2418		 * v6 queries; they won't work.
2419		 *
2420		 * If the name does exist but we didn't get our data, go
2421		 * ahead and try AAAA.
2422		 *
2423		 * If the result is neither of these, try a fetch for A.
2424		 */
2425		if (NXDOMAIN_RESULT(result))
2426			goto fetch;
2427		else if (NXRRSET_RESULT(result))
2428			goto v6;
2429
2430		if (!NAME_FETCH_V4(adbname))
2431			wanted_fetches |= DNS_ADBFIND_INET;
2432	}
2433
2434 v6:
2435	if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
2436	    && WANT_INET6(wanted_addresses)) {
2437		result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
2438		if (result == ISC_R_SUCCESS) {
2439			DP(DEF_LEVEL,
2440			   "dns_adb_createfind: found AAAA for name %p",
2441			   adbname);
2442			goto fetch;
2443		}
2444
2445		/*
2446		 * Did we get a CNAME or DNAME?
2447		 */
2448		if (result == DNS_R_ALIAS) {
2449			DP(DEF_LEVEL,
2450			   "dns_adb_createfind: name %p is an alias",
2451			   adbname);
2452			alias = ISC_TRUE;
2453			goto post_copy;
2454		}
2455
2456		/*
2457		 * Listen to negative cache hints, and don't start
2458		 * another query.
2459		 */
2460		if (NCACHE_RESULT(result) || AUTH_NX(result))
2461			goto fetch;
2462
2463		if (!NAME_FETCH_V6(adbname))
2464			wanted_fetches |= DNS_ADBFIND_INET6;
2465	}
2466
2467 fetch:
2468	if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
2469	    (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
2470		have_address = ISC_TRUE;
2471	else
2472		have_address = ISC_FALSE;
2473	if (wanted_fetches != 0 &&
2474	    ! (FIND_AVOIDFETCHES(find) && have_address)) {
2475		/*
2476		 * We're missing at least one address family.  Either the
2477		 * caller hasn't instructed us to avoid fetches, or we don't
2478		 * know anything about any of the address families that would
2479		 * be acceptable so we have to launch fetches.
2480		 */
2481
2482		if (FIND_STARTATZONE(find))
2483			start_at_zone = ISC_TRUE;
2484
2485		/*
2486		 * Start V4.
2487		 */
2488		if (WANT_INET(wanted_fetches) &&
2489		    fetch_name(adbname, start_at_zone,
2490			       dns_rdatatype_a) == ISC_R_SUCCESS) {
2491			DP(DEF_LEVEL,
2492			   "dns_adb_createfind: started A fetch for name %p",
2493			   adbname);
2494		}
2495
2496		/*
2497		 * Start V6.
2498		 */
2499		if (WANT_INET6(wanted_fetches) &&
2500		    fetch_name(adbname, start_at_zone,
2501			       dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
2502			DP(DEF_LEVEL,
2503			   "dns_adb_createfind: "
2504			   "started AAAA fetch for name %p",
2505			   adbname);
2506		}
2507	}
2508
2509	/*
2510	 * Run through the name and copy out the bits we are
2511	 * interested in.
2512	 */
2513	copy_namehook_lists(adb, find, zone, adbname, now);
2514
2515 post_copy:
2516	if (NAME_FETCH_V4(adbname))
2517		query_pending |= DNS_ADBFIND_INET;
2518	if (NAME_FETCH_V6(adbname))
2519		query_pending |= DNS_ADBFIND_INET6;
2520
2521	/*
2522	 * Attach to the name's query list if there are queries
2523	 * already running, and we have been asked to.
2524	 */
2525	want_event = ISC_TRUE;
2526	if (!FIND_WANTEVENT(find))
2527		want_event = ISC_FALSE;
2528	if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
2529		want_event = ISC_FALSE;
2530	if ((wanted_addresses & query_pending) == 0)
2531		want_event = ISC_FALSE;
2532	if (alias)
2533		want_event = ISC_FALSE;
2534	if (want_event) {
2535		find->adbname = adbname;
2536		find->name_bucket = bucket;
2537		ISC_LIST_APPEND(adbname->finds, find, plink);
2538		find->query_pending = (query_pending & wanted_addresses);
2539		find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
2540		find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
2541		DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
2542		   find, adbname);
2543	} else {
2544		/*
2545		 * Remove the flag so the caller knows there will never
2546		 * be an event, and set internal flags to fake that
2547		 * the event was sent and freed, so dns_adb_destroyfind() will
2548		 * do the right thing.
2549		 */
2550		find->query_pending = (query_pending & wanted_addresses);
2551		find->options &= ~DNS_ADBFIND_WANTEVENT;
2552		find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
2553		find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
2554	}
2555
2556	find->partial_result |= (adbname->partial_result & wanted_addresses);
2557	if (alias) {
2558		if (target != NULL) {
2559			result = dns_name_copy(&adbname->target, target, NULL);
2560			if (result != ISC_R_SUCCESS)
2561				goto out;
2562		}
2563		result = DNS_R_ALIAS;
2564	} else
2565		result = ISC_R_SUCCESS;
2566
2567	/*
2568	 * Copy out error flags from the name structure into the find.
2569	 */
2570	find->result_v4 = find_err_map[adbname->fetch_err];
2571	find->result_v6 = find_err_map[adbname->fetch6_err];
2572
2573 out:
2574	if (find != NULL) {
2575		*findp = find;
2576
2577		if (want_event) {
2578			isc_task_t *taskp;
2579
2580			INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
2581			taskp = NULL;
2582			isc_task_attach(task, &taskp);
2583			find->event.ev_sender = taskp;
2584			find->event.ev_action = action;
2585			find->event.ev_arg = arg;
2586		}
2587	}
2588
2589	if (bucket != DNS_ADB_INVALIDBUCKET)
2590		UNLOCK(&adb->namelocks[bucket]);
2591
2592	return (result);
2593}
2594
2595void
2596dns_adb_destroyfind(dns_adbfind_t **findp) {
2597	dns_adbfind_t *find;
2598	dns_adbentry_t *entry;
2599	dns_adbaddrinfo_t *ai;
2600	int bucket;
2601	dns_adb_t *adb;
2602
2603	REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
2604	find = *findp;
2605	*findp = NULL;
2606
2607	LOCK(&find->lock);
2608
2609	DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
2610
2611	adb = find->adb;
2612	REQUIRE(DNS_ADB_VALID(adb));
2613
2614	REQUIRE(FIND_EVENTFREED(find));
2615
2616	bucket = find->name_bucket;
2617	INSIST(bucket == DNS_ADB_INVALIDBUCKET);
2618
2619	UNLOCK(&find->lock);
2620
2621	/*
2622	 * The find doesn't exist on any list, and nothing is locked.
2623	 * Return the find to the memory pool, and decrement the adb's
2624	 * reference count.
2625	 */
2626	ai = ISC_LIST_HEAD(find->list);
2627	while (ai != NULL) {
2628		ISC_LIST_UNLINK(find->list, ai, publink);
2629		entry = ai->entry;
2630		ai->entry = NULL;
2631		INSIST(DNS_ADBENTRY_VALID(entry));
2632		RUNTIME_CHECK(dec_entry_refcnt(adb, entry, ISC_TRUE) ==
2633			      ISC_FALSE);
2634		free_adbaddrinfo(adb, &ai);
2635		ai = ISC_LIST_HEAD(find->list);
2636	}
2637
2638	/*
2639	 * WARNING:  The find is freed with the adb locked.  This is done
2640	 * to avoid a race condition where we free the find, some other
2641	 * thread tests to see if it should be destroyed, detects it should
2642	 * be, destroys it, and then we try to lock it for our check, but the
2643	 * lock is destroyed.
2644	 */
2645	LOCK(&adb->lock);
2646	if (free_adbfind(adb, &find))
2647		check_exit(adb);
2648	UNLOCK(&adb->lock);
2649}
2650
2651void
2652dns_adb_cancelfind(dns_adbfind_t *find) {
2653	isc_event_t *ev;
2654	isc_task_t *task;
2655	dns_adb_t *adb;
2656	int bucket;
2657	int unlock_bucket;
2658
2659	LOCK(&find->lock);
2660
2661	DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
2662
2663	adb = find->adb;
2664	REQUIRE(DNS_ADB_VALID(adb));
2665
2666	REQUIRE(!FIND_EVENTFREED(find));
2667	REQUIRE(FIND_WANTEVENT(find));
2668
2669	bucket = find->name_bucket;
2670	if (bucket == DNS_ADB_INVALIDBUCKET)
2671		goto cleanup;
2672
2673	/*
2674	 * We need to get the adbname's lock to unlink the find.
2675	 */
2676	unlock_bucket = bucket;
2677	violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
2678	bucket = find->name_bucket;
2679	if (bucket != DNS_ADB_INVALIDBUCKET) {
2680		ISC_LIST_UNLINK(find->adbname->finds, find, plink);
2681		find->adbname = NULL;
2682		find->name_bucket = DNS_ADB_INVALIDBUCKET;
2683	}
2684	UNLOCK(&adb->namelocks[unlock_bucket]);
2685	bucket = DNS_ADB_INVALIDBUCKET;
2686
2687 cleanup:
2688
2689	if (!FIND_EVENTSENT(find)) {
2690		ev = &find->event;
2691		task = ev->ev_sender;
2692		ev->ev_sender = find;
2693		ev->ev_type = DNS_EVENT_ADBCANCELED;
2694		ev->ev_destroy = event_free;
2695		ev->ev_destroy_arg = find;
2696		find->result_v4 = ISC_R_CANCELED;
2697		find->result_v6 = ISC_R_CANCELED;
2698
2699		DP(DEF_LEVEL, "sending event %p to task %p for find %p",
2700		   ev, task, find);
2701
2702		isc_task_sendanddetach(&task, (isc_event_t **)&ev);
2703	}
2704
2705	UNLOCK(&find->lock);
2706}
2707
2708void
2709dns_adb_dump(dns_adb_t *adb, FILE *f) {
2710	REQUIRE(DNS_ADB_VALID(adb));
2711	REQUIRE(f != NULL);
2712
2713	/*
2714	 * Lock the adb itself, lock all the name buckets, then lock all
2715	 * the entry buckets.  This should put the adb into a state where
2716	 * nothing can change, so we can iterate through everything and
2717	 * print at our leisure.
2718	 */
2719
2720	LOCK(&adb->lock);
2721	dump_adb(adb, f, ISC_FALSE);
2722	UNLOCK(&adb->lock);
2723}
2724
2725static void
2726dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
2727	if (value == INT_MAX)
2728		return;
2729	fprintf(f, " [%s TTL %d]", legend, value - now);
2730}
2731
2732static void
2733dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug) {
2734	int i;
2735	dns_adbname_t *name;
2736	isc_stdtime_t now;
2737
2738	isc_stdtime_get(&now);
2739
2740	fprintf(f, ";\n; Address database dump\n;\n");
2741	if (debug)
2742		fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
2743			adb, adb->erefcnt, adb->irefcnt,
2744			isc_mempool_getallocated(adb->nhmp));
2745
2746	for (i = 0; i < NBUCKETS; i++)
2747		LOCK(&adb->namelocks[i]);
2748	for (i = 0; i < NBUCKETS; i++)
2749		LOCK(&adb->entrylocks[i]);
2750
2751	/*
2752	 * Dump the names
2753	 */
2754	for (i = 0; i < NBUCKETS; i++) {
2755		name = ISC_LIST_HEAD(adb->names[i]);
2756		if (name == NULL)
2757			continue;
2758		if (debug)
2759			fprintf(f, "; bucket %d\n", i);
2760		for (;
2761		     name != NULL;
2762		     name = ISC_LIST_NEXT(name, plink))
2763		{
2764			if (debug)
2765				fprintf(f, "; name %p (flags %08x)\n",
2766					name, name->flags);
2767
2768			fprintf(f, "; ");
2769			print_dns_name(f, &name->name);
2770			if (dns_name_countlabels(&name->target) > 0) {
2771				fprintf(f, " alias ");
2772				print_dns_name(f, &name->target);
2773			}
2774
2775			dump_ttl(f, "v4", name->expire_v4, now);
2776			dump_ttl(f, "v6", name->expire_v6, now);
2777			dump_ttl(f, "target", name->expire_target, now);
2778
2779			fprintf(f, " [v4 %s] [v6 %s]",
2780				errnames[name->fetch_err],
2781				errnames[name->fetch6_err]);
2782
2783			fprintf(f, "\n");
2784
2785			print_namehook_list(f, "v4", &name->v4, debug, now);
2786			print_namehook_list(f, "v6", &name->v6, debug, now);
2787
2788			if (debug)
2789				print_fetch_list(f, name);
2790			if (debug)
2791				print_find_list(f, name);
2792
2793		}
2794	}
2795
2796	/*
2797	 * Unlock everything
2798	 */
2799	for (i = 0; i < NBUCKETS; i++)
2800		UNLOCK(&adb->entrylocks[i]);
2801	for (i = 0; i < NBUCKETS; i++)
2802		UNLOCK(&adb->namelocks[i]);
2803}
2804
2805static void
2806dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug,
2807	   isc_stdtime_t now)
2808{
2809	char addrbuf[ISC_NETADDR_FORMATSIZE];
2810	isc_netaddr_t netaddr;
2811	dns_adbzoneinfo_t *zi;
2812
2813	isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
2814	isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
2815
2816	if (debug)
2817		fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
2818
2819	fprintf(f, ";\t%s [srtt %u] [flags %08x]",
2820		addrbuf, entry->srtt, entry->flags);
2821	fprintf(f, "\n");
2822	for (zi = ISC_LIST_HEAD(entry->zoneinfo);
2823	     zi != NULL;
2824	     zi = ISC_LIST_NEXT(zi, plink)) {
2825		fprintf(f, ";\t\t");
2826		print_dns_name(f, &zi->zone);
2827		fprintf(f, " [lame TTL %d]\n", zi->lame_timer - now);
2828	}
2829}
2830
2831void
2832dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
2833	char tmp[512];
2834	const char *tmpp;
2835	dns_adbaddrinfo_t *ai;
2836	isc_sockaddr_t *sa;
2837
2838	/*
2839	 * Not used currently, in the API Just In Case we
2840	 * want to dump out the name and/or entries too.
2841	 */
2842
2843	LOCK(&find->lock);
2844
2845	fprintf(f, ";Find %p\n", find);
2846	fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
2847		find->query_pending, find->partial_result,
2848		find->options, find->flags);
2849	fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
2850		find->name_bucket, find->adbname, find->event.ev_sender);
2851
2852	ai = ISC_LIST_HEAD(find->list);
2853	if (ai != NULL)
2854		fprintf(f, "\tAddresses:\n");
2855	while (ai != NULL) {
2856		sa = &ai->sockaddr;
2857		switch (sa->type.sa.sa_family) {
2858		case AF_INET:
2859			tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
2860					 tmp, sizeof(tmp));
2861			break;
2862		case AF_INET6:
2863			tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
2864					 tmp, sizeof(tmp));
2865			break;
2866		default:
2867			tmpp = "UnkFamily";
2868		}
2869
2870		if (tmpp == NULL)
2871			tmpp = "BadAddress";
2872
2873		fprintf(f, "\t\tentry %p, flags %08x"
2874			" srtt %u addr %s\n",
2875			ai->entry, ai->flags, ai->srtt, tmpp);
2876
2877		ai = ISC_LIST_NEXT(ai, publink);
2878	}
2879
2880	UNLOCK(&find->lock);
2881}
2882
2883static void
2884print_dns_name(FILE *f, dns_name_t *name) {
2885	char buf[DNS_NAME_FORMATSIZE];
2886
2887	INSIST(f != NULL);
2888
2889	dns_name_format(name, buf, sizeof(buf));
2890	fprintf(f, "%s", buf);
2891}
2892
2893static void
2894print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list,
2895		    isc_boolean_t debug, isc_stdtime_t now)
2896{
2897	dns_adbnamehook_t *nh;
2898
2899	for (nh = ISC_LIST_HEAD(*list);
2900	     nh != NULL;
2901	     nh = ISC_LIST_NEXT(nh, plink))
2902	{
2903		if (debug)
2904			fprintf(f, ";\tHook(%s) %p\n", legend, nh);
2905		dump_entry(f, nh->entry, debug, now);
2906	}
2907}
2908
2909static inline void
2910print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) {
2911	fprintf(f, "\t\tFetch(%s): %p -> { nh %p, entry %p, fetch %p }\n",
2912		type, ft, ft->namehook, ft->entry, ft->fetch);
2913}
2914
2915static void
2916print_fetch_list(FILE *f, dns_adbname_t *n) {
2917	if (NAME_FETCH_A(n))
2918		print_fetch(f, n->fetch_a, "A");
2919	if (NAME_FETCH_AAAA(n))
2920		print_fetch(f, n->fetch_aaaa, "AAAA");
2921}
2922
2923static void
2924print_find_list(FILE *f, dns_adbname_t *name) {
2925	dns_adbfind_t *find;
2926
2927	find = ISC_LIST_HEAD(name->finds);
2928	while (find != NULL) {
2929		dns_adb_dumpfind(find, f);
2930		find = ISC_LIST_NEXT(find, plink);
2931	}
2932}
2933
2934static isc_result_t
2935dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype)
2936{
2937	isc_result_t result;
2938	dns_rdataset_t rdataset;
2939	dns_adb_t *adb;
2940	dns_fixedname_t foundname;
2941	dns_name_t *fname;
2942
2943	INSIST(DNS_ADBNAME_VALID(adbname));
2944	adb = adbname->adb;
2945	INSIST(DNS_ADB_VALID(adb));
2946	INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
2947
2948	dns_fixedname_init(&foundname);
2949	fname =	dns_fixedname_name(&foundname);
2950	dns_rdataset_init(&rdataset);
2951
2952	if (rdtype == dns_rdatatype_a)
2953		adbname->fetch_err = FIND_ERR_UNEXPECTED;
2954	else
2955		adbname->fetch6_err = FIND_ERR_UNEXPECTED;
2956
2957	result = dns_view_find(adb->view, &adbname->name, rdtype, now,
2958			       NAME_GLUEOK(adbname),
2959			       ISC_TF(NAME_HINTOK(adbname)),
2960			       NULL, NULL, fname, &rdataset, NULL);
2961
2962	/* XXXVIX this switch statement is too sparse to gen a jump table. */
2963	switch (result) {
2964	case DNS_R_GLUE:
2965	case DNS_R_HINT:
2966	case ISC_R_SUCCESS:
2967		/*
2968		 * Found in the database.  Even if we can't copy out
2969		 * any information, return success, or else a fetch
2970		 * will be made, which will only make things worse.
2971		 */
2972		if (rdtype == dns_rdatatype_a)
2973			adbname->fetch_err = FIND_ERR_SUCCESS;
2974		else
2975			adbname->fetch6_err = FIND_ERR_SUCCESS;
2976		result = import_rdataset(adbname, &rdataset, now);
2977		break;
2978	case DNS_R_NXDOMAIN:
2979	case DNS_R_NXRRSET:
2980		/*
2981		 * We're authoritative and the data doesn't exist.
2982		 * Make up a negative cache entry so we don't ask again
2983		 * for a while.
2984		 *
2985		 * XXXRTH  What time should we use?  I'm putting in 30 seconds
2986		 * for now.
2987		 */
2988		if (rdtype == dns_rdatatype_a) {
2989			adbname->expire_v4 = now + 30;
2990			DP(NCACHE_LEVEL,
2991			   "adb name %p: Caching auth negative entry for A",
2992			   adbname);
2993			if (result == DNS_R_NXDOMAIN)
2994				adbname->fetch_err = FIND_ERR_NXDOMAIN;
2995			else
2996				adbname->fetch_err = FIND_ERR_NXRRSET;
2997		} else {
2998			DP(NCACHE_LEVEL,
2999			   "adb name %p: Caching auth negative entry for AAAA",
3000			   adbname);
3001			adbname->expire_v6 = now + 30;
3002			if (result == DNS_R_NXDOMAIN)
3003				adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3004			else
3005				adbname->fetch6_err = FIND_ERR_NXRRSET;
3006		}
3007		break;
3008	case DNS_R_NCACHENXDOMAIN:
3009	case DNS_R_NCACHENXRRSET:
3010		/*
3011		 * We found a negative cache entry.  Pull the TTL from it
3012		 * so we won't ask again for a while.
3013		 */
3014		rdataset.ttl = ttlclamp(rdataset.ttl);
3015		if (rdtype == dns_rdatatype_a) {
3016			adbname->expire_v4 = rdataset.ttl + now;
3017			if (result == DNS_R_NCACHENXDOMAIN)
3018				adbname->fetch_err = FIND_ERR_NXDOMAIN;
3019			else
3020				adbname->fetch_err = FIND_ERR_NXRRSET;
3021			DP(NCACHE_LEVEL,
3022			  "adb name %p: Caching negative entry for A (ttl %u)",
3023			   adbname, rdataset.ttl);
3024		} else {
3025			DP(NCACHE_LEVEL,
3026		       "adb name %p: Caching negative entry for AAAA (ttl %u)",
3027			   adbname, rdataset.ttl);
3028			adbname->expire_v6 = rdataset.ttl + now;
3029			if (result == DNS_R_NCACHENXDOMAIN)
3030				adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3031			else
3032				adbname->fetch6_err = FIND_ERR_NXRRSET;
3033		}
3034		break;
3035	case DNS_R_CNAME:
3036	case DNS_R_DNAME:
3037		/*
3038		 * Clear the hint and glue flags, so this will match
3039		 * more often.
3040		 */
3041		adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
3042
3043		rdataset.ttl = ttlclamp(rdataset.ttl);
3044		clean_target(adb, &adbname->target);
3045		adbname->expire_target = INT_MAX;
3046		result = set_target(adb, &adbname->name, fname, &rdataset,
3047				    &adbname->target);
3048		if (result == ISC_R_SUCCESS) {
3049			result = DNS_R_ALIAS;
3050			DP(NCACHE_LEVEL,
3051			   "adb name %p: caching alias target",
3052			   adbname);
3053			adbname->expire_target = rdataset.ttl + now;
3054		}
3055		if (rdtype == dns_rdatatype_a)
3056			adbname->fetch_err = FIND_ERR_SUCCESS;
3057		else
3058			adbname->fetch6_err = FIND_ERR_SUCCESS;
3059		break;
3060	}
3061
3062	if (dns_rdataset_isassociated(&rdataset))
3063		dns_rdataset_disassociate(&rdataset);
3064
3065	return (result);
3066}
3067
3068static void
3069fetch_callback(isc_task_t *task, isc_event_t *ev) {
3070	dns_fetchevent_t *dev;
3071	dns_adbname_t *name;
3072	dns_adb_t *adb;
3073	dns_adbfetch_t *fetch;
3074	int bucket;
3075	isc_eventtype_t ev_status;
3076	isc_stdtime_t now;
3077	isc_result_t result;
3078	unsigned int address_type;
3079	isc_boolean_t want_check_exit = ISC_FALSE;
3080
3081	UNUSED(task);
3082
3083	INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
3084	dev = (dns_fetchevent_t *)ev;
3085	name = ev->ev_arg;
3086	INSIST(DNS_ADBNAME_VALID(name));
3087	adb = name->adb;
3088	INSIST(DNS_ADB_VALID(adb));
3089
3090	bucket = name->lock_bucket;
3091	LOCK(&adb->namelocks[bucket]);
3092
3093	INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
3094	address_type = 0;
3095	if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
3096		address_type = DNS_ADBFIND_INET;
3097		fetch = name->fetch_a;
3098		name->fetch_a = NULL;
3099	} else if (NAME_FETCH_AAAA(name)
3100		   && (name->fetch_aaaa->fetch == dev->fetch)) {
3101		address_type = DNS_ADBFIND_INET6;
3102		fetch = name->fetch_aaaa;
3103		name->fetch_aaaa = NULL;
3104	}
3105	INSIST(address_type != 0);
3106
3107	dns_resolver_destroyfetch(&fetch->fetch);
3108	dev->fetch = NULL;
3109
3110	ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
3111
3112	/*
3113	 * Cleanup things we don't care about.
3114	 */
3115	if (dev->node != NULL)
3116		dns_db_detachnode(dev->db, &dev->node);
3117	if (dev->db != NULL)
3118		dns_db_detach(&dev->db);
3119
3120	/*
3121	 * If this name is marked as dead, clean up, throwing away
3122	 * potentially good data.
3123	 */
3124	if (NAME_DEAD(name)) {
3125		free_adbfetch(adb, &fetch);
3126		isc_event_free(&ev);
3127
3128		want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
3129
3130		UNLOCK(&adb->namelocks[bucket]);
3131
3132		if (want_check_exit) {
3133			LOCK(&adb->lock);
3134			check_exit(adb);
3135			UNLOCK(&adb->lock);
3136		}
3137
3138		return;
3139	}
3140
3141	isc_stdtime_get(&now);
3142
3143	/*
3144	 * If we got a negative cache response, remember it.
3145	 */
3146	if (NCACHE_RESULT(dev->result)) {
3147		dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3148		if (address_type == DNS_ADBFIND_INET) {
3149			DP(NCACHE_LEVEL, "adb fetch name %p: "
3150			   "caching negative entry for A (ttl %u)",
3151			   name, dev->rdataset->ttl);
3152			name->expire_v4 = ISC_MIN(name->expire_v4,
3153						  dev->rdataset->ttl + now);
3154			if (dev->result == DNS_R_NCACHENXDOMAIN)
3155				name->fetch_err = FIND_ERR_NXDOMAIN;
3156			else
3157				name->fetch_err = FIND_ERR_NXRRSET;
3158		} else {
3159			DP(NCACHE_LEVEL, "adb fetch name %p: "
3160			   "caching negative entry for AAAA (ttl %u)",
3161			   name, dev->rdataset->ttl);
3162			name->expire_v6 = ISC_MIN(name->expire_v6,
3163						  dev->rdataset->ttl + now);
3164			if (dev->result == DNS_R_NCACHENXDOMAIN)
3165				name->fetch6_err = FIND_ERR_NXDOMAIN;
3166			else
3167				name->fetch6_err = FIND_ERR_NXRRSET;
3168		}
3169		goto out;
3170	}
3171
3172	/*
3173	 * Handle CNAME/DNAME.
3174	 */
3175	if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
3176		dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3177		clean_target(adb, &name->target);
3178		name->expire_target = INT_MAX;
3179		result = set_target(adb, &name->name,
3180				    dns_fixedname_name(&dev->foundname),
3181				    dev->rdataset,
3182				    &name->target);
3183		if (result == ISC_R_SUCCESS) {
3184			DP(NCACHE_LEVEL,
3185			   "adb fetch name %p: caching alias target",
3186			   name);
3187			name->expire_target = dev->rdataset->ttl + now;
3188		}
3189		goto check_result;
3190	}
3191
3192	/*
3193	 * Did we get back junk?  If so, and there are no more fetches
3194	 * sitting out there, tell all the finds about it.
3195	 */
3196	if (dev->result != ISC_R_SUCCESS) {
3197		char buf[DNS_NAME_FORMATSIZE];
3198
3199		dns_name_format(&name->name, buf, sizeof(buf));
3200		DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
3201		   buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
3202		   dns_result_totext(dev->result));
3203		/* XXXMLG Don't pound on bad servers. */
3204		if (address_type == DNS_ADBFIND_INET) {
3205			name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
3206			name->fetch_err = FIND_ERR_FAILURE;
3207		} else {
3208			name->expire_v6 = ISC_MIN(name->expire_v6, now + 300);
3209			name->fetch6_err = FIND_ERR_FAILURE;
3210		}
3211		goto out;
3212	}
3213
3214	/*
3215	 * We got something potentially useful.
3216	 */
3217	result = import_rdataset(name, &fetch->rdataset, now);
3218
3219 check_result:
3220	if (result == ISC_R_SUCCESS) {
3221		ev_status = DNS_EVENT_ADBMOREADDRESSES;
3222		if (address_type == DNS_ADBFIND_INET)
3223			name->fetch_err = FIND_ERR_SUCCESS;
3224		else
3225			name->fetch6_err = FIND_ERR_SUCCESS;
3226	}
3227
3228 out:
3229	free_adbfetch(adb, &fetch);
3230	isc_event_free(&ev);
3231
3232	clean_finds_at_name(name, ev_status, address_type);
3233
3234	UNLOCK(&adb->namelocks[bucket]);
3235}
3236
3237static isc_result_t
3238fetch_name(dns_adbname_t *adbname,
3239	   isc_boolean_t start_at_zone,
3240	   dns_rdatatype_t type)
3241{
3242	isc_result_t result;
3243	dns_adbfetch_t *fetch = NULL;
3244	dns_adb_t *adb;
3245	dns_fixedname_t fixed;
3246	dns_name_t *name;
3247	dns_rdataset_t rdataset;
3248	dns_rdataset_t *nameservers;
3249	unsigned int options;
3250
3251	INSIST(DNS_ADBNAME_VALID(adbname));
3252	adb = adbname->adb;
3253	INSIST(DNS_ADB_VALID(adb));
3254
3255	INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
3256	       (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
3257
3258	adbname->fetch_err = FIND_ERR_NOTFOUND;
3259
3260	name = NULL;
3261	nameservers = NULL;
3262	dns_rdataset_init(&rdataset);
3263
3264	options = DNS_FETCHOPT_NOVALIDATE;
3265	if (start_at_zone) {
3266		DP(ENTER_LEVEL,
3267		   "fetch_name: starting at zone for name %p",
3268		   adbname);
3269		dns_fixedname_init(&fixed);
3270		name = dns_fixedname_name(&fixed);
3271		result = dns_view_findzonecut2(adb->view, &adbname->name, name,
3272					       0, 0, ISC_TRUE, ISC_FALSE,
3273					       &rdataset, NULL);
3274		if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
3275			goto cleanup;
3276		nameservers = &rdataset;
3277		options |= DNS_FETCHOPT_UNSHARED;
3278	}
3279
3280	fetch = new_adbfetch(adb);
3281	if (fetch == NULL) {
3282		result = ISC_R_NOMEMORY;
3283		goto cleanup;
3284	}
3285
3286	result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
3287					  type, name, nameservers, NULL,
3288					  options, adb->task, fetch_callback,
3289					  adbname, &fetch->rdataset, NULL,
3290					  &fetch->fetch);
3291	if (result != ISC_R_SUCCESS)
3292		goto cleanup;
3293
3294	if (type == dns_rdatatype_a)
3295		adbname->fetch_a = fetch;
3296	else
3297		adbname->fetch_aaaa = fetch;
3298	fetch = NULL;  /* Keep us from cleaning this up below. */
3299
3300 cleanup:
3301	if (fetch != NULL)
3302		free_adbfetch(adb, &fetch);
3303	if (dns_rdataset_isassociated(&rdataset))
3304		dns_rdataset_disassociate(&rdataset);
3305
3306	return (result);
3307}
3308
3309/*
3310 * XXXMLG Needs to take a find argument and an address info, no zone or adb,
3311 * since these can be extracted from the find itself.
3312 */
3313isc_result_t
3314dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *zone,
3315		 isc_stdtime_t expire_time)
3316{
3317	dns_adbzoneinfo_t *zi;
3318	int bucket;
3319	isc_result_t result = ISC_R_SUCCESS;
3320
3321	REQUIRE(DNS_ADB_VALID(adb));
3322	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3323	REQUIRE(zone != NULL);
3324
3325	bucket = addr->entry->lock_bucket;
3326	LOCK(&adb->entrylocks[bucket]);
3327	zi = ISC_LIST_HEAD(addr->entry->zoneinfo);
3328	while (zi != NULL && dns_name_equal(zone, &zi->zone))
3329		zi = ISC_LIST_NEXT(zi, plink);
3330	if (zi != NULL) {
3331		if (expire_time > zi->lame_timer)
3332			zi->lame_timer = expire_time;
3333		goto unlock;
3334	}
3335	zi = new_adbzoneinfo(adb, zone);
3336	if (zi == NULL) {
3337		result = ISC_R_NOMEMORY;
3338		goto unlock;
3339	}
3340
3341	zi->lame_timer = expire_time;
3342
3343	ISC_LIST_PREPEND(addr->entry->zoneinfo, zi, plink);
3344 unlock:
3345	UNLOCK(&adb->entrylocks[bucket]);
3346
3347	return (ISC_R_SUCCESS);
3348}
3349
3350void
3351dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3352		   unsigned int rtt, unsigned int factor)
3353{
3354	int bucket;
3355	unsigned int new_srtt;
3356	isc_stdtime_t now;
3357
3358	REQUIRE(DNS_ADB_VALID(adb));
3359	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3360	REQUIRE(factor <= 10);
3361
3362	bucket = addr->entry->lock_bucket;
3363	LOCK(&adb->entrylocks[bucket]);
3364
3365	if (factor == DNS_ADB_RTTADJAGE)
3366		new_srtt = addr->entry->srtt * 98 / 100;
3367	else
3368		new_srtt = (addr->entry->srtt / 10 * factor)
3369			+ (rtt / 10 * (10 - factor));
3370
3371	addr->entry->srtt = new_srtt;
3372	addr->srtt = new_srtt;
3373
3374	isc_stdtime_get(&now);
3375	addr->entry->expires = now + ADB_ENTRY_WINDOW;
3376
3377	UNLOCK(&adb->entrylocks[bucket]);
3378}
3379
3380void
3381dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3382		    unsigned int bits, unsigned int mask)
3383{
3384	int bucket;
3385
3386	REQUIRE(DNS_ADB_VALID(adb));
3387	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3388
3389	bucket = addr->entry->lock_bucket;
3390	LOCK(&adb->entrylocks[bucket]);
3391
3392	addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
3393	/*
3394	 * Note that we do not update the other bits in addr->flags with
3395	 * the most recent values from addr->entry->flags.
3396	 */
3397	addr->flags = (addr->flags & ~mask) | (bits & mask);
3398
3399	UNLOCK(&adb->entrylocks[bucket]);
3400}
3401
3402isc_result_t
3403dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
3404		     dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
3405{
3406	int bucket;
3407	dns_adbentry_t *entry;
3408	dns_adbaddrinfo_t *addr;
3409	isc_result_t result;
3410	in_port_t port;
3411
3412	REQUIRE(DNS_ADB_VALID(adb));
3413	REQUIRE(addrp != NULL && *addrp == NULL);
3414
3415	UNUSED(now);
3416
3417	result = ISC_R_SUCCESS;
3418	bucket = DNS_ADB_INVALIDBUCKET;
3419	entry = find_entry_and_lock(adb, sa, &bucket);
3420	if (adb->entry_sd[bucket]) {
3421		result = ISC_R_SHUTTINGDOWN;
3422		goto unlock;
3423	}
3424	if (entry == NULL) {
3425		/*
3426		 * We don't know anything about this address.
3427		 */
3428		entry = new_adbentry(adb);
3429		if (entry == NULL) {
3430			result = ISC_R_NOMEMORY;
3431			goto unlock;
3432		}
3433		entry->sockaddr = *sa;
3434		link_entry(adb, bucket, entry);
3435		DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
3436	} else
3437		DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
3438
3439	port = isc_sockaddr_getport(sa);
3440	addr = new_adbaddrinfo(adb, entry, port);
3441	if (addr != NULL) {
3442		inc_entry_refcnt(adb, entry, ISC_FALSE);
3443		*addrp = addr;
3444	}
3445
3446 unlock:
3447	UNLOCK(&adb->entrylocks[bucket]);
3448
3449	return (result);
3450}
3451
3452void
3453dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
3454	dns_adbaddrinfo_t *addr;
3455	dns_adbentry_t *entry;
3456	int bucket;
3457	isc_stdtime_t now;
3458	isc_boolean_t want_check_exit = ISC_FALSE;
3459
3460	REQUIRE(DNS_ADB_VALID(adb));
3461	REQUIRE(addrp != NULL);
3462	addr = *addrp;
3463	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3464	entry = addr->entry;
3465	REQUIRE(DNS_ADBENTRY_VALID(entry));
3466
3467	isc_stdtime_get(&now);
3468
3469	*addrp = NULL;
3470
3471	bucket = addr->entry->lock_bucket;
3472	LOCK(&adb->entrylocks[bucket]);
3473
3474	entry->expires = now + ADB_ENTRY_WINDOW;
3475
3476	want_check_exit = dec_entry_refcnt(adb, entry, ISC_FALSE);
3477
3478	UNLOCK(&adb->entrylocks[bucket]);
3479
3480	addr->entry = NULL;
3481	free_adbaddrinfo(adb, &addr);
3482
3483	if (want_check_exit) {
3484		LOCK(&adb->lock);
3485		check_exit(adb);
3486		UNLOCK(&adb->lock);
3487	}
3488}
3489
3490void
3491dns_adb_flush(dns_adb_t *adb) {
3492	unsigned int i;
3493
3494	INSIST(DNS_ADB_VALID(adb));
3495
3496	LOCK(&adb->lock);
3497
3498	for (i = 0; i < NBUCKETS; i++) {
3499		/*
3500		 * Call our cleanup routines.
3501		 */
3502		RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
3503		RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
3504	}
3505
3506#ifdef DUMP_ADB_AFTER_CLEANING
3507	dump_adb(adb, stdout, ISC_TRUE);
3508#endif
3509
3510	UNLOCK(&adb->lock);
3511}
3512
3513void
3514dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
3515	dns_adbname_t *adbname;
3516	dns_adbname_t *nextname;
3517	int bucket;
3518
3519	INSIST(DNS_ADB_VALID(adb));
3520
3521	LOCK(&adb->lock);
3522	bucket = dns_name_hash(name, ISC_FALSE) % NBUCKETS;
3523	LOCK(&adb->namelocks[bucket]);
3524	adbname = ISC_LIST_HEAD(adb->names[bucket]);
3525	while (adbname != NULL) {
3526		nextname = ISC_LIST_NEXT(adbname, plink);
3527		if (!NAME_DEAD(adbname) &&
3528		    dns_name_equal(name, &adbname->name)) {
3529			RUNTIME_CHECK(kill_name(&adbname,
3530						DNS_EVENT_ADBCANCELED) ==
3531				      ISC_FALSE);
3532		}
3533		adbname = nextname;
3534	}
3535	UNLOCK(&adb->namelocks[bucket]);
3536	UNLOCK(&adb->lock);
3537}
3538
3539static void
3540water(void *arg, int mark) {
3541	dns_adb_t *adb = arg;
3542	isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
3543	isc_interval_t interval;
3544
3545	REQUIRE(DNS_ADB_VALID(adb));
3546
3547	DP(ISC_LOG_DEBUG(1),
3548	   "adb reached %s water mark", overmem ? "high" : "low");
3549
3550	adb->overmem = overmem;
3551	if (overmem) {
3552		isc_interval_set(&interval, 0, 1);
3553		(void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
3554				      &interval, ISC_TRUE);
3555	}
3556}
3557
3558void
3559dns_adb_setadbsize(dns_adb_t *adb, isc_uint32_t size) {
3560	isc_uint32_t hiwater;
3561	isc_uint32_t lowater;
3562
3563	INSIST(DNS_ADB_VALID(adb));
3564
3565	if (size != 0 && size < DNS_ADB_MINADBSIZE)
3566		size = DNS_ADB_MINADBSIZE;
3567
3568	hiwater = size - (size >> 3);   /* Approximately 7/8ths. */
3569	lowater = size - (size >> 2);   /* Approximately 3/4ths. */
3570
3571	if (size == 0 || hiwater == 0 || lowater == 0)
3572		isc_mem_setwater(adb->mctx, water, adb, 0, 0);
3573	else
3574		isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);
3575}
3576