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