1999-09-21 22:46:42 +00:00
|
|
|
/*
|
2001-01-09 22:01:04 +00:00
|
|
|
* Copyright (C) 1999-2001 Internet Software Consortium.
|
2000-08-01 01:33:37 +00:00
|
|
|
*
|
1999-09-21 22:46:42 +00:00
|
|
|
* 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.
|
2000-08-01 01:33:37 +00:00
|
|
|
*
|
2000-07-27 09:55:03 +00:00
|
|
|
* 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.
|
1999-09-21 22:46:42 +00:00
|
|
|
*/
|
|
|
|
|
2003-07-25 02:22:26 +00:00
|
|
|
/* $Id: adb.c,v 1.205 2003/07/25 02:22:24 marka Exp $ */
|
2000-06-22 22:00:42 +00:00
|
|
|
|
1999-09-23 00:43:10 +00:00
|
|
|
/*
|
|
|
|
* Implementation notes
|
|
|
|
* --------------------
|
|
|
|
*
|
1999-10-29 18:30:48 +00:00
|
|
|
* In finds, if task == NULL, no events will be generated, and no events
|
1999-09-23 00:43:10 +00:00
|
|
|
* have been sent. If task != NULL but taskaction == NULL, an event has been
|
1999-11-25 01:23:32 +00:00
|
|
|
* posted but not yet freed. If neither are NULL, no event was posted.
|
1999-09-23 00:43:10 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
1999-11-24 19:23:27 +00:00
|
|
|
/*
|
|
|
|
* After we have cleaned all buckets, dump the database contents.
|
|
|
|
*/
|
2000-06-08 01:43:21 +00:00
|
|
|
#if 0
|
1999-11-24 19:23:27 +00:00
|
|
|
#define DUMP_ADB_AFTER_CLEANING
|
2000-06-08 01:43:21 +00:00
|
|
|
#endif
|
1999-11-24 19:23:27 +00:00
|
|
|
|
1999-09-21 22:46:42 +00:00
|
|
|
#include <config.h>
|
|
|
|
|
2000-01-21 02:13:38 +00:00
|
|
|
#include <limits.h>
|
2000-05-08 14:38:29 +00:00
|
|
|
|
1999-09-24 23:54:42 +00:00
|
|
|
#include <isc/mutexblock.h>
|
2000-12-18 20:03:33 +00:00
|
|
|
#include <isc/netaddr.h>
|
1999-10-20 23:26:06 +00:00
|
|
|
#include <isc/random.h>
|
2000-05-08 19:23:32 +00:00
|
|
|
#include <isc/string.h> /* Required for HP/UX (and others?) */
|
2000-05-08 14:38:29 +00:00
|
|
|
#include <isc/task.h>
|
1999-10-25 22:53:15 +00:00
|
|
|
#include <isc/timer.h>
|
1999-12-16 22:24:22 +00:00
|
|
|
#include <isc/util.h>
|
1999-09-22 00:26:20 +00:00
|
|
|
|
1999-10-22 01:02:38 +00:00
|
|
|
#include <dns/adb.h>
|
1999-10-21 01:18:06 +00:00
|
|
|
#include <dns/db.h>
|
1999-10-16 00:38:21 +00:00
|
|
|
#include <dns/events.h>
|
1999-10-29 22:28:57 +00:00
|
|
|
#include <dns/log.h>
|
1999-10-05 23:50:43 +00:00
|
|
|
#include <dns/rdata.h>
|
|
|
|
#include <dns/rdataset.h>
|
2000-10-07 00:09:28 +00:00
|
|
|
#include <dns/rdatastruct.h>
|
1999-10-25 21:39:08 +00:00
|
|
|
#include <dns/resolver.h>
|
2000-05-02 03:54:17 +00:00
|
|
|
#include <dns/result.h>
|
1999-09-23 00:43:10 +00:00
|
|
|
|
2001-06-04 19:33:39 +00:00
|
|
|
#define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b')
|
1999-09-25 01:25:46 +00:00
|
|
|
#define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
|
2001-06-04 19:33:39 +00:00
|
|
|
#define DNS_ADBNAME_MAGIC ISC_MAGIC('a', 'd', 'b', 'N')
|
1999-09-25 01:25:46 +00:00
|
|
|
#define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
|
2001-06-04 19:33:39 +00:00
|
|
|
#define DNS_ADBNAMEHOOK_MAGIC ISC_MAGIC('a', 'd', 'N', 'H')
|
1999-09-25 01:25:46 +00:00
|
|
|
#define DNS_ADBNAMEHOOK_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
|
2001-06-04 19:33:39 +00:00
|
|
|
#define DNS_ADBZONEINFO_MAGIC ISC_MAGIC('a', 'd', 'b', 'Z')
|
1999-09-25 01:25:46 +00:00
|
|
|
#define DNS_ADBZONEINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBZONEINFO_MAGIC)
|
2001-06-04 19:33:39 +00:00
|
|
|
#define DNS_ADBENTRY_MAGIC ISC_MAGIC('a', 'd', 'b', 'E')
|
1999-09-25 01:25:46 +00:00
|
|
|
#define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
|
2001-06-04 19:33:39 +00:00
|
|
|
#define DNS_ADBFETCH_MAGIC ISC_MAGIC('a', 'd', 'F', '4')
|
1999-10-25 21:02:54 +00:00
|
|
|
#define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
|
2001-06-04 19:33:39 +00:00
|
|
|
#define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6')
|
1999-10-30 01:22:16 +00:00
|
|
|
#define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
|
1999-09-22 00:26:20 +00:00
|
|
|
|
1999-09-23 00:43:10 +00:00
|
|
|
/*
|
1999-11-25 01:23:32 +00:00
|
|
|
* The number of buckets needs to be a prime (for good hashing).
|
|
|
|
*
|
|
|
|
* XXXRTH How many buckets do we need?
|
1999-09-23 00:43:10 +00:00
|
|
|
*/
|
1999-12-01 02:05:16 +00:00
|
|
|
#define NBUCKETS 1009 /* how many buckets for names/addrs */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For type 3 negative cache entries, we will remember that the address is
|
1999-12-11 02:30:24 +00:00
|
|
|
* broken for this long. XXXMLG This is also used for actual addresses, too.
|
2002-11-27 09:52:58 +00:00
|
|
|
* The intent is to keep us from constantly asking about A/AAAA records
|
1999-12-11 02:30:24 +00:00
|
|
|
* if the zone has extremely low TTLs.
|
1999-12-01 02:05:16 +00:00
|
|
|
*/
|
2000-01-19 01:43:58 +00:00
|
|
|
#define ADB_CACHE_MINIMUM 10 /* seconds */
|
2000-06-07 20:15:48 +00:00
|
|
|
#define ADB_CACHE_MAXIMUM 86400 /* seconds (86400 = 24 hours) */
|
2003-07-18 04:30:01 +00:00
|
|
|
#define ADB_ENTRY_WINDOW 1800 /* seconds */
|
1999-09-23 00:43:10 +00:00
|
|
|
|
1999-11-25 01:23:32 +00:00
|
|
|
/*
|
2001-01-26 03:20:58 +00:00
|
|
|
* Wake up every CLEAN_SECONDS and clean CLEAN_BUCKETS buckets, so that all
|
|
|
|
* buckets are cleaned in CLEAN_PERIOD seconds.
|
1999-11-25 01:23:32 +00:00
|
|
|
*/
|
2001-01-26 03:20:58 +00:00
|
|
|
#define CLEAN_PERIOD 3600
|
|
|
|
#define CLEAN_SECONDS 30
|
|
|
|
#define CLEAN_BUCKETS ((NBUCKETS * CLEAN_SECONDS) / CLEAN_PERIOD)
|
1999-10-25 22:53:15 +00:00
|
|
|
|
2000-04-19 17:48:25 +00:00
|
|
|
#define FREE_ITEMS 64 /* free count for memory pools */
|
|
|
|
#define FILL_COUNT 16 /* fill count for memory pools */
|
1999-09-22 01:01:14 +00:00
|
|
|
|
1999-10-02 01:59:09 +00:00
|
|
|
#define DNS_ADB_INVALIDBUCKET (-1) /* invalid bucket address */
|
|
|
|
|
2001-10-25 04:57:46 +00:00
|
|
|
#define DNS_ADB_MINADBSIZE (1024*1024) /* 1 Megabyte */
|
|
|
|
|
1999-09-22 01:01:14 +00:00
|
|
|
typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
|
1999-09-22 00:26:20 +00:00
|
|
|
typedef struct dns_adbnamehook dns_adbnamehook_t;
|
1999-10-29 01:26:45 +00:00
|
|
|
typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
|
1999-09-22 00:26:20 +00:00
|
|
|
typedef struct dns_adbzoneinfo dns_adbzoneinfo_t;
|
1999-09-23 00:43:10 +00:00
|
|
|
typedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t;
|
1999-10-25 21:02:54 +00:00
|
|
|
typedef struct dns_adbfetch dns_adbfetch_t;
|
1999-10-30 01:22:16 +00:00
|
|
|
typedef struct dns_adbfetch6 dns_adbfetch6_t;
|
1999-09-21 22:46:42 +00:00
|
|
|
|
|
|
|
struct dns_adb {
|
1999-09-22 00:26:20 +00:00
|
|
|
unsigned int magic;
|
|
|
|
|
|
|
|
isc_mutex_t lock;
|
2001-11-07 22:40:33 +00:00
|
|
|
isc_mutex_t reflock; /* Covers irefcnt, erefcnt */
|
1999-09-22 00:26:20 +00:00
|
|
|
isc_mem_t *mctx;
|
1999-10-08 23:12:21 +00:00
|
|
|
dns_view_t *view;
|
1999-10-25 21:39:08 +00:00
|
|
|
isc_timermgr_t *timermgr;
|
1999-10-25 22:53:15 +00:00
|
|
|
isc_timer_t *timer;
|
1999-10-25 21:39:08 +00:00
|
|
|
isc_taskmgr_t *taskmgr;
|
1999-10-25 22:53:15 +00:00
|
|
|
isc_task_t *task;
|
2001-10-25 04:57:46 +00:00
|
|
|
isc_boolean_t overmem;
|
1999-10-29 23:53:12 +00:00
|
|
|
|
1999-10-25 22:53:15 +00:00
|
|
|
isc_interval_t tick_interval;
|
2000-01-12 03:00:33 +00:00
|
|
|
int next_cleanbucket;
|
1999-09-22 00:26:20 +00:00
|
|
|
|
1999-10-19 01:37:22 +00:00
|
|
|
unsigned int irefcnt;
|
|
|
|
unsigned int erefcnt;
|
1999-10-05 23:50:43 +00:00
|
|
|
|
1999-09-23 00:43:10 +00:00
|
|
|
isc_mutex_t mplock;
|
1999-09-22 00:26:20 +00:00
|
|
|
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 */
|
1999-10-29 18:07:32 +00:00
|
|
|
isc_mempool_t *ahmp; /* dns_adbfind_t */
|
1999-09-22 00:26:20 +00:00
|
|
|
isc_mempool_t *aimp; /* dns_adbaddrinfo_t */
|
1999-10-25 21:02:54 +00:00
|
|
|
isc_mempool_t *afmp; /* dns_adbfetch_t */
|
1999-09-22 00:26:20 +00:00
|
|
|
|
1999-09-22 01:01:14 +00:00
|
|
|
/*
|
|
|
|
* Bucketized locks and lists for names.
|
1999-11-25 01:23:32 +00:00
|
|
|
*
|
|
|
|
* XXXRTH Have a per-bucket structure that contains all of these?
|
1999-09-22 01:01:14 +00:00
|
|
|
*/
|
1999-11-05 02:05:06 +00:00
|
|
|
dns_adbnamelist_t names[NBUCKETS];
|
|
|
|
isc_mutex_t namelocks[NBUCKETS];
|
|
|
|
isc_boolean_t name_sd[NBUCKETS];
|
|
|
|
unsigned int name_refcnt[NBUCKETS];
|
1999-09-22 01:01:14 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Bucketized locks for entries.
|
1999-11-25 01:23:32 +00:00
|
|
|
*
|
|
|
|
* XXXRTH Have a per-bucket structure that contains all of these?
|
1999-09-22 01:01:14 +00:00
|
|
|
*/
|
1999-11-05 02:05:06 +00:00
|
|
|
dns_adbentrylist_t entries[NBUCKETS];
|
|
|
|
isc_mutex_t entrylocks[NBUCKETS];
|
2001-04-30 18:27:10 +00:00
|
|
|
isc_boolean_t entry_sd[NBUCKETS]; /* shutting down */
|
2000-01-12 03:00:33 +00:00
|
|
|
unsigned int entry_refcnt[NBUCKETS];
|
1999-11-22 19:57:58 +00:00
|
|
|
|
|
|
|
isc_event_t cevent;
|
|
|
|
isc_boolean_t cevent_sent;
|
|
|
|
isc_boolean_t shutting_down;
|
|
|
|
isc_eventlist_t whenshutdown;
|
1999-09-21 22:46:42 +00:00
|
|
|
};
|
|
|
|
|
1999-11-25 01:23:32 +00:00
|
|
|
/*
|
|
|
|
* XXXMLG Document these structures.
|
|
|
|
*/
|
|
|
|
|
1999-09-22 00:26:20 +00:00
|
|
|
struct dns_adbname {
|
|
|
|
unsigned int magic;
|
1999-09-23 00:43:10 +00:00
|
|
|
dns_name_t name;
|
1999-10-27 19:36:58 +00:00
|
|
|
dns_adb_t *adb;
|
1999-10-28 21:50:27 +00:00
|
|
|
unsigned int partial_result;
|
1999-10-30 01:58:02 +00:00
|
|
|
unsigned int flags;
|
1999-10-29 22:09:31 +00:00
|
|
|
int lock_bucket;
|
2000-01-19 01:43:58 +00:00
|
|
|
dns_name_t target;
|
|
|
|
isc_stdtime_t expire_target;
|
1999-10-29 01:26:45 +00:00
|
|
|
isc_stdtime_t expire_v4;
|
|
|
|
isc_stdtime_t expire_v6;
|
1999-10-30 01:22:16 +00:00
|
|
|
unsigned int chains;
|
1999-10-29 01:26:45 +00:00
|
|
|
dns_adbnamehooklist_t v4;
|
|
|
|
dns_adbnamehooklist_t v6;
|
1999-10-29 21:48:51 +00:00
|
|
|
dns_adbfetch_t *fetch_a;
|
|
|
|
dns_adbfetch_t *fetch_aaaa;
|
2000-08-26 02:21:45 +00:00
|
|
|
unsigned int fetch_err;
|
|
|
|
unsigned int fetch6_err;
|
1999-11-05 09:49:53 +00:00
|
|
|
dns_adbfindlist_t finds;
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LINK(dns_adbname_t) plink;
|
1999-09-22 00:26:20 +00:00
|
|
|
};
|
|
|
|
|
1999-10-25 21:02:54 +00:00
|
|
|
struct dns_adbfetch {
|
|
|
|
unsigned int magic;
|
|
|
|
dns_adbnamehook_t *namehook;
|
|
|
|
dns_adbentry_t *entry;
|
|
|
|
dns_fetch_t *fetch;
|
|
|
|
dns_rdataset_t rdataset;
|
|
|
|
};
|
|
|
|
|
1999-09-22 00:26:20 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
1999-09-23 00:43:10 +00:00
|
|
|
dns_adbentry_t *entry;
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LINK(dns_adbnamehook_t) plink;
|
1999-09-21 22:46:42 +00:00
|
|
|
};
|
|
|
|
|
1999-09-22 00:26:20 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
1999-10-08 23:12:21 +00:00
|
|
|
dns_name_t zone;
|
1999-10-19 20:55:04 +00:00
|
|
|
isc_stdtime_t lame_timer;
|
1999-09-22 00:26:20 +00:00
|
|
|
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LINK(dns_adbzoneinfo_t) plink;
|
1999-09-22 00:26:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* An address entry. It holds quite a bit of information about addresses,
|
2001-01-22 22:53:13 +00:00
|
|
|
* including edns state (in "flags"), rtt, and of course the address of
|
|
|
|
* the host.
|
1999-09-22 00:26:20 +00:00
|
|
|
*/
|
1999-09-21 22:46:42 +00:00
|
|
|
struct dns_adbentry {
|
1999-09-22 00:26:20 +00:00
|
|
|
unsigned int magic;
|
|
|
|
|
1999-09-23 00:43:10 +00:00
|
|
|
int lock_bucket;
|
1999-10-08 23:12:21 +00:00
|
|
|
unsigned int refcnt;
|
1999-09-22 00:26:20 +00:00
|
|
|
|
|
|
|
unsigned int flags;
|
|
|
|
unsigned int srtt;
|
|
|
|
isc_sockaddr_t sockaddr;
|
2001-04-30 18:27:10 +00:00
|
|
|
|
2000-01-12 03:00:33 +00:00
|
|
|
isc_stdtime_t expires;
|
2001-04-30 18:27:10 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
1999-09-22 00:26:20 +00:00
|
|
|
|
|
|
|
ISC_LIST(dns_adbzoneinfo_t) zoneinfo;
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LINK(dns_adbentry_t) plink;
|
1999-09-21 22:46:42 +00:00
|
|
|
};
|
|
|
|
|
1999-09-22 00:26:20 +00:00
|
|
|
/*
|
1999-09-23 00:43:10 +00:00
|
|
|
* Internal functions (and prototypes).
|
|
|
|
*/
|
1999-10-19 20:55:04 +00:00
|
|
|
static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
|
1999-10-08 23:12:21 +00:00
|
|
|
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 **);
|
1999-10-19 21:10:29 +00:00
|
|
|
static inline dns_adbzoneinfo_t *new_adbzoneinfo(dns_adb_t *, dns_name_t *);
|
1999-10-08 23:12:21 +00:00
|
|
|
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 **);
|
1999-10-29 18:30:48 +00:00
|
|
|
static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
|
2002-11-13 00:07:04 +00:00
|
|
|
static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
|
2000-06-01 00:30:58 +00:00
|
|
|
static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
|
|
|
|
in_port_t);
|
1999-10-29 01:26:45 +00:00
|
|
|
static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
|
|
|
|
static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
|
1999-10-08 23:12:21 +00:00
|
|
|
static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
|
2000-02-02 23:24:04 +00:00
|
|
|
unsigned int, int *);
|
1999-10-08 23:12:21 +00:00
|
|
|
static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
|
|
|
|
isc_sockaddr_t *, int *);
|
2000-12-18 20:03:33 +00:00
|
|
|
static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug);
|
1999-10-08 23:12:21 +00:00
|
|
|
static void print_dns_name(FILE *, dns_name_t *);
|
2000-12-18 20:03:33 +00:00
|
|
|
static void print_namehook_list(FILE *, const char *legend,
|
|
|
|
dns_adbnamehooklist_t *list,
|
2002-09-10 02:01:15 +00:00
|
|
|
isc_boolean_t debug,
|
|
|
|
isc_stdtime_t now);
|
1999-10-29 18:30:48 +00:00
|
|
|
static void print_find_list(FILE *, dns_adbname_t *);
|
1999-10-27 19:36:58 +00:00
|
|
|
static void print_fetch_list(FILE *, dns_adbname_t *);
|
2002-11-13 00:07:04 +00:00
|
|
|
static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
|
|
|
|
static inline void inc_adb_irefcnt(dns_adb_t *);
|
2001-11-07 22:40:33 +00:00
|
|
|
static inline void inc_adb_erefcnt(dns_adb_t *);
|
1999-10-08 23:12:21 +00:00
|
|
|
static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
|
|
|
|
isc_boolean_t);
|
2002-11-13 00:07:04 +00:00
|
|
|
static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
|
1999-10-08 23:12:21 +00:00
|
|
|
isc_boolean_t);
|
1999-10-19 20:55:04 +00:00
|
|
|
static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
|
2002-11-13 00:07:04 +00:00
|
|
|
static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
|
2000-01-19 01:43:58 +00:00
|
|
|
static void clean_target(dns_adb_t *, dns_name_t *);
|
1999-10-30 01:58:02 +00:00
|
|
|
static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
|
|
|
|
unsigned int);
|
2002-11-13 00:07:04 +00:00
|
|
|
static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t,
|
2001-10-25 04:57:46 +00:00
|
|
|
isc_boolean_t);
|
2000-01-21 02:50:27 +00:00
|
|
|
static void cancel_fetches_at_name(dns_adbname_t *);
|
1999-11-02 00:29:45 +00:00
|
|
|
static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
|
2000-02-02 23:24:04 +00:00
|
|
|
dns_rdatatype_t);
|
2002-11-27 09:52:58 +00:00
|
|
|
static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
|
|
|
|
dns_rdatatype_t);
|
1999-10-26 23:44:36 +00:00
|
|
|
static inline void check_exit(dns_adb_t *);
|
1999-10-25 22:53:15 +00:00
|
|
|
static void timer_cleanup(isc_task_t *, isc_event_t *);
|
1999-10-25 23:18:19 +00:00
|
|
|
static void destroy(dns_adb_t *);
|
2002-11-13 00:07:04 +00:00
|
|
|
static isc_boolean_t shutdown_names(dns_adb_t *);
|
|
|
|
static isc_boolean_t shutdown_entries(dns_adb_t *);
|
1999-10-26 23:44:36 +00:00
|
|
|
static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
|
2002-11-13 00:07:04 +00:00
|
|
|
static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *);
|
2000-01-12 03:00:33 +00:00
|
|
|
static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
|
2002-11-13 00:07:04 +00:00
|
|
|
static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
|
|
|
|
static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
|
2001-10-25 04:57:46 +00:00
|
|
|
static void water(void *arg, int mark);
|
1999-10-29 01:26:45 +00:00
|
|
|
|
1999-10-30 01:58:02 +00:00
|
|
|
/*
|
|
|
|
* MUST NOT overlap DNS_ADBFIND_* flags!
|
|
|
|
*/
|
|
|
|
#define FIND_EVENT_SENT 0x40000000
|
|
|
|
#define FIND_EVENT_FREED 0x80000000
|
1999-11-04 08:48:47 +00:00
|
|
|
#define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0)
|
|
|
|
#define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0)
|
1999-10-29 18:00:31 +00:00
|
|
|
|
1999-10-30 01:58:02 +00:00
|
|
|
#define NAME_NEEDS_POKE 0x80000000
|
|
|
|
#define NAME_IS_DEAD 0x40000000
|
2000-02-02 23:24:04 +00:00
|
|
|
#define NAME_HINT_OK DNS_ADBFIND_HINTOK
|
|
|
|
#define NAME_GLUE_OK DNS_ADBFIND_GLUEOK
|
2003-02-26 22:54:29 +00:00
|
|
|
#define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE
|
1999-10-30 01:58:02 +00:00
|
|
|
#define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0)
|
|
|
|
#define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0)
|
2000-02-02 23:24:04 +00:00
|
|
|
#define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0)
|
Silence IRIX warnings:
"adb.c", line 2042: remark(1552): variable "result" was set but never used
isc_result_t result;
^
"adb.c", line 3082: warning(1185): enumerated type mixed with another type
NAME_GLUEOK(adbname), NAME_HINTOK(adbname),
^
"adb.c", line 3187: warning(1185): enumerated type mixed with another type
now, NAME_GLUEOK(adbname), NAME_HINTOK(adbname),
Note that the first is in timer_cleanup, a function returning void in a context
that can't do anything with something other than void (as an isc_taskaction_t).
It calls isc_timer_reset, which could conceivably return ISC_R_NOMEMORY or
ISC_R_UNEXPECTED. For now the call has been cast to void, but someone
who knows the code better should have a look and see whether something more
intelligent could be done with an error (and, if not, remove my XXX and
make sure the comment is clear as to why ignoring the return is the
best that can be done).
2000-05-13 20:15:16 +00:00
|
|
|
#define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0)
|
1999-11-02 00:29:45 +00:00
|
|
|
|
1999-11-04 08:48:47 +00:00
|
|
|
/*
|
|
|
|
* To the name, address classes are all that really exist. If it has a
|
2002-11-27 09:52:58 +00:00
|
|
|
* V6 address it doesn't care if it came from a AAAA query.
|
1999-11-04 08:48:47 +00:00
|
|
|
*/
|
|
|
|
#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))
|
1999-10-26 23:44:36 +00:00
|
|
|
|
1999-11-04 08:48:47 +00:00
|
|
|
/*
|
2002-11-27 09:52:58 +00:00
|
|
|
* Fetches are broken out into A and AAAA types. In some cases,
|
1999-11-04 08:48:47 +00:00
|
|
|
* however, it makes more sense to test for a particular class of fetches,
|
|
|
|
* like V4 or V6 above.
|
2002-11-27 09:52:58 +00:00
|
|
|
* 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.
|
1999-11-04 08:48:47 +00:00
|
|
|
*/
|
1999-11-02 18:36:54 +00:00
|
|
|
#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))
|
2002-11-27 09:52:58 +00:00
|
|
|
#define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n))
|
1999-11-02 18:36:54 +00:00
|
|
|
#define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
|
1999-10-29 21:48:51 +00:00
|
|
|
|
1999-11-04 08:48:47 +00:00
|
|
|
/*
|
|
|
|
* 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)
|
1999-12-14 00:10:06 +00:00
|
|
|
#define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
|
|
|
|
!= 0)
|
2003-02-26 22:54:29 +00:00
|
|
|
#define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \
|
2000-01-06 00:56:37 +00:00
|
|
|
!= 0)
|
2000-02-02 23:24:04 +00:00
|
|
|
#define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
|
|
|
|
#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
|
1999-11-04 08:48:47 +00:00
|
|
|
#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list))
|
2000-02-02 23:27:39 +00:00
|
|
|
#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
|
1999-12-14 00:10:06 +00:00
|
|
|
|
1999-11-04 08:48:47 +00:00
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
|
1999-11-04 06:46:05 +00:00
|
|
|
#define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now))
|
|
|
|
|
2000-02-02 23:24:04 +00:00
|
|
|
/*
|
|
|
|
* 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))
|
2003-02-26 22:54:29 +00:00
|
|
|
#define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \
|
|
|
|
((o) & DNS_ADBFIND_STARTATZONE))
|
2000-02-02 23:24:04 +00:00
|
|
|
|
2002-09-10 02:01:15 +00:00
|
|
|
#define ENTER_LEVEL ISC_LOG_DEBUG(50)
|
1999-11-01 20:16:35 +00:00
|
|
|
#define EXIT_LEVEL ENTER_LEVEL
|
2002-09-10 02:01:15 +00:00
|
|
|
#define CLEAN_LEVEL ISC_LOG_DEBUG(100)
|
|
|
|
#define DEF_LEVEL ISC_LOG_DEBUG(5)
|
|
|
|
#define NCACHE_LEVEL ISC_LOG_DEBUG(20)
|
1999-11-01 20:16:35 +00:00
|
|
|
|
1999-11-24 19:23:27 +00:00
|
|
|
#define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \
|
|
|
|
(r) == DNS_R_NCACHENXRRSET)
|
2000-01-15 00:45:49 +00:00
|
|
|
#define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \
|
|
|
|
(r) == DNS_R_NXRRSET)
|
2000-08-26 02:21:45 +00:00
|
|
|
#define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \
|
|
|
|
(r) == DNS_R_NCACHENXDOMAIN)
|
2000-09-26 22:28:55 +00:00
|
|
|
#define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \
|
2000-12-20 23:31:11 +00:00
|
|
|
(r) == DNS_R_NXRRSET || \
|
|
|
|
(r) == DNS_R_HINTNXRRSET)
|
1999-11-24 19:23:27 +00:00
|
|
|
|
2000-08-26 02:21:45 +00:00
|
|
|
/*
|
|
|
|
* Error state rankings.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
2001-01-27 02:44:35 +00:00
|
|
|
static const char *errnames[] = {
|
|
|
|
"success",
|
|
|
|
"canceled",
|
|
|
|
"failure",
|
|
|
|
"nxdomain",
|
|
|
|
"nxrrset",
|
|
|
|
"unexpected",
|
|
|
|
"not_found"
|
|
|
|
};
|
|
|
|
|
2000-08-26 02:21:45 +00:00
|
|
|
#define NEWERR(old, new) (ISC_MIN((old), (new)))
|
|
|
|
|
|
|
|
static isc_result_t find_err_map[FIND_ERR_MAX] = {
|
|
|
|
ISC_R_SUCCESS,
|
|
|
|
ISC_R_CANCELED,
|
|
|
|
ISC_R_FAILURE,
|
|
|
|
DNS_R_NXDOMAIN,
|
|
|
|
DNS_R_NXRRSET,
|
|
|
|
ISC_R_UNEXPECTED,
|
|
|
|
ISC_R_NOTFOUND /* not YET found */
|
|
|
|
};
|
1999-11-24 19:23:27 +00:00
|
|
|
|
2001-08-08 22:54:55 +00:00
|
|
|
static void
|
|
|
|
DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
|
|
|
|
|
1999-10-29 22:28:57 +00:00
|
|
|
static void
|
2000-06-01 18:26:56 +00:00
|
|
|
DP(int level, const char *format, ...) {
|
1999-10-29 22:28:57 +00:00
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, format);
|
|
|
|
isc_log_vwrite(dns_lctx,
|
|
|
|
DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
|
2002-09-10 02:01:15 +00:00
|
|
|
level, format, args);
|
1999-10-29 22:28:57 +00:00
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2000-06-07 20:15:48 +00:00
|
|
|
static inline dns_ttl_t
|
|
|
|
ttlclamp(dns_ttl_t ttl) {
|
|
|
|
if (ttl < ADB_CACHE_MINIMUM)
|
|
|
|
ttl = ADB_CACHE_MINIMUM;
|
|
|
|
if (ttl > ADB_CACHE_MAXIMUM)
|
|
|
|
ttl = ADB_CACHE_MAXIMUM;
|
|
|
|
|
|
|
|
return (ttl);
|
|
|
|
}
|
|
|
|
|
1999-10-27 22:24:40 +00:00
|
|
|
/*
|
|
|
|
* Requires the adbname bucket be locked and that no entry buckets be locked.
|
1999-10-29 19:42:06 +00:00
|
|
|
*
|
|
|
|
* This code handles A and AAAA rdatasets only.
|
1999-10-27 22:24:40 +00:00
|
|
|
*/
|
|
|
|
static isc_result_t
|
1999-10-29 19:42:06 +00:00
|
|
|
import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
|
|
|
|
isc_stdtime_t now)
|
1999-10-27 22:24:40 +00:00
|
|
|
{
|
|
|
|
isc_result_t result;
|
1999-10-29 01:26:45 +00:00
|
|
|
dns_adb_t *adb;
|
1999-10-27 22:24:40 +00:00
|
|
|
dns_adbnamehook_t *nh;
|
2003-02-27 02:20:15 +00:00
|
|
|
dns_adbnamehook_t *anh;
|
2000-10-25 04:26:57 +00:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
1999-10-27 22:24:40 +00:00
|
|
|
struct in_addr ina;
|
1999-10-29 19:42:06 +00:00
|
|
|
struct in6_addr in6a;
|
1999-10-27 22:24:40 +00:00
|
|
|
isc_sockaddr_t sockaddr;
|
|
|
|
dns_adbentry_t *foundentry; /* NO CLEAN UP! */
|
|
|
|
int addr_bucket;
|
|
|
|
isc_boolean_t new_addresses_added;
|
1999-10-29 19:42:06 +00:00
|
|
|
dns_rdatatype_t rdtype;
|
1999-10-29 21:48:51 +00:00
|
|
|
unsigned int findoptions;
|
1999-10-27 22:24:40 +00:00
|
|
|
|
1999-10-29 01:26:45 +00:00
|
|
|
INSIST(DNS_ADBNAME_VALID(adbname));
|
|
|
|
adb = adbname->adb;
|
|
|
|
INSIST(DNS_ADB_VALID(adb));
|
|
|
|
|
1999-10-29 19:42:06 +00:00
|
|
|
rdtype = rdataset->type;
|
|
|
|
INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
|
1999-10-29 21:48:51 +00:00
|
|
|
if (rdtype == dns_rdatatype_a)
|
|
|
|
findoptions = DNS_ADBFIND_INET;
|
1999-12-02 23:45:30 +00:00
|
|
|
else
|
1999-10-29 21:48:51 +00:00
|
|
|
findoptions = DNS_ADBFIND_INET6;
|
1999-10-29 19:20:36 +00:00
|
|
|
|
1999-10-27 22:24:40 +00:00
|
|
|
addr_bucket = DNS_ADB_INVALIDBUCKET;
|
|
|
|
new_addresses_added = ISC_FALSE;
|
1999-10-29 21:48:51 +00:00
|
|
|
|
1999-12-01 02:05:16 +00:00
|
|
|
nh = NULL;
|
1999-10-27 22:24:40 +00:00
|
|
|
result = dns_rdataset_first(rdataset);
|
|
|
|
while (result == ISC_R_SUCCESS) {
|
2000-10-31 03:22:05 +00:00
|
|
|
dns_rdata_reset(&rdata);
|
1999-10-27 22:24:40 +00:00
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
1999-10-29 19:42:06 +00:00
|
|
|
if (rdtype == dns_rdatatype_a) {
|
|
|
|
INSIST(rdata.length == 4);
|
|
|
|
memcpy(&ina.s_addr, rdata.data, 4);
|
2000-06-01 00:30:58 +00:00
|
|
|
isc_sockaddr_fromin(&sockaddr, &ina, 0);
|
1999-10-27 22:24:40 +00:00
|
|
|
} else {
|
1999-10-29 19:42:06 +00:00
|
|
|
INSIST(rdata.length == 16);
|
1999-11-01 00:10:10 +00:00
|
|
|
memcpy(in6a.s6_addr, rdata.data, 16);
|
2000-06-01 00:30:58 +00:00
|
|
|
isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
|
1999-10-27 22:24:40 +00:00
|
|
|
}
|
|
|
|
|
1999-12-01 02:05:16 +00:00
|
|
|
INSIST(nh == NULL);
|
|
|
|
nh = new_adbnamehook(adb, NULL);
|
|
|
|
if (nh == NULL) {
|
|
|
|
adbname->partial_result |= findoptions;
|
|
|
|
result = ISC_R_NOMEMORY;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
1999-10-29 19:20:36 +00:00
|
|
|
foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket);
|
|
|
|
if (foundentry == NULL) {
|
|
|
|
dns_adbentry_t *entry;
|
|
|
|
|
|
|
|
entry = new_adbentry(adb);
|
|
|
|
if (entry == NULL) {
|
1999-10-29 21:48:51 +00:00
|
|
|
adbname->partial_result |= findoptions;
|
1999-10-29 19:20:36 +00:00
|
|
|
result = ISC_R_NOMEMORY;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->sockaddr = sockaddr;
|
|
|
|
entry->refcnt = 1;
|
|
|
|
|
|
|
|
nh->entry = entry;
|
|
|
|
|
2000-01-12 03:00:33 +00:00
|
|
|
link_entry(adb, addr_bucket, entry);
|
1999-10-29 19:20:36 +00:00
|
|
|
} else {
|
2003-02-27 02:20:15 +00:00
|
|
|
for (anh = ISC_LIST_HEAD(adbname->v4);
|
|
|
|
anh != NULL;
|
|
|
|
anh = ISC_LIST_NEXT(anh, plink))
|
|
|
|
if (anh->entry == foundentry)
|
|
|
|
break;
|
|
|
|
if (anh == NULL) {
|
|
|
|
foundentry->refcnt++;
|
|
|
|
nh->entry = foundentry;
|
|
|
|
} else
|
|
|
|
free_adbnamehook(adb, &nh);
|
1999-10-29 19:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
new_addresses_added = ISC_TRUE;
|
2003-02-27 02:20:15 +00:00
|
|
|
if (nh != NULL) {
|
|
|
|
if (rdtype == dns_rdatatype_a)
|
|
|
|
ISC_LIST_APPEND(adbname->v4, nh, plink);
|
|
|
|
else
|
|
|
|
ISC_LIST_APPEND(adbname->v6, nh, plink);
|
|
|
|
}
|
1999-10-29 19:20:36 +00:00
|
|
|
nh = NULL;
|
|
|
|
result = dns_rdataset_next(rdataset);
|
|
|
|
}
|
|
|
|
|
|
|
|
fail:
|
|
|
|
if (nh != NULL)
|
|
|
|
free_adbnamehook(adb, &nh);
|
|
|
|
|
|
|
|
if (addr_bucket != DNS_ADB_INVALIDBUCKET)
|
|
|
|
UNLOCK(&adb->entrylocks[addr_bucket]);
|
|
|
|
|
2003-07-18 04:30:01 +00:00
|
|
|
if (rdataset->trust == dns_trust_glue ||
|
|
|
|
rdataset->trust == dns_trust_additional)
|
|
|
|
rdataset->ttl = ADB_CACHE_MINIMUM;
|
|
|
|
else
|
|
|
|
rdataset->ttl = ttlclamp(rdataset->ttl);
|
1999-12-11 02:30:24 +00:00
|
|
|
|
1999-12-01 02:05:16 +00:00
|
|
|
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);
|
|
|
|
}
|
1999-10-29 19:20:36 +00:00
|
|
|
|
1999-12-01 02:05:16 +00:00
|
|
|
if (new_addresses_added) {
|
1999-11-05 02:05:06 +00:00
|
|
|
/*
|
|
|
|
* Lie a little here. This is more or less so code that cares
|
|
|
|
* can find out if any new information was added or not.
|
|
|
|
*/
|
1999-10-29 19:20:36 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
1999-11-05 02:05:06 +00:00
|
|
|
}
|
1999-10-27 22:24:40 +00:00
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
1999-10-26 23:44:36 +00:00
|
|
|
/*
|
|
|
|
* Requires the name's bucket be locked.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
static isc_boolean_t
|
2000-05-08 14:38:29 +00:00
|
|
|
kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
|
1999-10-26 23:44:36 +00:00
|
|
|
dns_adbname_t *name;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_boolean_t result = ISC_FALSE;
|
|
|
|
isc_boolean_t result4, result6;
|
1999-10-29 01:26:45 +00:00
|
|
|
dns_adb_t *adb;
|
1999-10-26 23:44:36 +00:00
|
|
|
|
|
|
|
INSIST(n != NULL);
|
|
|
|
name = *n;
|
|
|
|
*n = NULL;
|
|
|
|
INSIST(DNS_ADBNAME_VALID(name));
|
1999-10-29 01:26:45 +00:00
|
|
|
adb = name->adb;
|
|
|
|
INSIST(DNS_ADB_VALID(adb));
|
1999-10-26 23:44:36 +00:00
|
|
|
|
1999-11-01 20:16:35 +00:00
|
|
|
DP(DEF_LEVEL, "killing name %p", name);
|
1999-10-27 19:36:58 +00:00
|
|
|
|
1999-10-26 23:57:38 +00:00
|
|
|
/*
|
|
|
|
* If we're dead already, just check to see if we should go
|
|
|
|
* away now or not.
|
|
|
|
*/
|
1999-11-02 18:36:54 +00:00
|
|
|
if (NAME_DEAD(name) && !NAME_FETCH(name)) {
|
2002-11-13 00:07:04 +00:00
|
|
|
result = unlink_name(adb, name);
|
1999-10-26 23:57:38 +00:00
|
|
|
free_adbname(adb, &name);
|
2002-11-13 00:07:04 +00:00
|
|
|
if (result)
|
|
|
|
result = dec_adb_irefcnt(adb);
|
|
|
|
return (result);
|
1999-10-26 23:57:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clean up the name's various lists. These two are destructive
|
|
|
|
* in that they will always empty the list.
|
|
|
|
*/
|
1999-10-30 01:58:02 +00:00
|
|
|
clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
|
2002-11-13 00:07:04 +00:00
|
|
|
result4 = clean_namehooks(adb, &name->v4);
|
|
|
|
result6 = clean_namehooks(adb, &name->v6);
|
2000-01-19 01:43:58 +00:00
|
|
|
clean_target(adb, &name->target);
|
2002-11-13 00:07:04 +00:00
|
|
|
result = ISC_TF(result4 || result6);
|
1999-10-26 23:44:36 +00:00
|
|
|
|
1999-10-26 23:57:38 +00:00
|
|
|
/*
|
|
|
|
* If fetches are running, cancel them. If none are running, we can
|
|
|
|
* just kill the name here.
|
|
|
|
*/
|
1999-11-02 18:36:54 +00:00
|
|
|
if (!NAME_FETCH(name)) {
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(result == ISC_FALSE);
|
|
|
|
result = unlink_name(adb, name);
|
1999-10-26 23:44:36 +00:00
|
|
|
free_adbname(adb, &name);
|
2002-11-13 00:07:04 +00:00
|
|
|
if (result)
|
|
|
|
result = dec_adb_irefcnt(adb);
|
1999-10-26 23:44:36 +00:00
|
|
|
} else {
|
1999-10-30 01:58:02 +00:00
|
|
|
name->flags |= NAME_IS_DEAD;
|
2000-01-21 02:50:27 +00:00
|
|
|
cancel_fetches_at_name(name);
|
1999-10-26 23:44:36 +00:00
|
|
|
}
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
1999-10-26 23:44:36 +00:00
|
|
|
}
|
|
|
|
|
1999-10-29 01:26:45 +00:00
|
|
|
/*
|
|
|
|
* Requires the name's bucket be locked and no entry buckets be locked.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
static isc_boolean_t
|
2001-10-25 04:57:46 +00:00
|
|
|
check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now,
|
|
|
|
isc_boolean_t overmem)
|
|
|
|
{
|
1999-10-29 01:26:45 +00:00
|
|
|
dns_adb_t *adb;
|
2001-10-25 04:57:46 +00:00
|
|
|
isc_boolean_t expire;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_boolean_t result4 = ISC_FALSE;
|
|
|
|
isc_boolean_t result6 = ISC_FALSE;
|
1999-10-29 01:26:45 +00:00
|
|
|
|
|
|
|
INSIST(DNS_ADBNAME_VALID(name));
|
|
|
|
adb = name->adb;
|
|
|
|
INSIST(DNS_ADB_VALID(adb));
|
2001-10-25 04:57:46 +00:00
|
|
|
|
|
|
|
if (overmem) {
|
|
|
|
isc_uint32_t val;
|
|
|
|
|
|
|
|
isc_random_get(&val);
|
|
|
|
|
|
|
|
expire = ISC_TF((val % 4) == 0);
|
|
|
|
} else
|
|
|
|
expire = ISC_FALSE;
|
1999-10-29 01:26:45 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to see if we need to remove the v4 addresses
|
|
|
|
*/
|
2001-10-25 04:57:46 +00:00
|
|
|
if (!NAME_FETCH_V4(name) &&
|
|
|
|
(expire || EXPIRE_OK(name->expire_v4, now))) {
|
1999-11-04 08:48:47 +00:00
|
|
|
if (NAME_HAS_V4(name)) {
|
1999-11-04 08:35:45 +00:00
|
|
|
DP(DEF_LEVEL, "expiring v4 for name %p", name);
|
2002-11-13 00:07:04 +00:00
|
|
|
result4 = clean_namehooks(adb, &name->v4);
|
1999-11-04 08:50:12 +00:00
|
|
|
name->partial_result &= ~DNS_ADBFIND_INET;
|
1999-11-04 08:35:45 +00:00
|
|
|
}
|
1999-11-04 06:46:05 +00:00
|
|
|
name->expire_v4 = INT_MAX;
|
2002-11-16 17:20:03 +00:00
|
|
|
name->fetch_err = FIND_ERR_UNEXPECTED;
|
1999-10-29 21:48:51 +00:00
|
|
|
}
|
|
|
|
|
1999-10-29 01:26:45 +00:00
|
|
|
/*
|
|
|
|
* Check to see if we need to remove the v6 addresses
|
|
|
|
*/
|
2001-10-25 04:57:46 +00:00
|
|
|
if (!NAME_FETCH_V6(name) &&
|
|
|
|
(expire || EXPIRE_OK(name->expire_v6, now))) {
|
1999-11-04 08:48:47 +00:00
|
|
|
if (NAME_HAS_V6(name)) {
|
1999-11-04 08:35:45 +00:00
|
|
|
DP(DEF_LEVEL, "expiring v6 for name %p", name);
|
2002-11-13 00:07:04 +00:00
|
|
|
result6 = clean_namehooks(adb, &name->v6);
|
1999-11-04 08:50:12 +00:00
|
|
|
name->partial_result &= ~DNS_ADBFIND_INET6;
|
1999-11-04 08:35:45 +00:00
|
|
|
}
|
1999-11-04 06:46:05 +00:00
|
|
|
name->expire_v6 = INT_MAX;
|
2002-11-16 17:20:03 +00:00
|
|
|
name->fetch6_err = FIND_ERR_UNEXPECTED;
|
1999-10-29 21:48:51 +00:00
|
|
|
}
|
2000-01-19 01:43:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to see if we need to remove the alias target.
|
|
|
|
*/
|
2001-10-25 04:57:46 +00:00
|
|
|
if (expire || EXPIRE_OK(name->expire_target, now)) {
|
2000-01-19 01:43:58 +00:00
|
|
|
clean_target(adb, &name->target);
|
|
|
|
name->expire_target = INT_MAX;
|
|
|
|
}
|
2002-11-13 00:07:04 +00:00
|
|
|
return (ISC_TF(result4 || result6));
|
1999-10-29 01:26:45 +00:00
|
|
|
}
|
|
|
|
|
1999-10-26 23:44:36 +00:00
|
|
|
/*
|
|
|
|
* Requires the name's bucket be locked.
|
|
|
|
*/
|
|
|
|
static inline void
|
2000-05-08 14:38:29 +00:00
|
|
|
link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
|
1999-10-26 23:44:36 +00:00
|
|
|
INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
|
|
|
|
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LIST_PREPEND(adb->names[bucket], name, plink);
|
1999-10-26 23:44:36 +00:00
|
|
|
name->lock_bucket = bucket;
|
|
|
|
adb->name_refcnt[bucket]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Requires the name's bucket be locked.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
static inline isc_boolean_t
|
2000-05-08 14:38:29 +00:00
|
|
|
unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
|
1999-10-26 23:44:36 +00:00
|
|
|
int bucket;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_boolean_t result = ISC_FALSE;
|
1999-10-26 23:44:36 +00:00
|
|
|
|
|
|
|
bucket = name->lock_bucket;
|
|
|
|
INSIST(bucket != DNS_ADB_INVALIDBUCKET);
|
|
|
|
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LIST_UNLINK(adb->names[bucket], name, plink);
|
1999-10-26 23:44:36 +00:00
|
|
|
name->lock_bucket = DNS_ADB_INVALIDBUCKET;
|
|
|
|
INSIST(adb->name_refcnt[bucket] > 0);
|
|
|
|
adb->name_refcnt[bucket]--;
|
2000-01-13 20:42:43 +00:00
|
|
|
if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
|
2002-11-13 00:07:04 +00:00
|
|
|
result = ISC_TRUE;
|
|
|
|
return (result);
|
1999-10-26 23:44:36 +00:00
|
|
|
}
|
1999-10-22 05:19:42 +00:00
|
|
|
|
2000-01-12 03:00:33 +00:00
|
|
|
/*
|
|
|
|
* Requires the entry's bucket be locked.
|
|
|
|
*/
|
|
|
|
static inline void
|
2000-05-08 14:38:29 +00:00
|
|
|
link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
|
2000-01-12 03:00:33 +00:00
|
|
|
ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
|
|
|
|
entry->lock_bucket = bucket;
|
|
|
|
adb->entry_refcnt[bucket]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Requires the entry's bucket be locked.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
static inline isc_boolean_t
|
2000-05-08 14:38:29 +00:00
|
|
|
unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
|
2000-01-12 03:00:33 +00:00
|
|
|
int bucket;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_boolean_t result = ISC_FALSE;
|
2000-01-12 03:00:33 +00:00
|
|
|
|
|
|
|
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]--;
|
2000-01-13 20:42:43 +00:00
|
|
|
if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
|
2002-11-13 00:07:04 +00:00
|
|
|
result = ISC_TRUE;
|
|
|
|
return (result);
|
2000-01-12 03:00:33 +00:00
|
|
|
}
|
|
|
|
|
1999-10-19 01:37:22 +00:00
|
|
|
static inline void
|
2000-05-08 14:38:29 +00:00
|
|
|
violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
|
1999-10-19 01:37:22 +00:00
|
|
|
if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
|
|
|
|
UNLOCK(have);
|
|
|
|
LOCK(want);
|
|
|
|
LOCK(have);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1999-10-22 05:19:42 +00:00
|
|
|
* The ADB _MUST_ be locked before calling. Also, exit conditions must be
|
|
|
|
* checked after calling this function.
|
1999-10-19 01:37:22 +00:00
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
static isc_boolean_t
|
2000-05-08 14:38:29 +00:00
|
|
|
shutdown_names(dns_adb_t *adb) {
|
1999-10-19 01:37:22 +00:00
|
|
|
int bucket;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_boolean_t result = ISC_FALSE;
|
1999-10-19 01:37:22 +00:00
|
|
|
dns_adbname_t *name;
|
1999-10-26 23:44:36 +00:00
|
|
|
dns_adbname_t *next_name;
|
1999-10-19 01:37:22 +00:00
|
|
|
|
2001-10-19 01:29:41 +00:00
|
|
|
for (bucket = 0; bucket < NBUCKETS; bucket++) {
|
1999-10-19 01:37:22 +00:00
|
|
|
LOCK(&adb->namelocks[bucket]);
|
|
|
|
adb->name_sd[bucket] = ISC_TRUE;
|
|
|
|
|
|
|
|
name = ISC_LIST_HEAD(adb->names[bucket]);
|
2000-01-13 20:42:43 +00:00
|
|
|
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.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(result == ISC_FALSE);
|
|
|
|
result = dec_adb_irefcnt(adb);
|
2000-01-13 20:42:43 +00:00
|
|
|
} 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);
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(result == ISC_FALSE);
|
|
|
|
result = kill_name(&name,
|
|
|
|
DNS_EVENT_ADBSHUTDOWN);
|
2000-01-13 20:42:43 +00:00
|
|
|
name = next_name;
|
|
|
|
}
|
1999-10-19 01:37:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
UNLOCK(&adb->namelocks[bucket]);
|
|
|
|
}
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
1999-10-19 01:37:22 +00:00
|
|
|
}
|
|
|
|
|
2000-01-12 03:00:33 +00:00
|
|
|
/*
|
|
|
|
* The ADB _MUST_ be locked before calling. Also, exit conditions must be
|
|
|
|
* checked after calling this function.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
static isc_boolean_t
|
2000-05-08 14:38:29 +00:00
|
|
|
shutdown_entries(dns_adb_t *adb) {
|
2000-01-12 03:00:33 +00:00
|
|
|
int bucket;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_boolean_t result = ISC_FALSE;
|
2000-01-12 03:00:33 +00:00
|
|
|
dns_adbentry_t *entry;
|
|
|
|
dns_adbentry_t *next_entry;
|
|
|
|
|
2001-10-19 01:29:41 +00:00
|
|
|
for (bucket = 0; bucket < NBUCKETS; bucket++) {
|
2000-01-12 03:00:33 +00:00
|
|
|
LOCK(&adb->entrylocks[bucket]);
|
|
|
|
adb->entry_sd[bucket] = ISC_TRUE;
|
|
|
|
|
|
|
|
entry = ISC_LIST_HEAD(adb->entries[bucket]);
|
2000-01-13 20:42:43 +00:00
|
|
|
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.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
result = dec_adb_irefcnt(adb);
|
2000-01-13 20:42:43 +00:00
|
|
|
} 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) {
|
2002-11-13 00:07:04 +00:00
|
|
|
result = unlink_entry(adb, entry);
|
2000-01-13 20:42:43 +00:00
|
|
|
free_adbentry(adb, &entry);
|
2002-11-13 00:07:04 +00:00
|
|
|
if (result)
|
|
|
|
result = dec_adb_irefcnt(adb);
|
2000-01-13 20:42:43 +00:00
|
|
|
}
|
|
|
|
entry = next_entry;
|
2000-01-12 03:00:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-01-12 22:22:20 +00:00
|
|
|
UNLOCK(&adb->entrylocks[bucket]);
|
2000-01-12 03:00:33 +00:00
|
|
|
}
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
2000-01-12 03:00:33 +00:00
|
|
|
}
|
|
|
|
|
1999-10-26 23:44:36 +00:00
|
|
|
/*
|
|
|
|
* Name bucket must be locked
|
|
|
|
*/
|
|
|
|
static void
|
2000-05-08 14:38:29 +00:00
|
|
|
cancel_fetches_at_name(dns_adbname_t *name) {
|
1999-11-02 18:36:54 +00:00
|
|
|
if (NAME_FETCH_A(name))
|
2000-01-21 02:50:27 +00:00
|
|
|
dns_resolver_cancelfetch(name->fetch_a->fetch);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-11-02 18:36:54 +00:00
|
|
|
if (NAME_FETCH_AAAA(name))
|
2000-01-21 02:50:27 +00:00
|
|
|
dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
|
1999-10-26 23:44:36 +00:00
|
|
|
}
|
|
|
|
|
1999-10-20 23:26:06 +00:00
|
|
|
/*
|
|
|
|
* Assumes the name bucket is locked.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
static isc_boolean_t
|
2000-05-08 14:38:29 +00:00
|
|
|
clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
|
1999-10-19 01:37:22 +00:00
|
|
|
dns_adbentry_t *entry;
|
|
|
|
dns_adbnamehook_t *namehook;
|
|
|
|
int addr_bucket;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_boolean_t result = ISC_FALSE;
|
1999-10-19 01:37:22 +00:00
|
|
|
|
|
|
|
addr_bucket = DNS_ADB_INVALIDBUCKET;
|
1999-10-29 01:26:45 +00:00
|
|
|
namehook = ISC_LIST_HEAD(*namehooks);
|
1999-10-19 01:37:22 +00:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
2002-11-13 00:07:04 +00:00
|
|
|
result = dec_entry_refcnt(adb, entry, ISC_FALSE);
|
1999-10-19 01:37:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free the namehook
|
|
|
|
*/
|
|
|
|
namehook->entry = NULL;
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LIST_UNLINK(*namehooks, namehook, plink);
|
1999-10-19 01:37:22 +00:00
|
|
|
free_adbnamehook(adb, &namehook);
|
|
|
|
|
1999-10-29 01:26:45 +00:00
|
|
|
namehook = ISC_LIST_HEAD(*namehooks);
|
1999-10-19 01:37:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (addr_bucket != DNS_ADB_INVALIDBUCKET)
|
|
|
|
UNLOCK(&adb->entrylocks[addr_bucket]);
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
1999-10-19 01:37:22 +00:00
|
|
|
}
|
|
|
|
|
2000-01-19 01:43:58 +00:00
|
|
|
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;
|
2000-10-25 04:26:57 +00:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
2000-01-19 01:43:58 +00:00
|
|
|
dns_fixedname_t fixed1, fixed2;
|
|
|
|
dns_name_t *prefix, *new_target;
|
|
|
|
|
2000-01-21 02:50:27 +00:00
|
|
|
REQUIRE(dns_name_countlabels(target) == 0);
|
|
|
|
|
2000-01-19 01:43:58 +00:00
|
|
|
if (rdataset->type == dns_rdatatype_cname) {
|
2000-10-07 00:09:28 +00:00
|
|
|
dns_rdata_cname_t cname;
|
|
|
|
|
2000-01-19 01:43:58 +00:00
|
|
|
/*
|
|
|
|
* 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);
|
2000-10-07 00:09:28 +00:00
|
|
|
result = dns_rdata_tostruct(&rdata, &cname, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
result = dns_name_dup(&cname.cname, adb->mctx, target);
|
|
|
|
dns_rdata_freestruct(&cname);
|
2000-01-19 01:43:58 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
} else {
|
2000-10-07 00:09:28 +00:00
|
|
|
dns_rdata_dname_t dname;
|
|
|
|
|
2000-01-19 01:43:58 +00:00
|
|
|
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);
|
2000-10-07 00:09:28 +00:00
|
|
|
result = dns_rdata_tostruct(&rdata, &dname, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
2000-01-19 01:43:58 +00:00
|
|
|
/*
|
|
|
|
* 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);
|
2000-10-07 00:09:28 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
dns_rdata_freestruct(&dname);
|
2000-01-19 01:43:58 +00:00
|
|
|
return (result);
|
2000-10-07 00:09:28 +00:00
|
|
|
}
|
|
|
|
result = dns_name_concatenate(prefix, &dname.dname, new_target,
|
2000-01-19 01:43:58 +00:00
|
|
|
NULL);
|
2000-10-07 00:09:28 +00:00
|
|
|
dns_rdata_freestruct(&dname);
|
2000-01-19 01:43:58 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
result = dns_name_dup(new_target, adb->mctx, target);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
1999-10-29 18:00:31 +00:00
|
|
|
/*
|
|
|
|
* Assumes nothing is locked, since this is called by the client.
|
|
|
|
*/
|
|
|
|
static void
|
2000-05-08 14:38:29 +00:00
|
|
|
event_free(isc_event_t *event) {
|
1999-10-29 18:30:48 +00:00
|
|
|
dns_adbfind_t *find;
|
1999-10-29 18:00:31 +00:00
|
|
|
|
|
|
|
INSIST(event != NULL);
|
2000-04-17 19:22:44 +00:00
|
|
|
find = event->ev_destroy_arg;
|
1999-10-29 18:30:48 +00:00
|
|
|
INSIST(DNS_ADBFIND_VALID(find));
|
1999-10-29 18:00:31 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
LOCK(&find->lock);
|
|
|
|
find->flags |= FIND_EVENT_FREED;
|
2000-04-17 19:22:44 +00:00
|
|
|
event->ev_destroy_arg = NULL;
|
1999-10-29 18:30:48 +00:00
|
|
|
UNLOCK(&find->lock);
|
1999-10-29 18:00:31 +00:00
|
|
|
}
|
|
|
|
|
1999-10-20 23:26:06 +00:00
|
|
|
/*
|
|
|
|
* Assumes the name bucket is locked.
|
|
|
|
*/
|
1999-10-19 01:37:22 +00:00
|
|
|
static void
|
1999-10-30 01:58:02 +00:00
|
|
|
clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
|
|
|
|
unsigned int addrs)
|
1999-10-19 01:37:22 +00:00
|
|
|
{
|
|
|
|
isc_event_t *ev;
|
|
|
|
isc_task_t *task;
|
1999-10-29 18:30:48 +00:00
|
|
|
dns_adbfind_t *find;
|
1999-10-30 01:58:02 +00:00
|
|
|
dns_adbfind_t *next_find;
|
1999-11-01 20:16:35 +00:00
|
|
|
isc_boolean_t process;
|
2000-08-26 02:21:45 +00:00
|
|
|
unsigned int wanted, notify;
|
1999-11-01 20:16:35 +00:00
|
|
|
|
|
|
|
DP(ENTER_LEVEL,
|
|
|
|
"ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
|
|
|
|
name, evtype, addrs);
|
1999-10-19 01:37:22 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
find = ISC_LIST_HEAD(name->finds);
|
|
|
|
while (find != NULL) {
|
|
|
|
LOCK(&find->lock);
|
1999-10-30 01:58:02 +00:00
|
|
|
next_find = ISC_LIST_NEXT(find, plink);
|
1999-10-19 01:37:22 +00:00
|
|
|
|
1999-11-01 20:16:35 +00:00
|
|
|
process = ISC_FALSE;
|
|
|
|
wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
|
2000-08-26 02:21:45 +00:00
|
|
|
notify = wanted & addrs;
|
1999-11-01 20:16:35 +00:00
|
|
|
|
|
|
|
switch (evtype) {
|
|
|
|
case DNS_EVENT_ADBMOREADDRESSES:
|
2002-09-10 02:01:15 +00:00
|
|
|
DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES");
|
2000-08-26 02:21:45 +00:00
|
|
|
if ((notify) != 0) {
|
1999-11-01 20:16:35 +00:00
|
|
|
find->flags &= ~addrs;
|
|
|
|
process = ISC_TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DNS_EVENT_ADBNOMOREADDRESSES:
|
2002-09-10 02:01:15 +00:00
|
|
|
DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES");
|
1999-11-01 20:16:35 +00:00
|
|
|
find->flags &= ~addrs;
|
|
|
|
wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
|
2000-08-26 02:21:45 +00:00
|
|
|
if (wanted == 0)
|
1999-11-01 20:16:35 +00:00
|
|
|
process = ISC_TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
find->flags &= ~addrs;
|
|
|
|
process = ISC_TRUE;
|
1999-10-30 01:58:02 +00:00
|
|
|
}
|
1999-10-19 01:37:22 +00:00
|
|
|
|
1999-11-01 20:16:35 +00:00
|
|
|
if (process) {
|
|
|
|
DP(DEF_LEVEL, "cfan: processing find %p", find);
|
|
|
|
/*
|
|
|
|
* Unlink the find from the name, letting the caller
|
|
|
|
* call dns_adb_destroyfind() on it to clean it up
|
|
|
|
* later.
|
|
|
|
*/
|
|
|
|
ISC_LIST_UNLINK(name->finds, find, plink);
|
|
|
|
find->adbname = NULL;
|
|
|
|
find->name_bucket = DNS_ADB_INVALIDBUCKET;
|
1999-10-29 18:00:31 +00:00
|
|
|
|
1999-11-04 08:48:47 +00:00
|
|
|
INSIST(!FIND_EVENTSENT(find));
|
1999-10-29 03:05:24 +00:00
|
|
|
|
1999-11-01 20:16:35 +00:00
|
|
|
ev = &find->event;
|
2000-04-17 19:22:44 +00:00
|
|
|
task = ev->ev_sender;
|
|
|
|
ev->ev_sender = find;
|
2000-08-26 02:21:45 +00:00
|
|
|
find->result_v4 = find_err_map[name->fetch_err];
|
|
|
|
find->result_v6 = find_err_map[name->fetch6_err];
|
2000-04-17 19:22:44 +00:00
|
|
|
ev->ev_type = evtype;
|
|
|
|
ev->ev_destroy = event_free;
|
|
|
|
ev->ev_destroy_arg = find;
|
1999-10-29 03:05:24 +00:00
|
|
|
|
1999-11-01 20:16:35 +00:00
|
|
|
DP(DEF_LEVEL,
|
2001-10-27 00:32:31 +00:00
|
|
|
"sending event %p to task %p for find %p",
|
1999-11-01 20:16:35 +00:00
|
|
|
ev, task, find);
|
|
|
|
|
2000-08-26 02:21:45 +00:00
|
|
|
isc_task_sendanddetach(&task, (isc_event_t **)&ev);
|
1999-11-01 20:16:35 +00:00
|
|
|
} else {
|
|
|
|
DP(DEF_LEVEL, "cfan: skipping find %p", find);
|
|
|
|
}
|
1999-10-27 19:36:58 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
UNLOCK(&find->lock);
|
1999-10-30 01:58:02 +00:00
|
|
|
find = next_find;
|
1999-10-19 01:37:22 +00:00
|
|
|
}
|
1999-11-01 20:16:35 +00:00
|
|
|
|
|
|
|
DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
|
1999-10-19 01:37:22 +00:00
|
|
|
}
|
|
|
|
|
1999-10-26 23:44:36 +00:00
|
|
|
static inline void
|
2000-05-08 14:38:29 +00:00
|
|
|
check_exit(dns_adb_t *adb) {
|
2000-04-17 19:22:44 +00:00
|
|
|
isc_event_t *event;
|
1999-11-22 19:57:58 +00:00
|
|
|
/*
|
|
|
|
* The caller must be holding the adb lock.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
if (adb->shutting_down) {
|
|
|
|
/*
|
|
|
|
* If there aren't any external references either, we're
|
|
|
|
* done. Send the control event to initiate shutdown.
|
|
|
|
*/
|
|
|
|
INSIST(!adb->cevent_sent); /* Sanity check. */
|
|
|
|
event = &adb->cevent;
|
|
|
|
isc_task_send(adb->task, &event);
|
|
|
|
adb->cevent_sent = ISC_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline isc_boolean_t
|
|
|
|
dec_adb_irefcnt(dns_adb_t *adb) {
|
|
|
|
isc_event_t *event;
|
|
|
|
isc_task_t *etask;
|
|
|
|
isc_boolean_t result = ISC_FALSE;
|
1999-11-22 19:57:58 +00:00
|
|
|
|
2001-11-07 22:40:33 +00:00
|
|
|
LOCK(&adb->reflock);
|
2000-01-13 20:42:43 +00:00
|
|
|
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(adb->irefcnt > 0);
|
|
|
|
adb->irefcnt--;
|
|
|
|
|
|
|
|
if (adb->irefcnt == 0) {
|
2000-04-17 19:22:44 +00:00
|
|
|
event = ISC_LIST_HEAD(adb->whenshutdown);
|
|
|
|
while (event != NULL) {
|
|
|
|
ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
|
|
|
|
etask = event->ev_sender;
|
|
|
|
event->ev_sender = adb;
|
1999-11-22 19:57:58 +00:00
|
|
|
isc_task_sendanddetach(&etask, &event);
|
2000-04-17 19:22:44 +00:00
|
|
|
event = ISC_LIST_HEAD(adb->whenshutdown);
|
1999-11-22 19:57:58 +00:00
|
|
|
}
|
|
|
|
}
|
2002-11-13 00:07:04 +00:00
|
|
|
|
|
|
|
if (adb->irefcnt == 0 && adb->erefcnt == 0)
|
|
|
|
result = ISC_TRUE;
|
|
|
|
UNLOCK(&adb->reflock);
|
|
|
|
return (result);
|
1999-10-22 05:19:42 +00:00
|
|
|
}
|
|
|
|
|
1999-10-19 01:37:22 +00:00
|
|
|
static inline void
|
2002-11-13 00:07:04 +00:00
|
|
|
inc_adb_irefcnt(dns_adb_t *adb) {
|
2001-11-07 22:40:33 +00:00
|
|
|
LOCK(&adb->reflock);
|
2002-11-13 00:07:04 +00:00
|
|
|
adb->irefcnt++;
|
2001-11-07 22:40:33 +00:00
|
|
|
UNLOCK(&adb->reflock);
|
1999-10-19 01:37:22 +00:00
|
|
|
}
|
1999-10-05 23:50:43 +00:00
|
|
|
|
|
|
|
static inline void
|
2001-11-07 22:40:33 +00:00
|
|
|
inc_adb_erefcnt(dns_adb_t *adb) {
|
|
|
|
LOCK(&adb->reflock);
|
1999-10-19 01:37:22 +00:00
|
|
|
adb->erefcnt++;
|
2001-11-07 22:40:33 +00:00
|
|
|
UNLOCK(&adb->reflock);
|
1999-10-05 23:50:43 +00:00
|
|
|
}
|
|
|
|
|
1999-10-08 23:12:21 +00:00
|
|
|
static inline void
|
2000-05-08 14:38:29 +00:00
|
|
|
inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
|
1999-10-08 23:12:21 +00:00
|
|
|
int bucket;
|
|
|
|
|
|
|
|
bucket = entry->lock_bucket;
|
|
|
|
|
|
|
|
if (lock)
|
|
|
|
LOCK(&adb->entrylocks[bucket]);
|
|
|
|
|
|
|
|
entry->refcnt++;
|
|
|
|
|
|
|
|
if (lock)
|
|
|
|
UNLOCK(&adb->entrylocks[bucket]);
|
|
|
|
}
|
|
|
|
|
2002-11-13 00:07:04 +00:00
|
|
|
static inline isc_boolean_t
|
2000-05-08 14:38:29 +00:00
|
|
|
dec_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
|
1999-10-08 23:12:21 +00:00
|
|
|
int bucket;
|
|
|
|
isc_boolean_t destroy_entry;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_boolean_t result = ISC_FALSE;
|
1999-10-08 23:12:21 +00:00
|
|
|
|
|
|
|
bucket = entry->lock_bucket;
|
|
|
|
|
|
|
|
if (lock)
|
|
|
|
LOCK(&adb->entrylocks[bucket]);
|
|
|
|
|
|
|
|
INSIST(entry->refcnt > 0);
|
|
|
|
entry->refcnt--;
|
|
|
|
|
|
|
|
destroy_entry = ISC_FALSE;
|
2000-01-21 02:50:27 +00:00
|
|
|
if (entry->refcnt == 0 &&
|
|
|
|
(adb->entry_sd[bucket] || entry->expires == 0)) {
|
1999-10-08 23:12:21 +00:00
|
|
|
destroy_entry = ISC_TRUE;
|
2002-11-13 00:07:04 +00:00
|
|
|
result = unlink_entry(adb, entry);
|
1999-10-08 23:12:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lock)
|
|
|
|
UNLOCK(&adb->entrylocks[bucket]);
|
|
|
|
|
|
|
|
if (!destroy_entry)
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
1999-10-08 23:12:21 +00:00
|
|
|
|
|
|
|
entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
|
|
|
|
|
|
|
|
free_adbentry(adb, &entry);
|
2002-11-13 00:07:04 +00:00
|
|
|
if (result)
|
|
|
|
result =dec_adb_irefcnt(adb);
|
|
|
|
|
|
|
|
return (result);
|
1999-10-08 23:12:21 +00:00
|
|
|
}
|
|
|
|
|
1999-10-05 23:50:43 +00:00
|
|
|
static inline dns_adbname_t *
|
2000-05-08 14:38:29 +00:00
|
|
|
new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
|
1999-09-23 00:43:10 +00:00
|
|
|
dns_adbname_t *name;
|
|
|
|
|
|
|
|
name = isc_mempool_get(adb->nmp);
|
|
|
|
if (name == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
dns_name_init(&name->name, NULL);
|
1999-10-19 20:55:04 +00:00
|
|
|
if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
|
|
|
|
isc_mempool_put(adb->nmp, name);
|
|
|
|
return (NULL);
|
|
|
|
}
|
2000-01-19 01:43:58 +00:00
|
|
|
dns_name_init(&name->target, NULL);
|
1999-10-19 20:55:04 +00:00
|
|
|
name->magic = DNS_ADBNAME_MAGIC;
|
1999-10-27 19:36:58 +00:00
|
|
|
name->adb = adb;
|
1999-10-28 21:50:27 +00:00
|
|
|
name->partial_result = 0;
|
1999-10-30 01:58:02 +00:00
|
|
|
name->flags = 0;
|
1999-10-29 01:26:45 +00:00
|
|
|
name->expire_v4 = INT_MAX;
|
|
|
|
name->expire_v6 = INT_MAX;
|
2000-01-19 01:43:58 +00:00
|
|
|
name->expire_target = INT_MAX;
|
1999-10-30 01:22:16 +00:00
|
|
|
name->chains = 0;
|
1999-10-26 23:44:36 +00:00
|
|
|
name->lock_bucket = DNS_ADB_INVALIDBUCKET;
|
1999-10-29 01:26:45 +00:00
|
|
|
ISC_LIST_INIT(name->v4);
|
|
|
|
ISC_LIST_INIT(name->v6);
|
1999-10-29 21:48:51 +00:00
|
|
|
name->fetch_a = NULL;
|
|
|
|
name->fetch_aaaa = NULL;
|
2000-08-26 02:21:45 +00:00
|
|
|
name->fetch_err = FIND_ERR_UNEXPECTED;
|
|
|
|
name->fetch6_err = FIND_ERR_UNEXPECTED;
|
1999-10-29 18:30:48 +00:00
|
|
|
ISC_LIST_INIT(name->finds);
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LINK_INIT(name, plink);
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
return (name);
|
|
|
|
}
|
|
|
|
|
1999-10-05 23:50:43 +00:00
|
|
|
static inline void
|
2000-05-08 14:38:29 +00:00
|
|
|
free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
|
1999-10-02 01:59:09 +00:00
|
|
|
dns_adbname_t *n;
|
|
|
|
|
|
|
|
INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
|
|
|
|
n = *name;
|
|
|
|
*name = NULL;
|
|
|
|
|
1999-11-04 08:48:47 +00:00
|
|
|
INSIST(!NAME_HAS_V4(n));
|
|
|
|
INSIST(!NAME_HAS_V6(n));
|
1999-11-02 18:36:54 +00:00
|
|
|
INSIST(!NAME_FETCH(n));
|
1999-10-29 18:30:48 +00:00
|
|
|
INSIST(ISC_LIST_EMPTY(n->finds));
|
1999-10-29 01:53:20 +00:00
|
|
|
INSIST(!ISC_LINK_LINKED(n, plink));
|
1999-10-26 23:44:36 +00:00
|
|
|
INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
|
1999-10-27 19:36:58 +00:00
|
|
|
INSIST(n->adb == adb);
|
1999-10-02 01:59:09 +00:00
|
|
|
|
|
|
|
n->magic = 0;
|
|
|
|
dns_name_free(&n->name, adb->mctx);
|
|
|
|
|
|
|
|
isc_mempool_put(adb->nmp, n);
|
|
|
|
}
|
|
|
|
|
1999-10-05 23:50:43 +00:00
|
|
|
static inline dns_adbnamehook_t *
|
2000-05-08 14:38:29 +00:00
|
|
|
new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) {
|
1999-09-23 00:43:10 +00:00
|
|
|
dns_adbnamehook_t *nh;
|
|
|
|
|
|
|
|
nh = isc_mempool_get(adb->nhmp);
|
|
|
|
if (nh == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
nh->magic = DNS_ADBNAMEHOOK_MAGIC;
|
|
|
|
nh->entry = entry;
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LINK_INIT(nh, plink);
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
return (nh);
|
|
|
|
}
|
|
|
|
|
1999-10-05 23:50:43 +00:00
|
|
|
static inline void
|
2000-05-08 14:38:29 +00:00
|
|
|
free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) {
|
1999-10-02 01:59:09 +00:00
|
|
|
dns_adbnamehook_t *nh;
|
|
|
|
|
|
|
|
INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
|
|
|
|
nh = *namehook;
|
|
|
|
*namehook = NULL;
|
|
|
|
|
|
|
|
INSIST(nh->entry == NULL);
|
1999-10-29 01:53:20 +00:00
|
|
|
INSIST(!ISC_LINK_LINKED(nh, plink));
|
1999-10-02 01:59:09 +00:00
|
|
|
|
|
|
|
nh->magic = 0;
|
|
|
|
isc_mempool_put(adb->nhmp, nh);
|
|
|
|
}
|
|
|
|
|
1999-10-05 23:50:43 +00:00
|
|
|
static inline dns_adbzoneinfo_t *
|
2000-05-08 14:38:29 +00:00
|
|
|
new_adbzoneinfo(dns_adb_t *adb, dns_name_t *zone) {
|
1999-09-23 00:43:10 +00:00
|
|
|
dns_adbzoneinfo_t *zi;
|
|
|
|
|
|
|
|
zi = isc_mempool_get(adb->zimp);
|
|
|
|
if (zi == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
1999-10-08 23:12:21 +00:00
|
|
|
dns_name_init(&zi->zone, NULL);
|
1999-10-19 21:10:29 +00:00
|
|
|
if (dns_name_dup(zone, adb->mctx, &zi->zone) != ISC_R_SUCCESS) {
|
|
|
|
isc_mempool_put(adb->zimp, zi);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
zi->magic = DNS_ADBZONEINFO_MAGIC;
|
1999-09-23 00:43:10 +00:00
|
|
|
zi->lame_timer = 0;
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LINK_INIT(zi, plink);
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
return (zi);
|
|
|
|
}
|
|
|
|
|
1999-10-08 23:12:21 +00:00
|
|
|
static inline void
|
2000-05-08 14:38:29 +00:00
|
|
|
free_adbzoneinfo(dns_adb_t *adb, dns_adbzoneinfo_t **zoneinfo) {
|
1999-10-08 23:12:21 +00:00
|
|
|
dns_adbzoneinfo_t *zi;
|
|
|
|
|
1999-10-14 00:50:00 +00:00
|
|
|
INSIST(zoneinfo != NULL && DNS_ADBZONEINFO_VALID(*zoneinfo));
|
1999-10-08 23:12:21 +00:00
|
|
|
zi = *zoneinfo;
|
|
|
|
*zoneinfo = NULL;
|
|
|
|
|
1999-10-29 01:53:20 +00:00
|
|
|
INSIST(!ISC_LINK_LINKED(zi, plink));
|
1999-10-08 23:12:21 +00:00
|
|
|
|
|
|
|
dns_name_free(&zi->zone, adb->mctx);
|
|
|
|
|
|
|
|
zi->magic = 0;
|
|
|
|
|
|
|
|
isc_mempool_put(adb->zimp, zi);
|
|
|
|
}
|
|
|
|
|
1999-10-05 23:50:43 +00:00
|
|
|
static inline dns_adbentry_t *
|
2000-05-08 14:38:29 +00:00
|
|
|
new_adbentry(dns_adb_t *adb) {
|
1999-09-23 00:43:10 +00:00
|
|
|
dns_adbentry_t *e;
|
1999-10-20 23:26:06 +00:00
|
|
|
isc_uint32_t r;
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
e = isc_mempool_get(adb->emp);
|
|
|
|
if (e == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
e->magic = DNS_ADBENTRY_MAGIC;
|
1999-10-02 01:59:09 +00:00
|
|
|
e->lock_bucket = DNS_ADB_INVALIDBUCKET;
|
1999-10-08 23:12:21 +00:00
|
|
|
e->refcnt = 0;
|
1999-09-23 00:43:10 +00:00
|
|
|
e->flags = 0;
|
2000-09-06 02:40:00 +00:00
|
|
|
isc_random_get(&r);
|
1999-10-20 23:26:06 +00:00
|
|
|
e->srtt = (r & 0x1f) + 1;
|
2000-01-12 03:00:33 +00:00
|
|
|
e->expires = 0;
|
1999-09-23 00:43:10 +00:00
|
|
|
ISC_LIST_INIT(e->zoneinfo);
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LINK_INIT(e, plink);
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
return (e);
|
|
|
|
}
|
|
|
|
|
1999-10-05 23:50:43 +00:00
|
|
|
static inline void
|
2000-05-08 14:38:29 +00:00
|
|
|
free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
|
1999-10-02 01:59:09 +00:00
|
|
|
dns_adbentry_t *e;
|
1999-10-19 21:42:56 +00:00
|
|
|
dns_adbzoneinfo_t *zi;
|
1999-10-14 00:50:00 +00:00
|
|
|
|
1999-10-02 01:59:09 +00:00
|
|
|
INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
|
|
|
|
e = *entry;
|
|
|
|
*entry = NULL;
|
|
|
|
|
|
|
|
INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
|
1999-10-08 23:12:21 +00:00
|
|
|
INSIST(e->refcnt == 0);
|
1999-10-29 01:53:20 +00:00
|
|
|
INSIST(!ISC_LINK_LINKED(e, plink));
|
1999-10-02 01:59:09 +00:00
|
|
|
|
|
|
|
e->magic = 0;
|
1999-10-19 21:42:56 +00:00
|
|
|
|
|
|
|
zi = ISC_LIST_HEAD(e->zoneinfo);
|
|
|
|
while (zi != NULL) {
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LIST_UNLINK(e->zoneinfo, zi, plink);
|
1999-10-19 21:42:56 +00:00
|
|
|
free_adbzoneinfo(adb, &zi);
|
|
|
|
zi = ISC_LIST_HEAD(e->zoneinfo);
|
|
|
|
}
|
|
|
|
|
1999-10-02 01:59:09 +00:00
|
|
|
isc_mempool_put(adb->emp, e);
|
|
|
|
}
|
|
|
|
|
1999-10-29 18:07:32 +00:00
|
|
|
static inline dns_adbfind_t *
|
2000-05-08 14:38:29 +00:00
|
|
|
new_adbfind(dns_adb_t *adb) {
|
1999-10-29 18:07:32 +00:00
|
|
|
dns_adbfind_t *h;
|
1999-09-25 01:44:41 +00:00
|
|
|
isc_result_t result;
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
h = isc_mempool_get(adb->ahmp);
|
|
|
|
if (h == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
1999-09-25 01:44:41 +00:00
|
|
|
/*
|
2000-05-08 14:38:29 +00:00
|
|
|
* Public members.
|
1999-09-25 01:44:41 +00:00
|
|
|
*/
|
|
|
|
h->magic = 0;
|
1999-10-22 05:19:42 +00:00
|
|
|
h->adb = adb;
|
1999-10-28 21:50:27 +00:00
|
|
|
h->partial_result = 0;
|
1999-10-29 01:26:45 +00:00
|
|
|
h->options = 0;
|
1999-11-01 20:16:35 +00:00
|
|
|
h->flags = 0;
|
2000-08-26 02:21:45 +00:00
|
|
|
h->result_v4 = ISC_R_UNEXPECTED;
|
|
|
|
h->result_v6 = ISC_R_UNEXPECTED;
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LINK_INIT(h, publink);
|
1999-10-28 20:09:51 +00:00
|
|
|
ISC_LINK_INIT(h, plink);
|
1999-09-25 01:44:41 +00:00
|
|
|
ISC_LIST_INIT(h->list);
|
1999-10-14 00:50:00 +00:00
|
|
|
h->adbname = NULL;
|
1999-10-29 18:00:31 +00:00
|
|
|
h->name_bucket = DNS_ADB_INVALIDBUCKET;
|
1999-09-25 01:44:41 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* private members
|
|
|
|
*/
|
|
|
|
result = isc_mutex_init(&h->lock);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
1999-10-29 18:30:48 +00:00
|
|
|
"isc_mutex_init failed in new_adbfind()");
|
1999-09-25 01:44:41 +00:00
|
|
|
isc_mempool_put(adb->ahmp, h);
|
|
|
|
return (NULL);
|
|
|
|
}
|
1999-09-23 00:43:10 +00:00
|
|
|
|
2001-11-12 19:05:39 +00:00
|
|
|
ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
|
1999-09-23 00:43:10 +00:00
|
|
|
NULL, NULL, h);
|
|
|
|
|
2002-11-13 00:07:04 +00:00
|
|
|
inc_adb_irefcnt(adb);
|
1999-10-29 18:07:32 +00:00
|
|
|
h->magic = DNS_ADBFIND_MAGIC;
|
1999-09-23 00:43:10 +00:00
|
|
|
return (h);
|
|
|
|
}
|
|
|
|
|
1999-10-25 21:02:54 +00:00
|
|
|
static inline dns_adbfetch_t *
|
2000-05-08 14:38:29 +00:00
|
|
|
new_adbfetch(dns_adb_t *adb) {
|
1999-10-25 21:02:54 +00:00
|
|
|
dns_adbfetch_t *f;
|
|
|
|
|
|
|
|
f = isc_mempool_get(adb->afmp);
|
|
|
|
if (f == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
f->magic = 0;
|
|
|
|
f->namehook = NULL;
|
|
|
|
f->entry = NULL;
|
|
|
|
f->fetch = NULL;
|
|
|
|
|
|
|
|
f->namehook = new_adbnamehook(adb, NULL);
|
|
|
|
if (f->namehook == NULL)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
f->entry = new_adbentry(adb);
|
|
|
|
if (f->entry == NULL)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
dns_rdataset_init(&f->rdataset);
|
|
|
|
|
|
|
|
f->magic = DNS_ADBFETCH_MAGIC;
|
|
|
|
|
|
|
|
return (f);
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (f->namehook != NULL)
|
|
|
|
free_adbnamehook(adb, &f->namehook);
|
|
|
|
if (f->entry != NULL)
|
|
|
|
free_adbentry(adb, &f->entry);
|
|
|
|
isc_mempool_put(adb->afmp, f);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2000-05-08 14:38:29 +00:00
|
|
|
free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) {
|
1999-10-25 21:02:54 +00:00
|
|
|
dns_adbfetch_t *f;
|
|
|
|
|
|
|
|
INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
|
|
|
|
f = *fetch;
|
|
|
|
*fetch = NULL;
|
|
|
|
|
|
|
|
f->magic = 0;
|
|
|
|
|
|
|
|
if (f->namehook != NULL)
|
|
|
|
free_adbnamehook(adb, &f->namehook);
|
|
|
|
if (f->entry != NULL)
|
|
|
|
free_adbentry(adb, &f->entry);
|
|
|
|
|
1999-10-28 00:37:31 +00:00
|
|
|
if (dns_rdataset_isassociated(&f->rdataset))
|
|
|
|
dns_rdataset_disassociate(&f->rdataset);
|
1999-10-25 21:02:54 +00:00
|
|
|
|
|
|
|
isc_mempool_put(adb->afmp, f);
|
|
|
|
}
|
|
|
|
|
2002-11-13 00:07:04 +00:00
|
|
|
static inline isc_boolean_t
|
2000-05-08 14:38:29 +00:00
|
|
|
free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
|
1999-10-29 18:30:48 +00:00
|
|
|
dns_adbfind_t *find;
|
1999-10-08 23:12:21 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
|
|
|
|
find = *findp;
|
|
|
|
*findp = NULL;
|
1999-10-08 23:12:21 +00:00
|
|
|
|
1999-11-04 08:48:47 +00:00
|
|
|
INSIST(!FIND_HAS_ADDRS(find));
|
1999-10-29 18:30:48 +00:00
|
|
|
INSIST(!ISC_LINK_LINKED(find, publink));
|
|
|
|
INSIST(!ISC_LINK_LINKED(find, plink));
|
|
|
|
INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
|
|
|
|
INSIST(find->adbname == NULL);
|
1999-10-14 00:50:00 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
find->magic = 0;
|
1999-10-08 23:12:21 +00:00
|
|
|
|
2000-08-26 01:37:00 +00:00
|
|
|
DESTROYLOCK(&find->lock);
|
1999-10-29 18:30:48 +00:00
|
|
|
isc_mempool_put(adb->ahmp, find);
|
2002-11-13 00:07:04 +00:00
|
|
|
return (dec_adb_irefcnt(adb));
|
1999-10-08 23:12:21 +00:00
|
|
|
}
|
|
|
|
|
1999-09-23 00:43:10 +00:00
|
|
|
/*
|
|
|
|
* Copy bits from the entry into the newly allocated addrinfo. The entry
|
|
|
|
* must be locked, and the reference count must be bumped up by one
|
|
|
|
* if this function returns a valid pointer.
|
1999-09-22 00:26:20 +00:00
|
|
|
*/
|
1999-10-05 23:50:43 +00:00
|
|
|
static inline dns_adbaddrinfo_t *
|
2000-06-01 00:30:58 +00:00
|
|
|
new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
|
1999-09-23 00:43:10 +00:00
|
|
|
dns_adbaddrinfo_t *ai;
|
|
|
|
|
|
|
|
ai = isc_mempool_get(adb->aimp);
|
|
|
|
if (ai == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
ai->magic = DNS_ADBADDRINFO_MAGIC;
|
2000-06-01 00:30:58 +00:00
|
|
|
ai->sockaddr = entry->sockaddr;
|
|
|
|
isc_sockaddr_setport(&ai->sockaddr, port);
|
1999-09-23 00:43:10 +00:00
|
|
|
ai->srtt = entry->srtt;
|
|
|
|
ai->flags = entry->flags;
|
|
|
|
ai->entry = entry;
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LINK_INIT(ai, publink);
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
return (ai);
|
|
|
|
}
|
|
|
|
|
1999-10-14 00:50:00 +00:00
|
|
|
static inline void
|
2000-05-08 14:38:29 +00:00
|
|
|
free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
|
1999-10-14 00:50:00 +00:00
|
|
|
dns_adbaddrinfo_t *ai;
|
|
|
|
|
|
|
|
INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
|
|
|
|
ai = *ainfo;
|
|
|
|
*ainfo = NULL;
|
|
|
|
|
|
|
|
INSIST(ai->entry == NULL);
|
1999-10-29 01:53:20 +00:00
|
|
|
INSIST(!ISC_LINK_LINKED(ai, publink));
|
1999-10-14 00:50:00 +00:00
|
|
|
|
|
|
|
ai->magic = 0;
|
|
|
|
|
|
|
|
isc_mempool_put(adb->aimp, ai);
|
|
|
|
}
|
|
|
|
|
1999-09-23 00:43:10 +00:00
|
|
|
/*
|
|
|
|
* Search for the name. NOTE: The bucket is kept locked on both
|
|
|
|
* success and failure, so it must always be unlocked by the caller!
|
1999-10-02 01:59:09 +00:00
|
|
|
*
|
|
|
|
* On the first call to this function, *bucketp must be set to
|
|
|
|
* DNS_ADB_INVALIDBUCKET.
|
1999-09-23 00:43:10 +00:00
|
|
|
*/
|
1999-10-05 23:50:43 +00:00
|
|
|
static inline dns_adbname_t *
|
2000-02-02 23:24:04 +00:00
|
|
|
find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
|
|
|
|
unsigned int options, int *bucketp)
|
1999-09-23 00:43:10 +00:00
|
|
|
{
|
|
|
|
dns_adbname_t *adbname;
|
1999-10-05 23:50:43 +00:00
|
|
|
int bucket;
|
1999-09-23 00:43:10 +00:00
|
|
|
|
2003-07-25 02:22:26 +00:00
|
|
|
bucket = dns_fullname_hash(name, ISC_FALSE) % NBUCKETS;
|
1999-09-23 00:43:10 +00:00
|
|
|
|
1999-10-05 23:50:43 +00:00
|
|
|
if (*bucketp == DNS_ADB_INVALIDBUCKET) {
|
|
|
|
LOCK(&adb->namelocks[bucket]);
|
|
|
|
*bucketp = bucket;
|
|
|
|
} else if (*bucketp != bucket) {
|
|
|
|
UNLOCK(&adb->namelocks[*bucketp]);
|
|
|
|
LOCK(&adb->namelocks[bucket]);
|
|
|
|
*bucketp = bucket;
|
|
|
|
}
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
adbname = ISC_LIST_HEAD(adb->names[bucket]);
|
|
|
|
while (adbname != NULL) {
|
1999-10-30 01:58:02 +00:00
|
|
|
if (!NAME_DEAD(adbname)) {
|
2000-02-02 23:24:04 +00:00
|
|
|
if (dns_name_equal(name, &adbname->name)
|
2001-05-02 17:29:17 +00:00
|
|
|
&& GLUEHINT_OK(adbname, options)
|
2003-02-26 22:54:29 +00:00
|
|
|
&& STARTATZONE_MATCHES(adbname, options))
|
1999-10-26 23:44:36 +00:00
|
|
|
return (adbname);
|
|
|
|
}
|
1999-10-29 01:53:20 +00:00
|
|
|
adbname = ISC_LIST_NEXT(adbname, plink);
|
1999-09-23 00:43:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Search for the address. NOTE: The bucket is kept locked on both
|
1999-10-02 01:59:09 +00:00
|
|
|
* success and failure, so it must always be unlocked by the caller.
|
|
|
|
*
|
|
|
|
* On the first call to this function, *bucketp must be set to
|
|
|
|
* DNS_ADB_INVALIDBUCKET. This will cause a lock to occur. On
|
|
|
|
* later calls (within the same "lock path") it can be left alone, so
|
|
|
|
* if this function is called multiple times locking is only done if
|
|
|
|
* the bucket changes.
|
1999-09-23 00:43:10 +00:00
|
|
|
*/
|
1999-10-05 23:50:43 +00:00
|
|
|
static inline dns_adbentry_t *
|
2000-05-08 14:38:29 +00:00
|
|
|
find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp) {
|
1999-09-23 00:43:10 +00:00
|
|
|
dns_adbentry_t *entry;
|
1999-10-02 01:59:09 +00:00
|
|
|
int bucket;
|
1999-09-23 00:43:10 +00:00
|
|
|
|
1999-11-05 02:05:06 +00:00
|
|
|
bucket = isc_sockaddr_hash(addr, ISC_TRUE) % NBUCKETS;
|
1999-09-23 00:43:10 +00:00
|
|
|
|
1999-10-02 01:59:09 +00:00
|
|
|
if (*bucketp == DNS_ADB_INVALIDBUCKET) {
|
|
|
|
LOCK(&adb->entrylocks[bucket]);
|
|
|
|
*bucketp = bucket;
|
|
|
|
} else if (*bucketp != bucket) {
|
|
|
|
UNLOCK(&adb->entrylocks[*bucketp]);
|
|
|
|
LOCK(&adb->entrylocks[bucket]);
|
|
|
|
*bucketp = bucket;
|
|
|
|
}
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
entry = ISC_LIST_HEAD(adb->entries[bucket]);
|
|
|
|
while (entry != NULL) {
|
|
|
|
if (isc_sockaddr_equal(addr, &entry->sockaddr))
|
|
|
|
return (entry);
|
1999-10-29 01:53:20 +00:00
|
|
|
entry = ISC_LIST_NEXT(entry, plink);
|
1999-09-23 00:43:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
1999-09-22 00:26:20 +00:00
|
|
|
|
1999-10-19 20:55:04 +00:00
|
|
|
/*
|
|
|
|
* Entry bucket MUST be locked!
|
|
|
|
*/
|
|
|
|
static isc_boolean_t
|
1999-10-20 23:26:06 +00:00
|
|
|
entry_is_bad_for_zone(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *zone,
|
|
|
|
isc_stdtime_t now)
|
1999-10-19 20:55:04 +00:00
|
|
|
{
|
|
|
|
dns_adbzoneinfo_t *zi, *next_zi;
|
|
|
|
isc_boolean_t is_bad;
|
|
|
|
|
|
|
|
is_bad = ISC_FALSE;
|
|
|
|
|
|
|
|
zi = ISC_LIST_HEAD(entry->zoneinfo);
|
|
|
|
if (zi == NULL)
|
|
|
|
return (ISC_FALSE);
|
|
|
|
while (zi != NULL) {
|
1999-10-29 01:53:20 +00:00
|
|
|
next_zi = ISC_LIST_NEXT(zi, plink);
|
1999-10-19 20:55:04 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Has the entry expired?
|
|
|
|
*/
|
|
|
|
if (zi->lame_timer < now) {
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LIST_UNLINK(entry->zoneinfo, zi, plink);
|
1999-10-19 20:55:04 +00:00
|
|
|
free_adbzoneinfo(adb, &zi);
|
|
|
|
}
|
|
|
|
|
1999-10-20 23:26:06 +00:00
|
|
|
/*
|
|
|
|
* Order tests from least to most expensive.
|
|
|
|
*/
|
|
|
|
if (zi != NULL && !is_bad) {
|
1999-10-19 20:55:04 +00:00
|
|
|
if (dns_name_equal(zone, &zi->zone))
|
|
|
|
is_bad = ISC_TRUE;
|
1999-10-20 23:26:06 +00:00
|
|
|
}
|
1999-10-19 20:55:04 +00:00
|
|
|
|
|
|
|
zi = next_zi;
|
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-10-19 20:55:04 +00:00
|
|
|
return (is_bad);
|
|
|
|
}
|
|
|
|
|
1999-10-08 23:12:21 +00:00
|
|
|
static void
|
1999-11-02 00:29:45 +00:00
|
|
|
copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *zone,
|
|
|
|
dns_adbname_t *name, isc_stdtime_t now)
|
1999-10-08 23:12:21 +00:00
|
|
|
{
|
|
|
|
dns_adbnamehook_t *namehook;
|
|
|
|
dns_adbaddrinfo_t *addrinfo;
|
2000-02-16 00:16:36 +00:00
|
|
|
dns_adbentry_t *entry;
|
1999-10-19 20:55:04 +00:00
|
|
|
int bucket;
|
1999-10-08 23:12:21 +00:00
|
|
|
|
1999-10-19 20:55:04 +00:00
|
|
|
bucket = DNS_ADB_INVALIDBUCKET;
|
1999-10-08 23:12:21 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
if (find->options & DNS_ADBFIND_INET) {
|
1999-10-29 01:26:45 +00:00
|
|
|
namehook = ISC_LIST_HEAD(name->v4);
|
|
|
|
while (namehook != NULL) {
|
2000-02-16 00:16:36 +00:00
|
|
|
entry = namehook->entry;
|
|
|
|
bucket = entry->lock_bucket;
|
1999-10-29 01:26:45 +00:00
|
|
|
LOCK(&adb->entrylocks[bucket]);
|
2000-02-16 00:16:36 +00:00
|
|
|
|
2000-02-02 23:27:39 +00:00
|
|
|
if (!FIND_RETURNLAME(find)
|
2000-02-16 00:16:36 +00:00
|
|
|
&& entry_is_bad_for_zone(adb, entry, zone, now)) {
|
2000-02-02 23:24:04 +00:00
|
|
|
find->options |= DNS_ADBFIND_LAMEPRUNED;
|
1999-10-29 01:26:45 +00:00
|
|
|
goto nextv4;
|
2000-02-02 23:24:04 +00:00
|
|
|
}
|
2000-06-01 00:30:58 +00:00
|
|
|
addrinfo = new_adbaddrinfo(adb, entry, find->port);
|
1999-10-29 01:26:45 +00:00
|
|
|
if (addrinfo == NULL) {
|
1999-10-29 18:30:48 +00:00
|
|
|
find->partial_result |= DNS_ADBFIND_INET;
|
1999-10-29 01:26:45 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
/*
|
1999-10-29 18:30:48 +00:00
|
|
|
* Found a valid entry. Add it to the find's list.
|
1999-10-29 01:26:45 +00:00
|
|
|
*/
|
2000-02-16 00:16:36 +00:00
|
|
|
inc_entry_refcnt(adb, entry, ISC_FALSE);
|
1999-10-29 18:30:48 +00:00
|
|
|
ISC_LIST_APPEND(find->list, addrinfo, publink);
|
1999-10-29 01:26:45 +00:00
|
|
|
addrinfo = NULL;
|
|
|
|
nextv4:
|
|
|
|
UNLOCK(&adb->entrylocks[bucket]);
|
|
|
|
bucket = DNS_ADB_INVALIDBUCKET;
|
1999-10-29 01:53:20 +00:00
|
|
|
namehook = ISC_LIST_NEXT(namehook, plink);
|
1999-10-29 01:26:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-10-29 21:48:51 +00:00
|
|
|
if (find->options & DNS_ADBFIND_INET6) {
|
1999-10-29 01:26:45 +00:00
|
|
|
namehook = ISC_LIST_HEAD(name->v6);
|
|
|
|
while (namehook != NULL) {
|
2000-02-16 00:16:36 +00:00
|
|
|
entry = namehook->entry;
|
|
|
|
bucket = entry->lock_bucket;
|
1999-10-29 01:26:45 +00:00
|
|
|
LOCK(&adb->entrylocks[bucket]);
|
2000-02-16 00:16:36 +00:00
|
|
|
|
|
|
|
if (entry_is_bad_for_zone(adb, entry, zone, now))
|
1999-10-29 01:26:45 +00:00
|
|
|
goto nextv6;
|
2000-06-01 00:30:58 +00:00
|
|
|
addrinfo = new_adbaddrinfo(adb, entry, find->port);
|
1999-10-29 01:26:45 +00:00
|
|
|
if (addrinfo == NULL) {
|
1999-10-29 21:48:51 +00:00
|
|
|
find->partial_result |= DNS_ADBFIND_INET6;
|
1999-10-29 01:26:45 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
/*
|
1999-10-29 18:30:48 +00:00
|
|
|
* Found a valid entry. Add it to the find's list.
|
1999-10-29 01:26:45 +00:00
|
|
|
*/
|
2000-02-16 00:16:36 +00:00
|
|
|
inc_entry_refcnt(adb, entry, ISC_FALSE);
|
1999-10-29 18:30:48 +00:00
|
|
|
ISC_LIST_APPEND(find->list, addrinfo, publink);
|
1999-10-29 01:26:45 +00:00
|
|
|
addrinfo = NULL;
|
|
|
|
nextv6:
|
|
|
|
UNLOCK(&adb->entrylocks[bucket]);
|
|
|
|
bucket = DNS_ADB_INVALIDBUCKET;
|
1999-10-29 01:53:20 +00:00
|
|
|
namehook = ISC_LIST_NEXT(namehook, plink);
|
1999-10-08 23:12:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-10-19 20:55:04 +00:00
|
|
|
out:
|
|
|
|
if (bucket != DNS_ADB_INVALIDBUCKET)
|
|
|
|
UNLOCK(&adb->entrylocks[bucket]);
|
1999-10-08 23:12:21 +00:00
|
|
|
}
|
|
|
|
|
1999-10-25 23:07:14 +00:00
|
|
|
static void
|
2000-05-08 14:38:29 +00:00
|
|
|
shutdown_task(isc_task_t *task, isc_event_t *ev) {
|
1999-10-25 23:07:14 +00:00
|
|
|
dns_adb_t *adb;
|
1999-10-25 23:18:19 +00:00
|
|
|
|
2000-05-08 14:38:29 +00:00
|
|
|
UNUSED(task);
|
1999-10-25 23:07:14 +00:00
|
|
|
|
2000-04-17 19:22:44 +00:00
|
|
|
adb = ev->ev_arg;
|
1999-10-25 23:07:14 +00:00
|
|
|
INSIST(DNS_ADB_VALID(adb));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Kill the timer, and then the ADB itself. Note that this implies
|
|
|
|
* that this task was the one scheduled to get timer events. If
|
|
|
|
* this is not true (and it is unfortunate there is no way to INSIST()
|
1999-11-22 19:57:58 +00:00
|
|
|
* this) badness will occur.
|
1999-10-25 23:07:14 +00:00
|
|
|
*/
|
|
|
|
LOCK(&adb->lock);
|
|
|
|
isc_timer_detach(&adb->timer);
|
|
|
|
UNLOCK(&adb->lock);
|
|
|
|
isc_event_free(&ev);
|
1999-11-22 19:57:58 +00:00
|
|
|
destroy(adb);
|
1999-10-25 23:07:14 +00:00
|
|
|
}
|
|
|
|
|
1999-10-25 22:53:15 +00:00
|
|
|
/*
|
2001-11-05 20:02:41 +00:00
|
|
|
* Name bucket must be locked; adb may be locked; no other locks held.
|
1999-10-25 22:53:15 +00:00
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
static isc_boolean_t
|
2000-05-08 14:38:29 +00:00
|
|
|
check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
|
1999-10-29 23:53:12 +00:00
|
|
|
dns_adbname_t *name;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_result_t result = ISC_FALSE;
|
1999-10-29 23:53:12 +00:00
|
|
|
|
|
|
|
INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
|
|
|
|
name = *namep;
|
|
|
|
|
1999-11-04 08:48:47 +00:00
|
|
|
if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
1999-11-02 18:36:54 +00:00
|
|
|
if (NAME_FETCH(name))
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
1999-11-04 06:46:05 +00:00
|
|
|
if (!EXPIRE_OK(name->expire_v4, now))
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
1999-11-04 06:46:05 +00:00
|
|
|
if (!EXPIRE_OK(name->expire_v6, now))
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
2000-01-19 01:43:58 +00:00
|
|
|
if (!EXPIRE_OK(name->expire_target, now))
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
1999-10-29 23:53:12 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The name is empty. Delete it.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
|
2000-02-18 03:53:00 +00:00
|
|
|
*namep = NULL;
|
2000-01-13 20:42:43 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Our caller, or one of its callers, will be calling check_exit() at
|
|
|
|
* some point, so we don't need to do it here.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
1999-10-29 23:53:12 +00:00
|
|
|
}
|
|
|
|
|
2000-01-12 03:00:33 +00:00
|
|
|
/*
|
2001-11-05 20:02:41 +00:00
|
|
|
* Entry bucket must be locked; adb may be locked; no other locks held.
|
2000-01-12 03:00:33 +00:00
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
static isc_boolean_t
|
2000-01-12 03:00:33 +00:00
|
|
|
check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
|
|
|
|
{
|
|
|
|
dns_adbentry_t *entry;
|
2001-10-25 04:57:46 +00:00
|
|
|
isc_boolean_t expire;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_boolean_t result = ISC_FALSE;
|
2000-01-12 03:00:33 +00:00
|
|
|
|
|
|
|
INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
|
|
|
|
entry = *entryp;
|
|
|
|
|
|
|
|
if (entry->refcnt != 0)
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2001-10-25 04:57:46 +00:00
|
|
|
if (adb->overmem) {
|
|
|
|
isc_uint32_t val;
|
|
|
|
|
|
|
|
isc_random_get(&val);
|
|
|
|
|
|
|
|
expire = ISC_TF((val % 4) == 0);
|
|
|
|
} else
|
|
|
|
expire = ISC_FALSE;
|
|
|
|
|
2001-10-25 17:47:16 +00:00
|
|
|
if (entry->expires == 0 || (! expire && entry->expires > now))
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
2000-01-12 03:00:33 +00:00
|
|
|
/*
|
|
|
|
* The entry is not in use. Delete it.
|
|
|
|
*/
|
|
|
|
DP(DEF_LEVEL, "killing entry %p", entry);
|
|
|
|
INSIST(ISC_LINK_LINKED(entry, plink));
|
2002-11-13 00:07:04 +00:00
|
|
|
result = unlink_entry(adb, entry);
|
2000-01-12 03:00:33 +00:00
|
|
|
free_adbentry(adb, &entry);
|
2002-11-13 00:07:04 +00:00
|
|
|
if (result)
|
|
|
|
dec_adb_irefcnt(adb);
|
2000-02-18 03:53:00 +00:00
|
|
|
*entryp = NULL;
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
2000-01-12 03:00:33 +00:00
|
|
|
}
|
|
|
|
|
1999-10-29 23:53:12 +00:00
|
|
|
/*
|
|
|
|
* ADB must be locked, and no other locks held.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
static isc_boolean_t
|
2000-05-08 14:38:29 +00:00
|
|
|
cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
|
1999-10-29 23:53:12 +00:00
|
|
|
dns_adbname_t *name;
|
|
|
|
dns_adbname_t *next_name;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_result_t result = ISC_FALSE;
|
1999-10-29 23:53:12 +00:00
|
|
|
|
2000-01-12 03:00:33 +00:00
|
|
|
DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
|
1999-11-24 19:23:27 +00:00
|
|
|
|
1999-10-29 23:53:12 +00:00
|
|
|
LOCK(&adb->namelocks[bucket]);
|
|
|
|
if (adb->name_sd[bucket]) {
|
|
|
|
UNLOCK(&adb->namelocks[bucket]);
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
1999-10-29 23:53:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
name = ISC_LIST_HEAD(adb->names[bucket]);
|
|
|
|
while (name != NULL) {
|
|
|
|
next_name = ISC_LIST_NEXT(name, plink);
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(result == ISC_FALSE);
|
|
|
|
result = check_expire_namehooks(name, now, adb->overmem);
|
|
|
|
if (!result)
|
|
|
|
result = check_expire_name(&name, now);
|
1999-10-29 23:53:12 +00:00
|
|
|
name = next_name;
|
|
|
|
}
|
|
|
|
UNLOCK(&adb->namelocks[bucket]);
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
1999-10-25 22:53:15 +00:00
|
|
|
}
|
|
|
|
|
2000-01-12 03:00:33 +00:00
|
|
|
/*
|
|
|
|
* ADB must be locked, and no other locks held.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
static isc_boolean_t
|
2000-05-08 14:38:29 +00:00
|
|
|
cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
|
2000-01-12 03:00:33 +00:00
|
|
|
dns_adbentry_t *entry, *next_entry;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_boolean_t result = ISC_FALSE;
|
2000-01-12 03:00:33 +00:00
|
|
|
|
|
|
|
DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
|
|
|
|
|
|
|
|
LOCK(&adb->entrylocks[bucket]);
|
|
|
|
entry = ISC_LIST_HEAD(adb->entries[bucket]);
|
|
|
|
while (entry != NULL) {
|
|
|
|
next_entry = ISC_LIST_NEXT(entry, plink);
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(result == ISC_FALSE);
|
|
|
|
result = check_expire_entry(adb, &entry, now);
|
2000-01-12 03:00:33 +00:00
|
|
|
entry = next_entry;
|
|
|
|
}
|
|
|
|
UNLOCK(&adb->entrylocks[bucket]);
|
2002-11-13 00:07:04 +00:00
|
|
|
return (result);
|
2000-01-12 03:00:33 +00:00
|
|
|
}
|
|
|
|
|
1999-10-25 22:53:15 +00:00
|
|
|
static void
|
2000-05-08 14:38:29 +00:00
|
|
|
timer_cleanup(isc_task_t *task, isc_event_t *ev) {
|
1999-10-25 22:53:15 +00:00
|
|
|
dns_adb_t *adb;
|
1999-10-29 23:53:12 +00:00
|
|
|
isc_stdtime_t now;
|
2000-02-18 03:53:00 +00:00
|
|
|
unsigned int i;
|
2001-10-25 04:57:46 +00:00
|
|
|
isc_interval_t interval;
|
1999-10-25 22:53:15 +00:00
|
|
|
|
2000-02-18 03:53:00 +00:00
|
|
|
UNUSED(task);
|
1999-10-25 23:18:19 +00:00
|
|
|
|
2000-04-17 19:22:44 +00:00
|
|
|
adb = ev->ev_arg;
|
1999-10-25 22:53:15 +00:00
|
|
|
INSIST(DNS_ADB_VALID(adb));
|
|
|
|
|
|
|
|
LOCK(&adb->lock);
|
|
|
|
|
1999-12-16 23:29:07 +00:00
|
|
|
isc_stdtime_get(&now);
|
1999-10-29 23:53:12 +00:00
|
|
|
|
2001-10-19 01:29:41 +00:00
|
|
|
for (i = 0; i < CLEAN_BUCKETS; i++) {
|
2000-02-18 03:53:00 +00:00
|
|
|
/*
|
|
|
|
* Call our cleanup routines.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(cleanup_names(adb, adb->next_cleanbucket, now) ==
|
|
|
|
ISC_FALSE);
|
|
|
|
INSIST(cleanup_entries(adb, adb->next_cleanbucket, now) ==
|
|
|
|
ISC_FALSE);
|
1999-10-29 23:53:12 +00:00
|
|
|
|
2000-02-18 03:53:00 +00:00
|
|
|
/*
|
|
|
|
* Set the next bucket to be cleaned.
|
|
|
|
*/
|
|
|
|
adb->next_cleanbucket++;
|
|
|
|
if (adb->next_cleanbucket >= NBUCKETS) {
|
|
|
|
adb->next_cleanbucket = 0;
|
1999-11-24 19:23:27 +00:00
|
|
|
#ifdef DUMP_ADB_AFTER_CLEANING
|
2000-12-18 20:03:33 +00:00
|
|
|
dump_adb(adb, stdout, ISC_TRUE);
|
1999-11-24 19:23:27 +00:00
|
|
|
#endif
|
2000-02-18 03:53:00 +00:00
|
|
|
}
|
1999-11-24 19:23:27 +00:00
|
|
|
}
|
1999-10-29 23:53:12 +00:00
|
|
|
|
1999-10-25 22:53:15 +00:00
|
|
|
/*
|
|
|
|
* Reset the timer.
|
Silence IRIX warnings:
"adb.c", line 2042: remark(1552): variable "result" was set but never used
isc_result_t result;
^
"adb.c", line 3082: warning(1185): enumerated type mixed with another type
NAME_GLUEOK(adbname), NAME_HINTOK(adbname),
^
"adb.c", line 3187: warning(1185): enumerated type mixed with another type
now, NAME_GLUEOK(adbname), NAME_HINTOK(adbname),
Note that the first is in timer_cleanup, a function returning void in a context
that can't do anything with something other than void (as an isc_taskaction_t).
It calls isc_timer_reset, which could conceivably return ISC_R_NOMEMORY or
ISC_R_UNEXPECTED. For now the call has been cast to void, but someone
who knows the code better should have a look and see whether something more
intelligent could be done with an error (and, if not, remove my XXX and
make sure the comment is clear as to why ignoring the return is the
best that can be done).
2000-05-13 20:15:16 +00:00
|
|
|
* XXXDCL isc_timer_reset might return ISC_R_UNEXPECTED or
|
|
|
|
* ISC_R_NOMEMORY, but it isn't clear what could be done here
|
|
|
|
* if either one of those things happened.
|
1999-10-25 22:53:15 +00:00
|
|
|
*/
|
2001-10-25 04:57:46 +00:00
|
|
|
interval = adb->tick_interval;
|
|
|
|
if (adb->overmem)
|
|
|
|
isc_interval_set(&interval, 0, 1);
|
Silence IRIX warnings:
"adb.c", line 2042: remark(1552): variable "result" was set but never used
isc_result_t result;
^
"adb.c", line 3082: warning(1185): enumerated type mixed with another type
NAME_GLUEOK(adbname), NAME_HINTOK(adbname),
^
"adb.c", line 3187: warning(1185): enumerated type mixed with another type
now, NAME_GLUEOK(adbname), NAME_HINTOK(adbname),
Note that the first is in timer_cleanup, a function returning void in a context
that can't do anything with something other than void (as an isc_taskaction_t).
It calls isc_timer_reset, which could conceivably return ISC_R_NOMEMORY or
ISC_R_UNEXPECTED. For now the call has been cast to void, but someone
who knows the code better should have a look and see whether something more
intelligent could be done with an error (and, if not, remove my XXX and
make sure the comment is clear as to why ignoring the return is the
best that can be done).
2000-05-13 20:15:16 +00:00
|
|
|
(void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
|
2001-10-25 04:57:46 +00:00
|
|
|
&interval, ISC_FALSE);
|
1999-10-25 22:53:15 +00:00
|
|
|
|
|
|
|
UNLOCK(&adb->lock);
|
|
|
|
|
|
|
|
isc_event_free(&ev);
|
|
|
|
}
|
|
|
|
|
1999-09-24 23:54:42 +00:00
|
|
|
static void
|
2000-05-08 14:38:29 +00:00
|
|
|
destroy(dns_adb_t *adb) {
|
1999-09-24 23:54:42 +00:00
|
|
|
adb->magic = 0;
|
|
|
|
|
1999-10-25 23:07:14 +00:00
|
|
|
/*
|
|
|
|
* The timer is already dead, from the task's shutdown callback.
|
|
|
|
*/
|
1999-10-25 22:53:15 +00:00
|
|
|
isc_task_detach(&adb->task);
|
|
|
|
|
1999-09-24 23:54:42 +00:00
|
|
|
isc_mempool_destroy(&adb->nmp);
|
|
|
|
isc_mempool_destroy(&adb->nhmp);
|
|
|
|
isc_mempool_destroy(&adb->zimp);
|
|
|
|
isc_mempool_destroy(&adb->emp);
|
|
|
|
isc_mempool_destroy(&adb->ahmp);
|
|
|
|
isc_mempool_destroy(&adb->aimp);
|
1999-10-25 21:02:54 +00:00
|
|
|
isc_mempool_destroy(&adb->afmp);
|
1999-09-24 23:54:42 +00:00
|
|
|
|
2001-11-30 01:59:49 +00:00
|
|
|
DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
|
|
|
|
DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS);
|
1999-09-24 23:54:42 +00:00
|
|
|
|
2001-11-07 22:40:33 +00:00
|
|
|
DESTROYLOCK(&adb->reflock);
|
2000-08-26 01:37:00 +00:00
|
|
|
DESTROYLOCK(&adb->lock);
|
|
|
|
DESTROYLOCK(&adb->mplock);
|
1999-09-24 23:54:42 +00:00
|
|
|
|
2001-11-12 19:05:39 +00:00
|
|
|
isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
|
1999-09-24 23:54:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-09-22 00:26:20 +00:00
|
|
|
/*
|
|
|
|
* Public functions.
|
|
|
|
*/
|
|
|
|
|
1999-09-21 22:46:42 +00:00
|
|
|
isc_result_t
|
1999-10-25 21:40:56 +00:00
|
|
|
dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
|
1999-10-25 21:39:08 +00:00
|
|
|
isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
|
1999-09-21 22:46:42 +00:00
|
|
|
{
|
1999-09-23 00:43:10 +00:00
|
|
|
dns_adb_t *adb;
|
|
|
|
isc_result_t result;
|
|
|
|
int i;
|
|
|
|
|
1999-09-22 00:26:20 +00:00
|
|
|
REQUIRE(mem != NULL);
|
1999-10-25 22:53:15 +00:00
|
|
|
REQUIRE(view != NULL);
|
|
|
|
REQUIRE(timermgr != NULL);
|
|
|
|
REQUIRE(taskmgr != NULL);
|
1999-09-22 00:26:20 +00:00
|
|
|
REQUIRE(newadb != NULL && *newadb == NULL);
|
|
|
|
|
2001-11-12 19:05:39 +00:00
|
|
|
adb = isc_mem_get(mem, sizeof(dns_adb_t));
|
1999-09-23 00:43:10 +00:00
|
|
|
if (adb == NULL)
|
|
|
|
return (ISC_R_NOMEMORY);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize things here that cannot fail, and especially things
|
|
|
|
* that must be NULL for the error return to work properly.
|
|
|
|
*/
|
|
|
|
adb->magic = 0;
|
1999-10-19 01:37:22 +00:00
|
|
|
adb->erefcnt = 1;
|
|
|
|
adb->irefcnt = 0;
|
1999-09-23 00:43:10 +00:00
|
|
|
adb->nmp = NULL;
|
|
|
|
adb->nhmp = NULL;
|
|
|
|
adb->zimp = NULL;
|
|
|
|
adb->emp = NULL;
|
|
|
|
adb->ahmp = NULL;
|
|
|
|
adb->aimp = NULL;
|
1999-10-25 21:02:54 +00:00
|
|
|
adb->afmp = NULL;
|
1999-10-25 22:53:15 +00:00
|
|
|
adb->task = NULL;
|
|
|
|
adb->timer = NULL;
|
2001-10-25 04:57:46 +00:00
|
|
|
adb->mctx = NULL;
|
1999-10-25 22:53:15 +00:00
|
|
|
adb->view = view;
|
|
|
|
adb->timermgr = timermgr;
|
|
|
|
adb->taskmgr = taskmgr;
|
2000-01-12 03:00:33 +00:00
|
|
|
adb->next_cleanbucket = 0;
|
2001-11-12 19:05:39 +00:00
|
|
|
ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
|
1999-11-22 19:57:58 +00:00
|
|
|
DNS_EVENT_ADBCONTROL, shutdown_task, adb,
|
|
|
|
adb, NULL, NULL);
|
|
|
|
adb->cevent_sent = ISC_FALSE;
|
|
|
|
adb->shutting_down = ISC_FALSE;
|
2001-10-25 04:57:46 +00:00
|
|
|
adb->overmem = ISC_FALSE;
|
1999-11-22 19:57:58 +00:00
|
|
|
ISC_LIST_INIT(adb->whenshutdown);
|
1999-09-23 00:43:10 +00:00
|
|
|
|
2001-10-25 04:57:46 +00:00
|
|
|
isc_mem_attach(mem, &adb->mctx);
|
|
|
|
|
1999-10-20 23:26:06 +00:00
|
|
|
result = isc_mutex_init(&adb->lock);
|
1999-09-23 00:43:10 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
1999-10-05 23:50:43 +00:00
|
|
|
goto fail0b;
|
1999-10-25 23:18:19 +00:00
|
|
|
|
1999-10-20 23:26:06 +00:00
|
|
|
result = isc_mutex_init(&adb->mplock);
|
1999-10-05 23:50:43 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto fail0c;
|
1999-09-23 00:43:10 +00:00
|
|
|
|
2001-11-07 22:40:33 +00:00
|
|
|
result = isc_mutex_init(&adb->reflock);
|
2000-01-13 20:42:43 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto fail0d;
|
|
|
|
|
1999-09-23 00:43:10 +00:00
|
|
|
/*
|
1999-09-24 23:54:42 +00:00
|
|
|
* Initialize the bucket locks for names and elements.
|
|
|
|
* May as well initialize the list heads, too.
|
1999-09-23 00:43:10 +00:00
|
|
|
*/
|
1999-11-05 02:05:06 +00:00
|
|
|
result = isc_mutexblock_init(adb->namelocks, NBUCKETS);
|
1999-09-24 23:54:42 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto fail1;
|
2001-10-19 01:29:41 +00:00
|
|
|
for (i = 0; i < NBUCKETS; i++) {
|
1999-09-23 00:43:10 +00:00
|
|
|
ISC_LIST_INIT(adb->names[i]);
|
1999-10-19 01:37:22 +00:00
|
|
|
adb->name_sd[i] = ISC_FALSE;
|
|
|
|
adb->name_refcnt[i] = 0;
|
|
|
|
adb->irefcnt++;
|
|
|
|
}
|
2001-10-19 01:29:41 +00:00
|
|
|
for (i = 0; i < NBUCKETS; i++) {
|
1999-09-23 00:43:10 +00:00
|
|
|
ISC_LIST_INIT(adb->entries[i]);
|
2000-01-12 03:00:33 +00:00
|
|
|
adb->entry_sd[i] = ISC_FALSE;
|
|
|
|
adb->entry_refcnt[i] = 0;
|
|
|
|
adb->irefcnt++;
|
|
|
|
}
|
1999-11-05 02:05:06 +00:00
|
|
|
result = isc_mutexblock_init(adb->entrylocks, NBUCKETS);
|
1999-09-24 23:54:42 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto fail2;
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Memory pools
|
|
|
|
*/
|
2000-05-08 18:47:02 +00:00
|
|
|
#define MPINIT(t, p, n) do { \
|
2001-11-12 19:05:39 +00:00
|
|
|
result = isc_mempool_create(mem, sizeof(t), &(p)); \
|
1999-09-23 00:43:10 +00:00
|
|
|
if (result != ISC_R_SUCCESS) \
|
|
|
|
goto fail3; \
|
|
|
|
isc_mempool_setfreemax((p), FREE_ITEMS); \
|
|
|
|
isc_mempool_setfillcount((p), FILL_COUNT); \
|
1999-10-19 01:37:22 +00:00
|
|
|
isc_mempool_setname((p), n); \
|
2000-05-08 18:47:02 +00:00
|
|
|
isc_mempool_associatelock((p), &adb->mplock); \
|
1999-09-23 00:43:10 +00:00
|
|
|
} while (0)
|
|
|
|
|
2000-05-08 18:47:02 +00:00
|
|
|
MPINIT(dns_adbname_t, adb->nmp, "adbname");
|
|
|
|
MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
|
|
|
|
MPINIT(dns_adbzoneinfo_t, adb->zimp, "adbzoneinfo");
|
|
|
|
MPINIT(dns_adbentry_t, adb->emp, "adbentry");
|
|
|
|
MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
|
|
|
|
MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
|
|
|
|
MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
#undef MPINIT
|
|
|
|
|
1999-10-25 22:53:15 +00:00
|
|
|
/*
|
|
|
|
* Allocate a timer and a task for our periodic cleanup.
|
|
|
|
*/
|
2000-04-12 01:41:21 +00:00
|
|
|
result = isc_task_create(adb->taskmgr, 0, &adb->task);
|
1999-10-25 22:53:15 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto fail3;
|
2000-01-25 19:31:23 +00:00
|
|
|
isc_task_setname(adb->task, "ADB", adb);
|
1999-12-01 02:05:16 +00:00
|
|
|
/*
|
|
|
|
* XXXMLG When this is changed to be a config file option,
|
2000-08-01 01:33:37 +00:00
|
|
|
*/
|
1999-10-25 22:53:15 +00:00
|
|
|
isc_interval_set(&adb->tick_interval, CLEAN_SECONDS, 0);
|
|
|
|
result = isc_timer_create(adb->timermgr, isc_timertype_once,
|
|
|
|
NULL, &adb->tick_interval, adb->task,
|
|
|
|
timer_cleanup, adb, &adb->timer);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto fail3;
|
|
|
|
|
2002-09-10 02:01:15 +00:00
|
|
|
DP(ISC_LOG_DEBUG(5), "cleaning interval for adb: "
|
2000-02-18 03:53:00 +00:00
|
|
|
"%u buckets every %u seconds, %u buckets in system, %u cl.interval",
|
|
|
|
CLEAN_BUCKETS, CLEAN_SECONDS, NBUCKETS, CLEAN_PERIOD);
|
|
|
|
|
1999-09-23 00:43:10 +00:00
|
|
|
/*
|
|
|
|
* Normal return.
|
|
|
|
*/
|
|
|
|
adb->magic = DNS_ADB_MAGIC;
|
|
|
|
*newadb = adb;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
1999-10-25 22:53:15 +00:00
|
|
|
fail3:
|
|
|
|
if (adb->task != NULL)
|
|
|
|
isc_task_detach(&adb->task);
|
|
|
|
if (adb->timer != NULL)
|
|
|
|
isc_timer_detach(&adb->timer);
|
|
|
|
|
|
|
|
/* clean up entrylocks */
|
2001-11-30 01:59:49 +00:00
|
|
|
DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
fail2: /* clean up namelocks */
|
2001-11-30 01:59:49 +00:00
|
|
|
DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS);
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
fail1: /* clean up only allocated memory */
|
|
|
|
if (adb->nmp != NULL)
|
|
|
|
isc_mempool_destroy(&adb->nmp);
|
|
|
|
if (adb->nhmp != NULL)
|
|
|
|
isc_mempool_destroy(&adb->nhmp);
|
|
|
|
if (adb->zimp != NULL)
|
|
|
|
isc_mempool_destroy(&adb->zimp);
|
|
|
|
if (adb->emp != NULL)
|
|
|
|
isc_mempool_destroy(&adb->emp);
|
|
|
|
if (adb->ahmp != NULL)
|
|
|
|
isc_mempool_destroy(&adb->ahmp);
|
|
|
|
if (adb->aimp != NULL)
|
|
|
|
isc_mempool_destroy(&adb->aimp);
|
1999-10-30 01:58:02 +00:00
|
|
|
if (adb->afmp != NULL)
|
1999-10-25 21:02:54 +00:00
|
|
|
isc_mempool_destroy(&adb->afmp);
|
1999-09-23 00:43:10 +00:00
|
|
|
|
2001-11-07 22:40:33 +00:00
|
|
|
DESTROYLOCK(&adb->reflock);
|
2000-01-13 20:42:43 +00:00
|
|
|
fail0d:
|
2000-08-26 01:37:00 +00:00
|
|
|
DESTROYLOCK(&adb->mplock);
|
1999-10-20 23:26:06 +00:00
|
|
|
fail0c:
|
2000-08-26 01:37:00 +00:00
|
|
|
DESTROYLOCK(&adb->lock);
|
1999-10-20 23:26:06 +00:00
|
|
|
fail0b:
|
2001-11-12 19:05:39 +00:00
|
|
|
isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
return (result);
|
1999-09-21 22:46:42 +00:00
|
|
|
}
|
|
|
|
|
2000-04-18 08:18:52 +00:00
|
|
|
void
|
|
|
|
dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
|
|
|
|
|
|
|
|
REQUIRE(DNS_ADB_VALID(adb));
|
|
|
|
REQUIRE(adbx != NULL && *adbx == NULL);
|
|
|
|
|
2001-11-07 22:40:33 +00:00
|
|
|
inc_adb_erefcnt(adb);
|
2000-04-18 08:18:52 +00:00
|
|
|
*adbx = adb;
|
|
|
|
}
|
|
|
|
|
1999-09-21 22:46:42 +00:00
|
|
|
void
|
2000-05-08 14:38:29 +00:00
|
|
|
dns_adb_detach(dns_adb_t **adbx) {
|
1999-09-23 00:43:10 +00:00
|
|
|
dns_adb_t *adb;
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_boolean_t need_exit_check;
|
1999-09-23 00:43:10 +00:00
|
|
|
|
|
|
|
REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
|
|
|
|
|
|
|
|
adb = *adbx;
|
|
|
|
*adbx = NULL;
|
|
|
|
|
2001-11-14 22:32:10 +00:00
|
|
|
INSIST(adb->erefcnt > 0);
|
|
|
|
|
|
|
|
LOCK(&adb->reflock);
|
|
|
|
adb->erefcnt--;
|
2002-11-13 00:07:04 +00:00
|
|
|
need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
|
2001-11-14 22:32:10 +00:00
|
|
|
UNLOCK(&adb->reflock);
|
|
|
|
|
2002-11-13 00:07:04 +00:00
|
|
|
if (need_exit_check) {
|
2001-11-14 22:32:10 +00:00
|
|
|
LOCK(&adb->lock);
|
1999-11-22 19:57:58 +00:00
|
|
|
INSIST(adb->shutting_down);
|
2002-11-13 00:07:04 +00:00
|
|
|
check_exit(adb);
|
2001-11-14 22:32:10 +00:00
|
|
|
UNLOCK(&adb->lock);
|
|
|
|
}
|
1999-11-22 19:57:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-05-08 14:38:29 +00:00
|
|
|
dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
|
1999-11-22 19:57:58 +00:00
|
|
|
isc_task_t *clone;
|
|
|
|
isc_event_t *event;
|
2000-01-13 20:42:43 +00:00
|
|
|
isc_boolean_t zeroirefcnt = ISC_FALSE;
|
1999-11-22 19:57:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Send '*eventp' to 'task' when 'adb' has shutdown.
|
|
|
|
*/
|
|
|
|
|
|
|
|
REQUIRE(DNS_ADB_VALID(adb));
|
|
|
|
REQUIRE(eventp != NULL);
|
|
|
|
|
|
|
|
event = *eventp;
|
|
|
|
*eventp = NULL;
|
|
|
|
|
|
|
|
LOCK(&adb->lock);
|
2000-01-13 20:42:43 +00:00
|
|
|
|
2001-11-07 22:40:33 +00:00
|
|
|
LOCK(&adb->reflock);
|
|
|
|
zeroirefcnt = ISC_TF(adb->irefcnt == 0);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2000-01-13 20:42:43 +00:00
|
|
|
if (adb->shutting_down && zeroirefcnt &&
|
1999-11-22 19:57:58 +00:00
|
|
|
isc_mempool_getallocated(adb->ahmp) == 0) {
|
|
|
|
/*
|
|
|
|
* We're already shutdown. Send the event.
|
|
|
|
*/
|
2000-04-17 19:22:44 +00:00
|
|
|
event->ev_sender = adb;
|
1999-11-22 19:57:58 +00:00
|
|
|
isc_task_send(task, &event);
|
|
|
|
} else {
|
|
|
|
clone = NULL;
|
|
|
|
isc_task_attach(task, &clone);
|
2000-04-17 19:22:44 +00:00
|
|
|
event->ev_sender = clone;
|
|
|
|
ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
|
1999-11-22 19:57:58 +00:00
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2002-11-13 00:07:04 +00:00
|
|
|
UNLOCK(&adb->reflock);
|
1999-11-22 19:57:58 +00:00
|
|
|
UNLOCK(&adb->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_adb_shutdown(dns_adb_t *adb) {
|
2002-11-13 00:07:04 +00:00
|
|
|
isc_boolean_t need_check_exit;
|
1999-11-22 19:57:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Shutdown 'adb'.
|
|
|
|
*/
|
|
|
|
|
|
|
|
LOCK(&adb->lock);
|
|
|
|
|
|
|
|
if (!adb->shutting_down) {
|
|
|
|
adb->shutting_down = ISC_TRUE;
|
2001-10-25 04:57:46 +00:00
|
|
|
isc_mem_setwater(adb->mctx, water, adb, 0, 0);
|
2002-11-13 00:07:04 +00:00
|
|
|
need_check_exit = shutdown_names(adb);
|
|
|
|
if (!need_check_exit)
|
|
|
|
need_check_exit = shutdown_entries(adb);
|
|
|
|
if (need_check_exit)
|
|
|
|
check_exit(adb);
|
1999-11-22 19:57:58 +00:00
|
|
|
}
|
|
|
|
|
1999-10-25 23:07:14 +00:00
|
|
|
UNLOCK(&adb->lock);
|
1999-09-21 22:46:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
1999-10-29 18:00:31 +00:00
|
|
|
dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|
|
|
void *arg, dns_name_t *name, dns_name_t *zone,
|
2000-01-21 02:50:27 +00:00
|
|
|
unsigned int options, isc_stdtime_t now, dns_name_t *target,
|
2000-06-01 00:30:58 +00:00
|
|
|
in_port_t port, dns_adbfind_t **findp)
|
1999-09-21 22:46:42 +00:00
|
|
|
{
|
1999-10-29 18:30:48 +00:00
|
|
|
dns_adbfind_t *find;
|
1999-10-08 23:12:21 +00:00
|
|
|
dns_adbname_t *adbname;
|
|
|
|
int bucket;
|
2003-02-26 22:54:29 +00:00
|
|
|
isc_boolean_t want_event, start_at_zone, alias, have_address;
|
1999-10-05 23:50:43 +00:00
|
|
|
isc_result_t result;
|
1999-10-29 01:26:45 +00:00
|
|
|
unsigned int wanted_addresses;
|
1999-12-14 00:10:06 +00:00
|
|
|
unsigned int wanted_fetches;
|
1999-11-02 18:36:54 +00:00
|
|
|
unsigned int query_pending;
|
1999-10-05 23:50:43 +00:00
|
|
|
|
1999-09-22 00:26:20 +00:00
|
|
|
REQUIRE(DNS_ADB_VALID(adb));
|
|
|
|
if (task != NULL) {
|
|
|
|
REQUIRE(action != NULL);
|
|
|
|
}
|
1999-10-08 23:12:21 +00:00
|
|
|
REQUIRE(name != NULL);
|
1999-09-22 00:26:20 +00:00
|
|
|
REQUIRE(zone != NULL);
|
1999-10-29 18:30:48 +00:00
|
|
|
REQUIRE(findp != NULL && *findp == NULL);
|
2000-01-21 02:50:27 +00:00
|
|
|
REQUIRE(target == NULL || dns_name_hasbuffer(target));
|
1999-10-05 23:50:43 +00:00
|
|
|
|
1999-11-01 02:29:03 +00:00
|
|
|
REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
|
1999-10-29 01:26:45 +00:00
|
|
|
|
1999-10-19 01:37:22 +00:00
|
|
|
result = ISC_R_UNEXPECTED;
|
1999-10-29 01:26:45 +00:00
|
|
|
wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
|
1999-12-14 00:10:06 +00:00
|
|
|
wanted_fetches = 0;
|
1999-11-02 18:36:54 +00:00
|
|
|
query_pending = 0;
|
|
|
|
want_event = ISC_FALSE;
|
2003-02-26 22:54:29 +00:00
|
|
|
start_at_zone = ISC_FALSE;
|
2000-01-21 02:50:27 +00:00
|
|
|
alias = ISC_FALSE;
|
1999-09-22 00:26:20 +00:00
|
|
|
|
1999-12-16 23:29:07 +00:00
|
|
|
if (now == 0)
|
|
|
|
isc_stdtime_get(&now);
|
1999-10-20 23:26:06 +00:00
|
|
|
|
1999-09-25 02:44:40 +00:00
|
|
|
/*
|
1999-11-25 01:23:32 +00:00
|
|
|
* XXXMLG Move this comment somewhere else!
|
|
|
|
*
|
1999-10-08 23:12:21 +00:00
|
|
|
* Look up the name in our internal database.
|
1999-09-25 02:44:40 +00:00
|
|
|
*
|
|
|
|
* Possibilities: Note that these are not always exclusive.
|
|
|
|
*
|
1999-10-08 23:12:21 +00:00
|
|
|
* No name found. In this case, allocate a new name header and
|
|
|
|
* an initial namehook or two. If any of these allocations
|
|
|
|
* fail, clean up and return ISC_R_NOMEMORY.
|
1999-09-25 02:44:40 +00:00
|
|
|
*
|
|
|
|
* Name found, valid addresses present. Allocate one addrinfo
|
|
|
|
* structure for each found and append it to the linked list
|
|
|
|
* of addresses for this header.
|
|
|
|
*
|
|
|
|
* Name found, queries pending. In this case, if a task was
|
|
|
|
* passed in, allocate a job id, attach it to the name's job
|
|
|
|
* list and remember to tell the caller that there will be
|
|
|
|
* more info coming later.
|
|
|
|
*/
|
1999-11-25 01:23:32 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
find = new_adbfind(adb);
|
|
|
|
if (find == NULL)
|
1999-10-29 01:26:45 +00:00
|
|
|
return (ISC_R_NOMEMORY);
|
1999-10-08 23:12:21 +00:00
|
|
|
|
2000-06-01 00:30:58 +00:00
|
|
|
find->port = port;
|
|
|
|
|
1999-10-08 23:12:21 +00:00
|
|
|
/*
|
1999-10-29 01:26:45 +00:00
|
|
|
* Remember what types of addresses we are interested in.
|
|
|
|
*/
|
1999-10-29 18:30:48 +00:00
|
|
|
find->options = options;
|
1999-10-30 01:58:02 +00:00
|
|
|
find->flags |= wanted_addresses;
|
1999-11-04 08:48:47 +00:00
|
|
|
if (FIND_WANTEVENT(find)) {
|
|
|
|
REQUIRE(task != NULL);
|
|
|
|
}
|
1999-10-29 01:26:45 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Try to see if we know anything about this name at all.
|
1999-10-08 23:12:21 +00:00
|
|
|
*/
|
|
|
|
bucket = DNS_ADB_INVALIDBUCKET;
|
2000-02-02 23:24:04 +00:00
|
|
|
adbname = find_name_and_lock(adb, name, find->options, &bucket);
|
1999-10-19 01:37:22 +00:00
|
|
|
if (adb->name_sd[bucket]) {
|
1999-11-01 20:16:35 +00:00
|
|
|
DP(DEF_LEVEL,
|
1999-11-02 00:29:45 +00:00
|
|
|
"dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(free_adbfind(adb, &find) == ISC_FALSE);
|
1999-10-27 19:36:58 +00:00
|
|
|
result = ISC_R_SHUTTINGDOWN;
|
1999-10-29 01:26:45 +00:00
|
|
|
goto out;
|
1999-10-26 00:16:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1999-10-29 01:26:45 +00:00
|
|
|
* Nothing found. Allocate a new adbname structure for this name.
|
1999-10-26 00:16:36 +00:00
|
|
|
*/
|
1999-10-29 01:26:45 +00:00
|
|
|
if (adbname == NULL) {
|
|
|
|
adbname = new_adbname(adb, name);
|
|
|
|
if (adbname == NULL) {
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(free_adbfind(adb, &find) == ISC_FALSE);
|
1999-10-29 01:26:45 +00:00
|
|
|
result = ISC_R_NOMEMORY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
link_name(adb, bucket, adbname);
|
2000-02-02 23:24:04 +00:00
|
|
|
if (FIND_HINTOK(find))
|
|
|
|
adbname->flags |= NAME_HINT_OK;
|
|
|
|
if (FIND_GLUEOK(find))
|
|
|
|
adbname->flags |= NAME_GLUE_OK;
|
2003-02-26 22:54:29 +00:00
|
|
|
if (FIND_STARTATZONE(find))
|
|
|
|
adbname->flags |= NAME_STARTATZONE;
|
1999-10-27 19:36:58 +00:00
|
|
|
}
|
1999-10-25 23:43:20 +00:00
|
|
|
|
|
|
|
/*
|
1999-10-29 01:26:45 +00:00
|
|
|
* Expire old entries, etc.
|
1999-10-25 23:43:20 +00:00
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(check_expire_namehooks(adbname, now, adb->overmem) == ISC_FALSE);
|
1999-10-25 23:43:20 +00:00
|
|
|
|
2000-01-21 02:50:27 +00:00
|
|
|
/*
|
|
|
|
* Do we know that the name is an alias?
|
|
|
|
*/
|
|
|
|
if (!EXPIRE_OK(adbname->expire_target, now)) {
|
|
|
|
/*
|
|
|
|
* Yes, it is.
|
|
|
|
*/
|
|
|
|
DP(DEF_LEVEL,
|
|
|
|
"dns_adb_createfind: name %p is an alias (cached)",
|
|
|
|
adbname);
|
|
|
|
alias = ISC_TRUE;
|
|
|
|
goto post_copy;
|
|
|
|
}
|
|
|
|
|
1999-10-25 23:43:20 +00:00
|
|
|
/*
|
|
|
|
* Try to populate the name from the database and/or
|
2000-09-29 23:53:05 +00:00
|
|
|
* start fetches. First try looking for an A record
|
|
|
|
* in the database.
|
1999-10-25 23:43:20 +00:00
|
|
|
*/
|
2003-02-27 02:20:15 +00:00
|
|
|
if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
|
1999-10-29 01:26:45 +00:00
|
|
|
&& WANT_INET(wanted_addresses)) {
|
2000-02-02 23:24:04 +00:00
|
|
|
result = dbfind_name(adbname, now, dns_rdatatype_a);
|
1999-10-29 01:26:45 +00:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
1999-11-01 20:16:35 +00:00
|
|
|
DP(DEF_LEVEL,
|
2000-06-16 15:51:58 +00:00
|
|
|
"dns_adb_createfind: found A for name %p in db",
|
1999-10-29 22:28:57 +00:00
|
|
|
adbname);
|
1999-10-29 01:26:45 +00:00
|
|
|
goto v6;
|
|
|
|
}
|
1999-10-25 23:43:20 +00:00
|
|
|
|
2000-01-21 02:50:27 +00:00
|
|
|
/*
|
|
|
|
* Did we get a CNAME or DNAME?
|
|
|
|
*/
|
2000-01-28 00:32:32 +00:00
|
|
|
if (result == DNS_R_ALIAS) {
|
2000-01-21 02:50:27 +00:00
|
|
|
DP(DEF_LEVEL,
|
|
|
|
"dns_adb_createfind: name %p is an alias",
|
|
|
|
adbname);
|
|
|
|
alias = ISC_TRUE;
|
|
|
|
goto post_copy;
|
|
|
|
}
|
|
|
|
|
1999-11-24 19:23:27 +00:00
|
|
|
/*
|
2000-09-26 22:28:55 +00:00
|
|
|
* If the name doesn't exist at all, don't bother with
|
|
|
|
* v6 queries; they won't work.
|
|
|
|
*
|
|
|
|
* If the name does exist but we didn't get our data, go
|
2002-11-27 09:52:58 +00:00
|
|
|
* ahead and try AAAA.
|
2000-09-26 22:28:55 +00:00
|
|
|
*
|
2000-09-29 23:53:05 +00:00
|
|
|
* If the result is neither of these, try a fetch for A.
|
1999-11-24 19:23:27 +00:00
|
|
|
*/
|
2000-09-26 22:28:55 +00:00
|
|
|
if (NXDOMAIN_RESULT(result))
|
|
|
|
goto fetch;
|
|
|
|
else if (NXRRSET_RESULT(result))
|
1999-11-24 19:23:27 +00:00
|
|
|
goto v6;
|
|
|
|
|
2003-02-27 02:20:15 +00:00
|
|
|
if (!NAME_FETCH_V4(adbname))
|
|
|
|
wanted_fetches |= DNS_ADBFIND_INET;
|
1999-10-26 01:12:20 +00:00
|
|
|
}
|
|
|
|
|
1999-10-29 01:26:45 +00:00
|
|
|
v6:
|
2003-02-27 02:20:15 +00:00
|
|
|
if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
|
1999-10-30 02:26:03 +00:00
|
|
|
&& WANT_INET6(wanted_addresses)) {
|
2000-09-26 22:28:55 +00:00
|
|
|
result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
DP(DEF_LEVEL,
|
|
|
|
"dns_adb_createfind: found AAAA for name %p",
|
|
|
|
adbname);
|
|
|
|
goto fetch;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-11-27 09:52:58 +00:00
|
|
|
* Did we get a CNAME or DNAME?
|
2000-09-26 22:28:55 +00:00
|
|
|
*/
|
|
|
|
if (result == DNS_R_ALIAS) {
|
|
|
|
DP(DEF_LEVEL,
|
|
|
|
"dns_adb_createfind: name %p is an alias",
|
|
|
|
adbname);
|
|
|
|
alias = ISC_TRUE;
|
|
|
|
goto post_copy;
|
|
|
|
}
|
|
|
|
|
1999-11-24 19:23:27 +00:00
|
|
|
/*
|
|
|
|
* Listen to negative cache hints, and don't start
|
|
|
|
* another query.
|
|
|
|
*/
|
2000-01-15 00:45:49 +00:00
|
|
|
if (NCACHE_RESULT(result) || AUTH_NX(result))
|
1999-12-14 00:10:06 +00:00
|
|
|
goto fetch;
|
|
|
|
|
2003-02-27 02:20:15 +00:00
|
|
|
if (!NAME_FETCH_V6(adbname))
|
|
|
|
wanted_fetches |= DNS_ADBFIND_INET6;
|
1999-12-14 00:10:06 +00:00
|
|
|
}
|
1999-11-24 19:23:27 +00:00
|
|
|
|
1999-12-14 00:10:06 +00:00
|
|
|
fetch:
|
2001-02-28 20:51:22 +00:00
|
|
|
if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
|
|
|
|
(WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
|
|
|
|
have_address = ISC_TRUE;
|
|
|
|
else
|
|
|
|
have_address = ISC_FALSE;
|
1999-12-14 00:10:06 +00:00
|
|
|
if (wanted_fetches != 0 &&
|
2001-02-28 20:51:22 +00:00
|
|
|
! (FIND_AVOIDFETCHES(find) && have_address)) {
|
1999-10-29 19:20:36 +00:00
|
|
|
/*
|
1999-12-14 00:10:06 +00:00
|
|
|
* We're missing at least one address family. Either the
|
|
|
|
* caller hasn't instructed us to avoid fetches, or we don't
|
|
|
|
* know anything about any of the address families that would
|
|
|
|
* be acceptable so we have to launch fetches.
|
1999-10-29 19:20:36 +00:00
|
|
|
*/
|
1999-12-14 00:10:06 +00:00
|
|
|
|
2003-02-26 22:54:29 +00:00
|
|
|
if (FIND_STARTATZONE(find))
|
|
|
|
start_at_zone = ISC_TRUE;
|
2000-01-06 00:56:37 +00:00
|
|
|
|
1999-12-14 00:10:06 +00:00
|
|
|
/*
|
|
|
|
* Start V4.
|
|
|
|
*/
|
|
|
|
if (WANT_INET(wanted_fetches) &&
|
2003-02-26 22:54:29 +00:00
|
|
|
fetch_name(adbname, start_at_zone,
|
2002-11-27 09:52:58 +00:00
|
|
|
dns_rdatatype_a) == ISC_R_SUCCESS) {
|
1999-12-14 00:10:06 +00:00
|
|
|
DP(DEF_LEVEL,
|
2000-06-16 15:51:58 +00:00
|
|
|
"dns_adb_createfind: started A fetch for name %p",
|
1999-12-14 00:10:06 +00:00
|
|
|
adbname);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start V6.
|
|
|
|
*/
|
|
|
|
if (WANT_INET6(wanted_fetches) &&
|
2003-02-26 22:54:29 +00:00
|
|
|
fetch_name(adbname, start_at_zone,
|
2002-11-27 09:52:58 +00:00
|
|
|
dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
|
1999-11-01 20:16:35 +00:00
|
|
|
DP(DEF_LEVEL,
|
2002-11-27 09:52:58 +00:00
|
|
|
"dns_adb_createfind: "
|
|
|
|
"started AAAA fetch for name %p",
|
1999-10-29 22:28:57 +00:00
|
|
|
adbname);
|
1999-10-29 19:20:36 +00:00
|
|
|
}
|
1999-10-29 01:26:45 +00:00
|
|
|
}
|
1999-10-08 23:12:21 +00:00
|
|
|
|
|
|
|
/*
|
1999-10-29 01:26:45 +00:00
|
|
|
* Run through the name and copy out the bits we are
|
|
|
|
* interested in.
|
1999-10-08 23:12:21 +00:00
|
|
|
*/
|
1999-11-02 00:29:45 +00:00
|
|
|
copy_namehook_lists(adb, find, zone, adbname, now);
|
1999-10-21 01:37:57 +00:00
|
|
|
|
2000-01-27 02:14:53 +00:00
|
|
|
post_copy:
|
1999-11-02 18:36:54 +00:00
|
|
|
if (NAME_FETCH_V4(adbname))
|
|
|
|
query_pending |= DNS_ADBFIND_INET;
|
|
|
|
if (NAME_FETCH_V6(adbname))
|
|
|
|
query_pending |= DNS_ADBFIND_INET6;
|
|
|
|
|
1999-10-27 19:36:58 +00:00
|
|
|
/*
|
|
|
|
* Attach to the name's query list if there are queries
|
1999-10-29 01:26:45 +00:00
|
|
|
* already running, and we have been asked to.
|
1999-10-27 19:36:58 +00:00
|
|
|
*/
|
1999-11-02 18:36:54 +00:00
|
|
|
want_event = ISC_TRUE;
|
1999-11-04 08:48:47 +00:00
|
|
|
if (!FIND_WANTEVENT(find))
|
1999-11-02 18:36:54 +00:00
|
|
|
want_event = ISC_FALSE;
|
1999-11-04 08:48:47 +00:00
|
|
|
if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
|
1999-11-02 18:36:54 +00:00
|
|
|
want_event = ISC_FALSE;
|
|
|
|
if ((wanted_addresses & query_pending) == 0)
|
|
|
|
want_event = ISC_FALSE;
|
2000-01-21 02:50:27 +00:00
|
|
|
if (alias)
|
|
|
|
want_event = ISC_FALSE;
|
1999-11-02 18:36:54 +00:00
|
|
|
if (want_event) {
|
1999-10-29 18:30:48 +00:00
|
|
|
find->adbname = adbname;
|
|
|
|
find->name_bucket = bucket;
|
|
|
|
ISC_LIST_APPEND(adbname->finds, find, plink);
|
1999-11-02 18:36:54 +00:00
|
|
|
find->query_pending = (query_pending & wanted_addresses);
|
1999-11-01 20:16:35 +00:00
|
|
|
find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
|
|
|
|
find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
|
1999-11-05 02:05:06 +00:00
|
|
|
DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
|
1999-11-01 02:57:16 +00:00
|
|
|
find, adbname);
|
1999-10-29 01:26:45 +00:00
|
|
|
} else {
|
1999-10-29 18:00:31 +00:00
|
|
|
/*
|
|
|
|
* Remove the flag so the caller knows there will never
|
|
|
|
* be an event, and set internal flags to fake that
|
|
|
|
* the event was sent and freed, so dns_adb_destroyfind() will
|
|
|
|
* do the right thing.
|
|
|
|
*/
|
2000-01-27 02:14:53 +00:00
|
|
|
find->query_pending = (query_pending & wanted_addresses);
|
1999-10-29 18:30:48 +00:00
|
|
|
find->options &= ~DNS_ADBFIND_WANTEVENT;
|
|
|
|
find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
|
1999-11-01 20:16:35 +00:00
|
|
|
find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
|
1999-10-08 23:12:21 +00:00
|
|
|
}
|
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
find->partial_result |= (adbname->partial_result & wanted_addresses);
|
2000-01-21 02:50:27 +00:00
|
|
|
if (alias) {
|
|
|
|
if (target != NULL) {
|
2001-02-05 19:47:05 +00:00
|
|
|
result = dns_name_copy(&adbname->target, target, NULL);
|
2000-01-21 02:50:27 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
result = DNS_R_ALIAS;
|
|
|
|
} else
|
|
|
|
result = ISC_R_SUCCESS;
|
1999-10-19 20:55:04 +00:00
|
|
|
|
2000-08-26 02:21:45 +00:00
|
|
|
/*
|
|
|
|
* Copy out error flags from the name structure into the find.
|
|
|
|
*/
|
|
|
|
find->result_v4 = find_err_map[adbname->fetch_err];
|
|
|
|
find->result_v6 = find_err_map[adbname->fetch6_err];
|
|
|
|
|
1999-10-29 01:26:45 +00:00
|
|
|
out:
|
1999-10-29 18:30:48 +00:00
|
|
|
if (find != NULL) {
|
|
|
|
*findp = find;
|
1999-10-08 23:12:21 +00:00
|
|
|
|
1999-11-02 18:36:54 +00:00
|
|
|
if (want_event) {
|
1999-10-16 00:38:21 +00:00
|
|
|
isc_task_t *taskp;
|
|
|
|
|
1999-11-01 20:16:35 +00:00
|
|
|
INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
|
1999-10-16 00:38:21 +00:00
|
|
|
taskp = NULL;
|
|
|
|
isc_task_attach(task, &taskp);
|
2000-04-17 19:22:44 +00:00
|
|
|
find->event.ev_sender = taskp;
|
|
|
|
find->event.ev_action = action;
|
|
|
|
find->event.ev_arg = arg;
|
1999-10-16 00:38:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-10-08 23:12:21 +00:00
|
|
|
if (bucket != DNS_ADB_INVALIDBUCKET)
|
|
|
|
UNLOCK(&adb->namelocks[bucket]);
|
|
|
|
|
|
|
|
return (result);
|
1999-09-25 01:56:10 +00:00
|
|
|
}
|
|
|
|
|
1999-09-21 22:46:42 +00:00
|
|
|
void
|
2000-05-08 14:38:29 +00:00
|
|
|
dns_adb_destroyfind(dns_adbfind_t **findp) {
|
1999-10-29 18:30:48 +00:00
|
|
|
dns_adbfind_t *find;
|
1999-10-14 00:50:00 +00:00
|
|
|
dns_adbentry_t *entry;
|
|
|
|
dns_adbaddrinfo_t *ai;
|
|
|
|
int bucket;
|
1999-10-22 05:19:42 +00:00
|
|
|
dns_adb_t *adb;
|
1999-09-22 00:26:20 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
|
|
|
|
find = *findp;
|
|
|
|
*findp = NULL;
|
1999-09-21 22:46:42 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
LOCK(&find->lock);
|
1999-10-22 05:19:42 +00:00
|
|
|
|
2000-01-13 18:58:01 +00:00
|
|
|
DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
|
1999-10-27 19:36:58 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
adb = find->adb;
|
1999-10-22 05:19:42 +00:00
|
|
|
REQUIRE(DNS_ADB_VALID(adb));
|
1999-10-14 00:50:00 +00:00
|
|
|
|
1999-11-04 08:48:47 +00:00
|
|
|
REQUIRE(FIND_EVENTFREED(find));
|
1999-10-19 20:55:04 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
bucket = find->name_bucket;
|
1999-10-29 18:00:31 +00:00
|
|
|
INSIST(bucket == DNS_ADB_INVALIDBUCKET);
|
1999-10-14 00:50:00 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
UNLOCK(&find->lock);
|
1999-09-22 00:26:20 +00:00
|
|
|
|
1999-10-14 00:50:00 +00:00
|
|
|
/*
|
1999-10-29 18:30:48 +00:00
|
|
|
* The find doesn't exist on any list, and nothing is locked.
|
|
|
|
* Return the find to the memory pool, and decrement the adb's
|
1999-10-14 00:50:00 +00:00
|
|
|
* reference count.
|
|
|
|
*/
|
1999-10-29 18:30:48 +00:00
|
|
|
ai = ISC_LIST_HEAD(find->list);
|
1999-10-14 00:50:00 +00:00
|
|
|
while (ai != NULL) {
|
1999-10-29 18:30:48 +00:00
|
|
|
ISC_LIST_UNLINK(find->list, ai, publink);
|
1999-10-14 00:50:00 +00:00
|
|
|
entry = ai->entry;
|
|
|
|
ai->entry = NULL;
|
|
|
|
INSIST(DNS_ADBENTRY_VALID(entry));
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(dec_entry_refcnt(adb, entry, ISC_TRUE) == ISC_FALSE);
|
1999-10-14 00:50:00 +00:00
|
|
|
free_adbaddrinfo(adb, &ai);
|
1999-10-29 18:30:48 +00:00
|
|
|
ai = ISC_LIST_HEAD(find->list);
|
1999-10-14 00:50:00 +00:00
|
|
|
}
|
1999-10-22 05:19:42 +00:00
|
|
|
|
1999-10-29 18:00:31 +00:00
|
|
|
/*
|
1999-10-29 18:30:48 +00:00
|
|
|
* WARNING: The find is freed with the adb locked. This is done
|
|
|
|
* to avoid a race condition where we free the find, some other
|
1999-10-29 18:00:31 +00:00
|
|
|
* thread tests to see if it should be destroyed, detects it should
|
|
|
|
* be, destroys it, and then we try to lock it for our check, but the
|
|
|
|
* lock is destroyed.
|
|
|
|
*/
|
1999-10-22 05:19:42 +00:00
|
|
|
LOCK(&adb->lock);
|
2002-11-13 00:07:04 +00:00
|
|
|
if (free_adbfind(adb, &find))
|
|
|
|
check_exit(adb);
|
1999-10-25 23:07:14 +00:00
|
|
|
UNLOCK(&adb->lock);
|
1999-09-21 22:46:42 +00:00
|
|
|
}
|
1999-10-02 01:59:09 +00:00
|
|
|
|
1999-10-29 18:00:31 +00:00
|
|
|
void
|
2000-05-08 14:38:29 +00:00
|
|
|
dns_adb_cancelfind(dns_adbfind_t *find) {
|
1999-10-29 18:00:31 +00:00
|
|
|
isc_event_t *ev;
|
|
|
|
isc_task_t *task;
|
|
|
|
dns_adb_t *adb;
|
|
|
|
int bucket;
|
1999-12-10 23:22:13 +00:00
|
|
|
int unlock_bucket;
|
1999-10-29 18:00:31 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
LOCK(&find->lock);
|
1999-10-29 18:00:31 +00:00
|
|
|
|
1999-11-01 20:16:35 +00:00
|
|
|
DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
|
1999-10-29 18:00:31 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
adb = find->adb;
|
1999-10-29 18:00:31 +00:00
|
|
|
REQUIRE(DNS_ADB_VALID(adb));
|
|
|
|
|
1999-11-04 08:48:47 +00:00
|
|
|
REQUIRE(!FIND_EVENTFREED(find));
|
|
|
|
REQUIRE(FIND_WANTEVENT(find));
|
1999-10-29 18:00:31 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
bucket = find->name_bucket;
|
1999-10-29 18:00:31 +00:00
|
|
|
if (bucket == DNS_ADB_INVALIDBUCKET)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/*
|
1999-10-29 18:30:48 +00:00
|
|
|
* We need to get the adbname's lock to unlink the find.
|
1999-10-29 18:00:31 +00:00
|
|
|
*/
|
1999-12-10 23:22:13 +00:00
|
|
|
unlock_bucket = bucket;
|
|
|
|
violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
|
1999-10-29 18:30:48 +00:00
|
|
|
bucket = find->name_bucket;
|
1999-10-29 18:00:31 +00:00
|
|
|
if (bucket != DNS_ADB_INVALIDBUCKET) {
|
1999-10-29 18:30:48 +00:00
|
|
|
ISC_LIST_UNLINK(find->adbname->finds, find, plink);
|
|
|
|
find->adbname = NULL;
|
|
|
|
find->name_bucket = DNS_ADB_INVALIDBUCKET;
|
1999-10-29 18:00:31 +00:00
|
|
|
}
|
1999-12-10 23:22:13 +00:00
|
|
|
UNLOCK(&adb->namelocks[unlock_bucket]);
|
1999-10-29 18:00:31 +00:00
|
|
|
bucket = DNS_ADB_INVALIDBUCKET;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
1999-11-04 08:48:47 +00:00
|
|
|
if (!FIND_EVENTSENT(find)) {
|
1999-10-29 18:30:48 +00:00
|
|
|
ev = &find->event;
|
2000-04-17 19:22:44 +00:00
|
|
|
task = ev->ev_sender;
|
|
|
|
ev->ev_sender = find;
|
|
|
|
ev->ev_type = DNS_EVENT_ADBCANCELED;
|
|
|
|
ev->ev_destroy = event_free;
|
|
|
|
ev->ev_destroy_arg = find;
|
2000-08-26 02:21:45 +00:00
|
|
|
find->result_v4 = ISC_R_CANCELED;
|
|
|
|
find->result_v6 = ISC_R_CANCELED;
|
1999-10-29 18:00:31 +00:00
|
|
|
|
2001-10-27 00:32:31 +00:00
|
|
|
DP(DEF_LEVEL, "sending event %p to task %p for find %p",
|
1999-10-29 22:28:57 +00:00
|
|
|
ev, task, find);
|
1999-10-29 18:00:31 +00:00
|
|
|
|
2000-08-26 02:21:45 +00:00
|
|
|
isc_task_sendanddetach(&task, (isc_event_t **)&ev);
|
1999-10-29 18:00:31 +00:00
|
|
|
}
|
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
UNLOCK(&find->lock);
|
1999-10-29 18:00:31 +00:00
|
|
|
}
|
|
|
|
|
1999-10-02 01:59:09 +00:00
|
|
|
void
|
2000-05-08 14:38:29 +00:00
|
|
|
dns_adb_dump(dns_adb_t *adb, FILE *f) {
|
1999-10-02 01:59:09 +00:00
|
|
|
REQUIRE(DNS_ADB_VALID(adb));
|
|
|
|
REQUIRE(f != NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lock the adb itself, lock all the name buckets, then lock all
|
|
|
|
* the entry buckets. This should put the adb into a state where
|
|
|
|
* nothing can change, so we can iterate through everything and
|
2000-12-15 21:06:00 +00:00
|
|
|
* print at our leisure.
|
1999-10-02 01:59:09 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
LOCK(&adb->lock);
|
2001-01-27 02:44:35 +00:00
|
|
|
dump_adb(adb, f, ISC_FALSE);
|
1999-10-27 19:36:58 +00:00
|
|
|
UNLOCK(&adb->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2000-12-18 20:03:33 +00:00
|
|
|
dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
|
|
|
|
if (value == INT_MAX)
|
|
|
|
return;
|
|
|
|
fprintf(f, " [%s TTL %d]", legend, value - now);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug) {
|
1999-10-27 19:36:58 +00:00
|
|
|
int i;
|
|
|
|
dns_adbname_t *name;
|
1999-11-04 08:29:06 +00:00
|
|
|
isc_stdtime_t now;
|
|
|
|
|
1999-12-16 23:29:07 +00:00
|
|
|
isc_stdtime_get(&now);
|
1999-10-02 01:59:09 +00:00
|
|
|
|
2000-12-18 20:03:33 +00:00
|
|
|
fprintf(f, ";\n; Address database dump\n;\n");
|
|
|
|
if (debug)
|
|
|
|
fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
|
|
|
|
adb, adb->erefcnt, adb->irefcnt,
|
|
|
|
isc_mempool_getallocated(adb->nhmp));
|
1999-10-19 01:37:22 +00:00
|
|
|
|
2001-10-19 01:29:41 +00:00
|
|
|
for (i = 0; i < NBUCKETS; i++)
|
1999-10-02 01:59:09 +00:00
|
|
|
LOCK(&adb->namelocks[i]);
|
2001-10-19 01:29:41 +00:00
|
|
|
for (i = 0; i < NBUCKETS; i++)
|
1999-10-02 01:59:09 +00:00
|
|
|
LOCK(&adb->entrylocks[i]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Dump the names
|
|
|
|
*/
|
2001-10-19 01:29:41 +00:00
|
|
|
for (i = 0; i < NBUCKETS; i++) {
|
1999-10-02 01:59:09 +00:00
|
|
|
name = ISC_LIST_HEAD(adb->names[i]);
|
|
|
|
if (name == NULL)
|
|
|
|
continue;
|
2000-12-18 20:03:33 +00:00
|
|
|
if (debug)
|
|
|
|
fprintf(f, "; bucket %d\n", i);
|
|
|
|
for (;
|
|
|
|
name != NULL;
|
|
|
|
name = ISC_LIST_NEXT(name, plink))
|
|
|
|
{
|
|
|
|
if (debug)
|
|
|
|
fprintf(f, "; name %p (flags %08x)\n",
|
|
|
|
name, name->flags);
|
|
|
|
|
|
|
|
fprintf(f, "; ");
|
1999-10-02 01:59:09 +00:00
|
|
|
print_dns_name(f, &name->name);
|
2000-01-21 02:50:27 +00:00
|
|
|
if (dns_name_countlabels(&name->target) > 0) {
|
2000-12-18 20:03:33 +00:00
|
|
|
fprintf(f, " alias ");
|
2000-01-21 02:50:27 +00:00
|
|
|
print_dns_name(f, &name->target);
|
|
|
|
}
|
1999-10-02 01:59:09 +00:00
|
|
|
|
2000-12-18 20:03:33 +00:00
|
|
|
dump_ttl(f, "v4", name->expire_v4, now);
|
|
|
|
dump_ttl(f, "v6", name->expire_v6, now);
|
|
|
|
dump_ttl(f, "target", name->expire_target, now);
|
1999-10-02 01:59:09 +00:00
|
|
|
|
2001-01-27 02:44:35 +00:00
|
|
|
fprintf(f, " [v4 %s] [v6 %s]",
|
|
|
|
errnames[name->fetch_err],
|
|
|
|
errnames[name->fetch6_err]);
|
|
|
|
|
|
|
|
fprintf(f, "\n");
|
1999-10-12 02:06:08 +00:00
|
|
|
|
2002-09-10 02:01:15 +00:00
|
|
|
print_namehook_list(f, "v4", &name->v4, debug, now);
|
|
|
|
print_namehook_list(f, "v6", &name->v6, debug, now);
|
1999-10-02 01:59:09 +00:00
|
|
|
|
2000-12-18 20:03:33 +00:00
|
|
|
if (debug)
|
|
|
|
print_fetch_list(f, name);
|
|
|
|
if (debug)
|
|
|
|
print_find_list(f, name);
|
1999-10-02 01:59:09 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unlock everything
|
|
|
|
*/
|
2001-01-27 02:44:35 +00:00
|
|
|
for (i = 0; i < NBUCKETS; i++)
|
1999-10-02 01:59:09 +00:00
|
|
|
UNLOCK(&adb->entrylocks[i]);
|
2001-01-27 02:44:35 +00:00
|
|
|
for (i = 0; i < NBUCKETS; i++)
|
1999-10-02 01:59:09 +00:00
|
|
|
UNLOCK(&adb->namelocks[i]);
|
|
|
|
}
|
|
|
|
|
2000-12-18 20:03:33 +00:00
|
|
|
static void
|
2002-09-10 02:01:15 +00:00
|
|
|
dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug,
|
|
|
|
isc_stdtime_t now)
|
2000-12-18 20:03:33 +00:00
|
|
|
{
|
|
|
|
char addrbuf[ISC_NETADDR_FORMATSIZE];
|
|
|
|
isc_netaddr_t netaddr;
|
2002-09-10 02:01:15 +00:00
|
|
|
dns_adbzoneinfo_t *zi;
|
2000-12-18 20:03:33 +00:00
|
|
|
|
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
|
2001-11-12 19:05:39 +00:00
|
|
|
isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
|
2000-12-18 20:03:33 +00:00
|
|
|
|
|
|
|
if (debug)
|
2002-09-10 02:01:15 +00:00
|
|
|
fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
|
2000-12-18 20:03:33 +00:00
|
|
|
|
2002-09-10 02:01:15 +00:00
|
|
|
fprintf(f, ";\t%s [srtt %u] [flags %08x]",
|
|
|
|
addrbuf, entry->srtt, entry->flags);
|
2000-12-18 20:03:33 +00:00
|
|
|
fprintf(f, "\n");
|
2002-09-10 02:01:15 +00:00
|
|
|
for (zi = ISC_LIST_HEAD(entry->zoneinfo);
|
|
|
|
zi != NULL;
|
|
|
|
zi = ISC_LIST_NEXT(zi, plink)) {
|
|
|
|
fprintf(f, ";\t\t");
|
|
|
|
print_dns_name(f, &zi->zone);
|
2002-09-12 00:28:52 +00:00
|
|
|
fprintf(f, " [lame TTL %d]\n", zi->lame_timer - now);
|
2002-09-10 02:01:15 +00:00
|
|
|
}
|
2000-12-18 20:03:33 +00:00
|
|
|
}
|
|
|
|
|
1999-10-16 00:38:21 +00:00
|
|
|
void
|
2000-05-08 14:38:29 +00:00
|
|
|
dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
|
1999-10-16 00:38:21 +00:00
|
|
|
char tmp[512];
|
|
|
|
const char *tmpp;
|
|
|
|
dns_adbaddrinfo_t *ai;
|
|
|
|
isc_sockaddr_t *sa;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Not used currently, in the API Just In Case we
|
|
|
|
* want to dump out the name and/or entries too.
|
|
|
|
*/
|
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
LOCK(&find->lock);
|
1999-10-16 00:38:21 +00:00
|
|
|
|
2000-12-18 20:03:33 +00:00
|
|
|
fprintf(f, ";Find %p\n", find);
|
|
|
|
fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
|
1999-10-29 18:30:48 +00:00
|
|
|
find->query_pending, find->partial_result,
|
1999-11-01 20:16:35 +00:00
|
|
|
find->options, find->flags);
|
2000-12-18 20:03:33 +00:00
|
|
|
fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
|
2000-04-17 19:22:44 +00:00
|
|
|
find->name_bucket, find->adbname, find->event.ev_sender);
|
1999-10-16 00:38:21 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
ai = ISC_LIST_HEAD(find->list);
|
1999-10-16 00:38:21 +00:00
|
|
|
if (ai != NULL)
|
|
|
|
fprintf(f, "\tAddresses:\n");
|
|
|
|
while (ai != NULL) {
|
2000-06-01 00:30:58 +00:00
|
|
|
sa = &ai->sockaddr;
|
1999-10-16 00:38:21 +00:00
|
|
|
switch (sa->type.sa.sa_family) {
|
|
|
|
case AF_INET:
|
|
|
|
tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
|
2001-11-12 19:05:39 +00:00
|
|
|
tmp, sizeof(tmp));
|
1999-10-16 00:38:21 +00:00
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
|
2001-11-12 19:05:39 +00:00
|
|
|
tmp, sizeof(tmp));
|
1999-10-16 00:38:21 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
tmpp = "UnkFamily";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmpp == NULL)
|
2000-02-16 01:49:11 +00:00
|
|
|
tmpp = "BadAddress";
|
1999-10-16 00:38:21 +00:00
|
|
|
|
2001-02-09 00:13:55 +00:00
|
|
|
fprintf(f, "\t\tentry %p, flags %08x"
|
2001-01-22 22:51:23 +00:00
|
|
|
" srtt %u addr %s\n",
|
2001-02-09 00:13:55 +00:00
|
|
|
ai->entry, ai->flags, ai->srtt, tmpp);
|
1999-10-16 00:38:21 +00:00
|
|
|
|
1999-10-29 01:53:20 +00:00
|
|
|
ai = ISC_LIST_NEXT(ai, publink);
|
1999-10-16 00:38:21 +00:00
|
|
|
}
|
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
UNLOCK(&find->lock);
|
1999-10-16 00:38:21 +00:00
|
|
|
}
|
|
|
|
|
1999-10-02 01:59:09 +00:00
|
|
|
static void
|
2000-05-08 14:38:29 +00:00
|
|
|
print_dns_name(FILE *f, dns_name_t *name) {
|
2000-08-09 00:09:36 +00:00
|
|
|
char buf[DNS_NAME_FORMATSIZE];
|
1999-10-02 01:59:09 +00:00
|
|
|
|
|
|
|
INSIST(f != NULL);
|
|
|
|
|
2000-05-26 16:12:30 +00:00
|
|
|
dns_name_format(name, buf, sizeof(buf));
|
|
|
|
fprintf(f, "%s", buf);
|
1999-10-02 01:59:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2000-12-18 20:03:33 +00:00
|
|
|
print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list,
|
2002-09-10 02:01:15 +00:00
|
|
|
isc_boolean_t debug, isc_stdtime_t now)
|
2000-12-18 20:03:33 +00:00
|
|
|
{
|
1999-10-02 01:59:09 +00:00
|
|
|
dns_adbnamehook_t *nh;
|
|
|
|
|
2000-12-18 20:03:33 +00:00
|
|
|
for (nh = ISC_LIST_HEAD(*list);
|
|
|
|
nh != NULL;
|
|
|
|
nh = ISC_LIST_NEXT(nh, plink))
|
|
|
|
{
|
|
|
|
if (debug)
|
|
|
|
fprintf(f, ";\tHook(%s) %p\n", legend, nh);
|
2002-09-10 02:01:15 +00:00
|
|
|
dump_entry(f, nh->entry, debug, now);
|
1999-10-02 01:59:09 +00:00
|
|
|
}
|
|
|
|
}
|
1999-10-16 00:38:21 +00:00
|
|
|
|
1999-11-02 18:36:54 +00:00
|
|
|
static inline void
|
2000-06-01 18:26:56 +00:00
|
|
|
print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) {
|
1999-11-02 18:36:54 +00:00
|
|
|
fprintf(f, "\t\tFetch(%s): %p -> { nh %p, entry %p, fetch %p }\n",
|
|
|
|
type, ft, ft->namehook, ft->entry, ft->fetch);
|
|
|
|
}
|
|
|
|
|
1999-10-29 21:48:51 +00:00
|
|
|
static void
|
2000-05-08 14:38:29 +00:00
|
|
|
print_fetch_list(FILE *f, dns_adbname_t *n) {
|
1999-11-02 18:36:54 +00:00
|
|
|
if (NAME_FETCH_A(n))
|
|
|
|
print_fetch(f, n->fetch_a, "A");
|
|
|
|
if (NAME_FETCH_AAAA(n))
|
|
|
|
print_fetch(f, n->fetch_aaaa, "AAAA");
|
1999-10-27 19:36:58 +00:00
|
|
|
}
|
|
|
|
|
1999-10-16 00:38:21 +00:00
|
|
|
static void
|
2000-05-08 14:38:29 +00:00
|
|
|
print_find_list(FILE *f, dns_adbname_t *name) {
|
1999-10-29 18:30:48 +00:00
|
|
|
dns_adbfind_t *find;
|
1999-10-16 00:38:21 +00:00
|
|
|
|
1999-10-29 18:30:48 +00:00
|
|
|
find = ISC_LIST_HEAD(name->finds);
|
|
|
|
while (find != NULL) {
|
1999-11-01 02:57:16 +00:00
|
|
|
dns_adb_dumpfind(find, f);
|
1999-10-29 18:30:48 +00:00
|
|
|
find = ISC_LIST_NEXT(find, plink);
|
1999-10-16 00:38:21 +00:00
|
|
|
}
|
|
|
|
}
|
1999-10-19 20:55:04 +00:00
|
|
|
|
|
|
|
static isc_result_t
|
2000-05-08 14:38:29 +00:00
|
|
|
dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype)
|
1999-10-19 20:55:04 +00:00
|
|
|
{
|
|
|
|
isc_result_t result;
|
1999-10-21 01:18:06 +00:00
|
|
|
dns_rdataset_t rdataset;
|
1999-10-29 01:26:45 +00:00
|
|
|
dns_adb_t *adb;
|
2000-01-21 02:50:27 +00:00
|
|
|
dns_fixedname_t foundname;
|
|
|
|
dns_name_t *fname;
|
1999-10-19 20:55:04 +00:00
|
|
|
|
|
|
|
INSIST(DNS_ADBNAME_VALID(adbname));
|
1999-10-29 01:26:45 +00:00
|
|
|
adb = adbname->adb;
|
|
|
|
INSIST(DNS_ADB_VALID(adb));
|
1999-10-29 21:48:51 +00:00
|
|
|
INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
|
1999-10-19 20:55:04 +00:00
|
|
|
|
2000-01-21 02:50:27 +00:00
|
|
|
dns_fixedname_init(&foundname);
|
|
|
|
fname = dns_fixedname_name(&foundname);
|
1999-10-21 01:18:06 +00:00
|
|
|
dns_rdataset_init(&rdataset);
|
|
|
|
|
2000-08-26 02:21:45 +00:00
|
|
|
if (rdtype == dns_rdatatype_a)
|
|
|
|
adbname->fetch_err = FIND_ERR_UNEXPECTED;
|
|
|
|
else
|
|
|
|
adbname->fetch6_err = FIND_ERR_UNEXPECTED;
|
|
|
|
|
2000-01-21 02:50:27 +00:00
|
|
|
result = dns_view_find(adb->view, &adbname->name, rdtype, now,
|
Silence IRIX warnings:
"adb.c", line 2042: remark(1552): variable "result" was set but never used
isc_result_t result;
^
"adb.c", line 3082: warning(1185): enumerated type mixed with another type
NAME_GLUEOK(adbname), NAME_HINTOK(adbname),
^
"adb.c", line 3187: warning(1185): enumerated type mixed with another type
now, NAME_GLUEOK(adbname), NAME_HINTOK(adbname),
Note that the first is in timer_cleanup, a function returning void in a context
that can't do anything with something other than void (as an isc_taskaction_t).
It calls isc_timer_reset, which could conceivably return ISC_R_NOMEMORY or
ISC_R_UNEXPECTED. For now the call has been cast to void, but someone
who knows the code better should have a look and see whether something more
intelligent could be done with an error (and, if not, remove my XXX and
make sure the comment is clear as to why ignoring the return is the
best that can be done).
2000-05-13 20:15:16 +00:00
|
|
|
NAME_GLUEOK(adbname),
|
|
|
|
ISC_TF(NAME_HINTOK(adbname)),
|
2000-12-20 03:38:46 +00:00
|
|
|
NULL, NULL, fname, &rdataset, NULL);
|
2000-02-02 23:24:04 +00:00
|
|
|
|
1999-10-29 19:20:36 +00:00
|
|
|
switch (result) {
|
|
|
|
case DNS_R_GLUE:
|
|
|
|
case DNS_R_HINT:
|
2000-04-06 22:03:35 +00:00
|
|
|
case ISC_R_SUCCESS:
|
1999-10-29 19:20:36 +00:00
|
|
|
/*
|
|
|
|
* Found in the database. Even if we can't copy out
|
|
|
|
* any information, return success, or else a fetch
|
|
|
|
* will be made, which will only make things worse.
|
|
|
|
*/
|
2000-08-26 02:21:45 +00:00
|
|
|
if (rdtype == dns_rdatatype_a)
|
|
|
|
adbname->fetch_err = FIND_ERR_SUCCESS;
|
|
|
|
else
|
|
|
|
adbname->fetch6_err = FIND_ERR_SUCCESS;
|
1999-11-02 00:29:45 +00:00
|
|
|
result = import_rdataset(adbname, &rdataset, now);
|
1999-10-29 19:20:36 +00:00
|
|
|
break;
|
2000-01-15 00:45:49 +00:00
|
|
|
case DNS_R_NXDOMAIN:
|
|
|
|
case DNS_R_NXRRSET:
|
|
|
|
/*
|
|
|
|
* We're authoritative and the data doesn't exist.
|
|
|
|
* Make up a negative cache entry so we don't ask again
|
|
|
|
* for a while.
|
|
|
|
*
|
|
|
|
* XXXRTH What time should we use? I'm putting in 30 seconds
|
|
|
|
* for now.
|
|
|
|
*/
|
|
|
|
if (rdtype == dns_rdatatype_a) {
|
|
|
|
adbname->expire_v4 = now + 30;
|
|
|
|
DP(NCACHE_LEVEL,
|
|
|
|
"adb name %p: Caching auth negative entry for A",
|
|
|
|
adbname);
|
2000-08-26 02:21:45 +00:00
|
|
|
if (result == DNS_R_NXDOMAIN)
|
|
|
|
adbname->fetch_err = FIND_ERR_NXDOMAIN;
|
|
|
|
else
|
|
|
|
adbname->fetch_err = FIND_ERR_NXRRSET;
|
2000-01-15 00:45:49 +00:00
|
|
|
} else {
|
|
|
|
DP(NCACHE_LEVEL,
|
|
|
|
"adb name %p: Caching auth negative entry for AAAA",
|
|
|
|
adbname);
|
|
|
|
adbname->expire_v6 = now + 30;
|
2000-08-26 02:21:45 +00:00
|
|
|
if (result == DNS_R_NXDOMAIN)
|
|
|
|
adbname->fetch6_err = FIND_ERR_NXDOMAIN;
|
|
|
|
else
|
|
|
|
adbname->fetch6_err = FIND_ERR_NXRRSET;
|
2000-01-15 00:45:49 +00:00
|
|
|
}
|
2000-01-19 01:43:58 +00:00
|
|
|
break;
|
1999-11-04 06:46:05 +00:00
|
|
|
case DNS_R_NCACHENXDOMAIN:
|
|
|
|
case DNS_R_NCACHENXRRSET:
|
|
|
|
/*
|
|
|
|
* We found a negative cache entry. Pull the TTL from it
|
|
|
|
* so we won't ask again for a while.
|
|
|
|
*/
|
2000-06-07 20:15:48 +00:00
|
|
|
rdataset.ttl = ttlclamp(rdataset.ttl);
|
1999-11-04 06:46:05 +00:00
|
|
|
if (rdtype == dns_rdatatype_a) {
|
|
|
|
adbname->expire_v4 = rdataset.ttl + now;
|
2000-08-26 02:21:45 +00:00
|
|
|
if (result == DNS_R_NCACHENXDOMAIN)
|
|
|
|
adbname->fetch_err = FIND_ERR_NXDOMAIN;
|
|
|
|
else
|
|
|
|
adbname->fetch_err = FIND_ERR_NXRRSET;
|
2000-01-19 01:43:58 +00:00
|
|
|
DP(NCACHE_LEVEL,
|
|
|
|
"adb name %p: Caching negative entry for A (ttl %u)",
|
1999-11-05 02:05:06 +00:00
|
|
|
adbname, rdataset.ttl);
|
1999-11-04 06:46:05 +00:00
|
|
|
} else {
|
2000-01-19 01:43:58 +00:00
|
|
|
DP(NCACHE_LEVEL,
|
|
|
|
"adb name %p: Caching negative entry for AAAA (ttl %u)",
|
1999-11-05 02:05:06 +00:00
|
|
|
adbname, rdataset.ttl);
|
1999-11-04 06:46:05 +00:00
|
|
|
adbname->expire_v6 = rdataset.ttl + now;
|
2000-08-26 02:21:45 +00:00
|
|
|
if (result == DNS_R_NCACHENXDOMAIN)
|
|
|
|
adbname->fetch6_err = FIND_ERR_NXDOMAIN;
|
|
|
|
else
|
|
|
|
adbname->fetch6_err = FIND_ERR_NXRRSET;
|
1999-11-04 06:46:05 +00:00
|
|
|
}
|
2000-01-19 01:43:58 +00:00
|
|
|
break;
|
2000-01-21 02:50:27 +00:00
|
|
|
case DNS_R_CNAME:
|
|
|
|
case DNS_R_DNAME:
|
2000-02-02 23:24:04 +00:00
|
|
|
/*
|
|
|
|
* Clear the hint and glue flags, so this will match
|
|
|
|
* more often.
|
|
|
|
*/
|
|
|
|
adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
|
|
|
|
|
2000-06-07 20:15:48 +00:00
|
|
|
rdataset.ttl = ttlclamp(rdataset.ttl);
|
2000-01-21 02:50:27 +00:00
|
|
|
clean_target(adb, &adbname->target);
|
|
|
|
adbname->expire_target = INT_MAX;
|
|
|
|
result = set_target(adb, &adbname->name, fname, &rdataset,
|
|
|
|
&adbname->target);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
2000-01-28 00:32:32 +00:00
|
|
|
result = DNS_R_ALIAS;
|
2000-01-21 02:50:27 +00:00
|
|
|
DP(NCACHE_LEVEL,
|
|
|
|
"adb name %p: caching alias target",
|
|
|
|
adbname);
|
|
|
|
adbname->expire_target = rdataset.ttl + now;
|
|
|
|
}
|
2000-08-26 02:21:45 +00:00
|
|
|
if (rdtype == dns_rdatatype_a)
|
|
|
|
adbname->fetch_err = FIND_ERR_SUCCESS;
|
|
|
|
else
|
|
|
|
adbname->fetch6_err = FIND_ERR_SUCCESS;
|
2000-01-21 02:50:27 +00:00
|
|
|
break;
|
1999-10-29 19:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dns_rdataset_isassociated(&rdataset))
|
|
|
|
dns_rdataset_disassociate(&rdataset);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
1999-10-27 19:36:58 +00:00
|
|
|
static void
|
2000-05-08 14:38:29 +00:00
|
|
|
fetch_callback(isc_task_t *task, isc_event_t *ev) {
|
1999-10-27 19:36:58 +00:00
|
|
|
dns_fetchevent_t *dev;
|
|
|
|
dns_adbname_t *name;
|
|
|
|
dns_adb_t *adb;
|
|
|
|
dns_adbfetch_t *fetch;
|
|
|
|
int bucket;
|
|
|
|
isc_eventtype_t ev_status;
|
1999-10-27 22:24:40 +00:00
|
|
|
isc_stdtime_t now;
|
|
|
|
isc_result_t result;
|
1999-11-04 06:46:05 +00:00
|
|
|
unsigned int address_type;
|
2000-01-13 20:42:43 +00:00
|
|
|
isc_boolean_t want_check_exit = ISC_FALSE;
|
1999-10-27 19:36:58 +00:00
|
|
|
|
2000-08-11 16:47:33 +00:00
|
|
|
UNUSED(task);
|
1999-10-27 19:36:58 +00:00
|
|
|
|
2000-04-17 19:22:44 +00:00
|
|
|
INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
|
1999-10-27 19:36:58 +00:00
|
|
|
dev = (dns_fetchevent_t *)ev;
|
2000-04-17 19:22:44 +00:00
|
|
|
name = ev->ev_arg;
|
1999-10-27 19:36:58 +00:00
|
|
|
INSIST(DNS_ADBNAME_VALID(name));
|
|
|
|
adb = name->adb;
|
|
|
|
INSIST(DNS_ADB_VALID(adb));
|
|
|
|
|
|
|
|
bucket = name->lock_bucket;
|
|
|
|
LOCK(&adb->namelocks[bucket]);
|
|
|
|
|
1999-11-04 09:04:29 +00:00
|
|
|
INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
|
1999-11-04 06:46:05 +00:00
|
|
|
address_type = 0;
|
1999-11-04 09:04:29 +00:00
|
|
|
if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
|
|
|
|
address_type = DNS_ADBFIND_INET;
|
|
|
|
fetch = name->fetch_a;
|
|
|
|
name->fetch_a = NULL;
|
|
|
|
} else if (NAME_FETCH_AAAA(name)
|
|
|
|
&& (name->fetch_aaaa->fetch == dev->fetch)) {
|
|
|
|
address_type = DNS_ADBFIND_INET6;
|
|
|
|
fetch = name->fetch_aaaa;
|
|
|
|
name->fetch_aaaa = NULL;
|
|
|
|
}
|
1999-11-04 06:46:05 +00:00
|
|
|
INSIST(address_type != 0);
|
1999-10-29 21:48:51 +00:00
|
|
|
|
2000-01-21 02:50:27 +00:00
|
|
|
dns_resolver_destroyfetch(&fetch->fetch);
|
1999-10-29 19:20:36 +00:00
|
|
|
dev->fetch = NULL;
|
|
|
|
|
1999-10-29 23:53:12 +00:00
|
|
|
ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
|
|
|
|
|
1999-10-29 19:20:36 +00:00
|
|
|
/*
|
|
|
|
* Cleanup things we don't care about.
|
|
|
|
*/
|
|
|
|
if (dev->node != NULL)
|
|
|
|
dns_db_detachnode(dev->db, &dev->node);
|
|
|
|
if (dev->db != NULL)
|
|
|
|
dns_db_detach(&dev->db);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this name is marked as dead, clean up, throwing away
|
|
|
|
* potentially good data.
|
|
|
|
*/
|
1999-10-30 01:58:02 +00:00
|
|
|
if (NAME_DEAD(name)) {
|
1999-10-29 19:20:36 +00:00
|
|
|
free_adbfetch(adb, &fetch);
|
|
|
|
isc_event_free(&ev);
|
|
|
|
|
2002-11-13 00:07:04 +00:00
|
|
|
want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
|
1999-10-29 19:20:36 +00:00
|
|
|
|
|
|
|
UNLOCK(&adb->namelocks[bucket]);
|
|
|
|
|
2000-01-13 20:42:43 +00:00
|
|
|
if (want_check_exit) {
|
|
|
|
LOCK(&adb->lock);
|
|
|
|
check_exit(adb);
|
|
|
|
UNLOCK(&adb->lock);
|
|
|
|
}
|
1999-10-29 19:20:36 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2000-01-21 02:50:27 +00:00
|
|
|
isc_stdtime_get(&now);
|
|
|
|
|
1999-11-24 19:23:27 +00:00
|
|
|
/*
|
|
|
|
* If we got a negative cache response, remember it.
|
|
|
|
*/
|
|
|
|
if (NCACHE_RESULT(dev->result)) {
|
2000-06-07 20:15:48 +00:00
|
|
|
dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
|
1999-11-24 19:23:27 +00:00
|
|
|
if (address_type == DNS_ADBFIND_INET) {
|
1999-12-01 02:05:16 +00:00
|
|
|
DP(NCACHE_LEVEL, "adb fetch name %p: "
|
2001-10-27 00:32:31 +00:00
|
|
|
"caching negative entry for A (ttl %u)",
|
1999-11-24 19:23:27 +00:00
|
|
|
name, dev->rdataset->ttl);
|
|
|
|
name->expire_v4 = ISC_MIN(name->expire_v4,
|
|
|
|
dev->rdataset->ttl + now);
|
2000-08-26 02:21:45 +00:00
|
|
|
if (dev->result == DNS_R_NCACHENXDOMAIN)
|
|
|
|
name->fetch_err = FIND_ERR_NXDOMAIN;
|
|
|
|
else
|
|
|
|
name->fetch_err = FIND_ERR_NXRRSET;
|
1999-11-24 19:23:27 +00:00
|
|
|
} else {
|
1999-12-01 02:05:16 +00:00
|
|
|
DP(NCACHE_LEVEL, "adb fetch name %p: "
|
2001-10-27 00:32:31 +00:00
|
|
|
"caching negative entry for AAAA (ttl %u)",
|
1999-11-24 19:23:27 +00:00
|
|
|
name, dev->rdataset->ttl);
|
|
|
|
name->expire_v6 = ISC_MIN(name->expire_v6,
|
|
|
|
dev->rdataset->ttl + now);
|
2000-08-26 02:21:45 +00:00
|
|
|
if (dev->result == DNS_R_NCACHENXDOMAIN)
|
|
|
|
name->fetch6_err = FIND_ERR_NXDOMAIN;
|
|
|
|
else
|
|
|
|
name->fetch6_err = FIND_ERR_NXRRSET;
|
1999-11-24 19:23:27 +00:00
|
|
|
}
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
1999-11-25 01:23:32 +00:00
|
|
|
/*
|
2000-01-21 02:50:27 +00:00
|
|
|
* Handle CNAME/DNAME.
|
1999-11-25 01:23:32 +00:00
|
|
|
*/
|
2000-01-21 02:50:27 +00:00
|
|
|
if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
|
2000-06-07 20:15:48 +00:00
|
|
|
dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
|
2000-01-21 02:50:27 +00:00
|
|
|
clean_target(adb, &name->target);
|
|
|
|
name->expire_target = INT_MAX;
|
|
|
|
result = set_target(adb, &name->name,
|
|
|
|
dns_fixedname_name(&dev->foundname),
|
|
|
|
dev->rdataset,
|
|
|
|
&name->target);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
DP(NCACHE_LEVEL,
|
|
|
|
"adb fetch name %p: caching alias target",
|
|
|
|
name);
|
|
|
|
name->expire_target = dev->rdataset->ttl + now;
|
|
|
|
}
|
|
|
|
goto check_result;
|
|
|
|
}
|
1999-11-25 01:23:32 +00:00
|
|
|
|
1999-10-29 19:20:36 +00:00
|
|
|
/*
|
|
|
|
* Did we get back junk? If so, and there are no more fetches
|
|
|
|
* sitting out there, tell all the finds about it.
|
|
|
|
*/
|
1999-11-04 09:42:46 +00:00
|
|
|
if (dev->result != ISC_R_SUCCESS) {
|
2002-09-10 02:01:15 +00:00
|
|
|
char buf[DNS_NAME_FORMATSIZE];
|
|
|
|
|
|
|
|
dns_name_format(&name->name, buf, sizeof(buf));
|
|
|
|
DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
|
|
|
|
buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
|
|
|
|
dns_result_totext(dev->result));
|
1999-11-04 09:42:46 +00:00
|
|
|
/* XXXMLG Don't pound on bad servers. */
|
2000-08-26 02:21:45 +00:00
|
|
|
if (address_type == DNS_ADBFIND_INET) {
|
1999-11-04 09:42:46 +00:00
|
|
|
name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
|
2000-08-26 02:21:45 +00:00
|
|
|
name->fetch_err = FIND_ERR_FAILURE;
|
|
|
|
} else {
|
1999-11-04 09:42:46 +00:00
|
|
|
name->expire_v6 = ISC_MIN(name->expire_v6, now + 300);
|
2000-08-26 02:21:45 +00:00
|
|
|
name->fetch6_err = FIND_ERR_FAILURE;
|
|
|
|
}
|
1999-10-29 19:20:36 +00:00
|
|
|
goto out;
|
1999-11-04 09:42:46 +00:00
|
|
|
}
|
1999-10-29 19:20:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We got something potentially useful.
|
|
|
|
*/
|
1999-12-16 23:29:07 +00:00
|
|
|
result = import_rdataset(name, &fetch->rdataset, now);
|
2000-01-21 02:50:27 +00:00
|
|
|
|
|
|
|
check_result:
|
2000-08-26 02:21:45 +00:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
1999-10-29 19:20:36 +00:00
|
|
|
ev_status = DNS_EVENT_ADBMOREADDRESSES;
|
2000-08-26 02:21:45 +00:00
|
|
|
if (address_type == DNS_ADBFIND_INET)
|
|
|
|
name->fetch_err = FIND_ERR_SUCCESS;
|
|
|
|
else
|
|
|
|
name->fetch6_err = FIND_ERR_SUCCESS;
|
|
|
|
}
|
1999-10-29 19:20:36 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
free_adbfetch(adb, &fetch);
|
|
|
|
isc_event_free(&ev);
|
|
|
|
|
1999-11-04 06:46:05 +00:00
|
|
|
clean_finds_at_name(name, ev_status, address_type);
|
1999-10-27 19:36:58 +00:00
|
|
|
|
|
|
|
UNLOCK(&adb->namelocks[bucket]);
|
|
|
|
}
|
|
|
|
|
1999-10-26 01:12:20 +00:00
|
|
|
static isc_result_t
|
2002-11-27 09:52:58 +00:00
|
|
|
fetch_name(dns_adbname_t *adbname,
|
2003-02-26 22:54:29 +00:00
|
|
|
isc_boolean_t start_at_zone,
|
2002-11-27 09:52:58 +00:00
|
|
|
dns_rdatatype_t type)
|
|
|
|
{
|
1999-10-27 19:36:58 +00:00
|
|
|
isc_result_t result;
|
2001-06-11 04:26:41 +00:00
|
|
|
dns_adbfetch_t *fetch = NULL;
|
1999-10-29 01:26:45 +00:00
|
|
|
dns_adb_t *adb;
|
2003-02-26 22:54:29 +00:00
|
|
|
dns_fixedname_t fixed;
|
2000-01-06 00:56:37 +00:00
|
|
|
dns_name_t *name;
|
2000-02-12 02:19:53 +00:00
|
|
|
dns_rdataset_t rdataset;
|
|
|
|
dns_rdataset_t *nameservers;
|
2001-05-02 17:29:17 +00:00
|
|
|
unsigned int options;
|
1999-10-29 01:26:45 +00:00
|
|
|
|
|
|
|
INSIST(DNS_ADBNAME_VALID(adbname));
|
|
|
|
adb = adbname->adb;
|
|
|
|
INSIST(DNS_ADB_VALID(adb));
|
1999-10-27 19:36:58 +00:00
|
|
|
|
2002-11-27 09:52:58 +00:00
|
|
|
INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
|
|
|
|
(type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
|
1999-10-29 21:48:51 +00:00
|
|
|
|
2000-08-26 02:21:45 +00:00
|
|
|
adbname->fetch_err = FIND_ERR_NOTFOUND;
|
|
|
|
|
2000-02-12 02:19:53 +00:00
|
|
|
name = NULL;
|
|
|
|
nameservers = NULL;
|
|
|
|
dns_rdataset_init(&rdataset);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2001-05-02 17:29:17 +00:00
|
|
|
options = 0;
|
2003-02-26 22:54:29 +00:00
|
|
|
if (start_at_zone) {
|
|
|
|
DP(50, "fetch_name: starting at zone for %p",
|
2000-01-06 00:56:37 +00:00
|
|
|
adbname);
|
2003-02-26 22:54:29 +00:00
|
|
|
dns_fixedname_init(&fixed);
|
|
|
|
name = dns_fixedname_name(&fixed);
|
|
|
|
result = dns_view_findzonecut2(adb->view, &adbname->name, name,
|
|
|
|
0, 0, ISC_TRUE, ISC_FALSE,
|
|
|
|
&rdataset, NULL);
|
2000-02-12 02:19:53 +00:00
|
|
|
if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
|
|
|
|
goto cleanup;
|
|
|
|
nameservers = &rdataset;
|
2001-05-02 17:29:17 +00:00
|
|
|
options |= DNS_FETCHOPT_UNSHARED;
|
2000-02-12 02:19:53 +00:00
|
|
|
}
|
1999-10-27 19:36:58 +00:00
|
|
|
|
|
|
|
fetch = new_adbfetch(adb);
|
|
|
|
if (fetch == NULL) {
|
|
|
|
result = ISC_R_NOMEMORY;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
|
2002-11-27 09:52:58 +00:00
|
|
|
type, name, nameservers, NULL,
|
|
|
|
options, adb->task, fetch_callback,
|
1999-10-29 01:26:45 +00:00
|
|
|
adbname, &fetch->rdataset, NULL,
|
1999-10-27 19:36:58 +00:00
|
|
|
&fetch->fetch);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
|
|
|
|
2002-11-27 09:52:58 +00:00
|
|
|
if (type == dns_rdatatype_a)
|
|
|
|
adbname->fetch_a = fetch;
|
|
|
|
else
|
|
|
|
adbname->fetch_aaaa = fetch;
|
2001-11-05 20:02:41 +00:00
|
|
|
fetch = NULL; /* Keep us from cleaning this up below. */
|
1999-10-27 19:36:58 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (fetch != NULL)
|
|
|
|
free_adbfetch(adb, &fetch);
|
2000-02-12 02:19:53 +00:00
|
|
|
if (dns_rdataset_isassociated(&rdataset))
|
|
|
|
dns_rdataset_disassociate(&rdataset);
|
1999-10-30 02:26:03 +00:00
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2000-11-11 02:14:25 +00:00
|
|
|
/*
|
|
|
|
* XXXMLG Needs to take a find argument and an address info, no zone or adb,
|
|
|
|
* since these can be extracted from the find itself.
|
1999-11-02 00:29:45 +00:00
|
|
|
*/
|
1999-10-19 21:10:29 +00:00
|
|
|
isc_result_t
|
1999-10-19 21:28:09 +00:00
|
|
|
dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *zone,
|
|
|
|
isc_stdtime_t expire_time)
|
1999-10-19 21:10:29 +00:00
|
|
|
{
|
|
|
|
dns_adbzoneinfo_t *zi;
|
1999-10-19 21:28:09 +00:00
|
|
|
int bucket;
|
1999-10-19 21:10:29 +00:00
|
|
|
|
|
|
|
REQUIRE(DNS_ADB_VALID(adb));
|
|
|
|
REQUIRE(DNS_ADBADDRINFO_VALID(addr));
|
|
|
|
REQUIRE(zone != NULL);
|
|
|
|
|
|
|
|
zi = new_adbzoneinfo(adb, zone);
|
|
|
|
if (zi == NULL)
|
|
|
|
return (ISC_R_NOMEMORY);
|
|
|
|
|
1999-10-19 21:28:09 +00:00
|
|
|
zi->lame_timer = expire_time;
|
|
|
|
|
|
|
|
bucket = addr->entry->lock_bucket;
|
|
|
|
LOCK(&adb->entrylocks[bucket]);
|
1999-10-29 01:53:20 +00:00
|
|
|
ISC_LIST_PREPEND(addr->entry->zoneinfo, zi, plink);
|
1999-10-19 21:28:09 +00:00
|
|
|
UNLOCK(&adb->entrylocks[bucket]);
|
|
|
|
|
1999-10-19 21:10:29 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
1999-10-19 22:06:08 +00:00
|
|
|
|
1999-10-19 22:21:27 +00:00
|
|
|
void
|
|
|
|
dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
|
|
|
|
unsigned int rtt, unsigned int factor)
|
|
|
|
{
|
|
|
|
int bucket;
|
|
|
|
unsigned int new_srtt;
|
2003-07-18 04:30:01 +00:00
|
|
|
isc_stdtime_t now;
|
1999-10-19 22:21:27 +00:00
|
|
|
|
|
|
|
REQUIRE(DNS_ADB_VALID(adb));
|
|
|
|
REQUIRE(DNS_ADBADDRINFO_VALID(addr));
|
1999-11-19 00:30:13 +00:00
|
|
|
REQUIRE(factor <= 10);
|
1999-10-19 22:21:27 +00:00
|
|
|
|
|
|
|
bucket = addr->entry->lock_bucket;
|
|
|
|
LOCK(&adb->entrylocks[bucket]);
|
|
|
|
|
2002-05-27 06:30:25 +00:00
|
|
|
if (factor == DNS_ADB_RTTADJAGE)
|
|
|
|
new_srtt = addr->entry->srtt * 98 / 100;
|
|
|
|
else
|
|
|
|
new_srtt = (addr->entry->srtt / 10 * factor)
|
|
|
|
+ (rtt / 10 * (10 - factor));
|
1999-11-19 00:30:13 +00:00
|
|
|
|
1999-10-19 22:21:27 +00:00
|
|
|
addr->entry->srtt = new_srtt;
|
|
|
|
addr->srtt = new_srtt;
|
|
|
|
|
2003-07-18 04:30:01 +00:00
|
|
|
isc_stdtime_get(&now);
|
|
|
|
addr->entry->expires = now + ADB_ENTRY_WINDOW;
|
|
|
|
|
1999-10-19 22:21:27 +00:00
|
|
|
UNLOCK(&adb->entrylocks[bucket]);
|
|
|
|
}
|
1999-11-16 06:53:29 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
|
|
|
|
unsigned int bits, unsigned int mask)
|
|
|
|
{
|
|
|
|
int bucket;
|
|
|
|
|
|
|
|
REQUIRE(DNS_ADB_VALID(adb));
|
|
|
|
REQUIRE(DNS_ADBADDRINFO_VALID(addr));
|
|
|
|
|
|
|
|
bucket = addr->entry->lock_bucket;
|
|
|
|
LOCK(&adb->entrylocks[bucket]);
|
|
|
|
|
1999-11-16 21:04:18 +00:00
|
|
|
addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
|
|
|
|
/*
|
|
|
|
* Note that we do not update the other bits in addr->flags with
|
|
|
|
* the most recent values from addr->entry->flags.
|
|
|
|
*/
|
|
|
|
addr->flags = (addr->flags & ~mask) | (bits & mask);
|
1999-11-16 06:53:29 +00:00
|
|
|
|
|
|
|
UNLOCK(&adb->entrylocks[bucket]);
|
|
|
|
}
|
2000-01-12 03:00:33 +00:00
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
|
2000-02-16 00:16:36 +00:00
|
|
|
dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
|
2000-01-12 03:00:33 +00:00
|
|
|
{
|
|
|
|
int bucket;
|
|
|
|
dns_adbentry_t *entry;
|
|
|
|
dns_adbaddrinfo_t *addr;
|
|
|
|
isc_result_t result;
|
2000-06-01 00:30:58 +00:00
|
|
|
in_port_t port;
|
2000-01-12 03:00:33 +00:00
|
|
|
|
|
|
|
REQUIRE(DNS_ADB_VALID(adb));
|
|
|
|
REQUIRE(addrp != NULL && *addrp == NULL);
|
|
|
|
|
2001-01-22 22:51:23 +00:00
|
|
|
UNUSED(now);
|
2000-02-16 00:16:36 +00:00
|
|
|
|
2000-01-12 03:00:33 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
bucket = DNS_ADB_INVALIDBUCKET;
|
|
|
|
entry = find_entry_and_lock(adb, sa, &bucket);
|
|
|
|
if (adb->entry_sd[bucket]) {
|
|
|
|
result = ISC_R_SHUTTINGDOWN;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
if (entry == NULL) {
|
|
|
|
/*
|
|
|
|
* We don't know anything about this address.
|
|
|
|
*/
|
|
|
|
entry = new_adbentry(adb);
|
|
|
|
if (entry == NULL) {
|
|
|
|
result = ISC_R_NOMEMORY;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
entry->sockaddr = *sa;
|
|
|
|
link_entry(adb, bucket, entry);
|
2002-09-10 02:01:15 +00:00
|
|
|
DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
|
2000-01-12 03:00:33 +00:00
|
|
|
} else
|
2002-09-10 02:01:15 +00:00
|
|
|
DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
|
2000-01-12 03:00:33 +00:00
|
|
|
|
2000-06-01 00:30:58 +00:00
|
|
|
port = isc_sockaddr_getport(sa);
|
|
|
|
addr = new_adbaddrinfo(adb, entry, port);
|
2000-01-12 03:00:33 +00:00
|
|
|
if (addr != NULL) {
|
|
|
|
inc_entry_refcnt(adb, entry, ISC_FALSE);
|
|
|
|
*addrp = addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
UNLOCK(&adb->entrylocks[bucket]);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-05-08 14:38:29 +00:00
|
|
|
dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
|
2000-01-12 03:00:33 +00:00
|
|
|
dns_adbaddrinfo_t *addr;
|
|
|
|
dns_adbentry_t *entry;
|
|
|
|
int bucket;
|
|
|
|
isc_stdtime_t now;
|
2000-01-13 20:42:43 +00:00
|
|
|
isc_boolean_t want_check_exit = ISC_FALSE;
|
2000-01-12 03:00:33 +00:00
|
|
|
|
|
|
|
REQUIRE(DNS_ADB_VALID(adb));
|
|
|
|
REQUIRE(addrp != NULL);
|
|
|
|
addr = *addrp;
|
|
|
|
REQUIRE(DNS_ADBADDRINFO_VALID(addr));
|
|
|
|
entry = addr->entry;
|
|
|
|
REQUIRE(DNS_ADBENTRY_VALID(entry));
|
|
|
|
|
|
|
|
isc_stdtime_get(&now);
|
|
|
|
|
|
|
|
*addrp = NULL;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2000-01-12 03:00:33 +00:00
|
|
|
bucket = addr->entry->lock_bucket;
|
|
|
|
LOCK(&adb->entrylocks[bucket]);
|
|
|
|
|
2003-07-18 04:30:01 +00:00
|
|
|
entry->expires = now + ADB_ENTRY_WINDOW;
|
2000-01-12 03:00:33 +00:00
|
|
|
|
2002-11-13 00:07:04 +00:00
|
|
|
want_check_exit = dec_entry_refcnt(adb, entry, ISC_FALSE);
|
2000-01-12 03:00:33 +00:00
|
|
|
|
|
|
|
UNLOCK(&adb->entrylocks[bucket]);
|
|
|
|
|
|
|
|
addr->entry = NULL;
|
|
|
|
free_adbaddrinfo(adb, &addr);
|
2000-01-13 20:42:43 +00:00
|
|
|
|
|
|
|
if (want_check_exit) {
|
|
|
|
LOCK(&adb->lock);
|
|
|
|
check_exit(adb);
|
|
|
|
UNLOCK(&adb->lock);
|
|
|
|
}
|
2000-01-12 03:00:33 +00:00
|
|
|
}
|
2001-04-11 20:37:50 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
dns_adb_flush(dns_adb_t *adb) {
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
INSIST(DNS_ADB_VALID(adb));
|
|
|
|
|
|
|
|
LOCK(&adb->lock);
|
|
|
|
|
2001-10-19 01:29:41 +00:00
|
|
|
for (i = 0; i < NBUCKETS; i++) {
|
2001-04-11 20:37:50 +00:00
|
|
|
/*
|
|
|
|
* Call our cleanup routines.
|
|
|
|
*/
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
|
|
|
|
INSIST(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
|
2001-04-11 20:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DUMP_ADB_AFTER_CLEANING
|
|
|
|
dump_adb(adb, stdout, ISC_TRUE);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
UNLOCK(&adb->lock);
|
|
|
|
}
|
2001-10-25 04:57:46 +00:00
|
|
|
|
2001-11-27 03:00:50 +00:00
|
|
|
void
|
|
|
|
dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
|
|
|
|
dns_adbname_t *adbname;
|
|
|
|
dns_adbname_t *nextname;
|
|
|
|
int bucket;
|
|
|
|
|
|
|
|
INSIST(DNS_ADB_VALID(adb));
|
|
|
|
|
|
|
|
LOCK(&adb->lock);
|
|
|
|
bucket = dns_name_hash(name, ISC_FALSE) % NBUCKETS;
|
|
|
|
LOCK(&adb->namelocks[bucket]);
|
|
|
|
adbname = ISC_LIST_HEAD(adb->names[bucket]);
|
|
|
|
while (adbname != NULL) {
|
|
|
|
nextname = ISC_LIST_NEXT(adbname, plink);
|
|
|
|
if (!NAME_DEAD(adbname) &&
|
|
|
|
dns_name_equal(name, &adbname->name)) {
|
2002-11-13 00:07:04 +00:00
|
|
|
INSIST(kill_name(&adbname, DNS_EVENT_ADBCANCELED)
|
|
|
|
== ISC_FALSE);
|
2001-11-27 03:00:50 +00:00
|
|
|
}
|
|
|
|
adbname = nextname;
|
|
|
|
}
|
|
|
|
UNLOCK(&adb->namelocks[bucket]);
|
|
|
|
UNLOCK(&adb->lock);
|
|
|
|
}
|
|
|
|
|
2001-10-25 04:57:46 +00:00
|
|
|
static void
|
|
|
|
water(void *arg, int mark) {
|
|
|
|
dns_adb_t *adb = arg;
|
|
|
|
isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
|
|
|
|
isc_interval_t interval;
|
|
|
|
|
|
|
|
REQUIRE(DNS_ADB_VALID(adb));
|
|
|
|
|
2002-09-10 02:01:15 +00:00
|
|
|
DP(ISC_LOG_DEBUG(1),
|
|
|
|
"adb reached %s water mark", overmem ? "high" : "low");
|
2001-10-27 00:29:35 +00:00
|
|
|
|
2001-10-25 04:57:46 +00:00
|
|
|
adb->overmem = overmem;
|
|
|
|
if (overmem) {
|
|
|
|
isc_interval_set(&interval, 0, 1);
|
|
|
|
(void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
|
|
|
|
&interval, ISC_TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_adb_setadbsize(dns_adb_t *adb, isc_uint32_t size) {
|
|
|
|
isc_uint32_t hiwater;
|
|
|
|
isc_uint32_t lowater;
|
|
|
|
|
|
|
|
INSIST(DNS_ADB_VALID(adb));
|
|
|
|
|
|
|
|
if (size != 0 && size < DNS_ADB_MINADBSIZE)
|
|
|
|
size = DNS_ADB_MINADBSIZE;
|
|
|
|
|
|
|
|
hiwater = size - (size >> 3); /* Approximately 7/8ths. */
|
|
|
|
lowater = size - (size >> 2); /* Approximately 3/4ths. */
|
|
|
|
|
|
|
|
if (size == 0 || hiwater == 0 || lowater == 0)
|
|
|
|
isc_mem_setwater(adb->mctx, water, adb, 0, 0);
|
|
|
|
else
|
|
|
|
isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);
|
|
|
|
}
|