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 /*********************************************************************
30 Sort SRV record list based on weight and priority. See RFC 2782.
31 *********************************************************************/
33 static int dnssrvcmp( struct dns_rr_srv
*a
, struct dns_rr_srv
*b
)
35 if ( a
->priority
== b
->priority
) {
37 /* randomize entries with an equal weight and priority */
38 if ( a
->weight
== b
->weight
)
41 /* higher weights should be sorted lower */
42 if ( a
->weight
> b
->weight
)
48 if ( a
->priority
< b
->priority
)
54 struct ads_dns_lookup_srv_state
{
55 struct dns_rr_srv
*srvs
;
59 static void ads_dns_lookup_srv_done(struct tevent_req
*subreq
);
61 struct tevent_req
*ads_dns_lookup_srv_send(TALLOC_CTX
*mem_ctx
,
62 struct tevent_context
*ev
,
65 struct tevent_req
*req
, *subreq
;
66 struct ads_dns_lookup_srv_state
*state
;
68 req
= tevent_req_create(mem_ctx
, &state
,
69 struct ads_dns_lookup_srv_state
);
74 subreq
= dns_lookup_send(
82 if (tevent_req_nomem(subreq
, req
)) {
83 return tevent_req_post(req
, ev
);
85 tevent_req_set_callback(subreq
, ads_dns_lookup_srv_done
, req
);
89 static void ads_dns_lookup_srv_done(struct tevent_req
*subreq
)
91 struct tevent_req
*req
= tevent_req_callback_data(
92 subreq
, struct tevent_req
);
93 struct ads_dns_lookup_srv_state
*state
= tevent_req_data(
94 req
, struct ads_dns_lookup_srv_state
);
96 struct dns_name_packet
*reply
;
99 ret
= dns_lookup_recv(subreq
, state
, &reply
);
102 tevent_req_nterror(req
, map_nt_error_from_unix_common(ret
));
106 for (i
=0; i
<reply
->ancount
; i
++) {
107 if (reply
->answers
[i
].rr_type
== DNS_QTYPE_SRV
) {
108 state
->num_srvs
+= 1;
112 state
->srvs
= talloc_array(state
, struct dns_rr_srv
, state
->num_srvs
);
113 if (tevent_req_nomem(state
->srvs
, req
)) {
119 for (i
=0; i
<reply
->ancount
; i
++) {
120 struct dns_res_rec
*an
= &reply
->answers
[i
];
121 struct dns_rr_srv
*dst
= &state
->srvs
[idx
];
122 struct dns_srv_record
*src
;
124 if (an
->rr_type
!= DNS_QTYPE_SRV
) {
127 src
= &an
->rdata
.srv_record
;
129 *dst
= (struct dns_rr_srv
) {
130 .hostname
= talloc_move(state
->srvs
, &src
->target
),
131 .priority
= src
->priority
,
132 .weight
= src
->weight
,
138 for (i
=0; i
<reply
->arcount
; i
++) {
139 struct dns_res_rec
*ar
= &reply
->additional
[i
];
140 struct sockaddr_storage addr
;
144 ok
= dns_res_rec_get_sockaddr(ar
, &addr
);
149 for (j
=0; j
<state
->num_srvs
; j
++) {
150 struct dns_rr_srv
*srv
= &state
->srvs
[j
];
151 struct sockaddr_storage
*tmp
;
153 if (strcmp(srv
->hostname
, ar
->name
) != 0) {
157 tmp
= talloc_realloc(
160 struct sockaddr_storage
,
163 if (tevent_req_nomem(tmp
, req
)) {
168 srv
->ss_s
[srv
->num_ips
] = addr
;
173 TYPESAFE_QSORT(state
->srvs
, state
->num_srvs
, dnssrvcmp
);
175 tevent_req_done(req
);
178 NTSTATUS
ads_dns_lookup_srv_recv(struct tevent_req
*req
,
180 struct dns_rr_srv
**srvs
,
183 struct ads_dns_lookup_srv_state
*state
= tevent_req_data(
184 req
, struct ads_dns_lookup_srv_state
);
187 if (tevent_req_is_nterror(req
, &status
)) {
190 *srvs
= talloc_move(mem_ctx
, &state
->srvs
);
191 *num_srvs
= state
->num_srvs
;
192 tevent_req_received(req
);
196 /*********************************************************************
197 Simple wrapper for a DNS SRV query
198 *********************************************************************/
200 NTSTATUS
ads_dns_lookup_srv(TALLOC_CTX
*ctx
,
202 struct dns_rr_srv
**dclist
,
205 struct tevent_context
*ev
;
206 struct tevent_req
*req
;
207 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
210 ev
= samba_tevent_context_init(ctx
);
214 req
= ads_dns_lookup_srv_send(ev
, ev
, name
);
218 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
221 status
= ads_dns_lookup_srv_recv(req
, ctx
, dclist
, &num_srvs
);
222 if (NT_STATUS_IS_OK(status
)) {
223 *numdcs
= num_srvs
; /* size_t->int */
230 struct ads_dns_lookup_ns_state
{
231 struct dns_rr_ns
*nss
;
235 static void ads_dns_lookup_ns_done(struct tevent_req
*subreq
);
237 struct tevent_req
*ads_dns_lookup_ns_send(TALLOC_CTX
*mem_ctx
,
238 struct tevent_context
*ev
,
241 struct tevent_req
*req
, *subreq
;
242 struct ads_dns_lookup_ns_state
*state
;
244 req
= tevent_req_create(mem_ctx
, &state
,
245 struct ads_dns_lookup_ns_state
);
250 subreq
= dns_lookup_send(state
, ev
, NULL
, name
, DNS_QCLASS_IN
,
252 if (tevent_req_nomem(subreq
, req
)) {
253 return tevent_req_post(req
, ev
);
255 tevent_req_set_callback(subreq
, ads_dns_lookup_ns_done
, req
);
259 static void ads_dns_lookup_ns_done(struct tevent_req
*subreq
)
261 struct tevent_req
*req
= tevent_req_callback_data(
262 subreq
, struct tevent_req
);
263 struct ads_dns_lookup_ns_state
*state
= tevent_req_data(
264 req
, struct ads_dns_lookup_ns_state
);
266 struct dns_name_packet
*reply
;
269 ret
= dns_lookup_recv(subreq
, state
, &reply
);
272 tevent_req_nterror(req
, map_nt_error_from_unix_common(ret
));
276 for (i
=0; i
<reply
->ancount
; i
++) {
277 if (reply
->answers
[i
].rr_type
== DNS_QTYPE_NS
) {
282 state
->nss
= talloc_array(state
, struct dns_rr_ns
, state
->num_nss
);
283 if (tevent_req_nomem(state
->nss
, req
)) {
289 for (i
=0; i
<reply
->ancount
; i
++) {
290 struct dns_res_rec
*an
= &reply
->answers
[i
];
292 if (an
->rr_type
!= DNS_QTYPE_NS
) {
296 state
->nss
[idx
].hostname
= talloc_move(state
->nss
,
297 &an
->rdata
.ns_record
);
301 for (i
=0; i
<reply
->arcount
; i
++) {
302 struct dns_res_rec
*ar
= &reply
->additional
[i
];
303 struct sockaddr_storage addr
;
307 ok
= dns_res_rec_get_sockaddr(ar
, &addr
);
312 for (j
=0; j
<state
->num_nss
; j
++) {
313 struct dns_rr_ns
*ns
= &state
->nss
[j
];
315 if (strcmp(ns
->hostname
, ar
->name
) == 0) {
321 tevent_req_done(req
);
324 NTSTATUS
ads_dns_lookup_ns_recv(struct tevent_req
*req
,
326 struct dns_rr_ns
**nss
,
329 struct ads_dns_lookup_ns_state
*state
= tevent_req_data(
330 req
, struct ads_dns_lookup_ns_state
);
333 if (tevent_req_is_nterror(req
, &status
)) {
336 *nss
= talloc_move(mem_ctx
, &state
->nss
);
337 *num_nss
= state
->num_nss
;
338 tevent_req_received(req
);
342 /*********************************************************************
343 Simple wrapper for a DNS NS query
344 *********************************************************************/
346 NTSTATUS
ads_dns_lookup_ns(TALLOC_CTX
*ctx
,
347 const char *dnsdomain
,
348 struct dns_rr_ns
**nslist
,
351 struct tevent_context
*ev
;
352 struct tevent_req
*req
;
353 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
356 ev
= samba_tevent_context_init(ctx
);
360 req
= ads_dns_lookup_ns_send(ev
, ev
, dnsdomain
);
364 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
367 status
= ads_dns_lookup_ns_recv(req
, ctx
, nslist
, &num_ns
);
375 /********************************************************************
376 Query with optional sitename.
377 ********************************************************************/
379 static NTSTATUS
ads_dns_query_internal(TALLOC_CTX
*ctx
,
380 const char *servicename
,
381 const char *dc_pdc_gc_domains
,
383 const char *sitename
,
384 struct dns_rr_srv
**dclist
,
391 if ((sitename
!= NULL
) && (strlen(sitename
) != 0)) {
392 name
= talloc_asprintf(ctx
, "%s._tcp.%s._sites.%s._msdcs.%s",
393 servicename
, sitename
,
394 dc_pdc_gc_domains
, realm
);
396 return NT_STATUS_NO_MEMORY
;
399 status
= ads_dns_lookup_srv(ctx
, name
, dclist
, &num_srvs
);
403 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
404 NT_STATUS_EQUAL(status
, NT_STATUS_CONNECTION_REFUSED
)) {
408 if (NT_STATUS_IS_OK(status
) && (num_srvs
!= 0)) {
413 name
= talloc_asprintf(ctx
, "%s._tcp.%s._msdcs.%s",
414 servicename
, dc_pdc_gc_domains
, realm
);
416 return NT_STATUS_NO_MEMORY
;
418 status
= ads_dns_lookup_srv(ctx
, name
, dclist
, &num_srvs
);
421 *numdcs
= num_srvs
; /* automatic conversion size_t->int */
425 /********************************************************************
427 ********************************************************************/
429 NTSTATUS
ads_dns_query_dcs(TALLOC_CTX
*ctx
,
431 const char *sitename
,
432 struct dns_rr_srv
**dclist
,
437 status
= ads_dns_query_internal(ctx
,
447 /********************************************************************
449 ********************************************************************/
451 NTSTATUS
ads_dns_query_gcs(TALLOC_CTX
*ctx
,
453 const char *sitename
,
454 struct dns_rr_srv
**dclist
,
459 status
= ads_dns_query_internal(ctx
,
469 /********************************************************************
471 Even if our underlying kerberos libraries are UDP only, this
472 is pretty safe as it's unlikely that a KDC supports TCP and not UDP.
473 ********************************************************************/
475 NTSTATUS
ads_dns_query_kdcs(TALLOC_CTX
*ctx
,
476 const char *dns_forest_name
,
477 const char *sitename
,
478 struct dns_rr_srv
**dclist
,
483 status
= ads_dns_query_internal(ctx
,
493 /********************************************************************
494 Query for AD PDC. Sitename is obsolete here.
495 ********************************************************************/
497 NTSTATUS
ads_dns_query_pdc(TALLOC_CTX
*ctx
,
498 const char *dns_domain_name
,
499 struct dns_rr_srv
**dclist
,
502 return ads_dns_query_internal(ctx
,
511 /********************************************************************
512 Query for AD DC by guid. Sitename is obsolete here.
513 ********************************************************************/
515 NTSTATUS
ads_dns_query_dcs_guid(TALLOC_CTX
*ctx
,
516 const char *dns_forest_name
,
517 const char *domain_guid
,
518 struct dns_rr_srv
**dclist
,
521 /*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
526 domains
= talloc_asprintf(ctx
, "%s.domains", domain_guid
);
528 return NT_STATUS_NO_MEMORY
;
531 return ads_dns_query_internal(ctx
,