adb.c revision 254402
1135446Strhodes/* 2254402Serwin * Copyright (C) 2004-2013 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 18234010Sdougb/* $Id$ */ 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; 204135446Strhodes}; 205135446Strhodes 206170222Sdougb/*% 207135446Strhodes * This is a small widget that dangles off a dns_adbname_t. It contains a 208135446Strhodes * pointer to the address information about this host, and a link to the next 209135446Strhodes * namehook that will contain the next address this host has. 210135446Strhodes */ 211135446Strhodesstruct dns_adbnamehook { 212193149Sdougb unsigned int magic; 213193149Sdougb dns_adbentry_t *entry; 214193149Sdougb ISC_LINK(dns_adbnamehook_t) plink; 215135446Strhodes}; 216135446Strhodes 217170222Sdougb/*% 218170222Sdougb * This is a small widget that holds qname-specific information about an 219135446Strhodes * address. Currently limited to lameness, but could just as easily be 220135446Strhodes * extended to other types of information about zones. 221135446Strhodes */ 222170222Sdougbstruct dns_adblameinfo { 223193149Sdougb unsigned int magic; 224135446Strhodes 225193149Sdougb dns_name_t qname; 226193149Sdougb dns_rdatatype_t qtype; 227193149Sdougb isc_stdtime_t lame_timer; 228135446Strhodes 229193149Sdougb ISC_LINK(dns_adblameinfo_t) plink; 230135446Strhodes}; 231135446Strhodes 232170222Sdougb/*% 233135446Strhodes * An address entry. It holds quite a bit of information about addresses, 234135446Strhodes * including edns state (in "flags"), rtt, and of course the address of 235135446Strhodes * the host. 236135446Strhodes */ 237135446Strhodesstruct dns_adbentry { 238193149Sdougb unsigned int magic; 239135446Strhodes 240193149Sdougb int lock_bucket; 241193149Sdougb unsigned int refcnt; 242135446Strhodes 243193149Sdougb unsigned int flags; 244193149Sdougb unsigned int srtt; 245193149Sdougb isc_sockaddr_t sockaddr; 246135446Strhodes 247193149Sdougb isc_stdtime_t expires; 248170222Sdougb /*%< 249135446Strhodes * A nonzero 'expires' field indicates that the entry should 250135446Strhodes * persist until that time. This allows entries found 251135446Strhodes * using dns_adb_findaddrinfo() to persist for a limited time 252135446Strhodes * even though they are not necessarily associated with a 253135446Strhodes * name. 254135446Strhodes */ 255135446Strhodes 256193149Sdougb ISC_LIST(dns_adblameinfo_t) lameinfo; 257193149Sdougb ISC_LINK(dns_adbentry_t) plink; 258234010Sdougb 259135446Strhodes}; 260135446Strhodes 261135446Strhodes/* 262135446Strhodes * Internal functions (and prototypes). 263135446Strhodes */ 264135446Strhodesstatic inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *); 265135446Strhodesstatic inline void free_adbname(dns_adb_t *, dns_adbname_t **); 266135446Strhodesstatic inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *, 267135446Strhodes dns_adbentry_t *); 268135446Strhodesstatic inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **); 269170222Sdougbstatic inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *, dns_name_t *, 270170222Sdougb dns_rdatatype_t); 271170222Sdougbstatic inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **); 272135446Strhodesstatic inline dns_adbentry_t *new_adbentry(dns_adb_t *); 273135446Strhodesstatic inline void free_adbentry(dns_adb_t *, dns_adbentry_t **); 274135446Strhodesstatic inline dns_adbfind_t *new_adbfind(dns_adb_t *); 275135446Strhodesstatic inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **); 276135446Strhodesstatic inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *, 277135446Strhodes in_port_t); 278135446Strhodesstatic inline dns_adbfetch_t *new_adbfetch(dns_adb_t *); 279135446Strhodesstatic inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **); 280135446Strhodesstatic inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *, 281135446Strhodes unsigned int, int *); 282135446Strhodesstatic inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *, 283193149Sdougb isc_sockaddr_t *, int *, 284193149Sdougb isc_stdtime_t); 285143731Sdougbstatic void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t); 286135446Strhodesstatic void print_dns_name(FILE *, dns_name_t *); 287135446Strhodesstatic void print_namehook_list(FILE *, const char *legend, 288135446Strhodes dns_adbnamehooklist_t *list, 289135446Strhodes isc_boolean_t debug, 290135446Strhodes isc_stdtime_t now); 291135446Strhodesstatic void print_find_list(FILE *, dns_adbname_t *); 292135446Strhodesstatic void print_fetch_list(FILE *, dns_adbname_t *); 293135446Strhodesstatic inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *); 294135446Strhodesstatic inline void inc_adb_irefcnt(dns_adb_t *); 295135446Strhodesstatic inline void inc_adb_erefcnt(dns_adb_t *); 296135446Strhodesstatic inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *, 297135446Strhodes isc_boolean_t); 298214586Sdougbstatic inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, isc_boolean_t, 299214586Sdougb dns_adbentry_t *, isc_boolean_t); 300135446Strhodesstatic inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *); 301135446Strhodesstatic isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *); 302135446Strhodesstatic void clean_target(dns_adb_t *, dns_name_t *); 303135446Strhodesstatic void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, 304135446Strhodes unsigned int); 305193149Sdougbstatic isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t); 306193149Sdougbstatic isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **, 307193149Sdougb isc_stdtime_t); 308135446Strhodesstatic void cancel_fetches_at_name(dns_adbname_t *); 309135446Strhodesstatic isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t, 310135446Strhodes dns_rdatatype_t); 311135446Strhodesstatic isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t, 312135446Strhodes dns_rdatatype_t); 313135446Strhodesstatic inline void check_exit(dns_adb_t *); 314135446Strhodesstatic void destroy(dns_adb_t *); 315135446Strhodesstatic isc_boolean_t shutdown_names(dns_adb_t *); 316135446Strhodesstatic isc_boolean_t shutdown_entries(dns_adb_t *); 317135446Strhodesstatic inline void link_name(dns_adb_t *, int, dns_adbname_t *); 318135446Strhodesstatic inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *); 319135446Strhodesstatic inline void link_entry(dns_adb_t *, int, dns_adbentry_t *); 320135446Strhodesstatic inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *); 321135446Strhodesstatic isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t); 322143731Sdougbstatic void water(void *, int); 323143731Sdougbstatic void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t); 324135446Strhodes 325135446Strhodes/* 326135446Strhodes * MUST NOT overlap DNS_ADBFIND_* flags! 327135446Strhodes */ 328193149Sdougb#define FIND_EVENT_SENT 0x40000000 329193149Sdougb#define FIND_EVENT_FREED 0x80000000 330193149Sdougb#define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0) 331193149Sdougb#define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0) 332135446Strhodes 333193149Sdougb#define NAME_NEEDS_POKE 0x80000000 334193149Sdougb#define NAME_IS_DEAD 0x40000000 335193149Sdougb#define NAME_HINT_OK DNS_ADBFIND_HINTOK 336193149Sdougb#define NAME_GLUE_OK DNS_ADBFIND_GLUEOK 337193149Sdougb#define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE 338193149Sdougb#define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0) 339193149Sdougb#define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0) 340193149Sdougb#define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0) 341193149Sdougb#define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0) 342135446Strhodes 343135446Strhodes/* 344193149Sdougb * Private flag(s) for entries. 345193149Sdougb * MUST NOT overlap FCTX_ADDRINFO_xxx and DNS_FETCHOPT_NOEDNS0. 346193149Sdougb */ 347193149Sdougb#define ENTRY_IS_DEAD 0x80000000 348193149Sdougb 349193149Sdougb/* 350135446Strhodes * To the name, address classes are all that really exist. If it has a 351135446Strhodes * V6 address it doesn't care if it came from a AAAA query. 352135446Strhodes */ 353193149Sdougb#define NAME_HAS_V4(n) (!ISC_LIST_EMPTY((n)->v4)) 354193149Sdougb#define NAME_HAS_V6(n) (!ISC_LIST_EMPTY((n)->v6)) 355193149Sdougb#define NAME_HAS_ADDRS(n) (NAME_HAS_V4(n) || NAME_HAS_V6(n)) 356135446Strhodes 357135446Strhodes/* 358135446Strhodes * Fetches are broken out into A and AAAA types. In some cases, 359135446Strhodes * however, it makes more sense to test for a particular class of fetches, 360135446Strhodes * like V4 or V6 above. 361135446Strhodes * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA 362135446Strhodes * are now equal to FETCH_V4 and FETCH_V6, respectively. 363135446Strhodes */ 364193149Sdougb#define NAME_FETCH_A(n) ((n)->fetch_a != NULL) 365193149Sdougb#define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL) 366193149Sdougb#define NAME_FETCH_V4(n) (NAME_FETCH_A(n)) 367193149Sdougb#define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n)) 368193149Sdougb#define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n)) 369135446Strhodes 370135446Strhodes/* 371135446Strhodes * Find options and tests to see if there are addresses on the list. 372135446Strhodes */ 373193149Sdougb#define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0) 374193149Sdougb#define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0) 375193149Sdougb#define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \ 376135446Strhodes != 0) 377193149Sdougb#define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \ 378135446Strhodes != 0) 379193149Sdougb#define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0) 380193149Sdougb#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0) 381193149Sdougb#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list)) 382193149Sdougb#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0) 383135446Strhodes 384135446Strhodes/* 385135446Strhodes * These are currently used on simple unsigned ints, so they are 386135446Strhodes * not really associated with any particular type. 387135446Strhodes */ 388193149Sdougb#define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0) 389193149Sdougb#define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0) 390135446Strhodes 391193149Sdougb#define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now)) 392135446Strhodes 393135446Strhodes/* 394135446Strhodes * Find out if the flags on a name (nf) indicate if it is a hint or 395135446Strhodes * glue, and compare this to the appropriate bits set in o, to see if 396135446Strhodes * this is ok. 397135446Strhodes */ 398135446Strhodes#define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0)) 399135446Strhodes#define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0)) 400135446Strhodes#define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o)) 401135446Strhodes#define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \ 402135446Strhodes ((o) & DNS_ADBFIND_STARTATZONE)) 403135446Strhodes 404193149Sdougb#define ENTER_LEVEL ISC_LOG_DEBUG(50) 405193149Sdougb#define EXIT_LEVEL ENTER_LEVEL 406193149Sdougb#define CLEAN_LEVEL ISC_LOG_DEBUG(100) 407193149Sdougb#define DEF_LEVEL ISC_LOG_DEBUG(5) 408193149Sdougb#define NCACHE_LEVEL ISC_LOG_DEBUG(20) 409135446Strhodes 410193149Sdougb#define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \ 411135446Strhodes (r) == DNS_R_NCACHENXRRSET) 412193149Sdougb#define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \ 413135446Strhodes (r) == DNS_R_NXRRSET) 414193149Sdougb#define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \ 415135446Strhodes (r) == DNS_R_NCACHENXDOMAIN) 416193149Sdougb#define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \ 417135446Strhodes (r) == DNS_R_NXRRSET || \ 418135446Strhodes (r) == DNS_R_HINTNXRRSET) 419135446Strhodes 420135446Strhodes/* 421135446Strhodes * Error state rankings. 422135446Strhodes */ 423135446Strhodes 424193149Sdougb#define FIND_ERR_SUCCESS 0 /* highest rank */ 425193149Sdougb#define FIND_ERR_CANCELED 1 426193149Sdougb#define FIND_ERR_FAILURE 2 427193149Sdougb#define FIND_ERR_NXDOMAIN 3 428193149Sdougb#define FIND_ERR_NXRRSET 4 429193149Sdougb#define FIND_ERR_UNEXPECTED 5 430193149Sdougb#define FIND_ERR_NOTFOUND 6 431193149Sdougb#define FIND_ERR_MAX 7 432135446Strhodes 433135446Strhodesstatic const char *errnames[] = { 434135446Strhodes "success", 435135446Strhodes "canceled", 436135446Strhodes "failure", 437135446Strhodes "nxdomain", 438135446Strhodes "nxrrset", 439135446Strhodes "unexpected", 440135446Strhodes "not_found" 441135446Strhodes}; 442135446Strhodes 443193149Sdougb#define NEWERR(old, new) (ISC_MIN((old), (new))) 444135446Strhodes 445135446Strhodesstatic isc_result_t find_err_map[FIND_ERR_MAX] = { 446135446Strhodes ISC_R_SUCCESS, 447135446Strhodes ISC_R_CANCELED, 448135446Strhodes ISC_R_FAILURE, 449135446Strhodes DNS_R_NXDOMAIN, 450135446Strhodes DNS_R_NXRRSET, 451135446Strhodes ISC_R_UNEXPECTED, 452193149Sdougb ISC_R_NOTFOUND /* not YET found */ 453135446Strhodes}; 454135446Strhodes 455135446Strhodesstatic void 456135446StrhodesDP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3); 457135446Strhodes 458135446Strhodesstatic void 459135446StrhodesDP(int level, const char *format, ...) { 460135446Strhodes va_list args; 461135446Strhodes 462135446Strhodes va_start(args, format); 463135446Strhodes isc_log_vwrite(dns_lctx, 464135446Strhodes DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB, 465135446Strhodes level, format, args); 466135446Strhodes va_end(args); 467135446Strhodes} 468135446Strhodes 469193149Sdougb/*% 470193149Sdougb * Increment resolver-related statistics counters. 471193149Sdougb */ 472193149Sdougbstatic inline void 473193149Sdougbinc_stats(dns_adb_t *adb, isc_statscounter_t counter) { 474193149Sdougb if (adb->view->resstats != NULL) 475193149Sdougb isc_stats_increment(adb->view->resstats, counter); 476193149Sdougb} 477193149Sdougb 478135446Strhodesstatic inline dns_ttl_t 479135446Strhodesttlclamp(dns_ttl_t ttl) { 480135446Strhodes if (ttl < ADB_CACHE_MINIMUM) 481135446Strhodes ttl = ADB_CACHE_MINIMUM; 482135446Strhodes if (ttl > ADB_CACHE_MAXIMUM) 483135446Strhodes ttl = ADB_CACHE_MAXIMUM; 484135446Strhodes 485135446Strhodes return (ttl); 486135446Strhodes} 487135446Strhodes 488135446Strhodes/* 489224092Sdougb * Hashing is most efficient if the number of buckets is prime. 490224092Sdougb * The sequence below is the closest previous primes to 2^n and 491224092Sdougb * 1.5 * 2^n, for values of n from 10 to 28. (The tables will 492224092Sdougb * no longer grow beyond 2^28 entries.) 493224092Sdougb */ 494224092Sdougbstatic const unsigned nbuckets[] = { 1021, 1531, 2039, 3067, 4093, 6143, 495224092Sdougb 8191, 12281, 16381, 24571, 32749, 496224092Sdougb 49193, 65521, 98299, 131071, 199603, 497224092Sdougb 262139, 393209, 524287, 768431, 1048573, 498224092Sdougb 1572853, 2097143, 3145721, 4194301, 499224092Sdougb 6291449, 8388593, 12582893, 16777213, 500224092Sdougb 25165813, 33554393, 50331599, 67108859, 501224092Sdougb 100663291, 134217689, 201326557, 502224092Sdougb 268535431, 0 }; 503224092Sdougb 504224092Sdougbstatic void 505224092Sdougbgrow_entries(isc_task_t *task, isc_event_t *ev) { 506224092Sdougb dns_adb_t *adb; 507224092Sdougb dns_adbentry_t *e; 508224092Sdougb dns_adbentrylist_t *newdeadentries = NULL; 509224092Sdougb dns_adbentrylist_t *newentries = NULL; 510224092Sdougb isc_boolean_t *newentry_sd = NULL; 511224092Sdougb isc_mutex_t *newentrylocks = NULL; 512224092Sdougb isc_result_t result; 513224092Sdougb unsigned int *newentry_refcnt = NULL; 514224092Sdougb unsigned int i, n, bucket; 515224092Sdougb 516224092Sdougb adb = ev->ev_arg; 517224092Sdougb INSIST(DNS_ADB_VALID(adb)); 518224092Sdougb 519224092Sdougb isc_event_free(&ev); 520224092Sdougb 521254402Serwin result = isc_task_beginexclusive(task); 522254402Serwin if (result != ISC_R_SUCCESS) 523254402Serwin goto check_exit; 524224092Sdougb 525224092Sdougb i = 0; 526224092Sdougb while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i]) 527224092Sdougb i++; 528224092Sdougb if (nbuckets[i] != 0) 529224092Sdougb n = nbuckets[i]; 530224092Sdougb else 531224092Sdougb goto done; 532224092Sdougb 533224092Sdougb DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n); 534224092Sdougb 535224092Sdougb /* 536224092Sdougb * Are we shutting down? 537224092Sdougb */ 538224092Sdougb for (i = 0; i < adb->nentries; i++) 539224092Sdougb if (adb->entry_sd[i]) 540224092Sdougb goto cleanup; 541224092Sdougb 542224092Sdougb /* 543224092Sdougb * Grab all the resources we need. 544224092Sdougb */ 545224092Sdougb newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n); 546224092Sdougb newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n); 547224092Sdougb newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n); 548224092Sdougb newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n); 549224092Sdougb newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n); 550224092Sdougb if (newentries == NULL || newdeadentries == NULL || 551224092Sdougb newentrylocks == NULL || newentry_sd == NULL || 552224092Sdougb newentry_refcnt == NULL) 553224092Sdougb goto cleanup; 554224092Sdougb 555224092Sdougb /* 556224092Sdougb * Initialise the new resources. 557224092Sdougb */ 558224092Sdougb result = isc_mutexblock_init(newentrylocks, n); 559224092Sdougb if (result != ISC_R_SUCCESS) 560224092Sdougb goto cleanup; 561224092Sdougb 562224092Sdougb for (i = 0; i < n; i++) { 563224092Sdougb ISC_LIST_INIT(newentries[i]); 564224092Sdougb ISC_LIST_INIT(newdeadentries[i]); 565224092Sdougb newentry_sd[i] = ISC_FALSE; 566224092Sdougb newentry_refcnt[i] = 0; 567224092Sdougb adb->irefcnt++; 568224092Sdougb } 569224092Sdougb 570224092Sdougb /* 571224092Sdougb * Move entries to new arrays. 572224092Sdougb */ 573224092Sdougb for (i = 0; i < adb->nentries; i++) { 574224092Sdougb e = ISC_LIST_HEAD(adb->entries[i]); 575224092Sdougb while (e != NULL) { 576224092Sdougb ISC_LIST_UNLINK(adb->entries[i], e, plink); 577224092Sdougb bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n; 578224092Sdougb e->lock_bucket = bucket; 579224092Sdougb ISC_LIST_APPEND(newentries[bucket], e, plink); 580224092Sdougb INSIST(adb->entry_refcnt[i] > 0); 581224092Sdougb adb->entry_refcnt[i]--; 582224092Sdougb newentry_refcnt[bucket]++; 583224092Sdougb e = ISC_LIST_HEAD(adb->entries[i]); 584224092Sdougb } 585224092Sdougb e = ISC_LIST_HEAD(adb->deadentries[i]); 586224092Sdougb while (e != NULL) { 587224092Sdougb ISC_LIST_UNLINK(adb->deadentries[i], e, plink); 588224092Sdougb bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n; 589224092Sdougb e->lock_bucket = bucket; 590224092Sdougb ISC_LIST_APPEND(newdeadentries[bucket], e, plink); 591224092Sdougb INSIST(adb->entry_refcnt[i] > 0); 592224092Sdougb adb->entry_refcnt[i]--; 593224092Sdougb newentry_refcnt[bucket]++; 594224092Sdougb e = ISC_LIST_HEAD(adb->deadentries[i]); 595224092Sdougb } 596224092Sdougb INSIST(adb->entry_refcnt[i] == 0); 597224092Sdougb adb->irefcnt--; 598224092Sdougb } 599224092Sdougb 600224092Sdougb /* 601224092Sdougb * Cleanup old resources. 602224092Sdougb */ 603224092Sdougb DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries); 604224092Sdougb isc_mem_put(adb->mctx, adb->entries, 605224092Sdougb sizeof(*adb->entries) * adb->nentries); 606224092Sdougb isc_mem_put(adb->mctx, adb->deadentries, 607224092Sdougb sizeof(*adb->deadentries) * adb->nentries); 608224092Sdougb isc_mem_put(adb->mctx, adb->entrylocks, 609224092Sdougb sizeof(*adb->entrylocks) * adb->nentries); 610224092Sdougb isc_mem_put(adb->mctx, adb->entry_sd, 611224092Sdougb sizeof(*adb->entry_sd) * adb->nentries); 612224092Sdougb isc_mem_put(adb->mctx, adb->entry_refcnt, 613224092Sdougb sizeof(*adb->entry_refcnt) * adb->nentries); 614224092Sdougb 615224092Sdougb /* 616224092Sdougb * Install new resources. 617224092Sdougb */ 618224092Sdougb adb->entries = newentries; 619224092Sdougb adb->deadentries = newdeadentries; 620224092Sdougb adb->entrylocks = newentrylocks; 621224092Sdougb adb->entry_sd = newentry_sd; 622224092Sdougb adb->entry_refcnt = newentry_refcnt; 623224092Sdougb adb->nentries = n; 624224092Sdougb 625224092Sdougb /* 626224092Sdougb * Only on success do we set adb->growentries_sent to ISC_FALSE. 627224092Sdougb * This will prevent us being continuously being called on error. 628224092Sdougb */ 629224092Sdougb adb->growentries_sent = ISC_FALSE; 630224092Sdougb goto done; 631224092Sdougb 632224092Sdougb cleanup: 633224092Sdougb if (newentries != NULL) 634224092Sdougb isc_mem_put(adb->mctx, newentries, 635224092Sdougb sizeof(*newentries) * n); 636224092Sdougb if (newdeadentries != NULL) 637224092Sdougb isc_mem_put(adb->mctx, newdeadentries, 638224092Sdougb sizeof(*newdeadentries) * n); 639224092Sdougb if (newentrylocks != NULL) 640224092Sdougb isc_mem_put(adb->mctx, newentrylocks, 641224092Sdougb sizeof(*newentrylocks) * n); 642224092Sdougb if (newentry_sd != NULL) 643224092Sdougb isc_mem_put(adb->mctx, newentry_sd, 644224092Sdougb sizeof(*newentry_sd) * n); 645224092Sdougb if (newentry_refcnt != NULL) 646224092Sdougb isc_mem_put(adb->mctx, newentry_refcnt, 647224092Sdougb sizeof(*newentry_refcnt) * n); 648224092Sdougb done: 649224092Sdougb isc_task_endexclusive(task); 650224092Sdougb 651254402Serwin check_exit: 652224092Sdougb LOCK(&adb->lock); 653224092Sdougb if (dec_adb_irefcnt(adb)) 654224092Sdougb check_exit(adb); 655224092Sdougb UNLOCK(&adb->lock); 656224092Sdougb DP(ISC_LOG_INFO, "adb: grow_entries finished"); 657224092Sdougb} 658224092Sdougb 659224092Sdougbstatic void 660224092Sdougbgrow_names(isc_task_t *task, isc_event_t *ev) { 661224092Sdougb dns_adb_t *adb; 662224092Sdougb dns_adbname_t *name; 663224092Sdougb dns_adbnamelist_t *newdeadnames = NULL; 664224092Sdougb dns_adbnamelist_t *newnames = NULL; 665224092Sdougb isc_boolean_t *newname_sd = NULL; 666224092Sdougb isc_mutex_t *newnamelocks = NULL; 667224092Sdougb isc_result_t result; 668224092Sdougb unsigned int *newname_refcnt = NULL; 669224092Sdougb unsigned int i, n, bucket; 670224092Sdougb 671224092Sdougb adb = ev->ev_arg; 672224092Sdougb INSIST(DNS_ADB_VALID(adb)); 673224092Sdougb 674224092Sdougb isc_event_free(&ev); 675224092Sdougb 676254402Serwin result = isc_task_beginexclusive(task); 677254402Serwin if (result != ISC_R_SUCCESS) 678254402Serwin goto check_exit; 679224092Sdougb 680224092Sdougb i = 0; 681224092Sdougb while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i]) 682224092Sdougb i++; 683224092Sdougb if (nbuckets[i] != 0) 684224092Sdougb n = nbuckets[i]; 685224092Sdougb else 686224092Sdougb goto done; 687224092Sdougb 688224092Sdougb DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n); 689224092Sdougb 690224092Sdougb /* 691224092Sdougb * Are we shutting down? 692224092Sdougb */ 693224092Sdougb for (i = 0; i < adb->nnames; i++) 694224092Sdougb if (adb->name_sd[i]) 695224092Sdougb goto cleanup; 696224092Sdougb 697224092Sdougb /* 698224092Sdougb * Grab all the resources we need. 699224092Sdougb */ 700224092Sdougb newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n); 701224092Sdougb newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n); 702224092Sdougb newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n); 703224092Sdougb newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n); 704224092Sdougb newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n); 705224092Sdougb if (newnames == NULL || newdeadnames == NULL || 706224092Sdougb newnamelocks == NULL || newname_sd == NULL || 707224092Sdougb newname_refcnt == NULL) 708224092Sdougb goto cleanup; 709224092Sdougb 710224092Sdougb /* 711224092Sdougb * Initialise the new resources. 712224092Sdougb */ 713224092Sdougb result = isc_mutexblock_init(newnamelocks, n); 714224092Sdougb if (result != ISC_R_SUCCESS) 715224092Sdougb goto cleanup; 716224092Sdougb 717224092Sdougb for (i = 0; i < n; i++) { 718224092Sdougb ISC_LIST_INIT(newnames[i]); 719224092Sdougb ISC_LIST_INIT(newdeadnames[i]); 720224092Sdougb newname_sd[i] = ISC_FALSE; 721224092Sdougb newname_refcnt[i] = 0; 722224092Sdougb adb->irefcnt++; 723224092Sdougb } 724224092Sdougb 725224092Sdougb /* 726224092Sdougb * Move names to new arrays. 727224092Sdougb */ 728224092Sdougb for (i = 0; i < adb->nnames; i++) { 729224092Sdougb name = ISC_LIST_HEAD(adb->names[i]); 730224092Sdougb while (name != NULL) { 731224092Sdougb ISC_LIST_UNLINK(adb->names[i], name, plink); 732224092Sdougb bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n; 733224092Sdougb name->lock_bucket = bucket; 734224092Sdougb ISC_LIST_APPEND(newnames[bucket], name, plink); 735224092Sdougb INSIST(adb->name_refcnt[i] > 0); 736224092Sdougb adb->name_refcnt[i]--; 737224092Sdougb newname_refcnt[bucket]++; 738224092Sdougb name = ISC_LIST_HEAD(adb->names[i]); 739224092Sdougb } 740224092Sdougb name = ISC_LIST_HEAD(adb->deadnames[i]); 741224092Sdougb while (name != NULL) { 742224092Sdougb ISC_LIST_UNLINK(adb->deadnames[i], name, plink); 743224092Sdougb bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n; 744224092Sdougb name->lock_bucket = bucket; 745224092Sdougb ISC_LIST_APPEND(newdeadnames[bucket], name, plink); 746224092Sdougb INSIST(adb->name_refcnt[i] > 0); 747224092Sdougb adb->name_refcnt[i]--; 748224092Sdougb newname_refcnt[bucket]++; 749224092Sdougb name = ISC_LIST_HEAD(adb->deadnames[i]); 750224092Sdougb } 751224092Sdougb INSIST(adb->name_refcnt[i] == 0); 752224092Sdougb adb->irefcnt--; 753224092Sdougb } 754224092Sdougb 755224092Sdougb /* 756224092Sdougb * Cleanup old resources. 757224092Sdougb */ 758224092Sdougb DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames); 759224092Sdougb isc_mem_put(adb->mctx, adb->names, 760224092Sdougb sizeof(*adb->names) * adb->nnames); 761224092Sdougb isc_mem_put(adb->mctx, adb->deadnames, 762224092Sdougb sizeof(*adb->deadnames) * adb->nnames); 763224092Sdougb isc_mem_put(adb->mctx, adb->namelocks, 764224092Sdougb sizeof(*adb->namelocks) * adb->nnames); 765224092Sdougb isc_mem_put(adb->mctx, adb->name_sd, 766224092Sdougb sizeof(*adb->name_sd) * adb->nnames); 767224092Sdougb isc_mem_put(adb->mctx, adb->name_refcnt, 768224092Sdougb sizeof(*adb->name_refcnt) * adb->nnames); 769224092Sdougb 770224092Sdougb /* 771224092Sdougb * Install new resources. 772224092Sdougb */ 773224092Sdougb adb->names = newnames; 774224092Sdougb adb->deadnames = newdeadnames; 775224092Sdougb adb->namelocks = newnamelocks; 776224092Sdougb adb->name_sd = newname_sd; 777224092Sdougb adb->name_refcnt = newname_refcnt; 778224092Sdougb adb->nnames = n; 779224092Sdougb 780224092Sdougb /* 781224092Sdougb * Only on success do we set adb->grownames_sent to ISC_FALSE. 782224092Sdougb * This will prevent us being continuously being called on error. 783224092Sdougb */ 784224092Sdougb adb->grownames_sent = ISC_FALSE; 785224092Sdougb goto done; 786224092Sdougb 787224092Sdougb cleanup: 788224092Sdougb if (newnames != NULL) 789224092Sdougb isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n); 790224092Sdougb if (newdeadnames != NULL) 791224092Sdougb isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n); 792224092Sdougb if (newnamelocks != NULL) 793224092Sdougb isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n); 794224092Sdougb if (newname_sd != NULL) 795224092Sdougb isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n); 796224092Sdougb if (newname_refcnt != NULL) 797224092Sdougb isc_mem_put(adb->mctx, newname_refcnt, 798224092Sdougb sizeof(*newname_refcnt) * n); 799224092Sdougb done: 800224092Sdougb isc_task_endexclusive(task); 801224092Sdougb 802254402Serwin check_exit: 803224092Sdougb LOCK(&adb->lock); 804224092Sdougb if (dec_adb_irefcnt(adb)) 805224092Sdougb check_exit(adb); 806224092Sdougb UNLOCK(&adb->lock); 807224092Sdougb DP(ISC_LOG_INFO, "adb: grow_names finished"); 808224092Sdougb} 809224092Sdougb 810224092Sdougb/* 811135446Strhodes * Requires the adbname bucket be locked and that no entry buckets be locked. 812135446Strhodes * 813135446Strhodes * This code handles A and AAAA rdatasets only. 814135446Strhodes */ 815135446Strhodesstatic isc_result_t 816135446Strhodesimport_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset, 817135446Strhodes isc_stdtime_t now) 818135446Strhodes{ 819135446Strhodes isc_result_t result; 820135446Strhodes dns_adb_t *adb; 821135446Strhodes dns_adbnamehook_t *nh; 822135446Strhodes dns_adbnamehook_t *anh; 823135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 824135446Strhodes struct in_addr ina; 825135446Strhodes struct in6_addr in6a; 826135446Strhodes isc_sockaddr_t sockaddr; 827135446Strhodes dns_adbentry_t *foundentry; /* NO CLEAN UP! */ 828135446Strhodes int addr_bucket; 829135446Strhodes isc_boolean_t new_addresses_added; 830135446Strhodes dns_rdatatype_t rdtype; 831135446Strhodes unsigned int findoptions; 832186462Sdougb dns_adbnamehooklist_t *hookhead; 833135446Strhodes 834135446Strhodes INSIST(DNS_ADBNAME_VALID(adbname)); 835135446Strhodes adb = adbname->adb; 836135446Strhodes INSIST(DNS_ADB_VALID(adb)); 837135446Strhodes 838135446Strhodes rdtype = rdataset->type; 839135446Strhodes INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa)); 840135446Strhodes if (rdtype == dns_rdatatype_a) 841135446Strhodes findoptions = DNS_ADBFIND_INET; 842135446Strhodes else 843135446Strhodes findoptions = DNS_ADBFIND_INET6; 844135446Strhodes 845135446Strhodes addr_bucket = DNS_ADB_INVALIDBUCKET; 846135446Strhodes new_addresses_added = ISC_FALSE; 847135446Strhodes 848135446Strhodes nh = NULL; 849135446Strhodes result = dns_rdataset_first(rdataset); 850135446Strhodes while (result == ISC_R_SUCCESS) { 851135446Strhodes dns_rdata_reset(&rdata); 852135446Strhodes dns_rdataset_current(rdataset, &rdata); 853135446Strhodes if (rdtype == dns_rdatatype_a) { 854135446Strhodes INSIST(rdata.length == 4); 855135446Strhodes memcpy(&ina.s_addr, rdata.data, 4); 856135446Strhodes isc_sockaddr_fromin(&sockaddr, &ina, 0); 857186462Sdougb hookhead = &adbname->v4; 858135446Strhodes } else { 859135446Strhodes INSIST(rdata.length == 16); 860135446Strhodes memcpy(in6a.s6_addr, rdata.data, 16); 861135446Strhodes isc_sockaddr_fromin6(&sockaddr, &in6a, 0); 862186462Sdougb hookhead = &adbname->v6; 863135446Strhodes } 864135446Strhodes 865135446Strhodes INSIST(nh == NULL); 866135446Strhodes nh = new_adbnamehook(adb, NULL); 867135446Strhodes if (nh == NULL) { 868135446Strhodes adbname->partial_result |= findoptions; 869135446Strhodes result = ISC_R_NOMEMORY; 870135446Strhodes goto fail; 871135446Strhodes } 872135446Strhodes 873193149Sdougb foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket, 874193149Sdougb now); 875135446Strhodes if (foundentry == NULL) { 876135446Strhodes dns_adbentry_t *entry; 877135446Strhodes 878135446Strhodes entry = new_adbentry(adb); 879135446Strhodes if (entry == NULL) { 880135446Strhodes adbname->partial_result |= findoptions; 881135446Strhodes result = ISC_R_NOMEMORY; 882135446Strhodes goto fail; 883135446Strhodes } 884135446Strhodes 885135446Strhodes entry->sockaddr = sockaddr; 886135446Strhodes entry->refcnt = 1; 887135446Strhodes 888135446Strhodes nh->entry = entry; 889135446Strhodes 890135446Strhodes link_entry(adb, addr_bucket, entry); 891135446Strhodes } else { 892186462Sdougb for (anh = ISC_LIST_HEAD(*hookhead); 893135446Strhodes anh != NULL; 894135446Strhodes anh = ISC_LIST_NEXT(anh, plink)) 895135446Strhodes if (anh->entry == foundentry) 896135446Strhodes break; 897135446Strhodes if (anh == NULL) { 898135446Strhodes foundentry->refcnt++; 899135446Strhodes nh->entry = foundentry; 900135446Strhodes } else 901135446Strhodes free_adbnamehook(adb, &nh); 902135446Strhodes } 903135446Strhodes 904135446Strhodes new_addresses_added = ISC_TRUE; 905186462Sdougb if (nh != NULL) 906186462Sdougb ISC_LIST_APPEND(*hookhead, nh, plink); 907135446Strhodes nh = NULL; 908135446Strhodes result = dns_rdataset_next(rdataset); 909135446Strhodes } 910135446Strhodes 911135446Strhodes fail: 912135446Strhodes if (nh != NULL) 913135446Strhodes free_adbnamehook(adb, &nh); 914135446Strhodes 915135446Strhodes if (addr_bucket != DNS_ADB_INVALIDBUCKET) 916135446Strhodes UNLOCK(&adb->entrylocks[addr_bucket]); 917135446Strhodes 918135446Strhodes if (rdataset->trust == dns_trust_glue || 919135446Strhodes rdataset->trust == dns_trust_additional) 920135446Strhodes rdataset->ttl = ADB_CACHE_MINIMUM; 921225361Sdougb else if (rdataset->trust == dns_trust_ultimate) 922225361Sdougb rdataset->ttl = 0; 923135446Strhodes else 924135446Strhodes rdataset->ttl = ttlclamp(rdataset->ttl); 925135446Strhodes 926135446Strhodes if (rdtype == dns_rdatatype_a) { 927135446Strhodes DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset", 928135446Strhodes adbname->expire_v4, now + rdataset->ttl); 929135446Strhodes adbname->expire_v4 = ISC_MIN(adbname->expire_v4, 930135446Strhodes now + rdataset->ttl); 931135446Strhodes } else { 932135446Strhodes DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset", 933135446Strhodes adbname->expire_v6, now + rdataset->ttl); 934135446Strhodes adbname->expire_v6 = ISC_MIN(adbname->expire_v6, 935135446Strhodes now + rdataset->ttl); 936135446Strhodes } 937135446Strhodes 938135446Strhodes if (new_addresses_added) { 939135446Strhodes /* 940135446Strhodes * Lie a little here. This is more or less so code that cares 941135446Strhodes * can find out if any new information was added or not. 942135446Strhodes */ 943135446Strhodes return (ISC_R_SUCCESS); 944135446Strhodes } 945135446Strhodes 946135446Strhodes return (result); 947135446Strhodes} 948135446Strhodes 949135446Strhodes/* 950135446Strhodes * Requires the name's bucket be locked. 951135446Strhodes */ 952135446Strhodesstatic isc_boolean_t 953135446Strhodeskill_name(dns_adbname_t **n, isc_eventtype_t ev) { 954135446Strhodes dns_adbname_t *name; 955135446Strhodes isc_boolean_t result = ISC_FALSE; 956135446Strhodes isc_boolean_t result4, result6; 957193149Sdougb int bucket; 958135446Strhodes dns_adb_t *adb; 959135446Strhodes 960135446Strhodes INSIST(n != NULL); 961135446Strhodes name = *n; 962135446Strhodes *n = NULL; 963135446Strhodes INSIST(DNS_ADBNAME_VALID(name)); 964135446Strhodes adb = name->adb; 965135446Strhodes INSIST(DNS_ADB_VALID(adb)); 966135446Strhodes 967135446Strhodes DP(DEF_LEVEL, "killing name %p", name); 968135446Strhodes 969135446Strhodes /* 970135446Strhodes * If we're dead already, just check to see if we should go 971135446Strhodes * away now or not. 972135446Strhodes */ 973135446Strhodes if (NAME_DEAD(name) && !NAME_FETCH(name)) { 974135446Strhodes result = unlink_name(adb, name); 975135446Strhodes free_adbname(adb, &name); 976135446Strhodes if (result) 977135446Strhodes result = dec_adb_irefcnt(adb); 978135446Strhodes return (result); 979135446Strhodes } 980135446Strhodes 981135446Strhodes /* 982135446Strhodes * Clean up the name's various lists. These two are destructive 983135446Strhodes * in that they will always empty the list. 984135446Strhodes */ 985135446Strhodes clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK); 986135446Strhodes result4 = clean_namehooks(adb, &name->v4); 987135446Strhodes result6 = clean_namehooks(adb, &name->v6); 988135446Strhodes clean_target(adb, &name->target); 989135446Strhodes result = ISC_TF(result4 || result6); 990135446Strhodes 991135446Strhodes /* 992135446Strhodes * If fetches are running, cancel them. If none are running, we can 993135446Strhodes * just kill the name here. 994135446Strhodes */ 995135446Strhodes if (!NAME_FETCH(name)) { 996135446Strhodes INSIST(result == ISC_FALSE); 997135446Strhodes result = unlink_name(adb, name); 998135446Strhodes free_adbname(adb, &name); 999135446Strhodes if (result) 1000135446Strhodes result = dec_adb_irefcnt(adb); 1001135446Strhodes } else { 1002135446Strhodes cancel_fetches_at_name(name); 1003193149Sdougb if (!NAME_DEAD(name)) { 1004193149Sdougb bucket = name->lock_bucket; 1005193149Sdougb ISC_LIST_UNLINK(adb->names[bucket], name, plink); 1006193149Sdougb ISC_LIST_APPEND(adb->deadnames[bucket], name, plink); 1007193149Sdougb name->flags |= NAME_IS_DEAD; 1008193149Sdougb } 1009135446Strhodes } 1010135446Strhodes return (result); 1011135446Strhodes} 1012135446Strhodes 1013135446Strhodes/* 1014135446Strhodes * Requires the name's bucket be locked and no entry buckets be locked. 1015135446Strhodes */ 1016135446Strhodesstatic isc_boolean_t 1017193149Sdougbcheck_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) { 1018135446Strhodes dns_adb_t *adb; 1019135446Strhodes isc_boolean_t result4 = ISC_FALSE; 1020135446Strhodes isc_boolean_t result6 = ISC_FALSE; 1021135446Strhodes 1022135446Strhodes INSIST(DNS_ADBNAME_VALID(name)); 1023135446Strhodes adb = name->adb; 1024135446Strhodes INSIST(DNS_ADB_VALID(adb)); 1025135446Strhodes 1026135446Strhodes /* 1027135446Strhodes * Check to see if we need to remove the v4 addresses 1028135446Strhodes */ 1029193149Sdougb if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) { 1030135446Strhodes if (NAME_HAS_V4(name)) { 1031135446Strhodes DP(DEF_LEVEL, "expiring v4 for name %p", name); 1032135446Strhodes result4 = clean_namehooks(adb, &name->v4); 1033135446Strhodes name->partial_result &= ~DNS_ADBFIND_INET; 1034135446Strhodes } 1035135446Strhodes name->expire_v4 = INT_MAX; 1036135446Strhodes name->fetch_err = FIND_ERR_UNEXPECTED; 1037135446Strhodes } 1038135446Strhodes 1039135446Strhodes /* 1040135446Strhodes * Check to see if we need to remove the v6 addresses 1041135446Strhodes */ 1042193149Sdougb if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) { 1043135446Strhodes if (NAME_HAS_V6(name)) { 1044135446Strhodes DP(DEF_LEVEL, "expiring v6 for name %p", name); 1045135446Strhodes result6 = clean_namehooks(adb, &name->v6); 1046135446Strhodes name->partial_result &= ~DNS_ADBFIND_INET6; 1047135446Strhodes } 1048135446Strhodes name->expire_v6 = INT_MAX; 1049135446Strhodes name->fetch6_err = FIND_ERR_UNEXPECTED; 1050135446Strhodes } 1051135446Strhodes 1052135446Strhodes /* 1053135446Strhodes * Check to see if we need to remove the alias target. 1054135446Strhodes */ 1055193149Sdougb if (EXPIRE_OK(name->expire_target, now)) { 1056135446Strhodes clean_target(adb, &name->target); 1057135446Strhodes name->expire_target = INT_MAX; 1058135446Strhodes } 1059135446Strhodes return (ISC_TF(result4 || result6)); 1060135446Strhodes} 1061135446Strhodes 1062135446Strhodes/* 1063135446Strhodes * Requires the name's bucket be locked. 1064135446Strhodes */ 1065135446Strhodesstatic inline void 1066135446Strhodeslink_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) { 1067135446Strhodes INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET); 1068135446Strhodes 1069135446Strhodes ISC_LIST_PREPEND(adb->names[bucket], name, plink); 1070135446Strhodes name->lock_bucket = bucket; 1071135446Strhodes adb->name_refcnt[bucket]++; 1072135446Strhodes} 1073135446Strhodes 1074135446Strhodes/* 1075135446Strhodes * Requires the name's bucket be locked. 1076135446Strhodes */ 1077135446Strhodesstatic inline isc_boolean_t 1078135446Strhodesunlink_name(dns_adb_t *adb, dns_adbname_t *name) { 1079135446Strhodes int bucket; 1080135446Strhodes isc_boolean_t result = ISC_FALSE; 1081135446Strhodes 1082135446Strhodes bucket = name->lock_bucket; 1083135446Strhodes INSIST(bucket != DNS_ADB_INVALIDBUCKET); 1084135446Strhodes 1085193149Sdougb if (NAME_DEAD(name)) 1086193149Sdougb ISC_LIST_UNLINK(adb->deadnames[bucket], name, plink); 1087193149Sdougb else 1088193149Sdougb ISC_LIST_UNLINK(adb->names[bucket], name, plink); 1089135446Strhodes name->lock_bucket = DNS_ADB_INVALIDBUCKET; 1090135446Strhodes INSIST(adb->name_refcnt[bucket] > 0); 1091135446Strhodes adb->name_refcnt[bucket]--; 1092135446Strhodes if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0) 1093135446Strhodes result = ISC_TRUE; 1094135446Strhodes return (result); 1095135446Strhodes} 1096135446Strhodes 1097135446Strhodes/* 1098135446Strhodes * Requires the entry's bucket be locked. 1099135446Strhodes */ 1100135446Strhodesstatic inline void 1101135446Strhodeslink_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) { 1102193149Sdougb int i; 1103193149Sdougb dns_adbentry_t *e; 1104193149Sdougb 1105214586Sdougb if (isc_mem_isovermem(adb->mctx)) { 1106193149Sdougb for (i = 0; i < 2; i++) { 1107193149Sdougb e = ISC_LIST_TAIL(adb->entries[bucket]); 1108193149Sdougb if (e == NULL) 1109193149Sdougb break; 1110193149Sdougb if (e->refcnt == 0) { 1111193149Sdougb unlink_entry(adb, e); 1112193149Sdougb free_adbentry(adb, &e); 1113193149Sdougb continue; 1114193149Sdougb } 1115193149Sdougb INSIST((e->flags & ENTRY_IS_DEAD) == 0); 1116193149Sdougb e->flags |= ENTRY_IS_DEAD; 1117193149Sdougb ISC_LIST_UNLINK(adb->entries[bucket], e, plink); 1118193149Sdougb ISC_LIST_PREPEND(adb->deadentries[bucket], e, plink); 1119193149Sdougb } 1120193149Sdougb } 1121193149Sdougb 1122135446Strhodes ISC_LIST_PREPEND(adb->entries[bucket], entry, plink); 1123135446Strhodes entry->lock_bucket = bucket; 1124135446Strhodes adb->entry_refcnt[bucket]++; 1125135446Strhodes} 1126135446Strhodes 1127135446Strhodes/* 1128135446Strhodes * Requires the entry's bucket be locked. 1129135446Strhodes */ 1130135446Strhodesstatic inline isc_boolean_t 1131135446Strhodesunlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) { 1132135446Strhodes int bucket; 1133135446Strhodes isc_boolean_t result = ISC_FALSE; 1134135446Strhodes 1135135446Strhodes bucket = entry->lock_bucket; 1136135446Strhodes INSIST(bucket != DNS_ADB_INVALIDBUCKET); 1137135446Strhodes 1138193149Sdougb if ((entry->flags & ENTRY_IS_DEAD) != 0) 1139193149Sdougb ISC_LIST_UNLINK(adb->deadentries[bucket], entry, plink); 1140193149Sdougb else 1141193149Sdougb ISC_LIST_UNLINK(adb->entries[bucket], entry, plink); 1142135446Strhodes entry->lock_bucket = DNS_ADB_INVALIDBUCKET; 1143135446Strhodes INSIST(adb->entry_refcnt[bucket] > 0); 1144135446Strhodes adb->entry_refcnt[bucket]--; 1145135446Strhodes if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0) 1146135446Strhodes result = ISC_TRUE; 1147135446Strhodes return (result); 1148135446Strhodes} 1149135446Strhodes 1150135446Strhodesstatic inline void 1151135446Strhodesviolate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) { 1152135446Strhodes if (isc_mutex_trylock(want) != ISC_R_SUCCESS) { 1153135446Strhodes UNLOCK(have); 1154135446Strhodes LOCK(want); 1155135446Strhodes LOCK(have); 1156135446Strhodes } 1157135446Strhodes} 1158135446Strhodes 1159135446Strhodes/* 1160135446Strhodes * The ADB _MUST_ be locked before calling. Also, exit conditions must be 1161135446Strhodes * checked after calling this function. 1162135446Strhodes */ 1163135446Strhodesstatic isc_boolean_t 1164135446Strhodesshutdown_names(dns_adb_t *adb) { 1165224092Sdougb unsigned int bucket; 1166135446Strhodes isc_boolean_t result = ISC_FALSE; 1167135446Strhodes dns_adbname_t *name; 1168135446Strhodes dns_adbname_t *next_name; 1169135446Strhodes 1170224092Sdougb for (bucket = 0; bucket < adb->nnames; bucket++) { 1171135446Strhodes LOCK(&adb->namelocks[bucket]); 1172135446Strhodes adb->name_sd[bucket] = ISC_TRUE; 1173135446Strhodes 1174135446Strhodes name = ISC_LIST_HEAD(adb->names[bucket]); 1175135446Strhodes if (name == NULL) { 1176135446Strhodes /* 1177135446Strhodes * This bucket has no names. We must decrement the 1178135446Strhodes * irefcnt ourselves, since it will not be 1179135446Strhodes * automatically triggered by a name being unlinked. 1180135446Strhodes */ 1181135446Strhodes INSIST(result == ISC_FALSE); 1182135446Strhodes result = dec_adb_irefcnt(adb); 1183135446Strhodes } else { 1184135446Strhodes /* 1185135446Strhodes * Run through the list. For each name, clean up finds 1186135446Strhodes * found there, and cancel any fetches running. When 1187135446Strhodes * all the fetches are canceled, the name will destroy 1188135446Strhodes * itself. 1189135446Strhodes */ 1190135446Strhodes while (name != NULL) { 1191135446Strhodes next_name = ISC_LIST_NEXT(name, plink); 1192135446Strhodes INSIST(result == ISC_FALSE); 1193135446Strhodes result = kill_name(&name, 1194135446Strhodes DNS_EVENT_ADBSHUTDOWN); 1195135446Strhodes name = next_name; 1196135446Strhodes } 1197135446Strhodes } 1198135446Strhodes 1199135446Strhodes UNLOCK(&adb->namelocks[bucket]); 1200135446Strhodes } 1201135446Strhodes return (result); 1202135446Strhodes} 1203135446Strhodes 1204135446Strhodes/* 1205135446Strhodes * The ADB _MUST_ be locked before calling. Also, exit conditions must be 1206135446Strhodes * checked after calling this function. 1207135446Strhodes */ 1208135446Strhodesstatic isc_boolean_t 1209135446Strhodesshutdown_entries(dns_adb_t *adb) { 1210224092Sdougb unsigned int bucket; 1211135446Strhodes isc_boolean_t result = ISC_FALSE; 1212135446Strhodes dns_adbentry_t *entry; 1213135446Strhodes dns_adbentry_t *next_entry; 1214135446Strhodes 1215224092Sdougb for (bucket = 0; bucket < adb->nentries; bucket++) { 1216135446Strhodes LOCK(&adb->entrylocks[bucket]); 1217135446Strhodes adb->entry_sd[bucket] = ISC_TRUE; 1218135446Strhodes 1219135446Strhodes entry = ISC_LIST_HEAD(adb->entries[bucket]); 1220193149Sdougb if (adb->entry_refcnt[bucket] == 0) { 1221135446Strhodes /* 1222135446Strhodes * This bucket has no entries. We must decrement the 1223135446Strhodes * irefcnt ourselves, since it will not be 1224135446Strhodes * automatically triggered by an entry being unlinked. 1225135446Strhodes */ 1226135446Strhodes result = dec_adb_irefcnt(adb); 1227135446Strhodes } else { 1228135446Strhodes /* 1229135446Strhodes * Run through the list. Cleanup any entries not 1230135446Strhodes * associated with names, and which are not in use. 1231135446Strhodes */ 1232135446Strhodes while (entry != NULL) { 1233135446Strhodes next_entry = ISC_LIST_NEXT(entry, plink); 1234135446Strhodes if (entry->refcnt == 0 && 1235135446Strhodes entry->expires != 0) { 1236135446Strhodes result = unlink_entry(adb, entry); 1237135446Strhodes free_adbentry(adb, &entry); 1238135446Strhodes if (result) 1239135446Strhodes result = dec_adb_irefcnt(adb); 1240135446Strhodes } 1241135446Strhodes entry = next_entry; 1242135446Strhodes } 1243135446Strhodes } 1244135446Strhodes 1245135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 1246135446Strhodes } 1247135446Strhodes return (result); 1248135446Strhodes} 1249135446Strhodes 1250135446Strhodes/* 1251135446Strhodes * Name bucket must be locked 1252135446Strhodes */ 1253135446Strhodesstatic void 1254135446Strhodescancel_fetches_at_name(dns_adbname_t *name) { 1255135446Strhodes if (NAME_FETCH_A(name)) 1256135446Strhodes dns_resolver_cancelfetch(name->fetch_a->fetch); 1257135446Strhodes 1258135446Strhodes if (NAME_FETCH_AAAA(name)) 1259135446Strhodes dns_resolver_cancelfetch(name->fetch_aaaa->fetch); 1260135446Strhodes} 1261135446Strhodes 1262135446Strhodes/* 1263135446Strhodes * Assumes the name bucket is locked. 1264135446Strhodes */ 1265135446Strhodesstatic isc_boolean_t 1266135446Strhodesclean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) { 1267135446Strhodes dns_adbentry_t *entry; 1268135446Strhodes dns_adbnamehook_t *namehook; 1269135446Strhodes int addr_bucket; 1270135446Strhodes isc_boolean_t result = ISC_FALSE; 1271214586Sdougb isc_boolean_t overmem = isc_mem_isovermem(adb->mctx); 1272135446Strhodes 1273135446Strhodes addr_bucket = DNS_ADB_INVALIDBUCKET; 1274135446Strhodes namehook = ISC_LIST_HEAD(*namehooks); 1275135446Strhodes while (namehook != NULL) { 1276135446Strhodes INSIST(DNS_ADBNAMEHOOK_VALID(namehook)); 1277135446Strhodes 1278135446Strhodes /* 1279135446Strhodes * Clean up the entry if needed. 1280135446Strhodes */ 1281135446Strhodes entry = namehook->entry; 1282135446Strhodes if (entry != NULL) { 1283135446Strhodes INSIST(DNS_ADBENTRY_VALID(entry)); 1284135446Strhodes 1285135446Strhodes if (addr_bucket != entry->lock_bucket) { 1286135446Strhodes if (addr_bucket != DNS_ADB_INVALIDBUCKET) 1287135446Strhodes UNLOCK(&adb->entrylocks[addr_bucket]); 1288135446Strhodes addr_bucket = entry->lock_bucket; 1289254402Serwin INSIST(addr_bucket != DNS_ADB_INVALIDBUCKET); 1290135446Strhodes LOCK(&adb->entrylocks[addr_bucket]); 1291135446Strhodes } 1292135446Strhodes 1293214586Sdougb result = dec_entry_refcnt(adb, overmem, entry, 1294214586Sdougb ISC_FALSE); 1295135446Strhodes } 1296135446Strhodes 1297135446Strhodes /* 1298135446Strhodes * Free the namehook 1299135446Strhodes */ 1300135446Strhodes namehook->entry = NULL; 1301135446Strhodes ISC_LIST_UNLINK(*namehooks, namehook, plink); 1302135446Strhodes free_adbnamehook(adb, &namehook); 1303135446Strhodes 1304135446Strhodes namehook = ISC_LIST_HEAD(*namehooks); 1305135446Strhodes } 1306135446Strhodes 1307135446Strhodes if (addr_bucket != DNS_ADB_INVALIDBUCKET) 1308135446Strhodes UNLOCK(&adb->entrylocks[addr_bucket]); 1309135446Strhodes return (result); 1310135446Strhodes} 1311135446Strhodes 1312135446Strhodesstatic void 1313135446Strhodesclean_target(dns_adb_t *adb, dns_name_t *target) { 1314135446Strhodes if (dns_name_countlabels(target) > 0) { 1315135446Strhodes dns_name_free(target, adb->mctx); 1316135446Strhodes dns_name_init(target, NULL); 1317135446Strhodes } 1318135446Strhodes} 1319135446Strhodes 1320135446Strhodesstatic isc_result_t 1321135446Strhodesset_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname, 1322135446Strhodes dns_rdataset_t *rdataset, dns_name_t *target) 1323135446Strhodes{ 1324135446Strhodes isc_result_t result; 1325135446Strhodes dns_namereln_t namereln; 1326135446Strhodes unsigned int nlabels; 1327135446Strhodes int order; 1328135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 1329135446Strhodes dns_fixedname_t fixed1, fixed2; 1330135446Strhodes dns_name_t *prefix, *new_target; 1331135446Strhodes 1332135446Strhodes REQUIRE(dns_name_countlabels(target) == 0); 1333135446Strhodes 1334135446Strhodes if (rdataset->type == dns_rdatatype_cname) { 1335135446Strhodes dns_rdata_cname_t cname; 1336135446Strhodes 1337135446Strhodes /* 1338135446Strhodes * Copy the CNAME's target into the target name. 1339135446Strhodes */ 1340135446Strhodes result = dns_rdataset_first(rdataset); 1341135446Strhodes if (result != ISC_R_SUCCESS) 1342135446Strhodes return (result); 1343135446Strhodes dns_rdataset_current(rdataset, &rdata); 1344135446Strhodes result = dns_rdata_tostruct(&rdata, &cname, NULL); 1345135446Strhodes if (result != ISC_R_SUCCESS) 1346135446Strhodes return (result); 1347135446Strhodes result = dns_name_dup(&cname.cname, adb->mctx, target); 1348135446Strhodes dns_rdata_freestruct(&cname); 1349135446Strhodes if (result != ISC_R_SUCCESS) 1350135446Strhodes return (result); 1351135446Strhodes } else { 1352135446Strhodes dns_rdata_dname_t dname; 1353135446Strhodes 1354135446Strhodes INSIST(rdataset->type == dns_rdatatype_dname); 1355135446Strhodes namereln = dns_name_fullcompare(name, fname, &order, &nlabels); 1356135446Strhodes INSIST(namereln == dns_namereln_subdomain); 1357135446Strhodes /* 1358135446Strhodes * Get the target name of the DNAME. 1359135446Strhodes */ 1360135446Strhodes result = dns_rdataset_first(rdataset); 1361135446Strhodes if (result != ISC_R_SUCCESS) 1362135446Strhodes return (result); 1363135446Strhodes dns_rdataset_current(rdataset, &rdata); 1364135446Strhodes result = dns_rdata_tostruct(&rdata, &dname, NULL); 1365135446Strhodes if (result != ISC_R_SUCCESS) 1366135446Strhodes return (result); 1367135446Strhodes /* 1368135446Strhodes * Construct the new target name. 1369135446Strhodes */ 1370135446Strhodes dns_fixedname_init(&fixed1); 1371135446Strhodes prefix = dns_fixedname_name(&fixed1); 1372135446Strhodes dns_fixedname_init(&fixed2); 1373135446Strhodes new_target = dns_fixedname_name(&fixed2); 1374135446Strhodes dns_name_split(name, nlabels, prefix, NULL); 1375135446Strhodes result = dns_name_concatenate(prefix, &dname.dname, new_target, 1376135446Strhodes NULL); 1377135446Strhodes dns_rdata_freestruct(&dname); 1378135446Strhodes if (result != ISC_R_SUCCESS) 1379135446Strhodes return (result); 1380135446Strhodes result = dns_name_dup(new_target, adb->mctx, target); 1381135446Strhodes if (result != ISC_R_SUCCESS) 1382135446Strhodes return (result); 1383135446Strhodes } 1384135446Strhodes 1385135446Strhodes return (ISC_R_SUCCESS); 1386135446Strhodes} 1387135446Strhodes 1388135446Strhodes/* 1389135446Strhodes * Assumes nothing is locked, since this is called by the client. 1390135446Strhodes */ 1391135446Strhodesstatic void 1392135446Strhodesevent_free(isc_event_t *event) { 1393135446Strhodes dns_adbfind_t *find; 1394135446Strhodes 1395135446Strhodes INSIST(event != NULL); 1396135446Strhodes find = event->ev_destroy_arg; 1397135446Strhodes INSIST(DNS_ADBFIND_VALID(find)); 1398135446Strhodes 1399135446Strhodes LOCK(&find->lock); 1400135446Strhodes find->flags |= FIND_EVENT_FREED; 1401135446Strhodes event->ev_destroy_arg = NULL; 1402135446Strhodes UNLOCK(&find->lock); 1403135446Strhodes} 1404135446Strhodes 1405135446Strhodes/* 1406135446Strhodes * Assumes the name bucket is locked. 1407135446Strhodes */ 1408135446Strhodesstatic void 1409135446Strhodesclean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype, 1410135446Strhodes unsigned int addrs) 1411135446Strhodes{ 1412135446Strhodes isc_event_t *ev; 1413135446Strhodes isc_task_t *task; 1414135446Strhodes dns_adbfind_t *find; 1415135446Strhodes dns_adbfind_t *next_find; 1416135446Strhodes isc_boolean_t process; 1417135446Strhodes unsigned int wanted, notify; 1418135446Strhodes 1419135446Strhodes DP(ENTER_LEVEL, 1420135446Strhodes "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x", 1421135446Strhodes name, evtype, addrs); 1422135446Strhodes 1423135446Strhodes find = ISC_LIST_HEAD(name->finds); 1424135446Strhodes while (find != NULL) { 1425135446Strhodes LOCK(&find->lock); 1426135446Strhodes next_find = ISC_LIST_NEXT(find, plink); 1427135446Strhodes 1428135446Strhodes process = ISC_FALSE; 1429135446Strhodes wanted = find->flags & DNS_ADBFIND_ADDRESSMASK; 1430135446Strhodes notify = wanted & addrs; 1431135446Strhodes 1432135446Strhodes switch (evtype) { 1433135446Strhodes case DNS_EVENT_ADBMOREADDRESSES: 1434135446Strhodes DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES"); 1435135446Strhodes if ((notify) != 0) { 1436135446Strhodes find->flags &= ~addrs; 1437135446Strhodes process = ISC_TRUE; 1438135446Strhodes } 1439135446Strhodes break; 1440135446Strhodes case DNS_EVENT_ADBNOMOREADDRESSES: 1441135446Strhodes DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES"); 1442135446Strhodes find->flags &= ~addrs; 1443135446Strhodes wanted = find->flags & DNS_ADBFIND_ADDRESSMASK; 1444135446Strhodes if (wanted == 0) 1445135446Strhodes process = ISC_TRUE; 1446135446Strhodes break; 1447135446Strhodes default: 1448135446Strhodes find->flags &= ~addrs; 1449135446Strhodes process = ISC_TRUE; 1450135446Strhodes } 1451135446Strhodes 1452135446Strhodes if (process) { 1453135446Strhodes DP(DEF_LEVEL, "cfan: processing find %p", find); 1454135446Strhodes /* 1455135446Strhodes * Unlink the find from the name, letting the caller 1456135446Strhodes * call dns_adb_destroyfind() on it to clean it up 1457135446Strhodes * later. 1458135446Strhodes */ 1459135446Strhodes ISC_LIST_UNLINK(name->finds, find, plink); 1460135446Strhodes find->adbname = NULL; 1461135446Strhodes find->name_bucket = DNS_ADB_INVALIDBUCKET; 1462135446Strhodes 1463135446Strhodes INSIST(!FIND_EVENTSENT(find)); 1464135446Strhodes 1465135446Strhodes ev = &find->event; 1466135446Strhodes task = ev->ev_sender; 1467135446Strhodes ev->ev_sender = find; 1468135446Strhodes find->result_v4 = find_err_map[name->fetch_err]; 1469135446Strhodes find->result_v6 = find_err_map[name->fetch6_err]; 1470135446Strhodes ev->ev_type = evtype; 1471135446Strhodes ev->ev_destroy = event_free; 1472135446Strhodes ev->ev_destroy_arg = find; 1473135446Strhodes 1474135446Strhodes DP(DEF_LEVEL, 1475135446Strhodes "sending event %p to task %p for find %p", 1476135446Strhodes ev, task, find); 1477135446Strhodes 1478135446Strhodes isc_task_sendanddetach(&task, (isc_event_t **)&ev); 1479135446Strhodes } else { 1480135446Strhodes DP(DEF_LEVEL, "cfan: skipping find %p", find); 1481135446Strhodes } 1482135446Strhodes 1483135446Strhodes UNLOCK(&find->lock); 1484135446Strhodes find = next_find; 1485135446Strhodes } 1486135446Strhodes 1487135446Strhodes DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name); 1488135446Strhodes} 1489135446Strhodes 1490135446Strhodesstatic inline void 1491135446Strhodescheck_exit(dns_adb_t *adb) { 1492135446Strhodes isc_event_t *event; 1493135446Strhodes /* 1494135446Strhodes * The caller must be holding the adb lock. 1495135446Strhodes */ 1496135446Strhodes if (adb->shutting_down) { 1497135446Strhodes /* 1498135446Strhodes * If there aren't any external references either, we're 1499135446Strhodes * done. Send the control event to initiate shutdown. 1500135446Strhodes */ 1501193149Sdougb INSIST(!adb->cevent_sent); /* Sanity check. */ 1502135446Strhodes event = &adb->cevent; 1503135446Strhodes isc_task_send(adb->task, &event); 1504135446Strhodes adb->cevent_sent = ISC_TRUE; 1505135446Strhodes } 1506135446Strhodes} 1507135446Strhodes 1508135446Strhodesstatic inline isc_boolean_t 1509135446Strhodesdec_adb_irefcnt(dns_adb_t *adb) { 1510135446Strhodes isc_event_t *event; 1511135446Strhodes isc_task_t *etask; 1512135446Strhodes isc_boolean_t result = ISC_FALSE; 1513135446Strhodes 1514135446Strhodes LOCK(&adb->reflock); 1515135446Strhodes 1516135446Strhodes INSIST(adb->irefcnt > 0); 1517135446Strhodes adb->irefcnt--; 1518135446Strhodes 1519135446Strhodes if (adb->irefcnt == 0) { 1520135446Strhodes event = ISC_LIST_HEAD(adb->whenshutdown); 1521135446Strhodes while (event != NULL) { 1522135446Strhodes ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link); 1523135446Strhodes etask = event->ev_sender; 1524135446Strhodes event->ev_sender = adb; 1525135446Strhodes isc_task_sendanddetach(&etask, &event); 1526135446Strhodes event = ISC_LIST_HEAD(adb->whenshutdown); 1527135446Strhodes } 1528135446Strhodes } 1529135446Strhodes 1530135446Strhodes if (adb->irefcnt == 0 && adb->erefcnt == 0) 1531135446Strhodes result = ISC_TRUE; 1532135446Strhodes UNLOCK(&adb->reflock); 1533135446Strhodes return (result); 1534135446Strhodes} 1535135446Strhodes 1536135446Strhodesstatic inline void 1537135446Strhodesinc_adb_irefcnt(dns_adb_t *adb) { 1538135446Strhodes LOCK(&adb->reflock); 1539135446Strhodes adb->irefcnt++; 1540135446Strhodes UNLOCK(&adb->reflock); 1541135446Strhodes} 1542135446Strhodes 1543135446Strhodesstatic inline void 1544135446Strhodesinc_adb_erefcnt(dns_adb_t *adb) { 1545135446Strhodes LOCK(&adb->reflock); 1546135446Strhodes adb->erefcnt++; 1547135446Strhodes UNLOCK(&adb->reflock); 1548135446Strhodes} 1549135446Strhodes 1550135446Strhodesstatic inline void 1551135446Strhodesinc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) { 1552135446Strhodes int bucket; 1553135446Strhodes 1554135446Strhodes bucket = entry->lock_bucket; 1555135446Strhodes 1556135446Strhodes if (lock) 1557135446Strhodes LOCK(&adb->entrylocks[bucket]); 1558135446Strhodes 1559135446Strhodes entry->refcnt++; 1560135446Strhodes 1561135446Strhodes if (lock) 1562135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 1563135446Strhodes} 1564135446Strhodes 1565135446Strhodesstatic inline isc_boolean_t 1566214586Sdougbdec_entry_refcnt(dns_adb_t *adb, isc_boolean_t overmem, dns_adbentry_t *entry, 1567214586Sdougb isc_boolean_t lock) 1568214586Sdougb{ 1569135446Strhodes int bucket; 1570135446Strhodes isc_boolean_t destroy_entry; 1571135446Strhodes isc_boolean_t result = ISC_FALSE; 1572135446Strhodes 1573135446Strhodes bucket = entry->lock_bucket; 1574135446Strhodes 1575135446Strhodes if (lock) 1576135446Strhodes LOCK(&adb->entrylocks[bucket]); 1577135446Strhodes 1578135446Strhodes INSIST(entry->refcnt > 0); 1579135446Strhodes entry->refcnt--; 1580135446Strhodes 1581135446Strhodes destroy_entry = ISC_FALSE; 1582135446Strhodes if (entry->refcnt == 0 && 1583214586Sdougb (adb->entry_sd[bucket] || entry->expires == 0 || overmem || 1584193149Sdougb (entry->flags & ENTRY_IS_DEAD) != 0)) { 1585135446Strhodes destroy_entry = ISC_TRUE; 1586135446Strhodes result = unlink_entry(adb, entry); 1587135446Strhodes } 1588135446Strhodes 1589135446Strhodes if (lock) 1590135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 1591135446Strhodes 1592135446Strhodes if (!destroy_entry) 1593135446Strhodes return (result); 1594135446Strhodes 1595135446Strhodes entry->lock_bucket = DNS_ADB_INVALIDBUCKET; 1596135446Strhodes 1597135446Strhodes free_adbentry(adb, &entry); 1598135446Strhodes if (result) 1599193149Sdougb result = dec_adb_irefcnt(adb); 1600135446Strhodes 1601135446Strhodes return (result); 1602135446Strhodes} 1603135446Strhodes 1604135446Strhodesstatic inline dns_adbname_t * 1605135446Strhodesnew_adbname(dns_adb_t *adb, dns_name_t *dnsname) { 1606135446Strhodes dns_adbname_t *name; 1607135446Strhodes 1608135446Strhodes name = isc_mempool_get(adb->nmp); 1609135446Strhodes if (name == NULL) 1610135446Strhodes return (NULL); 1611135446Strhodes 1612135446Strhodes dns_name_init(&name->name, NULL); 1613135446Strhodes if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) { 1614135446Strhodes isc_mempool_put(adb->nmp, name); 1615135446Strhodes return (NULL); 1616135446Strhodes } 1617135446Strhodes dns_name_init(&name->target, NULL); 1618135446Strhodes name->magic = DNS_ADBNAME_MAGIC; 1619135446Strhodes name->adb = adb; 1620135446Strhodes name->partial_result = 0; 1621135446Strhodes name->flags = 0; 1622135446Strhodes name->expire_v4 = INT_MAX; 1623135446Strhodes name->expire_v6 = INT_MAX; 1624135446Strhodes name->expire_target = INT_MAX; 1625135446Strhodes name->chains = 0; 1626135446Strhodes name->lock_bucket = DNS_ADB_INVALIDBUCKET; 1627135446Strhodes ISC_LIST_INIT(name->v4); 1628135446Strhodes ISC_LIST_INIT(name->v6); 1629135446Strhodes name->fetch_a = NULL; 1630135446Strhodes name->fetch_aaaa = NULL; 1631135446Strhodes name->fetch_err = FIND_ERR_UNEXPECTED; 1632135446Strhodes name->fetch6_err = FIND_ERR_UNEXPECTED; 1633135446Strhodes ISC_LIST_INIT(name->finds); 1634135446Strhodes ISC_LINK_INIT(name, plink); 1635135446Strhodes 1636224092Sdougb LOCK(&adb->namescntlock); 1637224092Sdougb adb->namescnt++; 1638245163Serwin if (!adb->grownames_sent && adb->excl != NULL && 1639245163Serwin adb->namescnt > (adb->nnames * 8)) 1640245163Serwin { 1641224092Sdougb isc_event_t *event = &adb->grownames; 1642224092Sdougb inc_adb_irefcnt(adb); 1643245163Serwin isc_task_send(adb->excl, &event); 1644224092Sdougb adb->grownames_sent = ISC_TRUE; 1645224092Sdougb } 1646224092Sdougb UNLOCK(&adb->namescntlock); 1647224092Sdougb 1648135446Strhodes return (name); 1649135446Strhodes} 1650135446Strhodes 1651135446Strhodesstatic inline void 1652135446Strhodesfree_adbname(dns_adb_t *adb, dns_adbname_t **name) { 1653135446Strhodes dns_adbname_t *n; 1654135446Strhodes 1655135446Strhodes INSIST(name != NULL && DNS_ADBNAME_VALID(*name)); 1656135446Strhodes n = *name; 1657135446Strhodes *name = NULL; 1658135446Strhodes 1659135446Strhodes INSIST(!NAME_HAS_V4(n)); 1660135446Strhodes INSIST(!NAME_HAS_V6(n)); 1661135446Strhodes INSIST(!NAME_FETCH(n)); 1662135446Strhodes INSIST(ISC_LIST_EMPTY(n->finds)); 1663135446Strhodes INSIST(!ISC_LINK_LINKED(n, plink)); 1664135446Strhodes INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET); 1665135446Strhodes INSIST(n->adb == adb); 1666135446Strhodes 1667135446Strhodes n->magic = 0; 1668135446Strhodes dns_name_free(&n->name, adb->mctx); 1669135446Strhodes 1670135446Strhodes isc_mempool_put(adb->nmp, n); 1671224092Sdougb LOCK(&adb->namescntlock); 1672224092Sdougb adb->namescnt--; 1673224092Sdougb UNLOCK(&adb->namescntlock); 1674135446Strhodes} 1675135446Strhodes 1676135446Strhodesstatic inline dns_adbnamehook_t * 1677135446Strhodesnew_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) { 1678135446Strhodes dns_adbnamehook_t *nh; 1679135446Strhodes 1680135446Strhodes nh = isc_mempool_get(adb->nhmp); 1681135446Strhodes if (nh == NULL) 1682135446Strhodes return (NULL); 1683135446Strhodes 1684135446Strhodes nh->magic = DNS_ADBNAMEHOOK_MAGIC; 1685135446Strhodes nh->entry = entry; 1686135446Strhodes ISC_LINK_INIT(nh, plink); 1687135446Strhodes 1688135446Strhodes return (nh); 1689135446Strhodes} 1690135446Strhodes 1691135446Strhodesstatic inline void 1692135446Strhodesfree_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) { 1693135446Strhodes dns_adbnamehook_t *nh; 1694135446Strhodes 1695135446Strhodes INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook)); 1696135446Strhodes nh = *namehook; 1697135446Strhodes *namehook = NULL; 1698135446Strhodes 1699135446Strhodes INSIST(nh->entry == NULL); 1700135446Strhodes INSIST(!ISC_LINK_LINKED(nh, plink)); 1701135446Strhodes 1702135446Strhodes nh->magic = 0; 1703135446Strhodes isc_mempool_put(adb->nhmp, nh); 1704135446Strhodes} 1705135446Strhodes 1706170222Sdougbstatic inline dns_adblameinfo_t * 1707170222Sdougbnew_adblameinfo(dns_adb_t *adb, dns_name_t *qname, dns_rdatatype_t qtype) { 1708170222Sdougb dns_adblameinfo_t *li; 1709135446Strhodes 1710170222Sdougb li = isc_mempool_get(adb->limp); 1711170222Sdougb if (li == NULL) 1712135446Strhodes return (NULL); 1713135446Strhodes 1714170222Sdougb dns_name_init(&li->qname, NULL); 1715170222Sdougb if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) { 1716170222Sdougb isc_mempool_put(adb->limp, li); 1717135446Strhodes return (NULL); 1718135446Strhodes } 1719170222Sdougb li->magic = DNS_ADBLAMEINFO_MAGIC; 1720170222Sdougb li->lame_timer = 0; 1721170222Sdougb li->qtype = qtype; 1722170222Sdougb ISC_LINK_INIT(li, plink); 1723135446Strhodes 1724170222Sdougb return (li); 1725135446Strhodes} 1726135446Strhodes 1727135446Strhodesstatic inline void 1728170222Sdougbfree_adblameinfo(dns_adb_t *adb, dns_adblameinfo_t **lameinfo) { 1729170222Sdougb dns_adblameinfo_t *li; 1730135446Strhodes 1731170222Sdougb INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo)); 1732170222Sdougb li = *lameinfo; 1733170222Sdougb *lameinfo = NULL; 1734135446Strhodes 1735170222Sdougb INSIST(!ISC_LINK_LINKED(li, plink)); 1736135446Strhodes 1737170222Sdougb dns_name_free(&li->qname, adb->mctx); 1738135446Strhodes 1739170222Sdougb li->magic = 0; 1740135446Strhodes 1741170222Sdougb isc_mempool_put(adb->limp, li); 1742135446Strhodes} 1743135446Strhodes 1744135446Strhodesstatic inline dns_adbentry_t * 1745135446Strhodesnew_adbentry(dns_adb_t *adb) { 1746135446Strhodes dns_adbentry_t *e; 1747135446Strhodes isc_uint32_t r; 1748135446Strhodes 1749135446Strhodes e = isc_mempool_get(adb->emp); 1750135446Strhodes if (e == NULL) 1751135446Strhodes return (NULL); 1752135446Strhodes 1753135446Strhodes e->magic = DNS_ADBENTRY_MAGIC; 1754135446Strhodes e->lock_bucket = DNS_ADB_INVALIDBUCKET; 1755135446Strhodes e->refcnt = 0; 1756135446Strhodes e->flags = 0; 1757135446Strhodes isc_random_get(&r); 1758135446Strhodes e->srtt = (r & 0x1f) + 1; 1759135446Strhodes e->expires = 0; 1760170222Sdougb ISC_LIST_INIT(e->lameinfo); 1761135446Strhodes ISC_LINK_INIT(e, plink); 1762224092Sdougb LOCK(&adb->entriescntlock); 1763224092Sdougb adb->entriescnt++; 1764245163Serwin if (!adb->growentries_sent && adb->growentries_sent && 1765245163Serwin adb->entriescnt > (adb->nentries * 8)) 1766245163Serwin { 1767224092Sdougb isc_event_t *event = &adb->growentries; 1768224092Sdougb inc_adb_irefcnt(adb); 1769224092Sdougb isc_task_send(adb->task, &event); 1770224092Sdougb adb->growentries_sent = ISC_TRUE; 1771224092Sdougb } 1772224092Sdougb UNLOCK(&adb->entriescntlock); 1773135446Strhodes 1774135446Strhodes return (e); 1775135446Strhodes} 1776135446Strhodes 1777135446Strhodesstatic inline void 1778135446Strhodesfree_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) { 1779135446Strhodes dns_adbentry_t *e; 1780170222Sdougb dns_adblameinfo_t *li; 1781135446Strhodes 1782135446Strhodes INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry)); 1783135446Strhodes e = *entry; 1784135446Strhodes *entry = NULL; 1785135446Strhodes 1786135446Strhodes INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET); 1787135446Strhodes INSIST(e->refcnt == 0); 1788135446Strhodes INSIST(!ISC_LINK_LINKED(e, plink)); 1789135446Strhodes 1790135446Strhodes e->magic = 0; 1791135446Strhodes 1792170222Sdougb li = ISC_LIST_HEAD(e->lameinfo); 1793170222Sdougb while (li != NULL) { 1794170222Sdougb ISC_LIST_UNLINK(e->lameinfo, li, plink); 1795170222Sdougb free_adblameinfo(adb, &li); 1796170222Sdougb li = ISC_LIST_HEAD(e->lameinfo); 1797135446Strhodes } 1798135446Strhodes 1799135446Strhodes isc_mempool_put(adb->emp, e); 1800224092Sdougb LOCK(&adb->entriescntlock); 1801224092Sdougb adb->entriescnt--; 1802224092Sdougb UNLOCK(&adb->entriescntlock); 1803135446Strhodes} 1804135446Strhodes 1805135446Strhodesstatic inline dns_adbfind_t * 1806135446Strhodesnew_adbfind(dns_adb_t *adb) { 1807135446Strhodes dns_adbfind_t *h; 1808135446Strhodes isc_result_t result; 1809135446Strhodes 1810135446Strhodes h = isc_mempool_get(adb->ahmp); 1811135446Strhodes if (h == NULL) 1812135446Strhodes return (NULL); 1813135446Strhodes 1814135446Strhodes /* 1815135446Strhodes * Public members. 1816135446Strhodes */ 1817135446Strhodes h->magic = 0; 1818135446Strhodes h->adb = adb; 1819135446Strhodes h->partial_result = 0; 1820135446Strhodes h->options = 0; 1821135446Strhodes h->flags = 0; 1822135446Strhodes h->result_v4 = ISC_R_UNEXPECTED; 1823135446Strhodes h->result_v6 = ISC_R_UNEXPECTED; 1824135446Strhodes ISC_LINK_INIT(h, publink); 1825135446Strhodes ISC_LINK_INIT(h, plink); 1826135446Strhodes ISC_LIST_INIT(h->list); 1827135446Strhodes h->adbname = NULL; 1828135446Strhodes h->name_bucket = DNS_ADB_INVALIDBUCKET; 1829135446Strhodes 1830135446Strhodes /* 1831135446Strhodes * private members 1832135446Strhodes */ 1833135446Strhodes result = isc_mutex_init(&h->lock); 1834135446Strhodes if (result != ISC_R_SUCCESS) { 1835135446Strhodes isc_mempool_put(adb->ahmp, h); 1836135446Strhodes return (NULL); 1837135446Strhodes } 1838135446Strhodes 1839135446Strhodes ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL, 1840135446Strhodes NULL, NULL, h); 1841135446Strhodes 1842135446Strhodes inc_adb_irefcnt(adb); 1843135446Strhodes h->magic = DNS_ADBFIND_MAGIC; 1844135446Strhodes return (h); 1845135446Strhodes} 1846135446Strhodes 1847135446Strhodesstatic inline dns_adbfetch_t * 1848135446Strhodesnew_adbfetch(dns_adb_t *adb) { 1849135446Strhodes dns_adbfetch_t *f; 1850135446Strhodes 1851135446Strhodes f = isc_mempool_get(adb->afmp); 1852135446Strhodes if (f == NULL) 1853135446Strhodes return (NULL); 1854135446Strhodes 1855135446Strhodes f->magic = 0; 1856135446Strhodes f->fetch = NULL; 1857135446Strhodes 1858135446Strhodes dns_rdataset_init(&f->rdataset); 1859135446Strhodes 1860135446Strhodes f->magic = DNS_ADBFETCH_MAGIC; 1861135446Strhodes 1862135446Strhodes return (f); 1863135446Strhodes} 1864135446Strhodes 1865135446Strhodesstatic inline void 1866135446Strhodesfree_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) { 1867135446Strhodes dns_adbfetch_t *f; 1868135446Strhodes 1869135446Strhodes INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch)); 1870135446Strhodes f = *fetch; 1871135446Strhodes *fetch = NULL; 1872135446Strhodes 1873135446Strhodes f->magic = 0; 1874135446Strhodes 1875135446Strhodes if (dns_rdataset_isassociated(&f->rdataset)) 1876135446Strhodes dns_rdataset_disassociate(&f->rdataset); 1877135446Strhodes 1878135446Strhodes isc_mempool_put(adb->afmp, f); 1879135446Strhodes} 1880135446Strhodes 1881135446Strhodesstatic inline isc_boolean_t 1882135446Strhodesfree_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) { 1883135446Strhodes dns_adbfind_t *find; 1884135446Strhodes 1885135446Strhodes INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp)); 1886135446Strhodes find = *findp; 1887135446Strhodes *findp = NULL; 1888135446Strhodes 1889135446Strhodes INSIST(!FIND_HAS_ADDRS(find)); 1890135446Strhodes INSIST(!ISC_LINK_LINKED(find, publink)); 1891135446Strhodes INSIST(!ISC_LINK_LINKED(find, plink)); 1892135446Strhodes INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET); 1893135446Strhodes INSIST(find->adbname == NULL); 1894135446Strhodes 1895135446Strhodes find->magic = 0; 1896135446Strhodes 1897135446Strhodes DESTROYLOCK(&find->lock); 1898135446Strhodes isc_mempool_put(adb->ahmp, find); 1899135446Strhodes return (dec_adb_irefcnt(adb)); 1900135446Strhodes} 1901135446Strhodes 1902135446Strhodes/* 1903135446Strhodes * Copy bits from the entry into the newly allocated addrinfo. The entry 1904135446Strhodes * must be locked, and the reference count must be bumped up by one 1905135446Strhodes * if this function returns a valid pointer. 1906135446Strhodes */ 1907135446Strhodesstatic inline dns_adbaddrinfo_t * 1908135446Strhodesnew_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) { 1909135446Strhodes dns_adbaddrinfo_t *ai; 1910135446Strhodes 1911135446Strhodes ai = isc_mempool_get(adb->aimp); 1912135446Strhodes if (ai == NULL) 1913135446Strhodes return (NULL); 1914135446Strhodes 1915135446Strhodes ai->magic = DNS_ADBADDRINFO_MAGIC; 1916135446Strhodes ai->sockaddr = entry->sockaddr; 1917135446Strhodes isc_sockaddr_setport(&ai->sockaddr, port); 1918135446Strhodes ai->srtt = entry->srtt; 1919135446Strhodes ai->flags = entry->flags; 1920135446Strhodes ai->entry = entry; 1921135446Strhodes ISC_LINK_INIT(ai, publink); 1922135446Strhodes 1923135446Strhodes return (ai); 1924135446Strhodes} 1925135446Strhodes 1926135446Strhodesstatic inline void 1927135446Strhodesfree_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) { 1928135446Strhodes dns_adbaddrinfo_t *ai; 1929135446Strhodes 1930135446Strhodes INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo)); 1931135446Strhodes ai = *ainfo; 1932135446Strhodes *ainfo = NULL; 1933135446Strhodes 1934135446Strhodes INSIST(ai->entry == NULL); 1935135446Strhodes INSIST(!ISC_LINK_LINKED(ai, publink)); 1936135446Strhodes 1937135446Strhodes ai->magic = 0; 1938135446Strhodes 1939135446Strhodes isc_mempool_put(adb->aimp, ai); 1940135446Strhodes} 1941135446Strhodes 1942135446Strhodes/* 1943135446Strhodes * Search for the name. NOTE: The bucket is kept locked on both 1944135446Strhodes * success and failure, so it must always be unlocked by the caller! 1945135446Strhodes * 1946135446Strhodes * On the first call to this function, *bucketp must be set to 1947135446Strhodes * DNS_ADB_INVALIDBUCKET. 1948135446Strhodes */ 1949135446Strhodesstatic inline dns_adbname_t * 1950135446Strhodesfind_name_and_lock(dns_adb_t *adb, dns_name_t *name, 1951135446Strhodes unsigned int options, int *bucketp) 1952135446Strhodes{ 1953135446Strhodes dns_adbname_t *adbname; 1954135446Strhodes int bucket; 1955135446Strhodes 1956224092Sdougb bucket = dns_name_fullhash(name, ISC_FALSE) % adb->nnames; 1957135446Strhodes 1958135446Strhodes if (*bucketp == DNS_ADB_INVALIDBUCKET) { 1959135446Strhodes LOCK(&adb->namelocks[bucket]); 1960135446Strhodes *bucketp = bucket; 1961135446Strhodes } else if (*bucketp != bucket) { 1962135446Strhodes UNLOCK(&adb->namelocks[*bucketp]); 1963135446Strhodes LOCK(&adb->namelocks[bucket]); 1964135446Strhodes *bucketp = bucket; 1965135446Strhodes } 1966135446Strhodes 1967135446Strhodes adbname = ISC_LIST_HEAD(adb->names[bucket]); 1968135446Strhodes while (adbname != NULL) { 1969135446Strhodes if (!NAME_DEAD(adbname)) { 1970135446Strhodes if (dns_name_equal(name, &adbname->name) 1971135446Strhodes && GLUEHINT_OK(adbname, options) 1972135446Strhodes && STARTATZONE_MATCHES(adbname, options)) 1973135446Strhodes return (adbname); 1974135446Strhodes } 1975135446Strhodes adbname = ISC_LIST_NEXT(adbname, plink); 1976135446Strhodes } 1977135446Strhodes 1978135446Strhodes return (NULL); 1979135446Strhodes} 1980135446Strhodes 1981135446Strhodes/* 1982135446Strhodes * Search for the address. NOTE: The bucket is kept locked on both 1983135446Strhodes * success and failure, so it must always be unlocked by the caller. 1984135446Strhodes * 1985135446Strhodes * On the first call to this function, *bucketp must be set to 1986135446Strhodes * DNS_ADB_INVALIDBUCKET. This will cause a lock to occur. On 1987135446Strhodes * later calls (within the same "lock path") it can be left alone, so 1988135446Strhodes * if this function is called multiple times locking is only done if 1989135446Strhodes * the bucket changes. 1990135446Strhodes */ 1991135446Strhodesstatic inline dns_adbentry_t * 1992193149Sdougbfind_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp, 1993193149Sdougb isc_stdtime_t now) 1994193149Sdougb{ 1995193149Sdougb dns_adbentry_t *entry, *entry_next; 1996135446Strhodes int bucket; 1997135446Strhodes 1998224092Sdougb bucket = isc_sockaddr_hash(addr, ISC_TRUE) % adb->nentries; 1999135446Strhodes 2000135446Strhodes if (*bucketp == DNS_ADB_INVALIDBUCKET) { 2001135446Strhodes LOCK(&adb->entrylocks[bucket]); 2002135446Strhodes *bucketp = bucket; 2003135446Strhodes } else if (*bucketp != bucket) { 2004135446Strhodes UNLOCK(&adb->entrylocks[*bucketp]); 2005135446Strhodes LOCK(&adb->entrylocks[bucket]); 2006135446Strhodes *bucketp = bucket; 2007135446Strhodes } 2008135446Strhodes 2009193149Sdougb /* Search the list, while cleaning up expired entries. */ 2010193149Sdougb for (entry = ISC_LIST_HEAD(adb->entries[bucket]); 2011193149Sdougb entry != NULL; 2012193149Sdougb entry = entry_next) { 2013193149Sdougb entry_next = ISC_LIST_NEXT(entry, plink); 2014193149Sdougb (void)check_expire_entry(adb, &entry, now); 2015193149Sdougb if (entry != NULL && 2016193149Sdougb isc_sockaddr_equal(addr, &entry->sockaddr)) { 2017193149Sdougb ISC_LIST_UNLINK(adb->entries[bucket], entry, plink); 2018193149Sdougb ISC_LIST_PREPEND(adb->entries[bucket], entry, plink); 2019135446Strhodes return (entry); 2020193149Sdougb } 2021135446Strhodes } 2022135446Strhodes 2023135446Strhodes return (NULL); 2024135446Strhodes} 2025135446Strhodes 2026135446Strhodes/* 2027135446Strhodes * Entry bucket MUST be locked! 2028135446Strhodes */ 2029135446Strhodesstatic isc_boolean_t 2030170222Sdougbentry_is_lame(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *qname, 2031170222Sdougb dns_rdatatype_t qtype, isc_stdtime_t now) 2032135446Strhodes{ 2033170222Sdougb dns_adblameinfo_t *li, *next_li; 2034135446Strhodes isc_boolean_t is_bad; 2035135446Strhodes 2036135446Strhodes is_bad = ISC_FALSE; 2037135446Strhodes 2038170222Sdougb li = ISC_LIST_HEAD(entry->lameinfo); 2039170222Sdougb if (li == NULL) 2040135446Strhodes return (ISC_FALSE); 2041170222Sdougb while (li != NULL) { 2042170222Sdougb next_li = ISC_LIST_NEXT(li, plink); 2043135446Strhodes 2044135446Strhodes /* 2045135446Strhodes * Has the entry expired? 2046135446Strhodes */ 2047170222Sdougb if (li->lame_timer < now) { 2048170222Sdougb ISC_LIST_UNLINK(entry->lameinfo, li, plink); 2049170222Sdougb free_adblameinfo(adb, &li); 2050135446Strhodes } 2051135446Strhodes 2052135446Strhodes /* 2053135446Strhodes * Order tests from least to most expensive. 2054170222Sdougb * 2055170222Sdougb * We do not break out of the main loop here as 2056170222Sdougb * we use the loop for house keeping. 2057135446Strhodes */ 2058170222Sdougb if (li != NULL && !is_bad && li->qtype == qtype && 2059170222Sdougb dns_name_equal(qname, &li->qname)) 2060170222Sdougb is_bad = ISC_TRUE; 2061135446Strhodes 2062170222Sdougb li = next_li; 2063135446Strhodes } 2064135446Strhodes 2065135446Strhodes return (is_bad); 2066135446Strhodes} 2067135446Strhodes 2068135446Strhodesstatic void 2069170222Sdougbcopy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname, 2070170222Sdougb dns_rdatatype_t qtype, dns_adbname_t *name, 2071170222Sdougb isc_stdtime_t now) 2072135446Strhodes{ 2073135446Strhodes dns_adbnamehook_t *namehook; 2074135446Strhodes dns_adbaddrinfo_t *addrinfo; 2075135446Strhodes dns_adbentry_t *entry; 2076135446Strhodes int bucket; 2077135446Strhodes 2078135446Strhodes bucket = DNS_ADB_INVALIDBUCKET; 2079135446Strhodes 2080135446Strhodes if (find->options & DNS_ADBFIND_INET) { 2081135446Strhodes namehook = ISC_LIST_HEAD(name->v4); 2082135446Strhodes while (namehook != NULL) { 2083135446Strhodes entry = namehook->entry; 2084135446Strhodes bucket = entry->lock_bucket; 2085254402Serwin INSIST(bucket != DNS_ADB_INVALIDBUCKET); 2086135446Strhodes LOCK(&adb->entrylocks[bucket]); 2087135446Strhodes 2088135446Strhodes if (!FIND_RETURNLAME(find) 2089170222Sdougb && entry_is_lame(adb, entry, qname, qtype, now)) { 2090135446Strhodes find->options |= DNS_ADBFIND_LAMEPRUNED; 2091135446Strhodes goto nextv4; 2092135446Strhodes } 2093135446Strhodes addrinfo = new_adbaddrinfo(adb, entry, find->port); 2094135446Strhodes if (addrinfo == NULL) { 2095135446Strhodes find->partial_result |= DNS_ADBFIND_INET; 2096135446Strhodes goto out; 2097135446Strhodes } 2098135446Strhodes /* 2099135446Strhodes * Found a valid entry. Add it to the find's list. 2100135446Strhodes */ 2101135446Strhodes inc_entry_refcnt(adb, entry, ISC_FALSE); 2102135446Strhodes ISC_LIST_APPEND(find->list, addrinfo, publink); 2103135446Strhodes addrinfo = NULL; 2104135446Strhodes nextv4: 2105135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 2106135446Strhodes bucket = DNS_ADB_INVALIDBUCKET; 2107135446Strhodes namehook = ISC_LIST_NEXT(namehook, plink); 2108135446Strhodes } 2109135446Strhodes } 2110135446Strhodes 2111135446Strhodes if (find->options & DNS_ADBFIND_INET6) { 2112135446Strhodes namehook = ISC_LIST_HEAD(name->v6); 2113135446Strhodes while (namehook != NULL) { 2114135446Strhodes entry = namehook->entry; 2115135446Strhodes bucket = entry->lock_bucket; 2116254402Serwin INSIST(bucket != DNS_ADB_INVALIDBUCKET); 2117135446Strhodes LOCK(&adb->entrylocks[bucket]); 2118135446Strhodes 2119186462Sdougb if (!FIND_RETURNLAME(find) 2120186462Sdougb && entry_is_lame(adb, entry, qname, qtype, now)) { 2121186462Sdougb find->options |= DNS_ADBFIND_LAMEPRUNED; 2122135446Strhodes goto nextv6; 2123186462Sdougb } 2124135446Strhodes addrinfo = new_adbaddrinfo(adb, entry, find->port); 2125135446Strhodes if (addrinfo == NULL) { 2126135446Strhodes find->partial_result |= DNS_ADBFIND_INET6; 2127135446Strhodes goto out; 2128135446Strhodes } 2129135446Strhodes /* 2130135446Strhodes * Found a valid entry. Add it to the find's list. 2131135446Strhodes */ 2132135446Strhodes inc_entry_refcnt(adb, entry, ISC_FALSE); 2133135446Strhodes ISC_LIST_APPEND(find->list, addrinfo, publink); 2134135446Strhodes addrinfo = NULL; 2135135446Strhodes nextv6: 2136135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 2137135446Strhodes bucket = DNS_ADB_INVALIDBUCKET; 2138135446Strhodes namehook = ISC_LIST_NEXT(namehook, plink); 2139135446Strhodes } 2140135446Strhodes } 2141135446Strhodes 2142135446Strhodes out: 2143135446Strhodes if (bucket != DNS_ADB_INVALIDBUCKET) 2144135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 2145135446Strhodes} 2146135446Strhodes 2147135446Strhodesstatic void 2148135446Strhodesshutdown_task(isc_task_t *task, isc_event_t *ev) { 2149135446Strhodes dns_adb_t *adb; 2150135446Strhodes 2151135446Strhodes UNUSED(task); 2152135446Strhodes 2153135446Strhodes adb = ev->ev_arg; 2154135446Strhodes INSIST(DNS_ADB_VALID(adb)); 2155135446Strhodes 2156193149Sdougb isc_event_free(&ev); 2157135446Strhodes /* 2158186462Sdougb * Wait for lock around check_exit() call to be released. 2159186462Sdougb */ 2160186462Sdougb LOCK(&adb->lock); 2161135446Strhodes UNLOCK(&adb->lock); 2162135446Strhodes destroy(adb); 2163135446Strhodes} 2164135446Strhodes 2165135446Strhodes/* 2166135446Strhodes * Name bucket must be locked; adb may be locked; no other locks held. 2167135446Strhodes */ 2168135446Strhodesstatic isc_boolean_t 2169135446Strhodescheck_expire_name(dns_adbname_t **namep, isc_stdtime_t now) { 2170135446Strhodes dns_adbname_t *name; 2171153816Sdougb isc_boolean_t result = ISC_FALSE; 2172135446Strhodes 2173135446Strhodes INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep)); 2174135446Strhodes name = *namep; 2175135446Strhodes 2176135446Strhodes if (NAME_HAS_V4(name) || NAME_HAS_V6(name)) 2177135446Strhodes return (result); 2178135446Strhodes if (NAME_FETCH(name)) 2179135446Strhodes return (result); 2180135446Strhodes if (!EXPIRE_OK(name->expire_v4, now)) 2181135446Strhodes return (result); 2182135446Strhodes if (!EXPIRE_OK(name->expire_v6, now)) 2183135446Strhodes return (result); 2184135446Strhodes if (!EXPIRE_OK(name->expire_target, now)) 2185135446Strhodes return (result); 2186135446Strhodes 2187135446Strhodes /* 2188135446Strhodes * The name is empty. Delete it. 2189135446Strhodes */ 2190135446Strhodes result = kill_name(&name, DNS_EVENT_ADBEXPIRED); 2191135446Strhodes *namep = NULL; 2192135446Strhodes 2193135446Strhodes /* 2194135446Strhodes * Our caller, or one of its callers, will be calling check_exit() at 2195135446Strhodes * some point, so we don't need to do it here. 2196135446Strhodes */ 2197135446Strhodes return (result); 2198135446Strhodes} 2199135446Strhodes 2200193149Sdougb/*% 2201193149Sdougb * Examine the tail entry of the LRU list to see if it expires or is stale 2202193149Sdougb * (unused for some period); if so, the name entry will be freed. If the ADB 2203193149Sdougb * is in the overmem condition, the tail and the next to tail entries 2204193149Sdougb * will be unconditionally removed (unless they have an outstanding fetch). 2205193149Sdougb * We don't care about a race on 'overmem' at the risk of causing some 2206193149Sdougb * collateral damage or a small delay in starting cleanup, so we don't bother 2207193149Sdougb * to lock ADB (if it's not locked). 2208193149Sdougb * 2209193149Sdougb * Name bucket must be locked; adb may be locked; no other locks held. 2210193149Sdougb */ 2211193149Sdougbstatic void 2212193149Sdougbcheck_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) { 2213193149Sdougb int victims, max_victims; 2214193149Sdougb dns_adbname_t *victim, *next_victim; 2215214586Sdougb isc_boolean_t overmem = isc_mem_isovermem(adb->mctx); 2216193149Sdougb int scans = 0; 2217193149Sdougb 2218193149Sdougb INSIST(bucket != DNS_ADB_INVALIDBUCKET); 2219193149Sdougb 2220193149Sdougb max_victims = overmem ? 2 : 1; 2221193149Sdougb 2222193149Sdougb /* 2223193149Sdougb * We limit the number of scanned entries to 10 (arbitrary choice) 2224193149Sdougb * in order to avoid examining too many entries when there are many 2225193149Sdougb * tail entries that have fetches (this should be rare, but could 2226193149Sdougb * happen). 2227193149Sdougb */ 2228193149Sdougb victim = ISC_LIST_TAIL(adb->names[bucket]); 2229193149Sdougb for (victims = 0; 2230193149Sdougb victim != NULL && victims < max_victims && scans < 10; 2231193149Sdougb victim = next_victim) { 2232193149Sdougb INSIST(!NAME_DEAD(victim)); 2233193149Sdougb scans++; 2234193149Sdougb next_victim = ISC_LIST_PREV(victim, plink); 2235225361Sdougb (void)check_expire_name(&victim, now); 2236193149Sdougb if (victim == NULL) { 2237193149Sdougb victims++; 2238193149Sdougb goto next; 2239193149Sdougb } 2240193149Sdougb 2241193149Sdougb if (!NAME_FETCH(victim) && 2242193149Sdougb (overmem || victim->last_used + ADB_STALE_MARGIN <= now)) { 2243193149Sdougb RUNTIME_CHECK(kill_name(&victim, 2244193149Sdougb DNS_EVENT_ADBCANCELED) == 2245193149Sdougb ISC_FALSE); 2246193149Sdougb victims++; 2247193149Sdougb } 2248193149Sdougb 2249193149Sdougb next: 2250193149Sdougb if (!overmem) 2251193149Sdougb break; 2252193149Sdougb } 2253193149Sdougb} 2254193149Sdougb 2255135446Strhodes/* 2256135446Strhodes * Entry bucket must be locked; adb may be locked; no other locks held. 2257135446Strhodes */ 2258135446Strhodesstatic isc_boolean_t 2259135446Strhodescheck_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now) 2260135446Strhodes{ 2261135446Strhodes dns_adbentry_t *entry; 2262135446Strhodes isc_boolean_t result = ISC_FALSE; 2263135446Strhodes 2264135446Strhodes INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp)); 2265135446Strhodes entry = *entryp; 2266135446Strhodes 2267135446Strhodes if (entry->refcnt != 0) 2268135446Strhodes return (result); 2269135446Strhodes 2270193149Sdougb if (entry->expires == 0 || entry->expires > now) 2271135446Strhodes return (result); 2272135446Strhodes 2273135446Strhodes /* 2274135446Strhodes * The entry is not in use. Delete it. 2275135446Strhodes */ 2276135446Strhodes DP(DEF_LEVEL, "killing entry %p", entry); 2277135446Strhodes INSIST(ISC_LINK_LINKED(entry, plink)); 2278135446Strhodes result = unlink_entry(adb, entry); 2279135446Strhodes free_adbentry(adb, &entry); 2280135446Strhodes if (result) 2281135446Strhodes dec_adb_irefcnt(adb); 2282135446Strhodes *entryp = NULL; 2283135446Strhodes return (result); 2284135446Strhodes} 2285135446Strhodes 2286135446Strhodes/* 2287135446Strhodes * ADB must be locked, and no other locks held. 2288135446Strhodes */ 2289135446Strhodesstatic isc_boolean_t 2290135446Strhodescleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) { 2291135446Strhodes dns_adbname_t *name; 2292135446Strhodes dns_adbname_t *next_name; 2293153816Sdougb isc_boolean_t result = ISC_FALSE; 2294135446Strhodes 2295135446Strhodes DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket); 2296135446Strhodes 2297135446Strhodes LOCK(&adb->namelocks[bucket]); 2298135446Strhodes if (adb->name_sd[bucket]) { 2299135446Strhodes UNLOCK(&adb->namelocks[bucket]); 2300135446Strhodes return (result); 2301135446Strhodes } 2302135446Strhodes 2303135446Strhodes name = ISC_LIST_HEAD(adb->names[bucket]); 2304135446Strhodes while (name != NULL) { 2305135446Strhodes next_name = ISC_LIST_NEXT(name, plink); 2306135446Strhodes INSIST(result == ISC_FALSE); 2307193149Sdougb result = check_expire_namehooks(name, now); 2308135446Strhodes if (!result) 2309135446Strhodes result = check_expire_name(&name, now); 2310135446Strhodes name = next_name; 2311135446Strhodes } 2312135446Strhodes UNLOCK(&adb->namelocks[bucket]); 2313135446Strhodes return (result); 2314135446Strhodes} 2315135446Strhodes 2316135446Strhodes/* 2317135446Strhodes * ADB must be locked, and no other locks held. 2318135446Strhodes */ 2319135446Strhodesstatic isc_boolean_t 2320135446Strhodescleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) { 2321135446Strhodes dns_adbentry_t *entry, *next_entry; 2322135446Strhodes isc_boolean_t result = ISC_FALSE; 2323135446Strhodes 2324135446Strhodes DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket); 2325135446Strhodes 2326135446Strhodes LOCK(&adb->entrylocks[bucket]); 2327135446Strhodes entry = ISC_LIST_HEAD(adb->entries[bucket]); 2328135446Strhodes while (entry != NULL) { 2329135446Strhodes next_entry = ISC_LIST_NEXT(entry, plink); 2330135446Strhodes INSIST(result == ISC_FALSE); 2331135446Strhodes result = check_expire_entry(adb, &entry, now); 2332135446Strhodes entry = next_entry; 2333135446Strhodes } 2334135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 2335135446Strhodes return (result); 2336135446Strhodes} 2337135446Strhodes 2338135446Strhodesstatic void 2339135446Strhodesdestroy(dns_adb_t *adb) { 2340135446Strhodes adb->magic = 0; 2341135446Strhodes 2342135446Strhodes isc_task_detach(&adb->task); 2343254402Serwin if (adb->excl != NULL) 2344254402Serwin isc_task_detach(&adb->excl); 2345135446Strhodes 2346135446Strhodes isc_mempool_destroy(&adb->nmp); 2347135446Strhodes isc_mempool_destroy(&adb->nhmp); 2348170222Sdougb isc_mempool_destroy(&adb->limp); 2349135446Strhodes isc_mempool_destroy(&adb->emp); 2350135446Strhodes isc_mempool_destroy(&adb->ahmp); 2351135446Strhodes isc_mempool_destroy(&adb->aimp); 2352135446Strhodes isc_mempool_destroy(&adb->afmp); 2353135446Strhodes 2354224092Sdougb DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries); 2355224092Sdougb isc_mem_put(adb->mctx, adb->entries, 2356224092Sdougb sizeof(*adb->entries) * adb->nentries); 2357224092Sdougb isc_mem_put(adb->mctx, adb->deadentries, 2358224092Sdougb sizeof(*adb->deadentries) * adb->nentries); 2359224092Sdougb isc_mem_put(adb->mctx, adb->entrylocks, 2360224092Sdougb sizeof(*adb->entrylocks) * adb->nentries); 2361224092Sdougb isc_mem_put(adb->mctx, adb->entry_sd, 2362224092Sdougb sizeof(*adb->entry_sd) * adb->nentries); 2363224092Sdougb isc_mem_put(adb->mctx, adb->entry_refcnt, 2364224092Sdougb sizeof(*adb->entry_refcnt) * adb->nentries); 2365135446Strhodes 2366224092Sdougb DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames); 2367224092Sdougb isc_mem_put(adb->mctx, adb->names, 2368224092Sdougb sizeof(*adb->names) * adb->nnames); 2369224092Sdougb isc_mem_put(adb->mctx, adb->deadnames, 2370224092Sdougb sizeof(*adb->deadnames) * adb->nnames); 2371224092Sdougb isc_mem_put(adb->mctx, adb->namelocks, 2372224092Sdougb sizeof(*adb->namelocks) * adb->nnames); 2373224092Sdougb isc_mem_put(adb->mctx, adb->name_sd, 2374224092Sdougb sizeof(*adb->name_sd) * adb->nnames); 2375224092Sdougb isc_mem_put(adb->mctx, adb->name_refcnt, 2376224092Sdougb sizeof(*adb->name_refcnt) * adb->nnames); 2377224092Sdougb 2378135446Strhodes DESTROYLOCK(&adb->reflock); 2379135446Strhodes DESTROYLOCK(&adb->lock); 2380135446Strhodes DESTROYLOCK(&adb->mplock); 2381186462Sdougb DESTROYLOCK(&adb->overmemlock); 2382224092Sdougb DESTROYLOCK(&adb->entriescntlock); 2383224092Sdougb DESTROYLOCK(&adb->namescntlock); 2384135446Strhodes 2385135446Strhodes isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t)); 2386135446Strhodes} 2387135446Strhodes 2388135446Strhodes 2389135446Strhodes/* 2390135446Strhodes * Public functions. 2391135446Strhodes */ 2392135446Strhodes 2393135446Strhodesisc_result_t 2394135446Strhodesdns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, 2395135446Strhodes isc_taskmgr_t *taskmgr, dns_adb_t **newadb) 2396135446Strhodes{ 2397135446Strhodes dns_adb_t *adb; 2398135446Strhodes isc_result_t result; 2399224092Sdougb unsigned int i; 2400135446Strhodes 2401135446Strhodes REQUIRE(mem != NULL); 2402135446Strhodes REQUIRE(view != NULL); 2403193149Sdougb REQUIRE(timermgr != NULL); /* this is actually unused */ 2404135446Strhodes REQUIRE(taskmgr != NULL); 2405135446Strhodes REQUIRE(newadb != NULL && *newadb == NULL); 2406135446Strhodes 2407193149Sdougb UNUSED(timermgr); 2408193149Sdougb 2409135446Strhodes adb = isc_mem_get(mem, sizeof(dns_adb_t)); 2410135446Strhodes if (adb == NULL) 2411135446Strhodes return (ISC_R_NOMEMORY); 2412135446Strhodes 2413135446Strhodes /* 2414135446Strhodes * Initialize things here that cannot fail, and especially things 2415135446Strhodes * that must be NULL for the error return to work properly. 2416135446Strhodes */ 2417135446Strhodes adb->magic = 0; 2418135446Strhodes adb->erefcnt = 1; 2419135446Strhodes adb->irefcnt = 0; 2420135446Strhodes adb->nmp = NULL; 2421135446Strhodes adb->nhmp = NULL; 2422170222Sdougb adb->limp = NULL; 2423135446Strhodes adb->emp = NULL; 2424135446Strhodes adb->ahmp = NULL; 2425135446Strhodes adb->aimp = NULL; 2426135446Strhodes adb->afmp = NULL; 2427135446Strhodes adb->task = NULL; 2428245163Serwin adb->excl = NULL; 2429135446Strhodes adb->mctx = NULL; 2430135446Strhodes adb->view = view; 2431135446Strhodes adb->taskmgr = taskmgr; 2432135446Strhodes adb->next_cleanbucket = 0; 2433135446Strhodes ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL, 2434135446Strhodes DNS_EVENT_ADBCONTROL, shutdown_task, adb, 2435135446Strhodes adb, NULL, NULL); 2436135446Strhodes adb->cevent_sent = ISC_FALSE; 2437135446Strhodes adb->shutting_down = ISC_FALSE; 2438135446Strhodes ISC_LIST_INIT(adb->whenshutdown); 2439135446Strhodes 2440224092Sdougb adb->nentries = nbuckets[0]; 2441224092Sdougb adb->entriescnt = 0; 2442224092Sdougb adb->entries = NULL; 2443224092Sdougb adb->deadentries = NULL; 2444224092Sdougb adb->entry_sd = NULL; 2445224092Sdougb adb->entry_refcnt = NULL; 2446224092Sdougb adb->entrylocks = NULL; 2447224092Sdougb ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL, 2448224092Sdougb DNS_EVENT_ADBGROWENTRIES, grow_entries, adb, 2449224092Sdougb adb, NULL, NULL); 2450224092Sdougb adb->growentries_sent = ISC_FALSE; 2451224092Sdougb 2452224092Sdougb adb->nnames = nbuckets[0]; 2453224092Sdougb adb->namescnt = 0; 2454224092Sdougb adb->names = NULL; 2455224092Sdougb adb->deadnames = NULL; 2456224092Sdougb adb->name_sd = NULL; 2457224092Sdougb adb->name_refcnt = NULL; 2458224092Sdougb adb->namelocks = NULL; 2459224092Sdougb ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL, 2460224092Sdougb DNS_EVENT_ADBGROWNAMES, grow_names, adb, 2461224092Sdougb adb, NULL, NULL); 2462224092Sdougb adb->grownames_sent = ISC_FALSE; 2463224092Sdougb 2464245163Serwin result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl); 2465245163Serwin if (result != ISC_R_SUCCESS) { 2466245163Serwin DP(ISC_LOG_INFO, "adb: task-exclusive mode unavailable, " 2467245163Serwin "intializing table sizes to %u\n", 2468245163Serwin nbuckets[11]); 2469245163Serwin adb->nentries = nbuckets[11]; 2470245163Serwin adb->nnames= nbuckets[11]; 2471245163Serwin 2472245163Serwin } 2473245163Serwin 2474135446Strhodes isc_mem_attach(mem, &adb->mctx); 2475135446Strhodes 2476135446Strhodes result = isc_mutex_init(&adb->lock); 2477135446Strhodes if (result != ISC_R_SUCCESS) 2478135446Strhodes goto fail0b; 2479135446Strhodes 2480135446Strhodes result = isc_mutex_init(&adb->mplock); 2481135446Strhodes if (result != ISC_R_SUCCESS) 2482135446Strhodes goto fail0c; 2483135446Strhodes 2484135446Strhodes result = isc_mutex_init(&adb->reflock); 2485135446Strhodes if (result != ISC_R_SUCCESS) 2486135446Strhodes goto fail0d; 2487135446Strhodes 2488186462Sdougb result = isc_mutex_init(&adb->overmemlock); 2489186462Sdougb if (result != ISC_R_SUCCESS) 2490186462Sdougb goto fail0e; 2491186462Sdougb 2492224092Sdougb result = isc_mutex_init(&adb->entriescntlock); 2493224092Sdougb if (result != ISC_R_SUCCESS) 2494224092Sdougb goto fail0f; 2495224092Sdougb 2496224092Sdougb result = isc_mutex_init(&adb->namescntlock); 2497224092Sdougb if (result != ISC_R_SUCCESS) 2498224092Sdougb goto fail0g; 2499224092Sdougb 2500224092Sdougb#define ALLOCENTRY(adb, el) \ 2501224092Sdougb do { \ 2502224092Sdougb (adb)->el = isc_mem_get((adb)->mctx, \ 2503224092Sdougb sizeof(*(adb)->el) * (adb)->nentries); \ 2504224092Sdougb if ((adb)->el == NULL) { \ 2505224092Sdougb result = ISC_R_NOMEMORY; \ 2506224092Sdougb goto fail1; \ 2507224092Sdougb }\ 2508224092Sdougb } while (0) 2509224092Sdougb ALLOCENTRY(adb, entries); 2510224092Sdougb ALLOCENTRY(adb, deadentries); 2511224092Sdougb ALLOCENTRY(adb, entrylocks); 2512224092Sdougb ALLOCENTRY(adb, entry_sd); 2513224092Sdougb ALLOCENTRY(adb, entry_refcnt); 2514224092Sdougb#undef ALLOCENTRY 2515224092Sdougb 2516224092Sdougb#define ALLOCNAME(adb, el) \ 2517224092Sdougb do { \ 2518224092Sdougb (adb)->el = isc_mem_get((adb)->mctx, \ 2519224092Sdougb sizeof(*(adb)->el) * (adb)->nnames); \ 2520224092Sdougb if ((adb)->el == NULL) { \ 2521224092Sdougb result = ISC_R_NOMEMORY; \ 2522224092Sdougb goto fail1; \ 2523224092Sdougb }\ 2524224092Sdougb } while (0) 2525224092Sdougb ALLOCNAME(adb, names); 2526224092Sdougb ALLOCNAME(adb, deadnames); 2527224092Sdougb ALLOCNAME(adb, namelocks); 2528224092Sdougb ALLOCNAME(adb, name_sd); 2529224092Sdougb ALLOCNAME(adb, name_refcnt); 2530224092Sdougb#undef ALLOCNAME 2531224092Sdougb 2532135446Strhodes /* 2533135446Strhodes * Initialize the bucket locks for names and elements. 2534135446Strhodes * May as well initialize the list heads, too. 2535135446Strhodes */ 2536224092Sdougb result = isc_mutexblock_init(adb->namelocks, adb->nnames); 2537135446Strhodes if (result != ISC_R_SUCCESS) 2538135446Strhodes goto fail1; 2539224092Sdougb for (i = 0; i < adb->nnames; i++) { 2540135446Strhodes ISC_LIST_INIT(adb->names[i]); 2541193149Sdougb ISC_LIST_INIT(adb->deadnames[i]); 2542135446Strhodes adb->name_sd[i] = ISC_FALSE; 2543135446Strhodes adb->name_refcnt[i] = 0; 2544135446Strhodes adb->irefcnt++; 2545135446Strhodes } 2546224092Sdougb for (i = 0; i < adb->nentries; i++) { 2547135446Strhodes ISC_LIST_INIT(adb->entries[i]); 2548193149Sdougb ISC_LIST_INIT(adb->deadentries[i]); 2549135446Strhodes adb->entry_sd[i] = ISC_FALSE; 2550135446Strhodes adb->entry_refcnt[i] = 0; 2551135446Strhodes adb->irefcnt++; 2552135446Strhodes } 2553224092Sdougb result = isc_mutexblock_init(adb->entrylocks, adb->nentries); 2554135446Strhodes if (result != ISC_R_SUCCESS) 2555135446Strhodes goto fail2; 2556135446Strhodes 2557135446Strhodes /* 2558135446Strhodes * Memory pools 2559135446Strhodes */ 2560135446Strhodes#define MPINIT(t, p, n) do { \ 2561135446Strhodes result = isc_mempool_create(mem, sizeof(t), &(p)); \ 2562135446Strhodes if (result != ISC_R_SUCCESS) \ 2563135446Strhodes goto fail3; \ 2564135446Strhodes isc_mempool_setfreemax((p), FREE_ITEMS); \ 2565135446Strhodes isc_mempool_setfillcount((p), FILL_COUNT); \ 2566135446Strhodes isc_mempool_setname((p), n); \ 2567135446Strhodes isc_mempool_associatelock((p), &adb->mplock); \ 2568135446Strhodes} while (0) 2569135446Strhodes 2570135446Strhodes MPINIT(dns_adbname_t, adb->nmp, "adbname"); 2571135446Strhodes MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook"); 2572170222Sdougb MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo"); 2573135446Strhodes MPINIT(dns_adbentry_t, adb->emp, "adbentry"); 2574135446Strhodes MPINIT(dns_adbfind_t, adb->ahmp, "adbfind"); 2575135446Strhodes MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo"); 2576135446Strhodes MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch"); 2577135446Strhodes 2578135446Strhodes#undef MPINIT 2579135446Strhodes 2580135446Strhodes /* 2581193149Sdougb * Allocate an internal task. 2582135446Strhodes */ 2583135446Strhodes result = isc_task_create(adb->taskmgr, 0, &adb->task); 2584135446Strhodes if (result != ISC_R_SUCCESS) 2585135446Strhodes goto fail3; 2586245163Serwin 2587135446Strhodes isc_task_setname(adb->task, "ADB", adb); 2588135446Strhodes 2589135446Strhodes /* 2590135446Strhodes * Normal return. 2591135446Strhodes */ 2592135446Strhodes adb->magic = DNS_ADB_MAGIC; 2593135446Strhodes *newadb = adb; 2594135446Strhodes return (ISC_R_SUCCESS); 2595135446Strhodes 2596135446Strhodes fail3: 2597135446Strhodes if (adb->task != NULL) 2598135446Strhodes isc_task_detach(&adb->task); 2599135446Strhodes 2600135446Strhodes /* clean up entrylocks */ 2601224092Sdougb DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries); 2602135446Strhodes 2603135446Strhodes fail2: /* clean up namelocks */ 2604224092Sdougb DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames); 2605135446Strhodes 2606135446Strhodes fail1: /* clean up only allocated memory */ 2607224092Sdougb if (adb->entries != NULL) 2608224092Sdougb isc_mem_put(adb->mctx, adb->entries, 2609224092Sdougb sizeof(*adb->entries) * adb->nentries); 2610224092Sdougb if (adb->deadentries != NULL) 2611224092Sdougb isc_mem_put(adb->mctx, adb->deadentries, 2612224092Sdougb sizeof(*adb->deadentries) * adb->nentries); 2613224092Sdougb if (adb->entrylocks != NULL) 2614224092Sdougb isc_mem_put(adb->mctx, adb->entrylocks, 2615224092Sdougb sizeof(*adb->entrylocks) * adb->nentries); 2616224092Sdougb if (adb->entry_sd != NULL) 2617224092Sdougb isc_mem_put(adb->mctx, adb->entry_sd, 2618224092Sdougb sizeof(*adb->entry_sd) * adb->nentries); 2619224092Sdougb if (adb->entry_refcnt != NULL) 2620224092Sdougb isc_mem_put(adb->mctx, adb->entry_refcnt, 2621224092Sdougb sizeof(*adb->entry_refcnt) * adb->nentries); 2622224092Sdougb if (adb->names != NULL) 2623224092Sdougb isc_mem_put(adb->mctx, adb->names, 2624224092Sdougb sizeof(*adb->names) * adb->nnames); 2625224092Sdougb if (adb->deadnames != NULL) 2626224092Sdougb isc_mem_put(adb->mctx, adb->deadnames, 2627224092Sdougb sizeof(*adb->deadnames) * adb->nnames); 2628224092Sdougb if (adb->namelocks != NULL) 2629224092Sdougb isc_mem_put(adb->mctx, adb->namelocks, 2630224092Sdougb sizeof(*adb->namelocks) * adb->nnames); 2631224092Sdougb if (adb->name_sd != NULL) 2632224092Sdougb isc_mem_put(adb->mctx, adb->name_sd, 2633224092Sdougb sizeof(*adb->name_sd) * adb->nnames); 2634224092Sdougb if (adb->name_refcnt != NULL) 2635224092Sdougb isc_mem_put(adb->mctx, adb->name_refcnt, 2636224092Sdougb sizeof(*adb->name_refcnt) * adb->nnames); 2637135446Strhodes if (adb->nmp != NULL) 2638135446Strhodes isc_mempool_destroy(&adb->nmp); 2639135446Strhodes if (adb->nhmp != NULL) 2640135446Strhodes isc_mempool_destroy(&adb->nhmp); 2641170222Sdougb if (adb->limp != NULL) 2642170222Sdougb isc_mempool_destroy(&adb->limp); 2643135446Strhodes if (adb->emp != NULL) 2644135446Strhodes isc_mempool_destroy(&adb->emp); 2645135446Strhodes if (adb->ahmp != NULL) 2646135446Strhodes isc_mempool_destroy(&adb->ahmp); 2647135446Strhodes if (adb->aimp != NULL) 2648135446Strhodes isc_mempool_destroy(&adb->aimp); 2649135446Strhodes if (adb->afmp != NULL) 2650135446Strhodes isc_mempool_destroy(&adb->afmp); 2651135446Strhodes 2652224092Sdougb DESTROYLOCK(&adb->namescntlock); 2653224092Sdougb fail0g: 2654224092Sdougb DESTROYLOCK(&adb->entriescntlock); 2655224092Sdougb fail0f: 2656186462Sdougb DESTROYLOCK(&adb->overmemlock); 2657186462Sdougb fail0e: 2658135446Strhodes DESTROYLOCK(&adb->reflock); 2659135446Strhodes fail0d: 2660135446Strhodes DESTROYLOCK(&adb->mplock); 2661135446Strhodes fail0c: 2662135446Strhodes DESTROYLOCK(&adb->lock); 2663135446Strhodes fail0b: 2664135446Strhodes isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t)); 2665135446Strhodes 2666135446Strhodes return (result); 2667135446Strhodes} 2668135446Strhodes 2669135446Strhodesvoid 2670135446Strhodesdns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) { 2671135446Strhodes 2672135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 2673135446Strhodes REQUIRE(adbx != NULL && *adbx == NULL); 2674135446Strhodes 2675135446Strhodes inc_adb_erefcnt(adb); 2676135446Strhodes *adbx = adb; 2677135446Strhodes} 2678135446Strhodes 2679135446Strhodesvoid 2680135446Strhodesdns_adb_detach(dns_adb_t **adbx) { 2681135446Strhodes dns_adb_t *adb; 2682135446Strhodes isc_boolean_t need_exit_check; 2683135446Strhodes 2684135446Strhodes REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx)); 2685135446Strhodes 2686135446Strhodes adb = *adbx; 2687135446Strhodes *adbx = NULL; 2688135446Strhodes 2689135446Strhodes INSIST(adb->erefcnt > 0); 2690135446Strhodes 2691135446Strhodes LOCK(&adb->reflock); 2692135446Strhodes adb->erefcnt--; 2693135446Strhodes need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0); 2694135446Strhodes UNLOCK(&adb->reflock); 2695135446Strhodes 2696135446Strhodes if (need_exit_check) { 2697135446Strhodes LOCK(&adb->lock); 2698135446Strhodes INSIST(adb->shutting_down); 2699135446Strhodes check_exit(adb); 2700135446Strhodes UNLOCK(&adb->lock); 2701135446Strhodes } 2702135446Strhodes} 2703135446Strhodes 2704135446Strhodesvoid 2705135446Strhodesdns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) { 2706135446Strhodes isc_task_t *clone; 2707135446Strhodes isc_event_t *event; 2708135446Strhodes isc_boolean_t zeroirefcnt = ISC_FALSE; 2709135446Strhodes 2710135446Strhodes /* 2711135446Strhodes * Send '*eventp' to 'task' when 'adb' has shutdown. 2712135446Strhodes */ 2713135446Strhodes 2714135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 2715135446Strhodes REQUIRE(eventp != NULL); 2716135446Strhodes 2717135446Strhodes event = *eventp; 2718135446Strhodes *eventp = NULL; 2719135446Strhodes 2720135446Strhodes LOCK(&adb->lock); 2721135446Strhodes 2722135446Strhodes LOCK(&adb->reflock); 2723135446Strhodes zeroirefcnt = ISC_TF(adb->irefcnt == 0); 2724135446Strhodes 2725135446Strhodes if (adb->shutting_down && zeroirefcnt && 2726135446Strhodes isc_mempool_getallocated(adb->ahmp) == 0) { 2727135446Strhodes /* 2728135446Strhodes * We're already shutdown. Send the event. 2729135446Strhodes */ 2730135446Strhodes event->ev_sender = adb; 2731135446Strhodes isc_task_send(task, &event); 2732135446Strhodes } else { 2733135446Strhodes clone = NULL; 2734135446Strhodes isc_task_attach(task, &clone); 2735135446Strhodes event->ev_sender = clone; 2736135446Strhodes ISC_LIST_APPEND(adb->whenshutdown, event, ev_link); 2737135446Strhodes } 2738135446Strhodes 2739135446Strhodes UNLOCK(&adb->reflock); 2740135446Strhodes UNLOCK(&adb->lock); 2741135446Strhodes} 2742135446Strhodes 2743135446Strhodesvoid 2744135446Strhodesdns_adb_shutdown(dns_adb_t *adb) { 2745135446Strhodes isc_boolean_t need_check_exit; 2746135446Strhodes 2747135446Strhodes /* 2748135446Strhodes * Shutdown 'adb'. 2749135446Strhodes */ 2750135446Strhodes 2751135446Strhodes LOCK(&adb->lock); 2752135446Strhodes 2753135446Strhodes if (!adb->shutting_down) { 2754135446Strhodes adb->shutting_down = ISC_TRUE; 2755135446Strhodes isc_mem_setwater(adb->mctx, water, adb, 0, 0); 2756135446Strhodes need_check_exit = shutdown_names(adb); 2757135446Strhodes if (!need_check_exit) 2758135446Strhodes need_check_exit = shutdown_entries(adb); 2759135446Strhodes if (need_check_exit) 2760135446Strhodes check_exit(adb); 2761135446Strhodes } 2762135446Strhodes 2763135446Strhodes UNLOCK(&adb->lock); 2764135446Strhodes} 2765135446Strhodes 2766135446Strhodesisc_result_t 2767135446Strhodesdns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, 2768170222Sdougb void *arg, dns_name_t *name, dns_name_t *qname, 2769170222Sdougb dns_rdatatype_t qtype, unsigned int options, 2770170222Sdougb isc_stdtime_t now, dns_name_t *target, 2771135446Strhodes in_port_t port, dns_adbfind_t **findp) 2772135446Strhodes{ 2773135446Strhodes dns_adbfind_t *find; 2774135446Strhodes dns_adbname_t *adbname; 2775135446Strhodes int bucket; 2776135446Strhodes isc_boolean_t want_event, start_at_zone, alias, have_address; 2777135446Strhodes isc_result_t result; 2778135446Strhodes unsigned int wanted_addresses; 2779135446Strhodes unsigned int wanted_fetches; 2780135446Strhodes unsigned int query_pending; 2781135446Strhodes 2782135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 2783135446Strhodes if (task != NULL) { 2784135446Strhodes REQUIRE(action != NULL); 2785135446Strhodes } 2786135446Strhodes REQUIRE(name != NULL); 2787170222Sdougb REQUIRE(qname != NULL); 2788135446Strhodes REQUIRE(findp != NULL && *findp == NULL); 2789135446Strhodes REQUIRE(target == NULL || dns_name_hasbuffer(target)); 2790135446Strhodes 2791135446Strhodes REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0); 2792135446Strhodes 2793135446Strhodes result = ISC_R_UNEXPECTED; 2794225361Sdougb POST(result); 2795135446Strhodes wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK); 2796135446Strhodes wanted_fetches = 0; 2797135446Strhodes query_pending = 0; 2798135446Strhodes want_event = ISC_FALSE; 2799135446Strhodes start_at_zone = ISC_FALSE; 2800135446Strhodes alias = ISC_FALSE; 2801135446Strhodes 2802135446Strhodes if (now == 0) 2803135446Strhodes isc_stdtime_get(&now); 2804135446Strhodes 2805135446Strhodes /* 2806135446Strhodes * XXXMLG Move this comment somewhere else! 2807135446Strhodes * 2808135446Strhodes * Look up the name in our internal database. 2809135446Strhodes * 2810135446Strhodes * Possibilities: Note that these are not always exclusive. 2811135446Strhodes * 2812193149Sdougb * No name found. In this case, allocate a new name header and 2813193149Sdougb * an initial namehook or two. If any of these allocations 2814193149Sdougb * fail, clean up and return ISC_R_NOMEMORY. 2815135446Strhodes * 2816193149Sdougb * Name found, valid addresses present. Allocate one addrinfo 2817193149Sdougb * structure for each found and append it to the linked list 2818193149Sdougb * of addresses for this header. 2819135446Strhodes * 2820193149Sdougb * Name found, queries pending. In this case, if a task was 2821193149Sdougb * passed in, allocate a job id, attach it to the name's job 2822193149Sdougb * list and remember to tell the caller that there will be 2823193149Sdougb * more info coming later. 2824135446Strhodes */ 2825135446Strhodes 2826135446Strhodes find = new_adbfind(adb); 2827135446Strhodes if (find == NULL) 2828135446Strhodes return (ISC_R_NOMEMORY); 2829135446Strhodes 2830135446Strhodes find->port = port; 2831135446Strhodes 2832135446Strhodes /* 2833135446Strhodes * Remember what types of addresses we are interested in. 2834135446Strhodes */ 2835135446Strhodes find->options = options; 2836135446Strhodes find->flags |= wanted_addresses; 2837135446Strhodes if (FIND_WANTEVENT(find)) { 2838135446Strhodes REQUIRE(task != NULL); 2839135446Strhodes } 2840135446Strhodes 2841135446Strhodes /* 2842135446Strhodes * Try to see if we know anything about this name at all. 2843135446Strhodes */ 2844135446Strhodes bucket = DNS_ADB_INVALIDBUCKET; 2845135446Strhodes adbname = find_name_and_lock(adb, name, find->options, &bucket); 2846225361Sdougb INSIST(bucket != DNS_ADB_INVALIDBUCKET); 2847135446Strhodes if (adb->name_sd[bucket]) { 2848135446Strhodes DP(DEF_LEVEL, 2849135446Strhodes "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN"); 2850135446Strhodes RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); 2851135446Strhodes result = ISC_R_SHUTTINGDOWN; 2852135446Strhodes goto out; 2853135446Strhodes } 2854135446Strhodes 2855135446Strhodes /* 2856135446Strhodes * Nothing found. Allocate a new adbname structure for this name. 2857135446Strhodes */ 2858135446Strhodes if (adbname == NULL) { 2859193149Sdougb /* 2860193149Sdougb * See if there is any stale name at the end of list, and purge 2861193149Sdougb * it if so. 2862193149Sdougb */ 2863193149Sdougb check_stale_name(adb, bucket, now); 2864193149Sdougb 2865135446Strhodes adbname = new_adbname(adb, name); 2866135446Strhodes if (adbname == NULL) { 2867135446Strhodes RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); 2868135446Strhodes result = ISC_R_NOMEMORY; 2869135446Strhodes goto out; 2870135446Strhodes } 2871135446Strhodes link_name(adb, bucket, adbname); 2872135446Strhodes if (FIND_HINTOK(find)) 2873135446Strhodes adbname->flags |= NAME_HINT_OK; 2874135446Strhodes if (FIND_GLUEOK(find)) 2875135446Strhodes adbname->flags |= NAME_GLUE_OK; 2876135446Strhodes if (FIND_STARTATZONE(find)) 2877135446Strhodes adbname->flags |= NAME_STARTATZONE; 2878193149Sdougb } else { 2879193149Sdougb /* Move this name forward in the LRU list */ 2880193149Sdougb ISC_LIST_UNLINK(adb->names[bucket], adbname, plink); 2881193149Sdougb ISC_LIST_PREPEND(adb->names[bucket], adbname, plink); 2882135446Strhodes } 2883193149Sdougb adbname->last_used = now; 2884135446Strhodes 2885135446Strhodes /* 2886135446Strhodes * Expire old entries, etc. 2887135446Strhodes */ 2888193149Sdougb RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE); 2889135446Strhodes 2890135446Strhodes /* 2891135446Strhodes * Do we know that the name is an alias? 2892135446Strhodes */ 2893135446Strhodes if (!EXPIRE_OK(adbname->expire_target, now)) { 2894135446Strhodes /* 2895135446Strhodes * Yes, it is. 2896135446Strhodes */ 2897135446Strhodes DP(DEF_LEVEL, 2898135446Strhodes "dns_adb_createfind: name %p is an alias (cached)", 2899135446Strhodes adbname); 2900135446Strhodes alias = ISC_TRUE; 2901135446Strhodes goto post_copy; 2902135446Strhodes } 2903135446Strhodes 2904135446Strhodes /* 2905135446Strhodes * Try to populate the name from the database and/or 2906135446Strhodes * start fetches. First try looking for an A record 2907135446Strhodes * in the database. 2908135446Strhodes */ 2909135446Strhodes if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now) 2910135446Strhodes && WANT_INET(wanted_addresses)) { 2911135446Strhodes result = dbfind_name(adbname, now, dns_rdatatype_a); 2912135446Strhodes if (result == ISC_R_SUCCESS) { 2913135446Strhodes DP(DEF_LEVEL, 2914135446Strhodes "dns_adb_createfind: found A for name %p in db", 2915135446Strhodes adbname); 2916135446Strhodes goto v6; 2917135446Strhodes } 2918135446Strhodes 2919135446Strhodes /* 2920135446Strhodes * Did we get a CNAME or DNAME? 2921135446Strhodes */ 2922135446Strhodes if (result == DNS_R_ALIAS) { 2923135446Strhodes DP(DEF_LEVEL, 2924135446Strhodes "dns_adb_createfind: name %p is an alias", 2925135446Strhodes adbname); 2926135446Strhodes alias = ISC_TRUE; 2927135446Strhodes goto post_copy; 2928135446Strhodes } 2929135446Strhodes 2930135446Strhodes /* 2931135446Strhodes * If the name doesn't exist at all, don't bother with 2932135446Strhodes * v6 queries; they won't work. 2933135446Strhodes * 2934135446Strhodes * If the name does exist but we didn't get our data, go 2935135446Strhodes * ahead and try AAAA. 2936135446Strhodes * 2937135446Strhodes * If the result is neither of these, try a fetch for A. 2938135446Strhodes */ 2939135446Strhodes if (NXDOMAIN_RESULT(result)) 2940135446Strhodes goto fetch; 2941135446Strhodes else if (NXRRSET_RESULT(result)) 2942135446Strhodes goto v6; 2943135446Strhodes 2944135446Strhodes if (!NAME_FETCH_V4(adbname)) 2945135446Strhodes wanted_fetches |= DNS_ADBFIND_INET; 2946135446Strhodes } 2947135446Strhodes 2948135446Strhodes v6: 2949135446Strhodes if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now) 2950135446Strhodes && WANT_INET6(wanted_addresses)) { 2951135446Strhodes result = dbfind_name(adbname, now, dns_rdatatype_aaaa); 2952135446Strhodes if (result == ISC_R_SUCCESS) { 2953135446Strhodes DP(DEF_LEVEL, 2954135446Strhodes "dns_adb_createfind: found AAAA for name %p", 2955135446Strhodes adbname); 2956135446Strhodes goto fetch; 2957135446Strhodes } 2958135446Strhodes 2959135446Strhodes /* 2960135446Strhodes * Did we get a CNAME or DNAME? 2961135446Strhodes */ 2962135446Strhodes if (result == DNS_R_ALIAS) { 2963135446Strhodes DP(DEF_LEVEL, 2964135446Strhodes "dns_adb_createfind: name %p is an alias", 2965135446Strhodes adbname); 2966135446Strhodes alias = ISC_TRUE; 2967135446Strhodes goto post_copy; 2968135446Strhodes } 2969135446Strhodes 2970135446Strhodes /* 2971135446Strhodes * Listen to negative cache hints, and don't start 2972135446Strhodes * another query. 2973135446Strhodes */ 2974135446Strhodes if (NCACHE_RESULT(result) || AUTH_NX(result)) 2975135446Strhodes goto fetch; 2976135446Strhodes 2977135446Strhodes if (!NAME_FETCH_V6(adbname)) 2978135446Strhodes wanted_fetches |= DNS_ADBFIND_INET6; 2979135446Strhodes } 2980135446Strhodes 2981135446Strhodes fetch: 2982135446Strhodes if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) || 2983135446Strhodes (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname))) 2984135446Strhodes have_address = ISC_TRUE; 2985135446Strhodes else 2986135446Strhodes have_address = ISC_FALSE; 2987135446Strhodes if (wanted_fetches != 0 && 2988135446Strhodes ! (FIND_AVOIDFETCHES(find) && have_address)) { 2989135446Strhodes /* 2990135446Strhodes * We're missing at least one address family. Either the 2991135446Strhodes * caller hasn't instructed us to avoid fetches, or we don't 2992135446Strhodes * know anything about any of the address families that would 2993135446Strhodes * be acceptable so we have to launch fetches. 2994135446Strhodes */ 2995135446Strhodes 2996135446Strhodes if (FIND_STARTATZONE(find)) 2997135446Strhodes start_at_zone = ISC_TRUE; 2998135446Strhodes 2999135446Strhodes /* 3000135446Strhodes * Start V4. 3001135446Strhodes */ 3002135446Strhodes if (WANT_INET(wanted_fetches) && 3003135446Strhodes fetch_name(adbname, start_at_zone, 3004135446Strhodes dns_rdatatype_a) == ISC_R_SUCCESS) { 3005135446Strhodes DP(DEF_LEVEL, 3006135446Strhodes "dns_adb_createfind: started A fetch for name %p", 3007135446Strhodes adbname); 3008135446Strhodes } 3009135446Strhodes 3010135446Strhodes /* 3011135446Strhodes * Start V6. 3012135446Strhodes */ 3013135446Strhodes if (WANT_INET6(wanted_fetches) && 3014135446Strhodes fetch_name(adbname, start_at_zone, 3015135446Strhodes dns_rdatatype_aaaa) == ISC_R_SUCCESS) { 3016135446Strhodes DP(DEF_LEVEL, 3017135446Strhodes "dns_adb_createfind: " 3018135446Strhodes "started AAAA fetch for name %p", 3019135446Strhodes adbname); 3020135446Strhodes } 3021135446Strhodes } 3022135446Strhodes 3023135446Strhodes /* 3024135446Strhodes * Run through the name and copy out the bits we are 3025135446Strhodes * interested in. 3026135446Strhodes */ 3027170222Sdougb copy_namehook_lists(adb, find, qname, qtype, adbname, now); 3028135446Strhodes 3029135446Strhodes post_copy: 3030135446Strhodes if (NAME_FETCH_V4(adbname)) 3031135446Strhodes query_pending |= DNS_ADBFIND_INET; 3032135446Strhodes if (NAME_FETCH_V6(adbname)) 3033135446Strhodes query_pending |= DNS_ADBFIND_INET6; 3034135446Strhodes 3035135446Strhodes /* 3036135446Strhodes * Attach to the name's query list if there are queries 3037135446Strhodes * already running, and we have been asked to. 3038135446Strhodes */ 3039135446Strhodes want_event = ISC_TRUE; 3040135446Strhodes if (!FIND_WANTEVENT(find)) 3041135446Strhodes want_event = ISC_FALSE; 3042135446Strhodes if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find)) 3043135446Strhodes want_event = ISC_FALSE; 3044135446Strhodes if ((wanted_addresses & query_pending) == 0) 3045135446Strhodes want_event = ISC_FALSE; 3046135446Strhodes if (alias) 3047135446Strhodes want_event = ISC_FALSE; 3048135446Strhodes if (want_event) { 3049135446Strhodes find->adbname = adbname; 3050135446Strhodes find->name_bucket = bucket; 3051135446Strhodes ISC_LIST_APPEND(adbname->finds, find, plink); 3052135446Strhodes find->query_pending = (query_pending & wanted_addresses); 3053135446Strhodes find->flags &= ~DNS_ADBFIND_ADDRESSMASK; 3054135446Strhodes find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK); 3055135446Strhodes DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p", 3056135446Strhodes find, adbname); 3057135446Strhodes } else { 3058135446Strhodes /* 3059135446Strhodes * Remove the flag so the caller knows there will never 3060135446Strhodes * be an event, and set internal flags to fake that 3061135446Strhodes * the event was sent and freed, so dns_adb_destroyfind() will 3062135446Strhodes * do the right thing. 3063135446Strhodes */ 3064135446Strhodes find->query_pending = (query_pending & wanted_addresses); 3065135446Strhodes find->options &= ~DNS_ADBFIND_WANTEVENT; 3066135446Strhodes find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED); 3067135446Strhodes find->flags &= ~DNS_ADBFIND_ADDRESSMASK; 3068135446Strhodes } 3069135446Strhodes 3070135446Strhodes find->partial_result |= (adbname->partial_result & wanted_addresses); 3071135446Strhodes if (alias) { 3072135446Strhodes if (target != NULL) { 3073135446Strhodes result = dns_name_copy(&adbname->target, target, NULL); 3074135446Strhodes if (result != ISC_R_SUCCESS) 3075135446Strhodes goto out; 3076135446Strhodes } 3077135446Strhodes result = DNS_R_ALIAS; 3078135446Strhodes } else 3079135446Strhodes result = ISC_R_SUCCESS; 3080135446Strhodes 3081135446Strhodes /* 3082135446Strhodes * Copy out error flags from the name structure into the find. 3083135446Strhodes */ 3084135446Strhodes find->result_v4 = find_err_map[adbname->fetch_err]; 3085135446Strhodes find->result_v6 = find_err_map[adbname->fetch6_err]; 3086135446Strhodes 3087135446Strhodes out: 3088135446Strhodes if (find != NULL) { 3089135446Strhodes *findp = find; 3090135446Strhodes 3091135446Strhodes if (want_event) { 3092135446Strhodes isc_task_t *taskp; 3093135446Strhodes 3094135446Strhodes INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0); 3095135446Strhodes taskp = NULL; 3096135446Strhodes isc_task_attach(task, &taskp); 3097135446Strhodes find->event.ev_sender = taskp; 3098135446Strhodes find->event.ev_action = action; 3099135446Strhodes find->event.ev_arg = arg; 3100135446Strhodes } 3101135446Strhodes } 3102135446Strhodes 3103165071Sdougb UNLOCK(&adb->namelocks[bucket]); 3104135446Strhodes 3105135446Strhodes return (result); 3106135446Strhodes} 3107135446Strhodes 3108135446Strhodesvoid 3109135446Strhodesdns_adb_destroyfind(dns_adbfind_t **findp) { 3110135446Strhodes dns_adbfind_t *find; 3111135446Strhodes dns_adbentry_t *entry; 3112135446Strhodes dns_adbaddrinfo_t *ai; 3113135446Strhodes int bucket; 3114135446Strhodes dns_adb_t *adb; 3115214586Sdougb isc_boolean_t overmem; 3116135446Strhodes 3117135446Strhodes REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp)); 3118135446Strhodes find = *findp; 3119135446Strhodes *findp = NULL; 3120135446Strhodes 3121135446Strhodes LOCK(&find->lock); 3122135446Strhodes 3123135446Strhodes DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find); 3124135446Strhodes 3125135446Strhodes adb = find->adb; 3126135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3127135446Strhodes 3128135446Strhodes REQUIRE(FIND_EVENTFREED(find)); 3129135446Strhodes 3130135446Strhodes bucket = find->name_bucket; 3131135446Strhodes INSIST(bucket == DNS_ADB_INVALIDBUCKET); 3132135446Strhodes 3133135446Strhodes UNLOCK(&find->lock); 3134135446Strhodes 3135135446Strhodes /* 3136135446Strhodes * The find doesn't exist on any list, and nothing is locked. 3137135446Strhodes * Return the find to the memory pool, and decrement the adb's 3138135446Strhodes * reference count. 3139135446Strhodes */ 3140214586Sdougb overmem = isc_mem_isovermem(adb->mctx); 3141135446Strhodes ai = ISC_LIST_HEAD(find->list); 3142135446Strhodes while (ai != NULL) { 3143135446Strhodes ISC_LIST_UNLINK(find->list, ai, publink); 3144135446Strhodes entry = ai->entry; 3145135446Strhodes ai->entry = NULL; 3146135446Strhodes INSIST(DNS_ADBENTRY_VALID(entry)); 3147214586Sdougb RUNTIME_CHECK(dec_entry_refcnt(adb, overmem, entry, ISC_TRUE) == 3148135446Strhodes ISC_FALSE); 3149135446Strhodes free_adbaddrinfo(adb, &ai); 3150135446Strhodes ai = ISC_LIST_HEAD(find->list); 3151135446Strhodes } 3152135446Strhodes 3153135446Strhodes /* 3154135446Strhodes * WARNING: The find is freed with the adb locked. This is done 3155135446Strhodes * to avoid a race condition where we free the find, some other 3156135446Strhodes * thread tests to see if it should be destroyed, detects it should 3157135446Strhodes * be, destroys it, and then we try to lock it for our check, but the 3158135446Strhodes * lock is destroyed. 3159135446Strhodes */ 3160135446Strhodes LOCK(&adb->lock); 3161135446Strhodes if (free_adbfind(adb, &find)) 3162135446Strhodes check_exit(adb); 3163135446Strhodes UNLOCK(&adb->lock); 3164135446Strhodes} 3165135446Strhodes 3166135446Strhodesvoid 3167135446Strhodesdns_adb_cancelfind(dns_adbfind_t *find) { 3168135446Strhodes isc_event_t *ev; 3169135446Strhodes isc_task_t *task; 3170135446Strhodes dns_adb_t *adb; 3171135446Strhodes int bucket; 3172135446Strhodes int unlock_bucket; 3173135446Strhodes 3174135446Strhodes LOCK(&find->lock); 3175135446Strhodes 3176135446Strhodes DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find); 3177135446Strhodes 3178135446Strhodes adb = find->adb; 3179135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3180135446Strhodes 3181135446Strhodes REQUIRE(!FIND_EVENTFREED(find)); 3182135446Strhodes REQUIRE(FIND_WANTEVENT(find)); 3183135446Strhodes 3184135446Strhodes bucket = find->name_bucket; 3185135446Strhodes if (bucket == DNS_ADB_INVALIDBUCKET) 3186135446Strhodes goto cleanup; 3187135446Strhodes 3188135446Strhodes /* 3189135446Strhodes * We need to get the adbname's lock to unlink the find. 3190135446Strhodes */ 3191135446Strhodes unlock_bucket = bucket; 3192135446Strhodes violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]); 3193135446Strhodes bucket = find->name_bucket; 3194135446Strhodes if (bucket != DNS_ADB_INVALIDBUCKET) { 3195135446Strhodes ISC_LIST_UNLINK(find->adbname->finds, find, plink); 3196135446Strhodes find->adbname = NULL; 3197135446Strhodes find->name_bucket = DNS_ADB_INVALIDBUCKET; 3198135446Strhodes } 3199135446Strhodes UNLOCK(&adb->namelocks[unlock_bucket]); 3200135446Strhodes bucket = DNS_ADB_INVALIDBUCKET; 3201225361Sdougb POST(bucket); 3202135446Strhodes 3203135446Strhodes cleanup: 3204135446Strhodes 3205135446Strhodes if (!FIND_EVENTSENT(find)) { 3206135446Strhodes ev = &find->event; 3207135446Strhodes task = ev->ev_sender; 3208135446Strhodes ev->ev_sender = find; 3209135446Strhodes ev->ev_type = DNS_EVENT_ADBCANCELED; 3210135446Strhodes ev->ev_destroy = event_free; 3211135446Strhodes ev->ev_destroy_arg = find; 3212135446Strhodes find->result_v4 = ISC_R_CANCELED; 3213135446Strhodes find->result_v6 = ISC_R_CANCELED; 3214135446Strhodes 3215135446Strhodes DP(DEF_LEVEL, "sending event %p to task %p for find %p", 3216135446Strhodes ev, task, find); 3217135446Strhodes 3218135446Strhodes isc_task_sendanddetach(&task, (isc_event_t **)&ev); 3219135446Strhodes } 3220135446Strhodes 3221135446Strhodes UNLOCK(&find->lock); 3222135446Strhodes} 3223135446Strhodes 3224135446Strhodesvoid 3225135446Strhodesdns_adb_dump(dns_adb_t *adb, FILE *f) { 3226224092Sdougb unsigned int i; 3227143731Sdougb isc_stdtime_t now; 3228143731Sdougb 3229135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3230135446Strhodes REQUIRE(f != NULL); 3231135446Strhodes 3232135446Strhodes /* 3233135446Strhodes * Lock the adb itself, lock all the name buckets, then lock all 3234135446Strhodes * the entry buckets. This should put the adb into a state where 3235135446Strhodes * nothing can change, so we can iterate through everything and 3236135446Strhodes * print at our leisure. 3237135446Strhodes */ 3238135446Strhodes 3239135446Strhodes LOCK(&adb->lock); 3240143731Sdougb isc_stdtime_get(&now); 3241143731Sdougb 3242224092Sdougb for (i = 0; i < adb->nnames; i++) 3243143731Sdougb RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE); 3244224092Sdougb for (i = 0; i < adb->nentries; i++) 3245143731Sdougb RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE); 3246143731Sdougb 3247143731Sdougb dump_adb(adb, f, ISC_FALSE, now); 3248135446Strhodes UNLOCK(&adb->lock); 3249135446Strhodes} 3250135446Strhodes 3251135446Strhodesstatic void 3252135446Strhodesdump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) { 3253135446Strhodes if (value == INT_MAX) 3254135446Strhodes return; 3255135446Strhodes fprintf(f, " [%s TTL %d]", legend, value - now); 3256135446Strhodes} 3257135446Strhodes 3258135446Strhodesstatic void 3259143731Sdougbdump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) { 3260224092Sdougb unsigned int i; 3261135446Strhodes dns_adbname_t *name; 3262143731Sdougb dns_adbentry_t *entry; 3263135446Strhodes 3264135446Strhodes fprintf(f, ";\n; Address database dump\n;\n"); 3265135446Strhodes if (debug) 3266135446Strhodes fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n", 3267135446Strhodes adb, adb->erefcnt, adb->irefcnt, 3268135446Strhodes isc_mempool_getallocated(adb->nhmp)); 3269135446Strhodes 3270224092Sdougb for (i = 0; i < adb->nnames; i++) 3271135446Strhodes LOCK(&adb->namelocks[i]); 3272224092Sdougb for (i = 0; i < adb->nentries; i++) 3273135446Strhodes LOCK(&adb->entrylocks[i]); 3274135446Strhodes 3275135446Strhodes /* 3276135446Strhodes * Dump the names 3277135446Strhodes */ 3278224092Sdougb for (i = 0; i < adb->nnames; i++) { 3279135446Strhodes name = ISC_LIST_HEAD(adb->names[i]); 3280135446Strhodes if (name == NULL) 3281135446Strhodes continue; 3282135446Strhodes if (debug) 3283135446Strhodes fprintf(f, "; bucket %d\n", i); 3284135446Strhodes for (; 3285135446Strhodes name != NULL; 3286135446Strhodes name = ISC_LIST_NEXT(name, plink)) 3287135446Strhodes { 3288135446Strhodes if (debug) 3289135446Strhodes fprintf(f, "; name %p (flags %08x)\n", 3290135446Strhodes name, name->flags); 3291135446Strhodes 3292135446Strhodes fprintf(f, "; "); 3293135446Strhodes print_dns_name(f, &name->name); 3294135446Strhodes if (dns_name_countlabels(&name->target) > 0) { 3295135446Strhodes fprintf(f, " alias "); 3296135446Strhodes print_dns_name(f, &name->target); 3297135446Strhodes } 3298135446Strhodes 3299135446Strhodes dump_ttl(f, "v4", name->expire_v4, now); 3300135446Strhodes dump_ttl(f, "v6", name->expire_v6, now); 3301135446Strhodes dump_ttl(f, "target", name->expire_target, now); 3302135446Strhodes 3303135446Strhodes fprintf(f, " [v4 %s] [v6 %s]", 3304135446Strhodes errnames[name->fetch_err], 3305135446Strhodes errnames[name->fetch6_err]); 3306135446Strhodes 3307135446Strhodes fprintf(f, "\n"); 3308135446Strhodes 3309135446Strhodes print_namehook_list(f, "v4", &name->v4, debug, now); 3310135446Strhodes print_namehook_list(f, "v6", &name->v6, debug, now); 3311135446Strhodes 3312135446Strhodes if (debug) 3313135446Strhodes print_fetch_list(f, name); 3314135446Strhodes if (debug) 3315135446Strhodes print_find_list(f, name); 3316135446Strhodes 3317135446Strhodes } 3318135446Strhodes } 3319135446Strhodes 3320143731Sdougb fprintf(f, ";\n; Unassociated entries\n;\n"); 3321143731Sdougb 3322224092Sdougb for (i = 0; i < adb->nentries; i++) { 3323143731Sdougb entry = ISC_LIST_HEAD(adb->entries[i]); 3324143731Sdougb while (entry != NULL) { 3325143731Sdougb if (entry->refcnt == 0) 3326143731Sdougb dump_entry(f, entry, debug, now); 3327143731Sdougb entry = ISC_LIST_NEXT(entry, plink); 3328143731Sdougb } 3329143731Sdougb } 3330143731Sdougb 3331135446Strhodes /* 3332135446Strhodes * Unlock everything 3333135446Strhodes */ 3334224092Sdougb for (i = 0; i < adb->nentries; i++) 3335135446Strhodes UNLOCK(&adb->entrylocks[i]); 3336224092Sdougb for (i = 0; i < adb->nnames; i++) 3337135446Strhodes UNLOCK(&adb->namelocks[i]); 3338135446Strhodes} 3339135446Strhodes 3340135446Strhodesstatic void 3341135446Strhodesdump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug, 3342135446Strhodes isc_stdtime_t now) 3343135446Strhodes{ 3344135446Strhodes char addrbuf[ISC_NETADDR_FORMATSIZE]; 3345170222Sdougb char typebuf[DNS_RDATATYPE_FORMATSIZE]; 3346135446Strhodes isc_netaddr_t netaddr; 3347170222Sdougb dns_adblameinfo_t *li; 3348135446Strhodes 3349135446Strhodes isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr); 3350135446Strhodes isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf)); 3351135446Strhodes 3352135446Strhodes if (debug) 3353135446Strhodes fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt); 3354135446Strhodes 3355135446Strhodes fprintf(f, ";\t%s [srtt %u] [flags %08x]", 3356135446Strhodes addrbuf, entry->srtt, entry->flags); 3357143731Sdougb if (entry->expires != 0) 3358143731Sdougb fprintf(f, " [ttl %d]", entry->expires - now); 3359135446Strhodes fprintf(f, "\n"); 3360170222Sdougb for (li = ISC_LIST_HEAD(entry->lameinfo); 3361170222Sdougb li != NULL; 3362170222Sdougb li = ISC_LIST_NEXT(li, plink)) { 3363135446Strhodes fprintf(f, ";\t\t"); 3364170222Sdougb print_dns_name(f, &li->qname); 3365170222Sdougb dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf)); 3366170222Sdougb fprintf(f, " %s [lame TTL %d]\n", typebuf, 3367170222Sdougb li->lame_timer - now); 3368135446Strhodes } 3369135446Strhodes} 3370135446Strhodes 3371135446Strhodesvoid 3372135446Strhodesdns_adb_dumpfind(dns_adbfind_t *find, FILE *f) { 3373135446Strhodes char tmp[512]; 3374135446Strhodes const char *tmpp; 3375135446Strhodes dns_adbaddrinfo_t *ai; 3376135446Strhodes isc_sockaddr_t *sa; 3377135446Strhodes 3378135446Strhodes /* 3379135446Strhodes * Not used currently, in the API Just In Case we 3380135446Strhodes * want to dump out the name and/or entries too. 3381135446Strhodes */ 3382135446Strhodes 3383135446Strhodes LOCK(&find->lock); 3384135446Strhodes 3385135446Strhodes fprintf(f, ";Find %p\n", find); 3386135446Strhodes fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n", 3387135446Strhodes find->query_pending, find->partial_result, 3388135446Strhodes find->options, find->flags); 3389135446Strhodes fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n", 3390135446Strhodes find->name_bucket, find->adbname, find->event.ev_sender); 3391135446Strhodes 3392135446Strhodes ai = ISC_LIST_HEAD(find->list); 3393135446Strhodes if (ai != NULL) 3394135446Strhodes fprintf(f, "\tAddresses:\n"); 3395135446Strhodes while (ai != NULL) { 3396135446Strhodes sa = &ai->sockaddr; 3397135446Strhodes switch (sa->type.sa.sa_family) { 3398135446Strhodes case AF_INET: 3399135446Strhodes tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr, 3400135446Strhodes tmp, sizeof(tmp)); 3401135446Strhodes break; 3402135446Strhodes case AF_INET6: 3403135446Strhodes tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr, 3404135446Strhodes tmp, sizeof(tmp)); 3405135446Strhodes break; 3406135446Strhodes default: 3407135446Strhodes tmpp = "UnkFamily"; 3408135446Strhodes } 3409135446Strhodes 3410135446Strhodes if (tmpp == NULL) 3411135446Strhodes tmpp = "BadAddress"; 3412135446Strhodes 3413135446Strhodes fprintf(f, "\t\tentry %p, flags %08x" 3414135446Strhodes " srtt %u addr %s\n", 3415135446Strhodes ai->entry, ai->flags, ai->srtt, tmpp); 3416135446Strhodes 3417135446Strhodes ai = ISC_LIST_NEXT(ai, publink); 3418135446Strhodes } 3419135446Strhodes 3420135446Strhodes UNLOCK(&find->lock); 3421135446Strhodes} 3422135446Strhodes 3423135446Strhodesstatic void 3424135446Strhodesprint_dns_name(FILE *f, dns_name_t *name) { 3425135446Strhodes char buf[DNS_NAME_FORMATSIZE]; 3426135446Strhodes 3427135446Strhodes INSIST(f != NULL); 3428135446Strhodes 3429135446Strhodes dns_name_format(name, buf, sizeof(buf)); 3430135446Strhodes fprintf(f, "%s", buf); 3431135446Strhodes} 3432135446Strhodes 3433135446Strhodesstatic void 3434135446Strhodesprint_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list, 3435135446Strhodes isc_boolean_t debug, isc_stdtime_t now) 3436135446Strhodes{ 3437135446Strhodes dns_adbnamehook_t *nh; 3438135446Strhodes 3439135446Strhodes for (nh = ISC_LIST_HEAD(*list); 3440135446Strhodes nh != NULL; 3441135446Strhodes nh = ISC_LIST_NEXT(nh, plink)) 3442135446Strhodes { 3443135446Strhodes if (debug) 3444135446Strhodes fprintf(f, ";\tHook(%s) %p\n", legend, nh); 3445135446Strhodes dump_entry(f, nh->entry, debug, now); 3446135446Strhodes } 3447135446Strhodes} 3448135446Strhodes 3449135446Strhodesstatic inline void 3450135446Strhodesprint_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) { 3451193149Sdougb fprintf(f, "\t\tFetch(%s): %p -> { fetch %p }\n", 3452193149Sdougb type, ft, ft->fetch); 3453135446Strhodes} 3454135446Strhodes 3455135446Strhodesstatic void 3456135446Strhodesprint_fetch_list(FILE *f, dns_adbname_t *n) { 3457135446Strhodes if (NAME_FETCH_A(n)) 3458135446Strhodes print_fetch(f, n->fetch_a, "A"); 3459135446Strhodes if (NAME_FETCH_AAAA(n)) 3460135446Strhodes print_fetch(f, n->fetch_aaaa, "AAAA"); 3461135446Strhodes} 3462135446Strhodes 3463135446Strhodesstatic void 3464135446Strhodesprint_find_list(FILE *f, dns_adbname_t *name) { 3465135446Strhodes dns_adbfind_t *find; 3466135446Strhodes 3467135446Strhodes find = ISC_LIST_HEAD(name->finds); 3468135446Strhodes while (find != NULL) { 3469135446Strhodes dns_adb_dumpfind(find, f); 3470135446Strhodes find = ISC_LIST_NEXT(find, plink); 3471135446Strhodes } 3472135446Strhodes} 3473135446Strhodes 3474135446Strhodesstatic isc_result_t 3475135446Strhodesdbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype) 3476135446Strhodes{ 3477135446Strhodes isc_result_t result; 3478135446Strhodes dns_rdataset_t rdataset; 3479135446Strhodes dns_adb_t *adb; 3480135446Strhodes dns_fixedname_t foundname; 3481135446Strhodes dns_name_t *fname; 3482135446Strhodes 3483135446Strhodes INSIST(DNS_ADBNAME_VALID(adbname)); 3484135446Strhodes adb = adbname->adb; 3485135446Strhodes INSIST(DNS_ADB_VALID(adb)); 3486135446Strhodes INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa); 3487135446Strhodes 3488135446Strhodes dns_fixedname_init(&foundname); 3489193149Sdougb fname = dns_fixedname_name(&foundname); 3490135446Strhodes dns_rdataset_init(&rdataset); 3491135446Strhodes 3492135446Strhodes if (rdtype == dns_rdatatype_a) 3493135446Strhodes adbname->fetch_err = FIND_ERR_UNEXPECTED; 3494135446Strhodes else 3495135446Strhodes adbname->fetch6_err = FIND_ERR_UNEXPECTED; 3496135446Strhodes 3497224092Sdougb /* 3498224092Sdougb * We need to specify whether to search static-stub zones (if 3499224092Sdougb * configured) depending on whether this is a "start at zone" lookup, 3500224092Sdougb * i.e., whether it's a "bailiwick" glue. If it's bailiwick (in which 3501224092Sdougb * case NAME_STARTATZONE is set) we need to stop the search at any 3502224092Sdougb * matching static-stub zone without looking into the cache to honor 3503224092Sdougb * the configuration on which server we should send queries to. 3504224092Sdougb */ 3505224092Sdougb result = dns_view_find2(adb->view, &adbname->name, rdtype, now, 3506224092Sdougb NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0, 3507224092Sdougb ISC_TF(NAME_HINTOK(adbname)), 3508224092Sdougb (adbname->flags & NAME_STARTATZONE) != 0 ? 3509224092Sdougb ISC_TRUE : ISC_FALSE, 3510224092Sdougb NULL, NULL, fname, &rdataset, NULL); 3511135446Strhodes 3512135446Strhodes /* XXXVIX this switch statement is too sparse to gen a jump table. */ 3513135446Strhodes switch (result) { 3514135446Strhodes case DNS_R_GLUE: 3515135446Strhodes case DNS_R_HINT: 3516135446Strhodes case ISC_R_SUCCESS: 3517135446Strhodes /* 3518135446Strhodes * Found in the database. Even if we can't copy out 3519135446Strhodes * any information, return success, or else a fetch 3520135446Strhodes * will be made, which will only make things worse. 3521135446Strhodes */ 3522135446Strhodes if (rdtype == dns_rdatatype_a) 3523135446Strhodes adbname->fetch_err = FIND_ERR_SUCCESS; 3524135446Strhodes else 3525135446Strhodes adbname->fetch6_err = FIND_ERR_SUCCESS; 3526135446Strhodes result = import_rdataset(adbname, &rdataset, now); 3527135446Strhodes break; 3528135446Strhodes case DNS_R_NXDOMAIN: 3529135446Strhodes case DNS_R_NXRRSET: 3530135446Strhodes /* 3531135446Strhodes * We're authoritative and the data doesn't exist. 3532135446Strhodes * Make up a negative cache entry so we don't ask again 3533135446Strhodes * for a while. 3534135446Strhodes * 3535135446Strhodes * XXXRTH What time should we use? I'm putting in 30 seconds 3536135446Strhodes * for now. 3537135446Strhodes */ 3538135446Strhodes if (rdtype == dns_rdatatype_a) { 3539135446Strhodes adbname->expire_v4 = now + 30; 3540135446Strhodes DP(NCACHE_LEVEL, 3541135446Strhodes "adb name %p: Caching auth negative entry for A", 3542135446Strhodes adbname); 3543135446Strhodes if (result == DNS_R_NXDOMAIN) 3544135446Strhodes adbname->fetch_err = FIND_ERR_NXDOMAIN; 3545135446Strhodes else 3546135446Strhodes adbname->fetch_err = FIND_ERR_NXRRSET; 3547135446Strhodes } else { 3548135446Strhodes DP(NCACHE_LEVEL, 3549135446Strhodes "adb name %p: Caching auth negative entry for AAAA", 3550135446Strhodes adbname); 3551135446Strhodes adbname->expire_v6 = now + 30; 3552135446Strhodes if (result == DNS_R_NXDOMAIN) 3553135446Strhodes adbname->fetch6_err = FIND_ERR_NXDOMAIN; 3554135446Strhodes else 3555135446Strhodes adbname->fetch6_err = FIND_ERR_NXRRSET; 3556135446Strhodes } 3557135446Strhodes break; 3558135446Strhodes case DNS_R_NCACHENXDOMAIN: 3559135446Strhodes case DNS_R_NCACHENXRRSET: 3560135446Strhodes /* 3561135446Strhodes * We found a negative cache entry. Pull the TTL from it 3562135446Strhodes * so we won't ask again for a while. 3563135446Strhodes */ 3564135446Strhodes rdataset.ttl = ttlclamp(rdataset.ttl); 3565135446Strhodes if (rdtype == dns_rdatatype_a) { 3566135446Strhodes adbname->expire_v4 = rdataset.ttl + now; 3567135446Strhodes if (result == DNS_R_NCACHENXDOMAIN) 3568135446Strhodes adbname->fetch_err = FIND_ERR_NXDOMAIN; 3569135446Strhodes else 3570135446Strhodes adbname->fetch_err = FIND_ERR_NXRRSET; 3571135446Strhodes DP(NCACHE_LEVEL, 3572135446Strhodes "adb name %p: Caching negative entry for A (ttl %u)", 3573135446Strhodes adbname, rdataset.ttl); 3574135446Strhodes } else { 3575135446Strhodes DP(NCACHE_LEVEL, 3576135446Strhodes "adb name %p: Caching negative entry for AAAA (ttl %u)", 3577135446Strhodes adbname, rdataset.ttl); 3578135446Strhodes adbname->expire_v6 = rdataset.ttl + now; 3579135446Strhodes if (result == DNS_R_NCACHENXDOMAIN) 3580135446Strhodes adbname->fetch6_err = FIND_ERR_NXDOMAIN; 3581135446Strhodes else 3582135446Strhodes adbname->fetch6_err = FIND_ERR_NXRRSET; 3583135446Strhodes } 3584135446Strhodes break; 3585135446Strhodes case DNS_R_CNAME: 3586135446Strhodes case DNS_R_DNAME: 3587135446Strhodes /* 3588135446Strhodes * Clear the hint and glue flags, so this will match 3589135446Strhodes * more often. 3590135446Strhodes */ 3591135446Strhodes adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK); 3592135446Strhodes 3593135446Strhodes rdataset.ttl = ttlclamp(rdataset.ttl); 3594135446Strhodes clean_target(adb, &adbname->target); 3595135446Strhodes adbname->expire_target = INT_MAX; 3596135446Strhodes result = set_target(adb, &adbname->name, fname, &rdataset, 3597135446Strhodes &adbname->target); 3598135446Strhodes if (result == ISC_R_SUCCESS) { 3599135446Strhodes result = DNS_R_ALIAS; 3600135446Strhodes DP(NCACHE_LEVEL, 3601135446Strhodes "adb name %p: caching alias target", 3602135446Strhodes adbname); 3603135446Strhodes adbname->expire_target = rdataset.ttl + now; 3604135446Strhodes } 3605135446Strhodes if (rdtype == dns_rdatatype_a) 3606135446Strhodes adbname->fetch_err = FIND_ERR_SUCCESS; 3607135446Strhodes else 3608135446Strhodes adbname->fetch6_err = FIND_ERR_SUCCESS; 3609135446Strhodes break; 3610135446Strhodes } 3611135446Strhodes 3612135446Strhodes if (dns_rdataset_isassociated(&rdataset)) 3613135446Strhodes dns_rdataset_disassociate(&rdataset); 3614135446Strhodes 3615135446Strhodes return (result); 3616135446Strhodes} 3617135446Strhodes 3618135446Strhodesstatic void 3619135446Strhodesfetch_callback(isc_task_t *task, isc_event_t *ev) { 3620135446Strhodes dns_fetchevent_t *dev; 3621135446Strhodes dns_adbname_t *name; 3622135446Strhodes dns_adb_t *adb; 3623135446Strhodes dns_adbfetch_t *fetch; 3624135446Strhodes int bucket; 3625135446Strhodes isc_eventtype_t ev_status; 3626135446Strhodes isc_stdtime_t now; 3627135446Strhodes isc_result_t result; 3628135446Strhodes unsigned int address_type; 3629135446Strhodes isc_boolean_t want_check_exit = ISC_FALSE; 3630135446Strhodes 3631135446Strhodes UNUSED(task); 3632135446Strhodes 3633135446Strhodes INSIST(ev->ev_type == DNS_EVENT_FETCHDONE); 3634135446Strhodes dev = (dns_fetchevent_t *)ev; 3635135446Strhodes name = ev->ev_arg; 3636135446Strhodes INSIST(DNS_ADBNAME_VALID(name)); 3637135446Strhodes adb = name->adb; 3638135446Strhodes INSIST(DNS_ADB_VALID(adb)); 3639135446Strhodes 3640135446Strhodes bucket = name->lock_bucket; 3641135446Strhodes LOCK(&adb->namelocks[bucket]); 3642135446Strhodes 3643135446Strhodes INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name)); 3644135446Strhodes address_type = 0; 3645135446Strhodes if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) { 3646135446Strhodes address_type = DNS_ADBFIND_INET; 3647135446Strhodes fetch = name->fetch_a; 3648135446Strhodes name->fetch_a = NULL; 3649135446Strhodes } else if (NAME_FETCH_AAAA(name) 3650135446Strhodes && (name->fetch_aaaa->fetch == dev->fetch)) { 3651135446Strhodes address_type = DNS_ADBFIND_INET6; 3652135446Strhodes fetch = name->fetch_aaaa; 3653135446Strhodes name->fetch_aaaa = NULL; 3654186462Sdougb } else 3655186462Sdougb fetch = NULL; 3656135446Strhodes 3657186462Sdougb INSIST(address_type != 0 && fetch != NULL); 3658186462Sdougb 3659135446Strhodes dns_resolver_destroyfetch(&fetch->fetch); 3660135446Strhodes dev->fetch = NULL; 3661135446Strhodes 3662135446Strhodes ev_status = DNS_EVENT_ADBNOMOREADDRESSES; 3663135446Strhodes 3664135446Strhodes /* 3665135446Strhodes * Cleanup things we don't care about. 3666135446Strhodes */ 3667135446Strhodes if (dev->node != NULL) 3668135446Strhodes dns_db_detachnode(dev->db, &dev->node); 3669135446Strhodes if (dev->db != NULL) 3670135446Strhodes dns_db_detach(&dev->db); 3671135446Strhodes 3672135446Strhodes /* 3673135446Strhodes * If this name is marked as dead, clean up, throwing away 3674135446Strhodes * potentially good data. 3675135446Strhodes */ 3676135446Strhodes if (NAME_DEAD(name)) { 3677135446Strhodes free_adbfetch(adb, &fetch); 3678135446Strhodes isc_event_free(&ev); 3679135446Strhodes 3680135446Strhodes want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED); 3681135446Strhodes 3682135446Strhodes UNLOCK(&adb->namelocks[bucket]); 3683135446Strhodes 3684135446Strhodes if (want_check_exit) { 3685135446Strhodes LOCK(&adb->lock); 3686135446Strhodes check_exit(adb); 3687135446Strhodes UNLOCK(&adb->lock); 3688135446Strhodes } 3689135446Strhodes 3690135446Strhodes return; 3691135446Strhodes } 3692135446Strhodes 3693135446Strhodes isc_stdtime_get(&now); 3694135446Strhodes 3695135446Strhodes /* 3696135446Strhodes * If we got a negative cache response, remember it. 3697135446Strhodes */ 3698135446Strhodes if (NCACHE_RESULT(dev->result)) { 3699135446Strhodes dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl); 3700135446Strhodes if (address_type == DNS_ADBFIND_INET) { 3701135446Strhodes DP(NCACHE_LEVEL, "adb fetch name %p: " 3702135446Strhodes "caching negative entry for A (ttl %u)", 3703135446Strhodes name, dev->rdataset->ttl); 3704135446Strhodes name->expire_v4 = ISC_MIN(name->expire_v4, 3705135446Strhodes dev->rdataset->ttl + now); 3706135446Strhodes if (dev->result == DNS_R_NCACHENXDOMAIN) 3707135446Strhodes name->fetch_err = FIND_ERR_NXDOMAIN; 3708135446Strhodes else 3709135446Strhodes name->fetch_err = FIND_ERR_NXRRSET; 3710193149Sdougb inc_stats(adb, dns_resstatscounter_gluefetchv4fail); 3711135446Strhodes } else { 3712135446Strhodes DP(NCACHE_LEVEL, "adb fetch name %p: " 3713135446Strhodes "caching negative entry for AAAA (ttl %u)", 3714135446Strhodes name, dev->rdataset->ttl); 3715135446Strhodes name->expire_v6 = ISC_MIN(name->expire_v6, 3716135446Strhodes dev->rdataset->ttl + now); 3717135446Strhodes if (dev->result == DNS_R_NCACHENXDOMAIN) 3718135446Strhodes name->fetch6_err = FIND_ERR_NXDOMAIN; 3719135446Strhodes else 3720135446Strhodes name->fetch6_err = FIND_ERR_NXRRSET; 3721193149Sdougb inc_stats(adb, dns_resstatscounter_gluefetchv6fail); 3722135446Strhodes } 3723135446Strhodes goto out; 3724135446Strhodes } 3725135446Strhodes 3726135446Strhodes /* 3727135446Strhodes * Handle CNAME/DNAME. 3728135446Strhodes */ 3729135446Strhodes if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) { 3730135446Strhodes dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl); 3731135446Strhodes clean_target(adb, &name->target); 3732135446Strhodes name->expire_target = INT_MAX; 3733135446Strhodes result = set_target(adb, &name->name, 3734135446Strhodes dns_fixedname_name(&dev->foundname), 3735135446Strhodes dev->rdataset, 3736135446Strhodes &name->target); 3737135446Strhodes if (result == ISC_R_SUCCESS) { 3738135446Strhodes DP(NCACHE_LEVEL, 3739135446Strhodes "adb fetch name %p: caching alias target", 3740135446Strhodes name); 3741135446Strhodes name->expire_target = dev->rdataset->ttl + now; 3742135446Strhodes } 3743135446Strhodes goto check_result; 3744135446Strhodes } 3745135446Strhodes 3746135446Strhodes /* 3747135446Strhodes * Did we get back junk? If so, and there are no more fetches 3748135446Strhodes * sitting out there, tell all the finds about it. 3749135446Strhodes */ 3750135446Strhodes if (dev->result != ISC_R_SUCCESS) { 3751135446Strhodes char buf[DNS_NAME_FORMATSIZE]; 3752135446Strhodes 3753135446Strhodes dns_name_format(&name->name, buf, sizeof(buf)); 3754135446Strhodes DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s", 3755135446Strhodes buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA", 3756135446Strhodes dns_result_totext(dev->result)); 3757135446Strhodes /* XXXMLG Don't pound on bad servers. */ 3758135446Strhodes if (address_type == DNS_ADBFIND_INET) { 3759135446Strhodes name->expire_v4 = ISC_MIN(name->expire_v4, now + 300); 3760135446Strhodes name->fetch_err = FIND_ERR_FAILURE; 3761193149Sdougb inc_stats(adb, dns_resstatscounter_gluefetchv4fail); 3762135446Strhodes } else { 3763135446Strhodes name->expire_v6 = ISC_MIN(name->expire_v6, now + 300); 3764135446Strhodes name->fetch6_err = FIND_ERR_FAILURE; 3765193149Sdougb inc_stats(adb, dns_resstatscounter_gluefetchv6fail); 3766135446Strhodes } 3767135446Strhodes goto out; 3768135446Strhodes } 3769135446Strhodes 3770135446Strhodes /* 3771135446Strhodes * We got something potentially useful. 3772135446Strhodes */ 3773135446Strhodes result = import_rdataset(name, &fetch->rdataset, now); 3774135446Strhodes 3775135446Strhodes check_result: 3776135446Strhodes if (result == ISC_R_SUCCESS) { 3777135446Strhodes ev_status = DNS_EVENT_ADBMOREADDRESSES; 3778135446Strhodes if (address_type == DNS_ADBFIND_INET) 3779135446Strhodes name->fetch_err = FIND_ERR_SUCCESS; 3780135446Strhodes else 3781135446Strhodes name->fetch6_err = FIND_ERR_SUCCESS; 3782135446Strhodes } 3783135446Strhodes 3784135446Strhodes out: 3785135446Strhodes free_adbfetch(adb, &fetch); 3786135446Strhodes isc_event_free(&ev); 3787135446Strhodes 3788135446Strhodes clean_finds_at_name(name, ev_status, address_type); 3789135446Strhodes 3790135446Strhodes UNLOCK(&adb->namelocks[bucket]); 3791135446Strhodes} 3792135446Strhodes 3793135446Strhodesstatic isc_result_t 3794135446Strhodesfetch_name(dns_adbname_t *adbname, 3795135446Strhodes isc_boolean_t start_at_zone, 3796135446Strhodes dns_rdatatype_t type) 3797135446Strhodes{ 3798135446Strhodes isc_result_t result; 3799135446Strhodes dns_adbfetch_t *fetch = NULL; 3800135446Strhodes dns_adb_t *adb; 3801135446Strhodes dns_fixedname_t fixed; 3802135446Strhodes dns_name_t *name; 3803135446Strhodes dns_rdataset_t rdataset; 3804135446Strhodes dns_rdataset_t *nameservers; 3805135446Strhodes unsigned int options; 3806135446Strhodes 3807135446Strhodes INSIST(DNS_ADBNAME_VALID(adbname)); 3808135446Strhodes adb = adbname->adb; 3809135446Strhodes INSIST(DNS_ADB_VALID(adb)); 3810135446Strhodes 3811135446Strhodes INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) || 3812135446Strhodes (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname))); 3813135446Strhodes 3814135446Strhodes adbname->fetch_err = FIND_ERR_NOTFOUND; 3815135446Strhodes 3816135446Strhodes name = NULL; 3817135446Strhodes nameservers = NULL; 3818135446Strhodes dns_rdataset_init(&rdataset); 3819135446Strhodes 3820135446Strhodes options = DNS_FETCHOPT_NOVALIDATE; 3821135446Strhodes if (start_at_zone) { 3822135446Strhodes DP(ENTER_LEVEL, 3823135446Strhodes "fetch_name: starting at zone for name %p", 3824135446Strhodes adbname); 3825135446Strhodes dns_fixedname_init(&fixed); 3826135446Strhodes name = dns_fixedname_name(&fixed); 3827135446Strhodes result = dns_view_findzonecut2(adb->view, &adbname->name, name, 3828135446Strhodes 0, 0, ISC_TRUE, ISC_FALSE, 3829135446Strhodes &rdataset, NULL); 3830135446Strhodes if (result != ISC_R_SUCCESS && result != DNS_R_HINT) 3831135446Strhodes goto cleanup; 3832135446Strhodes nameservers = &rdataset; 3833135446Strhodes options |= DNS_FETCHOPT_UNSHARED; 3834135446Strhodes } 3835135446Strhodes 3836135446Strhodes fetch = new_adbfetch(adb); 3837135446Strhodes if (fetch == NULL) { 3838135446Strhodes result = ISC_R_NOMEMORY; 3839135446Strhodes goto cleanup; 3840135446Strhodes } 3841135446Strhodes 3842135446Strhodes result = dns_resolver_createfetch(adb->view->resolver, &adbname->name, 3843135446Strhodes type, name, nameservers, NULL, 3844135446Strhodes options, adb->task, fetch_callback, 3845135446Strhodes adbname, &fetch->rdataset, NULL, 3846135446Strhodes &fetch->fetch); 3847135446Strhodes if (result != ISC_R_SUCCESS) 3848135446Strhodes goto cleanup; 3849135446Strhodes 3850193149Sdougb if (type == dns_rdatatype_a) { 3851135446Strhodes adbname->fetch_a = fetch; 3852193149Sdougb inc_stats(adb, dns_resstatscounter_gluefetchv4); 3853193149Sdougb } else { 3854135446Strhodes adbname->fetch_aaaa = fetch; 3855193149Sdougb inc_stats(adb, dns_resstatscounter_gluefetchv6); 3856193149Sdougb } 3857135446Strhodes fetch = NULL; /* Keep us from cleaning this up below. */ 3858135446Strhodes 3859135446Strhodes cleanup: 3860135446Strhodes if (fetch != NULL) 3861135446Strhodes free_adbfetch(adb, &fetch); 3862135446Strhodes if (dns_rdataset_isassociated(&rdataset)) 3863135446Strhodes dns_rdataset_disassociate(&rdataset); 3864135446Strhodes 3865135446Strhodes return (result); 3866135446Strhodes} 3867135446Strhodes 3868135446Strhodes/* 3869135446Strhodes * XXXMLG Needs to take a find argument and an address info, no zone or adb, 3870135446Strhodes * since these can be extracted from the find itself. 3871135446Strhodes */ 3872135446Strhodesisc_result_t 3873170222Sdougbdns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname, 3874170222Sdougb dns_rdatatype_t qtype, isc_stdtime_t expire_time) 3875135446Strhodes{ 3876170222Sdougb dns_adblameinfo_t *li; 3877135446Strhodes int bucket; 3878135446Strhodes isc_result_t result = ISC_R_SUCCESS; 3879135446Strhodes 3880135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3881135446Strhodes REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3882170222Sdougb REQUIRE(qname != NULL); 3883135446Strhodes 3884135446Strhodes bucket = addr->entry->lock_bucket; 3885135446Strhodes LOCK(&adb->entrylocks[bucket]); 3886170222Sdougb li = ISC_LIST_HEAD(addr->entry->lameinfo); 3887170222Sdougb while (li != NULL && 3888170222Sdougb (li->qtype != qtype || !dns_name_equal(qname, &li->qname))) 3889170222Sdougb li = ISC_LIST_NEXT(li, plink); 3890170222Sdougb if (li != NULL) { 3891170222Sdougb if (expire_time > li->lame_timer) 3892170222Sdougb li->lame_timer = expire_time; 3893135446Strhodes goto unlock; 3894135446Strhodes } 3895170222Sdougb li = new_adblameinfo(adb, qname, qtype); 3896170222Sdougb if (li == NULL) { 3897135446Strhodes result = ISC_R_NOMEMORY; 3898135446Strhodes goto unlock; 3899135446Strhodes } 3900135446Strhodes 3901170222Sdougb li->lame_timer = expire_time; 3902135446Strhodes 3903170222Sdougb ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink); 3904135446Strhodes unlock: 3905135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 3906135446Strhodes 3907153816Sdougb return (result); 3908135446Strhodes} 3909135446Strhodes 3910135446Strhodesvoid 3911135446Strhodesdns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr, 3912135446Strhodes unsigned int rtt, unsigned int factor) 3913135446Strhodes{ 3914135446Strhodes int bucket; 3915135446Strhodes unsigned int new_srtt; 3916135446Strhodes isc_stdtime_t now; 3917135446Strhodes 3918135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3919135446Strhodes REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3920135446Strhodes REQUIRE(factor <= 10); 3921135446Strhodes 3922135446Strhodes bucket = addr->entry->lock_bucket; 3923135446Strhodes LOCK(&adb->entrylocks[bucket]); 3924135446Strhodes 3925135446Strhodes if (factor == DNS_ADB_RTTADJAGE) 3926135446Strhodes new_srtt = addr->entry->srtt * 98 / 100; 3927135446Strhodes else 3928135446Strhodes new_srtt = (addr->entry->srtt / 10 * factor) 3929135446Strhodes + (rtt / 10 * (10 - factor)); 3930135446Strhodes 3931135446Strhodes addr->entry->srtt = new_srtt; 3932135446Strhodes addr->srtt = new_srtt; 3933135446Strhodes 3934245163Serwin if (addr->entry->expires == 0) { 3935245163Serwin isc_stdtime_get(&now); 3936245163Serwin addr->entry->expires = now + ADB_ENTRY_WINDOW; 3937245163Serwin } 3938135446Strhodes 3939135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 3940135446Strhodes} 3941135446Strhodes 3942135446Strhodesvoid 3943135446Strhodesdns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr, 3944135446Strhodes unsigned int bits, unsigned int mask) 3945135446Strhodes{ 3946135446Strhodes int bucket; 3947245163Serwin isc_stdtime_t now; 3948135446Strhodes 3949135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3950135446Strhodes REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3951135446Strhodes 3952135446Strhodes bucket = addr->entry->lock_bucket; 3953135446Strhodes LOCK(&adb->entrylocks[bucket]); 3954135446Strhodes 3955135446Strhodes addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask); 3956245163Serwin if (addr->entry->expires == 0) { 3957245163Serwin isc_stdtime_get(&now); 3958245163Serwin addr->entry->expires = now + ADB_ENTRY_WINDOW; 3959245163Serwin } 3960245163Serwin 3961135446Strhodes /* 3962135446Strhodes * Note that we do not update the other bits in addr->flags with 3963135446Strhodes * the most recent values from addr->entry->flags. 3964135446Strhodes */ 3965135446Strhodes addr->flags = (addr->flags & ~mask) | (bits & mask); 3966135446Strhodes 3967135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 3968135446Strhodes} 3969135446Strhodes 3970135446Strhodesisc_result_t 3971135446Strhodesdns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa, 3972135446Strhodes dns_adbaddrinfo_t **addrp, isc_stdtime_t now) 3973135446Strhodes{ 3974135446Strhodes int bucket; 3975135446Strhodes dns_adbentry_t *entry; 3976135446Strhodes dns_adbaddrinfo_t *addr; 3977135446Strhodes isc_result_t result; 3978135446Strhodes in_port_t port; 3979135446Strhodes 3980135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 3981135446Strhodes REQUIRE(addrp != NULL && *addrp == NULL); 3982135446Strhodes 3983135446Strhodes UNUSED(now); 3984135446Strhodes 3985135446Strhodes result = ISC_R_SUCCESS; 3986135446Strhodes bucket = DNS_ADB_INVALIDBUCKET; 3987193149Sdougb entry = find_entry_and_lock(adb, sa, &bucket, now); 3988225361Sdougb INSIST(bucket != DNS_ADB_INVALIDBUCKET); 3989135446Strhodes if (adb->entry_sd[bucket]) { 3990135446Strhodes result = ISC_R_SHUTTINGDOWN; 3991135446Strhodes goto unlock; 3992135446Strhodes } 3993135446Strhodes if (entry == NULL) { 3994135446Strhodes /* 3995135446Strhodes * We don't know anything about this address. 3996135446Strhodes */ 3997135446Strhodes entry = new_adbentry(adb); 3998135446Strhodes if (entry == NULL) { 3999135446Strhodes result = ISC_R_NOMEMORY; 4000135446Strhodes goto unlock; 4001135446Strhodes } 4002135446Strhodes entry->sockaddr = *sa; 4003135446Strhodes link_entry(adb, bucket, entry); 4004135446Strhodes DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry); 4005135446Strhodes } else 4006135446Strhodes DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry); 4007135446Strhodes 4008135446Strhodes port = isc_sockaddr_getport(sa); 4009135446Strhodes addr = new_adbaddrinfo(adb, entry, port); 4010174187Sdougb if (addr == NULL) { 4011174187Sdougb result = ISC_R_NOMEMORY; 4012174187Sdougb } else { 4013135446Strhodes inc_entry_refcnt(adb, entry, ISC_FALSE); 4014135446Strhodes *addrp = addr; 4015135446Strhodes } 4016135446Strhodes 4017135446Strhodes unlock: 4018135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 4019135446Strhodes 4020135446Strhodes return (result); 4021135446Strhodes} 4022135446Strhodes 4023135446Strhodesvoid 4024135446Strhodesdns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) { 4025135446Strhodes dns_adbaddrinfo_t *addr; 4026135446Strhodes dns_adbentry_t *entry; 4027135446Strhodes int bucket; 4028135446Strhodes isc_stdtime_t now; 4029135446Strhodes isc_boolean_t want_check_exit = ISC_FALSE; 4030214586Sdougb isc_boolean_t overmem; 4031135446Strhodes 4032135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 4033135446Strhodes REQUIRE(addrp != NULL); 4034135446Strhodes addr = *addrp; 4035135446Strhodes REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 4036135446Strhodes entry = addr->entry; 4037135446Strhodes REQUIRE(DNS_ADBENTRY_VALID(entry)); 4038135446Strhodes 4039135446Strhodes *addrp = NULL; 4040214586Sdougb overmem = isc_mem_isovermem(adb->mctx); 4041135446Strhodes 4042135446Strhodes bucket = addr->entry->lock_bucket; 4043135446Strhodes LOCK(&adb->entrylocks[bucket]); 4044135446Strhodes 4045245163Serwin if (entry->expires == 0) { 4046245163Serwin isc_stdtime_get(&now); 4047245163Serwin entry->expires = now + ADB_ENTRY_WINDOW; 4048245163Serwin } 4049135446Strhodes 4050214586Sdougb want_check_exit = dec_entry_refcnt(adb, overmem, entry, ISC_FALSE); 4051135446Strhodes 4052135446Strhodes UNLOCK(&adb->entrylocks[bucket]); 4053135446Strhodes 4054135446Strhodes addr->entry = NULL; 4055135446Strhodes free_adbaddrinfo(adb, &addr); 4056135446Strhodes 4057135446Strhodes if (want_check_exit) { 4058135446Strhodes LOCK(&adb->lock); 4059135446Strhodes check_exit(adb); 4060135446Strhodes UNLOCK(&adb->lock); 4061135446Strhodes } 4062135446Strhodes} 4063135446Strhodes 4064135446Strhodesvoid 4065135446Strhodesdns_adb_flush(dns_adb_t *adb) { 4066135446Strhodes unsigned int i; 4067135446Strhodes 4068135446Strhodes INSIST(DNS_ADB_VALID(adb)); 4069135446Strhodes 4070135446Strhodes LOCK(&adb->lock); 4071135446Strhodes 4072143731Sdougb /* 4073143731Sdougb * Call our cleanup routines. 4074143731Sdougb */ 4075224092Sdougb for (i = 0; i < adb->nnames; i++) 4076135446Strhodes RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE); 4077224092Sdougb for (i = 0; i < adb->nentries; i++) 4078135446Strhodes RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE); 4079135446Strhodes 4080135446Strhodes#ifdef DUMP_ADB_AFTER_CLEANING 4081143731Sdougb dump_adb(adb, stdout, ISC_TRUE, INT_MAX); 4082135446Strhodes#endif 4083135446Strhodes 4084135446Strhodes UNLOCK(&adb->lock); 4085135446Strhodes} 4086135446Strhodes 4087135446Strhodesvoid 4088135446Strhodesdns_adb_flushname(dns_adb_t *adb, dns_name_t *name) { 4089135446Strhodes dns_adbname_t *adbname; 4090135446Strhodes dns_adbname_t *nextname; 4091135446Strhodes int bucket; 4092135446Strhodes 4093135446Strhodes INSIST(DNS_ADB_VALID(adb)); 4094135446Strhodes 4095135446Strhodes LOCK(&adb->lock); 4096224092Sdougb bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames; 4097135446Strhodes LOCK(&adb->namelocks[bucket]); 4098135446Strhodes adbname = ISC_LIST_HEAD(adb->names[bucket]); 4099135446Strhodes while (adbname != NULL) { 4100135446Strhodes nextname = ISC_LIST_NEXT(adbname, plink); 4101135446Strhodes if (!NAME_DEAD(adbname) && 4102135446Strhodes dns_name_equal(name, &adbname->name)) { 4103135446Strhodes RUNTIME_CHECK(kill_name(&adbname, 4104135446Strhodes DNS_EVENT_ADBCANCELED) == 4105135446Strhodes ISC_FALSE); 4106135446Strhodes } 4107135446Strhodes adbname = nextname; 4108135446Strhodes } 4109135446Strhodes UNLOCK(&adb->namelocks[bucket]); 4110135446Strhodes UNLOCK(&adb->lock); 4111135446Strhodes} 4112135446Strhodes 4113135446Strhodesstatic void 4114135446Strhodeswater(void *arg, int mark) { 4115214586Sdougb /* 4116214586Sdougb * We're going to change the way to handle overmem condition: use 4117214586Sdougb * isc_mem_isovermem() instead of storing the state via this callback, 4118214586Sdougb * since the latter way tends to cause race conditions. 4119214586Sdougb * To minimize the change, and in case we re-enable the callback 4120214586Sdougb * approach, however, keep this function at the moment. 4121214586Sdougb */ 4122214586Sdougb 4123135446Strhodes dns_adb_t *adb = arg; 4124135446Strhodes isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER); 4125135446Strhodes 4126135446Strhodes REQUIRE(DNS_ADB_VALID(adb)); 4127135446Strhodes 4128135446Strhodes DP(ISC_LOG_DEBUG(1), 4129135446Strhodes "adb reached %s water mark", overmem ? "high" : "low"); 4130135446Strhodes} 4131135446Strhodes 4132135446Strhodesvoid 4133135446Strhodesdns_adb_setadbsize(dns_adb_t *adb, isc_uint32_t size) { 4134135446Strhodes isc_uint32_t hiwater; 4135135446Strhodes isc_uint32_t lowater; 4136135446Strhodes 4137135446Strhodes INSIST(DNS_ADB_VALID(adb)); 4138135446Strhodes 4139254402Serwin if (size != 0U && size < DNS_ADB_MINADBSIZE) 4140135446Strhodes size = DNS_ADB_MINADBSIZE; 4141135446Strhodes 4142135446Strhodes hiwater = size - (size >> 3); /* Approximately 7/8ths. */ 4143135446Strhodes lowater = size - (size >> 2); /* Approximately 3/4ths. */ 4144135446Strhodes 4145254402Serwin if (size == 0U || hiwater == 0U || lowater == 0U) 4146135446Strhodes isc_mem_setwater(adb->mctx, water, adb, 0, 0); 4147135446Strhodes else 4148135446Strhodes isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater); 4149135446Strhodes} 4150