s4:kdc: split the kdc_tcp_proxy() logic from the main kdc logic
authorStefan Metzmacher <metze@samba.org>
Wed, 9 Feb 2011 11:17:23 +0000 (12:17 +0100)
committerStefan Metzmacher <metze@samba.org>
Fri, 4 Mar 2011 20:19:05 +0000 (21:19 +0100)
By having kdc_tcp_proxy_send/recv(), which just asks any writeable
dc for a reponse blob, we simplify the interaction between
client-local and local-writeable sockets.

This allows us to make kdc_socket, kdc_process_fn_t, kdc_tcp_call and kdc_tcp_socket
private to kdc.c again.

metze

source4/kdc/kdc-glue.h
source4/kdc/kdc.c
source4/kdc/proxy.c

index f9489b1fd16dcef635bedfbaa1d293f8ca78b1fe..b365cd75c6a0c9c7ccb34c29b121fb7b5329c3f0 100644 (file)
@@ -50,46 +50,6 @@ enum kdc_process_ret {
        KDC_PROCESS_FAILED,
        KDC_PROCESS_PROXY};
 
-struct kdc_tcp_call {
-       struct kdc_tcp_connection *kdc_conn;
-       DATA_BLOB in;
-       DATA_BLOB out;
-       uint8_t out_hdr[4];
-       struct iovec out_iov[2];
-};
-
-typedef enum kdc_process_ret (*kdc_process_fn_t)(struct kdc_server *kdc,
-                                                TALLOC_CTX *mem_ctx,
-                                                DATA_BLOB *input,
-                                                DATA_BLOB *reply,
-                                                struct tsocket_address *peer_addr,
-                                                struct tsocket_address *my_addr,
-                                                int datagram);
-
-
-/* hold information about one kdc socket */
-struct kdc_socket {
-       struct kdc_server *kdc;
-       struct tsocket_address *local_address;
-       kdc_process_fn_t process;
-};
-
-/*
-  state of an open tcp connection
-*/
-struct kdc_tcp_connection {
-       /* stream connection we belong to */
-       struct stream_connection *conn;
-
-       /* the kdc_server the connection belongs to */
-       struct kdc_socket *kdc_socket;
-
-       struct tstream_context *tstream;
-
-       struct tevent_queue *send_queue;
-};
-
-
 enum kdc_process_ret kpasswdd_process(struct kdc_server *kdc,
                                      TALLOC_CTX *mem_ctx,
                                      DATA_BLOB *input,
@@ -112,7 +72,13 @@ NTSTATUS kdc_udp_proxy_recv(struct tevent_req *req,
                            TALLOC_CTX *mem_ctx,
                            DATA_BLOB *out);
 
-void kdc_tcp_proxy(struct kdc_server *kdc, struct kdc_tcp_connection *kdc_conn,
-                  struct kdc_tcp_call *call, uint16_t port);
+struct tevent_req *kdc_tcp_proxy_send(TALLOC_CTX *mem_ctx,
+                                     struct tevent_context *ev,
+                                     struct kdc_server *kdc,
+                                     uint16_t port,
+                                     DATA_BLOB in);
+NTSTATUS kdc_tcp_proxy_recv(struct tevent_req *req,
+                           TALLOC_CTX *mem_ctx,
+                           DATA_BLOB *out);
 
 #endif
index 05c1d9c40d527641ec2fdc8a5f2c8f3189a7513c..26365acc7c0b4ffa22fee238f9185eddc0e5599d 100644 (file)
@@ -62,6 +62,45 @@ static NTSTATUS kdc_proxy_unavailable_error(struct kdc_server *kdc,
        return NT_STATUS_OK;
 }
 
+typedef enum kdc_process_ret (*kdc_process_fn_t)(struct kdc_server *kdc,
+                                                TALLOC_CTX *mem_ctx,
+                                                DATA_BLOB *input,
+                                                DATA_BLOB *reply,
+                                                struct tsocket_address *peer_addr,
+                                                struct tsocket_address *my_addr,
+                                                int datagram);
+
+/* hold information about one kdc socket */
+struct kdc_socket {
+       struct kdc_server *kdc;
+       struct tsocket_address *local_address;
+       kdc_process_fn_t process;
+};
+
+struct kdc_tcp_call {
+       struct kdc_tcp_connection *kdc_conn;
+       DATA_BLOB in;
+       DATA_BLOB out;
+       uint8_t out_hdr[4];
+       struct iovec out_iov[2];
+};
+
+/*
+  state of an open tcp connection
+*/
+struct kdc_tcp_connection {
+       /* stream connection we belong to */
+       struct stream_connection *conn;
+
+       /* the kdc_server the connection belongs to */
+       struct kdc_socket *kdc_socket;
+
+       struct tstream_context *tstream;
+
+       struct tevent_queue *send_queue;
+};
+
+
 static void kdc_tcp_terminate_connection(struct kdc_tcp_connection *kdcconn, const char *reason)
 {
        stream_terminate_connection(kdcconn->conn, reason);
@@ -143,6 +182,7 @@ static enum kdc_process_ret kdc_process(struct kdc_server *kdc,
        return KDC_PROCESS_OK;
 }
 
+static void kdc_tcp_call_proxy_done(struct tevent_req *subreq);
 static void kdc_tcp_call_writev_done(struct tevent_req *subreq);
 
 static void kdc_tcp_call_loop(struct tevent_req *subreq)
@@ -202,14 +242,94 @@ static void kdc_tcp_call_loop(struct tevent_req *subreq)
        }
 
        if (ret == KDC_PROCESS_PROXY) {
+               uint16_t port;
+
                if (!kdc_conn->kdc_socket->kdc->am_rodc) {
                        kdc_tcp_terminate_connection(kdc_conn,
                                                     "kdc_tcp_call_loop: proxying requested when not RODC");
                        return;
                }
-               kdc_tcp_proxy(kdc_conn->kdc_socket->kdc, kdc_conn, call,
-                             tsocket_address_inet_port(kdc_conn->conn->local_address));
-               goto done;
+               port = tsocket_address_inet_port(kdc_conn->conn->local_address);
+
+               subreq = kdc_tcp_proxy_send(call,
+                                           kdc_conn->conn->event.ctx,
+                                           kdc_conn->kdc_socket->kdc,
+                                           port,
+                                           call->in);
+               if (subreq == NULL) {
+                       kdc_tcp_terminate_connection(kdc_conn,
+                               "kdc_tcp_call_loop: kdc_tcp_proxy_send failed");
+                       return;
+               }
+               tevent_req_set_callback(subreq, kdc_tcp_call_proxy_done, call);
+               return;
+       }
+
+       /* First add the length of the out buffer */
+       RSIVAL(call->out_hdr, 0, call->out.length);
+       call->out_iov[0].iov_base = (char *) call->out_hdr;
+       call->out_iov[0].iov_len = 4;
+
+       call->out_iov[1].iov_base = (char *) call->out.data;
+       call->out_iov[1].iov_len = call->out.length;
+
+       subreq = tstream_writev_queue_send(call,
+                                          kdc_conn->conn->event.ctx,
+                                          kdc_conn->tstream,
+                                          kdc_conn->send_queue,
+                                          call->out_iov, 2);
+       if (subreq == NULL) {
+               kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: "
+                               "no memory for tstream_writev_queue_send");
+               return;
+       }
+       tevent_req_set_callback(subreq, kdc_tcp_call_writev_done, call);
+
+       /*
+        * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
+        * packet_full_request_u32 provides the pdu length then.
+        */
+       subreq = tstream_read_pdu_blob_send(kdc_conn,
+                                           kdc_conn->conn->event.ctx,
+                                           kdc_conn->tstream,
+                                           4, /* initial_read_size */
+                                           packet_full_request_u32,
+                                           kdc_conn);
+       if (subreq == NULL) {
+               kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: "
+                               "no memory for tstream_read_pdu_blob_send");
+               return;
+       }
+       tevent_req_set_callback(subreq, kdc_tcp_call_loop, kdc_conn);
+}
+
+static void kdc_tcp_call_proxy_done(struct tevent_req *subreq)
+{
+       struct kdc_tcp_call *call = tevent_req_callback_data(subreq,
+                       struct kdc_tcp_call);
+       struct kdc_tcp_connection *kdc_conn = call->kdc_conn;
+       NTSTATUS status;
+
+       status = kdc_tcp_proxy_recv(subreq, call, &call->out);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               /* generate an error packet */
+               status = kdc_proxy_unavailable_error(kdc_conn->kdc_socket->kdc,
+                                                    call, &call->out);
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               const char *reason;
+
+               reason = talloc_asprintf(call, "kdc_tcp_call_proxy_done: "
+                                        "kdc_proxy_unavailable_error - %s",
+                                        nt_errstr(status));
+               if (!reason) {
+                       reason = "kdc_tcp_call_proxy_done: kdc_proxy_unavailable_error() failed";
+               }
+
+               kdc_tcp_terminate_connection(call->kdc_conn, reason);
+               return;
        }
 
        /* First add the length of the out buffer */
@@ -232,7 +352,6 @@ static void kdc_tcp_call_loop(struct tevent_req *subreq)
        }
        tevent_req_set_callback(subreq, kdc_tcp_call_writev_done, call);
 
-done:
        /*
         * The krb5 tcp pdu's has the length as 4 byte (initial_read_size),
         * packet_full_request_u32 provides the pdu length then.
index a11f253b26bf0c9c115d1dccaec3ac9b5ee534a5..98db956f65e89c7493517039b22c9eca0ab9d3dc 100644 (file)
@@ -324,296 +324,262 @@ NTSTATUS kdc_udp_proxy_recv(struct tevent_req *req,
 }
 
 struct kdc_tcp_proxy_state {
-       struct kdc_tcp_call *call;
-       struct kdc_tcp_connection *kdc_conn;
+       struct tevent_context *ev;
        struct kdc_server *kdc;
        uint16_t port;
-       uint32_t next_proxy;
+       DATA_BLOB in;
+       uint8_t in_hdr[4];
+       struct iovec in_iov[2];
+       DATA_BLOB out;
        char **proxy_list;
-       const char *proxy_ip;
+       uint32_t next_proxy;
+       struct {
+               struct nbt_name name;
+               const char *ip;
+               struct tstream_context *stream;
+       } proxy;
 };
 
-static void kdc_tcp_next_proxy(struct kdc_tcp_proxy_state *state);
+static void kdc_tcp_next_proxy(struct tevent_req *req);
 
-/*
-  called when the send of the proxied reply to the client is done
- */
-static void kdc_tcp_proxy_reply_done(struct tevent_req *req)
+struct tevent_req *kdc_tcp_proxy_send(TALLOC_CTX *mem_ctx,
+                                     struct tevent_context *ev,
+                                     struct kdc_server *kdc,
+                                     uint16_t port,
+                                     DATA_BLOB in)
 {
-       struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
-                                                                    struct kdc_tcp_proxy_state);
-       int ret, sys_errno;
+       struct tevent_req *req;
+       struct kdc_tcp_proxy_state *state;
+       WERROR werr;
 
-       ret = tstream_writev_queue_recv(req, &sys_errno);
-       if (ret == -1) {
-               DEBUG(4,("kdc_tcp_proxy: writev of reply gave %d : %s\n",
-                        sys_errno, strerror(sys_errno)));
+       req = tevent_req_create(mem_ctx, &state,
+                               struct kdc_tcp_proxy_state);
+       if (req == NULL) {
+               return NULL;
        }
-       talloc_free(req);
-       talloc_free(state);
-}
-
-/*
-  called when the recv of the proxied reply is done
- */
-static void kdc_tcp_proxy_recv_done(struct tevent_req *req)
-{
-       struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
-                                                                    struct kdc_tcp_proxy_state);
-       NTSTATUS status;
-
-       status = tstream_read_pdu_blob_recv(req,
-                                           state,
-                                           &state->call->out);
-       talloc_free(req);
+       state->ev = ev;
+       state->kdc  = kdc;
+       state->port = port;
+       state->in = in;
 
-       if (!NT_STATUS_IS_OK(status)) {
-               kdc_tcp_next_proxy(state);
-               return;
+       werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
+       if (!W_ERROR_IS_OK(werr)) {
+               NTSTATUS status = werror_to_ntstatus(werr);
+               tevent_req_nterror(req, status);
+               return tevent_req_post(req, ev);
        }
 
+       RSIVAL(state->in_hdr, 0, state->in.length);
+       state->in_iov[0].iov_base = (char *)state->in_hdr;
+       state->in_iov[0].iov_len = 4;
+       state->in_iov[1].iov_base = (char *)state->in.data;
+       state->in_iov[1].iov_len = state->in.length;
 
-       /* send the reply to the original caller */
-
-       state->call->out_iov[0].iov_base = (char *)state->call->out.data;
-       state->call->out_iov[0].iov_len = state->call->out.length;
-
-       req = tstream_writev_queue_send(state,
-                                       state->kdc_conn->conn->event.ctx,
-                                       state->kdc_conn->tstream,
-                                       state->kdc_conn->send_queue,
-                                       state->call->out_iov, 1);
-       if (req == NULL) {
-               kdc_tcp_next_proxy(state);
-               return;
+       kdc_tcp_next_proxy(req);
+       if (!tevent_req_is_in_progress(req)) {
+               return tevent_req_post(req, ev);
        }
 
-       tevent_req_set_callback(req, kdc_tcp_proxy_reply_done, state);
+       return req;
 }
 
-/*
-  called when the send of the proxied packet is done
- */
-static void kdc_tcp_proxy_send_done(struct tevent_req *req)
-{
-       struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
-                                                                    struct kdc_tcp_proxy_state);
-       int ret, sys_errno;
-
-       ret = tstream_writev_queue_recv(req, &sys_errno);
-       talloc_free(req);
-       if (ret == -1) {
-               kdc_tcp_next_proxy(state);
-       }
-}
+static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq);
 
 /*
-  called when we've connected to the proxy
+  try the next proxy in the list
  */
-static void kdc_tcp_proxy_connect_done(struct tevent_req *req)
+static void kdc_tcp_next_proxy(struct tevent_req *req)
 {
-       struct kdc_tcp_proxy_state *state = tevent_req_callback_data(req,
-                                                                    struct kdc_tcp_proxy_state);
-       int ret, sys_errno;
-       struct tstream_context *stream;
-       struct tevent_queue *send_queue;
-
-
-       ret = tstream_inet_tcp_connect_recv(req, &sys_errno, state, &stream, NULL);
-       talloc_free(req);
+       struct kdc_tcp_proxy_state *state =
+               tevent_req_data(req,
+               struct kdc_tcp_proxy_state);
+       const char *proxy_dnsname = state->proxy_list[state->next_proxy];
+       struct composite_context *csubreq;
 
-       if (ret != 0) {
-               kdc_tcp_next_proxy(state);
+       if (proxy_dnsname == NULL) {
+               tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
                return;
        }
 
-       RSIVAL(state->call->out_hdr, 0, state->call->in.length);
-       state->call->out_iov[0].iov_base = (char *)state->call->out_hdr;
-       state->call->out_iov[0].iov_len = 4;
-       state->call->out_iov[1].iov_base = (char *) state->call->in.data;
-       state->call->out_iov[1].iov_len = state->call->in.length;
-
-       send_queue = tevent_queue_create(state, "kdc_tcp_proxy");
-       if (send_queue == NULL) {
-               kdc_tcp_next_proxy(state);
-               return;
-       }
+       state->next_proxy++;
 
-       req = tstream_writev_queue_send(state,
-                                       state->kdc_conn->conn->event.ctx,
-                                       stream,
-                                       send_queue,
-                                       state->call->out_iov, 2);
-       if (req == NULL) {
-               kdc_tcp_next_proxy(state);
-               return;
-       }
+       /* make sure we close the socket of the last try */
+       TALLOC_FREE(state->proxy.stream);
+       ZERO_STRUCT(state->proxy);
 
-       tevent_req_set_callback(req, kdc_tcp_proxy_send_done, state);
+       make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
 
-       req = tstream_read_pdu_blob_send(state,
-                                        state->kdc_conn->conn->event.ctx,
-                                        stream,
-                                        4, /* initial_read_size */
-                                        packet_full_request_u32,
-                                        state);
-       if (req == NULL) {
-               kdc_tcp_next_proxy(state);
+       csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
+                                      state,
+                                      RESOLVE_NAME_FLAG_FORCE_DNS,
+                                      0,
+                                      &state->proxy.name,
+                                      state->ev);
+       if (tevent_req_nomem(csubreq, req)) {
                return;
        }
-
-       tevent_req_set_callback(req, kdc_tcp_proxy_recv_done, state);
-       tevent_req_set_endtime(req, state->kdc->task->event_ctx,
-                              timeval_current_ofs(state->kdc->proxy_timeout, 0));
-
+       csubreq->async.fn = kdc_tcp_proxy_resolve_done;
+       csubreq->async.private_data = req;
 }
 
+static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq);
 
-/*
-  called when name resolution for a proxy is done
- */
-static void kdc_tcp_proxy_resolve_done(struct composite_context *c)
+static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq)
 {
-       struct kdc_tcp_proxy_state *state;
+       struct tevent_req *req =
+               talloc_get_type_abort(csubreq->async.private_data,
+               struct tevent_req);
+       struct kdc_tcp_proxy_state *state =
+               tevent_req_data(req,
+               struct kdc_tcp_proxy_state);
        NTSTATUS status;
-       struct tevent_req *req;
+       struct tevent_req *subreq;
        struct tsocket_address *local_addr, *proxy_addr;
        int ret;
 
-       state = talloc_get_type(c->async.private_data, struct kdc_tcp_proxy_state);
-
-       status = resolve_name_recv(c, state, &state->proxy_ip);
+       status = resolve_name_recv(csubreq, state, &state->proxy.ip);
        if (!NT_STATUS_IS_OK(status)) {
-               kdc_tcp_next_proxy(state);
+               DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
+                       state->proxy.name.name, nt_errstr(status)));
+               kdc_tcp_next_proxy(req);
                return;
        }
 
        /* get an address for us to use locally */
        ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
        if (ret != 0) {
-               kdc_tcp_next_proxy(state);
+               kdc_tcp_next_proxy(req);
                return;
        }
 
        ret = tsocket_address_inet_from_strings(state, "ip",
-                                               state->proxy_ip, state->port, &proxy_addr);
+                                               state->proxy.ip,
+                                               state->port,
+                                               &proxy_addr);
        if (ret != 0) {
-               kdc_tcp_next_proxy(state);
+               kdc_tcp_next_proxy(req);
                return;
        }
 
-       /* connect to the proxy */
-       req = tstream_inet_tcp_connect_send(state, state->kdc->task->event_ctx, local_addr, proxy_addr);
-       if (req == NULL) {
-               kdc_tcp_next_proxy(state);
+       subreq = tstream_inet_tcp_connect_send(state, state->ev,
+                                              local_addr, proxy_addr);
+       if (tevent_req_nomem(subreq, req)) {
                return;
        }
-
-       tevent_req_set_callback(req, kdc_tcp_proxy_connect_done, state);
-
-       tevent_req_set_endtime(req, state->kdc->task->event_ctx,
+       tevent_req_set_callback(subreq, kdc_tcp_proxy_connect_done, req);
+       tevent_req_set_endtime(subreq, state->ev,
                               timeval_current_ofs(state->kdc->proxy_timeout, 0));
-
-       DEBUG(4,("kdc_tcp_proxy: proxying request to %s\n", state->proxy_ip));
 }
 
+static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq);
+static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq);
 
-/*
-  called when our proxies are not available
- */
-static void kdc_tcp_proxy_unavailable(struct kdc_tcp_proxy_state *state)
+static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq)
 {
-       int kret;
-       krb5_data k5_error_blob;
-       struct tevent_req *req;
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct kdc_tcp_proxy_state *state =
+               tevent_req_data(req,
+               struct kdc_tcp_proxy_state);
+       int ret, sys_errno;
 
-       kret = krb5_mk_error(state->kdc->smb_krb5_context->krb5_context,
-                            KRB5KDC_ERR_SVC_UNAVAILABLE, NULL, NULL,
-                            NULL, NULL, NULL, NULL, &k5_error_blob);
-       if (kret != 0) {
-               DEBUG(2,(__location__ ": Unable to form krb5 error reply\n"));
-               talloc_free(state);
+       ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
+                                           state, &state->proxy.stream, NULL);
+       TALLOC_FREE(subreq);
+       if (ret != 0) {
+               kdc_tcp_next_proxy(req);
                return;
        }
 
-
-       state->call->out = data_blob_talloc(state, k5_error_blob.data, k5_error_blob.length);
-       krb5_data_free(&k5_error_blob);
-       if (!state->call->out.data) {
-               talloc_free(state);
+       subreq = tstream_writev_send(state,
+                                    state->ev,
+                                    state->proxy.stream,
+                                    state->in_iov, 2);
+       if (tevent_req_nomem(subreq, req)) {
                return;
        }
+       tevent_req_set_callback(subreq, kdc_tcp_proxy_writev_done, req);
 
-       state->call->out_iov[0].iov_base = (char *)state->call->out.data;
-       state->call->out_iov[0].iov_len = state->call->out.length;
-
-       req = tstream_writev_queue_send(state,
-                                       state->kdc_conn->conn->event.ctx,
-                                       state->kdc_conn->tstream,
-                                       state->kdc_conn->send_queue,
-                                       state->call->out_iov, 1);
-       if (!req) {
-               talloc_free(state);
+       subreq = tstream_read_pdu_blob_send(state,
+                                           state->ev,
+                                           state->proxy.stream,
+                                           4, /* initial_read_size */
+                                           packet_full_request_u32,
+                                           req);
+       if (tevent_req_nomem(subreq, req)) {
                return;
        }
+       tevent_req_set_callback(subreq, kdc_tcp_proxy_read_pdu_done, req);
+       tevent_req_set_endtime(subreq, state->kdc->task->event_ctx,
+                              timeval_current_ofs(state->kdc->proxy_timeout, 0));
 
-       tevent_req_set_callback(req, kdc_tcp_proxy_reply_done, state);
+       DEBUG(4,("kdc_tcp_proxy: proxying request to %s[%s]\n",
+                state->proxy.name.name, state->proxy.ip));
 }
 
-/*
-  try the next proxy in the list
- */
-static void kdc_tcp_next_proxy(struct kdc_tcp_proxy_state *state)
+static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq)
 {
-       const char *proxy_dnsname = state->proxy_list[state->next_proxy];
-       struct nbt_name name;
-       struct composite_context *c;
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       int ret, sys_errno;
 
-       if (proxy_dnsname == NULL) {
-               kdc_tcp_proxy_unavailable(state);
-               return;
+       ret = tstream_writev_recv(subreq, &sys_errno);
+       TALLOC_FREE(subreq);
+       if (ret == -1) {
+               kdc_tcp_next_proxy(req);
        }
+}
 
-       state->next_proxy++;
+static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct kdc_tcp_proxy_state *state =
+               tevent_req_data(req,
+               struct kdc_tcp_proxy_state);
+       NTSTATUS status;
+       DATA_BLOB raw;
 
-       make_nbt_name(&name, proxy_dnsname, 0);
+       status = tstream_read_pdu_blob_recv(subreq, state, &raw);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               kdc_tcp_next_proxy(req);
+               return;
+       }
 
-       c = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
-                                state,
-                                RESOLVE_NAME_FLAG_FORCE_DNS,
-                                0,
-                                &name,
-                                state->kdc->task->event_ctx);
-       if (c == NULL) {
-               kdc_tcp_next_proxy(state);
+       /*
+        * raw blob has the length in the first 4 bytes,
+        * which we do not need here.
+        */
+       state->out = data_blob_talloc(state, raw.data + 4, raw.length - 4);
+       if (state->out.length != raw.length - 4) {
+               tevent_req_nomem(NULL, req);
                return;
        }
-       c->async.fn = kdc_tcp_proxy_resolve_done;
-       c->async.private_data = state;
-}
 
+       tevent_req_done(req);
+}
 
-/*
-  proxy a TCP kdc request to a writeable DC
- */
-void kdc_tcp_proxy(struct kdc_server *kdc, struct kdc_tcp_connection *kdc_conn,
-                  struct kdc_tcp_call *call, uint16_t port)
+NTSTATUS kdc_tcp_proxy_recv(struct tevent_req *req,
+                           TALLOC_CTX *mem_ctx,
+                           DATA_BLOB *out)
 {
-       struct kdc_tcp_proxy_state *state;
-       WERROR werr;
-
-       state = talloc_zero(kdc_conn, struct kdc_tcp_proxy_state);
-
-       state->call = talloc_steal(state, call);
-       state->kdc_conn = kdc_conn;
-       state->kdc  = kdc;
-       state->port = port;
+       struct kdc_tcp_proxy_state *state =
+               tevent_req_data(req,
+               struct kdc_tcp_proxy_state);
+       NTSTATUS status;
 
-       werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
-       if (!W_ERROR_IS_OK(werr)) {
-               kdc_tcp_proxy_unavailable(state);
-               return;
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
        }
 
-       kdc_tcp_next_proxy(state);
+       out->data = talloc_move(mem_ctx, &state->out.data);
+       out->length = state->out.length;
+
+       tevent_req_received(req);
+       return NT_STATUS_OK;
 }