📄 rlm_ippool.c
字号:
} pthread_mutex_unlock(&data->op_mutex); } else{ pthread_mutex_unlock(&data->op_mutex); 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; int delete = 0; int found = 0; int mppp = 0; int extra = 0; int rcode; int num = 0; 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]; uint8_t key_str[17]; char hex_str[35]; char xlat_str[MAX_STRING_LEN]; FR_MD5_CTX md5_context; /* 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->vp_strvalue) && strcmp(vp->vp_strvalue,"DEFAULT"))) return RLM_MODULE_NOOP; } else { DEBUG("rlm_ippool: Could not find Pool-Name attribute."); return RLM_MODULE_NOOP; } /* * Find the caller id */ if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL) cli = vp->vp_strvalue; if (!radius_xlat(xlat_str,MAX_STRING_LEN,data->key, request, NULL)){ DEBUG("rlm_ippool: xlat on the 'key' directive failed"); return RLM_MODULE_NOOP; } fr_MD5Init(&md5_context); fr_MD5Update(&md5_context, xlat_str, strlen(xlat_str)); fr_MD5Final(key_str, &md5_context); key_str[16] = '\0'; fr_bin2hex(key_str,hex_str,16); hex_str[32] = '\0'; DEBUG("rlm_ippool: MD5 on 'key' directive maps to: %s",hex_str); memcpy(key.key,key_str,16); DEBUG("rlm_ippool: Searching for an entry for key: '%s'",hex_str); 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: %s",ip_ntoa(str,entry.ipaddr)); 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 with active=1 * then we use that for multilink (MPPP) to work properly. */ if (strcmp(entry.cli,cli) == 0 && entry.active){ 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 * 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; memcpy(key_tmp.key,key_str,16); 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); free(data_datum_tmp.dptr); 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; } } } 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->vp_integer; else entry.timeout = 0; if (extra) entry.extra = 1; data_datum.dptr = (char *) &entry; data_datum.dsize = sizeof(ippool_info); memcpy(key.key, key_str, 16); key_datum.dptr = (char *) &key; key_datum.dsize = sizeof(ippool_key); DEBUG2("rlm_ippool: Allocating ip to key: '%s'",hex_str); 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 key: %s",ip_ntoa(str,entry.ipaddr),hex_str); vp = radius_paircreate(request, &request->reply->vps, PW_FRAMED_IP_ADDRESS, PW_TYPE_IPADDR); vp->vp_ipaddr = entry.ipaddr; /* * If there is no Framed-Netmask attribute in the * reply, add one */ if (pairfind(request->reply->vps, PW_FRAMED_IP_NETMASK) == NULL) { vp = radius_paircreate(request, &request->reply->vps, PW_FRAMED_IP_NETMASK, PW_TYPE_IPADDR); vp->vp_ipaddr = ntohl(data->netmask); } } 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); 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 = { RLM_MODULE_INIT, "ippool", RLM_TYPE_THREAD_SAFE, /* type */ ippool_instantiate, /* instantiation */ ippool_detach, /* detach */ { NULL, /* authentication */ NULL, /* authorization */ NULL, /* preaccounting */ ippool_accounting, /* accounting */ NULL, /* checksimul */ NULL, /* pre-proxy */ NULL, /* post-proxy */ ippool_postauth /* post-auth */ },};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -