From: Alan T. DeKok Date: Tue, 14 Mar 2023 21:09:29 +0000 (-0400) Subject: run "send foo" through unlang X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8827a0b795fcadf441dd39b538e7efc5f9059e58;p=thirdparty%2Ffreeradius-server.git run "send foo" through unlang --- diff --git a/src/listen/bfd/proto_bfd.c b/src/listen/bfd/proto_bfd.c index 1831c6ed733..c014bdb1b3e 100644 --- a/src/listen/bfd/proto_bfd.c +++ b/src/listen/bfd/proto_bfd.c @@ -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 diff --git a/src/listen/bfd/proto_bfd_udp.c b/src/listen/bfd/proto_bfd_udp.c index 5ced20adcbb..28936784ac6 100644 --- a/src/listen/bfd/proto_bfd_udp.c +++ b/src/listen/bfd/proto_bfd_udp.c @@ -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); } diff --git a/src/listen/bfd/session.c b/src/listen/bfd/session.c index 334c6cb2083..a9860f9b349 100644 --- a/src/listen/bfd/session.c +++ b/src/listen/bfd/session.c @@ -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); } } diff --git a/src/listen/bfd/session.h b/src/listen/bfd/session.h index f44fb49264b..b223d6bea23 100644 --- a/src/listen/bfd/session.h +++ b/src/listen/bfd/session.h @@ -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.