📄 query.c
字号:
cleanup: if (rdataset != NULL) query_putrdataset(client, &rdataset); if (sigrdataset != NULL) query_putrdataset(client, &sigrdataset); if (fname != NULL) query_releasename(client, &fname); if (node != NULL) dns_db_detachnode(db, &node); if (db != NULL) dns_db_detach(&db); if (zone != NULL) dns_zone_detach(&zone); if (zdb != NULL) { query_putrdataset(client, &zrdataset); if (zsigrdataset != NULL) query_putrdataset(client, &zsigrdataset); if (zfname != NULL) query_releasename(client, &zfname); dns_db_detach(&zdb); }}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)); if (devent->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; } 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); 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) { result = isc_quota_attach(&ns_g_server->recursionquota, &client->recursionquota); 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)); return (result); } } /* * 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);}static inline isc_result_tquery_findparentkey(ns_client_t *client, dns_name_t *name, dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp, dns_dbnode_t **nodep, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset){ dns_db_t *pdb; dns_dbnode_t *pnode; dns_dbversion_t *pversion; dns_rdataset_t prdataset, psigrdataset; dns_rdataset_t *psigrdatasetp; isc_result_t result; dns_zone_t *pzone; isc_boolean_t is_zone; dns_fixedname_t pfoundname; /* * 'name' is at a zone cut. Try to find a KEY for 'name' in * the deepest ancestor zone of 'name' (if any). If it exists, * update *zonep, *dbp, *nodep, rdataset, and sigrdataset and * return ISC_R_SUCCESS. If not, leave them alone and return a * non-success status. */ pzone = NULL; pdb = NULL; pnode = NULL; pversion = NULL; dns_rdataset_init(&prdataset); if (sigrdataset != NULL) dns_rdataset_init(&psigrdataset); is_zone = ISC_FALSE; dns_fixedname_init(&pfoundname); result = query_getdb(client, name, DNS_GETDB_NOEXACT, &pzone, &pdb, &pversion, &is_zone); if (result != ISC_R_SUCCESS) goto cleanup; if (!is_zone) { result = ISC_R_FAILURE; goto cleanup; } if (sigrdataset != NULL) psigrdatasetp = &psigrdataset; else psigrdatasetp = NULL; result = dns_db_find(pdb, name, pversion, dns_rdatatype_key, client->query.dboptions, client->now, &pnode, dns_fixedname_name(&pfoundname), &prdataset, psigrdatasetp); if (result == ISC_R_SUCCESS) { if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); dns_rdataset_clone(&prdataset, rdataset); if (sigrdataset != NULL) { if (dns_rdataset_isassociated(sigrdataset)) dns_rdataset_disassociate(sigrdataset); if (dns_rdataset_isassociated(&psigrdataset)) dns_rdataset_clone(&psigrdataset, sigrdataset); } if (*nodep != NULL) dns_db_detachnode(*dbp, nodep); *nodep = pnode; pnode = NULL; *versionp = pversion; if (*dbp != NULL) dns_db_detach(dbp); *dbp = pdb; pdb = NULL; if (*zonep != NULL) dns_zone_detach(zonep); *zonep = pzone; pzone = NULL; } cleanup: if (dns_rdataset_isassociated(&prdataset)) dns_rdataset_disassociate(&prdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(&psigrdataset)) dns_rdataset_disassociate(&psigrdataset); if (pnode != NULL) dns_db_detachnode(pdb, &pnode); if (pdb != NULL) dns_db_detach(&pdb); if (pzone != NULL) dns_zone_detach(&pzone); 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);}/* * 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; unsigned int n, nlabels, nbits; dns_namereln_t namereln; int order; isc_buffer_t *dbuf; isc_buffer_t b; isc_result_t result, eresult; dns_fixedname_t fixed; dns_dbversion_t *version; dns_zone_t *zone; dns_rdata_cname_t cname; dns_rdata_dname_t dname; isc_boolean_t empty_wild; 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; empty_wild = ISC_FALSE; 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_sig) 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_sig) type = dns_rdatatype_any; else type = qtype; restart: CTRACE("query_find: restart"); want_restart = ISC_FALSE; authoritative = ISC_FALSE; version = NULL; /* * First we must find the right database. */ result = query_getdb(client, client->query.qname, 0, &zone, &db, &version, &is_zone); if (result != ISC_R_SUCCESS) { if (result == DNS_R_REFUSED) QUERY_ERROR(DNS_R_REFUSED); else QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } if (is_zone) authoritative = ISC_TRUE; if (event == NULL && client->query.restarts == 0) { if (is_zone) { dns_zone_attach(zone, &client->query.authzone); dns_db_attach(db, &client->query.authdb); } client->query.authdbset = ISC_TRUE; } db_find: CTRACE("query_find: db_find"); /* * We'll need some resources... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -