Commit 312e874d authored by Marek Vavruša's avatar Marek Vavruša

lib/resolve: correct edns0 handling for clients

the server responds with edns0 if the client requests it,
it also uses DNSSEC for queries if DO=1

the obtained records are not however validated
parent 5d666b04
......@@ -345,31 +345,12 @@ static int begin(knot_layer_t *ctx, void *module_param)
return reset(ctx);
}
static int prepare_additionals(knot_pkt_t *pkt)
{
knot_rrset_t opt_rr;
int ret = knot_edns_init(&opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, &pkt->mm);
if (ret != KNOT_EOK) {
return ret;
}
knot_pkt_begin(pkt, KNOT_ADDITIONAL);
ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, &opt_rr, KNOT_PF_FREE);
if (ret != KNOT_EOK) {
knot_rrset_clear(&opt_rr, &pkt->mm);
return ret;
}
return kr_ok();
}
static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt)
{
assert(pkt && ctx);
struct kr_request *req = ctx->data;
struct kr_query *query = kr_rplan_current(&req->rplan);
if (query == NULL || ctx->state == KNOT_STATE_DONE) {
assert(0);
if (!query || ctx->state & (KNOT_STATE_DONE|KNOT_STATE_FAIL)) {
return ctx->state;
}
......@@ -384,18 +365,9 @@ static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt)
return KNOT_STATE_FAIL;
}
/* Query built, expect answer. */
query->id = isaac_next_uint(&ISAAC, UINT16_MAX);
knot_wire_set_id(pkt->wire, query->id);
/* Declare EDNS0 support. */
if (!(query->flags & QUERY_SAFEMODE)) {
ret = prepare_additionals(pkt);
if (ret != 0) {
return KNOT_STATE_FAIL;
}
}
/* Query built, expect answer. */
return KNOT_STATE_CONSUME;
}
......
......@@ -131,6 +131,78 @@ static int sendrecv(struct sockaddr *addr, int proto, const knot_pkt_t *query, k
return knot_pkt_parse(resp, 0);
}
static int edns_put(knot_pkt_t *pkt)
{
/* Reclaim reserved size. */
int ret = knot_pkt_reclaim(pkt, knot_edns_wire_size(pkt->opt_rr));
if (ret != 0) {
return ret;
}
/* Write to packet. */
assert(pkt->current == KNOT_ADDITIONAL);
return knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, pkt->opt_rr, KNOT_PF_FREE);
}
static int edns_create(knot_pkt_t *pkt, knot_pkt_t *template)
{
/* Create empty OPT RR */
pkt->opt_rr = mm_alloc(&pkt->mm, sizeof(*pkt->opt_rr));
if (!pkt->opt_rr) {
return kr_error(ENOMEM);
}
int ret = knot_edns_init(pkt->opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, &pkt->mm);
if (ret != 0) {
return ret;
}
/* Set DO bit if set (DNSSEC requested). */
if (knot_pkt_has_dnssec(template)) {
knot_edns_set_do(pkt->opt_rr);
}
return knot_pkt_reserve(pkt, knot_edns_wire_size(pkt->opt_rr));
}
static int answer_prepare(knot_pkt_t *answer, knot_pkt_t *query)
{
if (!knot_wire_get_rd(query->wire)) {
return kr_error(ENOSYS); /* Only recursive service */
}
if (knot_pkt_init_response(answer, query) != 0) {
return kr_error(ENOMEM); /* Failed to initialize answer */
}
/* Handle EDNS in the query */
if (knot_pkt_has_edns(query)) {
int ret = edns_create(answer, query);
if (ret != 0){
return ret;
}
}
return kr_ok();
}
static int answer_finalize(knot_pkt_t *answer)
{
knot_pkt_begin(answer, KNOT_ADDITIONAL);
if (answer->opt_rr) {
return edns_put(answer);
}
return kr_ok();
}
static int query_finalize(struct kr_request *request, knot_pkt_t *pkt)
{
int ret = 0;
struct kr_query *qry = kr_rplan_current(&request->rplan);
knot_pkt_begin(pkt, KNOT_ADDITIONAL);
if (!(qry->flags & QUERY_SAFEMODE)) {
ret = edns_create(pkt, request->answer);
if (ret == 0) {
ret = edns_put(pkt);
}
}
return ret;
}
int kr_resolve(struct kr_context* ctx, knot_pkt_t *answer,
const knot_dname_t *qname, uint16_t qclass, uint16_t qtype)
{
......@@ -155,7 +227,6 @@ int kr_resolve(struct kr_context* ctx, knot_pkt_t *answer,
#ifndef NDEBUG
struct kr_rplan *rplan = &request.rplan; /* for DEBUG_MSG */
#endif
/* Resolve query, iteratively */
int proto = 0;
struct sockaddr *addr = NULL;
......@@ -188,7 +259,6 @@ int kr_resolve(struct kr_context* ctx, knot_pkt_t *answer,
return state == KNOT_STATE_DONE ? 0 : kr_error(EIO);
}
int kr_resolve_begin(struct kr_request *request, struct kr_context *ctx, knot_pkt_t *answer)
{
/* Initialize request */
......@@ -228,12 +298,10 @@ int kr_resolve_consume(struct kr_request *request, knot_pkt_t *packet)
/* Empty resolution plan, push packet as the new query */
if (packet && kr_rplan_empty(rplan)) {
if (!knot_wire_get_rd(packet->wire)) {
return KNOT_STATE_FAIL;
}
if (knot_pkt_init_response(request->answer, packet) != 0) {
if (answer_prepare(request->answer, packet) != 0) {
return KNOT_STATE_FAIL;
}
/* Start query resolution */
const knot_dname_t *qname = knot_pkt_qname(packet);
uint16_t qclass = knot_pkt_qclass(packet);
uint16_t qtype = knot_pkt_qtype(packet);
......@@ -324,7 +392,11 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t
DEBUG_MSG("=> querying: '%s' zone cut: '%s' m12n: '%s'\n", ns_str, zonecut_str, qname_str);
#endif
/* Issue dependent query to this address */
/* Prepare additional query */
int ret = query_finalize(request, packet);
if (ret != 0) {
return KNOT_STATE_FAIL;
}
*dst = &qry->ns.addr.ip;
*type = (qry->flags & QUERY_TCP) ? SOCK_STREAM : SOCK_DGRAM;
return state;
......@@ -336,6 +408,10 @@ int kr_resolve_finish(struct kr_request *request, int state)
struct kr_rplan *rplan = &request->rplan;
DEBUG_MSG("finished: %d, mempool: %zu B\n", state, (size_t) mp_total_size(request->pool.ctx));
#endif
/* Finalize answer */
if (answer_finalize(request->answer) != 0) {
state = KNOT_STATE_FAIL;
}
/* Error during procesing, internal failure */
if (state != KNOT_STATE_DONE) {
knot_pkt_t *answer = request->answer;
......@@ -343,7 +419,6 @@ int kr_resolve_finish(struct kr_request *request, int state)
knot_wire_set_rcode(answer->wire, KNOT_RCODE_SERVFAIL);
}
}
/* Clean up. */
knot_overlay_deinit(&request->overlay);
request->overlay.state = KNOT_STATE_NOOP;
......
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