addns: Async ads_dns_lookup_ns
[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 /* AIX resolv.h uses 'class' in struct ns_rr */
30
31 #if defined(AIX)
32 #  if defined(class)
33 #    undef class
34 #  endif
35 #endif  /* AIX */
36
37 /* resolver headers */
38
39 #include <sys/types.h>
40 #include <netinet/in.h>
41 #include <arpa/nameser.h>
42 #include <resolv.h>
43 #include <netdb.h>
44
45 #define MAX_DNS_PACKET_SIZE 0xffff
46
47 #ifdef NS_HFIXEDSZ      /* Bind 8/9 interface */
48 #if !defined(C_IN)      /* AIX 5.3 already defines C_IN */
49 #  define C_IN          ns_c_in
50 #endif
51 #if !defined(T_A)       /* AIX 5.3 already defines T_A */
52 #  define T_A           ns_t_a
53 #endif
54
55 #if defined(HAVE_IPV6)
56 #if !defined(T_AAAA)
57 #  define T_AAAA        ns_t_aaaa
58 #endif
59 #endif
60
61 #  define T_SRV         ns_t_srv
62 #if !defined(T_NS)      /* AIX 5.3 already defines T_NS */
63 #  define T_NS          ns_t_ns
64 #endif
65 #else
66 #  ifdef HFIXEDSZ
67 #    define NS_HFIXEDSZ HFIXEDSZ
68 #  else
69 #    define NS_HFIXEDSZ sizeof(HEADER)
70 #  endif        /* HFIXEDSZ */
71 #  ifdef PACKETSZ
72 #    define NS_PACKETSZ PACKETSZ
73 #  else /* 512 is usually the default */
74 #    define NS_PACKETSZ 512
75 #  endif        /* PACKETSZ */
76 #  define T_SRV         33
77 #endif
78
79 /*********************************************************************
80  Sort SRV record list based on weight and priority.  See RFC 2782.
81 *********************************************************************/
82
83 static int dnssrvcmp( struct dns_rr_srv *a, struct dns_rr_srv *b )
84 {
85         if ( a->priority == b->priority ) {
86
87                 /* randomize entries with an equal weight and priority */
88                 if ( a->weight == b->weight )
89                         return 0;
90
91                 /* higher weights should be sorted lower */
92                 if ( a->weight > b->weight )
93                         return -1;
94                 else
95                         return 1;
96         }
97
98         if ( a->priority < b->priority )
99                 return -1;
100
101         return 1;
102 }
103
104 struct ads_dns_lookup_srv_state {
105         struct dns_rr_srv *srvs;
106         size_t num_srvs;
107 };
108
109 static void ads_dns_lookup_srv_done(struct tevent_req *subreq);
110
111 struct tevent_req *ads_dns_lookup_srv_send(TALLOC_CTX *mem_ctx,
112                                            struct tevent_context *ev,
113                                            const char *name)
114 {
115         struct tevent_req *req, *subreq;
116         struct ads_dns_lookup_srv_state *state;
117
118         req = tevent_req_create(mem_ctx, &state,
119                                 struct ads_dns_lookup_srv_state);
120         if (req == NULL) {
121                 return NULL;
122         }
123
124         subreq = dns_lookup_send(
125                 state,
126                 ev,
127                 NULL,
128                 name,
129                 DNS_QCLASS_IN,
130                 DNS_QTYPE_SRV);
131
132         if (tevent_req_nomem(subreq, req)) {
133                 return tevent_req_post(req, ev);
134         }
135         tevent_req_set_callback(subreq, ads_dns_lookup_srv_done, req);
136         return req;
137 }
138
139 static void ads_dns_lookup_srv_done(struct tevent_req *subreq)
140 {
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);
145         int ret;
146         struct dns_name_packet *reply;
147         uint16_t i, idx;
148
149         ret = dns_lookup_recv(subreq, state, &reply);
150         TALLOC_FREE(subreq);
151         if (ret != 0) {
152                 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
153                 return;
154         }
155
156         for (i=0; i<reply->ancount; i++) {
157                 if (reply->answers[i].rr_type == DNS_QTYPE_SRV) {
158                         state->num_srvs += 1;
159                 }
160         }
161
162         state->srvs = talloc_array(state, struct dns_rr_srv, state->num_srvs);
163         if (tevent_req_nomem(state->srvs, req)) {
164                 return;
165         }
166
167         idx = 0;
168
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;
173
174                 if (an->rr_type != DNS_QTYPE_SRV) {
175                         continue;
176                 }
177                 src = &an->rdata.srv_record;
178
179                 *dst = (struct dns_rr_srv) {
180                         .hostname = talloc_move(state->srvs, &src->target),
181                         .priority = src->priority,
182                         .weight = src->weight,
183                         .port = src->port,
184                 };
185                 idx += 1;
186         }
187
188         for (i=0; i<reply->arcount; i++) {
189                 struct dns_res_rec *ar = &reply->additional[i];
190                 struct sockaddr_storage addr;
191                 bool ok;
192                 size_t j;
193
194                 ok = dns_res_rec_get_sockaddr(ar, &addr);
195                 if (!ok) {
196                         continue;
197                 }
198
199                 for (j=0; j<state->num_srvs; j++) {
200                         struct dns_rr_srv *srv = &state->srvs[j];
201                         struct sockaddr_storage *tmp;
202
203                         if (strcmp(srv->hostname, ar->name) != 0) {
204                                 continue;
205                         }
206
207                         tmp = talloc_realloc(
208                                 state->srvs,
209                                 srv->ss_s,
210                                 struct sockaddr_storage,
211                                 srv->num_ips+1);
212
213                         if (tevent_req_nomem(tmp, req)) {
214                                 return;
215                         }
216                         srv->ss_s = tmp;
217
218                         srv->ss_s[srv->num_ips] = addr;
219                         srv->num_ips += 1;
220                 }
221         }
222
223         TYPESAFE_QSORT(state->srvs, state->num_srvs, dnssrvcmp);
224
225         tevent_req_done(req);
226 }
227
228 NTSTATUS ads_dns_lookup_srv_recv(struct tevent_req *req,
229                                  TALLOC_CTX *mem_ctx,
230                                  struct dns_rr_srv **srvs,
231                                  size_t *num_srvs)
232 {
233         struct ads_dns_lookup_srv_state *state = tevent_req_data(
234                 req, struct ads_dns_lookup_srv_state);
235         NTSTATUS status;
236
237         if (tevent_req_is_nterror(req, &status)) {
238                 return status;
239         }
240         *srvs = talloc_move(mem_ctx, &state->srvs);
241         *num_srvs = state->num_srvs;
242         tevent_req_received(req);
243         return NT_STATUS_OK;
244 }
245
246 /*********************************************************************
247  Simple wrapper for a DNS SRV query
248 *********************************************************************/
249
250 NTSTATUS ads_dns_lookup_srv(TALLOC_CTX *ctx,
251                                 const char *name,
252                                 struct dns_rr_srv **dclist,
253                                 int *numdcs)
254 {
255         struct tevent_context *ev;
256         struct tevent_req *req;
257         NTSTATUS status = NT_STATUS_NO_MEMORY;
258         size_t num_srvs;
259
260         ev = samba_tevent_context_init(ctx);
261         if (ev == NULL) {
262                 goto fail;
263         }
264         req = ads_dns_lookup_srv_send(ev, ev, name);
265         if (req == NULL) {
266                 goto fail;
267         }
268         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
269                 goto fail;
270         }
271         status = ads_dns_lookup_srv_recv(req, ctx, dclist, &num_srvs);
272         *numdcs = num_srvs;     /* size_t->int */
273 fail:
274         TALLOC_FREE(ev);
275         return status;
276 }
277
278 struct ads_dns_lookup_ns_state {
279         struct dns_rr_ns *nss;
280         size_t num_nss;
281 };
282
283 static void ads_dns_lookup_ns_done(struct tevent_req *subreq);
284
285 struct tevent_req *ads_dns_lookup_ns_send(TALLOC_CTX *mem_ctx,
286                                           struct tevent_context *ev,
287                                           const char *name)
288 {
289         struct tevent_req *req, *subreq;
290         struct ads_dns_lookup_ns_state *state;
291
292         req = tevent_req_create(mem_ctx, &state,
293                                 struct ads_dns_lookup_ns_state);
294         if (req == NULL) {
295                 return NULL;
296         }
297
298         subreq = dns_lookup_send(state, ev, NULL, name, DNS_QCLASS_IN,
299                                  DNS_QTYPE_NS);
300         if (tevent_req_nomem(subreq, req)) {
301                 return tevent_req_post(req, ev);
302         }
303         tevent_req_set_callback(subreq, ads_dns_lookup_ns_done, req);
304         return req;
305 }
306
307 static void ads_dns_lookup_ns_done(struct tevent_req *subreq)
308 {
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);
313         int ret;
314         struct dns_name_packet *reply;
315         uint16_t i, idx;
316
317         ret = dns_lookup_recv(subreq, state, &reply);
318         TALLOC_FREE(subreq);
319         if (ret != 0) {
320                 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
321                 return;
322         }
323
324         for (i=0; i<reply->ancount; i++) {
325                 if (reply->answers[i].rr_type == DNS_QTYPE_NS) {
326                         state->num_nss += 1;
327                 }
328         }
329
330         state->nss = talloc_array(state, struct dns_rr_ns, state->num_nss);
331         if (tevent_req_nomem(state->nss, req)) {
332                 return;
333         }
334
335         idx = 0;
336
337         for (i=0; i<reply->ancount; i++) {
338                 struct dns_res_rec *an = &reply->answers[i];
339
340                 if (an->rr_type != DNS_QTYPE_NS) {
341                         continue;
342                 }
343
344                 state->nss[idx].hostname = talloc_move(state->nss,
345                                                        &an->rdata.ns_record);
346                 idx += 1;
347         }
348
349         for (i=0; i<reply->arcount; i++) {
350                 struct dns_res_rec *ar = &reply->additional[i];
351                 struct sockaddr_storage addr;
352                 bool ok;
353                 size_t j;
354
355                 ok = dns_res_rec_get_sockaddr(ar, &addr);
356                 if (!ok) {
357                         continue;
358                 }
359
360                 for (j=0; j<state->num_nss; j++) {
361                         struct dns_rr_ns *ns = &state->nss[j];
362
363                         if (strcmp(ns->hostname, ar->name) == 0) {
364                                 ns->ss = addr;
365                         }
366                 }
367         }
368
369         tevent_req_done(req);
370 }
371
372 NTSTATUS ads_dns_lookup_ns_recv(struct tevent_req *req,
373                                 TALLOC_CTX *mem_ctx,
374                                 struct dns_rr_ns **nss,
375                                 size_t *num_nss)
376 {
377         struct ads_dns_lookup_ns_state *state = tevent_req_data(
378                 req, struct ads_dns_lookup_ns_state);
379         NTSTATUS status;
380
381         if (tevent_req_is_nterror(req, &status)) {
382                 return status;
383         }
384         *nss = talloc_move(mem_ctx, &state->nss);
385         *num_nss = state->num_nss;
386         tevent_req_received(req);
387         return NT_STATUS_OK;
388 }
389
390 /*********************************************************************
391  Simple wrapper for a DNS NS query
392 *********************************************************************/
393
394 NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
395                                 const char *dnsdomain,
396                                 struct dns_rr_ns **nslist,
397                                 int *numns)
398 {
399         struct tevent_context *ev;
400         struct tevent_req *req;
401         NTSTATUS status = NT_STATUS_NO_MEMORY;
402         size_t num_ns = 0;
403
404         ev = samba_tevent_context_init(ctx);
405         if (ev == NULL) {
406                 goto fail;
407         }
408         req = ads_dns_lookup_ns_send(ev, ev, dnsdomain);
409         if (req == NULL) {
410                 goto fail;
411         }
412         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
413                 goto fail;
414         }
415         status = ads_dns_lookup_ns_recv(req, ctx, nslist, &num_ns);
416         *numns = num_ns;
417 fail:
418         TALLOC_FREE(ev);
419         return status;
420 }
421
422
423 /********************************************************************
424  Query with optional sitename.
425 ********************************************************************/
426
427 static NTSTATUS ads_dns_query_internal(TALLOC_CTX *ctx,
428                                        const char *servicename,
429                                        const char *dc_pdc_gc_domains,
430                                        const char *realm,
431                                        const char *sitename,
432                                        struct dns_rr_srv **dclist,
433                                        int *numdcs )
434 {
435         char *name;
436         NTSTATUS status;
437         int num_srvs = 0;
438
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);
443                 if (name == NULL) {
444                         return NT_STATUS_NO_MEMORY;
445                 }
446
447                 status = ads_dns_lookup_srv(ctx, name, dclist, &num_srvs);
448
449                 TALLOC_FREE(name);
450
451                 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
452                     NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
453                         return status;
454                 }
455
456                 if (NT_STATUS_IS_OK(status) && (num_srvs != 0)) {
457                         goto done;
458                 }
459         }
460
461         name = talloc_asprintf(ctx, "%s._tcp.%s._msdcs.%s",
462                                servicename, dc_pdc_gc_domains, realm);
463         if (name == NULL) {
464                 return NT_STATUS_NO_MEMORY;
465         }
466         status = ads_dns_lookup_srv(ctx, name, dclist, &num_srvs);
467
468 done:
469         *numdcs = num_srvs; /* automatic conversion size_t->int */
470         return status;
471 }
472
473 /********************************************************************
474  Query for AD DC's.
475 ********************************************************************/
476
477 NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
478                            const char *realm,
479                            const char *sitename,
480                            struct dns_rr_srv **dclist,
481                            int *numdcs )
482 {
483         NTSTATUS status;
484
485         status = ads_dns_query_internal(ctx,
486                                         "_ldap",
487                                         "dc",
488                                         realm,
489                                         sitename,
490                                         dclist,
491                                         numdcs);
492         return status;
493 }
494
495 /********************************************************************
496  Query for AD GC's.
497 ********************************************************************/
498
499 NTSTATUS ads_dns_query_gcs(TALLOC_CTX *ctx,
500                            const char *realm,
501                            const char *sitename,
502                            struct dns_rr_srv **dclist,
503                            int *numdcs )
504 {
505         NTSTATUS status;
506
507         status = ads_dns_query_internal(ctx,
508                                         "_ldap",
509                                         "gc",
510                                         realm,
511                                         sitename,
512                                         dclist,
513                                         numdcs);
514         return status;
515 }
516
517 /********************************************************************
518  Query for AD KDC's.
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 ********************************************************************/
522
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,
527                             int *numdcs )
528 {
529         NTSTATUS status;
530
531         status = ads_dns_query_internal(ctx,
532                                         "_kerberos",
533                                         "dc",
534                                         dns_forest_name,
535                                         sitename,
536                                         dclist,
537                                         numdcs);
538         return status;
539 }
540
541 /********************************************************************
542  Query for AD PDC. Sitename is obsolete here.
543 ********************************************************************/
544
545 NTSTATUS ads_dns_query_pdc(TALLOC_CTX *ctx,
546                            const char *dns_domain_name,
547                            struct dns_rr_srv **dclist,
548                            int *numdcs )
549 {
550         return ads_dns_query_internal(ctx,
551                                       "_ldap",
552                                       "pdc",
553                                       dns_domain_name,
554                                       NULL,
555                                       dclist,
556                                       numdcs);
557 }
558
559 /********************************************************************
560  Query for AD DC by guid. Sitename is obsolete here.
561 ********************************************************************/
562
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,
567                                 int *numdcs )
568 {
569         /*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
570
571         const char *domains;
572
573         /* little hack */
574         domains = talloc_asprintf(ctx, "%s.domains", domain_guid);
575         if (!domains) {
576                 return NT_STATUS_NO_MEMORY;
577         }
578
579         return ads_dns_query_internal(ctx,
580                                       "_ldap",
581                                       domains,
582                                       dns_forest_name,
583                                       NULL,
584                                       dclist,
585                                       numdcs);
586 }