The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
rlm_redis_ippool_tool.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: dbddfb9e2fbfb2c7fbe10a207e3e23282444cfc0 $
19 * @file rlm_redis_ippool_tool.c
20 * @brief IP population tool.
21 *
22 * @author Arran Cudbard-Bell
23 *
24 * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 * @copyright 2015 The FreeRADIUS server project
26 */
27RCSID("$Id: dbddfb9e2fbfb2c7fbe10a207e3e23282444cfc0 $")
28#include <freeradius-devel/server/base.h>
29#include <freeradius-devel/server/module_rlm.h>
30#include <freeradius-devel/io/listen.h>
31#include <freeradius-devel/unlang/base.h>
32#include <freeradius-devel/io/thread.h>
33
34#include "base.h"
35#include "redis_ippool.h"
36
37#define EXIT_WITH_FAILURE \
38do { \
39 ret = EXIT_FAILURE; \
40 goto cleanup; \
41} while (0)
42
44
50
76
79 { .out = &attr_ippool, .name = "IP-Pool", .type = FR_TYPE_TLV, .dict = &dict_freeradius },
80 { .out = &attr_ippool_name, .name = "IP-Pool.Name", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
81 { .out = &attr_ippool_lease, .name = "IP-Pool.Lease", .type = FR_TYPE_TLV, .dict = &dict_freeradius },
82 { .out = &attr_ippool_lease_address, .name = "IP-Pool.Lease.Address", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
83 { .out = &attr_ippool_lease_active, .name = "IP-Pool.Lease.Active", .type = FR_TYPE_BOOL, .dict = &dict_freeradius },
84 { .out = &attr_ippool_lease_expires, .name = "IP-Pool.Lease.Expires", .type = FR_TYPE_DATE, .dict = &dict_freeradius },
85 { .out = &attr_ippool_lease_device, .name = "IP-Pool.Lease.Device", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
86 { .out = &attr_ippool_lease_gateway, .name = "IP-Pool.Lease.Gateway", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
87 { .out = &attr_ippool_lease_range, .name = "IP-Pool.Lease.Range", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
88 { .out = &attr_ippool_stats, .name = "IP-Pool.Stats", .type = FR_TYPE_TLV, .dict = &dict_freeradius },
89 { .out = &attr_ippool_stats_total, .name = "IP-Pool.Stats.Total", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
90 { .out = &attr_ippool_stats_dynamic, .name = "IP-Pool.Stats.Dynamic", .type = FR_TYPE_TLV, .dict = &dict_freeradius },
91 { .out = &attr_ippool_stats_dynamic_total, .name = "IP-Pool.Stats.Dynamic.Total", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
92 { .out = &attr_ippool_stats_dynamic_free, .name = "IP-Pool.Stats.Dynamic.Free", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
93 { .out = &attr_ippool_stats_dynamic_expire1m, .name = "IP-Pool.Stats.Dynamic.Expire-1m", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
94 { .out = &attr_ippool_stats_dynamic_expire30m, .name = "IP-Pool.Stats.Dynamic.Expire-30m", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
95 { .out = &attr_ippool_stats_dynamic_expire1h, .name = "IP-Pool.Stats.Dynamic.Expire-1h", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
96 { .out = &attr_ippool_stats_dynamic_expire1d, .name = "IP-Pool.Stats.Dynamic.Expire-1d", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
97 { .out = &attr_ippool_stats_static, .name = "IP-Pool.Stats.Static", .type = FR_TYPE_TLV, .dict = &dict_freeradius },
98 { .out = &attr_ippool_stats_static_total, .name = "IP-Pool.Stats.Static.Total", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
99 { .out = &attr_ippool_stats_static_free, .name = "IP-Pool.Stats.Static.Free", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
100 { .out = &attr_ippool_stats_static_renew1m, .name = "IP-Pool.Stats.Static.Renew-1m", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
101 { .out = &attr_ippool_stats_static_renew30m, .name = "IP-Pool.Stats.Static.Renew-30m", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
102 { .out = &attr_ippool_stats_static_renew1h, .name = "IP-Pool.Stats.Static.Renew-1h", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
103 { .out = &attr_ippool_stats_static_renew1d, .name = "IP-Pool.Stats.Static.Renew-1d", .type = FR_TYPE_UINT64, .dict = &dict_freeradius },
105};
106
107/** Pool management actions
108 *
109 */
110typedef enum ippool_tool_action {
111 IPPOOL_TOOL_NOOP = 0, //!< Do nothing.
112 IPPOOL_TOOL_ADD, //!< Add one or more IP addresses.
113 IPPOOL_TOOL_REMOVE, //!< Remove one or more IP addresses.
114 IPPOOL_TOOL_RELEASE, //!< Release one or more IP addresses.
115 IPPOOL_TOOL_SHOW, //!< Show one or more IP addresses.
116 IPPOOL_TOOL_MODIFY, //!< Modify attributes of one or more IP addresses.
117 IPPOOL_TOOL_ASSIGN, //!< Assign a static IP address to a device.
118 IPPOOL_TOOL_UNASSIGN //!< Remove static IP address assignment.
120
121/** A single pool operation
122 *
123 */
124typedef struct {
125 char const *name; //!< Original range or CIDR string.
126
127 uint8_t const *pool; //!< Pool identifier.
128 size_t pool_len; //!< Length of the pool identifier.
129
130 uint8_t const *range; //!< Range identifier.
131 size_t range_len; //!< Length of the range identifier.
132
133 fr_ipaddr_t start; //!< Start address.
134 fr_ipaddr_t end; //!< End address.
135 uint8_t prefix; //!< Prefix - The bits between the address mask, and the prefix
136 //!< form the addresses to be modified in the pool.
137 ippool_tool_action_t action; //!< What to do to the leases described by net/prefix.
139
140static char const *name;
141
142#define EOL "\n"
143
144/** Static server config split into two parts
145 *
146 * The command line provided server value is inserted between
147 * the two sections, along with an optional $INCLUDE if the -f option is provided
148 */
149static char server_conf1[] =
150"thread { num_workers = 1}" EOL \
151"trigger { }" EOL \
152"client test { ipaddr = 127.0.0.1; secret = supersecret }" EOL \
153"modules {" EOL \
154" redis_ippool {" EOL \
155" owner = request.IP-Pool.Lease.Device" EOL \
156" pool_name = control.IP-Pool.Name" EOL \
157" requested_address = IP-Pool.Lease.Address[*]" EOL \
158" redis {" EOL \
159" virtual_server = redis" EOL \
160" pool { start = 0 }" EOL;
161
162static char server_conf2[] =
163" }" EOL \
164" }" EOL \
165"}" EOL \
166"server redis { namespace = redis } " EOL \
167"server default {" EOL \
168" namespace = radius" EOL \
169" recv Access-Request { redis_ippool.stats }" EOL \
170" recv Accounting-Request { redis_ippool.show }" EOL \
171"}";
172
173static NEVER_RETURNS void usage(int ret) {
174 INFO("Usage: %s -adrsm range... [-p prefix_len]... [-x]... [-oShf] server[:port] [pool] [range id]", name);
175 INFO("Pool management:");
176 INFO(" -a range Add address(es)/prefix(es) to the pool.");
177 INFO(" -d range Delete address(es)/prefix(es) in this range.");
178 INFO(" -r range Release address(es)/prefix(es) in this range.");
179 INFO(" -s range Show addresses/prefix in this range.");
180 INFO(" -A address/prefix Assign a static lease.");
181 INFO(" -O owner To use when assigning a static lease.");
182 INFO(" -U address/prefix Un-assign a static lease");
183 INFO(" -p prefix_len Length of prefix to allocate (defaults to 32/128)");
184 INFO(" This is used primarily for IPv6 where a prefix is");
185 INFO(" allocated to an intermediary router, which in turn");
186 INFO(" allocates sub-prefixes to the devices it serves.");
187 INFO(" This argument changes the prefix_len for the previous");
188 INFO(" instance of an -adrsm argument, only.");
189 INFO(" -m range Change the range id to the one specified for addresses");
190 INFO(" in this range.");
191 INFO(" -l List available pools.");
192// INFO(" -L List available ranges in pool [NYI]");
193// INFO(" -i file Import entries from ISC lease file [NYI]");
194 INFO(" "); /* -Werror=format-zero-length */
195// INFO("Pool status:");
196// INFO(" -I Output active entries in ISC lease file format [NYI]");
197 INFO(" -S Print pool statistics");
198 INFO(" "); /* -Werror=format-zero-length */
199 INFO("Configuration:");
200 INFO(" -h Print this help message and exit");
201 INFO(" -x Increase the verbosity level");
202// INFO(" -o attr=value Set option, these are specific to the backends [NYI]");
203 INFO(" -D dictdir Set main dictionary directory (defaults to " DICTDIR);
204 INFO(" -f file Load connection options from a FreeRADIUS format config file");
205 INFO(" This file should contain one or more `server = <fqdn>` pairs`");
206 INFO(" and, optionally `port = <port>`, `password = secret`");
207 INFO(" ");
208 INFO("<range> is range \"127.0.0.1-127.0.0.254\" or CIDR network \"127.0.0.1/24\" or host \"127.0.0.1\"");
209 INFO("CIDR host bits set start address, e.g. 127.0.0.200/24 -> 127.0.0.200-127.0.0.254");
210 fr_exit_now(ret);
211}
212
214{
215 if (bits >= 32) return 0xffffffff;
216 return (1U << bits) - 1;
217}
218
219/** Iterate over range of IP addresses
220 *
221 * Mutates the ipaddr passed in, adding one to the prefix bits on each call.
222 *
223 * @param[in,out] ipaddr to increment.
224 * @param[in] end ipaddr to stop at.
225 * @param[in] prefix Length of the prefix.
226 * @return
227 * - true if the prefix bits are not high (continue).
228 * - false if the prefix bits are high (stop).
229 */
230static bool ipaddr_next(fr_ipaddr_t *ipaddr, fr_ipaddr_t const *end, uint8_t prefix)
231{
232 switch (ipaddr->af) {
233 default:
234 case AF_UNSPEC:
235 fr_assert(0);
236 return false;
237
238 case AF_INET6:
239 {
240 uint128_t ip_curr, ip_end;
241
242 if (!fr_cond_assert((prefix > 0) && (prefix <= 128))) return false;
243
244 /* Don't be tempted to cast */
245 memcpy(&ip_curr, ipaddr->addr.v6.s6_addr, sizeof(ip_curr));
246 memcpy(&ip_end, end->addr.v6.s6_addr, sizeof(ip_curr));
247
248 ip_curr = ntohlll(ip_curr);
249 ip_end = ntohlll(ip_end);
250
251 /* We're done */
252 if (uint128_eq(ip_curr, ip_end)) return false;
253
254 /* Increment the prefix */
255 ip_curr = uint128_add(ip_curr, uint128_lshift(uint128_new(0, 1), (128 - prefix)));
256 ip_curr = htonlll(ip_curr);
257 memcpy(&ipaddr->addr.v6.s6_addr, &ip_curr, sizeof(ipaddr->addr.v6.s6_addr));
258 return true;
259 }
260
261 case AF_INET:
262 {
263 uint32_t ip_curr, ip_end;
264
265 if (!fr_cond_assert((prefix > 0) && (prefix <= 32))) return false;
266
267 ip_curr = ntohl(ipaddr->addr.v4.s_addr);
268 ip_end = ntohl(end->addr.v4.s_addr);
269
270 /* We're done */
271 if (ip_curr == ip_end) return false;
272
273 /* Increment the prefix */
274 ip_curr += 1 << (32 - prefix);
275 ipaddr->addr.v4.s_addr = htonl(ip_curr);
276 return true;
277 }
278 }
279}
280
281/** Run the redis_ippool.stats module method to fetch pool statistics
282 */
283static int redis_ippool_get_stats(request_t *request, fr_value_box_t *pool_name,
285{
286 rlm_rcode_t rcode;
287 fr_pair_t *vp;
288
289 /*
290 * Make sure the control list is empty before pools.list populates it.
291 */
292 fr_pair_list_free(&request->control_pairs);
293
294 /*
295 * Add the pool name for to fetch stats for
296 */
297 MEM(vp = fr_pair_afrom_da_nested(request->control_ctx, &request->control_pairs, attr_ippool_name));
298 if (fr_value_box_copy(vp, &vp->data, pool_name) < 0) return -1;
299
300 if (unlang_interpret_push_section(NULL, request, section,
301 FRAME_CONF(RLM_MODULE_OK, UNLANG_TOP_FRAME)) < 0) return -1;
302
303 rcode = unlang_interpret_synchronous(el, request);
304 switch (rcode) {
306 return -1;
307
308 default:
309 return 0;
310 }
311}
312
313/** Run the redis_ippool.show module method to fetch lease details
314 */
315static int redis_ippool_show(request_t *request, ippool_tool_operation_t const *op, CONF_SECTION *section,
317{
318 rlm_rcode_t rcode;
319 fr_pair_t *vp;
320 fr_ipaddr_t ipaddr = op->start;
321 char ip_buff[FR_IPADDR_PREFIX_STRLEN];
322
323 fr_pair_list_free(&request->control_pairs);
324 fr_pair_list_free(&request->request_pairs);
325
326 MEM(vp = fr_pair_afrom_da_nested(request->control_ctx, &request->control_pairs, attr_ippool_name));
327 if (fr_value_box_bstrndup(vp, &vp->data, NULL, (char const *)op->pool, op->pool_len, false) < 0) return -1;
328
329 ipaddr.prefix = (ipaddr.af == AF_INET6) ? 128 : 32;
330
331 do {
332 IPPOOL_SPRINT_IP(ip_buff, &ipaddr, ipaddr.prefix);
333 MEM(vp = fr_pair_afrom_da_nested(request->request_ctx, &request->request_pairs,
335 if (fr_value_box_from_str(vp, &vp->data, vp->da->type, NULL, ip_buff,
336 strlen(ip_buff), NULL) < 0) return -1;
337 } while (ipaddr_next(&ipaddr, &op->end, op->prefix));
338
339 if (unlang_interpret_push_section(NULL, request, section,
340 FRAME_CONF(RLM_MODULE_OK, UNLANG_TOP_FRAME)) < 0) return -1;
341
342 rcode = unlang_interpret_synchronous(el, request);
343 switch (rcode) {
345 return -1;
346
347 default:
348 return 0;
349 }
350}
351
352/** Convert an IP range or CIDR mask to a start and stop address
353 *
354 * @param[out] start_out Where to write the start address.
355 * @param[out] end_out Where to write the end address.
356 * @param[in] ip_str Unparsed IP string.
357 * @param[in] prefix length of prefixes we'll be allocating.
358 * @return
359 * - 0 on success.
360 * - -1 on failure.
361 */
362static int parse_ip_range(fr_ipaddr_t *start_out, fr_ipaddr_t *end_out, char const *ip_str, uint8_t prefix)
363{
364 fr_ipaddr_t start, end;
365 bool ex_broadcast;
366 char const *p;
367
368 p = strchr(ip_str, '-');
369 if (p) {
370 char start_buff[INET6_ADDRSTRLEN + 4];
371 char end_buff[INET6_ADDRSTRLEN + 4];
372 size_t len;
373
374 if ((size_t)(p - ip_str) >= sizeof(start_buff)) {
375 ERROR("Start address too long");
376 return -1;
377 }
378
379 len = strlcpy(start_buff, ip_str, (p - ip_str) + 1);
380 if (is_truncated(len, sizeof(start_buff))) {
381 ERROR("Start address too long");
382 return -1;
383 }
384
385 len = strlcpy(end_buff, p + 1, sizeof(end_buff));
386 if (is_truncated(len, sizeof(end_buff))) {
387 ERROR("End address too long");
388 return -1;
389 }
390
391 if (fr_inet_pton(&start, start_buff, -1, AF_UNSPEC, false, true) < 0) {
392 PERROR("Failed parsing \"%s\" as start address", start_buff);
393 return -1;
394 }
395
396 if (fr_inet_pton(&end, end_buff, -1, AF_UNSPEC, false, true) < 0) {
397 PERROR("Failed parsing \"%s\" end address", end_buff);
398 return -1;
399 }
400
401 if (start.af != end.af) {
402 ERROR("Start and end address must be of the same address family");
403 return -1;
404 }
405
406 if (!prefix) prefix = IPADDR_LEN(start.af);
407
408 /*
409 * IPv6 addresses
410 */
411 if (start.af == AF_INET6) {
412 uint128_t start_int, end_int;
413
414 memcpy(&start_int, start.addr.v6.s6_addr, sizeof(start_int));
415 memcpy(&end_int, end.addr.v6.s6_addr, sizeof(end_int));
416 if (uint128_gt(ntohlll(start_int), ntohlll(end_int))) {
417 ERROR("End address must be greater than or equal to start address");
418 return -1;
419 }
420 /*
421 * IPv4 addresses
422 */
423 } else {
424 if (ntohl((uint32_t)(start.addr.v4.s_addr)) >
425 ntohl((uint32_t)(end.addr.v4.s_addr))) {
426 ERROR("End address must be greater than or equal to start address");
427 return -1;
428 }
429 }
430
431 /*
432 * Mask start and end so we can do prefix ranges too
433 */
434 fr_ipaddr_mask(&start, prefix);
435 fr_ipaddr_mask(&end, prefix);
436 start.prefix = prefix;
437 end.prefix = prefix;
438
439 *start_out = start;
440 *end_out = end;
441
442 return 0;
443 }
444
445 if (fr_inet_pton(&start, ip_str, -1, AF_UNSPEC, false, false) < 0) {
446 ERROR("Failed parsing \"%s\" as IPv4/v6 subnet", ip_str);
447 return -1;
448 }
449
450 if (!prefix) prefix = IPADDR_LEN(start.af);
451
452 if (prefix < start.prefix) {
453 ERROR("-p must be greater than or equal to /<mask> (%u)", start.prefix);
454 return -1;
455 }
456 if (prefix > IPADDR_LEN(start.af)) {
457 ERROR("-p must be less than or equal to address length (%u)", IPADDR_LEN(start.af));
458 return -1;
459 }
460
461 if ((prefix - start.prefix) > 64) {
462 ERROR("-p must be less than or equal to %u", start.prefix + 64);
463 return -1;
464 }
465
466 /*
467 * Exclude the broadcast address only if we're dealing with IPv4 addresses
468 * if we're allocating IPv6 addresses or prefixes we don't need to.
469 */
470 ex_broadcast = (start.af == AF_INET) && (IPADDR_LEN(start.af) == prefix);
471
472 /*
473 * Excluding broadcast, 31/32 or 127/128 start/end are the same
474 */
475 if (ex_broadcast && (start.prefix >= (IPADDR_LEN(start.af) - 1))) {
476 *start_out = start;
477 *end_out = start;
478 return 0;
479 }
480
481 /*
482 * Set various fields (we only overwrite the IP later)
483 */
484 end = start;
485
486 if (start.af == AF_INET6) {
487 uint128_t ip, p_mask;
488
489 /* cond assert to satisfy clang scan */
490 if (!fr_cond_assert((prefix > 0) && (prefix <= 128))) return -1;
491
492 /* Don't be tempted to cast */
493 memcpy(&ip, start.addr.v6.s6_addr, sizeof(ip));
494 ip = ntohlll(ip);
495
496 /* Generate a mask that covers the prefix bits, and sets them high */
497 p_mask = uint128_lshift(uint128_gen_mask(prefix - start.prefix), (128 - prefix));
498 ip = htonlll(uint128_bor(p_mask, ip));
499
500 /* Decrement by one */
501 if (ex_broadcast) ip = uint128_sub(ip, uint128_new(0, 1));
502 memcpy(&end.addr.v6.s6_addr, &ip, sizeof(end.addr.v6.s6_addr));
503 } else {
504 uint32_t ip;
505
506 /* cond assert to satisfy clang scan */
507 if (!fr_cond_assert((prefix > 0) && (prefix <= 32))) return -1;
508
509 ip = ntohl(start.addr.v4.s_addr);
510
511 /* Generate a mask that covers the prefix bits and sets them high */
512 ip |= uint32_gen_mask(prefix - start.prefix) << (32 - prefix);
513
514 /* Decrement by one */
515 if (ex_broadcast) ip--;
516 end.addr.v4.s_addr = htonl(ip);
517 }
518
519 *start_out = start;
520 *end_out = end;
521
522 return 0;
523}
524
525static int run_xlat(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, fr_sbuff_t *xlat, fr_event_list_t *el)
526{
527 xlat_exp_head_t *ex;
528
529 if (xlat_tokenize(ctx, &ex,
530 xlat,
531 &(fr_sbuff_parse_rules_t){
532 .escapes = &(fr_sbuff_unescape_rules_t) {
533 .name = "xlat",
534 .chr = '\\',
535 .subs = {
536 ['%'] = '%',
537 ['\\'] = '\\',
538 },
539 }}, &(tmpl_rules_t) {
540 .attr = {
541 .allow_unknown = false,
542 .dict_def = dict_freeradius
543 },
544 .xlat = {
545 .runtime_el = el
546 },
547 .at_runtime = true
548 }) < 0) return -1;
549
550 if (xlat_needs_resolving(ex) &&
551 (xlat_resolve(ex, &(xlat_res_rules_t){ .allow_unresolved = false }) < 0)) {
552 talloc_free(ex);
553 return -1;
554 }
555
556 if (unlang_xlat_push(ctx, NULL, list, request, ex, UNLANG_TOP_FRAME) < 0) return -1;
558
559 return 0;
560}
561
562static int xlat_add_lease(TALLOC_CTX *ctx, fr_value_box_list_t *list,
564{
565 char xlat[1024];
566 ssize_t xlat_len;
567
568 op->start.prefix = op->end.prefix = IPADDR_LEN(op->start.af);
569 if (op->range) {
570 xlat_len = fr_sbuff_in_sprintf(&FR_SBUFF_OUT(xlat, sizeof(xlat)),
571 "%%redis_ippool.addresses.add('%s', '%pV', '%pV', %d, '%s')", op->pool,
572 fr_box_ipaddr(op->start), fr_box_ipaddr(op->end), op->prefix, op->range);
573 } else {
574 xlat_len = fr_sbuff_in_sprintf(&FR_SBUFF_OUT(xlat, sizeof(xlat)),
575 "%%redis_ippool.addresses.add('%s', '%pV', '%pV', %d)", op->pool,
576 fr_box_ipaddr(op->start), fr_box_ipaddr(op->end), op->prefix);
577 }
578 if (xlat_len < 0) return -1;
579
580 return run_xlat(ctx, list, request, &FR_SBUFF_IN(xlat, (size_t)xlat_len), el);
581}
582
583static int xlat_remove_lease(TALLOC_CTX *ctx, fr_value_box_list_t *list,
585{
586 char xlat[1024];
587 ssize_t xlat_len;
588
589 op->start.prefix = op->end.prefix = IPADDR_LEN(op->start.af);
590 xlat_len = fr_sbuff_in_sprintf(&FR_SBUFF_OUT(xlat, sizeof(xlat)),
591 "%%redis_ippool.addresses.remove('%s', '%pV', '%pV', %d)", op->pool,
592 fr_box_ipaddr(op->start), fr_box_ipaddr(op->end), op->prefix);
593 if (xlat_len < 0) return -1;
594
595 return run_xlat(ctx, list, request, &FR_SBUFF_IN(xlat, (size_t)xlat_len), el);
596}
597
598static int xlat_release_lease(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request,
600{
601 char xlat[1024];
602 ssize_t xlat_len;
603
604 op->start.prefix = op->end.prefix = IPADDR_LEN(op->start.af);
605 xlat_len = fr_sbuff_in_sprintf(&FR_SBUFF_OUT(xlat, sizeof(xlat)),
606 "%%redis_ippool.addresses.release('%s', '%pV', '%pV', %d)", op->pool,
607 fr_box_ipaddr(op->start), fr_box_ipaddr(op->end), op->prefix);
608 if (xlat_len < 0) return -1;
609
610 return run_xlat(ctx, list, request, &FR_SBUFF_IN(xlat, (size_t)xlat_len), el);
611}
612
613static int xlat_modify_lease(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request,
615{
616 char xlat[1024];
617 ssize_t xlat_len;
618
619 op->start.prefix = op->end.prefix = IPADDR_LEN(op->start.af);
620 xlat_len = fr_sbuff_in_sprintf(&FR_SBUFF_OUT(xlat, sizeof(xlat)),
621 "%%redis_ippool.addresses.modify('%s', '%pV', '%pV', '%s', %d)", op->pool,
622 fr_box_ipaddr(op->start), fr_box_ipaddr(op->end), op->range, op->prefix);
623 if (xlat_len < 0) return -1;
624
625 return run_xlat(ctx, list, request, &FR_SBUFF_IN(xlat, (size_t)xlat_len), el);
626}
627
628static int xlat_assign_lease(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request,
629 ippool_tool_operation_t *op, char const *owner, fr_event_list_t *el)
630{
631 char xlat[1024];
632 ssize_t xlat_len;
633
634 if (op->range) {
635 xlat_len = fr_sbuff_in_sprintf(&FR_SBUFF_OUT(xlat, sizeof(xlat)),
636 "%%redis_ippool.address.assign('%s', '%pV', '%s', '%s')", op->pool,
637 fr_box_ipaddr(op->start), owner, op->range);
638 } else {
639 xlat_len = fr_sbuff_in_sprintf(&FR_SBUFF_OUT(xlat, sizeof(xlat)),
640 "%%redis_ippool.address.assign('%s', '%pV', '%s')", op->pool,
641 fr_box_ipaddr(op->start), owner);
642 }
643 if (xlat_len < 0) return -1;
644
645 return run_xlat(ctx, list, request, &FR_SBUFF_IN(xlat, (size_t)xlat_len), el);
646}
647
648static int xlat_unassign_lease(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request,
649 ippool_tool_operation_t *op, char const *owner, fr_event_list_t *el)
650{
651 char xlat[1024];
652 ssize_t xlat_len;
653
654 xlat_len = fr_sbuff_in_sprintf(&FR_SBUFF_OUT(xlat, sizeof(xlat)),
655 "%%redis_ippool.address.unassign('%s', '%pV', '%s')", op->pool,
656 fr_box_ipaddr(op->start), owner);
657 if (xlat_len < 0) return -1;
658
659 return run_xlat(ctx, list, request, &FR_SBUFF_IN(xlat, (size_t)xlat_len), el);
660}
661
662/** Run the redis_ippool.pools.list xlat to fetch the list of pools across the cluster.
663 */
664static int redis_ippool_get_pools(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, fr_event_list_t *el)
665{
666 char xlat[] = "%redis_ippool.pools.list()";
667
668 return run_xlat(ctx, list, request, &FR_SBUFF_IN(xlat, sizeof(xlat) - 1), el);
669}
670
671static request_t *request_from_internal(TALLOC_CTX *ctx)
672{
673 request_t *request;
674
675 /*
676 * Create and initialize the new request.
677 */
678 request = request_local_alloc_internal(ctx, NULL);
679 if (!request->packet) request->packet = fr_packet_alloc(request, false);
680 if (!request->reply) request->reply = fr_packet_alloc(request, false);
681
682 request->packet->socket = (fr_socket_t){
683 .type = SOCK_DGRAM,
684 .inet = {
685 .src_ipaddr = {
686 .af = AF_INET,
687 .prefix = 32,
688 .addr = {
689 .v4 = {
690 .s_addr = htonl(INADDR_LOOPBACK)
691 }
692 }
693 },
694 .src_port = 18120,
695 .dst_ipaddr = {
696 .af = AF_INET,
697 .prefix = 32,
698 .addr = {
699 .v4 = {
700 .s_addr = htonl(INADDR_LOOPBACK)
701 }
702 }
703 },
704 .dst_port = 1812
705 }
706 };
707
708 request->log.dst = talloc_zero(request, log_dst_t);
709 request->log.dst->func = vlog_request;
710 request->log.dst->uctx = &default_log;
711 request->log.dst->lvl = fr_debug_lvl;
712
713 request->master_state = REQUEST_ACTIVE;
714 request->log.lvl = fr_debug_lvl;
715 request->async = talloc_zero(request, fr_async_t);
716
717 if (fr_packet_pairs_from_packet(request->request_ctx, &request->request_pairs, request->packet) < 0) {
718 talloc_free(request);
719 fprintf(stderr, "Failed converting packet IPs to attributes");
720 return NULL;
721 }
722
723 return request;
724}
725
726int main(int argc, char *argv[])
727{
728 static ippool_tool_operation_t ops[128];
729 ippool_tool_operation_t *p = ops, *end = ops + (NUM_ELEMENTS(ops));
730
731 int c, ret = EXIT_SUCCESS;
732
733 uint8_t *range_arg = NULL;
734 uint8_t *pool_arg = NULL;
735 bool do_export = false, print_stats = false, list_pools = false;
736 bool need_pool = false;
737 char *do_import = NULL;
738 char *filename = NULL;
739 char const *owner = NULL;
740
741 request_t *request = NULL;
742 fr_event_list_t *el = NULL;
743 fr_dict_t *dict = NULL;
744
745 TALLOC_CTX *autofree;
746 TALLOC_CTX *thread_ctx;
747
748 char *n;
750 char tmpdir[] = "/tmp/ippool_toolXXXXXX";
751 char filepath[sizeof("/tmp/ippool_toolXXXXXX/rlm_redis_ippool_tool.conf")];
752 FILE *conf_file;
753
754 fr_value_box_list_t vb_list; // To store results of xlat calls.
755 fr_value_box_t *changed;
756
757 virtual_server_t const *vs;
759 CONF_SECTION *pool_stats, *pool_show; // Process sections used to call module methods
760
761 fr_value_box_list_init(&vb_list);
762
763 name = argv[0];
764
766
768 thread_ctx = talloc_new(autofree);
769
771 if (!config) {
772 fr_perror("%s", name);
773 fr_exit_now(EXIT_FAILURE);
774 }
775
776 n = strrchr(name, FR_DIR_SEP);
777 if (!n) {
779 } else {
781 }
782
784
785#ifndef NDEBUG
786 if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), name, PANIC_ACTION_SIGNALS) < 0) {
787 fr_perror("%s", config->name);
788 fr_exit_now(EXIT_FAILURE);
789 }
790#else
792#endif
793
794 fr_debug_lvl = 0;
796
797#define ADD_ACTION(_action) \
798do { \
799 if (p >= end) { \
800 ERROR("Too many actions, max is " STRINGIFY(sizeof(ops))); \
801 usage(64); \
802 } \
803 p->action = _action; \
804 p->name = optarg; \
805 p++; \
806 need_pool = true; \
807} while (0)
808
809 while ((c = getopt(argc, argv, "a:d:D:r:s:Sm:A:U:O:p:ilLhxo:f:")) != -1) switch (c) {
810 case 'a':
812 break;
813
814 case 'd':
816 break;
817
818 case 'D':
820 break;
821
822 case 'r':
824 break;
825
826 case 's':
828 break;
829
830 case 'm':
832 break;
833
834 case 'A':
836 break;
837
838 case 'U':
840 break;
841
842 case 'O':
843 owner = optarg;
844 break;
845
846 case 'p':
847 {
848 unsigned long tmp;
849 char *q;
850
851 if (p == ops) {
852 ERROR("Prefix may only be specified after a pool management action");
853 usage(64);
854 }
855
856 tmp = strtoul(optarg, &q, 10);
857 if (q != (optarg + strlen(optarg))) {
858 ERROR("Prefix must be an integer value");
859 usage(64);
860 }
861
862 (p - 1)->prefix = (uint8_t)tmp & 0xff;
863 }
864 break;
865
866 case 'i':
867 do_import = optarg;
868 break;
869
870 case 'I':
871 do_export = true;
872 break;
873
874 case 'l':
875 if (list_pools) usage(1); /* Only allowed once */
876 list_pools = true;
877 break;
878
879 case 'S':
880 print_stats = true;
881 break;
882
883 case 'h':
884 usage(0);
885
886 case 'x':
887 fr_debug_lvl++;
888 break;
889
890 case 'o':
891 break;
892
893 case 'f':
894 filename = optarg;
895 break;
896
897 default:
898 usage(1);
899 }
900 argc -= optind;
901 argv += optind;
902
903 if (argc == 0) {
904 ERROR("Need server address/port");
905 usage(64);
906 }
907 if ((argc == 1) && need_pool) {
908 ERROR("Need pool to operate on");
909 usage(64);
910 }
911 if (argc > 3) usage(64);
912
914 fr_perror("%s", config->name);
915 ret = EXIT_FAILURE;
916 goto cleanup;
917 }
918
919 modules_init(config->lib_dir);
920
921 if (!fr_dict_global_ctx_init(NULL, true, config->dict_dir)) {
922 fr_perror("%s", config->name);
924 }
925
927 fr_perror("%s", config->name);
929 }
930
932 fr_perror("%s", config->name);
934 }
935
937 fr_perror("%s", config->name);
939 }
940
941 if (request_global_init() < 0) {
942 fr_perror("%s", config->name);
944 }
945
946 if (main_loop_init() < 0) {
947 PERROR("Failed initialising main event loop");
949 }
950
951 if (unlang_global_init() < 0) {
952 fr_perror("%s", config->name);
954 }
955
956 if (modules_rlm_init() < 0) {
957 fr_perror("%s", config->name);
959 }
960 if (virtual_servers_init() < 0) {
961 fr_perror("%s", config->name);
963 }
964
965 /*
966 * Build a temporary configuration file, merging in command
967 * line provided options.
968 */
969 if (!mkdtemp(tmpdir)) EXIT_WITH_FAILURE;
971 snprintf(filepath, sizeof(filepath), "%s/%s.conf", config->confdir, config->name);
972 conf_file = fopen(filepath, "w");
973 if (!conf_file) EXIT_WITH_FAILURE;
974 fputs(server_conf1, conf_file);
975 if (filename) {
976 fprintf(conf_file, "$INCLUDE %s\n", filename);
977 } else {
978 fprintf(conf_file, "server = %s\n", argv[0]);
979 }
980 fputs(server_conf2, conf_file);
981 fclose(conf_file);
982
984 unlink(filepath);
985 rmdir(tmpdir);
986
987 if (ret < 0) EXIT_WITH_FAILURE;
988
989 if (!client_find(NULL, &(fr_ipaddr_t) { .af = AF_INET, .prefix = 32, .addr.v4.s_addr = htonl(INADDR_LOOPBACK) },
990 IPPROTO_IP)) EXIT_WITH_FAILURE;
991
992 if (server_init(config->root_cs, config->confdir, dict) < 0) EXIT_WITH_FAILURE;
993
995 fr_assert(el);
996
998
1000 if (fr_thread_instantiate(thread_ctx, el) < 0) {
1001 fr_perror("%s", config->name);
1003 }
1004
1005 if (modules_rlm_coord_attach(el) < 0) {
1006 fr_perror("%s", config->name);
1008 }
1009
1010 if (fr_coord_pre_event_insert(el) < 0) {
1011 fr_strerror_const("Failed adding coordinator pre-check to event list");
1013 }
1014
1015 if (fr_coord_post_event_insert(el) < 0) {
1016 fr_strerror_const("Failed adding coordinator pre-check to event list");
1018 }
1019
1021
1022 vs = virtual_server_find("default");
1023 mi = module_rlm_static_by_name(NULL, "redis_ippool");
1024 if (!mi) EXIT_WITH_FAILURE;
1025
1026 /*
1027 * The module methods for these functions use call_env - which
1028 * preclude them being used with unlang_module_push. Instead they
1029 * need to be called from compiled process sections.
1030 * To avoid inventing another process module, these have been
1031 * wrapped in standard RADIUS process sections.
1032 */
1033 pool_stats = cf_section_find(virtual_server_cs(vs), "recv", "Access-Request");
1034 if (!pool_stats) EXIT_WITH_FAILURE;
1035 pool_show = cf_section_find(virtual_server_cs(vs), "recv", "Accounting-Request");
1036 if (!pool_show) EXIT_WITH_FAILURE;
1037
1038 /*
1039 * Unescape sequences in the pool name
1040 */
1041 if (argv[1] && (argv[1][0] != '\0')) {
1044
1045 MEM(fr_sbuff_init_talloc(autofree, &out, &tctx, strlen(argv[1]) + 1, SIZE_MAX));
1046 if (fr_value_str_unescape(NULL, &out, &FR_SBUFF_IN_STR(argv[1]), SIZE_MAX, '"') < 0) {
1047 ERROR("Failed unescaping pool name");
1048 fr_exit_now(EXIT_FAILURE);
1049 }
1050 talloc_realloc(autofree, out.buff, uint8_t, fr_sbuff_used(&out));
1051 pool_arg = (uint8_t *)out.buff;
1052 }
1053
1054 if (argc >= 3 && (argv[2][0] != '\0')) {
1057
1058 MEM(fr_sbuff_init_talloc(autofree, &out, &tctx, strlen(argv[1]) + 1, SIZE_MAX));
1059 if (fr_value_str_unescape(NULL, &out, &FR_SBUFF_IN_STR(argv[2]), SIZE_MAX, '"') < 0) {
1060 ERROR("Failed unescaping range name");
1061 fr_exit_now(EXIT_FAILURE);
1062 }
1063 talloc_realloc(autofree, out.buff, uint8_t, fr_sbuff_used(&out));
1064 range_arg = (uint8_t *)out.buff;
1065 }
1066
1067 if (!do_import && !do_export && !list_pools && !print_stats && (p == ops)) {
1068 ERROR("Nothing to do!");
1069 fr_exit_now(EXIT_FAILURE);
1070 }
1071
1072 if (do_import) {
1073 ERROR("NOT YET IMPLEMENTED");
1074 }
1075
1076 if (do_export) {
1077 ERROR("NOT YET IMPLEMENTED");
1078 }
1079
1080 if (print_stats) {
1081 fr_value_box_list_t pools;
1082 fr_pair_t *stats, *st, *dyn;
1083 fr_pair_t *total, *static_total, *static_free, *dyn_free;
1084 fr_pair_t *exp1m, *exp30m, *exp1h, *exp1d;
1085
1086 fr_value_box_list_init(&pools);
1087 if (pool_arg) {
1088 fr_value_box_t *vb;
1090 fr_value_box_bstrndup(vb, vb, NULL, (char *)pool_arg, talloc_array_length(pool_arg), false);
1091 fr_value_box_list_insert_tail(&pools, vb);
1092 } else {
1093 if (redis_ippool_get_pools(autofree, &pools, request, el) < 0) EXIT_WITH_FAILURE;
1094 }
1095
1096 fr_value_box_list_foreach(&pools, vb) {
1097 if (redis_ippool_get_stats(request, vb, pool_stats, el) < 0) EXIT_WITH_FAILURE;
1098
1099 INFO("pool : %pV", vb);
1100 stats = fr_pair_find_by_da_nested(&request->control_pairs, attr_ippool_stats);
1101 if (!stats) EXIT_WITH_FAILURE;
1102
1103 st = fr_pair_find_by_da(&stats->vp_group, NULL, attr_ippool_stats_static);
1104 dyn = fr_pair_find_by_da(&stats->vp_group, NULL, attr_ippool_stats_dynamic);
1105 if (!st || !dyn) EXIT_WITH_FAILURE;
1106
1107 total = fr_pair_find_by_da_nested(&stats->vp_group, attr_ippool_stats_total);
1108 if (!total) EXIT_WITH_FAILURE;
1109 INFO("total : %pV", &total->data);
1110
1111 static_total = fr_pair_find_by_da(&st->vp_group, NULL, attr_ippool_stats_static_total);
1112 if (!static_total) EXIT_WITH_FAILURE;
1113 INFO("dynamic total : %" PRIu64, total->vp_uint64 - static_total->vp_uint64);
1114
1115 dyn_free = fr_pair_find_by_da(&dyn->vp_group, NULL, attr_ippool_stats_dynamic_free);
1116 if (!dyn_free) EXIT_WITH_FAILURE;
1117 INFO("dynamic free : %pV", &dyn_free->data);
1118 INFO("dynamic used : %" PRIu64, total->vp_uint64 - static_total->vp_uint64 - dyn_free->vp_uint64);
1119 if ((total->vp_uint64 - static_total->vp_uint64) > 0) {
1120 INFO("dynamic used (%%) : %.2Lf",
1121 ((long double)(total->vp_uint64 - dyn_free->vp_uint64 - static_total->vp_uint64) /
1122 (long double)(total->vp_uint64 - static_total->vp_uint64)) * 100);
1123 } else {
1124 INFO("used (%%) : 0");
1125 }
1126
1127 exp1m = fr_pair_find_by_da(&dyn->vp_group, NULL, attr_ippool_stats_dynamic_expire1m);
1128 exp30m = fr_pair_find_by_da(&dyn->vp_group, NULL, attr_ippool_stats_dynamic_expire30m);
1129 exp1h = fr_pair_find_by_da(&dyn->vp_group, NULL, attr_ippool_stats_dynamic_expire1h);
1130 exp1d = fr_pair_find_by_da(&dyn->vp_group, NULL, attr_ippool_stats_dynamic_expire1d);
1131 if (!exp1m || !exp30m || !exp1h || !exp1d) EXIT_WITH_FAILURE;
1132
1133 INFO("expiring 0-1m : %" PRIu64, exp1m->vp_uint64);
1134 INFO("expiring 1-30m : %" PRIu64, exp30m->vp_uint64 - exp1m->vp_uint64);
1135 INFO("expiring 30m-1h : %" PRIu64, exp1h->vp_uint64 - exp30m->vp_uint64);
1136 INFO("expiring 1h-1d : %" PRIu64, exp1d->vp_uint64 - exp1h->vp_uint64);
1137 INFO("static total : %pV", &static_total->data);
1138
1139 static_free = fr_pair_find_by_da(&st->vp_group, NULL, attr_ippool_stats_static_free);
1140 if (!static_free) EXIT_WITH_FAILURE;
1141 INFO("static 'free' : %pV", &static_free->data);
1142 INFO("static issued : %" PRIu64, static_total->vp_uint64 - static_free->vp_uint64);
1143 if (static_total->vp_uint64) {
1144 INFO("static issued (%%) : %.2Lf",
1145 ((long double)(static_total->vp_uint64 - static_free->vp_uint64) /
1146 (long double)(static_total->vp_uint64)) * 100);
1147 } else {
1148 INFO("static issued (%%) : 0");
1149 }
1150
1151 exp1m = fr_pair_find_by_da(&st->vp_group, NULL, attr_ippool_stats_static_renew1m);
1152 exp30m = fr_pair_find_by_da(&st->vp_group, NULL, attr_ippool_stats_static_renew30m);
1153 exp1h = fr_pair_find_by_da(&st->vp_group, NULL, attr_ippool_stats_static_renew1h);
1154 exp1d = fr_pair_find_by_da(&st->vp_group, NULL, attr_ippool_stats_static_renew1d);
1155 if (!exp1m || !exp30m || !exp1h || !exp1d) EXIT_WITH_FAILURE;
1156
1157 INFO("static renew 0-1m : %" PRIu64, exp1m->vp_uint64);
1158 INFO("static renew 1-30m : %" PRIu64, exp30m->vp_uint64 - exp1m->vp_uint64);
1159 INFO("static renew 30m-1h : %" PRIu64, exp1h->vp_uint64 - exp30m->vp_uint64);
1160 INFO("static renew 1h-1d : %" PRIu64, exp1d->vp_uint64 - exp1h->vp_uint64);
1161 INFO("--");
1162 }
1163 fr_value_box_list_talloc_free(&pools);
1164 }
1165
1166 if (list_pools) {
1167 fr_value_box_list_t pools;
1168
1169 fr_value_box_list_init(&pools);
1170 if (redis_ippool_get_pools(autofree, &pools, request, el) < 0) EXIT_WITH_FAILURE;
1171 fr_value_box_list_foreach(&pools, vb) INFO("%pV", vb);
1172 INFO("--");
1173 fr_value_box_list_talloc_free(&pools);
1174 }
1175
1176 /*
1177 * Fixup the operations without specific pools or ranges
1178 * and parse the IP ranges.
1179 */
1180 end = p;
1181 for (p = ops; p < end; p++) {
1182 if (parse_ip_range(&p->start, &p->end, p->name, p->prefix) < 0) usage(64);
1183 if (!p->prefix) p->prefix = IPADDR_LEN(p->start.af);
1184
1185 if (!p->pool) {
1186 p->pool = pool_arg;
1187 p->pool_len = talloc_array_length(pool_arg);
1188 }
1189 if (!p->range && range_arg) {
1190 p->range = range_arg;
1191 p->range_len = talloc_array_length(range_arg);
1192 }
1193 }
1194
1195 for (p = ops; (p < end) && (p->start.af != AF_UNSPEC); p++) switch (p->action) {
1196 case IPPOOL_TOOL_ADD:
1197 fr_value_box_list_talloc_free(&vb_list);
1198 if (xlat_add_lease(autofree, &vb_list, request, p, el) < 0) EXIT_WITH_FAILURE;
1199
1200 changed = fr_value_box_list_head(&vb_list);
1201 INFO("Added %pV address(es)/prefix(es), %pV unchanged", changed, fr_value_box_list_next(&vb_list, changed));
1202 continue;
1203
1204 case IPPOOL_TOOL_REMOVE:
1205 fr_value_box_list_talloc_free(&vb_list);
1206 if (xlat_remove_lease(autofree, &vb_list, request, p, el) < 0) EXIT_WITH_FAILURE;
1207
1208 changed = fr_value_box_list_head(&vb_list);
1209 INFO("Removed %pV address(es)/prefix(es), %pV unchanged", changed, fr_value_box_list_next(&vb_list, changed));
1210 continue;
1211
1213 fr_value_box_list_talloc_free(&vb_list);
1214 if (xlat_release_lease(autofree, &vb_list, request, p, el) < 0) EXIT_WITH_FAILURE;
1215
1216 changed = fr_value_box_list_head(&vb_list);
1217 INFO("Released %pV address(es)/prefix(es). %pV unchanged", changed, fr_value_box_list_next(&vb_list, changed));
1218 continue;
1219
1220 case IPPOOL_TOOL_SHOW:
1221 {
1222 fr_pair_t *ippool, *vp, *device, *gateway, *expires;
1223
1224 if (redis_ippool_show(request, p, pool_show, el) < 0) EXIT_WITH_FAILURE;
1225
1226 vp = fr_pair_find_by_da_nested(&request->control_pairs, attr_ippool_lease);
1227 if (vp) {
1228 ippool = fr_pair_parent(vp);
1229 } else {
1230 ippool = fr_pair_find_by_da(&request->control_pairs, NULL, attr_ippool);
1231 }
1232 if (!ippool) EXIT_WITH_FAILURE;
1233
1234 INFO("Retrieved information for %u address(es)/prefix(es)",
1235 fr_pair_count_by_da(&ippool->vp_group, attr_ippool_lease));
1236 fr_pair_list_foreach(&ippool->vp_group, lease) {
1237 if (lease->da != attr_ippool_lease) continue;
1238
1239 INFO("--");
1240 vp = fr_pair_find_by_da(&lease->vp_group, NULL, attr_ippool_lease_range);
1241 if (vp) INFO("range : %pV", &vp->data);
1242
1243 vp = fr_pair_find_by_da(&lease->vp_group, NULL, attr_ippool_lease_address);
1244 if (!vp) EXIT_WITH_FAILURE;
1245 INFO("address/prefix : %pV", &vp->data);
1246
1247 vp = fr_pair_find_by_da(&lease->vp_group, NULL, attr_ippool_lease_active);
1248 if (!vp) EXIT_WITH_FAILURE;
1249 INFO("active : %s", vp->vp_bool ? "yes" : "no");
1250
1251 device = fr_pair_find_by_da(&lease->vp_group, NULL, attr_ippool_lease_device);
1252 gateway = fr_pair_find_by_da(&lease->vp_group, NULL, attr_ippool_lease_gateway);
1253 expires = fr_pair_find_by_da(&lease->vp_group, NULL, attr_ippool_lease_expires);
1254
1255 if (vp->vp_bool) {
1256 if (expires) INFO("lease expires : %pV", &expires->data);
1257 if (device) INFO("device id : %pV", &device->data);
1258 if (gateway) INFO("gateway id : %pV", &gateway->data);
1259 } else {
1260 if (expires) INFO("lease expired : %pV", &expires->data);
1261 if (device) INFO("last device id : %pV", &device->data);
1262 if (gateway) INFO("last gateway id : %pV", &gateway->data);
1263 }
1264 }
1265 }
1266 continue;
1267
1268 case IPPOOL_TOOL_MODIFY:
1269 fr_value_box_list_talloc_free(&vb_list);
1270 if (xlat_modify_lease(autofree, &vb_list, request, p, el) < 0) EXIT_WITH_FAILURE;
1271
1272 changed = fr_value_box_list_head(&vb_list);
1273 INFO("Modified %pV address(es)/prefix(es), %pV unchanged", changed, fr_value_box_list_next(&vb_list, changed));
1274 continue;
1275
1276 case IPPOOL_TOOL_ASSIGN:
1277 if (fr_ipaddr_cmp(&p->start, &p->end) != 0) {
1278 ERROR("Static assignment requires a single IP");
1279 fr_exit_now(EXIT_FAILURE);
1280 }
1281 if (!owner) {
1282 ERROR("Static assignment requires an owner");
1283 fr_exit_now(EXIT_FAILURE);
1284 }
1285
1286 fr_value_box_list_talloc_free(&vb_list);
1287 if (xlat_assign_lease(autofree, &vb_list, request, p, owner, el) < 0) EXIT_WITH_FAILURE;
1288 INFO("Assigned %pV address(es)/prefix(es)", fr_value_box_list_head(&vb_list));
1289 continue;
1290
1292 if (fr_ipaddr_cmp(&p->start, &p->end) != 0) {
1293 ERROR("Static lease un-assignment requires a single IP");
1294 fr_exit_now(EXIT_FAILURE);
1295 }
1296 if (!owner) {
1297 ERROR("Static lease un-assignment requires an owner");
1298 fr_exit_now(EXIT_FAILURE);
1299 }
1300
1301 fr_value_box_list_talloc_free(&vb_list);
1302 if (xlat_unassign_lease(autofree, &vb_list, request, p, owner, el) < 0) EXIT_WITH_FAILURE;
1303 INFO("Un-assigned %pV address(es)/prefix(es)", fr_value_box_list_head(&vb_list));
1304 continue;
1305
1306 case IPPOOL_TOOL_NOOP:
1307 break;
1308 }
1309
1310cleanup:
1311
1312 /*
1313 * The same clean up sequence as unit_test_module.c
1314 */
1315 if (el && (modules_rlm_coord_detach() > 0)) {
1317 ERROR("Failed setting up coordinator close events");
1318 }
1320 }
1321 talloc_free(thread_ctx);
1326 server_free();
1331 fr_dict_free(&dict, __FILE__);
1334
1335 return ret;
1336}
int n
Definition acutest.h:577
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition atexit.c:179
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition atexit.c:310
#define fr_atexit_thread_trigger_all(...)
Definition atexit.h:236
#define RCSID(id)
Definition build.h:560
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:382
#define unlikely(_x)
Definition build.h:455
#define NUM_ELEMENTS(_t)
Definition build.h:406
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1205
TALLOC_CTX * autofree
Definition common.c:29
fr_dict_t * dict
Definition common.c:31
int fr_coords_create(TALLOC_CTX *ctx, fr_event_list_t *el)
Start coordinators in single threaded mode.
Definition coord.c:621
void fr_coords_destroy(void)
Clean up coordinators in single threaded mode.
Definition coord.c:603
int fr_coord_close_event_insert(fr_event_list_t *el)
Definition coord.c:905
int fr_coord_post_event_insert(fr_event_list_t *el)
Insert instance specific post-event callbacks.
Definition coord.c:861
int fr_coord_pre_event_insert(fr_event_list_t *el)
Insert instance specific pre-event callbacks.
Definition coord.c:836
void fr_disable_null_tracking_on_free(TALLOC_CTX *ctx)
Disable the null tracking context when a talloc chunk is freed.
Definition debug.c:1034
void fr_talloc_fault_setup(void)
Register talloc fault handlers.
Definition debug.c:1050
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program, unsigned long fault_signals)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1074
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:177
#define PANIC_ACTION_SIGNALS
Definition debug.h:133
#define MEM(x)
Definition debug.h:38
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:272
#define ERROR(fmt,...)
Definition dhcpclient.c:40
static NEVER_RETURNS void usage(void)
Definition dhcpclient.c:113
#define fr_dict_autofree(_to_free)
Definition dict.h:937
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir, char const *dependent))
(Re-)Initialize the special internal dictionary
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:316
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:329
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition dict_util.c:4466
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4532
#define fr_dict_autoload(_to_load)
Definition dict.h:934
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:335
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir))
Initialise the global protocol hashes.
Definition dict_util.c:4850
Specifies an attribute which must be present for the module to function.
Definition dict.h:315
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:328
talloc_free(hp)
int fr_inet_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser.
Definition inet.c:783
void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
Zeroes out the host portion of an fr_ipaddr_t.
Definition inet.c:218
fr_cmp_ret_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1353
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition inet.h:69
int af
Address family.
Definition inet.h:64
union fr_ipaddr_t::@142 addr
#define FR_IPADDR_PREFIX_STRLEN
Like FR_IPADDR_STRLEN but with space for a prefix.
Definition inet.h:93
IPv4/6 prefix.
int unlang_interpret_push_section(unlang_result_t *p_result, request_t *request, CONF_SECTION *cs, unlang_frame_conf_t const *conf)
Push a configuration section onto the request stack for later interpretation.
Definition interpret.c:1535
#define FRAME_CONF(_default_rcode, _top_frame)
Definition interpret.h:158
#define UNLANG_TOP_FRAME
Definition interpret.h:36
rlm_rcode_t unlang_interpret_synchronous(fr_event_list_t *el, request_t *request)
Execute an unlang section synchronously.
int server_init(CONF_SECTION *cs, char const *conf_dir, fr_dict_t *dict)
Initialize src/lib/server/.
Definition base.c:42
void server_free(void)
Free src/lib/server/.
Definition base.c:137
void vlog_request(fr_log_type_t type, fr_log_lvl_t lvl, request_t *request, char const *file, int line, char const *fmt, va_list ap, void *uctx)
Send a log message to its destination, possibly including fields from the request.
Definition log.c:293
#define PERROR(_fmt,...)
Definition log.h:233
Definition log.h:70
int fr_packet_pairs_from_packet(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_packet_t const *packet)
Allocate a "Net." struct with src/dst host and port.
Definition packet.c:91
int unlang_global_init(void)
Definition base.c:158
int fr_event_loop(fr_event_list_t *el)
Run an event loop.
Definition event.c:2405
Stores all information relating to an event list.
Definition event.c:377
int fr_debug_lvl
Definition log.c:41
fr_log_t default_log
Definition log.c:308
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition packet.c:38
Minimal data structure to use the new code.
Definition listen.h:63
int main_config_free(main_config_t **config)
main_config_t * main_config_alloc(TALLOC_CTX *ctx)
Allocate a main_config_t struct, setting defaults.
void main_config_name_set_default(main_config_t *config, char const *name, bool overwrite_config)
Set the server name.
int main_config_init(main_config_t *config)
void main_config_confdir_set(main_config_t *config, char const *name)
Set the global radius config directory.
void main_config_dict_dir_set(main_config_t *config, char const *name)
Set the global dictionary directory.
Main server configuration.
Definition main_config.h:59
fr_event_list_t * main_loop_event_list(void)
Return the main loop event list.
Definition main_loop.c:173
int main_loop_init(void)
Initialise the main event loop, setting up signal handlers.
Definition main_loop.c:262
void main_loop_free(void)
Definition main_loop.c:198
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_BOOL
A truth value.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
module_instance_t * module_rlm_static_by_name(module_instance_t const *parent, char const *asked_name)
Definition module_rlm.c:814
int modules_rlm_coord_attach(fr_event_list_t *el)
Runs the coord_attach method of all registered backend modules.
Definition module_rlm.c:992
int modules_rlm_free(void)
Cleanup all global structures.
int modules_rlm_coord_detach(void)
Runs the coord_detach method of all registered backend modules.
Definition module_rlm.c:999
int modules_rlm_init(void)
Initialise the module list structure.
unsigned int fr_pair_count_by_da(fr_pair_list_t const *list, fr_dict_attr_t const *da)
Return the number of instances of a given da in the specified list.
Definition pair.c:685
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
Definition pair.c:783
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:708
fr_pair_t * fr_pair_parent(fr_pair_t const *vp)
Return a pointer to the parent pair.
Definition pair.c:915
fr_pair_t * fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
Create a pair (and all intermediate parents), and append it to the list.
Definition pair.c:481
#define is_truncated(_ret, _max)
Definition print.h:48
static const conf_parser_t config[]
Definition base.c:162
#define fr_assert(_expr)
Definition rad_assert.h:37
#define INFO(fmt,...)
Definition radict.c:63
static bool cleanup
Definition radsniff.c:59
#define RLM_MODULE_USER_SECTION_REJECT
Rcodes that translate to a user configurable section failing overall.
Definition rcode.h:79
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:44
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:49
#define IPADDR_LEN(_af)
#define IPPOOL_SPRINT_IP(_buff, _ip, _prefix)
If the prefix is as wide as the AF data size then print it without CIDR notation.
int request_global_init(void)
Definition request.c:598
#define request_local_alloc_internal(_ctx, _args)
Allocate a new internal request outside of the request pool.
Definition request.h:344
@ REQUEST_ACTIVE
Request is active (running or runnable)
Definition request.h:89
static fr_dict_attr_t const * attr_ippool_stats_dynamic_expire1d
int main(int argc, char *argv[])
static int xlat_remove_lease(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, ippool_tool_operation_t *op, fr_event_list_t *el)
fr_dict_attr_autoload_t redis_ippool_tool_dict_attr[]
static fr_dict_attr_t const * attr_ippool_stats_static_renew1m
char const * name
Original range or CIDR string.
static fr_dict_attr_t const * attr_ippool_stats_static
static fr_dict_attr_t const * attr_ippool_stats_static_renew1h
static fr_dict_attr_t const * attr_ippool_stats_dynamic_free
static char server_conf2[]
static fr_dict_attr_t const * attr_ippool_stats_static_renew30m
static int xlat_release_lease(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, ippool_tool_operation_t *op, fr_event_list_t *el)
static fr_dict_attr_t const * attr_ippool_stats_dynamic_expire1m
static fr_dict_attr_t const * attr_ippool_lease_device
static fr_dict_attr_t const * attr_ippool_stats_dynamic_expire30m
static fr_dict_attr_t const * attr_ippool_lease_gateway
static fr_dict_t const * dict_freeradius
#define EOL
static fr_dict_attr_t const * attr_ippool_stats_static_total
static fr_dict_attr_t const * attr_ippool_name
fr_dict_autoload_t redis_ippool_tool_dict[]
size_t pool_len
Length of the pool identifier.
static int redis_ippool_get_stats(request_t *request, fr_value_box_t *pool_name, CONF_SECTION *section, fr_event_list_t *el)
Run the redis_ippool.stats module method to fetch pool statistics.
static fr_dict_attr_t const * attr_ippool_stats_static_free
static char const * name
static fr_dict_attr_t const * attr_ippool_lease
static char server_conf1[]
Static server config split into two parts.
static uint32_t uint32_gen_mask(uint8_t bits)
static fr_dict_attr_t const * attr_ippool_lease_active
static int xlat_add_lease(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, ippool_tool_operation_t *op, fr_event_list_t *el)
static fr_dict_attr_t const * attr_ippool
static fr_dict_attr_t const * attr_ippool_stats_dynamic
#define ADD_ACTION(_action)
static int xlat_unassign_lease(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, ippool_tool_operation_t *op, char const *owner, fr_event_list_t *el)
static int redis_ippool_show(request_t *request, ippool_tool_operation_t const *op, CONF_SECTION *section, fr_event_list_t *el)
Run the redis_ippool.show module method to fetch lease details.
uint8_t const * range
Range identifier.
static fr_dict_attr_t const * attr_ippool_lease_address
static fr_dict_attr_t const * attr_ippool_lease_expires
uint8_t prefix
Prefix - The bits between the address mask, and the prefix form the addresses to be modified in the p...
uint8_t const * pool
Pool identifier.
ippool_tool_action_t action
What to do to the leases described by net/prefix.
size_t range_len
Length of the range identifier.
fr_ipaddr_t end
End address.
#define EXIT_WITH_FAILURE
ippool_tool_action
Pool management actions.
@ IPPOOL_TOOL_ADD
Add one or more IP addresses.
@ IPPOOL_TOOL_REMOVE
Remove one or more IP addresses.
@ IPPOOL_TOOL_NOOP
Do nothing.
@ IPPOOL_TOOL_MODIFY
Modify attributes of one or more IP addresses.
@ IPPOOL_TOOL_SHOW
Show one or more IP addresses.
@ IPPOOL_TOOL_ASSIGN
Assign a static IP address to a device.
@ IPPOOL_TOOL_RELEASE
Release one or more IP addresses.
@ IPPOOL_TOOL_UNASSIGN
Remove static IP address assignment.
static fr_dict_attr_t const * attr_ippool_lease_range
static int parse_ip_range(fr_ipaddr_t *start_out, fr_ipaddr_t *end_out, char const *ip_str, uint8_t prefix)
Convert an IP range or CIDR mask to a start and stop address.
static fr_dict_attr_t const * attr_ippool_stats
static fr_dict_attr_t const * attr_ippool_stats_dynamic_expire1h
fr_ipaddr_t start
Start address.
static fr_dict_attr_t const * attr_ippool_stats_static_renew1d
static int xlat_modify_lease(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, ippool_tool_operation_t *op, fr_event_list_t *el)
static int redis_ippool_get_pools(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, fr_event_list_t *el)
Run the redis_ippool.pools.list xlat to fetch the list of pools across the cluster.
static fr_dict_attr_t const * attr_ippool_stats_dynamic_total
static int run_xlat(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, fr_sbuff_t *xlat, fr_event_list_t *el)
static bool ipaddr_next(fr_ipaddr_t *ipaddr, fr_ipaddr_t const *end, uint8_t prefix)
Iterate over range of IP addresses.
static int xlat_assign_lease(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, ippool_tool_operation_t *op, char const *owner, fr_event_list_t *el)
static request_t * request_from_internal(TALLOC_CTX *ctx)
static fr_dict_attr_t const * attr_ippool_stats_total
enum ippool_tool_action ippool_tool_action_t
Pool management actions.
A single pool operation.
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition sbuff.c:1680
#define FR_SBUFF_IN(_start, _len_or_end)
#define FR_SBUFF_IN_STR(_start)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_used(_sbuff_or_marker)
Talloc sbuff extension structure.
Definition sbuff.h:137
Set of parsing rules for *unescape_until functions.
void fr_schedule_worker_id_set(int id)
Explicitly set the worker id for the current thread.
Definition schedule.c:120
Module instance data.
Definition module.h:289
struct tmpl_rules_s tmpl_rules_t
Definition tmpl.h:240
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:370
void modules_init(char const *lib_dir)
Perform global initialisation for modules.
Definition module.c:1981
fr_pair_t * vp
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition strlcpy.c:34
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:55
int fr_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Instantiate thread-specific data for modules, virtual servers, xlats, unlang, and TLS.
Definition thread.c:165
int fr_time_start(void)
Initialize the local time.
Definition time.c:157
static uint128_t uint128_new(uint64_t h, uint64_t l)
Creates a new uint128_t from a uint64_t.
Definition uint128.h:268
static uint128_t uint128_gen_mask(uint8_t bits)
Create a 128 bit integer value with n bits high.
Definition uint128.h:65
static uint128_t uint128_bor(uint128_t a, uint128_t b)
Perform bitwise | of two 128bit unsigned integers.
Definition uint128.h:239
static uint128_t uint128_lshift(uint128_t num, uint8_t bits)
Left shift 128 bit integer.
Definition uint128.h:191
static bool uint128_gt(uint128_t a, uint128_t b)
Return whether one integer is greater than the other.
Definition uint128.h:258
static bool uint128_eq(uint128_t a, uint128_t b)
Return whether the integers are equal.
Definition uint128.h:250
static uint128_t uint128_sub(uint128_t a, uint128_t b)
Subtract one 128bit integer from another.
Definition uint128.h:128
static uint128_t uint128_add(uint128_t a, uint128_t b)
Add two 128bit unsigned integers.
Definition uint128.h:115
static fr_event_list_t * el
int unlang_xlat_push(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
Definition xlat.c:269
bool xlat_needs_resolving(xlat_exp_head_t const *head)
Check to see if the expansion needs resolving.
fr_slen_t xlat_tokenize(TALLOC_CTX *ctx, xlat_exp_head_t **head, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
Tokenize an xlat expansion.
int xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules)
Walk over an xlat tree recursively, resolving any unresolved functions or references.
#define FR_DICTIONARY_INTERNAL_DIR
Definition conf.h:7
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition pair.h:281
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
Holds information necessary for binding or connecting to a socket.
Definition socket.h:60
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:737
#define fr_strerror_const(_msg)
Definition strerror.h:223
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition version.c:40
#define RADIUSD_MAGIC_NUMBER
Definition version.h:81
fr_slen_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules)
Definition value.c:6141
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition value.c:4421
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
Definition value.c:4899
fr_sbuff_err_t fr_value_str_unescape(size_t *len, fr_sbuff_t *out, fr_sbuff_t *in, size_t max, char quote)
Convert a string value with escape sequences into its binary form.
Definition value.c:1223
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:669
#define fr_box_ipaddr(_val)
Definition value.h:342
static fr_sbuff_err_t char ** out
Definition value.h:1062
static fr_sbuff_err_t char size_t * len
Definition value.h:1062
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:247
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.
int virtual_servers_init(void)
Performs global initialisation for the virtual server code.
int virtual_servers_free(void)