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

📄 listen.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * listen.c	Handle socket stuff * * Version:	$Id: listen.c,v 1.122 2008/04/20 15:00:06 aland 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2005,2006  The FreeRADIUS server project * Copyright 2005  Alan DeKok <aland@ox.org> */#include <freeradius-devel/ident.h>RCSID("$Id: listen.c,v 1.122 2008/04/20 15:00:06 aland Exp $")#include <freeradius-devel/radiusd.h>#include <freeradius-devel/radius_snmp.h>#include <freeradius-devel/modules.h>#include <freeradius-devel/rad_assert.h>#include <freeradius-devel/vqp.h>#include <freeradius-devel/dhcp.h>#include <freeradius-devel/vmps.h>#include <freeradius-devel/detail.h>#ifdef HAVE_SYS_RESOURCE_H#include <sys/resource.h>#endif#ifdef HAVE_NET_IF_H#include <net/if.h>#endif#ifdef HAVE_FCNTL_H#include <fcntl.h>#endif/* *	We'll use this below. */typedef int (*rad_listen_parse_t)(CONF_SECTION *, rad_listen_t *);typedef void (*rad_listen_free_t)(rad_listen_t *);typedef struct rad_listen_master_t {	rad_listen_parse_t	parse;	rad_listen_free_t	free;	rad_listen_recv_t	recv;	rad_listen_send_t	send;	rad_listen_print_t	print;	rad_listen_encode_t	encode;	rad_listen_decode_t	decode;} rad_listen_master_t;typedef struct listen_socket_t {	/*	 *	For normal sockets.	 */	fr_ipaddr_t	ipaddr;	int		port;	RADCLIENT_LIST	*clients;} listen_socket_t;/* *	Find a per-socket client. */RADCLIENT *client_listener_find(const rad_listen_t *listener,				       const fr_ipaddr_t *ipaddr){	const RADCLIENT_LIST *clients;	rad_assert(listener != NULL);	rad_assert(ipaddr != NULL);	rad_assert((listener->type == RAD_LISTEN_AUTH) ||		   (listener->type == RAD_LISTEN_ACCT) ||		   (listener->type == RAD_LISTEN_VQP) ||		   (listener->type == RAD_LISTEN_DHCP));	clients = ((listen_socket_t *)listener->data)->clients;	/*	 *	This HAS to have been initialized previously.	 */	rad_assert(clients != NULL);	return client_find(clients, ipaddr);}static int listen_bind(rad_listen_t *this);/* *	Process and reply to a server-status request. *	Like rad_authenticate and rad_accounting this should *	live in it's own file but it's so small we don't bother. */static int rad_status_server(REQUEST *request){	int rcode = RLM_MODULE_OK;	DICT_VALUE *dval;	switch (request->listener->type) {	case RAD_LISTEN_AUTH:		dval = dict_valbyname(PW_AUTZ_TYPE, "Status-Server");		if (dval) {			rcode = module_authorize(dval->value, request);		} else {			rcode = RLM_MODULE_OK;		}		switch (rcode) {		case RLM_MODULE_OK:		case RLM_MODULE_UPDATED:			request->reply->code = PW_AUTHENTICATION_ACK;			break;		case RLM_MODULE_FAIL:		case RLM_MODULE_HANDLED:			request->reply->code = 0; /* don't reply */			break;		default:		case RLM_MODULE_REJECT:			request->reply->code = PW_AUTHENTICATION_REJECT;			break;		}		break;	case RAD_LISTEN_ACCT:		dval = dict_valbyname(PW_ACCT_TYPE, "Status-Server");		if (dval) {			rcode = module_accounting(dval->value, request);		} else {			rcode = RLM_MODULE_OK;		}		switch (rcode) {		case RLM_MODULE_OK:		case RLM_MODULE_UPDATED:			request->reply->code = PW_ACCOUNTING_RESPONSE;			break;		default:			request->reply->code = 0; /* don't reply */			break;		}		break;	default:		return 0;	}	return 0;}static int socket_print(rad_listen_t *this, char *buffer, size_t bufsize){	listen_socket_t *sock = this->data;	const char *name;	char ip_buf[256];	if ((sock->ipaddr.af == AF_INET) &&	    (sock->ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY))) {		strcpy(ip_buf, "*");	} else {		ip_ntoh(&sock->ipaddr, ip_buf, sizeof(ip_buf));	}	switch (this->type) {	case RAD_LISTEN_AUTH:		name = "authentication";		break;	case RAD_LISTEN_ACCT:		name = "accounting";		break;	case RAD_LISTEN_PROXY:		name = "proxy";		break;#ifdef WITH_VMPS	case RAD_LISTEN_VQP:		name = "vmps";		break;#endif#ifdef WITH_DHCP	case RAD_LISTEN_DHCP:		name = "dhcp";		break;#endif	default:		name = "??";		break;	}	if (!this->server) {		return snprintf(buffer, bufsize, "%s address %s port %d",				name, ip_buf, sock->port);	}	return snprintf(buffer, bufsize, "%s address %s port %d as server %s",			name, ip_buf, sock->port, this->server);}/* *	Parse an authentication or accounting socket. */static int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this){	int		rcode;	int		listen_port;	fr_ipaddr_t	ipaddr;	listen_socket_t *sock = this->data;	char		*section_name = NULL;	CONF_SECTION	*client_cs, *parentcs;	/*	 *	Try IPv4 first	 */	ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);	rcode = cf_item_parse(cs, "ipaddr", PW_TYPE_IPADDR,			      &ipaddr.ipaddr.ip4addr, NULL);	if (rcode < 0) return -1;	if (rcode == 0) { /* successfully parsed IPv4 */		ipaddr.af = AF_INET;	} else {	/* maybe IPv6? */		rcode = cf_item_parse(cs, "ipv6addr", PW_TYPE_IPV6ADDR,				      &ipaddr.ipaddr.ip6addr, NULL);		if (rcode < 0) return -1;		if (rcode == 1) {			cf_log_err(cf_sectiontoitem(cs),				   "No address specified in listen section");			return -1;		}		ipaddr.af = AF_INET6;	}	rcode = cf_item_parse(cs, "port", PW_TYPE_INTEGER,			      &listen_port, "0");	if (rcode < 0) return -1;	if ((listen_port < 0) || (listen_port > 65500)) {			cf_log_err(cf_sectiontoitem(cs),				   "Invalid value for \"port\"");			return -1;	}	sock->ipaddr = ipaddr;	sock->port = listen_port;	/*	 *	And bind it to the port.	 */	if (listen_bind(this) < 0) {		char buffer[128];		cf_log_err(cf_sectiontoitem(cs),			   "Error binding to port for %s port %d",			   ip_ntoh(&sock->ipaddr, buffer, sizeof(buffer)),			   sock->port);		return -1;	}	/*	 *	If we can bind to interfaces, do so,	 *	else don't.	 */	if (cf_pair_find(cs, "interface")) {#ifndef SO_BINDTODEVICE		cf_log_err(cf_sectiontoitem(cs),			   "System does not support binding to interfaces.  Delete this line from the configuration file.");		return -1;#else		const char *value;		CONF_PAIR *cp = cf_pair_find(cs, "interface");		struct ifreq ifreq;		rad_assert(cp != NULL);		value = cf_pair_value(cp);		if (!value) {			cf_log_err(cf_sectiontoitem(cs),				   "No interface name given");			return -1;		}		strcpy(ifreq.ifr_name, value);		if (setsockopt(this->fd, SOL_SOCKET, SO_BINDTODEVICE,			       (char *)&ifreq, sizeof(ifreq)) < 0) {			cf_log_err(cf_sectiontoitem(cs),				   "Failed binding to interface %s: %s",				   value, strerror(errno));			return -1;		} /* else it worked. */#endif	}	/*	 *	Proxy sockets don't have clients.	 */	if (this->type == RAD_LISTEN_PROXY) return 0;		/*	 *	The more specific configurations are preferred to more	 *	generic ones.	 */	client_cs = NULL;	parentcs = cf_top_section(cs);	rcode = cf_item_parse(cs, "clients", PW_TYPE_STRING_PTR,			      &section_name, NULL);	if (rcode < 0) return -1; /* bad string */	if (rcode == 0) {		/*		 *	Explicit list given: use it.		 */		client_cs = cf_section_sub_find_name2(parentcs,						      "clients",						      section_name);		if (!client_cs) {			client_cs = cf_section_find(section_name);		}		if (!client_cs) {			cf_log_err(cf_sectiontoitem(cs),				   "Failed to find clients %s {...}",				   section_name);			free(section_name);			return -1;		}		free(section_name);	} /* else there was no "clients = " entry. */	if (!client_cs) {		CONF_SECTION *server_cs;		server_cs = cf_section_sub_find_name2(parentcs,						      "server",						      this->server);		/*		 *	Found a "server foo" section.  If there are clients		 *	in it, use them.		 */		if (server_cs &&		    (cf_section_sub_find(server_cs, "client") != NULL)) {			client_cs = server_cs;		}	}	/*	 *	Still nothing.  Look for global clients.	 */	if (!client_cs) client_cs = parentcs;	sock->clients = clients_parse_section(client_cs);	if (!sock->clients) {		cf_log_err(cf_sectiontoitem(cs),			   "Failed to find any clients for this listen section");		return -1;	}	return 0;}/* *	Send an authentication response packet */static int auth_socket_send(rad_listen_t *listener, REQUEST *request){	rad_assert(request->listener == listener);	rad_assert(listener->send == auth_socket_send);	return rad_send(request->reply, request->packet,			request->client->secret);}/* *	Send an accounting response packet (or not) */static int acct_socket_send(rad_listen_t *listener, REQUEST *request){	rad_assert(request->listener == listener);	rad_assert(listener->send == acct_socket_send);	/*	 *	Accounting reject's are silently dropped.	 *	 *	We do it here to avoid polluting the rest of the	 *	code with this knowledge	 */	if (request->reply->code == 0) return 0;	return rad_send(request->reply, request->packet,			request->client->secret);}/* *	Send a packet to a home server. * *	FIXME: have different code for proxy auth & acct! */static int proxy_socket_send(rad_listen_t *listener, REQUEST *request){	listen_socket_t *sock = listener->data;	rad_assert(request->proxy_listener == listener);	rad_assert(listener->send == proxy_socket_send);	request->proxy->src_ipaddr = sock->ipaddr;	request->proxy->src_port = sock->port;	return rad_send(request->proxy, request->packet,			request->home_server->secret);}/* *	Check if an incoming request is "ok" * *	It takes packets, not requests.  It sees if the packet looks *	OK.  If so, it does a number of sanity checks on it.  */static int auth_socket_recv(rad_listen_t *listener,			    RAD_REQUEST_FUNP *pfun, REQUEST **prequest){	ssize_t		rcode;	int		code, src_port;	RADIUS_PACKET	*packet;	RAD_REQUEST_FUNP fun = NULL;	char		buffer[128];	RADCLIENT	*client;	fr_ipaddr_t	src_ipaddr;	rcode = rad_recv_header(listener->fd, &src_ipaddr, &src_port, &code);	if (rcode < 0) return 0;	RAD_SNMP_TYPE_INC(listener, total_requests);	if (rcode < 20) {	/* AUTH_HDR_LEN */		RAD_SNMP_TYPE_INC(listener, total_malformed_requests);		return 0;	}	if ((client = client_listener_find(listener,					   &src_ipaddr)) == NULL) {		rad_recv_discard(listener->fd);		RAD_SNMP_TYPE_INC(listener, total_invalid_requests);		if (debug_flag > 0) {			char name[1024];			listener->print(listener, name, sizeof(name));			/*			 *	This is debugging rather than logging, so that			 *	DoS attacks don't affect us.			 */			DEBUG("Ignoring request to %s from unknown client %s port %d",			      name,			      inet_ntop(src_ipaddr.af, &src_ipaddr.ipaddr,					buffer, sizeof(buffer)), src_port);		}		return 0;	}	/*	 *	Some sanity checks, based on the packet code.	 */	switch(code) {	case PW_AUTHENTICATION_REQUEST:		RAD_SNMP_CLIENT_INC(listener, client, requests);		fun = rad_authenticate;		break;	case PW_STATUS_SERVER:		if (!mainconfig.status_server) {			rad_recv_discard(listener->fd);			RAD_SNMP_TYPE_INC(listener, total_packets_dropped);			RAD_SNMP_CLIENT_INC(listener, client, packets_dropped);

⌨️ 快捷键说明

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