mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 18:19:42 +00:00
refactor filter-aaaa implementation
- the goal of this change is for AAAA filtering to be fully contained in the query logic, and implemented at discrete points that can be replaced with hook callouts later on. - the new code may be slightly less efficient than the old filter-aaaa implementation, but maximum efficiency was never a priority for AAAA filtering anyway. - we now use the rdataset RENDERED attribute to indicate that an AAAA rdataset should not be included when rendering the message. (this flag was originally meant to indicate that an rdataset has already been rendered and should not be repeated, but it can also be used to prevent rendering in the first place.) - the DNS_MESSAGERENDER_FILTER_AAAA, NS_CLIENTATTR_FILTER_AAAA, and DNS_RDATASETGLUE_FILTERAAAA flags are all now unnecessary and have been removed.
This commit is contained in:
parent
29897b14dc
commit
d43dcef139
@ -117,7 +117,6 @@ echo_i "checking that A and not AAAA is returned when both AAAA and A records ex
|
||||
ret=0
|
||||
$DIG $DIGOPTS any dual.signed -b 10.53.0.1 @10.53.0.1 > dig.out.ns1.test$n || ret=1
|
||||
grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
|
||||
grep "AUTHORITY: 0," dig.out.ns1.test$n > /dev/null || ret=1
|
||||
grep "1.0.0.3" dig.out.ns1.test$n > /dev/null || ret=1
|
||||
grep "::3" dig.out.ns1.test$n > /dev/null && ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
@ -128,7 +127,6 @@ echo_i "checking that A and not AAAA is returned when both AAAA and A records ex
|
||||
ret=0
|
||||
$DIG $DIGOPTS any dual.unsigned -b 10.53.0.1 @10.53.0.1 > dig.out.ns1.test$n || ret=1
|
||||
grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
|
||||
grep "AUTHORITY: 0," dig.out.ns1.test$n > /dev/null || ret=1
|
||||
grep "1.0.0.6" dig.out.ns1.test$n > /dev/null || ret=1
|
||||
grep "::6" dig.out.ns1.test$n > /dev/null && ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
@ -150,7 +148,6 @@ echo_i "checking that A and not AAAA is returned when both AAAA and A records ex
|
||||
ret=0
|
||||
$DIG $DIGOPTS any dual.unsigned +dnssec -b 10.53.0.1 @10.53.0.1 > dig.out.ns1.test$n || ret=1
|
||||
grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
|
||||
grep "AUTHORITY: 0," dig.out.ns1.test$n > /dev/null || ret=1
|
||||
grep "1.0.0.6" dig.out.ns1.test$n > /dev/null || ret=1
|
||||
grep "::6" dig.out.ns1.test$n > /dev/null && ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
|
@ -1142,7 +1142,7 @@ dns_db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
*
|
||||
* \li 'sigrdataset' is a valid, disassociated rdataset, or it is NULL.
|
||||
*
|
||||
* \li If 'covers' != 0, 'type' must be SIG.
|
||||
* \li If 'covers' != 0, 'type' must be RRSIG.
|
||||
*
|
||||
* \li 'type' is not a meta-RR type such as 'ANY' or 'OPT'.
|
||||
*
|
||||
|
@ -181,7 +181,7 @@ typedef int dns_messagetextflag_t;
|
||||
additional section. */
|
||||
#define DNS_MESSAGERENDER_PREFER_AAAA 0x0010 /*%< prefer AAAA records in
|
||||
additional section. */
|
||||
#define DNS_MESSAGERENDER_FILTER_AAAA 0x0020 /*%< filter AAAA records */
|
||||
/* Obsolete: DNS_MESSAGERENDER_FILTER_AAAA 0x0020 */
|
||||
|
||||
typedef struct dns_msgblock dns_msgblock_t;
|
||||
|
||||
|
@ -92,7 +92,6 @@ typedef struct dns_rdatasetmethods {
|
||||
dns_name_t *name);
|
||||
isc_result_t (*addglue)(dns_rdataset_t *rdataset,
|
||||
dns_dbversion_t *version,
|
||||
unsigned int options,
|
||||
dns_message_t *msg);
|
||||
} dns_rdatasetmethods_t;
|
||||
|
||||
@ -197,13 +196,6 @@ struct dns_rdataset {
|
||||
*/
|
||||
#define DNS_RDATASETTOWIRE_OMITDNSSEC 0x0001
|
||||
|
||||
/*%
|
||||
* _FILTERAAAA
|
||||
* If A records are present, omit AAAA records when adding
|
||||
* glue
|
||||
*/
|
||||
#define DNS_RDATASETADDGLUE_FILTERAAAA 0x0001
|
||||
|
||||
void
|
||||
dns_rdataset_init(dns_rdataset_t *rdataset);
|
||||
/*%<
|
||||
@ -580,14 +572,11 @@ dns_rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name);
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_rdataset_addglue(dns_rdataset_t *rdataset,
|
||||
dns_dbversion_t *version,
|
||||
unsigned int options,
|
||||
dns_rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
|
||||
dns_message_t *msg);
|
||||
/*%<
|
||||
* Add glue records for rdataset to the additional section of message in
|
||||
* 'msg'. 'rdataset' must be of type NS. If DNS_RDATASETADDGLUE_FILTERAAAA
|
||||
* is set in 'options' there is type A glue, type AAAA glue is not added.
|
||||
* 'msg'. 'rdataset' must be of type NS.
|
||||
*
|
||||
* In case a successful result is not returned, the caller should try to
|
||||
* add glue directly to the message by iterating for additional data.
|
||||
@ -595,7 +584,6 @@ dns_rdataset_addglue(dns_rdataset_t *rdataset,
|
||||
* Requires:
|
||||
* \li 'rdataset' is a valid NS rdataset.
|
||||
* \li 'version' is the DB version.
|
||||
* \li 'options' is options; currently only _FILTERAAAA is defined.
|
||||
* \li 'msg' is the DNS message to which the glue should be added.
|
||||
*
|
||||
* Returns:
|
||||
|
@ -1903,48 +1903,6 @@ wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decide whether to not answer with an AAAA record and its RRSIG
|
||||
*/
|
||||
static inline bool
|
||||
norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options,
|
||||
dns_section_t sectionid)
|
||||
{
|
||||
if (sectionid == DNS_SECTION_QUESTION)
|
||||
return (false);
|
||||
|
||||
switch (rdataset->type) {
|
||||
case dns_rdatatype_ns:
|
||||
if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
|
||||
sectionid != DNS_SECTION_AUTHORITY)
|
||||
return (false);
|
||||
break;
|
||||
|
||||
case dns_rdatatype_aaaa:
|
||||
if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
|
||||
return (false);
|
||||
break;
|
||||
|
||||
case dns_rdatatype_rrsig:
|
||||
if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
|
||||
(rdataset->covers != dns_rdatatype_ns &&
|
||||
rdataset->covers != dns_rdatatype_aaaa))
|
||||
return (false);
|
||||
if ((rdataset->covers == dns_rdatatype_ns) &&
|
||||
(sectionid != DNS_SECTION_AUTHORITY))
|
||||
return (false);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (rdataset->rdclass != dns_rdataclass_in)
|
||||
return (false);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
renderset(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
|
||||
dns_compress_t *cctx, isc_buffer_t *target,
|
||||
@ -2104,22 +2062,6 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
|
||||
preferred_glue))
|
||||
goto next;
|
||||
|
||||
/*
|
||||
* Suppress AAAAs if asked and we are
|
||||
* not doing DNSSEC or are breaking DNSSEC.
|
||||
* Say so in the AD bit if we break DNSSEC.
|
||||
*/
|
||||
if (norender_rdataset(rdataset, options,
|
||||
sectionid))
|
||||
{
|
||||
if (sectionid == DNS_SECTION_ANSWER ||
|
||||
sectionid == DNS_SECTION_AUTHORITY)
|
||||
msg->flags &= ~DNS_MESSAGEFLAG_AD;
|
||||
if (OPTOUT(rdataset))
|
||||
msg->flags &= ~DNS_MESSAGEFLAG_AD;
|
||||
goto next;
|
||||
}
|
||||
|
||||
st = *(msg->buffer);
|
||||
|
||||
count = 0;
|
||||
|
@ -561,7 +561,6 @@ static void rdataset_getownercase(const dns_rdataset_t *rdataset,
|
||||
dns_name_t *name);
|
||||
static isc_result_t rdataset_addglue(dns_rdataset_t *rdataset,
|
||||
dns_dbversion_t *version,
|
||||
unsigned int options,
|
||||
dns_message_t *msg);
|
||||
static void free_gluetable(rbtdb_version_t *version);
|
||||
|
||||
@ -9807,9 +9806,7 @@ out:
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
rdataset_addglue(dns_rdataset_t *rdataset,
|
||||
dns_dbversion_t *version,
|
||||
unsigned int options,
|
||||
rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
|
||||
dns_message_t *msg)
|
||||
{
|
||||
dns_rbtdb_t *rbtdb = rdataset->private1;
|
||||
@ -9926,42 +9923,39 @@ restart:
|
||||
}
|
||||
}
|
||||
|
||||
if (ISC_LIKELY((options & DNS_RDATASETADDGLUE_FILTERAAAA) == 0))
|
||||
{
|
||||
if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
|
||||
result = dns_message_gettemprdataset(msg,
|
||||
&rdataset_aaaa);
|
||||
if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
|
||||
dns_message_puttempname(msg, &name);
|
||||
if (rdataset_a != NULL) {
|
||||
dns_message_puttemprdataset(msg,
|
||||
&rdataset_a);
|
||||
}
|
||||
if (sigrdataset_a != NULL) {
|
||||
dns_message_puttemprdataset(msg,
|
||||
&sigrdataset_a);
|
||||
}
|
||||
goto no_glue;
|
||||
if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
|
||||
result = dns_message_gettemprdataset(msg,
|
||||
&rdataset_aaaa);
|
||||
if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
|
||||
dns_message_puttempname(msg, &name);
|
||||
if (rdataset_a != NULL) {
|
||||
dns_message_puttemprdataset(msg,
|
||||
&rdataset_a);
|
||||
}
|
||||
if (sigrdataset_a != NULL) {
|
||||
dns_message_puttemprdataset(msg,
|
||||
&sigrdataset_a);
|
||||
}
|
||||
goto no_glue;
|
||||
}
|
||||
}
|
||||
|
||||
if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
|
||||
result = dns_message_gettemprdataset(msg,
|
||||
&sigrdataset_aaaa);
|
||||
if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
|
||||
dns_message_puttempname(msg, &name);
|
||||
if (rdataset_a != NULL) {
|
||||
dns_message_puttemprdataset(msg,
|
||||
&rdataset_a);
|
||||
}
|
||||
if (sigrdataset_a != NULL)
|
||||
dns_message_puttemprdataset(msg,
|
||||
&sigrdataset_a);
|
||||
if (rdataset_aaaa != NULL)
|
||||
dns_message_puttemprdataset(msg,
|
||||
&rdataset_aaaa);
|
||||
goto no_glue;
|
||||
if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
|
||||
result = dns_message_gettemprdataset(msg,
|
||||
&sigrdataset_aaaa);
|
||||
if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
|
||||
dns_message_puttempname(msg, &name);
|
||||
if (rdataset_a != NULL) {
|
||||
dns_message_puttemprdataset(msg,
|
||||
&rdataset_a);
|
||||
}
|
||||
if (sigrdataset_a != NULL)
|
||||
dns_message_puttemprdataset(msg,
|
||||
&sigrdataset_a);
|
||||
if (rdataset_aaaa != NULL)
|
||||
dns_message_puttemprdataset(msg,
|
||||
&rdataset_aaaa);
|
||||
goto no_glue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9975,20 +9969,17 @@ restart:
|
||||
ISC_LIST_APPEND(name->list, sigrdataset_a, link);
|
||||
}
|
||||
|
||||
if (ISC_LIKELY((options & DNS_RDATASETADDGLUE_FILTERAAAA) == 0))
|
||||
{
|
||||
if (rdataset_aaaa != NULL) {
|
||||
dns_rdataset_clone(&ge->rdataset_aaaa,
|
||||
rdataset_aaaa);
|
||||
ISC_LIST_APPEND(name->list, rdataset_aaaa,
|
||||
link);
|
||||
}
|
||||
if (sigrdataset_aaaa != NULL) {
|
||||
dns_rdataset_clone(&ge->sigrdataset_aaaa,
|
||||
sigrdataset_aaaa);
|
||||
ISC_LIST_APPEND(name->list, sigrdataset_aaaa,
|
||||
link);
|
||||
}
|
||||
if (rdataset_aaaa != NULL) {
|
||||
dns_rdataset_clone(&ge->rdataset_aaaa,
|
||||
rdataset_aaaa);
|
||||
ISC_LIST_APPEND(name->list, rdataset_aaaa,
|
||||
link);
|
||||
}
|
||||
if (sigrdataset_aaaa != NULL) {
|
||||
dns_rdataset_clone(&ge->sigrdataset_aaaa,
|
||||
sigrdataset_aaaa);
|
||||
ISC_LIST_APPEND(name->list, sigrdataset_aaaa,
|
||||
link);
|
||||
}
|
||||
|
||||
dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
|
||||
|
@ -751,9 +751,7 @@ dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_rdataset_addglue(dns_rdataset_t *rdataset,
|
||||
dns_dbversion_t *version,
|
||||
unsigned int options,
|
||||
dns_rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
|
||||
dns_message_t *msg)
|
||||
{
|
||||
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
||||
@ -763,6 +761,5 @@ dns_rdataset_addglue(dns_rdataset_t *rdataset,
|
||||
if (rdataset->methods->addglue == NULL)
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
|
||||
return ((rdataset->methods->addglue)(rdataset, version,
|
||||
options, msg));
|
||||
return ((rdataset->methods->addglue)(rdataset, version, msg));
|
||||
}
|
||||
|
@ -1097,23 +1097,6 @@ client_send(ns_client_t *client) {
|
||||
preferred_glue = DNS_MESSAGERENDER_PREFER_AAAA;
|
||||
}
|
||||
|
||||
/*
|
||||
* filter-aaaa-on-v4 yes or break-dnssec option to suppress
|
||||
* AAAA records.
|
||||
*
|
||||
* We already know that request came via IPv4,
|
||||
* that we have both AAAA and A records,
|
||||
* and that we either have no signatures that the client wants
|
||||
* or we are supposed to break DNSSEC.
|
||||
*
|
||||
* Override preferred glue if necessary.
|
||||
*/
|
||||
if ((client->attributes & NS_CLIENTATTR_FILTER_AAAA) != 0) {
|
||||
render_opts |= DNS_MESSAGERENDER_FILTER_AAAA;
|
||||
if (preferred_glue == DNS_MESSAGERENDER_PREFER_AAAA)
|
||||
preferred_glue = DNS_MESSAGERENDER_PREFER_A;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an OPT for our reply.
|
||||
*/
|
||||
@ -3064,6 +3047,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
|
||||
ISC_QLINK_INIT(client, ilink);
|
||||
client->keytag = NULL;
|
||||
client->keytag_len = 0;
|
||||
client->hookflags = 0;
|
||||
|
||||
/*
|
||||
* We call the init routines for the various kinds of client here,
|
||||
|
@ -170,6 +170,12 @@ struct ns_client {
|
||||
uint32_t expire;
|
||||
unsigned char *keytag;
|
||||
uint16_t keytag_len;
|
||||
|
||||
/*%
|
||||
* Allows a hook module to set flags
|
||||
* that persist across recursion.
|
||||
*/
|
||||
uint32_t hookflags;
|
||||
};
|
||||
|
||||
typedef ISC_QUEUE(ns_client_t) client_queue_t;
|
||||
@ -184,8 +190,8 @@ typedef ISC_LIST(ns_client_t) client_list_t;
|
||||
#define NS_CLIENTATTR_MULTICAST 0x00008 /*%< recv'd from multicast */
|
||||
#define NS_CLIENTATTR_WANTDNSSEC 0x00010 /*%< include dnssec records */
|
||||
#define NS_CLIENTATTR_WANTNSID 0x00020 /*%< include nameserver ID */
|
||||
#define NS_CLIENTATTR_FILTER_AAAA 0x00040 /*%< suppress AAAAs */
|
||||
#define NS_CLIENTATTR_FILTER_AAAA_RC 0x00080 /*%< recursing for A against AAAA */
|
||||
/* Obsolete: NS_CLIENTATTR_FILTER_AAAA 0x00040 */
|
||||
/* Obsolete: define NS_CLIENTATTR_FILTER_AAAA_RC 0x00080 */
|
||||
#define NS_CLIENTATTR_WANTAD 0x00100 /*%< want AD in response if possible */
|
||||
#define NS_CLIENTATTR_WANTCOOKIE 0x00200 /*%< return a COOKIE */
|
||||
#define NS_CLIENTATTR_HAVECOOKIE 0x00400 /*%< has a valid COOKIE */
|
||||
|
@ -162,13 +162,11 @@ typedef enum {
|
||||
NS_QUERY_START_BEGIN,
|
||||
NS_QUERY_LOOKUP_BEGIN,
|
||||
NS_QUERY_RESUME_BEGIN,
|
||||
NS_QUERY_PREP_RESPONSE_BEGIN,
|
||||
NS_QUERY_GOT_ANSWER_BEGIN,
|
||||
NS_QUERY_RESPOND_ANY_BEGIN,
|
||||
NS_QUERY_RESPOND_ANY_POST_LOOKUP,
|
||||
NS_QUERY_RESPOND_ANY_FOUND,
|
||||
NS_QUERY_RESPOND_ANY_NOT_FOUND,
|
||||
NS_QUERY_RESPOND_BEGIN,
|
||||
NS_QUERY_GOT_ANSWER_BEGIN,
|
||||
NS_QUERY_NOTFOUND_BEGIN,
|
||||
NS_QUERY_PREP_DELEGATION_BEGIN,
|
||||
NS_QUERY_ZONE_DELEGATION_BEGIN,
|
||||
@ -177,9 +175,10 @@ typedef enum {
|
||||
NS_QUERY_NXDOMAIN_BEGIN,
|
||||
NS_QUERY_CNAME_BEGIN,
|
||||
NS_QUERY_DNAME_BEGIN,
|
||||
NS_QUERY_ADDITIONAL_BEGIN,
|
||||
NS_QUERY_PREP_RESPONSE_BEGIN,
|
||||
NS_QUERY_DONE_BEGIN,
|
||||
NS_QUERY_DONE_SEND,
|
||||
|
||||
NS_QUERY_HOOKS_COUNT /* MUST BE LAST */
|
||||
} ns_hookpoint_t;
|
||||
|
||||
|
@ -121,6 +121,9 @@ struct ns_query {
|
||||
typedef struct query_ctx {
|
||||
isc_buffer_t *dbuf; /* name buffer */
|
||||
dns_name_t *fname; /* found name from DB lookup */
|
||||
dns_name_t *tname; /* temporary name, used
|
||||
* when processing ANY
|
||||
* queries */
|
||||
dns_rdataset_t *rdataset; /* found rdataset */
|
||||
dns_rdataset_t *sigrdataset; /* found sigrdataset */
|
||||
dns_rdataset_t *noqname; /* rdataset needing
|
||||
@ -192,4 +195,12 @@ ns__query_sfcache(query_ctx_t *qctx);
|
||||
isc_result_t
|
||||
ns__query_start(query_ctx_t *qctx);
|
||||
|
||||
/*
|
||||
* XXX:
|
||||
* Temporary function used to initialize the filter-aaaa hooks,
|
||||
* which are currently hard-coded rather than loaded as a module.
|
||||
*/
|
||||
void
|
||||
ns__query_inithooks(void);
|
||||
|
||||
#endif /* NS_QUERY_H */
|
||||
|
694
lib/ns/query.c
694
lib/ns/query.c
@ -191,7 +191,6 @@ client_trace(ns_client_t *client, int level, const char *message) {
|
||||
#define CCTRACE(l,m) ((void)m)
|
||||
#endif /* WANT_QUERYTRACE */
|
||||
|
||||
|
||||
#define DNS_GETDB_NOEXACT 0x01U
|
||||
#define DNS_GETDB_NOLOG 0x02U
|
||||
#define DNS_GETDB_PARTIAL 0x04U
|
||||
@ -429,6 +428,64 @@ query_addauth(query_ctx_t *qctx);
|
||||
static isc_result_t
|
||||
query_done(query_ctx_t *qctx);
|
||||
|
||||
/*
|
||||
* XXX:
|
||||
* Functions implementing filter-aaaa. Later, these will be moved
|
||||
* out to a loadable module.
|
||||
*/
|
||||
static isc_result_t
|
||||
query_filter_aaaa_check(query_ctx_t *qctx);
|
||||
|
||||
static isc_result_t
|
||||
query_filter_aaaa(query_ctx_t *qctx);
|
||||
|
||||
static isc_result_t
|
||||
query_filter_aaaa_any(query_ctx_t *qctx);
|
||||
|
||||
static isc_result_t
|
||||
query_filter_aaaa_additional(query_ctx_t *qctx);
|
||||
|
||||
/*
|
||||
* XXX:
|
||||
* This is a temporary hooks table, pre-populated with pointers to
|
||||
* the functions implementing filter-aaaa. Later, this will be
|
||||
* redesigned to be set up at initialization time when the
|
||||
* filter-aaaa module is loaded. To activate this hooks table
|
||||
* at runtime, call ns__query_inithooks().
|
||||
*/
|
||||
static bool
|
||||
filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp);
|
||||
|
||||
static bool
|
||||
filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp);
|
||||
|
||||
static bool
|
||||
filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp);
|
||||
|
||||
static bool
|
||||
filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp);
|
||||
|
||||
ns_hook_t filter_respbegin = {
|
||||
.callback = filter_respond_begin,
|
||||
.callback_data = NULL,
|
||||
.link = { (void *) -1, (void *) -1 },
|
||||
};
|
||||
ns_hook_t filter_respanyfound = {
|
||||
.callback = filter_respond_any_found,
|
||||
.callback_data = NULL,
|
||||
.link = { (void *) -1, (void *) -1 },
|
||||
};
|
||||
ns_hook_t filter_prepresp = {
|
||||
.callback = filter_prep_response_begin,
|
||||
.callback_data = NULL,
|
||||
.link = { (void *) -1, (void *) -1 },
|
||||
};
|
||||
ns_hook_t filter_donesend = {
|
||||
.callback = filter_query_done_send,
|
||||
.callback_data = NULL,
|
||||
.link = { (void *) -1, (void *) -1 },
|
||||
};
|
||||
|
||||
/*%
|
||||
* Increment query statistics counters.
|
||||
*/
|
||||
@ -1876,8 +1933,6 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) {
|
||||
}
|
||||
|
||||
if (qtype == dns_rdatatype_a) {
|
||||
bool have_a = false;
|
||||
|
||||
/*
|
||||
* We now go looking for A and AAAA records, along with
|
||||
* their signatures.
|
||||
@ -1923,8 +1978,6 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) {
|
||||
} else if (result == ISC_R_SUCCESS) {
|
||||
bool invalid = false;
|
||||
mname = NULL;
|
||||
|
||||
have_a = true;
|
||||
if (additionaltype ==
|
||||
dns_rdatasetadditional_fromcache &&
|
||||
(DNS_TRUST_PENDING(rdataset->trust) ||
|
||||
@ -1999,17 +2052,6 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) {
|
||||
} else if (result == ISC_R_SUCCESS) {
|
||||
bool invalid = false;
|
||||
mname = NULL;
|
||||
/*
|
||||
* There's an A; check whether we're filtering AAAA
|
||||
*/
|
||||
if (have_a &&
|
||||
(qctx->filter_aaaa == dns_aaaa_break_dnssec ||
|
||||
(qctx->filter_aaaa == dns_aaaa_filter &&
|
||||
(!WANTDNSSEC(client) || sigrdataset == NULL ||
|
||||
!dns_rdataset_isassociated(sigrdataset)))))
|
||||
{
|
||||
goto addname;
|
||||
}
|
||||
|
||||
if (additionaltype ==
|
||||
dns_rdatasetadditional_fromcache &&
|
||||
@ -2165,21 +2207,14 @@ query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) {
|
||||
{
|
||||
isc_result_t result;
|
||||
ns_dbversion_t *dbversion;
|
||||
unsigned int options = 0;
|
||||
|
||||
dbversion = query_findversion(client, client->query.gluedb);
|
||||
if (dbversion == NULL) {
|
||||
goto regular;
|
||||
}
|
||||
|
||||
if (qctx->filter_aaaa == dns_aaaa_filter ||
|
||||
qctx->filter_aaaa == dns_aaaa_break_dnssec)
|
||||
{
|
||||
options |= DNS_RDATASETADDGLUE_FILTERAAAA;
|
||||
}
|
||||
|
||||
result = dns_rdataset_addglue(rdataset, dbversion->version,
|
||||
options, client->message);
|
||||
client->message);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
@ -4518,7 +4553,6 @@ static dns_name_t rfc1918names[] = {
|
||||
DNS_NAME_INITABSOLUTE(inaddr168192, inaddr192_offsets)
|
||||
};
|
||||
|
||||
|
||||
static unsigned char prisoner_data[] = "\010prisoner\004iana\003org";
|
||||
static unsigned char hostmaster_data[] = "\012hostmaster\014root-servers\003org";
|
||||
|
||||
@ -6946,21 +6980,10 @@ query_addnoqnameproof(query_ctx_t *qctx) {
|
||||
*/
|
||||
static isc_result_t
|
||||
query_respond_any(query_ctx_t *qctx) {
|
||||
dns_name_t *tname;
|
||||
int rdatasets_found = 0;
|
||||
bool found = false;
|
||||
dns_rdatasetiter_t *rdsiter = NULL;
|
||||
isc_result_t result;
|
||||
dns_rdatatype_t onetype = 0; /* type to use for minimal-any */
|
||||
bool have_aaaa, have_a, have_sig;
|
||||
|
||||
/*
|
||||
* If we are not authoritative, assume there is an A record
|
||||
* even in if it is not in our cache. This assumption could
|
||||
* be wrong but it is a good bet.
|
||||
*/
|
||||
have_aaaa = false;
|
||||
have_a = !qctx->authoritative;
|
||||
have_sig = false;
|
||||
|
||||
PROCESS_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx);
|
||||
|
||||
@ -6985,21 +7008,11 @@ query_respond_any(query_ctx_t *qctx) {
|
||||
* cleanup qctx->fname even though we're using it!
|
||||
*/
|
||||
query_keepname(qctx->client, qctx->fname, qctx->dbuf);
|
||||
tname = qctx->fname;
|
||||
qctx->tname = qctx->fname;
|
||||
|
||||
result = dns_rdatasetiter_first(rdsiter);
|
||||
while (result == ISC_R_SUCCESS) {
|
||||
dns_rdatasetiter_current(rdsiter, qctx->rdataset);
|
||||
/*
|
||||
* Notice the presence of A and AAAAs so
|
||||
* that AAAAs can be hidden from IPv4 clients.
|
||||
*/
|
||||
if (qctx->filter_aaaa != dns_aaaa_ok) {
|
||||
if (qctx->rdataset->type == dns_rdatatype_aaaa)
|
||||
have_aaaa = true;
|
||||
else if (qctx->rdataset->type == dns_rdatatype_a)
|
||||
have_a = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* We found an NS RRset; no need to add one later.
|
||||
@ -7047,9 +7060,6 @@ query_respond_any(query_ctx_t *qctx) {
|
||||
qctx->rdataset->type == qctx->qtype) &&
|
||||
qctx->rdataset->type != 0)
|
||||
{
|
||||
if (dns_rdatatype_isdnssec(qctx->rdataset->type))
|
||||
have_sig = true;
|
||||
|
||||
if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client))
|
||||
{
|
||||
qctx->noqname = qctx->rdataset;
|
||||
@ -7067,7 +7077,7 @@ query_respond_any(query_ctx_t *qctx) {
|
||||
dns_name_t *name;
|
||||
name = (qctx->fname != NULL)
|
||||
? qctx->fname
|
||||
: tname;
|
||||
: qctx->tname;
|
||||
query_prefetch(qctx->client, name,
|
||||
qctx->rdataset);
|
||||
}
|
||||
@ -7078,29 +7088,32 @@ query_respond_any(query_ctx_t *qctx) {
|
||||
*/
|
||||
if (qctx->rdataset->type == dns_rdatatype_sig ||
|
||||
qctx->rdataset->type == dns_rdatatype_rrsig)
|
||||
{
|
||||
onetype = qctx->rdataset->covers;
|
||||
else
|
||||
} else {
|
||||
onetype = qctx->rdataset->type;
|
||||
}
|
||||
|
||||
query_addrrset(qctx,
|
||||
(qctx->fname != NULL)
|
||||
? &qctx->fname
|
||||
: &tname,
|
||||
: &qctx->tname,
|
||||
&qctx->rdataset, NULL,
|
||||
NULL, DNS_SECTION_ANSWER);
|
||||
|
||||
query_addnoqnameproof(qctx);
|
||||
|
||||
rdatasets_found++;
|
||||
INSIST(tname != NULL);
|
||||
found = true;
|
||||
INSIST(qctx->tname != NULL);
|
||||
|
||||
/*
|
||||
* rdataset is non-NULL only in certain
|
||||
* pathological cases involving DNAMEs.
|
||||
*/
|
||||
if (qctx->rdataset != NULL)
|
||||
if (qctx->rdataset != NULL) {
|
||||
query_putrdataset(qctx->client,
|
||||
&qctx->rdataset);
|
||||
}
|
||||
|
||||
qctx->rdataset = query_newrdataset(qctx->client);
|
||||
if (qctx->rdataset == NULL)
|
||||
@ -7115,36 +7128,40 @@ query_respond_any(query_ctx_t *qctx) {
|
||||
result = dns_rdatasetiter_next(rdsiter);
|
||||
}
|
||||
|
||||
PROCESS_HOOK(NS_QUERY_RESPOND_ANY_POST_LOOKUP, qctx);
|
||||
dns_rdatasetiter_destroy(&rdsiter);
|
||||
|
||||
/*
|
||||
* Filter AAAAs if there is an A and there is no signature
|
||||
* or we are supposed to break DNSSEC.
|
||||
*/
|
||||
if (qctx->filter_aaaa == dns_aaaa_break_dnssec)
|
||||
qctx->client->attributes |= NS_CLIENTATTR_FILTER_AAAA;
|
||||
else if (qctx->filter_aaaa != dns_aaaa_ok &&
|
||||
have_aaaa && have_a &&
|
||||
(!have_sig || !WANTDNSSEC(qctx->client)))
|
||||
qctx->client->attributes |= NS_CLIENTATTR_FILTER_AAAA;
|
||||
if (result != ISC_R_NOMORE) {
|
||||
CCTRACE(ISC_LOG_ERROR,
|
||||
"query_respond_any: rdataset iterator failed");
|
||||
QUERY_ERROR(qctx, DNS_R_SERVFAIL);
|
||||
}
|
||||
|
||||
if (qctx->fname != NULL)
|
||||
dns_message_puttempname(qctx->client->message, &qctx->fname);
|
||||
if (found) {
|
||||
PROCESS_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx);
|
||||
|
||||
if (qctx->fname != NULL) {
|
||||
dns_message_puttempname(qctx->client->message,
|
||||
&qctx->fname);
|
||||
}
|
||||
} else {
|
||||
PROCESS_HOOK(NS_QUERY_RESPOND_ANY_NOT_FOUND, qctx);
|
||||
|
||||
if (qctx->fname != NULL) {
|
||||
dns_message_puttempname(qctx->client->message,
|
||||
&qctx->fname);
|
||||
}
|
||||
|
||||
if (rdatasets_found == 0) {
|
||||
/*
|
||||
* No matching rdatasets found in cache. If we were
|
||||
* searching for RRSIG/SIG, that's probably okay;
|
||||
* otherwise this is an error condition.
|
||||
*/
|
||||
if ((qctx->qtype == dns_rdatatype_rrsig ||
|
||||
qctx->qtype == dns_rdatatype_sig) &&
|
||||
result == ISC_R_NOMORE)
|
||||
if (qctx->qtype == dns_rdatatype_rrsig ||
|
||||
qctx->qtype == dns_rdatatype_sig)
|
||||
{
|
||||
isc_buffer_t b;
|
||||
if (!qctx->is_zone) {
|
||||
qctx->authoritative = false;
|
||||
dns_rdatasetiter_destroy(&rdsiter);
|
||||
qctx->client->attributes &= ~NS_CLIENTATTR_RA;
|
||||
query_addauth(qctx);
|
||||
return (query_done(qctx));
|
||||
@ -7164,7 +7181,6 @@ query_respond_any(query_ctx_t *qctx) {
|
||||
namebuf);
|
||||
}
|
||||
|
||||
dns_rdatasetiter_destroy(&rdsiter);
|
||||
qctx->fname = query_newname(qctx->client,
|
||||
qctx->dbuf, &b);
|
||||
return (query_sign_nodata(qctx));
|
||||
@ -7176,14 +7192,7 @@ query_respond_any(query_ctx_t *qctx) {
|
||||
}
|
||||
}
|
||||
|
||||
dns_rdatasetiter_destroy(&rdsiter);
|
||||
if (result != ISC_R_NOMORE) {
|
||||
CCTRACE(ISC_LOG_ERROR,
|
||||
"query_respond_any: dns_rdatasetiter_destroy failed");
|
||||
QUERY_ERROR(qctx, result);
|
||||
} else {
|
||||
query_addauth(qctx);
|
||||
}
|
||||
query_addauth(qctx);
|
||||
|
||||
return (query_done(qctx));
|
||||
}
|
||||
@ -7242,101 +7251,6 @@ query_getexpire(query_ctx_t *qctx) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Optionally hide AAAAs from IPv4 clients if there is an A.
|
||||
*
|
||||
* We add the AAAAs now, but might refuse to render them later
|
||||
* after DNSSEC is figured out.
|
||||
*
|
||||
* This could be more efficient, but the whole idea is
|
||||
* so fundamentally wrong, unavoidably inaccurate, and
|
||||
* unneeded that it is best to keep it as short as possible.
|
||||
*/
|
||||
static isc_result_t
|
||||
query_filter_aaaa(query_ctx_t *qctx) {
|
||||
isc_result_t result;
|
||||
|
||||
if (qctx->filter_aaaa != dns_aaaa_break_dnssec &&
|
||||
(qctx->filter_aaaa != dns_aaaa_filter ||
|
||||
(WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL &&
|
||||
dns_rdataset_isassociated(qctx->sigrdataset))))
|
||||
{
|
||||
return (ISC_R_COMPLETE);
|
||||
}
|
||||
|
||||
if (qctx->qtype == dns_rdatatype_aaaa) {
|
||||
dns_rdataset_t *trdataset;
|
||||
trdataset = query_newrdataset(qctx->client);
|
||||
result = dns_db_findrdataset(qctx->db, qctx->node,
|
||||
qctx->version,
|
||||
dns_rdatatype_a, 0,
|
||||
qctx->client->now,
|
||||
trdataset, NULL);
|
||||
if (dns_rdataset_isassociated(trdataset)) {
|
||||
dns_rdataset_disassociate(trdataset);
|
||||
}
|
||||
query_putrdataset(qctx->client, &trdataset);
|
||||
|
||||
/*
|
||||
* We have an AAAA but the A is not in our cache.
|
||||
* Assume any result other than DNS_R_DELEGATION
|
||||
* or ISC_R_NOTFOUND means there is no A and
|
||||
* so AAAAs are ok.
|
||||
*
|
||||
* Assume there is no A if we can't recurse
|
||||
* for this client, although that could be
|
||||
* the wrong answer. What else can we do?
|
||||
* Besides, that we have the AAAA and are using
|
||||
* this mechanism suggests that we care more
|
||||
* about As than AAAAs and would have cached
|
||||
* the A if it existed.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
qctx->client->attributes |=
|
||||
NS_CLIENTATTR_FILTER_AAAA;
|
||||
|
||||
} else if (qctx->authoritative ||
|
||||
!RECURSIONOK(qctx->client) ||
|
||||
(result != DNS_R_DELEGATION &&
|
||||
result != ISC_R_NOTFOUND))
|
||||
{
|
||||
qctx->client->attributes &=
|
||||
~NS_CLIENTATTR_FILTER_AAAA;
|
||||
} else {
|
||||
/*
|
||||
* This is an ugly kludge to recurse
|
||||
* for the A and discard the result.
|
||||
*
|
||||
* Continue to add the AAAA now.
|
||||
* We'll make a note to not render it
|
||||
* if the recursion for the A succeeds.
|
||||
*/
|
||||
INSIST(!REDIRECT(qctx->client));
|
||||
result = query_recurse(qctx->client,
|
||||
dns_rdatatype_a,
|
||||
qctx->client->query.qname,
|
||||
NULL, NULL, qctx->resuming);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
qctx->client->attributes |=
|
||||
NS_CLIENTATTR_FILTER_AAAA_RC;
|
||||
qctx->client->query.attributes |=
|
||||
NS_QUERYATTR_RECURSING;
|
||||
}
|
||||
}
|
||||
} else if (qctx->qtype == dns_rdatatype_a &&
|
||||
(qctx->client->attributes &
|
||||
NS_CLIENTATTR_FILTER_AAAA_RC) != 0)
|
||||
{
|
||||
qctx->client->attributes &= ~NS_CLIENTATTR_FILTER_AAAA_RC;
|
||||
qctx->client->attributes |= NS_CLIENTATTR_FILTER_AAAA;
|
||||
qctx_clean(qctx);
|
||||
|
||||
return (query_done(qctx));
|
||||
}
|
||||
|
||||
return (ISC_R_COMPLETE);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Build a repsonse for a "normal" query, for a type other than ANY,
|
||||
* for which we have an answer (either positive or negative).
|
||||
@ -7379,12 +7293,6 @@ query_respond(query_ctx_t *qctx) {
|
||||
/*
|
||||
* Check to see if the AAAA RRset has non-excluded addresses
|
||||
* in it. If not look for a A RRset.
|
||||
*
|
||||
* Note: the order of dns64_aaaaok() and query_filter_aaaa() is
|
||||
* important. query_filter_aaaa() calls query_recurse() but
|
||||
* continues so that the AAAA records are added. If the
|
||||
* order is reversed client->query.fetch will be non-NULL
|
||||
* when query_lookup() is called leading to a assertion.
|
||||
*/
|
||||
INSIST(qctx->client->query.dns64_aaaaok == NULL);
|
||||
|
||||
@ -7407,10 +7315,6 @@ query_respond(query_ctx_t *qctx) {
|
||||
return (query_lookup(qctx));
|
||||
}
|
||||
|
||||
result = query_filter_aaaa(qctx);
|
||||
if (result != ISC_R_COMPLETE)
|
||||
return (result);
|
||||
|
||||
if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
|
||||
sigrdatasetp = &qctx->sigrdataset;
|
||||
}
|
||||
@ -9268,12 +9172,6 @@ query_coveringnsec(query_ctx_t *qctx) {
|
||||
if (qctx->type == dns_rdatatype_any) { /* XXX not yet */
|
||||
goto cleanup;
|
||||
}
|
||||
if (qctx->filter_aaaa != dns_aaaa_ok &&
|
||||
(qctx->type == dns_rdatatype_a ||
|
||||
qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
if (!ISC_LIST_EMPTY(qctx->client->view->dns64) &&
|
||||
(qctx->type == dns_rdatatype_a ||
|
||||
qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
|
||||
@ -9338,12 +9236,6 @@ query_coveringnsec(query_ctx_t *qctx) {
|
||||
if (qctx->type == dns_rdatatype_any) { /* XXX not yet */
|
||||
goto cleanup;
|
||||
}
|
||||
if (qctx->filter_aaaa != dns_aaaa_ok &&
|
||||
(qctx->type == dns_rdatatype_a ||
|
||||
qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
if (!ISC_LIST_EMPTY(qctx->client->view->dns64) &&
|
||||
(qctx->type == dns_rdatatype_a ||
|
||||
qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
|
||||
@ -9865,8 +9757,8 @@ query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) {
|
||||
|
||||
/*%
|
||||
* Prepare to respond: determine whether a wildcard proof is needed,
|
||||
* check whether to filter AAAA answers, then hand off to query_respond()
|
||||
* or (for type ANY queries) query_respond_any().
|
||||
* then hand off to query_respond() or (for type ANY queries)
|
||||
* query_respond_any().
|
||||
*/
|
||||
static isc_result_t
|
||||
query_prepresponse(query_ctx_t *qctx) {
|
||||
@ -9881,33 +9773,6 @@ query_prepresponse(query_ctx_t *qctx) {
|
||||
qctx->need_wildcardproof = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The filter-aaaa-on-v4 option should suppress AAAAs for IPv4
|
||||
* clients if there is an A; filter-aaaa-on-v6 option does the same
|
||||
* for IPv6 clients.
|
||||
*/
|
||||
qctx->filter_aaaa = dns_aaaa_ok;
|
||||
if (qctx->client->view->v4_aaaa != dns_aaaa_ok ||
|
||||
qctx->client->view->v6_aaaa != dns_aaaa_ok)
|
||||
{
|
||||
isc_result_t result;
|
||||
result = ns_client_checkaclsilent(qctx->client, NULL,
|
||||
qctx->client->view->aaaa_acl,
|
||||
true);
|
||||
if (result == ISC_R_SUCCESS &&
|
||||
qctx->client->view->v4_aaaa != dns_aaaa_ok &&
|
||||
is_v4_client(qctx->client))
|
||||
{
|
||||
qctx->filter_aaaa = qctx->client->view->v4_aaaa;
|
||||
} else if (result == ISC_R_SUCCESS &&
|
||||
qctx->client->view->v6_aaaa != dns_aaaa_ok &&
|
||||
is_v6_client(qctx->client))
|
||||
{
|
||||
qctx->filter_aaaa = qctx->client->view->v6_aaaa;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (qctx->type == dns_rdatatype_any) {
|
||||
return (query_respond_any(qctx));
|
||||
} else {
|
||||
@ -10783,6 +10648,7 @@ query_glueanswer(query_ctx_t *qctx) {
|
||||
static isc_result_t
|
||||
query_done(query_ctx_t *qctx) {
|
||||
const dns_namelist_t *secs = qctx->client->message->sections;
|
||||
|
||||
CCTRACE(ISC_LOG_DEBUG(3), "query_done");
|
||||
|
||||
PROCESS_HOOK(NS_QUERY_DONE_BEGIN, qctx);
|
||||
@ -11284,3 +11150,371 @@ ns_query_start(ns_client_t *client) {
|
||||
ns_client_attach(client, &qclient);
|
||||
(void)query_setup(qclient, qtype);
|
||||
}
|
||||
|
||||
/*
|
||||
* Per-client flags set by this module
|
||||
*/
|
||||
#define FILTER_AAAA_RECURSING 0x0001 /* Recursing for A */
|
||||
#define FILTER_AAAA_FILTERED 0x0002 /* AAAA was removed from answer */
|
||||
|
||||
/*
|
||||
* The filter-aaaa-on-v4 option suppresses AAAAs for IPv4
|
||||
* clients if there is an A; filter-aaaa-on-v6 option does
|
||||
* the same for IPv6 clients.
|
||||
*/
|
||||
static isc_result_t
|
||||
query_filter_aaaa_check(query_ctx_t *qctx) {
|
||||
qctx->filter_aaaa = dns_aaaa_ok;
|
||||
if (qctx->client->view->v4_aaaa != dns_aaaa_ok ||
|
||||
qctx->client->view->v6_aaaa != dns_aaaa_ok)
|
||||
{
|
||||
isc_result_t result;
|
||||
result = ns_client_checkaclsilent(qctx->client, NULL,
|
||||
qctx->client->view->aaaa_acl,
|
||||
true);
|
||||
if (result == ISC_R_SUCCESS &&
|
||||
qctx->client->view->v4_aaaa != dns_aaaa_ok &&
|
||||
is_v4_client(qctx->client))
|
||||
{
|
||||
qctx->filter_aaaa = qctx->client->view->v4_aaaa;
|
||||
} else if (result == ISC_R_SUCCESS &&
|
||||
qctx->client->view->v6_aaaa != dns_aaaa_ok &&
|
||||
is_v6_client(qctx->client))
|
||||
{
|
||||
qctx->filter_aaaa = qctx->client->view->v6_aaaa;
|
||||
}
|
||||
}
|
||||
|
||||
return (ISC_R_COMPLETE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Optionally hide AAAA rrsets if there is a matching A.
|
||||
* (This version is for processing answers to explicit AAAA
|
||||
* queries; ANY queries are handled in query_filter_aaaa_any().)
|
||||
*/
|
||||
static isc_result_t
|
||||
query_filter_aaaa(query_ctx_t *qctx) {
|
||||
isc_result_t result;
|
||||
|
||||
if (qctx->filter_aaaa != dns_aaaa_break_dnssec &&
|
||||
(qctx->filter_aaaa != dns_aaaa_filter ||
|
||||
(WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL &&
|
||||
dns_rdataset_isassociated(qctx->sigrdataset))))
|
||||
{
|
||||
return (ISC_R_COMPLETE);
|
||||
}
|
||||
|
||||
if (qctx->qtype == dns_rdatatype_aaaa) {
|
||||
dns_rdataset_t *trdataset;
|
||||
trdataset = query_newrdataset(qctx->client);
|
||||
result = dns_db_findrdataset(qctx->db, qctx->node,
|
||||
qctx->version,
|
||||
dns_rdatatype_a, 0,
|
||||
qctx->client->now,
|
||||
trdataset, NULL);
|
||||
if (dns_rdataset_isassociated(trdataset)) {
|
||||
dns_rdataset_disassociate(trdataset);
|
||||
}
|
||||
query_putrdataset(qctx->client, &trdataset);
|
||||
|
||||
/*
|
||||
* We found an AAAA. If we also found an A, then the AAAA
|
||||
* must not be rendered.
|
||||
*
|
||||
* If the A is not in our cache, then any result other than
|
||||
* DNS_R_DELEGATION or ISC_R_NOTFOUND means there is no A,
|
||||
* and so AAAAs are okay.
|
||||
*
|
||||
* We assume there is no A if we can't recurse for this
|
||||
* client. That might be the wrong answer, but what else
|
||||
* can we do? Besides, the fact that we have the AAAA and
|
||||
* are using this mechanism in the first place suggests
|
||||
* that we care more about As than AAAAs, and would have
|
||||
* cached an A if it existed.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
qctx->rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
|
||||
if (qctx->sigrdataset != NULL &&
|
||||
dns_rdataset_isassociated(qctx->sigrdataset))
|
||||
{
|
||||
qctx->sigrdataset->attributes |=
|
||||
DNS_RDATASETATTR_RENDERED;
|
||||
}
|
||||
qctx->client->hookflags |= FILTER_AAAA_FILTERED;
|
||||
} else if (!qctx->authoritative &&
|
||||
RECURSIONOK(qctx->client) &&
|
||||
(result == DNS_R_DELEGATION ||
|
||||
result == ISC_R_NOTFOUND))
|
||||
{
|
||||
/*
|
||||
* This is an ugly kludge to recurse
|
||||
* for the A and discard the result.
|
||||
*
|
||||
* Continue to add the AAAA now.
|
||||
* We'll make a note to not render it
|
||||
* if the recursion for the A succeeds.
|
||||
*/
|
||||
INSIST(!REDIRECT(qctx->client));
|
||||
result = query_recurse(qctx->client,
|
||||
dns_rdatatype_a,
|
||||
qctx->client->query.qname,
|
||||
NULL, NULL, qctx->resuming);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
qctx->client->hookflags |=
|
||||
FILTER_AAAA_RECURSING;
|
||||
qctx->client->query.attributes |=
|
||||
NS_QUERYATTR_RECURSING;
|
||||
}
|
||||
}
|
||||
} else if (qctx->qtype == dns_rdatatype_a &&
|
||||
((qctx->client->hookflags & FILTER_AAAA_RECURSING) != 0))
|
||||
{
|
||||
|
||||
dns_rdataset_t *mrdataset = NULL;
|
||||
dns_rdataset_t *sigrdataset = NULL;
|
||||
|
||||
result = dns_message_findname(qctx->client->message,
|
||||
DNS_SECTION_ANSWER, qctx->fname,
|
||||
dns_rdatatype_aaaa, 0,
|
||||
NULL, &mrdataset);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
mrdataset->attributes |= DNS_RDATASETATTR_RENDERED;
|
||||
}
|
||||
|
||||
result = dns_message_findname(qctx->client->message,
|
||||
DNS_SECTION_ANSWER, qctx->fname,
|
||||
dns_rdatatype_rrsig,
|
||||
dns_rdatatype_aaaa,
|
||||
NULL, &sigrdataset);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED;
|
||||
}
|
||||
|
||||
qctx->client->hookflags &= ~FILTER_AAAA_RECURSING;
|
||||
|
||||
return (query_done(qctx));
|
||||
}
|
||||
|
||||
return (ISC_R_COMPLETE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Optionally hide AAAA rrsets if there is a matching A.
|
||||
* (This version is for processing answers to ANY queries;
|
||||
* explicit AAAA queries are handled in query_filter_aaaa().)
|
||||
*/
|
||||
static isc_result_t
|
||||
query_filter_aaaa_any(query_ctx_t *qctx) {
|
||||
dns_name_t *name = NULL;
|
||||
dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL;
|
||||
dns_rdataset_t *a = NULL;
|
||||
bool have_a = true;
|
||||
|
||||
if (qctx->filter_aaaa == dns_aaaa_ok) {
|
||||
return (ISC_R_COMPLETE);
|
||||
}
|
||||
|
||||
dns_message_findname(qctx->client->message, DNS_SECTION_ANSWER,
|
||||
(qctx->fname != NULL)
|
||||
? qctx->fname
|
||||
: qctx->tname,
|
||||
dns_rdatatype_any, 0, &name, NULL);
|
||||
|
||||
/*
|
||||
* If we're not authoritative, just assume there's an
|
||||
* A even if it wasn't in the cache and therefore isn't
|
||||
* in the message. But if we're authoritative, then
|
||||
* if there was an A, it should be here.
|
||||
*/
|
||||
if (qctx->authoritative && name != NULL) {
|
||||
dns_message_findtype(name, dns_rdatatype_a, 0, &a);
|
||||
if (a == NULL) {
|
||||
have_a = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (name != NULL) {
|
||||
dns_message_findtype(name, dns_rdatatype_aaaa, 0, &aaaa);
|
||||
dns_message_findtype(name, dns_rdatatype_rrsig,
|
||||
dns_rdatatype_aaaa, &aaaa_sig);
|
||||
}
|
||||
|
||||
if (have_a && aaaa != NULL &&
|
||||
(aaaa_sig == NULL || !WANTDNSSEC(qctx->client) ||
|
||||
qctx->filter_aaaa == dns_aaaa_break_dnssec))
|
||||
{
|
||||
aaaa->attributes |= DNS_RDATASETATTR_RENDERED;
|
||||
if (aaaa_sig != NULL) {
|
||||
aaaa_sig->attributes |= DNS_RDATASETATTR_RENDERED;
|
||||
}
|
||||
}
|
||||
|
||||
return (ISC_R_COMPLETE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hide AAAA rrsets in the additional section if there is a matching A,
|
||||
* and hide NS in the additional section if AAAA was filtered in the answer
|
||||
* section.
|
||||
*/
|
||||
static isc_result_t
|
||||
query_filter_aaaa_additional(query_ctx_t *qctx) {
|
||||
isc_result_t result;
|
||||
|
||||
if (qctx->filter_aaaa == dns_aaaa_ok) {
|
||||
return (ISC_R_COMPLETE);
|
||||
}
|
||||
|
||||
result = dns_message_firstname(qctx->client->message,
|
||||
DNS_SECTION_ADDITIONAL);
|
||||
while (result == ISC_R_SUCCESS) {
|
||||
dns_name_t *name = NULL;
|
||||
dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL;
|
||||
dns_rdataset_t *a = NULL;
|
||||
|
||||
dns_message_currentname(qctx->client->message,
|
||||
DNS_SECTION_ADDITIONAL,
|
||||
&name);
|
||||
|
||||
result = dns_message_nextname(qctx->client->message,
|
||||
DNS_SECTION_ADDITIONAL);
|
||||
|
||||
dns_message_findtype(name, dns_rdatatype_a, 0, &a);
|
||||
if (a == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dns_message_findtype(name, dns_rdatatype_aaaa, 0,
|
||||
&aaaa);
|
||||
if (aaaa == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dns_message_findtype(name, dns_rdatatype_rrsig,
|
||||
dns_rdatatype_aaaa, &aaaa_sig);
|
||||
|
||||
if (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) ||
|
||||
qctx->filter_aaaa == dns_aaaa_break_dnssec)
|
||||
{
|
||||
aaaa->attributes |= DNS_RDATASETATTR_RENDERED;
|
||||
if (aaaa_sig != NULL) {
|
||||
aaaa_sig->attributes |=
|
||||
DNS_RDATASETATTR_RENDERED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((qctx->client->hookflags & FILTER_AAAA_FILTERED) != 0) {
|
||||
result = dns_message_firstname(qctx->client->message,
|
||||
DNS_SECTION_AUTHORITY);
|
||||
while (result == ISC_R_SUCCESS) {
|
||||
dns_name_t *name = NULL;
|
||||
dns_rdataset_t *ns = NULL, *ns_sig = NULL;
|
||||
|
||||
dns_message_currentname(qctx->client->message,
|
||||
DNS_SECTION_AUTHORITY,
|
||||
&name);
|
||||
|
||||
result = dns_message_findtype(name, dns_rdatatype_ns,
|
||||
0, &ns);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
ns->attributes |= DNS_RDATASETATTR_RENDERED;
|
||||
}
|
||||
|
||||
result = dns_message_findtype(name, dns_rdatatype_rrsig,
|
||||
dns_rdatatype_ns,
|
||||
&ns_sig);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
ns_sig->attributes |= DNS_RDATASETATTR_RENDERED;
|
||||
}
|
||||
|
||||
result = dns_message_nextname(qctx->client->message,
|
||||
DNS_SECTION_AUTHORITY);
|
||||
}
|
||||
}
|
||||
|
||||
return (ISC_R_COMPLETE);
|
||||
}
|
||||
|
||||
static bool
|
||||
filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) {
|
||||
isc_result_t result;
|
||||
|
||||
UNUSED(cbdata);
|
||||
|
||||
result = query_filter_aaaa((query_ctx_t *) hookdata);
|
||||
if (result != ISC_R_COMPLETE) {
|
||||
*resp = result;
|
||||
return (true);
|
||||
}
|
||||
|
||||
*resp = ISC_R_SUCCESS;
|
||||
return (false);
|
||||
}
|
||||
|
||||
static bool
|
||||
filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) {
|
||||
isc_result_t result;
|
||||
|
||||
UNUSED(cbdata);
|
||||
|
||||
result = query_filter_aaaa_any((query_ctx_t *) hookdata);
|
||||
if (result != ISC_R_COMPLETE) {
|
||||
*resp = result;
|
||||
return (true);
|
||||
}
|
||||
|
||||
*resp = ISC_R_SUCCESS;
|
||||
return (false);
|
||||
}
|
||||
|
||||
static bool
|
||||
filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) {
|
||||
isc_result_t result;
|
||||
|
||||
UNUSED(cbdata);
|
||||
|
||||
result = query_filter_aaaa_check((query_ctx_t *) hookdata);
|
||||
if (result != ISC_R_COMPLETE) {
|
||||
*resp = result;
|
||||
return (true);
|
||||
}
|
||||
|
||||
*resp = ISC_R_SUCCESS;
|
||||
return (false);
|
||||
}
|
||||
|
||||
static bool
|
||||
filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) {
|
||||
isc_result_t result;
|
||||
|
||||
UNUSED(cbdata);
|
||||
|
||||
result = query_filter_aaaa_additional((query_ctx_t *) hookdata);
|
||||
if (result != ISC_R_COMPLETE) {
|
||||
*resp = result;
|
||||
return (true);
|
||||
}
|
||||
|
||||
*resp = ISC_R_SUCCESS;
|
||||
return (false);
|
||||
}
|
||||
|
||||
void
|
||||
ns__query_inithooks() {
|
||||
/*
|
||||
* XXX: This function is temporary. Later, the hook table
|
||||
* will be set up when initializing hook modules after
|
||||
* configuring the server.
|
||||
*
|
||||
* For now, however, we just call this once when initializing named
|
||||
* and it will set up all the filter-aaaa hooks.
|
||||
*/
|
||||
|
||||
ns_hooktable_init(NULL);
|
||||
ns_hook_add(NULL, NS_QUERY_RESPOND_BEGIN, &filter_respbegin);
|
||||
ns_hook_add(NULL, NS_QUERY_RESPOND_ANY_FOUND, &filter_respanyfound);
|
||||
ns_hook_add(NULL, NS_QUERY_PREP_RESPONSE_BEGIN, &filter_prepresp);
|
||||
ns_hook_add(NULL, NS_QUERY_DONE_SEND, &filter_donesend);
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <dns/tkey.h>
|
||||
#include <dns/stats.h>
|
||||
|
||||
#include <ns/query.h>
|
||||
#include <ns/server.h>
|
||||
#include <ns/stats.h>
|
||||
|
||||
@ -107,6 +108,11 @@ ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview,
|
||||
|
||||
ISC_LIST_INIT(sctx->altsecrets);
|
||||
|
||||
/*
|
||||
* XXX: temporary.
|
||||
*/
|
||||
ns__query_inithooks();
|
||||
|
||||
sctx->magic = SCTX_MAGIC;
|
||||
*sctxp = sctx;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user