Resolve and connect to RADIUS servers not before required

This commit is contained in:
Martin Willi
2011-04-21 14:01:25 +02:00
parent 5b0bcfb1fc
commit f9a552f011
7 changed files with 94 additions and 56 deletions
@@ -82,7 +82,7 @@ static void load_servers(private_eap_radius_plugin_t *this)
"charon.plugins.eap-radius.port", RADIUS_PORT);
sockets = lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.sockets", 1);
server = radius_server_create(address, port, nas_identifier,
server = radius_server_create(address, address, port, nas_identifier,
secret, sockets, 0);
if (!server)
{
@@ -120,7 +120,7 @@ static void load_servers(private_eap_radius_plugin_t *this)
"charon.plugins.eap-radius.servers.%s.sockets", 1, section);
preference = lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.servers.%s.preference", 0, section);
server = radius_server_create(address, port, nas_identifier,
server = radius_server_create(section, address, port, nas_identifier,
secret, sockets, preference);
if (!server)
{
@@ -98,13 +98,14 @@ METHOD(radius_client_t, request, radius_message_t*,
req->add(req, RAT_STATE, this->state);
}
socket = this->server->get_socket(this->server);
DBG1(DBG_CFG, "sending RADIUS %N to %#H", radius_message_code_names,
req->get_code(req), this->server->get_address(this->server));
DBG1(DBG_CFG, "sending RADIUS %N to server '%s'", radius_message_code_names,
req->get_code(req), this->server->get_name(this->server));
res = socket->request(socket, req);
if (res)
{
DBG1(DBG_CFG, "received RADIUS %N from %#H", radius_message_code_names,
res->get_code(res), this->server->get_address(this->server));
DBG1(DBG_CFG, "received RADIUS %N from server '%s'",
radius_message_code_names, res->get_code(res),
this->server->get_name(this->server));
save_state(this, res);
if (res->get_code(res) == RMC_ACCESS_ACCEPT)
{
@@ -160,16 +161,16 @@ radius_client_t *radius_client_create()
/* for two with equal preference, 50-50 chance */
(current == best && random() % 2 == 0))
{
DBG2(DBG_CFG, "RADIUS server %H is candidate: %d",
server->get_address(server), current);
DBG2(DBG_CFG, "RADIUS server '%s' is candidate: %d",
server->get_name(server), current);
best = current;
DESTROY_IF(this->server);
this->server = server->get_ref(server);
}
else
{
DBG2(DBG_CFG, "RADIUS server %H skipped: %d",
server->get_address(server), current);
DBG2(DBG_CFG, "RADIUS server '%s' skipped: %d",
server->get_name(server), current);
}
}
enumerator->destroy(enumerator);
@@ -31,11 +31,6 @@ struct private_radius_server_t {
*/
radius_server_t public;
/**
* RADIUS server address
*/
host_t *host;
/**
* list of radius sockets, as radius_socket_t
*/
@@ -57,9 +52,9 @@ struct private_radius_server_t {
condvar_t *condvar;
/**
* RADIUS secret
* Server name
*/
chunk_t secret;
char *name;
/**
* NAS-Identifier
@@ -152,10 +147,10 @@ METHOD(radius_server_t, get_preference, int,
return pref;
}
METHOD(radius_server_t, get_address, host_t*,
METHOD(radius_server_t, get_name, char*,
private_radius_server_t *this)
{
return this->host;
return this->name;
}
METHOD(radius_server_t, get_ref, radius_server_t*,
@@ -171,12 +166,10 @@ METHOD(radius_server_t, destroy, void,
{
if (ref_put(&this->ref))
{
DESTROY_IF(this->host);
this->mutex->destroy(this->mutex);
this->condvar->destroy(this->condvar);
this->sockets->destroy_offset(this->sockets,
offsetof(radius_socket_t, destroy));
free(this->nas_identifier.ptr);
free(this);
}
}
@@ -184,7 +177,7 @@ METHOD(radius_server_t, destroy, void,
/**
* See header
*/
radius_server_t *radius_server_create(char *server, u_int16_t port,
radius_server_t *radius_server_create(char *name, char *address, u_int16_t port,
char *nas_identifier, char *secret, int sockets, int preference)
{
private_radius_server_t *this;
@@ -196,7 +189,7 @@ radius_server_t *radius_server_create(char *server, u_int16_t port,
.put_socket = _put_socket,
.get_nas_identifier = _get_nas_identifier,
.get_preference = _get_preference,
.get_address = _get_address,
.get_name = _get_name,
.get_ref = _get_ref,
.destroy = _destroy,
},
@@ -206,19 +199,14 @@ radius_server_t *radius_server_create(char *server, u_int16_t port,
.sockets = linked_list_create(),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
.condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
.host = host_create_from_dns(server, 0, port),
.name = name,
.preference = preference,
.ref = 1,
);
if (!this->host)
{
destroy(this);
return NULL;
}
while (sockets--)
{
socket = radius_socket_create(this->host,
socket = radius_socket_create(address, port,
chunk_create(secret, strlen(secret)));
if (!socket)
{
@@ -61,11 +61,11 @@ struct radius_server_t {
int (*get_preference)(radius_server_t *this);
/**
* Get the address of the RADIUS server.
* Get the name of the RADIUS server.
*
* @return address, internal data
* @return server name
*/
host_t* (*get_address)(radius_server_t *this);
char* (*get_name)(radius_server_t *this);
/**
* Increase reference count of this server.
@@ -83,14 +83,15 @@ struct radius_server_t {
/**
* Create a radius_server instance.
*
* @param server server address
* @param name server name
* @param address server address
* @param port server port
* @param nas_identifier NAS-Identifier to use with this server
* @param secret secret to use with this server
* @param sockets number of sockets to create in pool
* @param preference preference boost for this server
*/
radius_server_t *radius_server_create(char *server, u_int16_t port,
radius_server_t *radius_server_create(char *name, char *address, u_int16_t port,
char *nas_identifier, char *secret, int sockets, int preference);
#endif /** RADIUS_SERVER_H_ @}*/
@@ -48,6 +48,16 @@ struct private_radius_socket_t {
*/
int fd;
/**
* Server address
*/
char *address;
/**
* Server port
*/
u_int16_t port;
/**
* current RADIUS identifier
*/
@@ -74,6 +84,45 @@ struct private_radius_socket_t {
chunk_t secret;
};
/**
* Check or establish RADIUS connection
*/
static bool check_connection(private_radius_socket_t *this)
{
if (this->fd == -1)
{
host_t *server;
server = host_create_from_dns(this->address, AF_UNSPEC, this->port);
if (!server)
{
DBG1(DBG_CFG, "resolving RADIUS server address '%s' failed",
this->address);
return FALSE;
}
this->fd = socket(server->get_family(server), SOCK_DGRAM, IPPROTO_UDP);
if (this->fd == -1)
{
DBG1(DBG_CFG, "opening RADIUS socket for %#H failed: %s",
server, strerror(errno));
server->destroy(server);
return FALSE;
}
if (connect(this->fd, server->get_sockaddr(server),
*server->get_sockaddr_len(server)) < 0)
{
DBG1(DBG_CFG, "connecting RADIUS socket to %#H failed: %s",
server, strerror(errno));
server->destroy(server);
close(this->fd);
this->fd = -1;
return FALSE;
}
server->destroy(server);
}
return TRUE;
}
METHOD(radius_socket_t, request, radius_message_t*,
private_radius_socket_t *this, radius_message_t *request)
{
@@ -85,6 +134,11 @@ METHOD(radius_socket_t, request, radius_message_t*,
/* sign the request */
request->sign(request, this->rng, this->signer);
if (!check_connection(this))
{
return NULL;
}
data = request->get_encoding(request);
/* timeout after 2, 3, 4, 5 seconds */
for (i = 2; i <= 5; i++)
@@ -257,15 +311,18 @@ METHOD(radius_socket_t, destroy, void,
DESTROY_IF(this->hasher);
DESTROY_IF(this->signer);
DESTROY_IF(this->rng);
chunk_clear(&this->secret);
close(this->fd);
if (this->fd != -1)
{
close(this->fd);
}
free(this);
}
/**
* See header
*/
radius_socket_t *radius_socket_create(host_t *host, chunk_t secret)
radius_socket_t *radius_socket_create(char *address, u_int16_t port,
chunk_t secret)
{
private_radius_socket_t *this;
@@ -275,23 +332,11 @@ radius_socket_t *radius_socket_create(host_t *host, chunk_t secret)
.decrypt_msk = _decrypt_msk,
.destroy = _destroy,
},
.address = address,
.port = port,
.fd = -1,
);
this->fd = socket(host->get_family(host), SOCK_DGRAM, IPPROTO_UDP);
if (this->fd < 0)
{
DBG1(DBG_CFG, "opening RADIUS socket failed: %s", strerror(errno));
free(this);
return NULL;
}
if (connect(this->fd, host->get_sockaddr(host),
*host->get_sockaddr_len(host)) < 0)
{
DBG1(DBG_CFG, "connecting RADIUS socket failed");
close(this->fd);
free(this);
return NULL;
}
this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128);
this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
@@ -34,7 +34,7 @@ struct radius_socket_t {
/**
* Send a RADIUS request, wait for response.
*
* The socket fills in RADIUS Message identifier, builds a
* Request-Authenticator and calculates the Message-Authenticator
* attribute.
@@ -66,9 +66,11 @@ struct radius_socket_t {
/**
* Create a radius_socket instance.
*
* @param host RADIUS server address to connect to
* @param address server name
* @param port server port
* @param secret RADIUS secret
*/
radius_socket_t *radius_socket_create(host_t *host, chunk_t secret);
radius_socket_t *radius_socket_create(char *address, u_int16_t port,
chunk_t secret);
#endif /** RADIUS_SOCKET_H_ @}*/
@@ -183,6 +183,7 @@ static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this,
if (this->method)
{
action = "initiating";
type = this->method->get_type(this->method, &vendor);
if (this->method->initiate(this->method, &out) == NEED_MORE)
{
if (vendor)