26#include <freeradius-devel/io/application.h>
27#include <freeradius-devel/io/listen.h>
28#include <freeradius-devel/io/pair.h>
29#include <freeradius-devel/missing.h>
30#include <freeradius-devel/server/connection.h>
31#include <freeradius-devel/util/debug.h>
32#include <freeradius-devel/util/heap.h>
33#include <freeradius-devel/util/rb_expire.h>
35#include <sys/socket.h>
44#define check(_handle, _len_p) fr_radius_ok((_handle)->buffer, (size_t *)(_len_p), \
45 (_handle)->ctx.inst->max_attributes, false, NULL)
168 UNUSED int flags,
void *uctx);
203 fr_log(log, log_type,
file,
line,
"request %s, allocated %s:%d", request->name,
204 request->alloc_file, request->alloc_line);
279 request->async = talloc_zero(request,
fr_async_t);
290 while ((map = map_list_next(&
inst->status_check_map, map))) {
341 request->packet->code = u->
code;
399 DEBUG(
"%s - Reached maximum_retransmit_duration (%pVs > %pVs), failing status checks",
405 DEBUG(
"%s - Reached maximum_retransmit_count (%u > %u), failing status checks",
469 ERROR(
"%s - Failed reading response from socket: there is no server listening on outgoing connection %s",
474 ERROR(
"%s - Failed reading response from socket: %s",
490 ERROR(
"%s - Packet too short, expected at least %zu bytes got %zd bytes",
496 ERROR(
"%s - Received response with incorrect or expired ID. Expected %u, got %u",
501 if (!
check(h, &slen))
return;
503 if (
decode(h, &reply, &code,
527 DEBUG(
"%s - Received %u / %u replies for status check, on connection - %s",
529 DEBUG(
"%s - Next status check packet will be in %pVs",
575 DEBUG(
"%s - Sending %s ID %d over connection %s",
591 ERROR(
"%s - Failed sending %s ID %d length %zu over connection %s: %s",
601 if ((
size_t)slen < u->packet_len) {
603 ERROR(
"%s - Failed sending %s ID %d length %zu over connection %s: writing is blocked",
617 DEBUG(
"%s - %s request. Expecting response within %pVs",
674 size_t in_buffer = *size;
679 if (in_buffer < 20) {
701#define REQUIRE_MA(_h) (((_h)->ctx.inst->require_message_authenticator == FR_RADIUS_REQUIRE_MA_YES) || (_h)->ctx.inst->received_message_authenticator)
794 h->
bio.mem->uctx = h;
813 if (rcode < 0)
goto fail;
876 DEBUG4(
"Freeing handle %p", handle);
916 char const *log_prefix,
void *uctx)
931 PERROR(
"%s - Failed allocating state handler for new connection", ctx->
inst->
name);
1067 if (ret != 0)
return ret;
1073 if (ret != 0)
return ret;
1111 .request_code = u->
code,
1112 .request_authenticator = request_authenticator,
1113 .tmp_ctx = talloc(ctx,
uint8_t),
1114 .end =
data + data_len,
1116 .require_message_authenticator =
REQUIRE_MA(h),
1128 RDEBUG(
"Received %s ID %d length %zu reply packet on connection %s",
1141 !*(
inst->received_message_authenticator) &&
1144 RINFO(
"Packet contained a valid Message-Authenticator. Setting \"require_message_authenticator = yes\"");
1145 *(
inst->received_message_authenticator) =
true;
1148 *response_code = code;
1189 .add_proxy_state = u->
proxied,
1212 RPERROR(
"Failed encoding packet");
1219 if (packet_len < 0) {
1224 need = have - packet_len;
1227 RERROR(
"Failed encoding packet. Have %zu bytes of buffer, need %zu bytes",
1230 RERROR(
"Failed encoding packet. Have %zu bytes of buffer, need %zu bytes. "
1231 "Increase 'max_packet_size'", have, need);
1239 fr_assert((
size_t) packet_len <= u->packet_len);
1254 packet_len += 2 +
sizeof(
inst->common_ctx.proxy_state);
1267 RERROR(
"Failed signing packet");
1318 ERROR(
"Failed inserting revive timeout for connection");
1398 ERROR(
"Failed inserting zombie timeout for connection");
1413 RDEBUG(
"Using stream sockets - suppressing retransmission");
1421 RDEBUG(
"IO is blocked - suppressing retransmission");
1460 switch (retry->
state) {
1464 switch (treq->state) {
1471 RDEBUG(
"Packet is still in the backlog queue to be sent - suppressing retransmission");
1475 RDEBUG(
"Packet is still in the pending queue to be sent - suppressing retransmission");
1479 RDEBUG(
"Packet was partially written, as IO is blocked - suppressing retransmission");
1501 REDEBUG(
"Reached maximum_retransmit_duration (%pVs > %pVs), failing request",
1506 REDEBUG(
"Reached maximum_retransmit_count (%u > %u), failing request",
1537 request = treq->request;
1593 RDEBUG(
"Sending %s ID %d length %zu over connection %s",
1596 if (
encode(h, request, u, u->
id) < 0) {
1613 RDEBUG(
"Retransmitting %s ID %d length %zu over connection %s",
1632 if (slen ==
fr_bio_error(IO_WOULD_BLOCK))
goto requeue;
1640 ERROR(
"%s - Failed sending data over connection %s: %s",
1650 ERROR(
"%s - Failed sending data over connection %s: %s",
1666 RWARN(
"%s - Failed sending data over connection %s: sent zero bytes",
1673 if (packet_len < u->packet_len) {
1710 action = u->
proxied ?
"Proxied" :
"Originated";
1716 action =
"Retransmitted";
1722 RDEBUG(
"%s request. Expecting response within %pVs", action,
1730 RDEBUG(
"%s request. Relying on NAS to perform more retransmissions", action);
1751 bool error_601 =
false;
1766 memcpy(&error, attr + 2, 4);
1767 error = ntohl(error);
1768 if (error == 601) error_601 =
true;
1776 memcpy(&response_length, attr + 2, 4);
1793 if (attr[1] != 7)
continue;
1803 if ((attr[3] != 0) ||
1817 if (attr[6] != u->
code) {
1830 if (error_601 && response_length && (response_length > h->
buflen)) {
1831 if (response_length < 4096) response_length = 4096;
1832 if (response_length > 65535) response_length = 65535;
1840 h->
buflen = response_length;
1843 memcpy(h->
buffer, attr, end - attr);
1896 DEBUG(
"Received %u / %u replies for status check, on connection - %s",
1909 DEBUG(
"Received enough replies to status check, marking connection as active - %s", h->
ctx.
fd_info->
name);
1969 ERROR(
"%s - Failed reading response from socket: %s",
1976 ERROR(
"%s - Packet too short, expected at least %zu bytes got %zd bytes",
1987 WARN(
"%s - Ignoring reply with ID %i that arrived too late",
1993 request = treq->request;
2002 if (!
check(h, &slen)) {
2003 RWARN(
"Ignoring malformed packet");
2007 reason =
decode(request->reply_ctx, &reply, &code, h, request, u, rr->vector, h->
buffer, (
size_t)slen);
2080 treq->request->reply->code = code;
2225 if (!u->
treq)
return;
2257 if (!u->
treq)
return 0;
2295 REDEBUG(
"Failed allocating handler for request");
2305 u->
code = request->packet->code;
2306 u->
priority = request->async->priority;
2307 u->
recv_time = request->async->recv_time;
2320 REDEBUG(
"Unable to queue packet - connections at maximum capacity");
2328 REDEBUG(
"All destinations are down - cannot send packet");
2332 REDEBUG(
"Unable to queue packet");
2343 switch (
inst->mode) {
2346 REDEBUG(
"Internal sanity check failed - connection trunking cannot be used for replication");
2362 if (!request->parent) {
2363 u->
proxied = (request->client->cs != NULL);
2369 u->
proxied = (request->parent->packet->code == request->packet->code);
2375 if (u->
proxied)
goto timeout_retry;
2383 if (
inst->fd_config.socket_type == SOCK_DGRAM) {
2445 &
inst->trunk_conf,
inst->name, thread,
false);
2454 if (!thread->
bio.fd) {
2455 PERROR(
"%s - failed opening socket",
inst->name);
2459 thread->
bio.fd->uctx = thread;
2511 RDEBUG(
"Invalid destination IP address family in %pV", ipaddr);
2519 RWDEBUG(
"Replication of packets other then Accounting-Request will likely not do what you want.");
2527 .secret_length =
secret->vb_length,
2532 .common = &radius_ctx,
2537 .code = request->packet->code,
2538 .id = thread->
bio.id++ & 0xff,
2539 .add_proxy_state =
false,
2548 RPERROR(
"Failed encoding packet");
2556 RERROR(
"Failed signing packet");
2566 addr.
socket.inet.dst_ipaddr = ipaddr->vb_ip;
2567 addr.
socket.inet.dst_port = port->vb_uint16;
2569 RDEBUG(
"Replicating packet to %pV:%u", ipaddr, port->vb_uint16);
2575 if (packet_len < 0) {
2576 RPERROR(
"Failed sending packet to %pV:%u", ipaddr, port->vb_uint16);
2599 if (rcode != 0)
return rcode;
2614 dst->vb_uint32 = u->
rcode;
2661 RDEBUG(
"Invalid destination IP address family in %pV", ipaddr);
2666 .fd_config = (fr_bio_fd_config_t) {
2667 .dst_ipaddr = ipaddr->vb_ip,
2668 .dst_port = port->vb_uint16,
2677 .module_name =
inst->name,
2682 home->fd_config =
inst->fd_config;
2683 home->ctx.fd_config = &home->fd_config;
2686 home->fd_config.dst_ipaddr = ipaddr->vb_ip;
2687 home->fd_config.dst_port = port->vb_uint32;
2690 .secret = talloc_strdup(home,
secret->vb_strvalue),
2691 .secret_length =
secret->vb_length,
2692 .proxy_state =
inst->common_ctx.proxy_state,
2699 &
inst->trunk_conf,
inst->name, home,
false);
2700 if (!home->ctx.trunk) {
2725 if (old == home)
break;
2730 if (old->
ctx.
trunk->req_alloc)
break;
2749 REDEBUG(
"Failed enqueuing packet");
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
static int const char char buffer[256]
static ssize_t fr_bio_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Write raw data to a bio.
static ssize_t fr_bio_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read raw data from a bio.
void * uctx
user ctx, caller can manually set it.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define CMP_PREFER_SMALLER(_a, _b)
Evaluates to +1 for a > b, and -1 for a < b.
#define CC_NO_UBSAN(_sanitize)
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
@ CONNECTION_STATE_FAILED
Connection has failed.
@ CONNECTION_STATE_CONNECTED
File descriptor is open (ready for writing).
@ CONNECTION_STATE_INIT
Init state, sets up connection.
@ CONNECTION_STATE_CONNECTING
Waiting for connection to establish.
@ CONNECTION_FAILED
Connection is being reconnected because it failed.
Holds a complete set of functions for a connection.
HIDDEN fr_dict_attr_t const * attr_event_timestamp
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
@ FR_RADIUS_CODE_ACCESS_REQUEST
RFC2865 - Access-Request.
@ FR_RADIUS_CODE_MAX
Maximum possible protocol code.
@ FR_RADIUS_CODE_DISCONNECT_ACK
RFC3575/RFC5176 - Disconnect-Ack (positive)
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
@ FR_RADIUS_CODE_ACCOUNTING_RESPONSE
RFC2866 - Accounting-Response.
@ FR_RADIUS_CODE_COA_NAK
RFC3575/RFC5176 - CoA-Nak (not willing to perform)
@ FR_RADIUS_CODE_COA_ACK
RFC3575/RFC5176 - CoA-Ack (positive)
@ FR_RADIUS_CODE_DISCONNECT_NAK
RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
@ FR_RADIUS_CODE_PROTOCOL_ERROR
RFC7930 - Protocol-Error (generic NAK)
@ FR_RADIUS_CODE_ACCOUNTING_REQUEST
RFC2866 - Accounting-Request.
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
static fr_dict_attr_t const * attr_packet_type
bool fr_dict_compatible(fr_dict_t const *dict1, fr_dict_t const *dict2)
See if two dictionaries have the same end parent.
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
unsigned int offset
Positive offset from start of structure to fr_dlist_t.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
static void * fr_dlist_entry_to_item(size_t offset, fr_dlist_t const *entry)
Get the item from a fr_dlist_t.
Entry in a doubly linked list.
#define fr_event_fd_insert(...)
void(* fr_event_fd_cb_t)(fr_event_list_t *el, int fd, int flags, void *uctx)
Called when an IO event occurs on a file descriptor.
#define fr_event_timer_at(...)
int fr_bio_fd_connect_full(fr_bio_t *bio, fr_event_list_t *el, fr_bio_callback_t connected_cb, fr_bio_callback_t error_cb, fr_time_delta_t *timeout, fr_bio_callback_t timeout_cb)
Finalize a connect()
fr_bio_t * fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_fd_config_t const *cfg, size_t offset)
Allocate a FD bio.
fr_bio_fd_info_t const * fr_bio_fd_info(fr_bio_t *bio)
Returns a pointer to the bio-specific information.
int fr_bio_fd_write_only(fr_bio_t *bio)
Mark up a bio as write-only.
fr_socket_t socket
as connected socket
char const * name
printable name of this BIO
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
fr_bio_fd_state_t state
connecting, open, closed, etc.
@ FR_BIO_FD_STATE_CONNECTING
@ FR_BIO_FD_STATE_OPEN
error states must be before this
int connect_errno
from connect() or other APIs
fr_ipaddr_t dst_ipaddr
their IP address
int socket_type
SOCK_STREAM or SOCK_DGRAM.
uint16_t dst_port
their port
fr_socket_t socket
socket information, including FD.
bool write_blocked
did we block on write?
Configuration for sockets.
Run-time status of the socket.
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Minimal data structure to use the new code.
static bool fr_pair_encode_is_error(ssize_t slen)
Determine if the return code for an encoding function is a fatal error.
fr_bio_t * fr_bio_mem_alloc(TALLOC_CTX *ctx, size_t read_size, size_t write_size, fr_bio_t *next)
Allocate a memory buffer bio.
int fr_bio_mem_set_verify(fr_bio_t *bio, fr_bio_verify_t verify, void *verify_ctx, bool datagram)
Set the verification function for memory bios.
HIDDEN fr_dict_attr_t const * attr_eap_message
void log_request_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a fr_pair_list_t.
#define RPEDEBUG(fmt,...)
#define HEXDUMP3(_data, _len, _fmt,...)
#define RHEXDUMP3(_data, _len, _fmt,...)
int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t const *map, UNUSED void *uctx)
Convert a map to a fr_pair_t.
int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert map_t to fr_pair_t (s) and add them to a request_t.
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
Stores all information relating to an event list.
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
@ L_DBG_LVL_3
3rd highest priority debug messages (-xxx | -Xx).
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
fr_bio_verify_action_t
Status returned by the verification callback.
@ FR_BIO_VERIFY_ERROR_CLOSE
fatal error, the bio should be closed.
@ FR_BIO_VERIFY_DISCARD
the packet should be discarded
@ FR_BIO_VERIFY_OK
packet is OK
@ FR_BIO_VERIFY_WANT_MORE
not enough data for one packet
bool fr_radius_ok(uint8_t const *packet, size_t *packet_len_p, uint32_t max_attributes, bool require_message_authenticator, decode_fail_t *reason)
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
module_instance_t const * mi
Instance of the module being instantiated.
void * thread
Thread specific instance data.
void * rctx
Resume ctx that a module previously set.
fr_event_list_t * el
Event list to register any IO handlers and timers against.
void * thread
Thread instance data.
module_instance_t const * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for thread_instantiation calls.
static int mod_enqueue(bio_request_t **p_u, fr_retry_config_t const **p_retry_config, rlm_radius_t const *inst, trunk_t *trunk, request_t *request)
static int8_t request_prioritise(void const *one, void const *two)
static void do_retry(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_retry_t const *retry)
static bool check_for_zombie(fr_event_list_t *el, trunk_connection_t *tconn, fr_time_t now, fr_time_t last_sent)
See if the connection is zombied.
static void conn_init_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
Connection errored.
static void request_demux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
static void conn_discard(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
Read and discard data.
uint8_t id
Last ID assigned to this packet.
uint32_t max_packet_size
Our max packet size. may be different from the parent.
static void do_signal(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_signal_t action)
static void bio_connected(fr_bio_t *bio)
uint32_t num_replies
number of reply packets, sent is in retry.count
static const trunk_io_funcs_t io_funcs
struct bio_thread_t::@170 bio
uint32_t priority
copied from request->async->priority
static rlm_rcode_t radius_code_to_rcode[FR_RADIUS_CODE_MAX]
Turn a reply code into a module rcode;.
static void conn_init_timeout(fr_event_list_t *el, fr_time_t now, void *uctx)
Status check timer when opening the connection for the first time.
static void conn_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
Connection errored.
char const * module_name
the module that opened the connection
fr_bio_fd_info_t const * fd_info
status of the FD.
static void mod_signal(module_ctx_t const *mctx, UNUSED request_t *request, fr_signal_t action)
static xlat_action_t xlat_sendto_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
uint8_t last_id
Used when replicating to ensure IDs are distributed evenly.
static void mod_retry(module_ctx_t const *mctx, request_t *request, fr_retry_t const *retry)
Handle module retries.
static fr_radius_decode_fail_t decode(TALLOC_CTX *ctx, fr_pair_list_t *reply, uint8_t *response_code, bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t const request_authenticator[static RADIUS_AUTH_VECTOR_LENGTH], uint8_t *data, size_t data_len)
Decode response packet data, extracting relevant information and validating the packet.
static void conn_close(UNUSED fr_event_list_t *el, void *handle, UNUSED void *uctx)
Shutdown/close a file descriptor.
static void thread_conn_notify(trunk_connection_t *tconn, connection_t *conn, fr_event_list_t *el, trunk_connection_event_t notify_on, UNUSED void *uctx)
static int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id)
fr_time_t last_reply
When we last received a reply.
static void request_conn_release(connection_t *conn, void *preq_to_reset, UNUSED void *uctx)
Clear out anything associated with the handle from the request.
int fd
from thread or home server
bio_request_t * status_u
for sending status check packets
bio_handle_ctx_t ctx
for copying to bio_handle_t
static fr_bio_verify_action_t rlm_radius_verify(UNUSED fr_bio_t *bio, void *verify_ctx, UNUSED void *packet_ctx, const void *data, size_t *size)
static void mod_write(request_t *request, trunk_request_t *treq, bio_handle_t *h)
fr_event_timer_t const * ev
timer for retransmissions
#define check(_handle, _len_p)
fr_pair_list_t extra
VPs for debugging, like Proxy-State.
bool proxied
is this request being proxied
size_t buflen
Receive buffer length.
static void conn_init_readable(fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
Read the connection during the init and negotiation stage.
static void zombie_timeout(fr_event_list_t *el, fr_time_t now, void *uctx)
Mark a connection dead after "zombie_interval".
fr_time_t last_idle
last time we had nothing to do
static void bio_tracking_entry_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line, radius_track_entry_t *te)
Log additional information about a tracking entry.
static xlat_action_t xlat_radius_replicate(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
radius_track_entry_t * rr
ID tracking, resend count, etc.
size_t packet_len
Length of the packet.
static int _bio_handle_free(bio_handle_t *h)
Free a connection handle, closing associated resources.
size_t partial
partially sent data
fr_event_list_t * el
Event list.
static void request_cancel(UNUSED connection_t *conn, void *preq_to_reset, trunk_cancel_reason_t reason, UNUSED void *uctx)
Remove the request from any tracking structures.
static void home_server_free(void *data)
static void status_check_next(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Handle retries for a status check.
static void revive_timeout(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Revive a connection after "revive_interval".
static void protocol_error_reply(bio_request_t *u, bio_handle_t *h)
Deal with Protocol-Error replies, and possible negotiation.
static void status_check_reset(bio_handle_t *h, bio_request_t *u)
Reset a status_check packet, ready to reuse.
static void request_fail(request_t *request, NDEBUG_UNUSED void *preq, void *rctx, NDEBUG_UNUSED trunk_request_state_t state, UNUSED void *uctx)
Write out a canned failure.
fr_time_t recv_time
copied from request->async->recv_time
fr_retry_t retry
retransmission timers
static void conn_init_writable(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
static xlat_action_t xlat_radius_client(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
rlm_rcode_t rcode
from the transport
static void status_check_alloc(bio_handle_t *h)
fr_time_t mrs_time
Most recent sent time which had a reply.
bool status_checking
whether we're doing status checks
trunk_t * trunk
trunk handler
fr_time_t last_sent
last time we sent a packet.
static void conn_init_next(fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Perform the next step of init and negotiation.
bio_handle_ctx_t ctx
for copying to bio_handle_t
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Instantiate thread data for the submodule.
static void bio_error(fr_bio_t *bio)
static void status_check_reply(trunk_request_t *treq, fr_time_t now)
Deal with replies replies to status checks and possible negotiation.
static unlang_action_t mod_resume(rlm_rcode_t *p_result, module_ctx_t const *mctx, UNUSED request_t *request)
Resume execution of the request, returning the rcode set during trunk execution.
static int _bio_request_free(bio_request_t *u)
Free a bio_request_t.
fr_time_t first_sent
first time we sent a packet since going idle
static connection_t * thread_conn_alloc(trunk_connection_t *tconn, fr_event_list_t *el, connection_conf_t const *conf, char const *log_prefix, void *uctx)
static void xlat_sendto_retry(xlat_ctx_t const *xctx, request_t *request, fr_retry_t const *retry)
static void bio_request_reset(bio_request_t *u)
Clear out any connection specific resources from a udp request.
struct bio_handle_t::@171 bio
rlm_radius_t const * inst
our instance
static connection_state_t conn_init(void **h_out, connection_t *conn, void *uctx)
Initialise a new outbound connection.
fr_rb_expire_node_t expire
uint8_t * packet
Packet we write to the network.
static connection_state_t conn_failed(void *handle, connection_state_t state, UNUSED void *uctx)
Connection failed.
fr_radius_ctx_t radius_ctx
radius_track_t * tt
RADIUS ID tracking structure.
static void mod_dup(request_t *request, bio_request_t *u)
fr_event_timer_t const * zombie_ev
Zombie timeout.
static int8_t home_server_cmp(void const *one, void const *two)
Dynamic home server code.
static void request_mux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
uint8_t * buffer
Receive buffer.
request_t * status_request
static void request_complete(request_t *request, NDEBUG_UNUSED void *preq, void *rctx, UNUSED void *uctx)
Response has already been written to the rctx at this point.
bool status_check
is this packet a status check?
static xlat_arg_parser_t const xlat_radius_send_args[]
fr_bio_fd_config_t fd_config
fil descriptor configuration
fr_bio_fd_config_t * fd_config
for threads or sockets
static void xlat_sendto_signal(xlat_ctx_t const *xctx, request_t *request, fr_signal_t action)
Track the handle, which is tightly correlated with the FD.
Connect request_t to local tracking structure.
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
#define RADIUS_HEADER_LENGTH
#define RADIUS_AUTH_VECTOR_LENGTH
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
int fr_pair_delete_by_da(fr_pair_list_t *list, fr_dict_attr_t const *da)
Delete matching pairs from the specified list.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
static fr_internal_encode_ctx_t encode_ctx
ssize_t fr_radius_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t *packet, size_t packet_len, fr_radius_decode_ctx_t *decode_ctx)
int fr_radius_sign(uint8_t *packet, uint8_t const *vector, uint8_t const *secret, size_t secret_len)
Sign a previously encoded packet.
ssize_t fr_radius_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_radius_encode_ctx_t *packet_ctx)
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
static fr_dict_attr_t const * attr_user_password
static fr_dict_attr_t const * attr_proxy_state
@ FR_RADIUS_REQUIRE_MA_AUTO
Only require Message-Authenticator if we've previously received a packet from this client with Messag...
#define RADIUS_AUTH_VECTOR_OFFSET
fr_radius_decode_fail_t
Failure reasons.
@ DECODE_FAIL_UNKNOWN_PACKET_CODE
#define RADIUS_MAX_PACKET_SIZE
fr_radius_ctx_t const * common
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
static fr_dict_attr_t const * attr_extended_attribute_1
static fr_dict_attr_t const * attr_message_authenticator
uint32_t fr_rand(void)
Return a 32-bit random number.
Smaller fast random number generator.
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
bool fr_rb_expire_insert(fr_rb_expire_t *expire, void *data, fr_time_t now)
Attempt to find current data in the tree, if it does not exist insert it.
void fr_rb_expire_update(fr_rb_expire_t *expire, void *data, fr_time_t now)
#define fr_rb_expire_inline_talloc_init(_expire, _type, _field, _data_cmp, _data_free, _lifetime)
dlist for expiring old entries
#define RETURN_MODULE_RCODE(_rcode)
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_OK
The module is OK, continue.
@ RLM_MODULE_FAIL
Module failed, don't reply.
@ RLM_MODULE_REJECT
Immediately reject the request.
@ RLM_MODULE_UPDATED
OK (pairs modified).
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
#define request_local_alloc_external(_ctx, _args)
Allocate a new external request outside of the request pool.
static fr_dict_attr_t const * attr_error_cause
static int radius_fixups(rlm_radius_t const *inst, request_t *request)
Do any RADIUS-layer fixups for proxying.
static fr_dict_attr_t const * attr_nas_identifier
static fr_dict_attr_t const * attr_original_packet_code
static fr_dict_attr_t const * attr_response_length
fr_time_delta_t revive_interval
fr_retry_config_t retry[FR_RADIUS_CODE_MAX]
uint32_t status_check
code of status-check type
rlm_radius_mode_t mode
proxy, client, etc.
@ RLM_RADIUS_MODE_XLAT_PROXY
@ RLM_RADIUS_MODE_INVALID
@ RLM_RADIUS_MODE_REPLICATE
@ RLM_RADIUS_MODE_UNCONNECTED_REPLICATE
uint32_t max_packet_size
Maximum packet size.
fr_time_delta_t response_window
uint32_t max_attributes
Maximum number of attributes to decode in response.
fr_time_delta_t zombie_period
fr_bio_fd_config_t fd_config
for now MUST be at the start!
static conf_parser_t retry_config[]
void connection_signal_reconnect(connection_t *conn, connection_reason_t reason)
Asynchronously signal the connection should be reconnected.
int connection_signal_on_fd(connection_t *conn, int fd)
Setup the connection to change states to connected or failed based on I/O events.
connection_t * connection_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, connection_funcs_t const *funcs, connection_conf_t const *conf, char const *log_prefix, void const *uctx)
Allocate a new connection.
void connection_signal_connected(connection_t *conn)
Asynchronously signal that the connection is open.
void * data
Module's instance data.
#define pair_append_request(_attr, _da)
Allocate and append a fr_pair_t to the request list.
#define tmpl_is_attr(vpt)
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
fr_signal_t
Signals that can be generated/processed by request signal handlers.
@ FR_SIGNAL_DUP
A duplicate request was received.
@ FR_SIGNAL_CANCEL
Request has been cancelled.
eap_aka_sim_process_conf_t * inst
eap_type_t type
The preferred EAP-Type of this instance of the EAP-SIM/AKA/AKA' state machine.
#define fr_time()
Allow us to arbitrarily manipulate time.
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
Stores an attribute, a value and various bits of other data.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define talloc_get_type_abort_const
static int talloc_const_free(void const *ptr)
Free const'd memory.
#define fr_time_gteq(_a, _b)
static int64_t fr_time_unwrap(fr_time_t time)
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
#define fr_time_wrap(_time)
#define fr_time_lteq(_a, _b)
#define fr_time_eq(_a, _b)
#define fr_time_add(_a, _b)
Add a time/time delta together.
#define fr_time_gt(_a, _b)
#define fr_time_sub(_a, _b)
Subtract one time from another.
static fr_unix_time_t fr_time_to_unix_time(fr_time_t when)
Convert an fr_time_t (internal time) to our version of unix time (wallclock time)
#define fr_time_lt(_a, _b)
void radius_track_state_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line, radius_track_t *tt, radius_track_log_extra_t extra)
Print out the state of every tracking entry.
int radius_track_entry_update(radius_track_entry_t *te, uint8_t const *vector)
Update a tracking entry with the authentication vector.
radius_track_entry_t * radius_track_entry_find(radius_track_t *tt, uint8_t packet_id, uint8_t const *vector)
Find a tracking entry from a request authenticator.
radius_track_t * radius_track_alloc(TALLOC_CTX *ctx)
Create an radius_track_t.
#define radius_track_entry_release(_te)
void * uctx
Result/resumption context.
unsigned int num_requests
number of requests in the allocation
#define radius_track_entry_reserve(_te_out, _ctx, _tt, _request, _code, _uctx)
request_t * request
as always...
Track one request to a response.
void trunk_connection_callback_readable(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
Standard I/O read function.
void trunk_connection_callback_writable(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
Standard I/O write function.
void trunk_request_signal_partial(trunk_request_t *treq)
Signal a partial write.
void trunk_request_signal_fail(trunk_request_t *treq)
Signal that a trunk request failed.
trunk_request_t * trunk_request_alloc(trunk_t *trunk, request_t *request)
(Pre-)Allocate a new trunk request
trunk_t * trunk_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, trunk_io_funcs_t const *funcs, trunk_conf_t const *conf, char const *log_prefix, void const *uctx, bool delay_start)
Allocate a new collection of connections.
uint64_t trunk_connection_requests_requeue(trunk_connection_t *tconn, int states, uint64_t max, bool fail_bound)
Move requests off of a connection and requeue elsewhere.
trunk_enqueue_t trunk_request_enqueue_on_conn(trunk_request_t **treq_out, trunk_connection_t *tconn, request_t *request, void *preq, void *rctx, bool ignore_limits)
Enqueue additional requests on a specific connection.
trunk_enqueue_t trunk_request_enqueue(trunk_request_t **treq_out, trunk_t *trunk, request_t *request, void *preq, void *rctx)
Enqueue a request that needs data written to the trunk.
trunk_enqueue_t trunk_request_requeue(trunk_request_t *treq)
Re-enqueue a request on the same connection.
int trunk_connection_pop_request(trunk_request_t **treq_out, trunk_connection_t *tconn)
Pop a request off a connection's pending queue.
void trunk_request_signal_cancel(trunk_request_t *treq)
Cancel a trunk request.
void trunk_request_free(trunk_request_t **treq_to_free)
If the trunk request is freed then update the target requests.
void trunk_connection_signal_active(trunk_connection_t *tconn)
Signal a trunk connection is no longer full.
void trunk_connection_signal_inactive(trunk_connection_t *tconn)
Signal a trunk connection cannot accept more requests.
void trunk_request_signal_sent(trunk_request_t *treq)
Signal that the request was written to a connection successfully.
void trunk_request_signal_complete(trunk_request_t *treq)
Signal that a trunk request is complete.
void trunk_connection_signal_reconnect(trunk_connection_t *tconn, connection_reason_t reason)
Signal a trunk connection is no longer viable.
void trunk_request_state_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line, trunk_request_t const *treq)
Associates request queues with a connection.
Main trunk management handle.
#define TRUNK_REQUEST_STATE_ALL
All request states.
trunk_connection_alloc_t connection_alloc
Allocate a new connection_t.
trunk_connection_event_t
What type of I/O events the trunk connection is currently interested in receiving.
@ TRUNK_CONN_EVENT_BOTH
Trunk should be notified if a connection is readable or writable.
@ TRUNK_CONN_EVENT_WRITE
Trunk should be notified if a connection is writable.
@ TRUNK_CONN_EVENT_NONE
Don't notify the trunk on connection state changes.
@ TRUNK_CONN_EVENT_READ
Trunk should be notified if a connection is readable.
trunk_cancel_reason_t
Reasons for a request being cancelled.
@ TRUNK_CANCEL_REASON_REQUEUE
A previously sent request is being requeued.
@ TRUNK_ENQUEUE_DST_UNAVAILABLE
Destination is down.
@ TRUNK_ENQUEUE_FAIL
General failure.
@ TRUNK_ENQUEUE_OK
Operation was successful.
@ TRUNK_ENQUEUE_NO_CAPACITY
At maximum number of connections, and no connection has capacity.
@ TRUNK_ENQUEUE_IN_BACKLOG
Request should be enqueued in backlog.
trunk_request_state_t
Used for sanity checks and to simplify freeing.
@ TRUNK_REQUEST_STATE_PARTIAL
Some of the request was written to the socket, more of it should be written later.
@ TRUNK_REQUEST_STATE_REAPABLE
Request has been written, needs to persist, but we are not currently waiting for any response.
@ TRUNK_REQUEST_STATE_UNASSIGNED
Transition state - Request currently not assigned to any connection.
@ TRUNK_REQUEST_STATE_INIT
Initial state.
@ TRUNK_REQUEST_STATE_CANCEL_SENT
We've informed the remote server that the request has been cancelled.
@ TRUNK_REQUEST_STATE_COMPLETE
The request is complete.
@ TRUNK_REQUEST_STATE_FAILED
The request failed.
@ TRUNK_REQUEST_STATE_CANCEL
A request on a particular socket was cancel.
@ TRUNK_REQUEST_STATE_CANCEL_PARTIAL
We partially wrote a cancellation request.
@ TRUNK_REQUEST_STATE_BACKLOG
In the backlog.
@ TRUNK_REQUEST_STATE_CANCEL_COMPLETE
Remote server has acknowledged our cancellation.
@ TRUNK_REQUEST_STATE_PENDING
In the queue of a connection and is pending writing.
@ TRUNK_REQUEST_STATE_SENT
Was written to a socket. Waiting for a response.
I/O functions to pass to trunk_alloc.
static fr_event_list_t * el
xlat_action_t unlang_xlat_yield_to_retry(request_t *request, xlat_func_t resume, fr_unlang_xlat_retry_t retry, xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx, fr_retry_config_t const *retry_cfg)
Yield a request back to the interpreter, with retries.
bool required
Argument must be present, and non-empty.
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
#define XLAT_ARG_PARSER_TERMINATOR
@ XLAT_ACTION_FAIL
An xlat function failed.
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition for a single argument consumend by an xlat function.
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
fr_retry_state_t fr_retry_next(fr_retry_t *r, fr_time_t now)
Initialize a retransmission counter.
void fr_retry_init(fr_retry_t *r, fr_time_t now, fr_retry_config_t const *config)
Initialize a retransmission counter.
fr_time_t start
when we started the retransmission
fr_time_delta_t rt
retransmit interval
uint32_t mrc
Maximum retransmission count.
fr_retry_config_t const * config
master configuration
fr_retry_state_t state
so callers can see what state it's in.
@ FR_RETRY_MRC
reached maximum retransmission count
@ FR_RETRY_MRD
reached maximum retransmission duration
uint32_t count
number of sent packets
fr_time_delta_t mrd
Maximum retransmission duration.
fr_time_t updated
last update, really a cached "now".
fr_time_t next
when the next timer should be set
int af
AF_INET, AF_INET6, or AF_UNIX.
int fd
File descriptor if this is a live socket.
char const * fr_strerror(void)
Get the last library error.
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
#define fr_box_time_delta(_val)
static size_t char ** out
void * rctx
Resume context.
module_ctx_t const * mctx
Synthesised module calling ctx.