The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
master.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
5 * (at 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: cd389c337a25a3aff3191013008e22badc9d192a $
19 * @file io/master.c
20 * @brief Master IO handler
21 *
22 * @copyright 2018 Alan DeKok (aland@freeradius.org)
23 */
24#include <freeradius-devel/io/listen.h>
25#include <freeradius-devel/io/master.h>
26
27#include <freeradius-devel/server/base.h>
28#include <freeradius-devel/server/module.h>
29#include <freeradius-devel/util/debug.h>
30
31#include <freeradius-devel/util/misc.h>
32#include <freeradius-devel/util/syserror.h>
33
34typedef struct {
35 fr_event_list_t *el; //!< event list, for the master socket.
36 fr_network_t *nr; //!< network for the master socket
37
38 fr_trie_t *trie; //!< trie of clients
39 fr_heap_t *pending_clients; //!< heap of pending clients
40 fr_heap_t *alive_clients; //!< heap of active clients
41
42 fr_listen_t *listen; //!< The master IO path
43 fr_listen_t *child; //!< The child (app_io) IO path
44 fr_schedule_t *sc; //!< the scheduler
45
46 // @todo - count num_nak_clients, and num_nak_connections, too
47 uint32_t num_connections; //!< number of dynamic connections
48 uint32_t num_pending_packets; //!< number of pending packets
49 uint64_t client_id; //!< Unique client identifier.
51
52/** A saved packet
53 *
54 */
63
64
65/** Client states
66 *
67 */
68typedef enum {
70 PR_CLIENT_STATIC, //!< static / global clients
71 PR_CLIENT_NAK, //!< negative cache entry
72 PR_CLIENT_DYNAMIC, //!< dynamically defined client
73 PR_CLIENT_CONNECTED, //!< dynamically defined client in a connected socket
74 PR_CLIENT_PENDING, //!< dynamic client pending definition
76
77/*
78 * Dynamic clients are run through the normal src/process/foo state machine.
79 *
80 * request->async->packet_ctx is an fr_io_track_t
81 *
82 * track->dynamic is set to a non-zero value.
83 *
84 * The dynamic client code returns a buffer of 1 byte for a NAK.
85 *
86 * If the client creation is successful, then it does talloc(NULL, fr_client_t),
87 * fills out the structure, and sends the pointer in the buffer (8 bytes).
88 *
89 * This code will take over ownership of the structure, and
90 * create the dynamic client.
91 */
92
94
95/** Client definitions for master IO
96 *
97 */
99 fr_io_connection_t *connection; //!< parent connection
100 fr_io_client_state_t state; //!< state of this client
101 fr_ipaddr_t src_ipaddr; //!< packets come from this address
102 fr_ipaddr_t network; //!< network for dynamic clients
103 fr_client_t *radclient; //!< old-style definition of this client
104
105 int packets; //!< number of packets using this client
106 fr_heap_index_t pending_id; //!< for pending clients
107 fr_heap_index_t alive_id; //!< for all clients
108
109 bool use_connected; //!< does this client allow connected sub-sockets?
110 bool ready_to_delete; //!< are we ready to delete this client?
111 bool in_trie; //!< is the client in the trie?
112
113 fr_io_instance_t const *inst; //!< parent instance for master IO handler
115 fr_event_timer_t const *ev; //!< when we clean up the client
116 fr_rb_tree_t *table; //!< tracking table for packets
117
118 fr_heap_t *pending; //!< pending packets for this client
119 fr_hash_table_t *addresses; //!< list of src/dst addresses used by this client
120
121 pthread_mutex_t mutex; //!< for parent / child signaling
122 fr_hash_table_t *ht; //!< for tracking connected sockets
123};
124
125/** Track a connection
126 *
127 * This structure contains information about the connection,
128 * a pointer to the library instance so that we can clean up on exit,
129 * and the listener.
130 *
131 * It also points to a client structure which is for this connection,
132 * and only this connection.
133 *
134 * Finally, a pointer to the parent client, so that the child can
135 * tell the parent it's alive, and the parent can push packets to the
136 * child.
137 */
139 char const *name; //!< taken from proto_FOO_TRANSPORT
140 int packets; //!< number of packets using this connection
141 fr_io_address_t *address; //!< full information about the connection.
142 fr_listen_t *listen; //!< master listener for this socket
143 fr_listen_t *child; //!< child listener (app_io) for this socket
144 fr_io_client_t *client; //!< our local client (pending or connected).
145 fr_io_client_t *parent; //!< points to the parent client.
146 module_instance_t *mi; //!< for submodule
147
148 bool dead; //!< roundabout way to get the network side to close a socket
149 bool paused; //!< event filter doesn't like resuming something that isn't paused
150 bool in_parent_hash; //!< for tracking thread issues
151 fr_event_list_t *el; //!< event list for this connection
152 fr_network_t *nr; //!< network for this connection
153};
154
157 { 0 }
158};
159
162 { 0 }
163};
164
165static int track_free(fr_io_track_t *track)
166{
167 if (track->ev) (void) fr_event_timer_delete(&track->ev);
168
169 talloc_free_children(track);
170
171 fr_assert(track->client->packets > 0);
172 track->client->packets--;
173
174 return 0;
175}
176
178{
179 fr_assert(track->client->table != NULL);
180 fr_assert(fr_rb_find(track->client->table, track) != NULL);
181
182 if (!fr_rb_delete(track->client->table, track)) {
183 fr_assert(0);
184 }
185
186 return track_free(track);
187}
188
189/*
190 * Return negative numbers to put 'one' at the top of the heap.
191 * Return positive numbers to put 'two' at the top of the heap.
192 */
193static int8_t pending_packet_cmp(void const *one, void const *two)
194{
197 int ret;
198
199 /*
200 * Higher priority elements are larger than lower
201 * priority elements. So if "a" is larger than "b", we
202 * wish to prefer "a".
203 */
204 ret = CMP_PREFER_LARGER(a->priority, b->priority);
205 if (ret != 0) return ret;
206
207 /*
208 * Smaller numbers mean packets were received earlier.
209 * We want to process packets in time order. So if "a"
210 * is smaller than "b", we wish to prefer "a".
211 *
212 * After that, it doesn't really matter what order the
213 * packets go in. Since we'll never have two identical
214 * "recv_time" values, the code should never get here.
215 */
217}
218
219/*
220 * Order clients in the pending_clients heap, based on the
221 * packets that they contain.
222 */
223static int8_t pending_client_cmp(void const *one, void const *two)
224{
225 fr_io_pending_packet_t const *a;
226 fr_io_pending_packet_t const *b;
227
230
231 a = fr_heap_peek(c1->pending);
232 b = fr_heap_peek(c2->pending);
233
234 fr_assert(a != NULL);
235 fr_assert(b != NULL);
236
237 return pending_packet_cmp(a, b);
238}
239
240
241static int8_t address_cmp(void const *one, void const *two)
242{
245 int8_t ret;
246
247 CMP_RETURN(a, b, socket.inet.src_port);
248 CMP_RETURN(a, b, socket.inet.dst_port);
249 CMP_RETURN(a, b, socket.inet.ifindex);
250
251 ret = fr_ipaddr_cmp(&a->socket.inet.src_ipaddr, &b->socket.inet.src_ipaddr);
252 if (ret != 0) return ret;
253
254 return fr_ipaddr_cmp(&a->socket.inet.dst_ipaddr, &b->socket.inet.dst_ipaddr);
255}
256
257static uint32_t connection_hash(void const *ctx)
258{
261
262 hash = fr_hash(&c->address->socket.inet.src_ipaddr, sizeof(c->address->socket.inet.src_ipaddr));
263 hash = fr_hash_update(&c->address->socket.inet.src_port, sizeof(c->address->socket.inet.src_port), hash);
264
265 hash = fr_hash_update(&c->address->socket.inet.ifindex, sizeof(c->address->socket.inet.ifindex), hash);
266
267 hash = fr_hash_update(&c->address->socket.inet.dst_ipaddr, sizeof(c->address->socket.inet.dst_ipaddr), hash);
268 return fr_hash_update(&c->address->socket.inet.dst_port, sizeof(c->address->socket.inet.dst_port), hash);
269}
270
271static int8_t connection_cmp(void const *one, void const *two)
272{
275
276 return address_cmp(a->address, b->address);
277}
278
279
280static int8_t track_cmp(void const *one, void const *two)
281{
284 int ret;
285
286 fr_assert(a->client != NULL);
287 fr_assert(b->client != NULL);
288 fr_assert(a->client == b->client); /* tables are per-client */
289
292
293 /*
294 * Unconnected sockets must check src/dst ip/port.
295 */
296 ret = address_cmp(a->address, b->address);
297 if (ret != 0) return ret;
298
299 /*
300 * Call the per-protocol comparison function.
301 */
304 a->client->radclient,
305 a->packet, b->packet);
306 return CMP(ret, 0);
307}
308
309
310static int8_t track_connected_cmp(void const *one, void const *two)
311{
314 int ret;
315
316 fr_assert(a->client != NULL);
317 fr_assert(b->client != NULL);
318
321 fr_assert(a->client == b->client);
323
324 /*
325 * Note that we pass the connection "client", as
326 * we may do negotiation specific to this connection.
327 */
331 a->packet, b->packet);
332 return CMP(ret, 0);
333}
334
335
337{
338 fr_io_client_t *client;
339 fr_io_pending_packet_t *pending;
340
341 client = fr_heap_pop(&thread->pending_clients);
342 if (!client) {
343 /*
344 * 99% of the time we don't have pending clients.
345 * So we might as well free this, so that the
346 * caller doesn't keep checking us for every packet.
347 */
349 thread->pending_clients = NULL;
350 return NULL;
351 }
352
353 pending = fr_heap_pop(&client->pending);
354 fr_assert(pending != NULL);
355
356 /*
357 * If the client has more packets pending, add it back to
358 * the heap.
359 */
360 if (fr_heap_num_elements(client->pending) > 0) {
361 if (fr_heap_insert(&thread->pending_clients, client) < 0) {
362 fr_assert(0 == 1);
363 }
364 }
365
366 fr_assert(thread->num_pending_packets > 0);
367 thread->num_pending_packets--;
368
369 return pending;
370}
371
372static fr_client_t *radclient_clone(TALLOC_CTX *ctx, fr_client_t const *parent)
373{
374 fr_client_t *c;
375
376 if (!parent) return NULL;
377
378 c = talloc_zero(ctx, fr_client_t);
379 if (!c) return NULL;
380
381 /*
382 * Do NOT set ipaddr or src_ipaddr. The caller MUST do this!
383 */
384
385#define DUP_FIELD(_x) do { if (parent->_x) {c->_x = talloc_strdup(c, parent->_x); if (!c->_x) {goto error;}}} while (0)
386#define COPY_FIELD(_x) c->_x = parent->_x
387
388 DUP_FIELD(longname);
389 DUP_FIELD(shortname);
391 DUP_FIELD(nas_type);
392 DUP_FIELD(server);
393 DUP_FIELD(nas_type);
394
395 COPY_FIELD(require_message_authenticator);
396 COPY_FIELD(require_message_authenticator_is_set);
397 COPY_FIELD(limit_proxy_state);
398 COPY_FIELD(limit_proxy_state_is_set);
399 COPY_FIELD(received_message_authenticator);
400 COPY_FIELD(first_packet_no_proxy_state);
401 /* dynamic MUST be false */
402 COPY_FIELD(server_cs);
403 COPY_FIELD(cs);
404 COPY_FIELD(proto);
405 COPY_FIELD(active);
406
407 COPY_FIELD(use_connected);
408
409#ifdef WITH_TLS
410 COPY_FIELD(tls_required);
411#endif
412
413 c->ipaddr = parent->ipaddr;
414 c->src_ipaddr = parent->src_ipaddr;
415
416 return c;
417
418 /*
419 * @todo - fill in other fields, too!
420 */
421
422error:
423 talloc_free(c);
424 return NULL;
425}
426#undef COPY_FIELD
427#undef DUP_FIELD
428
429
430/** Count the number of connections used by active clients.
431 *
432 * Unfortunately, we also count NAK'd connections, too, even if they
433 * are closed. The alternative is to walk through all connections
434 * for each client, which would be a long time.
435 */
436static int count_connections(UNUSED uint8_t const *key, UNUSED size_t keylen, void *data, void *ctx)
437{
438 fr_io_client_t *client = talloc_get_type_abort(data, fr_io_client_t);
439 int connections;
440
441 pthread_mutex_lock(&client->mutex);
442
443 if (!client->ht) {
444 pthread_mutex_unlock(&client->mutex);
445 return 0;
446 }
447
448 connections = fr_hash_table_num_elements(client->ht);
449 pthread_mutex_unlock(&client->mutex);
450
451 fr_assert(client->use_connected);
452 *((uint32_t *) ctx) += connections;
453
454 return 0;
455}
456
457
458static int _client_free(fr_io_client_t *client)
459{
460 TALLOC_FREE(client->pending);
461
462 return 0;
463}
464
465static int connection_free(fr_io_connection_t *connection)
466{
467 /*
468 * This is it's own talloc context, as there are
469 * thousands of packets associated with it.
470 */
471 TALLOC_FREE(connection->client);
472
473 return 0;
474}
475
476/** Create a new connection.
477 *
478 * Called ONLY from the master socket.
479 */
481 fr_io_thread_t *thread,
482 fr_io_client_t *client, int fd,
483 fr_io_address_t *address,
485{
486 int ret;
487 fr_io_connection_t *connection;
488 module_instance_t *mi = NULL;
489 fr_listen_t *li;
490 fr_client_t *radclient;
491
492 /*
493 * Reload the app_io module as a "new" library. This
494 * causes the link count for the library to be correct.
495 * It also allocates a new instance data for it, too.
496 * Passing CONF_SECTION of NULL ensures that there's no
497 * config for it, as we'll just clone it's contents from
498 * the original. It also means that detach should be
499 * called when the instance data is freed.
500 */
501 if (!nak) {
502 CONF_SECTION *cs;
503 char *inst_name;
504
505 if (inst->max_connections || client->radclient->limit.max_connections) {
506 uint32_t max_connections = inst->max_connections ? inst->max_connections : client->radclient->limit.max_connections;
507
508 /*
509 * We've hit the connection limit. Walk
510 * over all clients with connections, and
511 * count the number of connections used.
512 */
513 if (thread->num_connections >= max_connections) {
514 thread->num_connections = 0;
515
516 (void) fr_trie_walk(thread->trie, &thread->num_connections, count_connections);
517
518 if ((thread->num_connections + 1) >= max_connections) {
519 DEBUG("proto_%s - Ignoring connection from client %s - 'max_connections' limit reached.",
520 inst->app->common.name, client->radclient->shortname);
521 if (fd >= 0) close(fd);
522 return NULL;
523 }
524 }
525 }
526
527 /*
528 * Add a client module into a sublist
529 */
530 inst_name = talloc_asprintf(NULL, "%"PRIu64, thread->client_id++);
531 mi = module_instance_copy(inst->clients, inst->submodule, inst_name);
532
533 cs = cf_section_dup(mi, NULL, inst->submodule->conf,
534 cf_section_name1(inst->submodule->conf),
535 cf_section_name2(inst->submodule->conf), false);
536 if (module_instance_conf_parse(mi, cs) < 0) {
537 cf_log_err(inst->server_cs, "Failed parsing module config");
538 goto cleanup;
539 }
540
541 /* Thread local module lists never run bootstrap */
542 if (module_instantiate(mi) < 0) {
543 cf_log_err(inst->server_cs, "Failed instantiating module");
544 goto cleanup;
545 }
546
547 if (module_thread_instantiate(mi, mi, thread->el) < 0) {
548 cf_log_err(inst->server_cs, "Failed instantiating module");
549 goto cleanup;
550 }
551
552 /*
553 * FIXME - Instantiate the new module?!
554 */
555 talloc_free(inst_name);
556 fr_assert(mi != NULL);
557 } else {
558 mi = talloc_init_const("nak");
559 }
560
561 MEM(connection = talloc_zero(mi, fr_io_connection_t));
562 MEM(connection->address = talloc_memdup(connection, address, sizeof(*address)));
563 (void) talloc_set_name_const(connection->address, "fr_io_address_t");
564
565 connection->parent = client;
566 connection->mi = mi;
567
568 MEM(connection->client = talloc_named(NULL, sizeof(fr_io_client_t), "fr_io_client_t"));
569 memset(connection->client, 0, sizeof(*connection->client));
570
571 MEM(connection->client->radclient = radclient = radclient_clone(connection->client, client->radclient));
572
573 talloc_set_destructor(connection->client, _client_free);
574 talloc_set_destructor(connection, connection_free);
575
578 connection->client->connection = connection;
579
580 /*
581 * Create the packet tracking table for this client.
582 *
583 * #todo - unify the code with static clients?
584 */
585 if (inst->app_io->track_duplicates) {
586 MEM(connection->client->table = fr_rb_inline_talloc_alloc(client, fr_io_track_t, node,
587 track_connected_cmp, NULL));
588 }
589
590 /*
591 * Set this radclient to be dynamic, and active.
592 */
593 radclient->dynamic = true;
594 radclient->active = true;
595
596 /*
597 * address->socket.inet.client points to a "static" client. We want
598 * to clean up everything associated with the connection
599 * when it closes. So we need to point to our own copy
600 * of the client here.
601 */
602 connection->address->radclient = connection->client->radclient;
603 connection->client->inst = inst;
604 connection->client->thread = thread;
605
606 /*
607 * Create a heap for packets which are pending for this
608 * client.
609 */
610 MEM(connection->client->pending = fr_heap_alloc(connection->client, pending_packet_cmp,
611 fr_io_pending_packet_t, heap_id, 0));
612
613 /*
614 * Clients for connected sockets are always a /32 or /128.
615 */
616 connection->client->src_ipaddr = address->socket.inet.src_ipaddr;
617 connection->client->network = address->socket.inet.src_ipaddr;
618
619 /*
620 * Don't initialize mutex or hash table.
621 * Connections cannot spawn other connections.
622 */
623
624 /*
625 * If this client state is pending, then the connection
626 * state is pending, too. That allows NAT gateways to be
627 * defined dynamically, AND for them to have multiple
628 * connections, each with a different client. This
629 * allows for different shared secrets to be used for
630 * different connections. Once the client gets defined
631 * for this connection, it will be either "connected" or
632 * not. If connected, then the parent client remains
633 * PENDING. Otherwise, the parent client is moved to
634 * DYNAMIC
635 *
636 * If this client state is static or dynamic,
637 * then we're just using connected sockets behind
638 * that client. The connections here all use the
639 * same shared secret, but they use different
640 * sockets, so they allow for sharing of IO
641 * across CPUs / threads.
642 */
643 switch (client->state) {
645 connection->client->state = PR_CLIENT_PENDING;
646
647 /*
648 * Needed for rlm_radius, which refuses to proxy packets
649 * that define a dynamic client.
650 */
651 radclient->active = false;
652 break;
653
654 case PR_CLIENT_STATIC:
656 connection->client->state = PR_CLIENT_CONNECTED;
657 break;
658
660 case PR_CLIENT_NAK:
662 fr_assert(0 == 1);
663 goto cleanup;
664 }
665
666 if (!nak) {
667 /*
668 * Get the child listener.
669 */
670 MEM(li = connection->child = talloc(connection, fr_listen_t));
671 memcpy(li, thread->listen, sizeof(*li));
672
673 /*
674 * Glue in the actual app_io
675 */
676 li->connected = true;
677 li->app_io = thread->child->app_io;
678 li->thread_instance = connection;
679 li->app_io_instance = mi->data;
681
682 /*
683 * Create writable thread instance data.
684 */
685 connection->child->thread_instance = talloc_zero_array(NULL, uint8_t,
686 inst->app_io->common.thread_inst_size);
687 talloc_set_destructor(connection->child, fr_io_listen_free);
688 talloc_set_name(connection->child->thread_instance, "proto_%s_thread_t",
689 inst->app_io->common.name);
690
691 /*
692 * This is "const", and the user can't
693 * touch it. So we just reuse the same
694 * configuration everywhere.
695 */
696 connection->child->app_io_instance = inst->app_io_instance;
697
698 /*
699 * Create the listener, based on our listener.
700 */
701 MEM(li = connection->listen = talloc(connection, fr_listen_t));
702
703 /*
704 * Note that our instance is effectively 'const'.
705 *
706 * i.e. we can't add things to it. Instead, we have to
707 * put all variable data into the connection.
708 */
709 memcpy(li, thread->listen, sizeof(*li));
710
711 /*
712 * Glue in the connection to the listener.
713 */
715
716 li->connected = true;
717 li->thread_instance = connection;
720
721 /*
722 * Instantiate the child, and open the socket.
723 */
724 fr_assert(inst->app_io->connection_set != NULL);
725
726 if (inst->app_io->connection_set(connection->child, connection->address) < 0) {
727 DEBUG("proto_%s - Failed setting connection for socket.", inst->app->common.name);
728 goto cleanup;
729 }
730
731 /*
732 * UDP sockets: open a new socket, and then
733 * connect it to the client. This emulates the
734 * behavior of accept().
735 *
736 * Note that there is a small window between the
737 * bind() and connect() where UDP packets for the
738 * wildcard socket can get received by this
739 * socket. We hope that this time frame is as
740 * small as possible.
741 *
742 * i.e. we ignore the problem, and don't
743 * currently check dst ip/port for UDP packets
744 * received on connected sockets.
745 */
746 if (fd < 0) {
747 socklen_t salen;
748 struct sockaddr_storage src;
749
750 if (fr_ipaddr_to_sockaddr(&src, &salen,
751 &connection->address->socket.inet.src_ipaddr,
752 connection->address->socket.inet.src_port) < 0) {
753 DEBUG("proto_%s - Failed getting IP address", inst->app->common.name);
754 talloc_free(mi);
755 return NULL;
756 }
757
758 if (inst->app_io->open(connection->child) < 0) {
759 DEBUG("proto_%s - Failed opening connected socket.", inst->app->common.name);
760 talloc_free(mi);
761 return NULL;
762 }
763
764 fd = connection->child->fd;
765
766 if (connect(fd, (struct sockaddr *) &src, salen) < 0) {
767 ERROR("proto_%s - Failed in connect: %s", inst->app->common.name, fr_syserror(errno));
768 goto cleanup;
769 }
770 } else {
771 connection->child->fd = fd;
772 }
773
774 /*
775 * Set the new FD, and get the module to set it's connection name.
776 */
777 if (inst->app_io->fd_set(connection->child, fd) < 0) {
778 DEBUG3("Failed setting FD to %s", inst->app_io->common.name);
779 goto cleanup;
780 }
781
782 li->fd = fd;
783
784 if (!inst->app_io->get_name) {
785 connection->name = fr_asprintf(connection, "proto_%s from client %pV port "
786 "%u to server %pV port %u",
787 inst->app->common.name,
788 fr_box_ipaddr(connection->address->socket.inet.src_ipaddr),
789 connection->address->socket.inet.src_port,
790 fr_box_ipaddr(connection->address->socket.inet.dst_ipaddr),
791 connection->address->socket.inet.dst_port);
792 } else {
793 connection->name = inst->app_io->get_name(connection->child);
794 }
795
796 /*
797 * Set the names for the listeners.
798 */
799 connection->listen->name = connection->name;
800 connection->child->name = connection->name;
801 }
802
803 /*
804 * Add the connection to the set of connections for this
805 * client.
806 */
807 pthread_mutex_lock(&client->mutex);
808 if (client->ht) {
809 if (nak) (void) fr_hash_table_delete(client->ht, nak);
810 ret = fr_hash_table_insert(client->ht, connection);
811 client->ready_to_delete = false;
812 connection->in_parent_hash = true;
813
814 if (!ret) {
815 pthread_mutex_unlock(&client->mutex);
816 ERROR("proto_%s - Failed inserting connection into tracking table. "
817 "Closing it, and discarding all packets for connection %s.",
818 inst->app_io->common.name, connection->name);
819 goto cleanup;
820 }
821 }
822 pthread_mutex_unlock(&client->mutex);
823
824 /*
825 * It's a NAK client. Set the state to NAK, and don't
826 * add it to the scheduler.
827 */
828 if (nak) {
829 connection->name = talloc_strdup(connection, nak->name);
830 connection->client->state = PR_CLIENT_NAK;
831 connection->el = nak->el;
832 return connection;
833 }
834
835 DEBUG("proto_%s - starting connection %s", inst->app_io->common.name, connection->name);
836 connection->nr = fr_schedule_listen_add(thread->sc, connection->listen);
837 if (!connection->nr) {
838 ERROR("proto_%s - Failed inserting connection into scheduler. "
839 "Closing it, and diuscarding all packets for connection %s.",
840 inst->app_io->common.name, connection->name);
841 pthread_mutex_lock(&client->mutex);
842 if (client->ht) (void) fr_hash_table_delete(client->ht, connection);
843 pthread_mutex_unlock(&client->mutex);
844
845 cleanup:
846 if (fd >= 0) close(fd);
847 talloc_free(mi);
848 return NULL;
849 }
850
851 /*
852 * We have one more connection. Note that we do
853 * NOT decrement this counter when a connection
854 * closes, as the close is done in a child
855 * thread. Instead, we just let counter hit the
856 * limit, and then walk over the clients to reset
857 * the count.
858 */
859 thread->num_connections++;
860
861 return connection;
862}
863
864
865/*
866 * And here we go into the rabbit hole...
867 *
868 * @todo future - have a similar structure
869 * fr_io_connection_io, which will duplicate some code,
870 * but may make things simpler?
871 */
872static void get_inst(fr_listen_t *li, fr_io_instance_t const **inst, fr_io_thread_t **thread,
873 fr_io_connection_t **connection, fr_listen_t **child)
874{
875 if (!li->connected) {
876 *inst = li->app_io_instance;
877 if (thread) *thread = li->thread_instance;
878 *connection = NULL;
879 if (child) *child = ((fr_io_thread_t *)li->thread_instance)->child;
880
881 } else {
882 fr_assert(connection != NULL);
883
884 *connection = li->thread_instance;
885 *inst = (*connection)->client->inst;
886 if (thread) *thread = NULL;
887 if (child) *child = (*connection)->child;
888 }
889}
890
891
892static fr_client_t *radclient_alloc(TALLOC_CTX *ctx, int ipproto, fr_io_address_t *address)
893{
894 fr_client_t *radclient;
895 char *shortname;
896
897 MEM(radclient = talloc_zero(ctx, fr_client_t));
898
899 fr_value_box_aprint(radclient, &shortname, fr_box_ipaddr(address->socket.inet.src_ipaddr), NULL);
900 radclient->longname = radclient->shortname = shortname;
901
902 radclient->secret = radclient->nas_type = talloc_strdup(radclient, "");
903
904 radclient->ipaddr = address->socket.inet.src_ipaddr;
905
906 radclient->src_ipaddr = address->socket.inet.dst_ipaddr;
907
908 radclient->proto = ipproto;
909 radclient->dynamic = true;
910
911 return radclient;
912}
913
914/*
915 * Remove a client from the list of "live" clients.
916 *
917 * This function is only used for the "main" socket. Clients
918 * from connections do not use it.
919 */
921{
922 talloc_get_type_abort(client, fr_io_client_t);
923
924 fr_assert(client->in_trie);
925 fr_assert(!client->connection);
926 fr_assert(client->thread);
927
928 if (client->pending) TALLOC_FREE(client->pending);
929
930 (void) fr_trie_remove_by_key(client->thread->trie, &client->src_ipaddr.addr, client->src_ipaddr.prefix);
931
932 if (client->thread->alive_clients) {
934 (void) fr_heap_extract(&client->thread->alive_clients, client);
935 }
936
937 return 0;
938}
939
940static fr_io_client_t *client_alloc(TALLOC_CTX *ctx, fr_io_client_state_t state,
941 fr_io_instance_t const *inst, fr_io_thread_t *thread, fr_client_t *radclient,
942 fr_ipaddr_t const *network)
943{
944 fr_io_client_t *client;
945
946 /*
947 * Create our own local client. This client
948 * holds our state which really shouldn't go into
949 * fr_client_t.
950 *
951 * Note that we create a new top-level talloc
952 * context for this client, as there may be tens
953 * of thousands of packets associated with this
954 * client. And we want to avoid problems with
955 * O(N) issues in talloc.
956 */
957 MEM(client = talloc_named(ctx, sizeof(fr_io_client_t), "fr_io_client_t"));
958 memset(client, 0, sizeof(*client));
959
960 client->state = state;
961 client->src_ipaddr = radclient->ipaddr;
962 client->radclient = radclient;
963 client->inst = inst;
964 client->thread = thread;
965
966 if (network) {
967 client->network = *network;
968 } else {
969 client->network = client->src_ipaddr;
970 }
971
972 /*
973 * At this point, this variable can only be true
974 * for STATIC clients. PENDING clients may set
975 * it to true later, after they've been defined.
976 */
977 client->use_connected = radclient->use_connected;
978
979 /*
980 * Create the pending heap for pending clients.
981 */
982 if (state == PR_CLIENT_PENDING) {
984 fr_io_pending_packet_t, heap_id, 0));
985 }
986
987 /*
988 * Create the packet tracking table for this client.
989 */
990 if (inst->app_io->track_duplicates) {
991 fr_assert(inst->app_io->track_compare != NULL);
992 MEM(client->table = fr_rb_inline_talloc_alloc(client, fr_io_track_t, node, track_cmp, NULL));
993 }
994
995 /*
996 * Allow connected sockets to be set on a
997 * per-client basis.
998 */
999 if (client->use_connected) {
1000 fr_assert(client->state == PR_CLIENT_STATIC);
1001
1002 (void) pthread_mutex_init(&client->mutex, NULL);
1003 MEM(client->ht = fr_hash_table_alloc(client, connection_hash, connection_cmp, NULL));
1004 }
1005
1006 /*
1007 * Add the newly defined client to the trie of
1008 * allowed clients.
1009 */
1010 if (fr_trie_insert_by_key(thread->trie, &client->src_ipaddr.addr, client->src_ipaddr.prefix, client)) {
1011 ERROR("proto_%s - Failed inserting client %s into tracking table. Discarding client, and all packets for it.",
1012 inst->app_io->common.name, client->radclient->shortname);
1013 talloc_free(client);
1014 return NULL;
1015 }
1016
1017 client->in_trie = true;
1018
1019 /*
1020 * Track the live clients so that we can clean
1021 * them up.
1022 */
1023 (void) fr_heap_insert(&thread->alive_clients, client);
1025
1026 /*
1027 * Now that we've inserted it into the heap and
1028 * incremented the numbers, set the destructor
1029 * function.
1030 */
1031 talloc_set_destructor(client, _client_live_free);
1032
1033 return client;
1034}
1035
1036
1038 fr_io_address_t *address,
1039 uint8_t const *packet, size_t packet_len,
1040 fr_time_t recv_time, bool *is_dup)
1041{
1042 size_t len;
1043 fr_io_track_t *track, *old;
1044 fr_io_address_t *my_address;
1045
1046 *is_dup = false;
1047
1048 /*
1049 * Allocate a new tracking structure. Most of the time
1050 * there are no duplicates, so this is fine.
1051 */
1052 MEM(track = talloc_zero_pooled_object(client, fr_io_track_t, 1, sizeof(*track) + sizeof(track->address) + 64));
1053 MEM(track->address = my_address = talloc_zero(track, fr_io_address_t));
1054
1055 memcpy(my_address, address, sizeof(*address));
1056 my_address->radclient = client->radclient;
1057
1058 track->client = client;
1059 if (client->connection) {
1060 track->address = client->connection->address;
1061 }
1062
1063 track->timestamp = recv_time;
1064 track->packets = 1;
1065
1066 /*
1067 * We're not tracking duplicates, so just return the
1068 * tracking entry. This tracks src/dst IP/port, client,
1069 * receive time, etc.
1070 */
1071 if (!client->inst->app_io->track_duplicates) {
1072 client->packets++;
1073 talloc_set_destructor(track, track_free);
1074 return track;
1075 }
1076
1077 /*
1078 * We are checking for duplicates, see if there is a dup
1079 * already in the tree.
1080 */
1081 track->packet = client->inst->app_io->track_create(client->inst->app_io_instance,
1082 client->thread->child->thread_instance,
1083 client->radclient,
1084 track, packet, packet_len);
1085 if (!track->packet) {
1086 talloc_free(track);
1087 return NULL;
1088 }
1089
1090 /*
1091 * No existing duplicate. Return the new tracking entry.
1092 */
1093 old = fr_rb_find(client->table, track);
1094 if (!old) goto do_insert;
1095
1096 fr_assert(old->client == client);
1097
1098 /*
1099 * It cannot be both in the free list and in the tracking table.
1100 *
1101 * 2020-08-17, this assertion fails randomly in travis.
1102 * Which means that "track" was in the free list, *and*
1103 * in the rbtree.
1104 */
1105 fr_assert(old != track);
1106
1107 /*
1108 * The new packet has the same dedup fields as the old
1109 * one, BUT it may be a conflicting packet. Check for
1110 * that via a simple memcmp().
1111 *
1112 * It's an exact duplicate. Drop the new one and
1113 * use the old one.
1114 *
1115 * If there's a cached reply, the caller will take care
1116 * of sending it to the network layer.
1117 */
1118 len = talloc_array_length(old->packet);
1119 if ((len == talloc_array_length(track->packet)) &&
1120 (memcmp(old->packet, track->packet, len) == 0)) {
1121 fr_assert(old != track);
1122
1123 /*
1124 * Ignore duplicates while the client is
1125 * still pending.
1126 */
1127 if (client->state == PR_CLIENT_PENDING) {
1128 DEBUG("Ignoring duplicate packet while client %s is still pending dynamic definition",
1129 client->radclient->shortname);
1130 return NULL;
1131 }
1132
1133 *is_dup = true;
1134 old->packets++;
1135 talloc_free(track);
1136
1137 /*
1138 * Retransmits can sit in the outbound queue for
1139 * a while. We don't want to time out this
1140 * struct while the packet is in the outbound
1141 * queue.
1142 */
1143 if (old->ev) (void) fr_event_timer_delete(&old->ev);
1144 return old;
1145 }
1146
1147 /*
1148 * Else it's a conflicting packet. Which is OK if we
1149 * already have a reply. We just delete the old entry,
1150 * and insert the new one.
1151 *
1152 * If there's no reply, then the old request is still
1153 * "live". Delete the old one from the tracking tree,
1154 * and return the new one.
1155 */
1156 if (old->reply_len || old->do_not_respond) {
1157 talloc_free(old);
1158
1159 } else {
1160 fr_assert(client == old->client);
1161
1162 if (!fr_rb_delete(client->table, old)) {
1163 fr_assert(0);
1164 }
1165 if (old->ev) (void) fr_event_timer_delete(&old->ev);
1166
1167 talloc_set_destructor(old, track_free);
1168
1169 old->discard = true; /* don't send any reply, there's nowhere for it to go */
1170 }
1171
1172do_insert:
1173 if (!fr_rb_insert(client->table, track)) {
1174 fr_assert(0);
1175 }
1176
1177 client->packets++;
1178 talloc_set_destructor(track, track_dedup_free);
1179 return track;
1180}
1181
1182
1184{
1185 fr_io_track_t *track = pending->track;
1186
1187 /*
1188 * Note that we don't check timestamps, replies, etc. If
1189 * a packet is pending, then any conflicting packet gets
1190 * the "pending" entry marked as such, and a new entry
1191 * added. Any duplicate packet gets suppressed. And
1192 * because the packets are pending, track->reply MUST be
1193 * NULL.
1194 */
1195 fr_assert(track->packets > 0);
1196 track->packets--;
1197
1198 /*
1199 * No more packets using this tracking entry,
1200 * delete it.
1201 */
1202 if (track->packets == 0) talloc_free(track);
1203
1204 return 0;
1205}
1206
1208 uint8_t const *buffer, size_t packet_len,
1209 fr_io_track_t *track,
1210 int priority)
1211{
1212 fr_io_pending_packet_t *pending;
1213
1214 MEM(pending = talloc_zero(client->pending, fr_io_pending_packet_t));
1215
1216 MEM(pending->buffer = talloc_memdup(pending, buffer, packet_len));
1217 pending->buffer_len = packet_len;
1218 pending->priority = priority;
1219 pending->track = track;
1220 pending->recv_time = track->timestamp; /* there can only be one */
1221
1222 talloc_set_destructor(pending, pending_free);
1223
1224 /*
1225 * Insert the pending packet for this client. If it
1226 * fails, silently discard the packet.
1227 */
1228 if (fr_heap_insert(&client->pending, pending) < 0) {
1229 talloc_free(pending);
1230 return NULL;
1231 }
1232
1233 /*
1234 * We only track pending packets for the
1235 * main socket. For connected sockets,
1236 * we pause the FD, so the number of
1237 * pending packets will always be small.
1238 */
1239 if (!client->connection) client->thread->num_pending_packets++;
1240
1241 return pending;
1242}
1243
1244
1245/*
1246 * Order clients in the alive_clients heap, based on their IP
1247 * address.
1248 *
1249 * This function is only used for the "main" socket. Clients
1250 * from connections do not use it.
1251 */
1252static int8_t alive_client_cmp(void const *one, void const *two)
1253{
1256
1257 return fr_ipaddr_cmp(&a->src_ipaddr, &b->src_ipaddr);
1258}
1259
1260/** Implement 99% of the read routines.
1261 *
1262 * The app_io->read does the transport-specific data read.
1263 */
1264static ssize_t mod_read(fr_listen_t *li, void **packet_ctx, fr_time_t *recv_time_p,
1265 uint8_t *buffer, size_t buffer_len, size_t *leftover)
1266{
1267 fr_io_instance_t const *inst;
1268 fr_io_thread_t *thread;
1269 ssize_t packet_len = -1;
1270 fr_time_t recv_time = fr_time_wrap(0);
1271 fr_io_client_t *client;
1272 fr_io_address_t address;
1273 fr_io_connection_t my_connection, *connection;
1274 fr_io_pending_packet_t *pending;
1275 fr_io_track_t *track;
1276 fr_listen_t *child;
1277 int value, accept_fd = -1;
1278 uint32_t priority = PRIORITY_NORMAL;
1279
1280 get_inst(li, &inst, &thread, &connection, &child);
1281
1282 track = NULL;
1283
1284 /*
1285 * There was data left over from the previous read, go
1286 * get the rest of it now. We MUST do this instead of
1287 * popping a pending packet, because the leftover bytes
1288 * are already in the output buffer.
1289 */
1290 if (*leftover) goto do_read;
1291
1292redo:
1293 /*
1294 * Read one pending packet. The packet may be pending
1295 * because of dynamic client definitions, or because it's
1296 * for a connected UDP socket, and was sent over by the
1297 * "master" UDP socket.
1298 */
1299 if (connection) {
1300 /*
1301 * The connection is dead. Tell the network side
1302 * to close it.
1303 */
1304 if (connection->dead) {
1305 DEBUG("Dead connection %s", connection->name);
1306 return -1;
1307 }
1308
1309 pending = fr_heap_pop(&connection->client->pending);
1310
1311 } else if (thread->pending_clients) {
1312 pending = pending_packet_pop(thread);
1313
1314 } else {
1315 pending = NULL;
1316 }
1317
1318 if (pending) {
1319 fr_assert(buffer_len >= pending->buffer_len);
1320 track = pending->track;
1321
1322 /*
1323 * Clear the destructor as we now own the
1324 * tracking entry.
1325 */
1326 talloc_set_destructor(pending, NULL);
1327
1328 /*
1329 * We received a conflicting packet while this
1330 * packet was pending. Discard this entry and
1331 * try to get another one.
1332 *
1333 * Note that the pending heap is *simple*. We
1334 * just track priority and recv_time. This means
1335 * it's fast, but also that it's hard to look up
1336 * random packets in the pending heap.
1337 */
1338 if (fr_time_neq(pending->recv_time, track->timestamp)) {
1339 DEBUG3("Discarding old packet");
1340 talloc_free(pending);
1341 goto redo;
1342 }
1343
1344 /*
1345 * We have a valid packet. Copy it over to the
1346 * caller, and return.
1347 */
1348 *packet_ctx = track;
1349 *leftover = 0;
1350 recv_time = *recv_time_p = pending->recv_time;
1351 client = track->client;
1352
1353 memcpy(buffer, pending->buffer, pending->buffer_len);
1354 packet_len = pending->buffer_len;
1355
1356 /*
1357 * Shouldn't be necessary, but what the heck...
1358 */
1359 memcpy(&address, track->address, sizeof(address));
1360 talloc_free(pending);
1361
1362 /*
1363 * Skip over all kinds of logic to find /
1364 * allocate the client, when we don't need to do
1365 * it any more.
1366 */
1367 goto have_client;
1368
1369 } else if (!connection && (inst->ipproto == IPPROTO_TCP)) {
1370 struct sockaddr_storage saremote;
1371 socklen_t salen;
1372
1373 salen = sizeof(saremote);
1374
1375 /*
1376 * We're a TCP socket but are NOT connected. We
1377 * must be the master socket. Accept the new
1378 * connection, and figure out src/dst IP/port.
1379 */
1380 accept_fd = accept(child->fd,
1381 (struct sockaddr *) &saremote, &salen);
1382
1383 /*
1384 * Couldn't open a NEW socket, but THIS ONE is
1385 * OK. So don't return -1.
1386 */
1387 if (accept_fd < 0) {
1388 DEBUG("proto_%s - failed to accept new socket: %s",
1389 inst->app->common.name, fr_syserror(errno));
1390 return 0;
1391 }
1392
1393 /*
1394 * Set the new descriptor to be non-blocking.
1395 */
1396 (void) fr_nonblock(accept_fd);
1397
1398#ifdef STATIC_ANALYZER
1399 saremote.ss_family = AF_INET; /* static analyzer doesn't know that accept() initializes this */
1400#endif
1401
1402 /*
1403 * Get IP addresses only if we have IP addresses.
1404 */
1405 if ((saremote.ss_family == AF_INET) || (saremote.ss_family == AF_INET6)) {
1406 memset(&address.socket, 0, sizeof(address.socket));
1407 (void) fr_ipaddr_from_sockaddr(&address.socket.inet.src_ipaddr, &address.socket.inet.src_port,
1408 &saremote, salen);
1409 salen = sizeof(saremote);
1410
1411 /*
1412 * @todo - only if the local listen address is "*".
1413 */
1414 (void) getsockname(accept_fd, (struct sockaddr *) &saremote, &salen);
1415 (void) fr_ipaddr_from_sockaddr(&address.socket.inet.dst_ipaddr, &address.socket.inet.dst_port,
1416 &saremote, salen);
1417 address.socket.type = (inst->ipproto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
1418 address.socket.fd = accept_fd;
1419 }
1420
1421 } else {
1422 fr_io_address_t *local_address;
1423
1424 /*
1425 * We're either not a TCP socket, or we are a
1426 * connected TCP socket. Just read it.
1427 */
1428do_read:
1429 local_address = &address;
1430
1431 /*
1432 * @todo - For connected TCP sockets which are
1433 * dynamically defined, the app_io read()
1434 * function should stop reading the socket if the
1435 * server is busy. That change puts TCP
1436 * backpressure on the client.
1437 *
1438 * @todo TLS - for TLS and dynamic sockets, do
1439 * the SSL setup here, but have a structure which
1440 * describes the TLS data and run THAT through
1441 * the dynamic client definition, instead of
1442 * using normal packets. Or, rely on the app_io
1443 * read() function to do all TLS work? Given
1444 * that some protocols have "starttls" beginning
1445 * after a clear-text exchange, it's likely best
1446 * to have yet another layer of trampoline
1447 * functions which do all of the TLS work.
1448 */
1449 packet_len = inst->app_io->read(child, (void **) &local_address, &recv_time,
1450 buffer, buffer_len, leftover);
1451 if (packet_len <= 0) {
1452 return packet_len;
1453 }
1454
1455 /*
1456 * Not allowed? Discard it. The priority()
1457 * function has done any complaining, if
1458 * necessary.
1459 */
1460 if (inst->app->priority) {
1461 value = inst->app->priority(inst->app_instance, buffer, packet_len);
1462 if (value <= 0) {
1463
1464 /*
1465 * @todo - unix sockets. We need to use
1466 * the "name" of the socket, in the
1467 * listener?
1468 */
1469 DEBUG2("proto_%s - ignoring packet from IP %pV. It is not configured as 'type = ...'",
1470 inst->app_io->common.name, fr_box_ipaddr(address.socket.inet.src_ipaddr));
1471 return 0;
1472 }
1473 priority = value;
1474 }
1475
1476 /*
1477 * If the connection is pending, pause reading of
1478 * more packets. If mod_write() accepts the
1479 * connection, it will resume reading.
1480 * Otherwise, it will close the socket without
1481 * resuming it.
1482 */
1483 if (connection &&
1484 (connection->client->state == PR_CLIENT_PENDING)) {
1485 fr_assert(!connection->paused);
1486
1487 connection->paused = true;
1488 (void) fr_event_filter_update(connection->el,
1489 child->fd,
1491 }
1492 }
1493
1494 /*
1495 * Look up the client, unless we already have one (for a
1496 * connected socket).
1497 */
1498 if (!connection) {
1499 client = fr_trie_lookup_by_key(thread->trie,
1500 &address.socket.inet.src_ipaddr.addr, address.socket.inet.src_ipaddr.prefix);
1501 fr_assert(!client || !client->connection);
1502
1503 } else {
1504 client = connection->client;
1505
1506 /*
1507 * We don't care what the read function says
1508 * about address. We have it already.
1509 */
1510 address = *connection->address;
1511 }
1512
1513 /*
1514 * Negative cache entry. Drop the packet.
1515 */
1516 if (client && client->state == PR_CLIENT_NAK) {
1517 if (accept_fd >= 0) close(accept_fd);
1518 return 0;
1519 }
1520
1521 /*
1522 * If there's no client, try to pull one from the global
1523 * / static client list. Or if dynamic clients are
1524 * allowed, try to define a dynamic client.
1525 */
1526 if (!client) {
1527 fr_client_t *radclient = NULL;
1529 fr_ipaddr_t const *network = NULL;
1530
1531 /*
1532 * We MUST be the master socket.
1533 */
1534 fr_assert(!connection);
1535
1536 radclient = inst->app_io->client_find(thread->child, &address.socket.inet.src_ipaddr, inst->ipproto);
1537 if (radclient) {
1538 state = PR_CLIENT_STATIC;
1539
1540 /*
1541 * Make our own copy that we can modify it.
1542 */
1543 MEM(radclient = radclient_clone(thread, radclient));
1544 radclient->active = true;
1545
1546 } else if (inst->dynamic_clients) {
1547 if (inst->max_clients && (fr_heap_num_elements(thread->alive_clients) >= inst->max_clients)) {
1548 if (accept_fd < 0) {
1549 DEBUG("proto_%s - ignoring packet from client IP address %pV - "
1550 "too many dynamic clients are defined",
1551 inst->app_io->common.name, fr_box_ipaddr(address.socket.inet.src_ipaddr));
1552 } else {
1553 DEBUG("proto_%s - ignoring connection attempt from client IP address %pV "
1554 "- too many dynamic clients are defined",
1555 inst->app_io->common.name, fr_box_ipaddr(address.socket.inet.src_ipaddr));
1556 close(accept_fd);
1557 }
1558 return 0;
1559 }
1560
1561 /*
1562 * Look up the allowed networks.
1563 */
1564 network = fr_trie_lookup_by_key(inst->networks, &address.socket.inet.src_ipaddr.addr,
1565 address.socket.inet.src_ipaddr.prefix);
1566 if (!network) {
1567 DEBUG3("Source IP %pV is outside of 'allowed' network range",
1568 fr_box_ipaddr(address.socket.inet.src_ipaddr));
1569 goto ignore;
1570 }
1571
1572 /*
1573 * It exists, but it's a "deny" rule, ignore it.
1574 */
1575 if (network->af == AF_UNSPEC) {
1576 DEBUG3("Source IP %pV is forbidden by the 'deny' network range",
1577 fr_box_ipaddr(address.socket.inet.src_ipaddr));
1578 goto ignore;
1579 }
1580
1581 /*
1582 * Allocate our local radclient as a
1583 * placeholder for the dynamic client.
1584 */
1585 radclient = radclient_alloc(thread, inst->ipproto, &address);
1586 state = PR_CLIENT_PENDING;
1587
1588 } else {
1589 ignore:
1590 if (accept_fd < 0) {
1591 DEBUG("proto_%s - ignoring packet from unknown client IP address %pV",
1592 inst->app_io->common.name, fr_box_ipaddr(address.socket.inet.src_ipaddr));
1593 } else {
1594 DEBUG("proto_%s - ignoring connection attempt from unknown client IP address %pV",
1595 inst->app_io->common.name, fr_box_ipaddr(address.socket.inet.src_ipaddr));
1596 close(accept_fd);
1597 }
1598 return 0;
1599 }
1600
1601 MEM(client = client_alloc(thread, state, inst, thread, radclient, network));
1602 }
1603
1604have_client:
1605 fr_assert(client->state != PR_CLIENT_INVALID);
1606 fr_assert(client->state != PR_CLIENT_NAK);
1607
1608 /*
1609 * We've accepted a new connection. Go allocate it, and
1610 * let it read from the socket.
1611 */
1612 if (accept_fd >= 0) {
1613 if (!fr_io_connection_alloc(inst, thread, client, accept_fd, &address, NULL)) {
1614 DEBUG("Failed to allocate connection from client %s.", client->radclient->shortname);
1615 }
1616
1617 return 0;
1618 }
1619
1620 /*
1621 * No connected sockets, OR we are the connected socket.
1622 *
1623 * Track this packet and return it if necessary.
1624 */
1625 if (connection || !client->use_connected) {
1626 fr_io_track_t *to_free = NULL;
1627
1628 /*
1629 * Add the packet to the tracking table, if it's
1630 * not already there. Pending packets will be in
1631 * the tracking table, but won't be counted as
1632 * "live" packets.
1633 */
1634 if (!track) {
1635 bool is_dup = false;
1636
1637 track = fr_io_track_add(client, &address, buffer, packet_len, recv_time, &is_dup);
1638 if (!track) {
1639 DEBUG("Failed tracking packet from client %s - discarding it",
1640 client->radclient->shortname);
1641 return 0;
1642 }
1643
1644 /*
1645 * If there's a cached reply, just send that and don't do anything else.
1646 */
1647 if (is_dup) {
1648 fr_network_t *nr;
1649
1650 if (track->do_not_respond) {
1651 DEBUG("Ignoring retransmit from client %s - we are not responding to this request", client->radclient->shortname);
1652 return 0;
1653 }
1654
1655 if (!track->reply) {
1656 fr_assert(!track->finished);
1657 DEBUG("Ignoring retransmit from client %s - we are still processing the request", client->radclient->shortname);
1658 return 0;
1659 }
1660
1661 if (connection) {
1662 nr = connection->nr;
1663 } else {
1664 nr = thread->nr;
1665 }
1666
1667 /*
1668 * @todo - mark things up so that we know to keep 'track' around
1669 * until the packet is actually written to the network. OR, add
1670 * a network API so that the talloc_free() function can remove
1671 * the packet from the queue of packets to be retransmitted.
1672 *
1673 * Perhaps via having fr_network_listen_write() return a pointer
1674 * to the localized message, and then caching that in the tracking
1675 * structure.
1676 */
1677 DEBUG("Sending duplicate reply to client %s", client->radclient->shortname);
1678 fr_network_listen_write(nr, li, track->reply, track->reply_len,
1679 track, track->timestamp);
1680 return 0;
1681 }
1682
1683 /*
1684 * Got to free this if we don't process the packet.
1685 */
1686 to_free = track;
1687 }
1688
1689 /*
1690 * This is a pending dynamic client. See if we
1691 * have to either run the dynamic client code to
1692 * define the client, OR to push the packet onto
1693 * the pending queue for this client.
1694 */
1695 if (client->state == PR_CLIENT_PENDING) {
1696 /*
1697 * Track pending packets for the master
1698 * socket. Connected sockets are paused
1699 * as soon as they are defined, so we
1700 * won't be reading any more packets from
1701 * them.
1702 *
1703 * Since we don't have pending packets
1704 * for connected sockets, we don't need
1705 * to track pending packets.
1706 */
1707 if (!connection && inst->max_pending_packets && (thread->num_pending_packets >= inst->max_pending_packets)) {
1708 DEBUG("Too many pending packets for client %pV - discarding packet",
1709 fr_box_ipaddr(client->src_ipaddr));
1710
1711 done:
1712 talloc_free(to_free);
1713 return 0;
1714 }
1715
1716 /*
1717 * Allocate the pending packet structure.
1718 */
1719 pending = fr_io_pending_alloc(client, buffer, packet_len,
1720 track, priority);
1721 if (!pending) {
1722 DEBUG("Failed tracking packet from client %pV - discarding packet", fr_box_ipaddr(client->src_ipaddr));
1723 goto done;
1724 }
1725
1726 if (fr_heap_num_elements(client->pending) > 1) {
1727 DEBUG("Client %pV is still being dynamically defined. "
1728 "Caching this packet until the client has been defined",
1729 fr_box_ipaddr(client->src_ipaddr));
1730 return 0;
1731 }
1732
1733 /*
1734 * Tell this packet that it's defining a
1735 * dynamic client.
1736 */
1737 track->dynamic = recv_time;
1738 }
1739
1740 /*
1741 * Remove all cleanup timers for the client /
1742 * connection. It's still in use, so we don't
1743 * want to clean it up.
1744 */
1745 if (client->ev) {
1746 talloc_const_free(client->ev);
1747 client->ready_to_delete = false;
1748 }
1749
1750 /*
1751 * Return the packet.
1752 */
1753 *recv_time_p = track->timestamp;
1754 *packet_ctx = track;
1755 return packet_len;
1756 }
1757
1758 /*
1759 * This must be the main UDP socket which creates
1760 * connections.
1761 */
1762 fr_assert(inst->ipproto == IPPROTO_UDP);
1763
1764 /*
1765 * We're using connected sockets, but this socket isn't
1766 * connected. It must be the master socket. The master
1767 * can either be STATIC, DYNAMIC, or PENDING. Whatever
1768 * the state, the child socket will take care of handling
1769 * the packet. e.g. dynamic clients, etc.
1770 */
1771 {
1772 bool nak = false;
1773
1774 my_connection.address = &address;
1775
1776 pthread_mutex_lock(&client->mutex);
1777 connection = fr_hash_table_find(client->ht, &my_connection);
1778 if (connection) nak = (connection->client->state == PR_CLIENT_NAK);
1779 pthread_mutex_unlock(&client->mutex);
1780
1781 /*
1782 * The connection is in NAK state, ignore packets
1783 * for it.
1784 */
1785 if (nak) {
1786 DEBUG("Discarding packet to NAKed connection %s", connection->name);
1787 return 0;
1788 }
1789 }
1790
1791 /*
1792 * No existing connection, create one.
1793 */
1794 if (!connection) {
1795 connection = fr_io_connection_alloc(inst, thread, client, -1, &address, NULL);
1796 if (!connection) {
1797 DEBUG("Failed to allocate connection from client %s. Discarding packet.", client->radclient->shortname);
1798 return 0;
1799 }
1800 }
1801
1802 DEBUG("Sending packet to connection %s", connection->name);
1803
1804 /*
1805 * Inject the packet into the connected socket. It will
1806 * process the packet as if it came in from the network.
1807 *
1808 * @todo future - after creating the connection, put the
1809 * current packet into connection->pending, instead of
1810 * inject?, and then call fr_network_listen_read() from
1811 * the child's instantiation routine???
1812 *
1813 * @todo TCP - for ACCEPT sockets, we don't have a
1814 * packet, so don't do this. Instead, the connection
1815 * will take care of figuring out what to do.
1816 *
1817 * We don't need "to_free" after this, as it will be
1818 * tracked in the connected socket.
1819 */
1820 (void) fr_network_listen_inject(connection->nr, connection->listen,
1821 buffer, packet_len, recv_time);
1822 return 0;
1823}
1824
1825/** Inject a packet to a connection.
1826 *
1827 * Always called in the context of the network.
1828 */
1829static int mod_inject(fr_listen_t *li, uint8_t const *buffer, size_t buffer_len, fr_time_t recv_time)
1830{
1831 fr_io_instance_t const *inst;
1832 int priority;
1833 bool is_dup = false;
1834 fr_io_connection_t *connection;
1835 fr_io_pending_packet_t *pending;
1836 fr_io_track_t *track;
1837
1838 get_inst(li, &inst, NULL, &connection, NULL);
1839
1840 if (!connection) {
1841 DEBUG2("Received injected packet for an unconnected socket.");
1842 return -1;
1843 }
1844
1845 priority = inst->app->priority(inst, buffer, buffer_len);
1846 if (priority <= 0) {
1847 return -1;
1848 }
1849
1850 /*
1851 * Track this packet, because that's what mod_read expects.
1852 */
1853 track = fr_io_track_add(connection->client, connection->address,
1854 buffer, buffer_len, recv_time, &is_dup);
1855 if (!track) {
1856 DEBUG2("Failed injecting packet to tracking table");
1857 return -1;
1858 }
1859
1860 talloc_get_type_abort(track, fr_io_track_t);
1861
1862 /*
1863 * @todo future - what to do with duplicates?
1864 */
1865 fr_assert(!is_dup);
1866
1867 /*
1868 * Remember to restore this packet later.
1869 */
1870 pending = fr_io_pending_alloc(connection->client, buffer, buffer_len,
1871 track, priority);
1872 if (!pending) {
1873 DEBUG2("Failed injecting packet due to allocation error");
1874 return -1;
1875 }
1876
1877 return 0;
1878}
1879
1880/** Open a new listener
1881 *
1882 */
1883static int mod_open(fr_listen_t *li)
1884{
1885 fr_io_thread_t *thread;
1886 fr_io_instance_t const *inst;
1887
1888 thread = li->thread_instance;
1889 inst = li->app_io_instance;
1890
1891 if (inst->app_io->open(thread->child) < 0) return -1;
1892
1893 li->fd = thread->child->fd; /* copy this back up */
1894
1895 /*
1896 * Set the name of the socket.
1897 */
1898 if (!li->app_io->get_name) {
1899 li->name = li->app_io->common.name;
1900 } else {
1901 li->name = li->app_io->get_name(li);
1902 }
1903
1904 /*
1905 * Note that we're opening a child socket, so we don't
1906 * put it into the list of global listeners.
1907 */
1908
1909 return 0;
1910}
1911
1912
1913/** Set the event list for a new socket
1914 *
1915 * @param[in] li the listener
1916 * @param[in] el the event list
1917 * @param[in] nr context from the network side
1918 */
1920{
1921 fr_io_instance_t const *inst;
1922 fr_io_connection_t *connection;
1923 fr_io_thread_t *thread;
1924 fr_listen_t *child;
1925
1926 get_inst(li, &inst, &thread, &connection, &child);
1927
1928 /*
1929 * We're not doing IO, so there are no timers for
1930 * cleaning up packets, dynamic clients, or connections.
1931 */
1932 if (!inst->submodule) return;
1933
1934 if (inst->app_io->event_list_set) {
1935 inst->app_io->event_list_set(child, el, nr);
1936 }
1937
1938 /*
1939 * Set event list and network side for this socket.
1940 */
1941 if (!connection) {
1942 thread->el = el;
1943 thread->nr = nr;
1944
1945 } else {
1946 connection->el = el;
1947 connection->nr = nr;
1948 }
1949}
1950
1951
1952static void client_expiry_timer(fr_event_list_t *el, fr_time_t now, void *uctx)
1953{
1954 fr_io_client_t *client = talloc_get_type_abort(uctx, fr_io_client_t);
1955 fr_io_instance_t const *inst;
1956 fr_io_connection_t *connection;
1957 fr_time_delta_t delay;
1958 int connections;
1959
1960 /*
1961 * No event list? We don't need to expire the client.
1962 */
1963 if (!el) return;
1964
1965 // @todo - print out what we plan on doing next
1966 connection = client->connection;
1967 inst = client->inst;
1968
1969 fr_assert(client->state != PR_CLIENT_STATIC);
1970
1971 /*
1972 * Called from the read or write functions with
1973 * now==0, to signal that we have to *set* the timer.
1974 */
1975 if (fr_time_eq(now, fr_time_wrap(0))) {
1976 /*
1977 * The timer is already set, don't do anything.
1978 */
1979 if (client->ev) return;
1980
1981 switch (client->state) {
1983 fr_assert(connection != NULL);
1985
1986 case PR_CLIENT_DYNAMIC:
1987 delay = inst->idle_timeout;
1989 (fr_time_delta_lt(client->radclient->limit.idle_timeout, inst->idle_timeout))) {
1990 delay = client->radclient->limit.idle_timeout;
1991 }
1992 break;
1993
1994 case PR_CLIENT_NAK:
1995 delay = inst->nak_lifetime;
1996 break;
1997
1998 default:
1999 fr_assert(0 == 1);
2000 return;
2001 }
2002
2003 DEBUG("TIMER - setting idle timeout to %pVs for connection from client %s", fr_box_time_delta(delay), client->radclient->shortname);
2004
2005 goto reset_timer;
2006 }
2007
2008 DEBUG("TIMER - checking status of client %s", client->radclient->shortname);
2009
2010 /*
2011 * It's a negative cache entry. Just delete it.
2012 */
2013 if (client->state == PR_CLIENT_NAK) {
2014 DEBUG("proto_%s - deleting NAK client %pV", inst->app_io->common.name, fr_box_ipaddr(client->src_ipaddr));
2015
2016 delete_client:
2017 fr_assert(client->packets == 0);
2018
2019 /*
2020 * It's a connected socket. Remove it from the
2021 * parents list of connections, and delete it.
2022 */
2023 if (connection) {
2024 pthread_mutex_lock(&connection->parent->mutex);
2025 if (connection->in_parent_hash) {
2026 connection->in_parent_hash = false;
2027 (void) fr_hash_table_delete(connection->parent->ht, connection);
2028 }
2029 pthread_mutex_unlock(&connection->parent->mutex);
2030
2031 /*
2032 * Mark the connection as dead, and tell
2033 * the network side to stop reading from
2034 * it.
2035 */
2036 connection->dead = true;
2037 fr_network_listen_read(connection->nr, connection->listen);
2038 return;
2039 }
2040
2041 talloc_free(client);
2042 return;
2043 }
2044
2045 /*
2046 * It's a dynamically defined client. If no one is using
2047 * it, clean it up after an idle timeout.
2048 */
2049 if ((client->state == PR_CLIENT_DYNAMIC) ||
2050 (client->state == PR_CLIENT_CONNECTED)) {
2051 if (client->packets > 0) {
2052 client->ready_to_delete = false;
2053 return;
2054 }
2055
2056 /*
2057 * No packets, check / set idle timeout.
2058 */
2059 goto idle_timeout;
2060 }
2061
2062 /*
2063 * The client is pending definition. It's either a
2064 * dynamic client which has timed out, OR it's a
2065 * "place-holder" client for connected sockets.
2066 */
2067 fr_assert(client->state == PR_CLIENT_PENDING);
2068
2069 /*
2070 * This is a dynamic client pending definition.
2071 * But it's taken too long to define, so we just
2072 * delete the client, and all packets for it. A
2073 * new packet will cause the dynamic definition
2074 * to be run again.
2075 */
2076 if (!client->use_connected) {
2077 if (!client->packets) {
2078 DEBUG("proto_%s - No packets are using unconnected socket %s", inst->app_io->common.name, connection->name);
2079 goto delete_client;
2080 }
2081
2082 /*
2083 * Tell the writer to NOT dynamically define the
2084 * client. We've run into a problem. Then,
2085 * return. The writer will take care of calling
2086 * us again when it notices that a PENDING client
2087 * is ready to delete.
2088 *
2089 * TBH... that shouldn't happen? We should rely
2090 * on the write to do this all of the time...
2091 */
2092 client->ready_to_delete = true;
2093 return;
2094 }
2095
2096 fr_assert(!connection);
2097
2098 /*
2099 * Find out how many connections are using this
2100 * client.
2101 */
2102 pthread_mutex_lock(&client->mutex);
2103 fr_assert(client->ht != NULL);
2104 connections = fr_hash_table_num_elements(client->ht);
2105 pthread_mutex_unlock(&client->mutex);
2106
2107 /*
2108 * No connections are using this client. If
2109 * we've passed the idle timeout, then just
2110 * delete it. Otherwise, set an idle timeout (as
2111 * above);
2112 */
2113 if (!connections) {
2114idle_timeout:
2115 /*
2116 * We didn't receive any packets during the
2117 * idle_timeout, just delete it.
2118 */
2119 if (client->ready_to_delete) {
2120 if (connection) {
2121 DEBUG("proto_%s - idle timeout for connection %s", inst->app_io->common.name, connection->name);
2122 } else {
2123 DEBUG("proto_%s - idle timeout for client %s", inst->app_io->common.name, client->radclient->shortname);
2124 }
2125 goto delete_client;
2126 }
2127
2128 /*
2129 * No packets and no idle timeout set, go set
2130 * idle timeut.
2131 */
2132 client->ready_to_delete = true;
2133 delay = inst->idle_timeout;
2134 goto reset_timer;
2135 }
2136
2137 /*
2138 * There are live sub-connections. Poll again after a
2139 * long period of time. Once all of the connections are
2140 * closed, we can then delete this client.
2141 *
2142 * @todo - maybe just leave it? we want to be able to
2143 * clean up this client after a while tho... especially
2144 * if the total number of clients is limited.
2145 */
2146 client->ready_to_delete = false;
2147 delay = inst->check_interval;
2148
2149reset_timer:
2150 if (fr_event_timer_in(client, el, &client->ev,
2151 delay, client_expiry_timer, client) < 0) {
2152 ERROR("proto_%s - Failed adding timeout for dynamic client %s. It will be permanent!",
2153 inst->app_io->common.name, client->radclient->shortname);
2154 return;
2155 }
2156
2157 return;
2158}
2159
2160
2161/*
2162 * Expire cached packets after cleanup_delay time
2163 */
2164static void packet_expiry_timer(fr_event_list_t *el, fr_time_t now, void *uctx)
2165{
2166 fr_io_track_t *track = talloc_get_type_abort(uctx, fr_io_track_t);
2167 fr_io_client_t *client = track->client;
2168 fr_io_instance_t const *inst = client->inst;
2169
2170 /*
2171 * Insert the timer if requested.
2172 *
2173 * On duplicates this also extends the expiry timer.
2174 */
2175 if (fr_time_eq(now, fr_time_wrap(0)) && !track->discard && inst->app_io->track_duplicates) {
2176 fr_assert(fr_time_delta_ispos(inst->cleanup_delay));
2177 fr_assert(track->do_not_respond || track->reply_len);
2178
2179 track->expires = fr_time_add(fr_time(), inst->cleanup_delay);
2180
2181 /*
2182 * if the timer succeeds, then "track"
2183 * will be cleaned up when the timer
2184 * fires.
2185 */
2186 if (fr_event_timer_at(track, el, &track->ev,
2187 track->expires, packet_expiry_timer, track) == 0) {
2188 DEBUG("proto_%s - cleaning up request in %.6fs", inst->app_io->common.name,
2189 fr_time_delta_unwrap(inst->cleanup_delay) / (double)NSEC);
2190 return;
2191 }
2192
2193 DEBUG("proto_%s - Failed adding cleanup_delay for packet. Discarding packet immediately",
2194 inst->app_io->common.name);
2195 }
2196
2197 /*
2198 * So that all cleanup paths can come here, not just the
2199 * timeout ones.
2200 */
2201 if (fr_time_neq(now, fr_time_wrap(0))) {
2202 DEBUG2("TIMER - proto_%s - cleanup delay", inst->app_io->common.name);
2203 } else {
2204 DEBUG2("proto_%s - cleaning up", inst->app_io->common.name);
2205 }
2206
2207 /*
2208 * Delete the tracking entry.
2209 */
2210 talloc_free(track);
2211
2212 /*
2213 * The client isn't dynamic, stop here.
2214 */
2215 if (client->state == PR_CLIENT_STATIC) return;
2216
2217 fr_assert(client->state != PR_CLIENT_NAK);
2218 fr_assert(client->state != PR_CLIENT_PENDING);
2219
2220 /*
2221 * If necessary, call the client expiry timer to clean up
2222 * the client.
2223 */
2224 if (client->packets == 0) {
2225 client_expiry_timer(el, now, client);
2226 }
2227}
2228
2229static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, fr_time_t request_time,
2230 uint8_t *buffer, size_t buffer_len, size_t written)
2231{
2232 fr_io_instance_t const *inst;
2233 fr_io_thread_t *thread;
2234 fr_io_connection_t *connection;
2235 fr_io_track_t *track = talloc_get_type_abort(packet_ctx, fr_io_track_t);
2236 fr_io_client_t *client;
2237 fr_client_t *radclient;
2238 fr_listen_t *child;
2240
2241 get_inst(li, &inst, &thread, &connection, &child);
2242
2243 client = track->client;
2244 if (connection) {
2245 el = connection->el;
2246 } else {
2247 el = thread->el;
2248 }
2249
2250 /*
2251 * A fully defined client means that we just send the reply.
2252 */
2253 if (client->state != PR_CLIENT_PENDING) {
2254 ssize_t packet_len;
2255
2256 track->finished = true;
2257
2258 /*
2259 * The request later received a conflicting
2260 * packet, so we discard this one.
2261 */
2262 if (fr_time_neq(track->timestamp, request_time) || track->discard) {
2263 fr_assert(track->packets > 0);
2264 track->packets--;
2265
2266 DEBUG3("Suppressing reply as we have a newer packet");
2267
2268 track->discard = true;
2269 goto setup_timer;
2270 }
2271
2272 /*
2273 * We have a NAK packet, or the request has timed
2274 * out, or it was discarded due to a conflicting
2275 * packet. We don't respond, but we do cache the
2276 * "do not respond" reply for a period of time.
2277 */
2278 if ((buffer_len == 1) || track->do_not_respond) {
2279 track->do_not_respond = true;
2280 goto setup_timer;
2281 }
2282
2283 /*
2284 * We have a real packet, write it to the network
2285 * via the underlying transport write.
2286 */
2287 packet_len = inst->app_io->write(child, track, request_time,
2288 buffer, buffer_len, written);
2289 if (packet_len <= 0) {
2290 track->discard = true;
2292 return packet_len;
2293 }
2294
2295 /*
2296 * Only a partial write. The network code will
2297 * take care of calling us again, and we will set
2298 * the expiry timer at that point.
2299 */
2300 if ((size_t) packet_len < buffer_len) {
2301 return packet_len;
2302 }
2303
2304 /*
2305 * We're not tracking duplicates, so just expire
2306 * the packet now.
2307 */
2308 if (!inst->app_io->track_duplicates) goto setup_timer;
2309
2310 /*
2311 * Cache the reply packet if we're doing dedup.
2312 *
2313 * On resend duplicate reply, the reply is
2314 * already filled out. So we don't do that twice.
2315 */
2316 if (!track->reply) {
2317 MEM(track->reply = talloc_memdup(track, buffer, buffer_len));
2318 track->reply_len = buffer_len;
2319 }
2320
2321 /*
2322 * Set the timer to expire the packet.
2323 *
2324 * On dedup this also extends the timer.
2325 */
2326 setup_timer:
2328 return buffer_len;
2329 }
2330
2331 /*
2332 * The client is pending, so we MUST have dynamic clients.
2333 *
2334 * If there's a connected socket and no dynamic clients, then the
2335 * client state is set to CONNECTED when the client is created.
2336 */
2337 fr_assert(inst->dynamic_clients);
2338 fr_assert(client->pending != NULL);
2339
2340 /*
2341 * The request has timed out trying to define the dynamic
2342 * client. Oops... try again.
2343 */
2344 if ((buffer_len == 1) && (*buffer == true)) {
2345 DEBUG("Request has timed out trying to define a new client. Trying again.");
2346 goto reread;
2347 }
2348
2349 /*
2350 * The dynamic client was NOT defined. Set it's state to
2351 * NAK, delete all pending packets, and close the
2352 * tracking table.
2353 */
2354 if (buffer_len == 1) {
2355 client->state = PR_CLIENT_NAK;
2356 TALLOC_FREE(client->pending);
2357 if (client->table) TALLOC_FREE(client->table);
2358 fr_assert(client->packets == 0);
2359
2360 /*
2361 * If we're a connected UDP socket, allocate a
2362 * new connection which is the place-holder for
2363 * the NAK. We will reject packets from from the
2364 * src/dst IP/port.
2365 *
2366 * The timer will take care of deleting the NAK
2367 * connection (which doesn't have any FDs
2368 * associated with it). The network side will
2369 * call mod_close() when the original connection
2370 * is done, which will then free that connection,
2371 * too.
2372 */
2373 if (connection && (inst->ipproto == IPPROTO_UDP)) {
2374 connection = fr_io_connection_alloc(inst, thread, client, -1, connection->address, connection);
2375 client_expiry_timer(el, fr_time_wrap(0), connection->client);
2376
2377 errno = ECONNREFUSED;
2378 return -1;
2379 }
2380
2381 /*
2382 * For connected TCP sockets, we just call the
2383 * expiry timer, which will close and free the
2384 * connection.
2385 */
2386 client_expiry_timer(el, fr_time_wrap(0), client);
2387 return buffer_len;
2388 }
2389
2390 fr_assert(buffer_len == sizeof(radclient));
2391
2392 memcpy(&radclient, buffer, sizeof(radclient));
2393
2394 if (!connection) {
2395 fr_ipaddr_t ipaddr;
2396
2397 /*
2398 * Check the encapsulating network against the
2399 * address that the user wants to use, but only
2400 * for unconnected sockets.
2401 */
2402 if (client->network.af != radclient->ipaddr.af) {
2403 DEBUG("Client IP address %pV IP version does not match the source network %pV of the packet.",
2404 fr_box_ipaddr(radclient->ipaddr), fr_box_ipaddr(client->network));
2405 goto error;
2406 }
2407
2408 /*
2409 * Network prefix is more restrictive than the one given
2410 * by the client... that's bad.
2411 */
2412 if (client->network.prefix > radclient->ipaddr.prefix) {
2413 DEBUG("Client IP address %pV is not within the prefix with the defined network %pV",
2414 fr_box_ipaddr(radclient->ipaddr), fr_box_ipaddr(client->network));
2415 goto error;
2416 }
2417
2418 ipaddr = radclient->ipaddr;
2419 fr_ipaddr_mask(&ipaddr, client->network.prefix);
2420 if (fr_ipaddr_cmp(&ipaddr, &client->network) != 0) {
2421 DEBUG("Client IP address %pV is not within the defined network %pV.",
2422 fr_box_ipaddr(radclient->ipaddr), fr_box_ipaddr(client->network));
2423 goto error;
2424 }
2425
2426 /*
2427 * We can't define dynamic clients as networks (for now).
2428 *
2429 * @todo - If we did allow it, we would have to remove
2430 * this client from the trie, update it's IP address, and
2431 * re-add it. We can PROBABLY do this if this client
2432 * isn't already connected, AND radclient->use_connected
2433 * is true. But that's for later...
2434 */
2435 if (((radclient->ipaddr.af == AF_INET) &&
2436 (radclient->ipaddr.prefix != 32)) ||
2437 ((radclient->ipaddr.af == AF_INET6) &&
2438 (radclient->ipaddr.prefix != 128))) {
2439 ERROR("Cannot define a dynamic client as a network");
2440
2441 error:
2442 talloc_free(radclient);
2443
2444 /*
2445 * Remove the pending client from the trie.
2446 */
2447 fr_assert(!connection);
2448 talloc_free(client);
2449 return buffer_len;
2450 }
2451 }
2452
2453 /*
2454 * The new client is mostly OK. Copy the various fields
2455 * over.
2456 */
2457#define COPY_FIELD(_x) client->radclient->_x = radclient->_x
2458#define DUP_FIELD(_x) client->radclient->_x = talloc_strdup(client->radclient, radclient->_x)
2459
2460 /*
2461 * Only these two fields are set. Other strings in
2462 * radclient are copies of these ones.
2463 */
2466
2467 DUP_FIELD(longname);
2468 DUP_FIELD(shortname);
2470 DUP_FIELD(nas_type);
2471
2472 COPY_FIELD(ipaddr);
2473 COPY_FIELD(src_ipaddr);
2474 COPY_FIELD(require_message_authenticator);
2475 COPY_FIELD(require_message_authenticator_is_set);
2476 COPY_FIELD(limit_proxy_state);
2477 COPY_FIELD(limit_proxy_state_is_set);
2478 COPY_FIELD(use_connected);
2479 COPY_FIELD(cs);
2480
2481 // @todo - fill in other fields?
2482
2483 talloc_free(radclient);
2484
2485 radclient = client->radclient; /* laziness */
2486 radclient->server_cs = inst->server_cs;
2487 radclient->server = cf_section_name2(inst->server_cs);
2488
2489 /*
2490 * Re-parent the conf section used to build this client
2491 * so its lifetime is linked to the client
2492 */
2493 talloc_steal(radclient, radclient->cs);
2494
2495 /*
2496 * This is a connected socket, and it's just been
2497 * allowed. Go poke the network side to read from the
2498 * socket.
2499 */
2500 if (connection) {
2501 fr_assert(connection != NULL);
2502 fr_assert(connection->client == client);
2503 fr_assert(client->connection != NULL);
2504
2505 client->state = PR_CLIENT_CONNECTED;
2506
2507 /*
2508 * Connections can't spawn new connections.
2509 */
2510 client->use_connected = radclient->use_connected = false;
2511
2512 /*
2513 * If we were paused. resume reading from the
2514 * connection.
2515 *
2516 * Note that the event list doesn't like resuming
2517 * a connection that isn't paused. It just sets
2518 * the read function to NULL.
2519 */
2520 if (connection->paused) {
2521 (void) fr_event_filter_update(el, child->fd,
2523 }
2524
2525 connection->parent->radclient->active = true;
2526 fr_assert(connection->parent->state == PR_CLIENT_PENDING);
2527 connection->parent->state = PR_CLIENT_DYNAMIC;
2528
2529 connection->parent->radclient->secret = talloc_strdup(connection->parent->radclient,
2530 radclient->secret);
2531 connection->parent->radclient->shortname = talloc_strdup(connection->parent->radclient,
2532 radclient->shortname);
2533
2534 /*
2535 * The client has been allowed.
2536 */
2537 client->state = PR_CLIENT_DYNAMIC;
2538 client->radclient->active = true;
2539 goto finish;
2540 }
2541
2542 fr_assert(connection == NULL);
2543 fr_assert(client->use_connected == false); /* we weren't sure until now */
2544
2545 /*
2546 * Disallow unsupported configurations.
2547 */
2548 if (radclient->use_connected && !inst->app_io->connection_set) {
2549 DEBUG("proto_%s - cannot use connected sockets as underlying 'transport = %s' does not support it.",
2550 inst->app_io->common.name, inst->submodule->module->exported->name);
2551 goto error;
2552 }
2553
2554
2555 /*
2556 * Dynamic clients can spawn new connections.
2557 */
2558 client->use_connected = radclient->use_connected;
2559
2560 /*
2561 * The admin has defined a client which uses connected
2562 * sockets. Go spawn it
2563 */
2564 if (client->use_connected) {
2565 fr_assert(connection == NULL);
2566
2567
2568 /*
2569 * Leave the state as PENDING. Each connection
2570 * will then cause a dynamic client to be
2571 * defined.
2572 */
2573 (void) pthread_mutex_init(&client->mutex, NULL);
2574 MEM(client->ht = fr_hash_table_alloc(client, connection_hash, connection_cmp, NULL));
2575
2576 } else {
2577 /*
2578 * The client has been allowed.
2579 */
2580 client->state = PR_CLIENT_DYNAMIC;
2581 client->radclient->active = true;
2582 }
2583
2584 /*
2585 * Add this client to the master socket, so that
2586 * mod_read() will see the pending client, pop the
2587 * pending packet, and process it.
2588 *
2589 */
2590 if (!thread->pending_clients) {
2592 fr_io_client_t, pending_id, 0));
2593 }
2594
2596 (void) fr_heap_insert(&thread->pending_clients, client);
2597
2598finish:
2599 /*
2600 * Maybe we defined the client, but the original packet
2601 * timed out, so there's nothing more to do. In that case, set up the expiry timers.
2602 */
2603 if (client->packets == 0) {
2604 client_expiry_timer(el, fr_time_wrap(0), client);
2605 }
2606
2607reread:
2608 /*
2609 * If there are pending packets (and there should be at
2610 * least one), tell the network socket to call our read()
2611 * function again.
2612 */
2613 if (fr_heap_num_elements(client->pending) > 0) {
2614 if (connection) {
2615 fr_network_listen_read(connection->nr, connection->listen);
2616 } else {
2617 fr_network_listen_read(thread->nr, thread->listen);
2618 }
2619 }
2620
2621 return buffer_len;
2622}
2623
2624/** Close the socket.
2625 *
2626 */
2627static int mod_close(fr_listen_t *li)
2628{
2629 fr_io_instance_t const *inst;
2630 fr_io_connection_t *connection;
2631 fr_listen_t *child;
2632
2633 get_inst(li, &inst, NULL, &connection, &child);
2634
2635 if (inst->app_io->close) {
2636 int ret;
2637
2638 ret = inst->app_io->close(child);
2639 if (ret < 0) return ret;
2640 } else {
2641 close(child->fd);
2642// child->fd = -1;
2643 }
2644
2645 if (!connection) return 0;
2646
2647 /*
2648 * We allocated this, so we're responsible for closing
2649 * it.
2650 */
2651 DEBUG("Closing connection %s", connection->name);
2652 if (connection->client->pending) {
2653 TALLOC_FREE(connection->client->pending); /* for any pending packets */
2654 }
2655
2656 /*
2657 * Remove connection from parent hash table
2658 */
2659 pthread_mutex_lock(&connection->parent->mutex);
2660 if (connection->in_parent_hash) {
2661 connection->in_parent_hash = false;
2662 (void) fr_hash_table_delete(connection->parent->ht, connection);
2663 }
2664 pthread_mutex_unlock(&connection->parent->mutex);
2665
2666 /*
2667 * Clean up listener
2668 */
2669 fr_network_listen_delete(connection->nr, child);
2670
2671 talloc_free(connection->mi);
2672
2673 return 0;
2674}
2675
2676static int mod_instantiate(module_inst_ctx_t const *mctx)
2677{
2678 fr_io_instance_t *inst = mctx->mi->data;
2679 CONF_SECTION *conf = mctx->mi->conf;
2680
2681 inst->app_io = (fr_app_io_t const *) inst->submodule->exported;
2682 inst->app_io_conf = inst->submodule->conf;
2683 inst->app_io_instance = inst->submodule->data;
2684
2685 /*
2686 * If we're not tracking duplicates then we don't need a
2687 * cleanup delay.
2688 *
2689 * If we are tracking duplicates, then we must have a non-zero cleanup delay.
2690 */
2691 if (!inst->app_io->track_duplicates) {
2692 inst->cleanup_delay = fr_time_delta_wrap(0);
2693
2694 } else {
2695 FR_TIME_DELTA_BOUND_CHECK("cleanup_delay", inst->cleanup_delay, >=, fr_time_delta_from_sec(1));
2696
2697 if (!inst->app_io->track_create) {
2698 cf_log_err(inst->app_io_conf, "Internal error: 'track_duplicates' is set, but there is no 'track create' function");
2699 return -1;
2700 }
2701 }
2702
2703 /*
2704 * Get various information after bootstrapping the
2705 * application IO module.
2706 */
2707 if (inst->app_io->network_get) {
2708 inst->app_io->network_get(&inst->ipproto, &inst->dynamic_clients, &inst->networks, inst->app_io_instance);
2709 }
2710
2711 if ((inst->ipproto == IPPROTO_TCP) && !inst->app_io->connection_set) {
2712 cf_log_err(inst->app_io_conf, "Missing 'connection set' API for proto_%s", inst->app_io->common.name);
2713 return -1;
2714 }
2715
2716 /*
2717 * Ensure that the dynamic client sections exist
2718 */
2719 if (inst->dynamic_clients) {
2721
2722 if (!cf_section_find(server, "new", "client")) {
2723 cf_log_err(conf, "Cannot use 'dynamic_clients = yes' as the virtual server has no 'new client { ... }' section defined.");
2724 return -1;
2725 }
2726
2727 if (!cf_section_find(server, "add", "client")) {
2728 cf_log_warn(conf, "No 'add client { ... }' section was defined.");
2729 }
2730
2731 if (!cf_section_find(server, "deny", "client")) {
2732 cf_log_warn(conf, "No 'deny client { ... }' section was defined.");
2733 }
2734 }
2735
2736 /*
2737 * Create a list of client modules.
2738 *
2739 * FIXME - Probably only want to do this for connected sockets?
2740 *
2741 * FIXME - We probably want write protect enabled?
2742 */
2743 inst->clients = module_list_alloc(inst, &module_list_type_thread_local, "clients", false);
2745
2746 return 0;
2747}
2748
2749
2750static char const *mod_name(fr_listen_t *li)
2751{
2752 fr_io_thread_t *thread;
2753 fr_io_connection_t *connection;
2754 fr_listen_t *child;
2755 fr_io_instance_t const *inst;
2756
2757 get_inst(li, &inst, &thread, &connection, &child);
2758
2759 fr_assert(child != NULL);
2760 return child->app_io->get_name(child);
2761}
2762
2763/** Create a trie from arrays of allow / deny IP addresses
2764 *
2765 * @param ctx the talloc ctx
2766 * @param af the address family to allow
2767 * @param allow the array of IPs / networks to allow. MUST be talloc'd
2768 * @param deny the array of IPs / networks to deny. MAY be NULL, MUST be talloc'd
2769 * @return
2770 * - fr_trie_t on success
2771 * - NULL on error
2772 */
2773fr_trie_t *fr_master_io_network(TALLOC_CTX *ctx, int af, fr_ipaddr_t *allow, fr_ipaddr_t *deny)
2774{
2775 fr_trie_t *trie;
2776 size_t i, num;
2777
2778 MEM(trie = fr_trie_alloc(ctx, NULL, NULL));
2779
2780 num = talloc_array_length(allow);
2781 fr_assert(num > 0);
2782
2783 for (i = 0; i < num; i++) {
2784 fr_ipaddr_t *network;
2785
2786 /*
2787 * Can't add v4 networks to a v6 socket, or vice versa.
2788 */
2789 if (allow[i].af != af) {
2790 fr_strerror_printf("Address family in entry %zd - 'allow = %pV' "
2791 "does not match 'ipaddr'", i + 1, fr_box_ipaddr(allow[i]));
2792 talloc_free(trie);
2793 return NULL;
2794 }
2795
2796 /*
2797 * Duplicates are bad.
2798 */
2799 network = fr_trie_match_by_key(trie,
2800 &allow[i].addr, allow[i].prefix);
2801 if (network) {
2802 fr_strerror_printf("Cannot add duplicate entry 'allow = %pV'",
2803 fr_box_ipaddr(allow[i]));
2804 talloc_free(trie);
2805 return NULL;
2806 }
2807
2808 /*
2809 * Look for overlapping entries.
2810 * i.e. the networks MUST be disjoint.
2811 *
2812 * Note that this catches 192.168.1/24
2813 * followed by 192.168/16, but NOT the
2814 * other way around. The best fix is
2815 * likely to add a flag to
2816 * fr_trie_alloc() saying "we can only
2817 * have terminal fr_trie_user_t nodes"
2818 */
2819 network = fr_trie_lookup_by_key(trie,
2820 &allow[i].addr, allow[i].prefix);
2821 if (network && (network->prefix <= allow[i].prefix)) {
2822 fr_strerror_printf("Cannot add overlapping entry 'allow = %pV'", fr_box_ipaddr(allow[i]));
2823 fr_strerror_const("Entry is completely enclosed inside of a previously defined network.");
2824 talloc_free(trie);
2825 return NULL;
2826 }
2827
2828 /*
2829 * Insert the network into the trie.
2830 * Lookups will return the fr_ipaddr_t of
2831 * the network.
2832 */
2833 if (fr_trie_insert_by_key(trie,
2834 &allow[i].addr, allow[i].prefix,
2835 &allow[i]) < 0) {
2836 fr_strerror_printf("Failed adding 'allow = %pV' to tracking table", fr_box_ipaddr(allow[i]));
2837 talloc_free(trie);
2838 return NULL;
2839 }
2840 }
2841
2842 /*
2843 * And now check denied networks.
2844 */
2845 num = talloc_array_length(deny);
2846 if (!num) return trie;
2847
2848 /*
2849 * Since the default is to deny, you can only add
2850 * a "deny" inside of a previous "allow".
2851 */
2852 for (i = 0; i < num; i++) {
2853 fr_ipaddr_t *network;
2854
2855 /*
2856 * Can't add v4 networks to a v6 socket, or vice versa.
2857 */
2858 if (deny[i].af != af) {
2859 fr_strerror_printf("Address family in entry %zd - 'deny = %pV' "
2860 "does not match 'ipaddr'", i + 1, fr_box_ipaddr(deny[i]));
2861 talloc_free(trie);
2862 return NULL;
2863 }
2864
2865 /*
2866 * Duplicates are bad.
2867 */
2868 network = fr_trie_match_by_key(trie,
2869 &deny[i].addr, deny[i].prefix);
2870 if (network) {
2871 fr_strerror_printf("Cannot add duplicate entry 'deny = %pV'", fr_box_ipaddr(deny[i]));
2872 talloc_free(trie);
2873 return NULL;
2874 }
2875
2876 /*
2877 * A "deny" can only be within a previous "allow".
2878 */
2879 network = fr_trie_lookup_by_key(trie,
2880 &deny[i].addr, deny[i].prefix);
2881 if (!network) {
2882 fr_strerror_printf("The network in entry %zd - 'deny = %pV' is not "
2883 "contained within a previous 'allow'", i + 1, fr_box_ipaddr(deny[i]));
2884 talloc_free(trie);
2885 return NULL;
2886 }
2887
2888 /*
2889 * We hack the AF in "deny" rules. If
2890 * the lookup gets AF_UNSPEC, then we're
2891 * adding a "deny" inside of a "deny".
2892 */
2893 if (network->af != af) {
2894 fr_strerror_printf("The network in entry %zd - 'deny = %pV' is overlaps "
2895 "with another 'deny' rule", i + 1, fr_box_ipaddr(deny[i]));
2896 talloc_free(trie);
2897 return NULL;
2898 }
2899
2900 /*
2901 * Insert the network into the trie.
2902 * Lookups will return the fr_ipaddr_t of
2903 * the network.
2904 */
2905 if (fr_trie_insert_by_key(trie,
2906 &deny[i].addr, deny[i].prefix,
2907 &deny[i]) < 0) {
2908 fr_strerror_printf("Failed adding 'deny = %pV' to tracking table", fr_box_ipaddr(deny[i]));
2909 talloc_free(trie);
2910 return NULL;
2911 }
2912
2913 /*
2914 * Hack it to make it a deny rule.
2915 */
2916 deny[i].af = AF_UNSPEC;
2917 }
2918
2919 return trie;
2920}
2921
2922
2924{
2925 if (!li->thread_instance) return 0;
2926
2928 return 0;
2929}
2930
2932 size_t default_message_size, size_t num_messages)
2933{
2934 fr_listen_t *li, *child;
2935 fr_io_thread_t *thread;
2936
2937 /*
2938 * No IO paths, so we don't initialize them.
2939 */
2940 if (!inst->app_io) {
2941 fr_assert(!inst->dynamic_clients);
2942 return 0;
2943 }
2944
2945 if (!inst->app_io->common.thread_inst_size) {
2946 fr_strerror_const("IO modules MUST set 'thread_inst_size' when using the master IO handler.");
2947 return -1;
2948 }
2949
2950 /*
2951 * Build the #fr_listen_t. This describes the complete
2952 * path data takes from the socket to the decoder and
2953 * back again.
2954 */
2955 MEM(li = talloc_zero(NULL, fr_listen_t));
2956 talloc_set_destructor(li, fr_io_listen_free);
2957
2958 /*
2959 * The first listener is the one for the application
2960 * (e.g. RADIUS). However, we mangle the IO path to
2961 * point to the master IO handler. That allows all of
2962 * the high-level work (dynamic client checking,
2963 * connected sockets, etc.) to be handled by the master
2964 * IO handler.
2965 *
2966 * This listener is then passed to the network code,
2967 * which calls our trampoline functions to do the actual
2968 * work.
2969 */
2970 li->app = inst->app;
2971 li->app_instance = inst->app_instance;
2972 li->server_cs = inst->server_cs;
2973
2974 /*
2975 * Set configurable parameters for message ring buffer.
2976 */
2977 li->default_message_size = default_message_size;
2978 li->num_messages = num_messages;
2979
2980 /*
2981 * Per-socket data lives here.
2982 */
2983 thread = talloc_zero(NULL, fr_io_thread_t);
2984 thread->listen = li;
2985 thread->sc = sc;
2986
2987 /*
2988 * Create the trie of clients for this socket.
2989 */
2990 MEM(thread->trie = fr_trie_alloc(thread, NULL, NULL));
2991
2992 if (inst->dynamic_clients) {
2994 fr_io_client_t, alive_id, 0));
2995 }
2996
2997 /*
2998 * Set the listener to call our master trampoline function.
2999 */
3000 li->app_io = &fr_master_app_io;
3001 li->thread_instance = thread;
3002 li->app_io_instance = inst;
3003 li->track_duplicates = inst->app_io->track_duplicates;
3004
3005 /*
3006 * The child listener points to the *actual* IO path.
3007 *
3008 * We need to create a complete listener here (e.g.
3009 * RADIUS + RADIUS_UDP), because the underlying IO
3010 * functions expect to get passed a full listener.
3011 *
3012 * Once the network side calls us, we will call the child
3013 * listener to do the actual IO.
3014 */
3015 child = thread->child = talloc_zero(li, fr_listen_t);
3016 memcpy(child, li, sizeof(*child));
3017
3018 /*
3019 * Reset these fields to point to the IO instance data.
3020 */
3021 child->app_io = inst->app_io;
3022 child->track_duplicates = inst->app_io->track_duplicates;
3023
3024 if (child->app_io->common.thread_inst_size > 0) {
3025 child->thread_instance = talloc_zero_array(NULL, uint8_t,
3026 inst->app_io->common.thread_inst_size);
3027 talloc_set_destructor(child, fr_io_listen_free);
3028
3029 talloc_set_name(child->thread_instance, "proto_%s_thread_t",
3030 inst->app_io->common.name);
3031
3032 /*
3033 * This is "const", and the user can't
3034 * touch it. So we just reuse the same
3035 * configuration everywhere.
3036 */
3037 child->app_io_instance = inst->app_io_instance;
3038
3039 } else {
3040 child->thread_instance = inst->app_io_instance;
3041 child->app_io_instance = child->thread_instance;
3042 }
3043
3044 /*
3045 * Don't call connection_set() for the main socket. It's
3046 * not connected. Instead, tell the IO path to open the
3047 * socket for us.
3048 */
3049 if (inst->app_io->open(child) < 0) {
3050 cf_log_err(inst->app_io_conf, "Failed opening %s interface", inst->app_io->common.name);
3051 talloc_free(li);
3052 return -1;
3053 }
3054
3055 li->fd = child->fd; /* copy this back up */
3056
3057 if (!child->app_io->get_name) {
3058 child->name = child->app_io->common.name;
3059 } else {
3060 child->name = child->app_io->get_name(child);
3061 }
3062 li->name = child->name;
3063
3064 /*
3065 * Record which socket we opened.
3066 */
3067 if (child->app_io_addr) {
3068 fr_listen_t *other;
3069
3070 other = listen_find_any(thread->child);
3071 if (other) {
3072 ERROR("Failed opening %s - that port is already in use by another listener in server %s { ... } - %s",
3073 child->name, cf_section_name2(other->server_cs), other->name);
3074
3075 ERROR("got socket %d %d\n", child->app_io_addr->inet.src_port, other->app_io_addr->inet.src_port);
3076
3077 talloc_free(li);
3078 return -1;
3079 }
3080
3081 (void) listen_record(child);
3082 }
3083
3084 /*
3085 * Add the socket to the scheduler, where it might end up
3086 * in a different thread.
3087 */
3088 if (!fr_schedule_listen_add(sc, li)) {
3089 talloc_free(li);
3090 return -1;
3091 }
3092
3093 return 0;
3094}
3095
3096/*
3097 * Used to create a tracking structure for fr_network_sendto_worker()
3098 */
3099fr_io_track_t *fr_master_io_track_alloc(fr_listen_t *li, fr_client_t *radclient, fr_ipaddr_t const *src_ipaddr, int src_port,
3100 fr_ipaddr_t const *dst_ipaddr, int dst_port)
3101{
3102 fr_io_instance_t const *inst;
3103 fr_io_thread_t *thread;
3104 fr_io_connection_t *connection;
3105 fr_listen_t *child;
3106 fr_io_track_t *track;
3107 fr_io_client_t *client;
3108 fr_io_address_t *address;
3109 fr_listen_t *parent = talloc_parent(li);
3110
3111 (void) talloc_get_type_abort(parent, fr_listen_t);
3112
3113 get_inst(parent, &inst, &thread, &connection, &child);
3114
3115 fr_assert(child == li);
3116
3117 if (unlikely(!thread)) return NULL;
3118 fr_assert(thread->trie != NULL);
3119
3120 client = fr_trie_lookup_by_key(thread->trie, &src_ipaddr->addr, src_ipaddr->prefix);
3121 if (!client) {
3122 MEM(client = client_alloc(thread, PR_CLIENT_STATIC, inst, thread, radclient, NULL));
3123 }
3124
3125 MEM(track = talloc_zero_pooled_object(client, fr_io_track_t, 1, sizeof(*track) + sizeof(track->address) + 64));
3126 MEM(track->address = address = talloc_zero(track, fr_io_address_t));
3127 track->client = client;
3128
3129 address->socket.inet.src_port = src_port;
3130 address->socket.inet.dst_port = dst_port;
3131
3132 address->socket.inet.src_ipaddr = *src_ipaddr;
3133 address->socket.inet.dst_ipaddr = *dst_ipaddr;
3134 address->radclient = radclient;
3135
3136 return track;
3137}
3138
3139
3141 .common = {
3142 .magic = MODULE_MAGIC_INIT,
3143 .name = "radius_master_io",
3144
3146 },
3147 .default_message_size = 4096,
3148 .track_duplicates = true,
3149
3150 .read = mod_read,
3151 .write = mod_write,
3152 .inject = mod_inject,
3153
3154 .open = mod_open,
3155 .close = mod_close,
3156 .event_list_set = mod_event_list_set,
3157 .get_name = mod_name,
3158};
static int const char char buffer[256]
Definition acutest.h:576
module_t common
Common fields to all loadable modules.
Definition app_io.h:34
fr_io_track_create_t track_create
create a tracking structure
Definition app_io.h:64
bool track_duplicates
track duplicate packets
Definition app_io.h:41
fr_io_name_t get_name
get the socket name
Definition app_io.h:70
fr_io_track_cmp_t track_compare
compare two tracking structures
Definition app_io.h:65
Public structure describing an I/O path for a protocol.
Definition app_io.h:33
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:322
#define CMP_PREFER_SMALLER(_a, _b)
Evaluates to +1 for a > b, and -1 for a < b.
Definition build.h:104
#define CMP_PREFER_LARGER(_a, _b)
Evaluates to -1 for a > b, and +1 for a < b.
Definition build.h:108
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
Definition build.h:121
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:112
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
#define FR_TIME_DELTA_BOUND_CHECK(_name, _var, _op, _bound)
Definition cf_parse.h:529
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1185
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1171
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1028
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:684
CONF_SECTION * cf_section_dup(TALLOC_CTX *ctx, CONF_SECTION *parent, CONF_SECTION const *cs, char const *name1, char const *name2, bool copy_meta)
Duplicate a configuration section.
Definition cf_util.c:928
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define cf_parent(_cf)
Definition cf_util.h:101
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:290
#define PRIORITY_NORMAL
Definition channel.h:151
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
Test enumeration values.
Definition dict_test.h:92
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:62
#define fr_event_filter_update(...)
Definition event.h:224
#define FR_EVENT_RESUME(_s, _f)
Re-add the filter for a func from kevent.
Definition event.h:110
#define FR_EVENT_SUSPEND(_s, _f)
Temporarily remove the filter for a func from kevent.
Definition event.h:94
#define fr_event_timer_at(...)
Definition event.h:250
#define fr_event_timer_in(...)
Definition event.h:255
Callbacks for the FR_EVENT_FILTER_IO filter.
Definition event.h:173
Structure describing a modification to a filter's state.
Definition event.h:75
void * fr_hash_table_find(fr_hash_table_t *ht, void const *data)
Find data in a hash table.
Definition hash.c:429
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
Definition hash.c:846
uint32_t fr_hash(void const *data, size_t size)
Definition hash.c:812
bool fr_hash_table_insert(fr_hash_table_t *ht, void const *data)
Insert data into a hash table.
Definition hash.c:468
bool fr_hash_table_delete(fr_hash_table_t *ht, void const *data)
Remove and free data (if a free function was specified)
Definition hash.c:594
uint32_t fr_hash_table_num_elements(fr_hash_table_t *ht)
Definition hash.c:610
#define fr_hash_table_alloc(_ctx, _hash_node, _cmp_node, _free_node)
Definition hash.h:58
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
Definition heap.c:146
void * fr_heap_pop(fr_heap_t **hp)
Remove a node from the heap.
Definition heap.c:322
int fr_heap_extract(fr_heap_t **hp, void *data)
Remove a node from the heap.
Definition heap.c:239
unsigned int fr_heap_index_t
Definition heap.h:80
static void * fr_heap_peek(fr_heap_t *h)
Return the item from the top of the heap but don't pop it.
Definition heap.h:136
#define fr_heap_alloc(_ctx, _cmp, _type, _field, _init)
Creates a heap that can be used with non-talloced elements.
Definition heap.h:100
static bool fr_heap_entry_inserted(fr_heap_index_t heap_idx)
Check if an entry is inserted into a heap.
Definition heap.h:124
static unsigned int fr_heap_num_elements(fr_heap_t *h)
Return the number of elements in the heap.
Definition heap.h:179
#define FR_HEAP_INDEX_INVALID
Definition heap.h:83
The main heap structure.
Definition heap.h:66
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port, struct sockaddr_storage const *sa, socklen_t salen)
Convert sockaddr to our internal ip address representation.
Definition inet.c:1441
int fr_ipaddr_to_sockaddr(struct sockaddr_storage *sa, socklen_t *salen, fr_ipaddr_t const *ipaddr, uint16_t port)
Convert our internal ip address representation to a sockaddr.
Definition inet.c:1392
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1346
void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
Zeroes out the host portion of an fr_ipaddr_t.
Definition inet.c:217
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition inet.h:69
int af
Address family.
Definition inet.h:64
union fr_ipaddr_t::@130 addr
IPv4/6 prefix.
fr_socket_t socket
src/dst ip and port.
Definition base.h:336
fr_client_t const * radclient
old-style client definition
Definition base.h:338
size_t num_messages
for the message ring buffer
Definition listen.h:52
char const * name
printable name for this socket - set by open
Definition listen.h:29
bool track_duplicates
do we track duplicate packets?
Definition listen.h:43
fr_socket_t * app_io_addr
for tracking duplicate sockets
Definition listen.h:35
void const * app_instance
Definition listen.h:38
size_t default_message_size
copied from app_io, but may be changed
Definition listen.h:51
bool connected
is this for a connected socket?
Definition listen.h:42
fr_app_t const * app
Definition listen.h:37
void const * app_io_instance
I/O path configuration context.
Definition listen.h:32
CONF_SECTION * server_cs
CONF_SECTION of the server.
Definition listen.h:40
void * thread_instance
thread / socket context
Definition listen.h:33
int fd
file descriptor for this socket - set by open
Definition listen.h:28
fr_app_io_t const * app_io
I/O path functions.
Definition listen.h:31
int fr_network_listen_delete(fr_network_t *nr, fr_listen_t *li)
Delete a socket from a network.
Definition network.c:259
int fr_network_listen_inject(fr_network_t *nr, fr_listen_t *li, uint8_t const *packet, size_t packet_len, fr_time_t recv_time)
Inject a packet for a listener to read.
Definition network.c:398
void fr_network_listen_read(fr_network_t *nr, fr_listen_t *li)
Signal the network to read from a listener.
Definition network.c:324
void fr_network_listen_write(fr_network_t *nr, fr_listen_t *li, uint8_t const *packet, size_t packet_len, void *packet_ctx, fr_time_t request_time)
Inject a packet for a listener to write.
Definition network.c:350
char const * server
Name of the virtual server client is associated with.
Definition client.h:129
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
Definition client.h:83
char const * secret
Secret PSK.
Definition client.h:90
bool active
for dynamic clients
Definition client.h:119
fr_ipaddr_t src_ipaddr
IPv4/IPv6 address to send responses from (family must match ipaddr).
Definition client.h:84
char const * nas_type
Type of client (arbitrary).
Definition client.h:127
int proto
Protocol number.
Definition client.h:143
CONF_SECTION * cs
CONF_SECTION that was parsed to generate the client.
Definition client.h:134
bool dynamic
Whether the client was dynamically defined.
Definition client.h:118
char const * longname
Client identifier.
Definition client.h:87
fr_socket_limit_t limit
Connections per client (TCP clients only).
Definition client.h:144
char const * shortname
Client nickname.
Definition client.h:88
bool use_connected
do we use connected sockets for this client
Definition client.h:120
CONF_SECTION * server_cs
Virtual server that the client is associated with.
Definition client.h:130
Describes a host allowed to send packets to the server.
Definition client.h:80
#define DEBUG3(_fmt,...)
Definition log.h:266
talloc_free(reap)
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
Definition event.c:1611
Stores all information relating to an event list.
Definition event.c:411
A timer event.
Definition event.c:102
fr_listen_t * child
The child (app_io) IO path.
Definition master.c:43
fr_network_t * nr
network for this connection
Definition master.c:152
static int8_t alive_client_cmp(void const *one, void const *two)
Definition master.c:1252
bool in_trie
is the client in the trie?
Definition master.c:111
bool paused
event filter doesn't like resuming something that isn't paused
Definition master.c:149
bool in_parent_hash
for tracking thread issues
Definition master.c:150
static fr_client_t * radclient_clone(TALLOC_CTX *ctx, fr_client_t const *parent)
Definition master.c:372
static ssize_t mod_read(fr_listen_t *li, void **packet_ctx, fr_time_t *recv_time_p, uint8_t *buffer, size_t buffer_len, size_t *leftover)
Implement 99% of the read routines.
Definition master.c:1264
int packets
number of packets using this connection
Definition master.c:140
static void client_expiry_timer(fr_event_list_t *el, fr_time_t now, void *uctx)
Definition master.c:1952
uint32_t num_pending_packets
number of pending packets
Definition master.c:48
#define DUP_FIELD(_x)
static int track_dedup_free(fr_io_track_t *track)
Definition master.c:177
fr_rb_tree_t * table
tracking table for packets
Definition master.c:116
fr_time_t recv_time
Definition master.c:58
static int8_t pending_packet_cmp(void const *one, void const *two)
Definition master.c:193
fr_heap_t * pending_clients
heap of pending clients
Definition master.c:39
static fr_io_track_t * fr_io_track_add(fr_io_client_t *client, fr_io_address_t *address, uint8_t const *packet, size_t packet_len, fr_time_t recv_time, bool *is_dup)
Definition master.c:1037
bool ready_to_delete
are we ready to delete this client?
Definition master.c:110
static fr_io_pending_packet_t * fr_io_pending_alloc(fr_io_client_t *client, uint8_t const *buffer, size_t packet_len, fr_io_track_t *track, int priority)
Definition master.c:1207
static int _client_live_free(fr_io_client_t *client)
Definition master.c:920
fr_heap_index_t pending_id
for pending clients
Definition master.c:106
static int pending_free(fr_io_pending_packet_t *pending)
Definition master.c:1183
bool use_connected
does this client allow connected sub-sockets?
Definition master.c:109
fr_io_client_t * client
our local client (pending or connected).
Definition master.c:144
static int track_free(fr_io_track_t *track)
Definition master.c:165
fr_app_io_t fr_master_app_io
Definition master.c:3140
fr_listen_t * listen
The master IO path.
Definition master.c:42
static int8_t pending_client_cmp(void const *one, void const *two)
Definition master.c:223
fr_io_track_t * fr_master_io_track_alloc(fr_listen_t *li, fr_client_t *radclient, fr_ipaddr_t const *src_ipaddr, int src_port, fr_ipaddr_t const *dst_ipaddr, int dst_port)
Definition master.c:3099
fr_io_address_t * address
full information about the connection.
Definition master.c:141
static int8_t address_cmp(void const *one, void const *two)
Definition master.c:241
fr_event_timer_t const * ev
when we clean up the client
Definition master.c:115
fr_listen_t * child
child listener (app_io) for this socket
Definition master.c:143
fr_listen_t * listen
master listener for this socket
Definition master.c:142
static void packet_expiry_timer(fr_event_list_t *el, fr_time_t now, void *uctx)
Definition master.c:2164
fr_network_t * nr
network for the master socket
Definition master.c:36
fr_trie_t * fr_master_io_network(TALLOC_CTX *ctx, int af, fr_ipaddr_t *allow, fr_ipaddr_t *deny)
Create a trie from arrays of allow / deny IP addresses.
Definition master.c:2773
static fr_io_pending_packet_t * pending_packet_pop(fr_io_thread_t *thread)
Definition master.c:336
fr_ipaddr_t network
network for dynamic clients
Definition master.c:102
static void mod_event_list_set(fr_listen_t *li, fr_event_list_t *el, void *nr)
Set the event list for a new socket.
Definition master.c:1919
static int mod_open(fr_listen_t *li)
Open a new listener.
Definition master.c:1883
pthread_mutex_t mutex
for parent / child signaling
Definition master.c:121
fr_heap_index_t heap_id
Definition master.c:56
static fr_io_client_t * client_alloc(TALLOC_CTX *ctx, fr_io_client_state_t state, fr_io_instance_t const *inst, fr_io_thread_t *thread, fr_client_t *radclient, fr_ipaddr_t const *network)
Definition master.c:940
fr_io_instance_t const * inst
parent instance for master IO handler
Definition master.c:113
#define COPY_FIELD(_x)
fr_trie_t * trie
trie of clients
Definition master.c:38
fr_io_client_state_t
Client states.
Definition master.c:68
@ PR_CLIENT_DYNAMIC
dynamically defined client
Definition master.c:72
@ PR_CLIENT_CONNECTED
dynamically defined client in a connected socket
Definition master.c:73
@ PR_CLIENT_PENDING
dynamic client pending definition
Definition master.c:74
@ PR_CLIENT_INVALID
Definition master.c:69
@ PR_CLIENT_NAK
negative cache entry
Definition master.c:71
@ PR_CLIENT_STATIC
static / global clients
Definition master.c:70
static void get_inst(fr_listen_t *li, fr_io_instance_t const **inst, fr_io_thread_t **thread, fr_io_connection_t **connection, fr_listen_t **child)
Definition master.c:872
static fr_event_update_t pause_read[]
Definition master.c:155
static int8_t track_connected_cmp(void const *one, void const *two)
Definition master.c:310
fr_heap_t * alive_clients
heap of active clients
Definition master.c:40
fr_schedule_t * sc
the scheduler
Definition master.c:44
static fr_io_connection_t * fr_io_connection_alloc(fr_io_instance_t const *inst, fr_io_thread_t *thread, fr_io_client_t *client, int fd, fr_io_address_t *address, fr_io_connection_t *nak)
Create a new connection.
Definition master.c:480
fr_hash_table_t * addresses
list of src/dst addresses used by this client
Definition master.c:119
int fr_master_io_listen(fr_io_instance_t *inst, fr_schedule_t *sc, size_t default_message_size, size_t num_messages)
Definition master.c:2931
static int connection_free(fr_io_connection_t *connection)
Definition master.c:465
int fr_io_listen_free(fr_listen_t *li)
Definition master.c:2923
char const * name
taken from proto_FOO_TRANSPORT
Definition master.c:139
fr_heap_index_t alive_id
for all clients
Definition master.c:107
fr_event_list_t * el
event list for this connection
Definition master.c:151
fr_io_client_state_t state
state of this client
Definition master.c:100
int packets
number of packets using this client
Definition master.c:105
static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, fr_time_t request_time, uint8_t *buffer, size_t buffer_len, size_t written)
Definition master.c:2229
bool dead
roundabout way to get the network side to close a socket
Definition master.c:148
fr_event_list_t * el
event list, for the master socket.
Definition master.c:35
uint64_t client_id
Unique client identifier.
Definition master.c:49
fr_io_thread_t * thread
Definition master.c:114
static char const * mod_name(fr_listen_t *li)
Definition master.c:2750
module_instance_t * mi
for submodule
Definition master.c:146
static int _client_free(fr_io_client_t *client)
Definition master.c:458
static int mod_close(fr_listen_t *li)
Close the socket.
Definition master.c:2627
static uint32_t connection_hash(void const *ctx)
Definition master.c:257
fr_io_connection_t * connection
parent connection
Definition master.c:99
fr_heap_t * pending
pending packets for this client
Definition master.c:118
static int count_connections(UNUSED uint8_t const *key, UNUSED size_t keylen, void *data, void *ctx)
Count the number of connections used by active clients.
Definition master.c:436
static int8_t connection_cmp(void const *one, void const *two)
Definition master.c:271
static int8_t track_cmp(void const *one, void const *two)
Definition master.c:280
fr_hash_table_t * ht
for tracking connected sockets
Definition master.c:122
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition master.c:2676
fr_io_track_t * track
Definition master.c:59
fr_client_t * radclient
old-style definition of this client
Definition master.c:103
fr_ipaddr_t src_ipaddr
packets come from this address
Definition master.c:101
static fr_event_update_t resume_read[]
Definition master.c:160
uint32_t num_connections
number of dynamic connections
Definition master.c:47
fr_io_client_t * parent
points to the parent client.
Definition master.c:145
static fr_client_t * radclient_alloc(TALLOC_CTX *ctx, int ipproto, fr_io_address_t *address)
Definition master.c:892
static int mod_inject(fr_listen_t *li, uint8_t const *buffer, size_t buffer_len, fr_time_t recv_time)
Inject a packet to a connection.
Definition master.c:1829
Client definitions for master IO.
Definition master.c:98
Track a connection.
Definition master.c:138
A saved packet.
Definition master.c:55
uint8_t * reply
reply packet (if any)
Definition master.h:46
fr_event_timer_t const * ev
when we clean up this tracking entry
Definition master.h:42
int packets
number of packets using this entry
Definition master.h:45
fr_time_t dynamic
timestamp for packet doing dynamic client definition
Definition master.h:53
void * app_io_instance
Easy access to the app_io instance.
Definition master.h:98
fr_app_io_t const * app_io
Easy access to the app_io handle.
Definition master.h:97
fr_io_address_t const * address
of this packet.. shared between multiple packets
Definition master.h:54
bool do_not_respond
don't respond
Definition master.h:50
bool discard
whether or not we discard the packet
Definition master.h:49
fr_time_t timestamp
when this packet was received
Definition master.h:43
bool finished
are we finished the request?
Definition master.h:51
uint8_t * packet
really a tracking structure, not a packet
Definition master.h:56
size_t reply_len
length of reply, or 1 for "do not reply"
Definition master.h:47
fr_io_client_t * client
client handling this packet.
Definition master.h:55
fr_time_t expires
when this packet expires
Definition master.h:44
The master IO instance.
Definition master.h:72
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
int fr_nonblock(UNUSED int fd)
Definition misc.c:293
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
char * fr_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Special version of asprintf which implements custom format specifiers.
Definition print.c:874
#define fr_assert(_expr)
Definition rad_assert.h:38
static int ipproto
static char * secret
static bool done
Definition radclient.c:80
#define DEBUG2(fmt,...)
Definition radclient.h:43
static bool cleanup
Definition radsniff.c:60
static rs_t * conf
Definition radsniff.c:53
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_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
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
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Definition rb.h:246
The main red black tree structure.
Definition rb.h:73
static unsigned int hash(char const *username, unsigned int tablesize)
Definition rlm_passwd.c:132
fr_network_t * fr_schedule_listen_add(fr_schedule_t *sc, fr_listen_t *li)
Add a fr_listen_t to a scheduler.
Definition schedule.c:881
The scheduler.
Definition schedule.c:125
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:329
void * data
Module's instance data.
Definition module.h:271
module_instantiate_t instantiate
Callback to allow the module to register any per-instance resources like sockets and file handles.
Definition module.h:218
@ MODULE_INSTANCE_BOOTSTRAPPED
Module instance has been bootstrapped, but not yet instantiated.
Definition module.h:244
size_t thread_inst_size
Size of the module's thread-specific instance data.
Definition module.h:235
Module instance data.
Definition module.h:265
fr_time_delta_t idle_timeout
Definition socket.h:38
uint32_t max_connections
Definition socket.h:33
static const uchar sc[16]
Definition smbdes.c:115
module_list_type_t const module_list_type_thread_local
Callbacks for a thread local list.
Definition module.c:590
void module_list_mask_set(module_list_t *ml, module_instance_state_t mask)
Set a new bootstrap/instantiate state for a list.
Definition module.c:1837
module_instance_t * module_instance_copy(module_list_t *dst, module_instance_t const *src, char const *inst_name)
Duplicate a module instance, placing it in a new module list.
Definition module.c:1536
module_list_t * module_list_alloc(TALLOC_CTX *ctx, module_list_type_t const *type, char const *name, bool write_protect)
Allocate a new module list.
Definition module.c:1859
int module_thread_instantiate(TALLOC_CTX *ctx, module_instance_t *mi, fr_event_list_t *el)
Allocate thread-local instance data for a module.
Definition module.c:1085
int module_instantiate(module_instance_t *instance)
Manually complete module setup by calling its instantiate function.
Definition module.c:1197
int module_instance_conf_parse(module_instance_t *mi, CONF_SECTION *conf)
Covert a CONF_SECTION into parsed module instance data.
Definition module.c:766
eap_aka_sim_process_conf_t * inst
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define talloc_get_type_abort_const
Definition talloc.h:282
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition talloc.h:177
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:224
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
Definition talloc.h:112
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
#define fr_time_delta_lt(_a, _b)
Definition time.h:285
static int64_t fr_time_unwrap(fr_time_t time)
Definition time.h:146
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
#define fr_time_delta_wrap(_time)
Definition time.h:152
#define fr_time_wrap(_time)
Definition time.h:145
#define fr_time_delta_ispos(_a)
Definition time.h:290
#define fr_time_eq(_a, _b)
Definition time.h:241
#define NSEC
Definition time.h:379
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
#define fr_time_neq(_a, _b)
Definition time.h:242
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
void * fr_trie_remove_by_key(fr_trie_t *ft, void const *key, size_t keylen)
Remove a key and return the associated user ctx.
Definition trie.c:2154
fr_trie_t * fr_trie_alloc(TALLOC_CTX *ctx, fr_trie_key_t get_key, fr_free_t free_data)
Allocate a trie.
Definition trie.c:741
int fr_trie_walk(fr_trie_t *ft, void *ctx, fr_trie_walk_t callback)
Definition trie.c:2607
void * fr_trie_lookup_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Lookup a key in a trie and return user ctx, if any.
Definition trie.c:1262
void * fr_trie_match_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Match a key and length in a trie and return user ctx, if any.
Definition trie.c:1286
int fr_trie_insert_by_key(fr_trie_t *ft, void const *key, size_t keylen, void const *data)
Insert a key and user ctx into a trie.
Definition trie.c:1875
close(uq->fd)
static fr_event_list_t * el
static fr_slen_t parent
Definition pair.h:851
int fd
File descriptor if this is a live socket.
Definition socket.h:81
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Definition socket.h:79
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
static fr_slen_t fr_value_box_aprint(TALLOC_CTX *ctx, char **out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules) 1(fr_value_box_print
#define fr_box_ipaddr(_val)
Definition value.h:294
static fr_slen_t data
Definition value.h:1265
#define fr_box_time_delta(_val)
Definition value.h:343
bool listen_record(fr_listen_t *li)
Record that we're listening on a particular IP / port.
fr_listen_t * listen_find_any(fr_listen_t *li)
See if another global listener is using a particular IP / port.