summaryrefslogtreecommitdiffstats
path: root/lib/libc/asr/res_search_async.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/asr/res_search_async.c')
-rw-r--r--lib/libc/asr/res_search_async.c117
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);
+ }
+}