Open RADIUS accounting sockets to exchange accounting messages
This commit is contained in:
@@ -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_ @}*/
|
||||||
|
|||||||
Reference in New Issue
Block a user