libcli/dns Improve dns_hosts_file, using Samba3's struct dns_rr_srv
authorAndrew Bartlett <abartlet@samba.org>
Mon, 25 Apr 2011 23:49:08 +0000 (09:49 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 26 Apr 2011 07:16:34 +0000 (17:16 +1000)
By reworking the 'fake DNS' file to use struct dns_rr_srv it should be
possible to emulate that resolver layer as well as the Samba4
sockaddr_storage* based layer.  This will then give us a common DNS
emulation for 'make test'.

Andrew Bartlett

libcli/dns/dns.h [new file with mode: 0644]
libcli/dns/dns_hosts_file.c [moved from libcli/nbt/dns_hosts_file.c with 58% similarity]
libcli/nbt/wscript_build
selftest/target/Samba3.pm
source3/libads/dns.h

diff --git a/libcli/dns/dns.h b/libcli/dns/dns.h
new file mode 100644 (file)
index 0000000..01aa6c4
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *  Unix SMB/CIFS implementation.
+ *  Internal DNS query structures
+ *  Copyright (C) Gerald Carter                2006.
+ *  Copyright (C) Andrew Bartlett 2011
+ *
+ *  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/>.
+ */
+
+/* DNS query section in replies */
+
+struct dns_query {
+       const char *hostname;
+       uint16_t type;
+       uint16_t in_class;
+};
+
+/* DNS RR record in reply */
+
+struct dns_rr {
+       const char *hostname;
+       uint16_t type;
+       uint16_t in_class;
+       uint32_t ttl;
+       uint16_t rdatalen;
+       uint8_t *rdata;
+};
+
+/* SRV records */
+
+struct dns_rr_srv {
+       const char *hostname;
+       uint16_t priority;
+       uint16_t weight;
+       uint16_t port;
+       size_t num_ips;
+       struct sockaddr_storage *ss_s;  /* support multi-homed hosts */
+};
+
+/* NS records */
+
+struct dns_rr_ns {
+       const char *hostname;
+       struct sockaddr_storage ss;
+};
+
+NTSTATUS resolve_dns_hosts_file_as_sockaddr(const char *dns_hosts_file,
+                                           const char *name, bool srv_lookup,
+                                           TALLOC_CTX *mem_ctx,
+                                           struct sockaddr_storage **return_iplist,
+                                           int *return_count);
+
+NTSTATUS resolve_dns_hosts_file_as_dns_rr(const char *dns_hosts_file,
+                                         const char *name, bool srv_lookup,
+                                         TALLOC_CTX *mem_ctx,
+                                         struct dns_rr_srv **return_rr,
+                                         int *return_count);
similarity index 58%
rename from libcli/nbt/dns_hosts_file.c
rename to libcli/dns/dns_hosts_file.c
index 801393650e037afde741ab79f5be77c0afbe6518..94d1d9704a3b58d8437dfab85f56d9b601a8526e 100644 (file)
@@ -5,7 +5,7 @@
 
    Copyright (C) Andrew Tridgell 1994-1998
    Copyright (C) Jeremy Allison 2007
-   Copyright (C) Andrew Bartlett 2009.
+   Copyright (C) Andrew Bartlett 2009-2011
 
    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
 #include "system/filesys.h"
 #include "system/network.h"
 #include "libcli/nbt/libnbt.h"
+#include "libcli/dns/dns.h"
+
+#ifdef strcasecmp
+#undef strcasecmp
+#endif
 
 /********************************************************
  Start parsing the dns_hosts_file file.
@@ -51,7 +56,7 @@ static XFILE *startdns_hosts_file(const char *fname)
 *********************************************************/
 
 static bool getdns_hosts_fileent(TALLOC_CTX *ctx, XFILE *fp, char **pp_name, char **pp_name_type,
-                         char **pp_next_name, 
+                         char **pp_next_name,
                          struct sockaddr_storage *pss, uint32_t *p_port)
 {
        char line[1024];
@@ -176,12 +181,12 @@ static void enddns_hosts_file(XFILE *fp)
  Resolve via "dns_hosts" method.
 *********************************************************/
 
-static NTSTATUS resolve_dns_hosts_file_as_sockaddr_recurse(const char *dns_hosts_file, 
-                                                          const char *name, bool srv_lookup,
-                                                          int level, uint32_t port, 
-                                                          TALLOC_CTX *mem_ctx, 
-                                                          struct sockaddr_storage **return_iplist,
-                                                          int *return_count)
+static NTSTATUS resolve_dns_hosts_file_as_dns_rr_recurse(const char *dns_hosts_file,
+                                                        const char *name, bool srv_lookup,
+                                                        int level, uint32_t port,
+                                                        TALLOC_CTX *mem_ctx,
+                                                        struct dns_rr_srv **return_rr,
+                                                        int *return_count)
 {
        /*
         * "dns_hosts" means parse the local dns_hosts file.
@@ -196,18 +201,21 @@ static NTSTATUS resolve_dns_hosts_file_as_sockaddr_recurse(const char *dns_hosts
        NTSTATUS status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
        TALLOC_CTX *ctx = NULL;
        TALLOC_CTX *ip_list_ctx = NULL;
+       struct dns_rr_srv *rr = NULL;
+
+       *return_rr = NULL;
 
        /* Don't recurse forever, even on our own flat files */
        if (level > 11) {
-
+               DEBUG(0, ("resolve_dns_hosts_file recursion limit reached looking up %s!\n", name));
+               return status;
        }
 
-       *return_iplist = NULL;
        *return_count = 0;
 
-       DEBUG(3,("resolve_dns_hosts: "
-               "Attempting dns_hosts lookup for name %s\n",
-               name));
+       DEBUG(3,("resolve_dns_hosts: (%d) "
+                "Attempting %s dns_hosts lookup for name %s\n",
+                level, srv_lookup ? "SRV" : "A", name));
 
        fp = startdns_hosts_file(dns_hosts_file);
 
@@ -229,79 +237,179 @@ static NTSTATUS resolve_dns_hosts_file_as_sockaddr_recurse(const char *dns_hosts
 
        while (getdns_hosts_fileent(ctx, fp, &host_name, &name_type, &next_name, &return_ss, &srv_port)) {
                if (!strequal(name, host_name)) {
-                       TALLOC_FREE(ctx);
-                       ctx = talloc_new(mem_ctx);
-                       if (!ctx) {
-                               enddns_hosts_file(fp);
-                               return NT_STATUS_NO_MEMORY;
-                       }
-
-                       continue;
-               }
-
-               if (srv_lookup) {
+                       /* continue at the bottom of the loop */
+               } else if (srv_lookup) {
                        if (strcasecmp(name_type, "SRV") == 0) {
+                               NTSTATUS status_recurse;
+                               struct dns_rr_srv *tmp_rr;
+                               int tmp_count = 0;
                                /* we only accept one host name per SRV entry */
-                               enddns_hosts_file(fp);
-                               status = resolve_dns_hosts_file_as_sockaddr_recurse(dns_hosts_file, next_name, 
-                                                                                   false, 
-                                                                                   level + 1, srv_port, 
-                                                                                   mem_ctx, return_iplist, 
-                                                                                   return_count);
-                               talloc_free(ip_list_ctx);
-                               return status;
-                       } else {
-                               continue;
+                               status_recurse
+                                       = resolve_dns_hosts_file_as_dns_rr_recurse(dns_hosts_file, next_name,
+                                                                                    false,
+                                                                                    level + 1, srv_port,
+                                                                                    ip_list_ctx, &tmp_rr,
+                                                                                    &tmp_count);
+                               if (NT_STATUS_EQUAL(status_recurse, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+                                       /* Don't fail on a dangling SRV record */
+                               } else if (!NT_STATUS_IS_OK(status_recurse)) {
+                                       enddns_hosts_file(fp);
+                                       talloc_free(ip_list_ctx);
+                                       return status_recurse;
+                               } else if (tmp_count != 1) {
+                                       status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                               } else {
+                                       status = status_recurse;
+                                       rr = talloc_realloc(ip_list_ctx, rr, struct dns_rr_srv, (*return_count) + 1);
+                                       if (!rr) {
+                                               enddns_hosts_file(fp);
+                                               return NT_STATUS_NO_MEMORY;
+                                       }
+                                       talloc_steal(rr, tmp_rr);
+                                       rr[*return_count] = *tmp_rr;
+                                       *return_count = (*return_count) + 1;
+                               }
                        }
                } else if (strcasecmp(name_type, "CNAME") == 0) {
                        /* we only accept one host name per CNAME */
                        enddns_hosts_file(fp);
-                       status = resolve_dns_hosts_file_as_sockaddr_recurse(dns_hosts_file, next_name, false, 
-                                                                           level + 1, port, 
-                                                                           mem_ctx, return_iplist, return_count);
+                       status = resolve_dns_hosts_file_as_dns_rr_recurse(dns_hosts_file, next_name, false,
+                                                                         level + 1, port,
+                                                                         mem_ctx, return_rr, return_count);
                        talloc_free(ip_list_ctx);
                        return status;
                } else if (strcasecmp(name_type, "A") == 0) {
+                       if (*return_count == 0) {
+                               /* We are happy to keep looking for other possible A record matches */
+                               rr = talloc_zero(ip_list_ctx,
+                                                 struct dns_rr_srv);
+
+                               if (rr == NULL) {
+                                       TALLOC_FREE(ctx);
+                                       enddns_hosts_file(fp);
+                                       DEBUG(3,("resolve_dns_hosts: talloc_realloc fail !\n"));
+                                       return NT_STATUS_NO_MEMORY;
+                               }
+
+                               rr->hostname = talloc_strdup(rr, host_name);
+
+                               if (rr->hostname == NULL) {
+                                       TALLOC_FREE(ctx);
+                                       enddns_hosts_file(fp);
+                                       DEBUG(3,("resolve_dns_hosts: talloc_realloc fail !\n"));
+                                       return NT_STATUS_NO_MEMORY;
+                               }
+                               rr->port = port;
+
+                               *return_count = 1;
+                       }
+
                        /* Set the specified port (possibly from a SRV lookup) into the structure we return */
                        set_sockaddr_port((struct sockaddr *)&return_ss, port);
 
                        /* We are happy to keep looking for other possible A record matches */
-                       *return_iplist = talloc_realloc(ip_list_ctx, (*return_iplist), 
-                                                       struct sockaddr_storage,
-                                                       (*return_count)+1);
+                       rr->ss_s = talloc_realloc(rr, rr->ss_s,
+                                                 struct sockaddr_storage,
+                                                 rr->num_ips + 1);
 
-                       if ((*return_iplist) == NULL) {
+                       if (rr->ss_s == NULL) {
                                TALLOC_FREE(ctx);
                                enddns_hosts_file(fp);
                                DEBUG(3,("resolve_dns_hosts: talloc_realloc fail !\n"));
                                return NT_STATUS_NO_MEMORY;
                        }
-                       
-                       (*return_iplist)[*return_count] = return_ss;
-                       *return_count += 1;
-                       
+
+                       rr->ss_s[rr->num_ips] = return_ss;
+                       rr->num_ips += 1;
+
                        /* we found something */
                        status = NT_STATUS_OK;
                }
+
+               TALLOC_FREE(ctx);
+               ctx = talloc_new(mem_ctx);
+               if (!ctx) {
+                       enddns_hosts_file(fp);
+                       return NT_STATUS_NO_MEMORY;
+               }
        }
 
-       talloc_steal(mem_ctx, *return_iplist);
+       *return_rr = talloc_steal(mem_ctx, rr);
        TALLOC_FREE(ip_list_ctx);
        enddns_hosts_file(fp);
        return status;
 }
 
 /********************************************************
- Resolve via "dns_hosts" method.
+ Resolve via "dns_hosts_file" method, returning a list of sockaddr_storage values
 *********************************************************/
 
-NTSTATUS resolve_dns_hosts_file_as_sockaddr(const char *dns_hosts_file, 
+NTSTATUS resolve_dns_hosts_file_as_sockaddr(const char *dns_hosts_file,
                                            const char *name, bool srv_lookup,
-                                           TALLOC_CTX *mem_ctx, 
+                                           TALLOC_CTX *mem_ctx,
                                            struct sockaddr_storage **return_iplist,
                                            int *return_count)
 {
-       return resolve_dns_hosts_file_as_sockaddr_recurse(dns_hosts_file, name, srv_lookup, 
-                                                         0, 0, 
-                                                         mem_ctx, return_iplist, return_count);
+       NTSTATUS status;
+       struct dns_rr_srv *dns_rr = NULL;
+       int i, j, rr_count = 0;
+
+       *return_iplist = NULL;
+       *return_count = 0;
+
+       status = resolve_dns_hosts_file_as_dns_rr_recurse(dns_hosts_file, name, srv_lookup,
+                                                         0, 0,
+                                                         mem_ctx, &dns_rr, &rr_count);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(3,("resolve_dns_hosts (sockaddr): "
+                        "failed to obtain %s result records for for name %s: %s\n",
+                        srv_lookup ? "SRV" : "A", name, nt_errstr(status)));
+               return status;
+       }
+
+       for (i=0; i < rr_count; i++) {
+               *return_iplist = talloc_realloc(mem_ctx, *return_iplist, struct sockaddr_storage, *return_count + dns_rr[i].num_ips);
+               if (!*return_iplist) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               for (j=0; j < dns_rr[i].num_ips; j++) {
+                       (*return_iplist)[*return_count] = dns_rr[i].ss_s[j];
+                       *return_count = *return_count + 1;
+               }
+       }
+       DEBUG(3,("resolve_dns_hosts (sockaddr): "
+               "Found %d results for for name %s\n",
+                *return_count, name));
+
+       return NT_STATUS_OK;
+}
+
+/********************************************************
+ Resolve via "dns_hosts_file" method, returning struct dns_rr_srv
+*********************************************************/
+
+NTSTATUS resolve_dns_hosts_file_as_dns_rr(const char *dns_hosts_file,
+                                           const char *name, bool srv_lookup,
+                                           TALLOC_CTX *mem_ctx,
+                                           struct dns_rr_srv **return_rr,
+                                           int *return_count)
+{
+       NTSTATUS status;
+       *return_rr = NULL;
+       *return_count = 0;
+
+       status = resolve_dns_hosts_file_as_dns_rr_recurse(dns_hosts_file, name, srv_lookup,
+                                                         0, 0,
+                                                         mem_ctx, return_rr, return_count);
+
+       if (NT_STATUS_IS_OK(status)) {
+               DEBUG(3,("resolve_dns_hosts (dns_rr): "
+                        "Found %d %s result records for for name %s\n",
+                        *return_count, srv_lookup ? "SRV" : "A", name));
+       } else {
+               DEBUG(3,("resolve_dns_hosts (dns_rr): "
+                        "failed to obtain %s result records for for name %s: %s\n",
+                        srv_lookup ? "SRV" : "A", name, nt_errstr(status)));
+       }
+       return status;
 }
index 6f7a1745b75aca8dcfbe8847d09aef28ed4e3550..07d8c51b1f46757a93650dd4f0a51bff7c95c059 100644 (file)
@@ -7,13 +7,13 @@ bld.SAMBA_SUBSYSTEM('NDR_NBT_BUF',
        )
 
 bld.SAMBA_SUBSYSTEM('lmhosts',
-                    source='lmhosts.c',
+                    source='lmhosts.c ../dns/dns_hosts_file.c',
                     deps='replace talloc'
                     )
 
 if bld.env._SAMBA_BUILD_ == 4:
     bld.SAMBA_LIBRARY('cli-nbt',
-                      source='nbtsocket.c namequery.c nameregister.c namerefresh.c namerelease.c dns_hosts_file.c',
+                      source='nbtsocket.c namequery.c nameregister.c namerefresh.c namerelease.c',
                       public_deps='ndr NDR_NBT tevent UTIL_TEVENT NDR_SECURITY samba_socket samba-util lmhosts',
                       private_library=True
                       )
index 3c0dd0918a36ffd5630b8d45f9e8f2a4b4cfbdad..a829b097974377b631a1ebcb4015aeec925abf41 100644 (file)
@@ -515,6 +515,8 @@ sub provision($$$$$$)
        my $bindir_abs = abs_path($self->{bindir});
        my $vfs_modulesdir_abs = ($ENV{VFSLIBDIR} or $bindir_abs);
 
+       my $dns_host_file = "$ENV{SELFTEST_PREFIX}/dns_host_file";
+
        my @dirs = ();
 
        my $shrdir="$prefix_abs/share";
@@ -714,6 +716,8 @@ sub provision($$$$$$)
        ncalrpc dir = $lockdir/ncalrpc
        rpc_server:epmapper = embedded
 
+        resolv:host file = $dns_host_file
+
        # Begin extra options
        $extra_options
        # End extra options
index b747e97bb77e339c3e1478e082d78412ffaf61ff..f53153ba263642478b0d8c9d2cf18f951afd9361 100644 (file)
 #ifndef _ADS_DNS_H
 #define _ADS_DNS_H
 
-/* DNS query section in replies */
-
-struct dns_query {
-       const char *hostname;
-       uint16 type;
-       uint16 in_class;
-};
-
-/* DNS RR record in reply */
-
-struct dns_rr {
-       const char *hostname;
-       uint16 type;
-       uint16 in_class;
-       uint32 ttl;
-       uint16 rdatalen;
-       uint8 *rdata;
-};
-
-/* SRV records */
-
-struct dns_rr_srv {
-       const char *hostname;
-       uint16 priority;
-       uint16 weight;
-       uint16 port;
-       size_t num_ips;
-       struct sockaddr_storage *ss_s;  /* support multi-homed hosts */
-};
-
-/* NS records */
-
-struct dns_rr_ns {
-       const char *hostname;
-       struct sockaddr_storage ss;
-};
+#include "libcli/dns/dns.h"
 
 /* The following definitions come from libads/dns.c  */