diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 0e1c40393..0f22d9655 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -520,6 +520,57 @@ fill_res(struct ub_result* res, struct ub_packed_rrset_key* answer, return 1; } +/** fill authority_data into result */ +static int +fill_res_authority(struct ub_result* res, struct ub_packed_rrset_key* answer, + struct query_info* rq, struct reply_info* rep) +{ + size_t i; + struct packed_rrset_data* authority_data; + res->authority_ttl = 0; + if(!answer) { + if(rep->rrset_count != 0) + res->authority_ttl = (int)rep->ttl; + res->authority_data = (char**)calloc(1, sizeof(char*)); + res->authority_len = (int*)calloc(1, sizeof(int)); + return (res->authority_data && res->authority_len); + } + authority_data = (struct packed_rrset_data*)answer->entry.data; + if(query_dname_compare(rq->qname, answer->rk.dname) != 0) { + if(!fill_canon(res, answer->rk.dname)) + return 0; /* out of memory */ + } else res->canonname = NULL; + res->authority_data = (char**)calloc(authority_data->count+1, sizeof(char*)); + res->authority_len = (int*)calloc(authority_data->count+1, sizeof(int)); + if(!res->authority_data || !res->authority_len) + return 0; /* out of memory */ + for(i=0; icount; i++) { + /* remove rdauthority_length from rauthority_data */ + res->authority_len[i] = (int)(authority_data->rr_len[i] - 2); + res->authority_data[i] = memdup(authority_data->rr_data[i]+2, (size_t)res->authority_len[i]); + if(!res->authority_data[i]) + return 0; /* out of memory */ + } + /* authority_ttl for positive answers, from CNAME and answer RRs */ + if(authority_data->count != 0) { + size_t j; + res->authority_ttl = (int)authority_data->ttl; + for(j=0; jns_numrrsets; j++) { + struct packed_rrset_data* d = + (struct packed_rrset_data*)rep->rrsets[rep->an_numrrsets + j]-> + entry.data; + if((int)d->ttl < res->authority_ttl) + res->authority_ttl = (int)d->ttl; + } + } + /* authority_ttl for negative answers */ + if(authority_data->count == 0 && rep->rrset_count != 0) + res->authority_ttl = (int)rep->ttl; + res->authority_data[authority_data->count] = NULL; + res->authority_len[authority_data->count] = 0; + return 1; +} + /** fill result from parsed message, on error fills servfail */ void libworker_enter_result(struct ub_result* res, sldns_buffer* buf, @@ -533,6 +584,10 @@ libworker_enter_result(struct ub_result* res, sldns_buffer* buf, log_err("cannot parse buf"); return; /* error parsing buf, or out of memory */ } + struct ub_packed_rrset_key *authority_rrset = reply_find_rrset_section_ns(rep, rq.qname, rq.qname_len, rq.qtype, rq.qclass); + if(!fill_res_authority(res, authority_rrset, &rq, rep)) + return; /* out of memory */ + if(!fill_res(res, reply_find_answer_rrset(&rq, rep), reply_find_final_cname_target(&rq, rep), &rq, rep)) return; /* out of memory */ diff --git a/libunbound/unbound.h b/libunbound/unbound.h index bb8e8acf0..6723ad8f7 100644 --- a/libunbound/unbound.h +++ b/libunbound/unbound.h @@ -136,9 +136,20 @@ struct ub_result { */ char** data; + /** + * a list of network order DNS rdata items, terminated with a + * NULL pointer, so that authority_data[0] is the first result entry, + * data[1] the second, and the last entry is NULL. + * If there was no data, authority_data[0] is NULL. + */ + char** authority_data; + /** the length in bytes of the data items, len[i] for data[i] */ int* len; + /** the length in bytes of the authority_data items, authority_len[i] for autority_data[i] */ + int* authority_len; + /** * canonical name for the result (the final cname). * zero terminated string. @@ -215,6 +226,12 @@ struct ub_result { * you also cannot trust this value. */ int ttl; + + /** + * TTL for the authority results, in seconds. If the security is bogus, then + * you also cannot trust this value. + */ + int authority_ttl; }; /**