async_resolv.c revision 19c6d0bf5346dc1862d14f7f3d886895cfb4d548
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen Async resolver
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen Martin Nagy <mnagy@redhat.com>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen Jakub Hrozek <jhrozek@redhat.com>
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen Copyright (C) Red Hat, Inc 2009
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 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 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#define ares_parse_srv_reply(abuf, alen, srv_out) \
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#define ares_parse_txt_reply(abuf, alen, txt_out) \
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#endif /* HAVE_ARES_DATA */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen#define DNS_HEADER_ANCOUNT(h) DNS__16BIT((h) + 6)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenenum host_database default_host_dbs[] = { DB_FILES, DB_DNS, DB_SENTINEL };
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 /* List of file descriptors that are watched by tevent. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Time in milliseconds before canceling a DNS request */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* The timeout watcher periodically calls ares_process_fd() to check
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * if our pending requests didn't timeout. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_get_family_order(struct confdb_ctx *cdb, const char *conf_path,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = confdb_get_string(cdb, tmp_ctx, conf_path,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else if (strcasecmp(str_opt, "ipv4_only") == 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else if (strcasecmp(str_opt, "ipv6_first") == 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else if (strcasecmp(str_opt, "ipv6_only") == 0) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Unknown value for option %s: %s\n",
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenfd_input_available(struct tevent_context *ev, struct tevent_fd *fde,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct fd_watch *watch = talloc_get_type(data, struct fd_watch);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ares_process_fd(watch->ctx->channel, watch->fd, ARES_SOCKET_BAD);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ares_process_fd(watch->ctx->channel, ARES_SOCKET_BAD, watch->fd);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainencheck_fd_timeouts(struct tevent_context *ev, struct tevent_timer *te,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct timeval current_time, void *private_data);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenadd_timeout_timer(struct tevent_context *ev, struct resolv_ctx *ctx)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Enforce a minimum of 1 second. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tv = tevent_timeval_current_ofs(tvp->tv_sec, tvp->tv_usec);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ctx->timeout_watcher = tevent_add_timer(ev, ctx, tv, check_fd_timeouts,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainencheck_fd_timeouts(struct tevent_context *ev, struct tevent_timer *te,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct timeval current_time, void *private_data)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *ctx = talloc_get_type(private_data, struct resolv_ctx);
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 ares_process_fd(ctx->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenschedule_timeout_watcher(struct tevent_context *ev, struct resolv_ctx *ctx)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(9, ("Scheduling DNS timeout watcher\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenunschedule_timeout_watcher(struct resolv_ctx *ctx)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Pending DNS requests mismatch\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(9, ("Unscheduling DNS timeout watcher\n"));
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 * 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 Sirainenfd_event(void *data, int s, int fd_read, int fd_write)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct resolv_ctx *ctx = talloc_get_type(data, struct resolv_ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* The socket is about to get closed. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Are we already watching this file descriptor? */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenfd_event_add(struct resolv_ctx *ctx, int s, int flags)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* The file descriptor is new, register it with tevent. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Out of memory allocating fd_watch structure\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_set_destructor(watch, fd_watch_destructor);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen watch->fde = tevent_add_fd(ctx->ev_ctx, watch, s, flags,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Remove the socket from list */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Ares channel already destroyed?\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Set ctx->channel to NULL first, so that callbacks that get
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * ARES_EDESTRUCTION won't retry. */
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 /* Only affects ares_gethostbyname */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = ares_init_options(&new_channel, &options,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Failed to initialize ares channel: %s\n",
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(4, ("Destroying the old c-ares channel\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ctx = talloc_zero(mem_ctx, struct resolv_ctx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen talloc_set_destructor(ctx, resolv_ctx_destructor);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(4, ("Recreating all c-ares channels\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_copy_in_addr(TALLOC_CTX *mem_ctx, struct resolv_addr *ret,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->ipaddr = talloc_array(mem_ctx, uint8_t, sizeof(struct in_addr));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen memcpy(ret->ipaddr, &attl->ipaddr, sizeof(struct in_addr));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_copy_in6_addr(TALLOC_CTX *mem_ctx, struct resolv_addr *ret,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->ipaddr = talloc_array(mem_ctx, uint8_t, sizeof(struct in6_addr));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen memcpy(ret->ipaddr, &a6ttl->ip6addr, sizeof(struct in6_addr));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_copy_hostent_common(TALLOC_CTX *mem_ctx, struct hostent *src)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = talloc_zero(mem_ctx, struct resolv_hostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (len = 0; src->h_aliases[len] != NULL; len++);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->aliases = talloc_array(ret, char *, len + 1);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (i = 0; i < len; i++) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->aliases[i] = talloc_strdup(ret->aliases, src->h_aliases[i]);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_copy_hostent(TALLOC_CTX *mem_ctx, struct hostent *src)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = resolv_copy_hostent_common(mem_ctx, src);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (len = 0; src->h_addr_list[len] != NULL; len++);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list = talloc_array(ret, struct resolv_addr *, len + 1);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (i = 0; i < len; i++) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list[i] = talloc_zero(ret->addr_list,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list[i]->ipaddr = talloc_memdup(ret->addr_list[i],
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_copy_hostent_ares(TALLOC_CTX *mem_ctx, struct hostent *src,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = resolv_copy_hostent_common(mem_ctx, src);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list = talloc_array(ret, struct resolv_addr *,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (i = 0; i < num_ares_ttl_data; i++) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret->addr_list[i] = talloc_zero(ret->addr_list,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen cret = resolv_copy_in_addr(ret->addr_list, ret->addr_list[i],
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/* =================== Resolve host name in files =========================*/
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Part of the query. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* query result */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* returned by ares. */
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 DEBUG(4, ("Trying to resolve %s record of '%s' in files\n",
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen state->family == AF_INET ? "A" : "AAAA", state->name));
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen state->status = ares_gethostbyname_file(state->resolv_ctx->channel,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->rhostent = resolv_copy_hostent(state, hostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Just say we didn't find anything and let the caller decide
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * about retrying */
39413f6b07f7e4f4c1aeeecab73a2c454c84e308Timo Sirainen tevent_req_error(req, return_code(state->status));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_files_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen int *status, struct resolv_hostent **rhostent)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_files_state *state = tevent_req_data(req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Fill in even in case of error as status contains the
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * c-ares return code */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *rhostent = talloc_steal(mem_ctx, state->rhostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen/* ==================== Resolve host name in DNS =========================*/
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Part of the query. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* query result */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* These are returned by ares. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_wakeup(struct tevent_req *subreq);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_query(struct tevent_req *req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_query_done(void *arg, int status, int timeouts,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_parse(struct gethostbyname_dns_state *state, int status,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic struct tevent_req *
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen req = tevent_req_create(mem_ctx, &state, struct gethostbyname_dns_state);
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 DEBUG(1, ("Failed to add critical timer to run next operation!\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_set_callback(subreq, resolv_gethostbyname_dns_wakeup, req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_wakeup(struct tevent_req *subreq)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_req *req = tevent_req_callback_data(subreq,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_dns_state *state = tevent_req_data(req,
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_query(struct tevent_req *req,
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 (state->family == AF_INET) ? ns_t_a : ns_t_aaaa,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_query_done(void *arg, int status, int timeouts,
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 unschedule_timeout_watcher(state->resolv_ctx);
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 schedule_timeout_watcher(state->ev, state->resolv_ctx);
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 */
b6dff2ba7a4640c1c4fa8fcad5602d236c31a2e4Timo Sirainen /* Any other error indicates a server error,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * so don't bother trying again
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = resolv_gethostbyname_dns_parse(state, status, timeouts, abuf, alen);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_parse(struct gethostbyname_dns_state *state,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen addr = talloc_array(state, struct ares_addrttl, naddrttls);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen status = ares_parse_a_reply(abuf, alen, &hostent,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen addr = talloc_array(state, struct ares_addr6ttl, naddrttls);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen status = ares_parse_aaaa_reply(abuf, alen, &hostent,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Unknown family %d\n", state->family));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->rhostent = resolv_copy_hostent_ares(state, hostent,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_dns_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_dns_state *state = tevent_req_data(req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Fill in even in case of error as status contains the
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * c-ares return code */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *rhostent = talloc_steal(mem_ctx, state->rhostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen/*******************************************************************
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * Get host by name. *
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *******************************************************************/
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Part of the query. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* In which order to use IPv4, or v6 */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Known hosts databases and index to the current one */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* These are returned by ares. The hostent struct will be freed
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen * when the user callback returns. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_address(TALLOC_CTX *mem_ctx, const char *address,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic inline int
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainenresolv_gethostbyname_family_init(enum restrict_family family_order);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_step(struct tevent_req *req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen req = tevent_req_create(mem_ctx, &state, struct gethostbyname_state);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen state->family = resolv_gethostbyname_family_init(state->family_order);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* Do not attempt to resolve IP addresses */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = resolv_gethostbyname_address(state, state->name,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Canot create a fake hostent structure\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen memset((void *) &hints, 0, sizeof(struct addrinfo));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen hints.ai_flags = AI_NUMERICHOST; /* No network lookups */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(9, ("[%s] does not look like an IP address\n", name));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return ret == 0;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_address(TALLOC_CTX *mem_ctx, const char *address,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent = talloc_zero(tmp_ctx, struct resolv_hostent);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->name = talloc_strdup(rhostent, address);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->addr_list = talloc_array(rhostent, struct resolv_addr *, 2);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->addr_list[0] = talloc_zero(rhostent->addr_list,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->addr_list[0]->ipaddr = talloc_array(rhostent->addr_list[0],
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen sizeof(struct in6_addr));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Could not parse address as neither v4 nor v6\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen rhostent->addr_list[0]->ttl = RESOLV_DEFAULT_TTL;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic inline int
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_family_init(enum restrict_family family_order)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(1, ("Unknown address family order %d\n", family_order));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_next(struct gethostbyname_state *state)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else if (state->family_order == IPV6_FIRST &&
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->family = resolv_gethostbyname_family_init(
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen DEBUG(4, ("No more hosts databases to retry\n"));
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_done(struct tevent_req *subreq);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_step(struct tevent_req *req)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_state *state = tevent_req_data(req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen subreq = resolv_gethostbyname_files_send(state, state->ev,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen subreq = resolv_gethostbyname_dns_send(state, state->ev,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen tevent_req_set_callback(subreq, resolv_gethostbyname_done, req);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenresolv_gethostbyname_done(struct tevent_req *subreq)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct tevent_req *req = tevent_req_callback_data(subreq,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct gethostbyname_state *state = tevent_req_data(req,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen ret = resolv_gethostbyname_files_recv(subreq, state,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* files is synchronous, there can be no timeouts */
case DB_DNS:
if (status) {
if (timeouts) {
if (rhostent) {
return EOK;
unsigned int addrindex)
char *address;
return NULL;
errno = 0;
return NULL;
return address;
struct sockaddr_storage *
int port)
return NULL;
case AF_INET:
case AF_INET6:
return NULL;
return sockaddr;
if (!old_list) {
return EOK;
while (old_list) {
if (!new_list) {
return ENOMEM;
return ENOMEM;
return ENOMEM;
return EOK;
struct getsrv_state {
/* the SRV query - for example _ldap._tcp.example.com */
const char *query;
int status;
int timeouts;
int retrying;
struct tevent_req *
return NULL;
return NULL;
return NULL;
return req;
int ret;
goto fail;
goto fail;
goto fail;
fail:
if (status)
if (timeouts)
if (reply_list)
return EOK;
struct tevent_req);
struct getsrv_state);
#ifdef BUILD_TXT
if (!old_list) {
return EOK;
while (old_list) {
if (!new_list) {
return ENOMEM;
return ENOMEM;
return ENOMEM;
return EOK;
struct gettxt_state {
const char *query;
int status;
int timeouts;
int retrying;
struct tevent_req *
return NULL;
return NULL;
return NULL;
return req;
int ret;
goto fail;
goto fail;
goto fail;
fail:
if (status)
if (timeouts)
if (reply_list)
return EOK;
struct tevent_req);
struct gettxt_state);
if (!list) {
return NULL;
return single_step;
struct ares_srv_reply *l, *r;
if (!left)
return right;
if (!right)
return left;
r = right;
l = left;
res = l;
l = l->next;
res = r;
r = r->next;
return res_start;
return list;
return list;
int len,
int *totals;
return EOK;
if (!totals) {
return ENOMEM;
r = *(start);
while (r != NULL) {
if (r->weight == 0) {
if (prev) {
tmp = r;
r = r->next;
prev = r;
r = r->next;
total = 0;
prev = r;
return EIO;
if (prev) {
if (!new_start) {
new_start = r;
new_end = r;
new_end = r;
return EOK;
int ret;
int len;
return EIO;
while (pri_start) {
len++;
if (ret) {
return ret;
if (prev_end) {
return EOK;