Open RADIUS accounting sockets to exchange accounting messages

This commit is contained in:
Martin Willi
2012-01-30 19:15:20 +01:00
parent a69aff5f17
commit 8e5b4aa023
5 changed files with 92 additions and 47 deletions
@@ -23,9 +23,14 @@
#include <threading/rwlock.h> #include <threading/rwlock.h>
/** /**
* Default RADIUS server port, when not configured * Default RADIUS server port for authentication
*/ */
#define RADIUS_PORT 1812 #define AUTH_PORT 1812
/**
* Default RADIUS server port for accounting
*/
#define ACCT_PORT 1813
typedef struct private_eap_radius_plugin_t private_eap_radius_plugin_t; typedef struct private_eap_radius_plugin_t private_eap_radius_plugin_t;
@@ -63,7 +68,7 @@ static void load_servers(private_eap_radius_plugin_t *this)
enumerator_t *enumerator; enumerator_t *enumerator;
radius_server_t *server; radius_server_t *server;
char *nas_identifier, *secret, *address, *section; char *nas_identifier, *secret, *address, *section;
int port, sockets, preference; int auth_port, acct_port, sockets, preference;
address = lib->settings->get_str(lib->settings, address = lib->settings->get_str(lib->settings,
"charon.plugins.eap-radius.server", NULL); "charon.plugins.eap-radius.server", NULL);
@@ -78,12 +83,12 @@ static void load_servers(private_eap_radius_plugin_t *this)
} }
nas_identifier = lib->settings->get_str(lib->settings, nas_identifier = lib->settings->get_str(lib->settings,
"charon.plugins.eap-radius.nas_identifier", "strongSwan"); "charon.plugins.eap-radius.nas_identifier", "strongSwan");
port = lib->settings->get_int(lib->settings, auth_port = lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.port", RADIUS_PORT); "charon.plugins.eap-radius.port", AUTH_PORT);
sockets = lib->settings->get_int(lib->settings, sockets = lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.sockets", 1); "charon.plugins.eap-radius.sockets", 1);
server = radius_server_create(address, address, port, nas_identifier, server = radius_server_create(address, address, auth_port, ACCT_PORT,
secret, sockets, 0); nas_identifier, secret, sockets, 0);
if (!server) if (!server)
{ {
DBG1(DBG_CFG, "no RADUIS server defined"); DBG1(DBG_CFG, "no RADUIS server defined");
@@ -114,14 +119,20 @@ static void load_servers(private_eap_radius_plugin_t *this)
nas_identifier = lib->settings->get_str(lib->settings, nas_identifier = lib->settings->get_str(lib->settings,
"charon.plugins.eap-radius.servers.%s.nas_identifier", "charon.plugins.eap-radius.servers.%s.nas_identifier",
"strongSwan", section); "strongSwan", section);
port = lib->settings->get_int(lib->settings, auth_port = lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.servers.%s.port", RADIUS_PORT, section); "charon.plugins.eap-radius.servers.%s.auth_port",
lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.servers.%s.port",
AUTH_PORT, section),
section);
acct_port = lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.servers.%s.acct_port", ACCT_PORT, section);
sockets = lib->settings->get_int(lib->settings, sockets = lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.servers.%s.sockets", 1, section); "charon.plugins.eap-radius.servers.%s.sockets", 1, section);
preference = lib->settings->get_int(lib->settings, preference = lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.servers.%s.preference", 0, section); "charon.plugins.eap-radius.servers.%s.preference", 0, section);
server = radius_server_create(section, address, port, nas_identifier, server = radius_server_create(section, address, auth_port, acct_port,
secret, sockets, preference); nas_identifier, secret, sockets, preference);
if (!server) if (!server)
{ {
DBG1(DBG_CFG, "loading RADIUS server '%s' failed, skipped", section); DBG1(DBG_CFG, "loading RADIUS server '%s' failed, skipped", section);
@@ -177,8 +177,10 @@ METHOD(radius_server_t, destroy, void,
/** /**
* See header * See header
*/ */
radius_server_t *radius_server_create(char *name, char *address, u_int16_t port, radius_server_t *radius_server_create(char *name, char *address,
char *nas_identifier, char *secret, int sockets, int preference) u_int16_t auth_port, u_int16_t acct_port,
char *nas_identifier, char *secret,
int sockets, int preference)
{ {
private_radius_server_t *this; private_radius_server_t *this;
radius_socket_t *socket; radius_socket_t *socket;
@@ -206,7 +208,7 @@ radius_server_t *radius_server_create(char *name, char *address, u_int16_t port,
while (sockets--) while (sockets--)
{ {
socket = radius_socket_create(address, port, socket = radius_socket_create(address, auth_port, acct_port,
chunk_create(secret, strlen(secret))); chunk_create(secret, strlen(secret)));
if (!socket) if (!socket)
{ {
@@ -85,13 +85,16 @@ struct radius_server_t {
* *
* @param name server name * @param name server name
* @param address server address * @param address server address
* @param port server port * @param auth_port server port for authentication
* @param acct_port server port for accounting
* @param nas_identifier NAS-Identifier to use with this server * @param nas_identifier NAS-Identifier to use with this server
* @param secret secret to use with this server * @param secret secret to use with this server
* @param sockets number of sockets to create in pool * @param sockets number of sockets to create in pool
* @param preference preference boost for this server * @param preference preference boost for this server
*/ */
radius_server_t *radius_server_create(char *name, char *address, u_int16_t port, radius_server_t *radius_server_create(char *name, char *address,
char *nas_identifier, char *secret, int sockets, int preference); u_int16_t auth_port, u_int16_t acct_port,
char *nas_identifier, char *secret,
int sockets, int preference);
#endif /** RADIUS_SERVER_H_ @}*/ #endif /** RADIUS_SERVER_H_ @}*/
@@ -44,20 +44,30 @@ struct private_radius_socket_t {
radius_socket_t public; radius_socket_t public;
/** /**
* socket file descriptor * Server port for authentication
*/ */
int fd; u_int16_t auth_port;
/**
* socket file descriptor for authentication
*/
int auth_fd;
/**
* Server port for accounting
*/
u_int16_t acct_port;
/**
* socket file descriptor for accounting
*/
int acct_fd;
/** /**
* Server address * Server address
*/ */
char *address; char *address;
/**
* Server port
*/
u_int16_t port;
/** /**
* current RADIUS identifier * current RADIUS identifier
*/ */
@@ -87,35 +97,36 @@ struct private_radius_socket_t {
/** /**
* Check or establish RADIUS connection * Check or establish RADIUS connection
*/ */
static bool check_connection(private_radius_socket_t *this) static bool check_connection(private_radius_socket_t *this,
int *fd, u_int16_t port)
{ {
if (this->fd == -1) if (*fd == -1)
{ {
host_t *server; host_t *server;
server = host_create_from_dns(this->address, AF_UNSPEC, this->port); server = host_create_from_dns(this->address, AF_UNSPEC, port);
if (!server) if (!server)
{ {
DBG1(DBG_CFG, "resolving RADIUS server address '%s' failed", DBG1(DBG_CFG, "resolving RADIUS server address '%s' failed",
this->address); this->address);
return FALSE; return FALSE;
} }
this->fd = socket(server->get_family(server), SOCK_DGRAM, IPPROTO_UDP); *fd = socket(server->get_family(server), SOCK_DGRAM, IPPROTO_UDP);
if (this->fd == -1) if (*fd == -1)
{ {
DBG1(DBG_CFG, "opening RADIUS socket for %#H failed: %s", DBG1(DBG_CFG, "opening RADIUS socket for %#H failed: %s",
server, strerror(errno)); server, strerror(errno));
server->destroy(server); server->destroy(server);
return FALSE; return FALSE;
} }
if (connect(this->fd, server->get_sockaddr(server), if (connect(*fd, server->get_sockaddr(server),
*server->get_sockaddr_len(server)) < 0) *server->get_sockaddr_len(server)) < 0)
{ {
DBG1(DBG_CFG, "connecting RADIUS socket to %#H failed: %s", DBG1(DBG_CFG, "connecting RADIUS socket to %#H failed: %s",
server, strerror(errno)); server, strerror(errno));
server->destroy(server); server->destroy(server);
close(this->fd); close(*fd);
this->fd = -1; *fd = -1;
return FALSE; return FALSE;
} }
server->destroy(server); server->destroy(server);
@@ -127,14 +138,25 @@ METHOD(radius_socket_t, request, radius_message_t*,
private_radius_socket_t *this, radius_message_t *request) private_radius_socket_t *this, radius_message_t *request)
{ {
chunk_t data; chunk_t data;
int i; int i, *fd;
u_int16_t port;
/* set Message Identifier */ /* set Message Identifier */
request->set_identifier(request, this->identifier++); request->set_identifier(request, this->identifier++);
/* sign the request */ /* sign the request */
request->sign(request, this->rng, this->signer, this->hasher, this->secret); request->sign(request, this->rng, this->signer, this->hasher, this->secret);
if (!check_connection(this)) if (request->get_code(request) == RMC_ACCOUNTING_REQUEST)
{
fd = &this->acct_fd;
port = this->acct_port;
}
else
{
fd = &this->auth_fd;
port = this->auth_port;
}
if (!check_connection(this, fd, port))
{ {
return NULL; return NULL;
} }
@@ -150,7 +172,7 @@ METHOD(radius_socket_t, request, radius_message_t*,
fd_set fds; fd_set fds;
int res; int res;
if (send(this->fd, data.ptr, data.len, 0) != data.len) if (send(*fd, data.ptr, data.len, 0) != data.len)
{ {
DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno)); DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno));
return NULL; return NULL;
@@ -161,8 +183,8 @@ METHOD(radius_socket_t, request, radius_message_t*,
while (TRUE) while (TRUE)
{ {
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(this->fd, &fds); FD_SET(*fd, &fds);
res = select(this->fd + 1, &fds, NULL, NULL, &tv); res = select((*fd) + 1, &fds, NULL, NULL, &tv);
/* TODO: updated tv to time not waited. Linux does this for us. */ /* TODO: updated tv to time not waited. Linux does this for us. */
if (res < 0) if (res < 0)
{ /* failed */ { /* failed */
@@ -176,7 +198,7 @@ METHOD(radius_socket_t, request, radius_message_t*,
retransmit = TRUE; retransmit = TRUE;
break; break;
} }
res = recv(this->fd, buf, sizeof(buf), MSG_DONTWAIT); res = recv(*fd, buf, sizeof(buf), MSG_DONTWAIT);
if (res <= 0) if (res <= 0)
{ {
DBG1(DBG_CFG, "receiving RADIUS message failed: %s", DBG1(DBG_CFG, "receiving RADIUS message failed: %s",
@@ -311,9 +333,13 @@ METHOD(radius_socket_t, destroy, void,
DESTROY_IF(this->hasher); DESTROY_IF(this->hasher);
DESTROY_IF(this->signer); DESTROY_IF(this->signer);
DESTROY_IF(this->rng); DESTROY_IF(this->rng);
if (this->fd != -1) if (this->auth_fd != -1)
{ {
close(this->fd); close(this->auth_fd);
};
if (this->acct_fd != -1)
{
close(this->acct_fd);
} }
free(this); free(this);
} }
@@ -321,8 +347,8 @@ METHOD(radius_socket_t, destroy, void,
/** /**
* See header * See header
*/ */
radius_socket_t *radius_socket_create(char *address, u_int16_t port, radius_socket_t *radius_socket_create(char *address, u_int16_t auth_port,
chunk_t secret) u_int16_t acct_port, chunk_t secret)
{ {
private_radius_socket_t *this; private_radius_socket_t *this;
@@ -333,8 +359,10 @@ radius_socket_t *radius_socket_create(char *address, u_int16_t port,
.destroy = _destroy, .destroy = _destroy,
}, },
.address = address, .address = address,
.port = port, .auth_port = auth_port,
.fd = -1, .auth_fd = -1,
.acct_port = acct_port,
.acct_fd = -1,
); );
this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
@@ -67,10 +67,11 @@ struct radius_socket_t {
* Create a radius_socket instance. * Create a radius_socket instance.
* *
* @param address server name * @param address server name
* @param port server port * @param auth_port server port for authentication
* @param acct_port server port for accounting
* @param secret RADIUS secret * @param secret RADIUS secret
*/ */
radius_socket_t *radius_socket_create(char *address, u_int16_t port, radius_socket_t *radius_socket_create(char *address, u_int16_t auth_port,
chunk_t secret); u_int16_t acct_port, chunk_t secret);
#endif /** RADIUS_SOCKET_H_ @}*/ #endif /** RADIUS_SOCKET_H_ @}*/