]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
eap-radius: Add support to specify and bind a specific source address
authorTobias Brunner <tobias@strongswan.org>
Thu, 16 Jan 2025 10:02:13 +0000 (11:02 +0100)
committerTobias Brunner <tobias@strongswan.org>
Fri, 28 Feb 2025 15:16:48 +0000 (16:16 +0100)
Using a specific address can be useful in scenarios where dynamic routing
could change the path to the RADIUS server and a changing source address
is a problem for the server.

Closes strongswan/strongswan#2598

conf/plugins/eap-radius.opt
src/libcharon/plugins/eap_radius/eap_radius_plugin.c
src/libradius/radius_config.c
src/libradius/radius_config.h
src/libradius/radius_socket.c
src/libradius/radius_socket.h

index dfed781659a88e7118881ec9e16bcc71276363a2..06b86f7642311e40d2994e95028660c1ce50b799 100644 (file)
@@ -84,6 +84,9 @@ charon.plugins.eap-radius.secret =
 charon.plugins.eap-radius.server =
        IP/Hostname of RADIUS server.
 
+charon.plugins.eap-radius.source =
+       Optional specific source IP to use.
+
 charon.plugins.eap-radius.retransmit_base = 1.4
        Base to use for calculating exponential back off.
 
@@ -96,12 +99,12 @@ charon.plugins.eap-radius.retransmit_tries = 4
 charon.plugins.eap-radius.servers {}
        Section to specify multiple RADIUS servers.
 
-       Section to specify multiple RADIUS servers. The **nas_identifier**,
-       **secret**, **sockets** and **port** (or **auth_port**) options can be
-       specified for each server. A server's IP/Hostname can be configured using
-       the **address** option. The **acct_port** [1813] option can be used to
-       specify the port used for RADIUS accounting. For each RADIUS server a
-       priority can be specified using the **preference** [0] option. The
+       Section to specify multiple RADIUS servers. The **source**,
+       **nas_identifier**,     **secret**, **sockets** and **port** (or **auth_port**)
+       options can be specified for each server. A server's IP/Hostname can be
+       configured using the **address** option. The **acct_port** [1813] option can
+       be used to specify the port used for RADIUS accounting. For each RADIUS
+       server a priority can be specified using the **preference** [0] option. The
        retransmission time for each server can set set using **retransmit_base**,
        **retransmit_timeout** and **retransmit_tries**.
 
index b6dc64088639b63b6ffecbaf3fc594214800c2ef..5051542615a8f36a7196b68b4456c63be03e2433 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2013-2025 Tobias Brunner
  * Copyright (C) 2009 Martin Willi
  *
  * Copyright (C) secunet Security Networks AG
@@ -119,7 +119,7 @@ static void load_configs(private_eap_radius_plugin_t *this)
 {
        enumerator_t *enumerator;
        radius_config_t *config;
-       char *nas_identifier, *secret, *address, *section;
+       char *nas_identifier, *secret, *address, *source, *section;
        int auth_port, acct_port, sockets, preference;
        u_int retransmit_tries;
        double retransmit_timeout, retransmit_base;
@@ -135,6 +135,8 @@ static void load_configs(private_eap_radius_plugin_t *this)
                        DBG1(DBG_CFG, "no RADIUS secret defined");
                        return;
                }
+               source = lib->settings->get_str(lib->settings,
+                                               "%s.plugins.eap-radius.source", NULL, lib->ns);
                nas_identifier = lib->settings->get_str(lib->settings,
                                                "%s.plugins.eap-radius.nas_identifier", "strongSwan",
                                                lib->ns);
@@ -150,7 +152,7 @@ static void load_configs(private_eap_radius_plugin_t *this)
                retransmit_base = lib->settings->get_double(lib->settings,
                                                "%s.plugins.eap-radius.retransmit_base", 1.4, lib->ns);
 
-               config = radius_config_create(address, address, auth_port, ACCT_PORT,
+               config = radius_config_create(address, address, source, auth_port, ACCT_PORT,
                                                                          nas_identifier, secret, sockets, 0,
                                                                          retransmit_tries, retransmit_timeout,
                                                                          retransmit_base);
@@ -183,6 +185,11 @@ static void load_configs(private_eap_radius_plugin_t *this)
                        DBG1(DBG_CFG, "RADIUS server '%s' misses secret, skipped", section);
                        continue;
                }
+               source = lib->settings->get_str(lib->settings,
+                               "%s.plugins.eap-radius.servers.%s.source",
+                                       lib->settings->get_str(lib->settings,
+                                               "%s.plugins.eap-radius.source", NULL, lib->ns),
+                               lib->ns, section);
                nas_identifier = lib->settings->get_str(lib->settings,
                                "%s.plugins.eap-radius.servers.%s.nas_identifier",
                                        lib->settings->get_str(lib->settings,
@@ -228,7 +235,7 @@ static void load_configs(private_eap_radius_plugin_t *this)
                                "%s.plugins.eap-radius.servers.%s.preference", 0,
                                lib->ns, section);
 
-               config = radius_config_create(section, address, auth_port, acct_port,
+               config = radius_config_create(section, address, source, auth_port, acct_port,
                                                                nas_identifier, secret, sockets, preference,
                                                                retransmit_tries, retransmit_timeout,
                                                                retransmit_base);
index 4ab9f640dbbb497969b08f57424244d397ab418e..bde408e90d6189c996f1829fb15d924389a504be 100644 (file)
@@ -200,7 +200,7 @@ METHOD(radius_config_t, destroy, void,
 /**
  * See header
  */
-radius_config_t *radius_config_create(char *name, char *address,
+radius_config_t *radius_config_create(char *name, char *address, char *source,
                                                                          uint16_t auth_port, uint16_t acct_port,
                                                                          char *nas_identifier, char *secret,
                                                                          int sockets, int preference,
@@ -232,7 +232,7 @@ radius_config_t *radius_config_create(char *name, char *address,
 
        while (sockets--)
        {
-               socket = radius_socket_create(address, auth_port, acct_port,
+               socket = radius_socket_create(address, source, auth_port, acct_port,
                                                                          chunk_create(secret, strlen(secret)),
                                                                          tries, timeout, base);
                if (!socket)
index 2cb1ee13868def1a3b5b1b3f7a0a0c3b0ec8c348..5a4d301e4c133bd422d3b69732c8830d091e8339 100644 (file)
@@ -108,6 +108,7 @@ struct radius_config_t {
  *
  * @param name                         server name
  * @param address                      server address
+ * @param source                       optional source address
  * @param auth_port                    server port for authentication
  * @param acct_port                    server port for accounting
  * @param nas_identifier       NAS-Identifier to use with this server
@@ -118,7 +119,7 @@ struct radius_config_t {
  * @param timeout                      retransmission timeout
  * @param base                         base to calculate retransmission timeout
  */
-radius_config_t *radius_config_create(char *name, char *address,
+radius_config_t *radius_config_create(char *name, char *address, char *source,
                                                                          uint16_t auth_port, uint16_t acct_port,
                                                                          char *nas_identifier, char *secret,
                                                                          int sockets, int preference,
index 8635e93cb4c3788ca9db6b9bb26d1778d22267d2..4b93fbda18b6891173804ddc0057d35027214ab0 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2015-2025 Tobias Brunner
  * Copyright (C) 2010 Martin Willi
  *
  * Copyright (C) secunet Security Networks AG
@@ -83,6 +84,11 @@ struct private_radius_socket_t {
         */
        char *address;
 
+       /**
+        * Source address
+        */
+       char *source;
+
        /**
         * current RADIUS identifier
         */
@@ -130,10 +136,10 @@ struct private_radius_socket_t {
 static bool check_connection(private_radius_socket_t *this,
                                                         int *fd, uint16_t port)
 {
+       host_t *server, *src = NULL;
+
        if (*fd == -1)
        {
-               host_t *server;
-
                server = host_create_from_dns(this->address, AF_UNSPEC, port);
                if (!server)
                {
@@ -149,19 +155,42 @@ static bool check_connection(private_radius_socket_t *this,
                        server->destroy(server);
                        return FALSE;
                }
+               if (this->source)
+               {
+                       src = host_create_from_string_and_family(this->source,
+                                                                                                        server->get_family(server), 0);
+                       if (!src)
+                       {
+                               DBG1(DBG_CFG, "invalid source address '%s' to reach RADIUS "
+                                        "server %#H", this->source, server);
+                               goto error;
+                       }
+                       if (bind(*fd, src->get_sockaddr(src),
+                                        *src->get_sockaddr_len(src)) == -1)
+                       {
+                               DBG1(DBG_CFG, "binding RADIUS socket to %H failed: %s", src,
+                                        strerror(errno));
+                               goto error;
+                       }
+               }
                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(*fd);
-                       *fd = -1;
-                       return FALSE;
+                       goto error;
                }
                server->destroy(server);
+               DESTROY_IF(src);
        }
        return TRUE;
+
+error:
+       server->destroy(server);
+       DESTROY_IF(src);
+       close(*fd);
+       *fd = -1;
+       return FALSE;
 }
 
 /**
@@ -383,7 +412,8 @@ METHOD(radius_socket_t, destroy, void,
 /**
  * See header
  */
-radius_socket_t *radius_socket_create(char *address, uint16_t auth_port,
+radius_socket_t *radius_socket_create(char *address, char *source,
+                                                                         uint16_t auth_port,
                                                                          uint16_t acct_port, chunk_t secret,
                                                                          u_int tries, double timeout, double base)
 {
@@ -396,6 +426,7 @@ radius_socket_t *radius_socket_create(char *address, uint16_t auth_port,
                        .destroy = _destroy,
                },
                .address = address,
+               .source = source,
                .auth_port = auth_port,
                .auth_fd = -1,
                .acct_port = acct_port,
index 69ee7c4eeb61467e560e1112f8096b213dd83559..f9415b9aed969196dd4b82ede888fcca5081afb4 100644 (file)
@@ -90,6 +90,7 @@ struct radius_socket_t {
  * Create a radius_socket instance.
  *
  * @param address      server name
+ * @param source       optional source address
  * @param auth_port    server port for authentication
  * @param acct_port    server port for accounting
  * @param secret       RADIUS secret
@@ -97,8 +98,9 @@ struct radius_socket_t {
  * @param timeout      retransmission timeout
  * @param base         base to calculate retransmission timeout
  */
-radius_socket_t *radius_socket_create(char *address, uint16_t auth_port,
-                                                                         uint16_t acct_port, chunk_t secret,
-                                                                         u_int tries, double timeout, double base);
+radius_socket_t *radius_socket_create(char *address, char *source,
+                                                                         uint16_t auth_port, uint16_t acct_port,
+                                                                         chunk_t secret, u_int tries,
+                                                                         double timeout, double base);
 
 #endif /** RADIUS_SOCKET_H_ @}*/