wscript: s/default/required/ _static_modules for the acl modules
[Samba.git] / lib / addns / dnsquery_srv.c
blob6cba22f32a2c48d9b7bbf02dca56d06ade47f63e
1 /*
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/>.
16 #include "replace.h"
17 #include "dnsquery.h"
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;
33 size_t num_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);
42 #endif
43 static void dns_rr_srv_fill_timedout(struct tevent_req *subreq);
45 static struct tevent_req *dns_rr_srv_fill_send(
46 TALLOC_CTX *mem_ctx,
47 struct tevent_context *ev,
48 struct dns_rr_srv *srvs,
49 size_t num_srvs,
50 uint32_t timeout)
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);
57 if (req == NULL) {
58 return NULL;
60 state->srvs = srvs;
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) {
78 continue;
80 if (srvs[i].ss_s != NULL) {
81 /* IP address returned in SRV record. */
82 continue;
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;
109 #endif
112 if (state->num_outstanding == 0) {
113 tevent_req_done(req);
114 return tevent_req_post(req, ev);
117 subreq = tevent_wakeup_send(
118 state->subreqs,
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);
126 return req;
129 static void dns_rr_srv_fill_done(
130 struct tevent_req *subreq,
131 NTSTATUS (*recv_fn)(
132 struct tevent_req *req,
133 TALLOC_CTX *mem_ctx,
134 uint8_t *rcode_out,
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;
145 size_t num_ips;
146 struct sockaddr_storage *tmp = NULL;
147 uint8_t rcode = 0;
148 char **hostnames_out = NULL;
149 struct samba_sockaddr *addrs = NULL;
150 size_t num_addrs = 0;
151 NTSTATUS status;
152 size_t i;
153 const char *ip_dbg_str = (recv_fn == ads_dns_lookup_a_recv) ?
154 "A" : "AAAA";
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 outweights 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;
169 break;
172 if (i == num_subreqs) {
173 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
174 return;
177 srv = &state->srvs[i/2]; /* 2 subreq per srv */
179 status = recv_fn(
180 subreq,
181 state,
182 &rcode,
183 &num_addrs,
184 &hostnames_out,
185 &addrs);
186 TALLOC_FREE(subreq);
188 if (!NT_STATUS_IS_OK(status)) {
189 DBG_INFO("async DNS %s lookup for %s returned %s\n",
190 ip_dbg_str,
191 srv->hostname,
192 nt_errstr(status));
193 num_addrs = 0;
194 goto done;
197 if (rcode != DNS_RCODE_OK) {
198 DBG_INFO("async DNS %s lookup for %s returned DNS code "
199 "%"PRIu8"\n",
200 ip_dbg_str,
201 srv->hostname,
202 rcode);
203 num_addrs = 0;
204 goto done;
207 if (num_addrs == 0) {
208 DBG_INFO("async DNS %s lookup for %s returned 0 addresses.\n",
209 ip_dbg_str,
210 srv->hostname);
211 goto done;
214 num_ips = talloc_array_length(srv->ss_s);
216 if (num_ips + num_addrs < num_addrs) {
217 /* overflow */
218 goto done;
221 tmp = talloc_realloc(
222 state->srvs,
223 srv->ss_s,
224 struct sockaddr_storage,
225 num_ips + num_addrs);
226 if (tmp == NULL) {
227 goto done;
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",
233 ip_dbg_str,
234 srv->hostname,
236 hostnames_out[i],
237 print_sockaddr(addr, sizeof(addr), &addrs[i].u.ss));
238 tmp[num_ips + i] = addrs[i].u.ss;
240 srv->ss_s = tmp;
241 srv->num_ips = num_ips + num_addrs;
243 done:
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);
260 #endif
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);
268 bool ok;
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",
283 num_addrs);
286 ok = tevent_wakeup_recv(subreq);
287 TALLOC_FREE(subreq);
288 TALLOC_FREE(state->subreqs);
289 if (!ok) {
290 tevent_req_oom(subreq);
291 return;
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;
310 const char *query;
312 struct tevent_req *fill_req;
313 struct tevent_req *timeout_req;
314 struct dns_rr_srv *srvs;
315 size_t num_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(
323 TALLOC_CTX *mem_ctx,
324 struct tevent_context *ev,
325 uint32_t async_dns_timeout,
326 const char *sitename,
327 const char *query)
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);
334 if (req == NULL) {
335 return NULL;
337 state->ev = ev;
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(
356 state,
357 "%.*s%s._sites.%s",
358 (int)(after_tcp - state->query),
359 state->query,
360 sitename,
361 after_tcp);
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);
372 return 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);
380 return 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);
389 NTSTATUS status;
391 status = ads_dns_lookup_srv_recv(
392 subreq, state, &state->srvs, &state->num_srvs);
393 TALLOC_FREE(subreq);
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);
398 return;
401 if (NT_STATUS_IS_OK(status) && (state->num_srvs != 0)) {
402 if (state->async_dns_timeout == 0) {
403 tevent_req_done(req);
404 return;
407 subreq = dns_rr_srv_fill_send(
408 state,
409 state->ev,
410 state->srvs,
411 state->num_srvs,
412 state->async_dns_timeout);
413 if (tevent_req_nomem(subreq, req)) {
414 return;
416 tevent_req_set_callback(
417 subreq, ads_dns_query_srv_filled, req);
418 return;
421 subreq = ads_dns_lookup_srv_send(state, state->ev, state->query);
422 if (tevent_req_nomem(subreq, req)) {
423 return;
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);
434 NTSTATUS status;
436 status = ads_dns_lookup_srv_recv(
437 subreq, state, &state->srvs, &state->num_srvs);
438 if (tevent_req_nterror(req, status)) {
439 return;
442 if ((state->num_srvs == 0) || (state->async_dns_timeout == 0)) {
443 tevent_req_done(req);
444 return;
447 subreq = dns_rr_srv_fill_send(
448 state,
449 state->ev,
450 state->srvs,
451 state->num_srvs,
452 state->async_dns_timeout);
453 if (tevent_req_nomem(subreq, req)) {
454 return;
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,
467 TALLOC_CTX *mem_ctx,
468 struct dns_rr_srv **srvs,
469 size_t *num_srvs)
471 struct ads_dns_query_srv_state *state = tevent_req_data(
472 req, struct ads_dns_query_srv_state);
473 NTSTATUS status;
475 if (tevent_req_is_nterror(req, &status)) {
476 tevent_req_received(req);
477 return status;
479 if (srvs != NULL) {
480 *srvs = talloc_move(mem_ctx, &state->srvs);
482 if (num_srvs != NULL) {
483 *num_srvs = state->num_srvs;
485 tevent_req_received(req);
486 return NT_STATUS_OK;
489 NTSTATUS ads_dns_query_srv(
490 TALLOC_CTX *mem_ctx,
491 uint32_t async_dns_timeout,
492 const char *sitename,
493 const char *query,
494 struct dns_rr_srv **srvs,
495 size_t *num_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);
503 if (ev == NULL) {
504 goto fail;
506 req = ads_dns_query_srv_send(
507 frame, ev, async_dns_timeout, sitename, query);
508 if (req == NULL) {
509 goto fail;
511 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
512 goto fail;
514 status = ads_dns_query_srv_recv(req, mem_ctx, srvs, num_srvs);
515 fail:
516 TALLOC_FREE(frame);
517 return status;
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);
523 return ret;
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);
529 return ret;
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);
536 return ret;
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);
543 return ret;
546 char *ads_dns_query_string_dcs_guid(
547 TALLOC_CTX *mem_ctx,
548 const struct GUID *domain_guid,
549 const char *realm)
551 struct GUID_txt_buf buf;
552 char *ret = NULL;
554 talloc_asprintf(
555 mem_ctx,
556 "_ldap._tcp.%s.domains._msdcs.%s",
557 GUID_buf_string(domain_guid, &buf),
558 realm);
559 return ret;