From 79cafdcc25948300e2b0c85955b67b0d0c4c73c7 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Wed, 13 Jan 2010 11:02:02 -0500 Subject: Handle IPv6 addresses with the async resolver --- server/providers/fail_over.c | 3 +-- server/resolv/async_resolv.c | 62 +++++++++++++++++++++++++++++++++++++++++--- server/resolv/async_resolv.h | 3 +-- server/tests/resolv-tests.c | 10 +++---- 4 files changed, 65 insertions(+), 13 deletions(-) (limited to 'server') diff --git a/server/providers/fail_over.c b/server/providers/fail_over.c index 9795ccec..7560b89e 100644 --- a/server/providers/fail_over.c +++ b/server/providers/fail_over.c @@ -497,9 +497,8 @@ fo_resolve_service_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, switch (get_server_status(server)) { case SERVER_NAME_NOT_RESOLVED: /* Request name resolution. */ - /* TODO: Enable IPv6. */ subreq = resolv_gethostbyname_send(server->common, ev, resolv, - server->common->name, AF_INET); + server->common->name); if (subreq == NULL) { ret = ENOMEM; goto done; diff --git a/server/resolv/async_resolv.c b/server/resolv/async_resolv.c index 7973a78f..70d8d11e 100644 --- a/server/resolv/async_resolv.c +++ b/server/resolv/async_resolv.c @@ -472,7 +472,7 @@ 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, int family) + struct resolv_ctx *ctx, const char *name) { struct tevent_req *req, *subreq; struct gethostbyname_state *state; @@ -491,7 +491,7 @@ resolv_gethostbyname_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, state->resolv_ctx = ctx; state->name = name; - state->family = family; + state->family = AF_INET; state->hostent = NULL; state->status = 0; state->timeouts = 0; @@ -512,6 +512,9 @@ resolv_gethostbyname_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, return req; } +static void +resolv_gethostbyname6_done(void *arg, int status, int timeouts, struct hostent *hostent); + static void resolv_gethostbyname_done(void *arg, int status, int timeouts, struct hostent *hostent) { @@ -540,10 +543,61 @@ resolv_gethostbyname_done(void *arg, int status, int timeouts, struct hostent *h state->status = status; state->timeouts = timeouts; - if (status != ARES_SUCCESS) + if (status != ARES_SUCCESS) { + if (status == ARES_ENOTFOUND || status == ARES_ENODATA) { + /* IPv4 failure. Try IPv6 */ + state->family = AF_INET6; + state->retrying = 0; + state->timeouts = 0; + DEBUG(4, ("Trying to resolve AAAA record of '%s'\n", + state->name)); + ares_gethostbyname(state->resolv_ctx->channel, state->name, + state->family, resolv_gethostbyname6_done, + req); + return; + } + + /* Any other error indicates a server error, + * so don't bother trying again + */ tevent_req_error(req, return_code(status)); - else + } + else { tevent_req_done(req); + } +} + +static void +resolv_gethostbyname6_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_gethostbyname6_done, req); + return; + } + + 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 diff --git a/server/resolv/async_resolv.h b/server/resolv/async_resolv.h index 5558e15c..2ba6449b 100644 --- a/server/resolv/async_resolv.h +++ b/server/resolv/async_resolv.h @@ -60,8 +60,7 @@ struct hostent *resolv_copy_hostent(TALLOC_CTX *mem_ctx, struct tevent_req *resolv_gethostbyname_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct resolv_ctx *ctx, - const char *name, - int family); + const char *name); int resolv_gethostbyname_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, diff --git a/server/tests/resolv-tests.c b/server/tests/resolv-tests.c index 0c18dfdc..c1b32781 100644 --- a/server/tests/resolv-tests.c +++ b/server/tests/resolv-tests.c @@ -178,7 +178,7 @@ START_TEST(test_resolv_localhost) } check_leaks_push(test_ctx); - req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname, AF_INET); + req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname); DEBUG(7, ("Sent resolv_gethostbyname\n")); if (req == NULL) { ret = ENOMEM; @@ -232,7 +232,7 @@ START_TEST(test_resolv_negative) } check_leaks_push(test_ctx); - req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname, AF_INET); + req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname); DEBUG(7, ("Sent resolv_gethostbyname\n")); if (req == NULL) { ret = ENOMEM; @@ -322,7 +322,7 @@ START_TEST(test_resolv_internet) test_ctx->tested_function = TESTING_HOSTNAME; check_leaks_push(test_ctx); - req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname, AF_INET); + req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname); DEBUG(7, ("Sent resolv_gethostbyname\n")); if (req == NULL) { ret = ENOMEM; @@ -425,7 +425,7 @@ START_TEST(test_resolv_free_context) return; } - req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname, AF_INET); + req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname); DEBUG(7, ("Sent resolv_gethostbyname\n")); if (req == NULL) { fail("Error calling resolv_gethostbyname_send"); @@ -484,7 +484,7 @@ START_TEST(test_resolv_free_req) } check_leaks_push(test_ctx); - req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname, AF_INET); + req = resolv_gethostbyname_send(test_ctx, test_ctx->ev, test_ctx->resolv, hostname); DEBUG(7, ("Sent resolv_gethostbyname\n")); if (req == NULL) { fail("Error calling resolv_gethostbyname_send"); -- cgit