async_resolv.c revision 3d334807f302603b81996b41f2a365ce75f36d17
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher/*
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher SSSD
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher Async resolver
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher Authors:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher Martin Nagy <mnagy@redhat.com>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher Jakub Hrozek <jhrozek@redhat.com>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher Copyright (C) Red Hat, Inc 2009
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher This program is free software; you can redistribute it and/or modify
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher it under the terms of the GNU General Public License as published by
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher the Free Software Foundation; either version 3 of the License, or
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher (at your option) any later version.
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher This program is distributed in the hope that it will be useful,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher but WITHOUT ANY WARRANTY; without even the implied warranty of
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher GNU General Public License for more details.
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher You should have received a copy of the GNU General Public License
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher along with this program. If not, see <http://www.gnu.org/licenses/>.
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher*/
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <sys/select.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <arpa/inet.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <arpa/nameser.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <ares.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <talloc.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <tevent.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <errno.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <netdb.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <stddef.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <string.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include <unistd.h>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "config.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "resolv/async_resolv.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "util/dlinklist.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#include "util/util.h"
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#ifndef HAVE_ARES_DATA
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#define ares_parse_srv_reply(abuf, alen, srv_out) \
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher _ares_parse_srv_reply(abuf, alen, srv_out)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#define ares_parse_txt_reply(abuf, alen, txt_out) \
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher _ares_parse_txt_reply(abuf, alen, txt_out)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#define ares_free_data(dataptr) \
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher _ares_free_data(dataptr)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#define ares_malloc_data(data) \
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher _ares_malloc_data(data)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#endif /* HAVE_ARES_DATA */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#define DNS__16BIT(p) (((p)[0] << 8) | (p)[1])
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher#define DNS_HEADER_ANCOUNT(h) DNS__16BIT((h) + 6)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstruct fd_watch {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct fd_watch *prev;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct fd_watch *next;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int fd;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_ctx *ctx;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct tevent_fd *fde;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher};
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstruct resolv_ctx {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Contexts are linked so we can keep track of them and re-create
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * the ares channels in all of them at once if we need to. */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_ctx *prev;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_ctx *next;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct tevent_context *ev_ctx;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ares_channel channel;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* List of file descriptors that are watched by tevent. */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct fd_watch *fds;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Time in milliseconds before canceling a DNS request */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int timeout;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* The timeout watcher periodically calls ares_process_fd() to check
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * if our pending requests didn't timeout. */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int pending_requests;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct tevent_timer *timeout_watcher;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher};
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstruct resolv_ctx *context_list;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic int
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherreturn_code(int ares_code)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher switch (ares_code) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher case ARES_SUCCESS:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return EOK;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher case ARES_ENOMEM:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return ENOMEM;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher case ARES_EFILE:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher default:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return EIO;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherconst char *
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherresolv_strerror(int ares_code)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return ares_strerror(ares_code);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic int
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherfd_watch_destructor(struct fd_watch *f)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DLIST_REMOVE(f->ctx->fds, f);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher f->fd = -1;
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher return 0;
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher}
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagherstatic void
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagherfd_input_available(struct tevent_context *ev, struct tevent_fd *fde,
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher uint16_t flags, void *data)
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher{
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher struct fd_watch *watch = talloc_get_type(data, struct fd_watch);
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher if (watch->ctx->channel == NULL) {
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher return;
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher }
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher if (flags & TEVENT_FD_READ) {
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher ares_process_fd(watch->ctx->channel, watch->fd, ARES_SOCKET_BAD);
346f41f1ede975cb2db0af570f5b454b9b306704Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (flags & TEVENT_FD_WRITE) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ares_process_fd(watch->ctx->channel, ARES_SOCKET_BAD, watch->fd);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallaghercheck_fd_timeouts(struct tevent_context *ev, struct tevent_timer *te,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct timeval current_time, void *private_data);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagheradd_timeout_timer(struct tevent_context *ev, struct resolv_ctx *ctx)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct timeval tv = { 0, 0 };
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny struct timeval *tvp;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny tvp = ares_timeout(ctx->channel, NULL, &tv);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (tvp == NULL) {
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny tvp = &tv;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny }
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek /* Enforce a minimum of 1 second. */
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (tvp->tv_sec < 1) {
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny tv = tevent_timeval_current_ofs(1, 0);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny } else {
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny tv = tevent_timeval_current_ofs(tvp->tv_sec, tvp->tv_usec);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny }
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny ctx->timeout_watcher = tevent_add_timer(ev, ctx, tv, check_fd_timeouts,
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny ctx);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (ctx->timeout_watcher == NULL) {
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny DEBUG(1, ("Out of memory\n"));
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny }
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny}
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenystatic void
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenycheck_fd_timeouts(struct tevent_context *ev, struct tevent_timer *te,
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny struct timeval current_time, void *private_data)
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny{
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny struct resolv_ctx *ctx = talloc_get_type(private_data, struct resolv_ctx);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek DEBUG(9, ("Checking for DNS timeouts\n"));
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek /* NULLify the timeout_watcher so we don't
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek * free it in the _done() function if it
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek * gets called. Now that we're already in
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek * the handler, tevent will take care of
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek * freeing it when it returns.
4a1e58d85409fbb7a12ac244c3dbef8c0c1b15dfMichal Zidek */
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny ctx->timeout_watcher = NULL;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny ares_process_fd(ctx->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (ctx->pending_requests > 0) {
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny add_timeout_timer(ev, ctx);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny }
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny}
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenystatic void
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenyschedule_timeout_watcher(struct tevent_context *ev, struct resolv_ctx *ctx)
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny{
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny ctx->pending_requests++;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (ctx->timeout_watcher) {
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny return;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny }
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny DEBUG(9, ("Scheduling DNS timeout watcher\n"));
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny add_timeout_timer(ev, ctx);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny}
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenystatic void
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenyunschedule_timeout_watcher(struct resolv_ctx *ctx)
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny{
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (ctx->pending_requests <= 0) {
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny DEBUG(1, ("Pending DNS requests mismatch\n"));
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny ctx->pending_requests--;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (ctx->pending_requests == 0) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DEBUG(9, ("Unscheduling DNS timeout watcher\n"));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher talloc_zfree(ctx->timeout_watcher);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void fd_event_add(struct resolv_ctx *ctx, int s, int flags);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void fd_event_close(struct resolv_ctx *ctx, int s);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher/*
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * When ares is ready to read or write to a file descriptor, it will
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * call this callback. If both read and write are 0, it means that ares
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * will soon close the socket. We are mainly using this function to register
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * new file descriptors with tevent.
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherfd_event(void *data, int s, int fd_read, int fd_write)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_ctx *ctx = talloc_get_type(data, struct resolv_ctx);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct fd_watch *watch;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int flags;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* The socket is about to get closed. */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (fd_read == 0 && fd_write == 0) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher fd_event_close(ctx, s);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher flags = fd_read ? TEVENT_FD_READ : 0;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher flags |= fd_write ? TEVENT_FD_WRITE : 0;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Are we already watching this file descriptor? */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher watch = ctx->fds;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher while (watch) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (watch->fd == s) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher tevent_fd_set_flags(watch->fde, flags);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher watch = watch->next;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher fd_event_add(ctx, s, flags);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherfd_event_add(struct resolv_ctx *ctx, int s, int flags)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct fd_watch *watch;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* The file descriptor is new, register it with tevent. */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher watch = talloc(ctx, struct fd_watch);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (watch == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DEBUG(1, ("Out of memory allocating fd_watch structure\n"));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher talloc_set_destructor(watch, fd_watch_destructor);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher watch->fd = s;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher watch->ctx = ctx;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher watch->fde = tevent_add_fd(ctx->ev_ctx, watch, s, flags,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher fd_input_available, watch);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny if (watch->fde == NULL) {
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny DEBUG(1, ("tevent_add_fd() failed\n"));
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny talloc_free(watch);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny return;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny }
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny DLIST_ADD(ctx->fds, watch);
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny}
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenystatic void
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zelenyfd_event_close(struct resolv_ctx *ctx, int s)
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny{
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny struct fd_watch *watch;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Remove the socket from list */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher watch = ctx->fds;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny while (watch) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (watch->fd == s) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher talloc_free(watch);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny watch = watch->next;
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny }
016e0d7202ff965018e41869c5ab501f86b0d081Jan Zeleny}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic int
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherresolv_ctx_destructor(struct resolv_ctx *ctx)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ares_channel channel;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DLIST_REMOVE(context_list, ctx);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ctx->channel == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DEBUG(1, ("Ares channel already destroyed?\n"));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return -1;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Set ctx->channel to NULL first, so that callbacks that get
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * ARES_EDESTRUCTION won't retry. */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher channel = ctx->channel;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ctx->channel = NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ares_destroy(channel);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return 0;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic int
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherrecreate_ares_channel(struct resolv_ctx *ctx)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ares_channel new_channel;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ares_channel old_channel;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct ares_options options;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DEBUG(4, ("Initializing new c-ares channel\n"));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* FIXME: the options would contain
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * the nameservers to contact, the domains
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * to search... => get from confdb
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher options.sock_state_cb = fd_event;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher options.sock_state_cb_data = ctx;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher options.timeout = ctx->timeout * 1000;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher options.lookups = discard_const("fb");
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher options.tries = 1;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret = ares_init_options(&new_channel, &options,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ARES_OPT_SOCK_STATE_CB |
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ARES_OPT_TIMEOUTMS |
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ARES_OPT_LOOKUPS |
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ARES_OPT_TRIES);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret != ARES_SUCCESS) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DEBUG(1, ("Failed to initialize ares channel: %s\n",
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher resolv_strerror(ret)));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return return_code(ret);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher old_channel = ctx->channel;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ctx->channel = new_channel;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (old_channel != NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DEBUG(4, ("Destroying the old c-ares channel\n"));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ares_destroy(old_channel);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return EOK;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherint
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherresolv_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int timeout, struct resolv_ctx **ctxp)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_ctx *ctx;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (timeout < 1) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return EINVAL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ctx = talloc_zero(mem_ctx, struct resolv_ctx);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ctx == NULL)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return ENOMEM;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ctx->ev_ctx = ev_ctx;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ctx->timeout = timeout;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret = recreate_ares_channel(ctx);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret != EOK) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto done;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DLIST_ADD(context_list, ctx);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher talloc_set_destructor(ctx, resolv_ctx_destructor);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher *ctxp = ctx;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return EOK;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherdone:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher talloc_free(ctx);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallaghervoid
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherresolv_reread_configuration(void)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_ctx *ctx;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DEBUG(4, ("Recreating all c-ares channels\n"));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DLIST_FOR_EACH(ctx, context_list) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher recreate_ares_channel(ctx);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstruct hostent *
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherresolv_copy_hostent(TALLOC_CTX *mem_ctx, struct hostent *src)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct hostent *ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int len;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int i;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret = talloc_zero(mem_ctx, struct hostent);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (src->h_name != NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->h_name = talloc_strdup(ret, src->h_name);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret->h_name == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (src->h_aliases != NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (len = 0; src->h_aliases[len] != NULL; len++);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->h_aliases = talloc_size(ret, sizeof(char *) * (len + 1));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret->h_aliases == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (i = 0; i < len; i++) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->h_aliases[i] = talloc_strdup(ret->h_aliases, src->h_aliases[i]);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret->h_aliases[i] == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->h_aliases[len] = NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->h_addrtype = src->h_addrtype;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->h_length = src->h_length;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (src->h_addr_list != NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (len = 0; src->h_addr_list[len] != NULL; len++);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->h_addr_list = talloc_size(ret, sizeof(char *) * (len + 1));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret->h_addr_list == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (i = 0; i < len; i++) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->h_addr_list[i] = talloc_memdup(ret->h_addr_list,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher src->h_addr_list[i],
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->h_length);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret->h_addr_list[i] == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->h_addr_list[len] = NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherfail:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher talloc_free(ret);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic errno_t
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherresolv_copy_in_addr(TALLOC_CTX *mem_ctx, struct resolv_addr *ret,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct ares_addrttl *attl)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->ipaddr = talloc_array(mem_ctx, uint8_t, sizeof(struct in_addr));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (!ret->ipaddr) return ENOMEM;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher memcpy(ret->ipaddr, &attl->ipaddr, sizeof(struct in_addr));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->ttl = attl->ttl;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return EOK;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic errno_t
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherresolv_copy_in6_addr(TALLOC_CTX *mem_ctx, struct resolv_addr *ret,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct ares_addr6ttl *a6ttl)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->ipaddr = talloc_array(mem_ctx, uint8_t, sizeof(struct in6_addr));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (!ret->ipaddr) return ENOMEM;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher memcpy(ret->ipaddr, &a6ttl->ip6addr, sizeof(struct in6_addr));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->ttl = a6ttl->ttl;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return EOK;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic struct resolv_hostent *
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherresolv_copy_hostent_common(TALLOC_CTX *mem_ctx, struct hostent *src)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_hostent *ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int len;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int i;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret = talloc_zero(mem_ctx, struct resolv_hostent);
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher if (ret == NULL) {
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher return NULL;
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher }
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher if (src->h_name != NULL) {
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher ret->name = talloc_strdup(ret, src->h_name);
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher if (ret->name == NULL) {
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher goto fail;
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher }
4e2d9fe30bf8b692972a9654c60d2d90ed355815Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (src->h_aliases != NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (len = 0; src->h_aliases[len] != NULL; len++);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->aliases = talloc_array(ret, char *, len + 1);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret->aliases == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (i = 0; i < len; i++) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->aliases[i] = talloc_strdup(ret->aliases, src->h_aliases[i]);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret->aliases[i] == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->aliases[len] = NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->family = src->h_addrtype;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherfail:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher talloc_free(ret);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstruct resolv_hostent *
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherresolv_copy_hostent2(TALLOC_CTX *mem_ctx, struct hostent *src)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_hostent *ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int len;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int i;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret = resolv_copy_hostent_common(mem_ctx, src);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (src->h_addr_list != NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (len = 0; src->h_addr_list[len] != NULL; len++);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->addr_list = talloc_array(ret, struct resolv_addr *, len + 1);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret->addr_list == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (i = 0; i < len; i++) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->addr_list[i] = talloc_zero(ret->addr_list,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_addr);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret->addr_list[i] == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->addr_list[i]->ipaddr = talloc_memdup(ret->addr_list[i],
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher src->h_addr_list[i],
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher src->h_length);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret->addr_list[i]->ipaddr == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->addr_list[i]->ttl = RESOLV_DEFAULT_TTL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->addr_list[len] = NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherfail:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher talloc_free(ret);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstruct resolv_hostent *
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherresolv_copy_hostent_ares(TALLOC_CTX *mem_ctx, struct hostent *src,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int family, void *ares_ttl_data,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int num_ares_ttl_data)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_hostent *ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher errno_t cret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int i;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret = resolv_copy_hostent_common(mem_ctx, src);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (num_ares_ttl_data > 0) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->addr_list = talloc_array(ret, struct resolv_addr *,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher num_ares_ttl_data + 1);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret->addr_list == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (i = 0; i < num_ares_ttl_data; i++) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->addr_list[i] = talloc_zero(ret->addr_list,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_addr);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (ret->addr_list[i] == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher switch (family) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher case AF_INET:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher cret = resolv_copy_in_addr(ret->addr_list, ret->addr_list[i],
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher &((struct ares_addrttl *) ares_ttl_data)[i]);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher break;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher case AF_INET6:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher cret = resolv_copy_in6_addr(ret->addr_list, ret->addr_list[i],
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher &((struct ares_addr6ttl *) ares_ttl_data)[i]);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher break;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher default:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DEBUG(1, ("Unknown address family %d\n"));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (cret != EOK) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DEBUG(1, ("Could not copy address\n"));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto fail;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->addr_list[num_ares_ttl_data] = NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ret->family = family;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return ret;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherfail:
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher talloc_free(ret);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher}
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher/* =================== Resolve host name in files =========================*/
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstruct gethostbyname_files_state {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_ctx *resolv_ctx;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Part of the query. */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher const char *name;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int family;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* query result */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_hostent *rhostent;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* returned by ares. */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int status;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher};
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher/* Fake up an async interface even though files would
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * always be blocking */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic struct tevent_req *
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherresolv_gethostbyname_files_send(TALLOC_CTX *mem_ctx,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct tevent_context *ev,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct resolv_ctx *ctx,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher const char *name,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher int family)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher{
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct tevent_req *req;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct gethostbyname_files_state *state;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct hostent *hostent = NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher req = tevent_req_create(mem_ctx, &state,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct gethostbyname_files_state);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (req == NULL) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher tevent_req_error(req, ENOMEM);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher goto done;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher }
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher state->resolv_ctx = ctx;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher state->name = name;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher state->rhostent = NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher state->family = family;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher DEBUG(4, ("Trying to resolve %s record of '%s' in files\n",
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher state->family == AF_INET ? "A" : "AAAA", state->name));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher state->status = ares_gethostbyname_file(state->resolv_ctx->channel,
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher state->name, state->family,
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher &hostent);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher if (state->status == ARES_SUCCESS) {
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher state->rhostent = resolv_copy_hostent2(state, hostent);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher if (state->rhostent == NULL) {
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher tevent_req_error(req, ENOMEM);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher goto done;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher }
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher } else if (state->status == ARES_ENOTFOUND ||
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher state->status == ARES_ENODATA) {
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher /* Just say we didn't find anything and let the caller decide
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher * about retrying */
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher tevent_req_error(req, ENOENT);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher goto done;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher } else {
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher tevent_req_error(req, return_code(state->status));
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher goto done;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher }
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher tevent_req_done(req);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagherdone:
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher if (hostent) ares_free_hostent(hostent);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher tevent_req_post(req, ev);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher return req;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher}
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagherstatic errno_t
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagherresolv_gethostbyname_files_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher int *status, struct resolv_hostent **rhostent)
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher{
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher struct gethostbyname_files_state *state = tevent_req_data(req,
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher struct gethostbyname_files_state);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher /* Fill in even in case of error as status contains the
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher * c-ares return code */
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher if (status) {
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher *status = state->status;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher }
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher if (rhostent) {
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher *rhostent = talloc_steal(mem_ctx, state->rhostent);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher }
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher TEVENT_REQ_RETURN_ON_ERROR(req);
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher return EOK;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher}
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher/* ==================== Resolve host name in DNS =========================*/
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagherstruct gethostbyname_dns_state {
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher struct resolv_ctx *resolv_ctx;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher struct tevent_context *ev;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher /* Part of the query. */
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher const char *name;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher int family;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher /* query result */
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher struct resolv_hostent *rhostent;
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher /* These are returned by ares. */
d92c50f6d75ae980b0d130134112a33e1584724cStephen Gallagher int status;
int timeouts;
int retrying;
};
static void
resolv_gethostbyname_dns_wakeup(struct tevent_req *subreq);
static void
resolv_gethostbyname_dns_query(struct tevent_req *req,
struct gethostbyname_dns_state *state);
static void
resolv_gethostbyname_dns_query_done(void *arg, int status, int timeouts,
unsigned char *abuf, int alen);
static int
resolv_gethostbyname_dns_parse(struct gethostbyname_dns_state *state, int status,
int timeouts, unsigned char *abuf, int alen);
static struct tevent_req *
resolv_gethostbyname_dns_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
struct resolv_ctx *ctx, const char *name,
int family)
{
struct tevent_req *req, *subreq;
struct gethostbyname_dns_state *state;
struct timeval tv = { 0, 0 };
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 gethostbyname_dns_state);
if (req == NULL) {
return NULL;
}
state->resolv_ctx = ctx;
state->ev = ev;
state->name = name;
state->rhostent = NULL;
state->status = 0;
state->timeouts = 0;
state->retrying = 0;
state->family = family;
/* We need to have a wrapper around ares async calls, because
* they can in some cases call it's callback immediately.
* This would not let our caller to set a callback for req. */
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, resolv_gethostbyname_dns_wakeup, req);
schedule_timeout_watcher(ev, ctx);
return req;
}
static void
resolv_gethostbyname_dns_wakeup(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct gethostbyname_dns_state *state = tevent_req_data(req,
struct gethostbyname_dns_state);
if (!tevent_wakeup_recv(subreq)) {
tevent_req_error(req, EIO);
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;
}
resolv_gethostbyname_dns_query(req, state);
}
static void
resolv_gethostbyname_dns_query(struct tevent_req *req,
struct gethostbyname_dns_state *state)
{
DEBUG(4, ("Trying to resolve %s record of '%s' in DNS\n",
state->family == AF_INET ? "A" : "AAAA", state->name));
ares_query(state->resolv_ctx->channel,
state->name, ns_c_in,
(state->family == AF_INET) ? ns_t_a : ns_t_aaaa,
resolv_gethostbyname_dns_query_done, req);
}
static void
resolv_gethostbyname_dns_query_done(void *arg, int status, int timeouts,
unsigned char *abuf, int alen)
{
struct tevent_req *req = talloc_get_type(arg, struct tevent_req);
struct gethostbyname_dns_state *state = tevent_req_data(req,
struct gethostbyname_dns_state);
errno_t ret;
unschedule_timeout_watcher(state->resolv_ctx);
state->status = status;
state->timeouts = timeouts;
/* If resolv.conf changed during processing of a request we might
* destroy the old channel before the request has a chance to finish.
* We must resend the request in this case */
if (state->retrying == 0 && status == ARES_EDESTRUCTION
&& state->resolv_ctx->channel != NULL) {
state->retrying = 1;
schedule_timeout_watcher(state->ev, state->resolv_ctx);
resolv_gethostbyname_dns_query(req, state);
return;
}
if (status == ARES_ENOTFOUND || status == ARES_ENODATA) {
/* Just say we didn't find anything and let the caller decide
* about retrying */
tevent_req_error(req, ENOENT);
return;
}
if (status != ARES_SUCCESS) {
/* Any other error indicates a server error,
* so don't bother trying again
*/
tevent_req_error(req, return_code(status));
return;
}
ret = resolv_gethostbyname_dns_parse(state, status, timeouts, abuf, alen);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
tevent_req_done(req);
}
static int
resolv_gethostbyname_dns_parse(struct gethostbyname_dns_state *state,
int status, int timeouts,
unsigned char *abuf, int alen)
{
TALLOC_CTX *tmp_ctx;
struct hostent *hostent;
int naddrttls;
errno_t ret;
void *addr;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
naddrttls = DNS_HEADER_ANCOUNT(abuf);
switch (state->family) {
case AF_INET:
DEBUG(7, ("Parsing an A reply\n"));
addr = talloc_array(state, struct ares_addrttl, naddrttls);
if (!addr) {
ret = ENOMEM;
goto fail;
}
status = ares_parse_a_reply(abuf, alen, &hostent,
(struct ares_addrttl *) addr,
&naddrttls);
break;
case AF_INET6:
DEBUG(7, ("Parsing an AAAA reply\n"));
addr = talloc_array(state, struct ares_addr6ttl, naddrttls);
if (!addr) {
ret = ENOMEM;
goto fail;
}
status = ares_parse_aaaa_reply(abuf, alen, &hostent,
(struct ares_addr6ttl *) addr,
&naddrttls);
break;
default:
DEBUG(1, ("Unknown family %d\n", state->family));
ret = EAFNOSUPPORT;
goto fail;
}
if (hostent != NULL) {
state->rhostent = resolv_copy_hostent_ares(state, hostent,
state->family,
addr, naddrttls);
free(hostent);
if (state->rhostent == NULL) {
ret = ENOMEM;
goto fail;
}
}
talloc_free(tmp_ctx);
return return_code(status);
fail:
talloc_free(tmp_ctx);
return ret;
}
static int
resolv_gethostbyname_dns_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
int *status, int *timeouts,
struct resolv_hostent **rhostent)
{
struct gethostbyname_dns_state *state = tevent_req_data(req,
struct gethostbyname_dns_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;
}
/*******************************************************************
* Get host by name. *
*******************************************************************/
struct gethostbyname_state {
struct resolv_ctx *resolv_ctx;
/* Part of the query. */
const char *name;
int family;
/* In which order to use IPv4, or v6 */
enum restrict_family family_order;
/* These are returned by ares. The hostent struct will be freed
* when the user callback returns. */
struct hostent *hostent;
int status;
int timeouts;
int retrying;
};
static void
ares_gethostbyname_wakeup(struct tevent_req *req);
struct tevent_req *
resolv_gethostbyname_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
struct resolv_ctx *ctx, const char *name,
enum restrict_family family_order)
{
struct tevent_req *req, *subreq;
struct gethostbyname_state *state;
struct timeval tv = { 0, 0 };
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 gethostbyname_state);
if (req == NULL)
return NULL;
state->resolv_ctx = ctx;
state->name = name;
state->hostent = NULL;
state->status = 0;
state->timeouts = 0;
state->retrying = 0;
state->family_order = family_order;
state->family = (family_order < IPV6_ONLY) ? AF_INET : AF_INET6;
DEBUG(4, ("Trying to resolve %s record of '%s'\n",
state->family == AF_INET ? "A" : "AAAA",
state->name));
/* We need to have a wrapper around ares_gethostbyname(), because
* ares_gethostbyname() can in some cases call it's callback immediately.
* This would not let our caller to set a callback for req. */
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_gethostbyname_wakeup, req);
schedule_timeout_watcher(ev, ctx);
return req;
}
static void
resolv_gethostbyname_next_done(void *arg, int status, int timeouts, struct hostent *hostent);
static void
resolv_gethostbyname_done(void *arg, int status, int timeouts, struct hostent *hostent)
{
struct tevent_req *req = talloc_get_type(arg, struct tevent_req);
struct gethostbyname_state *state = tevent_req_data(req, struct gethostbyname_state);
if (state->retrying == 0 && status == ARES_EDESTRUCTION
&& state->resolv_ctx->channel != NULL) {
state->retrying = 1;
ares_gethostbyname(state->resolv_ctx->channel, state->name,
state->family, resolv_gethostbyname_done, req);
return;
}
unschedule_timeout_watcher(state->resolv_ctx);
if (hostent != NULL) {
state->hostent = resolv_copy_hostent(req, hostent);
if (state->hostent == NULL) {
tevent_req_error(req, ENOMEM);
return;
}
} else {
state->hostent = NULL;
}
state->status = status;
state->timeouts = timeouts;
if (status != ARES_SUCCESS) {
if (status == ARES_ENOTFOUND || status == ARES_ENODATA) {
if (state->family_order == IPV4_FIRST) {
state->family = AF_INET6;
} else if (state->family_order == IPV6_FIRST) {
state->family = AF_INET;
} else {
tevent_req_error(req, return_code(status));
return;
}
state->retrying = 0;
state->timeouts = 0;
DEBUG(4, ("Trying to resolve %s record of '%s'\n",
state->family == AF_INET ? "A" : "AAAA",
state->name));
schedule_timeout_watcher(state->resolv_ctx->ev_ctx,
state->resolv_ctx);
ares_gethostbyname(state->resolv_ctx->channel, state->name,
state->family, resolv_gethostbyname_next_done,
req);
return;
}
/* Any other error indicates a server error,
* so don't bother trying again
*/
tevent_req_error(req, return_code(status));
}
else {
tevent_req_done(req);
}
}
static void
resolv_gethostbyname_next_done(void *arg, int status, int timeouts, struct hostent *hostent)
{
struct tevent_req *req = talloc_get_type(arg, struct tevent_req);
struct gethostbyname_state *state = tevent_req_data(req, struct gethostbyname_state);
if (state->retrying == 0 && status == ARES_EDESTRUCTION) {
state->retrying = 1;
ares_gethostbyname(state->resolv_ctx->channel, state->name,
state->family, resolv_gethostbyname_next_done, req);
return;
}
unschedule_timeout_watcher(state->resolv_ctx);
if (hostent != NULL) {
state->hostent = resolv_copy_hostent(req, hostent);
if (state->hostent == NULL) {
tevent_req_error(req, ENOMEM);
return;
}
} else {
state->hostent = NULL;
}
state->status = status;
state->timeouts = timeouts;
if (status != ARES_SUCCESS) {
tevent_req_error(req, return_code(status));
}
else {
tevent_req_done(req);
}
}
int
resolv_gethostbyname_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
int *status, int *timeouts,
struct hostent **hostent)
{
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 (hostent) {
*hostent = talloc_steal(mem_ctx, state->hostent);
}
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
char *
resolv_get_string_address(TALLOC_CTX *mem_ctx, struct hostent *hostent)
{
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->h_addrtype, hostent->h_addr_list[0],
address, 128) == NULL) {
DEBUG(1, ("inet_ntop failed [%d][%s].\n", errno, strerror(errno)));
talloc_free(address);
return NULL;
}
return address;
}
static void
ares_gethostbyname_wakeup(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct gethostbyname_state *state = tevent_req_data(req,
struct gethostbyname_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_gethostbyname(state->resolv_ctx->channel, state->name,
state->family, resolv_gethostbyname_done, req);
}
/*
* 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;
}