radiusload

Snebjørn Andersen sanderse at bellesystems.com
Fri May 26 07:08:19 EDT 2000


-- 
Snebjørn Andersen
Software Developer, Software Development
Belle Systems A/S
Tel.:   +45 5944 2500
E-mail: sanderse at bellesystems.com
Web:    http://www.bellesystems.com

Defining the Future of IP Services
-------------- next part --------------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <inttypes.h>
#include <netdb.h>

#include "main.h"
#include "md5.h"
#include "config.h"

#define	DEFAULT_CONFIG_FILE	"radiusload.cfg"

#define SUCCESS 0
#define FAILED -1

#define VENDOR_SPECIFIC								26
#define VENDOR_CISCO								9

#define  CISCO_VSA_CONNECTION_ID					24
#define  CISCO_VSA_SETUP_TIME						25
#define  CISCO_VSA_CALL_ORIGIN						26
#define  CISCO_VSA_CALL_TYPE						27
#define  CISCO_VSA_CONNECT_TIME						28
#define  CISCO_VSA_DISCONNECT_TIME					29
#define  CISCO_VSA_DISCONNECT_CAUSE					30
#define  CISCO_VSA_VOICE_QUALITY					31
#define  CISCO_VSA_GW_ID							33

unsigned char * addVendorAttribute(uint32_t vendor_id, unsigned char vendor_type, const char *value, unsigned char *ptr);

struct attribute_type_struct attributeType[] = 
{
    {AT_USER_NAME, VT_STRING },						/*  1 */
    {AT_USER_PASSWORD, VT_STRING },					/*  2 */
	{AT_CHAP_PASSWORD, VT_STRING },					/*  3 */
    {AT_NAS_IP_ADDRESS, VT_ADDRESS },				/*  4 */
    {AT_NAS_PORT, VT_INTEGER },						/*  5 */
    {AT_SERVICE_TYPE, VT_INTEGER },					/*  6 */
    {AT_FRAMED_PROTOCOL, VT_INTEGER },				/*  7 */
    {AT_FRAMED_ADDRESS, VT_ADDRESS},				/*  8 */
    {AT_CLASS, VT_STRING},							/* 25 */
    {AT_CALLED_STATION_ID, VT_STRING },				/* 30 */
    {AT_CALLING_STATION_ID, VT_STRING },			/* 31 */
    {AT_NAS_IDENTIFIER, VT_STRING },				/* 32 */
    {AT_ACCT_STATUS_TYPE, VT_INTEGER },				/* 40 */
    {AT_ACCT_INPUT_OCTETS, VT_INTEGER},				/* 42 */
    {AT_ACCT_OUTPUT_OCTETS, VT_INTEGER},			/* 43 */
    {AT_ACCT_SESSION_ID, VT_STRING},				/* 44 */
    {AT_ACCT_AUTHENTIC, VT_INTEGER},				/* 45 */
    {AT_ACCT_SESSION_TIME, VT_INTEGER},				/* 46 */
    {AT_ACCT_INPUT_PACKETS, VT_INTEGER},			/* 47 */
    {AT_ACCT_OUTPUT_PACKETS, VT_INTEGER},			/* 48 */
    {AT_NAS_PORT_ID, VT_INTEGER },					/* 61 */
    {0, 0}
};

unsigned long	auth_reqs_sent = 0;
unsigned long	acct_reqs_sent = 0;
unsigned long	auth_rejects = 0;
unsigned long	auth_accepts = 0;
unsigned long	curr_online = 0;
unsigned long	pending_reqs = 0;
unsigned long	lost_auth_resps = 0;
unsigned long	lost_acct_resps = 0;
unsigned long	out_of_ids = 0;
unsigned long	ip_addr = 0;
double			logon_time = 0;

int				scroll_stats = 1;
unsigned long	stat_lines = 0;

unsigned long	from_num;
unsigned long	to_num;
unsigned long	rate;
unsigned long	duration;
unsigned long	session_id;
char			prefix[64];
char			user_password[16];
char			shared_secret[32];
unsigned long	shared_secret_len;
unsigned long	dead_timeout;

unsigned long  	nas_ip_adr;

time_t			start_time;

unsigned long	current_user_num;

static unsigned char	net_buffer[1500]; /* MTU SIZE */
static unsigned char	tmp_buffer[1500];

char			config_file_name[100];

unsigned char			global_identifier;

unsigned h323_conf_id_sequencer = 0;
unsigned h323_conf_id_semiunique = 0;

int				auth_sock_fd;
int				acct_sock_fd;
static struct sockaddr	dest_auth_addr;
static struct sockaddr	dest_acct_addr;

struct pending_request	pending_req[256];
struct logged_on_user	*user_top = NULL, *user_bottom = NULL;

extern struct config		cfg;

static unsigned long nextUserNum();
int my_32bit_rand();

int main(int argc, char *argv[])
{
	int				rc, i, max_fd;
	fd_set			read_set, tmp_read_set;
	struct timeval	timeout;
	time_t			now, uniq;
	
	if( argc < 2 )
	{
		strcpy(config_file_name, DEFAULT_CONFIG_FILE);
	}
	else
	{
		strcpy(config_file_name, argv[1]);
	}
	
	rc = read_config(config_file_name);	
	
	if(rc == -1)
	{
		return 0;
	}
	
	nas_ip_adr=string2ip(cfg.nas_ip_addr);
	
	FD_ZERO( &read_set );

	for( i = 0 ; i < 256 ; i++ )
	{
		pending_req[i].active = 0;
	}

	srand( time(NULL) );
	
	start_time = time(NULL);
	from_num = cfg.from_num;
	to_num = cfg.to_num;
	rate = cfg.rate;
	duration = cfg.duration;
	global_identifier = 0;
	ip_addr = cfg.ip_prefix << 24;
	
	dead_timeout = cfg.dead_timeout;
	
	strcpy(prefix, cfg.prefix);
	strcpy(shared_secret, cfg.shared_secret);
	strcpy(user_password, cfg.password);
	
	shared_secret_len = strlen(shared_secret);
	session_id = 0;
	
	current_user_num = from_num;

	if( getRadiusSocket( &dest_auth_addr, cfg.auth_ip_addr, cfg.auth_port) != 1 )
	{
		fprintf(stderr, "main: getRadiusSocket() AUTH\n");
		exit(0);
	}

	if( getRadiusSocket( &dest_acct_addr, cfg.acct_ip_addr, cfg.acct_port ) != 1 )
	{
		fprintf(stderr, "main: getRadiusSocket() ACCT\n");
		exit(0);
	}

	auth_sock_fd = openUDPSocket();
	acct_sock_fd = openUDPSocket();

	FD_SET( auth_sock_fd, &read_set );
	FD_SET( acct_sock_fd, &read_set );
	
	max_fd = acct_sock_fd + 1;
	
	uniq = start_time;

	setbuf(stdout, NULL);

	printf("RADIUS work-loader v2000c (c) Belle Systems A/S 2000\n");
    printf("Compiled: " __DATE__ "  " __TIME__ "\n");
    printf("Special why-do-i-not-logg-off-the-users-after-some-time version\n");
    
	if(!scroll_stats)
	{
        printf("\nReqs   Acpts  Rjcts  CurOL  Pend  LstRs1 LstRs2 LstRq  LogTm\n");
		printf("--------------------------------------------------------------\n");
		printf("                                                     ");
	}
	
	for(;;)
	{
		tmp_read_set = read_set;

		timeout.tv_sec = 0;
		timeout.tv_usec = 100000; /* 0.1 sec */
	
		rc = select( max_fd, &tmp_read_set, NULL, NULL, &timeout);

		switch( rc )
		{
			case -1:	/* ERROR */
				break;
		
			case 0: /* TIME OUT */
				break;
				
			default:
				if( FD_ISSET( auth_sock_fd, &tmp_read_set ) )
				{
					handleAuthResponse(auth_sock_fd);
				}

				if( FD_ISSET( acct_sock_fd, &tmp_read_set ) )
				{
					handleAcctResponse(acct_sock_fd);
				}
				break;
		}
		
		now = time(NULL);

		if( now != uniq )
		{
			uniq = now;

			if(scroll_stats)
			{
				if( stat_lines % 10 == 0)
				{
					printf("\nReqs   Acpts  Rjcts  CurOL  Pend  LstRs1 LstRs2 LstRq  LogTm\n");
					printf("--------------------------------------------------------------\n");
				}
			}
			else
			{
				printf("\r");
			}

			printf("%05ld  %05ld  %05ld  %05ld  %04ld  %05ld  %05ld  %05ld  %02.3f",
				(long)cfg.send_auth?auth_reqs_sent:acct_reqs_sent,
				(long)auth_accepts,	
				(long)auth_rejects,
				(long)curr_online,
				(long)pending_reqs,
				(long)lost_auth_resps,
				(long)lost_acct_resps,
				(long)out_of_ids,
				logon_time/auth_accepts
				);
				
			if(scroll_stats)
			{
				printf("\n");
			}
			
			
			stat_lines++;

		}

		checkForLostResponses();
		if(cfg.send_auth)
		{
			if( (auth_reqs_sent < (unsigned long)cfg.no_requests)||(cfg.no_requests == 0) )
			{
				while( ( now - start_time ) * rate > auth_reqs_sent )
				{
					/* Time to send new requests */
				 
					sendAuthRequest();
					auth_reqs_sent++;
					if(auth_reqs_sent%16==0) {
						/*sleep for 5 microseconds so the radius server has time to recv() the packets*/
						struct timespec ts;
						ts.tv_sec = 0;
						ts.tv_nsec = 500000;
						/*nanosleep(&ts,NULL);*/
					}
				}
			}
		}
		else if(cfg.send_acct_start)
		{
			if((acct_reqs_sent<(unsigned long)cfg.no_requests) || (cfg.no_requests==0))
			{
				while((now-start_time)*rate > acct_reqs_sent)
				{
					sendUnauthenticatedAcctStartRequest();
					acct_reqs_sent++;
					if(acct_reqs_sent%16==0) {
						//sleep for 5 microseconds so the radius server has time to recv() the packets
						struct timespec ts;
						ts.tv_sec = 0;
						ts.tv_nsec = 500000;
						//nanosleep(&ts,NULL);
					}
				}
			}
		}
		else
		{
			if((acct_reqs_sent<(unsigned long)cfg.no_requests) || (cfg.no_requests==0))
			{
				while((now-start_time)*rate > acct_reqs_sent)
				{
					sendUnauthenticatedAcctStopRequest();
					acct_reqs_sent++;
					if(acct_reqs_sent%16==0) {
						//sleep for 5 microseconds so the radius server has time to recv() the packets
						struct timespec ts;
						ts.tv_sec = 0;
						ts.tv_nsec = 500000;
						//nanosleep(&ts,NULL);
					}
				}
			}
		}
		
		checkForAcctStopRequests();
	}
}


void checkForLostResponses()
{
	int		i;
	time_t	now;
	
	now = time(NULL);
	
	for( i = 0 ; i < 256 ; i++ )
	{
		if( ((now - pending_req[i].timestamp) > (time_t)dead_timeout) && pending_req[i].active  )
		{
			if(pending_req[i].code!=4)
				lost_auth_resps++;
			else
				lost_acct_resps++;
			pending_reqs--;
			pending_req[i].active = 0;
		} 
	}
}

void checkForAcctStopRequests()
{
	struct logged_on_user	*ptr=NULL;
	time_t	now;

	now = time(NULL);
    if (user_top==NULL && user_bottom!=NULL)
        //if ((user_top==NULL) != (user_bottom!=NULL))
    { 
        fprintf(stderr, "Listen er smadret [online %d]\n",(int)curr_online);
        if (user_top==NULL) fprintf(stderr, "user_top=NULL\n");
        if (user_bottom==NULL) fprintf(stderr, "botton=NULL\n");
        abort();
        exit(1);
    }
	//printf("user_top pointer = %p\n", user_top);
    //printf("ptr pointer = %p\n", ptr);
	ptr = user_top;

	while( ptr && ptr->timestamp<now )
	{
		struct logged_on_user *tmp_ptr=NULL;
		sendAcctStopRequest(ptr->port, ptr->username,
		                    ptr->session_id,ptr->class_attr, 
		                    ptr->framed_ip_addr);

        fprintf(stderr, "Loggin user off [%p]\n", ptr);
		//printf("tmp pointer = %p\n", tmp_ptr);
        //printf("ptr pointer = %p\n", ptr);
        tmp_ptr = ptr;
		ptr = ptr->next;
		free(tmp_ptr);
	}

	user_top = ptr;
    printf("Users = %ld\n", (long)curr_online);
    if (curr_online==0) sleep(100);
    
    //debug code:
    if(curr_online > 2000) {
        fprintf(stderr,"=========== Suspecious many online users ==========\n");
        fprintf(stderr,"curr_online = %d\n",(int)curr_online);
        fprintf(stderr,"now = %d\n", (int)now);
        fprintf(stderr,"duration = %ld\n",(long)duration);
        fprintf(stderr,"rate = %d\n", (int)rate);
        fprintf(stderr,"from=%d, to=%d\n", (int)from_num, (int)to_num);
        fprintf(stderr,"Dumping first 200 online users:\n");
        int i=0;
        for(ptr = user_top; ptr && i<200; i++) {
            fprintf(stderr,
                    "%d: timestamp=%d, port=%d, username='%s' \n",
                    i,
                    (int)ptr->timestamp,
                    (int)ptr->port,
                    ptr->username
                   );
            ptr=ptr->next;
        }
        fprintf(stderr,"========= Dont scroll! Or the lemmings will eat you! ==============\n");
        exit(1);
    }
}

void cpyStrAttribute( struct radius_header *resp_header,
						int attr_type,
						char *output)
{
	unsigned short				packet_len;
	unsigned char				*attr_ptr;
	
	packet_len = ntohs(resp_header->length);
	
	attr_ptr = (unsigned char *)resp_header->data;
	
	while( (attr_ptr - net_buffer) < packet_len )
	{
		if( *attr_ptr == attr_type )
		{
			memcpy( output, attr_ptr + 2, *(attr_ptr + 1) - 2);
			break;
		}
		
		attr_ptr += *(attr_ptr + 1);
	}
}

void cpyIPAddrAttribute( struct radius_header *resp_header,
						int attr_type,
						uint32_t *output)
{
	unsigned short				packet_len;
	unsigned char				*attr_ptr;
	
	packet_len = ntohs(resp_header->length);
	
	attr_ptr = (unsigned char *)resp_header->data;
	
	while( (attr_ptr - net_buffer) < packet_len )
	{
		if( *attr_ptr == attr_type )
		{
			uint32_t ip;
			memcpy( &ip, attr_ptr + 2, 4);
			*output = (uint32_t) ntohl(ip);
			break;
		}
		attr_ptr += *(attr_ptr + 1);
	}
}


void handleAuthResponse(int auth_fd)
{
	int						rc;
	struct sockaddr			incoming_addr;
    
    #ifdef linux
    socklen_t			incoming_addr_len = sizeof(incoming_addr);
    #else
    int						incoming_addr_len = sizeof(incoming_addr);
    #endif

	struct radius_header	*header;
	char					class_attr[254];
	uint32_t                framed_ip_addr=0;
	unsigned char			tmp_id;
	
	header = (struct radius_header *)net_buffer;
		
	/* LOOP? */

	rc = recvfrom(auth_fd,
					(char*)net_buffer,
					sizeof(net_buffer),
					0,
					&incoming_addr,
					&incoming_addr_len );
	
	tmp_id = header->identifier;
	
	if( pending_req[header->identifier].active &&
		pending_req[header->identifier].code == 1)
	{
		if(header->code == 2)
		{
			/* Accepted */

			logon_time += get_precise_time() - pending_req[header->identifier].precise_ts;
			
			auth_accepts++;
			curr_online++;
			
			class_attr[0]='\0';
			if(cfg.remember_class_attr)
			{
				cpyStrAttribute(header, AT_CLASS, class_attr);
			}
			if(cfg.remember_framed_ip_addr)
			{
				cpyIPAddrAttribute(header, AT_FRAMED_ADDRESS, &framed_ip_addr );
			}

			sendAcctStartRequest( pending_req[header->identifier].port,
			                      pending_req[header->identifier].username,
			                      class_attr,
			                      framed_ip_addr);
		}
		else
		{
			auth_rejects++;
			/* Rejected */
		}
		pending_req[tmp_id].active = 0;
		pending_reqs--;
	}
}

void handleAcctResponse(int acct_fd)
{
	int						rc;
    struct sockaddr			incoming_addr;	

    #ifdef linux
    socklen_t				incoming_addr_len=sizeof(incoming_addr);
    #else
    int						incoming_addr_len=sizeof(incoming_addr);
    #endif
    

	struct radius_header	*header;

	header = (struct radius_header *)net_buffer;

		
	rc = recvfrom(acct_fd,
					(char*)net_buffer,
					1500,
					0,
					&incoming_addr,
					&incoming_addr_len );

	if(pending_req[header->identifier].active &&
	   pending_req[header->identifier].code == 4)
	{
		if(header->code==5)
		{
			/*acct_accepts++*/
		}
		else
		{
			/*acct_rejects++*/
		}
		
		pending_req[header->identifier].active = 0;
		pending_reqs--;
	}
	
	return;
}

void sendAcctStartRequest(unsigned long port, const char *username, char *class_attr, uint32_t framed_ip_addr)
{
	unsigned char			id, *buffer, md5_digest[16];
	int						rc;
	struct radius_header	*req_header;
	char					session_id_str[10];
	unsigned long			value;
	unsigned short			packet_len;
	
	if(!cfg.send_acct_start)
	{
		return;
	}
	
	rc = findFreeIdentifier(&id);
	
	if( rc != SUCCESS )
	{
		return;
	}

	session_id++;

	insertUser( port, username, session_id, class_attr, framed_ip_addr );

	pending_req[id].code = 4;
	pending_req[id].acct_type = 1;
	pending_req[id].port = port;
	strcpy(pending_req[id].username, username);
	pending_req[id].timestamp = time(NULL);
	
	/* Send Accounting Start Request */		

	req_header = (struct radius_header *)net_buffer;

	req_header->code = 4;
	req_header->identifier = id;
	
	buffer = (unsigned char*)req_header->data;

	value = 0xc0a801aa;
	buffer = addAttribute(AT_NAS_IP_ADDRESS, &nas_ip_adr, buffer);

	buffer = addAttribute(AT_NAS_PORT, &port, buffer);
	
	value = 0; /* Async */
	buffer = addAttribute(AT_NAS_PORT_ID, &value, buffer);

	buffer = addAttribute(AT_USER_NAME, username, buffer);

	if(cfg.called_lineid[0]) buffer = addAttribute(AT_CALLED_STATION_ID, cfg.called_lineid, buffer);

	if(cfg.calling_lineid[0]) buffer = addAttribute(AT_CALLING_STATION_ID, cfg.calling_lineid, buffer);

	value = 1; /* Start */
	buffer = addAttribute(AT_ACCT_STATUS_TYPE, &value, buffer);

	if(class_attr && class_attr[0])
	{
		buffer = addAttribute(AT_CLASS, class_attr, buffer);
	}
	
	value = 1;
	buffer = addAttribute(AT_ACCT_AUTHENTIC, &value, buffer);

	value = 2;
	buffer = addAttribute(AT_SERVICE_TYPE, &value, buffer);

	sprintf(session_id_str, "%09ld", (long)session_id);
	buffer = addAttribute(AT_ACCT_SESSION_ID, session_id_str, buffer);

	value = 1;
	buffer = addAttribute(AT_FRAMED_PROTOCOL, &value, buffer);

	if(!cfg.remember_framed_ip_addr)
	{
		value = session_id + ip_addr;
	}
	else
	{
		value = framed_ip_addr;
	}
	buffer = addAttribute(AT_FRAMED_ADDRESS, &value, buffer);

	memset(req_header->authenticator, 0, AUTHENTICATOR_LENGTH);

	randomVector(buffer);

	packet_len = buffer - net_buffer;
	req_header->length = htons(packet_len);

	md5_calc(md5_digest, net_buffer, packet_len + AUTHENTICATOR_LENGTH);

	memcpy(req_header->authenticator, md5_digest, AUTHENTICATOR_LENGTH );

	rc = sendto(acct_sock_fd,(char*)net_buffer,	(size_t)packet_len,	(int)0,
				&dest_acct_addr,
				sizeof(struct sockaddr));
				
	if( rc != packet_len )
	{
		fprintf(stderr, "sendAcctStartRequest: sendto() failed\n");
	}
	{
		static int i=0;
		if((i++)%16==0) {
			/*sleep for 5 microseconds so the radius server has time to recv() the packets*/
			struct timespec ts;
			ts.tv_sec = 0;
			ts.tv_nsec = 500000;
			/*nanosleep(&ts,NULL);*/
		}
	}
}

void sendAcctStopRequest(unsigned long port, const char *username,
							unsigned long acct_session_id, const char *class_attr, uint32_t framed_ip_addr)
{
	unsigned char			id, *buffer, md5_digest[16];
	int						rc;
	struct radius_header	*req_header;
	unsigned long			value;
	unsigned short			packet_len;
	char					session_id_str[20];
	char					str_value[128];
	
	if(!cfg.send_acct_stop)
	{
		return;
	}
	
	rc = findFreeIdentifier(&id);
	if( rc != SUCCESS )
	{
		return;
	}

	pending_req[id].code = 4;
	pending_req[id].acct_type = 1;
	pending_req[id].port = port;
	strcpy(pending_req[id].username, username);
	pending_req[id].timestamp = time(NULL);

	curr_online--;

	/* Send Accounting Stop Request */

	req_header = (struct radius_header *)net_buffer;

	req_header->code = 4;
	req_header->identifier = id;
	
	buffer = req_header->data;

	value = 0xc0a801aa;
	buffer = addAttribute(AT_NAS_IP_ADDRESS, &nas_ip_adr, buffer);

	buffer = addAttribute(AT_NAS_PORT, &port, buffer);
	
	value = 0; /* Async */
	buffer = addAttribute(AT_NAS_PORT_ID, &value, buffer);

	buffer = addAttribute(AT_USER_NAME, username, buffer);

	if(cfg.called_lineid[0]) buffer = addAttribute(AT_CALLED_STATION_ID, cfg.called_lineid, buffer);

	if(cfg.calling_lineid[0]) buffer = addAttribute(AT_CALLING_STATION_ID, cfg.calling_lineid, buffer);

	value = 2; /* Stop */
	buffer = addAttribute(AT_ACCT_STATUS_TYPE, &value, buffer);

	if(class_attr && class_attr[0])
	{
		buffer = addAttribute(AT_CLASS, class_attr, buffer);
	}
	else if(!cfg.send_auth)
	{
		//fabricate a class attribute
		char fabricated_class_attr[256];
		sprintf(fabricated_class_attr,"BSC1:%ld_%d_1_%d_%d_1_2_-1_1_N_-1",
		        (long)time(0)-duration,
		        (int)port,
		        2504,
		        2504
		       );
		buffer = addAttribute(AT_CLASS, fabricated_class_attr, buffer);
	}
	
	
	value = 1;
	buffer = addAttribute(AT_ACCT_AUTHENTIC, &value, buffer);

	value = 2;
	buffer = addAttribute(AT_SERVICE_TYPE, &value, buffer);

	sprintf(session_id_str, "%09ld", (long)acct_session_id);
	buffer = addAttribute(AT_ACCT_SESSION_ID, session_id_str, buffer);

	value = 1;
	buffer = addAttribute(AT_FRAMED_PROTOCOL, &value, buffer);
	   	
	if(cfg.remember_framed_ip_addr==0)
	{
		value = acct_session_id + ip_addr;
	}
	else
	{
		value = framed_ip_addr;
	}
	buffer = addAttribute(AT_FRAMED_ADDRESS, &value, buffer);

	value = 8000;
	buffer = addAttribute(AT_ACCT_INPUT_OCTETS, &value, buffer);

	value = 800;
	buffer = addAttribute(AT_ACCT_OUTPUT_OCTETS, &value, buffer);

	value = 100;
	buffer = addAttribute(AT_ACCT_INPUT_PACKETS, &value, buffer);

	value = 10;
	buffer = addAttribute(AT_ACCT_OUTPUT_PACKETS, &value, buffer);

	buffer = addAttribute(AT_ACCT_SESSION_TIME, &duration, buffer);

	if ( cfg.use_voip_accounting )
	{
		char val[9];
		char valid_chars[] = {"01234567890abcdef"};
		
		if(h323_conf_id_semiunique==0) {
			struct sockaddr_in my_address;

            #ifdef linux
			socklen_t sl = sizeof(my_address);
            #else
			int sl = sizeof(my_address);
            #endif

			getsockname(acct_sock_fd, (struct sockaddr*)&my_address, &sl);
			h323_conf_id_semiunique = (getpid()<<16) | my_address.sin_port;
		}
	
		sprintf(str_value, "h323-conf-id=01234567 %8x %8x ", h323_conf_id_sequencer++, h323_conf_id_semiunique);
		
		for (int i=0; i <= 7; i++)
			val[i] = valid_chars[rand() % 16];
		val[8] = 0;
		strcat(str_value, val);

		buffer = addVendorAttribute(VENDOR_CISCO, CISCO_VSA_CONNECTION_ID, 
			str_value, buffer);
		
		buffer = addVendorAttribute(VENDOR_CISCO, CISCO_VSA_SETUP_TIME,
			"h323-setup-time=09:30:00.000 UTC Fri Dec 10 1999", buffer);
			
		buffer = addVendorAttribute(VENDOR_CISCO, CISCO_VSA_CONNECT_TIME,
			"h323-connect-time=09:30:00.000 UTC Fri Dec 10 1999", buffer);
		
		buffer = addVendorAttribute(VENDOR_CISCO, CISCO_VSA_DISCONNECT_TIME,
			"h323-disconnect-time=09:30:50.000 UTC Fri Dec 10 1999", buffer);
			
		buffer = addVendorAttribute(VENDOR_CISCO, CISCO_VSA_GW_ID,
			"h323-gw-id=192.168.1.149", buffer);
			
		buffer = addVendorAttribute(VENDOR_CISCO, CISCO_VSA_CALL_ORIGIN,
			"h323-call-origin=originate", buffer);
		
		buffer = addVendorAttribute(VENDOR_CISCO, CISCO_VSA_CALL_TYPE,
			"h323-call-type=VoIP", buffer);
		
		buffer = addVendorAttribute(VENDOR_CISCO, CISCO_VSA_DISCONNECT_CAUSE,
			"h323-disconnect-cause=10", buffer);

		buffer = addVendorAttribute(VENDOR_CISCO, CISCO_VSA_VOICE_QUALITY,
			"h323-voice-quality=0", buffer);
	}

	bzero(req_header->authenticator, AUTHENTICATOR_LENGTH);

	randomVector(buffer);

	packet_len = buffer - net_buffer;
	req_header->length = htons(packet_len);

	md5_calc(md5_digest, net_buffer, packet_len + AUTHENTICATOR_LENGTH);

	memcpy(req_header->authenticator, md5_digest, AUTHENTICATOR_LENGTH );

	char hex_str[2048];
	bintohex((char*)net_buffer, packet_len, hex_str);
	
/*	printf("Accounting stop packet:%s\n\n", hex_str);
*/

	rc = sendto(acct_sock_fd,
				(char*)net_buffer,
				packet_len,
				0,
				&dest_acct_addr,
				sizeof(struct sockaddr));
				
	if( rc != packet_len )
	{
		fprintf(stderr, "sendAcctStopRequest: sendto() failed\n");
	}	
}

void sendUnauthenticatedAcctStopRequest()
{
	unsigned long port;
	char username[64];
	uint32_t framed_ip_addr;
	unsigned long acct_session_id;
	unsigned long user_num = nextUserNum();
	
//	sprintf(username,"%s%010d", prefix, current_user_num);
    if(cfg.username_digits==0)
	    sprintf(username,"%s%ld", prefix, (long)user_num);
	else
	    sprintf(username,"%s%0*ld", prefix, cfg.username_digits, (long)user_num);
	port = user_num;
	framed_ip_addr = ::ip_addr + user_num;
	acct_session_id = user_num;
	
	sendAcctStopRequest(port, username, acct_session_id, NULL, framed_ip_addr);
	curr_online--;
}

void sendAuthRequest()
{
	unsigned char			id;
	char					username[64];
	int						rc, i;
	struct radius_header	*req_header;
	unsigned char			md5_digest[16], *password_ptr, *buffer;
	unsigned long			value, port;
	unsigned short			packet_len;
	unsigned long           user_num = nextUserNum();
	
	rc = findFreeIdentifier(&id);
	
	if( rc != SUCCESS )
	{
		return;
	}
	
//	sprintf( username, "%s%010d", prefix, current_user_num);
    if(cfg.username_digits==0)
	    sprintf(username,"%s%ld", prefix, (long)user_num);
	else
	    sprintf(username,"%s%0*ld", prefix, cfg.username_digits, (long)user_num);
	
	port = user_num;
	
	
	pending_req[id].code = 1;
	pending_req[id].port = port;
	strcpy( pending_req[id].username, username);
		
	/* Send Authentication Request */

	req_header = (struct radius_header *)net_buffer;

	req_header->code = 1;
	req_header->identifier = id;
	
	buffer = req_header->data;

	value = 0xc0a801aa;
	buffer = addAttribute(AT_NAS_IP_ADDRESS, &nas_ip_adr, buffer);

	buffer = addAttribute(AT_NAS_PORT, &port, buffer);
	
	value = 0; /* Async */
	buffer = addAttribute(AT_NAS_PORT_ID, &value, buffer);

	buffer = addAttribute(AT_USER_NAME, username, buffer);

	if(cfg.called_lineid[0]) buffer = addAttribute(AT_CALLED_STATION_ID, cfg.called_lineid, buffer);

	if(cfg.calling_lineid[0]) buffer = addAttribute(AT_CALLING_STATION_ID, cfg.calling_lineid, buffer);

	/* Save position of password attribute */

	password_ptr = buffer;
	
	buffer = addAttribute(AT_USER_PASSWORD, user_password, buffer);
	
	value = 2;
	buffer = addAttribute(AT_SERVICE_TYPE, &value, buffer);

	value = 1;
	buffer = addAttribute(AT_FRAMED_PROTOCOL, &value, buffer);

	randomVector(req_header->authenticator);
	
	packet_len = buffer - net_buffer;
	req_header->length = htons(packet_len);

	/* Encrypt password attribute value */

	memcpy(tmp_buffer + shared_secret_len,
			req_header->authenticator,
			AUTHENTICATOR_LENGTH );
			
	memcpy(tmp_buffer, shared_secret, shared_secret_len);

	md5_calc(md5_digest, tmp_buffer, shared_secret_len + AUTHENTICATOR_LENGTH );

    for( i = 0 ; i < 16 ; i++ )
    {
		password_ptr[2 + i] ^= md5_digest[i];
    }

	rc = sendto(auth_sock_fd,
				(char*)net_buffer,
				packet_len,
				0,
				&dest_auth_addr,
				sizeof(struct sockaddr));
				
	if( rc != packet_len )
	{
		fprintf(stderr, "sendAuthRequest: sendto() failed\n");
	}
}

void sendUnauthenticatedAcctStartRequest() {
	//Send a acct-start packet without any preceding authentication
	unsigned long port;
	char username[64];
	uint32_t framed_ip_addr;
	unsigned long user_num = nextUserNum();
	
//	sprintf(username,"%s%010d", prefix, current_user_num);
    if(cfg.username_digits==0)
	    sprintf(username,"%s%ld", prefix, (long)user_num);
	else
	    sprintf(username,"%s%0*ld", prefix, cfg.username_digits, (long)user_num);
	port = user_num;
	framed_ip_addr = ::ip_addr + user_num;
	
	
	sendAcctStartRequest(port, username, NULL, framed_ip_addr);
	curr_online++;
}


int findFreeIdentifier(unsigned char *new_id)
{
	int			i;
	
	for( i = 0 ; i <= 256 ; i++ )
	{
		global_identifier++;

		if( !pending_req[global_identifier].active )
		{
			pending_req[global_identifier].active = 1;
			pending_req[global_identifier].timestamp = time(NULL);
			pending_req[global_identifier].precise_ts = get_precise_time();
		
			*new_id = global_identifier;
			
			pending_reqs++;
			
			return SUCCESS;
		}
	}
	
	out_of_ids++;
	return FAILED;
}

int openUDPSocket()
{
	int fd, result;

	struct sockaddr salocal;
	struct sockaddr_in *sin;

	fd = socket (AF_INET, SOCK_DGRAM, 0);
	
	if (fd < 0)
	{
		(void) perror ("socket");
		return -1;
    }
    
	sin = (struct sockaddr_in *) & salocal;
	memset ((char *) sin, '\0', sizeof (salocal));
	sin->sin_family = AF_INET;
	sin->sin_addr.s_addr = INADDR_ANY;
	sin->sin_port = htons(0);
          
	result = bind (fd, & salocal, sizeof (*sin));

	if (result < 0) 
	{
		(void) perror ("bind");
		return -1;
	}
    
	return fd;
}

int getRadiusSocket(struct sockaddr *saradius, char *ip, int port)
{
	struct sockaddr_in *sin;

	sin = (struct sockaddr_in *) saradius;
	memset ((char *) sin, '\0', sizeof (struct sockaddr));
	sin->sin_family = AF_INET;

	sin->sin_addr.s_addr = 0;
	
	if( (sin->sin_addr.s_addr = string2ip(ip)) == 0 ) 
	{
		(void) perror ("radius ip address");
		return 0;
	}
    
	sin->sin_port = htons(port);
	return 1;
}

void randomVector(unsigned char *vector)
{
	int randno;
	int i;

	for( i = 0 ; i < AUTHENTICATOR_LENGTH ; )
	{
		randno = rand();
		memcpy(vector, &randno, sizeof(int));
		vector += sizeof(int);
		i += sizeof(int);
	}
}

void insertUser(unsigned long port, const char *username,
				unsigned long acct_session_id, const char *class_attr, uint32_t framed_ip_addr)
{
	struct logged_on_user	*ptr;
	
	ptr = (struct logged_on_user *)malloc(sizeof(struct logged_on_user));

	ptr->port = port;
	ptr->session_id = acct_session_id;
	strcpy( ptr->username, username);
	if(class_attr)
	{
		strcpy( ptr->class_attr, class_attr);
	}
	else
	{
		ptr->class_attr[0]='\0';
	}
	ptr->framed_ip_addr = framed_ip_addr;
	ptr->timestamp = time(NULL) + duration;
	ptr->next = NULL;
	
	if( user_bottom == NULL )
	{
        fprintf(stderr, "First time: adding user to list\n");
        printf("user top [%p]\n", ptr);
		user_top = ptr;
 

	}
	else
	{
        fprintf(stderr, "Adding user to list [%p]\n", ptr);
		user_bottom->next = ptr;
	}
	
	user_bottom = ptr;
    if (user_top->next != NULL && user_top==NULL) 
    {
        fprintf(stderr, "top Something is really wrong!");
    }
    if (user_bottom->next != NULL && user_bottom==NULL)
    {
          fprintf(stderr, "bottom Something is really wrong!");
    }   
}

unsigned char *addAttribute(unsigned char type, const void *value, unsigned char *ptr)
{
	int i;
	unsigned char *start_ptr;

	for( i = 0 ; attributeType[i].type != 0 ; i++ )
	{
		if( attributeType[i].type == type )
		{
			start_ptr = ptr;
			*ptr++ = type;
	
			switch( attributeType[i].value_type )
			{
				case VT_STRING:
					if( type != AT_USER_PASSWORD )
					{
						*ptr++ = strlen((char*)value) + 2;
						memcpy(ptr, (char*)value, strlen((char*)value));
						ptr += strlen((char*)value);
					}
					else
					{
						*ptr++ = 18;
						memset(ptr, 0, 18);
						memcpy(ptr, (char*)value, strlen((char*)value));
						ptr += 16;
					}
					break;
					
				case VT_ADDRESS:
				case VT_TIME:
				case VT_INTEGER: {
					uint32_t nvalue;
					*ptr++ = sizeof(long) + 2;
					nvalue = htonl( *((long*)value) );
					memcpy(ptr, &nvalue, 4);
					ptr += 4;
					break;
			    }
		
				default:
					printf("Unknown attribute!\n");
					return 0;
			}
		}
	}
	return ptr;
}

unsigned char * addVendorAttribute(uint32_t vendor_id, unsigned char vendor_type, const char *value, unsigned char *ptr)
{
	int value_len = strlen(value);

	/* set the attribute type to vendor specific */
	*ptr++ = VENDOR_SPECIFIC;

	/* set the total length of the attribute */
	*ptr++ = 2 + 4 + 1 + 1 + value_len;
	
	/* set the vendor ID (4 bytes) */
	vendor_id = htonl(vendor_id);
	memcpy(ptr, &vendor_id, 4);
	ptr+=4;
	
	/* set the vendor attribute type */
	*ptr++ = vendor_type;
	
	/* set the vendor attribute length */
	*ptr++ = value_len + 2;

	/* copy the attribute value */
	memcpy(ptr, (char*)value, value_len);
	ptr += value_len;
	
	return ptr;
}

double get_precise_time()
{
    #ifdef linux

    struct timeval tv;
    struct timezone tz;

    tz.tz_minuteswest = 120;

    gettimeofday(&tv, &tz);
    return (tv.tv_sec + (double)tv.tv_usec/1000000);

    #else

    struct timespec mytime;

    clock_gettime(0, &mytime);
    return(mytime.tv_sec + (double)mytime.tv_nsec/NANOSEC);

    #endif
}

long string2ip(const char *s) {
	struct hostent *he;
	he = gethostbyname((char*)s);
	if(!he) return 0;
	uint32_t ip;
	memcpy(&ip,he->h_addr_list[0],4);
	return ip;
}

static unsigned long nextUserNum() {
    unsigned long user_num;
	if(cfg.username_distribution==sequential_mode)
	{
	    user_num = current_user_num;
	    if(current_user_num==(unsigned long)cfg.to_num)
	        current_user_num = cfg.from_num;
	    else
	        current_user_num++;
	}
	else
	{
	    user_num = from_num + my_32bit_rand()%(cfg.to_num-cfg.from_num);
	}
	return user_num;
}

int my_32bit_rand() {
    static int l=0;
    int r = rand();
    l = ((l<<5) ^ r)&0x7fffffff;
    return l;
}


More information about the Python-list mailing list