Skip to content

Instantly share code, notes, and snippets.

@dimgrav
Last active August 28, 2017 11:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dimgrav/c11d347e88994aa7d7cfe1d3f00409a0 to your computer and use it in GitHub Desktop.
Save dimgrav/c11d347e88994aa7d7cfe1d3f00409a0 to your computer and use it in GitHub Desktop.
All the code patches produced for the requirements of my GSoC 2017 project with Samba (improve libcli/dns)
0001-libcli-dns-added-README.patch
0002-libcli-dns-cli_dns-library-for-TCP-UDP-async-request.patch
0003-libcli-dns-libtcp-TCP-definitions-for-cli_dns.patch
0004-libcli-dns-libudp-UDP-definitions-for-cli_dns.patch
0005-libcli-dns-libtsig-GSS-TSIG-definitions-for-cli_dns.patch
0006-libcli-dns-wrap_cli-provides-wrap-functionality-for-.patch
0007-libcli-dns-libwrap-wrapper-definitions-for-wrap_cli.patch
0008-cli-fn-client_crypto-GSS-TSIG-signing-feature-librar.patch
0009-cli-fn-dns_tcp-TCP-send-recv-request-feature-library.patch
0010-cli-fn-dns_udp-UDP-send-recv-request-feature-library.patch
0011-cli-fn-README-feature-libraries-information.patch
0012-cmocka-tests-cli_tests-test-suite-for-cli_dns-using-.patch
0013-cmocka-tests-wscript_build-integrate-recursive-build.patch
0014-cmocka-tests-README-test-suite-information.patch
0015-cmocka-tests-test-fn-cli_crypto_test-individual-test.patch
0016-cmocka-tests-test-fn-dns_tcp_test-individual-tests-f.patch
0017-cmocka-tests-test-fn-dns_udp_test-individual-tests-f.patch
0018-cmocka-tests-test-fn-wscript-waf-script-to-build-ind.patch
0019-source4-dns_server-dns_query-replaced-libdns.h-with-.patch
0020-wscript_build-added-recursive-building-for-libcli-dn.patch
0021-libcli-dns-libdns-renamed-to-libudp.patch
0022-libcli-dns-wscript_build-modified-to-build-clidns-su.patch
0023-libcli-dns-dns.c-replaced-by-cli_dns.patch
From 6fe1afd181635b46c97619530915353cec1135ae Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:11:01 +0300
Subject: [PATCH 01/23] libcli/dns: added README
---
libcli/dns/README.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 libcli/dns/README.md
diff --git a/libcli/dns/README.md b/libcli/dns/README.md
new file mode 100644
index 0000000..f5a1c53
--- /dev/null
+++ b/libcli/dns/README.md
@@ -0,0 +1,76 @@
+# Client-side DNS call handling with GSS-TSIG
+### Unix SMB/CIFS implementation
+### Dimitrios Gravanis (C) 2017
+### Based on the existing work by Samba Team
+
+--------------------------------------------------------
+About
+--------------------------------------------------------
+
+For the Samba AD DC, libcli/dns is a library that allows the handling of DNS
+calls (send/receive requests) and generates GSS-TSIG type encryption signature
+for signed packets, to accomodate encrypted client-server communication.
+
+It consists of its respective function and structure libraries, that provide
+definitions for client-side functionality.
+
+Test suites are also available, that inspect individual features of cli_dns.c
+
+For more information on the project goals, read the GSoC proposal [here](https://summerofcode.withgoogle.com/projects/#6642229069217792).
+
+The project timeline and development journal is documented in its dedicated [blogspot](https://dimgrav.blogspot.gr/).
+
+--------------------------------------------------------
+Content listing and descriptions
+--------------------------------------------------------
+
+1. cli-fn
+
+ * 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 for Samba with socketwrapper support (pre-existing dns.c)
+
+2. cmocka-tests
+
+ * cli_crypto_test.c: Tests GSS-TSIG client-side handling for signed $
+ * dns_tcp_test.c: Tests TCP client-side DNS call handling
+ * dns_udp_test.c: Tests UDP client-side DNS call handling
+ * cli_tests: Complete test suite for libcli/dns/cli_dns.c
+
+3. cli_dns.c: DNS UDP/TCP call handler with socketwrapper support and TSIG generation (replaces dns.c)
+
+4. dns.h: Internal DNS query structures
+
+5. libtcp.h: TCP client-side DNS structures
+
+6. libtsig.h: GSS-TSIG client-side DNS structures and utilites
+
+7. libudp.h: Small async DNS library for Samba with socketwrapper support (pre-existing libdns.h)
+
+8. libwrap.h: DNS UDP/TCP send/recv wrap library with TSIG generation
+
+9. wrap_cli.c: DNS UDP/TCP send/recv wrapping with TSIG generation
+
+--------------------------------------------------------
+DNS Client (with wrapper support)
+--------------------------------------------------------
+
+Handles TCP and UDP requests.
+
+The client may use either TCP or UDP protocols to send a DNS name request to
+the server, then handle the reception of the appropriate server response.
+
+Features:
+
+* UDP request send/receive
+* TCP request send/receive
+* GSS-TSIG generation
+* DNS name packet parsing and signing
+
+The library consists of cli_dns.c, that includes functions, and dns.h, libtcp.h,
+libtsig.h, libudp.h, that provide declarations, definitions and structures.
+
+### Wrapping
+wrap_cli.c provides multiple wrapping of the above functionality, to hide buffer
+creation, DNS packet parsing and signature generation. Definitions of the wrapped
+functions are provided in libwrap.h.
--
2.7.4
From be0bc659c08a3e6706b616cee92817889781cec5 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:12:20 +0300
Subject: [PATCH 02/23] libcli/dns/cli_dns: library for TCP/UDP async requests
using GSS-TSIG
---
libcli/dns/cli_dns.c | 541 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 541 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..ab41e09
--- /dev/null
+++ b/libcli/dns/cli_dns.c
@@ -0,0 +1,541 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DNS UDP/TCP call handler with socketwrapper support and TSIG generation
+
+ Copyright (C) 2017 Dimitrios Gravanis <dimgrav@gmail.com>
+
+ Based on:
+
+ DNS server startup
+ DNS structures
+ Small async DNS library for Samba with socketwrapper support
+
+ Copyright (C) 2010 Kai Blin <kai@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/dns.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"
+
+#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;
+
+ 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 3538e38751deb01942aa49e96fcd69e05688762a Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:13:09 +0300
Subject: [PATCH 03/23] libcli/dns/libtcp: TCP definitions for cli_dns
---
libcli/dns/libtcp.h | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 94 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..50cc9ec
--- /dev/null
+++ b/libcli/dns/libtcp.h
@@ -0,0 +1,94 @@
+/* TCP client-side DNS structures.
+ *
+ * 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 0ca1174209c9393ca01febb158b93faad73298d8 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:13:54 +0300
Subject: [PATCH 04/23] libcli/dns/libudp: UDP definitions for cli_dns
---
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@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 073aca58f436d3b152a21a98e9a20bda61ae0f86 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:14:26 +0300
Subject: [PATCH 05/23] libcli/dns/libtsig: GSS-TSIG definitions for cli_dns
---
libcli/dns/libtsig.h | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 114 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..0f7ec2f
--- /dev/null
+++ b/libcli/dns/libtsig.h
@@ -0,0 +1,114 @@
+/* GSS-TSIG client-side DNS structures and utilites.
+ *
+ * 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 b38eb95bda4b232abb422bdf570136361ee70ab6 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:15:16 +0300
Subject: [PATCH 06/23] libcli/dns/wrap_cli: provides wrap functionality for
cli_dns
---
libcli/dns/wrap_cli.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 83 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..f82ad91
--- /dev/null
+++ b/libcli/dns/wrap_cli.c
@@ -0,0 +1,83 @@
+/* DNS UDP/TCP send/recv wrapping with TSIG generation.
+ *
+ * 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 */
+struct 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 */
+struct 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 abb0aa0ba8c8364c54b298a24bc47cf5bd189557 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:15:58 +0300
Subject: [PATCH 07/23] libcli/dns/libwrap: wrapper definitions for wrap_cli
---
libcli/dns/libwrap.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 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..071d55c
--- /dev/null
+++ b/libcli/dns/libwrap.h
@@ -0,0 +1,44 @@
+/* DNS UDP/TCP send/recv wrap library with TSIG generation.
+ *
+ * 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 */
+struct 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 */
+struct 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 2e12732efc492ffe6e3cb09b78feaab6d6819cb2 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:17:10 +0300
Subject: [PATCH 08/23] cli-fn/client_crypto: GSS-TSIG signing feature library
---
libcli/dns/cli-fn/client_crypto.c | 201 ++++++++++++++++++++++++++++++++++++++
1 file changed, 201 insertions(+)
create mode 100644 libcli/dns/cli-fn/client_crypto.c
diff --git a/libcli/dns/cli-fn/client_crypto.c b/libcli/dns/cli-fn/client_crypto.c
new file mode 100644
index 0000000..5976af8
--- /dev/null
+++ b/libcli/dns/cli-fn/client_crypto.c
@@ -0,0 +1,201 @@
+/* GSS-TSIG client-side handling for signed packets.
+ *
+ * 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;
+}
--
2.7.4
From d0fdff708f2cca609dc5b5a273e74423d7ee5bd3 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:17:43 +0300
Subject: [PATCH 09/23] cli-fn/dns_tcp: TCP send/recv request feature library
---
libcli/dns/cli-fn/dns_tcp.c | 221 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 221 insertions(+)
create mode 100644 libcli/dns/cli-fn/dns_tcp.c
diff --git a/libcli/dns/cli-fn/dns_tcp.c b/libcli/dns/cli-fn/dns_tcp.c
new file mode 100644
index 0000000..4e94e0e
--- /dev/null
+++ b/libcli/dns/cli-fn/dns_tcp.c
@@ -0,0 +1,221 @@
+/* TCP client-side DNS call handling.
+ *
+ * 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/dns.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"
+
+#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;
+
+ 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;
+}
\ No newline at end of file
--
2.7.4
From a01c0c1dbeca73e4bbab08d3055a30b8dfceed3e Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:18:13 +0300
Subject: [PATCH 10/23] cli-fn/dns_udp: UDP send/recv request feature library
---
libcli/dns/cli-fn/dns_udp.c | 178 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 178 insertions(+)
create mode 100644 libcli/dns/cli-fn/dns_udp.c
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@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 b58d2eed4552646491c45ab05e860fe69b1dc2aa Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:18:54 +0300
Subject: [PATCH 11/23] cli-fn/README: feature libraries information
---
libcli/dns/cli-fn/README.md | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
create mode 100644 libcli/dns/cli-fn/README.md
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/*
--
2.7.4
From a4d01bcb5d7f8a39621f96e089cd0ab25234da83 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:19:47 +0300
Subject: [PATCH 12/23] cmocka-tests/cli_tests: test suite for cli_dns using
Cmocka
---
libcli/dns/cmocka-tests/cli_tests.c | 305 ++++++++++++++++++++++++++++++++++++
1 file changed, 305 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..090b953
--- /dev/null
+++ b/libcli/dns/cmocka-tests/cli_tests.c
@@ -0,0 +1,305 @@
+/* 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@cynapses.org>
+ * Jakub Hrozek <jakub.hrozek@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/dns.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"
+
+#define DNS_REQUEST_TIMEOUT 2
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_DNS
+
+
+/** 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)
+{
+ 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)
+{
+ 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)
+{
+ TALLOC_CTX *mem_ctx;
+ struct tevent_req *test_req;
+ uint8_t **test_reply = UINT8_MAX;
+ size_t *test_reply_len = SIZE_MAX;
+
+ 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)
+{
+ 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)
+{
+ 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)
+{
+ 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)
+{
+ struct tevent_req *test_req;
+ TALLOC_CTX *mem_ctx;
+ uint8_t **test_reply = UINT8_MAX;
+ size_t *test_reply_len = SIZE_MAX;
+
+ 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)
+{
+ 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)
+{
+ TALLOC_CTX *mem_ctx;
+ DATA_BLOB *in_test = {NULL, SIZE_MAX};
+
+ 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 = dns_cli_generate_tsig(test_client, mem_ctx,
+ test_state, test_packet, in_test);
+
+ /* expected WERROR output */
+ assert_true(W_ERROR_IS_OK(test_werr));
+ assert_true(W_ERROR_EQUAL(WERR_NOT_ENOUGH_MEMORY, test_werr));
+ assert_true(W_ERROR_EQUAL(DNS_ERR(FORMAT_ERROR), test_werr));
+ assert_true(W_ERROR_EQUAL(DNS_ERR(NOTAUTH), test_werr));
+
+ 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 5ab2b0943eaf60fee6502032f9c6d0b7c1d5e83f Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:20:30 +0300
Subject: [PATCH 13/23] cmocka-tests/wscript_build: integrate recursive build
for cli_tests
---
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 2c4b9f5333bd2ea3a8374db598317687ed8cc68e Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:21:03 +0300
Subject: [PATCH 14/23] cmocka-tests/README: test suite information
---
libcli/dns/cmocka-tests/README.md | 50 +++++++++++++++++++++++++++++++++++++++
1 file changed, 50 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..4c4a5b8
--- /dev/null
+++ b/libcli/dns/cmocka-tests/README.md
@@ -0,0 +1,50 @@
+## README: test suites
+
+
+*Test suite cli_tests.c is functional and currently incorporated in Samba/wscript/*
+
+*Individual test suites are functional, but stand alone waf built is not yet supported.*
+
+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 21057db243a576e3bae217c302c66788ef101a15 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:22:03 +0300
Subject: [PATCH 15/23] cmocka-tests/test-fn/cli_crypto_test: individual tests
for TSIG crypto feature
---
libcli/dns/cmocka-tests/test-fn/cli_crypto_test.c | 149 ++++++++++++++++++++++
1 file changed, 149 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..412c6c1
--- /dev/null
+++ b/libcli/dns/cmocka-tests/test-fn/cli_crypto_test.c
@@ -0,0 +1,149 @@
+/* Tests GSS-TSIG client-side handling for signed packets.
+ *
+ * Copyright 2017 (c) Dimitrios Gravanis
+ *
+ * Uses cmocka C testing API.
+ * Copyright 2013 (c) Andreas Schneider <asn@cynapses.org>
+ * Jakub Hrozek <jakub.hrozek@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"
+
+
+/** 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)
+{
+ 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)
+{
+ TALLOC_CTX *mem_ctx;
+ DATA_BLOB *in_test = {NULL, SIZE_MAX};
+
+ 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 = dns_cli_generate_tsig(test_client, mem_ctx,
+ test_state, test_packet, in_test);
+
+ /* expected WERROR output */
+ assert_true(W_ERROR_IS_OK(test_werr));
+ assert_true(W_ERROR_EQUAL(WERR_NOT_ENOUGH_MEMORY, test_werr));
+ assert_true(W_ERROR_EQUAL(DNS_ERR(FORMAT_ERROR), test_werr));
+ assert_true(W_ERROR_EQUAL(DNS_ERR(NOTAUTH), test_werr));
+
+ 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 2f1784cfb0df574b9d7ff9198bf752c2e71e3c83 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:22:35 +0300
Subject: [PATCH 16/23] cmocka-tests/test-fn/dns_tcp_test: individual tests for
TCP requests feature
---
libcli/dns/cmocka-tests/test-fn/dns_tcp_test.c | 100 +++++++++++++++++++++++++
1 file changed, 100 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..72f1848
--- /dev/null
+++ b/libcli/dns/cmocka-tests/test-fn/dns_tcp_test.c
@@ -0,0 +1,100 @@
+/* Tests TCP client-side DNS call handling.
+ *
+ * Copyright 2017 (c) Dimitrios Gravanis
+ *
+ * Uses cmocka C testing API.
+ * Copyright 2013 (c) Andreas Schneider <asn@cynapses.org>
+ * Jakub Hrozek <jakub.hrozek@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"
+
+
+/** test tcp send/recv functionality **/
+
+/* calls fail() if TCP test_req is NULL */
+static void test_req_send(void **state)
+{
+ 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)
+{
+ 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)
+{
+ 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)
+{
+ TALLOC_CTX *mem_ctx;
+ struct tevent_req *test_req;
+ uint8_t **test_reply = UINT8_MAX;
+ size_t *test_reply_len = SIZE_MAX;
+
+ 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 200c3b381d4b5404dfe68e17b188c4c400efc990 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:22:52 +0300
Subject: [PATCH 17/23] cmocka-tests/test-fn/dns_udp_test: individual tests for
UDP requests feature
---
libcli/dns/cmocka-tests/test-fn/dns_udp_test.c | 105 +++++++++++++++++++++++++
1 file changed, 105 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..3bb98b6
--- /dev/null
+++ b/libcli/dns/cmocka-tests/test-fn/dns_udp_test.c
@@ -0,0 +1,105 @@
+/* Tests UDP client-side DNS call handling.
+ *
+ * Copyright 2017 (c) Dimitrios Gravanis
+ *
+ * Uses cmocka C testing API.
+ * Copyright 2013 (c) Andreas Schneider <asn@cynapses.org>
+ * Jakub Hrozek <jakub.hrozek@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 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 15fa0f5c0af2c9b69063a4d07fb165c8568ff921 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:23:38 +0300
Subject: [PATCH 18/23] cmocka-tests/test-fn/wscript: waf script to build
individual tests *incomplete*
---
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 e9dd5fac73d4a2e4ddeda54fc8c71f87a8ef9ce0 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:24:38 +0300
Subject: [PATCH 19/23] source4/dns_server/dns_query: replaced libdns.h with
libudp.h in preprocessor
---
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 d465463eb33bd0accff80866f6300cab7b70c720 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:25:35 +0300
Subject: [PATCH 20/23] wscript_build: added recursive building for
libcli/dns/cmocka-tests
---
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 193386d977e013e2e187512c7e48b6460bdd5dd1 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:26:08 +0300
Subject: [PATCH 21/23] libcli/dns/libdns: renamed to libudp
---
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@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 ed46adf41b04b7b1eb4e9809e0f2fc0a9c11c610 Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:27:00 +0300
Subject: [PATCH 22/23] libcli/dns/wscript_build: modified to build clidns
subsystem 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 c8a878c321fae7fcbb6c195df2ae5794c8b4856d Mon Sep 17 00:00:00 2001
From: Dimitrios Gravanis <dimgrav@gmail.com>
Date: Sun, 27 Aug 2017 14:27:34 +0300
Subject: [PATCH 23/23] libcli/dns/dns.c: replaced by cli_dns
---
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@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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment