diff options
author | Martin Willi <martin@revosec.ch> | 2011-04-21 11:40:25 +0200 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2011-04-21 14:01:25 +0200 |
commit | f9a552f011cda2eb00373fba3e745ae279357cea (patch) | |
tree | ef396b4c0e6a03a8b8392c8a89528b437c7ed214 | |
parent | 5b0bcfb1fc4aabb6535db91e70f7f262328e664f (diff) | |
download | strongswan-f9a552f011cda2eb00373fba3e745ae279357cea.tar.bz2 strongswan-f9a552f011cda2eb00373fba3e745ae279357cea.tar.xz |
Resolve and connect to RADIUS servers not before required
-rw-r--r-- | src/libcharon/plugins/eap_radius/eap_radius_plugin.c | 4 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/radius_client.c | 17 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/radius_server.c | 28 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/radius_server.h | 11 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/radius_socket.c | 81 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_radius/radius_socket.h | 8 | ||||
-rw-r--r-- | src/libcharon/sa/authenticators/eap_authenticator.c | 1 |
7 files changed, 94 insertions, 56 deletions
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c index 9b1525662..c218bd48b 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c @@ -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) { diff --git a/src/libcharon/plugins/eap_radius/radius_client.c b/src/libcharon/plugins/eap_radius/radius_client.c index 0d7276af4..245308e59 100644 --- a/src/libcharon/plugins/eap_radius/radius_client.c +++ b/src/libcharon/plugins/eap_radius/radius_client.c @@ -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); diff --git a/src/libcharon/plugins/eap_radius/radius_server.c b/src/libcharon/plugins/eap_radius/radius_server.c index 37a2d331e..3baf39807 100644 --- a/src/libcharon/plugins/eap_radius/radius_server.c +++ b/src/libcharon/plugins/eap_radius/radius_server.c @@ -32,11 +32,6 @@ struct private_radius_server_t { radius_server_t public; /** - * RADIUS server address - */ - host_t *host; - - /** * list of radius sockets, as radius_socket_t */ linked_list_t *sockets; @@ -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) { diff --git a/src/libcharon/plugins/eap_radius/radius_server.h b/src/libcharon/plugins/eap_radius/radius_server.h index a9bc72180..c59361c49 100644 --- a/src/libcharon/plugins/eap_radius/radius_server.h +++ b/src/libcharon/plugins/eap_radius/radius_server.h @@ -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_ @}*/ diff --git a/src/libcharon/plugins/eap_radius/radius_socket.c b/src/libcharon/plugins/eap_radius/radius_socket.c index 76993e756..b3229c288 100644 --- a/src/libcharon/plugins/eap_radius/radius_socket.c +++ b/src/libcharon/plugins/eap_radius/radius_socket.c @@ -49,6 +49,16 @@ struct private_radius_socket_t { int fd; /** + * Server address + */ + char *address; + + /** + * Server port + */ + u_int16_t port; + + /** * current RADIUS identifier */ u_int8_t 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); diff --git a/src/libcharon/plugins/eap_radius/radius_socket.h b/src/libcharon/plugins/eap_radius/radius_socket.h index fe8491a8f..2875008eb 100644 --- a/src/libcharon/plugins/eap_radius/radius_socket.h +++ b/src/libcharon/plugins/eap_radius/radius_socket.h @@ -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_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap_authenticator.c b/src/libcharon/sa/authenticators/eap_authenticator.c index 6cae0034b..d442acb00 100644 --- a/src/libcharon/sa/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/authenticators/eap_authenticator.c @@ -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) |