From 971e56892e36f3351b123200dc1df5b7845aebd7 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Fri, 29 Sep 2017 09:51:58 +0100 Subject: [PATCH] server/: Maybe use GNU ADNS rather than mLib's `bres' for name resolution. This will let us do IPv6 resolution later. For now, very little looks like it's changed. --- configure.ac | 21 ++++++++ server/Makefile.am | 3 +- server/admin.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++- server/tripe.h | 13 ++++- 4 files changed, 175 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 84fcf5a9..887f81d3 100644 --- a/configure.ac +++ b/configure.ac @@ -63,6 +63,27 @@ case "$host_os" in ;; esac +AC_ARG_WITH([adns], + AS_HELP_STRING([--with-adns], + [use ADNS library for background name resolution]), + [want_adns=$withval], + [want_adns=auto]) +case $want_adns in + no) ;; + *) AC_CHECK_LIB([adns], [adns_submit], [have_adns=yes], [have_adns=no]) ;; +esac +AC_SUBST([ADNS_LIBS]) +case $want_adns,$have_adns in + yes,no) + AC_MSG_ERROR([ADNS library not found but explicitly requested]) + ;; + yes,yes | auto,yes) + ADNS_LIBS="-ladns" + AC_DEFINE([HAVE_LIBADNS], [1], + [Define if the GNU adns library is available.]) + ;; +esac + PKG_CHECK_MODULES([mLib], [mLib >= 2.2.1]) PKG_CHECK_MODULES([catacomb], [catacomb >= 2.2.2-38]) diff --git a/server/Makefile.am b/server/Makefile.am index a483aefd..1e6d71bc 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -27,7 +27,8 @@ include $(top_srcdir)/vars.am sbin_PROGRAMS = man_MANS = -LDADD = $(libtripe) $(libpriv) $(catacomb_LIBS) +LDADD = $(libtripe) $(libpriv) \ + $(catacomb_LIBS) $(ADNS_LIBS) ###-------------------------------------------------------------------------- ### The main server. diff --git a/server/admin.c b/server/admin.c index 44222eb8..58230baf 100644 --- a/server/admin.c +++ b/server/admin.c @@ -61,6 +61,10 @@ static const trace_opt w_opts[] = { /*----- Static variables --------------------------------------------------*/ +#ifdef HAVE_LIBADNS + static adns_state ads; + sel_hook hook; +#endif static admin *admins; static admin *a_dead; static sel_file sock; @@ -1011,6 +1015,101 @@ static void a_svcrelease(admin_service *svc) /*----- Name resolution operations ----------------------------------------*/ +#ifdef HAVE_LIBADNS + +/* --- @before_select@ --- * + * + * Arguments: @sel_state *s@ = the @sel@ multiplexor (unused) + * @sel_args *a@ = input to @select@, to be updated + * @void *p@ = a context pointer (unused) + * + * Returns: --- + * + * Use: An I/O multiplexor hook, called just before waiting for I/O + * events. + * + * Currently its main purpose is to wire ADNS into the event + * loop. + */ + +static void before_select(sel_state *s, sel_args *a, void *p) +{ + struct timeval now; + adns_query q; + adns_answer *n; + admin_resop *r; + int any = 0; + + /* --- Check for name-resolution progress --- * + * + * If there is any, then clobber the timeout: one of the resolver + * callbacks might have renewed its interest in a file descriptor, but too + * late to affect this @select@ call. + * + * I think, strictly, this is an mLib bug, but it's cheap enough to hack + * around here. Fixing it will wait for mLib 3. + */ + + for (;;) { + q = 0; + if (adns_check(ads, &q, &n, &p)) break; + r = p; + any = 1; + if (n->status != adns_s_ok) { + T( trace(T_ADMIN, "admin: resop %s failed: %s", + BGTAG(r), adns_strerror(n->status)); ) + a_bgfail(&r->bg, "resolve-error", "%s", r->addr, A_END); + r->func(r, ARES_FAIL); + } else { + T( trace(T_ADMIN, "admin: resop %s ok", BGTAG(r)); ) + assert(n->type == adns_r_addr); + assert(n->nrrs > 0); + assert(n->rrs.addr[0].len <= sizeof(r->sa)); + memcpy(&r->sa, &n->rrs.addr[0].addr, n->rrs.addr[0].len); + setport(&r->sa, r->port); + r->func(r, ARES_OK); + } + free(n); + sel_rmtimer(&r->t); + xfree(r->addr); + a_bgrelease(&r->bg); + } + + if (any) { a->tvp = &a->tv; a->tv.tv_sec = 0; a->tv.tv_usec = 0; } + + gettimeofday(&now, 0); + adns_beforeselect(ads, &a->maxfd, + &a->fd[SEL_READ], &a->fd[SEL_WRITE], &a->fd[SEL_EXC], + &a->tvp, &a->tv, &now); +} + +/* --- @after_select@ --- * + * + * Arguments: @sel_state *s@ = the @sel@ multiplexor (unused) + * @sel_args *a@ = input to @select@, to be updated + * @void *p@ = a context pointer (unused) + * + * Returns: --- + * + * Use: An I/O multiplexor hook, called just after waiting for I/O + * events. + * + * Currently its main purpose is to wire ADNS into the event + * loop. + */ + +static void after_select(sel_state *s, sel_args *a, void *p) +{ + struct timeval now; + + gettimeofday(&now, 0); + adns_afterselect(ads, a->maxfd, + &a->fd[SEL_READ], &a->fd[SEL_WRITE], &a->fd[SEL_EXC], + &now); +} + +#else + /* --- @a_resolved@ --- * * * Arguments: @struct hostent *h@ = pointer to resolved hostname @@ -1043,6 +1142,8 @@ static void a_resolved(struct hostent *h, void *v) a_bgrelease(&r->bg); } +#endif + /* --- @a_restimer@ --- * * * Arguments: @struct timeval *tv@ = timer @@ -1060,7 +1161,11 @@ static void a_restimer(struct timeval *tv, void *v) T( trace(T_ADMIN, "admin: resop %s timeout", BGTAG(r)); ) a_bgfail(&r->bg, "resolver-timeout", "%s", r->addr, A_END); r->func(r, ARES_FAIL); +#ifdef HAVE_LIBADNS + adns_cancel(r->q); +#else bres_abort(&r->r); +#endif xfree(r->addr); a_bgrelease(&r->bg); } @@ -1082,7 +1187,11 @@ static void a_rescancel(admin_bgop *bg) r->func(r, ARES_FAIL); sel_rmtimer(&r->t); xfree(r->addr); +#ifdef HAVE_LIBADNS + adns_cancel(r->q); +#else bres_abort(&r->r); +#endif } /* --- @a_resolve@ --- * @@ -1110,6 +1219,10 @@ static void a_resolve(admin *a, admin_resop *r, const char *tag, char *p; int i = 0, j; struct addrinfo *ai, *ailist, aihint = { 0 }; +#ifdef HAVE_LIBADNS + int err; + adns_queryflags qf; +#endif /* --- Fill in the easy bits of address --- */ @@ -1206,7 +1319,17 @@ static void a_resolve(admin *a, admin_resop *r, const char *tag, gettimeofday(&tv, 0); tv.tv_sec += T_RESOLVE; sel_addtimer(&sel, &r->t, &tv, a_restimer, r); +#ifdef HAVE_LIBADNS + qf = adns_qf_search | adns_qf_want_ipv4; + if ((err = adns_submit(ads, r->addr, adns_r_addr, qf, r, &r->q)) != 0) { + T( trace(T_ADMIN, "admin: resop %s adns_submit failed: %s", + BGTAG(r), strerror(err)); ) + a_bgfail(&r->bg, "resolve-error", "%s", r->addr, A_END); + goto fail_release; + } +#else bres_byname(&r->r, r->addr, a_resolved, r); +#endif return; fail: @@ -1731,7 +1854,10 @@ static void acmd_port(admin *a, unsigned ac, char *av[]) a_fail(a, "unknown-address-family", "%s", av[0], A_END); return; found: - assert(udpsock[i].fd >= 0); + if (udpsock[i].fd < 0) { + a_fail(a, "disabled-address-family", "%s", aftab[i].name, A_END); + return; + } } else { for (i = 0; i < NADDRFAM; i++) if (udpsock[i].fd >= 0) goto found; @@ -2358,6 +2484,9 @@ void a_init(const char *name, uid_t u, gid_t g, mode_t m) struct sigaction sa; size_t sz; mode_t omask; +#ifdef HAVE_LIBADNS + int err; +#endif /* --- Create services table --- */ @@ -2424,7 +2553,17 @@ again: sel_initfile(&sel, &sock, fd, SEL_READ, a_accept, 0); sel_addfile(&sock); sockname = name; +#ifdef HAVE_LIBADNS + if ((err = adns_init(&ads, + (adns_if_permit_ipv4 | adns_if_permit_ipv6 | + adns_if_noserverwarn | adns_if_nosigpipe | + adns_if_noautosys), + 0)) != 0) + die(EXIT_FAILURE, "failed to initialize ADNS: %s", strerror(errno)); + sel_addhook(&sel, &hook, before_select, after_select, 0); +#else bres_init(&sel); +#endif T( trace_custom(a_trace, 0); trace(T_ADMIN, "admin: enabled custom tracing"); ) flags |= F_INIT; diff --git a/server/tripe.h b/server/tripe.h index fc866b8a..6946c5f1 100644 --- a/server/tripe.h +++ b/server/tripe.h @@ -62,10 +62,17 @@ #include #include +#ifdef HAVE_LIBADNS +# define ADNS_FEATURE_MANYAF +# include +#endif + #include #include #include -#include +#ifndef HAVE_LIBADNS +# include +#endif #include #include #include @@ -689,7 +696,11 @@ typedef struct admin_bgop { typedef struct admin_resop { admin_bgop bg; /* Background operation header */ char *addr; /* Hostname to be resolved */ +#ifdef HAVE_LIBADNS + adns_query q; +#else bres_client r; /* Background resolver task */ +#endif sel_timer t; /* Timer for resolver */ addr sa; /* Socket address */ unsigned port; /* Port number chosen */ -- 2.11.0