📄 query.c
字号:
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; 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) return (result); dns_a6_init(&client->query.a6ctx, query_simplefind, query_adda6rrset, NULL, NULL, client); return (query_newnamebuf(client));}static inline ns_dbversion_t *query_findversion(ns_client_t *client, dns_db_t *db, isc_boolean_t *newzonep){ ns_dbversion_t *dbversion; /* * We may already have done a query related to this * database. If so, we must be sure to make subsequent * queries from the same version. */ for (dbversion = ISC_LIST_HEAD(client->query.activeversions); dbversion != NULL; dbversion = ISC_LIST_NEXT(dbversion, link)) { if (dbversion->db == db) break; } if (dbversion == NULL) { /* * This is a new zone for this query. Add it to * the active list. */ dbversion = query_getdbversion(client); if (dbversion == NULL) return (NULL); dns_db_attach(db, &dbversion->db); dns_db_currentversion(db, &dbversion->version); dbversion->queryok = ISC_FALSE; ISC_LIST_APPEND(client->query.activeversions, dbversion, link); *newzonep = ISC_TRUE; } else *newzonep = ISC_FALSE; return (dbversion);}static inline isc_result_tquery_getzonedb(ns_client_t *client, dns_name_t *name, unsigned int options, dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp){ isc_result_t result; isc_boolean_t check_acl, new_zone; dns_acl_t *queryacl; ns_dbversion_t *dbversion; unsigned int ztoptions; dns_zone_t *zone = NULL; dns_db_t *db = NULL; REQUIRE(zonep != NULL && *zonep == NULL); REQUIRE(dbp != NULL && *dbp == NULL); /* * Find a zone database to answer the query. */ ztoptions = ((options & DNS_GETDB_NOEXACT) != 0) ? DNS_ZTFIND_NOEXACT : 0; result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL, &zone); if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) result = dns_zone_getdb(zone, &db); if (result != ISC_R_SUCCESS) goto fail; /* * This limits our searching to the zone where the first name * (the query target) was looked for. This prevents following * CNAMES or DNAMES into other zones and prevents returning * additional data from other zones. */ if (!client->view->additionalfromauth && client->query.authdbset && db != client->query.authdb) goto refuse; /* * If the zone has an ACL, we'll check it, otherwise * we use the view's "allow-query" ACL. Each ACL is only checked * once per query. * * Also, get the database version to use. */ check_acl = ISC_TRUE; /* Keep compiler happy. */ queryacl = NULL; /* * Get the current version of this database. */ dbversion = query_findversion(client, db, &new_zone); if (dbversion == NULL) { result = DNS_R_SERVFAIL; goto fail; } if (new_zone) { check_acl = ISC_TRUE; } else if (!dbversion->queryok) { goto refuse; } else { check_acl = ISC_FALSE; } queryacl = dns_zone_getqueryacl(zone); if (queryacl == NULL) { queryacl = client->view->queryacl; if ((client->query.attributes & NS_QUERYATTR_QUERYOKVALID) != 0) { /* * We've evaluated the view's queryacl already. If * NS_QUERYATTR_QUERYOK is set, then the client is * allowed to make queries, otherwise the query should * be refused. */ check_acl = ISC_FALSE; if ((client->query.attributes & NS_QUERYATTR_QUERYOK) == 0) goto refuse; } else { /* * We haven't evaluated the view's queryacl yet. */ check_acl = ISC_TRUE; } } if (check_acl) { isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0); result = ns_client_checkaclsilent(client, queryacl, ISC_TRUE); if (log) { char msg[DNS_NAME_FORMATSIZE + DNS_RDATACLASS_FORMATSIZE + sizeof "query '/'"]; if (result == ISC_R_SUCCESS) { if (isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(3))) { ns_client_aclmsg("query", name, client->view->rdclass, msg, sizeof(msg)); ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(3), "%s approved", msg); } } else { ns_client_aclmsg("query", name, client->view->rdclass, msg, sizeof(msg)); ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_QUERY, ISC_LOG_INFO, "%s denied", msg); } } if (queryacl == client->view->queryacl) { if (result == ISC_R_SUCCESS) { /* * We were allowed by the default * "allow-query" ACL. Remember this so we * don't have to check again. */ client->query.attributes |= NS_QUERYATTR_QUERYOK; } /* * We've now evaluated the view's query ACL, and * the NS_QUERYATTR_QUERYOK attribute is now valid. */ client->query.attributes |= NS_QUERYATTR_QUERYOKVALID; } if (result != ISC_R_SUCCESS) goto refuse; } /* Approved. */ /* * Remember the result of the ACL check so we * don't have to check again. */ dbversion->queryok = ISC_TRUE; /* Transfer ownership. */ *zonep = zone; *dbp = db; *versionp = dbversion->version; return (ISC_R_SUCCESS); refuse: result = DNS_R_REFUSED; fail: if (zone != NULL) dns_zone_detach(&zone); if (db != NULL) dns_db_detach(&db); return (result);}static inline isc_result_tquery_getcachedb(ns_client_t *client, dns_db_t **dbp, unsigned int options){ isc_result_t result; isc_boolean_t check_acl; dns_db_t *db = NULL; REQUIRE(dbp != NULL && *dbp == NULL); /* * Find a cache database to answer the query. * This may fail with DNS_R_REFUSED if the client * is not allowed to use the cache. */ if (!USECACHE(client)) return (DNS_R_REFUSED); dns_db_attach(client->view->cachedb, &db); if ((client->query.attributes & NS_QUERYATTR_QUERYOKVALID) != 0) { /* * We've evaluated the view's queryacl already. If * NS_QUERYATTR_QUERYOK is set, then the client is * allowed to make queries, otherwise the query should * be refused. */ check_acl = ISC_FALSE; if ((client->query.attributes & NS_QUERYATTR_QUERYOK) == 0) goto refuse; } else { /* * We haven't evaluated the view's queryacl yet. */ check_acl = ISC_TRUE; } if (check_acl) { isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0); result = ns_client_checkacl(client, "query (cache)", client->view->queryacl, ISC_TRUE, log ? ISC_LOG_INFO : ISC_LOG_DEBUG(3)); if (result == ISC_R_SUCCESS) { /* * We were allowed by the default * "allow-query" ACL. Remember this so we * don't have to check again. */ client->query.attributes |= NS_QUERYATTR_QUERYOK; } /* * We've now evaluated the view's query ACL, and * the NS_QUERYATTR_QUERYOK attribute is now valid. */ client->query.attributes |= NS_QUERYATTR_QUERYOKVALID; if (result != ISC_R_SUCCESS) goto refuse; } /* Approved. */ /* Transfer ownership. */ *dbp = db; return (ISC_R_SUCCESS); refuse: result = DNS_R_REFUSED; if (db != NULL) dns_db_detach(&db); return (result);}static inline isc_result_tquery_getdb(ns_client_t *client, dns_name_t *name, unsigned int options, dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp, isc_boolean_t *is_zonep){ isc_result_t result; result = query_getzonedb(client, name, options, zonep, dbp, versionp); if (result == ISC_R_SUCCESS) { *is_zonep = ISC_TRUE; } else if (result == ISC_R_NOTFOUND) { result = query_getcachedb(client, dbp, options); *is_zonep = ISC_FALSE; } return (result);}static isc_result_tquery_simplefind(void *arg, dns_name_t *name, dns_rdatatype_t type, isc_stdtime_t now, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset){ ns_client_t *client = arg; isc_result_t result; dns_fixedname_t foundname; dns_db_t *db; dns_dbversion_t *version; unsigned int dboptions; isc_boolean_t is_zone; dns_rdataset_t zrdataset, zsigrdataset; dns_zone_t *zone; REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(rdataset != NULL); dns_rdataset_init(&zrdataset); if (sigrdataset != NULL) dns_rdataset_init(&zsigrdataset); /* * Find a database to answer the query. */ zone = NULL; db = NULL; version = NULL; result = query_getdb(client, name, 0, &zone, &db, &version, &is_zone); if (result != ISC_R_SUCCESS) goto cleanup; db_find: /* * Now look for an answer in the database. */ dns_fixedname_init(&foundname); dboptions = client->query.dboptions; if (db == client->query.gluedb || (!is_zone && CACHEGLUEOK(client))) dboptions |= DNS_DBFIND_GLUEOK; result = dns_db_find(db, name, version, type, dboptions, now, NULL, dns_fixedname_name(&foundname), rdataset, sigrdataset); if (result == DNS_R_DELEGATION || result == ISC_R_NOTFOUND) { if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) dns_rdataset_disassociate(sigrdataset); if (is_zone) { if (USECACHE(client)) { /* * Either the answer is in the cache, or we * don't know it. */ is_zone = ISC_FALSE; version = NULL; dns_db_detach(&db); dns_db_attach(client->view->cachedb, &db); goto db_find; } } else { /* * We don't have the data in the cache. If we've got * glue from the zone, use it. */ if (dns_rdataset_isassociated(&zrdataset)) { dns_rdataset_clone(&zrdataset, rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(&zsigrdataset)) dns_rdataset_clone(&zsigrdataset, sigrdataset); result = ISC_R_SUCCESS; goto cleanup; } } /* * We don't know the answer. */ result = ISC_R_NOTFOUND; } else if (result == DNS_R_GLUE) { if (USECACHE(client) && RECURSIONOK(client)) { /* * We found an answer, but the cache may be better. * Remember what we've got and go look in the cache. */ is_zone = ISC_FALSE; version = NULL; dns_rdataset_clone(rdataset, &zrdataset); dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { dns_rdataset_clone(sigrdataset, &zsigrdataset); dns_rdataset_disassociate(sigrdataset); } dns_db_detach(&db); dns_db_attach(client->view->cachedb, &db); goto db_find; } /* * Otherwise, the glue is the best answer. */ result = ISC_R_SUCCESS; } else if (result != ISC_R_SUCCESS) { if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) dns_rdataset_disassociate(sigrdataset); result = ISC_R_NOTFOUND; } /* * If we get here, the result is ISC_R_SUCCESS, and we found the * answer we were looking for in the zone. */ cleanup: if (dns_rdataset_isassociated(&zrdataset)) { dns_rdataset_disassociate(&zrdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(&zsigrdataset)) dns_rdataset_disassociate(&zsigrdataset); } if (db != NULL) dns_db_detach(&db); if (zone != NULL) dns_zone_detach(&zone); return (result);}static inline isc_boolean_tquery_isduplicate(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type, dns_name_t **mnamep){ dns_section_t section; dns_name_t *mname = NULL; isc_result_t result; CTRACE("query_isduplicate"); for (section = DNS_SECTION_ANSWER; section <= DNS_SECTION_ADDITIONAL; section++) { result = dns_message_findname(client->message, section, name, type, 0, &mname, NULL); if (result == ISC_R_SUCCESS) { /* * We've already got this RRset in the response. */ CTRACE("query_isduplicate: true: done"); return (ISC_TRUE); } else if (result == DNS_R_NXRRSET) { /* * The name exists, but the rdataset does not. */ if (section == DNS_SECTION_ADDITIONAL) break; } else RUNTIME_CHECK(result == DNS_R_NXDOMAIN); mname = NULL; } /* * If the dns_name_t we're looking up is already in the message, * we don't want to trigger the caller's name replacement logic. */ if (name == mname) mname = NULL; *mnamep = mname;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -