The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
client.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 40c825a4b954a7c702964ae62f17ba86cb36b4d9 $
19 * @file src/lib/server/client.c
20 * @brief Manage clients allowed to communicate with the server.
21 *
22 * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 * @copyright 2000,2006 The FreeRADIUS server project
24 * @copyright 2000 Alan DeKok (aland@freeradius.org)
25 * @copyright 2000 Miquel van Smoorenburg (miquels@cistron.nl)
26 */
27RCSID("$Id: 40c825a4b954a7c702964ae62f17ba86cb36b4d9 $")
28
29#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
30#include <freeradius-devel/server/cf_file.h>
31#include <freeradius-devel/server/cf_parse.h>
32#include <freeradius-devel/server/client.h>
33#include <freeradius-devel/server/main_config.h>
34#include <freeradius-devel/server/module.h>
35#include <freeradius-devel/server/virtual_servers.h>
36#include <freeradius-devel/unlang/call.h>
37
38#include <freeradius-devel/util/base16.h>
39#include <freeradius-devel/util/misc.h>
40#include <freeradius-devel/util/trie.h>
41
42#include <fcntl.h>
43#include <sys/stat.h>
44
45//#define WITH_TRIE (1)
46
47/** Group of clients
48 *
49 */
51 char const *name; //!< Name of the client list.
52#ifdef WITH_TRIE
53 fr_trie_t *v4_udp;
54 fr_trie_t *v6_udp;
55 fr_trie_t *v4_tcp;
56 fr_trie_t *v6_tcp;
57#else
59#endif
60};
61
62static fr_client_list_t *root_clients = NULL; //!< Global client list.
63
64#ifndef WITH_TRIE
65static int8_t client_cmp(void const *one, void const *two)
66{
67 int ret;
68 fr_client_t const *a = one;
69 fr_client_t const *b = two;
70
71 ret = fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
72 if (ret != 0) return ret;
73
74 /*
75 * 0 is "wildcard", or "both" protocols
76 */
77 if ((a->proto == IPPROTO_IP) || (b->proto == IPPROTO_IP)) return 0;
78
79 return CMP(a->proto, b->proto);
80}
81
82#endif
83
85{
86 TALLOC_FREE(root_clients);
87}
88
89/** Free a client
90 *
91 * It's up to the caller to ensure that it's deleted from any fr_client_list_t.
92 */
94{
95 if (!client) return;
96
97 talloc_free(client);
98}
99
100/** Return a new client list
101 *
102 * @note The container won't contain any clients.
103 *
104 * @return
105 * - New client list on success.
106 * - NULL on error (OOM).
107 */
109{
110 fr_client_list_t *clients = talloc_zero(cs, fr_client_list_t);
111
112 if (!clients) return NULL;
113
114 clients->name = talloc_strdup(clients, cs ? cf_section_name1(cs) : "root");
115
116#ifdef WITH_TRIE
117 clients->v4_udp = fr_trie_alloc(clients, NULL, NULL);
118 if (!clients->v4_udp) {
119 talloc_free(clients);
120 return NULL;
121 }
122
123 clients->v6_udp = fr_trie_alloc(clients, NULL, NULL);
124 if (!clients->v6_udp) {
125 talloc_free(clients);
126 return NULL;
127 }
128
129 clients->v4_tcp = fr_trie_alloc(clients, NULL, NULL);
130 if (!clients->v4_tcp) {
131 talloc_free(clients);
132 return NULL;
133 }
134
135 clients->v6_tcp = fr_trie_alloc(clients, NULL, NULL);
136 if (!clients->v6_tcp) {
137 talloc_free(clients);
138 return NULL;
139 }
140#endif /* WITH_TRIE */
141
142 return clients;
143}
144
145#ifdef WITH_TRIE
146/*
147 * @todo - either support client definitions where "proto = *",
148 * or update this code to allow for that. i.e. we create yet
149 * another set of v4/v6 tries, for "proto = *" clients. And then
150 * do lookups there, too. Or, just unify the udp/tcp tries, and
151 * instead do post-processing? Though those two clients can have
152 * different secrets... and the trie code doesn't allow 2
153 * fr_trie_user_t nodes in a row. So we would have to instead
154 * handle that ourselves, with a wrapper around the fr_client_t
155 * structure that does udp/tcp/wildcard demultiplexing
156 */
157static fr_trie_t *clients_trie(fr_client_list_t const *clients, fr_ipaddr_t const *ipaddr,
158 int proto)
159{
160 if (ipaddr->af == AF_INET) {
161 if (proto == IPPROTO_TCP) return clients->v4_tcp;
162
163 return clients->v4_udp;
164 }
165
166 fr_assert(ipaddr->af == AF_INET6);
167
168 if (proto == IPPROTO_TCP) return clients->v6_tcp;
169
170 return clients->v6_udp;
171}
172#endif /* WITH_TRIE */
173
174/** Add a client to a fr_client_list_t
175 *
176 * @param clients list to add client to, may be NULL if global client list is being used.
177 * @param client to add.
178 * @return
179 * - true on success.
180 * - false on failure.
181 */
183{
184#ifdef WITH_TRIE
185 fr_trie_t *trie;
186#else
187#endif
188 fr_client_t *old;
190
191 if (!client) return false;
192
193 /*
194 * Hack to fixup wildcard clients
195 *
196 * If the IP is all zeros, with a 32 or 128 bit netmask
197 * assume the user meant to configure 0.0.0.0/0 instead
198 * of 0.0.0.0/32 - which would require the src IP of
199 * the client to be all zeros.
200 */
201 if (fr_ipaddr_is_inaddr_any(&client->ipaddr) == 1) switch (client->ipaddr.af) {
202 case AF_INET:
203 if (client->ipaddr.prefix == 32) client->ipaddr.prefix = 0;
204 break;
205
206 case AF_INET6:
207 if (client->ipaddr.prefix == 128) client->ipaddr.prefix = 0;
208 break;
209
210 default:
211 fr_assert(0);
212 }
213
214 fr_inet_ntop_prefix(buffer, sizeof(buffer), &client->ipaddr);
215 DEBUG3("Adding client %s (%s) to prefix tree %i", buffer, client->longname, client->ipaddr.prefix);
216
217 /*
218 * If "clients" is NULL, it means add to the global list,
219 * unless we're trying to add it to a virtual server...
220 */
221 if (!clients) {
222 if (client->server != NULL) {
223 CONF_SECTION *cs;
224 CONF_SECTION *subcs;
225
226 if (!client->cs) {
227 ERROR("Failed to find configuration section in client. Ignoring 'virtual_server' directive");
228 return false;
229 }
230
231 cs = cf_section_find(cf_root(client->cs), "server", client->server);
232 if (!cs) {
233 ERROR("Failed to find virtual server %s", client->server);
234 return false;
235 }
236
237 /*
238 * If this server has no "listen" section, add the clients
239 * to the global client list.
240 */
241 subcs = cf_section_find(cs, "listen", NULL);
242 if (!subcs) goto global_clients;
243
244 /*
245 * If the client list already exists, use that.
246 * Otherwise, create a new client list.
247 */
248 clients = cf_data_value(cf_data_find(cs, fr_client_list_t, NULL));
249 if (!clients) {
250 MEM(clients = client_list_init(cs));
251 if (!cf_data_add(cs, clients, NULL, true)) {
252 ERROR("Failed to associate clients with virtual server %s", client->server);
253 talloc_free(clients);
254 return false;
255 }
256 }
257
258 } else {
259 global_clients:
260 /*
261 * Initialize the global list, if not done already.
262 */
263 if (!root_clients) {
265 if (!root_clients) return false;
266 }
267 clients = root_clients;
268 }
269 }
270
271#define namecmp(a) ((!old->a && !client->a) || (old->a && client->a && (strcmp(old->a, client->a) == 0)))
272
273#ifdef WITH_TRIE
274 trie = clients_trie(clients, &client->ipaddr, client->proto);
275
276 /*
277 * Cannot insert the same client twice.
278 */
279 old = fr_trie_match_by_key(trie, &client->ipaddr.addr, client->ipaddr.prefix);
280
281#else /* WITH_TRIE */
282
283 if (!clients->tree[client->ipaddr.prefix]) {
284 clients->tree[client->ipaddr.prefix] = fr_rb_inline_talloc_alloc(clients, fr_client_t, node, client_cmp,
285 NULL);
286 if (!clients->tree[client->ipaddr.prefix]) {
287 return false;
288 }
289 }
290
291 old = fr_rb_find(clients->tree[client->ipaddr.prefix], client);
292#endif
293 if (old) {
294 /*
295 * If it's a complete duplicate, then free the new
296 * one, and return "OK".
297 */
298 if (namecmp(longname) && namecmp(secret) &&
299 namecmp(shortname) && namecmp(nas_type) &&
300 namecmp(server) &&
302 WARN("Ignoring duplicate client %s", client->longname);
303 client_free(client);
304 return true;
305 }
306
307 ERROR("Failed to add duplicate client %s", client->shortname);
308 return false;
309 }
310#undef namecmp
311
312#ifdef WITH_TRIE
313 /*
314 * Other error adding client: likely is fatal.
315 */
316 if (fr_trie_insert_by_key(trie, &client->ipaddr.addr, client->ipaddr.prefix, client) < 0) {
317 return false;
318 }
319#else
320 if (!fr_rb_insert(clients->tree[client->ipaddr.prefix], client)) {
321 return false;
322 }
323#endif
324
325 /*
326 * @todo - do we want to do this for dynamic clients?
327 */
328 (void) talloc_steal(clients, client); /* reparent it */
329
330 return true;
331}
332
333
335{
336#ifdef WITH_TRIE
337 fr_trie_t *trie;
338#endif
339
340 if (!client) return;
341
342 if (!clients) clients = root_clients;
343
344 fr_assert(client->ipaddr.prefix <= 128);
345
346#ifdef WITH_TRIE
347 trie = clients_trie(clients, &client->ipaddr, client->proto);
348
349 /*
350 * Don't free the client. The caller is responsible for that.
351 */
352 (void) fr_trie_remove_by_key(trie, &client->ipaddr.addr, client->ipaddr.prefix);
353#else
354
355 if (!clients->tree[client->ipaddr.prefix]) return;
356
357 (void) fr_rb_delete(clients->tree[client->ipaddr.prefix], client);
358#endif
359}
360
362{
363 return NULL;
364}
365
366
367/*
368 * Find a client in the fr_client_t list.
369 */
370fr_client_t *client_find(fr_client_list_t const *clients, fr_ipaddr_t const *ipaddr, int proto)
371{
372#ifdef WITH_TRIE
373 fr_trie_t *trie;
374#else
375 int i, max;
376 fr_client_t my_client, *client;
377#endif
378
379 if (!clients) clients = root_clients;
380
381 if (!clients || !ipaddr) return NULL;
382
383#ifdef WITH_TRIE
384 trie = clients_trie(clients, ipaddr, proto);
385
386 return fr_trie_lookup_by_key(trie, &ipaddr->addr, ipaddr->prefix);
387#else
388
389 if (ipaddr->af == AF_INET) {
390 max = 32;
391 } else {
392 max = 128;
393 }
394
395 if (max > ipaddr->prefix) max = ipaddr->prefix;
396
397 my_client.proto = proto;
398 for (i = max; i >= 0; i--) {
399 if (!clients->tree[i]) continue;
400
401 my_client.ipaddr = *ipaddr;
402 fr_ipaddr_mask(&my_client.ipaddr, i);
403 client = fr_rb_find(clients->tree[i], &my_client);
404 if (client) {
405 return client;
406 }
407 }
408
409 return NULL;
410#endif
411}
412
414static char const *cl_srcipaddr = NULL;
415static char const *hs_proto = NULL;
416
418 { FR_CONF_OFFSET("max_connections", fr_client_t, limit.max_connections), .dflt = "16" },
419
420 { FR_CONF_OFFSET("lifetime", fr_client_t, limit.lifetime), .dflt = "0" },
421
422 { FR_CONF_OFFSET("idle_timeout", fr_client_t, limit.idle_timeout), .dflt = "30s" },
424};
425
426static const conf_parser_t client_config[] = {
428 { FR_CONF_POINTER("ipv4addr", FR_TYPE_IPV4_PREFIX, 0, &cl_ipaddr) },
429 { FR_CONF_POINTER("ipv6addr", FR_TYPE_IPV6_PREFIX, 0, &cl_ipaddr) },
430
431 { FR_CONF_POINTER("src_ipaddr", FR_TYPE_STRING, 0, &cl_srcipaddr) },
432
434 { FR_CONF_OFFSET("shortname", fr_client_t, shortname) },
435
436 { FR_CONF_OFFSET("nas_type", fr_client_t, nas_type) },
437
438 { FR_CONF_OFFSET_IS_SET("require_message_authenticator", FR_TYPE_UINT32, 0, fr_client_t, require_message_authenticator),
441 .dflt = "no" },
442
443 { FR_CONF_OFFSET_IS_SET("limit_proxy_state", FR_TYPE_UINT32, 0, fr_client_t, limit_proxy_state),
444 .func = cf_table_parse_int,
446 .dflt = "auto" },
447
448 { FR_CONF_OFFSET("protocol_error", fr_client_t, protocol_error) },
449
450 { FR_CONF_OFFSET("response_window", fr_client_t, response_window) },
451
452#ifdef NAS_VIOLATES_RFC
453 /*
454 * For vendors who violate the RFCs and go out of their way to make their systems vulnerable.
455 */
456 { FR_CONF_OFFSET("nas_violates_message_authenticator_rfc", fr_client_t, allow_vulnerable_clients) },
457#endif
458
459 { FR_CONF_POINTER("proto", FR_TYPE_STRING, 0, &hs_proto) },
460 { FR_CONF_POINTER("limit", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) limit_config },
461
463};
464
465/** Create a list of clients from a client section
466 *
467 * Iterates over all client definitions in the specified section, adding them to a client list.
468 */
469#ifdef WITH_TLS
470#define TLS_UNUSED
471#else
472#define TLS_UNUSED UNUSED
473#endif
474
476{
477 bool global = false;
478 CONF_SECTION *cs = NULL;
479 fr_client_t *c = NULL;
480 fr_client_list_t *clients = NULL;
481 CONF_SECTION *server_cs = NULL;
482
483 /*
484 * Be forgiving. If there's already a clients, return
485 * it. Otherwise create a new one.
486 */
487 clients = cf_data_value(cf_data_find(section, fr_client_list_t, NULL));
488 if (clients) return clients;
489
490 /*
491 * Parent the client list from the section.
492 */
493 clients = client_list_init(section);
494 if (!clients) return NULL;
495
496 /*
497 * If the section is hung off the config root, this is
498 * the global client list, else it's virtual server
499 * specific client list.
500 */
501 if (cf_root(section) == section) global = true;
502
503 if (strcmp("server", cf_section_name1(section)) == 0) server_cs = section;
504
505 /*
506 * Iterate over all the clients in the section, adding
507 * them to the client list.
508 */
509 while ((cs = cf_section_find_next(section, cs, "client", CF_IDENT_ANY))) {
510 /*
511 * Check this before parsing the client.
512 */
513 if (proto) {
514 CONF_PAIR *cp;
515 int client_proto = IPPROTO_UDP;
516
517 cp = cf_pair_find(cs, "proto");
518 if (cp) {
519 char const *value = cf_pair_value(cp);
520
521 if (!value) {
522 cf_log_err(cs, "'proto' field must have a value");
523 talloc_free(clients);
524 return NULL;
525 }
526
527 if (strcmp(value, "udp") == 0) {
528 /* do nothing */
529
530 } else if (strcmp(value, "tcp") == 0) {
531 client_proto = IPPROTO_TCP;
532#ifdef WITH_TLS
533 } else if (strcmp(value, "tls") == 0) {
534 client_proto = IPPROTO_TCP;
535#endif
536 } else if (strcmp(value, "*") == 0) {
537 client_proto = IPPROTO_IP; /* fake for dual */
538 } else {
539 cf_log_err(cs, "Unknown proto \"%s\".", value);
540 talloc_free(clients);
541 return NULL;
542 }
543 }
544
545 /*
546 * We don't have "proto = *", so the
547 * protocol MUST match what the caller
548 * asked for. Otherwise, we ignore the
549 * client.
550 */
551 if ((client_proto != IPPROTO_IP) && (proto != client_proto)) continue;
552 }
553
554
555 c = client_afrom_cs(cs, cs, server_cs, 0);
556 if (!c) {
557 error:
558 client_free(c);
559 talloc_free(clients);
560 return NULL;
561 }
562
563 /*
564 * TCP sockets are always connected.
565 */
566 c->use_connected |= (c->proto == IPPROTO_TCP);
567
568#ifdef WITH_TLS
569 /*
570 * TLS clients CANNOT use non-TLS listeners.
571 * non-TLS clients CANNOT use TLS listeners.
572 */
573 if (tls_required != c->tls_required) {
574 cf_log_err(cs, "Client does not have the same TLS configuration as the listener");
575 goto error;
576 }
577#endif
578
579 if (!client_add(clients, c)) {
580 cf_log_err(cs, "Failed to add client %s", cf_section_name2(cs));
581 goto error;
582 }
583
585 }
586
587 /*
588 * Associate the clients structure with the section.
589 */
590 if (!cf_data_add(section, clients, NULL, false)) {
591 cf_log_err(section, "Failed to associate clients with section %s", cf_section_name1(section));
592 talloc_free(clients);
593 return NULL;
594 }
595
596 /*
597 * Replace the global list of clients with the new one.
598 * The old one is still referenced from the original
599 * configuration, and will be freed when that is freed.
600 */
601 if (global) root_clients = clients;
602
603 return clients;
604}
605
606/** Create a client CONF_SECTION using a mapping section to map values from a result set to client attributes
607 *
608 * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too.
609 *
610 * @note Caller should free CONF_SECTION passed in as out, on error.
611 * Contents of that section will be in an undefined state.
612 *
613 * @param[in,out] out Section to perform mapping on. Either the root of the client config, or a parent section
614 * (when this function is called recursively).
615 * Should be alloced with cf_section_alloc, or if there's a separate template section, the
616 * result of calling cf_section_dup on that section.
617 * @param[in] map section.
618 * @param[in] func to call to retrieve CONF_PAIR values. Must return a talloced buffer containing the value.
619 * @param[in] data to pass to func, usually a result pointer.
620 * @return
621 * - 0 on success.
622 * - -1 on failure.
623 */
625{
626 CONF_ITEM const *ci;
627
628 for (ci = cf_item_next(map, NULL);
629 ci != NULL;
630 ci = cf_item_next(map, ci)) {
631 CONF_PAIR const *cp;
632 CONF_PAIR *old;
633 char *value;
634 char const *attr;
635
636 /*
637 * Recursively process map subsection
638 */
639 if (cf_item_is_section(ci)) {
640 CONF_SECTION *cs, *cc;
641
642 cs = cf_item_to_section(ci);
643 /*
644 * Use pre-existing section or alloc a new one
645 */
647 if (!cc) {
649 if (!cc) return -1;
650 }
651
652 if (client_map_section(cc, cs, func, data) < 0) return -1;
653 continue;
654 }
655
656 cp = cf_item_to_pair(ci);
657 attr = cf_pair_attr(cp);
658
659 /*
660 * The callback can return 0 (success) and not provide a value
661 * in which case we skip the mapping pair.
662 *
663 * Or return -1 in which case we error out.
664 */
665 if (func(&value, cp, data) < 0) {
666 cf_log_err(out, "Failed performing mapping \"%s\" = \"%s\"", attr, cf_pair_value(cp));
667 return -1;
668 }
669 if (!value) continue;
670
671 /*
672 * Replace an existing CONF_PAIR
673 */
674 old = cf_pair_find(out, attr);
675 if (old) {
678 continue;
679 }
680
681 /*
682 * ...or add a new CONF_PAIR
683 */
685 if (!cp) {
686 cf_log_err(out, "Failed allocing pair \"%s\" = \"%s\"", attr, value);
688 return -1;
689 }
692 }
693
694 return 0;
695}
696
697/** Allocate a new client from a config section
698 *
699 * @param ctx to allocate new clients in.
700 * @param cs to process as a client.
701 * @param server_cs The virtual server that this client belongs to.
702 * @param extra 0 allocate sizeof(fr_client_t) bytes
703 * >sizeof(client_t) number of bytes to allocate
704 * @return new fr_client_t struct.
705 */
706fr_client_t *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *server_cs, size_t extra)
707{
708 fr_client_t *c;
709 char const *name2;
710 CONF_PAIR *cp;
711
712 name2 = cf_section_name2(cs);
713 if (!name2) {
714 cf_log_err(cs, "Missing client name");
715 return NULL;
716 }
717
718 /*
719 * The size is fine.. Let's create the buffer
720 */
721 if (!extra) {
722 c = talloc_zero(ctx, fr_client_t);
723 if (!c) return NULL;
724 } else {
725 fr_assert(extra > sizeof(fr_client_t));
726
727 c = (fr_client_t *) talloc_zero_array(ctx, uint8_t, extra);
728 if (!c) return NULL;
729
730 talloc_set_name_const(c, "fr_client_t");
731 }
732
733 c->cs = cs;
734
735 memset(&cl_ipaddr, 0, sizeof(cl_ipaddr));
736 if (cf_section_rules_push(cs, client_config) < 0) goto error;
737
738 if (cf_section_parse(c, c, cs) < 0) {
739 cf_log_err(cs, "Error parsing client section");
740 error:
741 client_free(c);
742 hs_proto = NULL;
743 cl_srcipaddr = NULL;
744 return NULL;
745 }
746
747 /*
748 * Allow for binary secrets.
749 */
750 cp = cf_pair_find(cs, "secret");
751 if (cp && (cf_pair_operator(cp) == T_BARE_WORD)) {
752 char const *value;
753
754 value = cf_pair_value(cp);
755 if ((value[0] == '0') && (value[1] == 'x')) {
756 size_t bin_len, hex_len, converted;
757 uint8_t *bin;
758
759 /*
760 * '0x...' plus trailing NUL.
761 */
762 hex_len = talloc_array_length(value) - 3;
763 bin_len = (hex_len / 2) + 1;
764 MEM(bin = talloc_array(c, uint8_t, bin_len));
765 converted = fr_base16_decode(NULL,
766 &FR_DBUFF_TMP(bin, bin_len),
767 &FR_SBUFF_IN(value + 2, hex_len), false);
768 if (converted < (bin_len - 1)) {
769 cf_log_err(cs, "Invalid hex string in shared secret");
770 goto error;
771 }
772
774 c->secret = (char const *) bin;
775 }
776 }
777
778 /*
779 * Find the virtual server for this client.
780 */
781 if (c->server) {
782 virtual_server_t const *vs;
783 if (server_cs) {
784 cf_log_err(cs, "Clients inside of a 'server' section cannot point to a server");
785 goto error;
786 }
787
789 if (!vs) goto error;
790
792 if (!c->server_cs) {
793 cf_log_err(cs, "Failed to find virtual server %s", c->server);
794 goto error;
795 }
796
797 } else if (server_cs) {
798 c->server = cf_section_name2(server_cs);
799 c->server_cs = server_cs;
800
801 } /* else don't set c->server or c->server_cs, we will use listener->server */
802
803 /*
804 * Newer style client definitions with either ipaddr or ipaddr6
805 * config items.
806 */
807 if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
808 char buffer[128];
809
810 /*
811 * Sets ipv4/ipv6 address and prefix.
812 */
813 c->ipaddr = cl_ipaddr;
814
815 /*
816 * Set the long name to be the result of a reverse lookup on the IP address.
817 */
818 fr_inet_ntoh(&c->ipaddr, buffer, sizeof(buffer));
820
821 /*
822 * Set the short name to the name2.
823 */
824 if (!c->shortname) c->shortname = talloc_strdup(c, name2);
825 /*
826 * No "ipaddr" or "ipv6addr", use old-style "client <ipaddr> {" syntax.
827 */
828 } else {
829 cf_log_err(cs, "No 'ipaddr' or 'ipv4addr' or 'ipv6addr' configuration "
830 "directive found in client %s", name2);
831 goto error;
832 }
833
834 c->proto = IPPROTO_UDP;
835 if (hs_proto) {
836 if (strcmp(hs_proto, "udp") == 0) {
837 hs_proto = NULL;
838
839 } else if (strcmp(hs_proto, "tcp") == 0) {
840 hs_proto = NULL;
841 c->proto = IPPROTO_TCP;
842#ifdef WITH_TLS
843 } else if (strcmp(hs_proto, "tls") == 0) {
844 hs_proto = NULL;
845 c->proto = IPPROTO_TCP;
846 c->tls_required = true;
847
848#endif
849 } else if (strcmp(hs_proto, "*") == 0) {
850 hs_proto = NULL;
851 c->proto = IPPROTO_IP; /* fake for dual */
852 } else {
853 cf_log_err(cs, "Unknown proto \"%s\".", hs_proto);
854 goto error;
855 }
856 }
857
858 /*
859 * If a src_ipaddr is specified, when we send the return packet
860 * we will use this address instead of the src from the
861 * request.
862 */
863 if (cl_srcipaddr) {
864 switch (c->ipaddr.af) {
865 case AF_INET:
866 if (fr_inet_pton4(&c->src_ipaddr, cl_srcipaddr, -1, true, false, true) < 0) {
867 cf_log_perr(cs, "Failed parsing src_ipaddr");
868 goto error;
869 }
870 break;
871
872 case AF_INET6:
873 if (fr_inet_pton6(&c->src_ipaddr, cl_srcipaddr, -1, true, false, true) < 0) {
874 cf_log_perr(cs, "Failed parsing src_ipaddr");
875 goto error;
876 }
877 break;
878 default:
879 cf_log_err(cs, "ipaddr was not defined");
880 goto error;
881 }
882 cl_srcipaddr = NULL;
883 } else {
884 c->src_ipaddr.af = c->ipaddr.af; /* leave the rest as IFADDR_ANY */
885 }
886
887 /*
888 * A response_window of zero is OK, and means that it's
889 * ignored by the rest of the server timers.
890 */
892 FR_TIME_DELTA_BOUND_CHECK("response_window", c->response_window, >=, fr_time_delta_from_usec(1000));
895 }
896
897#ifdef WITH_TLS
898 /*
899 * If the client is TLS only, the secret can be
900 * omitted. When omitted, it's hard-coded to
901 * "radsec". See RFC 6614.
902 */
903 if (c->tls_required) {
904 if (c->secret) {
905 if (strcmp(c->secret, "radsec") != 0) {
906 cf_log_warn(cs, "'secret' is not 'radsec' for TLS");
907 cf_log_warn(cs, "Packets may not be processed correctly!");
908 }
909 } else {
910 c->secret = talloc_strdup(cs, "radsec");
911 }
912 }
913#endif
914
915 if ((c->proto == IPPROTO_TCP) || (c->proto == IPPROTO_IP)) {
922 }
923
925 return c;
926}
927
928/** Create a new client, consuming all attributes in the control list of the request
929 *
930 * @param ctx the talloc context
931 * @param request containing the client attributes.
932 * @return
933 * - New client on success.
934 * - NULL on error.
935 */
936fr_client_t *client_afrom_request(TALLOC_CTX *ctx, request_t *request)
937{
938 static int cnt;
939 CONF_SECTION *cs;
940 fr_client_t *c;
941 fr_sbuff_t *tmp;
942
943 if (!request) return NULL;
944
945 FR_SBUFF_TALLOC_THREAD_LOCAL(&tmp, 128, SIZE_MAX);
946
947 if (unlikely(fr_sbuff_in_sprintf(tmp, "dynamic_%i_", cnt++) <= 0)) {
948 name_error:
949 RERROR("Failed to generate dynamic client name");
950 return NULL;
951 }
952 if (unlikely(fr_value_box_print(tmp, fr_box_ipaddr(request->packet->socket.inet.src_ipaddr), NULL) <= 0)) goto name_error;
953 fr_sbuff_set_to_start(tmp);
954
955 cs = cf_section_alloc(ctx, NULL, "client", fr_sbuff_current(tmp));
956
957 RDEBUG2("Converting control.FreeRADIUS-Client-* to client {...} section");
958 RINDENT();
959
960 fr_pair_list_foreach(&request->control_pairs, vp) {
961 CONF_PAIR *cp = NULL;
962 char const *value;
963 char const *attr;
964 fr_token_t v_token = T_BARE_WORD;
965
966 if (!fr_dict_attr_is_top_level(vp->da)) continue;
967
968 switch (vp->da->attr) {
969 case FR_FREERADIUS_CLIENT_IP_ADDRESS:
970 attr = "ipv4addr";
971 vb_to_str:
972 fr_sbuff_set_to_start(tmp);
974 RERROR("Failed to convert %pP to string", vp);
975 error:
976 talloc_free(cs);
977 return NULL;
978 }
979 value = fr_sbuff_start(tmp);
980 break;
981
982 case FR_FREERADIUS_CLIENT_IP_PREFIX:
983 attr = "ipv4addr";
984 goto vb_to_str;
985
986 case FR_FREERADIUS_CLIENT_IPV6_ADDRESS:
987 attr = "ipv6addr";
988 goto vb_to_str;
989
990 case FR_FREERADIUS_CLIENT_IPV6_PREFIX:
991 attr = "ipv6addr";
992 goto vb_to_str;
993
994 case FR_FREERADIUS_CLIENT_SECRET:
995 attr = "secret";
996 value = vp->vp_strvalue;
997 break;
998
999 case FR_FREERADIUS_CLIENT_NAS_TYPE:
1000 attr = "nas_type";
1001 value = vp->vp_strvalue;
1002 break;
1003
1004 case FR_FREERADIUS_CLIENT_SHORTNAME:
1005 attr = "shortname";
1006 value = vp->vp_strvalue;
1007 break;
1008
1009 case FR_FREERADIUS_CLIENT_SRC_IP_ADDRESS:
1010 attr = "src_ipaddr";
1011 goto vb_to_str;
1012
1013 case FR_FREERADIUS_CLIENT_REQUIRE_MA:
1014 attr = "require_message_authenticator";
1015 goto vb_to_str;
1016
1017 case FR_FREERADIUS_CLIENT_LIMIT_PROXY_STATE:
1018 attr = "limit_proxy_state";
1019 goto vb_to_str;
1020
1021 case FR_FREERADIUS_CLIENT_TRACK_CONNECTIONS:
1022 attr = "track_connections";
1023 goto vb_to_str;
1024
1025 default:
1026 attr = vp->da->name;
1027 fr_sbuff_set_to_start(tmp);
1029 value = fr_sbuff_start(tmp);
1030 v_token = T_SINGLE_QUOTED_STRING;
1031 break;
1032 }
1033
1034 cp = cf_pair_alloc(cs, attr, value, T_OP_SET, T_BARE_WORD, v_token);
1035 if (!cp) {
1036 RERROR("Error creating equivalent conf pair for %s", vp->da->name);
1037 goto error;
1038 }
1039
1040 RDEBUG2("%s = %s", cf_pair_attr(cp), cf_pair_value(cp));
1041 }
1042
1043 REXDENT();
1044
1045 /*
1046 * @todo - allow for setting a DIFFERENT virtual server,
1047 * src IP, protocol, etc. This should all be in TLVs..
1048 */
1049 c = client_afrom_cs(cs, cs, unlang_call_current(request), 0);
1050 if (!c) goto error;
1051
1052 return c;
1053}
1054
1055/** Read a single client from a file
1056 *
1057 * This function supports asynchronous runtime loading of clients.
1058 *
1059 * @param[in] filename To read clients from.
1060 * @param[in] server_cs of virtual server clients should be added to.
1061 * @param[in] check_dns Check reverse lookup of IP address matches filename.
1062 * @return
1063 * - The new client on success.
1064 * - NULL on failure.
1065 */
1066fr_client_t *client_read(char const *filename, CONF_SECTION *server_cs, bool check_dns)
1067{
1068 char const *p;
1069 fr_client_t *c;
1070 CONF_SECTION *root_cs, *cs;
1071 char buffer[256];
1072
1073 if (!filename) return NULL;
1074
1075 root_cs = cf_section_alloc(NULL, NULL, "main", NULL);
1076 if (!root_cs) return NULL;
1077
1078 if ((cf_file_read(root_cs, filename, false) < 0) || (cf_section_pass2(root_cs) < 0)) {
1079 error:
1080 talloc_free(root_cs);
1081 return NULL;
1082 }
1083
1084 cs = cf_section_find(root_cs, "client", CF_IDENT_ANY);
1085 if (!cs) {
1086 ERROR("No \"client\" section found in client file");
1087 goto error;
1088 }
1089
1090 c = client_afrom_cs(cs, cs, server_cs, 0);
1091 if (!c) goto error;
1092
1093 /*
1094 * Detach c from cs (breaking the cs -> c parent link), then make root_cs a child of c. This
1095 * avoids a talloc cycle (c -> root_cs -> cs -> c), and ensures that freeing c also frees root_cs
1096 * and cs.
1097 */
1098 (void) talloc_steal(NULL, c);
1099 (void) talloc_steal(c, root_cs);
1100
1101 p = strrchr(filename, FR_DIR_SEP);
1102 if (p) {
1103 p++;
1104 } else {
1105 p = filename;
1106 }
1107
1108 if (!check_dns) return c;
1109
1110 /*
1111 * Additional validations
1112 */
1113 fr_inet_ntoh(&c->ipaddr, buffer, sizeof(buffer));
1114 if (strcmp(p, buffer) != 0) {
1115 ERROR("Invalid client definition in %s: IP address %s does not match name %s", filename, buffer, p);
1116 talloc_free(c); /* also frees root_cs and cs */
1117 return NULL;
1118 }
1119
1120 return c;
1121}
1122
1123/** Search up a list of requests trying to locate one which has a client
1124 *
1125 */
1127{
1128 fr_client_t *client;
1129 request_t *parent = request;
1130
1131 do {
1132 client = parent->client;
1133 } while (!client && (parent = parent->parent));
1134
1135 return client;
1136}
static int const char char buffer[256]
Definition acutest.h:576
#define fr_base16_decode(_err, _out, _in, _no_trailing)
Definition base16.h:92
#define RCSID(id)
Definition build.h:512
#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:407
#define UNUSED
Definition build.h:336
CONF_SECTION * unlang_call_current(request_t *request)
Return the last virtual server that was called.
Definition call.c:214
int cf_file_read(CONF_SECTION *cs, char const *filename, bool root)
Definition cf_file.c:3657
int cf_section_pass2(CONF_SECTION *cs)
Definition cf_file.c:970
int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
Parse a configuration section into user-supplied variables.
Definition cf_parse.c:1208
int cf_table_parse_int(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic function for parsing conf pair values as int.
Definition cf_parse.c:1636
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:657
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:611
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:280
#define cf_section_rules_push(_cs, _rule)
Definition cf_parse.h:689
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
Definition cf_parse.h:334
#define FR_CONF_OFFSET_IS_SET(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct,...
Definition cf_parse.h:294
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:268
#define FR_TIME_DELTA_BOUND_CHECK(_name, _var, _op, _bound)
Definition cf_parse.h:528
@ CONF_FLAG_SECRET
Only print value if debug level >= 3.
Definition cf_parse.h:433
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition cf_parse.h:423
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:594
Common header for all CONF_* types.
Definition cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:72
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1187
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1750
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
Definition cf_util.c:1269
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
Definition cf_util.c:1173
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:1029
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:685
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition cf_util.c:1422
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
Definition cf_util.c:1595
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:619
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:665
CONF_SECTION * cf_section_find_next(CONF_SECTION const *cs, CONF_SECTION const *prev, char const *name1, char const *name2)
Return the next matching section.
Definition cf_util.c:1050
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1581
int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value)
Replace pair value in a given section with the given value.
Definition cf_util.c:1343
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
Definition cf_util.c:723
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1565
#define cf_item_add(_parent, _child)
Definition cf_util.h:80
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:285
#define cf_data_add(_cf, _data, _name, _free)
Definition cf_util.h:251
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:240
#define cf_root(_cf)
Definition cf_util.h:95
#define cf_item_next(_parent, _curr)
Definition cf_util.h:89
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:292
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:143
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:286
#define cf_item_mark_parsed(_cf)
Definition cf_util.h:133
#define CF_IDENT_ANY
Definition cf_util.h:75
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:522
#define MEM(x)
Definition debug.h:46
#define ERROR(fmt,...)
Definition dhcpclient.c:40
static bool fr_dict_attr_is_top_level(fr_dict_attr_t const *da)
Return true if this attribute is parented directly off the dictionary root.
Definition dict.h:809
Test enumeration values.
Definition dict_test.h:92
talloc_free(hp)
char const * fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
Perform reverse resolution of an IP address.
Definition inet.c:356
char * fr_inet_ntop_prefix(char out[static FR_IPADDR_PREFIX_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
Print a fr_ipaddr_t as a CIDR style network prefix.
Definition inet.c:1080
int fr_inet_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask)
Parse an IPv6 address or IPv6 prefix in presentation format (and others)
Definition inet.c:632
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
Definition inet.c:62
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1353
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
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition inet.h:68
int af
Address family.
Definition inet.h:63
union fr_ipaddr_t::@137 addr
#define FR_IPADDR_PREFIX_STRLEN
Like FR_IPADDR_STRLEN but with space for a prefix.
Definition inet.h:92
IPv4/6 prefix.
fr_time_delta_t response_window
How long the client has to respond.
Definition client.h:145
char const * server
Name of the virtual server client is associated with.
Definition client.h:133
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
Definition client.h:83
fr_radius_require_ma_t require_message_authenticator
Require RADIUS message authenticator for incoming packets.
Definition client.h:94
char const * secret
Secret PSK.
Definition client.h:90
fr_ipaddr_t src_ipaddr
IPv4/IPv6 address to send responses from (family must match ipaddr).
Definition client.h:84
int(* client_value_cb_t)(char **out, CONF_PAIR const *cp, void *data)
Callback for retrieving values when building client sections.
Definition client.h:68
int proto
Protocol number.
Definition client.h:147
CONF_SECTION * cs
CONF_SECTION that was parsed to generate the client.
Definition client.h:138
char const * longname
Client identifier.
Definition client.h:87
fr_socket_limit_t limit
Connections per client (TCP clients only).
Definition client.h:148
char const * shortname
Client nickname.
Definition client.h:88
bool use_connected
do we use connected sockets for this client
Definition client.h:121
CONF_SECTION * server_cs
Virtual server that the client is associated with.
Definition client.h:134
Describes a host allowed to send packets to the server.
Definition client.h:80
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:455
#define DEBUG3(_fmt,...)
Definition log.h:266
#define RERROR(fmt,...)
Definition log.h:310
#define RINDENT()
Indent R* messages by one level.
Definition log.h:442
main_config_t const * main_config
Main server configuration.
Definition main_config.c:58
fr_worker_config_t worker
Worker thread configuration.
Definition main_config.h:61
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
int fr_inet_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask_bits)
unsigned char uint8_t
size_t fr_radius_limit_proxy_state_table_len
Definition base.c:102
size_t fr_radius_require_ma_table_len
Definition base.c:93
fr_table_num_sorted_t const fr_radius_limit_proxy_state_table[]
Definition base.c:95
fr_table_num_sorted_t const fr_radius_require_ma_table[]
Definition base.c:86
#define fr_assert(_expr)
Definition rad_assert.h:37
static char * secret
#define RDEBUG2(fmt,...)
#define WARN(fmt,...)
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
Definition rb.c:741
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Definition rb.h:244
The main red black tree structure.
Definition rb.h:71
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition sbuff.c:1605
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_current(_sbuff_or_marker)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
fr_time_delta_t idle_timeout
Definition socket.h:38
fr_time_delta_t lifetime
Definition socket.h:37
fr_client_t * client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *server_cs, size_t extra)
Allocate a new client from a config section.
Definition client.c:706
fr_client_t * client_find(fr_client_list_t const *clients, fr_ipaddr_t const *ipaddr, int proto)
Definition client.c:370
#define namecmp(a)
static int8_t client_cmp(void const *one, void const *two)
Definition client.c:65
char const * name
Name of the client list.
Definition client.c:51
fr_client_list_t * client_list_init(CONF_SECTION *cs)
Return a new client list.
Definition client.c:108
fr_client_t * client_findbynumber(UNUSED const fr_client_list_t *clients, UNUSED int number)
Definition client.c:361
fr_rb_tree_t * tree[129]
Definition client.c:58
int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_cb_t func, void *data)
Create a client CONF_SECTION using a mapping section to map values from a result set to client attrib...
Definition client.c:624
void client_free(fr_client_t *client)
Free a client.
Definition client.c:93
static fr_ipaddr_t cl_ipaddr
Definition client.c:413
fr_client_t * client_from_request(request_t *request)
Search up a list of requests trying to locate one which has a client.
Definition client.c:1126
#define TLS_UNUSED
Create a list of clients from a client section.
Definition client.c:472
static conf_parser_t limit_config[]
Definition client.c:417
fr_client_t * client_read(char const *filename, CONF_SECTION *server_cs, bool check_dns)
Read a single client from a file.
Definition client.c:1066
static char const * cl_srcipaddr
Definition client.c:414
static const conf_parser_t client_config[]
Definition client.c:426
static fr_client_list_t * root_clients
Global client list.
Definition client.c:62
fr_client_t * client_afrom_request(TALLOC_CTX *ctx, request_t *request)
Create a new client, consuming all attributes in the control list of the request.
Definition client.c:936
void client_list_free(void)
Definition client.c:84
fr_client_list_t * client_list_parse_section(CONF_SECTION *section, int proto, TLS_UNUSED bool tls_required)
Definition client.c:475
void client_delete(fr_client_list_t *clients, fr_client_t *client)
Definition client.c:334
bool client_add(fr_client_list_t *clients, fr_client_t *client)
Add a client to a fr_client_list_t.
Definition client.c:182
static char const * hs_proto
Definition client.c:415
Group of clients.
Definition client.c:50
fr_pair_t * vp
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:253
#define talloc_strdup(_ctx, _str)
Definition talloc.h:142
#define fr_time_delta_lt(_a, _b)
Definition time.h:285
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_delta_ispos(_a)
Definition time.h:290
static fr_time_delta_t fr_time_delta_from_usec(int64_t usec)
Definition time.h:568
enum fr_token fr_token_t
@ T_SINGLE_QUOTED_STRING
Definition token.h:120
@ T_BARE_WORD
Definition token.h:118
@ T_OP_SET
Definition token.h:82
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
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
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition pair.h:279
ssize_t fr_pair_print_value_quoted(fr_sbuff_t *out, fr_pair_t const *vp, fr_token_t quote)
Print the value of an attribute to a string.
Definition pair_print.c:59
static fr_slen_t parent
Definition pair.h:858
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
Definition value.c:6090
fr_sbuff_escape_rules_t const fr_value_escape_single
Definition value.c:393
#define fr_box_ipaddr(_val)
Definition value.h:317
static fr_slen_t data
Definition value.h:1340
static size_t char ** out
Definition value.h:1030
virtual_server_t const * virtual_server_find(char const *name)
Return virtual server matching the specified name.
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.
fr_time_delta_t max_request_time
maximum time a request can be processed
Definition worker.h:76