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