The branch, master has been updated via 5a72a2e dns_server: Remove unused handle_question via 6adec93 dns_server: Add handle_authoritative_send() via 3b7f99e dns_server: Add add_dns_res_rec() via b6aaf77 dns_server: Convert "ask_forwarder" params via 4b54e14 dns_server: Simplify array length handling via 3f2cbb6 dns_server: Simplify talloc handling via 9de59c7 dns_server: Consolidate talloc_realloc from 4807577 Fix bug 10881 Wrong keytab permissions when joining additional DC with BIND backend
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 5a72a2ed0d28004d51039313e84047554c0a8f63 Author: Volker Lendecke <v...@samba.org> Date: Tue Aug 11 07:40:50 2015 +0200 dns_server: Remove unused handle_question Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Kai Blin <k...@samba.org> Autobuild-User(master): Kai Blin <k...@samba.org> Autobuild-Date(master): Tue Dec 15 17:50:32 CET 2015 on sn-devel-104 commit 6adec9339dee488e41c7552451eca45ebae4b917 Author: Volker Lendecke <v...@samba.org> Date: Tue Aug 11 07:39:31 2015 +0200 dns_server: Add handle_authoritative_send() An async version of handle_question Bug: https://bugzilla.samba.org/show_bug.cgi?id=9409 Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Kai Blin <k...@samba.org> commit 3b7f99e6f4996cfd97220b3a6d5cceeab6ab5b79 Author: Volker Lendecke <v...@samba.org> Date: Sat Aug 8 14:36:43 2015 +0200 dns_server: Add add_dns_res_rec() Same as add_response_rr(), but it copies over a dns_res_rec Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Kai Blin <k...@samba.org> commit b6aaf77897082c6ac447e9514260b435ac3ad854 Author: Volker Lendecke <v...@samba.org> Date: Sat Aug 8 07:20:26 2015 +0200 dns_server: Convert "ask_forwarder" params Usually we have mem_ctx and ev first when doing a _send function Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Kai Blin <k...@samba.org> commit 4b54e14b7cf456e327b176b365e8471e0899210b Author: Volker Lendecke <v...@samba.org> Date: Sat Aug 8 06:54:11 2015 +0200 dns_server: Simplify array length handling talloc objects carry an implicit length Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Kai Blin <k...@samba.org> commit 3f2cbb616f8b0becf8a3479e72dda11433126e65 Author: Volker Lendecke <v...@samba.org> Date: Sat Aug 8 06:49:16 2015 +0200 dns_server: Simplify talloc handling By making sure that the answers are always allocated, we don't have to pass an explicit mem_ctx anymore Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Kai Blin <k...@samba.org> commit 9de59c7e3f01c578831a8e352ff8e9ee2312c77f Author: Volker Lendecke <v...@samba.org> Date: Fri Aug 7 08:27:19 2015 +0200 dns_server: Consolidate talloc_realloc This puts the talloc_realloc into add_response_rr instead of before create_response_rr. It is a bit less efficient, but as we do not expect hundreds of answers, I think this code is a bit easier to understand. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Kai Blin <k...@samba.org> ----------------------------------------------------------------------- Summary of changes: source4/dns_server/dns_query.c | 531 +++++++++++++++++++++++++++++++++-------- 1 file changed, 425 insertions(+), 106 deletions(-) Changeset truncated at 500 lines: diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c index 956898e..63c219a 100644 --- a/source4/dns_server/dns_query.c +++ b/source4/dns_server/dns_query.c @@ -40,15 +40,27 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_DNS -static WERROR create_response_rr(const char *name, - const struct dnsp_DnssrvRpcRecord *rec, - struct dns_res_rec **answers, uint16_t *ancount) +static WERROR add_response_rr(const char *name, + const struct dnsp_DnssrvRpcRecord *rec, + struct dns_res_rec **answers) { struct dns_res_rec *ans = *answers; - uint16_t ai = *ancount; + uint16_t ai = talloc_array_length(ans); char *tmp; uint32_t i; + if (ai == UINT16_MAX) { + return WERR_BUFFER_OVERFLOW; + } + + /* + * "ans" is always non-NULL and thus its own talloc context + */ + ans = talloc_realloc(ans, ans, struct dns_res_rec, ai+1); + if (ans == NULL) { + return WERR_NOMEM; + } + ZERO_STRUCT(ans[ai]); switch (rec->wType) { @@ -122,10 +134,132 @@ static WERROR create_response_rr(const char *name, ans[ai].rr_class = DNS_QCLASS_IN; ans[ai].ttl = rec->dwTtlSeconds; ans[ai].length = UINT16_MAX; - ai++; *answers = ans; - *ancount = ai; + + return WERR_OK; +} + +static WERROR add_dns_res_rec(struct dns_res_rec **pdst, + const struct dns_res_rec *src) +{ + struct dns_res_rec *dst = *pdst; + uint16_t di = talloc_array_length(dst); + + if (di == UINT16_MAX) { + return WERR_BUFFER_OVERFLOW; + } + + dst = talloc_realloc(dst, dst, struct dns_res_rec, di+1); + if (dst == NULL) { + return WERR_NOMEM; + } + + ZERO_STRUCT(dst[di]); + + dst[di] = (struct dns_res_rec) { + .name = talloc_strdup(dst, src->name), + .rr_type = src->rr_type, + .rr_class = src->rr_class, + .ttl = src->ttl, + .length = src->length + }; + + if (dst[di].name == NULL) { + return WERR_NOMEM; + } + + switch (src->rr_type) { + case DNS_QTYPE_CNAME: + dst[di].rdata.cname_record = talloc_strdup( + dst, src->rdata.cname_record); + if (dst[di].rdata.cname_record == NULL) { + return WERR_NOMEM; + } + break; + case DNS_QTYPE_A: + dst[di].rdata.ipv4_record = talloc_strdup( + dst, src->rdata.ipv4_record); + if (dst[di].rdata.ipv4_record == NULL) { + return WERR_NOMEM; + } + break; + case DNS_QTYPE_AAAA: + dst[di].rdata.ipv6_record = talloc_strdup( + dst, src->rdata.ipv6_record); + if (dst[di].rdata.ipv6_record == NULL) { + return WERR_NOMEM; + } + break; + case DNS_TYPE_NS: + dst[di].rdata.ns_record = talloc_strdup( + dst, src->rdata.ns_record); + if (dst[di].rdata.ns_record == NULL) { + return WERR_NOMEM; + } + break; + case DNS_QTYPE_SRV: + dst[di].rdata.srv_record = (struct dns_srv_record) { + .priority = src->rdata.srv_record.priority, + .weight = src->rdata.srv_record.weight, + .port = src->rdata.srv_record.port, + .target = talloc_strdup( + dst, src->rdata.srv_record.target) + }; + if (dst[di].rdata.srv_record.target == NULL) { + return WERR_NOMEM; + } + break; + case DNS_QTYPE_SOA: + dst[di].rdata.soa_record = (struct dns_soa_record) { + .mname = talloc_strdup( + dst, src->rdata.soa_record.mname), + .rname = talloc_strdup( + dst, src->rdata.soa_record.rname), + .serial = src->rdata.soa_record.serial, + .refresh = src->rdata.soa_record.refresh, + .retry = src->rdata.soa_record.retry, + .expire = src->rdata.soa_record.expire, + .minimum = src->rdata.soa_record.minimum + }; + + if ((dst[di].rdata.soa_record.mname == NULL) || + (dst[di].rdata.soa_record.rname == NULL)) { + return WERR_NOMEM; + } + + break; + case DNS_QTYPE_PTR: + dst[di].rdata.ptr_record = talloc_strdup( + dst, src->rdata.ptr_record); + if (dst[di].rdata.ptr_record == NULL) { + return WERR_NOMEM; + } + break; + case DNS_QTYPE_MX: + dst[di].rdata.mx_record = (struct dns_mx_record) { + .preference = src->rdata.mx_record.preference, + .exchange = talloc_strdup( + src, src->rdata.mx_record.exchange) + }; + + if (dst[di].rdata.mx_record.exchange == NULL) { + return WERR_NOMEM; + } + break; + case DNS_QTYPE_TXT: + dst[di].rdata.txt_record.txt = talloc_strdup( + dst, src->rdata.txt_record.txt); + if (dst[di].rdata.txt_record.txt == NULL) { + return WERR_NOMEM; + } + break; + default: + DBG_WARNING("Got unhandled type %u query.\n", src->rr_type); + return DNS_ERR(NOT_IMPLEMENTED); + } + + *pdst = dst; return WERR_OK; } @@ -139,8 +273,8 @@ struct ask_forwarder_state { static void ask_forwarder_done(struct tevent_req *subreq); static struct tevent_req *ask_forwarder_send( - struct dns_server *dns, TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct dns_server *dns, const char *forwarder, struct dns_name_question *question) { struct tevent_req *req, *subreq; @@ -258,12 +392,12 @@ static WERROR ask_forwarder_recv( static WERROR add_zone_authority_record(struct dns_server *dns, TALLOC_CTX *mem_ctx, const struct dns_name_question *question, - struct dns_res_rec **nsrecs, uint16_t *nscount) + struct dns_res_rec **nsrecs) { const char *zone = NULL; struct dnsp_DnssrvRpcRecord *recs; struct dns_res_rec *ns = *nsrecs; - uint16_t rec_count, ni = *nscount; + uint16_t rec_count; struct ldb_dn *dn = NULL; unsigned int ri; WERROR werror; @@ -281,127 +415,283 @@ static WERROR add_zone_authority_record(struct dns_server *dns, return werror; } - ns = talloc_realloc(mem_ctx, ns, struct dns_res_rec, rec_count + ni); - if (ns == NULL) { - return WERR_NOMEM; - } for (ri = 0; ri < rec_count; ri++) { if (recs[ri].wType == DNS_TYPE_SOA) { - werror = create_response_rr(zone, &recs[ri], &ns, &ni); + werror = add_response_rr(zone, &recs[ri], &ns); if (!W_ERROR_IS_OK(werror)) { return werror; } } } - *nscount = ni; *nsrecs = ns; return WERR_OK; } +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 WERROR handle_question(struct dns_server *dns, - TALLOC_CTX *mem_ctx, - const struct dns_name_question *question, - struct dns_res_rec **answers, uint16_t *ancount, - struct dns_res_rec **nsrecs, uint16_t *nscount) +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 dns_res_rec *ans = *answers; - struct dns_res_rec *ns = *nsrecs; - WERROR werror, werror_return; - unsigned int ri; - struct dnsp_DnssrvRpcRecord *recs; - uint16_t rec_count, ai = *ancount, ni = *nscount; - struct ldb_dn *dn = NULL; + struct tevent_req *req, *subreq; + struct handle_dnsrpcrec_state *state; + struct dns_name_question *new_q; + bool resolve_cname; + WERROR werr; - werror = dns_name2dn(dns, mem_ctx, question->name, &dn); - if (!W_ERROR_IS_OK(werror)) { - return werror; + req = tevent_req_create(mem_ctx, &state, + struct handle_dnsrpcrec_state); + if (req == NULL) { + return NULL; } + state->answers = answers; + state->nsrecs = nsrecs; - werror = dns_lookup_records(dns, mem_ctx, dn, &recs, &rec_count); - if (!W_ERROR_IS_OK(werror)) { - werror_return = werror; - goto done; + 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); } - ans = talloc_realloc(mem_ctx, ans, struct dns_res_rec, rec_count + ai); - if (ans == NULL) { - return WERR_NOMEM; + werr = add_response_rr(question->name, rec, state->answers); + if (tevent_req_werror(req, werr)) { + return tevent_req_post(req, ev); } - /* Set up for an NXDOMAIN reply if no match is found */ - werror_return = DNS_ERR(NAME_ERROR); + new_q = talloc(state, struct dns_name_question); + if (tevent_req_nomem(new_q, req)) { + return tevent_req_post(req, ev); + } - for (ri = 0; ri < rec_count; ri++) { - if ((recs[ri].wType == DNS_TYPE_CNAME) && - ((question->question_type == DNS_QTYPE_A) || - (question->question_type == DNS_QTYPE_AAAA))) { - struct dns_name_question *new_q = - talloc(mem_ctx, struct dns_name_question); + *new_q = (struct dns_name_question) { + .question_type = question->question_type, + .question_class = question->question_class, + .name = rec->data.cname + }; - if (new_q == NULL) { - return WERR_NOMEM; - } + 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; + } - /* We reply with one more record, so grow the array */ - ans = talloc_realloc(mem_ctx, ans, struct dns_res_rec, - rec_count + 1); - if (ans == NULL) { - TALLOC_FREE(new_q); - return WERR_NOMEM; - } + 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); - /* First put in the CNAME record */ - werror = create_response_rr(question->name, &recs[ri], &ans, &ai); - if (!W_ERROR_IS_OK(werror)) { - TALLOC_FREE(new_q); - return werror; - } + return req; +} - /* And then look up the name it points at.. */ +static void handle_dnsrpcrec_gotauth(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + WERROR werr; - /* First build up the new question */ - new_q->question_type = question->question_type; - new_q->question_class = question->question_class; - new_q->name = talloc_strdup(new_q, recs[ri].data.cname); - if (new_q->name == NULL) { - TALLOC_FREE(new_q); - return WERR_NOMEM; - } - /* and then call the lookup again */ - werror = handle_question(dns, mem_ctx, new_q, &ans, &ai, &ns, &ni); - if (!W_ERROR_IS_OK(werror)) { - goto done; - } - werror_return = WERR_OK; + 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; + } - continue; + for (i=0; i<ancount; i++) { + werr = add_dns_res_rec(state->answers, &answers[i]); + if (tevent_req_werror(req, werr)) { + return; } - if ((question->question_type != DNS_QTYPE_ALL) && - (recs[ri].wType != (enum dns_record_type) question->question_type)) { - werror_return = WERR_OK; - continue; - } - werror = create_response_rr(question->name, &recs[ri], &ans, &ai); - if (!W_ERROR_IS_OK(werror)) { - return werror; + } + + for (i=0; i<nscount; i++) { + werr = add_dns_res_rec(state->nsrecs, &nsrecs[i]); + if (tevent_req_werror(req, werr)) { + return; } - werror_return = WERR_OK; } -done: - /* Always add an authority record to replies we should know about */ - add_zone_authority_record(dns, mem_ctx, question, &ns, &ni); + tevent_req_done(req); +} - *ancount = ai; - *answers = ans; - *nscount = ni; - *nsrecs = ns; +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); -- Samba Shared Repository