2 * This program is 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.
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.
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
20 * @brief Manage clients allowed to communicate with the server.
22 * @copyright 2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23 * @copyright 2000,2006 The FreeRADIUS server project
24 * @copyright 2000 Alan DeKok <aland@ox.org>
25 * @copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
29 #include <freeradius-devel/radiusd.h>
30 #include <freeradius-devel/rad_assert.h>
37 #ifdef WITH_DYNAMIC_CLIENTS
43 struct radclient_list {
45 * FIXME: One set of trees for IPv4, and another for IPv6?
47 rbtree_t *trees[129]; /* for 0..128, inclusive. */
53 static rbtree_t *tree_num = NULL; /* client numbers 0..N */
54 static int tree_num_max = 0;
56 static RADCLIENT_LIST *root_clients = NULL;
58 #ifdef WITH_DYNAMIC_CLIENTS
59 static fr_fifo_t *deleted_clients = NULL;
63 * Callback for freeing a client.
65 void client_free(RADCLIENT *client)
69 #ifdef WITH_DYNAMIC_CLIENTS
70 if (client->dynamic == 2) {
73 if (!deleted_clients) {
74 deleted_clients = fr_fifo_create(NULL, 1024, (void (*)(void *))client_free);
75 if (!deleted_clients) return; /* MEMLEAK */
79 * Mark it as in the fifo, and remember when we
83 client->created = now = time(NULL); /* re-set it */
84 fr_fifo_push(deleted_clients, client);
87 * Peek at the head of the fifo. If it might
88 * still be in use, return. Otherwise, pop it
89 * from the queue and delete it.
91 client = fr_fifo_peek(deleted_clients);
92 rad_assert(client != NULL);
94 if ((client->created + 120) >= now) return;
96 client = fr_fifo_pop(deleted_clients);
97 rad_assert(client != NULL);
105 * Callback for comparing two clients.
107 static int client_ipaddr_cmp(void const *one, void const *two)
109 RADCLIENT const *a = one;
110 RADCLIENT const *b = two;
113 return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
117 rcode = fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
118 if (rcode != 0) return rcode;
123 if ((a->proto == IPPROTO_IP) ||
124 (b->proto == IPPROTO_IP)) return 0;
126 return (a->proto - b->proto);
131 static int client_num_cmp(void const *one, void const *two)
133 RADCLIENT const *a = one;
134 RADCLIENT const *b = two;
136 return (a->number - b->number);
141 * Free a RADCLIENT list.
143 void client_list_free(RADCLIENT_LIST *clients)
147 if (!clients) clients = root_clients;
148 if (!clients) return; /* Clients may not have been initialised yet */
150 for (i = 0; i <= 128; i++) {
151 if (clients->trees[i]) rbtree_free(clients->trees[i]);
152 clients->trees[i] = NULL;
155 if (clients == root_clients) {
157 if (tree_num) rbtree_free(tree_num);
164 #ifdef WITH_DYNAMIC_CLIENTS
166 * FIXME: No fr_fifo_delete()
170 talloc_free(clients);
174 * Return a new, initialized, set of clients.
176 RADCLIENT_LIST *client_list_init(CONF_SECTION *cs)
178 RADCLIENT_LIST *clients = talloc_zero(cs, RADCLIENT_LIST);
180 if (!clients) return NULL;
182 clients->min_prefix = 128;
187 /** Add a client to a RADCLIENT_LIST
189 * @param clients list to add client to, may be NULL if global client list is being used.
190 * @param client to add.
191 * @return true on success, false on failure.
193 bool client_add(RADCLIENT_LIST *clients, RADCLIENT *client)
196 char buffer[INET6_ADDRSTRLEN + 3];
198 if (!client) return false;
201 * Hack to fixup wildcard clients
203 * If the IP is all zeros, with a 32 or 128 bit netmask
204 * assume the user meant to configure 0.0.0.0/0 instead
205 * of 0.0.0.0/32 - which would require the src IP of
206 * the client to be all zeros.
208 if (fr_inaddr_any(&client->ipaddr) == 1) switch (client->ipaddr.af) {
210 if (client->ipaddr.prefix == 32) client->ipaddr.prefix = 0;
214 if (client->ipaddr.prefix == 128) client->ipaddr.prefix = 0;
221 fr_ntop(buffer, sizeof(buffer), &client->ipaddr);
222 DEBUG3("Adding client %s (%s) to prefix tree %i", buffer, client->longname, client->ipaddr.prefix);
225 * If the client also defines a server, do that now.
227 if (client->defines_coa_server) if (!realm_home_server_add(client->coa_server)) return false;
230 * If "clients" is NULL, it means add to the global list,
231 * unless we're trying to add it to a virtual server...
234 if (client->server != NULL) {
238 cs = cf_section_sub_find_name2(main_config.config, "server", client->server);
240 ERROR("Failed to find virtual server %s", client->server);
245 * If this server has no "listen" section, add the clients
246 * to the global client list.
248 subcs = cf_section_sub_find(cs, "listen");
249 if (!subcs) goto global_clients;
252 * If the client list already exists, use that.
253 * Otherwise, create a new client list.
255 clients = cf_data_find(cs, "clients");
257 clients = client_list_init(cs);
259 ERROR("Out of memory");
263 if (cf_data_add(cs, "clients", clients, (void (*)(void *)) client_list_free) < 0) {
264 ERROR("Failed to associate clients with virtual server %s", client->server);
265 client_list_free(clients);
273 * Initialize the global list, if not done already.
276 root_clients = client_list_init(NULL);
277 if (!root_clients) return false;
279 clients = root_clients;
284 * Create a tree for it.
286 if (!clients->trees[client->ipaddr.prefix]) {
287 clients->trees[client->ipaddr.prefix] = rbtree_create(clients, client_ipaddr_cmp, NULL, 0);
288 if (!clients->trees[client->ipaddr.prefix]) {
293 #define namecmp(a) ((!old->a && !client->a) || (old->a && client->a && (strcmp(old->a, client->a) == 0)))
296 * Cannot insert the same client twice.
298 old = rbtree_finddata(clients->trees[client->ipaddr.prefix], client);
301 * If it's a complete duplicate, then free the new
302 * one, and return "OK".
304 if ((fr_ipaddr_cmp(&old->ipaddr, &client->ipaddr) == 0) &&
305 (old->ipaddr.prefix == client->ipaddr.prefix) &&
306 namecmp(longname) && namecmp(secret) &&
307 namecmp(shortname) && namecmp(nas_type) &&
308 namecmp(login) && namecmp(password) && namecmp(server) &&
309 #ifdef WITH_DYNAMIC_CLIENTS
310 (old->lifetime == client->lifetime) &&
311 namecmp(client_server) &&
315 (old->coa_server == client->coa_server) &&
316 (old->coa_pool == client->coa_pool) &&
318 (old->message_authenticator == client->message_authenticator)) {
319 WARN("Ignoring duplicate client %s", client->longname);
324 ERROR("Failed to add duplicate client %s", client->shortname);
330 * Other error adding client: likely is fatal.
332 if (!rbtree_insert(clients->trees[client->ipaddr.prefix], client)) {
338 tree_num = rbtree_create(clients, client_num_cmp, NULL, 0);
341 #ifdef WITH_DYNAMIC_CLIENTS
343 * More catching of clients added by rlm_sql.
345 * The sql modules sets the dynamic flag BEFORE calling
346 * us. The client_afrom_request() function sets it AFTER
349 if (client->dynamic && (client->lifetime == 0)) {
353 * If there IS an enclosing network,
354 * inherit the lifetime from it.
356 network = client_find(clients, &client->ipaddr, client->proto);
358 client->lifetime = network->lifetime;
363 client->number = tree_num_max;
365 if (tree_num) rbtree_insert(tree_num, client);
368 if (client->ipaddr.prefix < clients->min_prefix) {
369 clients->min_prefix = client->ipaddr.prefix;
372 (void) talloc_steal(clients, client); /* reparent it */
378 #ifdef WITH_DYNAMIC_CLIENTS
379 void client_delete(RADCLIENT_LIST *clients, RADCLIENT *client)
383 if (!clients) clients = root_clients;
385 if (!client->dynamic) return;
387 rad_assert(client->ipaddr.prefix <= 128);
389 client->dynamic = 2; /* signal to client_free */
392 rbtree_deletebydata(tree_num, client);
394 rbtree_deletebydata(clients->trees[client->ipaddr.prefix], client);
400 * Find a client in the RADCLIENTS list by number.
401 * This is a support function for the statistics code.
403 RADCLIENT *client_findbynumber(RADCLIENT_LIST const *clients, int number)
405 if (!clients) clients = root_clients;
407 if (!clients) return NULL;
409 if (number >= tree_num_max) return NULL;
414 myclient.number = number;
416 return rbtree_finddata(tree_num, &myclient);
422 RADCLIENT *client_findbynumber(UNUSED const RADCLIENT_LIST *clients, UNUSED int number)
430 * Find a client in the RADCLIENTS list.
432 RADCLIENT *client_find(RADCLIENT_LIST const *clients, fr_ipaddr_t const *ipaddr, int proto)
434 int32_t i, max_prefix;
437 if (!clients) clients = root_clients;
439 if (!clients || !ipaddr) return NULL;
441 switch (ipaddr->af) {
454 for (i = max_prefix; i >= (int32_t) clients->min_prefix; i--) {
457 myclient.ipaddr = *ipaddr;
458 myclient.proto = proto;
459 fr_ipaddr_mask(&myclient.ipaddr, i);
461 if (!clients->trees[i]) continue;
463 data = rbtree_finddata(clients->trees[i], &myclient);
464 if (data) return data;
471 * Old wrapper for client_find
473 RADCLIENT *client_find_old(fr_ipaddr_t const *ipaddr)
475 return client_find(root_clients, ipaddr, IPPROTO_UDP);
478 static fr_ipaddr_t cl_ipaddr;
479 static uint32_t cl_netmask;
480 static char const *cl_srcipaddr = NULL;
481 static char const *hs_proto = NULL;
484 static CONF_PARSER limit_config[] = {
485 { "max_connections", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.max_connections), "16" },
487 { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.lifetime), "0" },
489 { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.idle_timeout), "30" },
491 CONF_PARSER_TERMINATOR
495 static const CONF_PARSER client_config[] = {
496 { "ipaddr", FR_CONF_POINTER(PW_TYPE_COMBO_IP_PREFIX, &cl_ipaddr), NULL },
497 { "ipv4addr", FR_CONF_POINTER(PW_TYPE_IPV4_PREFIX, &cl_ipaddr), NULL },
498 { "ipv6addr", FR_CONF_POINTER(PW_TYPE_IPV6_PREFIX, &cl_ipaddr), NULL },
500 { "netmask", FR_CONF_POINTER(PW_TYPE_INTEGER, &cl_netmask), NULL },
502 { "src_ipaddr", FR_CONF_POINTER(PW_TYPE_STRING, &cl_srcipaddr), NULL },
504 { "require_message_authenticator", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), "no" },
506 { "secret", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, RADCLIENT, secret), NULL },
507 { "shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), NULL },
509 { "nas_type", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, nas_type), NULL },
511 { "login", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, login), NULL },
512 { "password", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, password), NULL },
513 { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, server), NULL },
514 { "response_window", FR_CONF_OFFSET(PW_TYPE_TIMEVAL, RADCLIENT, response_window), NULL },
517 { "proto", FR_CONF_POINTER(PW_TYPE_STRING, &hs_proto), NULL },
518 { "limit", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) limit_config },
521 #ifdef WITH_DYNAMIC_CLIENTS
522 { "dynamic_clients", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, client_server), NULL },
523 { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, lifetime), NULL },
524 { "rate_limit", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, rate_limit), NULL },
527 CONF_PARSER_TERMINATOR
530 /** Create the linked list of clients from the new configuration type
534 RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, bool tls_required)
536 RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls_required)
539 bool global = false, in_server = false;
542 RADCLIENT_LIST *clients = NULL;
545 * Be forgiving. If there's already a clients, return
546 * it. Otherwise create a new one.
548 clients = cf_data_find(section, "clients");
549 if (clients) return clients;
551 clients = client_list_init(section);
552 if (!clients) return NULL;
554 if (cf_top_section(section) == section) global = true;
556 if (strcmp("server", cf_section_name1(section)) == 0) in_server = true;
558 for (cs = cf_subsection_find_next(section, NULL, "client");
560 cs = cf_subsection_find_next(section, cs, "client")) {
561 c = client_afrom_cs(cs, cs, in_server, false);
565 client_list_free(clients);
571 * TLS clients CANNOT use non-TLS listeners.
572 * non-TLS clients CANNOT use TLS listeners.
574 if (tls_required != c->tls_required) {
575 cf_log_err_cs(cs, "Client does not have the same TLS configuration as the listener");
581 * FIXME: Add the client as data via cf_data_add,
582 * for migration issues.
585 #ifdef WITH_DYNAMIC_CLIENTS
587 if (c->client_server) {
592 struct stat stat_buf;
596 * Find the directory where individual
597 * client definitions are stored.
599 cp = cf_pair_find(cs, "directory");
600 if (!cp) goto add_client;
602 value = cf_pair_value(cp);
604 cf_log_err_cs(cs, "The \"directory\" entry must not be empty");
608 DEBUG("including dynamic clients in %s", value);
610 dir = opendir(value);
612 cf_log_err_cs(cs, "Error reading directory %s: %s", value, fr_syserror(errno));
617 * Read the directory, ignoring "." files.
619 while ((dp = readdir(dir)) != NULL) {
623 if (dp->d_name[0] == '.') continue;
626 * Check for valid characters
628 for (p = dp->d_name; *p != '\0'; p++) {
629 if (isalpha((int)*p) ||
632 (*p == '.')) continue;
635 if (*p != '\0') continue;
637 snprintf(buf2, sizeof(buf2), "%s/%s", value, dp->d_name);
639 if ((stat(buf2, &stat_buf) != 0) || S_ISDIR(stat_buf.st_mode)) continue;
641 dc = client_read(buf2, in_server, true);
643 cf_log_err_cs(cs, "Failed reading client file \"%s\"", buf2);
649 * Validate, and add to the list.
651 if (!client_add_dynamic(clients, c, dc)) {
655 } /* loop over the directory */
658 #endif /* HAVE_DIRENT_H */
661 #endif /* WITH_DYNAMIC_CLIENTS */
662 if (!client_add(clients, c)) {
663 cf_log_err_cs(cs, "Failed to add client %s", cf_section_name2(cs));
670 * Associate the clients structure with the section.
672 if (cf_data_add(section, "clients", clients, NULL) < 0) {
673 cf_log_err_cs(section, "Failed to associate clients with section %s", cf_section_name1(section));
674 client_list_free(clients);
679 * Replace the global list of clients with the new one.
680 * The old one is still referenced from the original
681 * configuration, and will be freed when that is freed.
683 if (global) root_clients = clients;
688 #ifdef WITH_DYNAMIC_CLIENTS
690 * We overload this structure a lot.
692 static const CONF_PARSER dynamic_config[] = {
693 { "FreeRADIUS-Client-IP-Address", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, RADCLIENT, ipaddr), NULL },
694 { "FreeRADIUS-Client-IPv6-Address", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, RADCLIENT, ipaddr), NULL },
695 { "FreeRADIUS-Client-IP-Prefix", FR_CONF_OFFSET(PW_TYPE_IPV4_PREFIX, RADCLIENT, ipaddr), NULL },
696 { "FreeRADIUS-Client-IPv6-Prefix", FR_CONF_OFFSET(PW_TYPE_IPV6_PREFIX, RADCLIENT, ipaddr), NULL },
697 { "FreeRADIUS-Client-Src-IP-Address", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, RADCLIENT, src_ipaddr), NULL },
698 { "FreeRADIUS-Client-Src-IPv6-Address", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, RADCLIENT, src_ipaddr), NULL },
700 { "FreeRADIUS-Client-Require-MA", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), NULL },
702 { "FreeRADIUS-Client-Secret", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, secret), "" },
703 { "FreeRADIUS-Client-Shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), "" },
704 { "FreeRADIUS-Client-NAS-Type", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, nas_type), NULL },
705 { "FreeRADIUS-Client-Virtual-Server", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, server), NULL },
707 CONF_PARSER_TERMINATOR
710 /** Add a dynamic client
713 bool client_add_dynamic(RADCLIENT_LIST *clients, RADCLIENT *master, RADCLIENT *c)
718 * No virtual server defined. Inherit the parent's
721 if (master->server && !c->server) {
722 c->server = talloc_typed_strdup(c, master->server);
726 * If the client network isn't global (not tied to a
727 * virtual server), then ensure that this clients server
728 * is the same as the enclosing networks virtual server.
730 if (master->server && (strcmp(master->server, c->server) != 0)) {
731 ERROR("Cannot add client %s/%i: Virtual server %s is not the same as the virtual server for the network",
732 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix, c->server);
737 if (!client_add(clients, c)) {
738 ERROR("Cannot add client %s/%i: Internal error",
739 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix);
745 * Initialize the remaining fields.
748 c->lifetime = master->lifetime;
749 c->created = time(NULL);
750 c->longname = talloc_typed_strdup(c, c->shortname);
752 INFO("Adding client %s/%i with shared secret \"%s\"",
753 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix, c->secret);
762 /** Create a client CONF_SECTION using a mapping section to map values from a result set to client attributes
764 * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too.
766 * @note Caller should free CONF_SECTION passed in as out, on error.
767 * Contents of that section will be in an undefined state.
769 * @param[in,out] out Section to perform mapping on. Either the root of the client config, or a parent section
770 * (when this function is called recursively).
771 * Should be alloced with cf_section_alloc, or if there's a separate template section, the
772 * result of calling cf_section_dup on that section.
773 * @param[in] map section.
774 * @param[in] func to call to retrieve CONF_PAIR values. Must return a talloced buffer containing the value.
775 * @param[in] data to pass to func, usually a result pointer.
776 * @return 0 on success else -1 on error.
778 int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_cb_t func, void *data)
782 for (ci = cf_item_find_next(map, NULL);
784 ci = cf_item_find_next(map, ci)) {
791 * Recursively process map subsection
793 if (cf_item_is_section(ci)) {
794 CONF_SECTION *cs, *cc;
796 cs = cf_item_to_section(ci);
798 * Use pre-existing section or alloc a new one
800 cc = cf_section_sub_find_name2(out, cf_section_name1(cs), cf_section_name2(cs));
802 cc = cf_section_alloc(out, cf_section_name1(cs), cf_section_name2(cs));
803 cf_section_add(out, cc);
807 if (client_map_section(cc, cs, func, data) < 0) return -1;
811 cp = cf_item_to_pair(ci);
812 attr = cf_pair_attr(cp);
815 * The callback can return 0 (success) and not provide a value
816 * in which case we skip the mapping pair.
818 * Or return -1 in which case we error out.
820 if (func(&value, cp, data) < 0) {
821 cf_log_err_cs(out, "Failed performing mapping \"%s\" = \"%s\"", attr, cf_pair_value(cp));
824 if (!value) continue;
827 * Replace an existing CONF_PAIR
829 old = cf_pair_find(out, attr);
831 cf_pair_replace(out, old, value);
837 * ...or add a new CONF_PAIR
839 cp = cf_pair_alloc(out, attr, value, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
841 cf_log_err_cs(out, "Failed allocing pair \"%s\" = \"%s\"", attr, value);
846 cf_item_add(out, cf_pair_to_item(cp));
852 /** Allocate a new client from a config section
854 * @param ctx to allocate new clients in.
855 * @param cs to process as a client.
856 * @param in_server Whether the client should belong to a specific virtual server.
857 * @param with_coa If true and coa_server or coa_pool aren't specified automatically,
858 * create a coa home_server section and add it to the client CONF_SECTION.
859 * @return new RADCLIENT struct.
861 RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bool with_coa)
866 name2 = cf_section_name2(cs);
868 cf_log_err_cs(cs, "Missing client name");
873 * The size is fine.. Let's create the buffer
875 c = talloc_zero(ctx, RADCLIENT);
878 memset(&cl_ipaddr, 0, sizeof(cl_ipaddr));
881 if (cf_section_parse(cs, c, client_config) < 0) {
882 cf_log_err_cs(cs, "Error parsing client section");
894 * Global clients can set servers to use, per-server clients cannot.
896 if (in_server && c->server) {
897 cf_log_err_cs(cs, "Clients inside of an server section cannot point to a server");
902 * Allow the old method to specify "netmask". Just using "1.2.3.4" means it's a /32.
904 if (cl_netmask != 255) {
905 if ((cl_ipaddr.prefix != cl_netmask) &&
906 (((cl_ipaddr.af == AF_INET) && cl_ipaddr.prefix != 32) ||
907 ((cl_ipaddr.af == AF_INET6) && cl_ipaddr.prefix != 128))) {
908 cf_log_err_cs(cs, "Clients cannot use 'ipaddr/mask' and 'netmask' at the same time.");
912 cl_ipaddr.prefix = cl_netmask;
916 * Newer style client definitions with either ipaddr or ipaddr6
919 if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
923 * Sets ipv4/ipv6 address and prefix.
925 c->ipaddr = cl_ipaddr;
928 * Set the long name to be the result of a reverse lookup on the IP address.
930 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
931 c->longname = talloc_typed_strdup(c, buffer);
934 * Set the short name to the name2.
936 if (!c->shortname) c->shortname = talloc_typed_strdup(c, name2);
938 * No "ipaddr" or "ipv6addr", use old-style "client <ipaddr> {" syntax.
941 WARN("No 'ipaddr' or 'ipv4addr' or 'ipv6addr' field found in client %s. "
942 "Please fix your configuration", name2);
943 WARN("Support for old-style clients will be removed in a future release");
946 if (cf_pair_find(cs, "proto") != NULL) {
947 cf_log_err_cs(cs, "Cannot use 'proto' inside of old-style client definition");
951 if (fr_pton(&c->ipaddr, name2, -1, AF_UNSPEC, true) < 0) {
952 cf_log_err_cs(cs, "Failed parsing client name \"%s\" as ip address or hostname: %s", name2,
957 c->longname = talloc_typed_strdup(c, name2);
958 if (!c->shortname) c->shortname = talloc_typed_strdup(c, c->longname);
961 c->proto = IPPROTO_UDP;
963 if (strcmp(hs_proto, "udp") == 0) {
967 } else if (strcmp(hs_proto, "tcp") == 0) {
969 c->proto = IPPROTO_TCP;
971 } else if (strcmp(hs_proto, "tls") == 0) {
973 c->proto = IPPROTO_TCP;
974 c->tls_required = true;
976 } else if (strcmp(hs_proto, "radsec") == 0) {
978 c->proto = IPPROTO_TCP;
979 c->tls_required = true;
981 } else if (strcmp(hs_proto, "*") == 0) {
983 c->proto = IPPROTO_IP; /* fake for dual */
986 cf_log_err_cs(cs, "Unknown proto \"%s\".", hs_proto);
992 * If a src_ipaddr is specified, when we send the return packet
993 * we will use this address instead of the src from the
997 #ifdef WITH_UDPFROMTO
998 switch (c->ipaddr.af) {
1000 if (fr_pton4(&c->src_ipaddr, cl_srcipaddr, -1, true, false) < 0) {
1001 cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
1007 if (fr_pton6(&c->src_ipaddr, cl_srcipaddr, -1, true, false) < 0) {
1008 cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
1016 WARN("Server not built with udpfromto, ignoring client src_ipaddr");
1018 cl_srcipaddr = NULL;
1022 * A response_window of zero is OK, and means that it's
1023 * ignored by the rest of the server timers.
1025 if (timerisset(&c->response_window)) {
1026 FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, >=, 0, 1000);
1027 FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, 60, 0);
1028 FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, main_config.max_request_time, 0);
1031 #ifdef WITH_DYNAMIC_CLIENTS
1032 if (c->client_server) {
1033 c->secret = talloc_typed_strdup(c, "testing123");
1035 if (((c->ipaddr.af == AF_INET) && (c->ipaddr.prefix == 32)) ||
1036 ((c->ipaddr.af == AF_INET6) && (c->ipaddr.prefix == 128))) {
1037 cf_log_err_cs(cs, "Dynamic clients MUST be a network, not a single IP address");
1045 if (!c->secret || (c->secret[0] == '\0')) {
1047 char const *value = NULL;
1048 CONF_PAIR *cp = cf_pair_find(cs, "dhcp");
1050 if (cp) value = cf_pair_value(cp);
1053 * Secrets aren't needed for DHCP.
1055 if (value && (strcmp(value, "yes") == 0)) return c;
1060 * If the client is TLS only, the secret can be
1061 * omitted. When omitted, it's hard-coded to
1062 * "radsec". See RFC 6614.
1064 if (c->tls_required) {
1065 c->secret = talloc_typed_strdup(cs, "radsec");
1070 cf_log_err_cs(cs, "secret must be at least 1 character long");
1080 * Point the client to the home server pool, OR to the
1081 * home server. This gets around the problem of figuring
1082 * out which port to use.
1084 cp = cf_pair_find(cs, "coa_server");
1086 c->coa_name = cf_pair_value(cp);
1087 c->coa_pool = home_pool_byname(c->coa_name, HOME_TYPE_COA);
1089 c->coa_server = home_server_byname(c->coa_name, HOME_TYPE_COA);
1091 if (!c->coa_pool && !c->coa_server) {
1092 cf_log_err_cs(cs, "No such home_server or home_server_pool \"%s\"", c->coa_name);
1096 * If we're implicitly adding a CoA home server for
1097 * every client, or there's a server subsection,
1098 * create a home server CONF_SECTION and then parse
1099 * it into a home_server_t.
1101 } else if (with_coa || cf_section_sub_find(cs, "coa_server")) {
1102 CONF_SECTION *server;
1103 home_server_t *home;
1105 if (((c->ipaddr.af == AF_INET) && (c->ipaddr.prefix != 32)) ||
1106 ((c->ipaddr.af == AF_INET6) && (c->ipaddr.prefix != 128))) {
1107 WARN("Subnets not supported for home servers. "
1108 "Not adding client %s as home_server", name2);
1112 server = home_server_cs_afrom_client(cs);
1113 if (!server) goto error;
1116 * Must be allocated in the context of the client,
1117 * as allocating using the context of the
1118 * realm_config_t without a mutex, by one of the
1119 * workers, would be bad.
1121 home = home_server_afrom_cs(NULL, NULL, server);
1123 talloc_free(server);
1127 rad_assert(home->type == HOME_TYPE_COA);
1129 c->coa_server = home;
1130 c->defines_coa_server = true;
1137 if ((c->proto == IPPROTO_TCP) || (c->proto == IPPROTO_IP)) {
1138 if ((c->limit.idle_timeout > 0) && (c->limit.idle_timeout < 5))
1139 c->limit.idle_timeout = 5;
1140 if ((c->limit.lifetime > 0) && (c->limit.lifetime < 5))
1141 c->limit.lifetime = 5;
1142 if ((c->limit.lifetime > 0) && (c->limit.idle_timeout > c->limit.lifetime))
1143 c->limit.idle_timeout = 0;
1150 /** Add a client from a result set (SQL)
1152 * @todo This function should die. SQL should use client_afrom_cs.
1154 * @param ctx Talloc context.
1155 * @param identifier Client IP Address / IPv4 subnet / IPv6 subnet / FQDN.
1156 * @param secret Client secret.
1157 * @param shortname Client friendly name.
1158 * @param type NAS-Type.
1159 * @param server Virtual-Server to associate clients with.
1160 * @param require_ma If true all packets from client must include a message-authenticator.
1161 * @return The new client, or NULL on error.
1163 RADCLIENT *client_afrom_query(TALLOC_CTX *ctx, char const *identifier, char const *secret,
1164 char const *shortname, char const *type, char const *server, bool require_ma)
1169 rad_assert(identifier);
1172 c = talloc_zero(ctx, RADCLIENT);
1174 if (fr_pton(&c->ipaddr, identifier, -1, AF_UNSPEC, true) < 0) {
1175 ERROR("%s", fr_strerror());
1181 #ifdef WITH_DYNAMIC_CLIENTS
1184 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
1185 c->longname = talloc_typed_strdup(c, buffer);
1188 * Other values (secret, shortname, nas_type, virtual_server)
1190 c->secret = talloc_typed_strdup(c, secret);
1191 if (shortname) c->shortname = talloc_typed_strdup(c, shortname);
1192 if (type) c->nas_type = talloc_typed_strdup(c, type);
1193 if (server) c->server = talloc_typed_strdup(c, server);
1194 c->message_authenticator = require_ma;
1199 /** Create a new client, consuming all attributes in the control list of the request
1201 * @param clients list to add new client to.
1202 * @param request Fake request.
1203 * @return a new client on success, else NULL on error.
1205 RADCLIENT *client_afrom_request(RADCLIENT_LIST *clients, REQUEST *request)
1211 CONF_PAIR *cp = NULL;
1215 VALUE_PAIR *vp = NULL;
1217 if (!clients || !request) return NULL;
1219 snprintf(buffer, sizeof(buffer), "dynamic%i", cnt++);
1221 c = talloc_zero(clients, RADCLIENT);
1222 c->cs = cf_section_alloc(NULL, "client", buffer);
1223 talloc_steal(c, c->cs);
1224 c->ipaddr.af = AF_UNSPEC;
1225 c->src_ipaddr.af = AF_UNSPEC;
1227 fr_cursor_init(&cursor, &request->config);
1229 RDEBUG2("Converting control list to client fields");
1231 for (i = 0; dynamic_config[i].name != NULL; i++) {
1232 DICT_ATTR const *da;
1233 char *strvalue = NULL;
1235 da = dict_attrbyname(dynamic_config[i].name);
1237 RERROR("Cannot add client %s: attribute \"%s\" is not in the dictionary",
1238 ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
1239 dynamic_config[i].name);
1247 fr_cursor_first(&cursor);
1248 if (!fr_cursor_next_by_da(&cursor, da, TAG_ANY)) {
1250 * Not required. Skip it.
1252 if (!dynamic_config[i].dflt) continue;
1254 RERROR("Cannot add client %s: Required attribute \"%s\" is missing",
1255 ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
1256 dynamic_config[i].name);
1259 vp = fr_cursor_remove(&cursor);
1262 * Freed at the same time as the vp.
1264 strvalue = vp_aprints_value(vp, vp, '\'');
1266 switch (dynamic_config[i].type) {
1267 case PW_TYPE_IPV4_ADDR:
1268 if (da->attr == PW_FREERADIUS_CLIENT_IP_ADDRESS) {
1269 c->ipaddr.af = AF_INET;
1270 c->ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
1271 c->ipaddr.prefix = 32;
1272 cp = cf_pair_alloc(c->cs, "ipv4addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1273 } else if (da->attr == PW_FREERADIUS_CLIENT_SRC_IP_ADDRESS) {
1274 #ifdef WITH_UDPFROMTO
1275 RDEBUG2("src_ipaddr = %s", strvalue);
1276 c->src_ipaddr.af = AF_INET;
1277 c->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
1278 c->src_ipaddr.prefix = 32;
1279 cp = cf_pair_alloc(c->cs, "src_ipaddr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1281 RWARN("Server not built with udpfromto, ignoring FreeRADIUS-Client-Src-IP-Address");
1287 case PW_TYPE_IPV6_ADDR:
1288 if (da->attr == PW_FREERADIUS_CLIENT_IPV6_ADDRESS) {
1289 c->ipaddr.af = AF_INET6;
1290 c->ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
1291 c->ipaddr.prefix = 128;
1292 cp = cf_pair_alloc(c->cs, "ipv6addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1293 } else if (da->attr == PW_FREERADIUS_CLIENT_SRC_IPV6_ADDRESS) {
1294 #ifdef WITH_UDPFROMTO
1295 c->src_ipaddr.af = AF_INET6;
1296 c->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
1297 c->src_ipaddr.prefix = 128;
1298 cp = cf_pair_alloc(c->cs, "src_addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1300 RWARN("Server not built with udpfromto, ignoring FreeRADIUS-Client-Src-IPv6-Address");
1306 case PW_TYPE_IPV4_PREFIX:
1307 if (da->attr == PW_FREERADIUS_CLIENT_IP_PREFIX) {
1308 c->ipaddr.af = AF_INET;
1309 memcpy(&c->ipaddr.ipaddr.ip4addr, &vp->vp_ipv4prefix[2],
1310 sizeof(c->ipaddr.ipaddr.ip4addr.s_addr));
1311 fr_ipaddr_mask(&c->ipaddr, (vp->vp_ipv4prefix[1] & 0x3f));
1312 cp = cf_pair_alloc(c->cs, "ipv4addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1317 case PW_TYPE_IPV6_PREFIX:
1318 if (da->attr == PW_FREERADIUS_CLIENT_IPV6_PREFIX) {
1319 c->ipaddr.af = AF_INET6;
1320 memcpy(&c->ipaddr.ipaddr.ip6addr, &vp->vp_ipv6prefix[2],
1321 sizeof(c->ipaddr.ipaddr.ip6addr));
1322 fr_ipaddr_mask(&c->ipaddr, vp->vp_ipv6prefix[1]);
1323 cp = cf_pair_alloc(c->cs, "ipv6addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1328 case PW_TYPE_STRING:
1330 CONF_PARSER const *parse;
1333 * Cache pointer to CONF_PAIR buffer in RADCLIENT struct
1335 p = (char **) ((char *) c + dynamic_config[i].offset);
1336 if (*p) TALLOC_FREE(*p);
1337 if (!vp->vp_strvalue[0]) break;
1340 * We could reuse the CONF_PAIR buff, this just keeps things
1341 * consistent between client_afrom_cs, and client_afrom_query.
1343 *p = talloc_strdup(c, strvalue);
1346 * This is fairly nasty... In order to figure out the CONF_PAIR
1347 * name associated with a field, find offsets that match between
1348 * the dynamic_config CONF_PARSER table, and the client_config
1349 * CONF_PARSER table.
1351 * This is so that things that expect to find CONF_PAIRs in the
1352 * client CONF_SECTION for fields like 'nas_type' can.
1354 for (parse = client_config; parse->name; parse++) {
1355 if (parse->offset == dynamic_config[i].offset) break;
1359 cp = cf_pair_alloc(c->cs, parse->name, strvalue, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
1363 case PW_TYPE_BOOLEAN:
1365 CONF_PARSER const *parse;
1367 pi = (int *) ((bool *) ((char *) c + dynamic_config[i].offset));
1368 *pi = vp->vp_integer;
1371 * Same nastiness as above.
1373 for (parse = client_config; parse->name; parse++) {
1374 if (parse->offset == dynamic_config[i].offset) break;
1378 cp = cf_pair_alloc(c->cs, parse->name, strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1387 RERROR("Error creating equivalent conf pair for %s", vp->da->name);
1391 if (cf_pair_attr_type(cp) == T_SINGLE_QUOTED_STRING) {
1392 RDEBUG2("%s = '%s'", cf_pair_attr(cp), cf_pair_value(cp));
1394 RDEBUG2("%s = %s", cf_pair_attr(cp), cf_pair_value(cp));
1396 cf_pair_add(c->cs, cp);
1401 fr_cursor_first(&cursor);
1402 vp = fr_cursor_remove(&cursor);
1407 value = vp_aprints_value(vp, vp, '\'');
1409 ERROR("Failed stringifying value of &control:%s", vp->da->name);
1413 if (vp->da->type == PW_TYPE_STRING) {
1414 RDEBUG2("%s = '%s'", vp->da->name, value);
1415 cp = cf_pair_alloc(c->cs, vp->da->name, value, T_OP_SET,
1416 T_BARE_WORD, T_SINGLE_QUOTED_STRING);
1418 RDEBUG2("%s = %s", vp->da->name, value);
1419 cp = cf_pair_alloc(c->cs, vp->da->name, value, T_OP_SET,
1420 T_BARE_WORD, T_BARE_WORD);
1422 cf_pair_add(c->cs, cp);
1425 } while ((vp = fr_cursor_remove(&cursor)));
1429 if (c->ipaddr.af == AF_UNSPEC) {
1430 RERROR("Cannot add client %s: No IP address was specified.",
1431 ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)));
1440 * Need to apply the same mask as we set for the client
1441 * else clients created with FreeRADIUS-Client-IPv6-Prefix
1442 * or FreeRADIUS-Client-IPv4-Prefix will fail this check.
1444 addr = request->packet->src_ipaddr;
1445 fr_ipaddr_mask(&addr, c->ipaddr.prefix);
1446 if (fr_ipaddr_cmp(&addr, &c->ipaddr) != 0) {
1449 RERROR("Cannot add client %s: Not in specified subnet %s/%i",
1450 ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
1451 ip_ntoh(&c->ipaddr, buf2, sizeof(buf2)), c->ipaddr.prefix);
1456 if (!c->secret || !*c->secret) {
1457 RERROR("Cannot add client %s: No secret was specified",
1458 ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)));
1462 if (!client_add_dynamic(clients, request->client, c)) {
1466 if ((c->src_ipaddr.af != AF_UNSPEC) && (c->src_ipaddr.af != c->ipaddr.af)) {
1467 RERROR("Cannot add client %s: Client IP and src address are different IP version",
1468 ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)));
1477 * Read a client definition from the given filename.
1479 RADCLIENT *client_read(char const *filename, int in_server, int flag)
1486 if (!filename) return NULL;
1488 cs = cf_section_alloc(NULL, "main", NULL);
1489 if (!cs) return NULL;
1491 if (cf_file_read(cs, filename) < 0) {
1496 cs = cf_section_sub_find(cs, "client");
1498 ERROR("No \"client\" section found in client file");
1502 c = client_afrom_cs(cs, cs, in_server, false);
1503 if (!c) return NULL;
1505 p = strrchr(filename, FR_DIR_SEP);
1512 if (!flag) return c;
1515 * Additional validations
1517 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
1518 if (strcmp(p, buffer) != 0) {
1519 ERROR("Invalid client definition in %s: IP address %s does not match name %s", filename, buffer, p);