From: Alan T. DeKok Date: Wed, 26 Jul 2017 15:47:48 +0000 (-0400) Subject: re-do rlm_radius. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=44e29a20a0780bae0dc2cac9a2032761e7ea0342;p=thirdparty%2Ffreeradius-server.git re-do rlm_radius. The old method was way too complicated. So the new method is better. The connection code will be re-added in the next few commits. --- diff --git a/src/modules/rlm_radius/all.mk b/src/modules/rlm_radius/all.mk index d3e38e228b7..ad50702d063 100644 --- a/src/modules/rlm_radius/all.mk +++ b/src/modules/rlm_radius/all.mk @@ -1,4 +1,2 @@ -SUBMAKEFILES := rlm_radius.mk - -# rlm_radius_udp.mk +SUBMAKEFILES := rlm_radius.mk rlm_radius_udp.mk diff --git a/src/modules/rlm_radius/rlm_radius.c b/src/modules/rlm_radius/rlm_radius.c index 068e9332a60..f6ea3e0bfcf 100644 --- a/src/modules/rlm_radius/rlm_radius.c +++ b/src/modules/rlm_radius/rlm_radius.c @@ -40,8 +40,6 @@ */ RCSID("$Id$") -#include -#include #include #include @@ -248,7 +246,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_process(void *instance, void *thread, RE /* * Push the request and it's link to the IO submodule. */ - if (inst->io->push(inst, request, link, t->thread_io_ctx) < 0) { + if (inst->io->push(inst->io_instance, request, link, t->thread_io_ctx) < 0) { talloc_free(link); return RLM_MODULE_FAIL; } diff --git a/src/modules/rlm_radius/rlm_radius.h b/src/modules/rlm_radius/rlm_radius.h index 33d2a5efc53..5e86b9908da 100644 --- a/src/modules/rlm_radius/rlm_radius.h +++ b/src/modules/rlm_radius/rlm_radius.h @@ -15,7 +15,9 @@ */ #ifndef _RLM_RADIUS_H #define _RLM_RADIUS_H -#include + +#include +#include /* * $Id$ @@ -33,7 +35,7 @@ typedef struct rlm_radius_link_t rlm_radius_link_t; /** Push a REQUEST to an IO submodule * */ -typedef int (*fr_radius_io_push_t)(rlm_radius_t *inst, REQUEST *request, rlm_radius_link_t *link, void *thread); +typedef int (*fr_radius_io_push_t)(void *instance, REQUEST *request, rlm_radius_link_t *link, void *thread); /** Public structure describing an I/O path for an outgoing socket. @@ -82,20 +84,6 @@ struct rlm_radius_t { rlm_radius_retry_t packets[FR_MAX_PACKET_CODE]; }; -typedef struct rlm_radius_connection_t rlm_radius_connection_t; - -struct rlm_radius_link_t { - REQUEST *request; //!< the request we are for, so we can find it from the link - fr_dlist_t entry; //!< linked list of active requests for rlm_radius - - fr_time_t time_sent; //!< when we sent the packet - fr_time_t time_recv; //!< when we received the reply - - - rlm_rcode_t rcode; //!< from the transport - void *request_io_ctx; - rlm_radius_connection_t *c; //!< which connection we're queued or sent -}; /** Per-thread instance data * @@ -107,7 +95,22 @@ typedef struct rlm_radius_thread_t { fr_dlist_t running; //!< running requests - void *thread_io_ctx; //!< IO context for the IO submodule + void *thread_io_ctx; //!< thread context for the IO submodule } rlm_radius_thread_t; +/** Link a REQUEST to an rlm_radius thread context, and to the IO submodule. + * + */ +struct rlm_radius_link_t { + REQUEST *request; //!< the request we are for, so we can find it from the link + rlm_radius_thread_t *t; //!< thread context for rlm_radius + fr_dlist_t entry; //!< linked list of active requests for rlm_radius + + fr_time_t time_sent; //!< when we sent the packet + fr_time_t time_recv; //!< when we received the reply + + rlm_rcode_t rcode; //!< from the transport + void *request_io_ctx; //!< IO submodule tracking for this request +}; + #endif /* _RLM_RADIUS_H */ diff --git a/src/modules/rlm_radius/rlm_radius_udp.c b/src/modules/rlm_radius/rlm_radius_udp.c index eb68e10464f..77b11acc61e 100644 --- a/src/modules/rlm_radius/rlm_radius_udp.c +++ b/src/modules/rlm_radius/rlm_radius_udp.c @@ -32,15 +32,17 @@ */ RCSID("$Id$") -#include -#include #include #include +#include #include #include "rlm_radius.h" #include "track.h" +/** Static configuration for the module. + * + */ typedef struct rlm_radius_udp_t { fr_ipaddr_t dst_ipaddr; //!< IP of the home server fr_ipaddr_t src_ipaddr; //!< IP we open our socket on @@ -56,26 +58,42 @@ typedef struct rlm_radius_udp_t { bool recv_buff_is_set; //!< Whether we were provided with a recv_buf bool send_buff_is_set; //!< Whether we were provided with a send_buf +} rlm_radius_udp_t; - bool dst_ipaddr_is_set; //!< ipaddr config item is set. - bool dst_ipv4addr_is_set; //!< ipv4addr config item is set. - bool dst_ipv6addr_is_set; //!< ipv6addr config item is set. - bool src_ipaddr_is_set; //!< src_ipaddr config item is set. - bool src_ipv4addr_is_set; //!< src_ipv4addr config item is set. - bool src_ipv6addr_is_set; //!< src_ipv6addr config item is set. +/** Per-thread configuration for the module. + * + * This data structure holds the connections, etc. for this IO submodule. + */ +typedef struct rlm_radius_udp_thread_t { + rlm_radius_udp_t *inst; //!< IO submodule instance + fr_event_list_t *el; //!< event list -} rlm_radius_udp_t; + bool pending; //!< are there pending requests? + fr_dlist_t queued; //!< queued requests for some new connection -struct rlm_radius_client_io_ctx_t { + fr_dlist_t active; //!< active connections +} rlm_radius_udp_thread_t; + +typedef struct rlm_radius_udp_connection_t { rlm_radius_udp_t const *inst; //!< our module instance + fr_connection_t *conn; //!< Connection to our destination. + + fr_dlist_t entry; //!< in the linked list of connections + + struct timeval last_sent_with_reply; //!< most recent sent time which had a reply + + bool pending; //!< are there packets pending? + fr_dlist_t queued; //!< list of packets queued for sending + fr_dlist_t sent; //!< list of sent packets + uint32_t max_packet_size; //!< our max packet size. may be different from the parent... int fd; //!< file descriptor fr_ipaddr_t dst_ipaddr; //!< IP of the home server. stupid 'const' issues.. + uint16_t dst_port; //!< port of the home server fr_ipaddr_t src_ipaddr; //!< my source IP uint16_t src_port; //!< my source port - uint16_t dst_port; //!< port of the home server // @todo - track status-server, open, signaling, etc. @@ -83,13 +101,19 @@ struct rlm_radius_client_io_ctx_t { size_t buflen; //!< receive buffer length rlm_radius_id_t *id[FR_MAX_PACKET_CODE]; //!< ID tracking -}; +} rlm_radius_udp_connection_t; + + +/** Link a packet to a connection + * + */ +typedef struct rlm_radius_udp_request_t { + fr_dlist_t entry; //!< in the connection list of packets -typedef struct request_ctx_t { - uint8_t header[20]; + rlm_radius_udp_connection_t *c; //!< the connection + rlm_radius_request_t *rr; //!< the ID tracking, resend count, etc. - // @todo - timers, retransmits, etc -} request_ctx_t; +} rlm_radius_udp_request_t; static const CONF_PARSER module_config[] = { @@ -117,163 +141,60 @@ static const CONF_PARSER module_config[] = { }; -static int mod_write(REQUEST *request, void *request_ctx, void *io_ctx) +static rlm_radius_udp_connection_t *mod_connect(rlm_radius_udp_t *inst, rlm_radius_udp_thread_t *t) { - rlm_radius_client_io_ctx_t *io = talloc_get_type_abort(io_ctx, rlm_radius_client_io_ctx_t); - request_ctx_t *track = (request_ctx_t *) request_ctx; /* not talloc'd */ - ssize_t packet_len, data_size; - rlm_radius_request_t *rr; - - rad_assert(request->packet->code > 0); - rad_assert(request->packet->code < FR_MAX_PACKET_CODE); - - /* - * Create the tracking table if it doesn't already exist. - * - * @todo - move this into the "init" routine? where was can examine - * the rlm_radius_t, and create the relevant data structures. - */ - if (!io->id[request->packet->code]) { - io->id[request->packet->code] = rr_track_create(io_ctx); - if (!io->id[request->packet->code]) { - RDEBUG("Failed creating tracking table for code %d", request->packet->code); - return -1; - } - } - - /* - * Allocate an ID - */ - rr = rr_track_alloc(io->id[request->packet->code], request, request->packet->code, io, request_ctx); - if (!rr) { - RDEBUG("Failed allocating packet ID for code %d", request->packet->code); - return -1; - } + rlm_radius_udp_connection_t *c; - packet_len = fr_radius_encode(io->buffer, io->buflen, NULL, io->inst->secret, strlen(io->inst->secret), - rr->code, rr->id, request->packet->vps); - if (packet_len < 0) { - RDEBUG("Failed encoding packet: %s", fr_strerror()); - - // @todo - distinguish write errors from encode errors? - return -1; - } + c = talloc_zero(t, rlm_radius_udp_connection_t); + c->dst_ipaddr = inst->dst_ipaddr; + c->dst_port = inst->dst_port; + c->src_ipaddr = inst->src_ipaddr; + c->src_port = 0; - data_size = udp_send(io->fd, io->buffer, packet_len, 0, - &io->dst_ipaddr, io->dst_port, - 0, /* if_index */ - &io->src_ipaddr, io->src_port); - - // @todo - put the packet into an RB tree, too, so we can find replies... - memcpy(&track->header, io->buffer, 20); - - if (data_size < packet_len) { - rad_assert(0 == 1); - } - - return 1; + return c; } -/** Get a printable name for the socket - * - */ -static char const *mod_get_name(TALLOC_CTX *ctx, void *io_ctx) -{ - rlm_radius_client_io_ctx_t *io = talloc_get_type_abort(io_ctx, rlm_radius_client_io_ctx_t); - char src_buf[FR_IPADDR_STRLEN], dst_buf[FR_IPADDR_STRLEN]; - - fr_inet_ntop(dst_buf, sizeof(dst_buf), &io->dst_ipaddr); - - // @todo - make sure to get the local port number we're bound to - - if (fr_ipaddr_is_inaddr_any(&io->inst->src_ipaddr)) { - return talloc_asprintf(ctx, "home server %s port %u", dst_buf, io->dst_port); - } - fr_inet_ntop(src_buf, sizeof(src_buf), &io->inst->src_ipaddr); - return talloc_asprintf(ctx, "from %s to home server %s port %u", src_buf, dst_buf, io->dst_port); -} - - -/** Shutdown/close a file descriptor - * - */ -static void mod_close(int fd, void *io_ctx) -{ - rlm_radius_client_io_ctx_t *io = talloc_get_type_abort(io_ctx, rlm_radius_client_io_ctx_t); - - if (shutdown(fd, SHUT_RDWR) < 0) DEBUG3("Shutdown on socket (%i) failed: %s", fd, fr_syserror(errno)); - if (close(fd) < 0) DEBUG3("Closing socket (%i) failed: %s", fd, fr_syserror(errno)); - - io->fd = -1; -} - -/** Do more setup once the connection has been opened - * - */ -static fr_connection_state_t mod_open(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED void *io_ctx) +static int mod_push(void *instance, REQUEST *request, rlm_radius_link_t *link, void *thread) { -// rlm_radius_client_io_ctx_t_t *io = talloc_get_type_abort(io_ctx, rlm_radius_client_io_ctx_t); - - // @todo - create the initial Status-Server for negotiation and send that - - return FR_CONNECTION_STATE_CONNECTED; -} - - -/** Initialize the connection. - * - */ -static fr_connection_state_t mod_init(int *fd_out, void *io_ctx, void const *uctx) -{ - int fd; - rlm_radius_client_io_ctx_t *io = talloc_get_type_abort(io_ctx, rlm_radius_client_io_ctx_t); - rlm_radius_udp_t const *inst = talloc_get_type_abort(uctx, rlm_radius_udp_t); - - io->inst = inst; + rlm_radius_udp_t *inst = talloc_get_type_abort(instance, rlm_radius_udp_t); + rlm_radius_udp_thread_t *t = talloc_get_type_abort(thread, rlm_radius_udp_thread_t); + rlm_radius_udp_request_t *u = link->request_io_ctx; + rlm_radius_udp_connection_t *c; + fr_dlist_t *entry; - io->max_packet_size = inst->max_packet_size; - io->buflen = io->max_packet_size; - io->buffer = talloc_array(io, uint8_t, io->buflen); + rad_assert(request->packet->code > 0); + rad_assert(request->packet->code < FR_MAX_PACKET_CODE); - if (!io->buffer) { - return FR_CONNECTION_STATE_FAILED; + entry = FR_DLIST_FIRST(t->active); + if (!entry) { + c = mod_connect(inst, t); + if (!c) { + RDEBUG("Failed initializing new connection"); + return -1; + } } - io->dst_ipaddr = inst->dst_ipaddr; - io->dst_port = inst->dst_port; - io->src_ipaddr = inst->src_ipaddr; - io->src_port = 0; - /* - * Open the outgoing socket. - * - * @todo - pass src_ipaddr, and remove later call to fr_socket_bind() - * which does return the src_port, but doesn't set the "don't fragment" bit. + * Now that we have a connection, use it to send packets. */ - fd = fr_socket_client_udp(&io->src_ipaddr, &io->dst_ipaddr, io->dst_port, true); - if (fd < 0) { - DEBUG("Failed opening RADIUS client UDP socket: %s", fr_strerror()); - return FR_CONNECTION_STATE_FAILED; - } + c = fr_ptr_to_type(rlm_radius_udp_connection_t, entry, entry); + (void) talloc_get_type_abort(c, rlm_radius_udp_connection_t); -#if 0 - if (fr_socket_bind(fd, &io->src_ipaddr, &io->src_port, inst->interface) < 0) { - DEBUG("Failed binding RADIUS client UDP socket: %s FD %d %pV port %u interface %s", fr_strerror(), fd, fr_box_ipaddr(io->src_ipaddr), - io->src_port, inst->interface); - return FR_CONNECTION_STATE_FAILED; - } -#endif + u->c = c; - // @todo - set recv_buff and send_buff socket options - - io->fd = fd; + if (c->pending) { + fr_dlist_insert_head(&c->queued, &u->entry); + return 0; + } - // @todo - initialize the tracking memory, etc. + // @todo - try to write to the socket. If we can, return instead of adding it to the queue - *fd_out = fd; + c->pending = true; + fr_dlist_insert_head(&c->queued, &u->entry); +// mod_fd_active(c); - return FR_CONNECTION_STATE_CONNECTING; + return 0; } @@ -360,6 +281,28 @@ static int mod_instantiate(void *instance, CONF_SECTION *conf) } +/** Instantiate thread data for the submodule. + * + */ +static int mod_thread_instantiate(UNUSED CONF_SECTION const *cs, void *instance, fr_event_list_t *el, void *thread) +{ + rlm_radius_udp_thread_t *t = thread; + + (void) talloc_set_type(t, rlm_radius_udp_thread_t); + t->inst = instance; + t->el = el; + + t->pending = false; + FR_DLIST_INIT(t->queued); + FR_DLIST_INIT(t->active); + + // @todo - get parent, and initialize the list of IDs by code, from what is permitted by rlm_radius + + // start the connection + + return 0; +} + /* * The module name should be the only globally exported symbol. * That is, everything else should be 'static'. @@ -374,19 +317,13 @@ fr_radius_client_io_t rlm_radius_udp = { .magic = RLM_MODULE_INIT, .name = "radius_udp", .inst_size = sizeof(rlm_radius_udp_t), - .io_inst_size = sizeof(rlm_radius_client_io_ctx_t), - .request_inst_size = sizeof(request_ctx_t), + .request_inst_size = sizeof(rlm_radius_udp_request_t), + .thread_inst_size = sizeof(rlm_radius_udp_thread_t), + .config = module_config, .bootstrap = mod_bootstrap, .instantiate = mod_instantiate, - .init = mod_init, - .open = mod_open, - .close = mod_close, - .get_name = mod_get_name, - .write = mod_write, -#if 0 - .flush = mod_flush, - .remove = mod_remove, - .read = mod_read, -#endif + .thread_instantiate = mod_thread_instantiate, + + .push = mod_push, }; diff --git a/src/modules/rlm_radius/track.c b/src/modules/rlm_radius/track.c index de3b3257351..0b0e42d3195 100644 --- a/src/modules/rlm_radius/track.c +++ b/src/modules/rlm_radius/track.c @@ -94,13 +94,12 @@ static int rr_cmp(void const *one, void const *two) * @param[in] id The rlm_radius_id_t tracking table. * @param[in] request The request which will send the proxied packet. * @param[in] code Of the outbound request. - * @param[in] client_io_ctx Client I/O ctx. - * @param[in] request_io_ctx Request I/O ctx. + * @param[in] link the structure linking REQUEST to rlm_radius thread instance * @return * - NULL on error * - rlm_radius_request_t on success */ -rlm_radius_request_t *rr_track_alloc(rlm_radius_id_t *id, REQUEST *request, int code, void *client_io_ctx, void *request_io_ctx) +rlm_radius_request_t *rr_track_alloc(rlm_radius_id_t *id, REQUEST *request, int code, rlm_radius_link_t *link) { fr_dlist_t *entry; rlm_radius_request_t *rr; @@ -163,10 +162,9 @@ retry: rr->id = id->next_id; done: - rr->request = request; - rr->client_io_ctx = client_io_ctx; - rr->request_io_ctx = request_io_ctx; + rr->link = link; rr->code = code; + rr->request = request; id->num_requests++; return rr; } diff --git a/src/modules/rlm_radius/track.h b/src/modules/rlm_radius/track.h index 2f1cb3b0655..d7447cee7d4 100644 --- a/src/modules/rlm_radius/track.h +++ b/src/modules/rlm_radius/track.h @@ -16,6 +16,8 @@ #ifndef _RLM_RADIUS_TRACK_H #define _RLM_RADIUS_TRACK_H +#include "rlm_radius.h" + /* * $Id$ * @@ -29,11 +31,10 @@ * */ typedef struct rlm_radius_request_t { - REQUEST *request; //!< the original request - void *client_io_ctx; //!< the context for the client - void *request_io_ctx; + rlm_radius_link_t *link; //!< to the rlm_radius thread context, and to the IO submodule + REQUEST *request; //!< as always... - fr_event_timer_t const *ev; //!< timer event associated with this request + fr_event_timer_t const *ev; //!< timer event associated with this packet int code; //!< packet code (sigh) int id; //!< our ID @@ -62,7 +63,7 @@ typedef struct rlm_radius_id_t { } rlm_radius_id_t; rlm_radius_id_t *rr_track_create(TALLOC_CTX *ctx); -rlm_radius_request_t *rr_track_alloc(rlm_radius_id_t *id, REQUEST *request, int code, void *client_io_ctx, void *request_io_ctx) CC_HINT(nonnull); +rlm_radius_request_t *rr_track_alloc(rlm_radius_id_t *id, REQUEST *request, int code, rlm_radius_link_t *link) CC_HINT(nonnull); int rr_track_update(rlm_radius_id_t *id, rlm_radius_request_t *rr, uint8_t *vector) CC_HINT(nonnull); rlm_radius_request_t *rr_track_find(rlm_radius_id_t *id, int packet_id, uint8_t *vector) CC_HINT(nonnull(1)); int rr_track_delete(rlm_radius_id_t *id, rlm_radius_request_t *rr);