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