From: Evan Hunt Date: Thu, 22 Nov 2018 09:15:13 +0000 (+0000) Subject: add additional hook points, plus some minor refactoring X-Git-Tag: v9.13.5~7^2~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9df0bdc99c154a917bbfb20c1fed47c1818e769d;p=thirdparty%2Fbind9.git add additional hook points, plus some minor refactoring - added some hook points that will be needed for a dns64 module later - moved some code from the beginning of query_respond() to the end of query_prepresponse(); this has no effect on functionality but means we can have a hook point at the top of query_respond(), which seems nicer - compressed duplicated code into query_zerottl_refetch() function - added a qctx->answered flag so that a module can prevent query_addrrset() from being called from query_respond() when it's already been called from the module. --- diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index e61d15db725..fe710c30c3b 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -176,16 +176,22 @@ typedef enum { NS_QUERY_START_BEGIN, NS_QUERY_LOOKUP_BEGIN, NS_QUERY_RESUME_BEGIN, + NS_QUERY_RESUME_RESTORED, NS_QUERY_GOT_ANSWER_BEGIN, NS_QUERY_RESPOND_ANY_BEGIN, NS_QUERY_RESPOND_ANY_FOUND, + NS_QUERY_ADDANSWER_BEGIN, NS_QUERY_RESPOND_BEGIN, NS_QUERY_NOTFOUND_BEGIN, + NS_QUERY_NOTFOUND_RECURSE, NS_QUERY_PREP_DELEGATION_BEGIN, NS_QUERY_ZONE_DELEGATION_BEGIN, NS_QUERY_DELEGATION_BEGIN, + NS_QUERY_DELEGATION_RECURSE_BEGIN, NS_QUERY_NODATA_BEGIN, NS_QUERY_NXDOMAIN_BEGIN, + NS_QUERY_NCACHE_BEGIN, + NS_QUERY_ZEROTTL_RECURSE, NS_QUERY_CNAME_BEGIN, NS_QUERY_DNAME_BEGIN, NS_QUERY_PREP_RESPONSE_BEGIN, diff --git a/lib/ns/query.c b/lib/ns/query.c index 6df013d2953..32c0847b789 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -343,9 +343,9 @@ get_hooktab(query_ctx_t *qctx) { * 8. The answer was not found in the database (query_notfound(). * Set up a referral and go to 9. * - * 9. Handle a delegation response (query_delegation()). If we are - * allowed to recurse, go to 5, otherwise go to 15 to clean up and - * return the delegation to the client. + * 9. Handle a delegation response (query_delegation()). If we need + * to and are allowed to recurse (query_delegation_recurse()), go to 5, + * otherwise go to 15 to clean up and return the delegation to the client. * * 10. No such domain (query_nxdomain()). Attempt redirection; if * unsuccessful, add authority section records (query_addsoa(), @@ -433,6 +433,9 @@ query_zone_delegation(query_ctx_t *qctx); static isc_result_t query_delegation(query_ctx_t *qctx); +static isc_result_t +query_delegation_recurse(query_ctx_t *qctx); + static void query_addds(query_ctx_t *qctx); @@ -457,6 +460,9 @@ query_ncache(query_ctx_t *qctx, isc_result_t result); static isc_result_t query_coveringnsec(query_ctx_t *qctx); +static isc_result_t +query_zerottl_refetch(query_ctx_t *qctx); + static isc_result_t query_cname(query_ctx_t *qctx); @@ -5840,6 +5846,8 @@ query_resume(query_ctx_t *qctx) { qctx->type = qctx->qtype; } + CALL_HOOK(NS_QUERY_RESUME_RESTORED, qctx); + if (DNS64(qctx->client)) { qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64; qctx->dns64 = true; @@ -7008,42 +7016,73 @@ query_getexpire(query_ctx_t *qctx) { } /*% - * Build a repsonse for a "normal" query, for a type other than ANY, - * for which we have an answer (either positive or negative). + * Fill the ANSWER section of a positive response. */ static isc_result_t -query_respond(query_ctx_t *qctx) { +query_addanswer(query_ctx_t *qctx) { dns_rdataset_t **sigrdatasetp = NULL; isc_result_t result; - /* - * If we have a zero ttl from the cache, refetch. - */ - if (!qctx->is_zone && !qctx->resuming && !STALE(qctx->rdataset) && - qctx->rdataset->ttl == 0 && RECURSIONOK(qctx->client)) - { - qctx_clean(qctx); + CALL_HOOK(NS_QUERY_ADDANSWER_BEGIN, qctx); - INSIST(!REDIRECT(qctx->client)); - result = ns_query_recurse(qctx->client, qctx->qtype, - qctx->client->query.qname, - NULL, NULL, qctx->resuming); - if (result == ISC_R_SUCCESS) { - qctx->client->query.attributes |= - NS_QUERYATTR_RECURSING; - if (qctx->dns64) - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64; - if (qctx->dns64_exclude) - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64EXCLUDE; - } else { - QUERY_ERROR(qctx, result); + if (qctx->dns64) { + result = query_dns64(qctx); + qctx->noqname = NULL; + dns_rdataset_disassociate(qctx->rdataset); + dns_message_puttemprdataset(qctx->client->message, + &qctx->rdataset); + if (result == ISC_R_NOMORE) { +#ifndef dns64_bis_return_excluded_addresses + if (qctx->dns64_exclude) { + if (!qctx->is_zone) + return (ns_query_done(qctx)); + /* + * Add a fake SOA record. + */ + (void)query_addsoa(qctx, 600, + DNS_SECTION_AUTHORITY); + return (ns_query_done(qctx)); + } +#endif + if (qctx->is_zone) { + return (query_nodata(qctx, DNS_R_NXDOMAIN)); + } else { + return (query_ncache(qctx, DNS_R_NXDOMAIN)); + } + } else if (result != ISC_R_SUCCESS) { + qctx->result = result; + return (ns_query_done(qctx)); } - - return (ns_query_done(qctx)); + } else if (qctx->client->query.dns64_aaaaok != NULL) { + query_filter64(qctx); + ns_client_putrdataset(qctx->client, &qctx->rdataset); + } else { + if (!qctx->is_zone && RECURSIONOK(qctx->client)) { + query_prefetch(qctx->client, qctx->fname, + qctx->rdataset); + } + if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) { + sigrdatasetp = &qctx->sigrdataset; + } + query_addrrset(qctx, &qctx->fname, + &qctx->rdataset, sigrdatasetp, + qctx->dbuf, DNS_SECTION_ANSWER); } + return (ISC_R_COMPLETE); + + cleanup: + return (result); +} + +/*% + * Build a repsonse for a "normal" query, for a type other than ANY, + * for which we have an answer (either positive or negative). + */ +static isc_result_t +query_respond(query_ctx_t *qctx) { + isc_result_t result; + /* * Check to see if the AAAA RRset has non-excluded addresses * in it. If not look for a A RRset. @@ -7079,10 +7118,6 @@ query_respond(query_ctx_t *qctx) { */ CALL_HOOK(NS_QUERY_RESPOND_BEGIN, qctx); - if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) { - sigrdatasetp = &qctx->sigrdataset; - } - if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) { qctx->noqname = qctx->rdataset; } else { @@ -7117,44 +7152,9 @@ query_respond(query_ctx_t *qctx) { */ query_getexpire(qctx); - if (qctx->dns64) { - result = query_dns64(qctx); - qctx->noqname = NULL; - dns_rdataset_disassociate(qctx->rdataset); - dns_message_puttemprdataset(qctx->client->message, - &qctx->rdataset); - if (result == ISC_R_NOMORE) { -#ifndef dns64_bis_return_excluded_addresses - if (qctx->dns64_exclude) { - if (!qctx->is_zone) - return (ns_query_done(qctx)); - /* - * Add a fake SOA record. - */ - (void)query_addsoa(qctx, 600, - DNS_SECTION_AUTHORITY); - return (ns_query_done(qctx)); - } -#endif - if (qctx->is_zone) { - return (query_nodata(qctx, DNS_R_NXDOMAIN)); - } else { - return (query_ncache(qctx, DNS_R_NXDOMAIN)); - } - } else if (result != ISC_R_SUCCESS) { - qctx->result = result; - return (ns_query_done(qctx)); - } - } else if (qctx->client->query.dns64_aaaaok != NULL) { - query_filter64(qctx); - ns_client_putrdataset(qctx->client, &qctx->rdataset); - } else { - if (!qctx->is_zone && RECURSIONOK(qctx->client)) - query_prefetch(qctx->client, qctx->fname, - qctx->rdataset); - query_addrrset(qctx, &qctx->fname, - &qctx->rdataset, sigrdatasetp, - qctx->dbuf, DNS_SECTION_ANSWER); + result = query_addanswer(qctx); + if (result != ISC_R_COMPLETE) { + return (result); } query_addnoqnameproof(qctx); @@ -7441,7 +7441,8 @@ query_filter64(query_ctx_t *qctx) { i = 0; for (result = dns_rdataset_first(qctx->rdataset); result == ISC_R_SUCCESS; - result = dns_rdataset_next(qctx->rdataset)) { + result = dns_rdataset_next(qctx->rdataset)) + { if (!client->query.dns64_aaaaok[i++]) continue; dns_rdataset_current(qctx->rdataset, &rdata); @@ -7565,14 +7566,18 @@ query_notfound(query_ctx_t *qctx) { qctx->client->query.qname, NULL, NULL, qctx->resuming); if (result == ISC_R_SUCCESS) { + CALL_HOOK(NS_QUERY_NOTFOUND_RECURSE, qctx); qctx->client->query.attributes |= NS_QUERYATTR_RECURSING; - if (qctx->dns64) + + if (qctx->dns64) { qctx->client->query.attributes |= NS_QUERYATTR_DNS64; - if (qctx->dns64_exclude) + } + if (qctx->dns64_exclude) { qctx->client->query.attributes |= NS_QUERYATTR_DNS64EXCLUDE; + } } else { QUERY_ERROR(qctx, result); } @@ -7808,63 +7813,77 @@ query_delegation(query_ctx_t *qctx) { RESTORE(qctx->sigrdataset, qctx->zsigrdataset); } - if (RECURSIONOK(qctx->client)) { + result = query_delegation_recurse(qctx); + if (result != ISC_R_COMPLETE) { + return (result); + } + + return (query_prepare_delegation_response(qctx)); + + cleanup: + return (result); +} + +/*% + * Handle recursive queries that are triggered as part of the + * delegation process. + */ +static isc_result_t +query_delegation_recurse(query_ctx_t *qctx) { + isc_result_t result; + dns_name_t *qname = qctx->client->query.qname; + + if (!RECURSIONOK(qctx->client)) { + return (ISC_R_COMPLETE); + } + + CALL_HOOK(NS_QUERY_DELEGATION_RECURSE_BEGIN, qctx); + + /* + * We have a delegation and recursion is allowed, + * so we call ns_query_recurse() to follow it. + * This phase of the query processing is done; + * we'll resume via fetch_callback() and + * query_resume() when the recursion is complete. + */ + + INSIST(!REDIRECT(qctx->client)); + + if (dns_rdatatype_atparent(qctx->type)) { /* - * We have a delegation and recursion is allowed, - * so we call ns_query_recurse() to follow it. - * This phase of the query processing is done; - * we'll resume via fetch_callback() and - * query_resume() when the recursion is complete. + * Parent is authoritative for this RDATA type (i.e. DS). */ - dns_name_t *qname = qctx->client->query.qname; - - INSIST(!REDIRECT(qctx->client)); + result = ns_query_recurse(qctx->client, qctx->qtype, qname, + NULL, NULL, qctx->resuming); + } else if (qctx->dns64) { + /* + * Look up an A record so we can synthesize DNS64. + */ + result = ns_query_recurse(qctx->client, dns_rdatatype_a, qname, + NULL, NULL, qctx->resuming); + } else { + /* + * Any other recursion. + */ + result = ns_query_recurse(qctx->client, qctx->qtype, qname, + qctx->fname, qctx->rdataset, + qctx->resuming); + } - if (dns_rdatatype_atparent(qctx->type)) { - /* - * Parent is recursive for this rdata - * type (i.e., DS). - */ - result = ns_query_recurse(qctx->client, - qctx->qtype, qname, - NULL, NULL, - qctx->resuming); - } else if (qctx->dns64) { - /* - * Look up an A record so we can - * synthesize DNS64. - */ - result = ns_query_recurse(qctx->client, - dns_rdatatype_a, qname, - NULL, NULL, - qctx->resuming); - } else { - /* - * Any other recursion. - */ - result = ns_query_recurse(qctx->client, - qctx->qtype, qname, - qctx->fname, - qctx->rdataset, - qctx->resuming); + if (result == ISC_R_SUCCESS) { + qctx->client->query.attributes |= NS_QUERYATTR_RECURSING; + if (qctx->dns64) { + qctx->client->query.attributes |= NS_QUERYATTR_DNS64; } - if (result == ISC_R_SUCCESS) { + if (qctx->dns64_exclude) { qctx->client->query.attributes |= - NS_QUERYATTR_RECURSING; - if (qctx->dns64) - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64; - if (qctx->dns64_exclude) - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64EXCLUDE; - } else { - QUERY_ERROR(qctx, result); + NS_QUERYATTR_DNS64EXCLUDE; } - - return (ns_query_done(qctx)); + } else { + QUERY_ERROR(qctx, result); } - return (query_prepare_delegation_response(qctx)); + return (ns_query_done(qctx)); cleanup: return (result); @@ -9029,9 +9048,9 @@ query_coveringnsec(query_ctx_t *qctx) { /* * Zero TTL handling of wildcard record. * - * We don't yet have code to handle synthesis and type ANY, - * AAAA filtering or dns64 processing so we abort the - * synthesis here if there would be a interaction. + * We don't yet have code to handle synthesis and type ANY or dns64 + * processing so we abort the synthesis here if there would be a + * interaction. */ switch (result) { case ISC_R_SUCCESS: @@ -9189,6 +9208,8 @@ query_ncache(query_ctx_t *qctx, isc_result_t result) { result == DNS_R_NCACHENXRRSET || result == DNS_R_NXDOMAIN); + CALL_HOOK(NS_QUERY_NCACHE_BEGIN, qctx); + qctx->authoritative = false; if (result == DNS_R_NCACHENXDOMAIN) { @@ -9210,6 +9231,52 @@ query_ncache(query_ctx_t *qctx, isc_result_t result) { } return (query_nodata(qctx, result)); + + cleanup: + return (result); +} + +/* + * If we have a zero ttl from the cache, refetch. + */ +static isc_result_t +query_zerottl_refetch(query_ctx_t *qctx) { + isc_result_t result; + + if (qctx->is_zone || qctx->resuming || STALE(qctx->rdataset) || + qctx->rdataset->ttl != 0 || !RECURSIONOK(qctx->client)) + { + return (ISC_R_COMPLETE); + } + + qctx_clean(qctx); + + INSIST(!REDIRECT(qctx->client)); + + result = ns_query_recurse(qctx->client, qctx->qtype, + qctx->client->query.qname, + NULL, NULL, qctx->resuming); + if (result == ISC_R_SUCCESS) { + CALL_HOOK(NS_QUERY_ZEROTTL_RECURSE, qctx); + qctx->client->query.attributes |= + NS_QUERYATTR_RECURSING; + + if (qctx->dns64) { + qctx->client->query.attributes |= + NS_QUERYATTR_DNS64; + } + if (qctx->dns64_exclude) { + qctx->client->query.attributes |= + NS_QUERYATTR_DNS64EXCLUDE; + } + } else { + QUERY_ERROR(qctx, result); + } + + return (ns_query_done(qctx)); + + cleanup: + return (result); } /* @@ -9226,33 +9293,9 @@ query_cname(query_ctx_t *qctx) { CALL_HOOK(NS_QUERY_CNAME_BEGIN, qctx); - /* - * If we have a zero ttl from the cache refetch it. - */ - if (!qctx->is_zone && !qctx->resuming && !STALE(qctx->rdataset) && - qctx->rdataset->ttl == 0 && RECURSIONOK(qctx->client)) - { - qctx_clean(qctx); - - INSIST(!REDIRECT(qctx->client)); - - result = ns_query_recurse(qctx->client, qctx->qtype, - qctx->client->query.qname, - NULL, NULL, qctx->resuming); - if (result == ISC_R_SUCCESS) { - qctx->client->query.attributes |= - NS_QUERYATTR_RECURSING; - if (qctx->dns64) - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64; - if (qctx->dns64_exclude) - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64EXCLUDE; - } else { - QUERY_ERROR(qctx, result); - } - - return (ns_query_done(qctx)); + result = query_zerottl_refetch(qctx); + if (result != ISC_R_COMPLETE) { + return (result); } /* @@ -9587,6 +9630,11 @@ query_prepresponse(query_ctx_t *qctx) { return (query_respond_any(qctx)); } + result = query_zerottl_refetch(qctx); + if (result != ISC_R_COMPLETE) { + return (result); + } + return (query_respond(qctx)); cleanup: