36 #include <freeradius-devel/radiusd.h>
37 #include <freeradius-devel/modules.h>
38 #include <freeradius-devel/modpriv.h>
44 #define VENDORPEC_ASN 23782
45 #define ASN_IP_POOL_NAME 1
47 #define RLM_NETVIM_MAX_ROWS 1000000
48 #define RLM_NETVIM_TMP_PREFIX "auth-tmp-"
50 #define MAX_QUERY_LEN 4096
52 RCSID(
"$Id: e895213d9f998859d1143cc2b2d8e369c0541982 $")
59 pthread_mutex_t mutex;
90 if (!sqlsock)
return 0;
138 "nvp_select(): error while saving results of query");
144 "nvp_select(): no results in query");
150 "from results of query");
167 "UPDATE `%s`.`ips`, `radacct` "
169 "`ips`.`rsv_until` = `radacct`.`acctstoptime` + INTERVAL %u SECOND "
171 "`radacct`.`acctstoptime` IS NOT NULL AND "
173 "`ips`.`pid` IS NOT NULL AND "
174 "(`rsv_until` = 0 OR `rsv_until` > NOW())"
176 "`radacct`.`acctuniqueid` = `ips`.`rsv_by`",
189 "UPDATE `%s`.`ip_pools` "
190 "SET `ip_pools`.`free` = "
194 "`ips`.`ip` BETWEEN "
195 "`ip_pools`.`ip_start` AND `ip_pools`.`ip_stop` AND "
197 "`ips`.`pid` IS NULL OR "
198 "(`ips`.`rsv_until` > 0 AND `ips`.`rsv_until` < NOW())"
217 "requesting new SQL connection");
229 "UPDATE `%s`.`ips`, `radacct` "
232 "`ips`.`rsv_by` = `radacct`.`acctuniqueid`, "
233 "`ips`.`rsv_since` = `radacct`.`acctstarttime`, "
234 "`ips`.`rsv_until` = 0 "
236 "`radacct`.`acctstoptime` IS NULL AND "
237 "`ips`.`ip` = INET_ATON(`radacct`.`framedipaddress`) AND "
239 "`ips`.`pid` IS NULL OR "
241 "`ips`.`rsv_until` != 0"
270 inst->
myname =
"(no name)";
284 if (strcmp(sql_inst->
entry->
name,
"rlm_sql") != 0) {
286 " is not an instance of the rlm_sql module",
304 struct in_addr ip = {0};
311 weights_sum, used_sum, ip_start, ip_stop, connid;
321 "mod_post_auth(): IP address "
322 "already in the reply packet - exiting");
329 pname = vp->vp_strvalue;
331 "mod_post_auth(): pool name = '%s'",
336 "mod_post_auth(): no IP pool name - exiting");
343 nasip = ntohl(vp->vp_ipaddr);
348 "mod_post_auth(): no NAS IP address in "
349 "the request packet - using \"0.0.0.0/0\" (any)");
356 "mod_post_auth(): error while requesting an SQL socket");
361 if (
nvp_select(&row, inst, sqlsock,
"SELECT CONNECTION_ID()") < 1) {
368 connid = strtoul(row[0], (
char **) NULL, 10);
373 #ifdef HAVE_PTHREAD_D
374 && (pthread_mutex_trylock(&inst->mutex)) == 0
382 "mod_post_auth(): syncing with radacct table");
386 #ifdef HAVE_PTHREAD_D
392 "mod_post_auth(): synchronization failed");
400 "mod_post_auth(): selecting gid on position %lu",
405 "SELECT `host_groups`.`gid` "
407 "`%s`.`host_groups`, "
411 "`host_groups`.`gid` = `ids`.`id` AND "
412 "`ids`.`enabled` = 1 AND "
413 "`host_groups`.`gid` = `gid_ip`.`gid` AND "
414 "%lu BETWEEN `gid_ip`.`ip_start` AND `gid_ip`.`ip_stop` "
415 "ORDER BY (`gid_ip`.`ip_stop` - `gid_ip`.`ip_start`) ASC "
417 inst->
db_name, nasip, s_gid)) {
420 "mod_post_auth(): couldn't find "
421 "any more matching host groups");
430 gid = strtoul(row[0], (
char **) NULL, 10);
435 "mod_post_auth(): selecting prio on position %lu",
441 "`ip_pools`.`prio`, "
442 "SUM(`ip_pools`.`weight`) AS `weights_sum`, "
443 "(SUM(`ip_pools`.`total`) - "
444 "SUM(`ip_pools`.`free`)) AS `used_sum` "
448 "`%1$s`.`pool_names` "
450 "`ip_pools`.`gid` = %lu AND "
451 "`ids`.`id` = `ip_pools`.`pid` AND "
452 "`ids`.`enabled` = 1 AND "
453 "`pool_names`.`pnid` = `ip_pools`.`pnid` AND "
454 "`pool_names`.`name` = '%s' AND "
455 "`ip_pools`.`free` > 0 "
457 "ORDER BY `prio` ASC "
459 inst->
db_name, gid, pname, s_prio)) {
462 "mod_post_auth(): couldn't find "
463 "any more matching pools for gid = %lu",
473 prio = strtol(row[0], (
char **) NULL, 10);
474 weights_sum = strtoul(row[1], (
char **) NULL, 10);
475 used_sum = strtoul(row[2], (
char **) NULL, 10);
482 "mod_post_auth(): selecting PID on position %lu",
489 "`ip_pools`.`ip_start`, "
490 "`ip_pools`.`ip_stop` "
494 "`%1$s`.`pool_names` "
496 "`ip_pools`.`gid` = %lu AND "
497 "`ids`.`id` = `ip_pools`.`pid` AND "
498 "`ids`.`enabled` = 1 AND "
499 "`pool_names`.`pnid` = `ip_pools`.`pnid` AND "
500 "`pool_names`.`name` = '%s' AND "
501 "`ip_pools`.`free` > 0 AND "
503 "ORDER BY (`weight`/%lu.0000 - (`total` - `free`)/%lu) DESC "
505 inst->
db_name, gid, pname, prio,
506 weights_sum, used_sum, s_pid)) {
509 "mod_post_auth(): couldn't find any more "
510 "matching pools of prio = %ld for gid = %lu",
520 pid = strtoul(row[0], (
char **) NULL, 10);
521 ip_start = strtoul(row[1], (
char **) NULL, 10);
522 ip_stop = strtoul(row[2], (
char **) NULL, 10);
530 "`rsv_since` = NOW(), "
532 "`rsv_until` = NOW() + INTERVAL %d SECOND "
534 "`ip` BETWEEN %lu AND %lu AND "
537 "(`rsv_until` > 0 AND `rsv_until` < NOW())"
554 "ORDER BY `rsv_since` DESC "
559 "mod_post_auth(): couldn't reserve an IP address "
560 "from pool of pid = %lu (prio = %ld, gid = %lu)",
571 "UPDATE `%s`.`ip_pools` "
573 "`free` = `free` - 1 "
586 ip.s_addr = htonl(strtoul(row[0], (
char **) NULL, 10));
601 "mod_post_auth(): no free IP address found!");
615 PW_FRAMED_IP_ADDRESS, 0);
616 vp->vp_ipaddr = ip.s_addr;
627 struct in_addr nasip;
630 uint32_t framedip = 0;
638 sessid = vp->vp_strvalue;
642 "mod_accounting(): unique session ID not found");
648 acct_type = vp->vp_integer;
652 "couldn't find type of accounting packet");
668 "mod_accounting(): couldn't connect to database");
683 framedip = ntohl(vp->vp_ipaddr);
691 inst->
db_name, sessid, framedip)) {
700 "UPDATE `%s`.`ips`, `%1$s`.`ip_pools` "
702 "`ips`.`rsv_until` = NOW() + INTERVAL %u SECOND, "
703 "`ip_pools`.`free` = `ip_pools`.`free` + 1 "
705 "`ips`.`rsv_by` = '%s' AND "
706 "`ips`.`ip` BETWEEN `ip_pools`.`ip_start` AND `ip_pools`.`ip_stop`",
723 nasip.s_addr = vp->vp_ipaddr;
724 strlcpy(nasipstr, inet_ntoa(nasip),
sizeof(nasipstr));
727 "UPDATE `%s`.`ips`, `radacct` "
728 "SET `ips`.`rsv_until` = NOW() + INTERVAL %u SECOND "
730 "`radacct`.`nasipaddress` = '%s' AND "
731 "`ips`.`rsv_by` = `radacct`.`acctuniqueid`",
748 .name =
"sqlhpwippool",
751 .config = module_config,
PUBLIC int vsnprintf(char *string, size_t length, char *format, va_list args)
static int nvp_query(rlm_sqlhpwippool_t *data, rlm_sql_handle_t *sqlsock, char const *fmt,...)
void sql_rcode_t sql_rcode_t rlm_sql_query(rlm_sql_t const *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query) CC_HINT(nonnull(1
Only displayed when debugging is enabled.
Main server configuration.
static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
Write accounting data to Couchbase documents.
Prototypes and functions for the SQL module.
uint32_t free_after
How many seconds an IP should not be used after freeing.
The module is OK, continue.
static int nvp_freeclosed(rlm_sqlhpwippool_t *data, rlm_sql_handle_t *sqlsock)
static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request) CC_HINT(nonnull)
Metadata exported by the module.
int radlog(log_type_t lvl, char const *fmt,...) CC_HINT(format(printf
int(* sql_num_rows)(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
7 methods index for postauth section.
VALUE_PAIR * radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor)
Create a VALUE_PAIR and add it to a list of VALUE_PAIR s.
char const * myname
Name of this instance.
#define RLM_TYPE_THREAD_SAFE
Module is threadsafe.
bool no_free_fail
Fail if no free IP addresses found.
#define CONF_PARSER_TERMINATOR
sql_rcode_t(* sql_free_result)(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
static int nvp_syncfree(rlm_sqlhpwippool_t *data, rlm_sql_handle_t *sqlsock)
#define RLM_NETVIM_TMP_PREFIX
module_instance_t * module_instantiate(CONF_SECTION *modules, char const *askedname)
Load a module, and instantiate it.
sql_rcode_t(* sql_fetch_row)(rlm_sql_row_t *out, rlm_sql_handle_t *handle, rlm_sql_config_t *config)
Defines a CONF_PAIR to C data type mapping.
static int nvp_select(rlm_sql_row_t *row, rlm_sqlhpwippool_t *data, rlm_sql_handle_t *sqlsock, char const *fmt,...)
uint32_t sincesync
req. done so far since last free IP sync.
#define pthread_mutex_unlock(_x)
static int nvp_vquery(rlm_sqlhpwippool_t *data, rlm_sql_handle_t *sqlsock, char const *fmt, va_list ap)
#define RLM_NETVIM_MAX_ROWS
Immediately reject the request.
uint32_t sync_after
How often to sync with radacct.
static int nvp_select_finish(rlm_sqlhpwippool_t *data, rlm_sql_handle_t *sqlsock)
3 methods index for accounting section.
Stores an attribute, a value and various bits of other data.
module_t rlm_sqlhpwippool
static CONF_PARSER module_config[]
void void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
static int mod_instantiate(CONF_SECTION *conf, void *instance)
rlm_sql_config_t * config
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
char const * sql_instance_name
rlm_sql instance to use.
CONF_SECTION * cf_section_sub_find(CONF_SECTION const *, char const *name)
Find a sub-section in a section.
Module succeeded without doing anything.
uint64_t magic
Used to validate module struct.
Module failed, don't reply.
CONF_SECTION * config
Root of the server config.
#define FR_CONF_OFFSET(_n, _t, _s, _f)
static rlm_rcode_t CC_HINT(nonnull)
static int nvp_cleanup(rlm_sqlhpwippool_t *data)
void * fr_connection_get(fr_connection_pool_t *pool)
Reserve a connection in the connection pool.
static int nvp_finish(rlm_sqlhpwippool_t *data, rlm_sql_handle_t *sqlsock)
#define PW_STATUS_ACCOUNTING_ON
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.
size_t strlcpy(char *dst, char const *src, size_t siz)
sql_rcode_t(* sql_finish_query)(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
void fr_connection_release(fr_connection_pool_t *pool, void *conn)
Release a connection.
String of printable characters.
rlm_sql_module_t * module
struct rlm_sqlhpwippool_t rlm_sqlhpwippool_t
fr_connection_pool_t * pool
#define PW_STATUS_ACCOUNTING_OFF
sql_rcode_t(* sql_store_result)(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
char const * cf_section_name2(CONF_SECTION const *cs)
char const * db_name
Netvim database.