view extensions/radius_gw/rgw_servers.c @ 358:505a9ee1244b

Separated attributes and codes string definitions to inc files
author Sebastien Decugis <sdecugis@nict.go.jp>
date Wed, 20 May 2009 15:14:31 +0900
parents 555dc5a58aef
children 9fd830f8621a
line wrap: on
line source

/*********************************************************************************************************
* Software License Agreement (BSD License)                                                               *
* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
*													 *
* Copyright (c) 2008, WIDE Project and NICT								 *
* All rights reserved.											 *
* 													 *
* Redistribution and use of this software in source and binary forms, with or without modification, are  *
* permitted provided that the following conditions are met:						 *
* 													 *
* * Redistributions of source code must retain the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer.										 *
*    													 *
* * Redistributions in binary form must reproduce the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer in the documentation and/or other						 *
*   materials provided with the distribution.								 *
* 													 *
* * Neither the name of the WIDE Project or NICT nor the 						 *
*   names of its contributors may be used to endorse or 						 *
*   promote products derived from this software without 						 *
*   specific prior written permission of WIDE Project and 						 *
*   NICT.												 *
* 													 *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
*********************************************************************************************************/

/* Manage the server(s): opening sockets, receiving messages, ... */

#include "radius_gw_internal.h"

#define RADIUS_MAX_MSG_LEN 3000


/* Declare the rgw_servers */
struct rgw_servs rgw_servers;

void rgw_servers_dump(void)
{
	char ipstr[INET6_ADDRSTRLEN];
	
	if ( ! TRACE_BOOL(FULL) )
		return;
	
	log_debug(" auth server:\n");
	log_debug("    disabled..... : %s\n", rgw_servers.auth_serv.disabled ? "TRUE":"false");
	log_debug("    IP disabled.. : %s\n", rgw_servers.auth_serv.ip_disabled ? "TRUE":"false");
	log_debug("    IPv6 disabled : %s\n", rgw_servers.auth_serv.ip6_disabled ? "TRUE":"false");
	log_debug("    port......... : %hu\n", ntohs(rgw_servers.auth_serv.port));
	inet_ntop(AF_INET, &rgw_servers.auth_serv.ip_endpoint,ipstr,sizeof(ipstr));
	log_debug("    IP bind...... : %s\n", ipstr);
	inet_ntop(AF_INET6, &rgw_servers.auth_serv.ip6_endpoint,ipstr,sizeof(ipstr));
	log_debug("    IPv6 bind.... : %s\n", ipstr);

	log_debug(" acct server:\n");
	log_debug("    disabled..... : %s\n", rgw_servers.acct_serv.disabled ? "TRUE":"false");
	log_debug("    IP disabled.. : %s\n", rgw_servers.acct_serv.ip_disabled ? "TRUE":"false");
	log_debug("    IPv6 disabled : %s\n", rgw_servers.acct_serv.ip6_disabled ? "TRUE":"false");
	log_debug("    port......... : %hu\n", ntohs(rgw_servers.acct_serv.port));
	inet_ntop(AF_INET, &rgw_servers.acct_serv.ip_endpoint,ipstr,sizeof(ipstr));
	log_debug("    IP bind...... : %s\n", ipstr);
	inet_ntop(AF_INET6, &rgw_servers.acct_serv.ip6_endpoint,ipstr,sizeof(ipstr));
	log_debug("    IPv6 bind.... : %s\n", ipstr);

}

static struct servers_data {
	int	port; /* auth or acct */
	int	sock; /* the socket number */
	pthread_t th; /* the running server thread, or NULL */
	char    name[10];
} SERVERS[4];

int rgw_servers_init(void)
{
	memset(&rgw_servers, 0, sizeof(rgw_servers));
	memset(&SERVERS[0], 0, sizeof(SERVERS));

	rgw_servers.auth_serv.port = htons(1812);
	rgw_servers.auth_serv.ip_endpoint.s_addr = INADDR_ANY;
	memcpy(&rgw_servers.auth_serv.ip6_endpoint, &in6addr_any, sizeof(struct in6_addr));
	
	rgw_servers.acct_serv.port = htons(1813);
	rgw_servers.acct_serv.ip_endpoint.s_addr = INADDR_ANY;
	memcpy(&rgw_servers.acct_serv.ip6_endpoint, &in6addr_any, sizeof(struct in6_addr));
	
	
	return 0;
}

static void * server_thread(void * param)
{
	struct servers_data * me = (struct servers_data *)param;
	
	TRACE_ENTRY("%p", param);
	
	CHECK_PARAMS_DO(param, return NULL);
	
	log_set_thread_name( me->name, "rgw server" );
	
	/* Now loop on this socket, parse and queue each message received, until thread is cancelled. */
	while (1) {
		struct sockaddr_storage from;
		unsigned char * buf = NULL;
		socklen_t fromlen = sizeof(from);
		int len;
		rad_t * msg = NULL;
		void * nas_info = NULL;
		
		pthread_testcancel();
		
		CHECK_MALLOC_DO( buf = malloc(RADIUS_MAX_MSG_LEN), break );
		memset(buf, 0, RADIUS_MAX_MSG_LEN);
		
		/* read the next message */
		CHECK_SYS_DO( len = recvfrom( me->sock, buf, RADIUS_MAX_MSG_LEN, 0, (struct sockaddr *) &from, &fromlen),  break );
		{
			char ipstr[INET6_ADDRSTRLEN];
			uint16_t port;
			
			switch (from.ss_family) {
				case AF_INET:
					inet_ntop(AF_INET, &((struct sockaddr_in *)&from)->sin_addr,ipstr,sizeof(ipstr));
					port = ((struct sockaddr_in *)&from)->sin_port;
					break;
				case AF_INET6:
					inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&from)->sin6_addr,ipstr,sizeof(ipstr));
					port = ((struct sockaddr_in6 *)&from)->sin6_port;
					break;
				default:
					snprintf(ipstr,sizeof(ipstr),"(unknown AF:%d)", from.ss_family);
					port = 0;
			}
			
			TRACE_DEBUG(FULL, "Received %d bytes from [%s]:%hu", len, ipstr, ntohs(port));
		}
		
		/* parse the message or loop if message is bad */
		CHECK_FCT_DO( rgw_msg_parse(buf, len, &msg), 
			{ 
				TRACE_DEBUG(INFO, "Discarding invalid RADIUS message");
				free(buf); 
				continue; 
			} );
		
		/* Free the buffer, we don't need it anymore */
		free(buf);
		
		rg_msg_dump(FULL, msg);
		
		/* Search the associated client definition, if any */
		CHECK_FCT_DO( rgw_clients_search((struct sockaddr *) &from, &nas_info),
			{
				TRACE_DEBUG(INFO, "Discarding message from unknown RADIUS client");
				rg_msg_free(msg);
				continue;
			} );
				
		
		/* queue the message for a worker thread */
		CHECK_FCT_DO( rgw_work_add(msg, nas_info), break );
		
		/* Then wait for next incoming message */
	}
	
	return NULL;
	
}

/* Set the socket options for UDP sockets, before bind is called */
static int _udp_setsockopt(int family, int sk)
{
	int ret = 0;
	int opt;
	
	/* In case of v6 address, force the v6only option, we use a different socket for v4 */
	#ifdef IPV6_V6ONLY
	if (family == AF_INET6) {
		opt = 1;
		ret = setsockopt(sk, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
		if (ret != 0) {
			ret = errno;
			TRACE_DEBUG(INFO, "Unable to set the socket IPV6_V6ONLY option: %s", strerror(ret));
			return ret;
		}
	}
	#endif /* IPV6_V6ONLY */
	
	return 0;
}

#define UDPSERV( type, portval, family ) {									\
	if ( (! rgw_servers. type ## _serv.disabled) 								\
		&& ( ! rgw_servers.auth_serv.ip ## family ## _disabled ) ) {					\
			struct sockaddr_in ## family sin ## family;						\
			CHECK_SYS( SERVERS[idx].sock = socket(AF_INET ## family, SOCK_DGRAM, 0) );		\
			memset(& sin ## family, 0, sizeof(struct sockaddr_in ## family));			\
			sin ## family . sin ## family ## _family = AF_INET ## family;				\
			sin ## family . sin ## family ## _port = rgw_servers. type ## _serv . port;		\
			memcpy( &sin ## family.sin ## family ## _addr, 						\
					&rgw_servers. type ## _serv . ip ## family ## _endpoint,		\
					sizeof(struct in ## family ## _addr) );					\
			TRACE_DEBUG(ANNOYING, "Setting socket options...");					\
			CHECK_FCT( _udp_setsockopt(AF_INET ## family, SERVERS[idx].sock) );			\
			TRACE_DEBUG(ANNOYING, "Binding " #type " ip" #family " server...");			\
			CHECK_SYS( bind( SERVERS[idx].sock,							\
					(struct sockaddr *)&sin ## family,					\
					sizeof(struct sockaddr_in ## family) ) );				\
			SERVERS[idx].port = portval;								\
			snprintf(&SERVERS[idx].name[0], sizeof(SERVERS[idx].name), # type "/ip" #family);	\
			CHECK_POSIX( pthread_create(&SERVERS[idx].th, NULL, server_thread, &SERVERS[idx]) );	\
			idx++;											\
	}													\
}
	

int rgw_servers_start(void)
{
	int idx = 0;
	
	TRACE_ENTRY();
	
	UDPSERV( auth, RGW_EXT_PORT_AUTH,  );
	UDPSERV( auth, RGW_EXT_PORT_AUTH, 6 );
	UDPSERV( acct, RGW_EXT_PORT_ACCT,  );
	UDPSERV( acct, RGW_EXT_PORT_ACCT, 6 );
	
	TRACE_DEBUG(FULL, "%d UDP servers started succesfully.", idx);
	return 0;
}

void rgw_servers_fini(void)
{
	int idx = 0;
	
	for (idx = 0; idx < sizeof(SERVERS) / sizeof(SERVERS[0]); idx++) {
		if (SERVERS[idx].sock == 0)
			break;
		
		CHECK_FCT_DO( _thread_term(&SERVERS[idx].th), /* continue */ );
		close(SERVERS[idx].sock);
		SERVERS[idx].sock = 0;
	}
	
}


"Welcome to our mercurial repository"