1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

libcli/dns Improve dns_hosts_file, using Samba3's struct dns_rr_srv

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
This commit is contained in:
Andrew Bartlett 2011-04-26 09:49:08 +10:00
parent 3a88d49d12
commit c18954775e
5 changed files with 235 additions and 90 deletions

68
libcli/dns/dns.h Normal file
View File

@ -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);

View 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
@ -29,6 +29,11 @@
#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;
}

View 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
)

View 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

View File

@ -20,42 +20,7 @@
#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 */