2 Unix SMB/CIFS implementation.
4 Copyright (C) Gerald (Jerry) Carter 2006.
5 Copyright (C) Jeremy Allison 2007.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "lib/util/util_net.h"
23 #include "lib/util/tsort.h"
24 #include "librpc/gen_ndr/dns.h"
25 #include "libcli/dns/dns_lookup.h"
26 #include "lib/util/tevent_ntstatus.h"
29 /* AIX resolv.h uses 'class' in struct ns_rr */
37 /* resolver headers */
39 #include <sys/types.h>
40 #include <netinet/in.h>
41 #include <arpa/nameser.h>
45 #define MAX_DNS_PACKET_SIZE 0xffff
47 #ifdef NS_HFIXEDSZ /* Bind 8/9 interface */
48 #if !defined(C_IN) /* AIX 5.3 already defines C_IN */
51 #if !defined(T_A) /* AIX 5.3 already defines T_A */
55 #if defined(HAVE_IPV6)
57 # define T_AAAA ns_t_aaaa
61 # define T_SRV ns_t_srv
62 #if !defined(T_NS) /* AIX 5.3 already defines T_NS */
67 # define NS_HFIXEDSZ HFIXEDSZ
69 # define NS_HFIXEDSZ sizeof(HEADER)
70 # endif /* HFIXEDSZ */
72 # define NS_PACKETSZ PACKETSZ
73 # else /* 512 is usually the default */
74 # define NS_PACKETSZ 512
75 # endif /* PACKETSZ */
79 /*********************************************************************
80 Sort SRV record list based on weight and priority. See RFC 2782.
81 *********************************************************************/
83 static int dnssrvcmp( struct dns_rr_srv
*a
, struct dns_rr_srv
*b
)
85 if ( a
->priority
== b
->priority
) {
87 /* randomize entries with an equal weight and priority */
88 if ( a
->weight
== b
->weight
)
91 /* higher weights should be sorted lower */
92 if ( a
->weight
> b
->weight
)
98 if ( a
->priority
< b
->priority
)
104 struct ads_dns_lookup_srv_state
{
105 struct dns_rr_srv
*srvs
;
109 static void ads_dns_lookup_srv_done(struct tevent_req
*subreq
);
111 struct tevent_req
*ads_dns_lookup_srv_send(TALLOC_CTX
*mem_ctx
,
112 struct tevent_context
*ev
,
115 struct tevent_req
*req
, *subreq
;
116 struct ads_dns_lookup_srv_state
*state
;
118 req
= tevent_req_create(mem_ctx
, &state
,
119 struct ads_dns_lookup_srv_state
);
124 subreq
= dns_lookup_send(
132 if (tevent_req_nomem(subreq
, req
)) {
133 return tevent_req_post(req
, ev
);
135 tevent_req_set_callback(subreq
, ads_dns_lookup_srv_done
, req
);
139 static void ads_dns_lookup_srv_done(struct tevent_req
*subreq
)
141 struct tevent_req
*req
= tevent_req_callback_data(
142 subreq
, struct tevent_req
);
143 struct ads_dns_lookup_srv_state
*state
= tevent_req_data(
144 req
, struct ads_dns_lookup_srv_state
);
146 struct dns_name_packet
*reply
;
149 ret
= dns_lookup_recv(subreq
, state
, &reply
);
152 tevent_req_nterror(req
, map_nt_error_from_unix_common(ret
));
156 for (i
=0; i
<reply
->ancount
; i
++) {
157 if (reply
->answers
[i
].rr_type
== DNS_QTYPE_SRV
) {
158 state
->num_srvs
+= 1;
162 state
->srvs
= talloc_array(state
, struct dns_rr_srv
, state
->num_srvs
);
163 if (tevent_req_nomem(state
->srvs
, req
)) {
169 for (i
=0; i
<reply
->ancount
; i
++) {
170 struct dns_res_rec
*an
= &reply
->answers
[i
];
171 struct dns_rr_srv
*dst
= &state
->srvs
[idx
];
172 struct dns_srv_record
*src
;
174 if (an
->rr_type
!= DNS_QTYPE_SRV
) {
177 src
= &an
->rdata
.srv_record
;
179 *dst
= (struct dns_rr_srv
) {
180 .hostname
= talloc_move(state
->srvs
, &src
->target
),
181 .priority
= src
->priority
,
182 .weight
= src
->weight
,
188 for (i
=0; i
<reply
->arcount
; i
++) {
189 struct dns_res_rec
*ar
= &reply
->additional
[i
];
190 struct sockaddr_storage addr
;
194 ok
= dns_res_rec_get_sockaddr(ar
, &addr
);
199 for (j
=0; j
<state
->num_srvs
; j
++) {
200 struct dns_rr_srv
*srv
= &state
->srvs
[j
];
201 struct sockaddr_storage
*tmp
;
203 if (strcmp(srv
->hostname
, ar
->name
) != 0) {
207 tmp
= talloc_realloc(
210 struct sockaddr_storage
,
213 if (tevent_req_nomem(tmp
, req
)) {
218 srv
->ss_s
[srv
->num_ips
] = addr
;
223 TYPESAFE_QSORT(state
->srvs
, state
->num_srvs
, dnssrvcmp
);
225 tevent_req_done(req
);
228 NTSTATUS
ads_dns_lookup_srv_recv(struct tevent_req
*req
,
230 struct dns_rr_srv
**srvs
,
233 struct ads_dns_lookup_srv_state
*state
= tevent_req_data(
234 req
, struct ads_dns_lookup_srv_state
);
237 if (tevent_req_is_nterror(req
, &status
)) {
240 *srvs
= talloc_move(mem_ctx
, &state
->srvs
);
241 *num_srvs
= state
->num_srvs
;
242 tevent_req_received(req
);
246 /*********************************************************************
247 Simple wrapper for a DNS SRV query
248 *********************************************************************/
250 NTSTATUS
ads_dns_lookup_srv(TALLOC_CTX
*ctx
,
252 struct dns_rr_srv
**dclist
,
255 struct tevent_context
*ev
;
256 struct tevent_req
*req
;
257 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
260 ev
= samba_tevent_context_init(ctx
);
264 req
= ads_dns_lookup_srv_send(ev
, ev
, name
);
268 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
271 status
= ads_dns_lookup_srv_recv(req
, ctx
, dclist
, &num_srvs
);
272 *numdcs
= num_srvs
; /* size_t->int */
278 struct ads_dns_lookup_ns_state
{
279 struct dns_rr_ns
*nss
;
283 static void ads_dns_lookup_ns_done(struct tevent_req
*subreq
);
285 struct tevent_req
*ads_dns_lookup_ns_send(TALLOC_CTX
*mem_ctx
,
286 struct tevent_context
*ev
,
289 struct tevent_req
*req
, *subreq
;
290 struct ads_dns_lookup_ns_state
*state
;
292 req
= tevent_req_create(mem_ctx
, &state
,
293 struct ads_dns_lookup_ns_state
);
298 subreq
= dns_lookup_send(state
, ev
, NULL
, name
, DNS_QCLASS_IN
,
300 if (tevent_req_nomem(subreq
, req
)) {
301 return tevent_req_post(req
, ev
);
303 tevent_req_set_callback(subreq
, ads_dns_lookup_ns_done
, req
);
307 static void ads_dns_lookup_ns_done(struct tevent_req
*subreq
)
309 struct tevent_req
*req
= tevent_req_callback_data(
310 subreq
, struct tevent_req
);
311 struct ads_dns_lookup_ns_state
*state
= tevent_req_data(
312 req
, struct ads_dns_lookup_ns_state
);
314 struct dns_name_packet
*reply
;
317 ret
= dns_lookup_recv(subreq
, state
, &reply
);
320 tevent_req_nterror(req
, map_nt_error_from_unix_common(ret
));
324 for (i
=0; i
<reply
->ancount
; i
++) {
325 if (reply
->answers
[i
].rr_type
== DNS_QTYPE_NS
) {
330 state
->nss
= talloc_array(state
, struct dns_rr_ns
, state
->num_nss
);
331 if (tevent_req_nomem(state
->nss
, req
)) {
337 for (i
=0; i
<reply
->ancount
; i
++) {
338 struct dns_res_rec
*an
= &reply
->answers
[i
];
340 if (an
->rr_type
!= DNS_QTYPE_NS
) {
344 state
->nss
[idx
].hostname
= talloc_move(state
->nss
,
345 &an
->rdata
.ns_record
);
349 for (i
=0; i
<reply
->arcount
; i
++) {
350 struct dns_res_rec
*ar
= &reply
->additional
[i
];
351 struct sockaddr_storage addr
;
355 ok
= dns_res_rec_get_sockaddr(ar
, &addr
);
360 for (j
=0; j
<state
->num_nss
; j
++) {
361 struct dns_rr_ns
*ns
= &state
->nss
[j
];
363 if (strcmp(ns
->hostname
, ar
->name
) == 0) {
369 tevent_req_done(req
);
372 NTSTATUS
ads_dns_lookup_ns_recv(struct tevent_req
*req
,
374 struct dns_rr_ns
**nss
,
377 struct ads_dns_lookup_ns_state
*state
= tevent_req_data(
378 req
, struct ads_dns_lookup_ns_state
);
381 if (tevent_req_is_nterror(req
, &status
)) {
384 *nss
= talloc_move(mem_ctx
, &state
->nss
);
385 *num_nss
= state
->num_nss
;
386 tevent_req_received(req
);
390 /*********************************************************************
391 Simple wrapper for a DNS NS query
392 *********************************************************************/
394 NTSTATUS
ads_dns_lookup_ns(TALLOC_CTX
*ctx
,
395 const char *dnsdomain
,
396 struct dns_rr_ns
**nslist
,
399 struct tevent_context
*ev
;
400 struct tevent_req
*req
;
401 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
404 ev
= samba_tevent_context_init(ctx
);
408 req
= ads_dns_lookup_ns_send(ev
, ev
, dnsdomain
);
412 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
415 status
= ads_dns_lookup_ns_recv(req
, ctx
, nslist
, &num_ns
);
423 /********************************************************************
424 Query with optional sitename.
425 ********************************************************************/
427 static NTSTATUS
ads_dns_query_internal(TALLOC_CTX
*ctx
,
428 const char *servicename
,
429 const char *dc_pdc_gc_domains
,
431 const char *sitename
,
432 struct dns_rr_srv
**dclist
,
439 if ((sitename
!= NULL
) && (strlen(sitename
) != 0)) {
440 name
= talloc_asprintf(ctx
, "%s._tcp.%s._sites.%s._msdcs.%s",
441 servicename
, sitename
,
442 dc_pdc_gc_domains
, realm
);
444 return NT_STATUS_NO_MEMORY
;
447 status
= ads_dns_lookup_srv(ctx
, name
, dclist
, &num_srvs
);
451 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
452 NT_STATUS_EQUAL(status
, NT_STATUS_CONNECTION_REFUSED
)) {
456 if (NT_STATUS_IS_OK(status
) && (num_srvs
!= 0)) {
461 name
= talloc_asprintf(ctx
, "%s._tcp.%s._msdcs.%s",
462 servicename
, dc_pdc_gc_domains
, realm
);
464 return NT_STATUS_NO_MEMORY
;
466 status
= ads_dns_lookup_srv(ctx
, name
, dclist
, &num_srvs
);
469 *numdcs
= num_srvs
; /* automatic conversion size_t->int */
473 /********************************************************************
475 ********************************************************************/
477 NTSTATUS
ads_dns_query_dcs(TALLOC_CTX
*ctx
,
479 const char *sitename
,
480 struct dns_rr_srv
**dclist
,
485 status
= ads_dns_query_internal(ctx
,
495 /********************************************************************
497 ********************************************************************/
499 NTSTATUS
ads_dns_query_gcs(TALLOC_CTX
*ctx
,
501 const char *sitename
,
502 struct dns_rr_srv
**dclist
,
507 status
= ads_dns_query_internal(ctx
,
517 /********************************************************************
519 Even if our underlying kerberos libraries are UDP only, this
520 is pretty safe as it's unlikely that a KDC supports TCP and not UDP.
521 ********************************************************************/
523 NTSTATUS
ads_dns_query_kdcs(TALLOC_CTX
*ctx
,
524 const char *dns_forest_name
,
525 const char *sitename
,
526 struct dns_rr_srv
**dclist
,
531 status
= ads_dns_query_internal(ctx
,
541 /********************************************************************
542 Query for AD PDC. Sitename is obsolete here.
543 ********************************************************************/
545 NTSTATUS
ads_dns_query_pdc(TALLOC_CTX
*ctx
,
546 const char *dns_domain_name
,
547 struct dns_rr_srv
**dclist
,
550 return ads_dns_query_internal(ctx
,
559 /********************************************************************
560 Query for AD DC by guid. Sitename is obsolete here.
561 ********************************************************************/
563 NTSTATUS
ads_dns_query_dcs_guid(TALLOC_CTX
*ctx
,
564 const char *dns_forest_name
,
565 const char *domain_guid
,
566 struct dns_rr_srv
**dclist
,
569 /*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
574 domains
= talloc_asprintf(ctx
, "%s.domains", domain_guid
);
576 return NT_STATUS_NO_MEMORY
;
579 return ads_dns_query_internal(ctx
,