aboutsummaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorEric Faurot <eric@faurot.net>2014-02-25 18:30:17 +0100
committerEric Faurot <eric@faurot.net>2014-02-25 18:30:17 +0100
commitf403306c30ae1433c682a9bfa22ce0a286c92e73 (patch)
treeea6c0a5fa3a947378e836fcdc905b8b98a30eac2 /contrib
parentdo not corrupt session (diff)
downloadOpenSMTPD-f403306c30ae1433c682a9bfa22ce0a286c92e73.tar.xz
OpenSMTPD-f403306c30ae1433c682a9bfa22ce0a286c92e73.zip
sync asr
Diffstat (limited to 'contrib')
-rw-r--r--contrib/lib/libc/asr/asr_utils.c4
-rw-r--r--contrib/lib/libc/asr/getaddrinfo_async.c184
-rw-r--r--contrib/lib/libc/asr/gethostnamadr_async.c8
-rw-r--r--contrib/lib/libc/asr/getnetnamadr_async.c5
-rw-r--r--contrib/lib/libc/asr/res_init.c5
-rw-r--r--contrib/lib/libc/asr/res_search_async.c2
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) {