Line data Source code
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 0 : static int dnssrvcmp( struct dns_rr_srv *a, struct dns_rr_srv *b )
34 : {
35 0 : if ( a->priority == b->priority ) {
36 :
37 : /* randomize entries with an equal weight and priority */
38 0 : if ( a->weight == b->weight )
39 0 : return 0;
40 :
41 : /* higher weights should be sorted lower */
42 0 : if ( a->weight > b->weight )
43 0 : return -1;
44 : else
45 0 : return 1;
46 : }
47 :
48 0 : if ( a->priority < b->priority )
49 0 : return -1;
50 :
51 0 : 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 466 : struct tevent_req *ads_dns_lookup_srv_send(TALLOC_CTX *mem_ctx,
62 : struct tevent_context *ev,
63 : const char *name)
64 : {
65 0 : struct tevent_req *req, *subreq;
66 0 : struct ads_dns_lookup_srv_state *state;
67 :
68 466 : req = tevent_req_create(mem_ctx, &state,
69 : struct ads_dns_lookup_srv_state);
70 466 : if (req == NULL) {
71 0 : return NULL;
72 : }
73 :
74 466 : subreq = dns_lookup_send(
75 : state,
76 : ev,
77 : NULL,
78 : name,
79 : DNS_QCLASS_IN,
80 : DNS_QTYPE_SRV);
81 :
82 466 : if (tevent_req_nomem(subreq, req)) {
83 0 : return tevent_req_post(req, ev);
84 : }
85 466 : tevent_req_set_callback(subreq, ads_dns_lookup_srv_done, req);
86 466 : return req;
87 : }
88 :
89 466 : static void ads_dns_lookup_srv_done(struct tevent_req *subreq)
90 : {
91 466 : struct tevent_req *req = tevent_req_callback_data(
92 : subreq, struct tevent_req);
93 466 : struct ads_dns_lookup_srv_state *state = tevent_req_data(
94 : req, struct ads_dns_lookup_srv_state);
95 0 : int ret;
96 0 : struct dns_name_packet *reply;
97 0 : uint16_t i, idx;
98 :
99 466 : ret = dns_lookup_recv(subreq, state, &reply);
100 466 : TALLOC_FREE(subreq);
101 466 : if (ret != 0) {
102 13 : tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
103 13 : return;
104 : }
105 :
106 898 : for (i=0; i<reply->ancount; i++) {
107 445 : if (reply->answers[i].rr_type == DNS_QTYPE_SRV) {
108 : /* uint16_t can't wrap here. */
109 445 : state->num_srvs += 1;
110 : }
111 : }
112 :
113 453 : state->srvs = talloc_array(state, struct dns_rr_srv, state->num_srvs);
114 453 : if (tevent_req_nomem(state->srvs, req)) {
115 0 : return;
116 : }
117 :
118 453 : idx = 0;
119 :
120 898 : for (i=0; i<reply->ancount; i++) {
121 445 : struct dns_res_rec *an = &reply->answers[i];
122 445 : struct dns_rr_srv *dst = &state->srvs[idx];
123 0 : struct dns_srv_record *src;
124 :
125 445 : if (an->rr_type != DNS_QTYPE_SRV) {
126 0 : continue;
127 : }
128 445 : src = &an->rdata.srv_record;
129 :
130 445 : *dst = (struct dns_rr_srv) {
131 445 : .hostname = talloc_move(state->srvs, &src->target),
132 445 : .priority = src->priority,
133 445 : .weight = src->weight,
134 445 : .port = src->port,
135 : };
136 445 : idx += 1;
137 : }
138 :
139 453 : for (i=0; i<reply->arcount; i++) {
140 0 : struct dns_res_rec *ar = &reply->additional[i];
141 0 : struct sockaddr_storage addr;
142 0 : bool ok;
143 0 : size_t j;
144 :
145 0 : ok = dns_res_rec_get_sockaddr(ar, &addr);
146 0 : if (!ok) {
147 0 : continue;
148 : }
149 :
150 0 : for (j=0; j<state->num_srvs; j++) {
151 0 : struct dns_rr_srv *srv = &state->srvs[j];
152 0 : struct sockaddr_storage *tmp;
153 :
154 0 : if (strcmp(srv->hostname, ar->name) != 0) {
155 0 : continue;
156 : }
157 : /* uint16_t can't wrap here. */
158 0 : tmp = talloc_realloc(
159 : state->srvs,
160 : srv->ss_s,
161 : struct sockaddr_storage,
162 : srv->num_ips+1);
163 :
164 0 : if (tevent_req_nomem(tmp, req)) {
165 0 : return;
166 : }
167 0 : srv->ss_s = tmp;
168 :
169 0 : srv->ss_s[srv->num_ips] = addr;
170 0 : srv->num_ips += 1;
171 : }
172 : }
173 :
174 453 : TYPESAFE_QSORT(state->srvs, state->num_srvs, dnssrvcmp);
175 :
176 453 : tevent_req_done(req);
177 : }
178 :
179 466 : NTSTATUS ads_dns_lookup_srv_recv(struct tevent_req *req,
180 : TALLOC_CTX *mem_ctx,
181 : struct dns_rr_srv **srvs,
182 : size_t *num_srvs)
183 : {
184 466 : struct ads_dns_lookup_srv_state *state = tevent_req_data(
185 : req, struct ads_dns_lookup_srv_state);
186 0 : NTSTATUS status;
187 :
188 466 : if (tevent_req_is_nterror(req, &status)) {
189 13 : return status;
190 : }
191 453 : *srvs = talloc_move(mem_ctx, &state->srvs);
192 453 : *num_srvs = state->num_srvs;
193 453 : tevent_req_received(req);
194 453 : return NT_STATUS_OK;
195 : }
196 :
197 : /*********************************************************************
198 : Simple wrapper for a DNS SRV query
199 : *********************************************************************/
200 :
201 0 : NTSTATUS ads_dns_lookup_srv(TALLOC_CTX *ctx,
202 : const char *name,
203 : struct dns_rr_srv **dclist,
204 : size_t *numdcs)
205 : {
206 0 : struct tevent_context *ev;
207 0 : struct tevent_req *req;
208 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
209 0 : size_t num_srvs = 0;
210 :
211 0 : ev = samba_tevent_context_init(ctx);
212 0 : if (ev == NULL) {
213 0 : goto fail;
214 : }
215 0 : req = ads_dns_lookup_srv_send(ev, ev, name);
216 0 : if (req == NULL) {
217 0 : goto fail;
218 : }
219 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
220 0 : goto fail;
221 : }
222 0 : status = ads_dns_lookup_srv_recv(req, ctx, dclist, &num_srvs);
223 0 : if (NT_STATUS_IS_OK(status)) {
224 0 : *numdcs = num_srvs;
225 : }
226 0 : fail:
227 0 : TALLOC_FREE(ev);
228 0 : return status;
229 : }
230 :
231 : struct ads_dns_lookup_ns_state {
232 : struct dns_rr_ns *nss;
233 : size_t num_nss;
234 : };
235 :
236 : static void ads_dns_lookup_ns_done(struct tevent_req *subreq);
237 :
238 64 : struct tevent_req *ads_dns_lookup_ns_send(TALLOC_CTX *mem_ctx,
239 : struct tevent_context *ev,
240 : const char *name)
241 : {
242 0 : struct tevent_req *req, *subreq;
243 0 : struct ads_dns_lookup_ns_state *state;
244 :
245 64 : req = tevent_req_create(mem_ctx, &state,
246 : struct ads_dns_lookup_ns_state);
247 64 : if (req == NULL) {
248 0 : return NULL;
249 : }
250 :
251 64 : subreq = dns_lookup_send(state, ev, NULL, name, DNS_QCLASS_IN,
252 : DNS_QTYPE_NS);
253 64 : if (tevent_req_nomem(subreq, req)) {
254 0 : return tevent_req_post(req, ev);
255 : }
256 64 : tevent_req_set_callback(subreq, ads_dns_lookup_ns_done, req);
257 64 : return req;
258 : }
259 :
260 64 : static void ads_dns_lookup_ns_done(struct tevent_req *subreq)
261 : {
262 64 : struct tevent_req *req = tevent_req_callback_data(
263 : subreq, struct tevent_req);
264 64 : struct ads_dns_lookup_ns_state *state = tevent_req_data(
265 : req, struct ads_dns_lookup_ns_state);
266 0 : int ret;
267 0 : struct dns_name_packet *reply;
268 0 : uint16_t i, idx;
269 :
270 64 : ret = dns_lookup_recv(subreq, state, &reply);
271 64 : TALLOC_FREE(subreq);
272 64 : if (ret != 0) {
273 0 : tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
274 0 : return;
275 : }
276 :
277 106 : for (i=0; i<reply->ancount; i++) {
278 42 : if (reply->answers[i].rr_type == DNS_QTYPE_NS) {
279 42 : state->num_nss += 1;
280 : }
281 : }
282 :
283 64 : state->nss = talloc_array(state, struct dns_rr_ns, state->num_nss);
284 64 : if (tevent_req_nomem(state->nss, req)) {
285 0 : return;
286 : }
287 :
288 64 : idx = 0;
289 :
290 106 : for (i=0; i<reply->ancount; i++) {
291 42 : struct dns_res_rec *an = &reply->answers[i];
292 :
293 42 : if (an->rr_type != DNS_QTYPE_NS) {
294 0 : continue;
295 : }
296 :
297 42 : state->nss[idx].hostname = talloc_move(state->nss,
298 : &an->rdata.ns_record);
299 42 : idx += 1;
300 : }
301 :
302 64 : for (i=0; i<reply->arcount; i++) {
303 0 : struct dns_res_rec *ar = &reply->additional[i];
304 0 : struct sockaddr_storage addr;
305 0 : bool ok;
306 0 : size_t j;
307 :
308 0 : ok = dns_res_rec_get_sockaddr(ar, &addr);
309 0 : if (!ok) {
310 0 : continue;
311 : }
312 :
313 0 : for (j=0; j<state->num_nss; j++) {
314 0 : struct dns_rr_ns *ns = &state->nss[j];
315 :
316 0 : if (strcmp(ns->hostname, ar->name) == 0) {
317 0 : ns->ss = addr;
318 : }
319 : }
320 : }
321 :
322 64 : tevent_req_done(req);
323 : }
324 :
325 64 : NTSTATUS ads_dns_lookup_ns_recv(struct tevent_req *req,
326 : TALLOC_CTX *mem_ctx,
327 : struct dns_rr_ns **nss,
328 : size_t *num_nss)
329 : {
330 64 : struct ads_dns_lookup_ns_state *state = tevent_req_data(
331 : req, struct ads_dns_lookup_ns_state);
332 0 : NTSTATUS status;
333 :
334 64 : if (tevent_req_is_nterror(req, &status)) {
335 0 : return status;
336 : }
337 64 : *nss = talloc_move(mem_ctx, &state->nss);
338 64 : *num_nss = state->num_nss;
339 64 : tevent_req_received(req);
340 64 : return NT_STATUS_OK;
341 : }
342 :
343 : /*********************************************************************
344 : Simple wrapper for a DNS NS query
345 : *********************************************************************/
346 :
347 64 : NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
348 : const char *dnsdomain,
349 : struct dns_rr_ns **nslist,
350 : size_t *numns)
351 : {
352 0 : struct tevent_context *ev;
353 0 : struct tevent_req *req;
354 64 : NTSTATUS status = NT_STATUS_NO_MEMORY;
355 64 : size_t num_ns = 0;
356 :
357 64 : ev = samba_tevent_context_init(ctx);
358 64 : if (ev == NULL) {
359 0 : goto fail;
360 : }
361 64 : req = ads_dns_lookup_ns_send(ev, ev, dnsdomain);
362 64 : if (req == NULL) {
363 0 : goto fail;
364 : }
365 64 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
366 0 : goto fail;
367 : }
368 64 : status = ads_dns_lookup_ns_recv(req, ctx, nslist, &num_ns);
369 64 : *numns = num_ns;
370 64 : fail:
371 64 : TALLOC_FREE(ev);
372 64 : return status;
373 : }
374 :
375 : /*********************************************************************
376 : Async A record lookup.
377 : *********************************************************************/
378 :
379 : struct ads_dns_lookup_a_state {
380 : uint8_t rcode;
381 : size_t num_names;
382 : char **hostnames;
383 : struct samba_sockaddr *addrs;
384 : };
385 :
386 : static void ads_dns_lookup_a_done(struct tevent_req *subreq);
387 :
388 447 : struct tevent_req *ads_dns_lookup_a_send(TALLOC_CTX *mem_ctx,
389 : struct tevent_context *ev,
390 : const char *name)
391 : {
392 447 : struct tevent_req *req = NULL, *subreq = NULL;
393 447 : struct ads_dns_lookup_a_state *state = NULL;
394 :
395 447 : req = tevent_req_create(mem_ctx, &state,
396 : struct ads_dns_lookup_a_state);
397 447 : if (req == NULL) {
398 0 : return NULL;
399 : }
400 :
401 447 : subreq = dns_lookup_send(
402 : state,
403 : ev,
404 : NULL,
405 : name,
406 : DNS_QCLASS_IN,
407 : DNS_QTYPE_A);
408 :
409 447 : if (tevent_req_nomem(subreq, req)) {
410 0 : return tevent_req_post(req, ev);
411 : }
412 447 : tevent_req_set_callback(subreq, ads_dns_lookup_a_done, req);
413 447 : return req;
414 : }
415 :
416 447 : static void ads_dns_lookup_a_done(struct tevent_req *subreq)
417 : {
418 447 : struct tevent_req *req = tevent_req_callback_data(
419 : subreq, struct tevent_req);
420 447 : struct ads_dns_lookup_a_state *state = tevent_req_data(
421 : req, struct ads_dns_lookup_a_state);
422 0 : int ret;
423 447 : struct dns_name_packet *reply = NULL;
424 0 : uint16_t i;
425 :
426 447 : ret = dns_lookup_recv(subreq, state, &reply);
427 447 : TALLOC_FREE(subreq);
428 447 : if (ret != 0) {
429 0 : tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
430 0 : return;
431 : }
432 :
433 447 : state->rcode = (reply->operation & DNS_RCODE);
434 447 : if (state->rcode != DNS_RCODE_OK) {
435 : /* Don't bother looking for answers. */
436 0 : tevent_req_done(req);
437 0 : return;
438 : }
439 :
440 : /*
441 : * We don't care about CNAME answers here. We're
442 : * just wanting an async name -> IPv4 lookup.
443 : */
444 894 : for (i = 0; i < reply->ancount; i++) {
445 447 : if (reply->answers[i].rr_type == DNS_QTYPE_A) {
446 447 : state->num_names += 1;
447 : }
448 : }
449 :
450 447 : state->hostnames = talloc_zero_array(state,
451 : char *,
452 : state->num_names);
453 447 : if (tevent_req_nomem(state->hostnames, req)) {
454 0 : return;
455 : }
456 447 : state->addrs = talloc_zero_array(state,
457 : struct samba_sockaddr,
458 : state->num_names);
459 447 : if (tevent_req_nomem(state->addrs, req)) {
460 0 : return;
461 : }
462 :
463 447 : state->num_names = 0;
464 :
465 894 : for (i = 0; i < reply->ancount; i++) {
466 0 : bool ok;
467 447 : struct sockaddr_storage ss = {0};
468 447 : struct dns_res_rec *an = &reply->answers[i];
469 :
470 447 : if (an->rr_type != DNS_QTYPE_A) {
471 0 : continue;
472 : }
473 447 : if (an->name == NULL) {
474 : /* Can this happen? */
475 0 : continue;
476 : }
477 447 : if (an->rdata.ipv4_record == NULL) {
478 : /* Can this happen? */
479 0 : continue;
480 : }
481 447 : ok = dns_res_rec_get_sockaddr(an,
482 : &ss);
483 447 : if (!ok) {
484 0 : continue;
485 : }
486 447 : if (is_zero_addr(&ss)) {
487 0 : continue;
488 : }
489 447 : state->addrs[state->num_names].u.ss = ss;
490 447 : state->addrs[state->num_names].sa_socklen =
491 : sizeof(struct sockaddr_in);
492 894 : state->hostnames[state->num_names] = talloc_strdup(
493 447 : state->hostnames,
494 : an->name);
495 447 : if (tevent_req_nomem(state->hostnames[state->num_names], req)) {
496 0 : return;
497 : }
498 447 : state->num_names += 1;
499 : }
500 :
501 447 : tevent_req_done(req);
502 : }
503 :
504 447 : NTSTATUS ads_dns_lookup_a_recv(struct tevent_req *req,
505 : TALLOC_CTX *mem_ctx,
506 : uint8_t *rcode_out,
507 : size_t *num_names_out,
508 : char ***hostnames_out,
509 : struct samba_sockaddr **addrs_out)
510 : {
511 447 : struct ads_dns_lookup_a_state *state = tevent_req_data(
512 : req, struct ads_dns_lookup_a_state);
513 0 : NTSTATUS status;
514 :
515 447 : if (tevent_req_is_nterror(req, &status)) {
516 0 : return status;
517 : }
518 447 : if (rcode_out != NULL) {
519 : /*
520 : * If we got no names, an upper layer may
521 : * want to print a debug message.
522 : */
523 445 : *rcode_out = state->rcode;
524 : }
525 447 : if (hostnames_out != NULL) {
526 447 : *hostnames_out = talloc_move(mem_ctx,
527 : &state->hostnames);
528 : }
529 447 : if (addrs_out != NULL) {
530 447 : *addrs_out = talloc_move(mem_ctx,
531 : &state->addrs);
532 : }
533 447 : *num_names_out = state->num_names;
534 447 : tevent_req_received(req);
535 447 : return NT_STATUS_OK;
536 : }
537 :
538 : /*********************************************************************
539 : Simple wrapper for a DNS A query
540 : *********************************************************************/
541 :
542 2 : NTSTATUS ads_dns_lookup_a(TALLOC_CTX *ctx,
543 : const char *name_in,
544 : size_t *num_names_out,
545 : char ***hostnames_out,
546 : struct samba_sockaddr **addrs_out)
547 : {
548 0 : struct tevent_context *ev;
549 0 : struct tevent_req *req;
550 2 : NTSTATUS status = NT_STATUS_NO_MEMORY;
551 :
552 2 : ev = samba_tevent_context_init(ctx);
553 2 : if (ev == NULL) {
554 0 : goto fail;
555 : }
556 2 : req = ads_dns_lookup_a_send(ev, ev, name_in);
557 2 : if (req == NULL) {
558 0 : goto fail;
559 : }
560 2 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
561 0 : goto fail;
562 : }
563 : /*
564 : * Synchronous doesn't need to care about the rcode or
565 : * a copy of the name_in.
566 : */
567 2 : status = ads_dns_lookup_a_recv(req,
568 : ctx,
569 : NULL,
570 : num_names_out,
571 : hostnames_out,
572 : addrs_out);
573 2 : fail:
574 2 : TALLOC_FREE(ev);
575 2 : return status;
576 : }
577 :
578 : #if defined(HAVE_IPV6)
579 : /*********************************************************************
580 : Async AAAA record lookup.
581 : *********************************************************************/
582 :
583 : struct ads_dns_lookup_aaaa_state {
584 : uint8_t rcode;
585 : size_t num_names;
586 : char **hostnames;
587 : struct samba_sockaddr *addrs;
588 : };
589 :
590 : static void ads_dns_lookup_aaaa_done(struct tevent_req *subreq);
591 :
592 447 : struct tevent_req *ads_dns_lookup_aaaa_send(TALLOC_CTX *mem_ctx,
593 : struct tevent_context *ev,
594 : const char *name)
595 : {
596 447 : struct tevent_req *req, *subreq = NULL;
597 447 : struct ads_dns_lookup_aaaa_state *state = NULL;
598 :
599 447 : req = tevent_req_create(mem_ctx, &state,
600 : struct ads_dns_lookup_aaaa_state);
601 447 : if (req == NULL) {
602 0 : return NULL;
603 : }
604 :
605 447 : subreq = dns_lookup_send(
606 : state,
607 : ev,
608 : NULL,
609 : name,
610 : DNS_QCLASS_IN,
611 : DNS_QTYPE_AAAA);
612 :
613 447 : if (tevent_req_nomem(subreq, req)) {
614 0 : return tevent_req_post(req, ev);
615 : }
616 447 : tevent_req_set_callback(subreq, ads_dns_lookup_aaaa_done, req);
617 447 : return req;
618 : }
619 :
620 447 : static void ads_dns_lookup_aaaa_done(struct tevent_req *subreq)
621 : {
622 447 : struct tevent_req *req = tevent_req_callback_data(
623 : subreq, struct tevent_req);
624 447 : struct ads_dns_lookup_aaaa_state *state = tevent_req_data(
625 : req, struct ads_dns_lookup_aaaa_state);
626 0 : int ret;
627 447 : struct dns_name_packet *reply = NULL;
628 0 : uint16_t i;
629 :
630 447 : ret = dns_lookup_recv(subreq, state, &reply);
631 447 : TALLOC_FREE(subreq);
632 447 : if (ret != 0) {
633 0 : tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
634 0 : return;
635 : }
636 :
637 447 : state->rcode = (reply->operation & DNS_RCODE);
638 447 : if (state->rcode != DNS_RCODE_OK) {
639 : /* Don't bother looking for answers. */
640 0 : tevent_req_done(req);
641 0 : return;
642 : }
643 :
644 : /*
645 : * We don't care about CNAME answers here. We're
646 : * just wanting an async name -> IPv6 lookup.
647 : */
648 892 : for (i = 0; i < reply->ancount; i++) {
649 445 : if (reply->answers[i].rr_type == DNS_QTYPE_AAAA) {
650 445 : state->num_names += 1;
651 : }
652 : }
653 :
654 447 : state->hostnames = talloc_zero_array(state,
655 : char *,
656 : state->num_names);
657 447 : if (tevent_req_nomem(state->hostnames, req)) {
658 0 : return;
659 : }
660 447 : state->addrs = talloc_zero_array(state,
661 : struct samba_sockaddr,
662 : state->num_names);
663 447 : if (tevent_req_nomem(state->addrs, req)) {
664 0 : return;
665 : }
666 :
667 447 : state->num_names = 0;
668 :
669 892 : for (i = 0; i < reply->ancount; i++) {
670 0 : bool ok;
671 445 : struct sockaddr_storage ss = {0};
672 445 : struct dns_res_rec *an = &reply->answers[i];
673 :
674 445 : if (an->rr_type != DNS_QTYPE_AAAA) {
675 0 : continue;
676 : }
677 445 : if (an->name == NULL) {
678 : /* Can this happen? */
679 0 : continue;
680 : }
681 445 : if (an->rdata.ipv6_record == NULL) {
682 : /* Can this happen? */
683 0 : continue;
684 : }
685 445 : ok = dns_res_rec_get_sockaddr(an,
686 : &ss);
687 445 : if (!ok) {
688 0 : continue;
689 : }
690 445 : if (is_zero_addr(&ss)) {
691 0 : continue;
692 : }
693 445 : state->addrs[state->num_names].u.ss = ss;
694 445 : state->addrs[state->num_names].sa_socklen =
695 : sizeof(struct sockaddr_in6);
696 :
697 890 : state->hostnames[state->num_names] = talloc_strdup(
698 445 : state->hostnames,
699 : an->name);
700 445 : if (tevent_req_nomem(state->hostnames[state->num_names], req)) {
701 0 : return;
702 : }
703 445 : state->num_names += 1;
704 : }
705 :
706 447 : tevent_req_done(req);
707 : }
708 :
709 447 : NTSTATUS ads_dns_lookup_aaaa_recv(struct tevent_req *req,
710 : TALLOC_CTX *mem_ctx,
711 : uint8_t *rcode_out,
712 : size_t *num_names_out,
713 : char ***hostnames_out,
714 : struct samba_sockaddr **addrs_out)
715 : {
716 447 : struct ads_dns_lookup_aaaa_state *state = tevent_req_data(
717 : req, struct ads_dns_lookup_aaaa_state);
718 0 : NTSTATUS status;
719 :
720 447 : if (tevent_req_is_nterror(req, &status)) {
721 0 : return status;
722 : }
723 447 : if (rcode_out != NULL) {
724 : /*
725 : * If we got no names, an upper layer may
726 : * want to print a debug message.
727 : */
728 445 : *rcode_out = state->rcode;
729 : }
730 447 : if (hostnames_out != NULL) {
731 447 : *hostnames_out = talloc_move(mem_ctx,
732 : &state->hostnames);
733 : }
734 447 : if (addrs_out != NULL) {
735 447 : *addrs_out = talloc_move(mem_ctx,
736 : &state->addrs);
737 : }
738 447 : *num_names_out = state->num_names;
739 447 : tevent_req_received(req);
740 447 : return NT_STATUS_OK;
741 : }
742 :
743 : /*********************************************************************
744 : Simple wrapper for a DNS AAAA query
745 : *********************************************************************/
746 :
747 2 : NTSTATUS ads_dns_lookup_aaaa(TALLOC_CTX *ctx,
748 : const char *name_in,
749 : size_t *num_names_out,
750 : char ***hostnames_out,
751 : struct samba_sockaddr **addrs_out)
752 : {
753 2 : struct tevent_context *ev = NULL;
754 2 : struct tevent_req *req = NULL;
755 2 : NTSTATUS status = NT_STATUS_NO_MEMORY;
756 :
757 2 : ev = samba_tevent_context_init(ctx);
758 2 : if (ev == NULL) {
759 0 : goto fail;
760 : }
761 2 : req = ads_dns_lookup_aaaa_send(ev, ev, name_in);
762 2 : if (req == NULL) {
763 0 : goto fail;
764 : }
765 2 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
766 0 : goto fail;
767 : }
768 : /*
769 : * Synchronous doesn't need to care about the rcode or
770 : * a copy of the name_in.
771 : */
772 2 : status = ads_dns_lookup_aaaa_recv(req,
773 : ctx,
774 : NULL,
775 : num_names_out,
776 : hostnames_out,
777 : addrs_out);
778 2 : fail:
779 2 : TALLOC_FREE(ev);
780 2 : return status;
781 : }
782 : #endif
|