s4-resolv: fix resolution of SRV records pointing to A and AAAA records
[sfrench/samba-autobuild/.git] / source4 / libcli / resolve / dns_ex.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    async getaddrinfo()/dns_lookup() name resolution module
5
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Stefan Metzmacher 2008
8    Copyright (C) Matthieu Patou 2011
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25   this module uses a fork() per getaddrinfo() or dns_looup() call.
26   At first that might seem crazy, but it is actually very fast,
27   and solves many of the tricky problems of keeping a child
28   hanging around in a librar (like what happens when the parent forks).
29   We use a talloc destructor to ensure that the child is cleaned up
30   when we have finished with this name resolution.
31 */
32
33 #include "includes.h"
34 #include "lib/events/events.h"
35 #include "system/network.h"
36 #include "system/filesys.h"
37 #include "lib/socket/socket.h"
38 #include "libcli/composite/composite.h"
39 #include "librpc/gen_ndr/ndr_nbt.h"
40 #include "libcli/resolve/resolve.h"
41 #include "lib/util/util_net.h"
42
43 #ifdef class
44 #undef class
45 #endif
46
47 #include "heimdal/lib/roken/resolve.h"
48
49 struct dns_ex_state {
50         bool do_fallback;
51         uint32_t flags;
52         uint16_t port;
53         struct nbt_name name;
54         struct socket_address **addrs;
55         char **names;
56         pid_t child;
57         int child_fd;
58         struct tevent_fd *fde;
59         struct tevent_context *event_ctx;
60 };
61
62 /*
63   kill off a wayward child if needed. This allows us to stop an async
64   name resolution without leaving a potentially blocking call running
65   in a child
66 */
67 static int dns_ex_destructor(struct dns_ex_state *state)
68 {
69         int status;
70
71         kill(state->child, SIGTERM);
72         if (waitpid(state->child, &status, WNOHANG) == 0) {
73                 kill(state->child, SIGKILL);
74                 waitpid(state->child, &status, 0);
75         }
76
77         return 0;
78 }
79
80 static uint32_t count_dns_rr(struct rk_resource_record *head, unsigned record_type)
81 {
82         uint32_t count = 0;
83         struct rk_resource_record *rr;
84
85         for (rr=head; rr; rr=rr->next) {
86
87                 /* we are only interested in the IN class */
88                 if (rr->class != rk_ns_c_in) {
89                         continue;
90                 }
91
92                 /* we are only interested by requested record */
93                 if (rr->type != record_type) {
94                         continue;
95                 }
96
97                 switch(record_type) {
98                         case rk_ns_t_srv:
99
100                                 /* verify we actually have a SRV record here */
101                                 if (!rr->u.srv) {
102                                         continue;
103                                 }
104
105                                 /* Verify we got a port */
106                                 if (rr->u.srv->port == 0) {
107                                         continue;
108                                 }
109                                 count++;
110                                 break;
111                         case rk_ns_t_a:
112                         case rk_ns_t_aaaa:
113                                 /* verify we actually have a record here */
114                                 if (!rr->u.data) {
115                                         continue;
116                                 }
117                                 count++;
118                                 break;
119                         default:
120                                 count++;
121                                 break;
122                 }
123         }
124
125         return count;
126 }
127
128 struct dns_records_container {
129         char **list;
130         uint32_t count;
131 };
132
133 static char* rr_to_string(TALLOC_CTX *mem_ctx,
134                                         struct rk_resource_record *rr,
135                                         uint16_t port)
136 {
137         char addrstr[INET6_ADDRSTRLEN];
138         char *addr;
139
140         switch (rr->type) {
141                 case rk_ns_t_a:
142                         if (inet_ntop(AF_INET, rr->u.a,
143                                       addrstr, sizeof(addrstr)) == NULL) {
144                                 return NULL;
145                         }
146                         break;
147 #ifdef HAVE_IPV6
148                 case rk_ns_t_aaaa:
149                         if (inet_ntop(AF_INET6, (struct in6_addr *)rr->u.data,
150                                       addrstr, sizeof(addrstr)) == NULL) {
151                                 return NULL;
152                         }
153                         break;
154 #endif
155                 default:
156                         return NULL;
157         }
158
159         addr = talloc_asprintf(mem_ctx, "%s@%u/%s", addrstr,
160                                          port, rr->domain);
161
162         return addr;
163 }
164
165 static struct dns_records_container get_a_aaaa_records(TALLOC_CTX *mem_ctx,
166                                                         const char* name,
167                                                         int port)
168 {
169         struct rk_dns_reply *reply, *reply2, *rep, *tmp[3];
170         struct rk_resource_record *rr;
171         struct dns_records_container ret;
172         char **addrs = NULL;
173         uint32_t count, count2, total;
174         uint32_t i;
175
176         memset(&ret, 0, sizeof(struct dns_records_container));
177         /* this is the blocking call we are going to lots of trouble
178            to avoid them in the parent */
179         reply = rk_dns_lookup(name, "AAAA");
180
181         if (!reply) {
182                 return ret;
183         }
184
185         count = count_dns_rr(reply->head, rk_ns_t_aaaa);
186         count2 = count_dns_rr(reply->head, rk_ns_t_a);
187
188         if (!count2) {
189                 /*
190                  * DNS server didn't returned A when asked for AAAA records.
191                  * Most of the server do it, let's ask for A specificaly.
192                  */
193                 reply2 = rk_dns_lookup(name, "A");
194
195                 if (!reply2) {
196                         return ret;
197                 }
198
199                 count2 = count_dns_rr(reply2->head, rk_ns_t_a);
200         } else {
201                 reply2 = NULL;
202         }
203
204         count += count2;
205
206         if (count == 0) {
207                 goto done;
208         }
209
210         addrs = talloc_zero_array(mem_ctx, char*, count);
211         total = 0;
212
213         tmp[0] = reply;
214         tmp[1] = reply2;
215         tmp[2] = NULL;
216
217         /* Loop over all returned records and pick the records */
218         for (i=0; tmp[i] != NULL; i++) {
219                 rep = tmp[i];
220                 for (rr=rep->head; rr; rr=rr->next) {
221                         /* we are only interested in the IN class */
222                         if (rr->class != rk_ns_c_in) {
223                                 continue;
224                         }
225
226                         /* we are only interested in A and AAAA records */
227                         if (rr->type != rk_ns_t_a && rr->type != rk_ns_t_aaaa) {
228                                 continue;
229                         }
230
231                         /* verify we actually have a record here */
232                         if (!rr->u.data) {
233                                 continue;
234                         }
235                         rr_to_string(mem_ctx, rr, port);
236                         addrs[total] = rr_to_string(mem_ctx, rr, port);
237                         if (addrs[total]) {
238                                 total++;
239                         }
240                 }
241         }
242         if (total) {
243                 ret.count = total;
244                 ret.list = addrs;
245         }
246
247 done:
248         if (reply != NULL)
249                 rk_dns_free_data(reply);
250
251         if (reply2 != NULL)
252                 rk_dns_free_data(reply2);
253
254         return ret;
255 }
256
257 static struct dns_records_container get_srv_records(TALLOC_CTX *mem_ctx,
258                                                         const char* name)
259 {
260         struct rk_dns_reply *reply;
261         struct rk_resource_record *rr;
262         struct dns_records_container ret;
263         char **addrs = NULL;
264         uint32_t count, total;
265
266         memset(&ret, 0, sizeof(struct dns_records_container));
267         /* this is the blocking call we are going to lots of trouble
268            to avoid them in the parent */
269         reply = rk_dns_lookup(name, "SRV");
270
271         if (!reply) {
272                 return ret;
273         }
274
275         rk_dns_srv_order(reply);
276         count = count_dns_rr(reply->head, rk_ns_t_srv);
277
278         total = 0;
279         if (count == 0) {
280                 goto done;
281         }
282
283         /* Loop over all returned records and pick the records */
284         for (rr=reply->head; rr; rr=rr->next) {
285                 struct dns_records_container c;
286                 char* tmp_str;
287                 /* we are only interested in the IN class */
288                 if (rr->class != rk_ns_c_in) {
289                         continue;
290                 }
291
292                 /* we are only interested in SRV records */
293                 if (rr->type != rk_ns_t_srv) {
294                         continue;
295                 }
296
297                 /* verify we actually have a srv record here */
298                 if (!rr->u.srv) {
299                         continue;
300                 }
301
302                 /* Verify we got a port */
303                 if (rr->u.srv->port == 0) {
304                         continue;
305                 }
306
307                 tmp_str = rr->u.srv->target;
308                 if (strchr(tmp_str, '.') && tmp_str[strlen(tmp_str)-1] != '.') {
309                         /* we are asking for a fully qualified name, but the
310                         name doesn't end in a '.'. We need to prevent the
311                         DNS library trying the search domains configured in
312                         resolv.conf */
313                         tmp_str = talloc_asprintf(mem_ctx, "%s.", tmp_str);
314                 }
315
316                 c = get_a_aaaa_records(mem_ctx, tmp_str, rr->u.srv->port);
317                 total += c.count;
318                 if (addrs == NULL) {
319                         addrs = c.list;
320                 } else {
321                         unsigned j;
322
323                         addrs = talloc_realloc(mem_ctx, addrs, char*, total);
324                         for (j=0; j < c.count; j++) {
325                                 addrs[total - j] = talloc_steal(addrs, c.list[j]);
326                         }
327                 }
328         }
329
330         if (total) {
331                 ret.count = total;
332                 ret.list = addrs;
333         }
334
335
336 done:
337         if (reply != NULL)
338                 rk_dns_free_data(reply);
339
340         return ret;
341 }
342 /*
343   the blocking child
344 */
345 static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
346 {
347         bool first;
348         bool do_srv = (state->flags & RESOLVE_NAME_FLAG_DNS_SRV);
349         struct dns_records_container c;
350         char* addrs = NULL;
351         unsigned int i;
352
353         if (strchr(state->name.name, '.') && state->name.name[strlen(state->name.name)-1] != '.') {
354                 /* we are asking for a fully qualified name, but the
355                    name doesn't end in a '.'. We need to prevent the
356                    DNS library trying the search domains configured in
357                    resolv.conf */
358                 state->name.name = talloc_strdup_append(discard_const_p(char, state->name.name),
359                                                         ".");
360         }
361
362
363         if (do_srv) {
364                 c = get_srv_records(state, state->name.name);
365         } else {
366                 c = get_a_aaaa_records(state, state->name.name, state->port);
367         }
368
369         addrs = talloc_strdup(state, "");
370         if (!addrs) {
371                 goto done;
372         }
373         first = true;
374
375         for (i=0; i < c.count; i++) {
376                 addrs = talloc_asprintf_append_buffer(addrs, "%s%s",
377                                                         first?"":",",
378                                                         c.list[i]);
379                 first = false;
380         }
381
382         if (addrs) {
383                 DEBUG(11, ("Addrs = %s\n", addrs));
384                 write(fd, addrs, talloc_get_size(addrs));
385         }
386
387 done:
388         close(fd);
389 }
390
391 /*
392   the blocking child
393 */
394 static void run_child_getaddrinfo(struct dns_ex_state *state, int fd)
395 {
396         int ret;
397         struct addrinfo hints;
398         struct addrinfo *res;
399         struct addrinfo *res_list = NULL;
400         char *addrs;
401         bool first;
402
403         ZERO_STRUCT(hints);
404         hints.ai_socktype = SOCK_STREAM;
405         hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
406
407         ret = getaddrinfo(state->name.name, "0", &hints, &res_list);
408         /* try to fallback in case of error */
409         if (state->do_fallback) {
410                 switch (ret) {
411 #ifdef EAI_NODATA
412                 case EAI_NODATA:
413 #endif
414                 case EAI_NONAME:
415                         /* getaddrinfo() doesn't handle CNAME records */
416                         run_child_dns_lookup(state, fd);
417                         return;
418                 default:
419                         break;
420                 }
421         }
422         if (ret != 0) {
423                 goto done;
424         }
425
426         addrs = talloc_strdup(state, "");
427         if (!addrs) {
428                 goto done;
429         }
430         first = true;
431         for (res = res_list; res; res = res->ai_next) {
432                 char addrstr[INET6_ADDRSTRLEN];
433                 if (!print_sockaddr_len(addrstr, sizeof(addrstr), (struct sockaddr *)res->ai_addr, res->ai_addrlen)) {
434                         continue;
435                 }
436                 addrs = talloc_asprintf_append_buffer(addrs, "%s%s@%u/%s",
437                                                       first?"":",",
438                                                       addrstr,
439                                                       state->port,
440                                                       state->name.name);
441                 if (!addrs) {
442                         goto done;
443                 }
444                 first = false;
445         }
446
447         if (addrs) {
448                 write(fd, addrs, talloc_get_size(addrs));
449         }
450 done:
451         if (res_list) {
452                 freeaddrinfo(res_list);
453         }
454         close(fd);
455 }
456
457 /*
458   handle a read event on the pipe
459 */
460 static void pipe_handler(struct tevent_context *ev, struct tevent_fd *fde, 
461                          uint16_t flags, void *private_data)
462 {
463         struct composite_context *c = talloc_get_type(private_data, struct composite_context);
464         struct dns_ex_state *state = talloc_get_type(c->private_data,
465                                      struct dns_ex_state);
466         char *address;
467         uint32_t num_addrs, i;
468         char **addrs;
469         int ret;
470         int status;
471         int value = 0;
472
473         /* if we get any event from the child then we know that we
474            won't need to kill it off */
475         talloc_set_destructor(state, NULL);
476
477         if (ioctl(state->child_fd, FIONREAD, &value) != 0) {
478                 value = 8192;
479         }
480
481         address = talloc_array(state, char, value+1);
482         if (address) {
483                 /* yes, we don't care about EAGAIN or other niceities
484                    here. They just can't happen with this parent/child
485                    relationship, and even if they did then giving an error is
486                    the right thing to do */
487                 ret = read(state->child_fd, address, value);
488         } else {
489                 ret = -1;
490         }
491         if (waitpid(state->child, &status, WNOHANG) == 0) {
492                 kill(state->child, SIGKILL);
493                 waitpid(state->child, &status, 0);
494         }
495
496         if (ret <= 0) {
497                 DEBUG(3,("dns child failed to find name '%s' of type %s\n",
498                          state->name.name, (state->flags & RESOLVE_NAME_FLAG_DNS_SRV)?"SRV":"A"));
499                 composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
500                 return;
501         }
502
503         /* enusre the address looks good */
504         address[ret] = 0;
505
506         addrs = str_list_make(state, address, ",");
507         if (composite_nomem(addrs, c)) return;
508
509         num_addrs = str_list_length((const char * const *)addrs);
510
511         state->addrs = talloc_array(state, struct socket_address *,
512                                     num_addrs+1);
513         if (composite_nomem(state->addrs, c)) return;
514
515         state->names = talloc_array(state, char *, num_addrs+1);
516         if (composite_nomem(state->names, c)) return;
517
518         for (i=0; i < num_addrs; i++) {
519                 uint32_t port = 0;
520                 char *p = strrchr(addrs[i], '@');
521                 char *n;
522
523                 if (!p) {
524                         composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
525                         return;
526                 }
527
528                 *p = '\0';
529                 p++;
530
531                 n = strrchr(p, '/');
532                 if (!n) {
533                         composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
534                         return;
535                 }
536
537                 *n = '\0';
538                 n++;
539
540                 if (strcmp(addrs[i], "0.0.0.0") == 0) {
541                         composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
542                         return;
543                 }
544                 port = strtoul(p, NULL, 10);
545                 if (port > UINT16_MAX) {
546                         composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
547                         return;
548                 }
549                 state->addrs[i] = socket_address_from_strings(state->addrs,
550                                                               "ip",
551                                                               addrs[i],
552                                                               port);
553                 if (composite_nomem(state->addrs[i], c)) return;
554
555                 state->names[i] = talloc_strdup(state->names, n);
556                 if (composite_nomem(state->names[i], c)) return;
557         }
558         state->addrs[i] = NULL;
559         state->names[i] = NULL;
560
561         composite_done(c);
562 }
563
564 /*
565   getaddrinfo() or dns_lookup() name resolution method - async send
566  */
567 struct composite_context *resolve_name_dns_ex_send(TALLOC_CTX *mem_ctx,
568                                                    struct tevent_context *event_ctx,
569                                                    void *privdata,
570                                                    uint32_t flags,
571                                                    uint16_t port,
572                                                    struct nbt_name *name,
573                                                    bool do_fallback)
574 {
575         struct composite_context *c;
576         struct dns_ex_state *state;
577         int fd[2] = { -1, -1 };
578         int ret;
579
580         c = composite_create(mem_ctx, event_ctx);
581         if (c == NULL) return NULL;
582
583         if (flags & RESOLVE_NAME_FLAG_FORCE_NBT) {
584                 composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
585                 return c;
586         }
587
588         state = talloc_zero(c, struct dns_ex_state);
589         if (composite_nomem(state, c)) return c;
590         c->private_data = state;
591
592         c->status = nbt_name_dup(state, name, &state->name);
593         if (!composite_is_ok(c)) return c;
594
595         /* setup a pipe to chat to our child */
596         ret = pipe(fd);
597         if (ret == -1) {
598                 composite_error(c, map_nt_error_from_unix_common(errno));
599                 return c;
600         }
601
602         state->do_fallback = do_fallback;
603         state->flags = flags;
604         state->port = port;
605
606         state->child_fd = fd[0];
607         state->event_ctx = c->event_ctx;
608
609         /* we need to put the child in our event context so
610            we know when the dns_lookup() has finished */
611         state->fde = tevent_add_fd(c->event_ctx, c, state->child_fd, TEVENT_FD_READ,
612                                   pipe_handler, c);
613         if (composite_nomem(state->fde, c)) {
614                 close(fd[0]);
615                 close(fd[1]);
616                 return c;
617         }
618         tevent_fd_set_auto_close(state->fde);
619
620         state->child = fork();
621         if (state->child == (pid_t)-1) {
622                 composite_error(c, map_nt_error_from_unix_common(errno));
623                 return c;
624         }
625
626         if (state->child == 0) {
627                 close(fd[0]);
628                 if (state->flags & RESOLVE_NAME_FLAG_FORCE_DNS) {
629                         run_child_dns_lookup(state, fd[1]);
630                 } else {
631                         run_child_getaddrinfo(state, fd[1]);
632                 }
633                 _exit(0);
634         }
635         close(fd[1]);
636
637         /* cleanup wayward children */
638         talloc_set_destructor(state, dns_ex_destructor);
639
640         return c;
641 }
642
643 /*
644   getaddrinfo() or dns_lookup() name resolution method - recv side
645 */
646 NTSTATUS resolve_name_dns_ex_recv(struct composite_context *c, 
647                                   TALLOC_CTX *mem_ctx,
648                                   struct socket_address ***addrs,
649                                   char ***names)
650 {
651         NTSTATUS status;
652
653         status = composite_wait(c);
654
655         if (NT_STATUS_IS_OK(status)) {
656                 struct dns_ex_state *state = talloc_get_type(c->private_data,
657                                              struct dns_ex_state);
658                 *addrs = talloc_steal(mem_ctx, state->addrs);
659                 if (names) {
660                         *names = talloc_steal(mem_ctx, state->names);
661                 }
662         }
663
664         talloc_free(c);
665         return status;
666 }