adb.c 95.6 KB
Newer Older
Michael Graff's avatar
Michael Graff committed
1
/*
Bob Halley's avatar
Bob Halley committed
2
 * Copyright (C) 1999, 2000  Internet Software Consortium.
Michael Graff's avatar
Michael Graff committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 * 
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

18
19
20
21
/*
 * Implementation notes
 * --------------------
 *
22
 * In finds, if task == NULL, no events will be generated, and no events
23
 * have been sent.  If task != NULL but taskaction == NULL, an event has been
Bob Halley's avatar
Bob Halley committed
24
 * posted but not yet freed.  If neither are NULL, no event was posted.
25
26
27
 *
 */

28
29
30
31
32
/*
 * After we have cleaned all buckets, dump the database contents.
 */
#define DUMP_ADB_AFTER_CLEANING

Michael Graff's avatar
Michael Graff committed
33
34
#include <config.h>

Mark Andrews's avatar
Mark Andrews committed
35
#include <limits.h>
36

37
#include <isc/mutexblock.h>
Michael Graff's avatar
Michael Graff committed
38
#include <isc/random.h>
39
#include <isc/task.h>
Michael Graff's avatar
Michael Graff committed
40
#include <isc/timer.h>
Michael Graff's avatar
Michael Graff committed
41
#include <isc/util.h>
Michael Graff's avatar
Michael Graff committed
42

Bob Halley's avatar
Bob Halley committed
43
#include <dns/a6.h>
Michael Graff's avatar
Michael Graff committed
44
#include <dns/adb.h>
Michael Graff's avatar
Michael Graff committed
45
#include <dns/db.h>
46
#include <dns/events.h>
47
#include <dns/log.h>
Michael Graff's avatar
Michael Graff committed
48
49
#include <dns/rdata.h>
#include <dns/rdataset.h>
Michael Graff's avatar
fix    
Michael Graff committed
50
#include <dns/resolver.h>
51
#include <dns/result.h>
52

53
54
55
56
57
58
59
60
61
62
#define DNS_ADB_MAGIC		  0x44616462	/* Dadb. */
#define DNS_ADB_VALID(x)	  ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
#define DNS_ADBNAME_MAGIC	  0x6164624e	/* adbN. */
#define DNS_ADBNAME_VALID(x)	  ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
#define DNS_ADBNAMEHOOK_MAGIC	  0x61644e48	/* adNH. */
#define DNS_ADBNAMEHOOK_VALID(x)  ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
#define DNS_ADBZONEINFO_MAGIC	  0x6164625a	/* adbZ. */
#define DNS_ADBZONEINFO_VALID(x)  ISC_MAGIC_VALID(x, DNS_ADBZONEINFO_MAGIC)
#define DNS_ADBENTRY_MAGIC	  0x61646245	/* adbE. */
#define DNS_ADBENTRY_VALID(x)	  ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
Michael Graff's avatar
Michael Graff committed
63
#define DNS_ADBFETCH_MAGIC	  0x61644634	/* adF4. */
Michael Graff's avatar
Michael Graff committed
64
#define DNS_ADBFETCH_VALID(x)	  ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
Bob Halley's avatar
Bob Halley committed
65
66
#define DNS_ADBFETCH6_MAGIC	  0x61644636	/* adF6. */
#define DNS_ADBFETCH6_VALID(x)	  ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
Michael Graff's avatar
Michael Graff committed
67

68
/*
Bob Halley's avatar
Bob Halley committed
69
70
71
72
73
 * The number of buckets needs to be a prime (for good hashing).
 *
 * XXXRTH  How many buckets do we need?
 *
 * This value must be coordinated with CLEAN_SECONDS (below).
74
 */
75
76
77
78
#define NBUCKETS	       1009	/* how many buckets for names/addrs */

/*
 * For type 3 negative cache entries, we will remember that the address is
79
80
81
 * broken for this long.  XXXMLG This is also used for actual addresses, too.
 * The intent is to keep us from constantly asking about A/A6/AAAA records
 * if the zone has extremely low TTLs.
82
 */
83
#define ADB_CACHE_MINIMUM	10	/* seconds */
84

Bob Halley's avatar
Bob Halley committed
85
/*
86
 * Clean CLEAN_BUCKETS buckets every CLEAN_SECONDS.
Bob Halley's avatar
Bob Halley committed
87
 */
88
89
90
91
92
93
94
#define CLEAN_PERIOD		3600 /* one pass through every N seconds */
#define CLEAN_BUCKETS		((NBUCKETS / CLEAN_PERIOD) + 0.5)
#if CLEAN_BUCKET < 1
#undef CLEAN_BUCKETS
#define CLEAN_BUCKETS 1
#endif
#define CLEAN_SECONDS		(CLEAN_PERIOD * CLEAN_BUCKETS / NBUCKETS)
95
96
97
98
#if CLEAN_SECONDS < 1
#undef CLEAN_SECONDS
#define CLEAN_SECONDS		1
#endif
Michael Graff's avatar
Michael Graff committed
99

100
101
#define FREE_ITEMS		64	/* free count for memory pools */
#define FILL_COUNT		16	/* fill count for memory pools */
102

Michael Graff's avatar
Michael Graff committed
103
104
#define DNS_ADB_INVALIDBUCKET (-1)	/* invalid bucket address */

105
typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
Michael Graff's avatar
Michael Graff committed
106
typedef struct dns_adbnamehook dns_adbnamehook_t;
Michael Graff's avatar
Michael Graff committed
107
typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
Michael Graff's avatar
Michael Graff committed
108
typedef struct dns_adbzoneinfo dns_adbzoneinfo_t;
109
typedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t;
Michael Graff's avatar
Michael Graff committed
110
typedef struct dns_adbfetch dns_adbfetch_t;
Bob Halley's avatar
Bob Halley committed
111
typedef struct dns_adbfetch6 dns_adbfetch6_t;
Michael Graff's avatar
Michael Graff committed
112
113

struct dns_adb {
Michael Graff's avatar
Michael Graff committed
114
115
116
	unsigned int			magic;

	isc_mutex_t			lock;
117
	isc_mutex_t			ilock;
Michael Graff's avatar
Michael Graff committed
118
	isc_mem_t		       *mctx;
Michael Graff's avatar
Michael Graff committed
119
	dns_view_t		       *view;
Michael Graff's avatar
fix    
Michael Graff committed
120
	isc_timermgr_t		       *timermgr;
Michael Graff's avatar
Michael Graff committed
121
	isc_timer_t		       *timer;
Michael Graff's avatar
fix    
Michael Graff committed
122
	isc_taskmgr_t		       *taskmgr;
Michael Graff's avatar
Michael Graff committed
123
	isc_task_t		       *task;
Michael Graff's avatar
Michael Graff committed
124

Michael Graff's avatar
Michael Graff committed
125
	isc_interval_t			tick_interval;
126
	int				next_cleanbucket;
Michael Graff's avatar
Michael Graff committed
127

128
129
	unsigned int			irefcnt;
	unsigned int			erefcnt;
Michael Graff's avatar
Michael Graff committed
130

131
	isc_mutex_t			mplock;
Michael Graff's avatar
Michael Graff committed
132
133
134
135
	isc_mempool_t		       *nmp;	/* dns_adbname_t */
	isc_mempool_t		       *nhmp;	/* dns_adbnamehook_t */
	isc_mempool_t		       *zimp;	/* dns_adbzoneinfo_t */
	isc_mempool_t		       *emp;	/* dns_adbentry_t */
136
	isc_mempool_t		       *ahmp;	/* dns_adbfind_t */
Michael Graff's avatar
Michael Graff committed
137
	isc_mempool_t		       *aimp;	/* dns_adbaddrinfo_t */
Michael Graff's avatar
Michael Graff committed
138
	isc_mempool_t		       *afmp;	/* dns_adbfetch_t */
Bob Halley's avatar
Bob Halley committed
139
	isc_mempool_t		       *af6mp;	/* dns_adbfetch6_t */
Michael Graff's avatar
Michael Graff committed
140

Michael Graff's avatar
Michael Graff committed
141
142
	isc_random_t			rand;

143
144
	/*
	 * Bucketized locks and lists for names.
Bob Halley's avatar
Bob Halley committed
145
146
	 *
	 * XXXRTH  Have a per-bucket structure that contains all of these?
147
	 */
148
149
150
151
	dns_adbnamelist_t		names[NBUCKETS];
	isc_mutex_t			namelocks[NBUCKETS];
	isc_boolean_t			name_sd[NBUCKETS];
	unsigned int			name_refcnt[NBUCKETS];
152
153
154

	/*
	 * Bucketized locks for entries.
Bob Halley's avatar
Bob Halley committed
155
156
	 *
	 * XXXRTH  Have a per-bucket structure that contains all of these?
157
	 */
158
159
	dns_adbentrylist_t		entries[NBUCKETS];
	isc_mutex_t			entrylocks[NBUCKETS];
160
161
	isc_boolean_t			entry_sd[NBUCKETS];
	unsigned int			entry_refcnt[NBUCKETS];
162
163
164
165
166

	isc_event_t			cevent;
	isc_boolean_t			cevent_sent;
	isc_boolean_t			shutting_down;
	isc_eventlist_t			whenshutdown;
Michael Graff's avatar
Michael Graff committed
167
168
};

Bob Halley's avatar
Bob Halley committed
169
170
171
172
/*
 * XXXMLG  Document these structures.
 */

Michael Graff's avatar
Michael Graff committed
173
174
struct dns_adbname {
	unsigned int			magic;
175
	dns_name_t			name;
176
	dns_adb_t		       *adb;
Michael Graff's avatar
Michael Graff committed
177
	unsigned int			partial_result;
178
	unsigned int			flags;
Michael Graff's avatar
Michael Graff committed
179
	int				lock_bucket;
180
181
	dns_name_t			target;
	isc_stdtime_t			expire_target;
Michael Graff's avatar
Michael Graff committed
182
183
	isc_stdtime_t			expire_v4;
	isc_stdtime_t			expire_v6;
Bob Halley's avatar
Bob Halley committed
184
	unsigned int			chains;
Michael Graff's avatar
Michael Graff committed
185
186
	dns_adbnamehooklist_t		v4;
	dns_adbnamehooklist_t		v6;
187
188
	dns_adbfetch_t		       *fetch_a;
	dns_adbfetch_t		       *fetch_aaaa;
Bob Halley's avatar
Bob Halley committed
189
	ISC_LIST(dns_adbfetch6_t)	fetches_a6;
Bob Halley's avatar
Bob Halley committed
190
	dns_adbfindlist_t		finds;
191
	ISC_LINK(dns_adbname_t)		plink;
Michael Graff's avatar
Michael Graff committed
192
193
};

Michael Graff's avatar
Michael Graff committed
194
195
196
197
198
199
200
201
struct dns_adbfetch {
	unsigned int			magic;
	dns_adbnamehook_t	       *namehook;
	dns_adbentry_t		       *entry;
	dns_fetch_t		       *fetch;
	dns_rdataset_t			rdataset;
};

Bob Halley's avatar
Bob Halley committed
202
203
struct dns_adbfetch6 {
	unsigned int			magic;
204
	unsigned int			flags;
Bob Halley's avatar
Bob Halley committed
205
206
207
208
209
210
211
212
	dns_adbnamehook_t	       *namehook;
	dns_adbentry_t		       *entry;
	dns_fetch_t		       *fetch;
	dns_rdataset_t			rdataset;
	dns_a6context_t			a6ctx;
	ISC_LINK(dns_adbfetch6_t)	plink;
};

Michael Graff's avatar
Michael Graff committed
213
214
215
216
217
218
219
220
221
/*
 * dns_adbnamehook_t
 *
 * This is a small widget that dangles off a dns_adbname_t.  It contains a
 * pointer to the address information about this host, and a link to the next
 * namehook that will contain the next address this host has.
 */
struct dns_adbnamehook {
	unsigned int			magic;
222
	dns_adbentry_t		       *entry;
223
	ISC_LINK(dns_adbnamehook_t)	plink;
Michael Graff's avatar
Michael Graff committed
224
225
};

Michael Graff's avatar
Michael Graff committed
226
227
228
229
230
231
232
233
234
235
/*
 * dns_adbzoneinfo_t
 *
 * This is a small widget that holds zone-specific information about an
 * address.  Currently limited to lameness, but could just as easily be
 * extended to other types of information about zones.
 */
struct dns_adbzoneinfo {
	unsigned int			magic;

Michael Graff's avatar
Michael Graff committed
236
	dns_name_t			zone;
237
	isc_stdtime_t			lame_timer;
Michael Graff's avatar
Michael Graff committed
238

239
	ISC_LINK(dns_adbzoneinfo_t)	plink;
Michael Graff's avatar
Michael Graff committed
240
241
242
243
244
245
};

/*
 * An address entry.  It holds quite a bit of information about addresses,
 * including edns state, rtt, and of course the address of the host.
 */
Michael Graff's avatar
Michael Graff committed
246
struct dns_adbentry {
Michael Graff's avatar
Michael Graff committed
247
248
	unsigned int			magic;

249
	int				lock_bucket;
Michael Graff's avatar
Michael Graff committed
250
	unsigned int			refcnt;
Michael Graff's avatar
Michael Graff committed
251
252

	unsigned int			flags;
Michael Graff's avatar
Michael Graff committed
253
254
	int				edns_level;	/* must be int! */
	int				goodness;	/* bad < 0 <= good */
Michael Graff's avatar
Michael Graff committed
255
256
	unsigned int			srtt;
	isc_sockaddr_t			sockaddr;
257
	isc_stdtime_t			expires;
258
	isc_stdtime_t			avoid_bitstring;
Michael Graff's avatar
Michael Graff committed
259
260

	ISC_LIST(dns_adbzoneinfo_t)	zoneinfo;
261
	ISC_LINK(dns_adbentry_t)	plink;
Michael Graff's avatar
Michael Graff committed
262
263
};

Michael Graff's avatar
Michael Graff committed
264
/*
265
266
 * Internal functions (and prototypes).
 */
267
static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
Michael Graff's avatar
Michael Graff committed
268
269
270
271
static inline void free_adbname(dns_adb_t *, dns_adbname_t **);
static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
						 dns_adbentry_t *);
static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
272
static inline dns_adbzoneinfo_t *new_adbzoneinfo(dns_adb_t *, dns_name_t *);
Michael Graff's avatar
Michael Graff committed
273
274
275
static inline void free_adbzoneinfo(dns_adb_t *, dns_adbzoneinfo_t **);
static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
276
277
static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
static inline void free_adbfind(dns_adb_t *, dns_adbfind_t **);
Michael Graff's avatar
Michael Graff committed
278
279
static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *,
						 dns_adbentry_t *);
Michael Graff's avatar
Michael Graff committed
280
281
static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
Michael Graff's avatar
Michael Graff committed
282
283
static inline dns_adbfetch6_t *new_adbfetch6(dns_adb_t *, dns_adbname_t *,
					     dns_a6context_t *);
Bob Halley's avatar
Bob Halley committed
284
static inline void free_adbfetch6(dns_adb_t *, dns_adbfetch6_t **);
Michael Graff's avatar
Michael Graff committed
285
static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
286
						unsigned int, int *);
Michael Graff's avatar
Michael Graff committed
287
288
static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
						  isc_sockaddr_t *, int *);
289
static void dump_adb(dns_adb_t *, FILE *);
Michael Graff's avatar
Michael Graff committed
290
291
static void print_dns_name(FILE *, dns_name_t *);
static void print_namehook_list(FILE *, dns_adbname_t *);
292
static void print_find_list(FILE *, dns_adbname_t *);
293
static void print_fetch_list(FILE *, dns_adbname_t *);
294
static inline void dec_adb_irefcnt(dns_adb_t *);
295
static inline void inc_adb_erefcnt(dns_adb_t *, isc_boolean_t);
Michael Graff's avatar
Michael Graff committed
296
static inline void dec_adb_erefcnt(dns_adb_t *, isc_boolean_t);
Michael Graff's avatar
Michael Graff committed
297
298
299
300
static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
				    isc_boolean_t);
static inline void dec_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
				    isc_boolean_t);
301
static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
Michael Graff's avatar
Michael Graff committed
302
static void clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
303
static void clean_target(dns_adb_t *, dns_name_t *);
304
305
static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
				unsigned int);
Michael Graff's avatar
Michael Graff committed
306
static void check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
307
static void cancel_fetches_at_name(dns_adbname_t *);
308
static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
309
				dns_rdatatype_t);
310
311
static isc_result_t fetch_name_v4(dns_adbname_t *, isc_boolean_t);
static isc_result_t fetch_name_aaaa(dns_adbname_t *);
312
static isc_result_t fetch_name_a6(dns_adbname_t *, isc_boolean_t);
Michael Graff's avatar
Michael Graff committed
313
static inline void check_exit(dns_adb_t *);
Michael Graff's avatar
Michael Graff committed
314
static void timer_cleanup(isc_task_t *, isc_event_t *);
315
static void destroy(dns_adb_t *);
Michael Graff's avatar
Michael Graff committed
316
static void shutdown_names(dns_adb_t *);
317
static void shutdown_entries(dns_adb_t *);
Michael Graff's avatar
Michael Graff committed
318
319
static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
static inline void unlink_name(dns_adb_t *, dns_adbname_t *);
320
321
static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
static inline void unlink_entry(dns_adb_t *, dns_adbentry_t *);
Michael Graff's avatar
Michael Graff committed
322
323
static void kill_name(dns_adbname_t **, isc_eventtype_t);
static void fetch_callback_a6(isc_task_t *, isc_event_t *);
324
static isc_result_t dbfind_a6(dns_adbname_t *, isc_stdtime_t);
Michael Graff's avatar
Michael Graff committed
325

326
327
328
329
330
/*
 * MUST NOT overlap DNS_ADBFIND_* flags!
 */
#define FIND_EVENT_SENT		0x40000000
#define FIND_EVENT_FREED	0x80000000
331
332
#define FIND_EVENTSENT(h)	(((h)->flags & FIND_EVENT_SENT) != 0)
#define FIND_EVENTFREED(h)	(((h)->flags & FIND_EVENT_FREED) != 0)
333

334
335
#define NAME_NEEDS_POKE		0x80000000
#define NAME_IS_DEAD		0x40000000
336
337
#define NAME_HINT_OK		DNS_ADBFIND_HINTOK
#define NAME_GLUE_OK		DNS_ADBFIND_GLUEOK
338
339
#define NAME_DEAD(n)		(((n)->flags & NAME_IS_DEAD) != 0)
#define NAME_NEEDSPOKE(n)	(((n)->flags & NAME_NEEDS_POKE) != 0)
340
341
#define NAME_HINTOK(n)		(((n)->flags & NAME_HINT_OK) != 0)
#define NAME_GLUEOK(n)		(((n)->flags & NAME_GLUE_OK) != 0)
342

343
344
345
346
347
348
349
/*
 * To the name, address classes are all that really exist.  If it has a
 * V6 address it doesn't care if it came from an A6 chain or an AAAA query.
 */
#define NAME_HAS_V4(n)		(!ISC_LIST_EMPTY((n)->v4))
#define NAME_HAS_V6(n)		(!ISC_LIST_EMPTY((n)->v6))
#define NAME_HAS_ADDRS(n)	(NAME_HAS_V4(n) || NAME_HAS_V6(n))
Michael Graff's avatar
Michael Graff committed
350

351
352
353
354
355
/*
 * Fetches are broken out into A, AAAA, and A6 types.  In some cases,
 * however, it makes more sense to test for a particular class of fetches,
 * like V4 or V6 above.
 */
356
357
358
359
360
361
#define NAME_FETCH_A(n)		((n)->fetch_a != NULL)
#define NAME_FETCH_AAAA(n)	((n)->fetch_aaaa != NULL)
#define NAME_FETCH_A6(n)	(!ISC_LIST_EMPTY((n)->fetches_a6))
#define NAME_FETCH_V4(n)	(NAME_FETCH_A(n))
#define NAME_FETCH_V6(n)	(NAME_FETCH_AAAA(n) || NAME_FETCH_A6(n))
#define NAME_FETCH(n)		(NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
362

363
364
365
366
367
/*
 * Was this fetch started using the hints database?
 * Was this the initial fetch for the A6 record?  If so, we might want to
 * start AAAA queries if it fails.
 */
368
#define FETCH_FIRST_A6		0x80000000
369
370
371
372
373
374
375
#define FETCH_FIRSTA6(f)	(((f)->flags & FETCH_FIRST_A6) != 0)

/*
 * Find options and tests to see if there are addresses on the list.
 */
#define FIND_WANTEVENT(fn)	(((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
#define FIND_WANTEMPTYEVENT(fn)	(((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
Bob Halley's avatar
Bob Halley committed
376
377
#define FIND_AVOIDFETCHES(fn)	(((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
				 != 0)
Bob Halley's avatar
Bob Halley committed
378
379
#define FIND_STARTATROOT(fn)	(((fn)->options & DNS_ADBFIND_STARTATROOT) \
				 != 0)
380
381
#define FIND_HINTOK(fn)		(((fn)->options & DNS_ADBFIND_HINTOK) != 0)
#define FIND_GLUEOK(fn)		(((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
382
#define FIND_HAS_ADDRS(fn)	(!ISC_LIST_EMPTY((fn)->list))
Michael Graff's avatar
Michael Graff committed
383
#define FIND_RETURNLAME(fn)	(((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
Bob Halley's avatar
Bob Halley committed
384

385
386
387
388
389
390
391
/*
 * These are currently used on simple unsigned ints, so they are
 * not really associated with any particular type.
 */
#define WANT_INET(x)		(((x) & DNS_ADBFIND_INET) != 0)
#define WANT_INET6(x)		(((x) & DNS_ADBFIND_INET6) != 0)

392
393
#define EXPIRE_OK(exp, now)	((exp == INT_MAX) || (exp < now))

394
395
396
397
398
399
400
401
402
/*
 * Find out if the flags on a name (nf) indicate if it is a hint or
 * glue, and compare this to the appropriate bits set in o, to see if
 * this is ok.
 */
#define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0))
#define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0))
#define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o))

403
404
405
406
#define ENTER_LEVEL		50
#define EXIT_LEVEL		ENTER_LEVEL
#define CLEAN_LEVEL		100
#define DEF_LEVEL		5
407
#define NCACHE_LEVEL		20
408

409
410
#define NCACHE_RESULT(r)	((r) == DNS_R_NCACHENXDOMAIN || \
				 (r) == DNS_R_NCACHENXRRSET)
Bob Halley's avatar
Bob Halley committed
411
412
#define AUTH_NX(r)		((r) == DNS_R_NXDOMAIN || \
				 (r) == DNS_R_NXRRSET)
413
414


415
416
417
418
419
420
421
422
423
424
425
426
static void
DP(int level, char *format, ...)
{
	va_list args;

	va_start(args, format);
	isc_log_vwrite(dns_lctx,
		       DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
		       ISC_LOG_DEBUG(level), format, args);
	va_end(args);
}

427
428
/*
 * Requires the adbname bucket be locked and that no entry buckets be locked.
429
430
 *
 * This code handles A and AAAA rdatasets only.
431
432
 */
static isc_result_t
433
434
import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
		isc_stdtime_t now)
435
436
{
	isc_result_t result;
Michael Graff's avatar
Michael Graff committed
437
	dns_adb_t *adb;
438
439
440
	dns_adbnamehook_t *nh;
	dns_rdata_t rdata;
	struct in_addr ina;
441
	struct in6_addr in6a;
442
443
444
445
	isc_sockaddr_t sockaddr;
	dns_adbentry_t *foundentry;  /* NO CLEAN UP! */
	int addr_bucket;
	isc_boolean_t new_addresses_added;
446
	dns_rdatatype_t rdtype;
447
	unsigned int findoptions;
448

Michael Graff's avatar
Michael Graff committed
449
450
451
452
	INSIST(DNS_ADBNAME_VALID(adbname));
	adb = adbname->adb;
	INSIST(DNS_ADB_VALID(adb));

453
454
	rdtype = rdataset->type;
	INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
455
456
	if (rdtype == dns_rdatatype_a)
		findoptions = DNS_ADBFIND_INET;
457
	else
458
		findoptions = DNS_ADBFIND_INET6;
Michael Graff's avatar
Michael Graff committed
459

460
461
	addr_bucket = DNS_ADB_INVALIDBUCKET;
	new_addresses_added = ISC_FALSE;
462

463
	nh = NULL;
464
465
466
	result = dns_rdataset_first(rdataset);
	while (result == ISC_R_SUCCESS) {
		dns_rdataset_current(rdataset, &rdata);
467
468
469
470
		if (rdtype == dns_rdatatype_a) {
			INSIST(rdata.length == 4);
			memcpy(&ina.s_addr, rdata.data, 4);
			isc_sockaddr_fromin(&sockaddr, &ina, 53);
471
		} else {
472
			INSIST(rdata.length == 16);
Mark Andrews's avatar
Mark Andrews committed
473
			memcpy(in6a.s6_addr, rdata.data, 16);
474
			isc_sockaddr_fromin6(&sockaddr, &in6a, 53);
475
476
		}

477
478
479
480
481
482
483
484
485
486
487
488
489
490
		if (IN6_IS_ADDR_V4MAPPED(&sockaddr.type.sin6.sin6_addr)
		    || IN6_IS_ADDR_V4COMPAT(&sockaddr.type.sin6.sin6_addr)) {
			DP(1, "Ignoring IPv6 mapped IPv4 address");
			goto next;
		}

		INSIST(nh == NULL);
		nh = new_adbnamehook(adb, NULL);
		if (nh == NULL) {
			adbname->partial_result |= findoptions;
			result = ISC_R_NOMEMORY;
			goto fail;
		}

Michael Graff's avatar
Michael Graff committed
491
492
493
494
495
496
		foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket);
		if (foundentry == NULL) {
			dns_adbentry_t *entry;

			entry = new_adbentry(adb);
			if (entry == NULL) {
497
				adbname->partial_result |= findoptions;
Michael Graff's avatar
Michael Graff committed
498
499
500
501
502
503
504
505
506
				result = ISC_R_NOMEMORY;
				goto fail;
			}

			entry->sockaddr = sockaddr;
			entry->refcnt = 1;

			nh->entry = entry;

507
			link_entry(adb, addr_bucket, entry);
Michael Graff's avatar
Michael Graff committed
508
509
510
511
512
513
		} else {
			foundentry->refcnt++;
			nh->entry = foundentry;
		}

		new_addresses_added = ISC_TRUE;
514
515
516
517
		if (rdtype == dns_rdatatype_a)
			ISC_LIST_APPEND(adbname->v4, nh, plink);
		else
			ISC_LIST_APPEND(adbname->v6, nh, plink);
Michael Graff's avatar
Michael Graff committed
518
519
		nh = NULL;

520
521
	next:

Michael Graff's avatar
Michael Graff committed
522
523
524
525
526
527
528
529
530
531
		result = dns_rdataset_next(rdataset);
	}

 fail:
	if (nh != NULL)
		free_adbnamehook(adb, &nh);

	if (addr_bucket != DNS_ADB_INVALIDBUCKET)
		UNLOCK(&adb->entrylocks[addr_bucket]);

532
	rdataset->ttl = ISC_MAX(rdataset->ttl, ADB_CACHE_MINIMUM);
533

534
535
536
537
538
539
540
541
542
543
544
	if (rdtype == dns_rdatatype_a) {
		DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
		   adbname->expire_v4, now + rdataset->ttl);
		adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
					     now + rdataset->ttl);
	} else {
		DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
		   adbname->expire_v6, now + rdataset->ttl);
		adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
					     now + rdataset->ttl);
	}
Michael Graff's avatar
Michael Graff committed
545

546
	if (new_addresses_added) {
547
548
549
550
		/*
		 * Lie a little here.  This is more or less so code that cares
		 * can find out if any new information was added or not.
		 */
Michael Graff's avatar
Michael Graff committed
551
		return (ISC_R_SUCCESS);
552
	}
553
554
555
556

	return (result);
}

557
static void
558
import_a6(dns_a6context_t *a6ctx) {
559
560
561
562
563
564
565
	dns_adbname_t *name;
	dns_adb_t *adb;
	dns_adbnamehook_t *nh;
	dns_adbentry_t *foundentry;  /* NO CLEAN UP! */
	int addr_bucket;
	isc_sockaddr_t sockaddr;

566
	name = a6ctx->arg;
567
568
569
570
	INSIST(DNS_ADBNAME_VALID(name));
	adb = name->adb;
	INSIST(DNS_ADB_VALID(adb));

Bob Halley's avatar
Bob Halley committed
571
	addr_bucket = DNS_ADB_INVALIDBUCKET;
572

573
	DP(ENTER_LEVEL, "ENTER: import_a6() name %p", name);
574
	
575
576
577
578
579
580
	nh = new_adbnamehook(adb, NULL);
	if (nh == NULL) {
		name->partial_result |= DNS_ADBFIND_INET6; /* clear for AAAA */
		goto fail;
	}

581
	isc_sockaddr_fromin6(&sockaddr, &a6ctx->in6addr, 53);
582

583
584
585
586
587
588
	if (IN6_IS_ADDR_V4MAPPED(&sockaddr.type.sin6.sin6_addr)
	    || IN6_IS_ADDR_V4COMPAT(&sockaddr.type.sin6.sin6_addr)) {
		DP(1, "Ignoring IPv6 mapped IPv4 address");
		goto fail;
	}

589
590
591
592
593
594
595
596
597
598
599
600
	foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket);
	if (foundentry == NULL) {
		dns_adbentry_t *entry;
		entry = new_adbentry(adb);
		if (entry == NULL) {
			name->partial_result |= DNS_ADBFIND_INET6;
			goto fail;
		}

		entry->sockaddr = sockaddr;
		entry->refcnt = 1;
		nh->entry = entry;
601
		link_entry(adb, addr_bucket, entry);
602
603
604
605
606
607
608
609
	} else {
		foundentry->refcnt++;
		nh->entry = foundentry;
	}

	ISC_LIST_APPEND(name->v6, nh, plink);
	nh = NULL;

610
611
 fail:
	DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) in import_v6",
Bob Halley's avatar
Bob Halley committed
612
613
614
615
616
	   name->expire_v6, a6ctx->expiration);
	name->expire_v6 = ISC_MIN(name->expire_v6, a6ctx->expiration);

	name->flags |= NAME_NEEDS_POKE;

617
618
619
620
621
622
623
	if (nh != NULL)
		free_adbnamehook(adb, &nh);

	if (addr_bucket != DNS_ADB_INVALIDBUCKET)
		UNLOCK(&adb->entrylocks[addr_bucket]);
}

Michael Graff's avatar
Michael Graff committed
624
625
626
627
/*
 * Requires the name's bucket be locked.
 */
static void
628
kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
Michael Graff's avatar
Michael Graff committed
629
	dns_adbname_t *name;
Michael Graff's avatar
Michael Graff committed
630
	dns_adb_t *adb;
Michael Graff's avatar
Michael Graff committed
631
632
633
634
635

	INSIST(n != NULL);
	name = *n;
	*n = NULL;
	INSIST(DNS_ADBNAME_VALID(name));
Michael Graff's avatar
Michael Graff committed
636
637
	adb = name->adb;
	INSIST(DNS_ADB_VALID(adb));
Michael Graff's avatar
Michael Graff committed
638

639
	DP(DEF_LEVEL, "killing name %p", name);
640

641
642
643
644
	/*
	 * If we're dead already, just check to see if we should go
	 * away now or not.
	 */
645
	if (NAME_DEAD(name) && !NAME_FETCH(name)) {
646
647
648
649
650
651
652
653
654
		unlink_name(adb, name);
		free_adbname(adb, &name);
		return;
	}

	/*
	 * Clean up the name's various lists.  These two are destructive
	 * in that they will always empty the list.
	 */
655
	clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
Michael Graff's avatar
Michael Graff committed
656
657
	clean_namehooks(adb, &name->v4);
	clean_namehooks(adb, &name->v6);
658
	clean_target(adb, &name->target);
Michael Graff's avatar
Michael Graff committed
659

660
661
662
663
	/*
	 * If fetches are running, cancel them.  If none are running, we can
	 * just kill the name here.
	 */
664
	if (!NAME_FETCH(name)) {
Michael Graff's avatar
Michael Graff committed
665
666
667
		unlink_name(adb, name);
		free_adbname(adb, &name);
	} else {
668
		name->flags |= NAME_IS_DEAD;
669
		cancel_fetches_at_name(name);
Michael Graff's avatar
Michael Graff committed
670
671
672
	}
}

Michael Graff's avatar
Michael Graff committed
673
674
675
676
/*
 * Requires the name's bucket be locked and no entry buckets be locked.
 */
static void
677
check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
Michael Graff's avatar
Michael Graff committed
678
679
680
681
682
683
684
685
686
	dns_adb_t *adb;

	INSIST(DNS_ADBNAME_VALID(name));
	adb = name->adb;
	INSIST(DNS_ADB_VALID(adb));

	/*
	 * Check to see if we need to remove the v4 addresses
	 */
687
	if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) {
688
		if (NAME_HAS_V4(name)) {
689
690
			DP(DEF_LEVEL, "expiring v4 for name %p", name);
			clean_namehooks(adb, &name->v4);
691
			name->partial_result &= ~DNS_ADBFIND_INET;
692
		}
693
		name->expire_v4 = INT_MAX;
694
695
	}

Michael Graff's avatar
Michael Graff committed
696
697
698
	/*
	 * Check to see if we need to remove the v6 addresses
	 */
699
	if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) {
700
		if (NAME_HAS_V6(name)) {
701
702
			DP(DEF_LEVEL, "expiring v6 for name %p", name);
			clean_namehooks(adb, &name->v6);
703
			name->partial_result &= ~DNS_ADBFIND_INET6;
704
		}
705
		name->expire_v6 = INT_MAX;
706
	}
707
708
709
710
711
712
713
714

	/*
	 * Check to see if we need to remove the alias target.
	 */
	if (EXPIRE_OK(name->expire_target, now)) {
		clean_target(adb, &name->target);
		name->expire_target = INT_MAX;
	}
Michael Graff's avatar
Michael Graff committed
715
716
}

Michael Graff's avatar
Michael Graff committed
717
718
719
720
/*
 * Requires the name's bucket be locked.
 */
static inline void
721
link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
Michael Graff's avatar
Michael Graff committed
722
723
	INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);

724
	ISC_LIST_PREPEND(adb->names[bucket], name, plink);
Michael Graff's avatar
Michael Graff committed
725
726
727
728
729
730
731
732
	name->lock_bucket = bucket;
	adb->name_refcnt[bucket]++;
}

/*
 * Requires the name's bucket be locked.
 */
static inline void
733
unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
Michael Graff's avatar
Michael Graff committed
734
735
736
737
738
	int bucket;

	bucket = name->lock_bucket;
	INSIST(bucket != DNS_ADB_INVALIDBUCKET);

739
	ISC_LIST_UNLINK(adb->names[bucket], name, plink);
Michael Graff's avatar
Michael Graff committed
740
741
742
	name->lock_bucket = DNS_ADB_INVALIDBUCKET;
	INSIST(adb->name_refcnt[bucket] > 0);
	adb->name_refcnt[bucket]--;
743
744
	if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
		dec_adb_irefcnt(adb);
Michael Graff's avatar
Michael Graff committed
745
}
746

747
748
749
750
/*
 * Requires the entry's bucket be locked.
 */
static inline void
751
link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
752
753
754
755
756
757
758
759
760
	ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
	entry->lock_bucket = bucket;
	adb->entry_refcnt[bucket]++;
}

/*
 * Requires the entry's bucket be locked.
 */
static inline void
761
unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
762
763
764
765
766
767
768
769
770
	int bucket;

	bucket = entry->lock_bucket;
	INSIST(bucket != DNS_ADB_INVALIDBUCKET);

	ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
	entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
	INSIST(adb->entry_refcnt[bucket] > 0);
	adb->entry_refcnt[bucket]--;
771
772
	if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
		dec_adb_irefcnt(adb);
773
774
}

775
static inline void
776
violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
777
778
779
780
781
782
783
784
	if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
		UNLOCK(have);
		LOCK(want);
		LOCK(have);
	}
}

/*
785
786
 * The ADB _MUST_ be locked before calling.  Also, exit conditions must be
 * checked after calling this function.
787
788
 */
static void
789
shutdown_names(dns_adb_t *adb) {
790
791
	int bucket;
	dns_adbname_t *name;
Michael Graff's avatar
Michael Graff committed
792
	dns_adbname_t *next_name;
793

794
	for (bucket = 0 ; bucket < NBUCKETS ; bucket++) {
795
796
797
798
		LOCK(&adb->namelocks[bucket]);
		adb->name_sd[bucket] = ISC_TRUE;

		name = ISC_LIST_HEAD(adb->names[bucket]);
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
		if (name == NULL) {
			/*
			 * This bucket has no names.  We must decrement the
			 * irefcnt ourselves, since it will not be
			 * automatically triggered by a name being unlinked.
			 */
			dec_adb_irefcnt(adb);
		} else {
			/*
			 * Run through the list.  For each name, clean up finds
			 * found there, and cancel any fetches running.  When
			 * all the fetches are canceled, the name will destroy
			 * itself.
			 */
			while (name != NULL) {
				next_name = ISC_LIST_NEXT(name, plink);
				kill_name(&name, DNS_EVENT_ADBSHUTDOWN);
				name = next_name;
			}
818
819
820
821
822
823
		}

		UNLOCK(&adb->namelocks[bucket]);
	}
}

824
825
826
827
828
/*
 * The ADB _MUST_ be locked before calling.  Also, exit conditions must be
 * checked after calling this function.
 */
static void
829
shutdown_entries(dns_adb_t *adb) {
830
831
832
833
834
835
836
837
838
	int bucket;
	dns_adbentry_t *entry;
	dns_adbentry_t *next_entry;

	for (bucket = 0 ; bucket < NBUCKETS ; bucket++) {
		LOCK(&adb->entrylocks[bucket]);
		adb->entry_sd[bucket] = ISC_TRUE;

		entry = ISC_LIST_HEAD(adb->entries[bucket]);
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
		if (entry == NULL) {
			/*
			 * This bucket has no entries.  We must decrement the
			 * irefcnt ourselves, since it will not be
			 * automatically triggered by an entry being unlinked.
			 */
			dec_adb_irefcnt(adb);
		} else {
			/*
			 * Run through the list.  Cleanup any entries not
			 * associated with names, and which are not in use.
			 */
			while (entry != NULL) {
				next_entry = ISC_LIST_NEXT(entry, plink);
				if (entry->refcnt == 0 &&
				    entry->expires != 0) {
					unlink_entry(adb, entry);
					free_adbentry(adb, &entry);
				}
				entry = next_entry;
859
860
861
			}
		}

862
		UNLOCK(&adb->entrylocks[bucket]);
863
864
865
	}
}

Michael Graff's avatar
Michael Graff committed
866
867
868
869
/*
 * Name bucket must be locked
 */
static void
870
cancel_fetches_at_name(dns_adbname_t *name) {
871
872
	dns_adbfetch6_t *fetch6;

873
	if (NAME_FETCH_A(name))
874
875
	    dns_resolver_cancelfetch(name->fetch_a->fetch);
				     
Michael Graff's avatar
Michael Graff committed
876

877
	if (NAME_FETCH_AAAA(name))
878
879
	    dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
				     
880
881
882

	fetch6 = ISC_LIST_HEAD(name->fetches_a6);
	while (fetch6 != NULL) {
883
		dns_resolver_cancelfetch(fetch6->fetch);
884
885
		fetch6 = ISC_LIST_NEXT(fetch6, plink);
	}
Michael Graff's avatar
Michael Graff committed
886
887
}

Michael Graff's avatar
Michael Graff committed
888
889
890
/*
 * Assumes the name bucket is locked.
 */
891
static void
892
clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
893
894
895
896
897
	dns_adbentry_t *entry;
	dns_adbnamehook_t *namehook;
	int addr_bucket;

	addr_bucket = DNS_ADB_INVALIDBUCKET;
Michael Graff's avatar
Michael Graff committed
898
	namehook = ISC_LIST_HEAD(*namehooks);
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
	while (namehook != NULL) {
		INSIST(DNS_ADBNAMEHOOK_VALID(namehook));

		/*
		 * Clean up the entry if needed.
		 */
		entry = namehook->entry;
		if (entry != NULL) {
			INSIST(DNS_ADBENTRY_VALID(entry));

			if (addr_bucket != entry->lock_bucket) {
				if (addr_bucket != DNS_ADB_INVALIDBUCKET)
					UNLOCK(&adb->entrylocks[addr_bucket]);
				addr_bucket = entry->lock_bucket;
				LOCK(&adb->entrylocks[addr_bucket]);
			}

			dec_entry_refcnt(adb, entry, ISC_FALSE);
		}

		/*
		 * Free the namehook
		 */
		namehook->entry = NULL;
923
		ISC_LIST_UNLINK(*namehooks, namehook, plink);
924
925
		free_adbnamehook(adb, &namehook);

Michael Graff's avatar
Michael Graff committed
926
		namehook = ISC_LIST_HEAD(*namehooks);
927
928
929
930
931
932
	}

	if (addr_bucket != DNS_ADB_INVALIDBUCKET)
		UNLOCK(&adb->entrylocks[addr_bucket]);
}

933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
static void
clean_target(dns_adb_t *adb, dns_name_t *target) {
	if (dns_name_countlabels(target) > 0) {
		dns_name_free(target, adb->mctx);
		dns_name_init(target, NULL);
	}
}

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)
{
	isc_result_t result;
	dns_namereln_t namereln;
	unsigned int nlabels, nbits;
	int order;
	dns_rdata_t rdata;
	isc_region_t r;
	dns_name_t tname;
	dns_fixedname_t fixed1, fixed2;
	dns_name_t *prefix, *new_target;

955
956
	REQUIRE(dns_name_countlabels(target) == 0);

957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
	if (rdataset->type == dns_rdatatype_cname) {
		/*
		 * Copy the CNAME's target into the target name.
		 */
		result = dns_rdataset_first(rdataset);
		if (result != ISC_R_SUCCESS)
			return (result);
		dns_rdataset_current(rdataset, &rdata);
		r.base = rdata.data;
		r.length = rdata.length;
		dns_name_init(&tname, NULL);
		dns_name_fromregion(&tname, &r);
		result = dns_name_dup(&tname, adb->mctx, target);
		if (result != ISC_R_SUCCESS)
			return (result);
	} else {
		INSIST(rdataset->type == dns_rdatatype_dname);
		namereln = dns_name_fullcompare(name, fname, &order,
						&nlabels, &nbits);
		INSIST(namereln == dns_namereln_subdomain);
		/*
		 * Get the target name of the DNAME.
		 */
		result = dns_rdataset_first(rdataset);
		if (result != ISC_R_SUCCESS)
			return (result);
		dns_rdataset_current(rdataset, &rdata);
		r.base = rdata.data;
		r.length = rdata.length;
		dns_name_init(&tname, NULL);
		dns_name_fromregion(&tname, &r);
		/*
		 * Construct the new target name.
		 */
		dns_fixedname_init(&fixed1);
		prefix = dns_fixedname_name(&fixed1);
		dns_fixedname_init(&fixed2);
		new_target = dns_fixedname_name(&fixed2);
		result = dns_name_split(name, nlabels, nbits, prefix, NULL);
		if (result != ISC_R_SUCCESS)
			return (result);
		result = dns_name_concatenate(prefix, &tname, new_target,
					      NULL);
		if (result != ISC_R_SUCCESS)