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