WIP: libdns: Also do TCP requests
authorKai Blin <kai@samba.org>
Tue, 3 Apr 2012 06:00:57 +0000 (08:00 +0200)
committerKai Blin <kai@samba.org>
Tue, 8 May 2012 08:05:39 +0000 (10:05 +0200)
libcli/dns/dns.c
libcli/dns/libdns.h

index ac0c9e4995954bf89dafbeb02f629f04214eadee..ea0975d3f7bd3665dbdfabf654cd32ba4f676ad1 100644 (file)
@@ -39,8 +39,8 @@ struct dns_udp_request_state {
 };
 
 /* Declare callback functions used below. */
-static void dns_request_get_reply(struct tevent_req *subreq);
-static void dns_request_done(struct tevent_req *subreq);
+static void dns_udp_request_get_reply(struct tevent_req *subreq);
+static void dns_udp_request_done(struct tevent_req *subreq);
 
 struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
@@ -92,11 +92,11 @@ struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
-       tevent_req_set_callback(subreq, dns_request_get_reply, req);
+       tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
        return req;
 }
 
-static void dns_request_get_reply(struct tevent_req *subreq)
+static void dns_udp_request_get_reply(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(subreq,
                                                struct tevent_req);
@@ -123,6 +123,167 @@ static void dns_request_get_reply(struct tevent_req *subreq)
                return;
        }
 
+       tevent_req_set_callback(subreq, dns_udp_request_done, req);
+       return;
+}
+
+static void dns_udp_request_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(subreq,
+                                               struct tevent_req);
+       struct dns_udp_request_state *state = tevent_req_data(req,
+                                               struct dns_udp_request_state);
+
+       ssize_t len;
+       int err = 0;
+
+       len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
+       TALLOC_FREE(subreq);
+
+       if (len == -1 && err != 0) {
+               tevent_req_werror(req, unix_to_werror(err));
+               return;
+       }
+
+       state->reply_len = len;
+       dump_data(10, state->reply, state->reply_len);
+       tevent_req_done(req);
+}
+
+WERROR dns_udp_request_recv(struct tevent_req *req,
+                           TALLOC_CTX *mem_ctx,
+                           uint8_t **reply,
+                           size_t *reply_len)
+{
+       struct dns_udp_request_state *state = tevent_req_data(req,
+                       struct dns_udp_request_state);
+       WERROR w_error;
+
+       if (tevent_req_is_werror(req, &w_error)) {
+               tevent_req_received(req);
+               return w_error;
+       }
+
+       *reply = talloc_move(mem_ctx, &state->reply);
+       *reply_len = state->reply_len;
+       tevent_req_received(req);
+
+       return WERR_OK;
+}
+
+struct dns_tcp_request_state {
+       struct tevent_context *ev;
+       struct tstream_context *stream;
+       const uint8_t *query;
+       size_t query_len;
+       uint8_t *reply;
+       size_t reply_len;
+};
+
+static void dns_tcp_request_connected(struct tevent_req *subreq);
+static void dns_tcp_request_get_reply(struct tevent_req *subreq);
+static void dns_tcp_request_done(struct tevent_req *subreq);
+
+struct tevent_req *dns_tcp_request_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       const char *server_addr_string,
+                                       const uint8_t *query,
+                                       size_t query_len)
+{
+       struct tevent_req *req, *subreq;
+       struct dns_tcp_request_state *state;
+       struct tsocket_address *local_addr, *server_addr;
+       struct tstream_context *stream;
+       int ret;
+
+       req = tevent_req_create(mem_ctx, &state, struct dns_tcp_request_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->ev = ev;
+       state->query = query;
+       state->query_len = query_len;
+
+       dump_data(10, query, query_len);
+
+       ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
+                                               &local_addr);
+       if (ret != 0) {
+               tevent_req_werror(req, unix_to_werror(ret));
+               return tevent_req_post(req, ev);
+       }
+
+       ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
+                                               DNS_SERVICE_PORT, &server_addr);
+       if (ret != 0) {
+               tevent_req_werror(req, unix_to_werror(ret));
+               return tevent_req_post(req, ev);
+       }
+
+       subreq = tstream_inet_tcp_connect_send(state, ev, local_addr, server_addr);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       tevent_req_set_callback(subreq, dns_tcp_request_connected, req);
+       return req;
+}
+
+static void dns_tcp_request_connected(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(subreq,
+                                               struct tevent_req);
+       struct dns_udp_request_state *state = tevent_req_data(req,
+                                               struct dns_udp_request_state);
+
+       int ret;
+       int err = 0;
+
+       ret = tstream_inet_tcp_connect_recv(subreq, &err, state, &state->stream,
+                                           NULL);
+       TALLOC_FREE(subreq);
+       if (ret != 0) {
+               tevent_req_error(req, unix_to_werror(err));
+               return;
+       }
+
+       subreq = tstream_sendto_send(state, ev, stream, query, query_len, NULL);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       tevent_req_set_callback(subreq, dns_request_get_reply, req);
+       return;
+}
+
+static void dns_request_get_reply(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(subreq,
+                                               struct tevent_req);
+       struct dns_udp_request_state *state = tevent_req_data(req,
+                                               struct dns_udp_request_state);
+       ssize_t len;
+       int err = 0;
+
+       len = tstream_sendto_recv(subreq, &err);
+       TALLOC_FREE(subreq);
+
+       if (len == -1 && err != 0) {
+               tevent_req_werror(req, unix_to_werror(err));
+               return;
+       }
+
+       if (len != state->query_len) {
+               tevent_req_werror(req, WERR_NET_WRITE_FAULT);
+               return;
+       }
+
+       subreq = tstream_recvfrom_send(state, state->ev, state->stream);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+
        tevent_req_set_callback(subreq, dns_request_done, req);
        return;
 }
@@ -137,7 +298,7 @@ static void dns_request_done(struct tevent_req *subreq)
        ssize_t len;
        int err = 0;
 
-       len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
+       len = tstream_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
        TALLOC_FREE(subreq);
 
        if (len == -1 && err != 0) {
index 31474ebc530279075f728f6b3b6bf860c4967274..ca2788f3378694d57d4aa3abb8dae9843a5cd2d1 100644 (file)
@@ -50,4 +50,32 @@ WERROR dns_udp_request_recv(struct tevent_req *req,
                            uint8_t **reply,
                            size_t *reply_len);
 
+/** Send an dns request to a dns server using TCP
+ *
+ *@param mem_ctx        talloc memory context to use
+ *@param ev             tevent context to use
+ *@param server_address address of the server as a string
+ *@param query          dns query to send
+ *@param query_len      length of the query
+ *@return tevent_req with the active request or NULL on out-of-memory
+ */
+struct tevent_req *dns_tcp_request_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       const char *server_address,
+                                       const uint8_t *query,
+                                       size_t query_len);
+
+/** Get the dns response from a dns server via UDP
+ *
+ *@param req       tevent_req struct returned from dns_request_send
+ *@param mem_ctx   talloc memory context to use for the reply string
+ *@param reply     buffer that will be allocated and filled with the dns reply
+ *@param reply_len length of the reply buffer
+ *@return WERROR code depending on the async request result
+ */
+WERROR dns_tcp_request_recv(struct tevent_req *req,
+                           TALLOC_CTX *mem_ctx,
+                           uint8_t **reply,
+                           size_t *reply_len);
+
 #endif /*__LIBDNS_H__*/