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 *numdcs = num_srvs; /* size_t->int */
228 struct ads_dns_lookup_ns_state {
229 struct dns_rr_ns *nss;
233 static void ads_dns_lookup_ns_done(struct tevent_req *subreq);
235 struct tevent_req *ads_dns_lookup_ns_send(TALLOC_CTX *mem_ctx,
236 struct tevent_context *ev,
239 struct tevent_req *req, *subreq;
240 struct ads_dns_lookup_ns_state *state;
242 req = tevent_req_create(mem_ctx, &state,
243 struct ads_dns_lookup_ns_state);
248 subreq = dns_lookup_send(state, ev, NULL, name, DNS_QCLASS_IN,
250 if (tevent_req_nomem(subreq, req)) {
251 return tevent_req_post(req, ev);
253 tevent_req_set_callback(subreq, ads_dns_lookup_ns_done, req);
257 static void ads_dns_lookup_ns_done(struct tevent_req *subreq)
259 struct tevent_req *req = tevent_req_callback_data(
260 subreq, struct tevent_req);
261 struct ads_dns_lookup_ns_state *state = tevent_req_data(
262 req, struct ads_dns_lookup_ns_state);
264 struct dns_name_packet *reply;
267 ret = dns_lookup_recv(subreq, state, &reply);
270 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
274 for (i=0; i<reply->ancount; i++) {
275 if (reply->answers[i].rr_type == DNS_QTYPE_NS) {
280 state->nss = talloc_array(state, struct dns_rr_ns, state->num_nss);
281 if (tevent_req_nomem(state->nss, req)) {
287 for (i=0; i<reply->ancount; i++) {
288 struct dns_res_rec *an = &reply->answers[i];
290 if (an->rr_type != DNS_QTYPE_NS) {
294 state->nss[idx].hostname = talloc_move(state->nss,
295 &an->rdata.ns_record);
299 for (i=0; i<reply->arcount; i++) {
300 struct dns_res_rec *ar = &reply->additional[i];
301 struct sockaddr_storage addr;
305 ok = dns_res_rec_get_sockaddr(ar, &addr);
310 for (j=0; j<state->num_nss; j++) {
311 struct dns_rr_ns *ns = &state->nss[j];
313 if (strcmp(ns->hostname, ar->name) == 0) {
319 tevent_req_done(req);
322 NTSTATUS ads_dns_lookup_ns_recv(struct tevent_req *req,
324 struct dns_rr_ns **nss,
327 struct ads_dns_lookup_ns_state *state = tevent_req_data(
328 req, struct ads_dns_lookup_ns_state);
331 if (tevent_req_is_nterror(req, &status)) {
334 *nss = talloc_move(mem_ctx, &state->nss);
335 *num_nss = state->num_nss;
336 tevent_req_received(req);
340 /*********************************************************************
341 Simple wrapper for a DNS NS query
342 *********************************************************************/
344 NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
345 const char *dnsdomain,
346 struct dns_rr_ns **nslist,
349 struct tevent_context *ev;
350 struct tevent_req *req;
351 NTSTATUS status = NT_STATUS_NO_MEMORY;
354 ev = samba_tevent_context_init(ctx);
358 req = ads_dns_lookup_ns_send(ev, ev, dnsdomain);
362 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
365 status = ads_dns_lookup_ns_recv(req, ctx, nslist, &num_ns);
373 /********************************************************************
374 Query with optional sitename.
375 ********************************************************************/
377 static NTSTATUS ads_dns_query_internal(TALLOC_CTX *ctx,
378 const char *servicename,
379 const char *dc_pdc_gc_domains,
381 const char *sitename,
382 struct dns_rr_srv **dclist,
389 if ((sitename != NULL) && (strlen(sitename) != 0)) {
390 name = talloc_asprintf(ctx, "%s._tcp.%s._sites.%s._msdcs.%s",
391 servicename, sitename,
392 dc_pdc_gc_domains, realm);
394 return NT_STATUS_NO_MEMORY;
397 status = ads_dns_lookup_srv(ctx, name, dclist, &num_srvs);
401 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
402 NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
406 if (NT_STATUS_IS_OK(status) && (num_srvs != 0)) {
411 name = talloc_asprintf(ctx, "%s._tcp.%s._msdcs.%s",
412 servicename, dc_pdc_gc_domains, realm);
414 return NT_STATUS_NO_MEMORY;
416 status = ads_dns_lookup_srv(ctx, name, dclist, &num_srvs);
419 *numdcs = num_srvs; /* automatic conversion size_t->int */
423 /********************************************************************
425 ********************************************************************/
427 NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
429 const char *sitename,
430 struct dns_rr_srv **dclist,
435 status = ads_dns_query_internal(ctx,
445 /********************************************************************
447 ********************************************************************/
449 NTSTATUS ads_dns_query_gcs(TALLOC_CTX *ctx,
451 const char *sitename,
452 struct dns_rr_srv **dclist,
457 status = ads_dns_query_internal(ctx,
467 /********************************************************************
469 Even if our underlying kerberos libraries are UDP only, this
470 is pretty safe as it's unlikely that a KDC supports TCP and not UDP.
471 ********************************************************************/
473 NTSTATUS ads_dns_query_kdcs(TALLOC_CTX *ctx,
474 const char *dns_forest_name,
475 const char *sitename,
476 struct dns_rr_srv **dclist,
481 status = ads_dns_query_internal(ctx,
491 /********************************************************************
492 Query for AD PDC. Sitename is obsolete here.
493 ********************************************************************/
495 NTSTATUS ads_dns_query_pdc(TALLOC_CTX *ctx,
496 const char *dns_domain_name,
497 struct dns_rr_srv **dclist,
500 return ads_dns_query_internal(ctx,
509 /********************************************************************
510 Query for AD DC by guid. Sitename is obsolete here.
511 ********************************************************************/
513 NTSTATUS ads_dns_query_dcs_guid(TALLOC_CTX *ctx,
514 const char *dns_forest_name,
515 const char *domain_guid,
516 struct dns_rr_srv **dclist,
519 /*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
524 domains = talloc_asprintf(ctx, "%s.domains", domain_guid);
526 return NT_STATUS_NO_MEMORY;
529 return ads_dns_query_internal(ctx,