diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c index 4e5382582a4..e46e68bbe49 100644 --- a/source4/dns_server/dns_query.c +++ b/source4/dns_server/dns_query.c @@ -520,6 +520,271 @@ done: return werror_return; } +static struct tevent_req *handle_authoritative_send( + TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct dns_server *dns, const char *forwarder, + struct dns_name_question *question, + struct dns_res_rec **answers, struct dns_res_rec **nsrecs); +static WERROR handle_authoritative_recv(struct tevent_req *req); + +struct handle_dnsrpcrec_state { + struct dns_res_rec **answers; + struct dns_res_rec **nsrecs; +}; + +static void handle_dnsrpcrec_gotauth(struct tevent_req *subreq); +static void handle_dnsrpcrec_gotforwarded(struct tevent_req *subreq); + +static struct tevent_req *handle_dnsrpcrec_send( + TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct dns_server *dns, const char *forwarder, + const struct dns_name_question *question, + struct dnsp_DnssrvRpcRecord *rec, + struct dns_res_rec **answers, struct dns_res_rec **nsrecs) +{ + struct tevent_req *req, *subreq; + struct handle_dnsrpcrec_state *state; + struct dns_name_question *new_q; + bool resolve_cname; + WERROR werr; + + req = tevent_req_create(mem_ctx, &state, + struct handle_dnsrpcrec_state); + if (req == NULL) { + return NULL; + } + state->answers = answers; + state->nsrecs = nsrecs; + + resolve_cname = ((rec->wType == DNS_TYPE_CNAME) && + ((question->question_type == DNS_QTYPE_A) || + (question->question_type == DNS_QTYPE_AAAA))); + + if (!resolve_cname) { + if ((question->question_type != DNS_QTYPE_ALL) && + (rec->wType != + (enum dns_record_type) question->question_type)) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + werr = add_response_rr(question->name, rec, state->answers); + if (tevent_req_werror(req, werr)) { + return tevent_req_post(req, ev); + } + + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + werr = add_response_rr(question->name, rec, state->answers); + if (tevent_req_werror(req, werr)) { + return tevent_req_post(req, ev); + } + + new_q = talloc(state, struct dns_name_question); + if (tevent_req_nomem(new_q, req)) { + return tevent_req_post(req, ev); + } + + *new_q = (struct dns_name_question) { + .question_type = question->question_type, + .question_class = question->question_class, + .name = rec->data.cname + }; + + if (dns_authorative_for_zone(dns, new_q->name)) { + subreq = handle_authoritative_send( + state, ev, dns, forwarder, new_q, + state->answers, state->nsrecs); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, handle_dnsrpcrec_gotauth, req); + return req; + } + + subreq = ask_forwarder_send(state, ev, dns, forwarder, new_q); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, handle_dnsrpcrec_gotforwarded, req); + + return req; +} + +static void handle_dnsrpcrec_gotauth(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + WERROR werr; + + werr = handle_authoritative_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_werror(req, werr)) { + return; + } + tevent_req_done(req); +} + +static void handle_dnsrpcrec_gotforwarded(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct handle_dnsrpcrec_state *state = tevent_req_data( + req, struct handle_dnsrpcrec_state); + struct dns_res_rec *answers, *nsrecs, *additional; + uint16_t ancount = 0; + uint16_t nscount = 0; + uint16_t arcount = 0; + uint16_t i; + WERROR werr; + + werr = ask_forwarder_recv(subreq, state, &answers, &ancount, + &nsrecs, &nscount, &additional, &arcount); + if (tevent_req_werror(req, werr)) { + return; + } + + for (i=0; ianswers, &answers[i]); + if (tevent_req_werror(req, werr)) { + return; + } + } + + for (i=0; insrecs, &nsrecs[i]); + if (tevent_req_werror(req, werr)) { + return; + } + } + + tevent_req_done(req); +} + +static WERROR handle_dnsrpcrec_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_werror(req); +} + +struct handle_authoritative_state { + struct tevent_context *ev; + struct dns_server *dns; + struct dns_name_question *question; + const char *forwarder; + + struct dnsp_DnssrvRpcRecord *recs; + uint16_t rec_count; + uint16_t recs_done; + + struct dns_res_rec **answers; + struct dns_res_rec **nsrecs; +}; + +static void handle_authoritative_done(struct tevent_req *subreq); + +static struct tevent_req *handle_authoritative_send( + TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct dns_server *dns, const char *forwarder, + struct dns_name_question *question, + struct dns_res_rec **answers, struct dns_res_rec **nsrecs) +{ + struct tevent_req *req, *subreq; + struct handle_authoritative_state *state; + struct ldb_dn *dn = NULL; + WERROR werr; + + req = tevent_req_create(mem_ctx, &state, + struct handle_authoritative_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->dns = dns; + state->question = question; + state->forwarder = forwarder; + state->answers = answers; + state->nsrecs = nsrecs; + + werr = dns_name2dn(dns, state, question->name, &dn); + if (tevent_req_werror(req, werr)) { + return tevent_req_post(req, ev); + } + + werr = dns_lookup_records(dns, state, dn, &state->recs, + &state->rec_count); + TALLOC_FREE(dn); + if (tevent_req_werror(req, werr)) { + return tevent_req_post(req, ev); + } + + if (state->rec_count == 0) { + tevent_req_werror(req, DNS_ERR(NAME_ERROR)); + return tevent_req_post(req, ev); + } + + subreq = handle_dnsrpcrec_send( + state, state->ev, state->dns, state->forwarder, + state->question, &state->recs[state->recs_done], + state->answers, state->nsrecs); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, handle_authoritative_done, req); + return req; +} + +static void handle_authoritative_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct handle_authoritative_state *state = tevent_req_data( + req, struct handle_authoritative_state); + WERROR werr; + + werr = handle_dnsrpcrec_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_werror(req, werr)) { + return; + } + + state->recs_done += 1; + + if (state->recs_done == state->rec_count) { + tevent_req_done(req); + return; + } + + subreq = handle_dnsrpcrec_send( + state, state->ev, state->dns, state->forwarder, + state->question, &state->recs[state->recs_done], + state->answers, state->nsrecs); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, handle_authoritative_done, req); +} + +static WERROR handle_authoritative_recv(struct tevent_req *req) +{ + struct handle_authoritative_state *state = tevent_req_data( + req, struct handle_authoritative_state); + WERROR werr; + + if (tevent_req_is_werror(req, &werr)) { + return werr; + } + + werr = add_zone_authority_record(state->dns, state, state->question, + state->nsrecs); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + return WERR_OK; +} + static NTSTATUS create_tkey(struct dns_server *dns, const char* name, const char* algorithm, @@ -747,6 +1012,7 @@ struct dns_server_process_query_state { uint16_t arcount; }; +static void dns_server_process_query_got_auth(struct tevent_req *subreq); static void dns_server_process_query_got_response(struct tevent_req *subreq); struct tevent_req *dns_server_process_query_send( @@ -786,7 +1052,6 @@ struct tevent_req *dns_server_process_query_send( } if (dns_authorative_for_zone(dns, in->questions[0].name)) { - WERROR err; req_state->flags |= DNS_FLAG_AUTHORITATIVE; @@ -804,22 +1069,15 @@ struct tevent_req *dns_server_process_query_send( return tevent_req_post(req, ev); } - err = handle_question(dns, state, &in->questions[0], - &state->answers, &state->nsrecs); - - if (W_ERROR_EQUAL(err, DNS_ERR(NAME_ERROR))) { - err = WERR_OK; - } - - if (tevent_req_werror(req, err)) { + subreq = handle_authoritative_send( + state, ev, dns, lpcfg_dns_forwarder(dns->task->lp_ctx), + &in->questions[0], &state->answers, &state->nsrecs); + if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } - - state->ancount = talloc_array_length(state->answers); - state->nscount = talloc_array_length(state->nsrecs); - - tevent_req_done(req); - return tevent_req_post(req, ev); + tevent_req_set_callback( + subreq, dns_server_process_query_got_auth, req); + return req; } if ((req_state->flags & DNS_FLAG_RECURSION_DESIRED) && @@ -861,6 +1119,26 @@ static void dns_server_process_query_got_response(struct tevent_req *subreq) tevent_req_done(req); } +static void dns_server_process_query_got_auth(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct dns_server_process_query_state *state = tevent_req_data( + req, struct dns_server_process_query_state); + WERROR werr; + + werr = handle_authoritative_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_werror(req, werr)) { + return; + } + state->ancount = talloc_array_length(state->answers); + state->nscount = talloc_array_length(state->nsrecs); + state->arcount = talloc_array_length(state->additional); + + tevent_req_done(req); +} + WERROR dns_server_process_query_recv( struct tevent_req *req, TALLOC_CTX *mem_ctx, struct dns_res_rec **answers, uint16_t *ancount,