summaryrefslogtreecommitdiffstats
path: root/src/resolv
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2010-02-22 10:28:26 +0100
committerStephen Gallagher <sgallagh@redhat.com>2010-02-22 12:54:53 -0500
commite0bb119bdc1549d731f371202428c0cb667d3388 (patch)
tree3c4edcfb90558ca95a36c6edafdf9a98f35474d0 /src/resolv
parent48dbc3c447449b9bb1a9b7c839b9471ef4f547bf (diff)
downloadsssd-e0bb119bdc1549d731f371202428c0cb667d3388.tar.gz
sssd-e0bb119bdc1549d731f371202428c0cb667d3388.tar.xz
sssd-e0bb119bdc1549d731f371202428c0cb667d3388.zip
Restrict family lookups
Adds a new option that tells resolver which address family to prefer or use exclusively. Fixes: #404
Diffstat (limited to 'src/resolv')
-rw-r--r--src/resolv/async_resolv.c36
-rw-r--r--src/resolv/async_resolv.h10
2 files changed, 34 insertions, 12 deletions
diff --git a/src/resolv/async_resolv.c b/src/resolv/async_resolv.c
index 70d8d11e4..d0c5b7a33 100644
--- a/src/resolv/async_resolv.c
+++ b/src/resolv/async_resolv.c
@@ -459,6 +459,8 @@ struct gethostbyname_state {
/* 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;
@@ -472,14 +474,13 @@ 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)
+ 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 };
- DEBUG(4, ("Trying to resolve A record of '%s'\n", name));
-
if (ctx->channel == NULL) {
DEBUG(1, ("Invalid ares channel - this is likely a bug\n"));
return NULL;
@@ -491,11 +492,16 @@ resolv_gethostbyname_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
state->resolv_ctx = ctx;
state->name = name;
- state->family = AF_INET;
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.
@@ -513,7 +519,7 @@ resolv_gethostbyname_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
}
static void
-resolv_gethostbyname6_done(void *arg, int status, int timeouts, struct hostent *hostent);
+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)
@@ -545,14 +551,22 @@ resolv_gethostbyname_done(void *arg, int status, int timeouts, struct hostent *h
if (status != ARES_SUCCESS) {
if (status == ARES_ENOTFOUND || status == ARES_ENODATA) {
- /* IPv4 failure. Try IPv6 */
- state->family = AF_INET6;
+ 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 AAAA record of '%s'\n",
+ DEBUG(4, ("Trying to resolve %s record of '%s'\n",
+ state->family == AF_INET ? "A" : "AAAA",
state->name));
ares_gethostbyname(state->resolv_ctx->channel, state->name,
- state->family, resolv_gethostbyname6_done,
+ state->family, resolv_gethostbyname_next_done,
req);
return;
}
@@ -568,7 +582,7 @@ resolv_gethostbyname_done(void *arg, int status, int timeouts, struct hostent *h
}
static void
-resolv_gethostbyname6_done(void *arg, int status, int timeouts, struct hostent *hostent)
+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);
@@ -576,7 +590,7 @@ resolv_gethostbyname6_done(void *arg, int status, int timeouts, struct hostent *
if (state->retrying == 0 && status == ARES_EDESTRUCTION) {
state->retrying = 1;
ares_gethostbyname(state->resolv_ctx->channel, state->name,
- state->family, resolv_gethostbyname6_done, req);
+ state->family, resolv_gethostbyname_next_done, req);
return;
}
diff --git a/src/resolv/async_resolv.h b/src/resolv/async_resolv.h
index 2ba6449b2..5f87f12e3 100644
--- a/src/resolv/async_resolv.h
+++ b/src/resolv/async_resolv.h
@@ -57,10 +57,18 @@ struct hostent *resolv_copy_hostent(TALLOC_CTX *mem_ctx,
struct hostent *src);
/** Get host by name **/
+enum restrict_family {
+ IPV4_ONLY,
+ IPV4_FIRST,
+ IPV6_ONLY,
+ IPV6_FIRST
+};
+
struct tevent_req *resolv_gethostbyname_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct resolv_ctx *ctx,
- const char *name);
+ const char *name,
+ enum restrict_family family_order);
int resolv_gethostbyname_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,