diff options
author | 2012-09-05 21:49:12 +0000 | |
---|---|---|
committer | 2012-09-05 21:49:12 +0000 | |
commit | c5c8c49b7d93a9614396fdca60ffe24909e44a3b (patch) | |
tree | 6f9c14b8f149796d3563694a52b02558c6425fba /lib/libc | |
parent | run regress with the local env too (diff) | |
download | wireguard-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.inc | 6 | ||||
-rw-r--r-- | lib/libc/asr/asr.c | 13 | ||||
-rw-r--r-- | lib/libc/asr/asr_debug.c | 6 | ||||
-rw-r--r-- | lib/libc/asr/asr_private.h | 8 | ||||
-rw-r--r-- | lib/libc/asr/getaddrinfo_async.c | 354 | ||||
-rw-r--r-- | lib/libc/asr/hostaddr_async.c | 442 |
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 |