The branch, master has been updated
       via  26f7a67 s4 dns: Only do recursive queries when allowed/desired
       via  06dd4d8 s4 dns: Check smb.conf if we should allow recursion
       via  533b2e6 s4 dns: Allow changing the dns operation flags in handlers
       via  8d9da67 s4 dns: Only forward for zones we don't own
       via  a991391 s4 dns: Forward questions we can't answer to another server
       via  10b14fa s4 dns: Add a simple dns lookup helper
       via  7566e6a s4 dns: Add a simple async client library
      from  95ebb11 selftest.py: Add get_interface.

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 26f7a676f9a0f6f8c5ae3bef9247c675734f35cd
Author: Kai Blin <k...@samba.org>
Date:   Tue Mar 27 15:00:01 2012 +0200

    s4 dns: Only do recursive queries when allowed/desired
    
    If recursive queries are switched off in smb.conf or the client doesn't ask 
for
    recursion, don't recurse.
    
    Autobuild-User: Kai Blin <k...@samba.org>
    Autobuild-Date: Tue Mar 27 17:39:26 CEST 2012 on sn-devel-104

commit 06dd4d8ee1c5440809fa87fd8a1f3cfac8e9036a
Author: Kai Blin <k...@samba.org>
Date:   Tue Mar 27 14:42:15 2012 +0200

    s4 dns: Check smb.conf if we should allow recursion

commit 533b2e6612bd6497c1d53c31912bccba0260a3e9
Author: Kai Blin <k...@samba.org>
Date:   Tue Mar 27 13:59:03 2012 +0200

    s4 dns: Allow changing the dns operation flags in handlers

commit 8d9da67185aac48d7d0bc1e7b90262ae9afc6a64
Author: Kai Blin <k...@samba.org>
Date:   Tue Mar 27 13:36:16 2012 +0200

    s4 dns: Only forward for zones we don't own

commit a99139160555072339f8f9cc5912c570158fc236
Author: Kai Blin <k...@samba.org>
Date:   Tue Mar 27 08:42:22 2012 +0200

    s4 dns: Forward questions we can't answer to another server
    
    This makes use of libdns and currently hardcodes the forward server, but
    it works. :)

commit 10b14fa1c03fa9d686e94be20a2700954ae090fa
Author: Kai Blin <k...@samba.org>
Date:   Mon Mar 26 20:47:42 2012 +0200

    s4 dns: Add a simple dns lookup helper

commit 7566e6a5347b9d6b2b0b8b27f9211599febd8da1
Author: Kai Blin <k...@samba.org>
Date:   Sun Mar 11 10:13:51 2012 +0100

    s4 dns: Add a simple async client library

-----------------------------------------------------------------------

Summary of changes:
 lib/param/loadparm.c             |   21 +++++
 libcli/dns/dns.c                 |  172 ++++++++++++++++++++++++++++++++++++++
 libcli/dns/libdns.h              |   53 ++++++++++++
 libcli/dns/wscript_build         |    5 +
 source4/dns_server/dns_query.c   |  109 ++++++++++++++++++++++--
 source4/dns_server/dns_server.c  |   21 ++++-
 source4/dns_server/dns_server.h  |    7 ++
 source4/dns_server/dns_update.c  |    1 +
 source4/dns_server/dns_utils.c   |   28 ++++++
 source4/dns_server/wscript_build |    2 +-
 utils/samba-dig.c                |  160 +++++++++++++++++++++++++++++++++++
 utils/wscript_build              |    7 ++
 wscript_build                    |    2 +
 13 files changed, 575 insertions(+), 13 deletions(-)
 create mode 100644 libcli/dns/dns.c
 create mode 100644 libcli/dns/libdns.h
 create mode 100644 libcli/dns/wscript_build
 create mode 100644 utils/samba-dig.c
 create mode 100644 utils/wscript_build


Changeset truncated at 500 lines:

diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
index bb59a79..e3792b6 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -1256,6 +1256,22 @@ static struct parm_struct parm_table[] = {
                .special        = NULL,
                .enum_list      = enum_dns_update_settings
        },
+       {
+               .label          = "dns forwarder",
+               .type           = P_STRING,
+               .p_class        = P_GLOBAL,
+               .offset         = GLOBAL_VAR(dns_forwarder),
+               .special        = NULL,
+               .enum_list      = NULL
+       },
+       {
+               .label          = "dns recursive queries",
+               .type           = P_BOOL,
+               .p_class        = P_GLOBAL,
+               .offset         = GLOBAL_VAR(dns_recursive_queries),
+               .special        = NULL,
+               .enum_list      = NULL
+       },
 
        {NULL,  P_BOOL,  P_NONE,  0,  NULL,  NULL,  0}
 };
@@ -1536,7 +1552,10 @@ FN_GLOBAL_INTEGER(srv_minprotocol, srv_minprotocol)
 FN_GLOBAL_INTEGER(cli_maxprotocol, cli_maxprotocol)
 FN_GLOBAL_INTEGER(cli_minprotocol, cli_minprotocol)
 FN_GLOBAL_BOOL(paranoid_server_security, paranoid_server_security)
+
 FN_GLOBAL_INTEGER(allow_dns_updates, allow_dns_updates)
+FN_GLOBAL_CONST_STRING(dns_forwarder, dns_forwarder)
+FN_GLOBAL_BOOL(dns_recursive_queries, dns_recursive_queries)
 
 FN_GLOBAL_INTEGER(server_signing, server_signing)
 FN_GLOBAL_INTEGER(client_signing, client_signing)
@@ -3403,6 +3422,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX 
*mem_ctx)
        lpcfg_do_global_parameter(lp_ctx, "nsupdate command", 
"/usr/bin/nsupdate -g");
 
         lpcfg_do_global_parameter(lp_ctx, "allow dns updates", "False");
+        lpcfg_do_global_parameter(lp_ctx, "dns recursive queries", "False");
+        lpcfg_do_global_parameter(lp_ctx, "dns forwarder", "");
 
        for (i = 0; parm_table[i].label; i++) {
                if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) {
diff --git a/libcli/dns/dns.c b/libcli/dns/dns.c
new file mode 100644
index 0000000..ac0c9e4
--- /dev/null
+++ b/libcli/dns/dns.c
@@ -0,0 +1,172 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Small async DNS library for Samba with socketwrapper support
+
+   Copyright (C) 2010 Kai Blin  <k...@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
index 0000000..31474eb
--- /dev/null
+++ b/libcli/dns/libdns.h
@@ -0,0 +1,53 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Small async DNS library for Samba with socketwrapper support
+
+   Copyright (C) 2012 Kai Blin  <k...@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
index 0000000..2e445da
--- /dev/null
+++ b/libcli/dns/wscript_build
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('LIBCLI_DNS',
+        source='dns.c',
+        deps='LIBTSOCKET tevent-util')
diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index 4277659..b3984a4 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -20,14 +20,18 @@
 */
 
 #include "includes.h"
+#include "smbd/service_task.h"
 #include "libcli/util/werror.h"
 #include "librpc/ndr/libndr.h"
 #include "librpc/gen_ndr/ndr_dns.h"
 #include "librpc/gen_ndr/ndr_dnsp.h"
 #include <ldb.h>
+#include "param/param.h"
 #include "dsdb/samdb/samdb.h"
 #include "dsdb/common/util.h"
 #include "dns_server/dns_server.h"
+#include "libcli/dns/libdns.h"
+#include "lib/util/util_net.h"
 
 static WERROR create_response_rr(const struct dns_name_question *question,
                                 const struct dnsp_DnssrvRpcRecord *rec,
@@ -97,6 +101,80 @@ static WERROR create_response_rr(const struct 
dns_name_question *question,
        return WERR_OK;
 }
 
+static WERROR ask_forwarder(struct dns_server *dns,
+                           TALLOC_CTX *mem_ctx,
+                           struct dns_name_question *question,
+                           struct dns_res_rec **answers, uint16_t *ancount,
+                           struct dns_res_rec **nsrecs, uint16_t *nscount,
+                           struct dns_res_rec **additional, uint16_t *arcount)
+{
+       struct tevent_context *ev = tevent_context_init(mem_ctx);
+       struct dns_name_packet *out_packet, *in_packet;
+       uint16_t id = random();
+       DATA_BLOB out, in;
+       enum ndr_err_code ndr_err;
+       WERROR werr = WERR_OK;
+       struct tevent_req *req;
+       const char *forwarder = lpcfg_dns_forwarder(dns->task->lp_ctx);
+
+       if (!is_ipaddress(forwarder)) {
+               DEBUG(0, ("Invalid 'dns forwarder' setting '%s', needs to be "
+                         "an IP address\n", forwarder));
+               return DNS_ERR(NAME_ERROR);
+       }
+
+       out_packet = talloc_zero(mem_ctx, struct dns_name_packet);
+       W_ERROR_HAVE_NO_MEMORY(out_packet);
+
+       out_packet->id = id;
+       out_packet->operation |= DNS_OPCODE_QUERY | DNS_FLAG_RECURSION_DESIRED;
+
+       out_packet->qdcount = 1;
+       out_packet->questions = question;
+
+       ndr_err = ndr_push_struct_blob(&out, mem_ctx, out_packet,
+                       (ndr_push_flags_fn_t)ndr_push_dns_name_packet);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return DNS_ERR(SERVER_FAILURE);
+       }
+
+       req = dns_udp_request_send(mem_ctx, ev, forwarder, out.data, 
out.length);
+       W_ERROR_HAVE_NO_MEMORY(req);
+
+       if(!tevent_req_poll(req, ev)) {
+               return DNS_ERR(SERVER_FAILURE);
+       }
+
+       werr = dns_udp_request_recv(req, mem_ctx, &in.data, &in.length);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       in_packet = talloc_zero(mem_ctx, struct dns_name_packet);
+       W_ERROR_HAVE_NO_MEMORY(in_packet);
+
+       ndr_err = ndr_pull_struct_blob(&in, in_packet, in_packet,
+                       (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return DNS_ERR(SERVER_FAILURE);
+       }
+
+       if (in_packet->id != id) {
+               DEBUG(0, ("DNS packet id mismatch: 0x%0x, expected 0x%0x\n",
+                         in_packet->id, id));
+               return DNS_ERR(NAME_ERROR);
+       }
+
+       *ancount = in_packet->ancount;
+       *answers = talloc_move(mem_ctx, &in_packet->answers);
+
+       *nscount = in_packet->nscount;
+       *nsrecs = talloc_move(mem_ctx, &in_packet->nsrecs);
+
+       *arcount = in_packet->arcount;
+       *additional = talloc_move(mem_ctx, &in_packet->additional);
+
+       return werr;
+}
+
 static WERROR handle_question(struct dns_server *dns,
                              TALLOC_CTX *mem_ctx,
                              const struct dns_name_question *question,
@@ -139,14 +217,15 @@ static WERROR handle_question(struct dns_server *dns,
 }
 
 WERROR dns_server_process_query(struct dns_server *dns,
+                               struct dns_request_state *state,
                                TALLOC_CTX *mem_ctx,
                                struct dns_name_packet *in,
                                struct dns_res_rec **answers,    uint16_t 
*ancount,
                                struct dns_res_rec **nsrecs,     uint16_t 
*nscount,
                                struct dns_res_rec **additional, uint16_t 
*arcount)
 {
-       uint16_t num_answers=0;
-       struct dns_res_rec *ans=NULL;
+       uint16_t num_answers=0, num_nsrecs=0, num_additional=0;
+       struct dns_res_rec *ans=NULL, *ns=NULL, *adds=NULL;
        WERROR werror;
 
        if (in->qdcount != 1) {
@@ -158,18 +237,34 @@ WERROR dns_server_process_query(struct dns_server *dns,
                return DNS_ERR(NOT_IMPLEMENTED);
        }
 
-       werror = handle_question(dns, mem_ctx, &in->questions[0], &ans, 
&num_answers);
+       if (dns_authorative_for_zone(dns, in->questions[0].name)) {
+               state->flags |= DNS_FLAG_AUTHORITATIVE;
+               werror = handle_question(dns, mem_ctx, &in->questions[0],
+                                        &ans, &num_answers);
+       } else {
+               if (state->flags & DNS_FLAG_RECURSION_DESIRED &&
+                   state->flags & DNS_FLAG_RECURSION_AVAIL) {
+                       DEBUG(2, ("Not authorative for '%s', forwarding\n",
+                                 in->questions[0].name));
+                       werror = ask_forwarder(dns, mem_ctx, &in->questions[0],
+                                              &ans, &num_answers,
+                                              &ns, &num_nsrecs,
+                                              &adds, &num_additional);
+               } else {
+                       werror = DNS_ERR(NAME_ERROR);
+               }
+       }
        W_ERROR_NOT_OK_GOTO(werror, query_failed);
 
        *answers = ans;
        *ancount = num_answers;
 
        /*FIXME: Do something for these */
-       *nsrecs  = NULL;
-       *nscount = 0;
+       *nsrecs  = ns;
+       *nscount = num_nsrecs;
 
-       *additional = NULL;
-       *arcount    = 0;
+       *additional = adds;
+       *arcount    = num_additional;
 
        return WERR_OK;
 
diff --git a/source4/dns_server/dns_server.c b/source4/dns_server/dns_server.c
index cf43590..789940f 100644
--- a/source4/dns_server/dns_server.c
+++ b/source4/dns_server/dns_server.c
@@ -100,6 +100,7 @@ static NTSTATUS dns_process(struct dns_server *dns,
 {
        enum ndr_err_code ndr_err;
        WERROR ret;
+       struct dns_request_state *state;
        struct dns_name_packet *in_packet;
        struct dns_name_packet *out_packet;
        struct dns_res_rec *answers = NULL, *nsrecs = NULL, *additional = NULL;
@@ -109,9 +110,11 @@ static NTSTATUS dns_process(struct dns_server *dns,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       in_packet = talloc_zero(mem_ctx, struct dns_name_packet);
+       state = talloc_zero(mem_ctx, struct dns_request_state);
+
+       in_packet = talloc_zero(state, struct dns_name_packet);
        /* TODO: We don't really need an out_packet. */
-       out_packet = talloc_zero(mem_ctx, struct dns_name_packet);
+       out_packet = talloc_zero(state, struct dns_name_packet);
 
        if (in_packet == NULL) return NT_STATUS_NO_MEMORY;
        if (out_packet == NULL) return NT_STATUS_NO_MEMORY;
@@ -134,19 +137,25 @@ static NTSTATUS dns_process(struct dns_server *dns,
                NDR_PRINT_DEBUG(dns_name_packet, in_packet);
        }
        *out_packet = *in_packet;
-       out_packet->operation |= DNS_FLAG_REPLY;
+       state->flags |= in_packet->operation | DNS_FLAG_REPLY;
+
+       if (lpcfg_dns_recursive_queries(dns->task->lp_ctx)) {
+               state->flags |= DNS_FLAG_RECURSION_AVAIL;
+       }
 
        switch (in_packet->operation & DNS_OPCODE) {
        case DNS_OPCODE_QUERY:
 
-               ret = dns_server_process_query(dns, out_packet, in_packet,
+               ret = dns_server_process_query(dns, state,
+                                              out_packet, in_packet,


-- 
Samba Shared Repository

Reply via email to