📄 resolver.c
字号:
stdoptions = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT; if (fctx->restarts == 1) { /* * To avoid sending out a flood of queries likely to * result in NXRRSET, we suppress fetches for address * families we don't have the first time through, * provided that we have addresses in some family we * can use. * * We don't want to set this option all the time, since * if fctx->restarts > 1, we've clearly been having trouble * with the addresses we had, so getting more could help. */ stdoptions |= DNS_ADBFIND_AVOIDFETCHES; } if (res->dispatchv4 != NULL) stdoptions |= DNS_ADBFIND_INET; if (res->dispatchv6 != NULL) stdoptions |= DNS_ADBFIND_INET6; isc_stdtime_get(&now); restart: INSIST(ISC_LIST_EMPTY(fctx->finds)); result = dns_rdataset_first(&fctx->nameservers); while (result == ISC_R_SUCCESS) { dns_rdataset_current(&fctx->nameservers, &rdata); /* * Extract the name from the NS record. */ result = dns_rdata_tostruct(&rdata, &ns, NULL); if (result != ISC_R_SUCCESS) { dns_rdataset_next(&fctx->nameservers); continue; } options = stdoptions; /* * If this name is a subdomain of the query domain, tell * the ADB to start looking using zone/hint data. This keeps * us from getting stuck if the nameserver is beneath the * zone cut and we don't know its address (e.g. because the * A record has expired). */ if (dns_name_issubdomain(&ns.name, &fctx->domain)) options |= DNS_ADBFIND_STARTATZONE; options |= DNS_ADBFIND_GLUEOK; options |= DNS_ADBFIND_HINTOK; /* * See what we know about this address. */ find = NULL; result = dns_adb_createfind(fctx->adb, res->buckets[fctx->bucketnum].task, fctx_finddone, fctx, &ns.name, &fctx->domain, options, now, NULL, res->view->dstport, &find); if (result != ISC_R_SUCCESS) { if (result == DNS_R_ALIAS) { /* * XXXRTH Follow the CNAME/DNAME chain? */ dns_adb_destroyfind(&find); } } else if (!ISC_LIST_EMPTY(find->list)) { /* * We have at least some of the addresses for the * name. */ INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0); sort_adbfind(find); ISC_LIST_APPEND(fctx->finds, find, publink); } else { /* * We don't know any of the addresses for this * name. */ if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) { /* * We're looking for them and will get an * event about it later. */ fctx->pending++; } else { /* * And ADB isn't going to send us any events * either. This find loses. */ if ((find->options & DNS_ADBFIND_LAMEPRUNED) != 0) { /* * The ADB pruned lame servers for * this name. Remember that in case * we get desperate later on. */ pruned = ISC_TRUE; } dns_adb_destroyfind(&find); } } dns_rdata_reset(&rdata); dns_rdata_freestruct(&ns); result = dns_rdataset_next(&fctx->nameservers); } if (result != ISC_R_NOMORE) return (result); out: /* * Mark all known bad servers. */ all_bad = mark_bad(fctx); /* * How are we doing? */ if (all_bad) { /* * We've got no addresses. */ if (fctx->pending > 0) { /* * We're fetching the addresses, but don't have any * yet. Tell the caller to wait for an answer. */ result = DNS_R_WAIT; } else if (pruned) { /* * Some addresses were removed by lame pruning. * Turn pruning off and try again. */ FCTXTRACE("restarting with returnlame"); INSIST((stdoptions & DNS_ADBFIND_RETURNLAME) == 0); stdoptions |= DNS_ADBFIND_RETURNLAME; pruned = ISC_FALSE; fctx_cleanupfinds(fctx); goto restart; } else { /* * We've lost completely. We don't know any * addresses, and the ADB has told us it can't get * them. */ FCTXTRACE("no addresses"); result = ISC_R_FAILURE; } } else { /* * We've found some addresses. We might still be looking * for more addresses. */ /* * XXXRTH We could sort the forwaddrs here if the caller * wants to use the forwaddrs in "best order" as * opposed to "fixed order". */ sort_finds(fctx); result = ISC_R_SUCCESS; } return (result);}static inline voidpossibly_mark(fetchctx_t *fctx, dns_adbaddrinfo_t *addr){ isc_netaddr_t na; char buf[ISC_NETADDR_FORMATSIZE]; isc_sockaddr_t *sa; isc_boolean_t aborted = ISC_FALSE; isc_boolean_t bogus; dns_acl_t *blackhole; isc_netaddr_t ipaddr; dns_peer_t *peer = NULL; dns_resolver_t *res; const char *msg = NULL; sa = &addr->sockaddr; res = fctx->res; isc_netaddr_fromsockaddr(&ipaddr, sa); blackhole = dns_dispatchmgr_getblackhole(res->dispatchmgr); (void) dns_peerlist_peerbyaddr(res->view->peers, &ipaddr, &peer); if (blackhole != NULL) { int match; if (dns_acl_match(&ipaddr, NULL, blackhole, &res->view->aclenv, &match, NULL) == ISC_R_SUCCESS && match > 0) aborted = ISC_TRUE; } if (peer != NULL && dns_peer_getbogus(peer, &bogus) == ISC_R_SUCCESS && bogus) aborted = ISC_TRUE; if (aborted) { addr->flags |= FCTX_ADDRINFO_MARK; msg = "ignoring blackholed / bogus server: "; } else if (sa->type.sa.sa_family != AF_INET6) { return; } else if (IN6_IS_ADDR_V4MAPPED(&sa->type.sin6.sin6_addr)) { addr->flags |= FCTX_ADDRINFO_MARK; msg = "ignoring IPv6 mapped IPV4 address: "; } else if (IN6_IS_ADDR_V4COMPAT(&sa->type.sin6.sin6_addr)) { addr->flags |= FCTX_ADDRINFO_MARK; msg = "ignoring IPv6 compatibility IPV4 address: "; } else return; if (!isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3))) return; isc_netaddr_fromsockaddr(&na, sa); isc_netaddr_format(&na, buf, sizeof buf); FCTXTRACE2(msg, buf);}static inline dns_adbaddrinfo_t *fctx_nextaddress(fetchctx_t *fctx) { dns_adbfind_t *find; dns_adbaddrinfo_t *addrinfo; /* * Return the next untried address, if any. */ /* * Find the first unmarked forwarder (if any). */ for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { possibly_mark(fctx, addrinfo); if (UNMARKED(addrinfo)) { addrinfo->flags |= FCTX_ADDRINFO_MARK; fctx->find = NULL; return (addrinfo); } } /* * No forwarders. Move to the next find. */ find = fctx->find; if (find == NULL) find = ISC_LIST_HEAD(fctx->finds); else { find = ISC_LIST_NEXT(find, publink); if (find == NULL) find = ISC_LIST_HEAD(fctx->finds); } /* * Find the first unmarked addrinfo. */ addrinfo = NULL; while (find != fctx->find) { for (addrinfo = ISC_LIST_HEAD(find->list); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { possibly_mark(fctx, addrinfo); if (UNMARKED(addrinfo)) { addrinfo->flags |= FCTX_ADDRINFO_MARK; break; } } if (addrinfo != NULL) break; find = ISC_LIST_NEXT(find, publink); if (find != fctx->find && find == NULL) find = ISC_LIST_HEAD(fctx->finds); } fctx->find = find; return (addrinfo);}static voidfctx_try(fetchctx_t *fctx) { isc_result_t result; dns_adbaddrinfo_t *addrinfo; FCTXTRACE("try"); REQUIRE(!ADDRWAIT(fctx)); addrinfo = fctx_nextaddress(fctx); if (addrinfo == NULL) { /* * We have no more addresses. Start over. */ fctx_cancelqueries(fctx, ISC_TRUE); fctx_cleanupfinds(fctx); fctx_cleanupforwaddrs(fctx); result = fctx_getaddresses(fctx); if (result == DNS_R_WAIT) { /* * Sleep waiting for addresses. */ FCTXTRACE("addrwait"); fctx->attributes |= FCTX_ATTR_ADDRWAIT; return; } else if (result != ISC_R_SUCCESS) { /* * Something bad happened. */ fctx_done(fctx, result); return; } addrinfo = fctx_nextaddress(fctx); /* * While we may have addresses from the ADB, they * might be bad ones. In this case, return SERVFAIL. */ if (addrinfo == NULL) { fctx_done(fctx, DNS_R_SERVFAIL); return; } } result = fctx_query(fctx, addrinfo, fctx->options); if (result != ISC_R_SUCCESS) fctx_done(fctx, result);}static isc_boolean_tfctx_destroy(fetchctx_t *fctx) { dns_resolver_t *res; unsigned int bucketnum; isc_sockaddr_t *sa, *next_sa; /* * Caller must be holding the bucket lock. */ REQUIRE(VALID_FCTX(fctx)); REQUIRE(fctx->state == fetchstate_done || fctx->state == fetchstate_init); REQUIRE(ISC_LIST_EMPTY(fctx->events)); REQUIRE(ISC_LIST_EMPTY(fctx->queries)); REQUIRE(ISC_LIST_EMPTY(fctx->finds)); REQUIRE(fctx->pending == 0); REQUIRE(ISC_LIST_EMPTY(fctx->validators)); REQUIRE(fctx->references == 0); FCTXTRACE("destroy"); res = fctx->res; bucketnum = fctx->bucketnum; ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link); /* * Free bad. */ for (sa = ISC_LIST_HEAD(fctx->bad); sa != NULL; sa = next_sa) { next_sa = ISC_LIST_NEXT(sa, link); ISC_LIST_UNLINK(fctx->bad, sa, link); isc_mem_put(res->mctx, sa, sizeof *sa); } isc_timer_detach(&fctx->timer); dns_message_destroy(&fctx->rmessage); dns_message_destroy(&fctx->qmessage); if (dns_name_countlabels(&fctx->domain) > 0) dns_name_free(&fctx->domain, res->mctx); if (dns_rdataset_isassociated(&fctx->nameservers)) dns_rdataset_disassociate(&fctx->nameservers); dns_name_free(&fctx->name, res->mctx); dns_db_detach(&fctx->cache); dns_adb_detach(&fctx->adb); isc_mem_put(res->mctx, fctx, sizeof *fctx); if (res->buckets[bucketnum].exiting && ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs)) return (ISC_TRUE); return (ISC_FALSE);}/* * Fetch event handlers. */static voidfctx_timeout(isc_task_t *task, isc_event_t *event) { fetchctx_t *fctx = event->ev_arg; REQUIRE(VALID_FCTX(fctx)); UNUSED(task); FCTXTRACE("timeout"); if (event->ev_type == ISC_TIMEREVENT_LIFE) { fctx_done(fctx, ISC_R_TIMEDOUT); } else { fctx->timeouts++; /* * We could cancel the running queries here, or we could let * them keep going. Right now we choose the latter... */ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; /* * Our timer has triggered. Reestablish the fctx lifetime * timer. */ fctx_starttimer(fctx); /* * Keep trying. */ fctx_try(fctx); } isc_event_free(&event);}static voidfctx_shutdown(fetchctx_t *fctx) { isc_event_t *cevent; /* * Start the shutdown process for fctx, if it isn't already underway. */ FCTXTRACE("shutdown"); /* * The caller must be holding the appropriate bucket lock. */ if (fctx->want_shutdown) return; fctx->want_shutdown = ISC_TRUE; /* * Unless we're still initializing (in which case the * control event is still outstanding), we need to post * the control event to tell the fetch we want it to * exit. */ if (fctx->state != fetchstate_init) { cevent = &fctx->control_event; isc_task_send(fctx->res->buckets[fctx->bucketnum].task, &cevent); }}static voidfctx_doshutdown(isc_task_t *task, isc_event_t *event) { fetchctx_t *fctx = event->ev_arg; isc_boolean_t bucket_empty = ISC_FALSE; dns_resolver_t *res; unsigned int bucketnum; dns_validator_t *validator; REQUIRE(VALID_FCTX(fctx)); UNUSED(task); res = fctx->res; bucketnum = fctx->bucketnum; FCTXTRACE("doshutdown"); /* * An fctx that is shutting down is no longer in ADDRWAIT mode. */ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; /* * Cancel all pending validators. Note that this must be done * without the bucket lock held, since that could cause deadlock. */ validator = ISC_LIST_HEAD(fctx->validators); while (validator != NULL) { dns_validator_cancel(validator); validator = ISC_LIST_NEXT(validator, link); } /* * Shut down anything that is still running on behalf of this * fetch. To avoid deadlock with the ADB, we must do this * before we lock the bucket lock. */ fctx_stopeverything(fctx, ISC_FALSE); LOCK(&res->buckets[bucketnum].lock); fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN; INSIST(fctx->state == fetchstate_active || fctx->state == fetchstate_done); INSIST(fctx->want_shutdown); if (fctx->state != fetchstate_done) { fctx->state = fetchstate_done; fctx_sendevents(fctx, ISC_R_CANCELED); } if (fctx->references == 0 && fctx->pending == 0 && ISC_LIST_EMPTY(fctx->validators)) bucket_empty = fctx_destroy(fctx); UNLOCK(&res->buckets[bucketnum].lock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -