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
37 #include <freeradius-devel/radiusd.h>
38 #include <freeradius-devel/modules.h>
39 #include <freeradius-devel/modpriv.h>
45 #define VENDOR_ASN 23782
46 #define ASN_IP_POOL_NAME 1
47 #define PW_ASN_IP_POOL_NAME (ASN_IP_POOL_NAME | (VENDOR_ASN << 16))
49 #define RLM_NETVIM_LOG_FMT "rlm_sqlhpwippool(%s, line %u): %s"
50 #define RLM_NETVIM_MAX_ROWS 1000000
51 #define RLM_NETVIM_TMP_PREFIX "auth-tmp-"
53 static const char rcsid[] = "$Id$";
55 typedef struct rlm_sqlhpwippool_t {
56 const char *myname; /* name of this instance */
57 SQL_INST *sqlinst; /* SQL_INST for requested instance */
58 rlm_sql_module_t *db; /* here the fun takes place ;-) */
60 pthread_mutex_t mutex; /* used "with" syncafter */
62 int sincesync; /* req. done so far since last free IP sync. */
65 char *sqlinst_name; /* rlm_sql instance to use */
66 char *db_name; /* netvim database */
67 int nofreefail; /* fail if no free IP addresses found */
68 int freeafter; /* how many seconds an IP should not be used after
70 int syncafter; /* how often to sync with radacct */
73 /* char *name, int type,
74 * size_t offset, void *data, char *dflt */
75 static CONF_PARSER module_config[] = {
76 { "sqlinst_name", PW_TYPE_STRING_PTR,
77 offsetof(rlm_sqlhpwippool_t, sqlinst_name), NULL, "sql" },
78 { "db_name", PW_TYPE_STRING_PTR,
79 offsetof(rlm_sqlhpwippool_t, db_name), NULL, "netvim" },
80 { "nofreefail", PW_TYPE_BOOLEAN,
81 offsetof(rlm_sqlhpwippool_t, nofreefail), NULL, "yes" },
82 { "freeafter", PW_TYPE_INTEGER,
83 offsetof(rlm_sqlhpwippool_t, freeafter), NULL, "300" },
84 { "syncafter", PW_TYPE_INTEGER,
85 offsetof(rlm_sqlhpwippool_t, syncafter), NULL, "25" },
86 { NULL, -1, 0, NULL, NULL } /* end */
89 /* wrapper around radlog which adds prefix with module and instance name */
90 static int nvp_log(unsigned int line, rlm_sqlhpwippool_t *data, int lvl,
97 /* prefix log message with RLM_NETVIM_LOG_FMT */
98 snprintf(pfmt, sizeof(pfmt), RLM_NETVIM_LOG_FMT,
99 data->myname, line, fmt);
102 r = vradlog(lvl, pfmt, ap);
107 /* handy SQL query tool */
108 static int nvp_vquery(unsigned int line, rlm_sqlhpwippool_t *data,
109 SQLSOCK *sqlsock, const char *fmt, va_list ap)
111 char query[MAX_QUERY_LEN];
113 vsnprintf(query, MAX_QUERY_LEN, fmt, ap);
115 if (rlm_sql_query(sqlsock, data->sqlinst, query)) {
116 nvp_log(__LINE__, data, L_ERR, "nvp_vquery(): query from line %u: %s",
117 line, (char *)(data->db->sql_error)(sqlsock, data->sqlinst->config));
124 /* wrapper around nvp_vquery */
125 static int nvp_query(unsigned int line, rlm_sqlhpwippool_t *data,
126 SQLSOCK *sqlsock, const char *fmt, ...)
132 r = nvp_vquery(line, data, sqlsock, fmt, ap);
138 /* handy wrapper around data->db->sql_finish_query() */
139 static int nvp_finish(rlm_sqlhpwippool_t *data, SQLSOCK *sqlsock)
141 return (data->db->sql_finish_query)(sqlsock, data->sqlinst->config);
144 /* executes query and fetches first row
148 static int nvp_select(unsigned int line, rlm_sqlhpwippool_t *data,
149 SQLSOCK *sqlsock, const char *fmt, ...)
154 if (!nvp_vquery(line, data, sqlsock, fmt, ap)) {
160 if ((data->db->sql_store_result)(sqlsock, data->sqlinst->config)) {
161 nvp_log(__LINE__, data, L_ERR,
162 "nvp_select(): error while saving results of query from line %u",
167 if ((data->db->sql_num_rows)(sqlsock, data->sqlinst->config) < 1) {
168 nvp_log(__LINE__, data, L_DBG,
169 "nvp_select(): no results in query from line %u", line);
173 if ((data->db->sql_fetch_row)(sqlsock, data->sqlinst->config)) {
174 nvp_log(__LINE__, data, L_ERR, "nvp_select(): couldn't fetch row "
175 "from results of query from line %u",
183 static int nvp_select_finish(rlm_sqlhpwippool_t *data, SQLSOCK *sqlsock)
185 return ((data->db->sql_free_result)(sqlsock, data->sqlinst->config) ||
186 nvp_finish(data, sqlsock));
189 /* frees IPs of closed sessions (eg. by external modifications to db) */
190 static int nvp_freeclosed(rlm_sqlhpwippool_t *data, SQLSOCK *sqlsock)
192 if (!nvp_query(__LINE__, data, sqlsock,
193 "UPDATE `%s`.`ips`, `radacct` "
195 "`ips`.`rsv_until` = `radacct`.`acctstoptime` + INTERVAL %u SECOND "
197 "`radacct`.`acctstoptime` IS NOT NULL AND " /* session is closed */
198 "(" /* address is being used */
199 "`ips`.`pid` IS NOT NULL AND "
200 "(`rsv_until` = 0 OR `rsv_until` > NOW())"
202 "`radacct`.`acctuniqueid` = `ips`.`rsv_by`",
203 data->db_name, data->freeafter)) {
207 nvp_finish(data, sqlsock);
211 /* updates number of free IP addresses in pools */
212 static int nvp_syncfree(rlm_sqlhpwippool_t *data, SQLSOCK *sqlsock)
214 if (!nvp_query(__LINE__, data, sqlsock,
215 "UPDATE `%s`.`ip_pools` "
216 "SET `ip_pools`.`free` = "
220 "`ips`.`ip` BETWEEN "
221 "`ip_pools`.`ip_start` AND `ip_pools`.`ip_stop` AND "
223 "`ips`.`pid` IS NULL OR "
224 "(`ips`.`rsv_until` > 0 AND `ips`.`rsv_until` < NOW())"
230 nvp_finish(data, sqlsock);
234 /* cleanup IP pools and sync them with radacct */
235 static int nvp_cleanup(rlm_sqlhpwippool_t *data)
239 /* initialize the SQL socket */
240 sqlsock = sql_get_socket(data->sqlinst);
242 nvp_log(__LINE__, data, L_ERR, "nvp_cleanup(): error while "
243 "requesting new SQL connection");
247 /* free IPs of closed sessions */
248 if (!nvp_freeclosed(data, sqlsock)) {
249 sql_release_socket(data->sqlinst, sqlsock);
253 /* add sessions opened in the meantime */
254 if (!nvp_query(__LINE__, data, sqlsock,
255 "UPDATE `%s`.`ips`, `radacct` "
258 "`ips`.`rsv_by` = `radacct`.`acctuniqueid`, "
259 "`ips`.`rsv_since` = `radacct`.`acctstarttime`, "
260 "`ips`.`rsv_until` = 0 "
262 "`radacct`.`acctstoptime` IS NULL AND " /* session is opened */
263 "`ips`.`ip` = INET_ATON(`radacct`.`framedipaddress`) AND "
265 "`ips`.`pid` IS NULL OR "
266 /* "(`ips`.`rsv_until` > 0 AND `ips.`rsv_until` < NOW()) " */
267 "`ips`.`rsv_until` != 0" /* no acct pkt received yet */
270 sql_release_socket(data->sqlinst, sqlsock);
274 nvp_finish(data, sqlsock);
277 /* count number of free IP addresses in IP pools */
278 if (!nvp_syncfree(data, sqlsock)) {
279 sql_release_socket(data->sqlinst, sqlsock);
283 sql_release_socket(data->sqlinst, sqlsock);
287 static int sqlhpwippool_detach(void *instance)
289 rlm_sqlhpwippool_t *data = (rlm_sqlhpwippool_t *) instance;
291 /* (*data) is zeroed on instantiation */
292 if (data->sqlinst_name) free(data->sqlinst_name);
293 if (data->db_name) free(data->db_name);
299 /* standard foobar code */
300 static int sqlhpwippool_instantiate(CONF_SECTION *conf, void **instance)
302 rlm_sqlhpwippool_t *data;
303 module_instance_t *modinst;
305 /* set up a storage area for instance data */
306 data = rad_malloc(sizeof(*data));
307 if (!data) return -1;
308 memset(data, 0, sizeof(*data)); /* so _detach will know what to free */
310 /* fail if the configuration parameters can't be parsed */
311 if (cf_section_parse(conf, data, module_config) < 0) {
312 sqlhpwippool_detach(*instance);
317 data->myname = cf_section_name2(conf);
319 data->myname = "(no name)";
324 modinst = find_module_instance(cf_section_find("modules"), (data->sqlinst_name), 1 );
326 nvp_log(__LINE__, data, L_ERR,
327 "sqlhpwippool_instantiate(): cannot find module instance "
333 /* check if the given instance is really a rlm_sql instance */
334 if (strcmp(modinst->entry->name, "rlm_sql") != 0) {
335 nvp_log(__LINE__, data, L_ERR,
336 "sqlhpwippool_instantiate(): given instance (%s) is not "
337 "an instance of the rlm_sql module",
342 /* save pointers to useful "objects" */
343 data->sqlinst = (SQL_INST *) modinst->insthandle;
344 data->db = (rlm_sql_module_t *) data->sqlinst->module;
346 /* everything went ok, cleanup pool */
349 return ((nvp_cleanup(data)) ? 0 : -1);
352 /* assign new IP address, if required */
353 static int sqlhpwippool_postauth(void *instance, REQUEST *request)
356 unsigned char *pname; /* name of requested IP pool */
357 uint32_t nasip; /* NAS IP in host byte order */
358 struct in_addr ip = {0}; /* reserved IP for client (net. byte order) */
360 unsigned long s_gid, /* _s_elected in sql result set */
361 s_prio, /* as above */
362 s_pid, /* as above */
363 gid, /* real integer value */
365 weights_sum, used_sum, ip_start, ip_stop, connid;
368 rlm_sqlhpwippool_t *data = (rlm_sqlhpwippool_t *) instance;
370 /* if IP is already there, then nothing to do */
371 vp = pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS);
373 nvp_log(__LINE__, data, L_DBG,
374 "sqlhpwippool_postauth(): IP address "
375 "already in the reply packet - exiting");
376 return RLM_MODULE_NOOP;
379 /* if no pool name, we don't need to do anything */
380 vp = pairfind(request->reply->vps, PW_ASN_IP_POOL_NAME);
382 pname = vp->vp_strvalue;
383 nvp_log(__LINE__, data, L_DBG,
384 "sqlhpwippool_postauth(): pool name = '%s'",
388 nvp_log(__LINE__, data, L_DBG,
389 "sqlhpwippool_postauth(): no IP pool name - exiting");
390 return RLM_MODULE_NOOP;
393 /* if no NAS IP address, assign 0 */
394 vp = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS);
396 nasip = ntohl(vp->vp_ipaddr);
400 nvp_log(__LINE__, data, L_DBG,
401 "sqlhpwippool_postauth(): no NAS IP address in "
402 "the request packet - using \"0.0.0.0/0\" (any)");
405 /* get our database connection */
406 sqlsock = sql_get_socket(data->sqlinst);
408 nvp_log(__LINE__, data, L_ERR,
409 "sqlhpwippool_postauth(): error while requesting an SQL socket");
410 return RLM_MODULE_FAIL;
413 /* get connection id as temporary unique integer */
414 if (nvp_select(__LINE__, data, sqlsock, "SELECT CONNECTION_ID()") < 1) {
415 nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_postauth(): WTF ;-)!");
416 nvp_select_finish(data, sqlsock);
417 sql_release_socket(data->sqlinst, sqlsock);
418 return RLM_MODULE_FAIL;
421 connid = strtoul(sqlsock->row[0], (char **) NULL, 10);
422 nvp_select_finish(data, sqlsock);
424 /* synchronize with radacct db, if needed */
425 if (++data->sincesync >= data->syncafter
426 #ifdef HAVE_PTHREAD_D
427 && (pthread_mutex_trylock(&data->mutex)) == 0
434 nvp_log(__LINE__, data, L_DBG,
435 "sqlhpwippool_postauth(): syncing with radacct table");
437 r = (nvp_freeclosed(data, sqlsock) && nvp_syncfree(data, sqlsock));
439 #ifdef HAVE_PTHREAD_D
440 pthread_mutex_unlock(&data->mutex);
444 nvp_log(__LINE__, data, L_ERR,
445 "sqlhpwippool_postauth(): synchronization failed");
446 sql_release_socket(data->sqlinst, sqlsock);
447 return RLM_MODULE_FAIL;
451 for (s_gid = 0; s_gid < RLM_NETVIM_MAX_ROWS && !(ip.s_addr); s_gid++) {
452 nvp_log(__LINE__, data, L_DBG,
453 "sqlhpwippool_postauth(): selecting gid on position %lu",
456 /* find the most specific group which NAS belongs to */
457 switch (nvp_select(__LINE__, data, sqlsock,
458 "SELECT `host_groups`.`gid` "
460 "`%s`.`host_groups`, "
464 "`host_groups`.`gid` = `ids`.`id` AND "
465 "`ids`.`enabled` = 1 AND "
466 "`host_groups`.`gid` = `gid_ip`.`gid` AND "
467 "%lu BETWEEN `gid_ip`.`ip_start` AND `gid_ip`.`ip_stop` "
468 "ORDER BY (`gid_ip`.`ip_stop` - `gid_ip`.`ip_start`) ASC "
470 data->db_name, nasip, s_gid)) {
472 nvp_log(__LINE__, data, L_ERR,
473 "sqlhpwippool_postauth(): couldn't find "
474 "any more matching host groups");
475 goto end_gid; /* exit the main loop */
477 sql_release_socket(data->sqlinst, sqlsock);
478 return RLM_MODULE_FAIL;
481 /* store the group ID and free memory occupied by results */
482 gid = strtoul(sqlsock->row[0], (char **) NULL, 10);
483 nvp_select_finish(data, sqlsock);
485 for (s_prio = 0; s_prio < RLM_NETVIM_MAX_ROWS && !(ip.s_addr); s_prio++) {
486 nvp_log(__LINE__, data, L_DBG,
487 "sqlhpwippool_postauth(): selecting prio on position %lu",
490 /* prepare to search for best fit pool */
491 switch (nvp_select(__LINE__, data, sqlsock,
493 "`ip_pools`.`prio`, "
494 "SUM(`ip_pools`.`weight`) AS `weights_sum`, "
495 "(SUM(`ip_pools`.`total`) - "
496 "SUM(`ip_pools`.`free`)) AS `used_sum` "
500 "`%1$s`.`pool_names` "
502 "`ip_pools`.`gid` = %lu AND "
503 "`ids`.`id` = `ip_pools`.`pid` AND "
504 "`ids`.`enabled` = 1 AND "
505 "`pool_names`.`pnid` = `ip_pools`.`pnid` AND "
506 "`pool_names`.`name` = '%s' AND "
507 "`ip_pools`.`free` > 0 "
509 "ORDER BY `prio` ASC "
511 data->db_name, gid, pname, s_prio)) {
513 nvp_log(__LINE__, data, L_DBG,
514 "sqlhpwippool_postauth(): couldn't find "
515 "any more matching pools for gid = %u",
517 goto end_prio; /* select next gid */
519 sql_release_socket(data->sqlinst, sqlsock);
520 return RLM_MODULE_FAIL;
523 /* store the prio and weights sum */
524 prio = strtol(sqlsock->row[0], (char **) NULL, 10);
525 weights_sum = strtoul(sqlsock->row[1], (char **) NULL, 10);
526 used_sum = strtoul(sqlsock->row[2], (char **) NULL, 10);
529 nvp_select_finish(data, sqlsock);
531 for (s_pid = 0; s_pid < RLM_NETVIM_MAX_ROWS && !(ip.s_addr); s_pid++) {
532 nvp_log(__LINE__, data, L_DBG,
533 "sqlhpwippool_postauth(): selecting PID on position %lu",
536 /* search for best fit pool */
537 switch (nvp_select(__LINE__, data, sqlsock,
540 "`ip_pools`.`ip_start`, "
541 "`ip_pools`.`ip_stop` "
545 "`%1$s`.`pool_names` "
547 "`ip_pools`.`gid` = %lu AND "
548 "`ids`.`id` = `ip_pools`.`pid` AND "
549 "`ids`.`enabled` = 1 AND "
550 "`pool_names`.`pnid` = `ip_pools`.`pnid` AND "
551 "`pool_names`.`name` = '%s' AND "
552 "`ip_pools`.`free` > 0 AND "
554 "ORDER BY (`weight`/%lu.0000 - (`total` - `free`)/%lu) DESC "
556 data->db_name, gid, pname, prio,
557 weights_sum, used_sum, s_pid)) {
559 nvp_log(__LINE__, data, L_DBG,
560 "sqlhpwippool_postauth(): couldn't find any more "
561 "matching pools of prio = %ld for gid = %lu",
563 goto end_pid; /* select next prio */
565 sql_release_socket(data->sqlinst, sqlsock);
566 return RLM_MODULE_FAIL;
569 /* store the data and free memory occupied by results */
570 pid = strtoul(sqlsock->row[0], (char **) NULL, 10);
571 ip_start = strtoul(sqlsock->row[1], (char **) NULL, 10);
572 ip_stop = strtoul(sqlsock->row[2], (char **) NULL, 10);
573 nvp_select_finish(data, sqlsock);
575 /* reserve an IP address */
576 if (!nvp_query(__LINE__, data, sqlsock,
580 "`rsv_since` = NOW(), "
581 "`rsv_by` = '" RLM_NETVIM_TMP_PREFIX "%lu', "
582 "`rsv_until` = NOW() + INTERVAL %d SECOND "
584 "`ip` BETWEEN %lu AND %lu AND "
587 "(`rsv_until` > 0 AND `rsv_until` < NOW())"
591 data->db_name, pid, connid, data->freeafter, ip_start, ip_stop)) {
592 sql_release_socket(data->sqlinst, sqlsock);
593 return RLM_MODULE_FAIL;
596 nvp_finish(data, sqlsock);
599 /* select assigned IP address */
600 switch (nvp_select(__LINE__, data, sqlsock,
603 "WHERE `rsv_by` = '" RLM_NETVIM_TMP_PREFIX "%lu' "
604 "ORDER BY `rsv_since` DESC "
606 data->db_name, connid)) {
608 nvp_log(__LINE__, data, L_ERR,
609 "sqlhpwippool_postauth(): couldn't reserve an IP address "
610 "from pool of pid = %lu (prio = %ld, gid = %lu)",
612 continue; /* select next pid */
614 sql_release_socket(data->sqlinst, sqlsock);
615 return RLM_MODULE_FAIL;
618 /* update free IPs count */
619 if (!nvp_query(__LINE__, data, sqlsock,
620 "UPDATE `%s`.`ip_pools` "
622 "`free` = `free` - 1 "
626 data->db_name, pid)) {
627 sql_release_socket(data->sqlinst, sqlsock);
628 return RLM_MODULE_FAIL;
631 nvp_finish(data, sqlsock);
634 /* get assigned IP and free memory */
635 ip.s_addr = htonl(strtoul(sqlsock->row[0], (char **) NULL, 10));
636 nvp_select_finish(data, sqlsock);
638 end_pid: continue; /* stupid */
640 end_prio: continue; /* stupid */
644 /* release SQL socket */
645 sql_release_socket(data->sqlinst, sqlsock);
647 /* no free IP address found */
649 nvp_log(__LINE__, data, L_INFO,
650 "sqlhpwippool_postauth(): no free IP address found!");
652 if (data->nofreefail) {
653 nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): rejecting user");
654 return RLM_MODULE_REJECT;
657 nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): exiting");
658 return RLM_MODULE_NOOP;
662 /* add IP address to reply packet */
663 vp = radius_paircreate(request, &request->reply->vps,
664 PW_FRAMED_IP_ADDRESS, PW_TYPE_IPADDR);
665 vp->vp_ipaddr = ip.s_addr;
667 nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): returning %s",
669 return RLM_MODULE_OK;
672 static int sqlhpwippool_accounting(void *instance, REQUEST *request)
676 struct in_addr nasip; /* NAS IP */
677 unsigned char *sessid; /* unique session id */
678 char nasipstr[16]; /* NAS IP in string format */
679 uint32_t framedip = 0; /* client's IP, host byte order */
682 rlm_sqlhpwippool_t *data = (rlm_sqlhpwippool_t *) instance;
684 /* if no unique session ID, don't even try */
685 vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID);
687 sessid = vp->vp_strvalue;
690 nvp_log(__LINE__, data, L_ERR,
691 "sqlhpwippool_accounting(): unique session ID not found");
692 return RLM_MODULE_FAIL;
695 vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE);
697 acct_type = vp->vp_integer;
700 nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_accounting(): "
701 "couldn't find type of accounting packet");
702 return RLM_MODULE_FAIL;
705 if (!(acct_type == PW_STATUS_START ||
706 acct_type == PW_STATUS_ALIVE ||
707 acct_type == PW_STATUS_STOP ||
708 acct_type == PW_STATUS_ACCOUNTING_OFF ||
709 acct_type == PW_STATUS_ACCOUNTING_ON)) {
710 return RLM_MODULE_NOOP;
713 /* connect to database */
714 sqlsock = sql_get_socket(data->sqlinst);
716 nvp_log(__LINE__, data, L_ERR,
717 "sqlhpwippool_accounting(): couldn't connect to database");
718 return RLM_MODULE_FAIL;
723 case PW_STATUS_START:
724 case PW_STATUS_ALIVE:
725 vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS);
727 nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_accounting(): no framed IP");
728 sql_release_socket(data->sqlinst, sqlsock);
729 return RLM_MODULE_FAIL;
732 framedip = ntohl(vp->vp_ipaddr);
734 if (!nvp_query(__LINE__, data, sqlsock,
740 data->db_name, sessid, framedip)) {
741 sql_release_socket(data->sqlinst, sqlsock);
742 return RLM_MODULE_FAIL;
744 nvp_finish(data, sqlsock);
748 if (!nvp_query(__LINE__, data, sqlsock,
749 "UPDATE `%s`.`ips`, `%1$s`.`ip_pools` "
751 "`ips`.`rsv_until` = NOW() + INTERVAL %u SECOND, "
752 "`ip_pools`.`free` = `ip_pools`.`free` + 1 "
754 "`ips`.`rsv_by` = '%s' AND "
755 "`ips`.`ip` BETWEEN `ip_pools`.`ip_start` AND `ip_pools`.`ip_stop`",
756 data->db_name, data->freeafter, sessid)) {
757 sql_release_socket(data->sqlinst, sqlsock);
758 return RLM_MODULE_FAIL;
760 nvp_finish(data, sqlsock);
763 case PW_STATUS_ACCOUNTING_OFF:
764 case PW_STATUS_ACCOUNTING_ON:
765 vp = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS);
767 nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_accounting(): no NAS IP");
768 sql_release_socket(data->sqlinst, sqlsock);
769 return RLM_MODULE_FAIL;
772 nasip.s_addr = vp->vp_ipaddr;
773 strncpy(nasipstr, inet_ntoa(nasip), sizeof(nasipstr) - 1);
774 nasipstr[sizeof(nasipstr)] = 0;
776 if (!nvp_query(__LINE__, data, sqlsock,
777 "UPDATE `%s`.`ips`, `radacct` "
778 "SET `ips`.`rsv_until` = NOW() + INTERVAL %u SECOND "
780 "`radacct`.`nasipaddress` = '%s' AND "
781 "`ips`.`rsv_by` = `radacct`.`acctuniqueid`",
782 data->db_name, data->freeafter, nasipstr)) {
783 sql_release_socket(data->sqlinst, sqlsock);
784 return RLM_MODULE_FAIL;
786 nvp_finish(data, sqlsock);
791 sql_release_socket(data->sqlinst, sqlsock);
792 return RLM_MODULE_OK;
795 module_t rlm_sqlhpwippool = {
797 "sqlhpwippool", /* name */
798 RLM_TYPE_THREAD_SAFE, /* type */
799 sqlhpwippool_instantiate, /* instantiation */
800 sqlhpwippool_detach, /* detach */
802 NULL, /* authentication */
803 NULL, /* authorization */
804 NULL, /* preaccounting */
805 sqlhpwippool_accounting,/* accounting */
806 NULL, /* checksimul */
807 NULL, /* pre-proxy */
808 NULL, /* post-proxy */
809 sqlhpwippool_postauth /* post-auth */