From fb7fc8a853161355e2f56e9fdf1e5e7230512d5d Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Wed, 29 Oct 2014 13:35:36 +0100 Subject: [PATCH 1/5] dns: Add dns_get_authoritative_zone helper function Signed-off-by: Kai Blin Reviewed-by: Andreas Schneider --- source4/dns_server/dns_server.h | 2 ++ source4/dns_server/dns_utils.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/source4/dns_server/dns_server.h b/source4/dns_server/dns_server.h index 3423ee0..64b716a 100644 --- a/source4/dns_server/dns_server.h +++ b/source4/dns_server/dns_server.h @@ -93,6 +93,8 @@ bool dns_records_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2); bool dns_authorative_for_zone(struct dns_server *dns, const char *name); +const char *dns_get_authoritative_zone(struct dns_server *dns, + const char *name); WERROR dns_lookup_records(struct dns_server *dns, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, diff --git a/source4/dns_server/dns_utils.c b/source4/dns_server/dns_utils.c index c757c15..28412eb 100644 --- a/source4/dns_server/dns_utils.c +++ b/source4/dns_server/dns_utils.c @@ -199,6 +199,22 @@ bool dns_authorative_for_zone(struct dns_server *dns, return true; } +const char *dns_get_authoritative_zone(struct dns_server *dns, + const char *name) +{ + const struct dns_server_zone *z; + size_t host_part_len = 0; + + for (z = dns->zones; z != NULL; z = z->next) { + bool match; + match = dns_name_match(z->name, name, &host_part_len); + if (match) { + return z->name; + } + } + return NULL; +} + WERROR dns_name2dn(struct dns_server *dns, TALLOC_CTX *mem_ctx, const char *name, -- 1.9.1 From 4b58f29fd5f671716efa158cd898f2b475f8ab96 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Wed, 29 Oct 2014 13:36:58 +0100 Subject: [PATCH 2/5] dns: Just pass the name to create_response_rr Signed-off-by: Kai Blin Reviewed-by: Andreas Schneider --- source4/dns_server/dns_query.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c index 3cafc23..b510ccc 100644 --- a/source4/dns_server/dns_query.c +++ b/source4/dns_server/dns_query.c @@ -40,7 +40,7 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_DNS -static WERROR create_response_rr(const struct dns_name_question *question, +static WERROR create_response_rr(const char *name, const struct dnsp_DnssrvRpcRecord *rec, struct dns_res_rec **answers, uint16_t *ancount) { @@ -116,7 +116,7 @@ static WERROR create_response_rr(const struct dns_name_question *question, return DNS_ERR(NOT_IMPLEMENTED); } - ans[ai].name = talloc_strdup(ans, question->name); + ans[ai].name = talloc_strdup(ans, name); W_ERROR_HAVE_NO_MEMORY(ans[ai].name); ans[ai].rr_type = rec->wType; ans[ai].rr_class = DNS_QCLASS_IN; @@ -299,7 +299,7 @@ static WERROR handle_question(struct dns_server *dns, } /* First put in the CNAME record */ - werror = create_response_rr(question, &recs[ri], &ans, &ai); + werror = create_response_rr(question->name, &recs[ri], &ans, &ai); if (!W_ERROR_IS_OK(werror)) { return werror; } @@ -329,7 +329,7 @@ static WERROR handle_question(struct dns_server *dns, werror_return = WERR_OK; continue; } - werror = create_response_rr(question, &recs[ri], &ans, &ai); + werror = create_response_rr(question->name, &recs[ri], &ans, &ai); if (!W_ERROR_IS_OK(werror)) { return werror; } -- 1.9.1 From 78c21c3af0c50b8fda90d8aa3d087917a40a00e9 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Wed, 29 Oct 2014 13:39:16 +0100 Subject: [PATCH 3/5] dns: Also pass nsrecs to handle_question() Signed-off-by: Kai Blin Reviewed-by: Andreas Schneider --- source4/dns_server/dns_query.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c index b510ccc..aa79f1f 100644 --- a/source4/dns_server/dns_query.c +++ b/source4/dns_server/dns_query.c @@ -256,13 +256,15 @@ static WERROR ask_forwarder_recv( 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 **answers, uint16_t *ancount, + struct dns_res_rec **nsrecs, uint16_t *nscount) { 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; + uint16_t rec_count, ai = *ancount, ni = *nscount; struct ldb_dn *dn = NULL; werror = dns_name2dn(dns, mem_ctx, question->name, &dn); @@ -315,7 +317,7 @@ static WERROR handle_question(struct dns_server *dns, return WERR_NOMEM; } /* and then call the lookup again */ - werror = handle_question(dns, mem_ctx, new_q, &ans, &ai); + werror = handle_question(dns, mem_ctx, new_q, &ans, &ai, &ns, &ni); if (!W_ERROR_IS_OK(werror)) { return werror; } @@ -336,8 +338,11 @@ static WERROR handle_question(struct dns_server *dns, werror_return = WERR_OK; } +done: *ancount = ai; *answers = ans; + *nscount = ni; + *nsrecs = ns; return werror_return; } @@ -612,7 +617,8 @@ struct tevent_req *dns_server_process_query_send( req_state->flags |= DNS_FLAG_AUTHORITATIVE; err = handle_question(dns, state, &in->questions[0], - &state->answers, &state->ancount); + &state->answers, &state->ancount, + &state->nsrecs, &state->nscount); if (tevent_req_werror(req, err)) { return tevent_req_post(req, ev); } -- 1.9.1 From 40ef640cb56d7cb17bf24ba2db401577550fec60 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Wed, 29 Oct 2014 13:41:53 +0100 Subject: [PATCH 4/5] dns: Add a SOA record to error replies Signed-off-by: Kai Blin Reviewed-by: Andreas Schneider --- source4/dns_server/dns_query.c | 52 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c index aa79f1f..8ff48a5 100644 --- a/source4/dns_server/dns_query.c +++ b/source4/dns_server/dns_query.c @@ -253,6 +253,52 @@ static WERROR ask_forwarder_recv( return WERR_OK; } +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) +{ + const char *zone = NULL; + struct dnsp_DnssrvRpcRecord *recs; + struct dns_res_rec *ns = *nsrecs; + uint16_t rec_count, ni = *nscount; + struct ldb_dn *dn = NULL; + unsigned int ri; + WERROR werror; + + zone = dns_get_authoritative_zone(dns, question->name); + DEBUG(10, ("Creating zone authority record for '%s'\n", zone)); + + werror = dns_name2dn(dns, mem_ctx, zone, &dn); + if (!W_ERROR_IS_OK(werror)) { + return werror; + } + + werror = dns_lookup_records(dns, mem_ctx, dn, &recs, &rec_count); + if (!W_ERROR_IS_OK(werror)) { + 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); + if (!W_ERROR_IS_OK(werror)) { + return werror; + } + } + } + + *nscount = ni; + *nsrecs = ns; + + return WERR_OK; +} + + static WERROR handle_question(struct dns_server *dns, TALLOC_CTX *mem_ctx, const struct dns_name_question *question, @@ -271,7 +317,11 @@ static WERROR handle_question(struct dns_server *dns, W_ERROR_NOT_OK_RETURN(werror); werror = dns_lookup_records(dns, mem_ctx, dn, &recs, &rec_count); - W_ERROR_NOT_OK_RETURN(werror); + if (!W_ERROR_IS_OK(werror)) { + werror_return = werror; + add_zone_authority_record(dns, mem_ctx, question, &ns, &ni); + goto done; + } ans = talloc_realloc(mem_ctx, ans, struct dns_res_rec, rec_count + ai); if (ans == NULL) { -- 1.9.1 From a98a773404fa06bed322d5f98c2c4c10f95cc3d3 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Fri, 17 Jul 2015 15:27:51 +0200 Subject: [PATCH 5/5] dns: always add authority records Signed-off-by: Kai Blin Reviewed-by: Andreas Schneider --- python/samba/tests/dns.py | 34 +++++++++++++++++----------------- source4/dns_server/dns_query.c | 24 +++++++++++++++++------- source4/dns_server/dns_server.c | 6 +++++- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py index 04ac356..044eaf6 100644 --- a/python/samba/tests/dns.py +++ b/python/samba/tests/dns.py @@ -247,23 +247,23 @@ class TestSimpleQueries(DNSTest): response = self.dns_transaction_udp(p) self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NOTIMP) -# Only returns an authority section entry in BIND and Win DNS -# FIXME: Enable one Samba implements this feature -# def test_soa_hostname_query(self): -# "create a SOA query for a hostname" -# p = self.make_name_packet(dns.DNS_OPCODE_QUERY) -# questions = [] -# -# name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain()) -# q = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN) -# questions.append(q) -# -# self.finish_name_packet(p, questions) -# response = self.dns_transaction_udp(p) -# self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) -# self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY) -# # We don't get SOA records for single hosts -# self.assertEquals(response.ancount, 0) + def test_soa_hostname_query(self): + "create a SOA query for a hostname" + p = self.make_name_packet(dns.DNS_OPCODE_QUERY) + questions = [] + + name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain()) + q = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN) + questions.append(q) + + self.finish_name_packet(p, questions) + response = self.dns_transaction_udp(p) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) + self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY) + # We don't get SOA records for single hosts + self.assertEquals(response.ancount, 0) + # But we do respond with an authority section + self.assertEqual(response.nscount, 1) def test_soa_domain_query(self): "create a SOA query for a domain" diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c index 8ff48a5..94f5d49 100644 --- a/source4/dns_server/dns_query.c +++ b/source4/dns_server/dns_query.c @@ -314,12 +314,13 @@ static WERROR handle_question(struct dns_server *dns, struct ldb_dn *dn = NULL; werror = dns_name2dn(dns, mem_ctx, question->name, &dn); - W_ERROR_NOT_OK_RETURN(werror); + if (!W_ERROR_IS_OK(werror)) { + return werror; + } werror = dns_lookup_records(dns, mem_ctx, dn, &recs, &rec_count); if (!W_ERROR_IS_OK(werror)) { werror_return = werror; - add_zone_authority_record(dns, mem_ctx, question, &ns, &ni); goto done; } @@ -369,7 +370,7 @@ static WERROR handle_question(struct dns_server *dns, /* and then call the lookup again */ werror = handle_question(dns, mem_ctx, new_q, &ans, &ai, &ns, &ni); if (!W_ERROR_IS_OK(werror)) { - return werror; + goto done; } werror_return = WERR_OK; @@ -389,6 +390,9 @@ static WERROR handle_question(struct dns_server *dns, } done: + /* Always add an authority record to replies we should know about */ + add_zone_authority_record(dns, mem_ctx, question, &ns, &ni); + *ancount = ai; *answers = ans; *nscount = ni; @@ -670,7 +674,9 @@ struct tevent_req *dns_server_process_query_send( &state->answers, &state->ancount, &state->nsrecs, &state->nscount); if (tevent_req_werror(req, err)) { - return tevent_req_post(req, ev); + if (!W_ERROR_EQUAL(err, DNS_ERR(NAME_ERROR))) { + return tevent_req_post(req, ev); + } } tevent_req_done(req); return tevent_req_post(req, ev); @@ -724,10 +730,14 @@ WERROR dns_server_process_query_recv( { struct dns_server_process_query_state *state = tevent_req_data( req, struct dns_server_process_query_state); - WERROR err; + WERROR err = WERR_OK; if (tevent_req_is_werror(req, &err)) { - return err; + + if ((!W_ERROR_EQUAL(err, DNS_ERR(NAME_ERROR))) && + (!W_ERROR_EQUAL(err, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST))) { + return err; + } } *answers = talloc_move(mem_ctx, &state->answers); *ancount = state->ancount; @@ -735,5 +745,5 @@ WERROR dns_server_process_query_recv( *nscount = state->nscount; *additional = talloc_move(mem_ctx, &state->additional); *arcount = state->arcount; - return WERR_OK; + return err; } diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c index 3e18287..66ab738 100644 --- a/source4/dns_server/dns_server.c +++ b/source4/dns_server/dns_server.c @@ -234,9 +234,13 @@ static WERROR dns_process_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, if (tevent_req_is_werror(req, &ret)) { return ret; } - if (state->dns_err != DNS_RCODE_OK) { + if ((state->dns_err != DNS_RCODE_OK) && + (state->dns_err != DNS_RCODE_NXDOMAIN)) { goto drop; } + if (state->dns_err != DNS_RCODE_OK) { + state->out_packet.operation |= state->dns_err; + } state->out_packet.operation |= state->state.flags; if (state->state.sign) { -- 1.9.1