28 RCSID(
"$Id: 501ad5ec61f5c42c5006ec247b1a562178b7a8d2 $")
30 #include <freeradius-devel/radiusd.h>
31 #include <freeradius-devel/modules.h>
32 #include <freeradius-devel/modpriv.h>
33 #include <freeradius-devel/rad_assert.h>
134 "local address_key" EOL
135 "local device_key" EOL
147 "exists = redis.call('GET', device_key);" EOL
149 " local expires_in = tonumber(redis.call('ZSCORE', pool_key, exists) - ARGV[1])" EOL
150 " if expires_in > 0 then" EOL
151 " ip = redis.call('HMGET', '{' .. KEYS[1] .. '}:"IPPOOL_ADDRESS_KEY":' .. exists, 'device', 'range', 'counter')" EOL
152 " if ip and (ip[1] == ARGV[3]) then" EOL
161 "ip = redis.call('ZREVRANGE', pool_key, -1, -1, 'WITHSCORES')" EOL
162 "if not ip or not ip[1] then" EOL
165 "if ip[2] >= ARGV[1] then" EOL
168 "redis.call('ZADD', pool_key, ARGV[1] + ARGV[2], ip[1])" EOL
174 "redis.call('HMSET', address_key, 'device', ARGV[3], 'gateway', ARGV[4])" EOL
175 "redis.call('SET', device_key, ip[1])" EOL
176 "redis.call('EXPIRE', device_key, ARGV[2])" EOL
180 " redis.call('HGET', address_key, 'range'), " EOL
181 " tonumber(ARGV[2]), " EOL
182 " redis.call('HINCRBY', address_key, 'counter', 1)" EOL
206 "local address_key" EOL
207 "local device_key" EOL
214 "found = redis.call('HMGET', address_key, 'range', 'device', 'gateway', 'counter' )" EOL
215 "if not found[1] then" EOL
218 "if found[2] ~= ARGV[4] then" EOL
226 "redis.call('ZADD', pool_key, 'XX', ARGV[1] + ARGV[2], ARGV[3])" EOL
235 "if redis.call('EXPIRE', device_key, ARGV[2]) == 0 then" EOL
236 " redis.call('SET', device_key, ip[1])" EOL
237 " redis.call('EXPIRE', device_key, ARGV[2])" EOL
243 "if ARGV[5] ~= found[3] then" EOL
244 " redis.call('HSET', address_key, 'gateway', ARGV[5])" EOL
269 "local address_key" EOL
270 "local device_key" EOL
277 "found = redis.call('HGET', address_key, 'device')" EOL
278 "if not found then" EOL
281 "if found and found ~= ARGV[3] then" EOL
289 "redis.call('ZADD', pool_key, 'XX', ARGV[1] - 1, ARGV[2])" EOL
295 "redis.call('DEL', device_key)" EOL
298 " redis.call('HINCRBY', address_key, 'counter', 1) - 1" EOL
313 if (!wait_num)
return 0;
315 if (reply->type != REDIS_REPLY_INTEGER) {
316 REDEBUG(
"WAIT result is wrong type, expected integer got %s",
320 if (reply->integer < wait_num) {
321 REDEBUG(
"Too few slaves acknowledged allocation, needed %i, got %lli",
322 wait_num, reply->integer);
341 uint8_t *out_p = out;
343 slen =
tmpl_expand(NULL, (
char *)out_p, outlen - (out_p - out), request,
346 REDEBUG(
"Failed determining pool name");
350 REDEBUG(
"Pool name too long. Expected %zu bytes, got %zu bytes", outlen, (
size_t)slen);
360 uint8_t
const *key_prefix,
size_t key_prefix_len,
362 uint8_t
const *device_id,
size_t device_id_len,
363 uint8_t
const *gateway_id,
size_t gateway_id_len,
366 char *key_prefix_str, *device_str = NULL, *gateway_str = NULL;
368 key_prefix_str =
fr_asprint(request, (
char const *)key_prefix, key_prefix_len,
'"');
369 if (gateway_id) gateway_str =
fr_asprint(request, (
char const *)gateway_id, gateway_id_len,
'"');
370 if (device_id) device_str =
fr_asprint(request, (
char const *)device_id, device_id_len,
'"');
374 RDEBUGX(lvl,
"Allocating lease from pool \"%s\"%s%s%s%s%s%s, expires in %us",
376 device_str ?
", to \"" :
"", device_str ? device_str :
"",
377 device_str ?
"\"" :
"",
378 gateway_str ?
", on \"" :
"", gateway_str ? gateway_str :
"",
379 gateway_str ?
"\"" :
"",
384 RDEBUGX(lvl,
"Updating %s in pool \"%s\"%s%s%s%s%s%s, expires in %us",
385 ip_str, key_prefix_str,
386 device_str ?
", device \"" :
"", device_str ? device_str :
"",
387 device_str ?
"\"" :
"",
388 gateway_str ?
", gateway \"" :
"", gateway_str ? gateway_str :
"",
389 gateway_str ?
"\"" :
"",
394 RDEBUGX(lvl,
"Releasing %s%s%s%s to pool \"%s\"",
396 device_str ?
" leased by \"" :
"", device_str ? device_str :
"",
397 device_str ?
"\"" :
"",
409 talloc_free(key_prefix_str);
410 talloc_free(device_str);
411 talloc_free(gateway_str);
435 uint8_t
const *key,
size_t key_len,
436 uint32_t wait_num, uint32_t wait_timeout,
437 char const digest[],
char const *script,
438 char const *cmd, ...)
441 redisReply *replies[5];
442 size_t reply_cnt = 0, i;
459 RDEBUG3(
"Calling script 0x%s", digest);
461 redisvAppendCommand(conn->
handle, cmd, copy);
465 redisAppendCommand(conn->
handle,
"WAIT %i %i", wait_num, wait_timeout);
477 RDEBUG3(
"Loading script 0x%s", digest);
478 redisAppendCommand(conn->
handle,
"MULTI");
479 redisAppendCommand(conn->
handle,
"SCRIPT LOAD %s", script);
481 redisvAppendCommand(conn->
handle, cmd, copy);
483 redisAppendCommand(conn->
handle,
"EXEC");
486 redisAppendCommand(conn->
handle,
"WAIT %i %i", wait_num, wait_timeout);
497 if (replies[3]->type != REDIS_REPLY_ARRAY) {
498 REDEBUG(
"Bad response to EXEC, expected array got %s",
505 if (replies[3]->elements != 2) {
506 REDEBUG(
"Bad response to EXEC, expected 2 result elements, got %zu",
507 replies[3]->elements);
510 if (replies[3]->element[0]->type != REDIS_REPLY_STRING) {
511 REDEBUG(
"Bad response to SCRIPT LOAD, expected string got %s",
515 if (strcmp(replies[3]->element[0]->str, digest) != 0) {
516 RWDEBUG(
"Incorrect SHA1 from SCRIPT LOAD, expected %s, got %s",
517 digest, replies[3]->element[0]->str);
543 *out = replies[3]->element[1];
544 replies[3]->element[1] = NULL;
561 uint8_t
const *key_prefix,
size_t key_prefix_len,
562 uint8_t
const *device_id,
size_t device_id_len,
563 uint8_t
const *gateway_id,
size_t gateway_id_len,
567 redisReply *reply = NULL;
575 gettimeofday(&now, NULL);
580 if (!gateway_id) gateway_id = (uint8_t
const *)
"";
583 key_prefix, key_prefix_len,
586 "EVALSHA %s 1 %b %u %u %b %b",
588 key_prefix, key_prefix_len,
589 (
unsigned int)now.tv_sec, expires,
590 device_id, device_id_len,
591 gateway_id, gateway_id_len);
598 if (reply->type != REDIS_REPLY_ARRAY) {
599 REDEBUG(
"Expected result to be array got \"%s\"",
605 if (reply->elements == 0) {
606 REDEBUG(
"Got empty result array");
614 if (reply->element[0]->type != REDIS_REPLY_INTEGER) {
615 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
620 ret = reply->element[0]->integer;
621 if (ret < 0)
goto finish;
626 if (reply->elements > 1) {
637 switch (reply->element[1]->type) {
644 case REDIS_REPLY_INTEGER:
649 memset(&tmp, 0,
sizeof(tmp));
651 tmp.integer = ntohl((uint32_t)reply->element[1]->integer);
652 tmp.
length =
sizeof(ip_map.
rhs->tmpl_data_value.integer);
661 ip_map.
rhs->tmpl_data_value.integer = ntohl((uint32_t)reply->element[1]->integer);
662 ip_map.
rhs->tmpl_data_length =
sizeof(ip_map.
rhs->tmpl_data_value.integer);
668 case REDIS_REPLY_STRING:
669 ip_map.
rhs->tmpl_data_value.strvalue = reply->element[1]->str;
670 ip_map.
rhs->tmpl_data_length = reply->element[1]->
len;
681 REDEBUG(
"Server returned unexpected type \"%s\" for IP element (result[1])",
691 if (reply->elements > 2) {
692 switch (reply->element[2]->type) {
696 case REDIS_REPLY_STRING:
710 range_map.
rhs->tmpl_data_value.strvalue = reply->element[2]->str;
711 range_map.
rhs->tmpl_data_length = reply->element[2]->
len;
720 case REDIS_REPLY_NIL:
724 REDEBUG(
"Server returned unexpected type \"%s\" for range element (result[2])",
747 if (reply->element[3]->type != REDIS_REPLY_INTEGER) {
748 REDEBUG(
"Server returned unexpected type \"%s\" for expiry element (result[3])",
754 expiry_map.
rhs->tmpl_data_value.integer = reply->element[3]->integer;
755 expiry_map.
rhs->tmpl_data_length =
sizeof(expiry_map.
rhs->tmpl_data_value.integer);
771 uint8_t
const *key_prefix,
size_t key_prefix_len,
773 uint8_t
const *device_id,
size_t device_id_len,
774 uint8_t
const *gateway_id,
size_t gateway_id_len,
778 redisReply *reply = NULL;
786 gettimeofday(&now, NULL);
791 if (!device_id) device_id = (uint8_t
const *)
"";
792 if (!gateway_id) gateway_id = (uint8_t
const *)
"";
796 key_prefix, key_prefix_len,
799 "EVALSHA %s 1 %b %u %u %u %b %b",
801 key_prefix, key_prefix_len,
802 (
unsigned int)now.tv_sec, expires,
803 htonl(ip->
ipaddr.ip4addr.s_addr),
804 device_id, device_id_len,
805 gateway_id, gateway_id_len);
811 key_prefix, key_prefix_len,
814 "EVALSHA %s 1 %b %u %u %s %b %b",
816 key_prefix, key_prefix_len,
817 (
unsigned int)now.tv_sec, expires,
819 device_id, device_id_len,
820 gateway_id, gateway_id_len);
827 if (reply->type != REDIS_REPLY_ARRAY) {
828 REDEBUG(
"Expected result to be array got \"%s\"",
834 if (reply->elements == 0) {
835 REDEBUG(
"Got empty result array");
843 if (reply->element[0]->type != REDIS_REPLY_INTEGER) {
844 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
849 ret = reply->element[0]->integer;
850 if (ret < 0)
goto finish;
855 if (reply->elements > 1) {
856 switch (reply->element[1]->type) {
860 case REDIS_REPLY_STRING:
861 range_map.
rhs->tmpl_data_value.strvalue = reply->element[1]->str;
862 range_map.
rhs->tmpl_data_length = reply->element[1]->
len;
870 case REDIS_REPLY_NIL:
874 REDEBUG(
"Server returned unexpected type \"%s\" for range element (result[1])",
897 expiry_map.
rhs->tmpl_data_value.integer = expires;
898 expiry_map.
rhs->tmpl_data_length =
sizeof(expiry_map.
rhs->tmpl_data_value.integer);
916 uint8_t
const *key_prefix,
size_t key_prefix_len,
918 uint8_t
const *device_id,
size_t device_id_len)
921 redisReply *reply = NULL;
926 gettimeofday(&now, NULL);
931 if (!device_id) device_id = (uint8_t
const *)
"";
935 key_prefix, key_prefix_len,
938 "EVALSHA %s 1 %b %u %u %b",
940 key_prefix, key_prefix_len,
941 (
unsigned int)now.tv_sec,
942 htonl(ip->
ipaddr.ip4addr.s_addr),
943 device_id, device_id_len);
949 key_prefix, key_prefix_len,
952 "EVALSHA %s 1 %b %u %s %b",
954 key_prefix, key_prefix_len,
955 (
unsigned int)now.tv_sec,
957 device_id, device_id_len);
964 if (reply->type != REDIS_REPLY_ARRAY) {
965 REDEBUG(
"Expected result to be array got \"%s\"",
971 if (reply->elements == 0) {
972 REDEBUG(
"Got empty result array");
980 if (reply->element[0]->type != REDIS_REPLY_INTEGER) {
981 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
986 ret = reply->element[0]->integer;
987 if (ret < 0)
goto finish;
998 uint8_t
const *device_id = NULL, *gateway_id = NULL;
999 size_t key_prefix_len, device_id_len = 0, gateway_id_len = 0;
1002 char expires_buff[20];
1003 char const *expires_str;
1004 unsigned long expires = 0;
1007 slen =
ippool_pool_name((uint8_t *)&key_prefix,
sizeof(key_prefix), inst, request);
1010 key_prefix_len = (size_t)slen;
1014 (
char *)&device_id_buff,
sizeof(device_id_buff),
1020 device_id_len = (size_t)slen;
1025 (
char *)&gateway_id_buff,
sizeof(gateway_id_buff),
1031 gateway_id_len = (size_t)slen;
1036 if (
tmpl_expand(&expires_str, expires_buff,
sizeof(expires_buff),
1037 request, inst->
offer_time, NULL, NULL) < 0) {
1042 expires = strtoul(expires_str, &q, 10);
1043 if (q != (expires_str + strlen(expires_str))) {
1044 REDEBUG(
"Invalid offer_time. Must be an integer value");
1049 device_id, device_id_len, gateway_id, gateway_id_len, expires);
1051 device_id, device_id_len,
1052 gateway_id, gateway_id_len, (uint32_t)expires)) {
1054 RDEBUG2(
"IP address lease allocated");
1058 RWDEBUG(
"Pool contains no free addresses");
1067 char ip_buff[INET6_ADDRSTRLEN + 4];
1070 if (
tmpl_expand(&expires_str, expires_buff,
sizeof(expires_buff),
1071 request, inst->
lease_time, NULL, NULL) < 0) {
1076 expires = strtoul(expires_str, &q, 10);
1077 if (q != (expires_str + strlen(expires_str))) {
1078 REDEBUG(
"Invalid expires. Must be an integer value");
1083 REDEBUG(
"Failed expanding ip_address");
1087 if (
fr_inet_pton(&ip, ip_str, -1, AF_UNSPEC,
false,
true) < 0) {
1093 ip_str, device_id, device_id_len, gateway_id, gateway_id_len, expires);
1095 &ip, device_id, device_id_len,
1096 gateway_id, gateway_id_len, (uint32_t)expires)) {
1098 RDEBUG2(
"IP address lease updated");
1115 ip_rhs.tmpl_data_length = strlen(ip_str);
1116 ip_rhs.tmpl_data_value.strvalue = ip_str;
1129 REDEBUG(
"IP address is not a member of the specified pool");
1133 REDEBUG(
"IP address lease already expired at time of renewal");
1137 REDEBUG(
"IP address lease allocated to another device");
1147 char ip_buff[INET6_ADDRSTRLEN + 4];
1155 if (
fr_inet_pton(&ip, ip_str, -1, AF_UNSPEC,
false,
true) < 0) {
1161 ip_str, device_id, device_id_len, gateway_id, gateway_id_len, 0);
1163 &ip, device_id, device_id_len)) {
1165 RDEBUG2(
"IP address released");
1174 REDEBUG(
"IP address is not a member of the specified pool");
1178 REDEBUG(
"IP address lease allocated to another device");
1187 RDEBUG2(
"Bulk release not yet implemented");
1206 if (vp)
return mod_action(inst, request, vp->vp_integer);
1213 RDEBUG2(
"Couldn't find &request:Acct-Status-Type or &control:Pool-Action, doing nothing...");
1217 switch (vp->vp_integer) {
1270 inst->
conf.
prefix = talloc_asprintf(inst,
"rlm_redis (%s)", inst->
name);
1277 static bool done_hash =
false;
1286 if (!inst->
cluster)
return -1;
1301 fr_sha1_update(&sha1_ctx, (uint8_t
const *)lua_alloc_cmd,
sizeof(lua_alloc_cmd) - 1);
1306 fr_sha1_update(&sha1_ctx, (uint8_t
const *)lua_update_cmd,
sizeof(lua_update_cmd) - 1);
1311 fr_sha1_update(&sha1_ctx, (uint8_t
const *)lua_release_cmd,
sizeof(lua_release_cmd) - 1);
1331 .config = module_config,
static rlm_rcode_t mod_authorize(void *instance, REQUEST *request) CC_HINT(nonnull)
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *data, size_t len)
ssize_t tmpl_expand(char const **out, char *buff, size_t outlen, REQUEST *request, vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
Expand a vp_tmpl_t to a string writing the result to a buffer.
2nd highest priority debug messages (-xx | -X).
vp_tmpl_t * expiry_attr
Time at which the lease will expire.
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
int int map_to_request(REQUEST *request, vp_map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert vp_map_t to VALUE_PAIR (s) and add them to a REQUEST.
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Time value (struct timeval), only for config items.
vp_tmpl_t * pool_name
Name of the pool we're allocating IP addresses from.
Metadata exported by the module.
Configuration parameters for a redis connection.
char const * name
Raw string used to create the template.
vp_tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
static CONF_PARSER redis_config[]
7 methods index for postauth section.
FR_NAME_NUMBER const redis_reply_types[]
3rd highest priority debug messages (-xxx | -Xx).
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
vp_tmpl_t * gateway_id
Gateway identifier, usually NAS-Identifier or the actual Option 82 gateway.
#define SHA1_DIGEST_LENGTH
vp_tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
#define RLM_TYPE_THREAD_SAFE
Module is threadsafe.
static fr_redis_rcode_t ippool_script(redisReply **out, REQUEST *request, fr_redis_cluster_t *cluster, uint8_t const *key, size_t key_len, uint32_t wait_num, uint32_t wait_timeout, char const digest[], char const *script, char const *cmd,...)
Execute a script against Redis cluster.
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
#define CONF_PARSER_TERMINATOR
char const * prefix
Logging prefix for errors in fr_redis_cluster_conn_create.
static char lua_update_cmd[]
Lua script for updating leases.
#define IPPOOL_MAX_KEY_PREFIX_SIZE
#define _IPPOOL_RCODE_DEVICE_MISMATCH
static ippool_rcode_t redis_ippool_allocate(rlm_redis_ippool_t *inst, REQUEST *request, uint8_t const *key_prefix, size_t key_prefix_len, uint8_t const *device_id, size_t device_id_len, uint8_t const *gateway_id, size_t gateway_id_len, uint32_t expires)
Allocate a new IP address from a pool.
#define fr_redis_reply_free(_p)
Wrap freeReplyObject so we consistently check for NULL pointers.
struct timeval wait_timeout
How long we wait for slaves to acknowledge writing.
static int mod_instantiate(CONF_SECTION *conf, void *instance)
The module considers the request invalid.
#define _IPPOOL_RCODE_NOT_FOUND
void fr_redis_reply_print(log_lvl_t lvl, redisReply *reply, REQUEST *request, int idx)
Print the response data in a useful treelike form.
uint32_t wait_num
How many slaves we want to acknowledge allocations or updates.
static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request) CC_HINT(nonnull)
#define PW_TYPE_SUBSECTION
Defines a CONF_PAIR to C data type mapping.
static ippool_rcode_t redis_ippool_update(rlm_redis_ippool_t *inst, REQUEST *request, uint8_t const *key_prefix, size_t key_prefix_len, fr_ipaddr_t *ip, uint8_t const *device_id, size_t device_id_len, uint8_t const *gateway_id, size_t gateway_id_len, uint32_t expires)
Update an existing IP address in a pool.
void fr_sha1_init(fr_sha1_ctx *context)
struct rlm_redis_ippool rlm_redis_ippool_t
rlm_redis module instance
static int mod_bootstrap(CONF_SECTION *conf, void *instance)
#define is_truncated(_ret, _max)
static char lua_update_digest[(SHA1_DIGEST_LENGTH *2)+1]
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...
redisContext * handle
Hiredis context used when issuing commands.
vp_tmpl_t * range_attr
Attribute to write the range ID to.
int value_data_cast(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv, PW_TYPE src_type, fr_dict_attr_t const *src_enumv, value_data_t const *src)
Convert one type of value_data_t to another.
static char lua_alloc_digest[(SHA1_DIGEST_LENGTH *2)+1]
module_t rlm_redis_ippool
#define REDIS_COMMON_CONFIG
static char lua_alloc_cmd[]
Lua script for allocating new leases.
fr_redis_cluster_t * cluster
Redis cluster.
#define _IPPOOL_RCODE_SUCCESS
CONF_SECTION * cf_subsection_find_next(CONF_SECTION const *section, CONF_SECTION const *subsection, char const *name1)
void fr_redis_version_print(void)
Print the version of libhiredis the server was built against.
vp_tmpl_t * lease_time
How long an IP address should be allocated for.
union fr_ipaddr_t::@1 ipaddr
Unrecoverable library/server error.
3 methods index for accounting section.
static rlm_rcode_t mod_action(rlm_redis_ippool_t *inst, REQUEST *request, ippool_action_t action)
#define IPPOOL_SPRINT_IP(_buff, _ip, _prefix)
If the prefix is as wide as the AF data size then print it without CIDR notation. ...
Stores an attribute, a value and various bits of other data.
rlm_redis module instance
Redis connection sequence state.
void fr_sha1_final(uint8_t digest[20], fr_sha1_ctx *context)
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
tmpl_type_t type
What type of value tmpl refers to.
char const * fr_strerror(void)
Get the last library error.
#define IPPOOL_DEVICE_KEY
size_t len
Length of the raw string used to create the template.
bool ipv4_integer
Whether IPv4 addresses should be cast to integers, for renew operations.
char const * cf_section_name1(CONF_SECTION const *cs)
Module succeeded without doing anything.
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 *request, fr_redis_rcode_t status, redisReply **reply)
Get the next connection to attempt a command against.
size_t length
Length of value data.
uint64_t magic
Used to validate module struct.
Module failed, don't reply.
bool copy_on_update
Copy the address provided by ip_address to the reply_attr if updates are successful.
vp_tmpl_t * device_id
Unique device identifier.
#define FR_CONF_OFFSET(_n, _t, _s, _f)
static char lua_release_digest[(SHA1_DIGEST_LENGTH *2)+1]
static CONF_PARSER module_config[]
Common functions for interacting with Redis via hiredis.
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.
RADIUS_PACKET * packet
Incoming request.
vp_tmpl_t * offer_time
How long we should reserve a lease for during the pre-allocation stage (typically responding to DHCP ...
static int ippool_wait_check(REQUEST *request, uint32_t wait_num, redisReply *reply)
Check the requisite number of slaves replicated the lease info.
#define PW_STATUS_ACCOUNTING_ON
static ippool_rcode_t redis_ippool_release(rlm_redis_ippool_t *inst, REQUEST *request, uint8_t const *key_prefix, size_t key_prefix_len, fr_ipaddr_t *ip, uint8_t const *device_id, size_t device_id_len)
Release an existing IP address in a 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.
fr_redis_cluster_t * fr_redis_cluster_alloc(TALLOC_CTX *ctx, CONF_SECTION *module, fr_redis_conf_t *conf)
Allocate and initialise a new cluster structure.
fr_redis_rcode_t fr_redis_pipeline_result(fr_redis_rcode_t *rcode, redisReply *out[], size_t out_len, fr_redis_conn_t *conn, int pipelined)
Simplifies handling of pipelined commands with Redis cluster.
Common functions for interacting with Redis cluster via Hiredis.
fr_redis_rcode_t
Codes are ordered inversely by priority.
#define _IPPOOL_RCODE_POOL_EMPTY
int map_to_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx) CC_HINT(nonnull(2
#define PW_TYPE_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
fr_redis_conf_t conf
Connection parameters for the Redis server.
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 *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.
static ssize_t ippool_pool_name(uint8_t out[], size_t outlen, rlm_redis_ippool_t *inst, REQUEST *request)
Find the pool name we'll be allocating from.
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
#define PW_TYPE_ATTRIBUTE
Value must resolve to attribute in dict (deprecated, use PW_TYPE_TMPL).
#define FR_TIMEVAL_TO_MS(_x)
#define fr_redis_pipeline_free(_r, _n)
String of printable characters.
#define FR_CONF_POINTER(_n, _t, _p)
Operation was successfull.
#define RDEBUGX(_l, fmt,...)
static rlm_rcode_t mod_accounting(void *instance, REQUEST *request) CC_HINT(nonnull)
#define PW_TYPE_TMPL
CONF_PAIR should be parsed as a template.
1 methods index for authorize section.
static void ippool_action_print(REQUEST *request, ippool_action_t action, log_lvl_t lvl, uint8_t const *key_prefix, size_t key_prefix_len, char const *ip_str, uint8_t const *device_id, size_t device_id_len, uint8_t const *gateway_id, size_t gateway_id_len, uint32_t expires)
static char lua_release_cmd[]
Lua script for releasing leases.
#define FR_IPADDR_PREFIX_STRLEN
Like FR_IPADDR_STRLEN but with space for a prefix.
#define PW_STATUS_ACCOUNTING_OFF
A source or sink of value data.
vp_tmpl_t * reply_attr
IP attribute and destination.
size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
Convert binary data to a hex string.
#define IPPOOL_ADDRESS_KEY
char const * name
Instance name.
vp_tmpl_t * ip_address
Attribute to read the IP for renewal from.
char const * cf_section_name2(CONF_SECTION const *cs)
Connection handle, holding a redis context.