📄 rlm_ippool.c
字号:
DEBUG("rlm_ippool: Entry not found"); } return RLM_MODULE_OK;}static int ippool_postauth(void *instance, REQUEST *request){ rlm_ippool_t *data = (rlm_ippool_t *) instance; unsigned int port = 0; int delete = 0; int found = 0; int mppp = 0; int extra = 0; int rcode; int num = 0; char nas[MAX_NAS_NAME_SIZE]; datum key_datum; datum nextkey; datum data_datum; datum save_datum; ippool_key key; ippool_info entry; VALUE_PAIR *vp; char *cli = NULL; char str[32]; /* quiet the compiler */ instance = instance; request = request; /* Check if Pool-Name attribute exists. If it exists check our name and * run only if they match */ if ((vp = pairfind(request->config_items, PW_POOL_NAME)) != NULL){ if (data->name == NULL || strcmp(data->name,vp->strvalue)) return RLM_MODULE_NOOP; } else { DEBUG("rlm_ippool: Could not find Pool-Name attribute."); return RLM_MODULE_NOOP; } /* * Get the nas ip address * If not fail */ if ((vp = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS)) != NULL) strncpy(nas, vp->strvalue, MAX_NAS_NAME_SIZE - 1); else{ if ((vp = pairfind(request->packet->vps, PW_NAS_IDENTIFIER)) != NULL) strncpy(nas, vp->strvalue, MAX_NAS_NAME_SIZE - 1); else{ DEBUG("rlm_ippool: Could not find nas information. Return NOOP."); return RLM_MODULE_NOOP; } } /* * Find the caller id */ if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL) cli = vp->strvalue; /* * Find the port * If not fail */ if ((vp = pairfind(request->packet->vps, PW_NAS_PORT)) != NULL) port = vp->lvalue; else{ DEBUG("rlm_ippool: Could not find nas port information. Return NOOP."); 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->op_mutex); data_datum = gdbm_fetch(data->gdbm, key_datum); if (data_datum.dptr != NULL){ /* * If there is a corresponding entry in the database with active=1 it is stale. * Set active to zero */ found = 1; 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; entry.timestamp = 0; entry.timeout = 0; /* * Save the reference to the entry */ save_datum.dptr = key_datum.dptr; save_datum.dsize = key_datum.dsize; data_datum.dptr = (char *) &entry; data_datum.dsize = sizeof(ippool_info); rcode = gdbm_store(data->gdbm, 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)); pthread_mutex_unlock(&data->op_mutex); return RLM_MODULE_FAIL; } /* Decrease allocated count from the ip index */ key_datum.dptr = (char *) &entry.ipaddr; key_datum.dsize = sizeof(uint32_t); data_datum = gdbm_fetch(data->ip, key_datum); 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); rcode = gdbm_store(data->ip, 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)); pthread_mutex_unlock(&data->op_mutex); return RLM_MODULE_FAIL; } if (num >0 && entry.extra == 1){ /* * We are doing MPPP and we still have nas/port entries referencing * this ip. Delete this entry so that eventually we only keep one * reference to this ip. */ gdbm_delete(data->gdbm,save_datum); } } } } } pthread_mutex_unlock(&data->op_mutex); /* * If there is a Framed-IP-Address attribute in the reply, check for override */ if (pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS) != NULL) { DEBUG("rlm_ippool: Found Framed-IP-Address attribute in reply attribute list."); if (data->override) { /* Override supplied Framed-IP-Address */ DEBUG("rlm_ippool: override is set to yes. Override the existing Framed-IP-Address attribute."); pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS); } else { /* Abort */ DEBUG("rlm_ippool: override is set to no. Return NOOP."); return RLM_MODULE_NOOP; } } /* * Walk through the database searching for an active=0 entry. * We search twice. Once to see if we have an active entry with the same callerid * so that MPPP can work ok and then once again to find a free entry. */ pthread_mutex_lock(&data->op_mutex); key_datum.dptr = NULL; if (cli != NULL){ key_datum = gdbm_firstkey(data->gdbm); while(key_datum.dptr){ data_datum = gdbm_fetch(data->gdbm, key_datum); if (data_datum.dptr){ memcpy(&entry,data_datum.dptr, sizeof(ippool_info)); free(data_datum.dptr); /* * 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 (strcmp(entry.cli,cli) == 0 && entry.active){ memcpy(&key,key_datum.dptr,sizeof(ippool_key)); if (!strcmp(key.nas,nas)){ mppp = 1; break; } } } nextkey = gdbm_nextkey(data->gdbm, key_datum); free(key_datum.dptr); key_datum = nextkey; } } if (key_datum.dptr == NULL){ key_datum = gdbm_firstkey(data->gdbm); while(key_datum.dptr){ data_datum = gdbm_fetch(data->gdbm, key_datum); if (data_datum.dptr){ memcpy(&entry,data_datum.dptr, sizeof(ippool_info)); free(data_datum.dptr); /* * Find an entry with active == 0 * or an entry that has expired */ if (entry.active == 0 || (entry.timestamp && ((entry.timeout && request->timestamp >= (entry.timestamp + entry.timeout)) || (data->max_timeout && request->timestamp >= (entry.timestamp + data->max_timeout))))){ datum tmp; tmp.dptr = (char *) &entry.ipaddr; tmp.dsize = sizeof(uint32_t); data_datum = gdbm_fetch(data->ip, tmp); /* * 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. */ if (data_datum.dptr){ memcpy(&num,data_datum.dptr, sizeof(int)); free(data_datum.dptr); if (num == 0){ delete = 1; break; } } else{ delete = 1; break; } } } nextkey = gdbm_nextkey(data->gdbm, key_datum); free(key_datum.dptr); key_datum = nextkey; } } /* * If we have found a free entry set active to 1 then add a Framed-IP-Address attribute to * the reply * We keep the operation mutex locked until after we have set the corresponding entry active */ if (key_datum.dptr){ if (found && !mppp){ /* * Found == 1 means we have the nas/port combination entry in our database * We exchange the ip address between the nas/port entry and the free entry * Afterwards we will save the free ip address to the nas/port entry. * That is: * --------------------------------------------- * - NAS/PORT Entry |||| Free Entry ||| Time * - IP1 IP2(Free) BEFORE * - IP2(Free) IP1 AFTER * --------------------------------------------- * * We only do this if we are NOT doing MPPP * */ datum key_datum_tmp; datum data_datum_tmp; ippool_key key_tmp; memset(key_tmp.nas,0,MAX_NAS_NAME_SIZE); strncpy(key_tmp.nas,nas,MAX_NAS_NAME_SIZE -1 ); key_tmp.port = port; DEBUG("rlm_ippool: Searching for an entry for nas/port: %s/%u",key_tmp.nas,key_tmp.port); key_datum_tmp.dptr = (char *) &key_tmp; key_datum_tmp.dsize = sizeof(ippool_key); data_datum_tmp = gdbm_fetch(data->gdbm, key_datum_tmp); if (data_datum_tmp.dptr != NULL){ rcode = gdbm_store(data->gdbm, key_datum, data_datum_tmp, GDBM_REPLACE); if (rcode < 0) { radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s", data->session_db, gdbm_strerror(gdbm_errno)); pthread_mutex_unlock(&data->op_mutex); return RLM_MODULE_FAIL; } free(data_datum_tmp.dptr); } } else{ /* * We have not found the nas/port combination */ if (delete){ /* * Delete the entry so that we can change the key * All is well. We delete one entry and we add one entry */ gdbm_delete(data->gdbm, key_datum); } else{ /* * We are doing MPPP. (mppp should be 1) * We don't do anything. * We will create an extra not needed entry in the database in this case * but we don't really care since we always also use the ip_index database * when we search for a free entry. * We will also delete that entry on the accounting section so that we only * have one nas/port entry referencing each ip */ if (mppp) extra = 1; if (!mppp) radlog(L_ERR, "rlm_ippool: mppp is not one. Please report this behaviour."); } } free(key_datum.dptr); entry.active = 1; entry.timestamp = request->timestamp; if ((vp = pairfind(request->reply->vps, PW_SESSION_TIMEOUT)) != NULL) entry.timeout = (time_t) vp->lvalue; else entry.timeout = 0; if (extra) entry.extra = 1; data_datum.dptr = (char *) &entry; data_datum.dsize = sizeof(ippool_info); 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); rcode = gdbm_store(data->gdbm, 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)); pthread_mutex_unlock(&data->op_mutex); return RLM_MODULE_FAIL; } /* Increase the ip index count */ key_datum.dptr = (char *) &entry.ipaddr; key_datum.dsize = sizeof(uint32_t); data_datum = gdbm_fetch(data->ip, key_datum); if (data_datum.dptr){ memcpy(&num,data_datum.dptr,sizeof(int)); free(data_datum.dptr); } else num = 0; num++; DEBUG("rlm_ippool: num: %d",num); data_datum.dptr = (char *) # data_datum.dsize = sizeof(int); rcode = gdbm_store(data->ip, 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)); pthread_mutex_unlock(&data->op_mutex); return RLM_MODULE_FAIL; } pthread_mutex_unlock(&data->op_mutex); 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_FAIL; } vp->lvalue = entry.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); } } } else{ pthread_mutex_unlock(&data->op_mutex); DEBUG("rlm_ippool: No available ip addresses in pool."); return RLM_MODULE_NOTFOUND; } return RLM_MODULE_OK;}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->op_mutex); free(instance); return 0;}/* * The module name should be the only globally exported symbol. * That is, everything else should be 'static'. * * If the module needs to temporarily modify it's instantiation * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE. * The server will then take care of ensuring that the module * is single-threaded. */module_t rlm_ippool = { "IPPOOL", RLM_TYPE_THREAD_SAFE, /* type */ NULL, /* initialization */ ippool_instantiate, /* instantiation */ { NULL, /* authentication */ NULL, /* authorization */ NULL, /* preaccounting */ ippool_accounting, /* accounting */ NULL, /* checksimul */ NULL, /* pre-proxy */ NULL, /* post-proxy */ ippool_postauth /* post-auth */ }, ippool_detach, /* detach */ NULL, /* destroy */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -