[PATCH] Different bugfix for bug 9632

Jeremy Allison jra at samba.org
Wed Jan 3 22:21:40 UTC 2018


On Tue, Jan 02, 2018 at 01:16:22PM +0100, Volker Lendecke via samba-technical wrote:
> Hi!
> 
> The currently implemented bugfix for bug 9632 limits our DNS forwarder
> to a packet of 4k over UDP. The attached patchset allows us to proxy
> replies up to the DNS limit of 64k.
> 
> Review appreciated!

Wow, that's a great tutorial on the use of tstream_readv_pdu_send(),
thanks for that !

Nice work.

RB+ and pushed.

Jeremy.


> -- 
> 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

> From 53a12079e1d28cc35c6d5b63d48da27c48d30fe0 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Thu, 28 Dec 2017 21:41:33 +0100
> Subject: [PATCH 01/10] tsocket: Fix typos
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  lib/tsocket/tsocket.h | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/tsocket/tsocket.h b/lib/tsocket/tsocket.h
> index f52b7466dfb..dd0bd981f20 100644
> --- a/lib/tsocket/tsocket.h
> +++ b/lib/tsocket/tsocket.h
> @@ -805,7 +805,7 @@ bool tstream_bsd_optimize_readv(struct tstream_context *stream,
>   * @brief Connect async to a TCP endpoint and create a tstream_context for the
>   * stream based communication.
>   *
> - * Use this function to connenct asynchronously to a remote ipv4 or ipv6 TCP
> + * Use this function to connect asynchronously to a remote ipv4 or ipv6 TCP
>   * endpoint and create a tstream_context for the stream based communication.
>   *
>   * @param[in]  mem_ctx  The talloc memory context to use.
> @@ -961,7 +961,7 @@ struct sockaddr;
>   *
>   * @param[in]  sa       The sockaddr structure to convert.
>   *
> - * @param[in]  sa_socklen   The lenth of the sockaddr sturucte.
> + * @param[in]  sa_socklen   The length of the sockaddr structure.
>   *
>   * @param[out] addr     The tsocket pointer to allocate and fill.
>   *
> -- 
> 2.11.0
> 
> 
> From 7726eb946277aaf41ff5d6fedaa30399ccd66637 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Fri, 29 Dec 2017 09:36:31 +0100
> Subject: [PATCH 02/10] libdns: Fix a typo
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  libcli/dns/libdns.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/libcli/dns/libdns.h b/libcli/dns/libdns.h
> index 7ea2eb65716..91353a8e84d 100644
> --- a/libcli/dns/libdns.h
> +++ b/libcli/dns/libdns.h
> @@ -39,7 +39,7 @@ struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
>  
>  /** Get the dns response from a dns server via UDP
>   *
> - *@param req       tevent_req struct returned from dns_request_send
> + *@param req       tevent_req struct returned from dns_udp_request_send
>   *@param mem_ctx   talloc memory context to use for the reply string
>   *@param reply     buffer that will be allocated and filled with the dns reply
>   *@param reply_len length of the reply buffer
> -- 
> 2.11.0
> 
> 
> From 37efaf91fdc6ff8422c593163f7d735cf847ad53 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 27 Dec 2017 12:50:07 +0100
> Subject: [PATCH 03/10] dsdb: Fix the build on 32-bit FreeBSD
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source4/dsdb/samdb/ldb_modules/encrypted_secrets.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/source4/dsdb/samdb/ldb_modules/encrypted_secrets.c b/source4/dsdb/samdb/ldb_modules/encrypted_secrets.c
> index 8f3e0497b33..226f62f641e 100644
> --- a/source4/dsdb/samdb/ldb_modules/encrypted_secrets.c
> +++ b/source4/dsdb/samdb/ldb_modules/encrypted_secrets.c
> @@ -514,7 +514,7 @@ static struct ldb_val nettle_encrypt_aead(int *err,
>  	if (key_blob.length != ntl->key_size) {
>  		ldb_asprintf_errstring(ldb,
>  				       "Invalid EncryptedSecrets key size, "
> -				       "expected %ld bytes and is %ld bytes\n",
> +				       "expected %zu bytes and is %zu bytes\n",
>  				       ntl->key_size,
>  				       key_blob.length);
>  		goto error_exit;
> @@ -637,7 +637,7 @@ static void nettle_decrypt_aead(int *err,
>  	if (key_blob.length != ntl->key_size) {
>  		ldb_asprintf_errstring(ldb,
>  				       "Invalid EncryptedSecrets key size, "
> -				       "expected %ld bytes and is %ld bytes\n",
> +				       "expected %zu bytes and is %zu bytes\n",
>  				       ntl->key_size,
>  				       key_blob.length);
>  		goto error_exit;
> @@ -795,8 +795,8 @@ static struct ldb_val gnutls_encrypt_aead(int *err,
>  		if (key_blob.length != key_size) {
>  			ldb_asprintf_errstring(ldb,
>  					       "Invalid EncryptedSecrets key "
> -					       "size, expected %ld bytes and "
> -					       "it is %ld bytes\n",
> +					       "size, expected %zu bytes and "
> +					       "it is %zu bytes\n",
>  					       key_size,
>  					       key_blob.length);
>  			goto error_exit;
> @@ -961,8 +961,8 @@ static void gnutls_decrypt_aead(int *err,
>  		if (key_blob.length != key_size) {
>  			ldb_asprintf_errstring(ldb,
>  					       "Invalid EncryptedSecrets key "
> -					       "size, expected %ld bytes and "
> -					       "it is %ld bytes\n",
> +					       "size, expected %zu bytes and "
> +					       "it is %zu bytes\n",
>  					       key_size,
>  					       key_blob.length);
>  			goto error_exit;
> -- 
> 2.11.0
> 
> 
> From cbcc4e0097c8ecfea40cecd1b2db25a6ee4a25f4 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Thu, 28 Dec 2017 22:35:46 +0100
> Subject: [PATCH 04/10] libdns: dns/tcp client
> 
> Same signature as the UDP client in the same file. This opens and closes
> the socket per request. In the future, we might want to create a
> persistent TCP connection for our internal DNS server's forwarder. That
> will require proper handling of in-flight requests. Something for
> another day.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  libcli/dns/dns.c    | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  libcli/dns/libdns.h |  10 +++
>  2 files changed, 229 insertions(+)
> 
> diff --git a/libcli/dns/dns.c b/libcli/dns/dns.c
> index 7d066d802c1..9e180fe3fc9 100644
> --- a/libcli/dns/dns.c
> +++ b/libcli/dns/dns.c
> @@ -176,3 +176,222 @@ int dns_udp_request_recv(struct tevent_req *req,
>  
>  	return 0;
>  }
> +
> +struct dns_tcp_request_state {
> +	struct tevent_context *ev;
> +	struct tstream_context *stream;
> +	const uint8_t *query;
> +	size_t query_len;
> +
> +	uint8_t dns_msglen_hdr[2];
> +	struct iovec iov[2];
> +
> +	size_t nread;
> +	uint8_t *reply;
> +};
> +
> +static void dns_tcp_request_connected(struct tevent_req *subreq);
> +static void dns_tcp_request_sent(struct tevent_req *subreq);
> +static int dns_tcp_request_next_vector(struct tstream_context *stream,
> +				       void *private_data,
> +				       TALLOC_CTX *mem_ctx,
> +				       struct iovec **_vector,
> +				       size_t *_count);
> +static void dns_tcp_request_received(struct tevent_req *subreq);
> +
> +struct tevent_req *dns_tcp_request_send(TALLOC_CTX *mem_ctx,
> +					struct tevent_context *ev,
> +					const char *server_addr_string,
> +					const uint8_t *query,
> +					size_t query_len)
> +{
> +	struct tevent_req *req, *subreq;
> +	struct dns_tcp_request_state *state;
> +	struct tsocket_address *local, *remote;
> +	int ret;
> +
> +	req = tevent_req_create(mem_ctx, &state,
> +				struct dns_tcp_request_state);
> +	if (req == NULL) {
> +		return NULL;
> +	}
> +	state->ev = ev;
> +	state->query = query;
> +	state->query_len = query_len;
> +
> +	if (query_len > UINT16_MAX) {
> +		tevent_req_error(req, EMSGSIZE);
> +		return tevent_req_post(req, ev);
> +	}
> +
> +	ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local);
> +	if (ret != 0) {
> +		tevent_req_error(req, errno);
> +		return tevent_req_post(req, ev);
> +	}
> +
> +	ret = tsocket_address_inet_from_strings(
> +		state, "ip", server_addr_string, DNS_SERVICE_PORT, &remote);
> +	if (ret != 0) {
> +		tevent_req_error(req, errno);
> +		return tevent_req_post(req, ev);
> +	}
> +
> +	subreq = tstream_inet_tcp_connect_send(state, state->ev,
> +					       local, remote);
> +	if (tevent_req_nomem(subreq, req)) {
> +		return tevent_req_post(req, ev);
> +	}
> +	tevent_req_set_callback(subreq, dns_tcp_request_connected, req);
> +
> +	return req;
> +}
> +
> +static void dns_tcp_request_connected(struct tevent_req *subreq)
> +{
> +	struct tevent_req *req = tevent_req_callback_data(
> +		subreq, struct tevent_req);
> +	struct dns_tcp_request_state *state = tevent_req_data(
> +		req, struct dns_tcp_request_state);
> +	int ret, err;
> +
> +	ret = tstream_inet_tcp_connect_recv(subreq, &err, state,
> +					    &state->stream, NULL);
> +	TALLOC_FREE(subreq);
> +	if (ret == -1) {
> +		tevent_req_error(req, err);
> +		return;
> +	}
> +
> +	RSSVAL(state->dns_msglen_hdr, 0, state->query_len);
> +	state->iov[0] = (struct iovec) {
> +		.iov_base = state->dns_msglen_hdr,
> +		.iov_len = sizeof(state->dns_msglen_hdr)
> +	};
> +	state->iov[1] = (struct iovec) {
> +		.iov_base = discard_const_p(void, state->query),
> +		.iov_len = state->query_len
> +	};
> +
> +	subreq = tstream_writev_send(state, state->ev, state->stream,
> +				     state->iov, ARRAY_SIZE(state->iov));
> +	if (tevent_req_nomem(subreq, req)) {
> +		return;
> +	}
> +	tevent_req_set_callback(subreq, dns_tcp_request_sent, req);
> +}
> +
> +static void dns_tcp_request_sent(struct tevent_req *subreq)
> +{
> +	struct tevent_req *req = tevent_req_callback_data(
> +		subreq, struct tevent_req);
> +	struct dns_tcp_request_state *state = tevent_req_data(
> +		req, struct dns_tcp_request_state);
> +	int ret, err;
> +
> +	ret = tstream_writev_recv(subreq, &err);
> +	TALLOC_FREE(subreq);
> +	if (ret == -1) {
> +		tevent_req_error(req, err);
> +		return;
> +	}
> +
> +	subreq = tstream_readv_pdu_send(state, state->ev, state->stream,
> +					dns_tcp_request_next_vector, state);
> +	if (tevent_req_nomem(subreq, req)) {
> +		return;
> +	}
> +	tevent_req_set_callback(subreq, dns_tcp_request_received, req);
> +}
> +
> +static int dns_tcp_request_next_vector(struct tstream_context *stream,
> +				       void *private_data,
> +				       TALLOC_CTX *mem_ctx,
> +				       struct iovec **_vector,
> +				       size_t *_count)
> +{
> +	struct dns_tcp_request_state *state = talloc_get_type_abort(
> +		private_data, struct dns_tcp_request_state);
> +	struct iovec *vector;
> +	uint16_t msglen;
> +
> +	if (state->nread == 0) {
> +		vector = talloc_array(mem_ctx, struct iovec, 1);
> +		if (vector == NULL) {
> +			return -1;
> +		}
> +		vector[0] = (struct iovec) {
> +			.iov_base = state->dns_msglen_hdr,
> +			.iov_len = sizeof(state->dns_msglen_hdr)
> +		};
> +		state->nread = sizeof(state->dns_msglen_hdr);
> +
> +		*_vector = vector;
> +		*_count = 1;
> +		return 0;
> +	}
> +
> +	if (state->nread == sizeof(state->dns_msglen_hdr)) {
> +		msglen = RSVAL(state->dns_msglen_hdr, 0);
> +
> +		state->reply = talloc_array(state, uint8_t, msglen);
> +		if (state->reply == NULL) {
> +			return -1;
> +		}
> +
> +		vector = talloc_array(mem_ctx, struct iovec, 1);
> +		if (vector == NULL) {
> +			return -1;
> +		}
> +		vector[0] = (struct iovec) {
> +			.iov_base = state->reply,
> +			.iov_len = msglen
> +		};
> +		state->nread += msglen;
> +
> +		*_vector = vector;
> +		*_count = 1;
> +		return 0;
> +	}
> +
> +	*_vector = NULL;
> +	*_count = 0;
> +	return 0;
> +}
> +
> +static void dns_tcp_request_received(struct tevent_req *subreq)
> +{
> +	struct tevent_req *req = tevent_req_callback_data(
> +		subreq, struct tevent_req);
> +	int ret, err;
> +
> +	ret = tstream_readv_pdu_recv(subreq, &err);
> +	TALLOC_FREE(subreq);
> +	if (ret == -1) {
> +		tevent_req_error(req, err);
> +		return;
> +	}
> +
> +	tevent_req_done(req);
> +}
> +
> +int dns_tcp_request_recv(struct tevent_req *req,
> +			 TALLOC_CTX *mem_ctx,
> +			 uint8_t **reply,
> +			 size_t *reply_len)
> +{
> +	struct dns_tcp_request_state *state = tevent_req_data(
> +		req, struct dns_tcp_request_state);
> +	int err;
> +
> +	if (tevent_req_is_unix_error(req, &err)) {
> +		tevent_req_received(req);
> +		return err;
> +	}
> +
> +	*reply_len = talloc_array_length(state->reply);
> +	*reply = talloc_move(mem_ctx, &state->reply);
> +	tevent_req_received(req);
> +
> +	return 0;
> +}
> diff --git a/libcli/dns/libdns.h b/libcli/dns/libdns.h
> index 91353a8e84d..1fa73d3fb22 100644
> --- a/libcli/dns/libdns.h
> +++ b/libcli/dns/libdns.h
> @@ -50,4 +50,14 @@ int dns_udp_request_recv(struct tevent_req *req,
>  			 uint8_t **reply,
>  			 size_t *reply_len);
>  
> +struct tevent_req *dns_tcp_request_send(TALLOC_CTX *mem_ctx,
> +					struct tevent_context *ev,
> +					const char *server_addr_string,
> +					const uint8_t *query,
> +					size_t query_len);
> +int dns_tcp_request_recv(struct tevent_req *req,
> +			 TALLOC_CTX *mem_ctx,
> +			 uint8_t **reply,
> +			 size_t *reply_len);
> +
>  #endif /*__LIBDNS_H__*/
> -- 
> 2.11.0
> 
> 
> From cbfee4f233b52891dd6bc19cde3cd5164a41a8bc Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Fri, 29 Dec 2017 11:01:29 +0100
> Subject: [PATCH 05/10] libdns: Add dns_cli_request
> 
> First UDP, then TCP if truncation happened
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  libcli/dns/dns.c         | 191 ++++++++++++++++++++++++++++++++++++++++++++++-
>  libcli/dns/libdns.h      |  18 +++++
>  libcli/dns/wscript_build |   2 +-
>  3 files changed, 209 insertions(+), 2 deletions(-)
> 
> diff --git a/libcli/dns/dns.c b/libcli/dns/dns.c
> index 9e180fe3fc9..6404cb8aa40 100644
> --- a/libcli/dns/dns.c
> +++ b/libcli/dns/dns.c
> @@ -26,8 +26,10 @@
>  #include "libcli/dns/libdns.h"
>  #include "lib/util/tevent_unix.h"
>  #include "lib/util/samba_util.h"
> +#include "lib/util/debug.h"
>  #include "libcli/util/error.h"
> -#include "librpc/gen_ndr/dns.h"
> +#include "librpc/ndr/libndr.h"
> +#include "librpc/gen_ndr/ndr_dns.h"
>  
>  struct dns_udp_request_state {
>  	struct tevent_context *ev;
> @@ -395,3 +397,190 @@ int dns_tcp_request_recv(struct tevent_req *req,
>  
>  	return 0;
>  }
> +
> +struct dns_cli_request_state {
> +	struct tevent_context *ev;
> +	const char *nameserver;
> +
> +	uint16_t req_id;
> +
> +	DATA_BLOB query;
> +
> +	struct dns_name_packet *reply;
> +};
> +
> +static void dns_cli_request_udp_done(struct tevent_req *subreq);
> +static void dns_cli_request_tcp_done(struct tevent_req *subreq);
> +
> +struct tevent_req *dns_cli_request_send(TALLOC_CTX *mem_ctx,
> +					struct tevent_context *ev,
> +					const char *nameserver,
> +					const char *name,
> +					enum dns_qclass qclass,
> +					enum dns_qtype qtype)
> +{
> +	struct tevent_req *req, *subreq;
> +	struct dns_cli_request_state *state;
> +	struct dns_name_question question;
> +	struct dns_name_packet out_packet;
> +	enum ndr_err_code ndr_err;
> +
> +	req = tevent_req_create(mem_ctx, &state,
> +				struct dns_cli_request_state);
> +	if (req == NULL) {
> +		return NULL;
> +	}
> +	state->ev = ev;
> +	state->nameserver = nameserver;
> +
> +	DBG_DEBUG("Asking %s for %s/%d/%d via UDP\n", nameserver,
> +		  name, (int)qclass, (int)qtype);
> +
> +	generate_random_buffer((uint8_t *)&state->req_id,
> +			       sizeof(state->req_id));
> +
> +	question = (struct dns_name_question) {
> +		.name = discard_const_p(char, name),
> +		.question_type = qtype, .question_class = qclass
> +	};
> +
> +	out_packet = (struct dns_name_packet) {
> +		.id = state->req_id,
> +		.operation = DNS_OPCODE_QUERY | DNS_FLAG_RECURSION_DESIRED,
> +		.qdcount = 1,
> +		.questions = &question
> +	};
> +
> +	ndr_err = ndr_push_struct_blob(
> +		&state->query, state, &out_packet,
> +		(ndr_push_flags_fn_t)ndr_push_dns_name_packet);
> +	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
> +		tevent_req_error(req, ndr_map_error2errno(ndr_err));
> +		return tevent_req_post(req, ev);
> +	}
> +
> +	subreq = dns_udp_request_send(state, state->ev, state->nameserver,
> +				      state->query.data, state->query.length);
> +	if (tevent_req_nomem(subreq, req)) {
> +		return tevent_req_post(req, ev);
> +	}
> +	tevent_req_set_callback(subreq, dns_cli_request_udp_done, req);
> +	return req;
> +}
> +
> +static void dns_cli_request_udp_done(struct tevent_req *subreq)
> +{
> +	struct tevent_req *req = tevent_req_callback_data(
> +		subreq, struct tevent_req);
> +	struct dns_cli_request_state *state = tevent_req_data(
> +		req, struct dns_cli_request_state);
> +	DATA_BLOB reply;
> +	enum ndr_err_code ndr_err;
> +	int ret;
> +
> +	ret = dns_udp_request_recv(subreq, state, &reply.data, &reply.length);
> +	TALLOC_FREE(subreq);
> +	if (tevent_req_error(req, ret)) {
> +		return;
> +	}
> +
> +	state->reply = talloc(state, struct dns_name_packet);
> +	if (tevent_req_nomem(state->reply, req)) {
> +		return;
> +	}
> +
> +	ndr_err = ndr_pull_struct_blob(
> +		&reply, state->reply, state->reply,
> +		(ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
> +	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
> +		tevent_req_error(req, ndr_map_error2errno(ndr_err));
> +		return;
> +	}
> +	TALLOC_FREE(reply.data);
> +
> +	if (state->reply->id != state->req_id) {
> +		DBG_DEBUG("Got id %"PRIu16", expected %"PRIu16"\n",
> +			  state->reply->id, state->req_id);
> +		tevent_req_error(req, ENOMSG);
> +		return;
> +	}
> +
> +	if ((state->reply->operation & DNS_FLAG_TRUNCATION) == 0) {
> +		DBG_DEBUG("Got op=%x %"PRIu16"/%"PRIu16"/%"PRIu16"/%"PRIu16
> +			  " recs\n", (int)state->reply->operation,
> +			  state->reply->qdcount, state->reply->ancount,
> +			  state->reply->nscount, state->reply->nscount);
> +		tevent_req_done(req);
> +		return;
> +	}
> +
> +	DBG_DEBUG("Reply was truncated, retrying TCP\n");
> +
> +	TALLOC_FREE(state->reply);
> +
> +	subreq = dns_tcp_request_send(state, state->ev, state->nameserver,
> +				      state->query.data, state->query.length);
> +	if (tevent_req_nomem(subreq, req)) {
> +		return;
> +	}
> +	tevent_req_set_callback(subreq, dns_cli_request_tcp_done, req);
> +}
> +
> +static void dns_cli_request_tcp_done(struct tevent_req *subreq)
> +{
> +	struct tevent_req *req = tevent_req_callback_data(
> +		subreq, struct tevent_req);
> +	struct dns_cli_request_state *state = tevent_req_data(
> +		req, struct dns_cli_request_state);
> +	DATA_BLOB reply;
> +	enum ndr_err_code ndr_err;
> +	int ret;
> +
> +	ret = dns_tcp_request_recv(subreq, state, &reply.data, &reply.length);
> +	TALLOC_FREE(subreq);
> +	if (tevent_req_error(req, ret)) {
> +		return;
> +	}
> +
> +	state->reply = talloc(state, struct dns_name_packet);
> +	if (tevent_req_nomem(state->reply, req)) {
> +		return;
> +	}
> +
> +	ndr_err = ndr_pull_struct_blob(
> +		&reply, state->reply, state->reply,
> +		(ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
> +	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
> +		tevent_req_error(req, ndr_map_error2errno(ndr_err));
> +		return;
> +	}
> +	TALLOC_FREE(reply.data);
> +
> +	if (state->reply->id != state->req_id) {
> +		DBG_DEBUG("Got id %"PRIu16", expected %"PRIu16"\n",
> +			  state->reply->id, state->req_id);
> +		tevent_req_error(req, ENOMSG);
> +		return;
> +	}
> +
> +	DBG_DEBUG("Got op=%x %"PRIu16"/%"PRIu16"/%"PRIu16"/%"PRIu16
> +		  " recs\n", (int)state->reply->operation,
> +		  state->reply->qdcount, state->reply->ancount,
> +		  state->reply->nscount, state->reply->nscount);
> +
> +	tevent_req_done(req);
> +}
> +
> +int dns_cli_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
> +			 struct dns_name_packet **reply)
> +{
> +	struct dns_cli_request_state *state = tevent_req_data(
> +		req, struct dns_cli_request_state);
> +	int err;
> +
> +	if (tevent_req_is_unix_error(req, &err)) {
> +		return err;
> +	}
> +	*reply = talloc_move(mem_ctx, &state->reply);
> +	return 0;
> +}
> diff --git a/libcli/dns/libdns.h b/libcli/dns/libdns.h
> index 1fa73d3fb22..1b7c404f6b7 100644
> --- a/libcli/dns/libdns.h
> +++ b/libcli/dns/libdns.h
> @@ -22,6 +22,10 @@
>  #ifndef __LIBDNS_H__
>  #define __LIBDNS_H__
>  
> +#include "lib/util/data_blob.h"
> +#include "lib/util/time.h"
> +#include "librpc/gen_ndr/dns.h"
> +
>  /** Send an dns request to a dns server using UDP
>   *
>   *@param mem_ctx        talloc memory context to use
> @@ -60,4 +64,18 @@ int dns_tcp_request_recv(struct tevent_req *req,
>  			 uint8_t **reply,
>  			 size_t *reply_len);
>  
> +/*
> + * DNS request with fallback to TCP on truncation
> + */
> +
> +struct tevent_req *dns_cli_request_send(TALLOC_CTX *mem_ctx,
> +					struct tevent_context *ev,
> +					const char *nameserver,
> +					const char *name,
> +					enum dns_qclass qclass,
> +					enum dns_qtype qtype);
> +int dns_cli_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
> +			 struct dns_name_packet **reply);
> +
> +
>  #endif /*__LIBDNS_H__*/
> diff --git a/libcli/dns/wscript_build b/libcli/dns/wscript_build
> index 018df6b387e..2dcd8c17d9d 100644
> --- a/libcli/dns/wscript_build
> +++ b/libcli/dns/wscript_build
> @@ -2,4 +2,4 @@
>  
>  bld.SAMBA_SUBSYSTEM('clidns',
>          source='dns.c',
> -        public_deps='LIBTSOCKET tevent-util')
> +        public_deps='LIBTSOCKET tevent-util NDR_DNS')
> -- 
> 2.11.0
> 
> 
> From 0c1b9cffe5ba9e16a1d671322ad8704de80117ef Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Fri, 29 Dec 2017 11:11:59 +0100
> Subject: [PATCH 06/10] dns_server: Use dns_cli_request instead of direct udp
> 
> This skips adding the DNS option for a larger UDP packet size than
> 512. This is a different fix for bug 9632.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source4/dns_server/dns_query.c | 62 ++++--------------------------------------
>  1 file changed, 6 insertions(+), 56 deletions(-)
> 
> diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
> index 8d3f601b708..265cfd1878c 100644
> --- a/source4/dns_server/dns_query.c
> +++ b/source4/dns_server/dns_query.c
> @@ -270,9 +270,7 @@ static WERROR add_dns_res_rec(struct dns_res_rec **pdst,
>  }
>  
>  struct ask_forwarder_state {
> -	struct tevent_context *ev;
> -	uint16_t id;
> -	struct dns_name_packet in_packet;
> +	struct dns_name_packet *reply;
>  };
>  
>  static void ask_forwarder_done(struct tevent_req *subreq);
> @@ -284,49 +282,15 @@ static struct tevent_req *ask_forwarder_send(
>  {
>  	struct tevent_req *req, *subreq;
>  	struct ask_forwarder_state *state;
> -	struct dns_res_rec *options;
> -	struct dns_name_packet out_packet = { 0, };
> -	DATA_BLOB out_blob;
> -	enum ndr_err_code ndr_err;
> -	WERROR werr;
>  
>  	req = tevent_req_create(mem_ctx, &state, struct ask_forwarder_state);
>  	if (req == NULL) {
>  		return NULL;
>  	}
> -	state->ev = ev;
> -	generate_random_buffer((uint8_t *)&state->id, sizeof(state->id));
> -
> -	if (!is_ipaddress(forwarder)) {
> -		DEBUG(0, ("Invalid 'dns forwarder' setting '%s', needs to be "
> -			  "an IP address\n", forwarder));
> -		tevent_req_werror(req, DNS_ERR(NAME_ERROR));
> -		return tevent_req_post(req, ev);
> -	}
> -
> -	out_packet.id = state->id;
> -	out_packet.operation |= DNS_OPCODE_QUERY | DNS_FLAG_RECURSION_DESIRED;
> -	out_packet.qdcount = 1;
> -	out_packet.questions = question;
> -
> -	werr = dns_generate_options(dns, state, &options);
> -	if (!W_ERROR_IS_OK(werr)) {
> -		tevent_req_werror(req, werr);
> -		return tevent_req_post(req, ev);
> -	}
> -
> -	out_packet.arcount = 1;
> -	out_packet.additional = options;
>  
> -	ndr_err = ndr_push_struct_blob(
> -		&out_blob, state, &out_packet,
> -		(ndr_push_flags_fn_t)ndr_push_dns_name_packet);
> -	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
> -		tevent_req_werror(req, DNS_ERR(SERVER_FAILURE));
> -		return tevent_req_post(req, ev);
> -	}
> -	subreq = dns_udp_request_send(state, ev, forwarder, out_blob.data,
> -				      out_blob.length);
> +	subreq = dns_cli_request_send(state, ev, forwarder,
> +				      question->name, question->question_class,
> +				      question->question_type);
>  	if (tevent_req_nomem(subreq, req)) {
>  		return tevent_req_post(req, ev);
>  	}
> @@ -340,12 +304,9 @@ static void ask_forwarder_done(struct tevent_req *subreq)
>  		subreq, struct tevent_req);
>  	struct ask_forwarder_state *state = tevent_req_data(
>  		req, struct ask_forwarder_state);
> -	DATA_BLOB in_blob;
> -	enum ndr_err_code ndr_err;
>  	int ret;
>  
> -	ret = dns_udp_request_recv(subreq, state,
> -				   &in_blob.data, &in_blob.length);
> +	ret = dns_cli_request_recv(subreq, state, &state->reply);
>  	TALLOC_FREE(subreq);
>  
>  	if (ret != 0) {
> @@ -353,17 +314,6 @@ static void ask_forwarder_done(struct tevent_req *subreq)
>  		return;
>  	}
>  
> -	ndr_err = ndr_pull_struct_blob(
> -		&in_blob, state, &state->in_packet,
> -		(ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
> -	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
> -		tevent_req_werror(req, DNS_ERR(SERVER_FAILURE));
> -		return;
> -	}
> -	if (state->in_packet.id != state->id) {
> -		tevent_req_werror(req, DNS_ERR(NAME_ERROR));
> -		return;
> -	}
>  	tevent_req_done(req);
>  }
>  
> @@ -375,7 +325,7 @@ static WERROR ask_forwarder_recv(
>  {
>  	struct ask_forwarder_state *state = tevent_req_data(
>  		req, struct ask_forwarder_state);
> -	struct dns_name_packet *in_packet = &state->in_packet;
> +	struct dns_name_packet *in_packet = state->reply;
>  	WERROR err;
>  
>  	if (tevent_req_is_werror(req, &err)) {
> -- 
> 2.11.0
> 
> 
> From 0a924b4b5a7f0f4e27355502e183601fd6b91d30 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Fri, 29 Dec 2017 13:09:15 +0100
> Subject: [PATCH 07/10] ndr_dns: fix pushing unknown resource records
> 
> When pulling for example an RRSIG record, we end up with length!=0 *and*
> unexpected.length != 0, but with an unknown rrec. We should be able to
> marshall what we retrieved from the wire.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  librpc/ndr/ndr_dns.c | 11 ++++++++++-
>  1 file changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/librpc/ndr/ndr_dns.c b/librpc/ndr/ndr_dns.c
> index 4e4c556e20d..d37c8cc2ece 100644
> --- a/librpc/ndr/ndr_dns.c
> +++ b/librpc/ndr/ndr_dns.c
> @@ -289,11 +289,20 @@ _PUBLIC_ enum ndr_err_code ndr_push_dns_res_rec(struct ndr_push *ndr,
>  		_saved_offset1 = ndr->offset;
>  		NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
>  		if (r->length > 0) {
> +			uint32_t _saved_offset3;
> +
>  			NDR_CHECK(ndr_push_set_switch_value(ndr, &r->rdata,
>  							    r->rr_type));
> +			_saved_offset3 = ndr->offset;
>  			NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_SCALARS,
>  						     &r->rdata));
> -			if (r->unexpected.length > 0) {
> +			if ((ndr->offset != _saved_offset3) &&
> +			    (r->unexpected.length > 0)) {
> +				/*
> +				 * ndr_push_dns_rdata pushed a known
> +				 * record, but we have something
> +				 * unexpected. That's invalid.
> +				 */
>  				return ndr_push_error(ndr,
>  						      NDR_ERR_LENGTH,
>  						      "Invalid...Unexpected " \
> -- 
> 2.11.0
> 
> 
> From 777afc426acbec4b437273b1acd85c1924cf76b9 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Sun, 31 Dec 2017 10:59:40 +0100
> Subject: [PATCH 08/10] dns_server: Remove unused "dns" parameter from
>  ask_forwarder_send
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source4/dns_server/dns_query.c | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
> index 265cfd1878c..800d5c768bd 100644
> --- a/source4/dns_server/dns_query.c
> +++ b/source4/dns_server/dns_query.c
> @@ -277,7 +277,6 @@ static void ask_forwarder_done(struct tevent_req *subreq);
>  
>  static struct tevent_req *ask_forwarder_send(
>  	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;
> @@ -468,7 +467,7 @@ static struct tevent_req *handle_dnsrpcrec_send(
>  		return req;
>  	}
>  
> -	subreq = ask_forwarder_send(state, ev, dns, forwarder, new_q);
> +	subreq = ask_forwarder_send(state, ev, forwarder, new_q);
>  	if (tevent_req_nomem(subreq, req)) {
>  		return tevent_req_post(req, ev);
>  	}
> @@ -1008,7 +1007,7 @@ struct tevent_req *dns_server_process_query_send(
>  		DEBUG(5, ("Not authoritative for '%s', forwarding\n",
>  			  in->questions[0].name));
>  
> -		subreq = ask_forwarder_send(state, ev, dns,
> +		subreq = ask_forwarder_send(state, ev,
>  					    (forwarders == NULL ? NULL : forwarders[0]),
>  					    &in->questions[0]);
>  		if (tevent_req_nomem(subreq, req)) {
> @@ -1051,7 +1050,7 @@ static void dns_server_process_query_got_response(struct tevent_req *subreq)
>  
>  		DEBUG(5, ("DNS query returned %s, trying another forwarder.\n",
>  			  win_errstr(werr)));
> -		subreq = ask_forwarder_send(state, state->ev, state->dns,
> +		subreq = ask_forwarder_send(state, state->ev,
>  					    state->forwarders->forwarder,
>  					    state->question);
>  
> -- 
> 2.11.0
> 
> 
> From e32aa234b1f4d7541009ee6cd3816ee048e511d7 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Sun, 31 Dec 2017 11:00:01 +0100
> Subject: [PATCH 09/10] dns_server: Remove unused "dns_generate_options"
> 
> This was part of the previous bugfix for 9632, which has been replaced
> by TCP fallback code. We can dig this up from git if needed.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source4/dns_server/dns_server.h |  3 ---
>  source4/dns_server/dns_utils.c  | 20 --------------------
>  2 files changed, 23 deletions(-)
> 
> diff --git a/source4/dns_server/dns_server.h b/source4/dns_server/dns_server.h
> index 382b6bdf95b..7c5c09e57c0 100644
> --- a/source4/dns_server/dns_server.h
> +++ b/source4/dns_server/dns_server.h
> @@ -110,9 +110,6 @@ WERROR dns_name2dn(struct dns_server *dns,
>  		   TALLOC_CTX *mem_ctx,
>  		   const char *name,
>  		   struct ldb_dn **_dn);
> -WERROR dns_generate_options(struct dns_server *dns,
> -			    TALLOC_CTX *mem_ctx,
> -			    struct dns_res_rec **options);
>  struct dns_server_tkey *dns_find_tkey(struct dns_server_tkey_store *store,
>  				      const char *name);
>  WERROR dns_verify_tsig(struct dns_server *dns,
> diff --git a/source4/dns_server/dns_utils.c b/source4/dns_server/dns_utils.c
> index ee35bd223f7..081ee33caee 100644
> --- a/source4/dns_server/dns_utils.c
> +++ b/source4/dns_server/dns_utils.c
> @@ -201,23 +201,3 @@ WERROR dns_name2dn(struct dns_server *dns,
>  				  mem_ctx, name, dn);
>  }
>  
> -WERROR dns_generate_options(struct dns_server *dns,
> -			    TALLOC_CTX *mem_ctx,
> -			    struct dns_res_rec **options)
> -{
> -	struct dns_res_rec *o;
> -
> -	o = talloc_zero(mem_ctx, struct dns_res_rec);
> -	if (o == NULL) {
> -		return WERR_NOT_ENOUGH_MEMORY;
> -	}
> -	o->name = NULL;
> -	o->rr_type = DNS_QTYPE_OPT;
> -	/* This is ugly, but RFC2671 wants the payload size in this field */
> -	o->rr_class = (enum dns_qclass) dns->max_payload;
> -	o->ttl = 0;
> -	o->length = 0;
> -
> -	*options = o;
> -	return WERR_OK;
> -}
> -- 
> 2.11.0
> 
> 
> From 0b541de0da0afbd5b00cd39eed527d85f3d63028 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Sun, 31 Dec 2017 11:02:45 +0100
> Subject: [PATCH 10/10] dns_server: Remove "max_payload" from dns_server
> 
> This would have to be retrieved from the interface type we have I guess.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source4/dns_server/dns_server.c | 2 --
>  source4/dns_server/dns_server.h | 1 -
>  2 files changed, 3 deletions(-)
> 
> diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c
> index cd293b82522..9128c626cb9 100644
> --- a/source4/dns_server/dns_server.c
> +++ b/source4/dns_server/dns_server.c
> @@ -831,8 +831,6 @@ static void dns_task_init(struct task_server *task)
>  	}
>  
>  	dns->task = task;
> -	/*FIXME: Make this a configurable option */
> -	dns->max_payload = 4096;
>  
>  	dns->server_credentials = cli_credentials_init(dns);
>  	if (!dns->server_credentials) {
> diff --git a/source4/dns_server/dns_server.h b/source4/dns_server/dns_server.h
> index 7c5c09e57c0..05ef302680f 100644
> --- a/source4/dns_server/dns_server.h
> +++ b/source4/dns_server/dns_server.h
> @@ -50,7 +50,6 @@ struct dns_server {
>  	struct dns_server_zone *zones;
>  	struct dns_server_tkey_store *tkeys;
>  	struct cli_credentials *server_credentials;
> -	uint16_t max_payload;
>  };
>  
>  struct dns_request_state {
> -- 
> 2.11.0
> 




More information about the samba-technical mailing list