async_resolv.c revision 19c6d0bf5346dc1862d14f7f3d886895cfb4d548
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/*
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen SSSD
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen Async resolver
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen Authors:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen Martin Nagy <mnagy@redhat.com>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen Jakub Hrozek <jhrozek@redhat.com>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen Copyright (C) Red Hat, Inc 2009
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen This program is free software; you can redistribute it and/or modify
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen it under the terms of the GNU General Public License as published by
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen the Free Software Foundation; either version 3 of the License, or
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen (at your option) any later version.
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen This program is distributed in the hope that it will be useful,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen GNU General Public License for more details.
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen You should have received a copy of the GNU General Public License
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen*/
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include <sys/select.h>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include <arpa/inet.h>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include <arpa/nameser.h>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include <ares.h>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include <talloc.h>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include <tevent.h>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include <errno.h>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include <netdb.h>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include <stddef.h>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include <string.h>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include <unistd.h>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include "config.h"
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include "resolv/async_resolv.h"
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include "util/dlinklist.h"
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#include "util/util.h"
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#ifndef HAVE_ARES_DATA
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#define ares_parse_srv_reply(abuf, alen, srv_out) \
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen _ares_parse_srv_reply(abuf, alen, srv_out)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#define ares_parse_txt_reply(abuf, alen, txt_out) \
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen _ares_parse_txt_reply(abuf, alen, txt_out)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#define ares_free_data(dataptr) \
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen _ares_free_data(dataptr)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#define ares_malloc_data(data) \
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen _ares_malloc_data(data)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#endif /* HAVE_ARES_DATA */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#ifndef HAVE_STRUCT_ARES_ADDRTTL
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#define ares_addrttl addrttl
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#endif
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#ifndef HAVE_STRUCT_ARES_ADDR6TTL
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#define ares_addr6ttl addr6ttl
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#endif
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#define DNS__16BIT(p) (((p)[0] << 8) | (p)[1])
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#define DNS_HEADER_ANCOUNT(h) DNS__16BIT((h) + 6)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenenum host_database default_host_dbs[] = { DB_FILES, DB_DNS, DB_SENTINEL };
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstruct fd_watch {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct fd_watch *prev;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct fd_watch *next;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int fd;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_fd *fde;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen};
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstruct resolv_ctx {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Contexts are linked so we can keep track of them and re-create
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * the ares channels in all of them at once if we need to. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *prev;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *next;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_context *ev_ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ares_channel channel;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* List of file descriptors that are watched by tevent. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct fd_watch *fds;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Time in milliseconds before canceling a DNS request */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int timeout;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* The timeout watcher periodically calls ares_process_fd() to check
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * if our pending requests didn't timeout. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int pending_requests;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_timer *timeout_watcher;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen};
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstruct resolv_ctx *context_list;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenerrno_t
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_get_family_order(struct confdb_ctx *cdb, const char *conf_path,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen enum restrict_family *family_order)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen errno_t ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen TALLOC_CTX *tmp_ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen char *str_opt;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tmp_ctx = talloc_new(NULL);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!tmp_ctx) return ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = confdb_get_string(cdb, tmp_ctx, conf_path,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen CONFDB_DOMAIN_FAMILY_ORDER,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen "ipv4_first", &str_opt);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret != EOK) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto done;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(7, ("Lookup order: %s\n", str_opt));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (strcasecmp(str_opt, "ipv4_first") == 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *family_order = IPV4_FIRST;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else if (strcasecmp(str_opt, "ipv4_only") == 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *family_order = IPV4_ONLY;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else if (strcasecmp(str_opt, "ipv6_first") == 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *family_order = IPV6_FIRST;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else if (strcasecmp(str_opt, "ipv6_only") == 0) {
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen *family_order = IPV6_ONLY;
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen } else {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Unknown value for option %s: %s\n",
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen CONFDB_DOMAIN_FAMILY_ORDER, str_opt));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = EINVAL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto done;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = EOK;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainendone:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_free(tmp_ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic int
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenreturn_code(int ares_code)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen switch (ares_code) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case ARES_SUCCESS:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EOK;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case ARES_ENOMEM:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case ARES_EFILE:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen default:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EIO;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenconst char *
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_strerror(int ares_code)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ares_strerror(ares_code);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic int
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenfd_watch_destructor(struct fd_watch *f)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DLIST_REMOVE(f->ctx->fds, f);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen f->fd = -1;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenfd_input_available(struct tevent_context *ev, struct tevent_fd *fde,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen uint16_t flags, void *data)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct fd_watch *watch = talloc_get_type(data, struct fd_watch);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (watch->ctx->channel == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (flags & TEVENT_FD_READ) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ares_process_fd(watch->ctx->channel, watch->fd, ARES_SOCKET_BAD);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (flags & TEVENT_FD_WRITE) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ares_process_fd(watch->ctx->channel, ARES_SOCKET_BAD, watch->fd);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainencheck_fd_timeouts(struct tevent_context *ev, struct tevent_timer *te,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct timeval current_time, void *private_data);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenadd_timeout_timer(struct tevent_context *ev, struct resolv_ctx *ctx)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct timeval tv = { 0, 0 };
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct timeval *tvp;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tvp = ares_timeout(ctx->channel, NULL, &tv);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (tvp == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tvp = &tv;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Enforce a minimum of 1 second. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (tvp->tv_sec < 1) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tv = tevent_timeval_current_ofs(1, 0);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tv = tevent_timeval_current_ofs(tvp->tv_sec, tvp->tv_usec);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ctx->timeout_watcher = tevent_add_timer(ev, ctx, tv, check_fd_timeouts,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ctx->timeout_watcher == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Out of memory\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainencheck_fd_timeouts(struct tevent_context *ev, struct tevent_timer *te,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct timeval current_time, void *private_data)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *ctx = talloc_get_type(private_data, struct resolv_ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(9, ("Checking for DNS timeouts\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* NULLify the timeout_watcher so we don't
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * free it in the _done() function if it
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * gets called. Now that we're already in
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * the handler, tevent will take care of
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * freeing it when it returns.
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ctx->timeout_watcher = NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ares_process_fd(ctx->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ctx->pending_requests > 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen add_timeout_timer(ev, ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenschedule_timeout_watcher(struct tevent_context *ev, struct resolv_ctx *ctx)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ctx->pending_requests++;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ctx->timeout_watcher) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(9, ("Scheduling DNS timeout watcher\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen add_timeout_timer(ev, ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenunschedule_timeout_watcher(struct resolv_ctx *ctx)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ctx->pending_requests <= 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Pending DNS requests mismatch\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ctx->pending_requests--;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ctx->pending_requests == 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(9, ("Unscheduling DNS timeout watcher\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_zfree(ctx->timeout_watcher);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void fd_event_add(struct resolv_ctx *ctx, int s, int flags);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void fd_event_close(struct resolv_ctx *ctx, int s);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen/*
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * When ares is ready to read or write to a file descriptor, it will
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * call this callback. If both read and write are 0, it means that ares
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * will soon close the socket. We are mainly using this function to register
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * new file descriptors with tevent.
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenfd_event(void *data, int s, int fd_read, int fd_write)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *ctx = talloc_get_type(data, struct resolv_ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct fd_watch *watch;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int flags;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* The socket is about to get closed. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (fd_read == 0 && fd_write == 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen fd_event_close(ctx, s);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen flags = fd_read ? TEVENT_FD_READ : 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen flags |= fd_write ? TEVENT_FD_WRITE : 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Are we already watching this file descriptor? */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen watch = ctx->fds;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen while (watch) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (watch->fd == s) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_fd_set_flags(watch->fde, flags);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen watch = watch->next;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen fd_event_add(ctx, s, flags);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenfd_event_add(struct resolv_ctx *ctx, int s, int flags)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct fd_watch *watch;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* The file descriptor is new, register it with tevent. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen watch = talloc(ctx, struct fd_watch);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (watch == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Out of memory allocating fd_watch structure\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_set_destructor(watch, fd_watch_destructor);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen watch->fd = s;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen watch->ctx = ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen watch->fde = tevent_add_fd(ctx->ev_ctx, watch, s, flags,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen fd_input_available, watch);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (watch->fde == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("tevent_add_fd() failed\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_free(watch);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DLIST_ADD(ctx->fds, watch);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenfd_event_close(struct resolv_ctx *ctx, int s)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct fd_watch *watch;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Remove the socket from list */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen watch = ctx->fds;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen while (watch) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (watch->fd == s) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_free(watch);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen watch = watch->next;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic int
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_ctx_destructor(struct resolv_ctx *ctx)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ares_channel channel;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DLIST_REMOVE(context_list, ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ctx->channel == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Ares channel already destroyed?\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return -1;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Set ctx->channel to NULL first, so that callbacks that get
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * ARES_EDESTRUCTION won't retry. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen channel = ctx->channel;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ctx->channel = NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ares_destroy(channel);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic int
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenrecreate_ares_channel(struct resolv_ctx *ctx)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ares_channel new_channel;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ares_channel old_channel;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct ares_options options;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(4, ("Initializing new c-ares channel\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* FIXME: the options would contain
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * the nameservers to contact, the domains
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * to search... => get from confdb
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen options.sock_state_cb = fd_event;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen options.sock_state_cb_data = ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen options.timeout = ctx->timeout * 1000;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Only affects ares_gethostbyname */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen options.lookups = discard_const("f");
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen options.tries = 1;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = ares_init_options(&new_channel, &options,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ARES_OPT_SOCK_STATE_CB |
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ARES_OPT_TIMEOUTMS |
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ARES_OPT_LOOKUPS |
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ARES_OPT_TRIES);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret != ARES_SUCCESS) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Failed to initialize ares channel: %s\n",
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen resolv_strerror(ret)));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return return_code(ret);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen old_channel = ctx->channel;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ctx->channel = new_channel;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (old_channel != NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(4, ("Destroying the old c-ares channel\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ares_destroy(old_channel);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EOK;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenint
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int timeout, struct resolv_ctx **ctxp)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (timeout < 1) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EINVAL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ctx = talloc_zero(mem_ctx, struct resolv_ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ctx == NULL)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ctx->ev_ctx = ev_ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ctx->timeout = timeout;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = recreate_ares_channel(ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret != EOK) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto done;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DLIST_ADD(context_list, ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_set_destructor(ctx, resolv_ctx_destructor);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *ctxp = ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EOK;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainendone:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_free(ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenvoid
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_reread_configuration(void)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(4, ("Recreating all c-ares channels\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DLIST_FOR_EACH(ctx, context_list) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen recreate_ares_channel(ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic errno_t
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_copy_in_addr(TALLOC_CTX *mem_ctx, struct resolv_addr *ret,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct ares_addrttl *attl)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->ipaddr = talloc_array(mem_ctx, uint8_t, sizeof(struct in_addr));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!ret->ipaddr) return ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen memcpy(ret->ipaddr, &attl->ipaddr, sizeof(struct in_addr));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->ttl = attl->ttl;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EOK;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic errno_t
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_copy_in6_addr(TALLOC_CTX *mem_ctx, struct resolv_addr *ret,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct ares_addr6ttl *a6ttl)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->ipaddr = talloc_array(mem_ctx, uint8_t, sizeof(struct in6_addr));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!ret->ipaddr) return ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen memcpy(ret->ipaddr, &a6ttl->ip6addr, sizeof(struct in6_addr));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->ttl = a6ttl->ttl;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EOK;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic struct resolv_hostent *
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_copy_hostent_common(TALLOC_CTX *mem_ctx, struct hostent *src)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_hostent *ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int len;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int i;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = talloc_zero(mem_ctx, struct resolv_hostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (src->h_name != NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->name = talloc_strdup(ret, src->h_name);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret->name == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (src->h_aliases != NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (len = 0; src->h_aliases[len] != NULL; len++);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->aliases = talloc_array(ret, char *, len + 1);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret->aliases == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (i = 0; i < len; i++) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->aliases[i] = talloc_strdup(ret->aliases, src->h_aliases[i]);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret->aliases[i] == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->aliases[len] = NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->family = src->h_addrtype;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenfail:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_free(ret);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstruct resolv_hostent *
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_copy_hostent(TALLOC_CTX *mem_ctx, struct hostent *src)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_hostent *ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int len;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int i;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = resolv_copy_hostent_common(mem_ctx, src);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (src->h_addr_list != NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (len = 0; src->h_addr_list[len] != NULL; len++);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list = talloc_array(ret, struct resolv_addr *, len + 1);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret->addr_list == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (i = 0; i < len; i++) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list[i] = talloc_zero(ret->addr_list,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_addr);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret->addr_list[i] == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list[i]->ipaddr = talloc_memdup(ret->addr_list[i],
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen src->h_addr_list[i],
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen src->h_length);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret->addr_list[i]->ipaddr == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list[i]->ttl = RESOLV_DEFAULT_TTL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list[len] = NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenfail:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_free(ret);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstruct resolv_hostent *
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_copy_hostent_ares(TALLOC_CTX *mem_ctx, struct hostent *src,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int family, void *ares_ttl_data,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int num_ares_ttl_data)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_hostent *ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen errno_t cret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int i;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = resolv_copy_hostent_common(mem_ctx, src);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (num_ares_ttl_data > 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list = talloc_array(ret, struct resolv_addr *,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen num_ares_ttl_data + 1);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret->addr_list == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (i = 0; i < num_ares_ttl_data; i++) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list[i] = talloc_zero(ret->addr_list,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_addr);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret->addr_list[i] == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen switch (family) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case AF_INET:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen cret = resolv_copy_in_addr(ret->addr_list, ret->addr_list[i],
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen &((struct ares_addrttl *) ares_ttl_data)[i]);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen break;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case AF_INET6:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen cret = resolv_copy_in6_addr(ret->addr_list, ret->addr_list[i],
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen &((struct ares_addr6ttl *) ares_ttl_data)[i]);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen break;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen default:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Unknown address family %d\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (cret != EOK) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Could not copy address\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list[num_ares_ttl_data] = NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->family = family;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenfail:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_free(ret);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen/* =================== Resolve host name in files =========================*/
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstruct gethostbyname_files_state {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *resolv_ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Part of the query. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen const char *name;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int family;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* query result */
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen struct resolv_hostent *rhostent;
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* returned by ares. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int status;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen};
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen/* Fake up an async interface even though files would
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen * always be blocking */
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainenstatic struct tevent_req *
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainenresolv_gethostbyname_files_send(TALLOC_CTX *mem_ctx,
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen struct tevent_context *ev,
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen struct resolv_ctx *ctx,
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen const char *name,
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen int family)
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen{
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen struct tevent_req *req;
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen struct gethostbyname_files_state *state;
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen struct hostent *hostent = NULL;
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen req = tevent_req_create(mem_ctx, &state,
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen struct gethostbyname_files_state);
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen if (req == NULL) {
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen tevent_req_error(req, ENOMEM);
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen goto done;
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen }
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen state->resolv_ctx = ctx;
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen state->name = name;
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen state->rhostent = NULL;
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen state->family = family;
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen DEBUG(4, ("Trying to resolve %s record of '%s' in files\n",
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen state->family == AF_INET ? "A" : "AAAA", state->name));
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen state->status = ares_gethostbyname_file(state->resolv_ctx->channel,
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen state->name, state->family,
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen &hostent);
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (state->status == ARES_SUCCESS) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->rhostent = resolv_copy_hostent(state, hostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (state->rhostent == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_error(req, ENOMEM);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto done;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else if (state->status == ARES_ENOTFOUND ||
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->status == ARES_ENODATA) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Just say we didn't find anything and let the caller decide
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * about retrying */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_error(req, ENOENT);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto done;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else {
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen tevent_req_error(req, return_code(state->status));
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen goto done;
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_done(req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainendone:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (hostent) ares_free_hostent(hostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_post(req, ev);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return req;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic errno_t
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_files_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int *status, struct resolv_hostent **rhostent)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_files_state *state = tevent_req_data(req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_files_state);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Fill in even in case of error as status contains the
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * c-ares return code */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (status) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *status = state->status;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (rhostent) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *rhostent = talloc_steal(mem_ctx, state->rhostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen TEVENT_REQ_RETURN_ON_ERROR(req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EOK;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen/* ==================== Resolve host name in DNS =========================*/
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstruct gethostbyname_dns_state {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *resolv_ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_context *ev;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Part of the query. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen const char *name;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int family;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* query result */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_hostent *rhostent;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* These are returned by ares. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int status;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int timeouts;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int retrying;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen};
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_wakeup(struct tevent_req *subreq);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_query(struct tevent_req *req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_dns_state *state);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_query_done(void *arg, int status, int timeouts,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen unsigned char *abuf, int alen);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic int
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_parse(struct gethostbyname_dns_state *state, int status,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int timeouts, unsigned char *abuf, int alen);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic struct tevent_req *
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *ctx, const char *name,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int family)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_req *req, *subreq;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_dns_state *state;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct timeval tv = { 0, 0 };
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ctx->channel == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen req = tevent_req_create(mem_ctx, &state, struct gethostbyname_dns_state);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (req == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->resolv_ctx = ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->ev = ev;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->name = name;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->rhostent = NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->status = 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->timeouts = 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->retrying = 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family = family;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* We need to have a wrapper around ares async calls, because
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * they can in some cases call it's callback immediately.
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * This would not let our caller to set a callback for req. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen subreq = tevent_wakeup_send(req, ev, tv);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (subreq == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Failed to add critical timer to run next operation!\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_zfree(req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_set_callback(subreq, resolv_gethostbyname_dns_wakeup, req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen schedule_timeout_watcher(ev, ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return req;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_wakeup(struct tevent_req *subreq)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_req *req = tevent_req_callback_data(subreq,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_dns_state *state = tevent_req_data(req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_dns_state);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!tevent_wakeup_recv(subreq)) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_error(req, EIO);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_zfree(subreq);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (state->resolv_ctx->channel == NULL) {
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen tevent_req_error(req, EIO);
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen return;
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen }
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen resolv_gethostbyname_dns_query(req, state);
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen}
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_query(struct tevent_req *req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_dns_state *state)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(4, ("Trying to resolve %s record of '%s' in DNS\n",
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family == AF_INET ? "A" : "AAAA", state->name));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ares_query(state->resolv_ctx->channel,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->name, ns_c_in,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen (state->family == AF_INET) ? ns_t_a : ns_t_aaaa,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen resolv_gethostbyname_dns_query_done, req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_query_done(void *arg, int status, int timeouts,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen unsigned char *abuf, int alen)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_req *req = talloc_get_type(arg, struct tevent_req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_dns_state *state = tevent_req_data(req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_dns_state);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen errno_t ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen unschedule_timeout_watcher(state->resolv_ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->status = status;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->timeouts = timeouts;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* If resolv.conf changed during processing of a request we might
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * destroy the old channel before the request has a chance to finish.
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * We must resend the request in this case */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (state->retrying == 0 && status == ARES_EDESTRUCTION
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen && state->resolv_ctx->channel != NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->retrying = 1;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen schedule_timeout_watcher(state->ev, state->resolv_ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen resolv_gethostbyname_dns_query(req, state);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (status == ARES_ENOTFOUND || status == ARES_ENODATA) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Just say we didn't find anything and let the caller decide
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * about retrying */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_error(req, ENOENT);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (status != ARES_SUCCESS) {
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen /* Any other error indicates a server error,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * so don't bother trying again
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_error(req, return_code(status));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = resolv_gethostbyname_dns_parse(state, status, timeouts, abuf, alen);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret != EOK) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_error(req, ret);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_done(req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic int
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_parse(struct gethostbyname_dns_state *state,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int status, int timeouts,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen unsigned char *abuf, int alen)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen TALLOC_CTX *tmp_ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct hostent *hostent;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int naddrttls;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen errno_t ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen void *addr;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tmp_ctx = talloc_new(NULL);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!tmp_ctx) return ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen naddrttls = DNS_HEADER_ANCOUNT(abuf);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen switch (state->family) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case AF_INET:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(7, ("Parsing an A reply\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen addr = talloc_array(state, struct ares_addrttl, naddrttls);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!addr) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen status = ares_parse_a_reply(abuf, alen, &hostent,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen (struct ares_addrttl *) addr,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen &naddrttls);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen break;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case AF_INET6:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(7, ("Parsing an AAAA reply\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen addr = talloc_array(state, struct ares_addr6ttl, naddrttls);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!addr) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen status = ares_parse_aaaa_reply(abuf, alen, &hostent,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen (struct ares_addr6ttl *) addr,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen &naddrttls);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen break;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen default:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Unknown family %d\n", state->family));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = EAFNOSUPPORT;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (hostent != NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->rhostent = resolv_copy_hostent_ares(state, hostent,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen addr, naddrttls);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen free(hostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (state->rhostent == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto fail;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_free(tmp_ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return return_code(status);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenfail:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_free(tmp_ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic int
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int *status, int *timeouts,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_hostent **rhostent)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_dns_state *state = tevent_req_data(req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_dns_state);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Fill in even in case of error as status contains the
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * c-ares return code */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (status) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *status = state->status;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (timeouts) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *timeouts = state->timeouts;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (rhostent) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *rhostent = talloc_steal(mem_ctx, state->rhostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen TEVENT_REQ_RETURN_ON_ERROR(req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EOK;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen/*******************************************************************
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * Get host by name. *
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *******************************************************************/
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstruct gethostbyname_state {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *resolv_ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_context *ev;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Part of the query. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen const char *name;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int family;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* In which order to use IPv4, or v6 */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen enum restrict_family family_order;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Known hosts databases and index to the current one */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen enum host_database *db;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int dbi;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* These are returned by ares. The hostent struct will be freed
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * when the user callback returns. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_hostent *rhostent;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int status;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int timeouts;
b1e7bc754b8be7974aea48cb97c5ce866f9b2029Timo Sirainen int retrying;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen};
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic errno_t
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_address(TALLOC_CTX *mem_ctx, const char *address,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_hostent **_rhostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic inline int
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainenresolv_gethostbyname_family_init(enum restrict_family family_order);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainenstatic bool
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainenresolv_is_address(const char *name);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic errno_t
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_step(struct tevent_req *req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstruct tevent_req *
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *ctx, const char *name,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen enum restrict_family family_order,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen enum host_database *db)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_req *req;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_state *state;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen errno_t ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ctx->channel == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen req = tevent_req_create(mem_ctx, &state, struct gethostbyname_state);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (req == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->resolv_ctx = ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->ev = ev;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->name = name;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->rhostent = NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->status = 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->timeouts = 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->retrying = 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family_order = family_order;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family = resolv_gethostbyname_family_init(state->family_order);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->db = db;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->dbi = 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Do not attempt to resolve IP addresses */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (resolv_is_address(state->name)) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = resolv_gethostbyname_address(state, state->name,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen &state->rhostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret != EOK) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Canot create a fake hostent structure\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_zfree(req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_done(req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_post(req, ev);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return req;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = resolv_gethostbyname_step(req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret != EOK) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Cannot start the resolving\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_zfree(req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return req;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic bool
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_is_address(const char *name)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct addrinfo hints;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct addrinfo *res = NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen memset((void *) &hints, 0, sizeof(struct addrinfo));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen hints.ai_family = AF_UNSPEC;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen hints.ai_flags = AI_NUMERICHOST; /* No network lookups */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = getaddrinfo(name, NULL, &hints, &res);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen freeaddrinfo(res);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret != 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret == -2) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(9, ("[%s] does not look like an IP address\n", name));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(2, ("getaddrinfo failed [%d]: %s\n",
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret, gai_strerror(ret)));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ret == 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic errno_t
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_address(TALLOC_CTX *mem_ctx, const char *address,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_hostent **_rhostent)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_hostent *rhostent;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen TALLOC_CTX *tmp_ctx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen errno_t ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int family;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tmp_ctx = talloc_new(NULL);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!tmp_ctx) return ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent = talloc_zero(tmp_ctx, struct resolv_hostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!rhostent) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto done;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->name = talloc_strdup(rhostent, address);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->addr_list = talloc_array(rhostent, struct resolv_addr *, 2);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!rhostent->name ||
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen !rhostent->addr_list) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto done;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->addr_list[0] = talloc_zero(rhostent->addr_list,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_addr);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!rhostent->addr_list[0]) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto done;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->addr_list[0]->ipaddr = talloc_array(rhostent->addr_list[0],
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen uint8_t,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen sizeof(struct in6_addr));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!rhostent->addr_list[0]->ipaddr) {
49f8bdc504635afec3016a6973aac06d6ff8403fTimo Sirainen ret = ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto done;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen family = AF_INET;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = inet_pton(family, address,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->addr_list[0]->ipaddr);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret != 1) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen family = AF_INET6;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = inet_pton(family, address,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->addr_list[0]->ipaddr);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (ret != 1) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Could not parse address as neither v4 nor v6\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = EINVAL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen goto done;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->addr_list[0]->ttl = RESOLV_DEFAULT_TTL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->addr_list[1] = NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->family = family;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->aliases = NULL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *_rhostent = talloc_move(mem_ctx, &rhostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = EOK;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainendone:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_free(tmp_ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic inline int
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_family_init(enum restrict_family family_order)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen switch(family_order) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case IPV4_ONLY:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case IPV4_FIRST:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return AF_INET;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case IPV6_ONLY:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case IPV6_FIRST:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return AF_INET6;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Unknown address family order %d\n", family_order));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return -1;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic int
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_next(struct gethostbyname_state *state)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (state->family_order == IPV4_FIRST &&
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family == AF_INET) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family = AF_INET6;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EOK;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else if (state->family_order == IPV6_FIRST &&
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family == AF_INET6) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family = AF_INET;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EOK;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* No more address families for this DB, check if
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * there is another DB to try */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(5, ("No more address families to retry\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->dbi++;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (state->db[state->dbi] != DB_SENTINEL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family = resolv_gethostbyname_family_init(
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family_order);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EOK;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(4, ("No more hosts databases to retry\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ENOENT;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_done(struct tevent_req *subreq);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic errno_t
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_step(struct tevent_req *req)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_state *state = tevent_req_data(req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_state);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_req *subreq;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen switch(state->db[state->dbi]) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case DB_FILES:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(8, ("Querying files\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen subreq = resolv_gethostbyname_files_send(state, state->ev,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->resolv_ctx,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->name,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen break;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case DB_DNS:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(8, ("Querying DNS\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen subreq = resolv_gethostbyname_dns_send(state, state->ev,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->resolv_ctx,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->name,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen break;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen default:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Invalid hosts database\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EINVAL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (subreq == NULL) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ENOMEM;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_set_callback(subreq, resolv_gethostbyname_done, req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return EOK;
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen}
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_done(struct tevent_req *subreq)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_req *req = tevent_req_callback_data(subreq,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_state *state = tevent_req_data(req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_state);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen errno_t ret;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen switch(state->db[state->dbi]) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen case DB_FILES:
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = resolv_gethostbyname_files_recv(subreq, state,
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen &state->status,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen &state->rhostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* files is synchronous, there can be no timeouts */
state->timeouts = 0;
break;
case DB_DNS:
ret = resolv_gethostbyname_dns_recv(subreq, state,
&state->status, &state->timeouts,
&state->rhostent);
break;
default:
DEBUG(1, ("Invalid hosts database\n"));
tevent_req_error(req, EINVAL);
return;
}
talloc_zfree(subreq);
if (ret == ENOENT) {
ret = resolv_gethostbyname_next(state);
if (ret == EOK) {
ret = resolv_gethostbyname_step(req);
if (ret != EOK) {
tevent_req_error(req, ret);
}
return;
}
/* No more databases and/or address families */
tevent_req_error(req, ENOENT);
return;
}
if (ret != EOK) {
DEBUG(2, ("querying hosts database failed [%d]: %s\n",
ret, strerror(ret)));
tevent_req_error(req, ret);
return;
}
tevent_req_done(req);
}
int
resolv_gethostbyname_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
int *status, int *timeouts,
struct resolv_hostent **rhostent)
{
struct gethostbyname_state *state = tevent_req_data(req, struct gethostbyname_state);
/* Fill in even in case of error as status contains the
* c-ares return code */
if (status) {
*status = state->status;
}
if (timeouts) {
*timeouts = state->timeouts;
}
if (rhostent) {
*rhostent = talloc_steal(mem_ctx, state->rhostent);
}
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
char *
resolv_get_string_address_index(TALLOC_CTX *mem_ctx,
struct resolv_hostent *hostent,
unsigned int addrindex)
{
char *address;
if (!hostent) return NULL;
address = talloc_zero_size(mem_ctx, 128);
if (address == NULL) {
DEBUG(1, ("talloc_zero failed.\n"));
return NULL;
}
errno = 0;
if (inet_ntop(hostent->family, hostent->addr_list[addrindex]->ipaddr,
address, 128) == NULL) {
DEBUG(1, ("inet_ntop failed [%d][%s].\n", errno, strerror(errno)));
talloc_free(address);
return NULL;
}
return address;
}
struct sockaddr_storage *
resolv_get_sockaddr_address(TALLOC_CTX *mem_ctx, struct resolv_hostent *hostent,
int port)
{
struct sockaddr_storage *sockaddr;
if (!hostent) return NULL;
sockaddr = talloc_zero(mem_ctx, struct sockaddr_storage);
if (sockaddr == NULL) {
DEBUG(1, ("talloc_zero failed.\n"));
return NULL;
}
switch(hostent->family) {
case AF_INET:
sockaddr->ss_family = AF_INET;
memcpy(&((struct sockaddr_in *) sockaddr)->sin_addr,
hostent->addr_list[0]->ipaddr, sizeof(struct in_addr));
((struct sockaddr_in *) sockaddr)->sin_port = (in_port_t) htons(port);
break;
case AF_INET6:
sockaddr->ss_family = AF_INET6;
memcpy(&((struct sockaddr_in6 *) sockaddr)->sin6_addr,
hostent->addr_list[0]->ipaddr, sizeof(struct in6_addr));
((struct sockaddr_in6 *) sockaddr)->sin6_port = (in_port_t) htons(port);
break;
default:
DEBUG(1, ("Unknown address family %d\n"));
return NULL;
}
return sockaddr;
}
/*
* A simple helper function that will take an array of struct ares_srv_reply that
* was allocated by malloc() in c-ares and copies it using talloc. The old one
* is freed and the talloc one is put into 'reply_list' instead.
*/
static int
rewrite_talloc_srv_reply(TALLOC_CTX *mem_ctx, struct ares_srv_reply **reply_list)
{
struct ares_srv_reply *ptr = NULL;
struct ares_srv_reply *new_list = NULL;
struct ares_srv_reply *old_list = *reply_list;
/* Nothing to do, but not an error */
if (!old_list) {
return EOK;
}
/* Copy the linked list */
while (old_list) {
/* Special case for the first node */
if (!new_list) {
new_list = talloc_zero(mem_ctx, struct ares_srv_reply);
if (new_list == NULL) {
ares_free_data(*reply_list);
return ENOMEM;
}
ptr = new_list;
} else {
ptr->next = talloc_zero(new_list, struct ares_srv_reply);
if (ptr->next == NULL) {
ares_free_data(*reply_list);
talloc_free(new_list);
return ENOMEM;
}
ptr = ptr->next;
}
ptr->weight = old_list->weight;
ptr->priority = old_list->priority;
ptr->port = old_list->port;
ptr->host = talloc_strdup(ptr, old_list->host);
if (ptr->host == NULL) {
ares_free_data(*reply_list);
talloc_free(new_list);
return ENOMEM;
}
old_list = old_list->next;
}
/* Free the old one (uses malloc). */
ares_free_data(*reply_list);
/* And now put our own new_list in place. */
*reply_list = new_list;
return EOK;
}
/*******************************************************************
* Get SRV record *
*******************************************************************/
struct getsrv_state {
struct resolv_ctx *resolv_ctx;
/* the SRV query - for example _ldap._tcp.example.com */
const char *query;
/* parsed data returned by ares */
struct ares_srv_reply *reply_list;
int status;
int timeouts;
int retrying;
};
static void
ares_getsrv_wakeup(struct tevent_req *subreq);
struct tevent_req *
resolv_getsrv_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
struct resolv_ctx *ctx, const char *query)
{
struct tevent_req *req, *subreq;
struct getsrv_state *state;
struct timeval tv = { 0, 0 };
DEBUG(4, ("Trying to resolve SRV record of '%s'\n", query));
if (ctx->channel == NULL) {
DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
return NULL;
}
req = tevent_req_create(mem_ctx, &state, struct getsrv_state);
if (req == NULL)
return NULL;
state->resolv_ctx = ctx;
state->query = query;
state->reply_list = NULL;
state->status = 0;
state->timeouts = 0;
state->retrying = 0;
subreq = tevent_wakeup_send(req, ev, tv);
if (subreq == NULL) {
DEBUG(1, ("Failed to add critical timer to run next operation!\n"));
talloc_zfree(req);
return NULL;
}
tevent_req_set_callback(subreq, ares_getsrv_wakeup, req);
schedule_timeout_watcher(ev, ctx);
return req;
}
static void
resolv_getsrv_done(void *arg, int status, int timeouts, unsigned char *abuf, int alen)
{
struct tevent_req *req = talloc_get_type(arg, struct tevent_req);
struct getsrv_state *state = tevent_req_data(req, struct getsrv_state);
int ret;
struct ares_srv_reply *reply_list;
if (state->retrying == 0 && status == ARES_EDESTRUCTION
&& state->resolv_ctx->channel != NULL) {
state->retrying = 1;
ares_query(state->resolv_ctx->channel, state->query,
ns_c_in, ns_t_srv, resolv_getsrv_done, req);
return;
}
unschedule_timeout_watcher(state->resolv_ctx);
state->status = status;
state->timeouts = timeouts;
if (status != ARES_SUCCESS) {
ret = return_code(status);
goto fail;
}
ret = ares_parse_srv_reply(abuf, alen, &reply_list);
if (status != ARES_SUCCESS) {
DEBUG(2, ("SRV record parsing failed: %d: %s\n", ret, ares_strerror(ret)));
ret = return_code(ret);
goto fail;
}
ret = rewrite_talloc_srv_reply(req, &reply_list);
if (ret != EOK) {
goto fail;
}
state->reply_list = reply_list;
tevent_req_done(req);
return;
fail:
state->reply_list = NULL;
tevent_req_error(req, ret);
}
int
resolv_getsrv_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, int *status,
int *timeouts, struct ares_srv_reply **reply_list)
{
struct getsrv_state *state = tevent_req_data(req, struct getsrv_state);
if (status)
*status = state->status;
if (timeouts)
*timeouts = state->timeouts;
if (reply_list)
*reply_list = talloc_steal(mem_ctx, state->reply_list);
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
static void
ares_getsrv_wakeup(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct getsrv_state *state = tevent_req_data(req,
struct getsrv_state);
if (!tevent_wakeup_recv(subreq)) {
return;
}
talloc_zfree(subreq);
if (state->resolv_ctx->channel == NULL) {
DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
tevent_req_error(req, EIO);
return;
}
ares_query(state->resolv_ctx->channel, state->query,
ns_c_in, ns_t_srv, resolv_getsrv_done, req);
}
/* TXT parsing is not used anywhere in the code yet, so we disable it
* for now
*/
#ifdef BUILD_TXT
/*
* A simple helper function that will take an array of struct txt_reply that
* was allocated by malloc() in c-ares and copies it using talloc. The old one
* is freed and the talloc one is put into 'reply_list' instead.
*/
static int
rewrite_talloc_txt_reply(TALLOC_CTX *mem_ctx, struct ares_txt_reply **reply_list)
{
struct ares_txt_reply *ptr = NULL;
struct ares_txt_reply *new_list = NULL;
struct ares_txt_reply *old_list = *reply_list;
/* Nothing to do, but not an error */
if (!old_list) {
return EOK;
}
/* Copy the linked list */
while (old_list) {
/* Special case for the first node */
if (!new_list) {
new_list = talloc_zero(mem_ctx, struct ares_txt_reply);
if (new_list == NULL) {
ares_free_data(*reply_list);
talloc_free(new_list);
return ENOMEM;
}
ptr = new_list;
} else {
ptr->next = talloc_zero(new_list, struct ares_txt_reply);
if (ptr->next == NULL) {
ares_free_data(*reply_list);
talloc_free(new_list);
return ENOMEM;
}
ptr = ptr->next;
}
ptr->length = old_list->length;
ptr->txt = talloc_memdup(ptr, old_list->txt,
old_list->length);
if (ptr->txt == NULL) {
ares_free_data(*reply_list);
talloc_free(new_list);
return ENOMEM;
}
old_list = old_list->next;
}
ares_free_data(*reply_list);
/* And now put our own new_list in place. */
*reply_list = new_list;
return EOK;
}
/*******************************************************************
* Get TXT record *
*******************************************************************/
struct gettxt_state {
struct resolv_ctx *resolv_ctx;
/* the TXT query */
const char *query;
/* parsed data returned by ares */
struct ares_txt_reply *reply_list;
int status;
int timeouts;
int retrying;
};
static void
ares_gettxt_wakeup(struct tevent_req *subreq);
struct tevent_req *
resolv_gettxt_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
struct resolv_ctx *ctx, const char *query)
{
struct tevent_req *req, *subreq;
struct gettxt_state *state;
struct timeval tv = { 0, 0 };
DEBUG(4, ("Trying to resolve TXT record of '%s'\n", query));
if (ctx->channel == NULL) {
DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
return NULL;
}
req = tevent_req_create(mem_ctx, &state, struct gettxt_state);
if (req == NULL)
return NULL;
state->resolv_ctx = ctx;
state->query = query;
state->reply_list = NULL;
state->status = 0;
state->timeouts = 0;
state->retrying = 0;
subreq = tevent_wakeup_send(req, ev, tv);
if (subreq == NULL) {
DEBUG(1, ("Failed to add critical timer to run next operation!\n"));
talloc_zfree(req);
return NULL;
}
tevent_req_set_callback(subreq, ares_gettxt_wakeup, req);
schedule_timeout_watcher(ev, ctx);
return req;
}
static void
resolv_gettxt_done(void *arg, int status, int timeouts, unsigned char *abuf, int alen)
{
struct tevent_req *req = talloc_get_type(arg, struct tevent_req);
struct gettxt_state *state = tevent_req_data(req, struct gettxt_state);
int ret;
struct ares_txt_reply *reply_list;
if (state->retrying == 0 && status == ARES_EDESTRUCTION
&& state->resolv_ctx->channel != NULL) {
state->retrying = 1;
ares_query(state->resolv_ctx->channel, state->query,
ns_c_in, ns_t_txt, resolv_gettxt_done, req);
return;
}
unschedule_timeout_watcher(state->resolv_ctx);
state->status = status;
state->timeouts = timeouts;
if (status != ARES_SUCCESS) {
ret = return_code(status);
goto fail;
}
ret = ares_parse_txt_reply(abuf, alen, &reply_list);
if (status != ARES_SUCCESS) {
DEBUG(2, ("TXT record parsing failed: %d: %s\n", ret, ares_strerror(ret)));
ret = return_code(ret);
goto fail;
}
ret = rewrite_talloc_txt_reply(req, &reply_list);
if (ret != EOK) {
goto fail;
}
state->reply_list = reply_list;
tevent_req_done(req);
return;
fail:
state->reply_list = NULL;
tevent_req_error(req, ret);
}
int
resolv_gettxt_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, int *status,
int *timeouts, struct ares_txt_reply **reply_list)
{
struct gettxt_state *state = tevent_req_data(req, struct gettxt_state);
if (status)
*status = state->status;
if (timeouts)
*timeouts = state->timeouts;
if (reply_list)
*reply_list = talloc_steal(mem_ctx, state->reply_list);
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
static void
ares_gettxt_wakeup(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct gettxt_state *state = tevent_req_data(req,
struct gettxt_state);
if (!tevent_wakeup_recv(subreq)) {
return;
}
talloc_zfree(subreq);
if (state->resolv_ctx->channel == NULL) {
DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
tevent_req_error(req, EIO);
return;
}
ares_query(state->resolv_ctx->channel, state->query,
ns_c_in, ns_t_txt, resolv_gettxt_done, req);
}
#endif
static struct ares_srv_reply *split_reply_list(struct ares_srv_reply *list)
{
struct ares_srv_reply *single_step, *double_step, *prev;
if (!list) {
return NULL;
}
prev = list;
single_step = list->next;
double_step = single_step->next;
while (double_step && double_step->next) {
prev = single_step;
single_step = single_step->next;
double_step = double_step->next->next;
}
prev->next = NULL;
return single_step;
}
static struct ares_srv_reply *merge_reply_list(struct ares_srv_reply *left,
struct ares_srv_reply *right)
{
struct ares_srv_reply *l, *r;
struct ares_srv_reply *res, *res_start;
if (!left)
return right;
if (!right)
return left;
if (left->priority < right->priority) {
res_start = left;
l = left->next;
r = right;
} else {
res_start = right;
l = left;
r = right->next;
}
res = res_start;
while(l && r) {
if (l->priority < r->priority) {
res->next = l;
res = l;
l = l->next;
} else {
res->next = r;
res = r;
r = r->next;
}
}
res->next = l ? l : r;
return res_start;
}
/**
* sort linked list of struct ares_srv_reply by priority using merge sort.
*
* Merge sort is ideal for sorting linked lists as there is no problem
* with absence of random access into the list. The complexity is O(n log n)
*
* For reference, see Robert Sedgewick's "Algorithms in C", Addison-Wesley,
* ISBN 0-201-51425
*/
static struct ares_srv_reply *reply_priority_sort(struct ares_srv_reply *list)
{
struct ares_srv_reply *half;
if (!list || !list->next)
return list;
half = split_reply_list(list);
list = merge_reply_list(reply_priority_sort(list),
reply_priority_sort(half));
return list;
}
static int reply_weight_rearrange(TALLOC_CTX *mem_ctx,
int len,
struct ares_srv_reply **start,
struct ares_srv_reply **end)
{
int i;
int total, selected;
int *totals;
struct ares_srv_reply *r, *prev, *tmp;
struct ares_srv_reply *new_start = NULL;
struct ares_srv_reply *new_end = NULL;
if (len <= 1) {
return EOK;
}
totals = talloc_array(mem_ctx, int, len);
if (!totals) {
return ENOMEM;
}
srand(time(NULL) * getpid());
/* promote all servers with weight==0 to the top */
r = *(start);
prev = NULL;
while (r != NULL) {
if (r->weight == 0) {
/* remove from the old list */
if (prev) {
prev->next = r->next;
} else {
*start = r->next;
}
/* add to the head of the new list */
tmp = r;
r = r->next;
tmp->next = *start;
*start = tmp;
} else {
prev = r;
r = r->next;
}
}
*end = prev ? prev : *start;
while (*start != NULL) {
/* Commpute the sum of the weights of those RRs, and with each RR
* associate the running sum in the selected order.
*/
total = 0;
memset(totals, -1, sizeof(int) * len);
for (i = 0, r = *start; r != NULL; r=r->next, ++i) {
totals[i] = r->weight + total;
total = totals[i];
}
/* choose a uniform random number between 0 and the sum computed
* (inclusive), and select the RR whose running sum value is the
* first in the selected order which is greater than or equal to
* the random number selected.
*/
selected = (int)((total + 1) * (rand()/(RAND_MAX + 1.0)));
for (i = 0, r = *start, prev = NULL; r != NULL; r=r->next, ++i) {
if (totals[i] >= selected)
break;
prev = r;
}
if (r == NULL || totals[i] == -1) {
DEBUG(1, ("Bug: did not select any server!\n"));
return EIO;
}
/* remove r from the old list */
if (prev) {
prev->next = r->next;
} else {
*start = r->next;
}
/* add r to the end of the new list */
if (!new_start) {
new_start = r;
new_end = r;
} else {
new_end->next = r;
new_end = r;
}
}
new_end->next = NULL;
/* return the rearranged list */
*start = new_start;
*end = new_end;
talloc_free(totals);
return EOK;
}
int
resolv_sort_srv_reply(TALLOC_CTX *mem_ctx, struct ares_srv_reply **reply)
{
int ret;
struct ares_srv_reply *pri_start, *pri_end, *next, *prev_end;
int len;
/* RFC 2782 says: If there is precisely one SRV RR, and its Target is "."
* (the root domain), abort.
*/
if (*reply && !(*reply)->next && strcmp((*reply)->host, ".") == 0) {
DEBUG(1, ("DNS returned only the root domain, aborting\n"));
return EIO;
}
/* sort the list by priority */
*reply = reply_priority_sort(*reply);
pri_start = *reply;
prev_end = NULL;
while (pri_start) {
pri_end = pri_start;
/* Find nodes with the same priority */
len = 1;
while (pri_end->next && pri_end->priority == pri_end->next->priority) {
pri_end = pri_end->next;
len++;
}
/* rearrange each priority level according to the weight field */
next = pri_end->next;
pri_end->next = NULL;
ret = reply_weight_rearrange(mem_ctx, len, &pri_start, &pri_end);
if (ret) {
DEBUG(1, ("Error rearranging priority level [%d]: %s\n",
ret, strerror(ret)));
return ret;
}
/* Hook the level back into the list */
if (prev_end) {
prev_end->next = pri_start;
} else {
*reply = pri_start;
}
pri_end->next = next;
/* Move on to the next level */
prev_end = pri_end;
pri_start = next;
}
return EOK;
}