diff options
author | Eric Faurot <eric@cvs.openbsd.org> | 2012-09-05 15:56:14 +0000 |
---|---|---|
committer | Eric Faurot <eric@cvs.openbsd.org> | 2012-09-05 15:56:14 +0000 |
commit | aa51fd5de93ee82630863a2588f0e303e69a5648 (patch) | |
tree | 1a158fbca0e80f91c9810c0cf66635872df324c0 /lib | |
parent | e12ba72be62c4fcf3878a0e29f4a3ce81accbfbf (diff) |
Make hostaddr_async() return a linked list of struct addrinfo. First
round of a getaddrinfo_async() simplification. The goal is to make YP
support easier to add, and eventually remove the whole hostaddr_async
subquery.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/asr/asr.c | 16 | ||||
-rw-r--r-- | lib/libc/asr/asr_debug.c | 4 | ||||
-rw-r--r-- | lib/libc/asr/asr_private.h | 27 | ||||
-rw-r--r-- | lib/libc/asr/getaddrinfo_async.c | 43 | ||||
-rw-r--r-- | lib/libc/asr/hostaddr_async.c | 326 |
5 files changed, 200 insertions, 216 deletions
diff --git a/lib/libc/asr/asr.c b/lib/libc/asr/asr.c index d4db4ed2606..a0c7125594d 100644 --- a/lib/libc/asr/asr.c +++ b/lib/libc/asr/asr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: asr.c,v 1.4 2012/08/18 16:48:17 eric Exp $ */ +/* $OpenBSD: asr.c,v 1.5 2012/09/05 15:56:13 eric Exp $ */ /* * Copyright (c) 2010-2012 Eric Faurot <eric@openbsd.org> * @@ -309,14 +309,12 @@ async_free(struct async *as) break; case ASR_HOSTADDR: - if (as->as.host.name) - free(as->as.host.name); - if (as->as.host.subq) - async_free(as->as.host.subq); - if (as->as.host.pkt) - free(as->as.host.pkt); - if (as->as.host.file) - fclose(as->as.host.file); + 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; } diff --git a/lib/libc/asr/asr_debug.c b/lib/libc/asr/asr_debug.c index fcb605dc7e3..45f1976ec08 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.4 2012/07/07 20:41:52 eric Exp $ */ +/* $OpenBSD: asr_debug.c,v 1.5 2012/09/05 15:56:13 eric Exp $ */ /* * Copyright (c) 2010-2012 Eric Faurot <eric@openbsd.org> * @@ -441,8 +441,6 @@ struct kv kv_state[] = { { 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_READ_RR, "ASR_STATE_READ_RR" }, - { ASR_STATE_READ_FILE, "ASR_STATE_READ_FILE" }, { ASR_STATE_UDP_SEND, "ASR_STATE_UDP_SEND" }, { ASR_STATE_UDP_RECV, "ASR_STATE_UDP_RECV" }, { ASR_STATE_TCP_WRITE, "ASR_STATE_TCP_WRITE" }, diff --git a/lib/libc/asr/asr_private.h b/lib/libc/asr/asr_private.h index ddc3eb5da2d..b346f316649 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.3 2012/07/07 20:41:52 eric Exp $ */ +/* $OpenBSD: asr_private.h,v 1.4 2012/09/05 15:56:13 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> * @@ -268,30 +268,7 @@ struct async { int flags; struct async *subq; } ni; - - struct { - char *name; - int family; - int aiflags; - union { - struct sockaddr sa; - struct sockaddr_in sain; - struct sockaddr_in6 sain6; - } sa; - - struct async *subq; - int class; - int type; - int ancount; - unsigned char *pkt; - size_t pktlen; - size_t pktpos; - FILE *file; #define MAXTOKEN 10 - char *tokens[MAXTOKEN]; - int token_count; - int token_idx; - } host; } as; }; @@ -309,8 +286,6 @@ enum asr_state { ASR_STATE_NEXT_FAMILY, ASR_STATE_LOOKUP_FAMILY, ASR_STATE_NEXT_NS, - ASR_STATE_READ_RR, - ASR_STATE_READ_FILE, ASR_STATE_UDP_SEND, ASR_STATE_UDP_RECV, ASR_STATE_TCP_WRITE, diff --git a/lib/libc/asr/getaddrinfo_async.c b/lib/libc/asr/getaddrinfo_async.c index 7eb502256b8..a31fd31f9bc 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.5 2012/08/18 11:19:51 eric Exp $ */ +/* $OpenBSD: getaddrinfo_async.c,v 1.6 2012/09/05 15:56:13 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> * @@ -298,36 +298,33 @@ getaddrinfo_async_run(struct async *as, struct async_res *ar) if ((r = async_run(as->as.ai.subq, ar)) == ASYNC_COND) return (ASYNC_COND); - /* Got one more address, use it to extend the result list. */ - if (r == ASYNC_YIELD) { - if ((r = add_sockaddr(as, &ar->ar_sa.sa, - ar->ar_cname))) { - ar->ar_gai_errno = r; - async_set_state(as, ASR_STATE_HALT); - } - if (ar->ar_cname) - free(ar->ar_cname); - break; - } - /* * The subquery is done. Stop there if we have at least one * answer. */ as->as.ai.subq = NULL; - if (ar->ar_count) { - async_set_state(as, ASR_STATE_HALT); + 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. + */ + if (ar->ar_gai_errno == EAI_AGAIN) + as->as.ai.flags |= ASYNC_AGAIN; + async_set_state(as, ASR_STATE_SEARCH_DOMAIN); break; } - /* - * No anwser for this domain, but we might be suggested to - * try again later, so remember this. Then search the next - * domain. - */ - if (ar->ar_gai_errno == EAI_AGAIN) - as->as.ai.flags |= ASYNC_AGAIN; - async_set_state(as, ASR_STATE_SEARCH_DOMAIN); + /* iterate over and expand results */ + + for(ai = ar->ar_addrinfo; ai; ai = ai->ai_next) { + r = add_sockaddr(as, ai->ai_addr, ai->ai_canonname); + if (r) + break; + } + freeaddrinfo(ar->ar_addrinfo); + ar->ar_gai_errno = r; + async_set_state(as, ASR_STATE_HALT); break; case ASR_STATE_NOT_FOUND: diff --git a/lib/libc/asr/hostaddr_async.c b/lib/libc/asr/hostaddr_async.c index f76c6b0f3d3..c70b7e98202 100644 --- a/lib/libc/asr/hostaddr_async.c +++ b/lib/libc/asr/hostaddr_async.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostaddr_async.c,v 1.2 2012/08/18 13:31:03 eric Exp $ */ +/* $OpenBSD: hostaddr_async.c,v 1.3 2012/09/05 15:56:13 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> * @@ -30,7 +30,9 @@ #include "asr_private.h" static int hostaddr_async_run(struct async *, struct async_res *); -static int sockaddr_from_rr(struct sockaddr *, struct rr *); +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); /* * This API function allows to iterate over host addresses, for the given @@ -60,10 +62,10 @@ hostaddr_async_ctx(const char *name, int family, int flags, struct asr_ctx *ac) goto err; /* errno set */ as->as_run = hostaddr_async_run; - as->as.host.aiflags = flags; - as->as.host.family = family; - as->as.host.name = strdup(buf); - if (as->as.host.name == NULL) + 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); @@ -76,21 +78,18 @@ hostaddr_async_ctx(const char *name, int family, int flags, struct asr_ctx *ac) static int hostaddr_async_run(struct async *as, struct async_res *ar) { - struct packed p; - struct header h; - struct query q; - struct rr rr; - char buf[MAXDNAME], *c, *name; - int i, n, family, type, r; + char *name; + int n, family, type, r; + FILE *file; next: switch(as->as_state) { case ASR_STATE_INIT: - if (as->as.host.family != AF_INET && - as->as.host.family != AF_INET6 && - as->as.host.family != AF_UNSPEC) { + 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; @@ -104,7 +103,8 @@ hostaddr_async_run(struct async *as, struct async_res *ar) case ASR_STATE_NEXT_FAMILY: as->as_family_idx += 1; - if (as->as.host.family != AF_UNSPEC || AS_FAMILY(as) == -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. */ @@ -120,12 +120,10 @@ hostaddr_async_run(struct async *as, struct async_res *ar) 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; @@ -134,19 +132,16 @@ hostaddr_async_run(struct async *as, struct async_res *ar) /* FALLTHROUGH */ case ASR_STATE_SAME_DB: - - /* Query the current DB again. */ - + /* query the current DB again. */ switch(AS_DB(as)) { case ASR_DB_DNS: - - family = (as->as.host.family == AF_UNSPEC) ? - AS_FAMILY(as) : as->as.host.family; + 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.host.name; - as->as.host.subq = res_query_async_ctx(name, C_IN, + 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.host.subq == NULL) { + if (as->as.ai.subq == NULL) { if (errno == ENOMEM) ar->ar_gai_errno = EAI_MEMORY; else @@ -158,12 +153,24 @@ hostaddr_async_run(struct async *as, struct async_res *ar) break; case ASR_DB_FILE: - - as->as.host.file = fopen(as->as_ctx->ac_hostfile, "r"); - if (as->as.host.file == NULL) + file = fopen(as->as_ctx->ac_hostfile, "r"); + if (file == NULL) { async_set_state(as, ASR_STATE_NEXT_DB); - else - async_set_state(as, ASR_STATE_READ_FILE); + break; + } + family = (as->as.ai.hints.ai_family == AF_UNSPEC) ? + AS_FAMILY(as) : as->as.ai.hints.ai_family; + + n = addrinfo_from_file(as, family, file); + if (n == -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; default: @@ -172,111 +179,25 @@ hostaddr_async_run(struct async *as, struct async_res *ar) break; case ASR_STATE_SUBQUERY: - if ((r = async_run(as->as.host.subq, ar)) == ASYNC_COND) + if ((r = async_run(as->as.ai.subq, ar)) == ASYNC_COND) return (ASYNC_COND); - as->as.host.subq = NULL; + as->as.ai.subq = NULL; if (ar->ar_datalen == -1) { async_set_state(as, ASR_STATE_NEXT_DB); break; } - as->as.host.pkt = ar->ar_data; - as->as.host.pktlen = ar->ar_datalen; - packed_init(&p, as->as.host.pkt, as->as.host.pktlen); - unpack_header(&p, &h); - for(; h.qdcount; h.qdcount--) - unpack_query(&p, &q); - as->as.host.pktpos = p.offset; - as->as.host.ancount = h.ancount; - as->as.host.class = q.q_class; - as->as.host.type = q.q_type; - async_set_state(as, ASR_STATE_READ_RR); - break; - - case ASR_STATE_READ_RR: - - /* When done with this NS, try with next family */ - if (as->as.host.ancount == 0) { - free(as->as.host.pkt); - as->as.host.pkt = NULL; + 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); - break; - } - - /* Continue reading the packet where we left it. */ - packed_init(&p, as->as.host.pkt, as->as.host.pktlen); - p.offset = as->as.host.pktpos; - unpack_rr(&p, &rr); - as->as.host.pktpos = p.offset; - as->as.host.ancount -= 1; - if (rr.rr_type == as->as.host.type && - rr.rr_class == as->as.host.class) { - as->as_count += 1; - ar->ar_count = as->as_count; - sockaddr_from_rr(&ar->ar_sa.sa, &rr); - if (as->as.host.aiflags & AI_CANONNAME) - c = asr_strdname(rr.rr_dname, buf, - sizeof buf); - else if (as->as.host.aiflags & AI_FQDN) { - strlcpy(buf, as->as.host.name, sizeof buf); - c = buf; - } else - c = NULL; - if (c) { - if (c[strlen(c) - 1] == '.') - c[strlen(c) - 1] = '\0'; - ar->ar_cname = strdup(c); - } else - ar->ar_cname = NULL; - return (ASYNC_YIELD); - } - break; - - case ASR_STATE_READ_FILE: - - /* When done with the file, try next family. */ - n = asr_parse_namedb_line(as->as.host.file, as->as.host.tokens, - MAXTOKEN); - if (n == -1) { - fclose(as->as.host.file); - as->as.host.file = NULL; - async_set_state(as, ASR_STATE_NEXT_FAMILY); - break; - } - - for (i = 1; i < n; i++) { - if (strcasecmp(as->as.host.name, - as->as.host.tokens[i])) - continue; - - family = as->as.host.family; - if (family == AF_UNSPEC) - family = AS_FAMILY(as); - - if (sockaddr_from_str(&ar->ar_sa.sa, family, - as->as.host.tokens[0]) == -1) - continue; - - if (as->as.host.aiflags & AI_CANONNAME) { - strlcpy(buf, as->as.host.tokens[1], - sizeof buf); - c = buf; - } else if (as->as.host.aiflags & AI_FQDN) { - strlcpy(buf, as->as.host.name, sizeof buf); - c = buf; - } else - c = NULL; - if (c) { - if (c[strlen(c) - 1] == '.') - c[strlen(c) - 1] = '\0'; - ar->ar_cname = strdup(c); - } else - ar->ar_cname = NULL; - as->as_count += 1; - ar->ar_count = as->as_count; - return (ASYNC_YIELD); - } + free(ar->ar_data); break; case ASR_STATE_NOT_FOUND: @@ -284,9 +205,16 @@ hostaddr_async_run(struct async *as, struct async_res *ar) ar->ar_gai_errno = EAI_NODATA; async_set_state(as, ASR_STATE_HALT); break; - + case ASR_STATE_HALT: - ar->ar_count = ar->ar_gai_errno ? 0 : as->as_count; + 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: @@ -299,35 +227,123 @@ hostaddr_async_run(struct async *as, struct async_res *ar) } static int -sockaddr_from_rr(struct sockaddr *sa, struct rr *rr) +addrinfo_add(struct async *as, int family, const void *addr, size_t addrlen, + const char *name) { - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; + struct addrinfo *ai; - if (rr->rr_class != C_IN) + if ((ai = calloc(1, sizeof (*ai) + addrlen)) == NULL) return (-1); - switch (rr->rr_type) { - case T_A: - sin = (struct sockaddr_in*)sa; - memset(sin, 0, sizeof *sin); - sin->sin_len = sizeof *sin; - sin->sin_family = PF_INET; - sin->sin_addr = rr->rr.in_a.addr; - sin->sin_port = 0; - return (0); - case T_AAAA: - sin6 = (struct sockaddr_in6*)sa; - memset(sin6, 0, sizeof *sin6); - sin6->sin6_len = sizeof *sin6; - sin6->sin6_family = PF_INET6; - sin6->sin6_addr = rr->rr.in_aaaa.addr6; - sin6->sin6_port = 0; - return (0); + 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); - default: - break; + 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); +} - return (-1); +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); } |