Resolve and connect to RADIUS servers not before required
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user