Line data Source code
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.
6 : *
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.
11 : *
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/>.
14 : */
15 :
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"
25 :
26 : /*
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.
29 : */
30 :
31 : struct dns_rr_srv_fill_state {
32 : struct dns_rr_srv *srvs;
33 : size_t num_srvs;
34 :
35 : struct tevent_req **subreqs;
36 : size_t num_outstanding;
37 : };
38 :
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);
44 :
45 445 : 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)
51 : {
52 445 : struct tevent_req *req = NULL, *subreq = NULL;
53 445 : struct dns_rr_srv_fill_state *state = NULL;
54 0 : size_t i, num_subreqs;
55 :
56 445 : req = tevent_req_create(mem_ctx, &state, struct dns_rr_srv_fill_state);
57 445 : if (req == NULL) {
58 0 : return NULL;
59 : }
60 445 : state->srvs = srvs;
61 445 : state->num_srvs = num_srvs;
62 :
63 : /*
64 : * Without IPv6 we only use half of this, but who does not
65 : * have IPv6 these days?
66 : */
67 445 : num_subreqs = num_srvs * 2;
68 :
69 445 : state->subreqs = talloc_zero_array(
70 : state, struct tevent_req *, num_subreqs);
71 445 : if (tevent_req_nomem(state->subreqs, req)) {
72 0 : return tevent_req_post(req, ev);
73 : }
74 :
75 890 : for (i=0; i<num_srvs; i++) {
76 :
77 445 : if (srvs[i].hostname == NULL) {
78 0 : continue;
79 : }
80 445 : if (srvs[i].ss_s != NULL) {
81 : /* IP address returned in SRV record. */
82 0 : continue;
83 : }
84 :
85 445 : subreq = ads_dns_lookup_a_send(
86 445 : state->subreqs, ev, srvs[i].hostname);
87 445 : if (tevent_req_nomem(subreq, req)) {
88 0 : TALLOC_FREE(state->subreqs);
89 0 : return tevent_req_post(req, ev);
90 : }
91 445 : tevent_req_set_callback(
92 : subreq, dns_rr_srv_fill_done_a, req);
93 :
94 445 : state->subreqs[i*2] = subreq;
95 445 : state->num_outstanding += 1;
96 :
97 : #if defined(HAVE_IPV6)
98 445 : subreq = ads_dns_lookup_aaaa_send(
99 445 : state->subreqs, ev, srvs[i].hostname);
100 445 : if (tevent_req_nomem(subreq, req)) {
101 0 : TALLOC_FREE(state->subreqs);
102 0 : return tevent_req_post(req, ev);
103 : }
104 445 : tevent_req_set_callback(
105 : subreq, dns_rr_srv_fill_done_aaaa, req);
106 :
107 445 : state->subreqs[i*2+1] = subreq;
108 445 : state->num_outstanding += 1;
109 : #endif
110 : }
111 :
112 445 : if (state->num_outstanding == 0) {
113 0 : tevent_req_done(req);
114 0 : return tevent_req_post(req, ev);
115 : }
116 :
117 445 : subreq = tevent_wakeup_send(
118 445 : state->subreqs,
119 : ev,
120 : tevent_timeval_current_ofs(timeout, 0));
121 445 : if (tevent_req_nomem(subreq, req)) {
122 0 : return tevent_req_post(req, ev);
123 : }
124 445 : tevent_req_set_callback(subreq, dns_rr_srv_fill_timedout, req);
125 :
126 445 : return req;
127 : }
128 :
129 890 : 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))
138 : {
139 890 : struct tevent_req *req = tevent_req_callback_data(
140 : subreq, struct tevent_req);
141 890 : struct dns_rr_srv_fill_state *state = tevent_req_data(
142 : req, struct dns_rr_srv_fill_state);
143 890 : size_t num_subreqs = talloc_array_length(state->subreqs);
144 890 : struct dns_rr_srv *srv = NULL;
145 0 : size_t num_ips;
146 890 : struct sockaddr_storage *tmp = NULL;
147 890 : uint8_t rcode = 0;
148 890 : char **hostnames_out = NULL;
149 890 : struct samba_sockaddr *addrs = NULL;
150 890 : size_t num_addrs = 0;
151 0 : NTSTATUS status;
152 0 : size_t i;
153 890 : const char *ip_dbg_str = (recv_fn == ads_dns_lookup_a_recv) ?
154 890 : "A" : "AAAA";
155 :
156 : /*
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.
165 : */
166 1335 : for (i=0; i<num_subreqs; i++) {
167 1335 : if (state->subreqs[i] == subreq) {
168 890 : state->subreqs[i] = NULL;
169 890 : break;
170 : }
171 : }
172 890 : if (i == num_subreqs) {
173 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
174 0 : return;
175 : }
176 :
177 890 : srv = &state->srvs[i/2]; /* 2 subreq per srv */
178 :
179 890 : status = recv_fn(
180 : subreq,
181 : state,
182 : &rcode,
183 : &num_addrs,
184 : &hostnames_out,
185 : &addrs);
186 890 : TALLOC_FREE(subreq);
187 :
188 890 : if (!NT_STATUS_IS_OK(status)) {
189 0 : DBG_INFO("async DNS %s lookup for %s returned %s\n",
190 : ip_dbg_str,
191 : srv->hostname,
192 : nt_errstr(status));
193 0 : num_addrs = 0;
194 0 : goto done;
195 : }
196 :
197 890 : if (rcode != DNS_RCODE_OK) {
198 0 : DBG_INFO("async DNS %s lookup for %s returned DNS code "
199 : "%"PRIu8"\n",
200 : ip_dbg_str,
201 : srv->hostname,
202 : rcode);
203 0 : num_addrs = 0;
204 0 : goto done;
205 : }
206 :
207 890 : if (num_addrs == 0) {
208 2 : DBG_INFO("async DNS %s lookup for %s returned 0 addresses.\n",
209 : ip_dbg_str,
210 : srv->hostname);
211 2 : goto done;
212 : }
213 :
214 888 : num_ips = talloc_array_length(srv->ss_s);
215 :
216 888 : if (num_ips + num_addrs < num_addrs) {
217 : /* overflow */
218 0 : goto done;
219 : }
220 :
221 888 : tmp = talloc_realloc(
222 : state->srvs,
223 : srv->ss_s,
224 : struct sockaddr_storage,
225 : num_ips + num_addrs);
226 888 : if (tmp == NULL) {
227 0 : goto done;
228 : }
229 :
230 1776 : for (i=0; i<num_addrs; i++) {
231 0 : char addr[INET6_ADDRSTRLEN];
232 888 : DBG_INFO("async DNS %s lookup for %s [%zu] got %s -> %s\n",
233 : ip_dbg_str,
234 : srv->hostname,
235 : i,
236 : hostnames_out[i],
237 : print_sockaddr(addr, sizeof(addr), &addrs[i].u.ss));
238 888 : tmp[num_ips + i] = addrs[i].u.ss;
239 : }
240 888 : srv->ss_s = tmp;
241 888 : srv->num_ips = num_ips + num_addrs;
242 :
243 890 : done:
244 890 : state->num_outstanding -= 1;
245 890 : if (state->num_outstanding == 0) {
246 445 : tevent_req_done(req);
247 : }
248 : }
249 :
250 445 : static void dns_rr_srv_fill_done_a(struct tevent_req *subreq)
251 : {
252 445 : dns_rr_srv_fill_done(subreq, ads_dns_lookup_a_recv);
253 445 : }
254 :
255 : #if defined(HAVE_IPV6)
256 445 : static void dns_rr_srv_fill_done_aaaa(struct tevent_req *subreq)
257 : {
258 445 : dns_rr_srv_fill_done(subreq, ads_dns_lookup_aaaa_recv);
259 445 : }
260 : #endif
261 :
262 0 : static void dns_rr_srv_fill_timedout(struct tevent_req *subreq)
263 : {
264 0 : struct tevent_req *req = tevent_req_callback_data(
265 : subreq, struct tevent_req);
266 0 : struct dns_rr_srv_fill_state *state = tevent_req_data(
267 : req, struct dns_rr_srv_fill_state);
268 0 : bool ok;
269 :
270 0 : if (DEBUGLEVEL >= DBGLVL_INFO) {
271 0 : size_t i, num_addrs = 0;
272 :
273 0 : for (i=0; i<state->num_srvs; i++) {
274 : /*
275 : * Count for the debug. Code that fills this
276 : * in ensures no wrap.
277 : */
278 0 : num_addrs += state->srvs[i].num_ips;
279 : }
280 :
281 0 : DBG_INFO("async DNS lookup timed out after %zu addresses "
282 : "returned (not an error)\n",
283 : num_addrs);
284 : }
285 :
286 0 : ok = tevent_wakeup_recv(subreq);
287 0 : TALLOC_FREE(subreq);
288 0 : TALLOC_FREE(state->subreqs);
289 0 : if (!ok) {
290 0 : tevent_req_oom(subreq);
291 0 : return;
292 : }
293 :
294 0 : tevent_req_done(req);
295 : }
296 :
297 445 : static NTSTATUS dns_rr_srv_fill_recv(struct tevent_req *req)
298 : {
299 445 : return tevent_req_simple_recv_ntstatus(req);
300 : }
301 :
302 : /*
303 : * Request a SRV record and fill in the A/AAAA records if the SRV
304 : * record did not carry them.
305 : */
306 :
307 : struct ads_dns_query_srv_state {
308 : struct tevent_context *ev;
309 : uint32_t async_dns_timeout;
310 : const char *query;
311 :
312 : struct tevent_req *fill_req;
313 : struct tevent_req *timeout_req;
314 : struct dns_rr_srv *srvs;
315 : size_t num_srvs;
316 : };
317 :
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);
321 :
322 462 : 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)
328 : {
329 462 : struct tevent_req *req = NULL, *subreq = NULL;
330 462 : struct ads_dns_query_srv_state *state = NULL;
331 :
332 462 : req = tevent_req_create(
333 : mem_ctx, &state, struct ads_dns_query_srv_state);
334 462 : if (req == NULL) {
335 0 : return NULL;
336 : }
337 462 : state->ev = ev;
338 462 : state->async_dns_timeout = async_dns_timeout;
339 462 : state->query = query;
340 :
341 462 : if ((sitename != NULL) && (sitename[0] != '\0')) {
342 245 : char *after_tcp = NULL;
343 245 : char *site_aware = NULL;
344 :
345 : /*
346 : * ".<SITENAME>._sites" comes after "._tcp."
347 : */
348 245 : after_tcp = strstr(state->query, "._tcp.");
349 245 : if (after_tcp == NULL) {
350 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
351 0 : return tevent_req_post(req, ev);
352 : }
353 245 : after_tcp += 6; /* strlen("._tcp.") */
354 :
355 245 : site_aware = talloc_asprintf(
356 : state,
357 : "%.*s%s._sites.%s",
358 245 : (int)(after_tcp - state->query),
359 245 : state->query,
360 : sitename,
361 : after_tcp);
362 245 : if (tevent_req_nomem(site_aware, req)) {
363 0 : return tevent_req_post(req, ev);
364 : }
365 :
366 245 : subreq = ads_dns_lookup_srv_send(state, ev, site_aware);
367 245 : if (tevent_req_nomem(subreq, req)) {
368 0 : return tevent_req_post(req, ev);
369 : }
370 245 : tevent_req_set_callback(
371 : subreq, ads_dns_query_srv_site_aware_done, req);
372 245 : return req;
373 : }
374 :
375 217 : subreq = ads_dns_lookup_srv_send(state, state->ev, state->query);
376 217 : if (tevent_req_nomem(subreq, req)) {
377 0 : return tevent_req_post(req, ev);
378 : }
379 217 : tevent_req_set_callback(subreq, ads_dns_query_srv_done, req);
380 217 : return req;
381 : }
382 :
383 245 : static void ads_dns_query_srv_site_aware_done(struct tevent_req *subreq)
384 : {
385 245 : struct tevent_req *req = tevent_req_callback_data(
386 : subreq, struct tevent_req);
387 245 : struct ads_dns_query_srv_state *state = tevent_req_data(
388 : req, struct ads_dns_query_srv_state);
389 0 : NTSTATUS status;
390 :
391 245 : status = ads_dns_lookup_srv_recv(
392 : subreq, state, &state->srvs, &state->num_srvs);
393 245 : TALLOC_FREE(subreq);
394 :
395 245 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
396 245 : NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
397 0 : tevent_req_nterror(req, status);
398 0 : return;
399 : }
400 :
401 245 : if (NT_STATUS_IS_OK(status) && (state->num_srvs != 0)) {
402 241 : if (state->async_dns_timeout == 0) {
403 0 : tevent_req_done(req);
404 0 : return;
405 : }
406 :
407 241 : subreq = dns_rr_srv_fill_send(
408 : state,
409 : state->ev,
410 : state->srvs,
411 : state->num_srvs,
412 : state->async_dns_timeout);
413 241 : if (tevent_req_nomem(subreq, req)) {
414 0 : return;
415 : }
416 241 : tevent_req_set_callback(
417 : subreq, ads_dns_query_srv_filled, req);
418 241 : return;
419 : }
420 :
421 4 : subreq = ads_dns_lookup_srv_send(state, state->ev, state->query);
422 4 : if (tevent_req_nomem(subreq, req)) {
423 0 : return;
424 : }
425 4 : tevent_req_set_callback(subreq, ads_dns_query_srv_done, req);
426 : }
427 :
428 221 : static void ads_dns_query_srv_done(struct tevent_req *subreq)
429 : {
430 221 : struct tevent_req *req = tevent_req_callback_data(
431 : subreq, struct tevent_req);
432 221 : struct ads_dns_query_srv_state *state = tevent_req_data(
433 : req, struct ads_dns_query_srv_state);
434 0 : NTSTATUS status;
435 :
436 221 : status = ads_dns_lookup_srv_recv(
437 : subreq, state, &state->srvs, &state->num_srvs);
438 221 : if (tevent_req_nterror(req, status)) {
439 17 : return;
440 : }
441 :
442 208 : if ((state->num_srvs == 0) || (state->async_dns_timeout == 0)) {
443 4 : tevent_req_done(req);
444 4 : return;
445 : }
446 :
447 204 : subreq = dns_rr_srv_fill_send(
448 : state,
449 : state->ev,
450 : state->srvs,
451 : state->num_srvs,
452 : state->async_dns_timeout);
453 204 : if (tevent_req_nomem(subreq, req)) {
454 0 : return;
455 : }
456 204 : tevent_req_set_callback(subreq, ads_dns_query_srv_filled, req);
457 : }
458 :
459 445 : static void ads_dns_query_srv_filled(struct tevent_req *subreq)
460 : {
461 445 : NTSTATUS status = dns_rr_srv_fill_recv(subreq);
462 445 : return tevent_req_simple_finish_ntstatus(subreq, status);
463 : }
464 :
465 462 : 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)
470 : {
471 462 : struct ads_dns_query_srv_state *state = tevent_req_data(
472 : req, struct ads_dns_query_srv_state);
473 0 : NTSTATUS status;
474 :
475 462 : if (tevent_req_is_nterror(req, &status)) {
476 13 : tevent_req_received(req);
477 13 : return status;
478 : }
479 449 : if (srvs != NULL) {
480 449 : *srvs = talloc_move(mem_ctx, &state->srvs);
481 : }
482 449 : if (num_srvs != NULL) {
483 449 : *num_srvs = state->num_srvs;
484 : }
485 449 : tevent_req_received(req);
486 449 : return NT_STATUS_OK;
487 : }
488 :
489 462 : 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)
496 : {
497 462 : TALLOC_CTX *frame = talloc_stackframe();
498 462 : struct tevent_context *ev = NULL;
499 462 : struct tevent_req *req = NULL;
500 462 : NTSTATUS status = NT_STATUS_NO_MEMORY;
501 :
502 462 : ev = samba_tevent_context_init(frame);
503 462 : if (ev == NULL) {
504 0 : goto fail;
505 : }
506 462 : req = ads_dns_query_srv_send(
507 : frame, ev, async_dns_timeout, sitename, query);
508 462 : if (req == NULL) {
509 0 : goto fail;
510 : }
511 462 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
512 0 : goto fail;
513 : }
514 462 : status = ads_dns_query_srv_recv(req, mem_ctx, srvs, num_srvs);
515 462 : fail:
516 462 : TALLOC_FREE(frame);
517 462 : return status;
518 : }
519 :
520 86 : char *ads_dns_query_string_dcs(TALLOC_CTX *mem_ctx, const char *realm)
521 : {
522 86 : char *ret = talloc_asprintf(mem_ctx, "_ldap._tcp.dc._msdcs.%s", realm);
523 86 : return ret;
524 : }
525 :
526 0 : char *ads_dns_query_string_gcs(TALLOC_CTX *mem_ctx, const char *realm)
527 : {
528 0 : char *ret = talloc_asprintf(mem_ctx, "_ldap._tcp.gc._msdcs.%s", realm);
529 0 : return ret;
530 : }
531 :
532 376 : char *ads_dns_query_string_kdcs(TALLOC_CTX *mem_ctx, const char *realm)
533 : {
534 376 : char *ret = talloc_asprintf(
535 : mem_ctx, "_kerberos._tcp.dc._msdcs.%s", realm);
536 376 : return ret;
537 : }
538 :
539 0 : char *ads_dns_query_string_pdc(TALLOC_CTX *mem_ctx, const char *realm)
540 : {
541 0 : char *ret = talloc_asprintf(
542 : mem_ctx, "_ldap._tcp.pdc._msdcs.%s", realm);
543 0 : return ret;
544 : }
545 :
546 0 : char *ads_dns_query_string_dcs_guid(
547 : TALLOC_CTX *mem_ctx,
548 : const struct GUID *domain_guid,
549 : const char *realm)
550 : {
551 0 : struct GUID_txt_buf buf;
552 0 : char *ret = NULL;
553 :
554 0 : talloc_asprintf(
555 : mem_ctx,
556 : "_ldap._tcp.%s.domains._msdcs.%s",
557 : GUID_buf_string(domain_guid, &buf),
558 : realm);
559 0 : return ret;
560 : }
|