s4-resolve: Remove dependency on libroken
[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 #include "lib/addns/dnsquery.h"
43 #include "lib/addns/dns.h"
44 #include <arpa/nameser.h>
45 #include <resolv.h>
46
47 struct dns_ex_state {
48         bool do_fallback;
49         uint32_t flags;
50         uint16_t port;
51         struct nbt_name name;
52         struct socket_address **addrs;
53         char **names;
54         pid_t child;
55         int child_fd;
56         struct tevent_fd *fde;
57         struct tevent_context *event_ctx;
58 };
59
60 /*
61   kill off a wayward child if needed. This allows us to stop an async
62   name resolution without leaving a potentially blocking call running
63   in a child
64 */
65 static int dns_ex_destructor(struct dns_ex_state *state)
66 {
67         int status;
68
69         kill(state->child, SIGTERM);
70         if (waitpid(state->child, &status, WNOHANG) == 0) {
71                 kill(state->child, SIGKILL);
72                 waitpid(state->child, &status, 0);
73         }
74
75         return 0;
76 }
77
78 struct dns_records_container {
79         char **list;
80         uint32_t count;
81 };
82
83 static int reply_to_addrs(TALLOC_CTX *mem_ctx, uint32_t *a_num,
84                           char ***cur_addrs, uint32_t total,
85                           struct dns_request *reply, int port)
86 {
87         char addrstr[INET6_ADDRSTRLEN];
88         struct dns_rrec *rr;
89         char **addrs;
90         uint32_t i;
91         const char *addr;
92
93         /* at most we over-allocate here, but not by much */
94         addrs = talloc_realloc(mem_ctx, *cur_addrs, char *,
95                                 total + reply->num_answers);
96         if (!addrs) {
97                 return 0;
98         }
99         *cur_addrs = addrs;
100
101         for (i = 0; reply->answers[i]; i++) {
102                 rr = reply->answers[i];
103
104                 /* we are only interested in the IN class */
105                 if (rr->r_class != DNS_CLASS_IN) {
106                         continue;
107                 }
108
109                 if (rr->type == QTYPE_NS) {
110                         /*
111                          * After the record for NS will come the A or AAAA
112                          * record of the NS.
113                          */
114                         break;
115                 }
116
117                 /* verify we actually have a record here */
118                 if (!rr->data) {
119                         continue;
120                 }
121
122                 /* we are only interested in A and AAAA records */
123                 switch (rr->type) {
124                 case QTYPE_A:
125                         addr = inet_ntop(AF_INET,
126                                          (struct in_addr *)rr->data,
127                                          addrstr, sizeof(addrstr));
128                         if (addr == NULL) {
129                                 continue;
130                         }
131                         break;
132                 case QTYPE_AAAA:
133 #ifdef HAVE_IPV6
134                         addr = inet_ntop(AF_INET6,
135                                          (struct in6_addr *)rr->data,
136                                          addrstr, sizeof(addrstr));
137 #else
138                         addr = NULL;
139 #endif
140                         if (addr == NULL) {
141                                 continue;
142                         }
143                 default:
144                         continue;
145                 }
146
147                 addrs[total] = talloc_asprintf(addrs, "%s@%u/%s",
148                                                 addrstr, port,
149                                                 rr->name->pLabelList->label);
150                 if (addrs[total]) {
151                         total++;
152                         if (rr->type == QTYPE_A) {
153                                 (*a_num)++;
154                         }
155                 }
156         }
157
158         return total;
159 }
160
161 static DNS_ERROR dns_lookup(TALLOC_CTX *mem_ctx, const char* name,
162                             uint16_t q_type, struct dns_request **reply)
163 {
164         int len, rlen;
165         uint8_t *answer;
166         bool loop;
167         struct dns_buffer buf;
168         DNS_ERROR err;
169
170         /* give space for a good sized answer by default */
171         answer = NULL;
172         len = 1500;
173         do {
174                 answer = talloc_realloc(mem_ctx, answer, uint8_t, len);
175                 if (!answer) {
176                         return ERROR_DNS_NO_MEMORY;
177                 }
178                 rlen = res_search(name, DNS_CLASS_IN, q_type, answer, len);
179                 if (rlen == -1) {
180                         if (len >= 65535) {
181                                 return ERROR_DNS_SOCKET_ERROR;
182                         }
183                         /* retry once with max packet size */
184                         len = 65535;
185                         loop = true;
186                 } else if (rlen > len) {
187                         len = rlen;
188                         loop = true;
189                 } else {
190                         loop = false;
191                 }
192         } while(loop);
193
194         buf.data = answer;
195         buf.size = rlen;
196         buf.offset = 0;
197         buf.error = ERROR_DNS_SUCCESS;
198
199         err = dns_unmarshall_request(mem_ctx, &buf, reply);
200
201         TALLOC_FREE(answer);
202         return err;
203 }
204
205 static struct dns_records_container get_a_aaaa_records(TALLOC_CTX *mem_ctx,
206                                                         const char* name,
207                                                         int port)
208 {
209         struct dns_request *reply;
210         struct dns_records_container ret;
211         char **addrs = NULL;
212         uint32_t a_num, total;
213         uint16_t qtype;
214         TALLOC_CTX *tmp_ctx;
215         DNS_ERROR err;
216
217         memset(&ret, 0, sizeof(struct dns_records_container));
218
219         tmp_ctx = talloc_new(mem_ctx);
220         if (!tmp_ctx) {
221                 return ret;
222         }
223
224         qtype = QTYPE_AAAA;
225
226         /* this is the blocking call we are going to lots of trouble
227            to avoid them in the parent */
228         err = dns_lookup(tmp_ctx, name, qtype, &reply);
229         if (!ERR_DNS_IS_OK(err)) {
230                 qtype = QTYPE_A;
231                 err = dns_lookup(tmp_ctx, name, qtype, &reply);
232                 if (!ERR_DNS_IS_OK(err)) {
233                         goto done;
234                 }
235         }
236
237         a_num = total = 0;
238         total = reply_to_addrs(tmp_ctx, &a_num, &addrs, total, reply, port);
239
240         if (qtype == QTYPE_AAAA && a_num == 0) {
241                 /*
242                 * DNS server didn't returned A when asked for AAAA records.
243                 * Most of the server do it, let's ask for A specificaly.
244                 */
245                 err = dns_lookup(tmp_ctx, name, QTYPE_A, &reply);
246                 if (!ERR_DNS_IS_OK(err)) {
247                         goto done;
248                 }
249
250                 total = reply_to_addrs(tmp_ctx, &a_num, &addrs, total,
251                                         reply, port);
252
253         }
254
255         if (total) {
256                 talloc_steal(mem_ctx, addrs);
257                 ret.count = total;
258                 ret.list = addrs;
259         }
260
261 done:
262         TALLOC_FREE(tmp_ctx);
263         return ret;
264 }
265
266 static struct dns_records_container get_srv_records(TALLOC_CTX *mem_ctx,
267                                                         const char* name)
268 {
269         struct dns_records_container ret;
270         char **addrs = NULL;
271         struct dns_rr_srv *dclist;
272         NTSTATUS status;
273         uint32_t total;
274         unsigned i;
275         int count;
276
277         memset(&ret, 0, sizeof(struct dns_records_container));
278         /* this is the blocking call we are going to lots of trouble
279            to avoid them in the parent */
280         status = ads_dns_lookup_srv(mem_ctx, NULL, name, &dclist, &count);
281         if (!NT_STATUS_IS_OK(status)) {
282                 return ret;
283         }
284         total = 0;
285         if (count == 0) {
286                 return ret;
287         }
288
289         /* Loop over all returned records and pick the records */
290         for (i = 0; i < count; i++) {
291                 struct dns_records_container c;
292                 const char* tmp_str;
293
294                 tmp_str = dclist[i].hostname;
295                 if (strchr(tmp_str, '.') && tmp_str[strlen(tmp_str)-1] != '.') {
296                         /* we are asking for a fully qualified name, but the
297                         name doesn't end in a '.'. We need to prevent the
298                         DNS library trying the search domains configured in
299                         resolv.conf */
300                         tmp_str = talloc_asprintf(mem_ctx, "%s.", tmp_str);
301                 }
302
303                 c = get_a_aaaa_records(mem_ctx, tmp_str, dclist[i].port);
304                 total += c.count;
305                 if (addrs == NULL) {
306                         addrs = c.list;
307                 } else {
308                         unsigned j;
309
310                         addrs = talloc_realloc(mem_ctx, addrs, char*, total);
311                         for (j=0; j < c.count; j++) {
312                                 addrs[total - j - 1] = talloc_steal(addrs, c.list[j]);
313                         }
314                 }
315         }
316
317         if (total) {
318                 ret.count = total;
319                 ret.list = addrs;
320         }
321
322         return ret;
323 }
324 /*
325   the blocking child
326 */
327 static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
328 {
329         bool first;
330         bool do_srv = (state->flags & RESOLVE_NAME_FLAG_DNS_SRV);
331         struct dns_records_container c;
332         char* addrs = NULL;
333         unsigned int i;
334
335         if (strchr(state->name.name, '.') && state->name.name[strlen(state->name.name)-1] != '.') {
336                 /* we are asking for a fully qualified name, but the
337                    name doesn't end in a '.'. We need to prevent the
338                    DNS library trying the search domains configured in
339                    resolv.conf */
340                 state->name.name = talloc_strdup_append(discard_const_p(char, state->name.name),
341                                                         ".");
342         }
343
344
345         if (do_srv) {
346                 c = get_srv_records(state, state->name.name);
347         } else {
348                 c = get_a_aaaa_records(state, state->name.name, state->port);
349         }
350
351         /* This line in critical - if we return without writing to the
352          * pipe, this is the signal that the name did not exist */
353         if (c.count == 0) {
354                 goto done;
355         }
356
357         addrs = talloc_strdup(state, "");
358         if (!addrs) {
359                 goto done;
360         }
361         first = true;
362
363         for (i=0; i < c.count; i++) {
364                 addrs = talloc_asprintf_append_buffer(addrs, "%s%s",
365                                                         first?"":",",
366                                                         c.list[i]);
367                 first = false;
368         }
369
370         if (addrs) {
371                 DEBUG(11, ("Addrs = %s\n", addrs));
372                 write(fd, addrs, talloc_get_size(addrs));
373         }
374
375 done:
376         close(fd);
377 }
378
379 /*
380   the blocking child
381 */
382 static void run_child_getaddrinfo(struct dns_ex_state *state, int fd)
383 {
384         int ret;
385         struct addrinfo hints;
386         struct addrinfo *res;
387         struct addrinfo *res_list = NULL;
388         char *addrs;
389         bool first;
390
391         ZERO_STRUCT(hints);
392         hints.ai_socktype = SOCK_STREAM;
393         hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
394
395         ret = getaddrinfo(state->name.name, "0", &hints, &res_list);
396         /* try to fallback in case of error */
397         if (state->do_fallback) {
398                 switch (ret) {
399 #ifdef EAI_NODATA
400                 case EAI_NODATA:
401 #endif
402                 case EAI_NONAME:
403                         /* getaddrinfo() doesn't handle CNAME records */
404                         run_child_dns_lookup(state, fd);
405                         return;
406                 default:
407                         break;
408                 }
409         }
410         if (ret != 0) {
411                 goto done;
412         }
413
414         addrs = talloc_strdup(state, "");
415         if (!addrs) {
416                 goto done;
417         }
418         first = true;
419         for (res = res_list; res; res = res->ai_next) {
420                 char addrstr[INET6_ADDRSTRLEN];
421                 if (!print_sockaddr_len(addrstr, sizeof(addrstr), (struct sockaddr *)res->ai_addr, res->ai_addrlen)) {
422                         continue;
423                 }
424                 addrs = talloc_asprintf_append_buffer(addrs, "%s%s@%u/%s",
425                                                       first?"":",",
426                                                       addrstr,
427                                                       state->port,
428                                                       state->name.name);
429                 if (!addrs) {
430                         goto done;
431                 }
432                 first = false;
433         }
434
435         if (addrs) {
436                 write(fd, addrs, talloc_get_size(addrs));
437         }
438 done:
439         if (res_list) {
440                 freeaddrinfo(res_list);
441         }
442         close(fd);
443 }
444
445 /*
446   handle a read event on the pipe
447 */
448 static void pipe_handler(struct tevent_context *ev, struct tevent_fd *fde, 
449                          uint16_t flags, void *private_data)
450 {
451         struct composite_context *c = talloc_get_type(private_data, struct composite_context);
452         struct dns_ex_state *state = talloc_get_type(c->private_data,
453                                      struct dns_ex_state);
454         char *address;
455         uint32_t num_addrs, i;
456         char **addrs;
457         int ret;
458         int status;
459         int value = 0;
460
461         /* if we get any event from the child then we know that we
462            won't need to kill it off */
463         talloc_set_destructor(state, NULL);
464
465         if (ioctl(state->child_fd, FIONREAD, &value) != 0) {
466                 value = 8192;
467         }
468
469         address = talloc_array(state, char, value+1);
470         if (address) {
471                 /* yes, we don't care about EAGAIN or other niceities
472                    here. They just can't happen with this parent/child
473                    relationship, and even if they did then giving an error is
474                    the right thing to do */
475                 ret = read(state->child_fd, address, value);
476         } else {
477                 ret = -1;
478         }
479         if (waitpid(state->child, &status, WNOHANG) == 0) {
480                 kill(state->child, SIGKILL);
481                 waitpid(state->child, &status, 0);
482         }
483
484         if (ret <= 0) {
485                 /* The check for ret == 0 here is important, if the
486                  * name does not exist, then no bytes are written to
487                  * the pipe */
488                 DEBUG(3,("dns child failed to find name '%s' of type %s\n",
489                          state->name.name, (state->flags & RESOLVE_NAME_FLAG_DNS_SRV)?"SRV":"A"));
490                 composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
491                 return;
492         }
493
494         /* enusre the address looks good */
495         address[ret] = 0;
496
497         addrs = str_list_make(state, address, ",");
498         if (composite_nomem(addrs, c)) return;
499
500         num_addrs = str_list_length((const char * const *)addrs);
501
502         state->addrs = talloc_array(state, struct socket_address *,
503                                     num_addrs+1);
504         if (composite_nomem(state->addrs, c)) return;
505
506         state->names = talloc_array(state, char *, num_addrs+1);
507         if (composite_nomem(state->names, c)) return;
508
509         for (i=0; i < num_addrs; i++) {
510                 uint32_t port = 0;
511                 char *p = strrchr(addrs[i], '@');
512                 char *n;
513
514                 if (!p) {
515                         composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
516                         return;
517                 }
518
519                 *p = '\0';
520                 p++;
521
522                 n = strrchr(p, '/');
523                 if (!n) {
524                         composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
525                         return;
526                 }
527
528                 *n = '\0';
529                 n++;
530
531                 if (strcmp(addrs[i], "0.0.0.0") == 0) {
532                         composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
533                         return;
534                 }
535                 port = strtoul(p, NULL, 10);
536                 if (port > UINT16_MAX) {
537                         composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
538                         return;
539                 }
540                 state->addrs[i] = socket_address_from_strings(state->addrs,
541                                                               "ip",
542                                                               addrs[i],
543                                                               port);
544                 if (composite_nomem(state->addrs[i], c)) return;
545
546                 state->names[i] = talloc_strdup(state->names, n);
547                 if (composite_nomem(state->names[i], c)) return;
548         }
549         state->addrs[i] = NULL;
550         state->names[i] = NULL;
551
552         composite_done(c);
553 }
554
555 /*
556   getaddrinfo() or dns_lookup() name resolution method - async send
557  */
558 struct composite_context *resolve_name_dns_ex_send(TALLOC_CTX *mem_ctx,
559                                                    struct tevent_context *event_ctx,
560                                                    void *privdata,
561                                                    uint32_t flags,
562                                                    uint16_t port,
563                                                    struct nbt_name *name,
564                                                    bool do_fallback)
565 {
566         struct composite_context *c;
567         struct dns_ex_state *state;
568         int fd[2] = { -1, -1 };
569         int ret;
570
571         c = composite_create(mem_ctx, event_ctx);
572         if (c == NULL) return NULL;
573
574         if (flags & RESOLVE_NAME_FLAG_FORCE_NBT) {
575                 composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
576                 return c;
577         }
578
579         state = talloc_zero(c, struct dns_ex_state);
580         if (composite_nomem(state, c)) return c;
581         c->private_data = state;
582
583         c->status = nbt_name_dup(state, name, &state->name);
584         if (!composite_is_ok(c)) return c;
585
586         /* setup a pipe to chat to our child */
587         ret = pipe(fd);
588         if (ret == -1) {
589                 composite_error(c, map_nt_error_from_unix_common(errno));
590                 return c;
591         }
592
593         state->do_fallback = do_fallback;
594         state->flags = flags;
595         state->port = port;
596
597         state->child_fd = fd[0];
598         state->event_ctx = c->event_ctx;
599
600         /* we need to put the child in our event context so
601            we know when the dns_lookup() has finished */
602         state->fde = tevent_add_fd(c->event_ctx, c, state->child_fd, TEVENT_FD_READ,
603                                   pipe_handler, c);
604         if (composite_nomem(state->fde, c)) {
605                 close(fd[0]);
606                 close(fd[1]);
607                 return c;
608         }
609         tevent_fd_set_auto_close(state->fde);
610
611         state->child = fork();
612         if (state->child == (pid_t)-1) {
613                 composite_error(c, map_nt_error_from_unix_common(errno));
614                 return c;
615         }
616
617         if (state->child == 0) {
618                 close(fd[0]);
619                 if (state->flags & RESOLVE_NAME_FLAG_FORCE_DNS) {
620                         run_child_dns_lookup(state, fd[1]);
621                 } else {
622                         run_child_getaddrinfo(state, fd[1]);
623                 }
624                 _exit(0);
625         }
626         close(fd[1]);
627
628         /* cleanup wayward children */
629         talloc_set_destructor(state, dns_ex_destructor);
630
631         return c;
632 }
633
634 /*
635   getaddrinfo() or dns_lookup() name resolution method - recv side
636 */
637 NTSTATUS resolve_name_dns_ex_recv(struct composite_context *c, 
638                                   TALLOC_CTX *mem_ctx,
639                                   struct socket_address ***addrs,
640                                   char ***names)
641 {
642         NTSTATUS status;
643
644         status = composite_wait(c);
645
646         if (NT_STATUS_IS_OK(status)) {
647                 struct dns_ex_state *state = talloc_get_type(c->private_data,
648                                              struct dns_ex_state);
649                 *addrs = talloc_steal(mem_ctx, state->addrs);
650                 if (names) {
651                         *names = talloc_steal(mem_ctx, state->names);
652                 }
653         }
654
655         talloc_free(c);
656         return status;
657 }