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 |