The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
bio.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 1f8fdfb7af86205d07f804de194f1c1ce27b3da8 $
19 * @file src/modules/rlm_radius/bio.c
20 * @brief RADIUS BIO transport
21 *
22 * @copyright 2017 Network RADIUS SAS
23 * @copyright 2020 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 */
25
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>
34
35#include <sys/socket.h>
36
37//#include "rlm_radius.h"
38#include "track.h"
39
40typedef struct {
41 char const *module_name; //!< the module that opened the connection
42 rlm_radius_t const *inst; //!< our instance
43 fr_event_list_t *el; //!< Event list.
44 trunk_t *trunk; //!< trunk handler
45 fr_bio_fd_config_t fd_config; //!< for threads or sockets
46 fr_bio_fd_info_t const *fd_info; //!< status of the FD.
49
50typedef struct {
51 bio_handle_ctx_t ctx; //!< common struct for home servers and BIO handles
52
53 struct {
54 fr_bio_t *fd; //!< writing
55 uint32_t id; //!< for replication
56 fr_rb_expire_t expires; //!< for proxying / client sending
57 } bio;
59
61
62/** Track the handle, which is tightly correlated with the FD
63 *
64 */
65typedef struct {
66 bio_handle_ctx_t ctx; //!< common struct for home servers and BIO handles
67
68 int fd; //!< File descriptor.
69
70 struct {
71 fr_bio_t *read; //!< what we use for input
72 fr_bio_t *write; //!< what we use for output
73 fr_bio_t *fd; //!< raw FD
74 fr_bio_t *mem; //!< memory wrappers for stream sockets
75 } bio;
76
78
79 uint8_t last_id; //!< Used when replicating to ensure IDs are distributed
80 ///< evenly.
81
82 uint32_t max_packet_size; //!< Our max packet size. may be different from the parent.
83
84 uint8_t *buffer; //!< Receive buffer.
85 size_t buflen; //!< Receive buffer length.
86
87 radius_track_t *tt; //!< RADIUS ID tracking structure.
88
89 fr_time_t mrs_time; //!< Most recent sent time which had a reply.
90 fr_time_t last_reply; //!< When we last received a reply.
91 fr_time_t first_sent; //!< first time we sent a packet since going idle
92 fr_time_t last_sent; //!< last time we sent a packet.
93 fr_time_t last_idle; //!< last time we had nothing to do
94
95 fr_timer_t *zombie_ev; //!< Zombie timeout.
96
97 bool status_checking; //!< whether we're doing status checks
98 bio_request_t *status_u; //!< for sending status check packets
101
102
103/** Connect request_t to local tracking structure
104 *
105 */
108 rlm_rcode_t rcode; //!< from the transport
110
111 uint32_t priority; //!< copied from request->async->priority
112 fr_time_t recv_time; //!< copied from request->async->recv_time
113
114 uint32_t num_replies; //!< number of reply packets, sent is in retry.count
115
116 bool status_check; //!< is this packet a status check?
117 bool proxied; //!< is this request being proxied
118
119 fr_pair_list_t extra; //!< VPs for debugging, like Proxy-State.
120
121 uint8_t code; //!< Packet code.
122 uint8_t id; //!< Last ID assigned to this packet.
123 uint8_t *packet; //!< Packet we write to the network.
124 size_t packet_len; //!< Length of the packet.
125 size_t partial; //!< partially sent data
126
127 radius_track_entry_t *rr; //!< ID tracking, resend count, etc.
128 fr_timer_t *ev; //!< timer for retransmissions
129 fr_retry_t retry; //!< retransmission timers
130};
131
132typedef struct {
133 bio_handle_ctx_t ctx; //!< for copying to bio_handle_t
134
137
138/** Turn a reply code into a module rcode;
139 *
140 */
156
158 UNUSED int flags, void *uctx);
159
160static int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id);
161
162static fr_radius_decode_fail_t decode(TALLOC_CTX *ctx, fr_pair_list_t *reply, uint8_t *response_code,
163 bio_handle_t *h, request_t *request, bio_request_t *u,
164 uint8_t const request_authenticator[static RADIUS_AUTH_VECTOR_LENGTH],
165 uint8_t *data, size_t data_len);
166
168
169static void mod_write(request_t *request, trunk_request_t *treq, bio_handle_t *h);
170
171static int _bio_request_free(bio_request_t *u);
172
173static int8_t home_server_cmp(void const *one, void const *two);
174
175#ifndef NDEBUG
176/** Log additional information about a tracking entry
177 *
178 * @param[in] te Tracking entry we're logging information for.
179 * @param[in] log destination.
180 * @param[in] log_type Type of log message.
181 * @param[in] file the logging request was made in.
182 * @param[in] line logging request was made on.
183 */
184static void bio_tracking_entry_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line,
186{
187 request_t *request;
188
189 if (!te->request) return; /* Free entry */
190
191 request = talloc_get_type_abort(te->request, request_t);
192
193 fr_log(log, log_type, file, line, "request %s, allocated %s:%d", request->name,
194 request->alloc_file, request->alloc_line);
195
196 trunk_request_state_log(log, log_type, file, line, talloc_get_type_abort(te->uctx, trunk_request_t));
197}
198#endif
199
200/** Clear out any connection specific resources from a udp request
201 *
202 */
204{
205 TALLOC_FREE(u->packet);
207
208 /*
209 * Can have packet put no u->rr
210 * if this is part of a pre-trunk status check.
211 */
212 if (u->rr) radius_track_entry_release(&u->rr);
213
215}
216
217/** Reset a status_check packet, ready to reuse
218 *
219 */
221{
222 fr_assert(u->status_check == true);
223
224 h->status_checking = false;
225 u->num_replies = 0; /* Reset */
226 u->retry.start = fr_time_wrap(0);
227
229
231}
232
233/*
234 * Status-Server checks. Manually build the packet, and
235 * all of its associated glue.
236 */
238{
239 bio_request_t *u;
240 request_t *request;
241 rlm_radius_t const *inst = h->ctx.inst;
242 map_t *map = NULL;
243
245
246 MEM(request = request_local_alloc_external(h, (&(request_init_args_t){ .namespace = dict_radius })));
247 MEM(u = talloc_zero(request, bio_request_t));
248 talloc_set_destructor(u, _bio_request_free);
249
250 h->status_u = u;
251
252 h->status_request = request;
254
255 /*
256 * Status checks are prioritized over any other packet
257 */
258 u->priority = ~(uint32_t) 0;
259 u->status_check = true;
260
261 /*
262 * Allocate outside of the free list.
263 * There appears to be an issue where
264 * the thread destructor runs too
265 * early, and frees the freelist's
266 * head before the module destructor
267 * runs.
268 */
269 request->async = talloc_zero(request, fr_async_t);
270 talloc_const_free(request->name);
271 request->name = talloc_strdup(request, h->ctx.module_name);
272
273 request->packet = fr_packet_alloc(request, false);
274 request->reply = fr_packet_alloc(request, false);
275
276 /*
277 * Create the VPs, and ignore any errors
278 * creating them.
279 */
280 while ((map = map_list_next(&inst->status_check_map, map))) {
281 (void) map_to_request(request, map, map_to_vp, NULL);
282 }
283
284 /*
285 * Ensure that there's a NAS-Identifier, if one wasn't
286 * already added.
287 */
288 if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_nas_identifier)) {
289 fr_pair_t *vp;
290
292 fr_pair_value_strdup(vp, "status check - are you alive?", false);
293 }
294
295 /*
296 * Always add an Event-Timestamp, which will be the time
297 * at which the first packet is sent. Or for
298 * Status-Server, the time of the current packet.
299 */
300 if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_event_timestamp)) {
302 }
303
304 /*
305 * Initialize the request IO ctx. Note that we don't set
306 * destructors.
307 */
308 u->code = inst->status_check;
309 request->packet->code = u->code;
310
311 DEBUG3("%s - Status check packet type will be %s", h->ctx.module_name, fr_radius_packet_name[u->code]);
312 log_request_pair_list(L_DBG_LVL_3, request, NULL, &request->request_pairs, NULL);
313}
314
315/** Connection errored
316 *
317 * We were signalled by the event loop that a fatal error occurred on this connection.
318 *
319 * @param[in] el The event list signalling.
320 * @param[in] fd that errored.
321 * @param[in] flags El flags.
322 * @param[in] fd_errno The nature of the error.
323 * @param[in] uctx The trunk connection handle (tconn).
324 */
325static void conn_init_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
326{
327 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
328 bio_handle_t *h;
329
330 /*
331 * Connection must be in the connecting state when this fires
332 */
334
335 h = talloc_get_type_abort(conn->h, bio_handle_t);
336
337 ERROR("%s - Connection %s failed: %s", h->ctx.module_name, h->ctx.fd_info->name, fr_syserror(fd_errno));
338
340}
341
342/** Status check timer when opening the connection for the first time.
343 *
344 * Setup retries, or fail the connection.
345 */
346static void conn_init_timeout(UNUSED fr_timer_list_t *tl, fr_time_t now, void *uctx)
347{
348 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
349 bio_handle_t *h;
350 bio_request_t *u;
351
352 /*
353 * Connection must be in the connecting state when this fires
354 */
356
357 h = talloc_get_type_abort(conn->h, bio_handle_t);
358 u = h->status_u;
359
360 /*
361 * We're only interested in contiguous, good, replies.
362 */
363 u->num_replies = 0;
364
365 switch (fr_retry_next(&u->retry, now)) {
366 case FR_RETRY_MRD:
367 DEBUG("%s - Reached maximum_retransmit_duration (%pVs > %pVs), failing status checks",
370 goto fail;
371
372 case FR_RETRY_MRC:
373 DEBUG("%s - Reached maximum_retransmit_count (%u > %u), failing status checks",
375 fail:
377 return;
378
380 if (fr_event_fd_insert(h, NULL, conn->el, h->fd, conn_init_writable, NULL,
381 conn_init_error, conn) < 0) {
382 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
384 }
385 return;
386 }
387
388 fr_assert(0);
389}
390
391/** Perform the next step of init and negotiation.
392 *
393 */
394static void conn_init_next(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
395{
396 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
397 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
398
399 if (fr_event_fd_insert(h, NULL, conn->el, h->fd, conn_init_writable, NULL, conn_init_error, conn) < 0) {
400 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
402 }
403}
404
405/** Read the connection during the init and negotiation stage.
406 *
407 */
408static void conn_init_readable(fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
409{
410 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
411 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
412 trunk_t *trunk = h->ctx.trunk;
413 rlm_radius_t const *inst = h->ctx.inst;
414 bio_request_t *u = h->status_u;
415 ssize_t slen;
416 fr_pair_list_t reply;
417 uint8_t code = 0;
418
419 fr_pair_list_init(&reply);
420 slen = fr_bio_read(h->bio.read, NULL, h->buffer, h->buflen);
421 if (slen == 0) {
422 /*
423 * @todo - set BIO FD EOF callback, so that we don't have to check it here.
424 */
425 if (h->ctx.fd_info->eof) goto failed;
426 return;
427 }
428
429 /*
430 * We're done reading, return.
431 */
432 if (slen == fr_bio_error(IO_WOULD_BLOCK)) return;
433
434 if (slen < 0) {
435 switch (errno) {
436 case ECONNREFUSED:
437 ERROR("%s - Failed reading response from socket: there is no server listening on outgoing connection %s",
438 h->ctx.module_name, h->ctx.fd_info->name);
439 break;
440
441 default:
442 ERROR("%s - Failed reading response from socket: %s",
443 h->ctx.module_name, fr_syserror(errno));
444 break;
445 }
446
447 failed:
449 return;
450 }
451
452 /*
453 * Where we just return in this function, we're letting
454 * the response timer take care of progressing the
455 * connection attempt.
456 */
457 fr_assert(slen >= RADIUS_HEADER_LENGTH); /* checked in verify */
458
459 if (u->id != h->buffer[1]) {
460 ERROR("%s - Received response with incorrect or expired ID. Expected %u, got %u",
461 h->ctx.module_name, u->id, h->buffer[1]);
462 return;
463 }
464
465 if (decode(h, &reply, &code,
467 h->buffer, slen) != DECODE_FAIL_NONE) return;
468
469 fr_pair_list_free(&reply); /* FIXME - Do something with these... */
470
471 /*
472 * Process the error, and count this as a success.
473 * This is usually used for dynamic configuration
474 * on startup.
475 */
477
478 /*
479 * Last trunk event was a failure, be more careful about
480 * bringing up the connection (require multiple responses).
481 */
482 if ((fr_time_gt(trunk->last_failed, fr_time_wrap(0)) && (fr_time_gt(trunk->last_failed, trunk->last_connected))) &&
483 (u->num_replies < inst->num_answers_to_alive)) {
484 /*
485 * Leave the timer in place. This timer is BOTH when we
486 * give up on the current status check, AND when we send
487 * the next status check.
488 */
489 DEBUG("%s - Received %u / %u replies for status check, on connection - %s",
490 h->ctx.module_name, u->num_replies, inst->num_answers_to_alive, h->ctx.fd_info->name);
491 DEBUG("%s - Next status check packet will be in %pVs",
493
494 /*
495 * Set the timer for the next retransmit.
496 */
497 if (fr_timer_at(h, el->tl, &u->ev, u->retry.next, false, conn_init_next, conn) < 0) {
499 }
500 return;
501 }
502
503 /*
504 * It's alive!
505 */
506 status_check_reset(h, u);
507
508 DEBUG("%s - Connection open - %s", h->ctx.module_name, h->ctx.fd_info->name);
509
511}
512
513/** Send initial negotiation.
514 *
515 */
516static void conn_init_writable(fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
517{
518 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
519 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
520 bio_request_t *u = h->status_u;
521 ssize_t slen;
522
523 if (fr_time_eq(u->retry.start, fr_time_wrap(0))) {
524 u->id = fr_rand() & 0xff; /* We don't care what the value is here */
525 h->status_checking = true; /* Ensure this is valid */
526 fr_retry_init(&u->retry, fr_time(), &h->ctx.inst->retry[u->code]);
527
528 /*
529 * Status checks can never be retransmitted
530 * So increment the ID here.
531 */
532 } else {
534 u->id++;
535 }
536
537 DEBUG("%s - Sending %s ID %d over connection %s",
539
540 if (encode(h, h->status_request, u, u->id) < 0) {
541 fail:
543 return;
544 }
545 DEBUG3("Encoded packet");
546 HEXDUMP3(u->packet, u->packet_len, NULL);
547
548 fr_assert(u->packet != NULL);
550
551 slen = fr_bio_write(h->bio.write, NULL, u->packet, u->packet_len);
552
553 if (slen == fr_bio_error(IO_WOULD_BLOCK)) goto blocked;
554
555 if (slen < 0) {
556 ERROR("%s - Failed sending %s ID %d length %zu over connection %s: %s",
558
559
560 goto fail;
561 }
562
563 /*
564 * @todo - handle partial packets and blocked writes.
565 */
566 if ((size_t)slen < u->packet_len) {
567 blocked:
568 ERROR("%s - Failed sending %s ID %d length %zu over connection %s: writing is blocked",
570 goto fail;
571 }
572
573 /*
574 * Switch to waiting on read and insert the event
575 * for the response timeout.
576 */
577 if (fr_event_fd_insert(h, NULL, conn->el, h->fd, conn_init_readable, NULL, conn_init_error, conn) < 0) {
578 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
579 goto fail;
580 }
581
582 DEBUG("%s - %s request. Expecting response within %pVs",
583 h->ctx.module_name, (u->retry.count == 1) ? "Originated" : "Retransmitted",
585
586 if (fr_timer_at(h, el->tl, &u->ev, u->retry.next, false, conn_init_timeout, conn) < 0) {
587 PERROR("%s - Failed inserting timer event", h->ctx.module_name);
588 goto fail;
589 }
590
591 /*
592 * Save a copy of the header + Authentication Vector for checking the response.
593 */
594 MEM(u->packet = talloc_memdup(u, u->packet, RADIUS_HEADER_LENGTH));
595}
596
597/** Free a connection handle, closing associated resources
598 *
599 */
601{
602 fr_assert(h != NULL);
603
604 fr_assert(h->fd >= 0);
605
607
608 /*
609 * The connection code will take care of deleting the FD from the event loop.
610 */
611
612 DEBUG("%s - Connection closed - %s", h->ctx.module_name, h->ctx.fd_info->name);
613
614 return 0;
615}
616
617static void bio_connected(fr_bio_t *bio)
618{
619 bio_handle_t *h = bio->uctx;
620
621 DEBUG("%s - Connection open - %s", h->ctx.module_name, h->ctx.fd_info->name);
622
624}
625
626static void bio_error(fr_bio_t *bio)
627{
628 bio_handle_t *h = bio->uctx;
629
630 DEBUG("%s - Connection failed - %s - %s", h->ctx.module_name, h->ctx.fd_info->name,
632
634}
635
636static 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)
637{
639 size_t in_buffer = *size;
640 bio_handle_t *h = verify_ctx;
641 uint8_t const *hdr = data;
642 size_t want;
643
644 if (in_buffer < 20) {
645 *size = RADIUS_HEADER_LENGTH;
647 }
648
649 /*
650 * Packet is too large, discard it.
651 */
652 want = fr_nbo_to_uint16(hdr + 2);
653 if (want > h->ctx.inst->max_packet_size) {
654 ERROR("%s - Connection %s received too long packet", h->ctx.module_name, h->ctx.fd_info->name);
656 }
657
658 /*
659 * Not a full packet, we want more data.
660 */
661 if (want < *size) {
662 *size = want;
664 }
665
666#define REQUIRE_MA(_h) (((_h)->ctx.inst->require_message_authenticator == FR_RADIUS_REQUIRE_MA_YES) || *(_h)->ctx.inst->received_message_authenticator)
667
668 /*
669 * See if we need to discard the packet.
670 *
671 * @todo - rate limit these messages, and find a way to associate them with a request, or even
672 * the logging destination of the module.
673 */
674 if (!fr_radius_ok(data, size, h->ctx.inst->max_attributes, REQUIRE_MA(h), &failure)) {
676
677 PERROR("%s - Connection %s received bad packet", h->ctx.module_name, h->ctx.fd_info->name);
678
679 if (failure == DECODE_FAIL_MA_MISSING) {
681 ERROR("We are configured with 'require_message_authenticator = true'");
682 } else {
683 ERROR("We previously received a packet from this client which included a Message-Authenticator attribute");
684 }
685 }
686
687 if (h->ctx.fd_config.socket_type == SOCK_DGRAM) return FR_BIO_VERIFY_DISCARD;
688
690 }
691
692 /*
693 * @todo - check if the reply is allowed. Bad replies are discarded later, but it might be worth
694 * checking them here.
695 */
696
697 /*
698 * On input, *size is how much data we have. On output, *size is how much data we want.
699 */
700 return (in_buffer >= *size) ? FR_BIO_VERIFY_OK : FR_BIO_VERIFY_WANT_MORE;
701}
702
703
704/** Initialise a new outbound connection
705 *
706 * @param[out] h_out Where to write the new file descriptor.
707 * @param[in] conn to initialise.
708 * @param[in] uctx A #bio_thread_t
709 */
710CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
711static connection_state_t conn_init(void **h_out, connection_t *conn, void *uctx)
712{
713 int fd;
714 bio_handle_t *h;
715 bio_handle_ctx_t *ctx = uctx; /* thread or home server */
716
717 MEM(h = talloc_zero(conn, bio_handle_t));
718 h->ctx = *ctx;
719 h->conn = conn;
721 h->last_idle = fr_time();
722
723 MEM(h->buffer = talloc_array(h, uint8_t, h->max_packet_size));
724 h->buflen = h->max_packet_size;
725
726 MEM(h->tt = radius_track_alloc(h));
727
728 h->bio.fd = fr_bio_fd_alloc(h, &h->ctx.fd_config, 0);
729 if (!h->bio.fd) {
730 PERROR("%s - failed opening socket", h->ctx.module_name);
731 fail:
732 talloc_free(h);
734 }
735
736 h->bio.fd->uctx = h;
738
739 fd = h->ctx.fd_info->socket.fd;
740 fr_assert(fd >= 0);
741
742 /*
743 * Create a memory BIO for stream sockets. We want to return only complete packets, and not
744 * partial packets.
745 *
746 * @todo - maybe we want to have a fr_bio_verify_t which is independent of fr_bio_mem_t. That
747 * way we don't need a memory BIO for UDP sockets, but we can still add a verification layer for
748 * UDP sockets?
749 */
750 h->bio.mem = fr_bio_mem_alloc(h, (h->ctx.fd_config.socket_type == SOCK_DGRAM) ? 0 : h->ctx.inst->max_packet_size * 4,
751 0, h->bio.fd);
752 if (!h->bio.mem) {
753 PERROR("%s - Failed allocating memory buffer - ", h->ctx.module_name);
754 goto fail;
755 }
756
757 if (fr_bio_mem_set_verify(h->bio.mem, rlm_radius_verify, h, (h->ctx.fd_config.socket_type == SOCK_DGRAM)) < 0) {
758 PERROR("%s - Failed setting validation callback - ", h->ctx.module_name);
759 goto fail;
760 }
761
762 /*
763 * Set the BIO read function to be the memory BIO, which will then call the packet verification
764 * routine.
765 */
766 h->bio.read = h->bio.write = h->bio.mem;
767 h->bio.mem->uctx = h;
768
769 h->fd = fd;
770
771 talloc_set_destructor(h, _bio_handle_free);
772
773 /*
774 * If the socket isn't connected, then do that first.
775 */
777 int rcode;
778
780
781 /*
782 * We don't pass timeouts here because the trunk has it's own connection timeouts.
783 */
784 rcode = fr_bio_fd_connect_full(h->bio.fd, conn->el, bio_connected, bio_error, NULL, NULL);
785 if (rcode < 0) goto fail;
786
787 *h_out = h;
788
789 if (rcode == 0) return CONNECTION_STATE_CONNECTING;
790
791 fr_assert(rcode == 1);
793
794 /*
795 * If we're doing status checks, then we want at least
796 * one positive response before signalling that the
797 * connection is open.
798 *
799 * To do this we install special I/O handlers that
800 * only signal the connection as open once we get a
801 * status-check response.
802 */
803 } if (h->ctx.inst->status_check) {
805
806 /*
807 * Start status checking.
808 *
809 * If we've had no recent failures we need exactly
810 * one response to bring the connection online,
811 * otherwise we need inst->num_answers_to_alive
812 */
813 if (fr_event_fd_insert(h, NULL, conn->el, h->fd, NULL,
814 conn_init_writable, conn_init_error, conn) < 0) goto fail;
815
816 /*
817 * If we're not doing status-checks, signal the connection
818 * as open as soon as it becomes writable.
819 */
820 } else {
821 connection_signal_on_fd(conn, fd);
822 }
823
824 *h_out = h;
825
827}
828
829/** Shutdown/close a file descriptor
830 *
831 */
832static void conn_close(UNUSED fr_event_list_t *el, void *handle, UNUSED void *uctx)
833{
834 bio_handle_t *h = talloc_get_type_abort(handle, bio_handle_t);
835
836 /*
837 * There's tracking entries still allocated
838 * this is bad, they should have all been
839 * released.
840 */
841 if (h->tt && (h->tt->num_requests != 0)) {
842#ifndef NDEBUG
844#endif
845 fr_assert_fail("%u tracking entries still allocated at conn close", h->tt->num_requests);
846 }
847
848 fr_bio_shutdown(h->bio.mem);
849
850 DEBUG4("Freeing handle %p", handle);
851
852 talloc_free(h);
853}
854
855/** Connection failed
856 *
857 * @param[in] handle of connection that failed.
858 * @param[in] state the connection was in when it failed.
859 * @param[in] uctx UNUSED.
860 */
861static connection_state_t conn_failed(void *handle, connection_state_t state, UNUSED void *uctx)
862{
863 switch (state) {
864 /*
865 * If the connection was connected when it failed,
866 * we need to handle any outstanding packets and
867 * timer events before reconnecting.
868 */
870 {
871 bio_handle_t *h = talloc_get_type_abort(handle, bio_handle_t); /* h only available if connected */
872
873 /*
874 * Reset the Status-Server checks.
875 */
876 if (h->status_u) FR_TIMER_DISARM(h->status_u->ev);
877 break;
878
879 default:
880 break;
881 }
882 }
883
885}
886
887CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
889 connection_conf_t const *conf,
890 char const *log_prefix, void *uctx)
891{
892 connection_t *conn;
893 bio_handle_ctx_t *ctx = uctx; /* thread or home server */
894
895 conn = connection_alloc(tconn, el,
897 .init = conn_init,
898 .close = conn_close,
899 .failed = conn_failed
900 },
901 conf,
902 log_prefix,
903 uctx);
904 if (!conn) {
905 PERROR("%s - Failed allocating state handler for new connection", ctx->inst->name);
906 return NULL;
907 }
908 ctx->trunk = tconn->trunk;
909 ctx->module_name = log_prefix;
910
911 return conn;
912}
913
914/** Read and discard data
915 *
916 */
917static void conn_discard(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
918{
919 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
920 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
921 uint8_t buffer[4096];
922 ssize_t slen;
923
924 while ((slen = fr_bio_read(h->bio.read, NULL, buffer, sizeof(buffer))) > 0);
925
926 if (slen < 0) {
927 switch (errno) {
928 case EBADF:
929 case ECONNRESET:
930 case ENOTCONN:
931 case ETIMEDOUT:
932 ERROR("%s - Failed draining socket: %s", h->ctx.module_name, fr_syserror(errno));
934 break;
935
936 default:
937 break;
938 }
939 }
940}
941
942/** Connection errored
943 *
944 * We were signalled by the event loop that a fatal error occurred on this connection.
945 *
946 * @param[in] el The event list signalling.
947 * @param[in] fd that errored.
948 * @param[in] flags El flags.
949 * @param[in] fd_errno The nature of the error.
950 * @param[in] uctx The trunk connection handle (tconn).
951 */
952static void conn_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
953{
954 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
955 connection_t *conn = tconn->conn;
956 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
957
958 ERROR("%s - Connection %s failed: %s", h->ctx.module_name, h->ctx.fd_info->name, fr_syserror(fd_errno));
959
961}
962
963CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
966 trunk_connection_event_t notify_on, UNUSED void *uctx)
967{
968 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
969 fr_event_fd_cb_t read_fn = NULL;
970 fr_event_fd_cb_t write_fn = NULL;
971
972 switch (notify_on) {
973 /*
974 * We may have sent multiple requests to the
975 * other end, so it might be sending us multiple
976 * replies. We want to drain the socket, instead
977 * of letting the packets sit in the UDP receive
978 * queue.
979 */
981 read_fn = conn_discard;
982 break;
983
986 break;
987
990 break;
991
995 break;
996
997 }
998
999 /*
1000 * Over-ride read for replication.
1001 */
1003 read_fn = conn_discard;
1004
1005 if (fr_bio_fd_write_only(h->bio.fd) < 0) {
1006 PERROR("%s - Failed setting socket to write-only", h->ctx.module_name);
1008 return;
1009 }
1010 }
1011
1012 if (fr_event_fd_insert(h, NULL, el, h->fd,
1013 read_fn,
1014 write_fn,
1015 conn_error,
1016 tconn) < 0) {
1017 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
1018
1019 /*
1020 * May free the connection!
1021 */
1023 }
1024}
1025
1026/*
1027 * Return negative numbers to put 'a' at the top of the heap.
1028 * Return positive numbers to put 'b' at the top of the heap.
1029 *
1030 * We want the value with the lowest timestamp to be prioritized at
1031 * the top of the heap.
1032 */
1033static int8_t request_prioritise(void const *one, void const *two)
1034{
1035 bio_request_t const *a = one;
1036 bio_request_t const *b = two;
1037 int8_t ret;
1038
1039 /*
1040 * Prioritise status check packets
1041 */
1042 ret = (b->status_check - a->status_check);
1043 if (ret != 0) return ret;
1044
1045 /*
1046 * Larger priority is more important.
1047 */
1048 ret = CMP(a->priority, b->priority);
1049 if (ret != 0) return ret;
1050
1051 /*
1052 * Smaller timestamp (i.e. earlier) is more important.
1053 */
1055}
1056
1057/** Decode response packet data, extracting relevant information and validating the packet
1058 *
1059 * @param[in] ctx to allocate pairs in.
1060 * @param[out] reply Pointer to head of pair list to add reply attributes to.
1061 * @param[out] response_code The type of response packet.
1062 * @param[in] h connection handle.
1063 * @param[in] request the request.
1064 * @param[in] u UDP request.
1065 * @param[in] request_authenticator from the original request.
1066 * @param[in] data to decode.
1067 * @param[in] data_len Length of input data.
1068 * @return
1069 * - DECODE_FAIL_NONE on success.
1070 * - DECODE_FAIL_* on failure.
1071 */
1072static fr_radius_decode_fail_t decode(TALLOC_CTX *ctx, fr_pair_list_t *reply, uint8_t *response_code,
1073 bio_handle_t *h, request_t *request, bio_request_t *u,
1074 uint8_t const request_authenticator[static RADIUS_AUTH_VECTOR_LENGTH],
1075 uint8_t *data, size_t data_len)
1076{
1078 uint8_t code;
1079 fr_radius_decode_ctx_t decode_ctx;
1080
1081 *response_code = 0; /* Initialise to keep the rest of the code happy */
1082
1083 RHEXDUMP3(data, data_len, "Read packet");
1084
1085 decode_ctx = (fr_radius_decode_ctx_t) {
1086 .common = &h->ctx.radius_ctx,
1087 .request_code = u->code,
1088 .request_authenticator = request_authenticator,
1089 .tmp_ctx = talloc(ctx, uint8_t),
1090 .end = data + data_len,
1091 .verify = true,
1092 .require_message_authenticator = REQUIRE_MA(h),
1093 };
1094
1095 if (fr_radius_decode(ctx, reply, data, data_len, &decode_ctx) < 0) {
1096 talloc_free(decode_ctx.tmp_ctx);
1097 RPEDEBUG("Failed reading packet");
1098 return DECODE_FAIL_UNKNOWN;
1099 }
1100 talloc_free(decode_ctx.tmp_ctx);
1101
1102 code = data[0];
1103
1104 RDEBUG("Received %s ID %d length %zu reply packet on connection %s",
1105 fr_radius_packet_name[code], data[1], data_len, h->ctx.fd_info->name);
1106 log_request_pair_list(L_DBG_LVL_2, request, NULL, reply, NULL);
1107
1108 /*
1109 * This code is for BlastRADIUS mitigation.
1110 *
1111 * The scenario where this applies is where we send Message-Authenticator
1112 * but the home server doesn't support it or require it, in which case
1113 * the response can be manipulated by an attacker.
1114 */
1115 if ((u->code == FR_RADIUS_CODE_ACCESS_REQUEST) &&
1116 (inst->require_message_authenticator == FR_RADIUS_REQUIRE_MA_AUTO) &&
1117 !*(inst->received_message_authenticator) &&
1118 fr_pair_find_by_da(&request->request_pairs, NULL, attr_message_authenticator) &&
1119 !fr_pair_find_by_da(&request->request_pairs, NULL, attr_eap_message)) {
1120 RINFO("Packet contained a valid Message-Authenticator. Setting \"require_message_authenticator = yes\"");
1121 *(inst->received_message_authenticator) = true;
1122 }
1123
1124 *response_code = code;
1125
1126 /*
1127 * Record the fact we've seen a response
1128 */
1129 u->num_replies++;
1130
1131 /*
1132 * Fixup retry times
1133 */
1134 if (fr_time_gt(u->retry.start, h->mrs_time)) h->mrs_time = u->retry.start;
1135
1136 return DECODE_FAIL_NONE;
1137}
1138
1139static int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id)
1140{
1141 ssize_t packet_len;
1143 rlm_radius_t const *inst = h->ctx.inst;
1144
1145 fr_assert(inst->allowed[u->code]);
1146 fr_assert(!u->packet);
1147
1148 u->packet_len = inst->max_packet_size;
1149 u->packet = h->buffer;
1150
1151 /*
1152 * We should have at minimum 64-byte packets, so don't
1153 * bother doing run-time checks here.
1154 */
1156
1158 .common = &h->ctx.radius_ctx,
1159 .rand_ctx = (fr_fast_rand_t) {
1160 .a = fr_rand(),
1161 .b = fr_rand(),
1162 },
1163 .code = u->code,
1164 .id = id,
1165 .add_proxy_state = u->proxied,
1166 };
1167
1168 /*
1169 * If we're sending a status check packet, update any
1170 * necessary timestamps. Also, don't add Proxy-State, as
1171 * we're originating the packet.
1172 */
1173 if (u->status_check) {
1174 fr_pair_t *vp;
1175
1176 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_event_timestamp);
1177 if (vp) vp->vp_date = fr_time_to_unix_time(u->retry.updated);
1178
1179 encode_ctx.add_proxy_state = false;
1180 }
1181
1182 /*
1183 * Encode it, leaving room for Proxy-State if necessary.
1184 */
1185 packet_len = fr_radius_encode(&FR_DBUFF_TMP(u->packet, u->packet_len),
1186 &request->request_pairs, &encode_ctx);
1187 if (fr_pair_encode_is_error(packet_len)) {
1188 RPERROR("Failed encoding packet");
1189
1190 error:
1191 TALLOC_FREE(u->packet);
1192 return -1;
1193 }
1194
1195 if (packet_len < 0) {
1196 size_t have;
1197 size_t need;
1198
1199 have = u->packet_len;
1200 need = have - packet_len;
1201
1202 if (need > RADIUS_MAX_PACKET_SIZE) {
1203 RERROR("Failed encoding packet. Have %zu bytes of buffer, need %zu bytes",
1204 have, need);
1205 } else {
1206 RERROR("Failed encoding packet. Have %zu bytes of buffer, need %zu bytes. "
1207 "Increase 'max_packet_size'", have, need);
1208 }
1209
1210 goto error;
1211 }
1212 /*
1213 * The encoded packet should NOT over-run the input buffer.
1214 */
1215 fr_assert((size_t) packet_len <= u->packet_len);
1216
1217 /*
1218 * Add Proxy-State to the tail end of the packet.
1219 *
1220 * We need to add it here, and NOT in
1221 * request->request_pairs, because multiple modules
1222 * may be sending the packets at the same time.
1223 */
1224 if (encode_ctx.add_proxy_state) {
1225 fr_pair_t *vp;
1226
1228 fr_pair_value_memdup(vp, (uint8_t const *) &inst->common_ctx.proxy_state, sizeof(inst->common_ctx.proxy_state), false);
1229 fr_pair_append(&u->extra, vp);
1230 packet_len += 2 + sizeof(inst->common_ctx.proxy_state);
1231 }
1232
1233 /*
1234 * Update our version of the packet length.
1235 */
1236 u->packet_len = packet_len;
1237
1238 /*
1239 * Now that we're done mangling the packet, sign it.
1240 */
1241 if (fr_radius_sign(u->packet, NULL, (uint8_t const *) h->ctx.radius_ctx.secret,
1242 h->ctx.radius_ctx.secret_length) < 0) {
1243 RPERROR("Failed signing packet");
1244 goto error;
1245 }
1246
1247 return 0;
1248}
1249
1250
1251/** Revive a connection after "revive_interval"
1252 *
1253 */
1254static void revive_timeout(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
1255{
1256 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1257 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1258
1259 INFO("%s - Reviving connection %s", h->ctx.module_name, h->ctx.fd_info->name);
1261}
1262
1263/** Mark a connection dead after "zombie_interval"
1264 *
1265 */
1266static void zombie_timeout(fr_timer_list_t *tl, fr_time_t now, void *uctx)
1267{
1268 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1269 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1270
1271 INFO("%s - No replies during 'zombie_period', marking connection %s as dead", h->ctx.module_name, h->ctx.fd_info->name);
1272
1273 /*
1274 * Don't use this connection, and re-queue all of its
1275 * requests onto other connections.
1276 */
1278
1279 /*
1280 * We do have status checks. Try to reconnect the
1281 * connection immediately. If the status checks pass,
1282 * then the connection will be marked "alive"
1283 */
1284 if (h->ctx.inst->status_check) {
1286 return;
1287 }
1288
1289 /*
1290 * Revive the connection after a time.
1291 */
1292 if (fr_timer_at(h, tl, &h->zombie_ev,
1293 fr_time_add(now, h->ctx.inst->revive_interval), false,
1294 revive_timeout, tconn) < 0) {
1295 ERROR("Failed inserting revive timeout for connection");
1297 }
1298}
1299
1300
1301/** See if the connection is zombied.
1302 *
1303 * We check for zombie when major events happen:
1304 *
1305 * 1) request hits its final timeout
1306 * 2) request timer hits, and it needs to be retransmitted
1307 * 3) a DUP packet comes in, and the request needs to be retransmitted
1308 * 4) we're sending a packet.
1309 *
1310 * There MIGHT not be retries configured, so we MUST check for zombie
1311 * when any new packet comes in. Similarly, there MIGHT not be new
1312 * packets, but retries are configured, so we have to check there,
1313 * too.
1314 *
1315 * Also, the socket might not be writable for a while. There MIGHT
1316 * be a long time between getting the timer / DUP signal, and the
1317 * request finally being written to the socket. So we need to check
1318 * for zombie at BOTH the timeout and the mux / write function.
1319 *
1320 * @return
1321 * - true if the connection is zombie.
1322 * - false if the connection is not zombie.
1323 */
1325{
1326 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1327
1328 /*
1329 * We're replicating, and don't care about the health of
1330 * the home server, and this function should not be called.
1331 */
1333
1334 /*
1335 * If we're status checking OR already zombie, don't go to zombie
1336 */
1337 if (h->status_checking || fr_timer_armed(h->zombie_ev)) return true;
1338
1339 if (fr_time_eq(now, fr_time_wrap(0))) now = fr_time();
1340
1341 /*
1342 * We received a reply since this packet was sent, the connection isn't zombie.
1343 */
1344 if (fr_time_gteq(h->last_reply, last_sent)) return false;
1345
1346 /*
1347 * If we've seen ANY response in the allowed window, then the connection is still alive.
1348 */
1349 if ((h->ctx.inst->mode == RLM_RADIUS_MODE_PROXY) && fr_time_gt(last_sent, fr_time_wrap(0)) &&
1350 (fr_time_lt(fr_time_add(last_sent, h->ctx.inst->response_window), now))) return false;
1351
1352 /*
1353 * Stop using it for new requests.
1354 */
1355 WARN("%s - Entering Zombie state - connection %s", h->ctx.module_name, h->ctx.fd_info->name);
1357
1358 if (h->ctx.inst->status_check) {
1359 h->status_checking = true;
1360
1361 /*
1362 * Queue up the status check packet. It will be sent
1363 * when the connection is writable.
1364 */
1366 h->status_u->treq = NULL;
1367
1369 h->status_u, h->status_u, true) != TRUNK_ENQUEUE_OK) {
1371 }
1372 } else {
1373 if (fr_timer_at(h, el->tl, &h->zombie_ev, fr_time_add(now, h->ctx.inst->zombie_period),
1374 false, zombie_timeout, tconn) < 0) {
1375 ERROR("Failed inserting zombie timeout for connection");
1377 }
1378 }
1379
1380 return true;
1381}
1382
1383static void mod_dup(request_t *request, bio_request_t *u)
1384{
1385 bio_handle_t *h;
1386
1387 h = talloc_get_type_abort(u->treq->tconn->conn->h, bio_handle_t);
1388
1389 if (h->ctx.fd_config.socket_type != SOCK_DGRAM) {
1390 RDEBUG("Using stream sockets - suppressing retransmission");
1391 return;
1392 }
1393
1394 /*
1395 * Arguably this should never happen for UDP sockets.
1396 */
1397 if (h->ctx.fd_info->write_blocked) {
1398 RDEBUG("IO is blocked - suppressing retransmission");
1399 return;
1400 }
1401 u->is_retry = true;
1402
1403 /*
1404 * We are doing synchronous proxying, retransmit
1405 * the current request on the same connection.
1406 *
1407 * If it's zombie, we still resend it. If the
1408 * connection is dead, then a callback will move
1409 * this request to a new connection.
1410 */
1411 mod_write(request, u->treq, h);
1412}
1413
1414static void do_retry(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_retry_t const *retry);
1415
1416/** Handle module retries.
1417 *
1418 */
1419static void mod_retry(module_ctx_t const *mctx, request_t *request, fr_retry_t const *retry)
1420{
1421 bio_request_t *u = talloc_get_type_abort(mctx->rctx, bio_request_t);
1422 rlm_radius_t const *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
1423
1424 do_retry(inst, u, request, retry);
1425}
1426
1427static void do_retry(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_retry_t const *retry)
1428{
1429 trunk_request_t *treq = talloc_get_type_abort(u->treq, trunk_request_t);
1430 trunk_connection_t *tconn = treq->tconn;
1431 fr_time_t now = retry->updated;
1432
1433 fr_assert(request == treq->request);
1434 fr_assert(treq->preq); /* Must still have a protocol request */
1435 fr_assert(treq->preq == u);
1436
1437 switch (retry->state) {
1438 case FR_RETRY_CONTINUE:
1439 u->retry = *retry;
1440
1441 switch (treq->state) {
1444 fr_assert(0);
1445 break;
1446
1448 RDEBUG("Packet is still in the backlog queue to be sent - suppressing retransmission");
1449 return;
1450
1452 RDEBUG("Packet is still in the pending queue to be sent - suppressing retransmission");
1453 return;
1454
1456 RDEBUG("Packet was partially written, as IO is blocked - suppressing retransmission");
1457 return;
1458
1460 fr_assert(tconn);
1461
1462 mod_dup(request, u);
1463 return;
1464
1472 fr_assert(0);
1473 break;
1474 }
1475 break;
1476
1477 case FR_RETRY_MRD:
1478 REDEBUG("Reached maximum_retransmit_duration (%pVs > %pVs), failing request",
1480 break;
1481
1482 case FR_RETRY_MRC:
1483 REDEBUG("Reached maximum_retransmit_count (%u > %u), failing request",
1484 retry->count, retry->config->mrc);
1485 break;
1486 }
1487
1490
1491 /*
1492 * We don't do zombie stuff!
1493 */
1494 if (!tconn || (inst->mode == RLM_RADIUS_MODE_REPLICATE)) return;
1495
1496 check_for_zombie(unlang_interpret_event_list(request), tconn, now, retry->start);
1497}
1498
1499CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
1501 trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
1502{
1503 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
1504 trunk_request_t *treq;
1505 request_t *request;
1506
1507 if (unlikely(trunk_connection_pop_request(&treq, tconn) < 0)) return;
1508
1509 /*
1510 * No more requests to send
1511 */
1512 if (!treq) return;
1513
1514 request = treq->request;
1515
1516 mod_write(request, treq, h);
1517}
1518
1519static void mod_write(request_t *request, trunk_request_t *treq, bio_handle_t *h)
1520{
1521 rlm_radius_t const *inst = h->ctx.inst;
1522 bio_request_t *u;
1523 char const *action;
1524 uint8_t const *packet;
1525 size_t packet_len;
1526 ssize_t slen;
1527
1528 fr_assert((treq->state == TRUNK_REQUEST_STATE_PENDING) ||
1529 (treq->state == TRUNK_REQUEST_STATE_PARTIAL));
1530
1531 u = treq->preq;
1532
1534
1535 /*
1536 * If it's a partial packet, then write the partial bit.
1537 */
1538 if (u->partial) {
1539 fr_assert(u->partial < u->packet_len);
1540 packet = u->packet + u->partial;
1541 packet_len = u->packet_len - u->partial;
1542 goto do_write;
1543 }
1544
1545 /*
1546 * No previous packet, OR can't retransmit the
1547 * existing one. Oh well.
1548 *
1549 * Note that if we can't retransmit the previous
1550 * packet, then u->rr MUST already have been
1551 * deleted in the request_cancel() function
1552 * or request_release_conn() function when
1553 * the REQUEUE signal was received.
1554 */
1555 if (!u->packet) {
1556 fr_assert(!u->rr);
1557
1558 if (unlikely(radius_track_entry_reserve(&u->rr, treq, h->tt, request, u->code, treq) < 0)) {
1559#ifndef NDEBUG
1560 radius_track_state_log(&default_log, L_ERR, __FILE__, __LINE__,
1562#endif
1563 fr_assert_fail("Tracking entry allocation failed: %s", fr_strerror());
1565 return;
1566 }
1567 fr_assert(u->rr);
1568 u->id = u->rr->id;
1569
1570 RDEBUG("Sending %s ID %d length %zu over connection %s",
1572
1573 if (encode(h, request, u, u->id) < 0) {
1574 /*
1575 * Need to do this because request_conn_release
1576 * may not be called.
1577 */
1580 return;
1581 }
1582 RHEXDUMP3(u->packet, u->packet_len, "Encoded packet");
1583
1584 /*
1585 * Remember the authentication vector, which now has the
1586 * packet signature.
1587 */
1589 } else {
1590 RDEBUG("Retransmitting %s ID %d length %zu over connection %s",
1592 }
1593
1594 /*
1595 * @todo - When logging Message-Authenticator, don't print its' value.
1596 */
1597 log_request_pair_list(L_DBG_LVL_2, request, NULL, &request->request_pairs, NULL);
1598 if (!fr_pair_list_empty(&u->extra)) log_request_pair_list(L_DBG_LVL_2, request, NULL, &u->extra, NULL);
1599
1600 packet = u->packet;
1601 packet_len = u->packet_len;
1602
1603do_write:
1604 fr_assert(packet != NULL);
1605 fr_assert(packet_len >= RADIUS_HEADER_LENGTH);
1606
1607 slen = fr_bio_write(h->bio.write, NULL, packet, packet_len);
1608
1609 /*
1610 * Can't write anything, requeue it on a different socket.
1611 */
1612 if (slen == fr_bio_error(IO_WOULD_BLOCK)) goto requeue;
1613
1614 if (slen < 0) {
1615 switch (errno) {
1616 /*
1617 * There is an error in the request.
1618 */
1619 case EMSGSIZE: /* Packet size exceeds max size allowed on socket */
1620 ERROR("%s - Failed sending data over connection %s: %s",
1621 h->ctx.module_name, h->ctx.fd_info->name, fr_syserror(errno));
1623 break;
1624
1625 /*
1626 * There is an error in the connection. The reconnection will re-queue any pending or
1627 * sent requests, so we don't have to do any cleanup.
1628 */
1629 default:
1630 ERROR("%s - Failed sending data over connection %s: %s",
1631 h->ctx.module_name, h->ctx.fd_info->name, fr_syserror(errno));
1633 break;
1634 }
1635
1636 return;
1637 }
1638
1639 /*
1640 * No data to send, ignore the write for partials, but otherwise requeue it.
1641 */
1642 if (slen == 0) {
1643 if (u->partial) return;
1644
1645 requeue:
1646 RWARN("%s - Failed sending data over connection %s: sent zero bytes",
1647 h->ctx.module_name, h->ctx.fd_info->name);
1649 return;
1650 }
1651
1652 packet_len += slen;
1653 if (packet_len < u->packet_len) {
1654 /*
1655 * The first time around, save a copy of the packet for later writing.
1656 */
1657 if (!u->partial) MEM(u->packet = talloc_memdup(u, u->packet, u->packet_len));
1658
1659 u->partial = packet_len;
1661 return;
1662 }
1663
1664 /*
1665 * For retransmissions.
1666 */
1667 u->partial = 0;
1668
1669 /*
1670 * Don't print anything extra for replication.
1671 */
1672 if (inst->mode == RLM_RADIUS_MODE_REPLICATE) {
1673 u->rcode = RLM_MODULE_OK;
1675 return;
1676 }
1677
1678 /*
1679 * On first packet, signal it as sent, and update stats.
1680 *
1681 * Later packets are just retransmissions to the BIO, and don't need to involve
1682 * the trunk code.
1683 */
1684 if (u->retry.count == 1) {
1685 h->last_sent = u->retry.start;
1687
1689
1690 action = u->proxied ? "Proxied" : "Originated";
1691
1692 } else {
1693 /*
1694 * We don't signal the trunk that it's been sent, it was already senty
1695 */
1696 action = "Retransmitted";
1697 }
1698
1700
1701 if (!u->proxied) {
1702 RDEBUG("%s request. Expecting response within %pVs", action,
1704
1705 } else {
1706 /*
1707 * If the packet doesn't get a response,
1708 * then bio_request_free() will notice, and run conn_zombie()
1709 */
1710 RDEBUG("%s request. Relying on NAS to perform more retransmissions", action);
1711 }
1712
1713 /*
1714 * We don't retransmit over TCP.
1715 */
1716 if (h->ctx.fd_config.socket_type != SOCK_DGRAM) return;
1717
1718 /*
1719 * If we only send one datagram packet, then don't bother saving it.
1720 */
1721 if (u->retry.config && u->retry.config->mrc == 1) {
1722 u->packet = NULL;
1723 return;
1724 }
1725
1726 MEM(u->packet = talloc_memdup(u, u->packet, u->packet_len));
1727}
1728
1729/** Deal with Protocol-Error replies, and possible negotiation
1730 *
1731 */
1733{
1734 bool error_601 = false;
1735 uint32_t response_length = 0;
1736 uint8_t const *attr, *end;
1737
1738 end = h->buffer + fr_nbo_to_uint16(h->buffer + 2);
1739
1740 for (attr = h->buffer + RADIUS_HEADER_LENGTH;
1741 attr < end;
1742 attr += attr[1]) {
1743 /*
1744 * Error-Cause = Response-Too-Big
1745 */
1746 if ((attr[0] == attr_error_cause->attr) && (attr[1] == 6)) {
1747 uint32_t error;
1748
1749 memcpy(&error, attr + 2, 4);
1750 error = ntohl(error);
1751 if (error == 601) error_601 = true;
1752 continue;
1753 }
1754
1755 /*
1756 * The other end wants us to increase our Response-Length
1757 */
1758 if ((attr[0] == attr_response_length->attr) && (attr[1] == 6)) {
1759 memcpy(&response_length, attr + 2, 4);
1760 continue;
1761 }
1762
1763 /*
1764 * Protocol-Error packets MUST contain an
1765 * Original-Packet-Code attribute.
1766 *
1767 * The attribute containing the
1768 * Original-Packet-Code is an extended
1769 * attribute.
1770 */
1771 if (attr[0] != attr_extended_attribute_1->attr) continue;
1772
1773 /*
1774 * ATTR + LEN + EXT-Attr + uint32
1775 */
1776 if (attr[1] != 7) continue;
1777
1778 /*
1779 * See if there's an Original-Packet-Code.
1780 */
1781 if (attr[2] != (uint8_t)attr_original_packet_code->attr) continue;
1782
1783 /*
1784 * Has to be an 8-bit number.
1785 */
1786 if ((attr[3] != 0) ||
1787 (attr[4] != 0) ||
1788 (attr[5] != 0)) {
1790 return;
1791 }
1792
1793 /*
1794 * The value has to match. We don't
1795 * currently multiplex different codes
1796 * with the same IDs on connections. So
1797 * this check is just for RFC compliance,
1798 * and for sanity.
1799 */
1800 if (attr[6] != u->code) {
1802 return;
1803 }
1804 }
1805
1806 /*
1807 * Error-Cause = Response-Too-Big
1808 *
1809 * The other end says it needs more room to send it's response
1810 *
1811 * Limit it to reasonable values.
1812 */
1813 if (error_601 && response_length && (response_length > h->buflen)) {
1814 if (response_length < 4096) response_length = 4096;
1815 if (response_length > 65535) response_length = 65535;
1816
1817 DEBUG("%s - Increasing buffer size to %u for connection %s", h->ctx.module_name, response_length, h->ctx.fd_info->name);
1818
1819 /*
1820 * Make sure to copy the packet over!
1821 */
1822 attr = h->buffer;
1823 h->buflen = response_length;
1824 MEM(h->buffer = talloc_array(h, uint8_t, h->buflen));
1825
1826 memcpy(h->buffer, attr, end - attr);
1827 }
1828
1829 /*
1830 * fail - something went wrong internally, or with the connection.
1831 * invalid - wrong response to packet
1832 * handled - best remaining alternative :(
1833 *
1834 * i.e. if the response is NOT accept, reject, whatever,
1835 * then we shouldn't allow the caller to do any more
1836 * processing of this packet. There was a protocol
1837 * error, and the response is valid, but not useful for
1838 * anything.
1839 */
1841}
1842
1843
1844/** Handle retries for a status check
1845 *
1846 */
1848{
1849 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1850 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1851
1853 h->status_u, h->status_u, true) != TRUNK_ENQUEUE_OK) {
1855 }
1856}
1857
1858
1859/** Deal with replies replies to status checks and possible negotiation
1860 *
1861 */
1863{
1864 bio_handle_t *h = talloc_get_type_abort(treq->tconn->conn->h, bio_handle_t);
1865 rlm_radius_t const *inst = h->ctx.inst;
1866 bio_request_t *u = talloc_get_type_abort(treq->rctx, bio_request_t);
1867
1868 fr_assert(treq->preq == h->status_u);
1869 fr_assert(treq->rctx == h->status_u);
1870
1871 u->treq = NULL;
1872
1873 /*
1874 * @todo - do other negotiation and signaling.
1875 */
1877
1878 if (u->num_replies < inst->num_answers_to_alive) {
1879 DEBUG("Received %u / %u replies for status check, on connection - %s",
1880 u->num_replies, inst->num_answers_to_alive, h->ctx.fd_info->name);
1881 DEBUG("Next status check packet will be in %pVs", fr_box_time_delta(fr_time_sub(u->retry.next, now)));
1882
1883 /*
1884 * Set the timer for the next retransmit.
1885 */
1886 if (fr_timer_at(h, h->ctx.el->tl, &u->ev, u->retry.next, false, status_check_next, treq->tconn) < 0) {
1888 }
1889 return;
1890 }
1891
1892 DEBUG("Received enough replies to status check, marking connection as active - %s", h->ctx.fd_info->name);
1893
1894 /*
1895 * Set the "last idle" time to now, so that we don't
1896 * restart zombie_period until sufficient time has
1897 * passed.
1898 */
1899 h->last_idle = fr_time();
1900
1901 /*
1902 * Reset retry interval and retransmission counters
1903 * also frees u->ev.
1904 */
1905 status_check_reset(h, u);
1906 trunk_connection_signal_active(treq->tconn);
1907}
1908
1909CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
1911{
1912 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
1913
1914 DEBUG3("%s - Reading data for connection %s", h->ctx.module_name, h->ctx.fd_info->name);
1915
1916 while (true) {
1917 ssize_t slen;
1918
1919 trunk_request_t *treq;
1920 request_t *request;
1921 bio_request_t *u;
1924 uint8_t code = 0;
1925 fr_pair_list_t reply;
1926 fr_pair_t *vp;
1927
1928 fr_time_t now;
1929
1930 fr_pair_list_init(&reply);
1931
1932 /*
1933 * Drain the socket of all packets. If we're busy, this
1934 * saves a round through the event loop. If we're not
1935 * busy, a few extra system calls don't matter.
1936 */
1937 slen = fr_bio_read(h->bio.read, NULL, h->buffer, h->buflen);
1938 if (slen == 0) {
1939 /*
1940 * @todo - set BIO FD EOF callback, so that we don't have to check it here.
1941 */
1943 return;
1944 }
1945
1946 /*
1947 * We're done reading, return.
1948 */
1949 if (slen == fr_bio_error(IO_WOULD_BLOCK)) return;
1950
1951 if (slen < 0) {
1952 ERROR("%s - Failed reading response from socket: %s",
1953 h->ctx.module_name, fr_syserror(errno));
1955 return;
1956 }
1957
1958 fr_assert(slen >= RADIUS_HEADER_LENGTH); /* checked in verify */
1959
1960 /*
1961 * Note that we don't care about packet codes. All
1962 * packet codes share the same ID space.
1963 */
1964 rr = radius_track_entry_find(h->tt, h->buffer[1], NULL);
1965 if (!rr) {
1966 WARN("%s - Ignoring reply with ID %i that arrived too late",
1967 h->ctx.module_name, h->buffer[1]);
1968 continue;
1969 }
1970
1971 treq = talloc_get_type_abort(rr->uctx, trunk_request_t);
1972 request = treq->request;
1973 fr_assert(request != NULL);
1974 u = talloc_get_type_abort(treq->rctx, bio_request_t);
1975 fr_assert(u == treq->preq);
1976
1977 /*
1978 * Decode the incoming packet.
1979 */
1980 reason = decode(request->reply_ctx, &reply, &code, h, request, u, rr->vector, h->buffer, (size_t)slen);
1981 if (reason != DECODE_FAIL_NONE) continue;
1982
1983 /*
1984 * Only valid packets are processed
1985 * Otherwise an attacker could perform
1986 * a DoS attack against the proxying servers
1987 * by sending fake responses for upstream
1988 * servers.
1989 */
1990 h->last_reply = now = fr_time();
1991
1992 /*
1993 * Status-Server can have any reply code, we don't care
1994 * what it is. So long as it's signed properly, we
1995 * accept it. This flexibility is because we don't
1996 * expose Status-Server to the admins. It's only used by
1997 * this module for internal signalling.
1998 */
1999 if (u == h->status_u) {
2000 fr_pair_list_free(&reply); /* Probably want to pass this to status_check_reply? */
2001 status_check_reply(treq, now);
2003 continue;
2004 }
2005
2006 /*
2007 * Handle any state changes, etc. needed by receiving a
2008 * Protocol-Error reply packet.
2009 *
2010 * Protocol-Error is permitted as a reply to any
2011 * packet.
2012 */
2013 switch (code) {
2016 break;
2017
2018 default:
2019 break;
2020 }
2021
2022 /*
2023 * Mark up the request as being an Access-Challenge, if
2024 * required.
2025 *
2026 * We don't do this for other packet types, because the
2027 * ok/fail nature of the module return code will
2028 * automatically result in it the parent request
2029 * returning an ok/fail packet code.
2030 */
2032 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_packet_type);
2033 if (!vp) {
2034 MEM(vp = fr_pair_afrom_da(request->reply_ctx, attr_packet_type));
2036 fr_pair_append(&request->reply_pairs, vp);
2037 }
2038 }
2039
2040 /*
2041 * Delete Proxy-State attributes from the reply.
2042 */
2044
2045 /*
2046 * If the reply has Message-Authenticator, then over-ride its value with all zeros, so
2047 * that we don't confuse anyone reading the debug output.
2048 */
2049 if ((vp = fr_pair_find_by_da(&reply, NULL, attr_message_authenticator)) != NULL) {
2050 (void) fr_pair_value_memdup(vp, (uint8_t const *) "", 1, false);
2051 }
2052
2053 treq->request->reply->code = code;
2054 u->rcode = radius_code_to_rcode[code];
2055 fr_pair_list_append(&request->reply_pairs, &reply);
2057 }
2058}
2059
2060/*
2061 * This is the same as request_mux(), except that we immediately mark the request as complete.
2062 */
2063CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
2065 trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
2066{
2067 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
2068 trunk_request_t *treq;
2069
2070 if (unlikely(trunk_connection_pop_request(&treq, tconn) < 0)) return;
2071
2072 /*
2073 * No more requests to send
2074 */
2075 if (!treq) return;
2076
2077 mod_write(treq->request, treq, h);
2078}
2079
2080CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
2082{
2083 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
2084
2085 DEBUG3("%s - Reading data for connection %s", h->ctx.module_name, h->ctx.fd_info->name);
2086
2087 while (true) {
2088 ssize_t slen;
2089
2090 trunk_request_t *treq;
2091 request_t *request;
2092 bio_request_t *u;
2095 uint8_t code = 0;
2096 fr_pair_list_t reply;
2097
2098 fr_time_t now;
2099
2100 fr_pair_list_init(&reply);
2101
2102 /*
2103 * Drain the socket of all packets. If we're busy, this
2104 * saves a round through the event loop. If we're not
2105 * busy, a few extra system calls don't matter.
2106 */
2107 slen = fr_bio_read(h->bio.read, NULL, h->buffer, h->buflen);
2108 if (slen == 0) {
2109 /*
2110 * @todo - set BIO FD EOF callback, so that we don't have to check it here.
2111 */
2113 return;
2114 }
2115
2116 /*
2117 * We're done reading, return.
2118 */
2119 if (slen == fr_bio_error(IO_WOULD_BLOCK)) return;
2120
2121 if (slen < 0) {
2122 ERROR("%s - Failed reading response from socket: %s",
2123 h->ctx.module_name, fr_syserror(errno));
2125 return;
2126 }
2127
2128 fr_assert(slen >= RADIUS_HEADER_LENGTH); /* checked in verify */
2129
2130 /*
2131 * We only pay attention to Protocol-Error replies.
2132 *
2133 * All other packets are discarded.
2134 */
2136 continue;
2137 }
2138
2139 /*
2140 * Note that we don't care about packet codes. All
2141 * packet codes share the same ID space.
2142 */
2143 rr = radius_track_entry_find(h->tt, h->buffer[1], NULL);
2144 if (!rr) {
2145 WARN("%s - Ignoring reply with ID %i that arrived too late",
2146 h->ctx.module_name, h->buffer[1]);
2147 continue;
2148 }
2149
2150 treq = talloc_get_type_abort(rr->uctx, trunk_request_t);
2151 request = treq->request;
2152 fr_assert(request != NULL);
2153 u = talloc_get_type_abort(treq->rctx, bio_request_t);
2154 fr_assert(u == treq->preq);
2155
2156 /*
2157 * Decode the incoming packet
2158 */
2159 reason = decode(request->reply_ctx, &reply, &code, h, request, u, rr->vector, h->buffer, (size_t)slen);
2160 if (reason != DECODE_FAIL_NONE) continue;
2161
2162 /*
2163 * Only valid packets are processed
2164 * Otherwise an attacker could perform
2165 * a DoS attack against the proxying servers
2166 * by sending fake responses for upstream
2167 * servers.
2168 */
2169 h->last_reply = now = fr_time();
2170
2171 /*
2172 * Status-Server can have any reply code, we don't care
2173 * what it is. So long as it's signed properly, we
2174 * accept it. This flexibility is because we don't
2175 * expose Status-Server to the admins. It's only used by
2176 * this module for internal signalling.
2177 */
2178 if (u == h->status_u) {
2179 fr_pair_list_free(&reply); /* Probably want to pass this to status_check_reply? */
2180 status_check_reply(treq, now);
2182 continue;
2183 }
2184
2185 /*
2186 * Handle any state changes, etc. needed by receiving a
2187 * Protocol-Error reply packet.
2188 *
2189 * Protocol-Error is also permitted as a reply to any
2190 * packet.
2191 */
2193 }
2194}
2195
2196
2197/** Remove the request from any tracking structures
2198 *
2199 * Frees encoded packets if the request is being moved to a new connection
2200 */
2201static void request_cancel(UNUSED connection_t *conn, void *preq_to_reset,
2202 trunk_cancel_reason_t reason, UNUSED void *uctx)
2203{
2204 bio_request_t *u = preq_to_reset;
2205
2206 /*
2207 * Request has been requeued on the same
2208 * connection due to timeout or DUP signal. We
2209 * keep the same packet to avoid re-encoding it.
2210 */
2211 if (reason == TRUNK_CANCEL_REASON_REQUEUE) {
2212 /*
2213 * Delete the request_timeout
2214 *
2215 * Note: There might not be a request timeout
2216 * set in the case where the request was
2217 * queued for sendmmsg but never actually
2218 * sent.
2219 */
2220 FR_TIMER_DISARM(u->ev);
2221 }
2222
2223 /*
2224 * Other cancellations are dealt with by
2225 * request_conn_release as the request is removed
2226 * from the trunk.
2227 */
2228}
2229
2230/** Clear out anything associated with the handle from the request
2231 *
2232 */
2233static void request_conn_release(connection_t *conn, void *preq_to_reset, UNUSED void *uctx)
2234{
2235 bio_request_t *u = preq_to_reset;
2236 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
2237
2238 FR_TIMER_DISARM(u->ev);
2240
2241 if (h->ctx.inst->mode == RLM_RADIUS_MODE_REPLICATE) return;
2242
2243 u->num_replies = 0;
2244
2245 /*
2246 * If there are no outstanding tracking entries
2247 * allocated then the connection is "idle".
2248 */
2249 if (!h->tt || (h->tt->num_requests == 0)) h->last_idle = fr_time();
2250}
2251
2252/** Write out a canned failure
2253 *
2254 */
2255static void request_fail(request_t *request, NDEBUG_UNUSED void *preq, void *rctx,
2256 NDEBUG_UNUSED trunk_request_state_t state, UNUSED void *uctx)
2257{
2258 bio_request_t *u = talloc_get_type_abort(rctx, bio_request_t);
2259
2260 fr_assert(u == preq);
2261
2262 fr_assert(!u->rr && !u->packet && fr_pair_list_empty(&u->extra) && !u->ev); /* Dealt with by request_conn_release */
2263
2265
2266 if (u->status_check) return;
2267
2269 u->treq = NULL;
2270
2272}
2273
2274/** Response has already been written to the rctx at this point
2275 *
2276 */
2277static void request_complete(request_t *request, NDEBUG_UNUSED void *preq, void *rctx, UNUSED void *uctx)
2278{
2279 bio_request_t *u = talloc_get_type_abort(rctx, bio_request_t);
2280
2281 fr_assert(u == preq);
2282
2283 fr_assert(!u->rr && !u->packet && fr_pair_list_empty(&u->extra) && !u->ev); /* Dealt with by request_conn_release */
2284
2285 if (u->status_check) return;
2286
2287 u->treq = NULL;
2288
2290}
2291
2292/** Resume execution of the request, returning the rcode set during trunk execution
2293 *
2294 */
2296{
2297 bio_request_t *u = talloc_get_type_abort(mctx->rctx, bio_request_t);
2298 rlm_rcode_t rcode = u->rcode;
2299
2300 talloc_free(u);
2301
2302 RETURN_UNLANG_RCODE(rcode);
2303}
2304
2305static void do_signal(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_signal_t action);
2306
2307static void mod_signal(module_ctx_t const *mctx, UNUSED request_t *request, fr_signal_t action)
2308{
2310
2311 bio_request_t *u = talloc_get_type_abort(mctx->rctx, bio_request_t);
2312
2313 do_signal(inst, u, request, action);
2314}
2315
2316static void do_signal(rlm_radius_t const *inst, bio_request_t *u, UNUSED request_t *request, fr_signal_t action)
2317{
2318 /*
2319 * We received a duplicate packet, but we're not doing
2320 * synchronous proxying. Ignore the dup, and rely on the
2321 * IO submodule to time it's own retransmissions.
2322 */
2323 if ((action == FR_SIGNAL_DUP) && (inst->mode != RLM_RADIUS_MODE_PROXY)) return;
2324
2325 /*
2326 * If we don't have a treq associated with the
2327 * rctx it's likely because the request was
2328 * scheduled, but hasn't yet been resumed, and
2329 * has received a signal, OR has been resumed
2330 * and immediately cancelled as the event loop
2331 * is exiting, in which case
2332 * unlang_request_is_scheduled will return false
2333 * (don't use it).
2334 */
2335 if (!u->treq) return;
2336
2337 switch (action) {
2338 /*
2339 * The request is being cancelled, tell the
2340 * trunk so it can clean up the treq.
2341 */
2342 case FR_SIGNAL_CANCEL:
2344 u->treq = NULL;
2345 return;
2346
2347 /*
2348 * Requeue the request on the same connection
2349 * causing a "retransmission" if the request
2350 * has already been sent out.
2351 */
2352 case FR_SIGNAL_DUP:
2353 mod_dup(request, u);
2354 return;
2355
2356 default:
2357 return;
2358 }
2359}
2360
2361/** Free a bio_request_t
2362 *
2363 * Allows us to set break points for debugging.
2364 */
2366{
2367 if (!u->treq) return 0;
2368
2369#ifndef NDEBUG
2370 {
2371 trunk_request_t *treq;
2372 treq = talloc_get_type_abort(u->treq, trunk_request_t);
2373 fr_assert(treq->preq == u);
2374 }
2375#endif
2376
2377 fr_assert_msg(!fr_timer_armed(u->ev), "bio_request_t freed with active timer");
2378
2380
2381 fr_assert(u->rr == NULL);
2382
2383 return 0;
2384}
2385
2386static int mod_enqueue(bio_request_t **p_u, fr_retry_config_t const **p_retry_config,
2387 rlm_radius_t const *inst, trunk_t *trunk, request_t *request)
2388{
2389 bio_request_t *u;
2390 trunk_request_t *treq;
2392
2393 fr_assert(request->packet->code > 0);
2394 fr_assert(request->packet->code < FR_RADIUS_CODE_MAX);
2395
2396 /*
2397 * Do any necessary RADIUS level fixups
2398 * - check Proxy-State
2399 * - do CHAP-Challenge fixups
2400 */
2401 if (radius_fixups(inst, request) < 0) return 0;
2402
2403 treq = trunk_request_alloc(trunk, request);
2404 if (!treq) {
2405 REDEBUG("Failed allocating handler for request");
2406 return -1;
2407 }
2408
2409 MEM(u = talloc_zero(request, bio_request_t));
2410 talloc_set_destructor(u, _bio_request_free);
2411
2412 /*
2413 * Can't use compound literal - const issues.
2414 */
2415 u->code = request->packet->code;
2416 u->priority = request->priority;
2417 u->recv_time = request->async->recv_time;
2419
2420 u->retry.count = 1;
2421
2423
2424 switch(trunk_request_enqueue(&treq, trunk, request, u, u)) {
2425 case TRUNK_ENQUEUE_OK:
2427 break;
2428
2430 REDEBUG("Unable to queue packet - connections at maximum capacity");
2431 fail:
2432 fr_assert(!u->rr && !u->packet); /* Should not have been fed to the muxer */
2433 trunk_request_free(&treq); /* Return to the free list */
2434 talloc_free(u);
2435 return -1;
2436
2438 REDEBUG("All destinations are down - cannot send packet");
2439 goto fail;
2440
2441 case TRUNK_ENQUEUE_FAIL:
2442 REDEBUG("Unable to queue packet");
2443 goto fail;
2444 }
2445
2446 u->treq = treq; /* Remember for signalling purposes */
2447 fr_assert(treq->rctx == u);
2448
2449 /*
2450 * Figure out if we're originating the packet or proxying it. And also figure out if we have to
2451 * retry.
2452 */
2453 switch (inst->mode) {
2455 case RLM_RADIUS_MODE_UNCONNECTED_REPLICATE: /* unconnected sockets are UDP, and bypass the trunk */
2456 REDEBUG("Internal sanity check failed - connection trunking cannot be used for replication");
2457 return -1;
2458
2459 /*
2460 * We originate this packet if it was taken from the detail module, which doesn't have a
2461 * real client. @todo - do a better check here.
2462 *
2463 * We originate this packet if the parent request is not compatible with this one
2464 * (i.e. it's from a different protocol).
2465 *
2466 * We originate the packet if the parent is from the same dictionary, but has a different
2467 * packet code. This lets us receive Accounting-Request, and originate
2468 * Disconnect-Request.
2469 */
2472 if (!request->parent) {
2473 u->proxied = (request->client && request->client->cs != NULL);
2474
2475 } else if (!fr_dict_compatible(request->parent->proto_dict, request->proto_dict)) {
2476 u->proxied = false;
2477
2478 } else {
2479 u->proxied = (request->parent->packet->code == request->packet->code);
2480 }
2481
2482 /*
2483 * Proxied packets get a final timeout, as we retry only on DUP packets.
2484 */
2485 if (u->proxied) goto timeout_retry;
2486
2488
2489 /*
2490 * Client packets (i.e. packets we originate) get retries for UDP. And no retries for TCP.
2491 */
2493 if (inst->fd_config.socket_type == SOCK_DGRAM) {
2494 retry_config = &inst->retry[u->code];
2495 break;
2496 }
2498
2499 /*
2500 * Replicated packets are never retried, but they have a timeout if the socket isn't
2501 * ready for writing.
2502 */
2504 timeout_retry:
2505 retry_config = &inst->timeout_retry;
2506 break;
2507 }
2508
2509 /*
2510 * The event loop will take care of demux && sending the
2511 * packet, along with any retransmissions.
2512 */
2513 *p_u = u;
2514 *p_retry_config = retry_config;
2515
2516 return 1;
2517}
2518
2519static void home_server_free(void *data)
2520{
2521 home_server_t *home = data;
2522
2523 talloc_free(home);
2524}
2525
2528 .connection_notify = thread_conn_notify,
2529 .request_prioritise = request_prioritise,
2530 .request_mux = request_mux,
2531 .request_demux = request_demux,
2532 .request_conn_release = request_conn_release,
2533 .request_complete = request_complete,
2534 .request_fail = request_fail,
2535 .request_cancel = request_cancel,
2536};
2537
2540 .connection_notify = thread_conn_notify,
2541 .request_prioritise = request_prioritise,
2542 .request_mux = request_replicate_mux,
2543 .request_demux = request_replicate_demux,
2544 .request_conn_release = request_conn_release,
2545 .request_complete = request_complete,
2546 .request_fail = request_fail,
2547 .request_cancel = request_cancel,
2548};
2549
2550/** Instantiate thread data for the submodule.
2551 *
2552 */
2554{
2555 rlm_radius_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
2556 bio_thread_t *thread = talloc_get_type_abort(mctx->thread, bio_thread_t);
2557
2558 thread->ctx.el = mctx->el;
2559 thread->ctx.inst = inst;
2560 thread->ctx.fd_config = inst->fd_config;
2561 thread->ctx.radius_ctx = inst->common_ctx;
2562
2563 switch (inst->mode) {
2566 inst->home_server_lifetime);
2568
2569 default:
2570 thread->ctx.trunk = trunk_alloc(thread, mctx->el, &io_funcs,
2571 &inst->trunk_conf, inst->name, thread, false);
2572 if (!thread->ctx.trunk) return -1;
2573 return 0;
2574
2576 /*
2577 * We can replicate over TCP, but that uses trunks.
2578 */
2579 if (inst->fd_config.socket_type == SOCK_DGRAM) break;
2580
2581 thread->ctx.trunk = trunk_alloc(thread, mctx->el, &io_replicate_funcs,
2582 &inst->trunk_conf, inst->name, thread, false);
2583 if (!thread->ctx.trunk) return -1;
2584 return 0;
2585
2587 break;
2588 }
2589
2590 /*
2591 * If we have a port range, allocate the source IP based
2592 * on the range start, plus the thread ID. This means
2593 * that we can avoid "hunt and peck" attempts to open up
2594 * the source port.
2595 */
2596 if (thread->ctx.fd_config.src_port_start) {
2598 }
2599
2600 /*
2601 * Allocate an unconnected socket for replication.
2602 */
2603 thread->bio.fd = fr_bio_fd_alloc(thread, &thread->ctx.fd_config, 0);
2604 if (!thread->bio.fd) {
2605 PERROR("%s - failed opening socket", inst->name);
2607 }
2608
2609 thread->bio.fd->uctx = thread;
2610 thread->ctx.fd_info = fr_bio_fd_info(thread->bio.fd);
2611 fr_assert(thread->ctx.fd_info != NULL);
2612
2613 (void) fr_bio_fd_write_only(thread->bio.fd);
2614
2615 DEBUG("%s - Opened unconnected replication socket %s", inst->name, thread->ctx.fd_info->name);
2616 return 0;
2617}
2618
2620 { .required = true, .single = true, .type = FR_TYPE_COMBO_IP_ADDR },
2621 { .required = true, .single = true, .type = FR_TYPE_UINT16 },
2622 { .required = true, .single = true, .type = FR_TYPE_STRING },
2624};
2625
2626/*
2627 * %replicate.sendto.ipaddr(ipaddr, port, secret)
2628 */
2630 xlat_ctx_t const *xctx,
2631 request_t *request, fr_value_box_list_t *args)
2632{
2633 bio_thread_t *thread = talloc_get_type_abort(xctx->mctx->thread, bio_thread_t);
2634 fr_value_box_t *ipaddr, *port, *secret;
2635 ssize_t packet_len;
2636 uint8_t buffer[4096];
2637 fr_radius_ctx_t radius_ctx;
2640
2641 XLAT_ARGS(args, &ipaddr, &port, &secret);
2642
2643 /*
2644 * Can't change IP address families.
2645 */
2646 if (ipaddr->vb_ip.af != thread->ctx.fd_info->socket.af) {
2647 RPERROR("Invalid destination IP address family in %pV", ipaddr);
2648 return XLAT_ACTION_FAIL;
2649 }
2650
2651 /*
2652 * Warn if we're not replicating accounting data. It likely won't wokr/
2653 */
2654 if (request->packet->code != FR_RADIUS_CODE_ACCOUNTING_REQUEST) {
2655 RWDEBUG("Replication of packets other then Accounting-Request will likely not do what you want.");
2656 }
2657
2658 /*
2659 * Set up various context things.
2660 */
2661 radius_ctx = (fr_radius_ctx_t) {
2662 .secret = secret->vb_strvalue,
2663 .secret_length = secret->vb_length,
2664 .proxy_state = 0,
2665 };
2666
2668 .common = &radius_ctx,
2669 .rand_ctx = (fr_fast_rand_t) {
2670 .a = fr_rand(),
2671 .b = fr_rand(),
2672 },
2673 .code = request->packet->code,
2674 .id = thread->bio.id++ & 0xff,
2675 .add_proxy_state = false,
2676 };
2677
2678 /*
2679 * Encode the entire packet.
2680 */
2681 packet_len = fr_radius_encode(&FR_DBUFF_TMP(buffer, sizeof(buffer)),
2682 &request->request_pairs, &encode_ctx);
2683 if (fr_pair_encode_is_error(packet_len)) {
2684 RPERROR("Failed encoding packet");
2685 return XLAT_ACTION_FAIL;
2686 }
2687
2688 /*
2689 * Sign it.
2690 */
2691 if (fr_radius_sign(buffer, NULL, (uint8_t const *) radius_ctx.secret, radius_ctx.secret_length) < 0) {
2692 RPERROR("Failed signing packet");
2693 return XLAT_ACTION_FAIL;
2694 }
2695
2696 /*
2697 * Prepare destination address.
2698 */
2699 addr = (fr_bio_fd_packet_ctx_t) {
2700 .socket = thread->ctx.fd_info->socket,
2701 };
2702 addr.socket.inet.dst_ipaddr = ipaddr->vb_ip;
2703 addr.socket.inet.dst_port = port->vb_uint16;
2704
2705 RDEBUG("Replicating packet to %pV:%u", ipaddr, port->vb_uint16);
2706
2707 /*
2708 * We either send it, or fail.
2709 */
2710 packet_len = fr_bio_write(thread->bio.fd, &addr, buffer, packet_len);
2711 if (packet_len < 0) {
2712 RPERROR("Failed sending packet to %pV:%u", ipaddr, port->vb_uint16);
2713 return XLAT_ACTION_FAIL;
2714 }
2715
2716 /*
2717 * No return value.
2718 */
2719 return XLAT_ACTION_DONE;
2720}
2721
2722// **********************************************************************
2723
2724/** Dynamic home server code
2725 *
2726 */
2727
2728static int8_t home_server_cmp(void const *one, void const *two)
2729{
2730 home_server_t const *a = one;
2731 home_server_t const *b = two;
2732 int8_t rcode;
2733
2735 if (rcode != 0) return rcode;
2736
2738}
2739
2741 xlat_ctx_t const *xctx,
2742 request_t *request, UNUSED fr_value_box_list_t *in)
2743{
2744 bio_request_t *u = talloc_get_type_abort(xctx->rctx, bio_request_t);
2745 fr_value_box_t *dst;
2746
2747 if (u->rcode == RLM_MODULE_FAIL) return XLAT_ACTION_FAIL;
2748
2750 dst->vb_uint32 = request->reply->code;
2751
2752 fr_dcursor_append(out, dst);
2753
2754 return XLAT_ACTION_DONE;
2755}
2756
2757static void xlat_sendto_signal(xlat_ctx_t const *xctx, request_t *request, fr_signal_t action)
2758{
2759 rlm_radius_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_radius_t);
2760 bio_request_t *u = talloc_get_type_abort(xctx->rctx, bio_request_t);
2761
2762 do_signal(inst, u, request, action);
2763}
2764
2765/*
2766 * @todo - change this to mod_retry
2767 */
2768static void xlat_sendto_retry(xlat_ctx_t const *xctx, request_t *request, fr_retry_t const *retry)
2769{
2770 rlm_radius_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_radius_t);
2771 bio_request_t *u = talloc_get_type_abort(xctx->rctx, bio_request_t);
2772
2773 do_retry(inst, u, request, retry);
2774}
2775
2776/*
2777 * %proxy.sendto.ipaddr(ipaddr, port, secret)
2778 */
2780 xlat_ctx_t const *xctx,
2781 request_t *request, fr_value_box_list_t *args)
2782{
2783 rlm_radius_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_radius_t);
2784 bio_thread_t *thread = talloc_get_type_abort(xctx->mctx->thread, bio_thread_t);
2785 fr_value_box_t *ipaddr, *port, *secret;
2786 home_server_t *home;
2787 bio_request_t *u = NULL;
2788 fr_retry_config_t const *retry_config = NULL;
2789 int rcode;
2790
2791 XLAT_ARGS(args, &ipaddr, &port, &secret);
2792
2793 /*
2794 * Can't change IP address families.
2795 */
2796 if (ipaddr->vb_ip.af != thread->ctx.fd_config.src_ipaddr.af) {
2797 RDEBUG("Invalid destination IP address family in %pV", ipaddr);
2798 return XLAT_ACTION_DONE;
2799 }
2800
2801 home = fr_rb_find(&thread->bio.expires.tree, &(home_server_t) {
2802 .ctx = {
2803 .fd_config = (fr_bio_fd_config_t) {
2804 .dst_ipaddr = ipaddr->vb_ip,
2805 .dst_port = port->vb_uint16,
2806 },
2807 },
2808 });
2809 if (!home) {
2810 MEM(home = talloc(thread, home_server_t));
2811
2812 *home = (home_server_t) {
2813 .ctx = (bio_handle_ctx_t) {
2814 .el = unlang_interpret_event_list(request),
2815 .module_name = inst->name,
2816 .inst = inst,
2817 },
2818 };
2819
2820 /*
2821 * Copy the home server configuration from the root configuration. Then update it with
2822 * the needs of the home server.
2823 */
2824 home->ctx.fd_config = inst->fd_config;
2825 home->ctx.fd_config.type = FR_BIO_FD_CONNECTED;
2826 home->ctx.fd_config.dst_ipaddr = ipaddr->vb_ip;
2827 home->ctx.fd_config.dst_port = port->vb_uint32;
2828
2829 home->ctx.radius_ctx = (fr_radius_ctx_t) {
2830 .secret = talloc_strdup(home, secret->vb_strvalue),
2831 .secret_length = secret->vb_length,
2832 .proxy_state = inst->common_ctx.proxy_state,
2833 };
2834
2835 /*
2836 * Allocate the trunk and start it up.
2837 */
2838 home->ctx.trunk = trunk_alloc(home, unlang_interpret_event_list(request), &io_funcs,
2839 &inst->trunk_conf, inst->name, home, false);
2840 if (!home->ctx.trunk) {
2841 fail:
2842 talloc_free(home);
2843 return XLAT_ACTION_FAIL;
2844 }
2845
2846 if (!fr_rb_expire_insert(&thread->bio.expires, home, fr_time())) goto fail;
2847 } else {
2848 fr_rb_expire_t *expire = &thread->bio.expires;
2849 fr_time_t now = fr_time();
2850 home_server_t *old;
2851
2852 /*
2853 * We can't change secrets on the fly. The home
2854 * server has to expire first, and then the
2855 * secret can be changed.
2856 */
2857 if ((home->ctx.radius_ctx.secret_length != secret->vb_length) ||
2858 (strcmp(home->ctx.radius_ctx.secret, secret->vb_strvalue) != 0)) {
2859 RWDEBUG("The new secret is not the same as the old secret: Ignoring the new one");
2860 }
2861
2862 fr_rb_expire_update(expire, home, now);
2863
2864 while ((old = fr_dlist_head(&expire->head)) != NULL) {
2865 (void) talloc_get_type_abort(old, home_server_t);
2866
2867 fr_assert(old->ctx.trunk);
2868
2869 /*
2870 * Don't delete the home server we're about to use.
2871 */
2872 if (old == home) break;
2873
2874 /*
2875 * It still has a request allocated, do nothing.
2876 */
2877 if (old->ctx.trunk->req_alloc) break;
2878
2879 /*
2880 * Not yet time to expire.
2881 */
2882 if (fr_time_gt(old->expire.when, now)) break;
2883
2884 fr_dlist_remove(&expire->head, old);
2885 fr_rb_delete(&expire->tree, old);
2886 }
2887 }
2888
2889 /*
2890 * Enqueue the packet on the per-home-server trunk.
2891 */
2892 rcode = mod_enqueue(&u, &retry_config, inst, home->ctx.trunk, request);
2893 if (rcode == 0) return XLAT_ACTION_DONE;
2894
2895 if (rcode < 0) {
2896 REDEBUG("Failed enqueuing packet");
2897 return XLAT_ACTION_FAIL;
2898 }
2899 fr_assert(u != NULL);
2900 fr_assert(retry_config != NULL);
2901
2902 /*
2903 * Start the retry.
2904 *
2905 * @todo - change unlang_xlat_timeout_add() to unlang_xlat_retry_add().
2906 */
2907 fr_retry_init(&u->retry, fr_time(), retry_config);
2908
2911 u, retry_config);
2912}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
static int const char char buffer[256]
Definition acutest.h:576
int const char * file
Definition acutest.h:702
va_list args
Definition acutest.h:770
int const char int line
Definition acutest.h:702
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.
Definition base.h:173
static ssize_t fr_bio_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read raw data from a bio.
Definition base.h:150
void * uctx
user ctx, caller can manually set it.
Definition base.h:114
#define fr_bio_error(_x)
Definition base.h:193
#define NDEBUG_UNUSED
Definition build.h:328
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define CMP_PREFER_SMALLER(_a, _b)
Evaluates to +1 for a > b, and -1 for a < b.
Definition build.h:104
#define CC_NO_UBSAN(_sanitize)
Definition build.h:428
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:112
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
connection_state_t
Definition connection.h:47
@ CONNECTION_STATE_FAILED
Connection has failed.
Definition connection.h:56
@ CONNECTION_STATE_CONNECTED
File descriptor is open (ready for writing).
Definition connection.h:54
@ CONNECTION_STATE_INIT
Init state, sets up connection.
Definition connection.h:51
@ CONNECTION_STATE_CONNECTING
Waiting for connection to establish.
Definition connection.h:52
@ CONNECTION_FAILED
Connection is being reconnected because it failed.
Definition connection.h:85
Holds a complete set of functions for a connection.
Definition connection.h:193
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:514
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:408
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:202
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition debug.h:208
#define MEM(x)
Definition debug.h:36
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
Definition defs.h:43
@ FR_RADIUS_CODE_ACCESS_REQUEST
RFC2865 - Access-Request.
Definition defs.h:33
@ FR_RADIUS_CODE_MAX
Maximum possible protocol code.
Definition defs.h:53
@ FR_RADIUS_CODE_DISCONNECT_ACK
RFC3575/RFC5176 - Disconnect-Ack (positive)
Definition defs.h:47
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
Definition defs.h:34
@ FR_RADIUS_CODE_ACCOUNTING_RESPONSE
RFC2866 - Accounting-Response.
Definition defs.h:37
@ FR_RADIUS_CODE_COA_NAK
RFC3575/RFC5176 - CoA-Nak (not willing to perform)
Definition defs.h:51
@ FR_RADIUS_CODE_COA_ACK
RFC3575/RFC5176 - CoA-Ack (positive)
Definition defs.h:50
@ FR_RADIUS_CODE_DISCONNECT_NAK
RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
Definition defs.h:48
@ FR_RADIUS_CODE_PROTOCOL_ERROR
RFC7930 - Protocol-Error (generic NAK)
Definition defs.h:52
@ FR_RADIUS_CODE_ACCOUNTING_REQUEST
RFC2866 - Accounting-Request.
Definition defs.h:36
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
Definition defs.h:35
static fr_dict_attr_t const * attr_packet_type
Definition dhcpclient.c:89
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
bool fr_dict_compatible(fr_dict_t const *dict1, fr_dict_t const *dict2)
See if two dictionaries have the same end parent.
Definition dict_util.c:2622
static fr_slen_t in
Definition dict.h:841
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.
Definition dlist.h:486
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:638
#define fr_event_fd_insert(...)
Definition event.h:248
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.
Definition event.h:151
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()
Definition fd.c:1182
fr_bio_t * fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_fd_config_t const *cfg, size_t offset)
Allocate a FD bio.
Definition fd.c:966
fr_bio_fd_info_t const * fr_bio_fd_info(fr_bio_t *bio)
Returns a pointer to the bio-specific information.
Definition fd.c:1279
int fr_bio_fd_write_only(fr_bio_t *bio)
Mark up a bio as write-only.
Definition fd.c:1332
fr_socket_t socket
as connected socket
Definition fd.h:130
char const * name
printable name of this BIO
Definition fd.h:135
uint16_t src_port
our port
Definition fd.h:92
bool eof
are we at EOF?
Definition fd.h:139
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
Definition fd.h:68
fr_bio_fd_state_t state
connecting, open, closed, etc.
Definition fd.h:133
uint16_t src_port_start
limit source port ranges for client BIOs
Definition fd.h:95
@ FR_BIO_FD_STATE_CONNECTING
Definition fd.h:60
@ FR_BIO_FD_STATE_OPEN
error states must be before this
Definition fd.h:59
int connect_errno
from connect() or other APIs
Definition fd.h:141
fr_ipaddr_t dst_ipaddr
their IP address
Definition fd.h:90
int socket_type
SOCK_STREAM or SOCK_DGRAM.
Definition fd.h:84
uint16_t dst_port
their port
Definition fd.h:93
fr_socket_t socket
socket information, including FD.
Definition fd.h:52
bool write_blocked
did we block on write?
Definition fd.h:138
fr_ipaddr_t src_ipaddr
our IP address
Definition fd.h:89
Configuration for sockets.
Definition fd.h:81
Run-time status of the socket.
Definition fd.h:129
Per-packet context.
Definition fd.h:51
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1347
int af
Address family.
Definition inet.h:64
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1612
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:2009
Minimal data structure to use the new code.
Definition listen.h:59
static bool fr_pair_encode_is_error(ssize_t slen)
Determine if the return code for an encoding function is a fatal error.
Definition pair.h:74
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition base.c:151
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.
Definition mem.c:723
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.
Definition mem.c:901
HIDDEN fr_dict_attr_t const * attr_eap_message
Definition base.c:96
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.
Definition log.c:828
#define PERROR(_fmt,...)
Definition log.h:228
#define DEBUG3(_fmt,...)
Definition log.h:266
#define RWDEBUG(fmt,...)
Definition log.h:361
#define RWARN(fmt,...)
Definition log.h:297
#define RERROR(fmt,...)
Definition log.h:298
#define DEBUG4(_fmt,...)
Definition log.h:267
#define RPERROR(fmt,...)
Definition log.h:302
#define RINFO(fmt,...)
Definition log.h:296
#define RPEDEBUG(fmt,...)
Definition log.h:376
#define HEXDUMP3(_data, _len, _fmt,...)
Definition log.h:723
#define RHEXDUMP3(_data, _len, _fmt,...)
Definition log.h:705
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.
Definition map.c:1590
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.
Definition map.c:1869
talloc_free(reap)
Stores all information relating to an event list.
Definition event.c:377
fr_log_t default_log
Definition log.c:292
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.
Definition log.c:581
@ L_DBG_LVL_3
3rd highest priority debug messages (-xxx | -Xx).
Definition log.h:72
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
Definition log.h:71
fr_log_type_t
Definition log.h:54
@ L_ERR
Error message.
Definition log.h:56
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition packet.c:38
fr_bio_verify_action_t
Status returned by the verification callback.
Definition mem.h:32
@ FR_BIO_VERIFY_ERROR_CLOSE
fatal error, the bio should be closed.
Definition mem.h:36
@ FR_BIO_VERIFY_DISCARD
the packet should be discarded
Definition mem.h:34
@ FR_BIO_VERIFY_OK
packet is OK
Definition mem.h:33
@ FR_BIO_VERIFY_WANT_MORE
not enough data for one packet
Definition mem.h:35
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.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * thread
Thread specific instance data.
Definition module_ctx.h:43
void * rctx
Resume ctx that a module previously set.
Definition module_ctx.h:45
fr_event_list_t * el
Event list to register any IO handlers and timers against.
Definition module_ctx.h:68
void * thread
Thread instance data.
Definition module_ctx.h:67
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:64
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Temporary structure to hold arguments for thread_instantiation calls.
Definition module_ctx.h:63
struct bio_thread_t::@184 bio
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)
Definition bio.c:2386
fr_bio_fd_config_t fd_config
for threads or sockets
Definition bio.c:45
static int8_t request_prioritise(void const *one, void const *two)
Definition bio.c:1033
static void do_retry(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_retry_t const *retry)
Definition bio.c:1427
fr_timer_t * ev
timer for retransmissions
Definition bio.c:128
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.
Definition bio.c:1324
static void request_replicate_mux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Definition bio.c:2064
static void conn_init_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
Connection errored.
Definition bio.c:325
static void request_demux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Definition bio.c:1910
static void conn_discard(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
Read and discard data.
Definition bio.c:917
uint8_t id
Last ID assigned to this packet.
Definition bio.c:122
static void request_replicate_demux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Definition bio.c:2081
uint32_t max_packet_size
Our max packet size. may be different from the parent.
Definition bio.c:82
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)
Definition bio.c:617
uint32_t num_replies
number of reply packets, sent is in retry.count
Definition bio.c:114
static const trunk_io_funcs_t io_funcs
Definition bio.c:2526
uint32_t priority
copied from request->async->priority
Definition bio.c:111
static rlm_rcode_t radius_code_to_rcode[FR_RADIUS_CODE_MAX]
Turn a reply code into a module rcode;.
Definition bio.c:141
static void conn_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
Connection errored.
Definition bio.c:952
char const * module_name
the module that opened the connection
Definition bio.c:41
fr_bio_fd_info_t const * fd_info
status of the FD.
Definition bio.c:46
struct bio_handle_t::@185 bio
static void mod_signal(module_ctx_t const *mctx, UNUSED request_t *request, fr_signal_t action)
Definition bio.c:2307
uint8_t last_id
Used when replicating to ensure IDs are distributed evenly.
Definition bio.c:79
static void mod_retry(module_ctx_t const *mctx, request_t *request, fr_retry_t const *retry)
Handle module retries.
Definition bio.c:1419
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.
Definition bio.c:1072
static void conn_close(UNUSED fr_event_list_t *el, void *handle, UNUSED void *uctx)
Shutdown/close a file descriptor.
Definition bio.c:832
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)
Definition bio.c:964
static int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id)
Definition bio.c:1139
fr_time_t last_reply
When we last received a reply.
Definition bio.c:90
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.
Definition bio.c:2233
int fd
File descriptor.
Definition bio.c:68
bio_request_t * status_u
for sending status check packets
Definition bio.c:98
bio_handle_ctx_t ctx
common struct for home servers and BIO handles
Definition bio.c:51
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)
Definition bio.c:636
static void mod_write(request_t *request, trunk_request_t *treq, bio_handle_t *h)
Definition bio.c:1519
#define REQUIRE_MA(_h)
fr_pair_list_t extra
VPs for debugging, like Proxy-State.
Definition bio.c:119
bool proxied
is this request being proxied
Definition bio.c:117
size_t buflen
Receive buffer length.
Definition bio.c:85
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.
Definition bio.c:408
fr_time_t last_idle
last time we had nothing to do
Definition bio.c:93
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.
Definition bio.c:184
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)
Definition bio.c:2629
radius_track_entry_t * rr
ID tracking, resend count, etc.
Definition bio.c:127
size_t packet_len
Length of the packet.
Definition bio.c:124
static int _bio_handle_free(bio_handle_t *h)
Free a connection handle, closing associated resources.
Definition bio.c:600
size_t partial
partially sent data
Definition bio.c:125
fr_event_list_t * el
Event list.
Definition bio.c:43
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.
Definition bio.c:2201
static void home_server_free(void *data)
Definition bio.c:2519
static void protocol_error_reply(bio_request_t *u, bio_handle_t *h)
Deal with Protocol-Error replies, and possible negotiation.
Definition bio.c:1732
static void status_check_reset(bio_handle_t *h, bio_request_t *u)
Reset a status_check packet, ready to reuse.
Definition bio.c:220
static const trunk_io_funcs_t io_replicate_funcs
Definition bio.c:2538
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.
Definition bio.c:2255
fr_time_t recv_time
copied from request->async->recv_time
Definition bio.c:112
fr_retry_t retry
retransmission timers
Definition bio.c:129
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)
Definition bio.c:2779
rlm_rcode_t rcode
from the transport
Definition bio.c:108
static void status_check_alloc(bio_handle_t *h)
Definition bio.c:237
fr_time_t mrs_time
Most recent sent time which had a reply.
Definition bio.c:89
bool status_checking
whether we're doing status checks
Definition bio.c:97
trunk_t * trunk
trunk handler
Definition bio.c:44
fr_time_t last_sent
last time we sent a packet.
Definition bio.c:92
static void zombie_timeout(fr_timer_list_t *tl, fr_time_t now, void *uctx)
Mark a connection dead after "zombie_interval".
Definition bio.c:1266
bio_handle_ctx_t ctx
for copying to bio_handle_t
Definition bio.c:133
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Instantiate thread data for the submodule.
Definition bio.c:2553
static void bio_error(fr_bio_t *bio)
Definition bio.c:626
static void status_check_reply(trunk_request_t *treq, fr_time_t now)
Deal with replies replies to status checks and possible negotiation.
Definition bio.c:1862
static void conn_init_next(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
Perform the next step of init and negotiation.
Definition bio.c:394
bool is_retry
Definition bio.c:109
static int _bio_request_free(bio_request_t *u)
Free a bio_request_t.
Definition bio.c:2365
connection_t * conn
Definition bio.c:77
fr_time_t first_sent
first time we sent a packet since going idle
Definition bio.c:91
static unlang_action_t mod_resume(unlang_result_t *p_result, module_ctx_t const *mctx, UNUSED request_t *request)
Resume execution of the request, returning the rcode set during trunk execution.
Definition bio.c:2295
fr_timer_t * zombie_ev
Zombie timeout.
Definition bio.c:95
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)
Definition bio.c:888
static void xlat_sendto_retry(xlat_ctx_t const *xctx, request_t *request, fr_retry_t const *retry)
Definition bio.c:2768
static void bio_request_reset(bio_request_t *u)
Clear out any connection specific resources from a udp request.
Definition bio.c:203
trunk_request_t * treq
Definition bio.c:107
static xlat_action_t xlat_sendto_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
Definition bio.c:2740
static void status_check_next(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
Handle retries for a status check.
Definition bio.c:1847
rlm_radius_t const * inst
our instance
Definition bio.c:42
static connection_state_t conn_init(void **h_out, connection_t *conn, void *uctx)
Initialise a new outbound connection.
Definition bio.c:711
fr_rb_expire_node_t expire
Definition bio.c:135
static void revive_timeout(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
Revive a connection after "revive_interval".
Definition bio.c:1254
uint8_t * packet
Packet we write to the network.
Definition bio.c:123
static void conn_init_timeout(UNUSED fr_timer_list_t *tl, fr_time_t now, void *uctx)
Status check timer when opening the connection for the first time.
Definition bio.c:346
static connection_state_t conn_failed(void *handle, connection_state_t state, UNUSED void *uctx)
Connection failed.
Definition bio.c:861
fr_radius_ctx_t radius_ctx
Definition bio.c:47
radius_track_t * tt
RADIUS ID tracking structure.
Definition bio.c:87
static void mod_dup(request_t *request, bio_request_t *u)
Definition bio.c:1383
bio_handle_ctx_t ctx
common struct for home servers and BIO handles
Definition bio.c:66
static int8_t home_server_cmp(void const *one, void const *two)
Dynamic home server code.
Definition bio.c:2728
uint8_t code
Packet code.
Definition bio.c:121
static void request_mux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Definition bio.c:1500
uint8_t * buffer
Receive buffer.
Definition bio.c:84
request_t * status_request
Definition bio.c:99
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.
Definition bio.c:2277
bool status_check
is this packet a status check?
Definition bio.c:116
static xlat_arg_parser_t const xlat_radius_send_args[]
Definition bio.c:2619
static void xlat_sendto_signal(xlat_ctx_t const *xctx, request_t *request, fr_signal_t action)
Definition bio.c:2757
Track the handle, which is tightly correlated with the FD.
Definition bio.c:65
Connect request_t to local tracking structure.
Definition bio.c:106
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)
Definition nbo.h:146
#define RADIUS_HEADER_LENGTH
Definition net.h:80
#define RADIUS_AUTH_VECTOR_LENGTH
Definition net.h:89
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.
Definition pair.c:2936
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
Definition pair.c:2636
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.
Definition pair.c:697
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1342
int fr_pair_delete_by_da(fr_pair_list_t *list, fr_dict_attr_t const *da)
Delete matching pairs from the specified list.
Definition pair.c:1686
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.
Definition pair.c:287
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
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)
Definition base.c:1109
int fr_radius_sign(uint8_t *packet, uint8_t const *vector, uint8_t const *secret, size_t secret_len)
Sign a previously encoded packet.
Definition base.c:360
ssize_t fr_radius_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_radius_encode_ctx_t *packet_ctx)
Definition base.c:974
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition base.c:114
#define fr_assert(_expr)
Definition rad_assert.h:38
static fr_dict_t const * dict_radius
static char * secret
static fr_dict_attr_t const * attr_proxy_state
Definition radclient.c:128
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG(fmt,...)
Definition radclient.h:53
#define WARN(fmt,...)
Definition radclient.h:47
#define INFO(fmt,...)
Definition radict.c:54
@ FR_RADIUS_REQUIRE_MA_YES
Require Message-Authenticator.
Definition radius.h:64
@ FR_RADIUS_REQUIRE_MA_AUTO
Only require Message-Authenticator if we've previously received a packet from this client with Messag...
Definition radius.h:65
#define RADIUS_AUTH_VECTOR_OFFSET
Definition radius.h:33
fr_radius_decode_fail_t
Failure reasons.
Definition radius.h:162
@ DECODE_FAIL_UNKNOWN
Definition radius.h:179
@ DECODE_FAIL_NONE
Definition radius.h:163
@ DECODE_FAIL_MA_MISSING
Definition radius.h:176
@ DECODE_FAIL_UNKNOWN_PACKET_CODE
Definition radius.h:169
char const * secret
Definition radius.h:95
#define RADIUS_MAX_PACKET_SIZE
Definition radius.h:41
size_t secret_length
Definition radius.h:96
fr_radius_ctx_t const * common
Definition radius.h:125
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
Definition radius.h:129
static rs_t * conf
Definition radsniff.c:53
static fr_dict_attr_t const * attr_extended_attribute_1
Definition radsnmp.c:108
static fr_dict_attr_t const * attr_message_authenticator
Definition radsnmp.c:112
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:105
Smaller fast random number generator.
Definition rand.h:54
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.
Definition rb.c:577
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
Definition rb.c:741
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.
Definition rb_expire.c:39
void fr_rb_expire_update(fr_rb_expire_t *expire, void *data, fr_time_t now)
Definition rb_expire.c:55
#define fr_rb_expire_inline_talloc_init(_expire, _type, _field, _data_cmp, _data_free, _lifetime)
Definition rb_expire.h:50
fr_dlist_head_t head
Definition rb_expire.h:35
fr_rb_tree_t tree
Definition rb_expire.h:34
dlist for expiring old entries
Definition rb_expire.h:44
#define RETURN_UNLANG_RCODE(_rcode)
Definition rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:45
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:44
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:43
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:51
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition rcode.h:46
#define request_local_alloc_external(_ctx, _args)
Allocate a new external request outside of the request pool.
Definition request.h:335
Optional arguments for initialising requests.
Definition request.h:287
static fr_dict_attr_t const * attr_error_cause
Definition rlm_radius.c:192
static int radius_fixups(rlm_radius_t const *inst, request_t *request)
Do any RADIUS-layer fixups for proxying.
Definition rlm_radius.c:523
static fr_dict_attr_t const * attr_nas_identifier
Definition rlm_radius.c:197
static fr_dict_attr_t const * attr_original_packet_code
Definition rlm_radius.c:198
static fr_dict_attr_t const * attr_event_timestamp
Definition rlm_radius.c:193
static fr_dict_attr_t const * attr_response_length
Definition rlm_radius.c:199
fr_radius_require_ma_t require_message_authenticator
Require Message-Authenticator in responses.
Definition rlm_radius.h:80
fr_time_delta_t revive_interval
Definition rlm_radius.h:60
fr_retry_config_t retry[FR_RADIUS_CODE_MAX]
Definition rlm_radius.h:92
char const * name
Definition rlm_radius.h:56
uint32_t status_check
code of status-check type
Definition rlm_radius.h:84
rlm_radius_mode_t mode
proxy, client, etc.
Definition rlm_radius.h:76
@ RLM_RADIUS_MODE_XLAT_PROXY
Definition rlm_radius.h:47
@ RLM_RADIUS_MODE_INVALID
Definition rlm_radius.h:42
@ RLM_RADIUS_MODE_PROXY
Definition rlm_radius.h:43
@ RLM_RADIUS_MODE_REPLICATE
Definition rlm_radius.h:45
@ RLM_RADIUS_MODE_UNCONNECTED_REPLICATE
Definition rlm_radius.h:46
@ RLM_RADIUS_MODE_CLIENT
Definition rlm_radius.h:44
uint32_t max_packet_size
Maximum packet size.
Definition rlm_radius.h:66
fr_time_delta_t response_window
Definition rlm_radius.h:58
uint32_t max_attributes
Maximum number of attributes to decode in response.
Definition rlm_radius.h:78
fr_time_delta_t zombie_period
Definition rlm_radius.h:59
static conf_parser_t retry_config[]
Definition rlm_tacacs.c:39
int fr_schedule_worker_id(void)
Return the worker id for the current thread.
Definition schedule.c:157
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.
Definition module.h:291
#define pair_append_request(_attr, _da)
Allocate and append a fr_pair_t to the request list.
Definition pair.h:37
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_DUP
A duplicate request was received.
Definition signal.h:44
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
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.
Definition state_test.c:8
Definition log.h:96
Value pair map.
Definition map.h:77
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define talloc_get_type_abort_const
Definition talloc.h:287
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:229
#define fr_time_gteq(_a, _b)
Definition time.h:238
static int64_t fr_time_unwrap(fr_time_t time)
Definition time.h:146
#define fr_time_wrap(_time)
Definition time.h:145
#define fr_time_lteq(_a, _b)
Definition time.h:240
#define fr_time_eq(_a, _b)
Definition time.h:241
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
#define fr_time_gt(_a, _b)
Definition time.h:237
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition time.h:229
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)
Definition time.h:688
#define fr_time_lt(_a, _b)
Definition time.h:239
"server local" time.
Definition time.h:69
An event timer list.
Definition timer.c:50
A timer event.
Definition timer.c:84
#define FR_TIMER_DELETE_RETURN(_ev_p)
Definition timer.h:110
#define FR_TIMER_DISARM(_ev)
Definition timer.h:91
static bool fr_timer_armed(fr_timer_t *ev)
Definition timer.h:120
#define fr_timer_at(...)
Definition timer.h:81
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.
Definition track.c:294
int radius_track_entry_update(radius_track_entry_t *te, uint8_t const *vector)
Update a tracking entry with the authentication vector.
Definition track.c:219
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.
Definition track.c:248
radius_track_t * radius_track_alloc(TALLOC_CTX *ctx)
Create an radius_track_t.
Definition track.c:41
#define radius_track_entry_release(_te)
Definition track.h:90
void * uctx
Result/resumption context.
Definition track.h:47
uint8_t id
our ID
Definition track.h:50
unsigned int num_requests
number of requests in the allocation
Definition track.h:65
#define radius_track_entry_reserve(_te_out, _ctx, _tt, _request, _code, _uctx)
Definition track.h:82
request_t * request
as always...
Definition track.h:45
Track one request to a response.
Definition track.h:36
void trunk_connection_callback_readable(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
Standard I/O read function.
Definition trunk.c:4015
void trunk_connection_callback_writable(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
Standard I/O write function.
Definition trunk.c:4032
void trunk_request_signal_partial(trunk_request_t *treq)
Signal a partial write.
Definition trunk.c:2030
void trunk_request_signal_fail(trunk_request_t *treq)
Signal that a trunk request failed.
Definition trunk.c:2133
trunk_request_t * trunk_request_alloc(trunk_t *trunk, request_t *request)
(Pre-)Allocate a new trunk request
Definition trunk.c:2475
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.
Definition trunk.c:4947
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.
Definition trunk.c:2011
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.
Definition trunk.c:2742
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.
Definition trunk.c:2588
trunk_enqueue_t trunk_request_requeue(trunk_request_t *treq)
Re-enqueue a request on the same connection.
Definition trunk.c:2677
int trunk_connection_pop_request(trunk_request_t **treq_out, trunk_connection_t *tconn)
Pop a request off a connection's pending queue.
Definition trunk.c:3884
void trunk_request_signal_cancel(trunk_request_t *treq)
Cancel a trunk request.
Definition trunk.c:2153
void trunk_request_free(trunk_request_t **treq_to_free)
If the trunk request is freed then update the target requests.
Definition trunk.c:2323
void trunk_connection_signal_active(trunk_connection_t *tconn)
Signal a trunk connection is no longer full.
Definition trunk.c:3961
void trunk_connection_signal_inactive(trunk_connection_t *tconn)
Signal a trunk connection cannot accept more requests.
Definition trunk.c:3938
void trunk_request_signal_sent(trunk_request_t *treq)
Signal that the request was written to a connection successfully.
Definition trunk.c:2051
void trunk_request_signal_complete(trunk_request_t *treq)
Signal that a trunk request is complete.
Definition trunk.c:2095
void trunk_connection_signal_reconnect(trunk_connection_t *tconn, connection_reason_t reason)
Signal a trunk connection is no longer viable.
Definition trunk.c:4000
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)
Definition trunk.c:2829
Associates request queues with a connection.
Definition trunk.c:133
Wraps a normal request.
Definition trunk.c:99
Main trunk management handle.
Definition trunk.c:197
#define TRUNK_REQUEST_STATE_ALL
All request states.
Definition trunk.h:195
trunk_connection_alloc_t connection_alloc
Allocate a new connection_t.
Definition trunk.h:733
trunk_connection_event_t
What type of I/O events the trunk connection is currently interested in receiving.
Definition trunk.h:72
@ TRUNK_CONN_EVENT_BOTH
Trunk should be notified if a connection is readable or writable.
Definition trunk.h:79
@ TRUNK_CONN_EVENT_WRITE
Trunk should be notified if a connection is writable.
Definition trunk.h:77
@ TRUNK_CONN_EVENT_NONE
Don't notify the trunk on connection state changes.
Definition trunk.h:73
@ TRUNK_CONN_EVENT_READ
Trunk should be notified if a connection is readable.
Definition trunk.h:75
trunk_cancel_reason_t
Reasons for a request being cancelled.
Definition trunk.h:55
@ TRUNK_CANCEL_REASON_REQUEUE
A previously sent request is being requeued.
Definition trunk.h:59
@ TRUNK_ENQUEUE_DST_UNAVAILABLE
Destination is down.
Definition trunk.h:153
@ TRUNK_ENQUEUE_FAIL
General failure.
Definition trunk.h:154
@ TRUNK_ENQUEUE_OK
Operation was successful.
Definition trunk.h:150
@ TRUNK_ENQUEUE_NO_CAPACITY
At maximum number of connections, and no connection has capacity.
Definition trunk.h:151
@ TRUNK_ENQUEUE_IN_BACKLOG
Request should be enqueued in backlog.
Definition trunk.h:149
trunk_request_state_t
Used for sanity checks and to simplify freeing.
Definition trunk.h:161
@ TRUNK_REQUEST_STATE_PARTIAL
Some of the request was written to the socket, more of it should be written later.
Definition trunk.h:170
@ TRUNK_REQUEST_STATE_REAPABLE
Request has been written, needs to persist, but we are not currently waiting for any response.
Definition trunk.h:173
@ TRUNK_REQUEST_STATE_UNASSIGNED
Transition state - Request currently not assigned to any connection.
Definition trunk.h:165
@ TRUNK_REQUEST_STATE_INIT
Initial state.
Definition trunk.h:162
@ TRUNK_REQUEST_STATE_CANCEL_SENT
We've informed the remote server that the request has been cancelled.
Definition trunk.h:185
@ TRUNK_REQUEST_STATE_COMPLETE
The request is complete.
Definition trunk.h:182
@ TRUNK_REQUEST_STATE_FAILED
The request failed.
Definition trunk.h:183
@ TRUNK_REQUEST_STATE_CANCEL
A request on a particular socket was cancel.
Definition trunk.h:184
@ TRUNK_REQUEST_STATE_CANCEL_PARTIAL
We partially wrote a cancellation request.
Definition trunk.h:187
@ TRUNK_REQUEST_STATE_BACKLOG
In the backlog.
Definition trunk.h:167
@ TRUNK_REQUEST_STATE_CANCEL_COMPLETE
Remote server has acknowledged our cancellation.
Definition trunk.h:188
@ TRUNK_REQUEST_STATE_PENDING
In the queue of a connection and is pending writing.
Definition trunk.h:168
@ TRUNK_REQUEST_STATE_SENT
Was written to a socket. Waiting for a response.
Definition trunk.h:172
I/O functions to pass to trunk_alloc.
Definition trunk.h:732
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.
Definition xlat.c:668
uint8_t required
Argument must be present, and non-empty.
Definition xlat.h:146
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition xlat.h:383
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:170
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumend by an xlat function.
Definition xlat.h:145
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.
Definition retry.c:108
void fr_retry_init(fr_retry_t *r, fr_time_t now, fr_retry_config_t const *config)
Initialize a retransmission counter.
Definition retry.c:36
fr_time_t start
when we started the retransmission
Definition retry.h:53
fr_time_delta_t rt
retransmit interval
Definition retry.h:57
uint32_t mrc
Maximum retransmission count.
Definition retry.h:36
fr_retry_config_t const * config
master configuration
Definition retry.h:52
fr_retry_state_t state
so callers can see what state it's in.
Definition retry.h:60
@ FR_RETRY_MRC
reached maximum retransmission count
Definition retry.h:47
@ FR_RETRY_CONTINUE
Definition retry.h:46
@ FR_RETRY_MRD
reached maximum retransmission duration
Definition retry.h:48
uint32_t count
number of sent packets
Definition retry.h:58
fr_time_delta_t mrd
Maximum retransmission duration.
Definition retry.h:35
fr_time_t updated
last update, really a cached "now".
Definition retry.h:56
fr_time_t next
when the next timer should be set
Definition retry.h:55
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h:78
int fd
File descriptor if this is a live socket.
Definition socket.h:81
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:642
static fr_slen_t data
Definition value.h:1290
#define fr_box_time_delta(_val)
Definition value.h:364
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1022
void * rctx
Resume context.
Definition xlat_ctx.h:54
module_ctx_t const * mctx
Synthesised module calling ctx.
Definition xlat_ctx.h:52
An xlat calling ctx.
Definition xlat_ctx.h:49