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