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