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