]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
re-do rlm_radius.
authorAlan T. DeKok <aland@freeradius.org>
Wed, 26 Jul 2017 15:47:48 +0000 (11:47 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 26 Jul 2017 23:55:49 +0000 (19:55 -0400)
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.

src/modules/rlm_radius/all.mk
src/modules/rlm_radius/rlm_radius.c
src/modules/rlm_radius/rlm_radius.h
src/modules/rlm_radius/rlm_radius_udp.c
src/modules/rlm_radius/track.c
src/modules/rlm_radius/track.h

index d3e38e228b715b725352fd5b1610ed4c8b6fcc22..ad50702d063cdf2bef2a74dcaf5d0b26886f478d 100644 (file)
@@ -1,4 +1,2 @@
-SUBMAKEFILES := rlm_radius.mk
-
-# rlm_radius_udp.mk
+SUBMAKEFILES := rlm_radius.mk rlm_radius_udp.mk
 
index 068e9332a60d50102f5950ecc77f21ab0b19343c..f6ea3e0bfcfb60ffeedc41ba758fe9f84de933d9 100644 (file)
@@ -40,8 +40,6 @@
  */
 RCSID("$Id$")
 
-#include <freeradius-devel/radiusd.h>
-#include <freeradius-devel/modules.h>
 #include <freeradius-devel/io/application.h>
 #include <freeradius-devel/rad_assert.h>
 
@@ -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;
        }
index 33d2a5efc53a6a19e5d76767e8eed73717572131..5e86b9908dadf05cd1c5dceed56f60aecba28cbf 100644 (file)
@@ -15,7 +15,9 @@
  */
 #ifndef _RLM_RADIUS_H
 #define _RLM_RADIUS_H
-#include <freeradius-devel/connection.h>
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
 
 /*
  * $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 */
index eb68e10464fd6d176ae4a813bff53241c54b9a9b..77b11acc61eef13f1cb8c292c05518806b6088cb 100644 (file)
  */
 RCSID("$Id$")
 
-#include <freeradius-devel/radiusd.h>
-#include <freeradius-devel/modules.h>
 #include <freeradius-devel/io/application.h>
 #include <freeradius-devel/udp.h>
+#include <freeradius-devel/connection.h>
 #include <freeradius-devel/rad_assert.h>
 
 #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,
 };
index de3b32573514366b3fec7415948578fe050867ac..0b0e42d31954ce3616c664e633c078bad395fe49 100644 (file)
@@ -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;
 }
index 2f1cb3b0655de37a2eeb10552af7067d6330d28c..d7447cee7d47be1f306ba2dc4c06563decfabd9b 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef _RLM_RADIUS_TRACK_H
 #define _RLM_RADIUS_TRACK_H
 
+#include "rlm_radius.h"
+
 /*
  * $Id$
  *
  *
  */
 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);