📄 adb.c
字号:
f->fetch = NULL; f->namehook = new_adbnamehook(adb, NULL); if (f->namehook == NULL) goto err; f->entry = new_adbentry(adb); if (f->entry == NULL) goto err; dns_rdataset_init(&f->rdataset); f->magic = DNS_ADBFETCH_MAGIC; return (f); err: if (f->namehook != NULL) free_adbnamehook(adb, &f->namehook); if (f->entry != NULL) free_adbentry(adb, &f->entry); isc_mempool_put(adb->afmp, f); return (NULL);}static inline voidfree_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) { dns_adbfetch_t *f; INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch)); f = *fetch; *fetch = NULL; f->magic = 0; if (f->namehook != NULL) free_adbnamehook(adb, &f->namehook); if (f->entry != NULL) free_adbentry(adb, &f->entry); if (dns_rdataset_isassociated(&f->rdataset)) dns_rdataset_disassociate(&f->rdataset); isc_mempool_put(adb->afmp, f);}/* * Caller must be holding the name lock. */static isc_result_ta6find(void *arg, dns_name_t *a6name, dns_rdatatype_t type, isc_stdtime_t now, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset){ dns_adbname_t *name; dns_adb_t *adb; isc_result_t result; name = arg; INSIST(DNS_ADBNAME_VALID(name)); adb = name->adb; INSIST(DNS_ADB_VALID(adb)); result = dns_view_simplefind(adb->view, a6name, type, now, DNS_DBFIND_GLUEOK, ISC_FALSE, rdataset, sigrdataset); if (result == DNS_R_GLUE) result = ISC_R_SUCCESS; return (result);}/* * Caller must be holding the name lock. */static voida6missing(dns_a6context_t *a6ctx, dns_name_t *a6name) { dns_adbname_t *name; dns_adb_t *adb; dns_adbfetch6_t *fetch; isc_result_t result; name = a6ctx->arg; INSIST(DNS_ADBNAME_VALID(name)); adb = name->adb; INSIST(DNS_ADB_VALID(adb)); fetch = new_adbfetch6(adb, name, a6ctx); if (fetch == NULL) { name->partial_result |= DNS_ADBFIND_INET6; return; } result = dns_resolver_createfetch(adb->view->resolver, a6name, dns_rdatatype_a6, NULL, NULL, NULL, 0, adb->task, fetch_callback_a6, name, &fetch->rdataset, NULL, &fetch->fetch); if (result != ISC_R_SUCCESS) goto cleanup; name->chains = a6ctx->chains; ISC_LIST_APPEND(name->fetches_a6, fetch, plink); cleanup: if (result != ISC_R_SUCCESS) { free_adbfetch6(adb, &fetch); name->partial_result |= DNS_ADBFIND_INET6; }}static inline dns_adbfetch6_t *new_adbfetch6(dns_adb_t *adb, dns_adbname_t *name, dns_a6context_t *a6ctx) { dns_adbfetch6_t *f; f = isc_mempool_get(adb->af6mp); if (f == NULL) return (NULL); f->magic = 0; f->namehook = NULL; f->entry = NULL; f->fetch = NULL; f->flags = 0; f->namehook = new_adbnamehook(adb, NULL); if (f->namehook == NULL) goto err; f->entry = new_adbentry(adb); if (f->entry == NULL) goto err; dns_rdataset_init(&f->rdataset); dns_a6_init(&f->a6ctx, a6find, NULL, import_a6, a6missing, name); if (a6ctx != NULL) dns_a6_copy(a6ctx, &f->a6ctx); ISC_LINK_INIT(f, plink); f->magic = DNS_ADBFETCH6_MAGIC; return (f); err: if (f->namehook != NULL) free_adbnamehook(adb, &f->namehook); if (f->entry != NULL) free_adbentry(adb, &f->entry); isc_mempool_put(adb->af6mp, f); return (NULL);}static inline voidfree_adbfetch6(dns_adb_t *adb, dns_adbfetch6_t **fetch) { dns_adbfetch6_t *f; INSIST(fetch != NULL && DNS_ADBFETCH6_VALID(*fetch)); f = *fetch; *fetch = NULL; f->magic = 0; if (f->namehook != NULL) free_adbnamehook(adb, &f->namehook); if (f->entry != NULL) free_adbentry(adb, &f->entry); if (dns_rdataset_isassociated(&f->rdataset)) dns_rdataset_disassociate(&f->rdataset); isc_mempool_put(adb->af6mp, f);}static inline isc_boolean_tfree_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) { dns_adbfind_t *find; INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp)); find = *findp; *findp = NULL; INSIST(!FIND_HAS_ADDRS(find)); INSIST(!ISC_LINK_LINKED(find, publink)); INSIST(!ISC_LINK_LINKED(find, plink)); INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET); INSIST(find->adbname == NULL); find->magic = 0; DESTROYLOCK(&find->lock); isc_mempool_put(adb->ahmp, find); return (dec_adb_irefcnt(adb));}/* * Copy bits from the entry into the newly allocated addrinfo. The entry * must be locked, and the reference count must be bumped up by one * if this function returns a valid pointer. */static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) { dns_adbaddrinfo_t *ai; ai = isc_mempool_get(adb->aimp); if (ai == NULL) return (NULL); ai->magic = DNS_ADBADDRINFO_MAGIC; ai->sockaddr = entry->sockaddr; isc_sockaddr_setport(&ai->sockaddr, port); ai->srtt = entry->srtt; ai->flags = entry->flags; ai->entry = entry; ISC_LINK_INIT(ai, publink); return (ai);}static inline voidfree_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) { dns_adbaddrinfo_t *ai; INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo)); ai = *ainfo; *ainfo = NULL; INSIST(ai->entry == NULL); INSIST(!ISC_LINK_LINKED(ai, publink)); ai->magic = 0; isc_mempool_put(adb->aimp, ai);}/* * Search for the name. NOTE: The bucket is kept locked on both * success and failure, so it must always be unlocked by the caller! * * On the first call to this function, *bucketp must be set to * DNS_ADB_INVALIDBUCKET. */static inline dns_adbname_t *find_name_and_lock(dns_adb_t *adb, dns_name_t *name, unsigned int options, int *bucketp){ dns_adbname_t *adbname; int bucket; bucket = dns_fullname_hash(name, ISC_FALSE) % NBUCKETS; if (*bucketp == DNS_ADB_INVALIDBUCKET) { LOCK(&adb->namelocks[bucket]); *bucketp = bucket; } else if (*bucketp != bucket) { UNLOCK(&adb->namelocks[*bucketp]); LOCK(&adb->namelocks[bucket]); *bucketp = bucket; } adbname = ISC_LIST_HEAD(adb->names[bucket]); while (adbname != NULL) { if (!NAME_DEAD(adbname)) { if (dns_name_equal(name, &adbname->name) && GLUEHINT_OK(adbname, options) && STARTATZONE_MATCHES(adbname, options)) return (adbname); } adbname = ISC_LIST_NEXT(adbname, plink); } return (NULL);}/* * Search for the address. NOTE: The bucket is kept locked on both * success and failure, so it must always be unlocked by the caller. * * On the first call to this function, *bucketp must be set to * DNS_ADB_INVALIDBUCKET. This will cause a lock to occur. On * later calls (within the same "lock path") it can be left alone, so * if this function is called multiple times locking is only done if * the bucket changes. */static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp) { dns_adbentry_t *entry; int bucket; bucket = isc_sockaddr_hash(addr, ISC_TRUE) % NBUCKETS; if (*bucketp == DNS_ADB_INVALIDBUCKET) { LOCK(&adb->entrylocks[bucket]); *bucketp = bucket; } else if (*bucketp != bucket) { UNLOCK(&adb->entrylocks[*bucketp]); LOCK(&adb->entrylocks[bucket]); *bucketp = bucket; } entry = ISC_LIST_HEAD(adb->entries[bucket]); while (entry != NULL) { if (isc_sockaddr_equal(addr, &entry->sockaddr)) return (entry); entry = ISC_LIST_NEXT(entry, plink); } return (NULL);}/* * Entry bucket MUST be locked! */static isc_boolean_tentry_is_bad_for_zone(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *zone, isc_stdtime_t now){ dns_adbzoneinfo_t *zi, *next_zi; isc_boolean_t is_bad; is_bad = ISC_FALSE; zi = ISC_LIST_HEAD(entry->zoneinfo); if (zi == NULL) return (ISC_FALSE); while (zi != NULL) { next_zi = ISC_LIST_NEXT(zi, plink); /* * Has the entry expired? */ if (zi->lame_timer < now) { ISC_LIST_UNLINK(entry->zoneinfo, zi, plink); free_adbzoneinfo(adb, &zi); } /* * Order tests from least to most expensive. */ if (zi != NULL && !is_bad) { if (dns_name_equal(zone, &zi->zone)) is_bad = ISC_TRUE; } zi = next_zi; } return (is_bad);}static voidcopy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *zone, dns_adbname_t *name, isc_stdtime_t now){ dns_adbnamehook_t *namehook; dns_adbaddrinfo_t *addrinfo; dns_adbentry_t *entry; int bucket; bucket = DNS_ADB_INVALIDBUCKET; if (find->options & DNS_ADBFIND_INET) { namehook = ISC_LIST_HEAD(name->v4); while (namehook != NULL) { entry = namehook->entry; bucket = entry->lock_bucket; LOCK(&adb->entrylocks[bucket]); if (!FIND_RETURNLAME(find) && entry_is_bad_for_zone(adb, entry, zone, now)) { find->options |= DNS_ADBFIND_LAMEPRUNED; goto nextv4; } addrinfo = new_adbaddrinfo(adb, entry, find->port); if (addrinfo == NULL) { find->partial_result |= DNS_ADBFIND_INET; goto out; } /* * Found a valid entry. Add it to the find's list. */ inc_entry_refcnt(adb, entry, ISC_FALSE); ISC_LIST_APPEND(find->list, addrinfo, publink); addrinfo = NULL; nextv4: UNLOCK(&adb->entrylocks[bucket]); bucket = DNS_ADB_INVALIDBUCKET; namehook = ISC_LIST_NEXT(namehook, plink); } } if (find->options & DNS_ADBFIND_INET6) { namehook = ISC_LIST_HEAD(name->v6); while (namehook != NULL) { entry = namehook->entry; bucket = entry->lock_bucket; LOCK(&adb->entrylocks[bucket]); if (entry_is_bad_for_zone(adb, entry, zone, now)) goto nextv6; addrinfo = new_adbaddrinfo(adb, entry, find->port); if (addrinfo == NULL) { find->partial_result |= DNS_ADBFIND_INET6; goto out; } /* * Found a valid entry. Add it to the find's list. */ inc_entry_refcnt(adb, entry, ISC_FALSE); ISC_LIST_APPEND(find->list, addrinfo, publink); addrinfo = NULL; nextv6: UNLOCK(&adb->entrylocks[bucket]); bucket = DNS_ADB_INVALIDBUCKET; namehook = ISC_LIST_NEXT(namehook, plink); } } out: if (bucket != DNS_ADB_INVALIDBUCKET) UNLOCK(&adb->entrylocks[bucket]);}static voidshutdown_task(isc_task_t *task, isc_event_t *ev) { dns_adb_t *adb; UNUSED(task); adb = ev->ev_arg; INSIST(DNS_ADB_VALID(adb)); /* * Kill the timer, and then the ADB itself. Note that this implies * that this task was the one scheduled to get timer events. If * this is not true (and it is unfortunate there is no way to INSIST() * this) badness will occur. */ LOCK(&adb->lock); isc_timer_detach(&adb->timer); UNLOCK(&adb->lock); isc_event_free(&ev); destroy(adb);}/* * name bucket must be locked; adb may be locked; no other locks held. */static isc_boolean_tcheck_expire_name(dns_adbname_t **namep, isc_stdtime_t now) { dns_adbname_t *name; isc_result_t result = ISC_FALSE; INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep)); name = *namep; if (NAME_HAS_V4(name) || NAME_HAS_V6(name)) return (result); if (NAME_FETCH(name)) return (result); if (!EXPIRE_OK(name->expire_v4, now)) return (result); if (!EXPIRE_OK(name->expire_v6, now)) return (result); if (!EXPIRE_OK(name->expire_target, now)) return (result); /* * The name is empty. Delete it. */ result = kill_name(&name, DNS_EVENT_ADBEXPIRED); *namep = NULL; /* * Our caller, or one of its callers, will be calling check_exit() at * some point, so we don't need to do it here. */ return (result);}/* * entry bucket must be locked; adb may be locked; no other locks held. */static isc_boolean_tcheck_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now){ dns_adbentry_t *entry; isc_boolean_t result = ISC_FALSE; INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp)); entry = *entryp; if (entry->refcnt != 0) return (result); if (entry->expires == 0 || entry->expires > now) return (result); /* * The entry is not in use. Delete it. */ DP(DEF_LEVEL, "killing entry %p", entry); INSIST(ISC_LINK_LINKED(entry, plink)); result = unlink_entry(adb, entry); free_adbentry(adb, &entry); if (result) dec_adb_irefcnt(adb); *entryp = NULL; return (result);}/* * ADB must be locked, and no other locks held. */static isc_boolean_tcleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -