📄 query.c
字号:
/* * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. *//* $Id: query.c,v 1.198.2.13.4.30 2004/06/30 14:13:05 marka Exp $ */#include <config.h>#include <string.h>#include <isc/mem.h>#include <isc/util.h>#include <dns/adb.h>#include <dns/byaddr.h>#include <dns/db.h>#include <dns/events.h>#include <dns/message.h>#include <dns/order.h>#include <dns/rdata.h>#include <dns/rdataclass.h>#include <dns/rdatalist.h>#include <dns/rdataset.h>#include <dns/rdatasetiter.h>#include <dns/rdatastruct.h>#include <dns/rdatatype.h>#include <dns/resolver.h>#include <dns/result.h>#include <dns/stats.h>#include <dns/tkey.h>#include <dns/view.h>#include <dns/zone.h>#include <dns/zt.h>#include <named/client.h>#include <named/log.h>#include <named/server.h>#include <named/sortlist.h>#include <named/xfrout.h>#define PARTIALANSWER(c) (((c)->query.attributes & \ NS_QUERYATTR_PARTIALANSWER) != 0)#define USECACHE(c) (((c)->query.attributes & \ NS_QUERYATTR_CACHEOK) != 0)#define RECURSIONOK(c) (((c)->query.attributes & \ NS_QUERYATTR_RECURSIONOK) != 0)#define RECURSING(c) (((c)->query.attributes & \ NS_QUERYATTR_RECURSING) != 0)#define CACHEGLUEOK(c) (((c)->query.attributes & \ NS_QUERYATTR_CACHEGLUEOK) != 0)#define WANTRECURSION(c) (((c)->query.attributes & \ NS_QUERYATTR_WANTRECURSION) != 0)#define WANTDNSSEC(c) (((c)->attributes & \ NS_CLIENTATTR_WANTDNSSEC) != 0)#define NOAUTHORITY(c) (((c)->query.attributes & \ NS_QUERYATTR_NOAUTHORITY) != 0)#define NOADDITIONAL(c) (((c)->query.attributes & \ NS_QUERYATTR_NOADDITIONAL) != 0)#define SECURE(c) (((c)->query.attributes & \ NS_QUERYATTR_SECURE) != 0)#if 0#define CTRACE(m) isc_log_write(ns_g_lctx, \ NS_LOGCATEGORY_CLIENT, \ NS_LOGMODULE_QUERY, \ ISC_LOG_DEBUG(3), \ "client %p: %s", client, (m))#define QTRACE(m) isc_log_write(ns_g_lctx, \ NS_LOGCATEGORY_GENERAL, \ NS_LOGMODULE_QUERY, \ ISC_LOG_DEBUG(3), \ "query %p: %s", query, (m))#else#define CTRACE(m) ((void)m)#define QTRACE(m) ((void)m)#endif#define DNS_GETDB_NOEXACT 0x01U#define DNS_GETDB_NOLOG 0x02U#define DNS_GETDB_PARTIAL 0x04Ustatic voidquery_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype);/* * Increment query statistics counters. */static inline voidinc_stats(ns_client_t *client, dns_statscounter_t counter) { dns_zone_t *zone = client->query.authzone; REQUIRE(counter < DNS_STATS_NCOUNTERS); ns_g_server->querystats[counter]++; if (zone != NULL) { isc_uint64_t *zonestats = dns_zone_getstatscounters(zone); if (zonestats != NULL) zonestats[counter]++; }}static voidquery_send(ns_client_t *client) { dns_statscounter_t counter; if (client->message->rcode == dns_rcode_noerror) { if (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER])) { if (client->query.isreferral) { counter = dns_statscounter_referral; } else { counter = dns_statscounter_nxrrset; } } else { counter = dns_statscounter_success; } } else if (client->message->rcode == dns_rcode_nxdomain) { counter = dns_statscounter_nxdomain; } else { /* We end up here in case of YXDOMAIN, and maybe others */ counter = dns_statscounter_failure; } inc_stats(client, counter); ns_client_send(client);}static voidquery_error(ns_client_t *client, isc_result_t result) { inc_stats(client, dns_statscounter_failure); ns_client_error(client, result);}static voidquery_next(ns_client_t *client, isc_result_t result) { inc_stats(client, dns_statscounter_failure); ns_client_next(client, result);}static inline voidquery_maybeputqname(ns_client_t *client) { if (client->query.restarts > 0) { /* * client->query.qname was dynamically allocated. */ dns_message_puttempname(client->message, &client->query.qname); client->query.qname = NULL; }}static inline voidquery_freefreeversions(ns_client_t *client, isc_boolean_t everything) { ns_dbversion_t *dbversion, *dbversion_next; unsigned int i; for (dbversion = ISC_LIST_HEAD(client->query.freeversions), i = 0; dbversion != NULL; dbversion = dbversion_next, i++) { dbversion_next = ISC_LIST_NEXT(dbversion, link); /* * If we're not freeing everything, we keep the first three * dbversions structures around. */ if (i > 3 || everything) { ISC_LIST_UNLINK(client->query.freeversions, dbversion, link); isc_mem_put(client->mctx, dbversion, sizeof(*dbversion)); } }}voidns_query_cancel(ns_client_t *client) { LOCK(&client->query.fetchlock); if (client->query.fetch != NULL) { dns_resolver_cancelfetch(client->query.fetch); client->query.fetch = NULL; } UNLOCK(&client->query.fetchlock);}static inline voidquery_reset(ns_client_t *client, isc_boolean_t everything) { isc_buffer_t *dbuf, *dbuf_next; ns_dbversion_t *dbversion, *dbversion_next; /* * Reset the query state of a client to its default state. */ /* * Cancel the fetch if it's running. */ ns_query_cancel(client); /* * Cleanup any active versions. */ for (dbversion = ISC_LIST_HEAD(client->query.activeversions); dbversion != NULL; dbversion = dbversion_next) { dbversion_next = ISC_LIST_NEXT(dbversion, link); dns_db_closeversion(dbversion->db, &dbversion->version, ISC_FALSE); dns_db_detach(&dbversion->db); ISC_LIST_INITANDAPPEND(client->query.freeversions, dbversion, link); } ISC_LIST_INIT(client->query.activeversions); if (client->query.authdb != NULL) dns_db_detach(&client->query.authdb); if (client->query.authzone != NULL) dns_zone_detach(&client->query.authzone); query_freefreeversions(client, everything); for (dbuf = ISC_LIST_HEAD(client->query.namebufs); dbuf != NULL; dbuf = dbuf_next) { dbuf_next = ISC_LIST_NEXT(dbuf, link); if (dbuf_next != NULL || everything) { ISC_LIST_UNLINK(client->query.namebufs, dbuf, link); isc_buffer_free(&dbuf); } } query_maybeputqname(client); client->query.attributes = (NS_QUERYATTR_RECURSIONOK | NS_QUERYATTR_CACHEOK | NS_QUERYATTR_SECURE); client->query.restarts = 0; client->query.timerset = ISC_FALSE; client->query.origqname = NULL; client->query.qname = NULL; client->query.dboptions = 0; client->query.fetchoptions = 0; client->query.gluedb = NULL; client->query.authdbset = ISC_FALSE; client->query.isreferral = ISC_FALSE;}static voidquery_next_callback(ns_client_t *client) { query_reset(client, ISC_FALSE);}voidns_query_free(ns_client_t *client) { query_reset(client, ISC_TRUE);}static inline isc_result_tquery_newnamebuf(ns_client_t *client) { isc_buffer_t *dbuf; isc_result_t result; CTRACE("query_newnamebuf"); /* * Allocate a name buffer. */ dbuf = NULL; result = isc_buffer_allocate(client->mctx, &dbuf, 1024); if (result != ISC_R_SUCCESS) { CTRACE("query_newnamebuf: isc_buffer_allocate failed: done"); return (result); } ISC_LIST_APPEND(client->query.namebufs, dbuf, link); CTRACE("query_newnamebuf: done"); return (ISC_R_SUCCESS);}static inline isc_buffer_t *query_getnamebuf(ns_client_t *client) { isc_buffer_t *dbuf; isc_result_t result; isc_region_t r; CTRACE("query_getnamebuf"); /* * Return a name buffer with space for a maximal name, allocating * a new one if necessary. */ if (ISC_LIST_EMPTY(client->query.namebufs)) { result = query_newnamebuf(client); if (result != ISC_R_SUCCESS) { CTRACE("query_getnamebuf: query_newnamebuf failed: done"); return (NULL); } } dbuf = ISC_LIST_TAIL(client->query.namebufs); INSIST(dbuf != NULL); isc_buffer_availableregion(dbuf, &r); if (r.length < 255) { result = query_newnamebuf(client); if (result != ISC_R_SUCCESS) { CTRACE("query_getnamebuf: query_newnamebuf failed: done"); return (NULL); } dbuf = ISC_LIST_TAIL(client->query.namebufs); isc_buffer_availableregion(dbuf, &r); INSIST(r.length >= 255); } CTRACE("query_getnamebuf: done"); return (dbuf);}static inline voidquery_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) { isc_region_t r; CTRACE("query_keepname"); /* * 'name' is using space in 'dbuf', but 'dbuf' has not yet been * adjusted to take account of that. We do the adjustment. */ REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0); dns_name_toregion(name, &r); isc_buffer_add(dbuf, r.length); dns_name_setbuffer(name, NULL); client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;}static inline voidquery_releasename(ns_client_t *client, dns_name_t **namep) { dns_name_t *name = *namep; /* * 'name' is no longer needed. Return it to our pool of temporary * names. If it is using a name buffer, relinquish its exclusive * rights on the buffer. */ CTRACE("query_releasename"); if (dns_name_hasbuffer(name)) { INSIST((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0); client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED; } dns_message_puttempname(client->message, namep); CTRACE("query_releasename: done");}static inline dns_name_t *query_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf){ dns_name_t *name; isc_region_t r; isc_result_t result; REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0); CTRACE("query_newname"); name = NULL; result = dns_message_gettempname(client->message, &name); if (result != ISC_R_SUCCESS) { CTRACE("query_newname: dns_message_gettempname failed: done"); return (NULL); } isc_buffer_availableregion(dbuf, &r); isc_buffer_init(nbuf, r.base, r.length); dns_name_init(name, NULL); dns_name_setbuffer(name, nbuf); client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED; CTRACE("query_newname: done"); return (name);}static inline dns_rdataset_t *query_newrdataset(ns_client_t *client) { dns_rdataset_t *rdataset; isc_result_t result; CTRACE("query_newrdataset"); rdataset = NULL; result = dns_message_gettemprdataset(client->message, &rdataset); if (result != ISC_R_SUCCESS) { CTRACE("query_newrdataset: " "dns_message_gettemprdataset failed: done"); return (NULL); } dns_rdataset_init(rdataset); CTRACE("query_newrdataset: done"); return (rdataset);}static inline voidquery_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) { dns_rdataset_t *rdataset = *rdatasetp; CTRACE("query_putrdataset"); if (rdataset != NULL) { if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); dns_message_puttemprdataset(client->message, rdatasetp); } CTRACE("query_putrdataset: done");}static inline isc_result_tquery_newdbversion(ns_client_t *client, unsigned int n) { unsigned int i; ns_dbversion_t *dbversion; for (i = 0; i < n; i++) { dbversion = isc_mem_get(client->mctx, sizeof(*dbversion)); if (dbversion != NULL) { dbversion->db = NULL; dbversion->version = NULL; ISC_LIST_INITANDAPPEND(client->query.freeversions, dbversion, link); } else { /* * We only return ISC_R_NOMEMORY if we couldn't * allocate anything. */ if (i == 0) return (ISC_R_NOMEMORY); else return (ISC_R_SUCCESS); } } return (ISC_R_SUCCESS);}static inline ns_dbversion_t *query_getdbversion(ns_client_t *client) { isc_result_t result; ns_dbversion_t *dbversion; if (ISC_LIST_EMPTY(client->query.freeversions)) { result = query_newdbversion(client, 1); if (result != ISC_R_SUCCESS) return (NULL); } dbversion = ISC_LIST_HEAD(client->query.freeversions); INSIST(dbversion != NULL); ISC_LIST_UNLINK(client->query.freeversions, dbversion, link); return (dbversion);}isc_result_tns_query_init(ns_client_t *client) { isc_result_t result; ISC_LIST_INIT(client->query.namebufs); ISC_LIST_INIT(client->query.activeversions); ISC_LIST_INIT(client->query.freeversions); client->query.restarts = 0; client->query.timerset = ISC_FALSE; client->query.qname = NULL; result = isc_mutex_init(&client->query.fetchlock); if (result != ISC_R_SUCCESS) return (result); client->query.fetch = NULL; client->query.authdb = NULL; client->query.authzone = NULL; client->query.authdbset = ISC_FALSE; client->query.isreferral = ISC_FALSE; query_reset(client, ISC_FALSE); result = query_newdbversion(client, 3); if (result != ISC_R_SUCCESS) { DESTROYLOCK(&client->query.fetchlock); return (result); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -