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