📄 query.c
字号:
unsigned int labels; isc_buffer_t *dbuf, b; dns_name_t *fname; isc_result_t result; name = *namep; if ((name->attributes & DNS_NAMEATTR_WILDCARD) == 0) { query_addrrset(client, namep, rdatasetp, sigrdatasetp, NULL, DNS_SECTION_AUTHORITY); return; } if (sigrdatasetp == NULL) return; sigrdataset = *sigrdatasetp; if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset)) return; result = dns_rdataset_first(sigrdataset); if (result != ISC_R_SUCCESS) return; dns_rdata_init(&sigrdata); dns_rdataset_current(sigrdataset, &sigrdata); result = dns_rdata_tostruct(&sigrdata, &sig, NULL); if (result != ISC_R_SUCCESS) return; labels = dns_name_countlabels(name); if ((unsigned int)sig.labels + 1 >= labels) return; /* XXX */ query_addwildcardproof(client, db, client->query.qname, ISC_TRUE); /* * We'll need some resources... */ dbuf = query_getnamebuf(client); if (dbuf == NULL) return; fname = query_newname(client, dbuf, &b); if (fname == NULL) return; dns_name_split(name, sig.labels + 1, NULL, fname); /* This will succeed, since we've stripped labels. */ RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, fname, fname, NULL) == ISC_R_SUCCESS); query_addrrset(client, &fname, rdatasetp, sigrdatasetp, dbuf, DNS_SECTION_AUTHORITY);}static voidquery_resume(isc_task_t *task, isc_event_t *event) { dns_fetchevent_t *devent = (dns_fetchevent_t *)event; ns_client_t *client; isc_boolean_t fetch_cancelled, client_shuttingdown; /* * Resume a query after recursion. */ UNUSED(task); REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE); client = devent->ev_arg; REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(task == client->task); REQUIRE(RECURSING(client)); LOCK(&client->query.fetchlock); if (client->query.fetch != NULL) { /* * This is the fetch we've been waiting for. */ INSIST(devent->fetch == client->query.fetch); client->query.fetch = NULL; fetch_cancelled = ISC_FALSE; /* * Update client->now. */ isc_stdtime_get(&client->now); } else { /* * This is a fetch completion event for a cancelled fetch. * Clean up and don't resume the find. */ fetch_cancelled = ISC_TRUE; } UNLOCK(&client->query.fetchlock); INSIST(client->query.fetch == NULL); client->query.attributes &= ~NS_QUERYATTR_RECURSING; dns_resolver_destroyfetch(&devent->fetch); /* * If this client is shutting down, or this transaction * has timed out, do not resume the find. */ client_shuttingdown = ns_client_shuttingdown(client); if (fetch_cancelled || client_shuttingdown) { if (devent->node != NULL) dns_db_detachnode(devent->db, &devent->node); if (devent->db != NULL) dns_db_detach(&devent->db); query_putrdataset(client, &devent->rdataset); if (devent->sigrdataset != NULL) query_putrdataset(client, &devent->sigrdataset); isc_event_free(&event); if (fetch_cancelled) query_error(client, DNS_R_SERVFAIL); else query_next(client, ISC_R_CANCELED); /* * This may destroy the client. */ ns_client_detach(&client); } else { query_find(client, devent, 0); }}static isc_result_tquery_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain, dns_rdataset_t *nameservers){ isc_result_t result; dns_rdataset_t *rdataset, *sigrdataset; inc_stats(client, dns_statscounter_recursion); /* * We are about to recurse, which means that this client will * be unavailable for serving new requests for an indeterminate * amount of time. If this client is currently responsible * for handling incoming queries, set up a new client * object to handle them while we are waiting for a * response. There is no need to replace TCP clients * because those have already been replaced when the * connection was accepted (if allowed by the TCP quota). */ if (client->recursionquota == NULL) { isc_boolean_t killoldest = ISC_FALSE; result = isc_quota_attach(&ns_g_server->recursionquota, &client->recursionquota); if (result == ISC_R_SOFTQUOTA) { ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, ISC_LOG_WARNING, "recursive-clients limit exceeded, " "aborting oldest query"); killoldest = ISC_TRUE; result = ISC_R_SUCCESS; } if (dns_resolver_nrunning(client->view->resolver) > (unsigned int)ns_g_server->recursionquota.max) result = ISC_R_QUOTA; if (result == ISC_R_SUCCESS && !client->mortal && (client->attributes & NS_CLIENTATTR_TCP) == 0) result = ns_client_replace(client); if (result != ISC_R_SUCCESS) { ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, ISC_LOG_WARNING, "no more recursive clients: %s", isc_result_totext(result)); if (client->recursionquota != NULL) isc_quota_detach(&client->recursionquota); return (result); } ns_client_recursing(client, killoldest); } /* * Invoke the resolver. */ REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns); REQUIRE(client->query.fetch == NULL); rdataset = query_newrdataset(client); if (rdataset == NULL) return (ISC_R_NOMEMORY); if (WANTDNSSEC(client)) { sigrdataset = query_newrdataset(client); if (sigrdataset == NULL) { query_putrdataset(client, &rdataset); return (ISC_R_NOMEMORY); } } else sigrdataset = NULL; if (client->query.timerset == ISC_FALSE) ns_client_settimeout(client, 60); result = dns_resolver_createfetch(client->view->resolver, client->query.qname, qtype, qdomain, nameservers, NULL, client->query.fetchoptions, client->task, query_resume, client, rdataset, sigrdataset, &client->query.fetch); if (result == ISC_R_SUCCESS) { /* * Record that we're waiting for an event. A client which * is shutting down will not be destroyed until all the * events have been received. */ } else { query_putrdataset(client, &rdataset); if (sigrdataset != NULL) query_putrdataset(client, &sigrdataset); } return (result);}#define MAX_RESTARTS 16#define QUERY_ERROR(r) \do { \ eresult = r; \ want_restart = ISC_FALSE; \} while (0)/* * Extract a network address from the RDATA of an A or AAAA * record. * * Returns: * ISC_R_SUCCESS * ISC_R_NOTIMPLEMENTED The rdata is not a known address type. */static isc_result_trdata_tonetaddr(dns_rdata_t *rdata, isc_netaddr_t *netaddr) { struct in_addr ina; struct in6_addr in6a; switch (rdata->type) { case dns_rdatatype_a: INSIST(rdata->length == 4); memcpy(&ina.s_addr, rdata->data, 4); isc_netaddr_fromin(netaddr, &ina); return (ISC_R_SUCCESS); case dns_rdatatype_aaaa: INSIST(rdata->length == 16); memcpy(in6a.s6_addr, rdata->data, 16); isc_netaddr_fromin6(netaddr, &in6a); return (ISC_R_SUCCESS); default: return (ISC_R_NOTIMPLEMENTED); }}/* * Find the sort order of 'rdata' in the topology-like * ACL forming the second element in a 2-element top-level * sortlist statement. */static intquery_sortlist_order_2element(dns_rdata_t *rdata, void *arg) { isc_netaddr_t netaddr; if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS) return (INT_MAX); return (ns_sortlist_addrorder2(&netaddr, arg));}/* * Find the sort order of 'rdata' in the matching element * of a 1-element top-level sortlist statement. */static intquery_sortlist_order_1element(dns_rdata_t *rdata, void *arg) { isc_netaddr_t netaddr; if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS) return (INT_MAX); return (ns_sortlist_addrorder1(&netaddr, arg));}/* * Find the sortlist statement that applies to 'client' and set up * the sortlist info in in client->message appropriately. */static voidsetup_query_sortlist(ns_client_t *client) { isc_netaddr_t netaddr; dns_rdatasetorderfunc_t order = NULL; void *order_arg = NULL; isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); switch (ns_sortlist_setup(client->view->sortlist, &netaddr, &order_arg)) { case NS_SORTLISTTYPE_1ELEMENT: order = query_sortlist_order_1element; break; case NS_SORTLISTTYPE_2ELEMENT: order = query_sortlist_order_2element; break; case NS_SORTLISTTYPE_NONE: order = NULL; break; default: INSIST(0); break; } dns_message_setsortorder(client->message, order, order_arg);}static voidquery_addnoqnameproof(ns_client_t *client, dns_rdataset_t *rdataset) { isc_buffer_t *dbuf, b; dns_name_t *fname; dns_rdataset_t *nsec, *nsecsig; isc_result_t result = ISC_R_NOMEMORY; CTRACE("query_addnoqnameproof"); fname = NULL; nsec = NULL; nsecsig = NULL; dbuf = query_getnamebuf(client); if (dbuf == NULL) goto cleanup; fname = query_newname(client, dbuf, &b); nsec = query_newrdataset(client); nsecsig = query_newrdataset(client); if (fname == NULL || nsec == NULL || nsecsig == NULL) goto cleanup; result = dns_rdataset_getnoqname(rdataset, fname, nsec, nsecsig); RUNTIME_CHECK(result == ISC_R_SUCCESS); query_addrrset(client, &fname, &nsec, &nsecsig, dbuf, DNS_SECTION_AUTHORITY); cleanup: if (nsec != NULL) query_putrdataset(client, &nsec); if (nsecsig != NULL) query_putrdataset(client, &nsecsig); if (fname != NULL) query_releasename(client, &fname);}/* * Do the bulk of query processing for the current query of 'client'. * If 'event' is non-NULL, we are returning from recursion and 'qtype' * is ignored. Otherwise, 'qtype' is the query type. */static voidquery_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype){ dns_db_t *db, *zdb; dns_dbnode_t *node; dns_rdatatype_t type; dns_name_t *fname, *zfname, *tname, *prefix; dns_rdataset_t *rdataset, *trdataset; dns_rdataset_t *sigrdataset, *zrdataset, *zsigrdataset; dns_rdataset_t **sigrdatasetp; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdatasetiter_t *rdsiter; isc_boolean_t want_restart, authoritative, is_zone, need_wildcardproof; unsigned int n, nlabels; dns_namereln_t namereln; int order; isc_buffer_t *dbuf; isc_buffer_t b; isc_result_t result, eresult; dns_fixedname_t fixed; dns_fixedname_t wildcardname; dns_dbversion_t *version; dns_zone_t *zone; dns_rdata_cname_t cname; dns_rdata_dname_t dname; unsigned int options; isc_boolean_t empty_wild; dns_rdataset_t *noqname; CTRACE("query_find"); /* * One-time initialization. * * It's especially important to initialize anything that the cleanup * code might cleanup. */ eresult = ISC_R_SUCCESS; fname = NULL; zfname = NULL; rdataset = NULL; zrdataset = NULL; sigrdataset = NULL; zsigrdataset = NULL; node = NULL; db = NULL; zdb = NULL; version = NULL; zone = NULL; need_wildcardproof = ISC_FALSE; empty_wild = ISC_FALSE; options = 0; if (event != NULL) { /* * We're returning from recursion. Restore the query context * and resume. */ want_restart = ISC_FALSE; authoritative = ISC_FALSE; is_zone = ISC_FALSE; qtype = event->qtype; if (qtype == dns_rdatatype_rrsig) type = dns_rdatatype_any; else type = qtype; db = event->db; node = event->node; rdataset = event->rdataset; sigrdataset = event->sigrdataset; /* * We'll need some resources... */ dbuf = query_getnamebuf(client); if (dbuf == NULL) { QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } fname = query_newname(client, dbuf, &b); if (fname == NULL) { QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } tname = dns_fixedname_name(&event->foundname); result = dns_name_copy(tname, fname, NULL); if (result != ISC_R_SUCCESS) { QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } result = event->result; goto resume; } /* * Not returning from recursion. */ /* * If it's a SIG query, we'll iterate the node. */ if (qtype == dns_rdatatype_rrsig) type = dns_rdatatype_any; else type = qtype; restart: CTRACE("query_find: restart"); want_restart = ISC_FALSE; authoritative = ISC_FALSE; version = NULL; need_wildcardproof = ISC_FALSE; if (client->view->checknames && !dns_rdata_checkowner(client->query.qname, client->message->rdclass, qtype, ISC_FALSE)) { char namebuf[DNS_NAME_FORMATSIZE]; char typename[DNS_RDATATYPE_FORMATSIZE]; char classname[DNS_RDATACLASS_FORMATSIZE]; dns_name_format(client->query.qname, namebuf, sizeof(namebuf)); dns_rdatatype_format(qtype, typename, sizeof(typename)); dns_rdataclass_format(client->message->rdclass, classname, sizeof(classname)); ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_QUERY, ISC_LOG_ERROR, "check-names failure %s/%s/%s", namebuf, typename, classname); QUERY_ERROR(DNS_R_REFUSED); goto cleanup; } /* * First we must find the right database. */ options = 0; if (dns_rdatatype_atparent(qtype) && !dns_name_equal(client
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -