2 Unix SMB/CIFS implementation.
4 Copyright (C) Gerald (Jerry) Carter 2006.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 /* AIX resolv.h uses 'class' in struct ns_rr */
31 /* resolver headers */
33 #include <sys/types.h>
34 #include <netinet/in.h>
35 #include <arpa/nameser.h>
39 #define MAX_DNS_PACKET_SIZE 0xffff
41 #ifdef NS_HFIXEDSZ /* Bind 8/9 interface */
42 #if !defined(C_IN) /* AIX 5.3 already defines C_IN */
45 #if !defined(T_A) /* AIX 5.3 already defines T_A */
48 # define T_SRV ns_t_srv
51 # define NS_HFIXEDSZ HFIXEDSZ
53 # define NS_HFIXEDSZ sizeof(HEADER)
54 # endif /* HFIXEDSZ */
56 # define NS_PACKETSZ PACKETSZ
57 # else /* 512 is usually the default */
58 # define NS_PACKETSZ 512
59 # endif /* PACKETSZ */
63 /*********************************************************************
64 *********************************************************************/
66 static BOOL
ads_dns_parse_query( TALLOC_CTX
*ctx
, uint8
*start
, uint8
*end
,
67 uint8
**ptr
, struct dns_query
*q
)
75 if ( !start
|| !end
|| !q
|| !*ptr
)
78 /* See RFC 1035 for details. If this fails, then return. */
80 namelen
= dn_expand( start
, end
, p
, hostname
, sizeof(hostname
) );
85 q
->hostname
= talloc_strdup( ctx
, hostname
);
87 /* check that we have space remaining */
89 if ( PTR_DIFF(p
+4, end
) > 0 )
92 q
->type
= RSVAL( p
, 0 );
93 q
->in_class
= RSVAL( p
, 2 );
101 /*********************************************************************
102 *********************************************************************/
104 static BOOL
ads_dns_parse_rr( TALLOC_CTX
*ctx
, uint8
*start
, uint8
*end
,
105 uint8
**ptr
, struct dns_rr
*rr
)
111 if ( !start
|| !end
|| !rr
|| !*ptr
)
115 /* pull the name from the answer */
117 namelen
= dn_expand( start
, end
, p
, hostname
, sizeof(hostname
) );
122 rr
->hostname
= talloc_strdup( ctx
, hostname
);
124 /* check that we have space remaining */
126 if ( PTR_DIFF(p
+10, end
) > 0 )
129 /* pull some values and then skip onto the string */
131 rr
->type
= RSVAL(p
, 0);
132 rr
->in_class
= RSVAL(p
, 2);
133 rr
->ttl
= RIVAL(p
, 4);
134 rr
->rdatalen
= RSVAL(p
, 8);
138 /* sanity check the available space */
140 if ( PTR_DIFF(p
+rr
->rdatalen
, end
) > 0 ) {
145 /* save a point to the rdata for this section */
155 /*********************************************************************
156 *********************************************************************/
158 static BOOL
ads_dns_parse_rr_srv( TALLOC_CTX
*ctx
, uint8
*start
, uint8
*end
,
159 uint8
**ptr
, struct dns_rr_srv
*srv
)
166 if ( !start
|| !end
|| !srv
|| !*ptr
)
169 /* Parse the RR entry. Coming out of the this, ptr is at the beginning
170 of the next record */
172 if ( !ads_dns_parse_rr( ctx
, start
, end
, ptr
, &rr
) ) {
173 DEBUG(1,("ads_dns_parse_rr_srv: Failed to parse RR record\n"));
177 if ( rr
.type
!= T_SRV
) {
178 DEBUG(1,("ads_dns_parse_rr_srv: Bad answer type (%d)\n", rr
.type
));
184 srv
->priority
= RSVAL(p
, 0);
185 srv
->weight
= RSVAL(p
, 2);
186 srv
->port
= RSVAL(p
, 4);
190 namelen
= dn_expand( start
, end
, p
, dcname
, sizeof(dcname
) );
192 DEBUG(1,("ads_dns_parse_rr_srv: Failed to uncompress name!\n"));
195 srv
->hostname
= talloc_strdup( ctx
, dcname
);
201 /*********************************************************************
202 Sort SRV record list based on weight and priority. See RFC 2782.
203 *********************************************************************/
205 static int dnssrvcmp( struct dns_rr_srv
*a
, struct dns_rr_srv
*b
)
207 if ( a
->priority
== b
->priority
) {
209 /* randomize entries with an equal weight and priority */
210 if ( a
->weight
== b
->weight
)
213 /* higher weights should be sorted lower */
214 if ( a
->weight
> b
->weight
)
220 if ( a
->priority
< b
->priority
)
226 /*********************************************************************
227 Simple wrapper for a DNS SRV query
228 *********************************************************************/
230 NTSTATUS
ads_dns_lookup_srv( TALLOC_CTX
*ctx
, const char *name
, struct dns_rr_srv
**dclist
, int *numdcs
)
232 uint8
*buffer
= NULL
;
234 int resp_len
= NS_PACKETSZ
;
235 struct dns_rr_srv
*dcs
= NULL
;
236 int query_count
, answer_count
, auth_count
, additional_count
;
241 if ( !ctx
|| !name
|| !dclist
) {
242 return NT_STATUS_INVALID_PARAMETER
;
245 /* Send the request. May have to loop several times in case
250 TALLOC_FREE( buffer
);
252 buf_len
= resp_len
* sizeof(uint8
);
254 if ( (buffer
= TALLOC_ARRAY(ctx
, uint8
, buf_len
)) == NULL
) {
255 DEBUG(0,("ads_dns_lookup_srv: talloc() failed!\n"));
256 return NT_STATUS_NO_MEMORY
;
259 if ( (resp_len
= res_query(name
, C_IN
, T_SRV
, buffer
, buf_len
)) < 0 ) {
260 DEBUG(1,("ads_dns_lookup_srv: Failed to resolve %s (%s)\n", name
, strerror(errno
)));
261 TALLOC_FREE( buffer
);
262 return NT_STATUS_UNSUCCESSFUL
;
264 } while ( buf_len
< resp_len
&& resp_len
< MAX_DNS_PACKET_SIZE
);
268 /* For some insane reason, the ns_initparse() et. al. routines are only
269 available in libresolv.a, and not the shared lib. Who knows why....
270 So we have to parse the DNS reply ourselves */
272 /* Pull the answer RR's count from the header. Use the NMB ordering macros */
274 query_count
= RSVAL( p
, 4 );
275 answer_count
= RSVAL( p
, 6 );
276 auth_count
= RSVAL( p
, 8 );
277 additional_count
= RSVAL( p
, 10 );
279 DEBUG(4,("ads_dns_lookup_srv: %d records returned in the answer section.\n",
282 if ( (dcs
= TALLOC_ZERO_ARRAY(ctx
, struct dns_rr_srv
, answer_count
)) == NULL
) {
283 DEBUG(0,("ads_dns_lookup_srv: talloc() failure for %d char*'s\n",
285 return NT_STATUS_NO_MEMORY
;
288 /* now skip the header */
292 /* parse the query section */
294 for ( rrnum
=0; rrnum
<query_count
; rrnum
++ ) {
297 if ( !ads_dns_parse_query( ctx
, buffer
, buffer
+resp_len
, &p
, &q
) ) {
298 DEBUG(1,("ads_dns_lookup_srv: Failed to parse query record!\n"));
299 return NT_STATUS_UNSUCCESSFUL
;
303 /* now we are at the answer section */
305 for ( rrnum
=0; rrnum
<answer_count
; rrnum
++ ) {
306 if ( !ads_dns_parse_rr_srv( ctx
, buffer
, buffer
+resp_len
, &p
, &dcs
[rrnum
] ) ) {
307 DEBUG(1,("ads_dns_lookup_srv: Failed to parse answer record!\n"));
308 return NT_STATUS_UNSUCCESSFUL
;
313 /* Parse the authority section */
314 /* just skip these for now */
316 for ( rrnum
=0; rrnum
<auth_count
; rrnum
++ ) {
319 if ( !ads_dns_parse_rr( ctx
, buffer
, buffer
+resp_len
, &p
, &rr
) ) {
320 DEBUG(1,("ads_dns_lookup_srv: Failed to parse authority record!\n"));
321 return NT_STATUS_UNSUCCESSFUL
;
325 /* Parse the additional records section */
327 for ( rrnum
=0; rrnum
<additional_count
; rrnum
++ ) {
331 if ( !ads_dns_parse_rr( ctx
, buffer
, buffer
+resp_len
, &p
, &rr
) ) {
332 DEBUG(1,("ads_dns_lookup_srv: Failed to parse additional records section!\n"));
333 return NT_STATUS_UNSUCCESSFUL
;
336 /* only interested in A records as a shortcut for having to come
337 back later and lookup the name */
339 if ( (rr
.type
!= T_A
) || (rr
.rdatalen
!= 4) )
342 for ( i
=0; i
<idx
; i
++ ) {
343 if ( strcmp( rr
.hostname
, dcs
[i
].hostname
) == 0 ) {
344 uint8
*buf
= (uint8
*)&dcs
[i
].ip
.s_addr
;
345 memcpy( buf
, rr
.rdata
, 4 );
350 qsort( dcs
, idx
, sizeof(struct dns_rr_srv
), QSORT_CAST dnssrvcmp
);
358 /********************************************************************
359 ********************************************************************/
361 NTSTATUS
ads_dns_query_dcs( TALLOC_CTX
*ctx
, const char *domain
, struct dns_rr_srv
**dclist
, int *numdcs
)
365 snprintf( name
, sizeof(name
), "_ldap._tcp.dc._msdcs.%s", domain
);
367 return ads_dns_lookup_srv( ctx
, name
, dclist
, numdcs
);