📄 resolver.c
字号:
if (bucket_empty) empty_bucket(res);}static voidfctx_start(isc_task_t *task, isc_event_t *event) { fetchctx_t *fctx = event->ev_arg; isc_boolean_t done = ISC_FALSE, bucket_empty = ISC_FALSE; dns_resolver_t *res; unsigned int bucketnum; REQUIRE(VALID_FCTX(fctx)); UNUSED(task); res = fctx->res; bucketnum = fctx->bucketnum; FCTXTRACE("start"); LOCK(&res->buckets[bucketnum].lock); INSIST(fctx->state == fetchstate_init); if (fctx->want_shutdown) { /* * We haven't started this fctx yet, and we've been requested * to shut it down. */ fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN; fctx->state = fetchstate_done; fctx_sendevents(fctx, ISC_R_CANCELED); /* * Since we haven't started, we INSIST that we have no * pending ADB finds and no pending validations. */ INSIST(fctx->pending == 0); INSIST(ISC_LIST_EMPTY(fctx->validators)); if (fctx->references == 0) { /* * It's now safe to destroy this fctx. */ bucket_empty = fctx_destroy(fctx); } done = ISC_TRUE; } else { /* * Normal fctx startup. */ fctx->state = fetchstate_active; /* * Reset the control event for later use in shutting down * the fctx. */ ISC_EVENT_INIT(event, sizeof(*event), 0, NULL, DNS_EVENT_FETCHCONTROL, fctx_doshutdown, fctx, NULL, NULL, NULL); } UNLOCK(&res->buckets[bucketnum].lock); if (!done) { /* * All is well. Start working on the fetch. */ fctx_starttimer(fctx); fctx_try(fctx); } else if (bucket_empty) empty_bucket(res);}/* * Fetch Creation, Joining, and Cancelation. */static inline isc_result_tfctx_join(fetchctx_t *fctx, isc_task_t *task, isc_taskaction_t action, void *arg, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, dns_fetch_t *fetch){ isc_task_t *clone; dns_fetchevent_t *event; FCTXTRACE("join"); /* * We store the task we're going to send this event to in the * sender field. We'll make the fetch the sender when we actually * send the event. */ clone = NULL; isc_task_attach(task, &clone); event = (dns_fetchevent_t *) isc_event_allocate(fctx->res->mctx, clone, DNS_EVENT_FETCHDONE, action, arg, sizeof *event); if (event == NULL) { isc_task_detach(&clone); return (ISC_R_NOMEMORY); } event->result = DNS_R_SERVFAIL; event->qtype = fctx->type; event->db = NULL; event->node = NULL; event->rdataset = rdataset; event->sigrdataset = sigrdataset; event->fetch = fetch; dns_fixedname_init(&event->foundname); /* * Make sure that we can store the sigrdataset in the * first event if it is needed by any of the events. */ if (event->sigrdataset != NULL) ISC_LIST_PREPEND(fctx->events, event, ev_link); else ISC_LIST_APPEND(fctx->events, event, ev_link); fctx->references++; fetch->magic = DNS_FETCH_MAGIC; fetch->private = fctx; return (ISC_R_SUCCESS);}static isc_result_tfctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, dns_name_t *domain, dns_rdataset_t *nameservers, unsigned int options, unsigned int bucketnum, fetchctx_t **fctxp){ fetchctx_t *fctx; isc_result_t result = ISC_R_SUCCESS; isc_result_t iresult; isc_interval_t interval; dns_fixedname_t qdomain; unsigned int findoptions = 0; /* * Caller must be holding the lock for bucket number 'bucketnum'. */ REQUIRE(fctxp != NULL && *fctxp == NULL); fctx = isc_mem_get(res->mctx, sizeof *fctx); if (fctx == NULL) return (ISC_R_NOMEMORY); FCTXTRACE("create"); dns_name_init(&fctx->name, NULL); result = dns_name_dup(name, res->mctx, &fctx->name); if (result != ISC_R_SUCCESS) goto cleanup_fetch; dns_name_init(&fctx->domain, NULL); dns_rdataset_init(&fctx->nameservers); fctx->type = type; fctx->options = options; /* * Note! We do not attach to the task. We are relying on the * resolver to ensure that this task doesn't go away while we are * using it. */ fctx->res = res; fctx->references = 0; fctx->bucketnum = bucketnum; fctx->state = fetchstate_init; fctx->want_shutdown = ISC_FALSE; fctx->cloned = ISC_FALSE; ISC_LIST_INIT(fctx->queries); ISC_LIST_INIT(fctx->finds); ISC_LIST_INIT(fctx->forwaddrs); ISC_LIST_INIT(fctx->forwarders); fctx->fwdpolicy = dns_fwdpolicy_none; ISC_LIST_INIT(fctx->bad); ISC_LIST_INIT(fctx->validators); fctx->find = NULL; fctx->pending = 0; fctx->restarts = 0; fctx->timeouts = 0; if (dns_name_requiresedns(name)) fctx->attributes = FCTX_ATTR_NEEDEDNS0; else fctx->attributes = 0; if (domain == NULL) { dns_forwarders_t *forwarders = NULL; result = dns_fwdtable_find(fctx->res->view->fwdtable, &fctx->name, &forwarders); if (result == ISC_R_SUCCESS) fctx->fwdpolicy = forwarders->fwdpolicy; if (fctx->fwdpolicy != dns_fwdpolicy_only) { /* * The caller didn't supply a query domain and * nameservers, and we're not in forward-only mode, * so find the best nameservers to use. */ if (type == dns_rdatatype_key) findoptions |= DNS_DBFIND_NOEXACT; dns_fixedname_init(&qdomain); result = dns_view_findzonecut(res->view, name, dns_fixedname_name(&qdomain), 0, findoptions, ISC_TRUE, &fctx->nameservers, NULL); if (result != ISC_R_SUCCESS) goto cleanup_name; result = dns_name_dup(dns_fixedname_name(&qdomain), res->mctx, &fctx->domain); if (result != ISC_R_SUCCESS) { dns_rdataset_disassociate(&fctx->nameservers); goto cleanup_name; } } else { /* * We're in forward-only mode. Set the query domain * to ".". */ result = dns_name_dup(dns_rootname, res->mctx, &fctx->domain); if (result != ISC_R_SUCCESS) goto cleanup_name; } } else { result = dns_name_dup(domain, res->mctx, &fctx->domain); if (result != ISC_R_SUCCESS) goto cleanup_name; dns_rdataset_clone(nameservers, &fctx->nameservers); } INSIST(dns_name_issubdomain(&fctx->name, &fctx->domain)); fctx->qmessage = NULL; result = dns_message_create(res->mctx, DNS_MESSAGE_INTENTRENDER, &fctx->qmessage); if (result != ISC_R_SUCCESS) goto cleanup_domain; fctx->rmessage = NULL; result = dns_message_create(res->mctx, DNS_MESSAGE_INTENTPARSE, &fctx->rmessage); if (result != ISC_R_SUCCESS) goto cleanup_qmessage; /* * Compute an expiration time for the entire fetch. */ isc_interval_set(&interval, 30, 0); /* XXXRTH constant */ iresult = isc_time_nowplusinterval(&fctx->expires, &interval); if (iresult != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_time_nowplusinterval: %s", isc_result_totext(iresult)); result = ISC_R_UNEXPECTED; goto cleanup_rmessage; } /* * Default retry interval initialization. We set the interval now * mostly so it won't be uninitialized. It will be set to the * correct value before a query is issued. */ isc_interval_set(&fctx->interval, 2, 0); /* * Create an inactive timer. It will be made active when the fetch * is actually started. */ fctx->timer = NULL; iresult = isc_timer_create(res->timermgr, isc_timertype_inactive, NULL, NULL, res->buckets[bucketnum].task, fctx_timeout, fctx, &fctx->timer); if (iresult != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_timer_create: %s", isc_result_totext(iresult)); result = ISC_R_UNEXPECTED; goto cleanup_rmessage; } /* * Attach to the view's cache and adb. */ fctx->cache = NULL; dns_db_attach(res->view->cachedb, &fctx->cache); fctx->adb = NULL; dns_adb_attach(res->view->adb, &fctx->adb); ISC_LIST_INIT(fctx->events); ISC_LINK_INIT(fctx, link); fctx->magic = FCTX_MAGIC; ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link); *fctxp = fctx; return (ISC_R_SUCCESS); cleanup_rmessage: dns_message_destroy(&fctx->rmessage); cleanup_qmessage: dns_message_destroy(&fctx->qmessage); cleanup_domain: 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); cleanup_name: dns_name_free(&fctx->name, res->mctx); cleanup_fetch: isc_mem_put(res->mctx, fctx, sizeof *fctx); return (result);}/* * Handle Responses */static inline isc_boolean_tis_lame(fetchctx_t *fctx) { dns_message_t *message = fctx->rmessage; dns_name_t *name; dns_rdataset_t *rdataset; isc_result_t result; if (message->rcode != dns_rcode_noerror && message->rcode != dns_rcode_nxdomain) return (ISC_FALSE); if (message->counts[DNS_SECTION_ANSWER] != 0) return (ISC_FALSE); if (message->counts[DNS_SECTION_AUTHORITY] == 0) return (ISC_FALSE); result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); while (result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { dns_namereln_t namereln; int order; unsigned int labels, bits; if (rdataset->type != dns_rdatatype_ns) continue; namereln = dns_name_fullcompare(name, &fctx->domain, &order, &labels, &bits); if (namereln == dns_namereln_equal && (message->flags & DNS_MESSAGEFLAG_AA) != 0) return (ISC_FALSE); if (namereln == dns_namereln_subdomain) return (ISC_FALSE); return (ISC_TRUE); } result = dns_message_nextname(message, DNS_SECTION_AUTHORITY); } return (ISC_FALSE);}static inline voidlog_lame(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo) { char namebuf[DNS_NAME_FORMATSIZE]; char domainbuf[DNS_NAME_FORMATSIZE]; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); isc_sockaddr_format(&addrinfo->sockaddr, addrbuf, sizeof(addrbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, "lame server resolving '%s' (in '%s'?): %s", namebuf, domainbuf, addrbuf);}static inline isc_result_tsame_question(fetchctx_t *fctx) { isc_result_t result; dns_message_t *message = fctx->rmessage; dns_name_t *name; dns_rdataset_t *rdataset; /* * Caller must be holding the fctx lock. */ /* * XXXRTH Currently we support only one question. */ if (message->counts[DNS_SECTION_QUESTION] != 1) return (DNS_R_FORMERR); result = dns_message_firstname(message, DNS_SECTION_QUESTION); if (result != ISC_R_SUCCESS) return (result); name = NULL; dns_message_currentname(message, DNS_SECTION_QUESTION, &name); rdataset = ISC_LIST_HEAD(name->list); INSIST(rdataset != NULL); INSIST(ISC_LIST_NEXT(rdataset, link) == NULL); if (fctx->type != rdataset->type || fctx->res->rdclass != rdataset->rdclass || !dns_name_equal(&fctx->name, name)) return (DNS_R_FORMERR); return (ISC_R_SUCCESS);}static voidclone_results(fetchctx_t *fctx) { dns_fetchevent_t *event, *hevent; isc_result_t result; dns_name_t *name, *hname; /* * Set up any other events to have the same data as the first * event. * * Caller must be holding the appropriate lock. */ fctx->cloned = ISC_TRUE; hevent = ISC_LIST_HEAD(fctx->events); if (hevent == NULL) return; hname = dns_fixedname_name(&hevent->foundname); for (event = ISC_LIST_NEXT(hevent, ev_link); event != NULL; event = ISC_LIST_NEXT(event, ev_link)) { name = dns_fixedname_name(&event->foundname); result = dns_name_copy(hname, name, NULL); if (result != ISC_R_SUCCESS) event->result = result; else event->result = hevent->result; dns_db_attach(hevent->db, &event->db); dns_db_attachnode(hevent->db, hevent->node, &event->node); INSIST(hevent->rdataset != NULL); INSIST(event->rdataset != NULL); if (dns_rdataset_isassociated(hevent->rdataset)) dns_rdataset_clone(hevent->rdataset, event->rdataset); INSIST(! (hevent->sigrdataset == NULL && event->sigrdataset != NULL)); if (hevent->sigrdataset != NULL && dns_rdataset_isassociated(hevent->sigrdataset) && event->sigrdataset != NULL) dns_rdataset_clone(hevent->sigrdataset, event->sigrdataset); }}#define CACHE(r) (((r)->attributes & DNS_RDATASETATTR_CACHE) != 0)#define ANSWER(r) (((r)->attributes & DNS_RDATASETATTR_ANSWER) != 0)#define ANSWERSIG(r) (((r)->attributes & DNS_RDATASETATTR_ANSWERSIG) != 0)#define EXTERNAL(r) (((r)->attributes & DNS_RDATASETATTR_EXTERNAL) != 0)#define CHAINING(r) (((r)->attributes & DNS_RDATASETATTR_CHAINING) != 0)#define CHASE(r) (((r)->attributes & DNS_RDATASETATTR_CHASE) != 0)/* * Destroy '*fctx' if it is ready to be destroyed (i.e., if it has * no references and is no longer waiting for any events). If this * was the last fctx in the resolver, destroy the resolver. * * Requires: * '*fctx' is shutting down. */static voidmaybe_destroy(fetchctx_t *fctx) { unsigned int bucketnum; isc_boolean_t bucket_empty = ISC_FALSE; dns_resolver_t *res = fctx->res; REQUIRE(SHUTTINGDOWN(fctx)); if (fctx->pending != 0 || !ISC_LIST_EMPTY(fctx->validators)) return; bucketnum = fctx->bucketnum; LOCK(&res->buckets[bucketnum].lock); if (fctx->references == 0) bucket_empty = fctx_destroy(fctx); UNLOCK(&res->buckets[bucketnum].lock); if (bucket_empty) empty_bucket(res);}/* * The validator has finished. */static voidvalidated(isc_task_t *task, isc_event_t *event) { isc_result_t result = ISC_R_SUCCESS; isc_result_t eresult = ISC_R_SUCCESS; isc_stdtime_t now; fetchctx_t *fctx; dns_validatorevent_t *vevent; dns_fetchevent_t *hevent; dns_rdataset_t *ardataset = NULL; dns_rdataset_t *asigrdataset = NULL; dns_dbnode_t *node = NULL; isc_boolean_t negative; isc_boolean_t chaining; isc_boolean_t sentresponse; isc_uint32_t tt
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -