Open RADIUS accounting sockets to exchange accounting messages
authorMartin Willi <martin@revosec.ch>
Mon, 30 Jan 2012 18:15:20 +0000 (19:15 +0100)
committerMartin Willi <martin@revosec.ch>
Mon, 30 Jan 2012 18:15:20 +0000 (19:15 +0100)
src/libcharon/plugins/eap_radius/eap_radius_plugin.c
src/libcharon/plugins/eap_radius/radius_server.c
src/libcharon/plugins/eap_radius/radius_server.h
src/libcharon/plugins/eap_radius/radius_socket.c
src/libcharon/plugins/eap_radius/radius_socket.h

index 4119ec5..c38ebb9 100644 (file)
 #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;
 
@@ -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);
index 3baf398..282f508 100644 (file)
@@ -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)
                {
index c59361c..93b0e5d 100644 (file)
@@ -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_ @}*/
index 46513ee..56b65fe 100644 (file)
@@ -44,19 +44,29 @@ struct private_radius_socket_t {
        radius_socket_t public;
 
        /**
-        * socket file descriptor
+        * Server port for authentication
         */
-       int fd;
+       u_int16_t auth_port;
 
        /**
-        * Server address
+        * socket file descriptor for authentication
         */
-       char *address;
+       int auth_fd;
 
        /**
-        * Server port
+        * Server port for accounting
         */
-       u_int16_t port;
+       u_int16_t acct_port;
+
+       /**
+        * socket file descriptor for accounting
+        */
+       int acct_fd;
+
+       /**
+        * Server address
+        */
+       char *address;
 
        /**
         * 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->auth_fd);
+       };
+       if (this->acct_fd != -1)
        {
-               close(this->fd);
+               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);
index 2875008..0301ec6 100644 (file)
@@ -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_ @}*/