diff options
author | 2014-02-25 18:30:17 +0100 | |
---|---|---|
committer | 2014-02-25 18:30:17 +0100 | |
commit | f403306c30ae1433c682a9bfa22ce0a286c92e73 (patch) | |
tree | ea6c0a5fa3a947378e836fcdc905b8b98a30eac2 /contrib | |
parent | do not corrupt session (diff) | |
download | OpenSMTPD-f403306c30ae1433c682a9bfa22ce0a286c92e73.tar.xz OpenSMTPD-f403306c30ae1433c682a9bfa22ce0a286c92e73.zip |
sync asr
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/lib/libc/asr/asr_utils.c | 4 | ||||
-rw-r--r-- | contrib/lib/libc/asr/getaddrinfo_async.c | 184 | ||||
-rw-r--r-- | contrib/lib/libc/asr/gethostnamadr_async.c | 8 | ||||
-rw-r--r-- | contrib/lib/libc/asr/getnetnamadr_async.c | 5 | ||||
-rw-r--r-- | contrib/lib/libc/asr/res_init.c | 5 | ||||
-rw-r--r-- | contrib/lib/libc/asr/res_search_async.c | 2 |
6 files changed, 179 insertions, 29 deletions
diff --git a/contrib/lib/libc/asr/asr_utils.c b/contrib/lib/libc/asr/asr_utils.c index 7638d4f6..871ccc1a 100644 --- a/contrib/lib/libc/asr/asr_utils.c +++ b/contrib/lib/libc/asr/asr_utils.c @@ -56,10 +56,6 @@ dname_check_label(const char *s, size_t l) if (l == 0 || l > 63) return (-1); - for (l--; l; l--, s++) - if (!(isalnum((unsigned char)*s) || *s == '_' || *s == '-')) - return (-1); - return (0); } diff --git a/contrib/lib/libc/asr/getaddrinfo_async.c b/contrib/lib/libc/asr/getaddrinfo_async.c index 9b5eeb13..054e2084 100644 --- a/contrib/lib/libc/asr/getaddrinfo_async.c +++ b/contrib/lib/libc/asr/getaddrinfo_async.c @@ -29,6 +29,7 @@ #include <err.h> #include <errno.h> +#include <resolv.h> /* for res_hnok */ #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -45,6 +46,7 @@ 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 iter_domain(struct async *, const char *, char *, size_t); 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); @@ -68,6 +70,12 @@ static const struct match matches[] = { #define MATCH_SOCKTYPE(a, b) ((a) == matches[(b)].socktype || ((a) == 0 && \ matches[(b)].socktype != SOCK_RAW)) +enum { + DOM_INIT, + DOM_DOMAIN, + DOM_DONE +}; + struct async * getaddrinfo_async(const char *hostname, const char *servname, const struct addrinfo *hints, struct asr *asr) @@ -109,6 +117,7 @@ getaddrinfo_async_run(struct async *as, struct async_res *ar) int len; char alias[MAXDNAME], *name; #endif + char fqdn[MAXDNAME]; const char *str; struct addrinfo *ai; int i, family, r; @@ -290,9 +299,38 @@ getaddrinfo_async_run(struct async *as, struct async_res *ar) ar->ar_gai_errno = 0; async_set_state(as, ASR_STATE_HALT); } else - async_set_state(as, ASR_STATE_NEXT_DB); + async_set_state(as, ASR_STATE_NEXT_DOMAIN); + break; + } + async_set_state(as, ASR_STATE_SAME_DB); + break; + + case ASR_STATE_NEXT_DOMAIN: + /* domain search is only for dns */ + if (AS_DB(as) != ASR_DB_DNS) { + async_set_state(as, ASR_STATE_NEXT_DB); + break; + } + as->as_family_idx = 0; + + free(as->as.ai.fqdn); + as->as.ai.fqdn = NULL; + r = iter_domain(as, as->as.ai.hostname, fqdn, sizeof(fqdn)); + if (r == -1) { + async_set_state(as, ASR_STATE_NEXT_DB); + break; + } + if (r == 0) { + ar->ar_gai_errno = EAI_FAIL; + async_set_state(as, ASR_STATE_HALT); break; } + as->as.ai.fqdn = strdup(fqdn); + if (as->as.ai.fqdn == NULL) { + ar->ar_gai_errno = EAI_MEMORY; + async_set_state(as, ASR_STATE_HALT); + } + async_set_state(as, ASR_STATE_SAME_DB); break; @@ -300,20 +338,21 @@ getaddrinfo_async_run(struct async *as, struct async_res *ar) /* query the current DB again */ switch (AS_DB(as)) { case ASR_DB_DNS: + if (as->as.ai.fqdn == NULL) { + /* First try, initialize domain iteration */ + as->as_dom_flags = 0; + as->as_dom_step = DOM_INIT; + async_set_state(as, ASR_STATE_NEXT_DOMAIN); + break; + } + family = (as->as.ai.hints.ai_family == AF_UNSPEC) ? AS_FAMILY(as) : as->as.ai.hints.ai_family; - if (as->as.ai.fqdn) { - as->as.ai.subq = res_query_async_ctx( - as->as.ai.fqdn, C_IN, - (family == AF_INET6) ? T_AAAA : T_A, - as->as_ctx); - } - else { - as->as.ai.subq = res_search_async_ctx( - as->as.ai.hostname, C_IN, - (family == AF_INET6) ? T_AAAA : T_A, - as->as_ctx); - } + + as->as.ai.subq = res_query_async_ctx(as->as.ai.fqdn, + C_IN, (family == AF_INET6) ? T_AAAA : T_A, + as->as_ctx); + if (as->as.ai.subq == NULL) { if (errno == ENOMEM) ar->ar_gai_errno = EAI_MEMORY; @@ -505,6 +544,115 @@ iter_family(struct async *as, int first) } /* + * Concatenate a name and a domain name. The result has no trailing dot. + * Return the resulting string length, or 0 in case of error. + */ +static size_t +domcat(const char *name, const char *domain, char *buf, size_t buflen) +{ + size_t r; + + r = asr_make_fqdn(name, domain, buf, buflen); + if (r == 0) + return (0); + buf[r - 1] = '\0'; + + return (r - 1); +} + +/* + * Implement the search domain strategy. + * + * XXX duplicate from res_search_async + * + * This function works as a generator that constructs complete domains in + * buffer "buf" of size "len" for the given host name "name", according to the + * search rules defined by the resolving context. It is supposed to be called + * multiple times (with the same name) to generate the next possible domain + * name, if any. + * + * It returns -1 if all possibilities have been exhausted, 0 if there was an + * error generating the next name, or the resulting name length. + */ +static int +iter_domain(struct async *as, const char *name, char * buf, size_t len) +{ + const char *c; + int dots; + + switch (as->as_dom_step) { + + case DOM_INIT: + /* First call */ + + /* + * If "name" is an FQDN, that's the only result and we + * don't try anything else. + */ + if (strlen(name) && name[strlen(name) - 1] == '.') { + DPRINT("asr: iter_domain(\"%s\") fqdn\n", name); + as->as_dom_flags |= ASYNC_DOM_FQDN; + as->as_dom_step = DOM_DONE; + return (domcat(name, NULL, buf, len)); + } + + /* + * Otherwise, we iterate through the specified search domains. + */ + as->as_dom_step = DOM_DOMAIN; + as->as_dom_idx = 0; + + /* + * If "name" as enough dots, use it as-is first, as indicated + * in resolv.conf(5). + */ + dots = 0; + for (c = name; *c; c++) + dots += (*c == '.'); + if (dots >= as->as_ctx->ac_ndots) { + DPRINT("asr: iter_domain(\"%s\") ndots\n", name); + as->as_dom_flags |= ASYNC_DOM_NDOTS; + if (strlcpy(buf, name, len) >= len) + return (0); + return (strlen(buf)); + } + /* Otherwise, starts using the search domains */ + /* FALLTHROUGH */ + + case DOM_DOMAIN: + if (as->as_dom_idx < as->as_ctx->ac_domcount) { + DPRINT("asr: iter_domain(\"%s\") domain \"%s\"\n", + name, as->as_ctx->ac_dom[as->as_dom_idx]); + as->as_dom_flags |= ASYNC_DOM_DOMAIN; + return (domcat(name, + as->as_ctx->ac_dom[as->as_dom_idx++], buf, len)); + } + + /* No more domain to try. */ + + as->as_dom_step = DOM_DONE; + + /* + * If the name was not tried as an absolute name before, + * do it now. + */ + if (!(as->as_dom_flags & ASYNC_DOM_NDOTS)) { + DPRINT("asr: iter_domain(\"%s\") as is\n", name); + as->as_dom_flags |= ASYNC_DOM_ASIS; + if (strlcpy(buf, name, len) >= len) + return (0); + return (strlen(buf)); + } + /* Otherwise, we are done. */ + + case DOM_DONE: + default: + DPRINT("asr: iter_domain(\"%s\") done\n", name); + return (-1); + } +} + +/* * Use the sockaddr at "sa" to extend the result list on the "as" context, * with the specified canonical name "cname". This function adds one * entry per protocol/socktype match. @@ -652,14 +800,6 @@ addrinfo_from_pkt(struct async *as, char *pkt, size_t pktlen) rr.rr_class != q.q_class) continue; - if (as->as.ai.fqdn == NULL) { - asr_strdname(q.q_dname, buf, sizeof buf); - buf[strlen(buf) - 1] = '\0'; - as->as.ai.fqdn = strdup(buf); - if (as->as.ai.fqdn == NULL) - return (-1); /* errno set */ - } - memset(&u, 0, sizeof u); if (rr.rr_type == T_A) { #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN @@ -681,7 +821,7 @@ addrinfo_from_pkt(struct async *as, char *pkt, size_t pktlen) if (as->as.ai.hints.ai_flags & AI_CANONNAME) { asr_strdname(rr.rr_dname, buf, sizeof buf); buf[strlen(buf) - 1] = '\0'; - c = buf; + c = res_hnok(buf) ? buf : NULL; } else if (as->as.ai.hints.ai_flags & AI_FQDN) c = as->as.ai.fqdn; else diff --git a/contrib/lib/libc/asr/gethostnamadr_async.c b/contrib/lib/libc/asr/gethostnamadr_async.c index 92f658d6..1d8d8509 100644 --- a/contrib/lib/libc/asr/gethostnamadr_async.c +++ b/contrib/lib/libc/asr/gethostnamadr_async.c @@ -32,6 +32,7 @@ #include <ctype.h> #include <err.h> #include <errno.h> +#include <resolv.h> /* for res_hnok */ #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -507,8 +508,7 @@ hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen) if (strcasecmp(rr.rr_dname, dname) != 0) continue; if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1) - goto fail; - /* XXX See if we need MULTI_PTRS_ARE_ALIASES */ + hostent_add_alias(h, rr.rr.ptr.ptrname, 1); break; case T_A: @@ -573,6 +573,8 @@ hostent_set_cname(struct hostent_ext *h, const char *name, int isdname) if (isdname) { asr_strdname(name, buf, sizeof buf); buf[strlen(buf) - 1] = '\0'; + if (!res_hnok(buf)) + return (-1); name = buf; } @@ -601,6 +603,8 @@ hostent_add_alias(struct hostent_ext *h, const char *name, int isdname) if (isdname) { asr_strdname(name, buf, sizeof buf); buf[strlen(buf)-1] = '\0'; + if (!res_hnok(buf)) + return (-1); name = buf; } diff --git a/contrib/lib/libc/asr/getnetnamadr_async.c b/contrib/lib/libc/asr/getnetnamadr_async.c index 9a40638e..128e598d 100644 --- a/contrib/lib/libc/asr/getnetnamadr_async.c +++ b/contrib/lib/libc/asr/getnetnamadr_async.c @@ -25,6 +25,7 @@ #include <err.h> #include <errno.h> +#include <resolv.h> /* for res_hnok */ #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -402,6 +403,8 @@ netent_set_cname(struct netent_ext *n, const char *name, int isdname) if (isdname) { asr_strdname(name, buf, sizeof buf); buf[strlen(buf) - 1] = '\0'; + if (!res_hnok(buf)) + return (-1); name = buf; } @@ -431,6 +434,8 @@ netent_add_alias(struct netent_ext *n, const char *name, int isdname) if (isdname) { asr_strdname(name, buf, sizeof buf); buf[strlen(buf)-1] = '\0'; + if (!res_hnok(buf)) + return (-1); name = buf; } diff --git a/contrib/lib/libc/asr/res_init.c b/contrib/lib/libc/asr/res_init.c index c8958793..136a6a11 100644 --- a/contrib/lib/libc/asr/res_init.c +++ b/contrib/lib/libc/asr/res_init.c @@ -37,6 +37,7 @@ res_init(void) { _THREAD_PRIVATE_MUTEX(init); struct asr_ctx *ac; + int i; ac = asr_use_resolver(NULL); @@ -55,6 +56,10 @@ res_init(void) strlcpy(_res.lookups, ac->ac_db, sizeof(_res.lookups)); _res.nscount = ac->ac_nscount; + for (i = 0; i < ac->ac_nscount; i++) { + memcpy(&_res.nsaddr_list[i], ac->ac_ns[i], + SA_LEN(ac->ac_ns[i])); + } _res.options |= RES_INIT; } _THREAD_PRIVATE_MUTEX_UNLOCK(init); diff --git a/contrib/lib/libc/asr/res_search_async.c b/contrib/lib/libc/asr/res_search_async.c index 3c93fb02..e6017d55 100644 --- a/contrib/lib/libc/asr/res_search_async.c +++ b/contrib/lib/libc/asr/res_search_async.c @@ -162,7 +162,7 @@ res_search_async_run(struct async *as, struct async_res *ar) /* * The original resolver does something like this. */ - if (as->as_dom_flags & (ASYNC_DOM_NDOTS | ASYNC_DOM_ASIS)) + if (as->as_dom_flags & ASYNC_DOM_NDOTS) as->as.search.saved_h_errno = ar->ar_h_errno; if (as->as_dom_flags & ASYNC_DOM_DOMAIN) { |