Commit 3846cc78 authored by Grigorii Demidov's avatar Grigorii Demidov Committed by Marek Vavrusa

lib/resolve: empty final answer when SERVFAIL

parent db9b2213
......@@ -337,43 +337,62 @@ static void write_extra_records(rr_array_t *arr, knot_pkt_t *answer)
}
}
static int answer_fail(knot_pkt_t *answer)
{
int ret = kr_pkt_clear_payload(answer);
knot_wire_clear_ad(answer->wire);
knot_wire_clear_aa(answer->wire);
knot_wire_set_rcode(answer->wire, KNOT_RCODE_SERVFAIL);
if (ret == 0 && answer->opt_rr) {
/* OPT in SERVFAIL response is still useful for cookies/additional info. */
knot_pkt_begin(answer, KNOT_ADDITIONAL);
ret = edns_put(answer);
}
return ret;
}
static int answer_finalize(struct kr_request *request, int state)
{
/* Write authority records. */
struct kr_rplan *rplan = &request->rplan;
knot_pkt_t *answer = request->answer;
if (answer->current < KNOT_AUTHORITY)
/* Always set SERVFAIL for bogus answers. */
if (state == KNOT_STATE_FAIL && rplan->pending.len > 0) {
struct kr_query *last = array_tail(rplan->pending);
if ((last->flags & QUERY_DNSSEC_WANT) && (last->flags & QUERY_DNSSEC_BOGUS)) {
return answer_fail(answer);
}
}
/* Write authority records. */
if (answer->current < KNOT_AUTHORITY) {
knot_pkt_begin(answer, KNOT_AUTHORITY);
}
write_extra_records(&request->authority, answer);
/* Write additional records. */
knot_pkt_begin(answer, KNOT_ADDITIONAL);
write_extra_records(&request->additional, answer);
/* Write EDNS information */
int ret = 0;
if (answer->opt_rr) {
int ret = edns_put(answer);
if (ret != 0) {
return ret;
}
}
struct kr_rplan *rplan = &request->rplan;
/* Always set SERVFAIL for bogus answers. */
if (state == KNOT_STATE_FAIL && rplan->pending.len > 0) {
struct kr_query *last = array_tail(rplan->pending);
if ((last->flags & QUERY_DNSSEC_WANT) && (last->flags & QUERY_DNSSEC_BOGUS)) {
knot_wire_set_rcode(answer->wire,KNOT_RCODE_SERVFAIL);
}
knot_pkt_begin(answer, KNOT_ADDITIONAL);
ret = edns_put(answer);
}
/* Set AD=1 if succeeded and requested secured answer. */
const bool has_ad = knot_wire_get_ad(answer->wire);
knot_wire_clear_ad(answer->wire);
if (state == KNOT_STATE_DONE && rplan->resolved.len > 0) {
struct kr_query *last = array_tail(rplan->resolved);
/* Do not set AD for RRSIG query, as we can't validate it. */
const bool secure = (last->flags & QUERY_DNSSEC_WANT) && !(last->flags & QUERY_DNSSEC_INSECURE);
const bool secure = (last->flags & QUERY_DNSSEC_WANT) &&
!(last->flags & QUERY_DNSSEC_INSECURE);
if (has_ad && secure && knot_pkt_qtype(answer) != KNOT_RRTYPE_RRSIG) {
knot_wire_set_ad(answer->wire);
}
}
return kr_ok();
return ret;
}
static int query_finalize(struct kr_request *request, struct kr_query *qry, knot_pkt_t *pkt)
......
......@@ -208,6 +208,22 @@ int kr_pkt_recycle(knot_pkt_t *pkt)
return knot_pkt_parse_question(pkt);
}
int kr_pkt_clear_payload(knot_pkt_t *pkt)
{
pkt->rrset_count = 0;
pkt->size = KNOT_WIRE_HEADER_SIZE + pkt->qname_size +
2 * sizeof(uint16_t); /* QTYPE + QCLASS */
pkt->parsed = KNOT_WIRE_HEADER_SIZE;
pkt->current = KNOT_ANSWER;
knot_wire_set_ancount(pkt->wire, 0);
knot_wire_set_nscount(pkt->wire, 0);
knot_wire_set_arcount(pkt->wire, 0);
memset(&pkt->sections[KNOT_ANSWER], 0, sizeof(knot_pktsection_t) *
(KNOT_PKT_SECTIONS - (KNOT_ANSWER + 1)));
knot_pkt_begin(pkt, KNOT_ANSWER);
return knot_pkt_parse_question(pkt);
}
int kr_pkt_put(knot_pkt_t *pkt, const knot_dname_t *name, uint32_t ttl,
uint16_t rclass, uint16_t rtype, const uint8_t *rdata, uint16_t rdlen)
{
......
......@@ -103,6 +103,10 @@ int kr_memreserve(void *baton, char **mem, size_t elm_size, size_t want, size_t
KR_EXPORT
int kr_pkt_recycle(knot_pkt_t *pkt);
/** @internal Clear packet payload. */
KR_EXPORT
int kr_pkt_clear_payload(knot_pkt_t *pkt);
/** Construct and put record to packet. */
KR_EXPORT
int kr_pkt_put(knot_pkt_t *pkt, const knot_dname_t *name, uint32_t ttl,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment