87ae97e3d0ba6ab53f65bc63e1e798853bf36a63
[nivanova/samba-autobuild/.git] / lib / addns / dnsquery.c
1 /*
2    Unix SMB/CIFS implementation.
3    DNS utility library
4    Copyright (C) Gerald (Jerry) Carter           2006.
5    Copyright (C) Jeremy Allison                  2007.
6
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.
11
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.
16
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/>.
19 */
20
21 #include "includes.h"
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"
27 #include "dnsquery.h"
28
29 /*********************************************************************
30  Sort SRV record list based on weight and priority.  See RFC 2782.
31 *********************************************************************/
32
33 static int dnssrvcmp( struct dns_rr_srv *a, struct dns_rr_srv *b )
34 {
35         if ( a->priority == b->priority ) {
36
37                 /* randomize entries with an equal weight and priority */
38                 if ( a->weight == b->weight )
39                         return 0;
40
41                 /* higher weights should be sorted lower */
42                 if ( a->weight > b->weight )
43                         return -1;
44                 else
45                         return 1;
46         }
47
48         if ( a->priority < b->priority )
49                 return -1;
50
51         return 1;
52 }
53
54 struct ads_dns_lookup_srv_state {
55         struct dns_rr_srv *srvs;
56         size_t num_srvs;
57 };
58
59 static void ads_dns_lookup_srv_done(struct tevent_req *subreq);
60
61 struct tevent_req *ads_dns_lookup_srv_send(TALLOC_CTX *mem_ctx,
62                                            struct tevent_context *ev,
63                                            const char *name)
64 {
65         struct tevent_req *req, *subreq;
66         struct ads_dns_lookup_srv_state *state;
67
68         req = tevent_req_create(mem_ctx, &state,
69                                 struct ads_dns_lookup_srv_state);
70         if (req == NULL) {
71                 return NULL;
72         }
73
74         subreq = dns_lookup_send(
75                 state,
76                 ev,
77                 NULL,
78                 name,
79                 DNS_QCLASS_IN,
80                 DNS_QTYPE_SRV);
81
82         if (tevent_req_nomem(subreq, req)) {
83                 return tevent_req_post(req, ev);
84         }
85         tevent_req_set_callback(subreq, ads_dns_lookup_srv_done, req);
86         return req;
87 }
88
89 static void ads_dns_lookup_srv_done(struct tevent_req *subreq)
90 {
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);
95         int ret;
96         struct dns_name_packet *reply;
97         uint16_t i, idx;
98
99         ret = dns_lookup_recv(subreq, state, &reply);
100         TALLOC_FREE(subreq);
101         if (ret != 0) {
102                 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
103                 return;
104         }
105
106         for (i=0; i<reply->ancount; i++) {
107                 if (reply->answers[i].rr_type == DNS_QTYPE_SRV) {
108                         state->num_srvs += 1;
109                 }
110         }
111
112         state->srvs = talloc_array(state, struct dns_rr_srv, state->num_srvs);
113         if (tevent_req_nomem(state->srvs, req)) {
114                 return;
115         }
116
117         idx = 0;
118
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;
123
124                 if (an->rr_type != DNS_QTYPE_SRV) {
125                         continue;
126                 }
127                 src = &an->rdata.srv_record;
128
129                 *dst = (struct dns_rr_srv) {
130                         .hostname = talloc_move(state->srvs, &src->target),
131                         .priority = src->priority,
132                         .weight = src->weight,
133                         .port = src->port,
134                 };
135                 idx += 1;
136         }
137
138         for (i=0; i<reply->arcount; i++) {
139                 struct dns_res_rec *ar = &reply->additional[i];
140                 struct sockaddr_storage addr;
141                 bool ok;
142                 size_t j;
143
144                 ok = dns_res_rec_get_sockaddr(ar, &addr);
145                 if (!ok) {
146                         continue;
147                 }
148
149                 for (j=0; j<state->num_srvs; j++) {
150                         struct dns_rr_srv *srv = &state->srvs[j];
151                         struct sockaddr_storage *tmp;
152
153                         if (strcmp(srv->hostname, ar->name) != 0) {
154                                 continue;
155                         }
156
157                         tmp = talloc_realloc(
158                                 state->srvs,
159                                 srv->ss_s,
160                                 struct sockaddr_storage,
161                                 srv->num_ips+1);
162
163                         if (tevent_req_nomem(tmp, req)) {
164                                 return;
165                         }
166                         srv->ss_s = tmp;
167
168                         srv->ss_s[srv->num_ips] = addr;
169                         srv->num_ips += 1;
170                 }
171         }
172
173         TYPESAFE_QSORT(state->srvs, state->num_srvs, dnssrvcmp);
174
175         tevent_req_done(req);
176 }
177
178 NTSTATUS ads_dns_lookup_srv_recv(struct tevent_req *req,
179                                  TALLOC_CTX *mem_ctx,
180                                  struct dns_rr_srv **srvs,
181                                  size_t *num_srvs)
182 {
183         struct ads_dns_lookup_srv_state *state = tevent_req_data(
184                 req, struct ads_dns_lookup_srv_state);
185         NTSTATUS status;
186
187         if (tevent_req_is_nterror(req, &status)) {
188                 return status;
189         }
190         *srvs = talloc_move(mem_ctx, &state->srvs);
191         *num_srvs = state->num_srvs;
192         tevent_req_received(req);
193         return NT_STATUS_OK;
194 }
195
196 /*********************************************************************
197  Simple wrapper for a DNS SRV query
198 *********************************************************************/
199
200 NTSTATUS ads_dns_lookup_srv(TALLOC_CTX *ctx,
201                                 const char *name,
202                                 struct dns_rr_srv **dclist,
203                                 int *numdcs)
204 {
205         struct tevent_context *ev;
206         struct tevent_req *req;
207         NTSTATUS status = NT_STATUS_NO_MEMORY;
208         size_t num_srvs;
209
210         ev = samba_tevent_context_init(ctx);
211         if (ev == NULL) {
212                 goto fail;
213         }
214         req = ads_dns_lookup_srv_send(ev, ev, name);
215         if (req == NULL) {
216                 goto fail;
217         }
218         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
219                 goto fail;
220         }
221         status = ads_dns_lookup_srv_recv(req, ctx, dclist, &num_srvs);
222         *numdcs = num_srvs;     /* size_t->int */
223 fail:
224         TALLOC_FREE(ev);
225         return status;
226 }
227
228 struct ads_dns_lookup_ns_state {
229         struct dns_rr_ns *nss;
230         size_t num_nss;
231 };
232
233 static void ads_dns_lookup_ns_done(struct tevent_req *subreq);
234
235 struct tevent_req *ads_dns_lookup_ns_send(TALLOC_CTX *mem_ctx,
236                                           struct tevent_context *ev,
237                                           const char *name)
238 {
239         struct tevent_req *req, *subreq;
240         struct ads_dns_lookup_ns_state *state;
241
242         req = tevent_req_create(mem_ctx, &state,
243                                 struct ads_dns_lookup_ns_state);
244         if (req == NULL) {
245                 return NULL;
246         }
247
248         subreq = dns_lookup_send(state, ev, NULL, name, DNS_QCLASS_IN,
249                                  DNS_QTYPE_NS);
250         if (tevent_req_nomem(subreq, req)) {
251                 return tevent_req_post(req, ev);
252         }
253         tevent_req_set_callback(subreq, ads_dns_lookup_ns_done, req);
254         return req;
255 }
256
257 static void ads_dns_lookup_ns_done(struct tevent_req *subreq)
258 {
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);
263         int ret;
264         struct dns_name_packet *reply;
265         uint16_t i, idx;
266
267         ret = dns_lookup_recv(subreq, state, &reply);
268         TALLOC_FREE(subreq);
269         if (ret != 0) {
270                 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
271                 return;
272         }
273
274         for (i=0; i<reply->ancount; i++) {
275                 if (reply->answers[i].rr_type == DNS_QTYPE_NS) {
276                         state->num_nss += 1;
277                 }
278         }
279
280         state->nss = talloc_array(state, struct dns_rr_ns, state->num_nss);
281         if (tevent_req_nomem(state->nss, req)) {
282                 return;
283         }
284
285         idx = 0;
286
287         for (i=0; i<reply->ancount; i++) {
288                 struct dns_res_rec *an = &reply->answers[i];
289
290                 if (an->rr_type != DNS_QTYPE_NS) {
291                         continue;
292                 }
293
294                 state->nss[idx].hostname = talloc_move(state->nss,
295                                                        &an->rdata.ns_record);
296                 idx += 1;
297         }
298
299         for (i=0; i<reply->arcount; i++) {
300                 struct dns_res_rec *ar = &reply->additional[i];
301                 struct sockaddr_storage addr;
302                 bool ok;
303                 size_t j;
304
305                 ok = dns_res_rec_get_sockaddr(ar, &addr);
306                 if (!ok) {
307                         continue;
308                 }
309
310                 for (j=0; j<state->num_nss; j++) {
311                         struct dns_rr_ns *ns = &state->nss[j];
312
313                         if (strcmp(ns->hostname, ar->name) == 0) {
314                                 ns->ss = addr;
315                         }
316                 }
317         }
318
319         tevent_req_done(req);
320 }
321
322 NTSTATUS ads_dns_lookup_ns_recv(struct tevent_req *req,
323                                 TALLOC_CTX *mem_ctx,
324                                 struct dns_rr_ns **nss,
325                                 size_t *num_nss)
326 {
327         struct ads_dns_lookup_ns_state *state = tevent_req_data(
328                 req, struct ads_dns_lookup_ns_state);
329         NTSTATUS status;
330
331         if (tevent_req_is_nterror(req, &status)) {
332                 return status;
333         }
334         *nss = talloc_move(mem_ctx, &state->nss);
335         *num_nss = state->num_nss;
336         tevent_req_received(req);
337         return NT_STATUS_OK;
338 }
339
340 /*********************************************************************
341  Simple wrapper for a DNS NS query
342 *********************************************************************/
343
344 NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
345                                 const char *dnsdomain,
346                                 struct dns_rr_ns **nslist,
347                                 int *numns)
348 {
349         struct tevent_context *ev;
350         struct tevent_req *req;
351         NTSTATUS status = NT_STATUS_NO_MEMORY;
352         size_t num_ns = 0;
353
354         ev = samba_tevent_context_init(ctx);
355         if (ev == NULL) {
356                 goto fail;
357         }
358         req = ads_dns_lookup_ns_send(ev, ev, dnsdomain);
359         if (req == NULL) {
360                 goto fail;
361         }
362         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
363                 goto fail;
364         }
365         status = ads_dns_lookup_ns_recv(req, ctx, nslist, &num_ns);
366         *numns = num_ns;
367 fail:
368         TALLOC_FREE(ev);
369         return status;
370 }
371
372
373 /********************************************************************
374  Query with optional sitename.
375 ********************************************************************/
376
377 static NTSTATUS ads_dns_query_internal(TALLOC_CTX *ctx,
378                                        const char *servicename,
379                                        const char *dc_pdc_gc_domains,
380                                        const char *realm,
381                                        const char *sitename,
382                                        struct dns_rr_srv **dclist,
383                                        int *numdcs )
384 {
385         char *name;
386         NTSTATUS status;
387         int num_srvs = 0;
388
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);
393                 if (name == NULL) {
394                         return NT_STATUS_NO_MEMORY;
395                 }
396
397                 status = ads_dns_lookup_srv(ctx, name, dclist, &num_srvs);
398
399                 TALLOC_FREE(name);
400
401                 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
402                     NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
403                         return status;
404                 }
405
406                 if (NT_STATUS_IS_OK(status) && (num_srvs != 0)) {
407                         goto done;
408                 }
409         }
410
411         name = talloc_asprintf(ctx, "%s._tcp.%s._msdcs.%s",
412                                servicename, dc_pdc_gc_domains, realm);
413         if (name == NULL) {
414                 return NT_STATUS_NO_MEMORY;
415         }
416         status = ads_dns_lookup_srv(ctx, name, dclist, &num_srvs);
417
418 done:
419         *numdcs = num_srvs; /* automatic conversion size_t->int */
420         return status;
421 }
422
423 /********************************************************************
424  Query for AD DC's.
425 ********************************************************************/
426
427 NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
428                            const char *realm,
429                            const char *sitename,
430                            struct dns_rr_srv **dclist,
431                            int *numdcs )
432 {
433         NTSTATUS status;
434
435         status = ads_dns_query_internal(ctx,
436                                         "_ldap",
437                                         "dc",
438                                         realm,
439                                         sitename,
440                                         dclist,
441                                         numdcs);
442         return status;
443 }
444
445 /********************************************************************
446  Query for AD GC's.
447 ********************************************************************/
448
449 NTSTATUS ads_dns_query_gcs(TALLOC_CTX *ctx,
450                            const char *realm,
451                            const char *sitename,
452                            struct dns_rr_srv **dclist,
453                            int *numdcs )
454 {
455         NTSTATUS status;
456
457         status = ads_dns_query_internal(ctx,
458                                         "_ldap",
459                                         "gc",
460                                         realm,
461                                         sitename,
462                                         dclist,
463                                         numdcs);
464         return status;
465 }
466
467 /********************************************************************
468  Query for AD KDC's.
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 ********************************************************************/
472
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,
477                             int *numdcs )
478 {
479         NTSTATUS status;
480
481         status = ads_dns_query_internal(ctx,
482                                         "_kerberos",
483                                         "dc",
484                                         dns_forest_name,
485                                         sitename,
486                                         dclist,
487                                         numdcs);
488         return status;
489 }
490
491 /********************************************************************
492  Query for AD PDC. Sitename is obsolete here.
493 ********************************************************************/
494
495 NTSTATUS ads_dns_query_pdc(TALLOC_CTX *ctx,
496                            const char *dns_domain_name,
497                            struct dns_rr_srv **dclist,
498                            int *numdcs )
499 {
500         return ads_dns_query_internal(ctx,
501                                       "_ldap",
502                                       "pdc",
503                                       dns_domain_name,
504                                       NULL,
505                                       dclist,
506                                       numdcs);
507 }
508
509 /********************************************************************
510  Query for AD DC by guid. Sitename is obsolete here.
511 ********************************************************************/
512
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,
517                                 int *numdcs )
518 {
519         /*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
520
521         const char *domains;
522
523         /* little hack */
524         domains = talloc_asprintf(ctx, "%s.domains", domain_guid);
525         if (!domains) {
526                 return NT_STATUS_NO_MEMORY;
527         }
528
529         return ads_dns_query_internal(ctx,
530                                       "_ldap",
531                                       domains,
532                                       dns_forest_name,
533                                       NULL,
534                                       dclist,
535                                       numdcs);
536 }