adb.c revision 262706
154359Sroberto/* 254359Sroberto * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") 354359Sroberto * Copyright (C) 1999-2003 Internet Software Consortium. 454359Sroberto * 554359Sroberto * Permission to use, copy, modify, and/or distribute this software for any 654359Sroberto * purpose with or without fee is hereby granted, provided that the above 754359Sroberto * copyright notice and this permission notice appear in all copies. 854359Sroberto * 9285612Sdelphij * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 1054359Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 1154359Sroberto * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 1254359Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 1354359Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 1454359Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 1554359Sroberto * PERFORMANCE OF THIS SOFTWARE. 16182007Sroberto */ 1754359Sroberto 1854359Sroberto/* $Id: adb.c,v 1.264 2011/12/05 17:10:51 each Exp $ */ 1954359Sroberto 2054359Sroberto/*! \file 2154359Sroberto * 2254359Sroberto * \note 2354359Sroberto * In finds, if task == NULL, no events will be generated, and no events 2454359Sroberto * have been sent. If task != NULL but taskaction == NULL, an event has been 2554359Sroberto * posted but not yet freed. If neither are NULL, no event was posted. 2654359Sroberto * 2754359Sroberto */ 2854359Sroberto 2954359Sroberto#include <config.h> 3054359Sroberto 3154359Sroberto#include <limits.h> 3254359Sroberto 3354359Sroberto#include <isc/mutexblock.h> 3454359Sroberto#include <isc/netaddr.h> 3554359Sroberto#include <isc/random.h> 3654359Sroberto#include <isc/stats.h> 3754359Sroberto#include <isc/string.h> /* Required for HP/UX (and others?) */ 3854359Sroberto#include <isc/task.h> 3954359Sroberto#include <isc/util.h> 4054359Sroberto 4154359Sroberto#include <dns/adb.h> 4254359Sroberto#include <dns/db.h> 4354359Sroberto#include <dns/events.h> 4454359Sroberto#include <dns/log.h> 4554359Sroberto#include <dns/rdata.h> 4654359Sroberto#include <dns/rdataset.h> 47285612Sdelphij#include <dns/rdatastruct.h> 48285612Sdelphij#include <dns/rdatatype.h> 49285612Sdelphij#include <dns/resolver.h> 50285612Sdelphij#include <dns/result.h> 51285612Sdelphij#include <dns/stats.h> 52285612Sdelphij 53285612Sdelphij#define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b') 54285612Sdelphij#define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC) 5554359Sroberto#define DNS_ADBNAME_MAGIC ISC_MAGIC('a', 'd', 'b', 'N') 56285612Sdelphij#define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC) 5754359Sroberto#define DNS_ADBNAMEHOOK_MAGIC ISC_MAGIC('a', 'd', 'N', 'H') 5854359Sroberto#define DNS_ADBNAMEHOOK_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC) 59285612Sdelphij#define DNS_ADBLAMEINFO_MAGIC ISC_MAGIC('a', 'd', 'b', 'Z') 60285612Sdelphij#define DNS_ADBLAMEINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBLAMEINFO_MAGIC) 61285612Sdelphij#define DNS_ADBENTRY_MAGIC ISC_MAGIC('a', 'd', 'b', 'E') 62285612Sdelphij#define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC) 63285612Sdelphij#define DNS_ADBFETCH_MAGIC ISC_MAGIC('a', 'd', 'F', '4') 64285612Sdelphij#define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC) 65285612Sdelphij#define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6') 66285612Sdelphij#define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC) 67285612Sdelphij 68285612Sdelphij/*! 69285612Sdelphij * For type 3 negative cache entries, we will remember that the address is 70285612Sdelphij * broken for this long. XXXMLG This is also used for actual addresses, too. 71285612Sdelphij * The intent is to keep us from constantly asking about A/AAAA records 72285612Sdelphij * if the zone has extremely low TTLs. 73285612Sdelphij */ 7454359Sroberto#define ADB_CACHE_MINIMUM 10 /*%< seconds */ 75182007Sroberto#define ADB_CACHE_MAXIMUM 86400 /*%< seconds (86400 = 24 hours) */ 7654359Sroberto#define ADB_ENTRY_WINDOW 1800 /*%< seconds */ 77285612Sdelphij 78182007Sroberto/*% 79285612Sdelphij * The period in seconds after which an ADB name entry is regarded as stale 80182007Sroberto * and forced to be cleaned up. 81285612Sdelphij * TODO: This should probably be configurable at run-time. 82285612Sdelphij */ 83285612Sdelphij#ifndef ADB_STALE_MARGIN 84182007Sroberto#define ADB_STALE_MARGIN 1800 85285612Sdelphij#endif 86285612Sdelphij 87182007Sroberto#define FREE_ITEMS 64 /*%< free count for memory pools */ 88285612Sdelphij#define FILL_COUNT 16 /*%< fill count for memory pools */ 89182007Sroberto 90182007Sroberto#define DNS_ADB_INVALIDBUCKET (-1) /*%< invalid bucket address */ 91182007Sroberto 9254359Sroberto#define DNS_ADB_MINADBSIZE (1024U*1024U) /*%< 1 Megabyte */ 9354359Sroberto 9454359Srobertotypedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t; 9554359Srobertotypedef struct dns_adbnamehook dns_adbnamehook_t; 9654359Srobertotypedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t; 9754359Srobertotypedef struct dns_adblameinfo dns_adblameinfo_t; 98285612Sdelphijtypedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t; 99285612Sdelphijtypedef struct dns_adbfetch dns_adbfetch_t; 100285612Sdelphijtypedef struct dns_adbfetch6 dns_adbfetch6_t; 10154359Sroberto 10254359Sroberto/*% dns adb structure */ 103285612Sdelphijstruct dns_adb { 104285612Sdelphij unsigned int magic; 105285612Sdelphij 106285612Sdelphij isc_mutex_t lock; 107285612Sdelphij isc_mutex_t reflock; /*%< Covers irefcnt, erefcnt */ 10854359Sroberto isc_mutex_t overmemlock; /*%< Covers overmem */ 10954359Sroberto isc_mem_t *mctx; 110285612Sdelphij dns_view_t *view; 11154359Sroberto 112285612Sdelphij isc_taskmgr_t *taskmgr; 113285612Sdelphij isc_task_t *task; 114285612Sdelphij isc_task_t *excl; 115285612Sdelphij 116285612Sdelphij isc_interval_t tick_interval; 117285612Sdelphij int next_cleanbucket; 118285612Sdelphij 119285612Sdelphij unsigned int irefcnt; 120285612Sdelphij unsigned int erefcnt; 121285612Sdelphij 122285612Sdelphij isc_mutex_t mplock; 123285612Sdelphij isc_mempool_t *nmp; /*%< dns_adbname_t */ 124285612Sdelphij isc_mempool_t *nhmp; /*%< dns_adbnamehook_t */ 125285612Sdelphij isc_mempool_t *limp; /*%< dns_adblameinfo_t */ 126285612Sdelphij isc_mempool_t *emp; /*%< dns_adbentry_t */ 127285612Sdelphij isc_mempool_t *ahmp; /*%< dns_adbfind_t */ 128285612Sdelphij isc_mempool_t *aimp; /*%< dns_adbaddrinfo_t */ 129285612Sdelphij isc_mempool_t *afmp; /*%< dns_adbfetch_t */ 130285612Sdelphij 131285612Sdelphij /*! 132285612Sdelphij * Bucketized locks and lists for names. 133285612Sdelphij * 13454359Sroberto * XXXRTH Have a per-bucket structure that contains all of these? 13554359Sroberto */ 13654359Sroberto unsigned int nnames; 137285612Sdelphij isc_mutex_t namescntlock; 138285612Sdelphij unsigned int namescnt; 13954359Sroberto dns_adbnamelist_t *names; 140285612Sdelphij dns_adbnamelist_t *deadnames; 141285612Sdelphij isc_mutex_t *namelocks; 142285612Sdelphij isc_boolean_t *name_sd; 143285612Sdelphij unsigned int *name_refcnt; 144285612Sdelphij 145285612Sdelphij /*! 14654359Sroberto * Bucketized locks and lists for entries. 147285612Sdelphij * 148285612Sdelphij * XXXRTH Have a per-bucket structure that contains all of these? 14954359Sroberto */ 150285612Sdelphij unsigned int nentries; 151285612Sdelphij isc_mutex_t entriescntlock; 152285612Sdelphij unsigned int entriescnt; 15354359Sroberto dns_adbentrylist_t *entries; 154285612Sdelphij dns_adbentrylist_t *deadentries; 155285612Sdelphij isc_mutex_t *entrylocks; 156285612Sdelphij isc_boolean_t *entry_sd; /*%< shutting down */ 157285612Sdelphij unsigned int *entry_refcnt; 158285612Sdelphij 159285612Sdelphij isc_event_t cevent; 16054359Sroberto isc_boolean_t cevent_sent; 16154359Sroberto isc_boolean_t shutting_down; 162285612Sdelphij isc_eventlist_t whenshutdown; 163285612Sdelphij isc_event_t growentries; 164285612Sdelphij isc_boolean_t growentries_sent; 165285612Sdelphij isc_event_t grownames; 166285612Sdelphij isc_boolean_t grownames_sent; 167285612Sdelphij}; 168285612Sdelphij 169285612Sdelphij/* 17054359Sroberto * XXXMLG Document these structures. 17154359Sroberto */ 172285612Sdelphij 173285612Sdelphij/*% dns_adbname structure */ 174285612Sdelphijstruct dns_adbname { 175285612Sdelphij unsigned int magic; 176285612Sdelphij dns_name_t name; 177285612Sdelphij dns_adb_t *adb; 178285612Sdelphij unsigned int partial_result; 179285612Sdelphij unsigned int flags; 180285612Sdelphij int lock_bucket; 18154359Sroberto dns_name_t target; 18254359Sroberto isc_stdtime_t expire_target; 183285612Sdelphij isc_stdtime_t expire_v4; 184285612Sdelphij isc_stdtime_t expire_v6; 185285612Sdelphij unsigned int chains; 186285612Sdelphij dns_adbnamehooklist_t v4; 187285612Sdelphij dns_adbnamehooklist_t v6; 188285612Sdelphij dns_adbfetch_t *fetch_a; 189285612Sdelphij dns_adbfetch_t *fetch_aaaa; 190285612Sdelphij unsigned int fetch_err; 191285612Sdelphij unsigned int fetch6_err; 19254359Sroberto dns_adbfindlist_t finds; 193285612Sdelphij /* for LRU-based management */ 194285612Sdelphij isc_stdtime_t last_used; 195285612Sdelphij 196285612Sdelphij ISC_LINK(dns_adbname_t) plink; 197285612Sdelphij}; 198285612Sdelphij 19954359Sroberto/*% The adbfetch structure */ 20054359Srobertostruct dns_adbfetch { 201285612Sdelphij unsigned int magic; 202285612Sdelphij dns_fetch_t *fetch; 203285612Sdelphij dns_rdataset_t rdataset; 204285612Sdelphij}; 205285612Sdelphij 206285612Sdelphij/*% 207285612Sdelphij * This is a small widget that dangles off a dns_adbname_t. It contains a 208285612Sdelphij * pointer to the address information about this host, and a link to the next 20954359Sroberto * namehook that will contain the next address this host has. 21054359Sroberto */ 21154359Srobertostruct dns_adbnamehook { 21254359Sroberto unsigned int magic; 21354359Sroberto dns_adbentry_t *entry; 21454359Sroberto ISC_LINK(dns_adbnamehook_t) plink; 21554359Sroberto}; 21654359Sroberto 21754359Sroberto/*% 21854359Sroberto * This is a small widget that holds qname-specific information about an 21954359Sroberto * address. Currently limited to lameness, but could just as easily be 22054359Sroberto * extended to other types of information about zones. 22154359Sroberto */ 22254359Srobertostruct dns_adblameinfo { 223285612Sdelphij unsigned int magic; 22454359Sroberto 22554359Sroberto dns_name_t qname; 22654359Sroberto dns_rdatatype_t qtype; 22754359Sroberto isc_stdtime_t lame_timer; 22854359Sroberto 22954359Sroberto ISC_LINK(dns_adblameinfo_t) plink; 230285612Sdelphij}; 231285612Sdelphij 232285612Sdelphij/*% 233285612Sdelphij * An address entry. It holds quite a bit of information about addresses, 234285612Sdelphij * including edns state (in "flags"), rtt, and of course the address of 235285612Sdelphij * the host. 236285612Sdelphij */ 237285612Sdelphijstruct dns_adbentry { 238285612Sdelphij unsigned int magic; 239285612Sdelphij 24054359Sroberto int lock_bucket; 24154359Sroberto unsigned int refcnt; 24254359Sroberto 243182007Sroberto unsigned int flags; 244182007Sroberto unsigned int srtt; 24554359Sroberto isc_sockaddr_t sockaddr; 24654359Sroberto 24754359Sroberto isc_stdtime_t expires; 24854359Sroberto /*%< 249285612Sdelphij * A nonzero 'expires' field indicates that the entry should 25054359Sroberto * persist until that time. This allows entries found 251285612Sdelphij * using dns_adb_findaddrinfo() to persist for a limited time 25254359Sroberto * even though they are not necessarily associated with a 25354359Sroberto * name. 254285612Sdelphij */ 255285612Sdelphij 256285612Sdelphij ISC_LIST(dns_adblameinfo_t) lameinfo; 25754359Sroberto ISC_LINK(dns_adbentry_t) plink; 25854359Sroberto 25954359Sroberto}; 26054359Sroberto 26154359Sroberto/* 262285612Sdelphij * Internal functions (and prototypes). 263285612Sdelphij */ 264285612Sdelphijstatic inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *); 265285612Sdelphijstatic inline void free_adbname(dns_adb_t *, dns_adbname_t **); 266285612Sdelphijstatic inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *, 26754359Sroberto dns_adbentry_t *); 26854359Srobertostatic inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **); 26954359Srobertostatic inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *, dns_name_t *, 27054359Sroberto dns_rdatatype_t); 27154359Srobertostatic inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **); 27254359Srobertostatic inline dns_adbentry_t *new_adbentry(dns_adb_t *); 273285612Sdelphijstatic inline void free_adbentry(dns_adb_t *, dns_adbentry_t **); 274285612Sdelphijstatic inline dns_adbfind_t *new_adbfind(dns_adb_t *); 275285612Sdelphijstatic inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **); 27654359Srobertostatic inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *, 27754359Sroberto in_port_t); 27854359Srobertostatic inline dns_adbfetch_t *new_adbfetch(dns_adb_t *); 27954359Srobertostatic inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **); 28054359Srobertostatic inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *, 28154359Sroberto unsigned int, int *); 282285612Sdelphijstatic inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *, 283285612Sdelphij isc_sockaddr_t *, int *, 284285612Sdelphij isc_stdtime_t); 285285612Sdelphijstatic void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t); 28654359Srobertostatic void print_dns_name(FILE *, dns_name_t *); 287285612Sdelphijstatic void print_namehook_list(FILE *, const char *legend, 28854359Sroberto dns_adbnamehooklist_t *list, 28954359Sroberto isc_boolean_t debug, 29054359Sroberto isc_stdtime_t now); 29154359Srobertostatic void print_find_list(FILE *, dns_adbname_t *); 292132451Srobertostatic void print_fetch_list(FILE *, dns_adbname_t *); 29354359Srobertostatic inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *); 29454359Srobertostatic inline void inc_adb_irefcnt(dns_adb_t *); 29554359Srobertostatic inline void inc_adb_erefcnt(dns_adb_t *); 29654359Srobertostatic inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *, 297285612Sdelphij isc_boolean_t); 298285612Sdelphijstatic inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, isc_boolean_t, 29954359Sroberto dns_adbentry_t *, isc_boolean_t); 300285612Sdelphijstatic inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *); 30154359Srobertostatic isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *); 302285612Sdelphijstatic void clean_target(dns_adb_t *, dns_name_t *); 30354359Srobertostatic void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, 30454359Sroberto unsigned int); 30554359Srobertostatic isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t); 30654359Srobertostatic isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **, 30754359Sroberto isc_stdtime_t); 30854359Srobertostatic void cancel_fetches_at_name(dns_adbname_t *); 30954359Srobertostatic isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t, 31054359Sroberto dns_rdatatype_t); 31154359Srobertostatic isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t, 312285612Sdelphij dns_rdatatype_t); 31354359Srobertostatic inline void check_exit(dns_adb_t *); 31454359Srobertostatic void destroy(dns_adb_t *); 31554359Srobertostatic isc_boolean_t shutdown_names(dns_adb_t *); 31654359Srobertostatic isc_boolean_t shutdown_entries(dns_adb_t *); 31754359Srobertostatic inline void link_name(dns_adb_t *, int, dns_adbname_t *); 31854359Srobertostatic inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *); 31954359Srobertostatic inline void link_entry(dns_adb_t *, int, dns_adbentry_t *); 320285612Sdelphijstatic inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *); 32154359Srobertostatic isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t); 32254359Srobertostatic void water(void *, int); 32354359Srobertostatic void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t); 32454359Sroberto 325285612Sdelphij/* 326285612Sdelphij * MUST NOT overlap DNS_ADBFIND_* flags! 327285612Sdelphij */ 328285612Sdelphij#define FIND_EVENT_SENT 0x40000000 329285612Sdelphij#define FIND_EVENT_FREED 0x80000000 33054359Sroberto#define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0) 33154359Sroberto#define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0) 33254359Sroberto 33354359Sroberto#define NAME_NEEDS_POKE 0x80000000 33454359Sroberto#define NAME_IS_DEAD 0x40000000 335285612Sdelphij#define NAME_HINT_OK DNS_ADBFIND_HINTOK 33654359Sroberto#define NAME_GLUE_OK DNS_ADBFIND_GLUEOK 33754359Sroberto#define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE 33854359Sroberto#define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0) 33954359Sroberto#define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0) 34054359Sroberto#define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0) 34154359Sroberto#define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0) 34254359Sroberto 34354359Sroberto/* 34454359Sroberto * Private flag(s) for entries. 34554359Sroberto * MUST NOT overlap FCTX_ADDRINFO_xxx and DNS_FETCHOPT_NOEDNS0. 34654359Sroberto */ 34754359Sroberto#define ENTRY_IS_DEAD 0x80000000 34854359Sroberto 349285612Sdelphij/* 350285612Sdelphij * To the name, address classes are all that really exist. If it has a 35154359Sroberto * V6 address it doesn't care if it came from a AAAA query. 35254359Sroberto */ 353285612Sdelphij#define NAME_HAS_V4(n) (!ISC_LIST_EMPTY((n)->v4)) 354285612Sdelphij#define NAME_HAS_V6(n) (!ISC_LIST_EMPTY((n)->v6)) 35554359Sroberto#define NAME_HAS_ADDRS(n) (NAME_HAS_V4(n) || NAME_HAS_V6(n)) 35654359Sroberto 357285612Sdelphij/* 358285612Sdelphij * Fetches are broken out into A and AAAA types. In some cases, 359285612Sdelphij * however, it makes more sense to test for a particular class of fetches, 360285612Sdelphij * like V4 or V6 above. 36154359Sroberto * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA 36254359Sroberto * are now equal to FETCH_V4 and FETCH_V6, respectively. 363285612Sdelphij */ 36454359Sroberto#define NAME_FETCH_A(n) ((n)->fetch_a != NULL) 365285612Sdelphij#define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL) 366285612Sdelphij#define NAME_FETCH_V4(n) (NAME_FETCH_A(n)) 367285612Sdelphij#define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n)) 368285612Sdelphij#define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n)) 36954359Sroberto 370285612Sdelphij/* 371285612Sdelphij * Find options and tests to see if there are addresses on the list. 372285612Sdelphij */ 37354359Sroberto#define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0) 37454359Sroberto#define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0) 375285612Sdelphij#define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \ 376285612Sdelphij != 0) 377285612Sdelphij#define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \ 37854359Sroberto != 0) 37954359Sroberto#define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0) 380285612Sdelphij#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0) 381285612Sdelphij#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list)) 382285612Sdelphij#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0) 383285612Sdelphij 384285612Sdelphij/* 385285612Sdelphij * These are currently used on simple unsigned ints, so they are 38654359Sroberto * not really associated with any particular type. 38754359Sroberto */ 38854359Sroberto#define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0) 38954359Sroberto#define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0) 39054359Sroberto 39154359Sroberto#define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now)) 392285612Sdelphij 393285612Sdelphij/* 394285612Sdelphij * Find out if the flags on a name (nf) indicate if it is a hint or 395285612Sdelphij * glue, and compare this to the appropriate bits set in o, to see if 39654359Sroberto * this is ok. 39754359Sroberto */ 39854359Sroberto#define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0)) 39954359Sroberto#define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0)) 40054359Sroberto#define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o)) 40154359Sroberto#define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \ 40254359Sroberto ((o) & DNS_ADBFIND_STARTATZONE)) 40354359Sroberto 40454359Sroberto#define ENTER_LEVEL ISC_LOG_DEBUG(50) 405285612Sdelphij#define EXIT_LEVEL ENTER_LEVEL 406285612Sdelphij#define CLEAN_LEVEL ISC_LOG_DEBUG(100) 407285612Sdelphij#define DEF_LEVEL ISC_LOG_DEBUG(5) 408285612Sdelphij#define NCACHE_LEVEL ISC_LOG_DEBUG(20) 409285612Sdelphij 41054359Sroberto#define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \ 41154359Sroberto (r) == DNS_R_NCACHENXRRSET) 412285612Sdelphij#define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \ 413285612Sdelphij (r) == DNS_R_NXRRSET) 414285612Sdelphij#define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \ 415285612Sdelphij (r) == DNS_R_NCACHENXDOMAIN) 41654359Sroberto#define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \ 41754359Sroberto (r) == DNS_R_NXRRSET || \ 41854359Sroberto (r) == DNS_R_HINTNXRRSET) 419285612Sdelphij 420285612Sdelphij/* 421285612Sdelphij * Error state rankings. 422285612Sdelphij */ 42354359Sroberto 42454359Sroberto#define FIND_ERR_SUCCESS 0 /* highest rank */ 42554359Sroberto#define FIND_ERR_CANCELED 1 426285612Sdelphij#define FIND_ERR_FAILURE 2 427285612Sdelphij#define FIND_ERR_NXDOMAIN 3 42854359Sroberto#define FIND_ERR_NXRRSET 4 429285612Sdelphij#define FIND_ERR_UNEXPECTED 5 430285612Sdelphij#define FIND_ERR_NOTFOUND 6 431285612Sdelphij#define FIND_ERR_MAX 7 432285612Sdelphij 433285612Sdelphijstatic const char *errnames[] = { 434285612Sdelphij "success", 435285612Sdelphij "canceled", 43654359Sroberto "failure", 437285612Sdelphij "nxdomain", 438285612Sdelphij "nxrrset", 439285612Sdelphij "unexpected", 440285612Sdelphij "not_found" 441285612Sdelphij}; 442285612Sdelphij 443285612Sdelphij#define NEWERR(old, new) (ISC_MIN((old), (new))) 444285612Sdelphij 445285612Sdelphijstatic isc_result_t find_err_map[FIND_ERR_MAX] = { 446285612Sdelphij ISC_R_SUCCESS, 447285612Sdelphij ISC_R_CANCELED, 448285612Sdelphij ISC_R_FAILURE, 449285612Sdelphij DNS_R_NXDOMAIN, 45054359Sroberto DNS_R_NXRRSET, 45154359Sroberto ISC_R_UNEXPECTED, 452285612Sdelphij ISC_R_NOTFOUND /* not YET found */ 453285612Sdelphij}; 454285612Sdelphij 455285612Sdelphijstatic void 456285612SdelphijDP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3); 457285612Sdelphij 458285612Sdelphijstatic void 45954359SrobertoDP(int level, const char *format, ...) { 46054359Sroberto va_list args; 46154359Sroberto 46254359Sroberto va_start(args, format); 46354359Sroberto isc_log_vwrite(dns_lctx, 46454359Sroberto DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB, 465285612Sdelphij level, format, args); 46654359Sroberto va_end(args); 46754359Sroberto} 46854359Sroberto 46954359Sroberto/*% 47054359Sroberto * Increment resolver-related statistics counters. 47154359Sroberto */ 47254359Srobertostatic inline void 47354359Srobertoinc_stats(dns_adb_t *adb, isc_statscounter_t counter) { 47454359Sroberto if (adb->view->resstats != NULL) 47554359Sroberto isc_stats_increment(adb->view->resstats, counter); 47654359Sroberto} 47754359Sroberto 478285612Sdelphijstatic inline dns_ttl_t 479285612Sdelphijttlclamp(dns_ttl_t ttl) { 48054359Sroberto if (ttl < ADB_CACHE_MINIMUM) 48154359Sroberto ttl = ADB_CACHE_MINIMUM; 48254359Sroberto if (ttl > ADB_CACHE_MAXIMUM) 483285612Sdelphij ttl = ADB_CACHE_MAXIMUM; 48454359Sroberto 48554359Sroberto return (ttl); 48654359Sroberto} 48754359Sroberto 488285612Sdelphij/* 48954359Sroberto * Hashing is most efficient if the number of buckets is prime. 49054359Sroberto * The sequence below is the closest previous primes to 2^n and 491285612Sdelphij * 1.5 * 2^n, for values of n from 10 to 28. (The tables will 49254359Sroberto * no longer grow beyond 2^28 entries.) 49354359Sroberto */ 49454359Srobertostatic const unsigned nbuckets[] = { 1021, 1531, 2039, 3067, 4093, 6143, 495285612Sdelphij 8191, 12281, 16381, 24571, 32749, 496285612Sdelphij 49193, 65521, 98299, 131071, 199603, 49754359Sroberto 262139, 393209, 524287, 768431, 1048573, 49854359Sroberto 1572853, 2097143, 3145721, 4194301, 49954359Sroberto 6291449, 8388593, 12582893, 16777213, 500285612Sdelphij 25165813, 33554393, 50331599, 67108859, 501285612Sdelphij 100663291, 134217689, 201326557, 50254359Sroberto 268535431, 0 }; 503285612Sdelphij 504285612Sdelphijstatic void 505285612Sdelphijgrow_entries(isc_task_t *task, isc_event_t *ev) { 506285612Sdelphij dns_adb_t *adb; 507285612Sdelphij dns_adbentry_t *e; 508285612Sdelphij dns_adbentrylist_t *newdeadentries = NULL; 509285612Sdelphij dns_adbentrylist_t *newentries = NULL; 510285612Sdelphij isc_boolean_t *newentry_sd = NULL; 511285612Sdelphij isc_mutex_t *newentrylocks = NULL; 512285612Sdelphij isc_result_t result; 513285612Sdelphij unsigned int *newentry_refcnt = NULL; 514285612Sdelphij unsigned int i, n, bucket; 515285612Sdelphij 51654359Sroberto adb = ev->ev_arg; 517285612Sdelphij INSIST(DNS_ADB_VALID(adb)); 518285612Sdelphij 519285612Sdelphij isc_event_free(&ev); 520285612Sdelphij 521285612Sdelphij result = isc_task_beginexclusive(task); 522285612Sdelphij if (result != ISC_R_SUCCESS) 523285612Sdelphij goto check_exit; 524285612Sdelphij 525285612Sdelphij i = 0; 52654359Sroberto while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i]) 52754359Sroberto i++; 52854359Sroberto if (nbuckets[i] != 0) 52954359Sroberto n = nbuckets[i]; 53054359Sroberto else 53154359Sroberto goto done; 53254359Sroberto 53354359Sroberto DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n); 534285612Sdelphij 535285612Sdelphij /* 536285612Sdelphij * Are we shutting down? 53754359Sroberto */ 53854359Sroberto for (i = 0; i < adb->nentries; i++) 53954359Sroberto if (adb->entry_sd[i]) 54054359Sroberto goto cleanup; 54154359Sroberto 542285612Sdelphij /* 54354359Sroberto * Grab all the resources we need. 54454359Sroberto */ 54554359Sroberto newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n); 54654359Sroberto newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n); 547285612Sdelphij newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n); 54854359Sroberto newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n); 549285612Sdelphij newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n); 550285612Sdelphij if (newentries == NULL || newdeadentries == NULL || 55154359Sroberto newentrylocks == NULL || newentry_sd == NULL || 55254359Sroberto newentry_refcnt == NULL) 55354359Sroberto goto cleanup; 55454359Sroberto 555285612Sdelphij /* 55654359Sroberto * Initialise the new resources. 55754359Sroberto */ 55854359Sroberto result = isc_mutexblock_init(newentrylocks, n); 559285612Sdelphij if (result != ISC_R_SUCCESS) 56054359Sroberto goto cleanup; 56154359Sroberto 562285612Sdelphij for (i = 0; i < n; i++) { 563285612Sdelphij ISC_LIST_INIT(newentries[i]); 564285612Sdelphij ISC_LIST_INIT(newdeadentries[i]); 56554359Sroberto newentry_sd[i] = ISC_FALSE; 56654359Sroberto newentry_refcnt[i] = 0; 567285612Sdelphij adb->irefcnt++; 56854359Sroberto } 569285612Sdelphij 570182007Sroberto /* 571285612Sdelphij * Move entries to new arrays. 572182007Sroberto */ 573285612Sdelphij for (i = 0; i < adb->nentries; i++) { 574285612Sdelphij e = ISC_LIST_HEAD(adb->entries[i]); 575285612Sdelphij while (e != NULL) { 576285612Sdelphij ISC_LIST_UNLINK(adb->entries[i], e, plink); 577285612Sdelphij bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n; 578285612Sdelphij e->lock_bucket = bucket; 579285612Sdelphij ISC_LIST_APPEND(newentries[bucket], e, plink); 580285612Sdelphij INSIST(adb->entry_refcnt[i] > 0); 581285612Sdelphij adb->entry_refcnt[i]--; 58254359Sroberto newentry_refcnt[bucket]++; 58354359Sroberto e = ISC_LIST_HEAD(adb->entries[i]); 584285612Sdelphij } 58554359Sroberto e = ISC_LIST_HEAD(adb->deadentries[i]); 58654359Sroberto while (e != NULL) { 587285612Sdelphij ISC_LIST_UNLINK(adb->deadentries[i], e, plink); 588285612Sdelphij bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n; 589285612Sdelphij e->lock_bucket = bucket; 590285612Sdelphij ISC_LIST_APPEND(newdeadentries[bucket], e, plink); 591285612Sdelphij INSIST(adb->entry_refcnt[i] > 0); 592285612Sdelphij adb->entry_refcnt[i]--; 593285612Sdelphij newentry_refcnt[bucket]++; 59454359Sroberto e = ISC_LIST_HEAD(adb->deadentries[i]); 59554359Sroberto } 59654359Sroberto INSIST(adb->entry_refcnt[i] == 0); 59754359Sroberto adb->irefcnt--; 598285612Sdelphij } 599285612Sdelphij 600285612Sdelphij /* 601285612Sdelphij * Cleanup old resources. 602285612Sdelphij */ 603285612Sdelphij DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries); 604285612Sdelphij isc_mem_put(adb->mctx, adb->entries, 605285612Sdelphij sizeof(*adb->entries) * adb->nentries); 606285612Sdelphij isc_mem_put(adb->mctx, adb->deadentries, 607285612Sdelphij sizeof(*adb->deadentries) * adb->nentries); 608285612Sdelphij isc_mem_put(adb->mctx, adb->entrylocks, 609285612Sdelphij sizeof(*adb->entrylocks) * adb->nentries); 610285612Sdelphij isc_mem_put(adb->mctx, adb->entry_sd, 611285612Sdelphij sizeof(*adb->entry_sd) * adb->nentries); 612285612Sdelphij isc_mem_put(adb->mctx, adb->entry_refcnt, 613285612Sdelphij sizeof(*adb->entry_refcnt) * adb->nentries); 614285612Sdelphij 615285612Sdelphij /* 616285612Sdelphij * Install new resources. 617285612Sdelphij */ 618285612Sdelphij adb->entries = newentries; 61954359Sroberto adb->deadentries = newdeadentries; 620285612Sdelphij adb->entrylocks = newentrylocks; 62154359Sroberto adb->entry_sd = newentry_sd; 62254359Sroberto adb->entry_refcnt = newentry_refcnt; 623285612Sdelphij adb->nentries = n; 624285612Sdelphij 625285612Sdelphij /* 626285612Sdelphij * Only on success do we set adb->growentries_sent to ISC_FALSE. 627285612Sdelphij * This will prevent us being continuously being called on error. 62854359Sroberto */ 629285612Sdelphij adb->growentries_sent = ISC_FALSE; 630285612Sdelphij goto done; 631285612Sdelphij 632285612Sdelphij cleanup: 633285612Sdelphij if (newentries != NULL) 634285612Sdelphij isc_mem_put(adb->mctx, newentries, 635285612Sdelphij sizeof(*newentries) * n); 636285612Sdelphij if (newdeadentries != NULL) 637285612Sdelphij isc_mem_put(adb->mctx, newdeadentries, 638285612Sdelphij sizeof(*newdeadentries) * n); 639285612Sdelphij if (newentrylocks != NULL) 640285612Sdelphij isc_mem_put(adb->mctx, newentrylocks, 64154359Sroberto sizeof(*newentrylocks) * n); 642285612Sdelphij if (newentry_sd != NULL) 64354359Sroberto isc_mem_put(adb->mctx, newentry_sd, 64454359Sroberto sizeof(*newentry_sd) * n); 645285612Sdelphij if (newentry_refcnt != NULL) 646 isc_mem_put(adb->mctx, newentry_refcnt, 647 sizeof(*newentry_refcnt) * n); 648 done: 649 isc_task_endexclusive(task); 650 651 check_exit: 652 LOCK(&adb->lock); 653 if (dec_adb_irefcnt(adb)) 654 check_exit(adb); 655 UNLOCK(&adb->lock); 656 DP(ISC_LOG_INFO, "adb: grow_entries finished"); 657} 658 659static void 660grow_names(isc_task_t *task, isc_event_t *ev) { 661 dns_adb_t *adb; 662 dns_adbname_t *name; 663 dns_adbnamelist_t *newdeadnames = NULL; 664 dns_adbnamelist_t *newnames = NULL; 665 isc_boolean_t *newname_sd = NULL; 666 isc_mutex_t *newnamelocks = NULL; 667 isc_result_t result; 668 unsigned int *newname_refcnt = NULL; 669 unsigned int i, n, bucket; 670 671 adb = ev->ev_arg; 672 INSIST(DNS_ADB_VALID(adb)); 673 674 isc_event_free(&ev); 675 676 result = isc_task_beginexclusive(task); 677 if (result != ISC_R_SUCCESS) 678 goto check_exit; 679 680 i = 0; 681 while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i]) 682 i++; 683 if (nbuckets[i] != 0) 684 n = nbuckets[i]; 685 else 686 goto done; 687 688 DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n); 689 690 /* 691 * Are we shutting down? 692 */ 693 for (i = 0; i < adb->nnames; i++) 694 if (adb->name_sd[i]) 695 goto cleanup; 696 697 /* 698 * Grab all the resources we need. 699 */ 700 newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n); 701 newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n); 702 newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n); 703 newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n); 704 newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n); 705 if (newnames == NULL || newdeadnames == NULL || 706 newnamelocks == NULL || newname_sd == NULL || 707 newname_refcnt == NULL) 708 goto cleanup; 709 710 /* 711 * Initialise the new resources. 712 */ 713 result = isc_mutexblock_init(newnamelocks, n); 714 if (result != ISC_R_SUCCESS) 715 goto cleanup; 716 717 for (i = 0; i < n; i++) { 718 ISC_LIST_INIT(newnames[i]); 719 ISC_LIST_INIT(newdeadnames[i]); 720 newname_sd[i] = ISC_FALSE; 721 newname_refcnt[i] = 0; 722 adb->irefcnt++; 723 } 724 725 /* 726 * Move names to new arrays. 727 */ 728 for (i = 0; i < adb->nnames; i++) { 729 name = ISC_LIST_HEAD(adb->names[i]); 730 while (name != NULL) { 731 ISC_LIST_UNLINK(adb->names[i], name, plink); 732 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n; 733 name->lock_bucket = bucket; 734 ISC_LIST_APPEND(newnames[bucket], name, plink); 735 INSIST(adb->name_refcnt[i] > 0); 736 adb->name_refcnt[i]--; 737 newname_refcnt[bucket]++; 738 name = ISC_LIST_HEAD(adb->names[i]); 739 } 740 name = ISC_LIST_HEAD(adb->deadnames[i]); 741 while (name != NULL) { 742 ISC_LIST_UNLINK(adb->deadnames[i], name, plink); 743 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n; 744 name->lock_bucket = bucket; 745 ISC_LIST_APPEND(newdeadnames[bucket], name, plink); 746 INSIST(adb->name_refcnt[i] > 0); 747 adb->name_refcnt[i]--; 748 newname_refcnt[bucket]++; 749 name = ISC_LIST_HEAD(adb->deadnames[i]); 750 } 751 INSIST(adb->name_refcnt[i] == 0); 752 adb->irefcnt--; 753 } 754 755 /* 756 * Cleanup old resources. 757 */ 758 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames); 759 isc_mem_put(adb->mctx, adb->names, 760 sizeof(*adb->names) * adb->nnames); 761 isc_mem_put(adb->mctx, adb->deadnames, 762 sizeof(*adb->deadnames) * adb->nnames); 763 isc_mem_put(adb->mctx, adb->namelocks, 764 sizeof(*adb->namelocks) * adb->nnames); 765 isc_mem_put(adb->mctx, adb->name_sd, 766 sizeof(*adb->name_sd) * adb->nnames); 767 isc_mem_put(adb->mctx, adb->name_refcnt, 768 sizeof(*adb->name_refcnt) * adb->nnames); 769 770 /* 771 * Install new resources. 772 */ 773 adb->names = newnames; 774 adb->deadnames = newdeadnames; 775 adb->namelocks = newnamelocks; 776 adb->name_sd = newname_sd; 777 adb->name_refcnt = newname_refcnt; 778 adb->nnames = n; 779 780 /* 781 * Only on success do we set adb->grownames_sent to ISC_FALSE. 782 * This will prevent us being continuously being called on error. 783 */ 784 adb->grownames_sent = ISC_FALSE; 785 goto done; 786 787 cleanup: 788 if (newnames != NULL) 789 isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n); 790 if (newdeadnames != NULL) 791 isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n); 792 if (newnamelocks != NULL) 793 isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n); 794 if (newname_sd != NULL) 795 isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n); 796 if (newname_refcnt != NULL) 797 isc_mem_put(adb->mctx, newname_refcnt, 798 sizeof(*newname_refcnt) * n); 799 done: 800 isc_task_endexclusive(task); 801 802 check_exit: 803 LOCK(&adb->lock); 804 if (dec_adb_irefcnt(adb)) 805 check_exit(adb); 806 UNLOCK(&adb->lock); 807 DP(ISC_LOG_INFO, "adb: grow_names finished"); 808} 809 810/* 811 * Requires the adbname bucket be locked and that no entry buckets be locked. 812 * 813 * This code handles A and AAAA rdatasets only. 814 */ 815static isc_result_t 816import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset, 817 isc_stdtime_t now) 818{ 819 isc_result_t result; 820 dns_adb_t *adb; 821 dns_adbnamehook_t *nh; 822 dns_adbnamehook_t *anh; 823 dns_rdata_t rdata = DNS_RDATA_INIT; 824 struct in_addr ina; 825 struct in6_addr in6a; 826 isc_sockaddr_t sockaddr; 827 dns_adbentry_t *foundentry; /* NO CLEAN UP! */ 828 int addr_bucket; 829 isc_boolean_t new_addresses_added; 830 dns_rdatatype_t rdtype; 831 unsigned int findoptions; 832 dns_adbnamehooklist_t *hookhead; 833 834 INSIST(DNS_ADBNAME_VALID(adbname)); 835 adb = adbname->adb; 836 INSIST(DNS_ADB_VALID(adb)); 837 838 rdtype = rdataset->type; 839 INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa)); 840 if (rdtype == dns_rdatatype_a) 841 findoptions = DNS_ADBFIND_INET; 842 else 843 findoptions = DNS_ADBFIND_INET6; 844 845 addr_bucket = DNS_ADB_INVALIDBUCKET; 846 new_addresses_added = ISC_FALSE; 847 848 nh = NULL; 849 result = dns_rdataset_first(rdataset); 850 while (result == ISC_R_SUCCESS) { 851 dns_rdata_reset(&rdata); 852 dns_rdataset_current(rdataset, &rdata); 853 if (rdtype == dns_rdatatype_a) { 854 INSIST(rdata.length == 4); 855 memmove(&ina.s_addr, rdata.data, 4); 856 isc_sockaddr_fromin(&sockaddr, &ina, 0); 857 hookhead = &adbname->v4; 858 } else { 859 INSIST(rdata.length == 16); 860 memmove(in6a.s6_addr, rdata.data, 16); 861 isc_sockaddr_fromin6(&sockaddr, &in6a, 0); 862 hookhead = &adbname->v6; 863 } 864 865 INSIST(nh == NULL); 866 nh = new_adbnamehook(adb, NULL); 867 if (nh == NULL) { 868 adbname->partial_result |= findoptions; 869 result = ISC_R_NOMEMORY; 870 goto fail; 871 } 872 873 foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket, 874 now); 875 if (foundentry == NULL) { 876 dns_adbentry_t *entry; 877 878 entry = new_adbentry(adb); 879 if (entry == NULL) { 880 adbname->partial_result |= findoptions; 881 result = ISC_R_NOMEMORY; 882 goto fail; 883 } 884 885 entry->sockaddr = sockaddr; 886 entry->refcnt = 1; 887 888 nh->entry = entry; 889 890 link_entry(adb, addr_bucket, entry); 891 } else { 892 for (anh = ISC_LIST_HEAD(*hookhead); 893 anh != NULL; 894 anh = ISC_LIST_NEXT(anh, plink)) 895 if (anh->entry == foundentry) 896 break; 897 if (anh == NULL) { 898 foundentry->refcnt++; 899 nh->entry = foundentry; 900 } else 901 free_adbnamehook(adb, &nh); 902 } 903 904 new_addresses_added = ISC_TRUE; 905 if (nh != NULL) 906 ISC_LIST_APPEND(*hookhead, nh, plink); 907 nh = NULL; 908 result = dns_rdataset_next(rdataset); 909 } 910 911 fail: 912 if (nh != NULL) 913 free_adbnamehook(adb, &nh); 914 915 if (addr_bucket != DNS_ADB_INVALIDBUCKET) 916 UNLOCK(&adb->entrylocks[addr_bucket]); 917 918 if (rdataset->trust == dns_trust_glue || 919 rdataset->trust == dns_trust_additional) 920 rdataset->ttl = ADB_CACHE_MINIMUM; 921 else if (rdataset->trust == dns_trust_ultimate) 922 rdataset->ttl = 0; 923 else 924 rdataset->ttl = ttlclamp(rdataset->ttl); 925 926 if (rdtype == dns_rdatatype_a) { 927 DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset", 928 adbname->expire_v4, now + rdataset->ttl); 929 adbname->expire_v4 = ISC_MIN(adbname->expire_v4, 930 now + rdataset->ttl); 931 } else { 932 DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset", 933 adbname->expire_v6, now + rdataset->ttl); 934 adbname->expire_v6 = ISC_MIN(adbname->expire_v6, 935 now + rdataset->ttl); 936 } 937 938 if (new_addresses_added) { 939 /* 940 * Lie a little here. This is more or less so code that cares 941 * can find out if any new information was added or not. 942 */ 943 return (ISC_R_SUCCESS); 944 } 945 946 return (result); 947} 948 949/* 950 * Requires the name's bucket be locked. 951 */ 952static isc_boolean_t 953kill_name(dns_adbname_t **n, isc_eventtype_t ev) { 954 dns_adbname_t *name; 955 isc_boolean_t result = ISC_FALSE; 956 isc_boolean_t result4, result6; 957 int bucket; 958 dns_adb_t *adb; 959 960 INSIST(n != NULL); 961 name = *n; 962 *n = NULL; 963 INSIST(DNS_ADBNAME_VALID(name)); 964 adb = name->adb; 965 INSIST(DNS_ADB_VALID(adb)); 966 967 DP(DEF_LEVEL, "killing name %p", name); 968 969 /* 970 * If we're dead already, just check to see if we should go 971 * away now or not. 972 */ 973 if (NAME_DEAD(name) && !NAME_FETCH(name)) { 974 result = unlink_name(adb, name); 975 free_adbname(adb, &name); 976 if (result) 977 result = dec_adb_irefcnt(adb); 978 return (result); 979 } 980 981 /* 982 * Clean up the name's various lists. These two are destructive 983 * in that they will always empty the list. 984 */ 985 clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK); 986 result4 = clean_namehooks(adb, &name->v4); 987 result6 = clean_namehooks(adb, &name->v6); 988 clean_target(adb, &name->target); 989 result = ISC_TF(result4 || result6); 990 991 /* 992 * If fetches are running, cancel them. If none are running, we can 993 * just kill the name here. 994 */ 995 if (!NAME_FETCH(name)) { 996 INSIST(result == ISC_FALSE); 997 result = unlink_name(adb, name); 998 free_adbname(adb, &name); 999 if (result) 1000 result = dec_adb_irefcnt(adb); 1001 } else { 1002 cancel_fetches_at_name(name); 1003 if (!NAME_DEAD(name)) { 1004 bucket = name->lock_bucket; 1005 ISC_LIST_UNLINK(adb->names[bucket], name, plink); 1006 ISC_LIST_APPEND(adb->deadnames[bucket], name, plink); 1007 name->flags |= NAME_IS_DEAD; 1008 } 1009 } 1010 return (result); 1011} 1012 1013/* 1014 * Requires the name's bucket be locked and no entry buckets be locked. 1015 */ 1016static isc_boolean_t 1017check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) { 1018 dns_adb_t *adb; 1019 isc_boolean_t result4 = ISC_FALSE; 1020 isc_boolean_t result6 = ISC_FALSE; 1021 1022 INSIST(DNS_ADBNAME_VALID(name)); 1023 adb = name->adb; 1024 INSIST(DNS_ADB_VALID(adb)); 1025 1026 /* 1027 * Check to see if we need to remove the v4 addresses 1028 */ 1029 if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) { 1030 if (NAME_HAS_V4(name)) { 1031 DP(DEF_LEVEL, "expiring v4 for name %p", name); 1032 result4 = clean_namehooks(adb, &name->v4); 1033 name->partial_result &= ~DNS_ADBFIND_INET; 1034 } 1035 name->expire_v4 = INT_MAX; 1036 name->fetch_err = FIND_ERR_UNEXPECTED; 1037 } 1038 1039 /* 1040 * Check to see if we need to remove the v6 addresses 1041 */ 1042 if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) { 1043 if (NAME_HAS_V6(name)) { 1044 DP(DEF_LEVEL, "expiring v6 for name %p", name); 1045 result6 = clean_namehooks(adb, &name->v6); 1046 name->partial_result &= ~DNS_ADBFIND_INET6; 1047 } 1048 name->expire_v6 = INT_MAX; 1049 name->fetch6_err = FIND_ERR_UNEXPECTED; 1050 } 1051 1052 /* 1053 * Check to see if we need to remove the alias target. 1054 */ 1055 if (EXPIRE_OK(name->expire_target, now)) { 1056 clean_target(adb, &name->target); 1057 name->expire_target = INT_MAX; 1058 } 1059 return (ISC_TF(result4 || result6)); 1060} 1061 1062/* 1063 * Requires the name's bucket be locked. 1064 */ 1065static inline void 1066link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) { 1067 INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET); 1068 1069 ISC_LIST_PREPEND(adb->names[bucket], name, plink); 1070 name->lock_bucket = bucket; 1071 adb->name_refcnt[bucket]++; 1072} 1073 1074/* 1075 * Requires the name's bucket be locked. 1076 */ 1077static inline isc_boolean_t 1078unlink_name(dns_adb_t *adb, dns_adbname_t *name) { 1079 int bucket; 1080 isc_boolean_t result = ISC_FALSE; 1081 1082 bucket = name->lock_bucket; 1083 INSIST(bucket != DNS_ADB_INVALIDBUCKET); 1084 1085 if (NAME_DEAD(name)) 1086 ISC_LIST_UNLINK(adb->deadnames[bucket], name, plink); 1087 else 1088 ISC_LIST_UNLINK(adb->names[bucket], name, plink); 1089 name->lock_bucket = DNS_ADB_INVALIDBUCKET; 1090 INSIST(adb->name_refcnt[bucket] > 0); 1091 adb->name_refcnt[bucket]--; 1092 if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0) 1093 result = ISC_TRUE; 1094 return (result); 1095} 1096 1097/* 1098 * Requires the entry's bucket be locked. 1099 */ 1100static inline void 1101link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) { 1102 int i; 1103 dns_adbentry_t *e; 1104 1105 if (isc_mem_isovermem(adb->mctx)) { 1106 for (i = 0; i < 2; i++) { 1107 e = ISC_LIST_TAIL(adb->entries[bucket]); 1108 if (e == NULL) 1109 break; 1110 if (e->refcnt == 0) { 1111 unlink_entry(adb, e); 1112 free_adbentry(adb, &e); 1113 continue; 1114 } 1115 INSIST((e->flags & ENTRY_IS_DEAD) == 0); 1116 e->flags |= ENTRY_IS_DEAD; 1117 ISC_LIST_UNLINK(adb->entries[bucket], e, plink); 1118 ISC_LIST_PREPEND(adb->deadentries[bucket], e, plink); 1119 } 1120 } 1121 1122 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink); 1123 entry->lock_bucket = bucket; 1124 adb->entry_refcnt[bucket]++; 1125} 1126 1127/* 1128 * Requires the entry's bucket be locked. 1129 */ 1130static inline isc_boolean_t 1131unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) { 1132 int bucket; 1133 isc_boolean_t result = ISC_FALSE; 1134 1135 bucket = entry->lock_bucket; 1136 INSIST(bucket != DNS_ADB_INVALIDBUCKET); 1137 1138 if ((entry->flags & ENTRY_IS_DEAD) != 0) 1139 ISC_LIST_UNLINK(adb->deadentries[bucket], entry, plink); 1140 else 1141 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink); 1142 entry->lock_bucket = DNS_ADB_INVALIDBUCKET; 1143 INSIST(adb->entry_refcnt[bucket] > 0); 1144 adb->entry_refcnt[bucket]--; 1145 if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0) 1146 result = ISC_TRUE; 1147 return (result); 1148} 1149 1150static inline void 1151violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) { 1152 if (isc_mutex_trylock(want) != ISC_R_SUCCESS) { 1153 UNLOCK(have); 1154 LOCK(want); 1155 LOCK(have); 1156 } 1157} 1158 1159/* 1160 * The ADB _MUST_ be locked before calling. Also, exit conditions must be 1161 * checked after calling this function. 1162 */ 1163static isc_boolean_t 1164shutdown_names(dns_adb_t *adb) { 1165 unsigned int bucket; 1166 isc_boolean_t result = ISC_FALSE; 1167 dns_adbname_t *name; 1168 dns_adbname_t *next_name; 1169 1170 for (bucket = 0; bucket < adb->nnames; bucket++) { 1171 LOCK(&adb->namelocks[bucket]); 1172 adb->name_sd[bucket] = ISC_TRUE; 1173 1174 name = ISC_LIST_HEAD(adb->names[bucket]); 1175 if (name == NULL) { 1176 /* 1177 * This bucket has no names. We must decrement the 1178 * irefcnt ourselves, since it will not be 1179 * automatically triggered by a name being unlinked. 1180 */ 1181 INSIST(result == ISC_FALSE); 1182 result = dec_adb_irefcnt(adb); 1183 } else { 1184 /* 1185 * Run through the list. For each name, clean up finds 1186 * found there, and cancel any fetches running. When 1187 * all the fetches are canceled, the name will destroy 1188 * itself. 1189 */ 1190 while (name != NULL) { 1191 next_name = ISC_LIST_NEXT(name, plink); 1192 INSIST(result == ISC_FALSE); 1193 result = kill_name(&name, 1194 DNS_EVENT_ADBSHUTDOWN); 1195 name = next_name; 1196 } 1197 } 1198 1199 UNLOCK(&adb->namelocks[bucket]); 1200 } 1201 return (result); 1202} 1203 1204/* 1205 * The ADB _MUST_ be locked before calling. Also, exit conditions must be 1206 * checked after calling this function. 1207 */ 1208static isc_boolean_t 1209shutdown_entries(dns_adb_t *adb) { 1210 unsigned int bucket; 1211 isc_boolean_t result = ISC_FALSE; 1212 dns_adbentry_t *entry; 1213 dns_adbentry_t *next_entry; 1214 1215 for (bucket = 0; bucket < adb->nentries; bucket++) { 1216 LOCK(&adb->entrylocks[bucket]); 1217 adb->entry_sd[bucket] = ISC_TRUE; 1218 1219 entry = ISC_LIST_HEAD(adb->entries[bucket]); 1220 if (adb->entry_refcnt[bucket] == 0) { 1221 /* 1222 * This bucket has no entries. We must decrement the 1223 * irefcnt ourselves, since it will not be 1224 * automatically triggered by an entry being unlinked. 1225 */ 1226 result = dec_adb_irefcnt(adb); 1227 } else { 1228 /* 1229 * Run through the list. Cleanup any entries not 1230 * associated with names, and which are not in use. 1231 */ 1232 while (entry != NULL) { 1233 next_entry = ISC_LIST_NEXT(entry, plink); 1234 if (entry->refcnt == 0 && 1235 entry->expires != 0) { 1236 result = unlink_entry(adb, entry); 1237 free_adbentry(adb, &entry); 1238 if (result) 1239 result = dec_adb_irefcnt(adb); 1240 } 1241 entry = next_entry; 1242 } 1243 } 1244 1245 UNLOCK(&adb->entrylocks[bucket]); 1246 } 1247 return (result); 1248} 1249 1250/* 1251 * Name bucket must be locked 1252 */ 1253static void 1254cancel_fetches_at_name(dns_adbname_t *name) { 1255 if (NAME_FETCH_A(name)) 1256 dns_resolver_cancelfetch(name->fetch_a->fetch); 1257 1258 if (NAME_FETCH_AAAA(name)) 1259 dns_resolver_cancelfetch(name->fetch_aaaa->fetch); 1260} 1261 1262/* 1263 * Assumes the name bucket is locked. 1264 */ 1265static isc_boolean_t 1266clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) { 1267 dns_adbentry_t *entry; 1268 dns_adbnamehook_t *namehook; 1269 int addr_bucket; 1270 isc_boolean_t result = ISC_FALSE; 1271 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx); 1272 1273 addr_bucket = DNS_ADB_INVALIDBUCKET; 1274 namehook = ISC_LIST_HEAD(*namehooks); 1275 while (namehook != NULL) { 1276 INSIST(DNS_ADBNAMEHOOK_VALID(namehook)); 1277 1278 /* 1279 * Clean up the entry if needed. 1280 */ 1281 entry = namehook->entry; 1282 if (entry != NULL) { 1283 INSIST(DNS_ADBENTRY_VALID(entry)); 1284 1285 if (addr_bucket != entry->lock_bucket) { 1286 if (addr_bucket != DNS_ADB_INVALIDBUCKET) 1287 UNLOCK(&adb->entrylocks[addr_bucket]); 1288 addr_bucket = entry->lock_bucket; 1289 INSIST(addr_bucket != DNS_ADB_INVALIDBUCKET); 1290 LOCK(&adb->entrylocks[addr_bucket]); 1291 } 1292 1293 result = dec_entry_refcnt(adb, overmem, entry, 1294 ISC_FALSE); 1295 } 1296 1297 /* 1298 * Free the namehook 1299 */ 1300 namehook->entry = NULL; 1301 ISC_LIST_UNLINK(*namehooks, namehook, plink); 1302 free_adbnamehook(adb, &namehook); 1303 1304 namehook = ISC_LIST_HEAD(*namehooks); 1305 } 1306 1307 if (addr_bucket != DNS_ADB_INVALIDBUCKET) 1308 UNLOCK(&adb->entrylocks[addr_bucket]); 1309 return (result); 1310} 1311 1312static void 1313clean_target(dns_adb_t *adb, dns_name_t *target) { 1314 if (dns_name_countlabels(target) > 0) { 1315 dns_name_free(target, adb->mctx); 1316 dns_name_init(target, NULL); 1317 } 1318} 1319 1320static isc_result_t 1321set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname, 1322 dns_rdataset_t *rdataset, dns_name_t *target) 1323{ 1324 isc_result_t result; 1325 dns_namereln_t namereln; 1326 unsigned int nlabels; 1327 int order; 1328 dns_rdata_t rdata = DNS_RDATA_INIT; 1329 dns_fixedname_t fixed1, fixed2; 1330 dns_name_t *prefix, *new_target; 1331 1332 REQUIRE(dns_name_countlabels(target) == 0); 1333 1334 if (rdataset->type == dns_rdatatype_cname) { 1335 dns_rdata_cname_t cname; 1336 1337 /* 1338 * Copy the CNAME's target into the target name. 1339 */ 1340 result = dns_rdataset_first(rdataset); 1341 if (result != ISC_R_SUCCESS) 1342 return (result); 1343 dns_rdataset_current(rdataset, &rdata); 1344 result = dns_rdata_tostruct(&rdata, &cname, NULL); 1345 if (result != ISC_R_SUCCESS) 1346 return (result); 1347 result = dns_name_dup(&cname.cname, adb->mctx, target); 1348 dns_rdata_freestruct(&cname); 1349 if (result != ISC_R_SUCCESS) 1350 return (result); 1351 } else { 1352 dns_rdata_dname_t dname; 1353 1354 INSIST(rdataset->type == dns_rdatatype_dname); 1355 namereln = dns_name_fullcompare(name, fname, &order, &nlabels); 1356 INSIST(namereln == dns_namereln_subdomain); 1357 /* 1358 * Get the target name of the DNAME. 1359 */ 1360 result = dns_rdataset_first(rdataset); 1361 if (result != ISC_R_SUCCESS) 1362 return (result); 1363 dns_rdataset_current(rdataset, &rdata); 1364 result = dns_rdata_tostruct(&rdata, &dname, NULL); 1365 if (result != ISC_R_SUCCESS) 1366 return (result); 1367 /* 1368 * Construct the new target name. 1369 */ 1370 dns_fixedname_init(&fixed1); 1371 prefix = dns_fixedname_name(&fixed1); 1372 dns_fixedname_init(&fixed2); 1373 new_target = dns_fixedname_name(&fixed2); 1374 dns_name_split(name, nlabels, prefix, NULL); 1375 result = dns_name_concatenate(prefix, &dname.dname, new_target, 1376 NULL); 1377 dns_rdata_freestruct(&dname); 1378 if (result != ISC_R_SUCCESS) 1379 return (result); 1380 result = dns_name_dup(new_target, adb->mctx, target); 1381 if (result != ISC_R_SUCCESS) 1382 return (result); 1383 } 1384 1385 return (ISC_R_SUCCESS); 1386} 1387 1388/* 1389 * Assumes nothing is locked, since this is called by the client. 1390 */ 1391static void 1392event_free(isc_event_t *event) { 1393 dns_adbfind_t *find; 1394 1395 INSIST(event != NULL); 1396 find = event->ev_destroy_arg; 1397 INSIST(DNS_ADBFIND_VALID(find)); 1398 1399 LOCK(&find->lock); 1400 find->flags |= FIND_EVENT_FREED; 1401 event->ev_destroy_arg = NULL; 1402 UNLOCK(&find->lock); 1403} 1404 1405/* 1406 * Assumes the name bucket is locked. 1407 */ 1408static void 1409clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype, 1410 unsigned int addrs) 1411{ 1412 isc_event_t *ev; 1413 isc_task_t *task; 1414 dns_adbfind_t *find; 1415 dns_adbfind_t *next_find; 1416 isc_boolean_t process; 1417 unsigned int wanted, notify; 1418 1419 DP(ENTER_LEVEL, 1420 "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x", 1421 name, evtype, addrs); 1422 1423 find = ISC_LIST_HEAD(name->finds); 1424 while (find != NULL) { 1425 LOCK(&find->lock); 1426 next_find = ISC_LIST_NEXT(find, plink); 1427 1428 process = ISC_FALSE; 1429 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK; 1430 notify = wanted & addrs; 1431 1432 switch (evtype) { 1433 case DNS_EVENT_ADBMOREADDRESSES: 1434 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES"); 1435 if ((notify) != 0) { 1436 find->flags &= ~addrs; 1437 process = ISC_TRUE; 1438 } 1439 break; 1440 case DNS_EVENT_ADBNOMOREADDRESSES: 1441 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES"); 1442 find->flags &= ~addrs; 1443 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK; 1444 if (wanted == 0) 1445 process = ISC_TRUE; 1446 break; 1447 default: 1448 find->flags &= ~addrs; 1449 process = ISC_TRUE; 1450 } 1451 1452 if (process) { 1453 DP(DEF_LEVEL, "cfan: processing find %p", find); 1454 /* 1455 * Unlink the find from the name, letting the caller 1456 * call dns_adb_destroyfind() on it to clean it up 1457 * later. 1458 */ 1459 ISC_LIST_UNLINK(name->finds, find, plink); 1460 find->adbname = NULL; 1461 find->name_bucket = DNS_ADB_INVALIDBUCKET; 1462 1463 INSIST(!FIND_EVENTSENT(find)); 1464 1465 ev = &find->event; 1466 task = ev->ev_sender; 1467 ev->ev_sender = find; 1468 find->result_v4 = find_err_map[name->fetch_err]; 1469 find->result_v6 = find_err_map[name->fetch6_err]; 1470 ev->ev_type = evtype; 1471 ev->ev_destroy = event_free; 1472 ev->ev_destroy_arg = find; 1473 1474 DP(DEF_LEVEL, 1475 "sending event %p to task %p for find %p", 1476 ev, task, find); 1477 1478 isc_task_sendanddetach(&task, (isc_event_t **)&ev); 1479 } else { 1480 DP(DEF_LEVEL, "cfan: skipping find %p", find); 1481 } 1482 1483 UNLOCK(&find->lock); 1484 find = next_find; 1485 } 1486 1487 DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name); 1488} 1489 1490static inline void 1491check_exit(dns_adb_t *adb) { 1492 isc_event_t *event; 1493 /* 1494 * The caller must be holding the adb lock. 1495 */ 1496 if (adb->shutting_down) { 1497 /* 1498 * If there aren't any external references either, we're 1499 * done. Send the control event to initiate shutdown. 1500 */ 1501 INSIST(!adb->cevent_sent); /* Sanity check. */ 1502 event = &adb->cevent; 1503 isc_task_send(adb->task, &event); 1504 adb->cevent_sent = ISC_TRUE; 1505 } 1506} 1507 1508static inline isc_boolean_t 1509dec_adb_irefcnt(dns_adb_t *adb) { 1510 isc_event_t *event; 1511 isc_task_t *etask; 1512 isc_boolean_t result = ISC_FALSE; 1513 1514 LOCK(&adb->reflock); 1515 1516 INSIST(adb->irefcnt > 0); 1517 adb->irefcnt--; 1518 1519 if (adb->irefcnt == 0) { 1520 event = ISC_LIST_HEAD(adb->whenshutdown); 1521 while (event != NULL) { 1522 ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link); 1523 etask = event->ev_sender; 1524 event->ev_sender = adb; 1525 isc_task_sendanddetach(&etask, &event); 1526 event = ISC_LIST_HEAD(adb->whenshutdown); 1527 } 1528 } 1529 1530 if (adb->irefcnt == 0 && adb->erefcnt == 0) 1531 result = ISC_TRUE; 1532 UNLOCK(&adb->reflock); 1533 return (result); 1534} 1535 1536static inline void 1537inc_adb_irefcnt(dns_adb_t *adb) { 1538 LOCK(&adb->reflock); 1539 adb->irefcnt++; 1540 UNLOCK(&adb->reflock); 1541} 1542 1543static inline void 1544inc_adb_erefcnt(dns_adb_t *adb) { 1545 LOCK(&adb->reflock); 1546 adb->erefcnt++; 1547 UNLOCK(&adb->reflock); 1548} 1549 1550static inline void 1551inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) { 1552 int bucket; 1553 1554 bucket = entry->lock_bucket; 1555 1556 if (lock) 1557 LOCK(&adb->entrylocks[bucket]); 1558 1559 entry->refcnt++; 1560 1561 if (lock) 1562 UNLOCK(&adb->entrylocks[bucket]); 1563} 1564 1565static inline isc_boolean_t 1566dec_entry_refcnt(dns_adb_t *adb, isc_boolean_t overmem, dns_adbentry_t *entry, 1567 isc_boolean_t lock) 1568{ 1569 int bucket; 1570 isc_boolean_t destroy_entry; 1571 isc_boolean_t result = ISC_FALSE; 1572 1573 bucket = entry->lock_bucket; 1574 1575 if (lock) 1576 LOCK(&adb->entrylocks[bucket]); 1577 1578 INSIST(entry->refcnt > 0); 1579 entry->refcnt--; 1580 1581 destroy_entry = ISC_FALSE; 1582 if (entry->refcnt == 0 && 1583 (adb->entry_sd[bucket] || entry->expires == 0 || overmem || 1584 (entry->flags & ENTRY_IS_DEAD) != 0)) { 1585 destroy_entry = ISC_TRUE; 1586 result = unlink_entry(adb, entry); 1587 } 1588 1589 if (lock) 1590 UNLOCK(&adb->entrylocks[bucket]); 1591 1592 if (!destroy_entry) 1593 return (result); 1594 1595 entry->lock_bucket = DNS_ADB_INVALIDBUCKET; 1596 1597 free_adbentry(adb, &entry); 1598 if (result) 1599 result = dec_adb_irefcnt(adb); 1600 1601 return (result); 1602} 1603 1604static inline dns_adbname_t * 1605new_adbname(dns_adb_t *adb, dns_name_t *dnsname) { 1606 dns_adbname_t *name; 1607 1608 name = isc_mempool_get(adb->nmp); 1609 if (name == NULL) 1610 return (NULL); 1611 1612 dns_name_init(&name->name, NULL); 1613 if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) { 1614 isc_mempool_put(adb->nmp, name); 1615 return (NULL); 1616 } 1617 dns_name_init(&name->target, NULL); 1618 name->magic = DNS_ADBNAME_MAGIC; 1619 name->adb = adb; 1620 name->partial_result = 0; 1621 name->flags = 0; 1622 name->expire_v4 = INT_MAX; 1623 name->expire_v6 = INT_MAX; 1624 name->expire_target = INT_MAX; 1625 name->chains = 0; 1626 name->lock_bucket = DNS_ADB_INVALIDBUCKET; 1627 ISC_LIST_INIT(name->v4); 1628 ISC_LIST_INIT(name->v6); 1629 name->fetch_a = NULL; 1630 name->fetch_aaaa = NULL; 1631 name->fetch_err = FIND_ERR_UNEXPECTED; 1632 name->fetch6_err = FIND_ERR_UNEXPECTED; 1633 ISC_LIST_INIT(name->finds); 1634 ISC_LINK_INIT(name, plink); 1635 1636 LOCK(&adb->namescntlock); 1637 adb->namescnt++; 1638 if (!adb->grownames_sent && adb->excl != NULL && 1639 adb->namescnt > (adb->nnames * 8)) 1640 { 1641 isc_event_t *event = &adb->grownames; 1642 inc_adb_irefcnt(adb); 1643 isc_task_send(adb->excl, &event); 1644 adb->grownames_sent = ISC_TRUE; 1645 } 1646 UNLOCK(&adb->namescntlock); 1647 1648 return (name); 1649} 1650 1651static inline void 1652free_adbname(dns_adb_t *adb, dns_adbname_t **name) { 1653 dns_adbname_t *n; 1654 1655 INSIST(name != NULL && DNS_ADBNAME_VALID(*name)); 1656 n = *name; 1657 *name = NULL; 1658 1659 INSIST(!NAME_HAS_V4(n)); 1660 INSIST(!NAME_HAS_V6(n)); 1661 INSIST(!NAME_FETCH(n)); 1662 INSIST(ISC_LIST_EMPTY(n->finds)); 1663 INSIST(!ISC_LINK_LINKED(n, plink)); 1664 INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET); 1665 INSIST(n->adb == adb); 1666 1667 n->magic = 0; 1668 dns_name_free(&n->name, adb->mctx); 1669 1670 isc_mempool_put(adb->nmp, n); 1671 LOCK(&adb->namescntlock); 1672 adb->namescnt--; 1673 UNLOCK(&adb->namescntlock); 1674} 1675 1676static inline dns_adbnamehook_t * 1677new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) { 1678 dns_adbnamehook_t *nh; 1679 1680 nh = isc_mempool_get(adb->nhmp); 1681 if (nh == NULL) 1682 return (NULL); 1683 1684 nh->magic = DNS_ADBNAMEHOOK_MAGIC; 1685 nh->entry = entry; 1686 ISC_LINK_INIT(nh, plink); 1687 1688 return (nh); 1689} 1690 1691static inline void 1692free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) { 1693 dns_adbnamehook_t *nh; 1694 1695 INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook)); 1696 nh = *namehook; 1697 *namehook = NULL; 1698 1699 INSIST(nh->entry == NULL); 1700 INSIST(!ISC_LINK_LINKED(nh, plink)); 1701 1702 nh->magic = 0; 1703 isc_mempool_put(adb->nhmp, nh); 1704} 1705 1706static inline dns_adblameinfo_t * 1707new_adblameinfo(dns_adb_t *adb, dns_name_t *qname, dns_rdatatype_t qtype) { 1708 dns_adblameinfo_t *li; 1709 1710 li = isc_mempool_get(adb->limp); 1711 if (li == NULL) 1712 return (NULL); 1713 1714 dns_name_init(&li->qname, NULL); 1715 if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) { 1716 isc_mempool_put(adb->limp, li); 1717 return (NULL); 1718 } 1719 li->magic = DNS_ADBLAMEINFO_MAGIC; 1720 li->lame_timer = 0; 1721 li->qtype = qtype; 1722 ISC_LINK_INIT(li, plink); 1723 1724 return (li); 1725} 1726 1727static inline void 1728free_adblameinfo(dns_adb_t *adb, dns_adblameinfo_t **lameinfo) { 1729 dns_adblameinfo_t *li; 1730 1731 INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo)); 1732 li = *lameinfo; 1733 *lameinfo = NULL; 1734 1735 INSIST(!ISC_LINK_LINKED(li, plink)); 1736 1737 dns_name_free(&li->qname, adb->mctx); 1738 1739 li->magic = 0; 1740 1741 isc_mempool_put(adb->limp, li); 1742} 1743 1744static inline dns_adbentry_t * 1745new_adbentry(dns_adb_t *adb) { 1746 dns_adbentry_t *e; 1747 isc_uint32_t r; 1748 1749 e = isc_mempool_get(adb->emp); 1750 if (e == NULL) 1751 return (NULL); 1752 1753 e->magic = DNS_ADBENTRY_MAGIC; 1754 e->lock_bucket = DNS_ADB_INVALIDBUCKET; 1755 e->refcnt = 0; 1756 e->flags = 0; 1757 isc_random_get(&r); 1758 e->srtt = (r & 0x1f) + 1; 1759 e->expires = 0; 1760 ISC_LIST_INIT(e->lameinfo); 1761 ISC_LINK_INIT(e, plink); 1762 LOCK(&adb->entriescntlock); 1763 adb->entriescnt++; 1764 if (!adb->growentries_sent && adb->growentries_sent && 1765 adb->entriescnt > (adb->nentries * 8)) 1766 { 1767 isc_event_t *event = &adb->growentries; 1768 inc_adb_irefcnt(adb); 1769 isc_task_send(adb->task, &event); 1770 adb->growentries_sent = ISC_TRUE; 1771 } 1772 UNLOCK(&adb->entriescntlock); 1773 1774 return (e); 1775} 1776 1777static inline void 1778free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) { 1779 dns_adbentry_t *e; 1780 dns_adblameinfo_t *li; 1781 1782 INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry)); 1783 e = *entry; 1784 *entry = NULL; 1785 1786 INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET); 1787 INSIST(e->refcnt == 0); 1788 INSIST(!ISC_LINK_LINKED(e, plink)); 1789 1790 e->magic = 0; 1791 1792 li = ISC_LIST_HEAD(e->lameinfo); 1793 while (li != NULL) { 1794 ISC_LIST_UNLINK(e->lameinfo, li, plink); 1795 free_adblameinfo(adb, &li); 1796 li = ISC_LIST_HEAD(e->lameinfo); 1797 } 1798 1799 isc_mempool_put(adb->emp, e); 1800 LOCK(&adb->entriescntlock); 1801 adb->entriescnt--; 1802 UNLOCK(&adb->entriescntlock); 1803} 1804 1805static inline dns_adbfind_t * 1806new_adbfind(dns_adb_t *adb) { 1807 dns_adbfind_t *h; 1808 isc_result_t result; 1809 1810 h = isc_mempool_get(adb->ahmp); 1811 if (h == NULL) 1812 return (NULL); 1813 1814 /* 1815 * Public members. 1816 */ 1817 h->magic = 0; 1818 h->adb = adb; 1819 h->partial_result = 0; 1820 h->options = 0; 1821 h->flags = 0; 1822 h->result_v4 = ISC_R_UNEXPECTED; 1823 h->result_v6 = ISC_R_UNEXPECTED; 1824 ISC_LINK_INIT(h, publink); 1825 ISC_LINK_INIT(h, plink); 1826 ISC_LIST_INIT(h->list); 1827 h->adbname = NULL; 1828 h->name_bucket = DNS_ADB_INVALIDBUCKET; 1829 1830 /* 1831 * private members 1832 */ 1833 result = isc_mutex_init(&h->lock); 1834 if (result != ISC_R_SUCCESS) { 1835 isc_mempool_put(adb->ahmp, h); 1836 return (NULL); 1837 } 1838 1839 ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL, 1840 NULL, NULL, h); 1841 1842 inc_adb_irefcnt(adb); 1843 h->magic = DNS_ADBFIND_MAGIC; 1844 return (h); 1845} 1846 1847static inline dns_adbfetch_t * 1848new_adbfetch(dns_adb_t *adb) { 1849 dns_adbfetch_t *f; 1850 1851 f = isc_mempool_get(adb->afmp); 1852 if (f == NULL) 1853 return (NULL); 1854 1855 f->magic = 0; 1856 f->fetch = NULL; 1857 1858 dns_rdataset_init(&f->rdataset); 1859 1860 f->magic = DNS_ADBFETCH_MAGIC; 1861 1862 return (f); 1863} 1864 1865static inline void 1866free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) { 1867 dns_adbfetch_t *f; 1868 1869 INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch)); 1870 f = *fetch; 1871 *fetch = NULL; 1872 1873 f->magic = 0; 1874 1875 if (dns_rdataset_isassociated(&f->rdataset)) 1876 dns_rdataset_disassociate(&f->rdataset); 1877 1878 isc_mempool_put(adb->afmp, f); 1879} 1880 1881static inline isc_boolean_t 1882free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) { 1883 dns_adbfind_t *find; 1884 1885 INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp)); 1886 find = *findp; 1887 *findp = NULL; 1888 1889 INSIST(!FIND_HAS_ADDRS(find)); 1890 INSIST(!ISC_LINK_LINKED(find, publink)); 1891 INSIST(!ISC_LINK_LINKED(find, plink)); 1892 INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET); 1893 INSIST(find->adbname == NULL); 1894 1895 find->magic = 0; 1896 1897 DESTROYLOCK(&find->lock); 1898 isc_mempool_put(adb->ahmp, find); 1899 return (dec_adb_irefcnt(adb)); 1900} 1901 1902/* 1903 * Copy bits from the entry into the newly allocated addrinfo. The entry 1904 * must be locked, and the reference count must be bumped up by one 1905 * if this function returns a valid pointer. 1906 */ 1907static inline dns_adbaddrinfo_t * 1908new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) { 1909 dns_adbaddrinfo_t *ai; 1910 1911 ai = isc_mempool_get(adb->aimp); 1912 if (ai == NULL) 1913 return (NULL); 1914 1915 ai->magic = DNS_ADBADDRINFO_MAGIC; 1916 ai->sockaddr = entry->sockaddr; 1917 isc_sockaddr_setport(&ai->sockaddr, port); 1918 ai->srtt = entry->srtt; 1919 ai->flags = entry->flags; 1920 ai->entry = entry; 1921 ISC_LINK_INIT(ai, publink); 1922 1923 return (ai); 1924} 1925 1926static inline void 1927free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) { 1928 dns_adbaddrinfo_t *ai; 1929 1930 INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo)); 1931 ai = *ainfo; 1932 *ainfo = NULL; 1933 1934 INSIST(ai->entry == NULL); 1935 INSIST(!ISC_LINK_LINKED(ai, publink)); 1936 1937 ai->magic = 0; 1938 1939 isc_mempool_put(adb->aimp, ai); 1940} 1941 1942/* 1943 * Search for the name. NOTE: The bucket is kept locked on both 1944 * success and failure, so it must always be unlocked by the caller! 1945 * 1946 * On the first call to this function, *bucketp must be set to 1947 * DNS_ADB_INVALIDBUCKET. 1948 */ 1949static inline dns_adbname_t * 1950find_name_and_lock(dns_adb_t *adb, dns_name_t *name, 1951 unsigned int options, int *bucketp) 1952{ 1953 dns_adbname_t *adbname; 1954 int bucket; 1955 1956 bucket = dns_name_fullhash(name, ISC_FALSE) % adb->nnames; 1957 1958 if (*bucketp == DNS_ADB_INVALIDBUCKET) { 1959 LOCK(&adb->namelocks[bucket]); 1960 *bucketp = bucket; 1961 } else if (*bucketp != bucket) { 1962 UNLOCK(&adb->namelocks[*bucketp]); 1963 LOCK(&adb->namelocks[bucket]); 1964 *bucketp = bucket; 1965 } 1966 1967 adbname = ISC_LIST_HEAD(adb->names[bucket]); 1968 while (adbname != NULL) { 1969 if (!NAME_DEAD(adbname)) { 1970 if (dns_name_equal(name, &adbname->name) 1971 && GLUEHINT_OK(adbname, options) 1972 && STARTATZONE_MATCHES(adbname, options)) 1973 return (adbname); 1974 } 1975 adbname = ISC_LIST_NEXT(adbname, plink); 1976 } 1977 1978 return (NULL); 1979} 1980 1981/* 1982 * Search for the address. NOTE: The bucket is kept locked on both 1983 * success and failure, so it must always be unlocked by the caller. 1984 * 1985 * On the first call to this function, *bucketp must be set to 1986 * DNS_ADB_INVALIDBUCKET. This will cause a lock to occur. On 1987 * later calls (within the same "lock path") it can be left alone, so 1988 * if this function is called multiple times locking is only done if 1989 * the bucket changes. 1990 */ 1991static inline dns_adbentry_t * 1992find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp, 1993 isc_stdtime_t now) 1994{ 1995 dns_adbentry_t *entry, *entry_next; 1996 int bucket; 1997 1998 bucket = isc_sockaddr_hash(addr, ISC_TRUE) % adb->nentries; 1999 2000 if (*bucketp == DNS_ADB_INVALIDBUCKET) { 2001 LOCK(&adb->entrylocks[bucket]); 2002 *bucketp = bucket; 2003 } else if (*bucketp != bucket) { 2004 UNLOCK(&adb->entrylocks[*bucketp]); 2005 LOCK(&adb->entrylocks[bucket]); 2006 *bucketp = bucket; 2007 } 2008 2009 /* Search the list, while cleaning up expired entries. */ 2010 for (entry = ISC_LIST_HEAD(adb->entries[bucket]); 2011 entry != NULL; 2012 entry = entry_next) { 2013 entry_next = ISC_LIST_NEXT(entry, plink); 2014 (void)check_expire_entry(adb, &entry, now); 2015 if (entry != NULL && 2016 isc_sockaddr_equal(addr, &entry->sockaddr)) { 2017 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink); 2018 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink); 2019 return (entry); 2020 } 2021 } 2022 2023 return (NULL); 2024} 2025 2026/* 2027 * Entry bucket MUST be locked! 2028 */ 2029static isc_boolean_t 2030entry_is_lame(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *qname, 2031 dns_rdatatype_t qtype, isc_stdtime_t now) 2032{ 2033 dns_adblameinfo_t *li, *next_li; 2034 isc_boolean_t is_bad; 2035 2036 is_bad = ISC_FALSE; 2037 2038 li = ISC_LIST_HEAD(entry->lameinfo); 2039 if (li == NULL) 2040 return (ISC_FALSE); 2041 while (li != NULL) { 2042 next_li = ISC_LIST_NEXT(li, plink); 2043 2044 /* 2045 * Has the entry expired? 2046 */ 2047 if (li->lame_timer < now) { 2048 ISC_LIST_UNLINK(entry->lameinfo, li, plink); 2049 free_adblameinfo(adb, &li); 2050 } 2051 2052 /* 2053 * Order tests from least to most expensive. 2054 * 2055 * We do not break out of the main loop here as 2056 * we use the loop for house keeping. 2057 */ 2058 if (li != NULL && !is_bad && li->qtype == qtype && 2059 dns_name_equal(qname, &li->qname)) 2060 is_bad = ISC_TRUE; 2061 2062 li = next_li; 2063 } 2064 2065 return (is_bad); 2066} 2067 2068static void 2069copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname, 2070 dns_rdatatype_t qtype, dns_adbname_t *name, 2071 isc_stdtime_t now) 2072{ 2073 dns_adbnamehook_t *namehook; 2074 dns_adbaddrinfo_t *addrinfo; 2075 dns_adbentry_t *entry; 2076 int bucket; 2077 2078 bucket = DNS_ADB_INVALIDBUCKET; 2079 2080 if (find->options & DNS_ADBFIND_INET) { 2081 namehook = ISC_LIST_HEAD(name->v4); 2082 while (namehook != NULL) { 2083 entry = namehook->entry; 2084 bucket = entry->lock_bucket; 2085 INSIST(bucket != DNS_ADB_INVALIDBUCKET); 2086 LOCK(&adb->entrylocks[bucket]); 2087 2088 if (!FIND_RETURNLAME(find) 2089 && entry_is_lame(adb, entry, qname, qtype, now)) { 2090 find->options |= DNS_ADBFIND_LAMEPRUNED; 2091 goto nextv4; 2092 } 2093 addrinfo = new_adbaddrinfo(adb, entry, find->port); 2094 if (addrinfo == NULL) { 2095 find->partial_result |= DNS_ADBFIND_INET; 2096 goto out; 2097 } 2098 /* 2099 * Found a valid entry. Add it to the find's list. 2100 */ 2101 inc_entry_refcnt(adb, entry, ISC_FALSE); 2102 ISC_LIST_APPEND(find->list, addrinfo, publink); 2103 addrinfo = NULL; 2104 nextv4: 2105 UNLOCK(&adb->entrylocks[bucket]); 2106 bucket = DNS_ADB_INVALIDBUCKET; 2107 namehook = ISC_LIST_NEXT(namehook, plink); 2108 } 2109 } 2110 2111 if (find->options & DNS_ADBFIND_INET6) { 2112 namehook = ISC_LIST_HEAD(name->v6); 2113 while (namehook != NULL) { 2114 entry = namehook->entry; 2115 bucket = entry->lock_bucket; 2116 INSIST(bucket != DNS_ADB_INVALIDBUCKET); 2117 LOCK(&adb->entrylocks[bucket]); 2118 2119 if (!FIND_RETURNLAME(find) 2120 && entry_is_lame(adb, entry, qname, qtype, now)) { 2121 find->options |= DNS_ADBFIND_LAMEPRUNED; 2122 goto nextv6; 2123 } 2124 addrinfo = new_adbaddrinfo(adb, entry, find->port); 2125 if (addrinfo == NULL) { 2126 find->partial_result |= DNS_ADBFIND_INET6; 2127 goto out; 2128 } 2129 /* 2130 * Found a valid entry. Add it to the find's list. 2131 */ 2132 inc_entry_refcnt(adb, entry, ISC_FALSE); 2133 ISC_LIST_APPEND(find->list, addrinfo, publink); 2134 addrinfo = NULL; 2135 nextv6: 2136 UNLOCK(&adb->entrylocks[bucket]); 2137 bucket = DNS_ADB_INVALIDBUCKET; 2138 namehook = ISC_LIST_NEXT(namehook, plink); 2139 } 2140 } 2141 2142 out: 2143 if (bucket != DNS_ADB_INVALIDBUCKET) 2144 UNLOCK(&adb->entrylocks[bucket]); 2145} 2146 2147static void 2148shutdown_task(isc_task_t *task, isc_event_t *ev) { 2149 dns_adb_t *adb; 2150 2151 UNUSED(task); 2152 2153 adb = ev->ev_arg; 2154 INSIST(DNS_ADB_VALID(adb)); 2155 2156 isc_event_free(&ev); 2157 /* 2158 * Wait for lock around check_exit() call to be released. 2159 */ 2160 LOCK(&adb->lock); 2161 UNLOCK(&adb->lock); 2162 destroy(adb); 2163} 2164 2165/* 2166 * Name bucket must be locked; adb may be locked; no other locks held. 2167 */ 2168static isc_boolean_t 2169check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) { 2170 dns_adbname_t *name; 2171 isc_boolean_t result = ISC_FALSE; 2172 2173 INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep)); 2174 name = *namep; 2175 2176 if (NAME_HAS_V4(name) || NAME_HAS_V6(name)) 2177 return (result); 2178 if (NAME_FETCH(name)) 2179 return (result); 2180 if (!EXPIRE_OK(name->expire_v4, now)) 2181 return (result); 2182 if (!EXPIRE_OK(name->expire_v6, now)) 2183 return (result); 2184 if (!EXPIRE_OK(name->expire_target, now)) 2185 return (result); 2186 2187 /* 2188 * The name is empty. Delete it. 2189 */ 2190 result = kill_name(&name, DNS_EVENT_ADBEXPIRED); 2191 *namep = NULL; 2192 2193 /* 2194 * Our caller, or one of its callers, will be calling check_exit() at 2195 * some point, so we don't need to do it here. 2196 */ 2197 return (result); 2198} 2199 2200/*% 2201 * Examine the tail entry of the LRU list to see if it expires or is stale 2202 * (unused for some period); if so, the name entry will be freed. If the ADB 2203 * is in the overmem condition, the tail and the next to tail entries 2204 * will be unconditionally removed (unless they have an outstanding fetch). 2205 * We don't care about a race on 'overmem' at the risk of causing some 2206 * collateral damage or a small delay in starting cleanup, so we don't bother 2207 * to lock ADB (if it's not locked). 2208 * 2209 * Name bucket must be locked; adb may be locked; no other locks held. 2210 */ 2211static void 2212check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) { 2213 int victims, max_victims; 2214 dns_adbname_t *victim, *next_victim; 2215 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx); 2216 int scans = 0; 2217 2218 INSIST(bucket != DNS_ADB_INVALIDBUCKET); 2219 2220 max_victims = overmem ? 2 : 1; 2221 2222 /* 2223 * We limit the number of scanned entries to 10 (arbitrary choice) 2224 * in order to avoid examining too many entries when there are many 2225 * tail entries that have fetches (this should be rare, but could 2226 * happen). 2227 */ 2228 victim = ISC_LIST_TAIL(adb->names[bucket]); 2229 for (victims = 0; 2230 victim != NULL && victims < max_victims && scans < 10; 2231 victim = next_victim) { 2232 INSIST(!NAME_DEAD(victim)); 2233 scans++; 2234 next_victim = ISC_LIST_PREV(victim, plink); 2235 (void)check_expire_name(&victim, now); 2236 if (victim == NULL) { 2237 victims++; 2238 goto next; 2239 } 2240 2241 if (!NAME_FETCH(victim) && 2242 (overmem || victim->last_used + ADB_STALE_MARGIN <= now)) { 2243 RUNTIME_CHECK(kill_name(&victim, 2244 DNS_EVENT_ADBCANCELED) == 2245 ISC_FALSE); 2246 victims++; 2247 } 2248 2249 next: 2250 if (!overmem) 2251 break; 2252 } 2253} 2254 2255/* 2256 * Entry bucket must be locked; adb may be locked; no other locks held. 2257 */ 2258static isc_boolean_t 2259check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now) 2260{ 2261 dns_adbentry_t *entry; 2262 isc_boolean_t result = ISC_FALSE; 2263 2264 INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp)); 2265 entry = *entryp; 2266 2267 if (entry->refcnt != 0) 2268 return (result); 2269 2270 if (entry->expires == 0 || entry->expires > now) 2271 return (result); 2272 2273 /* 2274 * The entry is not in use. Delete it. 2275 */ 2276 DP(DEF_LEVEL, "killing entry %p", entry); 2277 INSIST(ISC_LINK_LINKED(entry, plink)); 2278 result = unlink_entry(adb, entry); 2279 free_adbentry(adb, &entry); 2280 if (result) 2281 dec_adb_irefcnt(adb); 2282 *entryp = NULL; 2283 return (result); 2284} 2285 2286/* 2287 * ADB must be locked, and no other locks held. 2288 */ 2289static isc_boolean_t 2290cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) { 2291 dns_adbname_t *name; 2292 dns_adbname_t *next_name; 2293 isc_boolean_t result = ISC_FALSE; 2294 2295 DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket); 2296 2297 LOCK(&adb->namelocks[bucket]); 2298 if (adb->name_sd[bucket]) { 2299 UNLOCK(&adb->namelocks[bucket]); 2300 return (result); 2301 } 2302 2303 name = ISC_LIST_HEAD(adb->names[bucket]); 2304 while (name != NULL) { 2305 next_name = ISC_LIST_NEXT(name, plink); 2306 INSIST(result == ISC_FALSE); 2307 result = check_expire_namehooks(name, now); 2308 if (!result) 2309 result = check_expire_name(&name, now); 2310 name = next_name; 2311 } 2312 UNLOCK(&adb->namelocks[bucket]); 2313 return (result); 2314} 2315 2316/* 2317 * ADB must be locked, and no other locks held. 2318 */ 2319static isc_boolean_t 2320cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) { 2321 dns_adbentry_t *entry, *next_entry; 2322 isc_boolean_t result = ISC_FALSE; 2323 2324 DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket); 2325 2326 LOCK(&adb->entrylocks[bucket]); 2327 entry = ISC_LIST_HEAD(adb->entries[bucket]); 2328 while (entry != NULL) { 2329 next_entry = ISC_LIST_NEXT(entry, plink); 2330 INSIST(result == ISC_FALSE); 2331 result = check_expire_entry(adb, &entry, now); 2332 entry = next_entry; 2333 } 2334 UNLOCK(&adb->entrylocks[bucket]); 2335 return (result); 2336} 2337 2338static void 2339destroy(dns_adb_t *adb) { 2340 adb->magic = 0; 2341 2342 isc_task_detach(&adb->task); 2343 if (adb->excl != NULL) 2344 isc_task_detach(&adb->excl); 2345 2346 isc_mempool_destroy(&adb->nmp); 2347 isc_mempool_destroy(&adb->nhmp); 2348 isc_mempool_destroy(&adb->limp); 2349 isc_mempool_destroy(&adb->emp); 2350 isc_mempool_destroy(&adb->ahmp); 2351 isc_mempool_destroy(&adb->aimp); 2352 isc_mempool_destroy(&adb->afmp); 2353 2354 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries); 2355 isc_mem_put(adb->mctx, adb->entries, 2356 sizeof(*adb->entries) * adb->nentries); 2357 isc_mem_put(adb->mctx, adb->deadentries, 2358 sizeof(*adb->deadentries) * adb->nentries); 2359 isc_mem_put(adb->mctx, adb->entrylocks, 2360 sizeof(*adb->entrylocks) * adb->nentries); 2361 isc_mem_put(adb->mctx, adb->entry_sd, 2362 sizeof(*adb->entry_sd) * adb->nentries); 2363 isc_mem_put(adb->mctx, adb->entry_refcnt, 2364 sizeof(*adb->entry_refcnt) * adb->nentries); 2365 2366 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames); 2367 isc_mem_put(adb->mctx, adb->names, 2368 sizeof(*adb->names) * adb->nnames); 2369 isc_mem_put(adb->mctx, adb->deadnames, 2370 sizeof(*adb->deadnames) * adb->nnames); 2371 isc_mem_put(adb->mctx, adb->namelocks, 2372 sizeof(*adb->namelocks) * adb->nnames); 2373 isc_mem_put(adb->mctx, adb->name_sd, 2374 sizeof(*adb->name_sd) * adb->nnames); 2375 isc_mem_put(adb->mctx, adb->name_refcnt, 2376 sizeof(*adb->name_refcnt) * adb->nnames); 2377 2378 DESTROYLOCK(&adb->reflock); 2379 DESTROYLOCK(&adb->lock); 2380 DESTROYLOCK(&adb->mplock); 2381 DESTROYLOCK(&adb->overmemlock); 2382 DESTROYLOCK(&adb->entriescntlock); 2383 DESTROYLOCK(&adb->namescntlock); 2384 2385 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t)); 2386} 2387 2388 2389/* 2390 * Public functions. 2391 */ 2392 2393isc_result_t 2394dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, 2395 isc_taskmgr_t *taskmgr, dns_adb_t **newadb) 2396{ 2397 dns_adb_t *adb; 2398 isc_result_t result; 2399 unsigned int i; 2400 2401 REQUIRE(mem != NULL); 2402 REQUIRE(view != NULL); 2403 REQUIRE(timermgr != NULL); /* this is actually unused */ 2404 REQUIRE(taskmgr != NULL); 2405 REQUIRE(newadb != NULL && *newadb == NULL); 2406 2407 UNUSED(timermgr); 2408 2409 adb = isc_mem_get(mem, sizeof(dns_adb_t)); 2410 if (adb == NULL) 2411 return (ISC_R_NOMEMORY); 2412 2413 /* 2414 * Initialize things here that cannot fail, and especially things 2415 * that must be NULL for the error return to work properly. 2416 */ 2417 adb->magic = 0; 2418 adb->erefcnt = 1; 2419 adb->irefcnt = 0; 2420 adb->nmp = NULL; 2421 adb->nhmp = NULL; 2422 adb->limp = NULL; 2423 adb->emp = NULL; 2424 adb->ahmp = NULL; 2425 adb->aimp = NULL; 2426 adb->afmp = NULL; 2427 adb->task = NULL; 2428 adb->excl = NULL; 2429 adb->mctx = NULL; 2430 adb->view = view; 2431 adb->taskmgr = taskmgr; 2432 adb->next_cleanbucket = 0; 2433 ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL, 2434 DNS_EVENT_ADBCONTROL, shutdown_task, adb, 2435 adb, NULL, NULL); 2436 adb->cevent_sent = ISC_FALSE; 2437 adb->shutting_down = ISC_FALSE; 2438 ISC_LIST_INIT(adb->whenshutdown); 2439 2440 adb->nentries = nbuckets[0]; 2441 adb->entriescnt = 0; 2442 adb->entries = NULL; 2443 adb->deadentries = NULL; 2444 adb->entry_sd = NULL; 2445 adb->entry_refcnt = NULL; 2446 adb->entrylocks = NULL; 2447 ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL, 2448 DNS_EVENT_ADBGROWENTRIES, grow_entries, adb, 2449 adb, NULL, NULL); 2450 adb->growentries_sent = ISC_FALSE; 2451 2452 adb->nnames = nbuckets[0]; 2453 adb->namescnt = 0; 2454 adb->names = NULL; 2455 adb->deadnames = NULL; 2456 adb->name_sd = NULL; 2457 adb->name_refcnt = NULL; 2458 adb->namelocks = NULL; 2459 ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL, 2460 DNS_EVENT_ADBGROWNAMES, grow_names, adb, 2461 adb, NULL, NULL); 2462 adb->grownames_sent = ISC_FALSE; 2463 2464 result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl); 2465 if (result != ISC_R_SUCCESS) { 2466 DP(ISC_LOG_INFO, "adb: task-exclusive mode unavailable, " 2467 "intializing table sizes to %u\n", 2468 nbuckets[11]); 2469 adb->nentries = nbuckets[11]; 2470 adb->nnames= nbuckets[11]; 2471 2472 } 2473 2474 isc_mem_attach(mem, &adb->mctx); 2475 2476 result = isc_mutex_init(&adb->lock); 2477 if (result != ISC_R_SUCCESS) 2478 goto fail0b; 2479 2480 result = isc_mutex_init(&adb->mplock); 2481 if (result != ISC_R_SUCCESS) 2482 goto fail0c; 2483 2484 result = isc_mutex_init(&adb->reflock); 2485 if (result != ISC_R_SUCCESS) 2486 goto fail0d; 2487 2488 result = isc_mutex_init(&adb->overmemlock); 2489 if (result != ISC_R_SUCCESS) 2490 goto fail0e; 2491 2492 result = isc_mutex_init(&adb->entriescntlock); 2493 if (result != ISC_R_SUCCESS) 2494 goto fail0f; 2495 2496 result = isc_mutex_init(&adb->namescntlock); 2497 if (result != ISC_R_SUCCESS) 2498 goto fail0g; 2499 2500#define ALLOCENTRY(adb, el) \ 2501 do { \ 2502 (adb)->el = isc_mem_get((adb)->mctx, \ 2503 sizeof(*(adb)->el) * (adb)->nentries); \ 2504 if ((adb)->el == NULL) { \ 2505 result = ISC_R_NOMEMORY; \ 2506 goto fail1; \ 2507 }\ 2508 } while (0) 2509 ALLOCENTRY(adb, entries); 2510 ALLOCENTRY(adb, deadentries); 2511 ALLOCENTRY(adb, entrylocks); 2512 ALLOCENTRY(adb, entry_sd); 2513 ALLOCENTRY(adb, entry_refcnt); 2514#undef ALLOCENTRY 2515 2516#define ALLOCNAME(adb, el) \ 2517 do { \ 2518 (adb)->el = isc_mem_get((adb)->mctx, \ 2519 sizeof(*(adb)->el) * (adb)->nnames); \ 2520 if ((adb)->el == NULL) { \ 2521 result = ISC_R_NOMEMORY; \ 2522 goto fail1; \ 2523 }\ 2524 } while (0) 2525 ALLOCNAME(adb, names); 2526 ALLOCNAME(adb, deadnames); 2527 ALLOCNAME(adb, namelocks); 2528 ALLOCNAME(adb, name_sd); 2529 ALLOCNAME(adb, name_refcnt); 2530#undef ALLOCNAME 2531 2532 /* 2533 * Initialize the bucket locks for names and elements. 2534 * May as well initialize the list heads, too. 2535 */ 2536 result = isc_mutexblock_init(adb->namelocks, adb->nnames); 2537 if (result != ISC_R_SUCCESS) 2538 goto fail1; 2539 for (i = 0; i < adb->nnames; i++) { 2540 ISC_LIST_INIT(adb->names[i]); 2541 ISC_LIST_INIT(adb->deadnames[i]); 2542 adb->name_sd[i] = ISC_FALSE; 2543 adb->name_refcnt[i] = 0; 2544 adb->irefcnt++; 2545 } 2546 for (i = 0; i < adb->nentries; i++) { 2547 ISC_LIST_INIT(adb->entries[i]); 2548 ISC_LIST_INIT(adb->deadentries[i]); 2549 adb->entry_sd[i] = ISC_FALSE; 2550 adb->entry_refcnt[i] = 0; 2551 adb->irefcnt++; 2552 } 2553 result = isc_mutexblock_init(adb->entrylocks, adb->nentries); 2554 if (result != ISC_R_SUCCESS) 2555 goto fail2; 2556 2557 /* 2558 * Memory pools 2559 */ 2560#define MPINIT(t, p, n) do { \ 2561 result = isc_mempool_create(mem, sizeof(t), &(p)); \ 2562 if (result != ISC_R_SUCCESS) \ 2563 goto fail3; \ 2564 isc_mempool_setfreemax((p), FREE_ITEMS); \ 2565 isc_mempool_setfillcount((p), FILL_COUNT); \ 2566 isc_mempool_setname((p), n); \ 2567 isc_mempool_associatelock((p), &adb->mplock); \ 2568} while (0) 2569 2570 MPINIT(dns_adbname_t, adb->nmp, "adbname"); 2571 MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook"); 2572 MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo"); 2573 MPINIT(dns_adbentry_t, adb->emp, "adbentry"); 2574 MPINIT(dns_adbfind_t, adb->ahmp, "adbfind"); 2575 MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo"); 2576 MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch"); 2577 2578#undef MPINIT 2579 2580 /* 2581 * Allocate an internal task. 2582 */ 2583 result = isc_task_create(adb->taskmgr, 0, &adb->task); 2584 if (result != ISC_R_SUCCESS) 2585 goto fail3; 2586 2587 isc_task_setname(adb->task, "ADB", adb); 2588 2589 /* 2590 * Normal return. 2591 */ 2592 adb->magic = DNS_ADB_MAGIC; 2593 *newadb = adb; 2594 return (ISC_R_SUCCESS); 2595 2596 fail3: 2597 if (adb->task != NULL) 2598 isc_task_detach(&adb->task); 2599 2600 /* clean up entrylocks */ 2601 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries); 2602 2603 fail2: /* clean up namelocks */ 2604 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames); 2605 2606 fail1: /* clean up only allocated memory */ 2607 if (adb->entries != NULL) 2608 isc_mem_put(adb->mctx, adb->entries, 2609 sizeof(*adb->entries) * adb->nentries); 2610 if (adb->deadentries != NULL) 2611 isc_mem_put(adb->mctx, adb->deadentries, 2612 sizeof(*adb->deadentries) * adb->nentries); 2613 if (adb->entrylocks != NULL) 2614 isc_mem_put(adb->mctx, adb->entrylocks, 2615 sizeof(*adb->entrylocks) * adb->nentries); 2616 if (adb->entry_sd != NULL) 2617 isc_mem_put(adb->mctx, adb->entry_sd, 2618 sizeof(*adb->entry_sd) * adb->nentries); 2619 if (adb->entry_refcnt != NULL) 2620 isc_mem_put(adb->mctx, adb->entry_refcnt, 2621 sizeof(*adb->entry_refcnt) * adb->nentries); 2622 if (adb->names != NULL) 2623 isc_mem_put(adb->mctx, adb->names, 2624 sizeof(*adb->names) * adb->nnames); 2625 if (adb->deadnames != NULL) 2626 isc_mem_put(adb->mctx, adb->deadnames, 2627 sizeof(*adb->deadnames) * adb->nnames); 2628 if (adb->namelocks != NULL) 2629 isc_mem_put(adb->mctx, adb->namelocks, 2630 sizeof(*adb->namelocks) * adb->nnames); 2631 if (adb->name_sd != NULL) 2632 isc_mem_put(adb->mctx, adb->name_sd, 2633 sizeof(*adb->name_sd) * adb->nnames); 2634 if (adb->name_refcnt != NULL) 2635 isc_mem_put(adb->mctx, adb->name_refcnt, 2636 sizeof(*adb->name_refcnt) * adb->nnames); 2637 if (adb->nmp != NULL) 2638 isc_mempool_destroy(&adb->nmp); 2639 if (adb->nhmp != NULL) 2640 isc_mempool_destroy(&adb->nhmp); 2641 if (adb->limp != NULL) 2642 isc_mempool_destroy(&adb->limp); 2643 if (adb->emp != NULL) 2644 isc_mempool_destroy(&adb->emp); 2645 if (adb->ahmp != NULL) 2646 isc_mempool_destroy(&adb->ahmp); 2647 if (adb->aimp != NULL) 2648 isc_mempool_destroy(&adb->aimp); 2649 if (adb->afmp != NULL) 2650 isc_mempool_destroy(&adb->afmp); 2651 2652 DESTROYLOCK(&adb->namescntlock); 2653 fail0g: 2654 DESTROYLOCK(&adb->entriescntlock); 2655 fail0f: 2656 DESTROYLOCK(&adb->overmemlock); 2657 fail0e: 2658 DESTROYLOCK(&adb->reflock); 2659 fail0d: 2660 DESTROYLOCK(&adb->mplock); 2661 fail0c: 2662 DESTROYLOCK(&adb->lock); 2663 fail0b: 2664 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t)); 2665 2666 return (result); 2667} 2668 2669void 2670dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) { 2671 2672 REQUIRE(DNS_ADB_VALID(adb)); 2673 REQUIRE(adbx != NULL && *adbx == NULL); 2674 2675 inc_adb_erefcnt(adb); 2676 *adbx = adb; 2677} 2678 2679void 2680dns_adb_detach(dns_adb_t **adbx) { 2681 dns_adb_t *adb; 2682 isc_boolean_t need_exit_check; 2683 2684 REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx)); 2685 2686 adb = *adbx; 2687 *adbx = NULL; 2688 2689 INSIST(adb->erefcnt > 0); 2690 2691 LOCK(&adb->reflock); 2692 adb->erefcnt--; 2693 need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0); 2694 UNLOCK(&adb->reflock); 2695 2696 if (need_exit_check) { 2697 LOCK(&adb->lock); 2698 INSIST(adb->shutting_down); 2699 check_exit(adb); 2700 UNLOCK(&adb->lock); 2701 } 2702} 2703 2704void 2705dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) { 2706 isc_task_t *clone; 2707 isc_event_t *event; 2708 isc_boolean_t zeroirefcnt = ISC_FALSE; 2709 2710 /* 2711 * Send '*eventp' to 'task' when 'adb' has shutdown. 2712 */ 2713 2714 REQUIRE(DNS_ADB_VALID(adb)); 2715 REQUIRE(eventp != NULL); 2716 2717 event = *eventp; 2718 *eventp = NULL; 2719 2720 LOCK(&adb->lock); 2721 2722 LOCK(&adb->reflock); 2723 zeroirefcnt = ISC_TF(adb->irefcnt == 0); 2724 2725 if (adb->shutting_down && zeroirefcnt && 2726 isc_mempool_getallocated(adb->ahmp) == 0) { 2727 /* 2728 * We're already shutdown. Send the event. 2729 */ 2730 event->ev_sender = adb; 2731 isc_task_send(task, &event); 2732 } else { 2733 clone = NULL; 2734 isc_task_attach(task, &clone); 2735 event->ev_sender = clone; 2736 ISC_LIST_APPEND(adb->whenshutdown, event, ev_link); 2737 } 2738 2739 UNLOCK(&adb->reflock); 2740 UNLOCK(&adb->lock); 2741} 2742 2743void 2744dns_adb_shutdown(dns_adb_t *adb) { 2745 isc_boolean_t need_check_exit; 2746 2747 /* 2748 * Shutdown 'adb'. 2749 */ 2750 2751 LOCK(&adb->lock); 2752 2753 if (!adb->shutting_down) { 2754 adb->shutting_down = ISC_TRUE; 2755 isc_mem_setwater(adb->mctx, water, adb, 0, 0); 2756 need_check_exit = shutdown_names(adb); 2757 if (!need_check_exit) 2758 need_check_exit = shutdown_entries(adb); 2759 if (need_check_exit) 2760 check_exit(adb); 2761 } 2762 2763 UNLOCK(&adb->lock); 2764} 2765 2766isc_result_t 2767dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, 2768 void *arg, dns_name_t *name, dns_name_t *qname, 2769 dns_rdatatype_t qtype, unsigned int options, 2770 isc_stdtime_t now, dns_name_t *target, 2771 in_port_t port, dns_adbfind_t **findp) 2772{ 2773 dns_adbfind_t *find; 2774 dns_adbname_t *adbname; 2775 int bucket; 2776 isc_boolean_t want_event, start_at_zone, alias, have_address; 2777 isc_result_t result; 2778 unsigned int wanted_addresses; 2779 unsigned int wanted_fetches; 2780 unsigned int query_pending; 2781 2782 REQUIRE(DNS_ADB_VALID(adb)); 2783 if (task != NULL) { 2784 REQUIRE(action != NULL); 2785 } 2786 REQUIRE(name != NULL); 2787 REQUIRE(qname != NULL); 2788 REQUIRE(findp != NULL && *findp == NULL); 2789 REQUIRE(target == NULL || dns_name_hasbuffer(target)); 2790 2791 REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0); 2792 2793 result = ISC_R_UNEXPECTED; 2794 POST(result); 2795 wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK); 2796 wanted_fetches = 0; 2797 query_pending = 0; 2798 want_event = ISC_FALSE; 2799 start_at_zone = ISC_FALSE; 2800 alias = ISC_FALSE; 2801 2802 if (now == 0) 2803 isc_stdtime_get(&now); 2804 2805 /* 2806 * XXXMLG Move this comment somewhere else! 2807 * 2808 * Look up the name in our internal database. 2809 * 2810 * Possibilities: Note that these are not always exclusive. 2811 * 2812 * No name found. In this case, allocate a new name header and 2813 * an initial namehook or two. If any of these allocations 2814 * fail, clean up and return ISC_R_NOMEMORY. 2815 * 2816 * Name found, valid addresses present. Allocate one addrinfo 2817 * structure for each found and append it to the linked list 2818 * of addresses for this header. 2819 * 2820 * Name found, queries pending. In this case, if a task was 2821 * passed in, allocate a job id, attach it to the name's job 2822 * list and remember to tell the caller that there will be 2823 * more info coming later. 2824 */ 2825 2826 find = new_adbfind(adb); 2827 if (find == NULL) 2828 return (ISC_R_NOMEMORY); 2829 2830 find->port = port; 2831 2832 /* 2833 * Remember what types of addresses we are interested in. 2834 */ 2835 find->options = options; 2836 find->flags |= wanted_addresses; 2837 if (FIND_WANTEVENT(find)) { 2838 REQUIRE(task != NULL); 2839 } 2840 2841 /* 2842 * Try to see if we know anything about this name at all. 2843 */ 2844 bucket = DNS_ADB_INVALIDBUCKET; 2845 adbname = find_name_and_lock(adb, name, find->options, &bucket); 2846 INSIST(bucket != DNS_ADB_INVALIDBUCKET); 2847 if (adb->name_sd[bucket]) { 2848 DP(DEF_LEVEL, 2849 "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN"); 2850 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); 2851 result = ISC_R_SHUTTINGDOWN; 2852 goto out; 2853 } 2854 2855 /* 2856 * Nothing found. Allocate a new adbname structure for this name. 2857 */ 2858 if (adbname == NULL) { 2859 /* 2860 * See if there is any stale name at the end of list, and purge 2861 * it if so. 2862 */ 2863 check_stale_name(adb, bucket, now); 2864 2865 adbname = new_adbname(adb, name); 2866 if (adbname == NULL) { 2867 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); 2868 result = ISC_R_NOMEMORY; 2869 goto out; 2870 } 2871 link_name(adb, bucket, adbname); 2872 if (FIND_HINTOK(find)) 2873 adbname->flags |= NAME_HINT_OK; 2874 if (FIND_GLUEOK(find)) 2875 adbname->flags |= NAME_GLUE_OK; 2876 if (FIND_STARTATZONE(find)) 2877 adbname->flags |= NAME_STARTATZONE; 2878 } else { 2879 /* Move this name forward in the LRU list */ 2880 ISC_LIST_UNLINK(adb->names[bucket], adbname, plink); 2881 ISC_LIST_PREPEND(adb->names[bucket], adbname, plink); 2882 } 2883 adbname->last_used = now; 2884 2885 /* 2886 * Expire old entries, etc. 2887 */ 2888 RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE); 2889 2890 /* 2891 * Do we know that the name is an alias? 2892 */ 2893 if (!EXPIRE_OK(adbname->expire_target, now)) { 2894 /* 2895 * Yes, it is. 2896 */ 2897 DP(DEF_LEVEL, 2898 "dns_adb_createfind: name %p is an alias (cached)", 2899 adbname); 2900 alias = ISC_TRUE; 2901 goto post_copy; 2902 } 2903 2904 /* 2905 * Try to populate the name from the database and/or 2906 * start fetches. First try looking for an A record 2907 * in the database. 2908 */ 2909 if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now) 2910 && WANT_INET(wanted_addresses)) { 2911 result = dbfind_name(adbname, now, dns_rdatatype_a); 2912 if (result == ISC_R_SUCCESS) { 2913 DP(DEF_LEVEL, 2914 "dns_adb_createfind: found A for name %p in db", 2915 adbname); 2916 goto v6; 2917 } 2918 2919 /* 2920 * Did we get a CNAME or DNAME? 2921 */ 2922 if (result == DNS_R_ALIAS) { 2923 DP(DEF_LEVEL, 2924 "dns_adb_createfind: name %p is an alias", 2925 adbname); 2926 alias = ISC_TRUE; 2927 goto post_copy; 2928 } 2929 2930 /* 2931 * If the name doesn't exist at all, don't bother with 2932 * v6 queries; they won't work. 2933 * 2934 * If the name does exist but we didn't get our data, go 2935 * ahead and try AAAA. 2936 * 2937 * If the result is neither of these, try a fetch for A. 2938 */ 2939 if (NXDOMAIN_RESULT(result)) 2940 goto fetch; 2941 else if (NXRRSET_RESULT(result)) 2942 goto v6; 2943 2944 if (!NAME_FETCH_V4(adbname)) 2945 wanted_fetches |= DNS_ADBFIND_INET; 2946 } 2947 2948 v6: 2949 if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now) 2950 && WANT_INET6(wanted_addresses)) { 2951 result = dbfind_name(adbname, now, dns_rdatatype_aaaa); 2952 if (result == ISC_R_SUCCESS) { 2953 DP(DEF_LEVEL, 2954 "dns_adb_createfind: found AAAA for name %p", 2955 adbname); 2956 goto fetch; 2957 } 2958 2959 /* 2960 * Did we get a CNAME or DNAME? 2961 */ 2962 if (result == DNS_R_ALIAS) { 2963 DP(DEF_LEVEL, 2964 "dns_adb_createfind: name %p is an alias", 2965 adbname); 2966 alias = ISC_TRUE; 2967 goto post_copy; 2968 } 2969 2970 /* 2971 * Listen to negative cache hints, and don't start 2972 * another query. 2973 */ 2974 if (NCACHE_RESULT(result) || AUTH_NX(result)) 2975 goto fetch; 2976 2977 if (!NAME_FETCH_V6(adbname)) 2978 wanted_fetches |= DNS_ADBFIND_INET6; 2979 } 2980 2981 fetch: 2982 if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) || 2983 (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname))) 2984 have_address = ISC_TRUE; 2985 else 2986 have_address = ISC_FALSE; 2987 if (wanted_fetches != 0 && 2988 ! (FIND_AVOIDFETCHES(find) && have_address)) { 2989 /* 2990 * We're missing at least one address family. Either the 2991 * caller hasn't instructed us to avoid fetches, or we don't 2992 * know anything about any of the address families that would 2993 * be acceptable so we have to launch fetches. 2994 */ 2995 2996 if (FIND_STARTATZONE(find)) 2997 start_at_zone = ISC_TRUE; 2998 2999 /* 3000 * Start V4. 3001 */ 3002 if (WANT_INET(wanted_fetches) && 3003 fetch_name(adbname, start_at_zone, 3004 dns_rdatatype_a) == ISC_R_SUCCESS) { 3005 DP(DEF_LEVEL, 3006 "dns_adb_createfind: started A fetch for name %p", 3007 adbname); 3008 } 3009 3010 /* 3011 * Start V6. 3012 */ 3013 if (WANT_INET6(wanted_fetches) && 3014 fetch_name(adbname, start_at_zone, 3015 dns_rdatatype_aaaa) == ISC_R_SUCCESS) { 3016 DP(DEF_LEVEL, 3017 "dns_adb_createfind: " 3018 "started AAAA fetch for name %p", 3019 adbname); 3020 } 3021 } 3022 3023 /* 3024 * Run through the name and copy out the bits we are 3025 * interested in. 3026 */ 3027 copy_namehook_lists(adb, find, qname, qtype, adbname, now); 3028 3029 post_copy: 3030 if (NAME_FETCH_V4(adbname)) 3031 query_pending |= DNS_ADBFIND_INET; 3032 if (NAME_FETCH_V6(adbname)) 3033 query_pending |= DNS_ADBFIND_INET6; 3034 3035 /* 3036 * Attach to the name's query list if there are queries 3037 * already running, and we have been asked to. 3038 */ 3039 want_event = ISC_TRUE; 3040 if (!FIND_WANTEVENT(find)) 3041 want_event = ISC_FALSE; 3042 if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find)) 3043 want_event = ISC_FALSE; 3044 if ((wanted_addresses & query_pending) == 0) 3045 want_event = ISC_FALSE; 3046 if (alias) 3047 want_event = ISC_FALSE; 3048 if (want_event) { 3049 find->adbname = adbname; 3050 find->name_bucket = bucket; 3051 ISC_LIST_APPEND(adbname->finds, find, plink); 3052 find->query_pending = (query_pending & wanted_addresses); 3053 find->flags &= ~DNS_ADBFIND_ADDRESSMASK; 3054 find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK); 3055 DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p", 3056 find, adbname); 3057 } else { 3058 /* 3059 * Remove the flag so the caller knows there will never 3060 * be an event, and set internal flags to fake that 3061 * the event was sent and freed, so dns_adb_destroyfind() will 3062 * do the right thing. 3063 */ 3064 find->query_pending = (query_pending & wanted_addresses); 3065 find->options &= ~DNS_ADBFIND_WANTEVENT; 3066 find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED); 3067 find->flags &= ~DNS_ADBFIND_ADDRESSMASK; 3068 } 3069 3070 find->partial_result |= (adbname->partial_result & wanted_addresses); 3071 if (alias) { 3072 if (target != NULL) { 3073 result = dns_name_copy(&adbname->target, target, NULL); 3074 if (result != ISC_R_SUCCESS) 3075 goto out; 3076 } 3077 result = DNS_R_ALIAS; 3078 } else 3079 result = ISC_R_SUCCESS; 3080 3081 /* 3082 * Copy out error flags from the name structure into the find. 3083 */ 3084 find->result_v4 = find_err_map[adbname->fetch_err]; 3085 find->result_v6 = find_err_map[adbname->fetch6_err]; 3086 3087 out: 3088 if (find != NULL) { 3089 *findp = find; 3090 3091 if (want_event) { 3092 isc_task_t *taskp; 3093 3094 INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0); 3095 taskp = NULL; 3096 isc_task_attach(task, &taskp); 3097 find->event.ev_sender = taskp; 3098 find->event.ev_action = action; 3099 find->event.ev_arg = arg; 3100 } 3101 } 3102 3103 UNLOCK(&adb->namelocks[bucket]); 3104 3105 return (result); 3106} 3107 3108void 3109dns_adb_destroyfind(dns_adbfind_t **findp) { 3110 dns_adbfind_t *find; 3111 dns_adbentry_t *entry; 3112 dns_adbaddrinfo_t *ai; 3113 int bucket; 3114 dns_adb_t *adb; 3115 isc_boolean_t overmem; 3116 3117 REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp)); 3118 find = *findp; 3119 *findp = NULL; 3120 3121 LOCK(&find->lock); 3122 3123 DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find); 3124 3125 adb = find->adb; 3126 REQUIRE(DNS_ADB_VALID(adb)); 3127 3128 REQUIRE(FIND_EVENTFREED(find)); 3129 3130 bucket = find->name_bucket; 3131 INSIST(bucket == DNS_ADB_INVALIDBUCKET); 3132 3133 UNLOCK(&find->lock); 3134 3135 /* 3136 * The find doesn't exist on any list, and nothing is locked. 3137 * Return the find to the memory pool, and decrement the adb's 3138 * reference count. 3139 */ 3140 overmem = isc_mem_isovermem(adb->mctx); 3141 ai = ISC_LIST_HEAD(find->list); 3142 while (ai != NULL) { 3143 ISC_LIST_UNLINK(find->list, ai, publink); 3144 entry = ai->entry; 3145 ai->entry = NULL; 3146 INSIST(DNS_ADBENTRY_VALID(entry)); 3147 RUNTIME_CHECK(dec_entry_refcnt(adb, overmem, entry, ISC_TRUE) == 3148 ISC_FALSE); 3149 free_adbaddrinfo(adb, &ai); 3150 ai = ISC_LIST_HEAD(find->list); 3151 } 3152 3153 /* 3154 * WARNING: The find is freed with the adb locked. This is done 3155 * to avoid a race condition where we free the find, some other 3156 * thread tests to see if it should be destroyed, detects it should 3157 * be, destroys it, and then we try to lock it for our check, but the 3158 * lock is destroyed. 3159 */ 3160 LOCK(&adb->lock); 3161 if (free_adbfind(adb, &find)) 3162 check_exit(adb); 3163 UNLOCK(&adb->lock); 3164} 3165 3166void 3167dns_adb_cancelfind(dns_adbfind_t *find) { 3168 isc_event_t *ev; 3169 isc_task_t *task; 3170 dns_adb_t *adb; 3171 int bucket; 3172 int unlock_bucket; 3173 3174 LOCK(&find->lock); 3175 3176 DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find); 3177 3178 adb = find->adb; 3179 REQUIRE(DNS_ADB_VALID(adb)); 3180 3181 REQUIRE(!FIND_EVENTFREED(find)); 3182 REQUIRE(FIND_WANTEVENT(find)); 3183 3184 bucket = find->name_bucket; 3185 if (bucket == DNS_ADB_INVALIDBUCKET) 3186 goto cleanup; 3187 3188 /* 3189 * We need to get the adbname's lock to unlink the find. 3190 */ 3191 unlock_bucket = bucket; 3192 violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]); 3193 bucket = find->name_bucket; 3194 if (bucket != DNS_ADB_INVALIDBUCKET) { 3195 ISC_LIST_UNLINK(find->adbname->finds, find, plink); 3196 find->adbname = NULL; 3197 find->name_bucket = DNS_ADB_INVALIDBUCKET; 3198 } 3199 UNLOCK(&adb->namelocks[unlock_bucket]); 3200 bucket = DNS_ADB_INVALIDBUCKET; 3201 POST(bucket); 3202 3203 cleanup: 3204 3205 if (!FIND_EVENTSENT(find)) { 3206 ev = &find->event; 3207 task = ev->ev_sender; 3208 ev->ev_sender = find; 3209 ev->ev_type = DNS_EVENT_ADBCANCELED; 3210 ev->ev_destroy = event_free; 3211 ev->ev_destroy_arg = find; 3212 find->result_v4 = ISC_R_CANCELED; 3213 find->result_v6 = ISC_R_CANCELED; 3214 3215 DP(DEF_LEVEL, "sending event %p to task %p for find %p", 3216 ev, task, find); 3217 3218 isc_task_sendanddetach(&task, (isc_event_t **)&ev); 3219 } 3220 3221 UNLOCK(&find->lock); 3222} 3223 3224void 3225dns_adb_dump(dns_adb_t *adb, FILE *f) { 3226 unsigned int i; 3227 isc_stdtime_t now; 3228 3229 REQUIRE(DNS_ADB_VALID(adb)); 3230 REQUIRE(f != NULL); 3231 3232 /* 3233 * Lock the adb itself, lock all the name buckets, then lock all 3234 * the entry buckets. This should put the adb into a state where 3235 * nothing can change, so we can iterate through everything and 3236 * print at our leisure. 3237 */ 3238 3239 LOCK(&adb->lock); 3240 isc_stdtime_get(&now); 3241 3242 for (i = 0; i < adb->nnames; i++) 3243 RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE); 3244 for (i = 0; i < adb->nentries; i++) 3245 RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE); 3246 3247 dump_adb(adb, f, ISC_FALSE, now); 3248 UNLOCK(&adb->lock); 3249} 3250 3251static void 3252dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) { 3253 if (value == INT_MAX) 3254 return; 3255 fprintf(f, " [%s TTL %d]", legend, value - now); 3256} 3257 3258static void 3259dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) { 3260 unsigned int i; 3261 dns_adbname_t *name; 3262 dns_adbentry_t *entry; 3263 3264 fprintf(f, ";\n; Address database dump\n;\n"); 3265 if (debug) 3266 fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n", 3267 adb, adb->erefcnt, adb->irefcnt, 3268 isc_mempool_getallocated(adb->nhmp)); 3269 3270 for (i = 0; i < adb->nnames; i++) 3271 LOCK(&adb->namelocks[i]); 3272 for (i = 0; i < adb->nentries; i++) 3273 LOCK(&adb->entrylocks[i]); 3274 3275 /* 3276 * Dump the names 3277 */ 3278 for (i = 0; i < adb->nnames; i++) { 3279 name = ISC_LIST_HEAD(adb->names[i]); 3280 if (name == NULL) 3281 continue; 3282 if (debug) 3283 fprintf(f, "; bucket %d\n", i); 3284 for (; 3285 name != NULL; 3286 name = ISC_LIST_NEXT(name, plink)) 3287 { 3288 if (debug) 3289 fprintf(f, "; name %p (flags %08x)\n", 3290 name, name->flags); 3291 3292 fprintf(f, "; "); 3293 print_dns_name(f, &name->name); 3294 if (dns_name_countlabels(&name->target) > 0) { 3295 fprintf(f, " alias "); 3296 print_dns_name(f, &name->target); 3297 } 3298 3299 dump_ttl(f, "v4", name->expire_v4, now); 3300 dump_ttl(f, "v6", name->expire_v6, now); 3301 dump_ttl(f, "target", name->expire_target, now); 3302 3303 fprintf(f, " [v4 %s] [v6 %s]", 3304 errnames[name->fetch_err], 3305 errnames[name->fetch6_err]); 3306 3307 fprintf(f, "\n"); 3308 3309 print_namehook_list(f, "v4", &name->v4, debug, now); 3310 print_namehook_list(f, "v6", &name->v6, debug, now); 3311 3312 if (debug) 3313 print_fetch_list(f, name); 3314 if (debug) 3315 print_find_list(f, name); 3316 3317 } 3318 } 3319 3320 fprintf(f, ";\n; Unassociated entries\n;\n"); 3321 3322 for (i = 0; i < adb->nentries; i++) { 3323 entry = ISC_LIST_HEAD(adb->entries[i]); 3324 while (entry != NULL) { 3325 if (entry->refcnt == 0) 3326 dump_entry(f, entry, debug, now); 3327 entry = ISC_LIST_NEXT(entry, plink); 3328 } 3329 } 3330 3331 /* 3332 * Unlock everything 3333 */ 3334 for (i = 0; i < adb->nentries; i++) 3335 UNLOCK(&adb->entrylocks[i]); 3336 for (i = 0; i < adb->nnames; i++) 3337 UNLOCK(&adb->namelocks[i]); 3338} 3339 3340static void 3341dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug, 3342 isc_stdtime_t now) 3343{ 3344 char addrbuf[ISC_NETADDR_FORMATSIZE]; 3345 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 3346 isc_netaddr_t netaddr; 3347 dns_adblameinfo_t *li; 3348 3349 isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr); 3350 isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf)); 3351 3352 if (debug) 3353 fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt); 3354 3355 fprintf(f, ";\t%s [srtt %u] [flags %08x]", 3356 addrbuf, entry->srtt, entry->flags); 3357 if (entry->expires != 0) 3358 fprintf(f, " [ttl %d]", entry->expires - now); 3359 fprintf(f, "\n"); 3360 for (li = ISC_LIST_HEAD(entry->lameinfo); 3361 li != NULL; 3362 li = ISC_LIST_NEXT(li, plink)) { 3363 fprintf(f, ";\t\t"); 3364 print_dns_name(f, &li->qname); 3365 dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf)); 3366 fprintf(f, " %s [lame TTL %d]\n", typebuf, 3367 li->lame_timer - now); 3368 } 3369} 3370 3371void 3372dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) { 3373 char tmp[512]; 3374 const char *tmpp; 3375 dns_adbaddrinfo_t *ai; 3376 isc_sockaddr_t *sa; 3377 3378 /* 3379 * Not used currently, in the API Just In Case we 3380 * want to dump out the name and/or entries too. 3381 */ 3382 3383 LOCK(&find->lock); 3384 3385 fprintf(f, ";Find %p\n", find); 3386 fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n", 3387 find->query_pending, find->partial_result, 3388 find->options, find->flags); 3389 fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n", 3390 find->name_bucket, find->adbname, find->event.ev_sender); 3391 3392 ai = ISC_LIST_HEAD(find->list); 3393 if (ai != NULL) 3394 fprintf(f, "\tAddresses:\n"); 3395 while (ai != NULL) { 3396 sa = &ai->sockaddr; 3397 switch (sa->type.sa.sa_family) { 3398 case AF_INET: 3399 tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr, 3400 tmp, sizeof(tmp)); 3401 break; 3402 case AF_INET6: 3403 tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr, 3404 tmp, sizeof(tmp)); 3405 break; 3406 default: 3407 tmpp = "UnkFamily"; 3408 } 3409 3410 if (tmpp == NULL) 3411 tmpp = "BadAddress"; 3412 3413 fprintf(f, "\t\tentry %p, flags %08x" 3414 " srtt %u addr %s\n", 3415 ai->entry, ai->flags, ai->srtt, tmpp); 3416 3417 ai = ISC_LIST_NEXT(ai, publink); 3418 } 3419 3420 UNLOCK(&find->lock); 3421} 3422 3423static void 3424print_dns_name(FILE *f, dns_name_t *name) { 3425 char buf[DNS_NAME_FORMATSIZE]; 3426 3427 INSIST(f != NULL); 3428 3429 dns_name_format(name, buf, sizeof(buf)); 3430 fprintf(f, "%s", buf); 3431} 3432 3433static void 3434print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list, 3435 isc_boolean_t debug, isc_stdtime_t now) 3436{ 3437 dns_adbnamehook_t *nh; 3438 3439 for (nh = ISC_LIST_HEAD(*list); 3440 nh != NULL; 3441 nh = ISC_LIST_NEXT(nh, plink)) 3442 { 3443 if (debug) 3444 fprintf(f, ";\tHook(%s) %p\n", legend, nh); 3445 dump_entry(f, nh->entry, debug, now); 3446 } 3447} 3448 3449static inline void 3450print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) { 3451 fprintf(f, "\t\tFetch(%s): %p -> { fetch %p }\n", 3452 type, ft, ft->fetch); 3453} 3454 3455static void 3456print_fetch_list(FILE *f, dns_adbname_t *n) { 3457 if (NAME_FETCH_A(n)) 3458 print_fetch(f, n->fetch_a, "A"); 3459 if (NAME_FETCH_AAAA(n)) 3460 print_fetch(f, n->fetch_aaaa, "AAAA"); 3461} 3462 3463static void 3464print_find_list(FILE *f, dns_adbname_t *name) { 3465 dns_adbfind_t *find; 3466 3467 find = ISC_LIST_HEAD(name->finds); 3468 while (find != NULL) { 3469 dns_adb_dumpfind(find, f); 3470 find = ISC_LIST_NEXT(find, plink); 3471 } 3472} 3473 3474static isc_result_t 3475dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype) 3476{ 3477 isc_result_t result; 3478 dns_rdataset_t rdataset; 3479 dns_adb_t *adb; 3480 dns_fixedname_t foundname; 3481 dns_name_t *fname; 3482 3483 INSIST(DNS_ADBNAME_VALID(adbname)); 3484 adb = adbname->adb; 3485 INSIST(DNS_ADB_VALID(adb)); 3486 INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa); 3487 3488 dns_fixedname_init(&foundname); 3489 fname = dns_fixedname_name(&foundname); 3490 dns_rdataset_init(&rdataset); 3491 3492 if (rdtype == dns_rdatatype_a) 3493 adbname->fetch_err = FIND_ERR_UNEXPECTED; 3494 else 3495 adbname->fetch6_err = FIND_ERR_UNEXPECTED; 3496 3497 /* 3498 * We need to specify whether to search static-stub zones (if 3499 * configured) depending on whether this is a "start at zone" lookup, 3500 * i.e., whether it's a "bailiwick" glue. If it's bailiwick (in which 3501 * case NAME_STARTATZONE is set) we need to stop the search at any 3502 * matching static-stub zone without looking into the cache to honor 3503 * the configuration on which server we should send queries to. 3504 */ 3505 result = dns_view_find2(adb->view, &adbname->name, rdtype, now, 3506 NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0, 3507 ISC_TF(NAME_HINTOK(adbname)), 3508 (adbname->flags & NAME_STARTATZONE) != 0 ? 3509 ISC_TRUE : ISC_FALSE, 3510 NULL, NULL, fname, &rdataset, NULL); 3511 3512 /* XXXVIX this switch statement is too sparse to gen a jump table. */ 3513 switch (result) { 3514 case DNS_R_GLUE: 3515 case DNS_R_HINT: 3516 case ISC_R_SUCCESS: 3517 /* 3518 * Found in the database. Even if we can't copy out 3519 * any information, return success, or else a fetch 3520 * will be made, which will only make things worse. 3521 */ 3522 if (rdtype == dns_rdatatype_a) 3523 adbname->fetch_err = FIND_ERR_SUCCESS; 3524 else 3525 adbname->fetch6_err = FIND_ERR_SUCCESS; 3526 result = import_rdataset(adbname, &rdataset, now); 3527 break; 3528 case DNS_R_NXDOMAIN: 3529 case DNS_R_NXRRSET: 3530 /* 3531 * We're authoritative and the data doesn't exist. 3532 * Make up a negative cache entry so we don't ask again 3533 * for a while. 3534 * 3535 * XXXRTH What time should we use? I'm putting in 30 seconds 3536 * for now. 3537 */ 3538 if (rdtype == dns_rdatatype_a) { 3539 adbname->expire_v4 = now + 30; 3540 DP(NCACHE_LEVEL, 3541 "adb name %p: Caching auth negative entry for A", 3542 adbname); 3543 if (result == DNS_R_NXDOMAIN) 3544 adbname->fetch_err = FIND_ERR_NXDOMAIN; 3545 else 3546 adbname->fetch_err = FIND_ERR_NXRRSET; 3547 } else { 3548 DP(NCACHE_LEVEL, 3549 "adb name %p: Caching auth negative entry for AAAA", 3550 adbname); 3551 adbname->expire_v6 = now + 30; 3552 if (result == DNS_R_NXDOMAIN) 3553 adbname->fetch6_err = FIND_ERR_NXDOMAIN; 3554 else 3555 adbname->fetch6_err = FIND_ERR_NXRRSET; 3556 } 3557 break; 3558 case DNS_R_NCACHENXDOMAIN: 3559 case DNS_R_NCACHENXRRSET: 3560 /* 3561 * We found a negative cache entry. Pull the TTL from it 3562 * so we won't ask again for a while. 3563 */ 3564 rdataset.ttl = ttlclamp(rdataset.ttl); 3565 if (rdtype == dns_rdatatype_a) { 3566 adbname->expire_v4 = rdataset.ttl + now; 3567 if (result == DNS_R_NCACHENXDOMAIN) 3568 adbname->fetch_err = FIND_ERR_NXDOMAIN; 3569 else 3570 adbname->fetch_err = FIND_ERR_NXRRSET; 3571 DP(NCACHE_LEVEL, 3572 "adb name %p: Caching negative entry for A (ttl %u)", 3573 adbname, rdataset.ttl); 3574 } else { 3575 DP(NCACHE_LEVEL, 3576 "adb name %p: Caching negative entry for AAAA (ttl %u)", 3577 adbname, rdataset.ttl); 3578 adbname->expire_v6 = rdataset.ttl + now; 3579 if (result == DNS_R_NCACHENXDOMAIN) 3580 adbname->fetch6_err = FIND_ERR_NXDOMAIN; 3581 else 3582 adbname->fetch6_err = FIND_ERR_NXRRSET; 3583 } 3584 break; 3585 case DNS_R_CNAME: 3586 case DNS_R_DNAME: 3587 /* 3588 * Clear the hint and glue flags, so this will match 3589 * more often. 3590 */ 3591 adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK); 3592 3593 rdataset.ttl = ttlclamp(rdataset.ttl); 3594 clean_target(adb, &adbname->target); 3595 adbname->expire_target = INT_MAX; 3596 result = set_target(adb, &adbname->name, fname, &rdataset, 3597 &adbname->target); 3598 if (result == ISC_R_SUCCESS) { 3599 result = DNS_R_ALIAS; 3600 DP(NCACHE_LEVEL, 3601 "adb name %p: caching alias target", 3602 adbname); 3603 adbname->expire_target = rdataset.ttl + now; 3604 } 3605 if (rdtype == dns_rdatatype_a) 3606 adbname->fetch_err = FIND_ERR_SUCCESS; 3607 else 3608 adbname->fetch6_err = FIND_ERR_SUCCESS; 3609 break; 3610 } 3611 3612 if (dns_rdataset_isassociated(&rdataset)) 3613 dns_rdataset_disassociate(&rdataset); 3614 3615 return (result); 3616} 3617 3618static void 3619fetch_callback(isc_task_t *task, isc_event_t *ev) { 3620 dns_fetchevent_t *dev; 3621 dns_adbname_t *name; 3622 dns_adb_t *adb; 3623 dns_adbfetch_t *fetch; 3624 int bucket; 3625 isc_eventtype_t ev_status; 3626 isc_stdtime_t now; 3627 isc_result_t result; 3628 unsigned int address_type; 3629 isc_boolean_t want_check_exit = ISC_FALSE; 3630 3631 UNUSED(task); 3632 3633 INSIST(ev->ev_type == DNS_EVENT_FETCHDONE); 3634 dev = (dns_fetchevent_t *)ev; 3635 name = ev->ev_arg; 3636 INSIST(DNS_ADBNAME_VALID(name)); 3637 adb = name->adb; 3638 INSIST(DNS_ADB_VALID(adb)); 3639 3640 bucket = name->lock_bucket; 3641 LOCK(&adb->namelocks[bucket]); 3642 3643 INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name)); 3644 address_type = 0; 3645 if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) { 3646 address_type = DNS_ADBFIND_INET; 3647 fetch = name->fetch_a; 3648 name->fetch_a = NULL; 3649 } else if (NAME_FETCH_AAAA(name) 3650 && (name->fetch_aaaa->fetch == dev->fetch)) { 3651 address_type = DNS_ADBFIND_INET6; 3652 fetch = name->fetch_aaaa; 3653 name->fetch_aaaa = NULL; 3654 } else 3655 fetch = NULL; 3656 3657 INSIST(address_type != 0 && fetch != NULL); 3658 3659 dns_resolver_destroyfetch(&fetch->fetch); 3660 dev->fetch = NULL; 3661 3662 ev_status = DNS_EVENT_ADBNOMOREADDRESSES; 3663 3664 /* 3665 * Cleanup things we don't care about. 3666 */ 3667 if (dev->node != NULL) 3668 dns_db_detachnode(dev->db, &dev->node); 3669 if (dev->db != NULL) 3670 dns_db_detach(&dev->db); 3671 3672 /* 3673 * If this name is marked as dead, clean up, throwing away 3674 * potentially good data. 3675 */ 3676 if (NAME_DEAD(name)) { 3677 free_adbfetch(adb, &fetch); 3678 isc_event_free(&ev); 3679 3680 want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED); 3681 3682 UNLOCK(&adb->namelocks[bucket]); 3683 3684 if (want_check_exit) { 3685 LOCK(&adb->lock); 3686 check_exit(adb); 3687 UNLOCK(&adb->lock); 3688 } 3689 3690 return; 3691 } 3692 3693 isc_stdtime_get(&now); 3694 3695 /* 3696 * If we got a negative cache response, remember it. 3697 */ 3698 if (NCACHE_RESULT(dev->result)) { 3699 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl); 3700 if (address_type == DNS_ADBFIND_INET) { 3701 DP(NCACHE_LEVEL, "adb fetch name %p: " 3702 "caching negative entry for A (ttl %u)", 3703 name, dev->rdataset->ttl); 3704 name->expire_v4 = ISC_MIN(name->expire_v4, 3705 dev->rdataset->ttl + now); 3706 if (dev->result == DNS_R_NCACHENXDOMAIN) 3707 name->fetch_err = FIND_ERR_NXDOMAIN; 3708 else 3709 name->fetch_err = FIND_ERR_NXRRSET; 3710 inc_stats(adb, dns_resstatscounter_gluefetchv4fail); 3711 } else { 3712 DP(NCACHE_LEVEL, "adb fetch name %p: " 3713 "caching negative entry for AAAA (ttl %u)", 3714 name, dev->rdataset->ttl); 3715 name->expire_v6 = ISC_MIN(name->expire_v6, 3716 dev->rdataset->ttl + now); 3717 if (dev->result == DNS_R_NCACHENXDOMAIN) 3718 name->fetch6_err = FIND_ERR_NXDOMAIN; 3719 else 3720 name->fetch6_err = FIND_ERR_NXRRSET; 3721 inc_stats(adb, dns_resstatscounter_gluefetchv6fail); 3722 } 3723 goto out; 3724 } 3725 3726 /* 3727 * Handle CNAME/DNAME. 3728 */ 3729 if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) { 3730 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl); 3731 clean_target(adb, &name->target); 3732 name->expire_target = INT_MAX; 3733 result = set_target(adb, &name->name, 3734 dns_fixedname_name(&dev->foundname), 3735 dev->rdataset, 3736 &name->target); 3737 if (result == ISC_R_SUCCESS) { 3738 DP(NCACHE_LEVEL, 3739 "adb fetch name %p: caching alias target", 3740 name); 3741 name->expire_target = dev->rdataset->ttl + now; 3742 } 3743 goto check_result; 3744 } 3745 3746 /* 3747 * Did we get back junk? If so, and there are no more fetches 3748 * sitting out there, tell all the finds about it. 3749 */ 3750 if (dev->result != ISC_R_SUCCESS) { 3751 char buf[DNS_NAME_FORMATSIZE]; 3752 3753 dns_name_format(&name->name, buf, sizeof(buf)); 3754 DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s", 3755 buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA", 3756 dns_result_totext(dev->result)); 3757 /* XXXMLG Don't pound on bad servers. */ 3758 if (address_type == DNS_ADBFIND_INET) { 3759 name->expire_v4 = ISC_MIN(name->expire_v4, now + 300); 3760 name->fetch_err = FIND_ERR_FAILURE; 3761 inc_stats(adb, dns_resstatscounter_gluefetchv4fail); 3762 } else { 3763 name->expire_v6 = ISC_MIN(name->expire_v6, now + 300); 3764 name->fetch6_err = FIND_ERR_FAILURE; 3765 inc_stats(adb, dns_resstatscounter_gluefetchv6fail); 3766 } 3767 goto out; 3768 } 3769 3770 /* 3771 * We got something potentially useful. 3772 */ 3773 result = import_rdataset(name, &fetch->rdataset, now); 3774 3775 check_result: 3776 if (result == ISC_R_SUCCESS) { 3777 ev_status = DNS_EVENT_ADBMOREADDRESSES; 3778 if (address_type == DNS_ADBFIND_INET) 3779 name->fetch_err = FIND_ERR_SUCCESS; 3780 else 3781 name->fetch6_err = FIND_ERR_SUCCESS; 3782 } 3783 3784 out: 3785 free_adbfetch(adb, &fetch); 3786 isc_event_free(&ev); 3787 3788 clean_finds_at_name(name, ev_status, address_type); 3789 3790 UNLOCK(&adb->namelocks[bucket]); 3791} 3792 3793static isc_result_t 3794fetch_name(dns_adbname_t *adbname, 3795 isc_boolean_t start_at_zone, 3796 dns_rdatatype_t type) 3797{ 3798 isc_result_t result; 3799 dns_adbfetch_t *fetch = NULL; 3800 dns_adb_t *adb; 3801 dns_fixedname_t fixed; 3802 dns_name_t *name; 3803 dns_rdataset_t rdataset; 3804 dns_rdataset_t *nameservers; 3805 unsigned int options; 3806 3807 INSIST(DNS_ADBNAME_VALID(adbname)); 3808 adb = adbname->adb; 3809 INSIST(DNS_ADB_VALID(adb)); 3810 3811 INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) || 3812 (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname))); 3813 3814 adbname->fetch_err = FIND_ERR_NOTFOUND; 3815 3816 name = NULL; 3817 nameservers = NULL; 3818 dns_rdataset_init(&rdataset); 3819 3820 options = DNS_FETCHOPT_NOVALIDATE; 3821 if (start_at_zone) { 3822 DP(ENTER_LEVEL, 3823 "fetch_name: starting at zone for name %p", 3824 adbname); 3825 dns_fixedname_init(&fixed); 3826 name = dns_fixedname_name(&fixed); 3827 result = dns_view_findzonecut2(adb->view, &adbname->name, name, 3828 0, 0, ISC_TRUE, ISC_FALSE, 3829 &rdataset, NULL); 3830 if (result != ISC_R_SUCCESS && result != DNS_R_HINT) 3831 goto cleanup; 3832 nameservers = &rdataset; 3833 options |= DNS_FETCHOPT_UNSHARED; 3834 } 3835 3836 fetch = new_adbfetch(adb); 3837 if (fetch == NULL) { 3838 result = ISC_R_NOMEMORY; 3839 goto cleanup; 3840 } 3841 3842 result = dns_resolver_createfetch(adb->view->resolver, &adbname->name, 3843 type, name, nameservers, NULL, 3844 options, adb->task, fetch_callback, 3845 adbname, &fetch->rdataset, NULL, 3846 &fetch->fetch); 3847 if (result != ISC_R_SUCCESS) 3848 goto cleanup; 3849 3850 if (type == dns_rdatatype_a) { 3851 adbname->fetch_a = fetch; 3852 inc_stats(adb, dns_resstatscounter_gluefetchv4); 3853 } else { 3854 adbname->fetch_aaaa = fetch; 3855 inc_stats(adb, dns_resstatscounter_gluefetchv6); 3856 } 3857 fetch = NULL; /* Keep us from cleaning this up below. */ 3858 3859 cleanup: 3860 if (fetch != NULL) 3861 free_adbfetch(adb, &fetch); 3862 if (dns_rdataset_isassociated(&rdataset)) 3863 dns_rdataset_disassociate(&rdataset); 3864 3865 return (result); 3866} 3867 3868/* 3869 * XXXMLG Needs to take a find argument and an address info, no zone or adb, 3870 * since these can be extracted from the find itself. 3871 */ 3872isc_result_t 3873dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname, 3874 dns_rdatatype_t qtype, isc_stdtime_t expire_time) 3875{ 3876 dns_adblameinfo_t *li; 3877 int bucket; 3878 isc_result_t result = ISC_R_SUCCESS; 3879 3880 REQUIRE(DNS_ADB_VALID(adb)); 3881 REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3882 REQUIRE(qname != NULL); 3883 3884 bucket = addr->entry->lock_bucket; 3885 LOCK(&adb->entrylocks[bucket]); 3886 li = ISC_LIST_HEAD(addr->entry->lameinfo); 3887 while (li != NULL && 3888 (li->qtype != qtype || !dns_name_equal(qname, &li->qname))) 3889 li = ISC_LIST_NEXT(li, plink); 3890 if (li != NULL) { 3891 if (expire_time > li->lame_timer) 3892 li->lame_timer = expire_time; 3893 goto unlock; 3894 } 3895 li = new_adblameinfo(adb, qname, qtype); 3896 if (li == NULL) { 3897 result = ISC_R_NOMEMORY; 3898 goto unlock; 3899 } 3900 3901 li->lame_timer = expire_time; 3902 3903 ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink); 3904 unlock: 3905 UNLOCK(&adb->entrylocks[bucket]); 3906 3907 return (result); 3908} 3909 3910void 3911dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr, 3912 unsigned int rtt, unsigned int factor) 3913{ 3914 int bucket; 3915 unsigned int new_srtt; 3916 isc_stdtime_t now; 3917 3918 REQUIRE(DNS_ADB_VALID(adb)); 3919 REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3920 REQUIRE(factor <= 10); 3921 3922 bucket = addr->entry->lock_bucket; 3923 LOCK(&adb->entrylocks[bucket]); 3924 3925 if (factor == DNS_ADB_RTTADJAGE) 3926 new_srtt = addr->entry->srtt * 98 / 100; 3927 else 3928 new_srtt = (addr->entry->srtt / 10 * factor) 3929 + (rtt / 10 * (10 - factor)); 3930 3931 addr->entry->srtt = new_srtt; 3932 addr->srtt = new_srtt; 3933 3934 if (addr->entry->expires == 0) { 3935 isc_stdtime_get(&now); 3936 addr->entry->expires = now + ADB_ENTRY_WINDOW; 3937 } 3938 3939 UNLOCK(&adb->entrylocks[bucket]); 3940} 3941 3942void 3943dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr, 3944 unsigned int bits, unsigned int mask) 3945{ 3946 int bucket; 3947 isc_stdtime_t now; 3948 3949 REQUIRE(DNS_ADB_VALID(adb)); 3950 REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 3951 3952 bucket = addr->entry->lock_bucket; 3953 LOCK(&adb->entrylocks[bucket]); 3954 3955 addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask); 3956 if (addr->entry->expires == 0) { 3957 isc_stdtime_get(&now); 3958 addr->entry->expires = now + ADB_ENTRY_WINDOW; 3959 } 3960 3961 /* 3962 * Note that we do not update the other bits in addr->flags with 3963 * the most recent values from addr->entry->flags. 3964 */ 3965 addr->flags = (addr->flags & ~mask) | (bits & mask); 3966 3967 UNLOCK(&adb->entrylocks[bucket]); 3968} 3969 3970isc_result_t 3971dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa, 3972 dns_adbaddrinfo_t **addrp, isc_stdtime_t now) 3973{ 3974 int bucket; 3975 dns_adbentry_t *entry; 3976 dns_adbaddrinfo_t *addr; 3977 isc_result_t result; 3978 in_port_t port; 3979 3980 REQUIRE(DNS_ADB_VALID(adb)); 3981 REQUIRE(addrp != NULL && *addrp == NULL); 3982 3983 UNUSED(now); 3984 3985 result = ISC_R_SUCCESS; 3986 bucket = DNS_ADB_INVALIDBUCKET; 3987 entry = find_entry_and_lock(adb, sa, &bucket, now); 3988 INSIST(bucket != DNS_ADB_INVALIDBUCKET); 3989 if (adb->entry_sd[bucket]) { 3990 result = ISC_R_SHUTTINGDOWN; 3991 goto unlock; 3992 } 3993 if (entry == NULL) { 3994 /* 3995 * We don't know anything about this address. 3996 */ 3997 entry = new_adbentry(adb); 3998 if (entry == NULL) { 3999 result = ISC_R_NOMEMORY; 4000 goto unlock; 4001 } 4002 entry->sockaddr = *sa; 4003 link_entry(adb, bucket, entry); 4004 DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry); 4005 } else 4006 DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry); 4007 4008 port = isc_sockaddr_getport(sa); 4009 addr = new_adbaddrinfo(adb, entry, port); 4010 if (addr == NULL) { 4011 result = ISC_R_NOMEMORY; 4012 } else { 4013 inc_entry_refcnt(adb, entry, ISC_FALSE); 4014 *addrp = addr; 4015 } 4016 4017 unlock: 4018 UNLOCK(&adb->entrylocks[bucket]); 4019 4020 return (result); 4021} 4022 4023void 4024dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) { 4025 dns_adbaddrinfo_t *addr; 4026 dns_adbentry_t *entry; 4027 int bucket; 4028 isc_stdtime_t now; 4029 isc_boolean_t want_check_exit = ISC_FALSE; 4030 isc_boolean_t overmem; 4031 4032 REQUIRE(DNS_ADB_VALID(adb)); 4033 REQUIRE(addrp != NULL); 4034 addr = *addrp; 4035 REQUIRE(DNS_ADBADDRINFO_VALID(addr)); 4036 entry = addr->entry; 4037 REQUIRE(DNS_ADBENTRY_VALID(entry)); 4038 4039 *addrp = NULL; 4040 overmem = isc_mem_isovermem(adb->mctx); 4041 4042 bucket = addr->entry->lock_bucket; 4043 LOCK(&adb->entrylocks[bucket]); 4044 4045 if (entry->expires == 0) { 4046 isc_stdtime_get(&now); 4047 entry->expires = now + ADB_ENTRY_WINDOW; 4048 } 4049 4050 want_check_exit = dec_entry_refcnt(adb, overmem, entry, ISC_FALSE); 4051 4052 UNLOCK(&adb->entrylocks[bucket]); 4053 4054 addr->entry = NULL; 4055 free_adbaddrinfo(adb, &addr); 4056 4057 if (want_check_exit) { 4058 LOCK(&adb->lock); 4059 check_exit(adb); 4060 UNLOCK(&adb->lock); 4061 } 4062} 4063 4064void 4065dns_adb_flush(dns_adb_t *adb) { 4066 unsigned int i; 4067 4068 INSIST(DNS_ADB_VALID(adb)); 4069 4070 LOCK(&adb->lock); 4071 4072 /* 4073 * Call our cleanup routines. 4074 */ 4075 for (i = 0; i < adb->nnames; i++) 4076 RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE); 4077 for (i = 0; i < adb->nentries; i++) 4078 RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE); 4079 4080#ifdef DUMP_ADB_AFTER_CLEANING 4081 dump_adb(adb, stdout, ISC_TRUE, INT_MAX); 4082#endif 4083 4084 UNLOCK(&adb->lock); 4085} 4086 4087void 4088dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) { 4089 dns_adbname_t *adbname; 4090 dns_adbname_t *nextname; 4091 int bucket; 4092 4093 INSIST(DNS_ADB_VALID(adb)); 4094 4095 LOCK(&adb->lock); 4096 bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames; 4097 LOCK(&adb->namelocks[bucket]); 4098 adbname = ISC_LIST_HEAD(adb->names[bucket]); 4099 while (adbname != NULL) { 4100 nextname = ISC_LIST_NEXT(adbname, plink); 4101 if (!NAME_DEAD(adbname) && 4102 dns_name_equal(name, &adbname->name)) { 4103 RUNTIME_CHECK(kill_name(&adbname, 4104 DNS_EVENT_ADBCANCELED) == 4105 ISC_FALSE); 4106 } 4107 adbname = nextname; 4108 } 4109 UNLOCK(&adb->namelocks[bucket]); 4110 UNLOCK(&adb->lock); 4111} 4112 4113static void 4114water(void *arg, int mark) { 4115 /* 4116 * We're going to change the way to handle overmem condition: use 4117 * isc_mem_isovermem() instead of storing the state via this callback, 4118 * since the latter way tends to cause race conditions. 4119 * To minimize the change, and in case we re-enable the callback 4120 * approach, however, keep this function at the moment. 4121 */ 4122 4123 dns_adb_t *adb = arg; 4124 isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER); 4125 4126 REQUIRE(DNS_ADB_VALID(adb)); 4127 4128 DP(ISC_LOG_DEBUG(1), 4129 "adb reached %s water mark", overmem ? "high" : "low"); 4130} 4131 4132void 4133dns_adb_setadbsize(dns_adb_t *adb, size_t size) { 4134 size_t hiwater, lowater; 4135 4136 INSIST(DNS_ADB_VALID(adb)); 4137 4138 if (size != 0U && size < DNS_ADB_MINADBSIZE) 4139 size = DNS_ADB_MINADBSIZE; 4140 4141 hiwater = size - (size >> 3); /* Approximately 7/8ths. */ 4142 lowater = size - (size >> 2); /* Approximately 3/4ths. */ 4143 4144 if (size == 0U || hiwater == 0U || lowater == 0U) 4145 isc_mem_setwater(adb->mctx, water, adb, 0, 0); 4146 else 4147 isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater); 4148} 4149