24#include <freeradius-devel/io/listen.h>
25#include <freeradius-devel/io/master.h>
27#include <freeradius-devel/server/base.h>
28#include <freeradius-devel/server/module.h>
29#include <freeradius-devel/server/log.h>
31#include <freeradius-devel/util/debug.h>
33#include <freeradius-devel/util/misc.h>
34#include <freeradius-devel/util/syserror.h>
183 talloc_free_children(track);
219 if (ret != 0)
return ret;
266 if (ret != 0)
return ret;
294static int8_t
track_cmp(
void const *one,
void const *two)
311 if (ret != 0)
return ret;
401#define DUP_FIELD(_x) do { if (parent->_x) {c->_x = talloc_strdup(c, parent->_x); if (!c->_x) {goto error;}}} while (0)
402#define COPY_FIELD(_x) c->_x = parent->_x
412 COPY_FIELD(require_message_authenticator_is_set);
458 pthread_mutex_lock(&client->
mutex);
461 pthread_mutex_unlock(&client->
mutex);
466 pthread_mutex_unlock(&client->
mutex);
505 TALLOC_FREE(connection->
client);
554 "proto_%s - Ignoring connection from client %s - 'max_connections' limit reached.",
556 if (fd >= 0)
close(fd);
565 inst_name = talloc_asprintf(NULL,
"%"PRIu64, thread->
client_id++);
597 MEM(connection->
address = talloc_memdup(connection, address,
sizeof(*address)));
598 (void) talloc_set_name_const(connection->
address,
"fr_io_address_t");
600 connection->
parent = client;
604 memset(connection->
client, 0,
sizeof(*connection->
client));
620 if (
inst->app_io->track_duplicates) {
678 switch (client->
state) {
686 radclient->
active =
false;
706 memcpy(li, thread->
listen,
sizeof(*li));
721 inst->app_io->common.thread_inst_size);
724 inst->app_io->common.name);
744 memcpy(li, thread->
listen,
sizeof(*li));
761 if (
inst->app_io->connection_set(connection->
child, connection->
address) < 0) {
762 DEBUG(
"proto_%s - Failed setting connection for socket.",
inst->app->common.name);
783 struct sockaddr_storage src;
788 DEBUG(
"proto_%s - Failed getting IP address",
inst->app->common.name);
793 if (
inst->app_io->open(connection->
child) < 0) {
794 DEBUG(
"proto_%s - Failed opening connected socket.",
inst->app->common.name);
801 if (connect(fd, (
struct sockaddr *) &src, salen) < 0) {
812 if (
inst->app_io->fd_set(connection->
child, fd) < 0) {
813 DEBUG3(
"Failed setting FD to %s",
inst->app_io->common.name);
819 if (!
inst->app_io->get_name) {
820 connection->
name =
fr_asprintf(connection,
"proto_%s from client %pV port "
821 "%u to server %pV port %u",
822 inst->app->common.name,
828 connection->
name =
inst->app_io->get_name(connection->
child);
842 pthread_mutex_lock(&client->
mutex);
850 pthread_mutex_unlock(&client->
mutex);
851 ERROR(
"proto_%s - Failed inserting connection into tracking table. "
852 "Closing it, and discarding all packets for connection %s.",
853 inst->app_io->common.name, connection->
name);
857 pthread_mutex_unlock(&client->
mutex);
864 INFO(
"proto_%s - Verification failed for packet from dynamic client %pV - adding IP address to the NAK cache",
867 connection->
name = talloc_strdup(connection, nak->
name);
869 connection->
el = nak->
el;
873 DEBUG(
"proto_%s - starting connection %s",
inst->app_io->common.name, connection->
name);
875 if (!connection->
nr) {
876 ERROR(
"proto_%s - Failed inserting connection into scheduler. "
877 "Closing it, and diuscarding all packets for connection %s.",
878 inst->app_io->common.name, connection->
name);
879 pthread_mutex_lock(&client->
mutex);
881 pthread_mutex_unlock(&client->
mutex);
884 if (fd >= 0)
close(fd);
923 *
inst = (*connection)->client->inst;
924 if (thread) *thread = NULL;
925 if (child) *child = (*connection)->child;
940 radclient->
secret = radclient->
nas_type = talloc_strdup(radclient,
"");
999 memset(client, 0,
sizeof(*client));
1001 client->
state = state;
1031 if (
inst->app_io->track_duplicates) {
1043 (void) pthread_mutex_init(&client->
mutex, NULL);
1052 ERROR(
"proto_%s - Failed inserting client %s into tracking table. Discarding client, and all packets for it.",
1088 uint8_t const *packet,
size_t packet_len,
1104 memcpy(my_address, address,
sizeof(*address));
1133 track, packet, packet_len);
1143 if (!old)
goto do_insert;
1167 len = talloc_array_length(old->
packet);
1168 if ((len == talloc_array_length(track->
packet)) &&
1177 DEBUG(
"Ignoring duplicate packet while client %s is still pending dynamic definition",
1268 pending->
track = track;
1326 int value, accept_fd = -1;
1331#define LOG_IGNORED_CLIENTS(_inst) ((_inst)->log_ignored_clients || fr_debug_lvl >= 1)
1343 if (*leftover)
goto do_read;
1357 if (connection->
dead) {
1358 DEBUG(
"Dead connection %s", connection->
name);
1373 track = pending->
track;
1379 talloc_set_destructor(pending, NULL);
1392 DEBUG3(
"Discarding old packet");
1393 TALLOC_FREE(pending);
1401 *packet_ctx = track;
1403 recv_time = *recv_time_p = pending->
recv_time;
1412 memcpy(&address, track->
address,
sizeof(address));
1413 TALLOC_FREE(pending);
1422 }
else if (!connection && (
inst->ipproto == IPPROTO_TCP)) {
1423 struct sockaddr_storage saremote;
1426 salen =
sizeof(saremote);
1433 accept_fd = accept(child->
fd,
1434 (
struct sockaddr *) &saremote, &salen);
1440 if (accept_fd < 0) {
1442 INFO,
"proto_%s - failed to accept new socket: %s",
1452#ifdef STATIC_ANALYZER
1453 saremote.ss_family = AF_INET;
1459 if ((saremote.ss_family == AF_INET) || (saremote.ss_family == AF_INET6)) {
1463 salen =
sizeof(saremote);
1468 (void) getsockname(accept_fd, (
struct sockaddr *) &saremote, &salen);
1471 address.
socket.
type = (
inst->ipproto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
1483 local_address = &address;
1503 packet_len =
inst->app_io->read(child, (
void **) &local_address, &recv_time,
1504 buffer, buffer_len, leftover);
1505 if (packet_len <= 0) {
1514 if (
inst->app->priority) {
1526 "proto_%s - ignoring packet from IP %pV. It is not configured as 'type = ...'",
1545 connection->
paused =
true;
1558 &address.
socket.inet.src_ipaddr.addr, address.
socket.inet.src_ipaddr.prefix);
1562 client = connection->
client;
1568 address = *connection->
address;
1575 if (accept_fd >= 0)
close(accept_fd);
1595 radclient =
inst->app_io->client_find(thread->
child, &address.
socket.inet.src_ipaddr,
inst->ipproto);
1603 radclient->
active =
true;
1605 }
else if (
inst->dynamic_clients) {
1607 error =
"Too many dynamic clients have been defined";
1615 address.
socket.inet.src_ipaddr.prefix);
1617 error =
"Address is outside of the the 'allow' network range";
1624 if (network->
af == AF_UNSPEC) {
1625 error =
"Address is forbidden by the 'deny' network range";
1639 error =
"No matching 'client' definition was found";
1642 if (accept_fd < 0) {
1645 msg =
"connection attempt";
1652 ERROR,
"proto_%s - Ignoring %s from IP address %pV - %s",
1671 if (accept_fd >= 0) {
1698 bool is_dup =
false;
1703 ERROR,
"Failed tracking packet from client %s - discarding it",
1715 DEBUG(
"Ignoring retransmit from client %s - we are not responding to this request", client->
radclient->
shortname);
1720 DEBUG(
"Ignoring transmit from client %s - we previously received a newer / conflicting packet", client->
radclient->
shortname);
1724 if (!track->
reply) {
1726 DEBUG(
"Ignoring retransmit from client %s - we are still processing the request", client->
radclient->
shortname);
1731 nr = connection->
nr;
1778 ERROR,
"Too many pending dynamic client packets for listener - discarding packet from %pV",
1794 ERROR,
"proto_%s - Failed allocating space for dynamic client %pV - discarding packet",
1800 DEBUG(
"Verification is still pending for dynamic client %pV - queuing additional packet(s)",
1811 INFO(
"proto_%s - Verification started for packet from dynamic client %pV - queuing new packets",
1829 *packet_ctx = track;
1854 my_connection.
address = &address;
1856 pthread_mutex_lock(&client->
mutex);
1859 pthread_mutex_unlock(&client->
mutex);
1869 DEBUG(
"Discarding packet to NAKed connection %s", connection->
name);
1886 DEBUG(
"Sending packet to connection %s", connection->
name);
1905 buffer, packet_len, recv_time) < 0) {
1907 "proto_%s - Discarding packet from dynamic client %pV - cannot push packet to connected socket",
1925 bool is_dup =
false;
1933 DEBUG2(
"Received injected packet for an unconnected socket.");
1938 if (priority <= 0) {
1946 buffer, buffer_len, recv_time, &is_dup);
1948 DEBUG2(
"Failed injecting packet to tracking table");
1965 DEBUG2(
"Failed injecting packet due to allocation error");
1983 if (
inst->app_io->open(thread->
child) < 0)
return -1;
2024 if (!
inst->submodule)
return;
2026 if (
inst->app_io->event_list_set) {
2027 inst->app_io->event_list_set(child,
el, nr);
2038 connection->
el =
el;
2039 connection->
nr = nr;
2073 switch (client->
state) {
2079 delay =
inst->idle_timeout;
2087 delay =
inst->nak_lifetime;
2104 INFO(
"proto_%s - Expiring NAK'd dynamic client %pV - permitting new packets to be verified",
2127 connection->
dead =
true;
2171 DEBUG(
"proto_%s - No packets are using unconnected socket %s",
inst->app_io->common.name, connection->
name);
2195 pthread_mutex_lock(&client->
mutex);
2198 pthread_mutex_unlock(&client->
mutex);
2214 DEBUG(
"proto_%s - idle timeout for connection %s",
inst->app_io->common.name, connection->
name);
2226 delay =
inst->idle_timeout;
2240 delay =
inst->check_interval;
2245 ERROR(
"proto_%s - Failed adding timeout for dynamic client %s. It will be permanent!",
2282 DEBUG(
"proto_%s - cleaning up request in %.6fs",
inst->app_io->common.name,
2287 DEBUG(
"proto_%s - Failed adding cleanup_delay for packet. Discarding packet immediately",
2288 inst->app_io->common.name);
2296 DEBUG2(
"TIMER - proto_%s - cleanup delay",
inst->app_io->common.name);
2298 DEBUG2(
"proto_%s - cleaning up",
inst->app_io->common.name);
2340 el = connection->
el;
2364 DEBUG3(
"Suppressing reply as we have a newer / conflicing packet from the same source");
2376 DEBUG3(
"Not sending response to request - it is marked as 'do not respond'");
2385 packet_len =
inst->app_io->write(child, track, request_time,
2386 buffer, buffer_len, written);
2387 if (packet_len <= 0) {
2388 ERROR(
"Failed writing the reply - not sending any response on %s",
name);
2399 if ((
size_t) packet_len < buffer_len) {
2400 DEBUG3(
"Partial write (%zd < %zu)", packet_len, buffer_len);
2408 if (!
inst->app_io->track_duplicates) {
2409 DEBUG3(
"Not tracking duplicates - expiring the request");
2419 if (!track->
reply) {
2448 if ((buffer_len == 1) && (*
buffer ==
true)) {
2449 DEBUG(
"Request has timed out trying to define a new client. Trying again.");
2458 if (buffer_len == 1) {
2459 INFO(
"proto_%s - Verification failed for packet from dynamic client %pV - adding IP address to the NAK cache",
2468 if (client->
table) TALLOC_FREE(client->
table);
2484 if (connection && (
inst->ipproto == IPPROTO_UDP)) {
2488 errno = ECONNREFUSED;
2501 fr_assert(buffer_len ==
sizeof(radclient));
2503 memcpy(&radclient,
buffer,
sizeof(radclient));
2514 DEBUG(
"Client IP address %pV IP family does not match the source network %pV of the packet.",
2524 DEBUG(
"Client IP address %pV is not within the prefix with the defined network %pV",
2529 ipaddr = radclient->
ipaddr;
2532 DEBUG(
"Client IP address %pV is not within the defined network %pV.",
2546 if (((radclient->
ipaddr.
af == AF_INET) &&
2548 ((radclient->
ipaddr.
af == AF_INET6) &&
2550 ERROR(
"Cannot define a dynamic client as a network");
2568#define COPY_FIELD(_dest, _x) _dest->radclient->_x = radclient->_x
2569#define DUP_FIELD(_dest, _x) _dest->radclient->_x = talloc_strdup(_dest->radclient, radclient->_x)
2585 COPY_FIELD(client, require_message_authenticator);
2586 COPY_FIELD(client, require_message_authenticator_is_set);
2588 COPY_FIELD(client, limit_proxy_state_is_set);
2626 if (connection->
paused) {
2661 INFO(
"proto_%s - Verification succeeded for packet from dynamic client %pV - processing queued packets",
2669 talloc_steal(radclient, radclient->
cs);
2679 DEBUG(
"proto_%s - cannot use connected sockets as underlying 'transport = %s' does not support it.",
2680 inst->app_io->common.name,
inst->submodule->module->exported->name);
2703 (void) pthread_mutex_init(&client->
mutex, NULL);
2713 INFO(
"proto_%s - Verification succeeded for packet from dynamic client %pV - processing %d queued packets",
2769 if (
inst->app_io->close) {
2772 ret =
inst->app_io->close(child);
2773 if (ret < 0)
return ret;
2779 if (!connection)
return 0;
2785 DEBUG(
"Closing connection %s", connection->
name);
2804 PERROR(
"Failed to delete connection %s", connection->
name);
2819 inst->app_io_conf =
inst->submodule->conf;
2820 inst->app_io_instance =
inst->submodule->data;
2828 if (!
inst->app_io->track_duplicates) {
2834 if (!
inst->app_io->track_create) {
2835 cf_log_err(
inst->app_io_conf,
"Internal error: 'track_duplicates' is set, but there is no 'track create' function");
2844 if (
inst->app_io->network_get) {
2845 inst->app_io->network_get(&
inst->ipproto, &
inst->dynamic_clients, &
inst->networks,
inst->app_io_instance);
2848 if ((
inst->ipproto == IPPROTO_TCP) && !
inst->app_io->connection_set) {
2849 cf_log_err(
inst->app_io_conf,
"Missing 'connection set' API for proto_%s",
inst->app_io->common.name);
2856 if (
inst->dynamic_clients) {
2860 cf_log_err(
conf,
"Cannot use 'dynamic_clients = yes' as the virtual server has no 'new client { ... }' section defined.");
2917 num = talloc_array_length(allow);
2920 for (i = 0; i < num; i++) {
2926 if (allow[i].af != af) {
2937 &allow[i].addr, allow[i].prefix);
2957 &allow[i].addr, allow[i].prefix);
2960 fr_strerror_const(
"Entry is completely enclosed inside of a previously defined network.");
2971 &allow[i].addr, allow[i].prefix,
2982 num = talloc_array_length(deny);
2983 if (!num)
return trie;
2989 for (i = 0; i < num; i++) {
2995 if (deny[i].af != af) {
3006 &deny[i].addr, deny[i].prefix);
3017 &deny[i].addr, deny[i].prefix);
3020 "contained within a previous 'allow'", i + 1,
fr_box_ipaddr(deny[i]));
3030 if (network->
af != af) {
3043 &deny[i].addr, deny[i].prefix,
3053 deny[i].
af = AF_UNSPEC;
3069 size_t default_message_size,
size_t num_messages)
3077 if (!
inst->app_io) {
3082 if (!
inst->app_io->common.thread_inst_size) {
3083 fr_strerror_const(
"IO modules MUST set 'thread_inst_size' when using the master IO handler.");
3129 if (
inst->dynamic_clients) {
3153 memcpy(child, li,
sizeof(*child));
3163 inst->app_io->common.thread_inst_size);
3167 inst->app_io->common.name);
3186 if (
inst->app_io->open(child) < 0) {
3187 cf_log_err(
inst->app_io_conf,
"Failed opening %s interface",
inst->app_io->common.name);
3209 ERROR(
"Failed opening %s - that port is already in use by another listener in server %s { ... } - %s",
3254 if (
unlikely(!thread))
return NULL;
3266 address->
socket.inet.src_port = src_port;
3267 address->
socket.inet.dst_port = dst_port;
3269 address->
socket.inet.src_ipaddr = *src_ipaddr;
3270 address->
socket.inet.dst_ipaddr = *dst_ipaddr;
3280 .name =
"radius_master_io",
3284 .default_message_size = 4096,
3285 .track_duplicates =
true,
static int const char char buffer[256]
module_t common
Common fields to all loadable modules.
fr_io_track_create_t track_create
create a tracking structure
bool track_duplicates
track duplicate packets
fr_io_name_t get_name
get the socket name
fr_io_track_cmp_t track_compare
compare two tracking structures
Public structure describing an I/O path for a protocol.
#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 CMP_PREFER_LARGER(_a, _b)
Evaluates to -1 for a > b, and +1 for a < b.
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
#define FR_TIME_DELTA_BOUND_CHECK(_name, _var, _op, _bound)
A section grouping multiple CONF_PAIR.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
CONF_SECTION * cf_section_dup(TALLOC_CTX *ctx, CONF_SECTION *parent, CONF_SECTION const *cs, char const *name1, char const *name2, bool copy_meta)
Duplicate a configuration section.
#define cf_log_err(_cf, _fmt,...)
#define cf_log_warn(_cf, _fmt,...)
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
#define fr_event_filter_update(...)
#define FR_EVENT_RESUME(_s, _f)
Re-add the filter for a func from kevent.
#define FR_EVENT_SUSPEND(_s, _f)
Temporarily remove the filter for a func from kevent.
Callbacks for the FR_EVENT_FILTER_IO filter.
Structure describing a modification to a filter's state.
void * fr_hash_table_find(fr_hash_table_t *ht, void const *data)
Find data in a hash table.
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
uint32_t fr_hash(void const *data, size_t size)
bool fr_hash_table_insert(fr_hash_table_t *ht, void const *data)
Insert data into a hash table.
bool fr_hash_table_delete(fr_hash_table_t *ht, void const *data)
Remove and free data (if a free function was specified)
uint32_t fr_hash_table_num_elements(fr_hash_table_t *ht)
#define fr_hash_table_alloc(_ctx, _hash_node, _cmp_node, _free_node)
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
void * fr_heap_pop(fr_heap_t **hp)
Remove a node from the heap.
int fr_heap_extract(fr_heap_t **hp, void *data)
Remove a node from the heap.
unsigned int fr_heap_index_t
static void * fr_heap_peek(fr_heap_t *h)
Return the item from the top of the heap but don't pop it.
#define fr_heap_alloc(_ctx, _cmp, _type, _field, _init)
Creates a heap that can be used with non-talloced elements.
static bool fr_heap_entry_inserted(fr_heap_index_t heap_idx)
Check if an entry is inserted into a heap.
static unsigned int fr_heap_num_elements(fr_heap_t *h)
Return the number of elements in the heap.
#define FR_HEAP_INDEX_INVALID
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port, struct sockaddr_storage const *sa, socklen_t salen)
Convert sockaddr to our internal ip address representation.
int fr_ipaddr_to_sockaddr(struct sockaddr_storage *sa, socklen_t *salen, fr_ipaddr_t const *ipaddr, uint16_t port)
Convert our internal ip address representation to a sockaddr.
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
Zeroes out the host portion of an fr_ipaddr_t.
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
union fr_ipaddr_t::@133 addr
fr_socket_t socket
src/dst ip and port.
fr_client_t const * radclient
old-style client definition
size_t num_messages
for the message ring buffer
char const * name
printable name for this socket - set by open
bool track_duplicates
do we track duplicate packets?
fr_socket_t * app_io_addr
for tracking duplicate sockets
void const * app_instance
size_t default_message_size
copied from app_io, but may be changed
bool connected
is this for a connected socket?
void const * app_io_instance
I/O path configuration context.
CONF_SECTION * server_cs
CONF_SECTION of the server.
void * thread_instance
thread / socket context
int fd
file descriptor for this socket - set by open
fr_app_io_t const * app_io
I/O path functions.
int fr_network_listen_delete(fr_network_t *nr, fr_listen_t *li)
Delete a socket from a network.
int fr_network_listen_inject(fr_network_t *nr, fr_listen_t *li, uint8_t const *packet, size_t packet_len, fr_time_t recv_time)
Inject a packet for a listener to read.
void fr_network_listen_read(fr_network_t *nr, fr_listen_t *li)
Signal the network to read from a listener.
void fr_network_listen_write(fr_network_t *nr, fr_listen_t *li, uint8_t const *packet, size_t packet_len, void *packet_ctx, fr_time_t request_time)
Inject a packet for a listener to write.
char const * server
Name of the virtual server client is associated with.
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
char const * secret
Secret PSK.
bool active
for dynamic clients
fr_ipaddr_t src_ipaddr
IPv4/IPv6 address to send responses from (family must match ipaddr).
char const * nas_type
Type of client (arbitrary).
int proto
Protocol number.
CONF_SECTION * cs
CONF_SECTION that was parsed to generate the client.
bool dynamic
Whether the client was dynamically defined.
char const * longname
Client identifier.
fr_socket_limit_t limit
Connections per client (TCP clients only).
char const * shortname
Client nickname.
bool use_connected
do we use connected sockets for this client
CONF_SECTION * server_cs
Virtual server that the client is associated with.
Describes a host allowed to send packets to the server.
#define RATE_LIMIT_LOCAL(_entry, _log, _fmt,...)
Rate limit messages using a local limiting entry.
Track when a log message was last repeated.
Stores all information relating to an event list.
fr_listen_t * child
The child (app_io) IO path.
fr_network_t * nr
network for this connection
static int8_t alive_client_cmp(void const *one, void const *two)
bool in_trie
is the client in the trie?
static fr_io_pending_packet_t * fr_io_pending_alloc(fr_io_connection_t *connection, fr_io_client_t *client, uint8_t const *buffer, size_t packet_len, fr_io_track_t *track, int priority)
bool paused
event filter doesn't like resuming something that isn't paused
bool in_parent_hash
for tracking thread issues
static fr_client_t * radclient_clone(TALLOC_CTX *ctx, fr_client_t const *parent)
static ssize_t mod_read(fr_listen_t *li, void **packet_ctx, fr_time_t *recv_time_p, uint8_t *buffer, size_t buffer_len, size_t *leftover)
Implement 99% of the read routines.
int packets
number of packets using this connection
uint32_t num_pending_packets
number of pending packets
static int track_dedup_free(fr_io_track_t *track)
fr_rb_tree_t * table
tracking table for packets
static int8_t pending_packet_cmp(void const *one, void const *two)
fr_heap_t * pending_clients
heap of pending clients
static fr_io_track_t * fr_io_track_add(fr_io_client_t *client, fr_io_address_t *address, uint8_t const *packet, size_t packet_len, fr_time_t recv_time, bool *is_dup)
bool ready_to_delete
are we ready to delete this client?
static int _client_live_free(fr_io_client_t *client)
fr_heap_index_t pending_id
for pending clients
static int pending_free(fr_io_pending_packet_t *pending)
bool use_connected
does this client allow connected sub-sockets?
fr_io_client_t * client
our local client (pending or connected).
static int track_free(fr_io_track_t *track)
fr_app_io_t fr_master_app_io
static void packet_expiry_timer(fr_timer_list_t *tl, fr_time_t now, void *uctx)
fr_listen_t * listen
The master IO path.
static int8_t pending_client_cmp(void const *one, void const *two)
fr_io_track_t * fr_master_io_track_alloc(fr_listen_t *li, fr_client_t *radclient, fr_ipaddr_t const *src_ipaddr, int src_port, fr_ipaddr_t const *dst_ipaddr, int dst_port)
fr_io_address_t * address
full information about the connection.
static int8_t address_cmp(void const *one, void const *two)
fr_listen_t * child
child listener (app_io) for this socket
fr_listen_t * listen
master listener for this socket
fr_timer_t * ev
when we clean up the client
fr_network_t * nr
network for the master socket
fr_trie_t * fr_master_io_network(TALLOC_CTX *ctx, int af, fr_ipaddr_t *allow, fr_ipaddr_t *deny)
Create a trie from arrays of allow / deny IP addresses.
static fr_io_pending_packet_t * pending_packet_pop(fr_io_thread_t *thread)
fr_ipaddr_t network
network for dynamic clients
static void mod_event_list_set(fr_listen_t *li, fr_event_list_t *el, void *nr)
Set the event list for a new socket.
static int mod_open(fr_listen_t *li)
Open a new listener.
pthread_mutex_t mutex
for parent / child signaling
static fr_io_client_t * client_alloc(TALLOC_CTX *ctx, fr_io_client_state_t state, fr_io_instance_t const *inst, fr_io_thread_t *thread, fr_client_t *radclient, fr_ipaddr_t const *network)
Allocate a dynamic client.
fr_io_instance_t const * inst
parent instance for master IO handler
#define LOG_IGNORED_CLIENTS(_inst)
fr_trie_t * trie
trie of clients
static void client_expiry_timer(fr_timer_list_t *tl, fr_time_t now, void *uctx)
fr_io_client_state_t
Client states.
@ PR_CLIENT_DYNAMIC
dynamically defined client
@ PR_CLIENT_CONNECTED
dynamically defined client in a connected socket
@ PR_CLIENT_PENDING
dynamic client pending definition
@ PR_CLIENT_NAK
negative cache entry
@ PR_CLIENT_STATIC
static / global clients
static void get_inst(fr_listen_t *li, fr_io_instance_t const **inst, fr_io_thread_t **thread, fr_io_connection_t **connection, fr_listen_t **child)
static fr_event_update_t pause_read[]
static int8_t track_connected_cmp(void const *one, void const *two)
fr_heap_t * alive_clients
heap of active dynamic clients
fr_schedule_t * sc
the scheduler
static fr_io_connection_t * fr_io_connection_alloc(fr_io_instance_t const *inst, fr_io_thread_t *thread, fr_io_client_t *client, int fd, fr_io_address_t *address, fr_io_connection_t *nak)
Create a new connection.
fr_hash_table_t * addresses
list of src/dst addresses used by this client
int fr_master_io_listen(fr_io_instance_t *inst, fr_schedule_t *sc, size_t default_message_size, size_t num_messages)
static int connection_free(fr_io_connection_t *connection)
struct fr_io_thread_t::@38 rate_limit
int fr_io_listen_free(fr_listen_t *li)
char const * name
taken from proto_FOO_TRANSPORT
fr_heap_index_t alive_id
for all clients
fr_event_list_t * el
event list for this connection
fr_io_client_state_t state
state of this client
int packets
number of packets using this client
static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, fr_time_t request_time, uint8_t *buffer, size_t buffer_len, size_t written)
bool dead
roundabout way to get the network side to close a socket
fr_event_list_t * el
event list, for the master socket.
uint64_t client_id
Unique client identifier.
static char const * mod_name(fr_listen_t *li)
module_instance_t * mi
for submodule
static int _client_free(fr_io_client_t *client)
static int mod_close(fr_listen_t *li)
Close the socket.
static uint32_t connection_hash(void const *ctx)
fr_io_connection_t * connection
parent connection
fr_heap_t * pending
pending packets for this client
static int count_connections(UNUSED uint8_t const *key, UNUSED size_t keylen, void *data, void *ctx)
Count the number of connections used by active clients.
static int8_t connection_cmp(void const *one, void const *two)
static int8_t track_cmp(void const *one, void const *two)
fr_hash_table_t * ht
for tracking connected sockets
static int mod_instantiate(module_inst_ctx_t const *mctx)
fr_client_t * radclient
old-style definition of this client
fr_ipaddr_t src_ipaddr
packets come from this address
static fr_event_update_t resume_read[]
static void client_pending_free(fr_io_client_t *client)
uint32_t num_connections
number of dynamic connections
fr_io_client_t * parent
points to the parent client.
static fr_client_t * radclient_alloc(TALLOC_CTX *ctx, int ipproto, fr_io_address_t *address)
static int mod_inject(fr_listen_t *li, uint8_t const *buffer, size_t buffer_len, fr_time_t recv_time)
Inject a packet to a connection.
Client definitions for master IO.
fr_timer_t * ev
when we clean up this tracking entry
uint8_t * reply
reply packet (if any)
int packets
number of packets using this entry
fr_time_t dynamic
timestamp for packet doing dynamic client definition
void * app_io_instance
Easy access to the app_io instance.
fr_app_io_t const * app_io
Easy access to the app_io handle.
fr_io_address_t const * address
of this packet.. shared between multiple packets
bool do_not_respond
don't respond
bool discard
whether or not we discard the packet
fr_time_t timestamp
when this packet was received
bool finished
are we finished the request?
uint8_t * packet
really a tracking structure, not a packet
size_t reply_len
length of reply, or 1 for "do not reply"
fr_io_client_t * client
client handling this packet.
fr_time_t expires
when this packet expires
int fr_nonblock(UNUSED int fd)
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for instantiation calls.
char * fr_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Special version of asprintf which implements custom format specifiers.
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_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
The main red black tree structure.
static unsigned int hash(char const *username, unsigned int tablesize)
fr_network_t * fr_schedule_listen_add(fr_schedule_t *sc, fr_listen_t *li)
Add a fr_listen_t to a scheduler.
CONF_SECTION * conf
Module's instance configuration.
void * data
Module's instance data.
module_instantiate_t instantiate
Callback to allow the module to register any per-instance resources like sockets and file handles.
@ MODULE_INSTANCE_BOOTSTRAPPED
Module instance has been bootstrapped, but not yet instantiated.
size_t thread_inst_size
Size of the module's thread-specific instance data.
fr_time_delta_t idle_timeout
static const uchar sc[16]
module_list_type_t const module_list_type_thread_local
Callbacks for a thread local list.
void module_list_mask_set(module_list_t *ml, module_instance_state_t mask)
Set a new bootstrap/instantiate state for a list.
module_instance_t * module_instance_copy(module_list_t *dst, module_instance_t const *src, char const *inst_name)
Duplicate a module instance, placing it in a new module list.
module_list_t * module_list_alloc(TALLOC_CTX *ctx, module_list_type_t const *type, char const *name, bool write_protect)
Allocate a new module list.
int module_thread_instantiate(TALLOC_CTX *ctx, module_instance_t *mi, fr_event_list_t *el)
Allocate thread-local instance data for a module.
int module_instantiate(module_instance_t *instance)
Manually complete module setup by calling its instantiate function.
int module_instance_conf_parse(module_instance_t *mi, CONF_SECTION *conf)
Covert a CONF_SECTION into parsed module instance data.
eap_aka_sim_process_conf_t * inst
#define fr_time()
Allow us to arbitrarily manipulate time.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define talloc_get_type_abort_const
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
static int talloc_const_free(void const *ptr)
Free const'd memory.
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
#define fr_time_delta_lt(_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_delta_wrap(_time)
#define fr_time_wrap(_time)
#define fr_time_delta_ispos(_a)
#define fr_time_eq(_a, _b)
#define fr_time_add(_a, _b)
Add a time/time delta together.
#define fr_time_neq(_a, _b)
A time delta, a difference in time measured in nanoseconds.
#define fr_timer_armed(_ev)
#define FR_TIMER_DELETE(_ev_p)
#define FR_TIMER_DELETE_RETURN(_ev_p)
#define FR_TIMER_DISARM(_ev)
void * fr_trie_remove_by_key(fr_trie_t *ft, void const *key, size_t keylen)
Remove a key and return the associated user ctx.
fr_trie_t * fr_trie_alloc(TALLOC_CTX *ctx, fr_trie_key_t get_key, fr_free_t free_data)
Allocate a trie.
int fr_trie_walk(fr_trie_t *ft, void *ctx, fr_trie_walk_t callback)
void * fr_trie_lookup_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Lookup a key in a trie and return user ctx, if any.
void * fr_trie_match_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Match a key and length in a trie and return user ctx, if any.
int fr_trie_insert_by_key(fr_trie_t *ft, void const *key, size_t keylen, void const *data)
Insert a key and user ctx into a trie.
static fr_event_list_t * el
int fd
File descriptor if this is a live socket.
int type
SOCK_STREAM, SOCK_DGRAM, etc.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
static fr_slen_t fr_value_box_aprint(TALLOC_CTX *ctx, char **out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules) 1(fr_value_box_print
#define fr_box_ipaddr(_val)
#define fr_box_time_delta(_val)
bool listen_record(fr_listen_t *li)
Record that we're listening on a particular IP / port.
fr_listen_t * listen_find_any(fr_listen_t *li)
See if another global listener is using a particular IP / port.