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 =
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**.
@@ -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);
+2 -2
View 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)
+2 -1
View 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,
+38 -7
View 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,
+5 -3
View 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_ @}*/