Patch format template for submission

Dimitris Gravanis dimgrav at gmail.com
Sat Aug 26 18:04:18 UTC 2017


Hi,

I tinkered (reset and pushed from scratch that is) with my samba-fork 
<https://github.com/dimgrav/samba> to produce the cleanest possible 
patch submission with git format-patch.

I did my best to make it organized and easy to review.

If you think that the format is fine, then I'll mail my patches for the 
final GSoC submission to the list either tonight, or some time tomorrow 
morning.

Cheers, Dimitris

-- 
Δ. Γραβάνης | D. Gravanis

-------------- next part --------------
From 8b23b8b710f6f12a1ac71fa3cedc3134e1b08a9f Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:06:55 +0300
Subject: [PATCH 01/19] cli-fn: added client function libraries and README

---
 libcli/dns/cli-fn/README.md       |  17 +++
 libcli/dns/cli-fn/client_crypto.c | 203 ++++++++++++++++++++++++++++++++++
 libcli/dns/cli-fn/dns_tcp.c       | 227 ++++++++++++++++++++++++++++++++++++++
 libcli/dns/cli-fn/dns_udp.c       | 178 ++++++++++++++++++++++++++++++
 4 files changed, 625 insertions(+)
 create mode 100644 libcli/dns/cli-fn/README.md
 create mode 100644 libcli/dns/cli-fn/client_crypto.c
 create mode 100644 libcli/dns/cli-fn/dns_tcp.c
 create mode 100644 libcli/dns/cli-fn/dns_udp.c

diff --git a/libcli/dns/cli-fn/README.md b/libcli/dns/cli-fn/README.md
new file mode 100644
index 0000000..bdd66ba
--- /dev/null
+++ b/libcli/dns/cli-fn/README.md
@@ -0,0 +1,17 @@
+## README: features
+
+The individual function libraries that are incorporated in cli_dns.c, 
+to provide client-side DNS call features. Each library comes with a 
+corresponding test suite in libcli/dns/cmocka-tests/ directory.
+
+Descriptions
+
+* client_crypto.c: GSS-TSIG client-side handling for signed packets
+* dns_tcp.c: TCP client-side DNS call handling
+* dns_udp.c: Small async DNS library with socketwrapper support
+
+It is highly recommended that the above libraries will be used for 
+adding and testing features in  libcli/dns individually, **BEFORE** 
+implementing any changes in libcli/cli_dns.c library.
+
+*Associated headers are found in libcli/dns/*
diff --git a/libcli/dns/cli-fn/client_crypto.c b/libcli/dns/cli-fn/client_crypto.c
new file mode 100644
index 0000000..6ba9a62
--- /dev/null
+++ b/libcli/dns/cli-fn/client_crypto.c
@@ -0,0 +1,203 @@
+/* GSS-TSIG client-side handling for signed packets.
+ *
+ * --WORK IN PROGRESS--
+ *
+ * Copyright (C) 2017 Dimitrios Gravanis
+ * 
+ * Based on the existing work on Samba Unix SMB/CIFS implementation by
+ * Kai Blin Copyright (C) 2011, Stefan Metzmacher Copyright (C) 2014.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/crypto/hmacmd5.h"
+#include "libcli/util/ntstatus.h"
+#include "auth/auth.h"
+#include "auth/gensec/gensec.h"
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "source4/dns_server/dns_server.h"
+#include "libcli/dns/libtsig.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_DNS
+
+/* 
+ * make a copy of the original tsig record
+ * with null rdata values
+ */
+static WERROR dns_empty_tsig(TALLOC_CTX *mem_ctx,
+					struct dns_res_rec *orig_record,
+					struct dns_res_rec *empty_record)
+{
+	/* see /libprc/idl/dns.idl for PIDL tsig definition */
+	empty_record->name = talloc_strdup(mem_ctx, orig_record->name);
+	W_ERROR_HAVE_NO_MEMORY(empty_record->name);
+	empty_record->rr_type = orig_record->rr_type;
+	empty_record->rr_class = orig_record->rr_class;
+	empty_record->ttl = orig_record->ttl;
+	empty_record->length = orig_record->length;
+	
+	/* empty tsig rdata field in the new record */
+	/* the smooth way! */
+	empty_record->rdata.tsig_record.algorithm_name = talloc_strdup(mem_ctx, 
+							orig_record->rdata.tsig_record.algorithm_name);
+	W_ERROR_HAVE_NO_MEMORY(empty_record->rdata.tsig_record.algorithm_name);
+	ZERO_STRUCT(empty_record->rdata.tsig_record);
+
+	return WERR_OK;
+}
+
+/* identify tkey in record */
+struct dns_client_tkey *dns_find_cli_tkey(struct dns_client_tkey_store *store,
+				        const char *name)
+{
+	struct dns_client_tkey *tkey = NULL;
+	uint16_t i = 0;
+
+	do {
+		struct dns_client_tkey *tmp_key = store->tkeys[i];
+
+		i++;
+		i %= TKEY_BUFFER_SIZE;
+
+		if (tmp_key == NULL) {
+			continue;
+		}
+		if (strcmp(name, tmp_key->name) == 0) {
+			tkey = tmp_key;
+			break;
+		}
+	} while (i != 0);
+
+	return tkey;
+}
+
+/* generate signature and rebuild packet with TSIG */
+WERROR dns_cli_generate_tsig(struct dns_client *dns,
+		       		TALLOC_CTX *mem_ctx,
+		       		struct dns_request_cli_state *state,
+		   			struct dns_name_packet *packet,
+	      			DATA_BLOB *in)
+{
+	int tsig_flag = 0;
+	struct dns_client_tkey *tkey = NULL;
+	uint16_t i, arcount = 0;
+	DATA_BLOB tsig_blob, fake_tsig_blob;
+	uint8_t *buffer = NULL;
+	size_t buffer_len = 0, packet_len = 0;
+	
+	NTSTATUS gen_sig;
+	DATA_BLOB sig = (DATA_BLOB) {.data = NULL, .length = 0};
+	struct dns_res_rec *tsig = NULL;
+	time_t current_time = time(NULL);
+
+	/* find TSIG record in inbound packet */
+	for (i=0; i < packet->arcount; i++) {
+		if (packet->additional[i].rr_type == DNS_QTYPE_TSIG) {
+			tsig_flag = 1;
+			break;
+		}
+	}
+	if (tsig_flag != 1) {
+		return WERR_OK;
+	}
+
+	/* check TSIG record format consistency */
+	if (tsig_flag == 1 && i + 1 != packet->arcount) {
+		DEBUG(1, ("TSIG format inconsistent!\n"));
+		return DNS_ERR(FORMAT_ERROR);
+	}
+
+	/* save the keyname from the TSIG request to add MAC later */
+	tkey = dns_find_cli_tkey(dns->tkeys, state->tsig->name);
+	if (tkey == NULL) {
+		state->key_name = talloc_strdup(state->mem_ctx,
+						state->tsig->name);
+		if (state->key_name == NULL) {
+			return WERR_NOT_ENOUGH_MEMORY;
+		}
+		state->tsig_error = DNS_RCODE_BADKEY;
+		return DNS_ERR(NOTAUTH);
+	}
+	state->key_name = talloc_strdup(state->mem_ctx, tkey->name);
+	if (state->key_name == NULL) {
+		return WERR_NOT_ENOUGH_MEMORY;
+	}
+
+	/* 
+	 * preserve input packet but remove TSIG record bytes
+	 * then count down the arcount field in the packet 
+	 */
+	packet_len = in->length - tsig_blob.length;
+	packet->arcount--;
+	arcount = RSVAL(buffer, 10);
+	RSSVAL(buffer, 10, arcount-1);
+
+	/* append fake_tsig_blob to buffer */
+	buffer_len = packet_len + fake_tsig_blob.length;
+	buffer = talloc_zero_array(mem_ctx, uint8_t, buffer_len);
+	if (buffer == NULL) {
+		return WERR_NOT_ENOUGH_MEMORY;
+	}
+	
+	memcpy(buffer, in->data, packet_len);
+	memcpy(buffer + packet_len, fake_tsig_blob.data, fake_tsig_blob.length);
+
+	/* generate signature */
+	gen_sig = gensec_sign_packet(tkey->gensec, mem_ctx, buffer, buffer_len,
+				    buffer, buffer_len, &sig);
+
+	/* get MAC size and save MAC to sig*/
+	sig.length = state->tsig->rdata.tsig_record.mac_size;
+	sig.data = talloc_memdup(mem_ctx, state->tsig->rdata.tsig_record.mac, sig.length);
+	if (sig.data == NULL) {
+		return WERR_NOT_ENOUGH_MEMORY;
+	}
+
+	/* rebuild packet with MAC from gensec_sign_packet() */
+	tsig = talloc_zero(mem_ctx, struct dns_res_rec);
+
+	tsig->name = talloc_strdup(tsig, state->key_name);
+	if (tsig->name == NULL) {
+		return WERR_NOT_ENOUGH_MEMORY;
+	}
+	tsig->rr_class = DNS_QCLASS_ANY;
+	tsig->rr_type = DNS_QTYPE_TSIG;
+	tsig->ttl = 0;
+	tsig->length = UINT16_MAX;
+	tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig, "gss-tsig");
+	tsig->rdata.tsig_record.time_prefix = 0;
+	tsig->rdata.tsig_record.time = current_time;
+	tsig->rdata.tsig_record.fudge = 300;
+	tsig->rdata.tsig_record.error = state->tsig_error;
+	tsig->rdata.tsig_record.original_id = packet->id;
+	tsig->rdata.tsig_record.other_size = 0;
+	tsig->rdata.tsig_record.other_data = NULL;
+	if (sig.length > 0) {
+		tsig->rdata.tsig_record.mac_size = sig.length;
+		tsig->rdata.tsig_record.mac = talloc_memdup(tsig, sig.data, sig.length);
+	}
+	
+	packet->additional = talloc_realloc(mem_ctx, packet->additional,
+					    struct dns_res_rec,
+					    packet->arcount + 1);
+	if (packet->additional == NULL) {
+		return WERR_NOT_ENOUGH_MEMORY;
+	}
+	packet->arcount++;
+	
+	return WERR_OK;
+}
diff --git a/libcli/dns/cli-fn/dns_tcp.c b/libcli/dns/cli-fn/dns_tcp.c
new file mode 100644
index 0000000..a6096e2
--- /dev/null
+++ b/libcli/dns/cli-fn/dns_tcp.c
@@ -0,0 +1,227 @@
+/* TCP client-side DNS call handling.
+ * 
+ * --WORK IN PROGRESS--
+ *
+ * Copyright (C) 2017 Dimitrios Gravanis
+ * 
+ * Based on the existing work on Samba Unix SMB/CIFS implementation by
+ * Kai Blin Copyright (C) 2011, Stefan Metzmacher Copyright (C) 2014
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/tsocket/tsocket.h"
+#include "libcli/util/tstream.h"
+#include "source4/smbd/service_task.h"
+#include "source4/smbd/service_stream.h"
+#include "source4/lib/stream/packet.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_dns.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+#include "lib/tsocket/tsocket.h"
+#include "libcli/dns/libudp.h"
+#include "libcli/dns/libtcp.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_werror.h"
+#include "lib/util/samba_util.h"
+#include "libcli/util/error.h"
+#include "librpc/gen_ndr/dns.h"
+
+#define DNS_REQUEST_TIMEOUT 2
+
+/*** TCP Requests ***/
+
+/* TCP callbacks */
+void dns_tcp_req_recv_reply(struct tevent_req *subreq);
+void dns_tcp_req_done(struct tevent_req *subreq);
+
+/* tcp request to send */
+struct tevent_req *dns_tcp_req_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					const char *server_addr_string,
+					struct iovec *vector,
+					size_t count)
+{
+	struct tevent_req *req, *subreq, *socreq;
+	struct dns_tcp_request_state *state;
+	struct tsocket_address *local_address, *remote_address;
+	struct tstream_context *stream;
+	int req_ret, soc_ret, err;
+
+	req = tevent_req_create(mem_ctx, &state, struct dns_tcp_request_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+
+	/* check for connected sockets and use if any */
+	req_ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
+						&local_address);
+	if (req_ret != 0) {
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
+	}
+
+	req_ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
+						DNS_SERVICE_PORT, &remote_address);
+	if (req_ret != 0) {
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
+	}
+
+	/* must be reviewed! */
+	soc_ret = tstream_inet_tcp_connect_recv(socreq, err, mem_ctx, stream, NULL);
+	TALLOC_FREE(socreq);
+	if (soc_ret == -1 && err != 0) {
+		tevent_req_error(socreq, err);
+		return tevent_req_post(req, ev);
+	}
+
+	socreq = tstream_inet_tcp_connect_send(mem_ctx, ev, local_address, remote_address);
+	if (tevent_req_nomem(socreq, req)) {
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(socreq, dns_tcp_req_send, req);
+
+	state->tstream = stream;
+	state->v_count = count;
+
+	subreq = tstream_writev_send(mem_ctx, ev, stream, vector, count);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	if (!tevent_req_set_endtime(req, ev,
+		timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
+		tevent_req_oom(req);
+		return tevent_req_post(req, ev);
+	}
+
+	/* associate callback */
+	tevent_req_set_callback(subreq, dns_tcp_req_recv_reply, req);
+	
+	return req;
+}
+
+/* get buffer and wait to receive server response */
+void dns_tcp_req_recv_reply(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);
+	ssize_t stream_len;
+	int err = 0;
+	NTSTATUS status;
+
+	stream_len = tstream_writev_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+
+	if (stream_len == -1 && err != 0) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	if (stream_len != state->v_count) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	/* response loop */
+	struct dns_tcp_connection *dns_conn = tevent_req_callback_data(subreq,
+			struct dns_tcp_connection);
+	struct tsocket_address *local_address, *server_address;
+	struct dns_client *dns = dns_conn->dns_socket->dns; // uses server iface
+	struct dns_tcp_call *call;
+
+	call = talloc(dns_conn, struct dns_tcp_call);
+	if (call == NULL) {
+		DEBUG(1, ("dns_tcp_req_recv_reply: NULL call\n"));
+		return;
+	}
+	call->dns_conn = dns_conn;
+
+	status = tstream_read_pdu_blob_recv(subreq, call, &call->in);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("tstream_read_pdu_blob_recv: error %s\n", nt_errstr(status)));
+		return;
+	}
+	
+	if (subreq == NULL) {
+		DEBUG(1, ("dns_tcp_req_recv_reply: NULL subreq\n"));
+		return;
+	}
+	tevent_req_set_callback(subreq, dns_tcp_req_done, call);
+	TALLOC_FREE(subreq);
+	
+	subreq = tstream_read_pdu_blob_send(dns_conn,
+					    dns_conn->conn->event.ctx,
+					    dns_conn->tstream,
+					    2, 
+					    packet_full_request_u16,
+					    dns_conn);
+	/* loop callback */
+	tevent_req_set_callback(subreq, dns_tcp_req_recv_reply, dns_conn);
+}
+
+/* callback status */
+void dns_tcp_req_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
+	struct dns_tcp_connection *dns_conn = tevent_req_callback_data(subreq,
+			struct dns_tcp_connection);
+	struct dns_tcp_call *call;
+	
+	WERROR err;
+	/*
+	err = dns_process_recv(subreq, call, &call->out);
+	
+	TALLOC_FREE(subreq);
+	*/
+	if (!W_ERROR_IS_OK(err)) {
+		DEBUG(1, ("dns_req_done error: %s\n", win_errstr(err)));
+		return;
+	}
+	
+	TALLOC_FREE(subreq);
+	tevent_req_done(req);
+}
+
+/*  receiver */
+int dns_tcp_req_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;
+
+	/* tevent_req_is_unix_error defined in tevent_unix.h */
+	if (tevent_req_is_unix_error(req, &err)) {
+		tevent_req_received(req);
+		return err;
+	}
+
+	*reply = talloc_move(mem_ctx, &state->reply);
+	*reply_len = state->reply_len;
+	tevent_req_received(req);
+
+	return 0;
+}
diff --git a/libcli/dns/cli-fn/dns_udp.c b/libcli/dns/cli-fn/dns_udp.c
new file mode 100644
index 0000000..f8a5495
--- /dev/null
+++ b/libcli/dns/cli-fn/dns_udp.c
@@ -0,0 +1,178 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Small async DNS library for Samba with socketwrapper support
+
+   Copyright (C) 2010 Kai Blin  <kai at samba.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/tsocket/tsocket.h"
+#include "libcli/dns/libudp.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/samba_util.h"
+#include "libcli/util/error.h"
+#include "librpc/gen_ndr/dns.h"
+
+struct dns_udp_request_state {
+	struct tevent_context *ev;
+	struct tdgram_context *dgram;
+	size_t query_len;
+	uint8_t *reply;
+	size_t reply_len;
+};
+
+#define DNS_REQUEST_TIMEOUT 2
+
+/* Declare callback functions used below. */
+void dns_udp_request_get_reply(struct tevent_req *subreq);
+void dns_udp_request_done(struct tevent_req *subreq);
+
+struct tevent_req *dns_udp_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_udp_request_state *state;
+	struct tsocket_address *local_addr, *server_addr;
+	struct tdgram_context *dgram;
+	int ret;
+
+	req = tevent_req_create(mem_ctx, &state, struct dns_udp_request_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+
+	/* Use connected UDP sockets */
+	ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
+						&local_addr);
+	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, &server_addr);
+	if (ret != 0) {
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
+	}
+
+	ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
+	if (ret != 0) {
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
+	}
+
+	state->dgram = dgram;
+	state->query_len = query_len;
+
+	dump_data(10, query, query_len);
+
+	subreq = tdgram_sendto_send(state, ev, dgram, query, query_len, NULL);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	if (!tevent_req_set_endtime(req, ev,
+				timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
+		tevent_req_oom(req);
+		return tevent_req_post(req, ev);
+	}
+
+	tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
+	return req;
+}
+
+void dns_udp_request_get_reply(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(subreq,
+						struct tevent_req);
+	struct dns_udp_request_state *state = tevent_req_data(req,
+						struct dns_udp_request_state);
+	ssize_t len;
+	int err = 0;
+
+	len = tdgram_sendto_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+
+	if (len == -1 && err != 0) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	if (len != state->query_len) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+
+	tevent_req_set_callback(subreq, dns_udp_request_done, req);
+}
+
+void dns_udp_request_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(subreq,
+						struct tevent_req);
+	struct dns_udp_request_state *state = tevent_req_data(req,
+						struct dns_udp_request_state);
+
+	ssize_t len;
+	int err = 0;
+
+	len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
+	TALLOC_FREE(subreq);
+
+	if (len == -1 && err != 0) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	state->reply_len = len;
+	dump_data(10, state->reply, state->reply_len);
+	tevent_req_done(req);
+}
+
+int dns_udp_request_recv(struct tevent_req *req,
+			 TALLOC_CTX *mem_ctx,
+			 uint8_t **reply,
+			 size_t *reply_len)
+{
+	struct dns_udp_request_state *state = tevent_req_data(req,
+			struct dns_udp_request_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		tevent_req_received(req);
+		return err;
+	}
+
+	*reply = talloc_move(mem_ctx, &state->reply);
+	*reply_len = state->reply_len;
+	tevent_req_received(req);
+
+	return 0;
+}
-- 
2.7.4


From 7f50b1c2264c5d6690293548c509cf99e8baf1ed Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:10:26 +0300
Subject: [PATCH 02/19] cli_dns: (replaces dns.c) client-side UDP/TCP req
 handler with GSS-TSIG crypto

---
 libcli/dns/cli_dns.c | 545 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 545 insertions(+)
 create mode 100644 libcli/dns/cli_dns.c

diff --git a/libcli/dns/cli_dns.c b/libcli/dns/cli_dns.c
new file mode 100644
index 0000000..0be4154
--- /dev/null
+++ b/libcli/dns/cli_dns.c
@@ -0,0 +1,545 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   DNS UDP/TCP call handler with socketwrapper support and TSIG generation
+
+   Copyright (C) 2017 Dimitrios Gravanis <dimgrav at gmail.com>
+
+   Based on:
+
+   DNS server startup
+   DNS structures
+   Small async DNS library for Samba with socketwrapper support
+
+   Copyright (C) 2010 Kai Blin  <kai at samba.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* TSIG generation */
+#include "includes.h"
+#include "lib/crypto/hmacmd5.h"
+#include "libcli/util/ntstatus.h"
+#include "auth/auth.h"
+#include "auth/gensec/gensec.h"
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "source4/dns_server/dns_server.h"
+#include "libcli/dns/libtsig.h"
+
+/* DNS call send/recv() */
+#include "replace.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/tsocket/tsocket.h"
+#include "libcli/util/tstream.h"
+#include "source4/smbd/service_task.h"
+#include "source4/smbd/service_stream.h"
+#include "source4/lib/stream/packet.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_dns.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+#include "lib/tsocket/tsocket.h"
+#include "libcli/dns/libudp.h"
+#include "libcli/dns/libtcp.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_werror.h"
+#include "lib/util/samba_util.h"
+#include "libcli/util/error.h"
+#include "librpc/gen_ndr/dns.h"
+
+#define DNS_REQUEST_TIMEOUT 2
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_DNS
+
+/*** UDP Requests ***/
+
+/* UDP state struct */
+struct dns_udp_request_state {
+	struct tevent_context *ev;
+	struct tdgram_context *dgram;
+	size_t query_len;
+	uint8_t *reply;
+	size_t reply_len;
+};
+
+/* UDP callbacks */
+void dns_udp_request_get_reply(struct tevent_req *subreq);
+void dns_udp_request_done(struct tevent_req *subreq);
+
+/* udp request to send */
+struct tevent_req *dns_udp_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_udp_request_state *state;
+	struct tsocket_address *local_addr, *server_addr;
+	struct tdgram_context *dgram;
+	int ret;
+
+	req = tevent_req_create(mem_ctx, &state, struct dns_udp_request_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+
+	/* Use connected UDP sockets */
+	ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
+						&local_addr);
+	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, &server_addr);
+	if (ret != 0) {
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
+	}
+
+	ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
+	if (ret != 0) {
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
+	}
+
+	state->dgram = dgram;
+	state->query_len = query_len;
+
+	dump_data(10, query, query_len);
+
+	subreq = tdgram_sendto_send(state, ev, dgram, query, query_len, NULL);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	if (!tevent_req_set_endtime(req, ev,
+				timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
+		tevent_req_oom(req);
+		return tevent_req_post(req, ev);
+	}
+
+	tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
+	return req;
+}
+
+/* wait for server reply */
+void dns_udp_request_get_reply(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(subreq,
+						struct tevent_req);
+	struct dns_udp_request_state *state = tevent_req_data(req,
+						struct dns_udp_request_state);
+	ssize_t len;
+	int err = 0;
+
+	len = tdgram_sendto_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+
+	if (len == -1 && err != 0) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	if (len != state->query_len) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+
+	tevent_req_set_callback(subreq, dns_udp_request_done, req);
+}
+
+/* callback status */
+void dns_udp_request_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(subreq,
+						struct tevent_req);
+	struct dns_udp_request_state *state = tevent_req_data(req,
+						struct dns_udp_request_state);
+
+	ssize_t len;
+	int err = 0;
+
+	len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
+	TALLOC_FREE(subreq);
+
+	if (len == -1 && err != 0) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	state->reply_len = len;
+	dump_data(10, state->reply, state->reply_len);
+	tevent_req_done(req);
+}
+
+/* receiver */
+int dns_udp_request_recv(struct tevent_req *req,
+			 TALLOC_CTX *mem_ctx,
+			 uint8_t **reply,
+			 size_t *reply_len)
+{
+	struct dns_udp_request_state *state = tevent_req_data(req,
+			struct dns_udp_request_state);
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		tevent_req_received(req);
+		return err;
+	}
+
+	*reply = talloc_move(mem_ctx, &state->reply);
+	*reply_len = state->reply_len;
+	tevent_req_received(req);
+
+	return 0;
+}
+
+/*** TCP Requests ***/
+
+/* TCP callbacks */
+void dns_tcp_req_recv_reply(struct tevent_req *subreq);
+void dns_tcp_req_done(struct tevent_req *subreq);
+
+/* tcp request to send */
+struct tevent_req *dns_tcp_req_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					const char *server_addr_string,
+					struct iovec *vector,
+					size_t count)
+{
+	struct tevent_req *req, *subreq, *socreq;
+	struct dns_tcp_request_state *state;
+	struct tsocket_address *local_address, *remote_address;
+	struct tstream_context *stream;
+	int req_ret, soc_ret, err;
+
+	req = tevent_req_create(mem_ctx, &state, struct dns_tcp_request_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+
+	/* check for connected sockets and use if any */
+	req_ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
+						&local_address);
+	if (req_ret != 0) {
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
+	}
+
+	req_ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
+						DNS_SERVICE_PORT, &remote_address);
+	if (req_ret != 0) {
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
+	}
+
+	/* must be reviewed! */
+	soc_ret = tstream_inet_tcp_connect_recv(socreq, err, mem_ctx, stream, NULL);
+	TALLOC_FREE(socreq);
+	if (soc_ret == -1 && err != 0) {
+		tevent_req_error(socreq, err);
+		return tevent_req_post(req, ev);
+	}
+
+	socreq = tstream_inet_tcp_connect_send(mem_ctx, ev, local_address, remote_address);
+	if (tevent_req_nomem(socreq, req)) {
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(socreq, dns_tcp_req_send, req);
+
+	state->tstream = stream;
+	state->v_count = count;
+
+	subreq = tstream_writev_send(mem_ctx, ev, stream, vector, count);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	if (!tevent_req_set_endtime(req, ev,
+		timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
+		tevent_req_oom(req);
+		return tevent_req_post(req, ev);
+	}
+
+	/* associate callback */
+	tevent_req_set_callback(subreq, dns_tcp_req_recv_reply, req);
+	
+	return req;
+}
+
+/* get buffer and wait to receive server response */
+void dns_tcp_req_recv_reply(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);
+	ssize_t stream_len;
+	int err = 0;
+	NTSTATUS status;
+
+	stream_len = tstream_writev_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+
+	if (stream_len == -1 && err != 0) {
+		tevent_req_error(req, err);
+		return;
+	}
+
+	if (stream_len != state->v_count) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	/* response loop */
+	struct dns_tcp_connection *dns_conn = tevent_req_callback_data(subreq,
+			struct dns_tcp_connection);
+	struct tsocket_address *local_address, *server_address;
+	struct dns_client *dns = dns_conn->dns_socket->dns; // uses server iface
+	struct dns_tcp_call *call;
+
+	call = talloc(dns_conn, struct dns_tcp_call);
+	if (call == NULL) {
+		DEBUG(1, ("dns_tcp_req_recv_reply: NULL call\n"));
+		return;
+	}
+	call->dns_conn = dns_conn;
+
+	status = tstream_read_pdu_blob_recv(subreq, call, &call->in);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("tstream_read_pdu_blob_recv: error %s\n", nt_errstr(status)));
+		return;
+	}
+	
+	if (subreq == NULL) {
+		DEBUG(1, ("dns_tcp_req_recv_reply: NULL subreq\n"));
+		return;
+	}
+	tevent_req_set_callback(subreq, dns_tcp_req_done, call);
+	TALLOC_FREE(subreq);
+	
+	subreq = tstream_read_pdu_blob_send(dns_conn,
+					    dns_conn->conn->event.ctx,
+					    dns_conn->tstream,
+					    2, 
+					    packet_full_request_u16,
+					    dns_conn);
+	/* loop callback */
+	tevent_req_set_callback(subreq, dns_tcp_req_recv_reply, dns_conn);
+}
+
+/* callback status */
+void dns_tcp_req_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
+	struct dns_tcp_connection *dns_conn = tevent_req_callback_data(subreq,
+			struct dns_tcp_connection);
+	struct dns_tcp_call *call;
+	
+	WERROR err;
+	/*
+	err = dns_process_recv(subreq, call, &call->out);
+	
+	TALLOC_FREE(subreq);
+	*/
+	if (!W_ERROR_IS_OK(err)) {
+		DEBUG(1, ("dns_req_done error: %s\n", win_errstr(err)));
+		return;
+	}
+	
+	TALLOC_FREE(subreq);
+	tevent_req_done(req);
+}
+
+/*  receiver */
+int dns_tcp_req_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;
+
+	/* tevent_req_is_unix_error defined in tevent_unix.h */
+	if (tevent_req_is_unix_error(req, &err)) {
+		tevent_req_received(req);
+		return err;
+	}
+
+	*reply = talloc_move(mem_ctx, &state->reply);
+	*reply_len = state->reply_len;
+	tevent_req_received(req);
+
+	return 0;
+}
+
+/*** TSIG generation ***/
+
+/* identify tkey in record */
+struct dns_client_tkey *dns_find_cli_tkey(struct dns_client_tkey_store *store,
+				        const char *name)
+{
+	struct dns_client_tkey *tkey = NULL;
+	uint16_t i = 0;
+
+	do {
+		struct dns_client_tkey *tmp_key = store->tkeys[i];
+
+		i++;
+		i %= TKEY_BUFFER_SIZE;
+
+		if (tmp_key == NULL) {
+			continue;
+		}
+		if (strcmp(name, tmp_key->name) == 0) {
+			tkey = tmp_key;
+			break;
+		}
+	} while (i != 0);
+
+	return tkey;
+}
+
+/* generate signature and rebuild packet with TSIG */
+WERROR dns_cli_generate_tsig(struct dns_client *dns,
+		       		TALLOC_CTX *mem_ctx,
+		       		struct dns_request_cli_state *state,
+		   			struct dns_name_packet *packet,
+	      			DATA_BLOB *in)
+{
+	int tsig_flag = 0;
+	struct dns_client_tkey *tkey = NULL;
+	uint16_t i, arcount = 0;
+	DATA_BLOB tsig_blob, fake_tsig_blob;
+	uint8_t *buffer = NULL;
+	size_t buffer_len = 0, packet_len = 0;
+	
+	NTSTATUS gen_sig;
+	DATA_BLOB sig = (DATA_BLOB) {.data = NULL, .length = 0};
+	struct dns_res_rec *tsig = NULL;
+	time_t current_time = time(NULL);
+
+	/* find TSIG record in inbound packet */
+	for (i=0; i < packet->arcount; i++) {
+		if (packet->additional[i].rr_type == DNS_QTYPE_TSIG) {
+			tsig_flag = 1;
+			break;
+		}
+	}
+	if (tsig_flag != 1) {
+		return WERR_OK;
+	}
+
+	/* check TSIG record format consistency */
+	if (tsig_flag == 1 && i + 1 != packet->arcount) {
+		DEBUG(1, ("TSIG format inconsistent!\n"));
+		return DNS_ERR(FORMAT_ERROR);
+	}
+
+	/* save the keyname from the TSIG request to add MAC later */
+	tkey = dns_find_cli_tkey(dns->tkeys, state->tsig->name);
+	if (tkey == NULL) {
+		state->key_name = talloc_strdup(state->mem_ctx,
+						state->tsig->name);
+		if (state->key_name == NULL) {
+			return WERR_NOT_ENOUGH_MEMORY;
+		}
+		state->tsig_error = DNS_RCODE_BADKEY;
+		return DNS_ERR(NOTAUTH);
+	}
+	state->key_name = talloc_strdup(state->mem_ctx, tkey->name);
+	if (state->key_name == NULL) {
+		return WERR_NOT_ENOUGH_MEMORY;
+	}
+
+	/* 
+	 * preserve input packet but remove TSIG record bytes
+	 * then count down the arcount field in the packet 
+	 */
+	packet_len = in->length - tsig_blob.length;
+	packet->arcount--;
+	arcount = RSVAL(buffer, 10);
+	RSSVAL(buffer, 10, arcount-1);
+
+	/* append fake_tsig_blob to buffer */
+	buffer_len = packet_len + fake_tsig_blob.length;
+	buffer = talloc_zero_array(mem_ctx, uint8_t, buffer_len);
+	if (buffer == NULL) {
+		return WERR_NOT_ENOUGH_MEMORY;
+	}
+	
+	memcpy(buffer, in->data, packet_len);
+	memcpy(buffer + packet_len, fake_tsig_blob.data, fake_tsig_blob.length);
+
+	/* generate signature */
+	gen_sig = gensec_sign_packet(tkey->gensec, mem_ctx, buffer, buffer_len,
+				    buffer, buffer_len, &sig);
+
+	/* get MAC size and save MAC to sig*/
+	sig.length = state->tsig->rdata.tsig_record.mac_size;
+	sig.data = talloc_memdup(mem_ctx, state->tsig->rdata.tsig_record.mac, sig.length);
+	if (sig.data == NULL) {
+		return WERR_NOT_ENOUGH_MEMORY;
+	}
+
+	/* rebuild packet with MAC from gensec_sign_packet() */
+	tsig = talloc_zero(mem_ctx, struct dns_res_rec);
+
+	tsig->name = talloc_strdup(tsig, state->key_name);
+	if (tsig->name == NULL) {
+		return WERR_NOT_ENOUGH_MEMORY;
+	}
+	tsig->rr_class = DNS_QCLASS_ANY;
+	tsig->rr_type = DNS_QTYPE_TSIG;
+	tsig->ttl = 0;
+	tsig->length = UINT16_MAX;
+	tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig, "gss-tsig");
+	tsig->rdata.tsig_record.time_prefix = 0;
+	tsig->rdata.tsig_record.time = current_time;
+	tsig->rdata.tsig_record.fudge = 300;
+	tsig->rdata.tsig_record.error = state->tsig_error;
+	tsig->rdata.tsig_record.original_id = packet->id;
+	tsig->rdata.tsig_record.other_size = 0;
+	tsig->rdata.tsig_record.other_data = NULL;
+	if (sig.length > 0) {
+		tsig->rdata.tsig_record.mac_size = sig.length;
+		tsig->rdata.tsig_record.mac = talloc_memdup(tsig, sig.data, sig.length);
+	}
+	
+	packet->additional = talloc_realloc(mem_ctx, packet->additional,
+					    struct dns_res_rec,
+					    packet->arcount + 1);
+	if (packet->additional == NULL) {
+		return WERR_NOT_ENOUGH_MEMORY;
+	}
+	packet->arcount++;
+	
+	return WERR_OK;
+}
\ No newline at end of file
-- 
2.7.4


From 523abeeb60bf8966f6419eeb54d3161348d50dd9 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:11:37 +0300
Subject: [PATCH 03/19] cli_tests: test suite for client functionality using
 cmocka

---
 libcli/dns/cmocka-tests/cli_tests.c | 319 ++++++++++++++++++++++++++++++++++++
 1 file changed, 319 insertions(+)
 create mode 100644 libcli/dns/cmocka-tests/cli_tests.c

diff --git a/libcli/dns/cmocka-tests/cli_tests.c b/libcli/dns/cmocka-tests/cli_tests.c
new file mode 100644
index 0000000..9e629e3
--- /dev/null
+++ b/libcli/dns/cmocka-tests/cli_tests.c
@@ -0,0 +1,319 @@
+/* Unix SMB/CIFS implementation.
+ * 
+ * Test suite for:
+ * DNS UDP/TCP call handler with socketwrapper support and TSIG generation
+ *
+ * Copyright 2017 (c) Dimitrios Gravanis
+ *
+ * Uses cmocka C testing API.
+ * Copyright 2013 (c) Andreas Schneider <asn at cynapses.org>
+ *                    Jakub Hrozek <jakub.hrozek at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* test requirements */
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include "libcli/dns/cli_dns.c"
+
+/* TSIG generation */
+#include "includes.h"
+#include "lib/crypto/hmacmd5.h"
+#include "libcli/util/ntstatus.h"
+#include "auth/auth.h"
+#include "auth/gensec/gensec.h"
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "source4/dns_server/dns_server.h"
+#include "libcli/dns/libtsig.h"
+
+/* DNS call send/recv() */
+#include "replace.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/tsocket/tsocket.h"
+#include "libcli/util/tstream.h"
+#include "source4/smbd/service_task.h"
+#include "source4/smbd/service_stream.h"
+#include "source4/lib/stream/packet.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_dns.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+#include "lib/tsocket/tsocket.h"
+#include "libcli/dns/libudp.h"
+#include "libcli/dns/libtcp.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_werror.h"
+#include "lib/util/samba_util.h"
+#include "libcli/util/error.h"
+#include "librpc/gen_ndr/dns.h"
+
+#define DNS_REQUEST_TIMEOUT 2
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_DNS
+
+
+/* --- INCOMPLETE ---*/
+
+/** test tcp send/recv functionality **/
+
+/* calls fail() if TCP test_req is NULL */
+static void test_req_send(void **state)
+{
+	/* incomplete */
+	TALLOC_CTX *mem_ctx;
+	struct tevent_context *test_ev;
+	const char *test_server_addr_string = "TEST_SRVR_ADDR";
+	struct iovec *test_vector;
+	size_t test_count = SIZE_MAX;
+
+	struct tevent_req *test_req = dns_tcp_req_send(mem_ctx, test_ev,
+			test_server_addr_string, test_vector, test_count);
+
+	assert_non_null(test_req);
+	TALLOC_FREE(mem_ctx);
+	return;
+}
+
+/* calls fail() if test_subreq is NULL */
+static void test_req_recv_reply(void **state)
+{
+	/* pending */
+	struct tevent_req *test_subreq;
+	assert_non_null(test_subreq);
+	dns_tcp_req_recv_reply(test_subreq);
+	return;
+}
+
+/* calls fail() if test_subreq is NULL */
+static void test_req_done(void **state)
+{
+	/* pending */
+	struct tevent_req *test_subreq;
+	assert_non_null(test_subreq);
+	dns_tcp_req_done(test_subreq);
+	return;
+}
+
+/* calls fail() if test_rcv is not 0 */
+static void test_req_recv(void **state)
+{
+	/* incomplete */
+	TALLOC_CTX *mem_ctx;
+	struct tevent_req *test_req;
+	uint8_t **test_reply = UINT8_MAX;
+	size_t *test_reply_len = SIZE_MAX;
+
+	/* pending */
+	int test_rcv = dns_tcp_req_recv(test_req, mem_ctx, test_reply, test_reply_len);
+	
+	assert_int_equal(test_rcv, 0);
+	TALLOC_FREE(mem_ctx);
+	return;
+}
+
+/** test udp send/recv functionality **/
+
+/* calls fail() if UDP test_req is NULL */
+static void test_request_send(void **state)
+{
+	/* pending */
+	TALLOC_CTX *mem_ctx;
+	struct tevent_context *test_ev;
+	const char *test_server_addr_string = "TEST_SRVR_ADDR";
+	const uint8_t *test_query = UINT8_MAX;
+	size_t test_query_len = SIZE_MAX;
+
+	struct tevent_req *test_req = dns_udp_request_send(mem_ctx, test_ev,
+			test_server_addr_string, test_query, test_query_len);
+	
+	assert_non_null(test_req);
+	TALLOC_FREE(mem_ctx);
+	return;
+}
+
+/* calls fail() if test_subreq is NULL */
+static void test_request_get_reply(void **state)
+{
+	/* pending */
+	struct tevent_req *test_subreq;
+	assert_non_null(test_subreq);
+	dns_udp_request_get_reply(test_subreq);
+	return;
+}
+
+/* calls fail() if test_subreq is NULL */
+static void test_request_done(void **state)
+{
+	/* pending */
+	struct tevent_req *test_subreq;
+	assert_non_null(test_subreq);
+	dns_udp_request_done(test_subreq);
+	return;
+}
+
+/* calls fail() if test_rcv is not 0 */
+static void test_request_recv(void **state)
+{
+	/* incomplete */
+	struct tevent_req *test_req;
+	TALLOC_CTX *mem_ctx;
+	uint8_t **test_reply = UINT8_MAX;
+	size_t *test_reply_len = SIZE_MAX;
+
+	/* pending */
+	int test_rcv = dns_udp_request_recv(test_req, mem_ctx, test_reply, test_reply_len);
+	
+	assert_int_equal(test_rcv, 0);
+	TALLOC_FREE(mem_ctx);
+	return;
+}
+
+/** test gss-tsig functionality **/
+
+/* helper struct functions */
+static struct dns_res_rec *test_record(void) {
+
+	TALLOC_CTX *mem_ctx;
+	struct dns_res_rec *test_rec;
+	test_rec->name = "TEST_RECORD";
+	test_rec->rr_type = DNS_QTYPE_TSIG;
+	test_rec->rr_class = DNS_QCLASS_ANY;
+	test_rec->ttl = 0;
+	test_rec->length = UINT16_MAX;
+	/* rdata */
+	test_rec->rdata.tsig_record.algorithm_name = "gss-tsig";
+	test_rec->rdata.tsig_record.time_prefix = 0;
+	test_rec->rdata.tsig_record.time = 0;
+	test_rec->rdata.tsig_record.fudge = 300;
+	test_rec->rdata.tsig_record.mac_size = UINT16_MAX;
+	test_rec->rdata.tsig_record.mac = NULL;
+	test_rec->rdata.tsig_record.original_id = UINT16_MAX;
+	test_rec->rdata.tsig_record.error = UINT16_MAX;
+	test_rec->rdata.tsig_record.other_size = 0;
+	test_rec->rdata.tsig_record.other_data = NULL;
+
+	return test_rec;
+};
+
+static struct dns_client_tkey *test_tkey_name(void) {
+	
+	struct dns_client_tkey *test_tkey = NULL;
+	test_tkey->name = "TEST_TKEY";
+
+	return test_tkey;
+};
+
+/* calls fail() if assertions are false */
+static void tkey_test(void **state)
+{
+	/* pending */
+	int err;
+	struct dns_client_tkey_store *test_store;
+	const char *test_name = "TEST_TKEY";
+	
+	struct dns_client_tkey *testing;
+	struct dns_client_tkey *verifier;
+
+	testing = test_tkey_name();
+	verifier  = dns_find_cli_tkey(test_store, test_name);
+
+	assert_non_null(testing);
+	assert_non_null(verifier);
+	assert_string_equal(testing->name, verifier->name);
+	
+	TALLOC_FREE(testing);
+	TALLOC_FREE(verifier);
+	return;
+}
+
+/* calls fail() if test_werr not in werr_set */
+static void gen_tsig_test(void **state)
+{
+	/* incomplete declarations */
+	TALLOC_CTX *mem_ctx;
+	DATA_BLOB *in_test = {NULL, SIZE_MAX};
+	unsigned long werr_set[4];
+	werr_set[0] = 0x0;
+	werr_set[1] = 0x8;
+	werr_set[2] = 0x2329;
+	werr_set[3] = 0x2331;
+	
+	struct dns_client *test_client;
+	test_client->samdb = NULL;
+	test_client->zones = NULL;
+	test_client->tkeys = NULL;
+	test_client->client_credentials = NULL;
+	test_client->max_payload = UINT16_MAX;
+	
+	struct dns_request_cli_state *test_state;
+	test_state->flags = UINT16_MAX;
+	test_state->authenticated = true;
+	test_state->sign = true;
+	test_state->key_name = "TKEY_NAME";
+	test_state->tsig->name = "TSIG_RECORD";
+	test_state->tsig->rr_type = DNS_QTYPE_TSIG;
+	test_state->tsig->rr_class = DNS_QCLASS_ANY;
+	test_state->tsig->ttl = 0;
+	test_state->tsig->length = UINT16_MAX;
+	test_state->tsig_error = UINT16_MAX;
+	
+	struct dns_name_packet *test_packet;
+	test_packet->id = UINT16_MAX;
+	test_packet->qdcount = UINT16_MAX;
+	test_packet->ancount = UINT16_MAX;
+	test_packet->nscount = UINT16_MAX;
+	test_packet->arcount = UINT16_MAX;
+
+	/* test error codes */
+	WERROR test_werr = (unsigned long) dns_cli_generate_tsig(test_client, mem_ctx,
+								test_state, test_packet, in_test);
+
+	assert_in_set(test_werr, werr_set, 4);
+	TALLOC_FREE(mem_ctx);
+	return;
+}
+
+/* run test suite */
+int main(void) 
+{
+	/* test structure */
+	const struct CMUnitTest tests[] = {
+		/* tcp */
+		cmocka_unit_test(test_req_send),
+		cmocka_unit_test(test_req_recv_reply),
+		cmocka_unit_test(test_req_done),
+		cmocka_unit_test(test_req_recv),
+		/* udp */
+		cmocka_unit_test(test_request_send),
+		cmocka_unit_test(test_request_get_reply),
+		cmocka_unit_test(test_request_done),
+		cmocka_unit_test(test_request_recv),
+		/* gss-tsig */
+		cmocka_unit_test(tkey_test),
+		cmocka_unit_test(gen_tsig_test),
+	};
+
+	cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+	return cmocka_run_group_tests(tests, NULL, NULL);
+}
\ No newline at end of file
-- 
2.7.4


From eb86dc84ff4d1ee0f3ffc7f0f3034f0e451ebb9c Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:12:24 +0300
Subject: [PATCH 04/19] wscript_build: integrate cli_tests to waf-samba

---
 libcli/dns/cmocka-tests/wscript_build | 7 +++++++
 1 file changed, 7 insertions(+)
 create mode 100755 libcli/dns/cmocka-tests/wscript_build

diff --git a/libcli/dns/cmocka-tests/wscript_build b/libcli/dns/cmocka-tests/wscript_build
new file mode 100755
index 0000000..8cf4219
--- /dev/null
+++ b/libcli/dns/cmocka-tests/wscript_build
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+# cli_dns test suite
+bld.SAMBA_BINARY('client_tests',
+		source='cli_tests.c',
+		deps='LIBTSOCKET tevent-util cmocka gensec auth samba_server_gensec dnsserver_common',
+		install=False)
-- 
2.7.4


From 53d3123b9d328f78771367282f88631bcde59412 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:12:57 +0300
Subject: [PATCH 05/19] cmocka-tests: added test suite README

---
 libcli/dns/cmocka-tests/README.md | 49 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 libcli/dns/cmocka-tests/README.md

diff --git a/libcli/dns/cmocka-tests/README.md b/libcli/dns/cmocka-tests/README.md
new file mode 100644
index 0000000..3549daf
--- /dev/null
+++ b/libcli/dns/cmocka-tests/README.md
@@ -0,0 +1,49 @@
+## README: test suites
+
+***WORK IN PROGRESS***
+
+*Test suite cli_tests.c is not functional and currently NOT incorporated in Samba/wscript*/
+
+Tests for the client features are divided in four different test suites:
+
+*	cli_crypto_test: transaction key name search and GSS-TSIG signature generation
+*	dns_tcp_test: individual DNS TCP send/receive request packet test
+*	dns_udp_test: individual DNS UDP send/receive request packet test
+*	cli_tests: complete test suite for libcli/dns/cli_dns.c
+
+*See cli-fn for corresponding libraries*
+
+### Configure and Build complete test suite
+
+The Samba top-level wscript and wscript_build have been modified to recursively implement test suites in 
+Samba builds. Running `$ waf configure && waf` in Samba top-level directory, takes care of creating the 
+test executable and incorporating it during the building process.
+
+### Configure and Build individual test suites
+
+You can build and incorporate individual tests in Samba builds, by configuring Samba with the "ENABLE_SELFTEST" 
+option:
+
+`$ ./configure --enable-selftest`
+
+### Configure and Build individual test suites (standalone)
+
+Samba contributors, or anyone interested in the specific code, may wish to build the individual tests for 
+feature testing and/or other development purposes. To do so:
+
+In dns/cmocka-tests/test-fn/:
+```
+$ waf configure
+
+$ waf
+```
+*default build directory is set to cmocka-tests/build-tests*
+
+To clean "leftovers":
+
+```
+$ waf clean
+
+$ waf distclean
+```
+
-- 
2.7.4


From d20e04a59f79071f782a55c31a0fee45f58caa59 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:13:57 +0300
Subject: [PATCH 06/19] cmocka-tests/test-fn: added wscript for individual
 feature test suites

---
 libcli/dns/cmocka-tests/test-fn/wscript | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100755 libcli/dns/cmocka-tests/test-fn/wscript

diff --git a/libcli/dns/cmocka-tests/test-fn/wscript b/libcli/dns/cmocka-tests/test-fn/wscript
new file mode 100755
index 0000000..2afb70c
--- /dev/null
+++ b/libcli/dns/cmocka-tests/test-fn/wscript
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+import os
+
+out = 'build-tests'
+
+# configures and builds individual tests in /cmocka-tests/test-fn
+def configure(conf):
+	print('configuring test suites in ' + out + '...')
+	return
+
+def build(bld):
+	print('building cli_crypto_test...')
+	bld.SAMBA_BINARY('cli_crypto_test',
+			source='cli_crypto_test.c',
+			deps='LIBTSOCKET tevent-util cmocka',
+			install=False)
+
+	print('building dns_tcp_test...')
+	bld.SAMBA_BINARY('dns_tcp_test',
+			source='dns_tcp_test.c',
+			deps='LIBTSOCKET tevent-util cmocka',
+			install=False)
+
+	print('building dns_udp_test...')
+	bld.SAMBA_BINARY('dns_udp_test',
+			source='dns_udp_test.c',
+			deps='LIBTSOCKET tevent-util cmocka',
+			install=False)
+			
+	print('DONE')
-- 
2.7.4


From e1de04fd19ed44d37145e0598d0ae8196cd9461b Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:15:15 +0300
Subject: [PATCH 07/19] cmocka-tests/test-fn/cli_crypto_test: tkey and tsig
 feature tests

---
 libcli/dns/cmocka-tests/test-fn/cli_crypto_test.c | 155 ++++++++++++++++++++++
 1 file changed, 155 insertions(+)
 create mode 100644 libcli/dns/cmocka-tests/test-fn/cli_crypto_test.c

diff --git a/libcli/dns/cmocka-tests/test-fn/cli_crypto_test.c b/libcli/dns/cmocka-tests/test-fn/cli_crypto_test.c
new file mode 100644
index 0000000..fdb5c3d
--- /dev/null
+++ b/libcli/dns/cmocka-tests/test-fn/cli_crypto_test.c
@@ -0,0 +1,155 @@
+/* Tests GSS-TSIG client-side handling for signed packets.
+ * 
+ * --WORK IN PROGRESS--
+ *
+ * Copyright 2017 (c) Dimitrios Gravanis
+ *
+ * Uses cmocka C testing API.
+ * Copyright 2013 (c) Andreas Schneider <asn at cynapses.org>
+ *                    Jakub Hrozek <jakub.hrozek at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include "libcli/dns/cli-fn/client_crypto.c"
+
+/* --- INCOMPLETE --- */
+
+/** test gss-tsig functionality **/
+
+/* helper struct functions */
+static struct dns_res_rec *test_record(void) {
+
+	TALLOC_CTX *mem_ctx;
+	struct dns_res_rec *test_rec;
+	test_rec->name = "TEST_RECORD";
+	test_rec->rr_type = DNS_QTYPE_TSIG;
+	test_rec->rr_class = DNS_QCLASS_ANY;
+	test_rec->ttl = 0;
+	test_rec->length = UINT16_MAX;
+	/* rdata */
+	test_rec->rdata.tsig_record.algorithm_name = "gss-tsig";
+	test_rec->rdata.tsig_record.time_prefix = 0;
+	test_rec->rdata.tsig_record.time = 0;
+	test_rec->rdata.tsig_record.fudge = 300;
+	test_rec->rdata.tsig_record.mac_size = UINT16_MAX;
+	test_rec->rdata.tsig_record.mac = NULL;
+	test_rec->rdata.tsig_record.original_id = UINT16_MAX;
+	test_rec->rdata.tsig_record.error = UINT16_MAX;
+	test_rec->rdata.tsig_record.other_size = 0;
+	test_rec->rdata.tsig_record.other_data = NULL;
+
+	return test_rec;
+};
+
+static struct dns_client_tkey *test_tkey_name(void) {
+	
+	struct dns_client_tkey *test_tkey = NULL;
+	test_tkey->name = "TEST_TKEY";
+
+	return test_tkey;
+};
+
+/* calls fail() if assertions are false */
+static void tkey_test(void **state)
+{
+	/* pending */
+	int err;
+	struct dns_client_tkey_store *test_store;
+	const char *test_name = "TEST_TKEY";
+	
+	struct dns_client_tkey *testing;
+	struct dns_client_tkey *verifier;
+
+	testing = test_tkey_name();
+	verifier  = dns_find_cli_tkey(test_store, test_name);
+
+	assert_non_null(testing);
+	assert_non_null(verifier);
+	assert_string_equal(testing->name, verifier->name);
+	
+	TALLOC_FREE(testing);
+	TALLOC_FREE(verifier);
+	return;
+}
+
+/* calls fail() if test_werr not in werr_set */
+static void gen_tsig_test(void **state)
+{
+	/* incomplete declarations */
+	TALLOC_CTX *mem_ctx;
+	DATA_BLOB *in_test = {NULL, SIZE_MAX};
+	unsigned long werr_set[4];
+	werr_set[0] = 0x0;
+	werr_set[1] = 0x8;
+	werr_set[2] = 0x2329;
+	werr_set[3] = 0x2331;
+	
+	struct dns_client *test_client;
+	test_client->samdb = NULL;
+	test_client->zones = NULL;
+	test_client->tkeys = NULL;
+	test_client->client_credentials = NULL;
+	test_client->max_payload = UINT16_MAX;
+	
+	struct dns_request_cli_state *test_state;
+	test_state->flags = UINT16_MAX;
+	test_state->authenticated = true;
+	test_state->sign = true;
+	test_state->key_name = "TKEY_NAME";
+	test_state->tsig->name = "TSIG_RECORD";
+	test_state->tsig->rr_type = DNS_QTYPE_TSIG;
+	test_state->tsig->rr_class = DNS_QCLASS_ANY;
+	test_state->tsig->ttl = 0;
+	test_state->tsig->length = UINT16_MAX;
+	test_state->tsig_error = UINT16_MAX;
+	
+	struct dns_name_packet *test_packet;
+	test_packet->id = UINT16_MAX;
+	test_packet->qdcount = UINT16_MAX;
+	test_packet->ancount = UINT16_MAX;
+	test_packet->nscount = UINT16_MAX;
+	test_packet->arcount = UINT16_MAX;
+
+	/* test error codes */
+	WERROR test_werr = (unsigned long) dns_cli_generate_tsig(test_client, mem_ctx,
+								test_state, test_packet, in_test);
+
+	assert_in_set(test_werr, werr_set, 4);
+	TALLOC_FREE(mem_ctx);
+	return;
+}
+
+/* run test suite */
+int main(void)
+{
+	/* tests structure */
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test(empty_sig_test),
+		cmocka_unit_test(tkey_test),
+		cmocka_unit_test(gen_tsig_test),
+	};
+
+	cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+	return cmocka_run_group_tests(tests, NULL, NULL);
+}
\ No newline at end of file
-- 
2.7.4


From 12d60e82949f5b6b4961f5accf3ff33191489d44 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:15:56 +0300
Subject: [PATCH 08/19] cmocka-tests/test-fn/dns_tcp_test: TCP send/recv
 feature tests

---
 libcli/dns/cmocka-tests/test-fn/dns_tcp_test.c | 108 +++++++++++++++++++++++++
 1 file changed, 108 insertions(+)
 create mode 100644 libcli/dns/cmocka-tests/test-fn/dns_tcp_test.c

diff --git a/libcli/dns/cmocka-tests/test-fn/dns_tcp_test.c b/libcli/dns/cmocka-tests/test-fn/dns_tcp_test.c
new file mode 100644
index 0000000..c4eef7d
--- /dev/null
+++ b/libcli/dns/cmocka-tests/test-fn/dns_tcp_test.c
@@ -0,0 +1,108 @@
+/* Tests TCP client-side DNS call handling.
+ * 
+ * --WORK IN PROGRESS--
+ *
+ * Copyright 2017 (c) Dimitrios Gravanis
+ *
+ * Uses cmocka C testing API.
+ * Copyright 2013 (c) Andreas Schneider <asn at cynapses.org>
+ *                    Jakub Hrozek <jakub.hrozek at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include "libcli/dns/cli-fn/dns_tcp.c"
+
+/* --- INCOMPLETE ---*/
+
+/** test tcp send/recv functionality **/
+
+/* calls fail() if TCP test_req is NULL */
+static void test_req_send(void **state)
+{
+	/* incomplete */
+	TALLOC_CTX *mem_ctx;
+	struct tevent_context *test_ev;
+	const char *test_server_addr_string = "TEST_SRVR_ADDR";
+	struct iovec *test_vector;
+	size_t test_count = SIZE_MAX;
+
+	struct tevent_req *test_req = dns_tcp_req_send(mem_ctx, test_ev,
+			test_server_addr_string, test_vector, test_count);
+
+	assert_non_null(test_req);
+	TALLOC_FREE(mem_ctx);
+	return;
+}
+
+/* calls fail() if test_subreq is NULL */
+static void test_req_recv_reply(void **state)
+{
+	/* pending */
+	struct tevent_req *test_subreq;
+	assert_non_null(test_subreq);
+	dns_tcp_req_recv_reply(test_subreq);
+	return;
+}
+
+/* calls fail() if test_subreq is NULL */
+static void test_req_done(void **state)
+{
+	/* pending */
+	struct tevent_req *test_subreq;
+	assert_non_null(test_subreq);
+	dns_tcp_req_done(test_subreq);
+	return;
+}
+
+/* calls fail() if test_rcv is not 0 */
+static void test_req_recv(void **state)
+{
+	/* incomplete */
+	TALLOC_CTX *mem_ctx;
+	struct tevent_req *test_req;
+	uint8_t **test_reply = UINT8_MAX;
+	size_t *test_reply_len = SIZE_MAX;
+
+	/* pending */
+	int test_rcv = dns_tcp_req_recv(test_req, mem_ctx, test_reply, test_reply_len);
+	
+	assert_int_equal(test_rcv, 0);
+	TALLOC_FREE(mem_ctx);
+	return;
+}
+
+/* run test suite */
+int main(void)
+{
+	/* tests structure */
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test(test_req_send),
+		cmocka_unit_test(test_req_recv_reply),
+		cmocka_unit_test(test_req_done),
+		cmocka_unit_test(test_req_recv),
+	};
+
+	cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+	return cmocka_run_group_tests(tests, NULL, NULL);
+}
\ No newline at end of file
-- 
2.7.4


From 980be5cff114a36d602098fe34fbf367ddd22650 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:16:12 +0300
Subject: [PATCH 09/19] cmocka-tests/test-fn/dns_udp_test: UDP send/recv
 feature tests

---
 libcli/dns/cmocka-tests/test-fn/dns_udp_test.c | 108 +++++++++++++++++++++++++
 1 file changed, 108 insertions(+)
 create mode 100644 libcli/dns/cmocka-tests/test-fn/dns_udp_test.c

diff --git a/libcli/dns/cmocka-tests/test-fn/dns_udp_test.c b/libcli/dns/cmocka-tests/test-fn/dns_udp_test.c
new file mode 100644
index 0000000..aa7ad45
--- /dev/null
+++ b/libcli/dns/cmocka-tests/test-fn/dns_udp_test.c
@@ -0,0 +1,108 @@
+/* Tests UDP client-side DNS call handling.
+ * 
+ * --WORK IN PROGRESS--
+ *
+ * Copyright 2017 (c) Dimitrios Gravanis
+ *
+ * Uses cmocka C testing API.
+ * Copyright 2013 (c) Andreas Schneider <asn at cynapses.org>
+ *                    Jakub Hrozek <jakub.hrozek at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include "libcli/dns/cli-fn/dns_udp.c"
+
+/* test suite --- INCOMPLETE --- */
+
+/** test udp send/recv functionality **/
+
+/* calls fail() if UDP test_req is NULL */
+static void test_request_send(void **state)
+{
+	/* pending */
+	TALLOC_CTX *mem_ctx;
+	struct tevent_context *test_ev;
+	const char *test_server_addr_string = "TEST_SRVR_ADDR";
+	const uint8_t *test_query = UINT8_MAX;
+	size_t test_query_len = SIZE_MAX;
+
+	struct tevent_req *test_req = dns_udp_request_send(mem_ctx, test_ev,
+			test_server_addr_string, test_query, test_query_len);
+	
+	assert_non_null(test_req);
+	TALLOC_FREE(mem_ctx);
+	return;
+}
+
+/* calls fail() if test_subreq is NULL */
+static void test_request_get_reply(void **state)
+{
+	/* pending */
+	struct tevent_req *test_subreq;
+	assert_non_null(test_subreq);
+	dns_udp_request_get_reply(test_subreq);
+	return;
+}
+
+/* calls fail() if test_subreq is NULL */
+static void test_request_done(void **state)
+{
+	/* pending */
+	struct tevent_req *test_subreq;
+	assert_non_null(test_subreq);
+	dns_udp_request_done(test_subreq);
+	return;
+}
+
+/* calls fail() if test_rcv is not 0 */
+static void test_request_recv(void **state)
+{
+	/* incomplete */
+	struct tevent_req *test_req;
+	TALLOC_CTX *mem_ctx;
+	uint8_t **test_reply = UINT8_MAX;
+	size_t *test_reply_len = SIZE_MAX;
+
+	/* pending */
+	int test_rcv = dns_udp_request_recv(test_req, mem_ctx, test_reply, test_reply_len);
+	
+	assert_int_equal(test_rcv, 0);
+	TALLOC_FREE(mem_ctx);
+	return;
+}
+
+/* run test suite */
+int main(void)
+{
+	/* tests structure */
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test(test_request_send),
+		cmocka_unit_test(test_request_get_reply),
+		cmocka_unit_test(test_request_done),
+		cmocka_unit_test(test_request_recv),
+	};
+
+	cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+	return cmocka_run_group_tests(tests, NULL, NULL);
+}
\ No newline at end of file
-- 
2.7.4


From 2dd3cf701bdbdc071e3d56dacc40203981f71492 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:16:59 +0300
Subject: [PATCH 10/19] libtcp: cli_dns TCP req send/recv library

---
 libcli/dns/libtcp.h | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)
 create mode 100644 libcli/dns/libtcp.h

diff --git a/libcli/dns/libtcp.h b/libcli/dns/libtcp.h
new file mode 100644
index 0000000..d3fb616
--- /dev/null
+++ b/libcli/dns/libtcp.h
@@ -0,0 +1,96 @@
+/* TCP client-side DNS structures.
+ * 
+ * --WORK IN PROGRESS--
+ *
+ * Copyright (C) 2017 Dimitrios Gravanis
+ * 
+ * Based on the existing work on Samba Unix SMB/CIFS implementation by
+ * Kai Blin Copyright (C) 2011, Stefan Metzmacher Copyright (C) 2014.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBTCP_H__
+#define __LIBTCP_H__
+
+#include "source4/dns_server/dns_server.h"
+#include "source4/dns_server/dnsserver_common.h"
+
+
+/** DNS TCP definitions **/
+struct tsocket_address;
+
+struct dns_socket {
+	struct dns_server *dns;
+	struct tsocket_address *local_address;
+};
+
+struct dns_tcp_request_state {
+	struct tevent_context *ev;
+	struct tstream_context **tstream;
+	size_t v_count;
+	uint32_t *reply;
+	size_t reply_len;
+};
+
+struct dns_tcp_connection {
+	struct stream_connection *conn;
+	struct dns_socket *dns_socket;
+	struct tstream_context *tstream;
+	struct tevent_queue *send_queue;
+};
+
+struct dns_tcp_call {
+	struct dns_tcp_connection *dns_conn;
+	DATA_BLOB in;
+	DATA_BLOB out;
+	uint8_t out_hdr[4];
+	struct iovec out_iov[2];
+};
+
+/** DNS TCP functions **/
+
+/* Send an DNS request to a DNS server via TCP
+ *
+ *@param mem_ctx        	talloc memory context to use
+ *@param ev             	tevent context to use
+ *@param server_addr_string address of the server as a string
+ *@param query          	dns query to send
+ *@param count 				length of the iovector
+ *@return tevent_req with the active request or NULL on out-of-memory
+ */
+struct tevent_req *dns_tcp_req_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					const char *server_addr_string,
+					struct iovec *vector,
+					size_t count);
+
+/* Receive the DNS response from the DNS server via TCP
+ *
+ *@param req       tevent_req struct returned from dns_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
+ *@return 0/errno
+ */
+int dns_tcp_req_recv(struct tevent_req *req,
+			 TALLOC_CTX *mem_ctx,
+			 uint8_t **reply,
+			 size_t *reply_len);
+
+/* Callbacks */
+void dns_tcp_req_recv_reply(struct tevent_req *subreq);
+void dns_tcp_req_done(struct tevent_req *subreq);
+
+#endif /*__LIBTCP_H__*/
\ No newline at end of file
-- 
2.7.4


From 7f04181aaa6ca64fc8fe5aa5a305870b185daf4a Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:17:50 +0300
Subject: [PATCH 11/19] libudp: renamed libdns.h

---
 libcli/dns/libudp.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 libcli/dns/libudp.h

diff --git a/libcli/dns/libudp.h b/libcli/dns/libudp.h
new file mode 100644
index 0000000..57ab85f
--- /dev/null
+++ b/libcli/dns/libudp.h
@@ -0,0 +1,53 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Small async DNS library for Samba with socketwrapper support
+
+   Copyright (C) 2012 Kai Blin  <kai at samba.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LIBUDP_H__
+#define __LIBUDP_H__
+
+/** Send an dns request to a dns server using UDP
+ *
+ *@param mem_ctx        talloc memory context to use
+ *@param ev             tevent context to use
+ *@param server_address address of the server as a string
+ *@param query          dns query to send
+ *@param query_len      length of the query
+ *@return tevent_req with the active request or NULL on out-of-memory
+ */
+struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					const char *server_address,
+					const uint8_t *query,
+					size_t query_len);
+
+/** Get the dns response from a dns server via UDP
+ *
+ *@param req       tevent_req struct returned from dns_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
+ *@return 0/errno
+ */
+int dns_udp_request_recv(struct tevent_req *req,
+			 TALLOC_CTX *mem_ctx,
+			 uint8_t **reply,
+			 size_t *reply_len);
+
+#endif /*__LIBUDP_H__*/
-- 
2.7.4


From 8dc28c0f816fb4e8d9b227f2341a6acfce2cf5f1 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:20:55 +0300
Subject: [PATCH 12/19] libtsig: cli_dns GSS-TSIG library

---
 libcli/dns/libtsig.h | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)
 create mode 100644 libcli/dns/libtsig.h

diff --git a/libcli/dns/libtsig.h b/libcli/dns/libtsig.h
new file mode 100644
index 0000000..5b6566a
--- /dev/null
+++ b/libcli/dns/libtsig.h
@@ -0,0 +1,116 @@
+/* GSS-TSIG client-side DNS structures and utilites.
+ * 
+ * --WORK IN PROGRESS--
+ *
+ * Copyright (C) 2017 Dimitrios Gravanis
+ * 
+ * Based on the existing work on Samba Unix SMB/CIFS implementation by
+ * Kai Blin Copyright (C) 2011, Stefan Metzmacher Copyright (C) 2014.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBTSIG_H__
+#define __LIBTSIG_H__
+
+#include "librpc/gen_ndr/dns.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+
+
+/** error definitions **/
+uint8_t werr_to_dns_err(WERROR werr);
+#define DNS_ERR(err_str) WERR_DNS_ERROR_RCODE_##err_str
+
+/** client structures **/
+struct dns_client_zone {
+	struct dns_client_zone *prev, *next;
+	const char *name;
+	struct ldb_dn *dn;
+};
+
+struct dns_client {
+	struct task_server *task;
+	struct ldb_context *samdb;
+	struct dns_client_zone *zones;
+	struct dns_client_tkey_store *tkeys;
+	struct cli_credentials *client_credentials;
+	uint16_t max_payload;
+};
+
+struct dns_request_cli_state {
+	TALLOC_CTX *mem_ctx;
+	uint16_t flags;
+	bool authenticated;
+	bool sign;
+	char *key_name;
+	struct dns_res_rec *tsig;
+	uint16_t tsig_error;
+};
+
+/** transaction key definitions **/
+#define TKEY_BUFFER_SIZE 128
+
+struct dns_client_tkey {
+	const char *name;
+	enum dns_tkey_mode mode;
+	const char *algorithm;
+	struct auth_session_info *session_info;
+	struct gensec_security *gensec;
+	bool complete;
+};
+
+struct dns_client_tkey_store {
+	struct dns_client_tkey **tkeys;
+	uint16_t next_idx;
+	uint16_t size;
+};
+
+/** functions **/
+
+/* Search for DNS key name in record to the expected name
+ *
+ *@param store 	dns_client_tkey_store to use for name search
+ *@param name   name to match
+ *@return tkey
+ */
+struct dns_client_tkey *dns_find_cli_tkey(struct dns_client_tkey_store *store,
+				      const char *name);
+
+/* Make a record copy with empty TSIG rdata
+ *
+ *@param mem_ctx        	talloc memory context to use
+ *@param orig_record       	dns_res_rec struct to duplicate
+ *@param empty_record		dns_res_rec struct with empty RDATA
+ *@return WERR_OK/WERR_NOT_ENOUGH_MEMORY
+ */
+WERROR dns_empty_tsig(TALLOC_CTX *mem_ctx,
+					struct dns_res_rec *orig_record,
+					struct dns_res_rec *empty_record);
+
+/* Sign packet and rebuild with TSIG
+ *
+ *@param dns 		dns_client structure with client internals
+ *@param mem_ctx 	talloc memory context to use
+ *@param packet 	dns_name_packet that is used
+ *@param state 		packet state
+ *@param in 		data and length of packet
+ *@return WERR_OK/_NOT_ENOUGH_MEMORY/_FORMAT_ERROR/_NOTAUTH
+ */
+WERROR dns_cli_generate_sig(struct dns_client *dns,
+		       TALLOC_CTX *mem_ctx,
+		       struct dns_name_packet *packet,
+		       struct dns_request_cli_state *state,
+		       DATA_BLOB *in);
+
+#endif /* __LIBTSIG_H__ */
\ No newline at end of file
-- 
2.7.4


From 765b1873bbc94dbd876fc185144037d9ca2845ef Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:21:31 +0300
Subject: [PATCH 13/19] libwrap: wrapper definitions library

---
 libcli/dns/libwrap.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 libcli/dns/libwrap.h

diff --git a/libcli/dns/libwrap.h b/libcli/dns/libwrap.h
new file mode 100644
index 0000000..2a722c3
--- /dev/null
+++ b/libcli/dns/libwrap.h
@@ -0,0 +1,46 @@
+/* DNS UDP/TCP send/recv wrap library with TSIG generation.
+ *
+ * --WORK IN PROGRESS--
+ *
+ * Copyright (C) 2017 Dimitrios Gravanis
+ * 
+ * Based on the existing work on Samba Unix SMB/CIFS implementation by
+ * Kai Blin Copyright (C) 2011, Stefan Metzmacher Copyright (C) 2014.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBWRAP_H__
+#define __LIBWRAP_H__
+
+/* udp */
+tevent_req *udp_req_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			const char *server_addr_string, const uint8_t *query, size_t query_len);
+
+int udp_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+	uint8_t **reply, size_t *reply_len);
+
+/* tcp */
+tevent_req *tcp_req_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			const char *server_addr_string, struct iovec *vector, size_t count);
+
+int tcp_req_recv(struct tevent_req *subreq, struct tevent_req *req,
+	TALLOC_CTX *mem_ctx, uint8_t **reply, size_t *reply_len);
+
+/* tsig gen */
+WERROR tcp_cli_tsig_gen(struct dns_client_tkey_store *store, const char *name,
+	   struct dns_client *dns, TALLOC_CTX *mem_ctx,v struct dns_request_state *state, 
+	   struct dns_name_packet *packet,	DATA_BLOB *in);
+
+#endif /* __LIBWRAP_H__ */
\ No newline at end of file
-- 
2.7.4


From ac9ea24ea3b494b51a4fa83bbccacf356434150f Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:23:35 +0300
Subject: [PATCH 14/19] wrap_cli: cli_dns wrapper functions library

---
 libcli/dns/wrap_cli.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)
 create mode 100644 libcli/dns/wrap_cli.c

diff --git a/libcli/dns/wrap_cli.c b/libcli/dns/wrap_cli.c
new file mode 100644
index 0000000..ea52e38
--- /dev/null
+++ b/libcli/dns/wrap_cli.c
@@ -0,0 +1,85 @@
+/* DNS UDP/TCP send/recv wrapping with TSIG generation.
+ *
+ * --WORK IN PROGRESS--
+ *
+ * Copyright (C) 2017 Dimitrios Gravanis
+ * 
+ * Based on the existing work on Samba Unix SMB/CIFS implementation by
+ * Kai Blin Copyright (C) 2011, Stefan Metzmacher Copyright (C) 2014.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libcli/dns/libwrap.h"
+
+/* wrap dns udp/tcp req send/recv() and tsig generation functions
+ * see libcli/dns/lib*.h for wrapped function declarations
+ */
+
+/* udp */
+tevent_req *__wrap_udp_req_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			const char *server_addr_string, const uint8_t *query, size_t query_len)
+{
+	return dns_udp_request_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					const char *server_addr_string,
+					const uint8_t *query,
+					size_t query_len);
+}
+
+int __wrap_udp_req_recv(struct tevent_req *subreq, struct tevent_req *req,
+			TALLOC_CTX *mem_ctx, uint8_t **reply, size_t *reply_len)
+{
+	void dns_udp_request_get_reply(tevent_req *subreq);
+
+	void dns_udp_request_done(tevent_req *subreq);
+
+	return dns_udp_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+				uint8_t **reply, size_t *reply_len);
+}
+
+/* tcp */
+tevent_req *__wrap_tcp_req_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			const char *server_addr_string, struct iovec *vector, size_t count)
+{
+	return dns_tcp_req_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					const char *server_addr_string,
+					struct iovec *vector,
+					size_t count);
+}
+
+int __wrap_tcp_req_recv(struct tevent_req *subreq, struct tevent_req *req,
+			TALLOC_CTX *mem_ctx, uint8_t **reply, size_t *reply_len)
+{
+	void dns_tcp_req_recv_reply(tevent_req *subreq);
+
+	void dns_tcp_req_done(tevent_req *subreq);
+
+	return dns_tcp_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, 
+				uint8_t **reply, size_t *reply_len);
+}
+
+/* tsig gen */
+WERROR __wrap_tcp_cli_tsig_gen(struct dns_client_tkey_store *store, const char *name,
+	   struct dns_client *dns, TALLOC_CTX *mem_ctx, struct dns_request_state *state, 
+	   struct dns_name_packet *packet, DATA_BLOB *in)
+{
+	struct dns_client_tkey *dns_find_cli_tkey(struct dns_client_tkey_store *store,
+				    const char *name);
+
+	return dns_cli_generate_tsig(struct dns_client *dns, TALLOC_CTX *mem_ctx,
+		       		struct dns_request_state *state, struct dns_name_packet *packet,
+		        	DATA_BLOB *in);
+}
\ No newline at end of file
-- 
2.7.4


From 1e220ba36c9fe863b1169bb168e8541be02ba36a Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:24:36 +0300
Subject: [PATCH 15/19] wscript_build: modified to build with cli_dns

---
 libcli/dns/wscript_build | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libcli/dns/wscript_build b/libcli/dns/wscript_build
index 018df6b..6923f7f 100644
--- a/libcli/dns/wscript_build
+++ b/libcli/dns/wscript_build
@@ -1,5 +1,7 @@
 #!/usr/bin/env python
 
+# builds a library for DNS TCP/UDP calls that utilizes GSS-TSIG encryption
 bld.SAMBA_SUBSYSTEM('clidns',
-        source='dns.c',
-        public_deps='LIBTSOCKET tevent-util')
+	    source='cli_dns.c',
+	    public_deps='LIBTSOCKET tevent-util',
+	    deps='gensec auth samba_server_gensec dnsserver_common')
-- 
2.7.4


From 78d5f8bec63aafedcd3d3c9922ac163790f43bf6 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:26:18 +0300
Subject: [PATCH 16/19] dns_server/dns_query: replaced libdns.h with libudp.h
 in preprocessor statements

---
 source4/dns_server/dns_query.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index fa92721..e72a9ef 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -30,7 +30,7 @@
 #include "dsdb/samdb/samdb.h"
 #include "dsdb/common/util.h"
 #include "dns_server/dns_server.h"
-#include "libcli/dns/libdns.h"
+#include "libcli/dns/libudp.h"
 #include "lib/util/dlinklist.h"
 #include "lib/util/util_net.h"
 #include "lib/util/tevent_werror.h"
-- 
2.7.4


From f2b8c50c066917f5891ab598f73c8c2450292a3f Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:27:18 +0300
Subject: [PATCH 17/19]  wscript_build: added recursive build for cmocka-tests,
 cmocka-tests/test-fn

---
 wscript_build | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/wscript_build b/wscript_build
index 8758b6d..43f89a3 100644
--- a/wscript_build
+++ b/wscript_build
@@ -120,12 +120,14 @@ bld.RECURSE('libcli/lsarpc')
 bld.RECURSE('libcli/drsuapi')
 bld.RECURSE('libcli/echo')
 bld.RECURSE('libcli/dns')
+bld.RECURSE('libcli/dns/cmocka-tests')
 bld.RECURSE('libcli/samsync')
 bld.RECURSE('libcli/registry')
 bld.RECURSE('source4/lib/policy')
 bld.RECURSE('libcli/named_pipe_auth')
 if bld.CONFIG_GET('ENABLE_SELFTEST'):
     bld.RECURSE('testsuite/unittests')
+    bld.RECURSE('libcli/dns/cmocka-tests/test-fn')
 
 if bld.CONFIG_GET('KRB5_VENDOR') in (None, 'heimdal'):
     if bld.CONFIG_GET("HEIMDAL_KRB5_CONFIG") and bld.CONFIG_GET("USING_SYSTEM_KRB5"):
-- 
2.7.4


From 9df3c4ccf38004ebdbf1157ee0b006e8a400731d Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:27:55 +0300
Subject: [PATCH 18/19] libdns: renamed as libudp.h

---
 libcli/dns/libdns.h | 53 -----------------------------------------------------
 1 file changed, 53 deletions(-)
 delete mode 100644 libcli/dns/libdns.h

diff --git a/libcli/dns/libdns.h b/libcli/dns/libdns.h
deleted file mode 100644
index 7ea2eb6..0000000
--- a/libcli/dns/libdns.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-   Unix SMB/CIFS implementation.
-
-   Small async DNS library for Samba with socketwrapper support
-
-   Copyright (C) 2012 Kai Blin  <kai at samba.org>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef __LIBDNS_H__
-#define __LIBDNS_H__
-
-/** Send an dns request to a dns server using UDP
- *
- *@param mem_ctx        talloc memory context to use
- *@param ev             tevent context to use
- *@param server_address address of the server as a string
- *@param query          dns query to send
- *@param query_len      length of the query
- *@return tevent_req with the active request or NULL on out-of-memory
- */
-struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
-					struct tevent_context *ev,
-					const char *server_address,
-					const uint8_t *query,
-					size_t query_len);
-
-/** Get the dns response from a dns server via UDP
- *
- *@param req       tevent_req struct returned from dns_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
- *@return 0/errno
- */
-int dns_udp_request_recv(struct tevent_req *req,
-			 TALLOC_CTX *mem_ctx,
-			 uint8_t **reply,
-			 size_t *reply_len);
-
-#endif /*__LIBDNS_H__*/
-- 
2.7.4


From 941a139d0b364784fba425a7eed105fd0b9b63ae Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav at gmail.com>
Date: Sat, 26 Aug 2017 20:29:00 +0300
Subject: [PATCH 19/19] dns.c: replaced by cli_dns.c as the client subsystem

---
 libcli/dns/dns.c | 178 -------------------------------------------------------
 1 file changed, 178 deletions(-)
 delete mode 100644 libcli/dns/dns.c

diff --git a/libcli/dns/dns.c b/libcli/dns/dns.c
deleted file mode 100644
index 7d066d8..0000000
--- a/libcli/dns/dns.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
-   Unix SMB/CIFS implementation.
-
-   Small async DNS library for Samba with socketwrapper support
-
-   Copyright (C) 2010 Kai Blin  <kai at samba.org>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "replace.h"
-#include "system/network.h"
-#include <tevent.h>
-#include "lib/tsocket/tsocket.h"
-#include "libcli/dns/libdns.h"
-#include "lib/util/tevent_unix.h"
-#include "lib/util/samba_util.h"
-#include "libcli/util/error.h"
-#include "librpc/gen_ndr/dns.h"
-
-struct dns_udp_request_state {
-	struct tevent_context *ev;
-	struct tdgram_context *dgram;
-	size_t query_len;
-	uint8_t *reply;
-	size_t reply_len;
-};
-
-#define DNS_REQUEST_TIMEOUT 2
-
-/* Declare callback functions used below. */
-static void dns_udp_request_get_reply(struct tevent_req *subreq);
-static void dns_udp_request_done(struct tevent_req *subreq);
-
-struct tevent_req *dns_udp_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_udp_request_state *state;
-	struct tsocket_address *local_addr, *server_addr;
-	struct tdgram_context *dgram;
-	int ret;
-
-	req = tevent_req_create(mem_ctx, &state, struct dns_udp_request_state);
-	if (req == NULL) {
-		return NULL;
-	}
-
-	state->ev = ev;
-
-	/* Use connected UDP sockets */
-	ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
-						&local_addr);
-	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, &server_addr);
-	if (ret != 0) {
-		tevent_req_error(req, errno);
-		return tevent_req_post(req, ev);
-	}
-
-	ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
-	if (ret != 0) {
-		tevent_req_error(req, errno);
-		return tevent_req_post(req, ev);
-	}
-
-	state->dgram = dgram;
-	state->query_len = query_len;
-
-	dump_data(10, query, query_len);
-
-	subreq = tdgram_sendto_send(state, ev, dgram, query, query_len, NULL);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
-	}
-
-	if (!tevent_req_set_endtime(req, ev,
-				timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
-		tevent_req_oom(req);
-		return tevent_req_post(req, ev);
-	}
-
-	tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
-	return req;
-}
-
-static void dns_udp_request_get_reply(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(subreq,
-						struct tevent_req);
-	struct dns_udp_request_state *state = tevent_req_data(req,
-						struct dns_udp_request_state);
-	ssize_t len;
-	int err = 0;
-
-	len = tdgram_sendto_recv(subreq, &err);
-	TALLOC_FREE(subreq);
-
-	if (len == -1 && err != 0) {
-		tevent_req_error(req, err);
-		return;
-	}
-
-	if (len != state->query_len) {
-		tevent_req_error(req, EIO);
-		return;
-	}
-
-	subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
-	if (tevent_req_nomem(subreq, req)) {
-		return;
-	}
-
-	tevent_req_set_callback(subreq, dns_udp_request_done, req);
-}
-
-static void dns_udp_request_done(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(subreq,
-						struct tevent_req);
-	struct dns_udp_request_state *state = tevent_req_data(req,
-						struct dns_udp_request_state);
-
-	ssize_t len;
-	int err = 0;
-
-	len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
-	TALLOC_FREE(subreq);
-
-	if (len == -1 && err != 0) {
-		tevent_req_error(req, err);
-		return;
-	}
-
-	state->reply_len = len;
-	dump_data(10, state->reply, state->reply_len);
-	tevent_req_done(req);
-}
-
-int dns_udp_request_recv(struct tevent_req *req,
-			 TALLOC_CTX *mem_ctx,
-			 uint8_t **reply,
-			 size_t *reply_len)
-{
-	struct dns_udp_request_state *state = tevent_req_data(req,
-			struct dns_udp_request_state);
-	int err;
-
-	if (tevent_req_is_unix_error(req, &err)) {
-		tevent_req_received(req);
-		return err;
-	}
-
-	*reply = talloc_move(mem_ctx, &state->reply);
-	*reply_len = state->reply_len;
-	tevent_req_received(req);
-
-	return 0;
-}
-- 
2.7.4



More information about the samba-technical mailing list