summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
authoreric <eric@openbsd.org>2012-09-05 21:49:12 +0000
committereric <eric@openbsd.org>2012-09-05 21:49:12 +0000
commitc5c8c49b7d93a9614396fdca60ffe24909e44a3b (patch)
tree6f9c14b8f149796d3563694a52b02558c6425fba /lib/libc
parentrun regress with the local env too (diff)
downloadwireguard-openbsd-c5c8c49b7d93a9614396fdca60ffe24909e44a3b.tar.xz
wireguard-openbsd-c5c8c49b7d93a9614396fdca60ffe24909e44a3b.zip
Get rid of the hostaddr_async subquery and merge its behaviour
directly into getaddrinfo_async_run. Simplifies everything by a great deal.
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/asr/Makefile.inc6
-rw-r--r--lib/libc/asr/asr.c13
-rw-r--r--lib/libc/asr/asr_debug.c6
-rw-r--r--lib/libc/asr/asr_private.h8
-rw-r--r--lib/libc/asr/getaddrinfo_async.c354
-rw-r--r--lib/libc/asr/hostaddr_async.c442
6 files changed, 298 insertions, 531 deletions
diff --git a/lib/libc/asr/Makefile.inc b/lib/libc/asr/Makefile.inc
index 5708aefabaa..fa21036c5ad 100644
--- a/lib/libc/asr/Makefile.inc
+++ b/lib/libc/asr/Makefile.inc
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile.inc,v 1.3 2012/07/07 15:40:54 eric Exp $
+# $OpenBSD: Makefile.inc,v 1.4 2012/09/05 21:49:12 eric Exp $
# asr sources
.PATH: ${LIBCSRCDIR}/asr
@@ -6,7 +6,7 @@
SRCS+= asr.c asr_debug.c asr_utils.c \
res_send_async.c res_search_async.c getrrsetbyname_async.c \
gethostnamadr_async.c getnetnamadr_async.c \
- hostaddr_async.c getaddrinfo_async.c getnameinfo_async.c
+ getaddrinfo_async.c getnameinfo_async.c
# resolver replacement. comment out to disable.
SRCS+= asr_resolver.c
@@ -23,9 +23,7 @@ MLINKS+ = \
async_resolver.3 gethostbyname_async.3 \
async_resolver.3 gethostbyname2_async.3 \
async_resolver.3 gethostbyaddr_async.3 \
- async_resolver.3 freehostent.3 \
async_resolver.3 getnetbyname_async.3 \
async_resolver.3 getnetbyaddr_async.3 \
- async_resolver.3 freenetent.3 \
async_resolver.3 getaddrinfo_async.3 \
async_resolver.3 getnameinfo_async.3
diff --git a/lib/libc/asr/asr.c b/lib/libc/asr/asr.c
index a0c7125594d..013c7dc27a5 100644
--- a/lib/libc/asr/asr.c
+++ b/lib/libc/asr/asr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: asr.c,v 1.5 2012/09/05 15:56:13 eric Exp $ */
+/* $OpenBSD: asr.c,v 1.6 2012/09/05 21:49:12 eric Exp $ */
/*
* Copyright (c) 2010-2012 Eric Faurot <eric@openbsd.org>
*
@@ -301,21 +301,14 @@ async_free(struct async *as)
free(as->as.ai.hostname);
if (as->as.ai.servname)
free(as->as.ai.servname);
+ if (as->as.ai.fqdn)
+ free(as->as.ai.fqdn);
break;
case ASR_GETNAMEINFO:
if (as->as.ni.subq)
async_free(as->as.ni.subq);
break;
-
- case ASR_HOSTADDR:
- if (as->as.ai.hostname)
- free(as->as.ai.hostname);
- if (as->as.ai.subq)
- async_free(as->as.ai.subq);
- if (as->as.ai.aifirst)
- freeaddrinfo(as->as.ai.aifirst);
- break;
}
asr_ctx_unref(as->as_ctx);
diff --git a/lib/libc/asr/asr_debug.c b/lib/libc/asr/asr_debug.c
index 45f1976ec08..0085b9ac3b5 100644
--- a/lib/libc/asr/asr_debug.c
+++ b/lib/libc/asr/asr_debug.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: asr_debug.c,v 1.5 2012/09/05 15:56:13 eric Exp $ */
+/* $OpenBSD: asr_debug.c,v 1.6 2012/09/05 21:49:12 eric Exp $ */
/*
* Copyright (c) 2010-2012 Eric Faurot <eric@openbsd.org>
*
@@ -420,7 +420,6 @@ struct kv kv_query_type[] = {
{ ASR_GETNETBYADDR, "ASR_GETNETBYADDR" },
{ ASR_GETADDRINFO, "ASR_GETADDRINFO" },
{ ASR_GETNAMEINFO, "ASR_GETNAMEINFO" },
- { ASR_HOSTADDR, "ASR_HOSTADDR" },
{ 0, NULL }
};
@@ -433,13 +432,10 @@ struct kv kv_db_type[] = {
struct kv kv_state[] = {
{ ASR_STATE_INIT, "ASR_STATE_INIT" },
- { ASR_STATE_SEARCH_DOMAIN, "ASR_STATE_SEARCH_DOMAIN" },
- { ASR_STATE_LOOKUP_DOMAIN, "ASR_STATE_LOOKUP_DOMAIN" },
{ ASR_STATE_NEXT_DOMAIN, "ASR_STATE_NEXT_DOMAIN" },
{ ASR_STATE_NEXT_DB, "ASR_STATE_NEXT_DB" },
{ ASR_STATE_SAME_DB, "ASR_STATE_SAME_DB" },
{ ASR_STATE_NEXT_FAMILY, "ASR_STATE_NEXT_FAMILY" },
- { ASR_STATE_LOOKUP_FAMILY, "ASR_STATE_LOOKUP_FAMILY" },
{ ASR_STATE_NEXT_NS, "ASR_STATE_NEXT_NS" },
{ ASR_STATE_UDP_SEND, "ASR_STATE_UDP_SEND" },
{ ASR_STATE_UDP_RECV, "ASR_STATE_UDP_RECV" },
diff --git a/lib/libc/asr/asr_private.h b/lib/libc/asr/asr_private.h
index b346f316649..03bd5655be1 100644
--- a/lib/libc/asr/asr_private.h
+++ b/lib/libc/asr/asr_private.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: asr_private.h,v 1.4 2012/09/05 15:56:13 eric Exp $ */
+/* $OpenBSD: asr_private.h,v 1.5 2012/09/05 21:49:12 eric Exp $ */
/*
* Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
*
@@ -109,7 +109,6 @@ enum async_type {
ASR_GETNETBYADDR,
ASR_GETADDRINFO,
ASR_GETNAMEINFO,
- ASR_HOSTADDR,
};
enum asr_db_type {
@@ -249,6 +248,7 @@ struct async {
} sa;
struct addrinfo hints;
+ char *fqdn;
struct addrinfo *aifirst;
struct addrinfo *ailast;
struct async *subq;
@@ -278,13 +278,10 @@ struct async {
enum asr_state {
ASR_STATE_INIT,
- ASR_STATE_SEARCH_DOMAIN,
- ASR_STATE_LOOKUP_DOMAIN,
ASR_STATE_NEXT_DOMAIN,
ASR_STATE_NEXT_DB,
ASR_STATE_SAME_DB,
ASR_STATE_NEXT_FAMILY,
- ASR_STATE_LOOKUP_FAMILY,
ASR_STATE_NEXT_NS,
ASR_STATE_UDP_SEND,
ASR_STATE_UDP_RECV,
@@ -327,7 +324,6 @@ struct async *res_search_async_ctx(const char *, int, int, unsigned char *, int,
struct asr_ctx *);
struct async *gethostbyaddr_async_ctx(const void *, socklen_t, int,
struct asr_ctx *);
-struct async *hostaddr_async_ctx(const char *, int, int, struct asr_ctx *);
#ifdef DEBUG
diff --git a/lib/libc/asr/getaddrinfo_async.c b/lib/libc/asr/getaddrinfo_async.c
index a31fd31f9bc..1996c2a6c56 100644
--- a/lib/libc/asr/getaddrinfo_async.c
+++ b/lib/libc/asr/getaddrinfo_async.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: getaddrinfo_async.c,v 1.6 2012/09/05 15:56:13 eric Exp $ */
+/* $OpenBSD: getaddrinfo_async.c,v 1.7 2012/09/05 21:49:12 eric Exp $ */
/*
* Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
*
@@ -37,7 +37,12 @@ struct match {
static int getaddrinfo_async_run(struct async *, struct async_res *);
static int get_port(const char *, const char *, int);
static int iter_family(struct async *, int);
-static int add_sockaddr(struct async *, struct sockaddr *, const char *);
+static int addrinfo_add(struct async *, const struct sockaddr *, const char *);
+static int addrinfo_from_file(struct async *, int, FILE *);
+static int addrinfo_from_pkt(struct async *, char *, size_t);
+#ifdef YP
+static int addrinfo_from_yp(struct async *, int, char *);
+#endif
static const struct match matches[] = {
{ PF_INET, SOCK_DGRAM, IPPROTO_UDP },
@@ -90,10 +95,16 @@ getaddrinfo_async(const char *hostname, const char *servname,
static int
getaddrinfo_async_run(struct async *as, struct async_res *ar)
{
+#ifdef YP
+ static char *domain = NULL;
+ char *res;
+ int len;
+#endif
const char *str;
struct addrinfo *ai;
int i, family, r;
char fqdn[MAXDNAME];
+ FILE *f;
union {
struct sockaddr sa;
struct sockaddr_in sain;
@@ -214,7 +225,7 @@ getaddrinfo_async_run(struct async *as, struct async_res *ar)
"::" : "::1";
/* This can't fail */
sockaddr_from_str(&sa.sa, family, str);
- if ((r = add_sockaddr(as, &sa.sa, NULL))) {
+ if ((r = addrinfo_add(as, &sa.sa, NULL))) {
ar->ar_gai_errno = r;
break;
}
@@ -235,7 +246,7 @@ getaddrinfo_async_run(struct async *as, struct async_res *ar)
as->as.ai.hostname) == -1)
continue;
- if ((r = add_sockaddr(as, &sa.sa, NULL))) {
+ if ((r = addrinfo_add(as, &sa.sa, NULL))) {
ar->ar_gai_errno = r;
}
break;
@@ -251,12 +262,11 @@ getaddrinfo_async_run(struct async *as, struct async_res *ar)
break;
}
- /* Starting domain lookup */
- async_set_state(as, ASR_STATE_SEARCH_DOMAIN);
+ /* start domain lookup */
+ async_set_state(as, ASR_STATE_NEXT_DOMAIN);
break;
- case ASR_STATE_SEARCH_DOMAIN:
-
+ case ASR_STATE_NEXT_DOMAIN:
r = asr_iter_domain(as, as->as.ai.hostname, fqdn, sizeof(fqdn));
if (r == -1) {
async_set_state(as, ASR_STATE_NOT_FOUND);
@@ -267,83 +277,151 @@ getaddrinfo_async_run(struct async *as, struct async_res *ar)
async_set_state(as, ASR_STATE_HALT);
break;
}
-
- /*
- * Create a subquery to lookup the host addresses.
- * We use the special hostaddr_async() API, which has the
- * nice property of honoring the "lookup" and "family" keyword
- * in the configuration, thus returning the right address
- * families in the right order, and thus fixing the current
- * getaddrinfo() feature documented in the BUGS section of
- * resolver.conf(5).
- */
- as->as.ai.subq = hostaddr_async_ctx(fqdn,
- as->as.ai.hints.ai_family, as->as.ai.hints.ai_flags,
- as->as_ctx);
- if (as->as.ai.subq == NULL) {
- if (errno == EINVAL) {
- ar->ar_gai_errno = EAI_FAIL;
- } else {
- ar->ar_gai_errno = EAI_MEMORY;
- }
+ if (as->as.ai.fqdn)
+ free(as->as.ai.fqdn);
+ if ((as->as.ai.fqdn = strdup(fqdn)) == NULL) {
+ ar->ar_gai_errno = EAI_MEMORY;
async_set_state(as, ASR_STATE_HALT);
break;
}
- async_set_state(as, ASR_STATE_LOOKUP_DOMAIN);
+ as->as_db_idx = 0;
+ async_set_state(as, ASR_STATE_NEXT_DB);
break;
- case ASR_STATE_LOOKUP_DOMAIN:
-
- /* Run the subquery */
- if ((r = async_run(as->as.ai.subq, ar)) == ASYNC_COND)
- return (ASYNC_COND);
+ case ASR_STATE_NEXT_DB:
+ if (asr_iter_db(as) == -1) {
+ async_set_state(as, ASR_STATE_NEXT_DOMAIN);
+ break;
+ }
+ as->as_family_idx = 0;
+ async_set_state(as, ASR_STATE_SAME_DB);
+ break;
- /*
- * The subquery is done. Stop there if we have at least one
- * answer.
- */
- as->as.ai.subq = NULL;
- if (ar->ar_count == 0) {
- /*
- * No anwser for this domain, but we might be suggested
- * to try again later, so remember this. Then search
- * the next domain.
+ case ASR_STATE_NEXT_FAMILY:
+ as->as_family_idx += 1;
+ if (as->as.ai.hints.ai_family != AF_UNSPEC ||
+ AS_FAMILY(as) == -1) {
+ /* The family was specified, or we have tried all
+ * families with this DB.
*/
- if (ar->ar_gai_errno == EAI_AGAIN)
- as->as.ai.flags |= ASYNC_AGAIN;
- async_set_state(as, ASR_STATE_SEARCH_DOMAIN);
+ if (as->as_count) {
+ ar->ar_gai_errno = 0;
+ async_set_state(as, ASR_STATE_HALT);
+ } else
+ async_set_state(as, ASR_STATE_NEXT_DB);
break;
}
+ async_set_state(as, ASR_STATE_SAME_DB);
+ break;
+
+ case ASR_STATE_SAME_DB:
+ /* query the current DB again. */
+ switch(AS_DB(as)) {
+ case ASR_DB_DNS:
+ family = (as->as.ai.hints.ai_family == AF_UNSPEC) ?
+ AS_FAMILY(as) : as->as.ai.hints.ai_family;
+ as->as.ai.subq = res_query_async_ctx(as->as.ai.fqdn,
+ C_IN, (family == AF_INET6) ? T_AAAA : T_A, NULL, 0,
+ as->as_ctx);
+ if (as->as.ai.subq == NULL) {
+ if (errno == ENOMEM)
+ ar->ar_gai_errno = EAI_MEMORY;
+ else
+ ar->ar_gai_errno = EAI_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ async_set_state(as, ASR_STATE_SUBQUERY);
+ break;
- /* iterate over and expand results */
+ case ASR_DB_FILE:
+ f = fopen(as->as_ctx->ac_hostfile, "r");
+ if (f == NULL) {
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+ family = (as->as.ai.hints.ai_family == AF_UNSPEC) ?
+ AS_FAMILY(as) : as->as.ai.hints.ai_family;
+
+ r = addrinfo_from_file(as, family, f);
+ if (r == -1) {
+ if (errno == ENOMEM)
+ ar->ar_gai_errno = EAI_MEMORY;
+ else
+ ar->ar_gai_errno = EAI_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ } else
+ async_set_state(as, ASR_STATE_NEXT_FAMILY);
+ fclose(f);
+ break;
- for(ai = ar->ar_addrinfo; ai; ai = ai->ai_next) {
- r = add_sockaddr(as, ai->ai_addr, ai->ai_canonname);
- if (r)
+#ifdef YP
+ case ASR_DB_YP:
+ if (!domain && _yp_check(&domain) == 0) {
+ async_set_state(as, ASR_STATE_NEXT_DB);
break;
+ }
+ family = (as->as.ai.hints.ai_family == AF_UNSPEC) ?
+ AS_FAMILY(as) : as->as.ai.hints.ai_family;
+ /* XXX
+ * ipnodes.byname could also contain IPv4 address
+ */
+ r = yp_match(domain, (family == AF_INET6) ?
+ "ipnodes.byname" : "hosts.byname",
+ as->as.ai.hostname, strlen(as->as.ai.hostname),
+ &res, &len);
+ if (r == 0) {
+ r = addrinfo_from_yp(as, family, res);
+ free(res);
+ if (r == -1) {
+ if (errno == ENOMEM)
+ ar->ar_gai_errno = EAI_MEMORY;
+ else
+ ar->ar_gai_errno = EAI_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ }
+ async_set_state(as, ASR_STATE_NEXT_FAMILY);
+ break;
+#endif
+ default:
+ async_set_state(as, ASR_STATE_NEXT_DB);
}
- freeaddrinfo(ar->ar_addrinfo);
- ar->ar_gai_errno = r;
- async_set_state(as, ASR_STATE_HALT);
break;
- case ASR_STATE_NOT_FOUND:
+ case ASR_STATE_SUBQUERY:
+ if ((r = async_run(as->as.ai.subq, ar)) == ASYNC_COND)
+ return (ASYNC_COND);
+ as->as.ai.subq = NULL;
- /*
- * No result found. Maybe we can try again.
- */
- if (as->as.ai.flags & ASYNC_AGAIN) {
+ if (ar->ar_datalen == -1) {
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+
+ r = addrinfo_from_pkt(as, ar->ar_data, ar->ar_datalen);
+ if (r == -1) {
+ if (errno == ENOMEM)
+ ar->ar_gai_errno = EAI_MEMORY;
+ else
+ ar->ar_gai_errno = EAI_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ } else
+ async_set_state(as, ASR_STATE_NEXT_FAMILY);
+ free(ar->ar_data);
+ break;
+
+ case ASR_STATE_NOT_FOUND:
+ /* No result found. Maybe we can try again. */
+ if (as->as.ai.flags & ASYNC_AGAIN)
ar->ar_gai_errno = EAI_AGAIN;
- } else {
+ else
ar->ar_gai_errno = EAI_NODATA;
- }
async_set_state(as, ASR_STATE_HALT);
break;
case ASR_STATE_HALT:
-
- /* Set the results. */
-
if (ar->ar_gai_errno == 0) {
ar->ar_count = as->as_count;
ar->ar_addrinfo = as->as.ai.aifirst;
@@ -426,7 +504,7 @@ iter_family(struct async *as, int first)
* entry per protocol/socktype match.
*/
static int
-add_sockaddr(struct async *as, struct sockaddr *sa, const char *cname)
+addrinfo_add(struct async *as, const struct sockaddr *sa, const char *cname)
{
struct addrinfo *ai;
int i, port;
@@ -481,3 +559,151 @@ add_sockaddr(struct async *as, struct sockaddr *sa, const char *cname)
return (0);
}
+
+static int
+addrinfo_from_file(struct async *as, int family, FILE *f)
+{
+ char *tokens[MAXTOKEN], *c;
+ int n, i;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sain;
+ struct sockaddr_in6 sain6;
+ } u;
+
+ for(;;) {
+ n = asr_parse_namedb_line(f, tokens, MAXTOKEN);
+ if (n == -1)
+ break; /* ignore errors reading the file */
+
+ for (i = 1; i < n; i++) {
+ if (strcasecmp(as->as.ai.fqdn, tokens[i]))
+ continue;
+ if (sockaddr_from_str(&u.sa, family, tokens[0]) == -1)
+ continue;
+ break;
+ }
+ if (i == n)
+ continue;
+
+ if (as->as.ai.hints.ai_flags & AI_CANONNAME)
+ c = tokens[1];
+ else if (as->as.ai.hints.ai_flags & AI_FQDN)
+ c = as->as.ai.fqdn;
+ else
+ c = NULL;
+
+ if (addrinfo_add(as, &u.sa, c))
+ return (-1); /* errno set */
+ }
+ return (0);
+}
+
+static int
+addrinfo_from_pkt(struct async *as, char *pkt, size_t pktlen)
+{
+ struct packed p;
+ struct header h;
+ struct query q;
+ struct rr rr;
+ int i;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sain;
+ struct sockaddr_in6 sain6;
+ } u;
+ char buf[MAXDNAME], *c;
+
+ packed_init(&p, pkt, pktlen);
+ unpack_header(&p, &h);
+ for(; h.qdcount; h.qdcount--)
+ unpack_query(&p, &q);
+
+ for (i = 0; i < h.ancount; i++) {
+ unpack_rr(&p, &rr);
+ if (rr.rr_type != q.q_type ||
+ rr.rr_class != q.q_class)
+ continue;
+
+ memset(&u, 0, sizeof u);
+ if (rr.rr_type == T_A) {
+ u.sain.sin_len = sizeof u.sain;
+ u.sain.sin_family = AF_INET;
+ u.sain.sin_addr = rr.rr.in_a.addr;
+ u.sain.sin_port = 0;
+ } else if (rr.rr_type == T_AAAA) {
+ u.sain6.sin6_len = sizeof u.sain6;
+ u.sain6.sin6_family = AF_INET6;
+ u.sain6.sin6_addr = rr.rr.in_aaaa.addr6;
+ u.sain6.sin6_port = 0;
+ } else
+ continue;
+
+ if (as->as.ai.hints.ai_flags & AI_CANONNAME) {
+ asr_strdname(rr.rr_dname, buf, sizeof buf);
+ buf[strlen(buf) - 1] = '\0';
+ c = buf;
+ } else if (as->as.ai.hints.ai_flags & AI_FQDN)
+ c = as->as.ai.fqdn;
+ else
+ c = NULL;
+
+ if (addrinfo_add(as, &u.sa, c))
+ return (-1); /* errno set */
+ }
+ return (0);
+}
+
+#ifdef YP
+static int
+strsplit(char *line, char **tokens, int ntokens)
+{
+ int ntok;
+ char *cp, **tp;
+
+ for(cp = line, tp = tokens, ntok = 0;
+ ntok < ntokens && (*tp = strsep(&cp, " \t")) != NULL; )
+ if (**tp != '\0') {
+ tp++;
+ ntok++;
+ }
+
+ return (ntok);
+}
+
+static int
+addrinfo_from_yp(struct async *as, int family, char *line)
+{
+ char *next, *tokens[MAXTOKEN], *c;
+ int i, ntok;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sain;
+ struct sockaddr_in6 sain6;
+ } u;
+
+ for(next = line; line; line = next) {
+ if ((next = strchr(line, '\n'))) {
+ *next = '\0';
+ next += 1;
+ }
+ ntok = strsplit(line, tokens, MAXTOKEN);
+ if (ntok < 2)
+ continue;
+
+ if (sockaddr_from_str(&u.sa, family, tokens[0]) == -1)
+ continue;
+
+ if (as->as.ai.hints.ai_flags & AI_CANONNAME)
+ c = tokens[1];
+ else if (as->as.ai.hints.ai_flags & AI_FQDN)
+ c = as->as.ai.fqdn;
+ else
+ c = NULL;
+
+ if (addrinfo_add(as, &u.sa, c))
+ return (-1); /* errno set */
+ }
+ return (0);
+}
+#endif
diff --git a/lib/libc/asr/hostaddr_async.c b/lib/libc/asr/hostaddr_async.c
deleted file mode 100644
index 8688d3a47fd..00000000000
--- a/lib/libc/asr/hostaddr_async.c
+++ /dev/null
@@ -1,442 +0,0 @@
-/* $OpenBSD: hostaddr_async.c,v 1.4 2012/09/05 16:52:05 eric Exp $ */
-/*
- * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/uio.h>
-
-#include <arpa/nameser.h>
-
-#include <err.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "asr.h"
-#include "asr_private.h"
-
-static int hostaddr_async_run(struct async *, struct async_res *);
-static int addrinfo_add(struct async *, int, const void *, size_t, const char *);
-static int addrinfo_from_file(struct async *, int, FILE *);
-static int addrinfo_from_pkt(struct async *, char *, size_t);
-#ifdef YP
-static int addrinfo_from_yp(struct async *, int, char *);
-#endif
-
-/*
- * This API function allows to iterate over host addresses, for the given
- * family which, must be AF_INET, AF_INET6, or AF_UNSPEC (in which case
- * the family lookup list from the resolver is used). The strategy is to
- * return all addresses found for the first DB that returned at least one
- * address.
- *
- * Flags can be 0, or one of AI_CANONNAME or AI_FQDN. If set, the
- * canonical name will be returned along with the address.
- */
-struct async *
-hostaddr_async_ctx(const char *name, int family, int flags, struct asr_ctx *ac)
-{
- struct async *as;
- char buf[MAXDNAME];
-
-#ifdef DEBUG
- asr_printf("asr: hostaddr_async_ctx(\"%s\", %i)\n", name, family);
-#endif
- if (asr_domcat(name, NULL, buf, sizeof buf) == 0) {
- errno = EINVAL;
- return (NULL);
- }
-
- if ((as = async_new(ac, ASR_HOSTADDR)) == NULL)
- goto err; /* errno set */
- as->as_run = hostaddr_async_run;
-
- as->as.ai.hints.ai_flags = flags;
- as->as.ai.hints.ai_family = family;
- as->as.ai.hostname = strdup(buf);
- if (as->as.ai.hostname == NULL)
- goto err; /* errno set */
-
- return (as);
- err:
- if (as)
- async_free(as);
- return (NULL);
-}
-
-static int
-hostaddr_async_run(struct async *as, struct async_res *ar)
-{
-#ifdef YP
- static char *domain = NULL;
- char *res;
- int len;
-#endif
- char *name;
- int family, type, r;
- FILE *file;
-
- next:
- switch(as->as_state) {
-
- case ASR_STATE_INIT:
-
- if (as->as.ai.hints.ai_family != AF_INET &&
- as->as.ai.hints.ai_family != AF_INET6 &&
- as->as.ai.hints.ai_family != AF_UNSPEC) {
- ar->ar_gai_errno = EAI_FAMILY;
- async_set_state(as, ASR_STATE_HALT);
- break;
- }
-
- as->as_count = 0;
- as->as_db_idx = 0;
- async_set_state(as, ASR_STATE_NEXT_DB);
- break;
-
- case ASR_STATE_NEXT_FAMILY:
-
- as->as_family_idx += 1;
- if (as->as.ai.hints.ai_family != AF_UNSPEC ||
- AS_FAMILY(as) == -1) {
- /* The family was specified, or we have tried all
- * families with this DB.
- */
- if (as->as_count) {
- ar->ar_gai_errno = 0;
- async_set_state(as, ASR_STATE_HALT);
- } else
- async_set_state(as, ASR_STATE_NEXT_DB);
- break;
- }
-
- async_set_state(as, ASR_STATE_LOOKUP_FAMILY);
- break;
-
- case ASR_STATE_LOOKUP_FAMILY:
- async_set_state(as, ASR_STATE_SAME_DB);
- break;
-
- case ASR_STATE_NEXT_DB:
- if (asr_iter_db(as) == -1) {
- async_set_state(as, ASR_STATE_NOT_FOUND);
- break;
- }
- as->as_family_idx = 0;
- /* FALLTHROUGH */
-
- case ASR_STATE_SAME_DB:
- /* query the current DB again. */
- switch(AS_DB(as)) {
- case ASR_DB_DNS:
- family = (as->as.ai.hints.ai_family == AF_UNSPEC) ?
- AS_FAMILY(as) : as->as.ai.hints.ai_family;
- type = (family == AF_INET6) ? T_AAAA : T_A;
- name = as->as.ai.hostname;
- as->as.ai.subq = res_query_async_ctx(name, C_IN,
- type, NULL, 0, as->as_ctx);
- if (as->as.ai.subq == NULL) {
- if (errno == ENOMEM)
- ar->ar_gai_errno = EAI_MEMORY;
- else
- ar->ar_gai_errno = EAI_FAIL;
- async_set_state(as, ASR_STATE_HALT);
- break;
- }
- async_set_state(as, ASR_STATE_SUBQUERY);
- break;
-
- case ASR_DB_FILE:
- file = fopen(as->as_ctx->ac_hostfile, "r");
- if (file == NULL) {
- async_set_state(as, ASR_STATE_NEXT_DB);
- break;
- }
- family = (as->as.ai.hints.ai_family == AF_UNSPEC) ?
- AS_FAMILY(as) : as->as.ai.hints.ai_family;
-
- r = addrinfo_from_file(as, family, file);
- if (r == -1) {
- if (errno == ENOMEM)
- ar->ar_gai_errno = EAI_MEMORY;
- else
- ar->ar_gai_errno = EAI_FAIL;
- async_set_state(as, ASR_STATE_HALT);
- } else
- async_set_state(as, ASR_STATE_NEXT_FAMILY);
- fclose(file);
- break;
-
-#ifdef YP
- case ASR_DB_YP:
- if (!domain && _yp_check(&domain) == 0) {
- async_set_state(as, ASR_STATE_NEXT_DB);
- break;
- }
- family = (as->as.ai.hints.ai_family == AF_UNSPEC) ?
- AS_FAMILY(as) : as->as.ai.hints.ai_family;
- /* XXX
- * ipnodes.byname could also contain IPv4 address
- */
- name = (family == AF_INET6) ?
- "ipnodes.byname" : "hosts.byname";
- r = yp_match(domain, name, as->as.ai.hostname,
- strlen(as->as.ai.hostname), &res, &len);
- if (r == 0) {
- r = addrinfo_from_yp(as, family, res);
- free(res);
- if (r == -1) {
- if (errno == ENOMEM)
- ar->ar_gai_errno = EAI_MEMORY;
- else
- ar->ar_gai_errno = EAI_FAIL;
- async_set_state(as, ASR_STATE_HALT);
- break;
- }
- }
- async_set_state(as, ASR_STATE_NEXT_FAMILY);
- break;
-#endif
-
- default:
- async_set_state(as, ASR_STATE_NEXT_DB);
- }
- break;
-
- case ASR_STATE_SUBQUERY:
- if ((r = async_run(as->as.ai.subq, ar)) == ASYNC_COND)
- return (ASYNC_COND);
- as->as.ai.subq = NULL;
-
- if (ar->ar_datalen == -1) {
- async_set_state(as, ASR_STATE_NEXT_DB);
- break;
- }
-
- r = addrinfo_from_pkt(as, ar->ar_data, ar->ar_datalen);
- if (r == -1) {
- if (errno == ENOMEM)
- ar->ar_gai_errno = EAI_MEMORY;
- else
- ar->ar_gai_errno = EAI_FAIL;
- async_set_state(as, ASR_STATE_HALT);
- } else
- async_set_state(as, ASR_STATE_NEXT_FAMILY);
- free(ar->ar_data);
- break;
-
- case ASR_STATE_NOT_FOUND:
- /* XXX the exact error depends on what query/send returned */
- ar->ar_gai_errno = EAI_NODATA;
- async_set_state(as, ASR_STATE_HALT);
- break;
-
- case ASR_STATE_HALT:
- if (ar->ar_gai_errno == 0) {
- ar->ar_count = as->as_count;
- ar->ar_addrinfo = as->as.ai.aifirst;
- as->as.ai.aifirst = NULL;
- } else {
- ar->ar_count = 0;
- ar->ar_addrinfo = NULL;
- }
- return (ASYNC_DONE);
-
- default:
- ar->ar_errno = EOPNOTSUPP;
- ar->ar_gai_errno = EAI_SYSTEM;
- async_set_state(as, ASR_STATE_HALT);
- break;
- }
- goto next;
-}
-
-static int
-addrinfo_add(struct async *as, int family, const void *addr, size_t addrlen,
- const char *name)
-{
- struct addrinfo *ai;
-
- if ((ai = calloc(1, sizeof (*ai) + addrlen)) == NULL)
- return (-1);
-
- ai->ai_family = family;
- ai->ai_addrlen = addrlen;
- ai->ai_addr = (void*)(ai + 1);
- if (name && (ai->ai_canonname = strdup(name)) == NULL) {
- free(ai);
- return (-1);
- }
- memmove(ai->ai_addr, addr, addrlen);
-
- if (!as->as.ai.aifirst)
- as->as.ai.aifirst = ai;
- if (as->as.ai.ailast)
- as->as.ai.ailast->ai_next = ai;
- as->as.ai.ailast = ai;
- as->as_count += 1;
-
- return (0);
-}
-
-static int
-addrinfo_from_file(struct async *as, int family, FILE *f)
-{
- char *tokens[MAXTOKEN], *c;
- int n, i;
- union {
- struct sockaddr sa;
- struct sockaddr_in sain;
- struct sockaddr_in6 sain6;
- } u;
-
- for(;;) {
- n = asr_parse_namedb_line(f, tokens, MAXTOKEN);
- if (n == -1)
- break; /* ignore errors reading the file */
-
- for (i = 1; i < n; i++) {
- if (strcasecmp(as->as.ai.hostname, tokens[i]))
- continue;
- if (sockaddr_from_str(&u.sa, family, tokens[0]) == -1)
- continue;
- break;
- }
- if (i == n)
- continue;
-
- if (as->as.ai.hints.ai_flags & AI_CANONNAME)
- c = tokens[1];
- else if (as->as.ai.hints.ai_flags & AI_FQDN)
- c = as->as.ai.hostname;
- else
- c = NULL;
-
- if (addrinfo_add(as, u.sa.sa_family, &u.sa, u.sa.sa_len, c))
- return (-1); /* errno set */
- }
- return (0);
-}
-
-static int
-addrinfo_from_pkt(struct async *as, char *pkt, size_t pktlen)
-{
- struct packed p;
- struct header h;
- struct query q;
- struct rr rr;
- int i;
- union {
- struct sockaddr sa;
- struct sockaddr_in sain;
- struct sockaddr_in6 sain6;
- } u;
- char buf[MAXDNAME], *c;
-
- packed_init(&p, pkt, pktlen);
- unpack_header(&p, &h);
- for(; h.qdcount; h.qdcount--)
- unpack_query(&p, &q);
-
- for (i = 0; i < h.ancount; i++) {
- unpack_rr(&p, &rr);
- if (rr.rr_type != q.q_type ||
- rr.rr_class != q.q_class)
- continue;
-
- memset(&u, 0, sizeof u);
- if (rr.rr_type == T_A) {
- u.sain.sin_len = sizeof u.sain;
- u.sain.sin_family = AF_INET;
- u.sain.sin_addr = rr.rr.in_a.addr;
- u.sain.sin_port = 0;
- } else if (rr.rr_type == T_AAAA) {
- u.sain6.sin6_len = sizeof u.sain6;
- u.sain6.sin6_family = AF_INET6;
- u.sain6.sin6_addr = rr.rr.in_aaaa.addr6;
- u.sain6.sin6_port = 0;
- } else
- continue;
-
- if (as->as.ai.hints.ai_flags & AI_CANONNAME) {
- asr_strdname(rr.rr_dname, buf, sizeof buf);
- buf[strlen(buf) - 1] = '\0';
- c = buf;
- } else if (as->as.ai.hints.ai_flags & AI_FQDN)
- c = as->as.ai.hostname;
- else
- c = NULL;
-
- if (addrinfo_add(as, u.sa.sa_family, &u.sa, u.sa.sa_len, c))
- return (-1); /* errno set */
- }
- return (0);
-}
-
-#ifdef YP
-static int
-strsplit(char *line, char **tokens, int ntokens)
-{
- int ntok;
- char *cp, **tp;
-
- for(cp = line, tp = tokens, ntok = 0;
- ntok < ntokens && (*tp = strsep(&cp, " \t")) != NULL; )
- if (**tp != '\0') {
- tp++;
- ntok++;
- }
-
- return (ntok);
-}
-
-static int
-addrinfo_from_yp(struct async *as, int family, char *line)
-{
- char *next, *tokens[MAXTOKEN], *c;
- int i, ntok;
- union {
- struct sockaddr sa;
- struct sockaddr_in sain;
- struct sockaddr_in6 sain6;
- } u;
-
- for(next = line; line; line = next) {
- if ((next = strchr(line, '\n'))) {
- *next = '\0';
- next += 1;
- }
- ntok = strsplit(line, tokens, MAXTOKEN);
- if (ntok < 2)
- continue;
-
- if (sockaddr_from_str(&u.sa, family, tokens[0]) == -1)
- continue;
-
- if (as->as.ai.hints.ai_flags & AI_CANONNAME)
- c = tokens[1];
- else if (as->as.ai.hints.ai_flags & AI_FQDN)
- c = as->as.ai.hostname;
- else
- c = NULL;
-
- if (addrinfo_add(as, u.sa.sa_family, &u.sa, u.sa.sa_len, c))
- return (-1); /* errno set */
- }
- return (0);
-}
-#endif