41RCSID(
"$Id: 6880a4ab7cf900174202758169877ac2b4c1d2a1 $")
43#include <freeradius-devel/server/base.h>
44#include <freeradius-devel/server/module_rlm.h>
45#include <freeradius-devel/server/modpriv.h>
47#include <freeradius-devel/util/debug.h>
48#include <freeradius-devel/util/base16.h>
49#include <freeradius-devel/util/token.h>
51#include <freeradius-devel/redis/base.h>
52#include <freeradius-devel/redis/cluster.h>
198 .pair.dflt =
"reply.IP-Pool.Range", .pair.dflt_quote =
T_BARE_WORD },
216 .pair.dflt =
"reply.IP-Pool.Range", .pair.dflt_quote =
T_BARE_WORD },
265 "local address_key" EOL
266 "local owner_key" EOL
271 "local wall_time = tonumber(ARGV[1])" EOL
280 "exists = redis.call('GET', owner_key);" EOL
282 " local expires = tonumber(redis.call('ZSCORE', pool_key, exists))" EOL
285 " if expires_in > 0 or static then" EOL
286 " ip = redis.call('HMGET', '{' .. KEYS[1] .. '}:"IPPOOL_ADDRESS_KEY":' .. exists, 'device', 'range', 'counter', 'gateway')" EOL
287 " if ip and (ip[1] == ARGV[3]) then" EOL
288 " if expires_in < tonumber(ARGV[2]) then" EOL
290 " expires_in = tonumber(ARGV[2])" EOL
291 " if not static then" EOL
292 " redis.call('EXPIRE', owner_key, ARGV[2])" EOL
299 " if ARGV[4] ~= ip[4] then" EOL
311 "if ARGV[5] and ARGV[5] ~= '' then" EOL
312 " local expires = tonumber(redis.call('ZSCORE', pool_key, ARGV[5]))" EOL
313 " if expires and tonumber(expires) < wall_time then" EOL
314 " ip = { ARGV[5] }" EOL
322 " ip = redis.call('ZREVRANGE', pool_key, -1, -1, 'WITHSCORES')" EOL
323 " if not ip or not ip[1] then" EOL
326 " if tonumber(ip[2]) >= wall_time then" EOL
330 "redis.call('ZADD', pool_key, 'XX', ARGV[1] + ARGV[2], ip[1])" EOL
336 "redis.call('HMSET', address_key, 'device', ARGV[3], 'gateway', ARGV[4])" EOL
337 "redis.call('SET', owner_key, ip[1])" EOL
338 "redis.call('EXPIRE', owner_key, ARGV[2])" EOL
342 " redis.call('HGET', address_key, 'range'), " EOL
343 " tonumber(ARGV[2]), " EOL
344 " redis.call('HINCRBY', address_key, 'counter', 1)" EOL
368 "local address_key" EOL
369 "local owner_key" EOL
376 "found = redis.call('HMGET', address_key, 'range', 'device', 'gateway', 'counter' )" EOL
380 "if not found[2] then" EOL
383 "if found[2] ~= ARGV[4] then" EOL
391 "local expires = tonumber(redis.call('ZSCORE', pool_key, ARGV[3]))" EOL
402 "if not static and (redis.call('EXPIRE', owner_key, ARGV[2]) == 0) then" EOL
403 " redis.call('SET', owner_key, ARGV[3])" EOL
404 " redis.call('EXPIRE', owner_key, ARGV[2])" EOL
410 "if ARGV[5] ~= found[3] then" EOL
411 " redis.call('HSET', address_key, 'gateway', ARGV[5])" EOL
436 "local address_key" EOL
437 "local owner_key" EOL
444 "found = redis.call('HGET', address_key, 'device')" EOL
445 "if not found then" EOL
448 "if found and found ~= ARGV[3] then" EOL
456 "found = tonumber(redis.call('ZSCORE', pool_key, ARGV[2]))" EOL
463 "if not static then" EOL
465 " redis.call('DEL', owner_key)" EOL
469 " redis.call('HINCRBY', address_key, 'counter', 1) - 1" EOL
484 if (!wait_num)
return 0;
486 if (reply->type != REDIS_REPLY_INTEGER) {
487 REDEBUG(
"WAIT result is wrong type, expected integer got %s",
491 if (reply->integer < wait_num) {
492 REDEBUG(
"Too few slaves acknowledged allocation, needed %i, got %lli",
493 wait_num, reply->integer);
507 char *device_str = NULL, *gateway_str = NULL;
509 if (gateway_id && gateway_id->vb_length > 0) gateway_str =
fr_asprint(request, gateway_id->vb_strvalue,
510 gateway_id->vb_length,
'"');
511 if (owner && owner->vb_length > 0) device_str =
fr_asprint(request, owner->vb_strvalue, owner->vb_length,
'"');
515 RDEBUGX(lvl,
"Allocating lease from pool \"%pV\"%s%s%s%s%s%s, expires in %us",
517 device_str ?
", to \"" :
"", device_str ? device_str :
"",
518 device_str ?
"\"" :
"",
519 gateway_str ?
", on \"" :
"", gateway_str ? gateway_str :
"",
520 gateway_str ?
"\"" :
"",
525 RDEBUGX(lvl,
"Updating %pV in pool \"%pV\"%s%s%s%s%s%s, expires in %us",
527 device_str ?
", device \"" :
"", device_str ? device_str :
"",
528 device_str ?
"\"" :
"",
529 gateway_str ?
", gateway \"" :
"", gateway_str ? gateway_str :
"",
530 gateway_str ?
"\"" :
"",
535 RDEBUGX(lvl,
"Releasing %pV%s%s%s to pool \"%pV\"",
537 device_str ?
" leased by \"" :
"", device_str ? device_str :
"",
538 device_str ?
"\"" :
"",
575 uint8_t const *key,
size_t key_len,
577 char const digest[],
char const *script,
578 char const *cmd, ...)
581 redisReply *replies[5];
582 size_t reply_cnt = 0, i;
586 unsigned int pipelined = 0;
593 memset(replies, 0,
sizeof(replies));
603 RDEBUG3(
"Calling script 0x%s", digest);
605 redisvAppendCommand(conn->
handle, cmd, copy);
627 RDEBUG3(
"Loading script 0x%s", digest);
628 redisAppendCommand(conn->
handle,
"MULTI");
629 redisAppendCommand(conn->
handle,
"SCRIPT LOAD %s", script);
631 redisvAppendCommand(conn->
handle, cmd, copy);
633 redisAppendCommand(conn->
handle,
"EXEC");
648 if (replies[3]->
type != REDIS_REPLY_ARRAY) {
649 RERROR(
"Bad response to EXEC, expected array got %s",
656 if (replies[3]->elements != 2) {
657 RERROR(
"Bad response to EXEC, expected 2 result elements, got %zu",
658 replies[3]->elements);
661 if (replies[3]->element[0]->
type != REDIS_REPLY_STRING) {
662 RERROR(
"Bad response to SCRIPT LOAD, expected string got %s",
666 if (strcmp(replies[3]->element[0]->str, digest) != 0) {
667 RWDEBUG(
"Incorrect SHA1 from SCRIPT LOAD, expected %s, got %s",
668 digest, replies[3]->element[0]->str);
694 *
out = replies[3]->element[1];
695 replies[3]->element[1] = NULL;
715 redisReply *reply = NULL;
730 "EVALSHA %s 1 %b %u %u %b %b %u",
733 (
unsigned int)now.tv_sec, lease_time,
749 "EVALSHA %s 1 %b %u %u %b %b %s",
752 (
unsigned int)now.tv_sec, lease_time,
763 if (reply->type != REDIS_REPLY_ARRAY) {
764 REDEBUG(
"Expected result to be array got \"%s\"",
770 if (reply->elements == 0) {
771 REDEBUG(
"Got empty result array");
779 if (reply->element[0]->type != REDIS_REPLY_INTEGER) {
780 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
785 ret = reply->element[0]->integer;
786 if (ret < 0)
goto finish;
791 if (reply->elements > 1) {
800 switch (reply->element[1]->type) {
807 case REDIS_REPLY_INTEGER:
815 RPEDEBUG(
"Failed converting integer to IPv4 address");
826 case REDIS_REPLY_STRING:
828 NULL, reply->element[1]->str, reply->element[1]->len,
false);
837 REDEBUG(
"Server returned unexpected type \"%s\" for IP element (result[1])",
847 if (reply->elements > 2) {
848 switch (reply->element[2]->type) {
852 case REDIS_REPLY_STRING:
863 NULL, reply->element[2]->str, reply->element[2]->len,
true);
871 case REDIS_REPLY_NIL:
875 REDEBUG(
"Server returned unexpected type \"%s\" for range element (result[2])",
894 if (reply->element[3]->type != REDIS_REPLY_INTEGER) {
895 REDEBUG(
"Server returned unexpected type \"%s\" for expiry element (result[3])",
923 redisReply *reply = NULL;
930 if ((ip->
af == AF_INET) &&
inst->ipv4_integer) {
935 "EVALSHA %s 1 %b %u %u %u %b %b",
938 (
unsigned int)now.tv_sec, expires,
939 htonl(ip->
addr.v4.s_addr),
940 (
uint8_t const *)owner->vb_strvalue, owner->vb_length,
941 (
uint8_t const *)gateway_id->vb_strvalue, gateway_id->vb_length);
950 "EVALSHA %s 1 %b %u %u %s %b %b",
953 (
unsigned int)now.tv_sec, expires,
955 (
uint8_t const *)owner->vb_strvalue, owner->vb_length,
956 (
uint8_t const *)gateway_id->vb_strvalue, gateway_id->vb_length);
963 if (reply->type != REDIS_REPLY_ARRAY) {
964 REDEBUG(
"Expected result to be array got \"%s\"",
970 if (reply->elements == 0) {
971 REDEBUG(
"Got empty result array");
979 if (reply->element[0]->type != REDIS_REPLY_INTEGER) {
980 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
985 ret = reply->element[0]->integer;
986 if (ret < 0)
goto finish;
991 if (reply->elements > 1) {
992 switch (reply->element[1]->type) {
996 case REDIS_REPLY_STRING:
1003 reply->element[1]->str, reply->element[1]->len,
true);
1011 case REDIS_REPLY_NIL:
1015 REDEBUG(
"Server returned unexpected type \"%s\" for range element (result[1])",
1027 map_t expiry_map = {
1058 redisReply *reply = NULL;
1065 if ((ip->
af == AF_INET) &&
inst->ipv4_integer) {
1067 (
uint8_t const *)key_prefix->vb_strvalue, key_prefix->vb_length,
1068 inst->wait_num,
inst->wait_timeout,
1070 "EVALSHA %s 1 %b %u %u %b",
1072 (
uint8_t const *)key_prefix->vb_strvalue, key_prefix->vb_length,
1073 (
unsigned int)now.tv_sec,
1074 htonl(ip->
addr.v4.s_addr),
1075 (
uint8_t const *)owner->vb_strvalue, owner->vb_length);
1081 (
uint8_t const *)key_prefix->vb_strvalue, key_prefix->vb_length,
1082 inst->wait_num,
inst->wait_timeout,
1084 "EVALSHA %s 1 %b %u %s %b",
1086 (
uint8_t const *)key_prefix->vb_strvalue, key_prefix->vb_length,
1087 (
unsigned int)now.tv_sec,
1089 (
uint8_t const *)owner->vb_strvalue, owner->vb_length);
1096 if (reply->type != REDIS_REPLY_ARRAY) {
1097 REDEBUG(
"Expected result to be array got \"%s\"",
1103 if (reply->elements == 0) {
1104 REDEBUG(
"Got empty result array");
1112 if (reply->element[0]->type != REDIS_REPLY_INTEGER) {
1113 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
1118 ret = reply->element[0]->integer;
1119 if (ret < 0)
goto finish;
1127#define CHECK_POOL_NAME \
1128 if (env->pool_name.vb_length > IPPOOL_MAX_KEY_PREFIX_SIZE) { \
1129 REDEBUG("Pool name too long. Expected %u bytes, got %ld bytes", \
1130 IPPOOL_MAX_KEY_PREFIX_SIZE, env->pool_name.vb_length); \
1131 RETURN_UNLANG_FAIL; \
1133 if (env->pool_name.vb_length == 0) { \
1134 RDEBUG2("Empty pool name. Doing nothing"); \
1135 RETURN_UNLANG_NOOP; \
1156 RDEBUG2(
"IP address lease allocated");
1160 RWDEBUG(
"Pool contains no free addresses");
1187 if (
inst->copy_on_update) {
1200 RPEDEBUG(
"Failed copying IP address to reply attribute");
1214 REDEBUG(
"Requested IP address \"%pV\" is not a member of the specified pool",
1219 REDEBUG(
"Requested IP address' \"%pV\" lease already expired at time of renewal",
1224 REDEBUG(
"Requested IP address' \"%pV\" lease allocated to another device",
1253 REDEBUG(
"Requested IP address \"%pV\" is not a member of the specified pool",
1258 REDEBUG(
"Requested IP address' \"%pV\" lease allocated to another device",
1270 RDEBUG2(
"Bulk release not yet implemented");
1276 static bool done_hash =
false;
1284 if (!
inst->cluster)
return -1;
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
#define fr_base16_encode(_out, _in)
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define CALL_ENV_TERMINATOR
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
call_env_parser_t const * env
Parsing rules for call method env.
@ CALL_ENV_FLAG_CONCAT
If the tmpl produced multiple boxes they should be concatenated.
@ CALL_ENV_FLAG_ATTRIBUTE
Tmpl MUST contain an attribute reference.
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
@ CALL_ENV_FLAG_BARE_WORD_ATTRIBUTE
bare words are treated as an attribute, but strings may be xlats.
@ CALL_ENV_FLAG_NULLABLE
Tmpl expansions are allowed to produce no output.
#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field)
Specify a call_env_parser_t which writes out runtime results to the specified field.
#define FR_CALL_ENV_PARSE_ONLY_OFFSET(_name, _cast_type, _flags, _struct, _parse_field)
Specify a call_env_parser_t which writes out the result of the parsing phase to the field specified.
#define CONF_PARSER_TERMINATOR
#define FR_CONF_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a matching CONF_PAIR is found
#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
fr_token_t quote
Quoting around the default value. Only used for templates.
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Defines a CONF_PAIR to C data type mapping.
A section grouping multiple CONF_PAIR.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
fr_redis_rcode_t fr_redis_cluster_state_next(fr_redis_cluster_state_t *state, fr_redis_conn_t **conn, fr_redis_cluster_t *cluster, request_t *request, fr_redis_rcode_t status, redisReply **reply)
Get the next connection to attempt a command against.
fr_redis_cluster_t * fr_redis_cluster_alloc(TALLOC_CTX *ctx, CONF_SECTION *module, fr_redis_conf_t *conf, char const *log_prefix, char const *trigger_prefix, fr_pair_list_t *trigger_args)
Allocate and initialise a new cluster structure.
fr_redis_rcode_t fr_redis_cluster_state_init(fr_redis_cluster_state_t *state, fr_redis_conn_t **conn, fr_redis_cluster_t *cluster, request_t *request, uint8_t const *key, size_t key_len, bool read_only)
Resolve a key to a pool, and reserve a connection in that pool.
bool fr_redis_cluster_min_version(fr_redis_cluster_t *cluster, char const *min_version)
Check if members of the cluster are above a certain version.
Redis connection sequence state.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
union fr_ipaddr_t::@137 addr
#define FR_IPADDR_PREFIX_STRLEN
Like FR_IPADDR_STRLEN but with space for a prefix.
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
#define RDEBUGX(_l, fmt,...)
#define RPEDEBUG(fmt,...)
int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t const *map, UNUSED void *uctx)
Convert a map to a fr_pair_t.
int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert map_t to fr_pair_t (s) and add them to a request_t.
@ L_DBG_LVL_3
3rd highest priority debug messages (-xxx | -Xx).
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
void * env_data
Per call environment data.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for instantiation calls.
module_t common
Common fields presented by all modules.
char * fr_asprint(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote)
Escape string that may contain binary data, and write it to a new buffer.
static const conf_parser_t config[]
#define RETURN_UNLANG_UPDATED
#define RETURN_UNLANG_INVALID
#define RETURN_UNLANG_NOTFOUND
#define RETURN_UNLANG_FAIL
#define RETURN_UNLANG_NOOP
void fr_redis_reply_print(fr_log_lvl_t lvl, redisReply *reply, request_t *request, int idx, fr_redis_rcode_t status)
Print the response data in a useful treelike form.
static void fr_redis_pipeline_free(redisReply *reply[], size_t num)
redisContext * handle
Hiredis context used when issuing commands.
#define REDIS_COMMON_CONFIG
static void fr_redis_reply_free(redisReply **reply)
Wrap freeReplyObject so we consistently check for NULL pointers.
void fr_redis_version_print(void)
Print the version of libhiredis the server was built against.
fr_table_num_sorted_t const redis_reply_types[]
fr_redis_rcode_t fr_redis_pipeline_result(unsigned int *pipelined, fr_redis_rcode_t *rcode, redisReply *out[], size_t out_len, fr_redis_conn_t *conn)
Simplifies handling of pipelined commands with Redis cluster.
fr_redis_rcode_t
Codes are ordered inversely by priority.
@ REDIS_RCODE_SUCCESS
Operation was successful.
@ REDIS_RCODE_TRY_AGAIN
Try the operation again.
@ REDIS_RCODE_NO_SCRIPT
Script doesn't exist.
@ REDIS_RCODE_ERROR
Unrecoverable library/server error.
Configuration parameters for a redis connection.
Connection handle, holding a redis context.
#define IPPOOL_STATIC_BIT
#define _IPPOOL_RCODE_NOT_FOUND
#define _IPPOOL_RCODE_POOL_EMPTY
@ IPPOOL_RCODE_DEVICE_MISMATCH
@ IPPOOL_RCODE_POOL_EMPTY
#define _IPPOOL_RCODE_DEVICE_MISMATCH
#define _IPPOOL_RCODE_SUCCESS
#define IPPOOL_SPRINT_IP(_buff, _ip, _prefix)
If the prefix is as wide as the AF data size then print it without CIDR notation.
#define IPPOOL_ADDRESS_KEY
static void ippool_action_print(request_t *request, ippool_action_t action, fr_log_lvl_t lvl, fr_value_box_t const *key_prefix, fr_value_box_t const *ip, fr_value_box_t const *owner, fr_value_box_t const *gateway_id, uint32_t expires)
tmpl_t * expiry_attr
Time at which the lease will expire.
fr_redis_cluster_t * cluster
Redis cluster.
static int mod_load(void)
static char lua_update_cmd[]
Lua script for updating leases.
fr_value_box_t pool_name
Name of the pool we're allocating IP addresses from.
static char lua_release_digest[(SHA1_DIGEST_LENGTH *2)+1]
static char lua_alloc_digest[(SHA1_DIGEST_LENGTH *2)+1]
char const * name
Instance name.
fr_value_box_t gateway_id
Gateway identifier, usually NAS-Identifier or Option 82 gateway.
tmpl_t * range_attr
Attribute to write the range ID to.
module_rlm_t rlm_redis_ippool
fr_value_box_t offer_time
How long we should reserve a lease for during the pre-allocation stage (typically responding to DHCP ...
static ippool_rcode_t redis_ippool_release(rlm_redis_ippool_t const *inst, request_t *request, fr_value_box_t const *key_prefix, fr_ipaddr_t *ip, fr_value_box_t const *owner)
Release an existing IP address in a pool.
fr_value_box_t gateway_id
Gateway identifier, usually NAS-Identifier or Option 82 gateway.
static unlang_action_t mod_update(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static unlang_action_t mod_bulk_release(unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
static unlang_action_t mod_alloc(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static const call_env_method_t redis_ippool_update_method_env
fr_value_box_t owner
Unique lease owner identifier.
static ippool_rcode_t redis_ippool_update(rlm_redis_ippool_t const *inst, request_t *request, redis_ippool_update_call_env_t *env, fr_ipaddr_t *ip, fr_value_box_t const *owner, fr_value_box_t const *gateway_id, uint32_t expires)
Update an existing IP address in a pool.
fr_value_box_t pool_name
Name of the pool we're allocating IP addresses from.
static unlang_action_t mod_release(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
fr_value_box_t pool_name
Name of the pool we're allocating IP addresses from.
fr_value_box_t lease_time
How long an IP address should be allocated for.
fr_value_box_t gateway_id
Gateway identifier, usually NAS-Identifier or Option 82 gateway.
static conf_parser_t redis_config[]
fr_value_box_t requested_address
Attribute to read the IP for renewal from.
fr_value_box_t requested_address
Attribute to read the IP for renewal from.
static char lua_release_cmd[]
Lua script for releasing leases.
fr_redis_conf_t conf
Connection parameters for the Redis server.
static fr_redis_rcode_t ippool_script(redisReply **out, request_t *request, fr_redis_cluster_t *cluster, uint8_t const *key, size_t key_len, uint32_t wait_num, fr_time_delta_t wait_timeout, char const digest[], char const *script, char const *cmd,...)
Execute a script against Redis cluster.
uint32_t wait_num
How many slaves we want to acknowledge allocations or updates.
static const call_env_method_t redis_ippool_release_method_env
fr_time_delta_t wait_timeout
How long we wait for slaves to acknowledge writing.
bool copy_on_update
Copy the address provided by ip_address to the allocated_address_attr if updates are successful.
tmpl_t * expiry_attr
Time at which the lease will expire.
static char lua_alloc_cmd[]
Lua script for allocating new leases.
tmpl_t * range_attr
Attribute to write the range ID to.
tmpl_t * allocated_address_attr
Attribute to populate with allocated IP.
static ippool_rcode_t redis_ippool_allocate(rlm_redis_ippool_t const *inst, request_t *request, redis_ippool_alloc_call_env_t *env, uint32_t lease_time)
Allocate a new IP address from a pool.
bool ipv4_integer
Whether IPv4 addresses should be cast to integers, for renew operations.
fr_value_box_t owner
Unique lease owner identifier.
tmpl_t * allocated_address_attr
Attribute to populate with allocated IP.
fr_value_box_t gateway_id
Gateway identifier, usually NAS-Identifier or Option 82 gateway.
fr_value_box_t lease_time
How long an IP address should be allocated for.
static int mod_instantiate(module_inst_ctx_t const *mctx)
fr_value_box_t pool_name
Name of the pool we're allocating IP addresses from.
static const call_env_method_t redis_ippool_bulk_release_method_env
static char lua_update_digest[(SHA1_DIGEST_LENGTH *2)+1]
fr_value_box_t owner
Unique lease owner identifier.
static int ippool_wait_check(request_t *request, uint32_t wait_num, redisReply *reply)
Check the requisite number of slaves replicated the lease info.
static conf_parser_t module_config[]
fr_value_box_t requested_address
Attribute to read the IP for renewal from.
static const call_env_method_t redis_ippool_alloc_method_env
Call environment used when calling redis_ippool allocate method.
Call environment used when calling redis_ippool bulk release method.
Call environment used when calling redis_ippool release method.
Call environment used when calling redis_ippool update method.
rlm_redis module instance
#define FR_SBUFF_OUT(_start, _len_or_end)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
CONF_SECTION * conf
Module's instance configuration.
size_t inst_size
Size of the module's instance data.
void * data
Module's instance data.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
#define tmpl_value(_tmpl)
@ TMPL_TYPE_DATA
Value in native boxed format.
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
tmpl_t * tmpl_init_shallow(tmpl_t *vpt, tmpl_type_t type, fr_token_t quote, char const *name, ssize_t len, tmpl_rules_t const *t_rules))
Initialise a tmpl without copying the input name string.
void fr_sha1_init(fr_sha1_ctx *context)
void fr_sha1_final(uint8_t digest[static SHA1_DIGEST_LENGTH], fr_sha1_ctx *context)
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *in, size_t len)
#define SHA1_DIGEST_LENGTH
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
#define talloc_get_type_abort_const
#define fr_time_to_timeval(_when)
Convert server epoch time to unix epoch time.
static int64_t fr_time_delta_to_msec(fr_time_delta_t delta)
A time delta, a difference in time measured in nanoseconds.
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
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.
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
#define fr_value_box(_box, _var, _tainted)
Automagically fill in a box, determining the value type from the type of the C variable.
static size_t char ** out