The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
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: 48ce76193ff6bf297ee4829abe6375ac31e1eded $
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/load_balance_priv.h>
31#include <freeradius-devel/util/heap.h>
32#include <freeradius-devel/util/rb_expire.h>
33
34
35//#include "rlm_radius.h"
36#include "track.h"
37
38typedef enum {
39 LIMIT_PORTS_NONE = 0, //!< Source port not restricted
40 LIMIT_PORTS_STATIC, //!< Limited source ports for static home servers
41 LIMIT_PORTS_DYNAMIC //!< Limited source ports for dynamic home servers
43
44typedef struct {
45 char const *module_name; //!< the module that opened the connection
46 rlm_radius_t const *inst; //!< our instance
47 fr_event_list_t *el; //!< Event list.
48 trunk_t *trunk; //!< trunk handler
49 fr_bio_fd_config_t fd_config; //!< for threads or sockets
50 fr_bio_fd_info_t const *fd_info; //!< status of the FD.
51 fr_radius_ctx_t radius_ctx; //!< for signing packets
52 bio_limit_ports_t limit_source_ports; //!< What type of port limit is in use.
53 bool dynamic; //!< is this a dynamic home server.
55
56typedef struct {
57 bio_handle_ctx_t ctx; //!< common struct for home servers and BIO handles
58
59 struct {
60 fr_bio_t *fd; //!< writing
61 uint32_t id; //!< for replication
62 fr_rb_expire_t expires; //!< for proxying / client sending
63 } bio;
64
68
70
71/** Track the handle, which is tightly correlated with the FD
72 *
73 */
74typedef struct {
75 bio_handle_ctx_t ctx; //!< common struct for home servers and BIO handles
76
77 int fd; //!< File descriptor.
78
79 struct {
80 fr_bio_t *main; //!< what we use for IO
81 fr_bio_t *fd; //!< raw FD
82 fr_bio_t *mem; //!< memory wrappers for stream sockets
83 } bio;
84
86
87 uint8_t last_id; //!< Used when replicating to ensure IDs are distributed
88 ///< evenly.
89
90 uint32_t max_packet_size; //!< Our max packet size. may be different from the parent.
91
92 uint8_t *buffer; //!< Receive buffer.
93 size_t buflen; //!< Receive buffer length.
94
95 radius_track_t *tt; //!< RADIUS ID tracking structure.
96
97 fr_time_t mrs_time; //!< Most recent sent time which had a reply.
98 fr_time_t last_reply; //!< When we last received a reply.
99 fr_time_t first_sent; //!< first time we sent a packet since going idle
100 fr_time_t last_sent; //!< last time we sent a packet.
101 fr_time_t last_idle; //!< last time we had nothing to do
102
103 fr_timer_t *zombie_ev; //!< Zombie timeout.
104 unlang_t const *instruction; //!< Instruction which triggered the start of the zombie period.
105
106 bool status_checking; //!< whether we're doing status checks
107 bio_request_t *status_u; //!< for sending status check packets
110
111
112/** Connect request_t to local tracking structure
113 *
114 */
117 rlm_rcode_t rcode; //!< from the transport
119
120 uint32_t priority; //!< copied from request->async->priority
121 fr_time_t recv_time; //!< copied from request->async->recv_time
122
123 uint32_t num_replies; //!< number of reply packets, sent is in retry.count
124
125 bool status_check; //!< is this packet a status check?
126 bool proxied; //!< is this request being proxied
127
128 fr_pair_list_t extra; //!< VPs for debugging, like Proxy-State.
129
130 uint8_t code; //!< Packet code.
131 uint8_t id; //!< Last ID assigned to this packet.
132 uint8_t *packet; //!< Packet we write to the network.
133 size_t packet_len; //!< Length of the packet.
134 size_t partial; //!< partially sent data
135
136 radius_track_entry_t *rr; //!< ID tracking, resend count, etc.
137 fr_timer_t *ev; //!< timer for retransmissions
138 fr_retry_t retry; //!< retransmission timers
139};
140
141typedef struct {
142 bio_handle_ctx_t ctx; //!< for copying to bio_handle_t
143
145
147 connection_t *connections[]; //!< for tracking outbound connections
149
150
151/** Turn a reply code into a module rcode;
152 *
153 */
169
171 UNUSED int flags, void *uctx);
172
173static int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id);
174
175static fr_radius_decode_fail_t decode(TALLOC_CTX *ctx, fr_pair_list_t *reply, uint8_t *response_code,
176 bio_handle_t *h, request_t *request, bio_request_t *u,
177 uint8_t const request_authenticator[static RADIUS_AUTH_VECTOR_LENGTH],
178 uint8_t *data, size_t data_len);
179
181
182static void mod_write(request_t *request, trunk_request_t *treq, bio_handle_t *h);
183
184static int _bio_request_free(bio_request_t *u);
185
186static fr_cmp_ret_t home_server_cmp(void const *one, void const *two);
187
188#ifndef NDEBUG
189/** Log additional information about a tracking entry
190 *
191 * @param[in] te Tracking entry we're logging information for.
192 * @param[in] log destination.
193 * @param[in] log_type Type of log message.
194 * @param[in] file the logging request was made in.
195 * @param[in] line logging request was made on.
196 */
197static void bio_tracking_entry_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line,
199{
200 request_t *request;
201
202 if (!te->request) return; /* Free entry */
203
204 request = talloc_get_type_abort(te->request, request_t);
205
206 fr_log(log, log_type, file, line, "request %s, allocated %s:%d", request->name,
207 request->alloc_file, request->alloc_line);
208
209 trunk_request_state_log(log, log_type, file, line, talloc_get_type_abort(te->uctx, trunk_request_t));
210}
211#endif
212
213/** Clear out any connection specific resources from a udp request
214 *
215 */
217{
218 TALLOC_FREE(u->packet);
220
221 /*
222 * Can have packet put no u->rr
223 * if this is part of a pre-trunk status check.
224 */
225 if (u->rr) radius_track_entry_release(&u->rr);
226
228}
229
230/** Reset a status_check packet, ready to reuse
231 *
232 */
234{
235 fr_assert(u->status_check == true);
236
237 h->status_checking = false;
238 u->num_replies = 0; /* Reset */
239 u->retry.start = fr_time_wrap(0);
240
242
244}
245
246/*
247 * Status-Server checks. Manually build the packet, and
248 * all of its associated glue.
249 */
251{
252 bio_request_t *u;
253 request_t *request;
254 fr_pair_t *vp;
255 rlm_radius_t const *inst = h->ctx.inst;
256
258
259 MEM(request = request_local_alloc_external(h, (&(request_init_args_t){ .namespace = dict_radius })));
260 MEM(u = talloc_zero(request, bio_request_t));
261 talloc_set_destructor(u, _bio_request_free);
262
263 h->status_u = u;
264
265 h->status_request = request;
267
268 /*
269 * Status checks are prioritized over any other packet
270 */
271 u->priority = ~(uint32_t) 0;
272 u->status_check = true;
273
274 /*
275 * Allocate outside of the free list.
276 * There appears to be an issue where
277 * the thread destructor runs too
278 * early, and frees the freelist's
279 * head before the module destructor
280 * runs.
281 */
282 request->async = talloc_zero(request, fr_async_t);
283 request->async->request = request;
284 talloc_const_free(request->name);
285 request->name = talloc_strdup(request, h->ctx.module_name);
286
287 request->packet = fr_packet_alloc(request, false);
288 request->reply = fr_packet_alloc(request, false);
289
290 /*
291 * Create the VPs, and ignore any errors creating them.
292 */
293 if (map_list_num_elements(&inst->status_check_map) > 0) {
294 map_t *map = NULL;
295
296 while ((map = map_list_next(&inst->status_check_map, map))) {
297 (void) map_to_request(request, map, map_to_vp, NULL);
298 }
299 } else {
300 /*
301 * Ensure that there's a NAS-Identifier with a value.
302 *
303 * Arguably if there's no status-check map, then the request_pairs are empty. But
304 * whatever...
305 */
306 if (!fr_pair_find_by_da(&request->request_pairs, NULL, attr_nas_identifier)) {
308 fr_pair_value_strdup(vp, "status check - are you alive?", false);
309 }
310 }
311
312 /*
313 * Always add an Event-Timestamp, and update its value every time we send a packet.
314 *
315 * The retry code will later update the timestamp, too, but updating it here means that the debug
316 * output doesn't show a zero-value Event-Timstamp.
317 */
318 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_event_timestamp);
319 if (!vp) {
321 }
322 vp->vp_date = fr_time_to_unix_time(fr_time());
323
324 /*
325 * Initialize the request IO ctx. Note that we don't set
326 * destructors.
327 */
328 u->code = inst->status_check;
329 request->packet->code = u->code;
330
331 DEBUG3("%s - Status check packet type will be %s", h->ctx.module_name, fr_radius_packet_name[u->code]);
332 log_request_proto_pair_list(L_DBG_LVL_3, request, NULL, &request->request_pairs, NULL);
333}
334
335/** Connection errored
336 *
337 * We were signalled by the event loop that a fatal error occurred on this connection.
338 *
339 * @param[in] el The event list signalling.
340 * @param[in] fd that errored.
341 * @param[in] flags El flags.
342 * @param[in] fd_errno The nature of the error.
343 * @param[in] uctx The trunk connection handle (tconn).
344 */
345static void conn_init_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
346{
347 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
348 bio_handle_t *h;
349
350 /*
351 * Connection must be in the connecting state when this fires
352 */
354
355 h = talloc_get_type_abort(conn->h, bio_handle_t);
356
357 ERROR("%s - Connection %s failed: %s", h->ctx.module_name, h->ctx.fd_info->name, fr_syserror(fd_errno));
358
360}
361
362/** Status check timer when opening the connection for the first time.
363 *
364 * Setup retries, or fail the connection.
365 */
366static void conn_init_timeout(UNUSED fr_timer_list_t *tl, fr_time_t now, void *uctx)
367{
368 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
369 bio_handle_t *h;
370 bio_request_t *u;
371
372 /*
373 * Connection must be in the connecting state when this fires
374 */
376
377 h = talloc_get_type_abort(conn->h, bio_handle_t);
378 u = h->status_u;
379
380 /*
381 * We're only interested in contiguous, good, replies.
382 */
383 u->num_replies = 0;
384
385 switch (fr_retry_next(&u->retry, now)) {
386 case FR_RETRY_MRD:
387 DEBUG("%s - Reached maximum_retransmit_duration (%pVs > %pVs), failing status checks",
390 goto fail;
391
392 case FR_RETRY_MRC:
393 DEBUG("%s - Reached maximum_retransmit_count (%u > %u), failing status checks",
395 fail:
397 return;
398
400 if (fr_event_fd_insert(h, NULL, conn->el, h->fd, conn_init_writable, NULL,
401 conn_init_error, conn) < 0) {
402 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
404 }
405 return;
406 }
407
408 fr_assert(0);
409}
410
411/** Perform the next step of init and negotiation.
412 *
413 */
414static void conn_init_next(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
415{
416 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
417 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
418
419 if (fr_event_fd_insert(h, NULL, conn->el, h->fd, conn_init_writable, NULL, conn_init_error, conn) < 0) {
420 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
422 }
423}
424
425/** Read the connection during the init and negotiation stage.
426 *
427 */
428static void conn_init_readable(fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
429{
430 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
431 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
432 trunk_t *trunk = h->ctx.trunk;
433 rlm_radius_t const *inst = h->ctx.inst;
434 bio_request_t *u = h->status_u;
435 ssize_t slen;
436 fr_pair_list_t reply;
437 uint8_t code = 0;
438
439 fr_pair_list_init(&reply);
440 slen = fr_bio_read(h->bio.main, NULL, h->buffer, h->buflen);
441 if (slen == 0) {
442 /*
443 * @todo - set BIO FD EOF callback, so that we don't have to check it here.
444 */
445 if (h->ctx.fd_info->eof) goto failed;
446 return;
447 }
448
449 /*
450 * We're done reading, return.
451 */
452 if (slen == fr_bio_error(IO_WOULD_BLOCK)) return;
453
454 if (slen < 0) {
455 switch (errno) {
456 case ECONNREFUSED:
457 ERROR("%s - Failed reading response from socket: there is no server listening on outgoing connection %s",
458 h->ctx.module_name, h->ctx.fd_info->name);
459 break;
460
461 default:
462 ERROR("%s - Failed reading response from socket: %s",
463 h->ctx.module_name, fr_syserror(errno));
464 break;
465 }
466
467 failed:
469 return;
470 }
471
472 /*
473 * Where we just return in this function, we're letting
474 * the response timer take care of progressing the
475 * connection attempt.
476 */
477 fr_assert(slen >= RADIUS_HEADER_LENGTH); /* checked in verify */
478
479 if (!u->packet) {
480 ERROR("%s - Received response to expired status check packet",
481 h->ctx.module_name);
482 return;
483 }
484
485 if (u->id != h->buffer[1]) {
486 ERROR("%s - Received response with incorrect or expired ID. Expected %u, got %u",
487 h->ctx.module_name, u->id, h->buffer[1]);
488 return;
489 }
490
491 if (decode(h, &reply, &code,
493 h->buffer, slen) != FR_RADIUS_FAIL_NONE) return;
494
495 fr_pair_list_free(&reply); /* FIXME - Do something with these... */
496
497 /*
498 * Process the error, and count this as a success.
499 * This is usually used for dynamic configuration
500 * on startup.
501 */
503
504 /*
505 * Last trunk event was a failure, be more careful about
506 * bringing up the connection (require multiple responses).
507 */
508 if ((fr_time_gt(trunk->last_failed, fr_time_wrap(0)) && (fr_time_gt(trunk->last_failed, trunk->last_connected))) &&
509 (u->num_replies < inst->num_answers_to_alive)) {
510 /*
511 * Leave the timer in place. This timer is BOTH when we
512 * give up on the current status check, AND when we send
513 * the next status check.
514 */
515 DEBUG("%s - Received %u / %u replies for status check, on connection - %s",
516 h->ctx.module_name, u->num_replies, inst->num_answers_to_alive, h->ctx.fd_info->name);
517 DEBUG("%s - Next status check packet will be in %pVs",
519
520 /*
521 * Set the timer for the next retransmit.
522 */
523 if (fr_timer_at(h, el->tl, &u->ev, u->retry.next, false, conn_init_next, conn) < 0) {
525 }
526 return;
527 }
528
529 /*
530 * It's alive!
531 */
532 status_check_reset(h, u);
533
534 DEBUG("%s - Connection open - %s", h->ctx.module_name, h->ctx.fd_info->name);
535
537}
538
539/** Send initial negotiation.
540 *
541 */
542static void conn_init_writable(fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
543{
544 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
545 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
546 bio_request_t *u = h->status_u;
547 ssize_t slen;
548
549 if (fr_time_eq(u->retry.start, fr_time_wrap(0))) {
550 u->id = fr_rand() & 0xff; /* We don't care what the value is here */
551 h->status_checking = true; /* Ensure this is valid */
552 fr_retry_init(&u->retry, fr_time(), &h->ctx.inst->retry[u->code]);
553
554 /*
555 * Status checks can never be retransmitted
556 * So increment the ID here.
557 */
558 } else {
560 u->id++;
561 }
562
563 DEBUG("%s - Sending %s ID %d over connection %s",
565
566 if (encode(h, h->status_request, u, u->id) < 0) {
567 fail:
569 return;
570 }
571 DEBUG3("Encoded packet");
572 HEXDUMP3(u->packet, u->packet_len, NULL);
573
574 fr_assert(u->packet != NULL);
576
577 slen = fr_bio_write(h->bio.main, NULL, u->packet, u->packet_len);
578
579 if (slen == fr_bio_error(IO_WOULD_BLOCK)) goto blocked;
580
581 if (slen < 0) {
582 ERROR("%s - Failed sending %s ID %d length %zu over connection %s: %s",
584 goto fail;
585 }
586
587 /*
588 * @todo - handle partial packets and blocked writes.
589 */
590 if ((size_t)slen < u->packet_len) {
591 blocked:
592 ERROR("%s - Failed sending %s ID %d length %zu over connection %s: writing is blocked",
594 goto fail;
595 }
596
597 /*
598 * Switch to waiting on read and insert the event
599 * for the response timeout.
600 */
601 if (fr_event_fd_insert(h, NULL, conn->el, h->fd, conn_init_readable, NULL, conn_init_error, conn) < 0) {
602 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
603 goto fail;
604 }
605
606 DEBUG("%s - %s request. Expecting response within %pVs",
607 h->ctx.module_name, (u->retry.count == 1) ? "Originated" : "Retransmitted",
609
610 if (fr_timer_at(h, el->tl, &u->ev, u->retry.next, false, conn_init_timeout, conn) < 0) {
611 PERROR("%s - Failed inserting timer event", h->ctx.module_name);
612 goto fail;
613 }
614}
615
616/** Free a connection handle, closing associated resources
617 *
618 */
620{
621 fr_assert(h != NULL);
622
623 fr_assert(h->fd >= 0);
624
626
627 /*
628 * The connection code will take care of deleting the FD from the event loop.
629 */
630
631 DEBUG("%s - Connection closed - %s", h->ctx.module_name, h->ctx.fd_info->name);
632
633 return 0;
634}
635
636static void bio_connected(fr_bio_t *bio)
637{
638 bio_handle_t *h = bio->uctx;
639
640 DEBUG("%s - Connection open - %s", h->ctx.module_name, h->ctx.fd_info->name);
641
643}
644
645static void bio_error(fr_bio_t *bio)
646{
647 bio_handle_t *h = bio->uctx;
648
649 DEBUG("%s - Connection failed - %s - %s", h->ctx.module_name, h->ctx.fd_info->name,
651
653}
654
655static 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)
656{
658 size_t in_buffer = *size;
659 bio_handle_t *h = verify_ctx;
660 uint8_t const *hdr = data;
661 size_t want;
662
663 if (in_buffer < 20) {
664 *size = RADIUS_HEADER_LENGTH;
666 }
667
668 /*
669 * Packet is too large, discard it.
670 */
671 want = fr_nbo_to_uint16(hdr + 2);
672 if (want > h->ctx.inst->max_packet_size) {
673 ERROR("%s - Connection %s received too long packet", h->ctx.module_name, h->ctx.fd_info->name);
675 }
676
677 /*
678 * Not a full packet, we want more data.
679 */
680 if (want > *size) {
681 *size = want;
683 }
684
685#define REQUIRE_MA(_h) (((_h)->ctx.inst->require_message_authenticator == FR_RADIUS_REQUIRE_MA_YES) || *(_h)->ctx.inst->received_message_authenticator)
686
687 /*
688 * See if we need to discard the packet.
689 *
690 * @todo - rate limit these messages, and find a way to associate them with a request, or even
691 * the logging destination of the module.
692 */
693 if (!fr_radius_ok(data, size, h->ctx.inst->max_attributes, REQUIRE_MA(h), &failure)) {
695
696 PERROR("%s - Connection %s received bad packet", h->ctx.module_name, h->ctx.fd_info->name);
697
698 if (failure == FR_RADIUS_FAIL_MA_MISSING) {
700 ERROR("We are configured with 'require_message_authenticator = true'");
701 } else {
702 ERROR("We previously received a packet from this client which included a Message-Authenticator attribute");
703 }
704 }
705
706 if (h->ctx.fd_config.socket_type == SOCK_DGRAM) return FR_BIO_VERIFY_DISCARD;
707
709 }
710
711 /*
712 * @todo - check if the reply is allowed. Bad replies are discarded later, but it might be worth
713 * checking them here.
714 */
715
716 /*
717 * On input, *size is how much data we have. On output, *size is how much data we want.
718 */
719 return (in_buffer >= *size) ? FR_BIO_VERIFY_OK : FR_BIO_VERIFY_WANT_MORE;
720}
721
722
723/** Initialise a new outbound connection
724 *
725 * @param[out] h_out Where to write the new file descriptor.
726 * @param[in] conn to initialise.
727 * @param[in] uctx A #bio_handle_ctx_t
728 */
729CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
730static connection_state_t conn_init(void **h_out, connection_t *conn, void *uctx)
731{
732 int fd;
733 bio_handle_t *h;
734 bio_handle_ctx_t *ctx = uctx; /* thread or home server */
735 connection_t **to_save = NULL;
736
737 MEM(h = talloc_zero(conn, bio_handle_t));
738 h->ctx = *ctx;
739 h->conn = conn;
741 h->last_idle = fr_time();
742
743 MEM(h->buffer = talloc_array(h, uint8_t, h->max_packet_size));
744 h->buflen = h->max_packet_size;
745
746 MEM(h->tt = radius_track_alloc(h));
747
748 /*
749 * We are proxying to multiple home servers, but using a limited port range. We must track the
750 * source port for each home server, so that we only can select the right unused source port for
751 * this home server.
752 */
753 switch (ctx->limit_source_ports) {
754 case LIMIT_PORTS_NONE:
755 break;
756
757 /*
758 * Dynamic home servers store source port usage in the home_server_t
759 */
761 {
762 int i;
763 home_server_t *home = talloc_get_type_abort(ctx, home_server_t);
764
765 for (i = 0; i < home->num_ports; i++) {
766 if (!home->connections[i]) {
767 to_save = &home->connections[i];
768
769 /*
770 * Set the source port, but also leave the src_port_start and
771 * src_port_end alone.
772 */
774 break;
775 }
776 }
777
778 if (!to_save) {
779 ERROR("%s - Failed opening socket to home server %pV:%u - source port range is full",
781 goto fail;
782 }
783 }
784 break;
785
786 /*
787 * Static home servers store source port usage in bio_thread_t
788 */
790 {
791 int i;
792 bio_thread_t *thread = talloc_get_type_abort(ctx, bio_thread_t);
793
794 for (i = 0; i < thread->num_ports; i++) {
795 if (!thread->connections[i]) {
796 to_save = &thread->connections[i];
798 break;
799 }
800 }
801
802 if (!to_save) {
803 ERROR("%s - Failed opening socket to home server %pV:%u - source port range is full",
805 goto fail;
806 }
807 }
808 break;
809 }
810
811 h->bio.fd = fr_bio_fd_alloc(h, &h->ctx.fd_config, 0);
812 if (!h->bio.fd) {
813 PERROR("%s - failed opening socket", h->ctx.module_name);
814 fail:
815 talloc_free(h);
817 }
818
819 h->bio.fd->uctx = h;
821
822 fd = h->ctx.fd_info->socket.fd;
823 fr_assert(fd >= 0);
824
825 /*
826 * Create a memory BIO for stream sockets. We want to return only complete packets, and not
827 * partial packets.
828 *
829 * @todo - maybe we want to have a fr_bio_verify_t which is independent of fr_bio_mem_t. That
830 * way we don't need a memory BIO for UDP sockets, but we can still add a verification layer for
831 * UDP sockets?
832 */
833 h->bio.mem = fr_bio_mem_alloc(h, (h->ctx.fd_config.socket_type == SOCK_DGRAM) ? 0 : h->ctx.inst->max_packet_size * 4,
834 0, h->bio.fd);
835 if (!h->bio.mem) {
836 PERROR("%s - Failed allocating memory buffer - ", h->ctx.module_name);
837 goto fail;
838 }
839
840 if (fr_bio_mem_set_verify(h->bio.mem, rlm_radius_verify, h, (h->ctx.fd_config.socket_type == SOCK_DGRAM)) < 0) {
841 PERROR("%s - Failed setting validation callback - ", h->ctx.module_name);
842 goto fail;
843 }
844
845 /*
846 * Set the BIO read function to be the memory BIO, which will then call the packet verification
847 * routine.
848 */
849 h->bio.main = h->bio.mem;
850 h->bio.mem->uctx = h;
851
852 h->fd = fd;
853
854 talloc_set_destructor(h, _bio_handle_free);
855
856 /*
857 * If the socket isn't connected, then do that first.
858 */
860 int rcode;
861
863
864 /*
865 * We don't pass timeouts here because the trunk has it's own connection timeouts.
866 */
867 rcode = fr_bio_fd_connect_full(h->bio.fd, conn->el, bio_connected, bio_error, NULL, NULL);
868 if (rcode < 0) goto fail;
869
870 *h_out = h;
871
872 if (rcode == 0) return CONNECTION_STATE_CONNECTING;
873
874 fr_assert(rcode == 1);
876
877 /*
878 * If we're doing status checks, then we want at least
879 * one positive response before signalling that the
880 * connection is open.
881 *
882 * To do this we install special I/O handlers that
883 * only signal the connection as open once we get a
884 * status-check response.
885 */
886 } if (h->ctx.inst->status_check) {
888
889 /*
890 * Start status checking.
891 *
892 * If we've had no recent failures we need exactly
893 * one response to bring the connection online,
894 * otherwise we need inst->num_answers_to_alive
895 */
896 if (fr_event_fd_insert(h, NULL, conn->el, h->fd, NULL,
897 conn_init_writable, conn_init_error, conn) < 0) goto fail;
898
899 /*
900 * If we're not doing status-checks, signal the connection
901 * as open as soon as it becomes writable.
902 */
903 } else {
904 connection_signal_on_fd(conn, fd);
905 }
906
907 *h_out = h;
908
909 if (to_save) *to_save = conn;
910
912}
913
914/** Shutdown/close a file descriptor
915 *
916 */
917static void conn_close(UNUSED fr_event_list_t *el, void *handle, void *uctx)
918{
919 bio_handle_t *h = talloc_get_type_abort(handle, bio_handle_t);
920
921 /*
922 * There's tracking entries still allocated
923 * this is bad, they should have all been
924 * released.
925 */
926 if (h->tt && (h->tt->num_requests != 0)) {
927#ifndef NDEBUG
929#endif
930 fr_assert_fail("%u tracking entries still allocated at conn close", h->tt->num_requests);
931 }
932
933 /*
934 * We have opened a limited number of outbound source ports. This means that when we close a
935 * port, we have to mark it unused.
936 */
937 switch (h->ctx.limit_source_ports) {
938 case LIMIT_PORTS_NONE:
939 break;
940
942 {
943 int offset;
944 home_server_t *home = talloc_get_type_abort(uctx, home_server_t);
945
948
950 fr_assert(offset < home->num_ports);
951
952 fr_assert(home->connections[offset] == h->conn);
953
954 home->connections[offset] = NULL;
955 }
956 break;
957
959 {
960 int offset;
961 bio_thread_t *thread = talloc_get_type_abort(uctx, bio_thread_t);
962
965
967 fr_assert(offset < thread->num_ports);
968
969 fr_assert(thread->connections[offset] == h->conn);
970
971 thread->connections[offset] = NULL;
972 }
973 break;
974 }
975
976 DEBUG4("Freeing handle %p", handle);
977
978 talloc_free(h);
979}
980
981/** Connection failed
982 *
983 * @param[in] handle of connection that failed.
984 * @param[in] state the connection was in when it failed.
985 * @param[in] uctx UNUSED.
986 */
988{
989 switch (state) {
990 /*
991 * If the connection was connected when it failed,
992 * we need to handle any outstanding packets and
993 * timer events before reconnecting.
994 */
996 {
997 bio_handle_t *h = talloc_get_type_abort(handle, bio_handle_t); /* h only available if connected */
998
999 /*
1000 * Reset the Status-Server checks.
1001 */
1002 if (h->status_u) FR_TIMER_DISARM(h->status_u->ev);
1003 break;
1004
1005 default:
1006 break;
1007 }
1008 }
1009
1010 return CONNECTION_STATE_INIT;
1011}
1012
1013CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
1015 connection_conf_t const *conf,
1016 char const *log_prefix, void *uctx)
1017{
1018 connection_t *conn;
1019 bio_handle_ctx_t *ctx = uctx; /* thread or home server */
1020
1021 conn = connection_alloc(tconn, el,
1023 .init = conn_init,
1024 .close = conn_close,
1025 .failed = conn_failed
1026 },
1027 conf,
1028 log_prefix,
1029 uctx);
1030 if (!conn) {
1031 PERROR("%s - Failed allocating state handler for new connection", ctx->inst->name);
1032 return NULL;
1033 }
1034 ctx->trunk = tconn->trunk;
1035 ctx->module_name = log_prefix;
1036
1037 return conn;
1038}
1039
1040/** Read and discard data
1041 *
1042 */
1043static void conn_discard(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
1044{
1045 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1046 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1047 uint8_t buffer[4096];
1048 ssize_t slen;
1049
1050 while ((slen = fr_bio_read(h->bio.main, NULL, buffer, sizeof(buffer))) > 0);
1051
1052 if (slen < 0) {
1053 switch (errno) {
1054 case EBADF:
1055 case ECONNRESET:
1056 case ENOTCONN:
1057 case ETIMEDOUT:
1058 ERROR("%s - Failed draining socket: %s", h->ctx.module_name, fr_syserror(errno));
1060 break;
1061
1062 default:
1063 break;
1064 }
1065 }
1066}
1067
1068/** Connection errored
1069 *
1070 * We were signalled by the event loop that a fatal error occurred on this connection.
1071 *
1072 * @param[in] el The event list signalling.
1073 * @param[in] fd that errored.
1074 * @param[in] flags El flags.
1075 * @param[in] fd_errno The nature of the error.
1076 * @param[in] uctx The trunk connection handle (tconn).
1077 */
1078static void conn_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
1079{
1080 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1081 connection_t *conn = tconn->conn;
1082 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
1083
1084 if (fd_errno) ERROR("%s - Connection %s failed: %s", h->ctx.module_name, h->ctx.fd_info->name, fr_syserror(fd_errno));
1085
1087}
1088
1089CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
1092 trunk_connection_event_t notify_on, UNUSED void *uctx)
1093{
1094 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
1095 fr_event_fd_cb_t read_fn = NULL;
1096 fr_event_fd_cb_t write_fn = NULL;
1097
1098 switch (notify_on) {
1099 /*
1100 * We may have sent multiple requests to the
1101 * other end, so it might be sending us multiple
1102 * replies. We want to drain the socket, instead
1103 * of letting the packets sit in the UDP receive
1104 * queue.
1105 */
1107 read_fn = conn_discard;
1108 break;
1109
1112 break;
1113
1116 break;
1117
1121 break;
1122
1123 }
1124
1125 /*
1126 * Over-ride read for replication.
1127 */
1129 if (read_fn) read_fn = conn_discard;
1130
1131 if (fr_bio_fd_write_only(h->bio.fd) < 0) {
1132 PERROR("%s - Failed setting socket to write-only", h->ctx.module_name);
1134 return;
1135 }
1136 }
1137
1138 if (fr_event_fd_insert(h, NULL, el, h->fd,
1139 read_fn,
1140 write_fn,
1141 conn_error,
1142 tconn) < 0) {
1143 PERROR("%s - Failed inserting FD event", h->ctx.module_name);
1144
1145 /*
1146 * May free the connection!
1147 */
1149 }
1150}
1151
1152/*
1153 * Return negative numbers to put 'a' at the top of the heap.
1154 * Return positive numbers to put 'b' at the top of the heap.
1155 *
1156 * We want the value with the lowest timestamp to be prioritized at
1157 * the top of the heap.
1158 */
1159static fr_cmp_ret_t request_prioritise(void const *one, void const *two)
1160{
1161 bio_request_t const *a = one;
1162 bio_request_t const *b = two;
1163 int8_t ret;
1164
1165 /*
1166 * Prioritise status check packets
1167 */
1169 if (ret != 0) return ret;
1170
1171 /*
1172 * Larger priority is more important.
1173 */
1174 ret = CMP_PREFER_LARGER(a->priority, b->priority);
1175 if (ret != 0) return ret;
1176
1177 /*
1178 * Smaller timestamp (i.e. earlier) is more important.
1179 */
1180 return fr_time_cmp(a->recv_time, b->recv_time);
1181}
1182
1183/** Decode response packet data, extracting relevant information and validating the packet
1184 *
1185 * @param[in] ctx to allocate pairs in.
1186 * @param[out] reply Pointer to head of pair list to add reply attributes to.
1187 * @param[out] response_code The type of response packet.
1188 * @param[in] h connection handle.
1189 * @param[in] request the request.
1190 * @param[in] u UDP request.
1191 * @param[in] request_authenticator from the original request.
1192 * @param[in] data to decode.
1193 * @param[in] data_len Length of input data.
1194 * @return
1195 * - FR_RADIUS_FAIL_NONE on success.
1196 * - FR_RADIUS_FAIL_* on failure.
1197 */
1198static fr_radius_decode_fail_t decode(TALLOC_CTX *ctx, fr_pair_list_t *reply, uint8_t *response_code,
1199 bio_handle_t *h, request_t *request, bio_request_t *u,
1200 uint8_t const request_authenticator[static RADIUS_AUTH_VECTOR_LENGTH],
1201 uint8_t *data, size_t data_len)
1202{
1204 uint8_t code;
1205 fr_radius_decode_ctx_t decode_ctx;
1206
1207 *response_code = 0; /* Initialise to keep the rest of the code happy */
1208
1209 RHEXDUMP3(data, data_len, "Read packet");
1210
1211 decode_ctx = (fr_radius_decode_ctx_t) {
1212 .common = &h->ctx.radius_ctx,
1213 .request_code = u->code,
1214 .request_authenticator = request_authenticator,
1215 .tmp_ctx = talloc(ctx, uint8_t),
1216 .end = data + data_len,
1217 .verify = true,
1218 .require_message_authenticator = REQUIRE_MA(h),
1219 };
1220
1221 if (fr_radius_decode(ctx, reply, data, data_len, &decode_ctx) < 0) {
1222 talloc_free(decode_ctx.tmp_ctx);
1223 RPEDEBUG("Failed reading packet");
1224 return decode_ctx.reason;
1225 }
1226 talloc_free(decode_ctx.tmp_ctx);
1227
1228 code = data[0];
1229
1230 RDEBUG("Received %s ID %d length %zu reply packet on connection %s",
1231 fr_radius_packet_name[code], data[1], data_len, h->ctx.fd_info->name);
1232 log_request_pair_list(L_DBG_LVL_2, request, NULL, reply, NULL);
1233
1234 /*
1235 * This code is for BlastRADIUS mitigation.
1236 *
1237 * The scenario where this applies is where we send Message-Authenticator
1238 * but the home server doesn't support it or require it, in which case
1239 * the response can be manipulated by an attacker.
1240 */
1241 if ((u->code == FR_RADIUS_CODE_ACCESS_REQUEST) &&
1242 (inst->require_message_authenticator == FR_RADIUS_REQUIRE_MA_AUTO) &&
1243 !*(inst->received_message_authenticator) &&
1245 !fr_pair_find_by_da(reply, NULL, attr_eap_message)) {
1246 RINFO("Packet contained a valid Message-Authenticator. Setting \"require_message_authenticator = yes\"");
1247 *(inst->received_message_authenticator) = true;
1248 }
1249
1250 *response_code = code;
1251
1252 /*
1253 * Record the fact we've seen a response
1254 */
1255 u->num_replies++;
1256
1257 /*
1258 * Fixup retry times
1259 */
1260 if (fr_time_gt(u->retry.start, h->mrs_time)) h->mrs_time = u->retry.start;
1261
1262 return FR_RADIUS_FAIL_NONE;
1263}
1264
1265static int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id)
1266{
1267 ssize_t packet_len;
1269 rlm_radius_t const *inst = h->ctx.inst;
1270
1271 fr_assert(inst->allowed[u->code]);
1272 fr_assert(!u->packet);
1273
1274 u->packet_len = inst->max_packet_size;
1275 u->packet = h->buffer;
1276
1277 /*
1278 * We should have at minimum 64-byte packets, so don't
1279 * bother doing run-time checks here.
1280 */
1282
1284 .common = &h->ctx.radius_ctx,
1285 .rand_ctx = (fr_fast_rand_t) {
1286 .a = fr_rand(),
1287 .b = fr_rand(),
1288 },
1289 .code = u->code,
1290 .id = id,
1291 .add_proxy_state = u->proxied,
1292 };
1293
1294 /*
1295 * If we're sending a status check packet, update any
1296 * necessary timestamps. Also, don't add Proxy-State, as
1297 * we're originating the packet.
1298 */
1299 if (u->status_check) {
1300 fr_pair_t *vp;
1301
1302 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_event_timestamp);
1303 if (vp) vp->vp_date = fr_time_to_unix_time(u->retry.updated);
1304
1305 encode_ctx.add_proxy_state = false;
1306 }
1307
1308 /*
1309 * Encode it, leaving room for Proxy-State if necessary.
1310 */
1311 packet_len = fr_radius_encode(&FR_DBUFF_TMP(u->packet, u->packet_len),
1312 &request->request_pairs, &encode_ctx);
1313 if (packet_len < 0) {
1314 RPERROR("Failed encoding packet");
1315 return -1;
1316 }
1317
1318 /*
1319 * The encoded packet should NOT over-run the input buffer.
1320 */
1321 fr_assert((size_t) packet_len <= u->packet_len);
1322
1323 /*
1324 * Add Proxy-State to the tail end of the packet.
1325 *
1326 * We need to add it here, and NOT in
1327 * request->request_pairs, because multiple modules
1328 * may be sending the packets at the same time.
1329 */
1330 if (encode_ctx.add_proxy_state) {
1331 fr_pair_t *vp;
1332
1334 fr_pair_value_memdup(vp, (uint8_t const *) &inst->common_ctx.proxy_state, sizeof(inst->common_ctx.proxy_state), false);
1335 fr_pair_append(&u->extra, vp);
1336 packet_len += 2 + sizeof(inst->common_ctx.proxy_state);
1337 }
1338
1339 /*
1340 * Update our version of the packet length.
1341 */
1342 u->packet_len = packet_len;
1343
1344 /*
1345 * Now that we're done mangling the packet, sign it.
1346 */
1347 if (fr_radius_sign(u->packet, NULL, (uint8_t const *) h->ctx.radius_ctx.secret,
1348 h->ctx.radius_ctx.secret_length) < 0) {
1349 RPERROR("Failed signing packet");
1350 return -1;
1351 }
1352
1353 MEM(u->packet = talloc_memdup(u, h->buffer, packet_len));
1354
1355 return 0;
1356}
1357
1358
1359/** Revive a connection after "revive_interval"
1360 *
1361 */
1362static void revive_timeout(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
1363{
1364 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1365 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1366
1367 INFO("%s - Reviving connection %s", h->ctx.module_name, h->ctx.fd_info->name);
1369}
1370
1371/** Mark a connection dead after "zombie_interval"
1372 *
1373 */
1374static void zombie_timeout(fr_timer_list_t *tl, fr_time_t now, void *uctx)
1375{
1376 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
1377 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1378
1379 INFO("%s - No replies during 'zombie_period', marking connection %s as dead", h->ctx.module_name, h->ctx.fd_info->name);
1380
1381 /*
1382 * Don't use this connection, and re-queue all of its
1383 * requests onto other connections.
1384 */
1386
1387 /*
1388 * We do have status checks. Try to reconnect the
1389 * connection immediately. If the status checks pass,
1390 * then the connection will be marked "alive"
1391 */
1392 if (h->ctx.inst->status_check) {
1394 return;
1395 }
1396
1397 if (!h->ctx.dynamic) {
1398 /*
1399 * Force the instruction to immediately fail until the revive interval has expired.
1400 */
1401 unlang_interpret_force_result(h->instruction, &(unlang_result_t){.rcode = RLM_MODULE_FAIL}, tl,
1403
1404 /*
1405 * Mark the connection as active, so when the module forced result times out
1406 * requests will be sent again.
1407 */
1409 return;
1410 }
1411
1412 /*
1413 * Revive the connection after a time.
1414 */
1415 if (fr_timer_at(h, tl, &h->zombie_ev,
1416 fr_time_add(now, h->ctx.inst->revive_interval), false,
1417 revive_timeout, tconn) < 0) {
1418 ERROR("Failed inserting revive timeout for connection");
1420 }
1421}
1422
1423
1424/** See if the connection is zombied.
1425 *
1426 * We check for zombie when major events happen:
1427 *
1428 * 1) request hits its final timeout
1429 * 2) request timer hits, and it needs to be retransmitted
1430 * 3) a DUP packet comes in, and the request needs to be retransmitted
1431 * 4) we're sending a packet.
1432 *
1433 * There MIGHT not be retries configured, so we MUST check for zombie
1434 * when any new packet comes in. Similarly, there MIGHT not be new
1435 * packets, but retries are configured, so we have to check there,
1436 * too.
1437 *
1438 * Also, the socket might not be writable for a while. There MIGHT
1439 * be a long time between getting the timer / DUP signal, and the
1440 * request finally being written to the socket. So we need to check
1441 * for zombie at BOTH the timeout and the mux / write function.
1442 *
1443 * @return
1444 * - true if the connection is zombie.
1445 * - false if the connection is not zombie.
1446 */
1447static bool check_for_zombie(request_t *request, trunk_connection_t *tconn, fr_time_t now, fr_time_t last_sent)
1448{
1449 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
1451
1452 /*
1453 * We're replicating, and don't care about the health of
1454 * the home server, and this function should not be called.
1455 */
1457
1458 /*
1459 * If we're status checking OR already zombie, don't go to zombie
1460 */
1461 if (h->status_checking || fr_timer_armed(h->zombie_ev)) return true;
1462
1463 if (fr_time_eq(now, fr_time_wrap(0))) now = fr_time();
1464
1465 /*
1466 * We received a reply since this packet was sent, the connection isn't zombie.
1467 */
1468 if (fr_time_gteq(h->last_reply, last_sent)) return false;
1469
1470 /*
1471 * If we've seen ANY response in the allowed window, then the connection is still alive.
1472 */
1473 if ((h->ctx.inst->mode == RLM_RADIUS_MODE_PROXY) &&
1474 fr_time_gt(h->last_reply, fr_time_sub(now, h->ctx.inst->response_window))) return false;
1475
1476 /*
1477 * Stop using it for new requests.
1478 */
1479 WARN("%s - Entering Zombie state - connection %s", h->ctx.module_name, h->ctx.fd_info->name);
1481
1482 if (h->ctx.inst->status_check) {
1483 /*
1484 * If it's UDP, reconnect. This will start the sending of status checks.
1485 */
1486 if (h->ctx.inst->fd_config.socket_type == SOCK_DGRAM) {
1489 }
1490
1491 h->status_checking = true;
1492
1493 /*
1494 * Queue up the status check packet. It will be sent
1495 * when the connection is writable.
1496 */
1498 h->status_u->treq = NULL;
1499
1501 h->status_u, h->status_u, true) != TRUNK_ENQUEUE_OK) {
1503 }
1504 } else {
1505 /*
1506 * Capture the instruction which started the zombie period.
1507 */
1509
1510 if (fr_timer_at(h, el->tl, &h->zombie_ev, fr_time_add(now, h->ctx.inst->zombie_period),
1511 false, zombie_timeout, tconn) < 0) {
1512 ERROR("Failed inserting zombie timeout for connection");
1514 }
1515 }
1516
1517 return true;
1518}
1519
1520static void mod_dup(request_t *request, bio_request_t *u)
1521{
1522 bio_handle_t *h;
1523
1524 h = talloc_get_type_abort(u->treq->tconn->conn->h, bio_handle_t);
1525
1526 if (h->ctx.fd_config.socket_type != SOCK_DGRAM) {
1527 RDEBUG("Using stream sockets - suppressing retransmission");
1528 return;
1529 }
1530
1531 /*
1532 * Arguably this should never happen for UDP sockets.
1533 */
1534 if (h->ctx.fd_info->write_blocked) {
1535 RDEBUG("IO is blocked - suppressing retransmission");
1536 return;
1537 }
1538 u->is_retry = true;
1539
1540 /*
1541 * We are doing synchronous proxying, retransmit
1542 * the current request on the same connection.
1543 *
1544 * If it's zombie, we still resend it. If the
1545 * connection is dead, then a callback will move
1546 * this request to a new connection.
1547 */
1548 mod_write(request, u->treq, h);
1549}
1550
1551static void do_retry(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_retry_t const *retry);
1552
1553/** Handle module retries.
1554 *
1555 */
1556static void mod_retry(module_ctx_t const *mctx, request_t *request, fr_retry_t const *retry)
1557{
1558 bio_request_t *u = talloc_get_type_abort(mctx->rctx, bio_request_t);
1559 rlm_radius_t const *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
1560
1561 do_retry(inst, u, request, retry);
1562}
1563
1564static void do_retry(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_retry_t const *retry)
1565{
1566 trunk_request_t *treq;
1567 trunk_connection_t *tconn;
1568 fr_time_t now;
1569
1570 if (!u->treq) {
1571 RDEBUG("Packet was cancelled by the connection handler - ignoring retry");
1572 return;
1573 }
1574
1575 treq = talloc_get_type_abort(u->treq, trunk_request_t);
1576
1577 fr_assert(request == treq->request);
1578 fr_assert(treq->preq); /* Must still have a protocol request */
1579 fr_assert(treq->preq == u);
1580
1581 tconn = treq->tconn;
1582 now = retry->updated;
1583
1584 switch (retry->state) {
1585 case FR_RETRY_CONTINUE:
1586 u->retry = *retry;
1587
1588 switch (treq->state) {
1591 fr_assert(0);
1592 break;
1593
1595 RDEBUG("Packet is still in the backlog queue to be sent - suppressing retransmission");
1596 return;
1597
1599 RDEBUG("Packet is still in the pending queue to be sent - suppressing retransmission");
1600 return;
1601
1603 RDEBUG("Packet was partially written, as IO is blocked - suppressing retransmission");
1604 return;
1605
1607 fr_assert(tconn);
1608
1609 mod_dup(request, u);
1610 return;
1611
1619 fr_assert(0);
1620 break;
1621 }
1622 break;
1623
1624 case FR_RETRY_MRD:
1625 REDEBUG("Reached maximum_retransmit_duration (%pVs > %pVs), failing request",
1627 break;
1628
1629 case FR_RETRY_MRC:
1630 REDEBUG("Reached maximum_retransmit_count (%u > %u), failing request",
1631 retry->count, retry->config->mrc);
1632 break;
1633 }
1634
1637
1638 /*
1639 * We don't do zombie stuff!
1640 */
1641 if (!tconn || (inst->mode == RLM_RADIUS_MODE_REPLICATE)) return;
1642
1643 check_for_zombie(request, tconn, now, retry->start);
1644}
1645
1646CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
1648 trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
1649{
1650 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
1651 trunk_request_t *treq;
1652 request_t *request;
1653
1654 if (unlikely(trunk_connection_pop_request(&treq, tconn) < 0)) return;
1655
1656 /*
1657 * No more requests to send
1658 */
1659 if (!treq) return;
1660
1661 request = treq->request;
1662
1663 mod_write(request, treq, h);
1664}
1665
1666static void mod_write(request_t *request, trunk_request_t *treq, bio_handle_t *h)
1667{
1668 rlm_radius_t const *inst = h->ctx.inst;
1669 bio_request_t *u;
1670 char const *action;
1671 uint8_t const *packet;
1672 size_t packet_len;
1673 ssize_t slen;
1674
1675 u = treq->preq;
1676
1677 fr_assert((treq->state == TRUNK_REQUEST_STATE_PENDING) ||
1678 (treq->state == TRUNK_REQUEST_STATE_PARTIAL) ||
1679 ((u->retry.count > 0) && (treq->state == TRUNK_REQUEST_STATE_SENT)));
1680
1682
1683 /*
1684 * If it's a partial packet, then write the partial bit.
1685 */
1686 if (u->partial) {
1687 fr_assert(u->partial < u->packet_len);
1688 packet = u->packet + u->partial;
1689 packet_len = u->packet_len - u->partial;
1690 goto do_write;
1691 }
1692
1693 /*
1694 * No previous packet, OR can't retransmit the
1695 * existing one. Oh well.
1696 *
1697 * Note that if we can't retransmit the previous
1698 * packet, then u->rr MUST already have been
1699 * deleted in the request_cancel() function
1700 * or request_release_conn() function when
1701 * the REQUEUE signal was received.
1702 */
1703 if (!u->packet) {
1704 fr_assert(!u->rr);
1705
1706 if (unlikely(radius_track_entry_reserve(&u->rr, treq, h->tt, request, u->code, treq) < 0)) {
1707#ifndef NDEBUG
1708 radius_track_state_log(&default_log, L_ERR, __FILE__, __LINE__,
1710#endif
1711 fr_assert_fail("Tracking entry allocation failed: %s", fr_strerror());
1713 return;
1714 }
1715 fr_assert(u->rr);
1716 u->id = u->rr->id;
1717
1718 RDEBUG("Sending %s ID %d length %zu over connection %s",
1720
1721 if (encode(h, request, u, u->id) < 0) {
1722 /*
1723 * Need to do this because request_conn_release
1724 * may not be called.
1725 */
1728 return;
1729 }
1730 RHEXDUMP3(u->packet, u->packet_len, "Encoded packet");
1731
1732 /*
1733 * Remember the authentication vector, which now has the
1734 * packet signature.
1735 */
1737 } else {
1738 RDEBUG("Retransmitting %s ID %d length %zu over connection %s",
1740 }
1741
1742 /*
1743 * @todo - When logging Message-Authenticator, don't print its' value.
1744 */
1745 log_request_proto_pair_list(L_DBG_LVL_2, request, NULL, &request->request_pairs, NULL);
1746 if (!fr_pair_list_empty(&u->extra)) log_request_proto_pair_list(L_DBG_LVL_2, request, NULL, &u->extra, NULL);
1747
1748 packet = u->packet;
1749 packet_len = u->packet_len;
1750
1751do_write:
1752 fr_assert(packet != NULL);
1753 fr_assert(packet_len >= RADIUS_HEADER_LENGTH);
1754
1755 slen = fr_bio_write(h->bio.main, NULL, packet, packet_len);
1756
1757 /*
1758 * Can't write anything, requeue it on a different socket.
1759 */
1760 if (slen == fr_bio_error(IO_WOULD_BLOCK)) goto requeue;
1761
1762 if (slen < 0) {
1763 switch (errno) {
1764 /*
1765 * There is an error in the request.
1766 */
1767 case EMSGSIZE: /* Packet size exceeds max size allowed on socket */
1768 ERROR("%s - Failed sending data over connection %s: %s",
1769 h->ctx.module_name, h->ctx.fd_info->name, fr_syserror(errno));
1771 break;
1772
1773 /*
1774 * There is an error in the connection. The reconnection will re-queue any pending or
1775 * sent requests, so we don't have to do any cleanup.
1776 */
1777 default:
1778 ERROR("%s - Failed sending data over connection %s: %s",
1779 h->ctx.module_name, h->ctx.fd_info->name, fr_syserror(errno));
1781 break;
1782 }
1783
1784 return;
1785 }
1786
1787 /*
1788 * No data to send, ignore the write for partials, but otherwise requeue it.
1789 */
1790 if (slen == 0) {
1791 if (u->partial) return;
1792
1793 /*
1794 * We didn't get a "blocked" error, but we didn't write any data. And the socket is
1795 * unconnected. This means we just discard the packet.
1796 */
1798 ERROR("%s - Failed sending %s ID %d length %zu over connection %s: Destination network is down or unreachable",
1801 return;
1802 }
1803
1804 requeue:
1805 RWARN("%s - Failed sending data over connection %s: sent zero bytes",
1806 h->ctx.module_name, h->ctx.fd_info->name);
1808 return;
1809 }
1810
1811 packet_len += slen;
1812 if (packet_len < u->packet_len) {
1813 u->partial = packet_len;
1815 return;
1816 }
1817
1818 /*
1819 * For retransmissions.
1820 */
1821 u->partial = 0;
1822
1823 /*
1824 * Don't print anything extra for replication.
1825 */
1826 if (inst->mode == RLM_RADIUS_MODE_REPLICATE) {
1827 u->rcode = RLM_MODULE_OK;
1829 return;
1830 }
1831
1832 /*
1833 * On first packet, signal it as sent, and update stats.
1834 *
1835 * Later packets are just retransmissions to the BIO, and don't need to involve
1836 * the trunk code.
1837 */
1838 if (u->retry.count == 1) {
1839 h->last_sent = u->retry.start;
1841
1843
1844 action = u->proxied ? "Proxied" : "Originated";
1845
1846 } else {
1847 /*
1848 * We don't signal the trunk that it's been sent, it was already senty
1849 */
1850 action = "Retransmitted";
1851 }
1852
1854
1855 if (!u->proxied) {
1856 RDEBUG("%s request. Expecting response within %pVs", action,
1858
1859 } else {
1860 /*
1861 * If the packet doesn't get a response,
1862 * then bio_request_free() will notice, and run conn_zombie()
1863 */
1864 RDEBUG("%s request. Relying on NAS to perform more retransmissions", action);
1865 }
1866
1867 /*
1868 * We don't retransmit over TCP.
1869 */
1870 if (h->ctx.fd_config.socket_type != SOCK_DGRAM) return;
1871
1872 /*
1873 * If we only send one datagram packet, then don't bother saving it.
1874 */
1875 if (u->retry.config && u->retry.config->mrc == 1) {
1876 u->packet = NULL;
1877 return;
1878 }
1879
1880 MEM(u->packet = talloc_memdup(u, u->packet, u->packet_len));
1881}
1882
1883/** Deal with Protocol-Error replies, and possible negotiation
1884 *
1885 */
1887{
1888 bool error_601 = false;
1889 uint32_t response_length = 0;
1890 uint8_t const *attr, *end;
1891
1892 end = h->buffer + fr_nbo_to_uint16(h->buffer + 2);
1893
1894 for (attr = h->buffer + RADIUS_HEADER_LENGTH;
1895 attr < end;
1896 attr += attr[1]) {
1897 /*
1898 * Error-Cause = Response-Too-Big
1899 */
1900 if ((attr[0] == attr_error_cause->attr) && (attr[1] == 6)) {
1901 uint32_t error;
1902
1903 memcpy(&error, attr + 2, 4);
1904 error = ntohl(error);
1905 if (error == 601) error_601 = true;
1906 continue;
1907 }
1908
1909 /*
1910 * The other end wants us to increase our Response-Length
1911 */
1912 if ((attr[0] == attr_response_length->attr) && (attr[1] == 6)) {
1913 memcpy(&response_length, attr + 2, 4);
1914 continue;
1915 }
1916
1917 /*
1918 * Protocol-Error packets MUST contain an
1919 * Original-Packet-Code attribute.
1920 *
1921 * The attribute containing the
1922 * Original-Packet-Code is an extended
1923 * attribute.
1924 */
1925 if (attr[0] != attr_extended_attribute_1->attr) continue;
1926
1927 /*
1928 * ATTR + LEN + EXT-Attr + uint32
1929 */
1930 if (attr[1] != 7) continue;
1931
1932 /*
1933 * See if there's an Original-Packet-Code.
1934 */
1935 if (attr[2] != (uint8_t)attr_original_packet_code->attr) continue;
1936
1937 /*
1938 * Has to be an 8-bit number.
1939 */
1940 if ((attr[3] != 0) ||
1941 (attr[4] != 0) ||
1942 (attr[5] != 0)) {
1944 return;
1945 }
1946
1947 /*
1948 * The value has to match. We don't
1949 * currently multiplex different codes
1950 * with the same IDs on connections. So
1951 * this check is just for RFC compliance,
1952 * and for sanity.
1953 */
1954 if (attr[6] != u->code) {
1956 return;
1957 }
1958 }
1959
1960 /*
1961 * Error-Cause = Response-Too-Big
1962 *
1963 * The other end says it needs more room to send it's response
1964 *
1965 * Limit it to reasonable values.
1966 */
1967 if (error_601 && response_length && (response_length > h->buflen)) {
1968 if (response_length < 4096) response_length = 4096;
1969 if (response_length > 65535) response_length = 65535;
1970
1971 DEBUG("%s - Increasing buffer size to %u for connection %s", h->ctx.module_name, response_length, h->ctx.fd_info->name);
1972
1973 /*
1974 * Make sure to copy the packet over!
1975 */
1976 attr = h->buffer;
1977 h->buflen = response_length;
1978 MEM(h->buffer = talloc_array(h, uint8_t, h->buflen));
1979
1980 memcpy(h->buffer, attr, end - attr);
1981 }
1982
1983 /*
1984 * fail - something went wrong internally, or with the connection.
1985 * invalid - wrong response to packet
1986 * handled - best remaining alternative :(
1987 *
1988 * i.e. if the response is NOT accept, reject, whatever,
1989 * then we shouldn't allow the caller to do any more
1990 * processing of this packet. There was a protocol
1991 * error, and the response is valid, but not useful for
1992 * anything.
1993 */
1995}
1996
1997
1998/** Handle retries for a status check
1999 *
2000 */
2002{
2003 trunk_connection_t *tconn = talloc_get_type_abort(uctx, trunk_connection_t);
2004 bio_handle_t *h = talloc_get_type_abort(tconn->conn->h, bio_handle_t);
2005
2007 h->status_u, h->status_u, true) != TRUNK_ENQUEUE_OK) {
2009 }
2010}
2011
2012
2013/** Deal with replies replies to status checks and possible negotiation
2014 *
2015 */
2017{
2018 bio_handle_t *h = talloc_get_type_abort(treq->tconn->conn->h, bio_handle_t);
2019 rlm_radius_t const *inst = h->ctx.inst;
2020 bio_request_t *u = talloc_get_type_abort(treq->rctx, bio_request_t);
2021
2022 fr_assert(treq->preq == h->status_u);
2023 fr_assert(treq->rctx == h->status_u);
2024
2025 u->treq = NULL;
2026
2027 /*
2028 * @todo - do other negotiation and signaling.
2029 */
2031
2032 if (u->num_replies < inst->num_answers_to_alive) {
2033 DEBUG("Received %u / %u replies for status check, on connection - %s",
2034 u->num_replies, inst->num_answers_to_alive, h->ctx.fd_info->name);
2035 DEBUG("Next status check packet will be in %pVs", fr_box_time_delta(fr_time_sub(u->retry.next, now)));
2036
2037 /*
2038 * Set the timer for the next retransmit.
2039 */
2040 if (fr_timer_at(h, h->ctx.el->tl, &u->ev, u->retry.next, false, status_check_next, treq->tconn) < 0) {
2042 }
2043 return;
2044 }
2045
2046 DEBUG("Received enough replies to status check, marking connection as active - %s", h->ctx.fd_info->name);
2047
2048 /*
2049 * Set the "last idle" time to now, so that we don't
2050 * restart zombie_period until sufficient time has
2051 * passed.
2052 */
2053 h->last_idle = fr_time();
2054
2055 /*
2056 * Reset retry interval and retransmission counters
2057 * also frees u->ev.
2058 */
2059 status_check_reset(h, u);
2060 trunk_connection_signal_active(treq->tconn);
2061}
2062
2063CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
2065{
2066 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
2067
2068 DEBUG3("%s - Reading data for connection %s", h->ctx.module_name, h->ctx.fd_info->name);
2069
2070 while (true) {
2071 ssize_t slen;
2072
2073 trunk_request_t *treq;
2074 request_t *request;
2075 bio_request_t *u;
2078 uint8_t code = 0;
2079 fr_pair_list_t reply;
2080 fr_pair_t *vp;
2081
2082 fr_time_t now;
2083
2084 fr_pair_list_init(&reply);
2085
2086 /*
2087 * Drain the socket of all packets. If we're busy, this
2088 * saves a round through the event loop. If we're not
2089 * busy, a few extra system calls don't matter.
2090 */
2091 slen = fr_bio_read(h->bio.main, NULL, h->buffer, h->buflen);
2092 if (slen == 0) {
2093 /*
2094 * @todo - set BIO FD EOF callback, so that we don't have to check it here.
2095 */
2097 return;
2098 }
2099
2100 /*
2101 * We're done reading, return.
2102 */
2103 if (slen == fr_bio_error(IO_WOULD_BLOCK)) return;
2104
2105 if (slen < 0) {
2106 ERROR("%s - Failed reading response from socket: %s",
2107 h->ctx.module_name, fr_syserror(errno));
2109 return;
2110 }
2111
2112 fr_assert(slen >= RADIUS_HEADER_LENGTH); /* checked in verify */
2113
2114 /*
2115 * Note that we don't care about packet codes. All
2116 * packet codes share the same ID space.
2117 */
2118 rr = radius_track_entry_find(h->tt, h->buffer[1], NULL);
2119 if (!rr) {
2120 WARN("%s - Ignoring reply with ID %i that arrived too late",
2121 h->ctx.module_name, h->buffer[1]);
2122 continue;
2123 }
2124
2125 treq = talloc_get_type_abort(rr->uctx, trunk_request_t);
2126 request = treq->request;
2127 fr_assert(request != NULL);
2128 u = talloc_get_type_abort(treq->rctx, bio_request_t);
2129 fr_assert(u == treq->preq);
2130
2131 /*
2132 * If we got a reply during the zombie period mark the
2133 * connection as active and remove the timer.
2134 */
2138 }
2139
2140 /*
2141 * Decode the incoming packet.
2142 */
2143 reason = decode(request->reply_ctx, &reply, &code, h, request, u, rr->vector, h->buffer, (size_t)slen);
2144 if (reason != FR_RADIUS_FAIL_NONE) continue;
2145
2146 /*
2147 * Only valid packets are processed
2148 * Otherwise an attacker could perform
2149 * a DoS attack against the proxying servers
2150 * by sending fake responses for upstream
2151 * servers.
2152 */
2153 h->last_reply = now = fr_time();
2154
2155 /*
2156 * Status-Server can have any reply code, we don't care
2157 * what it is. So long as it's signed properly, we
2158 * accept it. This flexibility is because we don't
2159 * expose Status-Server to the admins. It's only used by
2160 * this module for internal signalling.
2161 */
2162 if (u == h->status_u) {
2163 fr_pair_list_free(&reply); /* Probably want to pass this to status_check_reply? */
2164 status_check_reply(treq, now);
2166 continue;
2167 }
2168
2169 /*
2170 * Handle any state changes, etc. needed by receiving a
2171 * Protocol-Error reply packet.
2172 *
2173 * Protocol-Error is permitted as a reply to any
2174 * packet.
2175 */
2176 switch (code) {
2179
2180 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_original_packet_code);
2181 if (!vp) {
2182 RWDEBUG("Protocol-Error response is missing Original-Packet-Code");
2183 } else {
2184 fr_pair_delete_by_da(&request->reply_pairs, attr_original_packet_code);
2185 }
2186
2187 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_error_cause);
2188 if (!vp) {
2189 MEM(vp = fr_pair_afrom_da(request->reply_ctx, attr_error_cause));
2190 vp->vp_uint32 = FR_ERROR_CAUSE_VALUE_PROXY_PROCESSING_ERROR;
2191 fr_pair_append(&request->reply_pairs, vp);
2192 }
2193 break;
2194
2195 default:
2196 break;
2197 }
2198
2199 /*
2200 * Mark up the request as being an Access-Challenge, if
2201 * required.
2202 *
2203 * We don't do this for other packet types, because the
2204 * ok/fail nature of the module return code will
2205 * automatically result in it the parent request
2206 * returning an ok/fail packet code.
2207 */
2209 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_packet_type);
2210 if (!vp) {
2211 MEM(vp = fr_pair_afrom_da(request->reply_ctx, attr_packet_type));
2213 fr_pair_append(&request->reply_pairs, vp);
2214 }
2215
2216 /*
2217 * If the Access-Request got a challenge, AND the request doesn't have State, AND
2218 * the challenge does have State, THEN try to load-balance future packets to the
2219 * same destination.
2220 */
2221 if (h->ctx.inst->track_load_balance &&
2222 !fr_pair_find_by_da(&request->request_pairs, NULL, attr_state) &&
2223 fr_pair_find_by_da(&request->reply_pairs, NULL, attr_state)) {
2224 (void) unlang_load_balance_persist(request);
2225 }
2226 }
2227
2228 /*
2229 * Delete Proxy-State attributes from the reply.
2230 */
2232
2233 /*
2234 * If the reply has Message-Authenticator, then over-ride its value with all zeros, so
2235 * that we don't confuse anyone reading the debug output.
2236 */
2237 if ((vp = fr_pair_find_by_da(&reply, NULL, attr_message_authenticator)) != NULL) {
2238 (void) fr_pair_value_memdup(vp, (uint8_t const *) "", 1, false);
2239 }
2240
2241 treq->request->reply->code = code;
2242 u->rcode = radius_code_to_rcode[code];
2243 fr_pair_list_append(&request->reply_pairs, &reply);
2245 }
2246}
2247
2248/*
2249 * This is the same as request_mux(), except that we immediately mark the request as complete.
2250 */
2251CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
2253 trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
2254{
2255 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
2256 trunk_request_t *treq;
2257
2258 if (unlikely(trunk_connection_pop_request(&treq, tconn) < 0)) return;
2259
2260 /*
2261 * No more requests to send
2262 */
2263 if (!treq) return;
2264
2265 mod_write(treq->request, treq, h);
2267}
2268
2269CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
2271{
2272 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
2273
2274 DEBUG3("%s - Reading data for connection %s", h->ctx.module_name, h->ctx.fd_info->name);
2275
2276 while (true) {
2277 ssize_t slen;
2278
2279 trunk_request_t *treq;
2280 request_t *request;
2281 bio_request_t *u;
2284 uint8_t code = 0;
2285 fr_pair_list_t reply;
2286
2287 fr_time_t now;
2288
2289 fr_pair_list_init(&reply);
2290
2291 /*
2292 * Drain the socket of all packets. If we're busy, this
2293 * saves a round through the event loop. If we're not
2294 * busy, a few extra system calls don't matter.
2295 */
2296 slen = fr_bio_read(h->bio.main, NULL, h->buffer, h->buflen);
2297 if (slen == 0) {
2298 /*
2299 * @todo - set BIO FD EOF callback, so that we don't have to check it here.
2300 */
2302 return;
2303 }
2304
2305 /*
2306 * We're done reading, return.
2307 */
2308 if (slen == fr_bio_error(IO_WOULD_BLOCK)) return;
2309
2310 if (slen < 0) {
2311 ERROR("%s - Failed reading response from socket: %s",
2312 h->ctx.module_name, fr_syserror(errno));
2314 return;
2315 }
2316
2317 fr_assert(slen >= RADIUS_HEADER_LENGTH); /* checked in verify */
2318
2319 /*
2320 * We only pay attention to Protocol-Error replies.
2321 *
2322 * All other packets are discarded.
2323 */
2325 continue;
2326 }
2327
2328 /*
2329 * Note that we don't care about packet codes. All
2330 * packet codes share the same ID space.
2331 */
2332 rr = radius_track_entry_find(h->tt, h->buffer[1], NULL);
2333 if (!rr) {
2334 WARN("%s - Ignoring reply with ID %i that arrived too late",
2335 h->ctx.module_name, h->buffer[1]);
2336 continue;
2337 }
2338
2339 treq = talloc_get_type_abort(rr->uctx, trunk_request_t);
2340 request = treq->request;
2341 fr_assert(request != NULL);
2342 u = talloc_get_type_abort(treq->rctx, bio_request_t);
2343 fr_assert(u == treq->preq);
2344
2345 /*
2346 * Decode the incoming packet
2347 */
2348 reason = decode(request->reply_ctx, &reply, &code, h, request, u, rr->vector, h->buffer, (size_t)slen);
2349 if (reason != FR_RADIUS_FAIL_NONE) continue;
2350
2351 /*
2352 * Only valid packets are processed
2353 * Otherwise an attacker could perform
2354 * a DoS attack against the proxying servers
2355 * by sending fake responses for upstream
2356 * servers.
2357 */
2358 h->last_reply = now = fr_time();
2359
2360 /*
2361 * Status-Server can have any reply code, we don't care
2362 * what it is. So long as it's signed properly, we
2363 * accept it. This flexibility is because we don't
2364 * expose Status-Server to the admins. It's only used by
2365 * this module for internal signalling.
2366 */
2367 if (u == h->status_u) {
2368 fr_pair_list_free(&reply); /* Probably want to pass this to status_check_reply? */
2369 status_check_reply(treq, now);
2371 continue;
2372 }
2373
2374 /*
2375 * Handle any state changes, etc. needed by receiving a
2376 * Protocol-Error reply packet.
2377 *
2378 * Protocol-Error is also permitted as a reply to any
2379 * packet.
2380 */
2382 }
2383}
2384
2385
2386/** Remove the request from any tracking structures
2387 *
2388 * Frees encoded packets if the request is being moved to a new connection
2389 */
2390static void request_cancel(UNUSED connection_t *conn, void *preq_to_reset,
2391 trunk_cancel_reason_t reason, UNUSED void *uctx)
2392{
2393 bio_request_t *u = preq_to_reset;
2394
2395 /*
2396 * Request has been requeued on the same
2397 * connection due to timeout or DUP signal. We
2398 * keep the same packet to avoid re-encoding it.
2399 */
2400 if (reason == TRUNK_CANCEL_REASON_REQUEUE) {
2401 /*
2402 * Delete the request_timeout
2403 *
2404 * Note: There might not be a request timeout
2405 * set in the case where the request was
2406 * queued for sendmmsg but never actually
2407 * sent.
2408 */
2409 FR_TIMER_DISARM(u->ev);
2410 }
2411
2412 /*
2413 * Other cancellations are dealt with by
2414 * request_conn_release as the request is removed
2415 * from the trunk.
2416 */
2417}
2418
2419/** Clear out anything associated with the handle from the request
2420 *
2421 */
2422static void request_conn_release(connection_t *conn, void *preq_to_reset, UNUSED void *uctx)
2423{
2424 bio_request_t *u = preq_to_reset;
2425 bio_handle_t *h = talloc_get_type_abort(conn->h, bio_handle_t);
2426
2427 FR_TIMER_DISARM(u->ev);
2429
2430 if (h->ctx.inst->mode == RLM_RADIUS_MODE_REPLICATE) return;
2431
2432 u->num_replies = 0;
2433
2434 /*
2435 * If there are no outstanding tracking entries
2436 * allocated then the connection is "idle".
2437 */
2438 if (!h->tt || (h->tt->num_requests == 0)) h->last_idle = fr_time();
2439}
2440
2441/** Write out a canned failure
2442 *
2443 */
2444static void request_fail(request_t *request, NDEBUG_UNUSED void *preq, void *rctx,
2446{
2447 bio_request_t *u = talloc_get_type_abort(rctx, bio_request_t);
2448
2449 fr_assert(u == preq);
2450
2451 fr_assert(!u->rr && !u->packet && fr_pair_list_empty(&u->extra) && !u->ev); /* Dealt with by request_conn_release */
2452
2454
2455 if (u->status_check) return;
2456
2458 u->treq = NULL;
2459
2461}
2462
2463/** Response has already been written to the rctx at this point
2464 *
2465 */
2466static void request_complete(request_t *request, NDEBUG_UNUSED void *preq, void *rctx, UNUSED void *uctx)
2467{
2468 bio_request_t *u = talloc_get_type_abort(rctx, bio_request_t);
2469
2470 fr_assert(u == preq);
2471
2472 fr_assert(!u->rr && !u->packet && fr_pair_list_empty(&u->extra) && !u->ev); /* Dealt with by request_conn_release */
2473
2474 if (u->status_check) return;
2475
2476 u->treq = NULL;
2477
2479}
2480
2481/** Resume execution of the request, returning the rcode set during trunk execution
2482 *
2483 */
2485{
2486 bio_request_t *u = talloc_get_type_abort(mctx->rctx, bio_request_t);
2487 rlm_rcode_t rcode = u->rcode;
2488
2489 talloc_free(u);
2490
2491 RETURN_UNLANG_RCODE(rcode);
2492}
2493
2494static void do_signal(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_signal_t action);
2495
2496static void mod_signal(module_ctx_t const *mctx, UNUSED request_t *request, fr_signal_t action)
2497{
2499
2500 bio_request_t *u = talloc_get_type_abort(mctx->rctx, bio_request_t);
2501
2502 do_signal(inst, u, request, action);
2503}
2504
2505static void do_signal(rlm_radius_t const *inst, bio_request_t *u, UNUSED request_t *request, fr_signal_t action)
2506{
2507 /*
2508 * We received a duplicate packet, but we're not doing
2509 * synchronous proxying. Ignore the dup, and rely on the
2510 * IO submodule to time it's own retransmissions.
2511 */
2512 if ((action == FR_SIGNAL_DUP) && (inst->mode != RLM_RADIUS_MODE_PROXY)) return;
2513
2514 /*
2515 * If we don't have a treq associated with the
2516 * rctx it's likely because the request was
2517 * scheduled, but hasn't yet been resumed, and
2518 * has received a signal, OR has been resumed
2519 * and immediately cancelled as the event loop
2520 * is exiting, in which case
2521 * unlang_request_is_scheduled will return false
2522 * (don't use it).
2523 */
2524 if (!u->treq) return;
2525
2526 switch (action) {
2527 /*
2528 * The request is being cancelled, tell the
2529 * trunk so it can clean up the treq.
2530 */
2531 case FR_SIGNAL_CANCEL:
2533 u->treq = NULL;
2534 return;
2535
2536 /*
2537 * Requeue the request on the same connection
2538 * causing a "retransmission" if the request
2539 * has already been sent out.
2540 */
2541 case FR_SIGNAL_DUP:
2542 mod_dup(request, u);
2543 return;
2544
2545 default:
2546 return;
2547 }
2548}
2549
2550/** Free a bio_request_t
2551 *
2552 * Allows us to set break points for debugging.
2553 */
2555{
2556 if (!u->treq) return 0;
2557
2558#ifndef NDEBUG
2559 {
2560 trunk_request_t *treq;
2561 treq = talloc_get_type_abort(u->treq, trunk_request_t);
2562 fr_assert(treq->preq == u);
2563 }
2564#endif
2565
2566 fr_assert_msg(!fr_timer_armed(u->ev), "bio_request_t freed with active timer");
2567
2569
2570 fr_assert(u->rr == NULL);
2571
2572 return 0;
2573}
2574
2575static int mod_enqueue(bio_request_t **p_u, fr_retry_config_t const **p_retry_config,
2576 rlm_radius_t const *inst, trunk_t *trunk, request_t *request)
2577{
2578 bio_request_t *u;
2579 trunk_request_t *treq;
2581
2582 fr_assert(request->packet->code > 0);
2583 fr_assert(request->packet->code < FR_RADIUS_CODE_MAX);
2584
2585 /*
2586 * Do any necessary RADIUS level fixups
2587 * - check Proxy-State
2588 * - do CHAP-Challenge fixups
2589 */
2590 if (radius_fixups(inst, request) < 0) return 0;
2591
2592 treq = trunk_request_alloc(trunk, request);
2593 if (!treq) {
2594 REDEBUG("Failed allocating handler for request");
2595 return -1;
2596 }
2597
2598 MEM(u = talloc_zero(request, bio_request_t));
2599 talloc_set_destructor(u, _bio_request_free);
2600
2601 /*
2602 * Can't use compound literal - const issues.
2603 */
2604 u->code = request->packet->code;
2605 u->priority = request->priority;
2606 u->recv_time = request->async->recv_time;
2608
2609 u->retry.count = 1;
2610
2612
2613 switch(trunk_request_enqueue(&treq, trunk, request, u, u)) {
2614 case TRUNK_ENQUEUE_OK:
2616 break;
2617
2619 REDEBUG("Unable to queue packet - connections at maximum capacity");
2620 fail:
2621 fr_assert(!u->rr && !u->packet); /* Should not have been fed to the muxer */
2622 trunk_request_free(&treq); /* Return to the free list */
2623 talloc_free(u);
2624 return -1;
2625
2627 REDEBUG("All destinations are down - cannot send packet");
2628 goto fail;
2629
2630 case TRUNK_ENQUEUE_FAIL:
2631 REDEBUG("Unable to queue packet");
2632 goto fail;
2633 }
2634
2635 u->treq = treq; /* Remember for signalling purposes */
2636 fr_assert(treq->rctx == u);
2637
2638 /*
2639 * Figure out if we're originating the packet or proxying it. And also figure out if we have to
2640 * retry.
2641 */
2642 switch (inst->mode) {
2644 case RLM_RADIUS_MODE_UNCONNECTED_REPLICATE: /* unconnected sockets are UDP, and bypass the trunk */
2645 REDEBUG("Internal sanity check failed - connection trunking cannot be used for replication");
2646 return -1;
2647
2648 /*
2649 * We originate this packet if it was taken from the detail module, which doesn't have a
2650 * real client. @todo - do a better check here.
2651 *
2652 * We originate this packet if the parent request is not compatible with this one
2653 * (i.e. it's from a different protocol).
2654 *
2655 * We originate the packet if the parent is from the same dictionary, but has a different
2656 * packet code. This lets us receive Accounting-Request, and originate
2657 * Disconnect-Request.
2658 */
2661 if (!request->parent) {
2662 u->proxied = (request->client && request->client->cs != NULL);
2663
2664 } else if (!fr_dict_compatible(request->parent->proto_dict, request->proto_dict)) {
2665 u->proxied = false;
2666
2667 } else {
2668 u->proxied = (request->parent->packet->code == request->packet->code);
2669 }
2670
2671 /*
2672 * Proxied packets get a final timeout, as we retry only on DUP packets.
2673 */
2674 if (u->proxied) goto timeout_retry;
2675
2677
2678 /*
2679 * Client packets (i.e. packets we originate) get retries for UDP. And no retries for TCP.
2680 */
2682 if (inst->fd_config.socket_type == SOCK_DGRAM) {
2683 retry_config = &inst->retry[u->code];
2684 break;
2685 }
2687
2688 /*
2689 * Replicated packets are never retried, but they have a timeout if the socket isn't
2690 * ready for writing.
2691 */
2693 timeout_retry:
2694 retry_config = &inst->timeout_retry;
2695 break;
2696
2697 default:
2698 fr_assert(0);
2699 return -1;
2700 }
2701
2702 /*
2703 * The event loop will take care of demux && sending the
2704 * packet, along with any retransmissions.
2705 */
2706 *p_u = u;
2707 *p_retry_config = retry_config;
2708
2709 return 1;
2710}
2711
2712static void home_server_free(void *data)
2713{
2714 home_server_t *home = data;
2715
2716 talloc_free(home);
2717}
2718
2721 .connection_notify = thread_conn_notify,
2722 .request_prioritise = request_prioritise,
2723 .request_mux = request_mux,
2724 .request_demux = request_demux,
2725 .request_conn_release = request_conn_release,
2726 .request_complete = request_complete,
2727 .request_fail = request_fail,
2728 .request_cancel = request_cancel,
2729};
2730
2733 .connection_notify = thread_conn_notify,
2734 .request_prioritise = request_prioritise,
2735 .request_mux = request_replicate_mux,
2736 .request_demux = request_replicate_demux,
2737 .request_conn_release = request_conn_release,
2738 .request_complete = request_complete,
2739 .request_fail = request_fail,
2740 .request_cancel = request_cancel,
2741};
2742
2743/** Instantiate thread data for the submodule.
2744 *
2745 */
2747{
2748 rlm_radius_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
2749 bio_thread_t *thread = talloc_get_type_abort(mctx->thread, bio_thread_t);
2750
2751 thread->ctx.el = mctx->el;
2752 thread->ctx.inst = inst;
2753 thread->ctx.fd_config = inst->fd_config;
2754 thread->ctx.radius_ctx = inst->common_ctx;
2755
2756 switch (inst->mode) {
2759 inst->home_server_lifetime);
2761
2762 default:
2763 /*
2764 * Assign each thread a portion of the available source port range.
2765 */
2766 if (thread->ctx.fd_config.src_port_start) {
2767 uint16_t range = inst->fd_config.src_port_end - inst->fd_config.src_port_start + 1;
2768 thread->num_ports = range / main_config->max_workers;
2769 thread->ctx.fd_config.src_port_start = inst->fd_config.src_port_start + (thread->num_ports * fr_schedule_worker_id());
2770 thread->ctx.fd_config.src_port_end = inst->fd_config.src_port_start + (thread->num_ports * (fr_schedule_worker_id() +1)) - 1;
2771 if (inst->mode != RLM_RADIUS_MODE_XLAT_PROXY) {
2772 thread->connections = talloc_zero_array(thread, connection_t *, thread->num_ports);
2774 }
2775 }
2776
2777 thread->ctx.trunk = trunk_alloc(thread, mctx->el, &io_funcs,
2778 &inst->trunk_conf, inst->name, thread, false, inst->trigger_args);
2779 if (!thread->ctx.trunk) return -1;
2780 return 0;
2781
2783 /*
2784 * Replication trunks use a different set of functions.
2785 */
2786 thread->ctx.trunk = trunk_alloc(thread, mctx->el, &io_replicate_funcs,
2787 &inst->trunk_conf, inst->name, thread, false, inst->trigger_args);
2788 if (!thread->ctx.trunk) return -1;
2789 return 0;
2790
2792 break;
2793 }
2794
2795 /*
2796 * If we have a port range, allocate the source port based
2797 * on the range start, plus the thread ID. This means
2798 * that we can avoid "hunt and peck" attempts to open up
2799 * the source port.
2800 */
2801 if (thread->ctx.fd_config.src_port_start) {
2803 }
2804
2805 /*
2806 * Allocate an unconnected socket for replication.
2807 */
2808 thread->bio.fd = fr_bio_fd_alloc(thread, &thread->ctx.fd_config, 0);
2809 if (!thread->bio.fd) {
2810 PERROR("%s - failed opening socket", inst->name);
2811 return -1;
2812 }
2813
2814 thread->bio.fd->uctx = thread;
2815 thread->ctx.fd_info = fr_bio_fd_info(thread->bio.fd);
2816 fr_assert(thread->ctx.fd_info != NULL);
2817
2818 (void) fr_bio_fd_write_only(thread->bio.fd);
2819
2820 DEBUG("%s - Opened unconnected replication socket %s", inst->name, thread->ctx.fd_info->name);
2821 return 0;
2822}
2823
2825 { .required = true, .single = true, .type = FR_TYPE_COMBO_IP_ADDR },
2826 { .required = true, .single = true, .type = FR_TYPE_UINT16 },
2827 { .required = true, .single = true, .type = FR_TYPE_STRING },
2829};
2830
2831/*
2832 * %replicate.sendto.ipaddr(ipaddr, port, secret)
2833 */
2835 xlat_ctx_t const *xctx,
2836 request_t *request, fr_value_box_list_t *args)
2837{
2838 bio_thread_t *thread = talloc_get_type_abort(xctx->mctx->thread, bio_thread_t);
2839 fr_value_box_t *ipaddr, *port, *secret;
2840 ssize_t packet_len;
2841 uint8_t buffer[4096];
2842 fr_radius_ctx_t radius_ctx;
2845
2846 XLAT_ARGS(args, &ipaddr, &port, &secret);
2847
2848 /*
2849 * Can't change IP address families.
2850 */
2851 if (ipaddr->vb_ip.af != thread->ctx.fd_info->socket.af) {
2852 RPERROR("Invalid destination IP address family in %pV", ipaddr);
2853 return XLAT_ACTION_FAIL;
2854 }
2855
2856 /*
2857 * Warn if we're not replicating accounting data. It likely won't wokr/
2858 */
2859 if (request->packet->code != FR_RADIUS_CODE_ACCOUNTING_REQUEST) {
2860 RWDEBUG("Replication of packets other then Accounting-Request will likely not do what you want.");
2861 }
2862
2863 /*
2864 * Set up various context things.
2865 */
2866 radius_ctx = (fr_radius_ctx_t) {
2867 .secret = secret->vb_strvalue,
2868 .secret_length = secret->vb_length,
2869 .proxy_state = 0,
2870 };
2871
2873 .common = &radius_ctx,
2874 .rand_ctx = (fr_fast_rand_t) {
2875 .a = fr_rand(),
2876 .b = fr_rand(),
2877 },
2878 .code = request->packet->code,
2879 .id = thread->bio.id++ & 0xff,
2880 .add_proxy_state = false,
2881 };
2882
2883 /*
2884 * Encode the entire packet.
2885 */
2886 packet_len = fr_radius_encode(&FR_DBUFF_TMP(buffer, sizeof(buffer)),
2887 &request->request_pairs, &encode_ctx);
2888 if (packet_len < 0) {
2889 RPERROR("Failed encoding replicated packet");
2890 return XLAT_ACTION_FAIL;
2891 }
2892
2893 /*
2894 * Sign it.
2895 */
2896 if (fr_radius_sign(buffer, NULL, (uint8_t const *) radius_ctx.secret, radius_ctx.secret_length) < 0) {
2897 RPERROR("Failed signing replicated packet");
2898 return XLAT_ACTION_FAIL;
2899 }
2900
2901 /*
2902 * Prepare destination address.
2903 */
2904 addr = (fr_bio_fd_packet_ctx_t) {
2905 .socket = thread->ctx.fd_info->socket,
2906 };
2907 addr.socket.inet.dst_ipaddr = ipaddr->vb_ip;
2908 addr.socket.inet.dst_port = port->vb_uint16;
2909
2910 RDEBUG("Replicating packet to %pV:%u", ipaddr, port->vb_uint16);
2911
2912 /*
2913 * We either send it, or fail.
2914 */
2915 packet_len = fr_bio_write(thread->bio.fd, &addr, buffer, packet_len);
2916 if (packet_len < 0) {
2917 RPERROR("Failed replicating packet to %pV:%u", ipaddr, port->vb_uint16);
2918 return XLAT_ACTION_FAIL;
2919 }
2920
2921 /*
2922 * No return value.
2923 */
2924 return XLAT_ACTION_DONE;
2925}
2926
2927// **********************************************************************
2928
2929/** Dynamic home server code
2930 *
2931 */
2932
2933static fr_cmp_ret_t home_server_cmp(void const *one, void const *two)
2934{
2935 home_server_t const *a = one;
2936 home_server_t const *b = two;
2937 fr_cmp_ret_t rcode;
2938
2940 if (rcode != 0) return rcode;
2941
2943}
2944
2946 xlat_ctx_t const *xctx,
2947 request_t *request, UNUSED fr_value_box_list_t *in)
2948{
2949 bio_request_t *u = talloc_get_type_abort(xctx->rctx, bio_request_t);
2950 fr_value_box_t *dst;
2951
2952 if (u->rcode == RLM_MODULE_FAIL) return XLAT_ACTION_FAIL;
2953
2955 dst->vb_uint32 = request->reply->code;
2956
2957 fr_dcursor_append(out, dst);
2958
2959 return XLAT_ACTION_DONE;
2960}
2961
2962static void xlat_sendto_signal(xlat_ctx_t const *xctx, request_t *request, fr_signal_t action)
2963{
2964 rlm_radius_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_radius_t);
2965 bio_request_t *u = talloc_get_type_abort(xctx->rctx, bio_request_t);
2966
2967 do_signal(inst, u, request, action);
2968}
2969
2970/*
2971 * @todo - change this to mod_retry
2972 */
2973static void xlat_sendto_retry(xlat_ctx_t const *xctx, request_t *request, fr_retry_t const *retry)
2974{
2975 rlm_radius_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_radius_t);
2976 bio_request_t *u = talloc_get_type_abort(xctx->rctx, bio_request_t);
2977
2978 do_retry(inst, u, request, retry);
2979}
2980
2981/*
2982 * %proxy.sendto.ipaddr(ipaddr, port, secret)
2983 */
2985 xlat_ctx_t const *xctx,
2986 request_t *request, fr_value_box_list_t *args)
2987{
2988 rlm_radius_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_radius_t);
2989 bio_thread_t *thread = talloc_get_type_abort(xctx->mctx->thread, bio_thread_t);
2990 fr_value_box_t *ipaddr, *port, *secret;
2991 home_server_t *home;
2992 bio_request_t *u = NULL;
2993 fr_retry_config_t const *retry_config = NULL;
2994 int rcode;
2995
2996 XLAT_ARGS(args, &ipaddr, &port, &secret);
2997
2998 /*
2999 * Can't change IP address families.
3000 */
3001 if (ipaddr->vb_ip.af != thread->ctx.fd_config.src_ipaddr.af) {
3002 RDEBUG("Invalid destination IP address family in %pV", ipaddr);
3003 return XLAT_ACTION_DONE;
3004 }
3005
3006 fr_rb_find((void **)&home, &thread->bio.expires.tree, &(home_server_t) {
3007 .ctx = {
3008 .fd_config = (fr_bio_fd_config_t) {
3009 .dst_ipaddr = ipaddr->vb_ip,
3010 .dst_port = port->vb_uint16,
3011 },
3012 },
3013 });
3014 if (!home) {
3015 /*
3016 * Track which connections are made to this home server from which open ports.
3017 */
3018 MEM(home = (home_server_t *) talloc_zero_array(thread, uint8_t, sizeof(home_server_t) + sizeof(connection_t *) * thread->num_ports));
3019 talloc_set_type(home, home_server_t);
3020
3021 *home = (home_server_t) {
3022 .ctx = (bio_handle_ctx_t) {
3023 .el = unlang_interpret_event_list(request),
3024 .module_name = inst->name,
3025 .inst = inst,
3026 .limit_source_ports = (thread->num_ports > 0) ? LIMIT_PORTS_DYNAMIC : LIMIT_PORTS_NONE,
3027 .dynamic = true,
3028 },
3029 .num_ports = thread->num_ports,
3030 };
3031
3032 /*
3033 * Copy the home server configuration from the thread configuration. Then update it with
3034 * the needs of the home server.
3035 */
3036 home->ctx.fd_config = thread->ctx.fd_config;
3037 home->ctx.fd_config.type = FR_BIO_FD_CONNECTED;
3038 home->ctx.fd_config.dst_ipaddr = ipaddr->vb_ip;
3039 home->ctx.fd_config.dst_port = port->vb_uint32;
3040
3041 home->ctx.radius_ctx = (fr_radius_ctx_t) {
3042 .secret = talloc_strdup(home, secret->vb_strvalue),
3043 .secret_length = secret->vb_length,
3044 .proxy_state = inst->common_ctx.proxy_state,
3045 };
3046
3047 /*
3048 * Allocate the trunk and start it up.
3049 */
3050 home->ctx.trunk = trunk_alloc(home, unlang_interpret_event_list(request), &io_funcs,
3051 &inst->trunk_conf, inst->name, home, false, inst->trigger_args);
3052 if (!home->ctx.trunk) {
3053 fail:
3054 talloc_free(home);
3055 return XLAT_ACTION_FAIL;
3056 }
3057
3058 if (!fr_rb_expire_insert(&thread->bio.expires, home, fr_time())) goto fail;
3059 } else {
3060 fr_rb_expire_t *expire = &thread->bio.expires;
3061 fr_time_t now = fr_time();
3062 home_server_t *old;
3063
3064 /*
3065 * We can't change secrets on the fly. The home
3066 * server has to expire first, and then the
3067 * secret can be changed.
3068 */
3069 if ((home->ctx.radius_ctx.secret_length != secret->vb_length) ||
3070 (strcmp(home->ctx.radius_ctx.secret, secret->vb_strvalue) != 0)) {
3071 RWDEBUG("The new secret is not the same as the old secret: Ignoring the new one");
3072 }
3073
3074 fr_rb_expire_update(expire, home, now);
3075
3076 while ((old = fr_dlist_head(&expire->head)) != NULL) {
3077 (void) talloc_get_type_abort(old, home_server_t);
3078
3079 fr_assert(old->ctx.trunk);
3080
3081 /*
3082 * Don't delete the home server we're about to use.
3083 */
3084 if (old == home) break;
3085
3086 /*
3087 * It still has a request allocated, do nothing.
3088 */
3089 if (old->ctx.trunk->req_alloc) break;
3090
3091 /*
3092 * Not yet time to expire.
3093 */
3094 if (fr_time_gt(old->expire.when, now)) break;
3095
3096 fr_dlist_remove(&expire->head, old);
3097 fr_rb_delete(&expire->tree, old);
3098 }
3099 }
3100
3101 /*
3102 * Enqueue the packet on the per-home-server trunk.
3103 */
3104 rcode = mod_enqueue(&u, &retry_config, inst, home->ctx.trunk, request);
3105 if (rcode == 0) return XLAT_ACTION_DONE;
3106
3107 if (rcode < 0) {
3108 REDEBUG("Failed enqueuing packet");
3109 return XLAT_ACTION_FAIL;
3110 }
3111 fr_assert(u != NULL);
3112 fr_assert(retry_config != NULL);
3113
3114 /*
3115 * Start the retry.
3116 *
3117 * @todo - change unlang_xlat_timeout_add() to unlang_xlat_retry_add().
3118 */
3119 fr_retry_init(&u->retry, fr_time(), retry_config);
3120
3123 u, retry_config);
3124}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
static int const char char buffer[256]
Definition acutest.h:576
int const char * file
Definition acutest.h:702
va_list args
Definition acutest.h:770
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
#define NDEBUG_UNUSED
Definition build.h:395
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:391
#define CC_NO_UBSAN(_sanitize)
Definition build.h:503
#define CMP_PREFER_LARGER(_a, _b)
Evaluates to -1 for a > b, and +1 for a < b.
Definition build.h:109
#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:113
#define unlikely(_x)
Definition build.h:455
#define UNUSED
Definition build.h:384
connection_state_t
Definition connection.h:47
@ CONNECTION_STATE_FAILED
Connection has failed.
Definition connection.h:56
@ CONNECTION_STATE_CONNECTED
File descriptor is open (ready for writing).
Definition connection.h:54
@ CONNECTION_STATE_INIT
Init state, sets up connection.
Definition connection.h:51
@ CONNECTION_STATE_CONNECTING
Waiting for connection to establish.
Definition connection.h:52
@ CONNECTION_FAILED
Connection is being reconnected because it failed.
Definition connection.h:89
Holds a complete set of functions for a connection.
Definition connection.h:199
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:522
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:243
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition debug.h:249
#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_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:2867
static fr_slen_t in
Definition dict.h:882
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
Definition dwarf.c:424
Definition dwarf.c:563
#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
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:1198
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:971
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:1295
int fr_bio_fd_write_only(fr_bio_t *bio)
Mark up a bio as write-only.
Definition fd.c:1342
fr_socket_t socket
as connected socket
Definition fd.h:127
char const * name
printable name of this BIO
Definition fd.h:132
uint16_t src_port
our port
Definition fd.h:86
bool eof
are we at EOF?
Definition fd.h:136
@ 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
fr_bio_fd_type_t type
type of the socket
Definition fd.h:129
fr_bio_fd_state_t state
connecting, open, closed, etc.
Definition fd.h:130
uint16_t src_port_start
limit source port ranges for client BIOs
Definition fd.h:89
@ FR_BIO_FD_STATE_CONNECTING
Definition fd.h:55
@ FR_BIO_FD_STATE_OPEN
error states must be before this
Definition fd.h:54
int connect_errno
from connect() or other APIs
Definition fd.h:138
fr_ipaddr_t dst_ipaddr
their IP address
Definition fd.h:84
uint16_t src_port_end
limit source port ranges for client BIOs
Definition fd.h:90
int socket_type
SOCK_STREAM or SOCK_DGRAM.
Definition fd.h:78
uint16_t dst_port
their port
Definition fd.h:87
fr_socket_t socket
socket information, including FD.
Definition fd.h:47
bool write_blocked
did we block on write?
Definition fd.h:135
fr_ipaddr_t src_ipaddr
our IP address
Definition fd.h:83
Configuration for sockets.
Definition fd.h:75
Run-time status of the socket.
Definition fd.h:126
Per-packet context.
Definition fd.h:46
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_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:2008
unlang_t const * unlang_interpret_instruction(request_t *request)
Get the current instruction.
Definition interpret.c:327
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:2538
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:902
void log_request_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a fr_pair_list_t.
Definition log.c:828
#define PERROR(_fmt,...)
Definition log.h: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:740
#define RHEXDUMP3(_data, _len, _fmt,...)
Definition log.h:722
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:1534
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:1814
#define fr_time()
Definition event.c:60
Stores all information relating to an event list.
Definition event.c:377
fr_log_t default_log
Definition log.c:306
#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:63
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:729
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:906
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
fr_cmp_ret_t
Result of an ordering comparison.
Definition misc.h:50
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:2575
fr_bio_fd_config_t fd_config
for threads or sockets
Definition bio.c:49
struct bio_handle_t::@209 bio
int num_ports
Definition bio.c:146
static void do_retry(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_retry_t const *retry)
Definition bio.c:1564
fr_timer_t * ev
timer for retransmissions
Definition bio.c:137
static void request_replicate_mux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Definition bio.c:2252
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:345
static void request_demux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Definition bio.c:2064
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:1043
uint8_t id
Last ID assigned to this packet.
Definition bio.c:131
static void request_replicate_demux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Definition bio.c:2270
uint32_t max_packet_size
Our max packet size. may be different from the parent.
Definition bio.c:90
static void do_signal(rlm_radius_t const *inst, bio_request_t *u, request_t *request, fr_signal_t action)
bool dynamic
is this a dynamic home server.
Definition bio.c:53
static void bio_connected(fr_bio_t *bio)
Definition bio.c:636
uint32_t num_replies
number of reply packets, sent is in retry.count
Definition bio.c:123
static const trunk_io_funcs_t io_funcs
Definition bio.c:2719
static void conn_close(UNUSED fr_event_list_t *el, void *handle, void *uctx)
Shutdown/close a file descriptor.
Definition bio.c:917
bio_limit_ports_t
Definition bio.c:38
@ LIMIT_PORTS_DYNAMIC
Limited source ports for dynamic home servers.
Definition bio.c:41
@ LIMIT_PORTS_NONE
Source port not restricted.
Definition bio.c:39
@ LIMIT_PORTS_STATIC
Limited source ports for static home servers.
Definition bio.c:40
uint32_t priority
copied from request->async->priority
Definition bio.c:120
static rlm_rcode_t radius_code_to_rcode[FR_RADIUS_CODE_MAX]
Turn a reply code into a module rcode;.
Definition bio.c:154
unlang_t const * instruction
Instruction which triggered the start of the zombie period.
Definition bio.c:104
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:1078
char const * module_name
the module that opened the connection
Definition bio.c:45
fr_bio_fd_info_t const * fd_info
status of the FD.
Definition bio.c:50
connection_t * connections[]
for tracking outbound connections
Definition bio.c:147
static void mod_signal(module_ctx_t const *mctx, UNUSED request_t *request, fr_signal_t action)
Definition bio.c:2496
uint8_t last_id
Used when replicating to ensure IDs are distributed evenly.
Definition bio.c:87
static void mod_retry(module_ctx_t const *mctx, request_t *request, fr_retry_t const *retry)
Handle module retries.
Definition bio.c:1556
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:1198
static void thread_conn_notify(trunk_connection_t *tconn, connection_t *conn, fr_event_list_t *el, trunk_connection_event_t notify_on, UNUSED void *uctx)
Definition bio.c:1090
static int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id)
Definition bio.c:1265
fr_time_t last_reply
When we last received a reply.
Definition bio.c:98
static void request_conn_release(connection_t *conn, void *preq_to_reset, UNUSED void *uctx)
Clear out anything associated with the handle from the request.
Definition bio.c:2422
int fd
File descriptor.
Definition bio.c:77
bio_request_t * status_u
for sending status check packets
Definition bio.c:107
bio_handle_ctx_t ctx
common struct for home servers and BIO handles
Definition bio.c:57
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:655
static void mod_write(request_t *request, trunk_request_t *treq, bio_handle_t *h)
Definition bio.c:1666
#define REQUIRE_MA(_h)
fr_pair_list_t extra
VPs for debugging, like Proxy-State.
Definition bio.c:128
bool proxied
is this request being proxied
Definition bio.c:126
size_t buflen
Receive buffer length.
Definition bio.c:93
static void conn_init_readable(fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
Read the connection during the init and negotiation stage.
Definition bio.c:428
fr_time_t last_idle
last time we had nothing to do
Definition bio.c:101
static fr_cmp_ret_t request_prioritise(void const *one, void const *two)
Definition bio.c:1159
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:197
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:2834
radius_track_entry_t * rr
ID tracking, resend count, etc.
Definition bio.c:136
size_t packet_len
Length of the packet.
Definition bio.c:133
static int _bio_handle_free(bio_handle_t *h)
Free a connection handle, closing associated resources.
Definition bio.c:619
size_t partial
partially sent data
Definition bio.c:134
fr_event_list_t * el
Event list.
Definition bio.c:47
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:2390
static void home_server_free(void *data)
Definition bio.c:2712
int num_ports
Definition bio.c:65
static void protocol_error_reply(bio_request_t *u, bio_handle_t *h)
Deal with Protocol-Error replies, and possible negotiation.
Definition bio.c:1886
static void status_check_reset(bio_handle_t *h, bio_request_t *u)
Reset a status_check packet, ready to reuse.
Definition bio.c:233
static const trunk_io_funcs_t io_replicate_funcs
Definition bio.c:2731
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:2444
fr_time_t recv_time
copied from request->async->recv_time
Definition bio.c:121
fr_retry_t retry
retransmission timers
Definition bio.c:138
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:2984
struct bio_thread_t::@208 bio
rlm_rcode_t rcode
from the transport
Definition bio.c:117
static void status_check_alloc(bio_handle_t *h)
Definition bio.c:250
fr_time_t mrs_time
Most recent sent time which had a reply.
Definition bio.c:97
bool status_checking
whether we're doing status checks
Definition bio.c:106
trunk_t * trunk
trunk handler
Definition bio.c:48
fr_time_t last_sent
last time we sent a packet.
Definition bio.c:100
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:1374
bio_handle_ctx_t ctx
for copying to bio_handle_t
Definition bio.c:142
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Instantiate thread data for the submodule.
Definition bio.c:2746
static void bio_error(fr_bio_t *bio)
Definition bio.c:645
static void status_check_reply(trunk_request_t *treq, fr_time_t now)
Deal with replies replies to status checks and possible negotiation.
Definition bio.c:2016
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:1447
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:414
bool is_retry
Definition bio.c:118
static int _bio_request_free(bio_request_t *u)
Free a bio_request_t.
Definition bio.c:2554
connection_t * conn
Definition bio.c:85
fr_time_t first_sent
first time we sent a packet since going idle
Definition bio.c:99
static 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:2484
fr_timer_t * zombie_ev
Zombie timeout.
Definition bio.c:103
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:1014
static void xlat_sendto_retry(xlat_ctx_t const *xctx, request_t *request, fr_retry_t const *retry)
Definition bio.c:2973
static void bio_request_reset(bio_request_t *u)
Clear out any connection specific resources from a udp request.
Definition bio.c:216
trunk_request_t * treq
Definition bio.c:116
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:2945
static void status_check_next(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
Handle retries for a status check.
Definition bio.c:2001
rlm_radius_t const * inst
our instance
Definition bio.c:46
static connection_state_t conn_init(void **h_out, connection_t *conn, void *uctx)
Initialise a new outbound connection.
Definition bio.c:730
connection_t ** connections
Definition bio.c:66
fr_rb_expire_node_t expire
Definition bio.c:144
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:1362
uint8_t * packet
Packet we write to the network.
Definition bio.c:132
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:366
static connection_state_t conn_failed(void *handle, connection_state_t state, UNUSED void *uctx)
Connection failed.
Definition bio.c:987
bio_limit_ports_t limit_source_ports
What type of port limit is in use.
Definition bio.c:52
fr_radius_ctx_t radius_ctx
for signing packets
Definition bio.c:51
radius_track_t * tt
RADIUS ID tracking structure.
Definition bio.c:95
static void mod_dup(request_t *request, bio_request_t *u)
Definition bio.c:1520
bio_handle_ctx_t ctx
common struct for home servers and BIO handles
Definition bio.c:75
uint8_t code
Packet code.
Definition bio.c:130
static void request_mux(UNUSED fr_event_list_t *el, trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Definition bio.c:1647
static fr_cmp_ret_t home_server_cmp(void const *one, void const *two)
Dynamic home server code.
Definition bio.c:2933
uint8_t * buffer
Receive buffer.
Definition bio.c:92
request_t * status_request
Definition bio.c:108
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:2466
bool status_check
is this packet a status check?
Definition bio.c:125
static xlat_arg_parser_t const xlat_radius_send_args[]
Definition bio.c:2824
static void xlat_sendto_signal(xlat_ctx_t const *xctx, request_t *request, fr_signal_t action)
Definition bio.c:2962
Track the handle, which is tightly correlated with the FD.
Definition bio.c:74
Connect request_t to local tracking structure.
Definition bio.c:115
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition nbo.h:146
#define RADIUS_HEADER_LENGTH
Definition net.h:80
#define RADIUS_AUTH_VECTOR_LENGTH
Definition net.h:89
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition pair.c:2962
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
Definition pair.c:2663
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:1352
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:1696
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:290
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
static fr_internal_encode_ctx_t encode_ctx
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:1178
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:1028
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:63
@ 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
#define RADIUS_AUTH_VECTOR_OFFSET
Definition radius.h:33
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
@ FR_RADIUS_FAIL_UNKNOWN_PACKET_CODE
Definition radius.h:95
char const * secret
Definition radius.h:127
size_t secret_length
Definition radius.h:128
fr_radius_ctx_t const * common
Definition radius.h:159
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:104
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
#define RETURN_UNLANG_RCODE(_rcode)
Definition rcode.h:61
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 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:517
static fr_dict_attr_t const * attr_nas_identifier
Definition rlm_radius.c:194
static fr_dict_attr_t const * attr_original_packet_code
Definition rlm_radius.c:195
static fr_dict_attr_t const * attr_event_timestamp
Definition rlm_radius.c:190
static fr_dict_attr_t const * attr_response_length
Definition rlm_radius.c:196
fr_radius_require_ma_t require_message_authenticator
Require Message-Authenticator in responses.
Definition rlm_radius.h:75
fr_time_delta_t revive_interval
Definition rlm_radius.h:60
bool track_load_balance
do we track load-balance state
Definition rlm_radius.h:77
fr_retry_config_t retry[FR_RADIUS_CODE_MAX]
Definition rlm_radius.h:88
char const * name
Definition rlm_radius.h:56
uint32_t status_check
code of status-check type
Definition rlm_radius.h:80
rlm_radius_mode_t mode
proxy, client, etc.
Definition rlm_radius.h:71
@ RLM_RADIUS_MODE_XLAT_PROXY
radius.sendto.ipaddr(), but we do look for a reply.
Definition rlm_radius.h:47
@ RLM_RADIUS_MODE_INVALID
Definition rlm_radius.h:42
@ RLM_RADIUS_MODE_PROXY
we proxy to one home server
Definition rlm_radius.h:43
@ RLM_RADIUS_MODE_REPLICATE
to a particular destination
Definition rlm_radius.h:45
@ RLM_RADIUS_MODE_UNCONNECTED_REPLICATE
radius.sendto.ipaddr(), but we don't look for a reply
Definition rlm_radius.h:46
@ RLM_RADIUS_MODE_CLIENT
we are a client to one home server
Definition rlm_radius.h:44
uint32_t max_packet_size
Maximum packet size.
Definition rlm_radius.h:66
fr_time_delta_t response_window
Definition rlm_radius.h:58
uint32_t max_attributes
Maximum number of attributes to decode in response.
Definition rlm_radius.h:73
fr_time_delta_t zombie_period
Definition rlm_radius.h:59
fr_bio_fd_config_t fd_config
for now MUST be at the start!
Definition rlm_radius.h:54
static conf_parser_t retry_config[]
Definition rlm_tacacs.c:38
int fr_schedule_worker_id(void)
Return the worker id for the current thread.
Definition schedule.c:110
void connection_signal_reconnect(connection_t *conn, connection_reason_t reason)
Asynchronously signal the connection should be reconnected.
int connection_signal_on_fd(connection_t *conn, int fd)
Setup the connection to change states to connected or failed based on I/O events.
connection_t * connection_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, connection_funcs_t const *funcs, connection_conf_t const *conf, char const *log_prefix, void const *uctx)
Allocate a new connection.
void connection_signal_connected(connection_t *conn)
Asynchronously signal that the connection is open.
void * data
Module's instance data.
Definition module.h:293
#define pair_append_request(_attr, _da)
Allocate and append a fr_pair_t to the request list.
Definition pair.h:37
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_DUP
A duplicate request was received.
Definition signal.h:44
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
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
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define talloc_get_type_abort_const
Definition talloc.h:117
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:288
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
void * state
Definition testlib.c:46
#define fr_time_gteq(_a, _b)
Definition time.h:238
#define fr_time_wrap(_time)
Definition time.h:145
#define fr_time_lteq(_a, _b)
Definition time.h:240
#define fr_time_eq(_a, _b)
Definition time.h:241
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
#define fr_time_gt(_a, _b)
Definition time.h:237
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition time.h:229
static fr_unix_time_t fr_time_to_unix_time(fr_time_t when)
Convert an fr_time_t (internal time) to our version of unix time (wallclock time)
Definition time.h:688
static int8_t fr_time_cmp(fr_time_t a, fr_time_t b)
Compare two fr_time_t values.
Definition time.h:916
"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:103
#define FR_TIMER_DELETE_RETURN(_ev_p)
Definition timer.h:110
#define FR_TIMER_DISARM(_ev)
Definition timer.h:91
static bool fr_timer_armed(fr_timer_t *ev)
Definition timer.h:120
#define fr_timer_at(...)
Definition timer.h:81
void radius_track_state_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line, radius_track_t *tt, radius_track_log_extra_t extra)
Print out the state of every tracking entry.
Definition track.c: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
#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_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
trunk_cancel_reason_t
Reasons for a request being cancelled.
Definition trunk.h:55
@ TRUNK_CANCEL_REASON_REQUEUE
A previously sent request is being requeued.
Definition trunk.h:59
@ TRUNK_ENQUEUE_DST_UNAVAILABLE
Destination is down.
Definition trunk.h: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
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
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition xlat.h:384
unsigned int required
Argument must be present, and non-empty.
Definition xlat.h:147
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:171
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumed by an xlat function.
Definition xlat.h:146
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
@ FR_RETRY_MRC
reached maximum retransmission count
Definition retry.h:47
@ FR_RETRY_CONTINUE
Definition retry.h:46
@ FR_RETRY_MRD
reached maximum retransmission duration
Definition retry.h:48
uint32_t count
number of sent packets
Definition retry.h:58
fr_time_delta_t mrd
Maximum retransmission duration.
Definition retry.h:35
fr_time_t updated
last update, really a cached "now".
Definition retry.h:56
fr_time_t next
when the next timer should be set
Definition retry.h:55
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h: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:644
#define fr_box_ipaddr(_val)
Definition value.h:317
static fr_slen_t data
Definition value.h:1340
#define fr_box_time_delta(_val)
Definition value.h:366
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1030
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