From 8e5b4aa023accbf7b3406050b3b7175b9bd0b6b7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 30 Jan 2012 19:15:20 +0100 Subject: [PATCH] Open RADIUS accounting sockets to exchange accounting messages --- .../plugins/eap_radius/eap_radius_plugin.c | 33 +++++--- .../plugins/eap_radius/radius_server.c | 8 +- .../plugins/eap_radius/radius_server.h | 9 +- .../plugins/eap_radius/radius_socket.c | 82 +++++++++++++------ .../plugins/eap_radius/radius_socket.h | 7 +- 5 files changed, 92 insertions(+), 47 deletions(-) diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c index 4119ec571..c38ebb9be 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c @@ -23,9 +23,14 @@ #include /** - * 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; @@ -63,7 +68,7 @@ static void load_servers(private_eap_radius_plugin_t *this) enumerator_t *enumerator; radius_server_t *server; char *nas_identifier, *secret, *address, *section; - int port, sockets, preference; + int auth_port, acct_port, sockets, preference; address = lib->settings->get_str(lib->settings, "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, "charon.plugins.eap-radius.nas_identifier", "strongSwan"); - port = lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.port", RADIUS_PORT); + auth_port = lib->settings->get_int(lib->settings, + "charon.plugins.eap-radius.port", AUTH_PORT); sockets = lib->settings->get_int(lib->settings, "charon.plugins.eap-radius.sockets", 1); - server = radius_server_create(address, address, port, nas_identifier, - secret, sockets, 0); + server = radius_server_create(address, address, auth_port, ACCT_PORT, + nas_identifier, secret, sockets, 0); if (!server) { 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, "charon.plugins.eap-radius.servers.%s.nas_identifier", "strongSwan", section); - port = lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.servers.%s.port", RADIUS_PORT, section); + auth_port = lib->settings->get_int(lib->settings, + "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, "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(section, address, port, nas_identifier, - secret, sockets, preference); + server = radius_server_create(section, address, auth_port, acct_port, + nas_identifier, secret, sockets, preference); if (!server) { DBG1(DBG_CFG, "loading RADIUS server '%s' failed, skipped", section); diff --git a/src/libcharon/plugins/eap_radius/radius_server.c b/src/libcharon/plugins/eap_radius/radius_server.c index 3baf39807..282f50892 100644 --- a/src/libcharon/plugins/eap_radius/radius_server.c +++ b/src/libcharon/plugins/eap_radius/radius_server.c @@ -177,8 +177,10 @@ METHOD(radius_server_t, destroy, void, /** * See header */ -radius_server_t *radius_server_create(char *name, char *address, u_int16_t port, - char *nas_identifier, char *secret, int sockets, int preference) +radius_server_t *radius_server_create(char *name, char *address, + u_int16_t auth_port, u_int16_t acct_port, + char *nas_identifier, char *secret, + int sockets, int preference) { private_radius_server_t *this; radius_socket_t *socket; @@ -206,7 +208,7 @@ radius_server_t *radius_server_create(char *name, char *address, u_int16_t port, while (sockets--) { - socket = radius_socket_create(address, port, + socket = radius_socket_create(address, auth_port, acct_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 c59361c49..93b0e5d8d 100644 --- a/src/libcharon/plugins/eap_radius/radius_server.h +++ b/src/libcharon/plugins/eap_radius/radius_server.h @@ -85,13 +85,16 @@ struct radius_server_t { * * @param name server name * @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 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 *name, char *address, u_int16_t port, - char *nas_identifier, char *secret, int sockets, int preference); +radius_server_t *radius_server_create(char *name, char *address, + u_int16_t auth_port, u_int16_t acct_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 46513ee57..56b65fea8 100644 --- a/src/libcharon/plugins/eap_radius/radius_socket.c +++ b/src/libcharon/plugins/eap_radius/radius_socket.c @@ -44,20 +44,30 @@ struct private_radius_socket_t { 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 */ char *address; - /** - * Server port - */ - u_int16_t port; - /** * current RADIUS identifier */ @@ -87,35 +97,36 @@ struct private_radius_socket_t { /** * 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; - server = host_create_from_dns(this->address, AF_UNSPEC, this->port); + server = host_create_from_dns(this->address, AF_UNSPEC, 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) + *fd = socket(server->get_family(server), SOCK_DGRAM, IPPROTO_UDP); + if (*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), + if (connect(*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; + close(*fd); + *fd = -1; return FALSE; } server->destroy(server); @@ -127,14 +138,25 @@ METHOD(radius_socket_t, request, radius_message_t*, private_radius_socket_t *this, radius_message_t *request) { chunk_t data; - int i; + int i, *fd; + u_int16_t port; /* set Message Identifier */ request->set_identifier(request, this->identifier++); /* sign the request */ 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; } @@ -150,7 +172,7 @@ METHOD(radius_socket_t, request, radius_message_t*, fd_set fds; 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)); return NULL; @@ -161,8 +183,8 @@ METHOD(radius_socket_t, request, radius_message_t*, while (TRUE) { FD_ZERO(&fds); - FD_SET(this->fd, &fds); - res = select(this->fd + 1, &fds, NULL, NULL, &tv); + FD_SET(*fd, &fds); + res = select((*fd) + 1, &fds, NULL, NULL, &tv); /* TODO: updated tv to time not waited. Linux does this for us. */ if (res < 0) { /* failed */ @@ -176,7 +198,7 @@ METHOD(radius_socket_t, request, radius_message_t*, retransmit = TRUE; break; } - res = recv(this->fd, buf, sizeof(buf), MSG_DONTWAIT); + res = recv(*fd, buf, sizeof(buf), MSG_DONTWAIT); if (res <= 0) { 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->signer); 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); } @@ -321,8 +347,8 @@ METHOD(radius_socket_t, destroy, void, /** * See header */ -radius_socket_t *radius_socket_create(char *address, u_int16_t port, - chunk_t secret) +radius_socket_t *radius_socket_create(char *address, u_int16_t auth_port, + u_int16_t acct_port, chunk_t secret) { private_radius_socket_t *this; @@ -333,8 +359,10 @@ radius_socket_t *radius_socket_create(char *address, u_int16_t port, .destroy = _destroy, }, .address = address, - .port = port, - .fd = -1, + .auth_port = auth_port, + .auth_fd = -1, + .acct_port = acct_port, + .acct_fd = -1, ); this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); diff --git a/src/libcharon/plugins/eap_radius/radius_socket.h b/src/libcharon/plugins/eap_radius/radius_socket.h index 2875008eb..0301ec6d0 100644 --- a/src/libcharon/plugins/eap_radius/radius_socket.h +++ b/src/libcharon/plugins/eap_radius/radius_socket.h @@ -67,10 +67,11 @@ struct radius_socket_t { * Create a radius_socket instance. * * @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 */ -radius_socket_t *radius_socket_create(char *address, u_int16_t port, - chunk_t secret); +radius_socket_t *radius_socket_create(char *address, u_int16_t auth_port, + u_int16_t acct_port, chunk_t secret); #endif /** RADIUS_SOCKET_H_ @}*/