diff options
Diffstat (limited to 'lib/libc/asr/res_search_async.c')
-rw-r--r-- | lib/libc/asr/res_search_async.c | 117 |
1 files changed, 116 insertions, 1 deletions
diff --git a/lib/libc/asr/res_search_async.c b/lib/libc/asr/res_search_async.c index c3cae7683dd..8bc950db7bb 100644 --- a/lib/libc/asr/res_search_async.c +++ b/lib/libc/asr/res_search_async.c @@ -1,4 +1,4 @@ -/* $OpenBSD: res_search_async.c,v 1.8 2013/06/01 14:34:34 eric Exp $ */ +/* $OpenBSD: res_search_async.c,v 1.9 2013/06/01 15:02:01 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> * @@ -29,6 +29,8 @@ #include "asr_private.h" static int res_search_async_run(struct async *, struct async_res *); +size_t asr_domcat(const char *, const char *, char *, size_t); +int asr_iter_domain(struct async *, const char *, char *, size_t); /* * Unlike res_query_async(), this function returns a valid packet only if @@ -200,3 +202,116 @@ res_search_async_run(struct async *as, struct async_res *ar) } goto next; } + +/* + * Concatenate a name and a domain name. The result has no trailing dot. + * Return the resulting string length, or 0 in case of error. + */ +size_t +asr_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); +} + +enum { + DOM_INIT, + DOM_DOMAIN, + DOM_DONE +}; + +/* + * Implement the search domain strategy. + * + * 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. + */ +int +asr_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: asr_iter_domain(\"%s\") fqdn\n", name); + as->as_dom_flags |= ASYNC_DOM_FQDN; + as->as_dom_step = DOM_DONE; + return (asr_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: 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: 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 (asr_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: 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: asr_iter_domain(\"%s\") done\n", name); + return (-1); + } +} |