📄 rlm_sqlhpwippool.c
字号:
if (!sqlsock) { nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_postauth(): error while requesting an SQL socket"); return RLM_MODULE_FAIL; } /* get connection id as temporary unique integer */ if (nvp_select(__LINE__, data, sqlsock, "SELECT CONNECTION_ID()") < 1) { nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_postauth(): WTF ;-)!"); nvp_select_finish(data, sqlsock); sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } connid = strtoul(sqlsock->row[0], (char **) NULL, 10); nvp_select_finish(data, sqlsock); /* synchronize with radacct db, if needed */ if (++data->sincesync >= data->syncafter#ifdef HAVE_PTHREAD_D && (pthread_mutex_trylock(&data->mutex)) == 0#endif ) { int r; data->sincesync = 0; nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): syncing with radacct table"); r = (nvp_freeclosed(data, sqlsock) && nvp_syncfree(data, sqlsock));#ifdef HAVE_PTHREAD_D pthread_mutex_unlock(&data->mutex);#endif if (!r) { nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_postauth(): synchronization failed"); sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } } for (s_gid = 0; s_gid < RLM_NETVIM_MAX_ROWS && !(ip.s_addr); s_gid++) { nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): selecting gid on position %lu", s_gid); /* find the most specific group which NAS belongs to */ switch (nvp_select(__LINE__, data, sqlsock, "SELECT `host_groups`.`gid` " "FROM " "`%s`.`host_groups`, " "`%1$s`.`gid_ip`, " "`%1$s`.`ids` " "WHERE " "`host_groups`.`gid` = `ids`.`id` AND " "`ids`.`enabled` = 1 AND " "`host_groups`.`gid` = `gid_ip`.`gid` AND " "%lu BETWEEN `gid_ip`.`ip_start` AND `gid_ip`.`ip_stop` " "ORDER BY (`gid_ip`.`ip_stop` - `gid_ip`.`ip_start`) ASC " "LIMIT %lu, 1", data->db_name, nasip, s_gid)) { case -1: nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_postauth(): couldn't find " "any more matching host groups"); goto end_gid; /* exit the main loop */ case 0: sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } /* store the group ID and free memory occupied by results */ gid = strtoul(sqlsock->row[0], (char **) NULL, 10); nvp_select_finish(data, sqlsock); for (s_prio = 0; s_prio < RLM_NETVIM_MAX_ROWS && !(ip.s_addr); s_prio++) { nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): selecting prio on position %lu", s_prio); /* prepare to search for best fit pool */ switch (nvp_select(__LINE__, data, sqlsock, "SELECT " "`ip_pools`.`prio`, " "SUM(`ip_pools`.`weight`) AS `weights_sum`, " "(SUM(`ip_pools`.`total`) - " "SUM(`ip_pools`.`free`)) AS `used_sum` " "FROM " "`%s`.`ip_pools`, " "`%1$s`.`ids`, " "`%1$s`.`pool_names` " "WHERE " "`ip_pools`.`gid` = %lu AND " "`ids`.`id` = `ip_pools`.`pid` AND " "`ids`.`enabled` = 1 AND " "`pool_names`.`pnid` = `ip_pools`.`pnid` AND " "`pool_names`.`name` = '%s' AND " "`ip_pools`.`free` > 0 " "GROUP BY `prio` " "ORDER BY `prio` ASC " "LIMIT %lu, 1", data->db_name, gid, pname, s_prio)) { case -1: nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): couldn't find " "any more matching pools for gid = %u", gid); goto end_prio; /* select next gid */ case 0: sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } /* store the prio and weights sum */ prio = strtol(sqlsock->row[0], (char **) NULL, 10); weights_sum = strtoul(sqlsock->row[1], (char **) NULL, 10); used_sum = strtoul(sqlsock->row[2], (char **) NULL, 10); /* free memory */ nvp_select_finish(data, sqlsock); for (s_pid = 0; s_pid < RLM_NETVIM_MAX_ROWS && !(ip.s_addr); s_pid++) { nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): selecting PID on position %lu", s_pid); /* search for best fit pool */ switch (nvp_select(__LINE__, data, sqlsock, "SELECT " "`ip_pools`.`pid`, " "`ip_pools`.`ip_start`, " "`ip_pools`.`ip_stop` " "FROM " "`%s`.`ip_pools`, " "`%1$s`.`ids`, " "`%1$s`.`pool_names` " "WHERE " "`ip_pools`.`gid` = %lu AND " "`ids`.`id` = `ip_pools`.`pid` AND " "`ids`.`enabled` = 1 AND " "`pool_names`.`pnid` = `ip_pools`.`pnid` AND " "`pool_names`.`name` = '%s' AND " "`ip_pools`.`free` > 0 AND " "`prio` = %ld " "ORDER BY (`weight`/%lu.0000 - (`total` - `free`)/%lu) DESC " "LIMIT %lu, 1", data->db_name, gid, pname, prio, weights_sum, used_sum, s_pid)) { case -1: nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): couldn't find any more " "matching pools of prio = %ld for gid = %lu", prio, gid); goto end_pid; /* select next prio */ case 0: sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } /* store the data and free memory occupied by results */ pid = strtoul(sqlsock->row[0], (char **) NULL, 10); ip_start = strtoul(sqlsock->row[1], (char **) NULL, 10); ip_stop = strtoul(sqlsock->row[2], (char **) NULL, 10); nvp_select_finish(data, sqlsock); /* reserve an IP address */ if (!nvp_query(__LINE__, data, sqlsock, "UPDATE `%s`.`ips` " "SET " "`pid` = %lu, " "`rsv_since` = NOW(), " "`rsv_by` = '" RLM_NETVIM_TMP_PREFIX "%lu', " "`rsv_until` = NOW() + INTERVAL %d SECOND " "WHERE " "`ip` BETWEEN %lu AND %lu AND " "(" "`pid` IS NULL OR " "(`rsv_until` > 0 AND `rsv_until` < NOW())" ") " "ORDER BY RAND() " "LIMIT 1", data->db_name, pid, connid, data->freeafter, ip_start, ip_stop)) { sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } else { nvp_finish(data, sqlsock); } /* select assigned IP address */ switch (nvp_select(__LINE__, data, sqlsock, "SELECT `ip` " "FROM `%s`.`ips` " "WHERE `rsv_by` = '" RLM_NETVIM_TMP_PREFIX "%lu' " "ORDER BY `rsv_since` DESC " "LIMIT 1", data->db_name, connid)) { case -1: nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_postauth(): couldn't reserve an IP address " "from pool of pid = %lu (prio = %ld, gid = %lu)", pid, prio, gid); continue; /* select next pid */ case 0: sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } /* update free IPs count */ if (!nvp_query(__LINE__, data, sqlsock, "UPDATE `%s`.`ip_pools` " "SET " "`free` = `free` - 1 " "WHERE " "`pid` = %lu " "LIMIT 1", data->db_name, pid)) { sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } else { nvp_finish(data, sqlsock); } /* get assigned IP and free memory */ ip.s_addr = htonl(strtoul(sqlsock->row[0], (char **) NULL, 10)); nvp_select_finish(data, sqlsock); } /* pid */end_pid: continue; /* stupid */ } /* prio */end_prio: continue; /* stupid */ } /* gid */end_gid: /* release SQL socket */ sql_release_socket(data->sqlinst, sqlsock); /* no free IP address found */ if (!ip.s_addr) { nvp_log(__LINE__, data, L_INFO, "sqlhpwippool_postauth(): no free IP address found!"); if (data->nofreefail) { nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): rejecting user"); return RLM_MODULE_REJECT; } else { nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): exiting"); return RLM_MODULE_NOOP; } } /* add IP address to reply packet */ vp = radius_paircreate(request, &request->reply->vps, PW_FRAMED_IP_ADDRESS, PW_TYPE_IPADDR); vp->vp_ipaddr = ip.s_addr; nvp_log(__LINE__, data, L_DBG, "sqlhpwippool_postauth(): returning %s", inet_ntoa(ip)); return RLM_MODULE_OK;}static int sqlhpwippool_accounting(void *instance, REQUEST *request){ VALUE_PAIR *vp; SQLSOCK *sqlsock; struct in_addr nasip; /* NAS IP */ unsigned char *sessid; /* unique session id */ char nasipstr[16]; /* NAS IP in string format */ uint32_t framedip = 0; /* client's IP, host byte order */ uint32_t acct_type; rlm_sqlhpwippool_t *data = (rlm_sqlhpwippool_t *) instance; /* if no unique session ID, don't even try */ vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID); if (vp) { sessid = vp->vp_strvalue; } else { nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_accounting(): unique session ID not found"); return RLM_MODULE_FAIL; } vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE); if (vp) { acct_type = vp->vp_integer; } else { nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_accounting(): " "couldn't find type of accounting packet"); return RLM_MODULE_FAIL; } if (!(acct_type == PW_STATUS_START || acct_type == PW_STATUS_ALIVE || acct_type == PW_STATUS_STOP || acct_type == PW_STATUS_ACCOUNTING_OFF || acct_type == PW_STATUS_ACCOUNTING_ON)) { return RLM_MODULE_NOOP; } /* connect to database */ sqlsock = sql_get_socket(data->sqlinst); if (!sqlsock) { nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_accounting(): couldn't connect to database"); return RLM_MODULE_FAIL; } switch (acct_type) { case PW_STATUS_START: case PW_STATUS_ALIVE: vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS); if (!vp) { nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_accounting(): no framed IP"); sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } framedip = ntohl(vp->vp_ipaddr); if (!nvp_query(__LINE__, data, sqlsock, "UPDATE `%s`.`ips` " "SET " "`rsv_until` = 0, " "`rsv_by` = '%s' " "WHERE `ip` = %lu", data->db_name, sessid, framedip)) { sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } nvp_finish(data, sqlsock); break; case PW_STATUS_STOP: if (!nvp_query(__LINE__, data, sqlsock, "UPDATE `%s`.`ips`, `%1$s`.`ip_pools` " "SET " "`ips`.`rsv_until` = NOW() + INTERVAL %u SECOND, " "`ip_pools`.`free` = `ip_pools`.`free` + 1 " "WHERE " "`ips`.`rsv_by` = '%s' AND " "`ips`.`ip` BETWEEN `ip_pools`.`ip_start` AND `ip_pools`.`ip_stop`", data->db_name, data->freeafter, sessid)) { sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } nvp_finish(data, sqlsock); break; case PW_STATUS_ACCOUNTING_OFF: case PW_STATUS_ACCOUNTING_ON: vp = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS); if (!vp) { nvp_log(__LINE__, data, L_ERR, "sqlhpwippool_accounting(): no NAS IP"); sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } nasip.s_addr = vp->vp_ipaddr; strncpy(nasipstr, inet_ntoa(nasip), sizeof(nasipstr) - 1); nasipstr[sizeof(nasipstr)] = 0; if (!nvp_query(__LINE__, data, sqlsock, "UPDATE `%s`.`ips`, `radacct` " "SET `ips`.`rsv_until` = NOW() + INTERVAL %u SECOND " "WHERE " "`radacct`.`nasipaddress` = '%s' AND " "`ips`.`rsv_by` = `radacct`.`acctuniqueid`", data->db_name, data->freeafter, nasipstr)) { sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_FAIL; } nvp_finish(data, sqlsock); break; } sql_release_socket(data->sqlinst, sqlsock); return RLM_MODULE_OK;}module_t rlm_sqlhpwippool = { RLM_MODULE_INIT, "sqlhpwippool", /* name */ RLM_TYPE_THREAD_SAFE, /* type */ sqlhpwippool_instantiate, /* instantiation */ sqlhpwippool_detach, /* detach */ { NULL, /* authentication */ NULL, /* authorization */ NULL, /* preaccounting */ sqlhpwippool_accounting,/* accounting */ NULL, /* checksimul */ NULL, /* pre-proxy */ NULL, /* post-proxy */ sqlhpwippool_postauth /* post-auth */ },};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -