s4-dns-ex: use autoclose on the dns child pipe
[ira/wip.git] / source4 / libcli / resolve / dns_ex.c
index 5f08201978afd33d5325c3ac59584d0527465c9f..423668d4b6cbd1e21b05cec6f2f850926a6051a6 100644 (file)
 #include "libcli/composite/composite.h"
 #include "librpc/gen_ndr/ndr_nbt.h"
 #include "libcli/resolve/resolve.h"
+
+#ifdef class
+#undef class
+#endif
+
 #include "heimdal/lib/roken/resolve.h"
 
 struct dns_ex_state {
-       bool do_getaddrinfo;
        bool do_fallback;
-       bool do_srv;
        uint32_t flags;
        uint16_t port;
        struct nbt_name name;
@@ -50,8 +53,8 @@ struct dns_ex_state {
        char **names;
        pid_t child;
        int child_fd;
-       struct fd_event *fde;
-       struct event_context *event_ctx;
+       struct tevent_fd *fde;
+       struct tevent_context *event_ctx;
 };
 
 /*
@@ -64,7 +67,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);
@@ -78,38 +80,39 @@ static int dns_ex_destructor(struct dns_ex_state *state)
 */
 static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
 {
-       struct dns_reply *reply;
-       struct resource_record *rr;
+       struct rk_dns_reply *reply;
+       struct rk_resource_record *rr;
        uint32_t count = 0;
        uint32_t srv_valid = 0;
-       struct resource_record **srv_rr;
+       struct rk_resource_record **srv_rr;
        uint32_t addrs_valid = 0;
-       struct resource_record **addrs_rr;
+       struct rk_resource_record **addrs_rr;
        char *addrs;
        bool first;
        uint32_t i;
+       bool do_srv = (state->flags & RESOLVE_NAME_FLAG_DNS_SRV);
 
        /* this is the blocking call we are going to lots of trouble
           to avoid in the parent */
-       reply = dns_lookup(state->name.name, state->do_srv?"SRV":"A");
+       reply = rk_dns_lookup(state->name.name, do_srv?"SRV":"A");
        if (!reply) {
                goto done;
        }
 
-       if (state->do_srv) {
-               dns_srv_order(reply);
+       if (do_srv) {
+               rk_dns_srv_order(reply);
        }
 
        /* Loop over all returned records and pick the "srv" records */
        for (rr=reply->head; rr; rr=rr->next) {
                /* we are only interested in the IN class */
-               if (rr->class != C_IN) {
+               if (rr->class != rk_ns_c_in) {
                        continue;
                }
 
-               if (state->do_srv) {
+               if (do_srv) {
                        /* we are only interested in SRV records */
-                       if (rr->type != T_SRV) {
+                       if (rr->type != rk_ns_t_srv) {
                                continue;
                        }
 
@@ -125,7 +128,7 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
                } else {
                        /* we are only interested in A records */
                        /* TODO: add AAAA support */
-                       if (rr->type != T_A) {
+                       if (rr->type != rk_ns_t_a) {
                                continue;
                        }
 
@@ -142,14 +145,14 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
        }
 
        srv_rr = talloc_zero_array(state,
-                                  struct resource_record *,
+                                  struct rk_resource_record *,
                                   count);
        if (!srv_rr) {
                goto done;
        }
 
        addrs_rr = talloc_zero_array(state,
-                                    struct resource_record *,
+                                    struct rk_resource_record *,
                                     count);
        if (!addrs_rr) {
                goto done;
@@ -158,13 +161,13 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
        /* 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 */
-               if (rr->class != C_IN) {
+               if (rr->class != rk_ns_c_in) {
                        continue;
                }
 
-               if (state->do_srv) {
+               if (do_srv) {
                        /* we are only interested in SRV records */
-                       if (rr->type != T_SRV) {
+                       if (rr->type != rk_ns_c_in) {
                                continue;
                        }
 
@@ -183,7 +186,7 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
                } else {
                        /* we are only interested in A records */
                        /* TODO: add AAAA support */
-                       if (rr->type != T_A) {
+                       if (rr->type != rk_ns_t_a) {
                                continue;
                        }
 
@@ -200,12 +203,12 @@ 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) {
 
-                       if (rr->class != C_IN) {
+                       if (rr->class != rk_ns_c_in) {
                                continue;
                        }
 
                        /* we are only interested in SRV records */
-                       if (rr->type != T_A) {
+                       if (rr->type != rk_ns_t_a) {
                                continue;
                        }
 
@@ -230,13 +233,22 @@ static void run_child_dns_lookup(struct dns_ex_state *state, int fd)
        }
        first = true;
        for (i=0; i < count; i++) {
+               uint16_t port;
                if (!addrs_rr[i]) {
                        continue;
                }
+
+               if (srv_rr[i] &&
+                   (state->flags & RESOLVE_NAME_FLAG_OVERWRITE_PORT)) {
+                       port = srv_rr[i]->u.srv->port;
+               } else {
+                       port = state->port;
+               }
+
                addrs = talloc_asprintf_append_buffer(addrs, "%s%s:%u/%s",
                                                      first?"":",",
                                                      inet_ntoa(*addrs_rr[i]->u.a),
-                                                     state->port,
+                                                     port,
                                                      addrs_rr[i]->domain);
                if (!addrs) {
                        goto done;
@@ -270,10 +282,19 @@ static void run_child_getaddrinfo(struct dns_ex_state *state, int fd)
        hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
 
        ret = getaddrinfo(state->name.name, "0", &hints, &res_list);
-       if (ret == EAI_NODATA && state->do_fallback) {
-               /* getaddrinfo() doesn't handle CNAME records */
-               run_child_dns_lookup(state, fd);
-               return;
+       /* try to fallback in case of error */
+       if (state->do_fallback) {
+               switch (ret) {
+#ifdef EAI_NODATA
+               case EAI_NODATA:
+#endif
+               case EAI_NONAME:
+                       /* getaddrinfo() doesn't handle CNAME records */
+                       run_child_dns_lookup(state, fd);
+                       return;
+               default:
+                       break;
+               }
        }
        if (ret != 0) {
                goto done;
@@ -316,7 +337,7 @@ done:
 /*
   handle a read event on the pipe
 */
-static void pipe_handler(struct event_context *ev, struct fd_event *fde, 
+static void pipe_handler(struct tevent_context *ev, struct tevent_fd *fde, 
                         uint16_t flags, void *private_data)
 {
        struct composite_context *c = talloc_get_type(private_data, struct composite_context);
@@ -347,13 +368,14 @@ static void pipe_handler(struct event_context *ev, struct fd_event *fde,
        } else {
                ret = -1;
        }
-       close(state->child_fd);
        if (waitpid(state->child, &status, WNOHANG) == 0) {
                kill(state->child, SIGKILL);
                waitpid(state->child, &status, 0);
        }
 
        if (ret <= 0) {
+               DEBUG(3,("dns child failed to find name '%s' of type %s\n",
+                        state->name.name, (state->flags & RESOLVE_NAME_FLAG_DNS_SRV)?"SRV":"A"));
                composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
                return;
        }
@@ -424,14 +446,12 @@ static void pipe_handler(struct event_context *ev, struct fd_event *fde,
   getaddrinfo() or dns_lookup() name resolution method - async send
  */
 struct composite_context *resolve_name_dns_ex_send(TALLOC_CTX *mem_ctx,
-                                                  struct event_context *event_ctx,
+                                                  struct tevent_context *event_ctx,
                                                   void *privdata,
                                                   uint32_t flags,
                                                   uint16_t port,
                                                   struct nbt_name *name,
-                                                  bool do_getaddrinfo,
-                                                  bool do_fallback,
-                                                  bool do_srv)
+                                                  bool do_fallback)
 {
        struct composite_context *c;
        struct dns_ex_state *state;
@@ -441,7 +461,10 @@ struct composite_context *resolve_name_dns_ex_send(TALLOC_CTX *mem_ctx,
        c = composite_create(mem_ctx, event_ctx);
        if (c == NULL) return NULL;
 
-       if (composite_nomem(c->event_ctx, c)) return c;
+       if (flags & RESOLVE_NAME_FLAG_FORCE_NBT) {
+               composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+               return c;
+       }
 
        state = talloc_zero(c, struct dns_ex_state);
        if (composite_nomem(state, c)) return c;
@@ -457,9 +480,7 @@ struct composite_context *resolve_name_dns_ex_send(TALLOC_CTX *mem_ctx,
                return c;
        }
 
-       state->do_getaddrinfo = do_getaddrinfo;
        state->do_fallback = do_fallback;
-       state->do_srv = do_srv;
        state->flags = flags;
        state->port = port;
 
@@ -475,6 +496,7 @@ struct composite_context *resolve_name_dns_ex_send(TALLOC_CTX *mem_ctx,
                close(fd[1]);
                return c;
        }
+       tevent_fd_set_auto_close(state->fde);
 
        state->child = fork();
        if (state->child == (pid_t)-1) {
@@ -484,10 +506,10 @@ struct composite_context *resolve_name_dns_ex_send(TALLOC_CTX *mem_ctx,
 
        if (state->child == 0) {
                close(fd[0]);
-               if (state->do_getaddrinfo) {
-                       run_child_getaddrinfo(state, fd[1]);
-               } else {
+               if (state->flags & RESOLVE_NAME_FLAG_FORCE_DNS) {
                        run_child_dns_lookup(state, fd[1]);
+               } else {
+                       run_child_getaddrinfo(state, fd[1]);
                }
                _exit(0);
        }