/*----- Static variables --------------------------------------------------*/
+#ifdef HAVE_LIBADNS
+ static adns_state ads;
+ sel_hook hook;
+#endif
static admin *admins;
static admin *a_dead;
static sel_file sock;
/*----- 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
a_bgrelease(&r->bg);
}
+#endif
+
/* --- @a_restimer@ --- *
*
* Arguments: @struct timeval *tv@ = timer
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);
}
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@ --- *
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 --- */
{ fam = "ANY"; af = AF_UNSPEC; i++; }
else for (j = 0; j < NADDRFAM; j++) {
if (mystrieq(av[i], aftab[j].name)) {
- assert(udpsock[j].fd >= 0);
+ if (udpsock[j].fd < 0) {
+ a_fail(a, "disabled-address-family", "%s", aftab[j].name, A_END);
+ goto fail;
+ }
fam = aftab[j].name;
af = aftab[j].af;
i++;
T( trace(T_ADMIN, "admin: %u, resop %s, hostname `%s', family `%s'",
a->seq, BGTAG(r), r->addr, fam); )
- /* --- Make sure the address family is something we can implement --- */
-
- if (af != AF_UNSPEC && af != AF_INET) {
- T( trace(T_ADMIN, "admin: resop %s failed: unsupported address family",
- BGTAG(r)); )
- a_bgfail(&r->bg, "resolve-error", "%s", r->addr, A_END);
- goto fail_release;
- }
- assert(udpsock[AFIX_INET].fd >= 0);
-
/* --- If the name is numeric, do it the easy way --- */
- aihint.ai_family = AF_INET;
+ aihint.ai_family = af;
aihint.ai_socktype = SOCK_DGRAM;
aihint.ai_protocol = IPPROTO_UDP;
aihint.ai_flags = AI_NUMERICHOST;
gettimeofday(&tv, 0);
tv.tv_sec += T_RESOLVE;
sel_addtimer(&sel, &r->t, &tv, a_restimer, r);
+#ifdef HAVE_LIBADNS
+ qf = adns_qf_search;
+ for (j = 0; j < NADDRFAM; j++) {
+ if ((af == AF_UNSPEC || af == aftab[i].af) && udpsock[j].fd >= 0)
+ qf |= aftab[j].qf;
+ }
+ 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
+ if (af != AF_UNSPEC && af != AF_INET) {
+ T( trace(T_ADMIN, "admin: resop %s failed: unsupported address family",
+ BGTAG(r)); )
+ a_bgfail(&r->bg, "resolve-error", "%s", r->addr, A_END);
+ goto fail_release;
+ }
+ if (udpsock[AFIX_INET].fd < 0) {
+ a_bgfail(&r->bg, "disabled-address-family", "INET", A_END);
+ goto fail_release;
+ }
bres_byname(&r->r, r->addr, a_resolved, r);
+#endif
return;
fail:
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;
struct sigaction sa;
size_t sz;
mode_t omask;
+#ifdef HAVE_LIBADNS
+ int err;
+#endif
/* --- Create services table --- */
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;