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