eap-radius: Add support to specify and bind a specific source address

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
This commit is contained in:
Tobias Brunner
2025-02-28 16:16:48 +01:00
parent c3ae859b9b
commit 57703fa089
6 changed files with 67 additions and 23 deletions
+9 -6
View File
@@ -84,6 +84,9 @@ charon.plugins.eap-radius.secret =
charon.plugins.eap-radius.server = charon.plugins.eap-radius.server =
IP/Hostname of 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 charon.plugins.eap-radius.retransmit_base = 1.4
Base to use for calculating exponential back off. Base to use for calculating exponential back off.
@@ -96,12 +99,12 @@ charon.plugins.eap-radius.retransmit_tries = 4
charon.plugins.eap-radius.servers {} charon.plugins.eap-radius.servers {}
Section to specify multiple RADIUS servers. Section to specify multiple RADIUS servers.
Section to specify multiple RADIUS servers. The **nas_identifier**, Section to specify multiple RADIUS servers. The **source**,
**secret**, **sockets** and **port** (or **auth_port**) options can be **nas_identifier**, **secret**, **sockets** and **port** (or **auth_port**)
specified for each server. A server's IP/Hostname can be configured using options can be specified for each server. A server's IP/Hostname can be
the **address** option. The **acct_port** [1813] option can be used to configured using the **address** option. The **acct_port** [1813] option can
specify the port used for RADIUS accounting. For each RADIUS server a be used to specify the port used for RADIUS accounting. For each RADIUS
priority can be specified using the **preference** [0] option. The server a priority can be specified using the **preference** [0] option. The
retransmission time for each server can set set using **retransmit_base**, retransmission time for each server can set set using **retransmit_base**,
**retransmit_timeout** and **retransmit_tries**. **retransmit_timeout** and **retransmit_tries**.
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2013 Tobias Brunner * Copyright (C) 2013-2025 Tobias Brunner
* Copyright (C) 2009 Martin Willi * Copyright (C) 2009 Martin Willi
* *
* Copyright (C) secunet Security Networks AG * Copyright (C) secunet Security Networks AG
@@ -119,7 +119,7 @@ static void load_configs(private_eap_radius_plugin_t *this)
{ {
enumerator_t *enumerator; enumerator_t *enumerator;
radius_config_t *config; radius_config_t *config;
char *nas_identifier, *secret, *address, *section; char *nas_identifier, *secret, *address, *source, *section;
int auth_port, acct_port, sockets, preference; int auth_port, acct_port, sockets, preference;
u_int retransmit_tries; u_int retransmit_tries;
double retransmit_timeout, retransmit_base; 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"); DBG1(DBG_CFG, "no RADIUS secret defined");
return; return;
} }
source = lib->settings->get_str(lib->settings,
"%s.plugins.eap-radius.source", NULL, lib->ns);
nas_identifier = lib->settings->get_str(lib->settings, nas_identifier = lib->settings->get_str(lib->settings,
"%s.plugins.eap-radius.nas_identifier", "strongSwan", "%s.plugins.eap-radius.nas_identifier", "strongSwan",
lib->ns); lib->ns);
@@ -150,7 +152,7 @@ static void load_configs(private_eap_radius_plugin_t *this)
retransmit_base = lib->settings->get_double(lib->settings, retransmit_base = lib->settings->get_double(lib->settings,
"%s.plugins.eap-radius.retransmit_base", 1.4, lib->ns); "%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, nas_identifier, secret, sockets, 0,
retransmit_tries, retransmit_timeout, retransmit_tries, retransmit_timeout,
retransmit_base); 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); DBG1(DBG_CFG, "RADIUS server '%s' misses secret, skipped", section);
continue; 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, nas_identifier = lib->settings->get_str(lib->settings,
"%s.plugins.eap-radius.servers.%s.nas_identifier", "%s.plugins.eap-radius.servers.%s.nas_identifier",
lib->settings->get_str(lib->settings, 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, "%s.plugins.eap-radius.servers.%s.preference", 0,
lib->ns, section); 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, nas_identifier, secret, sockets, preference,
retransmit_tries, retransmit_timeout, retransmit_tries, retransmit_timeout,
retransmit_base); retransmit_base);
+2 -2
View File
@@ -200,7 +200,7 @@ METHOD(radius_config_t, destroy, void,
/** /**
* See header * 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, uint16_t auth_port, uint16_t acct_port,
char *nas_identifier, char *secret, char *nas_identifier, char *secret,
int sockets, int preference, int sockets, int preference,
@@ -232,7 +232,7 @@ radius_config_t *radius_config_create(char *name, char *address,
while (sockets--) 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)), chunk_create(secret, strlen(secret)),
tries, timeout, base); tries, timeout, base);
if (!socket) if (!socket)
+2 -1
View File
@@ -108,6 +108,7 @@ struct radius_config_t {
* *
* @param name server name * @param name server name
* @param address server address * @param address server address
* @param source optional source address
* @param auth_port server port for authentication * @param auth_port server port for authentication
* @param acct_port server port for accounting * @param acct_port server port for accounting
* @param nas_identifier NAS-Identifier to use with this server * @param nas_identifier NAS-Identifier to use with this server
@@ -118,7 +119,7 @@ struct radius_config_t {
* @param timeout retransmission timeout * @param timeout retransmission timeout
* @param base base to calculate 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, uint16_t auth_port, uint16_t acct_port,
char *nas_identifier, char *secret, char *nas_identifier, char *secret,
int sockets, int preference, int sockets, int preference,
+38 -7
View File
@@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2015-2025 Tobias Brunner
* Copyright (C) 2010 Martin Willi * Copyright (C) 2010 Martin Willi
* *
* Copyright (C) secunet Security Networks AG * Copyright (C) secunet Security Networks AG
@@ -83,6 +84,11 @@ struct private_radius_socket_t {
*/ */
char *address; char *address;
/**
* Source address
*/
char *source;
/** /**
* current RADIUS identifier * current RADIUS identifier
*/ */
@@ -130,10 +136,10 @@ struct private_radius_socket_t {
static bool check_connection(private_radius_socket_t *this, static bool check_connection(private_radius_socket_t *this,
int *fd, uint16_t port) int *fd, uint16_t port)
{ {
host_t *server, *src = NULL;
if (*fd == -1) if (*fd == -1)
{ {
host_t *server;
server = host_create_from_dns(this->address, AF_UNSPEC, port); server = host_create_from_dns(this->address, AF_UNSPEC, port);
if (!server) if (!server)
{ {
@@ -149,19 +155,42 @@ static bool check_connection(private_radius_socket_t *this,
server->destroy(server); server->destroy(server);
return FALSE; 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), if (connect(*fd, server->get_sockaddr(server),
*server->get_sockaddr_len(server)) < 0) *server->get_sockaddr_len(server)) < 0)
{ {
DBG1(DBG_CFG, "connecting RADIUS socket to %#H failed: %s", DBG1(DBG_CFG, "connecting RADIUS socket to %#H failed: %s",
server, strerror(errno)); server, strerror(errno));
server->destroy(server); goto error;
close(*fd);
*fd = -1;
return FALSE;
} }
server->destroy(server); server->destroy(server);
DESTROY_IF(src);
} }
return TRUE; 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 * 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, uint16_t acct_port, chunk_t secret,
u_int tries, double timeout, double base) 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, .destroy = _destroy,
}, },
.address = address, .address = address,
.source = source,
.auth_port = auth_port, .auth_port = auth_port,
.auth_fd = -1, .auth_fd = -1,
.acct_port = acct_port, .acct_port = acct_port,
+5 -3
View File
@@ -90,6 +90,7 @@ struct radius_socket_t {
* Create a radius_socket instance. * Create a radius_socket instance.
* *
* @param address server name * @param address server name
* @param source optional source address
* @param auth_port server port for authentication * @param auth_port server port for authentication
* @param acct_port server port for accounting * @param acct_port server port for accounting
* @param secret RADIUS secret * @param secret RADIUS secret
@@ -97,8 +98,9 @@ struct radius_socket_t {
* @param timeout retransmission timeout * @param timeout retransmission timeout
* @param base base to calculate retransmission timeout * @param base base to calculate retransmission timeout
*/ */
radius_socket_t *radius_socket_create(char *address, uint16_t auth_port, radius_socket_t *radius_socket_create(char *address, char *source,
uint16_t acct_port, chunk_t secret, uint16_t auth_port, uint16_t acct_port,
u_int tries, double timeout, double base); chunk_t secret, u_int tries,
double timeout, double base);
#endif /** RADIUS_SOCKET_H_ @}*/ #endif /** RADIUS_SOCKET_H_ @}*/