⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rlm_ippool.c

📁 RADIUS认证协议
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * rlm_ippool.c * * Version:  $Id: rlm_ippool.c,v 1.31 2004/05/03 10:51:26 kkalev Exp $ * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * Copyright 2001  The FreeRADIUS server project * Copyright 2002  Kostas Kalevras <kkalev@noc.ntua.gr> * * March 2002, Kostas Kalevras <kkalev@noc.ntua.gr> * - Initial release * April 2002, Kostas Kalevras <kkalev@noc.ntua.gr> * - Add support for the Pool-Name attribute * May 2002, Kostas Kalevras <kkalev@noc.ntua.gr> * - Check the return value of a gdbm_fetch() we didn't check * - Change the nas entry in the ippool_key structure from uint32 to string[64] *   That should allow us to also use the NAS-Identifier attribute * Sep 2002, Kostas Kalevras <kkalev@noc.ntua.gr> * - Move from authorize to post-auth * - Use mutex locks when accessing the gdbm files * - Fail if we don't find nas port information * Oct 2002, Kostas Kalevras <kkalev@noc.ntua.gr> * - Do a memset(0) on the key.nas before doing searches. Nusty bug * Jul 2003, Kostas Kalevras <kkalev@noc.ntua.gr> * - Make Multilink work this time * - Instead of locking file operations, lock transactions. That means we only keep *   one big transaction lock instead of per file locks (mutexes). * Sep 2003, Kostas Kalevras <kkalev@noc.ntua.gr> * - Fix postauth to not leak ip's *   Add an extra attribute in each entry <char extra> signifying if we need to delete this *   entry in the accounting phase. This is only true in case we are doing MPPP *   Various other code changes. Code comments should explain things *   Highly experimental at this phase. * Mar 2004, Kostas Kalevras <kkalev@noc.ntua.gr> * - Add a timestamp and a timeout attribute in ippool_info. When we assign an ip we set timestamp *   to request->timestamp and timeout to %{Session-Timeout:-0}. When we search for a free entry *   we check if timeout has expired. If it has then we free the entry. We also add a maximum *   timeout configuration directive. If it is non zero then we also use that one to free entries. */#include "config.h"#include "autoconf.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_STDINT_H#include <stdint.h>#endif#ifdef HAVE_INTTYPES_H#include <inttypes.h>#endif#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif#include "radiusd.h"#include "modules.h"#include "conffile.h"#include <gdbm.h>#include <time.h>#ifdef NEEDS_GDBM_SYNC#	define GDBM_SYNCOPT GDBM_SYNC#else#	define GDBM_SYNCOPT 0#endif#ifdef GDBM_NOLOCK#define GDBM_IPPOOL_OPTS (GDBM_SYNCOPT | GDBM_NOLOCK)#else#define GDBM_IPPOOL_OPTS (GDBM_SYNCOPT)#endif#define MAX_NAS_NAME_SIZE 64static const char rcsid[] = "$Id: rlm_ippool.c,v 1.31 2004/05/03 10:51:26 kkalev Exp $";/* *	Define a structure for our module configuration. * *	These variables do not need to be in a structure, but it's *	a lot cleaner to do so, and a pointer to the structure can *	be used as the instance handle. */typedef struct rlm_ippool_t {	char *session_db;	char *ip_index;	char *name;	uint32_t range_start;	uint32_t range_stop;	uint32_t netmask;	time_t max_timeout;	int cache_size;	int override;	GDBM_FILE gdbm;	GDBM_FILE ip;#ifdef HAVE_PTHREAD_H	pthread_mutex_t op_mutex;#endif} rlm_ippool_t;#ifndef HAVE_PTHREAD_H/* *	This is easier than ifdef's throughout the code. */#define pthread_mutex_init(_x, _y)#define pthread_mutex_destroy(_x)#define pthread_mutex_lock(_x)#define pthread_mutex_unlock(_x)#endiftypedef struct ippool_info {	uint32_t	ipaddr;	char		active;	char		cli[32];	char		extra;	time_t		timestamp;	time_t		timeout;} ippool_info;typedef struct ippool_key {	char nas[MAX_NAS_NAME_SIZE];	unsigned int port;} ippool_key;/* *	A mapping of configuration file names to internal variables. * *	Note that the string is dynamically allocated, so it MUST *	be freed.  When the configuration file parse re-reads the string, *	it free's the old one, and strdup's the new one, placing the pointer *	to the strdup'd string into 'config.string'.  This gets around *	buffer over-flows. */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 },  { "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" },  { "cache-size", PW_TYPE_INTEGER, offsetof(rlm_ippool_t,cache_size), NULL, "1000" },  { "override", PW_TYPE_BOOLEAN, offsetof(rlm_ippool_t,override), NULL, "no" },  { "maximum-timeout", PW_TYPE_INTEGER, offsetof(rlm_ippool_t,max_timeout), NULL, "0" },  { NULL, -1, 0, NULL, NULL }};/* *	Do any per-module initialization that is separate to each *	configured instance of the module.  e.g. set up connections *	to external databases, read configuration files, set up *	dictionary entries, etc. * *	If configuration information is given in the config section *	that must be referenced in later calls, store a handle to it *	in *instance otherwise put a null pointer there. */static int ippool_instantiate(CONF_SECTION *conf, void **instance){	rlm_ippool_t *data;	int cache_size;	ippool_info entry;	ippool_key key;	datum key_datum;	datum data_datum;	int i;	unsigned j;	const char *cli = "0";	char *pool_name = NULL;	/*	 *	Set up a storage area for instance data	 */	data = rad_malloc(sizeof(*data));	if (!data) {		return -1;	}	memset(data, 0, sizeof(*data));	/*	 *	If the configuration parameters can't be parsed, then	 *	fail.	 */	if (cf_section_parse(conf, data, module_config) < 0) {		free(data);		return -1;	}	cache_size = data->cache_size;	if (data->session_db == NULL) {		radlog(L_ERR, "rlm_ippool: 'session-db' must be set.");		free(data);		return -1;	}	if (data->ip_index == NULL) {		radlog(L_ERR, "rlm_ippool: 'ip-index' 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);	if (data->range_start == 0 || data->range_stop == 0 || \			 data->range_start >= data->range_stop ) {		radlog(L_ERR, "rlm_ippool: Invalid configuration data given.");		free(data);		return -1;	}	data->gdbm = gdbm_open(data->session_db, sizeof(int),			GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);	if (data->gdbm == 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),			GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);	if (data->ip == NULL) {		radlog(L_ERR, "rlm_ippool: Failed to open file %s: %s",				data->ip_index, strerror(errno));		return -1;	}	if (gdbm_setopt(data->gdbm, 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)		radlog(L_ERR, "rlm_ippool: Failed to set cache size");	key_datum = gdbm_firstkey(data->gdbm);	if (key_datum.dptr == NULL){			/*			 * If the database does not exist initialize it.			 * We set the nas/port pairs to not existent values and			 * active = 0			 */		int rcode;		uint32_t or_result;		char str[32];		const char *nas_init = "NOT_EXIST";		DEBUG("rlm_ippool: Initializing database");		for(i=data->range_start,j=~0;i<=data->range_stop;i++,j--){			/*			 * Net and Broadcast addresses are excluded			 */			or_result = i | data->netmask;			if (~data->netmask != 0 &&				(or_result == data->netmask ||			    (~or_result == 0))) {				DEBUG("rlm_ippool: IP %s excluded",				      ip_ntoa(str, ntohl(i)));				continue;			}			strcpy(key.nas, nas_init);			key.port = j;			key_datum.dptr = (char *) &key;			key_datum.dsize = sizeof(ippool_key);			entry.ipaddr = ntohl(i);			entry.active = 0;			entry.extra = 0;			entry.timestamp = 0;			entry.timeout = 0;			strcpy(entry.cli,cli);			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));				free(data);				gdbm_close(data->gdbm);				gdbm_close(data->ip);				return -1;			}		}	}	else		free(key_datum.dptr);	/* Add the ip pool name */	data->name = NULL;	pool_name = cf_section_name2(conf);	if (pool_name != NULL)		data->name = strdup(pool_name);	pthread_mutex_init(&data->op_mutex, NULL);	*instance = data;	return 0;}/* *	Check for an Accounting-Stop *	If we find one and we have allocated an IP to this nas/port combination, deallocate it. */static int ippool_accounting(void *instance, REQUEST *request){	rlm_ippool_t *data = (rlm_ippool_t *)instance;	datum key_datum;	datum data_datum;	datum save_datum;	int acctstatustype = 0;	unsigned int port = ~0;	int rcode;	char nas[MAX_NAS_NAME_SIZE];	ippool_info entry;	ippool_key key;	int num = 0;	VALUE_PAIR *vp;	char str[32];	if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) != NULL)		acctstatustype = vp->lvalue;	else {		DEBUG("rlm_ippool: Could not find account status type in packet. Return NOOP.");		return RLM_MODULE_NOOP;	}	switch(acctstatustype){		case PW_STATUS_STOP:			if ((vp = pairfind(request->packet->vps, PW_NAS_PORT)) != NULL)				port = vp->lvalue;			else {				DEBUG("rlm_ippool: Could not find port number in packet. Return NOOP.");				return RLM_MODULE_NOOP;			}			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 in packet. Return NOOP.");					return RLM_MODULE_NOOP;				}			}			break;		default:			/* We don't care about any other accounting packet */			DEBUG("rlm_ippool: This is not an Accounting-Stop. 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 the entry was found set active to zero		 */		memcpy(&entry, data_datum.dptr, sizeof(ippool_info));		free(data_datum.dptr);		DEBUG("rlm_ippool: Deallocated 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 *) &num;				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);	}	else{		pthread_mutex_unlock(&data->op_mutex);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -