From: Arran Cudbard-Bell Date: Wed, 30 Oct 2019 22:05:23 +0000 (-0600) Subject: Untested async io integration layer for libunbound X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d4cd4e2356d78af895b04dc62842e6777d29c989;p=thirdparty%2Ffreeradius-server.git Untested async io integration layer for libunbound --- diff --git a/src/modules/rlm_unbound/all.mk.in b/src/modules/rlm_unbound/all.mk.in index 2dd837d100c..710cef36614 100644 --- a/src/modules/rlm_unbound/all.mk.in +++ b/src/modules/rlm_unbound/all.mk.in @@ -6,7 +6,7 @@ TARGET := $(TARGETNAME).a endif endif -SOURCES := $(TARGETNAME).c +SOURCES := $(TARGETNAME).c io.c SRC_CFLAGS := @mod_cflags@ TGT_LDLIBS := @mod_ldflags@ $(OPENSSL_LIBS) diff --git a/src/modules/rlm_unbound/io.c b/src/modules/rlm_unbound/io.c new file mode 100644 index 00000000000..63897f99d76 --- /dev/null +++ b/src/modules/rlm_unbound/io.c @@ -0,0 +1,559 @@ +/* + * This program is is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * @file rlm_unbound/io.c + * @brief Provides interface between libunbound and the FreeRADIUS event loop + * + * @copyright 2019 The FreeRADIUS server project + * @copyright 2019 Arran Cudbard-Bell (a.cudbardb@freeradius.org) + */ +RCSID("$Id$") + +#define LOG_PREFIX "rlm_unbound - " + +#include +#include +#include + +#include "io.h" + +#ifdef HAVE_WDOCUMENTATION +DIAG_OFF(documentation) +#endif +#include +#ifdef HAVE_WDOCUMENTATION +DIAG_ON(documentation) +#endif + +/** Definition for libunbound's event callback + * + * Here because they don't provide one. + */ +typedef void(*unbound_cb_t)(int, short flags, void *uctx); + +/** Wrapper around our event loop specifying callbacks for creating new event handles + * + * This stores libunbound specific information in addition to the el for the current + * worker thread. It's passed into the 'new_event' callback when a new event handle + * is created. So we use it to pass in the el, and any other useful information. + * + * Lifetime should be bound to the thread instance. + */ +struct unbound_io_event_base_s { + struct ub_event_base base; //!< Interface structure for libunbound. + ///< MUST BE LISTED FIRST. + + rlm_unbound_thread_t *t; //!< Thread instance this event base belongs to. + + fr_event_list_t *el; //!< Event loop events should be inserted into. +}; + +/** Wrapper around event handle for our event loop + * + * This stores libunbound specific information for an event in our event loop. + * + * Lifetime should be bound to the event base. + */ +typedef struct { + struct ub_event base; //!< Unbound event base, which we populate with + ///< callback functions for adding events for FDs + ///< setting timers etc... + ///< MUST BE LISTED FIRST. + + unbound_io_event_base_t *ev_b; //!< Event base this handle was created for. + + fr_event_timer_t const *timer; //!< Stores the pointer to the enabled timer for + ///< this event handled. libunbound uses a single + ///< handle for managing related FD events and + ///< timers, which is weird, but ok... + + short events; //!< The events this event handle should receive + ///< when activated. + + int fd; //!< File descriptor this event handle relates to. + + unbound_cb_t cb; //!< The callback we need to call when a specified + ///< event happens. + + void *uctx; //!< This is the argument libunbound wants passed to + ///< the callback when it's called. It usually + ///< contains libunbound's internal connection handled. + ///< We don't have any visibility, it just remains + ///< an opaque blob to us. + + bool active; //!< Whether this event is considered active. +} unbound_io_event_t; + +/** Alter the enabled flags associated with the event + * + * Event *MUST* be disabled before these flags are changed. + */ +static void _unbound_io_event_flags_add(struct ub_event *ub_ev, short flags) +{ + unbound_io_event_t *ev = talloc_get_type_abort(ub_ev, unbound_io_event_t); + short new = ev->events | flags; + + DEBUG4("unbound event %p - Adding flags %i (current %i, new %i)", ev, flags, ev->events, new); + + rad_assert(!ev->active); /* must not be active */ + + ev->events = new; +} + +/** Alter the enabled flags associated with the event + * + * Event *MUST* be disabled before these flags are changed. + */ +static void _unbound_io_event_flags_del(struct ub_event *ub_ev, short flags) +{ + unbound_io_event_t *ev = talloc_get_type_abort(ub_ev, unbound_io_event_t); + short new = ev->events & ~flags; + + rad_assert(!ev->active); /* must not be active */ + + DEBUG4("unbound event %p - Removing flags %i (current %i, new %i)", ev, flags, ev->events, new); + + ev->events = new; +} + +/** Change the file descriptor associated with an event + * + * Event *MUST* be disabled before changing the fd. + */ +static void _unbound_io_event_fd_set(struct ub_event *ub_ev, int fd) +{ + unbound_io_event_t *ev = talloc_get_type_abort(ub_ev, unbound_io_event_t); + + rad_assert(!ev->active); /* must not be active */ + + DEBUG4("unbound event %p - Changed FD from %i to %i", ev, ev->fd, fd); + + ev->fd = fd; +} + +/** Free an event, and, by the magic of talloc, any timers or fd events + * + */ +static void _unbound_io_event_free(struct ub_event *ub_ev) +{ + unbound_io_event_t *ev = talloc_get_type_abort(ub_ev, unbound_io_event_t); + + DEBUG4("unbound event %p - Freed", ev); + + talloc_free(ev); +} + +/** Timeout fired + * + */ +static void _unbound_io_service_timer_expired(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx) +{ + unbound_io_event_t *ev = talloc_get_type_abort(uctx, unbound_io_event_t); + int ret; + + rad_assert(ev->active); /* must be active */ + + DEBUG4("unbound event %p - Timeout", ev); + + ev->cb(-1, UB_EV_TIMEOUT, ev->uctx); /* Inform libunbound */ + + /* + * Advanced libunbound's state + */ + ret = ub_process(ev->ev_b->t->ub); + if (ret != 0) { + ERROR("unbound event %p - ub_process errored after timeout event - %s (%i)", + ev, ub_strerror(ret), ret); + } +} + +/** Unbound FD became readable + * + * Because we don't have the separation between the IO event loop + * and the event loop processing results, we call ub_process + * immediately after calling the IO callback. + */ +static void _unbound_io_service_readable(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx) +{ + unbound_io_event_t *ev = talloc_get_type_abort(uctx, unbound_io_event_t); + int ret; + + rad_assert(ev->active); /* must be active */ + + DEBUG4("unbound event %p - FD %i now readable", ev, fd); + + ev->cb(-1, UB_EV_READ, ev->uctx); /* Inform libunbound */ + + /* + * Remove IO events + */ + if (!(ev->events | UB_EV_PERSIST)) { + DEBUG4("unbound event %p - UB_EV_PERSIST not set - Removing events for FD %i", ev, ev->fd); + if (fr_event_fd_delete(el, ev->fd, FR_EVENT_FILTER_IO) < 0) { + PERROR("unbound event %p - De-registration failed for FD %i", ev, ev->fd); + } + } + + /* + * Advanced libunbound's state + */ + ret = ub_process(ev->ev_b->t->ub); + if (ret != 0) { + ERROR("unbound event %p - ub_process errored after read event - %s (%i)", + ev, ub_strerror(ret), ret); + } +} + +/** Unbound FD became writable + * + */ +static void _unbound_io_service_writable(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx) +{ + unbound_io_event_t *ev = talloc_get_type_abort(uctx, unbound_io_event_t); + + rad_assert(ev->active); /* must be active */ + + DEBUG4("unbound event %p - FD %i now writable", ev, fd); + + ev->cb(-1, UB_EV_WRITE, ev->uctx); /* Inform libunbound */ + + /* + * Remove IO events + */ + if (!(ev->events | UB_EV_PERSIST)) { + DEBUG4("unbound event %p - UB_EV_PERSIST not set - Removing events for FD %i", ev, ev->fd); + if (fr_event_fd_delete(el, ev->fd, FR_EVENT_FILTER_IO) < 0) { + PERROR("unbound event %p - De-registration failed for FD %i", ev, ev->fd); + } + } +} + +/** Unbound FD errored + * + * libunbound doesn't request errors, so tell it a timeout occurred + * + * Because we don't have the separation between the IO event loop + * and the event loop processing results, we call ub_process + * immediately after calling the IO callback. + */ +static void _unbound_io_service_errored(UNUSED fr_event_list_t *el, + int fd, UNUSED int flags, int fd_errno, void *uctx) +{ + unbound_io_event_t *ev = talloc_get_type_abort(uctx, unbound_io_event_t); + int ret; + + rad_assert(ev->active); /* must be active */ + + DEBUG4("unbound event %p - FD %i errored: %s", ev, fd, fr_syserror(fd_errno)); + + /* + * Delete the timer as we're telling libunbound + * that it fired. This is imperfect but unbound + * doesn't have a callback for receiving errors. + */ + if (fr_event_timer_delete(ev->ev_b->el, &ev->timer) < 0) { + PERROR("ubound event %p - Failed disarming timeout", ev); + } + + ev->cb(-1, UB_EV_TIMEOUT, ev->uctx); /* Call libunbound - pretend this is a timeout */ + + /* + * Advanced libunbound's state + */ + ret = ub_process(ev->ev_b->t->ub); + if (ret != 0) { + ERROR("unbound event %p - ub_process errored after FD error - %s (%i)", ev, ub_strerror(ret), ret); + } +} + + +/** Activate FD events and set a timer for a timeout + * + */ +static int _unbound_io_event_activate(struct ub_event *ub_ev, struct timeval *tv) +{ + unbound_io_event_t *ev = talloc_get_type_abort(ub_ev, unbound_io_event_t); + + rad_assert(!ev->active); /* must not be active */ + + /* + * File descriptor event + */ + if ((ev->events & UB_EV_READ) && (ev->events & UB_EV_WRITE)) { + rad_assert(ev->fd >= 0); /* File descriptor must valid */ + + DEBUG4("unbound event %p - Registered for read+write events on FD %i", ev, ev->fd); + + if (fr_event_fd_insert(ev, ev->ev_b->el, ev->fd, + _unbound_io_service_readable, + _unbound_io_service_writable, + _unbound_io_service_errored, + ev) < 0) { + PERROR("unbound event %p - Registration failed for read+write+error events on FD %i", + ev, ev->fd); + + return -1; + } + } else if (ev->events & UB_EV_READ) { + rad_assert(ev->fd >= 0); /* File descriptor must valid */ + + DEBUG4("unbound event %p - Registered for read+error events on FD %i", ev, ev->fd); + + if (fr_event_fd_insert(ev, ev->ev_b->el, ev->fd, + _unbound_io_service_readable, + NULL, + _unbound_io_service_errored, + ev) < 0) { + PERROR("unbound event %p - Registration failed for read+error events on FD %i", + ev, ev->fd); + + return -1; + } + } else if (ev->events & UB_EV_WRITE) { + rad_assert(ev->fd >= 0); /* File descriptor must valid */ + + DEBUG4("unbound event %p - Registered for write+error events on FD %i", ev, ev->fd); + + if (fr_event_fd_insert(ev, ev->ev_b->el, ev->fd, + NULL, + _unbound_io_service_writable, + _unbound_io_service_errored, + ev) < 0) { + PERROR("unbound event %p - Registration failed for write+error events on FD %i", + ev, ev->fd); + + return -1; + } + } + + /* + * Add a timeout event + */ + if (ev->events & UB_EV_TIMEOUT) { + fr_time_delta_t timeout = fr_time_delta_from_timeval(tv); + + DEBUG4("unbound event %p - Timeout in %pV seconds", ev, fr_box_time_delta(timeout)); + + if (fr_event_timer_in(ev, ev->ev_b->el, &ev->timer, + timeout, _unbound_io_service_timer_expired, ev) < 0) { + PERROR("unbound event %p - Failed adding timeout", ev); + + if (ev->events & (UB_EV_READ | UB_EV_WRITE)) { + fr_event_fd_delete(ev->ev_b->el, ev->fd, FR_EVENT_FILTER_IO); + } + + return -1; + } + } + + ev->active = true; /* Event is now active! */ + + return 0; +} + +/* Deactivate FD events and disarm the timeout + * + */ +static int _unbound_io_event_deactivate(struct ub_event *ub_ev) +{ + unbound_io_event_t *ev = talloc_get_type_abort(ub_ev, unbound_io_event_t); + int ret = 0; + + if (!ev->active) return 0; /* Allow this to be called multiple times */ + + if (ev->events & (UB_EV_READ | UB_EV_WRITE)) { + DEBUG4("unbound event %p - De-registering FD %i", ev, ev->fd); + + if (fr_event_fd_delete(ev->ev_b->el, ev->fd, FR_EVENT_FILTER_IO) < 0) { + PERROR("unbound event %p - De-registration failed for FD %i", ev, ev->fd); + + ret = -1; + } + } + + if (ev->events & UB_EV_TIMEOUT) { + DEBUG4("unbound event %p - Disarming timeout", ev); + + if (ev->timer && (fr_event_timer_delete(ev->ev_b->el, &ev->timer) < 0)) { + PERROR("ubound event %p - Failed disarming timeout", ev); + + ret = -1; + } + } + + ev->active = false; /* Event is now inactive and can be modified */ + + return ret; +} + +/** Modify an existing timeout + * + */ +static int _unbound_io_timer_modify(struct ub_event *ub_ev, UNUSED struct ub_event_base *ev_b, + void (*cb)(int, short, void*), + void *uctx, struct timeval *tv) +{ + unbound_io_event_t *ev = talloc_get_type_abort(ub_ev, unbound_io_event_t); + int ret = 0; + fr_time_delta_t timeout; + + rad_assert(ev->events & UB_EV_TIMEOUT); + + if (ev->cb != cb) { + DEBUG4("unbound event %p - New callback %p (old callback was %p)", + ev, cb, ev->cb); + ev->cb = cb; + } + if (ev->uctx != uctx) { + DEBUG4("unbound event %p - New uctx %p (old uctx was %p)", + ev, uctx, ev->uctx); + ev->uctx = uctx; + } + if (ev->timer && (fr_event_timer_delete(ev->ev_b->el, &ev->timer) < 0)) { + PERROR("ubound event %p - Failed disarming timeout", ev); + + ret = -1; /* Continue ? */ + } + + timeout = fr_time_delta_from_timeval(tv); + + DEBUG4("unbound event %p - Timeout in %pV seconds", ev, fr_box_time_delta(timeout)); + + if (fr_event_timer_in(ev, ev->ev_b->el, &ev->timer, + timeout, _unbound_io_service_timer_expired, ev) < 0) { + PERROR("unbound event %p - Failed adding timeout", ev); + + ret = -1; + } + + return ret; +} + +/** Deactivate a timeout + * + */ +static int _unbound_io_timer_deactivate(struct ub_event *ub_ev) +{ + unbound_io_event_t *ev = talloc_get_type_abort(ub_ev, unbound_io_event_t); + + rad_assert(ev->events & UB_EV_TIMEOUT); + + DEBUG4("unbound event %p - Disarming timeout", ev); + + if (ev->timer && (fr_event_timer_delete(ev->ev_b->el, &ev->timer) < 0)) { + PERROR("unbound event %p - Failed disarming timeout", ev); + + return -1; + } + + return 0; +} + +/** Returns a new libunbound event handle + * + * This handle is used by libunbound to interface with the worker's event loop + */ +static struct ub_event *_unbound_io_event_new(struct ub_event_base* base, int fd, short flags, + void (*cb)(int, short, void*), void *uctx) +{ + unbound_io_event_base_t *ev_b = talloc_get_type_abort(base, unbound_io_event_base_t); + unbound_io_event_t *ev; + + static struct ub_event_vmt vmt = { + .add_bits = _unbound_io_event_flags_add, + .del_bits = _unbound_io_event_flags_del, + .set_fd = _unbound_io_event_fd_set, + .free = _unbound_io_event_free, + .add = _unbound_io_event_activate, + .del = _unbound_io_event_deactivate, + .add_timer = _unbound_io_timer_modify, + .del_timer = _unbound_io_timer_deactivate + }; + + MEM(ev = talloc_zero(ev_b, unbound_io_event_t)); + ev->base.magic = UB_EVENT_MAGIC; /* Magic value libunbound requires */ + ev->base.vmt = &vmt; /* Callbacks for adding/removing timers/fd events */ + ev->ev_b = ev_b; /* Our event base (containing the el ) */ + ev->events = flags; /* When this event should fire */ + ev->fd = fd; /* File descriptor to register events for */ + ev->cb = cb; /* Callback to execute on event */ + ev->uctx = uctx; /* Lib unbound's arg to pass to the cb */ + ev->active = false; /* Event is not currently active */ + + DEBUG4("unbound event %p - Allocated - Events %i, FD %i, callback %p, uctx %p", ev, flags, fd, cb, uctx); + + return (struct ub_event *)ev; +} + +/** Initialises a ub_ctx, writing it to t->ub + * + * The ub_ctx is configured to use the el specified. + * + * When the thread ctx is freed, unbound_io_free should be called to gracefully + * free the ub_ctx, and then the event base structure it depends on. + * + * @param[out] t Thread instance data to populate. + * @parma[in] el To use to run the unbound event loop. + * @return + * - 0 on success. + * - -1 on failure. + */ +int unbound_io_init(rlm_unbound_thread_t *t, fr_event_list_t *el) +{ + static struct ub_event_base_vmt vmt = { + .new_event = _unbound_io_event_new + }; + + /* + * Should be manually freed *AFTER* t->ub + * is freed. So must be parented from the NULL + * ctx. + */ + MEM(t->ev_b = talloc_zero(NULL, unbound_io_event_base_t)); + t->ev_b->base.magic = UB_EVENT_MAGIC; + t->ev_b->base.vmt = &vmt; + t->ev_b->el = el; + t->ev_b->t = t; + + /* + * Create the main ub_ctx using our event base + * which specifies how libunbound integrates + * with our event loop. + */ + t->ub = ub_ctx_create_ub_event((struct ub_event_base *)t->ev_b); + if (!t->ub) { + ERROR("Failed creating ub_ctx"); + TALLOC_FREE(t->ev_b); + return -1; + } + return 0; +} + +/** Frees ub_ctx and dependent memory + * + * @param[in,out] t Thread instance data to free resources from. + */ +void unbound_io_free(rlm_unbound_thread_t *t) +{ + if (t->ub) { + ub_ctx_delete(t->ub); + t->ub = NULL; + } + + TALLOC_FREE(t->ev_b); +} diff --git a/src/modules/rlm_unbound/io.h b/src/modules/rlm_unbound/io.h new file mode 100644 index 00000000000..b8ed7bd0d38 --- /dev/null +++ b/src/modules/rlm_unbound/io.h @@ -0,0 +1,53 @@ +#pragma once +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * + * @brief Function prototypes and datatypes for the REST (HTTP) transport. + * @file rlm_unbound/unbound.h + * + * @copyright 2019 The FreeRADIUS server project + * @copyright 2019 Arran Cudbard-Bell (a.cudbardb@freeradius.org) + */ +RCSIDH(rlm_unbound_io_h, "$Id$") + + +#ifdef HAVE_WDOCUMENTATION +DIAG_OFF(documentation) +#endif +#include +#ifdef HAVE_WDOCUMENTATION +DIAG_ON(documentation) +#endif + +typedef struct unbound_io_event_base_s unbound_io_event_base_t; + +typedef struct { + struct ub_ctx *ub; //!< There's one unbound context per thread, as they + ///< contain the event list configuration, so we need + ///< one per worker event loop. + unbound_io_event_base_t *ev_b; //!< Contains callbacks and configuration libunbound + ///< needs when creating new rlm_unbound_event_t. + ///< Must be freed after the ub_ctx. +} rlm_unbound_thread_t; + +/* + * io.c + */ +int unbound_io_init(rlm_unbound_thread_t *t, fr_event_list_t *el); +void unbound_io_free(rlm_unbound_thread_t *t); diff --git a/src/modules/rlm_unbound/rlm_unbound.c b/src/modules/rlm_unbound/rlm_unbound.c index 1490759d204..30949de38cd 100644 --- a/src/modules/rlm_unbound/rlm_unbound.c +++ b/src/modules/rlm_unbound/rlm_unbound.c @@ -31,13 +31,7 @@ RCSID("$Id$") #include #include -#ifdef HAVE_WDOCUMENTATION -DIAG_OFF(documentation) -#endif -#include -#ifdef HAVE_WDOCUMENTATION -DIAG_ON(documentation) -#endif +#include "io.h" typedef struct { struct ub_ctx *ub; /* This must come first. Do not move */ @@ -311,6 +305,27 @@ error0: return -1; } +typedef struct { + struct ub_result *result; //!< The result from the previous operation. +} dns_resume_ctx_t; + +/* +static xlat_action_t xlat_ptr(TALLOC_CTX *ctx, fr_cursor_t *out, + REQUEST *request, void const *xlat_inst, void *xlat_thread_inst, + fr_value_box_t **in) +{ + if (!*in) return XLAT_ACTION_DONE; + + if (fr_value_box_list_concat(ctx, *in, in, FR_TYPE_STRING, true) < 0) { + RPEDEBUG("Failed concatenating input string for attribute reference"); + return XLAT_ACTION_FAIL; + } + + yield_to + +} +*/ + static ssize_t xlat_ptr(TALLOC_CTX *ctx, char **out, size_t outlen, void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt) @@ -375,32 +390,6 @@ static void ub_fd_handler(UNUSED fr_event_list_t *el, UNUSED int sock, UNUSED in } } -static int mod_bootstrap(void *instance, CONF_SECTION *conf) -{ - rlm_unbound_t *inst = instance; - - inst->name = cf_section_name2(conf); - if (!inst->name) inst->name = cf_section_name1(conf); - - if (inst->timeout > 10000) { - cf_log_err(conf, "timeout must be 0 to 10000"); - return -1; - } - - MEM(inst->xlat_a_name = talloc_typed_asprintf(inst, "%s-a", inst->name)); - MEM(inst->xlat_aaaa_name = talloc_typed_asprintf(inst, "%s-aaaa", inst->name)); - MEM(inst->xlat_ptr_name = talloc_typed_asprintf(inst, "%s-ptr", inst->name)); - - if (xlat_register(inst, inst->xlat_a_name, xlat_a, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, false) || - xlat_register(inst, inst->xlat_aaaa_name, xlat_aaaa, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, false) || - xlat_register(inst, inst->xlat_ptr_name, xlat_ptr, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, false)) { - cf_log_err(conf, "Failed registering xlats"); - return -1; - } - - return 0; -} - static int mod_instantiate(void *instance, CONF_SECTION *conf) { rlm_unbound_t *inst = instance; @@ -671,6 +660,32 @@ static int mod_instantiate(void *instance, CONF_SECTION *conf) return -1; } +static int mod_bootstrap(void *instance, CONF_SECTION *conf) +{ + rlm_unbound_t *inst = instance; + + inst->name = cf_section_name2(conf); + if (!inst->name) inst->name = cf_section_name1(conf); + + if (inst->timeout > 10000) { + cf_log_err(conf, "timeout must be 0 to 10000"); + return -1; + } + + MEM(inst->xlat_a_name = talloc_typed_asprintf(inst, "%s-a", inst->name)); + MEM(inst->xlat_aaaa_name = talloc_typed_asprintf(inst, "%s-aaaa", inst->name)); + MEM(inst->xlat_ptr_name = talloc_typed_asprintf(inst, "%s-ptr", inst->name)); + + if (xlat_register(inst, inst->xlat_a_name, xlat_a, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, false) || + xlat_register(inst, inst->xlat_aaaa_name, xlat_aaaa, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, false) || + xlat_register(inst, inst->xlat_ptr_name, xlat_ptr, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, false)) { + cf_log_err(conf, "Failed registering xlats"); + return -1; + } + + return 0; +} + static int mod_detach(void *instance) { rlm_unbound_t *inst = instance; @@ -709,12 +724,13 @@ static int mod_detach(void *instance) extern module_t rlm_unbound; module_t rlm_unbound = { - .magic = RLM_MODULE_INIT, - .name = "unbound", - .type = RLM_TYPE_THREAD_SAFE, - .inst_size = sizeof(rlm_unbound_t), - .config = module_config, - .bootstrap = mod_bootstrap, - .instantiate = mod_instantiate, - .detach = mod_detach + .magic = RLM_MODULE_INIT, + .name = "unbound", + .type = RLM_TYPE_THREAD_SAFE, + .inst_size = sizeof(rlm_unbound_t), + .thread_inst_size = sizeof(rlm_unbound_thread_t), + .config = module_config, + .bootstrap = mod_bootstrap, + .instantiate = mod_instantiate, + .detach = mod_detach };