adb.c 122 KB
Newer Older
Michael Graff's avatar
Michael Graff committed
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4 5 6
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 8 9
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
Michael Graff's avatar
Michael Graff committed
10 11
 */

12
/*! \file
13
 *
14
 * \note
15
 * In finds, if task == NULL, no events will be generated, and no events
16
 * have been sent.  If task != NULL but taskaction == NULL, an event has been
Bob Halley's avatar
Bob Halley committed
17
 * posted but not yet freed.  If neither are NULL, no event was posted.
18 19 20
 *
 */

Mark Andrews's avatar
Mark Andrews committed
21
#include <limits.h>
22
#include <inttypes.h>
23
#include <stdbool.h>
24

25
#include <isc/mutexblock.h>
26
#include <isc/netaddr.h>
27
#include <isc/print.h>
Michael Graff's avatar
Michael Graff committed
28
#include <isc/random.h>
29
#include <isc/stats.h>
30
#include <isc/string.h>         /* Required for HP/UX (and others?) */
31
#include <isc/task.h>
Michael Graff's avatar
Michael Graff committed
32
#include <isc/util.h>
Michael Graff's avatar
Michael Graff committed
33

Michael Graff's avatar
Michael Graff committed
34
#include <dns/adb.h>
Michael Graff's avatar
Michael Graff committed
35
#include <dns/db.h>
36
#include <dns/events.h>
37
#include <dns/log.h>
Michael Graff's avatar
Michael Graff committed
38 39
#include <dns/rdata.h>
#include <dns/rdataset.h>
40
#include <dns/rdatastruct.h>
41
#include <dns/rdatatype.h>
Michael Graff's avatar
fix  
Michael Graff committed
42
#include <dns/resolver.h>
43
#include <dns/result.h>
44
#include <dns/stats.h>
45

46 47 48 49 50
#define DNS_ADB_MAGIC             ISC_MAGIC('D', 'a', 'd', 'b')
#define DNS_ADB_VALID(x)          ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
#define DNS_ADBNAME_MAGIC         ISC_MAGIC('a', 'd', 'b', 'N')
#define DNS_ADBNAME_VALID(x)      ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
#define DNS_ADBNAMEHOOK_MAGIC     ISC_MAGIC('a', 'd', 'N', 'H')
51
#define DNS_ADBNAMEHOOK_VALID(x)  ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
52
#define DNS_ADBLAMEINFO_MAGIC     ISC_MAGIC('a', 'd', 'b', 'Z')
53
#define DNS_ADBLAMEINFO_VALID(x)  ISC_MAGIC_VALID(x, DNS_ADBLAMEINFO_MAGIC)
54 55 56 57 58 59 60
#define DNS_ADBENTRY_MAGIC        ISC_MAGIC('a', 'd', 'b', 'E')
#define DNS_ADBENTRY_VALID(x)     ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
#define DNS_ADBFETCH_MAGIC        ISC_MAGIC('a', 'd', 'F', '4')
#define DNS_ADBFETCH_VALID(x)     ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
#define DNS_ADBFETCH6_MAGIC       ISC_MAGIC('a', 'd', 'F', '6')
#define DNS_ADBFETCH6_VALID(x)    ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)

61
/*!
62
 * For type 3 negative cache entries, we will remember that the address is
63
 * broken for this long.  XXXMLG This is also used for actual addresses, too.
64
 * The intent is to keep us from constantly asking about A/AAAA records
65
 * if the zone has extremely low TTLs.
66
 */
67 68 69
#define ADB_CACHE_MINIMUM       10      /*%< seconds */
#define ADB_CACHE_MAXIMUM       86400   /*%< seconds (86400 = 24 hours) */
#define ADB_ENTRY_WINDOW        1800    /*%< seconds */
70

71 72 73 74 75 76 77 78
/*%
 * The period in seconds after which an ADB name entry is regarded as stale
 * and forced to be cleaned up.
 * TODO: This should probably be configurable at run-time.
 */
#ifndef ADB_STALE_MARGIN
#define ADB_STALE_MARGIN        1800
#endif
Michael Graff's avatar
Michael Graff committed
79

80 81
#define FREE_ITEMS              64      /*%< free count for memory pools */
#define FILL_COUNT              16      /*%< fill count for memory pools */
82

83
#define DNS_ADB_INVALIDBUCKET (-1)      /*%< invalid bucket address */
Michael Graff's avatar
Michael Graff committed
84

Mark Andrews's avatar
Mark Andrews committed
85
#define DNS_ADB_MINADBSIZE      (1024U*1024U)     /*%< 1 Megabyte */
86

87
typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
Michael Graff's avatar
Michael Graff committed
88
typedef struct dns_adbnamehook dns_adbnamehook_t;
Michael Graff's avatar
Michael Graff committed
89
typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
90
typedef struct dns_adblameinfo dns_adblameinfo_t;
91
typedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t;
Michael Graff's avatar
Michael Graff committed
92
typedef struct dns_adbfetch dns_adbfetch_t;
Bob Halley's avatar
Bob Halley committed
93
typedef struct dns_adbfetch6 dns_adbfetch6_t;
Michael Graff's avatar
Michael Graff committed
94

95
/*% dns adb structure */
Michael Graff's avatar
Michael Graff committed
96
struct dns_adb {
Automatic Updater's avatar
Automatic Updater committed
97
	unsigned int                    magic;
98

Automatic Updater's avatar
Automatic Updater committed
99 100 101 102 103
	isc_mutex_t                     lock;
	isc_mutex_t                     reflock; /*%< Covers irefcnt, erefcnt */
	isc_mutex_t                     overmemlock; /*%< Covers overmem */
	isc_mem_t                      *mctx;
	dns_view_t                     *view;
104

Automatic Updater's avatar
Automatic Updater committed
105 106
	isc_taskmgr_t                  *taskmgr;
	isc_task_t                     *task;
107
	isc_task_t                     *excl;
Automatic Updater's avatar
Automatic Updater committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128

	isc_interval_t                  tick_interval;
	int                             next_cleanbucket;

	unsigned int                    irefcnt;
	unsigned int                    erefcnt;

	isc_mutex_t                     mplock;
	isc_mempool_t                  *nmp;    /*%< dns_adbname_t */
	isc_mempool_t                  *nhmp;   /*%< dns_adbnamehook_t */
	isc_mempool_t                  *limp;   /*%< dns_adblameinfo_t */
	isc_mempool_t                  *emp;    /*%< dns_adbentry_t */
	isc_mempool_t                  *ahmp;   /*%< dns_adbfind_t */
	isc_mempool_t                  *aimp;   /*%< dns_adbaddrinfo_t */
	isc_mempool_t                  *afmp;   /*%< dns_adbfetch_t */

	/*!
	 * Bucketized locks and lists for names.
	 *
	 * XXXRTH  Have a per-bucket structure that contains all of these?
	 */
129 130 131 132 133 134
	unsigned int			nnames;
	isc_mutex_t                     namescntlock;
	unsigned int			namescnt;
	dns_adbnamelist_t               *names;
	dns_adbnamelist_t               *deadnames;
	isc_mutex_t                     *namelocks;
135
	bool                   *name_sd;
136
	unsigned int                    *name_refcnt;
Automatic Updater's avatar
Automatic Updater committed
137 138

	/*!
139
	 * Bucketized locks and lists for entries.
Automatic Updater's avatar
Automatic Updater committed
140 141 142
	 *
	 * XXXRTH  Have a per-bucket structure that contains all of these?
	 */
143 144 145 146 147 148
	unsigned int			nentries;
	isc_mutex_t                     entriescntlock;
	unsigned int			entriescnt;
	dns_adbentrylist_t              *entries;
	dns_adbentrylist_t              *deadentries;
	isc_mutex_t                     *entrylocks;
149
	bool                   *entry_sd; /*%< shutting down */
150
	unsigned int                    *entry_refcnt;
Automatic Updater's avatar
Automatic Updater committed
151 152

	isc_event_t                     cevent;
153 154
	bool                   cevent_out;
	bool                   shutting_down;
Automatic Updater's avatar
Automatic Updater committed
155
	isc_eventlist_t                 whenshutdown;
156
	isc_event_t			growentries;
157
	bool			growentries_sent;
158
	isc_event_t			grownames;
159
	bool			grownames_sent;
Evan Hunt's avatar
Evan Hunt committed
160

161 162
	uint32_t			quota;
	uint32_t			atr_freq;
Evan Hunt's avatar
Evan Hunt committed
163 164 165
	double				atr_low;
	double				atr_high;
	double				atr_discount;
Michael Graff's avatar
Michael Graff committed
166 167
};

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

172
/*% dns_adbname structure */
Michael Graff's avatar
Michael Graff committed
173
struct dns_adbname {
Automatic Updater's avatar
Automatic Updater committed
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
	unsigned int                    magic;
	dns_name_t                      name;
	dns_adb_t                      *adb;
	unsigned int                    partial_result;
	unsigned int                    flags;
	int                             lock_bucket;
	dns_name_t                      target;
	isc_stdtime_t                   expire_target;
	isc_stdtime_t                   expire_v4;
	isc_stdtime_t                   expire_v6;
	unsigned int                    chains;
	dns_adbnamehooklist_t           v4;
	dns_adbnamehooklist_t           v6;
	dns_adbfetch_t                 *fetch_a;
	dns_adbfetch_t                 *fetch_aaaa;
	unsigned int                    fetch_err;
	unsigned int                    fetch6_err;
	dns_adbfindlist_t               finds;
	/* for LRU-based management */
	isc_stdtime_t                   last_used;

	ISC_LINK(dns_adbname_t)         plink;
Michael Graff's avatar
Michael Graff committed
196 197
};

198
/*% The adbfetch structure */
Michael Graff's avatar
Michael Graff committed
199
struct dns_adbfetch {
Automatic Updater's avatar
Automatic Updater committed
200 201 202
	unsigned int                    magic;
	dns_fetch_t                    *fetch;
	dns_rdataset_t                  rdataset;
203
	unsigned int			depth;
Michael Graff's avatar
Michael Graff committed
204 205
};

206
/*%
Michael Graff's avatar
Michael Graff committed
207 208 209 210 211
 * 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 {
Automatic Updater's avatar
Automatic Updater committed
212 213 214
	unsigned int                    magic;
	dns_adbentry_t                 *entry;
	ISC_LINK(dns_adbnamehook_t)     plink;
Michael Graff's avatar
Michael Graff committed
215 216
};

217
/*%
218
 * This is a small widget that holds qname-specific information about an
Michael Graff's avatar
Michael Graff committed
219 220 221
 * address.  Currently limited to lameness, but could just as easily be
 * extended to other types of information about zones.
 */
222
struct dns_adblameinfo {
Automatic Updater's avatar
Automatic Updater committed
223
	unsigned int                    magic;
Michael Graff's avatar
Michael Graff committed
224

Automatic Updater's avatar
Automatic Updater committed
225 226 227
	dns_name_t                      qname;
	dns_rdatatype_t                 qtype;
	isc_stdtime_t                   lame_timer;
Michael Graff's avatar
Michael Graff committed
228

Automatic Updater's avatar
Automatic Updater committed
229
	ISC_LINK(dns_adblameinfo_t)     plink;
Michael Graff's avatar
Michael Graff committed
230 231
};

232
/*%
Michael Graff's avatar
Michael Graff committed
233
 * An address entry.  It holds quite a bit of information about addresses,
234 235
 * including edns state (in "flags"), rtt, and of course the address of
 * the host.
Michael Graff's avatar
Michael Graff committed
236
 */
Michael Graff's avatar
Michael Graff committed
237
struct dns_adbentry {
Automatic Updater's avatar
Automatic Updater committed
238 239 240 241
	unsigned int                    magic;

	int                             lock_bucket;
	unsigned int                    refcnt;
242
	unsigned int                    nh;
Automatic Updater's avatar
Automatic Updater committed
243 244 245

	unsigned int                    flags;
	unsigned int                    srtt;
246
	uint16_t			udpsize;
Evan Hunt's avatar
Evan Hunt committed
247 248
	unsigned int			completed;
	unsigned int			timeouts;
249 250 251 252
	unsigned char			plain;
	unsigned char			plainto;
	unsigned char			edns;
	unsigned char			to4096;		/* Our max. */
Evan Hunt's avatar
Evan Hunt committed
253

254 255 256
	uint8_t			mode;
	uint32_t			quota;
	uint32_t			active;
Evan Hunt's avatar
Evan Hunt committed
257 258
	double				atr;

259 260 261 262 263 264 265
	/*
	 * Allow for encapsulated IPv4/IPv6 UDP packet over ethernet.
	 * Ethernet 1500 - IP(20) - IP6(40) - UDP(8) = 1432.
	 */
	unsigned char			to1432;		/* Ethernet */
	unsigned char			to1232;		/* IPv6 nofrag */
	unsigned char			to512;		/* plain DNS */
Automatic Updater's avatar
Automatic Updater committed
266
	isc_sockaddr_t                  sockaddr;
267
	unsigned char *			cookie;
268
	uint16_t			cookielen;
Automatic Updater's avatar
Automatic Updater committed
269 270

	isc_stdtime_t                   expires;
271
	isc_stdtime_t			lastage;
Automatic Updater's avatar
Automatic Updater committed
272 273 274 275 276 277 278 279 280 281
	/*%<
	 * A nonzero 'expires' field indicates that the entry should
	 * persist until that time.  This allows entries found
	 * using dns_adb_findaddrinfo() to persist for a limited time
	 * even though they are not necessarily associated with a
	 * name.
	 */

	ISC_LIST(dns_adblameinfo_t)     lameinfo;
	ISC_LINK(dns_adbentry_t)        plink;
Michael Graff's avatar
Michael Graff committed
282 283
};

Michael Graff's avatar
Michael Graff committed
284
/*
285 286
 * Internal functions (and prototypes).
 */
287
static inline dns_adbname_t *new_adbname(dns_adb_t *, const dns_name_t *);
Michael Graff's avatar
Michael Graff committed
288 289
static inline void free_adbname(dns_adb_t *, dns_adbname_t **);
static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
Automatic Updater's avatar
Automatic Updater committed
290
						 dns_adbentry_t *);
Michael Graff's avatar
Michael Graff committed
291
static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
292
static inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *,
293
						 const dns_name_t *,
Automatic Updater's avatar
Automatic Updater committed
294
						 dns_rdatatype_t);
295
static inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **);
Michael Graff's avatar
Michael Graff committed
296 297
static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
298
static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
299
static inline bool free_adbfind(dns_adb_t *, dns_adbfind_t **);
300
static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
Automatic Updater's avatar
Automatic Updater committed
301
						 in_port_t);
Michael Graff's avatar
Michael Graff committed
302 303
static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
304 305
static inline dns_adbname_t *find_name_and_lock(dns_adb_t *,
						const dns_name_t *,
Automatic Updater's avatar
Automatic Updater committed
306
						unsigned int, int *);
Michael Graff's avatar
Michael Graff committed
307
static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
308 309
						  const isc_sockaddr_t *,
						  int *, isc_stdtime_t);
310
static void dump_adb(dns_adb_t *, FILE *, bool debug, isc_stdtime_t);
311
static void print_dns_name(FILE *, const dns_name_t *);
312
static void print_namehook_list(FILE *, const char *legend,
Evan Hunt's avatar
Evan Hunt committed
313
				dns_adb_t *adb,
Automatic Updater's avatar
Automatic Updater committed
314
				dns_adbnamehooklist_t *list,
315
				bool debug,
Automatic Updater's avatar
Automatic Updater committed
316
				isc_stdtime_t now);
317
static void print_find_list(FILE *, dns_adbname_t *);
318
static void print_fetch_list(FILE *, dns_adbname_t *);
319
static inline bool dec_adb_irefcnt(dns_adb_t *);
Michael Graff's avatar
Michael Graff committed
320
static inline void inc_adb_irefcnt(dns_adb_t *);
321
static inline void inc_adb_erefcnt(dns_adb_t *);
Michael Graff's avatar
Michael Graff committed
322
static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
323 324 325
				    bool);
static inline bool dec_entry_refcnt(dns_adb_t *, bool,
					     dns_adbentry_t *, bool);
326
static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
327
static bool clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
328
static void clean_target(dns_adb_t *, dns_name_t *);
329
static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, unsigned int);
330 331
static bool check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
static bool check_expire_entry(dns_adb_t *, dns_adbentry_t **,
332
					isc_stdtime_t);
333
static void cancel_fetches_at_name(dns_adbname_t *);
334
static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
Automatic Updater's avatar
Automatic Updater committed
335
				dns_rdatatype_t);
336
static isc_result_t fetch_name(dns_adbname_t *, bool,
337
			       unsigned int, isc_counter_t *qc,
Mark Andrews's avatar
Mark Andrews committed
338
			       dns_rdatatype_t);
Michael Graff's avatar
Michael Graff committed
339
static inline void check_exit(dns_adb_t *);
340
static void destroy(dns_adb_t *);
341 342
static bool shutdown_names(dns_adb_t *);
static bool shutdown_entries(dns_adb_t *);
Michael Graff's avatar
Michael Graff committed
343
static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
344
static inline bool unlink_name(dns_adb_t *, dns_adbname_t *);
345
static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
346 347
static inline bool unlink_entry(dns_adb_t *, dns_adbentry_t *);
static bool kill_name(dns_adbname_t **, isc_eventtype_t);
348
static void water(void *, int);
Evan Hunt's avatar
Evan Hunt committed
349
static void dump_entry(FILE *, dns_adb_t *, dns_adbentry_t *,
350
		       bool, isc_stdtime_t);
351 352
static void adjustsrtt(dns_adbaddrinfo_t *addr, unsigned int rtt,
		       unsigned int factor, isc_stdtime_t now);
Mark Andrews's avatar
Mark Andrews committed
353
static void shutdown_task(isc_task_t *task, isc_event_t *ev);
Evan Hunt's avatar
Evan Hunt committed
354 355
static void log_quota(dns_adbentry_t *entry, const char *fmt, ...)
     ISC_FORMAT_PRINTF(2, 3);
Michael Graff's avatar
Michael Graff committed
356

357 358 359
/*
 * MUST NOT overlap DNS_ADBFIND_* flags!
 */
360 361 362 363 364 365 366 367 368 369 370 371 372 373
#define FIND_EVENT_SENT         0x40000000
#define FIND_EVENT_FREED        0x80000000
#define FIND_EVENTSENT(h)       (((h)->flags & FIND_EVENT_SENT) != 0)
#define FIND_EVENTFREED(h)      (((h)->flags & FIND_EVENT_FREED) != 0)

#define NAME_NEEDS_POKE         0x80000000
#define NAME_IS_DEAD            0x40000000
#define NAME_HINT_OK            DNS_ADBFIND_HINTOK
#define NAME_GLUE_OK            DNS_ADBFIND_GLUEOK
#define NAME_STARTATZONE        DNS_ADBFIND_STARTATZONE
#define NAME_DEAD(n)            (((n)->flags & NAME_IS_DEAD) != 0)
#define NAME_NEEDSPOKE(n)       (((n)->flags & NAME_NEEDS_POKE) != 0)
#define NAME_GLUEOK(n)          (((n)->flags & NAME_GLUE_OK) != 0)
#define NAME_HINTOK(n)          (((n)->flags & NAME_HINT_OK) != 0)
374

375 376 377 378
/*
 * Private flag(s) for entries.
 * MUST NOT overlap FCTX_ADDRINFO_xxx and DNS_FETCHOPT_NOEDNS0.
 */
379
#define ENTRY_IS_DEAD		0x00400000
380

381 382
/*
 * To the name, address classes are all that really exist.  If it has a
383
 * V6 address it doesn't care if it came from a AAAA query.
384
 */
385 386 387
#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
388

389
/*
390
 * Fetches are broken out into A and AAAA types.  In some cases,
391 392
 * however, it makes more sense to test for a particular class of fetches,
 * like V4 or V6 above.
393 394
 * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA
 * are now equal to FETCH_V4 and FETCH_V6, respectively.
395
 */
396 397 398 399 400
#define NAME_FETCH_A(n)         ((n)->fetch_a != NULL)
#define NAME_FETCH_AAAA(n)      ((n)->fetch_aaaa != NULL)
#define NAME_FETCH_V4(n)        (NAME_FETCH_A(n))
#define NAME_FETCH_V6(n)        (NAME_FETCH_AAAA(n))
#define NAME_FETCH(n)           (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
401

402 403 404
/*
 * Find options and tests to see if there are addresses on the list.
 */
405 406 407
#define FIND_WANTEVENT(fn)      (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
#define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
#define FIND_AVOIDFETCHES(fn)   (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
Automatic Updater's avatar
Automatic Updater committed
408
				 != 0)
409
#define FIND_STARTATZONE(fn)    (((fn)->options & DNS_ADBFIND_STARTATZONE) \
Automatic Updater's avatar
Automatic Updater committed
410
				 != 0)
411 412 413 414
#define FIND_HINTOK(fn)         (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
#define FIND_GLUEOK(fn)         (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
#define FIND_HAS_ADDRS(fn)      (!ISC_LIST_EMPTY((fn)->list))
#define FIND_RETURNLAME(fn)     (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
Bob Halley's avatar
Bob Halley committed
415

416 417 418 419
/*
 * These are currently used on simple unsigned ints, so they are
 * not really associated with any particular type.
 */
420 421
#define WANT_INET(x)            (((x) & DNS_ADBFIND_INET) != 0)
#define WANT_INET6(x)           (((x) & DNS_ADBFIND_INET6) != 0)
422

423
#define EXPIRE_OK(exp, now)     ((exp == INT_MAX) || (exp < now))
424

425 426 427 428 429 430 431 432
/*
 * 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))
433
#define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \
Automatic Updater's avatar
Automatic Updater committed
434
				    ((o) & DNS_ADBFIND_STARTATZONE))
435 436 437 438 439 440 441 442

#define ENTER_LEVEL             ISC_LOG_DEBUG(50)
#define EXIT_LEVEL              ENTER_LEVEL
#define CLEAN_LEVEL             ISC_LOG_DEBUG(100)
#define DEF_LEVEL               ISC_LOG_DEBUG(5)
#define NCACHE_LEVEL            ISC_LOG_DEBUG(20)

#define NCACHE_RESULT(r)        ((r) == DNS_R_NCACHENXDOMAIN || \
Automatic Updater's avatar
Automatic Updater committed
443
				 (r) == DNS_R_NCACHENXRRSET)
444
#define AUTH_NX(r)              ((r) == DNS_R_NXDOMAIN || \
Automatic Updater's avatar
Automatic Updater committed
445
				 (r) == DNS_R_NXRRSET)
446
#define NXDOMAIN_RESULT(r)      ((r) == DNS_R_NXDOMAIN || \
Automatic Updater's avatar
Automatic Updater committed
447
				 (r) == DNS_R_NCACHENXDOMAIN)
448
#define NXRRSET_RESULT(r)       ((r) == DNS_R_NCACHENXRRSET || \
Automatic Updater's avatar
Automatic Updater committed
449 450
				 (r) == DNS_R_NXRRSET || \
				 (r) == DNS_R_HINTNXRRSET)
451

Michael Graff's avatar
Michael Graff committed
452 453 454 455
/*
 * Error state rankings.
 */

456 457 458 459 460 461 462 463
#define FIND_ERR_SUCCESS                0  /* highest rank */
#define FIND_ERR_CANCELED               1
#define FIND_ERR_FAILURE                2
#define FIND_ERR_NXDOMAIN               3
#define FIND_ERR_NXRRSET                4
#define FIND_ERR_UNEXPECTED             5
#define FIND_ERR_NOTFOUND               6
#define FIND_ERR_MAX                    7
Michael Graff's avatar
Michael Graff committed
464

465
static const char *errnames[] = {
Automatic Updater's avatar
Automatic Updater committed
466 467 468 469 470 471 472
	"success",
	"canceled",
	"failure",
	"nxdomain",
	"nxrrset",
	"unexpected",
	"not_found"
473 474
};

475
#define NEWERR(old, new)        (ISC_MIN((old), (new)))
Michael Graff's avatar
Michael Graff committed
476 477

static isc_result_t find_err_map[FIND_ERR_MAX] = {
Automatic Updater's avatar
Automatic Updater committed
478 479 480 481 482 483 484
	ISC_R_SUCCESS,
	ISC_R_CANCELED,
	ISC_R_FAILURE,
	DNS_R_NXDOMAIN,
	DNS_R_NXRRSET,
	ISC_R_UNEXPECTED,
	ISC_R_NOTFOUND          /* not YET found */
Michael Graff's avatar
Michael Graff committed
485
};
486

487 488 489
static void
DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);

490
static void
David Lawrence's avatar
David Lawrence committed
491
DP(int level, const char *format, ...) {
Automatic Updater's avatar
Automatic Updater committed
492
	va_list args;
493

Automatic Updater's avatar
Automatic Updater committed
494 495 496 497 498
	va_start(args, format);
	isc_log_vwrite(dns_lctx,
		       DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
		       level, format, args);
	va_end(args);
499 500
}

501 502 503 504
/*%
 * Increment resolver-related statistics counters.
 */
static inline void
505
inc_stats(dns_adb_t *adb, isc_statscounter_t counter) {
506
	if (adb->view->resstats != NULL)
507
		isc_stats_increment(adb->view->resstats, counter);
508 509
}

510 511 512 513
/*%
 * Set adb-related statistics counters.
 */
static inline void
514
set_adbstat(dns_adb_t *adb, uint64_t val, isc_statscounter_t counter) {
515 516 517 518 519 520 521
	if (adb->view->adbstats != NULL)
		isc_stats_set(adb->view->adbstats, val, counter);
}

static inline void
dec_adbstats(dns_adb_t *adb, isc_statscounter_t counter) {
	if (adb->view->adbstats != NULL)
522
		isc_stats_decrement(adb->view->adbstats, counter);
523 524 525 526 527 528 529 530
}

static inline void
inc_adbstats(dns_adb_t *adb, isc_statscounter_t counter) {
	if (adb->view->adbstats != NULL)
		isc_stats_increment(adb->view->adbstats, counter);
}

531 532
static inline dns_ttl_t
ttlclamp(dns_ttl_t ttl) {
Automatic Updater's avatar
Automatic Updater committed
533 534 535 536
	if (ttl < ADB_CACHE_MINIMUM)
		ttl = ADB_CACHE_MINIMUM;
	if (ttl > ADB_CACHE_MAXIMUM)
		ttl = ADB_CACHE_MAXIMUM;
537

Automatic Updater's avatar
Automatic Updater committed
538
	return (ttl);
539 540
}

541 542 543 544 545 546 547 548 549
/*
 * Hashing is most efficient if the number of buckets is prime.
 * The sequence below is the closest previous primes to 2^n and
 * 1.5 * 2^n, for values of n from 10 to 28.  (The tables will
 * no longer grow beyond 2^28 entries.)
 */
static const unsigned nbuckets[] = { 1021, 1531, 2039, 3067, 4093, 6143,
				     8191, 12281, 16381, 24571, 32749,
				     49193, 65521, 98299, 131071, 199603,
Automatic Updater's avatar
Automatic Updater committed
550
				     262139, 393209, 524287, 768431, 1048573,
551 552
				     1572853, 2097143, 3145721, 4194301,
				     6291449, 8388593, 12582893, 16777213,
Automatic Updater's avatar
Automatic Updater committed
553
				     25165813, 33554393, 50331599, 67108859,
554 555 556 557 558 559 560 561 562
				     100663291, 134217689, 201326557,
				     268535431, 0 };

static void
grow_entries(isc_task_t *task, isc_event_t *ev) {
	dns_adb_t *adb;
	dns_adbentry_t *e;
	dns_adbentrylist_t *newdeadentries = NULL;
	dns_adbentrylist_t *newentries = NULL;
563
	bool *newentry_sd = NULL;
564 565 566 567
	isc_mutex_t *newentrylocks = NULL;
	isc_result_t result;
	unsigned int *newentry_refcnt = NULL;
	unsigned int i, n, bucket;
Automatic Updater's avatar
Automatic Updater committed
568

569 570 571 572 573
	adb = ev->ev_arg;
	INSIST(DNS_ADB_VALID(adb));

	isc_event_free(&ev);

574 575 576
	result = isc_task_beginexclusive(task);
	if (result != ISC_R_SUCCESS)
		goto check_exit;
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610

	i = 0;
	while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i])
		i++;
	if (nbuckets[i] != 0)
		n = nbuckets[i];
	else
		goto done;

	DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n);

	/*
	 * Are we shutting down?
	 */
	for (i = 0; i < adb->nentries; i++)
		if (adb->entry_sd[i])
			goto cleanup;

	/*
	 * Grab all the resources we need.
	 */
	newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n);
	newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n);
	newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n);
	newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n);
	newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n);
	if (newentries == NULL || newdeadentries == NULL ||
	    newentrylocks == NULL || newentry_sd == NULL ||
	    newentry_refcnt == NULL)
		goto cleanup;

	/*
	 * Initialise the new resources.
	 */
611
	isc_mutexblock_init(newentrylocks, n);
612 613 614 615

	for (i = 0; i < n; i++) {
		ISC_LIST_INIT(newentries[i]);
		ISC_LIST_INIT(newdeadentries[i]);
616
		newentry_sd[i] = false;
617 618 619 620 621 622 623 624 625 626 627
		newentry_refcnt[i] = 0;
		adb->irefcnt++;
	}

	/*
	 * Move entries to new arrays.
	 */
	for (i = 0; i < adb->nentries; i++) {
		e = ISC_LIST_HEAD(adb->entries[i]);
		while (e != NULL) {
			ISC_LIST_UNLINK(adb->entries[i], e, plink);
628
			bucket = isc_sockaddr_hash(&e->sockaddr, true) % n;
629 630 631 632 633 634 635 636 637 638
			e->lock_bucket = bucket;
			ISC_LIST_APPEND(newentries[bucket], e, plink);
			INSIST(adb->entry_refcnt[i] > 0);
			adb->entry_refcnt[i]--;
			newentry_refcnt[bucket]++;
			e = ISC_LIST_HEAD(adb->entries[i]);
		}
		e = ISC_LIST_HEAD(adb->deadentries[i]);
		while (e != NULL) {
			ISC_LIST_UNLINK(adb->deadentries[i], e, plink);
639
			bucket = isc_sockaddr_hash(&e->sockaddr, true) % n;
640 641 642 643 644 645 646 647 648 649 650 651 652 653
			e->lock_bucket = bucket;
			ISC_LIST_APPEND(newdeadentries[bucket], e, plink);
			INSIST(adb->entry_refcnt[i] > 0);
			adb->entry_refcnt[i]--;
			newentry_refcnt[bucket]++;
			e = ISC_LIST_HEAD(adb->deadentries[i]);
		}
		INSIST(adb->entry_refcnt[i] == 0);
		adb->irefcnt--;
	}

	/*
	 * Cleanup old resources.
	 */
654
	isc_mutexblock_destroy(adb->entrylocks, adb->nentries);
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
	isc_mem_put(adb->mctx, adb->entries,
		    sizeof(*adb->entries) * adb->nentries);
	isc_mem_put(adb->mctx, adb->deadentries,
		    sizeof(*adb->deadentries) * adb->nentries);
	isc_mem_put(adb->mctx, adb->entrylocks,
		    sizeof(*adb->entrylocks) * adb->nentries);
	isc_mem_put(adb->mctx, adb->entry_sd,
		    sizeof(*adb->entry_sd) * adb->nentries);
	isc_mem_put(adb->mctx, adb->entry_refcnt,
		    sizeof(*adb->entry_refcnt) * adb->nentries);

	/*
	 * Install new resources.
	 */
	adb->entries = newentries;
	adb->deadentries = newdeadentries;
	adb->entrylocks = newentrylocks;
	adb->entry_sd = newentry_sd;
	adb->entry_refcnt = newentry_refcnt;
	adb->nentries = n;

676 677
	set_adbstat(adb, adb->nentries, dns_adbstats_nentries);

678
	/*
679
	 * Only on success do we set adb->growentries_sent to false.
680 681
	 * This will prevent us being continuously being called on error.
	 */
682
	adb->growentries_sent = false;
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
	goto done;

 cleanup:
	if (newentries != NULL)
		isc_mem_put(adb->mctx, newentries,
			    sizeof(*newentries) * n);
	if (newdeadentries != NULL)
		isc_mem_put(adb->mctx, newdeadentries,
			    sizeof(*newdeadentries) * n);
	if (newentrylocks != NULL)
		isc_mem_put(adb->mctx, newentrylocks,
			    sizeof(*newentrylocks) * n);
	if (newentry_sd != NULL)
		isc_mem_put(adb->mctx, newentry_sd,
			    sizeof(*newentry_sd) * n);
	if (newentry_refcnt != NULL)
		isc_mem_put(adb->mctx, newentry_refcnt,
			     sizeof(*newentry_refcnt) * n);
 done:
	isc_task_endexclusive(task);

704
 check_exit:
Automatic Updater's avatar
Automatic Updater committed
705 706 707 708
	LOCK(&adb->lock);
	if (dec_adb_irefcnt(adb))
		check_exit(adb);
	UNLOCK(&adb->lock);
709 710 711 712 713 714 715 716 717
	DP(ISC_LOG_INFO, "adb: grow_entries finished");
}

static void
grow_names(isc_task_t *task, isc_event_t *ev) {
	dns_adb_t *adb;
	dns_adbname_t *name;
	dns_adbnamelist_t *newdeadnames = NULL;
	dns_adbnamelist_t *newnames = NULL;
718
	bool *newname_sd = NULL;
719 720 721 722
	isc_mutex_t *newnamelocks = NULL;
	isc_result_t result;
	unsigned int *newname_refcnt = NULL;
	unsigned int i, n, bucket;
Automatic Updater's avatar
Automatic Updater committed
723

724 725 726 727 728
	adb = ev->ev_arg;
	INSIST(DNS_ADB_VALID(adb));

	isc_event_free(&ev);

729 730 731
	result = isc_task_beginexclusive(task);
	if (result != ISC_R_SUCCESS)
		goto check_exit;
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765

	i = 0;
	while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i])
		i++;
	if (nbuckets[i] != 0)
		n = nbuckets[i];
	else
		goto done;

	DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n);

	/*
	 * Are we shutting down?
	 */
	for (i = 0; i < adb->nnames; i++)
		if (adb->name_sd[i])
			goto cleanup;

	/*
	 * Grab all the resources we need.
	 */
	newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n);
	newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n);
	newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n);
	newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n);
	newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n);
	if (newnames == NULL || newdeadnames == NULL ||
	    newnamelocks == NULL || newname_sd == NULL ||
	    newname_refcnt == NULL)
		goto cleanup;

	/*
	 * Initialise the new resources.
	 */
766
	isc_mutexblock_init(newnamelocks, n);
767 768 769 770

	for (i = 0; i < n; i++) {
		ISC_LIST_INIT(newnames[i]);
		ISC_LIST_INIT(newdeadnames[i]);
771
		newname_sd[i] = false;
772 773 774 775 776 777 778 779 780 781 782
		newname_refcnt[i] = 0;
		adb->irefcnt++;
	}

	/*
	 * Move names to new arrays.
	 */
	for (i = 0; i < adb->nnames; i++) {
		name = ISC_LIST_HEAD(adb->names[i]);
		while (name != NULL) {
			ISC_LIST_UNLINK(adb->names[i], name, plink);
783
			bucket = dns_name_fullhash(&name->name, true) % n;
784 785 786 787 788 789 790 791 792 793
			name->lock_bucket = bucket;
			ISC_LIST_APPEND(newnames[bucket], name, plink);
			INSIST(adb->name_refcnt[i] > 0);
			adb->name_refcnt[i]--;
			newname_refcnt[bucket]++;
			name = ISC_LIST_HEAD(adb->names[i]);
		}
		name = ISC_LIST_HEAD(adb->deadnames[i]);
		while (name != NULL) {
			ISC_LIST_UNLINK(adb->deadnames[i], name, plink);
794
			bucket = dns_name_fullhash(&name->name, true) % n;
795 796 797 798 799 800 801 802 803 804 805 806 807 808
			name->lock_bucket = bucket;
			ISC_LIST_APPEND(newdeadnames[bucket], name, plink);
			INSIST(adb->name_refcnt[i] > 0);
			adb->name_refcnt[i]--;
			newname_refcnt[bucket]++;
			name = ISC_LIST_HEAD(adb->deadnames[i]);
		}
		INSIST(adb->name_refcnt[i] == 0);
		adb->irefcnt--;
	}

	/*
	 * Cleanup old resources.
	 */
809
	isc_mutexblock_destroy(adb->namelocks, adb->nnames);
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
	isc_mem_put(adb->mctx, adb->names,
		    sizeof(*adb->names) * adb->nnames);
	isc_mem_put(adb->mctx, adb->deadnames,
		    sizeof(*adb->deadnames) * adb->nnames);
	isc_mem_put(adb->mctx, adb->namelocks,
		    sizeof(*adb->namelocks) * adb->nnames);
	isc_mem_put(adb->mctx, adb->name_sd,
		    sizeof(*adb->name_sd) * adb->nnames);
	isc_mem_put(adb->mctx, adb->name_refcnt,
		    sizeof(*adb->name_refcnt) * adb->nnames);

	/*
	 * Install new resources.
	 */
	adb->names = newnames;
	adb->deadnames = newdeadnames;
	adb->namelocks = newnamelocks;
	adb->name_sd = newname_sd;
	adb->name_refcnt = newname_refcnt;
	adb->nnames = n;

831 832
	set_adbstat(adb, adb->nnames, dns_adbstats_nnames);

833
	/*
834
	 * Only on success do we set adb->grownames_sent to false.
835 836
	 * This will prevent us being continuously being called on error.
	 */
837
	adb->grownames_sent = false;
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
	goto done;

 cleanup:
	if (newnames != NULL)
		isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n);
	if (newdeadnames != NULL)
		isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n);
	if (newnamelocks != NULL)
		isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n);
	if (newname_sd != NULL)
		isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n);
	if (newname_refcnt != NULL)
		isc_mem_put(adb->mctx, newname_refcnt,
			     sizeof(*newname_refcnt) * n);
 done:
	isc_task_endexclusive(task);

855
 check_exit:
Automatic Updater's avatar
Automatic Updater committed
856 857 858 859
	LOCK(&adb->lock);
	if (dec_adb_irefcnt(adb))
		check_exit(adb);
	UNLOCK(&adb->lock);
860 861 862
	DP(ISC_LOG_INFO, "adb: grow_names finished");
}

863 864
/*
 * Requires the adbname bucket be locked and that no entry buckets be locked.
865 866
 *
 * This code handles A and AAAA rdatasets only.
867 868
 */
static isc_result_t
869
import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
Automatic Updater's avatar
Automatic Updater committed
870
		isc_stdtime_t now)
871
{
Automatic Updater's avatar
Automatic Updater committed
872 873 874 875 876 877 878 879 880 881
	isc_result_t result;
	dns_adb_t *adb;
	dns_adbnamehook_t *nh;
	dns_adbnamehook_t *anh;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	struct in_addr ina;
	struct in6_addr in6a;
	isc_sockaddr_t sockaddr;
	dns_adbentry_t *foundentry;  /* NO CLEAN UP! */
	int addr_bucket;
882
	bool new_addresses_added;
Automatic Updater's avatar
Automatic Updater committed
883 884
	dns_rdatatype_t rdtype;
	unsigned int findoptions;
885
	dns_adbnamehooklist_t *hookhead;
Automatic Updater's avatar
Automatic Updater committed
886 887 888 889 890 891 892 893 894 895 896 897 898

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

	rdtype = rdataset->type;
	INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
	if (rdtype == dns_rdatatype_a)
		findoptions = DNS_ADBFIND_INET;
	else
		findoptions = DNS_ADBFIND_INET6;

	addr_bucket = DNS_ADB_INVALIDBUCKET;
899
	new_addresses_added = false;
Automatic Updater's avatar
Automatic Updater committed
900 901 902 903 904 905 906 907

	nh = NULL;
	result = dns_rdataset_first(rdataset);
	while (result == ISC_R_SUCCESS) {
		dns_rdata_reset(&rdata);
		dns_rdataset_current(rdataset, &rdata);
		if (rdtype == dns_rdatatype_a) {
			INSIST(rdata.length == 4);
908
			memmove(&ina.s_addr, rdata.data, 4);
Automatic Updater's avatar
Automatic Updater committed
909
			isc_sockaddr_fromin(&sockaddr, &ina, 0);
910
			hookhead = &adbname->v4;
Automatic Updater's avatar
Automatic Updater committed
911 912
		} else {
			INSIST(rdata.length == 16);
913
			memmove(in6a.s6_addr, rdata.data, 16);
Automatic Updater's avatar
Automatic Updater committed
914
			isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
915
			hookhead = &adbname->v6;
Automatic Updater's avatar
Automatic Updater committed
916 917 918 919 920 921 922 923 924 925
		}

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

926 927
		foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket,
						 now);
Automatic Updater's avatar
Automatic Updater committed
928 929 930 931 932 933 934 935 936 937 938 939
		if (foundentry == NULL) {
			dns_adbentry_t *entry;

			entry = new_adbentry(adb);
			if (entry == NULL) {
				adbname->partial_result |= findoptions;
				result = ISC_R_NOMEMORY;
				goto fail;
			}

			entry->sockaddr = sockaddr;
			entry->refcnt = 1;
940
			entry->nh = 1;
Automatic Updater's avatar
Automatic Updater committed
941 942 943 944 945

			nh->entry = entry;

			link_entry(adb, addr_bucket, entry);
		} else {
946
			for (anh = ISC_LIST_HEAD(*hookhead);
Automatic Updater's avatar
Automatic Updater committed
947 948 949 950 951 952
			     anh != NULL;
			     anh = ISC_LIST_NEXT(anh, plink))
				if (anh->entry == foundentry)
					break;
			if (anh == NULL) {
				foundentry->refcnt++;
953
				foundentry->nh++;
Automatic Updater's avatar
Automatic Updater committed
954 955 956 957 958
				nh->entry = foundentry;
			} else
				free_adbnamehook(adb, &nh);
		}

959
		new_addresses_added = true;
960 961
		if (nh != NULL)
			ISC_LIST_APPEND(*hookhead, nh, plink);
Automatic Updater's avatar
Automatic Updater committed
962 963 964
		nh = NULL;
		result = dns_rdataset_next(rdataset);
	}
Michael Graff's avatar
Michael Graff committed
965 966

 fail: