s4 dns: Add a simple async client library
authorKai Blin <kai@samba.org>
Sun, 11 Mar 2012 09:13:51 +0000 (10:13 +0100)
committerKai Blin <kai@samba.org>
Tue, 27 Mar 2012 14:03:07 +0000 (16:03 +0200)
libcli/dns/dns.c [new file with mode: 0644]
libcli/dns/libdns.h [new file with mode: 0644]
libcli/dns/wscript_build [new file with mode: 0644]
wscript_build

diff --git a/libcli/dns/dns.c b/libcli/dns/dns.c
new file mode 100644 (file)
index 0000000..ac0c9e4
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+   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/util/werror.h"
+#include "libcli/dns/libdns.h"
+#include "lib/util/tevent_werror.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;
+};
+
+/* Declare callback functions used below. */
+static void dns_request_get_reply(struct tevent_req *subreq);
+static void dns_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_werror(req, unix_to_werror(ret));
+               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_werror(req, unix_to_werror(ret));
+               return tevent_req_post(req, ev);
+       }
+
+       ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
+       if (ret != 0) {
+               tevent_req_werror(req, unix_to_werror(ret));
+               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);
+       }
+
+       tevent_req_set_callback(subreq, dns_request_get_reply, req);
+       return req;
+}
+
+static void dns_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_werror(req, unix_to_werror(err));
+               return;
+       }
+
+       if (len != state->query_len) {
+               tevent_req_werror(req, WERR_NET_WRITE_FAULT);
+               return;
+       }
+
+       subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+
+       tevent_req_set_callback(subreq, dns_request_done, req);
+       return;
+}
+
+static void dns_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_werror(req, unix_to_werror(err));
+               return;
+       }
+
+       state->reply_len = len;
+       dump_data(10, state->reply, state->reply_len);
+       tevent_req_done(req);
+}
+
+WERROR 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);
+       WERROR w_error;
+
+       if (tevent_req_is_werror(req, &w_error)) {
+               tevent_req_received(req);
+               return w_error;
+       }
+
+       *reply = talloc_move(mem_ctx, &state->reply);
+       *reply_len = state->reply_len;
+       tevent_req_received(req);
+
+       return WERR_OK;
+}
diff --git a/libcli/dns/libdns.h b/libcli/dns/libdns.h
new file mode 100644 (file)
index 0000000..31474eb
--- /dev/null
@@ -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 __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 WERROR code depending on the async request result
+ */
+WERROR dns_udp_request_recv(struct tevent_req *req,
+                           TALLOC_CTX *mem_ctx,
+                           uint8_t **reply,
+                           size_t *reply_len);
+
+#endif /*__LIBDNS_H__*/
diff --git a/libcli/dns/wscript_build b/libcli/dns/wscript_build
new file mode 100644 (file)
index 0000000..2e445da
--- /dev/null
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('LIBCLI_DNS',
+        source='dns.c',
+        deps='LIBTSOCKET tevent-util')
index f5dff8d..8dbfd70 100644 (file)
@@ -106,6 +106,7 @@ bld.RECURSE('libcli/auth')
 bld.RECURSE('libcli/lsarpc')
 bld.RECURSE('libcli/drsuapi')
 bld.RECURSE('libcli/echo')
+bld.RECURSE('libcli/dns')
 bld.RECURSE('libcli/samsync')
 bld.RECURSE('libcli/registry')
 bld.RECURSE('source4/lib/policy')