1 /*
2  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
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 /*! \file
19  *
20  * \note
21  * In finds, if task == NULL, no events will be generated, and no events
22  * have been sent.  If task != NULL but taskaction == NULL, an event has been
23  * posted but not yet freed.  If neither are NULL, no event was posted.
24  *
25  */
26 
27 #include <config.h>
28 
29 #include <limits.h>
30 
31 #include <isc/mutexblock.h>
32 #include <isc/netaddr.h>
33 #include <isc/print.h>
34 #include <isc/random.h>
35 #include <isc/stats.h>
36 #include <isc/string.h>         /* Required for HP/UX (and others?) */
37 #include <isc/task.h>
38 #include <isc/util.h>
39 
40 #include <dns/adb.h>
41 #include <dns/db.h>
42 #include <dns/events.h>
43 #include <dns/log.h>
44 #include <dns/rdata.h>
45 #include <dns/rdataset.h>
46 #include <dns/rdatastruct.h>
47 #include <dns/rdatatype.h>
48 #include <dns/resolver.h>
49 #include <dns/result.h>
50 #include <dns/stats.h>
51 
52 #define DNS_ADB_MAGIC             ISC_MAGIC('D', 'a', 'd', 'b')
53 #define DNS_ADB_VALID(x)          ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
54 #define DNS_ADBNAME_MAGIC         ISC_MAGIC('a', 'd', 'b', 'N')
55 #define DNS_ADBNAME_VALID(x)      ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
56 #define DNS_ADBNAMEHOOK_MAGIC     ISC_MAGIC('a', 'd', 'N', 'H')
57 #define DNS_ADBNAMEHOOK_VALID(x)  ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
58 #define DNS_ADBLAMEINFO_MAGIC     ISC_MAGIC('a', 'd', 'b', 'Z')
59 #define DNS_ADBLAMEINFO_VALID(x)  ISC_MAGIC_VALID(x, DNS_ADBLAMEINFO_MAGIC)
60 #define DNS_ADBENTRY_MAGIC        ISC_MAGIC('a', 'd', 'b', 'E')
61 #define DNS_ADBENTRY_VALID(x)     ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
62 #define DNS_ADBFETCH_MAGIC        ISC_MAGIC('a', 'd', 'F', '4')
63 #define DNS_ADBFETCH_VALID(x)     ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
64 #define DNS_ADBFETCH6_MAGIC       ISC_MAGIC('a', 'd', 'F', '6')
65 #define DNS_ADBFETCH6_VALID(x)    ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
66 
67 /*!
68  * For type 3 negative cache entries, we will remember that the address is
69  * broken for this long.  XXXMLG This is also used for actual addresses, too.
70  * The intent is to keep us from constantly asking about A/AAAA records
71  * if the zone has extremely low TTLs.
72  */
73 #define ADB_CACHE_MINIMUM       10      /*%< seconds */
74 #define ADB_CACHE_MAXIMUM       86400   /*%< seconds (86400 = 24 hours) */
75 #define ADB_ENTRY_WINDOW        1800    /*%< seconds */
76 
77 /*%
78  * The period in seconds after which an ADB name entry is regarded as stale
79  * and forced to be cleaned up.
80  * TODO: This should probably be configurable at run-time.
81  */
82 #ifndef ADB_STALE_MARGIN
83 #define ADB_STALE_MARGIN        1800
84 #endif
85 
86 #define FREE_ITEMS              64      /*%< free count for memory pools */
87 #define FILL_COUNT              16      /*%< fill count for memory pools */
88 
89 #define DNS_ADB_INVALIDBUCKET (-1)      /*%< invalid bucket address */
90 
91 #define DNS_ADB_MINADBSIZE      (1024U*1024U)     /*%< 1 Megabyte */
92 
93 typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
94 typedef struct dns_adbnamehook dns_adbnamehook_t;
95 typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
96 typedef struct dns_adblameinfo dns_adblameinfo_t;
97 typedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t;
98 typedef struct dns_adbfetch dns_adbfetch_t;
99 typedef struct dns_adbfetch6 dns_adbfetch6_t;
100 
101 /*% dns adb structure */
102 struct dns_adb {
103 	unsigned int                    magic;
104 
105 	isc_mutex_t                     lock;
106 	isc_mutex_t                     reflock; /*%< Covers irefcnt, erefcnt */
107 	isc_mutex_t                     overmemlock; /*%< Covers overmem */
108 	isc_mem_t                      *mctx;
109 	dns_view_t                     *view;
110 
111 	isc_taskmgr_t                  *taskmgr;
112 	isc_task_t                     *task;
113 	isc_task_t                     *excl;
114 
115 	isc_interval_t                  tick_interval;
116 	int                             next_cleanbucket;
117 
118 	unsigned int                    irefcnt;
119 	unsigned int                    erefcnt;
120 
121 	isc_mutex_t                     mplock;
122 	isc_mempool_t                  *nmp;    /*%< dns_adbname_t */
123 	isc_mempool_t                  *nhmp;   /*%< dns_adbnamehook_t */
124 	isc_mempool_t                  *limp;   /*%< dns_adblameinfo_t */
125 	isc_mempool_t                  *emp;    /*%< dns_adbentry_t */
126 	isc_mempool_t                  *ahmp;   /*%< dns_adbfind_t */
127 	isc_mempool_t                  *aimp;   /*%< dns_adbaddrinfo_t */
128 	isc_mempool_t                  *afmp;   /*%< dns_adbfetch_t */
129 
130 	/*!
131 	 * Bucketized locks and lists for names.
132 	 *
133 	 * XXXRTH  Have a per-bucket structure that contains all of these?
134 	 */
135 	unsigned int			nnames;
136 	isc_mutex_t                     namescntlock;
137 	unsigned int			namescnt;
138 	dns_adbnamelist_t               *names;
139 	dns_adbnamelist_t               *deadnames;
140 	isc_mutex_t                     *namelocks;
141 	isc_boolean_t                   *name_sd;
142 	unsigned int                    *name_refcnt;
143 
144 	/*!
145 	 * Bucketized locks and lists for entries.
146 	 *
147 	 * XXXRTH  Have a per-bucket structure that contains all of these?
148 	 */
149 	unsigned int			nentries;
150 	isc_mutex_t                     entriescntlock;
151 	unsigned int			entriescnt;
152 	dns_adbentrylist_t              *entries;
153 	dns_adbentrylist_t              *deadentries;
154 	isc_mutex_t                     *entrylocks;
155 	isc_boolean_t                   *entry_sd; /*%< shutting down */
156 	unsigned int                    *entry_refcnt;
157 
158 	isc_event_t                     cevent;
159 	isc_boolean_t                   cevent_out;
160 	isc_boolean_t                   shutting_down;
161 	isc_eventlist_t                 whenshutdown;
162 	isc_event_t			growentries;
163 	isc_boolean_t			growentries_sent;
164 	isc_event_t			grownames;
165 	isc_boolean_t			grownames_sent;
166 
167 #ifdef ENABLE_FETCHLIMIT
168 	isc_uint32_t			quota;
169 	isc_uint32_t			atr_freq;
170 	double				atr_low;
171 	double				atr_high;
172 	double				atr_discount;
173 #endif /* ENABLE_FETCHLIMIT */
174 };
175 
176 /*
177  * XXXMLG  Document these structures.
178  */
179 
180 /*% dns_adbname structure */
181 struct dns_adbname {
182 	unsigned int                    magic;
183 	dns_name_t                      name;
184 	dns_adb_t                      *adb;
185 	unsigned int                    partial_result;
186 	unsigned int                    flags;
187 	int                             lock_bucket;
188 	dns_name_t                      target;
189 	isc_stdtime_t                   expire_target;
190 	isc_stdtime_t                   expire_v4;
191 	isc_stdtime_t                   expire_v6;
192 	unsigned int                    chains;
193 	dns_adbnamehooklist_t           v4;
194 	dns_adbnamehooklist_t           v6;
195 	dns_adbfetch_t                 *fetch_a;
196 	dns_adbfetch_t                 *fetch_aaaa;
197 	unsigned int                    fetch_err;
198 	unsigned int                    fetch6_err;
199 	dns_adbfindlist_t               finds;
200 	/* for LRU-based management */
201 	isc_stdtime_t                   last_used;
202 
203 	ISC_LINK(dns_adbname_t)         plink;
204 };
205 
206 /*% The adbfetch structure */
207 struct dns_adbfetch {
208 	unsigned int                    magic;
209 	dns_fetch_t                    *fetch;
210 	dns_rdataset_t                  rdataset;
211 	unsigned int			depth;
212 };
213 
214 /*%
215  * This is a small widget that dangles off a dns_adbname_t.  It contains a
216  * pointer to the address information about this host, and a link to the next
217  * namehook that will contain the next address this host has.
218  */
219 struct dns_adbnamehook {
220 	unsigned int                    magic;
221 	dns_adbentry_t                 *entry;
222 	ISC_LINK(dns_adbnamehook_t)     plink;
223 };
224 
225 /*%
226  * This is a small widget that holds qname-specific information about an
227  * address.  Currently limited to lameness, but could just as easily be
228  * extended to other types of information about zones.
229  */
230 struct dns_adblameinfo {
231 	unsigned int                    magic;
232 
233 	dns_name_t                      qname;
234 	dns_rdatatype_t                 qtype;
235 	isc_stdtime_t                   lame_timer;
236 
237 	ISC_LINK(dns_adblameinfo_t)     plink;
238 };
239 
240 /*%
241  * An address entry.  It holds quite a bit of information about addresses,
242  * including edns state (in "flags"), rtt, and of course the address of
243  * the host.
244  */
245 struct dns_adbentry {
246 	unsigned int                    magic;
247 
248 	int                             lock_bucket;
249 	unsigned int                    refcnt;
250 	unsigned int                    nh;
251 
252 	unsigned int                    flags;
253 	unsigned int                    srtt;
254 
255 	unsigned int                    timeouts;
256 	unsigned int			completed;
257 
258 #ifdef ENABLE_FETCHLIMIT
259 	isc_uint8_t			mode;
260 	isc_uint32_t			quota;
261 	isc_uint32_t			active;
262 	double				atr;
263 #endif /* ENABLE_FETCHLIMIT */
264 
265 	isc_sockaddr_t                  sockaddr;
266 
267 	isc_stdtime_t                   expires;
268 	isc_stdtime_t			lastage;
269 	/*%<
270 	 * A nonzero 'expires' field indicates that the entry should
271 	 * persist until that time.  This allows entries found
272 	 * using dns_adb_findaddrinfo() to persist for a limited time
273 	 * even though they are not necessarily associated with a
274 	 * name.
275 	 */
276 
277 	ISC_LIST(dns_adblameinfo_t)     lameinfo;
278 	ISC_LINK(dns_adbentry_t)        plink;
279 
280 };
281 
282 /*
283  * Internal functions (and prototypes).
284  */
285 static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
286 static inline void free_adbname(dns_adb_t *, dns_adbname_t **);
287 static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
288 						 dns_adbentry_t *);
289 static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
290 static inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *, dns_name_t *,
291 						 dns_rdatatype_t);
292 static inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **);
293 static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
294 static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
295 static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
296 static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
297 static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
298 						 in_port_t);
299 static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
300 static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
301 static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
302 						unsigned int, int *);
303 static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
304 						  isc_sockaddr_t *, int *,
305 						  isc_stdtime_t);
306 static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t);
307 static void print_dns_name(FILE *, dns_name_t *);
308 static void print_namehook_list(FILE *, const char *legend,
309 				dns_adb_t *adb,
310 				dns_adbnamehooklist_t *list,
311 				isc_boolean_t debug,
312 				isc_stdtime_t now);
313 static void print_find_list(FILE *, dns_adbname_t *);
314 static void print_fetch_list(FILE *, dns_adbname_t *);
315 static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
316 static inline void inc_adb_irefcnt(dns_adb_t *);
317 static inline void inc_adb_erefcnt(dns_adb_t *);
318 static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
319 				    isc_boolean_t);
320 static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, isc_boolean_t,
321 					     dns_adbentry_t *, isc_boolean_t);
322 static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
323 static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
324 static void clean_target(dns_adb_t *, dns_name_t *);
325 static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, unsigned int);
326 static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
327 static isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **,
328 					isc_stdtime_t);
329 static void cancel_fetches_at_name(dns_adbname_t *);
330 static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
331 				dns_rdatatype_t);
332 static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
333 			       unsigned int, isc_counter_t *qc,
334 			       dns_rdatatype_t);
335 static inline void check_exit(dns_adb_t *);
336 static void destroy(dns_adb_t *);
337 static isc_boolean_t shutdown_names(dns_adb_t *);
338 static isc_boolean_t shutdown_entries(dns_adb_t *);
339 static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
340 static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *);
341 static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
342 static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
343 static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
344 static void water(void *, int);
345 static void dump_entry(FILE *, dns_adb_t *, dns_adbentry_t *,
346 		       isc_boolean_t, isc_stdtime_t);
347 static void adjustsrtt(dns_adbaddrinfo_t *addr, unsigned int rtt,
348 		       unsigned int factor, isc_stdtime_t now);
349 static void shutdown_task(isc_task_t *task, isc_event_t *ev);
350 #ifdef ENABLE_FETCHLIMIT
351 static void log_quota(dns_adbentry_t *entry, const char *fmt, ...)
352      ISC_FORMAT_PRINTF(2, 3);
353 #endif /* ENABLE_FETCHLIMIT */
354 
355 /*
356  * MUST NOT overlap DNS_ADBFIND_* flags!
357  */
358 #define FIND_EVENT_SENT         0x40000000
359 #define FIND_EVENT_FREED        0x80000000
360 #define FIND_EVENTSENT(h)       (((h)->flags & FIND_EVENT_SENT) != 0)
361 #define FIND_EVENTFREED(h)      (((h)->flags & FIND_EVENT_FREED) != 0)
362 
363 #define NAME_NEEDS_POKE         0x80000000
364 #define NAME_IS_DEAD            0x40000000
365 #define NAME_HINT_OK            DNS_ADBFIND_HINTOK
366 #define NAME_GLUE_OK            DNS_ADBFIND_GLUEOK
367 #define NAME_STARTATZONE        DNS_ADBFIND_STARTATZONE
368 #define NAME_DEAD(n)            (((n)->flags & NAME_IS_DEAD) != 0)
369 #define NAME_NEEDSPOKE(n)       (((n)->flags & NAME_NEEDS_POKE) != 0)
370 #define NAME_GLUEOK(n)          (((n)->flags & NAME_GLUE_OK) != 0)
371 #define NAME_HINTOK(n)          (((n)->flags & NAME_HINT_OK) != 0)
372 
373 /*
374  * Private flag(s) for entries.
375  * MUST NOT overlap FCTX_ADDRINFO_xxx and DNS_FETCHOPT_NOEDNS0.
376  */
377 #define ENTRY_IS_DEAD		0x00400000
378 
379 /*
380  * To the name, address classes are all that really exist.  If it has a
381  * V6 address it doesn't care if it came from a AAAA query.
382  */
383 #define NAME_HAS_V4(n)          (!ISC_LIST_EMPTY((n)->v4))
384 #define NAME_HAS_V6(n)          (!ISC_LIST_EMPTY((n)->v6))
385 #define NAME_HAS_ADDRS(n)       (NAME_HAS_V4(n) || NAME_HAS_V6(n))
386 
387 /*
388  * Fetches are broken out into A and AAAA types.  In some cases,
389  * however, it makes more sense to test for a particular class of fetches,
390  * like V4 or V6 above.
391  * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA
392  * are now equal to FETCH_V4 and FETCH_V6, respectively.
393  */
394 #define NAME_FETCH_A(n)         ((n)->fetch_a != NULL)
395 #define NAME_FETCH_AAAA(n)      ((n)->fetch_aaaa != NULL)
396 #define NAME_FETCH_V4(n)        (NAME_FETCH_A(n))
397 #define NAME_FETCH_V6(n)        (NAME_FETCH_AAAA(n))
398 #define NAME_FETCH(n)           (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
399 
400 /*
401  * Find options and tests to see if there are addresses on the list.
402  */
403 #define FIND_WANTEVENT(fn)      (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
404 #define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
405 #define FIND_AVOIDFETCHES(fn)   (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
406 				 != 0)
407 #define FIND_STARTATZONE(fn)    (((fn)->options & DNS_ADBFIND_STARTATZONE) \
408 				 != 0)
409 #define FIND_HINTOK(fn)         (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
410 #define FIND_GLUEOK(fn)         (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
411 #define FIND_HAS_ADDRS(fn)      (!ISC_LIST_EMPTY((fn)->list))
412 #define FIND_RETURNLAME(fn)     (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
413 
414 /*
415  * These are currently used on simple unsigned ints, so they are
416  * not really associated with any particular type.
417  */
418 #define WANT_INET(x)            (((x) & DNS_ADBFIND_INET) != 0)
419 #define WANT_INET6(x)           (((x) & DNS_ADBFIND_INET6) != 0)
420 
421 #define EXPIRE_OK(exp, now)     ((exp == INT_MAX) || (exp < now))
422 
423 /*
424  * Find out if the flags on a name (nf) indicate if it is a hint or
425  * glue, and compare this to the appropriate bits set in o, to see if
426  * this is ok.
427  */
428 #define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0))
429 #define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0))
430 #define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o))
431 #define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \
432 				    ((o) & DNS_ADBFIND_STARTATZONE))
433 
434 #define ENTER_LEVEL             ISC_LOG_DEBUG(50)
435 #define EXIT_LEVEL              ENTER_LEVEL
436 #define CLEAN_LEVEL             ISC_LOG_DEBUG(100)
437 #define DEF_LEVEL               ISC_LOG_DEBUG(5)
438 #define NCACHE_LEVEL            ISC_LOG_DEBUG(20)
439 
440 #define NCACHE_RESULT(r)        ((r) == DNS_R_NCACHENXDOMAIN || \
441 				 (r) == DNS_R_NCACHENXRRSET)
442 #define AUTH_NX(r)              ((r) == DNS_R_NXDOMAIN || \
443 				 (r) == DNS_R_NXRRSET)
444 #define NXDOMAIN_RESULT(r)      ((r) == DNS_R_NXDOMAIN || \
445 				 (r) == DNS_R_NCACHENXDOMAIN)
446 #define NXRRSET_RESULT(r)       ((r) == DNS_R_NCACHENXRRSET || \
447 				 (r) == DNS_R_NXRRSET || \
448 				 (r) == DNS_R_HINTNXRRSET)
449 
450 /*
451  * Error state rankings.
452  */
453 
454 #define FIND_ERR_SUCCESS                0  /* highest rank */
455 #define FIND_ERR_CANCELED               1
456 #define FIND_ERR_FAILURE                2
457 #define FIND_ERR_NXDOMAIN               3
458 #define FIND_ERR_NXRRSET                4
459 #define FIND_ERR_UNEXPECTED             5
460 #define FIND_ERR_NOTFOUND               6
461 #define FIND_ERR_MAX                    7
462 
463 static const char *errnames[] = {
464 	"success",
465 	"canceled",
466 	"failure",
467 	"nxdomain",
468 	"nxrrset",
469 	"unexpected",
470 	"not_found"
471 };
472 
473 #define NEWERR(old, new)        (ISC_MIN((old), (new)))
474 
475 static isc_result_t find_err_map[FIND_ERR_MAX] = {
476 	ISC_R_SUCCESS,
477 	ISC_R_CANCELED,
478 	ISC_R_FAILURE,
479 	DNS_R_NXDOMAIN,
480 	DNS_R_NXRRSET,
481 	ISC_R_UNEXPECTED,
482 	ISC_R_NOTFOUND          /* not YET found */
483 };
484 
485 static void
486 DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
487 
488 static void
DP(int level,const char * format,...)489 DP(int level, const char *format, ...) {
490 	va_list args;
491 
492 	va_start(args, format);
493 	isc_log_vwrite(dns_lctx,
494 		       DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
495 		       level, format, args);
496 	va_end(args);
497 }
498 
499 /*%
500  * Increment resolver-related statistics counters.
501  */
502 static inline void
inc_stats(dns_adb_t * adb,isc_statscounter_t counter)503 inc_stats(dns_adb_t *adb, isc_statscounter_t counter) {
504 	if (adb->view->resstats != NULL)
505 		isc_stats_increment(adb->view->resstats, counter);
506 }
507 
508 static inline dns_ttl_t
ttlclamp(dns_ttl_t ttl)509 ttlclamp(dns_ttl_t ttl) {
510 	if (ttl < ADB_CACHE_MINIMUM)
511 		ttl = ADB_CACHE_MINIMUM;
512 	if (ttl > ADB_CACHE_MAXIMUM)
513 		ttl = ADB_CACHE_MAXIMUM;
514 
515 	return (ttl);
516 }
517 
518 /*
519  * Hashing is most efficient if the number of buckets is prime.
520  * The sequence below is the closest previous primes to 2^n and
521  * 1.5 * 2^n, for values of n from 10 to 28.  (The tables will
522  * no longer grow beyond 2^28 entries.)
523  */
524 static const unsigned nbuckets[] = { 1021, 1531, 2039, 3067, 4093, 6143,
525 				     8191, 12281, 16381, 24571, 32749,
526 				     49193, 65521, 98299, 131071, 199603,
527 				     262139, 393209, 524287, 768431, 1048573,
528 				     1572853, 2097143, 3145721, 4194301,
529 				     6291449, 8388593, 12582893, 16777213,
530 				     25165813, 33554393, 50331599, 67108859,
531 				     100663291, 134217689, 201326557,
532 				     268535431, 0 };
533 
534 static void
grow_entries(isc_task_t * task,isc_event_t * ev)535 grow_entries(isc_task_t *task, isc_event_t *ev) {
536 	dns_adb_t *adb;
537 	dns_adbentry_t *e;
538 	dns_adbentrylist_t *newdeadentries = NULL;
539 	dns_adbentrylist_t *newentries = NULL;
540 	isc_boolean_t *newentry_sd = NULL;
541 	isc_mutex_t *newentrylocks = NULL;
542 	isc_result_t result;
543 	unsigned int *newentry_refcnt = NULL;
544 	unsigned int i, n, bucket;
545 
546 	adb = ev->ev_arg;
547 	INSIST(DNS_ADB_VALID(adb));
548 
549 	isc_event_free(&ev);
550 
551 	result = isc_task_beginexclusive(task);
552 	if (result != ISC_R_SUCCESS)
553 		goto check_exit;
554 
555 	i = 0;
556 	while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i])
557 		i++;
558 	if (nbuckets[i] != 0)
559 		n = nbuckets[i];
560 	else
561 		goto done;
562 
563 	DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n);
564 
565 	/*
566 	 * Are we shutting down?
567 	 */
568 	for (i = 0; i < adb->nentries; i++)
569 		if (adb->entry_sd[i])
570 			goto cleanup;
571 
572 	/*
573 	 * Grab all the resources we need.
574 	 */
575 	newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n);
576 	newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n);
577 	newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n);
578 	newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n);
579 	newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n);
580 	if (newentries == NULL || newdeadentries == NULL ||
581 	    newentrylocks == NULL || newentry_sd == NULL ||
582 	    newentry_refcnt == NULL)
583 		goto cleanup;
584 
585 	/*
586 	 * Initialise the new resources.
587 	 */
588 	result = isc_mutexblock_init(newentrylocks, n);
589 	if (result != ISC_R_SUCCESS)
590 		goto cleanup;
591 
592 	for (i = 0; i < n; i++) {
593 		ISC_LIST_INIT(newentries[i]);
594 		ISC_LIST_INIT(newdeadentries[i]);
595 		newentry_sd[i] = ISC_FALSE;
596 		newentry_refcnt[i] = 0;
597 		adb->irefcnt++;
598 	}
599 
600 	/*
601 	 * Move entries to new arrays.
602 	 */
603 	for (i = 0; i < adb->nentries; i++) {
604 		e = ISC_LIST_HEAD(adb->entries[i]);
605 		while (e != NULL) {
606 			ISC_LIST_UNLINK(adb->entries[i], e, plink);
607 			bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
608 			e->lock_bucket = bucket;
609 			ISC_LIST_APPEND(newentries[bucket], e, plink);
610 			INSIST(adb->entry_refcnt[i] > 0);
611 			adb->entry_refcnt[i]--;
612 			newentry_refcnt[bucket]++;
613 			e = ISC_LIST_HEAD(adb->entries[i]);
614 		}
615 		e = ISC_LIST_HEAD(adb->deadentries[i]);
616 		while (e != NULL) {
617 			ISC_LIST_UNLINK(adb->deadentries[i], e, plink);
618 			bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
619 			e->lock_bucket = bucket;
620 			ISC_LIST_APPEND(newdeadentries[bucket], e, plink);
621 			INSIST(adb->entry_refcnt[i] > 0);
622 			adb->entry_refcnt[i]--;
623 			newentry_refcnt[bucket]++;
624 			e = ISC_LIST_HEAD(adb->deadentries[i]);
625 		}
626 		INSIST(adb->entry_refcnt[i] == 0);
627 		adb->irefcnt--;
628 	}
629 
630 	/*
631 	 * Cleanup old resources.
632 	 */
633 	DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
634 	isc_mem_put(adb->mctx, adb->entries,
635 		    sizeof(*adb->entries) * adb->nentries);
636 	isc_mem_put(adb->mctx, adb->deadentries,
637 		    sizeof(*adb->deadentries) * adb->nentries);
638 	isc_mem_put(adb->mctx, adb->entrylocks,
639 		    sizeof(*adb->entrylocks) * adb->nentries);
640 	isc_mem_put(adb->mctx, adb->entry_sd,
641 		    sizeof(*adb->entry_sd) * adb->nentries);
642 	isc_mem_put(adb->mctx, adb->entry_refcnt,
643 		    sizeof(*adb->entry_refcnt) * adb->nentries);
644 
645 	/*
646 	 * Install new resources.
647 	 */
648 	adb->entries = newentries;
649 	adb->deadentries = newdeadentries;
650 	adb->entrylocks = newentrylocks;
651 	adb->entry_sd = newentry_sd;
652 	adb->entry_refcnt = newentry_refcnt;
653 	adb->nentries = n;
654 
655 	/*
656 	 * Only on success do we set adb->growentries_sent to ISC_FALSE.
657 	 * This will prevent us being continuously being called on error.
658 	 */
659 	adb->growentries_sent = ISC_FALSE;
660 	goto done;
661 
662  cleanup:
663 	if (newentries != NULL)
664 		isc_mem_put(adb->mctx, newentries,
665 			    sizeof(*newentries) * n);
666 	if (newdeadentries != NULL)
667 		isc_mem_put(adb->mctx, newdeadentries,
668 			    sizeof(*newdeadentries) * n);
669 	if (newentrylocks != NULL)
670 		isc_mem_put(adb->mctx, newentrylocks,
671 			    sizeof(*newentrylocks) * n);
672 	if (newentry_sd != NULL)
673 		isc_mem_put(adb->mctx, newentry_sd,
674 			    sizeof(*newentry_sd) * n);
675 	if (newentry_refcnt != NULL)
676 		isc_mem_put(adb->mctx, newentry_refcnt,
677 			     sizeof(*newentry_refcnt) * n);
678  done:
679 	isc_task_endexclusive(task);
680 
681  check_exit:
682 	LOCK(&adb->lock);
683 	if (dec_adb_irefcnt(adb))
684 		check_exit(adb);
685 	UNLOCK(&adb->lock);
686 	DP(ISC_LOG_INFO, "adb: grow_entries finished");
687 }
688 
689 static void
grow_names(isc_task_t * task,isc_event_t * ev)690 grow_names(isc_task_t *task, isc_event_t *ev) {
691 	dns_adb_t *adb;
692 	dns_adbname_t *name;
693 	dns_adbnamelist_t *newdeadnames = NULL;
694 	dns_adbnamelist_t *newnames = NULL;
695 	isc_boolean_t *newname_sd = NULL;
696 	isc_mutex_t *newnamelocks = NULL;
697 	isc_result_t result;
698 	unsigned int *newname_refcnt = NULL;
699 	unsigned int i, n, bucket;
700 
701 	adb = ev->ev_arg;
702 	INSIST(DNS_ADB_VALID(adb));
703 
704 	isc_event_free(&ev);
705 
706 	result = isc_task_beginexclusive(task);
707 	if (result != ISC_R_SUCCESS)
708 		goto check_exit;
709 
710 	i = 0;
711 	while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i])
712 		i++;
713 	if (nbuckets[i] != 0)
714 		n = nbuckets[i];
715 	else
716 		goto done;
717 
718 	DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n);
719 
720 	/*
721 	 * Are we shutting down?
722 	 */
723 	for (i = 0; i < adb->nnames; i++)
724 		if (adb->name_sd[i])
725 			goto cleanup;
726 
727 	/*
728 	 * Grab all the resources we need.
729 	 */
730 	newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n);
731 	newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n);
732 	newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n);
733 	newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n);
734 	newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n);
735 	if (newnames == NULL || newdeadnames == NULL ||
736 	    newnamelocks == NULL || newname_sd == NULL ||
737 	    newname_refcnt == NULL)
738 		goto cleanup;
739 
740 	/*
741 	 * Initialise the new resources.
742 	 */
743 	result = isc_mutexblock_init(newnamelocks, n);
744 	if (result != ISC_R_SUCCESS)
745 		goto cleanup;
746 
747 	for (i = 0; i < n; i++) {
748 		ISC_LIST_INIT(newnames[i]);
749 		ISC_LIST_INIT(newdeadnames[i]);
750 		newname_sd[i] = ISC_FALSE;
751 		newname_refcnt[i] = 0;
752 		adb->irefcnt++;
753 	}
754 
755 	/*
756 	 * Move names to new arrays.
757 	 */
758 	for (i = 0; i < adb->nnames; i++) {
759 		name = ISC_LIST_HEAD(adb->names[i]);
760 		while (name != NULL) {
761 			ISC_LIST_UNLINK(adb->names[i], name, plink);
762 			bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
763 			name->lock_bucket = bucket;
764 			ISC_LIST_APPEND(newnames[bucket], name, plink);
765 			INSIST(adb->name_refcnt[i] > 0);
766 			adb->name_refcnt[i]--;
767 			newname_refcnt[bucket]++;
768 			name = ISC_LIST_HEAD(adb->names[i]);
769 		}
770 		name = ISC_LIST_HEAD(adb->deadnames[i]);
771 		while (name != NULL) {
772 			ISC_LIST_UNLINK(adb->deadnames[i], name, plink);
773 			bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
774 			name->lock_bucket = bucket;
775 			ISC_LIST_APPEND(newdeadnames[bucket], name, plink);
776 			INSIST(adb->name_refcnt[i] > 0);
777 			adb->name_refcnt[i]--;
778 			newname_refcnt[bucket]++;
779 			name = ISC_LIST_HEAD(adb->deadnames[i]);
780 		}
781 		INSIST(adb->name_refcnt[i] == 0);
782 		adb->irefcnt--;
783 	}
784 
785 	/*
786 	 * Cleanup old resources.
787 	 */
788 	DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
789 	isc_mem_put(adb->mctx, adb->names,
790 		    sizeof(*adb->names) * adb->nnames);
791 	isc_mem_put(adb->mctx, adb->deadnames,
792 		    sizeof(*adb->deadnames) * adb->nnames);
793 	isc_mem_put(adb->mctx, adb->namelocks,
794 		    sizeof(*adb->namelocks) * adb->nnames);
795 	isc_mem_put(adb->mctx, adb->name_sd,
796 		    sizeof(*adb->name_sd) * adb->nnames);
797 	isc_mem_put(adb->mctx, adb->name_refcnt,
798 		    sizeof(*adb->name_refcnt) * adb->nnames);
799 
800 	/*
801 	 * Install new resources.
802 	 */
803 	adb->names = newnames;
804 	adb->deadnames = newdeadnames;
805 	adb->namelocks = newnamelocks;
806 	adb->name_sd = newname_sd;
807 	adb->name_refcnt = newname_refcnt;
808 	adb->nnames = n;
809 
810 	/*
811 	 * Only on success do we set adb->grownames_sent to ISC_FALSE.
812 	 * This will prevent us being continuously being called on error.
813 	 */
814 	adb->grownames_sent = ISC_FALSE;
815 	goto done;
816 
817  cleanup:
818 	if (newnames != NULL)
819 		isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n);
820 	if (newdeadnames != NULL)
821 		isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n);
822 	if (newnamelocks != NULL)
823 		isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n);
824 	if (newname_sd != NULL)
825 		isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n);
826 	if (newname_refcnt != NULL)
827 		isc_mem_put(adb->mctx, newname_refcnt,
828 			     sizeof(*newname_refcnt) * n);
829  done:
830 	isc_task_endexclusive(task);
831 
832  check_exit:
833 	LOCK(&adb->lock);
834 	if (dec_adb_irefcnt(adb))
835 		check_exit(adb);
836 	UNLOCK(&adb->lock);
837 	DP(ISC_LOG_INFO, "adb: grow_names finished");
838 }
839 
840 /*
841  * Requires the adbname bucket be locked and that no entry buckets be locked.
842  *
843  * This code handles A and AAAA rdatasets only.
844  */
845 static isc_result_t
import_rdataset(dns_adbname_t * adbname,dns_rdataset_t * rdataset,isc_stdtime_t now)846 import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
847 		isc_stdtime_t now)
848 {
849 	isc_result_t result;
850 	dns_adb_t *adb;
851 	dns_adbnamehook_t *nh;
852 	dns_adbnamehook_t *anh;
853 	dns_rdata_t rdata = DNS_RDATA_INIT;
854 	struct in_addr ina;
855 	struct in6_addr in6a;
856 	isc_sockaddr_t sockaddr;
857 	dns_adbentry_t *foundentry;  /* NO CLEAN UP! */
858 	int addr_bucket;
859 	isc_boolean_t new_addresses_added;
860 	dns_rdatatype_t rdtype;
861 	unsigned int findoptions;
862 	dns_adbnamehooklist_t *hookhead;
863 
864 	INSIST(DNS_ADBNAME_VALID(adbname));
865 	adb = adbname->adb;
866 	INSIST(DNS_ADB_VALID(adb));
867 
868 	rdtype = rdataset->type;
869 	INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
870 	if (rdtype == dns_rdatatype_a)
871 		findoptions = DNS_ADBFIND_INET;
872 	else
873 		findoptions = DNS_ADBFIND_INET6;
874 
875 	addr_bucket = DNS_ADB_INVALIDBUCKET;
876 	new_addresses_added = ISC_FALSE;
877 
878 	nh = NULL;
879 	result = dns_rdataset_first(rdataset);
880 	while (result == ISC_R_SUCCESS) {
881 		dns_rdata_reset(&rdata);
882 		dns_rdataset_current(rdataset, &rdata);
883 		if (rdtype == dns_rdatatype_a) {
884 			INSIST(rdata.length == 4);
885 			memmove(&ina.s_addr, rdata.data, 4);
886 			isc_sockaddr_fromin(&sockaddr, &ina, 0);
887 			hookhead = &adbname->v4;
888 		} else {
889 			INSIST(rdata.length == 16);
890 			memmove(in6a.s6_addr, rdata.data, 16);
891 			isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
892 			hookhead = &adbname->v6;
893 		}
894 
895 		INSIST(nh == NULL);
896 		nh = new_adbnamehook(adb, NULL);
897 		if (nh == NULL) {
898 			adbname->partial_result |= findoptions;
899 			result = ISC_R_NOMEMORY;
900 			goto fail;
901 		}
902 
903 		foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket,
904 						 now);
905 		if (foundentry == NULL) {
906 			dns_adbentry_t *entry;
907 
908 			entry = new_adbentry(adb);
909 			if (entry == NULL) {
910 				adbname->partial_result |= findoptions;
911 				result = ISC_R_NOMEMORY;
912 				goto fail;
913 			}
914 
915 			entry->sockaddr = sockaddr;
916 			entry->refcnt = 1;
917 			entry->nh = 1;
918 
919 			nh->entry = entry;
920 
921 			link_entry(adb, addr_bucket, entry);
922 		} else {
923 			for (anh = ISC_LIST_HEAD(*hookhead);
924 			     anh != NULL;
925 			     anh = ISC_LIST_NEXT(anh, plink))
926 				if (anh->entry == foundentry)
927 					break;
928 			if (anh == NULL) {
929 				foundentry->refcnt++;
930 				foundentry->nh++;
931 				nh->entry = foundentry;
932 			} else
933 				free_adbnamehook(adb, &nh);
934 		}
935 
936 		new_addresses_added = ISC_TRUE;
937 		if (nh != NULL)
938 			ISC_LIST_APPEND(*hookhead, nh, plink);
939 		nh = NULL;
940 		result = dns_rdataset_next(rdataset);
941 	}
942 
943  fail:
944 	if (nh != NULL)
945 		free_adbnamehook(adb, &nh);
946 
947 	if (addr_bucket != DNS_ADB_INVALIDBUCKET)
948 		UNLOCK(&adb->entrylocks[addr_bucket]);
949 
950 	if (rdataset->trust == dns_trust_glue ||
951 	    rdataset->trust == dns_trust_additional)
952 		rdataset->ttl = ADB_CACHE_MINIMUM;
953 	else if (rdataset->trust == dns_trust_ultimate)
954 		rdataset->ttl = 0;
955 	else
956 		rdataset->ttl = ttlclamp(rdataset->ttl);
957 
958 	if (rdtype == dns_rdatatype_a) {
959 		DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
960 		   adbname->expire_v4, now + rdataset->ttl);
961 		adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
962 					     now + rdataset->ttl);
963 	} else {
964 		DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
965 		   adbname->expire_v6, now + rdataset->ttl);
966 		adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
967 					     now + rdataset->ttl);
968 	}
969 
970 	if (new_addresses_added) {
971 		/*
972 		 * Lie a little here.  This is more or less so code that cares
973 		 * can find out if any new information was added or not.
974 		 */
975 		return (ISC_R_SUCCESS);
976 	}
977 
978 	return (result);
979 }
980 
981 /*
982  * Requires the name's bucket be locked.
983  */
984 static isc_boolean_t
kill_name(dns_adbname_t ** n,isc_eventtype_t ev)985 kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
986 	dns_adbname_t *name;
987 	isc_boolean_t result = ISC_FALSE;
988 	isc_boolean_t result4, result6;
989 	int bucket;
990 	dns_adb_t *adb;
991 
992 	INSIST(n != NULL);
993 	name = *n;
994 	*n = NULL;
995 	INSIST(DNS_ADBNAME_VALID(name));
996 	adb = name->adb;
997 	INSIST(DNS_ADB_VALID(adb));
998 
999 	DP(DEF_LEVEL, "killing name %p", name);
1000 
1001 	/*
1002 	 * If we're dead already, just check to see if we should go
1003 	 * away now or not.
1004 	 */
1005 	if (NAME_DEAD(name) && !NAME_FETCH(name)) {
1006 		result = unlink_name(adb, name);
1007 		free_adbname(adb, &name);
1008 		if (result)
1009 			result = dec_adb_irefcnt(adb);
1010 		return (result);
1011 	}
1012 
1013 	/*
1014 	 * Clean up the name's various lists.  These two are destructive
1015 	 * in that they will always empty the list.
1016 	 */
1017 	clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
1018 	result4 = clean_namehooks(adb, &name->v4);
1019 	result6 = clean_namehooks(adb, &name->v6);
1020 	clean_target(adb, &name->target);
1021 	result = ISC_TF(result4 || result6);
1022 
1023 	/*
1024 	 * If fetches are running, cancel them.  If none are running, we can
1025 	 * just kill the name here.
1026 	 */
1027 	if (!NAME_FETCH(name)) {
1028 		INSIST(result == ISC_FALSE);
1029 		result = unlink_name(adb, name);
1030 		free_adbname(adb, &name);
1031 		if (result)
1032 			result = dec_adb_irefcnt(adb);
1033 	} else {
1034 		cancel_fetches_at_name(name);
1035 		if (!NAME_DEAD(name)) {
1036 			bucket = name->lock_bucket;
1037 			ISC_LIST_UNLINK(adb->names[bucket], name, plink);
1038 			ISC_LIST_APPEND(adb->deadnames[bucket], name, plink);
1039 			name->flags |= NAME_IS_DEAD;
1040 		}
1041 	}
1042 	return (result);
1043 }
1044 
1045 /*
1046  * Requires the name's bucket be locked and no entry buckets be locked.
1047  */
1048 static isc_boolean_t
check_expire_namehooks(dns_adbname_t * name,isc_stdtime_t now)1049 check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
1050 	dns_adb_t *adb;
1051 	isc_boolean_t result4 = ISC_FALSE;
1052 	isc_boolean_t result6 = ISC_FALSE;
1053 
1054 	INSIST(DNS_ADBNAME_VALID(name));
1055 	adb = name->adb;
1056 	INSIST(DNS_ADB_VALID(adb));
1057 
1058 	/*
1059 	 * Check to see if we need to remove the v4 addresses
1060 	 */
1061 	if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) {
1062 		if (NAME_HAS_V4(name)) {
1063 			DP(DEF_LEVEL, "expiring v4 for name %p", name);
1064 			result4 = clean_namehooks(adb, &name->v4);
1065 			name->partial_result &= ~DNS_ADBFIND_INET;
1066 		}
1067 		name->expire_v4 = INT_MAX;
1068 		name->fetch_err = FIND_ERR_UNEXPECTED;
1069 	}
1070 
1071 	/*
1072 	 * Check to see if we need to remove the v6 addresses
1073 	 */
1074 	if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) {
1075 		if (NAME_HAS_V6(name)) {
1076 			DP(DEF_LEVEL, "expiring v6 for name %p", name);
1077 			result6 = clean_namehooks(adb, &name->v6);
1078 			name->partial_result &= ~DNS_ADBFIND_INET6;
1079 		}
1080 		name->expire_v6 = INT_MAX;
1081 		name->fetch6_err = FIND_ERR_UNEXPECTED;
1082 	}
1083 
1084 	/*
1085 	 * Check to see if we need to remove the alias target.
1086 	 */
1087 	if (EXPIRE_OK(name->expire_target, now)) {
1088 		clean_target(adb, &name->target);
1089 		name->expire_target = INT_MAX;
1090 	}
1091 	return (ISC_TF(result4 || result6));
1092 }
1093 
1094 /*
1095  * Requires the name's bucket be locked.
1096  */
1097 static inline void
link_name(dns_adb_t * adb,int bucket,dns_adbname_t * name)1098 link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
1099 	INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
1100 
1101 	ISC_LIST_PREPEND(adb->names[bucket], name, plink);
1102 	name->lock_bucket = bucket;
1103 	adb->name_refcnt[bucket]++;
1104 }
1105 
1106 /*
1107  * Requires the name's bucket be locked.
1108  */
1109 static inline isc_boolean_t
unlink_name(dns_adb_t * adb,dns_adbname_t * name)1110 unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
1111 	int bucket;
1112 	isc_boolean_t result = ISC_FALSE;
1113 
1114 	bucket = name->lock_bucket;
1115 	INSIST(bucket != DNS_ADB_INVALIDBUCKET);
1116 
1117 	if (NAME_DEAD(name))
1118 		ISC_LIST_UNLINK(adb->deadnames[bucket], name, plink);
1119 	else
1120 		ISC_LIST_UNLINK(adb->names[bucket], name, plink);
1121 	name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1122 	INSIST(adb->name_refcnt[bucket] > 0);
1123 	adb->name_refcnt[bucket]--;
1124 	if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
1125 		result = ISC_TRUE;
1126 	return (result);
1127 }
1128 
1129 /*
1130  * Requires the entry's bucket be locked.
1131  */
1132 static inline void
link_entry(dns_adb_t * adb,int bucket,dns_adbentry_t * entry)1133 link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
1134 	int i;
1135 	dns_adbentry_t *e;
1136 
1137 	if (isc_mem_isovermem(adb->mctx)) {
1138 		for (i = 0; i < 2; i++) {
1139 			e = ISC_LIST_TAIL(adb->entries[bucket]);
1140 			if (e == NULL)
1141 				break;
1142 			if (e->refcnt == 0) {
1143 				unlink_entry(adb, e);
1144 				free_adbentry(adb, &e);
1145 				continue;
1146 			}
1147 			INSIST((e->flags & ENTRY_IS_DEAD) == 0);
1148 			e->flags |= ENTRY_IS_DEAD;
1149 			ISC_LIST_UNLINK(adb->entries[bucket], e, plink);
1150 			ISC_LIST_PREPEND(adb->deadentries[bucket], e, plink);
1151 		}
1152 	}
1153 
1154 	ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
1155 	entry->lock_bucket = bucket;
1156 	adb->entry_refcnt[bucket]++;
1157 }
1158 
1159 /*
1160  * Requires the entry's bucket be locked.
1161  */
1162 static inline isc_boolean_t
unlink_entry(dns_adb_t * adb,dns_adbentry_t * entry)1163 unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
1164 	int bucket;
1165 	isc_boolean_t result = ISC_FALSE;
1166 
1167 	bucket = entry->lock_bucket;
1168 	INSIST(bucket != DNS_ADB_INVALIDBUCKET);
1169 
1170 	if ((entry->flags & ENTRY_IS_DEAD) != 0)
1171 		ISC_LIST_UNLINK(adb->deadentries[bucket], entry, plink);
1172 	else
1173 		ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
1174 	entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1175 	INSIST(adb->entry_refcnt[bucket] > 0);
1176 	adb->entry_refcnt[bucket]--;
1177 	if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
1178 		result = ISC_TRUE;
1179 	return (result);
1180 }
1181 
1182 static inline void
violate_locking_hierarchy(isc_mutex_t * have,isc_mutex_t * want)1183 violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
1184 	if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
1185 		UNLOCK(have);
1186 		LOCK(want);
1187 		LOCK(have);
1188 	}
1189 }
1190 
1191 /*
1192  * The ADB _MUST_ be locked before calling.  Also, exit conditions must be
1193  * checked after calling this function.
1194  */
1195 static isc_boolean_t
shutdown_names(dns_adb_t * adb)1196 shutdown_names(dns_adb_t *adb) {
1197 	unsigned int bucket;
1198 	isc_boolean_t result = ISC_FALSE;
1199 	dns_adbname_t *name;
1200 	dns_adbname_t *next_name;
1201 
1202 	for (bucket = 0; bucket < adb->nnames; bucket++) {
1203 		LOCK(&adb->namelocks[bucket]);
1204 		adb->name_sd[bucket] = ISC_TRUE;
1205 
1206 		name = ISC_LIST_HEAD(adb->names[bucket]);
1207 		if (name == NULL) {
1208 			/*
1209 			 * This bucket has no names.  We must decrement the
1210 			 * irefcnt ourselves, since it will not be
1211 			 * automatically triggered by a name being unlinked.
1212 			 */
1213 			INSIST(result == ISC_FALSE);
1214 			result = dec_adb_irefcnt(adb);
1215 		} else {
1216 			/*
1217 			 * Run through the list.  For each name, clean up finds
1218 			 * found there, and cancel any fetches running.  When
1219 			 * all the fetches are canceled, the name will destroy
1220 			 * itself.
1221 			 */
1222 			while (name != NULL) {
1223 				next_name = ISC_LIST_NEXT(name, plink);
1224 				INSIST(result == ISC_FALSE);
1225 				result = kill_name(&name,
1226 						   DNS_EVENT_ADBSHUTDOWN);
1227 				name = next_name;
1228 			}
1229 		}
1230 
1231 		UNLOCK(&adb->namelocks[bucket]);
1232 	}
1233 	return (result);
1234 }
1235 
1236 /*
1237  * The ADB _MUST_ be locked before calling.  Also, exit conditions must be
1238  * checked after calling this function.
1239  */
1240 static isc_boolean_t
shutdown_entries(dns_adb_t * adb)1241 shutdown_entries(dns_adb_t *adb) {
1242 	unsigned int bucket;
1243 	isc_boolean_t result = ISC_FALSE;
1244 	dns_adbentry_t *entry;
1245 	dns_adbentry_t *next_entry;
1246 
1247 	for (bucket = 0; bucket < adb->nentries; bucket++) {
1248 		LOCK(&adb->entrylocks[bucket]);
1249 		adb->entry_sd[bucket] = ISC_TRUE;
1250 
1251 		entry = ISC_LIST_HEAD(adb->entries[bucket]);
1252 		if (adb->entry_refcnt[bucket] == 0) {
1253 			/*
1254 			 * This bucket has no entries.  We must decrement the
1255 			 * irefcnt ourselves, since it will not be
1256 			 * automatically triggered by an entry being unlinked.
1257 			 */
1258 			result = dec_adb_irefcnt(adb);
1259 		} else {
1260 			/*
1261 			 * Run through the list.  Cleanup any entries not
1262 			 * associated with names, and which are not in use.
1263 			 */
1264 			while (entry != NULL) {
1265 				next_entry = ISC_LIST_NEXT(entry, plink);
1266 				if (entry->refcnt == 0 &&
1267 				    entry->expires != 0) {
1268 					result = unlink_entry(adb, entry);
1269 					free_adbentry(adb, &entry);
1270 					if (result)
1271 						result = dec_adb_irefcnt(adb);
1272 				}
1273 				entry = next_entry;
1274 			}
1275 		}
1276 
1277 		UNLOCK(&adb->entrylocks[bucket]);
1278 	}
1279 	return (result);
1280 }
1281 
1282 /*
1283  * Name bucket must be locked
1284  */
1285 static void
cancel_fetches_at_name(dns_adbname_t * name)1286 cancel_fetches_at_name(dns_adbname_t *name) {
1287 	if (NAME_FETCH_A(name))
1288 	    dns_resolver_cancelfetch(name->fetch_a->fetch);
1289 
1290 	if (NAME_FETCH_AAAA(name))
1291 	    dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
1292 }
1293 
1294 /*
1295  * Assumes the name bucket is locked.
1296  */
1297 static isc_boolean_t
clean_namehooks(dns_adb_t * adb,dns_adbnamehooklist_t * namehooks)1298 clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
1299 	dns_adbentry_t *entry;
1300 	dns_adbnamehook_t *namehook;
1301 	int addr_bucket;
1302 	isc_boolean_t result = ISC_FALSE;
1303 	isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
1304 
1305 	addr_bucket = DNS_ADB_INVALIDBUCKET;
1306 	namehook = ISC_LIST_HEAD(*namehooks);
1307 	while (namehook != NULL) {
1308 		INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
1309 
1310 		/*
1311 		 * Clean up the entry if needed.
1312 		 */
1313 		entry = namehook->entry;
1314 		if (entry != NULL) {
1315 			INSIST(DNS_ADBENTRY_VALID(entry));
1316 
1317 			if (addr_bucket != entry->lock_bucket) {
1318 				if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1319 					UNLOCK(&adb->entrylocks[addr_bucket]);
1320 				addr_bucket = entry->lock_bucket;
1321 				INSIST(addr_bucket != DNS_ADB_INVALIDBUCKET);
1322 				LOCK(&adb->entrylocks[addr_bucket]);
1323 			}
1324 
1325 			entry->nh--;
1326 			result = dec_entry_refcnt(adb, overmem, entry,
1327 						  ISC_FALSE);
1328 		}
1329 
1330 		/*
1331 		 * Free the namehook
1332 		 */
1333 		namehook->entry = NULL;
1334 		ISC_LIST_UNLINK(*namehooks, namehook, plink);
1335 		free_adbnamehook(adb, &namehook);
1336 
1337 		namehook = ISC_LIST_HEAD(*namehooks);
1338 	}
1339 
1340 	if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1341 		UNLOCK(&adb->entrylocks[addr_bucket]);
1342 	return (result);
1343 }
1344 
1345 static void
clean_target(dns_adb_t * adb,dns_name_t * target)1346 clean_target(dns_adb_t *adb, dns_name_t *target) {
1347 	if (dns_name_countlabels(target) > 0) {
1348 		dns_name_free(target, adb->mctx);
1349 		dns_name_init(target, NULL);
1350 	}
1351 }
1352 
1353 static isc_result_t
set_target(dns_adb_t * adb,dns_name_t * name,dns_name_t * fname,dns_rdataset_t * rdataset,dns_name_t * target)1354 set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
1355 	   dns_rdataset_t *rdataset, dns_name_t *target)
1356 {
1357 	isc_result_t result;
1358 	dns_namereln_t namereln;
1359 	unsigned int nlabels;
1360 	int order;
1361 	dns_rdata_t rdata = DNS_RDATA_INIT;
1362 	dns_fixedname_t fixed1, fixed2;
1363 	dns_name_t *prefix, *new_target;
1364 
1365 	REQUIRE(dns_name_countlabels(target) == 0);
1366 
1367 	if (rdataset->type == dns_rdatatype_cname) {
1368 		dns_rdata_cname_t cname;
1369 
1370 		/*
1371 		 * Copy the CNAME's target into the target name.
1372 		 */
1373 		result = dns_rdataset_first(rdataset);
1374 		if (result != ISC_R_SUCCESS)
1375 			return (result);
1376 		dns_rdataset_current(rdataset, &rdata);
1377 		result = dns_rdata_tostruct(&rdata, &cname, NULL);
1378 		if (result != ISC_R_SUCCESS)
1379 			return (result);
1380 		result = dns_name_dup(&cname.cname, adb->mctx, target);
1381 		dns_rdata_freestruct(&cname);
1382 		if (result != ISC_R_SUCCESS)
1383 			return (result);
1384 	} else {
1385 		dns_rdata_dname_t dname;
1386 
1387 		INSIST(rdataset->type == dns_rdatatype_dname);
1388 		namereln = dns_name_fullcompare(name, fname, &order, &nlabels);
1389 		INSIST(namereln == dns_namereln_subdomain);
1390 		/*
1391 		 * Get the target name of the DNAME.
1392 		 */
1393 		result = dns_rdataset_first(rdataset);
1394 		if (result != ISC_R_SUCCESS)
1395 			return (result);
1396 		dns_rdataset_current(rdataset, &rdata);
1397 		result = dns_rdata_tostruct(&rdata, &dname, NULL);
1398 		if (result != ISC_R_SUCCESS)
1399 			return (result);
1400 		/*
1401 		 * Construct the new target name.
1402 		 */
1403 		dns_fixedname_init(&fixed1);
1404 		prefix = dns_fixedname_name(&fixed1);
1405 		dns_fixedname_init(&fixed2);
1406 		new_target = dns_fixedname_name(&fixed2);
1407 		dns_name_split(name, nlabels, prefix, NULL);
1408 		result = dns_name_concatenate(prefix, &dname.dname, new_target,
1409 					      NULL);
1410 		dns_rdata_freestruct(&dname);
1411 		if (result != ISC_R_SUCCESS)
1412 			return (result);
1413 		result = dns_name_dup(new_target, adb->mctx, target);
1414 		if (result != ISC_R_SUCCESS)
1415 			return (result);
1416 	}
1417 
1418 	return (ISC_R_SUCCESS);
1419 }
1420 
1421 /*
1422  * Assumes nothing is locked, since this is called by the client.
1423  */
1424 static void
event_free(isc_event_t * event)1425 event_free(isc_event_t *event) {
1426 	dns_adbfind_t *find;
1427 
1428 	INSIST(event != NULL);
1429 	find = event->ev_destroy_arg;
1430 	INSIST(DNS_ADBFIND_VALID(find));
1431 
1432 	LOCK(&find->lock);
1433 	find->flags |= FIND_EVENT_FREED;
1434 	event->ev_destroy_arg = NULL;
1435 	UNLOCK(&find->lock);
1436 }
1437 
1438 /*
1439  * Assumes the name bucket is locked.
1440  */
1441 static void
clean_finds_at_name(dns_adbname_t * name,isc_eventtype_t evtype,unsigned int addrs)1442 clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
1443 		    unsigned int addrs)
1444 {
1445 	isc_event_t *ev;
1446 	isc_task_t *task;
1447 	dns_adbfind_t *find;
1448 	dns_adbfind_t *next_find;
1449 	isc_boolean_t process;
1450 	unsigned int wanted, notify;
1451 
1452 	DP(ENTER_LEVEL,
1453 	   "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
1454 	   name, evtype, addrs);
1455 
1456 	find = ISC_LIST_HEAD(name->finds);
1457 	while (find != NULL) {
1458 		LOCK(&find->lock);
1459 		next_find = ISC_LIST_NEXT(find, plink);
1460 
1461 		process = ISC_FALSE;
1462 		wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1463 		notify = wanted & addrs;
1464 
1465 		switch (evtype) {
1466 		case DNS_EVENT_ADBMOREADDRESSES:
1467 			DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES");
1468 			if ((notify) != 0) {
1469 				find->flags &= ~addrs;
1470 				process = ISC_TRUE;
1471 			}
1472 			break;
1473 		case DNS_EVENT_ADBNOMOREADDRESSES:
1474 			DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES");
1475 			find->flags &= ~addrs;
1476 			wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1477 			if (wanted == 0)
1478 				process = ISC_TRUE;
1479 			break;
1480 		default:
1481 			find->flags &= ~addrs;
1482 			process = ISC_TRUE;
1483 		}
1484 
1485 		if (process) {
1486 			DP(DEF_LEVEL, "cfan: processing find %p", find);
1487 			/*
1488 			 * Unlink the find from the name, letting the caller
1489 			 * call dns_adb_destroyfind() on it to clean it up
1490 			 * later.
1491 			 */
1492 			ISC_LIST_UNLINK(name->finds, find, plink);
1493 			find->adbname = NULL;
1494 			find->name_bucket = DNS_ADB_INVALIDBUCKET;
1495 
1496 			INSIST(!FIND_EVENTSENT(find));
1497 
1498 			ev = &find->event;
1499 			task = ev->ev_sender;
1500 			ev->ev_sender = find;
1501 			find->result_v4 = find_err_map[name->fetch_err];
1502 			find->result_v6 = find_err_map[name->fetch6_err];
1503 			ev->ev_type = evtype;
1504 			ev->ev_destroy = event_free;
1505 			ev->ev_destroy_arg = find;
1506 
1507 			DP(DEF_LEVEL,
1508 			   "sending event %p to task %p for find %p",
1509 			   ev, task, find);
1510 
1511 			isc_task_sendanddetach(&task, (isc_event_t **)&ev);
1512 			find->flags |= FIND_EVENT_SENT;
1513 		} else {
1514 			DP(DEF_LEVEL, "cfan: skipping find %p", find);
1515 		}
1516 
1517 		UNLOCK(&find->lock);
1518 		find = next_find;
1519 	}
1520 
1521 	DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
1522 }
1523 
1524 static inline void
check_exit(dns_adb_t * adb)1525 check_exit(dns_adb_t *adb) {
1526 	isc_event_t *event;
1527 	/*
1528 	 * The caller must be holding the adb lock.
1529 	 */
1530 	if (adb->shutting_down) {
1531 		/*
1532 		 * If there aren't any external references either, we're
1533 		 * done.  Send the control event to initiate shutdown.
1534 		 */
1535 		INSIST(!adb->cevent_out);      /* Sanity check. */
1536 		ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
1537 			       DNS_EVENT_ADBCONTROL, shutdown_task, adb,
1538 			       adb, NULL, NULL);
1539 		event = &adb->cevent;
1540 		isc_task_send(adb->task, &event);
1541 		adb->cevent_out = ISC_TRUE;
1542 	}
1543 }
1544 
1545 static inline isc_boolean_t
dec_adb_irefcnt(dns_adb_t * adb)1546 dec_adb_irefcnt(dns_adb_t *adb) {
1547 	isc_event_t *event;
1548 	isc_task_t *etask;
1549 	isc_boolean_t result = ISC_FALSE;
1550 
1551 	LOCK(&adb->reflock);
1552 
1553 	INSIST(adb->irefcnt > 0);
1554 	adb->irefcnt--;
1555 
1556 	if (adb->irefcnt == 0) {
1557 		event = ISC_LIST_HEAD(adb->whenshutdown);
1558 		while (event != NULL) {
1559 			ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
1560 			etask = event->ev_sender;
1561 			event->ev_sender = adb;
1562 			isc_task_sendanddetach(&etask, &event);
1563 			event = ISC_LIST_HEAD(adb->whenshutdown);
1564 		}
1565 	}
1566 
1567 	if (adb->irefcnt == 0 && adb->erefcnt == 0)
1568 		result = ISC_TRUE;
1569 	UNLOCK(&adb->reflock);
1570 	return (result);
1571 }
1572 
1573 static inline void
inc_adb_irefcnt(dns_adb_t * adb)1574 inc_adb_irefcnt(dns_adb_t *adb) {
1575 	LOCK(&adb->reflock);
1576 	adb->irefcnt++;
1577 	UNLOCK(&adb->reflock);
1578 }
1579 
1580 static inline void
inc_adb_erefcnt(dns_adb_t * adb)1581 inc_adb_erefcnt(dns_adb_t *adb) {
1582 	LOCK(&adb->reflock);
1583 	adb->erefcnt++;
1584 	UNLOCK(&adb->reflock);
1585 }
1586 
1587 static inline void
inc_entry_refcnt(dns_adb_t * adb,dns_adbentry_t * entry,isc_boolean_t lock)1588 inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
1589 	int bucket;
1590 
1591 	bucket = entry->lock_bucket;
1592 
1593 	if (lock)
1594 		LOCK(&adb->entrylocks[bucket]);
1595 
1596 	entry->refcnt++;
1597 
1598 	if (lock)
1599 		UNLOCK(&adb->entrylocks[bucket]);
1600 }
1601 
1602 static inline isc_boolean_t
dec_entry_refcnt(dns_adb_t * adb,isc_boolean_t overmem,dns_adbentry_t * entry,isc_boolean_t lock)1603 dec_entry_refcnt(dns_adb_t *adb, isc_boolean_t overmem, dns_adbentry_t *entry,
1604 		 isc_boolean_t lock)
1605 {
1606 	int bucket;
1607 	isc_boolean_t destroy_entry;
1608 	isc_boolean_t result = ISC_FALSE;
1609 
1610 	bucket = entry->lock_bucket;
1611 
1612 	if (lock)
1613 		LOCK(&adb->entrylocks[bucket]);
1614 
1615 	INSIST(entry->refcnt > 0);
1616 	entry->refcnt--;
1617 
1618 	destroy_entry = ISC_FALSE;
1619 	if (entry->refcnt == 0 &&
1620 	    (adb->entry_sd[bucket] || entry->expires == 0 || overmem ||
1621 	     (entry->flags & ENTRY_IS_DEAD) != 0)) {
1622 		destroy_entry = ISC_TRUE;
1623 		result = unlink_entry(adb, entry);
1624 	}
1625 
1626 	if (lock)
1627 		UNLOCK(&adb->entrylocks[bucket]);
1628 
1629 	if (!destroy_entry)
1630 		return (result);
1631 
1632 	entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1633 
1634 	free_adbentry(adb, &entry);
1635 	if (result)
1636 		result = dec_adb_irefcnt(adb);
1637 
1638 	return (result);
1639 }
1640 
1641 static inline dns_adbname_t *
new_adbname(dns_adb_t * adb,dns_name_t * dnsname)1642 new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
1643 	dns_adbname_t *name;
1644 
1645 	name = isc_mempool_get(adb->nmp);
1646 	if (name == NULL)
1647 		return (NULL);
1648 
1649 	dns_name_init(&name->name, NULL);
1650 	if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
1651 		isc_mempool_put(adb->nmp, name);
1652 		return (NULL);
1653 	}
1654 	dns_name_init(&name->target, NULL);
1655 	name->magic = DNS_ADBNAME_MAGIC;
1656 	name->adb = adb;
1657 	name->partial_result = 0;
1658 	name->flags = 0;
1659 	name->expire_v4 = INT_MAX;
1660 	name->expire_v6 = INT_MAX;
1661 	name->expire_target = INT_MAX;
1662 	name->chains = 0;
1663 	name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1664 	ISC_LIST_INIT(name->v4);
1665 	ISC_LIST_INIT(name->v6);
1666 	name->fetch_a = NULL;
1667 	name->fetch_aaaa = NULL;
1668 	name->fetch_err = FIND_ERR_UNEXPECTED;
1669 	name->fetch6_err = FIND_ERR_UNEXPECTED;
1670 	ISC_LIST_INIT(name->finds);
1671 	ISC_LINK_INIT(name, plink);
1672 
1673 	LOCK(&adb->namescntlock);
1674 	adb->namescnt++;
1675 	if (!adb->grownames_sent && adb->excl != NULL &&
1676 	    adb->namescnt > (adb->nnames * 8))
1677 	{
1678 		isc_event_t *event = &adb->grownames;
1679 		inc_adb_irefcnt(adb);
1680 		isc_task_send(adb->excl, &event);
1681 		adb->grownames_sent = ISC_TRUE;
1682 	}
1683 	UNLOCK(&adb->namescntlock);
1684 
1685 	return (name);
1686 }
1687 
1688 static inline void
free_adbname(dns_adb_t * adb,dns_adbname_t ** name)1689 free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
1690 	dns_adbname_t *n;
1691 
1692 	INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
1693 	n = *name;
1694 	*name = NULL;
1695 
1696 	INSIST(!NAME_HAS_V4(n));
1697 	INSIST(!NAME_HAS_V6(n));
1698 	INSIST(!NAME_FETCH(n));
1699 	INSIST(ISC_LIST_EMPTY(n->finds));
1700 	INSIST(!ISC_LINK_LINKED(n, plink));
1701 	INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
1702 	INSIST(n->adb == adb);
1703 
1704 	n->magic = 0;
1705 	dns_name_free(&n->name, adb->mctx);
1706 
1707 	isc_mempool_put(adb->nmp, n);
1708 	LOCK(&adb->namescntlock);
1709 	adb->namescnt--;
1710 	UNLOCK(&adb->namescntlock);
1711 }
1712 
1713 static inline dns_adbnamehook_t *
new_adbnamehook(dns_adb_t * adb,dns_adbentry_t * entry)1714 new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) {
1715 	dns_adbnamehook_t *nh;
1716 
1717 	nh = isc_mempool_get(adb->nhmp);
1718 	if (nh == NULL)
1719 		return (NULL);
1720 
1721 	nh->magic = DNS_ADBNAMEHOOK_MAGIC;
1722 	nh->entry = entry;
1723 	ISC_LINK_INIT(nh, plink);
1724 
1725 	return (nh);
1726 }
1727 
1728 static inline void
free_adbnamehook(dns_adb_t * adb,dns_adbnamehook_t ** namehook)1729 free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) {
1730 	dns_adbnamehook_t *nh;
1731 
1732 	INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
1733 	nh = *namehook;
1734 	*namehook = NULL;
1735 
1736 	INSIST(nh->entry == NULL);
1737 	INSIST(!ISC_LINK_LINKED(nh, plink));
1738 
1739 	nh->magic = 0;
1740 	isc_mempool_put(adb->nhmp, nh);
1741 }
1742 
1743 static inline dns_adblameinfo_t *
new_adblameinfo(dns_adb_t * adb,dns_name_t * qname,dns_rdatatype_t qtype)1744 new_adblameinfo(dns_adb_t *adb, dns_name_t *qname, dns_rdatatype_t qtype) {
1745 	dns_adblameinfo_t *li;
1746 
1747 	li = isc_mempool_get(adb->limp);
1748 	if (li == NULL)
1749 		return (NULL);
1750 
1751 	dns_name_init(&li->qname, NULL);
1752 	if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) {
1753 		isc_mempool_put(adb->limp, li);
1754 		return (NULL);
1755 	}
1756 	li->magic = DNS_ADBLAMEINFO_MAGIC;
1757 	li->lame_timer = 0;
1758 	li->qtype = qtype;
1759 	ISC_LINK_INIT(li, plink);
1760 
1761 	return (li);
1762 }
1763 
1764 static inline void
free_adblameinfo(dns_adb_t * adb,dns_adblameinfo_t ** lameinfo)1765 free_adblameinfo(dns_adb_t *adb, dns_adblameinfo_t **lameinfo) {
1766 	dns_adblameinfo_t *li;
1767 
1768 	INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo));
1769 	li = *lameinfo;
1770 	*lameinfo = NULL;
1771 
1772 	INSIST(!ISC_LINK_LINKED(li, plink));
1773 
1774 	dns_name_free(&li->qname, adb->mctx);
1775 
1776 	li->magic = 0;
1777 
1778 	isc_mempool_put(adb->limp, li);
1779 }
1780 
1781 static inline dns_adbentry_t *
new_adbentry(dns_adb_t * adb)1782 new_adbentry(dns_adb_t *adb) {
1783 	dns_adbentry_t *e;
1784 	isc_uint32_t r;
1785 
1786 	e = isc_mempool_get(adb->emp);
1787 	if (e == NULL)
1788 		return (NULL);
1789 
1790 	e->magic = DNS_ADBENTRY_MAGIC;
1791 	e->lock_bucket = DNS_ADB_INVALIDBUCKET;
1792 	e->refcnt = 0;
1793 	e->nh = 0;
1794 	e->flags = 0;
1795 	e->completed = 0;
1796 	e->timeouts = 0;
1797 	isc_random_get(&r);
1798 	e->srtt = (r & 0x1f) + 1;
1799 	e->lastage = 0;
1800 	e->expires = 0;
1801 #ifdef ENABLE_FETCHLIMIT
1802 	e->active = 0;
1803 	e->mode = 0;
1804 	e->quota = adb->quota;
1805 	e->atr = 0.0;
1806 #endif /* ENABLE_FETCHLIMIT */
1807 	ISC_LIST_INIT(e->lameinfo);
1808 	ISC_LINK_INIT(e, plink);
1809 	LOCK(&adb->entriescntlock);
1810 	adb->entriescnt++;
1811 	if (!adb->growentries_sent && adb->excl != NULL &&
1812 	    adb->entriescnt > (adb->nentries * 8))
1813 	{
1814 		isc_event_t *event = &adb->growentries;
1815 		inc_adb_irefcnt(adb);
1816 		isc_task_send(adb->excl, &event);
1817 		adb->growentries_sent = ISC_TRUE;
1818 	}
1819 	UNLOCK(&adb->entriescntlock);
1820 
1821 	return (e);
1822 }
1823 
1824 static inline void
free_adbentry(dns_adb_t * adb,dns_adbentry_t ** entry)1825 free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
1826 	dns_adbentry_t *e;
1827 	dns_adblameinfo_t *li;
1828 
1829 	INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
1830 	e = *entry;
1831 	*entry = NULL;
1832 
1833 	INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
1834 	INSIST(e->refcnt == 0);
1835 	INSIST(!ISC_LINK_LINKED(e, plink));
1836 
1837 	e->magic = 0;
1838 
1839 	li = ISC_LIST_HEAD(e->lameinfo);
1840 	while (li != NULL) {
1841 		ISC_LIST_UNLINK(e->lameinfo, li, plink);
1842 		free_adblameinfo(adb, &li);
1843 		li = ISC_LIST_HEAD(e->lameinfo);
1844 	}
1845 
1846 	isc_mempool_put(adb->emp, e);
1847 	LOCK(&adb->entriescntlock);
1848 	adb->entriescnt--;
1849 	UNLOCK(&adb->entriescntlock);
1850 }
1851 
1852 static inline dns_adbfind_t *
new_adbfind(dns_adb_t * adb)1853 new_adbfind(dns_adb_t *adb) {
1854 	dns_adbfind_t *h;
1855 	isc_result_t result;
1856 
1857 	h = isc_mempool_get(adb->ahmp);
1858 	if (h == NULL)
1859 		return (NULL);
1860 
1861 	/*
1862 	 * Public members.
1863 	 */
1864 	h->magic = 0;
1865 	h->adb = adb;
1866 	h->partial_result = 0;
1867 	h->options = 0;
1868 	h->flags = 0;
1869 	h->result_v4 = ISC_R_UNEXPECTED;
1870 	h->result_v6 = ISC_R_UNEXPECTED;
1871 	ISC_LINK_INIT(h, publink);
1872 	ISC_LINK_INIT(h, plink);
1873 	ISC_LIST_INIT(h->list);
1874 	h->adbname = NULL;
1875 	h->name_bucket = DNS_ADB_INVALIDBUCKET;
1876 
1877 	/*
1878 	 * private members
1879 	 */
1880 	result = isc_mutex_init(&h->lock);
1881 	if (result != ISC_R_SUCCESS) {
1882 		isc_mempool_put(adb->ahmp, h);
1883 		return (NULL);
1884 	}
1885 
1886 	ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
1887 		       NULL, NULL, h);
1888 
1889 	inc_adb_irefcnt(adb);
1890 	h->magic = DNS_ADBFIND_MAGIC;
1891 	return (h);
1892 }
1893 
1894 static inline dns_adbfetch_t *
new_adbfetch(dns_adb_t * adb)1895 new_adbfetch(dns_adb_t *adb) {
1896 	dns_adbfetch_t *f;
1897 
1898 	f = isc_mempool_get(adb->afmp);
1899 	if (f == NULL)
1900 		return (NULL);
1901 
1902 	f->magic = 0;
1903 	f->fetch = NULL;
1904 
1905 	dns_rdataset_init(&f->rdataset);
1906 
1907 	f->magic = DNS_ADBFETCH_MAGIC;
1908 
1909 	return (f);
1910 }
1911 
1912 static inline void
free_adbfetch(dns_adb_t * adb,dns_adbfetch_t ** fetch)1913 free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) {
1914 	dns_adbfetch_t *f;
1915 
1916 	INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
1917 	f = *fetch;
1918 	*fetch = NULL;
1919 
1920 	f->magic = 0;
1921 
1922 	if (dns_rdataset_isassociated(&f->rdataset))
1923 		dns_rdataset_disassociate(&f->rdataset);
1924 
1925 	isc_mempool_put(adb->afmp, f);
1926 }
1927 
1928 static inline isc_boolean_t
free_adbfind(dns_adb_t * adb,dns_adbfind_t ** findp)1929 free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
1930 	dns_adbfind_t *find;
1931 
1932 	INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
1933 	find = *findp;
1934 	*findp = NULL;
1935 
1936 	INSIST(!FIND_HAS_ADDRS(find));
1937 	INSIST(!ISC_LINK_LINKED(find, publink));
1938 	INSIST(!ISC_LINK_LINKED(find, plink));
1939 	INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
1940 	INSIST(find->adbname == NULL);
1941 
1942 	find->magic = 0;
1943 
1944 	DESTROYLOCK(&find->lock);
1945 	isc_mempool_put(adb->ahmp, find);
1946 	return (dec_adb_irefcnt(adb));
1947 }
1948 
1949 /*
1950  * Copy bits from the entry into the newly allocated addrinfo.  The entry
1951  * must be locked, and the reference count must be bumped up by one
1952  * if this function returns a valid pointer.
1953  */
1954 static inline dns_adbaddrinfo_t *
new_adbaddrinfo(dns_adb_t * adb,dns_adbentry_t * entry,in_port_t port)1955 new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
1956 	dns_adbaddrinfo_t *ai;
1957 
1958 	ai = isc_mempool_get(adb->aimp);
1959 	if (ai == NULL)
1960 		return (NULL);
1961 
1962 	ai->magic = DNS_ADBADDRINFO_MAGIC;
1963 	ai->sockaddr = entry->sockaddr;
1964 	isc_sockaddr_setport(&ai->sockaddr, port);
1965 	ai->srtt = entry->srtt;
1966 	ai->flags = entry->flags;
1967 	ai->entry = entry;
1968 	ISC_LINK_INIT(ai, publink);
1969 
1970 	return (ai);
1971 }
1972 
1973 static inline void
free_adbaddrinfo(dns_adb_t * adb,dns_adbaddrinfo_t ** ainfo)1974 free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
1975 	dns_adbaddrinfo_t *ai;
1976 
1977 	INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
1978 	ai = *ainfo;
1979 	*ainfo = NULL;
1980 
1981 	INSIST(ai->entry == NULL);
1982 	INSIST(!ISC_LINK_LINKED(ai, publink));
1983 
1984 	ai->magic = 0;
1985 
1986 	isc_mempool_put(adb->aimp, ai);
1987 }
1988 
1989 /*
1990  * Search for the name.  NOTE:  The bucket is kept locked on both
1991  * success and failure, so it must always be unlocked by the caller!
1992  *
1993  * On the first call to this function, *bucketp must be set to
1994  * DNS_ADB_INVALIDBUCKET.
1995  */
1996 static inline dns_adbname_t *
find_name_and_lock(dns_adb_t * adb,dns_name_t * name,unsigned int options,int * bucketp)1997 find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
1998 		   unsigned int options, int *bucketp)
1999 {
2000 	dns_adbname_t *adbname;
2001 	int bucket;
2002 
2003 	bucket = dns_name_fullhash(name, ISC_FALSE) % adb->nnames;
2004 
2005 	if (*bucketp == DNS_ADB_INVALIDBUCKET) {
2006 		LOCK(&adb->namelocks[bucket]);
2007 		*bucketp = bucket;
2008 	} else if (*bucketp != bucket) {
2009 		UNLOCK(&adb->namelocks[*bucketp]);
2010 		LOCK(&adb->namelocks[bucket]);
2011 		*bucketp = bucket;
2012 	}
2013 
2014 	adbname = ISC_LIST_HEAD(adb->names[bucket]);
2015 	while (adbname != NULL) {
2016 		if (!NAME_DEAD(adbname)) {
2017 			if (dns_name_equal(name, &adbname->name)
2018 			    && GLUEHINT_OK(adbname, options)
2019 			    && STARTATZONE_MATCHES(adbname, options))
2020 				return (adbname);
2021 		}
2022 		adbname = ISC_LIST_NEXT(adbname, plink);
2023 	}
2024 
2025 	return (NULL);
2026 }
2027 
2028 /*
2029  * Search for the address.  NOTE:  The bucket is kept locked on both
2030  * success and failure, so it must always be unlocked by the caller.
2031  *
2032  * On the first call to this function, *bucketp must be set to
2033  * DNS_ADB_INVALIDBUCKET.  This will cause a lock to occur.  On
2034  * later calls (within the same "lock path") it can be left alone, so
2035  * if this function is called multiple times locking is only done if
2036  * the bucket changes.
2037  */
2038 static inline dns_adbentry_t *
find_entry_and_lock(dns_adb_t * adb,isc_sockaddr_t * addr,int * bucketp,isc_stdtime_t now)2039 find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp,
2040 	isc_stdtime_t now)
2041 {
2042 	dns_adbentry_t *entry, *entry_next;
2043 	int bucket;
2044 
2045 	bucket = isc_sockaddr_hash(addr, ISC_TRUE) % adb->nentries;
2046 
2047 	if (*bucketp == DNS_ADB_INVALIDBUCKET) {
2048 		LOCK(&adb->entrylocks[bucket]);
2049 		*bucketp = bucket;
2050 	} else if (*bucketp != bucket) {
2051 		UNLOCK(&adb->entrylocks[*bucketp]);
2052 		LOCK(&adb->entrylocks[bucket]);
2053 		*bucketp = bucket;
2054 	}
2055 
2056 	/* Search the list, while cleaning up expired entries. */
2057 	for (entry = ISC_LIST_HEAD(adb->entries[bucket]);
2058 	     entry != NULL;
2059 	     entry = entry_next) {
2060 		entry_next = ISC_LIST_NEXT(entry, plink);
2061 		(void)check_expire_entry(adb, &entry, now);
2062 		if (entry != NULL &&
2063 		    isc_sockaddr_equal(addr, &entry->sockaddr)) {
2064 			ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
2065 			ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
2066 			return (entry);
2067 		}
2068 	}
2069 
2070 	return (NULL);
2071 }
2072 
2073 /*
2074  * Entry bucket MUST be locked!
2075  */
2076 static isc_boolean_t
entry_is_lame(dns_adb_t * adb,dns_adbentry_t * entry,dns_name_t * qname,dns_rdatatype_t qtype,isc_stdtime_t now)2077 entry_is_lame(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *qname,
2078 	      dns_rdatatype_t qtype, isc_stdtime_t now)
2079 {
2080 	dns_adblameinfo_t *li, *next_li;
2081 	isc_boolean_t is_bad;
2082 
2083 	is_bad = ISC_FALSE;
2084 
2085 	li = ISC_LIST_HEAD(entry->lameinfo);
2086 	if (li == NULL)
2087 		return (ISC_FALSE);
2088 	while (li != NULL) {
2089 		next_li = ISC_LIST_NEXT(li, plink);
2090 
2091 		/*
2092 		 * Has the entry expired?
2093 		 */
2094 		if (li->lame_timer < now) {
2095 			ISC_LIST_UNLINK(entry->lameinfo, li, plink);
2096 			free_adblameinfo(adb, &li);
2097 		}
2098 
2099 		/*
2100 		 * Order tests from least to most expensive.
2101 		 *
2102 		 * We do not break out of the main loop here as
2103 		 * we use the loop for house keeping.
2104 		 */
2105 		if (li != NULL && !is_bad && li->qtype == qtype &&
2106 		    dns_name_equal(qname, &li->qname))
2107 			is_bad = ISC_TRUE;
2108 
2109 		li = next_li;
2110 	}
2111 
2112 	return (is_bad);
2113 }
2114 
2115 #ifdef ENABLE_FETCHLIMIT
2116 static void
log_quota(dns_adbentry_t * entry,const char * fmt,...)2117 log_quota(dns_adbentry_t *entry, const char *fmt, ...) {
2118 	va_list ap;
2119 	char msgbuf[2048];
2120 	char addrbuf[ISC_NETADDR_FORMATSIZE];
2121 	isc_netaddr_t netaddr;
2122 
2123 	va_start(ap, fmt);
2124 	vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
2125 	va_end(ap);
2126 
2127 	isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
2128 	isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
2129 
2130 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
2131 		      ISC_LOG_INFO, "adb: quota %s (%d/%d): %s",
2132 		      addrbuf, entry->active, entry->quota, msgbuf);
2133 }
2134 #endif /* ENABLE_FETCHLIMIT */
2135 
2136 static void
copy_namehook_lists(dns_adb_t * adb,dns_adbfind_t * find,dns_name_t * qname,dns_rdatatype_t qtype,dns_adbname_t * name,isc_stdtime_t now)2137 copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname,
2138 		    dns_rdatatype_t qtype, dns_adbname_t *name,
2139 		    isc_stdtime_t now)
2140 {
2141 	dns_adbnamehook_t *namehook;
2142 	dns_adbaddrinfo_t *addrinfo;
2143 	dns_adbentry_t *entry;
2144 	int bucket;
2145 
2146 	bucket = DNS_ADB_INVALIDBUCKET;
2147 
2148 	if (find->options & DNS_ADBFIND_INET) {
2149 		namehook = ISC_LIST_HEAD(name->v4);
2150 		while (namehook != NULL) {
2151 			entry = namehook->entry;
2152 			bucket = entry->lock_bucket;
2153 			INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2154 			LOCK(&adb->entrylocks[bucket]);
2155 
2156 #ifdef ENABLE_FETCHLIMIT
2157 			if (entry->quota != 0 &&
2158 			    entry->active >= entry->quota)
2159 			{
2160 				find->options |=
2161 					(DNS_ADBFIND_LAMEPRUNED|
2162 					 DNS_ADBFIND_OVERQUOTA);
2163 				goto nextv4;
2164 			}
2165 #endif /* ENABLE_FETCHLIMIT */
2166 
2167 			if (!FIND_RETURNLAME(find)
2168 			    && entry_is_lame(adb, entry, qname, qtype, now)) {
2169 				find->options |= DNS_ADBFIND_LAMEPRUNED;
2170 				goto nextv4;
2171 			}
2172 			addrinfo = new_adbaddrinfo(adb, entry, find->port);
2173 			if (addrinfo == NULL) {
2174 				find->partial_result |= DNS_ADBFIND_INET;
2175 				goto out;
2176 			}
2177 			/*
2178 			 * Found a valid entry.  Add it to the find's list.
2179 			 */
2180 			inc_entry_refcnt(adb, entry, ISC_FALSE);
2181 			ISC_LIST_APPEND(find->list, addrinfo, publink);
2182 			addrinfo = NULL;
2183 		nextv4:
2184 			UNLOCK(&adb->entrylocks[bucket]);
2185 			bucket = DNS_ADB_INVALIDBUCKET;
2186 			namehook = ISC_LIST_NEXT(namehook, plink);
2187 		}
2188 	}
2189 
2190 	if (find->options & DNS_ADBFIND_INET6) {
2191 		namehook = ISC_LIST_HEAD(name->v6);
2192 		while (namehook != NULL) {
2193 			entry = namehook->entry;
2194 			bucket = entry->lock_bucket;
2195 			INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2196 			LOCK(&adb->entrylocks[bucket]);
2197 
2198 #ifdef ENABLE_FETCHLIMIT
2199 			if (entry->quota != 0 &&
2200 			    entry->active >= entry->quota)
2201 			{
2202 				find->options |=
2203 					(DNS_ADBFIND_LAMEPRUNED|
2204 					 DNS_ADBFIND_OVERQUOTA);
2205 				goto nextv6;
2206 			}
2207 #endif /* ENABLE_FETCHLIMIT */
2208 
2209 			if (!FIND_RETURNLAME(find)
2210 			    && entry_is_lame(adb, entry, qname, qtype, now)) {
2211 				find->options |= DNS_ADBFIND_LAMEPRUNED;
2212 				goto nextv6;
2213 			}
2214 			addrinfo = new_adbaddrinfo(adb, entry, find->port);
2215 			if (addrinfo == NULL) {
2216 				find->partial_result |= DNS_ADBFIND_INET6;
2217 				goto out;
2218 			}
2219 			/*
2220 			 * Found a valid entry.  Add it to the find's list.
2221 			 */
2222 			inc_entry_refcnt(adb, entry, ISC_FALSE);
2223 			ISC_LIST_APPEND(find->list, addrinfo, publink);
2224 			addrinfo = NULL;
2225 		nextv6:
2226 			UNLOCK(&adb->entrylocks[bucket]);
2227 			bucket = DNS_ADB_INVALIDBUCKET;
2228 			namehook = ISC_LIST_NEXT(namehook, plink);
2229 		}
2230 	}
2231 
2232  out:
2233 	if (bucket != DNS_ADB_INVALIDBUCKET)
2234 		UNLOCK(&adb->entrylocks[bucket]);
2235 }
2236 
2237 static void
shutdown_task(isc_task_t * task,isc_event_t * ev)2238 shutdown_task(isc_task_t *task, isc_event_t *ev) {
2239 	dns_adb_t *adb;
2240 
2241 	UNUSED(task);
2242 
2243 	adb = ev->ev_arg;
2244 	INSIST(DNS_ADB_VALID(adb));
2245 
2246 	isc_event_free(&ev);
2247 	/*
2248 	 * Wait for lock around check_exit() call to be released.
2249 	 */
2250 	LOCK(&adb->lock);
2251 	UNLOCK(&adb->lock);
2252 	destroy(adb);
2253 }
2254 
2255 /*
2256  * Name bucket must be locked; adb may be locked; no other locks held.
2257  */
2258 static isc_boolean_t
check_expire_name(dns_adbname_t ** namep,isc_stdtime_t now)2259 check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
2260 	dns_adbname_t *name;
2261 	isc_boolean_t result = ISC_FALSE;
2262 
2263 	INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
2264 	name = *namep;
2265 
2266 	if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
2267 		return (result);
2268 	if (NAME_FETCH(name))
2269 		return (result);
2270 	if (!EXPIRE_OK(name->expire_v4, now))
2271 		return (result);
2272 	if (!EXPIRE_OK(name->expire_v6, now))
2273 		return (result);
2274 	if (!EXPIRE_OK(name->expire_target, now))
2275 		return (result);
2276 
2277 	/*
2278 	 * The name is empty.  Delete it.
2279 	 */
2280 	result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
2281 	*namep = NULL;
2282 
2283 	/*
2284 	 * Our caller, or one of its callers, will be calling check_exit() at
2285 	 * some point, so we don't need to do it here.
2286 	 */
2287 	return (result);
2288 }
2289 
2290 /*%
2291  * Examine the tail entry of the LRU list to see if it expires or is stale
2292  * (unused for some period); if so, the name entry will be freed.  If the ADB
2293  * is in the overmem condition, the tail and the next to tail entries
2294  * will be unconditionally removed (unless they have an outstanding fetch).
2295  * We don't care about a race on 'overmem' at the risk of causing some
2296  * collateral damage or a small delay in starting cleanup, so we don't bother
2297  * to lock ADB (if it's not locked).
2298  *
2299  * Name bucket must be locked; adb may be locked; no other locks held.
2300  */
2301 static void
check_stale_name(dns_adb_t * adb,int bucket,isc_stdtime_t now)2302 check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2303 	int victims, max_victims;
2304 	dns_adbname_t *victim, *next_victim;
2305 	isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
2306 	int scans = 0;
2307 
2308 	INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2309 
2310 	max_victims = overmem ? 2 : 1;
2311 
2312 	/*
2313 	 * We limit the number of scanned entries to 10 (arbitrary choice)
2314 	 * in order to avoid examining too many entries when there are many
2315 	 * tail entries that have fetches (this should be rare, but could
2316 	 * happen).
2317 	 */
2318 	victim = ISC_LIST_TAIL(adb->names[bucket]);
2319 	for (victims = 0;
2320 	     victim != NULL && victims < max_victims && scans < 10;
2321 	     victim = next_victim) {
2322 		INSIST(!NAME_DEAD(victim));
2323 		scans++;
2324 		next_victim = ISC_LIST_PREV(victim, plink);
2325 		(void)check_expire_name(&victim, now);
2326 		if (victim == NULL) {
2327 			victims++;
2328 			goto next;
2329 		}
2330 
2331 		if (!NAME_FETCH(victim) &&
2332 		    (overmem || victim->last_used + ADB_STALE_MARGIN <= now)) {
2333 			RUNTIME_CHECK(kill_name(&victim,
2334 						DNS_EVENT_ADBCANCELED) ==
2335 				      ISC_FALSE);
2336 			victims++;
2337 		}
2338 
2339 	next:
2340 		if (!overmem)
2341 			break;
2342 	}
2343 }
2344 
2345 /*
2346  * Entry bucket must be locked; adb may be locked; no other locks held.
2347  */
2348 static isc_boolean_t
check_expire_entry(dns_adb_t * adb,dns_adbentry_t ** entryp,isc_stdtime_t now)2349 check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
2350 {
2351 	dns_adbentry_t *entry;
2352 	isc_boolean_t result = ISC_FALSE;
2353 
2354 	INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
2355 	entry = *entryp;
2356 
2357 	if (entry->refcnt != 0)
2358 		return (result);
2359 
2360 	if (entry->expires == 0 || entry->expires > now)
2361 		return (result);
2362 
2363 	/*
2364 	 * The entry is not in use.  Delete it.
2365 	 */
2366 	DP(DEF_LEVEL, "killing entry %p", entry);
2367 	INSIST(ISC_LINK_LINKED(entry, plink));
2368 	result = unlink_entry(adb, entry);
2369 	free_adbentry(adb, &entry);
2370 	if (result)
2371 		dec_adb_irefcnt(adb);
2372 	*entryp = NULL;
2373 	return (result);
2374 }
2375 
2376 /*
2377  * ADB must be locked, and no other locks held.
2378  */
2379 static isc_boolean_t
cleanup_names(dns_adb_t * adb,int bucket,isc_stdtime_t now)2380 cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2381 	dns_adbname_t *name;
2382 	dns_adbname_t *next_name;
2383 	isc_boolean_t result = ISC_FALSE;
2384 
2385 	DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
2386 
2387 	LOCK(&adb->namelocks[bucket]);
2388 	if (adb->name_sd[bucket]) {
2389 		UNLOCK(&adb->namelocks[bucket]);
2390 		return (result);
2391 	}
2392 
2393 	name = ISC_LIST_HEAD(adb->names[bucket]);
2394 	while (name != NULL) {
2395 		next_name = ISC_LIST_NEXT(name, plink);
2396 		INSIST(result == ISC_FALSE);
2397 		result = check_expire_namehooks(name, now);
2398 		if (!result)
2399 			result = check_expire_name(&name, now);
2400 		name = next_name;
2401 	}
2402 	UNLOCK(&adb->namelocks[bucket]);
2403 	return (result);
2404 }
2405 
2406 /*
2407  * ADB must be locked, and no other locks held.
2408  */
2409 static isc_boolean_t
cleanup_entries(dns_adb_t * adb,int bucket,isc_stdtime_t now)2410 cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2411 	dns_adbentry_t *entry, *next_entry;
2412 	isc_boolean_t result = ISC_FALSE;
2413 
2414 	DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
2415 
2416 	LOCK(&adb->entrylocks[bucket]);
2417 	entry = ISC_LIST_HEAD(adb->entries[bucket]);
2418 	while (entry != NULL) {
2419 		next_entry = ISC_LIST_NEXT(entry, plink);
2420 		INSIST(result == ISC_FALSE);
2421 		result = check_expire_entry(adb, &entry, now);
2422 		entry = next_entry;
2423 	}
2424 	UNLOCK(&adb->entrylocks[bucket]);
2425 	return (result);
2426 }
2427 
2428 static void
destroy(dns_adb_t * adb)2429 destroy(dns_adb_t *adb) {
2430 	adb->magic = 0;
2431 
2432 	isc_task_detach(&adb->task);
2433 	if (adb->excl != NULL)
2434 		isc_task_detach(&adb->excl);
2435 
2436 	isc_mempool_destroy(&adb->nmp);
2437 	isc_mempool_destroy(&adb->nhmp);
2438 	isc_mempool_destroy(&adb->limp);
2439 	isc_mempool_destroy(&adb->emp);
2440 	isc_mempool_destroy(&adb->ahmp);
2441 	isc_mempool_destroy(&adb->aimp);
2442 	isc_mempool_destroy(&adb->afmp);
2443 
2444 	DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
2445 	isc_mem_put(adb->mctx, adb->entries,
2446 		    sizeof(*adb->entries) * adb->nentries);
2447 	isc_mem_put(adb->mctx, adb->deadentries,
2448 		    sizeof(*adb->deadentries) * adb->nentries);
2449 	isc_mem_put(adb->mctx, adb->entrylocks,
2450 		    sizeof(*adb->entrylocks) * adb->nentries);
2451 	isc_mem_put(adb->mctx, adb->entry_sd,
2452 		    sizeof(*adb->entry_sd) * adb->nentries);
2453 	isc_mem_put(adb->mctx, adb->entry_refcnt,
2454 		    sizeof(*adb->entry_refcnt) * adb->nentries);
2455 
2456 	DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
2457 	isc_mem_put(adb->mctx, adb->names,
2458 		    sizeof(*adb->names) * adb->nnames);
2459 	isc_mem_put(adb->mctx, adb->deadnames,
2460 		    sizeof(*adb->deadnames) * adb->nnames);
2461 	isc_mem_put(adb->mctx, adb->namelocks,
2462 		    sizeof(*adb->namelocks) * adb->nnames);
2463 	isc_mem_put(adb->mctx, adb->name_sd,
2464 		    sizeof(*adb->name_sd) * adb->nnames);
2465 	isc_mem_put(adb->mctx, adb->name_refcnt,
2466 		    sizeof(*adb->name_refcnt) * adb->nnames);
2467 
2468 	DESTROYLOCK(&adb->reflock);
2469 	DESTROYLOCK(&adb->lock);
2470 	DESTROYLOCK(&adb->mplock);
2471 	DESTROYLOCK(&adb->overmemlock);
2472 	DESTROYLOCK(&adb->entriescntlock);
2473 	DESTROYLOCK(&adb->namescntlock);
2474 
2475 	isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2476 }
2477 
2478 
2479 /*
2480  * Public functions.
2481  */
2482 
2483 isc_result_t
dns_adb_create(isc_mem_t * mem,dns_view_t * view,isc_timermgr_t * timermgr,isc_taskmgr_t * taskmgr,dns_adb_t ** newadb)2484 dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
2485 	       isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
2486 {
2487 	dns_adb_t *adb;
2488 	isc_result_t result;
2489 	unsigned int i;
2490 
2491 	REQUIRE(mem != NULL);
2492 	REQUIRE(view != NULL);
2493 	REQUIRE(timermgr != NULL); /* this is actually unused */
2494 	REQUIRE(taskmgr != NULL);
2495 	REQUIRE(newadb != NULL && *newadb == NULL);
2496 
2497 	UNUSED(timermgr);
2498 
2499 	adb = isc_mem_get(mem, sizeof(dns_adb_t));
2500 	if (adb == NULL)
2501 		return (ISC_R_NOMEMORY);
2502 
2503 	/*
2504 	 * Initialize things here that cannot fail, and especially things
2505 	 * that must be NULL for the error return to work properly.
2506 	 */
2507 	adb->magic = 0;
2508 	adb->erefcnt = 1;
2509 	adb->irefcnt = 0;
2510 	adb->nmp = NULL;
2511 	adb->nhmp = NULL;
2512 	adb->limp = NULL;
2513 	adb->emp = NULL;
2514 	adb->ahmp = NULL;
2515 	adb->aimp = NULL;
2516 	adb->afmp = NULL;
2517 	adb->task = NULL;
2518 	adb->excl = NULL;
2519 	adb->mctx = NULL;
2520 	adb->view = view;
2521 	adb->taskmgr = taskmgr;
2522 	adb->next_cleanbucket = 0;
2523 	ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent),
2524 		       0, NULL, 0, NULL, NULL, NULL, NULL, NULL);
2525 	adb->cevent_out = ISC_FALSE;
2526 	adb->shutting_down = ISC_FALSE;
2527 	ISC_LIST_INIT(adb->whenshutdown);
2528 
2529 	adb->nentries = nbuckets[0];
2530 	adb->entriescnt = 0;
2531 	adb->entries = NULL;
2532 	adb->deadentries = NULL;
2533 	adb->entry_sd = NULL;
2534 	adb->entry_refcnt = NULL;
2535 	adb->entrylocks = NULL;
2536 	ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL,
2537 		       DNS_EVENT_ADBGROWENTRIES, grow_entries, adb,
2538 		       adb, NULL, NULL);
2539 	adb->growentries_sent = ISC_FALSE;
2540 
2541 #ifdef ENABLE_FETCHLIMIT
2542 	adb->quota = 0;
2543 	adb->atr_freq = 0;
2544 	adb->atr_low = 0.0;
2545 	adb->atr_high = 0.0;
2546 	adb->atr_discount = 0.0;
2547 #endif /* ENABLE_FETCHLIMIT */
2548 
2549 	adb->nnames = nbuckets[0];
2550 	adb->namescnt = 0;
2551 	adb->names = NULL;
2552 	adb->deadnames = NULL;
2553 	adb->name_sd = NULL;
2554 	adb->name_refcnt = NULL;
2555 	adb->namelocks = NULL;
2556 	ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL,
2557 		       DNS_EVENT_ADBGROWNAMES, grow_names, adb,
2558 		       adb, NULL, NULL);
2559 	adb->grownames_sent = ISC_FALSE;
2560 
2561 	result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl);
2562 	if (result != ISC_R_SUCCESS) {
2563 		DP(ISC_LOG_INFO, "adb: task-exclusive mode unavailable, "
2564 				 "intializing table sizes to %u\n",
2565 				 nbuckets[11]);
2566 		adb->nentries = nbuckets[11];
2567 		adb->nnames = nbuckets[11];
2568 	}
2569 
2570 	isc_mem_attach(mem, &adb->mctx);
2571 
2572 	result = isc_mutex_init(&adb->lock);
2573 	if (result != ISC_R_SUCCESS)
2574 		goto fail0b;
2575 
2576 	result = isc_mutex_init(&adb->mplock);
2577 	if (result != ISC_R_SUCCESS)
2578 		goto fail0c;
2579 
2580 	result = isc_mutex_init(&adb->reflock);
2581 	if (result != ISC_R_SUCCESS)
2582 		goto fail0d;
2583 
2584 	result = isc_mutex_init(&adb->overmemlock);
2585 	if (result != ISC_R_SUCCESS)
2586 		goto fail0e;
2587 
2588 	result = isc_mutex_init(&adb->entriescntlock);
2589 	if (result != ISC_R_SUCCESS)
2590 		goto fail0f;
2591 
2592 	result = isc_mutex_init(&adb->namescntlock);
2593 	if (result != ISC_R_SUCCESS)
2594 		goto fail0g;
2595 
2596 #define ALLOCENTRY(adb, el) \
2597 	do { \
2598 		(adb)->el = isc_mem_get((adb)->mctx, \
2599 				     sizeof(*(adb)->el) * (adb)->nentries); \
2600 		if ((adb)->el == NULL) { \
2601 			result = ISC_R_NOMEMORY; \
2602 			goto fail1; \
2603 		}\
2604 	} while (0)
2605 	ALLOCENTRY(adb, entries);
2606 	ALLOCENTRY(adb, deadentries);
2607 	ALLOCENTRY(adb, entrylocks);
2608 	ALLOCENTRY(adb, entry_sd);
2609 	ALLOCENTRY(adb, entry_refcnt);
2610 #undef ALLOCENTRY
2611 
2612 #define ALLOCNAME(adb, el) \
2613 	do { \
2614 		(adb)->el = isc_mem_get((adb)->mctx, \
2615 				     sizeof(*(adb)->el) * (adb)->nnames); \
2616 		if ((adb)->el == NULL) { \
2617 			result = ISC_R_NOMEMORY; \
2618 			goto fail1; \
2619 		}\
2620 	} while (0)
2621 	ALLOCNAME(adb, names);
2622 	ALLOCNAME(adb, deadnames);
2623 	ALLOCNAME(adb, namelocks);
2624 	ALLOCNAME(adb, name_sd);
2625 	ALLOCNAME(adb, name_refcnt);
2626 #undef ALLOCNAME
2627 
2628 	/*
2629 	 * Initialize the bucket locks for names and elements.
2630 	 * May as well initialize the list heads, too.
2631 	 */
2632 	result = isc_mutexblock_init(adb->namelocks, adb->nnames);
2633 	if (result != ISC_R_SUCCESS)
2634 		goto fail1;
2635 	for (i = 0; i < adb->nnames; i++) {
2636 		ISC_LIST_INIT(adb->names[i]);
2637 		ISC_LIST_INIT(adb->deadnames[i]);
2638 		adb->name_sd[i] = ISC_FALSE;
2639 		adb->name_refcnt[i] = 0;
2640 		adb->irefcnt++;
2641 	}
2642 	for (i = 0; i < adb->nentries; i++) {
2643 		ISC_LIST_INIT(adb->entries[i]);
2644 		ISC_LIST_INIT(adb->deadentries[i]);
2645 		adb->entry_sd[i] = ISC_FALSE;
2646 		adb->entry_refcnt[i] = 0;
2647 		adb->irefcnt++;
2648 	}
2649 	result = isc_mutexblock_init(adb->entrylocks, adb->nentries);
2650 	if (result != ISC_R_SUCCESS)
2651 		goto fail2;
2652 
2653 	/*
2654 	 * Memory pools
2655 	 */
2656 #define MPINIT(t, p, n) do { \
2657 	result = isc_mempool_create(mem, sizeof(t), &(p)); \
2658 	if (result != ISC_R_SUCCESS) \
2659 		goto fail3; \
2660 	isc_mempool_setfreemax((p), FREE_ITEMS); \
2661 	isc_mempool_setfillcount((p), FILL_COUNT); \
2662 	isc_mempool_setname((p), n); \
2663 	isc_mempool_associatelock((p), &adb->mplock); \
2664 } while (0)
2665 
2666 	MPINIT(dns_adbname_t, adb->nmp, "adbname");
2667 	MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
2668 	MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo");
2669 	MPINIT(dns_adbentry_t, adb->emp, "adbentry");
2670 	MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
2671 	MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
2672 	MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
2673 
2674 #undef MPINIT
2675 
2676 	/*
2677 	 * Allocate an internal task.
2678 	 */
2679 	result = isc_task_create(adb->taskmgr, 0, &adb->task);
2680 	if (result != ISC_R_SUCCESS)
2681 		goto fail3;
2682 
2683 	isc_task_setname(adb->task, "ADB", adb);
2684 
2685 	/*
2686 	 * Normal return.
2687 	 */
2688 	adb->magic = DNS_ADB_MAGIC;
2689 	*newadb = adb;
2690 	return (ISC_R_SUCCESS);
2691 
2692  fail3:
2693 	if (adb->task != NULL)
2694 		isc_task_detach(&adb->task);
2695 
2696 	/* clean up entrylocks */
2697 	DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
2698 
2699  fail2: /* clean up namelocks */
2700 	DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
2701 
2702  fail1: /* clean up only allocated memory */
2703 	if (adb->entries != NULL)
2704 		isc_mem_put(adb->mctx, adb->entries,
2705 			    sizeof(*adb->entries) * adb->nentries);
2706 	if (adb->deadentries != NULL)
2707 		isc_mem_put(adb->mctx, adb->deadentries,
2708 			    sizeof(*adb->deadentries) * adb->nentries);
2709 	if (adb->entrylocks != NULL)
2710 		isc_mem_put(adb->mctx, adb->entrylocks,
2711 			    sizeof(*adb->entrylocks) * adb->nentries);
2712 	if (adb->entry_sd != NULL)
2713 		isc_mem_put(adb->mctx, adb->entry_sd,
2714 			    sizeof(*adb->entry_sd) * adb->nentries);
2715 	if (adb->entry_refcnt != NULL)
2716 		isc_mem_put(adb->mctx, adb->entry_refcnt,
2717 			    sizeof(*adb->entry_refcnt) * adb->nentries);
2718 	if (adb->names != NULL)
2719 		isc_mem_put(adb->mctx, adb->names,
2720 			    sizeof(*adb->names) * adb->nnames);
2721 	if (adb->deadnames != NULL)
2722 		isc_mem_put(adb->mctx, adb->deadnames,
2723 			    sizeof(*adb->deadnames) * adb->nnames);
2724 	if (adb->namelocks != NULL)
2725 		isc_mem_put(adb->mctx, adb->namelocks,
2726 			    sizeof(*adb->namelocks) * adb->nnames);
2727 	if (adb->name_sd != NULL)
2728 		isc_mem_put(adb->mctx, adb->name_sd,
2729 			    sizeof(*adb->name_sd) * adb->nnames);
2730 	if (adb->name_refcnt != NULL)
2731 		isc_mem_put(adb->mctx, adb->name_refcnt,
2732 			    sizeof(*adb->name_refcnt) * adb->nnames);
2733 	if (adb->nmp != NULL)
2734 		isc_mempool_destroy(&adb->nmp);
2735 	if (adb->nhmp != NULL)
2736 		isc_mempool_destroy(&adb->nhmp);
2737 	if (adb->limp != NULL)
2738 		isc_mempool_destroy(&adb->limp);
2739 	if (adb->emp != NULL)
2740 		isc_mempool_destroy(&adb->emp);
2741 	if (adb->ahmp != NULL)
2742 		isc_mempool_destroy(&adb->ahmp);
2743 	if (adb->aimp != NULL)
2744 		isc_mempool_destroy(&adb->aimp);
2745 	if (adb->afmp != NULL)
2746 		isc_mempool_destroy(&adb->afmp);
2747 
2748 	DESTROYLOCK(&adb->namescntlock);
2749  fail0g:
2750 	DESTROYLOCK(&adb->entriescntlock);
2751  fail0f:
2752 	DESTROYLOCK(&adb->overmemlock);
2753  fail0e:
2754 	DESTROYLOCK(&adb->reflock);
2755  fail0d:
2756 	DESTROYLOCK(&adb->mplock);
2757  fail0c:
2758 	DESTROYLOCK(&adb->lock);
2759  fail0b:
2760 	if (adb->excl != NULL)
2761 		isc_task_detach(&adb->excl);
2762 	isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
2763 
2764 	return (result);
2765 }
2766 
2767 void
dns_adb_attach(dns_adb_t * adb,dns_adb_t ** adbx)2768 dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
2769 
2770 	REQUIRE(DNS_ADB_VALID(adb));
2771 	REQUIRE(adbx != NULL && *adbx == NULL);
2772 
2773 	inc_adb_erefcnt(adb);
2774 	*adbx = adb;
2775 }
2776 
2777 void
dns_adb_detach(dns_adb_t ** adbx)2778 dns_adb_detach(dns_adb_t **adbx) {
2779 	dns_adb_t *adb;
2780 	isc_boolean_t need_exit_check;
2781 
2782 	REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
2783 
2784 	adb = *adbx;
2785 	*adbx = NULL;
2786 
2787 	INSIST(adb->erefcnt > 0);
2788 
2789 	LOCK(&adb->reflock);
2790 	adb->erefcnt--;
2791 	need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
2792 	UNLOCK(&adb->reflock);
2793 
2794 	if (need_exit_check) {
2795 		LOCK(&adb->lock);
2796 		INSIST(adb->shutting_down);
2797 		check_exit(adb);
2798 		UNLOCK(&adb->lock);
2799 	}
2800 }
2801 
2802 void
dns_adb_whenshutdown(dns_adb_t * adb,isc_task_t * task,isc_event_t ** eventp)2803 dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
2804 	isc_task_t *clone;
2805 	isc_event_t *event;
2806 	isc_boolean_t zeroirefcnt = ISC_FALSE;
2807 
2808 	/*
2809 	 * Send '*eventp' to 'task' when 'adb' has shutdown.
2810 	 */
2811 
2812 	REQUIRE(DNS_ADB_VALID(adb));
2813 	REQUIRE(eventp != NULL);
2814 
2815 	event = *eventp;
2816 	*eventp = NULL;
2817 
2818 	LOCK(&adb->lock);
2819 
2820 	LOCK(&adb->reflock);
2821 	zeroirefcnt = ISC_TF(adb->irefcnt == 0);
2822 
2823 	if (adb->shutting_down && zeroirefcnt &&
2824 	    isc_mempool_getallocated(adb->ahmp) == 0) {
2825 		/*
2826 		 * We're already shutdown.  Send the event.
2827 		 */
2828 		event->ev_sender = adb;
2829 		isc_task_send(task, &event);
2830 	} else {
2831 		clone = NULL;
2832 		isc_task_attach(task, &clone);
2833 		event->ev_sender = clone;
2834 		ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
2835 	}
2836 
2837 	UNLOCK(&adb->reflock);
2838 	UNLOCK(&adb->lock);
2839 }
2840 
2841 static void
shutdown_stage2(isc_task_t * task,isc_event_t * event)2842 shutdown_stage2(isc_task_t *task, isc_event_t *event) {
2843 	dns_adb_t *adb;
2844 
2845 	UNUSED(task);
2846 
2847 	adb = event->ev_arg;
2848 	INSIST(DNS_ADB_VALID(adb));
2849 
2850 	LOCK(&adb->lock);
2851 	INSIST(adb->shutting_down);
2852 	adb->cevent_out = ISC_FALSE;
2853 	(void)shutdown_names(adb);
2854 	(void)shutdown_entries(adb);
2855 	if (dec_adb_irefcnt(adb))
2856 		check_exit(adb);
2857 	UNLOCK(&adb->lock);
2858 }
2859 
2860 void
dns_adb_shutdown(dns_adb_t * adb)2861 dns_adb_shutdown(dns_adb_t *adb) {
2862 	isc_event_t *event;
2863 
2864 	/*
2865 	 * Shutdown 'adb'.
2866 	 */
2867 
2868 	LOCK(&adb->lock);
2869 
2870 	if (!adb->shutting_down) {
2871 		adb->shutting_down = ISC_TRUE;
2872 		isc_mem_setwater(adb->mctx, water, adb, 0, 0);
2873 		/*
2874 		 * Isolate shutdown_names and shutdown_entries calls.
2875 		 */
2876 		inc_adb_irefcnt(adb);
2877 		ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
2878 			       DNS_EVENT_ADBCONTROL, shutdown_stage2, adb,
2879 			       adb, NULL, NULL);
2880 		adb->cevent_out = ISC_TRUE;
2881 		event = &adb->cevent;
2882 		isc_task_send(adb->task, &event);
2883 	}
2884 
2885 	UNLOCK(&adb->lock);
2886 }
2887 
2888 isc_result_t
dns_adb_createfind(dns_adb_t * adb,isc_task_t * task,isc_taskaction_t action,void * arg,dns_name_t * name,dns_name_t * qname,dns_rdatatype_t qtype,unsigned int options,isc_stdtime_t now,dns_name_t * target,in_port_t port,dns_adbfind_t ** findp)2889 dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
2890 		   void *arg, dns_name_t *name, dns_name_t *qname,
2891 		   dns_rdatatype_t qtype, unsigned int options,
2892 		   isc_stdtime_t now, dns_name_t *target,
2893 		   in_port_t port, dns_adbfind_t **findp)
2894 {
2895 	return (dns_adb_createfind2(adb, task, action, arg, name,
2896 				    qname, qtype, options, now,
2897 				    target, port, 0, NULL, findp));
2898 }
2899 
2900 isc_result_t
dns_adb_createfind2(dns_adb_t * adb,isc_task_t * task,isc_taskaction_t action,void * arg,dns_name_t * name,dns_name_t * qname,dns_rdatatype_t qtype,unsigned int options,isc_stdtime_t now,dns_name_t * target,in_port_t port,unsigned int depth,isc_counter_t * qc,dns_adbfind_t ** findp)2901 dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
2902 		    void *arg, dns_name_t *name, dns_name_t *qname,
2903 		    dns_rdatatype_t qtype, unsigned int options,
2904 		    isc_stdtime_t now, dns_name_t *target,
2905 		    in_port_t port, unsigned int depth, isc_counter_t *qc,
2906 		    dns_adbfind_t **findp)
2907 {
2908 	dns_adbfind_t *find;
2909 	dns_adbname_t *adbname;
2910 	int bucket;
2911 	isc_boolean_t want_event, start_at_zone, alias, have_address;
2912 	isc_result_t result;
2913 	unsigned int wanted_addresses;
2914 	unsigned int wanted_fetches;
2915 	unsigned int query_pending;
2916 
2917 	REQUIRE(DNS_ADB_VALID(adb));
2918 	if (task != NULL) {
2919 		REQUIRE(action != NULL);
2920 	}
2921 	REQUIRE(name != NULL);
2922 	REQUIRE(qname != NULL);
2923 	REQUIRE(findp != NULL && *findp == NULL);
2924 	REQUIRE(target == NULL || dns_name_hasbuffer(target));
2925 
2926 	REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
2927 
2928 	result = ISC_R_UNEXPECTED;
2929 	POST(result);
2930 	wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
2931 	wanted_fetches = 0;
2932 	query_pending = 0;
2933 	want_event = ISC_FALSE;
2934 	start_at_zone = ISC_FALSE;
2935 	alias = ISC_FALSE;
2936 
2937 	if (now == 0)
2938 		isc_stdtime_get(&now);
2939 
2940 	/*
2941 	 * XXXMLG  Move this comment somewhere else!
2942 	 *
2943 	 * Look up the name in our internal database.
2944 	 *
2945 	 * Possibilities:  Note that these are not always exclusive.
2946 	 *
2947 	 *      No name found.  In this case, allocate a new name header and
2948 	 *      an initial namehook or two.  If any of these allocations
2949 	 *      fail, clean up and return ISC_R_NOMEMORY.
2950 	 *
2951 	 *      Name found, valid addresses present.  Allocate one addrinfo
2952 	 *      structure for each found and append it to the linked list
2953 	 *      of addresses for this header.
2954 	 *
2955 	 *      Name found, queries pending.  In this case, if a task was
2956 	 *      passed in, allocate a job id, attach it to the name's job
2957 	 *      list and remember to tell the caller that there will be
2958 	 *      more info coming later.
2959 	 */
2960 
2961 	find = new_adbfind(adb);
2962 	if (find == NULL)
2963 		return (ISC_R_NOMEMORY);
2964 
2965 	find->port = port;
2966 
2967 	/*
2968 	 * Remember what types of addresses we are interested in.
2969 	 */
2970 	find->options = options;
2971 	find->flags |= wanted_addresses;
2972 	if (FIND_WANTEVENT(find)) {
2973 		REQUIRE(task != NULL);
2974 	}
2975 
2976 	/*
2977 	 * Try to see if we know anything about this name at all.
2978 	 */
2979 	bucket = DNS_ADB_INVALIDBUCKET;
2980 	adbname = find_name_and_lock(adb, name, find->options, &bucket);
2981 	INSIST(bucket != DNS_ADB_INVALIDBUCKET);
2982 	if (adb->name_sd[bucket]) {
2983 		DP(DEF_LEVEL,
2984 		   "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
2985 		RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2986 		result = ISC_R_SHUTTINGDOWN;
2987 		goto out;
2988 	}
2989 
2990 	/*
2991 	 * Nothing found.  Allocate a new adbname structure for this name.
2992 	 */
2993 	if (adbname == NULL) {
2994 		/*
2995 		 * See if there is any stale name at the end of list, and purge
2996 		 * it if so.
2997 		 */
2998 		check_stale_name(adb, bucket, now);
2999 
3000 		adbname = new_adbname(adb, name);
3001 		if (adbname == NULL) {
3002 			RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
3003 			result = ISC_R_NOMEMORY;
3004 			goto out;
3005 		}
3006 		link_name(adb, bucket, adbname);
3007 		if (FIND_HINTOK(find))
3008 			adbname->flags |= NAME_HINT_OK;
3009 		if (FIND_GLUEOK(find))
3010 			adbname->flags |= NAME_GLUE_OK;
3011 		if (FIND_STARTATZONE(find))
3012 			adbname->flags |= NAME_STARTATZONE;
3013 	} else {
3014 		/* Move this name forward in the LRU list */
3015 		ISC_LIST_UNLINK(adb->names[bucket], adbname, plink);
3016 		ISC_LIST_PREPEND(adb->names[bucket], adbname, plink);
3017 	}
3018 	adbname->last_used = now;
3019 
3020 	/*
3021 	 * Expire old entries, etc.
3022 	 */
3023 	RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE);
3024 
3025 	/*
3026 	 * Do we know that the name is an alias?
3027 	 */
3028 	if (!EXPIRE_OK(adbname->expire_target, now)) {
3029 		/*
3030 		 * Yes, it is.
3031 		 */
3032 		DP(DEF_LEVEL,
3033 		   "dns_adb_createfind: name %p is an alias (cached)",
3034 		   adbname);
3035 		alias = ISC_TRUE;
3036 		goto post_copy;
3037 	}
3038 
3039 	/*
3040 	 * Try to populate the name from the database and/or
3041 	 * start fetches.  First try looking for an A record
3042 	 * in the database.
3043 	 */
3044 	if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
3045 	    && WANT_INET(wanted_addresses)) {
3046 		result = dbfind_name(adbname, now, dns_rdatatype_a);
3047 		if (result == ISC_R_SUCCESS) {
3048 			DP(DEF_LEVEL,
3049 			   "dns_adb_createfind: found A for name %p in db",
3050 			   adbname);
3051 			goto v6;
3052 		}
3053 
3054 		/*
3055 		 * Did we get a CNAME or DNAME?
3056 		 */
3057 		if (result == DNS_R_ALIAS) {
3058 			DP(DEF_LEVEL,
3059 			   "dns_adb_createfind: name %p is an alias",
3060 			   adbname);
3061 			alias = ISC_TRUE;
3062 			goto post_copy;
3063 		}
3064 
3065 		/*
3066 		 * If the name doesn't exist at all, don't bother with
3067 		 * v6 queries; they won't work.
3068 		 *
3069 		 * If the name does exist but we didn't get our data, go
3070 		 * ahead and try AAAA.
3071 		 *
3072 		 * If the result is neither of these, try a fetch for A.
3073 		 */
3074 		if (NXDOMAIN_RESULT(result))
3075 			goto fetch;
3076 		else if (NXRRSET_RESULT(result))
3077 			goto v6;
3078 
3079 		if (!NAME_FETCH_V4(adbname))
3080 			wanted_fetches |= DNS_ADBFIND_INET;
3081 	}
3082 
3083  v6:
3084 	if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
3085 	    && WANT_INET6(wanted_addresses)) {
3086 		result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
3087 		if (result == ISC_R_SUCCESS) {
3088 			DP(DEF_LEVEL,
3089 			   "dns_adb_createfind: found AAAA for name %p",
3090 			   adbname);
3091 			goto fetch;
3092 		}
3093 
3094 		/*
3095 		 * Did we get a CNAME or DNAME?
3096 		 */
3097 		if (result == DNS_R_ALIAS) {
3098 			DP(DEF_LEVEL,
3099 			   "dns_adb_createfind: name %p is an alias",
3100 			   adbname);
3101 			alias = ISC_TRUE;
3102 			goto post_copy;
3103 		}
3104 
3105 		/*
3106 		 * Listen to negative cache hints, and don't start
3107 		 * another query.
3108 		 */
3109 		if (NCACHE_RESULT(result) || AUTH_NX(result))
3110 			goto fetch;
3111 
3112 		if (!NAME_FETCH_V6(adbname))
3113 			wanted_fetches |= DNS_ADBFIND_INET6;
3114 	}
3115 
3116  fetch:
3117 	if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
3118 	    (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
3119 		have_address = ISC_TRUE;
3120 	else
3121 		have_address = ISC_FALSE;
3122 	if (wanted_fetches != 0 &&
3123 	    ! (FIND_AVOIDFETCHES(find) && have_address)) {
3124 		/*
3125 		 * We're missing at least one address family.  Either the
3126 		 * caller hasn't instructed us to avoid fetches, or we don't
3127 		 * know anything about any of the address families that would
3128 		 * be acceptable so we have to launch fetches.
3129 		 */
3130 
3131 		if (FIND_STARTATZONE(find))
3132 			start_at_zone = ISC_TRUE;
3133 
3134 		/*
3135 		 * Start V4.
3136 		 */
3137 		if (WANT_INET(wanted_fetches) &&
3138 		    fetch_name(adbname, start_at_zone, depth, qc,
3139 			       dns_rdatatype_a) == ISC_R_SUCCESS) {
3140 			DP(DEF_LEVEL,
3141 			   "dns_adb_createfind: started A fetch for name %p",
3142 			   adbname);
3143 		}
3144 
3145 		/*
3146 		 * Start V6.
3147 		 */
3148 		if (WANT_INET6(wanted_fetches) &&
3149 		    fetch_name(adbname, start_at_zone, depth, qc,
3150 			       dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
3151 			DP(DEF_LEVEL,
3152 			   "dns_adb_createfind: "
3153 			   "started AAAA fetch for name %p",
3154 			   adbname);
3155 		}
3156 	}
3157 
3158 	/*
3159 	 * Run through the name and copy out the bits we are
3160 	 * interested in.
3161 	 */
3162 	copy_namehook_lists(adb, find, qname, qtype, adbname, now);
3163 
3164  post_copy:
3165 	if (NAME_FETCH_V4(adbname))
3166 		query_pending |= DNS_ADBFIND_INET;
3167 	if (NAME_FETCH_V6(adbname))
3168 		query_pending |= DNS_ADBFIND_INET6;
3169 
3170 	/*
3171 	 * Attach to the name's query list if there are queries
3172 	 * already running, and we have been asked to.
3173 	 */
3174 	want_event = ISC_TRUE;
3175 	if (!FIND_WANTEVENT(find))
3176 		want_event = ISC_FALSE;
3177 	if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
3178 		want_event = ISC_FALSE;
3179 	if ((wanted_addresses & query_pending) == 0)
3180 		want_event = ISC_FALSE;
3181 	if (alias)
3182 		want_event = ISC_FALSE;
3183 	if (want_event) {
3184 		find->adbname = adbname;
3185 		find->name_bucket = bucket;
3186 		ISC_LIST_APPEND(adbname->finds, find, plink);
3187 		find->query_pending = (query_pending & wanted_addresses);
3188 		find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
3189 		find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
3190 		DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
3191 		   find, adbname);
3192 	} else {
3193 		/*
3194 		 * Remove the flag so the caller knows there will never
3195 		 * be an event, and set internal flags to fake that
3196 		 * the event was sent and freed, so dns_adb_destroyfind() will
3197 		 * do the right thing.
3198 		 */
3199 		find->query_pending = (query_pending & wanted_addresses);
3200 		find->options &= ~DNS_ADBFIND_WANTEVENT;
3201 		find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
3202 		find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
3203 	}
3204 
3205 	find->partial_result |= (adbname->partial_result & wanted_addresses);
3206 	if (alias) {
3207 		if (target != NULL) {
3208 			result = dns_name_copy(&adbname->target, target, NULL);
3209 			if (result != ISC_R_SUCCESS)
3210 				goto out;
3211 		}
3212 		result = DNS_R_ALIAS;
3213 	} else
3214 		result = ISC_R_SUCCESS;
3215 
3216 	/*
3217 	 * Copy out error flags from the name structure into the find.
3218 	 */
3219 	find->result_v4 = find_err_map[adbname->fetch_err];
3220 	find->result_v6 = find_err_map[adbname->fetch6_err];
3221 
3222  out:
3223 	if (find != NULL) {
3224 		*findp = find;
3225 
3226 		if (want_event) {
3227 			isc_task_t *taskp;
3228 
3229 			INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
3230 			taskp = NULL;
3231 			isc_task_attach(task, &taskp);
3232 			find->event.ev_sender = taskp;
3233 			find->event.ev_action = action;
3234 			find->event.ev_arg = arg;
3235 		}
3236 	}
3237 
3238 	UNLOCK(&adb->namelocks[bucket]);
3239 
3240 	return (result);
3241 }
3242 
3243 void
dns_adb_destroyfind(dns_adbfind_t ** findp)3244 dns_adb_destroyfind(dns_adbfind_t **findp) {
3245 	dns_adbfind_t *find;
3246 	dns_adbentry_t *entry;
3247 	dns_adbaddrinfo_t *ai;
3248 	int bucket;
3249 	dns_adb_t *adb;
3250 	isc_boolean_t overmem;
3251 
3252 	REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
3253 	find = *findp;
3254 	*findp = NULL;
3255 
3256 	LOCK(&find->lock);
3257 
3258 	DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
3259 
3260 	adb = find->adb;
3261 	REQUIRE(DNS_ADB_VALID(adb));
3262 
3263 	REQUIRE(FIND_EVENTFREED(find));
3264 
3265 	bucket = find->name_bucket;
3266 	INSIST(bucket == DNS_ADB_INVALIDBUCKET);
3267 
3268 	UNLOCK(&find->lock);
3269 
3270 	/*
3271 	 * The find doesn't exist on any list, and nothing is locked.
3272 	 * Return the find to the memory pool, and decrement the adb's
3273 	 * reference count.
3274 	 */
3275 	overmem = isc_mem_isovermem(adb->mctx);
3276 	ai = ISC_LIST_HEAD(find->list);
3277 	while (ai != NULL) {
3278 		ISC_LIST_UNLINK(find->list, ai, publink);
3279 		entry = ai->entry;
3280 		ai->entry = NULL;
3281 		INSIST(DNS_ADBENTRY_VALID(entry));
3282 		RUNTIME_CHECK(dec_entry_refcnt(adb, overmem, entry, ISC_TRUE) ==
3283 			      ISC_FALSE);
3284 		free_adbaddrinfo(adb, &ai);
3285 		ai = ISC_LIST_HEAD(find->list);
3286 	}
3287 
3288 	/*
3289 	 * WARNING:  The find is freed with the adb locked.  This is done
3290 	 * to avoid a race condition where we free the find, some other
3291 	 * thread tests to see if it should be destroyed, detects it should
3292 	 * be, destroys it, and then we try to lock it for our check, but the
3293 	 * lock is destroyed.
3294 	 */
3295 	LOCK(&adb->lock);
3296 	if (free_adbfind(adb, &find))
3297 		check_exit(adb);
3298 	UNLOCK(&adb->lock);
3299 }
3300 
3301 void
dns_adb_cancelfind(dns_adbfind_t * find)3302 dns_adb_cancelfind(dns_adbfind_t *find) {
3303 	isc_event_t *ev;
3304 	isc_task_t *task;
3305 	dns_adb_t *adb;
3306 	int bucket;
3307 	int unlock_bucket;
3308 
3309 	LOCK(&find->lock);
3310 
3311 	DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
3312 
3313 	adb = find->adb;
3314 	REQUIRE(DNS_ADB_VALID(adb));
3315 
3316 	REQUIRE(!FIND_EVENTFREED(find));
3317 	REQUIRE(FIND_WANTEVENT(find));
3318 
3319 	bucket = find->name_bucket;
3320 	if (bucket == DNS_ADB_INVALIDBUCKET)
3321 		goto cleanup;
3322 
3323 	/*
3324 	 * We need to get the adbname's lock to unlink the find.
3325 	 */
3326 	unlock_bucket = bucket;
3327 	violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
3328 	bucket = find->name_bucket;
3329 	if (bucket != DNS_ADB_INVALIDBUCKET) {
3330 		ISC_LIST_UNLINK(find->adbname->finds, find, plink);
3331 		find->adbname = NULL;
3332 		find->name_bucket = DNS_ADB_INVALIDBUCKET;
3333 	}
3334 	UNLOCK(&adb->namelocks[unlock_bucket]);
3335 	bucket = DNS_ADB_INVALIDBUCKET;
3336 	POST(bucket);
3337 
3338  cleanup:
3339 
3340 	if (!FIND_EVENTSENT(find)) {
3341 		ev = &find->event;
3342 		task = ev->ev_sender;
3343 		ev->ev_sender = find;
3344 		ev->ev_type = DNS_EVENT_ADBCANCELED;
3345 		ev->ev_destroy = event_free;
3346 		ev->ev_destroy_arg = find;
3347 		find->result_v4 = ISC_R_CANCELED;
3348 		find->result_v6 = ISC_R_CANCELED;
3349 
3350 		DP(DEF_LEVEL, "sending event %p to task %p for find %p",
3351 		   ev, task, find);
3352 
3353 		isc_task_sendanddetach(&task, (isc_event_t **)&ev);
3354 	}
3355 
3356 	UNLOCK(&find->lock);
3357 }
3358 
3359 void
dns_adb_dump(dns_adb_t * adb,FILE * f)3360 dns_adb_dump(dns_adb_t *adb, FILE *f) {
3361 	unsigned int i;
3362 	isc_stdtime_t now;
3363 
3364 	REQUIRE(DNS_ADB_VALID(adb));
3365 	REQUIRE(f != NULL);
3366 
3367 	/*
3368 	 * Lock the adb itself, lock all the name buckets, then lock all
3369 	 * the entry buckets.  This should put the adb into a state where
3370 	 * nothing can change, so we can iterate through everything and
3371 	 * print at our leisure.
3372 	 */
3373 
3374 	LOCK(&adb->lock);
3375 	isc_stdtime_get(&now);
3376 
3377 	for (i = 0; i < adb->nnames; i++)
3378 		RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE);
3379 	for (i = 0; i < adb->nentries; i++)
3380 		RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE);
3381 
3382 	dump_adb(adb, f, ISC_FALSE, now);
3383 	UNLOCK(&adb->lock);
3384 }
3385 
3386 static void
dump_ttl(FILE * f,const char * legend,isc_stdtime_t value,isc_stdtime_t now)3387 dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
3388 	if (value == INT_MAX)
3389 		return;
3390 	fprintf(f, " [%s TTL %d]", legend, value - now);
3391 }
3392 
3393 static void
dump_adb(dns_adb_t * adb,FILE * f,isc_boolean_t debug,isc_stdtime_t now)3394 dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
3395 	unsigned int i;
3396 	dns_adbname_t *name;
3397 	dns_adbentry_t *entry;
3398 
3399 	fprintf(f, ";\n; Address database dump\n;\n");
3400 	if (debug)
3401 		fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
3402 			adb, adb->erefcnt, adb->irefcnt,
3403 			isc_mempool_getallocated(adb->nhmp));
3404 
3405 	for (i = 0; i < adb->nnames; i++)
3406 		LOCK(&adb->namelocks[i]);
3407 	for (i = 0; i < adb->nentries; i++)
3408 		LOCK(&adb->entrylocks[i]);
3409 
3410 	/*
3411 	 * Dump the names
3412 	 */
3413 	for (i = 0; i < adb->nnames; i++) {
3414 		name = ISC_LIST_HEAD(adb->names[i]);
3415 		if (name == NULL)
3416 			continue;
3417 		if (debug)
3418 			fprintf(f, "; bucket %d\n", i);
3419 		for (;
3420 		     name != NULL;
3421 		     name = ISC_LIST_NEXT(name, plink))
3422 		{
3423 			if (debug)
3424 				fprintf(f, "; name %p (flags %08x)\n",
3425 					name, name->flags);
3426 
3427 			fprintf(f, "; ");
3428 			print_dns_name(f, &name->name);
3429 			if (dns_name_countlabels(&name->target) > 0) {
3430 				fprintf(f, " alias ");
3431 				print_dns_name(f, &name->target);
3432 			}
3433 
3434 			dump_ttl(f, "v4", name->expire_v4, now);
3435 			dump_ttl(f, "v6", name->expire_v6, now);
3436 			dump_ttl(f, "target", name->expire_target, now);
3437 
3438 			fprintf(f, " [v4 %s] [v6 %s]",
3439 				errnames[name->fetch_err],
3440 				errnames[name->fetch6_err]);
3441 
3442 			fprintf(f, "\n");
3443 
3444 			print_namehook_list(f, "v4", adb,
3445 					    &name->v4, debug, now);
3446 			print_namehook_list(f, "v6", adb,
3447 					    &name->v6, debug, now);
3448 
3449 			if (debug)
3450 				print_fetch_list(f, name);
3451 			if (debug)
3452 				print_find_list(f, name);
3453 		}
3454 	}
3455 
3456 	fprintf(f, ";\n; Unassociated entries\n;\n");
3457 
3458 	for (i = 0; i < adb->nentries; i++) {
3459 		entry = ISC_LIST_HEAD(adb->entries[i]);
3460 		while (entry != NULL) {
3461 			if (entry->nh == 0)
3462 				dump_entry(f, adb, entry, debug, now);
3463 			entry = ISC_LIST_NEXT(entry, plink);
3464 		}
3465 	}
3466 
3467 	/*
3468 	 * Unlock everything
3469 	 */
3470 	for (i = 0; i < adb->nentries; i++)
3471 		UNLOCK(&adb->entrylocks[i]);
3472 	for (i = 0; i < adb->nnames; i++)
3473 		UNLOCK(&adb->namelocks[i]);
3474 }
3475 
3476 static void
dump_entry(FILE * f,dns_adb_t * adb,dns_adbentry_t * entry,isc_boolean_t debug,isc_stdtime_t now)3477 dump_entry(FILE *f, dns_adb_t *adb, dns_adbentry_t *entry,
3478 	   isc_boolean_t debug, isc_stdtime_t now)
3479 {
3480 	char addrbuf[ISC_NETADDR_FORMATSIZE];
3481 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
3482 	isc_netaddr_t netaddr;
3483 	dns_adblameinfo_t *li;
3484 
3485 #ifndef ENABLE_FETCHLIMIT
3486 	UNUSED(adb);
3487 #endif /* !ENABLE_FETCHLIMIT */
3488 
3489 	isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
3490 	isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
3491 
3492 	if (debug)
3493 		fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
3494 
3495 	fprintf(f, ";\t%s [srtt %u] [flags %08x]",
3496 		addrbuf, entry->srtt, entry->flags);
3497 	if (entry->expires != 0)
3498 		fprintf(f, " [ttl %d]", entry->expires - now);
3499 
3500 #ifdef ENABLE_FETCHLIMIT
3501 	if (adb != NULL && adb->quota != 0 && adb->atr_freq != 0) {
3502 		fprintf(f, " [atr %0.2f] [quota %d]",
3503 			entry->atr, entry->quota);
3504 	}
3505 #endif /* ENABLE_FETCHLIMIT */
3506 
3507 	fprintf(f, "\n");
3508 	for (li = ISC_LIST_HEAD(entry->lameinfo);
3509 	     li != NULL;
3510 	     li = ISC_LIST_NEXT(li, plink))
3511 	{
3512 		fprintf(f, ";\t\t");
3513 		print_dns_name(f, &li->qname);
3514 		dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf));
3515 		fprintf(f, " %s [lame TTL %d]\n", typebuf,
3516 			li->lame_timer - now);
3517 	}
3518 }
3519 
3520 void
dns_adb_dumpfind(dns_adbfind_t * find,FILE * f)3521 dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
3522 	char tmp[512];
3523 	const char *tmpp;
3524 	dns_adbaddrinfo_t *ai;
3525 	isc_sockaddr_t *sa;
3526 
3527 	/*
3528 	 * Not used currently, in the API Just In Case we
3529 	 * want to dump out the name and/or entries too.
3530 	 */
3531 
3532 	LOCK(&find->lock);
3533 
3534 	fprintf(f, ";Find %p\n", find);
3535 	fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
3536 		find->query_pending, find->partial_result,
3537 		find->options, find->flags);
3538 	fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
3539 		find->name_bucket, find->adbname, find->event.ev_sender);
3540 
3541 	ai = ISC_LIST_HEAD(find->list);
3542 	if (ai != NULL)
3543 		fprintf(f, "\tAddresses:\n");
3544 	while (ai != NULL) {
3545 		sa = &ai->sockaddr;
3546 		switch (sa->type.sa.sa_family) {
3547 		case AF_INET:
3548 			tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
3549 					 tmp, sizeof(tmp));
3550 			break;
3551 		case AF_INET6:
3552 			tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
3553 					 tmp, sizeof(tmp));
3554 			break;
3555 		default:
3556 			tmpp = "UnkFamily";
3557 		}
3558 
3559 		if (tmpp == NULL)
3560 			tmpp = "BadAddress";
3561 
3562 		fprintf(f, "\t\tentry %p, flags %08x"
3563 			" srtt %u addr %s\n",
3564 			ai->entry, ai->flags, ai->srtt, tmpp);
3565 
3566 		ai = ISC_LIST_NEXT(ai, publink);
3567 	}
3568 
3569 	UNLOCK(&find->lock);
3570 }
3571 
3572 static void
print_dns_name(FILE * f,dns_name_t * name)3573 print_dns_name(FILE *f, dns_name_t *name) {
3574 	char buf[DNS_NAME_FORMATSIZE];
3575 
3576 	INSIST(f != NULL);
3577 
3578 	dns_name_format(name, buf, sizeof(buf));
3579 	fprintf(f, "%s", buf);
3580 }
3581 
3582 static void
print_namehook_list(FILE * f,const char * legend,dns_adb_t * adb,dns_adbnamehooklist_t * list,isc_boolean_t debug,isc_stdtime_t now)3583 print_namehook_list(FILE *f, const char *legend,
3584 		    dns_adb_t *adb, dns_adbnamehooklist_t *list,
3585 		    isc_boolean_t debug, isc_stdtime_t now)
3586 {
3587 	dns_adbnamehook_t *nh;
3588 
3589 	for (nh = ISC_LIST_HEAD(*list);
3590 	     nh != NULL;
3591 	     nh = ISC_LIST_NEXT(nh, plink))
3592 	{
3593 		if (debug)
3594 			fprintf(f, ";\tHook(%s) %p\n", legend, nh);
3595 		dump_entry(f, adb, nh->entry, debug, now);
3596 	}
3597 }
3598 
3599 static inline void
print_fetch(FILE * f,dns_adbfetch_t * ft,const char * type)3600 print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) {
3601 	fprintf(f, "\t\tFetch(%s): %p -> { fetch %p }\n",
3602 		type, ft, ft->fetch);
3603 }
3604 
3605 static void
print_fetch_list(FILE * f,dns_adbname_t * n)3606 print_fetch_list(FILE *f, dns_adbname_t *n) {
3607 	if (NAME_FETCH_A(n))
3608 		print_fetch(f, n->fetch_a, "A");
3609 	if (NAME_FETCH_AAAA(n))
3610 		print_fetch(f, n->fetch_aaaa, "AAAA");
3611 }
3612 
3613 static void
print_find_list(FILE * f,dns_adbname_t * name)3614 print_find_list(FILE *f, dns_adbname_t *name) {
3615 	dns_adbfind_t *find;
3616 
3617 	find = ISC_LIST_HEAD(name->finds);
3618 	while (find != NULL) {
3619 		dns_adb_dumpfind(find, f);
3620 		find = ISC_LIST_NEXT(find, plink);
3621 	}
3622 }
3623 
3624 static isc_result_t
dbfind_name(dns_adbname_t * adbname,isc_stdtime_t now,dns_rdatatype_t rdtype)3625 dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype)
3626 {
3627 	isc_result_t result;
3628 	dns_rdataset_t rdataset;
3629 	dns_adb_t *adb;
3630 	dns_fixedname_t foundname;
3631 	dns_name_t *fname;
3632 
3633 	INSIST(DNS_ADBNAME_VALID(adbname));
3634 	adb = adbname->adb;
3635 	INSIST(DNS_ADB_VALID(adb));
3636 	INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
3637 
3638 	dns_fixedname_init(&foundname);
3639 	fname = dns_fixedname_name(&foundname);
3640 	dns_rdataset_init(&rdataset);
3641 
3642 	if (rdtype == dns_rdatatype_a)
3643 		adbname->fetch_err = FIND_ERR_UNEXPECTED;
3644 	else
3645 		adbname->fetch6_err = FIND_ERR_UNEXPECTED;
3646 
3647 	/*
3648 	 * We need to specify whether to search static-stub zones (if
3649 	 * configured) depending on whether this is a "start at zone" lookup,
3650 	 * i.e., whether it's a "bailiwick" glue.  If it's bailiwick (in which
3651 	 * case NAME_STARTATZONE is set) we need to stop the search at any
3652 	 * matching static-stub zone without looking into the cache to honor
3653 	 * the configuration on which server we should send queries to.
3654 	 */
3655 	result = dns_view_find2(adb->view, &adbname->name, rdtype, now,
3656 				NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0,
3657 				ISC_TF(NAME_HINTOK(adbname)),
3658 				(adbname->flags & NAME_STARTATZONE) != 0 ?
3659 				ISC_TRUE : ISC_FALSE,
3660 				NULL, NULL, fname, &rdataset, NULL);
3661 
3662 	/* XXXVIX this switch statement is too sparse to gen a jump table. */
3663 	switch (result) {
3664 	case DNS_R_GLUE:
3665 	case DNS_R_HINT:
3666 	case ISC_R_SUCCESS:
3667 		/*
3668 		 * Found in the database.  Even if we can't copy out
3669 		 * any information, return success, or else a fetch
3670 		 * will be made, which will only make things worse.
3671 		 */
3672 		if (rdtype == dns_rdatatype_a)
3673 			adbname->fetch_err = FIND_ERR_SUCCESS;
3674 		else
3675 			adbname->fetch6_err = FIND_ERR_SUCCESS;
3676 		result = import_rdataset(adbname, &rdataset, now);
3677 		break;
3678 	case DNS_R_NXDOMAIN:
3679 	case DNS_R_NXRRSET:
3680 		/*
3681 		 * We're authoritative and the data doesn't exist.
3682 		 * Make up a negative cache entry so we don't ask again
3683 		 * for a while.
3684 		 *
3685 		 * XXXRTH  What time should we use?  I'm putting in 30 seconds
3686 		 * for now.
3687 		 */
3688 		if (rdtype == dns_rdatatype_a) {
3689 			adbname->expire_v4 = now + 30;
3690 			DP(NCACHE_LEVEL,
3691 			   "adb name %p: Caching auth negative entry for A",
3692 			   adbname);
3693 			if (result == DNS_R_NXDOMAIN)
3694 				adbname->fetch_err = FIND_ERR_NXDOMAIN;
3695 			else
3696 				adbname->fetch_err = FIND_ERR_NXRRSET;
3697 		} else {
3698 			DP(NCACHE_LEVEL,
3699 			   "adb name %p: Caching auth negative entry for AAAA",
3700 			   adbname);
3701 			adbname->expire_v6 = now + 30;
3702 			if (result == DNS_R_NXDOMAIN)
3703 				adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3704 			else
3705 				adbname->fetch6_err = FIND_ERR_NXRRSET;
3706 		}
3707 		break;
3708 	case DNS_R_NCACHENXDOMAIN:
3709 	case DNS_R_NCACHENXRRSET:
3710 		/*
3711 		 * We found a negative cache entry.  Pull the TTL from it
3712 		 * so we won't ask again for a while.
3713 		 */
3714 		rdataset.ttl = ttlclamp(rdataset.ttl);
3715 		if (rdtype == dns_rdatatype_a) {
3716 			adbname->expire_v4 = rdataset.ttl + now;
3717 			if (result == DNS_R_NCACHENXDOMAIN)
3718 				adbname->fetch_err = FIND_ERR_NXDOMAIN;
3719 			else
3720 				adbname->fetch_err = FIND_ERR_NXRRSET;
3721 			DP(NCACHE_LEVEL,
3722 			  "adb name %p: Caching negative entry for A (ttl %u)",
3723 			   adbname, rdataset.ttl);
3724 		} else {
3725 			DP(NCACHE_LEVEL,
3726 		       "adb name %p: Caching negative entry for AAAA (ttl %u)",
3727 			   adbname, rdataset.ttl);
3728 			adbname->expire_v6 = rdataset.ttl + now;
3729 			if (result == DNS_R_NCACHENXDOMAIN)
3730 				adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3731 			else
3732 				adbname->fetch6_err = FIND_ERR_NXRRSET;
3733 		}
3734 		break;
3735 	case DNS_R_CNAME:
3736 	case DNS_R_DNAME:
3737 		/*
3738 		 * Clear the hint and glue flags, so this will match
3739 		 * more often.
3740 		 */
3741 		adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
3742 
3743 		rdataset.ttl = ttlclamp(rdataset.ttl);
3744 		clean_target(adb, &adbname->target);
3745 		adbname->expire_target = INT_MAX;
3746 		result = set_target(adb, &adbname->name, fname, &rdataset,
3747 				    &adbname->target);
3748 		if (result == ISC_R_SUCCESS) {
3749 			result = DNS_R_ALIAS;
3750 			DP(NCACHE_LEVEL,
3751 			   "adb name %p: caching alias target",
3752 			   adbname);
3753 			adbname->expire_target = rdataset.ttl + now;
3754 		}
3755 		if (rdtype == dns_rdatatype_a)
3756 			adbname->fetch_err = FIND_ERR_SUCCESS;
3757 		else
3758 			adbname->fetch6_err = FIND_ERR_SUCCESS;
3759 		break;
3760 	}
3761 
3762 	if (dns_rdataset_isassociated(&rdataset))
3763 		dns_rdataset_disassociate(&rdataset);
3764 
3765 	return (result);
3766 }
3767 
3768 static void
fetch_callback(isc_task_t * task,isc_event_t * ev)3769 fetch_callback(isc_task_t *task, isc_event_t *ev) {
3770 	dns_fetchevent_t *dev;
3771 	dns_adbname_t *name;
3772 	dns_adb_t *adb;
3773 	dns_adbfetch_t *fetch;
3774 	int bucket;
3775 	isc_eventtype_t ev_status;
3776 	isc_stdtime_t now;
3777 	isc_result_t result;
3778 	unsigned int address_type;
3779 	isc_boolean_t want_check_exit = ISC_FALSE;
3780 
3781 	UNUSED(task);
3782 
3783 	INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
3784 	dev = (dns_fetchevent_t *)ev;
3785 	name = ev->ev_arg;
3786 	INSIST(DNS_ADBNAME_VALID(name));
3787 	adb = name->adb;
3788 	INSIST(DNS_ADB_VALID(adb));
3789 
3790 	bucket = name->lock_bucket;
3791 	LOCK(&adb->namelocks[bucket]);
3792 
3793 	INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
3794 	address_type = 0;
3795 	if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
3796 		address_type = DNS_ADBFIND_INET;
3797 		fetch = name->fetch_a;
3798 		name->fetch_a = NULL;
3799 	} else if (NAME_FETCH_AAAA(name)
3800 		   && (name->fetch_aaaa->fetch == dev->fetch)) {
3801 		address_type = DNS_ADBFIND_INET6;
3802 		fetch = name->fetch_aaaa;
3803 		name->fetch_aaaa = NULL;
3804 	} else
3805 		fetch = NULL;
3806 
3807 	INSIST(address_type != 0 && fetch != NULL);
3808 
3809 	dns_resolver_destroyfetch(&fetch->fetch);
3810 	dev->fetch = NULL;
3811 
3812 	ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
3813 
3814 	/*
3815 	 * Cleanup things we don't care about.
3816 	 */
3817 	if (dev->node != NULL)
3818 		dns_db_detachnode(dev->db, &dev->node);
3819 	if (dev->db != NULL)
3820 		dns_db_detach(&dev->db);
3821 
3822 	/*
3823 	 * If this name is marked as dead, clean up, throwing away
3824 	 * potentially good data.
3825 	 */
3826 	if (NAME_DEAD(name)) {
3827 		free_adbfetch(adb, &fetch);
3828 		isc_event_free(&ev);
3829 
3830 		want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
3831 
3832 		UNLOCK(&adb->namelocks[bucket]);
3833 
3834 		if (want_check_exit) {
3835 			LOCK(&adb->lock);
3836 			check_exit(adb);
3837 			UNLOCK(&adb->lock);
3838 		}
3839 
3840 		return;
3841 	}
3842 
3843 	isc_stdtime_get(&now);
3844 
3845 	/*
3846 	 * If we got a negative cache response, remember it.
3847 	 */
3848 	if (NCACHE_RESULT(dev->result)) {
3849 		dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3850 		if (address_type == DNS_ADBFIND_INET) {
3851 			DP(NCACHE_LEVEL, "adb fetch name %p: "
3852 			   "caching negative entry for A (ttl %u)",
3853 			   name, dev->rdataset->ttl);
3854 			name->expire_v4 = ISC_MIN(name->expire_v4,
3855 						  dev->rdataset->ttl + now);
3856 			if (dev->result == DNS_R_NCACHENXDOMAIN)
3857 				name->fetch_err = FIND_ERR_NXDOMAIN;
3858 			else
3859 				name->fetch_err = FIND_ERR_NXRRSET;
3860 			inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
3861 		} else {
3862 			DP(NCACHE_LEVEL, "adb fetch name %p: "
3863 			   "caching negative entry for AAAA (ttl %u)",
3864 			   name, dev->rdataset->ttl);
3865 			name->expire_v6 = ISC_MIN(name->expire_v6,
3866 						  dev->rdataset->ttl + now);
3867 			if (dev->result == DNS_R_NCACHENXDOMAIN)
3868 				name->fetch6_err = FIND_ERR_NXDOMAIN;
3869 			else
3870 				name->fetch6_err = FIND_ERR_NXRRSET;
3871 			inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
3872 		}
3873 		goto out;
3874 	}
3875 
3876 	/*
3877 	 * Handle CNAME/DNAME.
3878 	 */
3879 	if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
3880 		dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3881 		clean_target(adb, &name->target);
3882 		name->expire_target = INT_MAX;
3883 		result = set_target(adb, &name->name,
3884 				    dns_fixedname_name(&dev->foundname),
3885 				    dev->rdataset,
3886 				    &name->target);
3887 		if (result == ISC_R_SUCCESS) {
3888 			DP(NCACHE_LEVEL,
3889 			   "adb fetch name %p: caching alias target",
3890 			   name);
3891 			name->expire_target = dev->rdataset->ttl + now;
3892 		}
3893 		goto check_result;
3894 	}
3895 
3896 	/*
3897 	 * Did we get back junk?  If so, and there are no more fetches
3898 	 * sitting out there, tell all the finds about it.
3899 	 */
3900 	if (dev->result != ISC_R_SUCCESS) {
3901 		char buf[DNS_NAME_FORMATSIZE];
3902 
3903 		dns_name_format(&name->name, buf, sizeof(buf));
3904 		DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
3905 		   buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
3906 		   dns_result_totext(dev->result));
3907 		/*
3908 		 * Don't record a failure unless this is the initial
3909 		 * fetch of a chain.
3910 		 */
3911 		if (fetch->depth > 1)
3912 			goto out;
3913 		/* XXXMLG Don't pound on bad servers. */
3914 		if (address_type == DNS_ADBFIND_INET) {
3915 			name->expire_v4 = ISC_MIN(name->expire_v4, now + 10);
3916 			name->fetch_err = FIND_ERR_FAILURE;
3917 			inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
3918 		} else {
3919 			name->expire_v6 = ISC_MIN(name->expire_v6, now + 10);
3920 			name->fetch6_err = FIND_ERR_FAILURE;
3921 			inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
3922 		}
3923 		goto out;
3924 	}
3925 
3926 	/*
3927 	 * We got something potentially useful.
3928 	 */
3929 	result = import_rdataset(name, &fetch->rdataset, now);
3930 
3931  check_result:
3932 	if (result == ISC_R_SUCCESS) {
3933 		ev_status = DNS_EVENT_ADBMOREADDRESSES;
3934 		if (address_type == DNS_ADBFIND_INET)
3935 			name->fetch_err = FIND_ERR_SUCCESS;
3936 		else
3937 			name->fetch6_err = FIND_ERR_SUCCESS;
3938 	}
3939 
3940  out:
3941 	free_adbfetch(adb, &fetch);
3942 	isc_event_free(&ev);
3943 
3944 	clean_finds_at_name(name, ev_status, address_type);
3945 
3946 	UNLOCK(&adb->namelocks[bucket]);
3947 }
3948 
3949 static isc_result_t
fetch_name(dns_adbname_t * adbname,isc_boolean_t start_at_zone,unsigned int depth,isc_counter_t * qc,dns_rdatatype_t type)3950 fetch_name(dns_adbname_t *adbname, isc_boolean_t start_at_zone,
3951 	   unsigned int depth, isc_counter_t *qc, dns_rdatatype_t type)
3952 {
3953 	isc_result_t result;
3954 	dns_adbfetch_t *fetch = NULL;
3955 	dns_adb_t *adb;
3956 	dns_fixedname_t fixed;
3957 	dns_name_t *name;
3958 	dns_rdataset_t rdataset;
3959 	dns_rdataset_t *nameservers;
3960 	unsigned int options;
3961 
3962 	INSIST(DNS_ADBNAME_VALID(adbname));
3963 	adb = adbname->adb;
3964 	INSIST(DNS_ADB_VALID(adb));
3965 
3966 	INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
3967 	       (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
3968 
3969 	adbname->fetch_err = FIND_ERR_NOTFOUND;
3970 
3971 	name = NULL;
3972 	nameservers = NULL;
3973 	dns_rdataset_init(&rdataset);
3974 
3975 	options = DNS_FETCHOPT_NOVALIDATE;
3976 	if (start_at_zone) {
3977 		DP(ENTER_LEVEL,
3978 		   "fetch_name: starting at zone for name %p",
3979 		   adbname);
3980 		dns_fixedname_init(&fixed);
3981 		name = dns_fixedname_name(&fixed);
3982 		result = dns_view_findzonecut2(adb->view, &adbname->name, name,
3983 					       0, 0, ISC_TRUE, ISC_FALSE,
3984 					       &rdataset, NULL);
3985 		if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
3986 			goto cleanup;
3987 		nameservers = &rdataset;
3988 		options |= DNS_FETCHOPT_UNSHARED;
3989 	}
3990 
3991 	fetch = new_adbfetch(adb);
3992 	if (fetch == NULL) {
3993 		result = ISC_R_NOMEMORY;
3994 		goto cleanup;
3995 	}
3996 	fetch->depth = depth;
3997 
3998 	result = dns_resolver_createfetch3(adb->view->resolver, &adbname->name,
3999 					   type, name, nameservers, NULL,
4000 					   NULL, 0, options, depth, qc,
4001 					   adb->task, fetch_callback, adbname,
4002 					   &fetch->rdataset, NULL,
4003 					   &fetch->fetch);
4004 	if (result != ISC_R_SUCCESS)
4005 		goto cleanup;
4006 
4007 	if (type == dns_rdatatype_a) {
4008 		adbname->fetch_a = fetch;
4009 		inc_stats(adb, dns_resstatscounter_gluefetchv4);
4010 	} else {
4011 		adbname->fetch_aaaa = fetch;
4012 		inc_stats(adb, dns_resstatscounter_gluefetchv6);
4013 	}
4014 	fetch = NULL;  /* Keep us from cleaning this up below. */
4015 
4016  cleanup:
4017 	if (fetch != NULL)
4018 		free_adbfetch(adb, &fetch);
4019 	if (dns_rdataset_isassociated(&rdataset))
4020 		dns_rdataset_disassociate(&rdataset);
4021 
4022 	return (result);
4023 }
4024 
4025 /*
4026  * XXXMLG Needs to take a find argument and an address info, no zone or adb,
4027  * since these can be extracted from the find itself.
4028  */
4029 isc_result_t
dns_adb_marklame(dns_adb_t * adb,dns_adbaddrinfo_t * addr,dns_name_t * qname,dns_rdatatype_t qtype,isc_stdtime_t expire_time)4030 dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname,
4031 		 dns_rdatatype_t qtype, isc_stdtime_t expire_time)
4032 {
4033 	dns_adblameinfo_t *li;
4034 	int bucket;
4035 	isc_result_t result = ISC_R_SUCCESS;
4036 
4037 	REQUIRE(DNS_ADB_VALID(adb));
4038 	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4039 	REQUIRE(qname != NULL);
4040 
4041 	bucket = addr->entry->lock_bucket;
4042 	LOCK(&adb->entrylocks[bucket]);
4043 	li = ISC_LIST_HEAD(addr->entry->lameinfo);
4044 	while (li != NULL &&
4045 	       (li->qtype != qtype || !dns_name_equal(qname, &li->qname)))
4046 		li = ISC_LIST_NEXT(li, plink);
4047 	if (li != NULL) {
4048 		if (expire_time > li->lame_timer)
4049 			li->lame_timer = expire_time;
4050 		goto unlock;
4051 	}
4052 	li = new_adblameinfo(adb, qname, qtype);
4053 	if (li == NULL) {
4054 		result = ISC_R_NOMEMORY;
4055 		goto unlock;
4056 	}
4057 
4058 	li->lame_timer = expire_time;
4059 
4060 	ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink);
4061  unlock:
4062 	UNLOCK(&adb->entrylocks[bucket]);
4063 
4064 	return (result);
4065 }
4066 
4067 void
dns_adb_adjustsrtt(dns_adb_t * adb,dns_adbaddrinfo_t * addr,unsigned int rtt,unsigned int factor)4068 dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
4069 		   unsigned int rtt, unsigned int factor)
4070 {
4071 	int bucket;
4072 	isc_stdtime_t now = 0;
4073 
4074 	REQUIRE(DNS_ADB_VALID(adb));
4075 	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4076 	REQUIRE(factor <= 10);
4077 
4078 	bucket = addr->entry->lock_bucket;
4079 	LOCK(&adb->entrylocks[bucket]);
4080 
4081 	if (addr->entry->expires == 0 || factor == DNS_ADB_RTTADJAGE)
4082 		isc_stdtime_get(&now);
4083 	adjustsrtt(addr, rtt, factor, now);
4084 
4085 	UNLOCK(&adb->entrylocks[bucket]);
4086 }
4087 
4088 void
dns_adb_agesrtt(dns_adb_t * adb,dns_adbaddrinfo_t * addr,isc_stdtime_t now)4089 dns_adb_agesrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr, isc_stdtime_t now) {
4090 	int bucket;
4091 
4092 	REQUIRE(DNS_ADB_VALID(adb));
4093 	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4094 
4095 	bucket = addr->entry->lock_bucket;
4096 	LOCK(&adb->entrylocks[bucket]);
4097 
4098 	adjustsrtt(addr, 0, DNS_ADB_RTTADJAGE, now);
4099 
4100 	UNLOCK(&adb->entrylocks[bucket]);
4101 }
4102 
4103 static void
adjustsrtt(dns_adbaddrinfo_t * addr,unsigned int rtt,unsigned int factor,isc_stdtime_t now)4104 adjustsrtt(dns_adbaddrinfo_t *addr, unsigned int rtt, unsigned int factor,
4105 	   isc_stdtime_t now)
4106 {
4107 	isc_uint64_t new_srtt;
4108 
4109 	if (factor == DNS_ADB_RTTADJAGE) {
4110 		if (addr->entry->lastage != now) {
4111 			new_srtt = addr->entry->srtt;
4112 			new_srtt <<= 9;
4113 			new_srtt -= addr->entry->srtt;
4114 			new_srtt >>= 9;
4115 			addr->entry->lastage = now;
4116 		} else
4117 			new_srtt = addr->entry->srtt;
4118 	} else
4119 		new_srtt = (addr->entry->srtt / 10 * factor)
4120 			+ (rtt / 10 * (10 - factor));
4121 
4122 	new_srtt &= 0xffffffff;
4123 	addr->entry->srtt = (unsigned int) new_srtt;
4124 	addr->srtt = (unsigned int) new_srtt;
4125 
4126 	if (addr->entry->expires == 0)
4127 		addr->entry->expires = now + ADB_ENTRY_WINDOW;
4128 }
4129 
4130 void
dns_adb_changeflags(dns_adb_t * adb,dns_adbaddrinfo_t * addr,unsigned int bits,unsigned int mask)4131 dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
4132 		    unsigned int bits, unsigned int mask)
4133 {
4134 	int bucket;
4135 	isc_stdtime_t now;
4136 
4137 	REQUIRE(DNS_ADB_VALID(adb));
4138 	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4139 
4140 	REQUIRE((bits & ENTRY_IS_DEAD) == 0);
4141 	REQUIRE((mask & ENTRY_IS_DEAD) == 0);
4142 
4143 	bucket = addr->entry->lock_bucket;
4144 	LOCK(&adb->entrylocks[bucket]);
4145 
4146 	addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
4147 	if (addr->entry->expires == 0) {
4148 		isc_stdtime_get(&now);
4149 		addr->entry->expires = now + ADB_ENTRY_WINDOW;
4150 	}
4151 
4152 	/*
4153 	 * Note that we do not update the other bits in addr->flags with
4154 	 * the most recent values from addr->entry->flags.
4155 	 */
4156 	addr->flags = (addr->flags & ~mask) | (bits & mask);
4157 
4158 	UNLOCK(&adb->entrylocks[bucket]);
4159 }
4160 
4161 #ifdef ENABLE_FETCHLIMIT
4162 /*
4163  * (10000 / ((10 + n) / 10)^(3/2)) for n in 0..99.
4164  * These will be used to make quota adjustments.
4165  */
4166 static int quota_adj[] = {
4167 	10000, 8668, 7607, 6747, 6037, 5443, 4941, 4512, 4141,
4168 	3818, 3536, 3286, 3065, 2867, 2690, 2530, 2385, 2254,
4169 	2134, 2025, 1925, 1832, 1747, 1668, 1595, 1527, 1464,
4170 	1405, 1350, 1298, 1250, 1205, 1162, 1121, 1083, 1048,
4171 	1014, 981, 922, 894, 868, 843, 820, 797, 775, 755,
4172 	735, 716, 698, 680, 664, 648, 632, 618, 603, 590, 577,
4173 	564, 552, 540, 529, 518, 507, 497, 487, 477, 468, 459,
4174 	450, 442, 434, 426, 418, 411, 404, 397, 390, 383, 377,
4175 	370, 364, 358, 353, 347, 342, 336, 331, 326, 321, 316,
4176 	312, 307, 303, 298, 294, 290, 286, 282, 278
4177 };
4178 
4179 /*
4180  * Caller must hold adbentry lock
4181  */
4182 static void
maybe_adjust_quota(dns_adb_t * adb,dns_adbaddrinfo_t * addr,isc_boolean_t timeout)4183 maybe_adjust_quota(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
4184 		   isc_boolean_t timeout)
4185 {
4186 	double tr;
4187 
4188 	UNUSED(adb);
4189 
4190 	if (adb->quota == 0 || adb->atr_freq == 0)
4191 		return;
4192 
4193 	if (timeout)
4194 		addr->entry->timeouts++;
4195 
4196 	if (addr->entry->completed++ <= adb->atr_freq)
4197 		return;
4198 
4199 	/*
4200 	 * Calculate an exponential rolling average of the timeout ratio
4201 	 *
4202 	 * XXX: Integer arithmetic might be better than floating point
4203 	 */
4204 	tr = (double) addr->entry->timeouts / addr->entry->completed;
4205 	addr->entry->timeouts = addr->entry->completed = 0;
4206 	INSIST(addr->entry->atr >= 0.0);
4207 	INSIST(addr->entry->atr <= 1.0);
4208 	INSIST(adb->atr_discount >= 0.0);
4209 	INSIST(adb->atr_discount <= 1.0);
4210 	addr->entry->atr *= 1.0 - adb->atr_discount;
4211 	addr->entry->atr += tr * adb->atr_discount;
4212 	addr->entry->atr = ISC_CLAMP(addr->entry->atr, 0.0, 1.0);
4213 
4214 	if (addr->entry->atr < adb->atr_low && addr->entry->mode > 0) {
4215 		addr->entry->quota = adb->quota *
4216 			quota_adj[--addr->entry->mode] / 10000;
4217 		log_quota(addr->entry, "atr %0.2f, quota increased to %d",
4218 			  addr->entry->atr, addr->entry->quota);
4219 	} else if (addr->entry->atr > adb->atr_high && addr->entry->mode < 99) {
4220 		addr->entry->quota = adb->quota *
4221 			quota_adj[++addr->entry->mode] / 10000;
4222 		log_quota(addr->entry, "atr %0.2f, quota decreased to %d",
4223 			  addr->entry->atr, addr->entry->quota);
4224 	}
4225 
4226 	/* Ensure we don't drop to zero */
4227 	if (addr->entry->quota == 0)
4228 		addr->entry->quota = 1;
4229 }
4230 #endif /* ENABLE_FETCHLIMIT */
4231 
4232 void
dns_adb_plainresponse(dns_adb_t * adb,dns_adbaddrinfo_t * addr)4233 dns_adb_plainresponse(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
4234 	int bucket;
4235 
4236 	REQUIRE(DNS_ADB_VALID(adb));
4237 	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4238 
4239 	bucket = addr->entry->lock_bucket;
4240 	LOCK(&adb->entrylocks[bucket]);
4241 
4242 #ifdef ENABLE_FETCHLIMIT
4243 	maybe_adjust_quota(adb, addr, ISC_FALSE);
4244 #endif /* ENABLE_FETCHLIMIT */
4245 
4246 	UNLOCK(&adb->entrylocks[bucket]);
4247 }
4248 
4249 void
dns_adb_timeout(dns_adb_t * adb,dns_adbaddrinfo_t * addr)4250 dns_adb_timeout(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
4251 #ifdef ENABLE_FETCHLIMIT
4252 	int bucket;
4253 
4254 	REQUIRE(DNS_ADB_VALID(adb));
4255 	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4256 
4257 	bucket = addr->entry->lock_bucket;
4258 	LOCK(&adb->entrylocks[bucket]);
4259 	maybe_adjust_quota(adb, addr, ISC_TRUE);
4260 	UNLOCK(&adb->entrylocks[bucket]);
4261 #else
4262 	UNUSED(adb);
4263 	UNUSED(addr);
4264 
4265 	return;
4266 #endif /* !ENABLE_FETCHLIMIT */
4267 }
4268 
4269 isc_result_t
dns_adb_findaddrinfo(dns_adb_t * adb,isc_sockaddr_t * sa,dns_adbaddrinfo_t ** addrp,isc_stdtime_t now)4270 dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
4271 		     dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
4272 {
4273 	int bucket;
4274 	dns_adbentry_t *entry;
4275 	dns_adbaddrinfo_t *addr;
4276 	isc_result_t result;
4277 	in_port_t port;
4278 
4279 	REQUIRE(DNS_ADB_VALID(adb));
4280 	REQUIRE(addrp != NULL && *addrp == NULL);
4281 
4282 	UNUSED(now);
4283 
4284 	result = ISC_R_SUCCESS;
4285 	bucket = DNS_ADB_INVALIDBUCKET;
4286 	entry = find_entry_and_lock(adb, sa, &bucket, now);
4287 	INSIST(bucket != DNS_ADB_INVALIDBUCKET);
4288 	if (adb->entry_sd[bucket]) {
4289 		result = ISC_R_SHUTTINGDOWN;
4290 		goto unlock;
4291 	}
4292 	if (entry == NULL) {
4293 		/*
4294 		 * We don't know anything about this address.
4295 		 */
4296 		entry = new_adbentry(adb);
4297 		if (entry == NULL) {
4298 			result = ISC_R_NOMEMORY;
4299 			goto unlock;
4300 		}
4301 		entry->sockaddr = *sa;
4302 		link_entry(adb, bucket, entry);
4303 		DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
4304 	} else
4305 		DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
4306 
4307 	port = isc_sockaddr_getport(sa);
4308 	addr = new_adbaddrinfo(adb, entry, port);
4309 	if (addr == NULL) {
4310 		result = ISC_R_NOMEMORY;
4311 	} else {
4312 		inc_entry_refcnt(adb, entry, ISC_FALSE);
4313 		*addrp = addr;
4314 	}
4315 
4316  unlock:
4317 	UNLOCK(&adb->entrylocks[bucket]);
4318 
4319 	return (result);
4320 }
4321 
4322 void
dns_adb_freeaddrinfo(dns_adb_t * adb,dns_adbaddrinfo_t ** addrp)4323 dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
4324 	dns_adbaddrinfo_t *addr;
4325 	dns_adbentry_t *entry;
4326 	int bucket;
4327 	isc_stdtime_t now;
4328 	isc_boolean_t want_check_exit = ISC_FALSE;
4329 	isc_boolean_t overmem;
4330 
4331 	REQUIRE(DNS_ADB_VALID(adb));
4332 	REQUIRE(addrp != NULL);
4333 	addr = *addrp;
4334 	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4335 	entry = addr->entry;
4336 	REQUIRE(DNS_ADBENTRY_VALID(entry));
4337 
4338 	*addrp = NULL;
4339 	overmem = isc_mem_isovermem(adb->mctx);
4340 
4341 	bucket = addr->entry->lock_bucket;
4342 	LOCK(&adb->entrylocks[bucket]);
4343 
4344 	if (entry->expires == 0) {
4345 		isc_stdtime_get(&now);
4346 		entry->expires = now + ADB_ENTRY_WINDOW;
4347 	}
4348 
4349 	want_check_exit = dec_entry_refcnt(adb, overmem, entry, ISC_FALSE);
4350 
4351 	UNLOCK(&adb->entrylocks[bucket]);
4352 
4353 	addr->entry = NULL;
4354 	free_adbaddrinfo(adb, &addr);
4355 
4356 	if (want_check_exit) {
4357 		LOCK(&adb->lock);
4358 		check_exit(adb);
4359 		UNLOCK(&adb->lock);
4360 	}
4361 }
4362 
4363 void
dns_adb_flush(dns_adb_t * adb)4364 dns_adb_flush(dns_adb_t *adb) {
4365 	unsigned int i;
4366 
4367 	INSIST(DNS_ADB_VALID(adb));
4368 
4369 	LOCK(&adb->lock);
4370 
4371 	/*
4372 	 * Call our cleanup routines.
4373 	 */
4374 	for (i = 0; i < adb->nnames; i++)
4375 		RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
4376 	for (i = 0; i < adb->nentries; i++)
4377 		RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
4378 
4379 #ifdef DUMP_ADB_AFTER_CLEANING
4380 	dump_adb(adb, stdout, ISC_TRUE, INT_MAX);
4381 #endif
4382 
4383 	UNLOCK(&adb->lock);
4384 }
4385 
4386 void
dns_adb_flushname(dns_adb_t * adb,dns_name_t * name)4387 dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
4388 	dns_adbname_t *adbname;
4389 	dns_adbname_t *nextname;
4390 	int bucket;
4391 
4392 	INSIST(DNS_ADB_VALID(adb));
4393 
4394 	LOCK(&adb->lock);
4395 	bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames;
4396 	LOCK(&adb->namelocks[bucket]);
4397 	adbname = ISC_LIST_HEAD(adb->names[bucket]);
4398 	while (adbname != NULL) {
4399 		nextname = ISC_LIST_NEXT(adbname, plink);
4400 		if (!NAME_DEAD(adbname) &&
4401 		    dns_name_equal(name, &adbname->name)) {
4402 			RUNTIME_CHECK(kill_name(&adbname,
4403 						DNS_EVENT_ADBCANCELED) ==
4404 				      ISC_FALSE);
4405 		}
4406 		adbname = nextname;
4407 	}
4408 	UNLOCK(&adb->namelocks[bucket]);
4409 	UNLOCK(&adb->lock);
4410 }
4411 
4412 static void
water(void * arg,int mark)4413 water(void *arg, int mark) {
4414 	/*
4415 	 * We're going to change the way to handle overmem condition: use
4416 	 * isc_mem_isovermem() instead of storing the state via this callback,
4417 	 * since the latter way tends to cause race conditions.
4418 	 * To minimize the change, and in case we re-enable the callback
4419 	 * approach, however, keep this function at the moment.
4420 	 */
4421 
4422 	dns_adb_t *adb = arg;
4423 	isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
4424 
4425 	REQUIRE(DNS_ADB_VALID(adb));
4426 
4427 	DP(ISC_LOG_DEBUG(1),
4428 	   "adb reached %s water mark", overmem ? "high" : "low");
4429 }
4430 
4431 void
dns_adb_setadbsize(dns_adb_t * adb,size_t size)4432 dns_adb_setadbsize(dns_adb_t *adb, size_t size) {
4433 	size_t hiwater, lowater;
4434 
4435 	INSIST(DNS_ADB_VALID(adb));
4436 
4437 	if (size != 0U && size < DNS_ADB_MINADBSIZE)
4438 		size = DNS_ADB_MINADBSIZE;
4439 
4440 	hiwater = size - (size >> 3);   /* Approximately 7/8ths. */
4441 	lowater = size - (size >> 2);   /* Approximately 3/4ths. */
4442 
4443 	if (size == 0U || hiwater == 0U || lowater == 0U)
4444 		isc_mem_setwater(adb->mctx, water, adb, 0, 0);
4445 	else
4446 		isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);
4447 }
4448 
4449 void
dns_adb_setquota(dns_adb_t * adb,isc_uint32_t quota,isc_uint32_t freq,double low,double high,double discount)4450 dns_adb_setquota(dns_adb_t *adb, isc_uint32_t quota, isc_uint32_t freq,
4451 		 double low, double high, double discount)
4452 {
4453 #ifdef ENABLE_FETCHLIMIT
4454 	REQUIRE(DNS_ADB_VALID(adb));
4455 
4456 	adb->quota = quota;
4457 	adb->atr_freq = freq;
4458 	adb->atr_low = low;
4459 	adb->atr_high = high;
4460 	adb->atr_discount = discount;
4461 #else
4462 	UNUSED(adb);
4463 	UNUSED(quota);
4464 	UNUSED(freq);
4465 	UNUSED(low);
4466 	UNUSED(high);
4467 	UNUSED(discount);
4468 
4469 	return;
4470 #endif /* !ENABLE_FETCHLIMIT */
4471 }
4472 
4473 isc_boolean_t
dns_adbentry_overquota(dns_adbentry_t * entry)4474 dns_adbentry_overquota(dns_adbentry_t *entry) {
4475 #ifdef ENABLE_FETCHLIMIT
4476 	isc_boolean_t block;
4477 	REQUIRE(DNS_ADBENTRY_VALID(entry));
4478 	block = ISC_TF(entry->quota != 0 && entry->active >= entry->quota);
4479 	return (block);
4480 #else
4481 	UNUSED(entry);
4482 
4483 	return (ISC_FALSE);
4484 #endif /* !ENABLE_FETCHLIMIT */
4485 }
4486 
4487 void
dns_adb_beginudpfetch(dns_adb_t * adb,dns_adbaddrinfo_t * addr)4488 dns_adb_beginudpfetch(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
4489 #ifdef ENABLE_FETCHLIMIT
4490 	int bucket;
4491 
4492 	REQUIRE(DNS_ADB_VALID(adb));
4493 	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4494 
4495 	bucket = addr->entry->lock_bucket;
4496 
4497 	LOCK(&adb->entrylocks[bucket]);
4498 	addr->entry->active++;
4499 	UNLOCK(&adb->entrylocks[bucket]);
4500 #else
4501 	UNUSED(adb);
4502 	UNUSED(addr);
4503 
4504 	return;
4505 #endif /* !ENABLE_FETCHLIMIT */
4506 }
4507 
4508 void
dns_adb_endudpfetch(dns_adb_t * adb,dns_adbaddrinfo_t * addr)4509 dns_adb_endudpfetch(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
4510 #ifdef ENABLE_FETCHLIMIT
4511 	int bucket;
4512 
4513 	REQUIRE(DNS_ADB_VALID(adb));
4514 	REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4515 
4516 	bucket = addr->entry->lock_bucket;
4517 
4518 	LOCK(&adb->entrylocks[bucket]);
4519 	if (addr->entry->active > 0)
4520 		addr->entry->active--;
4521 	UNLOCK(&adb->entrylocks[bucket]);
4522 #else
4523 	UNUSED(adb);
4524 	UNUSED(addr);
4525 
4526 	return;
4527 #endif /* !ENABLE_FETCHLIMIT */
4528 }
4529