⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 resolver.c

📁 bind-3.2.
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -