📄 adb.c
字号:
isc_sockaddr_fromin(&sockaddr, &ina, 0); } else { INSIST(rdata.length == 16); memcpy(in6a.s6_addr, rdata.data, 16); isc_sockaddr_fromin6(&sockaddr, &in6a, 0); } INSIST(nh == NULL); nh = new_adbnamehook(adb, NULL); if (nh == NULL) { adbname->partial_result |= findoptions; result = ISC_R_NOMEMORY; goto fail; } foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket); if (foundentry == NULL) { dns_adbentry_t *entry; entry = new_adbentry(adb); if (entry == NULL) { adbname->partial_result |= findoptions; result = ISC_R_NOMEMORY; goto fail; } entry->sockaddr = sockaddr; entry->refcnt = 1; nh->entry = entry; link_entry(adb, addr_bucket, entry); } else { for (anh = ISC_LIST_HEAD(adbname->v4); anh != NULL; anh = ISC_LIST_NEXT(anh, plink)) if (anh->entry == foundentry) break; if (anh == NULL) { foundentry->refcnt++; nh->entry = foundentry; } else free_adbnamehook(adb, &nh); } new_addresses_added = ISC_TRUE; if (nh != NULL) { if (rdtype == dns_rdatatype_a) ISC_LIST_APPEND(adbname->v4, nh, plink); else ISC_LIST_APPEND(adbname->v6, nh, plink); } nh = NULL; result = dns_rdataset_next(rdataset); } fail: if (nh != NULL) free_adbnamehook(adb, &nh); if (addr_bucket != DNS_ADB_INVALIDBUCKET) UNLOCK(&adb->entrylocks[addr_bucket]); if (rdataset->trust == dns_trust_glue || rdataset->trust == dns_trust_additional) rdataset->ttl = ADB_CACHE_MINIMUM; else rdataset->ttl = ttlclamp(rdataset->ttl); if (rdtype == dns_rdatatype_a) { DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset", adbname->expire_v4, now + rdataset->ttl); adbname->expire_v4 = ISC_MIN(adbname->expire_v4, now + rdataset->ttl); } else { DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset", adbname->expire_v6, now + rdataset->ttl); adbname->expire_v6 = ISC_MIN(adbname->expire_v6, now + rdataset->ttl); } if (new_addresses_added) { /* * Lie a little here. This is more or less so code that cares * can find out if any new information was added or not. */ return (ISC_R_SUCCESS); } return (result);}/* * Requires the name's bucket be locked. */static isc_boolean_tkill_name(dns_adbname_t **n, isc_eventtype_t ev) { dns_adbname_t *name; isc_boolean_t result = ISC_FALSE; isc_boolean_t result4, result6; dns_adb_t *adb; INSIST(n != NULL); name = *n; *n = NULL; INSIST(DNS_ADBNAME_VALID(name)); adb = name->adb; INSIST(DNS_ADB_VALID(adb)); DP(DEF_LEVEL, "killing name %p", name); /* * If we're dead already, just check to see if we should go * away now or not. */ if (NAME_DEAD(name) && !NAME_FETCH(name)) { result = unlink_name(adb, name); free_adbname(adb, &name); if (result) result = dec_adb_irefcnt(adb); return (result); } /* * Clean up the name's various lists. These two are destructive * in that they will always empty the list. */ clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK); result4 = clean_namehooks(adb, &name->v4); result6 = clean_namehooks(adb, &name->v6); clean_target(adb, &name->target); result = ISC_TF(result4 || result6); /* * If fetches are running, cancel them. If none are running, we can * just kill the name here. */ if (!NAME_FETCH(name)) { INSIST(result == ISC_FALSE); result = unlink_name(adb, name); free_adbname(adb, &name); if (result) result = dec_adb_irefcnt(adb); } else { name->flags |= NAME_IS_DEAD; cancel_fetches_at_name(name); } return (result);}/* * Requires the name's bucket be locked and no entry buckets be locked. */static isc_boolean_tcheck_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now, isc_boolean_t overmem){ dns_adb_t *adb; isc_boolean_t expire; isc_boolean_t result4 = ISC_FALSE; isc_boolean_t result6 = ISC_FALSE; INSIST(DNS_ADBNAME_VALID(name)); adb = name->adb; INSIST(DNS_ADB_VALID(adb)); if (overmem) { isc_uint32_t val; isc_random_get(&val); expire = ISC_TF((val % 4) == 0); } else expire = ISC_FALSE; /* * Check to see if we need to remove the v4 addresses */ if (!NAME_FETCH_V4(name) && (expire || EXPIRE_OK(name->expire_v4, now))) { if (NAME_HAS_V4(name)) { DP(DEF_LEVEL, "expiring v4 for name %p", name); result4 = clean_namehooks(adb, &name->v4); name->partial_result &= ~DNS_ADBFIND_INET; } name->expire_v4 = INT_MAX; name->fetch_err = FIND_ERR_UNEXPECTED; } /* * Check to see if we need to remove the v6 addresses */ if (!NAME_FETCH_V6(name) && (expire || EXPIRE_OK(name->expire_v6, now))) { if (NAME_HAS_V6(name)) { DP(DEF_LEVEL, "expiring v6 for name %p", name); result6 = clean_namehooks(adb, &name->v6); name->partial_result &= ~DNS_ADBFIND_INET6; } name->expire_v6 = INT_MAX; name->fetch6_err = FIND_ERR_UNEXPECTED; } /* * Check to see if we need to remove the alias target. */ if (expire || EXPIRE_OK(name->expire_target, now)) { clean_target(adb, &name->target); name->expire_target = INT_MAX; } return (ISC_TF(result4 || result6));}/* * Requires the name's bucket be locked. */static inline voidlink_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) { INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET); ISC_LIST_PREPEND(adb->names[bucket], name, plink); name->lock_bucket = bucket; adb->name_refcnt[bucket]++;}/* * Requires the name's bucket be locked. */static inline isc_boolean_tunlink_name(dns_adb_t *adb, dns_adbname_t *name) { int bucket; isc_boolean_t result = ISC_FALSE; bucket = name->lock_bucket; INSIST(bucket != DNS_ADB_INVALIDBUCKET); ISC_LIST_UNLINK(adb->names[bucket], name, plink); name->lock_bucket = DNS_ADB_INVALIDBUCKET; INSIST(adb->name_refcnt[bucket] > 0); adb->name_refcnt[bucket]--; if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0) result = ISC_TRUE; return (result);}/* * Requires the entry's bucket be locked. */static inline voidlink_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) { ISC_LIST_PREPEND(adb->entries[bucket], entry, plink); entry->lock_bucket = bucket; adb->entry_refcnt[bucket]++;}/* * Requires the entry's bucket be locked. */static inline isc_boolean_tunlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) { int bucket; isc_boolean_t result = ISC_FALSE; bucket = entry->lock_bucket; INSIST(bucket != DNS_ADB_INVALIDBUCKET); ISC_LIST_UNLINK(adb->entries[bucket], entry, plink); entry->lock_bucket = DNS_ADB_INVALIDBUCKET; INSIST(adb->entry_refcnt[bucket] > 0); adb->entry_refcnt[bucket]--; if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0) result = ISC_TRUE; return (result);}static inline voidviolate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) { if (isc_mutex_trylock(want) != ISC_R_SUCCESS) { UNLOCK(have); LOCK(want); LOCK(have); }}/* * The ADB _MUST_ be locked before calling. Also, exit conditions must be * checked after calling this function. */static isc_boolean_tshutdown_names(dns_adb_t *adb) { int bucket; isc_boolean_t result = ISC_FALSE; dns_adbname_t *name; dns_adbname_t *next_name; for (bucket = 0; bucket < NBUCKETS; bucket++) { LOCK(&adb->namelocks[bucket]); adb->name_sd[bucket] = ISC_TRUE; name = ISC_LIST_HEAD(adb->names[bucket]); if (name == NULL) { /* * This bucket has no names. We must decrement the * irefcnt ourselves, since it will not be * automatically triggered by a name being unlinked. */ INSIST(result == ISC_FALSE); result = dec_adb_irefcnt(adb); } else { /* * Run through the list. For each name, clean up finds * found there, and cancel any fetches running. When * all the fetches are canceled, the name will destroy * itself. */ while (name != NULL) { next_name = ISC_LIST_NEXT(name, plink); INSIST(result == ISC_FALSE); result = kill_name(&name, DNS_EVENT_ADBSHUTDOWN); name = next_name; } } UNLOCK(&adb->namelocks[bucket]); } return (result);}/* * The ADB _MUST_ be locked before calling. Also, exit conditions must be * checked after calling this function. */static isc_boolean_tshutdown_entries(dns_adb_t *adb) { int bucket; isc_boolean_t result = ISC_FALSE; dns_adbentry_t *entry; dns_adbentry_t *next_entry; for (bucket = 0; bucket < NBUCKETS; bucket++) { LOCK(&adb->entrylocks[bucket]); adb->entry_sd[bucket] = ISC_TRUE; entry = ISC_LIST_HEAD(adb->entries[bucket]); if (entry == NULL) { /* * This bucket has no entries. We must decrement the * irefcnt ourselves, since it will not be * automatically triggered by an entry being unlinked. */ result = dec_adb_irefcnt(adb); } else { /* * Run through the list. Cleanup any entries not * associated with names, and which are not in use. */ while (entry != NULL) { next_entry = ISC_LIST_NEXT(entry, plink); if (entry->refcnt == 0 && entry->expires != 0) { result = unlink_entry(adb, entry); free_adbentry(adb, &entry); if (result) result = dec_adb_irefcnt(adb); } entry = next_entry; } } UNLOCK(&adb->entrylocks[bucket]); } return (result);}/* * Name bucket must be locked */static voidcancel_fetches_at_name(dns_adbname_t *name) { if (NAME_FETCH_A(name)) dns_resolver_cancelfetch(name->fetch_a->fetch); if (NAME_FETCH_AAAA(name)) dns_resolver_cancelfetch(name->fetch_aaaa->fetch);}/* * Assumes the name bucket is locked. */static isc_boolean_tclean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) { dns_adbentry_t *entry; dns_adbnamehook_t *namehook; int addr_bucket; isc_boolean_t result = ISC_FALSE; addr_bucket = DNS_ADB_INVALIDBUCKET; namehook = ISC_LIST_HEAD(*namehooks); while (namehook != NULL) { INSIST(DNS_ADBNAMEHOOK_VALID(namehook)); /* * Clean up the entry if needed. */ entry = namehook->entry; if (entry != NULL) { INSIST(DNS_ADBENTRY_VALID(entry)); if (addr_bucket != entry->lock_bucket) { if (addr_bucket != DNS_ADB_INVALIDBUCKET) UNLOCK(&adb->entrylocks[addr_bucket]); addr_bucket = entry->lock_bucket; LOCK(&adb->entrylocks[addr_bucket]); } result = dec_entry_refcnt(adb, entry, ISC_FALSE); } /* * Free the namehook */ namehook->entry = NULL; ISC_LIST_UNLINK(*namehooks, namehook, plink); free_adbnamehook(adb, &namehook); namehook = ISC_LIST_HEAD(*namehooks); } if (addr_bucket != DNS_ADB_INVALIDBUCKET) UNLOCK(&adb->entrylocks[addr_bucket]); return (result);}static voidclean_target(dns_adb_t *adb, dns_name_t *target) { if (dns_name_countlabels(target) > 0) { dns_name_free(target, adb->mctx); dns_name_init(target, NULL); }}static isc_result_tset_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname, dns_rdataset_t *rdataset, dns_name_t *target){ isc_result_t result; dns_namereln_t namereln; unsigned int nlabels; int order; dns_rdata_t rdata = DNS_RDATA_INIT; dns_fixedname_t fixed1, fixed2; dns_name_t *prefix, *new_target; REQUIRE(dns_name_countlabels(target) == 0); if (rdataset->type == dns_rdatatype_cname) { dns_rdata_cname_t cname; /* * Copy the CNAME's target into the target name. */ result = dns_rdataset_first(rdataset); if (result != ISC_R_SUCCESS) return (result); dns_rdataset_current(rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &cname, NULL); if (result != ISC_R_SUCCESS) return (result); result = dns_name_dup(&cname.cname, adb->mctx, target); dns_rdata_freestruct(&cname); if (result != ISC_R_SUCCESS) return (result); } else { dns_rdata_dname_t dname; INSIST(rdataset->type == dns_rdatatype_dname); namereln = dns_name_fullcompare(name, fname, &order, &nlabels); INSIST(namereln == dns_namereln_subdomain); /* * Get the target name of the DNAME. */ result = dns_rdataset_first(rdataset); if (result != ISC_R_SUCCESS) return (result); dns_rdataset_current(rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &dname, NULL); if (result != ISC_R_SUCCESS) return (result); /* * Construct the new target name. */ dns_fixedname_init(&fixed1); prefix = dns_fixedname_name(&fixed1); dns_fixedname_init(&fixed2); new_target = dns_fixedname_name(&fixed2); dns_name_split(name, nlabels, prefix, NULL); result = dns_name_concatenate(prefix, &dname.dname, new_target, NULL); dns_rdata_freestruct(&dname); if (result != ISC_R_SUCCESS) return (result); result = dns_name_dup(new_target, adb->mctx, target); if (result != ISC_R_SUCCESS) return (result); } return (ISC_R_SUCCESS);}/* * Assumes nothing is locked, since this is called by the client.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -