2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 3 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 #include "dnsquery_srv.h"
19 #include "lib/util/debug.h"
20 #include "lib/util/tevent_ntstatus.h"
21 #include "lib/util/talloc_stack.h"
22 #include "lib/util/samba_util.h"
23 #include "librpc/gen_ndr/dns.h"
24 #include "librpc/ndr/libndr.h"
27 * For an array of dns_rr_srv records, issue A/AAAA queries for those
28 * records where the initial reply did not return IP addresses.
31 struct dns_rr_srv_fill_state
{
32 struct dns_rr_srv
*srvs
;
35 struct tevent_req
**subreqs
;
36 size_t num_outstanding
;
39 static void dns_rr_srv_fill_done_a(struct tevent_req
*subreq
);
40 #if defined(HAVE_IPV6)
41 static void dns_rr_srv_fill_done_aaaa(struct tevent_req
*subreq
);
43 static void dns_rr_srv_fill_timedout(struct tevent_req
*subreq
);
45 static struct tevent_req
*dns_rr_srv_fill_send(
47 struct tevent_context
*ev
,
48 struct dns_rr_srv
*srvs
,
52 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
53 struct dns_rr_srv_fill_state
*state
= NULL
;
54 size_t i
, num_subreqs
;
56 req
= tevent_req_create(mem_ctx
, &state
, struct dns_rr_srv_fill_state
);
61 state
->num_srvs
= num_srvs
;
64 * Without IPv6 we only use half of this, but who does not
65 * have IPv6 these days?
67 num_subreqs
= num_srvs
* 2;
69 state
->subreqs
= talloc_zero_array(
70 state
, struct tevent_req
*, num_subreqs
);
71 if (tevent_req_nomem(state
->subreqs
, req
)) {
72 return tevent_req_post(req
, ev
);
75 for (i
=0; i
<num_srvs
; i
++) {
77 if (srvs
[i
].hostname
== NULL
) {
80 if (srvs
[i
].ss_s
!= NULL
) {
81 /* IP address returned in SRV record. */
85 subreq
= ads_dns_lookup_a_send(
86 state
->subreqs
, ev
, srvs
[i
].hostname
);
87 if (tevent_req_nomem(subreq
, req
)) {
88 TALLOC_FREE(state
->subreqs
);
89 return tevent_req_post(req
, ev
);
91 tevent_req_set_callback(
92 subreq
, dns_rr_srv_fill_done_a
, req
);
94 state
->subreqs
[i
*2] = subreq
;
95 state
->num_outstanding
+= 1;
97 #if defined(HAVE_IPV6)
98 subreq
= ads_dns_lookup_aaaa_send(
99 state
->subreqs
, ev
, srvs
[i
].hostname
);
100 if (tevent_req_nomem(subreq
, req
)) {
101 TALLOC_FREE(state
->subreqs
);
102 return tevent_req_post(req
, ev
);
104 tevent_req_set_callback(
105 subreq
, dns_rr_srv_fill_done_aaaa
, req
);
107 state
->subreqs
[i
*2+1] = subreq
;
108 state
->num_outstanding
+= 1;
112 if (state
->num_outstanding
== 0) {
113 tevent_req_done(req
);
114 return tevent_req_post(req
, ev
);
117 subreq
= tevent_wakeup_send(
120 tevent_timeval_current_ofs(timeout
, 0));
121 if (tevent_req_nomem(subreq
, req
)) {
122 return tevent_req_post(req
, ev
);
124 tevent_req_set_callback(subreq
, dns_rr_srv_fill_timedout
, req
);
129 static void dns_rr_srv_fill_done(
130 struct tevent_req
*subreq
,
132 struct tevent_req
*req
,
135 size_t *num_names_out
,
136 char ***hostnames_out
,
137 struct samba_sockaddr
**addrs_out
))
139 struct tevent_req
*req
= tevent_req_callback_data(
140 subreq
, struct tevent_req
);
141 struct dns_rr_srv_fill_state
*state
= tevent_req_data(
142 req
, struct dns_rr_srv_fill_state
);
143 size_t num_subreqs
= talloc_array_length(state
->subreqs
);
144 struct dns_rr_srv
*srv
= NULL
;
146 struct sockaddr_storage
*tmp
= NULL
;
148 char **hostnames_out
= NULL
;
149 struct samba_sockaddr
*addrs
= NULL
;
150 size_t num_addrs
= 0;
153 const char *ip_dbg_str
= (recv_fn
== ads_dns_lookup_a_recv
) ?
157 * This loop walks all potential subreqs. Typical setups won't
158 * have more than a few DCs. If you have really many DCs
159 * (hundreds) and a DNS that doesn't return the DC IPs in the
160 * SRV reply, you have bigger problems than this loop linearly
161 * walking a pointer array. This is theoretically O(n^2), but
162 * probably the DNS roundtrip time outweighs this by a
163 * lot. And we have a global timeout on this whole
164 * dns_rr_srv_fill routine.
166 for (i
=0; i
<num_subreqs
; i
++) {
167 if (state
->subreqs
[i
] == subreq
) {
168 state
->subreqs
[i
] = NULL
;
172 if (i
== num_subreqs
) {
173 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
177 srv
= &state
->srvs
[i
/2]; /* 2 subreq per srv */
188 if (!NT_STATUS_IS_OK(status
)) {
189 DBG_INFO("async DNS %s lookup for %s returned %s\n",
197 if (rcode
!= DNS_RCODE_OK
) {
198 DBG_INFO("async DNS %s lookup for %s returned DNS code "
207 if (num_addrs
== 0) {
208 DBG_INFO("async DNS %s lookup for %s returned 0 addresses.\n",
214 num_ips
= talloc_array_length(srv
->ss_s
);
216 if (num_ips
+ num_addrs
< num_addrs
) {
221 tmp
= talloc_realloc(
224 struct sockaddr_storage
,
225 num_ips
+ num_addrs
);
230 for (i
=0; i
<num_addrs
; i
++) {
231 char addr
[INET6_ADDRSTRLEN
];
232 DBG_INFO("async DNS %s lookup for %s [%zu] got %s -> %s\n",
237 print_sockaddr(addr
, sizeof(addr
), &addrs
[i
].u
.ss
));
238 tmp
[num_ips
+ i
] = addrs
[i
].u
.ss
;
241 srv
->num_ips
= num_ips
+ num_addrs
;
244 state
->num_outstanding
-= 1;
245 if (state
->num_outstanding
== 0) {
246 tevent_req_done(req
);
250 static void dns_rr_srv_fill_done_a(struct tevent_req
*subreq
)
252 dns_rr_srv_fill_done(subreq
, ads_dns_lookup_a_recv
);
255 #if defined(HAVE_IPV6)
256 static void dns_rr_srv_fill_done_aaaa(struct tevent_req
*subreq
)
258 dns_rr_srv_fill_done(subreq
, ads_dns_lookup_aaaa_recv
);
262 static void dns_rr_srv_fill_timedout(struct tevent_req
*subreq
)
264 struct tevent_req
*req
= tevent_req_callback_data(
265 subreq
, struct tevent_req
);
266 struct dns_rr_srv_fill_state
*state
= tevent_req_data(
267 req
, struct dns_rr_srv_fill_state
);
270 if (DEBUGLEVEL
>= DBGLVL_INFO
) {
271 size_t i
, num_addrs
= 0;
273 for (i
=0; i
<state
->num_srvs
; i
++) {
275 * Count for the debug. Code that fills this
276 * in ensures no wrap.
278 num_addrs
+= state
->srvs
[i
].num_ips
;
281 DBG_INFO("async DNS lookup timed out after %zu addresses "
282 "returned (not an error)\n",
286 ok
= tevent_wakeup_recv(subreq
);
288 TALLOC_FREE(state
->subreqs
);
290 tevent_req_oom(subreq
);
294 tevent_req_done(req
);
297 static NTSTATUS
dns_rr_srv_fill_recv(struct tevent_req
*req
)
299 return tevent_req_simple_recv_ntstatus(req
);
303 * Request a SRV record and fill in the A/AAAA records if the SRV
304 * record did not carry them.
307 struct ads_dns_query_srv_state
{
308 struct tevent_context
*ev
;
309 uint32_t async_dns_timeout
;
312 struct tevent_req
*fill_req
;
313 struct tevent_req
*timeout_req
;
314 struct dns_rr_srv
*srvs
;
318 static void ads_dns_query_srv_site_aware_done(struct tevent_req
*subreq
);
319 static void ads_dns_query_srv_done(struct tevent_req
*subreq
);
320 static void ads_dns_query_srv_filled(struct tevent_req
*subreq
);
322 struct tevent_req
*ads_dns_query_srv_send(
324 struct tevent_context
*ev
,
325 uint32_t async_dns_timeout
,
326 const char *sitename
,
329 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
330 struct ads_dns_query_srv_state
*state
= NULL
;
332 req
= tevent_req_create(
333 mem_ctx
, &state
, struct ads_dns_query_srv_state
);
338 state
->async_dns_timeout
= async_dns_timeout
;
339 state
->query
= query
;
341 if ((sitename
!= NULL
) && (sitename
[0] != '\0')) {
342 char *after_tcp
= NULL
;
343 char *site_aware
= NULL
;
346 * ".<SITENAME>._sites" comes after "._tcp."
348 after_tcp
= strstr(state
->query
, "._tcp.");
349 if (after_tcp
== NULL
) {
350 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
351 return tevent_req_post(req
, ev
);
353 after_tcp
+= 6; /* strlen("._tcp.") */
355 site_aware
= talloc_asprintf(
358 (int)(after_tcp
- state
->query
),
362 if (tevent_req_nomem(site_aware
, req
)) {
363 return tevent_req_post(req
, ev
);
366 subreq
= ads_dns_lookup_srv_send(state
, ev
, site_aware
);
367 if (tevent_req_nomem(subreq
, req
)) {
368 return tevent_req_post(req
, ev
);
370 tevent_req_set_callback(
371 subreq
, ads_dns_query_srv_site_aware_done
, req
);
375 subreq
= ads_dns_lookup_srv_send(state
, state
->ev
, state
->query
);
376 if (tevent_req_nomem(subreq
, req
)) {
377 return tevent_req_post(req
, ev
);
379 tevent_req_set_callback(subreq
, ads_dns_query_srv_done
, req
);
383 static void ads_dns_query_srv_site_aware_done(struct tevent_req
*subreq
)
385 struct tevent_req
*req
= tevent_req_callback_data(
386 subreq
, struct tevent_req
);
387 struct ads_dns_query_srv_state
*state
= tevent_req_data(
388 req
, struct ads_dns_query_srv_state
);
391 status
= ads_dns_lookup_srv_recv(
392 subreq
, state
, &state
->srvs
, &state
->num_srvs
);
395 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
396 NT_STATUS_EQUAL(status
, NT_STATUS_CONNECTION_REFUSED
)) {
397 tevent_req_nterror(req
, status
);
401 if (NT_STATUS_IS_OK(status
) && (state
->num_srvs
!= 0)) {
402 if (state
->async_dns_timeout
== 0) {
403 tevent_req_done(req
);
407 subreq
= dns_rr_srv_fill_send(
412 state
->async_dns_timeout
);
413 if (tevent_req_nomem(subreq
, req
)) {
416 tevent_req_set_callback(
417 subreq
, ads_dns_query_srv_filled
, req
);
421 subreq
= ads_dns_lookup_srv_send(state
, state
->ev
, state
->query
);
422 if (tevent_req_nomem(subreq
, req
)) {
425 tevent_req_set_callback(subreq
, ads_dns_query_srv_done
, req
);
428 static void ads_dns_query_srv_done(struct tevent_req
*subreq
)
430 struct tevent_req
*req
= tevent_req_callback_data(
431 subreq
, struct tevent_req
);
432 struct ads_dns_query_srv_state
*state
= tevent_req_data(
433 req
, struct ads_dns_query_srv_state
);
436 status
= ads_dns_lookup_srv_recv(
437 subreq
, state
, &state
->srvs
, &state
->num_srvs
);
438 if (tevent_req_nterror(req
, status
)) {
442 if ((state
->num_srvs
== 0) || (state
->async_dns_timeout
== 0)) {
443 tevent_req_done(req
);
447 subreq
= dns_rr_srv_fill_send(
452 state
->async_dns_timeout
);
453 if (tevent_req_nomem(subreq
, req
)) {
456 tevent_req_set_callback(subreq
, ads_dns_query_srv_filled
, req
);
459 static void ads_dns_query_srv_filled(struct tevent_req
*subreq
)
461 NTSTATUS status
= dns_rr_srv_fill_recv(subreq
);
462 return tevent_req_simple_finish_ntstatus(subreq
, status
);
465 NTSTATUS
ads_dns_query_srv_recv(
466 struct tevent_req
*req
,
468 struct dns_rr_srv
**srvs
,
471 struct ads_dns_query_srv_state
*state
= tevent_req_data(
472 req
, struct ads_dns_query_srv_state
);
475 if (tevent_req_is_nterror(req
, &status
)) {
476 tevent_req_received(req
);
480 *srvs
= talloc_move(mem_ctx
, &state
->srvs
);
482 if (num_srvs
!= NULL
) {
483 *num_srvs
= state
->num_srvs
;
485 tevent_req_received(req
);
489 NTSTATUS
ads_dns_query_srv(
491 uint32_t async_dns_timeout
,
492 const char *sitename
,
494 struct dns_rr_srv
**srvs
,
497 TALLOC_CTX
*frame
= talloc_stackframe();
498 struct tevent_context
*ev
= NULL
;
499 struct tevent_req
*req
= NULL
;
500 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
502 ev
= samba_tevent_context_init(frame
);
506 req
= ads_dns_query_srv_send(
507 frame
, ev
, async_dns_timeout
, sitename
, query
);
511 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
514 status
= ads_dns_query_srv_recv(req
, mem_ctx
, srvs
, num_srvs
);
520 char *ads_dns_query_string_dcs(TALLOC_CTX
*mem_ctx
, const char *realm
)
522 char *ret
= talloc_asprintf(mem_ctx
, "_ldap._tcp.dc._msdcs.%s", realm
);
526 char *ads_dns_query_string_gcs(TALLOC_CTX
*mem_ctx
, const char *realm
)
528 char *ret
= talloc_asprintf(mem_ctx
, "_ldap._tcp.gc._msdcs.%s", realm
);
532 char *ads_dns_query_string_kdcs(TALLOC_CTX
*mem_ctx
, const char *realm
)
534 char *ret
= talloc_asprintf(
535 mem_ctx
, "_kerberos._tcp.dc._msdcs.%s", realm
);
539 char *ads_dns_query_string_pdc(TALLOC_CTX
*mem_ctx
, const char *realm
)
541 char *ret
= talloc_asprintf(
542 mem_ctx
, "_ldap._tcp.pdc._msdcs.%s", realm
);
546 char *ads_dns_query_string_dcs_guid(
548 const struct GUID
*domain_guid
,
551 struct GUID_txt_buf buf
;
556 "_ldap._tcp.%s.domains._msdcs.%s",
557 GUID_buf_string(domain_guid
, &buf
),