1135446Strhodes/* 2262706Serwin * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18254897Serwin/* $Id: adb.c,v 1.264 2011/12/05 17:10:51 each Exp $ */ 19135446Strhodes 20186462Sdougb/*! \file 21135446Strhodes * 22170222Sdougb * \note 23135446Strhodes * In finds, if task == NULL, no events will be generated, and no events 24135446Strhodes * have been sent. If task != NULL but taskaction == NULL, an event has been 25135446Strhodes * posted but not yet freed. If neither are NULL, no event was posted. 26135446Strhodes * 27135446Strhodes */ 28135446Strhodes 29135446Strhodes#include <config.h> 30135446Strhodes 31135446Strhodes#include <limits.h> 32135446Strhodes 33135446Strhodes#include <isc/mutexblock.h> 34135446Strhodes#include <isc/netaddr.h> 35135446Strhodes#include <isc/random.h> 36193149Sdougb#include <isc/stats.h> 37193149Sdougb#include <isc/string.h> /* Required for HP/UX (and others?) */ 38135446Strhodes#include <isc/task.h> 39135446Strhodes#include <isc/util.h> 40135446Strhodes 41135446Strhodes#include <dns/adb.h> 42135446Strhodes#include <dns/db.h> 43135446Strhodes#include <dns/events.h> 44135446Strhodes#include <dns/log.h> 45135446Strhodes#include <dns/rdata.h> 46135446Strhodes#include <dns/rdataset.h> 47135446Strhodes#include <dns/rdatastruct.h> 48170222Sdougb#include <dns/rdatatype.h> 49135446Strhodes#include <dns/resolver.h> 50135446Strhodes#include <dns/result.h> 51193149Sdougb#include <dns/stats.h> 52135446Strhodes 53193149Sdougb#define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b') 54193149Sdougb#define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC) 55193149Sdougb#define DNS_ADBNAME_MAGIC ISC_MAGIC('a', 'd', 'b', 'N') 56193149Sdougb#define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC) 57193149Sdougb#define DNS_ADBNAMEHOOK_MAGIC ISC_MAGIC('a', 'd', 'N', 'H') 58135446Strhodes#define DNS_ADBNAMEHOOK_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC) 59193149Sdougb#define DNS_ADBLAMEINFO_MAGIC ISC_MAGIC('a', 'd', 'b', 'Z') 60170222Sdougb#define DNS_ADBLAMEINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBLAMEINFO_MAGIC) 61193149Sdougb#define DNS_ADBENTRY_MAGIC ISC_MAGIC('a', 'd', 'b', 'E') 62193149Sdougb#define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC) 63193149Sdougb#define DNS_ADBFETCH_MAGIC ISC_MAGIC('a', 'd', 'F', '4') 64193149Sdougb#define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC) 65193149Sdougb#define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6') 66193149Sdougb#define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC) 67135446Strhodes 68186462Sdougb/*! 69135446Strhodes * For type 3 negative cache entries, we will remember that the address is 70135446Strhodes * broken for this long. XXXMLG This is also used for actual addresses, too. 71135446Strhodes * The intent is to keep us from constantly asking about A/AAAA records 72135446Strhodes * if the zone has extremely low TTLs. 73135446Strhodes */ 74193149Sdougb#define ADB_CACHE_MINIMUM 10 /*%< seconds */ 75193149Sdougb#define ADB_CACHE_MAXIMUM 86400 /*%< seconds (86400 = 24 hours) */ 76193149Sdougb#define ADB_ENTRY_WINDOW 1800 /*%< seconds */ 77135446Strhodes 78170222Sdougb/*% 79193149Sdougb * The period in seconds after which an ADB name entry is regarded as stale 80193149Sdougb * and forced to be cleaned up. 81193149Sdougb * TODO: This should probably be configurable at run-time. 82135446Strhodes */ 83193149Sdougb#ifndef ADB_STALE_MARGIN 84193149Sdougb#define ADB_STALE_MARGIN 1800 85193149Sdougb#endif 86135446Strhodes 87193149Sdougb#define FREE_ITEMS 64 /*%< free count for memory pools */ 88193149Sdougb#define FILL_COUNT 16 /*%< fill count for memory pools */ 89135446Strhodes 90193149Sdougb#define DNS_ADB_INVALIDBUCKET (-1) /*%< invalid bucket address */ 91135446Strhodes 92254402Serwin#define DNS_ADB_MINADBSIZE (1024U*1024U) /*%< 1 Megabyte */ 93135446Strhodes 94135446Strhodestypedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t; 95135446Strhodestypedef struct dns_adbnamehook dns_adbnamehook_t; 96135446Strhodestypedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t; 97170222Sdougbtypedef struct dns_adblameinfo dns_adblameinfo_t; 98135446Strhodestypedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t; 99135446Strhodestypedef struct dns_adbfetch dns_adbfetch_t; 100135446Strhodestypedef struct dns_adbfetch6 dns_adbfetch6_t; 101135446Strhodes 102170222Sdougb/*% dns adb structure */ 103135446Strhodesstruct dns_adb { 104193149Sdougb unsigned int magic; 105135446Strhodes 106193149Sdougb isc_mutex_t lock; 107193149Sdougb isc_mutex_t reflock; /*%< Covers irefcnt, erefcnt */ 108186462Sdougb isc_mutex_t overmemlock; /*%< Covers overmem */ 109193149Sdougb isc_mem_t *mctx; 110193149Sdougb dns_view_t *view; 111135446Strhodes 112193149Sdougb isc_taskmgr_t *taskmgr; 113193149Sdougb isc_task_t *task; 114245163Serwin isc_task_t *excl; 115135446Strhodes 116193149Sdougb isc_interval_t tick_interval; 117193149Sdougb int next_cleanbucket; 118135446Strhodes 119193149Sdougb unsigned int irefcnt; 120193149Sdougb unsigned int erefcnt; 121135446Strhodes 122193149Sdougb isc_mutex_t mplock; 123193149Sdougb isc_mempool_t *nmp; /*%< dns_adbname_t */ 124193149Sdougb isc_mempool_t *nhmp; /*%< dns_adbnamehook_t */ 125193149Sdougb isc_mempool_t *limp; /*%< dns_adblameinfo_t */ 126193149Sdougb isc_mempool_t *emp; /*%< dns_adbentry_t */ 127193149Sdougb isc_mempool_t *ahmp; /*%< dns_adbfind_t */ 128193149Sdougb isc_mempool_t *aimp; /*%< dns_adbaddrinfo_t */ 129193149Sdougb isc_mempool_t *afmp; /*%< dns_adbfetch_t */ 130193149Sdougb 131170222Sdougb /*! 132135446Strhodes * Bucketized locks and lists for names. 133135446Strhodes * 134135446Strhodes * XXXRTH Have a per-bucket structure that contains all of these? 135135446Strhodes */ 136224092Sdougb unsigned int nnames; 137224092Sdougb isc_mutex_t namescntlock; 138224092Sdougb unsigned int namescnt; 139224092Sdougb dns_adbnamelist_t *names; 140224092Sdougb dns_adbnamelist_t *deadnames; 141224092Sdougb isc_mutex_t *namelocks; 142224092Sdougb isc_boolean_t *name_sd; 143224092Sdougb unsigned int *name_refcnt; 144135446Strhodes 145170222Sdougb /*! 146224092Sdougb * Bucketized locks and lists for entries. 147135446Strhodes * 148135446Strhodes * XXXRTH Have a per-bucket structure that contains all of these? 149135446Strhodes */ 150224092Sdougb unsigned int nentries; 151224092Sdougb isc_mutex_t entriescntlock; 152224092Sdougb unsigned int entriescnt; 153224092Sdougb dns_adbentrylist_t *entries; 154224092Sdougb dns_adbentrylist_t *deadentries; 155224092Sdougb isc_mutex_t *entrylocks; 156224092Sdougb isc_boolean_t *entry_sd; /*%< shutting down */ 157224092Sdougb unsigned int *entry_refcnt; 158135446Strhodes 159193149Sdougb isc_event_t cevent; 160193149Sdougb isc_boolean_t cevent_sent; 161193149Sdougb isc_boolean_t shutting_down; 162193149Sdougb isc_eventlist_t whenshutdown; 163224092Sdougb isc_event_t growentries; 164224092Sdougb isc_boolean_t growentries_sent; 165224092Sdougb isc_event_t grownames; 166224092Sdougb isc_boolean_t grownames_sent; 167135446Strhodes}; 168135446Strhodes 169135446Strhodes/* 170135446Strhodes * XXXMLG Document these structures. 171135446Strhodes */ 172135446Strhodes 173170222Sdougb/*% dns_adbname structure */ 174135446Strhodesstruct dns_adbname { 175193149Sdougb unsigned int magic; 176193149Sdougb dns_name_t name; 177193149Sdougb dns_adb_t *adb; 178193149Sdougb unsigned int partial_result; 179193149Sdougb unsigned int flags; 180193149Sdougb int lock_bucket; 181193149Sdougb dns_name_t target; 182193149Sdougb isc_stdtime_t expire_target; 183193149Sdougb isc_stdtime_t expire_v4; 184193149Sdougb isc_stdtime_t expire_v6; 185193149Sdougb unsigned int chains; 186193149Sdougb dns_adbnamehooklist_t v4; 187193149Sdougb dns_adbnamehooklist_t v6; 188193149Sdougb dns_adbfetch_t *fetch_a; 189193149Sdougb dns_adbfetch_t *fetch_aaaa; 190193149Sdougb unsigned int fetch_err; 191193149Sdougb unsigned int fetch6_err; 192193149Sdougb dns_adbfindlist_t finds; 193193149Sdougb /* for LRU-based management */ 194193149Sdougb isc_stdtime_t last_used; 195193149Sdougb 196193149Sdougb ISC_LINK(dns_adbname_t) plink; 197135446Strhodes}; 198135446Strhodes 199170222Sdougb/*% The adbfetch structure */ 200135446Strhodesstruct dns_adbfetch { 201193149Sdougb unsigned int magic; 202193149Sdougb dns_fetch_t *fetch; 203193149Sdougb dns_rdataset_t rdataset; 204275672Sdelphij unsigned int depth; 205135446Strhodes}; 206135446Strhodes 207170222Sdougb/*% 208135446Strhodes * This is a small widget that dangles off a dns_adbname_t. It contains a 209135446Strhodes * pointer to the address information about this host, and a link to the next 210135446Strhodes * namehook that will contain the next address this host has. 211135446Strhodes */ 212135446Strhodesstruct dns_adbnamehook { 213193149Sdougb unsigned int magic; 214193149Sdougb dns_adbentry_t *entry; 215193149Sdougb ISC_LINK(dns_adbnamehook_t) plink; 216135446Strhodes}; 217135446Strhodes 218170222Sdougb/*% 219170222Sdougb * This is a small widget that holds qname-specific information about an 220135446Strhodes * address. Currently limited to lameness, but could just as easily be 221135446Strhodes * extended to other types of information about zones. 222135446Strhodes */ 223170222Sdougbstruct dns_adblameinfo { 224193149Sdougb unsigned int magic; 225135446Strhodes 226193149Sdougb dns_name_t qname; 227193149Sdougb dns_rdatatype_t qtype; 228193149Sdougb isc_stdtime_t lame_timer; 229135446Strhodes 230193149Sdougb ISC_LINK(dns_adblameinfo_t) plink; 231135446Strhodes}; 232135446Strhodes 233170222Sdougb/*% 234135446Strhodes * An address entry. It holds quite a bit of information about addresses, 235135446Strhodes * including edns state (in "flags"), rtt, and of course the address of 236135446Strhodes * the host. 237135446Strhodes */ 238135446Strhodesstruct dns_adbentry { 239193149Sdougb unsigned int magic; 240135446Strhodes 241193149Sdougb int lock_bucket; 242193149Sdougb unsigned int refcnt; 243135446Strhodes 244193149Sdougb unsigned int flags; 245193149Sdougb unsigned int srtt; 246193149Sdougb isc_sockaddr_t sockaddr; 247135446Strhodes 248193149Sdougb isc_stdtime_t expires; 249170222Sdougb /*%< 250135446Strhodes * A nonzero 'expires' field indicates that the entry should 251135446Strhodes * persist until that time. This allows entries found 252135446Strhodes * using dns_adb_findaddrinfo() to persist for a limited time 253135446Strhodes * even though they are not necessarily associated with a 254135446Strhodes * name. 255135446Strhodes */ 256135446Strhodes 257193149Sdougb ISC_LIST(dns_adblameinfo_t) lameinfo; 258193149Sdougb ISC_LINK(dns_adbentry_t) plink; 259234010Sdougb 260135446Strhodes}; 261135446Strhodes 262135446Strhodes/* 263135446Strhodes * Internal functions (and prototypes). 264135446Strhodes */ 265135446Strhodesstatic inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *); 266135446Strhodesstatic inline void free_adbname(dns_adb_t *, dns_adbname_t **); 267135446Strhodesstatic inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *, 268135446Strhodes dns_adbentry_t *); 269135446Strhodesstatic inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **); 270170222Sdougbstatic inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *, dns_name_t *, 271170222Sdougb dns_rdatatype_t); 272170222Sdougbstatic inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **); 273135446Strhodesstatic inline dns_adbentry_t *new_adbentry(dns_adb_t *); 274135446Strhodesstatic inline void free_adbentry(dns_adb_t *, dns_adbentry_t **); 275135446Strhodesstatic inline dns_adbfind_t *new_adbfind(dns_adb_t *); 276135446Strhodesstatic inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **); 277135446Strhodesstatic inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *, 278135446Strhodes in_port_t); 279135446Strhodesstatic inline dns_adbfetch_t *new_adbfetch(dns_adb_t *); 280135446Strhodesstatic inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **); 281135446Strhodesstatic inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *, 282135446Strhodes unsigned int, int *); 283135446Strhodesstatic inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *, 284193149Sdougb isc_sockaddr_t *, int *, 285193149Sdougb isc_stdtime_t); 286143731Sdougbstatic void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t); 287135446Strhodesstatic void print_dns_name(FILE *, dns_name_t *); 288135446Strhodesstatic void print_namehook_list(FILE *, const char *legend, 289135446Strhodes dns_adbnamehooklist_t *list, 290135446Strhodes isc_boolean_t debug, 291135446Strhodes isc_stdtime_t now); 292135446Strhodesstatic void print_find_list(FILE *, dns_adbname_t *); 293135446Strhodesstatic void print_fetch_list(FILE *, dns_adbname_t *); 294135446Strhodesstatic inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *); 295135446Strhodesstatic inline void inc_adb_irefcnt(dns_adb_t *); 296135446Strhodesstatic inline void inc_adb_erefcnt(dns_adb_t *); 297135446Strhodesstatic inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *, 298135446Strhodes isc_boolean_t); 299214586Sdougbstatic inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, isc_boolean_t, 300214586Sdougb dns_adbentry_t *, isc_boolean_t); 301135446Strhodesstatic inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *); 302135446Strhodesstatic isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *); 303135446Strhodesstatic void clean_target(dns_adb_t *, dns_name_t *); 304135446Strhodesstatic void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, 305275672Sdelphij isc_uint32_t, unsigned int); 306193149Sdougbstatic isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t); 307193149Sdougbstatic isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **, 308193149Sdougb isc_stdtime_t); 309135446Strhodesstatic void cancel_fetches_at_name(dns_adbname_t *); 310135446Strhodesstatic isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t, 311135446Strhodes dns_rdatatype_t); 312135446Strhodesstatic isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t, 313275672Sdelphij unsigned int, dns_rdatatype_t); 314135446Strhodesstatic inline void check_exit(dns_adb_t *); 315135446Strhodesstatic void destroy(dns_adb_t *); 316135446Strhodesstatic isc_boolean_t shutdown_names(dns_adb_t *); 317135446Strhodesstatic isc_boolean_t shutdown_entries(dns_adb_t *); 318135446Strhodesstatic inline void link_name(dns_adb_t *, int, dns_adbname_t *); 319135446Strhodesstatic inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *); 320135446Strhodesstatic inline void link_entry(dns_adb_t *, int, dns_adbentry_t *); 321135446Strhodesstatic inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *); 322135446Strhodesstatic isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t); 323143731Sdougbstatic void water(void *, int); 324143731Sdougbstatic void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t); 325135446Strhodes 326135446Strhodes/* 327135446Strhodes * MUST NOT overlap DNS_ADBFIND_* flags! 328135446Strhodes */ 329193149Sdougb#define FIND_EVENT_SENT 0x40000000 330193149Sdougb#define FIND_EVENT_FREED 0x80000000 331193149Sdougb#define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0) 332193149Sdougb#define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0) 333135446Strhodes 334193149Sdougb#define NAME_NEEDS_POKE 0x80000000 335193149Sdougb#define NAME_IS_DEAD 0x40000000 336193149Sdougb#define NAME_HINT_OK DNS_ADBFIND_HINTOK 337193149Sdougb#define NAME_GLUE_OK DNS_ADBFIND_GLUEOK 338193149Sdougb#define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE 339193149Sdougb#define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0) 340193149Sdougb#define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0) 341193149Sdougb#define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0) 342193149Sdougb#define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0) 343135446Strhodes 344135446Strhodes/* 345193149Sdougb * Private flag(s) for entries. 346193149Sdougb * MUST NOT overlap FCTX_ADDRINFO_xxx and DNS_FETCHOPT_NOEDNS0. 347193149Sdougb */ 348193149Sdougb#define ENTRY_IS_DEAD 0x80000000 349193149Sdougb 350193149Sdougb/* 351135446Strhodes * To the name, address classes are all that really exist. If it has a 352135446Strhodes * V6 address it doesn't care if it came from a AAAA query. 353135446Strhodes */ 354193149Sdougb#define NAME_HAS_V4(n) (!ISC_LIST_EMPTY((n)->v4)) 355193149Sdougb#define NAME_HAS_V6(n) (!ISC_LIST_EMPTY((n)->v6)) 356193149Sdougb#define NAME_HAS_ADDRS(n) (NAME_HAS_V4(n) || NAME_HAS_V6(n)) 357135446Strhodes 358135446Strhodes/* 359135446Strhodes * Fetches are broken out into A and AAAA types. In some cases, 360135446Strhodes * however, it makes more sense to test for a particular class of fetches, 361135446Strhodes * like V4 or V6 above. 362135446Strhodes * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA 363135446Strhodes * are now equal to FETCH_V4 and FETCH_V6, respectively. 364135446Strhodes */ 365193149Sdougb#define NAME_FETCH_A(n) ((n)->fetch_a != NULL) 366193149Sdougb#define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL) 367193149Sdougb#define NAME_FETCH_V4(n) (NAME_FETCH_A(n)) 368193149Sdougb#define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n)) 369193149Sdougb#define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n)) 370135446Strhodes 371135446Strhodes/* 372135446Strhodes * Find options and tests to see if there are addresses on the list. 373135446Strhodes */ 374193149Sdougb#define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0) 375193149Sdougb#define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0) 376193149Sdougb#define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \ 377135446Strhodes != 0) 378193149Sdougb#define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \ 379135446Strhodes != 0) 380193149Sdougb#define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0) 381193149Sdougb#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0) 382193149Sdougb#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list)) 383193149Sdougb#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0) 384135446Strhodes 385135446Strhodes/* 386135446Strhodes * These are currently used on simple unsigned ints, so they are 387135446Strhodes * not really associated with any particular type. 388135446Strhodes */ 389193149Sdougb#define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0) 390193149Sdougb#define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0) 391135446Strhodes 392193149Sdougb#define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now)) 393135446Strhodes 394135446Strhodes/* 395135446Strhodes * Find out if the flags on a name (nf) indicate if it is a hint or 396135446Strhodes * glue, and compare this to the appropriate bits set in o, to see if 397135446Strhodes * this is ok. 398135446Strhodes */ 399135446Strhodes#define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0)) 400135446Strhodes#define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0)) 401135446Strhodes#define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o)) 402135446Strhodes#define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \ 403135446Strhodes ((o) & DNS_ADBFIND_STARTATZONE)) 404135446Strhodes 405193149Sdougb#define ENTER_LEVEL ISC_LOG_DEBUG(50) 406193149Sdougb#define EXIT_LEVEL ENTER_LEVEL 407193149Sdougb#define CLEAN_LEVEL ISC_LOG_DEBUG(100) 408193149Sdougb#define DEF_LEVEL ISC_LOG_DEBUG(5) 409193149Sdougb#define NCACHE_LEVEL ISC_LOG_DEBUG(20) 410135446Strhodes 411193149Sdougb#define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \ 412135446Strhodes (r) == DNS_R_NCACHENXRRSET) 413193149Sdougb#define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \ 414135446Strhodes (r) == DNS_R_NXRRSET) 415193149Sdougb#define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \ 416135446Strhodes (r) == DNS_R_NCACHENXDOMAIN) 417193149Sdougb#define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \ 418135446Strhodes (r) == DNS_R_NXRRSET || \ 419135446Strhodes (r) == DNS_R_HINTNXRRSET) 420135446Strhodes 421135446Strhodes/* 422135446Strhodes * Error state rankings. 423135446Strhodes */ 424135446Strhodes 425193149Sdougb#define FIND_ERR_SUCCESS 0 /* highest rank */ 426193149Sdougb#define FIND_ERR_CANCELED 1 427193149Sdougb#define FIND_ERR_FAILURE 2 428193149Sdougb#define FIND_ERR_NXDOMAIN 3 429193149Sdougb#define FIND_ERR_NXRRSET 4 430193149Sdougb#define FIND_ERR_UNEXPECTED 5 431193149Sdougb#define FIND_ERR_NOTFOUND 6 432193149Sdougb#define FIND_ERR_MAX 7 433135446Strhodes 434135446Strhodesstatic const char *errnames[] = { 435135446Strhodes "success", 436135446Strhodes "canceled", 437135446Strhodes "failure", 438135446Strhodes "nxdomain", 439135446Strhodes "nxrrset", 440135446Strhodes "unexpected", 441135446Strhodes "not_found" 442135446Strhodes}; 443135446Strhodes 444193149Sdougb#define NEWERR(old, new) (ISC_MIN((old), (new))) 445135446Strhodes 446135446Strhodesstatic isc_result_t find_err_map[FIND_ERR_MAX] = { 447135446Strhodes ISC_R_SUCCESS, 448135446Strhodes ISC_R_CANCELED, 449135446Strhodes ISC_R_FAILURE, 450135446Strhodes DNS_R_NXDOMAIN, 451135446Strhodes DNS_R_NXRRSET, 452135446Strhodes ISC_R_UNEXPECTED, 453193149Sdougb ISC_R_NOTFOUND /* not YET found */ 454135446Strhodes}; 455135446Strhodes 456135446Strhodesstatic void 457135446StrhodesDP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3); 458135446Strhodes 459135446Strhodesstatic void 460135446StrhodesDP(int level, const char *format, ...) { 461135446Strhodes va_list args; 462135446Strhodes 463135446Strhodes va_start(args, format); 464135446Strhodes isc_log_vwrite(dns_lctx, 465135446Strhodes DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB, 466135446Strhodes level, format, args); 467135446Strhodes va_end(args); 468135446Strhodes} 469135446Strhodes 470193149Sdougb/*% 471193149Sdougb * Increment resolver-related statistics counters. 472193149Sdougb */ 473193149Sdougbstatic inline void 474193149Sdougbinc_stats(dns_adb_t *adb, isc_statscounter_t counter) { 475193149Sdougb if (adb->view->resstats != NULL) 476193149Sdougb isc_stats_increment(adb->view->resstats, counter); 477193149Sdougb} 478193149Sdougb 479135446Strhodesstatic inline dns_ttl_t 480135446Strhodesttlclamp(dns_ttl_t ttl) { 481135446Strhodes if (ttl < ADB_CACHE_MINIMUM) 482135446Strhodes ttl = ADB_CACHE_MINIMUM; 483135446Strhodes if (ttl > ADB_CACHE_MAXIMUM) 484135446Strhodes ttl = ADB_CACHE_MAXIMUM; 485135446Strhodes 486135446Strhodes return (ttl); 487135446Strhodes} 488135446Strhodes 489135446Strhodes/* 490224092Sdougb * Hashing is most efficient if the number of buckets is prime. 491224092Sdougb * The sequence below is the closest previous primes to 2^n and 492224092Sdougb * 1.5 * 2^n, for values of n from 10 to 28. (The tables will 493224092Sdougb * no longer grow beyond 2^28 entries.) 494224092Sdougb */ 495224092Sdougbstatic const unsigned nbuckets[] = { 1021, 1531, 2039, 3067, 4093, 6143, 496224092Sdougb 8191, 12281, 16381, 24571, 32749, 497224092Sdougb 49193, 65521, 98299, 131071, 199603, 498224092Sdougb 262139, 393209, 524287, 768431, 1048573, 499224092Sdougb 1572853, 2097143, 3145721, 4194301, 500224092Sdougb 6291449, 8388593, 12582893, 16777213, 501224092Sdougb 25165813, 33554393, 50331599, 67108859, 502224092Sdougb 100663291, 134217689, 201326557, 503224092Sdougb 268535431, 0 }; 504224092Sdougb 505224092Sdougbstatic void 506224092Sdougbgrow_entries(isc_task_t *task, isc_event_t *ev) { 507224092Sdougb dns_adb_t *adb; 508224092Sdougb dns_adbentry_t *e; 509224092Sdougb dns_adbentrylist_t *newdeadentries = NULL; 510224092Sdougb dns_adbentrylist_t *newentries = NULL; 511224092Sdougb isc_boolean_t *newentry_sd = NULL; 512224092Sdougb isc_mutex_t *newentrylocks = NULL; 513224092Sdougb isc_result_t result; 514224092Sdougb unsigned int *newentry_refcnt = NULL; 515224092Sdougb unsigned int i, n, bucket; 516224092Sdougb 517224092Sdougb adb = ev->ev_arg; 518224092Sdougb INSIST(DNS_ADB_VALID(adb)); 519224092Sdougb 520224092Sdougb isc_event_free(&ev); 521224092Sdougb 522254402Serwin result = isc_task_beginexclusive(task); 523254402Serwin if (result != ISC_R_SUCCESS) 524254402Serwin goto check_exit; 525224092Sdougb 526224092Sdougb i = 0; 527224092Sdougb while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i]) 528224092Sdougb i++; 529224092Sdougb if (nbuckets[i] != 0) 530224092Sdougb n = nbuckets[i]; 531224092Sdougb else 532224092Sdougb goto done; 533224092Sdougb 534224092Sdougb DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n); 535224092Sdougb 536224092Sdougb /* 537224092Sdougb * Are we shutting down? 538224092Sdougb */ 539224092Sdougb for (i = 0; i < adb->nentries; i++) 540224092Sdougb if (adb->entry_sd[i]) 541224092Sdougb goto cleanup; 542224092Sdougb 543224092Sdougb /* 544224092Sdougb * Grab all the resources we need. 545224092Sdougb */ 546224092Sdougb newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n); 547224092Sdougb newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n); 548224092Sdougb newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n); 549224092Sdougb newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n); 550224092Sdougb newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n); 551224092Sdougb if (newentries == NULL || newdeadentries == NULL || 552224092Sdougb newentrylocks == NULL || newentry_sd == NULL || 553224092Sdougb newentry_refcnt == NULL) 554224092Sdougb goto cleanup; 555224092Sdougb 556224092Sdougb /* 557224092Sdougb * Initialise the new resources. 558224092Sdougb */ 559224092Sdougb result = isc_mutexblock_init(newentrylocks, n); 560224092Sdougb if (result != ISC_R_SUCCESS) 561224092Sdougb goto cleanup; 562224092Sdougb 563224092Sdougb for (i = 0; i < n; i++) { 564224092Sdougb ISC_LIST_INIT(newentries[i]); 565224092Sdougb ISC_LIST_INIT(newdeadentries[i]); 566224092Sdougb newentry_sd[i] = ISC_FALSE; 567224092Sdougb newentry_refcnt[i] = 0; 568224092Sdougb adb->irefcnt++; 569224092Sdougb } 570224092Sdougb 571224092Sdougb /* 572224092Sdougb * Move entries to new arrays. 573224092Sdougb */ 574224092Sdougb for (i = 0; i < adb->nentries; i++) { 575224092Sdougb e = ISC_LIST_HEAD(adb->entries[i]); 576224092Sdougb while (e != NULL) { 577224092Sdougb ISC_LIST_UNLINK(adb->entries[i], e, plink); 578224092Sdougb bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n; 579224092Sdougb e->lock_bucket = bucket; 580224092Sdougb ISC_LIST_APPEND(newentries[bucket], e, plink); 581224092Sdougb INSIST(adb->entry_refcnt[i] > 0); 582224092Sdougb adb->entry_refcnt[i]--; 583224092Sdougb newentry_refcnt[bucket]++; 584224092Sdougb e = ISC_LIST_HEAD(adb->entries[i]); 585224092Sdougb } 586224092Sdougb e = ISC_LIST_HEAD(adb->deadentries[i]); 587224092Sdougb while (e != NULL) { 588224092Sdougb ISC_LIST_UNLINK(adb->deadentries[i], e, plink); 589224092Sdougb bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n; 590224092Sdougb e->lock_bucket = bucket; 591224092Sdougb ISC_LIST_APPEND(newdeadentries[bucket], e, plink); 592224092Sdougb INSIST(adb->entry_refcnt[i] > 0); 593224092Sdougb adb->entry_refcnt[i]--; 594224092Sdougb newentry_refcnt[bucket]++; 595224092Sdougb e = ISC_LIST_HEAD(adb->deadentries[i]); 596224092Sdougb } 597224092Sdougb INSIST(adb->entry_refcnt[i] == 0); 598224092Sdougb adb->irefcnt--; 599224092Sdougb } 600224092Sdougb 601224092Sdougb /* 602224092Sdougb * Cleanup old resources. 603224092Sdougb */ 604224092Sdougb DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries); 605224092Sdougb isc_mem_put(adb->mctx, adb->entries, 606224092Sdougb sizeof(*adb->entries) * adb->nentries); 607224092Sdougb isc_mem_put(adb->mctx, adb->deadentries, 608224092Sdougb sizeof(*adb->deadentries) * adb->nentries); 609224092Sdougb isc_mem_put(adb->mctx, adb->entrylocks, 610224092Sdougb sizeof(*adb->entrylocks) * adb->nentries); 611224092Sdougb isc_mem_put(adb->mctx, adb->entry_sd, 612224092Sdougb sizeof(*adb->entry_sd) * adb->nentries); 613224092Sdougb isc_mem_put(adb->mctx, adb->entry_refcnt, 614224092Sdougb sizeof(*adb->entry_refcnt) * adb->nentries); 615224092Sdougb 616224092Sdougb /* 617224092Sdougb * Install new resources. 618224092Sdougb */ 619224092Sdougb adb->entries = newentries; 620224092Sdougb adb->deadentries = newdeadentries; 621224092Sdougb adb->entrylocks = newentrylocks; 622224092Sdougb adb->entry_sd = newentry_sd; 623224092Sdougb adb->entry_refcnt = newentry_refcnt; 624224092Sdougb adb->nentries = n; 625224092Sdougb 626224092Sdougb /* 627224092Sdougb * Only on success do we set adb->growentries_sent to ISC_FALSE. 628224092Sdougb * This will prevent us being continuously being called on error. 629224092Sdougb */ 630224092Sdougb adb->growentries_sent = ISC_FALSE; 631224092Sdougb goto done; 632224092Sdougb 633224092Sdougb cleanup: 634224092Sdougb if (newentries != NULL) 635224092Sdougb isc_mem_put(adb->mctx, newentries, 636224092Sdougb sizeof(*newentries) * n); 637224092Sdougb if (newdeadentries != NULL) 638224092Sdougb isc_mem_put(adb->mctx, newdeadentries, 639224092Sdougb sizeof(*newdeadentries) * n); 640224092Sdougb if (newentrylocks != NULL) 641224092Sdougb isc_mem_put(adb->mctx, newentrylocks, 642224092Sdougb sizeof(*newentrylocks) * n); 643224092Sdougb if (newentry_sd != NULL) 644224092Sdougb isc_mem_put(adb->mctx, newentry_sd, 645224092Sdougb sizeof(*newentry_sd) * n); 646224092Sdougb if (newentry_refcnt != NULL) 647224092Sdougb isc_mem_put(adb->mctx, newentry_refcnt, 648224092Sdougb sizeof(*newentry_refcnt) * n); 649224092Sdougb done: 650224092Sdougb isc_task_endexclusive(task); 651224092Sdougb 652254402Serwin check_exit: 653224092Sdougb LOCK(&adb->lock); 654224092Sdougb if (dec_adb_irefcnt(adb)) 655224092Sdougb check_exit(adb); 656224092Sdougb UNLOCK(&adb->lock); 657224092Sdougb DP(ISC_LOG_INFO, "adb: grow_entries finished"); 658224092Sdougb} 659224092Sdougb 660224092Sdougbstatic void 661224092Sdougbgrow_names(isc_task_t *task, isc_event_t *ev) { 662224092Sdougb dns_adb_t *adb; 663224092Sdougb dns_adbname_t *name; 664224092Sdougb dns_adbnamelist_t *newdeadnames = NULL; 665224092Sdougb dns_adbnamelist_t *newnames = NULL; 666224092Sdougb isc_boolean_t *newname_sd = NULL; 667224092Sdougb isc_mutex_t *newnamelocks = NULL; 668224092Sdougb isc_result_t result; 669224092Sdougb unsigned int *newname_refcnt = NULL; 670224092Sdougb unsigned int i, n, bucket; 671224092Sdougb 672224092Sdougb adb = ev->ev_arg; 673224092Sdougb INSIST(DNS_ADB_VALID(adb)); 674224092Sdougb 675224092Sdougb isc_event_free(&ev); 676224092Sdougb 677254402Serwin result = isc_task_beginexclusive(task); 678254402Serwin if (result != ISC_R_SUCCESS) 679254402Serwin goto check_exit; 680224092Sdougb 681224092Sdougb i = 0; 682224092Sdougb while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i]) 683224092Sdougb i++; 684224092Sdougb if (nbuckets[i] != 0) 685224092Sdougb n = nbuckets[i]; 686224092Sdougb else 687224092Sdougb goto done; 688224092Sdougb 689224092Sdougb DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n); 690224092Sdougb 691224092Sdougb /* 692224092Sdougb * Are we shutting down? 693224092Sdougb */ 694224092Sdougb for (i = 0; i < adb->nnames; i++) 695224092Sdougb if (adb->name_sd[i]) 696224092Sdougb goto cleanup; 697224092Sdougb 698224092Sdougb /* 699224092Sdougb * Grab all the resources we need. 700224092Sdougb */ 701224092Sdougb newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n); 702224092Sdougb newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n); 703224092Sdougb newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n); 704224092Sdougb newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n); 705224092Sdougb newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n); 706224092Sdougb if (newnames == NULL || newdeadnames == NULL || 707224092Sdougb newnamelocks == NULL || newname_sd == NULL || 708224092Sdougb newname_refcnt == NULL) 709224092Sdougb goto cleanup; 710224092Sdougb 711224092Sdougb /* 712224092Sdougb * Initialise the new resources. 713224092Sdougb */ 714224092Sdougb result = isc_mutexblock_init(newnamelocks, n); 715224092Sdougb if (result != ISC_R_SUCCESS) 716224092Sdougb goto cleanup; 717224092Sdougb 718224092Sdougb for (i = 0; i < n; i++) { 719224092Sdougb ISC_LIST_INIT(newnames[i]); 720224092Sdougb ISC_LIST_INIT(newdeadnames[i]); 721224092Sdougb newname_sd[i] = ISC_FALSE; 722224092Sdougb newname_refcnt[i] = 0; 723224092Sdougb adb->irefcnt++; 724224092Sdougb } 725224092Sdougb 726224092Sdougb /* 727224092Sdougb * Move names to new arrays. 728224092Sdougb */ 729224092Sdougb for (i = 0; i < adb->nnames; i++) { 730224092Sdougb name = ISC_LIST_HEAD(adb->names[i]); 731224092Sdougb while (name != NULL) { 732224092Sdougb ISC_LIST_UNLINK(adb->names[i], name, plink); 733224092Sdougb bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n; 734224092Sdougb name->lock_bucket = bucket; 735224092Sdougb ISC_LIST_APPEND(newnames[bucket], name, plink); 736224092Sdougb INSIST(adb->name_refcnt[i] > 0); 737224092Sdougb adb->name_refcnt[i]--; 738224092Sdougb newname_refcnt[bucket]++; 739224092Sdougb name = ISC_LIST_HEAD(adb->names[i]); 740224092Sdougb } 741224092Sdougb name = ISC_LIST_HEAD(adb->deadnames[i]); 742224092Sdougb while (name != NULL) { 743224092Sdougb ISC_LIST_UNLINK(adb->deadnames[i], name, plink); 744224092Sdougb bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n; 745224092Sdougb name->lock_bucket = bucket; 746224092Sdougb ISC_LIST_APPEND(newdeadnames[bucket], name, plink); 747224092Sdougb INSIST(adb->name_refcnt[i] > 0); 748224092Sdougb adb->name_refcnt[i]--; 749224092Sdougb newname_refcnt[bucket]++; 750224092Sdougb name = ISC_LIST_HEAD(adb->deadnames[i]); 751224092Sdougb } 752224092Sdougb INSIST(adb->name_refcnt[i] == 0); 753224092Sdougb adb->irefcnt--; 754224092Sdougb } 755224092Sdougb 756224092Sdougb /* 757224092Sdougb * Cleanup old resources. 758224092Sdougb */ 759224092Sdougb DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames); 760224092Sdougb isc_mem_put(adb->mctx, adb->names, 761224092Sdougb sizeof(*adb->names) * adb->nnames); 762224092Sdougb isc_mem_put(adb->mctx, adb->deadnames, 763224092Sdougb sizeof(*adb->deadnames) * adb->nnames); 764224092Sdougb isc_mem_put(adb->mctx, adb->namelocks, 765224092Sdougb sizeof(*adb->namelocks) * adb->nnames); 766224092Sdougb isc_mem_put(adb->mctx, adb->name_sd, 767224092Sdougb sizeof(*adb->name_sd) * adb->nnames); 768224092Sdougb isc_mem_put(adb->mctx, adb->name_refcnt, 769224092Sdougb sizeof(*adb->name_refcnt) * adb->nnames); 770224092Sdougb 771224092Sdougb /* 772224092Sdougb * Install new resources. 773224092Sdougb */ 774224092Sdougb adb->names = newnames; 775224092Sdougb adb->deadnames = newdeadnames; 776224092Sdougb adb->namelocks = newnamelocks; 777224092Sdougb adb->name_sd = newname_sd; 778224092Sdougb adb->name_refcnt = newname_refcnt; 779224092Sdougb adb->nnames = n; 780224092Sdougb 781224092Sdougb /* 782224092Sdougb * Only on success do we set adb->grownames_sent to ISC_FALSE. 783224092Sdougb * This will prevent us being continuously being called on error. 784224092Sdougb */ 785224092Sdougb adb->grownames_sent = ISC_FALSE; 786224092Sdougb goto done; 787224092Sdougb 788224092Sdougb cleanup: 789224092Sdougb if (newnames != NULL) 790224092Sdougb isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n); 791224092Sdougb if (newdeadnames != NULL) 792224092Sdougb isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n); 793224092Sdougb if (newnamelocks != NULL) 794224092Sdougb isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n); 795224092Sdougb if (newname_sd != NULL) 796224092Sdougb isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n); 797224092Sdougb if (newname_refcnt != NULL) 798224092Sdougb isc_mem_put(adb->mctx, newname_refcnt, 799224092Sdougb sizeof(*newname_refcnt) * n); 800224092Sdougb done: 801224092Sdougb isc_task_endexclusive(task); 802224092Sdougb 803254402Serwin check_exit: 804224092Sdougb LOCK(&adb->lock); 805224092Sdougb if (dec_adb_irefcnt(adb)) 806224092Sdougb check_exit(adb); 807224092Sdougb UNLOCK(&adb->lock); 808224092Sdougb DP(ISC_LOG_INFO, "adb: grow_names finished"); 809224092Sdougb} 810224092Sdougb 811224092Sdougb/* 812135446Strhodes * Requires the adbname bucket be locked and that no entry buckets be locked. 813135446Strhodes * 814135446Strhodes * This code handles A and AAAA rdatasets only. 815135446Strhodes */ 816135446Strhodesstatic isc_result_t 817135446Strhodesimport_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset, 818135446Strhodes isc_stdtime_t now) 819135446Strhodes{ 820135446Strhodes isc_result_t result; 821135446Strhodes dns_adb_t *adb; 822135446Strhodes dns_adbnamehook_t *nh; 823135446Strhodes dns_adbnamehook_t *anh; 824135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 825135446Strhodes struct in_addr ina; 826135446Strhodes struct in6_addr in6a; 827135446Strhodes isc_sockaddr_t sockaddr; 828135446Strhodes dns_adbentry_t *foundentry; /* NO CLEAN UP! */ 829135446Strhodes int addr_bucket; 830135446Strhodes isc_boolean_t new_addresses_added; 831135446Strhodes dns_rdatatype_t rdtype; 832135446Strhodes unsigned int findoptions; 833186462Sdougb dns_adbnamehooklist_t *hookhead; 834135446Strhodes 835135446Strhodes INSIST(DNS_ADBNAME_VALID(adbname)); 836135446Strhodes adb = adbname->adb; 837135446Strhodes INSIST(DNS_ADB_VALID(adb)); 838135446Strhodes 839135446Strhodes rdtype = rdataset->type; 840135446Strhodes INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa)); 841135446Strhodes if (rdtype == dns_rdatatype_a) 842135446Strhodes findoptions = DNS_ADBFIND_INET; 843135446Strhodes else 844135446Strhodes findoptions = DNS_ADBFIND_INET6; 845135446Strhodes 846135446Strhodes addr_bucket = DNS_ADB_INVALIDBUCKET; 847135446Strhodes new_addresses_added = ISC_FALSE; 848135446Strhodes 849135446Strhodes nh = NULL; 850135446Strhodes result = dns_rdataset_first(rdataset); 851135446Strhodes while (result == ISC_R_SUCCESS) { 852135446Strhodes dns_rdata_reset(&rdata); 853135446Strhodes dns_rdataset_current(rdataset, &rdata); 854135446Strhodes if (rdtype == dns_rdatatype_a) { 855135446Strhodes INSIST(rdata.length == 4); 856262706Serwin memmove(&ina.s_addr, rdata.data, 4); 857135446Strhodes isc_sockaddr_fromin(&sockaddr, &ina, 0); 858186462Sdougb hookhead = &adbname->v4; 859135446Strhodes } else { 860135446Strhodes INSIST(rdata.length == 16); 861262706Serwin memmove(in6a.s6_addr, rdata.data, 16); 862135446Strhodes isc_sockaddr_fromin6(&sockaddr, &in6a, 0); 863186462Sdougb hookhead = &adbname->v6; 864135446Strhodes } 865135446Strhodes 866135446Strhodes INSIST(nh == NULL); 867135446Strhodes nh = new_adbnamehook(adb, NULL); 868135446Strhodes if (nh == NULL) { 869135446Strhodes adbname->partial_result |= findoptions; 870135446Strhodes result = ISC_R_NOMEMORY; 871135446Strhodes goto fail; 872135446Strhodes } 873135446Strhodes 874193149Sdougb foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket, 875193149Sdougb now); 876135446Strhodes if (foundentry == NULL) { 877135446Strhodes dns_adbentry_t *entry; 878135446Strhodes 879135446Strhodes entry = new_adbentry(adb); 880135446Strhodes if (entry == NULL) { 881135446Strhodes adbname->partial_result |= findoptions; 882135446Strhodes result = ISC_R_NOMEMORY; 883135446Strhodes goto fail; 884135446Strhodes } 885135446Strhodes 886135446Strhodes entry->sockaddr = sockaddr; 887135446Strhodes entry->refcnt = 1; 888135446Strhodes 889135446Strhodes nh->entry = entry; 890135446Strhodes 891135446Strhodes link_entry(adb, addr_bucket, entry); 892135446Strhodes } else { 893186462Sdougb for (anh = ISC_LIST_HEAD(*hookhead); 894135446Strhodes anh != NULL; 895135446Strhodes anh = ISC_LIST_NEXT(anh, plink)) 896135446Strhodes if (anh->entry == foundentry) 897135446Strhodes break; 898135446Strhodes if (anh == NULL) { 899135446Strhodes foundentry->refcnt++; 900135446Strhodes nh->entry = foundentry; 901135446Strhodes } else 902135446Strhodes free_adbnamehook(adb, &nh); 903135446Strhodes } 904135446Strhodes 905135446Strhodes new_addresses_added = ISC_TRUE; 906186462Sdougb if (nh != NULL) 907186462Sdougb ISC_LIST_APPEND(*hookhead, nh, plink); 908135446Strhodes nh = NULL; 909135446Strhodes result = dns_rdataset_next(rdataset); 910135446Strhodes } 911135446Strhodes 912135446Strhodes fail: 913135446Strhodes if (nh != NULL) 914135446Strhodes free_adbnamehook(adb, &nh); 915135446Strhodes 916135446Strhodes if (addr_bucket != DNS_ADB_INVALIDBUCKET) 917135446Strhodes UNLOCK(&adb->entrylocks[addr_bucket]); 918135446Strhodes 919135446Strhodes if (rdataset->trust == dns_trust_glue || 920135446Strhodes rdataset->trust == dns_trust_additional) 921135446Strhodes rdataset->ttl = ADB_CACHE_MINIMUM; 922225361Sdougb else if (rdataset->trust == dns_trust_ultimate) 923225361Sdougb rdataset->ttl = 0; 924135446Strhodes else 925135446Strhodes rdataset->ttl = ttlclamp(rdataset->ttl); 926135446Strhodes 927135446Strhodes if (rdtype == dns_rdatatype_a) { 928135446Strhodes DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset", 929135446Strhodes adbname->expire_v4, now + rdataset->ttl); 930135446Strhodes adbname->expire_v4 = ISC_MIN(adbname->expire_v4, 931135446Strhodes now + rdataset->ttl); 932135446Strhodes } else { 933135446Strhodes DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset", 934135446Strhodes adbname->expire_v6, now + rdataset->ttl); 935135446Strhodes adbname->expire_v6 = ISC_MIN(adbname->expire_v6, 936135446Strhodes now + rdataset->ttl); 937135446Strhodes } 938135446Strhodes 939135446Strhodes if (new_addresses_added) { 940135446Strhodes /* 941135446Strhodes * Lie a little here. This is more or less so code that cares 942135446Strhodes * can find out if any new information was added or not. 943135446Strhodes */ 944135446Strhodes return (ISC_R_SUCCESS); 945135446Strhodes } 946135446Strhodes 947135446Strhodes return (result); 948135446Strhodes} 949135446Strhodes 950135446Strhodes/* 951135446Strhodes * Requires the name's bucket be locked. 952135446Strhodes */ 953135446Strhodesstatic isc_boolean_t 954135446Strhodeskill_name(dns_adbname_t **n, isc_eventtype_t ev) { 955135446Strhodes dns_adbname_t *name; 956135446Strhodes isc_boolean_t result = ISC_FALSE; 957135446Strhodes isc_boolean_t result4, result6; 958193149Sdougb int bucket; 959135446Strhodes dns_adb_t *adb; 960135446Strhodes 961135446Strhodes INSIST(n != NULL); 962135446Strhodes name = *n; 963135446Strhodes *n = NULL; 964135446Strhodes INSIST(DNS_ADBNAME_VALID(name)); 965135446Strhodes adb = name->adb; 966135446Strhodes INSIST(DNS_ADB_VALID(adb)); 967135446Strhodes 968135446Strhodes DP(DEF_LEVEL, "killing name %p", name); 969135446Strhodes 970135446Strhodes /* 971135446Strhodes * If we're dead already, just check to see if we should go 972135446Strhodes * away now or not. 973135446Strhodes */ 974135446Strhodes if (NAME_DEAD(name) && !NAME_FETCH(name)) { 975135446Strhodes result = unlink_name(adb, name); 976135446Strhodes free_adbname(adb, &name); 977135446Strhodes if (result) 978135446Strhodes result = dec_adb_irefcnt(adb); 979135446Strhodes return (result); 980135446Strhodes } 981135446Strhodes 982135446Strhodes /* 983135446Strhodes * Clean up the name's various lists. These two are destructive 984135446Strhodes * in that they will always empty the list. 985135446Strhodes */ 986275672Sdelphij clean_finds_at_name(name, ev, 0, DNS_ADBFIND_ADDRESSMASK); 987135446Strhodes result4 = clean_namehooks(adb, &name->v4); 988135446Strhodes result6 = clean_namehooks(adb, &name->v6); 989135446Strhodes clean_target(adb, &name->target); 990135446Strhodes result = ISC_TF(result4 || result6); 991135446Strhodes 992135446Strhodes /* 993135446Strhodes * If fetches are running, cancel them. If none are running, we can 994135446Strhodes * just kill the name here. 995135446Strhodes */ 996135446Strhodes if (!NAME_FETCH(name)) { 997135446Strhodes INSIST(result == ISC_FALSE); 998135446Strhodes result = unlink_name(adb, name); 999135446Strhodes free_adbname(adb, &name); 1000135446Strhodes if (result) 1001135446Strhodes result = dec_adb_irefcnt(adb); 1002135446Strhodes } else { 1003135446Strhodes cancel_fetches_at_name(name); 1004193149Sdougb if (!NAME_DEAD(name)) { 1005193149Sdougb bucket = name->lock_bucket; 1006193149Sdougb ISC_LIST_UNLINK(adb->names[bucket], name, plink); 1007193149Sdougb ISC_LIST_APPEND(adb->deadnames[bucket], name, plink); 1008193149Sdougb name->flags |= NAME_IS_DEAD; 1009193149Sdougb } 1010135446Strhodes } 1011135446Strhodes return (result); 1012135446Strhodes} 1013135446Strhodes 1014135446Strhodes/* 1015135446Strhodes * Requires the name's bucket be locked and no entry buckets be locked. 1016135446Strhodes */ 1017135446Strhodesstatic isc_boolean_t 1018193149Sdougbcheck_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) { 1019135446Strhodes dns_adb_t *adb; 1020135446Strhodes isc_boolean_t result4 = ISC_FALSE; 1021135446Strhodes isc_boolean_t result6 = ISC_FALSE; 1022135446Strhodes 1023135446Strhodes INSIST(DNS_ADBNAME_VALID(name)); 1024135446Strhodes adb = name->adb; 1025135446Strhodes INSIST(DNS_ADB_VALID(adb)); 1026135446Strhodes 1027135446Strhodes /* 1028135446Strhodes * Check to see if we need to remove the v4 addresses 1029135446Strhodes */ 1030193149Sdougb if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) { 1031135446Strhodes if (NAME_HAS_V4(name)) { 1032135446Strhodes DP(DEF_LEVEL, "expiring v4 for name %p", name); 1033135446Strhodes result4 = clean_namehooks(adb, &name->v4); 1034135446Strhodes name->partial_result &= ~DNS_ADBFIND_INET; 1035135446Strhodes } 1036135446Strhodes name->expire_v4 = INT_MAX; 1037135446Strhodes name->fetch_err = FIND_ERR_UNEXPECTED; 1038135446Strhodes } 1039135446Strhodes 1040135446Strhodes /* 1041135446Strhodes * Check to see if we need to remove the v6 addresses 1042135446Strhodes */ 1043193149Sdougb if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) { 1044135446Strhodes if (NAME_HAS_V6(name)) { 1045135446Strhodes DP(DEF_LEVEL, "expiring v6 for name %p", name); 1046135446Strhodes result6 = clean_namehooks(adb, &name->v6); 1047135446Strhodes name->partial_result &= ~DNS_ADBFIND_INET6; 1048135446Strhodes } 1049135446Strhodes name->expire_v6 = INT_MAX; 1050135446Strhodes name->fetch6_err = FIND_ERR_UNEXPECTED; 1051135446Strhodes } 1052135446Strhodes 1053135446Strhodes /* 1054135446Strhodes * Check to see if we need to remove the alias target. 1055135446Strhodes */ 1056193149Sdougb if (EXPIRE_OK(name->expire_target, now)) { 1057135446Strhodes clean_target(adb, &name->target); 1058135446Strhodes name->expire_target = INT_MAX; 1059135446Strhodes } 1060135446Strhodes return (ISC_TF(result4 || result6)); 1061135446Strhodes} 1062135446Strhodes 1063135446Strhodes/* 1064135446Strhodes * Requires the name's bucket be locked. 1065135446Strhodes */ 1066135446Strhodesstatic inline void 1067135446Strhodeslink_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) { 1068135446Strhodes INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET); 1069135446Strhodes 1070135446Strhodes ISC_LIST_PREPEND(adb->names[bucket], name, plink); 1071135446Strhodes name->lock_bucket = bucket; 1072135446Strhodes adb->name_refcnt[bucket]++; 1073135446Strhodes} 1074135446Strhodes 1075135446Strhodes/* 1076135446Strhodes * Requires the name's bucket be locked. 1077135446Strhodes */ 1078135446Strhodesstatic inline isc_boolean_t 1079135446Strhodesunlink_name(dns_adb_t *adb, dns_adbname_t *name) { 1080135446Strhodes int bucket; 1081135446Strhodes isc_boolean_t result = ISC_FALSE; 1082135446Strhodes 1083135446Strhodes bucket = name->lock_bucket; 1084135446Strhodes INSIST(bucket != DNS_ADB_INVALIDBUCKET); 1085135446Strhodes 1086193149Sdougb if (NAME_DEAD(name)) 1087193149Sdougb ISC_LIST_UNLINK(adb->deadnames[bucket], name, plink); 1088193149Sdougb else 1089193149Sdougb ISC_LIST_UNLINK(adb->names[bucket], name, plink); 1090135446Strhodes name->lock_bucket = DNS_ADB_INVALIDBUCKET; 1091135446Strhodes INSIST(adb->name_refcnt[bucket] > 0); 1092135446Strhodes adb->name_refcnt[bucket]--; 1093135446Strhodes if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0) 1094135446Strhodes result = ISC_TRUE; 1095135446Strhodes return (result); 1096135446Strhodes} 1097135446Strhodes 1098135446Strhodes/* 1099135446Strhodes * Requires the entry's bucket be locked. 1100135446Strhodes */ 1101135446Strhodesstatic inline void 1102135446Strhodeslink_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) { 1103193149Sdougb int i; 1104193149Sdougb dns_adbentry_t *e; 1105193149Sdougb 1106214586Sdougb if (isc_mem_isovermem(adb->mctx)) { 1107193149Sdougb for (i = 0; i < 2; i++) { 1108193149Sdougb e = ISC_LIST_TAIL(adb->entries[bucket]); 1109193149Sdougb if (e == NULL) 1110193149Sdougb break; 1111193149Sdougb if (e->refcnt == 0) { 1112193149Sdougb unlink_entry(adb, e); 1113193149Sdougb free_adbentry(adb, &e); 1114193149Sdougb continue; 1115193149Sdougb } 1116193149Sdougb INSIST((e->flags & ENTRY_IS_DEAD) == 0); 1117193149Sdougb e->flags |= ENTRY_IS_DEAD; 1118193149Sdougb ISC_LIST_UNLINK(adb->entries[bucket], e, plink); 1119193149Sdougb ISC_LIST_PREPEND(adb->deadentries[bucket], e, plink); 1120193149Sdougb } 1121193149Sdougb } 1122193149Sdougb 1123135446Strhodes ISC_LIST_PREPEND(adb->entries[bucket], entry, plink); 1124135446Strhodes entry->lock_bucket = bucket; 1125135446Strhodes adb->entry_refcnt[bucket]++; 1126135446Strhodes} 1127135446Strhodes 1128135446Strhodes/* 1129135446Strhodes * Requires the entry's bucket be locked. 1130135446Strhodes */ 1131135446Strhodesstatic inline isc_boolean_t 1132135446Strhodesunlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) { 1133135446Strhodes int bucket; 1134135446Strhodes isc_boolean_t result = ISC_FALSE; 1135135446Strhodes 1136135446Strhodes bucket = entry->lock_bucket; 1137135446Strhodes INSIST(bucket != DNS_ADB_INVALIDBUCKET); 1138135446Strhodes 1139193149Sdougb if ((entry->flags & ENTRY_IS_DEAD) != 0) 1140193149Sdougb ISC_LIST_UNLINK(adb->deadentries[bucket], entry, plink); 1141193149Sdougb else 1142193149Sdougb ISC_LIST_UNLINK(adb->entries[bucket], entry, plink); 1143135446Strhodes entry->lock_bucket = DNS_ADB_INVALIDBUCKET; 1144135446Strhodes INSIST(adb->entry_refcnt[bucket] > 0); 1145135446Strhodes adb->entry_refcnt[bucket]--; 1146135446Strhodes if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0) 1147135446Strhodes result = ISC_TRUE; 1148135446Strhodes return (result); 1149135446Strhodes} 1150135446Strhodes 1151135446Strhodesstatic inline void 1152135446Strhodesviolate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) { 1153135446Strhodes if (isc_mutex_trylock(want) != ISC_R_SUCCESS) { 1154135446Strhodes UNLOCK(have); 1155135446Strhodes LOCK(want); 1156135446Strhodes LOCK(have); 1157135446Strhodes } 1158135446Strhodes} 1159135446Strhodes 1160135446Strhodes/* 1161135446Strhodes * The ADB _MUST_ be locked before calling. Also, exit conditions must be 1162135446Strhodes * checked after calling this function. 1163135446Strhodes */ 1164135446Strhodesstatic isc_boolean_t 1165135446Strhodesshutdown_names(dns_adb_t *adb) { 1166224092Sdougb unsigned int bucket; 1167135446Strhodes isc_boolean_t result = ISC_FALSE; 1168135446Strhodes dns_adbname_t *name; 1169135446Strhodes dns_adbname_t *next_name; 1170135446Strhodes 1171224092Sdougb for (bucket = 0; bucket < adb->nnames; bucket++) { 1172135446Strhodes LOCK(&adb->namelocks[bucket]); 1173135446Strhodes adb->name_sd[bucket] = ISC_TRUE; 1174135446Strhodes 1175135446Strhodes name = ISC_LIST_HEAD(adb->names[bucket]); 1176135446Strhodes if (name == NULL) { 1177135446Strhodes /* 1178135446Strhodes * This bucket has no names. We must decrement the 1179135446Strhodes * irefcnt ourselves, since it will not be 1180135446Strhodes * automatically triggered by a name being unlinked. 1181135446Strhodes */ 1182135446Strhodes INSIST(result == ISC_FALSE); 1183135446Strhodes result = dec_adb_irefcnt(adb); 1184135446Strhodes } else { 1185135446Strhodes /* 1186135446Strhodes * Run through the list. For each name, clean up finds 1187135446Strhodes * found there, and cancel any fetches running. When 1188135446Strhodes * all the fetches are canceled, the name will destroy 1189135446Strhodes * itself. 1190135446Strhodes */ 1191135446Strhodes while (name != NULL) { 1192135446Strhodes next_name = ISC_LIST_NEXT(name, plink); 1193135446Strhodes INSIST(result == ISC_FALSE); 1194135446Strhodes result = kill_name(&name, 1195135446Strhodes DNS_EVENT_ADBSHUTDOWN); 1196135446Strhodes name = next_name; 1197135446Strhodes } 1198135446Strhodes } 1199135446Strhodes 1200135446Strhodes UNLOCK(&adb->namelocks[bucket]); 1201135446Strhodes } 1202135446Strhodes return (result); 1203135446Strhodes} 1204135446Strhodes 1205135446Strhodes/* 1206135446Strhodes * The ADB _MUST_ be locked before calling. Also, exit conditions must be 1207135446Strhodes * checked after calling this function. 1208135446Strhodes */ 1209135446Strhodesstatic isc_boolean_t 1210135446Strhodesshutdown_entries(dns_adb_t *adb) { 1211224092Sdougb unsigned int bucket; 1212135446Strhodes isc_boolean_t result = ISC_FALSE; 1213135446Strhodes dns_adbentry_t *entry; 1214135446Strhodes dns_adbentry_t *next_entry; 1215135446Strhodes 1216224092Sdougb for (bucket = 0; bucket < adb->nentries; bucket++) { 1217135446Strhodes LOCK(&adb->entrylocks[bucket]); 1218135446Strhodes adb->entry_sd[bucket] = ISC_TRUE; 1219135446Strhodes 1220135446Strhodes entry = ISC_LIST_HEAD(adb->entries[bucket]); 1221193149Sdougb if (adb->entry_refcnt[bucket] == 0) { 1222135446Strhodes /* 1223135446Strhodes * This bucket has no entries. We must decrement the 1224135446Strhodes * irefcnt ourselves, since it will not be 1225135446Strhodes * automatically triggered by an entry being unlinked. 1226135446Strhodes */ 1227135446Strhodes result = dec_adb_irefcnt(adb); 1228135446Strhodes } else { 1229135446Strhodes /* 1230135446Strhodes * Run through the list. Cleanup any entries not 1231135446Strhodes * associated with names, and which are not in use. 1232135446Strhodes */ 1233135446Strhodes while (entry != NULL) { 1234135446Strhodes next_entry = ISC_LIST_NEXT(entry, plink); 1235135446Strhodes if (entry->refcnt == 0 && 1236135446Strhodes entry->expires != 0) { 1237135446Strhodes result = unlink_entry(adb, entry); 1238135446Strhodes free_adbentry(adb, &entry); 1239135446Strhodes if (result) 1240135446Strhodes result = dec_adb_irefcnt(adb); 1241135446Strhodes } 1242135446Strhodes entry = next_entry; 1243135446Strhodes } 1244135446Strhodes } 1245135446Strhodes 1246135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 1247135446Strhodes } 1248135446Strhodes return (result); 1249135446Strhodes} 1250135446Strhodes 1251135446Strhodes/* 1252135446Strhodes * Name bucket must be locked 1253135446Strhodes */ 1254135446Strhodesstatic void 1255135446Strhodescancel_fetches_at_name(dns_adbname_t *name) { 1256135446Strhodes if (NAME_FETCH_A(name)) 1257135446Strhodes dns_resolver_cancelfetch(name->fetch_a->fetch); 1258135446Strhodes 1259135446Strhodes if (NAME_FETCH_AAAA(name)) 1260135446Strhodes dns_resolver_cancelfetch(name->fetch_aaaa->fetch); 1261135446Strhodes} 1262135446Strhodes 1263135446Strhodes/* 1264135446Strhodes * Assumes the name bucket is locked. 1265135446Strhodes */ 1266135446Strhodesstatic isc_boolean_t 1267135446Strhodesclean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) { 1268135446Strhodes dns_adbentry_t *entry; 1269135446Strhodes dns_adbnamehook_t *namehook; 1270135446Strhodes int addr_bucket; 1271135446Strhodes isc_boolean_t result = ISC_FALSE; 1272214586Sdougb isc_boolean_t overmem = isc_mem_isovermem(adb->mctx); 1273135446Strhodes 1274135446Strhodes addr_bucket = DNS_ADB_INVALIDBUCKET; 1275135446Strhodes namehook = ISC_LIST_HEAD(*namehooks); 1276135446Strhodes while (namehook != NULL) { 1277135446Strhodes INSIST(DNS_ADBNAMEHOOK_VALID(namehook)); 1278135446Strhodes 1279135446Strhodes /* 1280135446Strhodes * Clean up the entry if needed. 1281135446Strhodes */ 1282135446Strhodes entry = namehook->entry; 1283135446Strhodes if (entry != NULL) { 1284135446Strhodes INSIST(DNS_ADBENTRY_VALID(entry)); 1285135446Strhodes 1286135446Strhodes if (addr_bucket != entry->lock_bucket) { 1287135446Strhodes if (addr_bucket != DNS_ADB_INVALIDBUCKET) 1288135446Strhodes UNLOCK(&adb->entrylocks[addr_bucket]); 1289135446Strhodes addr_bucket = entry->lock_bucket; 1290254402Serwin INSIST(addr_bucket != DNS_ADB_INVALIDBUCKET); 1291135446Strhodes LOCK(&adb->entrylocks[addr_bucket]); 1292135446Strhodes } 1293135446Strhodes 1294214586Sdougb result = dec_entry_refcnt(adb, overmem, entry, 1295214586Sdougb ISC_FALSE); 1296135446Strhodes } 1297135446Strhodes 1298135446Strhodes /* 1299135446Strhodes * Free the namehook 1300135446Strhodes */ 1301135446Strhodes namehook->entry = NULL; 1302135446Strhodes ISC_LIST_UNLINK(*namehooks, namehook, plink); 1303135446Strhodes free_adbnamehook(adb, &namehook); 1304135446Strhodes 1305135446Strhodes namehook = ISC_LIST_HEAD(*namehooks); 1306135446Strhodes } 1307135446Strhodes 1308135446Strhodes if (addr_bucket != DNS_ADB_INVALIDBUCKET) 1309135446Strhodes UNLOCK(&adb->entrylocks[addr_bucket]); 1310135446Strhodes return (result); 1311135446Strhodes} 1312135446Strhodes 1313135446Strhodesstatic void 1314135446Strhodesclean_target(dns_adb_t *adb, dns_name_t *target) { 1315135446Strhodes if (dns_name_countlabels(target) > 0) { 1316135446Strhodes dns_name_free(target, adb->mctx); 1317135446Strhodes dns_name_init(target, NULL); 1318135446Strhodes } 1319135446Strhodes} 1320135446Strhodes 1321135446Strhodesstatic isc_result_t 1322135446Strhodesset_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname, 1323135446Strhodes dns_rdataset_t *rdataset, dns_name_t *target) 1324135446Strhodes{ 1325135446Strhodes isc_result_t result; 1326135446Strhodes dns_namereln_t namereln; 1327135446Strhodes unsigned int nlabels; 1328135446Strhodes int order; 1329135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 1330135446Strhodes dns_fixedname_t fixed1, fixed2; 1331135446Strhodes dns_name_t *prefix, *new_target; 1332135446Strhodes 1333135446Strhodes REQUIRE(dns_name_countlabels(target) == 0); 1334135446Strhodes 1335135446Strhodes if (rdataset->type == dns_rdatatype_cname) { 1336135446Strhodes dns_rdata_cname_t cname; 1337135446Strhodes 1338135446Strhodes /* 1339135446Strhodes * Copy the CNAME's target into the target name. 1340135446Strhodes */ 1341135446Strhodes result = dns_rdataset_first(rdataset); 1342135446Strhodes if (result != ISC_R_SUCCESS) 1343135446Strhodes return (result); 1344135446Strhodes dns_rdataset_current(rdataset, &rdata); 1345135446Strhodes result = dns_rdata_tostruct(&rdata, &cname, NULL); 1346135446Strhodes if (result != ISC_R_SUCCESS) 1347135446Strhodes return (result); 1348135446Strhodes result = dns_name_dup(&cname.cname, adb->mctx, target); 1349135446Strhodes dns_rdata_freestruct(&cname); 1350135446Strhodes if (result != ISC_R_SUCCESS) 1351135446Strhodes return (result); 1352135446Strhodes } else { 1353135446Strhodes dns_rdata_dname_t dname; 1354135446Strhodes 1355135446Strhodes INSIST(rdataset->type == dns_rdatatype_dname); 1356135446Strhodes namereln = dns_name_fullcompare(name, fname, &order, &nlabels); 1357135446Strhodes INSIST(namereln == dns_namereln_subdomain); 1358135446Strhodes /* 1359135446Strhodes * Get the target name of the DNAME. 1360135446Strhodes */ 1361135446Strhodes result = dns_rdataset_first(rdataset); 1362135446Strhodes if (result != ISC_R_SUCCESS) 1363135446Strhodes return (result); 1364135446Strhodes dns_rdataset_current(rdataset, &rdata); 1365135446Strhodes result = dns_rdata_tostruct(&rdata, &dname, NULL); 1366135446Strhodes if (result != ISC_R_SUCCESS) 1367135446Strhodes return (result); 1368135446Strhodes /* 1369135446Strhodes * Construct the new target name. 1370135446Strhodes */ 1371135446Strhodes dns_fixedname_init(&fixed1); 1372135446Strhodes prefix = dns_fixedname_name(&fixed1); 1373135446Strhodes dns_fixedname_init(&fixed2); 1374135446Strhodes new_target = dns_fixedname_name(&fixed2); 1375135446Strhodes dns_name_split(name, nlabels, prefix, NULL); 1376135446Strhodes result = dns_name_concatenate(prefix, &dname.dname, new_target, 1377135446Strhodes NULL); 1378135446Strhodes dns_rdata_freestruct(&dname); 1379135446Strhodes if (result != ISC_R_SUCCESS) 1380135446Strhodes return (result); 1381135446Strhodes result = dns_name_dup(new_target, adb->mctx, target); 1382135446Strhodes if (result != ISC_R_SUCCESS) 1383135446Strhodes return (result); 1384135446Strhodes } 1385135446Strhodes 1386135446Strhodes return (ISC_R_SUCCESS); 1387135446Strhodes} 1388135446Strhodes 1389135446Strhodes/* 1390135446Strhodes * Assumes nothing is locked, since this is called by the client. 1391135446Strhodes */ 1392135446Strhodesstatic void 1393135446Strhodesevent_free(isc_event_t *event) { 1394135446Strhodes dns_adbfind_t *find; 1395135446Strhodes 1396135446Strhodes INSIST(event != NULL); 1397135446Strhodes find = event->ev_destroy_arg; 1398135446Strhodes INSIST(DNS_ADBFIND_VALID(find)); 1399135446Strhodes 1400135446Strhodes LOCK(&find->lock); 1401135446Strhodes find->flags |= FIND_EVENT_FREED; 1402135446Strhodes event->ev_destroy_arg = NULL; 1403135446Strhodes UNLOCK(&find->lock); 1404135446Strhodes} 1405135446Strhodes 1406135446Strhodes/* 1407135446Strhodes * Assumes the name bucket is locked. 1408135446Strhodes */ 1409135446Strhodesstatic void 1410135446Strhodesclean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype, 1411275672Sdelphij isc_uint32_t qtotal, unsigned int addrs) 1412135446Strhodes{ 1413135446Strhodes isc_event_t *ev; 1414135446Strhodes isc_task_t *task; 1415135446Strhodes dns_adbfind_t *find; 1416135446Strhodes dns_adbfind_t *next_find; 1417135446Strhodes isc_boolean_t process; 1418135446Strhodes unsigned int wanted, notify; 1419135446Strhodes 1420135446Strhodes DP(ENTER_LEVEL, 1421135446Strhodes "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x", 1422135446Strhodes name, evtype, addrs); 1423135446Strhodes 1424135446Strhodes find = ISC_LIST_HEAD(name->finds); 1425135446Strhodes while (find != NULL) { 1426135446Strhodes LOCK(&find->lock); 1427135446Strhodes next_find = ISC_LIST_NEXT(find, plink); 1428135446Strhodes 1429135446Strhodes process = ISC_FALSE; 1430135446Strhodes wanted = find->flags & DNS_ADBFIND_ADDRESSMASK; 1431135446Strhodes notify = wanted & addrs; 1432135446Strhodes 1433135446Strhodes switch (evtype) { 1434135446Strhodes case DNS_EVENT_ADBMOREADDRESSES: 1435135446Strhodes DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES"); 1436135446Strhodes if ((notify) != 0) { 1437135446Strhodes find->flags &= ~addrs; 1438135446Strhodes process = ISC_TRUE; 1439135446Strhodes } 1440135446Strhodes break; 1441135446Strhodes case DNS_EVENT_ADBNOMOREADDRESSES: 1442135446Strhodes DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES"); 1443135446Strhodes find->flags &= ~addrs; 1444135446Strhodes wanted = find->flags & DNS_ADBFIND_ADDRESSMASK; 1445135446Strhodes if (wanted == 0) 1446135446Strhodes process = ISC_TRUE; 1447135446Strhodes break; 1448135446Strhodes default: 1449135446Strhodes find->flags &= ~addrs; 1450135446Strhodes process = ISC_TRUE; 1451135446Strhodes } 1452135446Strhodes 1453135446Strhodes if (process) { 1454135446Strhodes DP(DEF_LEVEL, "cfan: processing find %p", find); 1455135446Strhodes /* 1456135446Strhodes * Unlink the find from the name, letting the caller 1457135446Strhodes * call dns_adb_destroyfind() on it to clean it up 1458135446Strhodes * later. 1459135446Strhodes */ 1460135446Strhodes ISC_LIST_UNLINK(name->finds, find, plink); 1461135446Strhodes find->adbname = NULL; 1462135446Strhodes find->name_bucket = DNS_ADB_INVALIDBUCKET; 1463135446Strhodes 1464135446Strhodes INSIST(!FIND_EVENTSENT(find)); 1465135446Strhodes 1466135446Strhodes ev = &find->event; 1467135446Strhodes task = ev->ev_sender; 1468135446Strhodes ev->ev_sender = find; 1469135446Strhodes find->result_v4 = find_err_map[name->fetch_err]; 1470135446Strhodes find->result_v6 = find_err_map[name->fetch6_err]; 1471275672Sdelphij find->qtotal += qtotal; 1472135446Strhodes ev->ev_type = evtype; 1473135446Strhodes ev->ev_destroy = event_free; 1474135446Strhodes ev->ev_destroy_arg = find; 1475135446Strhodes 1476135446Strhodes DP(DEF_LEVEL, 1477135446Strhodes "sending event %p to task %p for find %p", 1478135446Strhodes ev, task, find); 1479135446Strhodes 1480135446Strhodes isc_task_sendanddetach(&task, (isc_event_t **)&ev); 1481135446Strhodes } else { 1482135446Strhodes DP(DEF_LEVEL, "cfan: skipping find %p", find); 1483135446Strhodes } 1484135446Strhodes 1485135446Strhodes UNLOCK(&find->lock); 1486135446Strhodes find = next_find; 1487135446Strhodes } 1488135446Strhodes 1489135446Strhodes DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name); 1490135446Strhodes} 1491135446Strhodes 1492135446Strhodesstatic inline void 1493135446Strhodescheck_exit(dns_adb_t *adb) { 1494135446Strhodes isc_event_t *event; 1495135446Strhodes /* 1496135446Strhodes * The caller must be holding the adb lock. 1497135446Strhodes */ 1498135446Strhodes if (adb->shutting_down) { 1499135446Strhodes /* 1500135446Strhodes * If there aren't any external references either, we're 1501135446Strhodes * done. Send the control event to initiate shutdown. 1502135446Strhodes */ 1503193149Sdougb INSIST(!adb->cevent_sent); /* Sanity check. */ 1504135446Strhodes event = &adb->cevent; 1505135446Strhodes isc_task_send(adb->task, &event); 1506135446Strhodes adb->cevent_sent = ISC_TRUE; 1507135446Strhodes } 1508135446Strhodes} 1509135446Strhodes 1510135446Strhodesstatic inline isc_boolean_t 1511135446Strhodesdec_adb_irefcnt(dns_adb_t *adb) { 1512135446Strhodes isc_event_t *event; 1513135446Strhodes isc_task_t *etask; 1514135446Strhodes isc_boolean_t result = ISC_FALSE; 1515135446Strhodes 1516135446Strhodes LOCK(&adb->reflock); 1517135446Strhodes 1518135446Strhodes INSIST(adb->irefcnt > 0); 1519135446Strhodes adb->irefcnt--; 1520135446Strhodes 1521135446Strhodes if (adb->irefcnt == 0) { 1522135446Strhodes event = ISC_LIST_HEAD(adb->whenshutdown); 1523135446Strhodes while (event != NULL) { 1524135446Strhodes ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link); 1525135446Strhodes etask = event->ev_sender; 1526135446Strhodes event->ev_sender = adb; 1527135446Strhodes isc_task_sendanddetach(&etask, &event); 1528135446Strhodes event = ISC_LIST_HEAD(adb->whenshutdown); 1529135446Strhodes } 1530135446Strhodes } 1531135446Strhodes 1532135446Strhodes if (adb->irefcnt == 0 && adb->erefcnt == 0) 1533135446Strhodes result = ISC_TRUE; 1534135446Strhodes UNLOCK(&adb->reflock); 1535135446Strhodes return (result); 1536135446Strhodes} 1537135446Strhodes 1538135446Strhodesstatic inline void 1539135446Strhodesinc_adb_irefcnt(dns_adb_t *adb) { 1540135446Strhodes LOCK(&adb->reflock); 1541135446Strhodes adb->irefcnt++; 1542135446Strhodes UNLOCK(&adb->reflock); 1543135446Strhodes} 1544135446Strhodes 1545135446Strhodesstatic inline void 1546135446Strhodesinc_adb_erefcnt(dns_adb_t *adb) { 1547135446Strhodes LOCK(&adb->reflock); 1548135446Strhodes adb->erefcnt++; 1549135446Strhodes UNLOCK(&adb->reflock); 1550135446Strhodes} 1551135446Strhodes 1552135446Strhodesstatic inline void 1553135446Strhodesinc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) { 1554135446Strhodes int bucket; 1555135446Strhodes 1556135446Strhodes bucket = entry->lock_bucket; 1557135446Strhodes 1558135446Strhodes if (lock) 1559135446Strhodes LOCK(&adb->entrylocks[bucket]); 1560135446Strhodes 1561135446Strhodes entry->refcnt++; 1562135446Strhodes 1563135446Strhodes if (lock) 1564135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 1565135446Strhodes} 1566135446Strhodes 1567135446Strhodesstatic inline isc_boolean_t 1568214586Sdougbdec_entry_refcnt(dns_adb_t *adb, isc_boolean_t overmem, dns_adbentry_t *entry, 1569214586Sdougb isc_boolean_t lock) 1570214586Sdougb{ 1571135446Strhodes int bucket; 1572135446Strhodes isc_boolean_t destroy_entry; 1573135446Strhodes isc_boolean_t result = ISC_FALSE; 1574135446Strhodes 1575135446Strhodes bucket = entry->lock_bucket; 1576135446Strhodes 1577135446Strhodes if (lock) 1578135446Strhodes LOCK(&adb->entrylocks[bucket]); 1579135446Strhodes 1580135446Strhodes INSIST(entry->refcnt > 0); 1581135446Strhodes entry->refcnt--; 1582135446Strhodes 1583135446Strhodes destroy_entry = ISC_FALSE; 1584135446Strhodes if (entry->refcnt == 0 && 1585214586Sdougb (adb->entry_sd[bucket] || entry->expires == 0 || overmem || 1586193149Sdougb (entry->flags & ENTRY_IS_DEAD) != 0)) { 1587135446Strhodes destroy_entry = ISC_TRUE; 1588135446Strhodes result = unlink_entry(adb, entry); 1589135446Strhodes } 1590135446Strhodes 1591135446Strhodes if (lock) 1592135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 1593135446Strhodes 1594135446Strhodes if (!destroy_entry) 1595135446Strhodes return (result); 1596135446Strhodes 1597135446Strhodes entry->lock_bucket = DNS_ADB_INVALIDBUCKET; 1598135446Strhodes 1599135446Strhodes free_adbentry(adb, &entry); 1600135446Strhodes if (result) 1601193149Sdougb result = dec_adb_irefcnt(adb); 1602135446Strhodes 1603135446Strhodes return (result); 1604135446Strhodes} 1605135446Strhodes 1606135446Strhodesstatic inline dns_adbname_t * 1607135446Strhodesnew_adbname(dns_adb_t *adb, dns_name_t *dnsname) { 1608135446Strhodes dns_adbname_t *name; 1609135446Strhodes 1610135446Strhodes name = isc_mempool_get(adb->nmp); 1611135446Strhodes if (name == NULL) 1612135446Strhodes return (NULL); 1613135446Strhodes 1614135446Strhodes dns_name_init(&name->name, NULL); 1615135446Strhodes if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) { 1616135446Strhodes isc_mempool_put(adb->nmp, name); 1617135446Strhodes return (NULL); 1618135446Strhodes } 1619135446Strhodes dns_name_init(&name->target, NULL); 1620135446Strhodes name->magic = DNS_ADBNAME_MAGIC; 1621135446Strhodes name->adb = adb; 1622135446Strhodes name->partial_result = 0; 1623135446Strhodes name->flags = 0; 1624135446Strhodes name->expire_v4 = INT_MAX; 1625135446Strhodes name->expire_v6 = INT_MAX; 1626135446Strhodes name->expire_target = INT_MAX; 1627135446Strhodes name->chains = 0; 1628135446Strhodes name->lock_bucket = DNS_ADB_INVALIDBUCKET; 1629135446Strhodes ISC_LIST_INIT(name->v4); 1630135446Strhodes ISC_LIST_INIT(name->v6); 1631135446Strhodes name->fetch_a = NULL; 1632135446Strhodes name->fetch_aaaa = NULL; 1633135446Strhodes name->fetch_err = FIND_ERR_UNEXPECTED; 1634135446Strhodes name->fetch6_err = FIND_ERR_UNEXPECTED; 1635135446Strhodes ISC_LIST_INIT(name->finds); 1636135446Strhodes ISC_LINK_INIT(name, plink); 1637135446Strhodes 1638224092Sdougb LOCK(&adb->namescntlock); 1639224092Sdougb adb->namescnt++; 1640245163Serwin if (!adb->grownames_sent && adb->excl != NULL && 1641245163Serwin adb->namescnt > (adb->nnames * 8)) 1642245163Serwin { 1643224092Sdougb isc_event_t *event = &adb->grownames; 1644224092Sdougb inc_adb_irefcnt(adb); 1645245163Serwin isc_task_send(adb->excl, &event); 1646224092Sdougb adb->grownames_sent = ISC_TRUE; 1647224092Sdougb } 1648224092Sdougb UNLOCK(&adb->namescntlock); 1649224092Sdougb 1650135446Strhodes return (name); 1651135446Strhodes} 1652135446Strhodes 1653135446Strhodesstatic inline void 1654135446Strhodesfree_adbname(dns_adb_t *adb, dns_adbname_t **name) { 1655135446Strhodes dns_adbname_t *n; 1656135446Strhodes 1657135446Strhodes INSIST(name != NULL && DNS_ADBNAME_VALID(*name)); 1658135446Strhodes n = *name; 1659135446Strhodes *name = NULL; 1660135446Strhodes 1661135446Strhodes INSIST(!NAME_HAS_V4(n)); 1662135446Strhodes INSIST(!NAME_HAS_V6(n)); 1663135446Strhodes INSIST(!NAME_FETCH(n)); 1664135446Strhodes INSIST(ISC_LIST_EMPTY(n->finds)); 1665135446Strhodes INSIST(!ISC_LINK_LINKED(n, plink)); 1666135446Strhodes INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET); 1667135446Strhodes INSIST(n->adb == adb); 1668135446Strhodes 1669135446Strhodes n->magic = 0; 1670135446Strhodes dns_name_free(&n->name, adb->mctx); 1671135446Strhodes 1672135446Strhodes isc_mempool_put(adb->nmp, n); 1673224092Sdougb LOCK(&adb->namescntlock); 1674224092Sdougb adb->namescnt--; 1675224092Sdougb UNLOCK(&adb->namescntlock); 1676135446Strhodes} 1677135446Strhodes 1678135446Strhodesstatic inline dns_adbnamehook_t * 1679135446Strhodesnew_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) { 1680135446Strhodes dns_adbnamehook_t *nh; 1681135446Strhodes 1682135446Strhodes nh = isc_mempool_get(adb->nhmp); 1683135446Strhodes if (nh == NULL) 1684135446Strhodes return (NULL); 1685135446Strhodes 1686135446Strhodes nh->magic = DNS_ADBNAMEHOOK_MAGIC; 1687135446Strhodes nh->entry = entry; 1688135446Strhodes ISC_LINK_INIT(nh, plink); 1689135446Strhodes 1690135446Strhodes return (nh); 1691135446Strhodes} 1692135446Strhodes 1693135446Strhodesstatic inline void 1694135446Strhodesfree_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) { 1695135446Strhodes dns_adbnamehook_t *nh; 1696135446Strhodes 1697135446Strhodes INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook)); 1698135446Strhodes nh = *namehook; 1699135446Strhodes *namehook = NULL; 1700135446Strhodes 1701135446Strhodes INSIST(nh->entry == NULL); 1702135446Strhodes INSIST(!ISC_LINK_LINKED(nh, plink)); 1703135446Strhodes 1704135446Strhodes nh->magic = 0; 1705135446Strhodes isc_mempool_put(adb->nhmp, nh); 1706135446Strhodes} 1707135446Strhodes 1708170222Sdougbstatic inline dns_adblameinfo_t * 1709170222Sdougbnew_adblameinfo(dns_adb_t *adb, dns_name_t *qname, dns_rdatatype_t qtype) { 1710170222Sdougb dns_adblameinfo_t *li; 1711135446Strhodes 1712170222Sdougb li = isc_mempool_get(adb->limp); 1713170222Sdougb if (li == NULL) 1714135446Strhodes return (NULL); 1715135446Strhodes 1716170222Sdougb dns_name_init(&li->qname, NULL); 1717170222Sdougb if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) { 1718170222Sdougb isc_mempool_put(adb->limp, li); 1719135446Strhodes return (NULL); 1720135446Strhodes } 1721170222Sdougb li->magic = DNS_ADBLAMEINFO_MAGIC; 1722170222Sdougb li->lame_timer = 0; 1723170222Sdougb li->qtype = qtype; 1724170222Sdougb ISC_LINK_INIT(li, plink); 1725135446Strhodes 1726170222Sdougb return (li); 1727135446Strhodes} 1728135446Strhodes 1729135446Strhodesstatic inline void 1730170222Sdougbfree_adblameinfo(dns_adb_t *adb, dns_adblameinfo_t **lameinfo) { 1731170222Sdougb dns_adblameinfo_t *li; 1732135446Strhodes 1733170222Sdougb INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo)); 1734170222Sdougb li = *lameinfo; 1735170222Sdougb *lameinfo = NULL; 1736135446Strhodes 1737170222Sdougb INSIST(!ISC_LINK_LINKED(li, plink)); 1738135446Strhodes 1739170222Sdougb dns_name_free(&li->qname, adb->mctx); 1740135446Strhodes 1741170222Sdougb li->magic = 0; 1742135446Strhodes 1743170222Sdougb isc_mempool_put(adb->limp, li); 1744135446Strhodes} 1745135446Strhodes 1746135446Strhodesstatic inline dns_adbentry_t * 1747135446Strhodesnew_adbentry(dns_adb_t *adb) { 1748135446Strhodes dns_adbentry_t *e; 1749135446Strhodes isc_uint32_t r; 1750135446Strhodes 1751135446Strhodes e = isc_mempool_get(adb->emp); 1752135446Strhodes if (e == NULL) 1753135446Strhodes return (NULL); 1754135446Strhodes 1755135446Strhodes e->magic = DNS_ADBENTRY_MAGIC; 1756135446Strhodes e->lock_bucket = DNS_ADB_INVALIDBUCKET; 1757135446Strhodes e->refcnt = 0; 1758135446Strhodes e->flags = 0; 1759135446Strhodes isc_random_get(&r); 1760135446Strhodes e->srtt = (r & 0x1f) + 1; 1761135446Strhodes e->expires = 0; 1762170222Sdougb ISC_LIST_INIT(e->lameinfo); 1763135446Strhodes ISC_LINK_INIT(e, plink); 1764224092Sdougb LOCK(&adb->entriescntlock); 1765224092Sdougb adb->entriescnt++; 1766245163Serwin if (!adb->growentries_sent && adb->growentries_sent && 1767245163Serwin adb->entriescnt > (adb->nentries * 8)) 1768245163Serwin { 1769224092Sdougb isc_event_t *event = &adb->growentries; 1770224092Sdougb inc_adb_irefcnt(adb); 1771224092Sdougb isc_task_send(adb->task, &event); 1772224092Sdougb adb->growentries_sent = ISC_TRUE; 1773224092Sdougb } 1774224092Sdougb UNLOCK(&adb->entriescntlock); 1775135446Strhodes 1776135446Strhodes return (e); 1777135446Strhodes} 1778135446Strhodes 1779135446Strhodesstatic inline void 1780135446Strhodesfree_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) { 1781135446Strhodes dns_adbentry_t *e; 1782170222Sdougb dns_adblameinfo_t *li; 1783135446Strhodes 1784135446Strhodes INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry)); 1785135446Strhodes e = *entry; 1786135446Strhodes *entry = NULL; 1787135446Strhodes 1788135446Strhodes INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET); 1789135446Strhodes INSIST(e->refcnt == 0); 1790135446Strhodes INSIST(!ISC_LINK_LINKED(e, plink)); 1791135446Strhodes 1792135446Strhodes e->magic = 0; 1793135446Strhodes 1794170222Sdougb li = ISC_LIST_HEAD(e->lameinfo); 1795170222Sdougb while (li != NULL) { 1796170222Sdougb ISC_LIST_UNLINK(e->lameinfo, li, plink); 1797170222Sdougb free_adblameinfo(adb, &li); 1798170222Sdougb li = ISC_LIST_HEAD(e->lameinfo); 1799135446Strhodes } 1800135446Strhodes 1801135446Strhodes isc_mempool_put(adb->emp, e); 1802224092Sdougb LOCK(&adb->entriescntlock); 1803224092Sdougb adb->entriescnt--; 1804224092Sdougb UNLOCK(&adb->entriescntlock); 1805135446Strhodes} 1806135446Strhodes 1807135446Strhodesstatic inline dns_adbfind_t * 1808135446Strhodesnew_adbfind(dns_adb_t *adb) { 1809135446Strhodes dns_adbfind_t *h; 1810135446Strhodes isc_result_t result; 1811135446Strhodes 1812135446Strhodes h = isc_mempool_get(adb->ahmp); 1813135446Strhodes if (h == NULL) 1814135446Strhodes return (NULL); 1815135446Strhodes 1816135446Strhodes /* 1817135446Strhodes * Public members. 1818135446Strhodes */ 1819135446Strhodes h->magic = 0; 1820135446Strhodes h->adb = adb; 1821135446Strhodes h->partial_result = 0; 1822135446Strhodes h->options = 0; 1823135446Strhodes h->flags = 0; 1824135446Strhodes h->result_v4 = ISC_R_UNEXPECTED; 1825135446Strhodes h->result_v6 = ISC_R_UNEXPECTED; 1826275672Sdelphij h->qtotal = 0; 1827135446Strhodes ISC_LINK_INIT(h, publink); 1828135446Strhodes ISC_LINK_INIT(h, plink); 1829135446Strhodes ISC_LIST_INIT(h->list); 1830135446Strhodes h->adbname = NULL; 1831135446Strhodes h->name_bucket = DNS_ADB_INVALIDBUCKET; 1832135446Strhodes 1833135446Strhodes /* 1834135446Strhodes * private members 1835135446Strhodes */ 1836135446Strhodes result = isc_mutex_init(&h->lock); 1837135446Strhodes if (result != ISC_R_SUCCESS) { 1838135446Strhodes isc_mempool_put(adb->ahmp, h); 1839135446Strhodes return (NULL); 1840135446Strhodes } 1841135446Strhodes 1842135446Strhodes ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL, 1843135446Strhodes NULL, NULL, h); 1844135446Strhodes 1845135446Strhodes inc_adb_irefcnt(adb); 1846135446Strhodes h->magic = DNS_ADBFIND_MAGIC; 1847135446Strhodes return (h); 1848135446Strhodes} 1849135446Strhodes 1850135446Strhodesstatic inline dns_adbfetch_t * 1851135446Strhodesnew_adbfetch(dns_adb_t *adb) { 1852135446Strhodes dns_adbfetch_t *f; 1853135446Strhodes 1854135446Strhodes f = isc_mempool_get(adb->afmp); 1855135446Strhodes if (f == NULL) 1856135446Strhodes return (NULL); 1857135446Strhodes 1858135446Strhodes f->magic = 0; 1859135446Strhodes f->fetch = NULL; 1860135446Strhodes 1861135446Strhodes dns_rdataset_init(&f->rdataset); 1862135446Strhodes 1863135446Strhodes f->magic = DNS_ADBFETCH_MAGIC; 1864135446Strhodes 1865135446Strhodes return (f); 1866135446Strhodes} 1867135446Strhodes 1868135446Strhodesstatic inline void 1869135446Strhodesfree_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) { 1870135446Strhodes dns_adbfetch_t *f; 1871135446Strhodes 1872135446Strhodes INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch)); 1873135446Strhodes f = *fetch; 1874135446Strhodes *fetch = NULL; 1875135446Strhodes 1876135446Strhodes f->magic = 0; 1877135446Strhodes 1878135446Strhodes if (dns_rdataset_isassociated(&f->rdataset)) 1879135446Strhodes dns_rdataset_disassociate(&f->rdataset); 1880135446Strhodes 1881135446Strhodes isc_mempool_put(adb->afmp, f); 1882135446Strhodes} 1883135446Strhodes 1884135446Strhodesstatic inline isc_boolean_t 1885135446Strhodesfree_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) { 1886135446Strhodes dns_adbfind_t *find; 1887135446Strhodes 1888135446Strhodes INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp)); 1889135446Strhodes find = *findp; 1890135446Strhodes *findp = NULL; 1891135446Strhodes 1892135446Strhodes INSIST(!FIND_HAS_ADDRS(find)); 1893135446Strhodes INSIST(!ISC_LINK_LINKED(find, publink)); 1894135446Strhodes INSIST(!ISC_LINK_LINKED(find, plink)); 1895135446Strhodes INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET); 1896135446Strhodes INSIST(find->adbname == NULL); 1897135446Strhodes 1898135446Strhodes find->magic = 0; 1899135446Strhodes 1900135446Strhodes DESTROYLOCK(&find->lock); 1901135446Strhodes isc_mempool_put(adb->ahmp, find); 1902135446Strhodes return (dec_adb_irefcnt(adb)); 1903135446Strhodes} 1904135446Strhodes 1905135446Strhodes/* 1906135446Strhodes * Copy bits from the entry into the newly allocated addrinfo. The entry 1907135446Strhodes * must be locked, and the reference count must be bumped up by one 1908135446Strhodes * if this function returns a valid pointer. 1909135446Strhodes */ 1910135446Strhodesstatic inline dns_adbaddrinfo_t * 1911135446Strhodesnew_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) { 1912135446Strhodes dns_adbaddrinfo_t *ai; 1913135446Strhodes 1914135446Strhodes ai = isc_mempool_get(adb->aimp); 1915135446Strhodes if (ai == NULL) 1916135446Strhodes return (NULL); 1917135446Strhodes 1918135446Strhodes ai->magic = DNS_ADBADDRINFO_MAGIC; 1919135446Strhodes ai->sockaddr = entry->sockaddr; 1920135446Strhodes isc_sockaddr_setport(&ai->sockaddr, port); 1921135446Strhodes ai->srtt = entry->srtt; 1922135446Strhodes ai->flags = entry->flags; 1923135446Strhodes ai->entry = entry; 1924135446Strhodes ISC_LINK_INIT(ai, publink); 1925135446Strhodes 1926135446Strhodes return (ai); 1927135446Strhodes} 1928135446Strhodes 1929135446Strhodesstatic inline void 1930135446Strhodesfree_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) { 1931135446Strhodes dns_adbaddrinfo_t *ai; 1932135446Strhodes 1933135446Strhodes INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo)); 1934135446Strhodes ai = *ainfo; 1935135446Strhodes *ainfo = NULL; 1936135446Strhodes 1937135446Strhodes INSIST(ai->entry == NULL); 1938135446Strhodes INSIST(!ISC_LINK_LINKED(ai, publink)); 1939135446Strhodes 1940135446Strhodes ai->magic = 0; 1941135446Strhodes 1942135446Strhodes isc_mempool_put(adb->aimp, ai); 1943135446Strhodes} 1944135446Strhodes 1945135446Strhodes/* 1946135446Strhodes * Search for the name. NOTE: The bucket is kept locked on both 1947135446Strhodes * success and failure, so it must always be unlocked by the caller! 1948135446Strhodes * 1949135446Strhodes * On the first call to this function, *bucketp must be set to 1950135446Strhodes * DNS_ADB_INVALIDBUCKET. 1951135446Strhodes */ 1952135446Strhodesstatic inline dns_adbname_t * 1953135446Strhodesfind_name_and_lock(dns_adb_t *adb, dns_name_t *name, 1954135446Strhodes unsigned int options, int *bucketp) 1955135446Strhodes{ 1956135446Strhodes dns_adbname_t *adbname; 1957135446Strhodes int bucket; 1958135446Strhodes 1959224092Sdougb bucket = dns_name_fullhash(name, ISC_FALSE) % adb->nnames; 1960135446Strhodes 1961135446Strhodes if (*bucketp == DNS_ADB_INVALIDBUCKET) { 1962135446Strhodes LOCK(&adb->namelocks[bucket]); 1963135446Strhodes *bucketp = bucket; 1964135446Strhodes } else if (*bucketp != bucket) { 1965135446Strhodes UNLOCK(&adb->namelocks[*bucketp]); 1966135446Strhodes LOCK(&adb->namelocks[bucket]); 1967135446Strhodes *bucketp = bucket; 1968135446Strhodes } 1969135446Strhodes 1970135446Strhodes adbname = ISC_LIST_HEAD(adb->names[bucket]); 1971135446Strhodes while (adbname != NULL) { 1972135446Strhodes if (!NAME_DEAD(adbname)) { 1973135446Strhodes if (dns_name_equal(name, &adbname->name) 1974135446Strhodes && GLUEHINT_OK(adbname, options) 1975135446Strhodes && STARTATZONE_MATCHES(adbname, options)) 1976135446Strhodes return (adbname); 1977135446Strhodes } 1978135446Strhodes adbname = ISC_LIST_NEXT(adbname, plink); 1979135446Strhodes } 1980135446Strhodes 1981135446Strhodes return (NULL); 1982135446Strhodes} 1983135446Strhodes 1984135446Strhodes/* 1985135446Strhodes * Search for the address. NOTE: The bucket is kept locked on both 1986135446Strhodes * success and failure, so it must always be unlocked by the caller. 1987135446Strhodes * 1988135446Strhodes * On the first call to this function, *bucketp must be set to 1989135446Strhodes * DNS_ADB_INVALIDBUCKET. This will cause a lock to occur. On 1990135446Strhodes * later calls (within the same "lock path") it can be left alone, so 1991135446Strhodes * if this function is called multiple times locking is only done if 1992135446Strhodes * the bucket changes. 1993135446Strhodes */ 1994135446Strhodesstatic inline dns_adbentry_t * 1995193149Sdougbfind_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp, 1996193149Sdougb isc_stdtime_t now) 1997193149Sdougb{ 1998193149Sdougb dns_adbentry_t *entry, *entry_next; 1999135446Strhodes int bucket; 2000135446Strhodes 2001224092Sdougb bucket = isc_sockaddr_hash(addr, ISC_TRUE) % adb->nentries; 2002135446Strhodes 2003135446Strhodes if (*bucketp == DNS_ADB_INVALIDBUCKET) { 2004135446Strhodes LOCK(&adb->entrylocks[bucket]); 2005135446Strhodes *bucketp = bucket; 2006135446Strhodes } else if (*bucketp != bucket) { 2007135446Strhodes UNLOCK(&adb->entrylocks[*bucketp]); 2008135446Strhodes LOCK(&adb->entrylocks[bucket]); 2009135446Strhodes *bucketp = bucket; 2010135446Strhodes } 2011135446Strhodes 2012193149Sdougb /* Search the list, while cleaning up expired entries. */ 2013193149Sdougb for (entry = ISC_LIST_HEAD(adb->entries[bucket]); 2014193149Sdougb entry != NULL; 2015193149Sdougb entry = entry_next) { 2016193149Sdougb entry_next = ISC_LIST_NEXT(entry, plink); 2017193149Sdougb (void)check_expire_entry(adb, &entry, now); 2018193149Sdougb if (entry != NULL && 2019193149Sdougb isc_sockaddr_equal(addr, &entry->sockaddr)) { 2020193149Sdougb ISC_LIST_UNLINK(adb->entries[bucket], entry, plink); 2021193149Sdougb ISC_LIST_PREPEND(adb->entries[bucket], entry, plink); 2022135446Strhodes return (entry); 2023193149Sdougb } 2024135446Strhodes } 2025135446Strhodes 2026135446Strhodes return (NULL); 2027135446Strhodes} 2028135446Strhodes 2029135446Strhodes/* 2030135446Strhodes * Entry bucket MUST be locked! 2031135446Strhodes */ 2032135446Strhodesstatic isc_boolean_t 2033170222Sdougbentry_is_lame(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *qname, 2034170222Sdougb dns_rdatatype_t qtype, isc_stdtime_t now) 2035135446Strhodes{ 2036170222Sdougb dns_adblameinfo_t *li, *next_li; 2037135446Strhodes isc_boolean_t is_bad; 2038135446Strhodes 2039135446Strhodes is_bad = ISC_FALSE; 2040135446Strhodes 2041170222Sdougb li = ISC_LIST_HEAD(entry->lameinfo); 2042170222Sdougb if (li == NULL) 2043135446Strhodes return (ISC_FALSE); 2044170222Sdougb while (li != NULL) { 2045170222Sdougb next_li = ISC_LIST_NEXT(li, plink); 2046135446Strhodes 2047135446Strhodes /* 2048135446Strhodes * Has the entry expired? 2049135446Strhodes */ 2050170222Sdougb if (li->lame_timer < now) { 2051170222Sdougb ISC_LIST_UNLINK(entry->lameinfo, li, plink); 2052170222Sdougb free_adblameinfo(adb, &li); 2053135446Strhodes } 2054135446Strhodes 2055135446Strhodes /* 2056135446Strhodes * Order tests from least to most expensive. 2057170222Sdougb * 2058170222Sdougb * We do not break out of the main loop here as 2059170222Sdougb * we use the loop for house keeping. 2060135446Strhodes */ 2061170222Sdougb if (li != NULL && !is_bad && li->qtype == qtype && 2062170222Sdougb dns_name_equal(qname, &li->qname)) 2063170222Sdougb is_bad = ISC_TRUE; 2064135446Strhodes 2065170222Sdougb li = next_li; 2066135446Strhodes } 2067135446Strhodes 2068135446Strhodes return (is_bad); 2069135446Strhodes} 2070135446Strhodes 2071135446Strhodesstatic void 2072170222Sdougbcopy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname, 2073170222Sdougb dns_rdatatype_t qtype, dns_adbname_t *name, 2074170222Sdougb isc_stdtime_t now) 2075135446Strhodes{ 2076135446Strhodes dns_adbnamehook_t *namehook; 2077135446Strhodes dns_adbaddrinfo_t *addrinfo; 2078135446Strhodes dns_adbentry_t *entry; 2079135446Strhodes int bucket; 2080135446Strhodes 2081135446Strhodes bucket = DNS_ADB_INVALIDBUCKET; 2082135446Strhodes 2083135446Strhodes if (find->options & DNS_ADBFIND_INET) { 2084135446Strhodes namehook = ISC_LIST_HEAD(name->v4); 2085135446Strhodes while (namehook != NULL) { 2086135446Strhodes entry = namehook->entry; 2087135446Strhodes bucket = entry->lock_bucket; 2088254402Serwin INSIST(bucket != DNS_ADB_INVALIDBUCKET); 2089135446Strhodes LOCK(&adb->entrylocks[bucket]); 2090135446Strhodes 2091135446Strhodes if (!FIND_RETURNLAME(find) 2092170222Sdougb && entry_is_lame(adb, entry, qname, qtype, now)) { 2093135446Strhodes find->options |= DNS_ADBFIND_LAMEPRUNED; 2094135446Strhodes goto nextv4; 2095135446Strhodes } 2096135446Strhodes addrinfo = new_adbaddrinfo(adb, entry, find->port); 2097135446Strhodes if (addrinfo == NULL) { 2098135446Strhodes find->partial_result |= DNS_ADBFIND_INET; 2099135446Strhodes goto out; 2100135446Strhodes } 2101135446Strhodes /* 2102135446Strhodes * Found a valid entry. Add it to the find's list. 2103135446Strhodes */ 2104135446Strhodes inc_entry_refcnt(adb, entry, ISC_FALSE); 2105135446Strhodes ISC_LIST_APPEND(find->list, addrinfo, publink); 2106135446Strhodes addrinfo = NULL; 2107135446Strhodes nextv4: 2108135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 2109135446Strhodes bucket = DNS_ADB_INVALIDBUCKET; 2110135446Strhodes namehook = ISC_LIST_NEXT(namehook, plink); 2111135446Strhodes } 2112135446Strhodes } 2113135446Strhodes 2114135446Strhodes if (find->options & DNS_ADBFIND_INET6) { 2115135446Strhodes namehook = ISC_LIST_HEAD(name->v6); 2116135446Strhodes while (namehook != NULL) { 2117135446Strhodes entry = namehook->entry; 2118135446Strhodes bucket = entry->lock_bucket; 2119254402Serwin INSIST(bucket != DNS_ADB_INVALIDBUCKET); 2120135446Strhodes LOCK(&adb->entrylocks[bucket]); 2121135446Strhodes 2122186462Sdougb if (!FIND_RETURNLAME(find) 2123186462Sdougb && entry_is_lame(adb, entry, qname, qtype, now)) { 2124186462Sdougb find->options |= DNS_ADBFIND_LAMEPRUNED; 2125135446Strhodes goto nextv6; 2126186462Sdougb } 2127135446Strhodes addrinfo = new_adbaddrinfo(adb, entry, find->port); 2128135446Strhodes if (addrinfo == NULL) { 2129135446Strhodes find->partial_result |= DNS_ADBFIND_INET6; 2130135446Strhodes goto out; 2131135446Strhodes } 2132135446Strhodes /* 2133135446Strhodes * Found a valid entry. Add it to the find's list. 2134135446Strhodes */ 2135135446Strhodes inc_entry_refcnt(adb, entry, ISC_FALSE); 2136135446Strhodes ISC_LIST_APPEND(find->list, addrinfo, publink); 2137135446Strhodes addrinfo = NULL; 2138135446Strhodes nextv6: 2139135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 2140135446Strhodes bucket = DNS_ADB_INVALIDBUCKET; 2141135446Strhodes namehook = ISC_LIST_NEXT(namehook, plink); 2142135446Strhodes } 2143135446Strhodes } 2144135446Strhodes 2145135446Strhodes out: 2146135446Strhodes if (bucket != DNS_ADB_INVALIDBUCKET) 2147135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 2148135446Strhodes} 2149135446Strhodes 2150135446Strhodesstatic void 2151135446Strhodesshutdown_task(isc_task_t *task, isc_event_t *ev) { 2152135446Strhodes dns_adb_t *adb; 2153135446Strhodes 2154135446Strhodes UNUSED(task); 2155135446Strhodes 2156135446Strhodes adb = ev->ev_arg; 2157135446Strhodes INSIST(DNS_ADB_VALID(adb)); 2158135446Strhodes 2159193149Sdougb isc_event_free(&ev); 2160135446Strhodes /* 2161186462Sdougb * Wait for lock around check_exit() call to be released. 2162186462Sdougb */ 2163186462Sdougb LOCK(&adb->lock); 2164135446Strhodes UNLOCK(&adb->lock); 2165135446Strhodes destroy(adb); 2166135446Strhodes} 2167135446Strhodes 2168135446Strhodes/* 2169135446Strhodes * Name bucket must be locked; adb may be locked; no other locks held. 2170135446Strhodes */ 2171135446Strhodesstatic isc_boolean_t 2172135446Strhodescheck_expire_name(dns_adbname_t **namep, isc_stdtime_t now) { 2173135446Strhodes dns_adbname_t *name; 2174153816Sdougb isc_boolean_t result = ISC_FALSE; 2175135446Strhodes 2176135446Strhodes INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep)); 2177135446Strhodes name = *namep; 2178135446Strhodes 2179135446Strhodes if (NAME_HAS_V4(name) || NAME_HAS_V6(name)) 2180135446Strhodes return (result); 2181135446Strhodes if (NAME_FETCH(name)) 2182135446Strhodes return (result); 2183135446Strhodes if (!EXPIRE_OK(name->expire_v4, now)) 2184135446Strhodes return (result); 2185135446Strhodes if (!EXPIRE_OK(name->expire_v6, now)) 2186135446Strhodes return (result); 2187135446Strhodes if (!EXPIRE_OK(name->expire_target, now)) 2188135446Strhodes return (result); 2189135446Strhodes 2190135446Strhodes /* 2191135446Strhodes * The name is empty. Delete it. 2192135446Strhodes */ 2193135446Strhodes result = kill_name(&name, DNS_EVENT_ADBEXPIRED); 2194135446Strhodes *namep = NULL; 2195135446Strhodes 2196135446Strhodes /* 2197135446Strhodes * Our caller, or one of its callers, will be calling check_exit() at 2198135446Strhodes * some point, so we don't need to do it here. 2199135446Strhodes */ 2200135446Strhodes return (result); 2201135446Strhodes} 2202135446Strhodes 2203193149Sdougb/*% 2204193149Sdougb * Examine the tail entry of the LRU list to see if it expires or is stale 2205193149Sdougb * (unused for some period); if so, the name entry will be freed. If the ADB 2206193149Sdougb * is in the overmem condition, the tail and the next to tail entries 2207193149Sdougb * will be unconditionally removed (unless they have an outstanding fetch). 2208193149Sdougb * We don't care about a race on 'overmem' at the risk of causing some 2209193149Sdougb * collateral damage or a small delay in starting cleanup, so we don't bother 2210193149Sdougb * to lock ADB (if it's not locked). 2211193149Sdougb * 2212193149Sdougb * Name bucket must be locked; adb may be locked; no other locks held. 2213193149Sdougb */ 2214193149Sdougbstatic void 2215193149Sdougbcheck_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) { 2216193149Sdougb int victims, max_victims; 2217193149Sdougb dns_adbname_t *victim, *next_victim; 2218214586Sdougb isc_boolean_t overmem = isc_mem_isovermem(adb->mctx); 2219193149Sdougb int scans = 0; 2220193149Sdougb 2221193149Sdougb INSIST(bucket != DNS_ADB_INVALIDBUCKET); 2222193149Sdougb 2223193149Sdougb max_victims = overmem ? 2 : 1; 2224193149Sdougb 2225193149Sdougb /* 2226193149Sdougb * We limit the number of scanned entries to 10 (arbitrary choice) 2227193149Sdougb * in order to avoid examining too many entries when there are many 2228193149Sdougb * tail entries that have fetches (this should be rare, but could 2229193149Sdougb * happen). 2230193149Sdougb */ 2231193149Sdougb victim = ISC_LIST_TAIL(adb->names[bucket]); 2232193149Sdougb for (victims = 0; 2233193149Sdougb victim != NULL && victims < max_victims && scans < 10; 2234193149Sdougb victim = next_victim) { 2235193149Sdougb INSIST(!NAME_DEAD(victim)); 2236193149Sdougb scans++; 2237193149Sdougb next_victim = ISC_LIST_PREV(victim, plink); 2238225361Sdougb (void)check_expire_name(&victim, now); 2239193149Sdougb if (victim == NULL) { 2240193149Sdougb victims++; 2241193149Sdougb goto next; 2242193149Sdougb } 2243193149Sdougb 2244193149Sdougb if (!NAME_FETCH(victim) && 2245193149Sdougb (overmem || victim->last_used + ADB_STALE_MARGIN <= now)) { 2246193149Sdougb RUNTIME_CHECK(kill_name(&victim, 2247193149Sdougb DNS_EVENT_ADBCANCELED) == 2248193149Sdougb ISC_FALSE); 2249193149Sdougb victims++; 2250193149Sdougb } 2251193149Sdougb 2252193149Sdougb next: 2253193149Sdougb if (!overmem) 2254193149Sdougb break; 2255193149Sdougb } 2256193149Sdougb} 2257193149Sdougb 2258135446Strhodes/* 2259135446Strhodes * Entry bucket must be locked; adb may be locked; no other locks held. 2260135446Strhodes */ 2261135446Strhodesstatic isc_boolean_t 2262135446Strhodescheck_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now) 2263135446Strhodes{ 2264135446Strhodes dns_adbentry_t *entry; 2265135446Strhodes isc_boolean_t result = ISC_FALSE; 2266135446Strhodes 2267135446Strhodes INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp)); 2268135446Strhodes entry = *entryp; 2269135446Strhodes 2270135446Strhodes if (entry->refcnt != 0) 2271135446Strhodes return (result); 2272135446Strhodes 2273193149Sdougb if (entry->expires == 0 || entry->expires > now) 2274135446Strhodes return (result); 2275135446Strhodes 2276135446Strhodes /* 2277135446Strhodes * The entry is not in use. Delete it. 2278135446Strhodes */ 2279135446Strhodes DP(DEF_LEVEL, "killing entry %p", entry); 2280135446Strhodes INSIST(ISC_LINK_LINKED(entry, plink)); 2281135446Strhodes result = unlink_entry(adb, entry); 2282135446Strhodes free_adbentry(adb, &entry); 2283135446Strhodes if (result) 2284135446Strhodes dec_adb_irefcnt(adb); 2285135446Strhodes *entryp = NULL; 2286135446Strhodes return (result); 2287135446Strhodes} 2288135446Strhodes 2289135446Strhodes/* 2290135446Strhodes * ADB must be locked, and no other locks held. 2291135446Strhodes */ 2292135446Strhodesstatic isc_boolean_t 2293135446Strhodescleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) { 2294135446Strhodes dns_adbname_t *name; 2295135446Strhodes dns_adbname_t *next_name; 2296153816Sdougb isc_boolean_t result = ISC_FALSE; 2297135446Strhodes 2298135446Strhodes DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket); 2299135446Strhodes 2300135446Strhodes LOCK(&adb->namelocks[bucket]); 2301135446Strhodes if (adb->name_sd[bucket]) { 2302135446Strhodes UNLOCK(&adb->namelocks[bucket]); 2303135446Strhodes return (result); 2304135446Strhodes } 2305135446Strhodes 2306135446Strhodes name = ISC_LIST_HEAD(adb->names[bucket]); 2307135446Strhodes while (name != NULL) { 2308135446Strhodes next_name = ISC_LIST_NEXT(name, plink); 2309135446Strhodes INSIST(result == ISC_FALSE); 2310193149Sdougb result = check_expire_namehooks(name, now); 2311135446Strhodes if (!result) 2312135446Strhodes result = check_expire_name(&name, now); 2313135446Strhodes name = next_name; 2314135446Strhodes } 2315135446Strhodes UNLOCK(&adb->namelocks[bucket]); 2316135446Strhodes return (result); 2317135446Strhodes} 2318135446Strhodes 2319135446Strhodes/* 2320135446Strhodes * ADB must be locked, and no other locks held. 2321135446Strhodes */ 2322135446Strhodesstatic isc_boolean_t 2323135446Strhodescleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) { 2324135446Strhodes dns_adbentry_t *entry, *next_entry; 2325135446Strhodes isc_boolean_t result = ISC_FALSE; 2326135446Strhodes 2327135446Strhodes DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket); 2328135446Strhodes 2329135446Strhodes LOCK(&adb->entrylocks[bucket]); 2330135446Strhodes entry = ISC_LIST_HEAD(adb->entries[bucket]); 2331135446Strhodes while (entry != NULL) { 2332135446Strhodes next_entry = ISC_LIST_NEXT(entry, plink); 2333135446Strhodes INSIST(result == ISC_FALSE); 2334135446Strhodes result = check_expire_entry(adb, &entry, now); 2335135446Strhodes entry = next_entry; 2336135446Strhodes } 2337135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 2338135446Strhodes return (result); 2339135446Strhodes} 2340135446Strhodes 2341135446Strhodesstatic void 2342135446Strhodesdestroy(dns_adb_t *adb) { 2343135446Strhodes adb->magic = 0; 2344135446Strhodes 2345135446Strhodes isc_task_detach(&adb->task); 2346254402Serwin if (adb->excl != NULL) 2347254402Serwin isc_task_detach(&adb->excl); 2348135446Strhodes 2349135446Strhodes isc_mempool_destroy(&adb->nmp); 2350135446Strhodes isc_mempool_destroy(&adb->nhmp); 2351170222Sdougb isc_mempool_destroy(&adb->limp); 2352135446Strhodes isc_mempool_destroy(&adb->emp); 2353135446Strhodes isc_mempool_destroy(&adb->ahmp); 2354135446Strhodes isc_mempool_destroy(&adb->aimp); 2355135446Strhodes isc_mempool_destroy(&adb->afmp); 2356135446Strhodes 2357224092Sdougb DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries); 2358224092Sdougb isc_mem_put(adb->mctx, adb->entries, 2359224092Sdougb sizeof(*adb->entries) * adb->nentries); 2360224092Sdougb isc_mem_put(adb->mctx, adb->deadentries, 2361224092Sdougb sizeof(*adb->deadentries) * adb->nentries); 2362224092Sdougb isc_mem_put(adb->mctx, adb->entrylocks, 2363224092Sdougb sizeof(*adb->entrylocks) * adb->nentries); 2364224092Sdougb isc_mem_put(adb->mctx, adb->entry_sd, 2365224092Sdougb sizeof(*adb->entry_sd) * adb->nentries); 2366224092Sdougb isc_mem_put(adb->mctx, adb->entry_refcnt, 2367224092Sdougb sizeof(*adb->entry_refcnt) * adb->nentries); 2368135446Strhodes 2369224092Sdougb DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames); 2370224092Sdougb isc_mem_put(adb->mctx, adb->names, 2371224092Sdougb sizeof(*adb->names) * adb->nnames); 2372224092Sdougb isc_mem_put(adb->mctx, adb->deadnames, 2373224092Sdougb sizeof(*adb->deadnames) * adb->nnames); 2374224092Sdougb isc_mem_put(adb->mctx, adb->namelocks, 2375224092Sdougb sizeof(*adb->namelocks) * adb->nnames); 2376224092Sdougb isc_mem_put(adb->mctx, adb->name_sd, 2377224092Sdougb sizeof(*adb->name_sd) * adb->nnames); 2378224092Sdougb isc_mem_put(adb->mctx, adb->name_refcnt, 2379224092Sdougb sizeof(*adb->name_refcnt) * adb->nnames); 2380224092Sdougb 2381135446Strhodes DESTROYLOCK(&adb->reflock); 2382135446Strhodes DESTROYLOCK(&adb->lock); 2383135446Strhodes DESTROYLOCK(&adb->mplock); 2384186462Sdougb DESTROYLOCK(&adb->overmemlock); 2385224092Sdougb DESTROYLOCK(&adb->entriescntlock); 2386224092Sdougb DESTROYLOCK(&adb->namescntlock); 2387135446Strhodes 2388135446Strhodes isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t)); 2389135446Strhodes} 2390135446Strhodes 2391135446Strhodes 2392135446Strhodes/* 2393135446Strhodes * Public functions. 2394135446Strhodes */ 2395135446Strhodes 2396135446Strhodesisc_result_t 2397135446Strhodesdns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, 2398135446Strhodes isc_taskmgr_t *taskmgr, dns_adb_t **newadb) 2399135446Strhodes{ 2400135446Strhodes dns_adb_t *adb; 2401135446Strhodes isc_result_t result; 2402224092Sdougb unsigned int i; 2403135446Strhodes 2404135446Strhodes REQUIRE(mem != NULL); 2405135446Strhodes REQUIRE(view != NULL); 2406193149Sdougb REQUIRE(timermgr != NULL); /* this is actually unused */ 2407135446Strhodes REQUIRE(taskmgr != NULL); 2408135446Strhodes REQUIRE(newadb != NULL && *newadb == NULL); 2409135446Strhodes 2410193149Sdougb UNUSED(timermgr); 2411193149Sdougb 2412135446Strhodes adb = isc_mem_get(mem, sizeof(dns_adb_t)); 2413135446Strhodes if (adb == NULL) 2414135446Strhodes return (ISC_R_NOMEMORY); 2415135446Strhodes 2416135446Strhodes /* 2417135446Strhodes * Initialize things here that cannot fail, and especially things 2418135446Strhodes * that must be NULL for the error return to work properly. 2419135446Strhodes */ 2420135446Strhodes adb->magic = 0; 2421135446Strhodes adb->erefcnt = 1; 2422135446Strhodes adb->irefcnt = 0; 2423135446Strhodes adb->nmp = NULL; 2424135446Strhodes adb->nhmp = NULL; 2425170222Sdougb adb->limp = NULL; 2426135446Strhodes adb->emp = NULL; 2427135446Strhodes adb->ahmp = NULL; 2428135446Strhodes adb->aimp = NULL; 2429135446Strhodes adb->afmp = NULL; 2430135446Strhodes adb->task = NULL; 2431245163Serwin adb->excl = NULL; 2432135446Strhodes adb->mctx = NULL; 2433135446Strhodes adb->view = view; 2434135446Strhodes adb->taskmgr = taskmgr; 2435135446Strhodes adb->next_cleanbucket = 0; 2436135446Strhodes ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL, 2437135446Strhodes DNS_EVENT_ADBCONTROL, shutdown_task, adb, 2438135446Strhodes adb, NULL, NULL); 2439135446Strhodes adb->cevent_sent = ISC_FALSE; 2440135446Strhodes adb->shutting_down = ISC_FALSE; 2441135446Strhodes ISC_LIST_INIT(adb->whenshutdown); 2442135446Strhodes 2443224092Sdougb adb->nentries = nbuckets[0]; 2444224092Sdougb adb->entriescnt = 0; 2445224092Sdougb adb->entries = NULL; 2446224092Sdougb adb->deadentries = NULL; 2447224092Sdougb adb->entry_sd = NULL; 2448224092Sdougb adb->entry_refcnt = NULL; 2449224092Sdougb adb->entrylocks = NULL; 2450224092Sdougb ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL, 2451224092Sdougb DNS_EVENT_ADBGROWENTRIES, grow_entries, adb, 2452224092Sdougb adb, NULL, NULL); 2453224092Sdougb adb->growentries_sent = ISC_FALSE; 2454224092Sdougb 2455224092Sdougb adb->nnames = nbuckets[0]; 2456224092Sdougb adb->namescnt = 0; 2457224092Sdougb adb->names = NULL; 2458224092Sdougb adb->deadnames = NULL; 2459224092Sdougb adb->name_sd = NULL; 2460224092Sdougb adb->name_refcnt = NULL; 2461224092Sdougb adb->namelocks = NULL; 2462224092Sdougb ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL, 2463224092Sdougb DNS_EVENT_ADBGROWNAMES, grow_names, adb, 2464224092Sdougb adb, NULL, NULL); 2465224092Sdougb adb->grownames_sent = ISC_FALSE; 2466224092Sdougb 2467245163Serwin result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl); 2468245163Serwin if (result != ISC_R_SUCCESS) { 2469245163Serwin DP(ISC_LOG_INFO, "adb: task-exclusive mode unavailable, " 2470245163Serwin "intializing table sizes to %u\n", 2471245163Serwin nbuckets[11]); 2472245163Serwin adb->nentries = nbuckets[11]; 2473245163Serwin adb->nnames= nbuckets[11]; 2474245163Serwin 2475245163Serwin } 2476245163Serwin 2477135446Strhodes isc_mem_attach(mem, &adb->mctx); 2478135446Strhodes 2479135446Strhodes result = isc_mutex_init(&adb->lock); 2480135446Strhodes if (result != ISC_R_SUCCESS) 2481135446Strhodes goto fail0b; 2482135446Strhodes 2483135446Strhodes result = isc_mutex_init(&adb->mplock); 2484135446Strhodes if (result != ISC_R_SUCCESS) 2485135446Strhodes goto fail0c; 2486135446Strhodes 2487135446Strhodes result = isc_mutex_init(&adb->reflock); 2488135446Strhodes if (result != ISC_R_SUCCESS) 2489135446Strhodes goto fail0d; 2490135446Strhodes 2491186462Sdougb result = isc_mutex_init(&adb->overmemlock); 2492186462Sdougb if (result != ISC_R_SUCCESS) 2493186462Sdougb goto fail0e; 2494186462Sdougb 2495224092Sdougb result = isc_mutex_init(&adb->entriescntlock); 2496224092Sdougb if (result != ISC_R_SUCCESS) 2497224092Sdougb goto fail0f; 2498224092Sdougb 2499224092Sdougb result = isc_mutex_init(&adb->namescntlock); 2500224092Sdougb if (result != ISC_R_SUCCESS) 2501224092Sdougb goto fail0g; 2502224092Sdougb 2503224092Sdougb#define ALLOCENTRY(adb, el) \ 2504224092Sdougb do { \ 2505224092Sdougb (adb)->el = isc_mem_get((adb)->mctx, \ 2506224092Sdougb sizeof(*(adb)->el) * (adb)->nentries); \ 2507224092Sdougb if ((adb)->el == NULL) { \ 2508224092Sdougb result = ISC_R_NOMEMORY; \ 2509224092Sdougb goto fail1; \ 2510224092Sdougb }\ 2511224092Sdougb } while (0) 2512224092Sdougb ALLOCENTRY(adb, entries); 2513224092Sdougb ALLOCENTRY(adb, deadentries); 2514224092Sdougb ALLOCENTRY(adb, entrylocks); 2515224092Sdougb ALLOCENTRY(adb, entry_sd); 2516224092Sdougb ALLOCENTRY(adb, entry_refcnt); 2517224092Sdougb#undef ALLOCENTRY 2518224092Sdougb 2519224092Sdougb#define ALLOCNAME(adb, el) \ 2520224092Sdougb do { \ 2521224092Sdougb (adb)->el = isc_mem_get((adb)->mctx, \ 2522224092Sdougb sizeof(*(adb)->el) * (adb)->nnames); \ 2523224092Sdougb if ((adb)->el == NULL) { \ 2524224092Sdougb result = ISC_R_NOMEMORY; \ 2525224092Sdougb goto fail1; \ 2526224092Sdougb }\ 2527224092Sdougb } while (0) 2528224092Sdougb ALLOCNAME(adb, names); 2529224092Sdougb ALLOCNAME(adb, deadnames); 2530224092Sdougb ALLOCNAME(adb, namelocks); 2531224092Sdougb ALLOCNAME(adb, name_sd); 2532224092Sdougb ALLOCNAME(adb, name_refcnt); 2533224092Sdougb#undef ALLOCNAME 2534224092Sdougb 2535135446Strhodes /* 2536135446Strhodes * Initialize the bucket locks for names and elements. 2537135446Strhodes * May as well initialize the list heads, too. 2538135446Strhodes */ 2539224092Sdougb result = isc_mutexblock_init(adb->namelocks, adb->nnames); 2540135446Strhodes if (result != ISC_R_SUCCESS) 2541135446Strhodes goto fail1; 2542224092Sdougb for (i = 0; i < adb->nnames; i++) { 2543135446Strhodes ISC_LIST_INIT(adb->names[i]); 2544193149Sdougb ISC_LIST_INIT(adb->deadnames[i]); 2545135446Strhodes adb->name_sd[i] = ISC_FALSE; 2546135446Strhodes adb->name_refcnt[i] = 0; 2547135446Strhodes adb->irefcnt++; 2548135446Strhodes } 2549224092Sdougb for (i = 0; i < adb->nentries; i++) { 2550135446Strhodes ISC_LIST_INIT(adb->entries[i]); 2551193149Sdougb ISC_LIST_INIT(adb->deadentries[i]); 2552135446Strhodes adb->entry_sd[i] = ISC_FALSE; 2553135446Strhodes adb->entry_refcnt[i] = 0; 2554135446Strhodes adb->irefcnt++; 2555135446Strhodes } 2556224092Sdougb result = isc_mutexblock_init(adb->entrylocks, adb->nentries); 2557135446Strhodes if (result != ISC_R_SUCCESS) 2558135446Strhodes goto fail2; 2559135446Strhodes 2560135446Strhodes /* 2561135446Strhodes * Memory pools 2562135446Strhodes */ 2563135446Strhodes#define MPINIT(t, p, n) do { \ 2564135446Strhodes result = isc_mempool_create(mem, sizeof(t), &(p)); \ 2565135446Strhodes if (result != ISC_R_SUCCESS) \ 2566135446Strhodes goto fail3; \ 2567135446Strhodes isc_mempool_setfreemax((p), FREE_ITEMS); \ 2568135446Strhodes isc_mempool_setfillcount((p), FILL_COUNT); \ 2569135446Strhodes isc_mempool_setname((p), n); \ 2570135446Strhodes isc_mempool_associatelock((p), &adb->mplock); \ 2571135446Strhodes} while (0) 2572135446Strhodes 2573135446Strhodes MPINIT(dns_adbname_t, adb->nmp, "adbname"); 2574135446Strhodes MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook"); 2575170222Sdougb MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo"); 2576135446Strhodes MPINIT(dns_adbentry_t, adb->emp, "adbentry"); 2577135446Strhodes MPINIT(dns_adbfind_t, adb->ahmp, "adbfind"); 2578135446Strhodes MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo"); 2579135446Strhodes MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch"); 2580135446Strhodes 2581135446Strhodes#undef MPINIT 2582135446Strhodes 2583135446Strhodes /* 2584193149Sdougb * Allocate an internal task. 2585135446Strhodes */ 2586135446Strhodes result = isc_task_create(adb->taskmgr, 0, &adb->task); 2587135446Strhodes if (result != ISC_R_SUCCESS) 2588135446Strhodes goto fail3; 2589245163Serwin 2590135446Strhodes isc_task_setname(adb->task, "ADB", adb); 2591135446Strhodes 2592135446Strhodes /* 2593135446Strhodes * Normal return. 2594135446Strhodes */ 2595135446Strhodes adb->magic = DNS_ADB_MAGIC; 2596135446Strhodes *newadb = adb; 2597135446Strhodes return (ISC_R_SUCCESS); 2598135446Strhodes 2599135446Strhodes fail3: 2600135446Strhodes if (adb->task != NULL) 2601135446Strhodes isc_task_detach(&adb->task); 2602135446Strhodes 2603135446Strhodes /* clean up entrylocks */ 2604224092Sdougb DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries); 2605135446Strhodes 2606135446Strhodes fail2: /* clean up namelocks */ 2607224092Sdougb DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames); 2608135446Strhodes 2609135446Strhodes fail1: /* clean up only allocated memory */ 2610224092Sdougb if (adb->entries != NULL) 2611224092Sdougb isc_mem_put(adb->mctx, adb->entries, 2612224092Sdougb sizeof(*adb->entries) * adb->nentries); 2613224092Sdougb if (adb->deadentries != NULL) 2614224092Sdougb isc_mem_put(adb->mctx, adb->deadentries, 2615224092Sdougb sizeof(*adb->deadentries) * adb->nentries); 2616224092Sdougb if (adb->entrylocks != NULL) 2617224092Sdougb isc_mem_put(adb->mctx, adb->entrylocks, 2618224092Sdougb sizeof(*adb->entrylocks) * adb->nentries); 2619224092Sdougb if (adb->entry_sd != NULL) 2620224092Sdougb isc_mem_put(adb->mctx, adb->entry_sd, 2621224092Sdougb sizeof(*adb->entry_sd) * adb->nentries); 2622224092Sdougb if (adb->entry_refcnt != NULL) 2623224092Sdougb isc_mem_put(adb->mctx, adb->entry_refcnt, 2624224092Sdougb sizeof(*adb->entry_refcnt) * adb->nentries); 2625224092Sdougb if (adb->names != NULL) 2626224092Sdougb isc_mem_put(adb->mctx, adb->names, 2627224092Sdougb sizeof(*adb->names) * adb->nnames); 2628224092Sdougb if (adb->deadnames != NULL) 2629224092Sdougb isc_mem_put(adb->mctx, adb->deadnames, 2630224092Sdougb sizeof(*adb->deadnames) * adb->nnames); 2631224092Sdougb if (adb->namelocks != NULL) 2632224092Sdougb isc_mem_put(adb->mctx, adb->namelocks, 2633224092Sdougb sizeof(*adb->namelocks) * adb->nnames); 2634224092Sdougb if (adb->name_sd != NULL) 2635224092Sdougb isc_mem_put(adb->mctx, adb->name_sd, 2636224092Sdougb sizeof(*adb->name_sd) * adb->nnames); 2637224092Sdougb if (adb->name_refcnt != NULL) 2638224092Sdougb isc_mem_put(adb->mctx, adb->name_refcnt, 2639224092Sdougb sizeof(*adb->name_refcnt) * adb->nnames); 2640135446Strhodes if (adb->nmp != NULL) 2641135446Strhodes isc_mempool_destroy(&adb->nmp); 2642135446Strhodes if (adb->nhmp != NULL) 2643135446Strhodes isc_mempool_destroy(&adb->nhmp); 2644170222Sdougb if (adb->limp != NULL) 2645170222Sdougb isc_mempool_destroy(&adb->limp); 2646135446Strhodes if (adb->emp != NULL) 2647135446Strhodes isc_mempool_destroy(&adb->emp); 2648135446Strhodes if (adb->ahmp != NULL) 2649135446Strhodes isc_mempool_destroy(&adb->ahmp); 2650135446Strhodes if (adb->aimp != NULL) 2651135446Strhodes isc_mempool_destroy(&adb->aimp); 2652135446Strhodes if (adb->afmp != NULL) 2653135446Strhodes isc_mempool_destroy(&adb->afmp); 2654135446Strhodes 2655224092Sdougb DESTROYLOCK(&adb->namescntlock); 2656224092Sdougb fail0g: 2657224092Sdougb DESTROYLOCK(&adb->entriescntlock); 2658224092Sdougb fail0f: 2659186462Sdougb DESTROYLOCK(&adb->overmemlock); 2660186462Sdougb fail0e: 2661135446Strhodes DESTROYLOCK(&adb->reflock); 2662135446Strhodes fail0d: 2663135446Strhodes DESTROYLOCK(&adb->mplock); 2664135446Strhodes fail0c: 2665135446Strhodes DESTROYLOCK(&adb->lock); 2666135446Strhodes fail0b: 2667135446Strhodes isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t)); 2668135446Strhodes 2669135446Strhodes return (result); 2670135446Strhodes} 2671135446Strhodes 2672135446Strhodesvoid 2673135446Strhodesdns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) { 2674135446Strhodes 2675135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 2676135446Strhodes REQUIRE(adbx != NULL && *adbx == NULL); 2677135446Strhodes 2678135446Strhodes inc_adb_erefcnt(adb); 2679135446Strhodes *adbx = adb; 2680135446Strhodes} 2681135446Strhodes 2682135446Strhodesvoid 2683135446Strhodesdns_adb_detach(dns_adb_t **adbx) { 2684135446Strhodes dns_adb_t *adb; 2685135446Strhodes isc_boolean_t need_exit_check; 2686135446Strhodes 2687135446Strhodes REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx)); 2688135446Strhodes 2689135446Strhodes adb = *adbx; 2690135446Strhodes *adbx = NULL; 2691135446Strhodes 2692135446Strhodes INSIST(adb->erefcnt > 0); 2693135446Strhodes 2694135446Strhodes LOCK(&adb->reflock); 2695135446Strhodes adb->erefcnt--; 2696135446Strhodes need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0); 2697135446Strhodes UNLOCK(&adb->reflock); 2698135446Strhodes 2699135446Strhodes if (need_exit_check) { 2700135446Strhodes LOCK(&adb->lock); 2701135446Strhodes INSIST(adb->shutting_down); 2702135446Strhodes check_exit(adb); 2703135446Strhodes UNLOCK(&adb->lock); 2704135446Strhodes } 2705135446Strhodes} 2706135446Strhodes 2707135446Strhodesvoid 2708135446Strhodesdns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) { 2709135446Strhodes isc_task_t *clone; 2710135446Strhodes isc_event_t *event; 2711135446Strhodes isc_boolean_t zeroirefcnt = ISC_FALSE; 2712135446Strhodes 2713135446Strhodes /* 2714135446Strhodes * Send '*eventp' to 'task' when 'adb' has shutdown. 2715135446Strhodes */ 2716135446Strhodes 2717135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 2718135446Strhodes REQUIRE(eventp != NULL); 2719135446Strhodes 2720135446Strhodes event = *eventp; 2721135446Strhodes *eventp = NULL; 2722135446Strhodes 2723135446Strhodes LOCK(&adb->lock); 2724135446Strhodes 2725135446Strhodes LOCK(&adb->reflock); 2726135446Strhodes zeroirefcnt = ISC_TF(adb->irefcnt == 0); 2727135446Strhodes 2728135446Strhodes if (adb->shutting_down && zeroirefcnt && 2729135446Strhodes isc_mempool_getallocated(adb->ahmp) == 0) { 2730135446Strhodes /* 2731135446Strhodes * We're already shutdown. Send the event. 2732135446Strhodes */ 2733135446Strhodes event->ev_sender = adb; 2734135446Strhodes isc_task_send(task, &event); 2735135446Strhodes } else { 2736135446Strhodes clone = NULL; 2737135446Strhodes isc_task_attach(task, &clone); 2738135446Strhodes event->ev_sender = clone; 2739135446Strhodes ISC_LIST_APPEND(adb->whenshutdown, event, ev_link); 2740135446Strhodes } 2741135446Strhodes 2742135446Strhodes UNLOCK(&adb->reflock); 2743135446Strhodes UNLOCK(&adb->lock); 2744135446Strhodes} 2745135446Strhodes 2746135446Strhodesvoid 2747135446Strhodesdns_adb_shutdown(dns_adb_t *adb) { 2748135446Strhodes isc_boolean_t need_check_exit; 2749135446Strhodes 2750135446Strhodes /* 2751135446Strhodes * Shutdown 'adb'. 2752135446Strhodes */ 2753135446Strhodes 2754135446Strhodes LOCK(&adb->lock); 2755135446Strhodes 2756135446Strhodes if (!adb->shutting_down) { 2757135446Strhodes adb->shutting_down = ISC_TRUE; 2758135446Strhodes isc_mem_setwater(adb->mctx, water, adb, 0, 0); 2759135446Strhodes need_check_exit = shutdown_names(adb); 2760135446Strhodes if (!need_check_exit) 2761135446Strhodes need_check_exit = shutdown_entries(adb); 2762135446Strhodes if (need_check_exit) 2763135446Strhodes check_exit(adb); 2764135446Strhodes } 2765135446Strhodes 2766135446Strhodes UNLOCK(&adb->lock); 2767135446Strhodes} 2768135446Strhodes 2769135446Strhodesisc_result_t 2770135446Strhodesdns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, 2771170222Sdougb void *arg, dns_name_t *name, dns_name_t *qname, 2772170222Sdougb dns_rdatatype_t qtype, unsigned int options, 2773170222Sdougb isc_stdtime_t now, dns_name_t *target, 2774135446Strhodes in_port_t port, dns_adbfind_t **findp) 2775135446Strhodes{ 2776275672Sdelphij return (dns_adb_createfind2(adb, task, action, arg, name, 2777275672Sdelphij qname, qtype, options, now, 2778275672Sdelphij target, port, 0, findp)); 2779275672Sdelphij} 2780275672Sdelphij 2781275672Sdelphijisc_result_t 2782275672Sdelphijdns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, 2783275672Sdelphij void *arg, dns_name_t *name, dns_name_t *qname, 2784275672Sdelphij dns_rdatatype_t qtype, unsigned int options, 2785275672Sdelphij isc_stdtime_t now, dns_name_t *target, 2786275672Sdelphij in_port_t port, unsigned int depth, 2787275672Sdelphij dns_adbfind_t **findp) 2788275672Sdelphij{ 2789135446Strhodes dns_adbfind_t *find; 2790135446Strhodes dns_adbname_t *adbname; 2791135446Strhodes int bucket; 2792135446Strhodes isc_boolean_t want_event, start_at_zone, alias, have_address; 2793135446Strhodes isc_result_t result; 2794135446Strhodes unsigned int wanted_addresses; 2795135446Strhodes unsigned int wanted_fetches; 2796135446Strhodes unsigned int query_pending; 2797135446Strhodes 2798135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 2799135446Strhodes if (task != NULL) { 2800135446Strhodes REQUIRE(action != NULL); 2801135446Strhodes } 2802135446Strhodes REQUIRE(name != NULL); 2803170222Sdougb REQUIRE(qname != NULL); 2804135446Strhodes REQUIRE(findp != NULL && *findp == NULL); 2805135446Strhodes REQUIRE(target == NULL || dns_name_hasbuffer(target)); 2806135446Strhodes 2807135446Strhodes REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0); 2808135446Strhodes 2809135446Strhodes result = ISC_R_UNEXPECTED; 2810225361Sdougb POST(result); 2811135446Strhodes wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK); 2812135446Strhodes wanted_fetches = 0; 2813135446Strhodes query_pending = 0; 2814135446Strhodes want_event = ISC_FALSE; 2815135446Strhodes start_at_zone = ISC_FALSE; 2816135446Strhodes alias = ISC_FALSE; 2817135446Strhodes 2818135446Strhodes if (now == 0) 2819135446Strhodes isc_stdtime_get(&now); 2820135446Strhodes 2821135446Strhodes /* 2822135446Strhodes * XXXMLG Move this comment somewhere else! 2823135446Strhodes * 2824135446Strhodes * Look up the name in our internal database. 2825135446Strhodes * 2826135446Strhodes * Possibilities: Note that these are not always exclusive. 2827135446Strhodes * 2828193149Sdougb * No name found. In this case, allocate a new name header and 2829193149Sdougb * an initial namehook or two. If any of these allocations 2830193149Sdougb * fail, clean up and return ISC_R_NOMEMORY. 2831135446Strhodes * 2832193149Sdougb * Name found, valid addresses present. Allocate one addrinfo 2833193149Sdougb * structure for each found and append it to the linked list 2834193149Sdougb * of addresses for this header. 2835135446Strhodes * 2836193149Sdougb * Name found, queries pending. In this case, if a task was 2837193149Sdougb * passed in, allocate a job id, attach it to the name's job 2838193149Sdougb * list and remember to tell the caller that there will be 2839193149Sdougb * more info coming later. 2840135446Strhodes */ 2841135446Strhodes 2842135446Strhodes find = new_adbfind(adb); 2843135446Strhodes if (find == NULL) 2844135446Strhodes return (ISC_R_NOMEMORY); 2845135446Strhodes 2846135446Strhodes find->port = port; 2847135446Strhodes 2848135446Strhodes /* 2849135446Strhodes * Remember what types of addresses we are interested in. 2850135446Strhodes */ 2851135446Strhodes find->options = options; 2852135446Strhodes find->flags |= wanted_addresses; 2853135446Strhodes if (FIND_WANTEVENT(find)) { 2854135446Strhodes REQUIRE(task != NULL); 2855135446Strhodes } 2856135446Strhodes 2857135446Strhodes /* 2858135446Strhodes * Try to see if we know anything about this name at all. 2859135446Strhodes */ 2860135446Strhodes bucket = DNS_ADB_INVALIDBUCKET; 2861135446Strhodes adbname = find_name_and_lock(adb, name, find->options, &bucket); 2862225361Sdougb INSIST(bucket != DNS_ADB_INVALIDBUCKET); 2863135446Strhodes if (adb->name_sd[bucket]) { 2864135446Strhodes DP(DEF_LEVEL, 2865135446Strhodes "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN"); 2866135446Strhodes RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); 2867135446Strhodes result = ISC_R_SHUTTINGDOWN; 2868135446Strhodes goto out; 2869135446Strhodes } 2870135446Strhodes 2871135446Strhodes /* 2872135446Strhodes * Nothing found. Allocate a new adbname structure for this name. 2873135446Strhodes */ 2874135446Strhodes if (adbname == NULL) { 2875193149Sdougb /* 2876193149Sdougb * See if there is any stale name at the end of list, and purge 2877193149Sdougb * it if so. 2878193149Sdougb */ 2879193149Sdougb check_stale_name(adb, bucket, now); 2880193149Sdougb 2881135446Strhodes adbname = new_adbname(adb, name); 2882135446Strhodes if (adbname == NULL) { 2883135446Strhodes RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); 2884135446Strhodes result = ISC_R_NOMEMORY; 2885135446Strhodes goto out; 2886135446Strhodes } 2887135446Strhodes link_name(adb, bucket, adbname); 2888135446Strhodes if (FIND_HINTOK(find)) 2889135446Strhodes adbname->flags |= NAME_HINT_OK; 2890135446Strhodes if (FIND_GLUEOK(find)) 2891135446Strhodes adbname->flags |= NAME_GLUE_OK; 2892135446Strhodes if (FIND_STARTATZONE(find)) 2893135446Strhodes adbname->flags |= NAME_STARTATZONE; 2894193149Sdougb } else { 2895193149Sdougb /* Move this name forward in the LRU list */ 2896193149Sdougb ISC_LIST_UNLINK(adb->names[bucket], adbname, plink); 2897193149Sdougb ISC_LIST_PREPEND(adb->names[bucket], adbname, plink); 2898135446Strhodes } 2899193149Sdougb adbname->last_used = now; 2900135446Strhodes 2901135446Strhodes /* 2902135446Strhodes * Expire old entries, etc. 2903135446Strhodes */ 2904193149Sdougb RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE); 2905135446Strhodes 2906135446Strhodes /* 2907135446Strhodes * Do we know that the name is an alias? 2908135446Strhodes */ 2909135446Strhodes if (!EXPIRE_OK(adbname->expire_target, now)) { 2910135446Strhodes /* 2911135446Strhodes * Yes, it is. 2912135446Strhodes */ 2913135446Strhodes DP(DEF_LEVEL, 2914135446Strhodes "dns_adb_createfind: name %p is an alias (cached)", 2915135446Strhodes adbname); 2916135446Strhodes alias = ISC_TRUE; 2917135446Strhodes goto post_copy; 2918135446Strhodes } 2919135446Strhodes 2920135446Strhodes /* 2921135446Strhodes * Try to populate the name from the database and/or 2922135446Strhodes * start fetches. First try looking for an A record 2923135446Strhodes * in the database. 2924135446Strhodes */ 2925135446Strhodes if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now) 2926135446Strhodes && WANT_INET(wanted_addresses)) { 2927135446Strhodes result = dbfind_name(adbname, now, dns_rdatatype_a); 2928135446Strhodes if (result == ISC_R_SUCCESS) { 2929135446Strhodes DP(DEF_LEVEL, 2930135446Strhodes "dns_adb_createfind: found A for name %p in db", 2931135446Strhodes adbname); 2932135446Strhodes goto v6; 2933135446Strhodes } 2934135446Strhodes 2935135446Strhodes /* 2936135446Strhodes * Did we get a CNAME or DNAME? 2937135446Strhodes */ 2938135446Strhodes if (result == DNS_R_ALIAS) { 2939135446Strhodes DP(DEF_LEVEL, 2940135446Strhodes "dns_adb_createfind: name %p is an alias", 2941135446Strhodes adbname); 2942135446Strhodes alias = ISC_TRUE; 2943135446Strhodes goto post_copy; 2944135446Strhodes } 2945135446Strhodes 2946135446Strhodes /* 2947135446Strhodes * If the name doesn't exist at all, don't bother with 2948135446Strhodes * v6 queries; they won't work. 2949135446Strhodes * 2950135446Strhodes * If the name does exist but we didn't get our data, go 2951135446Strhodes * ahead and try AAAA. 2952135446Strhodes * 2953135446Strhodes * If the result is neither of these, try a fetch for A. 2954135446Strhodes */ 2955135446Strhodes if (NXDOMAIN_RESULT(result)) 2956135446Strhodes goto fetch; 2957135446Strhodes else if (NXRRSET_RESULT(result)) 2958135446Strhodes goto v6; 2959135446Strhodes 2960135446Strhodes if (!NAME_FETCH_V4(adbname)) 2961135446Strhodes wanted_fetches |= DNS_ADBFIND_INET; 2962135446Strhodes } 2963135446Strhodes 2964135446Strhodes v6: 2965135446Strhodes if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now) 2966135446Strhodes && WANT_INET6(wanted_addresses)) { 2967135446Strhodes result = dbfind_name(adbname, now, dns_rdatatype_aaaa); 2968135446Strhodes if (result == ISC_R_SUCCESS) { 2969135446Strhodes DP(DEF_LEVEL, 2970135446Strhodes "dns_adb_createfind: found AAAA for name %p", 2971135446Strhodes adbname); 2972135446Strhodes goto fetch; 2973135446Strhodes } 2974135446Strhodes 2975135446Strhodes /* 2976135446Strhodes * Did we get a CNAME or DNAME? 2977135446Strhodes */ 2978135446Strhodes if (result == DNS_R_ALIAS) { 2979135446Strhodes DP(DEF_LEVEL, 2980135446Strhodes "dns_adb_createfind: name %p is an alias", 2981135446Strhodes adbname); 2982135446Strhodes alias = ISC_TRUE; 2983135446Strhodes goto post_copy; 2984135446Strhodes } 2985135446Strhodes 2986135446Strhodes /* 2987135446Strhodes * Listen to negative cache hints, and don't start 2988135446Strhodes * another query. 2989135446Strhodes */ 2990135446Strhodes if (NCACHE_RESULT(result) || AUTH_NX(result)) 2991135446Strhodes goto fetch; 2992135446Strhodes 2993135446Strhodes if (!NAME_FETCH_V6(adbname)) 2994135446Strhodes wanted_fetches |= DNS_ADBFIND_INET6; 2995135446Strhodes } 2996135446Strhodes 2997135446Strhodes fetch: 2998135446Strhodes if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) || 2999135446Strhodes (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname))) 3000135446Strhodes have_address = ISC_TRUE; 3001135446Strhodes else 3002135446Strhodes have_address = ISC_FALSE; 3003135446Strhodes if (wanted_fetches != 0 && 3004135446Strhodes ! (FIND_AVOIDFETCHES(find) && have_address)) { 3005135446Strhodes /* 3006135446Strhodes * We're missing at least one address family. Either the 3007135446Strhodes * caller hasn't instructed us to avoid fetches, or we don't 3008135446Strhodes * know anything about any of the address families that would 3009135446Strhodes * be acceptable so we have to launch fetches. 3010135446Strhodes */ 3011135446Strhodes 3012135446Strhodes if (FIND_STARTATZONE(find)) 3013135446Strhodes start_at_zone = ISC_TRUE; 3014135446Strhodes 3015135446Strhodes /* 3016135446Strhodes * Start V4. 3017135446Strhodes */ 3018135446Strhodes if (WANT_INET(wanted_fetches) && 3019275672Sdelphij fetch_name(adbname, start_at_zone, depth, 3020135446Strhodes dns_rdatatype_a) == ISC_R_SUCCESS) { 3021135446Strhodes DP(DEF_LEVEL, 3022135446Strhodes "dns_adb_createfind: started A fetch for name %p", 3023135446Strhodes adbname); 3024135446Strhodes } 3025135446Strhodes 3026135446Strhodes /* 3027135446Strhodes * Start V6. 3028135446Strhodes */ 3029135446Strhodes if (WANT_INET6(wanted_fetches) && 3030275672Sdelphij fetch_name(adbname, start_at_zone, depth, 3031135446Strhodes dns_rdatatype_aaaa) == ISC_R_SUCCESS) { 3032135446Strhodes DP(DEF_LEVEL, 3033135446Strhodes "dns_adb_createfind: " 3034135446Strhodes "started AAAA fetch for name %p", 3035135446Strhodes adbname); 3036135446Strhodes } 3037135446Strhodes } 3038135446Strhodes 3039135446Strhodes /* 3040135446Strhodes * Run through the name and copy out the bits we are 3041135446Strhodes * interested in. 3042135446Strhodes */ 3043170222Sdougb copy_namehook_lists(adb, find, qname, qtype, adbname, now); 3044135446Strhodes 3045135446Strhodes post_copy: 3046135446Strhodes if (NAME_FETCH_V4(adbname)) 3047135446Strhodes query_pending |= DNS_ADBFIND_INET; 3048135446Strhodes if (NAME_FETCH_V6(adbname)) 3049135446Strhodes query_pending |= DNS_ADBFIND_INET6; 3050135446Strhodes 3051135446Strhodes /* 3052135446Strhodes * Attach to the name's query list if there are queries 3053135446Strhodes * already running, and we have been asked to. 3054135446Strhodes */ 3055135446Strhodes want_event = ISC_TRUE; 3056135446Strhodes if (!FIND_WANTEVENT(find)) 3057135446Strhodes want_event = ISC_FALSE; 3058135446Strhodes if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find)) 3059135446Strhodes want_event = ISC_FALSE; 3060135446Strhodes if ((wanted_addresses & query_pending) == 0) 3061135446Strhodes want_event = ISC_FALSE; 3062135446Strhodes if (alias) 3063135446Strhodes want_event = ISC_FALSE; 3064135446Strhodes if (want_event) { 3065135446Strhodes find->adbname = adbname; 3066135446Strhodes find->name_bucket = bucket; 3067135446Strhodes ISC_LIST_APPEND(adbname->finds, find, plink); 3068135446Strhodes find->query_pending = (query_pending & wanted_addresses); 3069135446Strhodes find->flags &= ~DNS_ADBFIND_ADDRESSMASK; 3070135446Strhodes find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK); 3071135446Strhodes DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p", 3072135446Strhodes find, adbname); 3073135446Strhodes } else { 3074135446Strhodes /* 3075135446Strhodes * Remove the flag so the caller knows there will never 3076135446Strhodes * be an event, and set internal flags to fake that 3077135446Strhodes * the event was sent and freed, so dns_adb_destroyfind() will 3078135446Strhodes * do the right thing. 3079135446Strhodes */ 3080135446Strhodes find->query_pending = (query_pending & wanted_addresses); 3081135446Strhodes find->options &= ~DNS_ADBFIND_WANTEVENT; 3082135446Strhodes find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED); 3083135446Strhodes find->flags &= ~DNS_ADBFIND_ADDRESSMASK; 3084135446Strhodes } 3085135446Strhodes 3086135446Strhodes find->partial_result |= (adbname->partial_result & wanted_addresses); 3087135446Strhodes if (alias) { 3088135446Strhodes if (target != NULL) { 3089135446Strhodes result = dns_name_copy(&adbname->target, target, NULL); 3090135446Strhodes if (result != ISC_R_SUCCESS) 3091135446Strhodes goto out; 3092135446Strhodes } 3093135446Strhodes result = DNS_R_ALIAS; 3094135446Strhodes } else 3095135446Strhodes result = ISC_R_SUCCESS; 3096135446Strhodes 3097135446Strhodes /* 3098135446Strhodes * Copy out error flags from the name structure into the find. 3099135446Strhodes */ 3100135446Strhodes find->result_v4 = find_err_map[adbname->fetch_err]; 3101135446Strhodes find->result_v6 = find_err_map[adbname->fetch6_err]; 3102135446Strhodes 3103135446Strhodes out: 3104135446Strhodes if (find != NULL) { 3105135446Strhodes *findp = find; 3106135446Strhodes 3107135446Strhodes if (want_event) { 3108135446Strhodes isc_task_t *taskp; 3109135446Strhodes 3110135446Strhodes INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0); 3111135446Strhodes taskp = NULL; 3112135446Strhodes isc_task_attach(task, &taskp); 3113135446Strhodes find->event.ev_sender = taskp; 3114135446Strhodes find->event.ev_action = action; 3115135446Strhodes find->event.ev_arg = arg; 3116135446Strhodes } 3117135446Strhodes } 3118135446Strhodes 3119165071Sdougb UNLOCK(&adb->namelocks[bucket]); 3120135446Strhodes 3121135446Strhodes return (result); 3122135446Strhodes} 3123135446Strhodes 3124135446Strhodesvoid 3125135446Strhodesdns_adb_destroyfind(dns_adbfind_t **findp) { 3126135446Strhodes dns_adbfind_t *find; 3127135446Strhodes dns_adbentry_t *entry; 3128135446Strhodes dns_adbaddrinfo_t *ai; 3129135446Strhodes int bucket; 3130135446Strhodes dns_adb_t *adb; 3131214586Sdougb isc_boolean_t overmem; 3132135446Strhodes 3133135446Strhodes REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp)); 3134135446Strhodes find = *findp; 3135135446Strhodes *findp = NULL; 3136135446Strhodes 3137135446Strhodes LOCK(&find->lock); 3138135446Strhodes 3139135446Strhodes DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find); 3140135446Strhodes 3141135446Strhodes adb = find->adb; 3142135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3143135446Strhodes 3144135446Strhodes REQUIRE(FIND_EVENTFREED(find)); 3145135446Strhodes 3146135446Strhodes bucket = find->name_bucket; 3147135446Strhodes INSIST(bucket == DNS_ADB_INVALIDBUCKET); 3148135446Strhodes 3149135446Strhodes UNLOCK(&find->lock); 3150135446Strhodes 3151135446Strhodes /* 3152135446Strhodes * The find doesn't exist on any list, and nothing is locked. 3153135446Strhodes * Return the find to the memory pool, and decrement the adb's 3154135446Strhodes * reference count. 3155135446Strhodes */ 3156214586Sdougb overmem = isc_mem_isovermem(adb->mctx); 3157135446Strhodes ai = ISC_LIST_HEAD(find->list); 3158135446Strhodes while (ai != NULL) { 3159135446Strhodes ISC_LIST_UNLINK(find->list, ai, publink); 3160135446Strhodes entry = ai->entry; 3161135446Strhodes ai->entry = NULL; 3162135446Strhodes INSIST(DNS_ADBENTRY_VALID(entry)); 3163214586Sdougb RUNTIME_CHECK(dec_entry_refcnt(adb, overmem, entry, ISC_TRUE) == 3164135446Strhodes ISC_FALSE); 3165135446Strhodes free_adbaddrinfo(adb, &ai); 3166135446Strhodes ai = ISC_LIST_HEAD(find->list); 3167135446Strhodes } 3168135446Strhodes 3169135446Strhodes /* 3170135446Strhodes * WARNING: The find is freed with the adb locked. This is done 3171135446Strhodes * to avoid a race condition where we free the find, some other 3172135446Strhodes * thread tests to see if it should be destroyed, detects it should 3173135446Strhodes * be, destroys it, and then we try to lock it for our check, but the 3174135446Strhodes * lock is destroyed. 3175135446Strhodes */ 3176135446Strhodes LOCK(&adb->lock); 3177135446Strhodes if (free_adbfind(adb, &find)) 3178135446Strhodes check_exit(adb); 3179135446Strhodes UNLOCK(&adb->lock); 3180135446Strhodes} 3181135446Strhodes 3182135446Strhodesvoid 3183135446Strhodesdns_adb_cancelfind(dns_adbfind_t *find) { 3184135446Strhodes isc_event_t *ev; 3185135446Strhodes isc_task_t *task; 3186135446Strhodes dns_adb_t *adb; 3187135446Strhodes int bucket; 3188135446Strhodes int unlock_bucket; 3189135446Strhodes 3190135446Strhodes LOCK(&find->lock); 3191135446Strhodes 3192135446Strhodes DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find); 3193135446Strhodes 3194135446Strhodes adb = find->adb; 3195135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3196135446Strhodes 3197135446Strhodes REQUIRE(!FIND_EVENTFREED(find)); 3198135446Strhodes REQUIRE(FIND_WANTEVENT(find)); 3199135446Strhodes 3200135446Strhodes bucket = find->name_bucket; 3201135446Strhodes if (bucket == DNS_ADB_INVALIDBUCKET) 3202135446Strhodes goto cleanup; 3203135446Strhodes 3204135446Strhodes /* 3205135446Strhodes * We need to get the adbname's lock to unlink the find. 3206135446Strhodes */ 3207135446Strhodes unlock_bucket = bucket; 3208135446Strhodes violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]); 3209135446Strhodes bucket = find->name_bucket; 3210135446Strhodes if (bucket != DNS_ADB_INVALIDBUCKET) { 3211135446Strhodes ISC_LIST_UNLINK(find->adbname->finds, find, plink); 3212135446Strhodes find->adbname = NULL; 3213135446Strhodes find->name_bucket = DNS_ADB_INVALIDBUCKET; 3214135446Strhodes } 3215135446Strhodes UNLOCK(&adb->namelocks[unlock_bucket]); 3216135446Strhodes bucket = DNS_ADB_INVALIDBUCKET; 3217225361Sdougb POST(bucket); 3218135446Strhodes 3219135446Strhodes cleanup: 3220135446Strhodes 3221135446Strhodes if (!FIND_EVENTSENT(find)) { 3222135446Strhodes ev = &find->event; 3223135446Strhodes task = ev->ev_sender; 3224135446Strhodes ev->ev_sender = find; 3225135446Strhodes ev->ev_type = DNS_EVENT_ADBCANCELED; 3226135446Strhodes ev->ev_destroy = event_free; 3227135446Strhodes ev->ev_destroy_arg = find; 3228135446Strhodes find->result_v4 = ISC_R_CANCELED; 3229135446Strhodes find->result_v6 = ISC_R_CANCELED; 3230135446Strhodes 3231135446Strhodes DP(DEF_LEVEL, "sending event %p to task %p for find %p", 3232135446Strhodes ev, task, find); 3233135446Strhodes 3234135446Strhodes isc_task_sendanddetach(&task, (isc_event_t **)&ev); 3235135446Strhodes } 3236135446Strhodes 3237135446Strhodes UNLOCK(&find->lock); 3238135446Strhodes} 3239135446Strhodes 3240135446Strhodesvoid 3241135446Strhodesdns_adb_dump(dns_adb_t *adb, FILE *f) { 3242224092Sdougb unsigned int i; 3243143731Sdougb isc_stdtime_t now; 3244143731Sdougb 3245135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3246135446Strhodes REQUIRE(f != NULL); 3247135446Strhodes 3248135446Strhodes /* 3249135446Strhodes * Lock the adb itself, lock all the name buckets, then lock all 3250135446Strhodes * the entry buckets. This should put the adb into a state where 3251135446Strhodes * nothing can change, so we can iterate through everything and 3252135446Strhodes * print at our leisure. 3253135446Strhodes */ 3254135446Strhodes 3255135446Strhodes LOCK(&adb->lock); 3256143731Sdougb isc_stdtime_get(&now); 3257143731Sdougb 3258224092Sdougb for (i = 0; i < adb->nnames; i++) 3259143731Sdougb RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE); 3260224092Sdougb for (i = 0; i < adb->nentries; i++) 3261143731Sdougb RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE); 3262143731Sdougb 3263143731Sdougb dump_adb(adb, f, ISC_FALSE, now); 3264135446Strhodes UNLOCK(&adb->lock); 3265135446Strhodes} 3266135446Strhodes 3267135446Strhodesstatic void 3268135446Strhodesdump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) { 3269135446Strhodes if (value == INT_MAX) 3270135446Strhodes return; 3271135446Strhodes fprintf(f, " [%s TTL %d]", legend, value - now); 3272135446Strhodes} 3273135446Strhodes 3274135446Strhodesstatic void 3275143731Sdougbdump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) { 3276224092Sdougb unsigned int i; 3277135446Strhodes dns_adbname_t *name; 3278143731Sdougb dns_adbentry_t *entry; 3279135446Strhodes 3280135446Strhodes fprintf(f, ";\n; Address database dump\n;\n"); 3281135446Strhodes if (debug) 3282135446Strhodes fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n", 3283135446Strhodes adb, adb->erefcnt, adb->irefcnt, 3284135446Strhodes isc_mempool_getallocated(adb->nhmp)); 3285135446Strhodes 3286224092Sdougb for (i = 0; i < adb->nnames; i++) 3287135446Strhodes LOCK(&adb->namelocks[i]); 3288224092Sdougb for (i = 0; i < adb->nentries; i++) 3289135446Strhodes LOCK(&adb->entrylocks[i]); 3290135446Strhodes 3291135446Strhodes /* 3292135446Strhodes * Dump the names 3293135446Strhodes */ 3294224092Sdougb for (i = 0; i < adb->nnames; i++) { 3295135446Strhodes name = ISC_LIST_HEAD(adb->names[i]); 3296135446Strhodes if (name == NULL) 3297135446Strhodes continue; 3298135446Strhodes if (debug) 3299135446Strhodes fprintf(f, "; bucket %d\n", i); 3300135446Strhodes for (; 3301135446Strhodes name != NULL; 3302135446Strhodes name = ISC_LIST_NEXT(name, plink)) 3303135446Strhodes { 3304135446Strhodes if (debug) 3305135446Strhodes fprintf(f, "; name %p (flags %08x)\n", 3306135446Strhodes name, name->flags); 3307135446Strhodes 3308135446Strhodes fprintf(f, "; "); 3309135446Strhodes print_dns_name(f, &name->name); 3310135446Strhodes if (dns_name_countlabels(&name->target) > 0) { 3311135446Strhodes fprintf(f, " alias "); 3312135446Strhodes print_dns_name(f, &name->target); 3313135446Strhodes } 3314135446Strhodes 3315135446Strhodes dump_ttl(f, "v4", name->expire_v4, now); 3316135446Strhodes dump_ttl(f, "v6", name->expire_v6, now); 3317135446Strhodes dump_ttl(f, "target", name->expire_target, now); 3318135446Strhodes 3319135446Strhodes fprintf(f, " [v4 %s] [v6 %s]", 3320135446Strhodes errnames[name->fetch_err], 3321135446Strhodes errnames[name->fetch6_err]); 3322135446Strhodes 3323135446Strhodes fprintf(f, "\n"); 3324135446Strhodes 3325135446Strhodes print_namehook_list(f, "v4", &name->v4, debug, now); 3326135446Strhodes print_namehook_list(f, "v6", &name->v6, debug, now); 3327135446Strhodes 3328135446Strhodes if (debug) 3329135446Strhodes print_fetch_list(f, name); 3330135446Strhodes if (debug) 3331135446Strhodes print_find_list(f, name); 3332135446Strhodes 3333135446Strhodes } 3334135446Strhodes } 3335135446Strhodes 3336143731Sdougb fprintf(f, ";\n; Unassociated entries\n;\n"); 3337143731Sdougb 3338224092Sdougb for (i = 0; i < adb->nentries; i++) { 3339143731Sdougb entry = ISC_LIST_HEAD(adb->entries[i]); 3340143731Sdougb while (entry != NULL) { 3341143731Sdougb if (entry->refcnt == 0) 3342143731Sdougb dump_entry(f, entry, debug, now); 3343143731Sdougb entry = ISC_LIST_NEXT(entry, plink); 3344143731Sdougb } 3345143731Sdougb } 3346143731Sdougb 3347135446Strhodes /* 3348135446Strhodes * Unlock everything 3349135446Strhodes */ 3350224092Sdougb for (i = 0; i < adb->nentries; i++) 3351135446Strhodes UNLOCK(&adb->entrylocks[i]); 3352224092Sdougb for (i = 0; i < adb->nnames; i++) 3353135446Strhodes UNLOCK(&adb->namelocks[i]); 3354135446Strhodes} 3355135446Strhodes 3356135446Strhodesstatic void 3357135446Strhodesdump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug, 3358135446Strhodes isc_stdtime_t now) 3359135446Strhodes{ 3360135446Strhodes char addrbuf[ISC_NETADDR_FORMATSIZE]; 3361170222Sdougb char typebuf[DNS_RDATATYPE_FORMATSIZE]; 3362135446Strhodes isc_netaddr_t netaddr; 3363170222Sdougb dns_adblameinfo_t *li; 3364135446Strhodes 3365135446Strhodes isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr); 3366135446Strhodes isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf)); 3367135446Strhodes 3368135446Strhodes if (debug) 3369135446Strhodes fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt); 3370135446Strhodes 3371135446Strhodes fprintf(f, ";\t%s [srtt %u] [flags %08x]", 3372135446Strhodes addrbuf, entry->srtt, entry->flags); 3373143731Sdougb if (entry->expires != 0) 3374143731Sdougb fprintf(f, " [ttl %d]", entry->expires - now); 3375135446Strhodes fprintf(f, "\n"); 3376170222Sdougb for (li = ISC_LIST_HEAD(entry->lameinfo); 3377170222Sdougb li != NULL; 3378170222Sdougb li = ISC_LIST_NEXT(li, plink)) { 3379135446Strhodes fprintf(f, ";\t\t"); 3380170222Sdougb print_dns_name(f, &li->qname); 3381170222Sdougb dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf)); 3382170222Sdougb fprintf(f, " %s [lame TTL %d]\n", typebuf, 3383170222Sdougb li->lame_timer - now); 3384135446Strhodes } 3385135446Strhodes} 3386135446Strhodes 3387135446Strhodesvoid 3388135446Strhodesdns_adb_dumpfind(dns_adbfind_t *find, FILE *f) { 3389135446Strhodes char tmp[512]; 3390135446Strhodes const char *tmpp; 3391135446Strhodes dns_adbaddrinfo_t *ai; 3392135446Strhodes isc_sockaddr_t *sa; 3393135446Strhodes 3394135446Strhodes /* 3395135446Strhodes * Not used currently, in the API Just In Case we 3396135446Strhodes * want to dump out the name and/or entries too. 3397135446Strhodes */ 3398135446Strhodes 3399135446Strhodes LOCK(&find->lock); 3400135446Strhodes 3401135446Strhodes fprintf(f, ";Find %p\n", find); 3402135446Strhodes fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n", 3403135446Strhodes find->query_pending, find->partial_result, 3404135446Strhodes find->options, find->flags); 3405135446Strhodes fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n", 3406135446Strhodes find->name_bucket, find->adbname, find->event.ev_sender); 3407135446Strhodes 3408135446Strhodes ai = ISC_LIST_HEAD(find->list); 3409135446Strhodes if (ai != NULL) 3410135446Strhodes fprintf(f, "\tAddresses:\n"); 3411135446Strhodes while (ai != NULL) { 3412135446Strhodes sa = &ai->sockaddr; 3413135446Strhodes switch (sa->type.sa.sa_family) { 3414135446Strhodes case AF_INET: 3415135446Strhodes tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr, 3416135446Strhodes tmp, sizeof(tmp)); 3417135446Strhodes break; 3418135446Strhodes case AF_INET6: 3419135446Strhodes tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr, 3420135446Strhodes tmp, sizeof(tmp)); 3421135446Strhodes break; 3422135446Strhodes default: 3423135446Strhodes tmpp = "UnkFamily"; 3424135446Strhodes } 3425135446Strhodes 3426135446Strhodes if (tmpp == NULL) 3427135446Strhodes tmpp = "BadAddress"; 3428135446Strhodes 3429135446Strhodes fprintf(f, "\t\tentry %p, flags %08x" 3430135446Strhodes " srtt %u addr %s\n", 3431135446Strhodes ai->entry, ai->flags, ai->srtt, tmpp); 3432135446Strhodes 3433135446Strhodes ai = ISC_LIST_NEXT(ai, publink); 3434135446Strhodes } 3435135446Strhodes 3436135446Strhodes UNLOCK(&find->lock); 3437135446Strhodes} 3438135446Strhodes 3439135446Strhodesstatic void 3440135446Strhodesprint_dns_name(FILE *f, dns_name_t *name) { 3441135446Strhodes char buf[DNS_NAME_FORMATSIZE]; 3442135446Strhodes 3443135446Strhodes INSIST(f != NULL); 3444135446Strhodes 3445135446Strhodes dns_name_format(name, buf, sizeof(buf)); 3446135446Strhodes fprintf(f, "%s", buf); 3447135446Strhodes} 3448135446Strhodes 3449135446Strhodesstatic void 3450135446Strhodesprint_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list, 3451135446Strhodes isc_boolean_t debug, isc_stdtime_t now) 3452135446Strhodes{ 3453135446Strhodes dns_adbnamehook_t *nh; 3454135446Strhodes 3455135446Strhodes for (nh = ISC_LIST_HEAD(*list); 3456135446Strhodes nh != NULL; 3457135446Strhodes nh = ISC_LIST_NEXT(nh, plink)) 3458135446Strhodes { 3459135446Strhodes if (debug) 3460135446Strhodes fprintf(f, ";\tHook(%s) %p\n", legend, nh); 3461135446Strhodes dump_entry(f, nh->entry, debug, now); 3462135446Strhodes } 3463135446Strhodes} 3464135446Strhodes 3465135446Strhodesstatic inline void 3466135446Strhodesprint_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) { 3467193149Sdougb fprintf(f, "\t\tFetch(%s): %p -> { fetch %p }\n", 3468193149Sdougb type, ft, ft->fetch); 3469135446Strhodes} 3470135446Strhodes 3471135446Strhodesstatic void 3472135446Strhodesprint_fetch_list(FILE *f, dns_adbname_t *n) { 3473135446Strhodes if (NAME_FETCH_A(n)) 3474135446Strhodes print_fetch(f, n->fetch_a, "A"); 3475135446Strhodes if (NAME_FETCH_AAAA(n)) 3476135446Strhodes print_fetch(f, n->fetch_aaaa, "AAAA"); 3477135446Strhodes} 3478135446Strhodes 3479135446Strhodesstatic void 3480135446Strhodesprint_find_list(FILE *f, dns_adbname_t *name) { 3481135446Strhodes dns_adbfind_t *find; 3482135446Strhodes 3483135446Strhodes find = ISC_LIST_HEAD(name->finds); 3484135446Strhodes while (find != NULL) { 3485135446Strhodes dns_adb_dumpfind(find, f); 3486135446Strhodes find = ISC_LIST_NEXT(find, plink); 3487135446Strhodes } 3488135446Strhodes} 3489135446Strhodes 3490135446Strhodesstatic isc_result_t 3491135446Strhodesdbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype) 3492135446Strhodes{ 3493135446Strhodes isc_result_t result; 3494135446Strhodes dns_rdataset_t rdataset; 3495135446Strhodes dns_adb_t *adb; 3496135446Strhodes dns_fixedname_t foundname; 3497135446Strhodes dns_name_t *fname; 3498135446Strhodes 3499135446Strhodes INSIST(DNS_ADBNAME_VALID(adbname)); 3500135446Strhodes adb = adbname->adb; 3501135446Strhodes INSIST(DNS_ADB_VALID(adb)); 3502135446Strhodes INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa); 3503135446Strhodes 3504135446Strhodes dns_fixedname_init(&foundname); 3505193149Sdougb fname = dns_fixedname_name(&foundname); 3506135446Strhodes dns_rdataset_init(&rdataset); 3507135446Strhodes 3508135446Strhodes if (rdtype == dns_rdatatype_a) 3509135446Strhodes adbname->fetch_err = FIND_ERR_UNEXPECTED; 3510135446Strhodes else 3511135446Strhodes adbname->fetch6_err = FIND_ERR_UNEXPECTED; 3512135446Strhodes 3513224092Sdougb /* 3514224092Sdougb * We need to specify whether to search static-stub zones (if 3515224092Sdougb * configured) depending on whether this is a "start at zone" lookup, 3516224092Sdougb * i.e., whether it's a "bailiwick" glue. If it's bailiwick (in which 3517224092Sdougb * case NAME_STARTATZONE is set) we need to stop the search at any 3518224092Sdougb * matching static-stub zone without looking into the cache to honor 3519224092Sdougb * the configuration on which server we should send queries to. 3520224092Sdougb */ 3521224092Sdougb result = dns_view_find2(adb->view, &adbname->name, rdtype, now, 3522224092Sdougb NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0, 3523224092Sdougb ISC_TF(NAME_HINTOK(adbname)), 3524224092Sdougb (adbname->flags & NAME_STARTATZONE) != 0 ? 3525224092Sdougb ISC_TRUE : ISC_FALSE, 3526224092Sdougb NULL, NULL, fname, &rdataset, NULL); 3527135446Strhodes 3528135446Strhodes /* XXXVIX this switch statement is too sparse to gen a jump table. */ 3529135446Strhodes switch (result) { 3530135446Strhodes case DNS_R_GLUE: 3531135446Strhodes case DNS_R_HINT: 3532135446Strhodes case ISC_R_SUCCESS: 3533135446Strhodes /* 3534135446Strhodes * Found in the database. Even if we can't copy out 3535135446Strhodes * any information, return success, or else a fetch 3536135446Strhodes * will be made, which will only make things worse. 3537135446Strhodes */ 3538135446Strhodes if (rdtype == dns_rdatatype_a) 3539135446Strhodes adbname->fetch_err = FIND_ERR_SUCCESS; 3540135446Strhodes else 3541135446Strhodes adbname->fetch6_err = FIND_ERR_SUCCESS; 3542135446Strhodes result = import_rdataset(adbname, &rdataset, now); 3543135446Strhodes break; 3544135446Strhodes case DNS_R_NXDOMAIN: 3545135446Strhodes case DNS_R_NXRRSET: 3546135446Strhodes /* 3547135446Strhodes * We're authoritative and the data doesn't exist. 3548135446Strhodes * Make up a negative cache entry so we don't ask again 3549135446Strhodes * for a while. 3550135446Strhodes * 3551135446Strhodes * XXXRTH What time should we use? I'm putting in 30 seconds 3552135446Strhodes * for now. 3553135446Strhodes */ 3554135446Strhodes if (rdtype == dns_rdatatype_a) { 3555135446Strhodes adbname->expire_v4 = now + 30; 3556135446Strhodes DP(NCACHE_LEVEL, 3557135446Strhodes "adb name %p: Caching auth negative entry for A", 3558135446Strhodes adbname); 3559135446Strhodes if (result == DNS_R_NXDOMAIN) 3560135446Strhodes adbname->fetch_err = FIND_ERR_NXDOMAIN; 3561135446Strhodes else 3562135446Strhodes adbname->fetch_err = FIND_ERR_NXRRSET; 3563135446Strhodes } else { 3564135446Strhodes DP(NCACHE_LEVEL, 3565135446Strhodes "adb name %p: Caching auth negative entry for AAAA", 3566135446Strhodes adbname); 3567135446Strhodes adbname->expire_v6 = now + 30; 3568135446Strhodes if (result == DNS_R_NXDOMAIN) 3569135446Strhodes adbname->fetch6_err = FIND_ERR_NXDOMAIN; 3570135446Strhodes else 3571135446Strhodes adbname->fetch6_err = FIND_ERR_NXRRSET; 3572135446Strhodes } 3573135446Strhodes break; 3574135446Strhodes case DNS_R_NCACHENXDOMAIN: 3575135446Strhodes case DNS_R_NCACHENXRRSET: 3576135446Strhodes /* 3577135446Strhodes * We found a negative cache entry. Pull the TTL from it 3578135446Strhodes * so we won't ask again for a while. 3579135446Strhodes */ 3580135446Strhodes rdataset.ttl = ttlclamp(rdataset.ttl); 3581135446Strhodes if (rdtype == dns_rdatatype_a) { 3582135446Strhodes adbname->expire_v4 = rdataset.ttl + now; 3583135446Strhodes if (result == DNS_R_NCACHENXDOMAIN) 3584135446Strhodes adbname->fetch_err = FIND_ERR_NXDOMAIN; 3585135446Strhodes else 3586135446Strhodes adbname->fetch_err = FIND_ERR_NXRRSET; 3587135446Strhodes DP(NCACHE_LEVEL, 3588135446Strhodes "adb name %p: Caching negative entry for A (ttl %u)", 3589135446Strhodes adbname, rdataset.ttl); 3590135446Strhodes } else { 3591135446Strhodes DP(NCACHE_LEVEL, 3592135446Strhodes "adb name %p: Caching negative entry for AAAA (ttl %u)", 3593135446Strhodes adbname, rdataset.ttl); 3594135446Strhodes adbname->expire_v6 = rdataset.ttl + now; 3595135446Strhodes if (result == DNS_R_NCACHENXDOMAIN) 3596135446Strhodes adbname->fetch6_err = FIND_ERR_NXDOMAIN; 3597135446Strhodes else 3598135446Strhodes adbname->fetch6_err = FIND_ERR_NXRRSET; 3599135446Strhodes } 3600135446Strhodes break; 3601135446Strhodes case DNS_R_CNAME: 3602135446Strhodes case DNS_R_DNAME: 3603135446Strhodes /* 3604135446Strhodes * Clear the hint and glue flags, so this will match 3605135446Strhodes * more often. 3606135446Strhodes */ 3607135446Strhodes adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK); 3608135446Strhodes 3609135446Strhodes rdataset.ttl = ttlclamp(rdataset.ttl); 3610135446Strhodes clean_target(adb, &adbname->target); 3611135446Strhodes adbname->expire_target = INT_MAX; 3612135446Strhodes result = set_target(adb, &adbname->name, fname, &rdataset, 3613135446Strhodes &adbname->target); 3614135446Strhodes if (result == ISC_R_SUCCESS) { 3615135446Strhodes result = DNS_R_ALIAS; 3616135446Strhodes DP(NCACHE_LEVEL, 3617135446Strhodes "adb name %p: caching alias target", 3618135446Strhodes adbname); 3619135446Strhodes adbname->expire_target = rdataset.ttl + now; 3620135446Strhodes } 3621135446Strhodes if (rdtype == dns_rdatatype_a) 3622135446Strhodes adbname->fetch_err = FIND_ERR_SUCCESS; 3623135446Strhodes else 3624135446Strhodes adbname->fetch6_err = FIND_ERR_SUCCESS; 3625135446Strhodes break; 3626135446Strhodes } 3627135446Strhodes 3628135446Strhodes if (dns_rdataset_isassociated(&rdataset)) 3629135446Strhodes dns_rdataset_disassociate(&rdataset); 3630135446Strhodes 3631135446Strhodes return (result); 3632135446Strhodes} 3633135446Strhodes 3634135446Strhodesstatic void 3635135446Strhodesfetch_callback(isc_task_t *task, isc_event_t *ev) { 3636135446Strhodes dns_fetchevent_t *dev; 3637135446Strhodes dns_adbname_t *name; 3638135446Strhodes dns_adb_t *adb; 3639135446Strhodes dns_adbfetch_t *fetch; 3640135446Strhodes int bucket; 3641135446Strhodes isc_eventtype_t ev_status; 3642135446Strhodes isc_stdtime_t now; 3643135446Strhodes isc_result_t result; 3644135446Strhodes unsigned int address_type; 3645135446Strhodes isc_boolean_t want_check_exit = ISC_FALSE; 3646275672Sdelphij isc_uint32_t qtotal = 0; 3647135446Strhodes 3648135446Strhodes UNUSED(task); 3649135446Strhodes 3650135446Strhodes INSIST(ev->ev_type == DNS_EVENT_FETCHDONE); 3651135446Strhodes dev = (dns_fetchevent_t *)ev; 3652135446Strhodes name = ev->ev_arg; 3653135446Strhodes INSIST(DNS_ADBNAME_VALID(name)); 3654135446Strhodes adb = name->adb; 3655135446Strhodes INSIST(DNS_ADB_VALID(adb)); 3656135446Strhodes 3657275672Sdelphij qtotal = dev->qtotal; 3658275672Sdelphij 3659135446Strhodes bucket = name->lock_bucket; 3660135446Strhodes LOCK(&adb->namelocks[bucket]); 3661135446Strhodes 3662135446Strhodes INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name)); 3663135446Strhodes address_type = 0; 3664135446Strhodes if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) { 3665135446Strhodes address_type = DNS_ADBFIND_INET; 3666135446Strhodes fetch = name->fetch_a; 3667135446Strhodes name->fetch_a = NULL; 3668135446Strhodes } else if (NAME_FETCH_AAAA(name) 3669135446Strhodes && (name->fetch_aaaa->fetch == dev->fetch)) { 3670135446Strhodes address_type = DNS_ADBFIND_INET6; 3671135446Strhodes fetch = name->fetch_aaaa; 3672135446Strhodes name->fetch_aaaa = NULL; 3673186462Sdougb } else 3674186462Sdougb fetch = NULL; 3675135446Strhodes 3676186462Sdougb INSIST(address_type != 0 && fetch != NULL); 3677186462Sdougb 3678135446Strhodes dns_resolver_destroyfetch(&fetch->fetch); 3679135446Strhodes dev->fetch = NULL; 3680135446Strhodes 3681135446Strhodes ev_status = DNS_EVENT_ADBNOMOREADDRESSES; 3682135446Strhodes 3683135446Strhodes /* 3684135446Strhodes * Cleanup things we don't care about. 3685135446Strhodes */ 3686135446Strhodes if (dev->node != NULL) 3687135446Strhodes dns_db_detachnode(dev->db, &dev->node); 3688135446Strhodes if (dev->db != NULL) 3689135446Strhodes dns_db_detach(&dev->db); 3690135446Strhodes 3691135446Strhodes /* 3692135446Strhodes * If this name is marked as dead, clean up, throwing away 3693135446Strhodes * potentially good data. 3694135446Strhodes */ 3695135446Strhodes if (NAME_DEAD(name)) { 3696135446Strhodes free_adbfetch(adb, &fetch); 3697135446Strhodes isc_event_free(&ev); 3698135446Strhodes 3699135446Strhodes want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED); 3700135446Strhodes 3701135446Strhodes UNLOCK(&adb->namelocks[bucket]); 3702135446Strhodes 3703135446Strhodes if (want_check_exit) { 3704135446Strhodes LOCK(&adb->lock); 3705135446Strhodes check_exit(adb); 3706135446Strhodes UNLOCK(&adb->lock); 3707135446Strhodes } 3708135446Strhodes 3709135446Strhodes return; 3710135446Strhodes } 3711135446Strhodes 3712135446Strhodes isc_stdtime_get(&now); 3713135446Strhodes 3714135446Strhodes /* 3715135446Strhodes * If we got a negative cache response, remember it. 3716135446Strhodes */ 3717135446Strhodes if (NCACHE_RESULT(dev->result)) { 3718135446Strhodes dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl); 3719135446Strhodes if (address_type == DNS_ADBFIND_INET) { 3720135446Strhodes DP(NCACHE_LEVEL, "adb fetch name %p: " 3721135446Strhodes "caching negative entry for A (ttl %u)", 3722135446Strhodes name, dev->rdataset->ttl); 3723135446Strhodes name->expire_v4 = ISC_MIN(name->expire_v4, 3724135446Strhodes dev->rdataset->ttl + now); 3725135446Strhodes if (dev->result == DNS_R_NCACHENXDOMAIN) 3726135446Strhodes name->fetch_err = FIND_ERR_NXDOMAIN; 3727135446Strhodes else 3728135446Strhodes name->fetch_err = FIND_ERR_NXRRSET; 3729193149Sdougb inc_stats(adb, dns_resstatscounter_gluefetchv4fail); 3730135446Strhodes } else { 3731135446Strhodes DP(NCACHE_LEVEL, "adb fetch name %p: " 3732135446Strhodes "caching negative entry for AAAA (ttl %u)", 3733135446Strhodes name, dev->rdataset->ttl); 3734135446Strhodes name->expire_v6 = ISC_MIN(name->expire_v6, 3735135446Strhodes dev->rdataset->ttl + now); 3736135446Strhodes if (dev->result == DNS_R_NCACHENXDOMAIN) 3737135446Strhodes name->fetch6_err = FIND_ERR_NXDOMAIN; 3738135446Strhodes else 3739135446Strhodes name->fetch6_err = FIND_ERR_NXRRSET; 3740193149Sdougb inc_stats(adb, dns_resstatscounter_gluefetchv6fail); 3741135446Strhodes } 3742135446Strhodes goto out; 3743135446Strhodes } 3744135446Strhodes 3745135446Strhodes /* 3746135446Strhodes * Handle CNAME/DNAME. 3747135446Strhodes */ 3748135446Strhodes if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) { 3749135446Strhodes dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl); 3750135446Strhodes clean_target(adb, &name->target); 3751135446Strhodes name->expire_target = INT_MAX; 3752135446Strhodes result = set_target(adb, &name->name, 3753135446Strhodes dns_fixedname_name(&dev->foundname), 3754135446Strhodes dev->rdataset, 3755135446Strhodes &name->target); 3756135446Strhodes if (result == ISC_R_SUCCESS) { 3757135446Strhodes DP(NCACHE_LEVEL, 3758135446Strhodes "adb fetch name %p: caching alias target", 3759135446Strhodes name); 3760135446Strhodes name->expire_target = dev->rdataset->ttl + now; 3761135446Strhodes } 3762135446Strhodes goto check_result; 3763135446Strhodes } 3764135446Strhodes 3765135446Strhodes /* 3766135446Strhodes * Did we get back junk? If so, and there are no more fetches 3767135446Strhodes * sitting out there, tell all the finds about it. 3768135446Strhodes */ 3769135446Strhodes if (dev->result != ISC_R_SUCCESS) { 3770135446Strhodes char buf[DNS_NAME_FORMATSIZE]; 3771135446Strhodes 3772135446Strhodes dns_name_format(&name->name, buf, sizeof(buf)); 3773135446Strhodes DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s", 3774135446Strhodes buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA", 3775135446Strhodes dns_result_totext(dev->result)); 3776275672Sdelphij /* 3777275672Sdelphij * Don't record a failure unless this is the initial 3778275672Sdelphij * fetch of a chain. 3779275672Sdelphij */ 3780275672Sdelphij if (fetch->depth > 1) 3781275672Sdelphij goto out; 3782135446Strhodes /* XXXMLG Don't pound on bad servers. */ 3783135446Strhodes if (address_type == DNS_ADBFIND_INET) { 3784135446Strhodes name->expire_v4 = ISC_MIN(name->expire_v4, now + 300); 3785135446Strhodes name->fetch_err = FIND_ERR_FAILURE; 3786193149Sdougb inc_stats(adb, dns_resstatscounter_gluefetchv4fail); 3787135446Strhodes } else { 3788135446Strhodes name->expire_v6 = ISC_MIN(name->expire_v6, now + 300); 3789135446Strhodes name->fetch6_err = FIND_ERR_FAILURE; 3790193149Sdougb inc_stats(adb, dns_resstatscounter_gluefetchv6fail); 3791135446Strhodes } 3792135446Strhodes goto out; 3793135446Strhodes } 3794135446Strhodes 3795135446Strhodes /* 3796135446Strhodes * We got something potentially useful. 3797135446Strhodes */ 3798135446Strhodes result = import_rdataset(name, &fetch->rdataset, now); 3799135446Strhodes 3800135446Strhodes check_result: 3801135446Strhodes if (result == ISC_R_SUCCESS) { 3802135446Strhodes ev_status = DNS_EVENT_ADBMOREADDRESSES; 3803135446Strhodes if (address_type == DNS_ADBFIND_INET) 3804135446Strhodes name->fetch_err = FIND_ERR_SUCCESS; 3805135446Strhodes else 3806135446Strhodes name->fetch6_err = FIND_ERR_SUCCESS; 3807135446Strhodes } 3808135446Strhodes 3809135446Strhodes out: 3810135446Strhodes free_adbfetch(adb, &fetch); 3811135446Strhodes isc_event_free(&ev); 3812135446Strhodes 3813275672Sdelphij clean_finds_at_name(name, ev_status, qtotal, address_type); 3814135446Strhodes 3815135446Strhodes UNLOCK(&adb->namelocks[bucket]); 3816135446Strhodes} 3817135446Strhodes 3818135446Strhodesstatic isc_result_t 3819275672Sdelphijfetch_name(dns_adbname_t *adbname, isc_boolean_t start_at_zone, 3820275672Sdelphij unsigned int depth, dns_rdatatype_t type) 3821135446Strhodes{ 3822135446Strhodes isc_result_t result; 3823135446Strhodes dns_adbfetch_t *fetch = NULL; 3824135446Strhodes dns_adb_t *adb; 3825135446Strhodes dns_fixedname_t fixed; 3826135446Strhodes dns_name_t *name; 3827135446Strhodes dns_rdataset_t rdataset; 3828135446Strhodes dns_rdataset_t *nameservers; 3829135446Strhodes unsigned int options; 3830135446Strhodes 3831135446Strhodes INSIST(DNS_ADBNAME_VALID(adbname)); 3832135446Strhodes adb = adbname->adb; 3833135446Strhodes INSIST(DNS_ADB_VALID(adb)); 3834135446Strhodes 3835135446Strhodes INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) || 3836135446Strhodes (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname))); 3837135446Strhodes 3838135446Strhodes adbname->fetch_err = FIND_ERR_NOTFOUND; 3839135446Strhodes 3840135446Strhodes name = NULL; 3841135446Strhodes nameservers = NULL; 3842135446Strhodes dns_rdataset_init(&rdataset); 3843135446Strhodes 3844135446Strhodes options = DNS_FETCHOPT_NOVALIDATE; 3845135446Strhodes if (start_at_zone) { 3846135446Strhodes DP(ENTER_LEVEL, 3847135446Strhodes "fetch_name: starting at zone for name %p", 3848135446Strhodes adbname); 3849135446Strhodes dns_fixedname_init(&fixed); 3850135446Strhodes name = dns_fixedname_name(&fixed); 3851135446Strhodes result = dns_view_findzonecut2(adb->view, &adbname->name, name, 3852135446Strhodes 0, 0, ISC_TRUE, ISC_FALSE, 3853135446Strhodes &rdataset, NULL); 3854135446Strhodes if (result != ISC_R_SUCCESS && result != DNS_R_HINT) 3855135446Strhodes goto cleanup; 3856135446Strhodes nameservers = &rdataset; 3857135446Strhodes options |= DNS_FETCHOPT_UNSHARED; 3858135446Strhodes } 3859135446Strhodes 3860135446Strhodes fetch = new_adbfetch(adb); 3861135446Strhodes if (fetch == NULL) { 3862135446Strhodes result = ISC_R_NOMEMORY; 3863135446Strhodes goto cleanup; 3864135446Strhodes } 3865275672Sdelphij fetch->depth = depth; 3866135446Strhodes 3867275672Sdelphij result = dns_resolver_createfetch3(adb->view->resolver, &adbname->name, 3868275672Sdelphij type, name, nameservers, NULL, 3869275672Sdelphij NULL, 0, options, depth, adb->task, 3870275672Sdelphij fetch_callback, adbname, 3871275672Sdelphij &fetch->rdataset, NULL, 3872275672Sdelphij &fetch->fetch); 3873135446Strhodes if (result != ISC_R_SUCCESS) 3874135446Strhodes goto cleanup; 3875135446Strhodes 3876193149Sdougb if (type == dns_rdatatype_a) { 3877135446Strhodes adbname->fetch_a = fetch; 3878193149Sdougb inc_stats(adb, dns_resstatscounter_gluefetchv4); 3879193149Sdougb } else { 3880135446Strhodes adbname->fetch_aaaa = fetch; 3881193149Sdougb inc_stats(adb, dns_resstatscounter_gluefetchv6); 3882193149Sdougb } 3883135446Strhodes fetch = NULL; /* Keep us from cleaning this up below. */ 3884135446Strhodes 3885135446Strhodes cleanup: 3886135446Strhodes if (fetch != NULL) 3887135446Strhodes free_adbfetch(adb, &fetch); 3888135446Strhodes if (dns_rdataset_isassociated(&rdataset)) 3889135446Strhodes dns_rdataset_disassociate(&rdataset); 3890135446Strhodes 3891135446Strhodes return (result); 3892135446Strhodes} 3893135446Strhodes 3894135446Strhodes/* 3895135446Strhodes * XXXMLG Needs to take a find argument and an address info, no zone or adb, 3896135446Strhodes * since these can be extracted from the find itself. 3897135446Strhodes */ 3898135446Strhodesisc_result_t 3899170222Sdougbdns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname, 3900170222Sdougb dns_rdatatype_t qtype, isc_stdtime_t expire_time) 3901135446Strhodes{ 3902170222Sdougb dns_adblameinfo_t *li; 3903135446Strhodes int bucket; 3904135446Strhodes isc_result_t result = ISC_R_SUCCESS; 3905135446Strhodes 3906135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3907135446Strhodes REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3908170222Sdougb REQUIRE(qname != NULL); 3909135446Strhodes 3910135446Strhodes bucket = addr->entry->lock_bucket; 3911135446Strhodes LOCK(&adb->entrylocks[bucket]); 3912170222Sdougb li = ISC_LIST_HEAD(addr->entry->lameinfo); 3913170222Sdougb while (li != NULL && 3914170222Sdougb (li->qtype != qtype || !dns_name_equal(qname, &li->qname))) 3915170222Sdougb li = ISC_LIST_NEXT(li, plink); 3916170222Sdougb if (li != NULL) { 3917170222Sdougb if (expire_time > li->lame_timer) 3918170222Sdougb li->lame_timer = expire_time; 3919135446Strhodes goto unlock; 3920135446Strhodes } 3921170222Sdougb li = new_adblameinfo(adb, qname, qtype); 3922170222Sdougb if (li == NULL) { 3923135446Strhodes result = ISC_R_NOMEMORY; 3924135446Strhodes goto unlock; 3925135446Strhodes } 3926135446Strhodes 3927170222Sdougb li->lame_timer = expire_time; 3928135446Strhodes 3929170222Sdougb ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink); 3930135446Strhodes unlock: 3931135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 3932135446Strhodes 3933153816Sdougb return (result); 3934135446Strhodes} 3935135446Strhodes 3936135446Strhodesvoid 3937135446Strhodesdns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr, 3938135446Strhodes unsigned int rtt, unsigned int factor) 3939135446Strhodes{ 3940135446Strhodes int bucket; 3941135446Strhodes unsigned int new_srtt; 3942135446Strhodes isc_stdtime_t now; 3943135446Strhodes 3944135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3945135446Strhodes REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3946135446Strhodes REQUIRE(factor <= 10); 3947135446Strhodes 3948135446Strhodes bucket = addr->entry->lock_bucket; 3949135446Strhodes LOCK(&adb->entrylocks[bucket]); 3950135446Strhodes 3951135446Strhodes if (factor == DNS_ADB_RTTADJAGE) 3952135446Strhodes new_srtt = addr->entry->srtt * 98 / 100; 3953135446Strhodes else 3954135446Strhodes new_srtt = (addr->entry->srtt / 10 * factor) 3955135446Strhodes + (rtt / 10 * (10 - factor)); 3956135446Strhodes 3957135446Strhodes addr->entry->srtt = new_srtt; 3958135446Strhodes addr->srtt = new_srtt; 3959135446Strhodes 3960245163Serwin if (addr->entry->expires == 0) { 3961245163Serwin isc_stdtime_get(&now); 3962245163Serwin addr->entry->expires = now + ADB_ENTRY_WINDOW; 3963245163Serwin } 3964135446Strhodes 3965135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 3966135446Strhodes} 3967135446Strhodes 3968135446Strhodesvoid 3969135446Strhodesdns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr, 3970135446Strhodes unsigned int bits, unsigned int mask) 3971135446Strhodes{ 3972135446Strhodes int bucket; 3973245163Serwin isc_stdtime_t now; 3974135446Strhodes 3975135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3976135446Strhodes REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3977135446Strhodes 3978135446Strhodes bucket = addr->entry->lock_bucket; 3979135446Strhodes LOCK(&adb->entrylocks[bucket]); 3980135446Strhodes 3981135446Strhodes addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask); 3982245163Serwin if (addr->entry->expires == 0) { 3983245163Serwin isc_stdtime_get(&now); 3984245163Serwin addr->entry->expires = now + ADB_ENTRY_WINDOW; 3985245163Serwin } 3986245163Serwin 3987135446Strhodes /* 3988135446Strhodes * Note that we do not update the other bits in addr->flags with 3989135446Strhodes * the most recent values from addr->entry->flags. 3990135446Strhodes */ 3991135446Strhodes addr->flags = (addr->flags & ~mask) | (bits & mask); 3992135446Strhodes 3993135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 3994135446Strhodes} 3995135446Strhodes 3996135446Strhodesisc_result_t 3997135446Strhodesdns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa, 3998135446Strhodes dns_adbaddrinfo_t **addrp, isc_stdtime_t now) 3999135446Strhodes{ 4000135446Strhodes int bucket; 4001135446Strhodes dns_adbentry_t *entry; 4002135446Strhodes dns_adbaddrinfo_t *addr; 4003135446Strhodes isc_result_t result; 4004135446Strhodes in_port_t port; 4005135446Strhodes 4006135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 4007135446Strhodes REQUIRE(addrp != NULL && *addrp == NULL); 4008135446Strhodes 4009135446Strhodes UNUSED(now); 4010135446Strhodes 4011135446Strhodes result = ISC_R_SUCCESS; 4012135446Strhodes bucket = DNS_ADB_INVALIDBUCKET; 4013193149Sdougb entry = find_entry_and_lock(adb, sa, &bucket, now); 4014225361Sdougb INSIST(bucket != DNS_ADB_INVALIDBUCKET); 4015135446Strhodes if (adb->entry_sd[bucket]) { 4016135446Strhodes result = ISC_R_SHUTTINGDOWN; 4017135446Strhodes goto unlock; 4018135446Strhodes } 4019135446Strhodes if (entry == NULL) { 4020135446Strhodes /* 4021135446Strhodes * We don't know anything about this address. 4022135446Strhodes */ 4023135446Strhodes entry = new_adbentry(adb); 4024135446Strhodes if (entry == NULL) { 4025135446Strhodes result = ISC_R_NOMEMORY; 4026135446Strhodes goto unlock; 4027135446Strhodes } 4028135446Strhodes entry->sockaddr = *sa; 4029135446Strhodes link_entry(adb, bucket, entry); 4030135446Strhodes DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry); 4031135446Strhodes } else 4032135446Strhodes DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry); 4033135446Strhodes 4034135446Strhodes port = isc_sockaddr_getport(sa); 4035135446Strhodes addr = new_adbaddrinfo(adb, entry, port); 4036174187Sdougb if (addr == NULL) { 4037174187Sdougb result = ISC_R_NOMEMORY; 4038174187Sdougb } else { 4039135446Strhodes inc_entry_refcnt(adb, entry, ISC_FALSE); 4040135446Strhodes *addrp = addr; 4041135446Strhodes } 4042135446Strhodes 4043135446Strhodes unlock: 4044135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 4045135446Strhodes 4046135446Strhodes return (result); 4047135446Strhodes} 4048135446Strhodes 4049135446Strhodesvoid 4050135446Strhodesdns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) { 4051135446Strhodes dns_adbaddrinfo_t *addr; 4052135446Strhodes dns_adbentry_t *entry; 4053135446Strhodes int bucket; 4054135446Strhodes isc_stdtime_t now; 4055135446Strhodes isc_boolean_t want_check_exit = ISC_FALSE; 4056214586Sdougb isc_boolean_t overmem; 4057135446Strhodes 4058135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 4059135446Strhodes REQUIRE(addrp != NULL); 4060135446Strhodes addr = *addrp; 4061135446Strhodes REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 4062135446Strhodes entry = addr->entry; 4063135446Strhodes REQUIRE(DNS_ADBENTRY_VALID(entry)); 4064135446Strhodes 4065135446Strhodes *addrp = NULL; 4066214586Sdougb overmem = isc_mem_isovermem(adb->mctx); 4067135446Strhodes 4068135446Strhodes bucket = addr->entry->lock_bucket; 4069135446Strhodes LOCK(&adb->entrylocks[bucket]); 4070135446Strhodes 4071245163Serwin if (entry->expires == 0) { 4072245163Serwin isc_stdtime_get(&now); 4073245163Serwin entry->expires = now + ADB_ENTRY_WINDOW; 4074245163Serwin } 4075135446Strhodes 4076214586Sdougb want_check_exit = dec_entry_refcnt(adb, overmem, entry, ISC_FALSE); 4077135446Strhodes 4078135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 4079135446Strhodes 4080135446Strhodes addr->entry = NULL; 4081135446Strhodes free_adbaddrinfo(adb, &addr); 4082135446Strhodes 4083135446Strhodes if (want_check_exit) { 4084135446Strhodes LOCK(&adb->lock); 4085135446Strhodes check_exit(adb); 4086135446Strhodes UNLOCK(&adb->lock); 4087135446Strhodes } 4088135446Strhodes} 4089135446Strhodes 4090135446Strhodesvoid 4091135446Strhodesdns_adb_flush(dns_adb_t *adb) { 4092135446Strhodes unsigned int i; 4093135446Strhodes 4094135446Strhodes INSIST(DNS_ADB_VALID(adb)); 4095135446Strhodes 4096135446Strhodes LOCK(&adb->lock); 4097135446Strhodes 4098143731Sdougb /* 4099143731Sdougb * Call our cleanup routines. 4100143731Sdougb */ 4101224092Sdougb for (i = 0; i < adb->nnames; i++) 4102135446Strhodes RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE); 4103224092Sdougb for (i = 0; i < adb->nentries; i++) 4104135446Strhodes RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE); 4105135446Strhodes 4106135446Strhodes#ifdef DUMP_ADB_AFTER_CLEANING 4107143731Sdougb dump_adb(adb, stdout, ISC_TRUE, INT_MAX); 4108135446Strhodes#endif 4109135446Strhodes 4110135446Strhodes UNLOCK(&adb->lock); 4111135446Strhodes} 4112135446Strhodes 4113135446Strhodesvoid 4114135446Strhodesdns_adb_flushname(dns_adb_t *adb, dns_name_t *name) { 4115135446Strhodes dns_adbname_t *adbname; 4116135446Strhodes dns_adbname_t *nextname; 4117135446Strhodes int bucket; 4118135446Strhodes 4119135446Strhodes INSIST(DNS_ADB_VALID(adb)); 4120135446Strhodes 4121135446Strhodes LOCK(&adb->lock); 4122224092Sdougb bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames; 4123135446Strhodes LOCK(&adb->namelocks[bucket]); 4124135446Strhodes adbname = ISC_LIST_HEAD(adb->names[bucket]); 4125135446Strhodes while (adbname != NULL) { 4126135446Strhodes nextname = ISC_LIST_NEXT(adbname, plink); 4127135446Strhodes if (!NAME_DEAD(adbname) && 4128135446Strhodes dns_name_equal(name, &adbname->name)) { 4129135446Strhodes RUNTIME_CHECK(kill_name(&adbname, 4130135446Strhodes DNS_EVENT_ADBCANCELED) == 4131135446Strhodes ISC_FALSE); 4132135446Strhodes } 4133135446Strhodes adbname = nextname; 4134135446Strhodes } 4135135446Strhodes UNLOCK(&adb->namelocks[bucket]); 4136135446Strhodes UNLOCK(&adb->lock); 4137135446Strhodes} 4138135446Strhodes 4139135446Strhodesstatic void 4140135446Strhodeswater(void *arg, int mark) { 4141214586Sdougb /* 4142214586Sdougb * We're going to change the way to handle overmem condition: use 4143214586Sdougb * isc_mem_isovermem() instead of storing the state via this callback, 4144214586Sdougb * since the latter way tends to cause race conditions. 4145214586Sdougb * To minimize the change, and in case we re-enable the callback 4146214586Sdougb * approach, however, keep this function at the moment. 4147214586Sdougb */ 4148214586Sdougb 4149135446Strhodes dns_adb_t *adb = arg; 4150135446Strhodes isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER); 4151135446Strhodes 4152135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 4153135446Strhodes 4154135446Strhodes DP(ISC_LOG_DEBUG(1), 4155135446Strhodes "adb reached %s water mark", overmem ? "high" : "low"); 4156135446Strhodes} 4157135446Strhodes 4158135446Strhodesvoid 4159254897Serwindns_adb_setadbsize(dns_adb_t *adb, size_t size) { 4160254897Serwin size_t hiwater, lowater; 4161135446Strhodes 4162135446Strhodes INSIST(DNS_ADB_VALID(adb)); 4163135446Strhodes 4164254402Serwin if (size != 0U && size < DNS_ADB_MINADBSIZE) 4165135446Strhodes size = DNS_ADB_MINADBSIZE; 4166135446Strhodes 4167135446Strhodes hiwater = size - (size >> 3); /* Approximately 7/8ths. */ 4168135446Strhodes lowater = size - (size >> 2); /* Approximately 3/4ths. */ 4169135446Strhodes 4170254402Serwin if (size == 0U || hiwater == 0U || lowater == 0U) 4171135446Strhodes isc_mem_setwater(adb->mctx, water, adb, 0, 0); 4172135446Strhodes else 4173135446Strhodes isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater); 4174135446Strhodes} 4175