[PATCH] Fix bug 9409

Volker Lendecke Volker.Lendecke at SerNet.DE
Tue Dec 15 07:29:11 UTC 2015


Hi!

Attached find a patchset that is supposed to fix
https://bugzilla.samba.org/show_bug.cgi?id=9409. I could
create a cname in AD that points to www.samba.org and
successfully resolve it via our internal DNS.

Review appreciated!

Thanks, Volker

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de
-------------- next part --------------
From 505a2092986d4f2166f47d3dc609da7416215f37 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 7 Aug 2015 08:27:19 +0200
Subject: [PATCH 1/7] 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 <vl at samba.org>
---
 source4/dns_server/dns_query.c | 41 ++++++++++++++++++-----------------------
 1 file changed, 18 insertions(+), 23 deletions(-)

diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index 956898e..fb29e8f 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -40,15 +40,24 @@
 #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(TALLOC_CTX *mem_ctx, const char *name,
+			      const struct dnsp_DnssrvRpcRecord *rec,
+			      struct dns_res_rec **answers, uint16_t *ancount)
 {
 	struct dns_res_rec *ans = *answers;
 	uint16_t ai = *ancount;
 	char *tmp;
 	uint32_t i;
 
+	if (ai == UINT16_MAX) {
+		return WERR_BUFFER_OVERFLOW;
+	}
+
+	ans = talloc_realloc(mem_ctx, ans, struct dns_res_rec, ai+1);
+	if (ans == NULL) {
+		return WERR_NOMEM;
+	}
+
 	ZERO_STRUCT(ans[ai]);
 
 	switch (rec->wType) {
@@ -281,13 +290,10 @@ 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(mem_ctx, zone, &recs[ri],
+						 &ns, &ni);
 			if (!W_ERROR_IS_OK(werror)) {
 				return werror;
 			}
@@ -326,11 +332,6 @@ static WERROR handle_question(struct dns_server *dns,
 		goto done;
 	}
 
-	ans = talloc_realloc(mem_ctx, ans, struct dns_res_rec, rec_count + ai);
-	if (ans == NULL) {
-		return WERR_NOMEM;
-	}
-
 	/* Set up for an NXDOMAIN reply if no match is found */
 	werror_return = DNS_ERR(NAME_ERROR);
 
@@ -345,16 +346,9 @@ static WERROR handle_question(struct dns_server *dns,
 				return WERR_NOMEM;
 			}
 
-			/* 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;
-			}
-
 			/* First put in the CNAME record */
-			werror = create_response_rr(question->name, &recs[ri], &ans, &ai);
+			werror = add_response_rr(mem_ctx, question->name,
+						 &recs[ri], &ans, &ai);
 			if (!W_ERROR_IS_OK(werror)) {
 				TALLOC_FREE(new_q);
 				return werror;
@@ -385,7 +379,8 @@ static WERROR handle_question(struct dns_server *dns,
 			werror_return = WERR_OK;
 			continue;
 		}
-		werror = create_response_rr(question->name, &recs[ri], &ans, &ai);
+		werror = add_response_rr(mem_ctx, question->name, &recs[ri],
+					 &ans, &ai);
 		if (!W_ERROR_IS_OK(werror)) {
 			return werror;
 		}
-- 
1.9.1


From fffad3e2d3ce99f0b91c2883037ff29ef165c97c Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 8 Aug 2015 06:49:16 +0200
Subject: [PATCH 2/7] 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 <vl at samba.org>
---
 source4/dns_server/dns_query.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index fb29e8f..98b4e62 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 add_response_rr(TALLOC_CTX *mem_ctx, const char *name,
+static WERROR add_response_rr(const char *name,
 			      const struct dnsp_DnssrvRpcRecord *rec,
 			      struct dns_res_rec **answers, uint16_t *ancount)
 {
@@ -53,7 +53,10 @@ static WERROR add_response_rr(TALLOC_CTX *mem_ctx, const char *name,
 		return WERR_BUFFER_OVERFLOW;
 	}
 
-	ans = talloc_realloc(mem_ctx, ans, struct dns_res_rec, ai+1);
+	/*
+	 * "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;
 	}
@@ -292,7 +295,7 @@ static WERROR add_zone_authority_record(struct dns_server *dns,
 
 	for (ri = 0; ri < rec_count; ri++) {
 		if (recs[ri].wType == DNS_TYPE_SOA) {
-			werror = add_response_rr(mem_ctx, zone, &recs[ri],
+			werror = add_response_rr(zone, &recs[ri],
 						 &ns, &ni);
 			if (!W_ERROR_IS_OK(werror)) {
 				return werror;
@@ -347,8 +350,8 @@ static WERROR handle_question(struct dns_server *dns,
 			}
 
 			/* First put in the CNAME record */
-			werror = add_response_rr(mem_ctx, question->name,
-						 &recs[ri], &ans, &ai);
+			werror = add_response_rr(question->name, &recs[ri],
+						 &ans, &ai);
 			if (!W_ERROR_IS_OK(werror)) {
 				TALLOC_FREE(new_q);
 				return werror;
@@ -379,7 +382,7 @@ static WERROR handle_question(struct dns_server *dns,
 			werror_return = WERR_OK;
 			continue;
 		}
-		werror = add_response_rr(mem_ctx, question->name, &recs[ri],
+		werror = add_response_rr(question->name, &recs[ri],
 					 &ans, &ai);
 		if (!W_ERROR_IS_OK(werror)) {
 			return werror;
@@ -668,6 +671,21 @@ struct tevent_req *dns_server_process_query_send(
 		WERROR err;
 
 		req_state->flags |= DNS_FLAG_AUTHORITATIVE;
+
+		/*
+		 * Initialize the response arrays, so that we can use
+		 * them as their own talloc contexts when doing the
+		 * realloc
+		 */
+		state->answers = talloc_array(state, struct dns_res_rec, 0);
+		if (tevent_req_nomem(state->answers, req)) {
+			return tevent_req_post(req, ev);
+		}
+		state->nsrecs = talloc_array(state, struct dns_res_rec, 0);
+		if (tevent_req_nomem(state->nsrecs, req)) {
+			return tevent_req_post(req, ev);
+		}
+
 		err = handle_question(dns, state, &in->questions[0],
 				      &state->answers, &state->ancount,
 				      &state->nsrecs, &state->nscount);
-- 
1.9.1


From 24f1df8ea4156ce65f03bce96b0b4a98bdceca00 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 8 Aug 2015 06:54:11 +0200
Subject: [PATCH 3/7] dns_server: Simplify array length handling

talloc objects carry an implicit length

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/dns_server/dns_query.c | 38 +++++++++++++++++---------------------
 1 file changed, 17 insertions(+), 21 deletions(-)

diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index 98b4e62..6971a47 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -42,10 +42,10 @@
 
 static WERROR add_response_rr(const char *name,
 			      const struct dnsp_DnssrvRpcRecord *rec,
-			      struct dns_res_rec **answers, uint16_t *ancount)
+			      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;
 
@@ -134,10 +134,8 @@ static WERROR add_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;
 }
@@ -270,12 +268,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;
@@ -295,15 +293,13 @@ static WERROR add_zone_authority_record(struct dns_server *dns,
 
 	for (ri = 0; ri < rec_count; ri++) {
 		if (recs[ri].wType == DNS_TYPE_SOA) {
-			werror = add_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;
@@ -313,15 +309,15 @@ static WERROR add_zone_authority_record(struct dns_server *dns,
 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)
+			      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;
+	uint16_t rec_count;
 	struct ldb_dn *dn = NULL;
 
 	werror = dns_name2dn(dns, mem_ctx, question->name, &dn);
@@ -351,7 +347,7 @@ static WERROR handle_question(struct dns_server *dns,
 
 			/* First put in the CNAME record */
 			werror = add_response_rr(question->name, &recs[ri],
-						 &ans, &ai);
+						 &ans);
 			if (!W_ERROR_IS_OK(werror)) {
 				TALLOC_FREE(new_q);
 				return werror;
@@ -368,7 +364,8 @@ 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, &ns, &ni);
+			werror = handle_question(dns, mem_ctx, new_q,
+						 &ans, &ns);
 			if (!W_ERROR_IS_OK(werror)) {
 				goto done;
 			}
@@ -382,8 +379,7 @@ static WERROR handle_question(struct dns_server *dns,
 			werror_return = WERR_OK;
 			continue;
 		}
-		werror = add_response_rr(question->name, &recs[ri],
-					 &ans, &ai);
+		werror = add_response_rr(question->name, &recs[ri], &ans);
 		if (!W_ERROR_IS_OK(werror)) {
 			return werror;
 		}
@@ -392,11 +388,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);
+	add_zone_authority_record(dns, mem_ctx, question, &ns);
 
-	*ancount = ai;
 	*answers = ans;
-	*nscount = ni;
 	*nsrecs = ns;
 
 	return werror_return;
@@ -687,8 +681,7 @@ struct tevent_req *dns_server_process_query_send(
 		}
 
 		err = handle_question(dns, state, &in->questions[0],
-				      &state->answers, &state->ancount,
-				      &state->nsrecs, &state->nscount);
+				      &state->answers, &state->nsrecs);
 
 		if (W_ERROR_EQUAL(err, DNS_ERR(NAME_ERROR))) {
 			err = WERR_OK;
@@ -698,6 +691,9 @@ struct tevent_req *dns_server_process_query_send(
 			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);
 	}
-- 
1.9.1


From 99ccb72c41a95f727c50157272c0428371cf9fcf Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 8 Aug 2015 07:20:26 +0200
Subject: [PATCH 4/7] dns_server: Convert "ask_forwarder" params

Usually we have mem_ctx and ev first when doing a _send function

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/dns_server/dns_query.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index 6971a47..128e46b 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -149,8 +149,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;
@@ -704,8 +704,7 @@ struct tevent_req *dns_server_process_query_send(
 			  in->questions[0].name));
 
 		subreq = ask_forwarder_send(
-			dns,
-			state, ev, lpcfg_dns_forwarder(dns->task->lp_ctx),
+			state, ev, dns, lpcfg_dns_forwarder(dns->task->lp_ctx),
 			&in->questions[0]);
 		if (tevent_req_nomem(subreq, req)) {
 			return tevent_req_post(req, ev);
-- 
1.9.1


From 27d8edf158c2215f73da730732da20840b7312de Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 8 Aug 2015 14:36:43 +0200
Subject: [PATCH 5/7] 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 <vl at samba.org>
---
 source4/dns_server/dns_query.c | 124 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index 128e46b..4e53825 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -140,6 +140,130 @@ static WERROR add_response_rr(const char *name,
 	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;
+}
+
 struct ask_forwarder_state {
 	struct tevent_context *ev;
 	uint16_t id;
-- 
1.9.1


From db3a13ceef608d5fc0f50f745212e9173ac4c2a8 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 11 Aug 2015 07:39:31 +0200
Subject: [PATCH 6/7] 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 <vl at samba.org>
---
 source4/dns_server/dns_query.c | 308 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 293 insertions(+), 15 deletions(-)

diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index 4e53825..e46e68b 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; i<ancount; i++) {
+		werr = add_dns_res_rec(state->answers, &answers[i]);
+		if (tevent_req_werror(req, werr)) {
+			return;
+		}
+	}
+
+	for (i=0; i<nscount; i++) {
+		werr = add_dns_res_rec(state->nsrecs, &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,
-- 
1.9.1


From 6c4eb3eb69e4d0b00377617eb9d22f3da614ac4c Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 11 Aug 2015 07:40:50 +0200
Subject: [PATCH 7/7] dns_server: Remove unused handle_question

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/dns_server/dns_query.c | 91 ------------------------------------------
 1 file changed, 91 deletions(-)

diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index e46e68b..63c219a 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -429,97 +429,6 @@ static WERROR add_zone_authority_record(struct dns_server *dns,
 	return WERR_OK;
 }
 
-
-static WERROR handle_question(struct dns_server *dns,
-			      TALLOC_CTX *mem_ctx,
-			      const struct dns_name_question *question,
-			      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;
-	struct ldb_dn *dn = NULL;
-
-	werror = dns_name2dn(dns, mem_ctx, question->name, &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)) {
-		werror_return = werror;
-		goto done;
-	}
-
-	/* Set up for an NXDOMAIN reply if no match is found */
-	werror_return = DNS_ERR(NAME_ERROR);
-
-	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);
-
-			if (new_q == NULL) {
-				return WERR_NOMEM;
-			}
-
-			/* First put in the CNAME record */
-			werror = add_response_rr(question->name, &recs[ri],
-						 &ans);
-			if (!W_ERROR_IS_OK(werror)) {
-				TALLOC_FREE(new_q);
-				return werror;
-			}
-
-			/* And then look up the name it points at.. */
-
-			/* 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, &ns);
-			if (!W_ERROR_IS_OK(werror)) {
-				goto done;
-			}
-			werror_return = WERR_OK;
-
-
-			continue;
-		}
-		if ((question->question_type != DNS_QTYPE_ALL) &&
-		    (recs[ri].wType != (enum dns_record_type) question->question_type)) {
-			werror_return = WERR_OK;
-			continue;
-		}
-		werror = add_response_rr(question->name, &recs[ri], &ans);
-		if (!W_ERROR_IS_OK(werror)) {
-			return werror;
-		}
-		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);
-
-	*answers = ans;
-	*nsrecs = ns;
-
-	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,
-- 
1.9.1



More information about the samba-technical mailing list