Hi there:
Didnt know if this would fit in freeradius-devel, so I just got Paul's
email (from June 19th) and hit "reply to all" :)
I needed this module functionality so badly that I coded ippool_postauth
and ippool_accounting following the algorithm he proposed. MPP detection
is not implemented, as I'm not sure to understand it well enough, and
there could be something we've missed, like what happens when there's
no caller-id attr..
It's been working for a week or so in production here with just one
realm (but planning to make it general, as soon as I have time to
migrate the user db) and it's doing a pretty good job so far. So
I decided to expose myself to public shame by posting a patch against
the current (as of July 2nd, 2003) CVS source tree.
Have mercy.. They say some things you never forget, but it's my first
non-trivial hack in years :)
Cheers,
Jon
diff -urN radiusd/src/modules/rlm_ippool/rlm_ippool.c new.radiusd/src/modules/rlm_ippool/rlm_ippool.c
--- radiusd/src/modules/rlm_ippool/rlm_ippool.c 2003-06-20 19:50:10.000000000 +0200
+++ new.radiusd/src/modules/rlm_ippool/rlm_ippool.c 2003-07-02 23:08:02.000000000 +0200
@@ -66,6 +66,7 @@
#endif
#define MAX_NAS_NAME_SIZE 64
+#define MAX_CLI_SIZE 32
static const char rcsid[] = "$Id: rlm_ippool.c,v 1.20 2003/06/20 17:50:10 phampson Exp $";
@@ -78,23 +79,66 @@
*/
typedef struct rlm_ippool_t {
char *session_db;
- char *ip_index;
+ char *ipindex_db;
+ char *callerid_db;
char *name;
uint32_t range_start;
uint32_t range_stop;
uint32_t netmask;
int cache_size;
int override;
- GDBM_FILE gdbm;
- GDBM_FILE ip;
- pthread_mutex_t session_mutex;
- pthread_mutex_t ip_mutex;
+ GDBM_FILE gsession_db;
+ GDBM_FILE gipindex_db;
+ GDBM_FILE gcallerid_db;
+ pthread_mutex_t mutex;
} rlm_ippool_t;
+/*
+ * session-db:
+ * [cli,nas] -> (ipaddr,port)
+ */
+typedef struct session_entry {
+ uint32_t ipaddr;
+} session_entry;
+
+typedef struct session_key {
+ char nas[MAX_NAS_NAME_SIZE];
+ unsigned int port;
+} session_key;
+
+/*
+ * ipindex-db:
+ * [ipaddr] -> (cli,nas,active)
+ */
+typedef struct ipindex_entry {
+ char cli[MAX_CLI_SIZE];
+ char nas[MAX_NAS_NAME_SIZE];
+ char active;
+} ipindex_entry;
+
+typedef struct ipindex_key {
+ uint32_t ipaddr;
+} ipindex_key;
+
+/*
+ * callerid-db:
+ * [cli,nas] -> (ipaddr,usage)
+ */
+typedef struct callerid_entry {
+ uint32_t ipaddr;
+ char usage;
+} callerid_entry;
+
+typedef struct callerid_key {
+ char cli[MAX_CLI_SIZE];
+ char nas[MAX_NAS_NAME_SIZE];
+} callerid_key;
+
+/* old structs */
typedef struct ippool_info {
uint32_t ipaddr;
char active;
- char cli[32];
+ char cli[MAX_CLI_SIZE];
} ippool_info;
typedef struct ippool_key {
@@ -113,7 +157,8 @@
*/
static CONF_PARSER module_config[] = {
{ "session-db", PW_TYPE_STRING_PTR, offsetof(rlm_ippool_t,session_db), NULL, NULL },
- { "ip-index", PW_TYPE_STRING_PTR, offsetof(rlm_ippool_t,ip_index), NULL, NULL },
+ { "ipindex-db", PW_TYPE_STRING_PTR, offsetof(rlm_ippool_t,ipindex_db), NULL, NULL },
+ { "callerid-db", PW_TYPE_STRING_PTR, offsetof(rlm_ippool_t,callerid_db), NULL, NULL },
{ "range-start", PW_TYPE_IPADDR, offsetof(rlm_ippool_t,range_start), NULL, "0" },
{ "range-stop", PW_TYPE_IPADDR, offsetof(rlm_ippool_t,range_stop), NULL, "0" },
{ "netmask", PW_TYPE_IPADDR, offsetof(rlm_ippool_t,netmask), NULL, "0" },
@@ -137,8 +182,12 @@
{
rlm_ippool_t *data;
int cache_size;
+ ipindex_entry entry;
+ ipindex_key key;
+ /*
ippool_info entry;
ippool_key key;
+ */
datum key_datum;
datum data_datum;
int i;
@@ -166,11 +215,16 @@
free(data);
return -1;
}
- if (data->ip_index == NULL) {
+ if (data->ipindex_db == NULL) {
radlog(L_ERR, "rlm_ippool: 'ip-index' must be set.");
free(data);
return -1;
}
+ if (data->callerid_db == NULL) {
+ radlog(L_ERR, "rlm_ippool: 'callerid-db' must be set.");
+ free(data);
+ return -1;
+ }
data->range_start = htonl(data->range_start);
data->range_stop = htonl(data->range_stop);
data->netmask = htonl(data->netmask);
@@ -181,36 +235,48 @@
return -1;
}
- data->gdbm = gdbm_open(data->session_db, sizeof(int),
+ data->gsession_db = gdbm_open(data->session_db, sizeof(int),
GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);
- if (data->gdbm == NULL) {
+ if (data->gsession_db == NULL) {
radlog(L_ERR, "rlm_ippool: Failed to open file %s: %s",
data->session_db, strerror(errno));
return -1;
}
- data->ip = gdbm_open(data->ip_index, sizeof(int),
+ data->gipindex_db = gdbm_open(data->ipindex_db, sizeof(int),
+ GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);
+ if (data->gipindex_db == NULL) {
+ radlog(L_ERR, "rlm_ippool: Failed to open file %s: %s",
+ data->ipindex_db, strerror(errno));
+ return -1;
+ }
+ data->gcallerid_db = gdbm_open(data->callerid_db, sizeof(int),
GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);
- if (data->ip == NULL) {
+ if (data->gcallerid_db == NULL) {
radlog(L_ERR, "rlm_ippool: Failed to open file %s: %s",
- data->ip_index, strerror(errno));
+ data->callerid_db, strerror(errno));
return -1;
}
- if (gdbm_setopt(data->gdbm, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1)
+ if (gdbm_setopt(data->gsession_db, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1)
radlog(L_ERR, "rlm_ippool: Failed to set cache size");
- if (gdbm_setopt(data->ip, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1)
+ if (gdbm_setopt(data->gipindex_db, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1)
+ radlog(L_ERR, "rlm_ippool: Failed to set cache size");
+ if (gdbm_setopt(data->gcallerid_db, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1)
radlog(L_ERR, "rlm_ippool: Failed to set cache size");
- key_datum = gdbm_firstkey(data->gdbm);
+ key_datum = gdbm_firstkey(data->gipindex_db);
if (key_datum.dptr == NULL){
/*
* If the database does not exist initialize it.
- * We set the nas/port pairs to not existent values and
+ * We set all data to zero/null
+ * cli = ""
+ * nas = ""
* active = 0
*/
int rcode;
uint32_t or_result;
char str[32];
const char *nas_init = "NOT_EXIST";
+ /* const char *cli_init = "NONE"; */
DEBUG("rlm_ippool: Initializing database");
for(i=data->range_start,j=~0;i<=data->range_stop;i++,j--){
@@ -227,25 +293,24 @@
continue;
}
- strcpy(key.nas, nas_init);
- key.port = j;
+ key.ipaddr = ntohl(i);
key_datum.dptr = (char *) &key;
- key_datum.dsize = sizeof(ippool_key);
+ key_datum.dsize = sizeof(ipindex_key);
- entry.ipaddr = ntohl(i);
- entry.active = 0;
strcpy(entry.cli,cli);
-
+ strcpy(entry.nas,nas_init);
+ entry.active = 0;
data_datum.dptr = (char *) &entry;
- data_datum.dsize = sizeof(ippool_info);
+ data_datum.dsize = sizeof(ipindex_entry);
- rcode = gdbm_store(data->gdbm, key_datum, data_datum, GDBM_REPLACE);
+ rcode = gdbm_store(data->gipindex_db, key_datum, data_datum, GDBM_REPLACE);
if (rcode < 0) {
radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
- data->session_db, gdbm_strerror(gdbm_errno));
+ data->ipindex_db, gdbm_strerror(gdbm_errno));
free(data);
- gdbm_close(data->gdbm);
- gdbm_close(data->ip);
+ gdbm_close(data->gsession_db);
+ gdbm_close(data->gipindex_db);
+ gdbm_close(data->gcallerid_db);
return -1;
}
}
@@ -258,8 +323,7 @@
pool_name = cf_section_name2(conf);
if (pool_name != NULL)
data->name = strdup(pool_name);
- pthread_mutex_init(&data->session_mutex, NULL);
- pthread_mutex_init(&data->ip_mutex, NULL);
+ pthread_mutex_init(&data->mutex, NULL);
*instance = data;
@@ -276,17 +340,24 @@
rlm_ippool_t *data = (rlm_ippool_t *)instance;
datum key_datum;
datum data_datum;
+ callerid_entry cli_entry;
+ callerid_key cli_key;
+ session_entry ses_entry;
+ session_key ses_key;
+ ipindex_entry ipi_entry;
+ ipindex_key ipi_key;
+ uint32_t ipaddr = 0;
int acctstatustype = 0;
unsigned int port = ~0;
int rcode;
char nas[MAX_NAS_NAME_SIZE];
- ippool_info entry;
- ippool_key key;
- int num = 0;
+ char cli[MAX_CLI_SIZE];
VALUE_PAIR *vp;
char str[32];
+
+
if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) != NULL)
acctstatustype = vp->lvalue;
else {
@@ -311,75 +382,161 @@
return RLM_MODULE_NOOP;
}
}
+ /* Get user ip address */
+ if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS)) != NULL) {
+ /* XXX ntoh? */
+ ipaddr = vp->lvalue;
+ DEBUG2("rlm_ippool: pairfind framed ip address: %s", ip_ntoa(str,ipaddr));
+ }
+ /* Get Caller Id */
+ if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL) {
+ strncpy(cli, vp->strvalue, MAX_CLI_SIZE -1 );
+ DEBUG2("rlm_ippool: pairfind caller id: %s", cli);
+ }
break;
default:
/* We don't care about any other accounting packet */
-
return RLM_MODULE_NOOP;
}
- memset(key.nas,0,MAX_NAS_NAME_SIZE);
- strncpy(key.nas,nas,MAX_NAS_NAME_SIZE -1 );
- key.port = port;
- DEBUG("rlm_ippool: Searching for an entry for nas/port: %s/%u",key.nas,key.port);
- key_datum.dptr = (char *) &key;
- key_datum.dsize = sizeof(ippool_key);
-
- pthread_mutex_lock(&data->session_mutex);
- data_datum = gdbm_fetch(data->gdbm, key_datum);
- pthread_mutex_unlock(&data->session_mutex);
- if (data_datum.dptr != NULL){
+ /* valid data so far:
+ * nas, port, (ipaddr?, cli?)
+ */
+ pthread_mutex_lock(&data->mutex);
- /*
- * If the entry was found set active to zero
- */
- memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
+ /* Get ip and delete session from session_db */
+ memset(&ses_key,0,sizeof(session_key));
+ strncpy(ses_key.nas, nas, MAX_NAS_NAME_SIZE -1);
+ ses_key.port = port;
+
+ key_datum.dptr = (char*)&ses_key;
+ key_datum.dsize = sizeof(session_key);
+
+ data_datum = gdbm_fetch(data->gsession_db, key_datum);
+
+ if (data_datum.dptr != NULL) {
+ memcpy(&ses_entry, data_datum.dptr, sizeof(session_entry));
free(data_datum.dptr);
- DEBUG("rlm_ippool: Deallocated entry for ip/port: %s/%u",ip_ntoa(str,entry.ipaddr),port);
- entry.active = 0;
- data_datum.dptr = (char *) &entry;
- data_datum.dsize = sizeof(ippool_info);
+ ipaddr = ses_entry.ipaddr;
+
+ DEBUG("rlm_ippool: Deallocated session entry for nas/port: %s/%u",nas,port);
+ gdbm_delete(data->gsession_db, key_datum);
+ } else {
+ if ( ipaddr == 0 ) {
+ /* Couldnt get user ip address
+ * Cant go on */
+
+ radlog(L_ERR, "rlm_ippool: Cannot find out IP address either in database or attr list.");
+ pthread_mutex_unlock(&data->mutex);
+ return RLM_MODULE_FAIL;
+ } else {
+ DEBUG("rlm_ippool: IP address not found in %s. Using %s from attr list...",
+ data->session_db, ip_ntoa(str, ipaddr));
+ }
+ }
+
+ /* add to valid data: ipaddr */
+
+ /* Lookup ip; get oldCLI */
+ /* not needed: memset(ipi_key,0,sizeof(ipindex_key)); */
+ ipi_key.ipaddr = ipaddr;
+
+ key_datum.dptr = (char*)&ipi_key;
+ key_datum.dsize = sizeof(ipindex_key);
+ data_datum = gdbm_fetch(data->gipindex_db, key_datum);
+
+ if (data_datum.dptr == NULL) {
+ if ( cli[0] == '\0' ) {
+ /* Couldnt get cli
+ * Cant go on */
+ radlog(L_ERR, "rlm_ippool: Cannot find out callerid either in %s or attr list.",
+ data->ipindex_db);
+ pthread_mutex_unlock(&data->mutex);
+ return RLM_MODULE_FAIL;
+ } else {
+ radlog(L_INFO, "rlm_ippool: Callerid not found in %s. Using %s from attr list...",
+ data->ipindex_db, cli);
+ /* XXX this shouldnt normally happen */
+ }
+ } else {
+ memcpy(&ipi_entry, data_datum.dptr, sizeof(ipindex_entry));
+ free(data_datum.dptr);
+
+ strncpy(cli, ipi_entry.cli, MAX_CLI_SIZE - 1);
+ }
+
+ /* add to valid data: cli */
+
+ /* lookup callerid in callerid_db */
+ memset(&cli_key, 0, sizeof(callerid_key));
+ strncpy(cli_key.cli, cli, MAX_CLI_SIZE - 1 );
+ strncpy(cli_key.nas, nas, MAX_NAS_NAME_SIZE - 1 );
+ key_datum.dptr = (char*)&cli_key;
+ key_datum.dsize = sizeof(callerid_key);
+ data_datum = gdbm_fetch(data->gcallerid_db, key_datum);
+ if (data_datum.dptr != NULL) {
+ memcpy(&cli_entry, data_datum.dptr, sizeof(callerid_entry));
+ free(data_datum.dptr);
+
+ cli_entry.usage--;
+ if (cli_entry.usage == 0) {
+ /* No longer used, delete entry */
+ DEBUG("rlm_ippool: Deleting no longer used entry in %s",
+ data->callerid_db);
+ gdbm_delete(data->gcallerid_db, key_datum);
+ }
- pthread_mutex_lock(&data->session_mutex);
- rcode = gdbm_store(data->gdbm, key_datum, data_datum, GDBM_REPLACE);
- pthread_mutex_unlock(&data->session_mutex);
+ } else {
+ /* Nothing we can do with callerid_db, but
+ * we can fake it so ip address in ipindex is marked as inactive */
+ /* XXX Is it always the Right Thing(tm) to do? */
+ cli_entry.usage = 0;
+ }
+
+ if (cli_entry.usage == 0) {
+
+ /* Mark ip inactive */
+ /* (refill all data just in case there was no entry,
+ * which shouldnt happen, anyway) */
+ ipi_key.ipaddr = ipaddr;
+ memset( &ipi_entry, 0, sizeof(ipi_entry));
+ strncpy( ipi_entry.cli, cli, MAX_CLI_SIZE -1 );
+ strncpy( ipi_entry.nas, nas, MAX_NAS_NAME_SIZE - 1 );
+ ipi_entry.active = 0;
+
+ key_datum.dptr = (char*)&ipi_key;
+ key_datum.dsize = sizeof(ipindex_key);
+ data_datum.dptr = (char*)&ipi_entry;
+ data_datum.dsize = sizeof(ipindex_entry);
+
+ DEBUG("rlm_ippool: Marking %s as inactive in %s",
+ ip_ntoa(str, ipaddr), data->ipindex_db);
+ rcode = gdbm_store(data->gipindex_db, key_datum, data_datum, GDBM_REPLACE);
if (rcode < 0) {
- radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
- data->session_db, gdbm_strerror(gdbm_errno));
+ radlog(L_ERR, "rlm_ippool: Failed storing data to %s while marking ip as inactive: %s",
+ data->ipindex_db, gdbm_strerror(gdbm_errno));
+ pthread_mutex_unlock(&data->mutex);
return RLM_MODULE_FAIL;
}
- /*
- * Decrease allocated count from the ip index
- */
- key_datum.dptr = (char *) &entry.ipaddr;
- key_datum.dsize = sizeof(uint32_t);
- pthread_mutex_lock(&data->ip_mutex);
- data_datum = gdbm_fetch(data->ip, key_datum);
- pthread_mutex_unlock(&data->ip_mutex);
- if (data_datum.dptr != NULL){
- memcpy(&num, data_datum.dptr, sizeof(int));
- free(data_datum.dptr);
- if (num >0){
- num--;
- DEBUG("rlm_ippool: num: %d",num);
- data_datum.dptr = (char *) #
- data_datum.dsize = sizeof(int);
- pthread_mutex_lock(&data->ip_mutex);
- rcode = gdbm_store(data->ip, key_datum, data_datum, GDBM_REPLACE);
- pthread_mutex_unlock(&data->ip_mutex);
- if (rcode < 0) {
- radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
- data->ip_index, gdbm_strerror(gdbm_errno));
- return RLM_MODULE_FAIL;
- }
- }
+ } else {
+ key_datum.dptr = (char*)&cli_key;
+ key_datum.dsize = sizeof(callerid_key);
+ data_datum.dptr = (char*)&cli_entry;
+ data_datum.dsize = sizeof(callerid_entry);
+ DEBUG("rlm_ippool: Updating ip %s usage to %d in %s",
+ ip_ntoa(str, ipaddr), cli_entry.usage, data->ipindex_db);
+ rcode = gdbm_store(data->gcallerid_db, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ radlog(L_ERR, "rlm_ippool: Failed storing data to %s while updating ip usage: %s",
+ data->callerid_db, gdbm_strerror(gdbm_errno));
+ pthread_mutex_unlock(&data->mutex);
+ return RLM_MODULE_FAIL;
}
}
- else
- DEBUG("rlm_ippool: Entry not found");
+ pthread_mutex_unlock(&data->mutex);
return RLM_MODULE_OK;
}
@@ -387,17 +544,24 @@
{
rlm_ippool_t *data = (rlm_ippool_t *) instance;
unsigned int port = 0;
- int delete = 0;
+ /* int delete = 0; */
int rcode;
- int num = 0;
+ /* int num = 0; */
char nas[MAX_NAS_NAME_SIZE];
datum key_datum;
- datum nextkey;
datum data_datum;
- ippool_key key;
- ippool_info entry;
+ datum nextkey;
+
+ callerid_entry cli_entry;
+ callerid_key cli_key;
+ session_entry ses_entry;
+ session_key ses_key;
+ ipindex_entry ipi_entry;
+ ipindex_key ipi_key;
+
VALUE_PAIR *vp;
- char *cli = NULL;
+ /* char *cli = NULL; */
+ char cli[MAX_CLI_SIZE];;
char str[32];
@@ -435,7 +599,7 @@
* Find the caller id
*/
if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL)
- cli = vp->strvalue;
+ strncpy(cli, vp->strvalue, MAX_CLI_SIZE - 1);
/*
* Find the port
@@ -448,65 +612,126 @@
return RLM_MODULE_NOOP;
}
- memset(key.nas,0,MAX_NAS_NAME_SIZE);
- strncpy(key.nas,nas,MAX_NAS_NAME_SIZE -1 );
- key.port = port;
- DEBUG("rlm_ippool: Searching for an entry for nas/port: %s/%u",key.nas,key.port);
- key_datum.dptr = (char *) &key;
- key_datum.dsize = sizeof(ippool_key);
-
- pthread_mutex_lock(&data->session_mutex);
- data_datum = gdbm_fetch(data->gdbm, key_datum);
- pthread_mutex_unlock(&data->session_mutex);
- if (data_datum.dptr != NULL){
+ /* Valid data so far: cli, nas, port */
+
+ pthread_mutex_lock(&data->mutex);
+
+ /*
+ *
+ * CHECK STALE NAS/PORT
+ *
+ */
+ /* look it up in session_db */
+ memset(ses_key.nas,0,MAX_NAS_NAME_SIZE);
+ strncpy(ses_key.nas,nas,MAX_NAS_NAME_SIZE -1 );
+ ses_key.port = port;
+
+ DEBUG("rlm_ippool: Searching for an entry for nas/port: %s/%u",ses_key.nas,ses_key.port);
+ key_datum.dptr = (char *) &ses_key;
+ key_datum.dsize = sizeof(session_key);
+
+ data_datum = gdbm_fetch(data->gsession_db, key_datum);
+ if (data_datum.dptr != NULL) {
+ memcpy(&ses_entry, data_datum.dptr, sizeof(session_entry));
+ free(data_datum.dptr);
+
+ /* Valid data so far:
+ * ses_entry(stale entry),
+ * cli, nas, port */
+
/*
- * If there is a corresponding entry in the database with active=1 it is stale.
- * Set active to zero
+ * If there is a corresponding entry in the database it is stale.
+ * Delete it, decrement (and maybe delete) ip usage in callerid_db
+ * and set inactive entry in ipindex_db
*/
- memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
- free(data_datum.dptr);
- if (entry.active){
- DEBUG("rlm_ippool: Found a stale entry for ip/port: %s/%u",ip_ntoa(str,entry.ipaddr),port);
- entry.active = 0;
- data_datum.dptr = (char *) &entry;
- data_datum.dsize = sizeof(ippool_info);
+ DEBUG("rlm_ippool: Found a stale entry for ip/port: %s/%u",ip_ntoa(str,ses_entry.ipaddr),port);
- pthread_mutex_lock(&data->session_mutex);
- rcode = gdbm_store(data->gdbm, key_datum, data_datum, GDBM_REPLACE);
- pthread_mutex_unlock(&data->session_mutex);
- if (rcode < 0) {
- radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
- data->session_db, gdbm_strerror(gdbm_errno));
- return RLM_MODULE_FAIL;
- }
- /* Decrease allocated count from the ip index */
+ /* Delete stale entry in session_db */
+ gdbm_delete(data->gsession_db, key_datum);
+
+ /* Lookup ip in ipindex_db */
+ ipi_key.ipaddr = ses_entry.ipaddr;
+ key_datum.dptr = (char*) &ipi_key;
+ key_datum.dsize = sizeof(ipindex_key);
+ data_datum = gdbm_fetch(data->gipindex_db, key_datum);
+
+ if ( data_datum.dptr == NULL ) {
+
+ /* Valid data so far:
+ * ipi_key, ses_entry(stale entry),
+ * cli, nas, port */
+ /* XXX put more useful info */
+ radlog(L_ERR, "rlm_ippool: ip-index not found for %s deallocating stale session data",
+ ip_ntoa(str, ipi_key.ipaddr));
- key_datum.dptr = (char *) &entry.ipaddr;
- key_datum.dsize = sizeof(uint32_t);
- pthread_mutex_lock(&data->ip_mutex);
- data_datum = gdbm_fetch(data->ip, key_datum);
- pthread_mutex_unlock(&data->ip_mutex);
- if (data_datum.dptr != NULL){
- memcpy(&num, data_datum.dptr, sizeof(int));
+ } else {
+
+ /* Valid data so far:
+ * ipi_key, ipi_entry, ses_entry(stale entry),
+ * cli, nas, port */
+ memcpy(&ipi_entry, data_datum.dptr, sizeof(ipindex_entry));
+ free(data_datum.dptr);
+
+ memset( cli_key.cli,0,MAX_CLI_SIZE);
+ strncpy( cli_key.cli, ipi_entry.cli, MAX_CLI_SIZE -1);
+ memset( cli_key.nas,0,MAX_NAS_NAME_SIZE);
+ strncpy( cli_key.nas, ipi_entry.nas, MAX_NAS_NAME_SIZE - 1);
+ key_datum.dptr = (char*) &cli_key;
+ key_datum.dsize = sizeof(callerid_key);
+ data_datum = gdbm_fetch(data->gcallerid_db, key_datum);
+
+ if ( data_datum.dptr != NULL ) {
+
+ memcpy(&cli_entry, data_datum.dptr, sizeof(callerid_entry));
free(data_datum.dptr);
- if (num >0){
- num--;
- DEBUG("rlm_ippool: num: %d",num);
- data_datum.dptr = (char *) #
- data_datum.dsize = sizeof(int);
- pthread_mutex_lock(&data->ip_mutex);
- rcode = gdbm_store(data->ip, key_datum, data_datum, GDBM_REPLACE);
- pthread_mutex_unlock(&data->ip_mutex);
+
+ /* ipi_entry not found/retrieved */
+ if (cli_entry.usage == 1) {
+ /* Last use, so we can delete it */
+ DEBUG2("rlm_ippool: removing usage counter in %s for ip no longer used.",
+ data->callerid_db);
+ gdbm_delete(data->gcallerid_db, key_datum);
+ } else {
+ /* Update callerid_db.usage */
+ cli_entry.usage--;
+ data_datum.dptr = (char *)&cli_entry;
+ data_datum.dsize = sizeof(callerid_entry);
+ DEBUG2("rlm_ippool: updating ip usage counter to %u in %s.",
+ cli_entry.usage, data->callerid_db);
+ rcode = gdbm_store(data->gcallerid_db, key_datum, data_datum, GDBM_REPLACE);
if (rcode < 0) {
- radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
- data->ip_index, gdbm_strerror(gdbm_errno));
+ radlog(L_ERR, "rlm_ippool: Failed updating data to %s: %s",
+ data->callerid_db, gdbm_strerror(gdbm_errno));
+ pthread_mutex_unlock(&data->mutex);
+ return RLM_MODULE_FAIL;
+ }
+
+ /* Mark ipindex-db.ip as inactive */
+ ipi_entry.active = 0;
+ data_datum.dptr = (char *)&ipi_entry;
+ data_datum.dsize = sizeof(ipindex_entry);
+ key_datum.dptr = (char *)&ipi_key;
+ key_datum.dsize = sizeof(ipindex_key);
+ DEBUG2("rlm_ippool: Marking ip %s as inactive.",
+ ip_ntoa(str,ipi_key.ipaddr));
+ rcode = gdbm_store(data->gipindex_db, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ radlog(L_ERR, "rlm_ippool: Failed updating data to %s: %s",
+ data->ipindex_db, gdbm_strerror(gdbm_errno));
+ pthread_mutex_unlock(&data->mutex);
return RLM_MODULE_FAIL;
}
}
+
+ DEBUG("rlm_ippool: All stale session data succesfully removed");
}
- }
+ else {
+ radlog(L_INFO, "rlm_ippool: callerid for stale entry not found.");
+ }
+ }
}
+
/*
* If there is a Framed-IP-Address attribute in the reply, check for override
*/
@@ -522,163 +747,151 @@
}
/*
- * Walk through the database searching for an active=0 entry.
+ * Walk through ipindex_db searching for an active=0 entry.
*/
- pthread_mutex_lock(&data->session_mutex);
- key_datum = gdbm_firstkey(data->gdbm);
+ DEBUG("rlm_ippool: Walking thru ipindex database looking for an unused entry.");
+ key_datum = gdbm_firstkey(data->gipindex_db);
while(key_datum.dptr){
- data_datum = gdbm_fetch(data->gdbm, key_datum);
+ data_datum = gdbm_fetch(data->gipindex_db, key_datum);
if (data_datum.dptr){
- memcpy(&entry,data_datum.dptr, sizeof(ippool_info));
+ memcpy(&ipi_entry,data_datum.dptr, sizeof(ipindex_entry));
free(data_datum.dptr);
+ /* get key data available */
+ memcpy(&ipi_key,key_datum.dptr, sizeof(ipindex_key));
+
/*
- * If we find an entry for the same caller-id and nas with active=1
- * then we use that for multilink (MPPP) to work properly.
- */
- if (cli != NULL && strcmp(entry.cli,cli) == 0 && entry.active){
- memcpy(&key,key_datum.dptr,sizeof(ippool_key));
- if (!strcmp(key.nas,nas))
- break;
- }
- if (entry.active == 0){
- datum tmp;
+ * data available so far:
+ * ipi_key, ipi_entry
+ */
+ if (ipi_entry.active == 0){
- tmp.dptr = (char *) &entry.ipaddr;
- tmp.dsize = sizeof(uint32_t);
- pthread_mutex_lock(&data->ip_mutex);
- data_datum = gdbm_fetch(data->ip, tmp);
- pthread_mutex_unlock(&data->ip_mutex);
+ /* Found available entry */
+ DEBUG2("rlm_ippool: Allocating ip %s to nas/port: %s/%u",ip_ntoa(str,ipi_key.ipaddr),nas,port);
- /*
- * If we find an entry in the ip index and the number is zero (meaning
- * that we haven't allocated the same ip address to another nas/port pair)
- * or if we don't find an entry then delete the session entry so
- * that we can change the key (nas/port)
- * Else we don't delete the session entry since we haven't yet deallocated the
- * corresponding ip address and we continue our search.
- */
+ /* Record cli, nas and active=1 */
+ memset( ipi_entry.cli,0,MAX_CLI_SIZE);
+ strncpy( ipi_entry.cli, cli, MAX_CLI_SIZE - 1);
+ memset( ipi_entry.nas,0,MAX_NAS_NAME_SIZE);
+ strncpy( ipi_entry.nas, nas, MAX_NAS_NAME_SIZE -1);
+ ipi_entry.active = 1;
+ data_datum.dptr = (char*) &ipi_entry;
+ data_datum.dsize = sizeof(ipindex_entry);
+ key_datum.dptr = (char*) &ipi_key;
+ key_datum.dsize = sizeof(ipindex_key);
- if (data_datum.dptr){
- memcpy(&num,data_datum.dptr, sizeof(int));
- free(data_datum.dptr);
- if (num == 0){
- delete = 1;
- break;
- }
+ rcode = gdbm_store(data->gipindex_db, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ radlog(L_ERR, "rlm_ippool: Failed updating data to %s: %s",
+ data->ipindex_db, gdbm_strerror(gdbm_errno));
+ pthread_mutex_unlock(&data->mutex);
+ return RLM_MODULE_FAIL;
}
- else{
- delete = 1;
- break;
+
+ /* Create entry in session_db */
+ memset(ses_key.nas,0,MAX_NAS_NAME_SIZE);
+ strncpy(ses_key.nas, nas, MAX_NAS_NAME_SIZE -1 );
+ ses_key.port = port;
+
+ ses_entry.ipaddr = ipi_key.ipaddr;
+
+ key_datum.dptr = (char*)&ses_key;
+ key_datum.dsize = sizeof(session_key);
+ data_datum.dptr = (char*)&ses_entry;
+ data_datum.dsize = sizeof(session_entry);
+
+ DEBUG2("rlm_ippool: Storing session (%s/%u) = %s.",
+ ses_key.nas, ses_key.port, ip_ntoa(str, ses_entry.ipaddr));
+ rcode = gdbm_store(data->gsession_db, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ radlog(L_ERR, "rlm_ippool: Failed updating data to %s: %s",
+ data->session_db, gdbm_strerror(gdbm_errno));
+ pthread_mutex_unlock(&data->mutex);
+ return RLM_MODULE_FAIL;
}
- }
- }
- nextkey = gdbm_nextkey(data->gdbm, key_datum);
- free(key_datum.dptr);
- key_datum = nextkey;
- }
- pthread_mutex_unlock(&data->session_mutex);
- /*
- * If we have found a free entry set active to 1 then add a Framed-IP-Address attribute to
- * the reply
- */
- if (key_datum.dptr){
- entry.active = 1;
- data_datum.dptr = (char *) &entry;
- data_datum.dsize = sizeof(ippool_info);
- if (delete){
- /*
- * Delete the entry so that we can change the key
- */
- pthread_mutex_lock(&data->session_mutex);
- gdbm_delete(data->gdbm, key_datum);
- pthread_mutex_unlock(&data->session_mutex);
- }
- free(key_datum.dptr);
- memset(key.nas,0,MAX_NAS_NAME_SIZE);
- strncpy(key.nas,nas,MAX_NAS_NAME_SIZE - 1);
- key.port = port;
- key_datum.dptr = (char *) &key;
- key_datum.dsize = sizeof(ippool_key);
-
- DEBUG2("rlm_ippool: Allocating ip to nas/port: %s/%u",key.nas,key.port);
- pthread_mutex_lock(&data->session_mutex);
- rcode = gdbm_store(data->gdbm, key_datum, data_datum, GDBM_REPLACE);
- pthread_mutex_unlock(&data->session_mutex);
- if (rcode < 0) {
- radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
- data->session_db, gdbm_strerror(gdbm_errno));
- return RLM_MODULE_FAIL;
- }
+ /* Update or create entry in callerid_db */
+ memset(&cli_key, 0, sizeof(callerid_key));
+ strncpy(cli_key.cli, cli, MAX_CLI_SIZE -1);
+ strncpy(cli_key.nas, nas, MAX_NAS_NAME_SIZE -1);
+ key_datum.dptr = (char *)&cli_key;
+ key_datum.dsize = sizeof(callerid_key);
+ data_datum = gdbm_fetch(data->gcallerid_db, key_datum);
+
+ if (data_datum.dptr == NULL) {
+ /* Creating a new entry */
+ cli_entry.ipaddr = ipi_key.ipaddr;
+ cli_entry.usage = 0;
+ } else {
+ /* Obtaining data */
+ memcpy(&cli_entry, data_datum.dptr, sizeof(callerid_entry));
+ free(data_datum.dptr);
+ }
+ cli_entry.usage ++;
- /* Increase the ip index count */
- key_datum.dptr = (char *) &entry.ipaddr;
- key_datum.dsize = sizeof(uint32_t);
- pthread_mutex_lock(&data->ip_mutex);
- data_datum = gdbm_fetch(data->ip, key_datum);
- pthread_mutex_unlock(&data->ip_mutex);
- if (data_datum.dptr){
- memcpy(&num,data_datum.dptr,sizeof(int));
- free(data_datum.dptr);
- }
- num++;
- DEBUG("rlm_ippool: num: %d",num);
- data_datum.dptr = (char *) #
- data_datum.dsize = sizeof(int);
- pthread_mutex_lock(&data->ip_mutex);
- rcode = gdbm_store(data->ip, key_datum, data_datum, GDBM_REPLACE);
- pthread_mutex_unlock(&data->ip_mutex);
- if (rcode < 0) {
- radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
- data->ip_index, gdbm_strerror(gdbm_errno));
- return RLM_MODULE_FAIL;
- }
-
+ data_datum.dptr = (char*)&cli_entry;
+ data_datum.dsize = sizeof(callerid_entry);
- DEBUG("rlm_ippool: Allocated ip %s to client on nas %s,port %u",ip_ntoa(str,entry.ipaddr),
- key.nas,port);
- if ((vp = paircreate(PW_FRAMED_IP_ADDRESS, PW_TYPE_IPADDR)) == NULL) {
- radlog(L_ERR|L_CONS, "no memory");
- return RLM_MODULE_NOOP;
- }
- vp->lvalue = entry.ipaddr;
- ip_ntoa(vp->strvalue, vp->lvalue);
- pairadd(&request->reply->vps, vp);
+ DEBUG2("rlm_ippool: Updating callerid db.");
+ rcode = gdbm_store(data->gcallerid_db, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ radlog(L_ERR, "rlm_ippool: Failed updating data to %s: %s",
+ data->callerid_db, gdbm_strerror(gdbm_errno));
+ pthread_mutex_unlock(&data->mutex);
+ return RLM_MODULE_FAIL;
+ }
- /*
- * If there is no Framed-Netmask attribute in the
- * reply, add one
- */
- if (pairfind(request->reply->vps, PW_FRAMED_IP_NETMASK) == NULL) {
- if ((vp = paircreate(PW_FRAMED_IP_NETMASK, PW_TYPE_IPADDR)) == NULL)
- radlog(L_ERR|L_CONS, "no memory");
- else {
- vp->lvalue = ntohl(data->netmask);
+ DEBUG("rlm_ippool: Allocated ip %s to client on nas %s,port %u",
+ ip_ntoa(str,ipi_key.ipaddr), nas,port);
+ if ((vp = paircreate(PW_FRAMED_IP_ADDRESS, PW_TYPE_IPADDR)) == NULL) {
+ radlog(L_ERR|L_CONS, "no memory");
+ return RLM_MODULE_NOOP;
+ }
+ vp->lvalue = ipi_key.ipaddr;
ip_ntoa(vp->strvalue, vp->lvalue);
pairadd(&request->reply->vps, vp);
+
+ /*
+ * If there is no Framed-Netmask attribute in the
+ * reply, add one
+ */
+ if (pairfind(request->reply->vps, PW_FRAMED_IP_NETMASK) == NULL) {
+ if ((vp = paircreate(PW_FRAMED_IP_NETMASK, PW_TYPE_IPADDR)) == NULL)
+ radlog(L_ERR|L_CONS, "no memory");
+ else {
+ vp->lvalue = ntohl(data->netmask);
+ ip_ntoa(vp->strvalue, vp->lvalue);
+ pairadd(&request->reply->vps, vp);
+ }
+ }
+ /* return ok */
+ pthread_mutex_unlock(&data->mutex);
+ return RLM_MODULE_OK;
}
}
-
- }
- else{
- DEBUG("rlm_ippool: No available ip addresses in pool.");
- return RLM_MODULE_NOOP;
+ nextkey = gdbm_nextkey(data->gipindex_db, key_datum);
+ free(key_datum.dptr);
+ key_datum = nextkey;
}
- return RLM_MODULE_OK;
+ pthread_mutex_unlock(&data->mutex);
+
+ DEBUG("rlm_ippool: No available ip addresses in pool.");
+ return RLM_MODULE_NOOP;
+
}
static int ippool_detach(void *instance)
{
rlm_ippool_t *data = (rlm_ippool_t *) instance;
- gdbm_close(data->gdbm);
- gdbm_close(data->ip);
- free(data->session_db);
- free(data->ip_index);
- pthread_mutex_destroy(&data->session_mutex);
- pthread_mutex_destroy(&data->ip_mutex);
+ gdbm_close(data->gsession_db);
+ gdbm_close(data->gipindex_db);
+ gdbm_close(data->gcallerid_db);
+ free(data->gsession_db);
+ free(data->gipindex_db);
+ free(data->gcallerid_db);
+ pthread_mutex_destroy(&data->mutex);
free(instance);
return 0;