mirror of https://github.com/getdnsapi/getdns.git
Handle DNSSEC policies on the packet/reply level
- All DNSSEC extension add the "dnssec_status" to the reply dicts. - With "dnssec_return_status" and "dnssec_return_only_secure", the "status" in the response dict is GETDNS_RESPSTATUS_NO_NAME when all replies are NXDOMAIN and/or BOGUS. - With "dnssec_return_only_secure", the "status" in the response dict is GETDNS_RESPSTATUS_NO_SECURE_ANSWERS when non of the replies are SECURE, even when all were NXDOMAIN. - When "dnssec_return_validation_chain" is set, besides the validation chain, all replies are returned, even when other DNSSEC extensions are set that would otherwise exclude these replies. This is the only modus were one can observe the "dnssec_status" to be GETDNS_DNSSEC_BOGUS. - When the "dnssec_return_status" extension is set (and "dnssec_return_validation_chain" is not), only non-bogus replies are returned. - When the "dnssec_return_only_secure" extension is set (and "dnssec_return_validation_chain" is not), only secure replies are returned.
This commit is contained in:
parent
bbdf91de9f
commit
8a2e3937c6
|
@ -408,37 +408,12 @@ create_reply_dict(struct getdns_context *context, getdns_network_req * req,
|
|||
struct getdns_dict *subdict = NULL;
|
||||
struct getdns_list *sublist = NULL;
|
||||
char *name = NULL;
|
||||
size_t i;
|
||||
|
||||
/* info (bools) about dns_req */
|
||||
int dnssec_return_status;
|
||||
int dnssec_return_only_secure;
|
||||
int do_dnssec;
|
||||
|
||||
/* info (bool) about network_req */
|
||||
int include_answers;
|
||||
int rrsig_in_answer;
|
||||
|
||||
struct getdns_dict *result = getdns_dict_create_with_context(context);
|
||||
if (!result) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dnssec_return_status = is_extension_set(req->owner->extensions,
|
||||
"dnssec_return_status");
|
||||
dnssec_return_only_secure = is_extension_set(req->owner->extensions,
|
||||
"dnssec_return_only_secure");
|
||||
do_dnssec = ( dnssec_return_status || dnssec_return_only_secure ) &&
|
||||
context->has_ta;
|
||||
dnssec_return_status = dnssec_return_status || dnssec_return_only_secure
|
||||
|| is_extension_set(req->owner->extensions,
|
||||
"dnssec_return_validation_chain");
|
||||
|
||||
include_answers = ! do_dnssec /* No DNSSEC, include answer.*/
|
||||
|| req->secure /* Always include secure answers. */
|
||||
|| (! dnssec_return_only_secure /* And insecure answers (ext.), */
|
||||
&& ! req->bogus); /* unless it is bogus. */
|
||||
|
||||
/* header */
|
||||
do {
|
||||
subdict = create_reply_header_dict(context, reply);
|
||||
|
@ -461,17 +436,7 @@ create_reply_dict(struct getdns_context *context, getdns_network_req * req,
|
|||
|
||||
/* answers */
|
||||
rr_list = ldns_pkt_answer(reply);
|
||||
rrsig_in_answer = 0;
|
||||
for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++)
|
||||
if (LDNS_RR_TYPE_RRSIG ==
|
||||
ldns_rr_get_type(ldns_rr_list_rr(rr_list, i))) {
|
||||
rrsig_in_answer = 1;
|
||||
break;
|
||||
}
|
||||
if (include_answers)
|
||||
sublist = create_list_from_rr_list(context, rr_list);
|
||||
else
|
||||
sublist = getdns_list_create_with_context(context);
|
||||
sublist = create_list_from_rr_list(context, rr_list);
|
||||
|
||||
r = getdns_dict_set_list(result, GETDNS_STR_KEY_ANSWER, sublist);
|
||||
getdns_list_destroy(sublist);
|
||||
|
@ -479,8 +444,7 @@ create_reply_dict(struct getdns_context *context, getdns_network_req * req,
|
|||
break;
|
||||
}
|
||||
|
||||
if (include_answers && just_addrs &&
|
||||
(req->request_type == GETDNS_RRTYPE_A ||
|
||||
if ((req->request_type == GETDNS_RRTYPE_A ||
|
||||
req->request_type == GETDNS_RRTYPE_AAAA)) {
|
||||
/* add to just addrs */
|
||||
r = add_only_addresses(just_addrs, rr_list);
|
||||
|
@ -518,25 +482,14 @@ create_reply_dict(struct getdns_context *context, getdns_network_req * req,
|
|||
}
|
||||
question = ldns_rr_list_rr(ldns_pkt_question(reply), 0);
|
||||
name = convert_rdf_to_str(ldns_rr_owner(question));
|
||||
if (name) {
|
||||
r = getdns_dict_util_set_string(result,
|
||||
GETDNS_STR_KEY_CANONICAL_NM, name);
|
||||
free(name);
|
||||
} else {
|
||||
if (! name) {
|
||||
r = GETDNS_RETURN_MEMORY_ERROR;
|
||||
}
|
||||
if (r != GETDNS_RETURN_GOOD)
|
||||
break;
|
||||
break;
|
||||
}
|
||||
r = getdns_dict_util_set_string(result,
|
||||
GETDNS_STR_KEY_CANONICAL_NM, name);
|
||||
free(name);
|
||||
|
||||
if (! dnssec_return_status)
|
||||
break;
|
||||
|
||||
r = getdns_dict_set_int(result, "dnssec_status",
|
||||
( req->secure ? GETDNS_DNSSEC_SECURE
|
||||
: req->bogus ? GETDNS_DNSSEC_BOGUS
|
||||
: rrsig_in_answer &&
|
||||
context->has_ta ? GETDNS_DNSSEC_INDETERMINATE
|
||||
: GETDNS_DNSSEC_INSECURE ));
|
||||
} while (0);
|
||||
|
||||
if (r != 0) {
|
||||
|
@ -558,6 +511,22 @@ get_canonical_name(const char *name)
|
|||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
rrsigs_in_answer(ldns_pkt *pkt)
|
||||
{
|
||||
ldns_rr_list *rr_list = ldns_pkt_answer(pkt);
|
||||
size_t i;
|
||||
|
||||
if (! rr_list)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++)
|
||||
if (LDNS_RR_TYPE_RRSIG ==
|
||||
ldns_rr_get_type(ldns_rr_list_rr(rr_list, i)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct getdns_dict *
|
||||
create_getdns_response(struct getdns_dns_req * completed_request)
|
||||
{
|
||||
|
@ -567,22 +536,22 @@ create_getdns_response(struct getdns_dns_req * completed_request)
|
|||
struct getdns_list *just_addrs = NULL;
|
||||
struct getdns_list *replies_tree = getdns_list_create_with_context(
|
||||
completed_request->context);
|
||||
getdns_network_req *netreq = completed_request->first_req;
|
||||
getdns_network_req *netreq;
|
||||
char *canonical_name = NULL;
|
||||
getdns_return_t r = 0;
|
||||
int nanswers = 0, all_secure = 1;
|
||||
int nreplies = 0, nanswers = 0, nsecure = 0, ninsecure = 0, nbogus = 0;
|
||||
|
||||
/* info (bools) about dns_req */
|
||||
int dnssec_return_status;
|
||||
int dnssec_return_validation_chain;
|
||||
int dnssec_return_only_secure;
|
||||
int do_dnssec;
|
||||
int dnssec_return_status;
|
||||
|
||||
dnssec_return_status = is_extension_set(
|
||||
completed_request->extensions, "dnssec_return_status");
|
||||
dnssec_return_validation_chain = is_extension_set(
|
||||
completed_request->extensions, "dnssec_return_validation_chain");
|
||||
dnssec_return_only_secure = is_extension_set(
|
||||
completed_request->extensions, "dnssec_return_only_secure");
|
||||
do_dnssec = ( dnssec_return_status || dnssec_return_only_secure ) &&
|
||||
completed_request->context->has_ta;
|
||||
dnssec_return_status = dnssec_return_only_secure || is_extension_set(
|
||||
completed_request->extensions, "dnssec_return_status");
|
||||
|
||||
if (completed_request->first_req->request_class == GETDNS_RRTYPE_A ||
|
||||
completed_request->first_req->request_class ==
|
||||
|
@ -605,13 +574,27 @@ create_getdns_response(struct getdns_dns_req * completed_request)
|
|||
break;
|
||||
}
|
||||
|
||||
while (netreq && r == GETDNS_RETURN_GOOD) {
|
||||
for ( netreq = completed_request->first_req
|
||||
; netreq && r == GETDNS_RETURN_GOOD
|
||||
; netreq = netreq->next ) {
|
||||
|
||||
all_secure = all_secure && netreq->secure;
|
||||
if (ldns_pkt_get_rcode(netreq->result) == LDNS_RCODE_NOERROR &&
|
||||
! (do_dnssec && netreq->bogus))
|
||||
nreplies++;
|
||||
if (netreq->secure)
|
||||
nsecure++;
|
||||
else if (! netreq->bogus)
|
||||
ninsecure++;
|
||||
if (dnssec_return_status && netreq->bogus)
|
||||
nbogus++;
|
||||
else if (LDNS_RCODE_NOERROR ==
|
||||
ldns_pkt_get_rcode(netreq->result))
|
||||
nanswers++;
|
||||
|
||||
if (! dnssec_return_validation_chain) {
|
||||
if (dnssec_return_status && netreq->bogus)
|
||||
continue;
|
||||
else if (dnssec_return_only_secure && ! netreq->secure)
|
||||
continue;
|
||||
}
|
||||
struct getdns_bindata full_data;
|
||||
full_data.data = NULL;
|
||||
full_data.size = 0;
|
||||
|
@ -627,6 +610,25 @@ create_getdns_response(struct getdns_dns_req * completed_request)
|
|||
/* reply tree */
|
||||
struct getdns_dict *reply = create_reply_dict(
|
||||
completed_request->context, netreq, just_addrs);
|
||||
|
||||
if (! reply) {
|
||||
r = GETDNS_RETURN_MEMORY_ERROR;
|
||||
break;
|
||||
}
|
||||
if (dnssec_return_status || dnssec_return_validation_chain) {
|
||||
r = getdns_dict_set_int(reply, "dnssec_status",
|
||||
( netreq->secure ? GETDNS_DNSSEC_SECURE
|
||||
: netreq->bogus ? GETDNS_DNSSEC_BOGUS
|
||||
: rrsigs_in_answer(netreq->result) &&
|
||||
completed_request->context->has_ta
|
||||
? GETDNS_DNSSEC_INDETERMINATE
|
||||
: GETDNS_DNSSEC_INSECURE ));
|
||||
|
||||
if (r != GETDNS_RETURN_GOOD) {
|
||||
getdns_dict_destroy(reply);
|
||||
break;
|
||||
}
|
||||
}
|
||||
r = getdns_list_add_item(replies_tree, &idx);
|
||||
if (r != GETDNS_RETURN_GOOD) {
|
||||
getdns_dict_destroy(reply);
|
||||
|
@ -655,7 +657,6 @@ create_getdns_response(struct getdns_dns_req * completed_request)
|
|||
// break inner while
|
||||
break;
|
||||
}
|
||||
netreq = netreq->next;
|
||||
}
|
||||
|
||||
if (r != GETDNS_RETURN_GOOD)
|
||||
|
@ -679,9 +680,10 @@ create_getdns_response(struct getdns_dns_req * completed_request)
|
|||
}
|
||||
}
|
||||
r = getdns_dict_set_int(result, GETDNS_STR_KEY_STATUS,
|
||||
dnssec_return_only_secure
|
||||
&& ! all_secure ? GETDNS_RESPSTATUS_NO_SECURE_ANSWERS
|
||||
: nanswers == 0 ? GETDNS_RESPSTATUS_NO_NAME
|
||||
nreplies == 0 ? GETDNS_RESPSTATUS_ALL_TIMEOUT :
|
||||
dnssec_return_only_secure && nsecure == 0 && ninsecure > 0
|
||||
? GETDNS_RESPSTATUS_NO_SECURE_ANSWERS :
|
||||
nanswers == 0 ? GETDNS_RESPSTATUS_NO_NAME
|
||||
: GETDNS_RESPSTATUS_GOOD);
|
||||
} while (0);
|
||||
|
||||
|
|
Loading…
Reference in New Issue