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