2007-10-29 23:34:00 +03:00
/*
2006-05-05 23:24:48 +04:00
Unix SMB / CIFS implementation .
DNS utility library
Copyright ( C ) Gerald ( Jerry ) Carter 2006.
2007-10-29 23:34:00 +03:00
Copyright ( C ) Jeremy Allison 2007.
2006-05-05 23:24:48 +04:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2006-05-05 23:24:48 +04:00
( at your option ) any later version .
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
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 .
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2006-05-05 23:24:48 +04:00
*/
# include "includes.h"
2010-07-01 00:36:40 +04:00
# include "libads/dns.h"
2011-03-31 01:47:34 +04:00
# include "../librpc/ndr/libndr.h"
2006-05-05 23:24:48 +04:00
/* AIX resolv.h uses 'class' in struct ns_rr */
# if defined(AIX)
# if defined(class)
# undef class
# endif
# endif /* AIX */
/* resolver headers */
# include <sys/types.h>
# include <netinet/in.h>
# include <arpa/nameser.h>
# include <resolv.h>
# include <netdb.h>
# define MAX_DNS_PACKET_SIZE 0xffff
2006-05-06 01:19:25 +04:00
# ifdef NS_HFIXEDSZ /* Bind 8/9 interface */
2006-07-11 22:01:26 +04:00
# if !defined(C_IN) /* AIX 5.3 already defines C_IN */
2006-05-06 01:19:25 +04:00
# define C_IN ns_c_in
2006-07-11 22:01:26 +04:00
# endif
# if !defined(T_A) /* AIX 5.3 already defines T_A */
2006-05-06 01:19:25 +04:00
# define T_A ns_t_a
2006-07-11 22:01:26 +04:00
# endif
2007-10-29 23:34:00 +03:00
# if defined(HAVE_IPV6)
# if !defined(T_AAAA)
# define T_AAAA ns_t_aaaa
# endif
# endif
2006-05-06 01:19:25 +04:00
# define T_SRV ns_t_srv
2006-09-13 17:02:51 +04:00
# if !defined(T_NS) /* AIX 5.3 already defines T_NS */
2006-07-20 00:53:10 +04:00
# define T_NS ns_t_ns
2006-09-13 17:02:51 +04:00
# endif
2006-05-06 01:19:25 +04:00
# else
2006-05-06 00:18:50 +04:00
# ifdef HFIXEDSZ
# define NS_HFIXEDSZ HFIXEDSZ
# else
2006-05-06 01:19:25 +04:00
# define NS_HFIXEDSZ sizeof(HEADER)
2006-05-12 20:38:51 +04:00
# endif /* HFIXEDSZ */
# ifdef PACKETSZ
# define NS_PACKETSZ PACKETSZ
# else /* 512 is usually the default */
# define NS_PACKETSZ 512
# endif /* PACKETSZ */
2006-05-06 01:19:25 +04:00
# define T_SRV 33
2006-05-06 00:18:50 +04:00
# endif
2006-05-05 23:24:48 +04:00
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool ads_dns_parse_query ( TALLOC_CTX * ctx , uint8 * start , uint8 * end ,
2006-05-05 23:24:48 +04:00
uint8 * * ptr , struct dns_query * q )
{
uint8 * p = * ptr ;
2007-11-16 05:27:26 +03:00
char hostname [ MAX_DNS_NAME_LENGTH ] ;
2006-05-05 23:24:48 +04:00
int namelen ;
ZERO_STRUCTP ( q ) ;
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
if ( ! start | | ! end | | ! q | | ! * ptr )
return False ;
/* See RFC 1035 for details. If this fails, then return. */
namelen = dn_expand ( start , end , p , hostname , sizeof ( hostname ) ) ;
if ( namelen < 0 ) {
return False ;
}
p + = namelen ;
q - > hostname = talloc_strdup ( ctx , hostname ) ;
/* check that we have space remaining */
if ( PTR_DIFF ( p + 4 , end ) > 0 )
return False ;
q - > type = RSVAL ( p , 0 ) ;
q - > in_class = RSVAL ( p , 2 ) ;
p + = 4 ;
* ptr = p ;
return True ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool ads_dns_parse_rr ( TALLOC_CTX * ctx , uint8 * start , uint8 * end ,
2006-05-05 23:24:48 +04:00
uint8 * * ptr , struct dns_rr * rr )
{
uint8 * p = * ptr ;
2007-11-16 05:27:26 +03:00
char hostname [ MAX_DNS_NAME_LENGTH ] ;
2006-05-05 23:24:48 +04:00
int namelen ;
if ( ! start | | ! end | | ! rr | | ! * ptr )
return - 1 ;
ZERO_STRUCTP ( rr ) ;
/* pull the name from the answer */
namelen = dn_expand ( start , end , p , hostname , sizeof ( hostname ) ) ;
if ( namelen < 0 ) {
return - 1 ;
}
p + = namelen ;
rr - > hostname = talloc_strdup ( ctx , hostname ) ;
/* check that we have space remaining */
if ( PTR_DIFF ( p + 10 , end ) > 0 )
return False ;
/* pull some values and then skip onto the string */
rr - > type = RSVAL ( p , 0 ) ;
rr - > in_class = RSVAL ( p , 2 ) ;
rr - > ttl = RIVAL ( p , 4 ) ;
rr - > rdatalen = RSVAL ( p , 8 ) ;
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
p + = 10 ;
/* sanity check the available space */
if ( PTR_DIFF ( p + rr - > rdatalen , end ) > 0 ) {
return False ;
}
/* save a point to the rdata for this section */
rr - > rdata = p ;
p + = rr - > rdatalen ;
* ptr = p ;
return True ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool ads_dns_parse_rr_srv ( TALLOC_CTX * ctx , uint8 * start , uint8 * end ,
2006-05-05 23:24:48 +04:00
uint8 * * ptr , struct dns_rr_srv * srv )
{
struct dns_rr rr ;
uint8 * p ;
2007-11-16 05:27:26 +03:00
char dcname [ MAX_DNS_NAME_LENGTH ] ;
2006-05-05 23:24:48 +04:00
int namelen ;
if ( ! start | | ! end | | ! srv | | ! * ptr )
return - 1 ;
2007-10-29 23:34:00 +03:00
/* Parse the RR entry. Coming out of the this, ptr is at the beginning
2006-05-05 23:24:48 +04:00
of the next record */
if ( ! ads_dns_parse_rr ( ctx , start , end , ptr , & rr ) ) {
DEBUG ( 1 , ( " ads_dns_parse_rr_srv: Failed to parse RR record \n " ) ) ;
return False ;
}
2006-05-06 01:19:25 +04:00
if ( rr . type ! = T_SRV ) {
2007-10-29 23:34:00 +03:00
DEBUG ( 1 , ( " ads_dns_parse_rr_srv: Bad answer type (%d) \n " ,
rr . type ) ) ;
2006-05-05 23:24:48 +04:00
return False ;
}
p = rr . rdata ;
srv - > priority = RSVAL ( p , 0 ) ;
srv - > weight = RSVAL ( p , 2 ) ;
srv - > port = RSVAL ( p , 4 ) ;
p + = 6 ;
namelen = dn_expand ( start , end , p , dcname , sizeof ( dcname ) ) ;
if ( namelen < 0 ) {
DEBUG ( 1 , ( " ads_dns_parse_rr_srv: Failed to uncompress name! \n " ) ) ;
return False ;
}
2008-04-30 18:57:15 +04:00
2006-05-05 23:24:48 +04:00
srv - > hostname = talloc_strdup ( ctx , dcname ) ;
2008-04-30 18:57:15 +04:00
DEBUG ( 10 , ( " ads_dns_parse_rr_srv: Parsed %s [%u, %u, %u] \n " ,
srv - > hostname ,
srv - > priority ,
srv - > weight ,
srv - > port ) ) ;
2006-05-05 23:24:48 +04:00
return True ;
}
2006-07-20 00:53:10 +04:00
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool ads_dns_parse_rr_ns ( TALLOC_CTX * ctx , uint8 * start , uint8 * end ,
2006-07-20 00:53:10 +04:00
uint8 * * ptr , struct dns_rr_ns * nsrec )
{
struct dns_rr rr ;
uint8 * p ;
2007-11-16 05:27:26 +03:00
char nsname [ MAX_DNS_NAME_LENGTH ] ;
2006-07-20 00:53:10 +04:00
int namelen ;
if ( ! start | | ! end | | ! nsrec | | ! * ptr )
return - 1 ;
2007-10-29 23:34:00 +03:00
/* Parse the RR entry. Coming out of the this, ptr is at the beginning
2006-07-20 00:53:10 +04:00
of the next record */
if ( ! ads_dns_parse_rr ( ctx , start , end , ptr , & rr ) ) {
DEBUG ( 1 , ( " ads_dns_parse_rr_ns: Failed to parse RR record \n " ) ) ;
return False ;
}
if ( rr . type ! = T_NS ) {
2007-10-29 23:34:00 +03:00
DEBUG ( 1 , ( " ads_dns_parse_rr_ns: Bad answer type (%d) \n " ,
rr . type ) ) ;
2006-07-20 00:53:10 +04:00
return False ;
}
p = rr . rdata ;
/* ame server hostname */
2007-10-29 23:34:00 +03:00
2006-07-20 00:53:10 +04:00
namelen = dn_expand ( start , end , p , nsname , sizeof ( nsname ) ) ;
if ( namelen < 0 ) {
DEBUG ( 1 , ( " ads_dns_parse_rr_ns: Failed to uncompress name! \n " ) ) ;
return False ;
}
nsrec - > hostname = talloc_strdup ( ctx , nsname ) ;
return True ;
}
2006-05-05 23:24:48 +04:00
/*********************************************************************
Sort SRV record list based on weight and priority . See RFC 2782.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int dnssrvcmp ( struct dns_rr_srv * a , struct dns_rr_srv * b )
{
if ( a - > priority = = b - > priority ) {
/* randomize entries with an equal weight and priority */
2007-10-29 23:34:00 +03:00
if ( a - > weight = = b - > weight )
2006-07-25 23:59:35 +04:00
return 0 ;
2006-05-05 23:24:48 +04:00
2007-10-29 23:34:00 +03:00
/* higher weights should be sorted lower */
2006-05-05 23:24:48 +04:00
if ( a - > weight > b - > weight )
return - 1 ;
else
return 1 ;
}
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
if ( a - > priority < b - > priority )
return - 1 ;
return 1 ;
}
/*********************************************************************
2006-07-20 00:53:10 +04:00
Simple wrapper for a DNS query
2006-05-05 23:24:48 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-05-07 01:06:55 +04:00
# define DNS_FAILED_WAITTIME 30
2007-10-29 23:34:00 +03:00
static NTSTATUS dns_send_req ( TALLOC_CTX * ctx , const char * name , int q_type ,
2006-07-20 00:53:10 +04:00
uint8 * * buf , int * resp_length )
2006-05-05 23:24:48 +04:00
{
uint8 * buffer = NULL ;
2008-04-30 18:57:15 +04:00
size_t buf_len = 0 ;
2007-10-29 23:34:00 +03:00
int resp_len = NS_PACKETSZ ;
2007-05-07 01:06:55 +04:00
static time_t last_dns_check = 0 ;
2007-10-29 23:34:00 +03:00
static NTSTATUS last_dns_status = NT_STATUS_OK ;
2010-09-07 03:54:01 +04:00
time_t now = time_mono ( NULL ) ;
2007-05-07 01:06:55 +04:00
/* Try to prevent bursts of DNS lookups if the server is down */
/* Protect against large clock changes */
if ( last_dns_check > now )
last_dns_check = 0 ;
2007-10-29 23:34:00 +03:00
/* IF we had a DNS timeout or a bad server and we are still
in the 30 second cache window , just return the previous
2007-05-07 01:06:55 +04:00
status and save the network timeout . */
if ( ( NT_STATUS_EQUAL ( last_dns_status , NT_STATUS_IO_TIMEOUT ) | |
NT_STATUS_EQUAL ( last_dns_status , NT_STATUS_CONNECTION_REFUSED ) ) & &
2007-10-29 23:34:00 +03:00
( last_dns_check + DNS_FAILED_WAITTIME ) > now )
2007-05-07 01:06:55 +04:00
{
DEBUG ( 10 , ( " last_dns_check: Returning cached status (%s) \n " ,
nt_errstr ( last_dns_status ) ) ) ;
return last_dns_status ;
}
/* Send the Query */
2006-05-05 23:24:48 +04:00
do {
if ( buffer )
TALLOC_FREE ( buffer ) ;
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
buf_len = resp_len * sizeof ( uint8 ) ;
2007-10-29 23:34:00 +03:00
if ( buf_len ) {
2011-06-07 05:30:12 +04:00
if ( ( buffer = talloc_array ( ctx , uint8 , buf_len ) )
2007-10-29 23:34:00 +03:00
= = NULL ) {
DEBUG ( 0 , ( " ads_dns_lookup_srv: "
" talloc() failed! \n " ) ) ;
2007-05-07 01:06:55 +04:00
last_dns_status = NT_STATUS_NO_MEMORY ;
2010-09-07 03:54:01 +04:00
last_dns_check = time_mono ( NULL ) ;
2007-10-29 23:34:00 +03:00
return last_dns_status ;
2007-04-30 06:39:34 +04:00
}
2006-05-05 23:24:48 +04:00
}
2007-10-29 23:34:00 +03:00
if ( ( resp_len = res_query ( name , C_IN , q_type , buffer , buf_len ) )
< 0 ) {
DEBUG ( 3 , ( " ads_dns_lookup_srv: "
" Failed to resolve %s (%s) \n " ,
name , strerror ( errno ) ) ) ;
2006-05-05 23:24:48 +04:00
TALLOC_FREE ( buffer ) ;
2007-05-07 01:06:55 +04:00
last_dns_status = NT_STATUS_UNSUCCESSFUL ;
2007-10-29 23:34:00 +03:00
2007-01-17 22:20:11 +03:00
if ( errno = = ETIMEDOUT ) {
2007-10-29 23:34:00 +03:00
last_dns_status = NT_STATUS_IO_TIMEOUT ;
2007-01-17 22:20:11 +03:00
}
if ( errno = = ECONNREFUSED ) {
2007-10-29 23:34:00 +03:00
last_dns_status = NT_STATUS_CONNECTION_REFUSED ;
2007-01-17 22:20:11 +03:00
}
2010-09-07 03:54:01 +04:00
last_dns_check = time_mono ( NULL ) ;
2007-05-07 01:06:55 +04:00
return last_dns_status ;
2006-05-05 23:24:48 +04:00
}
2008-04-30 18:57:15 +04:00
/* On AIX, Solaris, and possibly some older glibc systems (e.g. SLES8)
truncated replies never give back a resp_len > buflen
which ends up causing DNS resolve failures on large tcp DNS replies */
if ( buf_len = = resp_len ) {
if ( resp_len = = MAX_DNS_PACKET_SIZE ) {
DEBUG ( 1 , ( " dns_send_req: DNS reply too large when resolving %s \n " ,
name ) ) ;
TALLOC_FREE ( buffer ) ;
last_dns_status = NT_STATUS_BUFFER_TOO_SMALL ;
2010-09-07 03:54:01 +04:00
last_dns_check = time_mono ( NULL ) ;
2008-04-30 18:57:15 +04:00
return last_dns_status ;
}
resp_len = MIN ( resp_len * 2 , MAX_DNS_PACKET_SIZE ) ;
}
} while ( buf_len < resp_len & & resp_len < = MAX_DNS_PACKET_SIZE ) ;
2007-10-29 23:34:00 +03:00
2006-07-20 00:53:10 +04:00
* buf = buffer ;
* resp_length = resp_len ;
2010-09-07 03:54:01 +04:00
last_dns_check = time_mono ( NULL ) ;
2007-10-29 23:34:00 +03:00
last_dns_status = NT_STATUS_OK ;
2007-05-07 01:06:55 +04:00
return last_dns_status ;
2006-07-20 00:53:10 +04:00
}
/*********************************************************************
Simple wrapper for a DNS SRV query
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-29 23:34:00 +03:00
static NTSTATUS ads_dns_lookup_srv ( TALLOC_CTX * ctx ,
const char * name ,
struct dns_rr_srv * * dclist ,
int * numdcs )
2006-07-20 00:53:10 +04:00
{
uint8 * buffer = NULL ;
int resp_len = 0 ;
struct dns_rr_srv * dcs = NULL ;
int query_count , answer_count , auth_count , additional_count ;
uint8 * p = buffer ;
int rrnum ;
int idx = 0 ;
NTSTATUS status ;
2011-04-26 06:08:22 +04:00
const char * dns_hosts_file ;
2006-07-20 00:53:10 +04:00
if ( ! ctx | | ! name | | ! dclist ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2007-10-29 23:34:00 +03:00
2011-04-26 06:08:22 +04:00
dns_hosts_file = lp_parm_const_string ( - 1 , " resolv " , " host file " , NULL ) ;
if ( dns_hosts_file ) {
return resolve_dns_hosts_file_as_dns_rr ( dns_hosts_file ,
name , true , ctx ,
dclist , numdcs ) ;
}
2007-10-29 23:34:00 +03:00
/* Send the request. May have to loop several times in case
2006-07-20 00:53:10 +04:00
of large replies */
2006-05-05 23:24:48 +04:00
2006-07-20 00:53:10 +04:00
status = dns_send_req ( ctx , name , T_SRV , & buffer , & resp_len ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2006-09-08 01:08:29 +04:00
DEBUG ( 3 , ( " ads_dns_lookup_srv: Failed to send DNS query (%s) \n " ,
2006-07-20 00:53:10 +04:00
nt_errstr ( status ) ) ) ;
return status ;
}
2006-05-05 23:24:48 +04:00
p = buffer ;
/* For some insane reason, the ns_initparse() et. al. routines are only
available in libresolv . a , and not the shared lib . Who knows why . . . .
So we have to parse the DNS reply ourselves */
2007-10-29 23:34:00 +03:00
/* Pull the answer RR's count from the header.
* Use the NMB ordering macros */
2006-05-05 23:24:48 +04:00
query_count = RSVAL ( p , 4 ) ;
answer_count = RSVAL ( p , 6 ) ;
auth_count = RSVAL ( p , 8 ) ;
additional_count = RSVAL ( p , 10 ) ;
2007-10-29 23:34:00 +03:00
DEBUG ( 4 , ( " ads_dns_lookup_srv: "
" %d records returned in the answer section. \n " ,
2006-05-05 23:24:48 +04:00
answer_count ) ) ;
2007-10-29 23:34:00 +03:00
2007-04-30 06:51:26 +04:00
if ( answer_count ) {
2011-06-07 05:58:39 +04:00
if ( ( dcs = talloc_zero_array ( ctx , struct dns_rr_srv ,
2007-10-29 23:34:00 +03:00
answer_count ) ) = = NULL ) {
DEBUG ( 0 , ( " ads_dns_lookup_srv: "
" talloc() failure for %d char*'s \n " ,
2007-04-30 06:51:26 +04:00
answer_count ) ) ;
return NT_STATUS_NO_MEMORY ;
}
} else {
dcs = NULL ;
2006-05-05 23:24:48 +04:00
}
/* now skip the header */
p + = NS_HFIXEDSZ ;
/* parse the query section */
for ( rrnum = 0 ; rrnum < query_count ; rrnum + + ) {
struct dns_query q ;
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_query ( ctx , buffer ,
buffer + resp_len , & p , & q ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_srv: "
2008-04-30 18:57:15 +04:00
" Failed to parse query record [%d]! \n " , rrnum ) ) ;
2006-05-05 23:24:48 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
}
/* now we are at the answer section */
for ( rrnum = 0 ; rrnum < answer_count ; rrnum + + ) {
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_rr_srv ( ctx , buffer , buffer + resp_len ,
& p , & dcs [ rrnum ] ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_srv: "
2008-04-30 18:57:15 +04:00
" Failed to parse answer recordi [%d]! \n " , rrnum ) ) ;
2006-05-05 23:24:48 +04:00
return NT_STATUS_UNSUCCESSFUL ;
2007-10-29 23:34:00 +03:00
}
2006-05-05 23:24:48 +04:00
}
idx = rrnum ;
/* Parse the authority section */
/* just skip these for now */
for ( rrnum = 0 ; rrnum < auth_count ; rrnum + + ) {
struct dns_rr rr ;
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_rr ( ctx , buffer ,
buffer + resp_len , & p , & rr ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_srv: "
2008-04-30 18:57:15 +04:00
" Failed to parse authority record! [%d] \n " , rrnum ) ) ;
2006-05-05 23:24:48 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
}
/* Parse the additional records section */
for ( rrnum = 0 ; rrnum < additional_count ; rrnum + + ) {
struct dns_rr rr ;
int i ;
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_rr ( ctx , buffer , buffer + resp_len ,
& p , & rr ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_srv: Failed "
2008-04-30 18:57:15 +04:00
" to parse additional records section! [%d] \n " , rrnum ) ) ;
2006-05-05 23:24:48 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
2007-10-29 23:34:00 +03:00
/* Only interested in A or AAAA records as a shortcut for having
* to come back later and lookup the name . For multi - homed
* hosts , the number of additional records and exceed the
* number of answer records . */
if ( rr . type ! = T_A | | rr . rdatalen ! = 4 ) {
# if defined(HAVE_IPV6)
2009-09-23 16:40:25 +04:00
/* RFC2874 defines A6 records. This
2007-10-29 23:34:00 +03:00
* requires recusive and horribly complex lookups .
* Bastards . Ignore this for now . . . . JRA .
2009-09-23 16:40:25 +04:00
* Luckily RFC3363 reprecates A6 records .
2007-10-29 23:34:00 +03:00
*/
if ( rr . type ! = T_AAAA | | rr . rdatalen ! = 16 )
# endif
continue ;
}
2006-05-05 23:24:48 +04:00
for ( i = 0 ; i < idx ; i + + ) {
if ( strcmp ( rr . hostname , dcs [ i ] . hostname ) = = 0 ) {
2006-08-24 16:13:57 +04:00
int num_ips = dcs [ i ] . num_ips ;
2007-10-29 23:34:00 +03:00
struct sockaddr_storage * tmp_ss_s ;
2006-08-24 16:13:57 +04:00
/* allocate new memory */
2007-10-29 23:34:00 +03:00
if ( dcs [ i ] . num_ips = = 0 ) {
2011-06-07 05:30:12 +04:00
if ( ( dcs [ i ] . ss_s = talloc_array ( dcs ,
2007-10-29 23:34:00 +03:00
struct sockaddr_storage , 1 ) )
= = NULL ) {
2006-08-24 16:13:57 +04:00
return NT_STATUS_NO_MEMORY ;
}
} else {
2011-06-07 05:10:15 +04:00
if ( ( tmp_ss_s = talloc_realloc ( dcs ,
2007-10-29 23:34:00 +03:00
dcs [ i ] . ss_s ,
struct sockaddr_storage ,
dcs [ i ] . num_ips + 1 ) )
= = NULL ) {
2006-08-24 16:13:57 +04:00
return NT_STATUS_NO_MEMORY ;
}
2007-10-29 23:34:00 +03:00
dcs [ i ] . ss_s = tmp_ss_s ;
2006-08-24 16:13:57 +04:00
}
dcs [ i ] . num_ips + + ;
2007-10-29 23:34:00 +03:00
2006-08-24 16:13:57 +04:00
/* copy the new IP address */
2007-10-29 23:34:00 +03:00
if ( rr . type = = T_A ) {
struct in_addr ip ;
memcpy ( & ip , rr . rdata , 4 ) ;
in_addr_to_sockaddr_storage (
& dcs [ i ] . ss_s [ num_ips ] ,
ip ) ;
}
# if defined(HAVE_IPV6)
if ( rr . type = = T_AAAA ) {
struct in6_addr ip6 ;
memcpy ( & ip6 , rr . rdata , rr . rdatalen ) ;
in6_addr_to_sockaddr_storage (
& dcs [ i ] . ss_s [ num_ips ] ,
ip6 ) ;
}
# endif
2006-05-05 23:24:48 +04:00
}
}
}
2010-02-14 02:00:49 +03:00
TYPESAFE_QSORT ( dcs , idx , dnssrvcmp ) ;
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
* dclist = dcs ;
* numdcs = idx ;
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
return NT_STATUS_OK ;
}
2006-07-20 00:53:10 +04:00
/*********************************************************************
Simple wrapper for a DNS NS query
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-29 23:34:00 +03:00
NTSTATUS ads_dns_lookup_ns ( TALLOC_CTX * ctx ,
const char * dnsdomain ,
struct dns_rr_ns * * nslist ,
int * numns )
2006-07-20 00:53:10 +04:00
{
uint8 * buffer = NULL ;
int resp_len = 0 ;
struct dns_rr_ns * nsarray = NULL ;
int query_count , answer_count , auth_count , additional_count ;
uint8 * p ;
int rrnum ;
int idx = 0 ;
NTSTATUS status ;
2011-04-26 06:08:22 +04:00
const char * dns_hosts_file ;
2006-07-20 00:53:10 +04:00
if ( ! ctx | | ! dnsdomain | | ! nslist ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2007-10-29 23:34:00 +03:00
2011-04-26 06:08:22 +04:00
dns_hosts_file = lp_parm_const_string ( - 1 , " resolv " , " host file " , NULL ) ;
if ( dns_hosts_file ) {
DEBUG ( 1 , ( " NO 'NS' lookup available when using resolv:host file " ) ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2007-10-29 23:34:00 +03:00
/* Send the request. May have to loop several times in case
2006-07-20 00:53:10 +04:00
of large replies */
2007-10-29 23:34:00 +03:00
2006-07-20 00:53:10 +04:00
status = dns_send_req ( ctx , dnsdomain , T_NS , & buffer , & resp_len ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2006-09-08 01:08:29 +04:00
DEBUG ( 3 , ( " ads_dns_lookup_ns: Failed to send DNS query (%s) \n " ,
2006-07-20 00:53:10 +04:00
nt_errstr ( status ) ) ) ;
return status ;
}
p = buffer ;
/* For some insane reason, the ns_initparse() et. al. routines are only
available in libresolv . a , and not the shared lib . Who knows why . . . .
So we have to parse the DNS reply ourselves */
2007-10-29 23:34:00 +03:00
/* Pull the answer RR's count from the header.
* Use the NMB ordering macros */
2006-07-20 00:53:10 +04:00
query_count = RSVAL ( p , 4 ) ;
answer_count = RSVAL ( p , 6 ) ;
auth_count = RSVAL ( p , 8 ) ;
additional_count = RSVAL ( p , 10 ) ;
2007-10-29 23:34:00 +03:00
DEBUG ( 4 , ( " ads_dns_lookup_ns: "
" %d records returned in the answer section. \n " ,
2006-07-20 00:53:10 +04:00
answer_count ) ) ;
2007-10-29 23:34:00 +03:00
2007-04-30 06:39:34 +04:00
if ( answer_count ) {
2011-06-07 05:30:12 +04:00
if ( ( nsarray = talloc_array ( ctx , struct dns_rr_ns ,
2007-10-29 23:34:00 +03:00
answer_count ) ) = = NULL ) {
DEBUG ( 0 , ( " ads_dns_lookup_ns: "
" talloc() failure for %d char*'s \n " ,
2007-04-30 06:39:34 +04:00
answer_count ) ) ;
return NT_STATUS_NO_MEMORY ;
}
} else {
nsarray = NULL ;
2006-07-20 00:53:10 +04:00
}
/* now skip the header */
p + = NS_HFIXEDSZ ;
/* parse the query section */
for ( rrnum = 0 ; rrnum < query_count ; rrnum + + ) {
struct dns_query q ;
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_query ( ctx , buffer , buffer + resp_len ,
& p , & q ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_ns: "
" Failed to parse query record! \n " ) ) ;
2006-07-20 00:53:10 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
}
/* now we are at the answer section */
for ( rrnum = 0 ; rrnum < answer_count ; rrnum + + ) {
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_rr_ns ( ctx , buffer , buffer + resp_len ,
& p , & nsarray [ rrnum ] ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_ns: "
" Failed to parse answer record! \n " ) ) ;
2006-07-20 00:53:10 +04:00
return NT_STATUS_UNSUCCESSFUL ;
2007-10-29 23:34:00 +03:00
}
2006-07-20 00:53:10 +04:00
}
idx = rrnum ;
/* Parse the authority section */
/* just skip these for now */
for ( rrnum = 0 ; rrnum < auth_count ; rrnum + + ) {
struct dns_rr rr ;
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_rr ( ctx , buffer , buffer + resp_len ,
& p , & rr ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_ns: "
" Failed to parse authority record! \n " ) ) ;
2006-07-20 00:53:10 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
}
/* Parse the additional records section */
for ( rrnum = 0 ; rrnum < additional_count ; rrnum + + ) {
struct dns_rr rr ;
int i ;
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_rr ( ctx , buffer , buffer + resp_len ,
& p , & rr ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_ns: Failed "
" to parse additional records section! \n " ) ) ;
2006-07-20 00:53:10 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
2007-10-29 23:34:00 +03:00
/* only interested in A records as a shortcut for having to come
2006-07-20 00:53:10 +04:00
back later and lookup the name */
2007-10-29 23:34:00 +03:00
if ( rr . type ! = T_A | | rr . rdatalen ! = 4 ) {
# if defined(HAVE_IPV6)
if ( rr . type ! = T_AAAA | | rr . rdatalen ! = 16 )
# endif
continue ;
}
2006-07-20 00:53:10 +04:00
for ( i = 0 ; i < idx ; i + + ) {
2007-10-29 23:34:00 +03:00
if ( strcmp ( rr . hostname , nsarray [ i ] . hostname ) = = 0 ) {
if ( rr . type = = T_A ) {
struct in_addr ip ;
memcpy ( & ip , rr . rdata , 4 ) ;
in_addr_to_sockaddr_storage (
& nsarray [ i ] . ss ,
ip ) ;
}
# if defined(HAVE_IPV6)
if ( rr . type = = T_AAAA ) {
struct in6_addr ip6 ;
memcpy ( & ip6 , rr . rdata , rr . rdatalen ) ;
in6_addr_to_sockaddr_storage (
& nsarray [ i ] . ss ,
ip6 ) ;
}
# endif
2006-07-20 00:53:10 +04:00
}
}
}
2007-10-29 23:34:00 +03:00
2006-07-20 00:53:10 +04:00
* nslist = nsarray ;
* numns = idx ;
2007-10-29 23:34:00 +03:00
2006-07-20 00:53:10 +04:00
return NT_STATUS_OK ;
}
2006-08-30 08:40:03 +04:00
/********************************************************************
Query with optional sitename .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-08-28 18:27:48 +04:00
static NTSTATUS ads_dns_query_internal ( TALLOC_CTX * ctx ,
const char * servicename ,
const char * dc_pdc_gc_domains ,
const char * realm ,
const char * sitename ,
struct dns_rr_srv * * dclist ,
int * numdcs )
2006-08-30 08:40:03 +04:00
{
char * name ;
if ( sitename ) {
2007-08-28 18:27:48 +04:00
name = talloc_asprintf ( ctx , " %s._tcp.%s._sites.%s._msdcs.%s " ,
servicename , sitename ,
dc_pdc_gc_domains , realm ) ;
} else {
name = talloc_asprintf ( ctx , " %s._tcp.%s._msdcs.%s " ,
servicename , dc_pdc_gc_domains , realm ) ;
}
2006-08-30 08:40:03 +04:00
if ( ! name ) {
return NT_STATUS_NO_MEMORY ;
}
2006-05-05 23:24:48 +04:00
return ads_dns_lookup_srv ( ctx , name , dclist , numdcs ) ;
}
2006-08-30 08:40:03 +04:00
/********************************************************************
2007-01-17 21:25:35 +03:00
Query for AD DC ' s .
2006-08-30 08:40:03 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_query_dcs ( TALLOC_CTX * ctx ,
2007-08-28 18:27:48 +04:00
const char * realm ,
const char * sitename ,
struct dns_rr_srv * * dclist ,
int * numdcs )
2006-08-30 08:40:03 +04:00
{
NTSTATUS status ;
2007-08-28 18:27:48 +04:00
status = ads_dns_query_internal ( ctx , " _ldap " , " dc " , realm , sitename ,
2006-09-02 23:27:44 +04:00
dclist , numdcs ) ;
2007-01-17 22:20:11 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_IO_TIMEOUT ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_CONNECTION_REFUSED ) ) {
return status ;
}
2007-08-28 18:27:48 +04:00
if ( sitename & &
( ( ! NT_STATUS_IS_OK ( status ) ) | |
( NT_STATUS_IS_OK ( status ) & & ( numdcs = = 0 ) ) ) ) {
2006-08-30 08:40:03 +04:00
/* Sitename DNS query may have failed. Try without. */
2007-08-28 18:27:48 +04:00
status = ads_dns_query_internal ( ctx , " _ldap " , " dc " , realm ,
NULL , dclist , numdcs ) ;
}
return status ;
}
/********************************************************************
Query for AD GC ' s .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_query_gcs ( TALLOC_CTX * ctx ,
const char * realm ,
const char * sitename ,
struct dns_rr_srv * * dclist ,
int * numdcs )
{
NTSTATUS status ;
status = ads_dns_query_internal ( ctx , " _ldap " , " gc " , realm , sitename ,
dclist , numdcs ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_IO_TIMEOUT ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_CONNECTION_REFUSED ) ) {
return status ;
}
if ( sitename & &
( ( ! NT_STATUS_IS_OK ( status ) ) | |
( NT_STATUS_IS_OK ( status ) & & ( numdcs = = 0 ) ) ) ) {
/* Sitename DNS query may have failed. Try without. */
status = ads_dns_query_internal ( ctx , " _ldap " , " gc " , realm ,
NULL , dclist , numdcs ) ;
2006-09-02 23:27:44 +04:00
}
return status ;
}
/********************************************************************
2007-01-17 21:25:35 +03:00
Query for AD KDC ' s .
2006-09-02 23:27:44 +04:00
Even if our underlying kerberos libraries are UDP only , this
is pretty safe as it ' s unlikely that a KDC supports TCP and not UDP .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_query_kdcs ( TALLOC_CTX * ctx ,
2007-08-28 18:27:48 +04:00
const char * dns_forest_name ,
const char * sitename ,
struct dns_rr_srv * * dclist ,
int * numdcs )
2006-09-02 23:27:44 +04:00
{
NTSTATUS status ;
2007-08-28 18:27:48 +04:00
status = ads_dns_query_internal ( ctx , " _kerberos " , " dc " ,
dns_forest_name , sitename , dclist ,
numdcs ) ;
2007-01-17 22:20:11 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_IO_TIMEOUT ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_CONNECTION_REFUSED ) ) {
return status ;
}
2007-08-28 18:27:48 +04:00
if ( sitename & &
( ( ! NT_STATUS_IS_OK ( status ) ) | |
( NT_STATUS_IS_OK ( status ) & & ( numdcs = = 0 ) ) ) ) {
2006-09-02 23:27:44 +04:00
/* Sitename DNS query may have failed. Try without. */
2007-08-28 18:27:48 +04:00
status = ads_dns_query_internal ( ctx , " _kerberos " , " dc " ,
dns_forest_name , NULL ,
2006-09-02 23:27:44 +04:00
dclist , numdcs ) ;
2006-08-30 08:40:03 +04:00
}
return status ;
}
2007-08-28 18:27:48 +04:00
/********************************************************************
Query for AD PDC . Sitename is obsolete here .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_query_pdc ( TALLOC_CTX * ctx ,
const char * dns_domain_name ,
struct dns_rr_srv * * dclist ,
int * numdcs )
{
return ads_dns_query_internal ( ctx , " _ldap " , " pdc " , dns_domain_name ,
NULL , dclist , numdcs ) ;
}
/********************************************************************
Query for AD DC by guid . Sitename is obsolete here .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_query_dcs_guid ( TALLOC_CTX * ctx ,
const char * dns_forest_name ,
const struct GUID * domain_guid ,
struct dns_rr_srv * * dclist ,
int * numdcs )
{
/*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
const char * domains ;
2009-08-25 19:02:53 +04:00
char * guid_string ;
2007-08-28 18:27:48 +04:00
guid_string = GUID_string ( ctx , domain_guid ) ;
if ( ! guid_string ) {
return NT_STATUS_NO_MEMORY ;
}
/* little hack */
domains = talloc_asprintf ( ctx , " %s.domains " , guid_string ) ;
if ( ! domains ) {
return NT_STATUS_NO_MEMORY ;
}
2009-08-25 19:02:53 +04:00
TALLOC_FREE ( guid_string ) ;
2007-08-28 18:27:48 +04:00
return ads_dns_query_internal ( ctx , " _ldap " , domains , dns_forest_name ,
NULL , dclist , numdcs ) ;
}