summaryrefslogtreecommitdiffstats
path: root/src/providers/proxy/proxy_hosts.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers/proxy/proxy_hosts.c')
-rw-r--r--src/providers/proxy/proxy_hosts.c768
1 files changed, 768 insertions, 0 deletions
diff --git a/src/providers/proxy/proxy_hosts.c b/src/providers/proxy/proxy_hosts.c
new file mode 100644
index 0000000..d224829
--- /dev/null
+++ b/src/providers/proxy/proxy_hosts.c
@@ -0,0 +1,768 @@
+/*
+ SSSD
+
+ Authors:
+ Samuel Cabrero <scabrero@suse.com>
+
+ Copyright (C) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "providers/proxy/proxy.h"
+#include "db/sysdb_iphosts.h"
+#include <resolv.h>
+#include <arpa/inet.h>
+
+static errno_t
+nss_status_to_errno(enum nss_status status)
+{
+ switch (status) {
+ case NSS_STATUS_SUCCESS:
+ return EOK;
+ case NSS_STATUS_TRYAGAIN:
+ return EAGAIN;
+ case NSS_STATUS_NOTFOUND:
+ return ENOENT;
+ case NSS_STATUS_UNAVAIL:
+ default:
+ break;
+ }
+
+ return EIO;
+}
+
+static errno_t
+parse_hostent(TALLOC_CTX *mem_ctx,
+ struct hostent *result,
+ bool case_sensitive,
+ char **out_name,
+ char ***out_aliases,
+ char ***out_addresses)
+{
+ char **addresses = *out_addresses;
+ char **aliases = *out_aliases;
+ int i;
+ errno_t ret;
+
+ /* Parse addresses */
+ for (i = 0; result->h_addr_list[i] != NULL; i++) {
+ size_t len = talloc_array_length(addresses);
+ char buf[INET6_ADDRSTRLEN];
+ const char *addr = NULL;
+ bool found = false;
+ int j;
+
+ if (result->h_length == INADDRSZ) {
+ addr = inet_ntop(AF_INET, result->h_addr_list[i],
+ buf, INET6_ADDRSTRLEN);
+ } else if (result->h_length == IN6ADDRSZ) {
+ addr = inet_ntop(AF_INET6, result->h_addr_list[i],
+ buf, INET6_ADDRSTRLEN);
+ }
+
+ if (addr == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failed to convert host network address of host "
+ "'%s' to a character string: %s\n", result->h_name,
+ strerror(errno));
+ continue;
+ }
+
+ /* Skip duplicates */
+ for (j = 0;
+ j < len && addresses != NULL && addresses[j] != NULL;
+ j++) {
+ if (strcasecmp(addresses[j], addr) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ ret = add_string_to_list(mem_ctx, addr, &addresses);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Host [%s] has address [%s]\n",
+ result->h_name, addr);
+ }
+ }
+
+ for (i = 0; result->h_aliases[i] != NULL; i++) {
+ size_t len = talloc_array_length(aliases);
+ const char *alias = result->h_aliases[i];
+ bool found = false;
+ int j;
+
+ for (j = 0; j < len && aliases != NULL && aliases[j] != NULL; j++) {
+ if (case_sensitive && strcmp(aliases[j], alias) == 0) {
+ found = true;
+ break;
+ } else if (strcasecmp(aliases[j], alias) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ ret = add_string_to_list(mem_ctx, alias, &aliases);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Host [%s] has alias [%s]\n",
+ result->h_name, alias);
+ }
+ }
+
+ *out_name = talloc_strdup(mem_ctx, result->h_name);
+ *out_addresses = addresses;
+ *out_aliases = aliases;
+
+ ret = EOK;
+done:
+ return ret;
+}
+
+static errno_t
+proxy_save_host(struct sss_domain_info *domain,
+ bool lowercase,
+ uint64_t cache_timeout,
+ char *name,
+ char **aliases,
+ char **addresses)
+{
+ errno_t ret;
+ char *cased_name = NULL;
+ const char **cased_aliases = NULL;
+ const char **cased_addresses = NULL;
+ TALLOC_CTX *tmp_ctx;
+ char *lc_alias = NULL;
+ time_t now = time(NULL);
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Saving host [%s] into cache, domain [%s]\n",
+ name, domain->name);
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ cased_name = sss_get_cased_name(tmp_ctx, name,
+ domain->case_preserve);
+ if (cased_name == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot get cased name.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Count the aliases */
+ ret = sss_get_cased_name_list(tmp_ctx,
+ (const char * const *) aliases,
+ !lowercase, &cased_aliases);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot get cased aliases.\n");
+ goto done;
+ }
+
+ /* Count the addresses */
+ ret = sss_get_cased_name_list(tmp_ctx,
+ (const char * const *) addresses,
+ !lowercase, &cased_addresses);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot get cased addresses.\n");
+ goto done;
+ }
+
+ if (domain->case_preserve) {
+ /* Add lowercased alias to allow case-insensitive lookup */
+ lc_alias = sss_tc_utf8_str_tolower(tmp_ctx, name);
+ if (lc_alias == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = add_string_to_list(tmp_ctx, lc_alias,
+ discard_const_p(char **, &cased_aliases));
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to add lowercased name alias.\n");
+ goto done;
+ }
+ }
+
+ ret = sysdb_store_host(domain, cased_name, cased_aliases, cased_addresses,
+ NULL, NULL, cache_timeout, now);
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static errno_t
+get_host_by_name_internal(struct proxy_resolver_ctx *ctx,
+ struct sss_domain_info *domain,
+ TALLOC_CTX *mem_ctx,
+ const char *search_name, int af,
+ char **out_name,
+ char ***out_addresses,
+ char ***out_aliases)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ char *buffer = NULL;
+ size_t buflen = DEFAULT_BUFSIZE;
+ struct hostent *result = NULL;
+ enum nss_status status;
+ int err;
+ int h_err;
+ errno_t ret;
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Resolving host [%s] [%s]\n", search_name,
+ af == AF_INET ? "AF_INET" : "AF_INET6");
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ result = talloc_zero(tmp_ctx, struct hostent);
+ if (result == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Ask for IPv4 addresses */
+ err = 0;
+ h_err = 0;
+ for (status = NSS_STATUS_TRYAGAIN,
+ err = ERANGE, h_err = 0;
+ status == NSS_STATUS_TRYAGAIN && err == ERANGE;
+ buflen *= 2)
+ {
+ buffer = talloc_realloc_size(tmp_ctx, buffer, buflen);
+ if (buffer == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ status = ctx->ops.gethostbyname2_r(search_name, af, result,
+ buffer, buflen,
+ &err, &h_err);
+ }
+
+ ret = nss_status_to_errno(status);
+ if (ret != EOK) {
+ if (ret != ENOENT) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "gethostbyname2_r (%s) failed for host [%s]: %d, %s, %s.\n",
+ af == AF_INET ? "AF_INET" : "AF_INET6",
+ search_name, status, strerror(err), hstrerror(h_err));
+ }
+
+ goto done;
+ }
+
+ ret = parse_hostent(mem_ctx, result, domain->case_sensitive,
+ out_name, out_aliases, out_addresses);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to parse hostent [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static errno_t
+get_host_byname(struct proxy_resolver_ctx *ctx,
+ struct sss_domain_info *domain,
+ const char *search_name)
+{
+ TALLOC_CTX *tmp_ctx;
+ errno_t ret_v4;
+ errno_t ret_v6;
+ errno_t ret;
+ char *name = NULL;
+ char **addresses = NULL;
+ char **aliases = NULL;
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Processing request for host name [%s]\n",
+ search_name);
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret_v4 = get_host_by_name_internal(ctx, domain, tmp_ctx, search_name,
+ AF_INET, &name, &addresses, &aliases);
+ if (ret_v4 != EOK && ret_v4 != ENOENT) {
+ ret = ret_v4;
+ goto done;
+ }
+
+ ret_v6 = get_host_by_name_internal(ctx, domain, tmp_ctx, search_name,
+ AF_INET6, &name, &addresses, &aliases);
+ if (ret_v6 != EOK && ret_v6 != ENOENT) {
+ ret = ret_v6;
+ goto done;
+ }
+
+ if (ret_v4 == ENOENT && ret_v6 == ENOENT) {
+ /* Make sure we remove it from the cache */
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Host [%s] not found, removing from "
+ "cache\n", name);
+ sysdb_host_delete(domain, search_name, NULL);
+ ret = ENOENT;
+ goto done;
+ } else {
+ /* Results found. Save them into the cache */
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Host [%s] found, saving into "
+ "cache\n", name);
+ ret = proxy_save_host(domain, !domain->case_sensitive,
+ domain->resolver_timeout,
+ name, aliases, addresses);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to store host [%s] [%d]: %s\n",
+ name, ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t
+get_host_by_addr_internal(struct proxy_resolver_ctx *ctx,
+ struct sss_domain_info *domain,
+ TALLOC_CTX *mem_ctx,
+ const char *addrstr,
+ char **out_name,
+ char ***out_addresses,
+ char ***out_aliases)
+{
+ TALLOC_CTX *tmp_ctx;
+ char *buffer = NULL;
+ size_t buflen = DEFAULT_BUFSIZE;
+ struct hostent *result = NULL;
+ enum nss_status status;
+ int err;
+ int h_err;
+ char addrbuf[IN6ADDRSZ];
+ socklen_t addrlen = 0;
+ int af = 0;
+ errno_t ret;
+ char *name = NULL;
+ char **addresses = NULL;
+ char **aliases = NULL;
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Resolving host [%s]\n", addrstr);
+
+ if (inet_pton(AF_INET, addrstr, addrbuf)) {
+ af = AF_INET;
+ addrlen = INADDRSZ;
+ } else if (inet_pton(AF_INET6, addrstr, addrbuf)) {
+ af = AF_INET6;
+ addrlen = IN6ADDRSZ;
+ } else {
+ return EINVAL;
+ }
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ result = talloc_zero(tmp_ctx, struct hostent);
+ if (result == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Ask for IPv4 addresses */
+ err = 0;
+ h_err = 0;
+ for (status = NSS_STATUS_TRYAGAIN,
+ err = ERANGE, h_err = 0;
+ status == NSS_STATUS_TRYAGAIN && err == ERANGE;
+ buflen *= 2)
+ {
+ buffer = talloc_realloc_size(tmp_ctx, buffer, buflen);
+ if (buffer == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ status = ctx->ops.gethostbyaddr_r(addrbuf, addrlen, af, result,
+ buffer, buflen,
+ &err, &h_err);
+ }
+
+ ret = nss_status_to_errno(status);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "gethostbyaddr_r (%s) failed for host [%s]: %d, %s, %s.\n",
+ af == AF_INET ? "AF_INET" : "AF_INET6",
+ addrstr, status, strerror(err), hstrerror(h_err));
+ goto done;
+ }
+
+ if (ret == EOK) {
+ ret = parse_hostent(tmp_ctx, result, domain->case_sensitive,
+ &name, &aliases, &addresses);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failed to parse hostent [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ if (name != NULL) {
+ *out_name = talloc_steal(mem_ctx, name);
+ }
+ if (addresses != NULL) {
+ *out_addresses = talloc_steal(mem_ctx, addresses);
+ }
+ if (aliases != NULL) {
+ *out_aliases = talloc_steal(mem_ctx, aliases);
+ }
+
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static errno_t
+get_host_byaddr(struct proxy_resolver_ctx *ctx,
+ struct sss_domain_info *domain,
+ const char *address)
+{
+ TALLOC_CTX *tmp_ctx;
+ errno_t ret;
+ char *name = NULL;
+ char **addresses = NULL;
+ char **aliases = NULL;
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Processing request for host address [%s]\n",
+ address);
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = get_host_by_addr_internal(ctx, domain, tmp_ctx, address,
+ &name, &addresses, &aliases);
+ if (ret != EOK && ret != ENOENT) {
+ goto done;
+ }
+
+ if (ret == ENOENT) {
+ /* Make sure we remove it from the cache */
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Host [%s] not found, removing from "
+ "cache\n", address);
+ sysdb_host_delete(domain, NULL, address);
+ } else {
+ /* Results found. Save them into the cache */
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Host [%s] found, saving into "
+ "cache\n", address);
+ ret = proxy_save_host(domain, !domain->case_sensitive,
+ domain->resolver_timeout,
+ name, aliases, addresses);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to store host [%s] [%d]: %s\n",
+ name, ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t
+gethostent_internal(struct proxy_resolver_ctx *ctx,
+ struct sss_domain_info *domain,
+ TALLOC_CTX *mem_ctx,
+ char **out_name,
+ char ***out_addresses,
+ char ***out_aliases)
+
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ char *buffer = NULL;
+ size_t buflen = DEFAULT_BUFSIZE;
+ enum nss_status status;
+ struct hostent *result = NULL;
+ char *name = NULL;
+ char **addresses = NULL;
+ char **aliases = NULL;
+ int err;
+ int h_err;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ result = talloc_zero(tmp_ctx, struct hostent);
+ if (result == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (status = NSS_STATUS_TRYAGAIN,
+ err = ERANGE, h_err = 0;
+ status == NSS_STATUS_TRYAGAIN && err == ERANGE;
+ buflen *= 2)
+ {
+ buffer = talloc_realloc_size(tmp_ctx, buffer, buflen);
+ if (buffer == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ status = ctx->ops.gethostent_r(result,
+ buffer, buflen,
+ &err, &h_err);
+ }
+
+ ret = nss_status_to_errno(status);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "gethostent_r failed: %d, %s, %s.\n",
+ status, strerror(err), hstrerror(h_err));
+ goto done;
+ }
+
+ if (ret == EOK) {
+ ret = parse_hostent(tmp_ctx, result, domain->case_sensitive,
+ &name, &aliases, &addresses);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failed to parse hostent [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ if (name != NULL) {
+ *out_name = talloc_steal(mem_ctx, name);
+ }
+ if (addresses != NULL) {
+ *out_addresses = talloc_steal(mem_ctx, addresses);
+ }
+ if (aliases != NULL) {
+ *out_aliases = talloc_steal(mem_ctx, aliases);
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static errno_t
+enum_iphosts(struct proxy_resolver_ctx *ctx,
+ struct sss_domain_info *domain)
+{
+ struct sysdb_ctx *sysdb = domain->sysdb;
+ TALLOC_CTX *tmp_ctx = NULL;
+ bool in_transaction = false;
+ enum nss_status status;
+ errno_t ret;
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Enumerating iphosts\n");
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sysdb_transaction_start(sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
+ goto done;
+ }
+ in_transaction = true;
+
+ status = ctx->ops.sethostent();
+ if (status != NSS_STATUS_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ do {
+ char *name = NULL;
+ char **addresses = NULL;
+ char **aliases = NULL;
+
+ ret = gethostent_internal(ctx, domain, tmp_ctx, &name,
+ &addresses, &aliases);
+ if (ret == EOK) {
+ /* Results found. Save them into the cache */
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Host [%s] found, saving into "
+ "cache\n", name);
+
+ proxy_save_host(domain, !domain->case_sensitive,
+ domain->resolver_timeout,
+ name, aliases, addresses);
+ }
+
+ /* Free children to avoid using too much memory */
+ talloc_free_children(tmp_ctx);
+ } while (ret == EOK);
+
+ if (ret == ENOENT) {
+ /* We are done, commit transaction and stop loop */
+ DEBUG(SSSDBG_TRACE_FUNC, "Enumeration completed.\n");
+ ret = sysdb_transaction_commit(sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
+ goto done;
+ }
+ in_transaction = false;
+ } else {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "gethostent_r failed [%d]: %s\n",
+ ret, strerror(ret));
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ if (in_transaction) {
+ errno_t sret;
+
+ sret = sysdb_transaction_cancel(sysdb);
+ if (sret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Could not cancel transaction! [%s]\n",
+ strerror(sret));
+ }
+ }
+ ctx->ops.endhostent();
+ return ret;
+}
+
+static struct dp_reply_std
+proxy_hosts_info(TALLOC_CTX *mem_ctx,
+ struct proxy_resolver_ctx *ctx,
+ struct dp_resolver_data *data,
+ struct be_ctx *be_ctx,
+ struct sss_domain_info *domain)
+{
+ struct dp_reply_std reply;
+ errno_t ret;
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Processing host request, filter type [%d]\n",
+ data->filter_type);
+
+ switch (data->filter_type) {
+ case BE_FILTER_NAME:
+ ret = get_host_byname(ctx, domain, data->filter_value);
+ break;
+
+ case BE_FILTER_ADDR:
+ ret = get_host_byaddr(ctx, domain, data->filter_value);
+ break;
+
+ case BE_FILTER_ENUM:
+ ret = enum_iphosts(ctx, domain);
+ break;
+
+ default:
+ dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
+ "Invalid filter type");
+ return reply;
+ }
+
+ if (ret) {
+ if (ret == ENXIO) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "proxy returned UNAVAIL error, going offline!\n");
+ be_mark_offline(be_ctx);
+ }
+
+ dp_reply_std_set(&reply, DP_ERR_FATAL, ret, NULL);
+ return reply;
+ }
+
+ dp_reply_std_set(&reply, DP_ERR_OK, EOK, NULL);
+ return reply;
+}
+
+struct proxy_hosts_handler_state {
+ int dummy;
+ struct dp_reply_std reply;
+};
+
+struct tevent_req *
+proxy_hosts_handler_send(TALLOC_CTX *mem_ctx,
+ struct proxy_resolver_ctx *resolver_ctx,
+ struct dp_resolver_data *resolver_data,
+ struct dp_req_params *params)
+{
+ struct proxy_hosts_handler_state *state;
+ struct tevent_req *req;
+
+ req = tevent_req_create(mem_ctx, &state, struct proxy_hosts_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->reply = proxy_hosts_info(state, resolver_ctx, resolver_data,
+ params->be_ctx, params->be_ctx->domain);
+
+ tevent_req_done(req);
+ return tevent_req_post(req, params->ev);
+}
+
+errno_t
+proxy_hosts_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data)
+{
+ struct proxy_hosts_handler_state *state;
+
+ state = tevent_req_data(req, struct proxy_hosts_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *data = state->reply;
+
+ return EOK;
+}