s4:libcli: use tevent_ fn names instead of legacy event_ ones
[ambi/samba-autobuild/.git] / source4 / libcli / resolve / dns_ex.c
index 79ed78340c4b471c6baeae24d7efd38ab9ad1172..8f21b7fde527ae1a9448a2a7ae6f7e1f3148f5aa 100644 (file)
@@ -37,6 +37,7 @@
 #include "libcli/composite/composite.h"
 #include "librpc/gen_ndr/ndr_nbt.h"
 #include "libcli/resolve/resolve.h"
+#include "lib/util/util_net.h"
 
 #ifdef class
 #undef class
@@ -67,7 +68,6 @@ static int dns_ex_destructor(struct dns_ex_state *state)
        int status;
 
        kill(state->child, SIGTERM);
-       close(state->child_fd);
        if (waitpid(state->child, &status, WNOHANG) == 0) {
                kill(state->child, SIGKILL);
                waitpid(state->child, &status, 0);
@@ -88,11 +88,21 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
        struct rk_resource_record **srv_rr;
        uint32_t addrs_valid = 0;
        struct rk_resource_record **addrs_rr;
+       struct rk_dns_reply **srv_replies = NULL;
        char *addrs;
        bool first;
        uint32_t i;
        bool do_srv = (state->flags & RESOLVE_NAME_FLAG_DNS_SRV);
 
+       if (strchr(state->name.name, '.') && state->name.name[strlen(state->name.name)-1] != '.') {
+               /* we are asking for a fully qualified name, but the
+                  name doesn't end in a '.'. We need to prevent the
+                  DNS library trying the search domains configured in
+                  resolv.conf */
+               state->name.name = talloc_strdup_append(discard_const_p(char, state->name.name),
+                                                       ".");
+       }
+
        /* this is the blocking call we are going to lots of trouble
           to avoid in the parent */
        reply = rk_dns_lookup(state->name.name, do_srv?"SRV":"A");
@@ -127,14 +137,13 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
                                continue;
                        }
                } else {
-                       /* we are only interested in A records */
-                       /* TODO: add AAAA support */
-                       if (rr->type != rk_ns_t_a) {
+                       /* we are only interested in A or AAAA records */
+                       if (rr->type != rk_ns_t_a && rr->type != rk_ns_t_aaaa) {
                                continue;
                        }
 
-                       /* verify we actually have a record here */
-                       if (!rr->u.a) {
+                       /* verify we actually have a record here */
+                       if (!rr->u.data) {
                                continue;
                        }
                }
@@ -159,6 +168,13 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
                goto done;
        }
 
+       srv_replies = talloc_zero_array(state,
+                                       struct rk_dns_reply *,
+                                       count);
+       if (!srv_replies) {
+               goto done;
+       }
+
        /* Loop over all returned records and pick the records */
        for (rr=reply->head;rr;rr=rr->next) {
                /* we are only interested in the IN class */
@@ -168,7 +184,7 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
 
                if (do_srv) {
                        /* we are only interested in SRV records */
-                       if (rr->type != rk_ns_c_in) {
+                       if (rr->type != rk_ns_t_srv) {
                                continue;
                        }
 
@@ -185,14 +201,13 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
                        srv_rr[srv_valid] = rr;
                        srv_valid++;
                } else {
-                       /* we are only interested in A records */
-                       /* TODO: add AAAA support */
-                       if (rr->type != rk_ns_t_a) {
+                       /* we are only interested in A or AAAA records */
+                       if (rr->type != rk_ns_t_a && rr->type != rk_ns_t_aaaa) {
                                continue;
                        }
 
-                       /* verify we actually have a A record here */
-                       if (!rr->u.a) {
+                       /* verify we actually have a record record here */
+                       if (!rr->u.data) {
                                continue;
                        }
 
@@ -202,19 +217,23 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
        }
 
        for (i=0; i < srv_valid; i++) {
-               for (rr=reply->head;rr;rr=rr->next) {
+               srv_replies[i] = rk_dns_lookup(srv_rr[i]->u.srv->target, "A");
+               if (srv_replies[i] == NULL)
+                       continue;
 
+               /* Add first A record to addrs_rr */
+               for (rr=srv_replies[i]->head;rr;rr=rr->next) {
                        if (rr->class != rk_ns_c_in) {
                                continue;
                        }
 
-                       /* we are only interested in SRV records */
-                       if (rr->type != rk_ns_t_a) {
+                       /* we are only interested in A or AAAA records */
+                       if (rr->type != rk_ns_t_a && rr->type != rk_ns_t_aaaa) {
                                continue;
                        }
 
-                       /* verify we actually have a srv record here */
-                       if (strcmp(&srv_rr[i]->u.srv->target[0], rr->domain) != 0) {
+                       /* verify we actually have a record here */
+                       if (!rr->u.data) {
                                continue;
                        }
 
@@ -233,8 +252,10 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
                goto done;
        }
        first = true;
-       for (i=0; i < count; i++) {
+       for (i=0; i < addrs_valid; i++) {
                uint16_t port;
+               char addrstr[INET6_ADDRSTRLEN];
+
                if (!addrs_rr[i]) {
                        continue;
                }
@@ -246,9 +267,28 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
                        port = state->port;
                }
 
-               addrs = talloc_asprintf_append_buffer(addrs, "%s%s:%u/%s",
+               switch (addrs_rr[i]->type) {
+               case rk_ns_t_a:
+                       if (inet_ntop(AF_INET, addrs_rr[i]->u.a,
+                                     addrstr, sizeof(addrstr)) == NULL) {
+                               continue;
+                       }
+                       break;
+#ifdef HAVE_IPV6
+               case rk_ns_t_aaaa:
+                       if (inet_ntop(AF_INET6, (struct in6_addr *)addrs_rr[i]->u.data,
+                                     addrstr, sizeof(addrstr)) == NULL) {
+                               continue;
+                       }
+                       break;
+#endif
+               default:
+                       continue;
+               }
+
+               addrs = talloc_asprintf_append_buffer(addrs, "%s%s@%u/%s",
                                                      first?"":",",
-                                                     inet_ntoa(*addrs_rr[i]->u.a),
+                                                     addrstr,
                                                      port,
                                                      addrs_rr[i]->domain);
                if (!addrs) {
@@ -262,6 +302,12 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
        }
 
 done:
+       if (reply != NULL)
+               rk_dns_free_data(reply);
+       for (i=0; i < srv_valid; i++) {
+               if (srv_replies[i] != NULL)
+                       rk_dns_free_data(srv_replies[i]);
+       }
        close(fd);
 }
 
@@ -279,7 +325,6 @@ static void run_child_getaddrinfo(struct dns_ex_state *state, int fd)
 
        ZERO_STRUCT(hints);
        hints.ai_socktype = SOCK_STREAM;
-       hints.ai_family = AF_INET;/* TODO: add AF_INET6 support */
        hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
 
        ret = getaddrinfo(state->name.name, "0", &hints, &res_list);
@@ -307,16 +352,13 @@ static void run_child_getaddrinfo(struct dns_ex_state *state, int fd)
        }
        first = true;
        for (res = res_list; res; res = res->ai_next) {
-               struct sockaddr_in *in;
-
-               if (res->ai_family != AF_INET) {
+               char addrstr[INET6_ADDRSTRLEN];
+               if (!print_sockaddr_len(addrstr, sizeof(addrstr), (struct sockaddr *)res->ai_addr, res->ai_addrlen)) {
                        continue;
                }
-               in = (struct sockaddr_in *)res->ai_addr;
-
-               addrs = talloc_asprintf_append_buffer(addrs, "%s%s:%u/%s",
+               addrs = talloc_asprintf_append_buffer(addrs, "%s%s@%u/%s",
                                                      first?"":",",
-                                                     inet_ntoa(in->sin_addr),
+                                                     addrstr,
                                                      state->port,
                                                      state->name.name);
                if (!addrs) {
@@ -369,7 +411,6 @@ static void pipe_handler(struct tevent_context *ev, struct tevent_fd *fde,
        } else {
                ret = -1;
        }
-       close(state->child_fd);
        if (waitpid(state->child, &status, WNOHANG) == 0) {
                kill(state->child, SIGKILL);
                waitpid(state->child, &status, 0);
@@ -399,7 +440,7 @@ static void pipe_handler(struct tevent_context *ev, struct tevent_fd *fde,
 
        for (i=0; i < num_addrs; i++) {
                uint32_t port = 0;
-               char *p = strrchr(addrs[i], ':');
+               char *p = strrchr(addrs[i], '@');
                char *n;
 
                if (!p) {
@@ -419,8 +460,7 @@ static void pipe_handler(struct tevent_context *ev, struct tevent_fd *fde,
                *n = '\0';
                n++;
 
-               if (strcmp(addrs[i], "0.0.0.0") == 0 ||
-                   inet_addr(addrs[i]) == INADDR_NONE) {
+               if (strcmp(addrs[i], "0.0.0.0") == 0) {
                        composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
                        return;
                }
@@ -430,7 +470,7 @@ static void pipe_handler(struct tevent_context *ev, struct tevent_fd *fde,
                        return;
                }
                state->addrs[i] = socket_address_from_strings(state->addrs,
-                                                             "ipv4",
+                                                             "ip",
                                                              addrs[i],
                                                              port);
                if (composite_nomem(state->addrs[i], c)) return;
@@ -478,7 +518,7 @@ struct composite_context *resolve_name_dns_ex_send(TALLOC_CTX *mem_ctx,
        /* setup a pipe to chat to our child */
        ret = pipe(fd);
        if (ret == -1) {
-               composite_error(c, map_nt_error_from_unix(errno));
+               composite_error(c, map_nt_error_from_unix_common(errno));
                return c;
        }
 
@@ -491,17 +531,18 @@ struct composite_context *resolve_name_dns_ex_send(TALLOC_CTX *mem_ctx,
 
        /* we need to put the child in our event context so
           we know when the dns_lookup() has finished */
-       state->fde = event_add_fd(c->event_ctx, c, state->child_fd, EVENT_FD_READ, 
+       state->fde = tevent_add_fd(c->event_ctx, c, state->child_fd, TEVENT_FD_READ,
                                  pipe_handler, c);
        if (composite_nomem(state->fde, c)) {
                close(fd[0]);
                close(fd[1]);
                return c;
        }
+       tevent_fd_set_auto_close(state->fde);
 
        state->child = fork();
        if (state->child == (pid_t)-1) {
-               composite_error(c, map_nt_error_from_unix(errno));
+               composite_error(c, map_nt_error_from_unix_common(errno));
                return c;
        }