The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
bio.c
Go to the documentation of this file.
1/*
2 * This program 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: f63e1d9f18c596d9f71d513d0101be24493ed9d3 $
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/server/connection.h>
30#include <freeradius-devel/unlang/function.h>
31#include <freeradius-devel/unlang/load_balance_priv.h>
32#include <freeradius-devel/unlang/subrequest.h>
33#include <freeradius-devel/util/heap.h>
34#include <freeradius-devel/util/rb_expire.h>
35
36
37//#include "rlm_radius.h"
38#include "track.h"
39
40typedef enum : uint8_t {
41 LIMIT_PORTS_NONE = 0, //!< Source port not restricted
42 LIMIT_PORTS_STATIC, //!< Limited source ports for static home servers
43 LIMIT_PORTS_DYNAMIC //!< Limited source ports for dynamic home servers
45
46typedef struct {
47 char const *module_name; //!< the module that opened the connection
48 rlm_radius_t const *inst; //!< our instance
49 fr_event_list_t *el; //!< Event list.
50 trunk_t *trunk; //!< trunk handler
51 fr_bio_fd_config_t fd_config; //!< for threads or sockets
52 fr_bio_fd_info_t const *fd_info; //!< status of the FD.
53 fr_radius_ctx_t radius_ctx; //!< for signing packets
54 bio_limit_ports_t limit_source_ports; //!< What type of port limit is in use.
55 bool dynamic; //!< is this a dynamic home server.
56#ifdef WITH_TLS
57 SSL_CTX *ssl_ctx; //!< TLS context for this thread, NULL if we don't use TLS.
58#endif
60
61typedef struct {
62 bio_handle_ctx_t ctx; //!< common struct for home servers and BIO handles
63
64 struct {
65 fr_bio_t *fd; //!< writing
66 uint32_t id; //!< for replication
67 fr_rb_expire_t expires; //!< for proxying / client sending
68 } bio;
69
73
75
76/** Track the handle, which is tightly correlated with the FD
77 *
78 */
79typedef struct {
80 bio_handle_ctx_t ctx; //!< common struct for home servers and BIO handles
81
82 int fd; //!< File descriptor.
83
84 bool eof; //!< The BIO chain is at EOF, see bio_eof().
85
86 bool write_blocked; //!< A stream write blocked, and has not yet resumed. See
87 ///< bio_write_blocked() and bio_write_resume().
88
89 struct {
90 fr_bio_t *main; //!< what we use for IO
91 fr_bio_t *fd; //!< raw FD
92 fr_bio_t *mem; //!< memory wrappers for stream sockets
93#ifdef WITH_TLS
94 fr_bio_tls_t *tls; //!< TLS BIO.
95#endif
96 } bio;
97
99
100 uint8_t last_id; //!< Used when replicating to ensure IDs are distributed
101 ///< evenly.
102
103 uint32_t max_packet_size; //!< Our max packet size. may be different from the parent.
104
105 uint8_t *buffer; //!< Receive buffer.
106 size_t buflen; //!< Receive buffer length.
107
108 radius_track_t *tt; //!< RADIUS ID tracking structure.
109
110 fr_time_t mrs_time; //!< Most recent sent time which had a reply.
111 fr_time_t last_reply; //!< When we last received a reply.
112 fr_time_t first_sent; //!< first time we sent a packet since going idle
113 fr_time_t last_sent; //!< last time we sent a packet.
114 fr_time_t last_idle; //!< last time we had nothing to do
115
116 fr_timer_t *zombie_ev; //!< Zombie timeout.
117 unlang_t const *instruction; //!< Instruction which triggered the start of the zombie period.
118
119 bool status_checking; //!< whether we're doing status checks
120 bio_request_t *status_u; //!< for sending status check packets
122
123#ifdef WITH_TLS
124 request_t *conn_request; //!< owns the TLS bio, and runs the handshake. This is
125 ///< separate from status_request.
126 bool tls_starting; //!< Are we inside of fr_bio_tls_connect() ?
127 bool tls_started; //!< The connection request has run, and the TLS start is scheduled.
128 fr_timer_t *tls_ev; //!< Starts the TLS connection.
129 fr_timer_t *tls_failed_ev; //!< Signals the connection after the TLS connection failed.
130#endif
131
132 trunk_connection_t *tconn; //!< The trunk connection. Set by thread_conn_notify(), so it
133 ///< is NULL until the trunk has started to use the connection.
134 trunk_connection_event_t notify_on; //!< The events which the trunk last asked for.
136
137/** Is the connection at EOF?
138 *
139 * Either the whole BIO chain is at EOF, or the fd is at EOF.
140 */
141static inline CC_HINT(always_inline) bool bio_at_eof(bio_handle_t const *h)
142{
143 return h->eof || h->ctx.fd_info->eof;
144}
145
146
147/** Connect request_t to local tracking structure
148 *
149 */
152 rlm_rcode_t rcode; //!< from the transport
153
154 uint32_t priority; //!< copied from request->async->priority
155 fr_time_t recv_time; //!< copied from request->async->recv_time
156
157 uint32_t num_replies; //!< number of reply packets, sent is in retry.count
158
159 bool status_check; //!< is this packet a status check?
160 bool proxied; //!< is this request being proxied
161
162 fr_pair_list_t extra; //!< VPs for debugging, like Proxy-State.
163
164 uint8_t code; //!< Packet code.
165 uint8_t id; //!< Last ID assigned to this packet.
166 uint8_t *packet; //!< Packet we write to the network.
167 size_t packet_len; //!< Length of the packet.
168 size_t partial; //!< partially sent data
169
170 radius_track_entry_t *rr; //!< ID tracking, resend count, etc.
171 fr_timer_t *ev; //!< timer for retransmissions
172 fr_retry_t retry; //!< retransmission timers
173};
174
175typedef struct {
176 bio_handle_ctx_t ctx; //!< for copying to bio_handle_t
177
179
181 connection_t *connections[]; //!< for tracking outbound connections
183
184
185/** Turn a reply code into a module rcode;
186 *
187 */
203
205 UNUSED int flags, void *uctx);
206
208
209static fr_radius_decode_fail_t decode(TALLOC_CTX *ctx, fr_pair_list_t *reply, uint8_t *response_code,
211 uint8_t const request_authenticator[static RADIUS_AUTH_VECTOR_LENGTH],
212 uint8_t *data, size_t data_len);
213
215
217
219 trunk_connection_event_t notify_on, void *uctx);
220
221static int _bio_request_free(bio_request_t *u);
222
223static fr_cmp_ret_t home_server_cmp(void const *one, void const *two);
224
225#ifndef NDEBUG
226/** Log additional information about a tracking entry
227 *
228 * @param[in] te Tracking entry we're logging information for.
229 * @param[in] log destination.
230 * @param[in] log_type Type of log message.
231 * @param[in] file the logging request was made in.
232 * @param[in] line logging request was made on.
233 */
234static void bio_tracking_entry_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line,
236{
238
239 if (!te->request) return; /* Free entry */
240
241 request = talloc_get_type_abort(te->request, request_t);
242
243 fr_log(log, log_type, file, line, "request %s, allocated %s:%d", request->name,
244 request->alloc_file, request->alloc_line);
245
246 trunk_request_state_log(log, log_type, file, line, talloc_get_type_abort(te->uctx, trunk_request_t));
247}
248#endif
249
250/** Clear out any connection specific resources from a udp request
251 *
252 */
254{
255 TALLOC_FREE(u->packet);
257
258 /*
259 * Can have packet put no u->rr
260 * if this is part of a pre-trunk status check.
261 */
262 if (u->rr) radius_track_entry_release(&u->rr);
263
265}
266
267/** Reset a status_check packet, ready to reuse
268 *
269 */
271{
272 fr_assert(u->status_check == true);
273
274 h->status_checking = false;
275 u->num_replies = 0; /* Reset */
276 u->retry.start = fr_time_wrap(0);
277
279
281}
282
283/*
284 * Status-Server checks. Manually build the packet, and
285 * all of its associated glue.
286 */
288{
289 bio_request_t *u;
291 fr_pair_t *vp;
292 rlm_radius_t const *inst = h->ctx.inst;
293
295
297 MEM(u = talloc_zero(request, bio_request_t));
298 talloc_set_destructor(u, _bio_request_free);
299
300 h->status_u = u;
301
304
305 /*
306 * Status checks are prioritized over any other packet
307 */
308 u->priority = ~(uint32_t) 0;
309 u->status_check = true;
310
311 /*
312 * Allocate outside of the free list.
313 * There appears to be an issue where
314 * the thread destructor runs too
315 * early, and frees the freelist's
316 * head before the module destructor
317 * runs.
318 */
319 request->async = talloc_zero(request, fr_async_t);
320 request->async->request = request;
323
324 request->packet = fr_packet_alloc(request, false);
325 request->reply = fr_packet_alloc(request, false);
326
327 /*
328 * Create the VPs, and ignore any errors creating them.
329 */
330 if (map_list_num_elements(&inst->status_check_map) > 0) {
331 map_t *map = NULL;
332
333 while ((map = map_list_next(&inst->status_check_map, map))) {
334 (void) map_to_request(request, map, map_to_vp, NULL);
335 }
336 } else {
337 /*
338 * Ensure that there's a NAS-Identifier with a value.
339 *
340 * Arguably if there's no status-check map, then the request_pairs are empty. But
341 * whatever...
342 */
343 if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_nas_identifier)) {
345 fr_pair_value_strdup(vp, "status check - are you alive?", false);
346 }
347 }
348
349 /*
350 * Always add an Event-Timestamp, and update its value every time we send a packet.
351 *
352 * The retry code will later update the timestamp, too, but updating it here means that the debug
353 * output doesn't show a zero-value Event-Timstamp.
354 */
355 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_event_timestamp);
356 if (!vp) {
358 }
359 vp->vp_date = fr_time_to_unix_time(fr_time());
360
361 /*
362 * Initialize the request IO ctx. Note that we don't set
363 * destructors.
364 */
365 u->code = inst->status_check;
366 request->packet->code = u->code;
367
368 DEBUG3("%s - Status check packet type will be %s", h->ctx.module_name, fr_radius_packet_name[u->code]);
369 log_request_proto_pair_list(L_DBG_LVL_3, request, NULL, &request->request_pairs, NULL);
370}
371
372/** Connection errored
373 *
374 * We were signalled by the event loop that a fatal error occurred on this connection.
375 *
376 * @param[in] el The event list signalling.
377 * @param[in] fd that errored.
378 * @param[in] flags El flags.
379 * @param[in] fd_errno The nature of the error.
380 * @param[in] uctx The trunk connection handle (tconn).
381 */
382static void conn_init_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
383{
384 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
385 bio_handle_t *h;
386
387 /*
388 * Connection must be in the connecting state when this fires
389 */
391
392 h = talloc_get_type_abort(conn->h, bio_handle_t);
393
394 ERROR("%s - Connection %s failed: %s", h->ctx.module_name, h->ctx.fd_info->name, fr_syserror(fd_errno));
395
397}
398
399/** Status check timer when opening the connection for the first time.
400 *
401 * Setup retries, or fail the connection.
402 */
403static void conn_init_timeout(UNUSED fr_timer_list_t *tl, fr_time_t now, void *uctx)
404{
405 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
406 bio_handle_t *h;
407 bio_request_t *u;
408
409 /*
410 * Connection must be in the connecting state when this fires
411 */
413
414 h = talloc_get_type_abort(conn->h, bio_handle_t);
415 u = h->status_u;
416
417 /*
418 * We're only interested in contiguous, good, replies.
419 */
420 u->num_replies = 0;
421
422 switch (fr_retry_next(&u->retry, now)) {
423 case FR_RETRY_MRD:
424 DEBUG("%s - Reached maximum_retransmit_duration (%pVs > %pVs), failing status checks",
427 goto fail;
428
429 case FR_RETRY_MRC:
430 DEBUG("%s - Reached maximum_retransmit_count (%u > %u), failing status checks",
432 fail:
434 return;
435
437 if (fr_event_fd_insert(h, NULL, conn->el, h->fd, NULL, conn_init_writable,
438 conn_init_error, conn) < 0) {
439 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
441 }
442 return;
443 }
444
445 fr_assert(0);
446}
447
448/** Perform the next step of init and negotiation.
449 *
450 */
451static void conn_init_next(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
452{
453 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
454 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
455 bio_request_t *u = h->status_u;
456
457 /*
458 * The previous status check was answered, so start the retries again. Unlike conn_init_timeout(),
459 * we do not reset u->num_replies, as we want contiguous good replies.
460 */
462
463 if (fr_event_fd_insert(h, NULL, conn->el, h->fd, NULL, conn_init_writable, conn_init_error, conn) < 0) {
464 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
466 }
467}
468
469/** Read the connection during the init and negotiation stage.
470 *
471 */
472static void conn_init_readable(fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
473{
474 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
475 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
476 trunk_t *trunk = h->ctx.trunk;
477 rlm_radius_t const *inst = h->ctx.inst;
478 bio_request_t *u = h->status_u;
479 ssize_t slen;
481 uint8_t code = 0;
482
484 slen = fr_bio_read(h->bio.main, NULL, h->buffer, h->buflen);
485 if (slen == 0) {
486 if (bio_at_eof(h)) goto failed;
487 return;
488 }
489
490 /*
491 * We're done reading, return.
492 */
493 if (slen == fr_bio_error(IO_WOULD_BLOCK)) return;
494
495 if (slen < 0) {
496 switch (errno) {
497 case ECONNREFUSED:
498 ERROR("%s - Failed reading response from socket: there is no server listening on outgoing connection %s",
499 h->ctx.module_name, h->ctx.fd_info->name);
500 break;
501
502 default:
503 ERROR("%s - Failed reading response from socket: %s",
504 h->ctx.module_name, fr_syserror(errno));
505 break;
506 }
507
508 failed:
510 return;
511 }
512
513 /*
514 * Where we just return in this function, we're letting
515 * the response timer take care of progressing the
516 * connection attempt.
517 */
518 fr_assert(slen >= RADIUS_HEADER_LENGTH); /* checked in verify */
519
520 if (!u->packet) {
521 ERROR("%s - Received response to expired status check packet",
522 h->ctx.module_name);
523 return;
524 }
525
526 if (u->id != h->buffer[1]) {
527 ERROR("%s - Received response with incorrect or expired ID. Expected %u, got %u",
528 h->ctx.module_name, u->id, h->buffer[1]);
529 return;
530 }
531
532 if (decode(h, &reply, &code,
534 h->buffer, slen) != FR_RADIUS_FAIL_NONE) {
536 return;
537 }
538
539 fr_pair_list_free(&reply); /* FIXME - Do something with these... */
540
541 /*
542 * Process the error, and count this as a success.
543 * This is usually used for dynamic configuration
544 * on startup.
545 */
547
548 /*
549 * Last trunk event was a failure, be more careful about
550 * bringing up the connection (require multiple responses).
551 */
552 if ((fr_time_gt(trunk->last_failed, fr_time_wrap(0)) && (fr_time_gt(trunk->last_failed, trunk->last_connected))) &&
553 (u->num_replies < inst->num_answers_to_alive)) {
554 /*
555 * Leave the timer in place. This timer is BOTH when we
556 * give up on the current status check, AND when we send
557 * the next status check.
558 */
559 DEBUG("%s - Received %u / %u replies for status check, on connection - %s",
560 h->ctx.module_name, u->num_replies, inst->num_answers_to_alive, h->ctx.fd_info->name);
561 DEBUG("%s - Next status check packet will be in %pVs",
563
564 /*
565 * Set the timer for the next retransmit.
566 */
567 if (fr_timer_at(h, el->tl, &u->ev, u->retry.next, false, conn_init_next, conn) < 0) {
569 }
570 return;
571 }
572
573 /*
574 * It's alive!
575 */
576 status_check_reset(h, u);
577
578 DEBUG("%s - Connection open - %s", h->ctx.module_name, h->ctx.fd_info->name);
579
581}
582
583/** Send initial negotiation.
584 *
585 */
586static void conn_init_writable(fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
587{
588 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
589 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
590 bio_request_t *u = h->status_u;
591 ssize_t slen;
592
593 if (fr_time_eq(u->retry.start, fr_time_wrap(0))) {
594 u->id = fr_rand() & 0xff; /* We don't care what the value is here */
595 h->status_checking = true; /* Ensure this is valid */
597
598 /*
599 * Status checks can never be retransmitted
600 * So increment the ID here.
601 */
602 } else {
604 u->id++;
605 }
606
607 DEBUG("%s - Sending %s ID %d over connection %s",
609
610 if (encode(h, h->status_request, u, u->id) < 0) {
611 fail:
613 return;
614 }
615 DEBUG3("Encoded packet");
616 HEXDUMP3(u->packet, u->packet_len, NULL);
617
618 fr_assert(u->packet != NULL);
620
621 slen = fr_bio_write(h->bio.main, NULL, u->packet, u->packet_len);
622
623 if (slen == fr_bio_error(IO_WOULD_BLOCK)) goto blocked;
624
625 if (slen < 0) {
626 ERROR("%s - Failed sending %s ID %d length %zu over connection %s: %s",
628 goto fail;
629 }
630
631 /*
632 * @todo - handle partial packets and blocked writes.
633 */
634 if ((size_t)slen < u->packet_len) {
635 blocked:
636 ERROR("%s - Failed sending %s ID %d length %zu over connection %s: writing is blocked",
638 goto fail;
639 }
640
641 /*
642 * Switch to waiting on read and insert the event
643 * for the response timeout.
644 */
645 if (fr_event_fd_insert(h, NULL, conn->el, h->fd, conn_init_readable, NULL, conn_init_error, conn) < 0) {
646 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
647 goto fail;
648 }
649
650 DEBUG("%s - %s request. Expecting response within %pVs",
651 h->ctx.module_name, (u->retry.count == 1) ? "Originated" : "Retransmitted",
653
654 if (fr_timer_at(h, el->tl, &u->ev, u->retry.next, false, conn_init_timeout, conn) < 0) {
655 PERROR("%s - Failed inserting timer event", h->ctx.module_name);
656 goto fail;
657 }
658}
659
660/** Pause the connection when a stream BIO is blocked on write
661 *
662 * @return
663 * - 1 for "writes are blocked".
664 */
666{
667 bio_handle_t *h = bio->uctx;
668
669 /*
670 * @todo - the FD BIO runs the write_blocked callbacks only when the FD BIO changes from "not
671 * blocked" to "blocked". If the FD BIO is already flagged as blocked, then a write which
672 * returns IO_WOULD_BLOCK doesn't run the callback, and h->write_blocked stays false. That
673 * shouldn't happen, but there's no test for it.
674 *
675 * The solution is likely to hoist the `write_blocked` flag into a public flag in fr_bio_t. That
676 * lets us get rid of `h->write_blocked`. i.e. having multiple different flags for the same
677 * state is a source of issues.
678 */
679 h->write_blocked = true;
680
681 /*
682 * The trunk has not started to use the connection, e.g. the TCP connect or the TLS handshake is
683 * still running. The BIOs track their own blocked state.
684 */
685 if (!h->tconn) return 1;
686
687 DEBUG("%s - Writing is blocked on connection %s", h->ctx.module_name, h->ctx.fd_info->name);
688
690 thread_conn_notify(h->tconn, h->conn, h->conn->el, h->notify_on, NULL);
691
692 return 1;
693}
694
695/** Resume the connection when a stream BIO can write again.
696 *
697 * @return
698 * - 1 for "writes can resume".
699 */
701{
702 bio_handle_t *h = bio->uctx;
703
704 h->write_blocked = false;
705
706 if (!h->tconn) return 1;
707
708 DEBUG("%s - Writing is resumed on connection %s", h->ctx.module_name, h->ctx.fd_info->name);
709
711
712 /*
713 * bio_write_blocked() registered conn_writable_flush() as the write handler.
714 * The fd is almost always writable, so the handler would run in a loop. Register the events
715 * which the trunk wants.
716 */
717 thread_conn_notify(h->tconn, h->conn, h->conn->el, h->notify_on, NULL);
718
719 return 1;
720}
721
722#ifdef WITH_TLS
723/** Start the TLS connection
724 *
725 * The TLS bio needs to run the interpreter on the connection request. When the request is added to the
726 * worker, the worker runs the request function. Which is this one.
727
728 * fr_bio_tls_connect() runs the interpreter on the connection request. The interpreter asserts that the
729 * request is not in the runnable heap of the worker, and the worker adds a new request to the heap. The
730 * worker has therefore to run the request once, before the TLS connection can start. conn_request_hold() adds
731 * the timer which calls this function, and the timer runs only after the worker has finished with the request.
732 */
733static void conn_tls_start(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
734{
735 bio_handle_t *h = talloc_get_type_abort(uctx, bio_handle_t);
736 int rcode;
737
738 /*
739 * From fr_bio_tls_connect() until the "connected" callback, the TLS BIO owns the FD events. The
740 * fd bio connect and the TLS handshake both happen after fr_bio_tls_connect().
741 */
742 h->tls_starting = true;
743 rcode = fr_bio_tls_connect(h->bio.tls);
744 h->tls_starting = false;
745
746 if (rcode < 0) {
747 PERROR("%s - Failed starting the TLS connection", h->ctx.module_name);
749 }
750}
751
752/** The bottom frame of the connection request
753 *
754 * The worker runs a request which has no frames, and the interpreter asserts that the stack is not empty. This
755 * frame is the bottom of the stack. The TLS code pushes its own frame above this frame, once the TCP connection
756 * is open.
757 *
758 * The worker has finished with the request as soon as this frame yields. The function therefore asks for the
759 * TLS connection to start from an event, instead of starting the TLS connection here, as the TLS connection
760 * runs the interpreter on the request.
761 */
762static unlang_action_t conn_request_hold(UNUSED request_t *request, void *uctx)
763{
764 bio_handle_t *h = talloc_get_type_abort(uctx, bio_handle_t);
765
766 if (h->tls_started) return UNLANG_ACTION_YIELD;
767
768 h->tls_started = true;
769
770 if (fr_timer_in(h, h->conn->el->tl, &h->tls_ev, fr_time_delta_wrap(0), false, conn_tls_start, h) < 0) {
771 PERROR("%s - Failed adding a timer to start the TLS connection", h->ctx.module_name);
773 }
774
775 return UNLANG_ACTION_YIELD;
776}
777
778/** Allocate the request that owns the TLS bio.
779 *
780 * The code in src/lib/tls uses a request to handle the BIO and the TLS handshake. The TLS handshake runs the
781 * various unlang sessions for `verify certificate`, etc.
782 *
783 * This request is only used to manage the TLS state machine. The status check request is needed for UDP,
784 * and is therefore independent.
785 *
786 * The request is detached, which allows it to be managed by the worker. When the request is cancelled, it's
787 * stack is unwound, and the request is freed. As a result, the request is not owned by the handle.
788 *
789 * @param[in] h the connection handle. The fd bio MUST be allocated.
790 * @return
791 * - 0 on success.
792 * - -1 on failure.
793 */
794static int conn_request_alloc(bio_handle_t *h)
795{
797 unlang_interpret_t *intp;
798 static uint64_t number = 0;
799
800 fr_assert(h->bio.fd);
801 fr_assert(!h->conn_request);
802
804 if (!intp) {
805 ERROR("%s - No interpreter for the TLS connection request", h->ctx.module_name);
806 return -1;
807 }
808
809 MEM(request = request_local_alloc_internal(intp, &(request_init_args_t) { .detachable = true }));
810
811 MEM(request->packet = fr_packet_alloc(request, false));
812 MEM(request->reply = fr_packet_alloc(request, false));
813
814 /*
815 * The home server is the destination. The socket names it in log messages and in the
816 * session-state list.
817 */
818 request->packet->socket = h->ctx.fd_info->socket;
819
820 request->number = number++;
822 MEM(request->name = talloc_typed_asprintf(request, "%s TLS %" PRIu64, h->ctx.module_name, request->number));
823
825
826 if (unlang_function_push(request, conn_request_hold, conn_request_hold, NULL, FR_SIGNAL_NONE,
828 fail:
830 return -1;
831 }
832
833 /*
834 * Push the request onto the interpreter "runnable" queue. The worker is now responsible for the
835 * request.
836 */
838
839 /*
840 * Remove the `max_request_time` timer, which is automatically added by the worker. Instead,
841 * the request lives as long as the connection is up. Which could be a long time.
842 *
843 * When the connection is closed, the request is freed.
844 */
845 TALLOC_FREE(request->timeout);
846
847 h->conn_request = request;
848
849 return 0;
850}
851
852/** Callback to signal that the TLS connection is open.
853 *
854 */
855static void bio_tls_connected(fr_bio_t *bio)
856{
857 bio_handle_t *h = bio->uctx;
858
859 /*
860 * If we're doing status checks, then we want at least one positive response before signalling
861 * that the connection is open. The status check code is the same as for a socket without TLS.
862 *
863 * Insert an FD event to read from the socket, because the TLS BIO deleted its own "connection
864 * setup" FD events before calling this function.
865 */
866 if (h->ctx.inst->status_check) {
867 DEBUG("%s - TLS handshake finished - %s", h->ctx.module_name, h->ctx.fd_info->name);
868
870
871 if (fr_event_fd_insert(h, NULL, h->conn->el, h->fd, NULL,
873 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
875 }
876 return;
877 }
878
879 DEBUG("%s - TLS connection open - %s", h->ctx.module_name, h->ctx.fd_info->name);
880
882}
883
884/** Tell the connection that the TLS connection failed
885 *
886 * The timer runs bio_tls_failed() later, outside of the TLS code.
887 */
888static void conn_tls_failed(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
889{
890 bio_handle_t *h = talloc_get_type_abort(uctx, bio_handle_t);
891
893}
894
895/** Something in TLS failed.
896 *
897 * The TLS bio calls this function from inside of a read or a write. The TLS connection also calls this
898 * function from inside of the connection frame, which the worker runs for the connection request.
899 *
900 * Don't free the BIO, and don't signal the connection from here. Signalling the connection runs
901 * conn_close(), which frees the handle, the TLS bio, and the TLS connection, while the TLS code is still
902 * running and uses the TLS connection. Instead, run the signal from a timer. The timer is a
903 * child of the handle, so freeing the handle stops the timer.
904 *
905 * @todo - using a timer seems to be annoying and problematic. We need a better way.
906 */
907static void bio_tls_failed(fr_bio_t *bio)
908{
909 bio_handle_t *h = bio->uctx;
910 fr_tls_connection_t *tls_conn = fr_bio_tls_conn(h->bio.tls);
911
912 if (tls_conn->failed == TLS_CONNECTION_FAIL_SYSCALL) {
913 ERROR("%s - TLS connection failed - %s - %s", h->ctx.module_name, h->ctx.fd_info->name,
914 fr_syserror(tls_conn->error));
915 } else {
916 ERROR("%s - TLS connection failed - %s - %s", h->ctx.module_name, h->ctx.fd_info->name,
917 fr_table_str_by_value(fr_tls_connection_fail_table, tls_conn->failed, "<INVALID>"));
918 }
919
920 /*
921 * conn_init() is still running, and returns CONNECTION_STATE_FAILED when fr_bio_tls_connect()
922 * fails. Signalling the connection from here would make the connection code handle the same
923 * failure twice.
924 */
925 if (h->tls_starting) return;
926
927 if (fr_timer_armed(h->tls_failed_ev)) return;
928
929 if (fr_timer_in(h, h->conn->el->tl, &h->tls_failed_ev, fr_time_delta_wrap(0), false, conn_tls_failed, h) < 0) {
930 PERROR("%s - Failed adding a timer to signal the failed TLS connection", h->ctx.module_name);
931
932 /*
933 * We have no other way to update the connection. A connection which never reconnects is worse
934 * than the risk of this signal.
935 */
937 }
938}
939
940/** Allocate the TLS bio
941 *
942 * @param[in] h the connection handle. The fd bio MUST be allocated.
943 * @return
944 * - 0 on success.
945 * - -1 on failure.
946 */
947static int conn_tls_alloc(bio_handle_t *h)
948{
949 fr_tls_connection_t *tls_conn;
950
951 if (conn_request_alloc(h) < 0) return -1;
952
953 h->bio.tls = fr_bio_tls_alloc(h->conn_request, h->bio.fd, h->ctx.ssl_ctx, true, false);
954 if (!h->bio.tls) {
955 /*
956 * _bio_handle_free() expects that a connection request has a TLS bio. Without a TLS bio
957 * nothing owns the request, so cancel the request here. The worker unwinds and frees
958 * the request.
959 */
961 h->conn_request = NULL;
962 return -1;
963 }
964
965 ((fr_bio_t *) h->bio.tls)->uctx = h;
967 .connected = bio_tls_connected,
968 .failed = bio_tls_failed,
969 });
970
971 tls_conn = fr_bio_tls_conn(h->bio.tls);
972 tls_conn->name = talloc_typed_asprintf(tls_conn, "%s %s",
973 (h->ctx.fd_config.socket_type == SOCK_DGRAM) ? "DTLS" : "TLS",
974 h->ctx.fd_info->name);
975
976 return 0;
977}
978#endif
979
980/** Free a connection handle, closing associated resources
981 *
982 */
984{
985 fr_assert(h != NULL);
986
987 fr_assert(h->fd >= 0);
988
990
991#ifdef WITH_TLS
992 /*
993 * Parenting goes "connection request" -> TLS bio -> TLS connection. The TLS BIO also points to
994 * the FD BIO. The TLS bio MUST therefore be freed before the the FD bio.
995 *
996 * Freeing the TLS bio sends any TLS close_notify, deletes the fd events, and cancels the request.
997 * The interpreter then cleans it up, and frees everything.
998 *
999 * If the handle is being freed, then cancel the request. The request is allocated from the
1000 * interpreter ctx. The worker will clean up the request after it's cancelled.
1001 */
1002 h->tconn = NULL;
1003
1004 if (h->conn_request) {
1005 fr_assert(h->bio.tls);
1006
1007 /*
1008 * Before closing, forcibly write a TLS close_notify. But first delete the FD events, so
1009 * if there are any errors writing to the socket (IO error, or IO_WOULD_BLOCK), those are
1010 * ignored, and the close_notify is discarded.
1011 */
1012 (void) fr_event_fd_delete(h->conn->el, h->fd, FR_EVENT_FILTER_IO);
1013 fr_bio_tls_close_send(h->bio.tls);
1014
1015 /*
1016 * We're about to free the handle, so but the BIO sticks around until the interpreter
1017 * unwinds the cancelled request. Remove the callbacks so that they don't try to access
1018 * the freed handle.
1019 */
1020 fr_bio_cb_set((fr_bio_t *) h->bio.tls, NULL);
1021
1022 unlang_interpret_signal(h->conn_request, FR_SIGNAL_CANCEL);
1023 h->bio.tls = NULL;
1024 h->conn_request = NULL;
1025 }
1026#endif
1027
1028 /*
1029 * The connection code will take care of deleting the FD from the event loop.
1030 */
1031
1032 DEBUG("%s - Connection closed - %s", h->ctx.module_name, h->ctx.fd_info->name);
1033
1034 return 0;
1035}
1036
1037static void bio_connected(fr_bio_t *bio)
1038{
1039 bio_handle_t *h = bio->uctx;
1040
1041 DEBUG("%s - Connection open - %s", h->ctx.module_name, h->ctx.fd_info->name);
1042
1044}
1045
1046static void bio_error(fr_bio_t *bio)
1047{
1048 bio_handle_t *h = bio->uctx;
1049
1050 DEBUG("%s - Connection failed - %s - %s", h->ctx.module_name, h->ctx.fd_info->name,
1052
1054}
1055
1056/** The BIO chain is at EOF, and has no more data for us.
1057 *
1058 * For TLS, the peer sent us a close_notify alert. The fd BIO may not have seen EOF, as the peer can send
1059 * a close_notify and keep the TCP connection open.
1060 */
1061static void bio_eof(fr_bio_t *bio)
1062{
1063 bio_handle_t *h = bio->uctx;
1064
1065 h->eof = true;
1066}
1067
1068static 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)
1069{
1071 size_t in_buffer = *size;
1072 bio_handle_t *h = verify_ctx;
1073 uint8_t const *hdr = data;
1074 size_t want;
1075
1076 if (in_buffer < 20) {
1077 *size = RADIUS_HEADER_LENGTH;
1079 }
1080
1081 /*
1082 * Packet is too large, discard it.
1083 */
1084 want = fr_nbo_to_uint16(hdr + 2);
1085 if (want > h->ctx.inst->max_packet_size) {
1086 ERROR("%s - Connection %s received too long packet", h->ctx.module_name, h->ctx.fd_info->name);
1088 }
1089
1090 /*
1091 * Not a full packet, we want more data.
1092 */
1093 if (want > *size) {
1094 *size = want;
1096 }
1097
1098#ifndef WITH_TLS
1099#define REQUIRE_MA(_h) (((_h)->ctx.inst->require_message_authenticator == FR_RADIUS_REQUIRE_MA_YES) || *(_h)->ctx.inst->received_message_authenticator)
1100#else
1101#define REQUIRE_MA(_h) (!(_h)->bio.tls && (((_h)->ctx.inst->require_message_authenticator == FR_RADIUS_REQUIRE_MA_YES) || *(_h)->ctx.inst->received_message_authenticator))
1102#endif
1103 /*
1104 * See if we need to discard the packet.
1105 *
1106 * @todo - rate limit these messages, and find a way to associate them with a request, or even
1107 * the logging destination of the module.
1108 */
1109 if (!fr_radius_ok(data, size, h->ctx.inst->max_attributes, REQUIRE_MA(h), &failure)) {
1110 if (*size) return FR_BIO_VERIFY_DISCARD;
1111
1112 PERROR("%s - Connection %s received bad packet", h->ctx.module_name, h->ctx.fd_info->name);
1113
1114 if (failure == FR_RADIUS_FAIL_MA_MISSING) {
1116 ERROR("We are configured with 'require_message_authenticator = true'");
1117 } else {
1118 ERROR("We previously received a packet from this client which included a Message-Authenticator attribute");
1119 }
1120 }
1121
1122 if (h->ctx.fd_config.socket_type == SOCK_DGRAM) return FR_BIO_VERIFY_DISCARD;
1123
1125 }
1126
1127 /*
1128 * @todo - check if the reply is allowed. Bad replies are discarded later, but it might be worth
1129 * checking them here.
1130 */
1131
1132 /*
1133 * On input, *size is how much data we have. On output, *size is how much data we want.
1134 */
1135 return (in_buffer >= *size) ? FR_BIO_VERIFY_OK : FR_BIO_VERIFY_WANT_MORE;
1136}
1137
1138
1139/** Initialise a new outbound connection
1140 *
1141 * @param[out] h_out Where to write the new file descriptor.
1142 * @param[in] conn to initialise.
1143 * @param[in] uctx A #bio_handle_ctx_t
1144 */
1145CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
1146static connection_state_t conn_init(void **h_out, connection_t *conn, void *uctx)
1147{
1148 int fd;
1149 bio_handle_t *h;
1150 bio_handle_ctx_t *ctx = uctx; /* thread or home server */
1151 connection_t **to_save = NULL;
1152 fr_bio_t *next;
1153 size_t write_size;
1154
1155 MEM(h = talloc_zero(conn, bio_handle_t));
1156 h->ctx = *ctx;
1157 h->conn = conn;
1159 h->last_idle = fr_time();
1160
1161 MEM(h->buffer = talloc_array(h, uint8_t, h->max_packet_size));
1162 h->buflen = h->max_packet_size;
1163
1164 MEM(h->tt = radius_track_alloc(h));
1165
1166 h->bio.fd = fr_bio_fd_alloc(h, &h->ctx.fd_config, 0);
1167 if (!h->bio.fd) {
1168 PERROR("%s - failed opening socket", h->ctx.module_name);
1169 fail:
1170 talloc_free(h);
1172 }
1173
1174 h->bio.fd->uctx = h;
1175 h->ctx.fd_info = fr_bio_fd_info(h->bio.fd);
1176
1177 fd = h->ctx.fd_info->socket.fd;
1178 fr_assert(fd >= 0);
1179
1180 /*
1181 * We are proxying to multiple home servers, but using a limited port range. We must track the
1182 * source port for each home server, so that conn_close() can mark the source port as unused.
1183 * fr_bio_fd_alloc() has picked the source port from the range, and has saved the port in the
1184 * fd_info.
1185 */
1186 switch (ctx->limit_source_ports) {
1187 case LIMIT_PORTS_NONE:
1188 break;
1189
1190 /*
1191 * Dynamic home servers store source port usage in the home_server_t
1192 */
1194 {
1195 home_server_t *home = talloc_get_type_abort(ctx, home_server_t);
1196 int slot;
1197
1198 fr_assert(h->ctx.fd_info->socket.inet.src_port >= h->ctx.fd_config.src_port_start);
1199 fr_assert(h->ctx.fd_info->socket.inet.src_port <= h->ctx.fd_config.src_port_end);
1200
1201 slot = h->ctx.fd_info->socket.inet.src_port - h->ctx.fd_config.src_port_start;
1202 fr_assert(slot < home->num_ports);
1203
1204 if (home->connections[slot]) {
1205 ERROR("%s - Failed opening socket to home server %pV:%u - source port %u is already in use",
1207 h->ctx.fd_info->socket.inet.src_port);
1208 goto fail;
1209 }
1210
1211 to_save = &home->connections[slot];
1212 }
1213 break;
1214
1215 /*
1216 * Static home servers store source port usage in bio_thread_t
1217 */
1218 case LIMIT_PORTS_STATIC:
1219 {
1220 bio_thread_t *thread = talloc_get_type_abort(ctx, bio_thread_t);
1221 int slot;
1222
1223 fr_assert(h->ctx.fd_info->socket.inet.src_port >= h->ctx.fd_config.src_port_start);
1224 fr_assert(h->ctx.fd_info->socket.inet.src_port <= h->ctx.fd_config.src_port_end);
1225
1226 slot = h->ctx.fd_info->socket.inet.src_port - h->ctx.fd_config.src_port_start;
1227 fr_assert(slot < thread->num_ports);
1228
1229 if (thread->connections[slot]) {
1230 ERROR("%s - Failed opening socket to home server %pV:%u - source port %u is already in use",
1232 h->ctx.fd_info->socket.inet.src_port);
1233 goto fail;
1234 }
1235
1236 to_save = &thread->connections[slot];
1237 }
1238 break;
1239 }
1240
1241 /*
1242 * Set the destructor now, so that every failure below frees the TLS bio and the connection
1243 * request.
1244 */
1245 h->fd = fd;
1246 talloc_set_destructor(h, _bio_handle_free);
1247
1248 /*
1249 * Create a memory BIO for stream sockets. We want to return only complete packets, and not
1250 * partial packets.
1251 *
1252 * @todo - maybe we want to have a fr_bio_verify_t which is independent of fr_bio_mem_t. That
1253 * way we don't need a memory BIO for UDP sockets, but we can still add a verification layer for
1254 * UDP sockets?
1255 */
1256 next = h->bio.fd;
1257
1258#ifdef WITH_TLS
1259 /*
1260 * For TLS, the path goes mem -> TLS -> FD. The memory BIO sees the decrypted application data,
1261 * and can then run its validation callbacks.
1262 */
1263 if (h->ctx.ssl_ctx) {
1264 if (conn_tls_alloc(h) < 0) {
1265 PERROR("%s - Failed allocating the TLS bio", h->ctx.module_name);
1266 goto fail;
1267 }
1268
1269 next = (fr_bio_t *) h->bio.tls;
1270 }
1271#endif
1272
1273 /*
1274 * A plain stream socket can accept only part of a packet, so the memory BIO needs a write buffer to
1275 * keep the rest of the packet. conn_writable_flush() flushes the buffer. The TLS BIO keeps its own
1276 * pending data, so a TLS connection does not need a write buffer.
1277 */
1278 write_size = 0;
1279#ifdef WITH_TLS
1280 if (!h->bio.tls)
1281#endif
1282 if (h->ctx.fd_config.socket_type == SOCK_STREAM) write_size = h->ctx.inst->max_packet_size * 4;
1283
1284 h->bio.mem = fr_bio_mem_alloc(h, (h->ctx.fd_config.socket_type == SOCK_DGRAM) ? 0 : h->ctx.inst->max_packet_size * 4,
1285 write_size, next);
1286 if (!h->bio.mem) {
1287 PERROR("%s - Failed allocating memory buffer - ", h->ctx.module_name);
1288 goto fail;
1289 }
1290
1291 if (fr_bio_mem_set_verify(h->bio.mem, rlm_radius_verify, h, (h->ctx.fd_config.socket_type == SOCK_DGRAM)) < 0) {
1292 PERROR("%s - Failed setting validation callback - ", h->ctx.module_name);
1293 goto fail;
1294 }
1295
1296 /*
1297 * Set the BIO read function to be the memory BIO, which will then call the packet verification
1298 * routine.
1299 */
1300 h->bio.main = h->bio.mem;
1301 h->bio.mem->uctx = h;
1303 .eof = bio_eof,
1304 /*
1305 * Datagram sockets drop packets instead of blocking.
1306 */
1307 .write_blocked = (h->ctx.fd_config.socket_type == SOCK_STREAM) ? bio_write_blocked : NULL,
1308 });
1309
1310#ifdef WITH_TLS
1311 /*
1312 * The TLS BIO owns the FD events until the bio_tls_connected() is called.
1313 *
1314 * The fd bio connect and TLS handshakes all happen after fr_bio_tls_connect().
1315 */
1316 if (h->bio.tls) {
1317 /*
1318 * The connection request starts the TLS connection, see conn_request_hold().
1319 */
1320 *h_out = h;
1321
1322 if (to_save) *to_save = conn;
1323
1325 }
1326#endif
1327
1328 /*
1329 * Allocate the status check packet now, because a stream socket can be in the CONNECTING state.
1330 */
1332
1333 /*
1334 * If the socket isn't connected, then do that first.
1335 */
1337 int rcode;
1338
1340
1341 /*
1342 * We don't pass timeouts here because the trunk has it's own connection timeouts.
1343 */
1344 rcode = fr_bio_fd_connect_full(h->bio.fd, conn->el, bio_connected, bio_error, NULL, NULL);
1345 if (rcode < 0) goto fail;
1346
1347 *h_out = h;
1348
1349 if (rcode == 0) return CONNECTION_STATE_CONNECTING;
1350
1351 fr_assert(rcode == 1);
1352
1353 DEBUG("%s - Connection open - %s", h->ctx.module_name, h->ctx.fd_info->name);
1354
1356 }
1357
1358 /*
1359 * If we're doing status checks, then we want at least
1360 * one positive response before signalling that the
1361 * connection is open.
1362 *
1363 * To do this we install special I/O handlers that
1364 * only signal the connection as open once we get a
1365 * status-check response.
1366 */
1367 if (h->ctx.inst->status_check) {
1368 /*
1369 * Start status checking.
1370 *
1371 * If we've had no recent failures we need exactly
1372 * one response to bring the connection online,
1373 * otherwise we need inst->num_answers_to_alive
1374 */
1375 if (fr_event_fd_insert(h, NULL, conn->el, h->fd, NULL,
1376 conn_init_writable, conn_init_error, conn) < 0) goto fail;
1377
1378 /*
1379 * If we're not doing status-checks, signal the connection
1380 * as open as soon as it becomes writable.
1381 */
1382 } else {
1383 DEBUG("%s - Connection open - %s", h->ctx.module_name, h->ctx.fd_info->name);
1384 connection_signal_on_fd(conn, fd);
1385 }
1386
1387 *h_out = h;
1388
1389 if (to_save) *to_save = conn;
1390
1392}
1393
1394/** Shutdown/close a file descriptor
1395 *
1396 */
1397static void conn_close(UNUSED fr_event_list_t *el, void *handle, void *uctx)
1398{
1399 bio_handle_t *h = talloc_get_type_abort(handle, bio_handle_t);
1400
1401 /*
1402 * There's tracking entries still allocated
1403 * this is bad, they should have all been
1404 * released.
1405 */
1406 if (h->tt && (h->tt->num_requests != 0)) {
1407#ifndef NDEBUG
1409#endif
1410 fr_assert_fail("%u tracking entries still allocated at conn close", h->tt->num_requests);
1411 }
1412
1413 /*
1414 * We have opened a limited number of outbound source ports. This means that when we close a
1415 * port, we have to mark it unused.
1416 */
1417 switch (h->ctx.limit_source_ports) {
1418 case LIMIT_PORTS_NONE:
1419 break;
1420
1422 {
1423 int offset;
1424 home_server_t *home = talloc_get_type_abort(uctx, home_server_t);
1425
1426 fr_assert(h->ctx.fd_info->socket.inet.src_port >= h->ctx.fd_config.src_port_start);
1427 fr_assert(h->ctx.fd_info->socket.inet.src_port <= h->ctx.fd_config.src_port_end);
1428
1429 offset = h->ctx.fd_info->socket.inet.src_port - h->ctx.fd_config.src_port_start;
1430 fr_assert(offset < home->num_ports);
1431
1432 fr_assert(home->connections[offset] == h->conn);
1433
1434 home->connections[offset] = NULL;
1435 }
1436 break;
1437
1438 case LIMIT_PORTS_STATIC:
1439 {
1440 int offset;
1441 bio_thread_t *thread = talloc_get_type_abort(uctx, bio_thread_t);
1442
1443 fr_assert(h->ctx.fd_info->socket.inet.src_port >= h->ctx.fd_config.src_port_start);
1444 fr_assert(h->ctx.fd_info->socket.inet.src_port <= h->ctx.fd_config.src_port_end);
1445
1446 offset = h->ctx.fd_info->socket.inet.src_port - h->ctx.fd_config.src_port_start;
1447 fr_assert(offset < thread->num_ports);
1448
1449 fr_assert(thread->connections[offset] == h->conn);
1450
1451 thread->connections[offset] = NULL;
1452 }
1453 break;
1454 }
1455
1456 DEBUG4("Freeing handle %p", handle);
1457
1458 talloc_free(h);
1459}
1460
1461/** Connection failed
1462 *
1463 * @param[in] handle of connection that failed.
1464 * @param[in] state the connection was in when it failed.
1465 * @param[in] uctx UNUSED.
1466 */
1467static connection_state_t conn_failed(void *handle, connection_state_t state, UNUSED void *uctx)
1468{
1469 switch (state) {
1470 /*
1471 * If the connection was connected when it failed,
1472 * we need to handle any outstanding packets and
1473 * timer events before reconnecting.
1474 */
1476 {
1477 bio_handle_t *h = talloc_get_type_abort(handle, bio_handle_t); /* h only available if connected */
1478
1479 /*
1480 * Reset the Status-Server checks.
1481 */
1482 if (h->status_u) FR_TIMER_DISARM(h->status_u->ev);
1483 break;
1484
1485 default:
1486 break;
1487 }
1488 }
1489
1490 return CONNECTION_STATE_INIT;
1491}
1492
1493CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
1495 connection_conf_t const *conf,
1496 char const *log_prefix, void *uctx)
1497{
1498 connection_t *conn;
1499 bio_handle_ctx_t *ctx = uctx; /* thread or home server */
1500
1501 conn = connection_alloc(tconn, el,
1503 .init = conn_init,
1504 .close = conn_close,
1505 .failed = conn_failed
1506 },
1507 conf,
1508 log_prefix,
1509 uctx);
1510 if (!conn) {
1511 PERROR("%s - Failed allocating state handler for new connection", ctx->inst->name);
1512 return NULL;
1513 }
1514 ctx->trunk = tconn->trunk;
1515 ctx->module_name = log_prefix;
1516
1517 return conn;
1518}
1519
1520/** Read and discard data
1521 *
1522 */
1523static void conn_discard(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
1524{
1525 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1526 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1527 uint8_t buffer[4096];
1528 ssize_t slen;
1529
1530 while ((slen = fr_bio_read(h->bio.main, NULL, buffer, sizeof(buffer))) > 0);
1531
1532 if (slen < 0) {
1533 switch (errno) {
1534 case EBADF:
1535 case ECONNRESET:
1536 case ENOTCONN:
1537 case ETIMEDOUT:
1538 ERROR("%s - Failed draining socket: %s", h->ctx.module_name, fr_syserror(errno));
1540 break;
1541
1542 default:
1543 break;
1544 }
1545 }
1546}
1547
1548/** Connection errored
1549 *
1550 * We were signalled by the event loop that a fatal error occurred on this connection.
1551 *
1552 * @param[in] el The event list signalling.
1553 * @param[in] fd that errored.
1554 * @param[in] flags El flags.
1555 * @param[in] fd_errno The nature of the error.
1556 * @param[in] uctx The trunk connection handle (tconn).
1557 */
1558static void conn_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
1559{
1560 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1561 connection_t *conn = tconn->conn;
1562 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
1563
1564 if (fd_errno) ERROR("%s - Connection %s failed: %s", h->ctx.module_name, h->ctx.fd_info->name, fr_syserror(fd_errno));
1565
1567}
1568
1569/** The fd is writable, and the connection is blocked on write
1570 *
1571 */
1572CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
1573static void conn_writable_flush(fr_event_list_t *el, int fd, int flags, void *uctx)
1574{
1575 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1576 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1577 ssize_t slen;
1578
1579 /*
1580 * Write "no packet" with a size, which signals the BIOs to flush their buffers.
1581 *
1582 * The write returns the actual amount of data which was flushed, even though we don't care about
1583 * that. All we care is that _some_ data was written on success. If only partial data is
1584 * written, then the BIO returns "would block".
1585 */
1586 slen = fr_bio_write(h->bio.main, NULL, NULL, SIZE_MAX);
1587 if (slen == fr_bio_error(IO_WOULD_BLOCK)) return;
1588
1589 if (slen < 0) {
1590 ERROR("%s - Failed writing pending data on connection %s: %s", h->ctx.module_name,
1591 h->ctx.fd_info->name, fr_strerror());
1593 return;
1594 }
1595
1596 bio_write_resume(h->bio.main);
1597
1598 trunk_connection_callback_writable(el, fd, flags, uctx);
1599}
1600
1601CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
1604 trunk_connection_event_t notify_on, UNUSED void *uctx)
1605{
1606 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
1607 fr_event_fd_cb_t read_fn = NULL;
1608 fr_event_fd_cb_t write_fn = NULL;
1609
1610 h->tconn = tconn;
1611 h->notify_on = notify_on;
1612
1613 switch (notify_on) {
1614 /*
1615 * We may have sent multiple requests to the
1616 * other end, so it might be sending us multiple
1617 * replies. We want to drain the socket, instead
1618 * of letting the packets sit in the UDP receive
1619 * queue.
1620 */
1622 read_fn = conn_discard;
1623 break;
1624
1627 break;
1628
1631 break;
1632
1636 break;
1637
1638 }
1639
1640 /*
1641 * A blocked connection has data which has to reach the fd before the trunk code writes packets.
1642 */
1643 if (h->write_blocked) write_fn = conn_writable_flush;
1644
1645 /*
1646 * Over-ride read for replication.
1647 */
1649 if (read_fn) read_fn = conn_discard;
1650
1651 if (fr_bio_fd_write_only(h->bio.fd) < 0) {
1652 PERROR("%s - Failed setting socket to write-only", h->ctx.module_name);
1654 return;
1655 }
1656 }
1657
1658 if (fr_event_fd_insert(h, NULL, el, h->fd,
1659 read_fn,
1660 write_fn,
1661 conn_error,
1662 tconn) < 0) {
1663 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
1664
1665 /*
1666 * May free the connection!
1667 */
1669 }
1670}
1671
1672/*
1673 * Return negative numbers to put 'a' at the top of the heap.
1674 * Return positive numbers to put 'b' at the top of the heap.
1675 *
1676 * We want the value with the lowest timestamp to be prioritized at
1677 * the top of the heap.
1678 */
1679static fr_cmp_ret_t request_prioritise(void const *one, void const *two)
1680{
1681 bio_request_t const *a = one;
1682 bio_request_t const *b = two;
1683 fr_cmp_ret_t ret;
1684
1685 /*
1686 * Prioritise status check packets
1687 */
1689 if (ret != 0) return ret;
1690
1691 /*
1692 * Larger priority is more important.
1693 */
1694 ret = CMP_PREFER_LARGER(a->priority, b->priority);
1695 if (ret != 0) return ret;
1696
1697 /*
1698 * Smaller timestamp (i.e. earlier) is more important.
1699 */
1700 return fr_time_cmp(a->recv_time, b->recv_time);
1701}
1702
1703/** Decode response packet data, extracting relevant information and validating the packet
1704 *
1705 * @param[in] ctx to allocate pairs in.
1706 * @param[out] reply Pointer to head of pair list to add reply attributes to.
1707 * @param[out] response_code The type of response packet.
1708 * @param[in] h connection handle.
1709 * @param[in] request the request.
1710 * @param[in] u UDP request.
1711 * @param[in] request_authenticator from the original request.
1712 * @param[in] data to decode.
1713 * @param[in] data_len Length of input data.
1714 * @return
1715 * - FR_RADIUS_FAIL_NONE on success.
1716 * - FR_RADIUS_FAIL_* on failure.
1717 */
1718static fr_radius_decode_fail_t decode(TALLOC_CTX *ctx, fr_pair_list_t *reply, uint8_t *response_code,
1720 uint8_t const request_authenticator[static RADIUS_AUTH_VECTOR_LENGTH],
1721 uint8_t *data, size_t data_len)
1722{
1724 uint8_t code;
1725 fr_radius_decode_ctx_t decode_ctx;
1726
1727 *response_code = 0; /* Initialise to keep the rest of the code happy */
1728
1729 RHEXDUMP3(data, data_len, "Read packet");
1730
1731 decode_ctx = (fr_radius_decode_ctx_t) {
1732 .common = &h->ctx.radius_ctx,
1733 .request_code = u->code,
1734 .request_authenticator = request_authenticator,
1735 .tmp_ctx = talloc(ctx, uint8_t),
1736 .end = data + data_len,
1737 .verify = true,
1738 .require_message_authenticator = REQUIRE_MA(h),
1739 };
1740
1741 if (fr_radius_decode(ctx, reply, data, data_len, &decode_ctx) < 0) {
1742 talloc_free(decode_ctx.tmp_ctx);
1743 RPEDEBUG("Failed reading packet");
1744 return decode_ctx.reason;
1745 }
1746 talloc_free(decode_ctx.tmp_ctx);
1747
1748 code = data[0];
1749
1750 RDEBUG("Received %s ID %d length %zu reply packet on connection %s",
1751 fr_radius_packet_name[code], data[1], data_len, h->ctx.fd_info->name);
1753
1754 /*
1755 * This code is for BlastRADIUS mitigation.
1756 *
1757 * The scenario where this applies is where we send Message-Authenticator
1758 * but the home server doesn't support it or require it, in which case
1759 * the response can be manipulated by an attacker.
1760 */
1761 if ((u->code == FR_RADIUS_CODE_ACCESS_REQUEST) &&
1762#ifdef WITH_TLS
1763 !h->bio.tls &&
1764#endif
1765
1766 (inst->require_message_authenticator == FR_RADIUS_REQUIRE_MA_AUTO) &&
1767 !*(inst->received_message_authenticator) &&
1770 RINFO("Packet contained a valid Message-Authenticator. Setting \"require_message_authenticator = yes\"");
1771 *(inst->received_message_authenticator) = true;
1772 }
1773
1774 *response_code = code;
1775
1776 /*
1777 * Record the fact we've seen a response
1778 */
1779 u->num_replies++;
1780
1781 /*
1782 * Fixup retry times
1783 */
1784 if (fr_time_gt(u->retry.start, h->mrs_time)) h->mrs_time = u->retry.start;
1785
1786 return FR_RADIUS_FAIL_NONE;
1787}
1788
1790{
1791 ssize_t packet_len;
1793 rlm_radius_t const *inst = h->ctx.inst;
1794
1795 fr_assert(inst->allowed[u->code]);
1796 fr_assert(!u->packet);
1797
1798 u->packet_len = inst->max_packet_size;
1799 u->packet = h->buffer;
1800
1801 /*
1802 * We should have at minimum 64-byte packets, so don't
1803 * bother doing run-time checks here.
1804 */
1806
1808 .common = &h->ctx.radius_ctx,
1809 .rand_ctx = (fr_fast_rand_t) {
1810 .a = fr_rand(),
1811 .b = fr_rand(),
1812 },
1813 .code = u->code,
1814 .id = id,
1815 .add_proxy_state = u->proxied,
1816 };
1817
1818 /*
1819 * If we're sending a status check packet, update any
1820 * necessary timestamps. Also, don't add Proxy-State, as
1821 * we're originating the packet.
1822 */
1823 if (u->status_check) {
1824 fr_pair_t *vp;
1825
1826 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_event_timestamp);
1827 if (vp) vp->vp_date = fr_time_to_unix_time(u->retry.updated);
1828
1829 encode_ctx.add_proxy_state = false;
1830 }
1831
1832 /*
1833 * Encode it, leaving room for Proxy-State if necessary.
1834 */
1835 packet_len = fr_radius_encode(&FR_DBUFF_TMP(u->packet, u->packet_len),
1836 &request->request_pairs, &encode_ctx);
1837 if (packet_len < 0) {
1838 RPERROR("Failed encoding packet");
1839 u->packet = NULL;
1840 return -1;
1841 }
1842
1843 /*
1844 * The encoded packet should NOT over-run the input buffer.
1845 */
1846 fr_assert((size_t) packet_len <= u->packet_len);
1847
1848 /*
1849 * Add Proxy-State to the "extra" list. It has been added
1850 * to the encoded packet by `fr_radius_encode`.
1851 *
1852 * We need to add it here, and NOT in
1853 * request->request_pairs, because multiple modules
1854 * may be sending the packets at the same time.
1855 */
1856 if (encode_ctx.add_proxy_state) {
1857 fr_pair_t *vp;
1858
1860 fr_pair_value_memdup(vp, (uint8_t const *) &inst->common_ctx.proxy_state, sizeof(inst->common_ctx.proxy_state), false);
1861 fr_pair_append(&u->extra, vp);
1862 }
1863
1864 /*
1865 * Update our version of the packet length.
1866 */
1867 u->packet_len = packet_len;
1868
1869 /*
1870 * Now that we're done mangling the packet, sign it.
1871 */
1872 if (fr_radius_sign(u->packet, NULL, (uint8_t const *) h->ctx.radius_ctx.secret,
1873 h->ctx.radius_ctx.secret_length) < 0) {
1874 RPERROR("Failed signing packet");
1875 u->packet = NULL;
1876 return -1;
1877 }
1878
1879 MEM(u->packet = talloc_memdup(u, h->buffer, packet_len));
1880
1881 return 0;
1882}
1883
1884
1885/** Revive a connection after "revive_interval"
1886 *
1887 */
1888static void revive_timeout(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
1889{
1890 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1891 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1892
1893 INFO("%s - Reviving connection %s", h->ctx.module_name, h->ctx.fd_info->name);
1895}
1896
1897/** Mark a connection dead after "zombie_interval"
1898 *
1899 */
1900static void zombie_timeout(fr_timer_list_t *tl, fr_time_t now, void *uctx)
1901{
1902 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1903 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1904
1905 INFO("%s - No replies during 'zombie_period', marking connection %s as dead", h->ctx.module_name, h->ctx.fd_info->name);
1906
1907 /*
1908 * Don't use this connection, and re-queue its requests onto other connections.
1909 *
1910 * RFC 6613 Section 2.6.1 forbids retransmitting a request over a different TCP connection while the
1911 * first connection is open. So for stream sockets, we only requeue pending packets.
1912 */
1914 (h->ctx.fd_config.socket_type == SOCK_STREAM) ?
1916
1917 /*
1918 * We do have status checks. Try to reconnect the
1919 * connection immediately. If the status checks pass,
1920 * then the connection will be marked "alive"
1921 */
1922 if (h->ctx.inst->status_check) {
1924 return;
1925 }
1926
1927 if (!h->ctx.dynamic) {
1928 /*
1929 * Force the instruction to immediately fail until the revive interval has expired.
1930 */
1931 unlang_interpret_force_result(h->instruction, &(unlang_result_t){.rcode = RLM_MODULE_FAIL}, tl,
1933
1934 /*
1935 * Mark the connection as active, so when the module forced result times out
1936 * requests will be sent again.
1937 */
1939 return;
1940 }
1941
1942 /*
1943 * Revive the connection after a time.
1944 */
1945 if (fr_timer_at(h, tl, &h->zombie_ev,
1946 fr_time_add(now, h->ctx.inst->revive_interval), false,
1947 revive_timeout, tconn) < 0) {
1948 ERROR("Failed inserting revive timeout for connection");
1950 }
1951}
1952
1953
1954static void status_check_enqueue(trunk_connection_t *tconn, bio_handle_t *h, bool init);
1955
1956/** We timed out, without getting a status check reply.
1957 *
1958 */
1959static void status_check_timeout(UNUSED fr_timer_list_t *tl, fr_time_t now, void *uctx)
1960{
1961 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1962 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1963 bio_request_t *u = h->status_u;
1964
1965 if (h->ctx.fd_info->state != FR_BIO_FD_STATE_OPEN) return;
1966
1967 /*
1968 * Remove the status check which got no reply. Freeing the old request also releases the ID.
1969 */
1970 if (u->treq) {
1972 u->treq = NULL;
1973 }
1974
1975 /*
1976 * We are only interested in contiguous, good, replies.
1977 */
1978 u->num_replies = 0;
1979
1980 switch (fr_retry_next(&u->retry, now)) {
1981 case FR_RETRY_MRD:
1982 DEBUG("%s - Reached maximum_retransmit_duration (%pVs > %pVs), failing status checks",
1986 return;
1987
1988 case FR_RETRY_MRC:
1989 DEBUG("%s - Reached maximum_retransmit_count (%u > %u), failing status checks",
1990 h->ctx.module_name, u->retry.count, u->retry.config->mrc);
1992 return;
1993
1994 case FR_RETRY_CONTINUE:
1995 status_check_enqueue(tconn, h, false);
1996 return;
1997 }
1998
1999 fr_assert(0);
2000}
2001
2002
2003/** Queue a status check packet on an open connection, and wait for the reply
2004 *
2005 * The caller has already set up the retry state of the status check. The timer runs when the
2006 * status check gets no reply before u->retry.next.
2007 */
2009{
2010 bio_request_t *u = h->status_u;
2011
2012 u->treq = NULL;
2013
2015
2016 /*
2017 * Queue up the status check packet. It will be sent when the connection is writable.
2018 */
2019 if (trunk_request_enqueue_on_conn(&u->treq, tconn, h->status_request, u, u, true) != TRUNK_ENQUEUE_OK) {
2021 return;
2022 }
2023
2024 if (fr_timer_at(h, h->ctx.el->tl, &u->ev, u->retry.next, false, status_check_timeout, tconn) < 0) {
2026 }
2027}
2028
2029/** See if the connection is zombied.
2030 *
2031 * We check for zombie when major events happen:
2032 *
2033 * 1) request hits its final timeout
2034 * 2) request timer hits, and it needs to be retransmitted
2035 * 3) a DUP packet comes in, and the request needs to be retransmitted
2036 * 4) we're sending a packet.
2037 *
2038 * There MIGHT not be retries configured, so we MUST check for zombie
2039 * when any new packet comes in. Similarly, there MIGHT not be new
2040 * packets, but retries are configured, so we have to check there,
2041 * too.
2042 *
2043 * Also, the socket might not be writable for a while. There MIGHT
2044 * be a long time between getting the timer / DUP signal, and the
2045 * request finally being written to the socket. So we need to check
2046 * for zombie at BOTH the timeout and the mux / write function.
2047 *
2048 * @return
2049 * - true if the connection is zombie.
2050 * - false if the connection is not zombie.
2051 */
2053{
2054 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
2056
2057 /*
2058 * We're replicating, and don't care about the health of
2059 * the home server, and this function should not be called.
2060 */
2062
2063 /*
2064 * Only an open connection can become zombie. A connection which is connecting or closing
2065 * cannot send or receive the status checks, and the zombie timer would run on a connection
2066 * which is about to be freed.
2067 */
2068 if (h->ctx.fd_info->state != FR_BIO_FD_STATE_OPEN) return false;
2069
2070 /*
2071 * If we're status checking OR already zombie, don't go to zombie
2072 */
2073 if (h->status_checking || fr_timer_armed(h->zombie_ev)) return true;
2074
2075 if (fr_time_eq(now, fr_time_wrap(0))) now = fr_time();
2076
2077 /*
2078 * We received a reply since this packet was sent, the connection isn't zombie.
2079 */
2080 if (fr_time_gteq(h->last_reply, last_sent)) return false;
2081
2082 /*
2083 * If we've seen ANY response in the allowed window, then the connection is still alive.
2084 */
2085 if ((h->ctx.inst->mode == RLM_RADIUS_MODE_PROXY) &&
2086 fr_time_gt(h->last_reply, fr_time_sub(now, h->ctx.inst->response_window))) return false;
2087
2088 /*
2089 * Stop using it for new requests.
2090 */
2091 WARN("%s - Entering Zombie state - connection %s", h->ctx.module_name, h->ctx.fd_info->name);
2093
2094 if (h->ctx.inst->status_check) {
2095 /*
2096 * If it's UDP, reconnect. This will start the sending of status checks.
2097 */
2098 if (h->ctx.inst->fd_config.socket_type == SOCK_DGRAM) {
2101 return true;
2102 }
2103
2104 h->status_checking = true;
2105
2106 /*
2107 * Queue up the status check packet. It will be sent
2108 * when the connection is writable.
2109 */
2110 status_check_enqueue(tconn, h, true);
2111 } else {
2112 /*
2113 * Capture the instruction which started the zombie period.
2114 */
2116
2117 if (fr_timer_at(h, el->tl, &h->zombie_ev, fr_time_add(now, h->ctx.inst->zombie_period),
2118 false, zombie_timeout, tconn) < 0) {
2119 ERROR("Failed inserting zombie timeout for connection");
2121 }
2122 }
2123
2124 return true;
2125}
2126
2128{
2129 bio_handle_t *h;
2130
2131 if (!u->treq) {
2132 RDEBUG("Request is queued and waiting for a connection - suppressing retransmission");
2133 return;
2134 }
2135
2136 /*
2137 * Only a request which was written to the connection can be retransmitted. A request in the
2138 * backlog has no connection, and request_mux() writes the other requests.
2139 */
2140 if (u->treq->state != TRUNK_REQUEST_STATE_SENT) {
2141 RDEBUG("Request has not been sent - suppressing retransmission");
2142 return;
2143 }
2144
2145 h = talloc_get_type_abort(u->treq->tconn->conn->h, bio_handle_t);
2146
2147 if (h->ctx.fd_config.socket_type != SOCK_DGRAM) {
2148 RDEBUG("Using stream sockets - suppressing retransmission");
2149 return;
2150 }
2151
2152 /*
2153 * Arguably this should never happen for UDP sockets.
2154 */
2155 if (h->ctx.fd_info->write_blocked) {
2156 RDEBUG("IO is blocked - suppressing retransmission");
2157 return;
2158 }
2159
2160 /*
2161 * We are doing synchronous proxying, retransmit
2162 * the current request on the same connection.
2163 *
2164 * If it's zombie, we still resend it. If the
2165 * connection is dead, then a callback will move
2166 * this request to a new connection.
2167 */
2168 mod_write(request, u->treq, h);
2169}
2170
2171static void do_retry(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_retry_t const *retry);
2172
2173/** Handle module retries.
2174 *
2175 */
2176static void mod_retry(module_ctx_t const *mctx, request_t *request, fr_retry_t const *retry)
2177{
2178 bio_request_t *u = talloc_get_type_abort(mctx->rctx, bio_request_t);
2179 rlm_radius_t const *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
2180
2181 do_retry(inst, u, request, retry);
2182}
2183
2184static void do_retry(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_retry_t const *retry)
2185{
2186 trunk_request_t *treq;
2187 trunk_connection_t *tconn;
2188 fr_time_t now;
2189
2190 if (!u->treq) {
2191 RDEBUG("Packet was cancelled by the connection handler - ignoring retry");
2192 return;
2193 }
2194
2195 treq = talloc_get_type_abort(u->treq, trunk_request_t);
2196
2197 fr_assert(request == treq->request);
2198 fr_assert(treq->preq); /* Must still have a protocol request */
2199 fr_assert(treq->preq == u);
2200
2201 tconn = treq->tconn;
2202 now = retry->updated;
2203
2204 switch (retry->state) {
2205 case FR_RETRY_CONTINUE:
2206 u->retry = *retry;
2207
2208 switch (treq->state) {
2211 fr_assert(0);
2212 break;
2213
2215 RDEBUG("Packet is still in the backlog queue to be sent - suppressing retransmission");
2216 return;
2217
2219 RDEBUG("Packet is still in the pending queue to be sent - suppressing retransmission");
2220 return;
2221
2223 RDEBUG("Packet was partially written, as IO is blocked - suppressing retransmission");
2224 return;
2225
2227 fr_assert(tconn);
2228
2229 mod_dup(request, u);
2230 return;
2231
2239 fr_assert(0);
2240 break;
2241 }
2242 break;
2243
2244 case FR_RETRY_MRD:
2245 REDEBUG("Reached maximum_retransmit_duration (%pVs > %pVs), failing request",
2247 break;
2248
2249 case FR_RETRY_MRC:
2250 REDEBUG("Reached maximum_retransmit_count (%u > %u), failing request",
2251 retry->count, retry->config->mrc);
2252 break;
2253 }
2254
2257
2258 /*
2259 * We don't do zombie stuff!
2260 */
2261 if (!tconn || (inst->mode == RLM_RADIUS_MODE_REPLICATE)) return;
2262
2263 check_for_zombie(request, tconn, now, retry->start);
2264}
2265
2266CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
2268 trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
2269{
2270 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
2271 trunk_request_t *treq;
2273
2274 if (unlikely(trunk_connection_pop_request(&treq, tconn) < 0)) return;
2275
2276 /*
2277 * No more requests to send
2278 */
2279 if (!treq) return;
2280
2281 request = treq->request;
2282
2283 mod_write(request, treq, h);
2284}
2285
2287{
2288 rlm_radius_t const *inst = h->ctx.inst;
2289 bio_request_t *u;
2290 char const *action;
2291 uint8_t const *packet;
2292 size_t packet_len;
2293 ssize_t slen;
2294
2295 u = treq->preq;
2296
2297 fr_assert((treq->state == TRUNK_REQUEST_STATE_PENDING) ||
2298 (treq->state == TRUNK_REQUEST_STATE_PARTIAL) ||
2299 ((u->retry.count > 0) && (treq->state == TRUNK_REQUEST_STATE_SENT)));
2300
2302
2303 /*
2304 * If it's a partial packet, then write the partial bit.
2305 */
2306 if (u->partial) {
2307 fr_assert(u->partial < u->packet_len);
2308 packet = u->packet + u->partial;
2309 packet_len = u->packet_len - u->partial;
2310 goto do_write;
2311 }
2312
2313 /*
2314 * No previous packet, OR can't retransmit the
2315 * existing one. Oh well.
2316 *
2317 * Note that if we can't retransmit the previous
2318 * packet, then u->rr MUST already have been
2319 * deleted in the request_cancel() function
2320 * or request_release_conn() function when
2321 * the REQUEUE signal was received.
2322 */
2323 if (!u->packet) {
2324 fr_assert(!u->rr);
2325
2326 if (unlikely(radius_track_entry_reserve(&u->rr, treq, h->tt, request, u->code, treq) < 0)) {
2327#ifndef NDEBUG
2328 radius_track_state_log(&default_log, L_ERR, __FILE__, __LINE__,
2330#endif
2331 fr_assert_fail("Tracking entry allocation failed: %s", fr_strerror());
2333 return;
2334 }
2335 fr_assert(u->rr);
2336 u->id = u->rr->id;
2337
2338 RDEBUG("Sending %s ID %d length %zu over connection %s",
2340
2341 if (encode(h, request, u, u->id) < 0) {
2342 /*
2343 * Need to do this because request_conn_release
2344 * may not be called.
2345 */
2348 return;
2349 }
2350 RHEXDUMP3(u->packet, u->packet_len, "Encoded packet");
2351
2352 /*
2353 * Remember the authentication vector, which now has the
2354 * packet signature.
2355 */
2357 } else {
2358 RDEBUG("Retransmitting %s ID %d length %zu over connection %s",
2360 }
2361
2362 /*
2363 * @todo - When logging Message-Authenticator, don't print its' value.
2364 */
2365 log_request_proto_pair_list(L_DBG_LVL_2, request, NULL, &request->request_pairs, NULL);
2367
2368 packet = u->packet;
2369 packet_len = u->packet_len;
2370
2371do_write:
2372 fr_assert(packet != NULL);
2373 fr_assert(packet_len >= RADIUS_HEADER_LENGTH);
2374
2375 slen = fr_bio_write(h->bio.main, NULL, packet, packet_len);
2376
2377 /*
2378 * Can't write anything, requeue it on a different socket.
2379 */
2380 if (slen == fr_bio_error(IO_WOULD_BLOCK)) goto requeue;
2381
2382 if (slen < 0) {
2383 switch (errno) {
2384 /*
2385 * There is an error in the request.
2386 */
2387 case EMSGSIZE: /* Packet size exceeds max size allowed on socket */
2388 ERROR("%s - Failed sending data over connection %s: %s",
2389 h->ctx.module_name, h->ctx.fd_info->name, fr_syserror(errno));
2391 break;
2392
2393 /*
2394 * There is an error in the connection. The reconnection will re-queue any pending or
2395 * sent requests, so we don't have to do any cleanup.
2396 */
2397 default:
2398 ERROR("%s - Failed sending data over connection %s: %s",
2399 h->ctx.module_name, h->ctx.fd_info->name, fr_syserror(errno));
2401 break;
2402 }
2403
2404 return;
2405 }
2406
2407 /*
2408 * No data to send, ignore the write for partials, but otherwise requeue it.
2409 */
2410 if (slen == 0) {
2411 if (u->partial) return;
2412
2413 /*
2414 * We didn't get a "blocked" error, but we didn't write any data. And the socket is
2415 * unconnected. This means we just discard the packet.
2416 */
2418 ERROR("%s - Failed sending %s ID %d length %zu over connection %s: Destination network is down or unreachable",
2421 return;
2422 }
2423
2424 requeue:
2425 RWARN("%s - Failed sending data over connection %s: sent zero bytes",
2426 h->ctx.module_name, h->ctx.fd_info->name);
2428 return;
2429 }
2430
2431 packet_len += slen;
2432 if (packet_len < u->packet_len) {
2433 u->partial = packet_len;
2435 return;
2436 }
2437
2438 /*
2439 * For retransmissions.
2440 */
2441 u->partial = 0;
2442
2443 /*
2444 * Don't print anything extra for replication.
2445 */
2446 if (inst->mode == RLM_RADIUS_MODE_REPLICATE) {
2447 u->rcode = RLM_MODULE_OK;
2449 return;
2450 }
2451
2452 /*
2453 * A request which is not already in the SENT state is a new packet from request_mux(), and we
2454 * signal the trunk that it was written.
2455 *
2456 * A request which is in the SENT state is a retransmission, and we don't signal the trunk.
2457 */
2458 if (treq->state == TRUNK_REQUEST_STATE_SENT) {
2459 action = "Retransmitted";
2460
2461 } else {
2462 if (u->retry.count == 1) {
2463 h->last_sent = u->retry.start;
2465 }
2466
2468
2469 if (u->retry.count > 1) {
2470 action = "Retransmitted";
2471 } else {
2472 action = u->proxied ? "Proxied" : "Originated";
2473 }
2474 }
2475
2477
2478 if (!u->proxied) {
2479 RDEBUG("%s request. Expecting response within %pVs", action,
2481
2482 } else {
2483 /*
2484 * If the packet doesn't get a response, then bio_request_free() will notice, and look
2485 * for zombie connections.
2486 */
2487 RDEBUG("%s request. Relying on NAS to perform more retransmissions", action);
2488 }
2489
2490 /*
2491 * We don't retransmit over TCP.
2492 */
2493 if (h->ctx.fd_config.socket_type != SOCK_DGRAM) return;
2494
2495 /*
2496 * If we only send one datagram packet, then don't bother saving it.
2497 */
2498 if (u->retry.config && u->retry.config->mrc == 1) {
2499 u->packet = NULL;
2500 return;
2501 }
2502
2503 MEM(u->packet = talloc_memdup(u, u->packet, u->packet_len));
2504}
2505
2506/** Deal with Protocol-Error replies, and possible negotiation
2507 *
2508 */
2510{
2511 bool error_601 = false;
2512 uint32_t response_length = 0;
2513 uint8_t const *attr, *end;
2514
2515 end = h->buffer + fr_nbo_to_uint16(h->buffer + 2);
2516
2517 for (attr = h->buffer + RADIUS_HEADER_LENGTH;
2518 attr < end;
2519 attr += attr[1]) {
2520 /*
2521 * Error-Cause = Response-Too-Big
2522 */
2523 if ((attr[0] == attr_error_cause->attr) && (attr[1] == 6)) {
2524 uint32_t error;
2525
2526 error = fr_nbo_to_uint32(attr + 2);
2527 if (error == 601) error_601 = true;
2528 continue;
2529 }
2530
2531 /*
2532 * The other end wants us to increase our Response-Length
2533 */
2534 if ((attr[0] == attr_extended_attribute_1->attr) &&
2535 (attr[1] == 7) &&
2536 (attr[2] == attr_response_length->attr)) {
2537 response_length = fr_nbo_to_uint32(attr + 3);
2538 continue;
2539 }
2540
2541 /*
2542 * Protocol-Error packets MUST contain an
2543 * Original-Packet-Code attribute.
2544 *
2545 * The attribute containing the
2546 * Original-Packet-Code is an extended
2547 * attribute.
2548 */
2549 if (attr[0] != attr_extended_attribute_1->attr) continue;
2550
2551 /*
2552 * ATTR + LEN + EXT-Attr + uint32
2553 */
2554 if (attr[1] != 7) continue;
2555
2556 /*
2557 * See if there's an Original-Packet-Code.
2558 */
2559 if (attr[2] != (uint8_t)attr_original_packet_code->attr) continue;
2560
2561 /*
2562 * Has to be an 8-bit number.
2563 */
2564 if ((attr[3] != 0) ||
2565 (attr[4] != 0) ||
2566 (attr[5] != 0)) {
2568 return;
2569 }
2570
2571 /*
2572 * The value has to match. We don't
2573 * currently multiplex different codes
2574 * with the same IDs on connections. So
2575 * this check is just for RFC compliance,
2576 * and for sanity.
2577 */
2578 if (attr[6] != u->code) {
2580 return;
2581 }
2582 }
2583
2584 /*
2585 * Error-Cause = Response-Too-Big
2586 *
2587 * The other end says it needs more room to send it's response
2588 *
2589 * Limit it to reasonable values.
2590 */
2591 if (error_601 && response_length && (response_length > h->buflen)) {
2592 if (response_length < 4096) response_length = 4096;
2593 if (response_length > 65535) response_length = 65535;
2594
2595 DEBUG("%s - Increasing buffer size to %u for connection %s", h->ctx.module_name, response_length, h->ctx.fd_info->name);
2596
2597 /*
2598 * Make sure to copy the packet over!
2599 */
2600 MEM(h->buffer = talloc_realloc_size(h, h->buffer, response_length));
2601 h->buflen = response_length;
2602 }
2603
2604 /*
2605 * fail - something went wrong internally, or with the connection.
2606 * invalid - wrong response to packet
2607 * handled - best remaining alternative :(
2608 *
2609 * i.e. if the response is NOT accept, reject, whatever,
2610 * then we shouldn't allow the caller to do any more
2611 * processing of this packet. There was a protocol
2612 * error, and the response is valid, but not useful for
2613 * anything.
2614 */
2616}
2617
2618
2619/** Send the next status check, after the previous status check got a reply
2620 *
2621 */
2623{
2624 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
2625 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
2626
2627 /*
2628 * Status checks are sent only on an open connection.
2629 */
2630 if (h->ctx.fd_info->state != FR_BIO_FD_STATE_OPEN) return;
2631
2632 /*
2633 * The previous status check was answered, so start the retries again.
2634 */
2635 status_check_enqueue(tconn, h, true);
2636}
2637
2638/** Deal with replies replies to status checks and possible negotiation
2639 *
2640 */
2642{
2643 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
2644 rlm_radius_t const *inst = h->ctx.inst;
2645
2646 fr_assert(u == h->status_u);
2647
2648 /*
2649 * @todo - do other negotiation and signaling.
2650 */
2652
2653 if (u->num_replies < inst->num_answers_to_alive) {
2654 DEBUG("Received %u / %u replies for status check, on connection - %s",
2655 u->num_replies, inst->num_answers_to_alive, h->ctx.fd_info->name);
2656 DEBUG("Next status check packet will be in %pVs", fr_box_time_delta(fr_time_sub(u->retry.next, now)));
2657
2658 /*
2659 * Set the timer for the next status check.
2660 */
2661 if (fr_timer_at(h, h->ctx.el->tl, &u->ev, u->retry.next, false, status_check_next, tconn) < 0) {
2663 }
2664 return;
2665 }
2666
2667 DEBUG("Received enough replies to status check, marking connection as active - %s", h->ctx.fd_info->name);
2668
2669 /*
2670 * Set the "last idle" time to now, so that we don't
2671 * restart zombie_period until sufficient time has
2672 * passed.
2673 */
2674 h->last_idle = fr_time();
2675
2676 /*
2677 * Reset retry interval and retransmission counters
2678 * also frees u->ev.
2679 */
2680 status_check_reset(h, u);
2682}
2683
2684CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
2686{
2687 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
2688
2689 DEBUG3("%s - Reading data for connection %s", h->ctx.module_name, h->ctx.fd_info->name);
2690
2691 while (true) {
2692 ssize_t slen;
2693
2694 trunk_request_t *treq;
2696 bio_request_t *u;
2699 uint8_t code = 0;
2701 fr_pair_t *vp;
2702
2703 fr_time_t now;
2704
2706
2707 /*
2708 * Drain the socket of all packets. If we're busy, this
2709 * saves a round through the event loop. If we're not
2710 * busy, a few extra system calls don't matter.
2711 */
2712 slen = fr_bio_read(h->bio.main, NULL, h->buffer, h->buflen);
2713 if (slen == 0) {
2715 return;
2716 }
2717
2718 /*
2719 * We're done reading, return.
2720 */
2721 if (slen == fr_bio_error(IO_WOULD_BLOCK)) return;
2722
2723 if (slen < 0) {
2724 ERROR("%s - Failed reading response from socket: %s",
2725 h->ctx.module_name, fr_syserror(errno));
2727 return;
2728 }
2729
2730 fr_assert(slen >= RADIUS_HEADER_LENGTH); /* checked in verify */
2731
2732 /*
2733 * Note that we don't care about packet codes. All
2734 * packet codes share the same ID space.
2735 */
2736 rr = radius_track_entry_find(h->tt, h->buffer[1], NULL);
2737 if (!rr) {
2738 WARN("%s - Ignoring reply with ID %i that arrived too late",
2739 h->ctx.module_name, h->buffer[1]);
2740 continue;
2741 }
2742
2743 treq = talloc_get_type_abort(rr->uctx, trunk_request_t);
2744 request = treq->request;
2745 fr_assert(request != NULL);
2746 u = talloc_get_type_abort(treq->rctx, bio_request_t);
2747 fr_assert(u == treq->preq);
2748
2749 /*
2750 * If we got a reply during the zombie period mark the
2751 * connection as active and remove the timer.
2752 */
2756 }
2757
2758 /*
2759 * Decode the incoming packet.
2760 */
2761 reason = decode(request->reply_ctx, &reply, &code, h, request, u, rr->vector, h->buffer, (size_t)slen);
2762 if (reason != FR_RADIUS_FAIL_NONE) continue;
2763
2764 /*
2765 * Only valid packets are processed
2766 * Otherwise an attacker could perform
2767 * a DoS attack against the proxying servers
2768 * by sending fake responses for upstream
2769 * servers.
2770 */
2771 h->last_reply = now = fr_time();
2772
2773 /*
2774 * Status-Server can have any reply code, we don't care
2775 * what it is. So long as it's signed properly, we
2776 * accept it. This flexibility is because we don't
2777 * expose Status-Server to the admins. It's only used by
2778 * this module for internal signalling.
2779 */
2780 if (u == h->status_u) {
2781 fr_pair_list_free(&reply); /* Probably want to pass this to status_check_reply? */
2783 status_check_reply(tconn, u, now);
2784 continue;
2785 }
2786
2787 /*
2788 * Handle any state changes, etc. needed by receiving a
2789 * Protocol-Error reply packet.
2790 *
2791 * Protocol-Error is permitted as a reply to any
2792 * packet.
2793 */
2794 switch (code) {
2797
2798 /*
2799 * The attributes which the home server sent are in the "reply" list. They are
2800 * added to request->reply_pairs at the end of this function. Original-Packet-Code
2801 * is a child of Extended-Attribute-1, so we need the nested versions of the pair
2802 * functions.
2803 */
2805 if (!vp) {
2806 RWDEBUG("Protocol-Error response is missing Original-Packet-Code");
2807 } else {
2809 }
2810
2812 if (!vp) {
2814 vp->vp_uint32 = FR_ERROR_CAUSE_VALUE_PROXY_PROCESSING_ERROR;
2816 }
2817 break;
2818
2819 default:
2820 break;
2821 }
2822
2823 /*
2824 * Mark up the request as being an Access-Challenge, if
2825 * required.
2826 *
2827 * We don't do this for other packet types, because the
2828 * ok/fail nature of the module return code will
2829 * automatically result in it the parent request
2830 * returning an ok/fail packet code.
2831 */
2833 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_packet_type);
2834 if (!vp) {
2837 fr_pair_append(&request->reply_pairs, vp);
2838 }
2839
2840 /*
2841 * If the Access-Request got a challenge, AND the request doesn't have State, AND
2842 * the challenge does have State, THEN try to load-balance future packets to the
2843 * same destination.
2844 */
2845 if (h->ctx.inst->track_load_balance &&
2846 !fr_pair_find_by_da(&request->request_pairs, NULL, attr_state) &&
2849 }
2850 }
2851
2852 /*
2853 * Delete Proxy-State attributes from the reply.
2854 */
2856
2857 /*
2858 * If the reply has Message-Authenticator, then over-ride its value with all zeros, so
2859 * that we don't confuse anyone reading the debug output.
2860 */
2861 if ((vp = fr_pair_find_by_da(&reply, NULL, attr_message_authenticator)) != NULL) {
2862 (void) fr_pair_value_memdup(vp, (uint8_t const *) "", 1, false);
2863 }
2864
2865 treq->request->reply->code = code;
2866
2867 /*
2868 * protocol_error_reply() has already set u->rcode, which is FAIL when the
2869 * Original-Packet-Code is wrong.
2870 */
2872 fr_pair_list_append(&request->reply_pairs, &reply);
2874 }
2875}
2876
2877/*
2878 * This is the same as request_mux(), except that we immediately mark the request as complete.
2879 */
2880CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
2882 trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
2883{
2884 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
2885 trunk_request_t *treq;
2886
2887 if (unlikely(trunk_connection_pop_request(&treq, tconn) < 0)) return;
2888
2889 /*
2890 * No more requests to send
2891 */
2892 if (!treq) return;
2893
2894 /*
2895 * Write the request, and change to the next state.
2896 */
2897 mod_write(treq->request, treq, h);
2898}
2899
2900CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
2902{
2903 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
2904
2905 DEBUG3("%s - Reading data for connection %s", h->ctx.module_name, h->ctx.fd_info->name);
2906
2907 while (true) {
2908 ssize_t slen;
2909
2910 trunk_request_t *treq;
2912 bio_request_t *u;
2915 uint8_t code = 0;
2917
2918 fr_time_t now;
2919
2921
2922 /*
2923 * Drain the socket of all packets. If we're busy, this
2924 * saves a round through the event loop. If we're not
2925 * busy, a few extra system calls don't matter.
2926 */
2927 slen = fr_bio_read(h->bio.main, NULL, h->buffer, h->buflen);
2928 if (slen == 0) {
2930 return;
2931 }
2932
2933 /*
2934 * We're done reading, return.
2935 */
2936 if (slen == fr_bio_error(IO_WOULD_BLOCK)) return;
2937
2938 if (slen < 0) {
2939 ERROR("%s - Failed reading response from socket: %s",
2940 h->ctx.module_name, fr_syserror(errno));
2942 return;
2943 }
2944
2945 fr_assert(slen >= RADIUS_HEADER_LENGTH); /* checked in verify */
2946
2947 /*
2948 * We only pay attention to Protocol-Error replies.
2949 *
2950 * All other packets are discarded.
2951 */
2953 continue;
2954 }
2955
2956 /*
2957 * Note that we don't care about packet codes. All
2958 * packet codes share the same ID space.
2959 */
2960 rr = radius_track_entry_find(h->tt, h->buffer[1], NULL);
2961 if (!rr) {
2962 WARN("%s - Ignoring reply with ID %i that arrived too late",
2963 h->ctx.module_name, h->buffer[1]);
2964 continue;
2965 }
2966
2967 treq = talloc_get_type_abort(rr->uctx, trunk_request_t);
2968 request = treq->request;
2969 fr_assert(request != NULL);
2970 u = talloc_get_type_abort(treq->rctx, bio_request_t);
2971 fr_assert(u == treq->preq);
2972
2973 /*
2974 * Decode the incoming packet
2975 */
2976 reason = decode(request->reply_ctx, &reply, &code, h, request, u, rr->vector, h->buffer, (size_t)slen);
2977 if (reason != FR_RADIUS_FAIL_NONE) continue;
2978
2979 /*
2980 * Only valid packets are processed
2981 * Otherwise an attacker could perform
2982 * a DoS attack against the proxying servers
2983 * by sending fake responses for upstream
2984 * servers.
2985 */
2986 h->last_reply = now = fr_time();
2987
2988 /*
2989 * Status-Server can have any reply code, we don't care
2990 * what it is. So long as it's signed properly, we
2991 * accept it. This flexibility is because we don't
2992 * expose Status-Server to the admins. It's only used by
2993 * this module for internal signalling.
2994 */
2995 if (u == h->status_u) {
2996 fr_pair_list_free(&reply); /* Probably want to pass this to status_check_reply? */
2998 status_check_reply(tconn, u, now);
2999 continue;
3000 }
3001
3002 /*
3003 * Handle any state changes, etc. needed by receiving a
3004 * Protocol-Error reply packet.
3005 *
3006 * Protocol-Error is also permitted as a reply to any
3007 * packet.
3008 */
3010 }
3011}
3012
3013
3014/** Remove the request from any tracking structures
3015 *
3016 * Frees encoded packets if the request is being moved to a new connection
3017 */
3018static void request_cancel(UNUSED connection_t *conn, void *preq_to_reset,
3019 trunk_cancel_reason_t reason, UNUSED void *uctx)
3020{
3021 bio_request_t *u = preq_to_reset;
3022
3023 /*
3024 * Request has been requeued on the same
3025 * connection due to timeout or DUP signal. We
3026 * keep the same packet to avoid re-encoding it.
3027 */
3028 if (reason == TRUNK_CANCEL_REASON_REQUEUE) {
3029 /*
3030 * Delete the request_timeout
3031 *
3032 * Note: There might not be a request timeout
3033 * set in the case where the request was
3034 * queued for sendmmsg but never actually
3035 * sent.
3036 */
3037 FR_TIMER_DISARM(u->ev);
3038 }
3039
3040 /*
3041 * Other cancellations are dealt with by
3042 * request_conn_release as the request is removed
3043 * from the trunk.
3044 */
3045}
3046
3047/** Clear out anything associated with the handle from the request
3048 *
3049 */
3050static void request_conn_release(connection_t *conn, void *preq_to_reset, UNUSED void *uctx)
3051{
3052 bio_request_t *u = preq_to_reset;
3053 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
3054
3055 FR_TIMER_DISARM(u->ev);
3057
3058 if (h->ctx.inst->mode == RLM_RADIUS_MODE_REPLICATE) return;
3059
3060 /*
3061 * Status checks have their own counts and release in status_check_reset()
3062 */
3063 if (!u->status_check) u->num_replies = 0;
3064
3065 /*
3066 * If there are no outstanding tracking entries
3067 * allocated then the connection is "idle".
3068 */
3069 if (!h->tt || (h->tt->num_requests == 0)) h->last_idle = fr_time();
3070}
3071
3072/** Write out a canned failure
3073 *
3074 */
3075static void request_fail(request_t *request, NDEBUG_UNUSED void *preq, void *rctx,
3076 NDEBUG_UNUSED trunk_request_state_t state, UNUSED void *uctx)
3077{
3078 bio_request_t *u = talloc_get_type_abort(rctx, bio_request_t);
3079
3080 fr_assert(u == preq);
3081
3082 fr_assert(!u->rr && !u->packet && fr_pair_list_empty(&u->extra) && !fr_timer_armed(u->ev)); /* Dealt with by request_conn_release */
3083
3085
3086 /*
3087 * The trunk frees the status check treq after this callback. Clear the pointer so that
3088 * _bio_request_free() does not look at a freed treq.
3089 */
3090 if (u->status_check) {
3091 u->treq = NULL;
3092 return;
3093 }
3094
3096 u->treq = NULL;
3097
3099}
3100
3101/** Response has already been written to the rctx at this point
3102 *
3103 */
3104static void request_complete(request_t *request, NDEBUG_UNUSED void *preq, void *rctx, UNUSED void *uctx)
3105{
3106 bio_request_t *u = talloc_get_type_abort(rctx, bio_request_t);
3107
3108 fr_assert(u == preq);
3109
3110 fr_assert(!u->rr && !u->packet && fr_pair_list_empty(&u->extra) && !fr_timer_armed(u->ev)); /* Dealt with by request_conn_release */
3111
3112 /*
3113 * The trunk frees the status check treq after this callback. Clear the pointer so that
3114 * _bio_request_free() does not look at a freed treq.
3115 */
3116 if (u->status_check) {
3117 u->treq = NULL;
3118 return;
3119 }
3120
3121 u->treq = NULL;
3122
3124}
3125
3126/** Resume execution of the request, returning the rcode set during trunk execution
3127 *
3128 */
3130{
3131 bio_request_t *u = talloc_get_type_abort(mctx->rctx, bio_request_t);
3132 rlm_rcode_t rcode = u->rcode;
3133
3134 talloc_free(u);
3135
3136 RETURN_UNLANG_RCODE(rcode);
3137}
3138
3139static void do_signal(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_signal_t action);
3140
3141static void mod_signal(module_ctx_t const *mctx, request_t *request, fr_signal_t action)
3142{
3144
3145 bio_request_t *u = talloc_get_type_abort(mctx->rctx, bio_request_t);
3146
3147 do_signal(inst, u, request, action);
3148}
3149
3151{
3152 /*
3153 * We received a duplicate packet, but we're not doing
3154 * synchronous proxying. Ignore the dup, and rely on the
3155 * IO submodule to time it's own retransmissions.
3156 */
3157 if ((action == FR_SIGNAL_DUP) && (inst->mode != RLM_RADIUS_MODE_PROXY)) return;
3158
3159 switch (action) {
3160 /*
3161 * The request is being cancelled, tell the
3162 * trunk so it can clean up the treq.
3163 */
3164 case FR_SIGNAL_CANCEL:
3165 if (u->treq) {
3167 u->treq = NULL;
3168 }
3169 return;
3170
3171 /*
3172 * Requeue the request on the same connection
3173 * causing a "retransmission" if the request
3174 * has already been sent out.
3175 *
3176 * mod_dup() checks u->treq and complains if necessary.
3177 */
3178 case FR_SIGNAL_DUP:
3179 mod_dup(request, u);
3180 return;
3181
3182 default:
3183 return;
3184 }
3185}
3186
3187/** Free a bio_request_t
3188 *
3189 * Allows us to set break points for debugging.
3190 */
3192{
3193 if (!u->treq) return 0;
3194
3195#ifndef NDEBUG
3196 {
3197 trunk_request_t *treq;
3198 treq = talloc_get_type_abort(u->treq, trunk_request_t);
3199 fr_assert(treq->preq == u);
3200 }
3201#endif
3202
3203 fr_assert_msg(!fr_timer_armed(u->ev), "bio_request_t freed with active timer");
3204
3206
3207 fr_assert(u->rr == NULL);
3208
3209 return 0;
3210}
3211
3212static int mod_enqueue(bio_request_t **p_u, fr_retry_config_t const **p_retry_config,
3213 rlm_radius_t const *inst, trunk_t *trunk, request_t *request)
3214{
3215 bio_request_t *u;
3216 trunk_request_t *treq;
3218
3219 fr_assert(request->packet->code > 0);
3220 fr_assert(request->packet->code < FR_RADIUS_CODE_MAX);
3221
3222 /*
3223 * Do any necessary RADIUS level fixups
3224 * - check Proxy-State
3225 * - do CHAP-Challenge fixups
3226 */
3227 if (radius_fixups(inst, request) < 0) return -1;
3228
3229 treq = trunk_request_alloc(trunk, request);
3230 if (!treq) {
3231 REDEBUG("Failed allocating handler for request");
3232 return -1;
3233 }
3234
3235 MEM(u = talloc_zero(request, bio_request_t));
3236 talloc_set_destructor(u, _bio_request_free);
3237
3238 /*
3239 * Can't use compound literal - const issues.
3240 */
3241 u->code = request->packet->code;
3242 u->priority = request->priority;
3243 u->recv_time = request->async->recv_time;
3245
3246 u->retry.count = 1;
3247
3249
3250 switch(trunk_request_enqueue(&treq, trunk, request, u, u)) {
3251 case TRUNK_ENQUEUE_OK:
3253 break;
3254
3256 REDEBUG("Unable to queue packet - connections at maximum capacity");
3257 fail:
3258 fr_assert(!u->rr && !u->packet); /* Should not have been fed to the muxer */
3259 trunk_request_free(&treq); /* Return to the free list */
3260 talloc_free(u);
3261 return -1;
3262
3264 REDEBUG("All destinations are down - cannot send packet");
3265 goto fail;
3266
3267 case TRUNK_ENQUEUE_FAIL:
3268 REDEBUG("Unable to queue packet");
3269 goto fail;
3270 }
3271
3272 u->treq = treq; /* Remember for signalling purposes */
3273 fr_assert(treq->rctx == u);
3274
3275 /*
3276 * Figure out if we're originating the packet or proxying it. And also figure out if we have to
3277 * retry.
3278 */
3279 switch (inst->mode) {
3281 case RLM_RADIUS_MODE_UNCONNECTED_REPLICATE: /* unconnected sockets are UDP, and bypass the trunk */
3282 REDEBUG("Internal sanity check failed - connection trunking cannot be used for replication");
3283 return -1;
3284
3285 /*
3286 * We originate this packet if it was taken from the detail module, which doesn't have a
3287 * real client. @todo - do a better check here.
3288 *
3289 * We originate this packet if the parent request is not compatible with this one
3290 * (i.e. it's from a different protocol).
3291 *
3292 * We originate the packet if the parent is from the same dictionary, but has a different
3293 * packet code. This lets us receive Accounting-Request, and originate
3294 * Disconnect-Request.
3295 */
3298 if (!request->parent) {
3299 u->proxied = (request->client && request->client->cs != NULL);
3300
3301 } else if (!fr_dict_compatible(request->parent->proto_dict, request->proto_dict)) {
3302 u->proxied = false;
3303
3304 } else {
3305 u->proxied = (request->parent->packet->code == request->packet->code);
3306 }
3307
3308 /*
3309 * Proxied packets get a final timeout, as we retry only on DUP packets.
3310 */
3311 if (u->proxied) goto timeout_retry;
3312
3314
3315 /*
3316 * Client packets (i.e. packets we originate) get retries for UDP. And no retries for TCP.
3317 */
3319 if (inst->fd_config.socket_type == SOCK_DGRAM) {
3320 retry_config = &inst->retry[u->code];
3321 break;
3322 }
3324
3325 /*
3326 * Replicated packets are never retried, but they have a timeout if the socket isn't
3327 * ready for writing.
3328 */
3330 timeout_retry:
3331 retry_config = &inst->timeout_retry;
3332 break;
3333
3334 default:
3335 fr_assert(0);
3336 return -1;
3337 }
3338
3339 /*
3340 * The event loop will take care of demux && sending the
3341 * packet, along with any retransmissions.
3342 */
3343 *p_u = u;
3344 *p_retry_config = retry_config;
3345
3346 return 1;
3347}
3348
3349static void home_server_free(void *data)
3350{
3351 home_server_t *home = data;
3352
3353 talloc_free(home);
3354}
3355
3358 .connection_notify = thread_conn_notify,
3359 .request_prioritise = request_prioritise,
3360 .request_mux = request_mux,
3361 .request_demux = request_demux,
3362 .request_conn_release = request_conn_release,
3363 .request_complete = request_complete,
3364 .request_fail = request_fail,
3365 .request_cancel = request_cancel,
3366};
3367
3370 .connection_notify = thread_conn_notify,
3371 .request_prioritise = request_prioritise,
3372 .request_mux = request_replicate_mux,
3373 .request_demux = request_replicate_demux,
3374 .request_conn_release = request_conn_release,
3375 .request_complete = request_complete,
3376 .request_fail = request_fail,
3377 .request_cancel = request_cancel,
3378};
3379
3380/** Instantiate thread data for the submodule.
3381 *
3382 */
3384{
3385 rlm_radius_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
3386 bio_thread_t *thread = talloc_get_type_abort(mctx->thread, bio_thread_t);
3387 bool delay_start = false;
3388
3389 thread->ctx.el = mctx->el;
3390 thread->ctx.inst = inst;
3391 thread->ctx.fd_config = inst->fd_config;
3392 thread->ctx.radius_ctx = inst->common_ctx;
3393
3394#ifdef WITH_TLS
3395 /*
3396 * SSL_CTX cannot be shared across threads, so each worker thread allocates its own.
3397 */
3398 if (inst->tls_conf) {
3399 thread->ctx.ssl_ctx = fr_tls_ctx_alloc(inst->tls_conf, true);
3400 if (!thread->ctx.ssl_ctx) {
3401 PERROR("%s - failed allocating TLS context", inst->name);
3402 return -1;
3403 }
3404 }
3405#endif
3406
3407 switch (inst->mode) {
3410 inst->home_server_lifetime);
3412
3413 default:
3414 /*
3415 * Assign each thread a portion of the available source port range.
3416 */
3417 if (thread->ctx.fd_config.src_port_start) {
3418 uint16_t range = inst->fd_config.src_port_end - inst->fd_config.src_port_start + 1;
3419 thread->num_ports = range / main_config->max_workers;
3420 thread->ctx.fd_config.src_port_start = inst->fd_config.src_port_start + (thread->num_ports * fr_schedule_worker_id());
3421 thread->ctx.fd_config.src_port_end = inst->fd_config.src_port_start + (thread->num_ports * (fr_schedule_worker_id() +1)) - 1;
3422 if (inst->mode != RLM_RADIUS_MODE_XLAT_PROXY) {
3423 thread->connections = talloc_zero_array(thread, connection_t *, thread->num_ports);
3425 }
3426 }
3427
3428 /*
3429 * @todo - we are called for threads which do NOT have an interpreter set up. e.g. the
3430 * coordinator thread. This is likely wrong.
3431 *
3432 * For now, work around it.
3433 */
3434#ifdef WITH_TLS
3435 if (thread->ctx.ssl_ctx && !unlang_interpret_get_thread_default()) delay_start = true;
3436#endif
3437
3438 thread->ctx.trunk = trunk_alloc(thread, mctx->el, &io_funcs,
3439 &inst->trunk_conf, inst->name, thread, delay_start, inst->trigger_args);
3440 if (!thread->ctx.trunk) return -1;
3441 return 0;
3442
3444 /*
3445 * Replication trunks use a different set of functions.
3446 */
3447 thread->ctx.trunk = trunk_alloc(thread, mctx->el, &io_replicate_funcs,
3448 &inst->trunk_conf, inst->name, thread, false, inst->trigger_args);
3449 if (!thread->ctx.trunk) return -1;
3450 return 0;
3451
3453 break;
3454 }
3455
3456 /*
3457 * If we have a port range, allocate the source port based
3458 * on the range start, plus the thread ID. This means
3459 * that we can avoid "hunt and peck" attempts to open up
3460 * the source port.
3461 */
3462 if (thread->ctx.fd_config.src_port_start) {
3464 }
3465
3466 /*
3467 * Allocate an unconnected socket for replication.
3468 */
3469 thread->bio.fd = fr_bio_fd_alloc(thread, &thread->ctx.fd_config, 0);
3470 if (!thread->bio.fd) {
3471 PERROR("%s - failed opening socket", inst->name);
3472 return -1;
3473 }
3474
3475 thread->bio.fd->uctx = thread;
3476 thread->ctx.fd_info = fr_bio_fd_info(thread->bio.fd);
3477 fr_assert(thread->ctx.fd_info != NULL);
3478
3479 (void) fr_bio_fd_write_only(thread->bio.fd);
3480
3481 DEBUG("%s - Opened unconnected replication socket %s", inst->name, thread->ctx.fd_info->name);
3482 return 0;
3483}
3484
3485/** Free thread data for the submodule.
3486 *
3487 */
3489{
3490#ifdef WITH_TLS
3491 bio_thread_t *thread = talloc_get_type_abort(mctx->thread, bio_thread_t);
3492
3493 if (thread->ctx.ssl_ctx) SSL_CTX_free(thread->ctx.ssl_ctx);
3494#else
3495 (void) mctx;
3496#endif
3497
3498 return 0;
3499}
3500
3502 { .required = true, .single = true, .type = FR_TYPE_COMBO_IP_ADDR },
3503 { .required = true, .single = true, .type = FR_TYPE_UINT16 },
3504 { .required = true, .single = true, .type = FR_TYPE_STRING },
3506};
3507
3508/*
3509 * %replicate.sendto.ipaddr(ipaddr, port, secret)
3510 */
3512 xlat_ctx_t const *xctx,
3513 request_t *request, fr_value_box_list_t *args)
3514{
3515 bio_thread_t *thread = talloc_get_type_abort(xctx->mctx->thread, bio_thread_t);
3516 fr_value_box_t *ipaddr, *port, *secret;
3517 ssize_t packet_len;
3518 uint8_t buffer[4096];
3519 fr_radius_ctx_t radius_ctx;
3522
3523 XLAT_ARGS(args, &ipaddr, &port, &secret);
3524
3525 /*
3526 * Can't change IP address families.
3527 */
3528 if (ipaddr->vb_ip.af != thread->ctx.fd_info->socket.af) {
3529 RPERROR("Invalid destination IP address family in %pV", ipaddr);
3530 return XLAT_ACTION_FAIL;
3531 }
3532
3533 /*
3534 * This shouldn't happen, but what the heck.
3535 */
3536 if (!FR_RADIUS_PACKET_CODE_VALID(request->packet->code)) {
3537 REDEBUG("Cannot replicate packet code %u, it is not a RADIUS packet code", request->packet->code);
3538 return XLAT_ACTION_FAIL;
3539 }
3540
3541 /*
3542 * Warn if we're not replicating accounting data. It likely won't wokr/
3543 */
3544 if (request->packet->code != FR_RADIUS_CODE_ACCOUNTING_REQUEST) {
3545 RWDEBUG("Replication of packets other then Accounting-Request will likely not do what you want.");
3546 }
3547
3548 /*
3549 * Set up various context things.
3550 */
3551 radius_ctx = (fr_radius_ctx_t) {
3552 .secret = secret->vb_strvalue,
3553 .secret_length = secret->vb_length,
3554 .proxy_state = 0,
3555 };
3556
3558 .common = &radius_ctx,
3559 .rand_ctx = (fr_fast_rand_t) {
3560 .a = fr_rand(),
3561 .b = fr_rand(),
3562 },
3563 .code = request->packet->code,
3564 .id = thread->bio.id++ & 0xff,
3565 .add_proxy_state = false,
3566 };
3567
3568 /*
3569 * Encode the entire packet.
3570 */
3571 packet_len = fr_radius_encode(&FR_DBUFF_TMP(buffer, sizeof(buffer)),
3572 &request->request_pairs, &encode_ctx);
3573 if (packet_len < 0) {
3574 RPERROR("Failed encoding replicated packet");
3575 return XLAT_ACTION_FAIL;
3576 }
3577
3578 /*
3579 * Sign it.
3580 */
3581 if (fr_radius_sign(buffer, NULL, (uint8_t const *) radius_ctx.secret, radius_ctx.secret_length) < 0) {
3582 RPERROR("Failed signing replicated packet");
3583 return XLAT_ACTION_FAIL;
3584 }
3585
3586 /*
3587 * Prepare destination address.
3588 */
3589 addr = (fr_bio_fd_packet_ctx_t) {
3590 .socket = thread->ctx.fd_info->socket,
3591 };
3592 addr.socket.inet.dst_ipaddr = ipaddr->vb_ip;
3593 addr.socket.inet.dst_port = port->vb_uint16;
3594
3595 RDEBUG("Replicating packet to %pV:%u", ipaddr, port->vb_uint16);
3596
3597 /*
3598 * We either send it, or fail.
3599 */
3600 packet_len = fr_bio_write(thread->bio.fd, &addr, buffer, packet_len);
3601 if (packet_len < 0) {
3602 RPERROR("Failed replicating packet to %pV:%u", ipaddr, port->vb_uint16);
3603 return XLAT_ACTION_FAIL;
3604 }
3605
3606 /*
3607 * No return value.
3608 */
3609 return XLAT_ACTION_DONE;
3610}
3611
3612// **********************************************************************
3613
3614/** Dynamic home server code
3615 *
3616 */
3617
3618static fr_cmp_ret_t home_server_cmp(void const *one, void const *two)
3619{
3620 home_server_t const *a = one;
3621 home_server_t const *b = two;
3622 fr_cmp_ret_t rcode;
3623
3625 if (rcode != 0) return rcode;
3626
3628}
3629
3631 xlat_ctx_t const *xctx,
3632 request_t *request, UNUSED fr_value_box_list_t *in)
3633{
3634 bio_request_t *u = talloc_get_type_abort(xctx->rctx, bio_request_t);
3635 fr_value_box_t *dst;
3636
3637 if (u->rcode == RLM_MODULE_FAIL) return XLAT_ACTION_FAIL;
3638
3640 dst->vb_uint32 = request->reply->code;
3641
3642 fr_dcursor_append(out, dst);
3643
3644 return XLAT_ACTION_DONE;
3645}
3646
3648{
3649 rlm_radius_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_radius_t);
3650 bio_request_t *u = talloc_get_type_abort(xctx->rctx, bio_request_t);
3651
3652 do_signal(inst, u, request, action);
3653}
3654
3655/*
3656 * @todo - change this to mod_retry
3657 */
3658static void xlat_sendto_retry(xlat_ctx_t const *xctx, request_t *request, fr_retry_t const *retry)
3659{
3660 rlm_radius_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_radius_t);
3661 bio_request_t *u = talloc_get_type_abort(xctx->rctx, bio_request_t);
3662
3663 do_retry(inst, u, request, retry);
3664}
3665
3666/*
3667 * %proxy.sendto.ipaddr(ipaddr, port, secret)
3668 */
3670 xlat_ctx_t const *xctx,
3671 request_t *request, fr_value_box_list_t *args)
3672{
3673 rlm_radius_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_radius_t);
3674 bio_thread_t *thread = talloc_get_type_abort(xctx->mctx->thread, bio_thread_t);
3675 fr_value_box_t *ipaddr, *port, *secret;
3676 home_server_t *home;
3677 bio_request_t *u = NULL;
3678 fr_retry_config_t const *retry_config = NULL;
3679 int rcode;
3680 xlat_action_t action;
3681
3682 XLAT_ARGS(args, &ipaddr, &port, &secret);
3683
3684 /*
3685 * The packet code indexes tables which have FR_RADIUS_CODE_MAX entries.
3686 */
3687 if (!FR_RADIUS_PACKET_CODE_VALID(request->packet->code)) {
3688 REDEBUG("Cannot proxy packet code %u, it is not a RADIUS packet code", request->packet->code);
3689 return XLAT_ACTION_FAIL;
3690 }
3691
3692 /*
3693 * Can't change IP address families.
3694 */
3695 if (ipaddr->vb_ip.af != thread->ctx.fd_config.src_ipaddr.af) {
3696 RDEBUG("Invalid destination IP address family in %pV", ipaddr);
3697 return XLAT_ACTION_DONE;
3698 }
3699
3700 fr_rb_find((void **)&home, &thread->bio.expires.tree, &(home_server_t) {
3701 .ctx = {
3702 .fd_config = (fr_bio_fd_config_t) {
3703 .dst_ipaddr = ipaddr->vb_ip,
3704 .dst_port = port->vb_uint16,
3705 },
3706 },
3707 });
3708 if (!home) {
3709 /*
3710 * Track which connections are made to this home server from which open ports.
3711 */
3712 MEM(home = (home_server_t *) talloc_zero_array(thread, uint8_t, sizeof(home_server_t) + sizeof(connection_t *) * thread->num_ports));
3713 talloc_set_type(home, home_server_t);
3714
3715 *home = (home_server_t) {
3716 .ctx = (bio_handle_ctx_t) {
3718 .module_name = inst->name,
3719 .inst = inst,
3720 .limit_source_ports = (thread->num_ports > 0) ? LIMIT_PORTS_DYNAMIC : LIMIT_PORTS_NONE,
3721 .dynamic = true,
3722#ifdef WITH_TLS
3723 .ssl_ctx = thread->ctx.ssl_ctx, /* DTLS to dynamic destinations uses the thread context */
3724#endif
3725 },
3726 .num_ports = thread->num_ports,
3727 };
3728
3729 /*
3730 * Copy the home server configuration from the thread configuration. Then update it with
3731 * the needs of the home server.
3732 */
3733 home->ctx.fd_config = thread->ctx.fd_config;
3734 home->ctx.fd_config.type = FR_BIO_FD_CONNECTED;
3735 home->ctx.fd_config.dst_ipaddr = ipaddr->vb_ip;
3736 home->ctx.fd_config.dst_port = port->vb_uint16;
3737
3738 home->ctx.radius_ctx = (fr_radius_ctx_t) {
3739 .secret = talloc_strdup(home, secret->vb_strvalue),
3740 .secret_length = secret->vb_length,
3741 .proxy_state = inst->common_ctx.proxy_state,
3742 };
3743
3744 /*
3745 * Allocate the trunk and start it up.
3746 */
3747 home->ctx.trunk = trunk_alloc(home, unlang_interpret_event_list(request), &io_funcs,
3748 &inst->trunk_conf, inst->name, home, false, inst->trigger_args);
3749 if (!home->ctx.trunk) {
3750 fail:
3751 talloc_free(home);
3752 return XLAT_ACTION_FAIL;
3753 }
3754
3755 if (!fr_rb_expire_insert(&thread->bio.expires, home, fr_time())) goto fail;
3756 } else {
3757 fr_rb_expire_t *expire = &thread->bio.expires;
3758 fr_time_t now = fr_time();
3759 home_server_t *old;
3760
3761 /*
3762 * We can't change secrets on the fly. The home
3763 * server has to expire first, and then the
3764 * secret can be changed.
3765 */
3766 if ((home->ctx.radius_ctx.secret_length != secret->vb_length) ||
3767 (strcmp(home->ctx.radius_ctx.secret, secret->vb_strvalue) != 0)) {
3768 RWDEBUG("The new secret is not the same as the old secret: Ignoring the new one");
3769 }
3770
3771 fr_rb_expire_update(expire, home, now);
3772
3773 while ((old = fr_dlist_head(&expire->head)) != NULL) {
3774 (void) talloc_get_type_abort(old, home_server_t);
3775
3776 fr_assert(old->ctx.trunk);
3777
3778 /*
3779 * Don't delete the home server we're about to use.
3780 */
3781 if (old == home) break;
3782
3783 /*
3784 * It still has a request allocated, do nothing.
3785 */
3786 if (old->ctx.trunk->req_alloc) break;
3787
3788 /*
3789 * Not yet time to expire.
3790 */
3791 if (fr_time_gt(old->expire.when, now)) break;
3792
3793 fr_dlist_remove(&expire->head, old);
3794 fr_rb_delete(&expire->tree, old);
3795 }
3796 }
3797
3798 /*
3799 * Enqueue the packet on the per-home-server trunk.
3800 */
3801 rcode = mod_enqueue(&u, &retry_config, inst, home->ctx.trunk, request);
3802 if (rcode == 0) return XLAT_ACTION_DONE;
3803
3804 if (rcode < 0) {
3805 REDEBUG("Failed enqueuing packet");
3806 return XLAT_ACTION_FAIL;
3807 }
3808 fr_assert(u != NULL);
3809 fr_assert(retry_config != NULL);
3810
3811 /*
3812 * Start the retry.
3813 *
3814 * @todo - change unlang_xlat_timeout_add() to unlang_xlat_retry_add().
3815 */
3816 fr_retry_init(&u->retry, fr_time(), retry_config);
3817
3820 u, retry_config);
3821
3822 /*
3823 * The xlat is not yielding, so xlat_sendto_signal() will never be called. Remove the request
3824 * from the trunk.
3825 */
3826 if ((action == XLAT_ACTION_FAIL) && u->treq) {
3828 }
3829
3830 return action;
3831}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:42
static int const char char buffer[256]
Definition acutest.h:641
int const char * file
Definition acutest.h:855
va_list args
Definition acutest.h:923
void int line
Definition acutest.h:810
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:184
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:161
void * uctx
user ctx, caller can manually set it.
Definition base.h:114
#define fr_bio_error(_x)
Definition base.h:200
void fr_bio_tls_close_send(fr_bio_tls_t *my)
Send a TLS close_notify alert to the peer.
Definition tls.c:957
fr_tls_connection_t * fr_bio_tls_conn(fr_bio_tls_t *my)
The TLS connection, so the caller can set conn->name
Definition tls.c:1082
int fr_bio_tls_connect(fr_bio_tls_t *my)
Take the connection through every state which comes before application data.
Definition tls.c:1102
fr_bio_tls_t * fr_bio_tls_alloc(request_t *request, fr_bio_t *next, SSL_CTX *ssl_ctx, bool client, bool client_cert)
Allocate a TLS bio.
Definition tls.c:1031
static int packet_ctx
the tests pass only the address of packet_ctx
static uint8_t request[4]
static uint8_t reply[4]
#define NDEBUG_UNUSED
Definition build.h:426
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:422
#define CC_NO_UBSAN(_sanitize)
Definition build.h:534
#define CMP_PREFER_LARGER(_a, _b)
Evaluates to -1 for a > b, and +1 for a < b.
Definition build.h:126
#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:130
#define unlikely(_x)
Definition build.h:486
#define UNUSED
Definition build.h:415
fr_cmp_ret_t
Result of an ordering comparison.
Definition build.h:113
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:556
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:248
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition debug.h:254
#define MEM(x)
Definition debug.h:38
@ 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_STATUS_SERVER
RFC2865/RFC5997 - Status Server (request)
Definition defs.h:44
@ 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:88
#define ERROR(fmt,...)
Definition dhcpclient.c:40
int main(int argc, char **argv)
Definition dhcpclient.c:530
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
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:2948
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:468
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:620
#define fr_event_fd_insert(...)
Definition event.h:247
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:150
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:83
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:1349
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:1116
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:1446
int fr_bio_fd_write_only(fr_bio_t *bio)
Mark up a bio as write-only.
Definition fd.c:1493
fr_socket_t socket
as connected socket
Definition fd.h:145
char const * name
printable name of this BIO
Definition fd.h:150
uint16_t src_port
our port
Definition fd.h:104
bool eof
are we at EOF?
Definition fd.h:154
fr_bio_fd_type_t type
type of the socket
Definition fd.h:147
fr_bio_fd_state_t state
connecting, open, closed, etc.
Definition fd.h:148
uint16_t src_port_start
limit source port ranges for client BIOs
Definition fd.h:107
int connect_errno
from connect() or other APIs
Definition fd.h:156
fr_ipaddr_t dst_ipaddr
their IP address
Definition fd.h:102
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
Definition fd.h:63
@ FR_BIO_FD_UNCONNECTED
unconnected UDP / datagram only
Definition fd.h:60
uint16_t src_port_end
limit source port ranges for client BIOs
Definition fd.h:108
int socket_type
SOCK_STREAM or SOCK_DGRAM.
Definition fd.h:95
uint16_t dst_port
their port
Definition fd.h:105
@ FR_BIO_FD_STATE_CONNECTING
Definition fd.h:55
@ FR_BIO_FD_STATE_OPEN
error states must be before this
Definition fd.h:54
fr_socket_t socket
socket information, including FD.
Definition fd.h:47
bool write_blocked
did we block on write?
Definition fd.h:153
fr_ipaddr_t src_ipaddr
our IP address
Definition fd.h:101
Configuration for sockets.
Definition fd.h:92
Run-time status of the socket.
Definition fd.h:144
Per-packet context.
Definition fd.h:46
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
Definition function.h:181
talloc_free(hp)
fr_cmp_ret_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1353
int af
Address family.
Definition inet.h:64
void unlang_interpret_set(request_t *request, unlang_interpret_t *intp)
Set a specific interpreter for a request.
Definition interpret.c:2759
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:2022
unlang_interpret_t * unlang_interpret_get_thread_default(void)
Get the default interpreter for this thread.
Definition interpret.c:2801
unlang_t const * unlang_interpret_instruction(request_t *request)
Get the current instruction.
Definition interpret.c:327
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition interpret.c:1794
int unlang_interpret_force_result(unlang_t const *instruction, unlang_result_t *p_result, fr_timer_list_t *tl, fr_time_delta_t expire)
Set (or clear) a forced result.
Definition interpret.c:350
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:2778
#define UNLANG_TOP_FRAME
Definition interpret.h:36
el_self ties the lifetime of the event list to the interpreter
void fr_bio_cb_set(fr_bio_t *bio, fr_bio_cb_funcs_t const *cb)
Definition base.c:260
HIDDEN fr_dict_attr_t const * attr_eap_message
Definition base.c:94
void log_request_proto_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 list of protocol fr_pair_ts.
Definition log.c:905
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:831
#define PERROR(_fmt,...)
Definition log.h:233
#define DEBUG3(_fmt,...)
Definition log.h:271
#define RWDEBUG(fmt,...)
Definition log.h:378
#define RWARN(fmt,...)
Definition log.h:314
#define DEBUG4(_fmt,...)
Definition log.h:272
#define RPERROR(fmt,...)
Definition log.h:319
#define RINFO(fmt,...)
Definition log.h:313
#define RPEDEBUG(fmt,...)
Definition log.h:393
#define HEXDUMP3(_data, _len, _fmt,...)
Definition log.h:742
#define RHEXDUMP3(_data, _len, _fmt,...)
Definition log.h:724
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:1566
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:1846
#define fr_time()
Definition event.c:58
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Definition event.c:1204
Stores all information relating to an event list.
Definition event.c:375
fr_log_t default_log
Definition log.c:308
#define fr_log(_log, _lvl, _file, _line, _fmt,...)
Definition log.h:172
@ L_DBG_LVL_3
3rd highest priority debug messages (-xxx | -Xx).
Definition log.h:69
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
Definition log.h:68
fr_log_type_t
Definition log.h:51
@ L_ERR
Error message.
Definition log.h:53
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition packet.c:38
Minimal data structure to use the new code.
Definition listen.h:79
int unlang_load_balance_persist(request_t *request)
Persist the current load-balance selection.
main_config_t const * main_config
Main server configuration.
Definition main_config.c:56
uint32_t max_workers
for the scheduler
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:686
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:863
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)
unsigned short uint16_t
@ 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:3212
fr_bio_fd_config_t fd_config
for threads or sockets
Definition bio.c:51
int num_ports
Definition bio.c:180
static void do_retry(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_retry_t const *retry)
Definition bio.c:2184
fr_timer_t * ev
timer for retransmissions
Definition bio.c:171
static void status_check_timeout(UNUSED fr_timer_list_t *tl, fr_time_t now, void *uctx)
We timed out, without getting a status check reply.
Definition bio.c:1959
static void request_replicate_mux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Definition bio.c:2881
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:382
static void request_demux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Definition bio.c:2685
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:1523
uint8_t id
Last ID assigned to this packet.
Definition bio.c:165
static void request_replicate_demux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Definition bio.c:2901
uint32_t max_packet_size
Our max packet size. may be different from the parent.
Definition bio.c:103
static void do_signal(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_signal_t action)
Definition bio.c:3150
bool dynamic
is this a dynamic home server.
Definition bio.c:55
static void bio_connected(fr_bio_t *bio)
Definition bio.c:1037
uint32_t num_replies
number of reply packets, sent is in retry.count
Definition bio.c:157
static const trunk_io_funcs_t io_funcs
Definition bio.c:3356
static void conn_close(UNUSED fr_event_list_t *el, void *handle, void *uctx)
Shutdown/close a file descriptor.
Definition bio.c:1397
bool write_blocked
A stream write blocked, and has not yet resumed.
Definition bio.c:86
uint32_t priority
copied from request->async->priority
Definition bio.c:154
static rlm_rcode_t radius_code_to_rcode[FR_RADIUS_CODE_MAX]
Turn a reply code into a module rcode;.
Definition bio.c:188
static bool bio_at_eof(bio_handle_t const *h)
Is the connection at EOF?
Definition bio.c:141
unlang_t const * instruction
Instruction which triggered the start of the zombie period.
Definition bio.c:117
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:1558
char const * module_name
the module that opened the connection
Definition bio.c:47
fr_bio_fd_info_t const * fd_info
status of the FD.
Definition bio.c:52
connection_t * connections[]
for tracking outbound connections
Definition bio.c:181
uint8_t last_id
Used when replicating to ensure IDs are distributed evenly.
Definition bio.c:100
static void bio_eof(fr_bio_t *bio)
The BIO chain is at EOF, and has no more data for us.
Definition bio.c:1061
static void mod_retry(module_ctx_t const *mctx, request_t *request, fr_retry_t const *retry)
Handle module retries.
Definition bio.c:2176
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:1718
static int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id)
Definition bio.c:1789
fr_time_t last_reply
When we last received a reply.
Definition bio.c:111
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:3050
int fd
File descriptor.
Definition bio.c:82
bio_request_t * status_u
for sending status check packets
Definition bio.c:120
bio_handle_ctx_t ctx
common struct for home servers and BIO handles
Definition bio.c:62
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:1068
static void mod_write(request_t *request, trunk_request_t *treq, bio_handle_t *h)
Definition bio.c:2286
#define REQUIRE_MA(_h)
fr_pair_list_t extra
VPs for debugging, like Proxy-State.
Definition bio.c:162
bool proxied
is this request being proxied
Definition bio.c:160
size_t buflen
Receive buffer length.
Definition bio.c:106
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:472
struct bio_handle_t::@223 bio
bio_limit_ports_t
Definition bio.c:40
@ LIMIT_PORTS_DYNAMIC
Limited source ports for dynamic home servers.
Definition bio.c:43
@ LIMIT_PORTS_NONE
Source port not restricted.
Definition bio.c:41
@ LIMIT_PORTS_STATIC
Limited source ports for static home servers.
Definition bio.c:42
trunk_connection_event_t notify_on
The events which the trunk last asked for.
Definition bio.c:134
fr_time_t last_idle
last time we had nothing to do
Definition bio.c:114
static fr_cmp_ret_t request_prioritise(void const *one, void const *two)
Definition bio.c:1679
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:234
trunk_connection_t * tconn
The trunk connection.
Definition bio.c:132
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:3511
radius_track_entry_t * rr
ID tracking, resend count, etc.
Definition bio.c:170
size_t packet_len
Length of the packet.
Definition bio.c:167
static int _bio_handle_free(bio_handle_t *h)
Free a connection handle, closing associated resources.
Definition bio.c:983
static void conn_writable_flush(fr_event_list_t *el, int fd, int flags, void *uctx)
The fd is writable, and the connection is blocked on write.
Definition bio.c:1573
size_t partial
partially sent data
Definition bio.c:168
fr_event_list_t * el
Event list.
Definition bio.c:49
static int bio_write_blocked(fr_bio_t *bio)
Pause the connection when a stream BIO is blocked on write.
Definition bio.c:665
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:3018
static void home_server_free(void *data)
Definition bio.c:3349
bool eof
The BIO chain is at EOF, see bio_eof().
Definition bio.c:84
int num_ports
Definition bio.c:70
static void protocol_error_reply(bio_request_t *u, bio_handle_t *h)
Deal with Protocol-Error replies, and possible negotiation.
Definition bio.c:2509
static void status_check_reset(bio_handle_t *h, bio_request_t *u)
Reset a status_check packet, ready to reuse.
Definition bio.c:270
static const trunk_io_funcs_t io_replicate_funcs
Definition bio.c:3368
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:3075
fr_time_t recv_time
copied from request->async->recv_time
Definition bio.c:155
fr_retry_t retry
retransmission timers
Definition bio.c:172
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:3669
rlm_rcode_t rcode
from the transport
Definition bio.c:152
static void thread_conn_notify(trunk_connection_t *tconn, connection_t *conn, fr_event_list_t *el, trunk_connection_event_t notify_on, void *uctx)
static void status_check_alloc(bio_handle_t *h)
Definition bio.c:287
fr_time_t mrs_time
Most recent sent time which had a reply.
Definition bio.c:110
bool status_checking
whether we're doing status checks
Definition bio.c:119
static void status_check_reply(trunk_connection_t *tconn, bio_request_t *u, fr_time_t now)
Deal with replies replies to status checks and possible negotiation.
Definition bio.c:2641
trunk_t * trunk
trunk handler
Definition bio.c:50
fr_time_t last_sent
last time we sent a packet.
Definition bio.c:113
static void zombie_timeout(fr_timer_list_t *tl, fr_time_t now, void *uctx)
Mark a connection dead after "zombie_interval".
Definition bio.c:1900
bio_handle_ctx_t ctx
for copying to bio_handle_t
Definition bio.c:176
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Instantiate thread data for the submodule.
Definition bio.c:3383
static void bio_error(fr_bio_t *bio)
Definition bio.c:1046
static bool check_for_zombie(request_t *request, trunk_connection_t *tconn, fr_time_t now, fr_time_t last_sent)
See if the connection is zombied.
Definition bio.c:2052
static void mod_signal(module_ctx_t const *mctx, request_t *request, fr_signal_t action)
Definition bio.c:3141
struct bio_thread_t::@222 bio
static void conn_init_next(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
Perform the next step of init and negotiation.
Definition bio.c:451
static int _bio_request_free(bio_request_t *u)
Free a bio_request_t.
Definition bio.c:3191
connection_t * conn
Definition bio.c:98
fr_time_t first_sent
first time we sent a packet since going idle
Definition bio.c:112
static unlang_action_t mod_resume(unlang_result_t *p_result, module_ctx_t const *mctx, UNUSED request_t *request)
Resume execution of the request, returning the rcode set during trunk execution.
Definition bio.c:3129
fr_timer_t * zombie_ev
Zombie timeout.
Definition bio.c:116
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:1494
static void xlat_sendto_retry(xlat_ctx_t const *xctx, request_t *request, fr_retry_t const *retry)
Definition bio.c:3658
static void bio_request_reset(bio_request_t *u)
Clear out any connection specific resources from a udp request.
Definition bio.c:253
trunk_request_t * treq
Definition bio.c:151
static void status_check_enqueue(trunk_connection_t *tconn, bio_handle_t *h, bool init)
Queue a status check packet on an open connection, and wait for the reply.
Definition bio.c:2008
static xlat_action_t xlat_sendto_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
Definition bio.c:3630
static void status_check_next(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
Send the next status check, after the previous status check got a reply.
Definition bio.c:2622
rlm_radius_t const * inst
our instance
Definition bio.c:48
static connection_state_t conn_init(void **h_out, connection_t *conn, void *uctx)
Initialise a new outbound connection.
Definition bio.c:1146
connection_t ** connections
Definition bio.c:71
fr_rb_expire_node_t expire
Definition bio.c:178
static void revive_timeout(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
Revive a connection after "revive_interval".
Definition bio.c:1888
uint8_t * packet
Packet we write to the network.
Definition bio.c:166
static void conn_init_timeout(UNUSED fr_timer_list_t *tl, fr_time_t now, void *uctx)
Status check timer when opening the connection for the first time.
Definition bio.c:403
static connection_state_t conn_failed(void *handle, connection_state_t state, UNUSED void *uctx)
Connection failed.
Definition bio.c:1467
bio_limit_ports_t limit_source_ports
What type of port limit is in use.
Definition bio.c:54
fr_radius_ctx_t radius_ctx
for signing packets
Definition bio.c:53
radius_track_t * tt
RADIUS ID tracking structure.
Definition bio.c:108
static void mod_dup(request_t *request, bio_request_t *u)
Definition bio.c:2127
bio_handle_ctx_t ctx
common struct for home servers and BIO handles
Definition bio.c:80
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Free thread data for the submodule.
Definition bio.c:3488
uint8_t code
Packet code.
Definition bio.c:164
static void request_mux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Definition bio.c:2267
static fr_cmp_ret_t home_server_cmp(void const *one, void const *two)
Dynamic home server code.
Definition bio.c:3618
uint8_t * buffer
Receive buffer.
Definition bio.c:105
request_t * status_request
Definition bio.c:121
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:3104
bool status_check
is this packet a status check?
Definition bio.c:159
static xlat_arg_parser_t const xlat_radius_send_args[]
Definition bio.c:3501
static void xlat_sendto_signal(xlat_ctx_t const *xctx, request_t *request, fr_signal_t action)
Definition bio.c:3647
static int bio_write_resume(fr_bio_t *bio)
Resume the connection when a stream BIO can write again.
Definition bio.c:700
Track the handle, which is tightly correlated with the FD.
Definition bio.c:79
Connect request_t to local tracking structure.
Definition bio.c:150
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
static uint32_t fr_nbo_to_uint32(uint8_t const data[static sizeof(uint32_t)])
Read an unsigned 32bit integer from wire format (big endian)
Definition nbo.h:167
#define RADIUS_HEADER_LENGTH
Definition net.h:80
#define RADIUS_AUTH_VECTOR_LENGTH
Definition net.h:89
int fr_pair_delete_by_da_nested(fr_pair_list_t *list, fr_dict_attr_t const *da)
Delete matching pairs from the specified list, and prune any empty branches.
Definition pair.c:1665
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:2897
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
Definition pair.c:782
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
Definition pair.c:2598
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:707
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:1297
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:1641
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:284
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:47
static fr_internal_encode_ctx_t encode_ctx
static fr_dict_attr_t const * attr_state
static fr_dict_attr_t const * attr_error_cause
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:1183
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:361
ssize_t fr_radius_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_radius_encode_ctx_t *packet_ctx)
Definition base.c:1033
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition base.c:115
#define fr_assert(_expr)
Definition rad_assert.h:37
static char * secret
#define REDEBUG(fmt,...)
#define RDEBUG(fmt,...)
#define WARN(fmt,...)
static fr_dict_attr_t const * attr_proxy_state
Definition radclient.c:127
static fr_dict_attr_t const * attr_message_authenticator
Definition radclient.c:128
#define INFO(fmt,...)
Definition radict.c:67
#define RADIUS_AUTH_VECTOR_OFFSET
Definition radius.h:33
char const * secret
Definition radius.h:127
fr_radius_decode_fail_t
Failure reasons.
Definition radius.h:89
@ FR_RADIUS_FAIL_NONE
Definition radius.h:90
@ FR_RADIUS_FAIL_MA_MISSING
Definition radius.h:108
size_t secret_length
Definition radius.h:128
#define FR_RADIUS_PACKET_CODE_VALID(_x)
Definition radius.h:51
fr_radius_ctx_t const * common
Definition radius.h:159
@ FR_RADIUS_REQUIRE_MA_YES
Require Message-Authenticator.
Definition radius.h:63
@ FR_RADIUS_REQUIRE_MA_AUTO
Only require Message-Authenticator if we've previously received a packet from this client with Messag...
Definition radius.h:64
fr_radius_decode_fail_t reason
reason for decode failure
Definition radius.h:166
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
Definition radius.h:163
static fr_dict_t const * dict_radius
Definition radsniff.c:93
static rs_t * conf
Definition radsniff.c:52
static fr_dict_attr_t const * attr_extended_attribute_1
Definition radsnmp.c:110
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:128
Smaller fast random number generator.
Definition rand.h:54
int fr_rb_find(void **found, fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:586
int 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:767
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:57
#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
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:44
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:49
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:48
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:47
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:55
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition rcode.h:50
#define RETURN_UNLANG_RCODE(_rcode)
Definition rcode.h:67
#define request_local_alloc_internal(_ctx, _args)
Allocate a new internal request outside of the request pool.
Definition request.h:344
#define request_local_alloc_external(_ctx, _args)
Allocate a new external request outside of the request pool.
Definition request.h:336
Optional arguments for initialising requests.
Definition request.h:288
static int radius_fixups(rlm_radius_t const *inst, request_t *request)
Do any RADIUS-layer fixups for proxying.
Definition rlm_radius.c:593
static fr_dict_attr_t const * attr_nas_identifier
Definition rlm_radius.c:252
static fr_dict_attr_t const * attr_original_packet_code
Definition rlm_radius.c:253
static fr_dict_attr_t const * attr_event_timestamp
Definition rlm_radius.c:246
static fr_dict_attr_t const * attr_response_length
Definition rlm_radius.c:255
fr_radius_require_ma_t require_message_authenticator
Require Message-Authenticator in responses.
Definition rlm_radius.h:85
fr_time_delta_t revive_interval
Definition rlm_radius.h:66
bool track_load_balance
do we track load-balance state
Definition rlm_radius.h:87
fr_retry_config_t retry[FR_RADIUS_CODE_MAX]
Definition rlm_radius.h:98
char const * name
Definition rlm_radius.h:62
uint32_t status_check
code of status-check type
Definition rlm_radius.h:90
rlm_radius_mode_t mode
proxy, client, etc.
Definition rlm_radius.h:81
@ RLM_RADIUS_MODE_XLAT_PROXY
radius.sendto.ipaddr(), but we do look for a reply.
Definition rlm_radius.h:53
@ RLM_RADIUS_MODE_INVALID
Definition rlm_radius.h:48
@ RLM_RADIUS_MODE_PROXY
we proxy to one home server
Definition rlm_radius.h:49
@ RLM_RADIUS_MODE_REPLICATE
to a particular destination
Definition rlm_radius.h:51
@ RLM_RADIUS_MODE_UNCONNECTED_REPLICATE
radius.sendto.ipaddr(), but we don't look for a reply
Definition rlm_radius.h:52
@ RLM_RADIUS_MODE_CLIENT
we are a client to one home server
Definition rlm_radius.h:50
uint32_t max_packet_size
Maximum packet size.
Definition rlm_radius.h:76
fr_time_delta_t response_window
Definition rlm_radius.h:64
uint32_t max_attributes
Maximum number of attributes to decode in response.
Definition rlm_radius.h:83
fr_time_delta_t zombie_period
Definition rlm_radius.h:65
fr_bio_fd_config_t fd_config
for now MUST be at the start!
Definition rlm_radius.h:60
static char const * name
static conf_parser_t retry_config[]
Definition rlm_tacacs.c:38
int fr_schedule_worker_id(void)
Return the worker id for the current thread.
Definition schedule.c:111
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.
@ CONNECTION_FAILED
Connection is being reconnected because it failed.
Definition connection.h:89
connection_state_t
Definition connection.h:47
@ CONNECTION_STATE_FAILED
Connection has failed.
Definition connection.h:56
@ CONNECTION_STATE_CONNECTED
File descriptor is open (ready for writing).
Definition connection.h:54
@ CONNECTION_STATE_INIT
Init state, sets up connection.
Definition connection.h:51
@ CONNECTION_STATE_CONNECTING
Waiting for connection to establish.
Definition connection.h:52
Holds a complete set of functions for a connection.
Definition connection.h:199
void * data
Module's instance data.
Definition module.h:297
#define pair_append_request(_attr, _da)
Allocate and append a fr_pair_t to the request list.
Definition pair.h:37
#define FR_SIGNAL_ALLOW(_signals)
Signal mask which blocks every signal except the ones in _signals.
Definition signal.h:58
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_NONE
No signals.
Definition signal.h:39
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
init
Enter the EAP-IDENTITY state.
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
Definition log.h:93
Value pair map.
Definition map.h:77
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
int unlang_subrequest_child_push_and_detach(request_t *request)
Add a child request to the runnable queue.
Definition subrequest.c:503
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:621
#define talloc_get_type_abort_const
Definition talloc.h:117
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:289
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
#define fr_time_gteq(_a, _b)
Definition time.h:238
#define fr_time_delta_wrap(_time)
Definition time.h:152
#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
static fr_cmp_ret_t fr_time_cmp(fr_time_t a, fr_time_t b)
Compare two fr_time_t values.
Definition time.h:934
#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:706
"server local" time.
Definition time.h:69
An event timer list.
Definition timer.c:49
A timer event.
Definition timer.c:83
#define FR_TIMER_DELETE(_ev_p)
Definition timer.h:105
#define FR_TIMER_DELETE_RETURN(_ev_p)
Definition timer.h:112
#define fr_timer_in(...)
Definition timer.h:87
#define FR_TIMER_DISARM(_ev)
Definition timer.h:91
static bool fr_timer_armed(fr_timer_t *ev)
Definition timer.h:124
#define fr_timer_at(...)
Definition timer.h:81
void radius_track_state_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line, radius_track_t *tt, radius_track_log_extra_t extra)
Print out the state of every tracking entry.
Definition track.c:298
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:223
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:252
radius_track_t * radius_track_alloc(TALLOC_CTX *ctx)
Create an radius_track_t.
Definition track.c:38
#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:4110
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:4127
void trunk_request_signal_partial(trunk_request_t *treq)
Signal a partial write.
Definition trunk.c:2093
void trunk_request_signal_fail(trunk_request_t *treq)
Signal that a trunk request failed.
Definition trunk.c:2196
trunk_request_t * trunk_request_alloc(trunk_t *trunk, request_t *request)
(Pre-)Allocate a new trunk request
Definition trunk.c:2542
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:2074
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:2811
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:2657
trunk_enqueue_t trunk_request_requeue(trunk_request_t *treq)
Re-enqueue a request on the same connection.
Definition trunk.c:2746
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:3979
void trunk_request_signal_cancel(trunk_request_t *treq)
Cancel a trunk request.
Definition trunk.c:2216
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, fr_pair_list_t *trigger_args)
Allocate a new collection of connections.
Definition trunk.c:5124
void trunk_request_free(trunk_request_t **treq_to_free)
If the trunk request is freed then update the target requests.
Definition trunk.c:2386
void trunk_connection_signal_active(trunk_connection_t *tconn)
Signal a trunk connection is no longer full.
Definition trunk.c:4056
void trunk_connection_signal_inactive(trunk_connection_t *tconn)
Signal a trunk connection cannot accept more requests.
Definition trunk.c:4033
void trunk_request_signal_sent(trunk_request_t *treq)
Signal that the request was written to a connection successfully.
Definition trunk.c:2114
void trunk_request_signal_complete(trunk_request_t *treq)
Signal that a trunk request is complete.
Definition trunk.c:2158
void trunk_connection_signal_reconnect(trunk_connection_t *tconn, connection_reason_t reason)
Signal a trunk connection is no longer viable.
Definition trunk.c:4095
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:2912
Associates request queues with a connection.
Definition trunk.c:137
Wraps a normal request.
Definition trunk.c:99
Main trunk management handle.
Definition trunk.c:219
trunk_connection_event_t
What type of I/O events the trunk connection is currently interested in receiving.
Definition trunk.h:81
@ TRUNK_CONN_EVENT_BOTH
Trunk should be notified if a connection is readable or writable.
Definition trunk.h:88
@ TRUNK_CONN_EVENT_WRITE
Trunk should be notified if a connection is writable.
Definition trunk.h:86
@ TRUNK_CONN_EVENT_NONE
Don't notify the trunk on connection state changes.
Definition trunk.h:82
@ TRUNK_CONN_EVENT_READ
Trunk should be notified if a connection is readable.
Definition trunk.h:84
#define TRUNK_REQUEST_STATE_ALL
All request states.
Definition trunk.h:205
trunk_connection_alloc_t connection_alloc
Allocate a new connection_t.
Definition trunk.h:747
@ TRUNK_ENQUEUE_DST_UNAVAILABLE
Destination is down.
Definition trunk.h:163
@ TRUNK_ENQUEUE_FAIL
General internal sanity check failure.
Definition trunk.h:164
@ TRUNK_ENQUEUE_OK
Operation was successful.
Definition trunk.h:160
@ TRUNK_ENQUEUE_NO_CAPACITY
At maximum number of connections, and no connection has capacity.
Definition trunk.h:161
@ TRUNK_ENQUEUE_IN_BACKLOG
Request should be enqueued in backlog.
Definition trunk.h:159
trunk_request_state_t
Used for sanity checks and to simplify freeing.
Definition trunk.h:171
@ TRUNK_REQUEST_STATE_PARTIAL
Some of the request was written to the socket, more of it should be written later.
Definition trunk.h:180
@ TRUNK_REQUEST_STATE_REAPABLE
Request has been written, needs to persist, but we are not currently waiting for any response.
Definition trunk.h:183
@ TRUNK_REQUEST_STATE_UNASSIGNED
Transition state - Request currently not assigned to any connection.
Definition trunk.h:175
@ TRUNK_REQUEST_STATE_INIT
Initial state.
Definition trunk.h:172
@ TRUNK_REQUEST_STATE_CANCEL_SENT
We've informed the remote server that the request has been cancelled.
Definition trunk.h:195
@ TRUNK_REQUEST_STATE_COMPLETE
The request is complete.
Definition trunk.h:192
@ TRUNK_REQUEST_STATE_FAILED
The request failed.
Definition trunk.h:193
@ TRUNK_REQUEST_STATE_CANCEL
A request on a particular socket was cancel.
Definition trunk.h:194
@ TRUNK_REQUEST_STATE_CANCEL_PARTIAL
We partially wrote a cancellation request.
Definition trunk.h:197
@ TRUNK_REQUEST_STATE_BACKLOG
In the backlog.
Definition trunk.h:177
@ TRUNK_REQUEST_STATE_CANCEL_COMPLETE
Remote server has acknowledged our cancellation.
Definition trunk.h:198
@ TRUNK_REQUEST_STATE_PENDING
In the queue of a connection and is pending writing.
Definition trunk.h:178
@ TRUNK_REQUEST_STATE_SENT
Was written to a socket. Waiting for a response.
Definition trunk.h:182
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
I/O functions to pass to trunk_alloc.
Definition trunk.h:746
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:663
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
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition xlat.h:373
unsigned int required
Argument must be present, and non-empty.
Definition xlat.h:136
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:160
Definition for a single argument consumed by an xlat function.
Definition xlat.h:135
A node in a graph of unlang_op_t (s) that we execute.
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:110
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
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_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
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:83
int fd
File descriptor if this is a live socket.
Definition socket.h:86
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:558
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:668
static fr_sbuff_err_t char size_t fr_sbuff_t * in
Definition value.h:1061
#define fr_box_ipaddr(_val)
Definition value.h:348
static fr_slen_t data
Definition value.h:1366
static fr_sbuff_err_t char ** out
Definition value.h:1061
#define fr_box_time_delta(_val)
Definition value.h:397
int nonnull(2, 5))
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