3 * Chooses an IPv4 address from pools defined in ASN Netvim
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
21 * Copyright (c) 2005-2006 Pawel Foremski <pjf@asn.pl>,
22 * 2000-2006 The FreeRADIUS server project
24 * Current bugs/limits:
25 * - probably works only with newer versions of MySQL (subqueries)
26 * - requires FreeRADIUS' SQL user to have proper permissions on proper tables
27 * from Netvim database
28 * - of course uses dirty hacks to get access to the database
29 * - queries and table names are not configurable
30 * - IPv4 only (I don't even care about IPv6 by now)
31 * - pool names (fetched from database) are not "escaped"
32 * - you have to set encoding of radius.acctuniqueid to same as
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_LOG_FMT "rlm_sqlhpwippool(%s, line %u): %s"
48 #define RLM_NETVIM_MAX_ROWS 1000000
49 #define RLM_NETVIM_TMP_PREFIX "auth-tmp-"
51 static const char rcsid[] = "$Id$";
53 typedef struct rlm_sqlhpwippool_t {
54 const char *myname; /* name of this instance */
55 SQL_INST *sqlinst; /* SQL_INST for requested instance */
56 rlm_sql_module_t *db; /* here the fun takes place ;-) */
58 pthread_mutex_t mutex; /* used "with" syncafter */
60 int sincesync; /* req. done so far since last free IP sync. */
63 char *sqlinst_name; /* rlm_sql instance to use */
64 char *db_name; /* netvim database */
65 int nofreefail; /* fail if no free IP addresses found */
66 int freeafter; /* how many seconds an IP should not be used after
68 int syncafter; /* how often to sync with radacct */
71 /* char *name, int type,
72 * size_t offset, void *data, char *dflt */
73 static CONF_PARSER module_config[] = {
74 { "sqlinst_name", PW_TYPE_STRING_PTR,
75 offsetof(rlm_sqlhpwippool_t, sqlinst_name), NULL, "sql" },
76 { "db_name", PW_TYPE_STRING_PTR,
77 offsetof(rlm_sqlhpwippool_t, db_name), NULL, "netvim" },
78 { "nofreefail", PW_TYPE_BOOLEAN,
79 offsetof(rlm_sqlhpwippool_t, nofreefail), NULL, "yes" },
80 { "freeafter", PW_TYPE_INTEGER,
81 offsetof(rlm_sqlhpwippool_t, freeafter), NULL, "300" },
82 { "syncafter", PW_TYPE_INTEGER,
83 offsetof(rlm_sqlhpwippool_t, syncafter), NULL, "25" },
84 { NULL, -1, 0, NULL, NULL } /* end */
87 /* wrapper around radlog which adds prefix with module and instance name */
88 static int nvp_log(unsigned int line, rlm_sqlhpwippool_t *data, int lvl,
95 /* prefix log message with RLM_NETVIM_LOG_FMT */
96 snprintf(pfmt, sizeof(pfmt), RLM_NETVIM_LOG_FMT,
97 data->myname, line, fmt);
100 r = vradlog(lvl, pfmt, ap);
105 /* handy SQL query tool */
106 static int nvp_vquery(unsigned int line, rlm_sqlhpwippool_t *data,
107 SQLSOCK *sqlsock, const char *fmt, va_list ap)
109 char query[MAX_QUERY_LEN];
111 vsnprintf(query, MAX_QUERY_LEN, fmt, ap);
113 if (rlm_sql_query(&sqlsock, data->sqlinst, query)) {
114 nvp_log(__LINE__, data, L_ERR, "nvp_vquery(): query from line %u: %s",
115 line, (const char *)(data->db->sql_error)(sqlsock, data->sqlinst->config));
122 /* wrapper around nvp_vquery */
123 static int nvp_query(unsigned int line, rlm_sqlhpwippool_t *data,
124 SQLSOCK *sqlsock, const char *fmt, ...)
130 r = nvp_vquery(line, data, sqlsock, fmt, ap);
136 /* handy wrapper around data->db->sql_finish_query() */
137 static int nvp_finish(rlm_sqlhpwippool_t *data, SQLSOCK *sqlsock)
139 return (data->db->sql_finish_query)(sqlsock, data->sqlinst->config);
142 /* executes query and fetches first row
146 static int nvp_select(unsigned int line, rlm_sqlhpwippool_t *data,
147 SQLSOCK *sqlsock, const char *fmt, ...)
152 if (!nvp_vquery(line, data, sqlsock, fmt, ap)) {
158 if ((data->db->sql_store_result)(sqlsock, data->sqlinst->config)) {
159 nvp_log(__LINE__, data, L_ERR,
160 "nvp_select(): error while saving results of query from line %u",
165 if ((data->db->sql_num_rows)(sqlsock, data->sqlinst->config) < 1) {
166 nvp_log(__LINE__, data, L_DBG,
167 "nvp_select(): no results in query from line %u", line);
171 if ((data->db->sql_fetch_row)(sqlsock, data->sqlinst->config)) {
172 nvp_log(__LINE__, data, L_ERR, "nvp_select(): couldn't fetch row "
173 "from results of query from line %u",
181 static int nvp_select_finish(rlm_sqlhpwippool_t *data, SQLSOCK *sqlsock)
183 return ((data->db->sql_free_result)(sqlsock, data->sqlinst->config) ||
184 nvp_finish(data, sqlsock));
187 /* frees IPs of closed sessions (eg. by external modifications to db) */
188 static int nvp_freeclosed(rlm_sqlhpwippool_t *data, SQLSOCK *sqlsock)
190 if (!nvp_query(__LINE__, data, sqlsock,
191 "UPDATE `%s`.`ips`, `radacct` "
193 "`ips`.`rsv_until` = `radacct`.`acctstoptime` + INTERVAL %u SECOND "
195 "`radacct`.`acctstoptime` IS NOT NULL AND " /* session is closed */
196 "(" /* address is being used */
197 "`ips`.`pid` IS NOT NULL AND "
198 "(`rsv_until` = 0 OR `rsv_until` > NOW())"
200 "`radacct`.`acctuniqueid` = `ips`.`rsv_by`",
201 data->db_name, data->freeafter)) {
205 nvp_finish(data, sqlsock);
209 /* updates number of free IP addresses in pools */
210 static int nvp_syncfree(rlm_sqlhpwippool_t *data, SQLSOCK *sqlsock)
212 if (!nvp_query(__LINE__, data, sqlsock,
213 "UPDATE `%s`.`ip_pools` "
214 "SET `ip_pools`.`free` = "
218 "`ips`.`ip` BETWEEN "
219 "`ip_pools`.`ip_start` AND `ip_pools`.`ip_stop` AND "
221 "`ips`.`pid` IS NULL OR "
222 "(`ips`.`rsv_until` > 0 AND `ips`.`rsv_until` < NOW())"
228 nvp_finish(data, sqlsock);
232 /* cleanup IP pools and sync them with radacct */
233 static int nvp_cleanup(rlm_sqlhpwippool_t *data)
237 /* initialize the SQL socket */
238 sqlsock = sql_get_socket(data->sqlinst);
240 nvp_log(__LINE__, data, L_ERR, "nvp_cleanup(): error while "
241 "requesting new SQL connection");
245 /* free IPs of closed sessions */
246 if (!nvp_freeclosed(data, sqlsock)) {
247 sql_release_socket(data->sqlinst, sqlsock);
251 /* add sessions opened in the meantime */
252 if (!nvp_query(__LINE__, data, sqlsock,
253 "UPDATE `%s`.`ips`, `radacct` "
256 "`ips`.`rsv_by` = `radacct`.`acctuniqueid`, "
257 "`ips`.`rsv_since` = `radacct`.`acctstarttime`, "
258 "`ips`.`rsv_until` = 0 "
260 "`radacct`.`acctstoptime` IS NULL AND " /* session is opened */
261 "`ips`.`ip` = INET_ATON(`radacct`.`framedipaddress`) AND "
263 "`ips`.`pid` IS NULL OR "
264 /* "(`ips`.`rsv_until` > 0 AND `ips.`rsv_until` < NOW()) " */
265 "`ips`.`rsv_until` != 0" /* no acct pkt received yet */
268 sql_release_socket(data->sqlinst, sqlsock);
272 nvp_finish(data, sqlsock);
275 /* count number of free IP addresses in IP pools */
276 if (!nvp_syncfree(data, sqlsock)) {
277 sql_release_socket(data->sqlinst, sqlsock);
281 sql_release_socket(data->sqlinst, sqlsock);
285 static int sqlhpwippool_detach(void *instance)
287 rlm_sqlhpwippool_t *data = (rlm_sqlhpwippool_t *) instance;
289 /* (*data) is zeroed on instantiation */
290 if (data->sqlinst_name) free(data->sqlinst_name);
291 if (data->db_name) free(data->db_name);
297 /* standard foobar code */
298 static int sqlhpwippool_instantiate(CONF_SECTION *conf, void **instance)
300 rlm_sqlhpwippool_t *data;
301 module_instance_t *modinst;
303 /* set up a storage area for instance data */
304 data = rad_malloc(sizeof(*data));
305 if (!data) return -1;
306 memset(data, 0, sizeof(*data)); /* so _detach will know what to free */
308 /* fail if the configuration parameters can't be parsed */
309 if (cf_section_parse(conf, data, module_config) < 0) {
310 sqlhpwippool_detach(*instance);
315 data->myname = cf_section_name2(conf);
317 data->myname = "(no name)";
322 modinst = find_module_instance(cf_section_find("modules"), (data->sqlinst_name), 1 );
324 nvp_log(__LINE__, data, L_ERR,
325 "sqlhpwippool_instantiate(): cannot find module instance "
331 /* check if the given instance is really a rlm_sql instance */
332 if (strcmp(modinst->entry->name, "rlm_sql") != 0) {
333 nvp_log(__LINE__, data, L_ERR,
334 "sqlhpwippool_instantiate(): given instance (%s) is not "
335 "an instance of the rlm_sql module",
340 /* save pointers to useful "objects" */
341 data->sqlinst = (SQL_INST *) modinst->insthandle;
342 data->db = (rlm_sql_module_t *) data->sqlinst->module;
344 /* everything went ok, cleanup pool */
347 return ((nvp_cleanup(data)) ? 0 : -1);
350 /* assign new IP address, if required */
351 static int sqlhpwippool_postauth(void *instance, REQUEST *request)
354 char *pname; /* name of requested IP pool */
355 uint32_t nasip; /* NAS IP in host byte order */
356 struct in_addr ip = {0}; /* reserved IP for client (net. byte order) */
358 unsigned long s_gid, /* _s_elected in sql result set */
359 s_prio, /* as above */
360 s_pid, /* as above */
361 gid, /* real integer value */
363 weights_sum, used_sum, ip_start, ip_stop, connid;
366 rlm_sqlhpwippool_t *data = (rlm_sqlhpwippool_t *) instance;
368 /* if IP is already there, then nothing to do */
369 vp = pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY);
371 nvp_log(__LINE__, data, L_DBG,
372 "sqlhpwippool_postauth(): IP address "
373 "already in the reply packet - exiting");
374 return RLM_MODULE_NOOP;
377 /* if no pool name, we don't need to do anything */
378 vp = pairfind(request->reply->vps, ASN_IP_POOL_NAME, VENDORPEC_ASN, TAG_ANY);
380 pname = vp->vp_strvalue;
381 nvp_log(__LINE__, data, L_DBG,
382 "sqlhpwippool_postauth(): pool name = '%s'",
386 nvp_log(__LINE__, data, L_DBG,
387 "sqlhpwippool_postauth(): no IP pool name - exiting");
388 return RLM_MODULE_NOOP;
391 /* if no NAS IP address, assign 0 */
392 vp = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS, 0, TAG_ANY);
394 nasip = ntohl(vp->vp_ipaddr);
398 nvp_log(__LINE__, data, L_DBG,
399 "sqlhpwippool_postauth(): no NAS IP address in "
400 "the request packet - using \"0.0.0.0/0\" (any)");
403 /* get our database connection */
404 sqlsock = sql_get_socket(data->sqlinst);
406 nvp_log(__LINE__, data, L_ERR,
407 "sqlhpwippool_postauth(): error while requesting an SQL socket");
408 return RLM_MODULE_FAIL;
411 /* get connection id as temporary unique integer */
412 if (nvp_select(__LINE__, data, sqlsock, "SELECT CONNECTION_ID()") < 1) {
413 nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_postauth(): WTF ;-)!");
414 nvp_select_finish(data, sqlsock);
415 sql_release_socket(data->sqlinst, sqlsock);
416 return RLM_MODULE_FAIL;
419 connid = strtoul(sqlsock->row[0], (char **) NULL, 10);
420 nvp_select_finish(data, sqlsock);
422 /* synchronize with radacct db, if needed */
423 if (++data->sincesync >= data->syncafter
424 #ifdef HAVE_PTHREAD_D
425 && (pthread_mutex_trylock(&data->mutex)) == 0
432 nvp_log(__LINE__, data, L_DBG,
433 "sqlhpwippool_postauth(): syncing with radacct table");
435 r = (nvp_freeclosed(data, sqlsock) && nvp_syncfree(data, sqlsock));
437 #ifdef HAVE_PTHREAD_D
438 pthread_mutex_unlock(&data->mutex);
442 nvp_log(__LINE__, data, L_ERR,
443 "sqlhpwippool_postauth(): synchronization failed");
444 sql_release_socket(data->sqlinst, sqlsock);
445 return RLM_MODULE_FAIL;
449 for (s_gid = 0; s_gid < RLM_NETVIM_MAX_ROWS && !(ip.s_addr); s_gid++) {
450 nvp_log(__LINE__, data, L_DBG,
451 "sqlhpwippool_postauth(): selecting gid on position %lu",
454 /* find the most specific group which NAS belongs to */
455 switch (nvp_select(__LINE__, data, sqlsock,
456 "SELECT `host_groups`.`gid` "
458 "`%s`.`host_groups`, "
462 "`host_groups`.`gid` = `ids`.`id` AND "
463 "`ids`.`enabled` = 1 AND "
464 "`host_groups`.`gid` = `gid_ip`.`gid` AND "
465 "%lu BETWEEN `gid_ip`.`ip_start` AND `gid_ip`.`ip_stop` "
466 "ORDER BY (`gid_ip`.`ip_stop` - `gid_ip`.`ip_start`) ASC "
468 data->db_name, nasip, s_gid)) {
470 nvp_log(__LINE__, data, L_ERR,
471 "sqlhpwippool_postauth(): couldn't find "
472 "any more matching host groups");
473 goto end_gid; /* exit the main loop */
475 sql_release_socket(data->sqlinst, sqlsock);
476 return RLM_MODULE_FAIL;
479 /* store the group ID and free memory occupied by results */
480 gid = strtoul(sqlsock->row[0], (char **) NULL, 10);
481 nvp_select_finish(data, sqlsock);
483 for (s_prio = 0; s_prio < RLM_NETVIM_MAX_ROWS && !(ip.s_addr); s_prio++) {
484 nvp_log(__LINE__, data, L_DBG,
485 "sqlhpwippool_postauth(): selecting prio on position %lu",
488 /* prepare to search for best fit pool */
489 switch (nvp_select(__LINE__, data, sqlsock,
491 "`ip_pools`.`prio`, "
492 "SUM(`ip_pools`.`weight`) AS `weights_sum`, "
493 "(SUM(`ip_pools`.`total`) - "
494 "SUM(`ip_pools`.`free`)) AS `used_sum` "
498 "`%1$s`.`pool_names` "
500 "`ip_pools`.`gid` = %lu AND "
501 "`ids`.`id` = `ip_pools`.`pid` AND "
502 "`ids`.`enabled` = 1 AND "
503 "`pool_names`.`pnid` = `ip_pools`.`pnid` AND "
504 "`pool_names`.`name` = '%s' AND "
505 "`ip_pools`.`free` > 0 "
507 "ORDER BY `prio` ASC "
509 data->db_name, gid, pname, s_prio)) {
511 nvp_log(__LINE__, data, L_DBG,
512 "sqlhpwippool_postauth(): couldn't find "
513 "any more matching pools for gid = %u",
515 goto end_prio; /* select next gid */
517 sql_release_socket(data->sqlinst, sqlsock);
518 return RLM_MODULE_FAIL;
521 /* store the prio and weights sum */
522 prio = strtol(sqlsock->row[0], (char **) NULL, 10);
523 weights_sum = strtoul(sqlsock->row[1], (char **) NULL, 10);
524 used_sum = strtoul(sqlsock->row[2], (char **) NULL, 10);
527 nvp_select_finish(data, sqlsock);
529 for (s_pid = 0; s_pid < RLM_NETVIM_MAX_ROWS && !(ip.s_addr); s_pid++) {
530 nvp_log(__LINE__, data, L_DBG,
531 "sqlhpwippool_postauth(): selecting PID on position %lu",
534 /* search for best fit pool */
535 switch (nvp_select(__LINE__, data, sqlsock,
538 "`ip_pools`.`ip_start`, "
539 "`ip_pools`.`ip_stop` "
543 "`%1$s`.`pool_names` "
545 "`ip_pools`.`gid` = %lu AND "
546 "`ids`.`id` = `ip_pools`.`pid` AND "
547 "`ids`.`enabled` = 1 AND "
548 "`pool_names`.`pnid` = `ip_pools`.`pnid` AND "
549 "`pool_names`.`name` = '%s' AND "
550 "`ip_pools`.`free` > 0 AND "
552 "ORDER BY (`weight`/%lu.0000 - (`total` - `free`)/%lu) DESC "
554 data->db_name, gid, pname, prio,
555 weights_sum, used_sum, s_pid)) {
557 nvp_log(__LINE__, data, L_DBG,
558 "sqlhpwippool_postauth(): couldn't find any more "
559 "matching pools of prio = %ld for gid = %lu",
561 goto end_pid; /* select next prio */
563 sql_release_socket(data->sqlinst, sqlsock);
564 return RLM_MODULE_FAIL;
567 /* store the data and free memory occupied by results */
568 pid = strtoul(sqlsock->row[0], (char **) NULL, 10);
569 ip_start = strtoul(sqlsock->row[1], (char **) NULL, 10);
570 ip_stop = strtoul(sqlsock->row[2], (char **) NULL, 10);
571 nvp_select_finish(data, sqlsock);
573 /* reserve an IP address */
574 if (!nvp_query(__LINE__, data, sqlsock,
578 "`rsv_since` = NOW(), "
579 "`rsv_by` = '" RLM_NETVIM_TMP_PREFIX "%lu', "
580 "`rsv_until` = NOW() + INTERVAL %d SECOND "
582 "`ip` BETWEEN %lu AND %lu AND "
585 "(`rsv_until` > 0 AND `rsv_until` < NOW())"
589 data->db_name, pid, connid, data->freeafter, ip_start, ip_stop)) {
590 sql_release_socket(data->sqlinst, sqlsock);
591 return RLM_MODULE_FAIL;
594 nvp_finish(data, sqlsock);
597 /* select assigned IP address */
598 switch (nvp_select(__LINE__, data, sqlsock,
601 "WHERE `rsv_by` = '" RLM_NETVIM_TMP_PREFIX "%lu' "
602 "ORDER BY `rsv_since` DESC "
604 data->db_name, connid)) {
606 nvp_log(__LINE__, data, L_ERR,
607 "sqlhpwippool_postauth(): couldn't reserve an IP address "
608 "from pool of pid = %lu (prio = %ld, gid = %lu)",
610 continue; /* select next pid */
612 sql_release_socket(data->sqlinst, sqlsock);
613 return RLM_MODULE_FAIL;
616 /* update free IPs count */
617 if (!nvp_query(__LINE__, data, sqlsock,
618 "UPDATE `%s`.`ip_pools` "
620 "`free` = `free` - 1 "
624 data->db_name, pid)) {
625 sql_release_socket(data->sqlinst, sqlsock);
626 return RLM_MODULE_FAIL;
629 nvp_finish(data, sqlsock);
632 /* get assigned IP and free memory */
633 ip.s_addr = htonl(strtoul(sqlsock->row[0], (char **) NULL, 10));
634 nvp_select_finish(data, sqlsock);
636 end_pid: continue; /* stupid */
638 end_prio: continue; /* stupid */
642 /* release SQL socket */
643 sql_release_socket(data->sqlinst, sqlsock);
645 /* no free IP address found */
647 nvp_log(__LINE__, data, L_INFO,
648 "sqlhpwippool_postauth(): no free IP address found!");
650 if (data->nofreefail) {
651 nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): rejecting user");
652 return RLM_MODULE_REJECT;
655 nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): exiting");
656 return RLM_MODULE_NOOP;
660 /* add IP address to reply packet */
661 vp = radius_paircreate(request, &request->reply->vps,
662 PW_FRAMED_IP_ADDRESS, 0, PW_TYPE_IPADDR);
663 vp->vp_ipaddr = ip.s_addr;
665 nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): returning %s",
667 return RLM_MODULE_OK;
670 static int sqlhpwippool_accounting(void *instance, REQUEST *request)
674 struct in_addr nasip; /* NAS IP */
675 char *sessid; /* unique session id */
676 char nasipstr[16]; /* NAS IP in string format */
677 uint32_t framedip = 0; /* client's IP, host byte order */
680 rlm_sqlhpwippool_t *data = (rlm_sqlhpwippool_t *) instance;
682 /* if no unique session ID, don't even try */
683 vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID, 0, TAG_ANY);
685 sessid = vp->vp_strvalue;
688 nvp_log(__LINE__, data, L_ERR,
689 "sqlhpwippool_accounting(): unique session ID not found");
690 return RLM_MODULE_FAIL;
693 vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY);
695 acct_type = vp->vp_integer;
698 nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_accounting(): "
699 "couldn't find type of accounting packet");
700 return RLM_MODULE_FAIL;
703 if (!(acct_type == PW_STATUS_START ||
704 acct_type == PW_STATUS_ALIVE ||
705 acct_type == PW_STATUS_STOP ||
706 acct_type == PW_STATUS_ACCOUNTING_OFF ||
707 acct_type == PW_STATUS_ACCOUNTING_ON)) {
708 return RLM_MODULE_NOOP;
711 /* connect to database */
712 sqlsock = sql_get_socket(data->sqlinst);
714 nvp_log(__LINE__, data, L_ERR,
715 "sqlhpwippool_accounting(): couldn't connect to database");
716 return RLM_MODULE_FAIL;
721 case PW_STATUS_START:
722 case PW_STATUS_ALIVE:
723 vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY);
725 nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_accounting(): no framed IP");
726 sql_release_socket(data->sqlinst, sqlsock);
727 return RLM_MODULE_FAIL;
730 framedip = ntohl(vp->vp_ipaddr);
732 if (!nvp_query(__LINE__, data, sqlsock,
738 data->db_name, sessid, framedip)) {
739 sql_release_socket(data->sqlinst, sqlsock);
740 return RLM_MODULE_FAIL;
742 nvp_finish(data, sqlsock);
746 if (!nvp_query(__LINE__, data, sqlsock,
747 "UPDATE `%s`.`ips`, `%1$s`.`ip_pools` "
749 "`ips`.`rsv_until` = NOW() + INTERVAL %u SECOND, "
750 "`ip_pools`.`free` = `ip_pools`.`free` + 1 "
752 "`ips`.`rsv_by` = '%s' AND "
753 "`ips`.`ip` BETWEEN `ip_pools`.`ip_start` AND `ip_pools`.`ip_stop`",
754 data->db_name, data->freeafter, sessid)) {
755 sql_release_socket(data->sqlinst, sqlsock);
756 return RLM_MODULE_FAIL;
758 nvp_finish(data, sqlsock);
761 case PW_STATUS_ACCOUNTING_OFF:
762 case PW_STATUS_ACCOUNTING_ON:
763 vp = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS, 0, TAG_ANY);
765 nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_accounting(): no NAS IP");
766 sql_release_socket(data->sqlinst, sqlsock);
767 return RLM_MODULE_FAIL;
770 nasip.s_addr = vp->vp_ipaddr;
771 strlcpy(nasipstr, inet_ntoa(nasip), sizeof(nasipstr));
773 if (!nvp_query(__LINE__, data, sqlsock,
774 "UPDATE `%s`.`ips`, `radacct` "
775 "SET `ips`.`rsv_until` = NOW() + INTERVAL %u SECOND "
777 "`radacct`.`nasipaddress` = '%s' AND "
778 "`ips`.`rsv_by` = `radacct`.`acctuniqueid`",
779 data->db_name, data->freeafter, nasipstr)) {
780 sql_release_socket(data->sqlinst, sqlsock);
781 return RLM_MODULE_FAIL;
783 nvp_finish(data, sqlsock);
788 sql_release_socket(data->sqlinst, sqlsock);
789 return RLM_MODULE_OK;
792 module_t rlm_sqlhpwippool = {
794 "sqlhpwippool", /* name */
795 RLM_TYPE_THREAD_SAFE, /* type */
796 sqlhpwippool_instantiate, /* instantiation */
797 sqlhpwippool_detach, /* detach */
799 NULL, /* authentication */
800 NULL, /* authorization */
801 NULL, /* preaccounting */
802 sqlhpwippool_accounting,/* accounting */
803 NULL, /* checksimul */
804 NULL, /* pre-proxy */
805 NULL, /* post-proxy */
806 sqlhpwippool_postauth /* post-auth */