00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <config.h>
00028
00029 #include <limits.h>
00030
00031 #include <isc/mutexblock.h>
00032 #include <isc/netaddr.h>
00033 #include <isc/random.h>
00034 #include <isc/stats.h>
00035 #include <isc/string.h>
00036 #include <isc/task.h>
00037 #include <isc/util.h>
00038
00039 #include <dns/adb.h>
00040 #include <dns/db.h>
00041 #include <dns/events.h>
00042 #include <dns/log.h>
00043 #include <dns/rdata.h>
00044 #include <dns/rdataset.h>
00045 #include <dns/rdatastruct.h>
00046 #include <dns/rdatatype.h>
00047 #include <dns/resolver.h>
00048 #include <dns/result.h>
00049 #include <dns/stats.h>
00050
00051 #define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b')
00052 #define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
00053 #define DNS_ADBNAME_MAGIC ISC_MAGIC('a', 'd', 'b', 'N')
00054 #define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
00055 #define DNS_ADBNAMEHOOK_MAGIC ISC_MAGIC('a', 'd', 'N', 'H')
00056 #define DNS_ADBNAMEHOOK_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
00057 #define DNS_ADBLAMEINFO_MAGIC ISC_MAGIC('a', 'd', 'b', 'Z')
00058 #define DNS_ADBLAMEINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBLAMEINFO_MAGIC)
00059 #define DNS_ADBENTRY_MAGIC ISC_MAGIC('a', 'd', 'b', 'E')
00060 #define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
00061 #define DNS_ADBFETCH_MAGIC ISC_MAGIC('a', 'd', 'F', '4')
00062 #define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
00063 #define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6')
00064 #define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
00065
00066
00067
00068
00069
00070
00071
00072 #define ADB_CACHE_MINIMUM 10
00073 #define ADB_CACHE_MAXIMUM 86400
00074 #define ADB_ENTRY_WINDOW 1800
00075
00076
00077
00078
00079
00080
00081 #ifndef ADB_STALE_MARGIN
00082 #define ADB_STALE_MARGIN 1800
00083 #endif
00084
00085 #define FREE_ITEMS 64
00086 #define FILL_COUNT 16
00087
00088 #define DNS_ADB_INVALIDBUCKET (-1)
00089
00090 #define DNS_ADB_MINADBSIZE (1024U*1024U)
00091
00092 typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
00093 typedef struct dns_adbnamehook dns_adbnamehook_t;
00094 typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
00095 typedef struct dns_adblameinfo dns_adblameinfo_t;
00096 typedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t;
00097 typedef struct dns_adbfetch dns_adbfetch_t;
00098 typedef struct dns_adbfetch6 dns_adbfetch6_t;
00099
00100
00101 struct dns_adb {
00102 unsigned int magic;
00103
00104 isc_mutex_t lock;
00105 isc_mutex_t reflock;
00106 isc_mutex_t overmemlock;
00107 isc_mem_t *mctx;
00108 dns_view_t *view;
00109
00110 isc_taskmgr_t *taskmgr;
00111 isc_task_t *task;
00112 isc_task_t *excl;
00113
00114 isc_interval_t tick_interval;
00115 int next_cleanbucket;
00116
00117 unsigned int irefcnt;
00118 unsigned int erefcnt;
00119
00120 isc_mutex_t mplock;
00121 isc_mempool_t *nmp;
00122 isc_mempool_t *nhmp;
00123 isc_mempool_t *limp;
00124 isc_mempool_t *emp;
00125 isc_mempool_t *ahmp;
00126 isc_mempool_t *aimp;
00127 isc_mempool_t *afmp;
00128
00129
00130
00131
00132
00133
00134 unsigned int nnames;
00135 isc_mutex_t namescntlock;
00136 unsigned int namescnt;
00137 dns_adbnamelist_t *names;
00138 dns_adbnamelist_t *deadnames;
00139 isc_mutex_t *namelocks;
00140 isc_boolean_t *name_sd;
00141 unsigned int *name_refcnt;
00142
00143
00144
00145
00146
00147
00148 unsigned int nentries;
00149 isc_mutex_t entriescntlock;
00150 unsigned int entriescnt;
00151 dns_adbentrylist_t *entries;
00152 dns_adbentrylist_t *deadentries;
00153 isc_mutex_t *entrylocks;
00154 isc_boolean_t *entry_sd;
00155 unsigned int *entry_refcnt;
00156
00157 isc_event_t cevent;
00158 isc_boolean_t cevent_out;
00159 isc_boolean_t shutting_down;
00160 isc_eventlist_t whenshutdown;
00161 isc_event_t growentries;
00162 isc_boolean_t growentries_sent;
00163 isc_event_t grownames;
00164 isc_boolean_t grownames_sent;
00165 };
00166
00167
00168
00169
00170
00171
00172 struct dns_adbname {
00173 unsigned int magic;
00174 dns_name_t name;
00175 dns_adb_t *adb;
00176 unsigned int partial_result;
00177 unsigned int flags;
00178 int lock_bucket;
00179 dns_name_t target;
00180 isc_stdtime_t expire_target;
00181 isc_stdtime_t expire_v4;
00182 isc_stdtime_t expire_v6;
00183 unsigned int chains;
00184 dns_adbnamehooklist_t v4;
00185 dns_adbnamehooklist_t v6;
00186 dns_adbfetch_t *fetch_a;
00187 dns_adbfetch_t *fetch_aaaa;
00188 unsigned int fetch_err;
00189 unsigned int fetch6_err;
00190 dns_adbfindlist_t finds;
00191
00192 isc_stdtime_t last_used;
00193
00194 ISC_LINK(dns_adbname_t) plink;
00195 };
00196
00197
00198 struct dns_adbfetch {
00199 unsigned int magic;
00200 dns_fetch_t *fetch;
00201 dns_rdataset_t rdataset;
00202 unsigned int depth;
00203 };
00204
00205
00206
00207
00208
00209
00210 struct dns_adbnamehook {
00211 unsigned int magic;
00212 dns_adbentry_t *entry;
00213 ISC_LINK(dns_adbnamehook_t) plink;
00214 };
00215
00216
00217
00218
00219
00220
00221 struct dns_adblameinfo {
00222 unsigned int magic;
00223
00224 dns_name_t qname;
00225 dns_rdatatype_t qtype;
00226 isc_stdtime_t lame_timer;
00227
00228 ISC_LINK(dns_adblameinfo_t) plink;
00229 };
00230
00231
00232
00233
00234
00235
00236 struct dns_adbentry {
00237 unsigned int magic;
00238
00239 int lock_bucket;
00240 unsigned int refcnt;
00241
00242 unsigned int flags;
00243 unsigned int srtt;
00244 isc_uint16_t udpsize;
00245 unsigned char plain;
00246 unsigned char plainto;
00247 unsigned char edns;
00248 unsigned char to4096;
00249
00250
00251
00252
00253 unsigned char to1432;
00254 unsigned char to1232;
00255 unsigned char to512;
00256 isc_sockaddr_t sockaddr;
00257 unsigned char * sit;
00258 isc_uint16_t sitlen;
00259
00260 isc_stdtime_t expires;
00261 isc_stdtime_t lastage;
00262
00263
00264
00265
00266
00267
00268
00269
00270 ISC_LIST(dns_adblameinfo_t) lameinfo;
00271 ISC_LINK(dns_adbentry_t) plink;
00272 };
00273
00274
00275
00276
00277 static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
00278 static inline void free_adbname(dns_adb_t *, dns_adbname_t **);
00279 static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
00280 dns_adbentry_t *);
00281 static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
00282 static inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *, dns_name_t *,
00283 dns_rdatatype_t);
00284 static inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **);
00285 static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
00286 static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
00287 static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
00288 static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
00289 static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
00290 in_port_t);
00291 static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
00292 static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
00293 static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
00294 unsigned int, int *);
00295 static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
00296 isc_sockaddr_t *, int *,
00297 isc_stdtime_t);
00298 static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t);
00299 static void print_dns_name(FILE *, dns_name_t *);
00300 static void print_namehook_list(FILE *, const char *legend,
00301 dns_adbnamehooklist_t *list,
00302 isc_boolean_t debug,
00303 isc_stdtime_t now);
00304 static void print_find_list(FILE *, dns_adbname_t *);
00305 static void print_fetch_list(FILE *, dns_adbname_t *);
00306 static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
00307 static inline void inc_adb_irefcnt(dns_adb_t *);
00308 static inline void inc_adb_erefcnt(dns_adb_t *);
00309 static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
00310 isc_boolean_t);
00311 static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, isc_boolean_t,
00312 dns_adbentry_t *, isc_boolean_t);
00313 static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
00314 static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
00315 static void clean_target(dns_adb_t *, dns_name_t *);
00316 static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, unsigned int);
00317 static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
00318 static isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **,
00319 isc_stdtime_t);
00320 static void cancel_fetches_at_name(dns_adbname_t *);
00321 static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
00322 dns_rdatatype_t);
00323 static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
00324 unsigned int, isc_counter_t *qc,
00325 dns_rdatatype_t);
00326 static inline void check_exit(dns_adb_t *);
00327 static void destroy(dns_adb_t *);
00328 static isc_boolean_t shutdown_names(dns_adb_t *);
00329 static isc_boolean_t shutdown_entries(dns_adb_t *);
00330 static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
00331 static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *);
00332 static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
00333 static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
00334 static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
00335 static void water(void *, int);
00336 static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t);
00337 static void adjustsrtt(dns_adbaddrinfo_t *addr, unsigned int rtt,
00338 unsigned int factor, isc_stdtime_t now);
00339 static void shutdown_task(isc_task_t *task, isc_event_t *ev);
00340
00341
00342
00343
00344 #define FIND_EVENT_SENT 0x40000000
00345 #define FIND_EVENT_FREED 0x80000000
00346 #define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0)
00347 #define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0)
00348
00349 #define NAME_NEEDS_POKE 0x80000000
00350 #define NAME_IS_DEAD 0x40000000
00351 #define NAME_HINT_OK DNS_ADBFIND_HINTOK
00352 #define NAME_GLUE_OK DNS_ADBFIND_GLUEOK
00353 #define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE
00354 #define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0)
00355 #define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0)
00356 #define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0)
00357 #define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0)
00358
00359
00360
00361
00362
00363 #define ENTRY_IS_DEAD 0x00400000
00364
00365
00366
00367
00368
00369 #define NAME_HAS_V4(n) (!ISC_LIST_EMPTY((n)->v4))
00370 #define NAME_HAS_V6(n) (!ISC_LIST_EMPTY((n)->v6))
00371 #define NAME_HAS_ADDRS(n) (NAME_HAS_V4(n) || NAME_HAS_V6(n))
00372
00373
00374
00375
00376
00377
00378
00379
00380 #define NAME_FETCH_A(n) ((n)->fetch_a != NULL)
00381 #define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL)
00382 #define NAME_FETCH_V4(n) (NAME_FETCH_A(n))
00383 #define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n))
00384 #define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
00385
00386
00387
00388
00389 #define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
00390 #define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
00391 #define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
00392 != 0)
00393 #define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \
00394 != 0)
00395 #define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
00396 #define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
00397 #define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list))
00398 #define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
00399
00400
00401
00402
00403
00404 #define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0)
00405 #define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0)
00406
00407 #define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now))
00408
00409
00410
00411
00412
00413
00414 #define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0))
00415 #define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0))
00416 #define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o))
00417 #define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \
00418 ((o) & DNS_ADBFIND_STARTATZONE))
00419
00420 #define ENTER_LEVEL ISC_LOG_DEBUG(50)
00421 #define EXIT_LEVEL ENTER_LEVEL
00422 #define CLEAN_LEVEL ISC_LOG_DEBUG(100)
00423 #define DEF_LEVEL ISC_LOG_DEBUG(5)
00424 #define NCACHE_LEVEL ISC_LOG_DEBUG(20)
00425
00426 #define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \
00427 (r) == DNS_R_NCACHENXRRSET)
00428 #define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \
00429 (r) == DNS_R_NXRRSET)
00430 #define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \
00431 (r) == DNS_R_NCACHENXDOMAIN)
00432 #define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \
00433 (r) == DNS_R_NXRRSET || \
00434 (r) == DNS_R_HINTNXRRSET)
00435
00436
00437
00438
00439
00440 #define FIND_ERR_SUCCESS 0
00441 #define FIND_ERR_CANCELED 1
00442 #define FIND_ERR_FAILURE 2
00443 #define FIND_ERR_NXDOMAIN 3
00444 #define FIND_ERR_NXRRSET 4
00445 #define FIND_ERR_UNEXPECTED 5
00446 #define FIND_ERR_NOTFOUND 6
00447 #define FIND_ERR_MAX 7
00448
00449 static const char *errnames[] = {
00450 "success",
00451 "canceled",
00452 "failure",
00453 "nxdomain",
00454 "nxrrset",
00455 "unexpected",
00456 "not_found"
00457 };
00458
00459 #define NEWERR(old, new) (ISC_MIN((old), (new)))
00460
00461 static isc_result_t find_err_map[FIND_ERR_MAX] = {
00462 ISC_R_SUCCESS,
00463 ISC_R_CANCELED,
00464 ISC_R_FAILURE,
00465 DNS_R_NXDOMAIN,
00466 DNS_R_NXRRSET,
00467 ISC_R_UNEXPECTED,
00468 ISC_R_NOTFOUND
00469 };
00470
00471 static void
00472 DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
00473
00474 static void
00475 DP(int level, const char *format, ...) {
00476 va_list args;
00477
00478 va_start(args, format);
00479 isc_log_vwrite(dns_lctx,
00480 DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
00481 level, format, args);
00482 va_end(args);
00483 }
00484
00485
00486
00487
00488 static inline void
00489 inc_stats(dns_adb_t *adb, isc_statscounter_t counter) {
00490 if (adb->view->resstats != NULL)
00491 isc_stats_increment(adb->view->resstats, counter);
00492 }
00493
00494
00495
00496
00497 static inline void
00498 set_adbstat(dns_adb_t *adb, isc_uint64_t val, isc_statscounter_t counter) {
00499 if (adb->view->adbstats != NULL)
00500 isc_stats_set(adb->view->adbstats, val, counter);
00501 }
00502
00503 static inline void
00504 dec_adbstats(dns_adb_t *adb, isc_statscounter_t counter) {
00505 if (adb->view->adbstats != NULL)
00506 isc_stats_decrement(adb->view->adbstats, counter);
00507 }
00508
00509 static inline void
00510 inc_adbstats(dns_adb_t *adb, isc_statscounter_t counter) {
00511 if (adb->view->adbstats != NULL)
00512 isc_stats_increment(adb->view->adbstats, counter);
00513 }
00514
00515 static inline dns_ttl_t
00516 ttlclamp(dns_ttl_t ttl) {
00517 if (ttl < ADB_CACHE_MINIMUM)
00518 ttl = ADB_CACHE_MINIMUM;
00519 if (ttl > ADB_CACHE_MAXIMUM)
00520 ttl = ADB_CACHE_MAXIMUM;
00521
00522 return (ttl);
00523 }
00524
00525
00526
00527
00528
00529
00530
00531 static const unsigned nbuckets[] = { 1021, 1531, 2039, 3067, 4093, 6143,
00532 8191, 12281, 16381, 24571, 32749,
00533 49193, 65521, 98299, 131071, 199603,
00534 262139, 393209, 524287, 768431, 1048573,
00535 1572853, 2097143, 3145721, 4194301,
00536 6291449, 8388593, 12582893, 16777213,
00537 25165813, 33554393, 50331599, 67108859,
00538 100663291, 134217689, 201326557,
00539 268535431, 0 };
00540
00541 static void
00542 grow_entries(isc_task_t *task, isc_event_t *ev) {
00543 dns_adb_t *adb;
00544 dns_adbentry_t *e;
00545 dns_adbentrylist_t *newdeadentries = NULL;
00546 dns_adbentrylist_t *newentries = NULL;
00547 isc_boolean_t *newentry_sd = NULL;
00548 isc_mutex_t *newentrylocks = NULL;
00549 isc_result_t result;
00550 unsigned int *newentry_refcnt = NULL;
00551 unsigned int i, n, bucket;
00552
00553 adb = ev->ev_arg;
00554 INSIST(DNS_ADB_VALID(adb));
00555
00556 isc_event_free(&ev);
00557
00558 result = isc_task_beginexclusive(task);
00559 if (result != ISC_R_SUCCESS)
00560 goto check_exit;
00561
00562 i = 0;
00563 while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i])
00564 i++;
00565 if (nbuckets[i] != 0)
00566 n = nbuckets[i];
00567 else
00568 goto done;
00569
00570 DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n);
00571
00572
00573
00574
00575 for (i = 0; i < adb->nentries; i++)
00576 if (adb->entry_sd[i])
00577 goto cleanup;
00578
00579
00580
00581
00582 newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n);
00583 newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n);
00584 newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n);
00585 newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n);
00586 newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n);
00587 if (newentries == NULL || newdeadentries == NULL ||
00588 newentrylocks == NULL || newentry_sd == NULL ||
00589 newentry_refcnt == NULL)
00590 goto cleanup;
00591
00592
00593
00594
00595 result = isc_mutexblock_init(newentrylocks, n);
00596 if (result != ISC_R_SUCCESS)
00597 goto cleanup;
00598
00599 for (i = 0; i < n; i++) {
00600 ISC_LIST_INIT(newentries[i]);
00601 ISC_LIST_INIT(newdeadentries[i]);
00602 newentry_sd[i] = ISC_FALSE;
00603 newentry_refcnt[i] = 0;
00604 adb->irefcnt++;
00605 }
00606
00607
00608
00609
00610 for (i = 0; i < adb->nentries; i++) {
00611 e = ISC_LIST_HEAD(adb->entries[i]);
00612 while (e != NULL) {
00613 ISC_LIST_UNLINK(adb->entries[i], e, plink);
00614 bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
00615 e->lock_bucket = bucket;
00616 ISC_LIST_APPEND(newentries[bucket], e, plink);
00617 INSIST(adb->entry_refcnt[i] > 0);
00618 adb->entry_refcnt[i]--;
00619 newentry_refcnt[bucket]++;
00620 e = ISC_LIST_HEAD(adb->entries[i]);
00621 }
00622 e = ISC_LIST_HEAD(adb->deadentries[i]);
00623 while (e != NULL) {
00624 ISC_LIST_UNLINK(adb->deadentries[i], e, plink);
00625 bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
00626 e->lock_bucket = bucket;
00627 ISC_LIST_APPEND(newdeadentries[bucket], e, plink);
00628 INSIST(adb->entry_refcnt[i] > 0);
00629 adb->entry_refcnt[i]--;
00630 newentry_refcnt[bucket]++;
00631 e = ISC_LIST_HEAD(adb->deadentries[i]);
00632 }
00633 INSIST(adb->entry_refcnt[i] == 0);
00634 adb->irefcnt--;
00635 }
00636
00637
00638
00639
00640 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
00641 isc_mem_put(adb->mctx, adb->entries,
00642 sizeof(*adb->entries) * adb->nentries);
00643 isc_mem_put(adb->mctx, adb->deadentries,
00644 sizeof(*adb->deadentries) * adb->nentries);
00645 isc_mem_put(adb->mctx, adb->entrylocks,
00646 sizeof(*adb->entrylocks) * adb->nentries);
00647 isc_mem_put(adb->mctx, adb->entry_sd,
00648 sizeof(*adb->entry_sd) * adb->nentries);
00649 isc_mem_put(adb->mctx, adb->entry_refcnt,
00650 sizeof(*adb->entry_refcnt) * adb->nentries);
00651
00652
00653
00654
00655 adb->entries = newentries;
00656 adb->deadentries = newdeadentries;
00657 adb->entrylocks = newentrylocks;
00658 adb->entry_sd = newentry_sd;
00659 adb->entry_refcnt = newentry_refcnt;
00660 adb->nentries = n;
00661
00662 set_adbstat(adb, adb->nentries, dns_adbstats_nentries);
00663
00664
00665
00666
00667
00668 adb->growentries_sent = ISC_FALSE;
00669 goto done;
00670
00671 cleanup:
00672 if (newentries != NULL)
00673 isc_mem_put(adb->mctx, newentries,
00674 sizeof(*newentries) * n);
00675 if (newdeadentries != NULL)
00676 isc_mem_put(adb->mctx, newdeadentries,
00677 sizeof(*newdeadentries) * n);
00678 if (newentrylocks != NULL)
00679 isc_mem_put(adb->mctx, newentrylocks,
00680 sizeof(*newentrylocks) * n);
00681 if (newentry_sd != NULL)
00682 isc_mem_put(adb->mctx, newentry_sd,
00683 sizeof(*newentry_sd) * n);
00684 if (newentry_refcnt != NULL)
00685 isc_mem_put(adb->mctx, newentry_refcnt,
00686 sizeof(*newentry_refcnt) * n);
00687 done:
00688 isc_task_endexclusive(task);
00689
00690 check_exit:
00691 LOCK(&adb->lock);
00692 if (dec_adb_irefcnt(adb))
00693 check_exit(adb);
00694 UNLOCK(&adb->lock);
00695 DP(ISC_LOG_INFO, "adb: grow_entries finished");
00696 }
00697
00698 static void
00699 grow_names(isc_task_t *task, isc_event_t *ev) {
00700 dns_adb_t *adb;
00701 dns_adbname_t *name;
00702 dns_adbnamelist_t *newdeadnames = NULL;
00703 dns_adbnamelist_t *newnames = NULL;
00704 isc_boolean_t *newname_sd = NULL;
00705 isc_mutex_t *newnamelocks = NULL;
00706 isc_result_t result;
00707 unsigned int *newname_refcnt = NULL;
00708 unsigned int i, n, bucket;
00709
00710 adb = ev->ev_arg;
00711 INSIST(DNS_ADB_VALID(adb));
00712
00713 isc_event_free(&ev);
00714
00715 result = isc_task_beginexclusive(task);
00716 if (result != ISC_R_SUCCESS)
00717 goto check_exit;
00718
00719 i = 0;
00720 while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i])
00721 i++;
00722 if (nbuckets[i] != 0)
00723 n = nbuckets[i];
00724 else
00725 goto done;
00726
00727 DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n);
00728
00729
00730
00731
00732 for (i = 0; i < adb->nnames; i++)
00733 if (adb->name_sd[i])
00734 goto cleanup;
00735
00736
00737
00738
00739 newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n);
00740 newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n);
00741 newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n);
00742 newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n);
00743 newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n);
00744 if (newnames == NULL || newdeadnames == NULL ||
00745 newnamelocks == NULL || newname_sd == NULL ||
00746 newname_refcnt == NULL)
00747 goto cleanup;
00748
00749
00750
00751
00752 result = isc_mutexblock_init(newnamelocks, n);
00753 if (result != ISC_R_SUCCESS)
00754 goto cleanup;
00755
00756 for (i = 0; i < n; i++) {
00757 ISC_LIST_INIT(newnames[i]);
00758 ISC_LIST_INIT(newdeadnames[i]);
00759 newname_sd[i] = ISC_FALSE;
00760 newname_refcnt[i] = 0;
00761 adb->irefcnt++;
00762 }
00763
00764
00765
00766
00767 for (i = 0; i < adb->nnames; i++) {
00768 name = ISC_LIST_HEAD(adb->names[i]);
00769 while (name != NULL) {
00770 ISC_LIST_UNLINK(adb->names[i], name, plink);
00771 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
00772 name->lock_bucket = bucket;
00773 ISC_LIST_APPEND(newnames[bucket], name, plink);
00774 INSIST(adb->name_refcnt[i] > 0);
00775 adb->name_refcnt[i]--;
00776 newname_refcnt[bucket]++;
00777 name = ISC_LIST_HEAD(adb->names[i]);
00778 }
00779 name = ISC_LIST_HEAD(adb->deadnames[i]);
00780 while (name != NULL) {
00781 ISC_LIST_UNLINK(adb->deadnames[i], name, plink);
00782 bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
00783 name->lock_bucket = bucket;
00784 ISC_LIST_APPEND(newdeadnames[bucket], name, plink);
00785 INSIST(adb->name_refcnt[i] > 0);
00786 adb->name_refcnt[i]--;
00787 newname_refcnt[bucket]++;
00788 name = ISC_LIST_HEAD(adb->deadnames[i]);
00789 }
00790 INSIST(adb->name_refcnt[i] == 0);
00791 adb->irefcnt--;
00792 }
00793
00794
00795
00796
00797 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
00798 isc_mem_put(adb->mctx, adb->names,
00799 sizeof(*adb->names) * adb->nnames);
00800 isc_mem_put(adb->mctx, adb->deadnames,
00801 sizeof(*adb->deadnames) * adb->nnames);
00802 isc_mem_put(adb->mctx, adb->namelocks,
00803 sizeof(*adb->namelocks) * adb->nnames);
00804 isc_mem_put(adb->mctx, adb->name_sd,
00805 sizeof(*adb->name_sd) * adb->nnames);
00806 isc_mem_put(adb->mctx, adb->name_refcnt,
00807 sizeof(*adb->name_refcnt) * adb->nnames);
00808
00809
00810
00811
00812 adb->names = newnames;
00813 adb->deadnames = newdeadnames;
00814 adb->namelocks = newnamelocks;
00815 adb->name_sd = newname_sd;
00816 adb->name_refcnt = newname_refcnt;
00817 adb->nnames = n;
00818
00819 set_adbstat(adb, adb->nnames, dns_adbstats_nnames);
00820
00821
00822
00823
00824
00825 adb->grownames_sent = ISC_FALSE;
00826 goto done;
00827
00828 cleanup:
00829 if (newnames != NULL)
00830 isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n);
00831 if (newdeadnames != NULL)
00832 isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n);
00833 if (newnamelocks != NULL)
00834 isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n);
00835 if (newname_sd != NULL)
00836 isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n);
00837 if (newname_refcnt != NULL)
00838 isc_mem_put(adb->mctx, newname_refcnt,
00839 sizeof(*newname_refcnt) * n);
00840 done:
00841 isc_task_endexclusive(task);
00842
00843 check_exit:
00844 LOCK(&adb->lock);
00845 if (dec_adb_irefcnt(adb))
00846 check_exit(adb);
00847 UNLOCK(&adb->lock);
00848 DP(ISC_LOG_INFO, "adb: grow_names finished");
00849 }
00850
00851
00852
00853
00854
00855
00856 static isc_result_t
00857 import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
00858 isc_stdtime_t now)
00859 {
00860 isc_result_t result;
00861 dns_adb_t *adb;
00862 dns_adbnamehook_t *nh;
00863 dns_adbnamehook_t *anh;
00864 dns_rdata_t rdata = DNS_RDATA_INIT;
00865 struct in_addr ina;
00866 struct in6_addr in6a;
00867 isc_sockaddr_t sockaddr;
00868 dns_adbentry_t *foundentry;
00869 int addr_bucket;
00870 isc_boolean_t new_addresses_added;
00871 dns_rdatatype_t rdtype;
00872 unsigned int findoptions;
00873 dns_adbnamehooklist_t *hookhead;
00874
00875 INSIST(DNS_ADBNAME_VALID(adbname));
00876 adb = adbname->adb;
00877 INSIST(DNS_ADB_VALID(adb));
00878
00879 rdtype = rdataset->type;
00880 INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
00881 if (rdtype == dns_rdatatype_a)
00882 findoptions = DNS_ADBFIND_INET;
00883 else
00884 findoptions = DNS_ADBFIND_INET6;
00885
00886 addr_bucket = DNS_ADB_INVALIDBUCKET;
00887 new_addresses_added = ISC_FALSE;
00888
00889 nh = NULL;
00890 result = dns_rdataset_first(rdataset);
00891 while (result == ISC_R_SUCCESS) {
00892 dns_rdata_reset(&rdata);
00893 dns_rdataset_current(rdataset, &rdata);
00894 if (rdtype == dns_rdatatype_a) {
00895 INSIST(rdata.length == 4);
00896 memmove(&ina.s_addr, rdata.data, 4);
00897 isc_sockaddr_fromin(&sockaddr, &ina, 0);
00898 hookhead = &adbname->v4;
00899 } else {
00900 INSIST(rdata.length == 16);
00901 memmove(in6a.s6_addr, rdata.data, 16);
00902 isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
00903 hookhead = &adbname->v6;
00904 }
00905
00906 INSIST(nh == NULL);
00907 nh = new_adbnamehook(adb, NULL);
00908 if (nh == NULL) {
00909 adbname->partial_result |= findoptions;
00910 result = ISC_R_NOMEMORY;
00911 goto fail;
00912 }
00913
00914 foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket,
00915 now);
00916 if (foundentry == NULL) {
00917 dns_adbentry_t *entry;
00918
00919 entry = new_adbentry(adb);
00920 if (entry == NULL) {
00921 adbname->partial_result |= findoptions;
00922 result = ISC_R_NOMEMORY;
00923 goto fail;
00924 }
00925
00926 entry->sockaddr = sockaddr;
00927 entry->refcnt = 1;
00928
00929 nh->entry = entry;
00930
00931 link_entry(adb, addr_bucket, entry);
00932 } else {
00933 for (anh = ISC_LIST_HEAD(*hookhead);
00934 anh != NULL;
00935 anh = ISC_LIST_NEXT(anh, plink))
00936 if (anh->entry == foundentry)
00937 break;
00938 if (anh == NULL) {
00939 foundentry->refcnt++;
00940 nh->entry = foundentry;
00941 } else
00942 free_adbnamehook(adb, &nh);
00943 }
00944
00945 new_addresses_added = ISC_TRUE;
00946 if (nh != NULL)
00947 ISC_LIST_APPEND(*hookhead, nh, plink);
00948 nh = NULL;
00949 result = dns_rdataset_next(rdataset);
00950 }
00951
00952 fail:
00953 if (nh != NULL)
00954 free_adbnamehook(adb, &nh);
00955
00956 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
00957 UNLOCK(&adb->entrylocks[addr_bucket]);
00958
00959 if (rdataset->trust == dns_trust_glue ||
00960 rdataset->trust == dns_trust_additional)
00961 rdataset->ttl = ADB_CACHE_MINIMUM;
00962 else if (rdataset->trust == dns_trust_ultimate)
00963 rdataset->ttl = 0;
00964 else
00965 rdataset->ttl = ttlclamp(rdataset->ttl);
00966
00967 if (rdtype == dns_rdatatype_a) {
00968 DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
00969 adbname->expire_v4, now + rdataset->ttl);
00970 adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
00971 ISC_MIN(now + ADB_ENTRY_WINDOW,
00972 now + rdataset->ttl));
00973 } else {
00974 DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
00975 adbname->expire_v6, now + rdataset->ttl);
00976 adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
00977 ISC_MIN(now + ADB_ENTRY_WINDOW,
00978 now + rdataset->ttl));
00979 }
00980
00981 if (new_addresses_added) {
00982
00983
00984
00985
00986 return (ISC_R_SUCCESS);
00987 }
00988
00989 return (result);
00990 }
00991
00992
00993
00994
00995 static isc_boolean_t
00996 kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
00997 dns_adbname_t *name;
00998 isc_boolean_t result = ISC_FALSE;
00999 isc_boolean_t result4, result6;
01000 int bucket;
01001 dns_adb_t *adb;
01002
01003 INSIST(n != NULL);
01004 name = *n;
01005 *n = NULL;
01006 INSIST(DNS_ADBNAME_VALID(name));
01007 adb = name->adb;
01008 INSIST(DNS_ADB_VALID(adb));
01009
01010 DP(DEF_LEVEL, "killing name %p", name);
01011
01012
01013
01014
01015
01016 if (NAME_DEAD(name) && !NAME_FETCH(name)) {
01017 result = unlink_name(adb, name);
01018 free_adbname(adb, &name);
01019 if (result)
01020 result = dec_adb_irefcnt(adb);
01021 return (result);
01022 }
01023
01024
01025
01026
01027
01028 clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
01029 result4 = clean_namehooks(adb, &name->v4);
01030 result6 = clean_namehooks(adb, &name->v6);
01031 clean_target(adb, &name->target);
01032 result = ISC_TF(result4 || result6);
01033
01034
01035
01036
01037
01038 if (!NAME_FETCH(name)) {
01039 INSIST(result == ISC_FALSE);
01040 result = unlink_name(adb, name);
01041 free_adbname(adb, &name);
01042 if (result)
01043 result = dec_adb_irefcnt(adb);
01044 } else {
01045 cancel_fetches_at_name(name);
01046 if (!NAME_DEAD(name)) {
01047 bucket = name->lock_bucket;
01048 ISC_LIST_UNLINK(adb->names[bucket], name, plink);
01049 ISC_LIST_APPEND(adb->deadnames[bucket], name, plink);
01050 name->flags |= NAME_IS_DEAD;
01051 }
01052 }
01053 return (result);
01054 }
01055
01056
01057
01058
01059 static isc_boolean_t
01060 check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
01061 dns_adb_t *adb;
01062 isc_boolean_t result4 = ISC_FALSE;
01063 isc_boolean_t result6 = ISC_FALSE;
01064
01065 INSIST(DNS_ADBNAME_VALID(name));
01066 adb = name->adb;
01067 INSIST(DNS_ADB_VALID(adb));
01068
01069
01070
01071
01072 if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) {
01073 if (NAME_HAS_V4(name)) {
01074 DP(DEF_LEVEL, "expiring v4 for name %p", name);
01075 result4 = clean_namehooks(adb, &name->v4);
01076 name->partial_result &= ~DNS_ADBFIND_INET;
01077 }
01078 name->expire_v4 = INT_MAX;
01079 name->fetch_err = FIND_ERR_UNEXPECTED;
01080 }
01081
01082
01083
01084
01085 if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) {
01086 if (NAME_HAS_V6(name)) {
01087 DP(DEF_LEVEL, "expiring v6 for name %p", name);
01088 result6 = clean_namehooks(adb, &name->v6);
01089 name->partial_result &= ~DNS_ADBFIND_INET6;
01090 }
01091 name->expire_v6 = INT_MAX;
01092 name->fetch6_err = FIND_ERR_UNEXPECTED;
01093 }
01094
01095
01096
01097
01098 if (EXPIRE_OK(name->expire_target, now)) {
01099 clean_target(adb, &name->target);
01100 name->expire_target = INT_MAX;
01101 }
01102 return (ISC_TF(result4 || result6));
01103 }
01104
01105
01106
01107
01108 static inline void
01109 link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
01110 INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
01111
01112 ISC_LIST_PREPEND(adb->names[bucket], name, plink);
01113 name->lock_bucket = bucket;
01114 adb->name_refcnt[bucket]++;
01115 }
01116
01117
01118
01119
01120 static inline isc_boolean_t
01121 unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
01122 int bucket;
01123 isc_boolean_t result = ISC_FALSE;
01124
01125 bucket = name->lock_bucket;
01126 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
01127
01128 if (NAME_DEAD(name))
01129 ISC_LIST_UNLINK(adb->deadnames[bucket], name, plink);
01130 else
01131 ISC_LIST_UNLINK(adb->names[bucket], name, plink);
01132 name->lock_bucket = DNS_ADB_INVALIDBUCKET;
01133 INSIST(adb->name_refcnt[bucket] > 0);
01134 adb->name_refcnt[bucket]--;
01135 if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
01136 result = ISC_TRUE;
01137 return (result);
01138 }
01139
01140
01141
01142
01143 static inline void
01144 link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
01145 int i;
01146 dns_adbentry_t *e;
01147
01148 if (isc_mem_isovermem(adb->mctx)) {
01149 for (i = 0; i < 2; i++) {
01150 e = ISC_LIST_TAIL(adb->entries[bucket]);
01151 if (e == NULL)
01152 break;
01153 if (e->refcnt == 0) {
01154 unlink_entry(adb, e);
01155 free_adbentry(adb, &e);
01156 continue;
01157 }
01158 INSIST((e->flags & ENTRY_IS_DEAD) == 0);
01159 e->flags |= ENTRY_IS_DEAD;
01160 ISC_LIST_UNLINK(adb->entries[bucket], e, plink);
01161 ISC_LIST_PREPEND(adb->deadentries[bucket], e, plink);
01162 }
01163 }
01164
01165 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
01166 entry->lock_bucket = bucket;
01167 adb->entry_refcnt[bucket]++;
01168 }
01169
01170
01171
01172
01173 static inline isc_boolean_t
01174 unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
01175 int bucket;
01176 isc_boolean_t result = ISC_FALSE;
01177
01178 bucket = entry->lock_bucket;
01179 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
01180
01181 if ((entry->flags & ENTRY_IS_DEAD) != 0)
01182 ISC_LIST_UNLINK(adb->deadentries[bucket], entry, plink);
01183 else
01184 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
01185 entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
01186 INSIST(adb->entry_refcnt[bucket] > 0);
01187 adb->entry_refcnt[bucket]--;
01188 if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
01189 result = ISC_TRUE;
01190 return (result);
01191 }
01192
01193 static inline void
01194 violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
01195 if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
01196 UNLOCK(have);
01197 LOCK(want);
01198 LOCK(have);
01199 }
01200 }
01201
01202
01203
01204
01205
01206 static isc_boolean_t
01207 shutdown_names(dns_adb_t *adb) {
01208 unsigned int bucket;
01209 isc_boolean_t result = ISC_FALSE;
01210 dns_adbname_t *name;
01211 dns_adbname_t *next_name;
01212
01213 for (bucket = 0; bucket < adb->nnames; bucket++) {
01214 LOCK(&adb->namelocks[bucket]);
01215 adb->name_sd[bucket] = ISC_TRUE;
01216
01217 name = ISC_LIST_HEAD(adb->names[bucket]);
01218 if (name == NULL) {
01219
01220
01221
01222
01223
01224 INSIST(result == ISC_FALSE);
01225 result = dec_adb_irefcnt(adb);
01226 } else {
01227
01228
01229
01230
01231
01232
01233 while (name != NULL) {
01234 next_name = ISC_LIST_NEXT(name, plink);
01235 INSIST(result == ISC_FALSE);
01236 result = kill_name(&name,
01237 DNS_EVENT_ADBSHUTDOWN);
01238 name = next_name;
01239 }
01240 }
01241
01242 UNLOCK(&adb->namelocks[bucket]);
01243 }
01244 return (result);
01245 }
01246
01247
01248
01249
01250
01251 static isc_boolean_t
01252 shutdown_entries(dns_adb_t *adb) {
01253 unsigned int bucket;
01254 isc_boolean_t result = ISC_FALSE;
01255 dns_adbentry_t *entry;
01256 dns_adbentry_t *next_entry;
01257
01258 for (bucket = 0; bucket < adb->nentries; bucket++) {
01259 LOCK(&adb->entrylocks[bucket]);
01260 adb->entry_sd[bucket] = ISC_TRUE;
01261
01262 entry = ISC_LIST_HEAD(adb->entries[bucket]);
01263 if (adb->entry_refcnt[bucket] == 0) {
01264
01265
01266
01267
01268
01269 result = dec_adb_irefcnt(adb);
01270 } else {
01271
01272
01273
01274
01275 while (entry != NULL) {
01276 next_entry = ISC_LIST_NEXT(entry, plink);
01277 if (entry->refcnt == 0 &&
01278 entry->expires != 0) {
01279 result = unlink_entry(adb, entry);
01280 free_adbentry(adb, &entry);
01281 if (result)
01282 result = dec_adb_irefcnt(adb);
01283 }
01284 entry = next_entry;
01285 }
01286 }
01287
01288 UNLOCK(&adb->entrylocks[bucket]);
01289 }
01290 return (result);
01291 }
01292
01293
01294
01295
01296 static void
01297 cancel_fetches_at_name(dns_adbname_t *name) {
01298 if (NAME_FETCH_A(name))
01299 dns_resolver_cancelfetch(name->fetch_a->fetch);
01300
01301 if (NAME_FETCH_AAAA(name))
01302 dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
01303 }
01304
01305
01306
01307
01308 static isc_boolean_t
01309 clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
01310 dns_adbentry_t *entry;
01311 dns_adbnamehook_t *namehook;
01312 int addr_bucket;
01313 isc_boolean_t result = ISC_FALSE;
01314 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
01315
01316 addr_bucket = DNS_ADB_INVALIDBUCKET;
01317 namehook = ISC_LIST_HEAD(*namehooks);
01318 while (namehook != NULL) {
01319 INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
01320
01321
01322
01323
01324 entry = namehook->entry;
01325 if (entry != NULL) {
01326 INSIST(DNS_ADBENTRY_VALID(entry));
01327
01328 if (addr_bucket != entry->lock_bucket) {
01329 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
01330 UNLOCK(&adb->entrylocks[addr_bucket]);
01331 addr_bucket = entry->lock_bucket;
01332 INSIST(addr_bucket != DNS_ADB_INVALIDBUCKET);
01333 LOCK(&adb->entrylocks[addr_bucket]);
01334 }
01335
01336 result = dec_entry_refcnt(adb, overmem, entry,
01337 ISC_FALSE);
01338 }
01339
01340
01341
01342
01343 namehook->entry = NULL;
01344 ISC_LIST_UNLINK(*namehooks, namehook, plink);
01345 free_adbnamehook(adb, &namehook);
01346
01347 namehook = ISC_LIST_HEAD(*namehooks);
01348 }
01349
01350 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
01351 UNLOCK(&adb->entrylocks[addr_bucket]);
01352 return (result);
01353 }
01354
01355 static void
01356 clean_target(dns_adb_t *adb, dns_name_t *target) {
01357 if (dns_name_countlabels(target) > 0) {
01358 dns_name_free(target, adb->mctx);
01359 dns_name_init(target, NULL);
01360 }
01361 }
01362
01363 static isc_result_t
01364 set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
01365 dns_rdataset_t *rdataset, dns_name_t *target)
01366 {
01367 isc_result_t result;
01368 dns_namereln_t namereln;
01369 unsigned int nlabels;
01370 int order;
01371 dns_rdata_t rdata = DNS_RDATA_INIT;
01372 dns_fixedname_t fixed1, fixed2;
01373 dns_name_t *prefix, *new_target;
01374
01375 REQUIRE(dns_name_countlabels(target) == 0);
01376
01377 if (rdataset->type == dns_rdatatype_cname) {
01378 dns_rdata_cname_t cname;
01379
01380
01381
01382
01383 result = dns_rdataset_first(rdataset);
01384 if (result != ISC_R_SUCCESS)
01385 return (result);
01386 dns_rdataset_current(rdataset, &rdata);
01387 result = dns_rdata_tostruct(&rdata, &cname, NULL);
01388 if (result != ISC_R_SUCCESS)
01389 return (result);
01390 result = dns_name_dup(&cname.cname, adb->mctx, target);
01391 dns_rdata_freestruct(&cname);
01392 if (result != ISC_R_SUCCESS)
01393 return (result);
01394 } else {
01395 dns_rdata_dname_t dname;
01396
01397 INSIST(rdataset->type == dns_rdatatype_dname);
01398 namereln = dns_name_fullcompare(name, fname, &order, &nlabels);
01399 INSIST(namereln == dns_namereln_subdomain);
01400
01401
01402
01403 result = dns_rdataset_first(rdataset);
01404 if (result != ISC_R_SUCCESS)
01405 return (result);
01406 dns_rdataset_current(rdataset, &rdata);
01407 result = dns_rdata_tostruct(&rdata, &dname, NULL);
01408 if (result != ISC_R_SUCCESS)
01409 return (result);
01410
01411
01412
01413 dns_fixedname_init(&fixed1);
01414 prefix = dns_fixedname_name(&fixed1);
01415 dns_fixedname_init(&fixed2);
01416 new_target = dns_fixedname_name(&fixed2);
01417 dns_name_split(name, nlabels, prefix, NULL);
01418 result = dns_name_concatenate(prefix, &dname.dname, new_target,
01419 NULL);
01420 dns_rdata_freestruct(&dname);
01421 if (result != ISC_R_SUCCESS)
01422 return (result);
01423 result = dns_name_dup(new_target, adb->mctx, target);
01424 if (result != ISC_R_SUCCESS)
01425 return (result);
01426 }
01427
01428 return (ISC_R_SUCCESS);
01429 }
01430
01431
01432
01433
01434 static void
01435 event_free(isc_event_t *event) {
01436 dns_adbfind_t *find;
01437
01438 INSIST(event != NULL);
01439 find = event->ev_destroy_arg;
01440 INSIST(DNS_ADBFIND_VALID(find));
01441
01442 LOCK(&find->lock);
01443 find->flags |= FIND_EVENT_FREED;
01444 event->ev_destroy_arg = NULL;
01445 UNLOCK(&find->lock);
01446 }
01447
01448
01449
01450
01451 static void
01452 clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
01453 unsigned int addrs)
01454 {
01455 isc_event_t *ev;
01456 isc_task_t *task;
01457 dns_adbfind_t *find;
01458 dns_adbfind_t *next_find;
01459 isc_boolean_t process;
01460 unsigned int wanted, notify;
01461
01462 DP(ENTER_LEVEL,
01463 "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
01464 name, evtype, addrs);
01465
01466 find = ISC_LIST_HEAD(name->finds);
01467 while (find != NULL) {
01468 LOCK(&find->lock);
01469 next_find = ISC_LIST_NEXT(find, plink);
01470
01471 process = ISC_FALSE;
01472 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
01473 notify = wanted & addrs;
01474
01475 switch (evtype) {
01476 case DNS_EVENT_ADBMOREADDRESSES:
01477 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES");
01478 if ((notify) != 0) {
01479 find->flags &= ~addrs;
01480 process = ISC_TRUE;
01481 }
01482 break;
01483 case DNS_EVENT_ADBNOMOREADDRESSES:
01484 DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES");
01485 find->flags &= ~addrs;
01486 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
01487 if (wanted == 0)
01488 process = ISC_TRUE;
01489 break;
01490 default:
01491 find->flags &= ~addrs;
01492 process = ISC_TRUE;
01493 }
01494
01495 if (process) {
01496 DP(DEF_LEVEL, "cfan: processing find %p", find);
01497
01498
01499
01500
01501
01502 ISC_LIST_UNLINK(name->finds, find, plink);
01503 find->adbname = NULL;
01504 find->name_bucket = DNS_ADB_INVALIDBUCKET;
01505
01506 INSIST(!FIND_EVENTSENT(find));
01507
01508 ev = &find->event;
01509 task = ev->ev_sender;
01510 ev->ev_sender = find;
01511 find->result_v4 = find_err_map[name->fetch_err];
01512 find->result_v6 = find_err_map[name->fetch6_err];
01513 ev->ev_type = evtype;
01514 ev->ev_destroy = event_free;
01515 ev->ev_destroy_arg = find;
01516
01517 DP(DEF_LEVEL,
01518 "sending event %p to task %p for find %p",
01519 ev, task, find);
01520
01521 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
01522 find->flags |= FIND_EVENT_SENT;
01523 } else {
01524 DP(DEF_LEVEL, "cfan: skipping find %p", find);
01525 }
01526
01527 UNLOCK(&find->lock);
01528 find = next_find;
01529 }
01530
01531 DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
01532 }
01533
01534 static inline void
01535 check_exit(dns_adb_t *adb) {
01536 isc_event_t *event;
01537
01538
01539
01540 if (adb->shutting_down) {
01541
01542
01543
01544
01545 INSIST(!adb->cevent_out);
01546 ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
01547 DNS_EVENT_ADBCONTROL, shutdown_task, adb,
01548 adb, NULL, NULL);
01549 event = &adb->cevent;
01550 isc_task_send(adb->task, &event);
01551 adb->cevent_out = ISC_TRUE;
01552 }
01553 }
01554
01555 static inline isc_boolean_t
01556 dec_adb_irefcnt(dns_adb_t *adb) {
01557 isc_event_t *event;
01558 isc_task_t *etask;
01559 isc_boolean_t result = ISC_FALSE;
01560
01561 LOCK(&adb->reflock);
01562
01563 INSIST(adb->irefcnt > 0);
01564 adb->irefcnt--;
01565
01566 if (adb->irefcnt == 0) {
01567 event = ISC_LIST_HEAD(adb->whenshutdown);
01568 while (event != NULL) {
01569 ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
01570 etask = event->ev_sender;
01571 event->ev_sender = adb;
01572 isc_task_sendanddetach(&etask, &event);
01573 event = ISC_LIST_HEAD(adb->whenshutdown);
01574 }
01575 }
01576
01577 if (adb->irefcnt == 0 && adb->erefcnt == 0)
01578 result = ISC_TRUE;
01579 UNLOCK(&adb->reflock);
01580 return (result);
01581 }
01582
01583 static inline void
01584 inc_adb_irefcnt(dns_adb_t *adb) {
01585 LOCK(&adb->reflock);
01586 adb->irefcnt++;
01587 UNLOCK(&adb->reflock);
01588 }
01589
01590 static inline void
01591 inc_adb_erefcnt(dns_adb_t *adb) {
01592 LOCK(&adb->reflock);
01593 adb->erefcnt++;
01594 UNLOCK(&adb->reflock);
01595 }
01596
01597 static inline void
01598 inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
01599 int bucket;
01600
01601 bucket = entry->lock_bucket;
01602
01603 if (lock)
01604 LOCK(&adb->entrylocks[bucket]);
01605
01606 entry->refcnt++;
01607
01608 if (lock)
01609 UNLOCK(&adb->entrylocks[bucket]);
01610 }
01611
01612 static inline isc_boolean_t
01613 dec_entry_refcnt(dns_adb_t *adb, isc_boolean_t overmem, dns_adbentry_t *entry,
01614 isc_boolean_t lock)
01615 {
01616 int bucket;
01617 isc_boolean_t destroy_entry;
01618 isc_boolean_t result = ISC_FALSE;
01619
01620 bucket = entry->lock_bucket;
01621
01622 if (lock)
01623 LOCK(&adb->entrylocks[bucket]);
01624
01625 INSIST(entry->refcnt > 0);
01626 entry->refcnt--;
01627
01628 destroy_entry = ISC_FALSE;
01629 if (entry->refcnt == 0 &&
01630 (adb->entry_sd[bucket] || entry->expires == 0 || overmem ||
01631 (entry->flags & ENTRY_IS_DEAD) != 0)) {
01632 destroy_entry = ISC_TRUE;
01633 result = unlink_entry(adb, entry);
01634 }
01635
01636 if (lock)
01637 UNLOCK(&adb->entrylocks[bucket]);
01638
01639 if (!destroy_entry)
01640 return (result);
01641
01642 entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
01643
01644 free_adbentry(adb, &entry);
01645 if (result)
01646 result = dec_adb_irefcnt(adb);
01647
01648 return (result);
01649 }
01650
01651 static inline dns_adbname_t *
01652 new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
01653 dns_adbname_t *name;
01654
01655 name = isc_mempool_get(adb->nmp);
01656 if (name == NULL)
01657 return (NULL);
01658
01659 dns_name_init(&name->name, NULL);
01660 if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
01661 isc_mempool_put(adb->nmp, name);
01662 return (NULL);
01663 }
01664 dns_name_init(&name->target, NULL);
01665 name->magic = DNS_ADBNAME_MAGIC;
01666 name->adb = adb;
01667 name->partial_result = 0;
01668 name->flags = 0;
01669 name->expire_v4 = INT_MAX;
01670 name->expire_v6 = INT_MAX;
01671 name->expire_target = INT_MAX;
01672 name->chains = 0;
01673 name->lock_bucket = DNS_ADB_INVALIDBUCKET;
01674 ISC_LIST_INIT(name->v4);
01675 ISC_LIST_INIT(name->v6);
01676 name->fetch_a = NULL;
01677 name->fetch_aaaa = NULL;
01678 name->fetch_err = FIND_ERR_UNEXPECTED;
01679 name->fetch6_err = FIND_ERR_UNEXPECTED;
01680 ISC_LIST_INIT(name->finds);
01681 ISC_LINK_INIT(name, plink);
01682
01683 LOCK(&adb->namescntlock);
01684 adb->namescnt++;
01685 inc_adbstats(adb, dns_adbstats_namescnt);
01686 if (!adb->grownames_sent && adb->excl != NULL &&
01687 adb->namescnt > (adb->nnames * 8))
01688 {
01689 isc_event_t *event = &adb->grownames;
01690 inc_adb_irefcnt(adb);
01691 isc_task_send(adb->excl, &event);
01692 adb->grownames_sent = ISC_TRUE;
01693 }
01694 UNLOCK(&adb->namescntlock);
01695
01696 return (name);
01697 }
01698
01699 static inline void
01700 free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
01701 dns_adbname_t *n;
01702
01703 INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
01704 n = *name;
01705 *name = NULL;
01706
01707 INSIST(!NAME_HAS_V4(n));
01708 INSIST(!NAME_HAS_V6(n));
01709 INSIST(!NAME_FETCH(n));
01710 INSIST(ISC_LIST_EMPTY(n->finds));
01711 INSIST(!ISC_LINK_LINKED(n, plink));
01712 INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
01713 INSIST(n->adb == adb);
01714
01715 n->magic = 0;
01716 dns_name_free(&n->name, adb->mctx);
01717
01718 isc_mempool_put(adb->nmp, n);
01719 LOCK(&adb->namescntlock);
01720 adb->namescnt--;
01721 dec_adbstats(adb, dns_adbstats_namescnt);
01722 UNLOCK(&adb->namescntlock);
01723 }
01724
01725 static inline dns_adbnamehook_t *
01726 new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) {
01727 dns_adbnamehook_t *nh;
01728
01729 nh = isc_mempool_get(adb->nhmp);
01730 if (nh == NULL)
01731 return (NULL);
01732
01733 nh->magic = DNS_ADBNAMEHOOK_MAGIC;
01734 nh->entry = entry;
01735 ISC_LINK_INIT(nh, plink);
01736
01737 return (nh);
01738 }
01739
01740 static inline void
01741 free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) {
01742 dns_adbnamehook_t *nh;
01743
01744 INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
01745 nh = *namehook;
01746 *namehook = NULL;
01747
01748 INSIST(nh->entry == NULL);
01749 INSIST(!ISC_LINK_LINKED(nh, plink));
01750
01751 nh->magic = 0;
01752 isc_mempool_put(adb->nhmp, nh);
01753 }
01754
01755 static inline dns_adblameinfo_t *
01756 new_adblameinfo(dns_adb_t *adb, dns_name_t *qname, dns_rdatatype_t qtype) {
01757 dns_adblameinfo_t *li;
01758
01759 li = isc_mempool_get(adb->limp);
01760 if (li == NULL)
01761 return (NULL);
01762
01763 dns_name_init(&li->qname, NULL);
01764 if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) {
01765 isc_mempool_put(adb->limp, li);
01766 return (NULL);
01767 }
01768 li->magic = DNS_ADBLAMEINFO_MAGIC;
01769 li->lame_timer = 0;
01770 li->qtype = qtype;
01771 ISC_LINK_INIT(li, plink);
01772
01773 return (li);
01774 }
01775
01776 static inline void
01777 free_adblameinfo(dns_adb_t *adb, dns_adblameinfo_t **lameinfo) {
01778 dns_adblameinfo_t *li;
01779
01780 INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo));
01781 li = *lameinfo;
01782 *lameinfo = NULL;
01783
01784 INSIST(!ISC_LINK_LINKED(li, plink));
01785
01786 dns_name_free(&li->qname, adb->mctx);
01787
01788 li->magic = 0;
01789
01790 isc_mempool_put(adb->limp, li);
01791 }
01792
01793 static inline dns_adbentry_t *
01794 new_adbentry(dns_adb_t *adb) {
01795 dns_adbentry_t *e;
01796 isc_uint32_t r;
01797
01798 e = isc_mempool_get(adb->emp);
01799 if (e == NULL)
01800 return (NULL);
01801
01802 e->magic = DNS_ADBENTRY_MAGIC;
01803 e->lock_bucket = DNS_ADB_INVALIDBUCKET;
01804 e->refcnt = 0;
01805 e->flags = 0;
01806 e->udpsize = 0;
01807 e->edns = 0;
01808 e->plain = 0;
01809 e->plainto = 0;
01810 e->to4096 = 0;
01811 e->to1432 = 0;
01812 e->to1232 = 0;
01813 e->to512 = 0;
01814 e->sit = NULL;
01815 e->sitlen = 0;
01816 isc_random_get(&r);
01817 e->srtt = (r & 0x1f) + 1;
01818 e->lastage = 0;
01819 e->expires = 0;
01820 ISC_LIST_INIT(e->lameinfo);
01821 ISC_LINK_INIT(e, plink);
01822 LOCK(&adb->entriescntlock);
01823 adb->entriescnt++;
01824 inc_adbstats(adb, dns_adbstats_entriescnt);
01825 if (!adb->growentries_sent && adb->excl != NULL &&
01826 adb->entriescnt > (adb->nentries * 8))
01827 {
01828 isc_event_t *event = &adb->growentries;
01829 inc_adb_irefcnt(adb);
01830 isc_task_send(adb->excl, &event);
01831 adb->growentries_sent = ISC_TRUE;
01832 }
01833 UNLOCK(&adb->entriescntlock);
01834
01835 return (e);
01836 }
01837
01838 static inline void
01839 free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
01840 dns_adbentry_t *e;
01841 dns_adblameinfo_t *li;
01842
01843 INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
01844 e = *entry;
01845 *entry = NULL;
01846
01847 INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
01848 INSIST(e->refcnt == 0);
01849 INSIST(!ISC_LINK_LINKED(e, plink));
01850
01851 e->magic = 0;
01852
01853 if (e->sit != NULL)
01854 isc_mem_put(adb->mctx, e->sit, e->sitlen);
01855
01856 li = ISC_LIST_HEAD(e->lameinfo);
01857 while (li != NULL) {
01858 ISC_LIST_UNLINK(e->lameinfo, li, plink);
01859 free_adblameinfo(adb, &li);
01860 li = ISC_LIST_HEAD(e->lameinfo);
01861 }
01862
01863 isc_mempool_put(adb->emp, e);
01864 LOCK(&adb->entriescntlock);
01865 adb->entriescnt--;
01866 dec_adbstats(adb, dns_adbstats_entriescnt);
01867 UNLOCK(&adb->entriescntlock);
01868 }
01869
01870 static inline dns_adbfind_t *
01871 new_adbfind(dns_adb_t *adb) {
01872 dns_adbfind_t *h;
01873 isc_result_t result;
01874
01875 h = isc_mempool_get(adb->ahmp);
01876 if (h == NULL)
01877 return (NULL);
01878
01879
01880
01881
01882 h->magic = 0;
01883 h->adb = adb;
01884 h->partial_result = 0;
01885 h->options = 0;
01886 h->flags = 0;
01887 h->result_v4 = ISC_R_UNEXPECTED;
01888 h->result_v6 = ISC_R_UNEXPECTED;
01889 ISC_LINK_INIT(h, publink);
01890 ISC_LINK_INIT(h, plink);
01891 ISC_LIST_INIT(h->list);
01892 h->adbname = NULL;
01893 h->name_bucket = DNS_ADB_INVALIDBUCKET;
01894
01895
01896
01897
01898 result = isc_mutex_init(&h->lock);
01899 if (result != ISC_R_SUCCESS) {
01900 isc_mempool_put(adb->ahmp, h);
01901 return (NULL);
01902 }
01903
01904 ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
01905 NULL, NULL, h);
01906
01907 inc_adb_irefcnt(adb);
01908 h->magic = DNS_ADBFIND_MAGIC;
01909 return (h);
01910 }
01911
01912 static inline dns_adbfetch_t *
01913 new_adbfetch(dns_adb_t *adb) {
01914 dns_adbfetch_t *f;
01915
01916 f = isc_mempool_get(adb->afmp);
01917 if (f == NULL)
01918 return (NULL);
01919
01920 f->magic = 0;
01921 f->fetch = NULL;
01922
01923 dns_rdataset_init(&f->rdataset);
01924
01925 f->magic = DNS_ADBFETCH_MAGIC;
01926
01927 return (f);
01928 }
01929
01930 static inline void
01931 free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) {
01932 dns_adbfetch_t *f;
01933
01934 INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
01935 f = *fetch;
01936 *fetch = NULL;
01937
01938 f->magic = 0;
01939
01940 if (dns_rdataset_isassociated(&f->rdataset))
01941 dns_rdataset_disassociate(&f->rdataset);
01942
01943 isc_mempool_put(adb->afmp, f);
01944 }
01945
01946 static inline isc_boolean_t
01947 free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
01948 dns_adbfind_t *find;
01949
01950 INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
01951 find = *findp;
01952 *findp = NULL;
01953
01954 INSIST(!FIND_HAS_ADDRS(find));
01955 INSIST(!ISC_LINK_LINKED(find, publink));
01956 INSIST(!ISC_LINK_LINKED(find, plink));
01957 INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
01958 INSIST(find->adbname == NULL);
01959
01960 find->magic = 0;
01961
01962 DESTROYLOCK(&find->lock);
01963 isc_mempool_put(adb->ahmp, find);
01964 return (dec_adb_irefcnt(adb));
01965 }
01966
01967
01968
01969
01970
01971
01972 static inline dns_adbaddrinfo_t *
01973 new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
01974 dns_adbaddrinfo_t *ai;
01975
01976 ai = isc_mempool_get(adb->aimp);
01977 if (ai == NULL)
01978 return (NULL);
01979
01980 ai->magic = DNS_ADBADDRINFO_MAGIC;
01981 ai->sockaddr = entry->sockaddr;
01982 isc_sockaddr_setport(&ai->sockaddr, port);
01983 ai->srtt = entry->srtt;
01984 ai->flags = entry->flags;
01985 ai->entry = entry;
01986 ai->dscp = -1;
01987 ISC_LINK_INIT(ai, publink);
01988
01989 return (ai);
01990 }
01991
01992 static inline void
01993 free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
01994 dns_adbaddrinfo_t *ai;
01995
01996 INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
01997 ai = *ainfo;
01998 *ainfo = NULL;
01999
02000 INSIST(ai->entry == NULL);
02001 INSIST(!ISC_LINK_LINKED(ai, publink));
02002
02003 ai->magic = 0;
02004
02005 isc_mempool_put(adb->aimp, ai);
02006 }
02007
02008
02009
02010
02011
02012
02013
02014
02015 static inline dns_adbname_t *
02016 find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
02017 unsigned int options, int *bucketp)
02018 {
02019 dns_adbname_t *adbname;
02020 int bucket;
02021
02022 bucket = dns_name_fullhash(name, ISC_FALSE) % adb->nnames;
02023
02024 if (*bucketp == DNS_ADB_INVALIDBUCKET) {
02025 LOCK(&adb->namelocks[bucket]);
02026 *bucketp = bucket;
02027 } else if (*bucketp != bucket) {
02028 UNLOCK(&adb->namelocks[*bucketp]);
02029 LOCK(&adb->namelocks[bucket]);
02030 *bucketp = bucket;
02031 }
02032
02033 adbname = ISC_LIST_HEAD(adb->names[bucket]);
02034 while (adbname != NULL) {
02035 if (!NAME_DEAD(adbname)) {
02036 if (dns_name_equal(name, &adbname->name)
02037 && GLUEHINT_OK(adbname, options)
02038 && STARTATZONE_MATCHES(adbname, options))
02039 return (adbname);
02040 }
02041 adbname = ISC_LIST_NEXT(adbname, plink);
02042 }
02043
02044 return (NULL);
02045 }
02046
02047
02048
02049
02050
02051
02052
02053
02054
02055
02056
02057 static inline dns_adbentry_t *
02058 find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp,
02059 isc_stdtime_t now)
02060 {
02061 dns_adbentry_t *entry, *entry_next;
02062 int bucket;
02063
02064 bucket = isc_sockaddr_hash(addr, ISC_TRUE) % adb->nentries;
02065
02066 if (*bucketp == DNS_ADB_INVALIDBUCKET) {
02067 LOCK(&adb->entrylocks[bucket]);
02068 *bucketp = bucket;
02069 } else if (*bucketp != bucket) {
02070 UNLOCK(&adb->entrylocks[*bucketp]);
02071 LOCK(&adb->entrylocks[bucket]);
02072 *bucketp = bucket;
02073 }
02074
02075
02076 for (entry = ISC_LIST_HEAD(adb->entries[bucket]);
02077 entry != NULL;
02078 entry = entry_next) {
02079 entry_next = ISC_LIST_NEXT(entry, plink);
02080 (void)check_expire_entry(adb, &entry, now);
02081 if (entry != NULL &&
02082 (entry->expires == 0 || entry->expires > now) &&
02083 isc_sockaddr_equal(addr, &entry->sockaddr)) {
02084 ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
02085 ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
02086 return (entry);
02087 }
02088 }
02089
02090 return (NULL);
02091 }
02092
02093
02094
02095
02096 static isc_boolean_t
02097 entry_is_lame(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *qname,
02098 dns_rdatatype_t qtype, isc_stdtime_t now)
02099 {
02100 dns_adblameinfo_t *li, *next_li;
02101 isc_boolean_t is_bad;
02102
02103 is_bad = ISC_FALSE;
02104
02105 li = ISC_LIST_HEAD(entry->lameinfo);
02106 if (li == NULL)
02107 return (ISC_FALSE);
02108 while (li != NULL) {
02109 next_li = ISC_LIST_NEXT(li, plink);
02110
02111
02112
02113
02114 if (li->lame_timer < now) {
02115 ISC_LIST_UNLINK(entry->lameinfo, li, plink);
02116 free_adblameinfo(adb, &li);
02117 }
02118
02119
02120
02121
02122
02123
02124
02125 if (li != NULL && !is_bad && li->qtype == qtype &&
02126 dns_name_equal(qname, &li->qname))
02127 is_bad = ISC_TRUE;
02128
02129 li = next_li;
02130 }
02131
02132 return (is_bad);
02133 }
02134
02135 static void
02136 copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname,
02137 dns_rdatatype_t qtype, dns_adbname_t *name,
02138 isc_stdtime_t now)
02139 {
02140 dns_adbnamehook_t *namehook;
02141 dns_adbaddrinfo_t *addrinfo;
02142 dns_adbentry_t *entry;
02143 int bucket;
02144
02145 bucket = DNS_ADB_INVALIDBUCKET;
02146
02147 if (find->options & DNS_ADBFIND_INET) {
02148 namehook = ISC_LIST_HEAD(name->v4);
02149 while (namehook != NULL) {
02150 entry = namehook->entry;
02151 bucket = entry->lock_bucket;
02152 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
02153 LOCK(&adb->entrylocks[bucket]);
02154
02155 if (!FIND_RETURNLAME(find)
02156 && entry_is_lame(adb, entry, qname, qtype, now)) {
02157 find->options |= DNS_ADBFIND_LAMEPRUNED;
02158 goto nextv4;
02159 }
02160 addrinfo = new_adbaddrinfo(adb, entry, find->port);
02161 if (addrinfo == NULL) {
02162 find->partial_result |= DNS_ADBFIND_INET;
02163 goto out;
02164 }
02165
02166
02167
02168 inc_entry_refcnt(adb, entry, ISC_FALSE);
02169 ISC_LIST_APPEND(find->list, addrinfo, publink);
02170 addrinfo = NULL;
02171 nextv4:
02172 UNLOCK(&adb->entrylocks[bucket]);
02173 bucket = DNS_ADB_INVALIDBUCKET;
02174 namehook = ISC_LIST_NEXT(namehook, plink);
02175 }
02176 }
02177
02178 if (find->options & DNS_ADBFIND_INET6) {
02179 namehook = ISC_LIST_HEAD(name->v6);
02180 while (namehook != NULL) {
02181 entry = namehook->entry;
02182 bucket = entry->lock_bucket;
02183 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
02184 LOCK(&adb->entrylocks[bucket]);
02185
02186 if (!FIND_RETURNLAME(find)
02187 && entry_is_lame(adb, entry, qname, qtype, now)) {
02188 find->options |= DNS_ADBFIND_LAMEPRUNED;
02189 goto nextv6;
02190 }
02191 addrinfo = new_adbaddrinfo(adb, entry, find->port);
02192 if (addrinfo == NULL) {
02193 find->partial_result |= DNS_ADBFIND_INET6;
02194 goto out;
02195 }
02196
02197
02198
02199 inc_entry_refcnt(adb, entry, ISC_FALSE);
02200 ISC_LIST_APPEND(find->list, addrinfo, publink);
02201 addrinfo = NULL;
02202 nextv6:
02203 UNLOCK(&adb->entrylocks[bucket]);
02204 bucket = DNS_ADB_INVALIDBUCKET;
02205 namehook = ISC_LIST_NEXT(namehook, plink);
02206 }
02207 }
02208
02209 out:
02210 if (bucket != DNS_ADB_INVALIDBUCKET)
02211 UNLOCK(&adb->entrylocks[bucket]);
02212 }
02213
02214 static void
02215 shutdown_task(isc_task_t *task, isc_event_t *ev) {
02216 dns_adb_t *adb;
02217
02218 UNUSED(task);
02219
02220 adb = ev->ev_arg;
02221 INSIST(DNS_ADB_VALID(adb));
02222
02223 isc_event_free(&ev);
02224
02225
02226
02227 LOCK(&adb->lock);
02228 UNLOCK(&adb->lock);
02229 destroy(adb);
02230 }
02231
02232
02233
02234
02235 static isc_boolean_t
02236 check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
02237 dns_adbname_t *name;
02238 isc_boolean_t result = ISC_FALSE;
02239
02240 INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
02241 name = *namep;
02242
02243 if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
02244 return (result);
02245 if (NAME_FETCH(name))
02246 return (result);
02247 if (!EXPIRE_OK(name->expire_v4, now))
02248 return (result);
02249 if (!EXPIRE_OK(name->expire_v6, now))
02250 return (result);
02251 if (!EXPIRE_OK(name->expire_target, now))
02252 return (result);
02253
02254
02255
02256
02257 result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
02258 *namep = NULL;
02259
02260
02261
02262
02263
02264 return (result);
02265 }
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278 static void
02279 check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
02280 int victims, max_victims;
02281 dns_adbname_t *victim, *next_victim;
02282 isc_boolean_t overmem = isc_mem_isovermem(adb->mctx);
02283 int scans = 0;
02284
02285 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
02286
02287 max_victims = overmem ? 2 : 1;
02288
02289
02290
02291
02292
02293
02294
02295 victim = ISC_LIST_TAIL(adb->names[bucket]);
02296 for (victims = 0;
02297 victim != NULL && victims < max_victims && scans < 10;
02298 victim = next_victim) {
02299 INSIST(!NAME_DEAD(victim));
02300 scans++;
02301 next_victim = ISC_LIST_PREV(victim, plink);
02302 (void)check_expire_name(&victim, now);
02303 if (victim == NULL) {
02304 victims++;
02305 goto next;
02306 }
02307
02308 if (!NAME_FETCH(victim) &&
02309 (overmem || victim->last_used + ADB_STALE_MARGIN <= now)) {
02310 RUNTIME_CHECK(kill_name(&victim,
02311 DNS_EVENT_ADBCANCELED) ==
02312 ISC_FALSE);
02313 victims++;
02314 }
02315
02316 next:
02317 if (!overmem)
02318 break;
02319 }
02320 }
02321
02322
02323
02324
02325 static isc_boolean_t
02326 check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
02327 {
02328 dns_adbentry_t *entry;
02329 isc_boolean_t result = ISC_FALSE;
02330
02331 INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
02332 entry = *entryp;
02333
02334 if (entry->refcnt != 0)
02335 return (result);
02336
02337 if (entry->expires == 0 || entry->expires > now)
02338 return (result);
02339
02340
02341
02342
02343 DP(DEF_LEVEL, "killing entry %p", entry);
02344 INSIST(ISC_LINK_LINKED(entry, plink));
02345 result = unlink_entry(adb, entry);
02346 free_adbentry(adb, &entry);
02347 if (result)
02348 dec_adb_irefcnt(adb);
02349 *entryp = NULL;
02350 return (result);
02351 }
02352
02353
02354
02355
02356 static isc_boolean_t
02357 cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
02358 dns_adbname_t *name;
02359 dns_adbname_t *next_name;
02360 isc_boolean_t result = ISC_FALSE;
02361
02362 DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
02363
02364 LOCK(&adb->namelocks[bucket]);
02365 if (adb->name_sd[bucket]) {
02366 UNLOCK(&adb->namelocks[bucket]);
02367 return (result);
02368 }
02369
02370 name = ISC_LIST_HEAD(adb->names[bucket]);
02371 while (name != NULL) {
02372 next_name = ISC_LIST_NEXT(name, plink);
02373 INSIST(result == ISC_FALSE);
02374 result = check_expire_namehooks(name, now);
02375 if (!result)
02376 result = check_expire_name(&name, now);
02377 name = next_name;
02378 }
02379 UNLOCK(&adb->namelocks[bucket]);
02380 return (result);
02381 }
02382
02383
02384
02385
02386 static isc_boolean_t
02387 cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
02388 dns_adbentry_t *entry, *next_entry;
02389 isc_boolean_t result = ISC_FALSE;
02390
02391 DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
02392
02393 LOCK(&adb->entrylocks[bucket]);
02394 entry = ISC_LIST_HEAD(adb->entries[bucket]);
02395 while (entry != NULL) {
02396 next_entry = ISC_LIST_NEXT(entry, plink);
02397 INSIST(result == ISC_FALSE);
02398 result = check_expire_entry(adb, &entry, now);
02399 entry = next_entry;
02400 }
02401 UNLOCK(&adb->entrylocks[bucket]);
02402 return (result);
02403 }
02404
02405 static void
02406 destroy(dns_adb_t *adb) {
02407 adb->magic = 0;
02408
02409 isc_task_detach(&adb->task);
02410 if (adb->excl != NULL)
02411 isc_task_detach(&adb->excl);
02412
02413 isc_mempool_destroy(&adb->nmp);
02414 isc_mempool_destroy(&adb->nhmp);
02415 isc_mempool_destroy(&adb->limp);
02416 isc_mempool_destroy(&adb->emp);
02417 isc_mempool_destroy(&adb->ahmp);
02418 isc_mempool_destroy(&adb->aimp);
02419 isc_mempool_destroy(&adb->afmp);
02420
02421 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
02422 isc_mem_put(adb->mctx, adb->entries,
02423 sizeof(*adb->entries) * adb->nentries);
02424 isc_mem_put(adb->mctx, adb->deadentries,
02425 sizeof(*adb->deadentries) * adb->nentries);
02426 isc_mem_put(adb->mctx, adb->entrylocks,
02427 sizeof(*adb->entrylocks) * adb->nentries);
02428 isc_mem_put(adb->mctx, adb->entry_sd,
02429 sizeof(*adb->entry_sd) * adb->nentries);
02430 isc_mem_put(adb->mctx, adb->entry_refcnt,
02431 sizeof(*adb->entry_refcnt) * adb->nentries);
02432
02433 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
02434 isc_mem_put(adb->mctx, adb->names,
02435 sizeof(*adb->names) * adb->nnames);
02436 isc_mem_put(adb->mctx, adb->deadnames,
02437 sizeof(*adb->deadnames) * adb->nnames);
02438 isc_mem_put(adb->mctx, adb->namelocks,
02439 sizeof(*adb->namelocks) * adb->nnames);
02440 isc_mem_put(adb->mctx, adb->name_sd,
02441 sizeof(*adb->name_sd) * adb->nnames);
02442 isc_mem_put(adb->mctx, adb->name_refcnt,
02443 sizeof(*adb->name_refcnt) * adb->nnames);
02444
02445 DESTROYLOCK(&adb->reflock);
02446 DESTROYLOCK(&adb->lock);
02447 DESTROYLOCK(&adb->mplock);
02448 DESTROYLOCK(&adb->overmemlock);
02449 DESTROYLOCK(&adb->entriescntlock);
02450 DESTROYLOCK(&adb->namescntlock);
02451
02452 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
02453 }
02454
02455
02456
02457
02458
02459
02460 isc_result_t
02461 dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
02462 isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
02463 {
02464 dns_adb_t *adb;
02465 isc_result_t result;
02466 unsigned int i;
02467
02468 REQUIRE(mem != NULL);
02469 REQUIRE(view != NULL);
02470 REQUIRE(timermgr != NULL);
02471 REQUIRE(taskmgr != NULL);
02472 REQUIRE(newadb != NULL && *newadb == NULL);
02473
02474 UNUSED(timermgr);
02475
02476 adb = isc_mem_get(mem, sizeof(dns_adb_t));
02477 if (adb == NULL)
02478 return (ISC_R_NOMEMORY);
02479
02480
02481
02482
02483
02484 adb->magic = 0;
02485 adb->erefcnt = 1;
02486 adb->irefcnt = 0;
02487 adb->nmp = NULL;
02488 adb->nhmp = NULL;
02489 adb->limp = NULL;
02490 adb->emp = NULL;
02491 adb->ahmp = NULL;
02492 adb->aimp = NULL;
02493 adb->afmp = NULL;
02494 adb->task = NULL;
02495 adb->excl = NULL;
02496 adb->mctx = NULL;
02497 adb->view = view;
02498 adb->taskmgr = taskmgr;
02499 adb->next_cleanbucket = 0;
02500 ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent),
02501 0, NULL, 0, NULL, NULL, NULL, NULL, NULL);
02502 adb->cevent_out = ISC_FALSE;
02503 adb->shutting_down = ISC_FALSE;
02504 ISC_LIST_INIT(adb->whenshutdown);
02505
02506 adb->nentries = nbuckets[0];
02507 adb->entriescnt = 0;
02508 adb->entries = NULL;
02509 adb->deadentries = NULL;
02510 adb->entry_sd = NULL;
02511 adb->entry_refcnt = NULL;
02512 adb->entrylocks = NULL;
02513 ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL,
02514 DNS_EVENT_ADBGROWENTRIES, grow_entries, adb,
02515 adb, NULL, NULL);
02516 adb->growentries_sent = ISC_FALSE;
02517
02518 adb->nnames = nbuckets[0];
02519 adb->namescnt = 0;
02520 adb->names = NULL;
02521 adb->deadnames = NULL;
02522 adb->name_sd = NULL;
02523 adb->name_refcnt = NULL;
02524 adb->namelocks = NULL;
02525 ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL,
02526 DNS_EVENT_ADBGROWNAMES, grow_names, adb,
02527 adb, NULL, NULL);
02528 adb->grownames_sent = ISC_FALSE;
02529
02530 result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl);
02531 if (result != ISC_R_SUCCESS) {
02532 DP(DEF_LEVEL, "adb: task-exclusive mode unavailable, "
02533 "intializing table sizes to %u\n",
02534 nbuckets[11]);
02535 adb->nentries = nbuckets[11];
02536 adb->nnames = nbuckets[11];
02537 }
02538
02539 isc_mem_attach(mem, &adb->mctx);
02540
02541 result = isc_mutex_init(&adb->lock);
02542 if (result != ISC_R_SUCCESS)
02543 goto fail0b;
02544
02545 result = isc_mutex_init(&adb->mplock);
02546 if (result != ISC_R_SUCCESS)
02547 goto fail0c;
02548
02549 result = isc_mutex_init(&adb->reflock);
02550 if (result != ISC_R_SUCCESS)
02551 goto fail0d;
02552
02553 result = isc_mutex_init(&adb->overmemlock);
02554 if (result != ISC_R_SUCCESS)
02555 goto fail0e;
02556
02557 result = isc_mutex_init(&adb->entriescntlock);
02558 if (result != ISC_R_SUCCESS)
02559 goto fail0f;
02560
02561 result = isc_mutex_init(&adb->namescntlock);
02562 if (result != ISC_R_SUCCESS)
02563 goto fail0g;
02564
02565 #define ALLOCENTRY(adb, el) \
02566 do { \
02567 (adb)->el = isc_mem_get((adb)->mctx, \
02568 sizeof(*(adb)->el) * (adb)->nentries); \
02569 if ((adb)->el == NULL) { \
02570 result = ISC_R_NOMEMORY; \
02571 goto fail1; \
02572 }\
02573 } while (0)
02574 ALLOCENTRY(adb, entries);
02575 ALLOCENTRY(adb, deadentries);
02576 ALLOCENTRY(adb, entrylocks);
02577 ALLOCENTRY(adb, entry_sd);
02578 ALLOCENTRY(adb, entry_refcnt);
02579 #undef ALLOCENTRY
02580
02581 #define ALLOCNAME(adb, el) \
02582 do { \
02583 (adb)->el = isc_mem_get((adb)->mctx, \
02584 sizeof(*(adb)->el) * (adb)->nnames); \
02585 if ((adb)->el == NULL) { \
02586 result = ISC_R_NOMEMORY; \
02587 goto fail1; \
02588 }\
02589 } while (0)
02590 ALLOCNAME(adb, names);
02591 ALLOCNAME(adb, deadnames);
02592 ALLOCNAME(adb, namelocks);
02593 ALLOCNAME(adb, name_sd);
02594 ALLOCNAME(adb, name_refcnt);
02595 #undef ALLOCNAME
02596
02597
02598
02599
02600
02601 result = isc_mutexblock_init(adb->namelocks, adb->nnames);
02602 if (result != ISC_R_SUCCESS)
02603 goto fail1;
02604 for (i = 0; i < adb->nnames; i++) {
02605 ISC_LIST_INIT(adb->names[i]);
02606 ISC_LIST_INIT(adb->deadnames[i]);
02607 adb->name_sd[i] = ISC_FALSE;
02608 adb->name_refcnt[i] = 0;
02609 adb->irefcnt++;
02610 }
02611 for (i = 0; i < adb->nentries; i++) {
02612 ISC_LIST_INIT(adb->entries[i]);
02613 ISC_LIST_INIT(adb->deadentries[i]);
02614 adb->entry_sd[i] = ISC_FALSE;
02615 adb->entry_refcnt[i] = 0;
02616 adb->irefcnt++;
02617 }
02618 result = isc_mutexblock_init(adb->entrylocks, adb->nentries);
02619 if (result != ISC_R_SUCCESS)
02620 goto fail2;
02621
02622
02623
02624
02625 #define MPINIT(t, p, n) do { \
02626 result = isc_mempool_create(mem, sizeof(t), &(p)); \
02627 if (result != ISC_R_SUCCESS) \
02628 goto fail3; \
02629 isc_mempool_setfreemax((p), FREE_ITEMS); \
02630 isc_mempool_setfillcount((p), FILL_COUNT); \
02631 isc_mempool_setname((p), n); \
02632 isc_mempool_associatelock((p), &adb->mplock); \
02633 } while (0)
02634
02635 MPINIT(dns_adbname_t, adb->nmp, "adbname");
02636 MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
02637 MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo");
02638 MPINIT(dns_adbentry_t, adb->emp, "adbentry");
02639 MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
02640 MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
02641 MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
02642
02643 #undef MPINIT
02644
02645
02646
02647
02648 result = isc_task_create(adb->taskmgr, 0, &adb->task);
02649 if (result != ISC_R_SUCCESS)
02650 goto fail3;
02651
02652 isc_task_setname(adb->task, "ADB", adb);
02653
02654 result = isc_stats_create(adb->mctx, &view->adbstats, dns_adbstats_max);
02655 if (result != ISC_R_SUCCESS)
02656 goto fail3;
02657
02658 set_adbstat(adb, adb->nentries, dns_adbstats_nentries);
02659 set_adbstat(adb, adb->nnames, dns_adbstats_nnames);
02660
02661
02662
02663
02664 adb->magic = DNS_ADB_MAGIC;
02665 *newadb = adb;
02666 return (ISC_R_SUCCESS);
02667
02668 fail3:
02669 if (adb->task != NULL)
02670 isc_task_detach(&adb->task);
02671
02672
02673 DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
02674
02675 fail2:
02676 DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
02677
02678 fail1:
02679 if (adb->entries != NULL)
02680 isc_mem_put(adb->mctx, adb->entries,
02681 sizeof(*adb->entries) * adb->nentries);
02682 if (adb->deadentries != NULL)
02683 isc_mem_put(adb->mctx, adb->deadentries,
02684 sizeof(*adb->deadentries) * adb->nentries);
02685 if (adb->entrylocks != NULL)
02686 isc_mem_put(adb->mctx, adb->entrylocks,
02687 sizeof(*adb->entrylocks) * adb->nentries);
02688 if (adb->entry_sd != NULL)
02689 isc_mem_put(adb->mctx, adb->entry_sd,
02690 sizeof(*adb->entry_sd) * adb->nentries);
02691 if (adb->entry_refcnt != NULL)
02692 isc_mem_put(adb->mctx, adb->entry_refcnt,
02693 sizeof(*adb->entry_refcnt) * adb->nentries);
02694 if (adb->names != NULL)
02695 isc_mem_put(adb->mctx, adb->names,
02696 sizeof(*adb->names) * adb->nnames);
02697 if (adb->deadnames != NULL)
02698 isc_mem_put(adb->mctx, adb->deadnames,
02699 sizeof(*adb->deadnames) * adb->nnames);
02700 if (adb->namelocks != NULL)
02701 isc_mem_put(adb->mctx, adb->namelocks,
02702 sizeof(*adb->namelocks) * adb->nnames);
02703 if (adb->name_sd != NULL)
02704 isc_mem_put(adb->mctx, adb->name_sd,
02705 sizeof(*adb->name_sd) * adb->nnames);
02706 if (adb->name_refcnt != NULL)
02707 isc_mem_put(adb->mctx, adb->name_refcnt,
02708 sizeof(*adb->name_refcnt) * adb->nnames);
02709 if (adb->nmp != NULL)
02710 isc_mempool_destroy(&adb->nmp);
02711 if (adb->nhmp != NULL)
02712 isc_mempool_destroy(&adb->nhmp);
02713 if (adb->limp != NULL)
02714 isc_mempool_destroy(&adb->limp);
02715 if (adb->emp != NULL)
02716 isc_mempool_destroy(&adb->emp);
02717 if (adb->ahmp != NULL)
02718 isc_mempool_destroy(&adb->ahmp);
02719 if (adb->aimp != NULL)
02720 isc_mempool_destroy(&adb->aimp);
02721 if (adb->afmp != NULL)
02722 isc_mempool_destroy(&adb->afmp);
02723
02724 DESTROYLOCK(&adb->namescntlock);
02725 fail0g:
02726 DESTROYLOCK(&adb->entriescntlock);
02727 fail0f:
02728 DESTROYLOCK(&adb->overmemlock);
02729 fail0e:
02730 DESTROYLOCK(&adb->reflock);
02731 fail0d:
02732 DESTROYLOCK(&adb->mplock);
02733 fail0c:
02734 DESTROYLOCK(&adb->lock);
02735 fail0b:
02736 if (adb->excl != NULL)
02737 isc_task_detach(&adb->excl);
02738 isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
02739
02740 return (result);
02741 }
02742
02743 void
02744 dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
02745
02746 REQUIRE(DNS_ADB_VALID(adb));
02747 REQUIRE(adbx != NULL && *adbx == NULL);
02748
02749 inc_adb_erefcnt(adb);
02750 *adbx = adb;
02751 }
02752
02753 void
02754 dns_adb_detach(dns_adb_t **adbx) {
02755 dns_adb_t *adb;
02756 isc_boolean_t need_exit_check;
02757
02758 REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
02759
02760 adb = *adbx;
02761 *adbx = NULL;
02762
02763 INSIST(adb->erefcnt > 0);
02764
02765 LOCK(&adb->reflock);
02766 adb->erefcnt--;
02767 need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
02768 UNLOCK(&adb->reflock);
02769
02770 if (need_exit_check) {
02771 LOCK(&adb->lock);
02772 INSIST(adb->shutting_down);
02773 check_exit(adb);
02774 UNLOCK(&adb->lock);
02775 }
02776 }
02777
02778 void
02779 dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
02780 isc_task_t *clone;
02781 isc_event_t *event;
02782 isc_boolean_t zeroirefcnt = ISC_FALSE;
02783
02784
02785
02786
02787
02788 REQUIRE(DNS_ADB_VALID(adb));
02789 REQUIRE(eventp != NULL);
02790
02791 event = *eventp;
02792 *eventp = NULL;
02793
02794 LOCK(&adb->lock);
02795
02796 LOCK(&adb->reflock);
02797 zeroirefcnt = ISC_TF(adb->irefcnt == 0);
02798
02799 if (adb->shutting_down && zeroirefcnt &&
02800 isc_mempool_getallocated(adb->ahmp) == 0) {
02801
02802
02803
02804 event->ev_sender = adb;
02805 isc_task_send(task, &event);
02806 } else {
02807 clone = NULL;
02808 isc_task_attach(task, &clone);
02809 event->ev_sender = clone;
02810 ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
02811 }
02812
02813 UNLOCK(&adb->reflock);
02814 UNLOCK(&adb->lock);
02815 }
02816
02817 static void
02818 shutdown_stage2(isc_task_t *task, isc_event_t *event) {
02819 dns_adb_t *adb;
02820
02821 UNUSED(task);
02822
02823 adb = event->ev_arg;
02824 INSIST(DNS_ADB_VALID(adb));
02825
02826 LOCK(&adb->lock);
02827 INSIST(adb->shutting_down);
02828 adb->cevent_out = ISC_FALSE;
02829 (void)shutdown_names(adb);
02830 (void)shutdown_entries(adb);
02831 if (dec_adb_irefcnt(adb))
02832 check_exit(adb);
02833 UNLOCK(&adb->lock);
02834 }
02835
02836 void
02837 dns_adb_shutdown(dns_adb_t *adb) {
02838 isc_event_t *event;
02839
02840
02841
02842
02843
02844 LOCK(&adb->lock);
02845
02846 if (!adb->shutting_down) {
02847 adb->shutting_down = ISC_TRUE;
02848 isc_mem_setwater(adb->mctx, water, adb, 0, 0);
02849
02850
02851
02852 inc_adb_irefcnt(adb);
02853 ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
02854 DNS_EVENT_ADBCONTROL, shutdown_stage2, adb,
02855 adb, NULL, NULL);
02856 adb->cevent_out = ISC_TRUE;
02857 event = &adb->cevent;
02858 isc_task_send(adb->task, &event);
02859 }
02860
02861 UNLOCK(&adb->lock);
02862 }
02863
02864 isc_result_t
02865 dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
02866 void *arg, dns_name_t *name, dns_name_t *qname,
02867 dns_rdatatype_t qtype, unsigned int options,
02868 isc_stdtime_t now, dns_name_t *target,
02869 in_port_t port, dns_adbfind_t **findp)
02870 {
02871 return (dns_adb_createfind2(adb, task, action, arg, name,
02872 qname, qtype, options, now,
02873 target, port, 0, NULL, findp));
02874 }
02875
02876 isc_result_t
02877 dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
02878 void *arg, dns_name_t *name, dns_name_t *qname,
02879 dns_rdatatype_t qtype, unsigned int options,
02880 isc_stdtime_t now, dns_name_t *target,
02881 in_port_t port, unsigned int depth, isc_counter_t *qc,
02882 dns_adbfind_t **findp)
02883 {
02884 dns_adbfind_t *find;
02885 dns_adbname_t *adbname;
02886 int bucket;
02887 isc_boolean_t want_event, start_at_zone, alias, have_address;
02888 isc_result_t result;
02889 unsigned int wanted_addresses;
02890 unsigned int wanted_fetches;
02891 unsigned int query_pending;
02892 char namebuf[DNS_NAME_FORMATSIZE];
02893
02894 REQUIRE(DNS_ADB_VALID(adb));
02895 if (task != NULL) {
02896 REQUIRE(action != NULL);
02897 }
02898 REQUIRE(name != NULL);
02899 REQUIRE(qname != NULL);
02900 REQUIRE(findp != NULL && *findp == NULL);
02901 REQUIRE(target == NULL || dns_name_hasbuffer(target));
02902
02903 REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
02904
02905 result = ISC_R_UNEXPECTED;
02906 POST(result);
02907 wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
02908 wanted_fetches = 0;
02909 query_pending = 0;
02910 want_event = ISC_FALSE;
02911 start_at_zone = ISC_FALSE;
02912 alias = ISC_FALSE;
02913
02914 if (now == 0)
02915 isc_stdtime_get(&now);
02916
02917
02918
02919
02920
02921
02922
02923
02924
02925
02926
02927
02928
02929
02930
02931
02932
02933
02934
02935
02936
02937
02938 find = new_adbfind(adb);
02939 if (find == NULL)
02940 return (ISC_R_NOMEMORY);
02941
02942 find->port = port;
02943
02944
02945
02946
02947 find->options = options;
02948 find->flags |= wanted_addresses;
02949 if (FIND_WANTEVENT(find)) {
02950 REQUIRE(task != NULL);
02951 }
02952
02953 if (isc_log_wouldlog(dns_lctx, DEF_LEVEL))
02954 dns_name_format(name, namebuf, sizeof(namebuf));
02955 else
02956 namebuf[0] = 0;
02957
02958
02959
02960
02961 bucket = DNS_ADB_INVALIDBUCKET;
02962 adbname = find_name_and_lock(adb, name, find->options, &bucket);
02963 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
02964 if (adb->name_sd[bucket]) {
02965 DP(DEF_LEVEL,
02966 "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
02967 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
02968 result = ISC_R_SHUTTINGDOWN;
02969 goto out;
02970 }
02971
02972
02973
02974
02975 if (adbname == NULL) {
02976
02977
02978
02979
02980 check_stale_name(adb, bucket, now);
02981
02982 adbname = new_adbname(adb, name);
02983 if (adbname == NULL) {
02984 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
02985 result = ISC_R_NOMEMORY;
02986 goto out;
02987 }
02988 link_name(adb, bucket, adbname);
02989 if (FIND_HINTOK(find))
02990 adbname->flags |= NAME_HINT_OK;
02991 if (FIND_GLUEOK(find))
02992 adbname->flags |= NAME_GLUE_OK;
02993 if (FIND_STARTATZONE(find))
02994 adbname->flags |= NAME_STARTATZONE;
02995 } else {
02996
02997 ISC_LIST_UNLINK(adb->names[bucket], adbname, plink);
02998 ISC_LIST_PREPEND(adb->names[bucket], adbname, plink);
02999 }
03000 adbname->last_used = now;
03001
03002
03003
03004
03005 RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE);
03006
03007
03008
03009
03010 if (!EXPIRE_OK(adbname->expire_target, now)) {
03011
03012
03013
03014 DP(DEF_LEVEL,
03015 "dns_adb_createfind: name %s (%p) is an alias (cached)",
03016 namebuf, adbname);
03017 alias = ISC_TRUE;
03018 goto post_copy;
03019 }
03020
03021
03022
03023
03024
03025
03026 if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
03027 && WANT_INET(wanted_addresses)) {
03028 result = dbfind_name(adbname, now, dns_rdatatype_a);
03029 if (result == ISC_R_SUCCESS) {
03030 DP(DEF_LEVEL,
03031 "dns_adb_createfind: found A for name %s (%p) in db",
03032 namebuf, adbname);
03033 goto v6;
03034 }
03035
03036
03037
03038
03039 if (result == DNS_R_ALIAS) {
03040 DP(DEF_LEVEL,
03041 "dns_adb_createfind: name %s (%p) is an alias",
03042 namebuf, adbname);
03043 alias = ISC_TRUE;
03044 goto post_copy;
03045 }
03046
03047
03048
03049
03050
03051
03052
03053
03054
03055
03056 if (NXDOMAIN_RESULT(result))
03057 goto fetch;
03058 else if (NXRRSET_RESULT(result))
03059 goto v6;
03060
03061 if (!NAME_FETCH_V4(adbname))
03062 wanted_fetches |= DNS_ADBFIND_INET;
03063 }
03064
03065 v6:
03066 if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
03067 && WANT_INET6(wanted_addresses)) {
03068 result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
03069 if (result == ISC_R_SUCCESS) {
03070 DP(DEF_LEVEL,
03071 "dns_adb_createfind: found AAAA for name %s (%p)",
03072 namebuf, adbname);
03073 goto fetch;
03074 }
03075
03076
03077
03078
03079 if (result == DNS_R_ALIAS) {
03080 DP(DEF_LEVEL,
03081 "dns_adb_createfind: name %s (%p) is an alias",
03082 namebuf, adbname);
03083 alias = ISC_TRUE;
03084 goto post_copy;
03085 }
03086
03087
03088
03089
03090
03091 if (NCACHE_RESULT(result) || AUTH_NX(result))
03092 goto fetch;
03093
03094 if (!NAME_FETCH_V6(adbname))
03095 wanted_fetches |= DNS_ADBFIND_INET6;
03096 }
03097
03098 fetch:
03099 if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
03100 (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
03101 have_address = ISC_TRUE;
03102 else
03103 have_address = ISC_FALSE;
03104 if (wanted_fetches != 0 &&
03105 ! (FIND_AVOIDFETCHES(find) && have_address)) {
03106
03107
03108
03109
03110
03111
03112
03113 if (FIND_STARTATZONE(find))
03114 start_at_zone = ISC_TRUE;
03115
03116
03117
03118
03119 if (WANT_INET(wanted_fetches) &&
03120 fetch_name(adbname, start_at_zone, depth, qc,
03121 dns_rdatatype_a) == ISC_R_SUCCESS) {
03122 DP(DEF_LEVEL, "dns_adb_createfind: "
03123 "started A fetch for name %s (%p)",
03124 namebuf, adbname);
03125 }
03126
03127
03128
03129
03130 if (WANT_INET6(wanted_fetches) &&
03131 fetch_name(adbname, start_at_zone, depth, qc,
03132 dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
03133 DP(DEF_LEVEL, "dns_adb_createfind: "
03134 "started AAAA fetch for name %s (%p)",
03135 namebuf, adbname);
03136 }
03137 }
03138
03139
03140
03141
03142
03143 copy_namehook_lists(adb, find, qname, qtype, adbname, now);
03144
03145 post_copy:
03146 if (NAME_FETCH_V4(adbname))
03147 query_pending |= DNS_ADBFIND_INET;
03148 if (NAME_FETCH_V6(adbname))
03149 query_pending |= DNS_ADBFIND_INET6;
03150
03151
03152
03153
03154
03155 want_event = ISC_TRUE;
03156 if (!FIND_WANTEVENT(find))
03157 want_event = ISC_FALSE;
03158 if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
03159 want_event = ISC_FALSE;
03160 if ((wanted_addresses & query_pending) == 0)
03161 want_event = ISC_FALSE;
03162 if (alias)
03163 want_event = ISC_FALSE;
03164 if (want_event) {
03165 find->adbname = adbname;
03166 find->name_bucket = bucket;
03167 ISC_LIST_APPEND(adbname->finds, find, plink);
03168 find->query_pending = (query_pending & wanted_addresses);
03169 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
03170 find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
03171 DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
03172 find, adbname);
03173 } else {
03174
03175
03176
03177
03178
03179
03180 find->query_pending = (query_pending & wanted_addresses);
03181 find->options &= ~DNS_ADBFIND_WANTEVENT;
03182 find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
03183 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
03184 }
03185
03186 find->partial_result |= (adbname->partial_result & wanted_addresses);
03187 if (alias) {
03188 if (target != NULL) {
03189 result = dns_name_copy(&adbname->target, target, NULL);
03190 if (result != ISC_R_SUCCESS)
03191 goto out;
03192 }
03193 result = DNS_R_ALIAS;
03194 } else
03195 result = ISC_R_SUCCESS;
03196
03197
03198
03199
03200 find->result_v4 = find_err_map[adbname->fetch_err];
03201 find->result_v6 = find_err_map[adbname->fetch6_err];
03202
03203 out:
03204 if (find != NULL) {
03205 *findp = find;
03206
03207 if (want_event) {
03208 isc_task_t *taskp;
03209
03210 INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
03211 taskp = NULL;
03212 isc_task_attach(task, &taskp);
03213 find->event.ev_sender = taskp;
03214 find->event.ev_action = action;
03215 find->event.ev_arg = arg;
03216 }
03217 }
03218
03219 UNLOCK(&adb->namelocks[bucket]);
03220
03221 return (result);
03222 }
03223
03224 void
03225 dns_adb_destroyfind(dns_adbfind_t **findp) {
03226 dns_adbfind_t *find;
03227 dns_adbentry_t *entry;
03228 dns_adbaddrinfo_t *ai;
03229 int bucket;
03230 dns_adb_t *adb;
03231 isc_boolean_t overmem;
03232
03233 REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
03234 find = *findp;
03235 *findp = NULL;
03236
03237 LOCK(&find->lock);
03238
03239 DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
03240
03241 adb = find->adb;
03242 REQUIRE(DNS_ADB_VALID(adb));
03243
03244 REQUIRE(FIND_EVENTFREED(find));
03245
03246 bucket = find->name_bucket;
03247 INSIST(bucket == DNS_ADB_INVALIDBUCKET);
03248
03249 UNLOCK(&find->lock);
03250
03251
03252
03253
03254
03255
03256 overmem = isc_mem_isovermem(adb->mctx);
03257 ai = ISC_LIST_HEAD(find->list);
03258 while (ai != NULL) {
03259 ISC_LIST_UNLINK(find->list, ai, publink);
03260 entry = ai->entry;
03261 ai->entry = NULL;
03262 INSIST(DNS_ADBENTRY_VALID(entry));
03263 RUNTIME_CHECK(dec_entry_refcnt(adb, overmem, entry, ISC_TRUE) ==
03264 ISC_FALSE);
03265 free_adbaddrinfo(adb, &ai);
03266 ai = ISC_LIST_HEAD(find->list);
03267 }
03268
03269
03270
03271
03272
03273
03274
03275
03276 LOCK(&adb->lock);
03277 if (free_adbfind(adb, &find))
03278 check_exit(adb);
03279 UNLOCK(&adb->lock);
03280 }
03281
03282 void
03283 dns_adb_cancelfind(dns_adbfind_t *find) {
03284 isc_event_t *ev;
03285 isc_task_t *task;
03286 dns_adb_t *adb;
03287 int bucket;
03288 int unlock_bucket;
03289
03290 LOCK(&find->lock);
03291
03292 DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
03293
03294 adb = find->adb;
03295 REQUIRE(DNS_ADB_VALID(adb));
03296
03297 REQUIRE(!FIND_EVENTFREED(find));
03298 REQUIRE(FIND_WANTEVENT(find));
03299
03300 bucket = find->name_bucket;
03301 if (bucket == DNS_ADB_INVALIDBUCKET)
03302 goto cleanup;
03303
03304
03305
03306
03307 unlock_bucket = bucket;
03308 violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
03309 bucket = find->name_bucket;
03310 if (bucket != DNS_ADB_INVALIDBUCKET) {
03311 ISC_LIST_UNLINK(find->adbname->finds, find, plink);
03312 find->adbname = NULL;
03313 find->name_bucket = DNS_ADB_INVALIDBUCKET;
03314 }
03315 UNLOCK(&adb->namelocks[unlock_bucket]);
03316 bucket = DNS_ADB_INVALIDBUCKET;
03317 POST(bucket);
03318
03319 cleanup:
03320
03321 if (!FIND_EVENTSENT(find)) {
03322 ev = &find->event;
03323 task = ev->ev_sender;
03324 ev->ev_sender = find;
03325 ev->ev_type = DNS_EVENT_ADBCANCELED;
03326 ev->ev_destroy = event_free;
03327 ev->ev_destroy_arg = find;
03328 find->result_v4 = ISC_R_CANCELED;
03329 find->result_v6 = ISC_R_CANCELED;
03330
03331 DP(DEF_LEVEL, "sending event %p to task %p for find %p",
03332 ev, task, find);
03333
03334 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
03335 }
03336
03337 UNLOCK(&find->lock);
03338 }
03339
03340 void
03341 dns_adb_dump(dns_adb_t *adb, FILE *f) {
03342 unsigned int i;
03343 isc_stdtime_t now;
03344
03345 REQUIRE(DNS_ADB_VALID(adb));
03346 REQUIRE(f != NULL);
03347
03348
03349
03350
03351
03352
03353
03354
03355 LOCK(&adb->lock);
03356 isc_stdtime_get(&now);
03357
03358 for (i = 0; i < adb->nnames; i++)
03359 RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE);
03360 for (i = 0; i < adb->nentries; i++)
03361 RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE);
03362
03363 dump_adb(adb, f, ISC_FALSE, now);
03364 UNLOCK(&adb->lock);
03365 }
03366
03367 static void
03368 dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
03369 if (value == INT_MAX)
03370 return;
03371 fprintf(f, " [%s TTL %d]", legend, value - now);
03372 }
03373
03374 static void
03375 dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
03376 unsigned int i;
03377 dns_adbname_t *name;
03378 dns_adbentry_t *entry;
03379
03380 fprintf(f, ";\n; Address database dump\n;\n");
03381 fprintf(f, "; [edns success/4096 timeout/1432 timeout/1232 timeout/"
03382 "512 timeout]\n");
03383 fprintf(f, "; [plain success/timeout]\n;\n");
03384 if (debug)
03385 fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
03386 adb, adb->erefcnt, adb->irefcnt,
03387 isc_mempool_getallocated(adb->nhmp));
03388
03389 for (i = 0; i < adb->nnames; i++)
03390 LOCK(&adb->namelocks[i]);
03391 for (i = 0; i < adb->nentries; i++)
03392 LOCK(&adb->entrylocks[i]);
03393
03394
03395
03396
03397 for (i = 0; i < adb->nnames; i++) {
03398 name = ISC_LIST_HEAD(adb->names[i]);
03399 if (name == NULL)
03400 continue;
03401 if (debug)
03402 fprintf(f, "; bucket %d\n", i);
03403 for (;
03404 name != NULL;
03405 name = ISC_LIST_NEXT(name, plink))
03406 {
03407 if (debug)
03408 fprintf(f, "; name %p (flags %08x)\n",
03409 name, name->flags);
03410
03411 fprintf(f, "; ");
03412 print_dns_name(f, &name->name);
03413 if (dns_name_countlabels(&name->target) > 0) {
03414 fprintf(f, " alias ");
03415 print_dns_name(f, &name->target);
03416 }
03417
03418 dump_ttl(f, "v4", name->expire_v4, now);
03419 dump_ttl(f, "v6", name->expire_v6, now);
03420 dump_ttl(f, "target", name->expire_target, now);
03421
03422 fprintf(f, " [v4 %s] [v6 %s]",
03423 errnames[name->fetch_err],
03424 errnames[name->fetch6_err]);
03425
03426 fprintf(f, "\n");
03427
03428 print_namehook_list(f, "v4", &name->v4, debug, now);
03429 print_namehook_list(f, "v6", &name->v6, debug, now);
03430
03431 if (debug)
03432 print_fetch_list(f, name);
03433 if (debug)
03434 print_find_list(f, name);
03435
03436 }
03437 }
03438
03439 fprintf(f, ";\n; Unassociated entries\n;\n");
03440
03441 for (i = 0; i < adb->nentries; i++) {
03442 entry = ISC_LIST_HEAD(adb->entries[i]);
03443 while (entry != NULL) {
03444 if (entry->refcnt == 0)
03445 dump_entry(f, entry, debug, now);
03446 entry = ISC_LIST_NEXT(entry, plink);
03447 }
03448 }
03449
03450
03451
03452
03453 for (i = 0; i < adb->nentries; i++)
03454 UNLOCK(&adb->entrylocks[i]);
03455 for (i = 0; i < adb->nnames; i++)
03456 UNLOCK(&adb->namelocks[i]);
03457 }
03458
03459 static void
03460 dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug,
03461 isc_stdtime_t now)
03462 {
03463 char addrbuf[ISC_NETADDR_FORMATSIZE];
03464 char typebuf[DNS_RDATATYPE_FORMATSIZE];
03465 isc_netaddr_t netaddr;
03466 dns_adblameinfo_t *li;
03467
03468 isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
03469 isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
03470
03471 if (debug)
03472 fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
03473
03474 fprintf(f, ";\t%s [srtt %u] [flags %08x] [edns %u/%u/%u/%u/%u] "
03475 "[plain %u/%u]", addrbuf, entry->srtt, entry->flags,
03476 entry->edns, entry->to4096, entry->to1432, entry->to1232,
03477 entry->to512, entry->plain, entry->plainto);
03478 if (entry->udpsize != 0U)
03479 fprintf(f, " [udpsize %u]", entry->udpsize);
03480 #ifdef ISC_PLATFORM_USESIT
03481 if (entry->sit != NULL) {
03482 unsigned int i;
03483 fprintf(f, " [sit=");
03484 for (i = 0; i < entry->sitlen; i++)
03485 fprintf(f, "%02x", entry->sit[i]);
03486 fprintf(f, "]");
03487 }
03488 #endif
03489
03490 if (entry->expires != 0)
03491 fprintf(f, " [ttl %d]", entry->expires - now);
03492 fprintf(f, "\n");
03493 for (li = ISC_LIST_HEAD(entry->lameinfo);
03494 li != NULL;
03495 li = ISC_LIST_NEXT(li, plink)) {
03496 fprintf(f, ";\t\t");
03497 print_dns_name(f, &li->qname);
03498 dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf));
03499 fprintf(f, " %s [lame TTL %d]\n", typebuf,
03500 li->lame_timer - now);
03501 }
03502 }
03503
03504 void
03505 dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
03506 char tmp[512];
03507 const char *tmpp;
03508 dns_adbaddrinfo_t *ai;
03509 isc_sockaddr_t *sa;
03510
03511
03512
03513
03514
03515
03516 LOCK(&find->lock);
03517
03518 fprintf(f, ";Find %p\n", find);
03519 fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
03520 find->query_pending, find->partial_result,
03521 find->options, find->flags);
03522 fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
03523 find->name_bucket, find->adbname, find->event.ev_sender);
03524
03525 ai = ISC_LIST_HEAD(find->list);
03526 if (ai != NULL)
03527 fprintf(f, "\tAddresses:\n");
03528 while (ai != NULL) {
03529 sa = &ai->sockaddr;
03530 switch (sa->type.sa.sa_family) {
03531 case AF_INET:
03532 tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
03533 tmp, sizeof(tmp));
03534 break;
03535 case AF_INET6:
03536 tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
03537 tmp, sizeof(tmp));
03538 break;
03539 default:
03540 tmpp = "UnkFamily";
03541 }
03542
03543 if (tmpp == NULL)
03544 tmpp = "BadAddress";
03545
03546 fprintf(f, "\t\tentry %p, flags %08x"
03547 " srtt %u addr %s\n",
03548 ai->entry, ai->flags, ai->srtt, tmpp);
03549
03550 ai = ISC_LIST_NEXT(ai, publink);
03551 }
03552
03553 UNLOCK(&find->lock);
03554 }
03555
03556 static void
03557 print_dns_name(FILE *f, dns_name_t *name) {
03558 char buf[DNS_NAME_FORMATSIZE];
03559
03560 INSIST(f != NULL);
03561
03562 dns_name_format(name, buf, sizeof(buf));
03563 fprintf(f, "%s", buf);
03564 }
03565
03566 static void
03567 print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list,
03568 isc_boolean_t debug, isc_stdtime_t now)
03569 {
03570 dns_adbnamehook_t *nh;
03571
03572 for (nh = ISC_LIST_HEAD(*list);
03573 nh != NULL;
03574 nh = ISC_LIST_NEXT(nh, plink))
03575 {
03576 if (debug)
03577 fprintf(f, ";\tHook(%s) %p\n", legend, nh);
03578 dump_entry(f, nh->entry, debug, now);
03579 }
03580 }
03581
03582 static inline void
03583 print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) {
03584 fprintf(f, "\t\tFetch(%s): %p -> { fetch %p }\n",
03585 type, ft, ft->fetch);
03586 }
03587
03588 static void
03589 print_fetch_list(FILE *f, dns_adbname_t *n) {
03590 if (NAME_FETCH_A(n))
03591 print_fetch(f, n->fetch_a, "A");
03592 if (NAME_FETCH_AAAA(n))
03593 print_fetch(f, n->fetch_aaaa, "AAAA");
03594 }
03595
03596 static void
03597 print_find_list(FILE *f, dns_adbname_t *name) {
03598 dns_adbfind_t *find;
03599
03600 find = ISC_LIST_HEAD(name->finds);
03601 while (find != NULL) {
03602 dns_adb_dumpfind(find, f);
03603 find = ISC_LIST_NEXT(find, plink);
03604 }
03605 }
03606
03607 static isc_result_t
03608 dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype)
03609 {
03610 isc_result_t result;
03611 dns_rdataset_t rdataset;
03612 dns_adb_t *adb;
03613 dns_fixedname_t foundname;
03614 dns_name_t *fname;
03615
03616 INSIST(DNS_ADBNAME_VALID(adbname));
03617 adb = adbname->adb;
03618 INSIST(DNS_ADB_VALID(adb));
03619 INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
03620
03621 dns_fixedname_init(&foundname);
03622 fname = dns_fixedname_name(&foundname);
03623 dns_rdataset_init(&rdataset);
03624
03625 if (rdtype == dns_rdatatype_a)
03626 adbname->fetch_err = FIND_ERR_UNEXPECTED;
03627 else
03628 adbname->fetch6_err = FIND_ERR_UNEXPECTED;
03629
03630
03631
03632
03633
03634
03635
03636
03637
03638 result = dns_view_find2(adb->view, &adbname->name, rdtype, now,
03639 NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0,
03640 ISC_TF(NAME_HINTOK(adbname)),
03641 (adbname->flags & NAME_STARTATZONE) != 0 ?
03642 ISC_TRUE : ISC_FALSE,
03643 NULL, NULL, fname, &rdataset, NULL);
03644
03645
03646 switch (result) {
03647 case DNS_R_GLUE:
03648 case DNS_R_HINT:
03649 case ISC_R_SUCCESS:
03650
03651
03652
03653
03654
03655 if (rdtype == dns_rdatatype_a)
03656 adbname->fetch_err = FIND_ERR_SUCCESS;
03657 else
03658 adbname->fetch6_err = FIND_ERR_SUCCESS;
03659 result = import_rdataset(adbname, &rdataset, now);
03660 break;
03661 case DNS_R_NXDOMAIN:
03662 case DNS_R_NXRRSET:
03663
03664
03665
03666
03667
03668
03669
03670
03671 if (rdtype == dns_rdatatype_a) {
03672 adbname->expire_v4 = now + 30;
03673 DP(NCACHE_LEVEL,
03674 "adb name %p: Caching auth negative entry for A",
03675 adbname);
03676 if (result == DNS_R_NXDOMAIN)
03677 adbname->fetch_err = FIND_ERR_NXDOMAIN;
03678 else
03679 adbname->fetch_err = FIND_ERR_NXRRSET;
03680 } else {
03681 DP(NCACHE_LEVEL,
03682 "adb name %p: Caching auth negative entry for AAAA",
03683 adbname);
03684 adbname->expire_v6 = now + 30;
03685 if (result == DNS_R_NXDOMAIN)
03686 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
03687 else
03688 adbname->fetch6_err = FIND_ERR_NXRRSET;
03689 }
03690 break;
03691 case DNS_R_NCACHENXDOMAIN:
03692 case DNS_R_NCACHENXRRSET:
03693
03694
03695
03696
03697 rdataset.ttl = ttlclamp(rdataset.ttl);
03698 if (rdtype == dns_rdatatype_a) {
03699 adbname->expire_v4 = rdataset.ttl + now;
03700 if (result == DNS_R_NCACHENXDOMAIN)
03701 adbname->fetch_err = FIND_ERR_NXDOMAIN;
03702 else
03703 adbname->fetch_err = FIND_ERR_NXRRSET;
03704 DP(NCACHE_LEVEL,
03705 "adb name %p: Caching negative entry for A (ttl %u)",
03706 adbname, rdataset.ttl);
03707 } else {
03708 DP(NCACHE_LEVEL,
03709 "adb name %p: Caching negative entry for AAAA (ttl %u)",
03710 adbname, rdataset.ttl);
03711 adbname->expire_v6 = rdataset.ttl + now;
03712 if (result == DNS_R_NCACHENXDOMAIN)
03713 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
03714 else
03715 adbname->fetch6_err = FIND_ERR_NXRRSET;
03716 }
03717 break;
03718 case DNS_R_CNAME:
03719 case DNS_R_DNAME:
03720
03721
03722
03723
03724 adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
03725
03726 rdataset.ttl = ttlclamp(rdataset.ttl);
03727 clean_target(adb, &adbname->target);
03728 adbname->expire_target = INT_MAX;
03729 result = set_target(adb, &adbname->name, fname, &rdataset,
03730 &adbname->target);
03731 if (result == ISC_R_SUCCESS) {
03732 result = DNS_R_ALIAS;
03733 DP(NCACHE_LEVEL,
03734 "adb name %p: caching alias target",
03735 adbname);
03736 adbname->expire_target = rdataset.ttl + now;
03737 }
03738 if (rdtype == dns_rdatatype_a)
03739 adbname->fetch_err = FIND_ERR_SUCCESS;
03740 else
03741 adbname->fetch6_err = FIND_ERR_SUCCESS;
03742 break;
03743 }
03744
03745 if (dns_rdataset_isassociated(&rdataset))
03746 dns_rdataset_disassociate(&rdataset);
03747
03748 return (result);
03749 }
03750
03751 static void
03752 fetch_callback(isc_task_t *task, isc_event_t *ev) {
03753 dns_fetchevent_t *dev;
03754 dns_adbname_t *name;
03755 dns_adb_t *adb;
03756 dns_adbfetch_t *fetch;
03757 int bucket;
03758 isc_eventtype_t ev_status;
03759 isc_stdtime_t now;
03760 isc_result_t result;
03761 unsigned int address_type;
03762 isc_boolean_t want_check_exit = ISC_FALSE;
03763
03764 UNUSED(task);
03765
03766 INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
03767 dev = (dns_fetchevent_t *)ev;
03768 name = ev->ev_arg;
03769 INSIST(DNS_ADBNAME_VALID(name));
03770 adb = name->adb;
03771 INSIST(DNS_ADB_VALID(adb));
03772
03773 bucket = name->lock_bucket;
03774 LOCK(&adb->namelocks[bucket]);
03775
03776 INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
03777 address_type = 0;
03778 if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
03779 address_type = DNS_ADBFIND_INET;
03780 fetch = name->fetch_a;
03781 name->fetch_a = NULL;
03782 } else if (NAME_FETCH_AAAA(name)
03783 && (name->fetch_aaaa->fetch == dev->fetch)) {
03784 address_type = DNS_ADBFIND_INET6;
03785 fetch = name->fetch_aaaa;
03786 name->fetch_aaaa = NULL;
03787 } else
03788 fetch = NULL;
03789
03790 INSIST(address_type != 0 && fetch != NULL);
03791
03792 dns_resolver_destroyfetch(&fetch->fetch);
03793 dev->fetch = NULL;
03794
03795 ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
03796
03797
03798
03799
03800 if (dev->node != NULL)
03801 dns_db_detachnode(dev->db, &dev->node);
03802 if (dev->db != NULL)
03803 dns_db_detach(&dev->db);
03804
03805
03806
03807
03808
03809 if (NAME_DEAD(name)) {
03810 free_adbfetch(adb, &fetch);
03811 isc_event_free(&ev);
03812
03813 want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
03814
03815 UNLOCK(&adb->namelocks[bucket]);
03816
03817 if (want_check_exit) {
03818 LOCK(&adb->lock);
03819 check_exit(adb);
03820 UNLOCK(&adb->lock);
03821 }
03822
03823 return;
03824 }
03825
03826 isc_stdtime_get(&now);
03827
03828
03829
03830
03831 if (NCACHE_RESULT(dev->result)) {
03832 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
03833 if (address_type == DNS_ADBFIND_INET) {
03834 DP(NCACHE_LEVEL, "adb fetch name %p: "
03835 "caching negative entry for A (ttl %u)",
03836 name, dev->rdataset->ttl);
03837 name->expire_v4 = ISC_MIN(name->expire_v4,
03838 dev->rdataset->ttl + now);
03839 if (dev->result == DNS_R_NCACHENXDOMAIN)
03840 name->fetch_err = FIND_ERR_NXDOMAIN;
03841 else
03842 name->fetch_err = FIND_ERR_NXRRSET;
03843 inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
03844 } else {
03845 DP(NCACHE_LEVEL, "adb fetch name %p: "
03846 "caching negative entry for AAAA (ttl %u)",
03847 name, dev->rdataset->ttl);
03848 name->expire_v6 = ISC_MIN(name->expire_v6,
03849 dev->rdataset->ttl + now);
03850 if (dev->result == DNS_R_NCACHENXDOMAIN)
03851 name->fetch6_err = FIND_ERR_NXDOMAIN;
03852 else
03853 name->fetch6_err = FIND_ERR_NXRRSET;
03854 inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
03855 }
03856 goto out;
03857 }
03858
03859
03860
03861
03862 if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
03863 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
03864 clean_target(adb, &name->target);
03865 name->expire_target = INT_MAX;
03866 result = set_target(adb, &name->name,
03867 dns_fixedname_name(&dev->foundname),
03868 dev->rdataset,
03869 &name->target);
03870 if (result == ISC_R_SUCCESS) {
03871 DP(NCACHE_LEVEL,
03872 "adb fetch name %p: caching alias target",
03873 name);
03874 name->expire_target = dev->rdataset->ttl + now;
03875 }
03876 goto check_result;
03877 }
03878
03879
03880
03881
03882
03883 if (dev->result != ISC_R_SUCCESS) {
03884 char buf[DNS_NAME_FORMATSIZE];
03885
03886 dns_name_format(&name->name, buf, sizeof(buf));
03887 DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
03888 buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
03889 dns_result_totext(dev->result));
03890
03891
03892
03893
03894 if (fetch->depth > 1)
03895 goto out;
03896
03897 if (address_type == DNS_ADBFIND_INET) {
03898 name->expire_v4 = ISC_MIN(name->expire_v4, now + 10);
03899 name->fetch_err = FIND_ERR_FAILURE;
03900 inc_stats(adb, dns_resstatscounter_gluefetchv4fail);
03901 } else {
03902 name->expire_v6 = ISC_MIN(name->expire_v6, now + 10);
03903 name->fetch6_err = FIND_ERR_FAILURE;
03904 inc_stats(adb, dns_resstatscounter_gluefetchv6fail);
03905 }
03906 goto out;
03907 }
03908
03909
03910
03911
03912 result = import_rdataset(name, &fetch->rdataset, now);
03913
03914 check_result:
03915 if (result == ISC_R_SUCCESS) {
03916 ev_status = DNS_EVENT_ADBMOREADDRESSES;
03917 if (address_type == DNS_ADBFIND_INET)
03918 name->fetch_err = FIND_ERR_SUCCESS;
03919 else
03920 name->fetch6_err = FIND_ERR_SUCCESS;
03921 }
03922
03923 out:
03924 free_adbfetch(adb, &fetch);
03925 isc_event_free(&ev);
03926
03927 clean_finds_at_name(name, ev_status, address_type);
03928
03929 UNLOCK(&adb->namelocks[bucket]);
03930 }
03931
03932 static isc_result_t
03933 fetch_name(dns_adbname_t *adbname, isc_boolean_t start_at_zone,
03934 unsigned int depth, isc_counter_t *qc, dns_rdatatype_t type)
03935 {
03936 isc_result_t result;
03937 dns_adbfetch_t *fetch = NULL;
03938 dns_adb_t *adb;
03939 dns_fixedname_t fixed;
03940 dns_name_t *name;
03941 dns_rdataset_t rdataset;
03942 dns_rdataset_t *nameservers;
03943 unsigned int options;
03944
03945 INSIST(DNS_ADBNAME_VALID(adbname));
03946 adb = adbname->adb;
03947 INSIST(DNS_ADB_VALID(adb));
03948
03949 INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
03950 (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
03951
03952 adbname->fetch_err = FIND_ERR_NOTFOUND;
03953
03954 name = NULL;
03955 nameservers = NULL;
03956 dns_rdataset_init(&rdataset);
03957
03958 options = DNS_FETCHOPT_NOVALIDATE;
03959 if (start_at_zone) {
03960 DP(ENTER_LEVEL,
03961 "fetch_name: starting at zone for name %p",
03962 adbname);
03963 dns_fixedname_init(&fixed);
03964 name = dns_fixedname_name(&fixed);
03965 result = dns_view_findzonecut2(adb->view, &adbname->name, name,
03966 0, 0, ISC_TRUE, ISC_FALSE,
03967 &rdataset, NULL);
03968 if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
03969 goto cleanup;
03970 nameservers = &rdataset;
03971 options |= DNS_FETCHOPT_UNSHARED;
03972 }
03973
03974 fetch = new_adbfetch(adb);
03975 if (fetch == NULL) {
03976 result = ISC_R_NOMEMORY;
03977 goto cleanup;
03978 }
03979 fetch->depth = depth;
03980
03981 result = dns_resolver_createfetch3(adb->view->resolver, &adbname->name,
03982 type, name, nameservers, NULL,
03983 NULL, 0, options, depth, qc,
03984 adb->task, fetch_callback, adbname,
03985 &fetch->rdataset, NULL,
03986 &fetch->fetch);
03987 if (result != ISC_R_SUCCESS)
03988 goto cleanup;
03989
03990 if (type == dns_rdatatype_a) {
03991 adbname->fetch_a = fetch;
03992 inc_stats(adb, dns_resstatscounter_gluefetchv4);
03993 } else {
03994 adbname->fetch_aaaa = fetch;
03995 inc_stats(adb, dns_resstatscounter_gluefetchv6);
03996 }
03997 fetch = NULL;
03998
03999 cleanup:
04000 if (fetch != NULL)
04001 free_adbfetch(adb, &fetch);
04002 if (dns_rdataset_isassociated(&rdataset))
04003 dns_rdataset_disassociate(&rdataset);
04004
04005 return (result);
04006 }
04007
04008
04009
04010
04011
04012 isc_result_t
04013 dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname,
04014 dns_rdatatype_t qtype, isc_stdtime_t expire_time)
04015 {
04016 dns_adblameinfo_t *li;
04017 int bucket;
04018 isc_result_t result = ISC_R_SUCCESS;
04019
04020 REQUIRE(DNS_ADB_VALID(adb));
04021 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04022 REQUIRE(qname != NULL);
04023
04024 bucket = addr->entry->lock_bucket;
04025 LOCK(&adb->entrylocks[bucket]);
04026 li = ISC_LIST_HEAD(addr->entry->lameinfo);
04027 while (li != NULL &&
04028 (li->qtype != qtype || !dns_name_equal(qname, &li->qname)))
04029 li = ISC_LIST_NEXT(li, plink);
04030 if (li != NULL) {
04031 if (expire_time > li->lame_timer)
04032 li->lame_timer = expire_time;
04033 goto unlock;
04034 }
04035 li = new_adblameinfo(adb, qname, qtype);
04036 if (li == NULL) {
04037 result = ISC_R_NOMEMORY;
04038 goto unlock;
04039 }
04040
04041 li->lame_timer = expire_time;
04042
04043 ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink);
04044 unlock:
04045 UNLOCK(&adb->entrylocks[bucket]);
04046
04047 return (result);
04048 }
04049
04050 void
04051 dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
04052 unsigned int rtt, unsigned int factor)
04053 {
04054 int bucket;
04055 isc_stdtime_t now = 0;
04056
04057 REQUIRE(DNS_ADB_VALID(adb));
04058 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04059 REQUIRE(factor <= 10);
04060
04061 bucket = addr->entry->lock_bucket;
04062 LOCK(&adb->entrylocks[bucket]);
04063
04064 if (addr->entry->expires == 0 || factor == DNS_ADB_RTTADJAGE)
04065 isc_stdtime_get(&now);
04066 adjustsrtt(addr, rtt, factor, now);
04067
04068 UNLOCK(&adb->entrylocks[bucket]);
04069 }
04070
04071 void
04072 dns_adb_agesrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr, isc_stdtime_t now) {
04073 int bucket;
04074
04075 REQUIRE(DNS_ADB_VALID(adb));
04076 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04077
04078 bucket = addr->entry->lock_bucket;
04079 LOCK(&adb->entrylocks[bucket]);
04080
04081 adjustsrtt(addr, 0, DNS_ADB_RTTADJAGE, now);
04082
04083 UNLOCK(&adb->entrylocks[bucket]);
04084 }
04085
04086 static void
04087 adjustsrtt(dns_adbaddrinfo_t *addr, unsigned int rtt, unsigned int factor,
04088 isc_stdtime_t now)
04089 {
04090 isc_uint64_t new_srtt;
04091
04092 if (factor == DNS_ADB_RTTADJAGE) {
04093 if (addr->entry->lastage != now) {
04094 new_srtt = addr->entry->srtt;
04095 new_srtt <<= 9;
04096 new_srtt -= addr->entry->srtt;
04097 new_srtt >>= 9;
04098 addr->entry->lastage = now;
04099 } else
04100 new_srtt = addr->entry->srtt;
04101 } else
04102 new_srtt = ((isc_uint64_t)addr->entry->srtt / 10 * factor)
04103 + ((isc_uint64_t)rtt / 10 * (10 - factor));
04104
04105 addr->entry->srtt = (unsigned int) new_srtt;
04106 addr->srtt = (unsigned int) new_srtt;
04107
04108 if (addr->entry->expires == 0)
04109 addr->entry->expires = now + ADB_ENTRY_WINDOW;
04110 }
04111
04112 void
04113 dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
04114 unsigned int bits, unsigned int mask)
04115 {
04116 int bucket;
04117 isc_stdtime_t now;
04118
04119 REQUIRE(DNS_ADB_VALID(adb));
04120 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04121
04122 REQUIRE((bits & ENTRY_IS_DEAD) == 0);
04123 REQUIRE((mask & ENTRY_IS_DEAD) == 0);
04124
04125 bucket = addr->entry->lock_bucket;
04126 LOCK(&adb->entrylocks[bucket]);
04127
04128 addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
04129 if (addr->entry->expires == 0) {
04130 isc_stdtime_get(&now);
04131 addr->entry->expires = now + ADB_ENTRY_WINDOW;
04132 }
04133
04134
04135
04136
04137
04138 addr->flags = (addr->flags & ~mask) | (bits & mask);
04139
04140 UNLOCK(&adb->entrylocks[bucket]);
04141 }
04142
04143 #define EDNSTOS 3U
04144 isc_boolean_t
04145 dns_adb_noedns(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
04146 int bucket;
04147 isc_boolean_t noedns = ISC_FALSE;
04148
04149 REQUIRE(DNS_ADB_VALID(adb));
04150 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04151
04152 bucket = addr->entry->lock_bucket;
04153 LOCK(&adb->entrylocks[bucket]);
04154 if (addr->entry->edns == 0U &&
04155 (addr->entry->plain > EDNSTOS || addr->entry->to4096 > EDNSTOS)) {
04156 if (((addr->entry->plain + addr->entry->to4096) & 0x3f) != 0) {
04157 noedns = ISC_TRUE;
04158 } else {
04159
04160
04161
04162 addr->entry->plain++;
04163 if (addr->entry->plain == 0xff) {
04164 addr->entry->edns >>= 1;
04165 addr->entry->to4096 >>= 1;
04166 addr->entry->to1432 >>= 1;
04167 addr->entry->to1232 >>= 1;
04168 addr->entry->to512 >>= 1;
04169 addr->entry->plain >>= 1;
04170 addr->entry->plainto >>= 1;
04171 }
04172 }
04173 }
04174 UNLOCK(&adb->entrylocks[bucket]);
04175 return (noedns);
04176 }
04177
04178 void
04179 dns_adb_plainresponse(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
04180 int bucket;
04181
04182 REQUIRE(DNS_ADB_VALID(adb));
04183 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04184
04185 bucket = addr->entry->lock_bucket;
04186 LOCK(&adb->entrylocks[bucket]);
04187
04188 addr->entry->plain++;
04189 if (addr->entry->plain == 0xff) {
04190 addr->entry->edns >>= 1;
04191 addr->entry->to4096 >>= 1;
04192 addr->entry->to1432 >>= 1;
04193 addr->entry->to1232 >>= 1;
04194 addr->entry->to512 >>= 1;
04195 addr->entry->plain >>= 1;
04196 addr->entry->plainto >>= 1;
04197 }
04198 UNLOCK(&adb->entrylocks[bucket]);
04199 }
04200
04201 void
04202 dns_adb_timeout(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
04203 int bucket;
04204
04205 REQUIRE(DNS_ADB_VALID(adb));
04206 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04207
04208 bucket = addr->entry->lock_bucket;
04209 LOCK(&adb->entrylocks[bucket]);
04210
04211
04212
04213
04214 if (addr->entry->edns == 0 && addr->entry->plain == 0) {
04215 addr->entry->to512 = 0;
04216 addr->entry->to1232 = 0;
04217 addr->entry->to1432 = 0;
04218 addr->entry->to4096 = 0;
04219 } else {
04220 addr->entry->to512 >>= 1;
04221 addr->entry->to1232 >>= 1;
04222 addr->entry->to1432 >>= 1;
04223 addr->entry->to4096 >>= 1;
04224 }
04225 addr->entry->plainto++;
04226 if (addr->entry->plainto == 0xff) {
04227 addr->entry->edns >>= 1;
04228 addr->entry->plain >>= 1;
04229 addr->entry->plainto >>= 1;
04230 }
04231 UNLOCK(&adb->entrylocks[bucket]);
04232 }
04233
04234 void
04235 dns_adb_ednsto(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int size) {
04236 int bucket;
04237
04238 REQUIRE(DNS_ADB_VALID(adb));
04239 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04240
04241 bucket = addr->entry->lock_bucket;
04242 LOCK(&adb->entrylocks[bucket]);
04243
04244 if (size <= 512U) {
04245 if (addr->entry->to512 <= EDNSTOS) {
04246 addr->entry->to512++;
04247 addr->entry->to1232++;
04248 addr->entry->to1432++;
04249 addr->entry->to4096++;
04250 }
04251 } else if (size <= 1232U) {
04252 if (addr->entry->to1232 <= EDNSTOS) {
04253 addr->entry->to1232++;
04254 addr->entry->to1432++;
04255 addr->entry->to4096++;
04256 }
04257 } else if (size <= 1432U) {
04258 if (addr->entry->to1432 <= EDNSTOS) {
04259 addr->entry->to1432++;
04260 addr->entry->to4096++;
04261 }
04262 } else {
04263 if (addr->entry->to4096 <= EDNSTOS)
04264 addr->entry->to4096++;
04265 }
04266
04267 if (addr->entry->to4096 == 0xff) {
04268 addr->entry->edns >>= 1;
04269 addr->entry->to4096 >>= 1;
04270 addr->entry->to1432 >>= 1;
04271 addr->entry->to1232 >>= 1;
04272 addr->entry->to512 >>= 1;
04273 addr->entry->plain >>= 1;
04274 addr->entry->plainto >>= 1;
04275 }
04276 UNLOCK(&adb->entrylocks[bucket]);
04277 }
04278
04279 void
04280 dns_adb_setudpsize(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int size) {
04281 int bucket;
04282
04283 REQUIRE(DNS_ADB_VALID(adb));
04284 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04285
04286 bucket = addr->entry->lock_bucket;
04287 LOCK(&adb->entrylocks[bucket]);
04288 if (size < 512U)
04289 size = 512U;
04290 if (size > addr->entry->udpsize)
04291 addr->entry->udpsize = size;
04292 addr->entry->edns++;
04293 if (addr->entry->edns == 0xff) {
04294 addr->entry->edns >>= 1;
04295 addr->entry->to4096 >>= 1;
04296 addr->entry->to1432 >>= 1;
04297 addr->entry->to1232 >>= 1;
04298 addr->entry->to512 >>= 1;
04299 addr->entry->plain >>= 1;
04300 addr->entry->plainto >>= 1;
04301 }
04302 UNLOCK(&adb->entrylocks[bucket]);
04303 }
04304
04305 unsigned int
04306 dns_adb_getudpsize(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
04307 int bucket;
04308 unsigned int size;
04309
04310 REQUIRE(DNS_ADB_VALID(adb));
04311 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04312
04313 bucket = addr->entry->lock_bucket;
04314 LOCK(&adb->entrylocks[bucket]);
04315 size = addr->entry->udpsize;
04316 UNLOCK(&adb->entrylocks[bucket]);
04317
04318 return (size);
04319 }
04320
04321 unsigned int
04322 dns_adb_probesize(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
04323 return dns_adb_probesize2(adb, addr, 0);
04324 }
04325
04326 unsigned int
04327 dns_adb_probesize2(dns_adb_t *adb, dns_adbaddrinfo_t *addr, int lookups) {
04328 int bucket;
04329 unsigned int size;
04330
04331 REQUIRE(DNS_ADB_VALID(adb));
04332 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04333
04334 bucket = addr->entry->lock_bucket;
04335 LOCK(&adb->entrylocks[bucket]);
04336 if (addr->entry->to1232 > EDNSTOS || lookups >= 2)
04337 size = 512;
04338 else if (addr->entry->to1432 > EDNSTOS || lookups >= 1)
04339 size = 1232;
04340 else if (addr->entry->to4096 > EDNSTOS)
04341 size = 1432;
04342 else
04343 size = 4096;
04344
04345
04346
04347
04348 if (lookups > 0 &&
04349 size < addr->entry->udpsize && addr->entry->udpsize < 4096)
04350 size = addr->entry->udpsize;
04351 UNLOCK(&adb->entrylocks[bucket]);
04352
04353 return (size);
04354 }
04355
04356 void
04357 dns_adb_setsit(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
04358 const unsigned char *sit, size_t len)
04359 {
04360 int bucket;
04361
04362 REQUIRE(DNS_ADB_VALID(adb));
04363 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04364
04365 bucket = addr->entry->lock_bucket;
04366 LOCK(&adb->entrylocks[bucket]);
04367
04368 if (addr->entry->sit != NULL &&
04369 (sit == NULL || len != addr->entry->sitlen)) {
04370 isc_mem_put(adb->mctx, addr->entry->sit, addr->entry->sitlen);
04371 addr->entry->sit = NULL;
04372 addr->entry->sitlen = 0;
04373 }
04374
04375 if (addr->entry->sit == NULL && sit != NULL && len != 0U) {
04376 addr->entry->sit = isc_mem_get(adb->mctx, len);
04377 if (addr->entry->sit != NULL)
04378 addr->entry->sitlen = (isc_uint16_t)len;
04379 }
04380
04381 if (addr->entry->sit != NULL)
04382 memmove(addr->entry->sit, sit, len);
04383 UNLOCK(&adb->entrylocks[bucket]);
04384 }
04385
04386 size_t
04387 dns_adb_getsit(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
04388 unsigned char *sit, size_t len)
04389 {
04390 int bucket;
04391
04392 REQUIRE(DNS_ADB_VALID(adb));
04393 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04394
04395 bucket = addr->entry->lock_bucket;
04396 LOCK(&adb->entrylocks[bucket]);
04397 if (sit != NULL && addr->entry->sit != NULL &&
04398 len >= addr->entry->sitlen)
04399 {
04400 memmove(sit, addr->entry->sit, addr->entry->sitlen);
04401 len = addr->entry->sitlen;
04402 } else
04403 len = 0;
04404 UNLOCK(&adb->entrylocks[bucket]);
04405
04406 return (len);
04407 }
04408
04409 isc_result_t
04410 dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
04411 dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
04412 {
04413 int bucket;
04414 dns_adbentry_t *entry;
04415 dns_adbaddrinfo_t *addr;
04416 isc_result_t result;
04417 in_port_t port;
04418
04419 REQUIRE(DNS_ADB_VALID(adb));
04420 REQUIRE(addrp != NULL && *addrp == NULL);
04421
04422 UNUSED(now);
04423
04424 result = ISC_R_SUCCESS;
04425 bucket = DNS_ADB_INVALIDBUCKET;
04426 entry = find_entry_and_lock(adb, sa, &bucket, now);
04427 INSIST(bucket != DNS_ADB_INVALIDBUCKET);
04428 if (adb->entry_sd[bucket]) {
04429 result = ISC_R_SHUTTINGDOWN;
04430 goto unlock;
04431 }
04432 if (entry == NULL) {
04433
04434
04435
04436 entry = new_adbentry(adb);
04437 if (entry == NULL) {
04438 result = ISC_R_NOMEMORY;
04439 goto unlock;
04440 }
04441 entry->sockaddr = *sa;
04442 link_entry(adb, bucket, entry);
04443 DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
04444 } else
04445 DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
04446
04447 port = isc_sockaddr_getport(sa);
04448 addr = new_adbaddrinfo(adb, entry, port);
04449 if (addr == NULL) {
04450 result = ISC_R_NOMEMORY;
04451 } else {
04452 inc_entry_refcnt(adb, entry, ISC_FALSE);
04453 *addrp = addr;
04454 }
04455
04456 unlock:
04457 UNLOCK(&adb->entrylocks[bucket]);
04458
04459 return (result);
04460 }
04461
04462 void
04463 dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
04464 dns_adbaddrinfo_t *addr;
04465 dns_adbentry_t *entry;
04466 int bucket;
04467 isc_stdtime_t now;
04468 isc_boolean_t want_check_exit = ISC_FALSE;
04469 isc_boolean_t overmem;
04470
04471 REQUIRE(DNS_ADB_VALID(adb));
04472 REQUIRE(addrp != NULL);
04473 addr = *addrp;
04474 REQUIRE(DNS_ADBADDRINFO_VALID(addr));
04475 entry = addr->entry;
04476 REQUIRE(DNS_ADBENTRY_VALID(entry));
04477
04478 *addrp = NULL;
04479 overmem = isc_mem_isovermem(adb->mctx);
04480
04481 bucket = addr->entry->lock_bucket;
04482 LOCK(&adb->entrylocks[bucket]);
04483
04484 if (entry->expires == 0) {
04485 isc_stdtime_get(&now);
04486 entry->expires = now + ADB_ENTRY_WINDOW;
04487 }
04488
04489 want_check_exit = dec_entry_refcnt(adb, overmem, entry, ISC_FALSE);
04490
04491 UNLOCK(&adb->entrylocks[bucket]);
04492
04493 addr->entry = NULL;
04494 free_adbaddrinfo(adb, &addr);
04495
04496 if (want_check_exit) {
04497 LOCK(&adb->lock);
04498 check_exit(adb);
04499 UNLOCK(&adb->lock);
04500 }
04501 }
04502
04503 void
04504 dns_adb_flush(dns_adb_t *adb) {
04505 unsigned int i;
04506
04507 INSIST(DNS_ADB_VALID(adb));
04508
04509 LOCK(&adb->lock);
04510
04511
04512
04513
04514 for (i = 0; i < adb->nnames; i++)
04515 RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
04516 for (i = 0; i < adb->nentries; i++)
04517 RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
04518
04519 #ifdef DUMP_ADB_AFTER_CLEANING
04520 dump_adb(adb, stdout, ISC_TRUE, INT_MAX);
04521 #endif
04522
04523 UNLOCK(&adb->lock);
04524 }
04525
04526 void
04527 dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
04528 dns_adbname_t *adbname;
04529 dns_adbname_t *nextname;
04530 int bucket;
04531
04532 REQUIRE(DNS_ADB_VALID(adb));
04533 REQUIRE(name != NULL);
04534
04535 LOCK(&adb->lock);
04536 bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames;
04537 LOCK(&adb->namelocks[bucket]);
04538 adbname = ISC_LIST_HEAD(adb->names[bucket]);
04539 while (adbname != NULL) {
04540 nextname = ISC_LIST_NEXT(adbname, plink);
04541 if (!NAME_DEAD(adbname) &&
04542 dns_name_equal(name, &adbname->name)) {
04543 RUNTIME_CHECK(kill_name(&adbname,
04544 DNS_EVENT_ADBCANCELED) ==
04545 ISC_FALSE);
04546 }
04547 adbname = nextname;
04548 }
04549 UNLOCK(&adb->namelocks[bucket]);
04550 UNLOCK(&adb->lock);
04551 }
04552
04553 void
04554 dns_adb_flushnames(dns_adb_t *adb, dns_name_t *name) {
04555 dns_adbname_t *adbname, *nextname;
04556 unsigned int i;
04557
04558 REQUIRE(DNS_ADB_VALID(adb));
04559 REQUIRE(name != NULL);
04560
04561 LOCK(&adb->lock);
04562 for (i = 0; i < adb->nnames; i++) {
04563 LOCK(&adb->namelocks[i]);
04564 adbname = ISC_LIST_HEAD(adb->names[i]);
04565 while (adbname != NULL) {
04566 isc_boolean_t ret;
04567 nextname = ISC_LIST_NEXT(adbname, plink);
04568 if (!NAME_DEAD(adbname) &&
04569 dns_name_issubdomain(&adbname->name, name))
04570 {
04571 ret = kill_name(&adbname,
04572 DNS_EVENT_ADBCANCELED);
04573 RUNTIME_CHECK(ret == ISC_FALSE);
04574 }
04575 adbname = nextname;
04576 }
04577 UNLOCK(&adb->namelocks[i]);
04578 }
04579 UNLOCK(&adb->lock);
04580 }
04581
04582 static void
04583 water(void *arg, int mark) {
04584
04585
04586
04587
04588
04589
04590
04591
04592 dns_adb_t *adb = arg;
04593 isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
04594
04595 REQUIRE(DNS_ADB_VALID(adb));
04596
04597 DP(ISC_LOG_DEBUG(1),
04598 "adb reached %s water mark", overmem ? "high" : "low");
04599 }
04600
04601 void
04602 dns_adb_setadbsize(dns_adb_t *adb, size_t size) {
04603 size_t hiwater, lowater;
04604
04605 INSIST(DNS_ADB_VALID(adb));
04606
04607 if (size != 0U && size < DNS_ADB_MINADBSIZE)
04608 size = DNS_ADB_MINADBSIZE;
04609
04610 hiwater = size - (size >> 3);
04611 lowater = size - (size >> 2);
04612
04613 if (size == 0U || hiwater == 0U || lowater == 0U)
04614 isc_mem_setwater(adb->mctx, water, adb, 0, 0);
04615 else
04616 isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);
04617 }