]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
run "send foo" through unlang
authorAlan T. DeKok <aland@freeradius.org>
Tue, 14 Mar 2023 21:09:29 +0000 (17:09 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 14 Mar 2023 21:10:41 +0000 (17:10 -0400)
src/listen/bfd/proto_bfd.c
src/listen/bfd/proto_bfd_udp.c
src/listen/bfd/session.c
src/listen/bfd/session.h

index 1831c6ed7339494c43f27593ac90462e2a22c703..c014bdb1b3e0bd974c7e5fb96cdb9565c89d3c79 100644 (file)
@@ -182,7 +182,7 @@ static int mod_decode(UNUSED void const *instance, request_t *request, uint8_t *
        fr_client_t const       *client;
        fr_pair_t               *vp, *reply, *my, *your;
        bfd_wrapper_t const     *wrapper = (bfd_wrapper_t const *) data;
-       bfd_packet_t const      *packet = (bfd_packet_t const *) wrapper->packet;
+       bfd_packet_t const      *bfd = (bfd_packet_t const *) wrapper->packet;
 
        /*
         *      Set the request dictionary so that we can do
@@ -196,35 +196,51 @@ static int mod_decode(UNUSED void const *instance, request_t *request, uint8_t *
        /*
         *      Hacks for now until we have a lower-level decode routine.
         */
-       request->packet->code = packet->state;
-       request->packet->id = fr_nbo_to_uint32((uint8_t const *) &packet->my_disc);
+       request->packet->code = bfd->state;
+       request->packet->id = fr_nbo_to_uint32((uint8_t const *) &bfd->my_disc);
        request->reply->id = request->packet->id;
 
        request->packet->data = talloc_memdup(request->packet, data, data_len);
        request->packet->data_len = data_len;
 
+       /*
+        *      Set the rest of the fields.
+        */
+       request->client = UNCONST(fr_client_t *, client);
+
+       request->packet->socket = address->socket;
+       fr_socket_addr_swap(&request->reply->socket, &address->socket);
+
+       REQUEST_VERIFY(request);
+
+       /*
+        *      Decode the packet into the reply.
+        */
+       if (wrapper->type == BFD_WRAPPER_SEND_PACKET) {
+               if (fr_bfd_decode(request->reply_ctx, &request->reply_pairs,
+                                 (uint8_t const *) bfd, bfd->length,
+                                 client->secret, talloc_array_length(client->secret) - 1) < 0) {
+                       RPEDEBUG("Failed decoding packet");
+                       return -1;
+               }
+
+               request->reply->code = bfd->state;
+
+               return 0;
+       }
+
        /*
         *      Note that we don't set a limit on max_attributes here.
         *      That MUST be set and checked in the underlying
         *      transport, via a call to fr_radius_ok().
         */
        if (fr_bfd_decode(request->request_ctx, &request->request_pairs,
-                         (uint8_t const *) packet, packet->length,
+                         (uint8_t const *) bfd, bfd->length,
                          client->secret, talloc_array_length(client->secret) - 1) < 0) {
                RPEDEBUG("Failed decoding packet");
                return -1;
        }
 
-       /*
-        *      Set the rest of the fields.
-        */
-       request->client = UNCONST(fr_client_t *, client);
-
-       request->packet->socket = address->socket;
-       fr_socket_addr_swap(&request->reply->socket, &address->socket);
-
-       REQUEST_VERIFY(request);
-
        /*
         *      Initialize the reply.
         */
@@ -291,6 +307,7 @@ static ssize_t mod_encode(UNUSED void const *instance, request_t *request, uint8
        fr_io_address_t const   *address = track->address;
        fr_client_t const       *client;
        bfd_wrapper_t const     *wrapper = (bfd_wrapper_t const *) request->packet->data;
+       bfd_packet_t const      *bfd = (bfd_packet_t const *) wrapper->packet;
 
        /*
         *      Process layer NAK, or "Do not respond".
@@ -331,11 +348,16 @@ static ssize_t mod_encode(UNUSED void const *instance, request_t *request, uint8
                return sizeof(new_client);
        }
 
+       fr_assert((wrapper->packet + bfd->length) == (request->packet->data + request->packet->data_len));
+
        /*
-        *      @todo - change our state based on the reply packet.
+        *      Don't bother re-encoding the packet.
         */
-       *buffer = 0x00;
-       return 1;
+       memcpy(buffer, bfd, bfd->length);
+
+       fr_assert(fr_bfd_packet_ok(NULL, buffer, bfd->length));
+
+       return bfd->length;
 }
 
 /** Open listen sockets/connect to external event source
index 5ced20adcbb8c8d7ecc7cbc9ae67b0f9ae68dfcd..28936784ac648d519cd8f685956b124495512edf 100644 (file)
@@ -137,7 +137,7 @@ static ssize_t mod_read(fr_listen_t *li, void **packet_ctx, fr_time_t *recv_time
         */
        flags = UDP_FLAGS_CONNECTED * (thread->connection != NULL);
 
-       data_size = udp_recv(thread->sockfd, flags, &address->socket, wrapper->packet, buffer_len - (wrapper->packet - buffer), recv_time_p);
+       data_size = udp_recv(thread->sockfd, flags, &address->socket, wrapper->packet, buffer_len - offsetof(bfd_wrapper_t, packet), recv_time_p);
        if (data_size < 0) {
                PDEBUG2("proto_bfd_udp got read error");
                return data_size;
@@ -153,7 +153,7 @@ static ssize_t mod_read(fr_listen_t *li, void **packet_ctx, fr_time_t *recv_time
         */
        client =  fr_rb_find(inst->peers, &(fr_client_t) { .ipaddr = address->socket.inet.src_ipaddr, .proto = IPPROTO_UDP });
        if (!client) {
-               DEBUG2("proto_bfd_udp - Received invalid packet on %s - uknown client %pV:%u", thread->name,
+               DEBUG2("BFD %s - Received invalid packet on %s - unknown client %pV:%u", inst->server_name, thread->name,
                       fr_box_ipaddr(address->socket.inet.src_ipaddr), address->socket.inet.src_port);
                thread->stats.total_packets_dropped++;
                return 0;
@@ -162,7 +162,7 @@ static ssize_t mod_read(fr_listen_t *li, void **packet_ctx, fr_time_t *recv_time
        packet_len = data_size;
 
        if (!fr_bfd_packet_ok(&err, wrapper->packet, packet_len)) {
-               DEBUG2("proto_bfd_udp - Received invalid packet on %s - %s", thread->name, err);
+               DEBUG2("BFD %s - Received invalid packet on %s - %s", inst->server_name, thread->name, err);
                thread->stats.total_malformed_requests++;
                return 0;
        }
@@ -195,11 +195,10 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
                         uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
 {
        proto_bfd_udp_thread_t  *thread = talloc_get_type_abort(li->thread_instance, proto_bfd_udp_thread_t);
-       fr_io_track_t *track = talloc_get_type_abort(packet_ctx, fr_io_track_t);
-
-       fr_socket_t                     socket;
-
-       int                             flags;
+       fr_io_track_t           *track = talloc_get_type_abort(packet_ctx, fr_io_track_t);
+       bfd_session_t           *session;
+       ssize_t                 rcode;
+       char const *err;
 
        /*
         *      @todo - share a stats interface with the parent?  or
@@ -208,24 +207,24 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
         */
        thread->stats.total_responses++;
 
-       flags = UDP_FLAGS_CONNECTED * (thread->connection != NULL);
-
-       /*
-        *      Swap src/dst address so we send the response to
-        *      the client, not ourselves.
-        */
-       fr_socket_addr_swap(&socket, &track->address->socket);
+       session = UNCONST(bfd_session_t *, track->address->radclient);
 
-       /*
-        *      We only write RADIUS packets.
-        */
        fr_assert(buffer_len >= FR_BFD_HEADER_LENGTH);
 
-       /*
-        *      Only write replies if they're RADIUS packets.
-        *      sometimes we want to NOT send a reply...
-        */
-       return udp_send(&socket, flags, buffer, buffer_len);
+       fr_assert(fr_bfd_packet_ok(&err, buffer, buffer_len));
+
+       DEBUG("BFD %s peer %s sending %s",
+             session->server_name, session->client.shortname, fr_bfd_packet_names[session->session_state]);
+
+       rcode = sendfromto(session->sockfd, buffer, buffer_len, 0, 0,
+                          (struct sockaddr *) &session->local_sockaddr, session->local_salen,
+                          (struct sockaddr *) &session->remote_sockaddr, session->remote_salen);
+       if (rcode < 0) {
+               ERROR("Failed sending packet: %s", fr_syserror(errno));
+               fr_assert(0);
+       }
+
+       return rcode;
 }
 
 static void mod_network_get(void *instance, int *ipproto, bool *dynamic_clients, fr_trie_t const **trie)
@@ -503,6 +502,7 @@ static void mod_event_list_set(fr_listen_t *li, fr_event_list_t *el, void *nr)
                peer->nr = (fr_network_t *) nr;
                peer->sockfd = thread->sockfd;
                peer->server_name = inst->server_name;
+               peer->only_state_changes = inst->only_state_changes;
 
                bfd_session_start(peer);
        }
index 334c6cb208339ab41810fd7c867bb826546ad310..a9860f9b349b290d8f84f8aead25e984ecd5d4a7 100644 (file)
@@ -55,20 +55,22 @@ static void bfd_set_timeout(bfd_session_t *session, fr_time_t when);
  *     we will need to define some other kind of fake packet to send to the process
  *     module.
  */
-static void bfd_trigger(bfd_session_t *session, bfd_state_change_t change)
+static void bfd_trigger(UNUSED bfd_session_t *session, UNUSED bfd_state_change_t change)
 {
+#if 0
        bfd_wrapper_t wrapper;
+       fr_io_track_t *track;
 
        wrapper.type = BFD_WRAPPER_STATE_CHANGE;
        wrapper.state_change = change;
        wrapper.session = session;
 
-       /*
-        *      @todo - proto_bfd.c mod_decode() has to be updated to check for non-existent packet,
-        *      and create a fake "timeout" packet with appropriate data.
-        */
+       track = fr_master_io_track_alloc(session->listen, &session->client, &session->client.ipaddr, session->port,
+                                        &session->client.src_ipaddr, session->port);
+       if (!track) return;
 
-//     (void) fr_network_listen_inject(session->nr, session->listen, (uint8_t const *) &wrapper, sizeof(wrapper), fr_time());
+       (void) fr_network_sendto_worker(session->nr, session->listen, track, (uint8_t const *) &wrapper, sizeof(wrapper), fr_time());
+#endif
 }
 
 /*
@@ -721,6 +723,18 @@ static void bfd_control_packet_init(bfd_session_t *session, bfd_packet_t *bfd)
        bfd->min_echo_rx_interval = fr_time_delta_to_usec(session->my_min_echo_rx_interval);
 }
 
+static void bfd_send_init(bfd_session_t *session, bfd_packet_t *bfd)
+{
+       bfd_control_packet_init(session, bfd);
+
+       bfd->poll = session->doing_poll;
+
+       if (!bfd->demand) {
+               bfd_start_packets(session);
+       }
+
+       bfd_sign(session, bfd);
+}
 
 /*
  *     Send one BFD packet.
@@ -730,15 +744,7 @@ static void bfd_send_packet(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, vo
        bfd_session_t *session = ctx;
        bfd_packet_t bfd;
 
-       bfd_control_packet_init(session, &bfd);
-
-       bfd.poll = session->doing_poll;
-
-       if (!bfd.demand) {
-               bfd_start_packets(session);
-       }
-
-       bfd_sign(session, &bfd);
+       bfd_send_init(session, &bfd);
 
        DEBUG("BFD %s peer %s sending %s",
              session->server_name, session->client.shortname, fr_bfd_packet_names[session->session_state]);
@@ -753,6 +759,39 @@ static void bfd_send_packet(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, vo
        }
 }
 
+/*
+ *     Send one BFD packet.
+ */
+static void bfd_unlang_send_packet(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *ctx)
+{
+       bfd_session_t *session = ctx;
+       bfd_packet_t *bfd;
+       bfd_wrapper_t *wrapper;
+       fr_io_track_t *track;
+       fr_listen_t *parent;
+       uint8_t buffer[sizeof(bfd_wrapper_t) + sizeof(*bfd)];
+
+       wrapper = (bfd_wrapper_t *) buffer;
+       bfd = (bfd_packet_t *) wrapper->packet;
+
+       bfd_send_init(session, bfd);
+
+       session->last_sent = fr_time();
+
+       wrapper->type = BFD_WRAPPER_SEND_PACKET;
+       wrapper->state_change = BFD_STATE_CHANGE_NONE;
+       wrapper->session = session;
+
+       parent = talloc_parent(session->listen);
+       (void) talloc_get_type_abort(parent, fr_listen_t);
+
+       track = fr_master_io_track_alloc(session->listen, &session->client, &session->client.ipaddr, session->port,
+                                        &session->client.src_ipaddr, session->port);
+       if (!track) return;
+
+       (void) fr_network_sendto_worker(session->nr, parent, track, (uint8_t const *) wrapper, (wrapper->packet + bfd->length) - (uint8_t *) wrapper, fr_time());
+}
+
 /*
  *     Start sending packets.
  */
@@ -760,6 +799,7 @@ static void bfd_start_packets(bfd_session_t *session)
 {
        uint64_t        interval, base;
        uint64_t        jitter;
+       fr_event_timer_cb_t cb;
 
        if (session->ev_packet) return;
 
@@ -803,9 +843,15 @@ static void bfd_start_packets(bfd_session_t *session)
        interval = base;
        interval += jitter;
 
+       if (!session->only_state_changes) {
+               cb = bfd_unlang_send_packet;
+       } else {
+               cb = bfd_send_packet;
+       }
+
        if (fr_event_timer_in(session, session->el, &session->ev_packet,
                              fr_time_delta_wrap(interval),
-                             bfd_send_packet, session) < 0) {
+                             cb, session) < 0) {
                fr_assert("Failed to insert event" == NULL);
        }
 }
index f44fb49264b8baca12f90f108e57dd886ef08f7d..b223d6bea23bf2a5402f03efb33261e82b71a8e1 100644 (file)
@@ -32,6 +32,8 @@ typedef struct {
 
        char const                      *server_name;           //!< our name
 
+       bool                            only_state_changes;     //!< copied from proto_bfd_udp.c
+
        /*
         *      Peers are defined globally to a virtual server.  Each
         *      peer can only have one session associated with it.