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