adb.c revision 8e5fce1f9ceba17dd7e3ff0eb287e1e999c14249
f1c89cb4f5c72c54bb67dc48cd6f2b332eab9e92Automatic Updater * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC")
a6ca100924894cdd8e2b791d75a8cef32b1fba1fTinderbox User * Copyright (C) 1999-2003 Internet Software Consortium.
f1c89cb4f5c72c54bb67dc48cd6f2b332eab9e92Automatic Updater * Permission to use, copy, modify, and/or distribute this software for any
f1c89cb4f5c72c54bb67dc48cd6f2b332eab9e92Automatic Updater * purpose with or without fee is hereby granted, provided that the above
f1c89cb4f5c72c54bb67dc48cd6f2b332eab9e92Automatic Updater * copyright notice and this permission notice appear in all copies.
f1c89cb4f5c72c54bb67dc48cd6f2b332eab9e92Automatic Updater * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
f1c89cb4f5c72c54bb67dc48cd6f2b332eab9e92Automatic Updater * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
f1c89cb4f5c72c54bb67dc48cd6f2b332eab9e92Automatic Updater * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
f1c89cb4f5c72c54bb67dc48cd6f2b332eab9e92Automatic Updater * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
f1c89cb4f5c72c54bb67dc48cd6f2b332eab9e92Automatic Updater * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
f1c89cb4f5c72c54bb67dc48cd6f2b332eab9e92Automatic Updater * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
f1c89cb4f5c72c54bb67dc48cd6f2b332eab9e92Automatic Updater * PERFORMANCE OF THIS SOFTWARE.
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt/* $Id: adb.c,v 1.264.16.1 2011/12/22 07:48:27 marka Exp $ */
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * In finds, if task == NULL, no events will be generated, and no events
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * have been sent. If task != NULL but taskaction == NULL, an event has been
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * posted but not yet freed. If neither are NULL, no event was posted.
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#include <isc/string.h> /* Required for HP/UX (and others?) */
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b')
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADBNAME_MAGIC ISC_MAGIC('a', 'd', 'b', 'N')
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADBNAMEHOOK_MAGIC ISC_MAGIC('a', 'd', 'N', 'H')
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADBNAMEHOOK_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADBLAMEINFO_MAGIC ISC_MAGIC('a', 'd', 'b', 'Z')
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADBLAMEINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBLAMEINFO_MAGIC)
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADBENTRY_MAGIC ISC_MAGIC('a', 'd', 'b', 'E')
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADBFETCH_MAGIC ISC_MAGIC('a', 'd', 'F', '4')
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6')
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * For type 3 negative cache entries, we will remember that the address is
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * broken for this long. XXXMLG This is also used for actual addresses, too.
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * The intent is to keep us from constantly asking about A/AAAA records
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * if the zone has extremely low TTLs.
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define ADB_CACHE_MAXIMUM 86400 /*%< seconds (86400 = 24 hours) */
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * The period in seconds after which an ADB name entry is regarded as stale
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * and forced to be cleaned up.
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * TODO: This should probably be configurable at run-time.
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define FREE_ITEMS 64 /*%< free count for memory pools */
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define FILL_COUNT 16 /*%< fill count for memory pools */
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADB_INVALIDBUCKET (-1) /*%< invalid bucket address */
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt#define DNS_ADB_MINADBSIZE (1024*1024) /*%< 1 Megabyte */
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunttypedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunttypedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt/*% dns adb structure */
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int magic;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt isc_mutex_t reflock; /*%< Covers irefcnt, erefcnt */
79ce3a9e82384cc31fd6b86be8f3d1474fcfd9f4Evan Hunt unsigned int irefcnt;
79ce3a9e82384cc31fd6b86be8f3d1474fcfd9f4Evan Hunt unsigned int erefcnt;
03f979494f5c80e05a72f876914d9d44085fbd6aEvan Hunt * Bucketized locks and lists for names.
03f979494f5c80e05a72f876914d9d44085fbd6aEvan Hunt * XXXRTH Have a per-bucket structure that contains all of these?
79ce3a9e82384cc31fd6b86be8f3d1474fcfd9f4Evan Hunt unsigned int nnames;
79ce3a9e82384cc31fd6b86be8f3d1474fcfd9f4Evan Hunt unsigned int namescnt;
79ce3a9e82384cc31fd6b86be8f3d1474fcfd9f4Evan Hunt unsigned int *name_refcnt;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * Bucketized locks and lists for entries.
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * XXXRTH Have a per-bucket structure that contains all of these?
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int nentries;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int entriescnt;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int *entry_refcnt;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * XXXMLG Document these structures.
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt/*% dns_adbname structure */
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int magic;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int flags;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int chains;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int fetch6_err;
c6f4972c745f8903aba6dcca41f17a44c473db66Mark Andrews /* for LRU-based management */
c6f4972c745f8903aba6dcca41f17a44c473db66Mark Andrews/*% The adbfetch structure */
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int magic;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * This is a small widget that dangles off a dns_adbname_t. It contains a
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * pointer to the address information about this host, and a link to the next
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * namehook that will contain the next address this host has.
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int magic;
c6f4972c745f8903aba6dcca41f17a44c473db66Mark Andrews * This is a small widget that holds qname-specific information about an
c6f4972c745f8903aba6dcca41f17a44c473db66Mark Andrews * address. Currently limited to lameness, but could just as easily be
c6f4972c745f8903aba6dcca41f17a44c473db66Mark Andrews * extended to other types of information about zones.
c6f4972c745f8903aba6dcca41f17a44c473db66Mark Andrews unsigned int magic;
c6f4972c745f8903aba6dcca41f17a44c473db66Mark Andrews * An address entry. It holds quite a bit of information about addresses,
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * including edns state (in "flags"), rtt, and of course the address of
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int magic;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int refcnt;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int flags;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int srtt;
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * A nonzero 'expires' field indicates that the entry should
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * persist until that time. This allows entries found
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * using dns_adb_findaddrinfo() to persist for a limited time
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * even though they are not necessarily associated with a
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt * Internal functions (and prototypes).
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline void free_adbname(dns_adb_t *, dns_adbname_t **);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *, dns_name_t *,
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline dns_adbentry_t *new_adbentry(dns_adb_t *);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline dns_adbfind_t *new_adbfind(dns_adb_t *);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
2637d30fbd235fe98145f4312b10cc41a13bf7dcJeremy C. Reedstatic inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Hunt unsigned int, int *);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic void print_namehook_list(FILE *, const char *legend,
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic void print_find_list(FILE *, dns_adbname_t *);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic void print_fetch_list(FILE *, dns_adbname_t *);
0b24b2d3c423560a0a4cd9a4476b9a2dcafb7ea3Evan Huntstatic inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
static void water(void *, int);
((o) & DNS_ADBFIND_STARTATZONE))
(r) == DNS_R_NCACHENXRRSET)
(r) == DNS_R_NXRRSET)
(r) == DNS_R_NCACHENXDOMAIN)
(r) == DNS_R_NXRRSET || \
(r) == DNS_R_HINTNXRRSET)
static const char *errnames[] = {
static inline dns_ttl_t
return (ttl);
dns_adbentry_t *e;
unsigned int i, n, bucket;
goto check_exit;
if (nbuckets[i] != 0)
n = nbuckets[i];
goto done;
goto cleanup;
goto cleanup;
goto cleanup;
newentry_refcnt[i] = 0;
while (e != NULL) {
while (e != NULL) {
goto done;
sizeof(*newentries) * n);
sizeof(*newdeadentries) * n);
sizeof(*newentrylocks) * n);
sizeof(*newentry_sd) * n);
sizeof(*newentry_refcnt) * n);
done:
unsigned int i, n, bucket;
goto check_exit;
if (nbuckets[i] != 0)
n = nbuckets[i];
goto done;
goto cleanup;
goto cleanup;
goto cleanup;
newname_refcnt[i] = 0;
goto done;
sizeof(*newname_refcnt) * n);
done:
static isc_result_t
int addr_bucket;
unsigned int findoptions;
goto fail;
now);
goto fail;
fail:
if (new_addresses_added) {
return (ISC_R_SUCCESS);
return (result);
static isc_boolean_t
int bucket;
name = *n;
*n = NULL;
if (result)
return (result);
if (result)
return (result);
static isc_boolean_t
static inline isc_boolean_t
int bucket;
return (result);
dns_adbentry_t *e;
if (e == NULL)
if (e->refcnt == 0) {
static inline isc_boolean_t
int bucket;
return (result);
static isc_boolean_t
unsigned int bucket;
return (result);
static isc_boolean_t
unsigned int bucket;
if (result)
return (result);
static isc_boolean_t
int addr_bucket;
return (result);
static isc_result_t
unsigned int nlabels;
int order;
return (result);
return (result);
return (result);
return (result);
return (result);
NULL);
return (result);
return (result);
return (ISC_R_SUCCESS);
unsigned int addrs)
switch (evtype) {
if ((notify) != 0) {
if (wanted == 0)
if (process) {
static inline isc_boolean_t
return (result);
int bucket;
if (lock)
if (lock)
static inline isc_boolean_t
int bucket;
if (lock)
if (lock)
if (!destroy_entry)
return (result);
if (result)
return (result);
static inline dns_adbname_t *
return (NULL);
return (NULL);
return (name);
dns_adbname_t *n;
n = *name;
n->magic = 0;
static inline dns_adbnamehook_t *
return (NULL);
return (nh);
static inline dns_adblameinfo_t *
return (NULL);
return (NULL);
return (li);
static inline dns_adbentry_t *
dns_adbentry_t *e;
isc_uint32_t r;
if (e == NULL)
return (NULL);
e->refcnt = 0;
e->flags = 0;
isc_random_get(&r);
e->expires = 0;
dns_adbentry_t *e;
e = *entry;
e->magic = 0;
static inline dns_adbfind_t *
dns_adbfind_t *h;
if (h == NULL)
return (NULL);
h->magic = 0;
h->partial_result = 0;
h->options = 0;
h->flags = 0;
return (NULL);
static inline dns_adbfetch_t *
dns_adbfetch_t *f;
if (f == NULL)
return (NULL);
f->magic = 0;
dns_adbfetch_t *f;
f = *fetch;
f->magic = 0;
static inline isc_boolean_t
static inline dns_adbaddrinfo_t *
return (NULL);
return (ai);
static inline dns_adbname_t *
int bucket;
return (adbname);
return (NULL);
static inline dns_adbentry_t *
int bucket;
return (entry);
return (NULL);
static isc_boolean_t
return (ISC_FALSE);
return (is_bad);
int bucket;
goto nextv4;
goto out;
goto nextv6;
goto out;
out:
static isc_boolean_t
return (result);
return (result);
return (result);
return (result);
return (result);
return (result);
int scans = 0;
for (victims = 0;
scans++;
victims++;
goto next;
victims++;
next:
if (!overmem)
static isc_boolean_t
return (result);
return (result);
if (result)
return (result);
static isc_boolean_t
return (result);
if (!result)
return (result);
static isc_boolean_t
return (result);
return (ISC_R_NOMEMORY);
goto fail0b;
goto fail0c;
goto fail0d;
goto fail0e;
goto fail0f;
goto fail0g;
goto fail1; \
goto fail1; \
goto fail1;
goto fail2;
#define MPINIT(t, p, n) do { \
goto fail3; \
isc_mempool_setname((p), n); \
goto fail3;
goto fail3;
return (ISC_R_SUCCESS);
return (result);
if (need_exit_check) {
if (!need_check_exit)
if (need_check_exit)
int bucket;
unsigned int wanted_addresses;
unsigned int wanted_fetches;
unsigned int query_pending;
wanted_fetches = 0;
query_pending = 0;
if (now == 0)
return (ISC_R_NOMEMORY);
goto out;
goto out;
adbname);
goto post_copy;
adbname);
goto v6;
adbname);
goto post_copy;
goto fetch;
goto v6;
v6:
adbname);
goto fetch;
adbname);
goto post_copy;
goto fetch;
if (wanted_fetches != 0 &&
adbname);
adbname);
if (alias)
if (want_event) {
if (alias) {
goto out;
out:
if (want_event) {
return (result);
int bucket;
int bucket;
int unlock_bucket;
goto cleanup;
if (debug)
if (debug)
if (debug)
if (debug)
if (debug)
if (debug)
const char *tmpp;
case AF_INET:
case AF_INET6:
if (debug)
if (NAME_FETCH_A(n))
if (NAME_FETCH_AAAA(n))
static isc_result_t
switch (result) {
case DNS_R_GLUE:
case DNS_R_HINT:
case ISC_R_SUCCESS:
case DNS_R_NXDOMAIN:
case DNS_R_NXRRSET:
adbname);
adbname);
case DNS_R_NCACHENXDOMAIN:
case DNS_R_NCACHENXRRSET:
case DNS_R_CNAME:
case DNS_R_DNAME:
adbname);
return (result);
int bucket;
unsigned int address_type;
address_type = 0;
if (want_check_exit) {
goto out;
name);
goto check_result;
goto out;
out:
static isc_result_t
unsigned int options;
if (start_at_zone) {
adbname);
goto cleanup;
goto cleanup;
goto cleanup;
return (result);
int bucket;
goto unlock;
goto unlock;
return (result);
int bucket;
unsigned int new_srtt;
int bucket;
int bucket;
goto unlock;
goto unlock;
return (result);
int bucket;
if (want_check_exit) {
#ifdef DUMP_ADB_AFTER_CLEANING
int bucket;