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