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

📄 radrelay.c

📁 radius server在linux下的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * radrelay.c	This program tails a detail logfile, reads the log *		entries, forwards them to a remote radius server, *		and moves the processed records to another file. * *		Used to replicate accounting records to one (central) *		server - works even if remote server has extended *		downtime, and/or if this program is restarted. * *   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 Cistron Internet Services B.V. * Copyright 2002 Simon Ekstrand <simon@routemeister.net> * */char radrelay_rcsid[] ="$Id: radrelay.c,v 1.22.2.2 2005/05/23 09:35:09 nbk Exp $";#include "autoconf.h"#include "libradius.h"#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/stat.h>#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif#include <stdio.h>#include <fcntl.h>#include <time.h>#include <unistd.h>#include <netdb.h>#include <stdlib.h>#include <signal.h>#include <errno.h>#include <string.h>#include "radiusd.h"#include "conf.h"#include "radpaths.h"#include "missing.h"#include "conffile.h"const char *progname;int debug_flag = 0;const char *radlog_dir = NULL;radlog_dest_t radlog_dest = RADLOG_FILES;const char *radius_dir = NULL;const char *radacct_dir = NULL;const char *radlib_dir = NULL;uint32_t myip = INADDR_ANY;int log_stripped_names;struct main_config_t mainconfig;/* *	Possible states for request->state */#define		STATE_EMPTY	0#define		STATE_BUSY1	1#define		STATE_BUSY2	2#define		STATE_FULL	3/* *	Possible states for the loop() function. */#define		STATE_RUN	0#define		STATE_BACKLOG	1#define		STATE_WAIT	2#define		STATE_SHUTDOWN	3#define		STATE_CLOSE	4#define		NR_SLOTS	64/* *	A relay request. */struct relay_request {	int		state;				/* REQ_* state */	time_t		retrans;			/* when to retrans */	unsigned int	retrans_num;			/* Number of retransmissions */	time_t		timestamp;			/* orig recv time */	uint32_t	client_ip;			/* Client-IP-Addr */	RADIUS_PACKET	*req;				/* Radius request */};struct relay_misc {	int		sockfd;				/* Main socket descriptor */	uint32_t 	dst_addr;			/* Destination address */	short 		dst_port;			/* Destination port */	uint32_t	src_addr;			/* Source address */	char		detail[1024];			/* Detail file */	char 		*secret;			/* Secret */	char		f_secret[256];			/* File secret */};/* * Used for reading the client configurations from the config files. */char *c_secret = NULL;char *c_shortname = NULL;struct relay_request slots[NR_SLOTS];char id_map[256];int request_head = 0;int got_sigterm = 0;int debug = 0;int get_radius_id(void);void sigterm_handler(int sig);void ms_sleep(int msec);int isdateline(char *d);int read_one(FILE *fp, struct relay_request *req);int do_recv(struct relay_misc *r_args);int do_send(struct relay_request *r, char *secret);int detail_move(char *from, char *to);void loop(struct relay_misc *r_args);int find_shortname(char *shortname, char **host, char **secret);void usage(void);/* * Get a radius id which is not * currently being used (outstanding request) * Since NR_SLOTS < 256 we can't * have more outstanding requests than radius ids */int get_radius_id(){	unsigned int id = 0;	for(id = 0; id < 256; id++){		if (id_map[id] == 0)			break;	}	if (id == 256 || id_map[id] != 0){		fprintf(stdout, "get_radius_id(): No IDs available. Something is very wrong\n");		return -1;	}	id_map[id] = 1;	fprintf(stdout, "get_radius_id(): Assign RADIUS ID = %d\n",id);	return id;}void sigterm_handler(int sig){	signal(sig, sigterm_handler);	got_sigterm = 1;}/* *	Sleep a number of milli seconds */void ms_sleep(int msec){	struct timeval tv;	tv.tv_sec  = (msec / 1000);	tv.tv_usec = (msec % 1000) * 1000;	select(0, NULL, NULL, NULL, &tv);}/* *	Does this (remotely) look like "Tue Jan 23 06:55:48 2001" ? */int isdateline(char *d){	int y;	return sscanf(d, "%*s %*s %*d %*d:%*d:%*d %d", &y);}/* *	Read one request from the detail file. *	Note that the file is locked during the read, and that *	we return *with the file locked* if we reach end-of-file. * *	STATE_EMPTY:	Slot is empty. *	STATE_BUSY1:	Looking for start of a detail record (timestamp) *	STATE_BUSY2:	Reading the A/V pairs of a detail record. *	STATE_FULL:	Read the complete record. * */int read_one(FILE *fp, struct relay_request *r_req){	VALUE_PAIR *vp;	char *s;	char buf[256];	char key[32], val[32];	int skip;	long fpos;	int x;	unsigned int i = 0;	/* Never happens */	if (r_req->state == STATE_FULL)		return 0;	if (r_req->state == STATE_EMPTY) {		r_req->state = STATE_BUSY1;	}	/*	 * Try to lock the detail-file.	 * If lockf is used we want to lock the _whole_ file, hence the	 * fseek to the start of the file.	 */	fpos = ftell(fp);	fseek(fp, 0L, SEEK_SET);	do {		x = rad_lockfd_nonblock(fileno(fp), 0);		if (x == -1)			ms_sleep(100);	} while (x == -1 && i++ < 20);	if (x == -1)		return 0;redo:	s = NULL;	fseek(fp, fpos, SEEK_SET);	fpos = ftell(fp);	while ((s = fgets(buf, sizeof(buf), fp)) != NULL) {		/*		 * Eek! We've just read a broken attribute.		 * This does seem to happen every once in a long while		 * due to some quirk involving threading, multiple processes		 * going for the detail file lock at once and writes not		 * being flushed properly. Things should be ok next time		 * around.		 */		if (!strlen(buf)) {			fprintf(stdout, "read_one: ZERO BYTE\n");                       fseek(fp, fpos + 1, SEEK_SET);                       break;               } else if (buf[strlen(buf) - 1] != '\n') {			fprintf(stdout, "read_one: BROKEN ATTRIBUTE\n");			fseek(fp, fpos + strlen(buf), SEEK_SET);			break;		}		if (r_req->state == STATE_BUSY1) {			if (isdateline(buf)) {				r_req->state = STATE_BUSY2;			}		} else if (r_req->state == STATE_BUSY2) {			if (buf[0] != ' ' && buf[0] != '\t') {				r_req->state = STATE_FULL;				break;			}			/*			 *	Found A/V pair, but we skip non-protocol			 *	values.			 */			skip = 0;			if (sscanf(buf, "%31s = %31s", key, val) == 2) {				if (!strcasecmp(key, "Timestamp")) {					r_req->timestamp = atoi(val);					skip++;				} else				if (!strcasecmp(key, "Client-IP-Address")) {					r_req->client_ip = ip_getaddr(val);					skip++;				} else				if (!strcasecmp(key, "Request-Authenticator"))					skip++;			}			if (!skip) {				vp = NULL;				if (userparse(buf, &vp) > 0 &&				    (vp != NULL) &&				    (vp->attribute < 256 ||				     vp->attribute > 65535) &&				    vp->attribute != PW_VENDOR_SPECIFIC) {					pairadd(&(r_req->req->vps), vp);				} else {				  pairfree(&vp);				}			}		}		fpos = ftell(fp);	}	clearerr(fp);	if (r_req->state == STATE_FULL) {		/*		 *	w00 - we just completed reading a record in full.		 */		/*		 * Check that we have an Acct-Status-Type attribute. If not		 * reject the record		 */		if (pairfind(r_req->req->vps, PW_ACCT_STATUS_TYPE) == NULL){			fprintf(stdout, "read_one: No Acct-Status-Type attribute present. Rejecting record.\n");			r_req->state = STATE_BUSY1;			if (r_req->req->vps != NULL) {				pairfree(&r_req->req->vps);				r_req->req->vps = NULL;			}			if (r_req->req->data != NULL) {				free (r_req->req->data);				r_req->req->data = NULL;			}			r_req->retrans = 0;			r_req->retrans_num = 0;			r_req->timestamp = 0;			r_req->client_ip = 0;			goto redo;		}		if (r_req->timestamp == 0)			r_req->timestamp = time(NULL);		if ((vp = pairfind(r_req->req->vps, PW_ACCT_DELAY_TIME)) != NULL) {			r_req->timestamp -= vp->lvalue;			vp->lvalue = 0;		}		r_req->req->id = get_radius_id();	}	if (s == NULL) {		/*		 *	Apparently we reached end of file. If we didn't		 *	partially read a record, we let the caller know		 *	we're at end of file.		 */		if (r_req->state == STATE_BUSY1) {			r_req->state = STATE_EMPTY;		}		if (r_req->state == STATE_EMPTY || r_req->state == STATE_FULL)			return EOF;	}	fpos = ftell(fp);	fseek(fp, 0L, SEEK_SET);	rad_unlockfd(fileno(fp), 0);	fseek(fp, fpos, SEEK_SET);	return 0;}/* *	Receive answers from the remote server. */int do_recv(struct relay_misc *r_args){	RADIUS_PACKET *rep;	struct relay_request *r;	int i;	/*	 *	Receive packet and validate it's length.	 */	rep = rad_recv(r_args->sockfd);	if (rep == NULL) {		librad_perror("radrelay:");		return -1;	}	/*	 *	Must be an accounting response.	 *	FIXME: check if this is the right server!	 */	if (rep->code != PW_ACCOUNTING_RESPONSE)		return -1;	/*	 *	Decode packet into radius attributes.	 */	/*	 *	Now find it in the outstanding requests.	 */	for (i = 0; i < NR_SLOTS; i++) {		r = slots + i;		if (r->state == STATE_FULL && r->req->id == rep->id) {			if (rad_decode(rep, r->req, r_args->secret) != 0) {				librad_perror("rad_decode");				return -1;			}			/*			 *	Got it. Clear slot.			 *	FIXME: check reponse digest ?			 */			id_map[r->req->id] = 0;			fprintf(stdout, "do_recv: Free RADIUS ID = %d\n",r->req->id);			if (r->req->vps != NULL) {				pairfree(&r->req->vps);				r->req->vps = NULL;			}			if (r->req->data != NULL) {				free (r->req->data);				r->req->data = NULL;			}			r->state = STATE_EMPTY;			r->retrans = 0;			r->retrans_num = 0;			r->timestamp = 0;			r->client_ip = 0;			break;		}	}	rad_free(&rep);	return 0;}/* *	Send accounting packet to remote server. */int do_send(struct relay_request *r, char *secret){	VALUE_PAIR *vp;	time_t now;	/*	 *	Prevent loops.	 */	if (r->client_ip == r->req->dst_ipaddr) {		fprintf(stdout, "do_send: Client-IP == Dest-IP. Droping packet.\n");		fprintf(stdout, "do_send: Free RADIUS ID = %d\n",r->req->id);		id_map[r->req->id] = 0;		if (r->req->vps != NULL) {			pairfree(&r->req->vps);			r->req->vps = NULL;		}		if (r->req->data != NULL) {			free (r->req->data);			r->req->data = NULL;		}		r->state = STATE_EMPTY;		r->retrans = 0;		r->retrans_num = 0;		r->timestamp = 0;		r->client_ip = 0;		return 0;	}	/*	 *	Has the time come for this packet ?	 */	now = time(NULL);	if (r->retrans > now)		return 0;	/*	 * If we are resending a packet we *need* to	 * change the radius packet id since the request	 * authenticator is different (due to different	 * Acct-Delay-Time value).	 * Otherwise the radius server may consider the	 * packet a duplicate and we 'll get caught in a	 * loop.	 */	if (r->retrans > 0){		id_map[r->req->id] = 0;		r->req->id = get_radius_id();		if (r->req->data != NULL){			free(r->req->data);			r->req->data = NULL;		}		r->retrans_num++;	}	if (r->retrans_num > 20)		r->retrans = now + 70;	else		r->retrans = now + 3 + (3 * r->retrans_num);	/*	 *	Find the Acct-Delay-Time attribute. If it's	 *	not there, add one.	 */	if ((vp = pairfind(r->req->vps, PW_ACCT_DELAY_TIME)) == NULL) {		vp = paircreate(PW_ACCT_DELAY_TIME, PW_TYPE_INTEGER);		pairadd(&(r->req->vps), vp);	}	vp->lvalue = (now - r->timestamp);	/*	 *	Rebuild the entire packet every time from	 *	scratch - the signature changed because	 *	Acct-Delay-Time changed.	 */	rad_send(r->req, NULL, secret);	return 1;}/* *	Rename a file, then recreate the old file with the *	same permissions and zero size. */int detail_move(char *from, char *to){	struct stat st;	int n;	int oldmask;	if (stat(from, &st) < 0)

⌨️ 快捷键说明

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